Beispiel #1
0
/*{
** 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);
}
Beispiel #2
0
/*{
** 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);
}
Beispiel #3
0
/*{
** 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);
}
Beispiel #4
0
/*{
** 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);
}
Beispiel #5
0
/*{
** 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);
}
Beispiel #6
0
/*{
** 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);
}
Beispiel #7
0
/*{
** 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);
}
Beispiel #8
0
/*{
** 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 */
Beispiel #9
0
/*{
** 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 */
Beispiel #10
0
/*{
** 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);
}
Beispiel #11
0
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 */
}
Beispiel #12
0
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);
}
Beispiel #13
0
/*{
** 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 */
    }
}
Beispiel #14
0
/*{
** 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);
}
Beispiel #15
0
/*{
** 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);
}
Beispiel #16
0
/*{
** 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);
}
Beispiel #17
0
/*
** 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);
}
Beispiel #18
0
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);
}
Beispiel #19
0
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 */
Beispiel #20
0
/*{
** 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);
}
Beispiel #21
0
/*{
** 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);
}
Beispiel #22
0
/*{
** 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);
}
Beispiel #23
0
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);
}
Beispiel #24
0
/*{
** 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);
}
Beispiel #25
0
/*{
** 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);
}