Beispiel #1
0
DB_STATUS 
qeq_c2_delete(
QEF_RCB		*v_qer_p,
QEE_DSH		*i_dsh_p )
{
    DB_STATUS	    status = E_DB_OK;
    QES_DDB_SES	    *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses;
    QES_QRY_SES	    *qss_p = & dds_p->qes_d8_union.u2_qry_ses;
    QEE_DDB_CB	    *qee_p = i_dsh_p->dsh_ddb_cb;
    QEF_QP_CB	    *qp_p = i_dsh_p->dsh_qp_ptr;
    QEQ_DDQ_CB	    *ddq_p = & qp_p->qp_ddq_cb;	
    bool	    log_qry_55 = FALSE,
                    log_err_59 = FALSE;
    i4         i4_1, i4_2;
    RQR_CB	    rqr,
		    *rqr_p = & rqr;


    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55,
        & i4_1, & i4_2))
    {
        log_qry_55 = TRUE;
	qeq_p34_del_csr(v_qer_p, i_dsh_p);
    }
    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59,
        & i4_1, & i4_2))
        log_err_59 = TRUE;


    /* 2.  set up to call RQR_DELETE */

    MEfill(sizeof(rqr), '\0', (PTR) & rqr);
    rqr_p->rqr_session = dds_p->qes_d3_rqs_p;   /* RQF session id */
    rqr_p->rqr_tabl_name = ddq_p->qeq_d7_deltable;
    rqr_p->rqr_own_name = ddq_p->qeq_d9_delown;
						/* pass owner/table name for
						** CURSOR DELETE */
    rqr_p->rqr_timeout = QEK_0_TIME_QUANTUM;
    rqr_p->rqr_q_language = qss_p->qes_q2_lang;
    rqr_p->rqr_1_site = qss_p->qes_q3_ldb_p;
    STRUCT_ASSIGN_MACRO(qee_p->qee_d5_local_qid, rqr_p->rqr_qid);

    qss_p->qes_q1_qry_status |= QES_03Q_PHASE2;
						/* enter phase 2 for update */
    status = qed_u3_rqf_call(RQR_DELETE, rqr_p, v_qer_p);
    if (status)
    {
	if (log_err_59 && ! log_qry_55)
	    qeq_p34_del_csr(v_qer_p, i_dsh_p);
    }
    else
    {
    	qss_p->qes_q1_qry_status &= ~QES_03Q_PHASE2;
						/* enter phase 2 for update */
	v_qer_p->qef_rowcount = rqr_p->rqr_tupcount;
	v_qer_p->qef_count = rqr_p->rqr_tupcount;
    }
    return(status);
}
Beispiel #2
0
/*{
** Name: sxf_chk_sess_trace	- Checks if a session trace flag is set.
**
** Description:
**      Checks to see if a session trace flag is set.
**
** Inputs:
**	None
**
** Outputs:
**	Returns:
**	    bool
**
** History:
**	5-jul-93 (robf)
**		Created
*/
bool  
sxf_chk_sess_trace(i4 flag)
{
	DB_STATUS status;
	SXF_SCB   *scb;
	i4   err_code;
	i4	  val1,val2;
	/*
	**	Only check if there is tracing
	**	This saves the call to SCF if no tracing is needed
	*/
	if(sxf_tracing_on==FALSE)
		return FALSE;
	/*
	**	Get session id
	*/
        status = sxau_get_scb(&scb, &err_code);
	if( status!=E_DB_OK)
	{
		return FALSE;
	}
	/*
	**	Check if trace flag is set
	*/
    	if(ult_check_macro(&scb->sxf_trace, flag, &val1, &val2))
		return TRUE;
	else
		return FALSE;
}
Beispiel #3
0
/*{
** Name: psy_put	- Put characters in blocks for output
**
** Description:
**      This function buffers up characters to be sent to the user by SCF.
**	It puts as much of the current request in the current block as
**	possible.  If there is any overflow, it allocates another block and
**	puts the excess there.  It keeps doing this until all the input is
**	used up.
**
** Inputs:
**      mstream                         Memory stream to use for allocating
**					blocks.
**	inbuf				Characters to send to user
**	len				Number of chars to send to user
**	block				Pointer to pointer to block to use
**	err_blk				Filled in if an error happens
**
** Outputs:
**      block                           Filled in with string to send to user.
**					A new block may be allocated and this
**					pointer modified to point to new one.
**	err_blk				Filled in if an error happened
**	Returns:
**	    E_DB_OK			Success
**	    E_DB_FATAL			Failure
**	Exceptions:
**	    none
**
** Side Effects:
**	    Can allocate memory
**
** History:
**      15-jul-86 (jeff)
**          written
*/
DB_STATUS
psy_put(
	PSF_MSTREAM        *mstream,
	register char	   *inbuf,
	register i4	   len,
	PSY_QTEXT	   **block,
	DB_ERROR	   *err_blk)
{
    i4                  tocopy;
    i4			left;
    char		*outplace;
    PSY_QTEXT		*newblock;
    DB_STATUS		status;
#ifdef xDEBUG
    i4		val1, val2;	    /* tracing temps */
    PSS_SESBLK	   	*sess_cb;

    sess_cb = psf_sesscb();
#endif

    while (len > 0)
    {
	/* Copy as much of input as will fit in current block */
	left	= PSY_QTSIZE - (*block)->psy_qcount;
	tocopy = len > left ? left : len;
	outplace = (*block)->psy_qtext + (*block)->psy_qcount;
#ifdef xDEBUG
	if (ult_check_macro(&sess_cb->pss_trace,
				PSS_PSY_PUT_TRACE, &val1, &val2))
	{
	    TRdisplay("%.#s", tocopy, inbuf);
	}
#endif
	MEcopy(inbuf, tocopy, outplace);
	len			-= tocopy;
	(*block)->psy_qcount	+= tocopy;
	inbuf			+= tocopy;

	/* If there is more input, create another block and link it up */
	if (len > 0)
	{
	    status = psy_txtalloc(mstream, &newblock, err_blk);
	    if (DB_FAILURE_MACRO(status))
		return (status);

	    (*block)->psy_qnext = newblock;

	    /* Use the new block until a new one is allocated */
	    *block = newblock;
	}
    }

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

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

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

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

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

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

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

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

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

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

	enm = (char *)&alert.dba_alert;
	onm = (char *)&alert.dba_owner;
	errstr="RAISE";
	switch (scf_cb.scf_error.err_code)
	{
	  case E_SC0270_NO_EVENT_MESSAGE:
	    _VOID_ qef_error(E_QE019A_EVENT_MESSAGE, 0L, status, &err,
			     &qef_rcb->error, 1,
			     (i4)STlength(errstr), errstr);
	    break;
	  case E_SC0280_NO_ALERT_INIT:
	    _VOID_ qef_error(E_QE0200_NO_EVENTS, 0L, status, &err,
			     &qef_rcb->error, 1,
			     (i4)STlength(errstr), errstr);
	    break;
	  default:
	    _VOID_ qef_error(E_QE020F_EVENT_SCF_FAIL, 0L, status, &err,
			     &qef_rcb->error, 4,
			     (i4)STlength(errstr), errstr,
			     (i4)sizeof(i4),
					(PTR)&scf_cb.scf_error.err_code,
			     qec_trimwhite(DB_OWN_MAXNAME, onm), onm,
			     qec_trimwhite(DB_EVENT_MAXNAME, enm), enm);
	    break;
	}
	qef_rcb->error.err_code = E_QE0025_USER_ERROR;
	status = E_DB_ERROR;
    } /* If SCF not ok */
    return status;
}
Beispiel #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);
}
Beispiel #6
0
/*{
** Name: adu_rdm1_setup	- Setup for Redeem an ADF_COUPON
**
** Description:
**      This routine performs the initialization for the redeeming of
**      a coupon.  This amount primarily to initializing the
**      ADP_LO_WKSP function instance private and shared (adw_fip &
**      adw_shared, respectively).  This routine also moves the
**      appropriate peripheral header into the output area.
**
**      Since this routine moves the peripheral header to the output
**      area, in the case where the original call to this routine has
**      insufficient space for the output header, this routine may be
**      called more than once.  We note this since it is "unusual" for
**      the initialization routine to be called more than one time for
**      an object.  In the case where the original space is of
**      insufficent size, then this routine will return an indication
**      that the output area is full, and will move nothing into it.
**      Thus, this routine considers it a call-protocol error to be
**      called a second time with insufficient space.
**
** Inputs:
**      adf_scb                     The session's control block (ptr).
**      result_dv                   Pointer to DB_DATA_VALUE for
**                                      result.
**      coupon_dv                   Pointer to DB_DATA_VALUE
**                                      describing the input coupon to
**                                      be redeemed.
**      workspace_dv                Pointer to DB_DATA_VALUE
**                                      describing redeem's workspace.
**      continuation                Continuation indicator.  0
**                                      indicates the first call, else
**                                      not the first call.
**
** Outputs:
**      adf_scb->adf_error          Filled as appropriate.
**      *result_dv->db_data         Setup with beginning of peripheral
**                                      data type.
**      *workspace_dv->db_data      Initialized for ongoing redeem work.
**	Returns:
**	    DB_STATUS
**	Exceptions:
**	    None.
**
** Side Effects:
**	    None.
**
** History:
**      02-dec-1992 (fred)
**          Coded.  Created from adu_redeem prototype in support of
**          OME large objects.
**       8-Apr-1993 (fred)
**          Fixed bug in zero length large object handling.  For large
**          objects of zero length which are not nullable, the length
**          should not include the null-value-byte.
**      12-Oct-1993 (fred)
**          Removed call to ADP_INFORMATION -- subsumed by
**          adi_per_under(). 
**      10-sep-1998 (schte01)
**          Modified I4ASSIGN for axp_osf to pass the value, not the address
**          of the value, to be assigned. This worked under the -oldc
**          compiler option and got compile errors under -newc.
**	28-jul-1999 (thaju02)
**	    If the coupon stipulates that the data is not null, then
**	    the minimum result buffer length must be large enough to
**	    hold one byte of data along with all necessary info
**	    (ADP_HDR_SIZE + nextsegmarker(i4) + 2byteseglenindicator
**	    + 1byteofdata). Given a buffer with only 18 bytes of space
**	    available, 12 bytes are filled with peripheral header info
**	    in adu_rdm1_setup and 4 bytes are filled with the next
**	    segment marker in adu_redeem. In adc_lvch_xform, the 2 
**	    byte segment length indicator is initially set to zero 
**	    in the result buffer. If there is no space left in the 
**	    result buffer for segment data, we flush the buffer. In 
**	    the front end, upon receiving this result buffer, the 
**	    next segment marker indicates that there is data following, 
**	    yet the length is zero; terminal monitor infinitely loops. 
**	    (b98104)
**      12-aug-99 (stial01)
**          adu_rdm1_setup() 'blob_work' arg to adi_per_under should be  
**          NULL before redeem.
**      24-may-2000 (stial01)
**          adu_rdm1_setup() clear null indicator if not null (B101656)
**
[@history_template@]...
*/
DB_STATUS static
adu_rdm1_setup(ADF_CB             *adf_scb,
	       DB_DATA_VALUE      *result_dv,
	       DB_DATA_VALUE      *coupon_dv,
	       ADP_LO_WKSP        *work,
	       i4                 for_gca)
{
    DB_STATUS	    	status;  
    ADP_PERIPHERAL      *p = (ADP_PERIPHERAL *) result_dv->db_data;
    DB_DT_ID            dtid =
	ADI_DT_MAP_MACRO(abs(result_dv->db_datatype));
    i4			min_size;
    bool		isnull = 0;

    if (coupon_dv->db_datatype < 0)
	work->adw_fip.fip_null_bytes = 1;
    else
	work->adw_fip.fip_null_bytes = 0;

    if (ult_check_macro(&Adf_globs->Adf_trvect, ADF_011_RDM_TO_V_STYLE,
			&dummy1, &dummy2))
    {
	work->adw_fip.fip_test_mode = 1;
	work->adw_fip.fip_test_length = ADP_TST_VLENGTH +
	                                   work->adw_fip.fip_null_bytes;
	work->adw_fip.fip_test_sent = 0;
    }
    else
    {
	work->adw_fip.fip_test_mode = 0;
    }

    work->adw_shared.shd_exp_action = ADW_START;
    work->adw_fip.fip_done = FALSE;

    /*
    ** Fool the main routine into getting us an input segment.  Make
    ** look like the input segement is all used up.
    */
    
    work->adw_shared.shd_type = coupon_dv->db_datatype;
    work->adw_shared.shd_i_area = (char *) 0;
    work->adw_shared.shd_i_used = work->adw_shared.shd_i_length = 0;

    work->adw_shared.shd_o_used = ADP_HDR_SIZE;
    work->adw_shared.shd_o_length = result_dv->db_length;
    work->adw_shared.shd_o_area = (char *) result_dv->db_data;

    if (work->adw_shared.shd_o_length > MAXI2)
    {
	TRdisplay("adu_rdm1_setup shd_o_length %d MAX %d\n",
		work->adw_shared.shd_o_length, MAXI2);
	return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
    }
    work->adw_shared.shd_l0_check = work->adw_shared.shd_l1_check = 0;

    work->adw_fip.fip_pop_cb.pop_continuation = ADP_C_BEGIN_MASK;
    work->adw_fip.fip_pop_cb.pop_user_arg = (PTR) 0;
    
    work->adw_fip.fip_pop_cb.pop_type = (ADP_POP_TYPE);
    work->adw_fip.fip_pop_cb.pop_length = sizeof(ADP_POP_CB);
    work->adw_fip.fip_pop_cb.pop_ascii_id = ADP_POP_ASCII_ID;
    work->adw_fip.fip_pop_cb.pop_temporary = ADP_POP_PERMANENT;
    work->adw_fip.fip_pop_cb.pop_coupon = coupon_dv;
    work->adw_fip.fip_pop_cb.pop_segment = &work->adw_fip.fip_seg_dv;
    work->adw_fip.fip_pop_cb.pop_underdv = &work->adw_fip.fip_under_dv;
    status = adi_per_under(adf_scb,
			   result_dv->db_datatype,
			   &work->adw_fip.fip_under_dv);

    if (status)
    {
	return(adu_error(adf_scb, E_AD7000_ADP_BAD_INFO, 0));
    }

    STRUCT_ASSIGN_MACRO(work->adw_fip.fip_under_dv,
			work->adw_fip.fip_seg_dv);
    work->adw_fip.fip_seg_dv.db_data = (char *) ((char *) work +
						 sizeof(ADP_LO_WKSP));

    if (ADI_ISNULL_MACRO(coupon_dv) ||
       ((((ADP_PERIPHERAL *)coupon_dv->db_data)->per_length0 == 0)
       && (((ADP_PERIPHERAL *) coupon_dv->db_data)->per_length1 == 0))) 
	isnull = 1;

    if (isnull)
	/* hdr + segment indicator + sizeof(null byte) */
        min_size = ADP_HDR_SIZE + sizeof(i4) + work->adw_fip.fip_null_bytes; 
    else	
	/* hdr + segment indicator + segment length + segment single byte */
        min_size = ADP_HDR_SIZE + sizeof(i4) + sizeof(i2) + sizeof(char); 

    if (result_dv->db_length >= min_size)
    {
	if (for_gca)
	    work->adw_shared.shd_out_tag = ADP_P_GCA;
	else
	    work->adw_shared.shd_out_tag = ADP_P_DATA;
	
	I4ASSIGN_MACRO(work->adw_shared.shd_out_tag, p->per_tag);
	
	work->adw_shared.shd_out_segmented =
	    (work->adw_shared.shd_out_tag != ADP_P_DATA);

	I4ASSIGN_MACRO( ((ADP_PERIPHERAL *)
			 coupon_dv->db_data)->per_tag,
		       work->adw_shared.shd_inp_tag);
	work->adw_shared.shd_inp_segmented =
	    (work->adw_shared.shd_inp_tag != ADP_P_DATA);

	I4ASSIGN_MACRO( ((ADP_PERIPHERAL *)
			 coupon_dv->db_data)->per_length0,
		       p->per_length0);
	I4ASSIGN_MACRO(p->per_length0, work->adw_fip.fip_l0_value);
	I4ASSIGN_MACRO(((ADP_PERIPHERAL *)
			coupon_dv->db_data)->per_length1,
		       p->per_length1);
	I4ASSIGN_MACRO(p->per_length1, work->adw_fip.fip_l1_value);
	work->adw_fip.fip_state = ADW_F_RUNNING;
    }
    else if (work->adw_fip.fip_state != ADW_F_STARTING)
    {
	work->adw_fip.fip_state = ADW_F_STARTING;
	result_dv->db_length = 0;
	adf_scb->adf_errcb.ad_errcode = E_AD0002_INCOMPLETE;
	return(E_DB_INFO);
    }
    else
    {
	return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
    }

    if (isnull)
    {
	if (work->adw_fip.fip_test_mode)
	{
	    ((DB_TEXT_STRING *) p)->db_t_count = (i2) 0;

	    if (result_dv->db_length >=
		    (work->adw_fip.fip_test_length -
		              work->adw_fip.fip_test_sent))

	    {
		
		result_dv->db_length = work->adw_fip.fip_test_length -
		     work->adw_fip.fip_test_sent;
		work->adw_fip.fip_test_sent = work->adw_fip.fip_test_length;
	    }
	    else
	    {
		work->adw_fip.fip_state = ADW_F_DONE_NEED_NULL;
		work->adw_fip.fip_test_sent += result_dv->db_length;
		adf_scb->adf_errcb.ad_errcode = E_AD0002_INCOMPLETE;
		return(E_DB_INFO);
	    }
	}
	else
	{
	    i4	    zero = 0;

	    /*
	    **  Insert GCA mark that says there is no segment.
	    */
	
#if defined(axp_osf) || defined(ris_u64) || defined(LP64) || \
    defined(axp_lnx)
	    /*
	    **	We want to init the GCA field after the header, but
	    **	on axp_osf this is not the same as the start of the
	    **	coupon, because 8-byte alignment causes a slack 4-byte
	    **	integer to be between the header and the coupon.  See
	    **	adu_redeem above for a different way this field is set
	    **	to 1 when we have real data (not null).  The addressing
	    **	of this field should really be standardized in such a
	    **	way that contiguous layout of 4-byte aligned fields is
	    **	not assumed.
	    */
            I4ASSIGN_MACRO(zero,*((char *)p + ADP_HDR_SIZE)); 
#endif
	    I4ASSIGN_MACRO(zero, p->per_value);
	    
	    result_dv->db_length = ADP_NULL_PERIPH_SIZE;
	    if (work->adw_shared.shd_type > 0)
		result_dv->db_length -= 1;
        }
	if (ADI_ISNULL_MACRO(coupon_dv))
	    ADF_SETNULL_MACRO(result_dv);
	else
	    ADF_CLRNULL_MACRO(result_dv);
	adf_scb->adf_errcb.ad_errcode = E_DB_OK;
	work->adw_fip.fip_done = TRUE;
	return(E_DB_OK);
    }

    if (work->adw_fip.fip_test_mode)
    {
	i4	    	segment_count;
	i4	    	length1;
	i2		count;
	
	I4ASSIGN_MACRO(p->per_length1, length1);
	
	I4ASSIGN_MACRO(p->per_length0, segment_count);
	
	if (!segment_count)
	    segment_count = ADP_TST_SEG_CNT;
	
	count = min(	ADP_TST_VLENGTH,
		    (i2) (length1
			  + (segment_count *
			     (sizeof(i4) + sizeof(i2)))
			  + sizeof(i4) /* no more segments */
			  + work->adw_shared.shd_o_used)
		    ) - sizeof(i2);
	I2ASSIGN_MACRO(count, ((DB_TEXT_STRING *) p)->db_t_count);
    }
    return(E_DB_OK);
}
Beispiel #7
0
/*{
** Name: rdf_trace - Call RDF trace operation.
**
**	External call format:	status = rdf_trace(&db_debug_cb)
**
** Description:
**      This function is the standard entry point to RDF for setting and
**	clearing tracepoints(the "set trace point" command). Because RDF 
**	is a service facility, trace point for RDF can only be set on 
**	the server basis. There is no session level trace point. 
**	Db_debug_cb is the tracing control block that contains the trace 
**	flag information.
**
**	See file <rdftrace.h> for a description of all possible
**	RDF trace points.
**	
** Inputs:
**      debug_cb		    Pointer to a DB_DEBUG_CB
**        .db_trswitch              What operation to perform
**	    DB_TR_NOCHANGE	    None
**	    DB_TR_ON		    Turn on a tracepoint
**	    DB_TR_OFF		    Turn off a tracepoint
**	  .db_trace_point	    Trace point ID(the flag number)
**	  .db_value_count	    The number of values specified in
**				    the value array
**	  .db_vals[2]		    Optional values, to be interpreted
**				    differently for each tracepoint
** Outputs:
**	none
**
**	Returns:
**	    E_DB_OK			Function completed normally.
**	    E_DB_ERROR			Function failed due to error by caller;
**	    E_DB_FATAL			Function failed due to some internal
**					problem; 
**	Exceptions:
**		none
**
** Side Effects:
**	The trace vector in the server control block of RDF will be updated
**	to contain the trace information. The trace information will be persist
**	throughout the life of the server.
**
** History:
**	15-apr-86 (ac)
**          written
**	02-mar-87 (puree)
**	    replace global server control block with global pointer.
**	14-dec-1989 (teg)
**	    modify to go get svcb from SCF instead of using a global pointer
**	    to it.
**	16-jul-92 (teresa)
**	    prototypes
**	16-sep-92 (teresa)
**	    implement trace points rd3 and rd4 to clear ldbdesc cache.
**	22-apr-94 (teresa)
**	    added trace points rd11 and rd12 to dump memory statistics or all
**	    statistics.  This is an action trace point -- the dump occurs when 
**	    the trace point is selected rather than during query execution.
**	20-nov-2007 (thaju02)
**	    If trace point RD0022/RDU_CHECKSUM specified, invalidate 
**	    relcache. Entries need rdr_checksum to be calc/init'd 
**	    otherwise E_RD010D errors may be reported. (B119499)
*/
DB_STATUS
rdf_trace(DB_DEBUG_CB *debug_cb)
{
    i4		flag;
    i4		firstval;
    i4		secondval;
    DB_STATUS		status;
    i4		trace_scope;

    /* assure flag is legal */
    flag = debug_cb->db_trace_point;
    if (flag >= RDF_NB)
    {
	return (E_DB_ERROR);
    }

    /* There can be UP TO two values, but maybe they weren't given */
    firstval = (debug_cb->db_value_count > 0) ? debug_cb->db_vals[0] : 0L;
    secondval = (debug_cb->db_value_count > 1) ? debug_cb->db_vals[1] : 0L;

    /* see if this is an action trace.  Action traces require an immediate
    ** action rather than turning trace flags on/off/etc.
    */
    if ( (debug_cb->db_trswitch==DB_TR_ON) && (flag <= RD_ACT_MAX) )
    {
	/* see which action is requested.  Not all actions are implemented
	** yet, so its possible that this call may  become a no-opt 
	*/
	switch (flag)
	{
	case RD0001:
	case RD0002:
	case RD0003:
	case RD0004:
	case RD0005:
	case RD0010:
	    status=rdt_clear_cache(flag);
	    if (DB_FAILURE_MACRO(status))
	    {
		return(E_DB_ERROR);
	    }
	    break;
	case RD0011:
	    /* dump memory info.  This trace is used by tech support when
	    ** debugging out of memory errors. */
	    TRdisplay("\n...............................................\n");
	    TRdisplay("RDF Cache Memory Available:   %d\n",Rdi_svcb->rdv_memleft);
	    TRdisplay("RDF memory cache size     :   %d\n", 
			Rdi_svcb->rdv_pool_size);
	    TRdisplay("Max number of objects allowed on Cache:\n");
	    TRdisplay("   RELcache: %d,	    QTREE Cache: %d, \n",
			Rdi_svcb->rdv_cnt0_rdesc, Rdi_svcb->rdv_cnt1_qtree);
	    TRdisplay("   LDBDesc Cache %d,   DEFAULTS cache: %d\n",
			Rdi_svcb->rdv_cnt2_dist, Rdi_svcb->rdv_cnt3_default);
	    TRdisplay("Hashids:\n");
	    TRdisplay("   RELcache: %d,	    QTREE Cache: %d, \n",
			Rdi_svcb->rdv_rdesc_hashid, Rdi_svcb->rdv_qtree_hashid);
	    TRdisplay("   LDBDesc Cache %d,   DEFAULTS cache: %d\n",
			Rdi_svcb->rdv_dist_hashid, Rdi_svcb->rdv_def_hashid);
	    TRdisplay("...............................................\n");
	    break;
	case RD0012:
	    /* dump all of the RDF statistics */
	    rdf_report ( &Rdi_svcb->rdvstat );
	    break;

	    default:
		break;

	}
    }
    else
    {

	/*
	** determine if this is a session wide trace or a server wide trace
	** and process accordingly
	*/
	trace_scope = trace_type(flag);
	if (trace_scope == SVR_WIDE_TRACE)
	{   
	    /* turn trace on in svcb
	    **
	    ** Three possible actions: Turn on flag, turn it off, or do nothing.
	    */
	    switch (debug_cb->db_trswitch)
	    {
	    case DB_TR_ON:
		    if ((flag == RD0022) && 
			!(ult_check_macro(&Rdi_svcb->rdf_trace, 
					flag, &firstval, &secondval)))
		    {
			    /* setting RDU_CHECKSUM */
			    RDF_GLOBAL      global;
			    RDF_CB          rdfcb;
			    RDI_FCB         fcb;

			    global.rdfcb = &rdfcb;
			    rdfcb.rdf_rb.rdr_fcb = (PTR)&fcb;
			    rdfcb.rdf_info_blk = NULL;
			    rdfcb.rdf_rb.rdr_db_id = NULL;
			    rdfcb.rdf_rb.rdr_types_mask = 0;
			    rdfcb.rdf_rb.rdr_2types_mask = 0;
			    CSget_sid(&rdfcb.rdf_rb.rdr_session_id);
			    fcb.rdi_fac_id = DB_RDF_ID;
			    status = rdf_invalidate(&global, &rdfcb);
			    if (DB_FAILURE_MACRO(status))
				return(E_DB_ERROR);
		    }
		    ult_set_macro(&Rdi_svcb->rdf_trace, flag, firstval, secondval);
		break;

	    case DB_TR_OFF:
		    ult_clear_macro(&Rdi_svcb->rdf_trace, flag);
		break;

	    case DB_TR_NOCHANGE:
		/* Do nothing */
		break;

	    default:
		return (E_DB_ERROR);
	    };
	}
	else
	{
	    CS_SID	    sid;
	    RDF_SESS_CB	    *rdf_sess_cb;

	    /* 
	    ** this trace point is session specific, so use the session control
	    ** block for this trace point.
	    */

	    CSget_sid(&sid);
	    rdf_sess_cb = GET_RDF_SESSCB(sid);

	    /*
	    ** Three possible actions: Turn on flag, turn it off, or do nothing.
	    */

	    switch (debug_cb->db_trswitch)
	    {
	    case DB_TR_ON:
		    ult_set_macro(&rdf_sess_cb->rds_strace, 
				  flag, firstval, secondval);
		break;

	    case DB_TR_OFF:
		    ult_clear_macro(&rdf_sess_cb->rds_strace, flag);
		break;

	    case DB_TR_NOCHANGE:
		/* Do nothing */
		break;

	    default:
		return (E_DB_ERROR);
	    }
	}
    }
    return (E_DB_OK);
}
Beispiel #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);
}
Beispiel #9
0
DB_STATUS
qel_c0_cre_lnk(
QEF_RCB		*v_qer_p ) 
{
    DB_STATUS		status;
    QEF_CB		*qef_cb = v_qer_p->qef_cb;
    QES_DDB_SES		*dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses;
    QED_DDL_INFO	*ddl_p = & v_qer_p->qef_r3_ddb_req.qer_d7_ddl_info;
    DD_0LDB_PLUS	*plus_p = & ddl_p->qed_d6_tab_info_p->
			    dd_t9_ldb_p->dd_i2_ldb_plus;
    DD_CAPS		*caps_p = & plus_p->dd_p3_ldb_caps;
    DD_LDB_DESC		ldb,		    /* for replicating LDB desc */
			*ldb_p = & ldb,
			*cdb_p = & dds_p->qes_d4_ddb_p->
			    dd_d3_cdb_info.dd_i1_ldb_desc,
			*ddl_ldb_p = & ddl_p->qed_d6_tab_info_p->
			    dd_t9_ldb_p->dd_i1_ldb_desc;
    QEC_D9_TABLEINFO	tabinfo;	    /* used for table info of link */
    QEC_D2_LDBIDS	ldbids;		    /* used for internal LDB id info */
    QEC_D5_LONG_LDBNAMES
			longnames;	    /* used for excessively long LDB
					    ** name */
    QEC_L16_TABLES	tables;		    /* used for IITABLES-style info */
    QEC_D6_OBJECTS	objects;	    /* used for object info */
    QEC_L6_INDEXES	indexes;
    QEC_MIN_CAP_LVLS	pre_mins,
			aft_mins;
    QEC_LINK		link,		    /* used as global control block */
			*link_p = & link;
    QEQ_1CAN_QRY	del,
			ins,
			sel,
			upd,		    /* used for ordering canned query */
			*upd_p = & upd;
    u_i4		len;
    SYSTIME		now;
    bool		log_ddl_56 = FALSE,
			log_err_59 = FALSE;
    i4		i4_1,
			i4_2;
    QEC_INDEX_ID	ndx_ids[QEK_0MAX_NDX_COUNT + 1];
					    /* working space for index ids */
    RQB_BIND		rq_bind[QEC_CAT_COL_COUNT_MAX + 1];
    QEC_D7_OBJECT_BASE	obj_base,
			*base_p = & obj_base;
    i4			xact_mode;
    char		*cbuf = v_qer_p->qef_cb->qef_trfmt;
    i4			cbufsize = v_qer_p->qef_cb->qef_trsize;

    
    if (ult_check_macro(& qef_cb->qef_trace, QEF_TRACE_DDB_LOG_DDL_56,
	    & i4_1, & i4_2))
    {
        log_ddl_56 = TRUE;
    }
    
    if (ult_check_macro(& qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59,
	    & i4_1, & i4_2))
    {
        log_err_59 = TRUE;
    }
    sel.qeq_c2_rqf_bind_p = rq_bind;		/* must set up */
    del.qeq_c2_rqf_bind_p = (RQB_BIND *) NULL;
    ins.qeq_c2_rqf_bind_p = (RQB_BIND *) NULL;
    upd.qeq_c2_rqf_bind_p = (RQB_BIND *) NULL;

    /* 1.  set up control block */

    if (dds_p->qes_d7_ses_state == QES_4ST_REFRESH)	
						/* REGISTER WITH REFRESH ? */
	STRUCT_ASSIGN_MACRO(ddl_p->qed_d7_obj_id, tabinfo.d9_1_obj_id);
						/* yes */
    else					/* no */
    {
	tabinfo.d9_1_obj_id.db_tab_base = 0;	/* unknown */
	tabinfo.d9_1_obj_id.db_tab_index = 0;	/* always 0 for non-index */
    }
    link_p->qec_1_ddl_info_p = ddl_p;
    link_p->qec_2_tableinfo_p = & tabinfo;
    link_p->qec_3_ldb_id = 0;			
    link_p->qec_4_col_cnt = 0;
    MEfill(DB_DB_MAXNAME, ' ', link_p->qec_5_ldb_alias);
    link_p->qec_6_select_p = & sel;
    link_p->qec_7_ldbids_p = & ldbids;
    link_p->qec_8_longnames_p = & longnames;
    link_p->qec_9_tables_p = & tables;
    link_p->qec_10_haves = QEC_07_CREATE;
    if (caps_p->dd_c6_name_case == DD_2CASE_UPPER)
	link_p->qec_10_haves |= QEC_06_UPPER_LDB;
    if (caps_p->dd_c1_ldb_caps & DD_7CAP_USE_PHYSICAL_SOURCE)
	link_p->qec_10_haves |= QEC_10_USE_PHY_SRC;
    if (caps_p->dd_c2_ldb_caps & DD_201CAP_DIFF_ARCH)
	link_p->qec_10_haves |= QEC_11_LDB_DIFF_ARCH;

    /* make a copy of the LDB descriptor for non-$ingrs access if necessary */

    if (ddl_ldb_p->dd_l1_ingres_b)
    {
	/* make a copy for non-$ingres access */

	STRUCT_ASSIGN_MACRO(*ddl_ldb_p, ldb);
	ldb_p->dd_l1_ingres_b = FALSE;
	ldb_p->dd_l5_ldb_id = DD_0_IS_UNASSIGNED;
    }
    else
    {	
	/* use provided LDB descriptor but determine if LDB has a long name */

	qed_u0_trimtail(
		ddl_ldb_p->dd_l3_ldb_name, 
		(u_i4) DD_256_MAXDBNAME,
		ldb_p->dd_l3_ldb_name);

	len = STlength(ldb_p->dd_l3_ldb_name);
	if (len > DB_DB_MAXNAME)
	    link_p->qec_10_haves |= QEC_04_LONG_LDBNAME;

	ldb_p = ddl_ldb_p;
    }
    link_p->qec_11_ldb_obj_cnt = 0;
    link_p->qec_12_indexes_p = & indexes;
    link_p->qec_13_objects_p = & objects;
    link_p->qec_15_ndx_cnt = 0;
    link_p->qec_16_ndx_ids_p = ndx_ids;
    link_p->qec_19_ldb_p = ldb_p;
    link_p->qec_20_rqf_bind_p = rq_bind;
    link_p->qec_21_delete_p = & del;
    link_p->qec_22_insert_p = & ins;
    link_p->qec_23_update_p = & upd;

    status = qed_u8_gmt_now(v_qer_p, link_p->qec_24_cur_time);
    if (status)
	return(status);

    link_p->qec_24_cur_time[DD_25_DATE_SIZE] = EOS;
    link_p->qec_25_pre_mins_p = & pre_mins;
    link_p->qec_26_aft_mins_p = & aft_mins;
    link_p->qec_27_select_cnt = 0;
    link_p->qec_28_iistats_cnt = 0;
    
    TMnow(& now);
    link_p->qec_17_ts1 = now.TM_secs;
    link_p->qec_18_ts2 = now.TM_msecs;
    
    /* 2.  inform TPF of update intention on CDB (note that only CREATE does
    **	   LDB retrievals */

    /* 2.1 2PC is required if DDL concurrency is off. */
    if (dds_p->qes_d9_ctl_info & QES_01CTL_DDL_CONCURRENCY_ON)
	xact_mode = QEK_4TPF_1PC;
    else
	xact_mode = QEK_3TPF_UPDATE;

    status = qet_t5_register(v_qer_p, cdb_p, DB_SQL, xact_mode);
    if (status)
	return(status);

    if (log_ddl_56)
    {
	/* display beginning, CDB and LDB info */

	STprintf(cbuf, "\n%s %p: %s REGISTRATION begins%s\n",
	    IIQE_61_qefsess,
	    (PTR) v_qer_p->qef_cb,
	    IIQE_65_tracing,
	    IIQE_62_3dots);
        qec_tprintf(v_qer_p, cbufsize, cbuf);

	STprintf(cbuf, 
	    "%s %p: ...the CDB:\n",
	    IIQE_61_qefsess,
	    (PTR) v_qer_p->qef_cb);
        qec_tprintf(v_qer_p, cbufsize, cbuf);
	qed_w1_prt_ldbdesc(v_qer_p, cdb_p);

	STprintf(cbuf, 
	    "%s %p: ...the LDB:\n",
	    IIQE_61_qefsess,
	    (PTR) v_qer_p->qef_cb);
        qec_tprintf(v_qer_p, cbufsize, cbuf);
	qed_w1_prt_ldbdesc(v_qer_p, ldb_p);

	STprintf(cbuf, "\n");
        qec_tprintf(v_qer_p, cbufsize, cbuf);
    }
    /* 3.  update OBJECT_BASE in II_DD_DB_OBJECT_BASE */

    upd_p->qeq_c1_can_id = UPD_716_DD_DDB_OBJECT_BASE;
    upd_p->qeq_c3_ptr_u.d7_object_base_p = base_p;
    upd_p->qeq_c4_ldb_p = cdb_p;

    status = qel_u1_update(v_qer_p, link_p);
    if (status)
	goto END_TRACING;

    /* 4.  enter phase 1: set up necessary information */

    status = qel_c1_cre_p1(v_qer_p, link_p);
    if (status)
	goto END_TRACING;

    /* 2.  enter phase 2: promote information into STAR catalogs */

    status = qel_c2_cre_p2(v_qer_p, link_p);
    if (status)
	v_qer_p->qef_cb->qef_abort = TRUE;

END_TRACING:

    if (log_ddl_56)
    {
	/* display end tracing message */

	STprintf(cbuf, 
	    "%s %p: %s REGISTRATION ends\n\n",
	    IIQE_61_qefsess,
	    (PTR) v_qer_p->qef_cb,
	    IIQE_65_tracing);
        qec_tprintf(v_qer_p, cbufsize, cbuf);
    }

    return(status);
}    
Beispiel #10
0
DB_STATUS
tpd_s3_send_sps_to_ldb(
	TPR_CB		*v_tpr_p,
	TPD_LX_CB	*v1_lxcb_p)
{
    DB_STATUS	status = E_DB_OK;
    TPD_SS_CB	*sscb_p = (TPD_SS_CB *) v_tpr_p->tpr_session;
    TPD_DX_CB	*dxcb_p = & sscb_p->tss_dx_cb;
    TPD_LM_CB	*splm_p = & dxcb_p->tdx_23_sp_ulmcb;
    TPD_SP_CB	*spcb_p = (TPD_SP_CB *) splm_p->tlm_3_frst_ptr;
    i4		i;
    RQR_CB	rqr_cb;
    bool        trace_svpt_103 = FALSE,
                trace_err_104 = FALSE;
    i4     i4_1,
                i4_2;
    char	svpt_name[sizeof(DB_SP_NAME) + 1],
		qrytxt[100];


    if (spcb_p == NULL			/* no savepoints ? */
	||
	v1_lxcb_p->tlx_sp_cnt >= splm_p->tlm_2_cnt)
					/* LDB has seen all savepoints ? */
	return(E_DB_OK);		/* yes, nothing to do */

    /* skip the privileged CDB if DDL concurrency is ON, an "autocommit"
    ** condition */

    if (sscb_p->tss_ddl_cc && v1_lxcb_p->tlx_site.dd_l1_ingres_b)	
	return(E_DB_OK);		    /* nothing to do */

    if (ult_check_macro(& sscb_p->tss_3_trace_vector, TSS_TRACE_SVPT_103,
            & i4_1, & i4_2))
    {
        trace_svpt_103 = TRUE;
    }

    if (ult_check_macro(& sscb_p->tss_3_trace_vector, TSS_TRACE_ERROR_104,
            & i4_1, & i4_2))
    {
        trace_err_104 = TRUE;
    }

    /* pre-set static parameters to call RQF */

    rqr_cb.rqr_timeout = 0;
    rqr_cb.rqr_q_language = v_tpr_p->tpr_lang_type;
    rqr_cb.rqr_session = sscb_p->tss_rqf;
    
    /* query length to be set below when constructed */

    rqr_cb.rqr_msg.dd_p2_pkt_p = qrytxt;
    rqr_cb.rqr_msg.dd_p3_nxt_p = NULL;
    rqr_cb.rqr_1_site = & v1_lxcb_p->tlx_site;
    rqr_cb.rqr_dv_cnt = 0;
    rqr_cb.rqr_dv_p = (DB_DATA_VALUE *) NULL;

    /* position at the first savepoint not yet sent to the site */

    if (v1_lxcb_p->tlx_sp_cnt > 0)
	for (i = 0; spcb_p != NULL && i < v1_lxcb_p->tlx_sp_cnt; ++i)
	    spcb_p = spcb_p->tsp_4_next_p;  
				/* advance to the next savepoint */
    while (spcb_p != NULL)
    {
	/* set up dynamic parameters to request current savepoint */

	/* construct query for current savepoint on the fly */

	tpd_u0_trimtail((char *) & spcb_p->tsp_1_name, 
	    sizeof(DB_SP_NAME), svpt_name);
	if (v_tpr_p->tpr_lang_type == DB_QUEL)
	    STprintf(qrytxt, "%s %s;", IITP_10_savepoint_p, svpt_name);	
	else
	    STprintf(qrytxt, "%s %s;", IITP_10_savepoint_p, svpt_name);	

	rqr_cb.rqr_msg.dd_p1_len = (i4) STlength(qrytxt);

	if (trace_svpt_103)
	    tpd_p5_prt_tpfqry(v_tpr_p, qrytxt, & v1_lxcb_p->tlx_site,
		TPD_0TO_FE);

	status = tpd_u4_rqf_call(RQR_QUERY, & rqr_cb, v_tpr_p);
	if (status)
	{
	    if (trace_err_104)
		tpd_p5_prt_tpfqry(v_tpr_p, qrytxt, & v1_lxcb_p->tlx_site,
		    TPD_0TO_FE);
	    return(status);
	}
	spcb_p = spcb_p->tsp_4_next_p;	/* advance to next savepoint */
    }

    v1_lxcb_p->tlx_sp_cnt = splm_p->tlm_2_cnt;
					/* all savepoints are now known to site
					*/
    return(E_DB_OK);
}
Beispiel #11
0
DB_STATUS
qeq_c4_open(
QEF_RCB		*v_qer_p,
QEE_DSH		*v_dsh_p )
{
    DB_STATUS	    status = E_DB_OK;
    QEF_CB	    *qef_cb = v_qer_p->qef_cb;
    QEF_AHD	    *act_p = (QEF_AHD *) NULL,
		    *def_act_p = (QEF_AHD *) NULL;
    i4		    def_act_cnt = 0,
		    get_act_cnt = 0,
		    lnk_act_cnt = 0;
    QEQ_D1_QRY	    *sub_p = (QEQ_D1_QRY *) NULL;
    bool	    read_b = FALSE,
		    last_b = FALSE,
		    val_qp_51 = FALSE,
		    log_qry_55 = FALSE,
                    log_err_59 = FALSE;
    i4         i4_1, i4_2;


    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55,
        & i4_1, & i4_2))
    {
        log_qry_55 = TRUE;
        qeq_p31_opn_csr(v_qer_p, v_dsh_p);;
    }
    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59,
        & i4_1, & i4_2))
        log_err_59 = TRUE;

    /* verify that the following conditions are true of the query plan:
    **
    **  1)  there is exactly one last QEA_D7_OPN action,
    **  2)  there are no QEA_D2_GET, QEA_D4_LNK actions,
    **  3)  there are no read actions  */

    act_p = v_dsh_p->dsh_qp_ptr->qp_ahd; 

    while (act_p != (QEF_AHD *) NULL)
    {
	if (act_p->ahd_atype == QEA_D7_OPN)
	{
	    def_act_cnt++;
	    if (act_p->ahd_next == (QEF_AHD *) NULL)
		last_b = TRUE;
	}
	else if (act_p->ahd_atype == QEA_D2_GET)
	    get_act_cnt++;
	else if (act_p->ahd_atype == QEA_D4_LNK)
	    lnk_act_cnt++;
	else if (act_p->ahd_atype == QEA_D1_QRY)
	{
	    sub_p = & act_p->qhd_obj.qhd_d1_qry;
	    if (sub_p->qeq_q3_ctl_info & QEQ_001_READ_TUPLES)
		read_b = TRUE;
	}
	act_p = act_p->ahd_next;
    }
	
    if (! last_b || def_act_cnt != 1 || get_act_cnt != 0 || 
	lnk_act_cnt != 0 || read_b)
    {
	if (log_err_59 && !log_qry_55)
	    qeq_p31_opn_csr(v_qer_p, v_dsh_p);;

	status = qed_u2_set_interr(E_QE1999_BAD_QP, & v_qer_p->error);
	return(status);
    }

    qee_d1_qid(v_dsh_p);			/* generate query id for
						** sending to LDB */
    /* process each action in the QP */

    for (act_p = v_dsh_p->dsh_qp_ptr->qp_ahd; 
	 act_p != (QEF_AHD *)NULL; 
	 act_p = act_p->ahd_next)
    {
	/* check for deferred cursor, only one at a time is allowed */
	if (act_p->ahd_flags & QEA_DEF)
	{
	    v_dsh_p->dsh_qp_status |= DSH_DEFERRED_CURSOR;
	    if (qef_cb->qef_defr_curs)
	    {
		qed_u10_trap();
		v_qer_p->error.err_code = E_QE0026_DEFERRED_EXISTS;
		return(E_DB_ERROR);
	    }
	}

	switch (act_p->ahd_atype)
	{
	case QEA_D1_QRY:
	case QEA_D8_CRE:
	case QEA_D9_UPD:
	    status = qeq_d1_qry_act(v_qer_p, & act_p);
	    if (status)
		qed_u10_trap();
	    break;
	case QEA_D3_XFR:
	    status = qeq_d5_xfr_act(v_qer_p, act_p);
	    if (status)
		qed_u10_trap();
	    break;
	case QEA_D6_AGG:
	    status = qeq_d10_agg_act(v_qer_p, act_p);
	    if (status)
		qed_u10_trap();
	    break;
	case QEA_D7_OPN:
	    def_act_p = act_p;		/* keep track */

	    status = qeq_d8_def_act(v_qer_p, act_p);
	    if (status)
		qed_u10_trap();
	    break;
	default:
	    status = qed_u1_gen_interr(& v_qer_p->error);
	    qed_u10_trap();
	    break;
	}
	if (! status)
	    v_dsh_p->dsh_act_ptr = act_p;	/* promote to current dsh */
    }

    /* cleanup done by caller */

    v_dsh_p->dsh_act_ptr = def_act_p;    /* pt to define action */
    return (status);
}
Beispiel #12
0
DB_STATUS
qeq_c3_fetch(
QEF_RCB	    *v_qer_p,
QEE_DSH	    *i_dsh_p )
{
    DB_STATUS	    status = E_DB_OK;
    QES_DDB_SES	    *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses;
    QES_QRY_SES	    *qss_p = & dds_p->qes_d8_union.u2_qry_ses;
    QEE_DDB_CB	    *qee_p = i_dsh_p->dsh_ddb_cb;
/*
    QEF_QP_CB	    *qph_p = 
		    ((QEE+DSH *)(v_qer_p->qef_cb->qef_dsh))->dsh_qp_ptr;
*/
    bool	    log_qry_55 = FALSE,
                    log_err_59 = FALSE;
    i4         i4_1, i4_2;
    TPR_CB	    tpr,
		    *tpr_p = & tpr;
    RQR_CB	    rqr,
		    *rqr_p = & rqr;


    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55,
        & i4_1, & i4_2))
    {
        log_qry_55 = TRUE;
	qeq_p33_fet_csr(v_qer_p, i_dsh_p);
    }
    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59,
        & i4_1, & i4_2))
        log_err_59 = TRUE;

    if (! (qee_p->qee_d3_status & QEE_03Q_DEF))
    {
	/* cursor either not opened or closed */

	status = qed_u1_gen_interr(& v_qer_p->error);
	return(status);
    }

    if (qee_p->qee_d3_status & QEE_04Q_EOD)
    {
	/* no more data */

	v_qer_p->qef_rowcount = 0;

	/* must return E_QE0015_NO_MORE_ROWS to signal exhaustion of data */

	v_qer_p->error.err_code = E_QE0015_NO_MORE_ROWS;
	return(E_DB_WARN);
    }

