Beispiel #1
0
/*{
** Name: opx_init	- initialize the AIC and PAINE handlers
**
** Description:
**      This routine will inform SCF of the AIC and PAINE handlers
**
** Inputs:
**	opf_cb				    - ptr to caller's control block
**
** Outputs:
**	Returns:
**	    E_DB_OK
**          E_DB_ERROR - if initialization failed
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**      31-mar-87 (seputis)
**          initial creation
**      12-dec-88 (seputis)
**	    return E_DB_OK
[@history_template@]...
*/
DB_STATUS
opx_init(
	OPF_CB		*opf_cb)
{
    SCF_CB                 scf_cb;
    DB_STATUS              scf_status;

    scf_cb.scf_length = sizeof(scf_cb);
    scf_cb.scf_type = SCF_CB_TYPE;
    scf_cb.scf_facility = DB_OPF_ID;
    scf_cb.scf_ptr_union.scf_afcn = opx_call;
    scf_cb.scf_session = DB_NOSESSION;
    scf_cb.scf_nbr_union.scf_amask = SCS_PAINE_MASK;
    scf_status = scf_call(SCS_DECLARE, &scf_cb);
# ifdef E_OP0090_PAINE
    if (DB_FAILURE_MACRO(scf_status))
    {
	opx_rverror( opf_cb, scf_status, E_OP0090_PAINE,
	    scf_cb.scf_error.err_code);
	return(E_DB_ERROR);
    }
# endif
    scf_cb.scf_nbr_union.scf_amask = SCS_AIC_MASK;
    scf_status = scf_call(SCS_DECLARE, &scf_cb);
# ifdef E_OP0091_AIC
    if (DB_FAILURE_MACRO(scf_status))
    {
	opx_rverror( opf_cb, scf_status, E_OP0091_AIC,
	    scf_cb.scf_error.err_code);
	return(E_DB_ERROR);
    }
# endif
    return(E_DB_OK);
}
Beispiel #2
0
/*{
** Name: psy_kuser - Destroy user
**
**  INTERNAL PSF call format: status = psy_kuser(&psy_cb, sess_cb);
**
** Description:
**	This procedure deletes a user.  If the
**	user does not exist, the statement is aborted.
**	If the user does exist, the associated
**	iiuser tuple is deleted.
**	This procedure is called for SQL language only.
**
** Inputs:
**      psy_cb
**	    .psy_usrq			user list
**	sess_cb				Pointer to session control block
**					(Can be NULL)
**
** Outputs:
**      psy_cb
**	    .psy_error			Filled in if error happens
**	Returns:
**	    E_DB_OK			Function completed normally.
**	    E_DB_INFO			Function completed with warning(s).
**	    E_DB_WARN			One ore more roles were rejected.
**	    E_DB_ERROR			Function failed; non-catastrophic error
**	Exceptions:
**	    none
**
** Side Effects:
**	    Removed tuples from iiuser.
**
** History:
**	04-sep-89 (ralph)
**          written
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
*/
DB_STATUS
psy_kuser(
	PSY_CB             *psy_cb,
	PSS_SESBLK	   *sess_cb)
{
    DB_STATUS		status, stat;
    RDF_CB		rdf_cb;
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    DU_USER		ustuple;
    register DU_USER	*ustup = &ustuple;
    PSY_USR		*psy_usr;

    /* This code is called for SQL only */

    /*
    ** Fill in the part of RDF request block that will be constant.
    */
    pst_rdfcb_init(&rdf_cb, sess_cb);
    rdf_rb->rdr_update_op   = RDR_DELETE;
    rdf_rb->rdr_status	    = DB_SQL;
    rdf_rb->rdr_types_mask  = RDR_USER;
    rdf_rb->rdr_qrytuple    = (PTR) ustup;
    rdf_rb->rdr_qtuple_count = 1;

    ustup->du_gid	= 0;
    ustup->du_mid	= 0;
    ustup->du_status 	= 0;
    ustup->du_flagsmask	= 0;


    MEfill(sizeof(ustup->du_group),
	   (u_char)' ',
	   (PTR)&ustup->du_group);

    status = E_DB_OK;

    for (psy_usr  = (PSY_USR *)  psy_cb->psy_usrq.q_next;
	 psy_usr != (PSY_USR *) &psy_cb->psy_usrq;
	 psy_usr  = (PSY_USR *)  psy_usr->queue.q_next
	)
    {
	/* STRUCT_ASSIGN_MACRO(psy_usr->psy_usrnm,
			       ustup->du_name); */
	MEcopy((PTR)&psy_usr->psy_usrnm,
	       sizeof(ustup->du_name),
	       (PTR)&ustup->du_name);

	stat = rdf_call(RDF_UPDATE, (PTR)&rdf_cb);
	status = (stat > status) ? stat : status;

	if (DB_FAILURE_MACRO(stat))
	    break;
    }

    if (DB_FAILURE_MACRO(status))
	(VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, 
			     &psy_cb->psy_error);

    return    (status);
} 
Beispiel #3
0
/*{
** Name: psy_create_synonym - Insert a tuple into IISYNONYM.
**
** Description:
**	Call RDF_UPDATE to insert a tuple into IISYNONYM.
** Inputs:
**	psy_cb		PSY control block.
**	sess_cb		PSF session control block.
** Outputs:
**	Exceptions:
**	    none
** Returns:
**	E_DB_OK			synonym tuple has been inserted successfully;
**	error status from RDF	otherwise
**
** Side Effects:
**	    Modifies system catalogs.
**
** History:
**      19-apr-90 (andre)
**	    Created.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
**	03-aug-92 (barbara)
**	    Invalidate base object's infoblk from the RDF cache.
**	10-aug-93 (andre)
**	    fixed causes of compiler warnings
*/
DB_STATUS
psy_create_synonym(
	PSY_CB	   *psy_cb,
	PSS_SESBLK *sess_cb)
{
    RDF_CB		rdf_cb;
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    DB_STATUS		status;
    i4		err_code;

    /* Initialize the RDF request block. */
    pst_rdfcb_init(&rdf_cb, sess_cb);
    STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner);
    rdf_rb->rdr_2types_mask = (RDF_TYPES) RDR2_SYNONYM;
    rdf_rb->rdr_update_op = RDR_APPEND;
    rdf_rb->rdr_qrytuple = psy_cb->psy_tupptr;
    rdf_rb->rdr_tabid.db_tab_base = DM_B_SYNONYM_TAB_ID;
    rdf_rb->rdr_tabid.db_tab_index = DM_I_SYNONYM_TAB_ID;

    /* Insert a tuple into IISYNONYM */
    status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);

    if (DB_FAILURE_MACRO(status))
    {
	if (rdf_cb.rdf_error.err_code == E_RD0143_CREATE_SYNONYM)
	{
	    DB_IISYNONYM	*syn = (DB_IISYNONYM *) psy_cb->psy_tupptr;
	    
	    (VOID) psf_error(E_PS0454_CREATE_SYN_ERROR, 0L, PSF_USERERR,
		&err_code, &psy_cb->psy_error, 1,
		psf_trmwhite(sizeof(DB_SYNNAME), (char *) &syn->db_synname),
		&syn->db_synname);
	}
	else
	{
	    (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error,
		&psy_cb->psy_error);
	}

	return (status);
    }

    /* Invalidate the base object's info block from the RDF cache */
    {
	DB_IISYNONYM	*syn_tuple = (DB_IISYNONYM *) psy_cb->psy_tupptr;

	pst_rdfcb_init(&rdf_cb, sess_cb);
	STRUCT_ASSIGN_MACRO(syn_tuple->db_syntab_id, 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);
	}
    }
    return (status);
}
Beispiel #4
0
/*{
** Name: psy_kgroup - Destroy group
**
**  INTERNAL PSF call format: status = psy_kgroup(&psy_cb, sess_cb);
**
** Description:
**	This procedure deletes group identifiers.  No members can be
**	in the group to be deleted.  If members exist in a group,
**	the group is not deleted.
**	This procedure is called for SQL language only.
**
** Inputs:
**      psy_cb
**	    .psy_tblq			head of group  queue
**	sess_cb				Pointer to session control block
**					(Can be NULL)
**
** Outputs:
**      psy_cb
**	    .psy_error			Filled in if error happens
**	Returns:
**	    E_DB_OK			Function completed normally.
**	    E_DB_INFO			Function completed with message(s).
**	    E_DB_WARN			One or more groups were rejected.
**	    E_DB_ERROR			Function failed; non-catastrophic error
**	Exceptions:
**	    none
**
** Side Effects:
**	    Removed tuples from iiusergroup.
**
** History:
**	13-mar-89 (ralph)
**          written
**	20-may-89 (ralph)
**	    Allow multiple groups to be specified.
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
*/
DB_STATUS
psy_kgroup(
	PSY_CB             *psy_cb,
	PSS_SESBLK	   *sess_cb)
{
    DB_STATUS		status, stat;
    RDF_CB		rdf_cb;
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    DB_USERGROUP	ugtuple;
    register DB_USERGROUP *ugtup = &ugtuple;
    PSY_TBL		*psy_tbl;
    PSY_USR		*psy_usr;

    /* This code is called for SQL only */

    /*
    ** Fill in the part of RDF request block that will be constant.
    */
    pst_rdfcb_init(&rdf_cb, sess_cb);
    rdf_rb->rdr_update_op   = RDR_DELETE;
    rdf_rb->rdr_status	    = DB_SQL;
    rdf_rb->rdr_types_mask  = RDR_GROUP;
    rdf_rb->rdr_qrytuple    = (PTR) ugtup;
    rdf_rb->rdr_qtuple_count = 1;

    MEfill(sizeof(DB_OWN_NAME), (u_char)' ', (PTR)&ugtup->dbug_member);
    MEfill(sizeof(ugtup->dbug_reserve),
	   (u_char)' ',
	   (PTR)ugtup->dbug_reserve);

    status = E_DB_OK;

    for (psy_tbl  = (PSY_TBL *)  psy_cb->psy_tblq.q_next;
	 psy_tbl != (PSY_TBL *) &psy_cb->psy_tblq;
	 psy_tbl  = (PSY_TBL *)  psy_tbl->queue.q_next
	)
    {
	/* STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabnm,
			       ugtup->dbug_group); */
	MEcopy((PTR)&psy_tbl->psy_tabnm,
	       sizeof(ugtup->dbug_group),
	       (PTR)&ugtup->dbug_group);

	stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);
	status = (stat > status) ? stat : status;

	if (DB_FAILURE_MACRO(stat))
	    break;
    }

    if (DB_FAILURE_MACRO(status))
	(VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, 
			     &psy_cb->psy_error);

    return    (status);
}
Beispiel #5
0
/*{
** Name: OPU_RELEASE	- Return memory to the global memory pool
**
** Description:
**      This routine returns memory from the given mark to the end of the
**	ULM memory stream to the global memory pool.
[@comment_line@]...
**
** Inputs:
**	global -
**	    State info for the current query.
**      ulmrcb -
**          address of local control block, or NULL if
**	    global->ops_mstate.ops_ulmrcb should be used
**	mark -
**	    The mark stating where to start returning memory.
**
** Outputs:
**
**	Returns:
**	    none
**	Exceptions:
**	    none
**
** Side Effects:
**	    Memory is returned to the global memory pool
**
** History:
**      18-apr-87 (seputis)
**          initial creation
**	11-oct-2006 (hayke02)
**	    Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309.
[@history_template@]...
*/
VOID
opu_release(
	OPS_STATE   *global,
	ULM_RCB     *ulmrcb,
	ULM_SMARK   *mark)
{
    DB_STATUS      ulmstatus;		    /* return status from ULM */

    if (!ulmrcb)
    {
	ulmrcb = &global->ops_mstate.ops_ulmrcb; /* use global ulmrcb if
					    ** control block is not defined */
	ulmrcb->ulm_streamid_p = &global->ops_mstate.ops_streamid; 
					    /* mark memory
					    ** in the global stream */
    }
    /* store the mark to be initialized */
    ulmrcb->ulm_smark = mark;

    ulmstatus = ulm_reclaim( ulmrcb );
    if ( DB_FAILURE_MACRO(ulmstatus) )
    {
	if (ulmrcb->ulm_error.err_code == E_UL0005_NOMEM)
	{
	    opx_lerror(E_OP0002_NOMEMORY, 0, 0, 0, 0, 0);
	    opx_error( E_OP0002_NOMEMORY);  /* out of memory */
	}
#ifdef E_OP0093_ULM_ERROR
	else
	    opx_verror( ulmstatus, E_OP0093_ULM_ERROR, 
		ulmrcb->ulm_error.err_code); /* check for error */
#endif
    }	
}
Beispiel #6
0
/*{
** Name: psq_tinsert 	- Add a piece of query text to a chain in front
**			  of some piece.
**
** Description:
**      This function inserts a piece of query text to an existing chain.
**	New text is added in front of the existing piece specified by the
**	caller .
**	A need for the routine arises from the fact that the owner names need
**	to qualify database object names in case of database procedures.
**	Another use for the function is when synonym_name has to be
**	replaced with owner.actual_table_name in the text stored for views,
**	integrities, and permits.
**	These names become known when the scanner has already 'seen' the
**	object name (and therefore has already added it to the text chain).
**
** Inputs:
**      header                          Pointer to chain header
**	piece				Pointer to piece of text
**	size				Size of piece
**	result				Place to put pointer to new piece
**	oldpiece			Piece in front of which the new piece
**					will be inserted (should not be NULL).
**	err_blk				Filled in if an error happens
**
** Outputs:
**      result                          Filled in with pointer to chain element
**	err_blk				Filled in if an error happens
**	Returns:
**	    E_DB_OK			Success
**	    E_DB_ERROR			Non-catastrophic failure
**	    E_DB_FATAL			Catastrophic failure
**	Exceptions:
**	    none
**
** Side Effects:
**	    Allocates memory
**
** History:
**      02-jun-88 (stec)
**          written
**	04-jun-90 (andre)
**	    renamed from psq_tb1add() to psq_tinsert();
**	    changed the description to describe use of this function in
**	    conjunction with synonyms.
*/
DB_STATUS
psq_tinsert(
	PTR                header,
	u_char		   *piece,
	i4		   size,
	PTR		   *result,
	PTR		   oldpiece,
	DB_ERROR	   *err_blk)
{
    PSQ_THEAD           *hp = (PSQ_THEAD *) header;
    PSQ_TEXT		*tp, *op = (PSQ_TEXT *) oldpiece;
    i4		err_code;
    DB_STATUS		status;

    if (op == (PSQ_TEXT *) NULL)
    {
	/* Should not be reached */
	return (E_DB_ERROR);
    }

    /* Allocate enough space for PSQ_TEXT structure containing piece */
    hp->psq_tmem.ulm_psize = size + sizeof(PSQ_TEXT) - 1;
    status = ulm_palloc(&hp->psq_tmem);
    if (DB_FAILURE_MACRO(status))
    {
	if (hp->psq_tmem.ulm_error.err_code == E_UL0005_NOMEM)
	{
	    psf_error(E_PS0F02_MEMORY_FULL, 0L, PSF_CALLERR, 
		&err_code, err_blk, 0);
	}
	else
	    (VOID) psf_error(E_PS0371_ALLOC_TEXT_CHAIN,
		hp->psq_tmem.ulm_error.err_code, PSF_INTERR, &err_code,err_blk, 0);
	return (status);
    }
    *result = hp->psq_tmem.ulm_pptr;
    tp	    = (PSQ_TEXT*) *result;

    /* Fill in text piece */
    MEcopy((char *) piece, size, (char *) tp->psq_tval);
    tp->psq_psize = size;

    /* Hook it up to the chain */
    if (tp->psq_prev = op->psq_prev)
	tp->psq_prev->psq_next = tp;
    tp->psq_next = op;
    op->psq_prev = tp;

    if (hp->psq_first == op)
	hp->psq_first = tp;

    /* Add in the length to the total for the chain */
    hp->psq_tsize += size;

    return (E_DB_OK);
}
Beispiel #7
0
FUNC_EXTERN  DB_STATUS  IICXcreate_icas_xn_cb(
                           IICX_ID             *cx_id,          /* IN */
                           IICX_CB             **cx_cb_p_p      /* OUT */
                        )
{
    DB_STATUS		db_status;
    STATUS		cl_status;
    char		ebuf[20];
    IICX_ICAS_XN_CB     *icas_xn_cb_p;
    i4			i;

    /* LOCK the ICAS XN MAIN CB. CHECK !!! */

    if (IIcx_icas_xn_main_cb->num_free_icas_xn_cbs > 0)
    {
        *cx_cb_p_p = IIcx_icas_xn_main_cb->icas_xn_cb_free_list;
        IIcx_icas_xn_main_cb->icas_xn_cb_free_list =
                                          (*cx_cb_p_p)->cx_next;

        if ((*cx_cb_p_p)->cx_next != NULL)
            (*cx_cb_p_p)->cx_next->cx_prev = (*cx_cb_p_p)->cx_prev;
         
        IIcx_icas_xn_main_cb->num_free_icas_xn_cbs--;
    }

    if (*cx_cb_p_p != NULL)
    {
	/* UNLOCK the ICAS XN  Main CB. CHECK !!! */
        return( E_DB_OK );
    }

    /* UNLOCK the ICAS XN Main CB. CHECK !!! */

    /* No free ICAS XN CBs. Create one if appropriate */
    db_status = IICXget_new_cx_cb( cx_cb_p_p );
    if (DB_FAILURE_MACRO(db_status))
    {
       return(db_status);
    }

    if ((icas_xn_cb_p = (IICX_ICAS_XN_CB *)MEreqmem((u_i4)0, 
                                (u_i4)sizeof(IICX_ICAS_XN_CB),
                                TRUE, (STATUS *)&cl_status)) == NULL)
    {
           CVna((i4)cl_status, ebuf);
           IICXerror(GE_NO_RESOURCE, E_CX0002_CX_CB_ALLOC, 2, ebuf, 
                                      ERx("IICX_ICAS_XN_CB"));
           return( E_DB_FATAL );
    }

    (*cx_cb_p_p)->cx_sub_cb.icas_xn_cb_p = icas_xn_cb_p;

    return( E_DB_OK );

} /* IICXcreate_icas_xn_cb */
Beispiel #8
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 #9
0
/*  PSY_SQLVIEW - IS THIS AN SQL VIEW
**
**  Description:
**	This routine takes a range entry and determines if it is an
**  SQL view. This routine assumes that we know that the range entry
**  refers to a view.
**
** History:
**	29-sep-92 (andre)
**	    RDF may choose to allocate a new info block and return its address
**	    in rdf_info_blk - we need to copy it over to pss_rdrinfo to avoid
**	    memory leak and other assorted unpleasantries
*/
DB_STATUS
psy_sqlview(
	PSS_RNGTAB	    *rngvar,
	PSS_SESBLK	    *sess_cb,
	DB_ERROR	    *err_blk,
	i4		    *issql)
{
    DB_STATUS	    status = E_DB_OK;
    RDF_CB	    rdf_cb;
    PST_PROCEDURE   *pnode;
    PST_QTREE	    *vtree;
    i4	    err_code;

    *issql = FALSE;
    pst_rdfcb_init(&rdf_cb, sess_cb);
    STRUCT_ASSIGN_MACRO(rngvar->pss_tabid, rdf_cb.rdf_rb.rdr_tabid);
    rdf_cb.rdf_rb.rdr_types_mask = RDR_VIEW | RDR_QTREE ;
    rdf_cb.rdf_rb.rdr_qtuple_count = 1;
    rdf_cb.rdf_info_blk = rngvar->pss_rdrinfo;
    status = rdf_call(RDF_GETINFO, (PTR) &rdf_cb);

    /*
    ** RDF may choose to allocate a new info block and return its address in
    ** rdf_info_blk - we need to copy it over to pss_rdrinfo to avoid memory
    ** leak and other assorted unpleasantries
    */
    rngvar->pss_rdrinfo = rdf_cb.rdf_info_blk;
    
    if (DB_FAILURE_MACRO(status))
    {
	if (rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL)
	{
	    (VOID) psf_error(E_PS0903_TAB_NOTFOUND, rdf_cb.rdf_error.err_code,
		PSF_INTERR, &err_code, err_blk, 1,
		psf_trmwhite(sizeof(DB_TAB_NAME), 
		    (char *) &rngvar->pss_tabname),
		&rngvar->pss_tabname);
	}
	else
	{
	    (VOID) psf_rdf_error(RDF_GETINFO, &rdf_cb.rdf_error, err_blk);
	}
	return (status);
    }
    pnode = (PST_PROCEDURE *) rdf_cb.rdf_info_blk->rdr_view->qry_root_node;
    vtree = pnode->pst_stmts->pst_specific.pst_tree;
    if (vtree->pst_qtree->pst_sym.pst_value.pst_s_root.pst_qlang == DB_SQL)
	*issql = TRUE;

    return (status);
}
Beispiel #10
0
/*{
** Name: psq_tout	- Copy a text chain to QSF memory
**
** Description:
**      This function copies a text chain to QSF memory, as a text object.
**	It allocates it as a contiguous piece.
**
** Inputs:
**	rngtab			if non-NULL, range statements will be
**				generated for all entries of the range table
**				that are active (pss_used && pss_rgno >= 0);
**				should be non-NULL only for QUEL queries
**      header                  Pointer to chain header
**	mstream			Pointer to unopened memory stream
**	err_blk			Filled in if an error happens
**
** Outputs:
**      mstream                 Filled with object id for new text
**				object
**	err_blk			Filled in if an error happened
**	Returns:
**	    E_DB_OK		Success
**	    E_DB_ERROR		Non-catastrophic failure
**	    E_DB_FATAL		Catastrophic failure
**	Exceptions:
**	    none
**
** Side Effects:
**	    Allocates memory
**
** History:
**      18-jul-86 (jeff)
**          written
**      2-sep-86 (seputis)
**          changed MEcopy routine parameter to be &hp->psq_tsize
**	6-may-87 (daved)
**	    clear mstream lock id after unlocking memory stream
**	29-jun-87 (daved)
**	    emit the range table entries if a range table is provided.
**	10-aug-93 (andre)
**	    removed declaration of qsf_call()
*/
DB_STATUS
psq_tout(
	PSS_SESBLK	   *sess_cb,
	PSS_USRRANGE	   *rngtab,
	PTR                header,
	PSF_MSTREAM	   *mstream,
	DB_ERROR	   *err_blk)
{
    DB_STATUS           status;
    i4		err_code;
    u_char		*buf;
    QSF_RCB		qsf_rb;

    /* Open the QSF memory stream for the text object */
    status = psf_mopen(sess_cb, QSO_QTEXT_OBJ, mstream, err_blk);
    if (status != E_DB_OK)
	return (status);

    status = psq_store_text(sess_cb, rngtab, header, mstream, 
	(PTR *) &buf, (bool) FALSE, err_blk);
    if (DB_FAILURE_MACRO(status))
	return(status);

    /* Set the root of the object */
    status = psf_mroot(sess_cb, mstream, (PTR) buf, err_blk);
    if (status != E_DB_OK)
	return (status);

    /* Unlock the object */
    qsf_rb.qsf_type = QSFRB_CB;
    qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID;
    qsf_rb.qsf_length = sizeof(qsf_rb);
    qsf_rb.qsf_owner = (PTR)DB_PSF_ID;
    qsf_rb.qsf_sid = sess_cb->pss_sessid;
    STRUCT_ASSIGN_MACRO(mstream->psf_mstream, qsf_rb.qsf_obj_id);
    qsf_rb.qsf_lk_id = mstream->psf_mlock;
    status = qsf_call(QSO_UNLOCK, &qsf_rb);
    if (status != E_DB_OK)
    {
	(VOID) psf_error(E_PS0375_UNLOCK_QSF_TEXT,
	    qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0);
	return (status);
    }
    mstream->psf_mlock = 0;

    return (E_DB_OK);
}
Beispiel #11
0
static VOID
psy_push(PSY_STK *base, PTR val, STATUS *sts)
{
    /* Point to true list head block */
    PSY_STK *stk = base->head ? base->head : base;

    if (stk->sp >= N_STK)
    {
        base->head = (PSY_STK*)MEreqmem(0, sizeof(PSY_STK), FALSE, sts);
        if (!base->head || DB_FAILURE_MACRO(*sts))
	   return;
        base->head->head = stk;
        stk = base->head;
        stk->sp = 0;
   }
   stk->list[stk->sp++] = val;
}
Beispiel #12
0
/*{
** Name: opu_allocate	- allocate a new private memory stream
**
** Description:
**      This routine will allocate a new private memory stream from the ULM
**
** Inputs:
**      global                          ptr to global state variable
**
** Outputs:
**	Returns:
**	    PTR which represents the new memory stream
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	16-jun-86 (seputis)
**          initial creation
**	11-oct-2006 (hayke02)
**	    Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309.
[@history_line@]...
*/
PTR
opu_allocate(
    OPS_STATE          *global)
{
    DB_STATUS       ulmstatus;		/* return status from ulm */

    /* Tell ULM to return streamid into ulm_streamid */
    global->ops_mstate.ops_ulmrcb.ulm_streamid_p =
        &global->ops_mstate.ops_ulmrcb.ulm_streamid;
    ulmstatus = ulm_openstream(&global->ops_mstate.ops_ulmrcb);
    if (DB_FAILURE_MACRO(ulmstatus))
    {
        opx_lerror(E_OP0002_NOMEMORY, 0);
        opx_verror(ulmstatus, E_OP0002_NOMEMORY,
                   global->ops_mstate.ops_ulmrcb.ulm_error.err_code);
    }
    return ( global->ops_mstate.ops_ulmrcb.ulm_streamid );
}
Beispiel #13
0
/*{
** Name: psf_symall	Allocates memory for a symbol block.
**
** Description:
**      Symbol blocks are used mainly by scanners to pass additional data
**	to parsers. They also hold emmitted text. This routine allocates
**	a new block and takes care of initializing appropriate fields in the
**	session control block.
**
** Inputs:
**      pss_cb				session control block pointer.
**	psq_cb				query control block.
**	size				amount of memory to be allocated.
**
** Outputs:
**	pss_cb				session control block with
**					appropriate fields initialized.
**	psq_cb				query control block with psq_error
**					field initialized, if error.
**	Returns:
**	    E_DB_OK
**	    status			return by ULM
**
**	Exceptions:
**	    none
**
** Side Effects:
**	    Allocates memory.
**
** History:
**	25-nov-87 (stec)
**          written
**	31-jan-97 (pchang)
**	    psf_symall(), when allocating memory for a symbol table block,
**	    failed to take into account the space needed for the next block
**	    pointer 'pss_sbnext' which later caused memory overrun in the data
**	    area 'pss_symdata'.  In some cases, the corruption is neutralized
**	    when the user of the violated adjacent memory space overlays it
**	    with new data.  Whereas, if the violated memory space is occupied
**	    by a less volatile entity such as a pointer for a linked list,
**	    what follows could be a random SEGV.  (B75105?)
*/
DB_STATUS
psf_symall(
	PSS_SESBLK  *pss_cb,
	PSQ_CB	    *psq_cb,
	i4	    size)
{
    DB_STATUS	status = E_DB_OK;
    ULM_RCB	ulm_rcb;
    i4	err_code;

    /* If no more blocks, allocate another */
    if (pss_cb->pss_symblk->pss_sbnext==(PSS_SYMBLK *) NULL)
    {
	/* If out of room, allocate some more */
	ulm_rcb.ulm_facility = DB_PSF_ID;
	ulm_rcb.ulm_streamid_p = &pss_cb->pss_symstr;
	ulm_rcb.ulm_psize = size + sizeof(PTR);    /* add space for fwd ptr */
	ulm_rcb.ulm_memleft = &pss_cb->pss_memleft;
	status = ulm_palloc(&ulm_rcb);

	if (DB_FAILURE_MACRO(status))
	{
	    if (ulm_rcb.ulm_error.err_code == E_UL0005_NOMEM)
	    {
		psf_error(E_PS0F02_MEMORY_FULL, 0L, PSF_CALLERR,
		    &err_code, &psq_cb->psq_error, 0);
	    }
	    else
	    {
		psf_error(2704L, 0L, PSF_USERERR,
		    &err_code, &psq_cb->psq_error, 0);
	    }
	    return (status);
	}
	pss_cb->pss_symblk->pss_sbnext = (PSS_SYMBLK*) ulm_rcb.ulm_pptr;
	pss_cb->pss_symblk->pss_sbnext->pss_sbnext = NULL;
    }

    /* Set current block and next character pointer */
    pss_cb->pss_symblk = pss_cb->pss_symblk->pss_sbnext;
    pss_cb->pss_symnext = pss_cb->pss_symblk->pss_symdata;

    return (E_DB_OK);
}
Beispiel #14
0
DB_STATUS
IICXdelete_icas_xn_cb(
            IICX_CB       *cx_cb_p    /* IN */
           )
{
    DB_STATUS		db_status;
    IICX_ICAS_XN_CB 	*icas_xn_cb_p;
    i4			i;

    /* LOCK the ICAS XN MAIN CB. CHECK !!! */

    if ( IIcx_icas_xn_main_cb->num_free_icas_xn_cbs ==
         IIcx_icas_xn_main_cb->max_free_icas_xn_cbs )
    {

        /* UNLOCK the ICAS XN MAIN CB. CHECK !!! */
        db_status = IICXfree_cb( cx_cb_p );
        if (DB_FAILURE_MACRO( db_status ))
            return( db_status );
    }
    else
    {    
        IIcx_icas_xn_main_cb->num_free_icas_xn_cbs++;
        if (cx_cb_p->cx_prev != NULL)
            cx_cb_p->cx_prev->cx_next = cx_cb_p->cx_next;
        else
            IIcx_icas_xn_main_cb->icas_xn_list = cx_cb_p->cx_next;
        if (cx_cb_p->cx_next != NULL)
            cx_cb_p->cx_next->cx_prev = cx_cb_p->cx_prev;

        if (IIcx_icas_xn_main_cb->icas_xn_cb_free_list != NULL) 
	{
            IIcx_icas_xn_main_cb->icas_xn_cb_free_list->cx_prev = 
                                                   cx_cb_p;
	}
        cx_cb_p->cx_next = IIcx_icas_xn_main_cb->icas_xn_cb_free_list;
        cx_cb_p->cx_prev = NULL;
        IIcx_icas_xn_main_cb->icas_xn_cb_free_list = cx_cb_p;
        
    }

    return( E_DB_OK );

} /* IICXdelete_icas_xn_cb */
Beispiel #15
0
/*{
** Name: ops_alter	- alter session or server state for OPF
**
** Description:
**      This routine contains all processing of the SET commands for the
**      optimizer.  These commands can be at the server or session level.
**      There is currently no protection mechanism available for which
**      users are able to access these SET commands.  There probably should
**      be a system catalog created to decide privileges and min and max
**      values allowable for a session.  Currently, all users can do anything
**      at all.  This routine will not do anything in terms of checking
**      privileges.
**
**      SET [[SESSION] | SERVER] CPUFACTOR <value>
**      SET [[SESSION] | SERVER] TIMEOUT   <value>
**      SET [[SESSION] | SERVER] QEP
**      SET [[SESSION] | SERVER] NOQEP
**      SET [[SESSION] | SERVER] RET_INTO <storage_structure>
**
**      FIXME need to use semaphores to access global structures.
**
** Inputs:
**      opf_cb                          ptr to caller's control block
**
** Outputs:
**	Returns:
**	    E_DB_OK
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	30-jun-86 (seputis)
**          initial creation
[@history_line@]...
*/
DB_STATUS
ops_alter(
    OPF_CB             *opf_cb)
{
    DB_STATUS           status;			/* user return status */

    switch (opf_cb->opf_level)
    {
    case OPF_SERVER:
    {   /* change operating characteristics of the server */
        DB_STATUS	temp_status;
        /* get exclusive access before updating */
        status = ops_exlock(opf_cb,
                            &((OPS_CB *)(opf_cb->opf_scb))->ops_server->opg_semaphore);
        if (DB_FAILURE_MACRO(status))
            break;
        temp_status = ops_change( opf_cb,
                                  &((OPG_CB*)opf_cb->opf_server)->opg_alter);
        /* release exclusive access */
        status = ops_unlock(opf_cb,
                            &((OPS_CB *)(opf_cb->opf_scb))->ops_server->opg_semaphore);
        if (DB_SUCCESS_MACRO(status))
            status = temp_status;
        break;
    }
    case OPF_SESSION:
    {   /* change operating characteristics of this session */
        status = ops_change( opf_cb, &((OPS_CB *)(opf_cb->opf_scb))->ops_alter);
        break;
    }
    default:
# ifdef E_OP0089_ALTER
    {
        opx_rerror( opf_cb, E_OP0089_ALTER);
        return( E_DB_ERROR );
    }
#endif
    }
    return (status);
}
Beispiel #16
0
/*{
** Name: ops_qsfdestroy	- destroy a query plan
**
** Description:
**      Since the QP can be in several states, in order to destroy it
**	several error recovery paths may be needed. 
**
** Inputs:
**      global                          ptr to global state variable
**
** Outputs:
**	Returns:
**	    VOID
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**      13-apr-89 (seputis)
**          initial creation
[@history_template@]...
*/
static DB_STATUS
ops_qsfdestroy(
	OPS_STATE          *global)
{
    DB_STATUS	    qsfqpstatus;
    qsfqpstatus = qsf_call( QSO_DESTROY, &global->ops_qsfcb);
    if (DB_FAILURE_MACRO(qsfqpstatus))
    {
	/* attempt to get a lock on the object, since and error
	** may have occurred between the time the OPC released
	** the object and prior to returning to SCF */
	global->ops_qsfcb.qsf_lk_state = QSO_SHLOCK;
	qsfqpstatus = qsf_call( QSO_LOCK, &global->ops_qsfcb );
					/* ignore the error from
					** this routine since we
					** will attempt to delete the
					** object again anyway */

	qsfqpstatus = qsf_call( QSO_DESTROY, &global->ops_qsfcb);
    }
    return(qsfqpstatus);
}
Beispiel #17
0
/*{
** Name: psy_txtalloc	- Allocate a new text block
**
** Description:
**      This function allocates a new text block in a memory stream,
**	fills it in, and returns a pointer to it.
**
** Inputs:
**      mstream                         Pointer to memory stream
**	newblock			Place to put pointer to new block
**	err_blk				Filled in if error happens
**
** Outputs:
**      newblock                        Filled in with pointer to new block
**	err_blk				Filled in if an error happened
**	Returns:
**	    E_DB_OK			Success
**	    E_DB_ERROR			Failure
**	Exceptions:
**	    none
**
** Side Effects:
**	    Allocates memory
**
** History:
**      15-jul-86 (jeff)
**          written
*/
DB_STATUS
psy_txtalloc(
	PSF_MSTREAM        *mstream,
	PSY_QTEXT	   **newblock,
	DB_ERROR	   *err_blk)
{
    DB_STATUS           status;
    PSS_SESBLK	   	*sess_cb;

    sess_cb = psf_sesscb();

    /* Allocate the block */
    status = psf_malloc(sess_cb, mstream, sizeof(PSY_QTEXT), (PTR *) newblock, err_blk);
    if (DB_FAILURE_MACRO(status))
	return (status);

    /* Fill in the block */
    (*newblock)->psy_qnext = (PSY_QTEXT *) NULL;
    (*newblock)->psy_qcount = 0;

    return (E_DB_OK);
}
Beispiel #18
0
/*{
** Name: opu_memory	- get joinop memory
**
** Description:
**      This routine will allocate the requested size of memory from the 
**      joinop memory stream.  Memory in this stream is not deallocated 
**      until the optimization has completed.  The allocated memory will
**      be aligned for any datatype.
**
** Inputs:
**      global                          ptr to global state variable
**      size                            size of memory block requested.
**
** Outputs:
**	Returns:
**	    PTR to aligned memory of "size" bytes
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	16-jun-86 (seputis)
**          initial creation
**	4-mar-91 (seputis)
**	    make initialization of memory an xDEBUG feature
**	11-oct-2006 (hayke02)
**	    Send E_OP0002_NOMEMORY to errlog.log. This change fixes bug 116309.
**	5-oct-2007 (dougi)
**	    Accumulate memory acquisition stats.
*/
PTR
opu_memory(
	OPS_STATE          *global,
	i4                size)
{
    DB_STATUS      ulmstatus;		    /* return status from ULM */

    global->ops_mstate.ops_countalloc++;
    if (size >= 2048)
	global->ops_mstate.ops_count2kalloc++;
    global->ops_mstate.ops_totalloc += size;

    global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_streamid; /* allocate memory
					    ** from the global stream */
    global->ops_mstate.ops_ulmrcb.ulm_psize = size;    /* size of request */
    ulmstatus = ulm_palloc( &global->ops_mstate.ops_ulmrcb );
    if (DB_FAILURE_MACRO(ulmstatus))
    {
	if (global->ops_mstate.ops_ulmrcb.ulm_error.err_code == E_UL0005_NOMEM)
	{
	    opx_lerror(E_OP0002_NOMEMORY, 0, 0, 0, 0, 0);
	    opx_error( E_OP0002_NOMEMORY);  /* out of memory */
	}
#ifdef E_OP0093_ULM_ERROR
	else
	    opx_verror( ulmstatus, E_OP0093_ULM_ERROR, 
		global->ops_mstate.ops_ulmrcb.ulm_error.err_code); /* check for error */
#endif
    }	
#ifdef xDEBUG
    MEfill( size, (u_char)247, (PTR)global->ops_mstate.ops_ulmrcb.ulm_pptr); /*FIXME
                                            ** remove this initialization after
                                            ** test for uninitialized memory
                                            ** is not required any more */
#endif
    return( global->ops_mstate.ops_ulmrcb.ulm_pptr );  /* return the allocated
					    ** memory */
}
Beispiel #19
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 #20
0
/*
** Name: psq_destr_dbp_qep - destroy QSF object created for a dbproc
**
** Description:
**	If an error occurs in PSF in the course of parsing a dbproc definition
**	or recreating a dbproc QEP, we need to destroy the QEP object created 
** 	in PSF before exiting.  Otherwise, subsequent attempt to parse or 
**	recreate the dbproc will result in SC0206 because the QP object created
**	during the first (aborted) attempt will still be locked in QSF
**
** Input:
**	handle			QP object handle
**
** Output:
**	err_blk			filled in if an error occurs
**
** Side effects:
**
** History:
**	27-aug-93 (andre)
**	    extracted from psq_cbreturn() to enable psq_recreate() call it as 
**	    well
*/
DB_STATUS
psq_destr_dbp_qep(
		PSS_SESBLK	*sess_cb,
		PTR		handle,
		DB_ERROR	*err_blk)
{
    DB_STATUS	    status;
    PST_PROCEDURE   *pnode;
    QSF_RCB	    qsf_rb;
    i4	    err_code;

    /*
    ** first get the root of the query tree object - using it, we will 
    ** derive dbp QP object alias
    */
    
    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 = handle;

    status = qsf_call(QSO_INFO, &qsf_rb);

    if (DB_FAILURE_MACRO(status))
    {
        (VOID) psf_error(E_PS0A0A_CANTGETINFO, qsf_rb.qsf_error.err_code, 
	    PSF_INTERR, &err_code, err_blk, 0);
	return(status);
    }

    /* 
    ** We are interested in the proc node, because it holds the identifier for 
    ** the QP object we want to destroy.
    */
    pnode = (PST_PROCEDURE *) qsf_rb.qsf_root;

    /* 
    ** We can only proceed if root has been set - otherwise it is safe to 
    ** assume that the QP object has not been created - so we are done 
    */
    if (pnode == (PST_PROCEDURE *) NULL)
	return(E_DB_OK);

    qsf_rb.qsf_obj_id.qso_type = QSO_QP_OBJ;
    qsf_rb.qsf_obj_id.qso_lname = sizeof(DB_CURSOR_ID);
    (VOID) MEcopy((PTR) &pnode->pst_dbpid, sizeof(DB_CURSOR_ID),
        (PTR) qsf_rb.qsf_obj_id.qso_name);

    /* Lock it in shared mode before destroying. */
    qsf_rb.qsf_lk_state = QSO_SHLOCK;

    /* Get handle for the QP object to be destroyed */
    status = qsf_call(QSO_GETHANDLE, &qsf_rb);

    if (DB_FAILURE_MACRO(status))
    {
        /* 
	** looks like the error occurred before the dbproc QP object was 
	** created - we are done
	*/
        if (qsf_rb.qsf_error.err_code == E_QS0019_UNKNOWN_OBJ)
	    return(E_DB_OK);

        (VOID) psf_error(E_PS0A0B_CANTGETHNDLE, qsf_rb.qsf_error.err_code, 
	    PSF_INTERR, &err_code, err_blk, 0);
	return(status);
    }

    /* Now it is ready to be destroyed */
    status = qsf_call(QSO_DESTROY, &qsf_rb);

    if (DB_FAILURE_MACRO(status))
    {
        (VOID) psf_error(E_PS0A09_CANTDESTROY, qsf_rb.qsf_error.err_code, 
	    PSF_INTERR, &err_code, err_blk, 0);
	return(status);
    }

    return(E_DB_OK);
}
Beispiel #21
0
/*{
** Name: psy_subsvars	- Scan query tree and replace VAR nodes
**
** Description:
**	Scans a tree and finds all VAR nodes for this variable.
**	These nodes are looked up in the translation tree and
**	replaced by the value found there.  If this is for a
**	view, the corresponding node must exist in the translation
**	tree.  If not for a view, a 'zero' node (of a type appropriate based
**	on the context) is created and inserted, or, if for a "replace
**	cursor" command, a CURVAL node is substituted for the VAR
**	node.
**
**	This routine is one half of the guts of the whole view
**	algorithm.
**
**	VAR nodes are detached and replaced with the replacement
**	as defined by the view.  Note that there can never be any
**	problems here with update anomalies, since VAR nodes are
**	only used in retrieve contexts.
**
**	It does some extra processing with RESDOM nodes with
**	resno = 0.  These nodes specify a 'tid' domain, and are
**	included by the parser on REPLACE and DELETE commands
**	Subsvars will allow this construct iff the right hand pointer is a
**	VAR node with attno = 0.  In pre-Jupiter versions, this used
**	to update the variable number in these tid RESDOMs; in Jupiter,
**	however, it was changed to keep the same result variable number
**	throughout the qrymod process, so this should be unnecessary.
**	This is because the resvar is the variable number of the one and
**	only underlying base relation of the view on an update
**	(which is presumably the only case where this can come
**	up).  Psy_vrscan has already insured that there can only be
**	a single base relation in this case.
**
**	This whole messy thing is only done with view substitutions.
**	NOTE: THIS IS NOT TRUE!  IT IS ALSO DONE FOR INTEGRITY SUBSTITUTIONS!
**	I DON'T KNOW WHY THIS COMMENT IS HERE.
**
**	In order to fix the handling of aggregates over views, subsvars
**	calls psy_apql at the appropriate place to append a
**	view qualification (if any).  It is done here to handle nested
**	aggregates correctly since after psy_subsvars we no longer know
**	which nested aggregates actually contained the view variable.
**	The view qual will be appended if and only if the view var
**	appears explicitly within the immediate scope of a root node
**	(NOT in a nested aggregate.)
**
**	If at any scope we encounter a var node, we add the qualification
**	to that scope. Once a var node has been found in a scope (and
**	the qualifaction added), for example, a nested aggregate, the
**	qualification is not added to an outer scope unless a var node
**	in the view or integ has been found in that outer scope.
**
**  
** Inputs:
**	proot				Pointer to pointer to root of tree
**					to be updated
**	rngvar				view variable range table entry
**	transtree			Pointer to the target list of the
**					translation tree
**	vmode				PSQ_VIEW if called from view processor,
**					PSQ_APPEND is called from the integrity
**					processor with an APPEND command, else
**					something else.  Mostly, changes
**					handling of tid nodes, and forces an
**					error on a view if the VAR node in the
**					scanned tree does not exist in the
**					vtree.
**	vqual				View qualification to be appended,
**					if any.
**	resvar				Range table entry for result variable
**					in query being modified.
**	from_list			from_list from view getting added.
**	qmode				Query mode of user query.
**	cursid				Cursor id of current cursor, if any
**	result				Pointer to indicator for result.
**	dup_rb				Ptr to dup. request block
**	    pss_op_mask	    --		0
**	    pss_num_joins   --		PST_NOJOIN
**	    pss_tree_info   --		NULL
**	    pss_mstream	    --		ptr to memory stream to be used
**	    pss_err_blk	    --		ptr to error block
**
** Outputs:
**      proot                           User query tree can be updated
**      result                          Filled in with TRUE if view variable
**					was found, FALSE if not. Valid only
**					if E_DB_OK returned.
**	dup_rb
**	    pss_err_blk			Filled in if an error happens.
**	Returns:
**	    E_DB_OK			Success
**	    E_DB_ERROR			Failure
**	Exceptions:
**	    none
**
** Side Effects:
**	    Can allocate memory
**
** History:
**	19-jun-86 (jeff)
**          written
**	1-oct-86 (daved)
**	    set return to TRUE if a VAR node is found.
**	23-dec-86 (daved)
**	    copy qualification before appending it. this avoids graphs in
**	    the tree as well as, and more importantly, the re-use of the
**	    memory used by the qualification before its time. That is,
**	    if vqual is in temporary memory and gets deleted but the
**	    proot tree thinks the memory is still around, bad things happen.
**	12-aug-87 (stec)
**	    Removed test for special 'tid' attribute case, which, according
**	    to Jeff is no longer needed.
**	    Check for special 'tid' resdom now includes open cursor stmt.
**	15-oct-87 (stec)
**	    Added the removed test for special 'tid' attribute case;
**	    it's necessary for checking cases like "retrieve (viewname.tid)".
**	03-dec-87 (stec)
**	    Change psy_apql interface.
**	31-dec-87 (stec)
**	    Cleanup.
**	08-feb-88 (stec)
**	    Modify psy_subsvars to generate CURVAL nodes for replace cursor statement.
**	04-nov-88 (stec)
**	    Fix a view substitution bug. When visiting an AGHEAD node it may happen
**	    that count(*), or count(const) were defined, in which case there are
**	    no VAR nodes and the applicability of the view has to be determined from
**	    the relation bitmap in the node. This anomaly exists only in SQL.
**	14-dec-88 (stec)
**	    Fix correlated subqueries bug.
**	05-apr-89 (andre)
**	    simplify the test for when reference to the view in pst_tvrm is to
**	    be replaced with the tables used to define the view.  We no longer
**	    care if there were any variables found below the root node, instead,
**	    we do it for every root node which has a bit corresponding to the
**	    view set in pst_tvrm.
**	    As a part of the fix, qualification of the view will be appended to
**	    the tree whenever the view is found in the pst_tvrm of the root
**	    node.
**	    Besides allowing us to get rid of calling recursive psy_fixmap() in
**	    psy_view, but it also fixes bugs such as:
**	    "select const from view"  returning more rows than there are in the
**	    view.
**	04-may-89 (andre)
**	    for the time being, set pst_maks1 in all ROOT-type nodes to 0.
**	01-jun-89 (andre)
**	    The preceding fix was not perfect.
**	    "create view v as select * from t where <qual>;
**	     select <aggregate> from v\g"
**	     would result in as many rows containing result of applying
**	     <aggregate> as there are rows in v.  This happens only in SQL.  The
**	     problem is that <qual> gets appended to both AGGHEAD node and the
**	     ROOT node.  The solution is as follows:
**	         For every node N s.t. N is of type ROOT or SUBSELECT, remember
**		 if <qual> has been applied to an AGGHEAD node in the left
**		 subtree of N (in SQL you can not have AGGHEADs in the
**		 "where-clause").  If <qual> has been applied to AGGHEAD(s) in
**		 the left subtree of N, do not append it to the right subtree of
**		 N.
**	22-jun-89 (andre)
**	    And yet another fix for the previous bug fix.  I have incorrectly
**	    assumed that there may be no AGGHEADs in the right subtrre of
**	    ROOT/SUBSEL (select ... having agg(col)).  Before setting *mask to
**	    indicate that an AGGHEAD has been seen, make sure that we are in the
**	    left subtree of the immediate ROOT/SUBSEL parent
**	    (mask != (i4 *) NULL).  If mask is NULL, we must be in the right
**	    subtree, and the fact that we saw an AGGHEAD is of no importance
**	    (or shall I add "or so I believe"?)
**	13-sep-89 (andre)
**	    receive ptr to PSS_DUPRB which will point at memopry stream and
**	    error block + it will be used when calling pst_treedup().  The
**	    fields in dup_rb must be set as follows:
**	    pss_op_mask	    -- 0
**	    pss_num_joins   -- PST_NOJOIN
**	    pss_tree_info   -- NULL
**	    pss_mstream	    -- ptr to memory stream to be used
**	    pss_err_blk	    -- ptr to error block
**	14-sep-92 (andre)
**	    do not zero out pst_mask1 in PST_ROOT and PST_SUBSEL node
**	    (fix for bug 45238)
**	11-feb-93 (andre)
**	    if a query tree involved a reference to a TID attribute of a view V,
**	    replace it with a reference to TID attribute of V's underlying table
**	    or view; this is accomplished by replacing variable number found in
**	    the PST_VAR node with the variable number of the view's underlying
**	    table/view (which can be found by looking for the first set bit in
**	    from_list)
**	27-nov-02 (inkdo01)
**	    Range table expansion (i4 changed to PSAT_J_MASK).
**	13-Jun-2006 (kschendel)
**	    Barf if we translate a var node to a seqop default in an INSERT.
**	    This only happens if we're translating an integrity where-clause
**	    tree, and a var in that where-clause isn't mentioned in the
**	    values list, so we stick the default in instead.  Seqops aren't
**	    allowed in where clauses.  (It would imply that the insert
**	    integrity-permission depends on the sequence value, which is
**	    silly at best.)
**	15-May-2007 (kiria01) b111992
**	    Flatten out much of the recursion of this function to reduce
**	    runtime stack usage - especially bad with views containing
**	    massive IN clauses (>5K elements). 
**	28-nov-2007 (dougi)
**	    Add PSQ_REPDYN to PSQ_DEFCURS test for cached dynamic qs.
**	05-Nov-2009 (kiria01) b122841
**	    Use psl_mk_const_similar to cast default values directly.
**	12-Nov-2009 (kiria01) b122841
**	    Corrected psl_mk_const_similar parameters with explicit
**	    mstream.
**       5-Feb-2010 (hanal04) Bug 123209
**          psy_integ() calls psy_subsvars() to subsitute VARs in the
**          integrity tree with the corresponding nodes from the
**          user query. When a VAR is replaced with a CONST cast the
**          CONST to the VAR's datatype. This stops the substitution from
**          breaking ADE_COMPAREN & ADE_NCOMPAREN processing if the
**          VAR was part of an IN LIST. 
**	18-May-2010 (kiria01) b123442
**	    Force psl_mk_const_similar to generate coercion to cleanly 
**	    enable correct datatype to be represented when substituting
**	    default values.
*/
DB_STATUS
psy_subsvars(
	PSS_SESBLK	*cb,
	PST_QNODE	**proot,
	PSS_RNGTAB	*rngvar,
	PST_QNODE	*transtree,
	i4		vmode,
	PST_QNODE	*vqual,
	PSS_RNGTAB	*resvar,
	PST_J_MASK	*from_list,
	i4		qmode,
	DB_CURSOR_ID	*cursid,
	i4		*mask,
	PSS_DUPRB	*dup_rb)

