Example #1
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);
}
Example #2
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);
}
Example #3
0
/*
** Name: psl_lm5_setlockmode_distr()- perform semantic actions for SETLOCKMODE
**				      production.
**
** Description:
**	perform semantic action for SETLOCKMODE production in SQL
**	grammar for distributed thread.  SET LOCKMODE SESSION ... TIMEOUT
**	is handled by QEF in the distributed server by timing out on
**	queries to LDB; all other SET LOCKMODE ON TABLE options are sent
**	to QEF to pass on to LDB as text.
**
** Inputs:
**      sess_cb             ptr to a PSF session CB
**	    pss_distrib	    DB_3_DDB_SESS if distributed thread
**	    pss_stmt_flags  PSS_SET_LOCKMODE_SESS if SET LOCKMODE SESSION
**			    (distributed thread only)
**	scanbuf_ptr	    ptr into scanner buffer containing text of
**			    SET LOCKMODE statement
**      xlated_qry          For query text buffering
**
** Outputs:
**      err_blk             will be filled in if an error occurs
**
** Returns:
**      E_DB_{OK, ERROR}
**
** History:
**      5-mar-1991 (barbara)
**	    Extracted from 6.4 Star grammar for Sybil.
** 	4-dec-92 (barbara)
**	    If call to QEF fails, error has already been reported.  PSF must
**	    set psq_error (or SCF will complain); however, we want to avoid
**	    PSF retry so we also set PSQ_REDO to pretend we are already in
**	    server retry.
**	06-oct-93 (barbara)
**	    Fix for bug 53492.  SET LOCKMODE SESSION ... is now supported for
**	    options other than TIMEOUT.
*/
DB_STATUS
psl_lm5_setlockmode_distr(
	PSS_SESBLK  	*sess_cb,
	char		*scanbuf_ptr,
	PSS_Q_XLATE     *xlated_qry,
	PSQ_CB    	*psq_cb)
{
    QEF_RCB	*qef_rb;
    DB_STATUS	status;
    DB_ERROR	*err_blk = &psq_cb->psq_error;

    if (sess_cb->pss_distrib & DB_3_DDB_SESS)
    {
	qef_rb = (QEF_RCB *) sess_cb->pss_object;

	if (   sess_cb->pss_stmt_flags & PSS_SET_LOCKMODE_SESS
	    && qef_rb->qef_r3_ddb_req.qer_d14_ses_timeout != DMC_C_UNKNOWN)
	{
	    status = qef_call(QED_SES_TIMEOUT, ( PTR ) qef_rb);

	    if (DB_FAILURE_MACRO(status))
	    {
		err_blk->err_code = E_PS0001_USER_ERROR;
		/*
		** Make it appear as if query is already in retry so that
		** psq_call won't retry this failed statement.
		*/
		psq_cb->psq_flag |= PSQ_REDO;
		return(status);
	    }
	}

	else
	{
	    status = psq_x_add(sess_cb, (char *)scanbuf_ptr, &sess_cb->pss_ostream,
			 xlated_qry->pss_buf_size, &xlated_qry->pss_q_list,
			 (i4) ((char *) sess_cb->pss_endbuf - scanbuf_ptr),
			 " ", (char *) sess_cb->pss_endbuf, (char *) NULL,
			 err_blk);
		
	    if (DB_FAILURE_MACRO(status))
	    {
		return(status);
	    }

	    qef_rb->qef_r3_ddb_req.qer_d4_qry_info.qed_q4_pkt_p =
					    xlated_qry->pss_q_list.pss_head;
					    
	    if (~sess_cb->pss_stmt_flags & PSS_SET_LOCKMODE_SESS)
	    {
		status = qef_call(QED_QRY_FOR_LDB, ( PTR ) qef_rb);
	    }
	    else
	    {
		status = qef_call(QED_SET_FOR_RQF, ( PTR ) qef_rb);
	    }
	    if (DB_FAILURE_MACRO(status))
	    { 
		err_blk->err_code = E_PS0001_USER_ERROR;
		/*
		** Make it appear as if query is already in retry so that
		** psq_call won't retry this failed statement.
		*/
		psq_cb->psq_flag |= PSQ_REDO;
		return(status);
	    }
    	}

	/*
	** we are done; deallocate the memory as it will not be used by
	** anyone else
	*/
	status = psf_mclose(sess_cb, &sess_cb->pss_ostream, err_blk);

	if (DB_FAILURE_MACRO(status))
		return (status);

	/*
	** make sure psq_parseqry() realizes that the stream has been closed
	*/
	sess_cb->pss_ostream.psf_mstream.qso_handle = (PTR) NULL;
    }
    return (E_DB_OK);
}