예제 #1
0
/*{
** Name: QEA_PRC_INSERT                - Do insert for set input 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                 Delete current row of cursor action.
**      dsh
**      reset
**      state                   DSH_CT_INITIAL if this is an action call
**                              DSH_CT_CONTINUE for call back after processing
**                              a rule action list.
**
** Outputs:
**      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:
**      17-nov-92 (jhahn)
**          Created.
**	15-mar-93 (anitap)
**	    Prototyped.
**	15-mar-94 (jhahn)
**	    Made external.
**	06-mar-96 (nanpr01)
**	    Parameter change in qen_putIntoTempTable for passing the temp
**	    table page size.
**	13-Dec-2005 (kschendel)
**	    Inlined QEN_ADF changed to pointer, fix here.
*/
DB_STATUS
qea_prc_insert(
        QEF_AHD             *act,
	QEE_DSH		    *dsh,
        i4		    function,           /* Unused */
        i4                  state)              /* Unused */
{
    DB_STATUS          status  = E_DB_OK;
    PTR                *cbs = dsh->dsh_cbs;
    QEN_ADF            *qen_adf;
    ADE_EXCB           *ade_excb;

    qen_adf = act->qhd_obj.qhd_proc_insert.ahd_procparams;
    if (qen_adf != NULL)
    {
        /* Compute the actual parameters for this row of procedure
        ** call.
        */
        ade_excb = (ADE_EXCB *)cbs[qen_adf->qen_pos];
        ade_excb->excb_seg = ADE_SMAIN;
        status = ade_execute_cx(dsh->dsh_adf_cb, ade_excb);
        if (status != E_DB_OK)
        {
            status = qef_adf_error(&dsh->dsh_adf_cb->adf_errcb,
			    status, dsh->dsh_qefcb, &dsh->dsh_error);
            if (status != E_DB_OK)
                return (status);
        }
        return(qen_putIntoTempTable(dsh, act->qhd_obj.qhd_proc_insert.
                                     ahd_proc_temptable));
    }
    return(E_DB_OK);
}
예제 #2
0
/*
** Name: qeu_evraise
**
** Description:
**	This routine raises an event, it processes the external request
**	QEU_RAISE_EVENT, typically when raising the event associated with
**	a security alarm.
**
**	Note this *does* do event tracing (SET PRINTEVENTS/LOGEVENTS)
**	but does *not* do security checks/auditing on the operation, this
**	is assumed to be handled at a higher level.
**
** Inputs:
**	qef_rcb.evname   - Event name
**	qef_rcb.evowner  - Event owner
**	qef_rcb.evtext   - Event text 
**	qef_rcb.ev_l_text- Length of text
**
** History:
**	26-nov-93 (robf)
**         Created for secure 2.0
**	12-Jan-1998 (kinpa04/merja01)
**		Remove (i4) casting of session id.  This caused the 
**		session ID to get truncated on axp_osf while raising events.
**	10-Jan-2001 (jenjo02)
**	    We know this session's id; pass it to SCF.
**	30-Dec-2005 (kschendel)
**	    Update call to qef-adf-error.
**
*/
DB_STATUS
qeu_evraise(
	QEF_CB  *qef_cb,
	QEF_RCB *qef_rcb
)
{
    DB_DATA_VALUE tm;					/* Timestamp */
    DB_DATE	tm_date;
    SCF_ALERT	scfa;					
    SCF_CB	scf_cb;				
    SCF_SCI		sci_list[1];
    DB_ALERT_NAME alert;
    i4	err;
    char	*errstr;
    DB_STATUS   status=E_DB_OK;
    i4	tr1 = 0, tr2 = 0;			/* Dummy trace values */

    /*
    ** Build alert name
    */
    STRUCT_ASSIGN_MACRO(*qef_rcb->qef_evname, alert.dba_alert);
    STRUCT_ASSIGN_MACRO(*qef_rcb->qef_evowner, alert.dba_owner);

    scf_cb.scf_length	= sizeof(SCF_CB);
    scf_cb.scf_type	= SCF_CB_TYPE;
    scf_cb.scf_facility	= DB_QEF_ID;
    scf_cb.scf_session	= qef_cb->qef_ses_id;

    /* Get the database name */
    scf_cb.scf_ptr_union.scf_sci   = (SCI_LIST *) sci_list;
    scf_cb.scf_len_union.scf_ilength = 1;
    sci_list[0].sci_length  = sizeof(DB_DB_NAME);
    sci_list[0].sci_code    = SCI_DBNAME;
    sci_list[0].sci_aresult = (char *) &alert.dba_dbname;
    sci_list[0].sci_rlength = NULL;
    status = scf_call(SCU_INFORMATION, &scf_cb);
    if (status != E_DB_OK)
    {
         _VOID_ qef_error(E_QE022F_SCU_INFO_ERROR, 0L, status, &err,
			     &qef_rcb->error, 0);
	return E_DB_ERROR;
    }

    /* Format SCF event request block */
    scf_cb.scf_ptr_union.scf_alert_parms = &scfa;

    scfa.scfa_name = &alert;
    scfa.scfa_text_length = 0;
    scfa.scfa_user_text = NULL;
    scfa.scfa_flags = 0;

    if (qef_rcb->qef_ev_l_text > 0)		/* No need for empty strings */
    {
	if (qef_rcb->qef_ev_l_text > DB_EVDATA_MAX)
	    qef_rcb->qef_ev_l_text = DB_EVDATA_MAX;
	scfa.scfa_text_length = qef_rcb->qef_ev_l_text;
	scfa.scfa_user_text = qef_rcb->qef_evtext;
    }
    tm.db_datatype = DB_DTE_TYPE; 	/* Get time stamp for the event */
    tm.db_prec = 0;
    tm.db_length = sizeof(tm_date);
    tm.db_data = (PTR)&tm_date;
    tm.db_collID = -1;
    status = adu_datenow(qef_cb->qef_adf_cb, &tm);
    if (status != E_DB_OK)
    {
	    if ((status = qef_adf_error(&qef_cb->qef_adf_cb->adf_errcb,
			status, qef_cb, &qef_rcb->error)) != E_DB_OK)
		return (status);
    }
    scfa.scfa_when = &tm_date;

    /* If tracing and/or logging events then display event information */
    if (ult_check_macro(&qef_cb->qef_trace, QEF_T_EVENTS, &tr1, &tr2))
         qea_evtrace(qef_rcb, QEF_T_EVENTS, &alert, &tm, 
			(i4)qef_rcb->qef_ev_l_text,
			(char*)qef_rcb->qef_evtext);

    if (ult_check_macro(&qef_cb->qef_trace, QEF_T_LGEVENTS, &tr1, &tr2))
        qea_evtrace(qef_rcb, QEF_T_LGEVENTS, &alert, &tm, 0, (char *)NULL);

    /*
    ** Raise the event in SCF
    */
    status = scf_call(SCE_RAISE, &scf_cb);
    if (status != E_DB_OK)
    {
	char	*enm, *onm;	/* Event and owner names */

	enm = (char *)&alert.dba_alert;
	onm = (char *)&alert.dba_owner;
	errstr="RAISE";
	switch (scf_cb.scf_error.err_code)
	{
	  case E_SC0270_NO_EVENT_MESSAGE:
	    _VOID_ qef_error(E_QE019A_EVENT_MESSAGE, 0L, status, &err,
			     &qef_rcb->error, 1,
			     (i4)STlength(errstr), errstr);
	    break;
	  case E_SC0280_NO_ALERT_INIT:
	    _VOID_ qef_error(E_QE0200_NO_EVENTS, 0L, status, &err,
			     &qef_rcb->error, 1,
			     (i4)STlength(errstr), errstr);
	    break;
	  default:
	    _VOID_ qef_error(E_QE020F_EVENT_SCF_FAIL, 0L, status, &err,
			     &qef_rcb->error, 4,
			     (i4)STlength(errstr), errstr,
			     (i4)sizeof(i4),
					(PTR)&scf_cb.scf_error.err_code,
			     qec_trimwhite(DB_OWN_MAXNAME, onm), onm,
			     qec_trimwhite(DB_EVENT_MAXNAME, enm), enm);
	    break;
	}
	qef_rcb->error.err_code = E_QE0025_USER_ERROR;
	status = E_DB_ERROR;
    } /* If SCF not ok */
    return status;
}
예제 #3
0
/*{
** Name: QEA_RETROW - build a result row image for a database procedure
**
** Description:
**	This function is called to build a result row in a database 
**	procedure. Since the corresponding action can be contained in 
**	a loop (for, while or repeat), multiple rows may ultimately
**	be returned from one call to the procedure - one per call to 
**	this function. There may even be multiple return row action
**	headers in the same query plan, though they must all build
**	identically formatted result rows. 
**
**	Output buffer position tracking is a little different from the
**	usual GET tracking, partly because RETROW's can be interspersed
**	with various other actions in the row-producing DBP, and those
**	other actions may change the usual rowcount variables.
**	RETROW has three variables in the DSH that are used to track
**	the current buffer position.  "dsh_rpp_rowmax" is the number of
**	rows allows to be returned, as passed in from SCF;  this is
**	set upon (re)entry to the rowproc, although not when re-entering
**	QEF after a dependent rule/DBP re-parse/re-load.
**	When dsh_rowmax is set, the other two counters, dsh_rpp_rows and
**	dsh_rpp_bufs, are cleared.  "dsh_rpp_rows" counts rows emitted by
**	RETROW actions, and "dsh_rpp_bufs" counts output buffers used.
**	(The two are usually the same, but when blobs are around,
**	a single row might take up multiple output buffers.)
**	The top level of QEF (qeq_query) copies dsh_rpp_rows and
**	dsh_rpp_bufs back out to qef_rowcount and qef_count respectively,
**	just where SCF wants them.
**
**	The current output buffer could be computed from dsh_rpp_bufs,
**	but it's easier to track the next buffer to use in dsh_qef_nextout.
**	If dsh_qef_nextout isn't set yet, it must be the first row emitted
**	since SCF gave us a fresh set of output buffers, and we'll use
**	dsh_qef_output (i.e. qef_rcb->qef_output) for the first time.
**
**	Note that if the rowproc is interrupted back to SCF to load a
**	rule DBP, or for any reason other than "output buffer full",
**	SCF is careful to not mess with the output buffers.
**	There can only be one top-level row-producing procedure, so
**	there's no danger of anything else messing with the output
**	in progress.
**
**	NOTE: this function was cloned from qea_fetch. The differences in 
**	which "return row" actions are executed demanded a separation of
**	logic from qea_fetch.
**
**	Interestingly enough, the separation of rows emitted vs buffers
**	used ends up being rather strained, because SCF forgets to make the
**	distinction upon input!  We can make it work by checking the next-
**	buffer link rather than counting buffers.
**
** Inputs:
**      action				fetch action item
**      qef_rcb                         the qef request block
**	function			reset flags, not used
**
** Outputs:
**      dsh
**	    .dsh_rpp_rows		actual number of rows returned
**	    .dsh_rpp_bufs		number of buffers filled
**	    .dsh_qef_nextout		next output to use
**	    .dsh_error.err_code		one of the following
**				E_QE0000_OK
**				E_QE0017_BAD_CB
**				E_QE0018_BAD_PARAM_IN_CB
**				E_QE0019_NON_INTERNAL_FAIL
**				E_QE0002_INTERNAL_ERROR
**				E_QE0015_NO_MORE_ROWS
**	Returns:
**	    E_DB_{OK, WARN, ERROR, FATAL}
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**      28-oct-98 (inkdo01)
**          written
**	29-dec-03 (inkdo01)
**	    Changed reset parm to function.
**	28-feb-04 (inkdo01)
**	    Change qef_rcb parm to dsh in qeq_chk_resources call.
**	2-apr-04 (inkdo01)
**	    Fix to DSH changes (not updating output buffer list).
**	26-aug-04 (inkdo01)
**	    Add global base array support for return row results.
**	13-Aug-2005 (schka24)
**	    Rearrange output buffer tracking variables, revise comments
**	    to match current reality.
**	1-May-2006 (kschendel)
**	    Set blob base properly when doing global base arrays.
**	16-May-2010 (kschendel) b123565
**	    Caller must pass DSH to make parallel query + table procs
**	    work properly.
**	21-May-2010 (kschendel) b123775
**	    Delete unused sfinit segment test.
*/
DB_STATUS
qea_retrow(
QEF_AHD		*action,
QEF_RCB		*qef_rcb,
QEE_DSH		*dsh,
i4		function )
{
    QEF_CB	*qef_cb = qef_rcb->qef_cb;
    QEF_DATA	*output;
    i4 		bufs_used;
    DB_STATUS	status = E_DB_OK;
    QEN_ADF	*qen_adf;
    ADE_EXCB	*ade_excb;

#ifdef xDEBUG
    (VOID) qe2_chk_qp(dsh);
#endif

    /* Check if resource limits are exceeded by this query */
    if (action->qhd_obj.qhd_qep.ahd_estimates && (qef_cb->qef_fl_dbpriv &
        (DBPR_QROW_LIMIT | DBPR_QDIO_LIMIT | DBPR_QCPU_LIMIT |
        DBPR_QPAGE_LIMIT | DBPR_QCOST_LIMIT))
        )
    {
        if (qeq_chk_resource(dsh, action) != E_DB_OK)
	    return (E_DB_ERROR);
    }

    /* initialize the output buffer */
    qen_adf = action->qhd_obj.qhd_qep.ahd_current;
    ade_excb = (ADE_EXCB*) dsh->dsh_cbs[qen_adf->qen_pos];	

    /* Next output buffer to use is "nextout" unless it's not set yet. */
    output = dsh->dsh_qef_nextout;
    if (output == (QEF_DATA *)NULL)
	output = dsh->dsh_qef_output;

    bufs_used = 0;
    
    /* Materialize the row.  Usually just once around the FOR loop,
    ** unless something odd happens with blobs.
    */
    for (;;)
    {
	/* materialize row into output buffer.
	** Aim output row (uoutput) at caller supplied output buffer.
	** If there are blobs, tell adf that it's the blob area.
	*/
	ade_excb->excb_seg = ADE_SMAIN;
	ade_excb->excb_limited_base = ADE_NOBASE;
	if (qen_adf->qen_uoutput >= 0)
	{
	    if (qen_adf->qen_mask & QEN_HAS_PERIPH_OPND)
		ade_excb->excb_limited_base = qen_adf->qen_uoutput;
	    if (dsh->dsh_qp_ptr->qp_status & QEQP_GLOBAL_BASEARRAY)
	    {
		dsh->dsh_row[qen_adf->qen_uoutput] = output->dt_data;
	    }
	    else
	    {
		/* old-fashioned way, uoutput is local base, bias it
		** for blobs, set output pointer where old way wants it
		*/
		if (qen_adf->qen_mask & QEN_HAS_PERIPH_OPND)
		    ade_excb->excb_limited_base += ADE_ZBASE;
		ade_excb->excb_bases[ADE_ZBASE+qen_adf->qen_uoutput] =
							output->dt_data;
	    }
	    ade_excb->excb_size = output->dt_size;
	}

	/* process the tuples */

	status = ade_execute_cx(dsh->dsh_adf_cb, ade_excb);
	if (status != E_DB_OK)
	{
#ifdef xDEBUG
	    (VOID) qe2_chk_qp(dsh);
#endif
	    if ((status == E_DB_INFO) &&
			(dsh->dsh_adf_cb->adf_errcb.ad_errcode ==
				    E_AD0002_INCOMPLETE))
	    {
		/* Caught in mid-BLOB. */
		dsh->dsh_error.err_code = E_AD0002_INCOMPLETE;
		++ bufs_used;
		if (qen_adf->qen_uoutput >= 0)
		{
		    output->dt_size = ade_excb->excb_size;
		    ade_excb->excb_limited_base = ADE_NOBASE;
		    if (output->dt_next != NULL)
		    {
			output = output->dt_next;
			/* There's room left, loop back and output more */
			continue;
		    }
		}
		break;
	    }
	    else if ((status = qef_adf_error(
			&dsh->dsh_adf_cb->adf_errcb, status,
			qef_cb, &dsh->dsh_error)) != E_DB_OK)
	    {
		break;
	    }
	}
	bufs_used += 1;

	if (qen_adf->qen_uoutput >= 0)
	{
	    output->dt_size = ade_excb->excb_size;
	    ade_excb->excb_limited_base = ADE_NOBASE;
	}
	break;
    }

    /* Don't leave bogus error indication if we managed to fit it all */
    if (status == E_DB_OK)
	dsh->dsh_error.err_code = 0;

    /* Update counts, buffer addresses. */
    ++ dsh->dsh_rpp_rows;			/* Always just one row */
    dsh->dsh_rpp_bufs += bufs_used;
    dsh->dsh_qef_nextout = output->dt_next;
#ifdef xDEBUG
    (VOID) qe2_chk_qp(dsh);
#endif
    return (status);
}
예제 #4
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);
}
예제 #5
0
/*{
** Name: QEA_SAGG	- compute simple aggregate
**
** Description:
**      The routines in this file compute simple, scalar aggregates.
**  The basic algorithm is:
**	1) initialize the result relation
**	2) read tuples from the QEP
**	3) compute the aggregate for each tuple
**	4) move the result to its output location. 
**
**	Simple aggregate results are stored in a row buffer. The row buffer
**	used is in the qen_output field of the ahd_current QEN_ADF struct.
**        
**  The new implementation has a choice of two paths for aggregate processing.
**  If the involved aggregates are based on a simple table without a solo any
**  aggregate,they will invoke a special node called qen_origagg. 
**  The basic algorithm for this is:
**      1) initialize the result relation
**      2) call the node qen_origagg
**	3) move the result to its output location.
**
** Inputs:
**      action				QEA_SAGG action item
**
** Outputs:
**      qef_rcb
**	    .error.err_code		one of the following
**				E_QE0000_OK
**				E_QE0017_BAD_CB
**				E_QE0018_BAD_PARAM_IN_CB
**				E_QE0019_NON_INTERNAL_FAIL
**				E_QE0002_INTERNAL_ERROR
**				E_QE0015_NO_MORE_ROWS
**	Returns:
**	    E_DB_{OK, WARN, ERROR, FATAL}
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**      27-aug-86 (daved)
**          written
**	02-feb-88 (puree)
**	    add reset flag to the function arguments.
**	14-jul-93 (ed)
**	    replacing <dbms.h> by <gl.h> <sl.h> <iicommon.h> <dbdbms.h>
**	3-sep-93 (rickh)
**	    Flag the referential constraint state machine whether any
**	    rows qualified or not.  This is to support ALTER TABLE ADD
**	    REFERENTIAL CONSTRAINT.
**      14-jul-95 (ramra01)
**          Aggregate Otimization for Count(*) only. This is a forerunner
**          for the bit flags in OPF to indicate aggf optimzations for
**          count(*), min, max (Any or all of them) in a query with
**          restrictions.
**      21-aug-95 (ramra01)
**          Simple aggregate optimization extended to all functions 
**	    as long as it is against a base table.
**      01-nov-95 (ramra01)
**          count(*) optimize bypass adf calls only when it is the only
**          simple aggregate.
**	7-nov-95 (inkdo01)
**	    Changes to replace QEN_ADF structure instances by pointers in
**	    QEF_AHD structures.
**	19-feb-96 (inkdo01)
**	    Minor fix to optimize logic to avoid reference to ADF error
**	    buffer unless actually in optimize logic (fix for 74283).
**	15-mar-96 (pchang)
**	    Fixed regression to bug 73095.  An earlier fix was broken by changes
**	    made to enhance the processing of simple aggregate.  Specifically, 
**	    processing of simple aggregates is now carried out in DMF via
**	    qen_origagg() but the qef_remnull flag was not set after we 
**	    returned from the call to DMF.
**	29-oct-97 (inkdo01)
**	    Added code to support AHD_NOROWS flag (indicating no possible 
**	    rows from underlying query).
**	6-nov-97 (inkdo01)
**	    Add execution of ahd_constant code. SINIT/FINIT code must be 
**	    executed even if no rows are processed (because of ahd_constant).
**	28-aug-1998 (somsa01 for ocoro02)
**	    Bug 88218: Only set dmr_cb->dmr_count to 0 if node->qen_type
**	    = QE_ORIGAGG. Otherwise dmr_cb isn't initialised and causes a
**	    SEGV. Make sure in future dmr_cb is initialised if used outside
**	    the scope of QE_ORIGAGG.
**	2-jan-01 (inkdo01)
**	    Count optimization data ptr now addresses simple i4, not ADF_AG_STRUCT,
**	    with aggregate code improvements.
**	21-nov-03 (inkdo01)
**	    Add open_flag parm to qen_func calls for parallel query support.
**	29-dec-03 (inkdo01)
**	    DSH is now parameter, "function" replaces "reset".
**	16-feb-04 (inkdo01)
**	    Fix long term latent bug that produces bogus ADF errors.
**	28-feb-04 (inkdo01)
**	    Change qef_rcb parm to dsh in qeq_chk_resources call.
**	26-aug-04 (inkdo01)
**	    Support global base array for sagg result.
**	4-Jun-2009 (kschendel) b122118
**	    Minor dead code removal.
**	2-Dec-2010 (kschendel) SIR 124685
**	    Warning, prototype fixes.
*/
DB_STATUS
qea_sagg(
QEF_AHD		    *action,
QEF_RCB		    *qef_rcb,
QEE_DSH		    *dsh,
i4		    function )
{
    QEN_NODE	  *node = action->qhd_obj.qhd_qep.ahd_qep;
    bool	  reset = ((function & FUNC_RESET) != 0);
    DB_STATUS	  status;
    QEF_CB	  *qef_cb = dsh->dsh_qefcb;
    ADF_CB	  *adfcb = dsh->dsh_adf_cb;
    PTR		  *cbs	= dsh->dsh_cbs;
    QEN_ADF	  *qen_adf, *qen_adfconst;
    ADE_EXCB	  *ade_excb, *ade_excbconst;
    i4		  rowCount = 0;
    i4		  open_flag = (reset) ? (TOP_OPEN | function) : function;

    PTR           data = NULL;
    DMR_CB        *dmr_cb; 
    ADF_ERROR	  *adf_errcb;
    bool	  origagg = FALSE;
    i4  	  instr_cnt = 0;

    /* Check if resource limits are exceeded by this query */
    if (action->qhd_obj.qhd_qep.ahd_estimates && (qef_cb->qef_fl_dbpriv &
	(DBPR_QROW_LIMIT | DBPR_QDIO_LIMIT | DBPR_QCPU_LIMIT |
	 DBPR_QPAGE_LIMIT | DBPR_QCOST_LIMIT))
	)
    {
	if (qeq_chk_resource(dsh, action) != E_DB_OK)
	    return (E_DB_ERROR);
    }

    /* initialize the aggregate result */
    /* if there is no QEP, this will also create the result value */
    qen_adf		= action->qhd_obj.qhd_qep.ahd_current;
    ade_excb		= (ADE_EXCB*) cbs[qen_adf->qen_pos];	
    ade_excb->excb_seg	= ADE_SINIT;


    if (qen_adf->qen_uoutput > -1)
    {
	if (dsh->dsh_qp_ptr->qp_status & QEQP_GLOBAL_BASEARRAY)
	    dsh->dsh_row[qen_adf->qen_uoutput] = dsh->dsh_qef_output->dt_data;
	else
	    ade_excb->excb_bases[ADE_ZBASE + qen_adf->qen_uoutput] =
				dsh->dsh_qef_output->dt_data;
    }

    status = ade_execute_cx(adfcb, ade_excb);
    if (status != E_DB_OK)
    {
	if ((status = qef_adf_error(&adfcb->adf_errcb, status, 
	    qef_cb, &dsh->dsh_error)) != E_DB_OK)
	    return (status);
    }
    dsh->dsh_qef_remnull |= ade_excb->excb_nullskip;

    /* check for constant code */
    /* if there is some & it returns FALSE, skip to FINIT execution */
    qen_adfconst	= action->qhd_obj.qhd_qep.ahd_constant; 
    if (qen_adfconst)
    {
	ade_excbconst    = (ADE_EXCB*) cbs[qen_adfconst->qen_pos];
	ade_excbconst->excb_seg = ADE_SMAIN;
 
	/* process the constant expression */
	status = ade_execute_cx(adfcb, ade_excbconst);
	if (status != E_DB_OK)
	{
	    if ((status = qef_adf_error(&adfcb->adf_errcb,
			status, qef_cb, &dsh->dsh_error)) != E_DB_OK)
	     return (status);
	}
	/* handle the condition where the qualification failed */
	if (ade_excbconst->excb_value != ADE_TRUE)
	    goto finitit;
    }

    ade_countstar_loc( adfcb, ade_excb, &data, &instr_cnt);
    ade_excb->excb_seg	= ADE_SMAIN;
    /* get the rows */
    if (node)
    {
	origagg = (node->qen_type == QE_ORIGAGG);
	if (origagg)
        {
            dmr_cb = (DMR_CB*) cbs[node->node_qen.qen_orig.orig_get];
	    dmr_cb->dmr_agg_excb = (PTR) ade_excb; 
	    dmr_cb->dmr_agg_flags = 0;
	    dmr_cb->dmr_qef_adf_cb = (PTR) adfcb;
	    if (action->qhd_obj.qhd_qep.ahd_qepflag & AHD_CSTAROPT)
            {
	        dmr_cb->dmr_agg_flags |= DMR_AGLIM_COUNT;
	    }
	    if (node->node_qen.qen_orig.orig_flag & ORIG_MAXOPT)
	    {
	        dmr_cb->dmr_agg_flags |= DMR_AGLIM_MAX;
	    }
	    if (node->node_qen.qen_orig.orig_flag & ORIG_MINOPT)
	    {
	        dmr_cb->dmr_agg_flags |= DMR_AGLIM_MIN;
	    }
        }
	for (;;)
	{
	    /* fetch rows or call spl node for aggf optim */
	    if (action->qhd_obj.qhd_qep.ahd_qepflag & AHD_NOROWS)
	    {
		/* Negative syllogism assures no rows. */
		status = E_DB_WARN;
		dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS;
		if (origagg)
		    dmr_cb->dmr_count = 0;	/* just to be safe */
	    }
	    else
		status = (*node->qen_func)(node, qef_rcb, dsh, open_flag);
	    open_flag &= ~(TOP_OPEN | FUNC_RESET);

	    if (status != E_DB_OK)
	    {
		if (!origagg)	/* first, handle errors for non-ORIGAGG */
		{
	            if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS)
			break; 	/* end of scan, exit read loop */
		    else return(status);
		}

	        if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS)
		{
		    if (dmr_cb->dmr_agg_flags & DMR_AGLIM_COUNT && data)
		    {
                        *((i4 *)data) = dmr_cb->dmr_count;
		    }
                    rowCount = dmr_cb->dmr_count;
		    dsh->dsh_qef_remnull |= ade_excb->excb_nullskip;
		    break;
		}
                if (dsh->dsh_error.err_code == E_DM0167_AGG_ADE_EXCEPTION ||
            	    dsh->dsh_error.err_code == E_DM0166_AGG_ADE_FAILED)
                {
		    adf_errcb = (ADF_ERROR *)&adfcb->adf_errcb;
		    if ((adf_errcb->ad_errclass == ADF_INTERNAL_ERROR)  ||
			(adf_errcb->ad_errclass == ADF_USER_ERROR) ||
			(adf_errcb->ad_errclass == ADF_EXTERNAL_ERROR) )
		    {
                	if ((status = qef_adf_error(&adfcb->adf_errcb, status,
				qef_cb, &dsh->dsh_error)) != E_DB_OK)
			  return (status);
		    }
                }              
		    
		return (status);
	    }
            /* From the comment below this applies only for the select  */  
            /* any constraint and should not apply to agg optim         */

	    rowCount++;

	    if (data && instr_cnt == 1)
            {
                *((i4 *)data) += 1;
	    }
            else
            { 
		/* process the aggregate */
		status = ade_execute_cx(adfcb, ade_excb);
		if (status != E_DB_OK)
		{
		    if ((status = qef_adf_error(&adfcb->adf_errcb, 
				status, qef_cb, &dsh->dsh_error)) != E_DB_OK)
			return (status);
		}
            }
	    dsh->dsh_qef_remnull |= ade_excb->excb_nullskip;
	    /* if solo any aggregate, stop */
	    if (action->qhd_obj.qhd_qep.ahd_qepflag & AHD_ANY)
		break;
	}
	
    }
    else
    {
	/* process the aggregate */
	status = ade_execute_cx(adfcb, ade_excb);
	if (status != E_DB_OK)
	{
	    if ((status = qef_adf_error(&adfcb->adf_errcb, 
		status, qef_cb, &dsh->dsh_error)) != E_DB_OK)
		return (status);
	}
	dsh->dsh_qef_remnull |= ade_excb->excb_nullskip;
    }
    /* move the result to the result location */

finitit:		/* come from ahd_constant = FALSE */
    ade_excb->excb_seg	= ADE_SFINIT;
    status = ade_execute_cx(adfcb, ade_excb);
    if (status != E_DB_OK)
    {
	if ((status = qef_adf_error(&adfcb->adf_errcb, status, 
		qef_cb, &dsh->dsh_error)) != E_DB_OK)
	    return (status);
    }

    /*
    ** The ALTER TABLE ADD CONSTRAINT state machine for RERERENTIAL CONSTRAINTS
    ** cooks up a SELECT ANY( 1 ) statement.  Subsequent states in that
    ** machine need to know whether the SELECT returned 1 or 0 rows.  The
    ** following code flags that piece of information in the session control
    ** block.
    */

    if ( qef_cb->qef_callbackStatus & QEF_EXECUTE_SELECT_STMT )
    {
	if ( rowCount > 0 )
	{   qef_cb->qef_callbackStatus |= QEF_SELECT_RETURNED_ROWS; }
	else {  qef_cb->qef_callbackStatus &= ~( QEF_SELECT_RETURNED_ROWS ); }
    }

    return (E_DB_OK);
}