{
    PSY_STK	stk = {0, 0, {0, }};/* Backtrack stack */
    PST_QNODE	*t;		/* Temporary for *proot */
    i4		vn = rngvar
		    ? rngvar->pss_rgno : -1; /* can be NULL on replace cursor statements */
    i4		err_code;
    DB_STATUS	status = E_DB_OK;

    while(proot && (t = *proot))
    {
	/* These 3 mask variables are only used for ROOT, SUBSEL and AGHEAD */
	i4 newmask;	/* For receiving result from recursive call */
	i4 *l_mask;	/* For propagating state to recursive caller */
	i4 *r_mask;	/*  .. */

	/*
	** The recursive nature of this function has been restructured to
	** allow for most of the processing to be achieved in an iterative
	** manner. Unlike with the other functions in this module, the
	** flattening could not be complete due to the 'mask' output parameter
	** which requires local storage for certain node types: ROOT, SUBSEL
	** and AGHEAD. If we have one of these node types we recurse 1 level
	** to process the left and right sub-trees with the correct scoping of
	** the 'mask' variable.
	*/
	switch (t->pst_sym.pst_type)
	{
	case PST_ROOT:
	    /* Handle any unions */
	    if (t->pst_sym.pst_value.pst_s_root.pst_union.pst_next)
	    {
		/*
		** Defer the tree representing the next subselect in the UNION
		** status = psy_subsvars(cb, 
		**    &t->pst_sym.pst_value.pst_s_root.pst_union.pst_next, rngvar, transtree,
		**    vmode, vqual, resvar, from_list, qmode, cursid, (i4 *) NULL,
		**    dup_rb);
		*/
		psy_push(&stk, (PTR)&t->pst_sym.pst_value.pst_s_root.pst_union.pst_next,
		      &status);
		if (DB_FAILURE_MACRO(status))
		{
		    proot = NULL; /* Exiting to return error */
		    break;
		}
	    }
	    /*FALLTHROUGH*/
	case PST_SUBSEL:
	    /*
	    ** The following applies when language is SQL:
	    **	    if this is a ROOT or a SUBSELECT node, we want to know if the left
	    **	    subtree contains AGGHEAD nodes to which view qualification have been
	    **	    applied; we are not concerned with AGGHEAD nodes in the
	    **	    qualification (there shouldn't be any, anyway) or in other members
	    **	    of the union.
	    */

	    if (cb->pss_lang == DB_SQL)
	    {
		newmask = 0;
		l_mask = &newmask;

		/* we don't care about the right subtree */
		r_mask = (i4 *) NULL;	
	    }
	    /*FALLTHROUGH*/
	case PST_AGHEAD:
	    /*
	    ** The following applies when language is SQL:
	    **	    If this is an AGGHEAD node, set a bit in 'mask' to remember that
	    **	    we saw it.
	    */
	    if (t->pst_sym.pst_type == PST_AGHEAD)
	    {
		if (cb->pss_lang == DB_SQL)
		{
		    if (l_mask = r_mask = mask)
			/*
			** If we are in the right subtree of the immediate ROOT/SUBSELECT
			** parent, mask will be NULL, since we are not concerned with
			** AGHEADs in the right subtrees.
			*/
			*mask |= PSS_1SAW_AGG;
		}
		/*
		** pst_mask1 in PST_AGHEAD node is neither used nor set; I think it
		** would be a good idea to set it, but at this point there is not a heck
		** of a lot that we can do.  Here we will zero out PST_AGHEAD.pst_mask1
		** purely for esthetic reasons.
		*/
		t->pst_sym.pst_value.pst_s_root.pst_mask1 = 0;
	    }

	    /*
	    ** Recurse 1 level to process the left & right subtrees completly
	    ** so that we can complete the processing of this node
	    */
	    status = psy_subsvars(cb, &t->pst_left, rngvar, transtree, vmode, 
		vqual, resvar, from_list, qmode, cursid, l_mask, dup_rb);
	    if (DB_FAILURE_MACRO(status))
	    {
		proot = NULL; /* Exiting to return error */
		break;
	    }

	    /* Process the right branch */
	    status = psy_subsvars(cb, &t->pst_right, rngvar, transtree, vmode, 
		vqual, resvar, from_list, qmode, cursid, r_mask, dup_rb);
	    if (DB_FAILURE_MACRO(status))
	    {
		proot = NULL; /* Exiting to return error */
		break;
	    }

	    /* Add `from' list to bitmap, remove entry for replaced var */
	    if (BTtest(vn, (char*)&t->pst_sym.pst_value.pst_s_root.pst_tvrm))
	    {
		BTclear(vn, (char*)&t->pst_sym.pst_value.pst_s_root.pst_tvrm);
		BTor(PST_NUMVARS, (char *)from_list, 
			(char *)&t->pst_sym.pst_value.pst_s_root.pst_tvrm);
		t->pst_sym.pst_value.pst_s_root.pst_tvrc = 
		    BTcount((char*)&t->pst_sym.pst_value.pst_s_root.pst_tvrm,
			    BITS_IN(t->pst_sym.pst_value.pst_s_root.pst_tvrm));

		/*
		** We will append qualification (if there is one) if the
		** following holds:
		** 1) This is not an SQL (must be QUEL) query    OR
		** 2) if node is ROOT or SUBSEL (i.e. not an AGHEAD) then there
		**    were no AGHEADs found in its left subtree
		**
		**  Let QUAL <==> there is a qualification,
		**      SQL  <==> language is SQL
		**	ROOT <==> node type is ROOT
		**	SUBSEL <==> node type is SUBSEL
		**	AGG    <==> node type is AGHEAD
		**	SAW_AGG <==> mask & PSS_1SAW_AGG.  Then
		**	
		** (Do not apply qualification) <==>
		**  !QUAL + SQL * (ROOT + SUBSEL) * SAW_AGG -->
		**  (Apply qualification) <==>
		**  !(!QUAL + SQL * (ROOT + SUBSEL) * SAW_AGG) <==>
		**  QUAL * !(SQL * (ROOT + SUBSEL) * SAW_AGG)  <==>
		**  QUAL * (!SQL + !((ROOT + SUBSEL) * SAW_AGG)) <==>
		**  QUAL * (!SQL + !(ROOT + SUBSEL) + !SAW_AGG)  <==>
		**  QUAL * (!SQL + AGG + !SAW_AGG)
		*/
		if (vqual &&
		    (cb->pss_lang != DB_SQL	||
		    t->pst_sym.pst_type == PST_AGHEAD ||
		     (*l_mask & PSS_1SAW_AGG) == 0))
		{
		    PST_QNODE *vqual_copy;
		    dup_rb->pss_tree = vqual;
		    dup_rb->pss_dup  = &vqual_copy;
		    status = pst_treedup(cb, dup_rb);
		    dup_rb->pss_tree = (PST_QNODE *)NULL;
		    dup_rb->pss_dup  = (PST_QNODE **)NULL;
        		    
		    if (DB_FAILURE_MACRO(status))
		    {
			proot = NULL; /* Exiting to return error */
			break;
		    }
		    /* append view qualification */
		    status = psy_apql(cb, dup_rb->pss_mstream, vqual_copy, t,
				      dup_rb->pss_err_blk);
		    if (DB_FAILURE_MACRO(status))
		    {
			proot = NULL; /* Exiting to return error */
			break;
		    }
		}
	    }
	    /* left & right have been processed */
	    break;

	case PST_VAR:
	    /*
	    ** This is a terminal node - the expectation is that left & right are 0
	    */
            
	    /*
	    ** Check for a VAR node but of a different variable than the one
	    ** we are substituting for. REPLACE CURSOR (quel version) is an
	    ** exception because the substitution variable (resvar) is not
	    ** defined, in that case we do not want to execute the code
	    ** below, but want to continue the translation process.
	    */
	    if (vn != -1 && t->pst_sym.pst_value.pst_s_var.pst_vno != vn)
		break;
	    /*
	    ** if this is a reference to a TID attribute of a view (which is not
	    ** a "real" attribute), it needs to be translated into a reference
	    ** to the TID attribute of the view's underlying table or view
	    */
	    if (t->pst_sym.pst_value.pst_s_var.pst_atno.db_att_id == 0 &&
		vmode == PSQ_VIEW)
	    {
		t->pst_sym.pst_value.pst_s_var.pst_vno =
		    BTnext(-1, (char *) from_list, sizeof(*from_list));
	    }
	    else
	    {
		PST_QNODE *v;

		/* find var in vtree */
		status = psy_vfind((u_i2)t->pst_sym.pst_value.pst_s_var.pst_atno.db_att_id, 
		    transtree, &v, dup_rb->pss_err_blk);
		if (DB_FAILURE_MACRO(status))
		{
		    proot = NULL; /* Exiting to return error */
		    break;
		}

		if (v == (PST_QNODE *)NULL)
		{
		    /* attribute not defined in view */
		    if (vmode == PSQ_VIEW)
		    {
			psf_error(E_PS0D03_ATT_NOT_FOUND, 0L, PSF_INTERR, &err_code,
			    dup_rb->pss_err_blk, 0);
			status = E_DB_SEVERE;
			proot = NULL; /* Exiting to return error */
			break;
		    }
		    /* append defaults for integrity. Integrity might exist on a value
		    ** we are appending by default. I.e., the attribute was not mentioned
		    ** in the target list. We replace the var node in the integrity with
		    ** a default value so that the integrity will read 'default value' ?
		    ** value.
		    */
		    else if (vmode == PSQ_APPEND)
		    {
			status = psl_make_default_node(cb, dup_rb->pss_mstream, resvar,
						       t->pst_sym.pst_value
							     .pst_s_var.pst_atno.db_att_id,
						       &v, dup_rb->pss_err_blk);
			if (DB_FAILURE_MACRO(status))
			{
			    proot = NULL; /* Exiting to return error */
			    break;
			}
			/* Try to cast to column type */
			status = psl_mk_const_similar(cb, dup_rb->pss_mstream,
						&t->pst_sym.pst_dataval,
						&v, dup_rb->pss_err_blk, NULL);
			if (DB_FAILURE_MACRO(status))
			    return(status);

			/* If we ended up with a sequence default, fail. This is an
			** unreasonable situation, integrity where tests should not apply
			** to sequence defaults.
			*/
			if (v->pst_sym.pst_type == PST_SEQOP)
			{
			    psf_error(6319, 0, PSF_USERERR, &err_code,
				    dup_rb->pss_err_blk, 0);
			    status = E_DB_ERROR;
			    proot = NULL; /* Exiting to return error */
			    break;
			}
		    }
		    /* we would like to delete the qualification for this node since the
		    ** value is not changing and thus we don't need to worry about integrity
		    ** constaints on it. However, we don't do that. Instead we have the
		    ** integrity refer to the value in the current row that reflects the
		    ** value for the attribute. In the replace statement (not replace
		    ** cursor) we just perform the retrieve, the qualification is unneeded
		    ** but doesn't hurt anything. We want to avoid causing a retrieve for
		    ** each update cursor; therefore, we change the varnode to refer to the
		    ** current value (ie the retrieve has already been done).
		    */
		    else if (vmode == PSQ_REPCURS)
		    {
			PST_CRVAL_NODE curval;
			/* Create a CURVAL node for the corresponding column */
			curval.pst_curcol.db_att_id =
			    t->pst_sym.pst_value.pst_s_var.pst_atno.db_att_id;
			STRUCT_ASSIGN_MACRO(*cursid, curval.pst_cursor);
			status = pst_node(cb, dup_rb->pss_mstream, (PST_QNODE *)NULL,
				(PST_QNODE *)NULL, PST_CURVAL, (PTR)&curval, sizeof(curval),
				t->pst_sym.pst_dataval.db_datatype,
				t->pst_sym.pst_dataval.db_prec,
				t->pst_sym.pst_dataval.db_length,
				(DB_ANYTYPE *)t->pst_sym.pst_dataval.db_data, &v,
				dup_rb->pss_err_blk, (i4) 0);
			if (DB_FAILURE_MACRO(status))
			{
			    proot = NULL; /* Exiting to return error */
			    break;
			}
		    }
		}
		else
		{
		    dup_rb->pss_tree = v;
		    dup_rb->pss_dup  = &v;
		    status = pst_treedup(cb, dup_rb);
		    dup_rb->pss_tree = (PST_QNODE *)NULL;
		    dup_rb->pss_dup  = (PST_QNODE **)NULL;
                	
		    if (DB_FAILURE_MACRO(status))
		    {
			proot = NULL; /* Exiting to return error */
			break;
		    }

                    /* When called from psy_integ() v will be found but
                    ** may still need constants to be cast.
                    */
                    if ((v != (PST_QNODE *)NULL) &&
                        (v->pst_sym.pst_type == PST_CONST))
                    {
			bool handled;

                        /* Try to cast to column type */
                        status = psl_mk_const_similar(cb, dup_rb->pss_mstream,
                                                &t->pst_sym.pst_dataval,
                                                &v, dup_rb->pss_err_blk, 
                                                &handled);
                        if (DB_FAILURE_MACRO(status))
                            return(status);
                    }
		}

		/* replace VAR node */
		if (v != (PST_QNODE *)NULL)
		{
		    *proot = v;
		}
	    }
	    /* left and right should have been null as we are on a terminal */
	    break;

	case PST_RESDOM:
	    /* Process `TID' resdom used by DELETE, REPLACE and OPEN CURSOR */
	    if (t->pst_sym.pst_value.pst_s_rsdm.pst_rsno == 0 &&
		(qmode == PSQ_DELETE || qmode == PSQ_REPLACE || 
			qmode == PSQ_DEFCURS || qmode == PSQ_REPDYN))
	    {
		/*
		** If resvar not specified, or if not resvar, ignore leaf.
		*/
		if (resvar && vn == resvar->pss_rgno)
		{
		    /* t->right better be VAR node, attno 0 */
		    t = t->pst_right;
		    if (t->pst_sym.pst_type != PST_VAR ||
			t->pst_sym.pst_value.pst_s_var.pst_atno.db_att_id != 0 ||
			t->pst_sym.pst_value.pst_s_var.pst_vno != vn)
		    {			
			(VOID) psf_error(E_PS0D02_BAD_TID_NODE, 0L, PSF_INTERR, &err_code,
			    dup_rb->pss_err_blk, 0);
			status = E_DB_SEVERE;
			proot = NULL; /* Exiting to return error */
			break;
		    }
		}
		else if (t->pst_right)
		    /* Process the right branch */
		    psy_push(&stk, (PTR)&t->pst_right, &status);
	    }
	    else if (t->pst_right)
		/* Process the right branch */
		psy_push(&stk, (PTR)&t->pst_right, &status);

	    if (DB_FAILURE_MACRO(status))
	    {
		proot = NULL; /* Exiting to return error */
		break;
	    }
	    /* Process left branch */
	    if (t->pst_left)
		psy_push(&stk, (PTR)&t->pst_left, &status);
	    if (DB_FAILURE_MACRO(status))
	    {
		proot = NULL; /* Exiting to return error */
		break;
	    }
	    break;

	default:
	    /*
	    ** Just ensure that we traverse the tree
	    */
	    if (t->pst_right)
		psy_push(&stk, (PTR)&t->pst_right, &status);
	    if (DB_FAILURE_MACRO(status))
	    {
		proot = NULL; /* Exiting to return error */
		break;
	    }

	    if (t->pst_left)
		psy_push(&stk, (PTR)&t->pst_left, &status);
	    if (DB_FAILURE_MACRO(status))
	    {
		proot = NULL; /* Exiting to return error */
		break;
	    }
	    break;
	}
	if (!proot)    /* We're breaking out early to exit */
	    break;

	/*
	** Get next deferred node
	*/
	proot = (PST_QNODE**)psy_pop(&stk);
    }

    /* Release any outstanding entries */
    psy_pop_all(&stk);

    return status;
}
Beispiel #22
0
ADF_CB *
FEadfcb ()
{
    if (!done)
    {
	char		*cp;
	DB_STATUS	rval;
	PTR		srv_cb_ptr;
	SIZE_TYPE	srv_size;
	SIZE_TYPE	dbinfo_size;
	PTR		dbinfoptr;
        STATUS          tmtz_status;
        STATUS          date_status;
	char		date_type_alias[100];
        char            col[] = "udefault";
    	STATUS          status = OK;
    	CL_ERR_DESC     sys_err;
	ADUUCETAB	*ucode_ctbl; /* unicode collation information */
        PTR         	ucode_cvtbl;


	
    	done = TRUE;

	/* first, get the size of the ADF's server control block */
	srv_size = adg_srv_size();

	/* allocate enough memory for it */
	if ((srv_cb_ptr = MEreqmem(0, srv_size, FALSE, (STATUS *)NULL)) == NULL)
	{
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(alloc)"));
	}

	/*
	**  Fix up code so that "now" works properly for frontends.
	**  Only allocating enough for one (1) dbmsinfo() request.
	*/
	dbinfo_size = sizeof(ADF_TAB_DBMSINFO);
	if ((dbinfoptr = MEreqmem(0, dbinfo_size, TRUE, (STATUS*)NULL)) == NULL)
	{
		IIUGbmaBadMemoryAllocation(ERx("FEadfcb"));
	}

	dbinfo = (ADF_TAB_DBMSINFO *) dbinfoptr;

	dbinfo->tdbi_next = NULL;
	dbinfo->tdbi_prev = NULL;
	dbinfo->tdbi_length = dbinfo_size;
	dbinfo->tdbi_type = ADTDBI_TYPE;
	dbinfo->tdbi_s_reserved = -1;
	dbinfo->tdbi_l_reserved = (PTR)-1;
	dbinfo->tdbi_owner = (PTR)-1;
	dbinfo->tdbi_ascii_id = ADTDBI_ASCII_ID;
	dbinfo->tdbi_numreqs = 1;

	/*
	**  Now define request.
	*/
	dbinfo->tdbi_reqs[0].dbi_func = IIUGnfNowFunc;
	dbinfo->tdbi_reqs[0].dbi_num_inputs = 0;
	dbinfo->tdbi_reqs[0].dbi_lenspec.adi_lncompute = ADI_FIXED;
	STcopy("_BINTIM", dbinfo->tdbi_reqs[0].dbi_reqname);
	dbinfo->tdbi_reqs[0].dbi_reqcode = 1;
	dbinfo->tdbi_reqs[0].dbi_lenspec.adi_fixedsize = 4;
	dbinfo->tdbi_reqs[0].dbi_dtr = DB_INT_TYPE;

	/*
	** set timezone in ADF cb  - Any errors must be reported
        ** after adg_init() called.
	*/

	if ( (tmtz_status = TMtz_init(&cb.adf_tzcb)) == OK)
        {
	   tmtz_status = TMtz_year_cutoff(&cb.adf_year_cutoff);
        }

	/* Always use INGRESDATE by default, and check 
	** 'ii.<node>.config.date_alias' (kibro01) b118702
	*/
	cb.adf_date_type_alias = AD_DATE_TYPE_ALIAS_INGRES;
	STprintf(date_type_alias,ERx("ii.%s.config.date_alias"),PMhost());
	date_status = PMget(date_type_alias, &cp);
	if (date_status == OK && cp != NULL && STlength(cp))
	{
	    if (STbcompare(cp, 0, ERx("ansidate"), 0, 1) == 0)
		cb.adf_date_type_alias = AD_DATE_TYPE_ALIAS_ANSI;
	    else if (STbcompare(cp, 0, ERx("ingresdate"), 0, 1) == 0)
		cb.adf_date_type_alias = AD_DATE_TYPE_ALIAS_INGRES;
	    else
		cb.adf_date_type_alias = AD_DATE_TYPE_ALIAS_NONE;
	}

	/* set timezone table to NULL in ADF cb, adg_init() will fill it */
	/* cb.adf_tz_table = NULL; - not needed, done in declaration above */

	/* Start up ADF */
    	rval = adg_startup(srv_cb_ptr, srv_size, dbinfo, 0);
	if (DB_FAILURE_MACRO(rval))
	{
	    /*
	    ** Before bailing out, try to be helpful. Since the environment
	    ** is likely not set up correctly, write hard coded messages
	    ** since error message fetch will likely fail in this situation.
	    */
	    char	*tempchar;
	    i4		dummy;
	    LOCATION	temploc;
	    NMgtAt("II_SYSTEM", &tempchar);
	    if (tempchar && *tempchar)
	    {
		LOfroms(PATH, tempchar, &temploc);
		if (LOexist(&temploc))
		{
		    tempchar = ERx("FEadfcb: II_SYSTEM DOES NOT EXIST\n");
		    SIwrite(STlength(tempchar), tempchar, &dummy, stderr);
		}
		else
		{
		    NMloc(ADMIN, FILENAME, ERx("config.dat"), &temploc);
		    if (LOexist(&temploc))
		    {
			tempchar = ERx("FEadfcb: II_SYSTEM IS NOT SET CORRECTLY\n");
			SIwrite(STlength(tempchar), tempchar, &dummy, stderr);
		    }
		}
	    }
	    else
	    {
		tempchar = ERx("FEadfcb: II_SYSTEM IS NOT SET\n");
		SIwrite(STlength(tempchar), tempchar, &dummy, stderr);
	    }
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(start)"));
	}

	/* put the pointer to ADF's server control block in the ADF_CB */
	cb.adf_srv_cb = srv_cb_ptr;

	/* set up the error message buffer */
    	cb.adf_errcb.ad_ebuflen = DB_ERR_SIZE;
    	cb.adf_errcb.ad_errmsgp = ebuffer;

	/* initialize the ADF_CB */
    	rval = adg_init(&cb);
	if (DB_FAILURE_MACRO(rval))
	{
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(init)"));
	}

	/* find out which natural language we should speak */
	cb.adf_slang = iiuglcd_langcode();

	/* Always QUEL; for SQL explictly change this with 'IIAFdsDmlSet()'. */
	cb.adf_qlang = DB_QUEL;

	/* lets get the multinational info */

	/* 
	** Defaults for all of these are initially set statically, above.
	*/
	NMgtAt(ERx("II_DATE_FORMAT"), &cp);
    	if ( cp != NULL && *cp != EOS )
    	{
	    FEapply_date_format(&cb,cp);
    	}

	NMgtAt(ERx("II_MONEY_FORMAT"), &cp);
    	if ( cp != NULL && *cp != EOS )
    	{
	    FEapply_money_format(&cb,cp);
    	}

	NMgtAt(ERx("II_MONEY_PREC"), &cp);
    	if ( cp != NULL && *cp != EOS )
    	{
	    FEapply_money_prec(&cb,cp);
    	}

	NMgtAt(ERx("II_DECIMAL"), &cp);
    	if ( cp != NULL && *cp != EOS )
    	{
	    FEapply_decimal(&cb,cp);
    	}

	NMgtAt(ERx("II_UNICODE_SUBS"), &cp);
	if ( !cp )
	{
	    cb.adf_unisub_status = AD_UNISUB_OFF;
	}
	else
	{
	    /* As with SET unicode_substitution take the first char */
	    cb.adf_unisub_status = AD_UNISUB_ON;
	    *cb.adf_unisub_char = cp[0];
	}

	NMgtAt(ERx("II_NULL_STRING"), &cp);
	if ( cp != NULL && *cp != EOS )
	{
	    FEapply_null(&cb,cp);
	}

	/* If there was a Timezone error other than the expected ingbuild
	** error TM_PMFILE_OPNERR, then lets report it now. */

        if (tmtz_status && (tmtz_status != TM_PMFILE_OPNERR))
        {
	    LOCATION    loc_root;
	    STATUS status = OK;
	    status = NMloc(FILES, PATH, ERx("zoneinfo"), &loc_root);
#if defined(conf_BUILD_ARCH_32_64) && defined(BUILD_ARCH64)
            status = LOfaddpath(&loc_root, ERx("lp64"), &loc_root);
#endif
#if defined(conf_BUILD_ARCH_64_32) && defined(BUILD_ARCH32)
    {
        /*
        ** Reverse hybrid support must be available in ALL
        ** 32bit binaries
        */
        char    *rhbsup;
        NMgtAt("II_LP32_ENABLED", &rhbsup);
        if ( (rhbsup && *rhbsup) &&
       ( !(STbcompare(rhbsup, 0, "ON", 0, TRUE)) ||
         !(STbcompare(rhbsup, 0, "TRUE", 0, TRUE))))
            status = LOfaddpath(&loc_root, "lp32", &loc_root);
    }
#endif /* ! LP64 */

            if ( status == OK )
            {
		status = LOexist(&loc_root);
            }
            if ( status == OK )
	    {
                   IIUGerr(tmtz_status, 0, 0);

                   /* As this may disappear from the screen quickly,
                   ** let's pause to allow the users to reflect on the
                   ** fact that the timezone info is (probably) wrong.
                   */
                   if (!IIugefa_err_function) PCsleep(5000);
	    }
        }

	/* Initialize unicode collation for UTF8 installations */
	if (CMischarset_utf8())
	{
          if (status = aduucolinit(col, MEreqmem, 
			&ucode_ctbl, &ucode_cvtbl, &sys_err))
          {
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(alloc)"));
          }

          cb.adf_ucollation = (PTR) ucode_ctbl;

	  /* Set unicode normalization to NFC just in case 
	  ** Front end will need it.
	  */
          if ((status = adg_setnfc(&cb)) != E_DB_OK)
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(alloc)"));
	}
	/* lets not do this again! */
    }

    return &cb;
}
Beispiel #23
0
DB_STATUS qee_d8_undefrpt(
    QEF_RCB	    *qef_rcb,
    PTR	    i_qso_handle)
{
    DB_STATUS
    status = E_DB_OK,
    sav_status = E_DB_OK;
    DB_ERROR
    sav_err;
    i4	    err;
    GLOBALREF QEF_S_CB *Qef_s_cb;
    QEE_DSH	    *dsh_p   = (QEE_DSH *)NULL;
    QEF_QP_CB	    *qp;
    bool	    have_qp = FALSE;
    QSF_RCB	    qsf_rcb;
    ULM_RCB	    ulm;
    ULH_RCB	    ulh_rcb;

    struct
    {
        PTR	qso_handle;
        CS_SID	session_id;
    } ulh_name;



    /* 1.  acquire the QP using the handle */


    qsf_rcb.qsf_next = (QSF_RCB *)NULL;
    qsf_rcb.qsf_prev = (QSF_RCB *)NULL;
    qsf_rcb.qsf_length = sizeof(QSF_RCB);
    qsf_rcb.qsf_type = QSFRB_CB;
    qsf_rcb.qsf_owner = (PTR)DB_QEF_ID;
    qsf_rcb.qsf_ascii_id = QSFRB_ASCII_ID;
    qsf_rcb.qsf_sid = qef_rcb->qef_cb->qef_ses_id;
    ulh_rcb.ulh_hashid = Qef_s_cb->qef_ulhid;

    qsf_rcb.qsf_obj_id.qso_handle = i_qso_handle;

    qsf_rcb.qsf_lk_state = QSO_SHLOCK;
    status = qsf_call(QSO_LOCK, &qsf_rcb);
    if (status)
    {
        qef_rcb->error.err_code = E_QE0019_NON_INTERNAL_FAILURE;
        return(status);
    }

    have_qp = TRUE;
    qp = (QEF_QP_CB *) qsf_rcb.qsf_root;

    /* For sharable QP, sometimes the QP may have been destroyed by
    ** another session.  So check for a NULL root.  If so, release the
    ** lock and return. */

    if (qp == (QEF_QP_CB *) NULL)
    {
        qsf_call(QSO_UNLOCK, &qsf_rcb);
        return(E_DB_OK);
    }

    /* 2.  gotten the QP, acquire the DSH in ULH's cache */

    STRUCT_ASSIGN_MACRO(Qef_s_cb->qef_d_ulmcb, ulm);

    ulh_name.qso_handle = qsf_rcb.qsf_obj_id.qso_handle;
    ulh_name.session_id = qef_rcb->qef_cb->qef_ses_id;

    status = ulh_getmember(&ulh_rcb, (unsigned char *) &qp->qp_id,
                           (i4)sizeof(DB_CURSOR_ID),  (unsigned char *) & ulh_name,
                           (i4)sizeof(ulh_name), ULH_DESTROYABLE, 0);

    if (DB_FAILURE_MACRO(status))
    {
        qef_error(ulh_rcb.ulh_error.err_code, 0L, status, & err,
                  &qef_rcb->error, 0);
        qef_rcb->error.err_code = E_QE0102_CATALOG_DSH_OBJECT;
    }
    else
    {
        dsh_p = (QEE_DSH *)(ulh_rcb.ulh_object->ulh_uptr);
        ulm.ulm_streamid_p = &ulh_rcb.ulh_object->ulh_streamid;

        if (dsh_p != (QEE_DSH *)NULL)
        {
            /* 3.  reset the defined state of the REPEAT QUERY in the DSH */

            dsh_p->dsh_ddb_cb->qee_d3_status &= ~QEE_03Q_DEF;

            /* 4.  must release the acquired DSH */

            ulh_rcb.ulh_object = (ULH_OBJECT *)dsh_p->dsh_handle;
        }
        status = ulh_release(& ulh_rcb);
        if (status != E_DB_OK)
        {
            qef_error(ulh_rcb.ulh_error.err_code, 0L, status, & err,
                      &qef_rcb->error, 0);
            qef_rcb->error.err_code = E_QE0104_RELEASE_DSH_OBJECT;
        }

        /* must fall thru to release the QP */
    }

    /* 5.  release the QP */

    if (have_qp)
    {
        qsf_call(QSO_UNLOCK, & qsf_rcb);
    }
    if (status == E_DB_OK && sav_status)
    {
        status = sav_status;
        STRUCT_ASSIGN_MACRO(sav_err, qef_rcb->error);
    }
    return(status);
}
Beispiel #24
0
/*{
** Name: psy_dbpriv - GRANT/REVOKE database privileges
**
**  INTERNAL PSF call format: status = psy_dbpriv(&psy_cb, sess_cb);
**  EXTERNAL     call format: status = psy_call (PSY_DBPRIV,&psy_cb, sess_cb);
**
** Description:
**	This procedure is sued to grant and revoke database privileges.
**	A template iidbpriv tuple is built and shipped to RDF.
**	Eventually, the tuple is added/merged into iidbpriv.
**	This procedure is called for SQL language only.
**
** Inputs:
**      psy_cb
**	    .psy_usrq			list of grantees
**	    .psy_tblq			list of objects
**	    .psy_gtype			grantee type
**	    .psy_grant			statement type (GRANT or REVOKE)
**	    .psy_fl_dbpriv		control flags
**	    .psy_qdio_limit		query I/O  limit
**	    .psy_qrow_limit		query row  limit
**	    .psy_qcpu_limit		query CPU  limit
**	    .psy_qpage_limit		query page limit
**	    .psy_qcost_limit		query cost limit
**	    .psy_idle_limit		idle time  limit
**	    .psy_connect_limit		connect time  limit
**	    .psy_priority_limit		priority   limit
**	sess_cb				Pointer to session control block
**					(Can be NULL)
**
** Outputs:
**      psy_cb
**	    .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_SEVERE			Function failed; catastrophic error
**	Exceptions:
**	    none
**
** Side Effects:
**	    None.
**
** History:
**	10-apr-89 (ralph)
**          written
**	06-jun-89 (ralph)
**	    corrected unix portability problems
**	24-jun-89 (ralph)
**	    corrected internal error message
**	06-sep-89 (ralph)
**	    added support for GRANT/REVOKE ON ALL DATABASES
**	    removed DBGR_DEFAULT
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
**	19-jul-92 (andre)
**	    changes were made to enable a user to specify privileges to PUBLIC
**	    along with one or more user authorization identifiers
**	10-aug-93 (andre)
**	    fixed cause of a compiler warning
*/
DB_STATUS
psy_dbpriv(
	PSY_CB             *psy_cb,
	PSS_SESBLK	   *sess_cb)
{
    DB_STATUS		status = E_DB_OK;
    DB_STATUS		stat;
    i4		err_code;
    RDF_CB		rdf_cb;
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    DB_PRIVILEGES	dbprtuple;
    register DB_PRIVILEGES *dbprtup = &dbprtuple;
    PSY_USR		*psy_usr;
    PSY_TBL		*psy_tbl;
    bool		grant_to_public;
    bool		leave_loop = TRUE;
    
    /* This code is called for SQL only */

    do
    {
	/* Fill in the RDF request block */

	pst_rdfcb_init(&rdf_cb, sess_cb);
	if (psy_cb->psy_grant == PSY_DGRANT)
	    rdf_rb->rdr_update_op   = RDR_APPEND;
	else if (psy_cb->psy_grant == PSY_DREVOKE)
	    rdf_rb->rdr_update_op   = RDR_DELETE;
	else
	{
	    /* Invalid operation specified in psy_grant */
	    err_code = E_PS0D45_INVALID_GRANT_OP;
	    (VOID) psf_error(E_PS0D45_INVALID_GRANT_OP, 0L,
			     PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	    status   = E_DB_ERROR;
	    break;
	}
	rdf_rb->rdr_status	    = DB_SQL;
	rdf_rb->rdr_types_mask  = RDR_DBPRIV;
	rdf_rb->rdr_qrytuple    = (PTR) dbprtup;
	rdf_rb->rdr_qtuple_count = 1;

	/* Initialize the template iidbpriv tuple */

	dbprtup->dbpr_gtype	  = psy_cb->psy_gtype;
	dbprtup->dbpr_control	  = psy_cb->psy_ctl_dbpriv;
	dbprtup->dbpr_dbflags	  = 0;
	dbprtup->dbpr_flags	  = psy_cb->psy_fl_dbpriv;
	dbprtup->dbpr_qrow_limit  = psy_cb->psy_qrow_limit;
	dbprtup->dbpr_qdio_limit  = psy_cb->psy_qdio_limit;
	dbprtup->dbpr_qcpu_limit  = psy_cb->psy_qcpu_limit;
	dbprtup->dbpr_qpage_limit = psy_cb->psy_qpage_limit;
	dbprtup->dbpr_qcost_limit = psy_cb->psy_qcost_limit;
	dbprtup->dbpr_connect_time_limit = psy_cb->psy_connect_limit;
	dbprtup->dbpr_idle_time_limit    = psy_cb->psy_idle_limit;
	dbprtup->dbpr_priority_limit     = psy_cb->psy_priority_limit;

	MEfill(sizeof(dbprtup->dbpr_database), (u_char) ' ',
	    (PTR) &dbprtup->dbpr_database);

	MEfill(sizeof(dbprtup->dbpr_reserve), (u_char) ' ',
	    (PTR) dbprtup->dbpr_reserve);

	/* Point to first database object, if any */

	psy_tbl = (PSY_TBL *)psy_cb->psy_tblq.q_next;

	/* No database objects means GRANT/REVOKE ON ALL DATABASES */

	if (psy_tbl == (PSY_TBL *) &psy_cb->psy_tblq)
	    dbprtup->dbpr_dbflags |= DBPR_ALLDBS;

	/*
	** Pass the template tuples to RDF for each database/grantee.
	** RDF/QEF will return E_DB_INFO if a database/grantee is rejected,
	** or E_DB_WARN is a database is rejected.  Anything worse than
	** E_DB_WARN is a fatal error.
	*/

	/* Process each database/grantee */
	for (;;)
	{
	    /*
	    ** Copy in database name if one was provided.
	    ** None will be provided if ON ALL DATABASES was specified.
	    */
	    if (psy_tbl != (PSY_TBL *) &psy_cb->psy_tblq)
		MEcopy((PTR)&psy_tbl->psy_tabnm,
		       sizeof(dbprtup->dbpr_database),
		       (PTR)&dbprtup->dbpr_database);

	    grant_to_public = (psy_cb->psy_flags & PSY_PUBLIC) != 0;
	    psy_usr = (PSY_USR *)  psy_cb->psy_usrq.q_next;

	    do
	    {
		if (grant_to_public)
		{
		    /*
		    ** user specified TO/FROM PUBLIC, possibly along with other
		    ** user auth ids; we will process TO/FROM PUBLIC first
		    */
		    dbprtup->dbpr_gtype = DBGR_PUBLIC;
		    
		    MEmove(sizeof("public") - 1, (PTR) "public", ' ',
			sizeof(dbprtup->dbpr_gname),
			(PTR) &dbprtup->dbpr_gname);
		}
		else
		{
		    STRUCT_ASSIGN_MACRO(psy_usr->psy_usrnm,
			dbprtup->dbpr_gname);
		}
		
		stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);
		status = (stat > status) ? stat : status;
		if (stat > E_DB_INFO)
		    break;

		if (grant_to_public)
		{
		    dbprtup->dbpr_gtype = psy_cb->psy_gtype;

		    /*
		    ** remember that we have processed GRANT TO PUBLIC on this
		    ** database or on the installation
		    */
		    grant_to_public = FALSE;
		}
		else
		{
		    psy_usr = (PSY_USR *) psy_usr->queue.q_next;
		}

	    } while (psy_usr != (PSY_USR *) &psy_cb->psy_usrq);

	    /* Break out if failure */
	    if (DB_FAILURE_MACRO(status))
		break;

	    /* Point to next database object */
	    psy_tbl = (PSY_TBL *)  psy_tbl->queue.q_next;

	    /* Break out if no more objects */
	    if (psy_tbl == (PSY_TBL *) &psy_cb->psy_tblq)
		break;
	}

	/* We are done */

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

    if (DB_FAILURE_MACRO(status))
	(VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, 
			     &psy_cb->psy_error);

    return    (status);
}
Beispiel #25
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 #26
0
/*{
** Name: psy_integ	- Apply integrity constraints
**
** Description:
**      This function applies integrity constraints.  It gets the constraints
**	from RDF and puts them in the query where appropriate.
**
** Inputs:
**      mstream                         QSF memory stream to allocate from
**	root				Root of query tree to constrain
**	rngtab				Pointer to the range table
**	resvar				Pointer to the result range variable
**	qmode				Query mode of user's query
**	sess_cb				session control block
**	result				Place to put pointer to constrained tree
**	err_blk				Filled in if an error happens
**
** Outputs:
**      root                            Integrity constraints may be appended
**	result				Filled in with pointer to constrained
**					tree
**	err_blk				Filled in if an error happened
**	Returns:
**	    E_DB_OK			Success
**	    E_DB_ERROR			Failure
**	Exceptions:
**	    none
**
** Side Effects:
**	    Allocates memory
**
** History:
**	19-jun-86 (jeff)
**          Adapted from integrity.c in 4.0.
**      02-sep-86 (seputis)
**          changes for new RDF interface
**          fixed bug for no integrity case
**	04-dec-86 (daved)
**	    process define and replace cursor. Use copy of saved qual for
**	    replace cursor.
**	03-dec-87 (stec)
**	    Change psy_apql interface.
**	11-may-88 (stec)
**	    Make changes for db procs.
**	06-feb-89 (ralph)
**	    Modified to use DB_COL_WORDS*2 as extent of dset array
**	23-Feb-89 (andre)
**	    Changed the way the tree consisting of qualifications obtained from
**	    the integrity trees is constructed and merged with the
**	    qualifications found in the original tree.
**	18-may-89 (neil)
**	    Use session memory for cursors with integrities (bug fix).
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
**	04-sep-90 (andre)
**	    fixed bug 32976: for OPEN CURSOR (qmode==PSQ_DEFCURS) we need to
**			     compare attribute number(s) found in the integrity
**			     tuple with attribute number found in the VAR
**			     node(s) found in the portion of the target list
**			     which was built to represent the FOR UPDATE list
**			     (such node(s) are right children of RESDOM nodes
**			     with pst_rsupdt set to TRUE; note that for
**			     RESDOM nodes built to represent the real target
**			     list of SELECT, this field is set to FALSE.)
**	29-sep-92 (andre)
**	    RDF may choose to allocate a new info block and return its address
**	    in rdf_info_blk - we need to copy it over to pss_rdrinfo to avoid
**	    memory leak and other assorted unpleasantries
**	05-dec-92 (rblumer)
**	    ignore FIPS constraints during INGRES integrity processing
**	10-jan-93 (andre)
**	    after calling rdf_call() for IIINTEGRITY tuples, compare status to
**	    E_DB_OK instead of using DB_FAILURE_MACRO() since if there are fewer
**	    than 20 rows, rdf_call() sets err_code to E_RD0011 and status to
**	    E_DB_WARN
**	10-Feb-93 (Teresa)
**	    Changed RDF_GETINFO to RDF_READTUPLES for new RDF I/F
**	23-May-1997 (shero03)
**	    Save the rdr_info_blk after an UNFIX
**	22-Jul-2004 (schka24)
**	    Delete old ifdef'ed out normalization call
**	28-nov-2007 (dougi)
**	    Add PSQ_REPDYN to PSQ_DEFCURS test (cached dynamic).
*/
DB_STATUS
psy_integ(
	PSF_MSTREAM	*mstream,
	PST_QNODE	*root,
	PSS_USRRANGE	*rngtab,
	PSS_RNGTAB	*resvar,
	i4		qmode,
	PSS_SESBLK	*sess_cb,
	PST_QNODE	**result,
	DB_ERROR	*err_blk)
{
    register PST_QNODE	*r;
    PSC_CURBLK		*curblk = sess_cb->pss_crsr;
    CS_SID		sessid  = sess_cb->pss_sessid;
    PTR			db_id   = sess_cb->pss_dbid;
    i2			dset[DB_COL_WORDS*2];
    i2			doms;
    i2			*domset;
    bool		subset;
    PST_QNODE		*p;
    register i4	i;
    PST_QNODE		*iqual;
    PST_QNODE		**tmp1;
    DB_INTEGRITY	*inttup;
    i4		err_code;
    PST_QTREE		*qtree;
    PST_PROCEDURE	*pnode;
    DB_STATUS		status = E_DB_OK;
    i4			found;
    RDF_CB		rdf_cb;
    QEF_DATA		*qp;
    RDF_CB		rdf_tree_cb;
    PSS_DUPRB		dup_rb;
    i4			tupcount;
    i4			map[PST_NUMVARS];   /* Map for reassigning varnos */

    r = root;

    /* Initialize fields in dup_rb */
    dup_rb.pss_op_mask = 0;
    dup_rb.pss_num_joins = PST_NOJOIN;
    dup_rb.pss_tree_info = (i4 *) NULL;
    dup_rb.pss_mstream = mstream;
    dup_rb.pss_err_blk = err_blk;

    if (qmode == PSQ_REPCURS)
    {
	if (!curblk->psc_integ)
	{
	    *result = r;
	    return (E_DB_OK);
	}
	/*
	** On a replace cursor, get the query tree that was stored in the
	** cursor control block.
	*/
	/* copy the qual fragment so we can change below. */
	dup_rb.pss_tree = curblk->psc_integ;
	dup_rb.pss_dup  = &iqual;
	status = pst_treedup(sess_cb, &dup_rb);
	
	if (DB_FAILURE_MACRO(status))
	{
	    return (status);
	}
    }
    else
    {
	/*
	**  Check to see if we should apply the integrity
	**  algorithm.
	**
	**  This means checking to insure that we have an update
	**  and seeing if any integrity constraints apply.
	*/
	if 
	(
	    resvar == 0 || 
	    (resvar->pss_tabdesc->tbl_status_mask & DMT_INTEGRITIES) == 0
	)
	{
	    *result = r;
	    return (E_DB_OK);
	}
	/*
	**  Create a set of the domains updated in this query.
	*/

	for (i = 0; i < DB_COL_WORDS*2; i++)
	    dset[i] = 0;

	for (p = r->pst_left, doms = 0;
	    p != (PST_QNODE *) NULL && p->pst_sym.pst_type != PST_TREE;
	    p = p->pst_left)
	{
	    if (p->pst_sym.pst_type != PST_RESDOM)
	    {
		psf_error(E_PS0D0C_NOT_RESDOM, 0L, PSF_INTERR, &err_code,
		    err_blk, 0);
		return (E_DB_SEVERE);
	    }

	    /*
	    ** if we are defining a cursor, RESDOM numbers are meaningless as
	    ** at best they reflect position of an attribute in the target list
	    ** of a subselect or, at worst, they are set to 1 for all columns
	    ** mentioned in the FOR UPDATE LIST.  We really are interested only
	    ** in the VAR nodes which are children of RESDOM nodes built to
	    ** repersent columns appearing in the FOR UPDATE list, so we will
	    ** skip over RESDOM nodes which represent a true subselect
	    ** (i.e. pst_rsupdt == FALSE)
	    */
	    if (qmode == PSQ_DEFCURS)
	    {
		if (p->pst_sym.pst_value.pst_s_rsdm.pst_rsupdt)
		{
		    PST_QNODE	    *r_child = p->pst_right;

		    /*
		    ** this RESDOM was built to represent the column in the FOR
		    ** UPDATE list
		    */

		    /*
		    ** make sure the right child is a VAR node; otherwise flag
		    ** an error
		    */
		    if (r_child == (PST_QNODE *) NULL ||
		        r_child->pst_sym.pst_type != PST_VAR)
		    {
			psf_error(E_PS0C04_BAD_TREE, 0L, PSF_INTERR, &err_code,
			    err_blk, 0);
			return (E_DB_SEVERE);
		    }
		    
		    BTset((i4) r_child->
				 pst_sym.pst_value.pst_s_var.pst_atno.db_att_id,
			  (char *) dset);
		    ++doms;
		}
	    }
	    else
	    {
		BTset((i4) p->pst_sym.pst_value.pst_s_rsdm.pst_rsno,
		    (char *) dset);
		++doms;
	    }
	}

	/*
	** Note if we are appending a subset of the relation's domains.
	** If we are, we'll need to be extra careful to avoid violating
	** constraints on those attributes not being explicitly appended:
	*/
	subset = ((doms < resvar->pss_tabdesc->tbl_attr_count)
	    && (qmode == PSQ_APPEND));

	
	/*
	**  Scan integrity catalog for possible tuples.  If found,
	**  include them in the integrity qualification.
	*/

	iqual = (PST_QNODE *) NULL;

        /* Set up constant part of rdf query tree control block */
	pst_rdfcb_init(&rdf_tree_cb, sess_cb);
        STRUCT_ASSIGN_MACRO(resvar->pss_tabid, rdf_tree_cb.rdf_rb.rdr_tabid);
        rdf_tree_cb.rdf_rb.rdr_types_mask = RDR_INTEGRITIES | RDR_QTREE;
	rdf_tree_cb.rdf_rb.rdr_qtuple_count = 1;  
		/* Get 1 integ tree at a time */
	rdf_tree_cb.rdf_info_blk = resvar->pss_rdrinfo;

	/* Get all integrity tuples */
	pst_rdfcb_init(&rdf_cb, sess_cb);
	STRUCT_ASSIGN_MACRO(resvar->pss_tabid, rdf_cb.rdf_rb.rdr_tabid);
	rdf_cb.rdf_rb.rdr_types_mask = RDR_INTEGRITIES;
	rdf_cb.rdf_rb.rdr_update_op = RDR_OPEN;
	rdf_cb.rdf_rb.rdr_rec_access_id = NULL;
	rdf_cb.rdf_rb.rdr_qtuple_count = 20;  /* Get 20 integrities at a time */
	rdf_cb.rdf_info_blk = resvar->pss_rdrinfo;
	/* For each group of 20 integrities */
	while (rdf_cb.rdf_error.err_code == 0)
	{
	  status = rdf_call(RDF_READTUPLES, (PTR) &rdf_cb);

	  /*
          ** RDF may choose to allocate a new info block and return its address
	  ** in rdf_info_blk - we need to copy it over to pss_rdrinfo to avoid
	  ** memory leak and other assorted unpleasantries
          */
	  if (rdf_cb.rdf_info_blk != resvar->pss_rdrinfo)
	  {
	    resvar->pss_rdrinfo =
		rdf_tree_cb.rdf_info_blk = rdf_cb.rdf_info_blk;
	  }
	  
	  /*
	  ** Must not use DB_FAILURE_MACRO because E_RD0011 returns E_DB_WARN
	  ** that would be missed.
	  */
	  if (status != E_DB_OK)
	  {
	    if (   rdf_cb.rdf_error.err_code == E_RD0011_NO_MORE_ROWS
		|| rdf_cb.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND)
	    {
		status = E_DB_OK;
		if (rdf_cb.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND)
		    continue;
	    }
	    else if (rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL)
	    {
		(VOID) psf_error(2117L, 0L, PSF_USERERR,
		    &err_code, err_blk, 1,
		    psf_trmwhite(sizeof(DB_TAB_NAME), 
			(char *) &resvar->pss_tabname),
		    &resvar->pss_tabname);
		status = E_DB_ERROR;
		goto exit;
	    }
	    else
	    {
		(VOID) psf_rdf_error(RDF_READTUPLES, &rdf_cb.rdf_error, err_blk);
		goto exit;
	    }
	  }

	  rdf_cb.rdf_rb.rdr_update_op = RDR_GETNEXT;
    
	  /* FOR EACH INTEGRITY */
	  for 
	  (
	    qp = rdf_cb.rdf_info_blk->rdr_ituples->qrym_data,
	    tupcount = 0;
	    tupcount < rdf_cb.rdf_info_blk->rdr_ituples->qrym_cnt;
	    qp = qp->dt_next,
	    tupcount++
	  )
	  {
	    inttup = (DB_INTEGRITY*) qp->dt_data;

	    /*
	    ** Ignore FIPS constraints (i.e. SQL92 constraints)
	    ** (they are implemented via rules instead)
	    */
	    if (inttup->dbi_consflags != 0)
	    {
		continue;
	    }

	    /* check for some domain set overlap */

	    domset = (i2*) inttup->dbi_columns.db_domset;

	    for (i = 0; i < DB_COL_WORDS*2; i++)
	    {
		if ((dset[i] & domset[i]) != 0)
		    break;
	    }

	    /*
	    ** Check for appends where defaults don't satisfy integrity.
	    */

	    if ((i >= DB_COL_WORDS*2) && !subset)
	    {
		continue;
	    }

	    /* Get integrity tree and make qtree point to it */
	STRUCT_ASSIGN_MACRO(inttup->dbi_tree, rdf_tree_cb.rdf_rb.rdr_tree_id);
	    rdf_tree_cb.rdf_rb.rdr_qrymod_id = inttup->dbi_number;
	    rdf_tree_cb.rdf_rb.rdr_update_op = 0;
	    rdf_tree_cb.rdf_rb.rdr_rec_access_id = NULL;
	    rdf_tree_cb.rdf_info_blk = resvar->pss_rdrinfo;
	    rdf_tree_cb.rdf_rb.rdr_integrity = NULL;
	    STRUCT_ASSIGN_MACRO(inttup->dbi_tabid,
				rdf_tree_cb.rdf_rb.rdr_tabid);
	    rdf_tree_cb.rdf_rb.rdr_sequence = inttup->dbi_number;

	    status = rdf_call(RDF_GETINFO, (PTR) &rdf_tree_cb);
	    /*
	    ** RDF may choose to allocate a new info block and return its
	    ** address in rdf_info_blk - we need to copy it over to pss_rdrinfo
	    ** to avoid memory leak and other assorted unpleasantries
	    */
	    if (rdf_tree_cb.rdf_info_blk != resvar->pss_rdrinfo)
	    {
		resvar->pss_rdrinfo =
		    rdf_cb.rdf_info_blk = rdf_tree_cb.rdf_info_blk;
	    }

	    if (DB_FAILURE_MACRO(status))
	    {
		if (rdf_tree_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(DB_TAB_NAME), 
			    (char *) &resvar->pss_tabname),
			&resvar->pss_tabname);
		}
		else
		{
		    (VOID) psf_rdf_error(RDF_GETINFO, &rdf_tree_cb.rdf_error,
			err_blk);
		}
		goto exit;
	    }
	    pnode   = 
	    (PST_PROCEDURE *) rdf_tree_cb.rdf_rb.rdr_integrity->qry_root_node;
	    qtree = pnode->pst_stmts->pst_specific.pst_tree;
		
	    /* trim off (null) target list */
	    p = qtree->pst_qtree->pst_right;
	    /* use a copy of the qtree because the qtree is in RDF memory */
	    dup_rb.pss_tree = qtree->pst_qtree->pst_right;
	    dup_rb.pss_dup  = &p;
	    status = pst_treedup(sess_cb, &dup_rb);

	    {	/* unfix the query tree no matter what the above status is */
		DB_STATUS	temp_status;

		temp_status = rdf_call(RDF_UNFIX, (PTR) &rdf_tree_cb);
	        resvar->pss_rdrinfo = 
			rdf_cb.rdf_info_blk = rdf_tree_cb.rdf_info_blk;
		if (DB_FAILURE_MACRO(temp_status))
		{
		    (VOID) psf_rdf_error(RDF_UNFIX, &rdf_tree_cb.rdf_error,
			err_blk);
		    status = temp_status;
		}
	    }
	    if (DB_FAILURE_MACRO(status))
		goto exit;		/* close integrity file */

	    /*
	    ** Make the result variable for the integrity the same as the result
	    ** variable for the user query.  
	    ** I AM NOT SURE THE FOLLOWING COMMENT APPLIES SO I AM MERGING
	    ** THE RANGE VAR FOR APPENDS.
	    ** This is not done for append because
	    ** append doesn't have a result range variable.
	    */
	    for (i = 0; i < PST_NUMVARS; i++)
		map[i] = i;
	    i = inttup->dbi_resvar;

	    map[i] = resvar->pss_rgno;
	    status = psy_mapvars(p, map, err_blk);
	    if (DB_FAILURE_MACRO(status))
		goto exit;

	    /* add to integrity qual */

	    if (iqual == NULL)
	    {
		status = pst_node(sess_cb, mstream, p, (PST_QNODE *) NULL,
		    PST_AND, (PTR) NULL, sizeof(PST_OP_NODE), DB_NODT, (i2) 0,
		    (i4) 0, (DB_ANYTYPE *) NULL, &iqual, err_blk, (i4) 0);

		if (DB_FAILURE_MACRO(status))
		    goto exit;		/* close integrity file */

		/*
		** Note that tmp1 will contain address of the pst_right ptr
		** of the bottom AND node in the tree constructed from the
		** qualifications found in the integrities
		*/

		tmp1 = &iqual->pst_right;
	    }
	    else
	    {
		PST_QNODE	*newnode;
		
		status = pst_node(sess_cb, mstream, p, iqual, PST_AND,
		    (PTR) NULL, sizeof(PST_OP_NODE), DB_NODT, (i2) 0, (i4) 0,
		    (DB_ANYTYPE *) NULL, &newnode, err_blk, (i4) 0);

		if (DB_FAILURE_MACRO(status))
		    goto exit;		/* close integrity file */

		iqual = newnode;
	    }
	  }
	}
	if (rdf_cb.rdf_rb.rdr_rec_access_id != NULL)
	{
	    DB_STATUS	temp_status;
	    /* unfix integrity tuples */
	    rdf_cb.rdf_rb.rdr_update_op = RDR_CLOSE;
	    temp_status = rdf_call(RDF_READTUPLES, (PTR) &rdf_cb);
	    resvar->pss_rdrinfo =
		rdf_tree_cb.rdf_info_blk = rdf_cb.rdf_info_blk;
	    if (DB_FAILURE_MACRO(temp_status))
	    {
		(VOID) psf_rdf_error(RDF_READTUPLES, &rdf_cb.rdf_error, err_blk);
		status = temp_status;
	    }
	}
    }

    if (qmode == PSQ_DEFCURS || qmode == PSQ_REPDYN)
    {
        /*
        ** On a "define cursor", keep a copy of the integrity qualification
        ** for later use.
        */
        if (iqual == NULL)
        {
	    curblk->psc_integ = (PST_QNODE *) NULL;
        }
        else
        {
	    status = pst_trdup(curblk->psc_stream, iqual,
		&curblk->psc_integ, &sess_cb->pss_memleft, err_blk);
	    if (DB_FAILURE_MACRO(status))
	    {
		return (status);
	    }
	}
    }
    else
    {   
	/*
	**  Clean up the integrity qualification so that it will merge
	**  nicely into the tree, and then append it to the user's
	**  qualification.
	*/

	if (iqual != NULL)
	{
	    /* replace VAR nodes by corresponding user afcn from user's
	    ** query. For example, if the integ says r.a > 1 and the user's
	    ** query says resdom 4 = 4 + 3, the integ is modified to 4 + 3 > 1.
	    **
	    ** The following paragraph refers to the case where an integrity
	    ** refers to a variable not updated in the target list.
	    **
	    ** If there is no resdom for r.a, if the user didn't specify r.a
	    ** in the target list of the query, and the query is an append,
	    ** r.a > 1 is replaced with 'default val for col a' > 1. If the
	    ** query is a replace statement, we do nothing because r.a will
	    ** be retrieved but is not in the targ list. We will be verifying
	    ** what we know should already hold (ie the integrity constraint).
	    ** If we have replace cursor, we wan't to replace r.a with a value
	    ** so a retrieve can be avoided on the replace command. We can't
	    ** have col a = 5 where r.a > 1. We do, however, have the value r.a
	    ** in the row to be updated. QEF has this value. We replace r.a with
	    ** a curval node that refers to the value r.a.
	    */

	    /* will pass dup_rb, but first null out pss_tree and pss_dup */
	    dup_rb.pss_tree = (PST_QNODE *) NULL;
	    dup_rb.pss_dup  = (PST_QNODE **) NULL;
	    
	    status = psy_subsvars(sess_cb, &iqual, resvar, r->pst_left, qmode,
		(PST_QNODE *) NULL, resvar, (i4) 0, qmode,
		&curblk->psc_blkid, &found, &dup_rb);

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

	    /*
	    ** for REPLACE CURSOR, we need to traverse down the pst_right's
	    ** until we encounter NULL in place of which we will append the
	    ** qualification from the ROOT
	    ** Note that iqual is guaranteed to be an AND node with BOP for a
	    ** left child and either AND or NULL for the right child.
	    */

	    if (qmode == PSQ_REPCURS)
	    {
		for (tmp1 = &iqual->pst_right; (*tmp1) != (PST_QNODE *) NULL;
		     tmp1 = &(*tmp1)->pst_right)
		;
	    }
	    
	    /*
	    ** append qualification from the tree to the integrities and
	    ** make the result the new qualification for the tree
	    */
	    (*tmp1) = r->pst_right;
	    r->pst_right = iqual; 
	}
    }