/*
    ** 1.  set up to call TPF for read operation **

    MEfill(sizeof(tpr), '\0', (PTR) & tpr);
    tpr_p->tpr_session = dds_p->qes_d2_tps_p;	** TPF session id **
    tpr_p->tpr_rqf = dds_p->qes_d3_rqs_p;	** RQF session id **
    tpr_p->tpr_lang_type = qss_p->qes_q2_lang;
    tpr_p->tpr_site = & qee_p->qee_d11_ldbdesc;

    status = qed_u17_tpf_call(TPF_READ_DML, tpr_p, v_qer_p);
    if (status)
    {
	return(status);
    }
*/

    /* 2.  set up to call RQF to load data */

    MEfill(sizeof(rqr), '\0', (PTR) & rqr);
    rqr_p->rqr_session = dds_p->qes_d3_rqs_p;   /* RQF session id */

    rqr_p->rqr_q_language = qss_p->qes_q2_lang;
    rqr_p->rqr_timeout = QEK_0_TIME_QUANTUM;
    rqr_p->rqr_1_site = & qee_p->qee_d11_ldbdesc;
    STRUCT_ASSIGN_MACRO(qee_p->qee_d5_local_qid, rqr_p->rqr_qid);
    rqr_p->rqr_inv_parms = (PTR) v_qer_p->qef_param;	

    /* 3.  relay SCF parameters */

    rqr_p->rqr_tupcount = v_qer_p->qef_rowcount;
    rqr_p->rqr_tupdata = (PTR) v_qer_p->qef_output;
    rqr_p->rqr_tupdesc_p = (PTR) NULL;

    status = qed_u3_rqf_call(RQR_FETCH, rqr_p, v_qer_p);
    if (status)
    {
	if (log_err_59 && !log_qry_55)
	    qeq_p33_fet_csr(v_qer_p, i_dsh_p);

	/* it is assumed that RQF has repaired itself before returning */

	dds_p->qes_d7_ses_state = QES_0ST_NONE;	/* reset */
	STRUCT_ASSIGN_MACRO(rqr_p->rqr_error, v_qer_p->error);
	return(status);
    }

    if (rqr_p->rqr_end_of_data)
	qee_p->qee_d3_status |= QEE_04Q_EOD;	/* must set */

    /* return data gotten so far */

    v_qer_p->qef_rowcount = rqr_p->rqr_tupcount;
    v_qer_p->qef_count = rqr_p->rqr_count;

    if ((v_qer_p->qef_rowcount == 0) || (v_qer_p->qef_count == 0))
    {
	/* no more data */

	qee_p->qee_d3_status |= QEE_04Q_EOD;	/* must set */

	/* must return E_QE0015_NO_MORE_ROWS to signal no more data for 
	** subquery */

	v_qer_p->error.err_code = E_QE0015_NO_MORE_ROWS;
	return(E_DB_WARN);
    }
    else if ((v_qer_p->qef_rowcount == 0)
	     && (v_qer_p->qef_count != 0))
    {
	/* Here we emulate an incomplete condition */

	v_qer_p->error.err_code = E_AD0002_INCOMPLETE;
	return(E_DB_INFO);
    }

    return(E_DB_OK);
}
Beispiel #13
0
DB_STATUS
qeq_c1_close(
QEF_RCB	    *v_qer_p,
QEE_DSH	    *i_dsh_p )
{
    DB_STATUS	    status;
    QES_DDB_SES	    *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses;
    QEE_DDB_CB	    *qee_p = i_dsh_p->dsh_ddb_cb;
/*
    QES_QRY_SES	    *qss_p = & dds_p->qes_d8_union.u2_qry_ses;
    QEF_QP_CB	    *qp_p = dsh_p->dsh_qp_ptr;
*/
    QEQ_D1_QRY	    *sub_p = & i_dsh_p->dsh_act_ptr->qhd_obj.qhd_d1_qry;
    bool	    log_qry_55 = FALSE,
                    log_err_59 = FALSE;
    i4         i4_1, i4_2;
    RQR_CB	    rqr,
		    *rqr_p = & rqr;


    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55,
        & i4_1, & i4_2))
    {
        log_qry_55 = TRUE;
	qeq_p31_opn_csr(v_qer_p, i_dsh_p);
    }
    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59,
        & i4_1, & i4_2))
        log_err_59 = TRUE;

    /*
    ** Do actual close only if marked opened. We could be interrupted
    ** between when qef_open_count is incremented, and the actual open
    */

    if (!(qee_p->qee_d3_status & QEE_03Q_DEF))
	return (E_DB_OK);

    MEfill(sizeof(rqr), '\0', (PTR) & rqr);
    rqr_p->rqr_session = dds_p->qes_d3_rqs_p;   /* RQF session id */

    rqr_p->rqr_q_language = sub_p->qeq_q1_lang;
    rqr_p->rqr_timeout = sub_p->qeq_q2_quantum;
    rqr_p->rqr_1_site = sub_p->qeq_q5_ldb_p;
    rqr_p->rqr_tmp = qee_p->qee_d1_tmp_p;

    STRUCT_ASSIGN_MACRO(qee_p->qee_d5_local_qid, rqr_p->rqr_qid);
    rqr_p->rqr_inv_parms = (PTR) NULL;

    status = qed_u3_rqf_call(RQR_CLOSE, rqr_p, v_qer_p);
    if (status)
    {
	if (log_err_59 && !log_qry_55)
	    qeq_p31_opn_csr(v_qer_p, i_dsh_p);
	return(status);
    }	

    qee_p->qee_d3_status &= ~QEE_03Q_DEF;	/* cursor closed */

    return(E_DB_OK);
}
Beispiel #14
0
DB_STATUS
qen_fsmjoin(
QEN_NODE	*node,
QEF_RCB		*qef_rcb,
QEE_DSH		*dsh,
i4		function )
{
    QEF_CB	    *qef_cb = dsh->dsh_qefcb;
    DMR_CB	    *dmrcb;
    QEN_NODE	    *out_node = node->node_qen.qen_sjoin.sjn_out;
    QEN_NODE	    *in_node = node->node_qen.qen_sjoin.sjn_inner;
    QEE_XADDRS	    *node_xaddrs = dsh->dsh_xaddrs[node->qen_num];
    QEN_STATUS	    *qen_status = node_xaddrs->qex_status;
    ADE_EXCB	    *ade_excb;
    ADE_EXCB	    *jqual_excb = node_xaddrs->qex_jqual;
    QEN_HOLD	    *qen_hold;
    QEN_HOLD	    *ijFlagsHold = (QEN_HOLD *)NULL;
    QEN_SHD         *qen_shd;
    QEN_SHD         *ijFlagsShd;
    DB_STATUS	    status = E_DB_OK;
    bool	    reset = FALSE;
    bool	    out_reset = FALSE;
    bool	    in_reset = FALSE;
    bool            ojoin = (node->node_qen.qen_sjoin.sjn_oj != NULL); 
    bool            ljoin = FALSE;
    bool            rjoin = FALSE;
    bool	    innerTupleJoined;
    bool	    rematerializeInnerTuple = TRUE;
			/* During full joins, the last driving tuple may left
			** join.  This 0s all special eqcs from the
			** re-scannable stream.  The current re-scannable
			** tuple will right join.  To recover the state of
			** its special eqcs, simply re-materialize the inner
			** tuple.  That's what this variable is for.
			*/
    i4		    new_to_old;
    i4		    join_result;
    i4	    val1;
    i4	    val2;
    TIMERSTAT	    timerstat;
    bool potential_card_violation = FALSE;

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

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

	/* 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);
	    status = (*in_node->qen_func)(in_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))
	    {
		/* Ideally we would clean up all of our own shd crap here
		** instead of making qee do it...
		*/
		status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_CLOSE);
		status = (*in_node->qen_func)(in_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);
	}

	/* End of partition group call just gets passed down. */
	if (function & FUNC_EOGROUP)
	{
	    status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_EOGROUP);
	    status = (*in_node->qen_func)(in_node, qef_rcb, dsh, FUNC_EOGROUP);
	    return(E_DB_OK);
	}
    } /* if function */

    /* 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);
    }
     

    /* 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);

    dsh->dsh_error.err_code = E_QE0000_OK;

    qen_hold = dsh->dsh_hold[node->node_qen.qen_sjoin.sjn_hfile];
    qen_shd = dsh->dsh_shd[dsh->dsh_qp_ptr->qp_sort_cnt +
                            node->node_qen.qen_sjoin.sjn_hfile];

    if( ojoin && node->node_qen.qen_sjoin.sjn_oj->oj_ijFlagsFile >= 0 )
    {
        ijFlagsHold =
	  dsh->dsh_hold[node->node_qen.qen_sjoin.sjn_oj->oj_ijFlagsFile];
        ijFlagsShd = dsh->dsh_shd[dsh->dsh_qp_ptr->qp_sort_cnt +
                            node->node_qen.qen_sjoin.sjn_oj->oj_ijFlagsFile];
    }

    if ( ojoin ) switch(node->node_qen.qen_sjoin.sjn_oj->oj_jntype)
    {
       case DB_LEFT_JOIN:
         ljoin = TRUE;
         break;
       case DB_RIGHT_JOIN:
         rjoin = TRUE;
         break;
       case DB_FULL_JOIN:
         ljoin = TRUE;
         rjoin = TRUE;
         break;
       default: break;
    }

    /* If the node is to be reset, dump the hold file and reset the
    ** inner/outer nodes */

