/*{ ** Name: ops_gqtree - get query tree from QSF ** ** Description: ** This procedure will get a query tree from QSF ** and initialize the global QSF control block ** ** Inputs: ** global ptr to global state variable ** ** Outputs: ** global->ops_qsfcb initialized ** Returns: ** QSF status ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 26-jan-88 (seputis) ** initial creation ** 7-jan-94 (swm) ** Bug #58635 ** Added PTR cast for qsf_owner which has changed type to PTR. ** 10-Jan-2001 (jenjo02) ** Initialize qsf_sid with session's SID. [@history_template@]... */ DB_STATUS ops_gqtree( OPS_STATE *global) { /* get the query tree from QSF */ DB_STATUS qsfstatus; /* QSF return status */ global->ops_qsfcb.qsf_length = sizeof(QSF_RCB); /* initialize header ** for control block */ global->ops_qsfcb.qsf_type = QSFRB_CB; global->ops_qsfcb.qsf_owner = (PTR)DB_OPF_ID; global->ops_qsfcb.qsf_ascii_id = QSFRB_ASCII_ID; global->ops_qsfcb.qsf_sid = global->ops_cb->ops_sid; STRUCT_ASSIGN_MACRO(global->ops_caller_cb->opf_query_tree, global->ops_qsfcb.qsf_obj_id); /* move the name to the QSF control ** block */ global->ops_qsfcb.qsf_lk_state = QSO_EXLOCK; /* lock exclusively so ** that this object can be destroyed ** later */ qsfstatus = qsf_call( QSO_LOCK, &global->ops_qsfcb); /* get exclusive ** access to object */ if (DB_SUCCESS_MACRO(qsfstatus)) { global->ops_lk_id = global->ops_qsfcb.qsf_lk_id; /* save the lock id ** so that the object can be destroyed ** later */ global->ops_procedure = (PST_PROCEDURE *)global->ops_qsfcb.qsf_root; /* save ** the ptr to procedure header which ** should be the root */ } return(qsfstatus); }
/*{ ** Name: psf_mclose - Close a memory stream. ** ** Description: ** This function closes a memory stream, which amounts to deallocating ** all of the memory held by it. ** ** Inputs: ** sess_cb Ptr to session's CB. ** stream Pointer to the stream to be closed. ** err_blk Place to put error information. ** ** Outputs: ** err_blk Filled in with error information. ** E_PS0006_CANTFREE Error when freeing memory. ** ** Returns: ** E_DB_OK Operation succeeded. ** E_DB_ERROR Error by caller (e.g. bad parameter). ** E_DB_FATAL Operation failed (e.g. out of memory) ** Exceptions: ** none ** ** Side Effects: ** Deallocates memory. ** ** History: ** 27-dec-85 (jeff) ** written ** 6-may-87 (daved) ** lock memory stream if not already locked. ** This condition can happen if, for example, a syntax error ** is discovered after psq_tout has been called and we now ** want to delete the memory stream. */ DB_STATUS psf_mclose( PSS_SESBLK *sess_cb, PSF_MSTREAM *stream, DB_ERROR *err_blk) { i4 err_code; DB_STATUS status; if (stream->psf_mlock == 0) { status = psf_mlock(sess_cb, stream, err_blk); if (status != E_DB_OK) return (status); } sess_cb->pss_qsf_rcb.qsf_obj_id.qso_handle = stream->psf_mstream.qso_handle; sess_cb->pss_qsf_rcb.qsf_lk_id = stream->psf_mlock; status = qsf_call(QSO_DESTROY, &sess_cb->pss_qsf_rcb); if (status != E_DB_OK) { (VOID) psf_error(E_PS0A06_CANTFREE, sess_cb->pss_qsf_rcb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return (status); } return (E_DB_OK); }
/*{ ** Name: psf_mopen - Open a memory stream. ** ** Description: ** All memory allocation within the parser is done by means of streams. ** A memory stream must be opened before it is used. To open it, one ** specifies the type of object to be allocated (query text, query tree, ** or query plan), and gives a place to put the stream id and the lock ** id. The stream id and lock id are used for all future references to ** the memory stream. ** ** Inputs: ** sess_cb Ptr to session's CB. ** objtype The type of memory to be allocated. ** mstream Pointer to structure to contain stream ** id and lock id, which will uniquely ** identify object in future. ** err_blk Place to put the error information. ** E_PS0A05_BADMEMREQ Bad memory request ** ** Outputs: ** mstream Filled in with stream id and lock id ** err_blk Filled in with error number and text. ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s); ** error status in psq_cb.psq_error chain ** of error blocks. ** E_DB_ERROR Function failed due to error by caller; ** error status in psq_cb.psq_error chain ** of error blocks. ** E_DB_FATAL Function failed due to some internal ** problem; error status in ** psq_cb.psq_error chain of error blocks. ** ** Exceptions: ** none ** ** Side Effects: ** Allocates memory. ** ** History: ** 27-dec-85 (jeff) ** written */ DB_STATUS psf_mopen( PSS_SESBLK *sess_cb, i4 objtype, PSF_MSTREAM *mstream, DB_ERROR *err_blk) { i4 err_code; DB_STATUS status; sess_cb->pss_qsf_rcb.qsf_obj_id.qso_type = objtype; sess_cb->pss_qsf_rcb.qsf_obj_id.qso_lname = 0; status = qsf_call(QSO_CREATE, &sess_cb->pss_qsf_rcb); if (status != E_DB_OK) { i4 qerr; qerr = sess_cb->pss_qsf_rcb.qsf_error.err_code; if (qerr == E_QS0001_NOMEM) (VOID) psf_error(qerr, qerr, PSF_CALLERR, &err_code, err_blk, 0); else (VOID) psf_error(E_PS0A05_BADMEMREQ, qerr, PSF_INTERR, &err_code, err_blk, 0); mstream->psf_mstream.qso_handle = (PTR) NULL; mstream->psf_mlock = 0; return (status); } mstream->psf_mstream.qso_handle = sess_cb->pss_qsf_rcb.qsf_obj_id.qso_handle; mstream->psf_mlock = sess_cb->pss_qsf_rcb.qsf_lk_id; return (E_DB_OK); }
/*{ ** Name: ops_qsfdestroy - destroy a query plan ** ** Description: ** Since the QP can be in several states, in order to destroy it ** several error recovery paths may be needed. ** ** Inputs: ** global ptr to global state variable ** ** Outputs: ** Returns: ** VOID ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 13-apr-89 (seputis) ** initial creation [@history_template@]... */ static DB_STATUS ops_qsfdestroy( OPS_STATE *global) { DB_STATUS qsfqpstatus; qsfqpstatus = qsf_call( QSO_DESTROY, &global->ops_qsfcb); if (DB_FAILURE_MACRO(qsfqpstatus)) { /* attempt to get a lock on the object, since and error ** may have occurred between the time the OPC released ** the object and prior to returning to SCF */ global->ops_qsfcb.qsf_lk_state = QSO_SHLOCK; qsfqpstatus = qsf_call( QSO_LOCK, &global->ops_qsfcb ); /* ignore the error from ** this routine since we ** will attempt to delete the ** object again anyway */ qsfqpstatus = qsf_call( QSO_DESTROY, &global->ops_qsfcb); } return(qsfqpstatus); }
/*{ ** Name: psq_tout - Copy a text chain to QSF memory ** ** Description: ** This function copies a text chain to QSF memory, as a text object. ** It allocates it as a contiguous piece. ** ** Inputs: ** rngtab if non-NULL, range statements will be ** generated for all entries of the range table ** that are active (pss_used && pss_rgno >= 0); ** should be non-NULL only for QUEL queries ** header Pointer to chain header ** mstream Pointer to unopened memory stream ** err_blk Filled in if an error happens ** ** Outputs: ** mstream Filled with object id for new text ** object ** err_blk Filled in if an error happened ** Returns: ** E_DB_OK Success ** E_DB_ERROR Non-catastrophic failure ** E_DB_FATAL Catastrophic failure ** Exceptions: ** none ** ** Side Effects: ** Allocates memory ** ** History: ** 18-jul-86 (jeff) ** written ** 2-sep-86 (seputis) ** changed MEcopy routine parameter to be &hp->psq_tsize ** 6-may-87 (daved) ** clear mstream lock id after unlocking memory stream ** 29-jun-87 (daved) ** emit the range table entries if a range table is provided. ** 10-aug-93 (andre) ** removed declaration of qsf_call() */ DB_STATUS psq_tout( PSS_SESBLK *sess_cb, PSS_USRRANGE *rngtab, PTR header, PSF_MSTREAM *mstream, DB_ERROR *err_blk) { DB_STATUS status; i4 err_code; u_char *buf; QSF_RCB qsf_rb; /* Open the QSF memory stream for the text object */ status = psf_mopen(sess_cb, QSO_QTEXT_OBJ, mstream, err_blk); if (status != E_DB_OK) return (status); status = psq_store_text(sess_cb, rngtab, header, mstream, (PTR *) &buf, (bool) FALSE, err_blk); if (DB_FAILURE_MACRO(status)) return(status); /* Set the root of the object */ status = psf_mroot(sess_cb, mstream, (PTR) buf, err_blk); if (status != E_DB_OK) return (status); /* Unlock the 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(mstream->psf_mstream, qsf_rb.qsf_obj_id); qsf_rb.qsf_lk_id = mstream->psf_mlock; status = qsf_call(QSO_UNLOCK, &qsf_rb); if (status != E_DB_OK) { (VOID) psf_error(E_PS0375_UNLOCK_QSF_TEXT, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return (status); } mstream->psf_mlock = 0; return (E_DB_OK); }
/*{ ** Name: psf_malloc - Allocate memory from a stream. ** ** Description: ** This function allocates memory from a memory stream. If there is room ** in the current block, it will use it. If not, it will allocate another ** block and use that. ** ** Inputs: ** sess_cb Ptr to session's CB. ** stream Pointer to the stream to allocate from. ** size Number of bytes to allocate ** result Place to put pointer to allocated memory ** err_blk Place to put error information. ** ** Outputs: ** result Filled in with pointer to alloc. memory ** err_blk Filled in with error information. ** E_PS0A05_BADMEMREQ Bad memory request ** ** Returns: ** E_DB_OK Operation succeeded. ** E_DB_ERROR Error by caller (e.g. bad parameter). ** E_DB_FATAL Operation failed (e.g. out of memory) ** Exceptions: ** none ** ** Side Effects: ** Can allocate memory. ** ** History: ** 27-dec-85 (jeff) ** written */ DB_STATUS psf_malloc( PSS_SESBLK *sess_cb, PSF_MSTREAM *stream, i4 size, void *result, DB_ERROR *err_blk) { i4 err_code; DB_STATUS status; /* ** Caller error if non-positive request. */ if (size <= 0) { psf_error(E_PS0A05_BADMEMREQ, 0L, PSF_INTERR, &err_code, err_blk, 0); *(void **) result = NULL; return (E_DB_SEVERE); } /* Allocate the object from QSF */ sess_cb->pss_qsf_rcb.qsf_obj_id.qso_handle = stream->psf_mstream.qso_handle; sess_cb->pss_qsf_rcb.qsf_lk_id = stream->psf_mlock; sess_cb->pss_qsf_rcb.qsf_sz_piece = size; status = qsf_call(QSO_PALLOC, &sess_cb->pss_qsf_rcb); if (status != E_DB_OK) { i4 qerr = sess_cb->pss_qsf_rcb.qsf_error.err_code; if (qerr == E_QS0001_NOMEM) (VOID) psf_error(qerr, qerr, PSF_CALLERR, &err_code, err_blk, 0); else (VOID) psf_error(E_PS0A05_BADMEMREQ, qerr, PSF_INTERR, &err_code, err_blk, 0); *(void **) result = NULL; return (E_DB_ERROR); } *(void **) result = sess_cb->pss_qsf_rcb.qsf_piece; return (E_DB_OK); }
/*{ ** Name: psf_mroot - Set the root for a memory stream ** ** Description: ** This function sets the root for a memory stream. When the next ** facility looks at the object allocated by the stream, it can ask ** for the root. ** ** Inputs: ** sess_cb Ptr to session's CB. ** mstream Pointer to the memory stream ** root Pointer to the root of the object ** ** Outputs: ** None ** Returns: ** E_DB_OK Success ** E_DB_ERROR Non-catastrophic failure ** E_DB_FATAL Catastrophic failure ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 30-may-86 (jeff) ** written */ DB_STATUS psf_mroot( PSS_SESBLK *sess_cb, PSF_MSTREAM *mstream, PTR root, DB_ERROR *err_blk) { DB_STATUS status; i4 err_code; sess_cb->pss_qsf_rcb.qsf_obj_id.qso_handle = mstream->psf_mstream.qso_handle; sess_cb->pss_qsf_rcb.qsf_root = root; sess_cb->pss_qsf_rcb.qsf_lk_id = mstream->psf_mlock; status = qsf_call(QSO_SETROOT, &sess_cb->pss_qsf_rcb); if (status != E_DB_OK) { (VOID) psf_error(E_PS0A05_BADMEMREQ, sess_cb->pss_qsf_rcb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return (status); } return (E_DB_OK); }
/*{ ** Name: psf_mlock - Lock an QSO object stream ** ** Description: ** This function locks the specified QSO object. ** ** Inputs: ** sess_cb Ptr to session's CB. ** mstream Pointer to the memory stream ** .psf_mstream.qso_handle Object handle ** err_block Pointer to error control block ** ** Outputs: ** mstream Pointer to the memory stream ** .psf_mlock Lock id returned by QSF ** err_blk Filled in with error information. ** E_PS0A08_CANTLOCK Error when locking object type. ** ** Returns: ** E_DB_OK Success ** E_DB_ERROR Non-catastrophic failure ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 03-apr-87 (puree) ** Written. */ DB_STATUS psf_mlock( PSS_SESBLK *sess_cb, PSF_MSTREAM *mstream, DB_ERROR *err_blk) { DB_STATUS status; i4 err_code; sess_cb->pss_qsf_rcb.qsf_obj_id.qso_handle = mstream->psf_mstream.qso_handle; sess_cb->pss_qsf_rcb.qsf_lk_state = QSO_EXLOCK; sess_cb->pss_qsf_rcb.qsf_obj_id.qso_lname = 0; status = qsf_call(QSO_LOCK, &sess_cb->pss_qsf_rcb); if (status != E_DB_OK) { (VOID) psf_error(E_PS0A08_CANTLOCK, sess_cb->pss_qsf_rcb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return (status); } mstream->psf_mlock = sess_cb->pss_qsf_rcb.qsf_lk_id; return (E_DB_OK); } /* end psf_mlock */
/*{ ** Name: psf_munlock - Unlock a QSO object stream ** ** Description: ** This function unlocks the specified QSO object. ** ** Inputs: ** sess_cb Ptr to session's CB. ** mstream Pointer to the memory stream ** .psf_mstream.qso_handle Object handle ** err_block Pointer to error control block ** ** Outputs: ** mstream Pointer to the memory stream ** .psf_mlock Lock id returned by QSF ** err_blk Filled in with error information. ** E_PS0B05_CANT_UNLOCK Error when unlocking object type. ** ** Returns: ** E_DB_OK Success ** E_DB_ERROR Non-catastrophic failure ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 29-nov-93 (rblumer) ** Written. */ DB_STATUS psf_munlock( PSS_SESBLK *sess_cb, PSF_MSTREAM *mstream, DB_ERROR *err_blk) { DB_STATUS status; i4 err_code; sess_cb->pss_qsf_rcb.qsf_lk_id = mstream->psf_mlock; STRUCT_ASSIGN_MACRO(mstream->psf_mstream, sess_cb->pss_qsf_rcb.qsf_obj_id); status = qsf_call(QSO_UNLOCK, &sess_cb->pss_qsf_rcb); if (status != E_DB_OK) { (VOID) psf_error(E_PS0B05_CANT_UNLOCK, sess_cb->pss_qsf_rcb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return (status); } mstream->psf_mlock = 0; return (E_DB_OK); } /* end psf_munlock */
/*{ ** Name: psf_mchtyp - Change object type for a memory stream. ** ** Description: ** This function changes the object type for a memory stream. ** ** Inputs: ** sess_cb Ptr to session's CB. ** mstream Pointer to the memory stream ** newtype New type for the object ** err_block Pointer to error control block ** ** Outputs: ** err_blk Filled in with error information. ** E_PS0A07_CANTCHANGE Error when changing object type. ** ** Returns: ** E_DB_OK Success ** E_DB_ERROR Non-catastrophic failure ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 18-mar-87 (stec) ** Written. */ DB_STATUS psf_mchtyp( PSS_SESBLK *sess_cb, PSF_MSTREAM *mstream, i4 objtype, DB_ERROR *err_blk) { DB_STATUS status; i4 err_code; sess_cb->pss_qsf_rcb.qsf_obj_id.qso_handle = mstream->psf_mstream.qso_handle; sess_cb->pss_qsf_rcb.qsf_obj_id.qso_type = objtype; sess_cb->pss_qsf_rcb.qsf_obj_id.qso_lname = 0; sess_cb->pss_qsf_rcb.qsf_lk_id = mstream->psf_mlock; status = qsf_call(QSO_CHTYPE, &sess_cb->pss_qsf_rcb); if (status != E_DB_OK) { (VOID) psf_error(E_PS0A07_CANTCHANGE, sess_cb->pss_qsf_rcb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return (status); } return (E_DB_OK); }
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 */ }
i4 scs_msequencer(i4 op_code, SCD_SCB *scb, i4 *next_op ) { DB_STATUS status; DB_STATUS error; SCC_GCMSG *message; QSF_RCB *qs_ccb; GCA_TD_DATA *tdescr; PTR block; scb->scb_cscb.cscb_gci.gca_status = E_SC1000_PROCESSED; scb->cs_scb.cs_mask &= ~(CS_NOXACT_MASK); for (;;) { status = sc0m_allocate(0, (i4)(sizeof(SCC_GCMSG) + sizeof(GCA_TD_DATA) - sizeof(tdescr->gca_col_desc[0].gca_attname)), DB_SCF_ID, (PTR)SCS_MEM, CV_C_CONST_MACRO('m','n','t','r'), &block); message = (SCC_GCMSG *)block; if (status) { sc0e_0_put(status, 0); sc0e_0_uput(status, 0); scb->scb_sscb.sscb_state = SCS_TERMINATE; *next_op = CS_TERMINATE; status = E_DB_SEVERE; break; } message->scg_mask = 0; message->scg_mtype = GCA_TDESCR; message->scg_marea = ((char *) message + sizeof(SCC_GCMSG)); message->scg_msize = sizeof(GCA_TD_DATA) - sizeof(tdescr->gca_col_desc[0].gca_attname); tdescr = (GCA_TD_DATA *)message->scg_marea; tdescr->gca_result_modifier = 0; tdescr->gca_l_col_desc = 1; tdescr->gca_col_desc[0].gca_l_attname = 0; tdescr->gca_col_desc[0].gca_attdbv.db_prec = 0; tdescr->gca_col_desc[0].gca_attdbv.db_data = 0; tdescr->gca_col_desc[0].gca_attdbv.db_datatype = DB_VCH_TYPE; message->scg_next = (SCC_GCMSG *) &scb->scb_cscb.cscb_mnext; message->scg_prev = scb->scb_cscb.cscb_mnext.scg_prev; scb->scb_cscb.cscb_mnext.scg_prev->scg_next = message; scb->scb_cscb.cscb_mnext.scg_prev = message; /* status = sc0m_allocate(0, (i4)(sizeof(SCC_GCMSG) + scb->scb_cscb.cscb_comm_size), SCS_MEM, DB_SCF_ID, CV_C_CONST_MACRO('m','n','t','r'), &message); if (status) { sc0e_put(status, 0); sc0e_uput(status, 0); scb->scb_sscb.sscb_state = SCS_TERMINATE; *next_op = CS_TERMINATE; status = E_DB_SEVERE; break; } message->scg_mask = 0; message->scg_mtype = GCA_TUPLES; message->scg_marea = ((char *) message + sizeof(SCC_GCMSG)); message->scg_msize = scb->scb_cscb.cscb_comm_size; text_string = (DB_TEXT_STRING *)message->scg_marea; MEcopy(((PSQ_QDESC *) scb->scb_sscb.sscb_troot)->psq_qrytext, ((PSQ_QDESC *) scb->scb_sscb.sscb_troot)->psq_qrysize, text_string->db_t_text); text_string->db_t_text[ ((PSQ_QDESC *) scb->scb_sscb.sscb_troot)->psq_qrysize] = '\0'; */ qs_ccb = scb->scb_sscb.sscb_qsccb; /* ** execute monitor. user is "powerful" if has either ** SECURITY or OPERATOR privileges */ if(scb->scb_sscb.sscb_troot) { status = scs_monitor(op_code, (CS_SCB *)scb, next_op, ((PSQ_QDESC *) scb->scb_sscb.sscb_troot)->psq_qrytext, scb->scb_sscb.sscb_ics.ics_rustat & (DU_USECURITY|DU_UOPERATOR)?1:0, sc0e_tput); } /* message->scg_mask = 0; message->scg_mtype = GCA_TUPLES; text_string->db_t_count = STlength(text_string->db_t_text); message->scg_msize = text_string->db_t_count + 2; tdescr->gca_col_desc[0].gca_attdbv.db_length = message->scg_msize; tdescr->gca_tsize = message->scg_msize; message->scg_next = (SCC_GCMSG *) &scb->scb_cscb.cscb_mnext; message->scg_prev = scb->scb_cscb.cscb_mnext.scg_prev; scb->scb_cscb.cscb_mnext.scg_prev->scg_next = message; scb->scb_cscb.cscb_mnext.scg_prev = message; */ status = sc0m_allocate(0, (i4)(sizeof(SCC_GCMSG) + sizeof(GCA_RE_DATA)), DB_SCF_ID, (PTR)SCS_MEM, CV_C_CONST_MACRO('m','n','t','r'), &block); message = (SCC_GCMSG *)block; if (status) { sc0e_0_put(status, 0); sc0e_0_uput(status, 0); scb->scb_sscb.sscb_state = SCS_TERMINATE; *next_op = CS_TERMINATE; status = E_DB_SEVERE; break; } message->scg_mask = 0; message->scg_mtype = GCA_RESPONSE; message->scg_marea = ((char *) message + sizeof(SCC_GCMSG)); message->scg_msize = sizeof(GCA_RE_DATA); message->scg_next = (SCC_GCMSG *) &scb->scb_cscb.cscb_mnext; message->scg_prev = scb->scb_cscb.cscb_mnext.scg_prev; scb->scb_cscb.cscb_mnext.scg_prev->scg_next = message; scb->scb_cscb.cscb_mnext.scg_prev = message; break; } if (scb->scb_sscb.sscb_thandle) { qs_ccb = scb->scb_sscb.sscb_qsccb; qs_ccb->qsf_lk_id = scb->scb_sscb.sscb_tlk_id; qs_ccb->qsf_obj_id.qso_handle = scb->scb_sscb.sscb_thandle; status = qsf_call(QSO_DESTROY, qs_ccb); if (DB_FAILURE_MACRO(status)) { scs_qsf_error(status, qs_ccb->qsf_error.err_code, E_SC0210_SCS_SQNCR_ERROR); } scb->scb_sscb.sscb_thandle = 0; } scb->scb_sscb.sscb_state = SCS_INPUT; return(status); }
/*{ ** 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: 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: psq_parseqry - Parse a query and return a data structure ** ** INTERNAL PSF call format: status = psq_parseqry(&psq_cb, &sess_cb); ** ** EXTERNAL call format: status = psq_call(PSQ_PARSEQRY, &psq_cb, &sess_cb); ** ** Description: ** This function will parse a query in QSF memory. It will return a ** data structure (such as a query tree), and a code telling what kind of ** query was just parsed (e.g. a copy statement). This code will be ** called the "query mode". For qrymod definitions, it will store a ** modified version of the query text in QSF, for later insertion in the ** iiqrytext system relation. ** ** This function will check the syntax of each statement, and will perform ** some semantic validations. The syntax checking will be rather simple: ** each statement will either be right or wrong, and a syntax error will ** cause the whole go block to be aborted. Semantic checks will be more ** complicated; some of them will cause warnings (which will allow the ** statement to continue), and some will cause errors (causing the ** statement to be aborted). It should be noted that the semantic checks ** will not be the same in the Jupiter version as in previous versions; ** in the Jupiter version, for instance, the parser won't check for whether ** the statement is valid inside a multi-query transaction. ** ** Sometimes it will be found that the definition of a view, permit, or ** integrity is out of date. When this happens, this function will return ** an error status saying so, and an id for finding the query text in the ** iiqrytext relation, so that the definition can be re-parsed and ** re-stored. Accordingly, this function has an option by which one can ** tell it to get the query text out of the iiqrytext relation instead of ** QSF. ** ** When a statement is parsed that creates a new cursor, the parser will ** assign a cursor id to the cursor, create a cursor control block ** containing information about the cursor, and return the cursor id inside ** with the query tree representing the cursor. This cursor id will be ** used throughout the session to uniquely identify the cursor. When a ** "close cursor" statement is parsed, the parser will deallocate the ** control block associated with the cursor. ** ** The parser will automatically apply view, permit, and integrity ** processing to any data manipulation query it parses. This will not ** require a separate call to the parser. ** ** Multi-statement go blocks are no longer allowed, as they used to be in ** previous versions. This parser can handle only one statement at a time. ** ** Inputs: ** psq_cb ** .psq_qid A unique identifier for getting the ** query text from QSF. ** .psq_iiqrytext TRUE means to get the query text from ** the iiqrytext relation, not QSF. ** .psq_txtid Query text id key into iiqrytext ** relation; used only if above is true. ** sess_cb Pointer to the session control block ** ** Outputs: ** psq_cb ** .psq_qlang The language of the query text. ** .psq_mode The query mode (a code telling what ** kind of query was just parsed). ** .psq_result QSF id for the data structure produced ** (query tree, or control block stored as ** QEP). ** .psq_txtid Query text id key into iiqrytext ** relation; filled in if some qrymod ** object needs redefining. ** .psq_mnyfmt Set on a "set money_format" or ** "set money_prec" statement ** .psq_dtefmt Set on a "set date_format" statement ** .psq_decimal Set on a "set decimal" statement ** .psq_error Standard error block ** E_PS0000_OK Success ** E_PS0001_USER_ERROR Mistake by user ** E_PS0002_INTERNAL_ERROR Internal inconsistency inside PSF ** E_PS0B01_OUTDATED_VIEW View out of date; must re-define ** E_PS0B02_OUTDATED_PERMIT Permit out of date; must re-define ** E_PS0B03_OUTDATED_INTEG Integrity out of date; must re-def. ** E_PS0B04_CANT_GET_TEXT Can't get query text ** .psq_txtout QSF id for the create procedure stmt to ** be stored in the system catalog. ** ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s) ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Stores query tree or control block in QSF. ** Can open a cursor. ** ** History: ** 01-oct-85 (jeff) ** written ** 19-sep-86 (daved) ** end of qry should point to last char. This char should be a space. ** this makes the scanner's job easier ** 27-jan-87 (daved) ** add the printqry set command. ** 02-oct-87 (stec) ** Removed pss_journaling flag initialization; ** must be initialized in psqbgnses.c ** 19-jan-88 (stec) ** Changed initialization od pst_resloc. ** 25-may-88 (stec) ** Made changes in connection with DB procedures. ** QSF object of QP type has to be destroyed if ** translate_or_define worked for CREATE PROCEDURE. ** 23-aug-88 (stec) ** Initialize qso_handle in QSO_OBIDs in psq_cb. ** 21-apr-89 (neil) ** Extracted some initialization (psq_cbinit) from psq_parseqry to ** allow it to be called from other routines as well. ** 11-dec-89 (ralph) ** Change interface to QSO for dbprocs ** 12-sep-90 (teresa) ** fix faulty pss_retry logic. ** 15-jun-92 (barbara) ** Sybil merge. Pass in sess control block to pst_clrrng. ** 23-nov-92 (barbara) ** For Star, accept range statement as the one and only allowable ** QUEL statement. This is to support old FE's which use the range ** statement as a quick way to ascertain table existence. FEs of ** >= 6.5 vintage use a table_resolve() function, so at some point ** we can remove the QUEL range table statement support for Star. ** 24-nov-92 (ralph) ** CREATE SCHEMA: ** Initialize pss_prvgoval ** 22-dec-92 (rblumer) ** clean up after pss_tchain2 just like pss_tchain. ** 25-may-93 (rog) ** Move clean-up/exit code into psq_cbreturn() and then call it. ** 11-oct-93 (swm) ** Bug #56448 ** Declared trbuf for psf_display() to pass to TRformat. ** TRformat removes `\n' chars, so to ensure that psf_scctrace() ** outputs a logical line (which it is supposed to do), we allocate ** a buffer with one extra char for NL and will hide it from TRformat ** by specifying length of 1 byte less. The NL char will be inserted ** at the end of the message by psf_scctrace(). ** 16-mar-94 (andre) ** if performing an internal PSF retry and trace point ps129 (same as *8 SET PRINTQRY) is set, instead of redisplaying the query we will *8 tell the user that we are retrying the last query. ** 28-feb-2005 (wanfr01) ** Bug 64899, INGSRV87 ** Add stack overflow handler for TRU64. ** 17-mar-06 (dougi) ** Init pss_hintcount to 0 for optimizer hints project. ** 23-june-06 (dougi) ** Init pss_stmtno to 1 for procedure debugging. ** 05-sep-06 (toumi01) ** Init pss_stmtno to 0 (to match new "help procedure" numbering) ** lest we point, PC register like, to the _following_ statement. ** 15-Sep-2008 (kibro01) b120571 ** Use same session ID as available in iimonitor ** 16-Sep-2008 (kibro01) b120571 ** Remove compilation error from cast of sessid ** 16-Feb-2009 (kibro01) b121674 ** Add version to SESSION BEGINS message in sc930 and give out ** data type of parameters. ** 10-Jul-2009 (kibro01) b122299 ** Increase the version number due to dates being printed out now. ** 15-Jul-2009 (kibro01) b122172 ** Change QUERY or QUEL to REQUERY or REQUEL when a DB procedure is ** reparsed due to being invalidated. ** 23-Jul-2009 (kibro01) b122172 ** Separate the print_qry_buffer logic to avoid stack size problems. ** 3-Aug-2009 (kibro01) b122393 ** Use print_qry_buffer_ptr to avoid inlining. ** 4-Aug-2009 (kibro01) b122172 ** Allow REQUERY/REQUEL through even if the RECREATE flag is set so ** we get the useful debug output. ** 28-Oct-2009 (maspa05) b122725 ** ult_print_tracefile now uses integer constants instead of string ** for type parameter - SC930_LTYPE_PARM instead of "PARM" and so on ** Also moved function definitions for SC930 tracing to ulf.h ** The functions involved were - ult_always_trace, ult_open_tracefile ** ult_print_tracefile and ult_close_tracefile */ DB_STATUS psq_parseqry( register PSQ_CB *psq_cb, register PSS_SESBLK *sess_cb) { DB_STATUS status; DB_STATUS ret_val; QSF_RCB qsf_rb; i4 err_code; PSQ_QDESC *qdesc; i4 val1 = 0; i4 val2 = 0; i4 i; char trbuf[PSF_MAX_TEXT + 1]; /* last char for `\n' */ if ((status = psq_cbinit(psq_cb, sess_cb)) != E_DB_OK) return (status); /* ** The following is particular to queries that must be parsed. ** Get query text from QSF and put it in session control block ** Initialize the qbuf, nextchar, prevtok, and bgnstmt pointers */ 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; qsf_rb.qsf_obj_id.qso_handle = psq_cb->psq_qid; status = qsf_call(QSO_INFO, &qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0B04_CANT_GET_TEXT, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } qdesc = (PSQ_QDESC*) qsf_rb.qsf_root; /* print the qry buffer as long as this isn't a retry ** - although allow through the RECREATE case since it's useful ** for debugging to log reparsing an object */ if ((ult_always_trace() & SC930_TRACE) && ( ((sess_cb->pss_retry & PSS_REFRESH_CACHE)==0) || (sess_cb->pss_dbp_flags & PSS_RECREATE) != 0 ) ) { (*print_qry_buffer_ptr)(psq_cb, qdesc, sess_cb); } if (ult_check_macro(&sess_cb->pss_trace, PSS_PRINT_QRY_TRACE, &val1, &val2)) { if (psf_in_retry(sess_cb, psq_cb)) { psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "\n...retrying last query...\n"); } else { psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "\nQUERY BUFFER:\n"); psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "%.#s\n", qdesc->psq_qrysize, qdesc->psq_qrytext); psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "\nQUERY PARAMETERS:\n"); for (i = 0; i < qdesc->psq_dnum; i++) { psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "Parameter : %d\n", i); adu_2prvalue(psf_relay, qdesc->psq_qrydata[i]); psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "\n"); } } } sess_cb->pss_bgnstmt = (u_char*) qdesc->psq_qrytext; sess_cb->pss_prvgoval = (u_char*) NULL; sess_cb->pss_prvtok = (u_char*) qdesc->psq_qrytext; sess_cb->pss_qbuf = (u_char*) qdesc->psq_qrytext; sess_cb->pss_nxtchar = (u_char*) qdesc->psq_qrytext; sess_cb->pss_endbuf = sess_cb->pss_qbuf + qdesc->psq_qrysize - 1; sess_cb->pss_dmax = qdesc->psq_dnum; sess_cb->pss_qrydata = qdesc->psq_qrydata; *sess_cb->pss_endbuf = ' '; sess_cb->pss_lineno = 1; /* Start out at line one */ sess_cb->pss_stmtno = 0; /* and statement at zero */ sess_cb->pss_dval = 0; sess_cb->pss_hintcount = 0; psl_yinit(sess_cb); if (psq_cb->psq_qlang == DB_QUEL) { if (sess_cb->pss_distrib & DB_3_DDB_SESS) { char *c; char *r = "range"; /* skip leading white space chars, if any */ for (c = qdesc->psq_qrytext; c <= (char *) sess_cb->pss_endbuf && CMwhite(c); CMnext(c) ) ; /* compare the first word with "range" */ for (; *r != EOS && c <= (char *) sess_cb->pss_endbuf && !CMcmpnocase(c,r); CMnext(c), CMnext(r) ) ; /* ** we will go on to parse this statement iff ** 1) first non-white chars are "range" AND ** 2) 'e' is followed by a white space */ if (*r != EOS || c >= (char *) sess_cb->pss_endbuf || !CMwhite(c)) { (VOID) psf_error(5212L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error,0); return(E_DB_ERROR); } } sess_cb->pss_parser = pslparse; } else { sess_cb->pss_parser = pslsparse; } IIEXtry { status = (*sess_cb->pss_parser)(sess_cb, psq_cb); } IIEXcatch(pthread_stackovf_e) { (VOID) psf_error(5212L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error,0); } IIEXendtry ret_val = psq_cbreturn(psq_cb, sess_cb, status); return (ret_val); }
/* ** Name: psq_destr_dbp_qep - destroy QSF object created for a dbproc ** ** Description: ** If an error occurs in PSF in the course of parsing a dbproc definition ** or recreating a dbproc QEP, we need to destroy the QEP object created ** in PSF before exiting. Otherwise, subsequent attempt to parse or ** recreate the dbproc will result in SC0206 because the QP object created ** during the first (aborted) attempt will still be locked in QSF ** ** Input: ** handle QP object handle ** ** Output: ** err_blk filled in if an error occurs ** ** Side effects: ** ** History: ** 27-aug-93 (andre) ** extracted from psq_cbreturn() to enable psq_recreate() call it as ** well */ DB_STATUS psq_destr_dbp_qep( PSS_SESBLK *sess_cb, PTR handle, DB_ERROR *err_blk) { DB_STATUS status; PST_PROCEDURE *pnode; QSF_RCB qsf_rb; i4 err_code; /* ** first get the root of the query tree object - using it, we will ** derive dbp QP object alias */ 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; qsf_rb.qsf_obj_id.qso_handle = handle; status = qsf_call(QSO_INFO, &qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0A0A_CANTGETINFO, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return(status); } /* ** We are interested in the proc node, because it holds the identifier for ** the QP object we want to destroy. */ pnode = (PST_PROCEDURE *) qsf_rb.qsf_root; /* ** We can only proceed if root has been set - otherwise it is safe to ** assume that the QP object has not been created - so we are done */ if (pnode == (PST_PROCEDURE *) NULL) return(E_DB_OK); qsf_rb.qsf_obj_id.qso_type = QSO_QP_OBJ; qsf_rb.qsf_obj_id.qso_lname = sizeof(DB_CURSOR_ID); (VOID) MEcopy((PTR) &pnode->pst_dbpid, sizeof(DB_CURSOR_ID), (PTR) qsf_rb.qsf_obj_id.qso_name); /* Lock it in shared mode before destroying. */ qsf_rb.qsf_lk_state = QSO_SHLOCK; /* Get handle for the QP object to be destroyed */ status = qsf_call(QSO_GETHANDLE, &qsf_rb); if (DB_FAILURE_MACRO(status)) { /* ** looks like the error occurred before the dbproc QP object was ** created - we are done */ if (qsf_rb.qsf_error.err_code == E_QS0019_UNKNOWN_OBJ) return(E_DB_OK); (VOID) psf_error(E_PS0A0B_CANTGETHNDLE, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return(status); } /* Now it is ready to be destroyed */ status = qsf_call(QSO_DESTROY, &qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0A09_CANTDESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return(status); } return(E_DB_OK); }
DB_STATUS qee_d8_undefrpt( QEF_RCB *qef_rcb, PTR i_qso_handle) { DB_STATUS status = E_DB_OK, sav_status = E_DB_OK; DB_ERROR sav_err; i4 err; GLOBALREF QEF_S_CB *Qef_s_cb; QEE_DSH *dsh_p = (QEE_DSH *)NULL; QEF_QP_CB *qp; bool have_qp = FALSE; QSF_RCB qsf_rcb; ULM_RCB ulm; ULH_RCB ulh_rcb; struct { PTR qso_handle; CS_SID session_id; } ulh_name; /* 1. acquire the QP using the handle */ qsf_rcb.qsf_next = (QSF_RCB *)NULL; qsf_rcb.qsf_prev = (QSF_RCB *)NULL; qsf_rcb.qsf_length = sizeof(QSF_RCB); qsf_rcb.qsf_type = QSFRB_CB; qsf_rcb.qsf_owner = (PTR)DB_QEF_ID; qsf_rcb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rcb.qsf_sid = qef_rcb->qef_cb->qef_ses_id; ulh_rcb.ulh_hashid = Qef_s_cb->qef_ulhid; qsf_rcb.qsf_obj_id.qso_handle = i_qso_handle; qsf_rcb.qsf_lk_state = QSO_SHLOCK; status = qsf_call(QSO_LOCK, &qsf_rcb); if (status) { qef_rcb->error.err_code = E_QE0019_NON_INTERNAL_FAILURE; return(status); } have_qp = TRUE; qp = (QEF_QP_CB *) qsf_rcb.qsf_root; /* For sharable QP, sometimes the QP may have been destroyed by ** another session. So check for a NULL root. If so, release the ** lock and return. */ if (qp == (QEF_QP_CB *) NULL) { qsf_call(QSO_UNLOCK, &qsf_rcb); return(E_DB_OK); } /* 2. gotten the QP, acquire the DSH in ULH's cache */ STRUCT_ASSIGN_MACRO(Qef_s_cb->qef_d_ulmcb, ulm); ulh_name.qso_handle = qsf_rcb.qsf_obj_id.qso_handle; ulh_name.session_id = qef_rcb->qef_cb->qef_ses_id; status = ulh_getmember(&ulh_rcb, (unsigned char *) &qp->qp_id, (i4)sizeof(DB_CURSOR_ID), (unsigned char *) & ulh_name, (i4)sizeof(ulh_name), ULH_DESTROYABLE, 0); if (DB_FAILURE_MACRO(status)) { qef_error(ulh_rcb.ulh_error.err_code, 0L, status, & err, &qef_rcb->error, 0); qef_rcb->error.err_code = E_QE0102_CATALOG_DSH_OBJECT; } else { dsh_p = (QEE_DSH *)(ulh_rcb.ulh_object->ulh_uptr); ulm.ulm_streamid_p = &ulh_rcb.ulh_object->ulh_streamid; if (dsh_p != (QEE_DSH *)NULL) { /* 3. reset the defined state of the REPEAT QUERY in the DSH */ dsh_p->dsh_ddb_cb->qee_d3_status &= ~QEE_03Q_DEF; /* 4. must release the acquired DSH */ ulh_rcb.ulh_object = (ULH_OBJECT *)dsh_p->dsh_handle; } status = ulh_release(& ulh_rcb); if (status != E_DB_OK) { qef_error(ulh_rcb.ulh_error.err_code, 0L, status, & err, &qef_rcb->error, 0); qef_rcb->error.err_code = E_QE0104_RELEASE_DSH_OBJECT; } /* must fall thru to release the QP */ } /* 5. release the QP */ if (have_qp) { qsf_call(QSO_UNLOCK, & qsf_rcb); } if (status == E_DB_OK && sav_status) { status = sav_status; STRUCT_ASSIGN_MACRO(sav_err, qef_rcb->error); } return(status); }
DB_STATUS psy_calarm( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; RDR_RB *rdf_rb = &rdf_cb.rdf_rb; i4 textlen; /* Length of query text */ QSF_RCB qsf_rb; DB_STATUS status, loc_status; i4 err_code; DB_SECALARM *alarm= &psy_cb->psy_tuple.psy_alarm; /* Fill in QSF request to lock text */ 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; /* Initialize RDF_CB */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_types_mask = RDR_SECALM; /* Alarm definition */ rdf_rb->rdr_update_op = RDR_APPEND; rdf_rb->rdr_qrytuple = (PTR)&psy_cb->psy_tuple.psy_alarm; /* Alarm tuple */ /* ** Get the query text from QSF. QSF has stored the text ** as a {nat, string} pair - maybe not be aligned. */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); status = qsf_call(QSO_INFO, &qsf_rb); if (status != E_DB_OK) { psf_error(E_PS0D19_QSF_INFO, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); goto cleanup; } MEcopy((PTR)qsf_rb.qsf_root, sizeof(i4), (PTR)&textlen); rdf_rb->rdr_l_querytext = textlen; rdf_rb->rdr_querytext = ((char *)qsf_rb.qsf_root) + sizeof(i4); rdf_rb->rdr_tabid.db_tab_base=alarm->dba_objid.db_tab_base; /* ** Check type of alarm, and handle accordingly. ** Main difference is where/how subjects are handled: ** - Named alarms have a single subject, which has already been ** resolved in psl. Alarms to public are handled here also ** - Anonymous alarms (old style) may have multiple subjects. These ** operate much like permits, and are split into several alarms, one ** for each subject. */ if(STskipblank((char*)&alarm->dba_alarmname, sizeof(alarm->dba_alarmname)) ==NULL && (alarm->dba_subjtype==DBGR_USER || alarm->dba_subjtype==DBGR_APLID || alarm->dba_subjtype==DBGR_GROUP) ) { PSY_USR *psy_usr; u_char *subj_name; i4 subj_name_len; u_char delim_subj_name[DB_MAX_DELIMID]; /* ** Anonymous alarms. ** We loop over each subject, updating the query text for ** each subject and creating the alarm. */ psy_usr = (PSY_USR *) psy_cb->psy_usrq.q_next; do { subj_name = (u_char *) &psy_usr->psy_usrnm; subj_name_len = (i4) psf_trmwhite(sizeof(psy_usr->psy_usrnm), (char *) subj_name); if (~psy_usr->psy_usr_flags & PSY_REGID_USRSPEC) { status = psl_norm_id_2_delim_id(&subj_name, &subj_name_len, delim_subj_name, &psy_cb->psy_error); if (DB_FAILURE_MACRO(status)) return status; } if (subj_name_len < DB_MAX_DELIMID) subj_name[ subj_name_len ] = EOS; STmove((char*)subj_name, ' ', DB_MAX_DELIMID, rdf_rb->rdr_querytext + psy_cb->psy_noncol_grantee_off); STmove((char*)subj_name, ' ', sizeof(alarm->dba_subjname), (char*)&alarm->dba_subjname); /* Reset alarm name in case filled in by RDF/QEF */ MEfill(sizeof(alarm->dba_alarmname), ' ', (PTR)&alarm->dba_alarmname); /* Create a new alarm in iisecalarm */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (status != E_DB_OK) { if ( rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); } else { _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } goto cleanup; } /* If RDF error */ /* Next subject */ psy_usr = (PSY_USR *) psy_usr->queue.q_next; } while (psy_usr != (PSY_USR *) &psy_cb->psy_usrq); } else { /* Named alarms */ /* Create a new alarm in iisecalarm */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (status != E_DB_OK) { if ( rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); } else { _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } goto cleanup; } /* If RDF error */ } cleanup: qsf_rb.qsf_lk_state = QSO_EXLOCK; /* Destroy query text - lock it first */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); loc_status = qsf_call(QSO_LOCK, &qsf_rb); if (loc_status != E_DB_OK) { psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (loc_status > status) status = loc_status; } loc_status = qsf_call(QSO_DESTROY, &qsf_rb); if (loc_status != E_DB_OK) { psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (loc_status > status) status = loc_status; } /* Invalidate tableinfo from RDF cache if table object */ if(psy_cb->psy_gtype==DBOB_TABLE) { pst_rdfcb_init(&rdf_cb, sess_cb); STRUCT_ASSIGN_MACRO(alarm->dba_objid, rdf_rb->rdr_tabid); loc_status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(loc_status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); if (loc_status > status) status = loc_status; } } return (status); } /* psy_calarm */
/*{ ** Name: psy_gproc - Get a database procedure definition from ** the system catalogs. ** ** Description: ** ** Inputs: ** psq_cb ** psq_cursid ** db_cur_name dbproc name ** sess_cb ** pss_user current user name ** pss_dba dba name ** qsf_rb ** rdf_cb ** dbp_owner name of the owner whose dbproc will be ** looked up iff gproc_mask & PSS_DBP_BY_OWNER. ** gproc_mask mask used to specify the possible owners of ** the dbproc to look for ** PSS_USRDBP look for dbproc owned by the current user ** PSS_DBADBP look for dbproc owned by the DBA ** PSS_INGDBP look for dbproc owned by $INGRES ** PSS_DBP_BY_OWNER look for dbproc owned by the specific user ** ** NOTE: if PSS_DBP_BY_OWNER is set, ** PSS_USRDBP, PSS_DBADBP, and PSS_INGDBP ** will be disregarded ** otherwise, we expect that PSS_USRDBP ** will be always set, while PSS_DBADBP ** and PSS_INGDBP may or may not be set ** ** Outputs: ** alt_user set to point the name of dbproc owner if ** different from cb->pss_user ** psq_cb ** psq_error filled in if an error occurred ** ** ret_flags bits may be set to pass info to the caller ** PSS_MISSING_DBPROC dbproc not found ** ** Exceptions: ** none ** ** Returns ** E_DB_OK, E_DB_ERROR ** ** Side Effects: ** Allocates memory. ** ** History: ** 27-apr-88 (stec) ** Created. ** 04-aug-88 (stec) ** Improve recovery of resources. ** 17-aug-88 (stec) ** Change bad STRUCT_ASSIGN statements. ** 28-sep-88 (stec) ** Do not lock object on cleanup. ** 28-sep-88 (stec) ** Must not unfix RDF entry. ** 16-mar-89 (andre) ** Added a new parameter - alt_user. ** psy_gproc will no longer reset pss_user or set pss_ruset. Instead ** it may set the ptr passed to it to the name of the dbproc owner. ** 16-mar-89 (neil) ** Modified psy_gproc to access the procedure through the specified ** owner (psq_als_owner) if psq_alias_set is on. ** 27-apr-89 (andre) ** Further modify to search for dbprocs owned by $ingres if the search ** by user and DBA failed. The search part of the function has been, ** essentially, rewritten. ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 01-jun-90 (andre) ** Changed interface to allow caller to explicitly specify the possible ** owners of the dbproc to look for. ** 01-oct-91 (andre) ** Added ret_flags to the interface - this field will be used to pass ** additional info to the caller. in particular, it will allow us to ** signal certain classes of errors (e.g. dbproc not found) without ** setting return status to E_DB_ERROR, thus enabling the caller to ** distinguish such errors from unexpected errors ** 15-oct-1993 (rog) ** We need to use ulm_copy() instead of MEcopy() when copying query ** text that might be more than 64k. ** 12-jan-94 (andre) ** As a part of fix for bug 58048, we must remove the assumption that ** either PSS_USRDBP or PSS_DBP_BY_OWNER bit will always be set in ** gproc_mask. Now we will be prepared to handle PSS_DBP_BY_OWNER or ** one or more of PSS_USRDBP, PSS_DBADBP, and PSS_INGDBP. ** 13-jan-94 (andre) ** if we fail to find a dbproc, we will set PSS_MISSING_DBPROC in ** *ret_flags, but leave it up to the caller to issue an error ** message - this way the caller can decide whether this warrants an ** error message and if so can choose his favourite error message */ DB_STATUS psy_gproc( PSQ_CB *psq_cb, PSS_SESBLK *sess_cb, QSF_RCB *qsf_rb, RDF_CB *rdf_cb, DB_OWN_NAME **alt_user, DB_OWN_NAME *dbp_owner, i4 gproc_mask, i4 *ret_flags) { DB_STATUS status, stat; i4 err_code; RDD_QRYMOD *pinfo; PSQ_QDESC *qdesc; bool leave_loop = TRUE; DB_PROCEDURE *dbp; SXF_ACCESS access; i4 msgid; i4 local_status; *ret_flags = 0; /* First call RDF to retrieve the definition ** of the procedure. */ /* Initialize the RDF control block */ pst_rdfcb_init(rdf_cb, sess_cb); (VOID) MEcopy((PTR) psq_cb->psq_cursid.db_cur_name, sizeof (DB_DBP_NAME), (PTR) &rdf_cb->rdf_rb.rdr_name.rdr_prcname); rdf_cb->rdf_rb.rdr_types_mask = RDR_PROCEDURE | RDR_BY_NAME; /* assume that the dbproc is owned by the current user */ *alt_user = (DB_OWN_NAME *) NULL; do { if (gproc_mask & (PSS_USRDBP | PSS_DBP_BY_OWNER)) { if (gproc_mask & PSS_USRDBP) { STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_cb->rdf_rb.rdr_owner); } else { STRUCT_ASSIGN_MACRO((*dbp_owner), rdf_cb->rdf_rb.rdr_owner); if (MEcmp((PTR)&sess_cb->pss_user, (PTR) dbp_owner, sizeof(DB_OWN_NAME))) { *alt_user = dbp_owner; /* Try someone else */ } } /* Get the text */ status = rdf_call(RDF_GETINFO, (PTR) rdf_cb); /* ** We do not want to continue search if: ** 1) dbproc was found OR ** 2) we got an error other that PROC_NOT_FOUND OR ** 3) caller requested a dbproc owned by a specific user ** (gproc_mask & PSS_DBP_BY_OWNER) OR */ if ( DB_SUCCESS_MACRO(status) || rdf_cb->rdf_error.err_code != E_RD0201_PROC_NOT_FOUND || gproc_mask & PSS_DBP_BY_OWNER) { break; } } /* ** if we were told to check whether a dbproc is owned by the DBA, do so ** unless the DBA is the current user and we have already established ** that the current user does not own a dbproc with this name */ if ( gproc_mask & PSS_DBADBP && ( ~gproc_mask & PSS_USRDBP || MEcmp((PTR) &sess_cb->pss_user, (PTR) &sess_cb->pss_dba.db_tab_own, sizeof(DB_OWN_NAME)) ) ) { STRUCT_ASSIGN_MACRO(sess_cb->pss_dba.db_tab_own, rdf_cb->rdf_rb.rdr_owner); /* ** If we succeed and the DBA is different from the current user, ** the procedure text will have to be parsed in the context of ** dbproc's owner, i.e. DBA. Note that if we were also asked to ** check whether the dbproc is owned by the current user and still ** found ourselves here, DBA must be different from the current user */ if ( gproc_mask & PSS_USRDBP || MEcmp((PTR) &sess_cb->pss_user, (PTR) &sess_cb->pss_dba.db_tab_own, sizeof(DB_OWN_NAME))) { *alt_user = &sess_cb->pss_dba.db_tab_own; } /* Get the text */ status = rdf_call(RDF_GETINFO, (PTR) rdf_cb); /* ** We do not want to continue search if: ** 1) dbproc was found OR ** 2) we got an error other that PROC_NOT_FOUND */ if (DB_SUCCESS_MACRO(status) || rdf_cb->rdf_error.err_code != E_RD0201_PROC_NOT_FOUND) { break; } } if (gproc_mask & PSS_INGDBP) { MEmove(sizeof(*sess_cb->pss_cat_owner), (PTR)sess_cb->pss_cat_owner, ' ', DB_OWN_MAXNAME, (PTR) &rdf_cb->rdf_rb.rdr_owner); } else { /* ** if user has not requested that a dbproc owned by $INGRES be ** looked up, might as well get out of the loop */ break; } /* ** if we were told to check whether a dbproc is owned by $ingres, do so ** unless the $ingres is the current user and we have already ** established that the current user does not own a dbproc with this ** name or $ingres is the DBA and we have already established that the ** DBA does not own a dbproc with this name */ if ( ( ~gproc_mask & PSS_USRDBP || MEcmp((PTR)&sess_cb->pss_user, (PTR) &rdf_cb->rdf_rb.rdr_owner, sizeof(DB_OWN_NAME)) ) && ( ~gproc_mask & PSS_DBADBP || MEcmp((PTR) &sess_cb->pss_dba.db_tab_own, (PTR) &rdf_cb->rdf_rb.rdr_owner, sizeof(DB_OWN_NAME)) ) ) { /* ** If we succeed, the procedure text will have to be parsed in ** the context of the original owner, i.e. $ingres. */ *alt_user = &rdf_cb->rdf_rb.rdr_owner; /* ** If we succeed and $ingres is not the current user, the procedure ** text will have to be parsed in the context of dbproc's owner, ** i.e. $ingres. Note that if we were also asked to check whether ** the dbproc is owned by the current user and still found ourselves ** here, the current user must NOT be $ingres */ if ( gproc_mask & PSS_USRDBP || MEcmp((PTR) &sess_cb->pss_user, (PTR) &rdf_cb->rdf_rb.rdr_owner, sizeof(DB_OWN_NAME))) { *alt_user = &sess_cb->pss_dba.db_tab_own; } /* Get the text */ status = rdf_call(RDF_GETINFO, (PTR) rdf_cb); } /* leave_loop has already been set to TRUE */ } while (!leave_loop); if (DB_FAILURE_MACRO(status)) { if (rdf_cb->rdf_error.err_code == E_RD0201_PROC_NOT_FOUND) { /* ** dbproc was not found - set a bit in ret_flags and reset status to ** E_DB_OK to enable callers to distinguish between this and other ** errors */ status = E_DB_OK; *ret_flags |= PSS_MISSING_DBPROC; } else { (VOID) psf_rdf_error(RDF_GETINFO, &rdf_cb->rdf_error, &psq_cb->psq_error); } return(status); } /* we get here only if the dbproc was found */ /* ** If the procedure has a security label, validate it */ dbp=rdf_cb->rdf_info_blk->rdr_dbp; /* Initialize the QSF control block */ qsf_rb->qsf_type = QSFRB_CB; qsf_rb->qsf_ascii_id = QSFRB_ASCII_ID; qsf_rb->qsf_length = sizeof(QSF_RCB); qsf_rb->qsf_owner = (PTR)DB_PSF_ID; qsf_rb->qsf_sid = sess_cb->pss_sessid; qsf_rb->qsf_obj_id.qso_type = QSO_QTEXT_OBJ; qsf_rb->qsf_obj_id.qso_lname = 0; /* Having retrieved the text place it in QSF ** because the parser expects it to be there. */ status = qsf_call(QSO_CREATE, qsf_rb); if (DB_FAILURE_MACRO(status)) { i4 qerr = qsf_rb->qsf_error.err_code; if (qerr == E_QS0001_NOMEM) { (VOID) psf_error(qerr, qerr, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); } else { (VOID) psf_error(E_PS0A05_BADMEMREQ, qerr, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); } goto cleanup2; } /* Object is locked exclusively now. */ pinfo = rdf_cb->rdf_rb.rdr_procedure; /* Allocate enough memory for the query descriptor ** plus the length of text. */ qsf_rb->qsf_sz_piece = sizeof(PSQ_QDESC) + pinfo->rdf_l_querytext + 3; /* one space, one null, ** one for safety. */ status = qsf_call(QSO_PALLOC, qsf_rb); if (DB_FAILURE_MACRO(status)) { i4 qerr = qsf_rb->qsf_error.err_code; if (qerr == E_QS0001_NOMEM) { (VOID) psf_error(qerr, qerr, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); } else { (VOID) psf_error(E_PS0A05_BADMEMREQ, qerr, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); } goto cleanup1; } qdesc = (PSQ_QDESC *) qsf_rb->qsf_piece; /* Initialize query descriptor. */ qdesc->psq_qrysize = pinfo->rdf_l_querytext + 1; /* 1 trailing space */ qdesc->psq_datasize = 0; qdesc->psq_dnum = 0; qdesc->psq_qrytext = (char *)(qdesc + 1); /* Ptr arithmetic, should point ** right after the PSQ_QDESC. */ qdesc->psq_qrydata = (DB_DATA_VALUE **) NULL; /* QSF memory has been allocated now, copy ** the text from RDF. */ ulm_copy((PTR) pinfo->rdf_querytext, (i4) pinfo->rdf_l_querytext, (PTR) qdesc->psq_qrytext); /* Add a space after the text and null terminate. */ { char *p; p = qdesc->psq_qrytext; /* beginning of text */ p += pinfo->rdf_l_querytext; /* 1st char past end */ *p++ = ' '; *p = '\0'; /* 2nd char past end */ } /* Set root for the QSF object */ qsf_rb->qsf_root = qsf_rb->qsf_piece; status = qsf_call(QSO_SETROOT, qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0A05_BADMEMREQ, qsf_rb->qsf_error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); goto cleanup1; } status = qsf_call(QSO_UNLOCK, qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0B05_CANT_UNLOCK, qsf_rb->qsf_error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); goto cleanup1; } psq_cb->psq_qid = qsf_rb->qsf_obj_id.qso_handle; return (status); cleanup1: /* Destroy the object, it's already locked. */ 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, &psq_cb->psq_error, 0); if (stat > status) status = stat; } cleanup2: /* RDF object can be released now. */ stat = rdf_call(RDF_UNFIX, (PTR) rdf_cb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_rdf_error(RDF_UNFIX, &rdf_cb->rdf_error, &psq_cb->psq_error); if (stat > status) status = stat; } return (status); }
/*{ ** Name: psy_kproc - Drop a database procedure definition from ** the system catalogs. ** ** Description: ** ** Inputs: ** ** Outputs: ** Exceptions: ** none ** ** Side Effects: ** Modifies system catalogs. ** ** History: ** 27-apr-88 (stec) ** Created. ** 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. ** 06-aug-92 (teresa) ** change interface to invalidate procedure by name, owner. ** must set rdr_flags_mask = RDR_PROCEDURE when invalidating the ** procedure cache object. ** 07-nov-92 (andre) ** we will no longer create private aliases for dbproc QPs ** 16-jun-94 (andre) ** 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 */ DB_STATUS psy_kproc( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_STATUS status, stat; i4 err_code; 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_DELETE; status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND) { /* 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); return (status); } } /* Try to destroy the procedure QP in QSF if things went OK. */ if (DB_SUCCESS_MACRO(status)) { QSF_RCB qsf_rb; PSS_DBPALIAS dbpid; DB_CURSOR_ID dbp_curs_id; /* Initialize the header of the QSF control block */ 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; 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 QEP 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 exit; } else { /* Nothing to destroy, QP not in QSF */ goto exit; } } /* Now destroy the ALIAS and the QP objects 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; } } /* Invalidate procedure object from RDF cache */ 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; status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } exit: return (status); }
/*{ ** Name: QEA_CALLPROC - call the named procedure ** ** Description: ** The current execution environment is saved and an ** environment is created in which to execute the ** named procedure. ** ** This procedure is only called when a nested procedure is invoked. ** This can occur the first time through, or if the procedure is not ** found (LOAD_QP) or the plan was deemed invalid (INVALID_QUERY) then ** the procedure is re-entered in this routine. ** ** If rules are turned off (QEF_T_NORULES) then this procedure returns ** immediately. ** ** Inputs: ** action Callproc action header ** qef_rcb ** call_dsh DSH doing the callproc ** function unused ** state unused ** ** Outputs: ** call_dsh ** .error.err_code one of the following ** E_QE0119_LOAD_QP - Load a procedure QP ** E_QE0125_RULES_INHIBIT - Rules are turned off. ** E_QE0000_OK ** Returns: ** E_DB_{OK,WARN,ERROR,FATAL} ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 20-apr-89 (paul) ** Moved from qeq.c ** 09-may-89 (neil) ** Added rule name tracing. ** 26-may-89 (paul) ** Increase statement #, cleanup DSH on error recovery. ** 31-may-89 (neil) ** Cleanup tracing; modify when context count is set; reset "saved ** resource" bit if procedure is loaded. ** 23-jun-89 (neil) ** Extended trace for nested procedures: Indicate procedure nesting ** level and rule depth. ** 26-sep-89 (neil) ** Support for SET NORULES. ** 02-jan-90 (neil) ** DSH initialization error handling improved to indicate problem ** specifics. ** 03-jan-90 (ralph) ** Change interface to QSO_JUST_TRANS ** 10-jan-90 (neil) ** Improved DSH cleanup on DSH initialization errors. Made sure ** to confirm allocation error, and to pass a FALSE "release" flag ** to qeq_cleanup. ** 09-feb-90 (neil) ** Auditing cleanup: only audit the firing of rules and only if ** auditing is on (for performance). ** 09-nov-92 (jhahn) ** Added handling for byrefs. ** 14-dec-92 (jhahn) ** Cleaned up handling of byrefs. ** 12-feb-93 (jhahn) ** Added support for statement level rules. (FIPS) ** 24-mar-93 (jhahn) ** Various fixes for support of statement level rules. (FIPS) ** 02-apr-93 (jhahn) ** Made set input procedures called from rules bump qef_rule_depth. ** 01-may-93 (jhahn) ** Undid above change. Instead added new action QEA_INVOKE_RULE. ** 06-jul-93 (robf) ** Pass security label to qeu_secaudit ** 01-sep-93 (jhahn) ** Added support for multiple query plans for set input procedures. ** 7-jan-94 (swm) ** Bug #58635 ** Added PTR cast for qsf_owner which has changed type to PTR. ** 18-may-94 (anitap) ** Bug #63465 ** If error in nested procedure, the whole transaction was being ** rolled back. ** 7-nov-95 (inkdo01) ** Changes to replace QEN_ADF structure instances by pointers in ** QEF_AHD structures. ** 24-jul-96 (inkdo01) ** Added support of global temp table proc parms. ** 4-mar-97 (inkdo01) ** Added display of error QE030B (row rule calls SET OF proc). ** 23-may-97 (inkdo01) ** Change QE030B to only pass procname, since it is mapped to a ** US error in qeferror, anyway. ** 17-aug-99 (thaju02) ** initialize dmt_show.db_tab_id.db_tab_base to 0 prior to calling ** dmt_show, to avoid falsely reporting E_QE0018. (b98431) ** 27-apr-01 (inkdo01) ** Add code to detect nested/dynamic calls to row procs. ** 15-mar-04 (inkdo01) ** dsh_tempTables is now an array of ptrs. ** 17-mar-04 (inkdo01) ** We be fixin' a bug in error handlin' when qeq_dsh() doesn't ** return a dsh. ** 13-may-04 (inkdo01) ** Preserve status across qeq_cleanup calls. ** 18-may-04 (inkdo01) ** Quick fix to eliminate QE0018 when QE030D (US09AF) happens. ** 13-Jul-2004 (schka24) ** Straighten out which dsh is used where, fix loss of error ** code when finding called qp leading to QE0018. ** 13-Dec-2005 (kschendel) ** Inlined QEN_ADF changed to pointer, fix here. ** 29-May-2008 (gefei01) ** Prototype change for qeq_dsh(). ** 22-Apr-2009 (hanal04) Bug 121970 ** In printrule tracing print the ahd_pcount not qef_pcount ** which is set to zero if we are in a sub-procedure. ** 21-Jun-2010 (kschendel) b123775 ** Combine is-tproc and in-progress args to qeq-dsh. ** Make dbp alias a real QSO_NAME. */ DB_STATUS qea_callproc( QEF_AHD *act, QEF_RCB *qef_rcb, QEE_DSH *call_dsh, i4 function, /* Unused */ i4 state ) /* Unused */ { i4 err; DB_STATUS status = E_DB_OK, savestat; QEF_CB *qef_cb = call_dsh->dsh_qefcb; PTR *cbs = call_dsh->dsh_cbs; QEE_DSH *proc_dsh; /* DSH for called dbp */ QEN_ADF *qen_adf; ADE_EXCB *ade_excb; QSF_RCB qsf_rcb; i4 tr1 = 0, tr2 = 0; /* Dummy trace values */ DB_ERROR e_error; /* To pass to qeu_secaudit */ i4 page_count; bool is_deferred = act->qhd_obj.qhd_callproc.ahd_proc_temptable != NULL; bool gttparm = act->qhd_obj.qhd_callproc.ahd_gttid.db_tab_base != 0; bool need_cleanup = FALSE; bool need_release; bool from_rule = act->qhd_obj.qhd_callproc.ahd_rulename.db_name[0] != EOS; QEE_TEMP_TABLE *proc_temptable; char *cbuf = qef_cb->qef_trfmt; i4 cbufsize = qef_cb->qef_trsize; i4 open_count; do { /* ** This action is called back if a request to CREATE a QP for a ** CALLPROC fails. In this case we just continue with error processing. ** No need for another error as CLEAN_RSRC is only set if a client on ** the outside issued an error knowing we have a stacked environment. ** (Note: as of the 123775 fixes, we shouldn't ever get here with ** CLEAN_RSRC set, since qeq-query no longer attempts to execute ** the action from the sequencer callback. I'm leaving the code ** here for now, though.) */ if ((qef_rcb->qef_intstate & QEF_CLEAN_RSRC) != 0) { call_dsh->dsh_error.err_code = E_QE0025_USER_ERROR; qef_rcb->qef_intstate &= ~QEF_CLEAN_RSRC; status = E_DB_ERROR; break; } if (is_deferred) { proc_temptable = call_dsh->dsh_tempTables[act->qhd_obj.qhd_callproc .ahd_proc_temptable->ttb_tempTableIndex]; if (proc_temptable->tt_statusFlags & TT_EMPTY) if (from_rule) break; /* empty ttab in statement rule - ** nothing to do at all */ else status = openTempTable(qef_rcb, call_dsh, act->qhd_obj.qhd_callproc .ahd_proc_temptable->ttb_tempTableIndex, gttparm); else status = qen_rewindTempTable(call_dsh, act->qhd_obj. qhd_callproc.ahd_proc_temptable->ttb_tempTableIndex); if (status != E_DB_OK) break; } /* If called from a rule & SET NORULES is on, then inhibit execution */ if ( from_rule && ult_check_macro(&qef_cb->qef_trace, QEF_T_NORULES, &tr1, &tr2) ) { /* Trace inhibited rule if required */ if (ult_check_macro(&qef_cb->qef_trace, QEF_T_RULES, &tr1, &tr2)) { char *rn = act->qhd_obj.qhd_callproc.ahd_rulename.db_name; STprintf(cbuf, "PRINTRULES: Rule '%.*s' suppressed\n", qec_trimwhite(DB_RULE_MAXNAME, rn), rn); qec_tprintf(qef_rcb, cbufsize, cbuf); } call_dsh->dsh_error.err_code = E_QE0125_RULES_INHIBIT; status = E_DB_ERROR; break; } /* If rules off */ /* ** Security audit rule firing - check that is first time (not ** recreation), is a rule and, for performance, that we really ** need to audit. */ if ( (qef_rcb->qef_intstate & QEF_DBPROC_QP) == 0 && (act->qhd_obj.qhd_callproc.ahd_rulename.db_name[0] != EOS) && (Qef_s_cb->qef_state & QEF_S_C2SECURE) ) { status = qeu_secaudit(FALSE, qef_cb->qef_ses_id, act->qhd_obj.qhd_callproc.ahd_rulename.db_name, (DB_OWN_NAME *)&act->qhd_obj.qhd_callproc.ahd_ruleowner, sizeof(act->qhd_obj.qhd_callproc.ahd_rulename), SXF_E_RULE, I_SX202F_RULE_ACCESS, SXF_A_SUCCESS | SXF_A_EXECUTE, &e_error); if (status != E_DB_OK) { call_dsh->dsh_error.err_code = e_error.err_code; break; } } /* Actually execute a CALLPROC. */ /* We generate an actual parameter list, save the current */ /* execution context, stack the DSH and setup the new */ /* execution context. Processing then continues with the */ /* new QP. */ /* Save the current execution context as represented by */ /* QEF_RCB and the current DSH. */ STRUCT_ASSIGN_MACRO(*qef_rcb, *call_dsh->dsh_saved_rcb); call_dsh->dsh_act_ptr = act; qen_adf = act->qhd_obj.qhd_callproc.ahd_procparams; if (qen_adf != NULL) { /* Compute the actual parameters for this procedure */ /* call. */ qef_rcb->qef_pcount = act->qhd_obj.qhd_callproc.ahd_pcount; ade_excb = (ADE_EXCB *)cbs[qen_adf->qen_pos]; ade_excb->excb_seg = ADE_SMAIN; status = ade_execute_cx(call_dsh->dsh_adf_cb, ade_excb); if (status != E_DB_OK) { status = qef_adf_error(&call_dsh->dsh_adf_cb->adf_errcb, status, qef_cb, &call_dsh->dsh_error); if (status != E_DB_OK) break; } } else { /* No actual parameters */ qef_rcb->qef_pcount = 0; } /* ** If tracing rules and first time through then display ** rule/procedure information. */ if ((qef_rcb->qef_intstate & QEF_DBPROC_QP) == 0) { if (ult_check_macro(&qef_cb->qef_trace, QEF_T_RULES, &tr1, &tr2)) { char *rn, *pn; /* Rule/procedure names */ rn = act->qhd_obj.qhd_callproc.ahd_rulename.db_name; pn = act->qhd_obj.qhd_callproc.ahd_dbpalias.qso_n_id.db_cur_name; /* Tailor trace for rules vs nested procedures */ STprintf(cbuf, *rn == EOS ? "PRINTRULES 1: Executing procedure '%.*s'\n" : "PRINTRULES 1: Executing procedure '%.*s' from rule '%.*s'\n", qec_trimwhite(DB_DBP_MAXNAME, pn), pn, qec_trimwhite(DB_RULE_MAXNAME, rn), rn); qec_tprintf(qef_rcb, cbufsize, cbuf); STprintf(cbuf, "PRINTRULES 2: Rule/procedure depth = %d/%d, parameters passed = %d\n", qef_rcb->qef_rule_depth, qef_rcb->qef_context_cnt + 1, act->qhd_obj.qhd_callproc.ahd_pcount); qec_tprintf(qef_rcb, cbufsize, cbuf); } /* If tracing rules */ } /* ** Indicate that we have nested one more level, generate an error if ** we are nested too deeply. Context count is actually set later. */ if (qef_cb->qef_max_stack < qef_rcb->qef_context_cnt + 1) { status = E_DB_ERROR; qef_error(E_QE0208_EXCEED_MAX_CALL_DEPTH, 0L, status, &err, &call_dsh->dsh_error, 1, sizeof(qef_cb->qef_max_stack), &qef_cb->qef_max_stack); call_dsh->dsh_error.err_code = E_QE0122_ALREADY_REPORTED; break; } if (gttparm) { STRUCT_ASSIGN_MACRO(act->qhd_obj.qhd_callproc.ahd_gttid, qef_rcb->qef_setInputId); /* copy temptab ID */ page_count = 1; is_deferred = TRUE; } else if (is_deferred) { DMT_CB *dmt_cb = proc_temptable->tt_dmtcb; DMT_SHW_CB dmt_show; DMT_TBL_ENTRY dmt_tbl_entry; dmt_show.type = DMT_SH_CB; dmt_show.length = sizeof(DMT_SHW_CB); dmt_show.dmt_session_id = qef_cb->qef_ses_id; dmt_show.dmt_db_id = qef_rcb->qef_db_id; dmt_show.dmt_tab_id.db_tab_base = 0; dmt_show.dmt_flags_mask = DMT_M_TABLE | DMT_M_ACCESS_ID; dmt_show.dmt_char_array.data_address = NULL; dmt_show.dmt_table.data_address = (PTR) &dmt_tbl_entry; dmt_show.dmt_table.data_in_size = sizeof(DMT_TBL_ENTRY); dmt_show.dmt_record_access_id = dmt_cb->dmt_record_access_id; status = dmf_call(DMT_SHOW, &dmt_show); if (status != E_DB_OK) { STRUCT_ASSIGN_MACRO(dmt_show.error, call_dsh->dsh_error); break; } page_count = dmt_tbl_entry.tbl_page_count; STRUCT_ASSIGN_MACRO(dmt_cb->dmt_id, qef_rcb->qef_setInputId); } else { page_count = -1; MEfill(sizeof(DB_TAB_ID), (u_char)0, (PTR)&qef_rcb->qef_setInputId); } STRUCT_ASSIGN_MACRO(act->qhd_obj.qhd_callproc.ahd_procedureID, qef_rcb->qef_dbpId); /* Get the id of the procedure to call */ STRUCT_ASSIGN_MACRO(act->qhd_obj.qhd_callproc.ahd_dbpalias.qso_n_id, qef_rcb->qef_qp); qef_rcb->qef_qso_handle = NULL; /* Set the full name of the procedure into the RCB in case */ /* we have to call PSF to define the procedure. */ qef_rcb->qef_dbpname = act->qhd_obj.qhd_callproc.ahd_dbpalias; /* Lookup this procedure name as a QSF alias. At this time */ /* we do not have a valid DB_CURSOR_ID because we do not */ /* have the timestamp for the QP object. Ask QSF to look */ /* this up for us. If found, we continue executing, if not */ /* return to SCF to define this procedure. */ qsf_rcb.qsf_type = QSFRB_CB; qsf_rcb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rcb.qsf_length = sizeof(QSF_RCB); qsf_rcb.qsf_owner = (PTR)DB_QEF_ID; qsf_rcb.qsf_sid = qef_rcb->qef_cb->qef_ses_id; qsf_rcb.qsf_feobj_id.qso_type = QSO_ALIAS_OBJ; qsf_rcb.qsf_feobj_id.qso_lname = sizeof(qsf_rcb.qsf_feobj_id.qso_name); MEcopy((PTR)&act->qhd_obj.qhd_callproc.ahd_dbpalias, sizeof(qsf_rcb.qsf_feobj_id.qso_name), (PTR)qsf_rcb.qsf_feobj_id.qso_name); qsf_rcb.qsf_lk_state = QSO_FREE; status = qsf_call(QSO_JUST_TRANS, &qsf_rcb); if (DB_FAILURE_MACRO(status)) { /* No such procedure in QSF, ask SCF to define it */ /* Tell SCF to call us back even if the porcedure */ /* cannot be loaded. We will need to clean up */ qef_rcb->qef_intstate |= QEF_DBPROC_QP; call_dsh->dsh_error.err_code = E_QE0119_LOAD_QP; break; } else { /* ** The procedure was found - make sure "saved" bit isn't on for ** the scope of this execution. It may get turned back on if ** the QP or DSH is found to be invalid but then we'll re-enter ** here (to try again) and turn it off. */ qef_rcb->qef_intstate &= ~QEF_DBPROC_QP; } /* Increase context count now that we've loaded the QP */ qef_rcb->qef_context_cnt++; /* Procedure in QSF, load the timestamp into the QEF_RCB */ /* to allow normal QEF processing to continue. */ MEcopy((PTR)qsf_rcb.qsf_obj_id.qso_name, sizeof(DB_CURSOR_ID), (PTR)&qef_rcb->qef_qp); status = qeq_dsh(qef_rcb, 0 , &proc_dsh, QEQDSH_IN_PROGRESS, page_count); if (DB_FAILURE_MACRO(status)) { char *rn, *pn; /* Rule/procedure names */ STRUCT_ASSIGN_MACRO(qef_rcb->error, call_dsh->dsh_error); if (call_dsh->dsh_error.err_code == E_QE0023_INVALID_QUERY) { /* No such procedure in QSF, ask SCF to define it */ /* Tell SCF to call us back even if the porcedure */ /* cannot be loaded. We will need to clean up */ qef_cb->qef_dsh = (PTR) call_dsh; qef_rcb->qef_qp = call_dsh->dsh_saved_rcb->qef_qp; qef_rcb->qef_intstate |= QEF_DBPROC_QP; call_dsh->dsh_error.err_code = E_QE0119_LOAD_QP; qef_rcb->qef_context_cnt--; break; } /* ** The QP DSH is invalid for some reason. Generate error and return. ** If any allocation error then change to useful error message. */ if ( call_dsh->dsh_error.err_code == E_UL0005_NOMEM || call_dsh->dsh_error.err_code == E_QS0001_NOMEM || call_dsh->dsh_error.err_code == E_QE001E_NO_MEM || call_dsh->dsh_error.err_code == E_QE000D_NO_MEMORY_LEFT || call_dsh->dsh_error.err_code == E_QE030B_RULE_PROC_MISMATCH) { pn = act->qhd_obj.qhd_callproc.ahd_dbpalias.qso_n_id.db_cur_name; rn = act->qhd_obj.qhd_callproc.ahd_rulename.db_name; if (*rn == EOS) rn = "NULL "; if (call_dsh->dsh_error.err_code == E_QE030B_RULE_PROC_MISMATCH) qef_error(E_QE030B_RULE_PROC_MISMATCH, 0L, status, &err, &call_dsh->dsh_error, 1, /* qec_trimwhite(DB_RULE_MAXNAME, rn), rn, */ qec_trimwhite(DB_DBP_MAXNAME, pn), pn); else qef_error(E_QE0199_CALL_ALLOC, 0L, status, &err, &call_dsh->dsh_error, 3, qec_trimwhite(DB_DBP_MAXNAME, pn), pn, qec_trimwhite(DB_RULE_MAXNAME, rn), rn, sizeof(qef_rcb->qef_context_cnt),&qef_rcb->qef_context_cnt); call_dsh->dsh_error.err_code = E_QE0122_ALREADY_REPORTED; } /* ** Now clean up and restore to state before routine entry. ** Pass in FALSE for release as if the DSH is NULL we do NOT want ** to cause cleanup to release all DSH's for this session ** (qee_cleanup). If the DSH is not NULL it will be cleaned up at ** the end of the query. */ need_cleanup = TRUE; need_release = FALSE; break; } if (proc_dsh->dsh_qp_ptr->qp_status & QEQP_ROWPROC) { char *pn; /* Row producing procs cannot be invoked by QEA_CALLPROC (which ** implies either nested proc call or dynamic SQL proc call). */ pn = act->qhd_obj.qhd_callproc.ahd_dbpalias.qso_n_id.db_cur_name; qef_error(E_QE030D_NESTED_ROWPROCS, 0L, E_DB_ERROR, &err, &call_dsh->dsh_error, 1, qec_trimwhite(DB_DBP_MAXNAME, pn), pn); status = E_DB_ERROR; break; } /* Found QP and DSH, stack old context */ proc_dsh->dsh_stack = call_dsh; proc_dsh->dsh_stmt_no = qef_cb->qef_stmt++; qef_cb->qef_dsh = (PTR) proc_dsh; qef_cb->qef_open_count++; /* Initialize procedure parameters (& user params - even if wrong) */ if (proc_dsh->dsh_qp_ptr->qp_ndbp_params != 0 || qef_rcb->qef_pcount > 0) { status = qee_dbparam(qef_rcb, proc_dsh, call_dsh, act->qhd_obj.qhd_callproc.ahd_params, act->qhd_obj.qhd_callproc.ahd_pcount, TRUE); if (DB_FAILURE_MACRO(status)) { /* If we fail after acquiring the DSH, we need to */ /* deallocate the DSH and recover back to the original */ /* calling state. */ STRUCT_ASSIGN_MACRO(proc_dsh->dsh_error, call_dsh->dsh_error); qef_cb->qef_open_count--; need_cleanup = TRUE; need_release = TRUE; break; } } if (is_deferred) { /* FIXME should error if it's null */ if (proc_dsh->dsh_qp_ptr->qp_setInput != NULL) STRUCT_ASSIGN_MACRO(qef_rcb->qef_setInputId, * (DB_TAB_ID *)(proc_dsh->dsh_row[proc_dsh->dsh_qp_ptr-> qp_setInput->vl_tab_id_index])); } } while (FALSE); if (need_cleanup) { /* error in a nested DB procedure, abort up to the beginning of the ** procedure if there are no other cursors opened. We ** guarantee that by decrementing the qef_open_count. If the ** count becomes zero, qeq_cleanup will abort to the last internal ** savepoint. Fix for bug 63465. */ savestat = status; open_count = qef_cb->qef_open_count; while (qef_cb->qef_open_count > 0) qef_cb->qef_open_count--; status = qeq_cleanup(qef_rcb, status, need_release); status = savestat; qef_cb->qef_open_count = open_count; qef_cb->qef_dsh = (PTR) call_dsh; qef_rcb->qef_context_cnt--; qef_rcb->qef_pcount = call_dsh->dsh_saved_rcb->qef_pcount; qef_rcb->qef_usr_param = call_dsh->dsh_saved_rcb->qef_usr_param; qef_rcb->qef_qp = call_dsh->dsh_saved_rcb->qef_qp; qef_rcb->qef_qso_handle = call_dsh->dsh_saved_rcb->qef_qso_handle; call_dsh->dsh_qef_rowcount = call_dsh->dsh_saved_rcb->qef_rowcount; call_dsh->dsh_qef_targcount = call_dsh->dsh_saved_rcb->qef_targcount; call_dsh->dsh_qef_output = call_dsh->dsh_saved_rcb->qef_output; call_dsh->dsh_qef_count = call_dsh->dsh_saved_rcb->qef_count; } return (status); }
DB_STATUS qee_d7_rptadd( QEF_RCB *qef_rcb) { DB_STATUS status; QES_DDB_SES *dds_p = & qef_rcb->qef_cb->qef_c2_ddb_ses; PTR handle; QES_RPT_HANDLE *hand_p, *new_p; QSF_RCB qsf_rcb; i4 i; PTR temp_new_p; /* 1. obtain handle if not already known */ if (qef_rcb->qef_qso_handle == (PTR) NULL) { qsf_rcb.qsf_next = (QSF_RCB *)NULL; qsf_rcb.qsf_prev = (QSF_RCB *)NULL; qsf_rcb.qsf_length = sizeof(QSF_RCB); qsf_rcb.qsf_type = QSFRB_CB; qsf_rcb.qsf_owner = (PTR)DB_QEF_ID; qsf_rcb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rcb.qsf_sid = qef_rcb->qef_cb->qef_ses_id; qsf_rcb.qsf_obj_id.qso_type = QSO_QP_OBJ; qsf_rcb.qsf_obj_id.qso_lname = sizeof (DB_CURSOR_ID); MEcopy((PTR)& qef_rcb->qef_qp, sizeof (DB_CURSOR_ID), (PTR) qsf_rcb.qsf_obj_id.qso_name); qsf_rcb.qsf_lk_state = QSO_SHLOCK; status = qsf_call(QSO_GETHANDLE, & qsf_rcb); if (status) { if (qsf_rcb.qsf_error.err_code == E_QS0019_UNKNOWN_OBJ) qef_rcb->error.err_code = E_QE0023_INVALID_QUERY; else qef_rcb->error.err_code = E_QE0014_NO_QUERY_PLAN; return(status); } handle = qsf_rcb.qsf_obj_id.qso_handle; } else handle = qef_rcb->qef_qso_handle; /* 2. search for the existence of this handle in list */ for (i = 0, hand_p = dds_p->qes_d12_handle_p; i < dds_p->qes_d11_handle_cnt; ++i) { if (handle == hand_p->qes_3_qso_handle) return(E_DB_OK); /* handle already registered */ else { /* advance to next repeat query handle */ if (hand_p->qes_2_next != NULL) hand_p = hand_p->qes_2_next; } } /* 3. allocate structure for this new handle */ status = qee_d6_malloc( (i4) sizeof(QES_RPT_HANDLE), qef_rcb, &temp_new_p); new_p = (QES_RPT_HANDLE *)temp_new_p; if (status) return(status); /* 4. initialize handle structure and insert into list */ new_p->qes_1_prev = NULL; new_p->qes_2_next = NULL; new_p->qes_3_qso_handle = handle; if (dds_p->qes_d11_handle_cnt == 0) { /* this is the first one in the list */ dds_p->qes_d12_handle_p = (QES_RPT_HANDLE *) new_p; dds_p->qes_d11_handle_cnt = 1; /* set count */ } else { /* insert at head of list */ new_p->qes_2_next = dds_p->qes_d12_handle_p; dds_p->qes_d12_handle_p = (QES_RPT_HANDLE *) new_p; /* new first handle */ dds_p->qes_d11_handle_cnt += 1; /* increment count */ } return(E_DB_OK); }
/*{ ** Name: psy_dpermit - Define a permit. ** ** INTERNAL PSF call format: status = psy_dpermit(&psy_cb, sess_cb); ** ** EXTERNAL call format: status = psy_call(PSY_DPERMIT, &psy_cb, sess_cb); ** ** Description: ** Given all of the parameters necessary to CREATE/DEFINE a permit on a ** table or view, this function will store the permission in the system ** catalogs. This will include storing the query tree in the tree table, ** storing the text of the query in the iiqrytext table (really done by ** QEF), storing a row in the protect table, and issuing an "alter table" ** operation to DMF to indicate that there are permissions on the given ** table. ** ** Inputs: ** psy_cb ** .psy_qrytext Id of query text as stored in QSF. ** .psy_cols[] Array of columns on which to grant ** permission ** .psy_numcols Number of columns listed above; 0 means ** give permission on all columns ** .psy_intree QSF id of query tree representing the ** where clause in the permit ** .psy_opctl Bit map of defined operations ** .psy_opmap Bit map of permitted operations ** .psy_user Name of user who will get permission ** .psy_terminal Terminal at which permission is given ** (blank if none specified) ** .psy_timbgn Time of day at which the permission ** begins (minutes since 00:00) ** .psy_timend Time of day at which the permission ends ** (minutes since 00:00) ** .psy_daybgn Day of week at which the permission ** begins (0 = Sunday) ** .psy_dayend Day of week at which the permission ends ** (0 = Sunday) ** .psy_grant ** PSY_CPERM CREATE/DEFINE PERMIT ** .psy_tblq head of table queue ** .psy_colq head of column queue ** .psy_usrq head of user queue ** .psy_qlen length of first iiqrytext ** .psy_flags useful info ** PSY_EXCLUDE_COLUMNS user specified a list of columns to ** which privilege should not apply ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_txtid Id of query text as stored in the ** iiqrytext system relation. ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s); ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Stores text of query in iiqrytext relation, query tree in tree ** relation, row in protect relation identifying the permit. Does ** an alter table DMF operation to indicate that there are permissions ** on the table. ** ** History: ** 02-oct-85 (jeff) ** written ** 03-sep-86 (seputis) ** changed some psy_cb. to psy_cb-> ** added .db_att_id reference ** changed rdr_cb. rdr_cb-> ** 02-dec-86 (daved) ** bug fixing. check for permit on tables owned by user and not ** view. ** 29-apr-87 (stec) ** Implemented changes for GRANT statement. ** 10-may-88 (stec) ** Make changes for db procs. ** 03-oct-88 (andre) ** Modified call to pst_rgent to pass 0 as a query mode since it is ** clearly not PSQ_DESTROY ** 06-feb-89 (ralph) ** Added support for 300 attributes: ** Use DB_COL_BITS in place of DB_MAX_COLS ** Loop over domset array using DB_COL_WORDS ** 06-mar-89 (ralph) ** GRANT Enhancements, Phase 1: ** Initialize new DB_PROTECTION fields, dbp_seq and dbp_gtype ** 03-apr-89 (ralph) ** GRANT Enhancements, Phase 2: ** Use DBGR_USER when initializing dbp_gtype ** 08-may-89 (ralph) ** Initialize reserved field to blanks (was \0) ** 04-jun-89 (ralph) ** Initialize dbp_fill1 to zero ** Fix unix portability problems ** 02-nov-89 (neil) ** Alerters: Allowed privileges for events. ** 1-mar-90 (andre) ** If processing a GRANT on tables, check if ** ALL-TO-ALL or RETRIEVE-TO-ALL has already been granted, and if so, ** mark psy_mask appropriately. ** If user tried to CREATE ALL/RETRIEVE-TO-ALL, and one already exists, ** skip to the exit. ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 08-aug-90 (ralph) ** Initialize new fields in iiprotect tuple ** 14-dec-90 (ralph) ** Disallow use of GRANT by non-DBA if xORANGE ** 11-jan-90 (ralph) ** Allow user "$ingres" to use GRANT if xORANGE. ** This was done for CREATEDB (UPGRADEFE). ** 20-feb-91 (andre) ** For CREATE/DEFINE PERMIT, grantee type was stored in ** psy_cb->psy_gtype. ** 24-jun-91 (andre) ** IIPROTECT tuples for table permits will contain exactly one ** privilege. IIQRYTEXT template built for table-wide privileges ** contains a placeholder for a privilege name which will be filled in ** with each of the table-wide privileges being granted, one at a time. ** PSY_CB.psy_opmap will be set to correspond with privilege name ** stored in the IIQRYTEXT permit. ** 16-jul-91 (andre) ** responsibility for splitting permit tuples will passed on to ** qeu_cprot(). If a permit specified only one privilege, we will ** substitute the appropriate privilege name here and will not ask ** qeu_cprot() to split tuples. ** 06-aug-91 (andre) ** before proceeding to CREATE a permit on a view owned by the current ** user, we will call psy_tbl_grant_check() to ensure that this user ** may create a permit on his view. If the object is not owned by the ** current user, we will not try to verify that the user may ** CREATE/DEFINE a permit since (until the relevant FE changes are ** made) we intend to continue allowing any user with CATUPD to ** CREATE/DEFINE permits on catalogs and the dba will be allowed to ** CREATE/DEFINE permits on extended catalogs ** 11-nov-91 (rblumer) ** merged from 6.4: 26-feb-91 (andre) ** PST_QTREE was changed to store the range table as an array of ** pointers to PST_RNGENTRY structure. ** 14-feb-92 (andre) ** we will no longer have to fill in privilege name for permits ** specifying one privilege - it will be handled in respective ** grammars. ** 15-jun-92 (barbara) ** For Sybil, change interface to pst_rgent(), Star returns from ** psy_dpermit before permits get stored. ** 07-jul-92 (andre) ** DB_PROTECTION tuple will contain an indicator of how the permit was ** created, i.e. whether it was created using SQL or QUEL and if the ** former, then whether it was created using GRANT statement. Having ** this information will facilitate merging similar and identical ** permit tuples. ** 14-jul-92 (andre) ** semantics of GRANT ALL [PRIVILEGES] is different from that of ** CREATE PERMIT ALL in that the former (as dictated by SQL92) means ** "grant all privileges which the current auth id posesses WGO" ** whereas the latter (as is presently interpreted) means "grant all ** privileges that can be defined on the object" which in case of ** tables and views means SELECT, INSERT, DELETE, UPDATE. ** psy_tbl_grant_check() (function responsible for determining whether ** a user may grant specified privilege on a specified table or view) ** will have to be notified whether we are processing GRANT ALL. Its ** behaviour will change as follows: ** - if processing GRANT ALL and psy_tbl_grant_check() determines ** that the user does not possess some (but not all) of the ** privileges passed to it by the caller it will not treat it as an ** error, but will instead inform the caller of privileges that the ** user does not posess, ** - if processing GRANT ALL and psy_tbl_grant_check() determines ** that the user does not possess any of the privileges passed to ** it by the caller it will treat it as an error ** - if processing a statement other than GRANT ALL and ** psy_tbl_grant_check() determines that the user does not possess ** some of the privileges passed to it by the caller it will treat ** it as an error ** 16-jul-92 (andre) ** if a permit being created depends on some privileges, build a ** structure describing these privileges and store its address in ** rdf_cb->rdr_indep. ** 18-jul-92 (andre) ** we will no longer be telling QEF to turn off DMT_ALL_PROT or ** DMT_RETRIEVE_PRO when a user creates ALL/RETRIEVE TO ALL permit. ** QEF will figure out on its own whether PUBLIC now has RETRIEVE or ** ALL on a table/view ** 20-jul-92 (andre) ** if user specified a list of columns to which privilege(s) should ** not apply, set dbp_domset correctly ** 03-aug-92 (barbara) ** Invalidate base table infoblk from RDF cache for CREATE PERMIT ** and CREATE SEC_ALARM. ** 16-sep-92 (andre) ** privilege maps are build using bitwise ops, so care should be ** exercised when accessing it using BT*() functions ** 17-jun-93 (andre) ** changed interface of psy_secaudit() to accept PSS_SESBLK ** 5-jul-93 (robf) ** changed interface of psy_secaudit() to accept security label ** 7-jan-94 (swm) ** Bug #58635 ** Added PTR cast for qsf_owner which has changed type to PTR. ** 06-mar-96 (nanpr01) ** Move the QSF request block initialization up. because if ** pst_rgnent returns a failure status code, subsequent QSF ** calls get bad control block error. */ DB_STATUS psy_dpermit( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; QSF_RCB qsf_rb; DB_STATUS status; DB_STATUS stat; DB_PROTECTION ptuple; register DB_PROTECTION *protup = &ptuple; i4 *domset = ptuple.dbp_domset; register i4 i, j; i4 err_code; PSS_RNGTAB *rngvar; PSS_USRRANGE *rngtab; PST_PROCEDURE *pnode; PST_QTREE *qtree; DB_ERROR *err_blk = &psy_cb->psy_error; i4 textlen; i4 tree_lock = 0; i4 text_lock = 0; DB_TAB_ID tabids[PST_NUMVARS]; PSQ_INDEP_OBJECTS indep_objs; PSQ_OBJPRIV obj_priv; /* space for independent DELETE */ PSQ_COLPRIV col_privs[2]; /* ** space for independent INSERT and ** UPDATE */ PST_VRMAP varmap; PSY_TBL *psy_tbl; DB_TIME_ID timeid; DB_NAME *objname; /* ** For CREATE/DEFINE PERMIT execute code below. */ /* initialize the QSF control block */ 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; rngtab = &sess_cb->pss_auxrng; /* table info is stored in the only entry in the table queue */ psy_tbl = (PSY_TBL *) psy_cb->psy_tblq.q_next; status = pst_rgent(sess_cb, rngtab, -1, "", PST_SHWID, (DB_TAB_NAME *) NULL, (DB_TAB_OWN *) NULL, &psy_tbl->psy_tabid, TRUE, &rngvar, (i4) 0, err_blk); if (DB_FAILURE_MACRO(status)) goto exit; /* In STAR, we do not actually store permits */ if (sess_cb->pss_distrib & DB_3_DDB_SESS) { qsf_rb.qsf_lk_state = QSO_EXLOCK; goto exit; } /* Fill in the RDF request block */ pst_rdfcb_init(&rdf_cb, sess_cb); /* The table which is receiving the permit */ STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabid, rdf_rb->rdr_tabid); /* Tell RDF we're doing a permit definition */ rdf_rb->rdr_update_op = RDR_APPEND; rdf_rb->rdr_types_mask = RDR_PROTECT; rdf_rb->rdr_qrytuple = (PTR) protup; /* initialize independent object structure */ indep_objs.psq_objs = (PSQ_OBJ *) NULL; indep_objs.psq_objprivs = (PSQ_OBJPRIV *) NULL; indep_objs.psq_colprivs = (PSQ_COLPRIV *) NULL; indep_objs.psq_grantee = &sess_cb->pss_user; rdf_rb->rdr_indep = (PTR) &indep_objs; /* ** populate the IIPROTECT tuple */ /* Zero out the template */ (VOID)MEfill(sizeof(ptuple), (u_char) 0, (PTR) protup); /* store grantee type */ protup->dbp_gtype = psy_cb->psy_gtype; /* Init reserved block */ (VOID)MEfill(sizeof(protup->dbp_reserve), (u_char) ' ', (PTR) protup->dbp_reserve); /* Init obj name */ STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabnm, protup->dbp_obname); /*@FIX_ME@ Where does this come from? */ protup->dbp_obstat = ' '; /* store the object type indicator */ if (psy_tbl->psy_mask & PSY_OBJ_IS_TABLE) { protup->dbp_obtype = DBOB_TABLE; } else if (psy_tbl->psy_mask & PSY_OBJ_IS_VIEW) { protup->dbp_obtype = DBOB_VIEW; } else { protup->dbp_obtype = DBOB_INDEX; } STRUCT_ASSIGN_MACRO(psy_tbl->psy_owner, protup->dbp_obown); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, protup->dbp_grantor); TMnow((SYSTIME *)&timeid); protup->dbp_timestamp.db_tim_high_time = timeid.db_tim_high_time; protup->dbp_timestamp.db_tim_low_time = timeid.db_tim_low_time; /* The table on which we're giving permission */ STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabid, protup->dbp_tabid); /* Beginning and ending times of day */ protup->dbp_pdbgn = psy_cb->psy_timbgn; protup->dbp_pdend = psy_cb->psy_timend; /* Beginning and ending days of week */ protup->dbp_pwbgn = psy_cb->psy_daybgn; protup->dbp_pwend = psy_cb->psy_dayend; if (psy_cb->psy_numcols != 0 && ~psy_cb->psy_flags & PSY_EXCLUDE_COLUMNS) { /* user specified a list of columns to which privilege(s) will apply */ /* Bit map of permitted columns */ psy_fill_attmap(domset, ((i4) 0)); for (i = 0; i < psy_cb->psy_numcols; i++) { BTset((i4)psy_cb->psy_cols[i].db_att_id, (char *) domset); } } else { /* ** user specified table-wide privilege(s) or a list of columns L s.t. ** privilege(s) will apply to the entire table except for columns in L */ psy_fill_attmap(domset, ~((i4) 0)); if (psy_cb->psy_flags & PSY_EXCLUDE_COLUMNS) { /* ** exclude specified columns from the list of columns to which ** privilege(s) will apply */ for (i = 0; i < psy_cb->psy_numcols; i++) { BTclear((i4) psy_cb->psy_cols[i].db_att_id, (char *) domset); } } } if (rngvar->pss_tabdesc->tbl_status_mask & DMT_VIEW) { /* ** if view is owned by the current user, psy_tbl_grant_check() will ** determine if the permit can, indeed, be created; as long as we are ** preserving the kludge that allows users with CATUPD create permits on ** catalogs and DBAs to create permits on extended catalogs, we shall ** not call psy_tbl_grant_check() on view not owned by the current user, ** since it is likely to result in psy_tbl_grant_check() complaining ** about inadequate permissions */ if (!MEcmp((PTR) &rngvar->pss_ownname, (PTR) &sess_cb->pss_user, sizeof(sess_cb->pss_user))) { i4 tbl_wide_privs; PSY_COL_PRIVS col_specific_privs, *csp, indep_col_specific_privs; DB_TAB_ID indep_id; i4 indep_tbl_wide_privs; bool insuf_privs, quel_view; i4 val1, val2; /* ** build maps of table-wide and column-specific privileges for ** psy_tbl_grant_check() ** if a column list was specified with CREATE PERMIT and ** privileges specified in the statement include a set of ** privileges S s.t. for all P in S, P can only be specified as ** table-wide with GRANT statement (currently this includes ** SELECT, INSERT, DELETE), we will make ** psy_tbl_grant_check() think that privileges in S are ** table-wide. ** This will work correctly since if the view was defined over ** some objects owned by other user(s), for every P in S we ** would need table-wide privilege WGO on the underlying object. ** ** For the purposes of providing more descriptive output for ** trace point ps131, if column-list was specified, we will pass ** the map of attributes even if column-specific UPDATE was not ** specified */ if (psy_cb->psy_numcols != 0 && (psy_cb->psy_opmap & DB_REPLACE || ult_check_macro(&sess_cb->pss_trace, 3, &val1, &val2) ) ) { i4 *ip; csp = &col_specific_privs; /* ** column-specific UPDATE privilege will not be translated into ** a table-wide privilege since GRANT allows for specification ** of column-specific UPDATE privilege */ csp->psy_col_privs = psy_cb->psy_opmap & DB_REPLACE; tbl_wide_privs = psy_cb->psy_opmap & ~DB_REPLACE; /* ** if creating a permit on a set of columns and UPDATE is not ** one of the privileges named in the statement, store the ** attribute map in the first element of the attribute map list */ ip = (csp->psy_col_privs) ? csp->psy_attmap[PSY_UPDATE_ATTRMAP].map : csp->psy_attmap->map; /* copy the attribute map */ for (i = 0; i < DB_COL_WORDS; i++, ip++) { *ip = domset[i]; } } else { tbl_wide_privs = psy_cb->psy_opmap; csp = (PSY_COL_PRIVS *) NULL; } status = psy_tbl_grant_check(sess_cb, (i4) PSQ_PROT, &rngvar->pss_tabid, &tbl_wide_privs, csp, &indep_id, &indep_tbl_wide_privs, &indep_col_specific_privs, psy_cb->psy_flags, &insuf_privs, &quel_view, &psy_cb->psy_error); if (DB_FAILURE_MACRO(status)) { goto exit; } if (insuf_privs) { /* must audit failure to create a permit */ if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) { DB_ERROR e_error; /* Must audit CREATE PERMIT failure. */ status = psy_secaudit(FALSE, sess_cb, (char *)&rngvar->pss_tabdesc->tbl_name, &rngvar->pss_tabdesc->tbl_owner, sizeof(DB_TAB_NAME), SXF_E_TABLE, I_SX2016_PROT_TAB_CREATE, SXF_A_FAIL | SXF_A_CREATE, &e_error); status = (status > E_DB_ERROR) ? status : E_DB_ERROR; } goto exit; } else if (quel_view) { goto exit; } /* ** If user is trying to grant one or more of ** INSERT/DELETE/UPDATE on his/her view whose underlying table ** or view is owned by another user, psy_tbl_grant_check() will ** return id of the underlying object along with map of ** privileges. We will convert maps of independent privileges ** into elements of independent privilege list and pass them ** along to QEF */ if ( indep_id.db_tab_base != (i4) 0 && ( indep_id.db_tab_base != rngvar->pss_tabid.db_tab_base || indep_id.db_tab_index != rngvar->pss_tabid.db_tab_index ) ) { if (indep_tbl_wide_privs & DB_DELETE) { /* ** the only expected independent table-wide privilege ** is DELETE */ obj_priv.psq_next = (PSQ_OBJPRIV *) NULL; obj_priv.psq_objtype = PSQ_OBJTYPE_IS_TABLE; obj_priv.psq_privmap = (i4) DB_DELETE; obj_priv.psq_objid.db_tab_base = indep_id.db_tab_base; obj_priv.psq_objid.db_tab_index = indep_id.db_tab_index; indep_objs.psq_objprivs = &obj_priv; } if (indep_col_specific_privs.psy_col_privs) { i4 i, j; PSQ_COLPRIV *csp; i4 *att_map, *p; i4 priv_map = 0; /* ** privilege map is built using bitwise operators, but ** here using BTnext() makes code much more palatable, ** so convert a privilege map */ if (indep_col_specific_privs.psy_col_privs & DB_APPEND) BTset(DB_APPP, (char *) &priv_map); if (indep_col_specific_privs.psy_col_privs & DB_REPLACE) BTset(DB_REPP, (char *) &priv_map); for (i = -1, csp = col_privs; (i = BTnext(i, (char *) &priv_map, BITS_IN(priv_map))) != -1; csp++ ) { csp->psq_next = indep_objs.psq_colprivs; indep_objs.psq_colprivs = csp; csp->psq_objtype = PSQ_OBJTYPE_IS_TABLE; csp->psq_tabid.db_tab_base = indep_id.db_tab_base; csp->psq_tabid.db_tab_index = indep_id.db_tab_index; switch (i) { case DB_APPP: /* INSERT privilege */ { csp->psq_privmap = (i4) DB_APPEND; att_map = indep_col_specific_privs. psy_attmap[PSY_INSERT_ATTRMAP].map; break; } case DB_REPP: { csp->psq_privmap = (i4) DB_REPLACE; att_map = indep_col_specific_privs. psy_attmap[PSY_UPDATE_ATTRMAP].map; break; } } for (p = csp->psq_attrmap, j = 0; j < DB_COL_WORDS; j++) { *p++ = *att_map++; } } } } } else { /* ** either this is a catalog and the user has CATUPD or ** this is an extended catalog and the user is the DBA; ** since we may be allowing a user to create a permit by ** circumventing the permit system, we only need to ascertain that ** this is an SQL view */ i4 issql = 0; status = psy_sqlview(rngvar, sess_cb, err_blk, &issql); if (status) { goto exit; } if (!issql) { /* can only have permits on SQL views */ psf_error(3598L, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(rngvar->pss_tabname), (char *) &rngvar->pss_tabname), &rngvar->pss_tabname); status = E_DB_ERROR; goto exit; } } } /* Name of user getting permission */ STRUCT_ASSIGN_MACRO(psy_cb->psy_user, protup->dbp_owner); /* Terminal at which permission given */ STRUCT_ASSIGN_MACRO(psy_cb->psy_terminal, protup->dbp_term); /* Give RDF pointer to query tree, if any */ if (!psy_cb->psy_istree) { rdf_rb->rdr_qry_root_node = (PTR) NULL; } else { PST_VRMAP varset; i4 j; STRUCT_ASSIGN_MACRO(psy_cb->psy_intree, qsf_rb.qsf_obj_id); qsf_rb.qsf_lk_state = QSO_EXLOCK; status = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0D19_QSF_INFO, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); goto exit; } tree_lock = qsf_rb.qsf_lk_id; pnode = (PST_PROCEDURE *) qsf_rb.qsf_root; qtree = (PST_QTREE *) pnode->pst_stmts->pst_specific.pst_tree; rdf_rb->rdr_qry_root_node = (PTR) pnode; /* check for no views in the qualification. */ (VOID)psy_varset(qtree->pst_qtree, &varset); j = BTnext(-1, (char *) &varset, BITS_IN(varset)); for ( ; j >= 0; j = BTnext(j, (char *) &varset, BITS_IN(varset))) { status = pst_rgent(sess_cb, rngtab, -1, "", PST_SHWID, (DB_TAB_NAME *) NULL, (DB_TAB_OWN *) NULL, &qtree->pst_rangetab[j]->pst_rngvar, TRUE, &rngvar, (i4) 0, err_blk); if (status) goto exit; if (rngvar->pss_tabdesc->tbl_status_mask & DMT_VIEW) { psf_error(3597L, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(rngvar->pss_tabname), (char *) &rngvar->pss_tabname), &rngvar->pss_tabname); status = E_DB_ERROR; goto exit; } } } /* Give RDF a pointer to the query text to be stored in iiqrytext */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); qsf_rb.qsf_lk_state = QSO_EXLOCK; status = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0D19_QSF_INFO, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); goto exit; } text_lock = qsf_rb.qsf_lk_id; MEcopy((char *) qsf_rb.qsf_root, sizeof(i4), (char *) &textlen); rdf_rb->rdr_l_querytext = textlen; rdf_rb->rdr_querytext = ((char *) qsf_rb.qsf_root) + sizeof(i4); rdf_rb->rdr_status = (sess_cb->pss_lang == DB_SQL) ? DB_SQL : 0; /* determine if the permit specifies exactly one privilege */ if (BTcount((char *) &psy_cb->psy_opmap, BITS_IN(psy_cb->psy_opmap)) > 1) { /* ** if permit specified more than one privilege, notify QEF that it will ** have to split the permit into multiple IIPROTECT tuples */ rdf_rb->rdr_instr |= RDF_SPLIT_PERM; } else if (psy_cb->psy_opmap & DB_RETRIEVE) { /* ** if qeu_cprot() will not be splitting the permit into multiple tuples ** and RETRIEVE is the privilege mentioned in it, set the two bits ** associated with DB_RETRIEVE */ psy_cb->psy_opmap |= DB_TEST | DB_AGGREGATE; psy_cb->psy_opctl |= DB_TEST | DB_AGGREGATE; } /* Null out the DMU control block pointer, just in case */ rdf_rb->rdr_dmu_cb = (PTR) NULL; /* produce list of dependent tables */ rdf_rb->rdr_cnt_base_id = 0; if (psy_cb->psy_istree && qtree->pst_qtree) { j = 0; (VOID)psy_varset(qtree->pst_qtree, &varmap); for (i = -1; (i = BTnext(i, (char*) &varmap, PST_NUMVARS)) > -1;) { /* if this is the table that is getting the permit, ignore */ if (qtree->pst_rangetab[i]->pst_rngvar.db_tab_base != psy_tbl->psy_tabid.db_tab_base || qtree->pst_rangetab[i]->pst_rngvar.db_tab_index != psy_tbl->psy_tabid.db_tab_index ) { rdf_rb->rdr_cnt_base_id++; STRUCT_ASSIGN_MACRO(qtree->pst_rangetab[i]->pst_rngvar, tabids[j++]); } } rdf_rb->rdr_base_id = tabids; } protup->dbp_popctl = psy_cb->psy_opctl; protup->dbp_popset = psy_cb->psy_opmap; /* ** store an indication of whether this permit is being created using SQL or ** QUEL */ protup->dbp_flags = (sess_cb->pss_lang == DB_SQL) ? DBP_SQL_PERM : (i2) 0; protup->dbp_flags |= DBP_65_PLUS_PERM; /* Now let RDF do all the work of the permit definition */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(psy_tbl->psy_tabnm), (char *) &psy_tbl->psy_tabnm), &psy_tbl->psy_tabnm); } else { (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } goto exit; } /* ** Invalidate base object's infoblk from RDF cache. */ pst_rdfcb_init(&rdf_cb, sess_cb); STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[0], rdf_rb->rdr_tabid); status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } exit: qsf_rb.qsf_lk_state = QSO_EXLOCK; if (psy_cb->psy_istree) { /* Destroy query tree */ STRUCT_ASSIGN_MACRO(psy_cb->psy_intree, qsf_rb.qsf_obj_id); if ((qsf_rb.qsf_lk_id = tree_lock) == 0) { stat = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (!status || stat == E_DB_FATAL) status = stat; } tree_lock = qsf_rb.qsf_lk_id; } stat = qsf_call(QSO_DESTROY, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (!status || stat == E_DB_FATAL) status = stat; } tree_lock = 0; } /* Destroy query text */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); if ((qsf_rb.qsf_lk_id = text_lock) == 0) { stat = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (!status || stat == E_DB_FATAL) status = stat; } text_lock = qsf_rb.qsf_lk_id; } stat = qsf_call(QSO_DESTROY, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (!status || stat == E_DB_FATAL) status = stat; } return (status); }
/*{ ** Name: psy_alarm - Dispatch security alarm qrymod routines ** ** INTERNAL PSF call format: status = psy_alarm(&psy_cb, sess_cb); ** EXTERNAL call format: status = psy_call (PSY_ALARM, &psy_cb, sess_cb); ** ** Description: ** This procedure checks the psy_alflag field of the PSY_CB ** to determine which qrymod processing routine to call: ** PSY_CALARM results in call to psy_calarm() ** PSY_KALARM results in call to psy_kalarm() ** ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_alflag location operation ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s); ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_SEVERE Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** None. ** ** History: ** 21-sep-89 (ralph) ** written ** 29-nov-93 (robf) ** Now really call psy_calarm/psy_kalarm() */ DB_STATUS psy_alarm( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status=E_DB_OK; i4 err_code; i4 user_status; char dbname[DB_DB_MAXNAME]; SCF_CB scf_cb; SCF_SCI sci_list[2]; bool loop=FALSE; DB_SECALARM *alarm= &psy_cb->psy_tuple.psy_alarm; DB_STATUS local_status; DB_ERROR e_error; /* This code is called for SQL only */ /* ** Ensure we're connected to the iidbdb database for database/installation ** alarms, and have SECURITY privilege */ if(alarm->dba_objtype==DBOB_DATABASE) do { scf_cb.scf_length = sizeof (SCF_CB); scf_cb.scf_type = SCF_CB_TYPE; scf_cb.scf_facility = DB_PSF_ID; scf_cb.scf_session = sess_cb->pss_sessid; scf_cb.scf_ptr_union.scf_sci = (SCI_LIST *) sci_list; scf_cb.scf_len_union.scf_ilength = 1; sci_list[0].sci_code = SCI_DBNAME; sci_list[0].sci_length = sizeof(dbname); sci_list[0].sci_aresult = (char *) dbname; sci_list[0].sci_rlength = NULL; status = scf_call(SCU_INFORMATION, &scf_cb); if (status != E_DB_OK) { err_code = scf_cb.scf_error.err_code; (VOID) psf_error(E_PS0D13_SCU_INFO_ERR, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); status = (status > E_DB_SEVERE) ? status : E_DB_SEVERE; return(status); } if (MEcmp((PTR)dbname, (PTR)DB_DBDB_NAME, sizeof(dbname))) { /* Session not connected to iidbdb */ err_code = E_US18D4_6356_NOT_DBDB; (VOID) psf_error(E_US18D4_6356_NOT_DBDB, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("CREATE/DROP SECURITY_ALARM ON DATABASE")-1, "CREATE/DROP SECURITY_ALARM ON DATABASE"); status=E_DB_ERROR; break; } if( !(sess_cb->pss_ustat & DU_USECURITY)) { err_code = E_US18D5_6357_FORM_NOT_AUTH; (VOID) psf_error(E_US18D5_6357_FORM_NOT_AUTH, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("CREATE/DROP SECURITY_ALARM")-1, "CREATE/DROP SECURITY_ALARM"); status=E_DB_ERROR; break; } } while(loop); if (status!=E_DB_OK) { /* ** Audit failure */ if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) { SXF_EVENT evtype; i4 msgid; if(alarm->dba_objtype==DBOB_DATABASE) evtype=SXF_E_DATABASE; else evtype=SXF_E_TABLE; if(psy_cb->psy_alflag&PSY_CALARM) msgid=I_SX202D_ALARM_CREATE; else msgid=I_SX202E_ALARM_DROP; local_status = psy_secaudit(FALSE, sess_cb, (char *)&alarm->dba_objname, (DB_OWN_NAME *)NULL, sizeof(alarm->dba_objname), evtype, msgid, SXF_A_CONTROL|SXF_A_FAIL, &e_error); } if(psy_cb->psy_alflag&PSY_CALARM) { /* ** Destroy query text for CREATE SECURITY_ALARM before ** returning */ DB_STATUS loc_status; QSF_RCB qsf_rb; qsf_rb.qsf_lk_state = QSO_EXLOCK; 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; /* Destroy query text - lock it first */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); loc_status = qsf_call(QSO_LOCK, &qsf_rb); if (loc_status != E_DB_OK) { psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (loc_status > status) status = loc_status; } loc_status = qsf_call(QSO_DESTROY, &qsf_rb); if (loc_status != E_DB_OK) { psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (loc_status > status) status = loc_status; } } return status; } /* Select the proper routine to process this request */ switch (psy_cb->psy_alflag & (PSY_CALARM | PSY_KALARM)) { case PSY_CALARM: status = psy_calarm(psy_cb, sess_cb); break; case PSY_KALARM: status = psy_kalarm(psy_cb, sess_cb); break; default: status = E_DB_SEVERE; err_code = E_PS0D49_INVALID_ALARM_OP; (VOID) psf_error(E_PS0D49_INVALID_ALARM_OP, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); break; } return (status); }