exit:
    if ((qmode != PSQ_REPCURS)
	&&
	(rdf_cb.rdf_rb.rdr_rec_access_id != NULL))
    {
	DB_STATUS	temp_status;
	/* unfix integrity tuples */
	rdf_cb.rdf_rb.rdr_update_op = RDR_CLOSE;
	temp_status = rdf_call(RDF_READTUPLES, (PTR) &rdf_cb);
	resvar->pss_rdrinfo =
	    rdf_tree_cb.rdf_info_blk = rdf_cb.rdf_info_blk;
	if (DB_FAILURE_MACRO(temp_status))
	{
	    (VOID) psf_rdf_error(RDF_READTUPLES, &rdf_cb.rdf_error, err_blk);
	    status = temp_status;
	}
    }
    if (status == E_DB_OK)
    {
	*result = r;
    }
    return (status);
}
Beispiel #27
0
/*{
** Name: psy_kinteg	- Destroy one or more integrities for a table.
**
**  INTERNAL PSF call format: status = psy_kinteg(&psy_cb, sess_cb);
**
**  EXTERNAL call format:     status = psy_call(PSY_KINTEG, &psy_cb, sess_cb);
**
** Description:
**      The psy_kinteg function removes the definitions of one or more
**	integrities on a table from the system relations (integrities,
**	tree, and iiqrytext).
**	Optionally, one can tell this function to destroy all of the
**	integrities on the given table.
**
** Inputs:
**      psy_cb
**          .psy_tables[0]              Id of table from which to remove
**					integrities
**          .psy_numbs[]                Array of integrity id numbers telling
**					which integrities to destroy (at most
**					20)
**          .psy_numnms                 Number telling how many integrity
**					numbers there are.  Zero means to
**					destroy all of the integrities
**					on the given table.
**	    .psy_tabname[0]		Name of table from which to remove
**					integrities
**	sess_cb				Pointer to session control block
**					(Can be NULL)
**
** Outputs:
**      psy_cb
**	    .psy_error			Filled in if an error happens
**		.err_code		    What the error was
**		    E_PS0000_OK			Success
**		    E_PS0001_USER_ERROR		User made a mistake
**		    E_PS0002_INTERNAL_ERROR	Internal inconsistency in PSF
**	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:
**	    Removes query tree(s) representing predicates of integrities from
**	    tree relation, text of defining query (or queries) from iiqrytext
**	    relation, rows defining integrity (or integrities) from integrities
**	    relation.  If there are no more integrities on this table, will
**	    use DMF alter table function to indicate this.
**
** History:
**	02-oct-85 (jeff)
**          written
**	30-aug-88 (andre)
**	    check if the user specified integrity 0 to be deleted,
**	    and if so, warn that it doesn't exist (this will prevent someone
**	    from inadvertently deleting all integrities by specifying that
**	    integrity 0 be deleted.)
**	30-aug-88 (andre)
**	    When looking at individual integrities, return E_DB_ERROR if any
**	    errors were found when processing individual integrities.
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
**	03-aug-1992 (barbara)
**	    Call pst_rdfcb_init to initialize RDF_CB before calling RDF.
**	    Invalidate infoblk from RDF cache after dropping integrity.
**	07-aug-92 (teresa)
**	    RDF_INVALID must be called for the base object that the
**	    integrity was defined on as well as for the integrity trees.
**	14-sep-92 (barbara)
**	    Set type field and tableid in the RDF cb used to invalidate
**	    the cached entries.
**	14-jul-93 (ed)
**	    replacing <dbms.h> by <gl.h> <sl.h> <iicommon.h> <dbdbms.h>
**	10-aug-93 (andre)
**	    removed declaration of rdf_call()
**	30-sep-93 (stephenb)
**	    Pass tablename from psy_cb to rdf_rb, so that we can use the
**	    information to audit in QEF.
*/
DB_STATUS
psy_kinteg(
    PSY_CB             *psy_cb,
    PSS_SESBLK	   *sess_cb)
{
    RDF_CB              rdf_cb;
    RDF_CB              rdf_inv_cb; 	/* For invalidation */
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    DB_STATUS		status = E_DB_OK;
    i4		err_code;
    register i4	i;

    /* Fill in RDF control block */
    pst_rdfcb_init(&rdf_cb, sess_cb);
    pst_rdfcb_init(&rdf_inv_cb, sess_cb);
    STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[0], rdf_rb->rdr_tabid);
    STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[0], rdf_inv_cb.rdf_rb.rdr_tabid);
    rdf_rb->rdr_types_mask = RDR_INTEGRITIES;
    rdf_inv_cb.rdf_rb.rdr_types_mask = RDR_INTEGRITIES;
    rdf_rb->rdr_update_op = RDR_DELETE;
    rdf_rb->rdr_name.rdr_tabname = psy_cb->psy_tabname[0];

    /* No integrity numbers means destroy all integrities. */
    if (psy_cb->psy_numnms == 0)
    {
        /* Zero integrity number means destroy all integs. */
        rdf_rb->rdr_qrymod_id = 0;
        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, &psy_cb->psy_error, 1,
                                 psf_trmwhite(sizeof(psy_cb->psy_tabname[0]),
                                              (char *) &psy_cb->psy_tabname[0]),
                                 &psy_cb->psy_tabname[0]);
            }
            else
            {
                (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error,
                                     &psy_cb->psy_error);
            }
            return (status);
        }

        /* Invalidate table info from RDF cache */

        /* first invalidate the object from the relation cache */
        status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb);
        if (DB_FAILURE_MACRO(status))
            (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error,
                                 &psy_cb->psy_error);

        /* now invalidate any integrity trees from the cache */
        rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_CLASS;
        status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb);
        if (DB_FAILURE_MACRO(status))
            (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error,
                                 &psy_cb->psy_error);
    }
    else
    {
        DB_STATUS   stat;

        /* Run through the integrity numbers, destroying each one */
        for (i = 0; i < psy_cb->psy_numnms; i++)
        {

            /* if user specified 0, complain and proceed with next integrity # */
            if ((rdf_rb->rdr_qrymod_id = psy_cb->psy_numbs[i]) == 0)
            {
                /* remember error to report later */
                status = (status > E_DB_ERROR) ? status : E_DB_ERROR;

                (VOID) psf_error(5203, 0L, PSF_USERERR, &err_code,
                                 &psy_cb->psy_error, 1,
                                 sizeof (rdf_rb->rdr_qrymod_id),
                                 &rdf_rb->rdr_qrymod_id);
                continue;
            }

            stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);

            /* remember the highest status seen so far */
            status = (status > stat) ? status : stat;

            if (DB_FAILURE_MACRO(stat))
            {
                switch (rdf_cb.rdf_error.err_code)
                {
                case E_RD0002_UNKNOWN_TBL:
                    (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR,
                                     &err_code, &psy_cb->psy_error, 1,
                                     psf_trmwhite(sizeof(psy_cb->psy_tabname[0]),
                                                  (char *) &psy_cb->psy_tabname[0]),
                                     &psy_cb->psy_tabname[0]);
                    break;

                case E_RD0013_NO_TUPLE_FOUND:
                    (VOID) psf_error(5203, 0L, PSF_USERERR,
                                     &err_code, &psy_cb->psy_error, 1,
                                     sizeof (rdf_rb->rdr_qrymod_id),
                                     &rdf_rb->rdr_qrymod_id);
                    continue;

                default:
                    (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error,
                                         &psy_cb->psy_error);
                }

                return (status);
            }

            /* invalidate the integrity tree from the cache. */
            rdf_inv_cb.rdf_rb.rdr_sequence = psy_cb->psy_numbs[i];
            rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_ALIAS;
            status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb);
            if (DB_FAILURE_MACRO(status))
            {
                (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error,
                                     &psy_cb->psy_error);
                break;
            }
        }
        /* now invalidate the integrity base object from the relation cache */
        if (DB_SUCCESS_MACRO(status))
        {
            rdf_inv_cb.rdf_rb.rdr_sequence = 0;
            rdf_inv_cb.rdf_rb.rdr_2types_mask &= ~RDR2_ALIAS;
            status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb);
            if (DB_FAILURE_MACRO(status))
            {
                (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error,
                                     &psy_cb->psy_error);
            }
        }
    }

    return    (status);
}
Beispiel #28
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 #29
0
/*
** {
** Name: adu_redeem	- Redeem an ADF_COUPON
**
** Description:
**      This routine redeems an ADF_COUPON, i.e. it materializes the object
**	represented by the coupon.  Since objects represented by coupons
**	may not fit in memory, this routine must deal with returning partial
**	results.  In such cases, it will store its partial status in its fourth
**	argument, which is to be returned for each call. 
**
** Inputs:
**      adf_scb                  Standard ADF session control block
**      result_dv                Ptr to DB_DATA_VALUE into which to
**                               place the result.
**      coupon_dv                Ptr to DB_DATA_VALUE which contains
**                               the input to redeem.
**      workspace_dv             Ptr to DB_DATA_VALUE which points to
**                               the workspace.  This workspace is
**                               expected to be maintained across
**                               calls to this routine for any given
**                               coupon.  (I.e. it can be "new" only
**                               when "continuation" (next param) is
**                               zero.
**      continuation             Is this a continuation of a previous
**                               call.
**
** Outputs:
**      adf_scb->adf_errcb       Filled as appropriate.
**      result_dv->db_length     Filled with the length of the result
**                               area actually used.
**      *workspace->db_data      Filled with info to be used by
**                               subsequent invocations of this routine.
**	Returns:
**          E_DB_ERROR           In case of error
**          E_DB_INFO/E_AD0002_INCOMPLETE
**                               When more calls are necessary
**          E_DB_OK              When complete.
**
**	Exceptions:
**	    None.
**
** Side Effects:
**	    None.
**
** History:
**      07-dec-1989 (fred)
**          Prototyped.
**      06-oct-1992 (fred)
**          Altered to work with timezone integration.  As a temporary measure,
**	    this routine was using the ADF_CB.adf_4rsvd field to store
**	    some context across calls.  In that this field disappeared, a new,
**	    more appropriately named field was added (adf_lo_context).  This
**	    new ADF_CB field is now used in this file.
**	30-Oct-1992 (fred)
**	    Fixed to correctly handle being called with a length too short
**	    for the original header.
**	20-Nov-1992 (fred)
**	    Rewritten for better clarity & better delineation of
**	    function in support of OME large objects.
**      18-Oct-1993 (fred)
**          Moved check for FEXI function so that STAR, which has
**          none, can send null blobs sometimes.  It helps get a tiny
**          bit of support in to STAR.
**      13-Apr-1994 (fred)
**          Altered to hand status from FEXI call straight back.  By
**          not losing the actual status, interrupts may avoid logging
**          too much stuff.
**      14-Sep-1995 (shust01/thaju02)
**          fixed problem of endless loop when we are finished, but we
**	    come in just to get the NULL byte.  work->adw_shared.shd_o_used 
**	    had old size (which was max value), so we never end.  Set
**	    work->adw_shared.shd_o_used = 0.
**	24-Oct-2001 (thaju02)
**	    If adc_lvch_xform() was unable to fit the 2-byte segment
**	    length in the result buffer, decrement result length
**	    with unused byte and flush segment. (B104122)
[@history_template@]...
*/
DB_STATUS
adu_redeem(
ADF_CB            *adf_scb,
DB_DATA_VALUE	   *result_dv,
DB_DATA_VALUE      *coupon_dv,
DB_DATA_VALUE      *workspace_dv,
i4            continuation)
{
    ADP_LO_WKSP 	*work = (ADP_LO_WKSP *) workspace_dv->db_data;
    DB_DT_ID		dtid;
    ADP_PERIPHERAL	*p = (ADP_PERIPHERAL *) result_dv->db_data;
    DB_STATUS		status;
    i4			done = FALSE;
    i4                  flush;
    i4			for_gca = 1;
    i4                  loop_around;

    if (result_dv->db_datatype != coupon_dv->db_datatype)
	return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
	
    dtid = ADI_DT_MAP_MACRO(abs(result_dv->db_datatype));
    if (    dtid <= 0
	 || dtid  > ADI_MXDTS
	 || Adf_globs->Adi_dtptrs[dtid] == NULL
	 || !Adf_globs->Adi_dtptrs[dtid]->adi_under_dt
       )
	return(adu_error(adf_scb, E_AD2004_BAD_DTID, 0));

    if ((!continuation) || (work->adw_fip.fip_state == ADW_F_STARTING))
    {
	if (!continuation)
	    work->adw_fip.fip_state = ADW_F_INITIAL;
	status = adu_rdm1_setup(adf_scb, result_dv, coupon_dv, work, for_gca);
	if (status || work->adw_fip.fip_done)
	    return(status);
    }
    else if (work->adw_fip.fip_state == ADW_F_DONE_NEED_NULL)
    {
	/*
	**  This is an indication that we finished, but didn't
	**  send the NULL byte, and must do so now...
	*/
	
	work->adw_shared.shd_o_used = 0;
	status = adu_rdm2_finish(adf_scb, result_dv, coupon_dv, work, for_gca);
	return(status);
    }
    else
    {
	if (Adf_globs->Adi_fexi[ADI_01PERIPH_FEXI].adi_fcn_fexi == NULL)
	    return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
	work->adw_shared.shd_o_used = 0;
	work->adw_shared.shd_o_length = result_dv->db_length;
	work->adw_shared.shd_o_area = (char *) result_dv->db_data;
	work->adw_fip.fip_pop_cb.pop_continuation = 0;

	work->adw_fip.fip_pop_cb.pop_coupon = coupon_dv;
    }

    for (flush = 0;
	    !done
		&& (!flush)
		&& (work->adw_shared.shd_l1_check <
		    	    	    	work->adw_fip.fip_l1_value);
	/* No update action */)
    
    {
	switch (work->adw_shared.shd_exp_action)
	{
	case ADW_FLUSH_SEGMENT:
	case ADW_START:
	    if (for_gca)
	    {
		/*
		** Since we got a segment back, insert the `here
	        ** comes another segment indicator'.
		*/

		i4		one = 1;

		if ( (work->adw_shared.shd_o_length -
		                         work->adw_shared.shd_o_used)
		       < sizeof(one))
		{
		    /* Then the next segment marker won't fit.  Dump */
		    /* the current segment and move on... */

		    /* fix_me -- better error... */
		
		    return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
		}

		I4ASSIGN_MACRO(one,
		     work->adw_shared.shd_o_area[work->adw_shared.shd_o_used]);
		work->adw_shared.shd_o_used += sizeof(one);
	    }
	    /* Fall thru -- if out of input data, get some */

	case ADW_FLSH_SEG_NOFIT_LIND:
	case ADW_NEXT_SEGMENT:
	    
	    if (   (work->adw_shared.shd_exp_action == ADW_NEXT_SEGMENT)
		&& (work->adw_shared.shd_inp_tag == ADP_P_COUPON))
	    {
		/*
		**  For [DBMS style] coupons, each segment is in a row
		**  unto itself, regardless of the length of the row.
		**  Since this routine is datatype independent, it
		**  cannot tell when a segment is up, and thus must
		**  rely on the called routine.  Thus, if the callee
		**  asks for a new segment when processing a DBMS
		**  coupon, this routine will assume that the current
		**  set of data has been all used up...
		*/

		work->adw_shared.shd_i_used =
		    work->adw_shared.shd_i_length;
	    }

	    /* Fall thru... */

	case ADW_GET_DATA:
	    if (work->adw_shared.shd_i_used == work->adw_shared.shd_i_length)
	    {
		/*
		** If no unmoved segment data, then get some more.
		*/
		
		if (work->adw_fip.fip_done)
		{
		    done = TRUE;
		    status = E_DB_OK;
		}
		else
		{
		    status =
			(*Adf_globs->Adi_fexi[ADI_01PERIPH_FEXI].adi_fcn_fexi)
			    (ADP_GET, &work->adw_fip.fip_pop_cb);
		    if (status)
		    {
			if (work->adw_fip.fip_pop_cb.pop_error.err_code
			    == E_AD7001_ADP_NONEXT)
			{
			    work->adw_fip.fip_done = TRUE;
			    
			    if (status == E_DB_WARN)
				status = E_DB_OK;
			    else
				break;
			}
			else
			{
			    return(adu_error(adf_scb,
				   work->adw_fip.fip_pop_cb.pop_error.err_code,
					     0));
			}
		    }
		    
		    work->adw_shared.shd_i_used = 0;
		    work->adw_shared.shd_i_length =
			work->adw_fip.fip_seg_dv.db_length;
		    work->adw_shared.shd_i_area =
			work->adw_fip.fip_seg_dv.db_data;

		}
	    }
	    break;

	case ADW_CONTINUE:  /* This shouldn't happen */
	default:            /* Nor should anything else */
	    return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
	    break;
	}
	if (done)
	    break;

	status = adc_xform(adf_scb, (PTR)work);
	if (DB_FAILURE_MACRO(status))
	{
	    return(adu_error(adf_scb, E_AD7003_ADP_BAD_RECON, 0));
	}
	if (work->adw_shared.shd_exp_action == ADW_FLUSH_SEGMENT)
	{
	    flush = 1;
	}

	/* B104122 */
	if (work->adw_shared.shd_exp_action == ADW_FLSH_SEG_NOFIT_LIND)
	{
	    result_dv->db_length = work->adw_shared.shd_o_used;
	    flush = 1;
	}

	/* B?????? */
	if (work->adw_shared.shd_exp_action == ADW_FLUSH_INCOMPLETE_SEGMENT)
	{
	    result_dv->db_length = work->adw_shared.shd_o_used;
	    work->adw_shared.shd_exp_action = ADW_FLUSH_SEGMENT;
	    flush = 1;
	}

	work->adw_fip.fip_pop_cb.pop_continuation = 0;
    }

    if (work->adw_shared.shd_l1_check == work->adw_fip.fip_l1_value)
    {
	done = TRUE;
    }

    if (work->adw_fip.fip_test_mode)
    {
	work->adw_fip.fip_test_sent += work->adw_shared.shd_o_used;
	
	if ((work->adw_fip.fip_test_length
	         - work->adw_fip.fip_test_sent
	         - work->adw_fip.fip_null_bytes
	         - (for_gca * sizeof(i4)))
	     <= 0)
	{
	    /*
	    **	Then, for test purposes, we've sent all that we can.
	    **	Emulate completion.
	    */

	    work->adw_fip.fip_done = done = TRUE;
	    work->adw_shared.shd_i_used = work->adw_shared.shd_i_length;
	    work->adw_shared.shd_l1_check = work->adw_fip.fip_l1_value;
	    work->adw_shared.shd_o_used = work->adw_fip.fip_test_length
		                             - work->adw_fip.fip_test_sent
		                             - sizeof(i4)    /* end marker */
			                     - work->adw_fip.fip_null_bytes;
	                                        /* null indicator */
	    work->adw_fip.fip_test_sent =
		work->adw_fip.fip_test_length - sizeof(i4)
		                              - work->adw_fip.fip_null_bytes;
	}

    }
    
    if (done && ((work->adw_shared.shd_exp_action == ADW_NEXT_SEGMENT)
		 || (work->adw_shared.shd_exp_action == ADW_FLUSH_SEGMENT)))
    {
	/*
	** If we think we are done and have used all the input,...
	*/

	status = adu_rdm2_finish(adf_scb, result_dv, coupon_dv, work, for_gca);
    }
    else
    {
	/*
	** Otherwise, if we are surpassing the amount of data which
	** be available...
	*/

	if (work->adw_shared.shd_l1_check > work->adw_fip.fip_l1_value)
	{
	    /*
	    ** FIX_ME -- better error message...
	    ** Then we would be sending an inconsistent blob.
	    ** That would be bad.
	    */

	    return(adu_error(adf_scb, E_AD7004_ADP_BAD_BLOB,0));
	}
	adf_scb->adf_errcb.ad_errcode  = E_AD0002_INCOMPLETE;
	status = E_DB_INFO;
    }
    return(status);
}
Beispiel #30
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);
}