/*{ ** Name: opx_error - this routine will report an optimizer error ** ** Description: ** This routine will report a E_DB_ERROR optimizer error. The routine ** will not return 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 ** ** Outputs: ** Returns: ** - routine does not return ** 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 [@history_line@]... */ VOID opx_error( OPX_ERROR error) { OPS_CB *opscb; /* ptr to session control block ** for this optimization */ opscb = ops_getcb(); opscb->ops_retstatus = E_DB_ERROR; /* return status code */ opx_rerror( opscb->ops_callercb, error); /* log error */ EXsignal( (EX)EX_JNP_LJMP, (i4)1, (long)error);/* signal an optimizer long ** jump */ }
/*{ ** Name: opx_exception - handle unknown exception for optimizer ** ** Description: ** This routine will handle unknown exceptions for the optimizer ** ** Inputs: ** ex_args argument list from exception handler ** ** Outputs: ** Returns: ** STATUS - appropriate CL return code for exception handler ** Exceptions: ** ** ** Side Effects: ** ** ** History: ** 20-jan-87 (seputis) ** initial creation ** 7-nov-88 (seputis) ** use EXsys_report ** 26-jun-91 (seputis) ** added check for OPC access violations ** 11-mar-92 (rog) ** Use EXsys_report for everything, not just EXSEGVIO. Call ** scs_avformat to dump info about the offending session. Remove ** underscores from EX return statuses. ** 02-jul-1993 (rog) ** Call ulx_exception() to handle all of the reporting duties. ** OPF should need to call adx_handler, so remove call to ** opx_adfexception(). [@history_line@]... [@history_template@]... */ STATUS opx_exception( EX_ARGS *args) { /* unexpected exception so record the error and return to ** deallocate resources */ OPS_CB *opscb; /* session control block */ OPF_CB *opfcb; /* caller's control block */ OPX_ERROR errorcode; /* error code for exception */ opscb = ops_getcb(); /* get optimizer session control block */ opfcb = opscb->ops_state->ops_caller_cb; /* report unexpected exception ** otherwise */ if (opfcb->opf_errorblock.err_code == E_OP0082_UNEXPECTED_EX) { /* try to check for exception within an exception as soon as possible */ errorcode = E_OP0083_UNEXPECTED_EXEX; /* second exception ** occurred so do not deallocate ** any resources */ opscb->ops_retstatus = E_DB_SEVERE; /* make sure an high enough priority ** error is reported */ } else { if (opscb->ops_state->ops_gmask & OPS_OPCEXCEPTION) errorcode = E_OP08A2_EXCEPTION; /* check for exception in ** OPC component of OPF */ else errorcode = E_OP0082_UNEXPECTED_EX; /* check for exception ** in non-OPC components of OPF */ } ulx_exception( args, DB_OPF_ID, E_OP0901_UNKNOWN_EXCEPTION, TRUE); if (opscb->ops_retstatus != E_DB_SEVERE && opscb->ops_retstatus != E_DB_FATAL) opscb->ops_retstatus = E_DB_ERROR; /* make sure an high enough priority ** error is reported */ opx_rerror(opscb->ops_state->ops_caller_cb, errorcode);/*log error*/ return (EXDECLARE); /* return to exception handler declaration pt */ }
/*{ ** Name: ops_alter - alter session or server state for OPF ** ** Description: ** This routine contains all processing of the SET commands for the ** optimizer. These commands can be at the server or session level. ** There is currently no protection mechanism available for which ** users are able to access these SET commands. There probably should ** be a system catalog created to decide privileges and min and max ** values allowable for a session. Currently, all users can do anything ** at all. This routine will not do anything in terms of checking ** privileges. ** ** SET [[SESSION] | SERVER] CPUFACTOR <value> ** SET [[SESSION] | SERVER] TIMEOUT <value> ** SET [[SESSION] | SERVER] QEP ** SET [[SESSION] | SERVER] NOQEP ** SET [[SESSION] | SERVER] RET_INTO <storage_structure> ** ** FIXME need to use semaphores to access global structures. ** ** Inputs: ** opf_cb ptr to caller's control block ** ** Outputs: ** Returns: ** E_DB_OK ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 30-jun-86 (seputis) ** initial creation [@history_line@]... */ DB_STATUS ops_alter( OPF_CB *opf_cb) { DB_STATUS status; /* user return status */ switch (opf_cb->opf_level) { case OPF_SERVER: { /* change operating characteristics of the server */ DB_STATUS temp_status; /* get exclusive access before updating */ status = ops_exlock(opf_cb, &((OPS_CB *)(opf_cb->opf_scb))->ops_server->opg_semaphore); if (DB_FAILURE_MACRO(status)) break; temp_status = ops_change( opf_cb, &((OPG_CB*)opf_cb->opf_server)->opg_alter); /* release exclusive access */ status = ops_unlock(opf_cb, &((OPS_CB *)(opf_cb->opf_scb))->ops_server->opg_semaphore); if (DB_SUCCESS_MACRO(status)) status = temp_status; break; } case OPF_SESSION: { /* change operating characteristics of this session */ status = ops_change( opf_cb, &((OPS_CB *)(opf_cb->opf_scb))->ops_alter); break; } default: # ifdef E_OP0089_ALTER { opx_rerror( opf_cb, E_OP0089_ALTER); return( E_DB_ERROR ); } #endif } return (status); }
/*{ ** Name: ops_change - change characteristics for SET command ** ** Description: ** This routine will change the characteristics of an OPS_ALTER ** control block ** ** Inputs: ** opf_cb ptr to caller's control block ** altercb ptr to alter control block to update ** ** Outputs: ** Returns: ** E_DB_OK, E_DB_ERROR ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 1-jul-86 (seputis) ** initial creation ** 8-aug-89 (seputis) ** added OPF_SUBSELECT ** 12-jul-90 (seputis) ** added OPS_ARESOURCE and OPS_ANORESOURCE for b30809 ** 22-jul-02 (inkdo01) ** Added OPF_[NO]OPTIMIZEONLY to obviate need for tp auth. ** 4-june-03 (inkdo01) ** Added "set [no]ojflatten" as synonym for tp op134. ** 11-june-03 (inkdo01) ** Added support for "set joinop [no]newenum", "set [no]hash". ** 4-mar-04 (inkdo01) ** Added support for "set [no]parallel [n]". ** 17-Aug-2010 (horda03) b124274 ** IF SET QEP and opf_value set then enable Segmented QEP ** displays. disable otherwise. [@history_line@]... */ static DB_STATUS ops_change( OPF_CB *opf_cb, OPS_ALTER *altercb) { i4 opcode; /* characteristic to be changed */ DB_DEBUG_CB debugcb; opcode = opf_cb->opf_alter; { switch (opcode) { case OPF_MEMORY: { altercb->ops_maxmemory = opf_cb->opf_value; /* new default memory */ break; } case OPF_INLIST_THRESH: { altercb->ops_inlist_thresh = opf_cb->opf_value; /* new default inlist threshold */ break; } case OPF_TIMEOUT: { altercb->ops_timeout = TRUE; altercb->ops_sestime = opf_cb->opf_value; /* new default timeout */ break; } case OPF_TIMEOUTABORT: { altercb->ops_timeout = TRUE; altercb->ops_timeoutabort = opf_cb->opf_value; break; } case OPF_NOTIMEOUT: { altercb->ops_timeout = FALSE; break; } case OPF_CPUFACTOR: { altercb->ops_cpufactor = opf_cb->opf_value; /* new default weight ** between CPU and I/O */ break; } case OPF_QEP: { altercb->ops_qep = TRUE; /* print QEP */ altercb->ops_qep_flag = opf_cb->opf_value ? ULD_FLAG_SEGMENTS : ULD_FLAG_NONE; break; } case OPF_NOQEP: { altercb->ops_qep = FALSE; /* print qep */ altercb->ops_qep_flag = ULD_FLAG_NONE; break; } case OPF_RET_INTO: { altercb->ops_storage = opf_cb->opf_value; /* default storage ** structure for temps */ altercb->ops_compressed = opf_cb->opf_compressed; /* default ** compressed mode structure ** for temps */ break; } case OPF_SUBSELECT: { /* FIXME - probably should make this a session control variable ** rather than using a trace flag */ debugcb.db_trswitch = DB_TR_ON; debugcb.db_value_count = 0; debugcb.db_trace_point = OPT_GMAX + OPT_F004_FLATTEN; opt_call(&debugcb); /* turn OFF flattening */ break; } case OPF_NOSUBSELECT: { debugcb.db_trswitch = DB_TR_OFF; debugcb.db_value_count = 0; debugcb.db_trace_point = OPT_GMAX + OPT_F004_FLATTEN; opt_call(&debugcb); /* turn ON flattening */ break; } case OPF_OJSUBSELECT: { debugcb.db_trswitch = DB_TR_OFF; debugcb.db_value_count = 0; debugcb.db_trace_point = OPT_GMAX + OPT_F006_NONOTEX; opt_call(&debugcb); /* turn ON OJ flattening */ break; } case OPF_NOOJSUBSELECT: { debugcb.db_trswitch = DB_TR_ON; debugcb.db_value_count = 0; debugcb.db_trace_point = OPT_GMAX + OPT_F006_NONOTEX; opt_call(&debugcb); /* turn OFF OJ flattening */ break; } case OPF_OPTIMIZEONLY: { debugcb.db_trswitch = DB_TR_ON; debugcb.db_value_count = 0; debugcb.db_trace_point = OPT_GMAX + OPT_F032_NOEXECUTE; opt_call(&debugcb); /* turn OFF execution */ break; } case OPF_NOOPTIMIZEONLY: { debugcb.db_trswitch = DB_TR_OFF; debugcb.db_value_count = 0; debugcb.db_trace_point = OPT_GMAX + OPT_F032_NOEXECUTE; opt_call(&debugcb); /* turn ON execution */ break; } case OPF_HASH: { altercb->ops_hash = TRUE; /* enable hash join/agg */ break; } case OPF_NOHASH: { altercb->ops_hash = FALSE; /* disable hash join/agg */ break; } case OPF_NEWENUM: { altercb->ops_newenum = TRUE; /* enable new enumeration */ break; } case OPF_NONEWENUM: { altercb->ops_newenum = FALSE; /* disable new enumeration */ break; } case OPF_PARALLEL: { altercb->ops_parallel = TRUE; /* enable || query plans */ if (opf_cb->opf_value >= 0) altercb->ops_pq_dop = opf_cb->opf_value; /* update degree of ||ism */ break; } case OPF_NOPARALLEL: { altercb->ops_parallel = FALSE; /* disable || query plans */ break; } case OPF_ARESOURCE: { altercb->ops_amask |= OPS_ARESOURCE; /* causes enumeration ** to be used in all cases so that ** resource control gets accurate ** estimates */ break; } case OPF_ANORESOURCE: { altercb->ops_amask &= (~OPS_ARESOURCE); /* turns off enumeration ** for single table queries so that ** resource control will not get accurate ** estimates if it is used */ break; } case OPF_CARDCHK: { altercb->ops_nocardchk = FALSE; /* Enable cardinality checks */ break; } case OPF_NOCARDCHK: { altercb->ops_nocardchk = TRUE; /* Ignore card checks (legacy mode) */ break; } # ifdef E_OP0089_ALTER default: { opx_rerror( opf_cb, E_OP0089_ALTER); return( E_DB_ERROR ); } # endif } } return (E_DB_OK); }
/*{ ** Name: opn_timeout - check for timeout condition ** ** Description: ** Check the various indications that timeout has occurred. ** ** Inputs: ** subquery ptr to subquery state ** ** Outputs: ** ** Returns: ** bool - TRUE is timeout condition has been detected ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 14-may-90 (seputis) ** - b21582, do not allow large CPU gaps before checking ** for a timeout condition ** 26-nov-90 (seputis) ** - added support for new server startup flags ** 31-jan-91 (seputis) ** - use more time to optimize queries in DB procedures ** 20-mar-91 (seputis) ** - b 36600 added calls to CSswitch to allow context ** switching if no query plan is found or notimeout is used ** 3-dec-92 (ed) ** OP255 was doing a notimeout on all subqueries if the second ** parameter was set ** 31-jan-97 (inkdo01) ** Simplify CSswitch interface so that all calls to timeout ** result in a CSswitch call. This fixes a CPU lockout problem ** in (at least) Solaris, because the switch depended largely ** on faulty quantum testing logic in CSstatistics. ** 15-sep-98 (sarjo01) ** Redo of function, adding support for ops_timeoutabort ** 14-jul-99 (inkdo01) ** Add code to do quick exit for where-less idiot queries. ** 13-Feb-2007 (kschendel) ** Replace CSswitch with better CScancelCheck. [@history_template@]... */ bool opn_timeout( OPS_SUBQUERY *subquery) { OPS_CB *scb; /* ptr to session control block for ** currently active user */ OPS_STATE *global; /* ptr to global state variable */ if (subquery->ops_mask & OPS_IDIOT_NOWHERE && subquery->ops_bestco) return(TRUE); /* if idiot query (join, but no where) ** and we have valid plan, quit now */ global = subquery->ops_global; /* get ptr to global state variable */ scb = global->ops_cb; /* get ptr to active session control ** block */ if (scb->ops_alter.ops_timeout) /* TRUE if optimizer should timeout */ { i4 joinop_timeout; i4 joinop_abort; joinop_timeout = scb->ops_alter.ops_sestime; joinop_abort = scb->ops_alter.ops_timeoutabort; if (joinop_abort == 0) { if (subquery->ops_bestco) { TIMERSTAT timer_block; STATUS cs_status; i4 nowcpu; /* cpu time used by process */ OPO_COST miladjust; /* adjustment to cost to obtain ** millisec equivalent */ i4 first; /* plan to timeout */ i4 second; /* subquery plan to timeout */ bool planid_timeout; /* check if tracing flag is ** set and override timeout ** check with new one */ planid_timeout = FALSE; if ((global->ops_qheader->pst_numparm > 0) || global->ops_procedure->pst_isdbp) miladjust = scb->ops_alter.ops_tout * scb->ops_alter.ops_repeat; /* use more time to optimize ** a repeat query */ else miladjust = scb->ops_alter.ops_tout; if (scb->ops_check) { if (opt_svtrace( scb, OPT_F125_TIMEFACTOR, &first, &second) && first>0) /* see if there is a miladjust factor ** from the user */ miladjust = (miladjust*first)/100.0; /* this will increase/decrease ** the amount of time required to timeout */ planid_timeout = opt_svtrace( scb, OPT_F127_TIMEOUT, &first, &second); /* this will time out based on subquery ** plan id and number of plans being ** evaluated */ } if (cs_status = CSstatistics(&timer_block, (i4)0)) { /* get cpu time used by session from SCF to calculate ** difference from when optimization began FIXME - this ** is an expensive routine to call, perhaps some other ** way of timing out could be used such as number of CO ** nodes processed */ opx_verror(E_DB_ERROR, E_OP0490_CSSTATISTICS, (OPX_FACILITY)cs_status); } nowcpu = timer_block.stat_cpu -global->ops_estate.opn_startime; if ( (((nowcpu > (miladjust * subquery->ops_cost)) || /* if the amount of time spent so ** far on optimization is roughly ** about how much time the best ** solution found so far ** will take to execute, then stop */ ( (joinop_timeout > 0) && (nowcpu > joinop_timeout))) && ( !planid_timeout /* if the plan timeout tracing is ** set then this should override ** the normal timeout mechanism */ || ( (second != 0) && (second != subquery->ops_tsubquery) /* apply timeout ** to all query plans except the ** one specified */ ) )) || ( planid_timeout && (first <= subquery->ops_tcurrent) && ( (second == 0) /* check if all plans should be ** timed out */ || (second == subquery->ops_tsubquery) /* check if a ** particular subquery is being ** search for */ ) )) { opx_verror(E_DB_WARN, E_OP0006_TIMEOUT, (OPX_FACILITY)0); return(TRUE); } } } else { TIMERSTAT timer_block; STATUS cs_status; i4 nowcpu; /* cpu time used by process */ OPO_COST miladjust; /* adjustment to cost to obtain ** millisec equivalent */ i4 first; /* plan to timeout */ i4 second; /* subquery plan to timeout */ bool planid_timeout; /* check if tracing flag is ** set and override timeout ** check with new one */ if (joinop_timeout == 0 || joinop_timeout >= joinop_abort) joinop_timeout = joinop_abort; planid_timeout = FALSE; if ((global->ops_qheader->pst_numparm > 0) || global->ops_procedure->pst_isdbp) miladjust = scb->ops_alter.ops_tout * scb->ops_alter.ops_repeat; /* use more time to optimize ** a repeat query */ else miladjust = scb->ops_alter.ops_tout; if (scb->ops_check) { if (opt_svtrace( scb, OPT_F125_TIMEFACTOR, &first, &second) && first>0) /* see if there is a miladjust factor ** from the user */ miladjust = (miladjust*first)/100.0; /* this will increase/decrease ** the amount of time required to timeout */ planid_timeout = opt_svtrace( scb, OPT_F127_TIMEOUT, &first, &second); /* this will time out based on subquery ** plan id and number of plans being ** evaluated */ } if (cs_status = CSstatistics(&timer_block, (i4)0)) { opx_verror(E_DB_ERROR, E_OP0490_CSSTATISTICS, (OPX_FACILITY)cs_status); } nowcpu = timer_block.stat_cpu -global->ops_estate.opn_startime; if ( subquery->ops_bestco && ( ( ((nowcpu > (miladjust * subquery->ops_cost)) || ((joinop_timeout > 0) && (nowcpu > joinop_timeout))) && ( !planid_timeout || ( (second != 0) && (second != subquery->ops_tsubquery) ) ) ) || ( planid_timeout && (first <= subquery->ops_tcurrent) && ( (second == 0) || (second == subquery->ops_tsubquery) )) ) ) { opx_verror(E_DB_WARN, E_OP0006_TIMEOUT, (OPX_FACILITY)0); return(TRUE); } else if (nowcpu > joinop_abort) { if (subquery->ops_bestco) { opx_verror(E_DB_WARN, E_OP0006_TIMEOUT, (OPX_FACILITY)0); return(TRUE); } else { scb->ops_interrupt = TRUE; opx_rerror(subquery->ops_global->ops_caller_cb, E_OP0018_TIMEOUTABORT); } } } /* else */ } /* Check for cancels if OS-threaded, time-slice if internal threaded */ CScancelCheck(global->ops_cb->ops_sid); return(FALSE); }