예제 #1
0
/*{
** Name: QEU_CLOSE      - close an opened table
**
** External QEF call:       status = qef_call(QEU_CLOSE, &qeu_cb);
**
** Description:
**      Close a table opened through the QEU_OPEN command. 
**
** Inputs:
**      qeu_cb
**	    .qeu_eflag			    designate error handling semantis
**					    for user errors.
**		QEF_INTERNAL		    return error code.
**		QEF_EXTERNAL		    send message to user.
**          .qeu_acc_id			    table access id
**
** Outputs:
**      qeu_cb
**          .error.err_code                 One of the following
**                                          E_QE0000_OK
**                                          E_QE0002_INTERNAL_ERROR
**                                          E_QE0004_NO_TRANSACTION
**                                          E_QE0007_NO_CURSOR
**                                          E_QE0017_BAD_CB
**                                          E_QE0018_BAD_PARAM_IN_CB
**      Returns:
**          E_DB_OK
**          E_DB_ERROR                      caller error
**          E_DB_FATAL                      internal error
**      Exceptions:
**          none
**
** Side Effects:
**          none
**
** History:
**      27-may-86 (daved)
**          written
**	14-may-87 (daved)
**	    zero the access id to cause an error in DMF if a table is
**	    closed twice.
*/
DB_STATUS
qeu_close(
QEF_CB      *qef_cb,
QEU_CB      *qeu_cb)
{
    i4     err;
    DMT_CB      dmt_cb;
    DB_STATUS   status;

    /* QEU_CLOSE is only valid in a transaction */
    if (qef_cb->qef_stat == QEF_NOTRAN)
    {
        qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err,
            &qeu_cb->error, 0);
        return (E_DB_ERROR);
    }
    MEfill(sizeof(DMT_CB), 0, (PTR) &dmt_cb);
    dmt_cb.type         = DMT_TABLE_CB;
    dmt_cb.length       = sizeof(DMT_CB);
    dmt_cb.dmt_flags_mask   = 0;
    dmt_cb.dmt_record_access_id = qeu_cb->qeu_acc_id;
    status = dmf_call(DMT_CLOSE, &dmt_cb);
    if (status != E_DB_OK)
    {
        qef_error(dmt_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0);
    }
    else
	qef_cb->qef_open_count--;
    qeu_cb->qeu_acc_id = (PTR) NULL;
    return (status);
}
예제 #2
0
파일: qearupd.c 프로젝트: saqibjamil/Ingres
/*
** {
** Name: QEA_RUPDATE		- update the current cursor
**
**  External QEF call:	    status = qef_call(QEQ_REPLACE, &qef_rcb);
**
** Description:
**      The current row in the named cursor (QP) is
**  updated and sent to DMF 
**
** Inputs:
**	action			Update current row of cursor action.
**      qef_rcb
**	assoc_dsh		DSH for QP for cursor to be updated.
**	reset
**	state			DSH_CT_INITIAL if this is an action call
**				DSH_CT_CONTINUE for call back after processing
**				a rule action list.
**
** Outputs:
**      qef_rcb
**	    .qef_remnull	SET if an aggregate computation found a NULL val
**	    .qef_rowcount	number of rows replaced
**	    .qef_targcount	number of attempted replaces 
**	    .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_QE0008_CURSOR_NOT_OPENED
**				E_QE0021_NO_ROW
**				E_QE0009_NO_PERMISSION
**				E_QE000A_READ_ONLY
**				E_QE0012_DUPLICATE_KEY
**				E_QE0010_DUPLIATE_ROW
**				E_QE0011_AMBIGUOUS_REPLACE
**				E_QE0013_INTEGRITY_FAILED
**				E_QE0024_TRANSACTION_ABORTED
**				E_QE0034_LOCK_QUOTA_EXCEEDED
**				E_QE0035_LOCK_RESOURCE_BUSY
**				E_QE0036_LOCK_TIMER_EXPIRED
**				E_QE002A_DEADLOCK
**	Returns:
**	    E_DB_{OK,WARN,ERROR,FATAL}
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	11-JUN-86 (daved)
**          written
**	22-may-87 (daved)
**	    catch cursor not positioned errors
**	14-oct-87 (puree)
**	    make sure that qen_error is called in case of E_DB_ERROR from
**	    qeq_validate.
**	02-feb-88 (puree)
**	    added reset flag to qeq_validate and all qea_xxxx call sequence.
**	29-aug-88 (puree)
**	    implement replace cursor by tid if the cursor was position on
**	    a secondary index table and by current position if the cursor
**	    is positioned on the base table.
**	    fix duplicate handling error.
**	12-oct-88 (puree)
**	    If a table validation fails during cursor replace, abort the
**	    cursor.
**	23-feb-89 (paul)
**	    Clean up qef_cb state before returning.
**	17-apr-89 (paul)
**	    Processing cursor updates integrated into qeq_query. Update cursor
**	    logic moved from qeq.c to this file (qearupd.c). This routine is
**	    a simplified version of what was previously called qeq_replace.
**	25-sep-89 (paul)
**	    Added support for using TIDs as parameters to procedures invoked
**	    from rules.
**	25-jan-90 (nancy) -- set status to E_DB_OK when replace cursor
**	    causes dups and duplicate handling is set to SKIP_DUPS.
**	29-jan-90 (nancy) -- fix bug 8388 (8575), use assoc dsh for replace
**	    by tid.
**	29-jun-90 (davebf)
**	    Handle rows which were accessed by TID only  (bug 31113)
**       5-Nov-1993 (fred)
**          Remove any remaining large object temporaries.
**       7-Apr-1994 (fred)
**          Commented out large object removal pending better way...
**	7-nov-95 (inkdo01)
**	    Changes to replace QEN_ADF structure instances by pointers in
**	    QEF_AHD structures.
**	29-dec-03 (inkdo01)
**	    DSH is now parameter, "function" replaces "reset".
**	5-feb-04 (inkdo01)
**	    Add support for partitioned tables.
**	12-mar-04 (inkdo01)
**	    Fix to handle bigtids on byte-swapped machines.
**	19-mar-04 (inkdo01)
**	    Fix for bigtids and rules.
**	12-may-04 (inkdo01)
**	    Call qeq_part_open unconditionally - it'll determine whether
**	    partition cbs are already prepared.
**	8-Jul-2004 (schka24)
**	    Still some tid byte-ordering confusion on x86, make tid handling
**	    more portable.
**	26-aug-04 (inkdo01)
**	    Add global base array support for update buffer.
**	24-Feb-05 (hweho01)
**	    The copying of tid needs to be handled differently if   
**          TID_SWAP is defined, so the tid value can be preserved. 
**          Star #13864021.
**	28-Feb-2005 (schka24)
**	    Rework the above fix, it turns out that the underlying problem
**	    was the 4byte-tidp flag not getting set.  Now that it's set
**	    properly, obey it here.  Also, do partition opens against the
**	    cursor query, not the RUP -- it's the one with the valid list..
**	18-Jul-2005 (schka24)
**	    Well, I fixed by-tid updates, but not true in-place updates!
**	    Use new ahd_ruporig machinery to get at the current partition
**	    number for in-place updating.
**	13-Dec-2005 (kschendel)
**	    Can count on qen-ade-cx now.
**	16-Jan-2006 (kschendel)
**	    Access qen-status thru xaddrs.
**	20-june-06 (dougi)
**	    Add support for BEFORE triggers.
**	1-Nov-2006 (kschendel)
**	    Some fixes to BEFORE triggers, make sure things are set up.
**	7-mar-2007 (dougi)
**	    Slight change to address the DMR_CB (broken by BEFORE changes).
**	8-Sep-2008 (kibro01) b120693
**	    Remove unused action parameter from qeq_part_open
**	09-Sep-2009 (thaju02) B122374
**	    If BEFORE trigger has been executed, do not use ahd_upd_colmap.
**	    ahd_upd_colmap may not reflect cols updated by the rule/proc.
**	15-Jan-2010 (jonj)
**	    SIR 121619 MVCC: If E_DM0029_ROW_UPDATE_CONFLICT returned,
**	    invalidate the QP and retry.
**	1-Jul-2010 (kschendel) b124004
**	    Minor changes for RUP from scrollable keyset cursors;  the
**	    fetched row is always in dsh-qef-output.
*/
DB_STATUS
qea_rupdate(
QEF_AHD		    *act,
QEF_RCB		    *qef_rcb,
QEE_DSH		    *dsh,
QEE_DSH		    *assoc_dsh,
i4		    function,
i4		    state )
{
    i4		err;
    DB_STATUS		status	= E_DB_OK;
    QEF_CB		*qef_cb = dsh->dsh_qefcb;
    ADF_CB		*adfcb = dsh->dsh_adf_cb;
    DMR_CB		*dmr_cb, *pdmr_cb;
    QEN_ADF		*qen_adf;
    ADE_EXCB		*ade_excb;
    PTR			*assoc_cbs = assoc_dsh->dsh_cbs;
    PTR			output, save_addr;
    char		*tidinput;  /* location of tid */
    DB_TID8		oldbigtid, newbigtid;
    u_i2		oldpartno = 0;
    u_i2		newpartno = 0;
    i4			odmr_cb_ix;	/* CB number of DMR_CB */
    i4			orig_node;
    
    status = E_DB_OK;
    
    for (;;)
    {
	/* A cursor update affects only a single row. If we are called back  */
	/* after rules processing simply return. */
	if (state == DSH_CT_CONTINUE)
	    break;

	/* Address the DMR_CB used to access the row.  The odmr_cb_ix is in
	** the associated (cursor) QP context.  We'll adjust for partitioning
	** a bit later.
	*/
	odmr_cb_ix = act->qhd_obj.qhd_qep.ahd_odmr_cb;
	dmr_cb = (DMR_CB*) assoc_cbs[odmr_cb_ix];
	if (status == DSH_CT_CONTINUE3)
	{
	    /* Resuming from a BEFORE trigger, reset variables */
	    MEcopy(dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_tid],
			sizeof(DB_TID8), (PTR) &newbigtid);
	    MEcopy(dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_tid],
			sizeof(DB_TID8), (PTR) &oldbigtid);
	    oldpartno = oldbigtid.tid.tid_partno;
	    newpartno = newbigtid.tid.tid_partno;
	    output = dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_row];
	    if (act->qhd_obj.qhd_qep.ahd_part_def != NULL)
		dmr_cb = (DMR_CB *) assoc_cbs[odmr_cb_ix + oldpartno + 1];
	}
	else
	{
	    /* Normal path */
	    dsh->dsh_qef_remnull = 0;
	    dsh->dsh_qef_rowcount = 0;

	    /* Use fetch row for holding update row if need be */
	    output = assoc_dsh->dsh_row[assoc_dsh->dsh_qp_ptr->qp_fetch_ahd->qhd_obj.qhd_qep.ahd_ruprow];

	    /* make sure we have a positioned record */
	    if (assoc_dsh->dsh_positioned == FALSE)
	    {
		/* no record could be valid in this action's updatable control block.
		** Nor do we know what we will be looking at when we access the
		** update control block index number
		*/
		dsh->dsh_error.err_code = E_QE0021_NO_ROW;
		status = E_DB_ERROR;
		break;
	    }

	    /* check that this query plan has update privilege */
	    if ((assoc_dsh->dsh_qp_ptr->qp_status & QEQP_UPDATE) == 0)
	    {
		/* no permission */
		dsh->dsh_error.err_code = E_QE0009_NO_PERMISSION;
		status = E_DB_ERROR;
		break;
    	    }

	    if (qef_cb->qef_c1_distrib & DB_3_DDB_SESS)	/* distributed? */
	    {
		/* DDB processing */

		status = qeq_c5_replace(qef_rcb, dsh);
		if (status == E_DB_OK)
		    dsh->dsh_qef_rowcount = 1;
		else
		    dsh->dsh_qef_rowcount = 0;
		return(status);
	    }

	    /* LDB processing */

	    /* process the qualification expression */
	    qen_adf     = act->qhd_obj.qhd_qep.ahd_constant;
	    if (qen_adf != NULL)
	    {
		ade_excb = (ADE_EXCB*) dsh->dsh_cbs[qen_adf->qen_pos];
		if (dsh->dsh_qp_ptr->qp_status & QEQP_GLOBAL_BASEARRAY)
		    dsh->dsh_row[qen_adf->qen_uoutput] = output;
		else ade_excb->excb_bases[ADE_ZBASE + qen_adf->qen_uoutput] = output;
		status = qen_execute_cx(dsh, ade_excb);
		if (status != E_DB_OK)
		    break;

		/* handle condition where qualification failed. */
		if (ade_excb->excb_value != ADE_TRUE)
		{
		    dsh->dsh_qef_targcount = 1;
		    dsh->dsh_qef_rowcount = 0;
		    break;
		}
	    }

	    /* REPLACE THE TUPLE
	    ** if the cursor is positioned on the base table (ahd_tidoffset is
	    ** -1), replace the tuple at the current position.  Otherwise the
	    ** cursor must have been positioned via a secondary index.  Get
	    ** the tid, re-fetch the original row by tid, and replace the
	    ** base table tuple by the tid.
	    */

	    if (act->qhd_obj.qhd_qep.ahd_tidoffset == -1)
	    {
		/* If partitioned, dig the current partition number out of
		** the node status for the orig (or kjoin/tjoin) node that
		** fetched the row in the first place.  OPC has kindly put
		** the node number of same into ahd_ruporig.
		*/
		if (act->qhd_obj.qhd_qep.ahd_part_def != NULL)
		{
		    orig_node = act->qhd_obj.qhd_qep.ahd_ruporig;
		    if (orig_node == -1)
		    {
			TRdisplay("%@ qea_rupd: missing ahd_ruporig\n");
			dsh->dsh_error.err_code = E_QE0002_INTERNAL_ERROR;
			status = E_DB_ERROR;
			break;
		    }
		    oldpartno = assoc_dsh->dsh_xaddrs[orig_node]->
						qex_status->node_ppart_num;
		    dmr_cb = (DMR_CB *) assoc_cbs[odmr_cb_ix + oldpartno + 1];
		}
		dmr_cb->dmr_flags_mask = DMR_CURRENT_POS;
	    }
	    else
	    {
		/* set the tid */
		tidinput  = 
		    (char *) assoc_dsh->dsh_row[act->qhd_obj.qhd_qep.ahd_tidrow]
				 + act->qhd_obj.qhd_qep.ahd_tidoffset;

		if (act->qhd_obj.qhd_qep.ahd_qepflag & AHD_4BYTE_TIDP)
		{
		    I4ASSIGN_MACRO(*tidinput, oldbigtid.tid_i4.tid );
		    oldbigtid.tid_i4.tpf = 0;
		}
		else
		{
		    I8ASSIGN_MACRO(*tidinput, oldbigtid);
		}
		oldpartno = oldbigtid.tid.tid_partno;
		newpartno = oldpartno;
	
		/* Check for partitioning and set up DMR_CB. */
		if (act->qhd_obj.qhd_qep.ahd_part_def)
		{
		    /* Open against "get" action.  The RUP action dmtix and
		    ** flags are the same as the cursor's, thanks to OPC.
		    */
		    status = qeq_part_open(qef_rcb, assoc_dsh, NULL, 0, 
			odmr_cb_ix,
			act->qhd_obj.qhd_qep.ahd_dmtix, oldpartno);
			
		    if (status != E_DB_OK)
		    {
			dsh->dsh_error.err_code = assoc_dsh->dsh_error.err_code;
			return(status);
		    }
		    pdmr_cb = (DMR_CB *)assoc_cbs[odmr_cb_ix + oldpartno+1];

		    STRUCT_ASSIGN_MACRO(dmr_cb->dmr_data, pdmr_cb->dmr_data);
		    dmr_cb = pdmr_cb;
		}
		dmr_cb->dmr_tid = oldbigtid.tid_i4.tid;
		dmr_cb->dmr_flags_mask = DMR_BY_TID;
	
		/* get the tuple to be updated. */
		save_addr = dmr_cb->dmr_data.data_address;
		dmr_cb->dmr_data.data_address = output;
		status = dmf_call(DMR_GET, dmr_cb);
		dmr_cb->dmr_data.data_address = save_addr;
		if (status != E_DB_OK)
		{
		    dsh->dsh_error.err_code = dmr_cb->error.err_code;
		    return (status);
		}
	    }

	    /* If we have rules, save a copy of the row before updating */
	    if (act->qhd_obj.qhd_qep.ahd_after_act != NULL ||
		act->qhd_obj.qhd_qep.ahd_before_act != NULL)
	    {
		MEcopy(output, act->qhd_obj.qhd_qep.ahd_repsize,
		    dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_row]);
		oldbigtid.tid_i4.tpf = 0;
		oldbigtid.tid_i4.tid = dmr_cb->dmr_tid;
		oldbigtid.tid.tid_partno = oldpartno;
	    }

	    /* process the update expression */
	    qen_adf     = act->qhd_obj.qhd_qep.ahd_current;
	    ade_excb    = (ADE_EXCB*) dsh->dsh_cbs[qen_adf->qen_pos];	
	    if (dsh->dsh_qp_ptr->qp_status & QEQP_GLOBAL_BASEARRAY)
		dsh->dsh_row[qen_adf->qen_uoutput] = output;
	    else ade_excb->excb_bases[ADE_ZBASE+qen_adf->qen_uoutput] = output;

	    status = qen_execute_cx(dsh, ade_excb);
	    if (status != E_DB_OK)
		break;

	    /* Check for partitioning and see if we changed target partition. */
	    if (act->qhd_obj.qhd_qep.ahd_part_def && 
		(act->qhd_obj.qhd_qep.ahd_qepflag & AHD_PCOLS_UPDATE))
	    {
		status = adt_whichpart_no(adfcb,
			act->qhd_obj.qhd_qep.ahd_part_def, 
			output, &newpartno);
		if (status != E_DB_OK)
		    return(status);
	    }
	    /* Process BEFORE triggers (if any). */
	    if (act->qhd_obj.qhd_qep.ahd_before_act != NULL)
	    {
		/*
		** Place the TID in a known location so it can be used
		** as a parameter to the procedure fired by the rule.
		*/
		newbigtid.tid_i4.tpf = 0;
		newbigtid.tid_i4.tid = dmr_cb->dmr_tid;
		newbigtid.tid.tid_partno = newpartno;
		MEcopy ((PTR)&newbigtid, sizeof(DB_TID8),
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_tid]);   
		MEcopy ((PTR)&oldbigtid, sizeof(DB_TID8),
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_tid]);   

		MEcopy(output, act->qhd_obj.qhd_qep.ahd_repsize,
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_row]);
		dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_ptr = act;
		dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_status =
			DSH_CT_CONTINUE3;
		dsh->dsh_depth_act++;
		dsh->dsh_act_ptr = act->qhd_obj.qhd_qep.ahd_before_act;
		dsh->dsh_error.err_code = E_QE0120_RULE_ACTION_LIST;
		status = E_DB_ERROR;
		break;
	    }
	}    /* end of !DSH_CT_CONTINUE3 */

	state = DSH_CT_INITIAL;			/* signal resumption after
						** BEFORE trigger */

	if (act->qhd_obj.qhd_qep.ahd_qepflag & AHD_PCOLS_UPDATE &&
		oldpartno != newpartno)
	{
	    /* Partition has changed for row in partitioned table.
	    ** Delete from 1st partition and insert into next.
	    ** We have to hope that DMF can keep it all straight.
	    */
	    status = dmf_call(DMR_DELETE, dmr_cb);
	    if (status != E_DB_OK)
	    {
		if (dmr_cb->error.err_code == E_DM0055_NONEXT)
		    dsh->dsh_error.err_code = 4599;
		else
		    dsh->dsh_error.err_code = dmr_cb->error.err_code;
		break;
	    }

	    /* Get output partition DMR_CB, then do DMR_PUT.
	    ** Don't change the fetching DSH's current dmr-cb in case
	    ** we're running a true in-place cursor.
	    */
	    status = qeq_part_open(qef_rcb, assoc_dsh, NULL, 0, 
		odmr_cb_ix,
		act->qhd_obj.qhd_qep.ahd_dmtix, newpartno);
			
	    if (status != E_DB_OK)
	    {
		dsh->dsh_error.err_code = assoc_dsh->dsh_error.err_code;
		return(status);
	    }
	    dmr_cb = (DMR_CB *)assoc_cbs[odmr_cb_ix + newpartno+1];

	    dsh->dsh_qef_targcount = 1;
	    /* Final preparation of new partition DMR_CB. */
	    dmr_cb->dmr_flags_mask = 0;
	    dmr_cb->dmr_val_logkey = 0;
	    dmr_cb->dmr_data.data_address = output;
	    dmr_cb->dmr_data.data_in_size  =
				act->qhd_obj.qhd_qep.ahd_repsize;
	    if (act->qhd_obj.qhd_qep.ahd_duphandle != QEF_SKIP_DUP)
		dmr_cb->dmr_flags_mask |= DMR_DUP_ROLLBACK;
	    status = dmf_call(DMR_PUT, dmr_cb);

	}
	else
	{
	    dsh->dsh_qef_targcount = 1;
	    if ((act->qhd_obj.qhd_qep.ahd_upd_colmap) && 
		(act->qhd_obj.qhd_qep.ahd_before_act == NULL))
		dmr_cb->dmr_attset = 
			(char *)act->qhd_obj.qhd_qep.ahd_upd_colmap;
	    else
		dmr_cb->dmr_attset = (char *)0;

	    if (act->qhd_obj.qhd_qep.ahd_duphandle != QEF_SKIP_DUP)
		dmr_cb->dmr_flags_mask |= DMR_DUP_ROLLBACK;
	    status = dmf_call(DMR_REPLACE, dmr_cb);
	}
	    
	if (status == E_DB_OK || 
		((dmr_cb->error.err_code == E_DM0046_DUPLICATE_RECORD ||
		  dmr_cb->error.err_code == E_DM0045_DUPLICATE_KEY    ||
		  dmr_cb->error.err_code == E_DM0048_SIDUPLICATE_KEY) &&
		 act->qhd_obj.qhd_qep.ahd_duphandle == QEF_SKIP_DUP))
	{
	    if (status == E_DB_OK)
	    {
	    	dsh->dsh_qef_rowcount = 1;
		/* Look for rules to apply */
		if (act->qhd_obj.qhd_qep.ahd_after_act != NULL)
		{
		    /*
		    ** Place the TID in a known location so it can be used
		    ** as a parameter to the procedure fired by the rule.
		    */
		    newbigtid.tid_i4.tpf = 0;
		    newbigtid.tid_i4.tid = dmr_cb->dmr_tid;
		    newbigtid.tid.tid_partno = newpartno;
		    MEcopy ((PTR)&newbigtid, sizeof(DB_TID8),
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_tid]);   
		    MEcopy ((PTR)&oldbigtid, sizeof(DB_TID8),
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_tid]);   

		    MEcopy(output, act->qhd_obj.qhd_qep.ahd_repsize,
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_row]);
		    dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_ptr = act;
		    dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_status =
			DSH_CT_CONTINUE;
		    dsh->dsh_depth_act++;
		    dsh->dsh_act_ptr = act->qhd_obj.qhd_qep.ahd_after_act;
		    dsh->dsh_error.err_code = E_QE0120_RULE_ACTION_LIST;
		    status = E_DB_ERROR;
		    break;
		}
	    }
	    else
	    {
		dsh->dsh_qef_rowcount = 0;
		status = E_DB_OK;
	    }	
	    break;	    
	}
	
	if (dmr_cb->error.err_code == E_DM0055_NONEXT)
	    dsh->dsh_error.err_code = 4599;
	else
	if ( dmr_cb->error.err_code == E_DM0029_ROW_UPDATE_CONFLICT )
	{
	    dsh->dsh_qp_status |= DSH_QP_OBSOLETE;
	    dsh->dsh_error.err_code = E_QE0023_INVALID_QUERY;
	    status = E_DB_WARN;
	}
	else
	    dsh->dsh_error.err_code = dmr_cb->error.err_code;
	break;
    }

    return (status);
}
예제 #3
0
/*{
** Name: qeu_cevent 	- Store event information for one event.
**
** External QEF call:   status = qef_call(QEU_CEVENT, &qeuq_cb);
**
** Description:
**	Add the event tuple and the event query text to the appropriate
**	tables (iievent and iiqrytext).
**
**	Most of the event tuple was filled by the parser from the CREATE EVENT
**	statement, except that since this is the first access to iievent,
**	the uniqueness of the event name (within the current user scope) is
**	validated here.  First, all events that have the same name and
**	owner are fetched (the iievent table is hashed on name and owner
**	so this is a singleton keyed retrieval).  If there are any then
**	the event is a duplicate and an error is returned.  If this is
**	unique then the event is entered into iievent.
**
**	To allow permissions to apply to events, an event tuple includes
**	a "dummy table id" (much like database procedures).  This id is
**	retrieved from DMU_GET_TABID.
**
**	An internal qrytext id (time-stamp) is created and all the qrytext
**	tuples associated with the event are entered into iiqrytext.
**	Note that the size of CREATE EVENT query text is never likely to
**	be more than one iiqrytext tuple, but the code allows more than
**	one tuple in case a WITH clause is added in the future (extending
**	the length of the statement).
**
**	The current "create date" is retrieved from ADF (using date("now")).
**
** Inputs:
**      qef_cb                  QEF session control block
**      qeuq_cb
**	    .qeuq_eflag	        Designate error handling for user errors.
**		QEF_INTERNAL	Return error code.
**		QEF_EXTERNAL	Send message to user.
**	    .qeuq_cq		Number of query text tuples.
**	    .qeuq_qry_tup	Query text tuples.
**	    .qeuq_culd		Number of event tuples.  Must be 1.
**	    .qeuq_uld_tup	Event tuple:
**		.dbe_name	Event name.
**		.dbe_owner	Event owner.
**		.dbe_type	Event type.
**				The remaining fields are filled here.
**	    .qeuq_db_id		Database id.
**	    .qeuq_d_id		DMF session id.
**
** Outputs:
**      qeuq_cb
**	    .error.err_code	E_QE0002_INTERNAL_ERROR
**				E_QE0017_BAD_CB
**				E_QE0018_BAD_PARAM_IN_CB
**				E_QE0022_ABORTED
**				E_QE020A_EVENT_EXISTS (ret E_QE0025_USER_ERROR)
**	Returns:
**	    E_DB_{OK, WARN, ERROR, FATAL}
**	Exceptions:
**	    none
**
** History:
**	28-aug-89 (neil)
**	    Written for Terminator II/alerters.
**	09-feb-90 (neil)
**	   Added auditing functionality.
**	03-mar-90 (neil)
**	   Clear adf_constants before calling ADF.  The problem was that the
**	   session CB may have been pointing at "old" data which had been
**	   reused for other things.
**	19-may-93 (anitap)
**	    Added support to create implicit schema for dbevent.
**	07-jul-93 (anitap)
**	    Added two arguments qef_rcb & qeuq_cb to qea_schema() instead of
**	    PTR.
**	    Changed assignment of flag to IMPLICIT_SCHEMA.
**	21-sep-93 (stephenb)
**	    Replace generic I_SX2032_EVENT_ACCESS with I_SX2032_EVENT_CREATE. 
**	27-oct-93 (andre)
**	    As a part of fix for bug 51852 (which was reported in 6.4 but can
**	    and will manifest itself in 6.5 as soon as someone places some 
**	    stress on the DBMS), we want to use the dbevent id (really 
**	    guaranteed to be unique) instead of timestamps (allegedly unique, 
**	    but in fact may be non-unique if several objects get created in 
**	    rapid succession on a reasonably fast box) to identify IIQRYTEXT 
**	    tuples associated with a given dbevent.  This id (pumped through 
**	    randomizing function) will be used to key into IIQRYTEXT 
*/
DB_STATUS
qeu_cevent(
QEF_CB          *qef_cb,
QEUQ_CB		    *qeuq_cb)
{
    DB_IIEVENT    	*evtuple;	/* New event tuple */
    DB_IIEVENT    	evtuple_temp;	/* Tuple and 			   */
    DMR_ATTR_ENTRY  	evkey_array[2];	/*       keys for uniqueness check */
    DMR_ATTR_ENTRY  	*evkey_ptr_array[2];
    DMU_CB		dmu_cb;		/* For unique table-id request */
    DB_DATA_VALUE	evcreate_dv;	/* For create date */
    DB_IIQRYTEXT	*qtuple;	/* Event text */
    DB_TAB_ID		randomized_id;
    i4		    	i;		/* Querytext counter  */
    QEF_DATA	    	*next;		/*   and data pointer */
    DB_STATUS	    	status, local_status;
    DB_ERROR		e_error;
    i4	    	error;
    bool	    	tbl_opened = FALSE;
    QEU_CB	    	tranqeu;	/* May need a transaction */
    bool	    	transtarted = FALSE;
    QEU_CB	    	qeu;
    QEF_DATA	    	qef_data;
    i4			flag = IMPLICIT_SCHEMA;
    QEF_RCB	        *qef_rcb = (QEF_RCB *)NULL;

    for (;;)	/* Dummy for loop for error breaks */
    {
	/* Validate CB and parameters */
	if (qeuq_cb->qeuq_type != QEUQCB_CB ||
            qeuq_cb->qeuq_length != sizeof(QEUQ_CB))
	{
	    status = E_DB_ERROR;
	    error = E_QE0017_BAD_CB;
	    break;
	}
	if (   (qeuq_cb->qeuq_cq == 0   || qeuq_cb->qeuq_qry_tup == NULL)
            || (qeuq_cb->qeuq_culd != 1 || qeuq_cb->qeuq_uld_tup == NULL)
            || (qeuq_cb->qeuq_db_id == NULL)
            || (qeuq_cb->qeuq_d_id == 0))
	{
	    status = E_DB_ERROR;
	    error = E_QE0018_BAD_PARAM_IN_CB;
	    break;
	}

	/*
	** Check to see if transaction is in progress, if so set a local
	** transaction, otherwise we'll use the user's transaction.
	*/
	if (qef_cb->qef_stat == QEF_NOTRAN)
	{
	    tranqeu.qeu_type = QEUCB_CB;
	    tranqeu.qeu_length = sizeof(QEUCB_CB);
	    tranqeu.qeu_db_id = qeuq_cb->qeuq_db_id;
	    tranqeu.qeu_d_id = qeuq_cb->qeuq_d_id;
	    tranqeu.qeu_flag = 0;
	    status = qeu_btran(qef_cb, &tranqeu);
	    if (status != E_DB_OK)
	    {
		error = tranqeu.error.err_code;
		break;
	    }
	    transtarted = TRUE;
	}
	/* Escalate the transaction to MST */
	if (qef_cb->qef_auto == QEF_OFF)
	    qef_cb->qef_stat = QEF_MSTRAN;

	evtuple = (DB_IIEVENT *)qeuq_cb->qeuq_uld_tup->dt_data;

	/* Validate that the event name/owner is unique */
	qeu.qeu_type = QEUCB_CB;
        qeu.qeu_length = sizeof(QEUCB_CB);
        qeu.qeu_tab_id.db_tab_base  = DM_B_EVENT_TAB_ID;
        qeu.qeu_tab_id.db_tab_index  = DM_I_EVENT_TAB_ID;
        qeu.qeu_db_id = qeuq_cb->qeuq_db_id;
        qeu.qeu_lk_mode = DMT_IX;
        qeu.qeu_flag = DMT_U_DIRECT;
        qeu.qeu_access_mode = DMT_A_WRITE;
	qeu.qeu_mask = 0;
	status = qeu_open(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened = TRUE;

	/* Retrieve the same named/owned event - if not there then ok */
	qeu.qeu_count = 1;
        qeu.qeu_tup_length = sizeof(DB_IIEVENT);
	qeu.qeu_output = &qef_data;
	qef_data.dt_next = NULL;
        qef_data.dt_size = sizeof(DB_IIEVENT);
        qef_data.dt_data = (PTR)&evtuple_temp;
	qeu.qeu_getnext = QEU_REPO;
	qeu.qeu_klen = 2;			/* Keyed on name and owner */
	qeu.qeu_key = evkey_ptr_array;
	evkey_ptr_array[0] = &evkey_array[0];
	evkey_ptr_array[0]->attr_number = DM_1_EVENT_KEY;
	evkey_ptr_array[0]->attr_operator = DMR_OP_EQ;
	evkey_ptr_array[0]->attr_value = (char *)&evtuple->dbe_name;
	evkey_ptr_array[1] = &evkey_array[1];
	evkey_ptr_array[1]->attr_number = DM_2_EVENT_KEY;
	evkey_ptr_array[1]->attr_operator = DMR_OP_EQ;
	evkey_ptr_array[1]->attr_value = (char *)&evtuple->dbe_owner;
	qeu.qeu_qual = NULL;
	qeu.qeu_qarg = NULL;
	status = qeu_get(qef_cb, &qeu);
	if (status == E_DB_OK)		/* Found the same event! */
	{
	    (VOID)qef_error(E_QE020A_EVENT_EXISTS, 0L, E_DB_ERROR,
			    &error, &qeuq_cb->error, 1,
			    qec_trimwhite(sizeof(evtuple->dbe_name),
					  (char *)&evtuple->dbe_name),
			    (PTR)&evtuple->dbe_name);
	    error = E_QE0025_USER_ERROR;
	    break;
	}
	if (qeu.error.err_code != E_QE0015_NO_MORE_ROWS)
	{
	    error = qeu.error.err_code;	 /* Some other error */
	    break;
	}
	/* The event is unique - append it */

	status = E_DB_OK;

	/*
	** Get unique event id (a table id) from DMF.  This id enables
	** permissions to be associated with the event.
	*/
	dmu_cb.type = DMU_UTILITY_CB;
	dmu_cb.length = sizeof(DMU_CB);
	dmu_cb.dmu_flags_mask = 0;
	dmu_cb.dmu_tran_id = qef_cb->qef_dmt_id;
	dmu_cb.dmu_db_id = qeuq_cb->qeuq_db_id;
	status = dmf_call(DMU_GET_TABID, &dmu_cb);
	if (status != E_DB_OK)
	{
	    error = dmu_cb.error.err_code;
	    break;
	}
	evtuple->dbe_uniqueid.db_tab_base  = dmu_cb.dmu_tbl_id.db_tab_base;
	evtuple->dbe_uniqueid.db_tab_index = dmu_cb.dmu_tbl_id.db_tab_index;

	/*
	** use dbevent id to generate randomized id which will be used to 
	** identify IIQRYTEXT tuples associated with this dbevent
	*/
	randomized_id.db_tab_base = 
	    ulb_rev_bits(evtuple->dbe_uniqueid.db_tab_base);
	randomized_id.db_tab_index = 
	    ulb_rev_bits(evtuple->dbe_uniqueid.db_tab_index);

	/* set text id to "randomized" id */
	evtuple->dbe_txtid.db_qry_high_time = randomized_id.db_tab_base;
	evtuple->dbe_txtid.db_qry_low_time  = randomized_id.db_tab_index;

	/* Get the create date of the event */
	evcreate_dv.db_datatype = DB_DTE_TYPE;
	evcreate_dv.db_prec = 0;
	evcreate_dv.db_length = sizeof(DB_DATE);
	evcreate_dv.db_data = (PTR)&evtuple->dbe_create;
	evcreate_dv.db_collID = -1;
	qef_cb->qef_adf_cb->adf_constants = NULL;
	status = adu_datenow(qef_cb->qef_adf_cb, &evcreate_dv);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}

	/* Insert single event tuple */
	qeu.qeu_count = 1;
        qeu.qeu_tup_length = sizeof(DB_IIEVENT);
	qeu.qeu_input = qeuq_cb->qeuq_uld_tup; /* Which points at evtuple */
	status = qeu_append(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	status = qeu_close(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened = FALSE;

	/*
	** Update all query text tuples with query id - validate list.  Even
	** though we will probably have just one text tuple this is set up
	** for syntactic extensions to the CREATE EVENT statement.
	*/
	next = qeuq_cb->qeuq_qry_tup;
	for (i = 0; i < qeuq_cb->qeuq_cq; i++)
	{
	    qtuple = (DB_IIQRYTEXT *)next->dt_data;
	    next = next->dt_next;
	    qtuple->dbq_txtid.db_qry_high_time = randomized_id.db_tab_base;
	    qtuple->dbq_txtid.db_qry_low_time  = randomized_id.db_tab_index;
	    if (i < (qeuq_cb->qeuq_cq -1) && next == NULL)
	    {
		error = E_QE0018_BAD_PARAM_IN_CB;
		status = E_DB_ERROR;
		break;
	    }
	} /* for all query text tuples */
	if (status != E_DB_OK)
	    break;

	/* Insert all query text tuples */
	qeu.qeu_tab_id.db_tab_base = DM_B_QRYTEXT_TAB_ID;
	qeu.qeu_tab_id.db_tab_index = 0L;
	qeu.qeu_mask = 0;
	status = qeu_open(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened = TRUE;
	qeu.qeu_count = qeuq_cb->qeuq_cq;
        qeu.qeu_tup_length = sizeof(DB_IIQRYTEXT);
	qeu.qeu_input = qeuq_cb->qeuq_qry_tup;
	status = qeu_append(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	status = qeu_close(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened = FALSE;

        status = qea_schema(qef_rcb, qeuq_cb, qef_cb, 
		(DB_SCHEMA_NAME *)&evtuple->dbe_owner, flag);
        if (status != E_DB_OK)
        {
           error = qeuq_cb->error.err_code;
           break;
        }

	if (transtarted)		   /* If we started a transaction */
	{
	    status = qeu_etran(qef_cb, &tranqeu);
	    if (status != E_DB_OK)
	    {
		error = tranqeu.error.err_code;
		break;
	    }
	}


	/* Audit CREATE EVENT */
	if ( Qef_s_cb->qef_state & QEF_S_C2SECURE )
	{
	    status = qeu_secaudit(FALSE, qef_cb->qef_ses_id, 
		  evtuple->dbe_name.db_ev_name, &evtuple->dbe_owner, DB_EVENT_MAXNAME,
		  SXF_E_EVENT, I_SX2032_EVENT_CREATE, 
		  SXF_A_SUCCESS | SXF_A_CREATE, &e_error);

	    if (status != E_DB_OK)
		break;
	}

	qeuq_cb->error.err_code = E_QE0000_OK;
	return (E_DB_OK);
    } /* End dummy for */

    /* call qef_error to handle error messages */
    (VOID) qef_error(error, 0L, status, &error, &qeuq_cb->error, 0);

    /* Close off all the tables. */
    local_status = E_DB_OK;
    if (tbl_opened)		    /* If system table opened, close it */
    {
	local_status = qeu_close(qef_cb, &qeu);
	if (local_status != E_DB_OK)
	{
	    (VOID) qef_error(qeu.error.err_code, 0L, local_status, &error,
		    	     &qeuq_cb->error, 0);
	    if (local_status > status)
		status = local_status;
	}
    }

    if (transtarted)		   /* If we started a transaction */
    {
        local_status = qeu_atran(qef_cb, &tranqeu);
        if (local_status != E_DB_OK)
	{
	    (VOID) qef_error(tranqeu.error.err_code, 0L, local_status,
			     &error, &qeuq_cb->error, 0);
	    if (local_status > status)
		status = local_status;
	}
    }
    return (status);
} /* qeu_cevent */
예제 #4
0
/*{
** Name: openTempTable		- Open a temp table used 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:
**      qef_rcb
**	tempTableNumber		index to dsh temptable array for temporary
**				table to be created.
**
** Outputs:
**      Returns:
**          E_DB_{OK,WARN,ERROR,FATAL} (from table creation)
**      Exceptions:
**          none
**
** Side Effects:
**          none
**
** History:
**	18-jul-96 (inkdo01)
**	    Created.
**	29-oct-1998 (somsa01)
**	    If we are opening a Global Temporary Table, turn on the
**	    DMT_SESSION_TEMP flag in dmt_flags_mask before the open.
**	    (Bug #94059)
**	12-nov-1998 (somsa01)
**	    Added another parameter, and refined the check for a Global
**	    Session Temporary Table.  (Bug #94059)
**	15-mar-04 (inkdo01)
**	    dsh_tempTables is now an array of ptrs.
**	13-Jul-2004 (schka24)
**	    Pass in dsh so we get the right one for sure.
**	30-Jul-2004 (jenjo02)
**	    Use dsh_dmt_id rather than qef_dmt_id transaction context.
**	4-Jun-2009 (kschendel) b122118
**	    Use open-and-link utility.
*/
static DB_STATUS openTempTable(
	QEF_RCB 	*rcb,
	QEE_DSH		*dsh,
	i4		tempTableNumber,
	bool		gttparm
)
{
    QEE_TEMP_TABLE  *tempTable = dsh->dsh_tempTables[ tempTableNumber ];
    DMT_CB	    *dmt = tempTable->tt_dmtcb;
    DMR_CB	    *dmr = tempTable->tt_dmrcb;
    DM_MDATA	    dm_mdata;
    DB_STATUS status = E_DB_OK;

    for (;;)	/* something to break out of */
    {
	/* create the table if it doesn't already exist */

	if ( !( tempTable->tt_statusFlags & TT_CREATED ) )
	{
	    dmt->dmt_db_id = rcb->qef_db_id;
	    dmt->dmt_tran_id = dsh->dsh_dmt_id;
	    MEmove(8, (PTR) "$default", (char) ' ', 
	            sizeof(DB_LOC_NAME),
	            (PTR) dmt->dmt_location.data_address);
	    dmt->dmt_location.data_in_size = sizeof(DB_LOC_NAME);

	    dmt->dmt_flags_mask = DMT_DBMS_REQUEST;
	    if (gttparm)
		dmt->dmt_flags_mask |= DMT_SESSION_TEMP;
	    dmr->dmr_flags_mask = 0;
	    /*
	    ** We assume that the sort key descriptor was set up
	    ** earlier, probably at QEE time.
	    */

	    if ( tempTable->tt_statusFlags & TT_PLEASE_SORT )
		dmt->dmt_flags_mask |= DMT_LOAD;

	    if ( tempTable->tt_statusFlags & TT_NO_DUPLICATES )
		dmr->dmr_flags_mask |= DMR_NODUPLICATES;

	    dmr->dmr_count = 1;
	    dmr->dmr_s_estimated_records = TT_TUPLE_COUNT_GUESS;
	    dmr->dmr_tid = 0;
	    dm_mdata.data_address = dsh->dsh_row[ tempTable->tt_tuple ];
	    dm_mdata.data_size =
		dsh->dsh_qp_ptr->qp_row_len[ tempTable->tt_tuple ];
	    dmr->dmr_mdata = &dm_mdata;

	    status = dmf_call(DMT_CREATE_TEMP, dmt);
	    if (status != E_DB_OK)
	    {
	        if (dmt->error.err_code == E_DM0078_TABLE_EXISTS)
	        {
		    dsh->dsh_error.err_code = E_QE0050_TEMP_TABLE_EXISTS;
		    status = E_DB_ERROR;
	        }
	        else
	        {
		    dsh->dsh_error.err_code = dmt->error.err_code;
	        }
	        break;
	    }

	    /* Open the temp table */
	    dmt->dmt_flags_mask = 0;
	    if (gttparm)
		dmt->dmt_flags_mask |= DMT_SESSION_TEMP;
	    dmt->dmt_sequence = dsh->dsh_stmt_no;
	    dmt->dmt_access_mode = DMT_A_WRITE;
	    dmt->dmt_lock_mode = DMT_X;
	    dmt->dmt_update_mode = DMT_U_DIRECT;
	
	    status = qen_openAndLink(dmt, dsh);
	    if (status != E_DB_OK)
	    {
	        break;
	    }

            tempTable->tt_statusFlags |= TT_CREATED;
	    dmr->dmr_access_id = dmt->dmt_record_access_id;
	}	/* end of table creation */

	break;
    }	/* end of code block */

    return( status );
}
예제 #5
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);
}
예제 #6
0
static DB_STATUS
qen_ts_reset(QEE_DSH *dsh, QEN_NODE *node, QEN_STATUS *qen_status)
{

    PTR		*cbs = dsh->dsh_cbs;
    DMT_CB	*dmt = (DMT_CB *)cbs[node->node_qen.qen_tsort.tsort_create];
    DMR_CB	*dmr_load = (DMR_CB*)cbs[node->node_qen.qen_tsort.tsort_load];
    DB_STATUS	status;
    QEN_SHD	*shd = dsh->dsh_shd[node->node_qen.qen_tsort.tsort_shd];

    /* Dump old data in the sort file:
    ** For QEF in-memory sort, Close the sort buffer memory stream */
    if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT)
    {
	status = qen_u33_resetSortFile( shd, dsh );
	if (status != E_DB_OK)
	    return (status);

	qen_status->node_status = QEN0_INITIAL;
    }	
    else 
    {
	/* For DMF sort, call DMF to dump data in the sorter. */

	if (dmt->dmt_record_access_id == (PTR)NULL)
	{
	    /*
	    ** A commit has closed the sort hold file. It should
	    ** be initialised.
	    */
	    qen_status->node_status = QEN0_INITIAL;
	}
	else
	{
	    /* Pitch out contents of sort temp */
	    dmr_load->dmr_flags_mask = 0;
	    status = dmf_call(DMR_DUMP_DATA, dmr_load);
	    if (status != E_DB_OK)
	    {
		dsh->dsh_error.err_code = dmr_load->error.err_code;
		return (status);
	    }
	    dmr_load->dmr_flags_mask = (node->node_qen.qen_tsort.tsort_dups |
						DMR_SORT_NOCOPY);
	    dmr_load->dmr_count = 1;  /* reset for subsequent loads */

	    /* Close the table and remove it from the
	    ** dsh_open_dmtcbs list.
	    */
	    dmt->dmt_flags_mask = 0;
	    status = qen_closeAndUnlink(dmt, dsh);
	    if (status != E_DB_OK)
	    {
		dsh->dsh_error.err_code = dmt->error.err_code;
		return(status);
	    }  

	    status = dmf_call(DMT_DELETE_TEMP, dmt);
	    if (status)
	    {
		dsh->dsh_error.err_code = dmt->error.err_code;
		return(status);
	    }

	    /* Having ended the dmse_sort the existing code
	    ** for starting a new one on a reset assumes we
	    ** would be in a QEF sort that ran out of memory.
	    ** Switch back to an inital state with QEF sort.
	    ** some of the following sorts actually run to
	    ** completion under QEF sort anyway.
	    */
	    qen_status->node_status = QEN0_INITIAL;
	    qen_status->node_u.node_sort.node_sort_status = QEN0_QEF_SORT;
	}
    }
    /* make sure end-of-partition flag is off (it should be...) */
    qen_status->node_status_flags &= QEN2_OPART_END;
    return (E_DB_OK);

} /* qen_ts_reset */
예제 #7
0
static	DB_STATUS
qen_ts_dump(
QEN_SHD		   *shd,
QEE_DSH		   *dsh,
QEN_NODE           *node,
i4		   rowno,
bool		   heap_sort,
bool		   no_qef )
{
    PTR		*cbs = dsh->dsh_cbs;
    DMT_CB	*dmt = (DMT_CB *)cbs[node->node_qen.qen_tsort.tsort_create];
    DMR_CB	*dmr_load = (DMR_CB*)cbs[node->node_qen.qen_tsort.tsort_load];
    DMR_CB	*dmr_get = (DMR_CB*) cbs[node->node_qen.qen_tsort.tsort_get];
    DMT_CHAR_ENTRY	char_array[2];
    DB_STATUS	status;


    for (;;)	    /* to break off in case of error */
    {
	/* Initialize the DMT_CB for the sorter table */
	dmt->dmt_flags_mask = DMT_LOAD | DMT_DBMS_REQUEST;
	dmt->dmt_db_id = dsh->dsh_qefcb->qef_rcb->qef_db_id;
	dmt->dmt_tran_id = dsh->dsh_dmt_id;
	MEmove(8, (PTR) "$default", (char) ' ', 
	    sizeof(DB_LOC_NAME),
	    (PTR) dmt->dmt_location.data_address);
	dmt->dmt_location.data_in_size = sizeof(DB_LOC_NAME);


	/* Initialize table attribute descriptors */
	dmt->dmt_attr_array.ptr_address = 
		    (PTR) node->node_qen.qen_tsort.tsort_atts;
	dmt->dmt_attr_array.ptr_in_count = 
		    node->node_qen.qen_tsort.tsort_acount;
	dmt->dmt_attr_array.ptr_size = sizeof (DMF_ATTR_ENTRY);

	/* Initialize the the sort key descriptors */
	dmt->dmt_key_array.ptr_address = 
		(PTR) node->node_qen.qen_tsort.tsort_satts;
	dmt->dmt_key_array.ptr_in_count = 
		node->node_qen.qen_tsort.tsort_scount;
	dmt->dmt_key_array.ptr_size = sizeof (DMT_KEY_ENTRY);

	/*  Pass the page size */
	char_array[0].char_id = DMT_C_PAGE_SIZE;
	char_array[0].char_value = node->node_qen.qen_tsort.tsort_pagesize;
	char_array[1].char_id = DMT_C_DUPLICATES;
	char_array[1].char_value = DMT_C_ON; /* duplicate rows allowed */
	dmt->dmt_char_array.data_address = (PTR) &char_array;
	dmt->dmt_char_array.data_in_size = 2 * sizeof(DMT_CHAR_ENTRY);

	/* Create the sorter table */
	status = dmf_call(DMT_CREATE_TEMP, dmt);
	if (status != E_DB_OK)
	{
	    if (dmt->error.err_code == E_DM0078_TABLE_EXISTS)
	    {
		dsh->dsh_error.err_code = E_QE0050_TEMP_TABLE_EXISTS;
		status = E_DB_ERROR;
	    }
	    else
	    {
		dsh->dsh_error.err_code = dmt->error.err_code;
	    }
	    break;
	}

	/* Open the sorter table */
	dmt->dmt_flags_mask = 0;
	dmt->dmt_sequence = dsh->dsh_stmt_no;
	dmt->dmt_access_mode = DMT_A_WRITE;
	dmt->dmt_lock_mode = DMT_X;
	dmt->dmt_update_mode = DMT_U_DIRECT;
	dmt->dmt_char_array.data_address = 0;
	dmt->dmt_char_array.data_in_size = 0;
	
	status = qen_openAndLink(dmt, dsh);
	if (status != E_DB_OK)
	{
	    break;
	}

	/* Initialize the DMR_CB for loading the sorter */
	dmr_load->dmr_access_id = dmt->dmt_record_access_id;
	dmr_load->dmr_count = 1;
	dmr_load->dmr_flags_mask = (node->node_qen.qen_tsort.tsort_dups |
					DMR_SORT_NOCOPY);
	dmr_load->dmr_s_estimated_records = node->qen_est_tuples;
	dmr_load->dmr_tid = 0;

	/* Initialize the DMR_CB for reading the sorter */
	dmr_get->dmr_access_id = dmt->dmt_record_access_id;
	dmr_get->dmr_data.data_address = dsh->dsh_row[rowno];
	dmr_get->dmr_data.data_in_size =  dsh->dsh_qp_ptr->qp_row_len[rowno];
	dmr_get->dmr_tid = 0;

	if (no_qef)
	    break;				/* leave, if nothing there */

	/* If we have tuples in the in-memory sort buffer, load them into
	** DMF sorter table now and write current tuple. */
        if (heap_sort) status = qes_dump(dsh, shd, dmr_load);
	 else status = qes_dumploop(dsh, shd, dmr_load);
	break;
    }	/* end of error-break loop */
    return (status);
}
예제 #8
0
DB_STATUS
qen_tsort(
QEN_NODE           *node,
QEF_RCB            *qef_rcb,
QEE_DSH		   *dsh,
i4		    function )
{
    QEF_CB	*qef_cb = dsh->dsh_qefcb;
    PTR		*cbs = dsh->dsh_cbs;
    ADE_EXCB	*ade_excb;
    DMR_CB	*dmr_load = (DMR_CB*)cbs[node->node_qen.qen_tsort.tsort_load];
    DMR_CB	*dmr_get = (DMR_CB*) cbs[node->node_qen.qen_tsort.tsort_get];
    QEN_NODE	*out_node = node->node_qen.qen_tsort.tsort_out;
    QEE_XADDRS	*node_xaddrs = dsh->dsh_xaddrs[node->qen_num];
    QEN_STATUS	*qen_status = node_xaddrs->qex_status;
    QEN_SHD	*shd = dsh->dsh_shd[node->node_qen.qen_tsort.tsort_shd];
    DB_STATUS	status;
    bool	reset = FALSE;
    bool	heap_sort = TRUE, no_qef = FALSE;
    i4		rowno;
    i4		out_func = NO_FUNC;
    DM_MDATA	dm_mdata;
    i4	val1;
    i4	val2;
    TIMERSTAT	timerstat;
    i4          loop_cntr = 0;

    if (function != 0)
    {
	if (function & FUNC_RESET)
	{
	    reset = TRUE;
	    out_func = FUNC_RESET;
	}

	/* Do open processing, if required. Only if this is the root node
	** of the query tree do we continue executing the function. */
	if ((function & TOP_OPEN || function & MID_OPEN) && 
	    !(qen_status->node_status_flags & QEN1_NODE_OPEN))
	{
	    status = (*out_node->qen_func)(out_node, qef_rcb, dsh, MID_OPEN);
	    qen_status->node_status_flags = QEN1_NODE_OPEN;
	    if (function & MID_OPEN)
		return(E_DB_OK);
	    function &= ~TOP_OPEN;
	}
	/* Do close processing, if required. */
	if (function & FUNC_CLOSE)
	{
	    if (!(qen_status->node_status_flags & QEN8_NODE_CLOSED))
	    {
		status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_CLOSE);
		qen_status->node_status_flags = 
		    (qen_status->node_status_flags & ~QEN1_NODE_OPEN) | QEN8_NODE_CLOSED;
	    }
	    return(E_DB_OK);
	}
	if (function & FUNC_EOGROUP)
	{
	    /* End of partition group request ends our sort if we're returning
	    ** rows.  If we aren't in the middle of returning rows, pass the
	    ** EOG request on down so that the child skips the upcoming group
	    ** and moves on to the next one.
	    */
	    if (qen_status->node_status == QEN3_GET_NEXT_INNER)
	    {
		status = qen_ts_reset(dsh, node, qen_status);
		/* FIXME we should do better at remembering whether this
		** sort load got EOF or EOG, and pass it on up now.  At
		** present (Apr '07), tsorts aren't very common except under
		** merge join plans, where early eof detection doesn't
		** matter much.  (the tsort is on the outer side.)
		** For now, pass EOG back up, if we're really at EOF caller
		** will find out soon enough.
		*/
		if (status == E_DB_OK)
		{
		    status = E_DB_WARN;
		    dsh->dsh_error.err_code = E_QE00A5_END_OF_PARTITION;
		}
	    }
	    else
	    {
		status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_EOGROUP);
		/* Pass resulting EOF or EOG indication in dsh up to caller */
	    }
	    return(status);
	}
    } /* if function != 0 */


    /* Check for cancel, context switch if not MT */
    CScancelCheck(dsh->dsh_sid);
    if (QEF_CHECK_FOR_INTERRUPT(qef_cb, dsh) == E_DB_ERROR)
	return (E_DB_ERROR);

    /* If the trace point qe90 is turned on then gather cpu and dio stats */
    if (dsh->dsh_qp_stats)
    {
	qen_bcost_begin(dsh, &timerstat, qen_status);
    }

    if (node->node_qen.qen_tsort.tsort_dups == DMR_NODUPLICATES &&
        ult_check_macro(&qef_cb->qef_trace, 92, &val1, &val2))
            heap_sort = FALSE;

    if (ult_check_macro(&qef_cb->qef_trace, 94, &val1, &val2))
    {
	no_qef = TRUE;
	qen_status->node_u.node_sort.node_sort_status = QEN9_DMF_SORT;
    }

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

    for (;;)	    /* to break off in case of error */
    {
	if (reset && qen_status->node_status != QEN0_INITIAL)
	{
	    status = qen_ts_reset(dsh, node, qen_status);
	    if (status != E_DB_OK)
		break;
	}

	/* If NO MORE ROWS from this node, just return */
	if (qen_status->node_status == QEN4_NO_MORE_ROWS)
	{
	    dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS;
	    status = E_DB_WARN;
	    break;
	}

	rowno = node->node_qen.qen_tsort.tsort_mat->qen_output;
	ade_excb = node_xaddrs->qex_otmat;

	/* If this is the first time execution, or if the node is reset, 
	** initialize the sorter. If this is not, just go get a tuple.
	*/
	if (qen_status->node_status == QEN0_INITIAL || 
	    qen_status->node_status == QEN1_EXECUTED)
	{
	    if (qen_status->node_status == QEN0_INITIAL)
	    {
		if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT)
		{
		    status = qes_init(dsh, shd, node, rowno,
				node->node_qen.qen_tsort.tsort_dups);
		    if (status != E_DB_OK)
		    {
			if (dsh->dsh_error.err_code == E_QE000D_NO_MEMORY_LEFT)
			{
			    /* out of space, convert it to DMF sort */
			    qen_status->node_u.node_sort.node_sort_status = QEN9_DMF_SORT;
			    status = E_DB_OK;
			}
			else
			{
			    break;
			}
		    }
		}

		if (qen_status->node_u.node_sort.node_sort_status == QEN9_DMF_SORT)
		{
		    status = qen_ts_dump(shd, dsh, node, 
					rowno, heap_sort, no_qef);
		    if (status != E_DB_OK)
			break;
		}

		if (node->node_qen.qen_tsort.tsort_pqual != NULL)
		    qeq_join_pqreset(dsh, node->node_qen.qen_tsort.tsort_pqual);

		qen_status->node_status = QEN1_EXECUTED;
	    }

	    /* Common code for QEN0_INITIAL and QEN1_EXECUTED */

	    /* Get dm_mdata ready for DMF loading  */
	    dm_mdata.data_address = dsh->dsh_row[rowno];
	    dm_mdata.data_size = dsh->dsh_qp_ptr->qp_row_len[rowno];
	    dmr_load->dmr_mdata = &dm_mdata;

            dsh->dsh_qp_status |= DSH_SORT;

	    /* Get rows from the underneath node and append them to the 
	    ** sorter */
	    for (;;)
	    {
		/* fetch rows */
		status = (*out_node->qen_func)(out_node, qef_rcb, dsh, out_func);
		out_func = NO_FUNC;
		if (status != E_DB_OK)
		{
		    /* the error.err_code field in qef_rcb should already be
		    ** filled in.
		    */
		    if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS)
		    {
			status = E_DB_OK;
		    }
		    else if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION &&
			(node->qen_flags & QEN_PART_SEPARATE))
		    {
			/* End of rows from partitioning group. Flag the
			** fact and make it look like regular "eof". */
			qen_status->node_status_flags |= QEN2_OPART_END;
			dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS;
			status = E_DB_OK;
		    }

		    break;
		}
		
		/* project the attributes into sort tuple row */
		status = qen_execute_cx(dsh, ade_excb);
		if (status != E_DB_OK)
		    break;

		/* If we're generating partition qualifications on behalf
		** of a parent FSM join, eval against this row.
		*/
		if (node->node_qen.qen_tsort.tsort_pqual != NULL)
		{
		    status = qeq_join_pquals(dsh, node->node_qen.qen_tsort.tsort_pqual);
		    if (status != E_DB_OK)
			break;
		}

                /* append the sort tuple into the sorter - note periodic
                ** differences between heap sort and trace point mandated
                ** insert sort */
		if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT)
		{
		    if (heap_sort) status = qes_putheap(dsh, shd, 
                         node->node_qen.qen_tsort.tsort_cmplist,
                         node->node_qen.qen_tsort.tsort_scount); 
                     else status = qes_insert(dsh, shd,
                         node->node_qen.qen_tsort.tsort_cmplist,
                         node->node_qen.qen_tsort.tsort_scount);

		    if (status != E_DB_OK && 
			dsh->dsh_error.err_code == E_QE000D_NO_MEMORY_LEFT)
		    {
			/* out of space, convert it to DMF sort */
			qen_status->node_u.node_sort.node_sort_status = QEN9_DMF_SORT;
			status = qen_ts_dump(shd, dsh, 
					node, rowno, heap_sort, no_qef);
		    }
		    if (status != E_DB_OK)
			break;
		}

		if(qen_status->node_u.node_sort.node_sort_status == QEN9_DMF_SORT)  
		{
		    status = dmf_call(DMR_LOAD, dmr_load);
		    if (status != E_DB_OK)
		    {
			dsh->dsh_error.err_code = dmr_load->error.err_code; 
			break;
		    }
		}

                if (!(Qef_s_cb->qef_state & QEF_S_IS_MT) && (loop_cntr++ >1000))
                {
                   /* On an Internal threaded system, after processing 1000 rows
                   ** give another thread a chance.
                   */

                   loop_cntr = 0;

                   CSswitch();
                }
	    }
	    if (status != E_DB_OK)
		break;

	    /* End of loading loop */
	    /* Finish up join-time part qual if we're doing it */
	    if (node->node_qen.qen_tsort.tsort_pqual != NULL)
	    {
		qeq_join_pqeof(dsh, node->node_qen.qen_tsort.tsort_pqual);
	    }
	    if(qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT)
	    {
		if (!heap_sort) qes_endsort(dsh, shd);
						/* prep return of tups */

	    }
	    else   /* DMF */
	    {
		/* Tell DMF that there are no more rows */
		dmr_load->dmr_flags_mask = (DMR_ENDLOAD | DMR_SORT_NOCOPY);
		status = dmf_call(DMR_LOAD, dmr_load);
		if (status != E_DB_OK)
		{
		    dsh->dsh_error.err_code = dmr_load->error.err_code;
		    break;
		}

		/* position the table for reading sorted tuples */
		dmr_get->dmr_flags_mask = DMR_SORTGET;
		dmr_get->dmr_position_type = DMR_ALL;
		status = dmf_call(DMR_POSITION, dmr_get);
		if (status != E_DB_OK)
		{
		    dsh->dsh_error.err_code = dmr_get->error.err_code;
		    break;
		}
	    }

	    /* Mark the node is ready to return tuples */
	    qen_status->node_status = QEN3_GET_NEXT_INNER;
	}


	/* 
	** Return a tuple from the sorter to the caller.
	*/
	if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT)
	{
	    if (heap_sort) 
	    {
		status = qes_getheap(dsh, shd, 
                         node->node_qen.qen_tsort.tsort_cmplist,
                         node->node_qen.qen_tsort.tsort_scount); 
		if (status != E_DB_OK) 
		{
		    if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS)
		    {
			qen_status->node_status = QEN4_NO_MORE_ROWS;
			status = E_DB_WARN;
		    }
		    break;
		}
	    }
	    else
	    {		/* rows come straight from pointer array */
	 	/* Check for the end of buffer */
		if (shd->shd_next_tup == shd->shd_tup_cnt)
		{
		    qen_status->node_status = QEN4_NO_MORE_ROWS;
		    dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS;
		    status = E_DB_WARN;
		    break;
		}

		/* Copy tuple to the row buffer */
		MEcopy((PTR)(shd->shd_vector[shd->shd_next_tup]), 
		    shd->shd_width, (PTR)shd->shd_row);
		++shd->shd_next_tup;
		status = E_DB_OK;
	    }
	}
	else
	{
	    dmr_get->dmr_flags_mask = (DMR_NEXT | DMR_SORTGET);
	    status = dmf_call(DMR_GET, dmr_get);
	    if (status != E_DB_OK)
	    {
		if (dmr_get->error.err_code == E_DM0055_NONEXT)
		{
		    qen_status->node_status = QEN4_NO_MORE_ROWS;
		    dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS;
		    status = E_DB_WARN;
		}
		else
		{
		    dsh->dsh_error.err_code = dmr_get->error.err_code;
		}
		break;
	    }
	}
	/* status has to be OK here */

	/* Increment the count of rows that this node has returned */
	qen_status->node_rcount++;
	dsh->dsh_error.err_code = 0;

	/* print tracing information DO NOT xDEBUG THIS */
	if (node->qen_prow &&
		(ult_check_macro(&qef_cb->qef_trace, 100+node->qen_num,
				    &val1, &val2) ||
		    ult_check_macro(&qef_cb->qef_trace, 99,
				    &val1, &val2)
		)
	    )
	{
	    (void) qen_print_row(node, qef_rcb, dsh);
	}

	break;
    }	    /* end of error-break loop */

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

    if (dsh->dsh_qp_stats)
    {
	qen_ecost_end(dsh, &timerstat, qen_status);
    }

    dsh->dsh_qp_status &= ~DSH_SORT;

    if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS &&
	(qen_status->node_status_flags & QEN2_OPART_END))
    {
	/* If this was just the end of a partition, reset error code
	** to notify the caller. */
	qen_status->node_status_flags &= ~QEN2_OPART_END;
	dsh->dsh_error.err_code = E_QE00A5_END_OF_PARTITION;
	status = E_DB_WARN;
    }
    return (status);
}
예제 #9
0
/*{
** Name: qeu_dsecalarm 	- Drop single or all alarm definition.
**
** External QEF call:   status = qef_call(QEU_DSECALM, &qeuq_cb);
**
** Description:
**	Drop the alarm tuple, the alarm text from the appropriate tables 
**	(iisecalarm, iiqrytext and update the table "relstat" field. An
**	alarm can be dropped either by name (when the DROP SECURITY_ALARM
**      statement is issued) or by object id (when its associated object 
**      is dropped).
**
**	When originating from the DROP SECURITY_ALARM  statement the single 
**	alarm tuple is deleted based on its name - provided in the
**	qeuq_uld_tup parameter.  In this case the single alarm is fetched
**	(to collect the text, table id) and deleted.  If it wasn't
**	found then an error is returned.  
**
**	When originating from a DROP TABLE statement (this is similar to
**	the DROP INTEGRITY ON table ALL), all tuples that satisfy the
**	table-id are fetched (to collect their text ids) and dropped.
**	If none are found no error is returned.  
**
**	For each alarm that is dropped the text tuples are
**	also dropped based on the ids collected from the fetched alarm.
**
**	The way this routine works is the following:
**
**	    set up QEU CB's for iisecalarm, iiqrytext and open tables;
**	    if (DROP SECURITY_ALARM) then
**		set up iisecalarm "qualified" name and owner;
**	    else
**		set up iisecalarm "keyed" on DROP object id;
**	    endif;
**	    for (all alarm tuples found) loop
**		get alarm tuple;
**		if (not found) then
**		    if (DROP SECURITY_ALARM) then
**			error - alarm does not exist;
**			break;
**		    else
**			clear error;
**			break;
**		    endif;
**		endif;
**		set up iiqrytext keys based on alarm text id;
**		for (all text tuples found) loop
**		    get text tuple;
**		    delete text tuple;
**		endloop;
**		delete current alarm tuple;
**		if (DROP SECURITY_ALARM) then
**		    endloop;
**		endif;
**	    endloop;
**	    close tables;
**
** Inputs:
**      qef_cb                  QEF session control block
**      qeuq_cb
**	    .qeuq_eflag	        Designate error handling for user errors.
**		QEF_INTERNAL	Return error code.
**		QEF_EXTERNAL	Send message to user.
**	    .qeuq_rtbl		Table id of alarm - if DROP TABLE.  If DROP
**				SECURITY_ALARM then this is ignored.
**	    .qeuq_cr		Must be 1 if DROP SECURITY_ALARM, 0 
**				if DROP TABLE.
**	    .qeuq_uld_tup	Alarm tuple to be deleted - if DROP 
**				SECURITY_ALARM, otherwise this is ignored:
**		.dba_alarmname	alarm name *or*
**		.dba_alarmno	Alarm number
**	    .qeuq_db_id		Database id.
**	    .qeuq_d_id		DMF session id.
**	from_drop_alarm		TRUE if called from DROP SECURITY_ALARM
**	
** Outputs:
**      qeuq_cb
**	    .error.err_code	E_QE0002_INTERNAL_ERROR
**				E_QE0017_BAD_CB
**				E_QE0018_BAD_PARAM_IN_CB
**				E_QE0022_ABORTED
**	Returns:
**	    E_DB_{OK, WARN, ERROR, FATAL}
**	Exceptions:
**	    none
**
** History:
**	26-nov-93 (robf)
**	    Written for Secure 2.0
**	30-dec-93 (robf)
**          Don't  write audit records if called implicitly during drop
**	    of a table.
**	16-feb-94 (robf)
**          Check DROP ALL flag from  qeuq_cb.qeuq_permit_mask & QEU_DROP_ALL,
**	    so we loop appropriately when there are several alarms on
**	    the object to be dropped.
*/
DB_STATUS
qeu_dsecalarm(
QEF_CB          *qef_cb,
QEUQ_CB		*qeuq_cb,
bool		from_drop_alarm)
{
    QEU_CB	    	tranqeu;	/* For transaction request */
    bool	    	transtarted = FALSE;	    
    QEU_CB	    	aqeu;		/* For iisecalarm table */
    QEF_DATA	    	aqef_data;
    DB_SECALARM	    	*atuple_name;	/* Input tuple with name or id */
    DB_SECALARM	    	atuple;		/* Tuple currently being deleted */
    bool	    	alarm_opened = FALSE;
    DMR_ATTR_ENTRY  	akey_array[3];
    DMR_ATTR_ENTRY  	*akey_ptr_array[3];
    QEU_CB	    	qqeu;		/* For iiqrytext table */
    QEU_QUAL_PARAMS	qparams;
    DB_IIQRYTEXT	qtuple;
    QEF_DATA	    	qqef_data;
    bool	    	qtext_opened = FALSE;
    DMR_ATTR_ENTRY  	qkey_array[2];
    DMR_ATTR_ENTRY  	*qkey_ptr_array[2];
    bool		drop_specific_alarm;	/* TRUE if dropping a specific
						** alarm */
    char		obj_type;
    char		*alarm_name;
    DB_STATUS	    	status, local_status;
    i4	    	error;
    DB_ERROR 		e_error;
    SXF_ACCESS		access;
    SXF_EVENT		evtype;
    DB_OWN_NAME		objowner;

    for (;;)	/* Dummy for loop for error breaks */
    {
	MEfill(sizeof(objowner),' ',(PTR)&objowner);

	/* Validate CB and parameters */
	if (qeuq_cb->qeuq_type != QEUQCB_CB ||
            qeuq_cb->qeuq_length != sizeof(QEUQ_CB))	
	{
	    status = E_DB_ERROR;
	    error = E_QE0017_BAD_CB;
	    break;
	}
	if (   (qeuq_cb->qeuq_rtbl == NULL && qeuq_cb->qeuq_cr == 0)
            || (qeuq_cb->qeuq_db_id == NULL)
            || (qeuq_cb->qeuq_d_id == 0))
	{
	    status = E_DB_ERROR;
	    error = E_QE0018_BAD_PARAM_IN_CB;
	    break;
	}

	drop_specific_alarm = from_drop_alarm;

	/*
	** If passed DROP ALL then not dropping  specific alarm
	*/
	if(qeuq_cb->qeuq_permit_mask & QEU_DROP_ALL)
		drop_specific_alarm=FALSE;


	/* 
	** Check to see if transaction is in progress, if so set a local
	** transaction, otherwise we'll use the user's transaction.
	*/
	if (qef_cb->qef_stat == QEF_NOTRAN)
	{
	    tranqeu.qeu_type = QEUCB_CB;
	    tranqeu.qeu_length = sizeof(QEUCB_CB);
	    tranqeu.qeu_db_id = qeuq_cb->qeuq_db_id;
	    tranqeu.qeu_d_id = qeuq_cb->qeuq_d_id;
	    tranqeu.qeu_flag = 0;
	    tranqeu.qeu_mask = 0;
	    status = qeu_btran(qef_cb, &tranqeu);
	    if (status != E_DB_OK)
	    {	
		error = tranqeu.error.err_code;
		break;	
	    }	    
	    transtarted = TRUE;
	}
	/* Escalate the transaction to MST */
	if (qef_cb->qef_auto == QEF_OFF)
	    qef_cb->qef_stat = QEF_MSTRAN;


	/* Open iisecalarm, iiqrytext tables */
	aqeu.qeu_type = QEUCB_CB;
        aqeu.qeu_length = sizeof(QEUCB_CB);
        aqeu.qeu_db_id = qeuq_cb->qeuq_db_id;
        aqeu.qeu_lk_mode = DMT_IX;
        aqeu.qeu_flag = DMT_U_DIRECT;
        aqeu.qeu_access_mode = DMT_A_WRITE;
	aqeu.qeu_mask = 0;
	STRUCT_ASSIGN_MACRO(aqeu, qqeu);	/* Quick initialization */

	/* Open iisecalarm */
        aqeu.qeu_tab_id.db_tab_base = DM_B_IISECALARM_TAB_ID;    
        aqeu.qeu_tab_id.db_tab_index = DM_I_IISECALARM_TAB_ID; 	
	status = qeu_open(qef_cb, &aqeu);
	if (status != E_DB_OK)
	{
	    error = aqeu.error.err_code;
	    break;
	}
	alarm_opened = TRUE;

        qqeu.qeu_tab_id.db_tab_base = DM_B_QRYTEXT_TAB_ID; /* Open iiqrytext */
        qqeu.qeu_tab_id.db_tab_index = DM_I_QRYTEXT_TAB_ID; 	
	status = qeu_open(qef_cb, &qqeu);
	if (status != E_DB_OK)
	{
	    error = qqeu.error.err_code;
	    break;
	}
	qtext_opened = TRUE;

	aqeu.qeu_count = 1;	   	    /* Initialize alarm-specific qeu */
        aqeu.qeu_tup_length = sizeof(DB_SECALARM);
	aqeu.qeu_output = &aqef_data;
	aqef_data.dt_next = NULL;
        aqef_data.dt_size = sizeof(DB_SECALARM);
        aqef_data.dt_data = (PTR)&atuple;

	qqeu.qeu_count = 1;	   	    /* Initialize qtext-specific qeu */
        qqeu.qeu_tup_length = sizeof(DB_IIQRYTEXT);
	qqeu.qeu_output = &qqef_data;
	qqef_data.dt_next = NULL;
        qqef_data.dt_size = sizeof(DB_IIQRYTEXT);
        qqef_data.dt_data = (PTR)&qtuple;

	/*
	** If DROP SECURITY_ALARM then position iisecalarm table based on 
	** alarm name or numbr
	** and drop the specific alarm (if we can't find it issue an error).
	** Positioning is done via qeu_qalarm_by_name/id.  
	** If DROP TABLE then fetch and drop ALL alarms applied to the table.
	*/
	aqeu.qeu_getnext = QEU_REPO;
	if (from_drop_alarm)		
	{
	    /*
	    ** Might be scanning for database/installation alarms
	    ** or special DROP ALL processing.
	    */
            atuple_name   = (DB_SECALARM *)qeuq_cb->qeuq_uld_tup->dt_data;
	    alarm_name=(char*)&atuple_name->dba_alarmname;

	    /*
	    ** alarmno -1 indicates all alarms when qualifying
	    */
	    if(qeuq_cb->qeuq_permit_mask & QEU_DROP_ALL)
		atuple_name->dba_alarmno= -1;
	    /* Get alarm that matches alarm name (qualified) */
	    qparams.qeu_qparms[0] = (PTR) atuple_name;
	    aqeu.qeu_klen = 0;				/* Not keyed */
	    aqeu.qeu_qual = qeu_qalarm_by_name;
	    aqeu.qeu_qarg = &qparams;
	}
	else				/* DROP TABLE */
	{
	    /* Get alarm that applies to specific table id (keyed) */
	    obj_type=DBOB_TABLE;
	    alarm_name="unknown";

	    aqeu.qeu_klen = 3;
	    aqeu.qeu_key = akey_ptr_array;
	    akey_ptr_array[0] = &akey_array[0];
	    akey_ptr_array[1] = &akey_array[1];
	    akey_ptr_array[2] = &akey_array[2];

	    akey_ptr_array[0]->attr_number = DM_1_IISECALARM_KEY;
	    akey_ptr_array[0]->attr_operator = DMR_OP_EQ;
	    akey_ptr_array[0]->attr_value = (char*)&obj_type;

	    akey_ptr_array[1]->attr_number = DM_2_IISECALARM_KEY;
	    akey_ptr_array[1]->attr_operator = DMR_OP_EQ;
	    akey_ptr_array[1]->attr_value =
				    (char *)&qeuq_cb->qeuq_rtbl->db_tab_base;
	    akey_ptr_array[2]->attr_number = DM_3_IISECALARM_KEY;
	    akey_ptr_array[2]->attr_operator = DMR_OP_EQ;
	    akey_ptr_array[2]->attr_value =
				    (char *)&qeuq_cb->qeuq_rtbl->db_tab_index;
	    aqeu.qeu_qual = NULL;
	    aqeu.qeu_qarg = NULL;
	}
	for (;;)		/* For all alarm tuples found */
	{
	    status = qeu_get(qef_cb, &aqeu);
	    if (status != E_DB_OK)
	    {
		if (aqeu.error.err_code == E_QE0015_NO_MORE_ROWS)
		{
		    if (drop_specific_alarm)
		    {
			(VOID)qef_error(E_US2473_9331_ALARM_ABSENT, 0L,
				    E_DB_ERROR, &error, &qeuq_cb->error, 1,
				    qec_trimwhite(sizeof(atuple_name->dba_alarmname),
						alarm_name),
				    (PTR)alarm_name);
			error = E_QE0000_OK;
			status=E_DB_OK;
		    }
		    else	/* No [more] alarms for table */
		    {
			error = E_QE0000_OK;
			status = E_DB_OK;
		    }
		}
		else	/* Other error */
		{
		    error = aqeu.error.err_code;
		}
		break;
	    } /* If no alarms found */
	    aqeu.qeu_getnext = QEU_NOREPO;
            aqeu.qeu_klen = 0;
	    
	    status = E_DB_OK;

            /* Postion iiqrytxt table for query id associated with this alarm */
	    qkey_ptr_array[0] = &qkey_array[0];
	    qkey_ptr_array[1] = &qkey_array[1];
	    qqeu.qeu_getnext = QEU_REPO;
	    qqeu.qeu_klen = 2;       
	    qqeu.qeu_key = qkey_ptr_array;
	    qkey_ptr_array[0]->attr_number = DM_1_QRYTEXT_KEY;
	    qkey_ptr_array[0]->attr_operator = DMR_OP_EQ;
	    qkey_ptr_array[0]->attr_value =
				(char *)&atuple.dba_txtid.db_qry_high_time;
	    qkey_ptr_array[1]->attr_number = DM_2_QRYTEXT_KEY;
	    qkey_ptr_array[1]->attr_operator = DMR_OP_EQ;
	    qkey_ptr_array[1]->attr_value =
				(char *)&atuple.dba_txtid.db_qry_low_time;
	    qqeu.qeu_qual = NULL;
	    qqeu.qeu_qarg = NULL;
	    for (;;)		/* For all query text tuples */
	    {
		status = qeu_get(qef_cb, &qqeu);
		if (status != E_DB_OK)
		{
		    error = qqeu.error.err_code;
		    break;
		}
		qqeu.qeu_klen = 0;
		qqeu.qeu_getnext = QEU_NOREPO;
		status = qeu_delete(qef_cb, &qqeu);
		if (status != E_DB_OK)
		{
		    error = qqeu.error.err_code;
		    break;
		}
	    } /* For all query text tuples */
	    if (error != E_QE0015_NO_MORE_ROWS)
		break;

	    if(atuple.dba_objtype==DBOB_TABLE)
	    {
    		DMT_CHAR_ENTRY  	char_spec;	
    		DMT_CB	    	dmt_cb;
	    	/* 
            	** Alter the table relstat to flag alarms. This 
		** validates that the table exists and ensures that we 
		** get an exclusive lock on it.
           	*/
	    	char_spec.char_id = DMT_C_ALARM;    
	    	char_spec.char_value = DMT_C_ON;
		MEfill(sizeof(DMT_CB), 0, (PTR) &dmt_cb);
	    	dmt_cb.dmt_flags_mask = 0;
	    	dmt_cb.dmt_db_id = qeuq_cb->qeuq_db_id;
	    	dmt_cb.dmt_char_array.data_in_size = sizeof(DMT_CHAR_ENTRY);
	    	dmt_cb.dmt_char_array.data_address = (PTR)&char_spec;
	    	dmt_cb.length = sizeof(DMT_CB);
	    	dmt_cb.type = DMT_TABLE_CB;
	    	dmt_cb.dmt_id.db_tab_base  = atuple.dba_objid.db_tab_base;
	    	dmt_cb.dmt_id.db_tab_index = atuple.dba_objid.db_tab_index;
	    	dmt_cb.dmt_tran_id = qef_cb->qef_dmt_id;
	    	status = dmf_call(DMT_ALTER, &dmt_cb);
	    	if (status != E_DB_OK)
    	    	{
		    error = dmt_cb.error.err_code;
		    if (error == E_DM0054_NONEXISTENT_TABLE)
		    {
			error = E_QE0025_USER_ERROR;
			status = E_DB_OK;	/* Still remove the alarm */
		    }
		    else
		    {
			/* 
			** Some other error
			*/
	        	break;
		    }
	    	}
	     }
	     else if(!(atuple.dba_flags&DBA_ALL_DBS))
	     {
		/*
		** Check access to the  database, also get the security label
		** for later use
		*/
	    	status=qeu_db_exists(qef_cb, qeuq_cb,
		    (DB_DB_NAME *)&atuple.dba_objname, SXF_A_CONTROL, &objowner);
	    	if(status==E_DB_ERROR)
	    	{
			/* Error, no access to database */
			break;
	    	}
	    	else  if  (status==E_DB_WARN)
	    	{
			/* Database not found */
			status=E_DB_ERROR;
			/* E_US2474_9332_ALARM_NO_DB */
	        	(VOID)qef_error(9332, 0L, E_DB_ERROR,
			    &error, &qeuq_cb->error, 1,
			    qec_trimwhite(sizeof(atuple.dba_objname),
					  (char *)&atuple.dba_objname),
			    (PTR)&atuple.dba_objname);
			break;
		}
	    }
	    /* Now delete the current alarm tuple */
	    status = qeu_delete(qef_cb, &aqeu);
	    if (status != E_DB_OK)
	    {
		error = aqeu.error.err_code;
		break;
	    }
		
	    /*
	    ** If  doing a specific DROP SECURITY_ALARM we're done with this 
	    ** loop. 
	    ** Otherwise continue with next alarm applied to table.
	    */
	    if (drop_specific_alarm)
		break;
	} /* For all alarm found */

	if (status != E_DB_OK)
	    break;

	break;
    } /* End dummy for loop */

    /* Handle any error messages */
    if (status != E_DB_OK)
	(VOID) qef_error(error, 0L, status, &error, &qeuq_cb->error, 0);
    
    /* Close off all the tables and transaction */
    if (alarm_opened)
    {
	local_status = qeu_close(qef_cb, &aqeu);    
	if (local_status != E_DB_OK)
	{
	    (VOID) qef_error(aqeu.error.err_code, 0L, local_status, 
			     &error, &qeuq_cb->error, 0);
	    if (local_status > status)
		status = local_status;
	}
    }
    if (qtext_opened)
    {
	local_status = qeu_close(qef_cb, &qqeu);    
	if (local_status != E_DB_OK)
	{
	    (VOID) qef_error(qqeu.error.err_code, 0L, local_status, 
			     &error, &qeuq_cb->error, 0);
	    if (local_status > status)
		status = local_status;
	}
    }
    if (transtarted)
    {
	if (status == E_DB_OK)
	    local_status = qeu_etran(qef_cb, &tranqeu);
	else
	    local_status = qeu_atran(qef_cb, &tranqeu);
	if (local_status != E_DB_OK)
	{
	    (VOID) qef_error(tranqeu.error.err_code, 0L, local_status, 
			     &error, &qeuq_cb->error, 0);
	    if (local_status > status)
		status = local_status;
	}
    }
    /*
    ** Dropping an alarm is a control operation on the base object
    ** (database/table).
    */
    if( from_drop_alarm==TRUE && Qef_s_cb->qef_state & QEF_S_C2SECURE )
    {
        if(atuple.dba_objtype==DBOB_DATABASE)
        {
	    evtype=SXF_E_DATABASE;
	    /*
	    ** Database label/owner should be set in db_exists request above
	    */
        }
        else
        {
	    evtype=SXF_E_TABLE;
        }
        if(status==E_DB_OK)
	    access=(SXF_A_CONTROL|SXF_A_SUCCESS);
        else
	    access=(SXF_A_CONTROL|SXF_A_FAIL);
        if(qeu_secaudit(FALSE, qef_cb->qef_ses_id,
		(char *)&atuple.dba_objname,
		&objowner,
		sizeof(atuple.dba_objname), 
		evtype,
		I_SX202E_ALARM_DROP,
		access,
		&e_error)!=E_DB_OK)
        {
	    error = e_error.err_code;
	    status=E_DB_ERROR;
        }
    }
    if(status!=E_DB_OK)
    {
    	(VOID) qef_error(E_QE028C_DROP_ALARM_ERR, 0L, local_status, 
		     &error, &qeuq_cb->error, 0);
	qeuq_cb->error.err_code= E_QE0025_USER_ERROR;
    }
    return (status);
} /* qeu_dsecalarm */
예제 #10
0
DB_STATUS
qeu_csecalarm(
QEF_CB          *qef_cb,
QEUQ_CB		    *qeuq_cb)
{
    DB_IIQRYTEXT	*qtuple;	/* Alarm text */
    DB_SECALARM    	*atuple;	/* New alarm tuple */
    DB_SECALARM    	atuple_temp;	/* Tuple to check for uniqueness */
    DB_STATUS	    	status, local_status;
    i4	    	error=0;
    bool	    	transtarted = FALSE;	    
    bool	    	tbl_opened = FALSE;
    i4		    	i;		/* Querytext tuple counter */
    QEF_DATA	    	*next;		/*	     and data pointer       */
    QEU_CB	    	tranqeu;
    QEU_CB	    	qeu;
    QEU_QUAL_PARAMS	qparams;
    DB_QRY_ID	    	qryid;		/* Ids for query text */
    QEF_DATA	    	qef_data;
    bool		loop=FALSE;
    QEF_RCB		qef_rcb;
    i4		number;
    DMR_ATTR_ENTRY  	akey_array[3];
    DMR_ATTR_ENTRY  	*akey_ptr_array[3];
    DMT_CHAR_ENTRY  	char_spec;	/* DMT_ALTER specification */
    DMT_CB	    	dmt_cb;
    DB_ERROR 		e_error;
    SXF_ACCESS		access;
    SXF_EVENT		evtype;
    DB_OWN_NAME		objowner;

    do
    {
	MEfill(sizeof(objowner),' ',(PTR)&objowner);

	/* Validate CB and parameters */
	if (qeuq_cb->qeuq_type != QEUQCB_CB ||
            qeuq_cb->qeuq_length != sizeof(QEUQ_CB))	
	{
	    status = E_DB_ERROR;
	    error = E_QE0017_BAD_CB;
	    break;
	}
	if (   qeuq_cb->qeuq_cq == 0 || qeuq_cb->qeuq_qry_tup == NULL
            || ( qeuq_cb->qeuq_uld_tup == NULL)
            || (qeuq_cb->qeuq_db_id == NULL)
            || (qeuq_cb->qeuq_d_id == 0))
	{
	    status = E_DB_ERROR;
	    error = E_QE0018_BAD_PARAM_IN_CB;
	    break;
	}
        qef_rcb.qef_cb = qef_cb;
        qef_rcb.qef_db_id = qeuq_cb->qeuq_db_id;
        qef_cb->qef_dbid = qeuq_cb->qeuq_db_id;
		
	/* 
	** Check to see if transaction is in progress, if so set a local
	** transaction, otherwise we'll use the user's transaction.
	*/
	if (qef_cb->qef_stat == QEF_NOTRAN)
	{
	    tranqeu.qeu_type = QEUCB_CB;
	    tranqeu.qeu_length = sizeof(QEUCB_CB);
	    tranqeu.qeu_db_id = qeuq_cb->qeuq_db_id;
	    tranqeu.qeu_d_id = qeuq_cb->qeuq_d_id;
	    tranqeu.qeu_flag = 0;
	    tranqeu.qeu_mask = 0;
	    status = qeu_btran(qef_cb, &tranqeu);
	    if (status != E_DB_OK)
	    {	
		error = tranqeu.error.err_code;
		break;	
	    }	    
	    transtarted = TRUE;
	}
	/* Escalate the transaction to MST */
	if (qef_cb->qef_auto == QEF_OFF)
	    qef_cb->qef_stat = QEF_MSTRAN;

	atuple = (DB_SECALARM *)qeuq_cb->qeuq_uld_tup->dt_data;

        /* For  database alarms, make sure the database exists */
	if(atuple->dba_objtype==DBOB_DATABASE &&
	   !(atuple->dba_flags&DBA_ALL_DBS))
	{
	    status=qeu_db_exists(qef_cb, qeuq_cb, 
		(DB_DB_NAME *)&atuple->dba_objname, SXF_A_CONTROL, &objowner);
	    if(status==E_DB_ERROR)
	    {
		/* Error checking database name */
		break;
	    }
	    else  if  (status==E_DB_WARN)
	    {
		/* Database not found */
		status=E_DB_ERROR;
		/* E_US2474_9332_ALARM_NO_DB */
	        (VOID)qef_error(9332, 0L, E_DB_ERROR,
			    &error, &qeuq_cb->error, 1,
			    qec_trimwhite(sizeof(atuple->dba_objname),
					  (char *)&atuple->dba_objname),
			    (PTR)&atuple->dba_objname);
		break;
	    }
	}
	else if(atuple->dba_objtype==DBOB_TABLE)
	{
	    /* 
            ** Alter the table relstat to flag alarms exist. This validates that
            ** the table exists and ensures that we get an exclusive lock on it.
            */
	    char_spec.char_id = DMT_C_ALARM;      /* create alarm code */
	    char_spec.char_value = DMT_C_ON;
	    MEfill(sizeof(DMT_CB), 0, (PTR) &dmt_cb);
	    dmt_cb.dmt_flags_mask = 0;
	    dmt_cb.dmt_db_id = qeuq_cb->qeuq_db_id;
	    dmt_cb.dmt_char_array.data_in_size = sizeof(DMT_CHAR_ENTRY);
	    dmt_cb.dmt_char_array.data_address = (PTR)&char_spec;
	    dmt_cb.length = sizeof(DMT_CB);
	    dmt_cb.type = DMT_TABLE_CB;
	    dmt_cb.dmt_id.db_tab_base  = atuple->dba_objid.db_tab_base;
	    dmt_cb.dmt_id.db_tab_index = atuple->dba_objid.db_tab_index;
	    dmt_cb.dmt_tran_id = qef_cb->qef_dmt_id;
	    status = dmf_call(DMT_ALTER, &dmt_cb);
	    if (status != E_DB_OK)
    	    {
	        error = dmt_cb.error.err_code;
	        break;
	    }
	}
	/* Get a unique query id */
	TMnow((SYSTIME *)&qryid);
	atuple->dba_txtid.db_qry_high_time = qryid.db_qry_high_time;
	atuple->dba_txtid.db_qry_low_time  = qryid.db_qry_low_time;

	/* Get a unique alarm id */
        
        status = qea_reserveID(&atuple->dba_alarmid, 
			qef_cb, &qef_rcb.error);

	if (status != E_DB_OK)
	{   
		error = qef_rcb.error.err_code;  
		break; 
	}
	/*
	** Generate an alarm name if needed, all blanks indicates no
	** name specified. This is required for uniqueness check below.
	*/
	if(!STskipblank( (char*)&atuple->dba_alarmname, 
				sizeof(atuple->dba_alarmname)))
	{
		status=qeu_gen_alarm_name(
			atuple->dba_objtype,
			(char*)&atuple->dba_objname,
			&qef_rcb,
			&atuple->dba_alarmid,
			(char*)&atuple->dba_alarmname,
			&error);
		if(status!=E_DB_OK)
			break;
	}
	/* Validate that the alarm name is unique */
	qeu.qeu_type = QEUCB_CB;
        qeu.qeu_length = sizeof(QEUCB_CB);
        qeu.qeu_tab_id.db_tab_base  = DM_B_IISECALARM_TAB_ID;
        qeu.qeu_tab_id.db_tab_index  = DM_I_IISECALARM_TAB_ID;
        qeu.qeu_db_id = qeuq_cb->qeuq_db_id;
        qeu.qeu_lk_mode = DMT_IX;
        qeu.qeu_flag = DMT_U_DIRECT;
        qeu.qeu_access_mode = DMT_A_WRITE;
	qeu.qeu_mask = 0;
	status = qeu_open(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened = TRUE;
	atuple->dba_alarmno=0;

	/* Retrieve the same named alarm - if not there then ok */
	qeu.qeu_count = 1;
        qeu.qeu_tup_length = sizeof(DB_SECALARM);
	qeu.qeu_output = &qef_data;
	qef_data.dt_next = NULL;
        qef_data.dt_size = sizeof(DB_SECALARM);
        qef_data.dt_data = (PTR)&atuple_temp;
	qeu.qeu_getnext = QEU_REPO;
	qeu.qeu_klen = 0;				/* Not keyed */
	qparams.qeu_qparms[0] = (PTR) atuple;	/* What we're looking for */
	qeu.qeu_qual = qeu_qalarm_by_name;
	qeu.qeu_qarg = &qparams;
	status = qeu_get(qef_cb, &qeu);
	if (status == E_DB_OK)		/* Found the same alarm! */
	{
	    (VOID)qef_error(E_US2472_9330_ALARM_EXISTS, 0L, E_DB_ERROR,
			    &error, &qeuq_cb->error, 1,
			    qec_trimwhite(sizeof(atuple->dba_alarmname),
					  (char *)&atuple->dba_alarmname),
			    (PTR)&atuple->dba_alarmname);
	    error = E_QE0025_USER_ERROR;
	    break;
	}
	if (qeu.error.err_code != E_QE0015_NO_MORE_ROWS)
	{
	    /* Some other error */
	    error = qeu.error.err_code;
	    break;
	}
	status = qeu_close(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened=FALSE;
	/*
	** Generate a unique alarm number. This is primarily for
	** backwards compatibility with "anonymous" alarms which had
	** to be dropped by number, not name.
	*/
	
	status = qeu_open(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened = TRUE;
	qeu.qeu_count = 1;
        qeu.qeu_tup_length = sizeof(DB_SECALARM);
	qeu.qeu_input = &qef_data;
	qeu.qeu_output = &qef_data;
	qef_data.dt_next = 0;
        qef_data.dt_size = sizeof(DB_SECALARM);
        qef_data.dt_data = (PTR) &atuple_temp;
	
	qeu.qeu_getnext = QEU_REPO;
	qeu.qeu_klen = 3;       
	qeu.qeu_key = akey_ptr_array;
	akey_ptr_array[0] = &akey_array[0];
	akey_ptr_array[1] = &akey_array[1];
	akey_ptr_array[2] = &akey_array[2];

	akey_ptr_array[0]->attr_number = DM_1_IISECALARM_KEY;
	akey_ptr_array[0]->attr_operator = DMR_OP_EQ;
	akey_ptr_array[0]->attr_value = (char*) &atuple->dba_objtype;

	akey_ptr_array[1]->attr_number = DM_2_IISECALARM_KEY;
	akey_ptr_array[1]->attr_operator = DMR_OP_EQ;
	akey_ptr_array[1]->attr_value = (char*) &atuple->dba_objid.db_tab_base;
        
	akey_ptr_array[2]->attr_number = DM_3_IISECALARM_KEY;
	akey_ptr_array[2]->attr_operator = DMR_OP_EQ;
	akey_ptr_array[2]->attr_value = (char*) &atuple->dba_objid.db_tab_index;
        
	qeu.qeu_qual = 0;
	qeu.qeu_qarg = 0;
     
	/* 
        ** Get all alarm tuples for this object
        ** and determine the next alarm number.
        */
	status = E_DB_OK;
	number = 0;
	while (status == E_DB_OK)
	{
            status = qeu_get(qef_cb, &qeu);
	    if (status != E_DB_OK)
	    {
		error = qeu.error.err_code;
		break;
	    }
	    qeu.qeu_getnext = QEU_NOREPO;
            qeu.qeu_klen = 0;
	    if (atuple_temp.dba_alarmno > number)
                number = atuple_temp.dba_alarmno;
	}
	if (error != E_QE0015_NO_MORE_ROWS)
	    break;
 
	/* 
        ** We have to add 1 to derive the next alarm number.
	*/
	atuple->dba_alarmno=number+1;

	/* Save the alarm tuple */
	status = E_DB_OK;
		
	/* Insert single alarm tuple */
	qeu.qeu_count = 1;
        qeu.qeu_tup_length = sizeof(DB_SECALARM);
	qeu.qeu_input = qeuq_cb->qeuq_uld_tup;
	status = qeu_append(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	status = qeu_close(qef_cb, &qeu);    
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened = FALSE;

	/* Update all query text tuples with query id - validate list */
	next = qeuq_cb->qeuq_qry_tup;
	for (i = 0; i < qeuq_cb->qeuq_cq; i++)
	{
	    qtuple = (DB_IIQRYTEXT *)next->dt_data;
	    next = next->dt_next;
	    qtuple->dbq_txtid.db_qry_high_time = qryid.db_qry_high_time;
	    qtuple->dbq_txtid.db_qry_low_time  = qryid.db_qry_low_time;
	    if (i < (qeuq_cb->qeuq_cq -1) && next == NULL)
	    {
		error = E_QE0018_BAD_PARAM_IN_CB;
		status = E_DB_ERROR;
		break;
	    }
	} /* for all query text tuples */
	if (status != E_DB_OK)
	    break;

	/* Insert all query text tuples */
	qeu.qeu_tab_id.db_tab_base = DM_B_QRYTEXT_TAB_ID;
	qeu.qeu_tab_id.db_tab_index = 0L;
	status = qeu_open(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened = TRUE;
	qeu.qeu_count = qeuq_cb->qeuq_cq;
        qeu.qeu_tup_length = sizeof(DB_IIQRYTEXT);
	qeu.qeu_input = qeuq_cb->qeuq_qry_tup;
	status = qeu_append(qef_cb, &qeu);
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	status = qeu_close(qef_cb, &qeu);    
	if (status != E_DB_OK)
	{
	    error = qeu.error.err_code;
	    break;
	}
	tbl_opened = FALSE;
	
	if (transtarted)		   /* If we started a transaction */
	{
	    status = qeu_etran(qef_cb, &tranqeu);
	    if (status != E_DB_OK)
	    {
		error = tranqeu.error.err_code;
		break;
	    }
	}
    }
    while(loop);

    /* call qef_error to handle error messages */
    if(error)
	    (VOID) qef_error(error, 0L, status, &error, &qeuq_cb->error, 0);
    
    /* Close off all the tables. */
    local_status = E_DB_OK;
    if (tbl_opened)		    /* If system table opened, close it */
    {
	local_status = qeu_close(qef_cb, &qeu);
	if (local_status != E_DB_OK)
	{
	    (VOID) qef_error(qeu.error.err_code, 0L, local_status, &error, 
		    	     &qeuq_cb->error, 0);
	    if (local_status > status)
		status = local_status;
	}
    }

    if (transtarted)		   /* If we started a transaction */
    {
        local_status = qeu_atran(qef_cb, &tranqeu);
        if (local_status != E_DB_OK)
	{
	    (VOID) qef_error(tranqeu.error.err_code, 0L, local_status, 
			     &error, &qeuq_cb->error, 0);
	    if (local_status > status)
		status = local_status;
	}
    }
  
    if ( Qef_s_cb->qef_state & QEF_S_C2SECURE )
    {
	if(atuple->dba_objtype==DBOB_DATABASE)
	{
	    evtype=SXF_E_DATABASE;
	}
	else
	{
	    evtype=SXF_E_TABLE;
	}
	/*
	** Creating an alarm is a control operation on the base object
	** (database/table)
	*/
	if(status==E_DB_OK)
	    access=(SXF_A_CONTROL|SXF_A_SUCCESS);
	else
	    access=(SXF_A_CONTROL|SXF_A_FAIL);
	if(qeu_secaudit(FALSE, qef_cb->qef_ses_id,
		    (char *)&atuple->dba_objname,
		    &objowner,
		    sizeof(atuple->dba_objname),
		    evtype,
		    I_SX202D_ALARM_CREATE,
		    access,
		    &e_error)!=E_DB_OK)
	{
		error = e_error.err_code;
		status=E_DB_ERROR;
	}
    }

    /*
    ** Log QEF create error
    */
    if(status!=E_DB_OK)
    {
    	(VOID) qef_error(E_QE028B_CREATE_ALARM_ERR, 0L, local_status, 
		     &error, &qeuq_cb->error, 0);
	qeuq_cb->error.err_code= E_QE0025_USER_ERROR;
    }
    return (status);
} /* qeu_csecalarm */
예제 #11
0
/*{
** Name: QEU_OPEN       - open a table
**
** External QEF call:   status = qef_call(QEU_OPEN, &qeu_cb);
**
** Description:
**      A table is opened. A transaction must be in progress when
** this routine is called. This routine must be called before any
** of qeu_delete, qeu_append or qeu_get is called.
** Tables are opened without DMT_NOWAIT being set and are opened for
** direct update.
**
** Inputs:
**       qeu_cb
**          .qeu_flag                       zero or QEU_SHOW_STAT
**                                          indicates if internal request for 
**                                          statistics.
**	    .qeu_eflag			    designate error handling semantis
**					    for user errors.
**		QEF_INTERNAL		    return error code.
**		QEF_EXTERNAL		    send message to user.
**          .qeu_tab_id                     table id
**          .qeu_db_id                      database id
**          .qeu_lk_mode                    lock mode
**              DMT_X                       exclusive table lock
**              DMT_S                       shared table lock
**              DMT_IX                      exclusive page lock
**              DMT_IS                      shared table lock
**              DMT_SIX                     shared table lock with ability
**                                          to exclusive lock pages
**          .qeu_access_mode                access mode
**              DMT_A_READ
**              DMT_A_WRITE
**
** Outputs:
**      qeu_cb
**          .qeu_acc_id                     table access id
**          .error.err_code                 One of the following
**                                          E_QE0000_OK
**                                          E_QE0002_INTERNAL_ERROR
**                                          E_QE0004_NO_TRANSACTION
**                                          E_QE0017_BAD_CB
**                                          E_QE0018_BAD_PARAM_IN_CB
**                                          E_QE0022_ABORTED
**                                          <DMF error messages>
**      Returns:
**          E_DB_OK
**          E_DB_ERROR                      caller error
**          E_DB_FATAL                      internal error
**      Exceptions:
**          none
**
** Side Effects:
**          none
**
** History:
**      27-may-86 (daved)
**          written
**      18-jul-89 (jennifer)
**          Added a flag to indicate that an internal request 
**          for statistical information is being requested.
**          This solves a B1 security problem where statistics
**          could be unpredicatable if B1 labels were checked.
**          For an internal request they aren't checked, for a 
**          normal query on the iihistogram and iistatistics 
**          table they are checked.
**	23-jan-91 (seputis)
**	    added support for timeout and maxlocks
**	25-mar-99 (shust01)
**	    Initialized dmt_mustlock.  On rare occasions storage happened
**	    to be equal to a 1 (TRUE), causing locks to be taken out even
**	    though readlock=nolock was set.
**	07-mar-2000 (gupsh01)
**	    Do not handle error E_DM006A_TRAN_ACCESS_CONFLICT here as it will
**	    be handled by the calling facility. (BUG 100777).
**	14-feb-03 (inkdo01)
**	    Special check for non-existant iisequence catalog, so message
**	    can be issued that database doesn't support sequences.
**	    
*/
DB_STATUS
qeu_open(
QEF_CB          *qef_cb,
QEU_CB         *qeu_cb)
{
    DMT_CB      dmt_cb;
    DB_STATUS   status;
    i4     err;
    DMT_CHAR_ENTRY  lockmode[2];
    i4		lockcount;

    MEfill(sizeof(DMT_CB), 0, (PTR) &dmt_cb);
    dmt_cb.type         = DMT_TABLE_CB;
    dmt_cb.length       = sizeof(DMT_CB);
    dmt_cb.dmt_db_id    = qeu_cb->qeu_db_id;
    STRUCT_ASSIGN_MACRO(qeu_cb->qeu_tab_id, dmt_cb.dmt_id);
    dmt_cb.dmt_flags_mask  = 0;
    if (qeu_cb->qeu_flag & QEU_SHOW_STAT)
	dmt_cb.dmt_flags_mask |= DMT_SHOW_STAT;
    if (qeu_cb->qeu_flag & QEU_BYPASS_PRIV)
	dmt_cb.dmt_flags_mask |= DMT_DBMS_REQUEST;
    dmt_cb.dmt_lock_mode   = qeu_cb->qeu_lk_mode;
    dmt_cb.dmt_update_mode = DMT_U_DIRECT;
    dmt_cb.dmt_mustlock    = FALSE;
    dmt_cb.dmt_access_mode = qeu_cb->qeu_access_mode;
    lockcount = 0;
    if (qeu_cb->qeu_mask & QEU_TIMEOUT)
    {
	lockmode[lockcount].char_id = DMT_C_TIMEOUT_LOCK;
	lockmode[lockcount].char_value = qeu_cb->qeu_timeout;
	lockcount++;
    }
    if (qeu_cb->qeu_mask & QEU_MAXLOCKS)
    {
	lockmode[lockcount].char_id = DMT_C_PG_LOCKS_MAX;
	lockmode[lockcount].char_value = qeu_cb->qeu_maxlocks;
	lockcount++;
    }
    if (lockcount > 0)
    {
	dmt_cb.dmt_char_array.data_address = (PTR)lockmode;
	dmt_cb.dmt_char_array.data_in_size = sizeof(lockmode[0]) * lockcount;
	dmt_cb.dmt_char_array.data_out_size = 0;
    }
    else
	dmt_cb.dmt_char_array.data_in_size = 0;

    dmt_cb.dmt_sequence	   = qef_cb->qef_stmt;

    /* QEU_OPEN is only valid in a transaction */
    if (qef_cb->qef_stat == QEF_NOTRAN)
    {
        qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err,
            &qeu_cb->error, 0);
        return (E_DB_ERROR);
    }
    dmt_cb.dmt_tran_id = qef_cb->qef_dmt_id;
    status = dmf_call(DMT_OPEN, &dmt_cb);
    if (status == E_DB_OK)
    {
        qeu_cb->qeu_acc_id = dmt_cb.dmt_record_access_id;
        qef_cb->qef_open_count++;
    }
    else 
    {
	/* 
	** Do not handle the dmf error E_DM006A_TRAN_ACCESS_CONFLICT here  
	** as it is being handled by the calling facility BUG: 100777 
	**/
	if (dmt_cb.error.err_code == E_DM006A_TRAN_ACCESS_CONFLICT)
	{
	    qeu_cb->error.err_code = dmt_cb.error.err_code;
	    qeu_cb->error.err_data = dmt_cb.error.err_data;
	}
	else if (dmt_cb.error.err_code == E_DM0054_NONEXISTENT_TABLE &&
	    qeu_cb->qeu_tab_id.db_tab_base == DM_B_SEQ_TAB_ID)
         qef_error(E_QE00A1_IISEQ_NOTDEFINED, 0L, status, &err, 
						&qeu_cb->error, 0);
	else qef_error(dmt_cb.error.err_code, 0L, status, &err, 
						&qeu_cb->error, 0);
    }
    return (status);
}
예제 #12
0
/*{
** Name: QEU_GET        - get tuples from an open table
**
** External QEF call:   status = qef_call(QEU_GET, &qeu_cb);
**
** Description:
**      Tuples are retrieved from an open table. 
**
** Inputs:
**       qeu_cb
**	    .qeu_eflag			    designate error handling semantis
**					    for user errors.
**		QEF_INTERNAL		    return error code.
**		QEF_EXTERNAL		    send message to user.
**          .qeu_acc_id                     table access id
**          .qeu_tup_length                 length of retrieved tuple
**          .qeu_count                      number of tuples to retrieve
**          .qeu_getnext                    reposition	
**              QEU_REPO		    repostion using key
**		QEU_NOREPO		    continue from previous call to
**					    this routine
**          .qeu_klen                       length of key - number of entries
**          .qeu_key                        key for retrieve
**          .qeu_qual                       qualification function
**          .qeu_qarg                       argument to qualification function
**	    .qeu_flag			    operation qualifier
**		QEU_BY_TID		    get tuple by TID - will only be
**					    considered if !QEU_REPO
**	    .qeu_tid                        contains TID of the tuple to be
**					    retrieved
**          .qeu_output                     output buffer
**      <qeu_key> is a pointer to an array of pointers of type DMR_ATTR_ENTRY
**              .attr_number
**              .attr_operation
**              .attr_value_ptr
**
** Outputs:
**      qeu_cb
**          .qeu_count                      number of tuples retrieved
**          .error.err_code                 One of the following
**                                          E_QE0000_OK
**                                          E_QE0002_INTERNAL_ERROR
**                                          E_QE0004_NO_TRANSACTION
**                                          E_QE0007_NO_CURSOR
**                                          E_QE0017_BAD_CB
**                                          E_QE0018_BAD_PARAM_IN_CB
**                                          E_QE0015_NO_MORE_ROWS
**                                          E_QE0022_ABORTED
**					    E_QE0015_NO_MORE_ROWS
**          .qeu_output                     output buffer
**      Returns:
**          E_DB_OK
**          E_DB_WARN
**          E_DB_ERROR                      caller error
**          E_DB_FATAL                      internal error
**      Exceptions:
**          none
**
** Side Effects:
**          the output buffers are filled in
**
** History:
**      27-may-86 (daved)
**          written
**      31-jul-86 (jennifer)
**          Modified qeu_get to not allocate output
**          from memory stream, but to assume output
**          array is already initialized.
**      20-aug-86 (jennifer)
**          When dmf returns nonext, then qef must
**          return no-more-rows.
**	10-oct-87 (puree)
**	    Same as above even during positioning.
**	04-jan-90 (andre)
**	    return tid of the last tuple which was successfully read in
**	    QU_CB->qeu_tid
**	17-jun-92 (andre)
**	    add support for retrieval by TID - qeu_gentext should NOT be set to
**	    QEU_REPO
**	27-jul-96 (ramra01)
**	    Alter table project: Position only flag on qeu_get.
**	11-Apr-2008 (kschendel)
**	    Revised DMF qualification requirements, simplified for QEU.
*/
DB_STATUS
qeu_get(
QEF_CB          *qef_cb,
QEU_CB          *qeu_cb)
{
    i4     err;
    DMR_CB      dmr_cb;
    i4     count;          /* number of tuples returned */
    i4		i;
    DB_STATUS   status;
    PTR         tuple;
    QEF_DATA    *dataptr;

    count = qeu_cb->qeu_count;		/* number of rows to get */
    qeu_cb->qeu_count = 0;

    /* QEU_GET is only valid in a transaction */
    if (qef_cb->qef_stat == QEF_NOTRAN)
    {
        qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err,
            &qeu_cb->error, 0);
        return (E_DB_ERROR);
    }
    dmr_cb.type                 = DMR_RECORD_CB;
    dmr_cb.length               = sizeof(DMR_CB);
    dmr_cb.dmr_access_id        = qeu_cb->qeu_acc_id;
    dmr_cb.dmr_tid              = 0;                    /* not used */
    dmr_cb.dmr_q_fcn		= NULL;
    /* if positioning the cursor */
    if (qeu_cb->qeu_getnext == QEU_REPO)
    {
        /* if there is a key, position by qual. Else, position all records */
        if (qeu_cb->qeu_klen == 0)
            dmr_cb.dmr_position_type = DMR_ALL;
        else
        {
            /* set the keys */
            dmr_cb.dmr_position_type = DMR_QUAL;
	    dmr_cb.dmr_attr_desc.ptr_address    = (PTR) qeu_cb->qeu_key;
	    dmr_cb.dmr_attr_desc.ptr_in_count   = qeu_cb->qeu_klen;
	    dmr_cb.dmr_attr_desc.ptr_size	= sizeof (DMR_ATTR_ENTRY);
	    dmr_cb.dmr_s_estimated_records	= -1;
        }
        /* row qualifier */
        dmr_cb.dmr_q_fcn = (DB_STATUS (*)(void *,void *)) qeu_cb->qeu_qual;
        dmr_cb.dmr_q_arg = (PTR) qeu_cb->qeu_qarg;
	if (qeu_cb->qeu_qual != NULL)
	{
	    dmr_cb.dmr_q_rowaddr = &qeu_cb->qeu_qarg->qeu_rowaddr;
	    dmr_cb.dmr_q_retval = &qeu_cb->qeu_qarg->qeu_retval;
	}
        dmr_cb.dmr_flags_mask = 0;
        status = dmf_call(DMR_POSITION, &dmr_cb);
        if (status != E_DB_OK)
        {
            if (dmr_cb.error.err_code == E_DM0055_NONEXT)
                qeu_cb->error.err_code = E_QE0015_NO_MORE_ROWS;
            else
            {
                qef_error(dmr_cb.error.err_code, 0L, status, &err, 
		    &qeu_cb->error, 0);
            }
            return (status);
        }
    }

    if (qeu_cb->qeu_flag & QEU_POSITION_ONLY)
       return (E_DB_OK);

    /* We can now start getting records */
    /* point to space for the first tuple */
    /* the tuple length will not change. Tell DMF about it */
    dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_tup_length;

    /* assign the beginning of the output chain */
    dataptr = qeu_cb->qeu_output;
    tuple = dataptr->dt_data;
    i = 0;

    /*
    ** if qeu_getnexdt was not set to QEU_REPO and QEU_BY_TID was set in
    ** qeu_flag, tell dmr_get() to get a tuple with specified TID; otherwise
    ** tell it to get the next row
    */
    if (qeu_cb->qeu_getnext != QEU_REPO && qeu_cb->qeu_flag & QEU_BY_TID)
    {
	dmr_cb.dmr_flags_mask = DMR_BY_TID;
	dmr_cb.dmr_tid = qeu_cb->qeu_tid;
    }
    else
    {
	dmr_cb.dmr_flags_mask = DMR_NEXT;
    }

    for (;;)
    {
        /* get the tuple */
        dmr_cb.dmr_data.data_address = tuple;
        status = dmf_call(DMR_GET, &dmr_cb);
        if (status != E_DB_OK)
        {
            if (dmr_cb.error.err_code == E_DM0055_NONEXT)
	    {
		qeu_cb->error.err_code = E_QE0015_NO_MORE_ROWS;
                break;
	    }
            else
            {
                qef_error(dmr_cb.error.err_code, 0L, status, &err, 
		    &qeu_cb->error, 0);
                return (status);
            }
        }

	/* save TID of the last tuple read */
	qeu_cb->qeu_tid = dmr_cb.dmr_tid;

        /*
	** get space for next tuple - if retrieving by TID we never want to get
	** more than one tuple
	*/
        if (++i < count && dmr_cb.dmr_flags_mask != DMR_BY_TID)
        {
            /* move to next entry in the output chain */
            dataptr = dataptr->dt_next;
            tuple = dataptr->dt_data;
        }
        else
            break;
    }
    /* assign output value */
    qeu_cb->qeu_count = i;
    return (status);
}
예제 #13
0
/*{
** Name: QEU_DELETE     - delete tuples from a table
**
** External QEF call:   status = qef_call(QEU_DELETE, &qeu_cb);
**
** Description:
**      Tuples are deleted from a table opened with the QEU_OPEN
** command. If no qualification is given, the current tuple is 
** deleted.
**
** Inputs:
**       qeu_cb
**	    .qeu_eflag			    designate error handling semantis
**					    for user errors.
**		QEF_INTERNAL		    return error code.
**		QEF_EXTERNAL		    send message to user.
**          .qeu_acc_id                     table access id
**          .qeu_tup_length                 tuple length of the table
**					    Only required for keyed delete
**          .qeu_qual                       qualification function
**          .qeu_qarg                       argument to qualification function
**          .qeu_klen                       length of key - number of entries
**          .qeu_key                        key for delete
**      <qeu_key> is a pointer to an array of pointers of type DMR_ATTR_ENTRY
**              .attr_number
**              .attr_operation
**              .attr_value_ptr
**	    .qeu_flag			    operation qualifier
**		QEU_BY_TID		    remove tuple whose TID is in qeu_tid
**	    .qeu_tid			    contains TID of the tuple to be
**					    removed if (qeu_flag & QEU_BY_TID)
**
** Outputs:
**      qeu_cb
**          .qeu_count                      number of tuples retrieved
**          .error.err_code                 One of the following
**                                          E_QE0000_OK
**                                          E_QE0002_INTERNAL_ERROR
**                                          E_QE0004_NO_TRANSACTION
**                                          E_QE0007_NO_CURSOR
**                                          E_QE0017_BAD_CB
**                                          E_QE0018_BAD_PARAM_IN_CB
**      Returns:
**          E_DB_OK
**          E_DB_ERROR                      caller error
**          E_DB_FATAL                      internal error
**      Exceptions:
**          none
**
** Side Effects:
**          none
**
** History:
**      27-may-86 (daved)
**          written
**      02-sep-86 (jennifer)
**          Modified qeu_delete to return a count of tuples 
**          deleted.
**	21-oct-86 (daved)
**	    did above fix for case where dmf returns no more rows.
**	22-dec-86 (daved)
**	    return OK if deleting keyed records
**      10-dec-87 (puree)
**          Converted all ulm_palloc to qec_palloc
**	04-jan-91 (andre)
**	    added functionality to delete tuples by TID
**	18-jun-92 (andre)
**	    do not allocate memory unless we will actually be reading tuples,
**	    i.e. if a key is specified
**	06-mar-96 (nanpr01)
**	    removed the dependency on DB_MAXTUP for increased tuple size
**	    project. Also added the check to make sure tuple size is set
**	    whoever called this routine.  Also tuple size consistency is
**	    checked iff qeu_klen > 0.
**	24-Jan-2001 (jenjo02)
**	    Ensure that memory stream is closed before returning.
**	11-Apr-2008 (kschendel)
**	    Revised DMF qualification requirements, simplified for QEU.
*/
DB_STATUS
qeu_delete(
QEF_CB          *qef_cb,
QEU_CB          *qeu_cb)
{
    i4         err;
    i4              count;
    DMR_CB          dmr_cb;
    DB_STATUS       status;
    GLOBALREF QEF_S_CB *Qef_s_cb;
    ULM_RCB         ulm;        /* so we don't need to allocate a tuple buffer
                                ** as a stack variable, use dynamic memory
                                */

    count = 0;
    qeu_cb->qeu_count = 0;
    qeu_cb->error.err_code = E_QE0000_OK;

    /* QEU_DELETE is only valid in a transaction */
    if (qef_cb->qef_stat == QEF_NOTRAN)
    {
        qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err,
            &qeu_cb->error, 0);
        return (E_DB_ERROR);
    }
    dmr_cb.type                 = DMR_RECORD_CB;
    dmr_cb.length               = sizeof(DMR_CB);
    dmr_cb.dmr_access_id        = qeu_cb->qeu_acc_id;
    dmr_cb.dmr_q_fcn		= NULL;

    /* position the cursor */
    /* if there is a key, position by qual. Else, position all records */
    if (qeu_cb->qeu_klen)
    {
        if (qeu_cb->qeu_tup_length <= 0)
        {
            qef_error(E_QE0018_BAD_PARAM_IN_CB, 0L, E_DB_ERROR, &err,
                &qeu_cb->error, 0);
            return (E_DB_ERROR);
        }
	/* allocate memory for a tuple only if planning to call qeu_get() */
	
	STRUCT_ASSIGN_MACRO(Qef_s_cb->qef_d_ulmcb, ulm);
	/* Open stream and allocate tuple memory in one action */
	ulm.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC;
	ulm.ulm_psize = ulm.ulm_blocksize = qeu_cb->qeu_tup_length;

	if ((status = qec_mopen(&ulm)) != E_DB_OK)
	{
	    qef_error(E_QE001E_NO_MEM, 0L, E_DB_ERROR, &err,
		&qeu_cb->error, 0);
	    return (status);
	}

        /* set the keys */
        dmr_cb.dmr_position_type = DMR_QUAL;
        dmr_cb.dmr_attr_desc.ptr_address    = (PTR) qeu_cb->qeu_key;
        dmr_cb.dmr_attr_desc.ptr_in_count   = qeu_cb->qeu_klen;
	dmr_cb.dmr_attr_desc.ptr_size	    = sizeof (DMR_ATTR_ENTRY);
	dmr_cb.dmr_s_estimated_records	    = -1;

        /* row qualifier */
        dmr_cb.dmr_q_fcn = (DB_STATUS (*)(void *,void *)) qeu_cb->qeu_qual;
        dmr_cb.dmr_q_arg = (PTR) qeu_cb->qeu_qarg;
	if (qeu_cb->qeu_qual != NULL)
	{
	    dmr_cb.dmr_q_rowaddr = &qeu_cb->qeu_qarg->qeu_rowaddr;
	    dmr_cb.dmr_q_retval = &qeu_cb->qeu_qarg->qeu_retval;
	}
	dmr_cb.dmr_flags_mask = 0;
        status = dmf_call(DMR_POSITION, &dmr_cb);
        if (status != E_DB_OK)
        {
	    ulm_closestream(&ulm);
	    if (dmr_cb.error.err_code == E_DM0055_NONEXT)
		return (E_DB_OK);

            qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0);
            return (status);
        }
        /* the tuple length will not change. Tell DMF about it */
	dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_tup_length;
	dmr_cb.dmr_data.data_address = ulm.ulm_pptr;
    }

    for (;;)
    {
        if (qeu_cb->qeu_klen)
	{
            /* get the tuple */
            dmr_cb.dmr_flags_mask = DMR_NEXT;
            status = dmf_call(DMR_GET, &dmr_cb);
            if (status != E_DB_OK)
            {
                if (dmr_cb.error.err_code == E_DM0055_NONEXT)
		{
		    status = E_DB_OK;
                    break;
		}
                else
                {
                    qef_error(dmr_cb.error.err_code, 0L, status, 
                        &err, &qeu_cb->error, 0);
                }
                break;
            }
	}
	/*
	** delete the tuple: if deleting by TID, copy qeu_tid to dmr_tid and set
	** dmr_flags_mask to DMR_BY_TID
	*/
	if (qeu_cb->qeu_flag & QEU_BY_TID)
	{
	    dmr_cb.dmr_flags_mask = DMR_BY_TID;
	    dmr_cb.dmr_tid = qeu_cb->qeu_tid;
	}
	/* otherwise delete the current tuple */
	else
	{
	    dmr_cb.dmr_flags_mask = DMR_CURRENT_POS;
	}

        status = dmf_call(DMR_DELETE, &dmr_cb);
        if (status != E_DB_OK)
        {
            qef_error(dmr_cb.error.err_code, 0L, status, 
                &err, &qeu_cb->error, 0);
            break;
        }
	count++;
	if (qeu_cb->qeu_klen == 0)
	{
	    /* we are only deleting current tuple */
	    break;        
        }
    }
    
    if (qeu_cb->qeu_klen)
    {
	/* don't try to close a stream unless it was opened */
	ulm_closestream(&ulm);
    }
    
    qeu_cb->qeu_count = count;
    return (status);
}
예제 #14
0
/*{
** Name: QEU_APPEND     - append rows to table
**
** External QEF call:   status = qef_call(QEU_APPEND, &qeu_cb);
**
** Description:
**      This routine appends N tuples to an opened table. The table
** must have been opened with the QEU_OPEN command. This operation
** is valid only in an internal transaction (see QET.C).
**
** Inputs:
**       qeu_cb
**	    .qeu_eflag			    designate error handling semantis
**					    for user errors.
**		QEF_INTERNAL		    return error code.
**		QEF_EXTERNAL		    send message to user.
**          .qeu_acc_id                     table access id
**          .qeu_count                      number of tuples to append
**          .qeu_tup_length                 lenth of each tuple
**          .qeu_input                      input buffer
**					    
**
** Outputs:
**      qeu_cb
**          .qeu_count                      Number of tuples appended
**          .error.err_code                 One of the following
**                                          E_QE0000_OK
**                                          E_QE0002_INTERNAL_ERROR
**                                          E_QE0004_NO_TRANSACTION
**                                          E_QE0007_NO_CURSOR
**                                          E_QE0017_BAD_CB
**                                          E_QE0018_BAD_PARAM_IN_CB
**      Returns:
**          E_DB_OK
**          E_DB_ERROR                      caller error
**          E_DB_FATAL                      internal error
**      Exceptions:
**          none
**
** Side Effects:
**          none
**
** History:
**      27-may-86 (daved)
**          written
**	14-jul-93 (ed)
**	    replacing <dbms.h> by <gl.h> <sl.h> <iicommon.h> <dbdbms.h>
**	26-jul-93 (walt)
**	    Initialize the local variable "status" in qeu_append to E_DB_OK.
**	    If there are no rows to append it's possible to hit the closing
**	    return(status) statement without ever assigning status a
**	    non-garbage value.
**      01-feb-94 (stial01)
**          BUG 66409: copy from is hanging if DM0151_SI_DUPLICATE_KEY_STMT,
**          If this error occurs process it like the other duplicate errors. 
*/
DB_STATUS
qeu_append(
QEF_CB      *qef_cb,
QEU_CB      *qeu_cb)
{
    i4     err;
    DMR_CB      dmr_cb;
    i4     count;              /* number of tuples to appended */
    DB_STATUS   status = E_DB_OK;
    QEF_DATA    *dataptr;
    i4          i;
    i4		num_appended;	    /* number of tuples appended */

    count = qeu_cb->qeu_count;
    qeu_cb->qeu_count = 0;

    /* QEU_APPEND is only valid in a transaction */
    if (qef_cb->qef_stat == QEF_NOTRAN)
    {
        qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err,
            &qeu_cb->error, 0);
        return (E_DB_ERROR);
    }
    dmr_cb.type                 = DMR_RECORD_CB;
    dmr_cb.length               = sizeof(DMR_CB);
    dmr_cb.dmr_flags_mask	= 0;
    dmr_cb.dmr_access_id        = qeu_cb->qeu_acc_id;
    dmr_cb.dmr_tid              = 0;                    /* not used */
    dataptr                     = qeu_cb->qeu_input;    
    /* start appending rows */
    num_appended = 0;
    for (i = 0; i < count; i++)
    {
        dmr_cb.dmr_data.data_address = dataptr->dt_data;
        dmr_cb.dmr_data.data_in_size = dataptr->dt_size;
        status = dmf_call(DMR_PUT, &dmr_cb);
        if (status != E_DB_OK)
        {
	    /* *** FIXME *** This is insanely stupid -- dup rows/keys
	    ** are just ignored.  That was bad enough for COPY FROM,
	    ** which no longer comes here, but it seems that a bunch of
	    ** the QEU hurlers EXPECT a silent success on dup key/row.
	    ** Someday, root that crap out, and allow this routine to
	    ** treat errors in some rational manner...
	    */

	    if (dmr_cb.error.err_code == E_DM0046_DUPLICATE_RECORD ||
		  dmr_cb.error.err_code == E_DM0045_DUPLICATE_KEY ||
		  dmr_cb.error.err_code == E_DM0048_SIDUPLICATE_KEY ||
		  dmr_cb.error.err_code == E_DM0150_DUPLICATE_KEY_STMT ||
		  dmr_cb.error.err_code == E_DM0151_SIDUPLICATE_KEY_STMT)
	    {
		status = E_DB_OK;
		qeu_cb->error.err_code = dmr_cb.error.err_code;
	    }
	    else
	    {
		qef_error(dmr_cb.error.err_code, 0L, status, 
					&err, &qeu_cb->error, 0);
		return (status);
	    }
        }
        else
        {
            /* successful append */
            num_appended++;
        }
        /* next next record */
        dataptr = dataptr->dt_next;
    }
    /* tell user how many rows were appended */
    qeu_cb->qeu_count = num_appended;
    return (status);
}
예제 #15
0
/*{
** Name: QEU_REPLACE     - replace tuple(s) in a table
**
** External QEF call:   status = qef_call(QEU_REPLACE, &qeu_cb);
**
** Description:
**      A tuple is replaced in a table opened with the QEU_OPEN
** command.
** If QEU_BY_TID is specified,
**	the tuple with specified TID is repalced
** else if qeu_cb->kqeu_klen > 0
**	qeu_f_qual points to a function which will both determine whether the
**	tuple should be updated and make appropriate changes to the tuple
**      passed to it
** else
**	replace the tuple which was read by position as specified by the caller
**
** Inputs:
**       qeu_cb
**	    .qeu_eflag			    designate error handling semantis
**					    for user errors.
**		QEF_INTERNAL		    return error code.
**		QEF_EXTERNAL		    send message to user.
**          .qeu_acc_id                     table access id
**          .qeu_tup_length                 lenth of a tuple
**          .qeu_input                      buffer containing new values for the
**					    tuple being replaced
**	    .qeu_qual			    qualification function for DMF
**	    .qeu_qarg			    argument to (*qeu_qual) ()
**          .qeu_klen                       length of key 
**          .qeu_key                        key for update
**      <qeu_key> is a pointer to an array of pointers of type DMR_ATTR_ENTRY
**              .attr_number
**              .attr_operation
**              .attr_value_ptr
**	    .qeu_flag			    operation qualifier
**		QEU_BY_TID		    replace tuple whose TID is in
**					    qeu_tid
**	    .qeu_tid			    contains TID of the tuple to be
**					    replaced if (qeu_flag & QEU_BY_TID)
**	    .qeu_f_qual			    if !(qeu_klen > 0) this must point
**					    at a function which will decide
**					    whether and how the current tuple
**					    must be replaced
**	    .qeu_f_qarg			    argument to (*qeu_f_qual) ()
**	    
** Outputs:
**      qeu_cb
**	    .qeu_count			    number of tuples updated
**          .error.err_code                 One of the following
**                                          E_QE0000_OK
**                                          E_QE0002_INTERNAL_ERROR
**                                          E_QE0004_NO_TRANSACTION
**                                          E_QE0007_NO_CURSOR
**                                          E_QE0017_BAD_CB
**                                          E_QE0018_BAD_PARAM_IN_CB
**      Returns:
**          E_DB_OK
**          E_DB_ERROR                      caller error
**          E_DB_FATAL                      internal error
**      Exceptions:
**          none
**
** Side Effects:
**          none
**
** History:
**      18-jun-92 (andre)
**          written
**	22-jun-92 (andre)
**	    changed the function to allow update one row by tid or to update
**	    multiple rows subject to qualification function
**	24-jun-92 (andre)
**	    another change to allow update of prepositioned tuple
**	13-sep-93 (robf)
**	    Extended to handle update multiple rows without
**	    requiring a key position. This is signalled when qeu_klen==0
**	    and qeu_qual != NULL and qeu_f_qual!=NULL
**	30-nov-93 (robf)
**          When updating multiple rows, keep going after first update.
**	24-Jan-2001 (jenjo02)
**	    Ensure that memory stream is closed before returning.
**	11-Apr-2008 (kschendel)
**	    Revised DMF qualification requirements, simplified for QEU.
*/
DB_STATUS
qeu_replace(
QEF_CB          *qef_cb,
QEU_CB          *qeu_cb)
{
    i4		    err = 0L;
    DMR_CB		    dmr_cb;
    DB_STATUS		    status;
    GLOBALREF QEF_S_CB	    *Qef_s_cb;
    ULM_RCB		    ulm;
    i4			    (*repl_func)(void *, void *);
    bool		    position_all=FALSE;
    bool		    mem_opened=FALSE;

    if (qeu_cb->qeu_flag & QEU_BY_TID)
    {
	/*
	** if update_by_tid, no key(s), qualification function, or qualification
	** function parameters should be passed;
	** qeu_cb->qeu_input must point at a structure containing a ptr to the
	** new value for the tuple of specified size
	*/
	if (qeu_cb->qeu_klen || qeu_cb->qeu_qual || qeu_cb->qeu_qarg ||
	    qeu_cb->qeu_f_qual || qeu_cb->qeu_f_qarg || !qeu_cb->qeu_input ||
	    !qeu_cb->qeu_input->dt_data || !qeu_cb->qeu_input->dt_size)
	{
	    err = E_QE0018_BAD_PARAM_IN_CB;
	    status = E_DB_ERROR;
	}
    }
    else if (qeu_cb->qeu_klen==0 &&  
	    (repl_func = qeu_cb->qeu_f_qual) != NULL &&
	    qeu_cb->qeu_qual)
    {
	position_all=TRUE;
	/*
	** Request to replace all qualifying in table, without key 
	** positioning
	*/
	if (!qeu_cb->qeu_qarg || 
	    !qeu_cb->qeu_f_qarg 
	    )
	{
	    err = E_QE0018_BAD_PARAM_IN_CB;
	    status = E_DB_ERROR;
	}
    }
    else if (qeu_cb->qeu_klen == 0)
    {
	/*
	** if asked to update the current tuple, no qualification function, or
	** qualification function parameters should be passed;
	** qeu_cb->qeu_input must point at a structure containing a ptr to
	** the new value for the tuple of specified size
	*/
	if (qeu_cb->qeu_qual || qeu_cb->qeu_qarg || qeu_cb->qeu_f_qual ||
	    qeu_cb->qeu_f_qarg || !qeu_cb->qeu_input ||
	    !qeu_cb->qeu_input->dt_data || !qeu_cb->qeu_input->dt_size)
	{
	    err = E_QE0018_BAD_PARAM_IN_CB;
	    status = E_DB_ERROR;
	}
    }
    else if ((repl_func = qeu_cb->qeu_f_qual) == NULL)
    {
	/*
	** if caller supplied a key, must specify the function which
	** will determine whether and how the tuple must be updated
	*/
	err = E_QE0018_BAD_PARAM_IN_CB;
	status = E_DB_ERROR;
    }

    if (err)
    {
	(VOID) qef_error(err, 0L, status, &err, &qeu_cb->error, 0);
	return(status);
    }

    qeu_cb->qeu_count = 0;
    qeu_cb->error.err_code = E_QE0000_OK;

    /* QEU_REPLACE is only valid in a transaction */
    if (qef_cb->qef_stat == QEF_NOTRAN)
    {
        qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err,
            &qeu_cb->error, 0);
        return (E_DB_ERROR);
    }

    dmr_cb.type                 = DMR_RECORD_CB;
    dmr_cb.length               = sizeof(DMR_CB);
    dmr_cb.dmr_access_id        = qeu_cb->qeu_acc_id;
    dmr_cb.dmr_q_fcn		= NULL;

    /* if replacing by key, position the cursor */
    if (qeu_cb->qeu_klen || position_all)
    {
	/* allocate memory for a tuple only if planning to call qeu_get() */
	
	STRUCT_ASSIGN_MACRO(Qef_s_cb->qef_d_ulmcb, ulm);
	/* Open stream and allocate tuple memory in one action */
	ulm.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC;
	ulm.ulm_psize = ulm.ulm_blocksize = qeu_cb->qeu_tup_length;

	if ((status = qec_mopen(&ulm)) != E_DB_OK)
	{
	    qef_error(E_QE001E_NO_MEM, 0L, E_DB_ERROR, &err,
		&qeu_cb->error, 0);
	    return (status);
	}
	mem_opened=TRUE;

        /* set the keys */
	if(position_all)
	{
		dmr_cb.dmr_position_type = DMR_ALL;
	}
	else
	{
		dmr_cb.dmr_position_type = DMR_QUAL;
		dmr_cb.dmr_attr_desc.ptr_address    = (PTR) qeu_cb->qeu_key;
		dmr_cb.dmr_attr_desc.ptr_in_count   = qeu_cb->qeu_klen;
		dmr_cb.dmr_attr_desc.ptr_size	    = sizeof (DMR_ATTR_ENTRY);
		dmr_cb.dmr_s_estimated_records	    = -1;
	}
        /* row qualifier */
        dmr_cb.dmr_q_fcn = (DB_STATUS (*)(void *,void *)) qeu_cb->qeu_qual;
        dmr_cb.dmr_q_arg = (PTR) qeu_cb->qeu_qarg;
	if (qeu_cb->qeu_qual != NULL)
	{
	    dmr_cb.dmr_q_rowaddr = &qeu_cb->qeu_qarg->qeu_rowaddr;
	    dmr_cb.dmr_q_retval = &qeu_cb->qeu_qarg->qeu_retval;
	}
	dmr_cb.dmr_flags_mask = 0;
        status = dmf_call(DMR_POSITION, &dmr_cb);
        if (status != E_DB_OK)
        {
	    ulm_closestream(&ulm);

	    if (dmr_cb.error.err_code == E_DM0055_NONEXT)
		return (E_DB_OK);
            qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0);
            return (status);
        }

	/* the tuple length will not change. Tell DMF about it */
	dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_tup_length;
	dmr_cb.dmr_data.data_address = ulm.ulm_pptr;
    }
    else
    {
	/*
	** make dmr_data point at the new value for the tuple
	*/
	dmr_cb.dmr_data.data_address = qeu_cb->qeu_input->dt_data;
	dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_input->dt_size;

	/*
	** if (qeu_flag & QEU_BY_TID)
	**    indicate to dmr_replace() that we are replacing by tid
	** else
	**    indicate to dmr_replace to replace the current tuple
	*/

	if (qeu_cb->qeu_flag & QEU_BY_TID)
	{	
	    dmr_cb.dmr_flags_mask = DMR_BY_TID;
	    dmr_cb.dmr_tid = qeu_cb->qeu_tid;
	}
	else
	{
	    dmr_cb.dmr_flags_mask = DMR_CURRENT_POS;
	}
    }

    for (;;)
    {
        if (qeu_cb->qeu_klen || position_all)
	{
	    i4	ret_val;

            /* get the tuple */
            dmr_cb.dmr_flags_mask = DMR_NEXT;
            status = dmf_call(DMR_GET, &dmr_cb);
            if (status != E_DB_OK)
            {
                if (dmr_cb.error.err_code == E_DM0055_NONEXT)
		{
		    status = E_DB_OK;
		}
		else
		{
		    err = dmr_cb.error.err_code;
		}
                break;
            }

	    /*
	    ** let caller's function determine whether and how the tuple must be
	    ** changed; QEU_F_RETURN indicates that we must proceed; QEU_F_NEXT
	    ** says "skip this tuple"
	    */
	    ret_val = (*repl_func) (dmr_cb.dmr_data.data_address,
		qeu_cb->qeu_f_qarg);

	    if (ret_val != QEU_F_RETURN)
	    {
		continue;
	    }

	    /* will replace the current tuple */
	    dmr_cb.dmr_flags_mask = DMR_CURRENT_POS;
	}

	dmr_cb.dmr_attset = NULL;
	status = dmf_call(DMR_REPLACE, &dmr_cb);
	if (status != E_DB_OK)
	{
	    err = dmr_cb.error.err_code;
	    break;
	}
	else
	{
	    qeu_cb->qeu_count++;
	}

	if (qeu_cb->qeu_klen == 0 && !position_all)
	{
	    /* we were replacing a tuple by tid and are done */
	    break;
	}
    }

    if (status != E_DB_OK)
    {
	qef_error(err, 0L, status, &err, &qeu_cb->error, 0);
    }

    if (mem_opened)
    {
	/* don't try to close a stream unless it was opened */
	ulm_closestream(&ulm);
    }
    
    return (status);
}
예제 #16
0
/*{
** Name: psq_bgn_session	- Begin a parser session.
**
**  INTERNAL PSF call format: status = psq_bgn_session(&psq_cb, &sess_cb);
**
**  EXTERNAL call format: status = psq_call(PSQ_BGN_SESSION, &psq_cb, &sess_cb);
**
** Description:
**      The psq_bgn_session function begins a parser session.  It should be
**	called each time a new user connects to a server.  There may be 
**      many parser sessions per database server.  There should be one parser 
**      session for each invocation of the database system that is connected 
**      to the server.  When starting a parser session, one has to tell it
**	what query language to use, and other session parameters.
**
** Inputs:
**      psq_cb
**          .psq_qlang                  The query language to use.
**          .psq_decimal
**		.psf_decspec		TRUE indicates that the decimal marker
**					has been specified.  FALSE means use the
**					default (a ".").
**		.psf_decimal		The character to use as a decimal marker
**					(if specified).
**	    .psq_distrib		Indicator for whether distributed
**					statements and constructs should be
**					accepted.
**	    .psq_sessid			Session id 
**	    .psq_server			address of server control block
**	    .psq_adf_cb			Pointer to session's ADF_CB
**	    .psq_dbid			Database id for this session.
**	    .psq_user			User name of 
**	    .psq_dba			User name of dba
**	    .psq_group			Group id of session
**	    .psq_aplid			Application id of session
**	    .psq_flag			bitmask containing the following flags:
**	      .psq_catupd		  TRUE means catalogs updateable
**	      .psq_warnings		  Set to TRUE if user wishes to see
**					  warnings on unsupported commands
**	    .psq_idxstruct		Structure for creating new indexes
**					(e.g. DB_ISAM_STORE)
**	    .psq_udbid			Unique database id for this session.
**	    .psq_ustat	 		User status flags from SCS_ICS
**	    .psq_dbxlate		Case translation semantics for the db
**	sess_cb				Pointer to session control block
**					(Can be NULL)
**
** Outputs:
**      psq_cb
**          .psq_error                  Error information
**		.err_code		    What error occurred
**		    E_PS0000_OK			Success
**		    E_PS0001_INTERNAL_ERROR	    Internal PSF problem
**		    E_PS0201_BAD_QLANG		    Bad query language specifier
**		    E_PS0203_NO_DECIMAL		    No decimal marker specified
**		    E_PS0204_BAD_DISTRIB	    Bad distributed
**						    specification
**		    E_PS0205_SRV_NOT_INIT	    Server not initialized
**		    E_PS0206_TOO_MANY_SESS	    Too many sessions at one
**						    time
**	Returns:
**	    E_DB_OK			Function completed normally.
**	    E_DB_WARN			Function completed with warning(s)
**	    E_DB_ERROR			Function failed; non-catastrophic error
**	    E_DB_SEVERE			Session is to be aborted
**	    E_DB_FATAL			Function failed; catastrophic error
**	Exceptions:
**	    none
**
** Side Effects:
**	    Causes memory to be allocated.
**	    Increments the session count in the server control block.
**
** History:
**	01-oct-85 (jeff)
**          written
**	28-jul-86 (jeff)
**	    Added initialization of pss_catupd and pss_idxstruct
**      26-aug-86 (seputis)
**          Removed definition of yaccstream
**	13-apr-87 (puree)
**	    Initialize prototype list for dynamic SQL.
**	24-apr-87 (stec)
**	    init pss_project.
**	11-may-87 (stec)
**	    store psq_udbid to pss_dbid.
**	04-sep-87 (stec)
**	    Added critical region code where needed.
**	02-oct-87 (stec)
**	    Added pss_journaling initialization.
**	13-jun-88 (stec)
**	    Added initialization of pss_ruset for DB procs.
**	08-mar-89 (andre)
**	    Copy dba_drop_all from PSQ_CB to PSS_SESBLK.
**	15-mar-89 (ralph)
**	    GRANT Enhancements, Phase 1:
**	    Copy psq_aplid to pss_aplid;
**	    Copy psq_group to pss_group.
**	16-mar-89 (neil)
**	    Initialized rule field.
**	27-jul-89 (jrb)
**	    Copy numeric literals flag into session cb.
**	27-oct-89 (ralph)
**	    Copy user status flags to session control block.
**	11-oct-89 (ralph)
**	    Initialize pss_rgset and pss_raset.
**	28-dec-89 (andre)
**	    Copy fips_mode from PSQ_CB to PSS_SESBLK.
**	13-feb-90 (andre)
**	    set scf_stype to SCU_EXCLUSIVE before calling scu_swait.
**	12-sep-90 (sandyh)
**	    Added support for session memory value calculated from psf
**	    memory startup parameter.
**	15-nov-90 (andre)
**	    check the return status after calling SCF to acquire or to release a
**	    semaphore.
**	    If an error occurred when trying to acquire the semaphore, return
**	    E_DB_SEVERE to abort the session.
**	    If an error occurred when trying to release the semaphore, return
**	    E_DB_FATAL to bring down the server.
**	17-may-91 (andre)
**	    store DBA name into sess_cb->pss_dbaname and NULL-terminate.
**	08-nov-91 (rblumer)
**          merged from 6.4:  25-jul-91 (andre)
**		if (psq_cb->psq_flag & PSQ_STRIP_NL_IN_STRCONST), set bit
**		PSS_STRIP_NL_IN_STRCONST in sess_cb->pss_ses_flag.  this will
**		indicate that we are connected to an older FE, so the scanners
**		will continue to strip NLs inside quoted strings;
**		this is required to fix bug 38098
**	14-jan-92 (barbara)
**	    Included ddb.h for Star.  Updated to check for distributed
**	    specification.
**	26-feb-92 (andre)
**	    if PSQ_REPAIR_SYSCAT is set in psq_cb->psq_flag, set
**	    PSS_REPAIR_SYSCAT in sess_cb->pss_ses_flags
**	30-mar-1992 (bryanp)
**	    Fill in pss_sess_owner with a session-unique owner name for use
**	    by temporary tables which are owned by this session.
**	02-jun-92 (andre)
**	    initialize pss_dependencies_stream to NULL to avloid use of illegal
**	    address throughout the parser.
**	24-nov-92 (ralph)
**	    CREATE SCHEMA:
**	    Initialize pss_prvgoval
**	22-dec-92 (rblumer)
**	    initialize pointer for statement-level rule list.
**	14-jan-93 (andre)
**	    remember whether we are running UPGRADEDB - this will enable us to
**	    decide whether IIDEVICES can be dropped - which is needed by
**	    UPGRADEDB
**	15-mar-93 (ralph)
**	    DELIM_IDENT: initialize pss_dbxlate to zero
**	08-apr-93 (andre)
**	    names of rule list headers in sess_cb have changed (and their
**	    number has doubled)
**	26-mar-93 (ralph)
**	    DELIM_IDENT: Must initialize pss_dbxlate from psq_cb.psq_dbxlate
**	    and pss_cat_owner from psq_cat_owner.
**	10-aug-93 (andre)
**	    fixed cause of a compiler warning
**	08-sep-93 (swm)
**	    Changed sizeof(DB_SESSID) to sizeof(CS_SID) to reflect recent CL
**	    interface revision.
**	20-sep-93 (rogerk)
**	    Changed default table create semantics to be WITH JOURNALING.
**	    Initialized the pss_ses_flag setting to include PSS_JOURNALING
**	    which mimics the user requesting "set journaling" to indicate that
**	    tables created should be journaled.
**	08-oct-93 (rblumer)
**	    increased values allowed in pss_trace vector, using PSS_TVALS.
**	18-oct-93 (rogerk)
**	    Added support for journal default override.  Check psf server
**	    control block flag for PSF_NO_JNL_DEFAULT override before setting
**	    the session parse flag to assume journaling on table creates.
**	15-nov-93 (andre)
**	    add code to initialize a newly added sess_cb->pss_flattening_flags
**	01-nov-93 (anitap)
**	    if PSQ_INGRES_PRIV is set in psq_cb->psq_flag, set
**	    PSS_INGRES_PRIV in sess_cb->pss_ses_flags.
**	17-dec-93 (rblumer)
**	    "FIPS mode" no longer exists.  It was replaced some time ago by
**	    several feature-specific flags (e.g. flatten_nosingleton and
**	    direct_cursor_mode).  So I removed all FIPS_MODE flags.
**	02-jan-94 (andre)
**	    if starting a local session, call DMF to determine whether the 
**	    database to which we are connected is being journaled and record 
**	    that information by setting (or not setting) PSS_JOURNALED_DB bit 
**	    in pss_ses_flags
**	 7-jan-94 (swm)
**	    Bug #58635
**	    Added PTR cast for pss_owner which has changed type to PTR.
**	17-mar-94 (robf)
**          Add support for PSQ_SELECT_ALL flag
**	13-Feb-1995 (canor01)
**	    initialize the pss_audit field in the session control block
**	09-Oct-1998 (jenjo02)
**	    Removed SCF semaphore functions, inlining the CS calls instead.
**	23-mar-1999 (thaju02)
**	    Modified '$Sess' to use #define DB_SESS_TEMP_OWNER. (B94067)
**      01-Dec-2000 (hanal04) Bug 100680 INGSRV 1123
**          If PSQ_RULE_UPD_PREFETCH is set turn on PSS_RULE_UPD_PREFETCH
**          in the session control block to signify that we should use
**          the prefetch stategy required to ensure consitent behaviour in
**          updating rules fired by updates.
**	10-Jan-2001 (jenjo02)
**	    Remove callback to SCF to get session id and ADF_CB;
**	    *ADF_CB now supplied by scsinit in PSQ_CB.
**	30-Jan-2004 (schka24)
**	    Get rid of a type-cast warning on adf cb.
**	3-Feb-2005 (schka24)
**	    Num-literals renamed to parser-compat, fix here.
**	15-june-06 (dougi)
**	    Add support for "before" triggers.
**	30-aug-06 (thaju02)
**	    If PSQ_RULE_DEL_PREFETCH is set turn on PSS_RULE_DEL_PREFETCH
**          in the session control block, for prefetch strategy to 
**          be applied for deletes. (B116355)
**	26-Oct-2009 (kiria01) SIR 121883
**	    Scalar sub-query support: Added copy of
**	    psq_flag.PSQ_NOCHK_SINGLETON_CARD to session flag
**	    for defaulting SET CARDINALITY_CHECK
**      November 2009 (stephenb)
**          Batch execution; initilization of new fields.
**      29-apr-2010 (stephenb)
**          Init batch_copy_optim.
**	04-may-2010 (miket) SIR 122403
**	    Init new sess_cb->pss_stmt_flags2.
**	19-May-2010 (kiria01) b123766
**	    Get cardinality check default from server block not psq_cb
**	21-Jul-2010 (kschendel) SIR 124104
**	    Initialize default compression from facility cb.
**	14-Oct-2010 (kschendel) SIR 124544
**	    Initialize default result structure from facility cb.
**	19-Nov-2010 (kiria01) SIR 124690
**	    Add support for setting installation wide collation defaults.
*/
DB_STATUS
psq_bgn_session(
	register PSQ_CB     *psq_cb,
	register PSS_SESBLK *sess_cb)
{
    i4		    err_code;
    i4			    i;
    DB_STATUS		    status = E_DB_OK;
    STATUS		    sem_status;
    i4		    sem_errno;
    bool		    leave_loop = TRUE;
    ULM_RCB		    ulm_rcb;

    /*
    ** No error to begin with.
    */
    psq_cb->psq_error.err_code = E_PS0000_OK;

    /*
    ** Do as much validity checking as possible before allocating any memory.
    ** That way, there won't be any cleaning up to do for the majority of
    ** errors.
    */

    /*
    ** Check for server initialized. This code could be placed within
    ** critical region, but this is not necessary, since this is a flag
    ** test.
    */
    if (!Psf_srvblk->psf_srvinit)
    {
	(VOID) psf_error(E_PS0205_SRV_NOT_INIT, 0L, PSF_CALLERR, &err_code,
	    &psq_cb->psq_error, 0);
	return (E_DB_ERROR);
    }

    /*
    ** Check for valid language spec.
    */
    if (psq_cb->psq_qlang != DB_QUEL && psq_cb->psq_qlang != DB_SQL)
    {
	(VOID) psf_error(E_PS0201_BAD_QLANG, 0L, PSF_CALLERR, &err_code,
	    &psq_cb->psq_error, 0);
	return (E_DB_ERROR);
    }
	
    /*
    ** Check whether language is allowed in this server.  This will be useful
    ** when we have configurable servers, where some query languages can be
    ** used and some can't. This code could be placed within a critical region
    ** but it is not necessary, since this is a flag test only.
    */
    if ((psq_cb->psq_qlang & Psf_srvblk->psf_lang_allowed) == 0)
    {
	(VOID) psf_error(E_PS0202_QLANG_NOT_ALLOWED, 0L, PSF_CALLERR, &err_code,
	    &psq_cb->psq_error, 0);
	return (E_DB_ERROR);
    }

    /*
    ** Make sure that the decimal character is actually specified.
    */
    if (!psq_cb->psq_decimal.db_decspec)
    {
	(VOID) psf_error(E_PS0203_NO_DECIMAL, 0L, PSF_CALLERR, &err_code,
	    &psq_cb->psq_error, 0);
	return (E_DB_ERROR);
    }

     /* Check distributed specification
    **
    ** a=local_server, b=distrib_server, c=distrib_session
    **
    **   a,b
    **
    **     00  01  11  10
    **    -----------------
    ** c  |   |   |   |   |
    **  0 | 1 | 1 | 0 | 0 |
    **    |   |   |   |   |
    **    -----------------  ==> ERROR
    **    |   |   |   |   |
    **  1 | 1 | 0 | 0 | 1 |
    **    |   |   |   |   |
    **    -----------------
    */
    if (   !(psq_cb->psq_distrib & (DB_1_LOCAL_SVR | DB_3_DDB_SESS))
	|| ((~psq_cb->psq_distrib & DB_2_DISTRIB_SVR)
	    && (psq_cb->psq_distrib & DB_3_DDB_SESS))
	)
    {
	psf_error(E_PS0204_BAD_DISTRIB, 0L, PSF_CALLERR, &err_code,
	    &psq_cb->psq_error,0);
	return (E_DB_ERROR);
    }

    /*
    ** Check for too many sessions in server at one time.
    ** This code must be executed as a critical region.
    */

    do		    /* something to break out of */
    {
	/* get the semaphore */
	if (sem_status = CSp_semaphore(1, &Psf_srvblk->psf_sem)) /* exclusive */
	{
	    status = E_DB_SEVERE;	/* abort the session */
	    sem_errno = E_PS020A_BGNSES_GETSEM_FAILURE;
	    break;
	}

	if (Psf_srvblk->psf_nmsess >= Psf_srvblk->psf_mxsess)
	{
	    (VOID) psf_error(E_PS0208_TOO_MANY_SESS, 0L, PSF_CALLERR, &err_code,
		&psq_cb->psq_error, 0);
	    status = E_DB_ERROR;
	    break;
	}

	/* Increment the session count */
	Psf_srvblk->psf_nmsess++;
	sess_cb->pss_psessid = ++Psf_srvblk->psf_sess_num;

	/* leave_loop has already been set to TRUE */
    } while (!leave_loop);

    /* if semaphore has been successfully acquired, try to release it */
    if (sem_status == OK)
    {
	if (sem_status = CSv_semaphore(&Psf_srvblk->psf_sem))
	{
	    status = E_DB_FATAL;	/* bring down the server */
	    sem_errno = E_PS020B_BGNSES_RELSEM_FAILURE;
	}
    }

    /*
    ** if an error was encountered while trying to get or to release a
    ** semaphore, report it here
    */
    if (sem_status != OK)
    {
	(VOID) psf_error(sem_errno, sem_status, PSF_INTERR,
	    &err_code, &psq_cb->psq_error, 0);
    }

    if (DB_FAILURE_MACRO(status))
    {
	return(status);
    }

    /*
    ** Initialize the case translation semantics stuff
    */
    sess_cb->pss_dbxlate = psq_cb->psq_dbxlate;
    sess_cb->pss_cat_owner = psq_cb->psq_cat_owner;

    /*
    ** Copy the user name and dba name to the session control block.
    */
    STRUCT_ASSIGN_MACRO(psq_cb->psq_user.db_tab_own, sess_cb->pss_user);
    STRUCT_ASSIGN_MACRO(psq_cb->psq_dba, sess_cb->pss_dba);
    STRUCT_ASSIGN_MACRO(psq_cb->psq_group, sess_cb->pss_group);
    STRUCT_ASSIGN_MACRO(psq_cb->psq_aplid, sess_cb->pss_aplid);

    /* copy DBA name into sess_cb->pss_dbaname and NULL-terminate */
    {
	u_i2			dba_name_len;

	dba_name_len = (u_i2) psf_trmwhite((u_i4) sizeof(sess_cb->pss_dba),
			    (char *) &sess_cb->pss_dba);
	MEcopy((PTR) &sess_cb->pss_dba, dba_name_len,
	       (PTR) sess_cb->pss_dbaname);

	sess_cb->pss_dbaname[dba_name_len] = EOS;
    }

    /*
    ** Build a DB_OWN_NAME which contains a session-unique owner name. This
    ** owner name will be used for temporary tables which are owned by this
    ** session.
    */
    {
	char	    temp_sess_id[10];

	STmove(DB_SESS_TEMP_OWNER, ' ', sizeof(sess_cb->pss_sess_owner),
		(char *)&sess_cb->pss_sess_owner);
	/*
	** We can't convert directly into the sess_owner field because CVlx
	** null-terminates the result, and we don't want the trailing null
	*/
	CVlx(sess_cb->pss_psessid, temp_sess_id);
	MEcopy(temp_sess_id, 8, &sess_cb->pss_sess_owner.db_own_name[5]);
    }

    /*
    ** Start with per-user quota of memory.  Note that user may have overridden
    ** the default value at server startup in which case we will use calculated
    ** amount (pool/sessions); otherwise, default amount will be used.
    */
    sess_cb->pss_memleft = (Psf_srvblk->psf_sess_mem) ? Psf_srvblk->psf_sess_mem
						      : PSF_SESMEM;

    /*
    ** Initialize the user range table.
    */
    if (pst_rginit(&sess_cb->pss_usrrange) != E_DB_OK)
    {
	return (E_DB_FATAL);
    }
	
    /*
    ** Initialize the auxiliary range table.
    */
    if (pst_rginit(&sess_cb->pss_auxrng) != E_DB_OK)
    {
	return (E_DB_FATAL);
    }

    /*
    ** Open a memory stream for the symbol table.  The symbol table is
    ** composed of a list of blocks.
    ** Allocate the symbol table at the same time.
    */
    ulm_rcb.ulm_facility = DB_PSF_ID;
    ulm_rcb.ulm_poolid = Psf_srvblk->psf_poolid;
    ulm_rcb.ulm_blocksize = sizeof(PSS_SYMBLK);
    ulm_rcb.ulm_memleft = &sess_cb->pss_memleft;
    /* Set pointer to stream handle for ULM */
    ulm_rcb.ulm_streamid_p = &sess_cb->pss_symstr;
    /* Open a private, thread-safe stream */
    ulm_rcb.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC;
    ulm_rcb.ulm_psize = sizeof(PSS_SYMBLK);
    if (ulm_openstream(&ulm_rcb) != E_DB_OK)
    {
	if (ulm_rcb.ulm_error.err_code == E_UL0005_NOMEM)
	{
	    (VOID) psf_error(E_PS0F02_MEMORY_FULL, 0L, PSF_CALLERR, 
		&err_code, &psq_cb->psq_error, 0);
	}
	else
	{
	    (VOID) psf_error(E_PS0A02_BADALLOC, ulm_rcb.ulm_error.err_code,
		PSF_INTERR, &err_code, &psq_cb->psq_error, 0);
	}

	return((ulm_rcb.ulm_error.err_code == E_UL0004_CORRUPT) ? E_DB_FATAL
								: E_DB_ERROR);
    }

    sess_cb->pss_symtab = (PSS_SYMBLK*) ulm_rcb.ulm_pptr;
    sess_cb->pss_symtab->pss_sbnext = (PSS_SYMBLK *) NULL;

    /*
    ** Allocate the YACC_CB.  
    */

    if ((status = psl_yalloc(sess_cb->pss_symstr, 
	&sess_cb->pss_memleft,
	(PTR *) &sess_cb->pss_yacc, &psq_cb->psq_error)) != E_DB_OK)
    {
	/*
	** If the allocation failed, remember to close the streams, so the
	** memory associated with it will be freed.
	*/
	(VOID) ulm_closestream(&ulm_rcb);
	return (status);
    }
	
    /*
    ** Fill in the control block header.
    */
    sess_cb->pss_next = (PSS_SESBLK *) NULL;
    sess_cb->pss_prev = (PSS_SESBLK *) NULL;
    sess_cb->pss_length = sizeof(PSS_SESBLK);
    sess_cb->pss_type = PSS_SBID;
    sess_cb->pss_owner = (PTR)DB_PSF_ID;
    sess_cb->pss_ascii_id = PSSSES_ID;

    /*
    ** Initialize the session control block.
    */
    /* Save the session id */
    sess_cb->pss_sessid	    = psq_cb->psq_sessid;

    /* Set pointer to session's ADF_CB */
    sess_cb->pss_adfcb	    = (ADF_CB *) psq_cb->psq_adfcb;

    /* No cursors yet */
    sess_cb->pss_numcursors = 0;

    /* Language has already been validated */
    sess_cb->pss_lang = psq_cb->psq_qlang;

    /* Decimal spec has already been validated */
    sess_cb->pss_decimal = psq_cb->psq_decimal.db_decimal;

    /* Distributed spec has already been validated */
    sess_cb->pss_distrib = psq_cb->psq_distrib;

    /* Save the database id */
    sess_cb->pss_dbid = psq_cb->psq_dbid;

    /* Save the unique database id */
    sess_cb->pss_udbid = psq_cb->psq_udbid;

    /* Initialize QSF_RCB for use by psfmem.c functions */
    sess_cb->pss_qsf_rcb.qsf_type = QSFRB_CB;
    sess_cb->pss_qsf_rcb.qsf_ascii_id = QSFRB_ASCII_ID;
    sess_cb->pss_qsf_rcb.qsf_length = sizeof(sess_cb->pss_qsf_rcb);
    sess_cb->pss_qsf_rcb.qsf_owner = (PTR)DB_PSF_ID;
    sess_cb->pss_qsf_rcb.qsf_sid = sess_cb->pss_sessid;

    /*
    **	so session reset all bit flags
    */
    sess_cb->pss_stmt_flags = sess_cb->pss_stmt_flags2 =
	sess_cb->pss_dbp_flags = sess_cb->pss_ses_flag = 0L;
    sess_cb->pss_flattening_flags = 0;

    /*
    ** Default table create semantics are to assume journaling unless
    ** the PSF_NO_JNL_DEFAULT override is set.
    */
    if ((Psf_srvblk->psf_flags & PSF_NO_JNL_DEFAULT) == 0)
	sess_cb->pss_ses_flag |= PSS_JOURNALING;

	    /* catalog update flag */
    if (psq_cb->psq_flag & PSQ_CATUPD)
	sess_cb->pss_ses_flag |= PSS_CATUPD;

	    /* warnings on unsupported commands */
    if (psq_cb->psq_flag & PSQ_WARNINGS)
	sess_cb->pss_ses_flag |= PSS_WARNINGS;

	/* INDICATE if the DBA may DROP everyone's tables */
    if (psq_cb->psq_flag & PSQ_DBA_DROP_ALL)
	sess_cb->pss_ses_flag |= PSS_DBA_DROP_ALL;

	/* INDICATE if the session may SELECT everyone's tables */
    if (psq_cb->psq_flag & PSQ_SELECT_ALL)
	sess_cb->pss_ses_flag |= PSS_SELECT_ALL;

	/*
	** indicate that the session is allowed to INSERT/DELETE/UPDATE an index
	** which is a catalog (but not an extended catalog
	*/
    if (psq_cb->psq_flag & PSQ_REPAIR_SYSCAT)
	sess_cb->pss_ses_flag |= PSS_REPAIR_SYSCAT;

	/* 
	** indicate that the session allows $ingres to drop/add constraint on
	** tables owned by other users
	*/
    if (psq_cb->psq_flag & PSQ_INGRES_PRIV)
	sess_cb->pss_ses_flag |= PSS_INGRES_PRIV;	

    if (psq_cb->psq_flag & PSQ_ROW_SEC_KEY)
	sess_cb->pss_ses_flag |= PSS_ROW_SEC_KEY;

    /* See if passwords, roles allowed */
    if (psq_cb->psq_flag & PSQ_PASSWORD_NONE)
	sess_cb->pss_ses_flag |= PSS_PASSWORD_NONE;

    if (psq_cb->psq_flag & PSQ_ROLE_NONE)
	sess_cb->pss_ses_flag |= PSS_ROLE_NONE;

    if (psq_cb->psq_flag & PSQ_ROLE_NEED_PW)
	sess_cb->pss_ses_flag |= PSS_ROLE_NEED_PW;

	/* remember whether we are running UPGRADEDB */
    if (psq_cb->psq_flag & PSQ_RUNNING_UPGRADEDB)
	sess_cb->pss_ses_flag |= PSS_RUNNING_UPGRADEDB;

    /* Pick up serverwide default for card check */
    if (Psf_srvblk->psf_flags & PSF_NOCHK_SINGLETON_CARD)
	sess_cb->pss_ses_flag |= PSS_NOCHK_SINGLETON_CARD;

        /* Initialize pss_project. */
    sess_cb->pss_ses_flag |= PSS_PROJECT;	/* pss_project = TRUE */
    
    /* init last statement */
    sess_cb->pss_last_sname[0] = EOS;
    /* batch optimization switch starts undefined */
    sess_cb->batch_copy_optim = PSS_BATCH_OPTIM_UNDEF;

    /* 
    ** if starting a local session, determine whether the database is being 
    ** journaled
    */
    if (~psq_cb->psq_distrib & DB_3_DDB_SESS)
    {
        DMC_CB		    dmc_cb, *dmc = &dmc_cb;
        DMC_CHAR_ENTRY	    dmc_char;

	MEfill(sizeof(dmc_cb), (u_char) 0, (PTR) dmc);

        dmc->type = DMC_CONTROL_CB;
        dmc->length = sizeof(*dmc);
        dmc->dmc_op_type = DMC_DATABASE_OP;
	dmc->dmc_session_id = (PTR) sess_cb->pss_sessid;
        dmc->dmc_flags_mask = DMC_JOURNAL;
        dmc->dmc_char_array.data_address= (PTR) &dmc_char;
	dmc->dmc_char_array.data_out_size = sizeof(dmc_char);
	dmc->dmc_db_id = (char *) sess_cb->pss_dbid;
	
	status = dmf_call(DMC_SHOW, (PTR) dmc);
	if (DB_FAILURE_MACRO(status))
	{
	    (VOID) psf_error(E_PS020E_CANT_GET_DB_JOUR_STATUS, 
		dmc->error.err_code, PSF_INTERR, &err_code, 
		&psq_cb->psq_error, 0);
	    return(status);
	}

	if (dmc_char.char_value == DMC_C_ON)
	{
	    sess_cb->pss_ses_flag |= PSS_JOURNALED_DB;
	}
    }

    /* Save the storage structure for indexes */
    sess_cb->pss_idxstruct = psq_cb->psq_idxstruct;

    /* Make session copy of parser compatability settings */
    sess_cb->pss_parser_compat = psq_cb->psq_parser_compat;

    /* remember if NLs inside string constants need to be stripped */
    if (psq_cb->psq_flag & PSQ_STRIP_NL_IN_STRCONST)
	sess_cb->pss_ses_flag |= PSS_STRIP_NL_IN_STRCONST;

    /* no rule tree yet */
    sess_cb->pss_row_lvl_usr_rules  =
    sess_cb->pss_row_lvl_sys_rules  =
    sess_cb->pss_stmt_lvl_usr_rules =
    sess_cb->pss_stmt_lvl_sys_rules =
    sess_cb->pss_row_lvl_usr_before_rules  =
    sess_cb->pss_row_lvl_sys_before_rules  =
    sess_cb->pss_stmt_lvl_usr_before_rules =
    sess_cb->pss_stmt_lvl_sys_before_rules = (PST_STATEMENT *) NULL;

    if (psq_cb->psq_flag & PSQ_RULE_DEL_PREFETCH)
	sess_cb->pss_ses_flag |= PSS_RULE_DEL_PREFETCH;

    if(psq_cb->psq_flag2 & PSQ_RULE_UPD_PREFETCH)
        sess_cb->pss_ses_flag |= PSS_RULE_UPD_PREFETCH;

    /* copy user status flags to session control block */
    sess_cb->pss_ustat = psq_cb->psq_ustat;

    /*
    ** Initialize lots of pointer to NULL because nothing is happening yet.
    */
    sess_cb->pss_qbuf = sess_cb->pss_nxtchar = sess_cb->pss_prvtok =
	sess_cb->pss_bgnstmt = sess_cb->pss_endbuf =
	sess_cb->pss_prvgoval = (u_char *) NULL;

    /* initialize pss_audit */
    sess_cb->pss_audit = NULL;

    for (i = 0; i < PSS_CURTABSIZE; i++)
    {
	sess_cb->pss_curstab.pss_curque[i] = (PSC_CURBLK *) NULL;
    }

    /* initialize prototype list for dynamic SQL */
    sess_cb->pss_proto = (PST_PROTO *) NULL;

    /*
    ** pss_dependencies_stream, when not NULL, is expected to point at a valid
    ** stream descriptor.  After closing the stream we always reset
    ** pss_dependencies_stream to NULL, but in some cases we may end up checking
    ** pss_dependencies_stream before ever opening (and closing it).  As a
    ** result, you may end up using invalid address as a stream pointer.
    ** Initializing it here to NULL will ensure that it is non-NULL iff it
    ** points at a valid open stream descriptor.
    */
    sess_cb->pss_dependencies_stream = (PSF_MSTREAM *) NULL;

    /* No trace flags set */
    /* expect lint message */
    ult_init_macro(&sess_cb->pss_trace, PSS_TBITS, PSS_TVALS, PSS_TVAO);

    /* Cursor id set to 0, no cursors open yet */
    sess_cb->pss_crsid = 0;

    sess_cb->pss_create_compression = Psf_srvblk->psf_create_compression;

    /* SCF can pass a client requested result_structure, but if it
    ** doesn't, init from server default.
    */
    if (psq_cb->psq_result_struct != 0)
    {
	sess_cb->pss_result_struct = psq_cb->psq_result_struct;
	sess_cb->pss_result_compression = psq_cb->psq_result_compression;
    }
    else
    {
	sess_cb->pss_result_struct = Psf_srvblk->psf_result_struct;
	sess_cb->pss_result_compression = Psf_srvblk->psf_result_compression;
    }

    if (psq_cb->psq_def_coll > DB_NOCOLLATION)
	sess_cb->pss_def_coll = psq_cb->psq_def_coll;
    else
	sess_cb->pss_def_coll = Psf_srvblk->psf_def_coll;
    if (psq_cb->psq_def_unicode_coll > DB_NOCOLLATION)
	sess_cb->pss_def_unicode_coll = psq_cb->psq_def_unicode_coll;
    else
	sess_cb->pss_def_unicode_coll = Psf_srvblk->psf_def_unicode_coll;

    return (E_DB_OK);
}