loop_reset:
    if (reset)
    {
	if (qen_status->node_status != QEN0_INITIAL && 
	    in_node->qen_type != QE_SORT)
	{
	    /* reset in memory or dump dmf hold if it has been created */
	    status = qen_u9_dump_hold(qen_hold, dsh, qen_shd);
	    if(status) goto errexit;
	    qen_hold->hold_medium = HMED_IN_MEMORY;  /* set back to mem */
	}
	qen_hold->hold_buffer_status = HFILE6_BUF_EMPTY;

	if ( qen_status->node_status != QEN0_INITIAL && ijFlagsHold )
	{
	    /* dump tid hold file if it has been created */

	    status = qen_u9_dump_hold( ijFlagsHold, dsh, ijFlagsShd );
	    if(status) goto errexit;  
	    ijFlagsHold->hold_medium = HMED_IN_MEMORY;  /* set back to mem */
	}

	qen_status->node_status = QEN0_INITIAL;  /* reset = reintialize */
	qen_status->node_u.node_join.node_inner_status = QEN0_INITIAL;
	qen_status->node_u.node_join.node_outer_status = QEN0_INITIAL;
	qen_status->node_u.node_join.node_outer_count = 0;

	qen_status->node_access = (	QEN_READ_NEXT_OUTER |
					QEN_READ_NEXT_INNER |
					QEN_OUTER_HAS_JOINED	);  
    }

    if (qen_status->node_status == QEN0_INITIAL)  
    {
	qen_status->node_u.node_join.node_outer_status = QEN0_INITIAL;

	/* set num entries in mem_hold in case we build one */
	/* this may not be a hard number in future */
	/* qen_shd->shd_tup_cnt = 20; */

	/* by setting it to -1, the required memory will be configured to */
	/* suit the condition. if it is < 20, it will use the dmf hold mem*/
	/* ramra01 19-oct-94 */
	qen_shd->shd_tup_cnt = -1;

	if( ijFlagsHold )
	{
	    ijFlagsHold->hold_status = HFILE0_NOFILE;	/* default */
	    ijFlagsHold->hold_status2 = 0;		/* default */
	    ijFlagsHold->hold_medium = HMED_IN_MEMORY;  /* default */
	    /* in case we build a hold file
	    ** tell qen_u1_append to calculate its size in memory
	    ** or go to DMF hold */
	    ijFlagsShd->shd_tup_cnt = -1;
	}

	if(rjoin)
	{
	    /* consistency check */
	    if( !ijFlagsHold )
	    {
		/* rjoin and no hold file for inner join flags */
		dsh->dsh_error.err_code = E_QE0002_INTERNAL_ERROR;
		status = E_DB_ERROR;
		goto errexit;           
	    }
	}

	qen_status->node_access = (	QEN_READ_NEXT_OUTER |
					QEN_READ_NEXT_INNER |
					QEN_OUTER_HAS_JOINED	);  
    }

    for (;;)   /* The loop */
    {
	status = E_DB_OK;

	/*********************************************************
	**	
	**	LOGIC TO READ FROM THE OUTER TUPLE STREAM
	**
	**
	**
	*********************************************************/

	if( qen_status->node_access & QEN_READ_NEXT_OUTER )
	{

	    /*
	    ** If the previous outer tuple did not inner join with
	    ** any inner tuples, then it's an outer join.  Return
	    ** it along with nulls for the right side if it passes
	    ** the WHERE clause.
	    */

	    if ( ljoin && !( qen_status->node_access & QEN_OUTER_HAS_JOINED ) )
	    {
		/*
		** Set the "outer has joined" flag so that if we emit
		** a left join, we won't come back into this conditional
		** the next time through this fmsjoin node.
		*/
		qen_status->node_access |= QEN_OUTER_HAS_JOINED;

		/* now execute oj_lnull */
		status = qen_execute_cx(dsh, node_xaddrs->qex_lnull);
		if (status != E_DB_OK)
		    goto errexit;   /* if ade error, return error */

		/* Execute jqual restriction, if any */
		if ( jqual_excb == NULL)
		    break;	/* emit a left join */
		else
		{
		    status = qen_execute_cx(dsh, jqual_excb);
		    if (status != E_DB_OK)
			goto errexit;   /* if ade error, return error */
		    if (jqual_excb->excb_value == ADE_TRUE)
			break;	/* emit a left join */
		}
	    }	/* endif previous outer did not join */

	    qen_status->node_access &= ~(	QEN_READ_NEXT_OUTER |
						QEN_OUTER_HAS_JOINED	);
	    /* get a new outer */

	newouter:
	    if ( qen_status->node_u.node_join.node_outer_status == QEN8_OUTER_EOF )
	    {
	        status = E_DB_WARN;
		dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS;
	    }
	    else	/* this is where we actually read the outer stream! */
	    {
	        status = (*out_node->qen_func)(out_node, qef_rcb, dsh,
				(out_reset) ? FUNC_RESET : NO_FUNC);
		if (status == E_DB_OK)
		    qen_status->node_u.node_join.node_outer_count++;
	    }
	    out_reset = FALSE;

	    /* a little error handling.  check for end of outer stream */
	    if (status != E_DB_OK)
	    {
		if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS ||
		    dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION &&
		    node->qen_flags & QEN_PART_SEPARATE)
		{
		    /* If no outer rows were read and we're doing partition
		    ** grouping, skip the next inner partition to re-sync. */
		    if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION &&
			qen_status->node_u.node_join.node_outer_count <= 0)
		     if (!rjoin)
		     {
			if (node->qen_flags & QEN_PART_SEPARATE)
			{
			    status = (*in_node->qen_func)(in_node, qef_rcb, 
						dsh, FUNC_EOGROUP);
			    if (dsh->dsh_error.err_code == 
						E_QE00A5_END_OF_PARTITION)
				qen_status->node_status_flags |=
						QEN4_IPART_END;
					/* if just EOPartition, flag it */
			}
		     goto errexit;
		     }

		    qen_status->node_access |= QEN_OUTER_HAS_JOINED;
                    qen_status->node_u.node_join.node_outer_status = QEN8_OUTER_EOF;

		    if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION)
			qen_status->node_status_flags |= QEN2_OPART_END;
					/* if just EOPartition, flag it */

		    /*
		    ** If ( the inner stream is exhausted and there's nothing
		    ** to rescan ) or we're not right joining,
		    ** then there are no more tuples to return.  This should
		    ** be the only way to end this fsmjoin node.
		    */
		    if ( INNER_STREAM_EXHAUSTED || rjoin == FALSE  )
                    {
		       qen_status->node_status = QEN4_NO_MORE_ROWS;
                       break;    /* done */
                    }    
                    
                    else	/* we must check some more inner tuples */
		    {
                       dsh->dsh_error.err_code = 0;   /*reset*/

		       if(qen_status->node_status == QEN0_INITIAL)  /* empty */
		       {
			    qen_status->node_status = QEN1_EXECUTED;
			    qen_hold->hold_status = HFILE0_NOFILE;
			    qen_hold->hold_status2 = 0;
			    qen_hold->hold_medium = HMED_IN_MEMORY;
			    if(in_node->qen_type == QE_SORT)
			    {
				status = qen_u32_dosort(in_node, 
							qef_rcb, 
							dsh, 
							qen_status, 
							qen_hold,
							qen_shd, 
					(in_reset) ? FUNC_RESET : NO_FUNC);
				if(status) goto errexit;
			    }
			    in_reset = FALSE;
		       }	/* endif first time through */
		    }	/* endif no more inner tuples to check */
		}
		else if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION)
		{
		    /* No more rows in partitioning group - read from 
		    ** next group. */
		    out_reset = TRUE;
		    goto newouter;
		}
		else  /* return error from reading outer stream */
		{
		    break;
		}
	    }	/* end of error handling for outer stream EOF */


            if(qen_status->node_status == QEN0_INITIAL)
            {
		qen_status->node_status = QEN1_EXECUTED;  /* init done */
		qen_hold->hold_status = HFILE0_NOFILE;  /* default */
		qen_hold->hold_status2 = 0;		/* default */
		qen_hold->hold_medium = HMED_IN_MEMORY;  /* default */
		if(in_node->qen_type  == QE_SORT)
		{

		    status = qen_u32_dosort(in_node, 
					    qef_rcb, 
					    dsh, 
					    qen_status, 
					    qen_hold,
					    qen_shd, 
					(in_reset) ? FUNC_RESET : NO_FUNC);
		    if(status) goto errexit;
		    in_reset = FALSE;
		}

		/* now materialize the first join key */
		status = qen_execute_cx(dsh, node_xaddrs->qex_okmat);
		if (status != E_DB_OK)
		    goto errexit;   /* if ade error, return error */
	    }

	    /* If not the first time */
	    else
	    {
		if ( qen_status->node_u.node_join.node_outer_status == QEN8_OUTER_EOF )
		{
		    new_to_old = NEW_GT_OLD;
		}
		else	/* outer not at EOF */
		{
		    /* compare the old outer key to the new one. */
		    new_to_old = ADE_1EQ2;
		    if ((ade_excb = node_xaddrs->qex_kcompare) != NULL)
		    {
			status = qen_execute_cx(dsh, ade_excb);
			if (status != E_DB_OK)
			    goto errexit;   /* if ade error, return error */
			new_to_old = ade_excb->excb_cmp;
		    }

		    /* Materialize the new outer key if the old and the 
		    ** new outer keys are not equal */
		    if (new_to_old != ADE_1EQ2)
		    {
			status = qen_execute_cx(dsh, node_xaddrs->qex_okmat);
			if (status != E_DB_OK)
			    goto errexit;   /* if ade error, return error */
		    }
		    else if ((node->qen_flags & QEN_CARD_MASK) == QEN_CARD_01L)
		    {
			/* Right outer - note cardinality */
			potential_card_violation = (new_to_old == ADE_1EQ2);
		    }
		}	/* endif outer not at EOF */

		/*
		** If there are inner tuples to rescan, decide whether
		** to thumb through them again or dump them.
		*/


		if ( qen_status->node_access & QEN_RESCAN_MARKED )
		{
		    if ( new_to_old == ADE_1EQ2 )
		    {
		        status = repositionInnerStream( node, dsh );
		        if(status != E_DB_OK) break;   /* to error */
		        continue;
		    }

		    else	/* key has changed */
		    {
		        if ( rjoin )
		        {
		            status = repositionInnerStream( node, dsh );
		            if(status != E_DB_OK) break;   /* to error */
		            qen_status->node_access |= QEN_LOOKING_FOR_RIGHT_JOINS;
		            continue; /* to get a new inner */
		        }
		        else	/* don't have to return right joins */
		        {
		            status = clearHoldFiles( node, dsh );
		            if(status != E_DB_OK) break;   /* to error */
		        }
		    }	/* endif comparison of new and old keys */
		}	/* endif there are inner tuples to rescan */
	    }	/* end first or subsequent times */
	}  /* end if read_outer  */

	/*********************************************************
	**	
	**	LOGIC TO READ FROM THE INNER TUPLE STREAM
	**
	**
	*********************************************************/

	if( qen_status->node_access & QEN_READ_NEXT_INNER )
	{
            qen_status->node_access &= ~QEN_READ_NEXT_INNER;

	    if ( !INNER_STREAM_EXHAUSTED )
	    {
		/*
		** If we're rescanning the hold files and will eventually
		** have to look for right joins, read from the hold file
		** of inner join flags.
		*/
		if ( rjoin &&
		     ( ijFlagsHold->hold_status2 & HFILE_REPOSITIONED )  )
		{
		    if (qen_u40_readInnerJoinFlag( ijFlagsHold, dsh,
	    				ijFlagsShd,
					&innerTupleJoined ) != E_DB_OK)
		    {
			/*
			** If innerJoinFlags is exhausted and we were
			** looking for right joins, then we've found
			** all the right joins for this key.  Dump the
			** hold files.
			*/
		        if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS)
		        {
			    /* Hold file ends, mark this. Continue reading. */
			    ijFlagsHold->hold_buffer_status = HFILE6_BUF_EMPTY;
			    ijFlagsHold->hold_status = HFILE2_AT_EOF;
			    if ( qen_status->node_access &
				 QEN_LOOKING_FOR_RIGHT_JOINS )
			    {
				qen_status->node_access &= 
				    ~( QEN_LOOKING_FOR_RIGHT_JOINS |
				       QEN_READ_NEXT_OUTER );
				qen_status->node_access |= 
				    QEN_READ_NEXT_INNER;
				status = clearHoldFiles( node, dsh );
				if(status != E_DB_OK) break;   /* to error */
				continue;	/* get next inner */
			    }
			}
			else	/* other errors are fatal */
			{
			    break;
			}
		    }	/* endif innerJoinFlags read wasn't OK */
		}	/* endif rjoin and rescanning hold files */

	        /* Read from hold file if it is positioned */
	        if (qen_hold->hold_status == HFILE3_POSITIONED)
	        {
		    if (qen_u4_read_positioned(qen_hold, dsh,
	    			       qen_shd) != E_DB_OK)
		    {
		        if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS)
		        {
			    /* Hold file ends, must read from inner node */
			    qen_hold->hold_buffer_status = HFILE6_BUF_EMPTY;
			    qen_hold->hold_status = HFILE2_AT_EOF;
			    dsh->dsh_error.err_code = 0;
			    qen_status->node_access |= QEN_READ_NEXT_INNER;
			    if (node->qen_flags & QEN_PART_SEPARATE &&
				!(qen_hold->hold_status2 &
						HFILE_LAST_PARTITION))
			    {
				qen_status->node_status_flags |=
							QEN4_IPART_END;
				dsh->dsh_error.err_code = 
						E_QE00A5_END_OF_PARTITION;
			    }
			    continue;	/* to read a new inner */
		        }
			else	/* other, presumably fatal error */
			{
			    break;
			}
		    }   /* end if hold end */

		    if(in_node->qen_type == QE_SORT)  /* if hold from sort */
		    {
		        /* Materialize the inner tuple from sort's row buffer
		           into my row buffer. */
			status = qen_execute_cx(dsh, node_xaddrs->qex_itmat);
			if (status != E_DB_OK)
			    goto errexit;   /* if ade error, return error */
			rematerializeInnerTuple = FALSE;
		    } /* end if hold from sort */

		    qen_hold->hold_buffer_status = HFILE7_FROM_HOLD;
	        }	/* end if positioned */
	        /* if not EOF on stream */
	        else if (qen_status->node_u.node_join.node_inner_status != QEN11_INNER_ENDS)
	        {
		    if(qen_hold->unget_status)   /* if occupied */
                    {
                        /* put unget in row buffer */
                        MEcopy((PTR)qen_hold->unget_buffer, 
			   qen_shd->shd_width,
                           (PTR)qen_shd->shd_row);
                        qen_hold->unget_status = 0;   /* set no unget */
		        qen_hold->hold_buffer_status = HFILE8_FROM_INNER;
                    }
                    else   /* get new from stream */
                    {
		newinner:
		        status = (*in_node->qen_func)(in_node, qef_rcb, dsh,
					(in_reset) ? FUNC_RESET : NO_FUNC);
		        in_reset = FALSE;
		        if (status != E_DB_OK)
		        {
			    if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS ||
				dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION
				&& (node->qen_flags & QEN_PART_SEPARATE))
			    {
			        qen_hold->hold_buffer_status = HFILE6_BUF_EMPTY;

				if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION)
				    qen_status->node_status_flags |= QEN4_IPART_END;
					/* if just EOPartition, flag it */

			        /* mark EOF on stream */
			        qen_status->node_u.node_join.node_inner_status = QEN11_INNER_ENDS;
			        if(qen_hold->hold_status == HFILE2_AT_EOF ||
			           qen_hold->hold_status == HFILE0_NOFILE ||
			           qen_hold->hold_status == HFILE1_EMPTY )
			        {
			           qen_status->node_u.node_join.node_hold_stream = 
			        	    QEN5_HOLD_STREAM_EOF;
			        }
			    }
			    else if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION)
			    {
				/* No more rows in partitioning group - read 
				** from next group. */
				in_reset = TRUE;
				goto newinner;
			    }
			    else
			    {
			        break;	/* other, fatal error */
			    }
		        }
			else	/* inner tuple successfully read */
			{
		            /* Materialize the inner tuple into row buffer. */
			    status = qen_execute_cx(dsh, node_xaddrs->qex_itmat);
			    if (status != E_DB_OK)
				goto errexit;
		            qen_hold->hold_buffer_status = HFILE8_FROM_INNER;
			    rematerializeInnerTuple = FALSE;
			}
                    }  /* end if unget occupied */
	        }   /* end of read from hold/inner */
	    }	/* endif inner stream not exhausted */
	}    /* end if read_inner */

	/***************************************************************
	**
	**	LOOK FOR RIGHT JOINS
	**
	**
	***************************************************************/

	if ( qen_status->node_access & QEN_LOOKING_FOR_RIGHT_JOINS )
	{
	    qen_status->node_access &= ~QEN_READ_NEXT_OUTER;
	    qen_status->node_access |= QEN_READ_NEXT_INNER;

	    if ( innerTupleJoined == FALSE )
	    {
		status = qen_execute_cx(dsh, node_xaddrs->qex_rnull);
		if (status != E_DB_OK)
		    goto errexit;   /* if ade error, return error */
		if (jqual_excb == NULL)
		    break;	/* return right join */
		else
		{
		    status = qen_execute_cx(dsh, jqual_excb);
		    if (status != E_DB_OK)
			goto errexit;   /* if ade error, return error */
		    if (jqual_excb->excb_value == ADE_TRUE)
			break;  /* to return right join */
		}
	    }	/* endif inner tuple joined with some outer */

	    continue;	/* evaluate next inner tuple for right joins */
	}	/* endif looking for right joins */

	/***************************************************************
	**
	**	COMPARE THE INNER AND OUTER JOIN KEYS
	**
	**
	***************************************************************/


	if ( INNER_STREAM_EXHAUSTED ||
	     qen_hold->hold_buffer_status == HFILE6_BUF_EMPTY )
	{
	    join_result = OUTER_LT_INNER;
	}

	else if(qen_status->node_u.node_join.node_outer_status == QEN8_OUTER_EOF)
	{
	    join_result = OUTER_GT_INNER;
	}

	else	/* we have an inner and outer.  join them on the join key. */
	{
	    join_result = ADE_1EQ2;
	    if ((ade_excb = node_xaddrs->qex_joinkey) != NULL)
	    {
		status = qen_execute_cx(dsh, ade_excb);
		if (status != E_DB_OK)
		    goto errexit;   /* if ade error, return error */
		join_result = ade_excb->excb_cmp;
	    }

	    if (join_result == ADE_BOTHNULL)
	    {  
	        join_result = OUTER_GT_INNER;
	    }

	    else if (join_result == ADE_1ISNULL)
	    {
	        join_result = OUTER_GT_INNER;
	    }

	    else if (join_result == ADE_2ISNULL)
	    {
	        join_result = OUTER_LT_INNER;
	    }
	}	/* endif we have inner and outer */

	/***************************************************************
	**
	**	OUTER AND INNER KEYS NOW JOINED.  PERFORM OTHER
	**	QUALIFICATIONS NOW.  EMIT JOINS WHERE APPROPRIATE.
	**
	***************************************************************/


	if (join_result == OUTER_LT_INNER)
	{                           
	    qen_status->node_access |= QEN_READ_NEXT_OUTER;
	    qen_status->node_access &= ~QEN_READ_NEXT_INNER;
	    continue;	/* get next outer */
	}

	if ( join_result == OUTER_GT_INNER )
	{
	    qen_status->node_access &= ~QEN_READ_NEXT_OUTER;
	    qen_status->node_access |= QEN_READ_NEXT_INNER;

	    if ( rjoin )
	    {
		/* rematerialize inner tuple if the ultimate outer tuple
		** just left joined.  rematerialization will reset the
		** special equivalence classes from the inner stream.
		*/

		if ( rematerializeInnerTuple == TRUE )
		{
		    status = qen_execute_cx(dsh, node_xaddrs->qex_itmat);
		    if (status != E_DB_OK)
			goto errexit;   /* if ade error, return error */
		    rematerializeInnerTuple = FALSE;
		}

		/* execute oj_rnull */
		status = qen_execute_cx(dsh, node_xaddrs->qex_rnull);
		if (status != E_DB_OK)
		    goto errexit;   /* if ade error, return error */

		if (jqual_excb == NULL)
		    break;	/* return right join */
		else
		{
		    status = qen_execute_cx(dsh, jqual_excb);
		    if (status != E_DB_OK)
			goto errexit;   /* if ade error, return error */
		    if (jqual_excb->excb_value == ADE_TRUE)
			break;  /* to return right join */
		}
	    }
	    continue;	/* get next inner */
	}    /* endif outer greater than inner */
		
	/* We come to this point when joinkey returns OUTER_EQ_INNER */ 

	if ( join_result != OUTER_EQ_INNER )
	{
	    /* consistency check */
	    dsh->dsh_error.err_code = E_QE0002_INTERNAL_ERROR;
	    status = E_DB_ERROR;
	    goto errexit;           
	}	/* end consistency check */

	if (qen_hold->hold_buffer_status == HFILE8_FROM_INNER)
	{
	    /* append to hold */
            status = qen_u1_append(qen_hold, qen_shd, dsh); 
	    if(status) break;  /* to return error */
	}	

	/* If this is the first inner that joins with the current
	** outer, save the hold file TID so we can reposition it later.
	*/
	if ( !( qen_status->node_access & QEN_RESCAN_MARKED ) )
	{
	    if ( qen_u5_save_position(qen_hold, qen_shd) )
		goto errexit;
	    qen_status->node_access |= QEN_RESCAN_MARKED;
	}
	else if ((node->qen_flags & QEN_CARD_MASK) == QEN_CARD_01R &&
	    (qen_status->node_access & QEN_OUTER_HAS_JOINED) != 0)
	{
	    /* Left outer - note cardinality */
	    potential_card_violation = TRUE;
	}

	qen_status->node_access &= ~QEN_READ_NEXT_OUTER;
	qen_status->node_access |= QEN_READ_NEXT_INNER;

	/* execute OQUAL */
	ade_excb = node_xaddrs->qex_onqual;
	status = qen_execute_cx(dsh, ade_excb);
	if (status != E_DB_OK)
	    goto errexit;   /* if ade error, return error */
	if (ade_excb == NULL || ade_excb->excb_value == ADE_TRUE)
	{
	    /* not OJ, or OQUAL succeeds.  Remember that a join occurred. */
	    qen_status->node_access |= QEN_OUTER_HAS_JOINED;  

	    if ( rjoin )
	    {
		if ( status = qen_u41_storeInnerJoinFlag( ijFlagsHold,
		ijFlagsShd, dsh, innerTupleJoined,
		     ( i4 ) TRUE ) ) goto errexit;   /* error */
	    }

	    /* set the special eqcs to "inner join" state */
	    status = qen_execute_cx(dsh, node_xaddrs->qex_eqmat);
	    if (status != E_DB_OK)
		goto errexit;   /* if ade error, return error */

	    if (jqual_excb != NULL)
	    {
		status = qen_execute_cx(dsh, jqual_excb);
		if (status != E_DB_OK)
		    goto errexit;   /* if ade error, return error */
	    }
	    if( jqual_excb == NULL || jqual_excb->excb_value == ADE_TRUE)
	    {
		/* JQUAL succeeds */
		if(node->node_qen.qen_sjoin.sjn_kuniq)  /* if kuniq */
		{
		    /* make next entry read new outer bit not new inner */
		    qen_status->node_access |= QEN_READ_NEXT_OUTER;
		    qen_status->node_access &= ~QEN_READ_NEXT_INNER;
		}	/* endif key unique */
		if (potential_card_violation)
		{
		    /* We only want to act on seltype violation after
		    ** qualification and that is now. */
		    qen_status->node_status = QEN7_FAILED;
		    dsh->dsh_error.err_code = E_QE004C_NOT_ZEROONE_ROWS;
		    status = E_DB_ERROR;
		    goto errexit;
		}

		break;  /* emit inner join */
	    }
	}
	else	/* OQUAL failed */
	{
	    if ( rjoin )
	    {
	        if ( status = qen_u41_storeInnerJoinFlag( ijFlagsHold,
	            ijFlagsShd, dsh, innerTupleJoined,
		    ( i4 ) FALSE ) )
	        goto errexit;   /* error */
	    }

	}	/* end check of OQUAL status */

	/* OQUAL or JQUAL failed.  Get next inner. */

	continue;

    }	/* end of get loop */

    /********************************************************************
    **
    **	CLEANUP.  MATERIALIZE FUNCTION ATTRIBUTES.  ERROR EXIT WHEN
    **	APPROPRIATE.
    **
    ********************************************************************/

    if (status == E_DB_OK)
    {
	status = qen_execute_cx(dsh, node_xaddrs->qex_fatts);
	if (status != E_DB_OK)
	    goto errexit;   

	/* Increment the count of rows that this node has returned */
	qen_status->node_rcount++;

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

#ifdef xDEBUG
	(VOID) qe2_chk_qp(dsh);
#endif 
    }
    else
    {
	if(in_node->qen_type == QE_SORT)  /* if sort child */
	/* release the memory now if in memory */
	{
	    qen_u31_release_mem(qen_hold, dsh,
	    	  dsh->dsh_shd[in_node->node_qen.qen_sort.sort_shd] );
	}
	else
	if(qen_hold)  /* if hold file */
	{
	    /* release our hold file, if in memory */
	    qen_u31_release_mem(qen_hold, dsh, qen_shd );
	}
    }

