/*{ ** Name: OPU_RELEASE - Return memory to the global memory pool ** ** Description: ** This routine returns memory from the given mark to the end of the ** ULM memory stream to the global memory pool. [@comment_line@]... ** ** Inputs: ** global - ** State info for the current query. ** ulmrcb - ** address of local control block, or NULL if ** global->ops_mstate.ops_ulmrcb should be used ** mark - ** The mark stating where to start returning memory. ** ** Outputs: ** ** Returns: ** none ** Exceptions: ** none ** ** Side Effects: ** Memory is returned to the global memory pool ** ** History: ** 18-apr-87 (seputis) ** initial creation ** 11-oct-2006 (hayke02) ** Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309. [@history_template@]... */ VOID opu_release( OPS_STATE *global, ULM_RCB *ulmrcb, ULM_SMARK *mark) { DB_STATUS ulmstatus; /* return status from ULM */ if (!ulmrcb) { ulmrcb = &global->ops_mstate.ops_ulmrcb; /* use global ulmrcb if ** control block is not defined */ ulmrcb->ulm_streamid_p = &global->ops_mstate.ops_streamid; /* mark memory ** in the global stream */ } /* store the mark to be initialized */ ulmrcb->ulm_smark = mark; ulmstatus = ulm_reclaim( ulmrcb ); if ( DB_FAILURE_MACRO(ulmstatus) ) { if (ulmrcb->ulm_error.err_code == E_UL0005_NOMEM) { opx_lerror(E_OP0002_NOMEMORY, 0, 0, 0, 0, 0); opx_error( E_OP0002_NOMEMORY); /* out of memory */ } #ifdef E_OP0093_ULM_ERROR else opx_verror( ulmstatus, E_OP0093_ULM_ERROR, ulmrcb->ulm_error.err_code); /* check for error */ #endif } }
/*{ ** Name: OPU_RSMEMORY_RECLAIM - Return memory to the global memory pool ** ** Description: ** This routine returns memory from the given mark to the end of the ** ULM memory stream to the global memory pool. [@comment_line@]... ** ** Inputs: ** global - ** State info for the current query. ** global->ops_mstate.ops_ulmrcb - ** The ULM control block. ** global->ops_mstate.ops_sstreamid - ** The stream id. ** mark - ** The mark stating where to start returning memory. ** ** Outputs: ** ** Returns: ** The address of the allocated memory. ** Exceptions: ** none ** ** Side Effects: ** Memory is returned to the global memory pool ** ** History: ** 19-July-87 (eric) ** written ** 11-oct-2006 (hayke02) ** Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309. [@history_template@]... */ VOID opu_Rsmemory_reclaim( OPS_STATE *global, ULM_SMARK *mark) { DB_STATUS ulmstatus; /* return status from ULM */ /* store the stream id */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_sstreamid; /* store the mark to be initialized */ global->ops_mstate.ops_ulmrcb.ulm_smark = mark; if ( (ulmstatus = ulm_reclaim( &global->ops_mstate.ops_ulmrcb )) != E_DB_OK ) { if (global->ops_mstate.ops_ulmrcb.ulm_error.err_code == E_UL0005_NOMEM) { opx_lerror(E_OP0002_NOMEMORY, 0, 0, 0, 0, 0); opx_error( E_OP0002_NOMEMORY); /* out of memory */ } #ifdef E_OP0093_ULM_ERROR else opx_verror( ulmstatus, E_OP0093_ULM_ERROR, global->ops_mstate.ops_ulmrcb.ulm_error.err_code); /* check for error */ #endif } }
/*{ ** Name: OPU_GSMEMORY_CLOSE - Get memory from the stack ULM memory stream ** ** Description: ** This routine allocates memory from the ULM memory stream that is used ** for the stack style memory usage. [@comment_line@]... ** ** Inputs: ** global - ** State info for the current query. ** global->ops_mstate.ops_ulmrcb - ** The ULM control block. ** global->ops_mstate.ops_sstreamid - ** The stream id. ** size - ** size of the piece of memory to allocate. ** ** Outputs: ** ** Returns: ** The address of the allocated memory. ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 19-July-87 (eric) ** written ** 21-feb-91 (seputis) ** make non-zero initialization of memory an xDEBUG feature ** 16-sep-93 (smc) ** Moved <cs.h> for CS_SID. ** 11-oct-2006 (hayke02) ** Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309. [@history_line@]... [@history_template@]... */ PTR opu_Gsmemory_get( OPS_STATE *global, i4 size) { DB_STATUS ulmstatus; /* return status from ULM */ /* store the stream id */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_sstreamid; /* store the size to be allocate */ global->ops_mstate.ops_ulmrcb.ulm_psize = size; if ( (ulmstatus = ulm_palloc( &global->ops_mstate.ops_ulmrcb )) != E_DB_OK ) { if (global->ops_mstate.ops_ulmrcb.ulm_error.err_code == E_UL0005_NOMEM) { opx_lerror(E_OP0002_NOMEMORY, 0, 0, 0, 0, 0); opx_error( E_OP0002_NOMEMORY); /* out of memory */ } #ifdef E_OP0093_ULM_ERROR else opx_verror( ulmstatus, E_OP0093_ULM_ERROR, global->ops_mstate.ops_ulmrcb.ulm_error.err_code); /* check for error */ #endif } #ifdef xDEBUG MEfill( size, (u_char)127, (PTR)global->ops_mstate.ops_ulmrcb.ulm_pptr); /*FIXME ** remove this initialization after ** test for uninitialized memory ** is not required any more */ #endif /* return the allocated memory */ return( global->ops_mstate.ops_ulmrcb.ulm_pptr ); }
/*{ ** Name: opu_allocate - allocate a new private memory stream ** ** Description: ** This routine will allocate a new private memory stream from the ULM ** ** Inputs: ** global ptr to global state variable ** ** Outputs: ** Returns: ** PTR which represents the new memory stream ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 16-jun-86 (seputis) ** initial creation ** 11-oct-2006 (hayke02) ** Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309. [@history_line@]... */ PTR opu_allocate( OPS_STATE *global) { DB_STATUS ulmstatus; /* return status from ulm */ /* Tell ULM to return streamid into ulm_streamid */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_ulmrcb.ulm_streamid; ulmstatus = ulm_openstream(&global->ops_mstate.ops_ulmrcb); if (DB_FAILURE_MACRO(ulmstatus)) { opx_lerror(E_OP0002_NOMEMORY, 0); opx_verror(ulmstatus, E_OP0002_NOMEMORY, global->ops_mstate.ops_ulmrcb.ulm_error.err_code); } return ( global->ops_mstate.ops_ulmrcb.ulm_streamid ); }
/*{ ** Name: opu_memory - get joinop memory ** ** Description: ** This routine will allocate the requested size of memory from the ** joinop memory stream. Memory in this stream is not deallocated ** until the optimization has completed. The allocated memory will ** be aligned for any datatype. ** ** Inputs: ** global ptr to global state variable ** size size of memory block requested. ** ** Outputs: ** Returns: ** PTR to aligned memory of "size" bytes ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 16-jun-86 (seputis) ** initial creation ** 4-mar-91 (seputis) ** make initialization of memory an xDEBUG feature ** 11-oct-2006 (hayke02) ** Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309. ** 5-oct-2007 (dougi) ** Accumulate memory acquisition stats. */ PTR opu_memory( OPS_STATE *global, i4 size) { DB_STATUS ulmstatus; /* return status from ULM */ global->ops_mstate.ops_countalloc++; if (size >= 2048) global->ops_mstate.ops_count2kalloc++; global->ops_mstate.ops_totalloc += size; global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_streamid; /* allocate memory ** from the global stream */ global->ops_mstate.ops_ulmrcb.ulm_psize = size; /* size of request */ ulmstatus = ulm_palloc( &global->ops_mstate.ops_ulmrcb ); if (DB_FAILURE_MACRO(ulmstatus)) { if (global->ops_mstate.ops_ulmrcb.ulm_error.err_code == E_UL0005_NOMEM) { opx_lerror(E_OP0002_NOMEMORY, 0, 0, 0, 0, 0); opx_error( E_OP0002_NOMEMORY); /* out of memory */ } #ifdef E_OP0093_ULM_ERROR else opx_verror( ulmstatus, E_OP0093_ULM_ERROR, global->ops_mstate.ops_ulmrcb.ulm_error.err_code); /* check for error */ #endif } #ifdef xDEBUG MEfill( size, (u_char)247, (PTR)global->ops_mstate.ops_ulmrcb.ulm_pptr); /*FIXME ** remove this initialization after ** test for uninitialized memory ** is not required any more */ #endif return( global->ops_mstate.ops_ulmrcb.ulm_pptr ); /* return the allocated ** memory */ }
/*{ ** Name: OPU_OSMEMORY_OPEN - Initialize the stack ULM memory stream ** ** Description: ** This routine initializes the ULM memory stream that will be used ** for the stack style memory allocation and deallocation. [@comment_line@]... ** ** Inputs: ** global - ** State info for the current query. ** global->ops_mstate.ops_ulmrcb - ** The ULM control block. ** ** Outputs: ** global->ops_mstate.ops_sstreamid - ** The new stream id. ** ** Returns: ** Nothing ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 19-July-87 (eric) ** written ** 11-oct-2006 (hayke02) ** Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309. [@history_template@]... */ VOID opu_Osmemory_open( OPS_STATE *global) { DB_STATUS ulmstatus; /* return status from ULM */ /* Set the output streamid location for ULM */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_sstreamid; if ( (ulmstatus = ulm_openstream( &global->ops_mstate.ops_ulmrcb )) != E_DB_OK ) { if (global->ops_mstate.ops_ulmrcb.ulm_error.err_code == E_UL0005_NOMEM) { opx_lerror(E_OP0002_NOMEMORY, 0, 0, 0, 0, 0); opx_error( E_OP0002_NOMEMORY); /* out of memory */ } #ifdef E_OP0093_ULM_ERROR else opx_verror( ulmstatus, E_OP0093_ULM_ERROR, global->ops_mstate.ops_ulmrcb.ulm_error.err_code); /* check for error */ #endif } }
/*{ ** Name: OPU_CSMEMORY_CLOSE - Close the stack ULM memory stream ** ** Description: ** This routine closes the ULM memory stream that was used ** for the stack style memory allocation and deallocation. [@comment_line@]... ** ** Inputs: ** global - ** State info for the current query. ** global->ops_mstate.ops_ulmrcb - ** The ULM control block. ** global->ops_mstate.ops_sstreamid - ** The stream id. ** ** Outputs: ** ** Returns: ** Nothing ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 19-July-87 (eric) ** written ** 11-oct-2006 (hayke02) ** Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309. [@history_template@]... */ VOID opu_Csmemory_close( OPS_STATE *global) { DB_STATUS ulmstatus; /* return status from ULM */ /* store the stream id */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_sstreamid; /* ULM will nullify ops_sstreamid */ if ( (ulmstatus = ulm_closestream( &global->ops_mstate.ops_ulmrcb )) != E_DB_OK ) { if (global->ops_mstate.ops_ulmrcb.ulm_error.err_code == E_UL0005_NOMEM) { opx_lerror(E_OP0002_NOMEMORY, 0, 0, 0, 0, 0); opx_error( E_OP0002_NOMEMORY); /* out of memory */ } #ifdef E_OP0093_ULM_ERROR else opx_verror( ulmstatus, E_OP0093_ULM_ERROR, global->ops_mstate.ops_ulmrcb.ulm_error.err_code); /* check for error */ #endif } }
VOID opc_querycomp( OPS_STATE *global) { DB_STATUS ret; global->ops_gmask |= OPS_OPCEXCEPTION; /* mark facility as being in OPC */ #ifdef OPT_F033_OPF_TO_OPC if (opt_strace(global->ops_cb, OPT_F033_OPF_TO_OPC) == TRUE) { char temp[OPT_PBLEN + 1]; bool init = 0; if (global->ops_cstate.opc_prbuf == NULL) { global->ops_cstate.opc_prbuf = temp; init++; } /* Trace all of 'global' */ if (global->ops_statement != NULL) { opt_state(global); } if (init) { global->ops_cstate.opc_prbuf = NULL; } } #endif if ( opt_strace(global->ops_cb, OPT_F071_QEP_WITHOUT_COST ) == TRUE && global->ops_subquery) { opt_cotree_without_stats( global ); } /* If this is CREATE TABLE, check for primary, unique, foreign key ** constraints to use for default base table structure. */ if (global->ops_statement && global->ops_statement->pst_type == PST_CREATE_TABLE_TYPE && global->ops_statement->pst_specific.pst_createTable. pst_createTableFlags == PST_CRT_TABLE) { QEU_CB *qeucb = global->ops_statement->pst_specific.pst_createTable.pst_createTableQEUCB; DMU_CB *dmucb = (DMU_CB *) qeucb->qeu_d_cb; bool checkit = FALSE; if (BTtest(DMU_AUTOSTRUCT, dmucb->dmu_chars.dmu_indicators)) checkit = (dmucb->dmu_chars.dmu_flags & DMU_FLAG_AUTOSTRUCT) != 0; else checkit = opt_strace(global->ops_cb, OPT_F084_TBLAUTOSTRUCT ) || global->ops_cb->ops_alter.ops_autostruct != 0; if (checkit) opc_checkcons(global->ops_statement, dmucb); } /* On entry for rule processing, assume ops_qpinit == TRUE. There */ /* is no need to allocate a memory stream since we are contuing */ /* processing on the QP that was started by the triggering statement. */ if (global->ops_qpinit == FALSE) { /* First, lets open the stack ULM memory stream that OPC uses */ opu_Osmemory_open(global); /* Tell QSF that we want to store an object; */ global->ops_qsfcb.qsf_obj_id.qso_type = QSO_QP_OBJ; 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); if (global->ops_caller_cb->opf_locator) MEcopy((PTR)"ql", sizeof("ql"), p); else 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 if ( global->ops_procedure->pst_isdbp == TRUE || ( global->ops_qheader != NULL && (global->ops_qheader->pst_mask1 & PST_RPTQRY) ) ) { 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); } else { global->ops_qsfcb.qsf_obj_id.qso_lname = 0; } /* Also allow for the case where a concurrent clash causes a new ** object at an awkward point */ if ((ret = qsf_call(QSO_CREATE, &global->ops_qsfcb)) != E_DB_OK && !(ret == E_DB_ERROR && global->ops_qsfcb.qsf_error.err_code == E_QS001C_EXTRA_OBJECT) && !((global->ops_procedure->pst_flags & PST_SET_INPUT_PARAM) && global->ops_qsfcb.qsf_error.err_code == E_QS001C_EXTRA_OBJECT)) { /* if object exists and we have a named query plan. */ if (global->ops_qsfcb.qsf_error.err_code == E_QS000A_OBJ_ALREADY_EXISTS ) { /* Log query info */ QSO_OBID *obj = &global->ops_qsfcb.qsf_obj_id; char *qrytype; char *objtype; char *objname; char *qrytext; char tmp[(DB_OWN_MAXNAME + DB_CURSOR_MAXNAME) + 3 + 1]; DB_STATUS status; QSF_RCB qsf_rb; PSQ_QDESC *qdesc; if (global->ops_procedure->pst_isdbp == TRUE) qrytype = "database procedure"; else if (global->ops_qheader != NULL && (global->ops_qheader->pst_mask1 & PST_RPTQRY) ) qrytype = "repeat query"; else qrytype = "non-repeat query"; objtype = "QSO_QP_OBJ"; if (obj->qso_lname == 0) { objname = "QSF object has no name"; } else { char fmt[30]; DB_CURSOR_ID *curid; char *user; i4 *dbid; curid = (DB_CURSOR_ID *)obj->qso_name; user = curid->db_cur_name + DB_CURSOR_MAXNAME; dbid = (i4 *)(user + DB_OWN_MAXNAME); STprintf(fmt, ":%%lx:%%lx:%%.%ds:%%.%ds:%%lx:", DB_CURSOR_MAXNAME, DB_OWN_MAXNAME); STprintf(tmp, fmt, (i4)curid->db_cursor_id[0], (i4)curid->db_cursor_id[1], curid->db_cur_name, user, (i4)(*dbid)); objname = tmp; } qsf_rb.qsf_type = QSFRB_CB; qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rb.qsf_length = sizeof(qsf_rb); qsf_rb.qsf_owner = (PTR)DB_OPF_ID; qsf_rb.qsf_obj_id.qso_handle = global->ops_caller_cb->opf_thandle; qrytext = "Query text was not available."; if (qsf_rb.qsf_obj_id.qso_handle != NULL) { status = qsf_call(QSO_INFO, &qsf_rb); if (DB_SUCCESS_MACRO(status)) { qdesc = (PSQ_QDESC*) qsf_rb.qsf_root; qrytext = qdesc->psq_qrytext; } } /* log an error */ opx_lerror((OPX_ERROR)E_OP089F_QSF_FAILCREATE, (i4)4, (PTR)qrytype, (PTR)objtype, (PTR)objname, (PTR)qrytext); } opx_verror(ret, E_OP0882_QSF_CREATE, global->ops_qsfcb.qsf_error.err_code); } /* Put the handle for the QEP into the callers CB; ** - will be used for deallocation in case of an error ** - both the object id and the lock id are needed in order to destroy ** the object */ STRUCT_ASSIGN_MACRO(global->ops_qsfcb.qsf_obj_id, global->ops_caller_cb->opf_qep); global->ops_qplk_id = global->ops_qsfcb.qsf_lk_id; global->ops_qpinit = TRUE; /* Allocate and initialize the QP. */ opc_iqp_init(global); } /* Continue the QP compilation by adding the current statement */ if (global->ops_statement != NULL) { opc_cqp_continue(global); } /* if it's time to stop compiling the query, then lets close stuff. */ /* The caller is responsible for making one additional call to OPC */ /* with ops_statement == NULL after all statements in the QP we are */ /* currently building have been compiled. Note that this is a change */ /* from the previous version of this routine which required the extra */ /* call only if a db procedure was being compiled. Such a call must */ /* also be made after the last statement in each rule list. This allows */ /* OPC to link all conditionals statements in the rule list together */ /* before continuing with the next user statement to be compiled. */ if (global->ops_statement == NULL) { /* We're finished compiling all of the statements, so lets finish ** the QP */ opc_fqp_finish(global); /* The QP is only associated with the outer query, not a rule list */ if (!global->ops_inAfterRules && !global->ops_inBeforeRules) { /* Tell QSF what the root of the QEP is; */ global->ops_qsfcb.qsf_root = (PTR) global->ops_cstate.opc_qp; if ((ret = qsf_call(QSO_SETROOT, &global->ops_qsfcb)) != E_DB_OK) { opx_verror(ret, E_OP0883_QSF_SETROOT, global->ops_qsfcb.qsf_error.err_code); } if ((ret = qsf_call(QSO_UNLOCK, &global->ops_qsfcb)) != E_DB_OK) { opx_verror(ret, E_OP089E_QSF_UNLOCK, global->ops_qsfcb.qsf_error.err_code); } /* Now lets close the stack ULM memory stream that OPC used */ opu_Csmemory_close(global); } } global->ops_gmask &= (~OPS_OPCEXCEPTION); /* mark facility as leaving OPC */ }
/*{ ** Name: opn_ceval - evaluate the cost of the join operator tree ** ** Description: ** Entry point for routines which evaluate cost of a join operator tree. ** Contains checks for timeouts within the optimizer. ** ** Inputs: ** subquery ptr to subquery being analyzed ** ->ops_estate.opn_sroot ptr to root of join operator tree ** ** Outputs: ** subquery->ops_bestco ptr to best plan found ** subquery->ops_cost cost of best plan found ** Returns: ** VOID ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 11-jun-86 (seputis) ** initial creation from costeval ** 2-nov-88 (seputis) ** changed CSstatistics interface ** 2-nov-88 (seputis) ** add trace flag to timeout on number of plans being evaluated ** 15-aug-89 (seputis) ** add trace flag to adjust timeout factor which converts cost to time ** used to help isolate early timeout problems ** 16-may-90 (seputis) ** - b21582, move timeout checking to opn_timeout routine so it can be ** called from opn_arl ** 17-oct-90 (seputis) ** - b33386 - print error is no qep is found ** 22-apr-91 (seputis) ** - fix floating point exception handling problems ** 19-nov-99 (inkdo01) ** Changes to remove EXsignal from opn_exit processing. ** 18-oct-02 (inkdo01) ** Changes to enable new enumeration. ** 30-mar-2004 (hayke02) ** Call opn_exit() with a FALSE longjump. ** 30-Jun-2006 (kiria01) b116309 ** Capture memory exhaustion error to errlog.log. ** 11-Mar-2008 (kschendel) b122118 ** Remove unused ops_tempco. Fix up bfexception stuff so that we ** stop calling recover pointlessly at the start of every query. [@history_line@]... */ OPN_STATUS opn_ceval( OPS_SUBQUERY *subquery) { EX_CONTEXT excontext; /* context block for exception ** handler*/ OPN_SUBTREE *opn_ssubtp; /* dummy var ignored at this level ** - list of subtrees with possible cost ** orderings (including reformats) ** - all element in the list have same ** relations but in different order or ** use a different tree structure. */ OPN_RLS *opn_srlmp; /* dummy var ignored at this level ** - list of list of subtrees, with a ** different set of relations for each ** OPN_RLS element */ OPN_EQS *opn_seqp; /* dummy var ignored at this level ** - used to create a list of different ** OPN_SUBTREE (using indexes) if ** an index exists. */ OPN_STATUS sigstat = OPN_SIGOK; if ( EXdeclare(opn_mhandler, &excontext) == EX_DECLARE ) /* set ** up exception handler to ** recover from out of memory ** errors */ { /* this point will only be reached if the enumeration processing has ** run out of memory. The optimizer will try to continue by copying ** the best CO tree found so far, out of enumeration memory, and ** reinitializing the enumeration stream, and continuing. ** The out-of-memory error will be reported if a complete pass of ** cost evaluation cannot be completed. */ (VOID)EXdelete(); /* cancel exception handler prior ** to exiting routine */ if (subquery->ops_global->ops_gmask & OPS_FLINT) { subquery->ops_global->ops_gmask &= ~OPS_FLINT; /* reset exception ** indicator */ return(OPN_SIGOK); /* skip this plan if a float ** or integer exception has occurred ** during processing */ } if ( EXdeclare(opn_mhandler, &excontext) == EX_DECLARE ) /* set ** exception handler to catch case in ** which no progress is made */ { (VOID)EXdelete(); /* cancel exception handler prior ** to exiting routine */ if (subquery->ops_bestco) opx_verror(E_DB_WARN, E_OP0400_MEMORY, (OPX_FACILITY)0); /* report ** warning message to caller */ else { opx_lerror(E_OP0400_MEMORY, 0); /* Output to errlog.log as well kiria01-b116309 */ opx_error(E_OP0400_MEMORY); /* exit with a user error if the query ** cannot find at least one acceptable ** query plan */ } opn_exit(subquery, FALSE); /* exit with current query plan */ return(OPN_SIGEXIT); } opn_recover(subquery); /* routine will copy best CO tree ** and reinitialize memory stream */ } subquery->ops_global->ops_gmask &= (~OPS_FPEXCEPTION); /* reset fp exception ** indicator before evaluating ** plan */ if (subquery->ops_global->ops_gmask & OPS_BFPEXCEPTION && subquery->ops_bestco != NULL) opn_recover(subquery); /* if the current best plan occurred with ** exceptions then enumeration memory needs ** to be flushed, so that subsequent plans ** do not use subtrees which may have ** been created with exceptions, this means ** that the OPF cache of sub-trees is not ** used if one exception has occurred and ** the current best plan was created with ** exceptions */ (VOID) opn_nodecost ( subquery, subquery->ops_global->ops_estate.opn_sroot, (subquery->ops_mask & OPS_LAENUM) ? subquery->ops_laeqcmap : &subquery->ops_eclass.ope_maps.opo_eqcmap, &opn_ssubtp, &opn_seqp, &opn_srlmp, &sigstat); if (sigstat != OPN_SIGEXIT && !(subquery->ops_mask & OPS_LAENUM) && opn_timeout(subquery)) /* check for timeout (but only for ** old style enumeration) */ { (VOID)EXdelete(); /* cancel exception handler prior ** to exiting routine, call after ** opn_timeout in case out of memory ** errors occur */ opn_exit(subquery, FALSE); /* at this point we ** return the subquery->opn_bestco ** tree, this ** could also happen in freeco ** and enumerate */ return(OPN_SIGEXIT); } (VOID)EXdelete(); /* cancel exception handler prior ** to exiting routine */ return(sigstat); }
/*{ ** Name: ops_init - initialize structures needed for optimization ** ** Description: ** This routine will initialize the "global state" variable which contains ** all information for the optimization of this query for this session. ** ** Inputs: ** global ptr to global state variable ** .ops_cb ptr to session control block ** .ops_caller_cb ptr to same object as opf_cb ** opf_cb caller's control block ** ** Outputs: ** global all components initialized ** Returns: ** E_DB_OK, E_DB_ERROR ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 24-feb-86 (seputis) ** initial creation ** 26-nov-90 (stec) ** Added initialization of ops_prbuf in OPS_STATE struct. ** 28-dec-90 (stec) ** Changed initialization of print buffer; ops_prbuf has been ** removed, opc_prbuf in OPC_STATE struct will be initialized ** instead. ** 28-jan-91 (seputis) ** added support for OPF ACTIVE FLAG ** 11-jun-91 (seputis) ** ifdef distributed code until header files merge ** 04-sep-92 (fpang) ** Fixed initialization of rdr_r1_distrib. ** 27-apr-95 (inkdo01) ** Init ops_osubquery to NULL ** 26-nov-96 (inkdo01) ** Allow users OPF memory equal to 1.5 config.dat definition. That way ** the boundary users don't dictate the size of the mem pool (it being ** highly unlikely that all users will want big memory simultaneously). ** 12-dec-96 (inkdo01) ** Shamed into doing the above change more rigourously. Now a new ** config parm (opf_maxmemf) defines the proportion of the OPF pool ** available to any session. This gets computed in opsstartup, so the ** code added for the previous change is now removed. ** 20-jun-1997 (nanpr01) ** Initialize the rdf_info_blk to NULL. This is specially required ** for query without a base table. ** 23-oct-98 (inkdo01) ** Init opc_retrowno, opc_retrowoff for row producing procs. ** 27-oct-98 (inkdo01) ** Quicky afterthought to init opc_retrow_rsd. ** 11-oct-2006 (hayke02) ** Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309. ** 25-Nov-2008 (hanal04) Bug 121248 ** Initialise new caller_ref field in the opv_rdfcb to avoid SEGVs ** later on. ** 25-feb-10 (smeke01) b123333 ** As the NULL-ing of ops_trace.opt_conode has been remmoved from ** opt_printCostTree() we need to make sure it is initialised here ** prior to any call of opt_cotree() by trace point op145 (set qep). [@history_line@]... [@history_template@]... */ VOID ops_init( OPF_CB *opf_cb, OPS_STATE *global) { /* initialize some variables so that error recovery can determine which ** resources to free (i.e. which resources have been successfully ** allocated) ** - this must be done prior to the allocation of a memory stream since ** the streamid is used to indicate whether any resources at all have ** been allocated */ global->ops_cb = (OPS_CB *)opf_cb->opf_scb; /* save session control block */ /* global->ops_caller_cb initialized before exception handler established */ global->ops_adfcb = global->ops_cb->ops_adfcb; /* get current ADF control ** block for session */ if (global->ops_adfcb) { /* init adf_constants since this may uninitialized after the ** previous query executed by QEF, and may cause ADF to write ** to deallocated memory */ global->ops_adfcb->adf_constants = (ADK_CONST_BLK *)NULL; } global->ops_qheader = NULL; global->ops_statement = NULL; global->ops_procedure = NULL; /* - NULL indicates that QSF query ** tree has not been fixed ** - used by error handling to determine ** if this resource needs to be ** deallocated */ /* global->ops_lk_id initialized below */ /* global->ops_parmtotal initialized below */ global->ops_mstate.ops_streamid = NULL;/* init so deallocate routines do not ** access unless it is necessary */ global->ops_mstate.ops_sstreamid = NULL; /* init so deallocate routines do ** not access unless it is necessary */ global->ops_mstate.ops_tstreamid = NULL; /* the temporary buffer stream is ** allocated only when needed */ global->ops_subquery = NULL; /* initialize the subquery list */ global->ops_osubquery = NULL; /* initialise pointer used in opt_printCostTree() for tracing CO node */ global->ops_trace.opt_conode = NULL; /* global->ops_astate initialized by aggregate processing phase */ /* global->ops_estate initialized by joinop processing phase */ global->ops_qpinit = FALSE; /* query plan object not allocated yet*/ global->ops_cstate.opc_prbuf = NULL;/* trace print buffer ptr. */ global->ops_cstate.opc_relation = NULL; /* init relation descriptor ** so deallocation routine will ** only be done if OPC allocates ** an RDF descriptor */ global->ops_cstate.opc_retrowno = -1; global->ops_cstate.opc_retrowoff = 0; /* result row buffer init */ global->ops_cstate.opc_retrow_rsd = (PST_QNODE *) NULL; ops_qinit(global, (PST_STATEMENT *)NULL); /* init range table only for resource ** deallocation */ { /* allocate a memory stream to be used by the optimizer ** - the streamid PTR was initialized to NULL earlier - prior to the ** establishment of the exception handler so that it can be used ** to indicate to the cleanup routines that no resources have been ** allocated */ DB_STATUS ulmstatus; global->ops_mstate.ops_ulmrcb.ulm_facility = DB_OPF_ID; /* identifies optimizer ** so that ULM can make SCF calls on ** behave of the optimizer */ global->ops_mstate.ops_ulmrcb.ulm_poolid = global->ops_cb->ops_server->opg_memory; /* poolid of OPF ** obtained at server startup time */ global->ops_mstate.ops_ulmrcb.ulm_blocksize = 0; /* use default for ** now */ global->ops_mstate.ops_memleft =global->ops_cb->ops_alter.ops_maxmemory; /* save amount of memory which can be ** used by this session */ global->ops_mstate.ops_mlimit = global->ops_mstate.ops_memleft / 10; /* if 10% of memory is left trigger ** garbage collection routines */ global->ops_mstate.ops_ulmrcb.ulm_memleft = &global->ops_mstate.ops_memleft; /* ** and point to it for ULM */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_streamid; /* ** Where ULM will return streamid */ global->ops_mstate.ops_ulmrcb.ulm_flags = ULM_PRIVATE_STREAM; /* Allocate private, thread-safe streams */ ulmstatus = ulm_openstream(&global->ops_mstate.ops_ulmrcb); /* get memory for the ** optimizer */ if (DB_FAILURE_MACRO(ulmstatus)) { opx_lerror(E_OP0002_NOMEMORY, 0, 0, 0, 0, 0); opx_verror( ulmstatus, E_OP0002_NOMEMORY, global->ops_mstate.ops_ulmrcb.ulm_error.err_code); } global->ops_mstate.ops_tptr = NULL; /* init temp buffer ptr from ** ops_tstreamid*/ global->ops_mstate.ops_tsize = 0; /* init temp buffer size */ /* ULM has set ops_streamid to the ** streamid for "global optimizer" ** memory, note the enumeration will ** create other streamids for "local" ** memory but still use the ** same control ops_ulmrcb ** in order to decrement and ** increment the same "memleft" counter */ /* initialize ptrs to full size array of ptrs, allocate once for DB procedure ** or 4K will be wasted for each assignment statement and query */ global->ops_mstate.ops_trt = NULL; global->ops_mstate.ops_tft = NULL; global->ops_mstate.ops_tat = NULL; global->ops_mstate.ops_tet = NULL; global->ops_mstate.ops_tbft = NULL; global->ops_mstate.ops_usemain = FALSE; /* disable redirection of ** memory allocation */ global->ops_mstate.ops_totalloc = 0; /* init stats fields */ global->ops_mstate.ops_countalloc = 0; global->ops_mstate.ops_count2kalloc = 0; global->ops_mstate.ops_recover = 0; } { /* get the procedure from QSF */ DB_STATUS qsfstatus; /* QSF return status */ qsfstatus = ops_gqtree(global); /* get procedure from QSF */ if (DB_FAILURE_MACRO(qsfstatus)) opx_verror( qsfstatus, E_OP0085_QSO_LOCK, global->ops_qsfcb.qsf_error.err_code); /* report error */ } { /* initialize the RDF control block used to fetch information for ** the global range table */ RDR_RB *rdfrb; /* ptr to RDF request block */ rdfrb = &global->ops_rangetab.opv_rdfcb.rdf_rb; global->ops_rangetab.opv_rdfcb.rdf_info_blk = NULL; global->ops_rangetab.opv_rdfcb.caller_ref = (RDR_INFO **)NULL; rdfrb->rdr_db_id = global->ops_cb->ops_dbid; /* save the data base id ** for this session only */ rdfrb->rdr_unique_dbid = global->ops_cb->ops_udbid; /* save unique ** dbid for all sessions */ rdfrb->rdr_session_id = global->ops_cb->ops_sid; /* save the session id ** for this session */ rdfrb->rdr_fcb = global->ops_cb->ops_server->opg_rdfhandle; /* save the ** poolid for the RDF info */ if (global->ops_cb->ops_smask & OPS_MDISTRIBUTED) rdfrb->rdr_r1_distrib = DB_3_DDB_SESS; else rdfrb->rdr_r1_distrib = 0; if (global->ops_cb->ops_smask & OPS_MCONDITION) rdfrb->rdr_2types_mask = RDR2_TIMEOUT; /* indicate that timeout should ** occur on all RDF accesses */ else rdfrb->rdr_2types_mask = 0; rdfrb->rdr_instr = RDF_NO_INSTR; } }