Esempio n. 1
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);
}
Esempio n. 2
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);
}