errexit:

    if ((dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS ||
	dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION) &&
	(qen_status->node_status_flags & 
			(QEN2_OPART_END | QEN4_IPART_END)))
    {
	/* Restart using next partitioning group. */
	out_reset = in_reset = reset = TRUE;
	qen_status->node_status_flags &=
			~(QEN2_OPART_END | QEN4_IPART_END);
	goto loop_reset;
    }

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

    return (status);	    

}
Beispiel #15
0
DB_STATUS
tpd_s4_abort_to_svpt(
	TPR_CB		*v_tpr_p,
	i4		 i_new_svpt_cnt,
	DB_SP_NAME	*i_svpt_name_p)
{
    DB_STATUS	status = E_DB_OK;
    DB_ERROR	save_err;
    bool	ok = TRUE;	    /* indicate whether all aborts are OK */
    TPD_SS_CB   *sscb_p = (TPD_SS_CB *) v_tpr_p->tpr_session;
    TPD_DX_CB	*dxcb_p = & sscb_p->tss_dx_cb;    /* transaction context */
    TPD_LM_CB	*splm_p = & dxcb_p->tdx_23_sp_ulmcb,
		*lxlm_p = & dxcb_p->tdx_22_lx_ulmcb;
    TPD_LX_CB	*lxcb_p = NULL;
    TPD_SP_CB	*spcb_p = NULL;
    i4		i,
		j;
    bool        trace_svpt_103 = FALSE,
                trace_err_104 = FALSE;
    i4     i4_1,
                i4_2;
    RQR_CB	rqr_cb;		    /* RQF request control block */
    char	svpt_name[sizeof(DB_SP_NAME) + 1],
		qrytxt[100];


    if (ult_check_macro(& sscb_p->tss_3_trace_vector, TSS_TRACE_SVPT_103,
            & i4_1, & i4_2))
    {
        trace_svpt_103 = TRUE;
    }

    if (ult_check_macro(& sscb_p->tss_3_trace_vector, TSS_TRACE_ERROR_104,
            & i4_1, & i4_2))
    {
        trace_err_104 = TRUE;
    }

    rqr_cb.rqr_q_language = v_tpr_p->tpr_lang_type;
    rqr_cb.rqr_session = sscb_p->tss_rqf;

    rqr_cb.rqr_dv_cnt = 0;
    rqr_cb.rqr_dv_p = (DB_DATA_VALUE *) NULL;

    tpd_u0_trimtail(i_svpt_name_p, sizeof(DB_SP_NAME), svpt_name);
    if (v_tpr_p->tpr_lang_type == DB_QUEL)
	STprintf(qrytxt, "%s %s;", IITP_11_abort_to_p, svpt_name);	
    else
	STprintf(qrytxt, "%s %s;", IITP_12_rollback_to_p, svpt_name);	
    rqr_cb.rqr_msg.dd_p1_len = (i4) STlength(qrytxt);
    rqr_cb.rqr_msg.dd_p2_pkt_p = qrytxt;
    rqr_cb.rqr_msg.dd_p3_nxt_p = NULL;

    /* loop through each site to abort to this savepoint if known to the site */

    lxcb_p = (TPD_LX_CB *) lxlm_p->tlm_3_frst_ptr;
    i = 0;
    while (lxcb_p != (TPD_LX_CB *) NULL && status == E_DB_OK)
    {
	if (i_new_svpt_cnt <= lxcb_p->tlx_sp_cnt)   /* LDB has knowledge of this
						    ** savepoint */
	{
	    /* set up to inform of rollback to this savepoint */

	    rqr_cb.rqr_1_site = & lxcb_p->tlx_site;

	    /* skip CDB if DDL_CONCURRENCY is ON */

	    if (! (sscb_p->tss_ddl_cc && rqr_cb.rqr_1_site->dd_l1_ingres_b))
	    {
		rqr_cb.rqr_dv_cnt = 0;
		rqr_cb.rqr_dv_p = (DB_DATA_VALUE *) NULL;
		rqr_cb.rqr_timeout = 0;

		if (trace_svpt_103)
		    tpd_p5_prt_tpfqry(v_tpr_p, qrytxt, & lxcb_p->tlx_site,
			TPD_0TO_FE);

		status = tpd_u4_rqf_call(RQR_QUERY, & rqr_cb, v_tpr_p);
		if (status)
		{
		    if (trace_err_104)
			tpd_p5_prt_tpfqry(v_tpr_p, qrytxt, 
			    & lxcb_p->tlx_site, TPD_0TO_FE);
		    STRUCT_ASSIGN_MACRO(v_tpr_p->tpr_error, save_err);
		    ok = FALSE;
		}
		lxcb_p->tlx_20_flags |= LX_01FLAG_REG;  /* Register.. */
	    }
	    lxcb_p->tlx_sp_cnt = i_new_svpt_cnt; /* these are all savepoints 
					    ** the LDB has knowledge of */
	}
	lxcb_p = lxcb_p->tlx_22_next_p;
	++i;				    /* debugging aid */
    }
    /* update to reflect fewer outstanding session savepoints if necessary */

    if (i_new_svpt_cnt < splm_p->tlm_2_cnt)
    {
	spcb_p = (TPD_SP_CB *) splm_p->tlm_3_frst_ptr;
	for (i = 1; (spcb_p != (TPD_SP_CB *) NULL) && (i < i_new_svpt_cnt); ++i)
	{
	    if (spcb_p != (TPD_SP_CB *) NULL)
		spcb_p = spcb_p->tsp_4_next_p;
	}
	if (i != i_new_svpt_cnt)
	    ok = FALSE;
	else
	{
	    /* update to reflect */

	    spcb_p->tsp_4_next_p = (TPD_SP_CB *) NULL;
	    splm_p->tlm_4_last_ptr = (PTR) spcb_p;
	    splm_p->tlm_2_cnt = i_new_svpt_cnt;
	}
    }
    if (ok)
	return(E_DB_OK);
    else
    {
	STRUCT_ASSIGN_MACRO(save_err, v_tpr_p->tpr_error);
	return(E_DB_ERROR);
    }    
}
Beispiel #16
0
/*{
** Name: psq_parseqry	- Parse a query and return a data structure
**
**  INTERNAL PSF call format: status = psq_parseqry(&psq_cb, &sess_cb);
**
**  EXTERNAL call format:    status = psq_call(PSQ_PARSEQRY, &psq_cb, &sess_cb);
**
** Description:
**	This function will parse a query in QSF memory.  It will return a
**	data structure (such as a query tree), and a code telling what kind of
**	query was just parsed (e.g. a copy statement).  This code will be
**	called the "query mode".  For qrymod definitions, it will store a
**	modified version of the query text in QSF, for later insertion in the
**	iiqrytext system relation.
**
**	This function will check the syntax of each statement, and will perform
**	some semantic validations.  The syntax checking will be rather simple:
**	each statement will either be right or wrong, and a syntax error will
**	cause the whole go block to be aborted.  Semantic checks will be more
**	complicated; some of them will cause warnings (which will allow the
**	statement to continue), and some will cause errors (causing the
**	statement to be aborted).  It should be noted that the semantic checks
**	will not be the same in the Jupiter version as in previous versions;
**	in the Jupiter version, for instance, the parser won't check for whether
**	the statement is valid inside a multi-query transaction.
**
**	Sometimes it will be found that the definition of a view, permit, or
**	integrity is out of date.  When this happens, this function will return
**	an error status saying so, and an id for finding the query text in the
**	iiqrytext relation, so that the definition can be re-parsed and
**	re-stored.  Accordingly, this function has an option by which one can
**	tell it to get the query text out of the iiqrytext relation instead of
**	QSF.
**
**	When a statement is parsed that creates a new cursor, the parser will
**	assign a cursor id to the cursor, create a cursor control block
**	containing information about the cursor, and return the cursor id inside
**	with the query tree representing the cursor.  This cursor id will be
**	used throughout the session to uniquely identify the cursor.  When a
**	"close cursor" statement is parsed, the parser will deallocate the
**	control block associated with the cursor.
**
**	The parser will automatically apply view, permit, and integrity
**	processing to any data manipulation query it parses.  This will not
**	require a separate call to the parser.
**
**	Multi-statement go blocks are no longer allowed, as they used to be in
**	previous versions.  This parser can handle only one statement at a time.
**
** Inputs:
**      psq_cb
**          .psq_qid                    A unique identifier for getting the
**					query text from QSF.
**	    .psq_iiqrytext		TRUE means to get the query text from
**					the iiqrytext relation, not QSF.
**	    .psq_txtid			Query text id key into iiqrytext
**					relation; used only if above is true.
**	sess_cb				Pointer to the session control block
**
** Outputs:
**      psq_cb
**	    .psq_qlang			The language of the query text.
**          .psq_mode                   The query mode (a code telling what
**					kind of query was just parsed).
**	    .psq_result			QSF id for the data structure produced
**					(query tree, or control block stored as
**					QEP).
**	    .psq_txtid			Query text id key into iiqrytext
**					relation; filled in if some qrymod
**					object needs redefining.
**	    .psq_mnyfmt			Set on a "set money_format" or
**					"set money_prec" statement
**	    .psq_dtefmt			Set on a "set date_format" statement
**	    .psq_decimal		Set on a "set decimal" statement
**          .psq_error                  Standard error block
**		E_PS0000_OK		    Success
**		E_PS0001_USER_ERROR	    Mistake by user
**		E_PS0002_INTERNAL_ERROR	    Internal inconsistency inside PSF
**		E_PS0B01_OUTDATED_VIEW	    View out of date; must re-define
**		E_PS0B02_OUTDATED_PERMIT    Permit out of date; must re-define
**		E_PS0B03_OUTDATED_INTEG	    Integrity out of date; must re-def.
**		E_PS0B04_CANT_GET_TEXT	    Can't get query text
**	    .psq_txtout			QSF id for the create procedure stmt to
**					be stored in the system catalog.
**
**	Returns:
**	    E_DB_OK			Function completed normally.
**	    E_DB_WARN			Function completed with warning(s)
**	    E_DB_ERROR			Function failed; non-catastrophic error
**	    E_DB_FATAL			Function failed; catastrophic error
**	Exceptions:
**	    none
**
** Side Effects:
**	    Stores query tree or control block in QSF.
**	    Can open a cursor.
**
** History:
**	01-oct-85 (jeff)
**          written
**	19-sep-86 (daved)
**	    end of qry should point to last char. This char should be a space.
**	    this makes the scanner's job easier
**	27-jan-87 (daved)
**	    add the printqry set command.
**	02-oct-87 (stec)
**	    Removed pss_journaling flag initialization;
**	    must be initialized in psqbgnses.c
**	19-jan-88 (stec)
**	    Changed initialization od pst_resloc.
**	25-may-88 (stec)
**	    Made changes in connection with DB procedures.
**	    QSF object of QP type has to be destroyed if
**	    translate_or_define worked for CREATE PROCEDURE. 
**	23-aug-88 (stec)
**	    Initialize qso_handle in QSO_OBIDs in psq_cb.
**	21-apr-89 (neil)
**	    Extracted some initialization (psq_cbinit) from psq_parseqry to
**	    allow it to be called from other routines as well.
**	11-dec-89 (ralph)
**	    Change interface to QSO for dbprocs
**	12-sep-90 (teresa)
**	    fix faulty pss_retry logic.
**	15-jun-92 (barbara)
**	    Sybil merge.  Pass in sess control block to pst_clrrng.
**	23-nov-92 (barbara)
**	    For Star, accept range statement as the one and only allowable
**	    QUEL statement.  This is to support old FE's which use the range
**	    statement as a quick way to ascertain table existence.  FEs of
**	    >= 6.5 vintage use a table_resolve() function, so at some point
**	    we can remove the QUEL range table statement support for Star.
**      24-nov-92 (ralph)
**          CREATE SCHEMA:
**          Initialize pss_prvgoval
**	22-dec-92 (rblumer)
**	    clean up after pss_tchain2 just like pss_tchain.
**	25-may-93 (rog)
**	    Move clean-up/exit code into psq_cbreturn() and then call it.
**	11-oct-93 (swm)
**	    Bug #56448
**	    Declared trbuf for psf_display() to pass to TRformat.
**	    TRformat removes `\n' chars, so to ensure that psf_scctrace()
**	    outputs a logical line (which it is supposed to do), we allocate
**	    a buffer with one extra char for NL and will hide it from TRformat
**	    by specifying length of 1 byte less. The NL char will be inserted
**	    at the end of the message by psf_scctrace().
**	16-mar-94 (andre)
**	    if performing an internal PSF retry and trace point ps129 (same as 
*8	    SET PRINTQRY) is set, instead of redisplaying the query we will 
*8	    tell the user that we are retrying the last query.
**	28-feb-2005 (wanfr01)
**	    Bug 64899, INGSRV87
**	    Add stack overflow handler for TRU64.
**	17-mar-06 (dougi)
**	    Init pss_hintcount to 0 for optimizer hints project.
**	23-june-06 (dougi)
**	    Init pss_stmtno to 1 for procedure debugging.
**	05-sep-06 (toumi01)
**	    Init pss_stmtno to 0 (to match new "help procedure" numbering)
**	    lest we point, PC register like, to the _following_ statement.
**	15-Sep-2008 (kibro01) b120571
**	    Use same session ID as available in iimonitor
**	16-Sep-2008 (kibro01) b120571
**	    Remove compilation error from cast of sessid
**	16-Feb-2009 (kibro01) b121674
**	    Add version to SESSION BEGINS message in sc930 and give out
**	    data type of parameters.
**	10-Jul-2009 (kibro01) b122299
**	    Increase the version number due to dates being printed out now.
**	15-Jul-2009 (kibro01) b122172
**	    Change QUERY or QUEL to REQUERY or REQUEL when a DB procedure is
**	    reparsed due to being invalidated.
**	23-Jul-2009 (kibro01) b122172
**	    Separate the print_qry_buffer logic to avoid stack size problems.
**	3-Aug-2009 (kibro01) b122393
**	    Use print_qry_buffer_ptr to avoid inlining.
**	4-Aug-2009 (kibro01) b122172
**	    Allow REQUERY/REQUEL through even if the RECREATE flag is set so
**	    we get the useful debug output.
**     28-Oct-2009 (maspa05) b122725
**          ult_print_tracefile now uses integer constants instead of string
**          for type parameter - SC930_LTYPE_PARM instead of "PARM" and so on
**          Also moved function definitions for SC930 tracing to ulf.h
**          The functions involved were - ult_always_trace, ult_open_tracefile
**          ult_print_tracefile and ult_close_tracefile
*/
DB_STATUS
psq_parseqry(
	register PSQ_CB     *psq_cb,
	register PSS_SESBLK *sess_cb)
{
    DB_STATUS		    status;
    DB_STATUS		    ret_val;
    QSF_RCB		    qsf_rb;
    i4		    err_code;
    PSQ_QDESC		    *qdesc;
    i4		    val1 = 0;
    i4		    val2 = 0;
    i4			    i;
    char		    trbuf[PSF_MAX_TEXT + 1]; /* last char for `\n' */

    if ((status = psq_cbinit(psq_cb, sess_cb)) != E_DB_OK)
	return (status);

    /*
    ** The following is particular to queries that must be parsed.
    ** Get query text from QSF and put it in session control block
    ** Initialize the qbuf, nextchar, prevtok, and bgnstmt pointers
    */

    qsf_rb.qsf_type = QSFRB_CB;
    qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID;
    qsf_rb.qsf_length = sizeof(qsf_rb);
    qsf_rb.qsf_owner = (PTR)DB_PSF_ID;
    qsf_rb.qsf_sid = sess_cb->pss_sessid;

    qsf_rb.qsf_obj_id.qso_handle = psq_cb->psq_qid;
    status = qsf_call(QSO_INFO, &qsf_rb);
    if (DB_FAILURE_MACRO(status))
    {
	(VOID) psf_error(E_PS0B04_CANT_GET_TEXT, 0L, PSF_CALLERR, &err_code,
	    &psq_cb->psq_error, 0);
	return (E_DB_ERROR);
    }

    qdesc		    = (PSQ_QDESC*) qsf_rb.qsf_root;

    /* print the qry buffer as long as this isn't a retry 
    ** - although allow through the RECREATE case since it's useful
    ** for debugging to log reparsing an object */
    if ((ult_always_trace() & SC930_TRACE) && 
	( ((sess_cb->pss_retry & PSS_REFRESH_CACHE)==0) ||
	  (sess_cb->pss_dbp_flags & PSS_RECREATE) != 0 ) )
    {
	(*print_qry_buffer_ptr)(psq_cb, qdesc, sess_cb);
    }
    if (ult_check_macro(&sess_cb->pss_trace,
				PSS_PRINT_QRY_TRACE, &val1, &val2))
    {
	if (psf_in_retry(sess_cb, psq_cb))
	{
	    psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1,
		    "\n...retrying last query...\n");
	}
	else
	{
	    psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1,
		    "\nQUERY BUFFER:\n");
	    psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1,
		    "%.#s\n", qdesc->psq_qrysize, qdesc->psq_qrytext);
	    psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1,
		    "\nQUERY PARAMETERS:\n");
	    for (i = 0; i < qdesc->psq_dnum; i++)
	    {
	        psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1,
		  "Parameter : %d\n", i);
	        adu_2prvalue(psf_relay, qdesc->psq_qrydata[i]);
	        psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "\n");
	    }
	}
    }

    sess_cb->pss_bgnstmt    = (u_char*) qdesc->psq_qrytext;
    sess_cb->pss_prvgoval   = (u_char*) NULL;
    sess_cb->pss_prvtok	    = (u_char*) qdesc->psq_qrytext;
    sess_cb->pss_qbuf	    = (u_char*) qdesc->psq_qrytext;
    sess_cb->pss_nxtchar    = (u_char*) qdesc->psq_qrytext;
    sess_cb->pss_endbuf	    = sess_cb->pss_qbuf + qdesc->psq_qrysize - 1;
    sess_cb->pss_dmax	    = qdesc->psq_dnum;
    sess_cb->pss_qrydata    = qdesc->psq_qrydata;
    *sess_cb->pss_endbuf    = ' ';
    sess_cb->pss_lineno	    = 1;	/* Start out at line one */
    sess_cb->pss_stmtno	    = 0;	/* and statement at zero */
    sess_cb->pss_dval	    = 0;
    sess_cb->pss_hintcount  = 0;

    psl_yinit(sess_cb);
    if (psq_cb->psq_qlang == DB_QUEL)
    {
	if (sess_cb->pss_distrib & DB_3_DDB_SESS)
	{
	    char	*c;
	    char	*r = "range";

	    /* skip leading white space chars, if any */
	    for (c = qdesc->psq_qrytext;
		 c <= (char *) sess_cb->pss_endbuf && CMwhite(c);
		 CMnext(c)
		)
	    ;

	    /* compare the first word with "range" */
	    for (;
		 *r != EOS && c <= (char *) sess_cb->pss_endbuf &&
		 !CMcmpnocase(c,r);
		 CMnext(c), CMnext(r)
		)	
	    ;

	    /*
	    ** we will go on to parse this statement iff
	    ** 1) first non-white chars are "range"     AND
	    ** 2) 'e' is followed by a white space
	    */
	    if (*r != EOS || c >= (char *) sess_cb->pss_endbuf || !CMwhite(c))
	    {
		(VOID) psf_error(5212L, 0L, PSF_USERERR, &err_code,
				    &psq_cb->psq_error,0);
		return(E_DB_ERROR);
	    }
	}
	sess_cb->pss_parser = pslparse;
    }
    else
    {
	sess_cb->pss_parser = pslsparse;
    }

    IIEXtry
    {
         status = (*sess_cb->pss_parser)(sess_cb, psq_cb);
    }
    IIEXcatch(pthread_stackovf_e)
    {
	(VOID) psf_error(5212L, 0L, PSF_USERERR, &err_code,
			    &psq_cb->psq_error,0);
    }
    IIEXendtry
    
    ret_val = psq_cbreturn(psq_cb, sess_cb, status);

    return (ret_val);
}
Beispiel #17
0
/*{
** Name: psy_dpermit	- Define a permit.
**
**  INTERNAL PSF call format: status = psy_dpermit(&psy_cb, sess_cb);
**
**  EXTERNAL call format:     status = psy_call(PSY_DPERMIT, &psy_cb, sess_cb);
**
** Description:
**	Given all of the parameters necessary to CREATE/DEFINE a permit on a
**	table or view, this function will store the permission in the system
**	catalogs.  This will include storing the query tree in the tree table,
**	storing the text of the query in the iiqrytext table (really done by
**	QEF), storing a row in the protect table, and issuing an "alter table"
**	operation to DMF to indicate that there are permissions on the given
**	table.
**
** Inputs:
**      psy_cb
**	    .psy_qrytext		Id of query text as stored in QSF.
**	    .psy_cols[]			Array of columns on which to grant
**					permission
**	    .psy_numcols		Number of columns listed above; 0 means
**					give permission on all columns
**          .psy_intree                 QSF id of query tree representing the
**					where clause in the permit
**          .psy_opctl                  Bit map of defined   operations
**          .psy_opmap                  Bit map of permitted operations
**          .psy_user                   Name of user who will get permission
**          .psy_terminal               Terminal at which permission is given
**					(blank if none specified)
**          .psy_timbgn                 Time of day at which the permission
**					begins (minutes since 00:00)
**          .psy_timend                 Time of day at which the permission ends
**					(minutes since 00:00)
**          .psy_daybgn                 Day of week at which the permission
**					begins (0 = Sunday)
**          .psy_dayend                 Day of week at which the permission ends
**					(0 = Sunday)
**	    .psy_grant
**		PSY_CPERM		CREATE/DEFINE PERMIT
**	    .psy_tblq			head of table queue
**	    .psy_colq			head of column queue
**	    .psy_usrq			head of user queue
**	    .psy_qlen			length of first iiqrytext
**	    .psy_flags			useful info
**		PSY_EXCLUDE_COLUMNS	user specified a list of columns to
**					which privilege should not apply
**	sess_cb				Pointer to session control block
**					(Can be NULL)
**
** Outputs:
**      psy_cb
**          .psy_txtid                  Id of query text as stored in the
**					iiqrytext system relation.
**	    .psy_error			Filled in if error happens
**	Returns:
**	    E_DB_OK			Function completed normally.
**	    E_DB_WARN			Function completed with warning(s);
**	    E_DB_ERROR			Function failed; non-catastrophic error
**	    E_DB_FATAL			Function failed; catastrophic error
**	Exceptions:
**	    none
**
** Side Effects:
**	    Stores text of query in iiqrytext relation, query tree in tree
**	    relation, row in protect relation identifying the permit.  Does
**	    an alter table DMF operation to indicate that there are permissions
**	    on the table.
**
** History:
**	02-oct-85 (jeff)
**          written
**      03-sep-86 (seputis)
**          changed some psy_cb. to psy_cb->
**          added .db_att_id reference
**          changed rdr_cb. rdr_cb->
**	02-dec-86 (daved)
**	    bug fixing. check for permit on tables owned by user and not
**	    view.
**	29-apr-87 (stec)
**	    Implemented changes for GRANT statement.
**	10-may-88 (stec)
**	    Make changes for db procs.
**	03-oct-88 (andre)
**	    Modified call to pst_rgent to pass 0 as a query mode since it is
**	    clearly not PSQ_DESTROY
**	06-feb-89 (ralph)
**	    Added support for 300 attributes:
**		Use DB_COL_BITS in place of DB_MAX_COLS
**		Loop over domset array using DB_COL_WORDS
**	06-mar-89 (ralph)
**	    GRANT Enhancements, Phase 1:
**	    Initialize new DB_PROTECTION fields, dbp_seq and dbp_gtype
**	03-apr-89 (ralph)
**	    GRANT Enhancements, Phase 2:
**	    Use DBGR_USER when initializing dbp_gtype
**	08-may-89 (ralph)
**	    Initialize reserved field to blanks (was \0)
**	04-jun-89 (ralph)
**	    Initialize dbp_fill1 to zero
**	    Fix unix portability problems
**	02-nov-89 (neil)
**	    Alerters: Allowed privileges for events.
**	1-mar-90 (andre)
**	    If processing a GRANT on tables, check if 
**	    ALL-TO-ALL or RETRIEVE-TO-ALL has already been granted, and if so,
**	    mark psy_mask appropriately.
**	    If user tried to CREATE ALL/RETRIEVE-TO-ALL, and one already exists,
**	    skip to the exit.
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
**	08-aug-90 (ralph)
**	    Initialize new fields in iiprotect tuple
**	14-dec-90 (ralph)
**	    Disallow use of GRANT by non-DBA if xORANGE
**	11-jan-90 (ralph)
**	    Allow user "$ingres" to use GRANT if xORANGE.
**	    This was done for CREATEDB (UPGRADEFE).
**	20-feb-91 (andre)
**	    For CREATE/DEFINE PERMIT, grantee type was stored in
**	    psy_cb->psy_gtype.
**	24-jun-91 (andre)
**	    IIPROTECT tuples for table permits will contain exactly one
**	    privilege.  IIQRYTEXT template built for table-wide privileges
**	    contains a placeholder for a privilege name which will be filled in
**	    with each of the table-wide privileges being granted, one at a time.
**	    PSY_CB.psy_opmap will be set to correspond with privilege name
**	    stored in the IIQRYTEXT permit.
**	16-jul-91 (andre)
**	    responsibility for splitting permit tuples will passed on to
**	    qeu_cprot().  If a permit specified only one privilege, we will
**	    substitute the appropriate privilege name here and will not ask
**	    qeu_cprot() to split tuples.
**	06-aug-91 (andre)
**	    before proceeding to CREATE a permit on a view owned by the current
**	    user, we will call psy_tbl_grant_check() to ensure that this user
**	    may create a permit on his view.  If the object is not owned by the
**	    current user, we will not try to verify that the user may
**	    CREATE/DEFINE a permit since (until the relevant FE changes are
**	    made) we intend to continue allowing any user with CATUPD to
**	    CREATE/DEFINE permits on catalogs and the dba will be allowed to
**	    CREATE/DEFINE permits on extended catalogs
**	11-nov-91 (rblumer)
**	  merged from 6.4:  26-feb-91 (andre)
**	    PST_QTREE was changed to store the range table as an array of
**	    pointers to PST_RNGENTRY structure.
**	14-feb-92 (andre)
**	    we will no longer have to fill in privilege name for permits
**	    specifying one privilege - it will be handled in respective
**	    grammars.
**	15-jun-92 (barbara)
**	    For Sybil, change interface to pst_rgent(), Star returns from
**	    psy_dpermit before permits get stored.
**	07-jul-92 (andre)
**	    DB_PROTECTION tuple will contain an indicator of how the permit was
**	    created, i.e. whether it was created using SQL or QUEL and if the
**	    former, then whether it was created using GRANT statement.  Having
**	    this information will facilitate merging similar and identical
**	    permit tuples.
**	14-jul-92 (andre)
**	    semantics of GRANT ALL [PRIVILEGES] is different from that of
**	    CREATE PERMIT ALL in that the former (as dictated by SQL92) means
**	    "grant all privileges which the current auth id posesses WGO"
**	    whereas the latter (as is presently interpreted) means "grant all
**	    privileges that can be defined on the object" which in case of
**	    tables and views means SELECT, INSERT, DELETE, UPDATE.
**	    psy_tbl_grant_check() (function responsible for determining whether
**	    a user may grant specified privilege on a specified table or view)
**	    will have to be notified whether we are processing GRANT ALL.  Its
**	    behaviour will change as follows:
**	      - if processing GRANT ALL and psy_tbl_grant_check() determines
**	        that the user does not possess some (but not all) of the
**		privileges passed to it by the caller it will not treat it as an
**		error, but will instead inform the caller of privileges that the
**		user does not posess,
**	      - if processing GRANT ALL and psy_tbl_grant_check() determines
**	        that the user does not possess any of the privileges passed to
**		it by the caller it will treat it as an error
**	      - if processing a statement other than GRANT ALL and
**	        psy_tbl_grant_check() determines that the user does not possess
**		some of the privileges passed to it by the caller it will treat
**		it as an error
**	16-jul-92 (andre)
**	    if a permit being created depends on some privileges, build a
**	    structure describing these privileges and store its address in
**	    rdf_cb->rdr_indep.
**	18-jul-92 (andre)
**	    we will no longer be telling QEF to turn off DMT_ALL_PROT or
**	    DMT_RETRIEVE_PRO when a user creates ALL/RETRIEVE TO ALL permit.
**	    QEF will figure out on its own whether PUBLIC now has RETRIEVE or
**	    ALL on a table/view
**	20-jul-92 (andre)
**	    if user specified a list of columns to which privilege(s) should
**	    not apply, set dbp_domset correctly
**	03-aug-92 (barbara)
**	    Invalidate base table infoblk from RDF cache for CREATE PERMIT
**	    and CREATE SEC_ALARM.
**	16-sep-92 (andre)
**	    privilege maps are build using bitwise ops, so care should be
**	    exercised when accessing it using BT*() functions
**	17-jun-93 (andre)
**	    changed interface of psy_secaudit() to accept PSS_SESBLK
**	5-jul-93 (robf)
**	    changed interface of  psy_secaudit() to accept security label
**	 7-jan-94 (swm)
**	    Bug #58635
**	    Added PTR cast for qsf_owner which has changed type to PTR.
**	06-mar-96 (nanpr01)
**	    Move the QSF request block initialization up. because if  
**	    pst_rgnent returns a failure status code, subsequent QSF
**	    calls get bad control block error.
*/
DB_STATUS
psy_dpermit(
	PSY_CB             *psy_cb,
	PSS_SESBLK	   *sess_cb)
{
    RDF_CB              rdf_cb;
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    QSF_RCB		qsf_rb;
    DB_STATUS		status;
    DB_STATUS		stat;
    DB_PROTECTION	ptuple;
    register DB_PROTECTION *protup = &ptuple;
    i4			*domset	= ptuple.dbp_domset;
    register i4	i, j;
    i4		err_code;
    PSS_RNGTAB		*rngvar;
    PSS_USRRANGE	*rngtab;
    PST_PROCEDURE	*pnode;
    PST_QTREE		*qtree;
    DB_ERROR		*err_blk = &psy_cb->psy_error;
    i4			textlen;
    i4			tree_lock   = 0;
    i4			text_lock   = 0;
    DB_TAB_ID		tabids[PST_NUMVARS];
    PSQ_INDEP_OBJECTS   indep_objs;
    PSQ_OBJPRIV         obj_priv;       /* space for independent DELETE */
    PSQ_COLPRIV         col_privs[2];   /*
                                        ** space for independent INSERT and
					** UPDATE
					*/
    PST_VRMAP		varmap;
    PSY_TBL		*psy_tbl;
    DB_TIME_ID		timeid;
    DB_NAME             *objname;

    /*
    ** For CREATE/DEFINE PERMIT execute code below.
    */

    /* initialize the QSF control block */
    qsf_rb.qsf_type	= QSFRB_CB;
    qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID;
    qsf_rb.qsf_length	= sizeof(qsf_rb);
    qsf_rb.qsf_owner	= (PTR)DB_PSF_ID;
    qsf_rb.qsf_sid	= sess_cb->pss_sessid;

    rngtab = &sess_cb->pss_auxrng;

    /* table info is stored in the only entry in the table queue */
    psy_tbl = (PSY_TBL *) psy_cb->psy_tblq.q_next;

    status = pst_rgent(sess_cb, rngtab, -1, "", PST_SHWID,
	(DB_TAB_NAME *) NULL, (DB_TAB_OWN *) NULL,
	&psy_tbl->psy_tabid, TRUE, &rngvar, (i4) 0, err_blk);
	
    if (DB_FAILURE_MACRO(status))
	goto exit;

    /* In STAR, we do not actually store permits */
    if (sess_cb->pss_distrib & DB_3_DDB_SESS)
    {
	qsf_rb.qsf_lk_state = QSO_EXLOCK;
	goto exit;
    }

    /* Fill in the RDF request block */
    pst_rdfcb_init(&rdf_cb, sess_cb);

    /* The table which is receiving the permit */
    STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabid, rdf_rb->rdr_tabid);
    
    /* Tell RDF we're doing a permit definition */
    rdf_rb->rdr_update_op   = RDR_APPEND;

    rdf_rb->rdr_types_mask = RDR_PROTECT;
    rdf_rb->rdr_qrytuple = (PTR) protup;

    /* initialize independent object structure */
    indep_objs.psq_objs	= (PSQ_OBJ *) NULL;
    indep_objs.psq_objprivs = (PSQ_OBJPRIV *) NULL;
    indep_objs.psq_colprivs = (PSQ_COLPRIV *) NULL;
    indep_objs.psq_grantee  = &sess_cb->pss_user;

    rdf_rb->rdr_indep	    = (PTR) &indep_objs;

    /*
    ** populate the IIPROTECT tuple
    */

    /* Zero out the template */
    (VOID)MEfill(sizeof(ptuple), (u_char) 0, (PTR) protup);

    /* store grantee type */
    protup->dbp_gtype = psy_cb->psy_gtype;

    /* Init reserved block */
    (VOID)MEfill(sizeof(protup->dbp_reserve),
	(u_char) ' ', (PTR) protup->dbp_reserve);

    /* Init obj name */
    STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabnm, protup->dbp_obname);

    /*@FIX_ME@ Where does this come from? */
    protup->dbp_obstat = ' ';

    /* store the object type indicator */
    if (psy_tbl->psy_mask & PSY_OBJ_IS_TABLE)
    {
	protup->dbp_obtype = DBOB_TABLE;
    }
    else if (psy_tbl->psy_mask & PSY_OBJ_IS_VIEW)
    {
	protup->dbp_obtype = DBOB_VIEW;
    }
    else
    {
	protup->dbp_obtype = DBOB_INDEX;
    }

    STRUCT_ASSIGN_MACRO(psy_tbl->psy_owner, protup->dbp_obown);

    STRUCT_ASSIGN_MACRO(sess_cb->pss_user, protup->dbp_grantor);

    TMnow((SYSTIME *)&timeid);
    protup->dbp_timestamp.db_tim_high_time = timeid.db_tim_high_time;
    protup->dbp_timestamp.db_tim_low_time  = timeid.db_tim_low_time;

    /* The table on which we're giving permission */
    STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabid, protup->dbp_tabid);

    /* Beginning and ending times of day */
    protup->dbp_pdbgn = psy_cb->psy_timbgn;
    protup->dbp_pdend = psy_cb->psy_timend;

    /* Beginning and ending days of week */
    protup->dbp_pwbgn = psy_cb->psy_daybgn;
    protup->dbp_pwend = psy_cb->psy_dayend;

    if (psy_cb->psy_numcols != 0 && ~psy_cb->psy_flags & PSY_EXCLUDE_COLUMNS)
    {
	/* user specified a list of columns to which privilege(s) will apply */
	
	/* Bit map of permitted columns */
	psy_fill_attmap(domset, ((i4) 0));

	for (i = 0; i < psy_cb->psy_numcols; i++)
	{
	    BTset((i4)psy_cb->psy_cols[i].db_att_id, (char *) domset);
	}	
    }
    else
    {
	/*
	** user specified table-wide privilege(s) or a list of columns L s.t.
	** privilege(s) will apply to the entire table except for columns in L
	*/

	psy_fill_attmap(domset, ~((i4) 0));

	if (psy_cb->psy_flags & PSY_EXCLUDE_COLUMNS)
	{
	    /*
	    ** exclude specified columns from the list of columns to which
	    ** privilege(s) will apply
	    */
	    for (i = 0; i < psy_cb->psy_numcols; i++)
	    {
		BTclear((i4) psy_cb->psy_cols[i].db_att_id, (char *) domset);
	    }
	}
    }

    if (rngvar->pss_tabdesc->tbl_status_mask & DMT_VIEW)
    {
	/*
	** if view is owned by the current user, psy_tbl_grant_check() will
	** determine if the permit can, indeed, be created;  as long as we are
	** preserving the kludge that allows users with CATUPD create permits on
	** catalogs and DBAs to create permits on extended catalogs, we shall
	** not call psy_tbl_grant_check() on view not owned by the current user,
	** since it is likely to result in psy_tbl_grant_check() complaining
	** about inadequate permissions
	*/
	if (!MEcmp((PTR) &rngvar->pss_ownname, (PTR) &sess_cb->pss_user,
	    sizeof(sess_cb->pss_user)))
	{
	    i4			    tbl_wide_privs;
	    PSY_COL_PRIVS	    col_specific_privs, *csp,
				    indep_col_specific_privs;
	    DB_TAB_ID		    indep_id;
	    i4			    indep_tbl_wide_privs;
	    bool		    insuf_privs, quel_view;
	    i4		    val1, val2;

	    /*
	    ** build maps of table-wide and column-specific privileges for
	    ** psy_tbl_grant_check()
	    ** if a column list was specified with CREATE PERMIT and
	    ** privileges specified in the statement include a set of
	    ** privileges S s.t. for all P in S, P can only be specified as
	    ** table-wide with GRANT statement (currently this includes
	    ** SELECT, INSERT, DELETE), we will make 
	    ** psy_tbl_grant_check() think that privileges in S are
	    ** table-wide.
	    ** This will work correctly since if the view was defined over
	    ** some objects owned by other user(s), for every P in S we
	    ** would need table-wide privilege WGO on the underlying object.
	    **
	    ** For the purposes of providing more descriptive output for
	    ** trace point ps131, if column-list was specified, we will pass
	    ** the map of attributes even if column-specific UPDATE was not
	    ** specified
	    */

	    if (psy_cb->psy_numcols != 0 &&
		(psy_cb->psy_opmap & DB_REPLACE ||
		 ult_check_macro(&sess_cb->pss_trace, 3, &val1, &val2)
		)
	       )
	    {
		i4	    *ip;

		csp = &col_specific_privs;

		/*
		** column-specific UPDATE privilege will not be translated into
		** a table-wide privilege since GRANT allows for specification
		** of column-specific UPDATE privilege
		*/
		csp->psy_col_privs = psy_cb->psy_opmap & DB_REPLACE;
		tbl_wide_privs = psy_cb->psy_opmap & ~DB_REPLACE;

		/*
		** if creating a permit on a set of columns and UPDATE is not
		** one of the privileges named in the statement, store the
		** attribute map in the first element of the attribute map list
		*/
		ip = (csp->psy_col_privs)
		    ? csp->psy_attmap[PSY_UPDATE_ATTRMAP].map
		    : csp->psy_attmap->map;

		/* copy the attribute map */
		for (i = 0; i < DB_COL_WORDS; i++, ip++)
		{
		    *ip = domset[i];
		}
	    }
	    else
	    {
		tbl_wide_privs = psy_cb->psy_opmap;
		csp = (PSY_COL_PRIVS *) NULL;
	    }

	    status = psy_tbl_grant_check(sess_cb, (i4) PSQ_PROT,
		&rngvar->pss_tabid, &tbl_wide_privs, csp, &indep_id,
		&indep_tbl_wide_privs, &indep_col_specific_privs,
		psy_cb->psy_flags, &insuf_privs, &quel_view,
		&psy_cb->psy_error);
	    if (DB_FAILURE_MACRO(status))
	    {
		goto exit;
	    }

	    if (insuf_privs)
	    {
		/* must audit failure to create a permit */
		if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE )
		{
		    DB_ERROR	e_error;

		    /* Must audit CREATE PERMIT failure. */
		    status = psy_secaudit(FALSE, sess_cb,
			    (char *)&rngvar->pss_tabdesc->tbl_name,
			    &rngvar->pss_tabdesc->tbl_owner,
			    sizeof(DB_TAB_NAME), SXF_E_TABLE,
			    I_SX2016_PROT_TAB_CREATE, SXF_A_FAIL | SXF_A_CREATE,
			    &e_error);
		    
		    status = (status > E_DB_ERROR) ? status : E_DB_ERROR;
		}
		goto exit;
	    }
	    else if (quel_view)
	    {
		goto exit;
	    }
	    
	    /*
	    ** If user is trying to grant one or more of
	    ** INSERT/DELETE/UPDATE on his/her view whose underlying table
	    ** or view is owned by another user, psy_tbl_grant_check() will
	    ** return id of the underlying object along with map of
	    ** privileges.  We will convert maps of independent privileges
	    ** into elements of independent privilege list and pass them
	    ** along to QEF
	    */
	    if (   indep_id.db_tab_base != (i4) 0
		&& (   indep_id.db_tab_base != rngvar->pss_tabid.db_tab_base
		    || indep_id.db_tab_index !=
			   rngvar->pss_tabid.db_tab_index
		   )
	       )
	    {
		if (indep_tbl_wide_privs & DB_DELETE)
		{
		    /*
		    ** the only expected independent table-wide privilege
		    ** is DELETE
		    */
		    obj_priv.psq_next		= (PSQ_OBJPRIV *) NULL;
		    obj_priv.psq_objtype		= PSQ_OBJTYPE_IS_TABLE;
		    obj_priv.psq_privmap		= (i4) DB_DELETE;
		    obj_priv.psq_objid.db_tab_base	= indep_id.db_tab_base;
		    obj_priv.psq_objid.db_tab_index = indep_id.db_tab_index;
		    indep_objs.psq_objprivs		= &obj_priv;
		}

		if (indep_col_specific_privs.psy_col_privs)
		{
		    i4		i, j;
		    PSQ_COLPRIV	*csp;
		    i4		*att_map, *p;
		    i4		priv_map = 0;

		    /*
		    ** privilege map is built using bitwise operators, but
		    ** here using BTnext() makes code much more palatable,
		    ** so convert a privilege map
		    */
		    if (indep_col_specific_privs.psy_col_privs & DB_APPEND)
			BTset(DB_APPP, (char *) &priv_map);
		    if (indep_col_specific_privs.psy_col_privs & DB_REPLACE)
			BTset(DB_REPP, (char *) &priv_map);

		    for (i = -1, csp = col_privs;
			 (i = BTnext(i, (char *) &priv_map, BITS_IN(priv_map)))
			      != -1;
			  csp++
			)
		    {
			csp->psq_next = indep_objs.psq_colprivs;
			indep_objs.psq_colprivs = csp;
			csp->psq_objtype = PSQ_OBJTYPE_IS_TABLE;
			csp->psq_tabid.db_tab_base = indep_id.db_tab_base;
			csp->psq_tabid.db_tab_index = indep_id.db_tab_index;
			switch (i)
			{
			    case DB_APPP:	    /* INSERT privilege */
			    {
				csp->psq_privmap = (i4) DB_APPEND;
				att_map = indep_col_specific_privs.
				    psy_attmap[PSY_INSERT_ATTRMAP].map;
				break;
			    }
			    case DB_REPP:
			    {
				csp->psq_privmap = (i4) DB_REPLACE;
				att_map = indep_col_specific_privs.
				    psy_attmap[PSY_UPDATE_ATTRMAP].map;
				break;
			    }
			}

			for (p = csp->psq_attrmap, j = 0;
			     j < DB_COL_WORDS;
			     j++)
			{
			    *p++ = *att_map++;
			}
		    }
		}
	    }
	}
	else
	{
	    /*
	    ** either this is a catalog and the user has CATUPD or
	    ** this is an extended catalog and the user is the DBA;
	    ** since we may be allowing a user to create a permit by
	    ** circumventing the permit system, we only need to ascertain that
	    ** this is an SQL view
	    */
	    i4	    issql = 0;

	    status = psy_sqlview(rngvar, sess_cb, err_blk, &issql);
	    if (status)
	    {
		goto exit;
	    }
	    if (!issql)
	    {
		/* can only have permits on SQL views */
		psf_error(3598L, 0L, PSF_USERERR, &err_code, err_blk, 1, 
		    psf_trmwhite(sizeof(rngvar->pss_tabname),
			(char *) &rngvar->pss_tabname),
		    &rngvar->pss_tabname);
		status = E_DB_ERROR;
		goto exit;
	    }
	}
    }
    /* Name of user getting permission */
    STRUCT_ASSIGN_MACRO(psy_cb->psy_user, protup->dbp_owner);

    /* Terminal at which permission given */
    STRUCT_ASSIGN_MACRO(psy_cb->psy_terminal, protup->dbp_term);

    /* Give RDF pointer to query tree, if any */
    if (!psy_cb->psy_istree)
    {
	rdf_rb->rdr_qry_root_node = (PTR) NULL;
    }
    else
    {
	PST_VRMAP   varset;
	i4	    j;

	STRUCT_ASSIGN_MACRO(psy_cb->psy_intree, qsf_rb.qsf_obj_id);
	qsf_rb.qsf_lk_state = QSO_EXLOCK;
	status = qsf_call(QSO_LOCK, &qsf_rb);
	if (DB_FAILURE_MACRO(status))
	{
	    (VOID) psf_error(E_PS0D19_QSF_INFO, qsf_rb.qsf_error.err_code,
		PSF_INTERR, &err_code, err_blk, 0);
	    goto exit;
	}

	tree_lock		= qsf_rb.qsf_lk_id;
	pnode = (PST_PROCEDURE *) qsf_rb.qsf_root;
	qtree = (PST_QTREE *) pnode->pst_stmts->pst_specific.pst_tree;
	rdf_rb->rdr_qry_root_node = (PTR) pnode;
	/* check for no views in the qualification.
	*/
	(VOID)psy_varset(qtree->pst_qtree, &varset);	
	j = BTnext(-1, (char *) &varset, BITS_IN(varset));
	for ( ; j >= 0; j = BTnext(j, (char *) &varset, BITS_IN(varset)))
	{
	    status = pst_rgent(sess_cb, rngtab, -1, "", PST_SHWID,
		(DB_TAB_NAME *) NULL, (DB_TAB_OWN *) NULL,
		&qtree->pst_rangetab[j]->pst_rngvar, TRUE,
		&rngvar, (i4) 0, err_blk);
	    if (status)
		goto exit;		

	    if (rngvar->pss_tabdesc->tbl_status_mask & DMT_VIEW)
	    {
		psf_error(3597L, 0L, PSF_USERERR, &err_code, err_blk, 1,
		    psf_trmwhite(sizeof(rngvar->pss_tabname),
			(char *) &rngvar->pss_tabname),
		    &rngvar->pss_tabname);
		    status = E_DB_ERROR;
		    goto exit;
	    }
	}
    }
    
    /* Give RDF a pointer to the query text to be stored in iiqrytext */
    STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id);
    qsf_rb.qsf_lk_state = QSO_EXLOCK;
    status = qsf_call(QSO_LOCK, &qsf_rb);
    if (DB_FAILURE_MACRO(status))
    {
	(VOID) psf_error(E_PS0D19_QSF_INFO, qsf_rb.qsf_error.err_code,
	    PSF_INTERR, &err_code, err_blk, 0);
	goto exit;
    }

    text_lock = qsf_rb.qsf_lk_id;

    MEcopy((char *) qsf_rb.qsf_root, sizeof(i4), (char *) &textlen);
    rdf_rb->rdr_l_querytext = textlen;
    rdf_rb->rdr_querytext = ((char *) qsf_rb.qsf_root) + sizeof(i4);
    rdf_rb->rdr_status = (sess_cb->pss_lang == DB_SQL) ? DB_SQL : 0;

    /* determine if the permit specifies exactly one privilege */
    if (BTcount((char *) &psy_cb->psy_opmap, BITS_IN(psy_cb->psy_opmap)) > 1)
    {
	/*
	** if permit specified more than one privilege, notify QEF that it will
	** have to split the permit into multiple IIPROTECT tuples
	*/
	rdf_rb->rdr_instr |= RDF_SPLIT_PERM;
    }
    else if (psy_cb->psy_opmap & DB_RETRIEVE)
    {
	/*
	** if qeu_cprot() will not be splitting the permit into multiple tuples
	** and RETRIEVE is the privilege mentioned in it, set the two bits
	** associated with DB_RETRIEVE
	*/
	psy_cb->psy_opmap |= DB_TEST | DB_AGGREGATE;
	psy_cb->psy_opctl |= DB_TEST | DB_AGGREGATE;
    }

    /* Null out the DMU control block pointer, just in case */
    rdf_rb->rdr_dmu_cb = (PTR) NULL;

    /* produce list of dependent tables */
    rdf_rb->rdr_cnt_base_id = 0;
    if (psy_cb->psy_istree && qtree->pst_qtree) 
    {
	j = 0;
	(VOID)psy_varset(qtree->pst_qtree, &varmap);
	for (i = -1; (i = BTnext(i, (char*) &varmap, PST_NUMVARS)) > -1;)
	{
	    /* if this is the table that is getting the permit, ignore */
	    if (qtree->pst_rangetab[i]->pst_rngvar.db_tab_base != 
		    psy_tbl->psy_tabid.db_tab_base
		||
		qtree->pst_rangetab[i]->pst_rngvar.db_tab_index !=
		    psy_tbl->psy_tabid.db_tab_index
	    )
	    {
		rdf_rb->rdr_cnt_base_id++;
		STRUCT_ASSIGN_MACRO(qtree->pst_rangetab[i]->pst_rngvar,
		    tabids[j++]);
	    }
	}
	rdf_rb->rdr_base_id = tabids;
    }

    protup->dbp_popctl = psy_cb->psy_opctl;
    protup->dbp_popset = psy_cb->psy_opmap;
    
    /*
    ** store an indication of whether this permit is being created using SQL or
    ** QUEL
    */
    protup->dbp_flags = (sess_cb->pss_lang == DB_SQL) ? DBP_SQL_PERM : (i2) 0;
    protup->dbp_flags |= DBP_65_PLUS_PERM;

    /* Now let RDF do all the work of the permit definition */
    status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);
    if (DB_FAILURE_MACRO(status))
    {
	if (rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL)
	{
	    (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR,
		&err_code, err_blk, 1,
		psf_trmwhite(sizeof(psy_tbl->psy_tabnm),
		    (char *) &psy_tbl->psy_tabnm),
		&psy_tbl->psy_tabnm);
	}
	else
	{
	    (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error,
		&psy_cb->psy_error);
	}
	goto exit;
    }

    /*
    ** Invalidate base object's infoblk from RDF cache.
    */
    pst_rdfcb_init(&rdf_cb, sess_cb);
    STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[0], rdf_rb->rdr_tabid);
    status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb);
    if (DB_FAILURE_MACRO(status))
    {
	(VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error,
				&psy_cb->psy_error);
    }

