/*{ ** Name: psy_cproc - Create a database procedure definition in ** the system catalogs. ** ** Description: ** ** Inputs: ** ** Outputs: ** Exceptions: ** none ** ** Side Effects: ** Modifies system catalogs. ** ** History: ** 27-apr-88 (stec) ** Created. ** 23-aug-88 (stec) ** Added comments, initialize new fields in DB_PROCEDURE. ** 26-apr-89 (andre) ** For internal procedures, set db_mask[0] to DB_IPROC. ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 12-jun-90 (andre) ** when trying to destroy a dbproc QEP, use "private" alias, which is ** always defined as opposed to the "public" alias which would not be ** defined if the dbproc is not grantable. ** 04-mar-92 (andre) ** set DB_ACTIVE_DBP in db_mask[0] to indicate that the dbproc is not ** abandoned. If the dbproc is grantable, set DB_DBPGRANT_OK in ** db_mask[0]. ** 18-may-92 (andre) ** call psy_dbp_status() to verify that the new dbproc is not abandoned ** and trust psy_dbp_status() to determine whether the dbproc is ** grantable or just active. ** 19-may-92 (andre) ** in pslsgram.yi, pss_dependencies_stream was opened to collect info ** about objects/privileges on which the new dbproc depends; ** this stream must be closed before leaving this function since the ** dependence information will be of no use once we return ** 01-jun-92 (andre) ** pass information about objects/privileges on which the new database ** procedure depends to QEF. ** 26-jun-92 (andre) ** enter information about the dbproc into IIPROCEDURE and the list of ** objects and privileges on which it depends into IIDBDEPENDS and ** IIPRIV respectively before calling psy_dbp_status() to determine ** whether it is active. This is necessary since otherwise it would be ** impossible to create mutually recursive database procedures (if P1 ** calls P2 and we are trying to create P2 calling P1, psy_dbp_status() ** will report that P1 is dormant and prevent us from creating P2) ** ** Since we won't know whether the dbproc is active and/or grantable ** until psy_dbp_status() is done, we will set only DB_DBP_INDEP_LIST ** bit in IIPROCEDURE.dbp_mask1 here, unless the independent ** object/privilege list is empty, in which case there is no reason to ** call psy_dbp_status(), so we will set DB_DBPGRANT_OK and ** DB_ACTIVE_DBP bits in IIPROCEDURE.dbp_mask1. ** ** If the independent object/privilege list is not empty and the ** procedure is not dormant, psy_dbp_status() will set appropriate bits ** (DB_DBPGRANT_OK and/or DB_ACTIVE_DBP) in IIPROCEDURE.dbp_mask1 once ** it has determined whether the dbproc is active or grantable ** 09-sep-92 (andre) ** psy_dbp_status() no longer accepts or returns an indicator of ** whether cache had to be flushed in psy_dbp_priv_check() ** 07-nov-92 (andre) ** we will no longer create private aliases for dbproc QPs ** 22-feb-93 (rblumer) ** initialize new RDF proc_param variables for both normal and ** set-input procedures; reverse order of MEcopy and I4assign in ** QP cleanup code so that qsf id gets set up correctly. ** 13-apr-93 (andre) ** if creating a system-generated procedure, independent ** object/privilege list will be empty - QEF will insert IIDBDEPENDS ** tuple recording dependence of the dbproc on a constraint (for ** constraint-enforcing dbprocs) or view (for CHECK OPTION-enforcing ** dbprocs.) Here we will set bits indicating that there will be ** independent object list and that the dbproc is active but not ** grantable (we don't want the user to grant privileges on ** system-generated dbprocs) ** 01-sep-93 (andre) ** in the course of parsing a dbproc definition, we will try to ** determine id of a base table on which the dbproc depends; here we ** will copy it into proctuple.dbPdbp_ubt_id to ensure that it gets ** inserted into IIPROCEDURE ** 22-oct-93 (rblumer) ** normal procedures will now have their parameters inserted into the ** catalogs (previously just set-input procedures did); changed ** initialization of db_parameterCount, rdr_proc_param_cnt and ** rdr_proc_params to work for both types of procedures. ** 30-apr-94 (andre) ** fix for bug 61087: ** proctuple.db_mask[0] was being set before proctuple was MEfill'd ** with NULLCHAR; moved the line initializing proctuple.db_mask[0] ** below call to MEfill() ** 16-jun-94 (andre) ** Bug #64395 ** it is dangerous to cast a (char *) into a (DB_CURSOR_ID *) and then ** dereference the resulting pointer because the chat ptr may not be ** pointing at memory not aligned on an appopriate boundary. Instead, ** we will allocate a DB_CURSOR_ID structure on the stack, initialize ** it and MEcopy() it into the char array ** 19-june-06 (dougi) ** Add DBP_DATA_CHANGE flag for BEFORE trigger validation. ** 28-march-2008 (dougi) ** Changes to support table procedures and named result row elements. ** 4-feb-2009 (dougi) ** Tidy up computation of table procedure result row length. ** 30-mar-2009 (toumi01) b121871 ** Rewrite and simplify the computation of table procedure input ** and output parameter count and width (fixes a logic error that ** caused the result width to be decremented by the width of the ** first result parameter when there were no input parameters). */ DB_STATUS psy_cproc( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; i4 textlen; QSF_RCB qsf_rb; DB_PROCEDURE proctuple; DB_STATUS status, stat; i4 err_code; PSY_TBL dbp_descr; i4 dbp_mask[2]; bool empty_indep_list, rowproc; /* If this is a recreate case, and this code gets called ** just return since there is no work to be done, not even ** recovery of resources. */ if (sess_cb->pss_dbp_flags & PSS_RECREATE) return(E_DB_OK); /* determine if the new dbproc depends on any object or privileges */ if ( sess_cb->pss_indep_objs.psq_objs || sess_cb->pss_indep_objs.psq_objprivs || sess_cb->pss_indep_objs.psq_colprivs ) { empty_indep_list = FALSE; } else { empty_indep_list = TRUE; } /* ** Initialize the header of the QSF control block ** NOTE: it is important that we init qsf_rb before calling ** psy_dbp_status() - if the dbproc cannot be created, code under ** exit: will expect the control block set up for deleting the query ** text QSF object and the query plan QSF object */ 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_PSF_ID; qsf_rb.qsf_sid = sess_cb->pss_sessid; STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); /* Retrieve info about the procedure text object */ status = qsf_call(QSO_INFO, &qsf_rb); if (DB_FAILURE_MACRO(status)) { goto exit; } /* Get the text length. */ MEcopy((PTR) qsf_rb.qsf_root, sizeof(i4), (PTR) &textlen); /* Initialize the II_PROCEDURE tuple. */ MEfill(sizeof(proctuple), NULLCHAR, (PTR) &proctuple); (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME), (PTR)&proctuple.db_dbpname); /* Current user is the owner. */ STRUCT_ASSIGN_MACRO(sess_cb->pss_user, proctuple.db_owner); proctuple.db_txtlen = textlen; TMnow((SYSTIME *) &proctuple.db_txtid); /* ** if the independent object/privilege list is non-empty, we will set ** DB_DBP_INDEP_LIST bit and leave it to psy_dbp_status() to set the ** remaining bits, if appropriate; otherwise we will set DB_DBPGRANT_OK and ** DB_ACTIVE_DBP bits and avoid calling psy_dbp_status() ** ** if creating a system-generated dbproc, mark the dbproc ACTIVE and ** indicate that there is independent object list (there is not one at this ** point, but QEF will insert IIDBDEPENDS tuple recording dependence of the ** dbproc on a constraint (for constraint-enforcing dbprocs) or view (for ** CHECK OPTION-enforcingdbprocs.) */ /* If working on internal dbproc, set DB_IPROC in db_mask[0] */ if (sess_cb->pss_dbp_flags & PSS_IPROC) proctuple.db_mask[0] |= DB_IPROC; if (sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED) proctuple.db_mask[0] |= DBP_SYSTEM_GENERATED | DB_ACTIVE_DBP | DB_DBP_INDEP_LIST; else if (empty_indep_list) proctuple.db_mask[0] |= DB_DBPGRANT_OK | DB_ACTIVE_DBP; else proctuple.db_mask[0] |= DB_DBP_INDEP_LIST; if (sess_cb->pss_dbp_flags & PSS_SET_INPUT_PARAM) proctuple.db_mask[0] |= DBP_SETINPUT; if (sess_cb->pss_dbp_flags & PSS_NOT_DROPPABLE) proctuple.db_mask[0] |= DBP_NOT_DROPPABLE; if (sess_cb->pss_dbp_flags & PSS_SUPPORTS_CONS) proctuple.db_mask[0] |= DBP_CONS; if (sess_cb->pss_dbp_flags & PSS_DATA_CHANGE) proctuple.db_mask[0] |= DBP_DATA_CHANGE; if (sess_cb->pss_dbp_flags & PSS_OUT_PARMS) proctuple.db_mask[0] |= DBP_OUT_PARMS; if (sess_cb->pss_dbp_flags & PSS_TX_STMT) proctuple.db_mask[0] |= DBP_TX_STMT; if (sess_cb->pss_dbp_flags & PSS_ROW_PROC) { rowproc = TRUE; proctuple.db_mask[0] |= DBP_ROW_PROC; } else rowproc = FALSE; proctuple.db_mask[1] = 0; /* ** if we were able to determine id of a base table on which this dbproc will ** depend, copy it into proctuple */ proctuple.db_dbp_ubt_id.db_tab_base = sess_cb->pss_dbp_ubt_id.db_tab_base; proctuple.db_dbp_ubt_id.db_tab_index = sess_cb->pss_dbp_ubt_id.db_tab_index; /* db_procid to be filled in by RDF or QEF */ proctuple.db_parameterCount = 0; proctuple.db_recordWidth = 0; proctuple.db_rescolCount = 0; proctuple.db_resrowWidth = 0; if (sess_cb->pss_procparmlist != (QEF_DATA *) NULL) { DB_PROCEDURE_PARAMETER *param_tuple; QEF_DATA *listptr; /* compute count and total width of input and result parameters */ for (listptr = sess_cb->pss_procparmlist; listptr != (QEF_DATA *) NULL; listptr = listptr->dt_next) { param_tuple = (DB_PROCEDURE_PARAMETER *)listptr->dt_data; if (param_tuple->dbpp_flags & DBPP_RESULT_COL) { proctuple.db_rescolCount++; proctuple.db_resrowWidth = param_tuple->dbpp_offset + param_tuple->dbpp_length; } else { proctuple.db_parameterCount++; proctuple.db_recordWidth = param_tuple->dbpp_offset + param_tuple->dbpp_length; } } if (proctuple.db_rescolCount > 0) proctuple.db_resrowWidth -= proctuple.db_recordWidth; } /* Initialize the RDF request block. */ pst_rdfcb_init(&rdf_cb, sess_cb); (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME), (PTR)&rdf_rb->rdr_name.rdr_prcname); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner); rdf_rb->rdr_types_mask = RDR_PROCEDURE; rdf_rb->rdr_update_op = RDR_APPEND; rdf_rb->rdr_qrytuple = (PTR) &proctuple; rdf_rb->rdr_l_querytext = textlen; rdf_rb->rdr_querytext = ((char *) qsf_rb.qsf_root) + sizeof(i4); /* ** pass information about objects/privileges on which the new database ** procedure depends to QEF */ sess_cb->pss_indep_objs.psq_grantee = &sess_cb->pss_user; rdf_rb->rdr_indep = (PTR) &sess_cb->pss_indep_objs; /* fill in the description of the procedure's parameters ** (which RDF/QEF will store into iiprocedure_parameter); */ rdf_rb->rdr_proc_param_cnt = proctuple.db_parameterCount + proctuple.db_rescolCount; rdf_rb->rdr_proc_params = sess_cb->pss_procparmlist; /* Create a new procedure in the system catalogs */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0137_DUPLICATE_PROCS) { /* Retry */ psy_cb->psy_error.err_code = E_PS0008_RETRY; } else { (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } goto exit; } /* ** if the independent object/privilege list is non-empty, verify that the ** dbproc we are about to create is not abandoned; strictly speaking, as ** long as the independent object list is empty, we are guaranteed that the ** dbproc is not abandoned (user posesses required privileges), but we will ** take an extra step and try to determine whether it is grantable */ if (!empty_indep_list) { MEcopy((PTR) psy_cb->psy_tabname, sizeof(DB_DBP_NAME), (PTR) &dbp_descr.psy_tabnm); dbp_descr.psy_tabid.db_tab_base = proctuple.db_procid.db_tab_base; dbp_descr.psy_tabid.db_tab_index = proctuple.db_procid.db_tab_index; status = psy_dbp_status(&dbp_descr, sess_cb, (PSF_QUEUE *) NULL, (i4) PSQ_CREDBP, dbp_mask, &psy_cb->psy_error); if (DB_FAILURE_MACRO(status)) { goto exit; } } exit: /* ** close the memory stream which was used to allocate descriptors of ** objects/privileges on which the new dbproc depends */ stat = psf_mclose(sess_cb, sess_cb->pss_dependencies_stream, &psy_cb->psy_error); if (DB_FAILURE_MACRO(stat) && stat > status) status = stat; /* ** ensure that no one tries to use the stream that is no longer valid */ sess_cb->pss_dependencies_stream = (PSF_MSTREAM *) NULL; /* Get a lock on the query text from QSF */ qsf_rb.qsf_lk_state = QSO_EXLOCK; stat = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0A08_CANTLOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (stat > status) status = stat; } else { /* Now destroy the query text */ stat = qsf_call(QSO_DESTROY, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0A09_CANTDESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (stat > status) status = stat; } } /* Destroy the procedure QP in QSF if things went wrong. */ if (DB_FAILURE_MACRO(status)) { PSS_DBPALIAS dbpid; DB_CURSOR_ID dbp_curs_id; qsf_rb.qsf_feobj_id.qso_type = QSO_ALIAS_OBJ; qsf_rb.qsf_feobj_id.qso_lname = sizeof(dbpid); /* Identify the object first */ dbp_curs_id.db_cursor_id[0] = dbp_curs_id.db_cursor_id[1] = 0; (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], DB_TAB_MAXNAME, (PTR)dbp_curs_id.db_cur_name); MEcopy((PTR) &dbp_curs_id, sizeof(DB_CURSOR_ID), (PTR) dbpid); (VOID) MEcopy((PTR) &sess_cb->pss_user, DB_OWN_MAXNAME, (PTR) (dbpid + sizeof(DB_CURSOR_ID))); I4ASSIGN_MACRO(sess_cb->pss_udbid, *(i4 *) (dbpid + sizeof(DB_CURSOR_ID) + DB_OWN_MAXNAME)); (VOID)MEcopy((PTR) dbpid, sizeof(dbpid), (PTR) qsf_rb.qsf_feobj_id.qso_name); /* See if QP for the alias already exists. */ qsf_rb.qsf_lk_state = QSO_SHLOCK; stat = qsf_call(QSO_JUST_TRANS, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { if (qsf_rb.qsf_error.err_code != E_QS0019_UNKNOWN_OBJ) { (VOID) psf_error(E_PS037A_QSF_TRANS_ERR, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (stat > status) status = stat; goto exit1; } else { /* QP disappeared, which is alright. */ goto exit1; } } /* Now destroy the QP object in QSF */ stat = qsf_call(QSO_DESTROY, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0A09_CANTDESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (stat > status) status = stat; } } exit1: return (status); }
/*{ ** Name: psq_cbreturn - Clear call and session CB after processing. ** ** Description: ** This routine is a common routine that clears up the call (psq_cb) and ** session CB (sess_cb) after processing a query. The routine ** psq_parseqry still does its own work as it handles various errors ** associated with textual queries. ** ** Inputs: ** psq_cb Pointer to call CB. ** sess_cb Pointer to the session control block ** ** Outputs: ** psq_cb ** .psq_result Result query tree. ** Returns: ** DB_STATUS ** Exceptions: ** None ** ** Side Effects: ** None ** ** History: ** 21-apr-89 (neil) ** Extracted this from psq_parseqry to allow it to be called from ** other routines as well. ** 15-jun-92 (barbara) ** Sybil merge. Pass in sess control block to pst_clrrng. ** 25-may-1993 (rog) ** Moved clean-up/exit code here from psq_parseqry() above, and added ** status argument so that we know whether to execute the good exit ** code or the bad exit code. ** 10-aug-93 (andre) ** fixed cause of a compiler warning ** 27-aug-93 (andre) ** (part of fix for bug 54348) ** moved code responsible for destroying a dbproc QEP into a separate ** function (psq_destr_dbp_qep()) which will be called from ** psq_cbreturn() and from psq_recreate() if an error occurs AFTER the ** dbproc QEP QSF object has been created ** 16-mar-94 (andre) ** use psf_retry() to determine whether we are going to retry parsing ** this query and, therefore, whether we should destroy any QSF objects ** created during the just completed attempt ** 28-jan-2004 (schka24) ** Close partition def memory if open. ** 15-Mar-2006 (kschendel) ** Close function-arg stream if open. ** 28-nov-2007 (dougi) ** Different logic for PSQ_REPDYN (for cached dynamic queries). */ DB_STATUS psq_cbreturn( PSQ_CB *psq_cb, PSS_SESBLK *sess_cb, DB_STATUS ret_val) { DB_STATUS status; i4 err_code; QSF_RCB qsf_rb; 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_PSF_ID; qsf_rb.qsf_sid = sess_cb->pss_sessid; /* Tasks that are common to both a normal return and an error return. */ do /* Something to break out of */ { /* Clear any cached stack blocks as we're going to ** trash the memory stream in here anyway. */ sess_cb->pss_stk_freelist = NULL; /* Other stuff that shouldn't be left dangling */ sess_cb->pss_yyvars = NULL; /* ** Clear out the user's range table. */ status = pst_clrrng(sess_cb, &sess_cb->pss_usrrange, &psq_cb->psq_error); if (status == E_DB_FATAL) ret_val = status; /* ** Clear out the auxliary range table. */ status = pst_clrrng(sess_cb, &sess_cb->pss_auxrng, &psq_cb->psq_error); if (status == E_DB_FATAL) ret_val = status; /* ** If the statement has emitted query text, close the stream. */ if (sess_cb->pss_tchain != (PTR) NULL) { status = psq_tclose(sess_cb->pss_tchain, &psq_cb->psq_error); if (status == E_DB_FATAL) ret_val = status; sess_cb->pss_tchain = (PTR) NULL; } if (sess_cb->pss_tchain2 != (PTR) NULL) { status = psq_tclose(sess_cb->pss_tchain2, &psq_cb->psq_error); if (status == E_DB_FATAL) ret_val = status; sess_cb->pss_tchain2 = (PTR) NULL; } /* Close partition definition working memory stream if in use */ if (sess_cb->pss_ses_flag & PSS_PARTDEF_STREAM_OPEN) { status = ulm_closestream(&sess_cb->pss_partdef_stream); /* Toss any error */ sess_cb->pss_ses_flag &= ~PSS_PARTDEF_STREAM_OPEN; } /* Close nested-function-call arg list stack if it was needed */ if (sess_cb->pss_funarg_stream != NULL) { ULM_RCB ulm; ulm.ulm_facility = DB_PSF_ID; ulm.ulm_poolid = Psf_srvblk->psf_poolid; ulm.ulm_streamid_p = &sess_cb->pss_funarg_stream; ulm.ulm_memleft = &sess_cb->pss_memleft; status = ulm_closestream(&ulm); /* Ignore error */ sess_cb->pss_funarg_stream = NULL; } } while (0); for (; ret_val == E_DB_OK; ) /* Something to break out of */ { /* ** This is the path we take for a successful exit. ** If we have a problem here, we break out of this loop and ** fall through to the failure exit code. */ /* ** Set the QSF id of the return object and unlock it, if any. */ if (sess_cb->pss_ostream.psf_mstream.qso_handle != (PTR) NULL) { qsf_rb.qsf_obj_id.qso_handle = sess_cb->pss_ostream.psf_mstream.qso_handle; qsf_rb.qsf_lk_id = sess_cb->pss_ostream.psf_mlock; if (psq_cb->psq_mode == PSQ_REPDYN) { /* If cached dynamic qp already exists, destroy parse ** tree object. */ if (ret_val = qsf_call(QSO_DESTROY, &qsf_rb)) { (VOID) psf_error(E_PS0A09_CANTDESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); /* break out to the failure code. */ break; } } else { /* If not cached dynamic, copy object ID and unlock ** parse tree. */ STRUCT_ASSIGN_MACRO(sess_cb->pss_ostream.psf_mstream, psq_cb->psq_result); if (ret_val = qsf_call(QSO_UNLOCK, &qsf_rb)) { (VOID) psf_error(E_PS0B05_CANT_UNLOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); /* break out to the failure code. */ break; } } sess_cb->pss_ostream.psf_mlock = 0; } /* ** Unlock the text stream if it was used. ** this is unlocked after the text stream is created. ** (Don't know why this was taken out.) */ #ifdef NO if (sess_cb->pss_tstream.psf_mstream.qso_handle != (PTR) NULL) { qsf_rb.qsf_obj_id.qso_handle = sess_cb->pss_tstream.psf_mstream.qso_handle; qsf_rb.qsf_lk_id = sess_cb->pss_tstream.psf_mlock; if (ret_val = qsf_call(QSO_UNLOCK, &qsf_rb)) { (VOID) psf_error(E_PS0B05_CANT_UNLOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); /* break out to the failure code. */ break; } sess_cb->pss_tstream.psf_mlock = 0; } #endif /* Unlock the control block stream if it was used */ if (sess_cb->pss_cbstream.psf_mstream.qso_handle != (PTR) NULL) { qsf_rb.qsf_obj_id.qso_handle = sess_cb->pss_cbstream.psf_mstream.qso_handle; qsf_rb.qsf_lk_id = sess_cb->pss_cbstream.psf_mlock; if (ret_val = qsf_call(QSO_UNLOCK, &qsf_rb)) { (VOID) psf_error(E_PS0B05_CANT_UNLOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); /* break out to the failure code. */ break; } sess_cb->pss_cbstream.psf_mlock = 0; } /* ** We need to deallocate memory if the same query is to be tried ** again. This is supposed to fix The 'drop table, nonexistent_table' ** memory leak problem. */ if (psf_retry(sess_cb, psq_cb, ret_val)) { if (sess_cb->pss_ostream.psf_mstream.qso_handle != (PTR) NULL) { (VOID) psf_mclose(sess_cb, &sess_cb->pss_ostream, &psq_cb->psq_error); sess_cb->pss_ostream.psf_mstream.qso_handle = (PTR) NULL; } if (sess_cb->pss_tstream.psf_mstream.qso_handle != (PTR) NULL) { (VOID) psf_mclose(sess_cb, &sess_cb->pss_tstream, &psq_cb->psq_error); sess_cb->pss_tstream.psf_mstream.qso_handle = (PTR) NULL; } if (sess_cb->pss_cbstream.psf_mstream.qso_handle != (PTR) NULL) { (VOID) psf_mclose(sess_cb, &sess_cb->pss_cbstream, &psq_cb->psq_error); sess_cb->pss_cbstream.psf_mstream.qso_handle = (PTR) NULL; } } /* end with no output streams */ sess_cb->pss_ostream.psf_mstream.qso_handle = (PTR) NULL; sess_cb->pss_tstream.psf_mstream.qso_handle = (PTR) NULL; sess_cb->pss_cbstream.psf_mstream.qso_handle = (PTR) NULL; if (ret_val == E_DB_OK) { /* ** this IF statement is here to keep acc from complaining - we would ** never reach this point unless ret_val was E_DB_OK */ return (ret_val); } } /* This is the failure exit code. */ /* ** On an error, the yacc error handling function will call psf_error. ** All that's necessary here is to return a status indicating that ** an error has occurred. If an output object has been allocated, ** and the error caused the statement to fail, deallocate the object ** before returning. Same for miscellaneous objects, like control ** blocks and query text. */ if (ret_val == E_DB_ERROR || ret_val == E_DB_FATAL || ret_val == E_DB_SEVERE) { /* ** In case of CREATE PROCEDURE statement we also need to ** destroy the QEP object in QSF if it was created. */ if (sess_cb->pss_ostream.psf_mstream.qso_handle != (PTR) NULL && psq_cb->psq_mode == PSQ_CREDBP ) { DB_STATUS stat; stat = psq_destr_dbp_qep(sess_cb, sess_cb->pss_ostream.psf_mstream.qso_handle, &psq_cb->psq_error); if (stat > ret_val) ret_val = stat; } if (sess_cb->pss_ostream.psf_mstream.qso_handle != (PTR) NULL) { (VOID) psf_mclose(sess_cb, &sess_cb->pss_ostream, &psq_cb->psq_error); sess_cb->pss_ostream.psf_mstream.qso_handle = (PTR) NULL; } if (sess_cb->pss_tstream.psf_mstream.qso_handle != (PTR) NULL) { (VOID) psf_mclose(sess_cb, &sess_cb->pss_tstream, &psq_cb->psq_error); sess_cb->pss_tstream.psf_mstream.qso_handle = (PTR) NULL; } if (sess_cb->pss_cbstream.psf_mstream.qso_handle != (PTR) NULL) { (VOID) psf_mclose(sess_cb, &sess_cb->pss_cbstream, &psq_cb->psq_error); sess_cb->pss_cbstream.psf_mstream.qso_handle = (PTR) NULL; } } /* ** If the statement was a "define cursor" or a "define repeat cursor", ** we have to deallocate the cursor control block, if it was allocated. */ if (sess_cb->pss_cstream != (PTR) NULL) { status = psq_delcursor(sess_cb->pss_crsr, &sess_cb->pss_curstab, &sess_cb->pss_memleft, &psq_cb->psq_error); if (status == E_DB_FATAL) ret_val = status; } return(ret_val); }
/* ** Name: psl_lm5_setlockmode_distr()- perform semantic actions for SETLOCKMODE ** production. ** ** Description: ** perform semantic action for SETLOCKMODE production in SQL ** grammar for distributed thread. SET LOCKMODE SESSION ... TIMEOUT ** is handled by QEF in the distributed server by timing out on ** queries to LDB; all other SET LOCKMODE ON TABLE options are sent ** to QEF to pass on to LDB as text. ** ** Inputs: ** sess_cb ptr to a PSF session CB ** pss_distrib DB_3_DDB_SESS if distributed thread ** pss_stmt_flags PSS_SET_LOCKMODE_SESS if SET LOCKMODE SESSION ** (distributed thread only) ** scanbuf_ptr ptr into scanner buffer containing text of ** SET LOCKMODE statement ** xlated_qry For query text buffering ** ** Outputs: ** err_blk will be filled in if an error occurs ** ** Returns: ** E_DB_{OK, ERROR} ** ** History: ** 5-mar-1991 (barbara) ** Extracted from 6.4 Star grammar for Sybil. ** 4-dec-92 (barbara) ** If call to QEF fails, error has already been reported. PSF must ** set psq_error (or SCF will complain); however, we want to avoid ** PSF retry so we also set PSQ_REDO to pretend we are already in ** server retry. ** 06-oct-93 (barbara) ** Fix for bug 53492. SET LOCKMODE SESSION ... is now supported for ** options other than TIMEOUT. */ DB_STATUS psl_lm5_setlockmode_distr( PSS_SESBLK *sess_cb, char *scanbuf_ptr, PSS_Q_XLATE *xlated_qry, PSQ_CB *psq_cb) { QEF_RCB *qef_rb; DB_STATUS status; DB_ERROR *err_blk = &psq_cb->psq_error; if (sess_cb->pss_distrib & DB_3_DDB_SESS) { qef_rb = (QEF_RCB *) sess_cb->pss_object; if ( sess_cb->pss_stmt_flags & PSS_SET_LOCKMODE_SESS && qef_rb->qef_r3_ddb_req.qer_d14_ses_timeout != DMC_C_UNKNOWN) { status = qef_call(QED_SES_TIMEOUT, ( PTR ) qef_rb); if (DB_FAILURE_MACRO(status)) { err_blk->err_code = E_PS0001_USER_ERROR; /* ** Make it appear as if query is already in retry so that ** psq_call won't retry this failed statement. */ psq_cb->psq_flag |= PSQ_REDO; return(status); } } else { status = psq_x_add(sess_cb, (char *)scanbuf_ptr, &sess_cb->pss_ostream, xlated_qry->pss_buf_size, &xlated_qry->pss_q_list, (i4) ((char *) sess_cb->pss_endbuf - scanbuf_ptr), " ", (char *) sess_cb->pss_endbuf, (char *) NULL, err_blk); if (DB_FAILURE_MACRO(status)) { return(status); } qef_rb->qef_r3_ddb_req.qer_d4_qry_info.qed_q4_pkt_p = xlated_qry->pss_q_list.pss_head; if (~sess_cb->pss_stmt_flags & PSS_SET_LOCKMODE_SESS) { status = qef_call(QED_QRY_FOR_LDB, ( PTR ) qef_rb); } else { status = qef_call(QED_SET_FOR_RQF, ( PTR ) qef_rb); } if (DB_FAILURE_MACRO(status)) { err_blk->err_code = E_PS0001_USER_ERROR; /* ** Make it appear as if query is already in retry so that ** psq_call won't retry this failed statement. */ psq_cb->psq_flag |= PSQ_REDO; return(status); } } /* ** we are done; deallocate the memory as it will not be used by ** anyone else */ status = psf_mclose(sess_cb, &sess_cb->pss_ostream, err_blk); if (DB_FAILURE_MACRO(status)) return (status); /* ** make sure psq_parseqry() realizes that the stream has been closed */ sess_cb->pss_ostream.psf_mstream.qso_handle = (PTR) NULL; } return (E_DB_OK); }