Beispiel #1
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 #2
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 #3
0
/*{
** Name: psq_str_dmp	- Dump a name
**
** Description:
**      This function dumps a string for debugging purposes.  Non-zero length
**	implies that the string may have some trailing blanks which will be
**	eliminated before pritning; otherwise it is assumed to be
**	NULL-terminated.
**
** Inputs:
**	str				string to print
**      len				length; if non-zero, trailing blanks, if
**					any will be eliminated; otherwise, it
**					will be assumed to be NULL-terminated
**
** Outputs:
**      None
**	
** Returns:
**	    E_DB_OK			Success
**	    E_DB_ERROR			Non-catastrophic failure
**	    E_DB_FATAL			Catastrophic failure
**
** Exceptions:
**	    none
**
** Side Effects:
**	    Sends output to terminal and/or log file.
**
** History:
**	26-nov-91 (andre)
**          written
*/
DB_STATUS 
psq_str_dmp(
	u_char	    *str,
	i4	    len)
{
    STATUS		    status;

    if (len > 0)
    {
	status = TRdisplay("%.#s", (i4) psf_trmwhite(len, (char *) str), str);
    }
    else if (len == 0)
    {
	status = TRdisplay("%s", str);
    }
    else
    {
	return(E_DB_ERROR);
    }

    return((status == TR_OK) ? E_DB_OK : E_DB_ERROR);
}
Beispiel #4
0
/*{
** Name: psy_qrymod	- Process views, permits, and integrities
**
** Description:
**      This function applies the qrymod algorithm to user queries.
**	This algorithm is well-described in the specific functions
**	psyview.c, psyinteg.c, and psypermit.c.  It MUST be applied
**	in the order: views, integrities, permits.  This is because
**	permits are on base tables, not on views, and we don't want
**	the extra qualifications stuck on by the permit process to
**	affect the integrities.
**
**	Rules modifications are applied after all other query mods.
**	Rules processing (in psyrules.c) may add statement trees to rule lists
**	maintained in sess_cb.
**
** Inputs:
**      qtree                           The query tree to modify
**	sess_cb				Current session control block
**	psq_cb				Calling control block
**	num_joins			ptr to a var containing number of joins
**					in the query tree
**
** Outputs:
**      qtree                           Can be modified by views, permits,
**					and integrities
**	sess_cb				All kinds of miscellaneous stuff
**					that is too detailed to describe here
**	psq_cb
**	    .err_blk			Filled in if an error happens
**
**	*num_joins			Will be incremented if any of the views
**					involved in the query or any permits
**					applied use joins.
**
**	*resp_mask			if the qmode==PSQ_VIEW will contain
**					indicators of whether the view appears
**					to be updateable and/or grantable view 
**
**	Returns:
**	    E_DB_OK			Success
**	    E_DB_FATAL			Failure
**	Exceptions:
**	    none
**
** Side Effects:
**	    Can allocate memory
**	    Catalog I/O
**
** History:
**      09-jul-86 (jeff)
**          Adapted from 4.0 qrymod() function
**      02-sep-86 (seputis)
**          used result relation from auxiliary table since RDF ptrs are NULLed
**	18-sep-86 (daved)
**	    the result relation in the session cb is not always the
**	    same as the one found in the user range table. this is because
**	    the one in the range table is accurate only in an append statement.
**	    thus, we will now change the session cb to point to the correct
**	    result relation.
**	2-apr-87 (daved)
**	    set a pss_permit flag in the range table for each used entry.
**	    psy_permit will clear this flag. Psy_view will set this flag
**	    in all range entries that a derived from a table that still has
**	    this flag set, else it will clear this flag for new entries.
**	    We will then call psy_permit again, to catch all the new entries.
**	24-sep-87 (stec)
**	    Change error handling - call psf_error.
**	25-oct-87 (stec)
**	    Remove transaction creation, this is now done by SCF.
**	26-jan-89 (neil)
**	    Now also calls psy_rules to fill in rule tree.
**	08-mar-89 (neil)
**	    Calls psy_rules with more arguments.
**	22-jun-89 (andre)
**	    remove call to psy_protect() before call to psy_view() since
**	    psy_view() was modified to call psy_protect() before performing
**	    query modification on SQL views not belonging to the user.
**	    Additionally, &qtree will not be passed to psy_view(), since there
**	    is no apparent reason to do so (we no longer attempt to assign to
**	    the corresponding argument inside of psy_view() )
**      24-jul-89 (jennifer)
**	    For each statement, indicate that audit information is NULL.
**	08-sep-89 (andre)
**	    recieve and pass to psy_view() and psy_permit() ptr to a var
**	    containing number of joins in the query tree.
**	19-sep-90 (andre)
**	    as a result of changes in psy_view(), we no longer need to call
**	    psy_permit() from psy_qrymod().
**	13-dec-90 (ralph)
**	    Move reset of pss_audit to before psy_view invocation (b34903)
**	11-mar-91 (andre)
**	    if qmode is PSQ_VIEW, pass PSQ_RETRIEVE to psy_view(), psy_integ(),
**	    and psy_rules() + do not try to copy pss_usrrange to pss_auxrng
**	    since psy_dview() already placed the range table entries into
**	    pss_auxrng.
**	    (this is a part of fix for bug 33038)
**	07-aug-91 (andre)
**	    if qmode is PSQ_VIEW do NOT translate it to PSQ_RETRIEVE +
**	    if qmode is PSQ_VIEW do not bother calling psy_integ() and
**	    psy_rules()
**
**	    Added resp_mask to the argument list.  This mask will be used to
**	    communicate info to the caller of psy_qrymod().  psy_qrymod() itself
**	    will not contribute anything to the information, instead, it will
**	    pass it to other functions (initially only to psy_view()) which will
**	    be responsible for providing the actual information.
**	30-dec-92 (andre)
**	    when processing a view tree in the course of processing CREATE RULE
**	    on a view we do NOT want to do any permit, rule, or integrity
**	    checking
**	04-jan-93 (andre)
**	    if we are processing DELETE, INSERT, or UPDATE, and a table or a
**	    view being updated has rules defined on it, set PSS_CHECK_RULES in
**	    sess_cb->pss_resrng->pss_var_mask to remind psy_view() to call
**	    psy_rules()
**
**	    since psy_dview() is going away, and psl_cview() calls psy_qrymod()
**	    with range variables as they were entered in the grammar, we must
**	    copy the range table from pss_usrrange to pss_auxrng for define VIEW
**	    just as we do for all other QUEL statements
**
**	    In most cases psy_rules() will NO LONGER be called from
**	    psy_qrymod().  It will be called from psy_view() when processing
**	    INSERT, DELETE, or UPDATE. This change was necessary because now
**	    rules can be defined on views, and it seemed reasonable that rule
**	    checking (just like privilege checking) can be driven from
**	    psy_view().  The once exception occurs when we are processing UPDATE
**	    WHERE CURRENT OF - psy_view() will simply return when presented with
**	    this query mode, but there may be rules that apply to this
**	    statement.  Consequently, psy_rules() will be called from
**	    psy_qrymod() only when psq_qmode == PSQ_REPCURS
**	08-jan-93 (rblumer) 
**	    set flag to bypass permission checking for dummy set-input
**	    range variables.
**	30-mar-93 (rblumer) 
**	    set check_perms to false for system-generated procedures
**	    and for (internal) queries with PSS_NO_CHECKPERMS set.
**	01-apr-93 (andre)
**	    (fix for bugs 50823, 50825, and 50899)
**	    do not copy QUEL range table to aux. range table when processing
**	    REPLACE CURSOR - the entry describing the table/view over
**	    which the cursor has been defined has already been placed into
**	    pss_auxrng
**	08-apr-93 (andre)
**	    do not call psy_rules() explicitly for PSQ_REPCURS.  psy_view() will
**	    now handle PSQ_REPCURS and call psy_rules() when necessary.
**	09-apr-93 (andre)
**	    set PSS_CHECK_RULES in the pss_var_mask corresponding to the
**	    table/view being updated via a cursor
**	26-apr-93 (markg)
**	    If the server is running C2 then initialize each range
**	    entry to show that it needs to be audited.
**	5-jul-93 (robf)
**	    If server is C2 then initialize any result range table to show
**	    it needs to be audited.
**	14-sep-93 (robf)
**	    Add QUERY_SYSCAT check, disallowing direct querying of
**	    base catalogs without privilege. This is done here rather than
**	    lower down in view/permit processing since we want to allow
**	    access to views on base catalogs (e.g. standard catalogs)
**	    to go ahead. 
**	13-oct-93 (robf)
**          Add <st.h>
**	25-oct-93 (stephenb)
**	    If the server is running C2 then also initialize the result range
**	    entry to show that it needs to be audited.
**	13-dec-93 (robf)
**          When checking for query_syscat privilege, allow for extended
**	    catalogs. Some catalogs (like iistar_cdbs) have both the
**	    DMT_CATALOG and DMT_EXTENDED_CAT bits set. In this case we allow
**          access since this priv restricts base catalogs only.
**	09-feb-94 (andre)
**	    fix for bug 59595:
**		we also need to forego checking permits if we are parsing a 
**		system-generated query
**	11-jul-94 (robf)
**          Restrict direct queries to table extensions the same way
**	    as system catalogs, i.e. to those with SELECT_SYSCAT privilege.
**	    The rationale for this is that info in extensions is really
**          part of the base table, and to present an appropriately
**          protected view of the data access should be through the base
**          table, not directly at the extension.
*/
DB_STATUS
psy_qrymod(
	PST_QNODE          *qtree,
	PSS_SESBLK	   *sess_cb,
	PSQ_CB		   *psq_cb,
	PST_J_ID	   *num_joins,
	i4		   *resp_mask)
{
    PSS_RNGTAB          *resrng;
    PSS_USRRANGE	*rngtab = &sess_cb->pss_auxrng;
    PSF_MSTREAM         *mstream = &sess_cb->pss_ostream;
    DB_ERROR		*err_blk = &psq_cb->psq_error;
    i4			qmode = psq_cb->psq_mode;
    DB_STATUS		status;
    i4			i;
    i4			check_perms = TRUE;
    GLOBALREF PSF_SERVBLK *Psf_srvblk;
    i4		err_code;
    bool		can_query_syscat=FALSE;

    *resp_mask = 0L;	    /* init the response mask */

    /*
    ** avoid permit checking when processing RULE trees,
    ** or when parsing/reparsing a system-generated procedure,
    ** or when parsing a system-generated query (e.g. a query to check whether
    ** constraints hold on existing data)
    */
    if ((psq_cb->psq_mode == PSQ_RULE)
	|| (   (sess_cb->pss_dbp_flags & PSS_DBPROC)
	    && (sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED))
	|| (psq_cb->psq_flag & PSQ_NO_CHECK_PERMS)
	|| (   (psq_cb->psq_info != (PST_INFO *) NULL)
	    && (psq_cb->psq_info->pst_execflags & PST_SYSTEM_GENERATED))
       )
    {
	check_perms = FALSE;
    }
    /*
    ** Can user directly query system catalogs ?
    ** Users with databse privilege QUERY_SYSCAT, or users with
    ** SECURITY subject privilege may directly query system cats
    */
    if(psy_ckdbpr(psq_cb, DBPR_QUERY_SYSCAT)==E_DB_OK)
	can_query_syscat=TRUE;
    else if(sess_cb->pss_ustat&DU_USECURITY)
	can_query_syscat=TRUE;
    else
	can_query_syscat=FALSE;

    /*
    ** Reset pss_audit prior to calling psy_view.
    */
    sess_cb->pss_audit = NULL;

    /*
    ** We don't want to clobber the user's view of the range table in
    ** the process of doing qrymod.  Therefore, we will copy the user's
    ** range table to the auxiliary range table, and use that instead.
    */

    /* don't need to copy range table for SQL because there are no range
    ** table entries that live longer than one statement
    **
    ** REPLACE CURSOR places description of the table/view over which it is
    ** defined into pss_auxrng
    */
    if (   sess_cb->pss_lang == DB_QUEL
	&& qmode != PSQ_REPCURS)
    {
	status = pst_rgcopy(&sess_cb->pss_usrrange, rngtab, 
	    &sess_cb->pss_resrng, err_blk);
	if (DB_FAILURE_MACRO(status))
	    return (status);
    }    
    for (i = 0; i < PST_NUMVARS; i++)
    {
	rngtab->pss_rngtab[i].pss_rgparent = -1;

	/* don't want to check permissions on
	** set-input temporary tables
	*/
	if (rngtab->pss_rngtab[i].pss_rgtype == PST_SETINPUT)
	    rngtab->pss_rngtab[i].pss_permit = FALSE;
	else
	    rngtab->pss_rngtab[i].pss_permit = check_perms;

	/*
	** See if this is a real base catalog.
	** We special case iidbcapabilities since its marked as a base 
	** catalog, but gets directly queried (and needs to be
	** accessed by frontends)
	*/
	if(rngtab->pss_rngtab[i].pss_used &&
	   rngtab->pss_rngtab[i].pss_rgno != -1 &&
	   rngtab->pss_rngtab[i].pss_tabdesc &&
	   ((
	   (rngtab->pss_rngtab[i].pss_tabdesc->tbl_2_status_mask&DMT_TEXTENSION)
	   ) || (
	   (rngtab->pss_rngtab[i].pss_tabdesc->tbl_status_mask&DMT_CATALOG) &&
	   !(rngtab->pss_rngtab[i].pss_tabdesc->tbl_status_mask&DMT_VIEW) &&
	   !(rngtab->pss_rngtab[i].pss_tabdesc->tbl_status_mask&DMT_EXTENDED_CAT) &&
	   STncasecmp((char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name,
			"iidbcapabilities", GL_MAXNAME)!=0
	   ))
        )
	{
		/*
		** This is a base catalog.
		*/
		if(!can_query_syscat)
		{
		    /*
		    ** Error, user can't query base catalogs.
		    */
		    if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE )
			(VOID)psy_secaudit( 
			    FALSE,
			    sess_cb,
			    (char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name,
			    &rngtab->pss_rngtab[i].pss_tabdesc->tbl_owner,
			    DB_MAXNAME,
			    SXF_E_SECURITY,
			    I_SX273B_QUERY_SYSCAT,
			    (SXF_A_SELECT|SXF_A_FAIL),
			    err_blk);

		    (VOID) psf_error(E_PS035A_CANT_QUERY_SYSCAT, 
				0L, PSF_USERERR, &err_code,
			        err_blk, 1,
			        psf_trmwhite(sizeof(DB_NAME),
				  (char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name),
				(char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name);
		    return E_DB_ERROR;
		}
	}
	/*
	** If this is a C2 server set the PSS_DOAUDIT flag
	** for this entry.
	*/
	if (Psf_srvblk->psf_capabilities & PSF_C_C2SECURE)
	    rngtab->pss_rngtab[i].pss_var_mask |= PSS_DOAUDIT;
    }
    
    if (resrng = sess_cb->pss_resrng)
    {
	/* don't want to check permissions
	** on set-input temporary tables
	*/
	if (rngtab->pss_rngtab[i].pss_rgtype == PST_SETINPUT)
	    rngtab->pss_rngtab[i].pss_permit = FALSE;
	else
	    rngtab->pss_rngtab[i].pss_permit = check_perms;

	/*
	** if processing DELETE, UPDATE, INSERT, or UPDATE/REPLACE cursor, and
	** there are rules defined on the view/table being updated, set
	** PSS_CHECK_RULES in pss_var_mask
	*/
	if (   (   qmode == PSQ_APPEND
		|| qmode == PSQ_DELETE
		|| qmode == PSQ_REPLACE
		|| qmode == PSQ_REPCURS
	       )
	    && resrng->pss_tabdesc->tbl_status_mask & DMT_RULE
	   )
	{
	    resrng->pss_var_mask |= PSS_CHECK_RULES;
	}
        /*
        ** If this is a C2 server set the PSS_DOAUDIT flag
        ** for the result table.
        */
        if (Psf_srvblk->psf_capabilities & PSF_C_C2SECURE)
		rngtab->pss_rsrng.pss_var_mask |= PSS_DOAUDIT;
    }


    /* Apply view processing */
    status = psy_view(mstream, qtree, rngtab, qmode, sess_cb, err_blk,
		      num_joins, resp_mask);
    if (DB_FAILURE_MACRO(status))
    {
	return (status);
    }

    /*
    ** do not check for existing INTEGRITIES when processing trees as a
    ** part of CREATE/DEFINE VIEW or CREATE RULE processing
    */
    if (qmode != PSQ_VIEW && qmode != PSQ_RULE)
    {
	/* Apply integrity processing */
	status = psy_integ(mstream, qtree, rngtab, resrng, qmode,
	    sess_cb, &qtree, err_blk);
	if (DB_FAILURE_MACRO(status))
	{
	    return (status);
	}
    }

    return (status);
}
Beispiel #5
0
/*{
** Name: PSQ_TCNVT	- convert db_data_value to text form
**
** Description:
**      This routine takes any user supplied db_data_value and converts
**  it to the value's textual representation.  This is required for the
**  iiqrytext catalog.  It is assumed that all datavalues can be written
**  into a character representation. 
**
** Inputs:
**	sess_cb				session control block
**	    .pss_adfcb			adf session control block for output
**					arguments.
**      header                          Pointer to chain header
**	dbval				db_data_value
**	result				Place to put pointer to new piece
**	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:
**      29-jun-87 (daved)
**          written
**	28-jan-91 (andre)
**	    fix bug 35446: size of a new piece should include quotes, if they
**	    were added.
**	18-nov-91 (rog)
**	    Fixed bug 40869, et alia: the above fix missed adding the quotes
**	    to the total size and not just the piece size.
**	23-Sep-2009 (kiria01) b122578
**	    Initialise the ADF_FN_BLK .adf_fi_desc and adf_dv_n members.
**	19-Aug-2010 (kschendel) b124282
**	    Make sure fi-desc is always set to something.
*/
DB_STATUS
psq_tcnvt(
	PSS_SESBLK	   *sess_cb,
	PTR                header,
	DB_DATA_VALUE	   *dbval,
	PTR		   *result,
	DB_ERROR	   *err_blk)
{
    PSQ_THEAD           *hp;
    PSQ_TEXT		*tp;
    i4		err_code;
    DB_STATUS		status;
    ADF_CB		*adf_cb;
    ADF_FN_BLK		adffn;
    i4			dv_size;
    i4			count;
    char		*cptr;
    char		*quote_char;
    DB_TEXT_STRING      *string;
    ADI_DT_NAME		dt_fname;
    ADI_DT_NAME		dt_tname;
    char		f4_style;
    char		f8_style;
    i4			f4_width;
    i4			f8_width;
    i4			f4_prec;
    i4			f8_prec;
    i4			totype;
    i4			is_string;

    hp	    = (PSQ_THEAD *) header;
    adf_cb  = (ADF_CB *) sess_cb->pss_adfcb;
    status  = E_DB_OK;
    totype  = (DB_DT_ID) DB_LTXT_TYPE;

    adffn.adf_r_dv.db_datatype = totype;
    if (dbval->db_datatype == totype)
	dv_size = dbval->db_length;
    else
	dv_size = 0;

    /* JRBCMT -- PSF is not allowed to know this!!  First of all, date is   */
    /* missing from the list below and decimal will soon need to be on it.  */
    /* But also, we need to fix this code so that it doesn't make	    */
    /* assumptions about what types exist.  I think the proper approach is  */
    /* to quote all non-intrinsic types, but this should be investigated.   */

    /* are we dealing with a string type (incoming). */
    if (abs(dbval->db_datatype) == DB_INT_TYPE ||
        abs(dbval->db_datatype) == DB_FLT_TYPE ||
	abs(dbval->db_datatype) == DB_MNY_TYPE ||
	abs(dbval->db_datatype) == DB_BOO_TYPE)
    {
	is_string = FALSE;
	quote_char = (char *) NULL;
    }
    else
    {
	is_string = TRUE;
	quote_char = (sess_cb->pss_lang == DB_SQL) ? "\'" : "\"";
    }
    

    /* set the floating point conversion display */
    f4_style = adf_cb->adf_outarg.ad_f4style;
    f8_style = adf_cb->adf_outarg.ad_f8style;
    f4_width = adf_cb->adf_outarg.ad_f4width;
    f8_width = adf_cb->adf_outarg.ad_f8width;
    f4_prec  = adf_cb->adf_outarg.ad_f4prec;
    f8_prec  = adf_cb->adf_outarg.ad_f8prec;

    adf_cb->adf_outarg.ad_f4style = 'n';
    adf_cb->adf_outarg.ad_f8style = 'n';
    adf_cb->adf_outarg.ad_f4width = 20;
    adf_cb->adf_outarg.ad_f8width = 20;
    adf_cb->adf_outarg.ad_f4prec  = 10;
    adf_cb->adf_outarg.ad_f8prec  = 10;

    /* get the function instance id for this conversion */
    status = adi_ficoerce(adf_cb, dbval->db_datatype, totype, &adffn.adf_fi_id);
    if (status != E_DB_OK)
    {
	goto exit;
    }         

    /* determine the result size. */
    status = adi_fidesc(adf_cb, adffn.adf_fi_id, &adffn.adf_fi_desc);
    if (status != E_DB_OK)
    {
	goto exit;
    }
    if (!dv_size)
    {
	/* Now lets fill in the datatype length info and allocate space for the 
	** data.
	*/
	status = adi_0calclen(adf_cb, &adffn.adf_fi_desc->adi_lenspec, 1, &dbval, 
		&adffn.adf_r_dv);
	dv_size = adffn.adf_r_dv.db_length;

	if (status != E_DB_OK)
	{
	     goto exit;
	}
    }
    /* if string, add room for quotes */
    if (is_string)
	dv_size += 2 * CMbytecnt(quote_char);

    /* Allocate enough space for PSQ_TEXT structure containing piece */
    hp->psq_tmem.ulm_psize = dv_size + sizeof(PSQ_TEXT) - 1;
    status = ulm_palloc(&hp->psq_tmem);
    if (status != E_DB_OK)
    {
	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;

    string	  = (DB_TEXT_STRING*) tp->psq_tval;
    /* Fill in text piece */
    adffn.adf_r_dv.db_length	= dv_size;
    adffn.adf_r_dv.db_data	= (PTR) string;
    adffn.adf_dv_n		= 1;
    STRUCT_ASSIGN_MACRO(*dbval, adffn.adf_1_dv);
    adffn.adf_pat_flags		= AD_PAT_DOESNT_APPLY;
    if ((status = adf_func(adf_cb, &adffn)) != E_DB_OK)
    {
	goto exit;
    }
    /* CAUTION: entering tricky code.
    ** string is a variable containing a text datatype. We want to convert
    ** to a C datatype.  We also want to add quote characters if the datatype
    ** was a string type.  We grab the count from the string variable first.
    ** we can then use the 2 byte count for character data.
    */
    count = string->db_t_count;
    cptr = (char *)  string;
    if (is_string)
    {
	/*
	** for strings, copy the opening quote (" or ', depending on language)
	*/ 
	CMcpychar(quote_char, cptr);
	cptr += CMbytecnt(quote_char);
    }
    MEcopy((PTR) string->db_t_text, count, (PTR) cptr);
    cptr += count;
    if (is_string)
    {
	/*
	** for strings, copy the closing quote (" or ', depending on language)
	*/ 
	CMcpychar(quote_char, cptr);
    }

    /* if storing a string, do not forget to account for quotes (bug 35446) */
    tp->psq_psize = (is_string) ? count + 2 * CMbytecnt(quote_char) : count;

    /* Hook it up to the chain */
    tp->psq_next = (PSQ_TEXT *) NULL;
    if (hp->psq_last != (PSQ_TEXT *) NULL)
    {
	hp->psq_last->psq_next = tp;
	tp->psq_prev = hp->psq_last;
    }
    else
    {
	tp->psq_prev = NULL;
    }
    hp->psq_last = tp;
    if (hp->psq_first == (PSQ_TEXT *) NULL)
	hp->psq_first = tp;

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

exit:
    /* set the floating point conversion display */
    adf_cb->adf_outarg.ad_f4style = f4_style;
    adf_cb->adf_outarg.ad_f8style = f8_style;
    adf_cb->adf_outarg.ad_f4width = f4_width;
    adf_cb->adf_outarg.ad_f8width = f8_width;
    adf_cb->adf_outarg.ad_f4prec  = f4_prec;
    adf_cb->adf_outarg.ad_f8prec  = f8_prec;

    if (status != E_DB_OK)
    {
	(VOID) adi_tyname(adf_cb, dbval->db_datatype, &dt_fname);
	(VOID) adi_tyname(adf_cb, totype, &dt_tname);
	(VOID) psf_error(2911L, 0L, PSF_USERERR,
	    &err_code, err_blk, 3, sizeof (sess_cb->pss_lineno),
	    &sess_cb->pss_lineno, 
	    psf_trmwhite(sizeof(dt_fname), (char *) &dt_fname), &dt_fname, 
	    psf_trmwhite(sizeof (dt_tname), (char *) &dt_tname), &dt_tname);
        return (E_DB_ERROR);    
    }
    return (status);
}
Beispiel #6
0
/*
** Name: psq_store_text - store query text in a contiguous block of QSF memory
**
** Description:
**	Copy contents of a query text chain (prepended, if necessary with RANGE
**	statements) into a contiguous block of QSF memory.  Caller may specify
**	that the text be stored in DB_TEXT_STRING format by setting
**	return_db_text_string to TRUE; otherwise the function will return a i4
**	followed by query text.
**
** Input:
**	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 opened memory stream
**	return_db_text_string	if TRUE, function will store text in
**				DB_TEXT_STRING format; otherwise it will store
**				it a a i4  (length) followed by text
**
** Output:
**	result			query text in specified format
**	err_blk			Filled in if an error happens
**
** Side efects:
**	allocates memory
**
** Returns:
**	E_DB_{OK,ERROR}
**
** History:
**	09-jan-93 (andre)
**	    written
**	29-jul-2001 (toumi01)
**	    problem found doing i64_aix port:
**	    (u_char *)'\n' should be (uchar)'\n'
**	    (u_char *)'\0' should be (uchar)'\0'
**      26-Oct-2009 (coomi01) b122714
**          Move psq_store_text() declarator to pshparse.h and make it public here.
**	24-Jun-2010 (kschendel) b123775
**	    Correct a call to trim-whitespace.
*/
DB_STATUS
psq_store_text(
	PSS_SESBLK	    *sess_cb,
	PSS_USRRANGE	    *rngtab,
	PTR		    header,
	PSF_MSTREAM	    *mstream,
	PTR		    *result,
	bool		    return_db_text_string,
	DB_ERROR	    *err_blk)
{
    DB_STATUS		status;
    i4			i;
    PSQ_THEAD		*hp = (PSQ_THEAD *) header;
    i4			size = hp->psq_tsize;
    PSQ_TEXT		*tp;
    PSS_RNGTAB		*rngvar;
    u_char		*out;
    
    if (rngtab)
    {
	/*
	** allocate enough space for range statements. each range statement
	** looks like range of 'rngname' is 'tabname'\n.
	** Thus, max space is 14+2*DB_MAX_NAME.
	*/
	for (i = 0, rngvar = rngtab->pss_rngtab; i < PST_NUMVARS; i++, rngvar++)
	{
	    /* Only look at range vars that are being used */
	    if (rngvar->pss_used && rngvar->pss_rgno >= 0)
	    {
		size += (  14   /* "range of  is \n" */
			 + psf_trmwhite(DB_TAB_MAXNAME, rngvar->pss_rgname)
			 + psf_trmwhite(sizeof(DB_TAB_NAME),
			       (char *) &rngvar->pss_tabname));
	    }
	}
    }
    
    if (return_db_text_string)
    {
	DB_TEXT_STRING	    *str;

	status = psf_malloc(sess_cb, mstream, size + sizeof(*str) - sizeof(u_char),
	    result, err_blk);
	if (status != E_DB_OK)
	    return (status);

	str = (DB_TEXT_STRING *) *result;

	/*
	** store the total length of query text 
	*/
	str->db_t_count = size;

	out = str->db_t_text;

    }
    else
    {
	/* Allocate a piece large enough for all the text + a i4  (count) */
	status = psf_malloc(sess_cb, mstream, size + sizeof(i4), result, err_blk);
	if (status != E_DB_OK)
	    return (status);

	out = (u_char *) *result;
	
	/* Copy the length into the buffer */
	MEcopy((char *) &size, sizeof(size), (char *) out);

	out += sizeof(size);
    }
    
    /* Copy the pieces into the buffer; first put the range statements */
    if (rngtab)
    {
	for (i = 0, rngvar = rngtab->pss_rngtab; i < PST_NUMVARS; i++, rngvar++)
	{
	    /* Only look at range vars that are being used */
	    if (rngvar->pss_used && rngvar->pss_rgno >= 0)
	    {
		i4 plen;

		STncpy( (char *)out, "range of ", 9);
		out += 9;

		/* add in range name */
		plen = psf_trmwhite(DB_TAB_MAXNAME, rngvar->pss_rgname);
		STncpy( (char *)out, rngvar->pss_rgname, plen);
		out += plen;

		STncpy( (char *)out, " is ", 4);
		out += 4;

		plen = psf_trmwhite(DB_TAB_MAXNAME, rngvar->pss_tabname.db_tab_name);
		STncpy( (char *)out, (char *)&rngvar->pss_tabname, plen);
		out += plen;

		*out = (u_char)'\n';
		out++;
		*out = (u_char)'\0';
	    }
	}
    }

    for (tp = hp->psq_first; tp != (PSQ_TEXT *) NULL; tp = tp->psq_next)
    {
	MEcopy((char *) tp->psq_tval, tp->psq_psize, (char *) out);
	out += tp->psq_psize;
    }

    return(E_DB_OK);
}
Beispiel #7
0
/*{
** Name: psy_seqperm	- Check if the user/group/role has sequence permission.
**
** Description:
**	This routine retrieves all protection tuples applicable to a given
**	sequence until it establishes that the user posesses all privileges
**	specified in *privs (SUCCESS) or until there are no more left (FAILURE).
**	(The only privilege defined on sequences is NEXT - like SELECT)
**
**	The routine assumes that if the current user is the same as the sequence
**	owner, then no 	privileges need be checked.
**	
** Inputs:
**	rdf_cb				RDF CB that was used to extract the
**					original sequence.  Note that the RDF
**					operation type masks will be modified
**					in this routine
**					(rdr_types_mask will be set to
**					RDR_PROTECT|RDR2_SEQUENCE)
**	privs				ptr to a map of privileges to verify
**	    DB_NEXT			user must posess NEXT on sequence
**	    DB_GRANT_OPTION		privilege(s) must be grantable
**	sess_cb				Session CB with various values plus:
**	    .pss_user			User name.
**	    .pss_group			Group name.
**	    .pss_aplid			Application/role name.
**      seq_info			sequence descriptor
**	qmode				mode of the query
**	grant_all			TRUE if processing GRANT ALL;
**					FALSE otherwise
**
** Outputs:
**	privs				if non-zero, indicates which privileges
**					the user does not posess
**	err_blk.err_code		Filled in if an error happened:
**					  errors from RDF & other PSF utilities
**	Returns:
**	    E_DB_OK			Success
**	    E_DB_ERROR			Failure
**	Exceptions:
**	    none
**	
** Side Effects:
**	1. Via RDF will also access iiprotect.
**
** History:
**	3-may-02 (inkdo01)
**	    Written for sequence support (cloned from psy_evperm).
**	24-apr-03 (inkdo01)
**	    Corrected "missing privilege" message.
*/
DB_STATUS
psy_seqperm(
	RDF_CB		*rdf_cb,
	i4		*privs,
	PSS_SESBLK      *sess_cb,
	PSS_SEQINFO	*seq_info,
	i4		qmode,
	i4		grant_all,
	DB_ERROR	*err_blk)
{
    RDR_RB	    	*rdf_rb = &rdf_cb->rdf_rb;	/* RDR request block */
#define	PSY_RDF_SEQ	5
    DB_PROTECTION	seqprots[PSY_RDF_SEQ];	/* Set of returned tuples */
    DB_PROTECTION   	*protup;	/* Single tuple within set */
    i4		     	tupcount;	/* Number of tuples in scan */
    DB_STATUS	     	status;
    i4			save_privs = *privs, privs_wgo = (i4) 0;
    PSQ_OBJPRIV         *seqpriv_element = (PSQ_OBJPRIV *) NULL;

				/* 
				** will be used to remember whether the 
				** <auth id> attempting to grant privilege(s)
				** him/herself possesses any privilege on the 
				** object; 
				** will start off pessimistic, but may be reset 
				** to TRUE if we find at least one permit 
				** granting ANY privilege to <auth id> 
				** attempting to grant the privilege or to 
				** PUBLIC
				*/
    bool		cant_access = TRUE;

    status = E_DB_OK;

    if (!MEcmp((PTR) &sess_cb->pss_user,
	    (PTR) &seq_info->pss_seqown, sizeof(sess_cb->pss_user))
       )
    {
	/* owner of the sequence posesses all privileges on it */
	*privs = (i4) 0;
    }

    if (!*privs)
    {
	/* no privileges to check or the sequence is owned by the current user */
	return(E_DB_OK);
    }

    /*
    ** rdr_rec_access_id must be set before we try to scan a privilege list
    ** since under some circumstances we may skip all the way to saw_the_perms:
    ** and seqperm_exit, and code under seqperm_exit: relies on rdr_rec_access_id
    ** being set to NULL as indication that the tuple stream has not been opened
    */
    rdf_rb->rdr_rec_access_id  = NULL;    

    /*
    ** if processing CREATE PROCEDURE, before scanning IIPROTECT to check if the
    ** user has the required privileges on the sequence, check if some of the
    ** privileges have already been checked.
    */
    if (sess_cb->pss_dbp_flags & PSS_DBPROC)
    {
	bool			missing;

	status = psy_check_objprivs(sess_cb, privs, &seqpriv_element,
	    &sess_cb->pss_indep_objs.psq_objprivs, &missing,
	    &seq_info->pss_seqid, sess_cb->pss_dependencies_stream,
	    PSQ_OBJTYPE_IS_SEQUENCE, err_blk);
	if (DB_FAILURE_MACRO(status))
	{
	    return(status);
	}
	else if (missing)
	{
	    if (sess_cb->pss_dbp_flags & PSS_DBPGRANT_OK)
	    {
		/* dbproc is clearly ungrantable now */
		sess_cb->pss_dbp_flags &= ~PSS_DBPGRANT_OK;
	    }

	    if (sess_cb->pss_dbp_flags & PSS_0DBPGRANT_CHECK)
	    {
		/*
		** if we determine that a user lacks some privilege(s) by
		** scanning IIPROTECT, code under saw_the_perms expects
		** priv to contain a map of privileges which could not be
		** satisfied;
		** if parsing a dbproc to determine its grantability, required
		** privileges must be all grantable (so we OR DB_GRANT_OPTION
		** into *privs);
		** strictly speaking, it is unnecessary to OR DB_GRANT_OPTION
		** into *privs, but I prefer to ensure that saw_the_perms: code
		** does not have to figure out whether or not IIPROTECT was
		** scanned
		*/
		*privs |= DB_GRANT_OPTION;
	    }

	    goto saw_the_perms;
	}
	else if (!*privs)
	{
	    /*
	    ** we were able to determine that the user posesses required
	    ** privilege(s) based on information contained in independent
	    ** privilege lists
	    */
	    return(E_DB_OK);
	}
    }

    /*
    ** if we are parsing a dbproc to determine if its owner can grant permit on
    ** it, we definitely want all of the privileges WGO;
    ** when processing GRANT, caller is expected to set DB_GRANT_OPTION in
    ** *privs
    */

    if (sess_cb->pss_dbp_flags & PSS_DBPROC)
    {
	if (sess_cb->pss_dbp_flags & PSS_0DBPGRANT_CHECK)
	{
	    /*
	    ** if parsing a dbproc to determine if it is grantable, user must be
	    ** able to grant required privileges
	    */
	    *privs |= DB_GRANT_OPTION;
	}
	else if (sess_cb->pss_dbp_flags & PSS_DBPGRANT_OK)
	{
	    /*
	    ** if we are processing a definition of a dbproc which appears to be
	    ** grantable so far, we will check for existence of all required
	    ** privileges WGO to ensure that it is, indeed, grantable.
	    */
	    privs_wgo = *privs;
	}
    }
    
    /*
    ** Some RDF fields are already set in calling routine.  Permit tuples are
    ** extracted by unique "dummy" table id.  In the case of sequences there
    ** cannot be any caching of permissions (as there are no timestamps) so we
    ** pass in an iiprotect result tuple set (seqprots).
    */
    STRUCT_ASSIGN_MACRO(seq_info->pss_seqid, rdf_rb->rdr_tabid);
    rdf_rb->rdr_types_mask     = RDR_PROTECT;
    rdf_rb->rdr_2types_mask    = RDR2_SEQUENCE; 
    rdf_rb->rdr_instr          = RDF_NO_INSTR;
    rdf_rb->rdr_update_op      = RDR_OPEN;
    rdf_rb->rdr_qrymod_id      = 0;		/* Get all protect tuples */
    rdf_cb->rdf_error.err_code = 0;

    /* For each group of permits */
    while (rdf_cb->rdf_error.err_code == 0 && (*privs || privs_wgo))
    {
	/* Get a set at a time */
	rdf_rb->rdr_qtuple_count = PSY_RDF_SEQ;
	rdf_rb->rdr_qrytuple     = (PTR) seqprots;  /* Result block for tuples */
	status = rdf_call(RDF_READTUPLES, (PTR) rdf_cb);
	rdf_rb->rdr_update_op = RDR_GETNEXT;
	if (status != E_DB_OK)
	{
	    switch(rdf_cb->rdf_error.err_code)
	    {
	      case E_RD0011_NO_MORE_ROWS:
		status = E_DB_OK;
		break;
	      case E_RD0013_NO_TUPLE_FOUND:
		status = E_DB_OK;
		continue;			/* Will stop outer loop */
	      default:
		_VOID_ psf_rdf_error(RDF_READTUPLES, &rdf_cb->rdf_error, err_blk);
		goto seqperm_exit;
	    } /* End switch error */
	} /* If error */

	/* For each permit tuple */
	for (tupcount = 0, protup = seqprots;
	     tupcount < rdf_rb->rdr_qtuple_count;
	     tupcount++, protup++)
	{
	    bool	applies;
	    i4		privs_found;

	    /* check if the permit applies to this session */
	    status = psy_grantee_ok(sess_cb, protup, &applies, err_blk);
	    if (DB_FAILURE_MACRO(status))
	    {
		goto seqperm_exit;
	    }
	    else if (!applies)
	    {
		continue;
	    }

	    /*
	    ** remember that the <auth id> attempting to grant a privilege 
	    ** possesses some privilege on the sequence
	    */
	    if (qmode == PSQ_GRANT && cant_access)
	        cant_access = FALSE;

	    /*
	    ** if some of the required privileges have not been satisfied yet,
	    ** we will check for privileges in *privs; otherwise we will check
	    ** for privileges in (privs_wgo|DB_GRANT_OPTION)
	    */
	    privs_found = prochk((*privs) ? *privs
					  : (privs_wgo | DB_GRANT_OPTION),
		(i4 *) NULL, protup, sess_cb);

	    if (!privs_found)
		continue;

	    /* mark the operations as having been handled */
	    *privs &= ~privs_found;

	    /*
	    ** if the newly found privileges are WGO and we are looking for
	    ** all/some of them WGO, update the map of privileges WGO being
	    ** sought
	    */
	    if (protup->dbp_popset & DB_GRANT_OPTION && privs_found & privs_wgo)
	    {
		privs_wgo &= ~privs_found;
	    }

	    /*
	    ** check if all required privileges have been satisfied;
	    ** note that DB_GRANT_OPTION bit does not get turned off when we
	    ** find a tuple matching the required privileges since when we
	    ** process GRANT ON SEQUENCE, more than one privilege may be required
	    */
	    if (*privs && !(*privs & ~DB_GRANT_OPTION))
	    {
		*privs = (i4) 0;
	    }

	    if (!*privs && !privs_wgo)
	    {
		/*
		** all the required privileges have been satisfied and the
		** required privileges WGO (if any) have been satisfied as
		** well -  we don't need to examine any more tuples
		*/
		break;
	    }
	} /* For all tuples */
    } /* While there are RDF tuples */

saw_the_perms:
    if (   sess_cb->pss_dbp_flags & PSS_DBPGRANT_OK
	&& (privs_wgo || *privs & DB_GRANT_OPTION))
    {
	/*
	** we are processing a dbproc definition; until now the dbproc appeared
	** to be grantable, but the user lacks the required privileges WGO on
	** this sequence - mark the dbproc as non-grantable
	*/
	sess_cb->pss_dbp_flags &= ~PSS_DBPGRANT_OK;
    }

    /*
    ** if processing a dbproc, we will record the privileges which the current
    ** user posesses if
    **	    - user posesses all the required privileges or
    **	    - we were parsing the dbproc to determine if it is grantable (in
    **	      which case the current dbproc will be marked as ungrantable, but
    **	      the privilege information may come in handy when processing the
    **	      next dbproc mentioned in the same GRANT statement.)
    **
    ** NOTE: we do not build independent privilege list for system-generated
    **	     dbprocs
    */
    if (   sess_cb->pss_dbp_flags & PSS_DBPROC
	&& ~sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED
	&& (!*privs || sess_cb->pss_dbp_flags & PSS_0DBPGRANT_CHECK))
    {
	if (save_privs & ~*privs)
	{
	    if (seqpriv_element)
	    {
		seqpriv_element->psq_privmap |= (save_privs & ~*privs);
	    }
	    else
	    {
		/* create a new descriptor */

		status = psy_insert_objpriv(sess_cb, &seq_info->pss_seqid,
		    PSQ_OBJTYPE_IS_SEQUENCE, save_privs & ~*privs,
		    sess_cb->pss_dependencies_stream,
		    &sess_cb->pss_indep_objs.psq_objprivs, err_blk);

		if (DB_FAILURE_MACRO(status))
		    goto seqperm_exit;
	    }
	}
    }

    if (*privs)
    {
	char                buf[60];  /* buffer for missing privilege string */
	i4		    err_code;

	psy_prvmap_to_str((qmode == PSQ_GRANT) ? *privs & ~DB_GRANT_OPTION
					       : *privs,
	    buf, sess_cb->pss_lang);

	if (sess_cb->pss_dbp_flags & PSS_DBPROC)
	    sess_cb->pss_dbp_flags |= PSS_MISSING_PRIV;
	    
	if (qmode == PSQ_GRANT)
	{
	    if (cant_access)
	    {
		_VOID_ psf_error(E_US088F_2191_INACCESSIBLE_EVENT, 0L, 
		    PSF_USERERR, &err_code, err_blk, 3,
		    sizeof("GRANT") - 1, "GRANT",
		    psf_trmwhite(sizeof(DB_OWN_NAME), 
			(char *) &seq_info->pss_seqown), 
		    &seq_info->pss_seqown,
		    psf_trmwhite(sizeof(DB_NAME),
			(char *) &seq_info->pss_seqname),
		    &seq_info->pss_seqname);
	    }
	    else if (!grant_all)
	    {
		/* privileges were specified explicitly */
		_VOID_ psf_error(E_PS0551_INSUF_PRIV_GRANT_OBJ, 0L, PSF_USERERR,
		    &err_code, err_blk, 3,
		    STlength(buf), buf,
		    psf_trmwhite(sizeof(DB_NAME), 
			(char *) &seq_info->pss_seqname),
		    &seq_info->pss_seqname,
		    psf_trmwhite(sizeof(DB_OWN_NAME), 
			(char *) &seq_info->pss_seqown),
		    &seq_info->pss_seqown);
	    }
	    else if (save_privs == *privs)
	    {
		/* user entered GRANT ALL [PRIVILEGES] */
		_VOID_ psf_error(E_PS0563_NOPRIV_ON_GRANT_EV, 0L, PSF_USERERR,
		    &err_code, err_blk, 2,
		    psf_trmwhite(sizeof(DB_NAME), 
			(char *) &seq_info->pss_seqname),
		    &seq_info->pss_seqname,
		    psf_trmwhite(sizeof(DB_OWN_NAME), 
			(char *) &seq_info->pss_seqown),
		    &seq_info->pss_seqown);
	    }
	}
	else if (   sess_cb->pss_dbp_flags & PSS_DBPROC
		 && sess_cb->pss_dbp_flags & PSS_0DBPGRANT_CHECK)
	{
	    /*
	    ** if we were processing a dbproc definition to determine if it
	    ** is grantable, record those of required privileges which the
	    ** current user does not posess
	    */

	    _VOID_ psf_error(E_PS0557_DBPGRANT_LACK_EVPRIV, 0L, PSF_USERERR,
		&err_code, err_blk, 4,
		psf_trmwhite(sizeof(DB_NAME), (char *) &seq_info->pss_seqname),
		&seq_info->pss_seqname,
		psf_trmwhite(sizeof(DB_OWN_NAME), 
		    (char *) &seq_info->pss_seqown),
		&seq_info->pss_seqown,
		psf_trmwhite(sizeof(DB_DBP_NAME), 
		    (char *) sess_cb->pss_dbpgrant_name),
		sess_cb->pss_dbpgrant_name,
		STlength(buf), buf);

	    status = psy_insert_objpriv(sess_cb, &seq_info->pss_seqid,
		PSQ_OBJTYPE_IS_SEQUENCE | PSQ_MISSING_PRIVILEGE,
		save_privs & *privs, sess_cb->pss_dependencies_stream,
		&sess_cb->pss_indep_objs.psq_objprivs, err_blk);
	}
	else
	{
	    char	*op;

	    op = "NEXT VALUE";	/* only one possible */

	    _VOID_ psf_error(E_PS0D3D_MISSING_SEQUENCE_PRIV, 0L, PSF_USERERR,
		&err_code, err_blk, 4, 
		STlength(op), op, 
		STlength(buf), buf,
		psf_trmwhite(sizeof(DB_NAME), 
		    (char *) &seq_info->pss_seqname),
		&seq_info->pss_seqname,
		psf_trmwhite(sizeof(DB_OWN_NAME), 
		    (char *) &seq_info->pss_seqown),
		&seq_info->pss_seqown);
	}
    }
	    
seqperm_exit:
    /* Close iiprotect system catalog */
    if (rdf_rb->rdr_rec_access_id != NULL)
    {
	DB_STATUS	stat;

	rdf_rb->rdr_update_op = RDR_CLOSE;
	stat = rdf_call(RDF_READTUPLES, (PTR) rdf_cb);
	if (DB_FAILURE_MACRO(stat))
	{
	    _VOID_ psf_rdf_error(RDF_READTUPLES, &rdf_cb->rdf_error, err_blk);

	    if (stat > status)
	    {
		status = stat;	
	    }
	}
    }
    /*
    ** If user does not have privs we need to audit that they failed to perform
    ** the action on the event.
    */
    if ( *privs && Psf_srvblk->psf_capabilities & PSF_C_C2SECURE )
    {
	i4		msg_id;
	i4		accessmask = SXF_A_FAIL;

	/* determin action */
	switch (qmode)
	{
	    default: 
		accessmask |= SXF_A_RAISE;
		msg_id = I_SX2704_RAISE_DBEVENT;
		break;
	}
/*	stat = psy_secaudit(FALSE, sess_cb, 
		ev_info->pss_alert_name.dba_alert.db_name, 
		&ev_info->pss_alert_name.dba_owner,
		sizeof(ev_info->pss_alert_name.dba_alert.db_name),
		SXF_E_EVENT, msg_id, accessmask, 
		(PTR)&ev_info->pss_evsecid,
		DB_SECID_TYPE,
		&e_error);
	if (stat > status)
	    status = stat;  */
    }
    return(status);
} /* psy_seqperm */
Beispiel #8
0
/*{
** Name: psy_gsequence	- Get description of a sequence from RDF.
**
** Description:
** 	This routine calls RDF to return the iisequence tuple for a sequence,
**	then moves certain columns into the PSS_SEQINFO structure for its caller.
**	It is used by psl to verify the existence of a sequence referenced in 
**	a sequence operation (next/current value) and return definition information.
**
** Inputs:
**	sess_cb				Pointer to session control block.
**	    .pss_user			User/owner of the event.
**	seq_own				Sequence owner (from syntax).
**	seq_name			Sequence name (from syntax).
**	seq_mask			flag field
**	    PSS_USRSEQ	    search for sequence owned by the current user
**	    PSS_DBASEQ	    search for sequence owned by the DBA
**				    (must not be set unless 
**				    (seq_mask & PSS_USRSEQ))
**	    PSS_INGSEQ	    search for sequence owned by $ingres
**                                  (must not be set unless
**                                  (seq_mask & PSS_USRSEQ))
**	    PSS_SEQ_BY_OWNER	    search for sequence owned by the specified 
**				    owner
**	    PSS_SEQ_BY_ID	    search for sequence by id
**		NOTE:		    PSS_USRSEQ <==> !PSS_SEQ_BY_OWNER
**				    PSS_SEQ_BY_ID ==> !PSS_SEQ_BY_OWNER
**				    PSS_SEQ_BY_ID ==> !PSS_USRSEQ
**	privs				Pointer to privilege bit map (if we're to
**					check privileges on this sequence) or NULL.
**	qmode				Query mode (for errors).
**	grant_all			Flag indicating GRANT ALL accompanied request.
**
** Outputs:
**	seq_info			Pointer to sequence information block
**	    .pss_seqname		Sequence name.
**	    .pss_owner			Sequence owner.
**	    .pss_seqid			Internal sequence ID.
**	    .pss_dt			Sequence value datatype.
**	    .pss_length			Sequence value length.
**	    .pss_secid			Sequence security ID.
**      err_blk
**	    .err_code			Filled in if an error happens:
**		E_US1914_SEQ_NOT_FOUND	  Cannot find sequence definition.
**		Generally, the error codes returned by RDF and QEU
**		qrymod processing routines are passed back to the caller
**		except where they are user errors (eg, sequence doesn't exist).
**
**	Returns:
**	    E_DB_OK, E_DB_WARN, E_DB_ERROR, E_DB_FATAL
**	Exceptions:
**	    none
**
** Side Effects:
**	none
**
** History:
**	18-mar-02 (inkdo01)
**	    Cloned from psy_gevent for sequence support.
**	21-feb-03 (inkdo01)
**	    Add seq_mask to control iisequence retrieval.
**	24-apr-03 (inkdo01)
**	    Reset IISEQUENCE ptr for secondary calls to RDF.
**	24-apr-03 (inkdo01)
**	    Fix "not found" message for "drop sequence".
**      09-Mar-2010 (coomi01) b123351
**          Block users from dropping dba sequences.
**      29-Apr-2010 (coomi01) b123638
**          Backout the above change, then put in a test
**          to prevent delete dba's sequence by non dba.  
**          This allows non-dba to find sequence for 
**          updating.
**	15-Oct-2010 (kschendel) SIR 124544
**	    Update psl-command-string call.
*/
DB_STATUS
psy_gsequence(
	PSS_SESBLK      *sess_cb,
	DB_OWN_NAME	*seq_own,
	DB_NAME		*seq_name,
	i4		seq_mask,
	PSS_SEQINFO	*seq_info,
	DB_IISEQUENCE	*seqp,
	i4		*ret_flags,
	i4		*privs,
	i4		qmode,
	i4		grant_all,
	DB_ERROR	*err_blk)
{
    DB_STATUS		status;
    RDF_CB		rdf_seq;	/* RDF for sequence */
    DB_IISEQUENCE	seqtuple;	/* sequence tuple to retrieve into */
    i4		err_code;
    bool	leave_loop = TRUE;

    *ret_flags = 0;

    /* First retrieve sequence tuple from RDF */
    if (seqp == NULL)
	seqp = &seqtuple;

    /* zero out RDF_CB and init common elements */
    pst_rdfcb_init(&rdf_seq, sess_cb);

    /* init relevant elements */
    {
	rdf_seq.rdf_rb.rdr_types_mask = RDR_BY_NAME;
	rdf_seq.rdf_rb.rdr_2types_mask = RDR2_SEQUENCE;
	MEmove(sizeof(DB_NAME), (PTR) seq_name, ' ',
	    sizeof(DB_NAME), (PTR) &rdf_seq.rdf_rb.rdr_name.rdr_seqname);
	STRUCT_ASSIGN_MACRO((*seq_own), rdf_seq.rdf_rb.rdr_owner);
    }
    
    rdf_seq.rdf_rb.rdr_update_op = RDR_OPEN;
    rdf_seq.rdf_rb.rdr_qtuple_count = 1;
    rdf_seq.rdf_rb.rdr_qrytuple = (PTR) seqp;

    do     		/* something to break out of */
    {
	status = rdf_call(RDF_GETINFO, (PTR) &rdf_seq);

	/*
	** if caller specified sequence owner name, or
	**    the sequence was found, or
	**    an error other than "sequence not found" was encountered,
	**  bail out
	*/
	if (   seq_mask & PSS_SEQ_BY_OWNER
	    || status == E_DB_OK
	    || rdf_seq.rdf_error.err_code != E_RD0013_NO_TUPLE_FOUND
	   )
	    break;

	/*
	** if sequence was not found, and
	**    - caller requested that DBA's sequences be considered, and
	**    - user is not the DBA,
	**    - check we are not attempting to destroy the sequence.
	** check if the sequence is owned by the DBA
	*/
	if ((qmode != PSQ_DSEQUENCE) &&
	       seq_mask & PSS_DBASEQ
	    && MEcmp((PTR) &sess_cb->pss_dba.db_tab_own, 
		   (PTR) &sess_cb->pss_user, sizeof(DB_OWN_NAME))
	   )
	{
	    STRUCT_ASSIGN_MACRO(sess_cb->pss_dba.db_tab_own,
				rdf_seq.rdf_rb.rdr_owner);
	    rdf_seq.rdf_rb.rdr_qtuple_count = 1;
	    rdf_seq.rdf_rb.rdr_qrytuple = (PTR) &seqtuple;
	    status = rdf_call(RDF_GETINFO, (PTR) &rdf_seq);
	    if (status == E_DB_OK)
		STRUCT_ASSIGN_MACRO(seqtuple, *seqp);
	}

	/*
	** if still not found, and
	**   - caller requested that sequences owned by $ingres be considered, and
	**   - user is not $ingres and
	**   - DBA is not $ingres,
	** check if the sequence is owned by $ingres
	*/
	if (   status != E_DB_OK
	    && rdf_seq.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND
	    && seq_mask & PSS_INGSEQ
	   )
	{
	    if (   MEcmp((PTR) &sess_cb->pss_user,
			 (PTR) sess_cb->pss_cat_owner,
			 sizeof(DB_OWN_NAME)) 
		&& MEcmp((PTR) &sess_cb->pss_dba.db_tab_own,
			 (PTR) sess_cb->pss_cat_owner,
			 sizeof(DB_OWN_NAME))
	       )
	    {
		STRUCT_ASSIGN_MACRO((*sess_cb->pss_cat_owner),
				    rdf_seq.rdf_rb.rdr_owner);
		rdf_seq.rdf_rb.rdr_qtuple_count = 1;
		rdf_seq.rdf_rb.rdr_qrytuple = (PTR) &seqtuple;
		status = rdf_call(RDF_GETINFO, (PTR) &rdf_seq);
		if (status == E_DB_OK)
		    STRUCT_ASSIGN_MACRO(seqtuple, *seqp);
	    }
	}

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

    if (status != E_DB_OK)
    {
	if (rdf_seq.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND)
	{
	    if (qmode == PSQ_ASEQUENCE || qmode == PSQ_DSEQUENCE)
	    {
		_VOID_ psf_error(6419L, 0L,
		    PSF_USERERR, &err_code, err_blk, 1,
		    psf_trmwhite(sizeof(*seq_name), 
		    (PTR)seq_name), (PTR)seq_name);
	    }
	    else /* must be DML currval/nextval request */
	    {
		char        qry[PSL_MAX_COMM_STRING];
		i4     qry_len;

		psl_command_string(qmode, sess_cb, qry, &qry_len);
		_VOID_ psf_error(6420L, 0L,
		    PSF_USERERR, &err_code, err_blk, 2,
		    qry_len, qry,
		    psf_trmwhite(sizeof(*seq_name), (char *) seq_name),
		    (PTR) seq_name);
	    }
	    if (sess_cb->pss_dbp_flags & PSS_DBPROC)
		sess_cb->pss_dbp_flags |= PSS_MISSING_OBJ;

	    *ret_flags |= PSS_MISSING_SEQUENCE;
	    status = E_DB_OK;
	}
	else /* some other error */
	{
	    _VOID_ psf_rdf_error(RDF_GETINFO, &rdf_seq.rdf_error, err_blk);
	}

	return (status);
    } /* If RDF did not return the sequence tuple */

    STRUCT_ASSIGN_MACRO(rdf_seq.rdf_rb.rdr_owner, (*seq_own));
					/* copy back successful owner */

    if (seq_info != NULL)
    {
	/* fill in a sequence descriptor */
	STRUCT_ASSIGN_MACRO(seqp->dbs_name, seq_info->pss_seqname);
	STRUCT_ASSIGN_MACRO(seqp->dbs_owner, seq_info->pss_seqown);
	STRUCT_ASSIGN_MACRO(seqp->dbs_uniqueid, seq_info->pss_seqid);
	seq_info->pss_dt = seqp->dbs_type;
	seq_info->pss_length = seqp->dbs_length;
	seq_info->pss_prec = seqp->dbs_prec;
    }

    /*
    ** if we are parsing a dbproc and the sequence which we have just looked up
    ** is owned by the dbproc's owner, we will add the sequence to the dbproc's
    ** independent object list unless it has already been added.
    ** Note that only sequences owned by the current user will be included into
    ** the list of independent objects.
    **
    ** NOTE: we do not build independent object list for system-generated
    **	     dbprocs
    */
    if (   sess_cb->pss_dbp_flags & PSS_DBPROC
	&& ~sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED
        && !MEcmp((PTR) &sess_cb->pss_user, (PTR) &seqp->dbs_owner,
		  sizeof(sess_cb->pss_user))
       )
    {
	status = pst_add_1indepobj(sess_cb, &seqp->dbs_uniqueid,
	    PSQ_OBJTYPE_IS_SEQUENCE, (DB_DBP_NAME *) NULL,
	    &sess_cb->pss_indep_objs.psq_objs, sess_cb->pss_dependencies_stream,
	    err_blk);

	if (DB_FAILURE_MACRO(status))
	{
	    return(status);
	}
    }
		  
    if (privs && *privs)
    {
	i4	    privs_to_find = *privs;

	status = psy_seqperm(&rdf_seq, &privs_to_find, sess_cb, seq_info, qmode,
	    grant_all, err_blk);
	if (DB_FAILURE_MACRO(status))
	{
	    return (status);
	}
	else if (privs_to_find)
	{
	    if (grant_all && *privs != privs_to_find)
	    {
		/*
		** if we are processing GRANT ALL and psy_seqperm() has
		** determined that the user may grant some but not all
		** privileges on the sequence, reset the privilege map
		** accordingly
		*/
		*privs &= ~(privs_to_find & ~((i4) DB_GRANT_OPTION));
	    }
	    else
	    {
		*ret_flags |= PSS_INSUF_SEQ_PRIVS;
		return(E_DB_OK);
	    }
	} /* If no permission */
    }

    return(E_DB_OK);

}
Beispiel #9
0
/*
** Name: psl_lm3_setlockparm_name() - perform semantic action for SETLOCKPARM
**				      production when the characteristic value
**				      has been specified as a string
**
** Input: 
**	sess_cb		    PSF session CB
**	    pss_distrib	    DB_3_DDB_SESS if distributed thread
**	    pss_stmt_flags  PSS_SET_LOCKMODE_SESS if SET LOCKMODE SESSION
**			    (distributed thread only)
**	    pss_object	    pointer to the root of a QSF object
**			    (of type (DMC_CB *) or (QEF_RCB *)).
**	char_type	    characteristic type
**	char_val	    value as specified by the user
**
** Output:
**	err_blk		    filled in if an error occurred
**	sess_cb		    PSF session CB
**	    pss_object	    characteristics of SETLOCKPARM filled in.
**
** Returns:
**	E_DB_{OK, ERROR, SEVERE}
**
** Side effects:
**	None
**
**  History:
**	07-mar-91 (andre)
**	    plagiarized from SETLOCKPARM production
**	21-apr-92 (barbara)
**	    Added support for Sybil.  For distributed thread, on
**	    SET LOCKMODE SESSION .. TIMEOUT we set timeout value
**	    specifically for QEF; all other options are passed to QEF
**	    in textual representation (see psl_lm5_setlockmode_distr) and
**	    are ignored in this function.
**      22-nov-1996 (dilma04)
**          Row-level locking project:
**          Add support for LEVEL=ROW.
**      24-jan-97 (dilma04)
**          Fix bug 80115: report an error if trying to specify row locking
**          for a system catalog or a table with 2k page size. 
**      12-feb-97 (dilma04)
**          Set Lockmode Cleanup:
**          Change readlock values according to new definitions.
**	25-feb-99 (hayke02)
**	    When setting row level locking in STAR, we now do not check
**	    if the lockmode scope is table. This was causing a SIGSEGV
**	    because dmc_cb had not been set. This change fixes bug 95490.
**	31-May-2006 (kschendel)
**	    Allow level=row for catalogs, no reason to exclude it.
**	15-Jan-2010 (stial01)
**	    SIR 121619 MVCC: Add lock level MVCC
*/
DB_STATUS
psl_lm3_setlockparm_name(
	i4	    char_type,
	char	    *char_val,
	PSS_SESBLK  *sess_cb,
	DB_ERROR    *err_blk)
{
    i4		err_code, err_no = 0L;
    DMC_CHAR_ENTRY	*chr;
    DM_DATA	    	*char_array;
    DMC_CB		*dmc_cb; 
    bool		not_distr = ~sess_cb->pss_distrib & DB_3_DDB_SESS;
    i4		*val, dummy;

    if (not_distr)
    {
    	char_array = &((DMC_CB *)sess_cb->pss_object)->dmc_char_array;
        dmc_cb = (DMC_CB *) sess_cb->pss_object;

    	if (char_array->data_in_size / sizeof (DMC_CHAR_ENTRY) ==
	    MAX_LOCKMODE_CHARS)
    	{
	    (VOID) psf_error(5931L, 0L, PSF_USERERR, &err_code, err_blk, 0);
	    return (E_DB_ERROR);	/* non-zero return means error */
    	}   

    	chr = (DMC_CHAR_ENTRY *)
	    ((char *) char_array->data_address + char_array->data_in_size);
	val = &chr->char_value;
    }
    else
    {
	val = &dummy;	
    }

    switch (char_type)
    {
	case LOCKLEVEL:
	    /*
	    ** Acceptable values for locklevel are "row", "page", "table",
	    ** "session", "system", "mvcc".
	    */
	    if (not_distr)
		chr->char_id = DMC_C_LLEVEL;

	    if (!STcompare(char_val, "page"))
	    {
		*val = DMC_C_PAGE;
	    }
	    else if (!STcompare(char_val, "session"))
	    {
		*val = DMC_C_SESSION;
	    }
	    else if (!STcompare(char_val, "system"))
	    {
		*val = DMC_C_SYSTEM;
	    }
	    else if (!STcompare(char_val, "table"))
	    {
		*val = DMC_C_TABLE;
	    }
            else if (!STcompare(char_val, "row")
		    || !STcompare(char_val, "mvcc"))
            {
                if (not_distr && (dmc_cb->dmc_sl_scope == DMC_SL_TABLE))
                {
                    DB_TAB_ID       *tabid = &dmc_cb->dmc_table_id;
                    PSS_RNGTAB      *tbl = &sess_cb->pss_auxrng.pss_rsrng;
 
		    if (tbl->pss_tabdesc->tbl_pg_type == DB_PG_V1)
                    {
                        (VOID) psf_error(E_PS03B0_ILLEGAL_ROW_LOCKING, 0L,
                            PSF_USERERR, &err_code, err_blk, 2,
			    STlength(char_val), char_val,
                            psf_trmwhite(sizeof(tbl->pss_tabname),
                                     (char *) &tbl->pss_tabname),
                            &tbl->pss_tabname);
                        return (E_DB_ERROR);
                    }
                }
  
		if (*char_val == 'r')
		    *val = DMC_C_ROW;
		else
		    *val = DMC_C_MVCC;
            }
	    else
	    {
		err_no = 5924L;
	    }
	    break;

	case READLOCK:
	    /*
	    ** Acceptable values for readlock are "nolock", "shared",
            ** "exclusive", "session", "system".
	    */
	    if (not_distr)
		chr->char_id = DMC_C_LREADLOCK;

	    if (!STcompare(char_val, "nolock"))
	    {
		*val = DMC_C_READ_NOLOCK; 
	    }
	    else if (!STcompare(char_val, "shared"))
	    {
                *val = DMC_C_READ_SHARE;
	    }
	    else if (!STcompare(char_val, "exclusive"))
	    {
		*val = DMC_C_READ_EXCLUSIVE; 
	    }
	    else if (!STcompare(char_val, "session"))
	    {
		*val = DMC_C_SESSION;
	    }
	    else if (!STcompare(char_val, "system"))
	    {
		*val = DMC_C_SYSTEM;
	    }
	    else
	    {
		err_no = 5925L;
	    }
	    break;

	case MAXLOCKS:
	    /*
	    ** Acceptable values for maxlocks are "session", "system".
	    */
	    if (not_distr)
		chr->char_id = DMC_C_LMAXLOCKS;

	    if (!STcompare(char_val, "session"))
	    {
		*val = DMC_C_SESSION;
	    }
	    else if (!STcompare(char_val, "system"))
	    {
		*val = DMC_C_SYSTEM;
	    }
	    else
	    {
		err_no = 5926L;
	    }
	    break;

	case TIMEOUT:
	    /*
	    ** Acceptable values for timeout are "session" , "system",
	    ** and "nowait".
	    */
	    if (not_distr)
	    {
		chr->char_id = DMC_C_LTIMEOUT;
	    }
	    else if (sess_cb->pss_stmt_flags & PSS_SET_LOCKMODE_SESS)
	    {
		/*
		** The distributed server is interested in the value from 
		** the SETLOCKKEY production when the SETLOCKSCOPE value
		** is session.
		*/
		val =
	&((QEF_RCB *)sess_cb->pss_object)->qef_r3_ddb_req.qer_d14_ses_timeout;
	    }

	    if (!STcompare(char_val, "session"))
	    {
		*val = DMC_C_SESSION;
	    }
	    else if (!STcompare(char_val, "system"))
	    {
		*val = DMC_C_SYSTEM;
	    }
	    else if (!STcompare(char_val, "nowait"))
	    {
		*val = DMC_C_NOWAIT;
	    }
	    else
	    {
		err_no = 5927L;
	    }
	    break;

	default:
	    /* Unknown "set lockmode" parameter */
	    (VOID) psf_error(E_PS0351_UNKNOWN_LOCKPARM, 0L, PSF_INTERR, 
		&err_code, err_blk, 1,
		(i4) sizeof(char_type), &char_type);
	    return (E_DB_SEVERE);    /* non-zero return means error */
    }

    if (err_no != 0L)
    {
	(VOID) psf_error(err_no, 0L, PSF_USERERR, &err_code, err_blk, 1,
	    (i4) STlength(char_val), char_val);
	return (E_DB_ERROR);	/* non-zero return means error */
    }
    else
    {
	if (not_distr)
	    char_array->data_in_size += sizeof (DMC_CHAR_ENTRY);
    }

    return(E_DB_OK);
}
Beispiel #10
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 #11
0
/*{
** Name: psy_drop_synonym - Drop an IISYNONYM tuple.
**
** Description:
**	Call RDF_UPDATE to delete a tuple from IISYNONYM.
** Inputs:
**	psy_cb		PSY control block.
**	sess_cb		PSF session control block.
** Outputs:
**	Exceptions:
**	    none
** Returns:
**	E_DB_OK			synonym tuple has been deleted 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 table infoblk from RDF's cache.
**	10-aug-93 (andre)
**	    fixed causes of compiler warnings
**	13-sep-93 (andre)
**	    QEF will assume responsibility for altering timestamps of tables
**	    (or underlying tables of views) synonym(s) on which have been 
**	    dropped.  We will supply QEF with the id of the object on which 
**	    the synonym was defined
**	22-oct-93 (andre)
**	    In the unlikely event that RDF's cache entry for the synonym named 
**	    in the DROP SYNONYM statement is stale and the synonym no longer 
**	    exists, RDF will return E_RD014A_NONEXISTENT_SYNONYM which we will 
**	    translate into 2753L
*/
DB_STATUS
psy_drop_synonym(
	PSY_CB	   *psy_cb,
	PSS_SESBLK *sess_cb)
{
    RDF_CB		rdf_cb;
    RDF_CB		rdf_inv_cb;
    DB_IISYNONYM	syn_tuple;
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    DB_STATUS		status;
    register i4	syn_count;
    i4		err_code;


    /* Initialize the RDF request block. */
    pst_rdfcb_init(&rdf_cb, sess_cb);
    pst_rdfcb_init(&rdf_inv_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_DELETE;
    rdf_rb->rdr_qrytuple = (PTR) &syn_tuple;
    rdf_rb->rdr_tabid.db_tab_base = DM_B_SYNONYM_TAB_ID;
    rdf_rb->rdr_tabid.db_tab_index = DM_I_SYNONYM_TAB_ID;

    MEmove(sizeof(DB_OWN_NAME), (char *)&sess_cb->pss_user, ' ',
           sizeof(DB_SYNOWN), (char *)&syn_tuple.db_synowner);

    for (syn_count = 0; syn_count < psy_cb->psy_numtabs; syn_count++)
    {
	/* store synonym name in the tuple */
	MEmove(sizeof(DB_TAB_NAME), (char *)(psy_cb->psy_tabname + syn_count),
	       ' ', sizeof(DB_SYNNAME), (char *)&syn_tuple.db_synname);
	
	syn_tuple.db_syntab_id.db_tab_base = 
	    psy_cb->psy_tables[syn_count].db_tab_base;
	
	syn_tuple.db_syntab_id.db_tab_index = 
	    psy_cb->psy_tables[syn_count].db_tab_index;

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

	if (DB_FAILURE_MACRO(status))
	{
	    if (rdf_cb.rdf_error.err_code == E_RD0144_DROP_SYNONYM)
	    {
		(VOID) psf_error(E_PS0456_DROP_SYN_ERROR, 0L, PSF_USERERR,
		    &err_code, &psy_cb->psy_error, 1,
		    psf_trmwhite(sizeof(DB_SYNNAME), 
			(char *) &syn_tuple.db_synname),
		    &syn_tuple.db_synname);
	    }
	    else if (rdf_cb.rdf_error.err_code == E_RD014A_NONEXISTENT_SYNONYM)
	    {
		/* 
		** looks like RDF cache entry was stale - tell user that 
		** synonym did not exist and proceed on to the next entry
		*/
		status = E_DB_OK;

		(VOID) psf_error(2753L, 0L, PSF_USERERR, &err_code,
		    &psy_cb->psy_error, 2,
		    sizeof("DROP SYNONYM") - 1, "DROP SYNONYM",
		    psf_trmwhite(sizeof(DB_SYNNAME), 
			(char *) &syn_tuple.db_synname),
		    &syn_tuple.db_synname);
		
		continue;
	    }
	    else
	    {
		(VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error,
		    &psy_cb->psy_error);
	    }
	    break;
	}


	STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[syn_count],
			    rdf_inv_cb.rdf_rb.rdr_tabid);
				
	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;
	}
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	sess_cb->pss_dbaname[dba_name_len] = EOS;
    }

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

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

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

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

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

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

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

    /*
    ** Allocate the YACC_CB.  
    */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    sess_cb->pss_create_compression = Psf_srvblk->psf_create_compression;

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

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

    return (E_DB_OK);
}
Beispiel #13
0
DB_STATUS
psy_calarm(
	PSY_CB	   *psy_cb,
	PSS_SESBLK *sess_cb)
{
    RDF_CB		rdf_cb;
    RDR_RB		*rdf_rb = &rdf_cb.rdf_rb;
    i4			textlen;		/* Length of query text */
    QSF_RCB		qsf_rb;
    DB_STATUS		status, loc_status;
    i4		err_code;
    DB_SECALARM		*alarm= &psy_cb->psy_tuple.psy_alarm;

    /* Fill in QSF request to lock text */
    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;

    /* Initialize RDF_CB */
    pst_rdfcb_init(&rdf_cb, sess_cb);
    rdf_rb->rdr_types_mask  = RDR_SECALM;	/* Alarm definition */
    rdf_rb->rdr_update_op   = RDR_APPEND;
    rdf_rb->rdr_qrytuple    = (PTR)&psy_cb->psy_tuple.psy_alarm; /* Alarm tuple */

    /*
    ** Get the query text from QSF.  QSF has stored the text 
    ** as a {nat, string} pair - maybe not be aligned.
    */
    STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id);
    status = qsf_call(QSO_INFO, &qsf_rb);
    if (status != E_DB_OK)
    {
	psf_error(E_PS0D19_QSF_INFO, qsf_rb.qsf_error.err_code,
		  PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	goto cleanup;
    }
    MEcopy((PTR)qsf_rb.qsf_root, sizeof(i4), (PTR)&textlen);
    rdf_rb->rdr_l_querytext	= textlen;
    rdf_rb->rdr_querytext	= ((char *)qsf_rb.qsf_root) + sizeof(i4);
    rdf_rb->rdr_tabid.db_tab_base=alarm->dba_objid.db_tab_base;

    /*
    ** Check type of alarm, and handle accordingly.
    ** Main difference is where/how subjects are handled:
    ** - Named alarms have a single subject, which has already been 
    **   resolved in psl. Alarms to public are handled here also
    ** - Anonymous alarms (old style) may have multiple subjects. These
    **   operate much like permits, and are split into several alarms, one
    **   for each subject.
    */
    if(STskipblank((char*)&alarm->dba_alarmname,
		sizeof(alarm->dba_alarmname)) ==NULL &&
	    (alarm->dba_subjtype==DBGR_USER ||
	     alarm->dba_subjtype==DBGR_APLID ||
	     alarm->dba_subjtype==DBGR_GROUP)
	)
    {
        PSY_USR		*psy_usr;
	u_char		*subj_name;
	i4		subj_name_len;
        u_char          delim_subj_name[DB_MAX_DELIMID];
	/*
	** Anonymous alarms.
	** We loop over each subject, updating the query text for
	** each subject and creating the alarm.
	*/
	psy_usr = (PSY_USR *) psy_cb->psy_usrq.q_next;
	do 
	{
	    subj_name = (u_char *) &psy_usr->psy_usrnm;
	    subj_name_len = 
		(i4) psf_trmwhite(sizeof(psy_usr->psy_usrnm), 
		    (char *) subj_name);
	    if (~psy_usr->psy_usr_flags & PSY_REGID_USRSPEC)
	    {
		status = psl_norm_id_2_delim_id(&subj_name, 
		    &subj_name_len, delim_subj_name, 
		    &psy_cb->psy_error);
		if (DB_FAILURE_MACRO(status))
			return status;
	    }
	    if (subj_name_len < DB_MAX_DELIMID)
		subj_name[ subj_name_len ] = EOS;
	    STmove((char*)subj_name, ' ', DB_MAX_DELIMID,
		  rdf_rb->rdr_querytext + psy_cb->psy_noncol_grantee_off);

            STmove((char*)subj_name, ' ', sizeof(alarm->dba_subjname),
		(char*)&alarm->dba_subjname);
			
	    /* Reset alarm name in case filled in by RDF/QEF */
	    MEfill(sizeof(alarm->dba_alarmname), ' ',
		    (PTR)&alarm->dba_alarmname);


	    /* Create a new alarm in iisecalarm */
	    status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);
	    if (status != E_DB_OK)
	    {
		if (   rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL)
		{
		    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);
	        }
		goto cleanup;
	    } /* If RDF error */

	    /* Next subject */
	    psy_usr = (PSY_USR *) psy_usr->queue.q_next;
        } while (psy_usr != (PSY_USR *) &psy_cb->psy_usrq);
    }
    else
    {
	/* Named alarms */
	/* Create a new alarm in iisecalarm */
	status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);
	if (status != E_DB_OK)
	{
	    if (   rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL)
	    {
		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);
	    }
	    goto cleanup;
	} /* If RDF error */
    }

cleanup:
    qsf_rb.qsf_lk_state	= QSO_EXLOCK;

    /* Destroy query text - lock it first */
    STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id);
    loc_status = qsf_call(QSO_LOCK, &qsf_rb);
    if (loc_status != E_DB_OK)
    {
	psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code,
		  PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	if (loc_status > status)
	    status = loc_status;
    }
    loc_status = qsf_call(QSO_DESTROY, &qsf_rb);
    if (loc_status != E_DB_OK)
    {
	psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code,
		  PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	if (loc_status > status)
	    status = loc_status;
    }

    /* Invalidate tableinfo from RDF cache if table object */
    if(psy_cb->psy_gtype==DBOB_TABLE)
    {
        pst_rdfcb_init(&rdf_cb, sess_cb);
        STRUCT_ASSIGN_MACRO(alarm->dba_objid, rdf_rb->rdr_tabid);
        loc_status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb);
        if (DB_FAILURE_MACRO(loc_status))
        {
	    (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error,
				&psy_cb->psy_error);
	    if (loc_status > status)
	        status = loc_status;
	}
    }
    return (status);
} /* psy_calarm */
Beispiel #14
0
/*
** Name: psl_lm4_setlockparm_num()  - perform semantic action for SETLOCKPARM
**				      production when the characteristic value
**				      has been specified as a number or a string
**				      constant containing a number
**
** Input:
**	char_type		    characteristic type
**	char_val		    value as specified by the user
**	sess_cb			    PSF session CB
**	    pss_distrib	    	    DB_3_DDB_SESS if distributed thread
**	    pss_stmt_flags  	    PSS_SET_LOCKMODE_SESS if SET LOCKMODE
**				    SESSION (distributed thread only)
**	    pss_object		    points to DMC_CB (or QEF_RCB) structure
**		dmc_char_array	    characteristics array
**		dmc_sl_scope	    scope of SET LOCKMODE
**	    pss_auxrng
**		pss_rerng	    if setting lockmode on a table, table's
**				    description can be found here
**
** Output:
**	err_blk		    filled in if an error occurred
**
** Returns:
**	E_DB_{OK, ERROR, SEVERE}
**
** Side effects:
**	None
**
**  History:
**	07-mar-91 (andre)
**	    plagiarized from SETLOCKPARM production
**	21-apr-92 (barbara)
**	    Added support for Sybil.  For distributed thread, on
**	    SET LOCKMODE SESSION .. TIMEOUT we set timeout value
**	    specifically for QEF.
**	19-oct-92 (barbara)
**	    Test for non_distrib before testing dmc_cb fields (because
**	    Star doesn't have valid dmc_cb).
*/
DB_STATUS
psl_lm4_setlockparm_num(
	i4	    char_type,
	i4	    char_val,
	PSS_SESBLK  *sess_cb,
	DB_ERROR    *err_blk)
{
    i4		err_code, err_no = 0L;
    DMC_CHAR_ENTRY	*chr;
    DMC_CB		*dmc_cb;
    bool		not_distr = ~sess_cb->pss_distrib & DB_3_DDB_SESS;


    if (not_distr)
    {
    	dmc_cb = (DMC_CB *) sess_cb->pss_object;

    	if (dmc_cb->dmc_char_array.data_in_size / sizeof (DMC_CHAR_ENTRY) ==
	    MAX_LOCKMODE_CHARS)
    	{
	    (VOID) psf_error(5931L, 0L, PSF_USERERR, &err_code, err_blk, 0);
	    return (E_DB_ERROR);	/* non-zero return means error */
    	}   

        chr = (DMC_CHAR_ENTRY *)
	    ((char *) dmc_cb->dmc_char_array.data_address +
	     dmc_cb->dmc_char_array.data_in_size);
    }

    switch (char_type)
    {
	case LOCKLEVEL:
	    /* Can't set locklevel to a number */
	    err_no = 5924L;
	    break;

	case READLOCK:
	    /* Can't set readlocks to a number */
	    err_no = 5925L;
	    break;

	case MAXLOCKS:
	    if (not_distr)	
	    {
	    	chr->char_id = DMC_C_LMAXLOCKS;
	    }
	    break;

	case TIMEOUT:
	{
	    extern PSF_SERVBLK  *Psf_srvblk;

	    /*
	    ** if server was started with OPF flag which may result in
	    ** deadlock when accesing SCONSUR catalogs, iihistogram, and
	    ** iistatistics, we have to prevent user from specifying
	    ** TIMEOUT=0 for any of these catalogs
	    */

	    if (not_distr &&
		Psf_srvblk->psf_flags & PSF_NO_ZERO_TIMEOUT &&
		dmc_cb->dmc_sl_scope == DMC_SL_TABLE) 
	    {
		DB_TAB_ID	*tabid = &dmc_cb->dmc_table_id;
		PSS_RNGTAB	*tbl = &sess_cb->pss_auxrng.pss_rsrng;
		i4		mask = tbl->pss_tabdesc->tbl_status_mask;

		if (mask & DMT_CATALOG
		    &&
		    char_val == 0L
		    &&
		    (mask & DMT_CONCURRENCY
		     ||
		     tabid->db_tab_base == DM_B_STATISTICS_TAB_ID &&
		     tabid->db_tab_index == DM_I_STATISTICS_TAB_ID
		     ||
		     tabid->db_tab_base == DM_B_HISTOGRAM_TAB_ID  &&
		     tabid->db_tab_index == DM_I_HISTOGRAM_TAB_ID
		    )
		   )
		{
		    (VOID) psf_error(E_PS0352_ILLEGAL_0_TIMEOUT, 0L,
			PSF_USERERR, &err_code, err_blk, 1,
			psf_trmwhite(sizeof(tbl->pss_tabname),
				     (char *) &tbl->pss_tabname),
			&tbl->pss_tabname);
		    return (E_DB_ERROR);
		}
	    }
	    
	    if (not_distr)
	    {
	    	chr->char_id = DMC_C_LTIMEOUT;
	    }
	    else if (sess_cb->pss_stmt_flags & PSS_SET_LOCKMODE_SESS)
	    {
	    	/*
	    	** The distributed server is interested in the value from 
	    	** the SETLOCKKEY production when the SETLOCKSCOPE value
	    	** was session; otherwise the set statement is just
	    	** pased on to the LDBs.
	    	*/
		((QEF_RCB*)sess_cb->pss_object)->qef_r3_ddb_req.
			qer_d14_ses_timeout = char_val;
	    }
	    break;
	}

	default:
	    /* Unknown "set lockmode" parameter */
	    (VOID) psf_error(E_PS0351_UNKNOWN_LOCKPARM, 0L, PSF_INTERR, 
		&err_code, err_blk, 1,
		(i4) sizeof(char_type), &char_type);
	    return (E_DB_SEVERE);    /* non-zero return means error */
    }

    if (err_no != 0L)
    {
	char	num_buf[30];

	CVla((i4) char_val, num_buf);
	(VOID) psf_error(err_no, 0L, PSF_USERERR, &err_code, err_blk, 1,
	    (i4) STlength(num_buf), num_buf);
	return (E_DB_ERROR);    /* non-zero return means error */
    }
    else if (not_distr)
    {
	chr->char_value = char_val;
	dmc_cb->dmc_char_array.data_in_size += sizeof (DMC_CHAR_ENTRY);
    }

    return(E_DB_OK);
}
Beispiel #15
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 #16
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 #17
0
/*
** NOTE: in SQL grammar target_list of a subselect is processed BEFORE the
**	 from_list; consequently, data types of target list elements are not
**	 known when we build RESDOM nodes for the target list elements of form
**	 [<corr_name>.]<col_name>.  In psl_p_tlist(), we revisit the prototype
**	 tree and fill in the newly available information (type, length,
**	 precision, etc.)
**
**	 When making changes to pst_adresdom(), please take time to understand
**	 the effect these changes may have on the processing of prototype trees.
*/
DB_STATUS
pst_adresdom(
	char               *attname,
	PST_QNODE	   *left,
	PST_QNODE	   *right,
	PSS_SESBLK	   *cb,
	PSQ_CB		   *psq_cb,
	PST_QNODE	   **newnode)
{
    DB_STATUS           status;
    DMT_ATT_ENTRY	*coldesc;
    DMT_ATT_ENTRY	column;
    PSS_RNGTAB		*resrange;
    char		colname[sizeof(DB_ATT_NAME) + 1];   /* null term. */
    PST_RSDM_NODE	resdom;
    i4		err_code;
    PSC_RESCOL		*rescol;
    ADF_CB	*adf_scb;
    i2          null_adjust = 0;
    i4			temp_collID;

    /* Convert column name to a null-terminated string. */
    (VOID) MEcopy((PTR) attname, sizeof(DB_ATT_NAME), (PTR) colname);
    colname[sizeof(DB_ATT_NAME)] = '\0';
    (VOID) STtrmwhite(colname);

    /* For these operations, the result domain comes from the result table */
    if (psq_cb->psq_mode == PSQ_APPEND || psq_cb->psq_mode == PSQ_PROT)
    {
	/* Get the result range variable */
	if (psq_cb->psq_qlang == DB_SQL)
	{
	    resrange = &cb->pss_auxrng.pss_rsrng;
	}
	else
	{
	    resrange = &cb->pss_usrrange.pss_rsrng;
	}

	/* "tid" result column not allowed with these operations */
	if (!STcasecmp(((*cb->pss_dbxlate & CUI_ID_REG_U) ? "TID" : "tid"),
			colname ))
	{
	    psf_error(2100L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4,
		(i4) sizeof(cb->pss_lineno), &cb->pss_lineno, 
		psf_trmwhite(sizeof(DB_TAB_NAME), 
		    (char *) &resrange->pss_tabname),
		&resrange->pss_tabname,
		psf_trmwhite(sizeof(DB_OWN_NAME), 
		    (char *) &resrange->pss_ownname),
		&resrange->pss_ownname,
		psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname);
	    return (E_DB_ERROR);
	}

	/* Get the column description */
	coldesc = pst_coldesc(resrange, (DB_ATT_NAME *) attname);
	if (coldesc == (DMT_ATT_ENTRY *) NULL)
	{
	    psf_error(2100L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4,
		(i4) sizeof(cb->pss_lineno), &cb->pss_lineno,
		psf_trmwhite(sizeof(DB_TAB_NAME), 
		    (char *) &resrange->pss_tabname),
		&resrange->pss_tabname,
		psf_trmwhite(sizeof(DB_OWN_NAME), 
		    (char *) &resrange->pss_ownname),
		&resrange->pss_ownname,
		psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname);
	    return (E_DB_ERROR);
	}
	if (coldesc->att_flags & DMU_F_SYS_MAINTAINED)
	{
	    psf_error(E_US1900_6400_UPD_LOGKEY, 0L, PSF_USERERR, 
		&err_code, &psq_cb->psq_error, 4,
		(i4) sizeof(cb->pss_lineno), &cb->pss_lineno,
		psf_trmwhite(sizeof(DB_TAB_NAME), 
		    (char *) &resrange->pss_tabname),
		&resrange->pss_tabname,
		psf_trmwhite(sizeof(DB_OWN_NAME), 
		    (char *) &resrange->pss_ownname),
		&resrange->pss_ownname,
		psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname);

	    return (E_DB_ERROR);
	}
    }
    else if (psq_cb->psq_mode == PSQ_REPLACE)
    {
	/*
	** For the "replace" command, use the result range variable that's
	** in the normal user range table, not the special slot that's
	** reserved for the result table in the append command.
	*/
	/* Get the result range variable */
	resrange = cb->pss_resrng;

	/* "tid" result column not allowed with these operations */
	if (!STcasecmp(((*cb->pss_dbxlate & CUI_ID_REG_U) ? "TID" : "tid"),
			colname))
	{
	    psf_error(2100L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4,
		(i4) sizeof(cb->pss_lineno), &cb->pss_lineno,
		psf_trmwhite(sizeof(DB_TAB_NAME), 
		    (char *) &resrange->pss_tabname),
		&resrange->pss_tabname,
		psf_trmwhite(sizeof(DB_OWN_NAME), 
		    (char *) &resrange->pss_ownname),
		&resrange->pss_ownname,
		psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname);
	    return (E_DB_ERROR);
	}

	/* Get the column description */
	coldesc = pst_coldesc(resrange, (DB_ATT_NAME *) attname);
	if (coldesc == (DMT_ATT_ENTRY *) NULL)
	{
	    psf_error(2100L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4,
		(i4) sizeof(cb->pss_lineno), &cb->pss_lineno,
		psf_trmwhite(sizeof(DB_TAB_NAME), 
		    (char *) &resrange->pss_tabname),
		&resrange->pss_tabname,
		psf_trmwhite(sizeof(DB_OWN_NAME), 
		    (char *) &resrange->pss_ownname),
		&resrange->pss_ownname,
		psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname);
	    return (E_DB_ERROR);
	}

	if (coldesc->att_flags & DMU_F_SYS_MAINTAINED)
	{
	    psf_error(E_US1900_6400_UPD_LOGKEY, 0L, PSF_USERERR, 
		&err_code, &psq_cb->psq_error, 4,
		(i4) sizeof(cb->pss_lineno), &cb->pss_lineno,
		psf_trmwhite(sizeof(DB_TAB_NAME), 
		    (char *) &resrange->pss_tabname),
		&resrange->pss_tabname,
		psf_trmwhite(sizeof(DB_OWN_NAME), 
		    (char *) &resrange->pss_ownname),
		&resrange->pss_ownname,
		psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname);

	    return (E_DB_ERROR);
	}
    }
    else if (psq_cb->psq_mode == PSQ_REPCURS)
    {
	/*
	** For the "replace cursor" command, the info comes from the cursor 
	** control block. Cursor column list and update map should always 
	** specify same column set, so the second if statemnt (BTtest) could,
	** perhaps, be removed.
	*/
	rescol = psq_ccol(cb->pss_crsr, (DB_ATT_NAME *) attname);
	if (rescol == (PSC_RESCOL *) NULL)
	{
	    psf_error(2207L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 3,
		sizeof(cb->pss_lineno), &cb->pss_lineno,
		psf_trmwhite(DB_CURSOR_MAXNAME,
			cb->pss_crsr->psc_blkid.db_cur_name),
		cb->pss_crsr->psc_blkid.db_cur_name,
		psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname);
	    return (E_DB_ERROR);
	}

	/* Make sure the column was declared "for update" */
	if (!BTtest((i4) rescol->psc_attid.db_att_id,
	    (char *) &cb->pss_crsr->psc_updmap))
	{
	    psf_error(2207L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 3,
		sizeof(cb->pss_lineno), &cb->pss_lineno,
		psf_trmwhite(DB_CURSOR_MAXNAME, 
			cb->pss_crsr->psc_blkid.db_cur_name),
		cb->pss_crsr->psc_blkid.db_cur_name,
		psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname);
	    return (E_DB_ERROR);
	}

	/* Set up column descriptor */
	coldesc = &column;
	MEcopy((char *) attname, sizeof(DB_ATT_NAME),
	    (char *) &coldesc->att_name);

#ifdef NO
	/*
	** Count columns.  Give error if too many.  One extra for tid.
	*/
	cb->pss_rsdmno++;
	if (cb->pss_rsdmno > (DB_MAX_COLS + 1))
	{
	    psf_error(2130L, 0L, PSF_USERERR, &err_code,
		&psq_cb->psq_error, 1, (i4) sizeof(cb->pss_lineno),
		&cb->pss_lineno);
	    return (E_DB_ERROR);
	}
	coldesc->att_number = cb->pss_rsdmno;
#endif

	coldesc->att_number	= rescol->psc_attid.db_att_id;
	coldesc->att_type	= rescol->psc_type;
	coldesc->att_width	= rescol->psc_len;
	coldesc->att_prec	= rescol->psc_prec;
	coldesc->att_collID	= -1;
	coldesc->att_geomtype = -1;
	coldesc->att_srid = -1;
	coldesc->att_encflags = 0;
	coldesc->att_encwid = 0;
    }
    else
    {
	/*
	** In all other cases, just take the datatype info
	** from the right child.
	*/
	coldesc = &column;
	MEcopy((char *) attname, sizeof(DB_ATT_NAME),
	    (char *) &coldesc->att_name);

	/*
	** Count columns.  Give error if too many.  One extra for tid.
	*/
	cb->pss_rsdmno++;
	if (cb->pss_rsdmno > (DB_MAX_COLS + 1))
	{
	    psf_error(2130L, 0L, PSF_USERERR, &err_code,
		&psq_cb->psq_error, 1, (i4) sizeof(cb->pss_lineno),
		&cb->pss_lineno);
	    return (E_DB_ERROR);
	}
	coldesc->att_number = cb->pss_rsdmno;

	status = pst_rsdm_dt_resolve(right, coldesc, cb, psq_cb);
	if (DB_FAILURE_MACRO(status))
	    return(status);
    }

    /* Copy attribute information into PST_RSDM_NODE */
    resdom.pst_rsno = coldesc->att_number;
    /* The two fields below are initialized for a common case.
    ** They are context sensitive and in many cases may have to be
    ** modified by the caller of this routine.
    */
    resdom.pst_ntargno = resdom.pst_rsno;
    resdom.pst_ttargtype = PST_USER;
    resdom.pst_dmuflags  = 0;
    /* Don't bother with the conversion id for now */
    /* Not for update until we know otherwise */
    resdom.pst_rsupdt = FALSE;
    resdom.pst_rsflags = PST_RS_PRINT;
    MEcopy((char *) &coldesc->att_name, sizeof(DB_ATT_NAME),
	(char *) resdom.pst_rsname);
    temp_collID = coldesc->att_collID;

    /* If client can not handle i8 INTs downgrade to i4 */
    adf_scb = (ADF_CB *) cb->pss_adfcb;
    if ( !(adf_scb->adf_proto_level & AD_I8_PROTO) && (abs(coldesc->att_type) == DB_INT_TYPE) )
    {
        if(coldesc->att_type < 0)
        {
            null_adjust = 1;
        }
        if((coldesc->att_width - null_adjust) == sizeof(i8))
        {
            coldesc->att_width -= sizeof(i4);
        }
    }

    /* Now allocate the node */
    status = pst_node(cb, &cb->pss_ostream, left, right, PST_RESDOM,
	(char *) &resdom, sizeof(PST_RSDM_NODE), (DB_DT_ID) coldesc->att_type,
	(i2) coldesc->att_prec, (i4) coldesc->att_width, (DB_ANYTYPE *) NULL,
	newnode, &psq_cb->psq_error, (i4) 0);
    if (status != E_DB_OK)
    {
	return (status);
    }

    (*newnode)->pst_sym.pst_dataval.db_collID = temp_collID;
    /* Remember the last result domain produced */
    cb->pss_tlist = *newnode;
    return (E_DB_OK);
}
Beispiel #18
0
/*{
** Name: psy_kpermit	- Destroy one or more permits on a database object
**			  (a table or a procedure or an event).
**
**  INTERNAL PSF call format: status = psy_kpermit(&psy_cb, &sess_cb);
**
**  EXTERNAL call format:     status = psy_call(PSY_KPERMIT, &psy_cb, &sess_cb);
**
** Description:
**      The psy_kpermit function removes the definition of one or more permits 
**      on a table, a procedure, or an event from all system relations
**	(protect, tree, and iiqrytext).
**	Optionally, one can tell this function to destroy all of the permits
**	on a given table, procedure or event.
**
**	Dropping all permits on a table is similar enough to dropping those on
**	a procedure, so we will handle them together.  On the other hand, when
**	permit numbers are specified, processing is somewhat differen, e.g.
**	we (at least for now) disallow dropping 0 and 1 on a dbproc.
**	Events follow exactly the same model as procedures.
** Inputs:
**      psy_cb
**          .psy_tables[0]              Id of table for which to destroy
**					permit(s)
**          .psy_numbs[]                Id numbers of the permits to destroy
**					(20 maximum)
**          .psy_numnms                 Number of permit numbers given.  Zero
**					means to destroy all of the permits on
**					the given table.
**	    .psy_tabname[0]		Name of the table for which to destroy
**					permit(s)
**	    .psy_grant			PSY_PDROP if dropping permits on
**					dbproc(s);
**					PSY_TDROP if dropping permits on
**					table(s).
**					PSY_SDROP if dropping security alarms.
**					PSY_EVDROP if dropping permits on
**					event(s).
**	sess_cb				Pointer to session control block.
**
** 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:
**	    Deletes query tree representing predicate of permit from tree
**	    relation, query text of permit definition from iiqrytext relation,
**	    does a dmf alter table on the base table to indicate that there
**	    are no more permissions on it should that happen to be the case.
**	    
** History:
**	02-oct-85 (jeff)
**          written
**	05-aug-88 (andre)
**	    modified for DROPping permits on dbprocs.
**	03-oct-88 (andre)
**	    Modify call to pst_rgent to pass 0 as a query mode since it is
**	    clearly not PSQ_DESTROY.
**	04-oct-88 (andre)
**	    Make sure that the highest status received is reported to caller
**	02-nov-89 (neil)
**	    Alerters: Changes for dropping permits on events.
**	16-jan-90 (ralph)
**	    Add integrity check for DROP PERMIT/SECURITY_ALARM:
**	    don't allow drop permit to drop a security alarm;
**	    don't allow drop security_alarm to drop a permit.
**	    Initialise status to E_DB_OK.
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
**	04-feb-91 (neil)
**	    Fix 2 error cases:
**	    1. If pst_rgent returns E_PS0903_TAB_NOTFOUND then return this
**	       error to the user.  Can happen through Dynamic SQL where you
**	       drop the table before you exec the statement that drops grant.
**	    2. Allow E_RD0025_USER_ERROR from RDF_UPDATE and continue.
**	29-aug-91 (andre)
**	    Do not call RDF to destroy permits if the object is a QUEL view
**	    owned by the DBA.
**
**	    Until now we could safely assume that if a view is non-grantable and
**	    there are permits defined on it, then the view is a QUEL view owned
**	    by the DBA and the only permit defined on it is an access permit.
**	    With advent of GRANT WGO, there may be permits defined on views
**	    marked as non-grantable (since "grantable" means that the view is
**	    defined on top of the objects owned by its owner so that its owner
**	    can always grant access to the view) and grantable QUEL views will
**	    be marked as such (this way if a user creates an SQL view on top of
**	    his grantable QUEL view we are guaranteed that the new view is also
**	    grantable).  By not trying to destroy permits on QUEL views owned by
**	    the DBA we will ensure that a user cannot destroy an access permit
**	    which gets created for QUEL views owned by the DBA.
**	16-jun-92 (barbara)
**	    Change interface to pst_rgent.
**	22-jul-92 (andre)
**	    permits 0 and 1 will no longer hold special meaning for tables; in
**	    the past they meant ALL/RETRIEVE TO ALL, but with introduction of
**	    grantable privileges, they will no longer be created.  Whether
**	    permit numbers 0 and 1 will become available for regular permits
**	    needs to be decided, but one thing is for sure, psy_kpermit() will
**	    not need to know about it.
**
**	    If user is destroying all permits or security_alarms, set
**	    RDR_DROP_ALL over rdr_types_mask
**	27-jul-92 (andre)
**	    we may be told that we may not drop a permit or all permits because
**	    it would render some permit or object abandoned
**	03-aug-92 (barbara)
**	    Invalidate base table info from RDF cache.
**	07-aug-92 (teresa)
**	    RDF_INVALID must be called to invalidate the base object from RDF's
**	    relation cache as well as to remove any permit trees from RDF's
**	    qtree cache.
**	08-nov-92 (andre)
**	    having dropped ALL permits on PROCEDURE, remember to set
**	    RDR_PROCEDURE in rdf_inv_cb.rdf_rb.rdr_types_mask before calling
**	    RDF_INVALIDATE
**	26-apr-93 (markg)
**	    Fixed bug which caused AV when attempting to drop a 
**	    security_alarm. The problem was caused by incorrectly
**	    referencing a NULL pointer when initializing a local variable. 
**	10-aug-93 (andre)
**	    fixed cause of compiler warning
**	13-sep-93 (andre)
**	    PSF will no longer be in business of altering timestamps of tables
**	    (or underlying base tables of views) on which permit(s) or 
** 	    security_alarm(s) have been dropped - responsibility for this has 
** 	    been assumed by QEF
*/
DB_STATUS
psy_kpermit(
	PSY_CB             *psy_cb,
	PSS_SESBLK	   *sess_cb)
{
    RDF_CB              rdf_cb;
    RDF_CB              rdf_inv_cb;
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    DB_STATUS		status = E_DB_OK;
    i4		err_code;
    i4		msgid;
    register i4	i;
    PSS_RNGTAB		*rngvar;

    /* 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_inv_cb.rdf_rb.rdr_types_mask = RDR_PROTECT;

    rdf_rb->rdr_update_op = RDR_DELETE;

    if (psy_cb->psy_grant == PSY_TDROP)		/* dropping perm on a table */
    {
	/* get range table entry for this table */
	status = pst_rgent(sess_cb, &sess_cb->pss_auxrng, -1, "", PST_SHWID,
	    (DB_TAB_NAME*) NULL, (DB_TAB_OWN*) NULL, &psy_cb->psy_tables[0],
	    TRUE, &rngvar, (i4) 0, &psy_cb->psy_error);
	if (DB_FAILURE_MACRO(status))
	{
	    if (psy_cb->psy_error.err_code == E_PS0903_TAB_NOTFOUND)
	    {
		(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]);
	    }
	    return (status);
	}
	rdf_rb->rdr_types_mask = RDR_PROTECT;
    }
    else if (psy_cb->psy_grant == PSY_SDROP)	/* dropping security alarm  */
    {
	rdf_rb->rdr_types_mask = RDR_SECALM;
    }
    else if (psy_cb->psy_grant == PSY_PDROP)    /* dropping perm on a dbproc */
    {
	DB_DBP_NAME	*dbpname = (DB_DBP_NAME *) psy_cb->psy_tabname;

	/* save dbproc name and owner for RDF */

	STRUCT_ASSIGN_MACRO(*dbpname, rdf_rb->rdr_name.rdr_prcname); 
	STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner);
	
	rdf_rb->rdr_types_mask = RDR_PROTECT | RDR_PROCEDURE;
	rdf_inv_cb.rdf_rb.rdr_types_mask |= RDR_PROCEDURE;
    }
    else if (psy_cb->psy_grant == PSY_EVDROP)	    /* dropping perm on event */
    {
	DB_EVENT_NAME		*evname = (DB_EVENT_NAME *)psy_cb->psy_tabname;

	/* Save event name and owner for RDF */
	STRUCT_ASSIGN_MACRO(*evname, rdf_rb->rdr_name.rdr_evname); 
	STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner);
	rdf_rb->rdr_types_mask = RDR_PROTECT | RDR_EVENT;
    }

    /* Zero permit numbers means destroy all permits */
    
    if (psy_cb->psy_numnms == 0)
    {
	/*								
	** Note that this block handles destroying all permits on
	** a dbproc, event or a table or all security_alarms on a table
	*/

	/*
	** check if user may drop permits (access permits get special
	** treatment).  If not, we are done.
	*/
	if (psy_cb->psy_grant == PSY_TDROP)
	{
	    /*
	    ** if this is a QUEL view owned by the DBA, avoid calling RDF since
	    ** we need to rpevent a user from destroying access permit which is
	    ** created on such views.
	    */
	    if (   rngvar->pss_tabdesc->tbl_status_mask & DMT_VIEW
		&& !MEcmp((PTR) &sess_cb->pss_dba, (PTR) &rngvar->pss_ownname,
			sizeof(DB_OWN_NAME))
	       )
	    {
		/* check if this is a QUEL view */
		i4	    issql = 0;

		status = psy_sqlview(rngvar, sess_cb, &psy_cb->psy_error,
		    &issql);
		if (DB_FAILURE_MACRO(status))
		{
		    return(status);
		}

		if (!issql)
		{
		    return(E_DB_OK);
		}
	    }
	}
	
	/* tell RDF that we are dropping ALL permits or security_alarms */
	rdf_rb->rdr_types_mask |= RDR_DROP_ALL;

	status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);
	if (DB_FAILURE_MACRO(status))
	{
	    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_RD0201_PROC_NOT_FOUND:
		{
		    (VOID) psf_error(E_PS0905_DBP_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_RD0210_ABANDONED_OBJECTS:
		{
		    char	*obj_type;
		    i4		type_len;

		    switch (psy_cb->psy_grant)
		    {
			case PSY_TDROP:
			    obj_type = "table";
			    type_len = sizeof("table") - 1;
			    break;
			case PSY_PDROP:
			    obj_type = "database procedure";
			    type_len = sizeof("database procedure") - 1;
			    break;
			case PSY_EVDROP:
			    obj_type = "dbevent";
			    type_len = sizeof("dbevent") - 1;
			    break;
			default:
			    obj_type = "UNKNOWN OBJECT TYPE";
			    type_len = sizeof("UNKNOWN OBJECT TYPE") - 1;
			    break;
		    }
		    
		    (VOID) psf_error(E_PS0564_ALLPROT_ABANDONED_OBJ, 0L,
			PSF_USERERR, &err_code, &psy_cb->psy_error, 2,
			type_len, obj_type,
			psf_trmwhite(sizeof(psy_cb->psy_tabname[0]),
			    (char *) psy_cb->psy_tabname),
			psy_cb->psy_tabname);
		    break;
		}
		default: 
		{
		    /* Event errors are handled in QEF */
		    (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error,
					 &psy_cb->psy_error);
		}
	    }

	    return (status);
	}
	/*
	** Invalidate base object's infoblk from RDF cache; rdr_tabid
	** already contains base table id; Call RDF to invalidate the
	** base object. Then call again to invalidate any permit trees,
	** set rdr_2_types mask for tree.
	*/
	status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); /* drop infoblk */
	if (DB_FAILURE_MACRO(status))
	{
	    (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error,
				&psy_cb->psy_error);
	    return(status);
	}
	rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_CLASS; /* drop permit trees */
	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);
	}
    }
    else if (psy_cb->psy_grant == PSY_PDROP || psy_cb->psy_grant == PSY_EVDROP)
    {
	DB_STATUS   stat;
	
	/* Run through permit numbers, destroying each one */
	for (i = 0; i < psy_cb->psy_numnms; i++)
	{
	    rdf_rb->rdr_qrymod_id = psy_cb->psy_numbs[i];

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

	    /* remember the error to report later */
	    status = (status > stat) ? status : stat;

	    if (DB_FAILURE_MACRO(status))
	    {
		switch (rdf_cb.rdf_error.err_code)
		{
		    case E_RD0201_PROC_NOT_FOUND:
		    {
			(VOID) psf_error(E_PS0905_DBP_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_RD0210_ABANDONED_OBJECTS:
		    {
			char	*obj_type;
			i4	type_len;

			if (psy_cb->psy_grant == PSY_PDROP)
			{
			    obj_type = "database procedure";
			    type_len = sizeof("database procedure") - 1;
			}
			else
			{
			    obj_type = "dbevent";
			    type_len = sizeof("dbevent") - 1;
			}

			(VOID) psf_error(E_PS0565_PROT_ABANDONED_OBJ, 0L,
			    PSF_USERERR, &err_code, &psy_cb->psy_error, 3,
			    sizeof(psy_cb->psy_numbs[i]), psy_cb->psy_numbs + i,
			    type_len, obj_type,
			    psf_trmwhite(sizeof(psy_cb->psy_tabname[0]),
				(char *) psy_cb->psy_tabname),
			    psy_cb->psy_tabname);
			break;
		    }
		    case E_RD0013_NO_TUPLE_FOUND:
		    {
			(VOID) psf_error((i4) 5204, 0L, PSF_USERERR,
					 &err_code, &psy_cb->psy_error, 1,
					 sizeof (rdf_rb->rdr_qrymod_id),
					 &rdf_rb->rdr_qrymod_id);
			continue;
		    }

		    case E_RD0025_USER_ERROR:
			/*
			** Warning already handled - may be repeated when
			** we try some more updates (if this is a multi-
			** permit drop).
			*/
			if (psy_cb->psy_grant == PSY_EVDROP)
			{
			    status = E_DB_OK;
			    continue;
			}
			/* else fall through */
		    
		    default:
		    {
			/* Event-specific errors are reported through QEF */
			(VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error,
					     &psy_cb->psy_error);
			break;
		    }
		}

		return (status);
	    }

	    /*
	    ** Invalidate base object's infoblk from RDF cache: rdr_tabid
	    ** already contains base table id; rdr_sequence contains
	    ** permit number; set rdr_2_types mask.
	    */
	    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);
		return(status);
	    }
	}
	/* 
	** invalidate the relation cache entry that the permit was defined on 
	*/
	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);
	}
    }
    else	    /* drop permit or security alarm on a table */
    {
	DB_STATUS   stat;
	bool	    cant_drop_perms = FALSE;

	if (psy_cb->psy_grant == PSY_TDROP)
	{
	    i4	mask = rngvar->pss_tabdesc->tbl_status_mask;
	    /*
	    ** if this is a QUEL view owned by the DBA, avoid calling RDF since
	    ** we need to rpevent a user from destroying access permit which is
	    ** created on such views.  Instead, we will act as if the tuple was
	    ** not found by QEF (without actually calling it.)
	    */
	    if (   mask & DMT_VIEW
		&& !MEcmp((PTR) &sess_cb->pss_dba, (PTR) &rngvar->pss_ownname,
			sizeof(DB_OWN_NAME))
	       )
	    {
		/* check if this is a QUEL view */
		i4	    issql = 0;

		status = psy_sqlview(rngvar, sess_cb, &psy_cb->psy_error,
		    &issql);
		if (DB_FAILURE_MACRO(status))
		{
		    return(status);
		}

		if (!issql)
		{
		    cant_drop_perms = TRUE;
		    
		    /* errors will be reported later */
		    status = E_DB_ERROR;
		}
	    }
	}

	/* Run through permit or security_alarm numbers, destroying each one */
	for (i = 0; i < psy_cb->psy_numnms; i++)
	{
	    if (cant_drop_perms)
	    {
		(VOID) psf_error(5204L, 0L, PSF_USERERR,
		    &err_code, &psy_cb->psy_error, 1,
		    sizeof (psy_cb->psy_numbs[i]), (PTR) &psy_cb->psy_numbs[i]);
		continue;
	    }
	    else
	    {
		rdf_rb->rdr_qrymod_id = psy_cb->psy_numbs[i];
	    }

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

	    /* remember the error to report later */
	    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_RD0210_ABANDONED_OBJECTS:
		    {
			(VOID) psf_error(E_PS0565_PROT_ABANDONED_OBJ, 0L,
			    PSF_USERERR, &err_code, &psy_cb->psy_error, 3,
			    sizeof(psy_cb->psy_numbs[i]), psy_cb->psy_numbs + i,
			    sizeof("table") - 1, "table",
			    psf_trmwhite(sizeof(psy_cb->psy_tabname[0]),
				(char *) psy_cb->psy_tabname),
			    psy_cb->psy_tabname);
			break;
		    }
		    case E_RD0013_NO_TUPLE_FOUND:
		    {
			if (psy_cb->psy_grant == PSY_SDROP)
			    msgid = (i4)5213;
			else
			    msgid = (i4)5204;
			(VOID) psf_error(msgid, 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);
			break;
		    }
		}

		return (status);
	    }

	    /*
	    ** Invalidate base object's infoblk from RDF cache: rdr_tabid
	    ** already contains base table id; rdr_sequence contains
	    ** permit number (if not drop security alarm); set rdr_2_types mask.
	    */
	    if (psy_cb->psy_grant == PSY_SDROP)
	    {
		rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_KILLTREES;
	    }
	    else
	    {
		rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_ALIAS;
		rdf_inv_cb.rdf_rb.rdr_types_mask = RDR_PROTECT;
	    }
	    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);
	    }
	}

	/* now invalidate the base object that the permit was defined on */
	rdf_inv_cb.rdf_rb.rdr_2types_mask &= ~(RDR2_ALIAS | RDR2_KILLTREES);
	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);
	}
    }

    return    (status);
} 
Beispiel #19
0
/*{
** Name: psy_reregister	    - REREGISTER a STAR object.
**
**  INTERNAL PSF call format: status = psy_reregister(&psy_cb, &sess_cb);
**
**  EXTERNAL call format:     status = psy_call(PSY_REREGISTER, &psy_cb,
**						&sess_cb);
**
** Description:
**      The psy_reregister function will call QEF to REREGISTER a STAR object.
**	QED_DDL_INFO block has been already prepared, so there is very little to
**	do here.
**
** Inputs:
**      psy_cb
**          .psy_dmucb 			ptr to QED_DDL_INFO
**	sess_cb				Pointer to session control block
**					(Can be NULL)
**
** Outputs:
**      psy_cb
**	    .psy_error			Filled in if 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
**		    E_PS0003_INTERRUPTED	User interrupt
**		    E_PS0005_USER_MUST_ABORT	User must abort xact
**		    E_PS0008_RETRY		Query should be retried.
**	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:
**	    STAR object will be dropped and recreated with the SAME object id.
**	    RDF cache entry for this object will be destroyed.
** History:
**      04-apr-89 (andre)    
**          written
**	15-jun-92 (barbara)
**	    All psy functions called from psy_call pass the same parameters.
**	    Add session control block to fit in with this scheme.
**	03-aug-92 (barbara)
**	    Invalidate registered object from RDF cache.
**	07-dec-92 (andre)
**	    address of psy_dmucb (which is overloaded with the address of a
**	    QED_DDL_INFO) will be stored in QEU_CB.qeu_ddl_info instead
**	    of overloading qeu_qso.
**	10-aug-93 (andre)
**	    fixed the cause of a compiler warning
*/
DB_STATUS
psy_reregister(
	PSY_CB          *psy_cb,
	PSS_SESBLK	*sess_cb,
	QEU_CB		*qeu_cb)
{
    char		*ddb_obj_name;
    i4		err_code;
    RDF_CB		rdf_cb;
    RDR_RB		*rdf_rb = &rdf_cb.rdf_rb;
    DB_STATUS		status;

    qeu_cb->qeu_d_cb = (PTR) NULL;

    qeu_cb->qeu_ddl_info = psy_cb->psy_dmucb;

    qeu_cb->qeu_d_op = QED_RLINK;

    status = qef_call(QEU_DBU, ( PTR ) qeu_cb);

    if (DB_FAILURE_MACRO(status))
    {
	switch (qeu_cb->error.err_code)
	{
	    /* object unknown */
	    case E_QE0031_NONEXISTENT_TABLE:		
	    {
		ddb_obj_name =
			((QED_DDL_INFO *) psy_cb->psy_dmucb)->qed_d1_obj_name;
			
		(VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L,
		    PSF_USERERR, &err_code, &psy_cb->psy_error,1,
		   psf_trmwhite(sizeof(DD_OBJ_NAME), ddb_obj_name),
			 ddb_obj_name);
		break;
	    }
	    /* interrupt */
	    case E_QE0022_QUERY_ABORTED:
	    {
		(VOID) psf_error(E_PS0003_INTERRUPTED,
		    0L, PSF_USERERR,
		    &err_code, &psy_cb->psy_error,0);
		break;
	    }
	    /* should be retried */
	    case E_QE0023_INVALID_QUERY:
	    {
		psy_cb->psy_error.err_code = E_PS0008_RETRY;
		break;
	    }
	    /* user has some other locks on the object */
	    case E_QE0051_TABLE_ACCESS_CONFLICT:
	    {
		(VOID) psf_error(E_PS0D21_QEF_ERROR, 0L,
		    PSF_USERERR, &err_code, &psy_cb->psy_error,0);
		break;
	    }
	    /* resource related */
	    case E_QE000D_NO_MEMORY_LEFT:
	    case E_QE000E_ACTIVE_COUNT_EXCEEDED:
	    case E_QE000F_OUT_OF_OTHER_RESOURCES:
	    case E_QE001E_NO_MEM:
	    {
		(VOID) psf_error(E_PS0D23_QEF_ERROR,
		    qeu_cb->error.err_code, PSF_USERERR,
		    &err_code, &psy_cb->psy_error,0);
		break;
	    }
	    /* lock timer */
	    case E_QE0035_LOCK_RESOURCE_BUSY:
	    case E_QE0036_LOCK_TIMER_EXPIRED:
	    {
		(VOID) psf_error(4702L,
		    qeu_cb->error.err_code, PSF_USERERR,
		    &err_code, &psy_cb->psy_error,0);
		break;
	    }
	    /* resource quota */
	    case E_QE0052_RESOURCE_QUOTA_EXCEED:
	    case E_QE0067_DB_OPEN_QUOTA_EXCEEDED:
	    case E_QE0068_DB_QUOTA_EXCEEDED:
	    case E_QE006B_SESSION_QUOTA_EXCEEDED:
	    {
		(VOID) psf_error(4707L,
		    qeu_cb->error.err_code, PSF_USERERR,
		    &err_code, &psy_cb->psy_error,0);
		break;
	    }
	    /* log full */
	    case E_QE0024_TRANSACTION_ABORTED:
	    {
		(VOID) psf_error(4706L,
		    qeu_cb->error.err_code, PSF_USERERR,
		    &err_code, &psy_cb->psy_error,0);
		break;
	    }
	    /* deadlock */
	    case E_QE002A_DEADLOCK:
	    {
		(VOID) psf_error(4700L,
		    qeu_cb->error.err_code, PSF_USERERR,
		    &err_code, &psy_cb->psy_error,0);
		break;
	    }
	    /* lock quota */
	    case E_QE0034_LOCK_QUOTA_EXCEEDED:
	    {
		(VOID) psf_error(4705L,
		    qeu_cb->error.err_code, PSF_USERERR,
		    &err_code, &psy_cb->psy_error,0);
		break;
	    }
	    /* inconsistent database */
	    case E_QE0099_DB_INCONSISTENT:
	    {
		(VOID) psf_error(38L,
		    qeu_cb->error.err_code, PSF_USERERR,
		    &err_code, &psy_cb->psy_error,0);
		break;
	    }
	    case E_QE0025_USER_ERROR:
	    {
	      psy_cb->psy_error.err_code = E_PS0001_USER_ERROR;
	      break;
	    }
	    default:
	    {
		(VOID) psf_error(E_PS0D20_QEF_ERROR,
		    qeu_cb->error.err_code,
		    PSF_INTERR, &err_code, &psy_cb->psy_error,0);
	    }
	}

	return (status);
    }

    /* Invalidate registered object from RDF cache */
    {
	QED_DDL_INFO	*ddl_info = (QED_DDL_INFO *)psy_cb->psy_dmucb;

	pst_rdfcb_init(&rdf_cb, sess_cb);
	STRUCT_ASSIGN_MACRO(ddl_info->qed_d7_obj_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);
}