/*{ ** Name: opx_init - initialize the AIC and PAINE handlers ** ** Description: ** This routine will inform SCF of the AIC and PAINE handlers ** ** Inputs: ** opf_cb - ptr to caller's control block ** ** Outputs: ** Returns: ** E_DB_OK ** E_DB_ERROR - if initialization failed ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 31-mar-87 (seputis) ** initial creation ** 12-dec-88 (seputis) ** return E_DB_OK [@history_template@]... */ DB_STATUS opx_init( OPF_CB *opf_cb) { SCF_CB scf_cb; DB_STATUS scf_status; scf_cb.scf_length = sizeof(scf_cb); scf_cb.scf_type = SCF_CB_TYPE; scf_cb.scf_facility = DB_OPF_ID; scf_cb.scf_ptr_union.scf_afcn = opx_call; scf_cb.scf_session = DB_NOSESSION; scf_cb.scf_nbr_union.scf_amask = SCS_PAINE_MASK; scf_status = scf_call(SCS_DECLARE, &scf_cb); # ifdef E_OP0090_PAINE if (DB_FAILURE_MACRO(scf_status)) { opx_rverror( opf_cb, scf_status, E_OP0090_PAINE, scf_cb.scf_error.err_code); return(E_DB_ERROR); } # endif scf_cb.scf_nbr_union.scf_amask = SCS_AIC_MASK; scf_status = scf_call(SCS_DECLARE, &scf_cb); # ifdef E_OP0091_AIC if (DB_FAILURE_MACRO(scf_status)) { opx_rverror( opf_cb, scf_status, E_OP0091_AIC, scf_cb.scf_error.err_code); return(E_DB_ERROR); } # endif return(E_DB_OK); }
/*{ ** Name: ops_unlock - release exclusive access to server control block ** ** Description: {@comment_line@}... ** ** Inputs: [@PARAM_DESCR@]... ** ** Outputs: [@PARAM_DESCR@]... ** Returns: ** {@return_description@} ** Exceptions: ** [@description_or_none@] ** ** Side Effects: ** [@description_or_none@] ** ** History: ** 09-Oct-1998 (jenjo02) ** Removed SCF semaphore functions, inlining the CS calls instead. [@history_template@]... */ DB_STATUS ops_unlock( OPF_CB *opf_cb, SCF_SEMAPHORE *semaphore) { STATUS status; status = CSv_semaphore(semaphore); 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); }
/*{ ** 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); }
/*{ ** Name: opx_verror - this routine will report another facility's error ** ** Description: ** This routine will report an error from another facility ** optimizer error. It will check the status and see the error ** is recoverable. The routine will not return if the status is fatal ** but instead generate an internal exception and ** exit via the exception handling mechanism. The error code will be ** placed directly in the user's calling control block. A ptr to this ** block was placed in the session control block (which can be requested ** from SCF) ** ** Inputs: ** error optimizer error code to report ** facility facility's error code ** status facility's return status ** ** Outputs: ** Returns: ** VOID ** Exceptions: ** - internal exception generated ** ** Side Effects: ** the exception handling routines are responsible for ** deallocating OPF resources bound to this session. ** ** History: ** 3-jul-86 (seputis) ** initial creation ** 28-jan-91 (seputis) ** added support for OPF ACTIVE flag ** 30-apr-92 (bryanp) ** Translate E_RD002A_DEADLOCK to E_OP0010_RDF_DEADLOCK. [@history_line@]... */ VOID opx_verror( DB_STATUS status, OPX_ERROR error, OPX_FACILITY facility) { OPS_CB *opscb; /* ptr to session control block ** for this optimization */ opscb = ops_getcb(); opscb->ops_retstatus = status; /* save status code */ if (facility == E_RD002A_DEADLOCK) error = E_OP0010_RDF_DEADLOCK; if ((facility == E_RD002B_LOCK_TIMER_EXPIRED) && (opscb->ops_smask & OPS_MCONDITION)) { error = E_OP000D_RETRY; /* when an attempt is made to ** report the RDF timeout error ** then it should be translated ** into a retry error, since an ** undetected deadlock may have ** occurred due to the ACTIVE flag */ opscb->ops_server->opg_sretry++; /* track number of retrys */ opx_vrecover(status, E_OP000D_RETRY, facility); /* this routine will not ** return */ } else opx_rverror(opscb->ops_callercb, status, error, facility); if (DB_SUCCESS_MACRO(status)) { return; /* return if error is not ** serious */ } EXsignal( (EX)EX_JNP_LJMP, (i4)1, (long)error); /* signal an optimizer long ** jump with error code */ }
/*{ ** Name: ops_deallocate - deallocate resources for an optimization ** ** Description: ** This routine will deallocate the resources used for an optimization. ** Resources include any memory requested from the optimizer memory pool ** and any RDF cache objects which were locked in the global range ** table ** ** Inputs: ** global ptr to global state variable ** report TRUE if errors should be reported ** via the user's control block. ** partial_dbp partial deallocation required for ** statement within a procedure ** ** Outputs: ** Returns: ** VOID ** Exceptions: ** none ** ** Side Effects: ** memory resources released, RDF unfixed, ** QSF query tree memory released ** ** History: ** 29-jun-86 (seputis) ** initial creation ** 8-nov-88 (seputis) ** if no query run trace point is set then destroy the QP since ** SCF assumes optimizer cleans up after error ** 8-nov-88 (seputis) ** turn off CPU accounting if was off originally ** 28-jan-91 (seputis) ** added support for OPF ACTIVE flag ** 20-jul-93 (ed) ** changed name ops_lock for solaris, due to OS conflict ** 29-jul-93 (andre) ** rdr_types_mask must be initialized (to RDR_RELATION) before ** calling RDF_UNFIX. Otherwise RDF may end up complaining because we ** ask it to destroy a relation cache entry while RDR_PROCEDURE bit is ** set. ** 12-aug-93 (swm) ** Cast first parameter of CSaltr_session() to CS_SID to match ** revised CL interface specification. ** 02-Jun-1997 (shero03) ** Update the saved rdf_info_block after calling RDF. ** 02-Aug-2001 (hanal04) Bug 105360 INGSRV 1505 ** Plug the RDF memory leak introduced by inkdo01's new ** function oph_temphist(). ** 17-Dec-2003 (jenjo02) ** Added (CS_SID)NULL to CScnd_signal prototype. ** 6-Feb-2006 (kschendel) ** Fix some squirrely looking code that purported to avoid dangling ** references, but didn't really. (No symptoms known.) ** 14-nov-2007 (dougi) ** Add support for cached dynamic query plans. ** 20-may-2008 (dougi) ** Add support for table procedures. ** 29-may-2009 (wanfr01) Bug 122125 ** Need to add dbid to cache_dynamic queries for db uniqueness */ VOID ops_deallocate( OPS_STATE *global, bool report, bool partial_dbp) { DB_STATUS finalstatus; /* this status is returned to the user ** - it will contain the first error ** during resource deallocation */ DB_ERROR error; /* error code from offending facility */ finalstatus = E_DB_OK; error.err_code = 0; { /* close any fixed RDF objects - deallocate prior to closing the ** global memory stream */ OPV_IGVARS gvar; /* index into global range variable ** table */ OPV_GRT *gbase; /* ptr to base of array of ptrs ** to global range table elements */ OPV_IGVARS maxgvar; /* number of global range table ** elements allocated */ RDF_CB *rdfcb; /* ptr to rdf control block used ** unfix the relation info */ OPV_GBMVARS *rdfmap; /* ptr to map of global range ** variables which have RDF info ** fixed */ gbase = global->ops_rangetab.opv_base; maxgvar = global->ops_rangetab.opv_gv; rdfcb = &global->ops_rangetab.opv_rdfcb; rdfmap = &global->ops_rangetab.opv_mrdf; /* ** rdr_types_mask needs to be initialized - since we will be unfixing ** relation entries, RDR_RELATION seems like a good choice, although 0 ** would suffice as well */ rdfcb->rdf_rb.rdr_types_mask = RDR_RELATION; if (global->ops_cstate.opc_relation) { /* OPC allocates a RDF descriptor for cursors so deallocate ** if this is the case */ DB_STATUS opcrdfstatus; /* RDF return status */ rdfcb->rdf_info_blk = global->ops_cstate.opc_relation; opcrdfstatus = rdf_call( RDF_UNFIX, (PTR)rdfcb ); if ( (DB_FAILURE_MACRO(opcrdfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = opcrdfstatus; error.err_code = rdfcb->rdf_error.err_code; } global->ops_cstate.opc_relation = NULL; } if (maxgvar) { for ( gvar = -1; (gvar = BTnext((i4)gvar, (char *)rdfmap, (i4)maxgvar)) >=0;) { OPV_GRV *gvarp; /* ptr to global range variable to ** be deallocated */ if ((gvarp = gbase->opv_grv[gvar]) /* NULL if not allocated */ && (gvarp->opv_relation) /* not NULL if RDF has been ** called for this range variable */ && !(gvarp->opv_gmask & OPV_TPROC) /* not table procedure */ ) { /* if this element has been allocated and if it has an RDF ** cache element associated with it */ DB_STATUS rdfstatus; /* RDF return status */ gbase->opv_grv[gvar] = NULL; /* so we do not try to deallocate ** twice in case of an error */ rdfcb->rdf_info_blk = gvarp->opv_relation; rdfstatus = rdf_call( RDF_UNFIX, (PTR)rdfcb ); if ( (DB_FAILURE_MACRO(rdfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = rdfstatus; error.err_code = rdfcb->rdf_error.err_code; } gvarp->opv_relation = NULL; } if ((gvarp) && (gvarp->opv_ttmodel)) { /* if this element has been allocated and if it has an RDF ** cache element associated with a persistent table ** which provides histogram models. */ DB_STATUS rdfstatus; /* RDF return status */ rdfcb->rdf_info_blk = gvarp->opv_ttmodel; gvarp->opv_ttmodel = NULL; rdfstatus = rdf_call( RDF_UNFIX, (PTR)rdfcb ); if ( (DB_FAILURE_MACRO(rdfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = rdfstatus; error.err_code = rdfcb->rdf_error.err_code; } } } global->ops_rangetab.opv_gv = 0; } } if (partial_dbp) return; /* only deallocate the global range table ** for DBP, and keep the memory streams ** until the end */ if (global->ops_estate.opn_statistics && global->ops_estate.opn_reset_statistics) { /* statistics CPU accounting was turned on, and needs to be reset */ STATUS cs_status; i4 turn_off; turn_off = FALSE; /* turn off accounting */ global->ops_estate.opn_statistics = FALSE; cs_status = CSaltr_session((CS_SID)0, CS_AS_CPUSTATS, (PTR)&turn_off); if (cs_status != OK) { finalstatus = E_DB_ERROR; error.err_code = cs_status; } } /* deallocate ULM memory stream */ if (global->ops_mstate.ops_streamid == NULL) /* non-zero if allocated */ { /* check if ULM stream does not exist then this deallocation has ** already occurred so just return */ return; } else { DB_STATUS ulm1status;/* ULM return status */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_streamid; /* ulm will NULL ops_streamid */ ulm1status = ulm_closestream( &global->ops_mstate.ops_ulmrcb ); if ( (DB_FAILURE_MACRO(ulm1status)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = ulm1status; error.err_code = global->ops_mstate.ops_ulmrcb.ulm_error.err_code; } } /* deallocate ULM temp buffer memory stream */ if ( global->ops_mstate.ops_tstreamid ) /* non-zero if allocated */ { DB_STATUS ulm2status; /* ULM return status */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_tstreamid; /* ulm will NULL ops_tstreamid */ ulm2status = ulm_closestream( &global->ops_mstate.ops_ulmrcb ); if ( (DB_FAILURE_MACRO(ulm2status)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = ulm2status; error.err_code = global->ops_mstate.ops_ulmrcb.ulm_error.err_code; } } /* deallocate OPC ULM buffer memory stream */ if ( global->ops_mstate.ops_sstreamid ) /* non-zero if allocated */ { DB_STATUS ulm3status; /* ULM return status */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_sstreamid; /* ulm will NULL ops_sstreamid */ ulm3status = ulm_closestream( &global->ops_mstate.ops_ulmrcb ); if ( (DB_FAILURE_MACRO(ulm3status)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = ulm3status; error.err_code = global->ops_mstate.ops_ulmrcb.ulm_error.err_code; } } if (!report #ifdef OPT_F032_NOEXECUTE || /* if trace flag is set then cleanup QSF memory since optimizer will ** generate an error to SCF and SCF assumes optimizer will cleanup */ (global->ops_cb->ops_check && (opt_strace( global->ops_cb, OPT_F032_NOEXECUTE) || opt_strace( global->ops_cb, OPT_F023_NOCOMP) ) ) #endif ) { /* an error or an asychronous abort has occurred so destroy the plan ** or shared plan , FIXME destroy the shared plan in the earlier ** exception handler */ DB_STATUS qsfqpstatus; /* QSF return status */ if(global->ops_qpinit) { /* deallocate QSF object for query plan if another error has occurred ** - in this case OPC has already created a new QP handle and has ** gotten a lock on it */ STRUCT_ASSIGN_MACRO(global->ops_caller_cb->opf_qep, global->ops_qsfcb.qsf_obj_id); /* get ** query plan id */ global->ops_qsfcb.qsf_lk_id = global->ops_qplk_id; /* get lock id for ** QSF */ qsfqpstatus = ops_qsfdestroy(global); /* destroy the query plan */ if ( (DB_FAILURE_MACRO(qsfqpstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = qsfqpstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } else { /* OPC has not been reached so need to check for shared query plan */ if (!global->ops_procedure) { /* get query tree if it has not already been retrieved */ qsfqpstatus = ops_gqtree(global); if ( (DB_FAILURE_MACRO(qsfqpstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = qsfqpstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } if (global->ops_qheader && (global->ops_qheader->pst_mask1 & PST_RPTQRY)) { /* shared query plan possible */ if (global->ops_procedure->pst_flags & PST_REPEAT_DYNAMIC) { char *p; global->ops_qsfcb.qsf_obj_id.qso_lname = sizeof(DB_CURSOR_ID) + sizeof(i4); MEfill(sizeof(global->ops_qsfcb.qsf_obj_id.qso_name), 0, global->ops_qsfcb.qsf_obj_id.qso_name); MEcopy((PTR)&global->ops_procedure-> pst_dbpid.db_cursor_id[0], sizeof (global->ops_procedure-> pst_dbpid.db_cursor_id[0]), (PTR)global->ops_qsfcb.qsf_obj_id.qso_name); p = (char *) global->ops_qsfcb.qsf_obj_id.qso_name + 2*sizeof(i4); MEcopy((PTR)"qp", sizeof("qp"), p); p = (char *) global->ops_qsfcb.qsf_obj_id.qso_name + sizeof(DB_CURSOR_ID); I4ASSIGN_MACRO(global->ops_caller_cb->opf_udbid, *(i4 *) p); } else /* must be proc or regular repeat query */ { global->ops_qsfcb.qsf_obj_id.qso_lname = sizeof (global->ops_procedure->pst_dbpid); MEcopy((PTR)&global->ops_procedure->pst_dbpid, sizeof (global->ops_procedure->pst_dbpid), (PTR)&global->ops_qsfcb.qsf_obj_id.qso_name[0]); } global->ops_qsfcb.qsf_obj_id.qso_type = QSO_QP_OBJ; global->ops_qsfcb.qsf_lk_state = QSO_SHLOCK; qsfqpstatus = qsf_call(QSO_GETHANDLE, &global->ops_qsfcb); if (DB_SUCCESS_MACRO(qsfqpstatus)) { qsfqpstatus = ops_qsfdestroy( global ); if ( (DB_FAILURE_MACRO(qsfqpstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = qsfqpstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } else if (global->ops_qsfcb.qsf_error.err_code != E_QS0019_UNKNOWN_OBJ) { /* if object is not found then this is not a shared query */ finalstatus = qsfqpstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } } } /* release QSF memory allocated to query tree, make sure that this ** is done after the QP has been processed since pst_rptqry is still ** needed for above block */ { DB_STATUS qsfstatus; /* QSF return status */ STRUCT_ASSIGN_MACRO(global->ops_caller_cb->opf_query_tree, global->ops_qsfcb.qsf_obj_id); /* get ** query tree id */ global->ops_qsfcb.qsf_lk_id = global->ops_lk_id; /* get lock id for ** QSF */ qsfstatus = ops_qsfdestroy( global ); if ( (DB_FAILURE_MACRO(qsfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = qsfstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } /* signal that the session is exiting OPF and that another thread may enter */ if (global->ops_cb->ops_smask & OPS_MCONDITION) { DB_STATUS lockstatus; OPG_CB *servercb; servercb = global->ops_cb->ops_server; global->ops_cb->ops_smask &= (~OPS_MCONDITION); lockstatus = ops_exlock(global->ops_caller_cb, &servercb->opg_semaphore); /* check if server ** thread is available, obtain ** semaphore lock on critical variable */ servercb->opg_activeuser--; /* since exit is about to occur, and memory ** has already been deallocated, allow another ** user to enter OPF */ servercb->opg_waitinguser--; /* since exit is about to occur, and memory ** has already been deallocated, allow another ** user to enter OPF */ if (DB_FAILURE_MACRO(lockstatus) && (DB_SUCCESS_MACRO(finalstatus))) { finalstatus = lockstatus; error.err_code = global->ops_caller_cb->opf_errorblock.err_data; } else { if (servercb->opg_waitinguser > servercb->opg_activeuser) { STATUS csstatus; csstatus = CScnd_signal(&servercb->opg_condition, (CS_SID)NULL); /* signal only if some users are waiting */ if ((csstatus != OK) && (DB_SUCCESS_MACRO(finalstatus))) { finalstatus = E_DB_ERROR; error.err_code = csstatus; } } lockstatus = ops_unlock(global->ops_caller_cb, &servercb->opg_semaphore); /* check if server ** thread is available */ if (DB_FAILURE_MACRO(lockstatus) && (DB_SUCCESS_MACRO(finalstatus))) { finalstatus = lockstatus; error.err_code = global->ops_caller_cb->opf_errorblock.err_data; } } } if (DB_FAILURE_MACRO(finalstatus)) { if (report) opx_verror( finalstatus, E_OP0084_DEALLOCATION, error.err_code); /* report ** error and generate an exception */ else opx_rverror(global->ops_cb->ops_callercb, finalstatus, E_OP0084_DEALLOCATION, error.err_code); /* report error only but do not generate an ** exception */ } }
/*{ ** Name: opx_adfexception - handle ADF exceptions if possible ** ** Description: ** Routine will be called by exception handlers in the optimizer to ** handle arithmetic exceptions if possible ** ** Inputs: ** ops_cb OPF session control block ** ex_args exception handler arguments ** ** Outputs: ** Returns: ** exception status - EXCONTINUES, or EXRESIGNAL ** where EXRESIGNAL means that the exception is unknown ** Exceptions: ** OPF exception is generated for a fatal ADF exception ** ** Side Effects: ** none ** ** History: ** 20-jan-86 (seputis) ** initial creation ** 31-mar-92 (rog) ** Remove underscores from EX return statuses. ** 24-oct-92 (andre) ** interface of opx_sccerror() has been changed to receive ** (DB_SQLSTATE *) [@history_template@]... */ static STATUS opx_adfexception( OPS_CB *ops_cb, EX_ARGS *ex_args) { DB_STATUS status; ADF_CB *adf_scb; adf_scb = ops_cb->ops_adfcb; status = adx_handler(adf_scb, ex_args); if ((status == E_DB_WARN) && (adf_scb->adf_errcb.ad_errcode == E_AD0116_EX_UNKNOWN) ) { /* adf does not know about this error so resignal it */ return (EXRESIGNAL); } if (DB_SUCCESS_MACRO(status)) { /* adf will return OK status if it knowns about the error and the ** correct action is to continue */ #ifdef OPT_F031_WARNINGS /* if trace flag is set then warning or info errors will be reported */ if ( DB_SUCCESS_MACRO(status) && ops_cb->ops_check && opt_strace( ops_cb, OPT_F031_WARNINGS) ) opx_rverror( ops_cb->ops_callercb, E_DB_WARN, E_OP0701_ADF_EXCEPTION, (OPX_FACILITY)0); /* report ** warning is ** trace flag is set */ #endif return(EXCONTINUES); /* return if error is not ** serious */ } { OPX_ERROR adf_error; OPX_ERROR opf_error; ops_cb->ops_retstatus = status; if (adf_scb->adf_errcb.ad_errclass == ADF_USER_ERROR) { /* report the error message to the user */ adf_error = adf_scb->adf_errcb.ad_usererr; opf_error = E_OP0702_ADF_EXCEPTION; } else { /* report non-user error code */ adf_error = adf_scb->adf_errcb.ad_errcode; opf_error = E_OP0795_ADF_EXCEPTION; } opx_rverror(ops_cb->ops_callercb, E_DB_WARN, opf_error,(OPX_FACILITY)0); /* do not report facility error ** since opx_sccerror will report it ** in the next statement ** - need to use the formatted message ** the ADF provides since it may contain ** parameters */ (VOID) opx_sccerror(status, &adf_scb->adf_errcb.ad_sqlstate, adf_error, adf_scb->adf_errcb.ad_errmsgp, adf_scb->adf_errcb.ad_emsglen); } return (EXDECLARE); /* return to declaration point of ** exception handler */ }