exit:

    qsf_rb.qsf_lk_state = QSO_EXLOCK;

    if (psy_cb->psy_istree)
    {
	/* Destroy query tree */
	STRUCT_ASSIGN_MACRO(psy_cb->psy_intree, qsf_rb.qsf_obj_id);

	if ((qsf_rb.qsf_lk_id = tree_lock) == 0)
	{
	    stat = qsf_call(QSO_LOCK, &qsf_rb);
	    if (DB_FAILURE_MACRO(stat))
	    {
		(VOID) psf_error(E_PS0D18_QSF_LOCK,
		    qsf_rb.qsf_error.err_code, PSF_INTERR,
		    &err_code, &psy_cb->psy_error, 0);
		if (!status || stat == E_DB_FATAL)
		    status = stat;
	    }
	    tree_lock = qsf_rb.qsf_lk_id;
	}

	stat = qsf_call(QSO_DESTROY, &qsf_rb);
	if (DB_FAILURE_MACRO(stat))
	{
	    (VOID) psf_error(E_PS0D1A_QSF_DESTROY,
		qsf_rb.qsf_error.err_code, PSF_INTERR,
		&err_code, &psy_cb->psy_error, 0);
	    if (!status || stat == E_DB_FATAL)
		status = stat;
	}

	tree_lock = 0;
    }

    /* Destroy query text */
    STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id);

    if ((qsf_rb.qsf_lk_id = text_lock) == 0)
    {
	stat = qsf_call(QSO_LOCK, &qsf_rb);
	if (DB_FAILURE_MACRO(stat))
	{
	    (VOID) psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code,
		PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	    if (!status || stat == E_DB_FATAL)
		status = stat;
	}
	text_lock = qsf_rb.qsf_lk_id;
    }

    stat = qsf_call(QSO_DESTROY, &qsf_rb);
    if (DB_FAILURE_MACRO(stat))
    {
	(VOID) psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code,
	    PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	if (!status || stat == E_DB_FATAL)
	    status = stat;
    }

    return (status);
}
Beispiel #18
0
DB_STATUS
qeq_c5_replace(
QEF_RCB	    *v_qer_p,
QEE_DSH	    *i_dsh_p )
{
    DB_STATUS	    status = E_DB_OK;
    QEE_DSH	    *ree_p = i_dsh_p->dsh_aqp_dsh;  
						/* must use update dsh for 
						** cursor */
    QEE_DDB_CB	    *uee_p = ree_p->dsh_ddb_cb;
    QES_DDB_SES	    *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses;
    QES_QRY_SES	    *qss_p = & dds_p->qes_d8_union.u2_qry_ses;
    QEQ_DDQ_CB	    *ddq_p = & i_dsh_p->dsh_qp_ptr->qp_ddq_cb;
    QEF_AHD	    *act_p = i_dsh_p->dsh_qp_ptr->qp_ahd;
    QEQ_D1_QRY	    *sub_p = & act_p->qhd_obj.qhd_d1_qry;
    bool	    log_qry_55 = FALSE,
                    log_err_59 = FALSE;
    i4         i4_1, i4_2;
    TPR_CB	    tpr,
		    *tpr_p = & tpr;
    RQR_CB	    rqr,
		    *rqr_p = & rqr;


    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55,
        & i4_1, & i4_2))
    {
	log_qry_55 = TRUE;
	qeq_p35_upd_csr(v_qer_p, i_dsh_p);
    }

    if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59,
        & i4_1, & i4_2))
        log_err_59 = TRUE;


    /* 2.  then set up to call RQF to replace */

    MEfill(sizeof(rqr), '\0', (PTR) & rqr);
    rqr_p->rqr_session = dds_p->qes_d3_rqs_p;   /* RQF session id */

    rqr_p->rqr_q_language = qss_p->qes_q2_lang; 
    rqr_p->rqr_timeout = sub_p->qeq_q2_quantum;
    STRUCT_ASSIGN_MACRO(*sub_p->qeq_q4_seg_p->qeq_s2_pkt_p, rqr_p->rqr_msg);
    rqr_p->rqr_1_site = sub_p->qeq_q5_ldb_p;
    if (sub_p->qeq_q8_dv_cnt == 0)
    {
	rqr_p->rqr_dv_cnt = v_qer_p->qef_pcount;
	rqr_p->rqr_dv_p = (DB_DATA_VALUE *) v_qer_p->qef_param;
						/* pass array base */
    }
    else
    {

	rqr_p->rqr_dv_cnt = ddq_p->qeq_d4_total_cnt;
	rqr_p->rqr_dv_p = ddq_p->qeq_d6_fixed_data;
/*	rqr_p->rqr_dv_p = uee_p->qee_d7_dv_p + 1;*/
						/* 1-based, make 0-based */
    }
    rqr_p->rqr_qid_first = sub_p->qeq_q12_qid_first;
    STRUCT_ASSIGN_MACRO(uee_p->qee_d5_local_qid, rqr_p->rqr_qid);
    rqr_p->rqr_tmp = uee_p->qee_d1_tmp_p;

    qss_p->qes_q1_qry_status |= QES_03Q_PHASE2;
						/* enter phase 2 for update */
    status = qed_u3_rqf_call(RQR_UPDATE, rqr_p, v_qer_p);
    if (status)
    {
	if (log_err_59 && !log_qry_55)
	    qeq_p35_upd_csr(v_qer_p, i_dsh_p);
	return(status);
    }	
    else
	qss_p->qes_q1_qry_status &= ~QES_03Q_PHASE2;

    v_qer_p->qef_rowcount = rqr_p->rqr_tupcount;
    v_qer_p->qef_count = rqr_p->rqr_tupcount;
						/* return update row count */
    return(E_DB_OK);
}