GSTATUS DDFSemOpen ( PSEMAPHORE sem, bool exclusive) { GSTATUS err = GSTAT_OK; STATUS status; if ((status = CSp_semaphore(TRUE, &sem->semaphore)) == OK) { while (status == OK && ((exclusive == TRUE) ? sem->have != 0 : sem->have < 0)) status = CScnd_wait(&sem->cond, &sem->semaphore); if (status == OK) { if (exclusive == TRUE) sem->have--; else sem->have++; status = CSv_semaphore(&sem->semaphore); } else if (status != E_CS000F_REQUEST_ABORTED) { CSv_semaphore(&sem->semaphore); err = DDFStatusAlloc (E_DF0008_SEM_CANNOT_OPEN); } } return(err); }
/*{ ** Name: ops_exlock - exclusive access to OPF server control block ** ** Description: ** Get semaphore to have single thread access to update OPF ** structures including OPF server control block ** ** Inputs: ** opf_cb opf control block ** semaphore ptr to OPF semaphore ** ** Outputs: ** Returns: ** ** Exceptions: ** ** Side Effects: ** gets lock on OPF semaphore ** ** History: ** 20-jul-93 (ed) ** changed name ops_lock for solaris, due to OS conflict ** 09-Oct-1998 (jenjo02) ** Removed SCF semaphore functions, inlining the CS calls instead. [@history_line@]... [@history_template@]... */ DB_STATUS ops_exlock( OPF_CB *opf_cb, SCF_SEMAPHORE *semaphore) { STATUS status; /* First, wait to get exclusive access to the server control block */ status = CSp_semaphore(1, semaphore); /* exclusive */ if (status != OK) { # ifdef E_OP0092_SEMWAIT opx_rverror( opf_cb, E_DB_ERROR, E_OP0092_SEMWAIT, status); # endif return(E_DB_ERROR); } return(E_DB_OK); }
GSTATUS DDFSemClose ( PSEMAPHORE sem) { GSTATUS err = GSTAT_OK; STATUS status; G_ASSERT(!sem, E_DF0010_SEM_BAD_INIT); if ((status = CSp_semaphore(TRUE, &sem->semaphore)) == OK) { if (sem->have < 0) { sem->have = 0; /* when releaseing an exclusive - several shares may wake */ status = CScnd_broadcast(&sem->cond); } else { sem->have--; if (sem->have == 0) { /* when releaseing a share - at most one exclusive may wake */ status = CScnd_signal(&sem->cond, (CS_SID)NULL); } } if (status == OK) { if (CSv_semaphore(&sem->semaphore) != OK) err = DDFStatusAlloc (E_DF0009_SEM_CANNOT_CLOSE); } else { CSv_semaphore(&sem->semaphore); } } return(err); }
/* request and wait for semaphore */ STATUS Psem( CS_SEMAPHORE *sp) { STATUS rv; #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ SIfprintf( stderr,"Error: unexpected exception in Psem()..."); EXdelete(); return FAIL; } #endif if( rv = CSp_semaphore( TRUE, sp ) ) semerr( rv, sp, "Psem" ); #ifdef EX_DEBUG EXdelete(); #endif return( rv ); }
/* ** Name: QEN_PRINT_ROW - This routine prints the current row for a given ** QEN_NODE ** ** Description: ** This routine prints out the current row for the given QEN_NODE. ** This is done with the help of ADF, who converts data into a ** printable form, similiar to what the terminal monitor needs to do. ** ** FIXME this really belongs in qenutl since it applies to any node, ** not just fsm-joins. ** ** Inputs: ** node - ** The qen_node that refers to the row. ** qef_rcb - ** The request control block that we get most of our query common ** info from, like cbs, the dsh, dsh rows, etc. ** ** Outputs: ** ** Returns: ** DB_STATUS ** Exceptions: ** none ** ** Side Effects: ** causes a row to be printed to the FE (via SCC_TRACE). ** ** History: ** 17-may-89 (eric) ** created ** 6-aug-04 (inkdo01) ** Drop increment of node_rcount - it's already incremented in the ** node handlers and this simply doubles its value. ** 13-Dec-2005 (kschendel) ** Can count on qen-ade-cx now. ** 11-Mar-2010 (hanal04) Bug 123415 ** Make sure QE99 and OP173 do not interleave output with ** using parallel query. ** 12-May-2010 (kschendel) Bug 123720 ** Above doesn't quite go far enough, mutex the buffer. ** Take qef_trsem for valid parallel-query output. */ DB_STATUS qen_print_row( QEN_NODE *node, QEF_RCB *qef_rcb, QEE_DSH *dsh ) { QEN_STATUS *qen_status = dsh->dsh_xaddrs[node->qen_num]->qex_status; QEN_ADF *qen_adf; DB_STATUS status = E_DB_OK; char *cbuf = dsh->dsh_qefcb->qef_trfmt; i4 cbufsize = dsh->dsh_qefcb->qef_trsize; qen_adf = node->qen_prow; /* Checked non-NULL by caller */ if (qen_status->node_rcount > 0) { /* process the row print expression */ status = qen_execute_cx(dsh, dsh->dsh_xaddrs[node->qen_num]->qex_prow); if (status != E_DB_OK) { # ifdef xDEBUG (VOID) qe2_chk_qp(dsh); # endif return (status); } /* Print in one operation to avoid interleaved output */ CSp_semaphore(1, &dsh->dsh_qefcb->qef_trsem); STprintf(cbuf, "Row %d of node %d\n%s\n\n", qen_status->node_rcount, node->qen_num, dsh->dsh_row[qen_adf->qen_output]); qec_tprintf(qef_rcb, cbufsize, cbuf); CSv_semaphore(&dsh->dsh_qefcb->qef_trsem); } return(E_DB_OK); }
/*{ ** Name: psf_debug - Standard entry point for debugging PSF. ** ** Description: ** This function is the standard entry point to PSF for setting and ** clearing tracepoints. ** ** Inputs: ** debug_cb Pointer to a DB_DEBUG_CB ** .db_trswitch What operation to perform ** DB_TR_NOCHANGE None ** DB_TR_ON Turn on a tracepoint ** DB_TR_OFF Turn off a tracepoint ** .db_trace_point The number of the tracepoint to be ** effected ** .db_vals[2] Optional values, to be interpreted ** differently for each tracepoint ** .db_value_count The number of values specified in ** the above array ** ** Outputs: ** None ** Returns: ** E_DB_OK Success ** E_DB_WARN Operation completed with warning(s) ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 17-apr-86 (jeff) ** written ** 13-feb-90 (andre) ** set scf_stype to SCU_EXCLUSIVE before calling scu_swait. ** 14-jul-93 (ed) ** replacing <dbms.h> by <gl.h> <sl.h> <iicommon.h> <dbdbms.h> ** 10-aug-93 (andre) ** removed declaration of scf_call() ** 08-oct-93 (rblumer) ** In order to allow session trace points that take a value, ** changed ult_set_macro call to use firstval and secondval ** instead of hard-coding zeros for the values. ** 09-Oct-1998 (jenjo02) ** Removed SCF semaphore functions, inlining the CS calls instead. ** 04-may-1999 (hanch04) ** Change TRformat's print function to pass a PTR not an i4. ** 21-Feb-2007 (hanal04) Bug 117736 ** Added trace point PS503 to dump PSF's ULM memory usage to the ** DBMS log. */ DB_STATUS psf_debug( DB_DEBUG_CB *debug_cb) { i4 flag; i4 firstval; i4 secondval; PSS_SESBLK *sess_cb; extern PSF_SERVBLK *Psf_srvblk; /* Get the session control block */ sess_cb = psf_sesscb(); /* Flags 0 - PSF_TBITS-1 are for the server; all others are for sessions */ flag = debug_cb->db_trace_point; if (flag >= PSF_TBITS) { flag = flag - PSF_TBITS; if (flag >= PSS_TBITS) return (E_DB_ERROR); } /* There can be UP TO two values, but maybe they weren't given */ if (debug_cb->db_value_count > 0) firstval = debug_cb->db_vals[0]; else firstval = 0L; if (debug_cb->db_value_count > 1) secondval = debug_cb->db_vals[1]; else secondval = 0L; /* ** Three possible actions: Turn on flag, turn it off, or do nothing. */ switch (debug_cb->db_trswitch) { case DB_TR_ON: /* First PSF_TBITS flags belong to server, others to session */ if (debug_cb->db_trace_point < PSF_TBITS) { CSp_semaphore(1, &Psf_srvblk->psf_sem); /* exclusive */ ult_set_macro(&Psf_srvblk->psf_trace, flag, firstval, secondval); CSv_semaphore(&Psf_srvblk->psf_sem); } else { /* Do nothing if couln't get session control block */ if (sess_cb != (PSS_SESBLK *) NULL) { if(flag == PSS_ULM_DUMP_POOL) { ULM_RCB ulm_rcb; char buf[512]; SCF_CB scf_cb; ulm_rcb.ulm_poolid = Psf_srvblk->psf_poolid; ulm_rcb.ulm_facility = DB_PSF_ID; _VOID_ ulm_mappool(&ulm_rcb); ulm_print_pool(&ulm_rcb); STprintf(buf, "ULM Memory Pool Map and ULM Memory Print Pool for PSF has been \nwritten to the DBMS log file."); scf_cb.scf_length = sizeof(scf_cb); scf_cb.scf_type = SCF_CB_TYPE; scf_cb.scf_facility = DB_PSF_ID; scf_cb.scf_session = DB_NOSESSION; scf_cb.scf_nbr_union.scf_local_error = 0; scf_cb.scf_len_union.scf_blength = STlength(buf); scf_cb.scf_ptr_union.scf_buffer = buf; _VOID_ scf_call(SCC_TRACE, &scf_cb); } else { ult_set_macro(&sess_cb->pss_trace, flag, firstval, secondval); /* Yacc debugging requires a special call */ if (flag == PSS_YTRACE) psl_trace((PTR) sess_cb->pss_yacc, TRUE); } } } break; case DB_TR_OFF: /* First PSF_TBITS flags belong to server, others to session */ if (debug_cb->db_trace_point < PSF_TBITS) { CSp_semaphore(1, &Psf_srvblk->psf_sem); /* exclusive */ ult_clear_macro(&Psf_srvblk->psf_trace, flag); CSv_semaphore(&Psf_srvblk->psf_sem); } else { /* Do nothing if couldn't get session control block */ if (sess_cb != (PSS_SESBLK *) NULL) { ult_clear_macro(&sess_cb->pss_trace, flag); /* Yacc debugging requires a special call */ if (flag == PSS_YTRACE) psl_trace((PTR) sess_cb->pss_yacc, FALSE); } } break; case DB_TR_NOCHANGE: /* Do nothing */ break; default: return (E_DB_ERROR); } return (E_DB_OK); }
DB_STATUS dmx_secure( DMX_CB *dmx_cb) { DML_SCB *scb; DMX_CB *dmx = dmx_cb; DML_XCB *xcb; DB_STATUS status = E_DB_ERROR; i4 error,local_error; DMP_RCB *rcb; CL_ERR_DESC sys_err; STATUS cl_stat; i4 qnext; DMC_REPQ *repq = (DMC_REPQ *)(Dmc_rep + 1); i4 rep_iq_lock; i4 rep_maxlocks; DB_TAB_TIMESTAMP timestamp; LK_EVENT lk_event; CLRDBERR(&dmx->error); for (;;) { xcb = (DML_XCB *)dmx->dmx_tran_id; if (dm0m_check((DM_OBJECT *)xcb, (i4)XCB_CB) != E_DB_OK) { SETDBERR(&dmx->error, 0, E_DM003B_BAD_TRAN_ID); break; } if (dmx->dmx_dis_tran_id.db_dis_tran_id_type == 0) { SETDBERR(&dmx->error, 0, E_DM002A_BAD_PARAMETER); break; } if (xcb->xcb_state & (XCB_STMTABORT | XCB_TRANABORT)) { SETDBERR(&dmx->error, 0, E_DM0064_USER_ABORT); break; } if (xcb->xcb_state & XCB_WILLING_COMMIT) { SETDBERR(&dmx->error, 0, E_DM0132_ILLEGAL_STMT); break; } scb = xcb->xcb_scb_ptr; /* Clear user interrupt state in SCB. */ scb->scb_ui_state &= ~SCB_USER_INTR; /* Clear the force abort state of the SCB. */ if (xcb->xcb_state & XCB_FORCE_ABORT) scb->scb_ui_state &= ~SCB_FORCE_ABORT; /* ** If the transaction has written no Begin Transaction record, ** then force one to the log file now. */ if (xcb->xcb_flags & XCB_DELAYBT) { status = dmxe_writebt(xcb, TRUE, &dmx->error); if (status != E_DB_OK) { xcb->xcb_state |= XCB_TRANABORT; break; } } /* ** If the database is replicated, the input queue must ** be processed before putting the transaction in a ** willing commit state. ** ** All of this transaction's tables, including those ** associated with replication, must be closed and ** their pages tossed from the cache. ** ** This is the same processing as that for a ** "normal" commit. */ if ((xcb->xcb_odcb_ptr->odcb_dcb_ptr->dcb_status & DCB_S_REPLICATE) && (DMZ_SES_MACRO(32) == 0 || dmd_reptrace() == FALSE) && ((xcb->xcb_rep_input_q == NULL) || (xcb->xcb_rep_input_q == (DMP_RCB *)-1))) { if (dmf_svcb->svcb_rep_iqlock == DMC_C_ROW) rep_iq_lock = DM2T_RIX; else if (dmf_svcb->svcb_rep_iqlock == DMC_C_TABLE) rep_iq_lock = DM2T_X; else rep_iq_lock = DM2T_IX; /* allow a minimum maxlocks value of 50 ... */ if (dmf_svcb->svcb_rep_dtmaxlock > 50) rep_maxlocks = dmf_svcb->svcb_rep_dtmaxlock; /* ...but default to 100 */ else if (dmf_svcb->svcb_lk_maxlocks > 100) rep_maxlocks = dmf_svcb->svcb_lk_maxlocks; else rep_maxlocks = 100; status = dm2t_open(xcb->xcb_odcb_ptr->odcb_dcb_ptr, &xcb->xcb_odcb_ptr->odcb_dcb_ptr->rep_input_q, rep_iq_lock, DM2T_UDIRECT, DM2T_A_WRITE, (i4)0, rep_maxlocks, (i4)0, xcb->xcb_log_id, xcb->xcb_lk_id, (i4)0, (i4)0, (i4)0, &(xcb->xcb_tran_id), ×tamp, &(xcb->xcb_rep_input_q), (DML_SCB *)0, &dmx->error); if (status != E_DB_OK) { xcb->xcb_state |= XCB_TRANABORT; break; } } /* ** clean up replication input queue RCB */ if (xcb->xcb_rep_input_q) { HRSYSTIME curtime; bool list_ok = TRUE; i4 semaphore_status = -1; (VOID)TMhrnow(&curtime); /* If rep_txq_size=0, Dmc_rep will be NULL and we have to ** do the distribution synchronously now (kibro01) b118566 */ if (Dmc_rep == NULL) list_ok = FALSE; /* ** if we had the input queue open, then we need to distribute */ if (list_ok) { semaphore_status = CSp_semaphore(TRUE, &Dmc_rep->rep_sem); if (semaphore_status == E_DB_OK) { qnext = (Dmc_rep->queue_start == Dmc_rep->queue_end && repq[Dmc_rep->queue_start].active == 0 && repq[Dmc_rep->queue_start].tx_id == 0) ? Dmc_rep->queue_end : (Dmc_rep->queue_end + 1) % Dmc_rep->seg_size; if (qnext == Dmc_rep->queue_start && Dmc_rep->queue_start != Dmc_rep->queue_end) { list_ok = FALSE; } } else { TRdisplay("%@ dmxsecure() CSp_semaphore failed %d\n", semaphore_status); /* Error getting the semaphore, can't rely on the list */ list_ok = FALSE; } } if (!list_ok) { /* queue is full, print warning and distribute manually */ if (semaphore_status == E_DB_OK) CSv_semaphore(&Dmc_rep->rep_sem); /* If we have a queue and it's full, log that fact */ if (Dmc_rep) { uleFormat(NULL, W_DM9561_REP_TXQ_FULL, NULL, ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &local_error, 0); } status = dm2rep_qman(xcb->xcb_odcb_ptr->odcb_dcb_ptr, xcb->xcb_rep_remote_tx ? xcb->xcb_rep_remote_tx : (i4)xcb->xcb_tran_id.db_low_tran, &curtime, xcb->xcb_rep_input_q, xcb->xcb_lk_id, &dmx->error, FALSE); if (status != E_DB_OK) { if (dmx->error.err_code > E_DM004A_INTERNAL_ERROR) { uleFormat( &dmx->error, 0, NULL, ULE_LOG , NULL, (char * )NULL, 0L, (i4 *)NULL, &local_error, 0); SETDBERR(&dmx->error, 0, E_DM957F_REP_DISTRIB_ERROR); } xcb->xcb_state |= XCB_TRANABORT; break; } } else { /* we have mutex and an entry we can use, so fill out entry */ /* we assume we are only accessing one db in this tx */ STRUCT_ASSIGN_MACRO(xcb->xcb_odcb_ptr->odcb_dcb_ptr->dcb_name, repq[qnext].dbname); /* ** use remote TX if it's set (by the replication server) */ if (xcb->xcb_rep_remote_tx) repq[qnext].tx_id = xcb->xcb_rep_remote_tx; else repq[qnext].tx_id = (i4)xcb->xcb_tran_id.db_low_tran; repq[qnext].active = FALSE; MEcopy((char *)&curtime, sizeof(HRSYSTIME), (char *)&repq[qnext].trans_time); Dmc_rep->queue_end = qnext; CSv_semaphore(&Dmc_rep->rep_sem); /* ** signal the queue management thread(s) */ lk_event.type_high = REP_READQ; lk_event.type_low = 0; lk_event.value = REP_READQ_VAL; cl_stat = LKevent(LK_E_CLR | LK_E_CROSS_PROCESS, xcb->xcb_lk_id, &lk_event, &sys_err); if (cl_stat != OK) { uleFormat(NULL, cl_stat, &sys_err, ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0); uleFormat(&dmx->error, E_DM904B_BAD_LOCK_EVENT, &sys_err, ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 3, 0, LK_E_CLR, 0, REP_READQ, 0, xcb->xcb_lk_id); status = E_DB_ERROR; break; } } /* ** user updates to the input queue will cause xcb_rep_input_q to ** be set to -1, the table will already be closed by the user in ** this case */ if (xcb->xcb_rep_input_q != (DMP_RCB *)-1) { status = dm2t_close(xcb->xcb_rep_input_q, (i4)0, &dmx->error); if (status != E_DB_OK) { if (dmx->error.err_code != E_DM004A_INTERNAL_ERROR) { uleFormat( &dmx->error, 0, NULL, ULE_LOG , NULL, (char * )NULL, 0L, (i4 *)NULL, &local_error, 0); SETDBERR(&dmx->error, 0, E_DM009A_ERROR_SECURE_TRAN); } xcb->xcb_state |= XCB_TRANABORT; return (status); } xcb->xcb_rep_input_q = (DMP_RCB*)NULL; } } /* Close all open tables and destroy all open temporary tables. */ while (xcb->xcb_rq_next != (DMP_RCB*) &xcb->xcb_rq_next) { /* Get next RCB. */ rcb = (DMP_RCB *)((char *)xcb->xcb_rq_next - (char *)&(((DMP_RCB*)0)->rcb_xq_next)); /* Remove from the XCB. */ rcb->rcb_xq_next->rcb_q_prev = rcb->rcb_xq_prev; rcb->rcb_xq_prev->rcb_q_next = rcb->rcb_xq_next; /* Deallocate the RCB. */ status = dm2t_close(rcb, (i4)0, &dmx->error); if (status != E_DB_OK) { if (dmx->error.err_code != E_DM004A_INTERNAL_ERROR) { uleFormat( &dmx->error, 0, NULL, ULE_LOG , NULL, (char * )NULL, 0L, (i4 *)NULL, &local_error, 0); SETDBERR(&dmx->error, 0, E_DM009A_ERROR_SECURE_TRAN); } xcb->xcb_state |= XCB_TRANABORT; return (status); } } /* Now prepare to commit the transaction. */ STRUCT_ASSIGN_MACRO(dmx->dmx_dis_tran_id, xcb->xcb_dis_tran_id); status = dmxe_secure(&xcb->xcb_tran_id, &xcb->xcb_dis_tran_id, xcb->xcb_log_id, xcb->xcb_lk_id, &dmx->error); if (status != E_DB_OK) { if (dmx->error.err_code > E_DM_INTERNAL) { uleFormat(&dmx->error, 0, NULL, ULE_LOG, NULL, (char * )NULL, (i4)0, (i4 *)NULL, &error, 0); SETDBERR(&dmx->error, 0, E_DM009A_ERROR_SECURE_TRAN); } xcb->xcb_state |= XCB_TRANABORT; return (E_DB_ERROR); } /* Mark the state of the transaction in xcb to WILLING COMMIT. */ xcb->xcb_x_type |= XCB_DISTRIBUTED; xcb->xcb_state |= XCB_WILLING_COMMIT; return (E_DB_OK); } return (status); }
/*{ ** Name: LGK_initialize() - initialize the lg/lk shared mem segment. ** ** Description: ** This routine is called by the LGinitialize or LKinitialize routine. IT ** assumes that a previous caller has allocated the shared memory segment. ** ** If it discovers that the shared memory segment has not yet been ** initialized, it calls the LG and LK initialize-memory routines to do so. ** ** Inputs: ** flag - bit mask of: ** LOCK_LGK_MEMORY to lock the shared data segment ** LGK_IS_CSP if process is CSP process this node. ** ** Outputs: ** sys_err - place for system-specific error information. ** ** Returns: ** OK - success ** !OK - failure (CS*() routine failure, segment not mapped, ...) ** ** History: ** Summer, 1992 (bryanp) ** Working on the new portable logging and locking system. ** 19-oct-1992 (bryanp) ** Check memory version number when attaching. ** 22-oct-1992 (bryanp) ** Change LGLKDATA.MEM to lglkdata.mem. ** 23-Oct-1992 (daveb) ** name the semaphore too. ** 13-feb-1993 (keving) ** Remove support for II_LGK_MEMORY_SIZE. If II_LG_MEMSIZE ** is not set then calculate memory size from PM values. ** 24-may-1993 (bryanp) ** If the shared memory is the wrong version, don't install the ** at_exit handlers (the rundown routines won't be able to interpret ** the memory properly). ** 26-jul-1993 (jnash) ** Add 'flag' param lock the LGK data segment. ** 20-sep-1993 (bryanp) ** In addition to calling PCatexit, call (on VMS) sys$dclexh, since ** there are some situations (image death and image rundown without ** process rundown) which are caught neither by PCatexit (since ** PCexit isn't run) nor by check-dead threads (since process ** rundown never happened). This fixes a hole where an access- ** violating ckpdb or auditdb command never got cleaned up. ** 31-jan-1994 (bryanp) ** Back out a few "features" which are proving countereffective: ** 1) Don't bother checking mem_creator_pid to see if the previous ** creator of the shared memory has died. This was an attempt to ** gracefully re-use sticky shared memory following a system crash, ** but it is suspected as being the culprit in a series of system ** failures by re-initializing the shared memory at inopportune ** times. ** 2) Don't complain if the shared memory already exists but is of a ** different size than you expected. Just go ahead and try to use ** it anyway. ** 21-feb-1994 (bryanp) ** Reverse item (1) of the above 31-jan-1994 change and re-enable the ** graceful re-use of shared memory. People weren't happy with ** having to run ipcclean and csinstall all the time. ** 23-may-1994 (bryanp) ** On VMS, disable ^Y for LG/LK-aware processes. We don't want to allow ** ^Y because you might interrupt the process right in the middle ** of an LG or LK operation, while holding the shared memory ** semaphore, and this would then wedge the whole installation. ** ** 17-May-1994 (daveb) 59127 ** Attach lgk_mem semaphore if we're attaching to the segment. ** 30-jan-1995 (lawst01) bug 61984 ** Use memory needed calculation from the 'lgk_calculate_size' ** function to determine the size of the shared memory pool for ** locking and locking. If the II_LG_MEMSIZE variable is specified ** with a value larger than needed use the supplied value. If ** lgk_calculate_size is unable to calculate a size then use the ** magic number of 400000. In addition issue a warning message ** and continue executing in the event the number of pages ** allocated is less than the number requested. ** 24-apr-1997 (nanpr01) ** Reinstate Bryanp's change. In the process of fixing bug 61984 ** by Steve Lawrence and subsequent undo of Steve's fix by Nick ** Ireland on 25-jun-96 (nick) caused the if 0 code removed. ** Part of the Steve's change was not reinstated such as not returning ** the status and exit and continue. ** 1. Don't complain if the shared memory already exists but is of a ** different size than you expected. Just go ahead and try to use ** it. ** 18-aug-1998 (hweho01) ** Reclaim the kernel resource if LG/LK shared memory segment is ** reinitialized. If the shared segment is re-used (the previous creator ** of the shared segment has died), the cross-process semaphores get ** initialized more than once at the same locations. That cause the ** kernel resource leaks on DG/UX (OS release 4.11MU04). To fix the ** problem, CS_cp_sem_cleanup() is called to destroy all the ** semaphores before LG/LK shraed segment get recreated. ** CS_cp_sem_cleanup() is made dependent on xCL_NEED_SEM_CLEANUP and ** OS_THREADS_USED, it returns immediately for most platforms. ** 27-Mar-2000 (jenjo02) ** Added test for crossed thread types, refuse connection ** to LGK memory with E_DMA811_LGK_MT_MISMATCH. ** 18-apr-2001 (devjo01) ** s103715 (Portable cluster support) ** - Add CX mem requirement calculations. ** - Add LGK_IS_CSP flag to indicate that LGK memory is being ** initialized for a CSP process. ** - Add basic CX initialization. ** 19-sep-2002 (devjo01) ** If running NUMA clustered allocate memory out of local RAD. ** 30-Apr-2003 (jenjo02) ** Rearchitected to silence long-tolerated race conditions. ** BUG 110121. ** 27-feb-2004 (devjo01) ** Rework allocation of CX shared memory to be compatible ** with race condition fix introduced for bug 110121. ** 29-Dec-2008 (jonj) ** If lgk_calculate_size() returns FAIL, the total memory ** needed exceeds MAX_SIZE_TYPE and we can't continue, but ** tell what we can about the needs of the various bits of ** memory before quitting. ** 06-Aug-2009 (wanfr01) ** Bug 122418 - Return E_DMA812 if LOCK_LGK_MUST_ATTACH is ** is passed in and memory segment does not exist ** 20-Nov-2009 (maspa05) bug 122642 ** In order to synchronize creation of UUIDs across servers added ** a semaphore and a 'last time' variable into LGK memory. ** 14-Dec-2009 (maspa05) bug 122642 ** #ifdef out the above change for Windows. The rest of the change ** does not apply to Windows so the variables aren't defined. */ STATUS LGK_initialize( i4 flag, CL_ERR_DESC *sys_err, char *lgk_info) { PTR ptr; SIZE_TYPE memleft; SIZE_TYPE size; STATUS ret_val; STATUS mem_exists; char mem_name[15]; SIZE_TYPE allocated_pages; i4 me_flags; i4 me_locked_flag; SIZE_TYPE memory_needed; char *nm_string; SIZE_TYPE pages; LGK_MEM *lgk_mem; i4 err_code; SIZE_TYPE min_memory; i4 retries; i4 i; i4 attached; PID *my_pid_slot; i4 clustered; u_i4 nodes; SIZE_TYPE cxmemreq; PTR pcxmem; LGLK_INFO lgkcount; char instid[4]; CL_CLEAR_ERR(sys_err); /* ** if LGK_base is set then this routine has already been called. It is ** set up so that both LGiniitalize and LKinitialize calls it, but only ** the first call does anything. */ if (LGK_base.lgk_mem_ptr) return(OK); PCpid( &LGK_my_pid ); memory_needed = 0; NMgtAt("II_LG_MEMSIZE", &nm_string); if (nm_string && *nm_string) #if defined(LP64) if (CVal8(nm_string, (long*)&memory_needed)) #else if (CVal(nm_string, (i4 *)&memory_needed)) #endif /* LP64 */ memory_needed = 0; /* Always calculate memory needed from PM resource settings */ /* and compare with supplied value, if supplied value is less */ /* than minimum then use minimum */ min_memory = 0; if ( OK == lgk_get_counts(&lgkcount, FALSE)) { if ( lgk_calculate_size(FALSE, &lgkcount, &min_memory) ) { /* ** Memory exceeds MAX_SIZE_TYPE, can't continue. ** ** Do calculation again, this time with "wordy" ** so user can see allocation bits, then quit. */ lgk_calculate_size(TRUE, &lgkcount, &min_memory); return (E_DMA802_LGKINIT_ERROR); } } if (min_memory) memory_needed = (memory_needed < min_memory) ? min_memory : memory_needed; else memory_needed = (memory_needed < 400000 ) ? 400000 : memory_needed; clustered = (i4)CXcluster_enabled(); cxmemreq = 0; if ( clustered ) { if ( OK != CXcluster_nodes( &nodes, NULL ) ) nodes = 0; cxmemreq = CXshm_required( 0, nodes, lgkcount.lgk_max_xacts, lgkcount.lgk_max_locks, lgkcount.lgk_max_resources ); if ( MAX_SIZE_TYPE - memory_needed < cxmemreq ) { /* ** Memory exceeds MAX_SIZE_TYPE, can't continue. ** ** Do calculation again, this time with "wordy" ** so user can see allocation bits, then quit. */ SIprintf("Total LG/LK/CX allocation exceeds max of %lu bytes by %lu\n" "Adjust logging/locking configuration values and try again\n", MAX_SIZE_TYPE, cxmemreq - (MAX_SIZE_TYPE - memory_needed)); lgk_calculate_size(TRUE, &lgkcount, &min_memory); return (E_DMA802_LGKINIT_ERROR); } memory_needed += cxmemreq; } if ( memory_needed < MAX_SIZE_TYPE - ME_MPAGESIZE ) pages = (memory_needed + ME_MPAGESIZE - 1) / ME_MPAGESIZE; else pages = memory_needed / ME_MPAGESIZE; /* ** Lock the LGK segment if requested to do so */ if (flag & LOCK_LGK_MEMORY) me_locked_flag = ME_LOCKED_MASK; else me_locked_flag = 0; me_flags = (me_locked_flag | ME_MSHARED_MASK | ME_IO_MASK | ME_CREATE_MASK | ME_NOTPERM_MASK | ME_MZERO_MASK); if (CXnuma_user_rad()) me_flags |= ME_LOCAL_RAD; STcopy("lglkdata.mem", mem_name); /* ** In general, we just want to attach to the shared memory and detect if ** we are the first process to do so. However, there are ugly race ** conditions to consider, as well as complications because the shared ** memory may be left around following a system crash. ** ** First we attempt to create the shared memory. Usually it already exists, ** so we check for and handle the case of "already exists". */ /* ** (jenjo02) ** ** Restructured to better handle all those ugly race conditions ** which are easily reproduced by running two scripts, one that ** continuously executes "lockstat" while the other is starting ** and stopping Ingres. ** ** For example, ** ** lockstat A acquires and init's the memory ** RCP attaches to "A" memory ** lockstat A terminates normally ** lockstat B attaches to "A" memory, sees that ** "A"s pid is no longer alive, and ** reinitializes the memory, much to ** the RCP's chagrin. ** or (more commonly) ** ** lockstat A acquires and begins to init the mem ** RCP attaches to "A" memory which is ** still being zero-filled by lockstat, ** checks the version number (zero), ** and fails with a E_DMA434 mismatch. ** ** The fix utilizes the mem_ext_sem to synchronize multiple ** processes; if the semaphore hasn't been initialized or ** if mem_version_no is zero, we'll wait one second and retry, ** up to 60 seconds before giving up. This gives the creating ** process time to complete initialization of the memory. ** ** Up to LGK_MAX_PIDS are allowed to attach to the shared ** memory. When a process attaches it sets its PID in the ** first vacant slot in lgk_mem->mem_pid[]; if there are ** no vacant slots, the attach is refused. When the process ** terminates normally by calling LGK_rundown(), it zeroes ** its PID slot. ** ** When attaching to an existing segment, we check if ** there are any live processes still using the memory; ** if so, we can't destroy it (no matter who created it). ** If there are no live processes attached to the memory, ** we destroy and reallocate it (based on current config.dat ** settings). */ for ( retries = 0; ;retries++ ) { LGK_base.lgk_mem_ptr = (PTR)NULL; /* Give up if unable to get memory in one minute */ #if defined(conf_CLUSTER_BUILD) if (retries > 1) #else if ( retries ) #endif { if ( retries < 60 ) PCsleep(1000); else { /* Another process has it blocked way too long */ uleFormat(NULL, E_DMA800_LGKINIT_GETMEM, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0); /* Unable to attach allocated shared memory segment. */ return (E_DMA802_LGKINIT_ERROR); } } ret_val = MEget_pages(me_flags, pages, mem_name, (PTR*)&lgk_mem, &allocated_pages, sys_err); if ( mem_exists = ret_val ) { if (ret_val == ME_ALREADY_EXISTS) { ret_val = MEget_pages((me_locked_flag | ME_MSHARED_MASK | ME_IO_MASK), pages, mem_name, (PTR*)&lgk_mem, &allocated_pages, sys_err); #if defined(conf_CLUSTER_BUILD) if (ret_val && !retries) continue; /* try one more time */ #endif } if (ret_val) { uleFormat(NULL, ret_val, sys_err, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0); uleFormat(NULL, E_DMA800_LGKINIT_GETMEM, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0); /* Unable to attach allocated shared memory segment. */ return (E_DMA802_LGKINIT_ERROR); } } else if (flag & LOCK_LGK_MUST_ATTACH) { /* Do not use the shared segment you just allocated */ MEfree_pages((PTR)lgk_mem, allocated_pages, sys_err); return (E_DMA812_LGK_NO_SEGMENT); } size = allocated_pages * ME_MPAGESIZE; /* Expose this process to the memory */ LGK_base.lgk_mem_ptr = (PTR)lgk_mem; if ( mem_exists ) { /* ** Memory exists. ** ** Try to acquire the semaphore. If it's ** uninitialzed, retry from the top. ** ** If the version is zero, then another ** process is initializing the memory; ** keep retrying until the version is ** filled in. ** */ if ( ret_val = CSp_semaphore(1, &lgk_mem->mem_ext_sem) ) { if ( ret_val != E_CS000A_NO_SEMAPHORE ) { uleFormat(NULL, ret_val, sys_err, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0); ret_val = E_DMA802_LGKINIT_ERROR; break; } continue; } /* Retry if still being init'd by another process */ if ( !lgk_mem->mem_version_no ) { CSv_semaphore(&lgk_mem->mem_ext_sem); continue; } /* ** Check pids which appear to be attached to ** the memory: ** ** If any process is still alive, then we ** assume the memory is consistent and use it. ** ** If a process is now dead, it terminated ** without going through LGK_rundown ** to zero its PID slot, zero it now. ** ** If there are no live PIDs attached to ** the memory, we destroy and recreate it. */ my_pid_slot = (PID*)NULL; attached = 0; for ( i = 0; i < LGK_MAX_PIDS; i++ ) { if ( lgk_mem->mem_pid[i] && PCis_alive(lgk_mem->mem_pid[i]) ) { attached++; } else { /* Vacate the slot */ if (lgk_mem->mem_pid[i]) { uleFormat(NULL, E_DMA499_DEAD_PROCESS_INFO, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2, 0, lgk_mem->mem_pid[i], 0, lgk_mem->mem_info[i].info_txt); } lgk_mem->mem_pid[i] = (PID)0; lgk_mem->mem_info[i].info_txt[0] = EOS; /* Use first vacant slot for this process */ if ( !my_pid_slot ) { my_pid_slot = &lgk_mem->mem_pid[i]; LGK_base.lgk_pid_slot = i; } } /* Quit when both questions answered */ if ( attached && my_pid_slot ) break; } /* If no living pids attached, destroy/reallocate */ if ( !attached ) { CSv_semaphore(&lgk_mem->mem_ext_sem); if ( LGK_destroy(allocated_pages, sys_err) ) { ret_val = E_DMA802_LGKINIT_ERROR; break; } continue; } /* All attached pids alive? */ if ( !my_pid_slot ) { /* ... then there's no room for this process */ uleFormat(NULL, E_DMA80A_LGK_ATTACH_LIMIT, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 1, 0, attached); ret_val = E_DMA802_LGKINIT_ERROR; } else if (lgk_mem->mem_version_no != LGK_MEM_VERSION_CURRENT) { uleFormat(NULL, E_DMA434_LGK_VERSION_MISMATCH, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2, 0, lgk_mem->mem_version_no, 0, LGK_MEM_VERSION_CURRENT); ret_val = E_DMA435_WRONG_LGKMEM_VERSION; } /* ** Don't allow mixed connections of MT/non-MT processes. ** Among other things, the mutexing mechanisms are ** incompatible! */ else if ( (CS_is_mt() && (lgk_mem->mem_status & LGK_IS_MT) == 0) || (!CS_is_mt() && lgk_mem->mem_status & LGK_IS_MT) ) { uleFormat(NULL, E_DMA811_LGK_MT_MISMATCH, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2, 0, (lgk_mem->mem_status & LGK_IS_MT) ? "OS" : "INTERNAL", 0, (CS_is_mt()) ? "OS" : "INTERNAL"); ret_val = E_DMA802_LGKINIT_ERROR; } else { /* ** CX memory (if any) will lie immediately past LGK header. */ pcxmem = (PTR)(lgk_mem + 1); pcxmem = (PTR)ME_ALIGN_MACRO(pcxmem, sizeof(ALIGN_RESTRICT)); LGK_base.lgk_lkd_ptr = (char *)LGK_base.lgk_mem_ptr + lgk_mem->mem_lkd; LGK_base.lgk_lgd_ptr = (char *)LGK_base.lgk_mem_ptr + lgk_mem->mem_lgd; /* Stuff our pid in first vacant slot */ *my_pid_slot = LGK_my_pid; STlcopy(lgk_info, lgk_mem->mem_info[i].info_txt, LGK_INFO_SIZE-1); } #if defined(VMS) || defined(UNIX) /* set up pointers to reference the uuid mutex and last time * variable */ if (!ID_uuid_sem_ptr) ID_uuid_sem_ptr=&lgk_mem->id_uuid_sem; if (!ID_uuid_last_time_ptr) ID_uuid_last_time_ptr=&lgk_mem->uuid_last_time; if (!ID_uuid_last_cnt_ptr) ID_uuid_last_cnt_ptr=&lgk_mem->uuid_last_cnt; #endif CSv_semaphore(&lgk_mem->mem_ext_sem); } else { /* Memory did not exist */ /* Zero the version to keep other processes out */ lgk_mem->mem_version_no = 0; #if defined(VMS) || defined(UNIX) /* set up the uuid mutex and last time pointers to * reference the objects in shared memory */ { STATUS id_stat; ID_uuid_sem_ptr=&lgk_mem->id_uuid_sem; ID_uuid_last_time_ptr=&lgk_mem->uuid_last_time; ID_uuid_last_cnt_ptr=&lgk_mem->uuid_last_cnt; *ID_uuid_last_cnt_ptr=0; ID_UUID_SEM_INIT(ID_uuid_sem_ptr,CS_SEM_MULTI,"uuid sem", &id_stat); } #endif /* ... then initialize the mutex */ CSw_semaphore(&lgk_mem->mem_ext_sem, CS_SEM_MULTI, "LGK mem ext sem" ); /* Record if memory created for MT or not */ if ( CS_is_mt() ) lgk_mem->mem_status = LGK_IS_MT; /* ** memory is as follows: ** ** -----------------------------------------------------------| ** | LGK_MEM struct (keep track of this mem) | ** | | ** -----------------------------------------------------------| ** | If a clustered installation memory reserved for CX | ** | | ** ------------------------------------------------------------ ** | LKD - database of info for lk system | ** | | ** ------------------------------------------------------------ ** | LGD - database of info for lg system | ** | | ** ------------------------------------------------------------ ** | memory manipulated by LGKm_* routines for structures used | ** | by both the lk and lg systems. | ** | | ** ------------------------------------------------------------ */ /* put the LGK_MEM struct at head of segment leaving ptr pointing ** at next aligned piece of memory */ /* ** CX memory (if any) will lie immediately past LGK header. */ pcxmem = (PTR)(lgk_mem + 1); pcxmem = (PTR)ME_ALIGN_MACRO(pcxmem, sizeof(ALIGN_RESTRICT)); LGK_base.lgk_lkd_ptr = pcxmem + cxmemreq; LGK_base.lgk_lkd_ptr = (PTR) ME_ALIGN_MACRO(LGK_base.lgk_lkd_ptr, sizeof(ALIGN_RESTRICT)); lgk_mem->mem_lkd = (i4)((char *)LGK_base.lgk_lkd_ptr - (char *)LGK_base.lgk_mem_ptr); LGK_base.lgk_lgd_ptr = (PTR) ((char *) LGK_base.lgk_lkd_ptr + sizeof(LKD)); LGK_base.lgk_lgd_ptr = (PTR) ME_ALIGN_MACRO(LGK_base.lgk_lgd_ptr, sizeof(ALIGN_RESTRICT)); lgk_mem->mem_lgd = (i4)((char *)LGK_base.lgk_lgd_ptr - (char *)LGK_base.lgk_mem_ptr); /* now initialize the rest of memory for allocation */ /* how much memory is left? */ ptr = ((char *)LGK_base.lgk_lgd_ptr + sizeof(LGD)); memleft = size - (((char *) ptr) - ((char *) LGK_base.lgk_mem_ptr)); if ( (ret_val = lgkm_initialize_mem(memleft, ptr)) == OK && (ret_val = LG_meminit(sys_err)) == OK && (ret_val = LK_meminit(sys_err)) == OK ) { /* Clear array of attached pids and pid info */ for ( i = 0; i < LGK_MAX_PIDS; i++ ) { lgk_mem->mem_pid[i] = (PID)0; lgk_mem->mem_info[i].info_txt[0] = EOS; } /* Set the creator pid */ LGK_base.lgk_pid_slot = 0; lgk_mem->mem_creator_pid = LGK_my_pid; /* Set the version, releasing other processes */ lgk_mem->mem_version_no = LGK_MEM_VERSION_CURRENT; } else { uleFormat(NULL, ret_val, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0); ret_val = E_DMA802_LGKINIT_ERROR; /* Destroy the shared memory */ LGK_destroy(allocated_pages, sys_err); } } if ( ret_val == OK ) { PCatexit(LGK_rundown); if ( clustered ) { /* ** Perform preliminary cluster connection and CX memory init. */ /* Get installation code */ NMgtAt("II_INSTALLATION", &nm_string); if ( nm_string ) { instid[0] = *(nm_string); instid[1] = *(nm_string+1); } else { instid[0] = 'A'; instid[1] = 'A'; } instid[2] = '\0'; ret_val = CXinitialize( instid, pcxmem, flag & LGK_IS_CSP ); if ( ret_val ) { /* Report error returned from CX */ uleFormat(NULL, ret_val, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0 ); break; } } #ifdef VMS { static $EXHDEF exit_block; i4 ctrl_y_mask = 0x02000000; /* ** On VMS, programs like the dmfjsp and logstat run as images in ** the shell process. That is, the system doesn't start and stop ** a process for each invocation of the program, it just starts ** and stops an image in the same process. This means that if ** the program should die, the image may be rundown but the process ** will remain, which means that the check-dead threads of other ** processes in the installation will not feel that they need to ** rundown this process, since it's still alive. ** ** By declaring an exit handler, which will get a chance to run ** even if PCexit isn't called, we improve our chances of getting ** to perform rundown processing if we should die unexpectedly. ** ** Furthermore, we ask DCL to disable its ^Y processing, which ** lessens the chance that the user will interrupt us while we ** are holding the semaphore. */ exit_block.exh$g_func = LGK_rundown; exit_block.exh$l_argcount = 1; exit_block.exh$gl_value = &exit_block.exh$l_status; if (sys$dclexh(&exit_block) != SS$_NORMAL) ret_val = FAIL; lib$disable_ctrl(&ctrl_y_mask, 0); } #endif } break; } if ( ret_val ) LGK_base.lgk_mem_ptr = NULL; return(ret_val); }
DB_STATUS qss_end_session( QSF_RCB *qsf_rb) { STATUS status = E_DB_OK; QSF_CB *scb = qsf_rb->qsf_scb; QSF_RCB int_qsf_rb; QSO_OBJ_HDR *objects = (QSO_OBJ_HDR *) scb->qss_obj_list; QSO_OBJ_HDR *obj; i4 error; i4 count; #ifdef xDEBUG QSF_CB *prevses; QSF_CB *nextses; i4 trace_003; #endif /* xDEBUG */ CLRDBERR(&qsf_rb->qsf_error); /* Toss any uncommitted named session-owned objects first. ** There shouldn't be any, if QEF did its job right, but who knows. ** The important thing is that we NOT have objects pretending to be ** on a session list when the session has ended. */ int_qsf_rb.qsf_sid = qsf_rb->qsf_sid; int_qsf_rb.qsf_scb = scb; CLRDBERR(&int_qsf_rb.qsf_error); (void) qsf_clrsesobj(&int_qsf_rb); /* ** Look for orphaned objects that should not exist and destroy unshareable ** named objects. */ count = QSF_MAX_ORPHANS; while (objects != (QSO_OBJ_HDR *) NULL && --count > 0) { STATUS status; QSO_OBJ_HDR *current_obj = objects; objects = objects->qso_obnext; if (current_obj->qso_obid.qso_lname == 0) { char *type; switch (current_obj->qso_obid.qso_type) { case QSO_QTEXT_OBJ: type = "Query Text"; break; case QSO_QTREE_OBJ: type = "Query Tree"; break; case QSO_QP_OBJ: type = "Query Plan"; break; case QSO_SQLDA_OBJ: type = "SQLDA"; break; case QSO_ALIAS_OBJ: type = "Alias"; break; default: type = "Unknown"; break; } /* Report the orphaned object. */ uleFormat( &int_qsf_rb.qsf_error, E_QS001E_ORPHANED_OBJ, NULL, (i4) ULE_LOG, NULL, NULL, (i4) 0, NULL, &error, 1, 0, type); } int_qsf_rb.qsf_obj_id = current_obj->qso_obid; int_qsf_rb.qsf_lk_state = QSO_EXLOCK; int_qsf_rb.qsf_sid = qsf_rb->qsf_sid; int_qsf_rb.qsf_scb = scb; status = qso_lock(&int_qsf_rb); if (DB_FAILURE_MACRO(status)) { uleFormat( &int_qsf_rb.qsf_error, 0, NULL, (i4) ULE_LOG, NULL, NULL, (i4) 0, NULL, &error, 0); } int_qsf_rb.qsf_lk_id = current_obj->qso_lk_id; status = qso_destroy(&int_qsf_rb); if (DB_FAILURE_MACRO(status)) { uleFormat( &int_qsf_rb.qsf_error, 0, NULL, (i4) ULE_LOG, NULL, NULL, (i4) 0, NULL, &error, 0); } } if (count <= 0) { uleFormat( &int_qsf_rb.qsf_error, E_QS001F_TOO_MANY_ORPHANS, NULL, (i4) ULE_LOG, NULL, NULL, (i4) 0, NULL, &error, 0); } #ifdef xDEBUG if (Qsr_scb->qsr_tracing && qst_trcheck(&scb, QSF_001_ENDSES_OBJQ)) { DB_ERROR save_err = qsf_rb->qsf_error; TRdisplay("<<< Dumping QSF object queue before ending session >>>\n"); (void) qsd_obq_dump(qsf_rb); qsf_rb->qsf_error = save_err; } trace_003 = ( Qsr_scb->qsr_tracing && qst_trcheck(&scb, QSF_003_CHK_SCB_LIST) ); /* Must check before ** we blow away the ** the session CB. */ #endif /* xDEBUG */ /* First, wait to get exclusive access to QSF's SERVER CONTROL BLOCK */ /* ----------------------------------------------------------------- */ if (CSp_semaphore((i4) TRUE, &Qsr_scb->qsr_psem)) { SETDBERR(&qsf_rb->qsf_error, 0, E_QS0008_SEMWAIT); /* Return now, instead of attempting to do a v() */ return (E_DB_ERROR); } /* Do a quick run through the global LRU-able (persistent) object list ** and clear the session if it's us. This indicates that the object ** is not on any session list, and prevents someone else from believing ** a stale qso_session. */ obj = Qsr_scb->qsr_1st_lru; while (obj != NULL) { if (obj->qso_session == scb) obj->qso_session = NULL; obj = obj->qso_lrnext; } /* Now remove this session from QSF's server CB */ /* -------------------------------------------- */ if (scb == Qsr_scb->qsr_se1st) Qsr_scb->qsr_se1st = scb->qsf_next; else scb->qsf_prev->qsf_next = scb->qsf_next; if (scb->qsf_next != NULL) scb->qsf_next->qsf_prev = scb->qsf_prev; scb->qsf_prev = scb->qsf_next = NULL; Qsr_scb->qsr_nsess--; #ifdef xDEBUG if (trace_003) { /* This code just verifies that the session CB list is intact */ /* ---------------------------------------------------------- */ count = Qsr_scb->qsr_nsess; prevses = NULL; nextses = Qsr_scb->qsr_se1st; while (count-- > 0) { if (nextses == NULL) { TRdisplay("*** Not enough QSF session CBs found"); TRdisplay(" while ending a session.\n"); SETDBERR(&qsf_rb->qsf_error, 0, E_QS9999_INTERNAL_ERROR); return (E_DB_FATAL); } if ( (nextses->qsf_prev != prevses) || (nextses->qsf_ascii_id != QSFCB_ASCII_ID) || (nextses->qsf_type != QSFCB_CB) || (nextses->qsf_length != sizeof(QSF_CB)) ) { TRdisplay("*** QSF's session CB list found trashed"); TRdisplay(" while ending a session.\n"); SETDBERR(&qsf_rb->qsf_error, 0, E_QS9999_INTERNAL_ERROR); return (E_DB_FATAL); } prevses = nextses; nextses = nextses->qsf_next; } if (nextses != NULL) { TRdisplay("*** Too many QSF session CBs detected"); TRdisplay(" while ending a session.\n"); SETDBERR(&qsf_rb->qsf_error, 0, E_QS9999_INTERNAL_ERROR); return (E_DB_FATAL); } } #endif /* xDEBUG */ status = E_DB_OK; /* Release exclusive access to QSF's SERVER CONTROL BLOCK */ /* ------------------------------------------------------ */ if (CSv_semaphore(&Qsr_scb->qsr_psem)) { status = E_DB_ERROR; SETDBERR(&qsf_rb->qsf_error, 0, E_QS0004_SEMRELEASE); } return (status); }
DB_STATUS qss_bgn_session( QSF_RCB *qsf_rb ) { STATUS status; QSF_CB *scb = qsf_rb->qsf_scb; #ifdef xDEBUG i4 n; QSF_CB *prevses; QSF_CB *nextses; #endif /* xDEBUG */ CLRDBERR(&qsf_rb->qsf_error); Qsr_scb = (QSR_CB *) qsf_rb->qsf_server; if (scb == NULL) { SETDBERR(&qsf_rb->qsf_error, 0, E_QS001B_NO_SESSION_CB); return (E_DB_SEVERE); } /* Before anything, set up the session CB's standard header portion */ /* ---------------------------------------------------------------- */ scb->qsf_ascii_id = QSFCB_ASCII_ID; scb->qsf_type = QSFCB_CB; scb->qsf_length = sizeof(QSF_CB); scb->qsf_prev = NULL; /* Update the other structure information. */ /* ---------------------------------------- */ scb->qss_obj_list = (QSO_OBJ_HDR *) NULL; scb->qss_master = (QSO_MASTER_HDR *) NULL; scb->qss_snamed_list = (QSO_OBJ_HDR *) NULL; /* Init the tracing vector */ /* ----------------------- */ ult_init_macro(&scb->qss_trstruct.trvect, 128, 0, 8); /* Get exclusive access to QSF's SERVER CONTROL BLOCK */ /* -------------------------------------------------- */ if (CSp_semaphore((i4) TRUE, &Qsr_scb->qsr_psem)) { SETDBERR(&qsf_rb->qsf_error, 0, E_QS0008_SEMWAIT); /* Return now, instead of attempting to do a v() */ return (E_DB_ERROR); } /* Make the session known to QSF's server CB */ /* ----------------------------------------- */ if (Qsr_scb->qsr_se1st != (QSF_CB *) NULL) Qsr_scb->qsr_se1st->qsf_prev = scb; scb->qsf_next = Qsr_scb->qsr_se1st; Qsr_scb->qsr_se1st = scb; Qsr_scb->qsr_nsess++; if (Qsr_scb->qsr_nsess > Qsr_scb->qsr_mxsess) Qsr_scb->qsr_mxsess = Qsr_scb->qsr_nsess; #ifdef xDEBUG if (Qsr_scb->qsr_tracing && qst_trcheck(&scb, QSF_003_CHK_SCB_LIST)) { /* This code just verifies that the session CB list is intact */ /* ---------------------------------------------------------- */ n = Qsr_scb->qsr_nsess; prevses = NULL; nextses = Qsr_scb->qsr_se1st; while (n-- > 0) { if (nextses == NULL) { TRdisplay("*** Not enough QSF session CBs found"); TRdisplay(" while beginning a session.\n"); SETDBERR(&qsf_rb->qsf_error, 0, E_QS9999_INTERNAL_ERROR); return (E_DB_FATAL); } if ( (nextses->qsf_prev != prevses) || (nextses->qsf_ascii_id != QSFCB_ASCII_ID) || (nextses->qsf_type != QSFCB_CB) || (nextses->qsf_length != sizeof(QSF_CB)) ) { TRdisplay("*** QSF's session CB list found trashed"); TRdisplay(" while beginning a session.\n"); SETDBERR(&qsf_rb->qsf_error, 0, E_QS9999_INTERNAL_ERROR); return (E_DB_FATAL); } prevses = nextses; nextses = nextses->qsf_next; } if (nextses != NULL) { TRdisplay("*** Too many QSF session CBs detected"); TRdisplay(" while beginning a session.\n"); SETDBERR(&qsf_rb->qsf_error, 0, E_QS9999_INTERNAL_ERROR); return (E_DB_FATAL); } } #endif /* xDEBUG */ status = E_DB_OK; /* Release exclusive access to QSF's SERVER CONTROL BLOCK */ /* ------------------------------------------------------ */ if (CSv_semaphore(&Qsr_scb->qsr_psem)) { status = E_DB_ERROR; SETDBERR(&qsf_rb->qsf_error, 0, E_QS0004_SEMRELEASE); } return (status); }
/*{ ** Name: psq_bgn_session - Begin a parser session. ** ** INTERNAL PSF call format: status = psq_bgn_session(&psq_cb, &sess_cb); ** ** EXTERNAL call format: status = psq_call(PSQ_BGN_SESSION, &psq_cb, &sess_cb); ** ** Description: ** The psq_bgn_session function begins a parser session. It should be ** called each time a new user connects to a server. There may be ** many parser sessions per database server. There should be one parser ** session for each invocation of the database system that is connected ** to the server. When starting a parser session, one has to tell it ** what query language to use, and other session parameters. ** ** Inputs: ** psq_cb ** .psq_qlang The query language to use. ** .psq_decimal ** .psf_decspec TRUE indicates that the decimal marker ** has been specified. FALSE means use the ** default (a "."). ** .psf_decimal The character to use as a decimal marker ** (if specified). ** .psq_distrib Indicator for whether distributed ** statements and constructs should be ** accepted. ** .psq_sessid Session id ** .psq_server address of server control block ** .psq_adf_cb Pointer to session's ADF_CB ** .psq_dbid Database id for this session. ** .psq_user User name of ** .psq_dba User name of dba ** .psq_group Group id of session ** .psq_aplid Application id of session ** .psq_flag bitmask containing the following flags: ** .psq_catupd TRUE means catalogs updateable ** .psq_warnings Set to TRUE if user wishes to see ** warnings on unsupported commands ** .psq_idxstruct Structure for creating new indexes ** (e.g. DB_ISAM_STORE) ** .psq_udbid Unique database id for this session. ** .psq_ustat User status flags from SCS_ICS ** .psq_dbxlate Case translation semantics for the db ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psq_cb ** .psq_error Error information ** .err_code What error occurred ** E_PS0000_OK Success ** E_PS0001_INTERNAL_ERROR Internal PSF problem ** E_PS0201_BAD_QLANG Bad query language specifier ** E_PS0203_NO_DECIMAL No decimal marker specified ** E_PS0204_BAD_DISTRIB Bad distributed ** specification ** E_PS0205_SRV_NOT_INIT Server not initialized ** E_PS0206_TOO_MANY_SESS Too many sessions at one ** time ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s) ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_SEVERE Session is to be aborted ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Causes memory to be allocated. ** Increments the session count in the server control block. ** ** History: ** 01-oct-85 (jeff) ** written ** 28-jul-86 (jeff) ** Added initialization of pss_catupd and pss_idxstruct ** 26-aug-86 (seputis) ** Removed definition of yaccstream ** 13-apr-87 (puree) ** Initialize prototype list for dynamic SQL. ** 24-apr-87 (stec) ** init pss_project. ** 11-may-87 (stec) ** store psq_udbid to pss_dbid. ** 04-sep-87 (stec) ** Added critical region code where needed. ** 02-oct-87 (stec) ** Added pss_journaling initialization. ** 13-jun-88 (stec) ** Added initialization of pss_ruset for DB procs. ** 08-mar-89 (andre) ** Copy dba_drop_all from PSQ_CB to PSS_SESBLK. ** 15-mar-89 (ralph) ** GRANT Enhancements, Phase 1: ** Copy psq_aplid to pss_aplid; ** Copy psq_group to pss_group. ** 16-mar-89 (neil) ** Initialized rule field. ** 27-jul-89 (jrb) ** Copy numeric literals flag into session cb. ** 27-oct-89 (ralph) ** Copy user status flags to session control block. ** 11-oct-89 (ralph) ** Initialize pss_rgset and pss_raset. ** 28-dec-89 (andre) ** Copy fips_mode from PSQ_CB to PSS_SESBLK. ** 13-feb-90 (andre) ** set scf_stype to SCU_EXCLUSIVE before calling scu_swait. ** 12-sep-90 (sandyh) ** Added support for session memory value calculated from psf ** memory startup parameter. ** 15-nov-90 (andre) ** check the return status after calling SCF to acquire or to release a ** semaphore. ** If an error occurred when trying to acquire the semaphore, return ** E_DB_SEVERE to abort the session. ** If an error occurred when trying to release the semaphore, return ** E_DB_FATAL to bring down the server. ** 17-may-91 (andre) ** store DBA name into sess_cb->pss_dbaname and NULL-terminate. ** 08-nov-91 (rblumer) ** merged from 6.4: 25-jul-91 (andre) ** if (psq_cb->psq_flag & PSQ_STRIP_NL_IN_STRCONST), set bit ** PSS_STRIP_NL_IN_STRCONST in sess_cb->pss_ses_flag. this will ** indicate that we are connected to an older FE, so the scanners ** will continue to strip NLs inside quoted strings; ** this is required to fix bug 38098 ** 14-jan-92 (barbara) ** Included ddb.h for Star. Updated to check for distributed ** specification. ** 26-feb-92 (andre) ** if PSQ_REPAIR_SYSCAT is set in psq_cb->psq_flag, set ** PSS_REPAIR_SYSCAT in sess_cb->pss_ses_flags ** 30-mar-1992 (bryanp) ** Fill in pss_sess_owner with a session-unique owner name for use ** by temporary tables which are owned by this session. ** 02-jun-92 (andre) ** initialize pss_dependencies_stream to NULL to avloid use of illegal ** address throughout the parser. ** 24-nov-92 (ralph) ** CREATE SCHEMA: ** Initialize pss_prvgoval ** 22-dec-92 (rblumer) ** initialize pointer for statement-level rule list. ** 14-jan-93 (andre) ** remember whether we are running UPGRADEDB - this will enable us to ** decide whether IIDEVICES can be dropped - which is needed by ** UPGRADEDB ** 15-mar-93 (ralph) ** DELIM_IDENT: initialize pss_dbxlate to zero ** 08-apr-93 (andre) ** names of rule list headers in sess_cb have changed (and their ** number has doubled) ** 26-mar-93 (ralph) ** DELIM_IDENT: Must initialize pss_dbxlate from psq_cb.psq_dbxlate ** and pss_cat_owner from psq_cat_owner. ** 10-aug-93 (andre) ** fixed cause of a compiler warning ** 08-sep-93 (swm) ** Changed sizeof(DB_SESSID) to sizeof(CS_SID) to reflect recent CL ** interface revision. ** 20-sep-93 (rogerk) ** Changed default table create semantics to be WITH JOURNALING. ** Initialized the pss_ses_flag setting to include PSS_JOURNALING ** which mimics the user requesting "set journaling" to indicate that ** tables created should be journaled. ** 08-oct-93 (rblumer) ** increased values allowed in pss_trace vector, using PSS_TVALS. ** 18-oct-93 (rogerk) ** Added support for journal default override. Check psf server ** control block flag for PSF_NO_JNL_DEFAULT override before setting ** the session parse flag to assume journaling on table creates. ** 15-nov-93 (andre) ** add code to initialize a newly added sess_cb->pss_flattening_flags ** 01-nov-93 (anitap) ** if PSQ_INGRES_PRIV is set in psq_cb->psq_flag, set ** PSS_INGRES_PRIV in sess_cb->pss_ses_flags. ** 17-dec-93 (rblumer) ** "FIPS mode" no longer exists. It was replaced some time ago by ** several feature-specific flags (e.g. flatten_nosingleton and ** direct_cursor_mode). So I removed all FIPS_MODE flags. ** 02-jan-94 (andre) ** if starting a local session, call DMF to determine whether the ** database to which we are connected is being journaled and record ** that information by setting (or not setting) PSS_JOURNALED_DB bit ** in pss_ses_flags ** 7-jan-94 (swm) ** Bug #58635 ** Added PTR cast for pss_owner which has changed type to PTR. ** 17-mar-94 (robf) ** Add support for PSQ_SELECT_ALL flag ** 13-Feb-1995 (canor01) ** initialize the pss_audit field in the session control block ** 09-Oct-1998 (jenjo02) ** Removed SCF semaphore functions, inlining the CS calls instead. ** 23-mar-1999 (thaju02) ** Modified '$Sess' to use #define DB_SESS_TEMP_OWNER. (B94067) ** 01-Dec-2000 (hanal04) Bug 100680 INGSRV 1123 ** If PSQ_RULE_UPD_PREFETCH is set turn on PSS_RULE_UPD_PREFETCH ** in the session control block to signify that we should use ** the prefetch stategy required to ensure consitent behaviour in ** updating rules fired by updates. ** 10-Jan-2001 (jenjo02) ** Remove callback to SCF to get session id and ADF_CB; ** *ADF_CB now supplied by scsinit in PSQ_CB. ** 30-Jan-2004 (schka24) ** Get rid of a type-cast warning on adf cb. ** 3-Feb-2005 (schka24) ** Num-literals renamed to parser-compat, fix here. ** 15-june-06 (dougi) ** Add support for "before" triggers. ** 30-aug-06 (thaju02) ** If PSQ_RULE_DEL_PREFETCH is set turn on PSS_RULE_DEL_PREFETCH ** in the session control block, for prefetch strategy to ** be applied for deletes. (B116355) ** 26-Oct-2009 (kiria01) SIR 121883 ** Scalar sub-query support: Added copy of ** psq_flag.PSQ_NOCHK_SINGLETON_CARD to session flag ** for defaulting SET CARDINALITY_CHECK ** November 2009 (stephenb) ** Batch execution; initilization of new fields. ** 29-apr-2010 (stephenb) ** Init batch_copy_optim. ** 04-may-2010 (miket) SIR 122403 ** Init new sess_cb->pss_stmt_flags2. ** 19-May-2010 (kiria01) b123766 ** Get cardinality check default from server block not psq_cb ** 21-Jul-2010 (kschendel) SIR 124104 ** Initialize default compression from facility cb. ** 14-Oct-2010 (kschendel) SIR 124544 ** Initialize default result structure from facility cb. ** 19-Nov-2010 (kiria01) SIR 124690 ** Add support for setting installation wide collation defaults. */ DB_STATUS psq_bgn_session( register PSQ_CB *psq_cb, register PSS_SESBLK *sess_cb) { i4 err_code; i4 i; DB_STATUS status = E_DB_OK; STATUS sem_status; i4 sem_errno; bool leave_loop = TRUE; ULM_RCB ulm_rcb; /* ** No error to begin with. */ psq_cb->psq_error.err_code = E_PS0000_OK; /* ** Do as much validity checking as possible before allocating any memory. ** That way, there won't be any cleaning up to do for the majority of ** errors. */ /* ** Check for server initialized. This code could be placed within ** critical region, but this is not necessary, since this is a flag ** test. */ if (!Psf_srvblk->psf_srvinit) { (VOID) psf_error(E_PS0205_SRV_NOT_INIT, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* ** Check for valid language spec. */ if (psq_cb->psq_qlang != DB_QUEL && psq_cb->psq_qlang != DB_SQL) { (VOID) psf_error(E_PS0201_BAD_QLANG, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* ** Check whether language is allowed in this server. This will be useful ** when we have configurable servers, where some query languages can be ** used and some can't. This code could be placed within a critical region ** but it is not necessary, since this is a flag test only. */ if ((psq_cb->psq_qlang & Psf_srvblk->psf_lang_allowed) == 0) { (VOID) psf_error(E_PS0202_QLANG_NOT_ALLOWED, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* ** Make sure that the decimal character is actually specified. */ if (!psq_cb->psq_decimal.db_decspec) { (VOID) psf_error(E_PS0203_NO_DECIMAL, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* Check distributed specification ** ** a=local_server, b=distrib_server, c=distrib_session ** ** a,b ** ** 00 01 11 10 ** ----------------- ** c | | | | | ** 0 | 1 | 1 | 0 | 0 | ** | | | | | ** ----------------- ==> ERROR ** | | | | | ** 1 | 1 | 0 | 0 | 1 | ** | | | | | ** ----------------- */ if ( !(psq_cb->psq_distrib & (DB_1_LOCAL_SVR | DB_3_DDB_SESS)) || ((~psq_cb->psq_distrib & DB_2_DISTRIB_SVR) && (psq_cb->psq_distrib & DB_3_DDB_SESS)) ) { psf_error(E_PS0204_BAD_DISTRIB, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error,0); return (E_DB_ERROR); } /* ** Check for too many sessions in server at one time. ** This code must be executed as a critical region. */ do /* something to break out of */ { /* get the semaphore */ if (sem_status = CSp_semaphore(1, &Psf_srvblk->psf_sem)) /* exclusive */ { status = E_DB_SEVERE; /* abort the session */ sem_errno = E_PS020A_BGNSES_GETSEM_FAILURE; break; } if (Psf_srvblk->psf_nmsess >= Psf_srvblk->psf_mxsess) { (VOID) psf_error(E_PS0208_TOO_MANY_SESS, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); status = E_DB_ERROR; break; } /* Increment the session count */ Psf_srvblk->psf_nmsess++; sess_cb->pss_psessid = ++Psf_srvblk->psf_sess_num; /* leave_loop has already been set to TRUE */ } while (!leave_loop); /* if semaphore has been successfully acquired, try to release it */ if (sem_status == OK) { if (sem_status = CSv_semaphore(&Psf_srvblk->psf_sem)) { status = E_DB_FATAL; /* bring down the server */ sem_errno = E_PS020B_BGNSES_RELSEM_FAILURE; } } /* ** if an error was encountered while trying to get or to release a ** semaphore, report it here */ if (sem_status != OK) { (VOID) psf_error(sem_errno, sem_status, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); } if (DB_FAILURE_MACRO(status)) { return(status); } /* ** Initialize the case translation semantics stuff */ sess_cb->pss_dbxlate = psq_cb->psq_dbxlate; sess_cb->pss_cat_owner = psq_cb->psq_cat_owner; /* ** Copy the user name and dba name to the session control block. */ STRUCT_ASSIGN_MACRO(psq_cb->psq_user.db_tab_own, sess_cb->pss_user); STRUCT_ASSIGN_MACRO(psq_cb->psq_dba, sess_cb->pss_dba); STRUCT_ASSIGN_MACRO(psq_cb->psq_group, sess_cb->pss_group); STRUCT_ASSIGN_MACRO(psq_cb->psq_aplid, sess_cb->pss_aplid); /* copy DBA name into sess_cb->pss_dbaname and NULL-terminate */ { u_i2 dba_name_len; dba_name_len = (u_i2) psf_trmwhite((u_i4) sizeof(sess_cb->pss_dba), (char *) &sess_cb->pss_dba); MEcopy((PTR) &sess_cb->pss_dba, dba_name_len, (PTR) sess_cb->pss_dbaname); sess_cb->pss_dbaname[dba_name_len] = EOS; } /* ** Build a DB_OWN_NAME which contains a session-unique owner name. This ** owner name will be used for temporary tables which are owned by this ** session. */ { char temp_sess_id[10]; STmove(DB_SESS_TEMP_OWNER, ' ', sizeof(sess_cb->pss_sess_owner), (char *)&sess_cb->pss_sess_owner); /* ** We can't convert directly into the sess_owner field because CVlx ** null-terminates the result, and we don't want the trailing null */ CVlx(sess_cb->pss_psessid, temp_sess_id); MEcopy(temp_sess_id, 8, &sess_cb->pss_sess_owner.db_own_name[5]); } /* ** Start with per-user quota of memory. Note that user may have overridden ** the default value at server startup in which case we will use calculated ** amount (pool/sessions); otherwise, default amount will be used. */ sess_cb->pss_memleft = (Psf_srvblk->psf_sess_mem) ? Psf_srvblk->psf_sess_mem : PSF_SESMEM; /* ** Initialize the user range table. */ if (pst_rginit(&sess_cb->pss_usrrange) != E_DB_OK) { return (E_DB_FATAL); } /* ** Initialize the auxiliary range table. */ if (pst_rginit(&sess_cb->pss_auxrng) != E_DB_OK) { return (E_DB_FATAL); } /* ** Open a memory stream for the symbol table. The symbol table is ** composed of a list of blocks. ** Allocate the symbol table at the same time. */ ulm_rcb.ulm_facility = DB_PSF_ID; ulm_rcb.ulm_poolid = Psf_srvblk->psf_poolid; ulm_rcb.ulm_blocksize = sizeof(PSS_SYMBLK); ulm_rcb.ulm_memleft = &sess_cb->pss_memleft; /* Set pointer to stream handle for ULM */ ulm_rcb.ulm_streamid_p = &sess_cb->pss_symstr; /* Open a private, thread-safe stream */ ulm_rcb.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC; ulm_rcb.ulm_psize = sizeof(PSS_SYMBLK); if (ulm_openstream(&ulm_rcb) != E_DB_OK) { if (ulm_rcb.ulm_error.err_code == E_UL0005_NOMEM) { (VOID) psf_error(E_PS0F02_MEMORY_FULL, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); } else { (VOID) psf_error(E_PS0A02_BADALLOC, ulm_rcb.ulm_error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); } return((ulm_rcb.ulm_error.err_code == E_UL0004_CORRUPT) ? E_DB_FATAL : E_DB_ERROR); } sess_cb->pss_symtab = (PSS_SYMBLK*) ulm_rcb.ulm_pptr; sess_cb->pss_symtab->pss_sbnext = (PSS_SYMBLK *) NULL; /* ** Allocate the YACC_CB. */ if ((status = psl_yalloc(sess_cb->pss_symstr, &sess_cb->pss_memleft, (PTR *) &sess_cb->pss_yacc, &psq_cb->psq_error)) != E_DB_OK) { /* ** If the allocation failed, remember to close the streams, so the ** memory associated with it will be freed. */ (VOID) ulm_closestream(&ulm_rcb); return (status); } /* ** Fill in the control block header. */ sess_cb->pss_next = (PSS_SESBLK *) NULL; sess_cb->pss_prev = (PSS_SESBLK *) NULL; sess_cb->pss_length = sizeof(PSS_SESBLK); sess_cb->pss_type = PSS_SBID; sess_cb->pss_owner = (PTR)DB_PSF_ID; sess_cb->pss_ascii_id = PSSSES_ID; /* ** Initialize the session control block. */ /* Save the session id */ sess_cb->pss_sessid = psq_cb->psq_sessid; /* Set pointer to session's ADF_CB */ sess_cb->pss_adfcb = (ADF_CB *) psq_cb->psq_adfcb; /* No cursors yet */ sess_cb->pss_numcursors = 0; /* Language has already been validated */ sess_cb->pss_lang = psq_cb->psq_qlang; /* Decimal spec has already been validated */ sess_cb->pss_decimal = psq_cb->psq_decimal.db_decimal; /* Distributed spec has already been validated */ sess_cb->pss_distrib = psq_cb->psq_distrib; /* Save the database id */ sess_cb->pss_dbid = psq_cb->psq_dbid; /* Save the unique database id */ sess_cb->pss_udbid = psq_cb->psq_udbid; /* Initialize QSF_RCB for use by psfmem.c functions */ sess_cb->pss_qsf_rcb.qsf_type = QSFRB_CB; sess_cb->pss_qsf_rcb.qsf_ascii_id = QSFRB_ASCII_ID; sess_cb->pss_qsf_rcb.qsf_length = sizeof(sess_cb->pss_qsf_rcb); sess_cb->pss_qsf_rcb.qsf_owner = (PTR)DB_PSF_ID; sess_cb->pss_qsf_rcb.qsf_sid = sess_cb->pss_sessid; /* ** so session reset all bit flags */ sess_cb->pss_stmt_flags = sess_cb->pss_stmt_flags2 = sess_cb->pss_dbp_flags = sess_cb->pss_ses_flag = 0L; sess_cb->pss_flattening_flags = 0; /* ** Default table create semantics are to assume journaling unless ** the PSF_NO_JNL_DEFAULT override is set. */ if ((Psf_srvblk->psf_flags & PSF_NO_JNL_DEFAULT) == 0) sess_cb->pss_ses_flag |= PSS_JOURNALING; /* catalog update flag */ if (psq_cb->psq_flag & PSQ_CATUPD) sess_cb->pss_ses_flag |= PSS_CATUPD; /* warnings on unsupported commands */ if (psq_cb->psq_flag & PSQ_WARNINGS) sess_cb->pss_ses_flag |= PSS_WARNINGS; /* INDICATE if the DBA may DROP everyone's tables */ if (psq_cb->psq_flag & PSQ_DBA_DROP_ALL) sess_cb->pss_ses_flag |= PSS_DBA_DROP_ALL; /* INDICATE if the session may SELECT everyone's tables */ if (psq_cb->psq_flag & PSQ_SELECT_ALL) sess_cb->pss_ses_flag |= PSS_SELECT_ALL; /* ** indicate that the session is allowed to INSERT/DELETE/UPDATE an index ** which is a catalog (but not an extended catalog */ if (psq_cb->psq_flag & PSQ_REPAIR_SYSCAT) sess_cb->pss_ses_flag |= PSS_REPAIR_SYSCAT; /* ** indicate that the session allows $ingres to drop/add constraint on ** tables owned by other users */ if (psq_cb->psq_flag & PSQ_INGRES_PRIV) sess_cb->pss_ses_flag |= PSS_INGRES_PRIV; if (psq_cb->psq_flag & PSQ_ROW_SEC_KEY) sess_cb->pss_ses_flag |= PSS_ROW_SEC_KEY; /* See if passwords, roles allowed */ if (psq_cb->psq_flag & PSQ_PASSWORD_NONE) sess_cb->pss_ses_flag |= PSS_PASSWORD_NONE; if (psq_cb->psq_flag & PSQ_ROLE_NONE) sess_cb->pss_ses_flag |= PSS_ROLE_NONE; if (psq_cb->psq_flag & PSQ_ROLE_NEED_PW) sess_cb->pss_ses_flag |= PSS_ROLE_NEED_PW; /* remember whether we are running UPGRADEDB */ if (psq_cb->psq_flag & PSQ_RUNNING_UPGRADEDB) sess_cb->pss_ses_flag |= PSS_RUNNING_UPGRADEDB; /* Pick up serverwide default for card check */ if (Psf_srvblk->psf_flags & PSF_NOCHK_SINGLETON_CARD) sess_cb->pss_ses_flag |= PSS_NOCHK_SINGLETON_CARD; /* Initialize pss_project. */ sess_cb->pss_ses_flag |= PSS_PROJECT; /* pss_project = TRUE */ /* init last statement */ sess_cb->pss_last_sname[0] = EOS; /* batch optimization switch starts undefined */ sess_cb->batch_copy_optim = PSS_BATCH_OPTIM_UNDEF; /* ** if starting a local session, determine whether the database is being ** journaled */ if (~psq_cb->psq_distrib & DB_3_DDB_SESS) { DMC_CB dmc_cb, *dmc = &dmc_cb; DMC_CHAR_ENTRY dmc_char; MEfill(sizeof(dmc_cb), (u_char) 0, (PTR) dmc); dmc->type = DMC_CONTROL_CB; dmc->length = sizeof(*dmc); dmc->dmc_op_type = DMC_DATABASE_OP; dmc->dmc_session_id = (PTR) sess_cb->pss_sessid; dmc->dmc_flags_mask = DMC_JOURNAL; dmc->dmc_char_array.data_address= (PTR) &dmc_char; dmc->dmc_char_array.data_out_size = sizeof(dmc_char); dmc->dmc_db_id = (char *) sess_cb->pss_dbid; status = dmf_call(DMC_SHOW, (PTR) dmc); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS020E_CANT_GET_DB_JOUR_STATUS, dmc->error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); return(status); } if (dmc_char.char_value == DMC_C_ON) { sess_cb->pss_ses_flag |= PSS_JOURNALED_DB; } } /* Save the storage structure for indexes */ sess_cb->pss_idxstruct = psq_cb->psq_idxstruct; /* Make session copy of parser compatability settings */ sess_cb->pss_parser_compat = psq_cb->psq_parser_compat; /* remember if NLs inside string constants need to be stripped */ if (psq_cb->psq_flag & PSQ_STRIP_NL_IN_STRCONST) sess_cb->pss_ses_flag |= PSS_STRIP_NL_IN_STRCONST; /* no rule tree yet */ sess_cb->pss_row_lvl_usr_rules = sess_cb->pss_row_lvl_sys_rules = sess_cb->pss_stmt_lvl_usr_rules = sess_cb->pss_stmt_lvl_sys_rules = sess_cb->pss_row_lvl_usr_before_rules = sess_cb->pss_row_lvl_sys_before_rules = sess_cb->pss_stmt_lvl_usr_before_rules = sess_cb->pss_stmt_lvl_sys_before_rules = (PST_STATEMENT *) NULL; if (psq_cb->psq_flag & PSQ_RULE_DEL_PREFETCH) sess_cb->pss_ses_flag |= PSS_RULE_DEL_PREFETCH; if(psq_cb->psq_flag2 & PSQ_RULE_UPD_PREFETCH) sess_cb->pss_ses_flag |= PSS_RULE_UPD_PREFETCH; /* copy user status flags to session control block */ sess_cb->pss_ustat = psq_cb->psq_ustat; /* ** Initialize lots of pointer to NULL because nothing is happening yet. */ sess_cb->pss_qbuf = sess_cb->pss_nxtchar = sess_cb->pss_prvtok = sess_cb->pss_bgnstmt = sess_cb->pss_endbuf = sess_cb->pss_prvgoval = (u_char *) NULL; /* initialize pss_audit */ sess_cb->pss_audit = NULL; for (i = 0; i < PSS_CURTABSIZE; i++) { sess_cb->pss_curstab.pss_curque[i] = (PSC_CURBLK *) NULL; } /* initialize prototype list for dynamic SQL */ sess_cb->pss_proto = (PST_PROTO *) NULL; /* ** pss_dependencies_stream, when not NULL, is expected to point at a valid ** stream descriptor. After closing the stream we always reset ** pss_dependencies_stream to NULL, but in some cases we may end up checking ** pss_dependencies_stream before ever opening (and closing it). As a ** result, you may end up using invalid address as a stream pointer. ** Initializing it here to NULL will ensure that it is non-NULL iff it ** points at a valid open stream descriptor. */ sess_cb->pss_dependencies_stream = (PSF_MSTREAM *) NULL; /* No trace flags set */ /* expect lint message */ ult_init_macro(&sess_cb->pss_trace, PSS_TBITS, PSS_TVALS, PSS_TVAO); /* Cursor id set to 0, no cursors open yet */ sess_cb->pss_crsid = 0; sess_cb->pss_create_compression = Psf_srvblk->psf_create_compression; /* SCF can pass a client requested result_structure, but if it ** doesn't, init from server default. */ if (psq_cb->psq_result_struct != 0) { sess_cb->pss_result_struct = psq_cb->psq_result_struct; sess_cb->pss_result_compression = psq_cb->psq_result_compression; } else { sess_cb->pss_result_struct = Psf_srvblk->psf_result_struct; sess_cb->pss_result_compression = Psf_srvblk->psf_result_compression; } if (psq_cb->psq_def_coll > DB_NOCOLLATION) sess_cb->pss_def_coll = psq_cb->psq_def_coll; else sess_cb->pss_def_coll = Psf_srvblk->psf_def_coll; if (psq_cb->psq_def_unicode_coll > DB_NOCOLLATION) sess_cb->pss_def_unicode_coll = psq_cb->psq_def_unicode_coll; else sess_cb->pss_def_unicode_coll = Psf_srvblk->psf_def_unicode_coll; return (E_DB_OK); }
/* ** Name: SXC_END_SESSION - end a SXF session ** ** Description: ** This routine is used to end a SXF session, it is called at ** session end time via the sxf_call(SXC_END_SESSION) request. ** This request must be made by a session that has previously been ** registered with SXF via the sxc_bgn_session routine. All resourses ** allocated by this session will be released. ** ** Overview of algorithm:- ** ** Locate the SXF_SCB for this session. ** Call sxac_end_session to remove the session from the auditing system. ** Unlink SXF_SCB from SCB list in the server control block. ** Destroy the SXF_SCB. ** ** Inputs: ** rcb ** .sxf_scb Pointer to the session control block. ** ** Outputs: ** rcb ** .sxf_error error code returned to the caller ** ** Returns: ** DB_STATUS ** ** History: ** 11-aug-92 (markg) ** Initial creation. ** 26-oct-1992 (markg) ** Updated error handling. */ DB_STATUS sxc_end_session( SXF_RCB *rcb) { DB_STATUS status = E_DB_OK; i4 err_code = E_SX0000_OK; i4 local_err; SXF_SCB *scb; bool scb_found = FALSE; for (;;) { /* Locate SCB and remove the session from the audit system */ if (Sxf_svcb->sxf_svcb_status & SXF_SNGL_USER) { if (Sxf_svcb->sxf_scb_list == NULL) { err_code = E_SX000D_INVALID_SESSION; break; } else { scb = Sxf_svcb->sxf_scb_list; } } else { CSp_semaphore(TRUE, &Sxf_svcb->sxf_svcb_sem); for (scb = Sxf_svcb->sxf_scb_list; scb != NULL; scb = scb->sxf_next) { if (scb == (SXF_SCB *) rcb->sxf_scb) { scb_found = TRUE; break; } } CSv_semaphore(&Sxf_svcb->sxf_svcb_sem); if (scb_found == FALSE) { err_code = E_SX000D_INVALID_SESSION; break; } } status = sxac_end_session(scb, &local_err); if (status != E_DB_OK) { err_code = local_err; _VOID_ ule_format(err_code, NULL, ULE_LOG, NULL, NULL, 0L, NULL, &local_err, 0); } /* Remove SCB from list of active sessions and destroy it */ CSp_semaphore(TRUE, &Sxf_svcb->sxf_svcb_sem); if (scb->sxf_prev != NULL) scb->sxf_prev->sxf_next = scb->sxf_next; else Sxf_svcb->sxf_scb_list = scb->sxf_next; if (scb->sxf_next != NULL) scb->sxf_next->sxf_prev = scb->sxf_prev; Sxf_svcb->sxf_active_ses--; CSv_semaphore(&Sxf_svcb->sxf_svcb_sem); status = sxc_destroy_scb(scb, &local_err); if (status != E_DB_OK) { err_code = local_err; _VOID_ ule_format(err_code, NULL, ULE_LOG, NULL, NULL, 0L, NULL, &local_err, 0); } break; } /* Handle any errors */ if (err_code != E_SX0000_OK) { if (err_code > E_SXF_INTERNAL) err_code = E_SX000E_BAD_SESSION_END; rcb->sxf_error.err_code = err_code; if (status == E_DB_OK) status = E_DB_ERROR; } return (status); }