Beispiel #1
0
/*{
** Name: opn_index_hint	- check current table/index combination against
**	index hints
**
** Description:
**	Valid combinations of tables/indexes must include both table
**	and index for any index hint in subquery hint array.
**
** Inputs:
**      subquery                        ptr to current subquery being analyzed
**      combination			current combination of tables/indexes
**      numleaves                       number of tables/indexes in current
**					combination
**
** Outputs:
**	Returns:
**	    TRUE if combination satisfies all relevant index hints
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	21-mar-06 (dougi)
**	    Written for optimzer hints project.
*/
bool
opn_index_hint(
	OPS_SUBQUERY       *subquery,
	OPN_STLEAVES	   combination,
	OPN_LEAVES	   numleaves)
{
    i4			i, j;
    OPS_TABHINT		*hintp;
    OPV_VARS		*varp;
    OPV_RT		*vbase = subquery->ops_vars.opv_base;
    bool		gotone;


    /* Search the hint list for index hints. Then search the current
    ** combination for the table in the hint. Then search the current
    ** combination for the index in the hint. If the table is there and
    ** the index isn't, return FALSE. Otherwise return TRUE. */

    for (i = 0, hintp = subquery->ops_hints; i < subquery->ops_hintcount;
						i++, hintp++)
    {
	if (hintp->ops_hintcode != PST_THINT_INDEX)
	    continue;			/* only index hints */

	for (j = 0, gotone = FALSE; j < numleaves && !gotone; j++)
	{
	    varp = vbase->opv_rt[combination[j]];
	    if (MEcmp((char *)&hintp->ops_name1,
		(char *)&varp->opv_grv->opv_relation->rdr_rel->tbl_name,
		sizeof(DB_TAB_NAME)) == 0)
		gotone = TRUE;
	}

	if (!gotone)
	    continue;			/* hint table isn't in combo */

	for (j = 0, gotone = FALSE; j < numleaves && !gotone; j++)
	{
	    varp = vbase->opv_rt[combination[j]];
	    if (MEcmp((char *)&hintp->ops_name2,
		(char *)&varp->opv_grv->opv_relation->rdr_rel->tbl_name,
		sizeof(DB_TAB_NAME)) == 0)
		gotone = TRUE;
	}

	if (!gotone)
	    return(FALSE);		/* didn't find the index when 
					** table IS in the combination */
    }

    return(TRUE);

}
Beispiel #2
0
TPD_SP_CB *
tpd_s1_srch_sp(
	TPD_SS_CB	*v_sscb_p,
	DB_SP_NAME	*sp_name,
	i4		*o1_good_cnt_p)
{
    TPD_DX_CB	*dxcb_p = & v_sscb_p->tss_dx_cb;
    TPD_LM_CB	*splm_p = & dxcb_p->tdx_23_sp_ulmcb;
    TPD_SP_CB	*cur_sp = (TPD_SP_CB *) splm_p->tlm_3_frst_ptr;
    bool	found = FALSE;			/* assume */
    i4		good_cnt;


    *o1_good_cnt_p = 0;				/* assume */

    if (cur_sp == (TPD_SP_CB *) NULL)
	return((TPD_SP_CB *) NULL);

    for (found = FALSE, good_cnt = 0; !found && (cur_sp != NULL); ++good_cnt)
    { 
	if (MEcmp(sp_name, & cur_sp->tsp_1_name, sizeof(DB_SP_NAME)) == 0)
	{
	    /* match */

	    found = TRUE;
	}
	else
	    cur_sp = cur_sp->tsp_4_next_p;	/* advance to next sp */
    }

    *o1_good_cnt_p = good_cnt;			/* return good count */
    return(cur_sp);
}
Beispiel #3
0
STATUS
gcn_pwd_auth( char *user, char *passwd )
{
    STATUS	status = FAIL;

    /*
    ** The reserved internal login is accepted.
    ** An installation password is rejected.
    ** If the password appears to be a ticket,
    ** it must match an existing ticket.  Other-
    ** wise, the caller must validate the login.
    */
    if ( ! STcompare( user, GCN_NOUSER ) )
    {
	if ( ! STcompare(passwd, GCN_NOPASS) )  
	    status = OK;
	else
	    status = E_GC0145_GCN_INPW_NOT_ALLOWED;
    }
    else  if ( ! MEcmp( passwd, GCN_AUTH_TICKET_MAG, GCN_L_AUTH_TICKET_MAG ) )
    {
	u_i1	lticket[ GCN_L_TICKET ];
	i4	len;

	CItobin( (PTR)(passwd + GCN_L_AUTH_TICKET_MAG), &len, lticket );
	status = gcn_use_lticket( user, lticket, len );
    }

    return( status );
}
Beispiel #4
0
static VOID
AddLock( LK_LOCK_KEY	LkKey,
	 i4 		thread_type )
{
    ulong	hashnum,
    		hashstart;
    LOCKS	*hashtable = CsSamplerBlkPtr->Lock;
    
    ++CsSamplerBlkPtr->numlocksamples;	/* count the total number */

    if (LkKey.lk_type)
    {	/* A lock key */
    	hashnum = LockHash(&LkKey) % MAXLOCKS;
    }
    else
    {   /* All "unnamed" locks use the last slot */
    	hashnum = MAXLOCKS;
    }

    hashstart = hashnum;
    do 
    {
	if (hashtable[hashnum].lk_key.lk_type == 0)
	{   /* Slot available: add lock entry to the table */
	    MEcopy((PTR)&LkKey, sizeof(LK_LOCK_KEY), 
	    	   (PTR)&hashtable[hashnum].lk_key);
	    hashtable[hashnum].count[thread_type] = 1;
	    break;
	}
	if (MEcmp((PTR)&LkKey, (PTR)&hashtable[hashnum].lk_key,
		  sizeof(LK_LOCK_KEY)) == 0)
	{   /* Found the correct lock entry...increment the count. */
	    ++hashtable[hashnum].count[thread_type];
	    break;
	}
	/* This is a hash collision...see if the next slot is available. */
	/* If past the end of the table, wrap around to beginning.	 */
	if (++hashnum >= MAXLOCKS)
	    hashnum = 0;		
    } while (hashnum != hashstart);
    /*
    ** If we fall out of the 'do' loop without finding a slot (the table is
    ** full), just ignore this lock.
    */
} /* AddLock() */
Beispiel #5
0
STATUS
CS_mod_session(char *uns_decimal_session, CS_SCB ** scbp)
{
	u_i4            scb_as_ulong;
	CS_SCB         *an_scb;
	CS_SCB         *scan_scb;
	STATUS          stat;
	CS_SCB         *this_scb;
        bool           blFound = FALSE;

	CSget_scb(&this_scb);
	CS_str_to_uns(uns_decimal_session, &scb_as_ulong);
	an_scb = (CS_SCB *) scb_as_ulong;

	for (scan_scb = Cs_srv_block.cs_known_list->cs_next;
	     scan_scb && scan_scb != Cs_srv_block.cs_known_list;
	     scan_scb = scan_scb->cs_next) {
		if (scan_scb == an_scb)
                {
                        blFound = TRUE;
			break;
                }
	}

	if ((!blFound) && ((an_scb = CS_find_scb(an_scb)) == 0)) {
		/* FIXME -- real error status */
		/* "Invalid session id" */

		stat = MO_NO_INSTANCE;
	} else if ((MEcmp(an_scb->cs_username, this_scb->cs_username,
			  sizeof(an_scb->cs_username)))) {
		/* FIXME -- better error */
		/* "Superuser or owner status required to modify sessions" */

		stat = MO_NO_WRITE;
	} else {
		*scbp = an_scb;
		stat = OK;
	}
	return (stat);
}
Beispiel #6
0
static STATUS
CS_mod_session( char *uns_decimal_session, CS_SCB **scbp )
{
    u_i4 scb_as_ulong;
    CS_SID an_sid;
    CS_SCB *an_scb;
    STATUS stat;
    CS_SCB *this_scb;
    
    CSget_scb(&this_scb);

    CS_str_to_uns( uns_decimal_session, &scb_as_ulong );
    an_sid = (CS_SID)scb_as_ulong;
    
    an_scb = CS_find_scb(an_sid);

    if (an_scb == NULL)
    {
	/* FIXME -- real error status */
	/* "Invalid session id" */

	stat = MO_NO_INSTANCE;
    }
    else if ((MEcmp(an_scb->cs_username, this_scb->cs_username,
		    sizeof(an_scb->cs_username))))
    {
	/* FIXME -- better error */
	/* "Superuser or owner status required to modify sessions" */

	stat = MO_NO_WRITE;
    }
    else
    {
	*scbp = an_scb;
	stat = OK;
    }
    return( stat );
}
Beispiel #7
0
DB_STATUS
qel_c1_cre_p1(
QEF_RCB		*v_qer_p,
QEC_LINK	*v_lnk_p )
{
    DB_STATUS	    status;
    QES_DDB_SES	    *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses;
    QED_DDL_INFO    *ddl_p = & v_qer_p->qef_r3_ddb_req.qer_d7_ddl_info;
    DD_LDB_DESC	    *ldb_p = v_lnk_p->qec_19_ldb_p;
    bool	    obj_id_b = TRUE;	/* assume new object id required */


    /*  1.  determine if LDB is INGRES */

    if (
	(MEcmp(
		ldb_p->dd_l4_dbms_name, 
		IIQE_c6_cap_ingres, 
		QEK_005_LEN) == 0)
	||
	(MEcmp(
		ldb_p->dd_l4_dbms_name, 
		IIQE_c5_low_ingres, 
		QEK_005_LEN) == 0)
       )
	v_lnk_p->qec_10_haves |= QEC_03_INGRES;

    /*	2.  retrieve existing OBJECT_BASE from IIDD_DDB_OBJECT_BASE */

    if (dds_p->qes_d7_ses_state == QES_4ST_REFRESH
	&&
	ddl_p->qed_d6_tab_info_p->dd_t3_tab_type != DD_4OBJ_INDEX)
				/* REFRESH LINK ? */
	obj_id_b = FALSE;	/* Yes, retain original object id */

    if (obj_id_b)
    {
	/* retrieve the new object id as required */

	status = qel_c3_obj_base(v_qer_p, v_lnk_p);
	if (status)
	    return(status);
    }

    /*	3.  retrieve the LDB's id from IIDD_DDB_LDBIDS if it exists */

    if (v_lnk_p->qec_10_haves & QEC_04_LONG_LDBNAME)
	status = qel_c5_ldbid_long(v_qer_p, v_lnk_p);	
    else
	status = qel_c4_ldbid_short(FALSE, v_qer_p, v_lnk_p);	
					    /* FALSE for no database alias */
    if (status)
	return(status);

    v_lnk_p->qec_3_ldb_id = v_lnk_p->qec_7_ldbids_p->d2_5_ldb_id;

    /*	4.  retrieve the table's information from the LDB's IITABLES */

    status = qel_c6_ldb_tables(v_qer_p, v_lnk_p);	
    if (status)
	return(status);

    /*	5.  if the LDB is a new participant, do:
    **	
    **	    determine if it has an excessively long name, 
    **	    retrieve information about existence of user names, dba name, and
    **	    compute the minimum levels of LDB capabilities existing
    **	    in IIDD_DDB_LDB_DBCAPS */

    if (v_lnk_p->qec_3_ldb_id == 0)
    {
	if (v_lnk_p->qec_1_ddl_info_p->qed_d6_tab_info_p->
	    dd_t9_ldb_p->dd_i1_ldb_desc.dd_l3_ldb_name[0] == ' ')
	{
	    status = qed_u1_gen_interr(& v_qer_p->error);
	    return(status);
	}

	status = qel_c7_ldb_chrs(v_qer_p, v_lnk_p);
	if (status)
	    return(status);

	status = qel_a1_min_cap_lvls(TRUE, v_qer_p, v_lnk_p); 
						/* TRUE for filling what
						** qec_25_pre_mins_p points
						** at */
    }

    return(status);
}
Beispiel #8
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 #9
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 #10
0
DB_STATUS
dmu_modify(DMU_CB    *dmu_cb)
{
    DM_SVCB		*svcb = dmf_svcb;
    DMU_CB		*dmu = dmu_cb;
    DML_XCB		*xcb;
    DML_ODCB		*odcb;
    DM2U_MOD_CB		local_mcb, *mcb = &local_mcb;

    i4			recovery;
    i4			truncate;
    i4			duplicates;
    i4			i,j;
    i4			indicator;
    i4			error, local_error;
    DB_STATUS		status;
    bool                bad_loc;
    i4			blob_add_extend = 0;
    bool                used_default_page_size = TRUE;
    i4			page_size;
    i4			verify_options;
    i4			mask;
    i4			has_extensions = 0;
    DB_OWN_NAME		table_owner;
    DB_TAB_NAME		table_name;
    bool		got_action;
    bool		is_table_debug;
    bool		reorg;

    CLRDBERR(&dmu->error);

    /* Any modify should make table recovery disallowed except for the
    ** alter_status options which change logical, physical consistency
    ** and table recovery bit itself
    */
    mcb->mcb_mod_options2 = DM2U_2_TBL_RECOVERY_DEFAULT;

    do
    {
	/*  Check for bad flags. */

	mask = ~(DMU_VGRANT_OK | DMU_INTERNAL_REQ | DMU_RETINTO
		| DMU_PARTITION | DMU_MASTER_OP | DMU_ONLINE_START | DMU_ONLINE_END
		| DMU_NO_PAR_INDEX | DMU_PIND_CHAINED | DMU_NODEPENDENCY_CHECK);
        if ( (dmu->dmu_flags_mask & mask) != 0)
	{
	    SETDBERR(&dmu->error, 0, E_DM001A_BAD_FLAG);
	    break;
	}

	/*  Validate the transaction id. */

	xcb = (DML_XCB *)dmu->dmu_tran_id;
	if (dm0m_check((DM_OBJECT *)xcb, (i4)XCB_CB) != E_DB_OK)
	{
	    SETDBERR(&dmu->error, 0, E_DM003B_BAD_TRAN_ID);
	    break;
	}

	/* Check for external interrupts */
	if ( xcb->xcb_scb_ptr->scb_ui_state )
	    dmxCheckForInterrupt(xcb, &error);

	if ( xcb->xcb_state )
	{
	    if (xcb->xcb_state & XCB_USER_INTR)
	    {
		SETDBERR(&dmu->error, 0, E_DM0065_USER_INTR);
		break;
	    }
	    if (xcb->xcb_state & XCB_FORCE_ABORT)
	    {
		SETDBERR(&dmu->error, 0, E_DM010C_TRAN_ABORTED);
		break;
	    }
	    if (xcb->xcb_state & XCB_ABORT)
	    {
		SETDBERR(&dmu->error, 0, E_DM0064_USER_ABORT);
		break;
	    }	    
	}

	/*  Check the database identifier. */

	odcb = (DML_ODCB *)dmu->dmu_db_id;
	if (dm0m_check((DM_OBJECT *)odcb, (i4)ODCB_CB) != E_DB_OK)
	{
	    SETDBERR(&dmu->error, 0, E_DM0010_BAD_DB_ID);
	    break;
	}

	mcb->mcb_db_lockmode = DM2T_X;

	/*  Check that this is a update transaction on the database 
        **  that can be updated. */
	if (odcb != xcb->xcb_odcb_ptr)
	{
	    SETDBERR(&dmu->error, 0, E_DM005D_TABLE_ACCESS_CONFLICT);
	    break;
	}

	/* Prime the MCB */
	mcb->mcb_dcb = odcb->odcb_dcb_ptr;
	mcb->mcb_xcb = xcb;
	mcb->mcb_tbl_id = &dmu->dmu_tbl_id;
	mcb->mcb_omcb = (DM2U_OMCB*)NULL;
	mcb->mcb_dmu = dmu;
	mcb->mcb_structure = 0;
	mcb->mcb_i_fill = 0;
	mcb->mcb_l_fill = 0;
	mcb->mcb_d_fill = 0;
	mcb->mcb_unique = FALSE;
	mcb->mcb_compressed = TCB_C_NONE;
        mcb->mcb_index_compressed = FALSE;
	mcb->mcb_temporary = FALSE;
	mcb->mcb_merge = FALSE;
	mcb->mcb_clustered = FALSE;
	mcb->mcb_modoptions = 0;
	mcb->mcb_min_pages = 0;
	mcb->mcb_max_pages = 0;
	mcb->mcb_allocation = 0;
	mcb->mcb_extend = 0;
	mcb->mcb_page_type = TCB_PG_INVALID;
	mcb->mcb_page_size = svcb->svcb_page_size;
	mcb->mcb_tup_info = &dmu->dmu_tup_cnt;
	mcb->mcb_reltups = 0;
	mcb->mcb_tab_name = &table_name;
	mcb->mcb_tab_owner = &table_owner;
	mcb->mcb_has_extensions = &has_extensions;
	mcb->mcb_relstat2 = 0;
	mcb->mcb_flagsmask = dmu->dmu_flags_mask;
	mcb->mcb_tbl_pri = 0;
	mcb->mcb_rfp_entry = (DM2U_RFP_ENTRY*)NULL;
	mcb->mcb_new_part_def = (DB_PART_DEF*)dmu->dmu_part_def;
	mcb->mcb_new_partdef_size = dmu->dmu_partdef_size;
	mcb->mcb_verify = 0;

	dmu->dmu_tup_cnt = 0;
        truncate = 0;
	reorg = FALSE;
	duplicates = -1;
	verify_options = 0;
	got_action = FALSE;

	/* FIXME better messages (in general) */
	/* If there's a partdef it has to be one-piece, else bad param */
	if (dmu->dmu_part_def != NULL
	  && dmu->dmu_part_def->ndims > 0
	  && (dmu->dmu_part_def->part_flags & DB_PARTF_ONEPIECE) == 0)
	{
	    SETDBERR(&dmu->error, 0, E_DM002A_BAD_PARAMETER);
	    break;
	}

	/* Disassemble the modify action.
	** FIXME this used to be buried in the characteristics array.
	** It would make much more sense to just carry the action
	** code through, but that will have to wait for another day.
	*/
	got_action = FALSE;
	switch (dmu->dmu_action)
	{
	case DMU_ACT_STORAGE:
	    if (BTtest(DMU_STRUCTURE, dmu->dmu_chars.dmu_indicators))
	    {
		got_action = TRUE;
		mcb->mcb_structure = dmu->dmu_chars.dmu_struct;
	    }
	    break;

	case DMU_ACT_ADDEXTEND:
	    got_action = TRUE;
	    mcb->mcb_mod_options2 |= DM2U_2_ADD_EXTEND;
	    break;

	case DMU_ACT_ENCRYPT:
	    got_action = TRUE;
	    mcb->mcb_mod_options2 |= DM2U_2_ENCRYPT;
	    break;

	case DMU_ACT_LOG_CONSISTENT:
	    if (BTtest(DMU_ACTION_ONOFF, dmu->dmu_chars.dmu_indicators))
	    {
		got_action = TRUE;
		mcb->mcb_mod_options2 &= ~DM2U_2_TBL_RECOVERY_DEFAULT;
		if ( dmu->dmu_chars.dmu_flags & DMU_FLAG_ACTON )
		    mcb->mcb_mod_options2 |= DM2U_2_LOG_CONSISTENT;
		else
		    mcb->mcb_mod_options2 |= DM2U_2_LOG_INCONSISTENT;
	    }
	    break;

	case DMU_ACT_MERGE:
	    got_action = TRUE;
	    mcb->mcb_merge = TRUE;
	    break;

	case DMU_ACT_PERSISTENCE:
	    if (BTtest(DMU_PERSISTS_OVER_MODIFIES, dmu->dmu_chars.dmu_indicators))
	    {
		got_action = TRUE;
		mcb->mcb_mod_options2 |= (dmu->dmu_chars.dmu_flags & DMU_FLAG_PERSISTENCE) ?
			DM2U_2_PERSISTS_OVER_MODIFIES :
			DM2U_2_NOPERSIST_OVER_MODIFIES;
	    }
	    break;

	case DMU_ACT_PHYS_CONSISTENT:
	    if (BTtest(DMU_ACTION_ONOFF, dmu->dmu_chars.dmu_indicators))
	    {
		got_action = TRUE;
		mcb->mcb_mod_options2 &= ~DM2U_2_TBL_RECOVERY_DEFAULT;
		if ( dmu->dmu_chars.dmu_flags & DMU_FLAG_ACTON )
		    mcb->mcb_mod_options2 |= DM2U_2_PHYS_CONSISTENT;
		else
		    mcb->mcb_mod_options2 |= DM2U_2_PHYS_INCONSISTENT;
	    }
	    break;

	case DMU_ACT_PRIORITY:
	    if (BTtest(DMU_TABLE_PRIORITY, dmu->dmu_chars.dmu_indicators))
		got_action = TRUE;
	    /* flag setting when we hit the priority char */
	    break;

	case DMU_ACT_READONLY:
	    if (BTtest(DMU_ACTION_ONOFF, dmu->dmu_chars.dmu_indicators))
	    {
		got_action = TRUE;
		if ( dmu->dmu_chars.dmu_flags & DMU_FLAG_ACTON )
		    mcb->mcb_mod_options2 |= DM2U_2_READONLY;
		else
		    mcb->mcb_mod_options2 |= DM2U_2_NOREADONLY;
	    }
	    break;

	case DMU_ACT_REORG:
	    got_action = TRUE;
	    reorg = TRUE;
	    break;

	case DMU_ACT_TABLE_RECOVERY:
	    if (BTtest(DMU_ACTION_ONOFF, dmu->dmu_chars.dmu_indicators))
	    {
		got_action = TRUE;
		mcb->mcb_mod_options2 &= ~DM2U_2_TBL_RECOVERY_DEFAULT;
		if ( dmu->dmu_chars.dmu_flags & DMU_FLAG_ACTON )
		    mcb->mcb_mod_options2 |= DM2U_2_TBL_RECOVERY_ALLOWED;
		else
		    mcb->mcb_mod_options2 |= DM2U_2_TBL_RECOVERY_DISALLOWED;
	    }
	    break;

	case DMU_ACT_TRUNC:
	    got_action = TRUE;
	    truncate++;
	    break;

	case DMU_ACT_USCOPE:
	    if (BTtest(DMU_STATEMENT_LEVEL_UNIQUE, dmu->dmu_chars.dmu_indicators))
	    {
		got_action = TRUE;
		mcb->mcb_mod_options2 |= DM2U_2_STATEMENT_LEVEL_UNIQUE;
	    }
	    break;

	case DMU_ACT_VERIFY:
	    if (BTtest(DMU_VACTION, dmu->dmu_chars.dmu_indicators))
	    {
		got_action = TRUE;
		mcb->mcb_verify = dmu->dmu_chars.dmu_vaction;
	    }
	    break;
	} /* switch */

	if (! got_action)
	{
	    SETDBERR(&dmu->error, 0, E_DM000E_BAD_CHAR_VALUE);
	    break;
	}

	/* Disassemble the characteristics.
	** FIXME probably better to just carry it through, but one step
	** at a time!
	*/
	indicator = -1;
	while ((indicator = BTnext(indicator, dmu->dmu_chars.dmu_indicators, DMU_CHARIND_LAST)) != -1)
	{
	    switch (indicator)
	    {
	    case DMU_ACTION_ONOFF:
	    case DMU_STRUCTURE:
		/* Already picked it up, just skip on */
		continue;

	    case DMU_IFILL:
		mcb->mcb_i_fill = dmu->dmu_chars.dmu_nonleaff;
		if (mcb->mcb_i_fill > 100)
		    mcb->mcb_i_fill = 100;
		continue;

	    case DMU_LEAFFILL:
		mcb->mcb_l_fill = dmu->dmu_chars.dmu_leaff;
		if (mcb->mcb_l_fill > 100)
		    mcb->mcb_l_fill = 100;
		continue;

	    case DMU_DATAFILL:
		mcb->mcb_d_fill = dmu->dmu_chars.dmu_fillfac;
		if (mcb->mcb_d_fill > 100)
		    mcb->mcb_d_fill = 100;
		continue;

	    case DMU_PAGE_SIZE:
		used_default_page_size = FALSE;
		mcb->mcb_page_size = dmu->dmu_chars.dmu_page_size;
		if (mcb->mcb_page_size != 2048   && mcb->mcb_page_size != 4096  &&
		    mcb->mcb_page_size != 8192   && mcb->mcb_page_size != 16384 &&
		    mcb->mcb_page_size != 32768  && mcb->mcb_page_size != 65536)
		{
		    SETDBERR(&dmu->error, indicator, E_DM000E_BAD_CHAR_VALUE);
		    break;
		}
		else if (!dm0p_has_buffers(mcb->mcb_page_size))
		{
		    SETDBERR(&dmu->error, 0, E_DM0157_NO_BMCACHE_BUFFERS);
		    break;
		}		    
		else
		{
		    continue;
		}

	    case DMU_MINPAGES:
		mcb->mcb_min_pages = dmu->dmu_chars.dmu_minpgs;
		continue;

	    case DMU_MAXPAGES:
		mcb->mcb_max_pages = dmu->dmu_chars.dmu_maxpgs;
		continue;

	    case DMU_UNIQUE:
		mcb->mcb_unique = TRUE;
		continue;

	    case DMU_DCOMPRESSION:
		/* Translate DMU_xxx to TCB compression types */
		if (dmu->dmu_chars.dmu_dcompress == DMU_COMP_ON)
		    mcb->mcb_compressed = TCB_C_DEFAULT;
		else if (dmu->dmu_chars.dmu_dcompress == DMU_COMP_HI)
		    mcb->mcb_compressed = TCB_C_HICOMPRESS;
		continue;

            case DMU_KCOMPRESSION:
                mcb->mcb_index_compressed =
			(dmu->dmu_chars.dmu_kcompress != DMU_COMP_OFF);
                continue;

	    case DMU_TEMP_TABLE:
		mcb->mcb_temporary = TRUE;
		continue;

	    case DMU_RECOVERY:
		recovery = (dmu->dmu_chars.dmu_flags & DMU_FLAG_RECOVERY) != 0;
		if (recovery)
		{
		    /* recovery isn't currently supported */
		    SETDBERR(&dmu->error, indicator, E_DM000D_BAD_CHAR_ID);
		    break;
		}
		continue;

	    case DMU_DUPLICATES:
		duplicates = 0;
		if (dmu->dmu_chars.dmu_flags & DMU_FLAG_DUPS)
		    duplicates = 1;
		continue;

	    case DMU_ALLOCATION:
		mcb->mcb_allocation = dmu->dmu_chars.dmu_alloc;
		continue;

	    case DMU_EXTEND:
		mcb->mcb_extend = dmu->dmu_chars.dmu_extend;
		continue;

	    case DMU_VACTION:
		/* Already got it, just skip on */
		continue;

	    case DMU_VOPTION:
		verify_options = dmu->dmu_chars.dmu_voption;
		continue;

	    case DMU_STATEMENT_LEVEL_UNIQUE:
		if (dmu->dmu_chars.dmu_flags & DMU_FLAG_UNIQUE_STMT)
		    mcb->mcb_relstat2 |= TCB_STATEMENT_LEVEL_UNIQUE;
		continue;

	    case DMU_PERSISTS_OVER_MODIFIES:
		if (dmu->dmu_chars.dmu_flags & DMU_FLAG_PERSISTENCE)
		    mcb->mcb_relstat2 |= TCB_PERSISTS_OVER_MODIFIES;
		continue;

	    case DMU_SYSTEM_GENERATED:
		mcb->mcb_relstat2 |= TCB_SYSTEM_GENERATED;
		continue;

	    case DMU_SUPPORTS_CONSTRAINT:
		mcb->mcb_relstat2 |= TCB_SUPPORTS_CONSTRAINT;
		continue;

	    case DMU_NOT_UNIQUE:
		mcb->mcb_relstat2 |= TCB_NOT_UNIQUE;
		continue;

	    case DMU_NOT_DROPPABLE:
		mcb->mcb_relstat2 |= TCB_NOT_DROPPABLE;
		continue;

	    case DMU_ROW_SEC_AUDIT:
		mcb->mcb_relstat2 |= TCB_ROW_AUDIT;
		continue;

	    case DMU_TABLE_PRIORITY:
		mcb->mcb_tbl_pri = dmu->dmu_chars.dmu_cache_priority;
		if (mcb->mcb_tbl_pri < 0 || mcb->mcb_tbl_pri > DB_MAX_TABLEPRI)
		{
		    SETDBERR(&dmu->error, indicator, E_DM000E_BAD_CHAR_VALUE);
		    break;
		}
		/*
		** DMU_TABLE_PRIORITY    is set if priority came from WITH clause.
		** DMU_TO_TABLE_PRIORITY is set if priority came from MODIFY TO clause.
		*/
		if (dmu->dmu_action != DMU_ACT_PRIORITY)
		    mcb->mcb_mod_options2 |= DM2U_2_TABLE_PRIORITY;
		else
		    mcb->mcb_mod_options2 |= DM2U_2_TO_TABLE_PRIORITY;
		continue;

	    case DMU_BLOBEXTEND:
		blob_add_extend = dmu->dmu_chars.dmu_blobextend;
		continue;

	    case DMU_CLUSTERED:
		mcb->mcb_clustered = (dmu->dmu_chars.dmu_flags & DMU_FLAG_CLUSTERED) != 0;
		continue;

	    case DMU_CONCURRENT_UPDATES:
		/* Translate from PSF flag to DMU internal flag */
		if (dmu->dmu_chars.dmu_flags & DMU_FLAG_CONCUR_U)
		    mcb->mcb_flagsmask |= DMU_ONLINE_START;
		continue;

	    default:
		/* Ignore anything else, might be for CREATE, who knows */
		continue;
	    }
	    break;
	}

	/*
	** If no page size specified, set page_size to zero
	** In this case the current page size will be used
	*/
	if (used_default_page_size)
	    mcb->mcb_page_size = 0;

	/* Save a local copy for dmpe_modify, since dm2u_modify can alter mcb */
	page_size = mcb->mcb_page_size;

	if (mcb->mcb_structure == TCB_HEAP)
	{
	    if (mcb->mcb_d_fill == 0)
		mcb->mcb_d_fill = DM_F_HEAP;
	}
	else if (mcb->mcb_structure == TCB_ISAM)
	{
	    if (mcb->mcb_i_fill == 0)
		mcb->mcb_i_fill = DM_FI_ISAM;
	    if (mcb->mcb_d_fill == 0)
	    {
		if (mcb->mcb_compressed != TCB_C_NONE)
		    mcb->mcb_d_fill = DM_F_CISAM;
		else
		    mcb->mcb_d_fill = DM_F_ISAM;
	    }
	}
	else if (mcb->mcb_structure == TCB_HASH)
	{
	    if (mcb->mcb_d_fill == 0)
	    {
		if (mcb->mcb_compressed != TCB_C_NONE)
		    mcb->mcb_d_fill = DM_F_CHASH;
		else
		    mcb->mcb_d_fill = DM_F_HASH;
	    }
	    if (mcb->mcb_min_pages == 0)
	    {
		if (mcb->mcb_compressed != TCB_C_NONE)
		    mcb->mcb_min_pages = 1;
		else
		    mcb->mcb_min_pages = 10;

		/* If user specified max pages, don't set minpages higher */
		if (mcb->mcb_min_pages > mcb->mcb_max_pages && mcb->mcb_max_pages != 0)
		    mcb->mcb_min_pages = mcb->mcb_max_pages;
	    }
	    if (mcb->mcb_max_pages == 0)
		mcb->mcb_max_pages = 8388607;
	}
	else if (mcb->mcb_structure == TCB_BTREE || mcb->mcb_merge)
	{
            if (DMZ_AM_MACRO(16) && !mcb->mcb_temporary)
            {
                /* DM616 -- forces index compression to be used: */
                mcb->mcb_index_compressed = TRUE;
            }

	    if (mcb->mcb_i_fill == 0)
		mcb->mcb_i_fill = DM_FI_BTREE;
	    if (mcb->mcb_l_fill == 0)
		mcb->mcb_l_fill = DM_FL_BTREE;
	    if (mcb->mcb_d_fill == 0)
	    {
		if (mcb->mcb_compressed != TCB_C_NONE)
		    mcb->mcb_d_fill = DM_F_CBTREE;
		else
		    mcb->mcb_d_fill = DM_F_BTREE;
	    }
	}
	else if (truncate)
	{
	    if (mcb->mcb_d_fill == 0)
		mcb->mcb_d_fill = DM_F_HEAP;
	}

	if (mcb->mcb_structure == TCB_HASH && mcb->mcb_min_pages > mcb->mcb_max_pages)
	{
	    SETDBERR(&dmu->error, 0, E_DM000D_BAD_CHAR_ID);
	    break;
	}

	mcb->mcb_kcount = dmu->dmu_key_array.ptr_in_count;
	mcb->mcb_key = (DMU_KEY_ENTRY**) dmu->dmu_key_array.ptr_address;
	if (mcb->mcb_kcount && (mcb->mcb_key == (DMU_KEY_ENTRY**)NULL ||
              dmu->dmu_key_array.ptr_size != sizeof(DMU_KEY_ENTRY)))
	{
	    SETDBERR(&dmu->error, 0, E_DM002A_BAD_PARAMETER);
	    break;
	}

	if (truncate)
	{
	    mcb->mcb_kcount = 0;
	    mcb->mcb_modoptions |= DM2U_TRUNCATE;
	}
	if (duplicates == 1)
	    mcb->mcb_modoptions |= DM2U_DUPLICATES;
	else if (duplicates == 0)
	    mcb->mcb_modoptions |= DM2U_NODUPLICATES;
	/* else duplicates == -1, set neither flag */
	if (reorg)
	    mcb->mcb_modoptions |= DM2U_REORG;

	/* CLUSTERED implies and requires Unique */
	if ( mcb->mcb_clustered && mcb->mcb_structure == TCB_BTREE )
	    mcb->mcb_unique = TRUE;
	else
	    mcb->mcb_clustered = FALSE;


	if (mcb->mcb_verify)
	{
	    if (verify_options == 0)
	    {
		/*  Apply defaults. */

		switch (mcb->mcb_verify)
		{
		case DMU_V_VERIFY:
		    verify_options = DMU_T_LINK | DMU_T_RECORD | DMU_T_ATTRIBUTE;
		    break;

		case DMU_V_REPAIR:
		case DMU_V_DEBUG:
		    verify_options = DMU_T_BITMAP;
		    break;

		case DMU_V_PATCH:
		case DMU_V_FPATCH:
		    break;
		}
	    }
	    /* Shift modifiers into place */
	    mcb->mcb_verify |= (verify_options << DM1U_MODSHIFT);
	}
	is_table_debug = ((mcb->mcb_verify & DM1U_OPMASK) == DM1U_DEBUG);

	/* Check the location names for duplicates, too many. */

	mcb->mcb_location = (DB_LOC_NAME*)NULL;
	mcb->mcb_l_count = 0;
	if (dmu->dmu_location.data_address && 
	    (dmu->dmu_location.data_in_size >= sizeof(DB_LOC_NAME)) &&
	    mcb->mcb_temporary == FALSE)
	{
	    mcb->mcb_location = (DB_LOC_NAME *) dmu->dmu_location.data_address;
	    mcb->mcb_l_count = dmu->dmu_location.data_in_size/sizeof(DB_LOC_NAME);
	    if (mcb->mcb_l_count > DM_LOC_MAX)
	    {
		SETDBERR(&dmu->error, 0, E_DM0071_LOCATIONS_TOO_MANY);
		break;
	    }
	    bad_loc = FALSE;
	    for (i = 0; i < mcb->mcb_l_count; i++)
	    {
		for (j = 0; j < i; j++)
		{
		    /* 
                    ** Compare this location name against other 
                    ** already given, they cannot be the same.
                    */

		    if (MEcmp(mcb->mcb_location[j].db_loc_name,
                              mcb->mcb_location[i].db_loc_name,
			      sizeof(DB_LOC_NAME)) == 0 )
		    {
			SETDBERR(&dmu->error, i, E_DM001E_DUP_LOCATION_NAME);
			bad_loc = TRUE;
			break;
		    }	    	    
		}
		if (bad_loc == TRUE)
		    break;		    
	    }

	    if (bad_loc == TRUE)
		break;
	}
	else
	{
	    /* There must a location list if you are reorganizing
            ** to a different number of locations.
            */
	    if (reorg)
	    {
		if (dmu->dmu_location.data_address &&
					    dmu->dmu_location.data_in_size)
		    SETDBERR(&dmu->error, 0, E_DM001F_LOCATION_LIST_ERROR);
		else
		    SETDBERR(&dmu->error, 0, E_DM0072_NO_LOCATION);
		break;	    
	    }
	}

	mcb->mcb_partitions = (DMU_PHYPART_CHAR*)NULL;
	mcb->mcb_nparts = 0;
	if ( dmu->dmu_ppchar_array.data_address && 
	     dmu->dmu_ppchar_array.data_in_size >= sizeof(DMU_PHYPART_CHAR) )
	{
	    mcb->mcb_partitions = (DMU_PHYPART_CHAR*)dmu->dmu_ppchar_array.data_address;
	    mcb->mcb_nparts = dmu->dmu_ppchar_array.data_in_size
			/ sizeof(DMU_PHYPART_CHAR);
	}
    
	if ((xcb->xcb_x_type & XCB_RONLY) && !is_table_debug)
	{
	    SETDBERR(&dmu->error, 0, E_DM006A_TRAN_ACCESS_CONFLICT);
	    break;
	}

	/*
	** If this is the first write operation for this transaction,
	** then we need to write the begin transaction record.
	*/
	if ((xcb->xcb_flags & XCB_DELAYBT) != 0 && mcb->mcb_temporary == FALSE
	  && !is_table_debug)
	{
	    status = dmxe_writebt(xcb, TRUE, &dmu->error);
	    if (status != E_DB_OK)
	    {
		xcb->xcb_state |= XCB_TRANABORT;
		break;
	    }
	}

        /* Calls the physical layer to process the rest of the modify */

	status = dm2u_modify(mcb, &dmu->error);

	if (status == E_DB_OK && has_extensions)
	{
	    if ((mcb->mcb_mod_options2 & DM2U_2_ADD_EXTEND) && blob_add_extend == 0)
		status = E_DB_OK;
	    else
	    {
		/* FIX ME make modify etabs optional !! */
		/* Add flag to modify top make modify etabs optional */
		/* Add sysmod dbname tablename blob-column-name */
#ifdef xDEBUG
		TRdisplay("Modify etabs for %~t %~t\n",
		    sizeof(DB_TAB_NAME), table_name.db_tab_name,
		    sizeof(DB_OWN_NAME), table_owner.db_own_name);
#endif
		status = dmpe_modify(dmu, odcb->odcb_dcb_ptr, xcb,
			    &dmu->dmu_tbl_id, mcb->mcb_db_lockmode, mcb->mcb_temporary,
			    truncate, (i4)0, blob_add_extend, &dmu->error);
	    }
	}
	  
	    
	/*	Audit successful MODIFY/PATCH of TABLE. */

	if ( status == E_DB_OK && dmf_svcb->svcb_status & SVCB_C2SECURE )
	{
	    i4 msgid;
	    i4 access = SXF_A_SUCCESS;

	    if ((mcb->mcb_verify & DM1U_OPMASK) == DM1U_PATCH ||
		(mcb->mcb_verify & DM1U_OPMASK) == DM1U_FPATCH)
	    {
		access |= SXF_A_ALTER;
		msgid = I_SX271A_TABLE_PATCH;
	    }
	    else 
	    {
		access |= SXF_A_MODIFY;
		msgid = I_SX270F_TABLE_MODIFY;
	    }
	    /*
	    **	Audit success
	    */
	    status = dma_write_audit(
			SXF_E_TABLE,
			access,
			table_name.db_tab_name,	/* Table/view name */
			sizeof(table_name.db_tab_name),	/* Table/view name */
			&table_owner,	/* Table/view owner */
			msgid, 
			FALSE, /* Not force */
			&dmu->error, NULL);
	}

	if (status == E_DB_OK)
	{
	    /* If modify to reorg or merge then return no tuple count info. */
	    if (reorg || (mcb->mcb_merge) || (mcb->mcb_verify != 0))
	    {
		dmu->dmu_tup_cnt = DM_NO_TUPINFO;
	    }
	    return (E_DB_OK);
	}
	else
	{
            if (dmu->error.err_code > E_DM_INTERNAL)
            {
                uleFormat(&dmu->error, 0, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, 
		    (char * )NULL, (i4)0, (i4 *)NULL, &local_error, 0);
		SETDBERR(&dmu->error, 0, E_DM0091_ERROR_MODIFYING_TABLE);
            }
	    switch (dmu->error.err_code)
	    {
		case E_DM004B_LOCK_QUOTA_EXCEEDED:
		case E_DM0112_RESOURCE_QUOTA_EXCEED:
		case E_DM0091_ERROR_MODIFYING_TABLE:
		case E_DM009B_ERROR_CHK_PATCH_TABLE:
		case E_DM0045_DUPLICATE_KEY:
		case E_DM0137_GATEWAY_ACCESS_ERROR:
	        case E_DM006A_TRAN_ACCESS_CONFLICT:
		    xcb->xcb_state |= XCB_STMTABORT;
		    break;

		case E_DM0042_DEADLOCK:
		case E_DM004A_INTERNAL_ERROR:
		case E_DM0100_DB_INCONSISTENT:
		    xcb->xcb_state |= XCB_TRANABORT;
		    break;
		case E_DM0065_USER_INTR:
		    xcb->xcb_state |= XCB_USER_INTR;
		    break;
		case E_DM010C_TRAN_ABORTED:
		    xcb->xcb_state |= XCB_FORCE_ABORT;
		    break;
		case E_DM007D_BTREE_BAD_KEY_LENGTH:
		    dmu->dmu_tup_cnt = dmu->dmu_tup_cnt; /* same for now */
		default:
                    break;
	    }
	}
    } while (FALSE);

    if (dmu->error.err_code > E_DM_INTERNAL)
    {
	uleFormat(&dmu->error, 0, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, 
	    (char * )NULL, (i4)0, (i4 *)NULL, &local_error, 0);
	SETDBERR(&dmu->error, 0, E_DM0091_ERROR_MODIFYING_TABLE);
    }

    return (E_DB_ERROR);
}
Beispiel #11
0
VOID
CS_sampler(void)
{
	CS_SCB	*an_scb;
	i4 	sleeptime, elapsed, seconds, event;
	i4	starttime, stoptime;
	i4 	cs_thread_type;
	i4 	cs_state;
	bool	attached = FALSE;
	u_i4	bior, biow;
	u_i4	dior, diork, diow, diowk;
	u_i4	lior, liork, liow, liowk;

  /*
  ** This thread goes into a loop:
  **	1. Lock the sampler block
  **	2. Do sampling
  **	3. Sleep for the specified interval
  ** The thread will exit normally when the sampler block pointer is NULL.
  ** The thread exits abnormally if it cannot lock the block.
  */
  starttime = CS_checktime();
  elapsed = 0;

  /* Prime the local I/O, Transaction rate counters */
  bior  = Cs_srv_block.cs_wtstatistics.cs_bior_done;
  biow  = Cs_srv_block.cs_wtstatistics.cs_biow_done;
  dior  = Cs_srv_block.cs_wtstatistics.cs_dior_done;
  diork = Cs_srv_block.cs_wtstatistics.cs_dior_kbytes;
  diow  = Cs_srv_block.cs_wtstatistics.cs_diow_done;
  diowk = Cs_srv_block.cs_wtstatistics.cs_diow_kbytes;
  lior  = Cs_srv_block.cs_wtstatistics.cs_lior_done;
  liork = Cs_srv_block.cs_wtstatistics.cs_lior_kbytes;
  liow  = Cs_srv_block.cs_wtstatistics.cs_liow_done;
  liowk = Cs_srv_block.cs_wtstatistics.cs_liow_kbytes;

  /* Transaction rates cannot be determined */
  CsSamplerBlkPtr->txn[CURR] = 0;
  CsSamplerBlkPtr->txn[PEAK] = 0;

  for (;;)
  {
				 
    if (LockSamplerBlk(&hCsSamplerSem) != OK)
    {
    	ExitThread((DWORD)-1);
    }

    if (CsSamplerBlkPtr->shutdown)
    {
	/*
	** Detach the sampler block Managed Object
	*/
	if (attached)
	    MOdetach(CSsamp_index_name, "CsSamplerBlkPtr");

	MEfree((PTR)CsSamplerBlkPtr);
	CsSamplerBlkPtr = NULL;

	CSsamp_stopping = TRUE;
    	UnlockSamplerBlk(hCsSamplerSem);
	CloseHandle(hCsSamplerSem);
	hCsSamplerSem = NULL;

    	ExitThread(0);
    }

    if (!attached)
    {
	/*
	** Attach the sampler block Managed Object
	*/
	MOattach(MO_INSTANCE_VAR, CSsamp_index_name, "CsSamplerBlkPtr",
		 (PTR) CsSamplerBlkPtr);
	attached = TRUE;
    }

    ++CsSamplerBlkPtr->numsamples;   /* Count the number of times we sample */

    /* Loop thru all the SCBs in the server */
    for (an_scb = Cs_srv_block.cs_known_list->cs_next;
    	 an_scb && an_scb != Cs_srv_block.cs_known_list;
	 an_scb = an_scb->cs_next)
    {
	if (an_scb->cs_thread_type >= -1 && 
	    an_scb->cs_thread_type <= MAXSAMPTHREADS - 1)
	    cs_thread_type = an_scb->cs_thread_type;
	else
	    cs_thread_type = MAXSAMPTHREADS - 1; /* use the <invalid> thread */

	/* If Factotum thread, try to isolate which kind */
	if ( cs_thread_type == CS_FACTOTUM )
	{
	    if ( MEcmp((char *)&an_scb->cs_username, " <WriteBehind", 13) == 0 )
		cs_thread_type = CS_WRITE_BEHIND;
	    else if ( MEcmp((char *)&an_scb->cs_username, " <Sort", 6) == 0 )
		cs_thread_type = CS_SORT;
	}

	if (an_scb->cs_state >= 0 &&
	    an_scb->cs_state <= MAXSTATES - 1) 
	    cs_state = an_scb->cs_state;
	else
	    cs_state = MAXSTATES - 1;		/* use the <invalid> state */

	++CsSamplerBlkPtr->Thread[cs_thread_type].numthreadsamples;

	if ( cs_thread_type == CS_NORMAL )
	    ++CsSamplerBlkPtr->totusersamples;
	else
	    ++CsSamplerBlkPtr->totsyssamples;

	switch (cs_state)
	{
	    case CS_COMPUTABLE:		/* Count current facility */
	    {	
	    	i4  facility;

		++CsSamplerBlkPtr->Thread[cs_thread_type].state[cs_state];
		facility = (*Cs_srv_block.cs_facility)(an_scb);
		if (facility >= MAXFACS || facility < 0)
		    facility = MAXFACS - 1;
		++CsSamplerBlkPtr->Thread[cs_thread_type].facility[facility];
		break;
	    }

	    case CS_EVENT_WAIT:		/* Count event types */
		if ( an_scb->cs_memory & CS_BIO_MASK )
		    ++CsSamplerBlkPtr->Thread[cs_thread_type].evwait[EV_BIO];
		else if ( an_scb->cs_memory & CS_DIO_MASK )
		    ++CsSamplerBlkPtr->Thread[cs_thread_type].evwait[EV_DIO];
		else if ( an_scb->cs_memory & CS_LIO_MASK )
		    ++CsSamplerBlkPtr->Thread[cs_thread_type].evwait[EV_LIO];
		else if ( an_scb->cs_memory & CS_LOG_MASK )
		    ++CsSamplerBlkPtr->Thread[cs_thread_type].evwait[EV_LOG];
		else if (an_scb->cs_memory & CS_LOCK_MASK)
		{
		    ++CsSamplerBlkPtr->Thread[cs_thread_type].evwait[EV_LOCK];
		    AddLock( an_scb->cs_sync_obj ?
		    		*((LK_LOCK_KEY *)an_scb->cs_sync_obj) :
		    		dummy_lock,
			     cs_thread_type );
		}
		else
		    ++CsSamplerBlkPtr->Thread[cs_thread_type].state[cs_state];
		event = (an_scb->cs_memory & CS_DIO_MASK ?
			  an_scb->cs_memory & CS_IOR_MASK ?
			  0 : 1
			 :
			 an_scb->cs_memory & CS_LIO_MASK ?
			  an_scb->cs_memory & CS_IOR_MASK ?
			  2 : 3
			 :
			 an_scb->cs_memory & CS_BIO_MASK ?
			  an_scb->cs_memory & CS_IOR_MASK ?
			  4 : 5
			 :
			 an_scb->cs_memory & CS_LOG_MASK ?
			  6 :
			 an_scb->cs_memory & CS_LOCK_MASK ?
			  7 :
			 an_scb->cs_memory & CS_LGEVENT_MASK ?
			  8 :
			 an_scb->cs_memory & CS_LKEVENT_MASK ?
			  9 :
			 /* else it is ...   unknown */
			  10);

		switch (cs_thread_type)
		{
		    case CS_USER_THREAD:
			++CsSamplerBlkPtr->numusereventsamples;
			++CsSamplerBlkPtr->userevent[event]; /* count event type */
			break;
		    default:
			++CsSamplerBlkPtr->numsyseventsamples;
			++CsSamplerBlkPtr->sysevent[event]; /* count event type */
			break;
		} /* switch (cs_thread_type) */
		break;

	    case CS_MUTEX:
		++CsSamplerBlkPtr->Thread[cs_thread_type].state[cs_state];
		AddMutex( ((CS_SEMAPHORE *)an_scb->cs_sync_obj),
				cs_thread_type );
		break;

	    /* Uninteresting states */
	    default:
		++CsSamplerBlkPtr->Thread[cs_thread_type].state[cs_state];
		break;
	} /* switch (cs_state) */
    } /* for */

    /*
    ** If a second or more worth of intervals appear to have elapsed,
    ** compute current and peak per-second I/O, Transaction rates.
    */
    if ( (elapsed += CsSamplerBlkPtr->interval) >= 1000 )
    {
	/* Get the current time; the interval is not reliable! */
	stoptime = CS_checktime();

	if ( (seconds = stoptime - starttime) )
	{
	    if ( (CsSamplerBlkPtr->bior[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_bior_done - bior)
		       / seconds)
		    > CsSamplerBlkPtr->bior[PEAK] )
		CsSamplerBlkPtr->bior[PEAK] = CsSamplerBlkPtr->bior[CURR];

	    if ( (CsSamplerBlkPtr->biow[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_biow_done - biow)
		       / seconds)
		    > CsSamplerBlkPtr->biow[PEAK] )
		CsSamplerBlkPtr->biow[PEAK] = CsSamplerBlkPtr->biow[CURR];

	    if ( (CsSamplerBlkPtr->dior[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_dior_done - dior)
		       / seconds)
		    > CsSamplerBlkPtr->dior[PEAK] )
		CsSamplerBlkPtr->dior[PEAK] = CsSamplerBlkPtr->dior[CURR];

	    if ( (CsSamplerBlkPtr->diork[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_dior_kbytes - diork)
		       / seconds)
		    > CsSamplerBlkPtr->diork[PEAK] )
		CsSamplerBlkPtr->diork[PEAK] = CsSamplerBlkPtr->diork[CURR];

	    if ( (CsSamplerBlkPtr->diow[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_diow_done - diow)
		       / seconds)
		    > CsSamplerBlkPtr->diow[PEAK] )
		CsSamplerBlkPtr->diow[PEAK] = CsSamplerBlkPtr->diow[CURR];

	    if ( (CsSamplerBlkPtr->diowk[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_diow_kbytes - diowk)
		       / seconds)
		    > CsSamplerBlkPtr->diowk[PEAK] )
		CsSamplerBlkPtr->diowk[PEAK] = CsSamplerBlkPtr->diowk[CURR];

	    if ( (CsSamplerBlkPtr->lior[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_lior_done - lior)
			/ seconds)
		    > CsSamplerBlkPtr->lior[PEAK] )
		CsSamplerBlkPtr->lior[PEAK] = CsSamplerBlkPtr->lior[CURR];

	    if ( (CsSamplerBlkPtr->liork[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_lior_kbytes - liork)
			/ seconds)
		    > CsSamplerBlkPtr->liork[PEAK] )
		CsSamplerBlkPtr->liork[PEAK] = CsSamplerBlkPtr->liork[CURR];

	    if ( (CsSamplerBlkPtr->liow[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_liow_done - liow)
			/ seconds)
		    > CsSamplerBlkPtr->liow[PEAK] )
		CsSamplerBlkPtr->liow[PEAK] = CsSamplerBlkPtr->liow[CURR];

	    if ( (CsSamplerBlkPtr->liowk[CURR] =
		   (Cs_srv_block.cs_wtstatistics.cs_liow_kbytes - liowk)
			/ seconds)
		    > CsSamplerBlkPtr->liowk[PEAK] )
		CsSamplerBlkPtr->liowk[PEAK] = CsSamplerBlkPtr->liowk[CURR];

	    /* Transaction rate cannot be determined */
	}

	starttime = CS_checktime();
	elapsed = 0;
        bior  = Cs_srv_block.cs_wtstatistics.cs_bior_done;
        biow  = Cs_srv_block.cs_wtstatistics.cs_biow_done;
        dior  = Cs_srv_block.cs_wtstatistics.cs_dior_done;
        diork = Cs_srv_block.cs_wtstatistics.cs_dior_kbytes;
        diow  = Cs_srv_block.cs_wtstatistics.cs_diow_done;
        diowk = Cs_srv_block.cs_wtstatistics.cs_diow_kbytes;
	lior  = Cs_srv_block.cs_wtstatistics.cs_lior_done;
	liork = Cs_srv_block.cs_wtstatistics.cs_lior_kbytes;
	liow  = Cs_srv_block.cs_wtstatistics.cs_liow_done;
	liowk = Cs_srv_block.cs_wtstatistics.cs_liow_kbytes;
    }

    sleeptime = CsSamplerBlkPtr->interval;

    UnlockSamplerBlk(hCsSamplerSem);

    Sleep (sleeptime);
  } /* for (;;) */

} /* CS_sampler */
Beispiel #12
0
/*{
** Name: opv_agrv	- allocate new global range variable
**
** Description:
**	Find a free slot in the global range table for an 
**      aggregate function, or implicitly referenced index.  
**      If there are no free slots for the aggregate function, then the 
**      optimization is aborted and an error reported.  There will be
**      one global range table per optimization and there will be no
**      overlapping of range table assignments i.e. it is conceivable
**      the two temporary relations could use the same range table
**      entry since they do not exist at the same... this will not be
**      done.
**
** Inputs:
**      global				ptr to global state variable
**      name                            ptr to table name
**                                      NULL- indicates a temporary table
**      owner                           ptr to owner name
**      abort                           TRUE if optimization should be aborted
**                                      in case of error
**
** Outputs:
**	Returns:
**	    - index into global range table representing the allocated
**          variable
**	Exceptions:
**	    Will generate an internal exception if the global range table
**          is full.  This will abort the query and report an error.
**
** Side Effects:
**	    none
**
** History:
**	7-apr-86 (seputis)
**          initial creation
**	11-apr-91 (seputis)
**	    ask for RDF info if name, or table ID is given so
**	    that explicit secondary index substitution can get
**	    histograms
**	18-sep-92 (ed)
**	    bug 44850 - added parameter to allow multi-to-one mapping
**	    so a common aggregate temp can be used
**	17-Jan-2004 (schka24)
**	    Rename RDR_BLD_KEY to RDR_BLD_PHYS, gives us partition info too.
[@history_line@]...
*/
OPV_IGVARS
opv_agrv(
	OPS_STATE          *global,
	DB_TAB_NAME        *name,
	DB_OWN_NAME        *owner,
	DB_TAB_ID          *table_id,
	OPS_SQTYPE         sqtype,
	bool               abort,
	OPV_GBMVARS        *gbmap,
	OPV_IGVARS	   gvarno)
{
    OPV_IGVARS		grv_index; /* index into global range table */
    OPV_IGVARS		empty_index; /* index into global range table of
				    ** free element */
    OPV_GRT             *gbase;    /* ptr to base of array of ptrs to global
				   ** range table elements */
    bool		lookup;    /* look for existing definition if
                                   ** names are available */

    lookup = name && owner;	   /* TRUE - if RDF table ID given */
    empty_index = OPV_NOGVAR;
    gbase = global->ops_rangetab.opv_base;
    for ( grv_index = 0; grv_index < OPV_MAXVAR; grv_index++)
    {
	OPV_GRV		*existing_var;
	if (!(existing_var = gbase->opv_grv[grv_index]))
	{
	    if (empty_index == OPV_NOGVAR)
	    {
		empty_index = grv_index;
		if (!lookup)
		    break;	    /* empty slot found and we do not need
				    ** to continue searching for an existing
                                    ** table entry of the same name */
	    }
	}
	else
	{
	    if (lookup
		&&
		existing_var->opv_relation
		&&
		existing_var->opv_relation->rdr_rel
		&&
		(   existing_var->opv_relation->rdr_rel->tbl_name.db_tab_name[0]
		    ==
		    name->db_tab_name[0]
		)
		&&
		(  existing_var->opv_relation->rdr_rel->tbl_owner.db_own_name[0]
		    ==
		    owner->db_own_name[0]
		)
		&&
		!MEcmp((PTR)&existing_var->opv_relation->rdr_rel->tbl_name,
		    (PTR)name, sizeof(*name))
		&&
		!MEcmp((PTR)&existing_var->opv_relation->rdr_rel->tbl_owner,
		    (PTR)owner, sizeof(*owner))
		&&
		(   !gbmap
		    ||
		    !BTtest((i4)grv_index, (char *)gbmap)  /* do not use the
						** same global range variable
                                                ** in the same subquery twice
                                                ** or OPC will complain */
		)
	       )
	    {	/* a match has been found */
		if (gbmap)
		    BTset((i4)grv_index, (char *)gbmap); /* set the global
						** bit map so that this
                                                ** range variable is not
                                                ** reused in the same subquery
                                                */
		return(grv_index);
	    }
	}
    }

    if (empty_index != OPV_NOGVAR)
    {
	if (gvarno == OPV_NOGVAR)
	{
	    /* empty slot found - allocate and initialize slot and return     */
	    OPV_GRV       *grv;     /* pointer to global range table element  */
	    RDF_CB	      *rdfcb;

	    rdfcb = &global->ops_rangetab.opv_rdfcb;
	    if (name || table_id)
	    {   /* if name is available then table ID might be available */
		if (table_id)
		{	/* use table ID if available */
		    STRUCT_ASSIGN_MACRO((*table_id), rdfcb->rdf_rb.rdr_tabid); /*
					** need table name */
		    rdfcb->rdf_rb.rdr_types_mask = RDR_RELATION | 
			RDR_ATTRIBUTES | RDR_BLD_PHYS; /*get relation info 
					    ** - The optimizer uses attribute
					    ** info in query tree directly 
					    ** but it is needed to be requested
					    ** since the RDF uses attr info to
					    ** build RDR_BLK_PHYS info.  The
					    ** attribute info does not need to
					    ** be requested if RDF is changed.*/
		}
		else
		{	/* table ID not available so use name */
		    MEfill( (i4)sizeof(DB_TAB_ID), (u_char)0, 
			(PTR)&rdfcb->rdf_rb.rdr_tabid);
		    rdfcb->rdf_rb.rdr_types_mask = RDR_RELATION | 
			RDR_ATTRIBUTES | RDR_BLD_PHYS | RDR_BY_NAME;
		    STRUCT_ASSIGN_MACRO((*name), rdfcb->rdf_rb.rdr_name.rdr_tabname);/* need
					    ** table name */
		    STRUCT_ASSIGN_MACRO((*owner), rdfcb->rdf_rb.rdr_owner);/* 
					    ** need table owner */
		}
	    }
	    else
		rdfcb->rdf_info_blk = NULL; /* get new ptr to info
					    ** associated with global var */

	    /* allocate and initialize global range table element */
	    if (opv_parser(global, empty_index, sqtype, 
		(name != NULL) || (table_id != NULL), /* TRUE - if rdf info needs to be retrieved */ 
		FALSE,		/* TRUE - if this is a parser range table element */
		abort)		/* TRUE - if error occurs then otherwise FALSE
				    ** means return varinit == TRUE */
		)
		return(OPV_NOGVAR);	/* ignore variable if error occurs */

	    grv = gbase->opv_grv[empty_index]; /* get ptr to element */
	    grv->opv_qrt = OPV_NOGVAR; /* indicates that this table was not
				    ** explicitly referenced in the query */
	    grv->opv_relation = rdfcb->rdf_info_blk; /* save ptr to RDF info */
	}
	else
	{
	    gbase->opv_grv[empty_index] = gbase->opv_grv[gvarno]; /* used
					** for aggregate temporaries which
					** require "2 cursors" */
	}
	if (gbmap)
	    BTset((i4)empty_index, (char *)gbmap); /* set the global
				    ** bit map so that this
				    ** range variable is not
				    ** reused in the same subquery
				    */
    }
    else if (abort)
	/* the entire table is full so report and error */
	opx_error(E_OP0005_GRANGETABLE);
    return (empty_index);	    /* return with no range table entry */
}
Beispiel #13
0
static DB_STATUS
qeu_qalarm_by_name(
	void *toss, QEU_QUAL_PARAMS *qparams)
{
    DB_SECALARM *search_tup;
    DB_SECALARM *cur_tup;

    search_tup = (DB_SECALARM *) qparams->qeu_qparms[0];
    cur_tup = (DB_SECALARM *) qparams->qeu_rowaddr;
    qparams->qeu_retval = ADE_NOT_TRUE;
    if (search_tup == NULL || cur_tup == NULL)	/* Consistency check */
    {
	return (E_DB_ERROR);
    }

    if (*search_tup->dba_objname.db_name == '\000' &&
        search_tup->dba_objtype == 'D')
    {
	qparams->qeu_retval = ADE_TRUE;
        return (E_DB_OK);                  /* It's ours */
    }

    /*
    ** If user specified a number, then look for that.
    ** Note that alarm -1 indicates all alarms for that object
    */
    if(((search_tup->dba_alarmno>0 && 
       search_tup->dba_alarmno==cur_tup->dba_alarmno) ||
	 search_tup->dba_alarmno==-1) &&
       search_tup->dba_objid.db_tab_base==cur_tup->dba_objid.db_tab_base &&
       search_tup->dba_objid.db_tab_index==cur_tup->dba_objid.db_tab_index &&
       search_tup->dba_objtype==cur_tup->dba_objtype &&
       search_tup->dba_objtype==DBOB_TABLE
       )
    {
	qparams->qeu_retval = ADE_TRUE;
	return (E_DB_OK);			/* It's ours */
    }
    /*
    ** Check for databases, which all have the same object id so
    ** we have to check by name instead
    */
    if(((search_tup->dba_alarmno>0 && 
       search_tup->dba_alarmno==cur_tup->dba_alarmno) ||
	 search_tup->dba_alarmno==-1) &&
       !MEcmp((PTR)&search_tup->dba_objname,(PTR)&cur_tup->dba_objname,
		sizeof(cur_tup->dba_objname)) &&
       search_tup->dba_objtype==cur_tup->dba_objtype &&
       search_tup->dba_objtype==DBOB_DATABASE
       )
    {
	qparams->qeu_retval = ADE_TRUE;
	return (E_DB_OK);			/* It's ours */
    }
    /*
    ** Check by name
    */
    if (MEcmp((PTR)&search_tup->dba_alarmname, 
		   (PTR)&cur_tup->dba_alarmname,
		  sizeof(cur_tup->dba_alarmname)) == 0 &&
       search_tup->dba_objtype==cur_tup->dba_objtype &&
       (search_tup->dba_objtype == DBOB_TABLE &&
       search_tup->dba_objid.db_tab_base == cur_tup->dba_objid.db_tab_base &&
       search_tup->dba_objid.db_tab_index == cur_tup->dba_objid.db_tab_index ||
       search_tup->dba_objtype == DBOB_DATABASE &&
       !(MEcmp((PTR)&search_tup->dba_objname,(PTR)&cur_tup->dba_objname,
                 sizeof(cur_tup->dba_objname))))
       )
    {
	qparams->qeu_retval = ADE_TRUE;
    }
    return (E_DB_OK);
} /* qeu_qalarm_by_name */
Beispiel #14
0
DB_STATUS
qeu_12_objects(
QEF_RCB		*i_qer_p,
QEC_LINK	*v_lnk_p)
{
    DB_STATUS	    status;
    QES_DDB_SES	    *dds_p = & i_qer_p->qef_cb->qef_c2_ddb_ses;
    QED_DDL_INFO    *ddl_p = v_lnk_p->qec_1_ddl_info_p;
    DD_LDB_DESC	    *cdb_p = 
			& dds_p->qes_d4_ddb_p->dd_d3_cdb_info.dd_i1_ldb_desc;
    QEC_D6_OBJECTS  *objects_p = v_lnk_p->qec_13_objects_p;
    QEQ_1CAN_QRY    *ins_p = v_lnk_p->qec_22_insert_p;
    u_i4	    l_obj, l_own, l_ing;


    /* 1.  set up insert information */

    l_obj = (u_i4)qed_u0_trimtail( ddl_p->qed_d1_obj_name, DB_OBJ_MAXNAME, 
	    objects_p->d6_1_obj_name);

    l_own = (u_i4)qed_u0_trimtail( ddl_p->qed_d2_obj_owner, DB_OWN_MAXNAME,
	    objects_p->d6_2_obj_owner);

    l_ing = STlength( IIQE_c0_usr_ingres );

    STcopy(
	v_lnk_p->qec_24_cur_time, 
	objects_p->d6_5_obj_cre);

    objects_p->d6_6_obj_type[0] = 'V';		/* view */
    objects_p->d6_6_obj_type[1] = EOS;

    STcopy(
	objects_p->d6_5_obj_cre,
	objects_p->d6_7_obj_alt);

    /*
    ** Assume that if object name begins with ii, and if owner is $ingres,
    ** then it is a system object.
    */

    if( ( l_obj >= 2 ) &&
        (MEcmp( objects_p->d6_1_obj_name, "ii", 2 ) == 0 ) &&
        ( l_own == l_ing ) &&
        (MEcmp( objects_p->d6_2_obj_owner, IIQE_c0_usr_ingres, l_ing ) == 0 ))
    {
        objects_p->d6_8_sys_obj[0] = 'Y';       /* system object */
    }
    else
    {
        objects_p->d6_8_sys_obj[0] = 'N';       /* not a system object */
    }

    objects_p->d6_8_sys_obj[1] = EOS;

    objects_p->d6_9_to_expire[0] = 'N';		/* no expiration date */
    objects_p->d6_9_to_expire[1] = EOS;

    objects_p->d6_10_exp_date[0] = EOS;		/* no expiration date */

    ins_p->qeq_c1_can_id = INS_615_DD_DDB_OBJECTS;
    ins_p->qeq_c3_ptr_u.d6_objects_p = objects_p;
    ins_p->qeq_c4_ldb_p = cdb_p;

    /* 2.  send INSERT query */

    status = qel_i1_insert(i_qer_p, v_lnk_p);
    return(status);
}    
Beispiel #15
0
/*{
** Name: dmve_del_location - The recovery of an delete location operation.
**
** Description:
**	This function performs the recovery of the delete location 
**      update operation.  This is to update the config file 
**      with any new locations deleted by unextenddb.
**	In the case of UNDO, reads the config file, if update has been
**      made, then it adds it otherwise it just closes and continues.
**      In case of DO, reads the config file, deletes and then closes.
**
** Inputs:
**	dmve_cb
**	    .dmve_log_rec	    The rename file log record.
**	    .dmve_action	    Should be DMVE_UNDO, DMVE_REDO or DMVE_DO.
**	    .dmve_dcb_ptr	    Pointer to DCB.
**
** Outputs:
**	dmve_cb
**	    .dmve_error.err_code    The reason for error status.
**	Returns:
**	    E_DB_OK
**	    E_DB_ERROR
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	29-apr-2004 (gorvi01)
**          Created for UNEXTENDDB.
**	09-Nov-2004 (jenjo02)
**	    Relocated misplaced logging of CLR from DMVE_DO 
**	    to DMVE_UNDO
*/
DB_STATUS
dmve_del_location(
DMVE_CB		*dmve_cb)
{
    DMVE_CB		*dmve = dmve_cb;
    DB_STATUS		status = E_DB_OK;
    DB_STATUS		local_status = E_DB_OK;
    i4		error = E_DB_OK, local_error = E_DB_OK;
    DM0L_DEL_LOCATION	*log_rec = (DM0L_DEL_LOCATION *)dmve_cb->dmve_log_rec;
    LG_LSN		*log_lsn = &log_rec->loc_header.lsn; 
    DMP_DCB             *dcb;
    DM0C_CNF		*config = 0;
    DM0C_CNF		*cnf = 0;
    i4             lock_list;
    DMP_LOC_ENTRY       *l;
    i4	        loc_count;
    i4	        i;
    i4	        recovery_action;
    i4	        dm0l_flags;
    DB_ERROR		local_dberr;

    CLRDBERR(&dmve->dmve_error);

    for (;;)
    {
	if (log_rec->loc_header.length != sizeof(DM0L_DEL_LOCATION) || 
	    log_rec->loc_header.type != DM0LDELLOCATION)
	{
	    SETDBERR(&dmve->dmve_error, 0, E_DM9601_DMVE_BAD_PARAMETER);
	    break;
	}

	dcb = dmve->dmve_dcb_ptr;
	lock_list = dmve->dmve_lk_id; 

	recovery_action = dmve->dmve_action;
	if (log_rec->loc_header.flags & DM0L_CLR)
	    recovery_action = DMVE_UNDO;

        switch (recovery_action)
	{

	   case DMVE_REDO:
	     break;

    	   case DMVE_DO:

	    /* 
	    ** Remove the location entry from the DCB, if it exists.
	    */
	    if (dcb->dcb_ext && dcb->dcb_ext->ext_count)
		loc_count = dcb->dcb_ext->ext_count;
	    else
	  	loc_count = 0;

	    for (i = 0; i < loc_count; i++)
	    {	    
		l = &dcb->dcb_ext->ext_entry[i];
		if (MEcmp((char *)&l->logical, (char *)&log_rec->loc_name,
		    sizeof(DB_LOC_NAME)) == 0)
			break;
	    }
	    if (i >= loc_count)
	    {
		/* No entry found, nothing to remove. */
		;
#ifdef xDEBUG
		TRdisplay(
		    "dmve_del_location: UNDO location '%s' not found in DCB.\n",
		    (char *)&log_rec->loc_name);
#endif
	    }
	    else if (i == (loc_count - 1))
	    {
		/* This is last entry, easy. */
		dcb->dcb_ext->ext_entry[i].phys_length = 0;
	        dcb->dcb_ext->ext_count--;
	    }		
	    else
	    {	    
		/* In middle of list, compress. */
		loc_count--;
		MEcopy((char *)&dcb->dcb_ext->ext_entry[i+1].logical,
		   sizeof(DMP_LOC_ENTRY) * (loc_count-i),
		   (char *)&dcb->dcb_ext->ext_entry[i].logical);

		/* Mark the end of list. */

		dcb->dcb_ext->ext_entry[loc_count].phys_length = 0;
	        dcb->dcb_ext->ext_count--;
	    }

	    /*  
	    ** Open the configuration file. 
	    */
            status = dm0c_open(dcb, DM0C_NOLOCK, lock_list, 
                                       &cnf, &dmve->dmve_error);
	    if (status != E_DB_OK)
		break;
	    config = cnf;

	    /* 
	    ** Delete this entry from the list. 
	    */
	    loc_count = cnf->cnf_dsc->dsc_ext_count;
	    for (i = 0; i < loc_count; i++)
	    {	    
		l = &cnf->cnf_ext[i].ext_location;
		if (MEcmp((char *)&l->logical, (char *)&log_rec->loc_name,
		    sizeof(DB_LOC_NAME)) == 0)
			break;
	    }
	    if (i >= loc_count)
	    {
		/* No entry found, nothing to undo. */
		break;
	    }

	    if (i == (loc_count - 1))
	    {
		/* This is last entry, easy. */
		cnf->cnf_ext[i].length = 0;
		cnf->cnf_ext[i].type = 0;
	        cnf->cnf_dsc->dsc_ext_count--;
		
	    }		
	    else
	    {	    
		/* In middle of list, compress. */
		loc_count--;
		MEcopy((char *)&cnf->cnf_ext[i+1].ext_location.logical,
			       sizeof(DMP_LOC_ENTRY)*(loc_count-i),
                               (char *)&cnf->cnf_ext[i].ext_location.logical);

		/* Mark the end of list. */

		cnf->cnf_ext[loc_count].length = 0;
		cnf->cnf_ext[loc_count].type = 0;
	        cnf->cnf_dsc->dsc_ext_count--;

	    }
	    /*  Close the configuration file. */

	    status = dm0c_close(cnf, DM0C_UPDATE | DM0C_COPY, &dmve->dmve_error);
	    if (status != E_DB_OK)
		break;
	    config = 0;
	    break;    

	case DMVE_UNDO:

	    /*
	    ** Write CLR if necessary
	    */
	    if ((dmve->dmve_logging) &&
	        ((log_rec->loc_header.flags & DM0L_CLR) == 0))
	    {
		dm0l_flags = log_rec->loc_header.flags | DM0L_CLR;

		status = dm0l_del_location(dmve->dmve_log_id, dm0l_flags, 
		    log_rec->loc_type, &log_rec->loc_name, 
		    log_rec->loc_l_extent, &log_rec->loc_extent,
		    log_lsn, &dmve->dmve_error);
		if (status != E_DB_OK)
		{
		    /* XXXX Better error message and continue after logging. */
		    TRdisplay(
		 "dmve_del_location: dm0l_del_location error, status: %d, error: %d\n", 
			status, dmve->dmve_error.err_code);
		    /*
		     * Bug56702: return logfull indication.
		     */
		    dmve->dmve_logfull = dmve->dmve_error.err_code; 
		    break;
		}
	    }

	    /*  Open the configuration file. */

	    l = dcb->dcb_ext->ext_entry;
	    loc_count = dcb->dcb_ext->ext_count;
	    for (i = 0; i < loc_count; i++, l++)
	    if ((MEcmp((char *)&l->logical, (char *)&log_rec->loc_name,
		sizeof(DB_LOC_NAME)) == 0)
		&& (l->flags == log_rec->loc_type))
		break;
	    if (i < loc_count)
	    {
		/* Found this entry, return error. */
		SETDBERR(&dmve->dmve_error, 0, E_DM007E_LOCATION_EXISTS);
		break;
	    }
		    
            status = dm0c_open(dcb, 0, lock_list, 
                                       &cnf, &dmve->dmve_error);
	    if (status != E_DB_OK)
		break;
	    config = cnf;

	    /* Check if there is room. */

            if (cnf->cnf_free_bytes	< sizeof(DM0C_EXT))
	    {
		status = dm0c_extend(cnf, &dmve->dmve_error);
		if (status != E_DB_OK)
		{
		    SETDBERR(&dmve->dmve_error, 0, E_DM0071_LOCATIONS_TOO_MANY);
		    break;
		}
	    }


	    i = cnf->cnf_dsc->dsc_ext_count++;
	    cnf->cnf_ext[i].length = sizeof(DM0C_EXT);
	    cnf->cnf_ext[i].type = DM0C_T_EXT;
	    MEcopy((char *)&log_rec->loc_name, sizeof(DB_LOC_NAME),
                               (char *)&cnf->cnf_ext[i].ext_location.logical);
	    MEcopy((char *)&log_rec->loc_extent,  sizeof(DM_FILENAME),
			       (char *)&cnf->cnf_ext[i].ext_location.physical);
	    cnf->cnf_ext[i].ext_location.flags = log_rec->loc_type;
	    cnf->cnf_ext[i].ext_location.phys_length = log_rec->loc_l_extent;
	    cnf->cnf_ext[i+1].length = 0;
	    cnf->cnf_ext[i+1].type = 0;

	    /* Add new location info to DCB so RFP will be able to use it. */

	    dcb->dcb_ext->ext_count = cnf->cnf_dsc->dsc_ext_count;
	    STRUCT_ASSIGN_MACRO(cnf->cnf_ext[i].ext_location,
				dcb->dcb_ext->ext_entry[i]);

	    /*  Close the configuration file. */

	    status = dm0c_close(cnf, DM0C_UPDATE, &dmve->dmve_error);
	    if (status != E_DB_OK)
		break;
	    config = 0;
	    break;    

	} /* end switch. */
	if (config != 0)
	{
	    (void) dm0c_close(cnf, 0, &local_dberr);
	}	
	if (status != E_DB_OK)
	{
	    uleFormat(&dmve->dmve_error, 0, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    break;
	}
	return(E_DB_OK);

    } /* end for. */
    if (dmve->dmve_error.err_code > E_DM_INTERNAL)
    {
	uleFormat(&dmve->dmve_error, 0, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, 
	    (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	SETDBERR(&dmve->dmve_error, 0, E_DM9617_DMVE_LOCATION);
    }
    return(status);

}
Beispiel #16
0
/*{
** Name: dmve_ext_alter - The recovery of an extent alteration.
**
** Description:
**	This function performs the recovery of the extent alteration
**	done when iiqef_alter_extension (an internal procedure) changes
**	bits in the config file to alter an extent type.
**
**	Currently the only operation supported is changing a defaultable
**	work location (DU_EXT_WORK) to an auxiliary work location (DU_EXT_AWORK)
**	and vice-versa.
**
**	For UNDO, we read the config file and if the update has been made
**	we reverse it, otherwise we just close it and continue.  For DO, we
**	read the config file and if the update was done we ignore, otherwise
**	we make the update.
**
** Inputs:
**	dmve_cb
**	    .dmve_log_rec	    The rename file log record.
**	    .dmve_action	    Should be DMVE_UNDO, DMVE_REDO or DMVE_DO.
**	    .dmve_dcb_ptr	    Pointer to DCB.
**
** Outputs:
**	dmve_cb
**	    .dmve_error.err_code    The reason for error status.
**	Returns:
**	    E_DB_OK
**	    E_DB_ERROR
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	15-sep-93 (jrb)
**          Created for MLSort project.
**	15-apr-1994 (chiku)
**	    Bug56702: return logfull indication.
**	06-may-1996 (nanpr01)
**	    Get rid of compiler warning message.
*/
DB_STATUS
dmve_ext_alter(
DMVE_CB		*dmve_cb)
{
    DMVE_CB		*dmve = dmve_cb;
    DB_STATUS		status = E_DB_OK;
    DB_STATUS		local_status = E_DB_OK;
    i4		error = E_DB_OK, local_error = E_DB_OK;
    DM0L_EXT_ALTER	*log_rec = (DM0L_EXT_ALTER *)dmve_cb->dmve_log_rec;
    LG_LSN		*log_lsn = &log_rec->ext_header.lsn; 
    DMP_DCB             *dcb;
    DM0C_CNF		*config = 0;
    DM0C_CNF		*cnf = 0;
    i4             lock_list;
    DMP_LOC_ENTRY       *l;
    i4	        loc_count;
    i4	        i;
    i4	        recovery_action;
    i4	        dm0l_flags;
    DM2D_ALTER_INFO	dm2d;
    DB_ERROR		local_dberr;

    CLRDBERR(&dmve->dmve_error);

    for (;;)
    {
	if (log_rec->ext_header.length != sizeof(DM0L_EXT_ALTER) || 
	    log_rec->ext_header.type != DM0LEXTALTER)
	{
	    SETDBERR(&dmve->dmve_error, 0, E_DM9601_DMVE_BAD_PARAMETER);
	    break;
	}

	dcb = dmve->dmve_dcb_ptr;
	lock_list = dmve->dmve_lk_id; 

	recovery_action = dmve->dmve_action;
	if (log_rec->ext_header.flags & DM0L_CLR)
	    recovery_action = DMVE_UNDO;

        switch (recovery_action)
	{
	  case DMVE_UNDO:

	    /*
	    ** Write CLR if necessary
	    */
	    if ((dmve->dmve_logging) &&
	        ((log_rec->ext_header.flags & DM0L_CLR) == 0))
	    {
		dm0l_flags = log_rec->ext_header.flags | DM0L_CLR;

		status = dm0l_ext_alter(dmve->dmve_log_id, dm0l_flags, 
		    log_rec->ext_otype, log_rec->ext_ntype,
		    &log_rec->ext_lname, log_lsn, &dmve->dmve_error);
		if (status != E_DB_OK)
		{
		    /* XXXX Better error message and continue after logging. */
		    TRdisplay(
		 "dmve_ext_alter: dm0l_ext_alter error, status: %d, error: %d\n", 
			status, dmve->dmve_error.err_code);
		    /*
		     * Bug56702: return logfull indication.
		     */
		    dmve->dmve_logfull = dmve->dmve_error.err_code;
		    break;
		}
	    }

	    /*  
	    ** Open the configuration file. 
	    */
            status = dm0c_open(dcb, DM0C_NOLOCK, lock_list, &cnf, &dmve->dmve_error);
	    if (status != E_DB_OK)
		break;
	    config = cnf;

	    /* 
	    ** Change bits for location named in the log_rec
	    */
	    loc_count = cnf->cnf_dsc->dsc_ext_count;
	    for (i = 0; i < loc_count; i++)
	    {	    
		l = &cnf->cnf_ext[i].ext_location;
		if (MEcmp((char *)&l->logical, (char *)&log_rec->ext_lname,
		    sizeof(DB_LOC_NAME)) == 0)
			break;
	    }
	    if (i >= loc_count)
	    {
		/* No entry found; this is bad... */
		TRdisplay(
	       "dmve_ext_alter: UNDO location '%s' not found in config file.\n",
		    (char *)&log_rec->ext_lname);

		SETDBERR(&dmve->dmve_error, 0, E_DM92A0_DMVE_ALTER_UNDO);
		status = E_DB_ERROR;
		break;
	    }

	    /* Undo changes to bits of the current location if necessary */
	    if (l->flags & log_rec->ext_ntype)
	    {
		l->flags &= ~(log_rec->ext_ntype);
		l->flags |= log_rec->ext_otype;
	    }

	    /*  Close the configuration file. */

	    status = dm0c_close(cnf, DM0C_UPDATE | DM0C_COPY, &dmve->dmve_error);
	    if (status != E_DB_OK)
		break;
	    config = 0;
	    break;    

	case DMVE_REDO:
	    break;

	case DMVE_DO:
	    /* Fill in dm2d block in preparation for calling dm2d_alter_db
	    ** to rollforward the extent alteration
	    **
	    ** lock_no_wait doesn't matter because we won't do any logging
	    ** or locking in dm2d_alter_db when calling it from here.
	    */
	    dm2d.lock_list	= lock_list;
	    dm2d.lock_no_wait	= 1;
	    dm2d.logging	= 0;
	    dm2d.locking	= 0;
	    dm2d.name		= &dcb->dcb_name;
	    dm2d.db_loc		= (char *) &dcb->dcb_location.physical;
	    dm2d.l_db_loc	= dcb->dcb_location.phys_length;
	    dm2d.location_name  = &log_rec->ext_lname;
	    dm2d.alter_op	= DM2D_EXT_ALTER;

	    dm2d.alter_info.ext_info.drop_loc_type = log_rec->ext_otype; 
	    dm2d.alter_info.ext_info.add_loc_type  = log_rec->ext_ntype;

	    status = dm2d_alter_db(&dm2d, &dmve->dmve_error);

	    break;    
	} /* end switch. */

	if (config != 0)
	{
	    (void) dm0c_close(cnf, 0, &local_dberr);
	}	
	if (status != E_DB_OK)
	{
	    uleFormat(&dmve->dmve_error, 0, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    break;
	}
	return(E_DB_OK);

    } /* end for. */

    if (dmve->dmve_error.err_code > E_DM_INTERNAL)
    {
	uleFormat(&dmve->dmve_error, 0, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, 
	    (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	SETDBERR(&dmve->dmve_error, 0, E_DM9617_DMVE_LOCATION);
    }
    return(status);

}
Beispiel #17
0
/*{
** Name: opa_obylist	- replace variables in outer by inner
**
** Description:
**      This procedure will attempt to replace the variables in the outer 
**      aggregate by using bylist attributes of the inner aggregate. 
**
** Inputs:
**      global                          global state variable
**      inner                           inner function aggregate subquery 
**					whose bylist will be used to attempt
**                                      to replace the outer aggregate variables
**      outer                           outer aggregate subquery whose variables
**                                      will possibly be replaced by the inner
**
** Outputs:
**	Returns:
**	    VOID
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	15-apr-86 (seputis)
**          initial creation
**	16-may-96 (inkdo01)
**	    Change 409554 has been backed out to fix bug 74793. It claimed to
**	    eliminate obsolete code (because of change 409457), but the code
**	    appears to have still been necessary for queries involving outer
**	    joins of aggregate views.
**	3-dec-02 (inkdo01)
**	    Changes for range table expansion.
**	23-nov-05 (inkdo01)
**	    Fix a bug in one of the more complex expressions that derived from 
**	    the range table expansion.
[@history_line@]...
*/
static VOID
opa_obylist(
	OPS_STATE          *global,
	OPS_SUBQUERY       *inner,
	OPS_SUBQUERY       *outer)
{
    OPV_GBMVARS         outermap;   /* var map of outer aggregate */

    opv_smap(outer);		    /* get variable map of outer aggregate */
    MEcopy((char *)&outer->ops_root->pst_sym.pst_value.pst_s_root.pst_lvrm,
	sizeof(outermap), (char *)&outermap);
    BTor(OPV_MAXVAR, (char *)&outer->ops_root->pst_sym.pst_value.pst_s_root.pst_rvrm,
	(char *)&outermap);
    opv_smap(inner);                /* get variable map of inner aggregate */

    BTand(OPV_MAXVAR, (char *)&inner->ops_agg.opa_blmap, (char *)&outermap);
    if (BTcount((char *)&outermap, OPV_MAXVAR) == 0)
	/* if the outer aggregate and the inner aggregate do not have any
	** variables in common then there can be no replacement so return.
	*/
	return;

    BTor(OPV_MAXVAR, (char *)&inner->ops_root->pst_sym.pst_value.pst_s_root.pst_tvrm,
	(char *)&outer->ops_aggmap);
    BTor(OPV_MAXVAR, (char *)&inner->ops_root->pst_sym.pst_value.pst_s_root.pst_lvrm,
	(char *)&outer->ops_aggmap);
    BTor(OPV_MAXVAR, (char *)&inner->ops_root->pst_sym.pst_value.pst_s_root.pst_rvrm,
	(char *)&outer->ops_aggmap);
				    /* this set of variables could be substituted
                                    ** in the outer, so they are not to be
                                    ** assumed to be in the from list for
                                    ** a cartesean product as in the query
                                    ** "select r.a from r,s" */
    {
	OPV_GBMVARS	       usedmap;	/* var map of variables which were
					** replaced by substituting the
					** bylist attributes of the inner
					*/
	OPV_GBMVARS            newmap;	/* var map of the outer aggregate
                                        ** after the inner aggregate bylist
                                        ** used to substitute expressions
                                        ** in the outer
                                        */
	OPV_GBMVARS		tempmap;
	MEfill(sizeof(usedmap), 0, (char *)&usedmap);
					/* initialize var map */
	opa_checkopt(global, inner->ops_agg.opa_byhead->pst_left, outer->ops_root,
	    &usedmap, &newmap); 	/* this routine will return information
                                        ** on what the query tree would
                                        ** look like if the inner aggregate
                                        ** was substituted (without actually
                                        ** doing the substitution)
                                        */
	MEcopy((char *)&newmap, sizeof(newmap), (char *)&tempmap);
	BTand(OPV_MAXVAR, (char *)&usedmap, (char *)&tempmap);
	/* This replaces the old (32 bit varmap) test of "usedmap &&
	** !(newmap & usedmap)". */
	if (BTcount((char *)&usedmap, OPV_MAXVAR) != 0 &&
					/* non-zero implies some optimizations
                                        ** were found */
	    BTcount((char *)&tempmap, OPV_MAXVAR) == 0)
					/* the substitution would eliminate
                                        ** those variables entirely */
	{
	    /* COMMIT THE CHANGES
	    ** the usedmap is non-zero so some variable subtitutions were
	    ** found.  Moreover, the substitutions would entirely eliminate
            ** the variables since newmap is non-zero
            **
	    ** First making a copy of the bylist for the outer aggregate 
	    ** if it exists (and if it is not the main query).  This
            ** is done to avoid the problem of optimizing away the links
            ** made by the outer aggregate.  For example, in the query
            ** RETRIEVE SUPPLIERS WHO SUPPLY ALL PARTS 
            **   ret( s.sname, s.s) where any(p.p by s.s where any(sp.tid
            **	    by p.p,s.s where p.p=sp.p and s.s=sp.s)=0)=0
            ** In this query the outer aggregate references only attributes
            ** in the BY list of the inner aggregate, and won't have the
            ** aggregate result linked to the main query ... if we did
            ** not make a copy of the bylist ... remember that the outer
            ** aggregate was linked to the main query by using the by list
            ** subtrees directly!
            ** FIXME - OPA_LINK will copy the bylists anyways so this copy
            ** is not needed
            */
	    OPV_IGVARS            innervarno; /* var number of inner
                                            ** aggregate which will be
                                            ** referenced for substitution */

	    if (outer->ops_sqtype == OPS_MAIN) 
		global->ops_gmask |= OPS_TCHECK;
	    else if (outer->ops_agg.opa_byhead)   /* outer aggregate has a by list */
	    {
		PST_QNODE             *bylist; /* used to traverse the bylist */

		/* traverse the bylist and copy the subtrees */
		for ( bylist = outer->ops_agg.opa_byhead->pst_left;
		    bylist && bylist->pst_sym.pst_type != PST_TREE;
		    bylist = bylist->pst_left)

		    opv_copytree( global, &bylist->pst_right );
	    }

	    /* Traverse the tree and actually perform the substitutions instead
            ** of only checking for them
            */
	    innervarno = (*inner->ops_agg.opa_graft)->pst_sym.pst_value.
		    pst_s_var.pst_vno;
	    if (outer->ops_global->ops_qheader->pst_numjoins > 0)
	    {	/* make sure that all the outer joins semantics are
		** the same for all the relations referenced, or else
		** semantics are lost, i.e. cannot substitute if variables
		** have different maps */
		PST_J_MASK	pinner;
		PST_J_MASK	pouter;
		bool		first_time;
		OPV_IGVARS	gvar;
		PST_J_MASK	*ijmaskp;
		PST_J_MASK	*ojmaskp;
		OPL_PARSER	*pinnerp;
		OPL_PARSER	*pouterp;

		first_time = TRUE;
		pinnerp = outer->ops_oj.opl_pinner;
		pouterp = outer->ops_oj.opl_pouter;
		for (gvar = -1; (gvar = BTnext((i4)gvar, (char *)&usedmap, 
			(i4)BITS_IN(usedmap)))>=0;)
		{
		    if (first_time)
		    {
			MEcopy((PTR)&pinnerp->opl_parser[gvar],
			    sizeof(pinner), (PTR)&pinner);
			MEcopy((PTR)&pouterp->opl_parser[gvar],
			    sizeof(pouter), (PTR)&pouter);
		    }
		    else
		    {
			if (MEcmp((PTR)&pinnerp->opl_parser[gvar],
			    (PTR)&pinner, sizeof(pinner))
			    ||
			    MEcmp((PTR)&pouterp->opl_parser[gvar],
			    (PTR)&pouter, sizeof(pouter))
			    )
			    return;	    /* outer joins semantics of
					    ** variables to be substituted are
					    ** different, FIXME, try to substitute
					    ** one variable instead of 2 */
		    }
		}
		/* copy the outer join semantics to the substituted variable */
		ijmaskp = &pinnerp->opl_parser[innervarno]; 
		ojmaskp = &pouterp->opl_parser[innervarno];
		if ((BTnext((i4)-1, (char *)ijmaskp, (i4)BITS_IN(*ijmaskp)) >= 0)
		    ||
		    (BTnext((i4)-1, (char *)ojmaskp, (i4)BITS_IN(*ojmaskp)) >= 0)
		    )
		    opx_error(E_OP0288_OJAGG);	/* should not already have an
					    ** outer join defined on this aggregate
					    ** in this query */
		MEcopy((PTR)&pinner, sizeof(*ijmaskp), (PTR)ijmaskp);
		MEcopy((PTR)&pouter, sizeof(*ojmaskp), (PTR)ojmaskp);
	    }
	    outer->ops_vmflag = FALSE;  /* bitmaps need to be updated if a
                                        ** substitution on the outer is made */
	    opa_commit(global, inner->ops_agg.opa_byhead->pst_left, 
		&outer->ops_root, innervarno); /* this routine will traverse 
                                        ** the tree in the same way as 
                                        ** opa_checkopt except that 
                                        ** substitutions will actually be made
                                        */
	    global->ops_gmask &= (~OPS_TCHECK);
	}
    }
}
Beispiel #18
0
/*{
** Name: scs_monitor	- Implement the SCS part of the monitor task
**
** Description:
**	This routine is called ala the regular thread processing routine.
**	It parses its input, decides what to do, and returns the output.
**
**	The commmands completely interpreted here are:
**
**		set server shut	(CS_CLOSE)
**			Disallow new connections, shutdown when
**			last current session exits.
**          
**          	remove SESSION
**          	    	New improved "safe" version, acts the same
**  	    	    	as front-end exiting and dropping GCA connection.
**	
**		kill SESSION
**			Signal CS_KILL_EVENT to a user session actively
**			running a query.
**          
**	NEW:
**		set server closed
**			Disallow new regular user sessions.
**          
**		set server open
**			Reallow new regular user sessions.  Cancel
**			any pending 'set server shut' shutdown.
**
**		show server listen
**
**		crash session SESSIONID
**
**	Commands partially handled here and partially in CSmonitor are:
**
**		stop server	(CS_KILL)
**			Kill user sessions, shutdown when they're gone.
**          
**		stop server conditional (CS_COND_CLOSE)
**			Shutdown if no sessions, which never works because
**			this session always exists.
**          
**		crash server	(CS_CRASH)
**			Take the server down immediately.
**
**	All other commands are passed to CSmonitor for handling.
**
** Inputs:
**	mode				Mode of operation
**					    CS_INPUT, _OUPUT, ...
**	scb				Sessions control block to monitor
**	*command			Text of the command
**	powerful			Is this user powerful
**	output_fcn			Function to call to perform the output.
**					This routine will be called as
**					    (*output_fcn)(newline_present,
**							    length,
**							    buffer)
**					where buffer is the length character
**					output string, and newline_present
**					indicates whether a newline needs to
**					be added to the end of the string.
**
** Outputs:
**	next_mode			As above.
**	Returns:
**	    OK
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	26-Jul-1993 (daveb)
**	    created.
**	15-Sep-1993 (daveb)
**	    ifdef out all but drop connection for now.
**	1-Nov-1993 (daveb)
**	    Match LRC proposal.  Drop becomes remove, remove becomes kill.
**      10-Nov-1993 (daveb)
**          Match approved proposal.  Kill becomes "crash session SESSIONID"
**	15-dec-93 (robf)
**          Add prototype "broadcast" message request.
**	4-mar-94 (robf)
**          Add initial security auditing to iimonitor events.
**	12-dec-1996 (canor01)
**	    Add support for sampler thread.
**	24-Apr-2003 (jenjo02)
**	    Added "kill" command to abort eligible queries
**	    while leaving the session intact, SIR 110141.
**	17-Sep-2004 (schka24)
**	    Manual fix to remove command so that it fires.
**      05-may-2005 (horda03) Bug 114453/INGSRV 3290
**          For server/session changes log the command.
**      22-may-2007 (horda03) Bug 117966
**          Log the command before calling CSmonitor, as
**          the CS could be crashing the server.
**      23-Sep-2009 (hanal04) Bug 115316
**          Added "SHOW SERVER CAPABILITIES".
*/
static STATUS
scs_monitor( i4 mode, CS_SCB *scb, i4 *nmode, char *command,
	    i4 powerful, i4 (*output_fcn)(PTR, i4, char *) )
{
    STATUS		ret_stat;
    char		buf[81];
    bool		completely_done;
    PTR			ptr_scb;
    SCD_SCB		*an_scb;
    i4                  log_cmd = 0;
    i4                  local_error;
    SCD_SCB		*my_scb = (SCD_SCB*)scb;
    
    *nmode = CS_EXCHANGE;
    completely_done = FALSE;
    ret_stat = OK;
    
    switch (mode)
    {
    case CS_INITIATE:
	*nmode = CS_INPUT;
	break;
	
    case CS_TERMINATE:
	break;
	
    case CS_INPUT:
		
	CVlower(command);
	if (STscompare("setservershut", 0, command, 0) == 0)
	{
	    /* Audit log the attempt here? */
	    if (!powerful)
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Superuser status required to stop servers");
		if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		    scs_mon_audit((SCD_SCB*)scb, 
			    SXF_A_CONTROL|SXF_A_FAIL,
			    I_SX274D_SET_SERVER_SHUT
			    );
	    }
	    else /* disallow regular listens, exit when last conn exits */
	    {
		Sc_main_cb->sc_listen_mask = 
		    (SC_LSN_TERM_IDLE |SC_LSN_SPECIAL_OK) ;
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Server will stop. %d. sessions remaining",
			 Sc_main_cb->sc_current_conns );
		if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		    scs_mon_audit((SCD_SCB*)scb, 
			    SXF_A_CONTROL|SXF_A_SUCCESS,
			    I_SX274D_SET_SERVER_SHUT
			    );
                log_cmd = 1;
	    }
	    completely_done = TRUE;
	}
	else if (STscompare("setserverclosed", 0, command, 0) == 0)
	{
	    /* Audit log the attempt here? */
	    if (!powerful)
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Superuser status required to disable connections");
		if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		    scs_mon_audit((SCD_SCB*)scb, 
			    SXF_A_CONTROL|SXF_A_FAIL,
			    I_SX2748_SET_SERVER_CLOSED
			    );
	    }
	    else		/* Disallow regular listens */
	    {
		if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		    scs_mon_audit((SCD_SCB*)scb, 
			    SXF_A_CONTROL|SXF_A_SUCCESS,
			    I_SX2748_SET_SERVER_CLOSED
			    );
		Sc_main_cb->sc_listen_mask &= (~SC_LSN_REGULAR_OK);
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "User connections now disabled" );
                log_cmd = 1;
	    }
	    completely_done = TRUE;
	}
	else if (STscompare("setserveropen", 0, command, 0) == 0)
	{
	    /* Audit log the attempt here? */
	    if (!powerful)
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Superuser status required to enable connections");
		if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		    scs_mon_audit((SCD_SCB*)scb, 
			    SXF_A_CONTROL|SXF_A_FAIL,
			    I_SX2749_SET_SERVER_OPEN
			    );
	    }
	    else  /* allow all listens, cancel any impending shutdown */
	    {
		Sc_main_cb->sc_listen_mask =
		    (SC_LSN_REGULAR_OK | SC_LSN_SPECIAL_OK);
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "User connections now allowed" );
		if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		    scs_mon_audit((SCD_SCB*)scb, 
			    SXF_A_CONTROL|SXF_A_SUCCESS,
			    I_SX2749_SET_SERVER_OPEN
			    );
                log_cmd = 1;
	    }
	    completely_done = TRUE;
	}
	else if (STncasecmp("broadcast", command, 9) == 0)
	{
	    /* Audit log the attempt here? */
	    if (!powerful)
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Superuser status required to broadcast messages");
	    }
	    else  
	    {
		/*
		** Broadcast the message to any connected sessions
		*/
		scs_scan_scbs(scs_broadcast_mesg, (PTR)(command+10));
	    }
	    completely_done = TRUE;
	}
	else if (STscompare("stopserverconditional", 0, command, 0) == 0 ||
		 STscompare("stopserver", 0, command, 0) == 0 ||
		 STscompare("crashserver", 0, command, 0) == 0 )
	{
	    /* Audit log the attempt here? */
	    if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		scs_mon_audit((SCD_SCB*)scb, 
			powerful?
			    SXF_A_CONTROL|SXF_A_SUCCESS:
			    SXF_A_CONTROL|SXF_A_FAIL,         /* Action */
			I_SX274A_STOP_SERVER
			);
                log_cmd = powerful;
	}
        else if (STscompare("showservercapabilities", 0, command, 0) == 0)
        {
            TRformat(output_fcn, 1, buf, sizeof(buf) - 1, "%v",
                     SC_CAPABILITIES_FLAGS, Sc_main_cb->sc_capabilities );
            completely_done = TRUE;
        }
	else if (STscompare("showserverlisten", 0, command, 0) == 0)
	{
	    TRformat(output_fcn, 1, buf, sizeof(buf) - 1, "%s", 
		     Sc_main_cb->sc_listen_mask & SC_LSN_REGULAR_OK ?
		     "OPEN" : "CLOSED" );
	    completely_done = TRUE;
	}
	else if (STscompare("showservershutdown", 0, command, 0) == 0)
	{
	    TRformat(output_fcn, 1, buf, sizeof(buf) - 1, "%s", 
		     Sc_main_cb->sc_listen_mask & SC_LSN_TERM_IDLE ?
		     "PENDING" : "OPEN" );
	    completely_done = TRUE;
	}
# ifdef NOT_SUPPORTED
	else if (STscompare("showconnections", 0, command, 0) == 0 )
	{
	    scs_scan_scbs( scs_show_func, (PTR)&powerful );
	    completely_done = TRUE;
	}
	else if (STscompare("show connection", 15, command, 15) == 0 )
	{
	    completely_done = TRUE;
	    STzapblank(command, command);
	    if (CVaxptr(command + 14, &ptr_scb) ||
		!scs_is_user_scb( (an_scb = (SCD_SCB *)ptr_scb) ) )
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Invalid connection id");
		break;
	    }
	    scs_show_func( an_scb, &powerful );
	}
# endif
	else if (STscompare("remove", 6, command, 6) == 0)
	{
	    completely_done = TRUE;
	    STzapblank(command, command);
	    if (CVaxptr(command + 6, &ptr_scb) || scb == NULL ||
		!scs_is_user_scb( (an_scb = (SCD_SCB *)ptr_scb) ) ||
		an_scb == my_scb )
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Invalid session id");
		break;
	    }
	    if ((MEcmp(an_scb->cs_scb.cs_username, scb->cs_username,
		       sizeof(scb->cs_username))) && !powerful)
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Superuser or owner status required to remove session");
		if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		    scs_mon_audit((SCD_SCB*)scb, 
			    SXF_A_CONTROL|SXF_A_FAIL,
			    I_SX274B_REMOVE_SESSION
			    );
		break;
	    }
	    if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		scs_mon_audit((SCD_SCB*)scb, 
			SXF_A_CONTROL|SXF_A_SUCCESS,
			I_SX274B_REMOVE_SESSION
			);
	    scs_remove_sess( an_scb );
	    TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
		     "Session %p removed", an_scb);
            log_cmd = 1;
	}
	else if (STscompare("crash session", 13, command, 13) == 0)
	{
	    completely_done = TRUE;
	    STzapblank(command, command);
	    if (CVaxptr(command + 12, &ptr_scb) || scb == NULL ||
		!scs_is_user_scb( (an_scb = (SCD_SCB *)ptr_scb) ) ||
		an_scb == my_scb )
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Invalid session id");
		break;
	    }
	    if ((MEcmp(an_scb->cs_scb.cs_username, scb->cs_username,
		       sizeof(scb->cs_username))) && !powerful)
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Superuser or owner status required to crash session");
		if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		    scs_mon_audit((SCD_SCB*)scb, 
			SXF_A_CONTROL|SXF_A_FAIL,
			I_SX274C_CRASH_SESSION
			);
		break;
	    }
	    if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		scs_mon_audit((SCD_SCB*)scb, 
			SXF_A_CONTROL|SXF_A_SUCCESS,
			I_SX274C_CRASH_SESSION
			);
	    scs_crash_sess( an_scb );
	    TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
		     "Session %p crashed", an_scb);
            log_cmd = 1;
	}
	else if (STscompare("kill", 4, command, 4) == 0)
	{
	    completely_done = TRUE;
	    STzapblank(command, command);
	    if (CVaxptr(command + 4, &ptr_scb) || scb == NULL ||
		!scs_is_user_scb( (an_scb = (SCD_SCB *)ptr_scb) ) ||
		an_scb == my_scb )
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Invalid session id");
	    }
	    else if ((MEcmp(an_scb->cs_scb.cs_username, scb->cs_username,
		       sizeof(scb->cs_username))) && !powerful)
	    {
		TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			 "Superuser or owner status required to kill query");
		if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
		    scs_mon_audit((SCD_SCB*)scb, 
			SXF_A_CONTROL|SXF_A_FAIL,
			I_SX2755_KILL_QUERY
			);
	    }
	    else switch ( an_scb->scb_sscb.sscb_qmode )
	    {
		case 0:
		    TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			    "Session %p is not executing a query", an_scb);
		    break;

		/* Honor only "meaningful" types of queries: */
		case PSQ_RETRIEVE:
		case PSQ_RETINTO:
		case PSQ_APPEND:
		case PSQ_REPLACE:
		case PSQ_DELETE:
		case PSQ_COPY:
		case PSQ_MODIFY:
		case PSQ_EXECQRY:
		case PSQ_EXCURS:
		case PSQ_CALLPROC:
		case PSQ_REPCURS:
		case PSQ_RETCURS:
		case PSQ_EXEDBP:
		case PSQ_REGPROC:
		case PSQ_DDEXECPROC:
		case PSQ_CREATE:
		    if ( an_scb->scb_sscb.sscb_force_abort ||
			 an_scb->scb_sscb.sscb_interrupt )
		    {
			TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			     "Session %p query already aborting", an_scb);
		    }
		    else
		    {
			scs_kill_query( an_scb );
			if ( Sc_main_cb->sc_capabilities & SC_C_C2SECURE )
			    scs_mon_audit((SCD_SCB*)scb, 
				    SXF_A_CONTROL|SXF_A_SUCCESS,
				    I_SX2755_KILL_QUERY
				    );
			TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
				 "Session %p query killed", an_scb);
		    }
		    break;

		default:
		    TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
			     "Session %p query cannot be killed", an_scb);
		    break;
	    }
	}
# ifdef NOT_SUPPORTED
	else if (STscompare("help", 0, command, 0) == 0)
	{
	    TRformat(output_fcn, 1, buf, sizeof(buf) - 1,
		     "SCS monitor commands:\nset server shut\nset server closed\nset server open\nshow server listen\nshow server shutdown\nremove SESSION\ncrash session SESSION\n\nCS monitor commands:\n");
	}
# endif
        else if (! CS_is_mt())
	    /* OS Thread version will start an OS thread in the CS */
            if ((STscompare("start sampling", 14, command, 14) == 0))
            {
                if (!powerful)
                {
                    TRformat(output_fcn, (i4 *) 1, buf, sizeof(buf)-1,
                        "Superuser status required to start sampling.", 0L);
                }
                else
                {
                    GCA_LS_PARMS        local_crb;
	            CL_ERR_DESC         errdesc;

                    local_crb.gca_status = 0;
                    local_crb.gca_assoc_id = 0;
                    local_crb.gca_size_advise = 0;
                    local_crb.gca_user_name = "<Sampler Thread>";
                    local_crb.gca_account_name = 0;
                    local_crb.gca_access_point_identifier = "NONE";
                    local_crb.gca_application_id = 0;

		    /* set up all the CS control blocks for the sampler */
	            ret_stat = CSmonitor( mode, scb, nmode, command,
				          powerful, output_fcn );

		    if ( ret_stat == OK )
                        ret_stat = CSadd_thread(CS_LIM_PRIORITY-1, (PTR) &local_crb,
                                                SCS_SSAMPLER, (CS_SID*)NULL, &errdesc);

                    if (ret_stat)
                    {
                        TRformat(output_fcn, (i4 *) 1, buf, sizeof(buf)-1,
                               "Sampling failed to start.");
                    }
                }
            }

        /* log the command before calling CSmonitor(), as the server could be left in an
        ** unknown state if the command CRASH SERVER or STOP SERVER are used
        */

        if (log_cmd)
        {
           ule_format( I_SC051E_IIMONITOR_CMD, 0, ULE_LOG, NULL, 0, 0, 0, &local_error,
                       3, STlength(command), command,
                       DB_OWN_MAXNAME, &((SCD_SCB *)scb)->scb_sscb.sscb_ics.ics_rusername,
                       sizeof(DB_TERM_NAME), &((SCD_SCB *)scb)->scb_sscb.sscb_ics.ics_terminal, 
                       0, 0);
        }

	if( !completely_done )
	    ret_stat = CSmonitor( mode, scb, nmode, command,
				 powerful, output_fcn );
	break;
	
    case CS_OUTPUT:
	break;
    }

    return( ret_stat );
}
Beispiel #19
0
/*{
** Name: LGadd	- Add Database.
**
** Description:
**	Add database to logging system for a process.
**
**      This routine adds a database to the logging system.  This service
**	is used to inform the logging system that records recorded in the log
**	file should be associated with this database.  A database can be 
**	marked as journaled by setting the LG_JOURNAL flag.  The fact that a
**	database is journaled is used by the logging system to recognize the
**	need to copy log records from the log file to a journal file.
**
** NOTE on adding databases that are being recovered:
**	When a database requires REDO recovery, the LDB for that database
**	is marked LDB_RECOVER.  This routine will return LG_DB_INCONSISTENT
**	(signifying that the database is inconsistent) if anyone tries
**	to add the db while it is being recovered.  This is not a very
**	on-line solution.
**
**	A better solution is to make sure that servers that want to open
**	a database that is currently being recovered are forced to wait
**	until the db is fully recovered, then they should be able to
**	proceed.
**
** Inputs:
**      lg_id                           Log identifier.
**	flag				Zero or
**					    LG_JOURNAL: if a journaled DB.
** 					    LG_NOTDB: not a DB; administrative
** 					    LG_PRETEND_CONSISTENT: used by verifydb
** 					    LG_FCT: fast commit
** 					    LG_READONLY: a readonly database
**	buffer				Database information buffer.
**      l_buffer                        Length of buffer.
**
** Outputs:
**      db_id                           Database identifier. Unique
**                                      identifier associated with this
**                                      instantiation of the logging/locking
**                                      server.  After logging/locking 
**                                      restarted, a database can have
**                                      a different id.
**      sys_err                         Reason for error return status.
**	Returns:
**	    OK				Success.
**	    LG_BADPARAM			Bad parameters to call.
**	    LG_DB_INCONSISTENT		Inconsistent database.
**	    LG_EXCEED_LIMIT		Out of LDB's.
**	    LG_SHUTTING_DOWN		Shutdown has occured (or pending).
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	Summer, 1992 (bryanp)
**	    Working on the new portable logging and locking system.
**	18-jan-1993 (rogerk)
**	    Removed LG_WILLING_COMMIT flag - now only LG_ADDONLY is used
**	    during recovery processing.  Add ldb_j_last_la, ldb_d_last_la
**	    fields.
**	15-mar-1993 (rogerk)
**	    Reduced Logging - Phase IV:
**	    Removed LG_ADDONLY flag.  Recovery processing now adds db with
**		a normal LGadd call and alters it via LG_A_DBCONTEXT to
**		reestablish its context.
**	26-apr-1993 (bryanp)
**	    6.5 Cluster Support:
**		Add ldb_sback_lsn field to the LDB.
**		Make sure that lpd_type is set so that LPDs can be deallocated
**		    properly upon error.
**	26-jul-1993 (bryanp)
**	    When adding a database which is associated with a remote log file,
**		do not signal a local opening of the database. This occurs
**		when the CSP process on one node is recovering the work
**		performed by another node; in this case we do NOT wish to
**		signal to the RCP that a local open is being performed, since
**		in fact no local access is implied by adding this database.
**	    When adding the notdb again, increment the ldb_lpd_count even if
**		the ldb_buffer info doesn't match. The notdb is always the notdb
**	26-jul-1993 (rogerk)
**	    Changed journal and dump window tracking in the logging system.
**	    Use new journal and dump log address fields.
**	12-oct-1993 (tad)
**	    Bug #56449
**	    Changed %x to %p for pointer values.
**	30-Jan-1996 (jenjo02)
**	    Reorganized LG_add() such that if NOTDB is wanted, 
**	    the search of the ldb queue is bypassed; after all,
**	    we know it's buried in the LGD and easy to find.
**	11-Sep-1996 (jenjo02)
**	    Fix a bug in LG_add() search of lgd_ldb_q which was looping
**	    if more that 2 LDBs were extant.
** 	13-jun-1997 (wonst02)
** 	    Added LG_READONLY and LDB_READONLY for readonly databases.
**	12-nov-1998 (kitch01)
**		Bug 90140. If the database is currently pending a close then
**		mark the open as in CLOSE_WAIT. This will ensure that the close
**		is processed before this open and prevent locking errors on the journals
**      7-oct-2004 (thaju02)
**          Use SIZE_TYPE to allow memory pools > 2Gig.
        21-Jun-2006 (hanal04) Bug 116272
**          Take the lgd_mutex before the ldb_mutex in order to ensure
**          the acquisition order is consistent with LG_archive_complete()
**          and LG_event(). Flag LG_signal_event() that we already have the
**          lgd_mutex.
**	01-Nov-2006 (jonj)
**	    Use consistent ldb_q_mutex, ldb_mutex ordering thoughout the code.
**	    Don't put LDB on queue until it's completely initialized.
**	15-Jan-2010 (jonj)
**	    SIR 121619 MVCC: Initialize new ldb_active_lxbq.
**      09-aug-2010 (maspa05) b123189, b123960
**          Pass flag to indicate a readonly database LDB_RODB, so that it
**          gets picked up by LGshow
*/
STATUS
LGadd(
LG_LGID             external_lg_id,
i4		    flag,
char		    *buffer,
i4		    l_buffer,
LG_DBID		    *external_db_id,
CL_ERR_DESC	    *sys_err)
{
    register LGD        *lgd = (LGD *)LGK_base.lgk_lgd_ptr;
    register LPB	*lpb;
    register LDB	*ldb;
    register LFB	*lfb;
    register LPD	*lpd;
    LDB			*next_ldb;
    LPD			*next_lpd;
    SIZE_TYPE		end_offset;
    SIZE_TYPE		ldb_offset;
    SIZE_TYPE		*lpbb_table;
    SIZE_TYPE		*ldbb_table;
    i4			err_code;
    bool		initialize_ldb = FALSE;
    STATUS		status;
    LG_I4ID_TO_ID	lg_id;
    LG_ID		*db_id = (LG_ID*)external_db_id;
    LFB			*cur_db_lfb;
    i4			SignalEvent = 0;

    /*
    ** If the logging system is already in "shutdown" mode, then no new
    ** LGadd calls are permitted
    */
    LG_WHERE("LGadd")

    CL_CLEAR_ERR(sys_err);

    if ((lgd->lgd_status & (LGD_START_SHUTDOWN | LGD_IMM_SHUTDOWN)) != 0)
	return (LG_SHUTTING_DOWN);

    if (l_buffer == 0 ||
	l_buffer > sizeof(ldb->ldb_buffer))
    {
	uleFormat(NULL, E_DMA411_LGADD_BAD_LEN, (CL_ERR_DESC *)NULL,
		    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2,
		    0, l_buffer, 0, sizeof(ldb->ldb_buffer));
	return (LG_BADPARAM);
    }

    /*	Check the lg_id. */

    lg_id.id_i4id = external_lg_id;
    if (lg_id.id_lgid.id_id == 0 || (i4)lg_id.id_lgid.id_id > lgd->lgd_lpbb_count)
    {
	uleFormat(NULL, E_DMA40F_LGADD_BAD_ID, (CL_ERR_DESC *)NULL,
		    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2,
		    0, lg_id.id_lgid.id_id, 0, lgd->lgd_lpbb_count);
	return (LG_BADPARAM);
    }

    lpbb_table = (SIZE_TYPE *)LGK_PTR_FROM_OFFSET(lgd->lgd_lpbb_table);
    lpb = (LPB *)LGK_PTR_FROM_OFFSET(lpbb_table[lg_id.id_lgid.id_id]);

    if (status = LG_mutex(SEM_EXCL, &lpb->lpb_mutex))
	return(status);

    if (lpb->lpb_type != LPB_TYPE ||
	lpb->lpb_id.id_instance != lg_id.id_lgid.id_instance)
    {
	(VOID)LG_unmutex(&lpb->lpb_mutex);
	uleFormat(NULL, E_DMA410_LGADD_BAD_PROC, (CL_ERR_DESC *)NULL,
		    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 3,
		    0, lpb->lpb_type, 0, lpb->lpb_id.id_instance,
		    0, lg_id.id_lgid.id_instance);
	return (LG_BADPARAM);
    }

    /*
    **  Allocate an LPD, causing lpd_type to be set to LPD_TYPE.
    */

    if ((lpd = (LPD *)LG_allocate_cb(LPD_TYPE)) == 0) 
    {
	(VOID)LG_unmutex(&lpb->lpb_mutex);
	return (LG_EXCEED_LIMIT);
    }

    /*
    ** CLEANUP: error returns after this point must free the lpd before
    **		returning! 
    */

    lfb = (LFB *)LGK_PTR_FROM_OFFSET(lpb->lpb_lfb_offset);

    /*
    ** If this isn't a real user database, but is instead the "NOTDB"
    ** database which is used by system processes such as the DMFRCP and
    ** DMFACP daemons, then it has a special reserved LDB slot and does not
    ** get located by its database information buffer, therefore we
    ** can skip locking and scanning the ldb queue.
    */
    end_offset = LGK_OFFSET_FROM_PTR(&lgd->lgd_ldb_next);

    /*
    ** When both the lgd_ldb_q and ldb must be mutexed, always take
    ** the lgd_ldb_q_mutex, then ldb_mutex.
    */

    /* Lock and hold the ldb queue mutex */
    if (status = LG_mutex(SEM_EXCL, &lgd->lgd_ldb_q_mutex))
	return(status);

    if (flag & LG_NOTDB)
    {
	ldbb_table = (SIZE_TYPE *)LGK_PTR_FROM_OFFSET(lgd->lgd_ldbb_table);
	ldb = (LDB *)LGK_PTR_FROM_OFFSET(ldbb_table[1]);

	if (status = LG_mutex(SEM_EXCL, &ldb->ldb_mutex))
	    return(status);

	/*
	** IF the notdb has already been initialized, then we have some
	** caller who is adding the notdb with a different buffer, thus
	** we didn't match when we searched the database list for a
	** matching ldb_buffer field. Since we really don't care about the
	** ldb_buffer for the notdb (the notdb is the notdb, after all),
	** we'll treat this case as though the ldb buffer fields matched.
	*/
	if (ldb->ldb_type == LDB_TYPE)
	{
	    /*  Count new reference to LDB. */
	    ldb->ldb_lpd_count++;
	}
	else
	{
	    /*
	    ** first use of NOTDB; initialize it.
	    */
	    lgd->lgd_ldb_inuse++;
	    initialize_ldb = TRUE;
	}
    }
    else
    {
	/*
	** Scan database list to see if this database is already known. Each
	** database is identified by a "database information buffer", which DMF
	** passes in. This buffer contains items such as the database name, owner
	** name, etc. If the database information buffer passed to LGadd exactly
	** matches the database information buffer of an existing LDB, then this
	** database is already known (has already been added by another logging
	** system process).
	*/

	for (ldb_offset = lgd->lgd_ldb_next;
	    ldb_offset != end_offset;)
	{
	    ldb = (LDB *)LGK_PTR_FROM_OFFSET(ldb_offset);

	    if (ldb->ldb_l_buffer != l_buffer ||
		MEcmp(ldb->ldb_buffer, buffer, l_buffer))
	    {
		ldb_offset = ldb->ldb_next;
		continue;
	    }

	    if ( CXcluster_enabled() )
	    {
	        /*
		** Node recovery must use distinct ldb context per node log file
		*/
		cur_db_lfb = (LFB *)LGK_PTR_FROM_OFFSET(ldb->ldb_lfb_offset);

		if ((lfb->lfb_l_nodename || cur_db_lfb->lfb_l_nodename) &&
		    (lfb->lfb_l_nodename != cur_db_lfb->lfb_l_nodename ||
		    MEcmp(lfb->lfb_nodename, cur_db_lfb->lfb_nodename,
				    lfb->lfb_l_nodename)))
		{
		    ldb_offset = ldb->ldb_next;
#ifdef xDEBUG
		    TRdisplay("%@ RCP-P1: Recovering %~t, ignore ldb for %~t %x\n",
			lfb->lfb_l_nodename, lfb->lfb_nodename,
			cur_db_lfb->lfb_l_nodename, cur_db_lfb->lfb_nodename,
			flag & LG_CSP_RECOVER);
#endif

		    continue;
		}
	    }
	    
	    if (status = LG_mutex(SEM_EXCL, &ldb->ldb_mutex))
		return(status);

	    /*
	    ** Check again after semaphore wait.
	    ** If LDB is no longer a match (it was in the 
	    ** process of being eradicated while we waited for
	    ** the ldb_mutex), and start the search again from
	    ** the top of the queue.
	    */
	    if (ldb->ldb_type != LDB_TYPE ||
	        ldb->ldb_l_buffer != l_buffer ||
		MEcmp(ldb->ldb_buffer, buffer, l_buffer))
	    {
		(VOID)LG_unmutex(&ldb->ldb_mutex);
		ldb_offset = lgd->lgd_ldb_next;
		continue;
	    }
	    break;
	}

	if (ldb_offset != end_offset)
	{
	    /*
	    **  LDB exists. If the database is already known to be inconsistent,
	    **  then no new adds of the database are permitted, unless the caller
	    **  acknowledges that it "knows" that the database is inconsistent by
	    **  passing the "pretend consistent" flag (used by verifydb).
	    */

	    if (ldb->ldb_status & LDB_INVALID)
	    {
		if ( (flag & LG_PRETEND_CONSISTENT) == 0 )
		{
		    (VOID)LG_unmutex(&ldb->ldb_mutex);
		    (VOID)LG_unmutex(&lgd->lgd_ldb_q_mutex);
		    LG_deallocate_cb(LPD_TYPE, (PTR)lpd);
		    (VOID)LG_unmutex(&lpb->lpb_mutex);
		    return (LG_DB_INCONSISTENT);	
		}
	    }

	    /*
	    ** If the database reference count is zero, then the database
	    ** must be opened by the RCP before the server can use it.
	    ** Mark the status opendb_pending - this will suspend any thread
	    ** making an LGwrite call on this database (note that the first
	    ** thing a server does after opening a database is to write an
	    ** OPENDB log record) until the RCP has finished opening it.
	    **
	    ** If the database reference count is not zero, but the database
	    ** is undergoing REDO recovery, then we cannot allow new servers
	    ** to access the database until recovery is complete.  Set the
	    ** database status to opendb_pending and opn_wait.
	    **
	    ** NOTE that if we begin to support READ-ONLY databases and servers
	    ** are able to open databases without writing an OPENDB record, then
	    ** we must come up with a new method of suspending database openers
	    ** until recovery is complete.
	    */
		/* Bug 90140. If the database is currently pending a close then
		** mark the open as in CLOSE_WAIT. This will ensure that the close
		** is processed before this open and prevent locking errors on the journals
		*/
	    if (ldb->ldb_lpd_count == 0)
	    {
		if ((ldb->ldb_status & LDB_PURGE) == 0)
		{
		    if ((ldb->ldb_status & LDB_OPENDB_PEND) == 0)
		    {
			ldb->ldb_status |= LDB_OPENDB_PEND;
			if (ldb->ldb_status & LDB_CLOSEDB_PEND)
				ldb->ldb_status |= LDB_CLOSE_WAIT;
			if (flag & LG_PRETEND_CONSISTENT)
			    ldb->ldb_status |= LDB_PRETEND_CONSISTENT;
	    		if (flag & LG_READONLY)
			    ldb->ldb_status |= LDB_READONLY;
	    		if (flag & LG_RODB)
			    ldb->ldb_status |= LDB_RODB;
			SignalEvent = LGD_OPENDB;
		    }
		}
		else
		    ldb->ldb_status &= ~(LDB_PURGE);
	    }
	    else if (ldb->ldb_status & LDB_RECOVER)
	    {
		/*
		** The database is open, but is being recovered.
		** Set the opendb_pending and opn_wait flags - this will 
		** prevent any new transactions from proceeding on this 
		** database until recovery is complete.  Marking this
		** database as OPENDB_PEND will not cause the database to
		** be processed in count_opens because of the opn_wait flag.
		*/
		ldb->ldb_status |= (LDB_OPENDB_PEND | LDB_OPN_WAIT);
	    }
	    /*  Count new reference to LDB. */

	    ldb->ldb_lpd_count++;
	}
	else
	{
	    /*
	    ** This database is NOT known.
	    **
	    ** If the caller has passed special flags indicating that they
	    ** require that the newly-added database must have a particular DB_ID
	    ** assigned to it, then ensure that the new LDB gets the right ID.
	    **
	    ** Otherwise, just pick the next LDB off the free list.

	    */
	    /*
	    **  Allocate a new LDB 
	    **  returning with the ldb_mutex held
	    **  and lgd_ldb_inuse incremented.
	    */
	    if ((ldb = (LDB *)LG_allocate_cb(LDB_TYPE)) == 0)
	    {
		LG_deallocate_cb(LPD_TYPE, (PTR)lpd);
		(VOID)LG_unmutex(&lgd->lgd_ldb_q_mutex);
		(VOID)LG_unmutex(&lpb->lpb_mutex);
		return (LG_EXCEED_LIMIT);
	    }
	    initialize_ldb = TRUE;
	}
    }

#ifdef xDEBUG
    /*
    ** For a while, we were having problems with corruption of the LFB/LDB
    ** large block queues, and this debugging code helped to track those
    ** problems down.
    */
    if (ldb->ldb_id.id_id == 0)
    {
	TRdisplay("%@ LGadd: args were:(%d,%d).%x.%p.%x.%p\n",
		lg_id.id_lgid.id_id, lg_id.id_lgid.id_instance,
		flag, buffer, l_buffer, db_id);
	LG_debug_wacky_ldb_found(lgd, ldb);
	return (LG_BADPARAM);
    }
#endif

    /*
    ** NOTE: Be careful about adding error returns after this point,
    ** because any such error return must first free up BOTH the LPD AND
    ** the LDB, if an LDB was actually allocated.
    */

    /*
    **  Initialize the LDB, if one was allocated
    **  or if first use of NOTDB LDB.
    */
    if (initialize_ldb)
    {
	MEcopy((PTR)buffer, l_buffer, (PTR)ldb->ldb_buffer);
	ldb->ldb_l_buffer = l_buffer;
	ldb->ldb_type = LDB_TYPE;
	ldb->ldb_status = LDB_ACTIVE;
	ldb->ldb_stat.read = 0;
	ldb->ldb_stat.write = 0;
	ldb->ldb_stat.begin = 0;
	ldb->ldb_stat.wait = 0;
	ldb->ldb_stat.force = 0;
	ldb->ldb_stat.end = 0;
	ldb->ldb_lxbo_count = 0;
	ldb->ldb_lxb_count = 0;
	ldb->ldb_lpd_count = 1;
	ldb->ldb_lfb_offset = lpb->lpb_lfb_offset;
	ldb->ldb_j_first_la.la_sequence = 0;
	ldb->ldb_j_first_la.la_block    = 0;
	ldb->ldb_j_first_la.la_offset   = 0;
	ldb->ldb_j_last_la.la_sequence  = 0;
	ldb->ldb_j_last_la.la_block     = 0;
	ldb->ldb_j_last_la.la_offset    = 0;
	ldb->ldb_d_first_la.la_sequence = 0;
	ldb->ldb_d_first_la.la_block    = 0;
	ldb->ldb_d_first_la.la_offset   = 0;
	ldb->ldb_d_last_la.la_sequence  = 0;
	ldb->ldb_d_last_la.la_block     = 0;
	ldb->ldb_d_last_la.la_offset    = 0;
	ldb->ldb_sbackup.la_sequence    = 0;
	ldb->ldb_sbackup.la_block       = 0;
	ldb->ldb_sbackup.la_offset      = 0;
	ldb->ldb_sback_lsn.lsn_high     = 0;
	ldb->ldb_sback_lsn.lsn_low      = 0;
	ldb->ldb_eback_lsn.lsn_high     = 0;
	ldb->ldb_eback_lsn.lsn_low      = 0;

	/*
	** Assume no simulated MVCC journal writes.
	**
	** This may be changed by LGalter(LG_A_JFIB)
	*/
	MEfill(sizeof(ldb->ldb_jfib), 0, &ldb->ldb_jfib);

	/*
	** Set last_commit, last_lsn, and first_la to
	** the current values from the header.
	*/
	ldb->ldb_last_commit = lfb->lfb_header.lgh_last_lsn;
	ldb->ldb_last_lsn = lfb->lfb_header.lgh_last_lsn;
	ldb->ldb_first_la = lfb->lfb_header.lgh_end;

	/*
	** Initialize active transaction queue to empty.
	*/
	ldb->ldb_active_lxbq.lxbq_next = ldb->ldb_active_lxbq.lxbq_prev
		= LGK_OFFSET_FROM_PTR(&ldb->ldb_active_lxbq.lxbq_next);

	ldb->ldb_lgid_low = 0;
	ldb->ldb_lgid_high = 0;

	/*
	** Extract the external Database Id from the info buffer to
	** put in an accessable place of the ldb.
	*/
	I4ASSIGN_MACRO(ldb->ldb_buffer[DB_DB_MAXNAME+DB_OWN_MAXNAME], ldb->ldb_database_id);

	if (flag & LG_NOTDB)
	{
	    ldb->ldb_status |= LDB_NOTDB;
	}
	else
	{
	    if (flag & LG_JOURNAL)
		ldb->ldb_status |= LDB_JOURNAL;
	    if (flag & LG_PRETEND_CONSISTENT)
		ldb->ldb_status |= LDB_PRETEND_CONSISTENT;
	    if (flag & LG_READONLY)
		ldb->ldb_status |= LDB_READONLY;
	    if (flag & LG_RODB)
	        ldb->ldb_status |= LDB_RODB;
	}

	if ((ldb->ldb_status & LDB_NOTDB) == 0)
	{
	    if ((lfb->lfb_status & LFB_USE_DIIO) == 0)
	    {
		/*
		** signal to the RCP that local use of this database is
		** beginning. The database remains in pending-open state
		** until the RCP acknowledges the open.
		*/
		ldb->ldb_status |= LDB_OPENDB_PEND;
		SignalEvent = LGD_OPENDB;
	    }
	}
    }

    /*
    ** The LPD (Logging system Process-Database connection block) contains
    ** pointers to its associated database and process blocks, and contains
    ** a list of all transactions which this process has begun within this
    ** database:
    */

    lpd->lpd_ldb = LGK_OFFSET_FROM_PTR(ldb);
    lpd->lpd_lpb = LGK_OFFSET_FROM_PTR(lpb);

    lpd->lpd_lxbq.lxbq_next = lpd->lpd_lxbq.lxbq_prev =
	    LGK_OFFSET_FROM_PTR(&lpd->lpd_lxbq.lxbq_next);

    lpd->lpd_lxb_count = 0;

    /*	Change various counters. */

    lpb->lpb_lpd_count++;
    lgd->lgd_stat.add++;

    /*	Queue LPD to the LPB. */

    lpd->lpd_next = lpb->lpb_lpd_next;
    lpd->lpd_prev = LGK_OFFSET_FROM_PTR(&lpb->lpb_lpd_next);

    next_lpd = (LPD *)LGK_PTR_FROM_OFFSET(lpb->lpb_lpd_next);
    next_lpd->lpd_prev    = 
	    lpb->lpb_lpd_next = LGK_OFFSET_FROM_PTR(lpd);

    /*
    ** If the adding process uses fast commit, then mark the database
    ** as open with FC protocols.  Should a crash occur, all updates to
    ** this db since the last Consistency Point will need to be redone.
    */
    if ((flag & LG_FCT) && (lpb->lpb_status & LPB_FCT))
	ldb->ldb_status |= LDB_FAST_COMMIT;

    /* If opener wants MVCC, ensure that it is on, found or not */
    if ( flag & LG_MVCC )
	ldb->ldb_status |= LDB_MVCC;

    /*	Return identifier. */

    *db_id = lpd->lpd_id;

    if ( initialize_ldb )
    {
	/* Lastly, insert LDB on the active queue. */

	ldb->ldb_next = lgd->lgd_ldb_next;
	ldb->ldb_prev = end_offset;
	next_ldb = (LDB *)LGK_PTR_FROM_OFFSET(lgd->lgd_ldb_next);
	next_ldb->ldb_prev    = 
	    lgd->lgd_ldb_next = LGK_OFFSET_FROM_PTR(ldb);
    }

    /*
    ** Unwind the mutexes
    */
    (VOID)LG_unmutex(&ldb->ldb_mutex); 
    (VOID)LG_unmutex(&lgd->lgd_ldb_q_mutex); 
    (VOID)LG_unmutex(&lpb->lpb_mutex); 

    /* If any events to signal, do so */
    if ( SignalEvent )
	LG_signal_event(SignalEvent, 0, FALSE);

    return (OK);
}
Beispiel #20
0
/*{
** Name: adt_compare() - Compare 2 data values.
**
** Description:
**	This routine compares two data values.  This will tell the caller if the
**	supplied values are equal, or if not, which one is "greater than" the
**	other.
**
**	This routine exists as a performance boost for DMF.  DMF is not allowed
**	to know how to compare data values for the various datatypes.
**	Therefore, if this routine did not exist, DMF would have to make a
**	function call to "adc_compare()" for every attribute in the tuples
**	being compared.  Even though tuples are constructs that seem a level
**	above what ADF logically handles, the performance improvement in this
**	case justifies this routine.
**
**	To avoid the overhead of an adc_compare call,
**	this routine has built into it the semantics for
**	comparing several of the most common datatypes supported by INGRES.
**
**	If the routine does run across a datatype that is not in this list, it
**	will call the general routine "adc_compare()", thereby guaranteeing
**	that it will function (perhaps slower), for ALL datatypes, even future
**	user defined ADTs.
**
**	When NULL values are involved, this routine will use the same semantics
**	that "adc_compare()" uses:  a NULL value will be considered greater
**	than any other value, and equal to another NULL value.
**
**	PLEASE NOTE:  As with "adc_compare()", no pattern matching for
**	-----------   the string datatypes is done within this routine.
**
**
** Inputs:
**	adf_scb				Pointer to an ADF session control block.
**	    .adf_errcb			ADF_ERROR struct.
**		.ad_ebuflen		The length, in bytes, of the buffer
**					pointed to by ad_errmsgp.
**		.ad_errmsgp		Pointer to a buffer to put formatted
**					error message in, if necessary.
**      atr                             Pointer to DB_ATTR.
**      d1                        	Pointer to first value.
**      d2                              Pointer to second value.
**
** Outputs:
**	adf_scb				Pointer to an ADF session control block.
**	    .adf_errcb			ADF_ERROR struct.  If an
**					error occurs the following fields will
**					be set.  NOTE: if .ad_ebuflen = 0 or
**					.ad_errmsgp = NULL, no error message
**					will be formatted.
**		.ad_errcode		ADF error code for the error.
**		.ad_errclass		Signifies the ADF error class.
**		.ad_usererr		If .ad_errclass is ADF_USER_ERROR,
**					this field is set to the corresponding
**					user error which will either map to
**					an ADF error code or a user-error code.
**		.ad_emsglen		The length, in bytes, of the resulting
**					formatted error message.
**		.adf_errmsgp		Pointer to the formatted error message.
**      status                          Status returned from
**					adc_compare(), if called.
**	
**	    The following DB_STATUS codes may be returned by adc_compare():
**	    E_DB_OK, E_DB_WARN, E_DB_ERROR, E_DB_SEVERE, E_DB_FATAL
**
**	    If a DB_STATUS code other than E_DB_OK is returned, the caller
**	    can look in the field adf_scb.adf_errcb.ad_errcode to determine
**	    the ADF error code.  The following is a list of possible ADF error
**	    codes that can be returned by this routine:
**
**          E_AD0000_OK                 Operation succeeded.
**          E_AD2004_BAD_DTID           Datatype id unknown to ADF.
**          E_AD2005_BAD_DTLEN          Internal length is illegal for
**					the given datatype.
**		(Others not yet defined)
**
** Returns:
**      i4  < 0   if 1st < 2nd
**          = 0   if 1st = 2nd
**          > 0   if 1st > 2nd
**
** Exceptions:
**       none
**
** Side Effects:
**       none
**
** History:
**      10-Feb-86 (thurston)
**          Initial creation.
**	03-apr-86 (thurston)
**	    Initial coding.  Also, added two more return statuses (stati?):
**          E_AD2004_BAD_DTID and E_AD2005_BAD_DTLEN.
**      11-jun-86 (jennifer)
**          Fixed bug compare result asigned to adt_cmp_result instead
**          of indirect through this pointer, i.e. *adt_cmp_result.
**      11-jun-86 (jennifer)
**	    Fixed bug where the first entry of attribute array (0)
**          was being used.  This entry is always garbage since 
**          attributes are numbered from 1.
**      27-jul-86 (ericj)
**	    Converted for new ADF error handling.
**	19-nov-86 (thurston)
**	    Fixed the comparison for text.
**	22-sep-88 (thurston)
**	    Added bit representation check as a first pass on each attr.  Also,
**	    added code to deal with nullable types here ... this could be a big
**	    win, since all nullable types were going through adc_compare(), now
**	    they need not.  Also, added cases for CHAR and VARCHAR.
**	21-oct-88 (thurston)
**	    Got rid of all of the `#ifdef BYTE_ALIGN' stuff by using the
**	    appropriate [I2,I4,F4,F8]ASSIGN_MACROs.  This also avoids a bunch
**	    of MEcopy() calls on BYTE_ALIGN machines.
**	21-Apr-89 (anton)
**	    Added local collation support
**	17-Jun-89 (anton)
**	    Moved local collation routines to ADU from CL
**	25-jul-89 (jrb)
**	    Added support for decimal datatype.
**	02-jan-90 (jrb)
**	    Fix alignment problem.
**	08-aug-91 (seg)
**	    "d1" and "d2" are dereferenced too often with the assumption
**	    that (PTR) == (char *) to fix.  Made them (char *).
**	28-mar-2001 (abbjo03)
**	    Add support for DB_NCHR_TYPE and DB_NVCHR_TYPE.
**	16-dec-04 (inkdo01)
**	    Add collation ID parm to aduucmp() calls.
**	02-Feb-2005 (jenjo02)
**	    Consolidated from the nine adt functions which duplicated
**	    this "compare" code. Runs the most optimal compare
**	    based on datatype for a single attribute.
**
**	    Optimized CHA/VCH compares to use MEcmp rather than
**	    CMcmpcase loop when possible.
**
**	    Replace giant switch statement with if-then-else
**	    ordered most likely to least likely, more or less.
**	    The switch was consuming 27% of the CPU used by this
**	    function.
**
**	    Added DB_STATUS *status as a function parameter so
**	    if adc_compare returns an error, it will be returned
**	    to the caller rather than as a bogus compare "result".
**	27-Apr-2005 (jenjo02 for stial01)
**	    Replaced computing compare value using arithmetic
**	    (d1 - d2) with logical compares ( d1 < d2...) as
**	    the arithmetic may over/underflow and return the
**	    wrong result.
**	13-May-2005 (thaju02)
**	    For differing length vchar, return value based on 
**	    comparison of longer length vchar to blank. (B114514)
**	19-Jun-2006 (gupsh01)
**	    Added support for new date/time types.
**	3-may-2007 (dougi)
**	    Tweak slightly to allow MEcmp() on collation/double byte
**	    if they're bytewise equal.
**	10-may-2007 (dougi)
**	    Add logic to handle ordering of c/text/char/varchar in UTF8
**	    server.
**	25-jul-2007 (gupsh01)	
**	    Although UTF8 is multibyte it is meant to be processed through
**	    UTF8 comparison code utilizing unicode comparison.
**	17-Aug-2007 (gupsh01)
**	    Fix the UTF8 handling.
*/
i4
adt_compare(
ADF_CB		    *adf_scb,
DB_ATTS		    *atr,		/* Attribute in question */
char		    *d1,		/* Ptr to 1st value */
char		    *d2,		/* Ptr to 2nd value */
DB_STATUS	    *status)		/* Status from adc_compare */

{
    i4			cur_cmp;	/* Result of latest attr cmp */
    i4			vi1, vi2;	/* Temp i4's used to cmp ints */
    i8			lli1, lli2;	/* Compare i8's */
    f8			vf1, vf2;	/* Temp f8's used to cmp flts */
    u_char	        *lc1, *lc2;
    u_char	        blank;
    i4			atr_bdt;	/* Base datatype of attr */
    i2			atr_len;	/* Length of cur attribute */
    i4			d1_isnull, d2_isnull;
    DB_DATA_VALUE	dv1, dv2;	/* Data value structs for call
					** to adc_compare(), if that is
					** necessary.
					*/
    u_char		*tc1, *tc2;	/* Temps used for string compare */
    u_char		*endtc1, *endtc2;
    UCS2		*tn1, *tn2;	/* Temps used for Nstring compare */
    UCS2		*endtn1, *endtn2;
	/*
	**  The following four lines provide temp storage to solve
	**  byte allignment problems on some archictectures.
	*/
    i2			i2_t1, i2_t2;
    i4			i4_t1, i4_t2;
    f4			f4_t1, f4_t2;
    f8			f8_t1, f8_t2;

#define	ADT_LT	(i4)-1
#define ADT_EQ	(i4)0
#define	ADT_GT	(i4)1

    *status = E_DB_OK;

    atr_len = atr->length;

    if ( (atr_bdt = atr->type) < 0 )
    {
	/* Nullable datatype */

	d1_isnull = (*((char *)d1 + atr_len - 1) & ADF_NVL_BIT);
	d2_isnull = (*((char *)d2 + atr_len - 1) & ADF_NVL_BIT);

	if ( !d1_isnull && !d2_isnull )
	{
	    /* Neither is the Null value, look at data */
	    atr_bdt = -atr_bdt;
	    atr_len--;
	}
	else if (d1_isnull && d2_isnull)
	    return(ADT_EQ);   /* both are Null values; 1st = 2nd */
	else if (d1_isnull)
	    return(ADT_GT);   /* 1st is Null value; 1st > 2nd */
	else
	    return(ADT_LT);  /* 2nd is Null value; 1st < 2nd */
    }

    /* "if then else" consumes ~27% less CPU than "switch" */

    if ( atr_bdt == DB_INT_TYPE )
    {
	/* If both operands aligned... */
	/* Extra casts to shut up compilers -- only care about low bits */
	if ( (((i4)(SCALARP)d1 | (i4)(SCALARP)d2) & atr_len-1) == 0 )
	{
	    if ( atr_len == 4 )
	    {
		if      (*(i4*)d1 < *(i4*)d2)	return(ADT_LT);
		else if (*(i4*)d1 > *(i4*)d2)	return(ADT_GT);
		else			  	return(ADT_EQ);
	    }
	    if ( atr_len == 8 )
	    {
		if      (*(i8*)d1 < *(i8*)d2)	return(ADT_LT);
		else if (*(i8*)d1 > *(i8*)d2)	return(ADT_GT);
		else			  	return(ADT_EQ);
	    }
	    if ( atr_len == 2 )
	    {
		if      (*(i2*)d1 < *(i2*)d2)	return(ADT_LT);
		else if (*(i2*)d1 > *(i2*)d2)	return(ADT_GT);
		else			  	return(ADT_EQ);
	    }
	
	    if      (*(i1*)d1 < *(i1*)d2)	return(ADT_LT);
	    else if (*(i1*)d1 > *(i1*)d2)	return(ADT_GT);
	    else			  	return(ADT_EQ);
	}
	/* One or both not aligned... */
	if (atr_len == 4)
	{
	    I4ASSIGN_MACRO(*d1, i4_t1);
	    I4ASSIGN_MACRO(*d2, i4_t2);
	    if      (i4_t1 < i4_t2)	return(ADT_LT);
	    else if (i4_t1 > i4_t2)	return(ADT_GT);
	    else			return(ADT_EQ);
	}
	if (atr_len == 8)
	{
	    I8ASSIGN_MACRO(*d1, lli1);
	    I8ASSIGN_MACRO(*d2, lli2);
	    if      (lli1 < lli2)	return(ADT_LT);
	    else if (lli1 > lli2)	return(ADT_GT);
	    else		  	return(ADT_EQ);
	}
	if (atr_len == 2)
	{
	    I2ASSIGN_MACRO(*d1, i2_t1);
	    I2ASSIGN_MACRO(*d2, i2_t2);
	    if      (i2_t1 < i2_t2)	return(ADT_LT);
	    else if (i2_t1 > i2_t2)	return(ADT_GT);
	    else			return(ADT_EQ);
	}
	if      (*(i1*)d1 < *(i1*)d2)	return(ADT_LT);
	else if (*(i1*)d1 > *(i1*)d2)	return(ADT_GT);
	else			  	return(ADT_EQ);
    }

    if ( atr_bdt == DB_FLT_TYPE || atr_bdt == DB_MNY_TYPE )
    {
	/* If both operands aligned... */
	/* Extra casts to shut up compilers, only care about low bits */
	if ( (((i4)(SCALARP)d1 | (i4)(SCALARP)d2) & atr_len-1) == 0 )
	{
	    if ( atr_len == 8 )
	    {
		if      (*(f8*)d1 < *(f8*)d2) return(ADT_LT);
		else if (*(f8*)d1 > *(f8*)d2) return(ADT_GT);
		else                  	  return(ADT_EQ);
	    }
	    if      (*(f4*)d1 < *(f4*)d2) return(ADT_LT);
	    else if (*(f4*)d1 > *(f4*)d2) return(ADT_GT);
	    else                  	  return(ADT_EQ);
	}

	/* One or both not aligned... */
	if ( atr_len == 8 )
	{
	    F8ASSIGN_MACRO(*d1, f8_t1);
	    F8ASSIGN_MACRO(*d2, f8_t2);
	    if      (f8_t1 < f8_t2) return(ADT_LT);
	    else if (f8_t1 > f8_t2) return(ADT_GT);
	    else   		    return(ADT_EQ);
	}
	F4ASSIGN_MACRO(*d1, f4_t1);
	F4ASSIGN_MACRO(*d2, f4_t2);
	if      (f4_t1 < f4_t2) return(ADT_LT);
	else if (f4_t1 > f4_t2) return(ADT_GT);
	else   		        return(ADT_EQ);
    }

    if ( atr_bdt == DB_BYTE_TYPE || atr_bdt == DB_TABKEY_TYPE ||
	      atr_bdt == DB_LOGKEY_TYPE )
    {
	return(MEcmp(d1, d2, atr_len));
    }

    if ( atr_bdt == DB_CHA_TYPE || atr_bdt == DB_VCH_TYPE )
    {
	if ( atr_bdt == DB_CHA_TYPE )
	{
	    /* Try the turbo compare. */
	    cur_cmp = MEcmp(d1, d2, atr_len);

	    /* If not equal and UTF8-enabled ... */
	    if (cur_cmp && (adf_scb->adf_utf8_flag & AD_UTF8_ENABLED))
		return(adt_utf8comp(adf_scb, atr, atr_bdt, atr_len, 
							d1, d2, status));

	    /* If neither collation nor doublebyte or if byte-wise equal ... */
	    if ( !(adf_scb->adf_collation || 
		   Adf_globs->Adi_status & ADI_DBLBYTE) || cur_cmp == 0)
	    {
		return(cur_cmp);
	    }

	    tc1    = (u_char *) d1;
	    tc2    = (u_char *) d2;
	    endtc1 = tc1 + atr_len;
	    endtc2 = tc2 + atr_len;
	}
	else
	{
	    I2ASSIGN_MACRO(((DB_TEXT_STRING *)d1)->db_t_count, i2_t1);
	    I2ASSIGN_MACRO(((DB_TEXT_STRING *)d2)->db_t_count, i2_t2);
	    tc1 = (u_char *)d1 + DB_CNTSIZE;
	    tc2 = (u_char *)d2 + DB_CNTSIZE;

	    /* Try the turbo compare on the prefix. */
	    cur_cmp = MEcmp((char *)tc1, (char *)tc2, min(i2_t1, i2_t2));

	    /* If neither collation nor doublebyte... */
	    if ( !(adf_scb->adf_collation || 
		   Adf_globs->Adi_status & ADI_DBLBYTE) || 
			(adf_scb->adf_utf8_flag & AD_UTF8_ENABLED))
	    {
		i2	diff = i2_t1 - i2_t2;
	    
		/* If not equal or lengths differ and UTF8-enabled ... */
		if ((diff || cur_cmp) && 
			(adf_scb->adf_utf8_flag & AD_UTF8_ENABLED))
		    return(adt_utf8comp(adf_scb, atr, atr_bdt, atr_len, 
							d1, d2, status));

		/* If short compare produces inequality or lengths are
		** the same ... */
		if ( cur_cmp || diff == 0 )
		{
		    return(cur_cmp);
		}

		/*
		** Equal for shorter length.
		** If longer trails all blanks, they're equal
		*/
		if ( diff > 0 )
		{
		    /* tc1 is longer */
		    tc1 += i2_t2;
		    while ( *(tc1++) == MIN_CHAR && --diff > 0 );

		    if (!diff)
			return( ADT_EQ );
		    else
		    {
			tc1--;
			if (*tc1 > MIN_CHAR)
			    return(ADT_GT);
			else
			    return(ADT_LT);
		    }
		}
		else
		{
		    /* tc2 is longer */
		    tc2 += i2_t1;
		    while ( *(tc2++) == MIN_CHAR && ++diff < 0 );

		    if (!diff)
			return( ADT_EQ );
		    else
		    {
			tc2--;
			if (MIN_CHAR > *tc2)
			    return(ADT_GT);
			else 
			    return(ADT_LT);
		    }
		}

	    }
	    else if (i2_t1 == i2_t2 && cur_cmp == 0)
		return(cur_cmp);	/* byte wise compare returns "=" */

	    endtc1 = tc1 + i2_t1;
	    endtc2 = tc2 + i2_t2;
	}

	if (adf_scb->adf_collation)
	    return(adugcmp((ADULTABLE *)adf_scb->adf_collation,
			 ADUL_BLANKPAD, tc1, endtc1, tc2, endtc2));

	/* Doublebyte is rather more tedious */
	blank = (u_char)MIN_CHAR;
	cur_cmp = ADT_EQ;
	
	while ( cur_cmp == ADT_EQ )
	{
	    if (tc1 < endtc1)
	    {
		lc1 = tc1;
		CMnext(tc1);
	    }
	    else
	    {
		lc1 = &blank;
	    }
	    
	    if (tc2 < endtc2)
	    {
		lc2 = tc2;
		CMnext(tc2);
	    }
	    else
	    {
		lc2 = &blank;
	    }
	    
	    /* if both pointing to blank or we happen to be comparing
	    ** a string to itself then break
	    */
	    if (lc1 == lc2)
		break;
	    
	    cur_cmp = CMcmpcase(lc1, lc2);
	}
	return(cur_cmp);
    }

    if ( atr_bdt == DB_NCHR_TYPE || atr_bdt == DB_NVCHR_TYPE )
    {
	if ( atr_bdt == DB_NCHR_TYPE )
	{
	    tn1 = (UCS2 *)d1;
	    tn2 = (UCS2 *)d2;
	    endtn1 = tn1 + atr_len / sizeof(UCS2);
	    endtn2 = tn2 + atr_len / sizeof(UCS2);
	}
	else
	{
	    tn1 = ((DB_NVCHR_STRING *)d1)->element_array;
	    tn2 = ((DB_NVCHR_STRING *)d2)->element_array;
	    I2ASSIGN_MACRO(((DB_NVCHR_STRING *)d1)->count, i2_t1);
	    I2ASSIGN_MACRO(((DB_NVCHR_STRING *)d2)->count, i2_t2);
	    endtn1 = tn1 + i2_t1;
	    endtn2 = tn2 + i2_t2;
	}
      
	*status = aduucmp(adf_scb, ADUL_BLANKPAD,
	    tn1, endtn1, tn2, endtn2, &cur_cmp, atr->collID);
	return (cur_cmp);
    }

    if ( atr_bdt == DB_CHR_TYPE )
    {
	if (adf_scb->adf_utf8_flag & AD_UTF8_ENABLED)
	    return(adt_utf8comp(adf_scb, atr, atr_bdt, atr_len, 
							d1, d2, status));

	if (adf_scb->adf_collation)
	    return(adugcmp((ADULTABLE *)adf_scb->adf_collation,
			     ADUL_SKIPBLANK, (u_char *)d1,
			     atr_len + (u_char *)d1, (u_char *)d2,
			     atr_len + (u_char *)d2));
	return(STscompare((char *)d1, atr_len, (char *)d2, atr_len));
    }

    if ( atr_bdt == DB_TXT_TYPE )
    {
	if (adf_scb->adf_utf8_flag & AD_UTF8_ENABLED)
	    return(adt_utf8comp(adf_scb, atr, atr_bdt, atr_len, 
							d1, d2, status));

	I2ASSIGN_MACRO(((DB_TEXT_STRING *)d1)->db_t_count, i2_t1);
	I2ASSIGN_MACRO(((DB_TEXT_STRING *)d2)->db_t_count, i2_t2);
	tc1 = (u_char *)d1 + DB_CNTSIZE;
	tc2 = (u_char *)d2 + DB_CNTSIZE;
	endtc1 = tc1 + i2_t1;
	endtc2 = tc2 + i2_t2;

	if (adf_scb->adf_collation)
	    return(adugcmp((ADULTABLE *)adf_scb->adf_collation,
			     0, tc1, endtc1, tc2, endtc2));

	cur_cmp = ADT_EQ;
	while (cur_cmp == ADT_EQ && tc1 < endtc1  &&  tc2 < endtc2)
	{
	    if ( (cur_cmp = CMcmpcase(tc1, tc2)) == ADT_EQ )
	    {
		CMnext(tc1);
		CMnext(tc2);
	    }
	}
	
	/* If equal up to shorter, short strings < long */
	return( (cur_cmp) ? cur_cmp : (endtc1 - tc1) - (endtc2 - tc2) );
    }

    if ( atr_bdt == DB_DEC_TYPE )
    {
	/*  See if the bit representation is identical. */
	if ( MEcmp(d1, d2, atr_len) )
	{
	    i4	    pr;
	    i4	    sc;

	    pr = DB_P_DECODE_MACRO(atr->precision);
	    sc = DB_S_DECODE_MACRO(atr->precision);
	    return(MHpkcmp((PTR)d1, pr, sc, (PTR)d2, pr, sc));
	}
	return(ADT_EQ);
    }

    /* Bit-equivalent dates we can handle here */
    if (( atr_bdt == DB_DTE_TYPE || 
	 atr_bdt == DB_ADTE_TYPE ||
	 atr_bdt == DB_TMWO_TYPE ||
	 atr_bdt == DB_TMW_TYPE ||
	 atr_bdt == DB_TME_TYPE ||
	 atr_bdt == DB_TSWO_TYPE ||
	 atr_bdt == DB_TSW_TYPE ||
	 atr_bdt == DB_TSTMP_TYPE ||
	 atr_bdt == DB_INYM_TYPE ||
	 atr_bdt == DB_INDS_TYPE ) &&
	MEcmp(d1, d2, (u_i2)atr_len) == 0 )
    {
	return(ADT_EQ);
    }

    /* Will have to do it the slow way */
    dv1.db_datatype = dv2.db_datatype = (DB_DT_ID)atr_bdt;
    dv1.db_prec = dv2.db_prec = atr->precision;
    dv1.db_length = dv2.db_length = atr_len;
    dv1.db_collID = dv2.db_collID = atr->collID;
    dv1.db_data = d1;
    dv2.db_data = d2;
    *status = adc_compare(adf_scb, &dv1, &dv2, &cur_cmp);

    return(cur_cmp);
}
Beispiel #21
0
/*{
** Name: psy_gproc - Get a database procedure definition from
**		     the system catalogs.
**
** Description:
**
** Inputs:
**	    psq_cb	    
**		psq_cursid
**		    db_cur_name	    dbproc name
**	    sess_cb
**		pss_user	    current user name
**		pss_dba		    dba name
**	    qsf_rb	    
**	    rdf_cb
**	    dbp_owner		    name of the owner whose dbproc will be
**				    looked up iff gproc_mask & PSS_DBP_BY_OWNER.
**	    gproc_mask		    mask used to specify the possible owners of
**				    the dbproc to look for
**		PSS_USRDBP	    look for dbproc owned by the current user
**		PSS_DBADBP	    look for dbproc owned by the DBA
**		PSS_INGDBP	    look for dbproc owned by $INGRES
**		PSS_DBP_BY_OWNER    look for dbproc owned by the specific user
**
**				    NOTE: if PSS_DBP_BY_OWNER is set,
**				          PSS_USRDBP, PSS_DBADBP, and PSS_INGDBP
**					  will be disregarded
**					  otherwise, we expect that PSS_USRDBP
**					  will be always set, while PSS_DBADBP
**					  and PSS_INGDBP may or may not be set
**
** Outputs:
**	    alt_user		    set to point the name of dbproc owner if
**				    different from cb->pss_user
**	    psq_cb
**		psq_error	    filled in if an error occurred
**
**	    ret_flags		    bits may be set to pass info to the caller
**		PSS_MISSING_DBPROC  dbproc not found
**
** Exceptions:
**	    none
**
** Returns
**	E_DB_OK, E_DB_ERROR
**
** Side Effects:
**	    Allocates memory.
**
** History:
**      27-apr-88 (stec)
**	    Created.
**	04-aug-88 (stec)
**	    Improve recovery of resources.
**	17-aug-88 (stec)
**	    Change bad STRUCT_ASSIGN statements.
**	28-sep-88 (stec)
**	    Do not lock object on cleanup.
**	28-sep-88 (stec)
**	    Must not unfix RDF entry.
**	16-mar-89 (andre)
**	    Added a new parameter - alt_user.
**	    psy_gproc will no longer reset pss_user or set pss_ruset.  Instead
**	    it may set the ptr passed to it to the name of the dbproc owner.
**	16-mar-89 (neil)
**	    Modified psy_gproc to access the procedure through the specified
**	    owner (psq_als_owner) if psq_alias_set is on.
**	27-apr-89 (andre)
**	    Further modify to search for dbprocs owned by $ingres if the search
**	    by user and DBA failed.  The search part of the function has been,
**	    essentially, rewritten.
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
**	01-jun-90 (andre)
**	    Changed interface to allow caller to explicitly specify the possible
**	    owners of the dbproc to look for.
**	01-oct-91 (andre)
**	    Added ret_flags to the interface - this field will be used to pass
**	    additional info to the caller.  in particular, it will allow us to
**	    signal certain classes of errors (e.g. dbproc not found) without
**	    setting return status to E_DB_ERROR, thus enabling the caller to
**	    distinguish such errors from unexpected errors
**	15-oct-1993 (rog)
**	    We need to use ulm_copy() instead of MEcopy() when copying query
**	    text that might be more than 64k.
**	12-jan-94 (andre)
**	    As a part of fix for bug 58048, we must remove the assumption that 
**	    either PSS_USRDBP or PSS_DBP_BY_OWNER bit will always be set in 
**	    gproc_mask.  Now we will be prepared to handle PSS_DBP_BY_OWNER or
**	    one or more of PSS_USRDBP, PSS_DBADBP, and PSS_INGDBP.
**	13-jan-94 (andre)
**	    if we fail to find a dbproc, we will set PSS_MISSING_DBPROC in 
**	    *ret_flags, but leave it up to the caller to issue an error 
**	    message - this way the caller can decide whether this warrants an 
**	    error message and if so can choose his favourite error message
*/
DB_STATUS
psy_gproc(
	PSQ_CB		*psq_cb,
	PSS_SESBLK	*sess_cb,
	QSF_RCB		*qsf_rb,
	RDF_CB		*rdf_cb,
	DB_OWN_NAME	**alt_user,
	DB_OWN_NAME	*dbp_owner,
	i4		gproc_mask,
	i4		*ret_flags)
{
    DB_STATUS		status, stat;
    i4		err_code;
    RDD_QRYMOD		*pinfo;
    PSQ_QDESC		*qdesc;
    bool		leave_loop = TRUE;
    DB_PROCEDURE *dbp;
    SXF_ACCESS  access;
    i4	msgid;
    i4	local_status;

    *ret_flags = 0;

    /* First call RDF to retrieve the definition
    ** of the procedure.
    */

    /* Initialize the RDF control block */
    pst_rdfcb_init(rdf_cb, sess_cb);

    (VOID) MEcopy((PTR) psq_cb->psq_cursid.db_cur_name,
	sizeof (DB_DBP_NAME),
	(PTR) &rdf_cb->rdf_rb.rdr_name.rdr_prcname);
    rdf_cb->rdf_rb.rdr_types_mask = RDR_PROCEDURE | RDR_BY_NAME;

    /* assume that the dbproc is owned by the current user */
    *alt_user = (DB_OWN_NAME *) NULL;
    
    do
    {
	if (gproc_mask & (PSS_USRDBP | PSS_DBP_BY_OWNER))
	{
	    if (gproc_mask & PSS_USRDBP)
	    {
		STRUCT_ASSIGN_MACRO(sess_cb->pss_user, 
		    rdf_cb->rdf_rb.rdr_owner);
	    }
	    else
	    {
		STRUCT_ASSIGN_MACRO((*dbp_owner), rdf_cb->rdf_rb.rdr_owner);
		if (MEcmp((PTR)&sess_cb->pss_user, (PTR) dbp_owner,
			  sizeof(DB_OWN_NAME)))
		{
		    *alt_user = dbp_owner;		/* Try someone else */
		}
	    }

	    /* Get the text */
	    status = rdf_call(RDF_GETINFO, (PTR) rdf_cb);

	    /*
	    ** We do not want to continue search if:
	    ** 1) dbproc was found					    OR
	    ** 2) we got an error other that PROC_NOT_FOUND		    OR
	    ** 3) caller requested a dbproc owned by a specific user
	    **    (gproc_mask & PSS_DBP_BY_OWNER)			    OR
	    */
	    if (   DB_SUCCESS_MACRO(status)				    
		|| rdf_cb->rdf_error.err_code != E_RD0201_PROC_NOT_FOUND   
		|| gproc_mask & PSS_DBP_BY_OWNER)
	    {
	        break;
	    }
	}

	/* 
	** if we were told to check whether a dbproc is owned by the DBA, do so
	** unless the DBA is the current user and we have already established 
	** that the current user does not own a dbproc with this name
	*/
	if (   gproc_mask & PSS_DBADBP 
	    && (   ~gproc_mask & PSS_USRDBP
		|| MEcmp((PTR) &sess_cb->pss_user, 
		       (PTR) &sess_cb->pss_dba.db_tab_own, sizeof(DB_OWN_NAME))
	       )
	   )
	{
	    STRUCT_ASSIGN_MACRO(sess_cb->pss_dba.db_tab_own,
				rdf_cb->rdf_rb.rdr_owner);

	    /*
	    ** If we succeed and the DBA is different from the current user, 
	    ** the procedure text will have to be parsed in the context of 
	    ** dbproc's owner, i.e. DBA.  Note that if we were also asked to 
	    ** check whether the dbproc is owned by the current user and still 
	    ** found ourselves here, DBA must be different from the current user
	    */
	    if (   gproc_mask & PSS_USRDBP
		|| MEcmp((PTR) &sess_cb->pss_user,
		       (PTR) &sess_cb->pss_dba.db_tab_own, sizeof(DB_OWN_NAME)))
	    {
	        *alt_user = &sess_cb->pss_dba.db_tab_own;
	    }

	    /* Get the text */
	    status = rdf_call(RDF_GETINFO, (PTR) rdf_cb);

	    /*
	    ** We do not want to continue search if:
	    ** 1) dbproc was found				OR
	    ** 2) we got an error other that PROC_NOT_FOUND
	    */
	    if (DB_SUCCESS_MACRO(status) ||
	        rdf_cb->rdf_error.err_code != E_RD0201_PROC_NOT_FOUND)
	    {
		break;
	    }
	}

	if (gproc_mask & PSS_INGDBP)
	{
	    MEmove(sizeof(*sess_cb->pss_cat_owner), (PTR)sess_cb->pss_cat_owner,
		   ' ', DB_OWN_MAXNAME, (PTR) &rdf_cb->rdf_rb.rdr_owner); 
	}
	else
	{
	    /*
	    ** if user has not requested that a dbproc owned by $INGRES be
	    ** looked up, might as well get out of the loop
	    */
	    break;
	}
	
	/* 
	** if we were told to check whether a dbproc is owned by $ingres, do so
	** unless the $ingres is the current user and we have already 
	** established that the current user does not own a dbproc with this 
	** name or $ingres is the DBA and we have already established that the
	** DBA does not own a dbproc with this name
	*/
	if (   (   ~gproc_mask & PSS_USRDBP
	        || MEcmp((PTR)&sess_cb->pss_user, 
		       (PTR) &rdf_cb->rdf_rb.rdr_owner, sizeof(DB_OWN_NAME))
	       )
	    && (   ~gproc_mask & PSS_DBADBP
		|| MEcmp((PTR) &sess_cb->pss_dba.db_tab_own,
	               (PTR) &rdf_cb->rdf_rb.rdr_owner, sizeof(DB_OWN_NAME))
	       )
	   )
	{
	    /*
	    ** If we succeed, the procedure text will have to be parsed in
	    ** the context of the original owner, i.e. $ingres.
	    */
	    *alt_user = &rdf_cb->rdf_rb.rdr_owner;
	    /*
	    ** If we succeed and $ingres is not the current user, the procedure
	    ** text will have to be parsed in the context of dbproc's owner, 
	    ** i.e. $ingres.  Note that if we were also asked to check whether 
	    ** the dbproc is owned by the current user and still found ourselves
	    ** here, the current user must NOT be $ingres
	    */
	    if (   gproc_mask & PSS_USRDBP
		|| MEcmp((PTR) &sess_cb->pss_user,
		       (PTR) &rdf_cb->rdf_rb.rdr_owner, sizeof(DB_OWN_NAME)))
	    {
	        *alt_user = &sess_cb->pss_dba.db_tab_own;
	    }


	    /* Get the text */
	    status = rdf_call(RDF_GETINFO, (PTR) rdf_cb);
	}
	
	/* leave_loop has already been set to TRUE */
    } while (!leave_loop);

    if (DB_FAILURE_MACRO(status))
    {
	if (rdf_cb->rdf_error.err_code == E_RD0201_PROC_NOT_FOUND)
	{
	    /*
	    ** dbproc was not found - set a bit in ret_flags and reset status to
	    ** E_DB_OK to enable callers to distinguish between this and other
	    ** errors
	    */
	    status = E_DB_OK;
	    *ret_flags |= PSS_MISSING_DBPROC;
	}
	else
	{
	    (VOID) psf_rdf_error(RDF_GETINFO, &rdf_cb->rdf_error,
				 &psq_cb->psq_error);
	}
	return(status);
    }

    /* we get here only if the dbproc was found */
    
    /*
    ** If the procedure has a security label, validate it
    */
    dbp=rdf_cb->rdf_info_blk->rdr_dbp;

    /* 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_RCB);
    qsf_rb->qsf_owner = (PTR)DB_PSF_ID;
    qsf_rb->qsf_sid = sess_cb->pss_sessid;
    qsf_rb->qsf_obj_id.qso_type = QSO_QTEXT_OBJ;
    qsf_rb->qsf_obj_id.qso_lname = 0;

    /* Having retrieved the text place it in QSF
    ** because the parser expects it to be there.
    */
    status = qsf_call(QSO_CREATE, qsf_rb);

    if (DB_FAILURE_MACRO(status))
    {
	i4	    qerr = qsf_rb->qsf_error.err_code;

	if (qerr == E_QS0001_NOMEM)
	{
	    (VOID) psf_error(qerr, qerr,
		PSF_CALLERR, &err_code, &psq_cb->psq_error, 0);
	}
	else
	{
	    (VOID) psf_error(E_PS0A05_BADMEMREQ, qerr,
		PSF_INTERR, &err_code, &psq_cb->psq_error, 0);
	}

	goto cleanup2;
    }

    /* Object is locked exclusively now. */

    pinfo = rdf_cb->rdf_rb.rdr_procedure;

    /* Allocate enough memory for the query descriptor
    ** plus the length of text.
    */
    qsf_rb->qsf_sz_piece = sizeof(PSQ_QDESC) +
	pinfo->rdf_l_querytext + 3; /* one space, one null,
				    ** one for safety.
				    */

    status = qsf_call(QSO_PALLOC, qsf_rb);

    if (DB_FAILURE_MACRO(status))
    {
	i4	    qerr = qsf_rb->qsf_error.err_code;

	if (qerr == E_QS0001_NOMEM)
	{
	    (VOID) psf_error(qerr, qerr,
		PSF_CALLERR, &err_code, &psq_cb->psq_error, 0);
	}
	else
	{
	    (VOID) psf_error(E_PS0A05_BADMEMREQ, qerr,
		PSF_INTERR, &err_code, &psq_cb->psq_error, 0);
	}

	goto cleanup1;
    }

    qdesc = (PSQ_QDESC *) qsf_rb->qsf_piece;

    /* Initialize query descriptor. */
    qdesc->psq_qrysize = pinfo->rdf_l_querytext + 1; /* 1 trailing space */
    qdesc->psq_datasize = 0;
    qdesc->psq_dnum = 0;
    qdesc->psq_qrytext = (char *)(qdesc + 1); /* Ptr arithmetic, should point
				    ** right after the PSQ_QDESC.
				    */
    qdesc->psq_qrydata = (DB_DATA_VALUE **) NULL;

    /* QSF memory has been allocated now, copy
    ** the text from RDF.
    */
    ulm_copy((PTR) pinfo->rdf_querytext,
	     (i4) pinfo->rdf_l_querytext,
	     (PTR) qdesc->psq_qrytext);

    /* Add a space after the text and null terminate. */
    {
	char	*p;

	p = qdesc->psq_qrytext;		/* beginning of text */
	p += pinfo->rdf_l_querytext;	/* 1st char past end */
	*p++ = ' ';
	*p = '\0';			/* 2nd char past end */
    }

    /* Set root for the QSF object */
    qsf_rb->qsf_root = qsf_rb->qsf_piece;

    status = qsf_call(QSO_SETROOT, qsf_rb);

    if (DB_FAILURE_MACRO(status))
    {
	(VOID) psf_error(E_PS0A05_BADMEMREQ, qsf_rb->qsf_error.err_code,
		PSF_INTERR, &err_code, &psq_cb->psq_error, 0);
	goto cleanup1;
    }

    status = qsf_call(QSO_UNLOCK, qsf_rb);

    if (DB_FAILURE_MACRO(status))
    {
	(VOID) psf_error(E_PS0B05_CANT_UNLOCK, qsf_rb->qsf_error.err_code,
		PSF_INTERR, &err_code, &psq_cb->psq_error, 0);
	goto cleanup1;
    }

    psq_cb->psq_qid = qsf_rb->qsf_obj_id.qso_handle;

    return (status);

cleanup1:
    /* Destroy the object, it's already locked. */
    stat = qsf_call(QSO_DESTROY, qsf_rb);

    if (DB_FAILURE_MACRO(stat))
    {
	(VOID) psf_error(E_PS0A09_CANTDESTROY, qsf_rb->qsf_error.err_code,
		PSF_INTERR, &err_code, &psq_cb->psq_error, 0);
	if (stat > status)
	    status = stat;
    }

cleanup2:
    /* RDF object can be released now. */

    stat = rdf_call(RDF_UNFIX, (PTR) rdf_cb);

    if (DB_FAILURE_MACRO(stat))
    {
	(VOID) psf_rdf_error(RDF_UNFIX,
	    &rdf_cb->rdf_error, &psq_cb->psq_error);
	if (stat > status)
	    status = stat;
    }

    return (status);
}
Beispiel #22
0
/*{
** Name: opv_smap	- map query tree associated with subquery
**
** Description:
**      This routine will map the query tree associated with the subquery.  A
**      subquery is typically associated with a PST_AGHEAD, or PST_ROOT node. 
**      A flag is check to see if the variable map was invalidated by any 
**      previous substitution.  For now this will be a consistency check 
**      and the tree will be mapped anyways.  FIXME later change this to 
**      avoid mapping the tree if there has been no substitutions.
**
** Inputs:
**      subquery                        ptr to subquery which will be mapped
**
** Outputs:
**      subquery->ops_root              this PST_RT_NODE will have the bitmaps
**                                      updated
**	Returns:
**	    VOID
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	3-jul-86 (seputis)
**          initial creation
**	22-apr-90 (seputis)
**          fix rohm-haas bug (no bug number), aggregate on a select distinct view
**	24-jun-91 (seputis)
**	    turn off consistency check to avoid traversal of parse tree
**	5-dec-02 (inkdo01)
**	    Changes for range table expansion.
**	31-Aug-2006 (kschendel)
**	    Watch for HFAGG as well as RFAGG.
*/
VOID
opv_smap(
	OPS_SUBQUERY       *subquery)
{
    OPV_GBMVARS         map;		/* range var map of query tree fragment
                                        */

    if (subquery->ops_vmflag)		/* TRUE if varmap is up-to-date */
    {
#ifdef E_OP0388_VARBITMAP
	/* check if this var map is valid as claimed */
#ifdef xDEBUG
	MEfill(sizeof(map), 0, (char *)&map);
	opv_mapvar(subquery->ops_root->pst_left, &map);
	if (MEcmp((char *)&map, (char *)&subquery->ops_root->pst_sym.pst_value.
		pst_s_root.pst_lvrm, sizeof(map)) != 0)
	    opx_error( E_OP0388_VARBITMAP); /* bit map
					** inconsistent with left side */
	MEfill(sizeof(map), 0, (char *)&map);
	opv_mapvar(subquery->ops_root->pst_right, &map);
	if (MEcmp((char *)&map, (char *)&subquery->ops_root->pst_sym.pst_value.
		pst_s_root.pst_rvrm, sizeof(map)) != 0)
	    opx_error( E_OP0388_VARBITMAP); /* bit map
					** inconsistent with right side */
#endif
	return;
#endif
    }

    if ((subquery->ops_sqtype == OPS_FAGG)
	||
	(subquery->ops_sqtype == OPS_HFAGG)
	||
	(subquery->ops_sqtype == OPS_RFAGG)
	)
    {
	/* map the bylist for the function aggregate */
	MEfill(sizeof(map), 0, (char *)&map);
	opv_mapvar(subquery->ops_agg.opa_byhead->pst_left, &map); /* map
					** the bylist portion of the function
					** aggregate */
	MEcopy((char *)&map, sizeof(map), (char *)&subquery->ops_agg.opa_blmap);
	if (subquery->ops_root->pst_left == subquery->ops_agg.opa_byhead)
	{
	    OPV_GBMVARS         aopmap;	/* map of AOP operator
					    */
	    MEfill(sizeof(aopmap), 0, (char *)&aopmap);
	    opv_mapvar(subquery->ops_agg.opa_aop, &aopmap); /* map the AOP node
					    ** of the function aggregate */
	    MEcopy((char *)&map, sizeof(map),
		(char *)&subquery->ops_root->pst_sym.pst_value.pst_s_root.pst_lvrm);
	    BTor(OPV_MAXVAR, (char *)&aopmap, 
		(char *)&subquery->ops_root->pst_sym.pst_value.pst_s_root.pst_lvrm);
	}
	else
	{   /* non-printing resdoms exist above the byhead so 
	    ** the entire tree needs to be scanned */
	    MEfill(sizeof(PST_J_MASK), 0, 
		(char *)&subquery->ops_root->pst_sym.pst_value.pst_s_root.pst_lvrm);
	    opv_mapvar(subquery->ops_root->pst_left, 
		&subquery->ops_root->pst_sym.pst_value.pst_s_root.pst_lvrm ); 
					/* map the AOP node
					** of the function aggregate */
	}
    }
    else
    {
	/* map the left side of the tree */
	MEfill(sizeof(map), 0, (char *)&map);
	opv_mapvar(subquery->ops_root->pst_left, &map);
	MEcopy((char *)&map, sizeof(map),
	    (char *)&subquery->ops_root->pst_sym.pst_value.pst_s_root.pst_lvrm);
    }

    /* map the right side of the tree */
    MEfill(sizeof(map), 0, (char *)&map);
    opv_mapvar(subquery->ops_root->pst_right, &map);
    MEcopy((char *)&map, sizeof(map),
	(char *)&subquery->ops_root->pst_sym.pst_value.pst_s_root.pst_rvrm);

    subquery->ops_vmflag = TRUE;	/* bit maps are now valid */
}
Beispiel #23
0
/*{
** Name: DIrename - Renames a file. 
**
** Description:
**      The DIrename will change the name of a file. 
**	The file MUST be closed.  The file can be renamed
**      but the path cannot be changed.  A fully qualified
**      filename must be provided for old and new names.
**      This includes the type qualifier extension.
**   
** Inputs:
**	di_io_unused	     UNUSED DI_IO pointer (always set to 0 by caller)
**      path                 Pointer to the path name.
**      pathlength           Length of path name.
**      oldfilename          Pointer to old file name.
**      oldlength            Length of old file name.
**      newfilename          Pointer to new file name.
**      newlength            Length of new file name.
** Outputs:
**      err_code             Pointer to a variable used
**                           to return operating system 
**                           errors.
**    Returns:
**        OK
**        DI_BADRNAME        Any i/o error during rename.
**        DI_BADPARAM        Parameter(s) in error.
**        DI_DIRNOTFOUND     Path not found.
**    Exceptions:
**        none
**
** Side Effects:
**        none
**
** History:
**    26-mar-87 (mmm)    
**          Created new for 6.0.
**    06-feb-89 (mikem)
**	    Clear the CL_ERR_DESC.
**	15-apr-1992 (bryanp)
**	    Remove DI_IO argument and no longer support renaming open files.
**    30-nov-1992 (rmuth)
**	    - Prototype.
**	    - DIlru error checking
**    17-sep-1994 (nanpr01)
**          - Needs to check for interrupted system calls specially for
**            SIGUSR2. Curren implementation of 1 more retry is optimistic.
**            In lot of UNIX systems, link, unlink, rename cannot be 
**            interrupted(HP-UX).But Solaris returns EINTR. Bug # 57938. 
**    10-oct-1994 (nanpr01)
**          - Wrong number of parameter in DIlru_flush. Bug # 64169
**	20-Feb-1998 (jenjo02)
**	    DIlru_flush() prototype changed, it now computes the number of
**	    FDs to close instead of being passed an arbitrary number.
**	    Cleaned up handling of errno, which will be invalid after calling
**	    DIlru_flush().
**  15-Apr-2004 (fanch01)
**      Force closing of LRU file descriptors when a rename error is
**      is encountered.  Only occurs on a rename failure and the only
**      file that is closed is the file associated with the error.
**      Relieves problems on filesystems which don't accomodate renaming
**      open files.  "Interesting" semaphore usage is consistent with other
**      DI usage.
**	21-Apr-2004 (schka24)
**	    retry declaration got misplaced somehow, fix so it compiles.
**	26-Jul-2005 (schka24)
**	    Don't flush fd's on any random rename failure.  Do a better job
**	    of re-verifying the fd and di-io after locking the fd when we're
**	    searching for a file-open conflict.
**	30-Sep-2005 (jenjo02)
**	    htb_fd_list_mutex, fd_mutex are now CS_SYNCH objects.
**	15-Nov-2010 (kschendel) SIR 124685
**	    Delete unused variables.
*/
STATUS
DIrename(
    DI_IO	   *di_io_unused,
    char           *path,
    u_i4          pathlength,
    char           *oldfilename,
    u_i4          oldlength,
    char           *newfilename,
    u_i4          newlength,
    CL_ERR_DESC     *err_code)
{
    char    oldfile[DI_FULL_PATH_MAX];
    char    newfile[DI_FULL_PATH_MAX];
    STATUS  ret_val;
    CL_ERR_DESC	    local_err;

    /* unix variables */
    int	    os_ret;

	/* retry variables */
	i4 retry = 0, failflag = 0;

    /* default returns */
    ret_val = OK;

    if ((pathlength > DI_PATH_MAX)	|| 
	(pathlength == 0)		||
	(oldlength > DI_FILENAME_MAX)	|| 
	(oldlength == 0)		|| 
	(newlength > DI_FILENAME_MAX)	||
	(newlength == 0))
	return (DI_BADPARAM);		

    /* get null terminated path and filename for old file */

    MEcopy((PTR) path, pathlength, (PTR) oldfile);
    oldfile[pathlength] = '/';
    MEcopy((PTR) oldfilename, oldlength, (PTR) &oldfile[pathlength + 1]);
    oldfile[pathlength + oldlength + 1] = '\0';

    /* get null terminated path and filename for new file */

    MEcopy((PTR) path, pathlength, (PTR) newfile);
    newfile[pathlength] = '/';
    MEcopy((PTR) newfilename, newlength, (PTR) &newfile[pathlength + 1]);
    newfile[pathlength + newlength + 1] = '\0';

	do
	{
		if (retry > 0 && failflag++ == 0)
			TRdisplay("%@ DIrename: retry on %t/%t\n",
					  pathlength, path, oldlength, oldfilename);
		retry = 0;
		CL_CLEAR_ERR( err_code );
#ifdef	xCL_035_RENAME_EXISTS
		/* Now rename the file. */    
		while  ((os_ret = rename(oldfile, newfile)) == -1) 
		{
			SETCLERR(err_code, 0, ER_rename);
			if (err_code->errnum != EINTR)
				break;
		}
#else /* xCL_035_RENAME_EXISTS */
		/* Now rename the file. */    
		while ((os_ret = link(oldfile, newfile)) == -1) 
		{
			SETCLERR(err_code, 0, ER_rename);
			if (err_code->errnum != EINTR)
				break;
		}
		if (os_ret != -1)
		{
			while ((os_ret = unlink(oldfile)) == -1) 
			{
				if (err_code->errnum != EINTR)
					break;
			}
		}
#endif /* xCL_035_RENAME_EXISTS */

		/* if the rename failed, see if we're holding the file open */
		if (os_ret == -1 && htb_initialized)
		{
			QUEUE *p, *q, *next;
			CS_synch_lock(&htb->htb_fd_list_mutex);
			q = &htb->htb_fd_list;
			for (p = q->q_prev; p != q; p = next)
			{
				DI_FILE_DESC *di_file = (DI_FILE_DESC *) p;
				DI_IO *di_io = (DI_IO *) di_file->fd_uniq.uniq_di_file;
				next = p->q_prev;
				if (di_io != NULL && di_file->fd_state == FD_IN_USE
				  && di_io->io_type == DI_IO_ASCII_ID
				  && pathlength == di_io->io_l_pathname
				  && oldlength == di_io->io_l_filename)
				{
					CS_synch_unlock(&htb->htb_fd_list_mutex);
					CS_synch_lock(&di_file->fd_mutex);
					/* Make sure it's still the right
					** DI_IO and compare the filename */
					if ((DI_IO *) di_file->fd_uniq.uniq_di_file == di_io &&
					      di_file->fd_state == FD_IN_USE &&
					      di_file->fd_unix_fd != -1 &&
					      !(di_io->io_open_flags & DI_O_NOT_LRU_MASK) &&
						di_io->io_type == DI_IO_ASCII_ID &&
						pathlength == di_io->io_l_pathname &&
						MEcmp((PTR) di_io->io_pathname, path, pathlength) == 0
						&& oldlength == di_io->io_l_filename &&
						MEcmp((PTR) di_io->io_filename, oldfilename,
							  oldlength) == 0)
					{
						/* have a match, print out stats */
						/* try to close it */
						CS_synch_unlock(&di_file->fd_mutex);
						DIlru_close(di_io, &local_err);
						retry++;
					}
					else
						CS_synch_unlock(&di_file->fd_mutex);
					CS_synch_lock(&htb->htb_fd_list_mutex);
				}
			}
			CS_synch_unlock(&htb->htb_fd_list_mutex);
		}
	} while (retry);

    if (os_ret == -1)
    {
	if ((err_code->errnum == ENOTDIR) || (err_code->errnum == EACCES))
	{
	    ret_val = DI_DIRNOTFOUND;
	}
	else
	{
	    ret_val = DI_BADRNAME;
	}
    }
    else
	CL_CLEAR_ERR( err_code );

    return(ret_val);
}
Beispiel #24
0
DB_STATUS
adt_compute_change(
ADF_CB		    *adf_scb,
i4		    adt_natts,		/* # of attrs in each tuple. */
DB_ATTS	    	    *adt_atts,		/* Ptr to vector of DB_ATTS,
					** 1 for each attr in tuple, and
					** in attr order.
					*/
char		    *adt_tup1,		/* Ptr to 1st tuple. */
char		    *adt_tup2,		/* Ptr to 2nd tuple. */
i4		    adt_change_set[(DB_MAX_COLS + 31) / 32],
i4		    adt_value_set[(DB_MAX_COLS + 31) / 32],
i4		    *adt_key_change,	/* Place to put cmp result. */
i4		    *adt_nkey_change)	/* Place to put cmp result. */

{
    DB_ATTS		*atr;		/* Ptr to current DB_ATTS */
					/********************************/
    char		*d1;		/* Ptrs to data in data records */
    char		*d2;		/* for current attributes       */
					/********************************/
    i2			atr_len;	/* Length of cur attribute */
    i4			atr_bdt;
    i4			i;
    i4			d1_isnull, d2_isnull;
    DB_STATUS		status = E_DB_OK;

    for (i = 1; i <= adt_natts && status == E_DB_OK; i++)
    {
	atr = ++adt_atts;

	if (atr->ver_dropped)
	   continue;

	atr_len = atr->length;

	d1 = (char *)adt_tup1 + atr->offset;
	d2 = (char *)adt_tup2 + atr->offset;

	if ( (atr_bdt = atr->type) < 0 )
	{
	    /* Nullable. Check to see if the nullability changed. */

	    d1_isnull = (*((char *)d1 + atr_len - 1) & ADF_NVL_BIT);
	    d2_isnull = (*((char *)d2 + atr_len - 1) & ADF_NVL_BIT);

	    if ( !d1_isnull && !d2_isnull )
	    {
		/* Neither is the Null value, look at data */
		atr_len--;
		atr_bdt = -atr_bdt;
	    }
	    else if (d1_isnull && d2_isnull)
	    {
		/* both are Null values, check if representation changed */
		if ( MEcmp((PTR)d1, (PTR)d2, atr_len-1) )
		{
		    adt_change_set[i >> 5] |= (1 << (i & 0x1f));
		    if ( atr->key )
			*adt_key_change |= ADT_REPRESENTATION;
		    else
			*adt_nkey_change |= ADT_REPRESENTATION;
		}
		continue;
	    }
	    else
	    {
		/* One is Null, the other not; values differ */
		if (atr->key)
Beispiel #25
0
int
main(int argc, char *argv[])
{
#define 	MAXBUF	4095

	char 	buf[ MAXBUF+1 ];
	int	iarg, ibuf, ichr;
	bool	debug = FALSE;
        CL_ERR_DESC     err_code;
        char		*p1 = NULL;
        char		pid[MAXBUF];
        char    	*database = ERx("");
        char    	*user = ERx("");
        char    	*xmlfile = ERx("");
        char    	sql_fname[LO_NM_LEN + 1];
        char    	*work_dir = NULL;
        char    	directory[MAX_LOC + 1]; 
        char    	*tmp_dir = NULL;
        char		tmp_buf[MAX_LOC + 1];
        char		subdir_buf[MAX_LOC + 1];
        char		sql_loc_buf[MAX_LOC + 1];
	char		*progname; 
        LOCATION    tmp_dir_loc;
        LOCATION    tmp_subdir_loc;
        LOCATION    tmp_buff_loc;
        LOCATION    curr_loc;
        LOCATION    sql_file_loc;
	char        *password = ERx("");
	char        *groupid = ERx("");
	ARGRET  rarg;
        i4      pos;
	LOCATION    xmlfile_loc;
	FILE	    *xmlfile_read;
	STATUS	    stat = FAIL;
	char	    dbuf[256];
	char	    encode[32];
        u_i4        tmppid;
        TM_STAMP    tm_stamp;


	/* Tell EX this is an ingres tool. */
   	(void) EXsetclient(EX_INGRES_TOOL);

	/* Call IIUGinit to initialize character set attribute table */
	if ( IIUGinit() != OK)
	    PCexit(FAIL);

	progname = ERget(F_XM0006_IMPXML);
	FEcopyright(progname, ERx("2001")); 

	/*
	** Get arguments from command line
	*/

	/* required parameters */

	if (FEutaopen(argc, argv, ERx("xmlimport")) != OK)
          PCexit(FAIL);

	/* database name is required */
	if (FEutaget(ERx("database"), 0, FARG_PROMPT, &rarg, &pos) != OK)
          PCexit(FAIL);
	database = rarg.dat.name;

        if (FEutaget(ERx("xmlfile"), 0, FARG_PROMPT, &rarg, &pos) != OK)
            PCexit(FAIL);
        xmlfile = rarg.dat.name;

        if (FEutaget(ERx("user"), 0, FARG_FAIL, &rarg, &pos) == OK)
            user = rarg.dat.name;

        if (FEutaget(ERx("password"), 0, FARG_FAIL, &rarg, &pos) == OK)
        {
            char *IIUIpassword();

            if ((password = IIUIpassword(ERx("-P"))) == NULL)
            {
                FEutaerr(BADARG, 1, ERx(""));
                PCexit(FAIL);
            }
        }

        if (FEutaget(ERx("groupid"), 0, FARG_FAIL, &rarg, &pos) == OK)
          groupid = rarg.dat.name;

        if (FEutaget(ERx("debug"), 0, FARG_FAIL, &rarg, &pos) == OK)
	  debug = TRUE;

        ibuf = STlength(buf); 

        /* b121678: pid is no longer based on process id, but it's
        ** a random number instead.
        */
        PCpid(&tmppid);
        TMget_stamp(&tm_stamp);
        MHsrand2(tmppid * tm_stamp.tms_usec);
        STprintf(pid, "%x", MHrand2());

#ifdef xDEBUG
        SIprintf(" the pid is: %s \n", pid);
#endif

        /* create the sql file */
	/* Avoid a name like "foo.xml.sql" on VMS, use pid.sql instead */
        STcopy(pid, sql_fname); 
        STcat(sql_fname, ".sql");

        /* 
        ** create in the temp location a directory 
        ** with the name pid. set this directory 
        ** as the working directory for impxml
        */

      NMloc (TEMP, PATH, NULL, &tmp_dir_loc);	
      /* make a location for TMP loc */
      /* print location name */
      LOcopy (&tmp_dir_loc, tmp_buf, &tmp_buff_loc);
      LOtos (&tmp_buff_loc, &tmp_dir);

#ifdef xDEBUG
      SIprintf ("temploc: %s \n", tmp_dir);
#endif

      /* make a subdir location with filename, pid */
      STcopy (pid, subdir_buf);				
      /* Initialize result loc so that everyone is happy */
      LOcopy (&tmp_dir_loc, sql_loc_buf, &sql_file_loc); 
      /* Generate location for temp subdirectory */
      if (LOfaddpath (&tmp_dir_loc, subdir_buf, &sql_file_loc) != OK)
      {
	 IIUGerr(E_XM0007_Locname_Failed, UG_ERR_FATAL, 2, tmp_dir, subdir_buf);
	 /* NOTREACHED */
      }

      /* print the location name */
      LOcopy (&sql_file_loc, tmp_buf, &tmp_buff_loc);    
      LOtos (&tmp_buff_loc, &work_dir);

#ifdef xDEBUG
	SIprintf ("work dir loc: %s \n", work_dir);
#endif

      /* create the subdir */
      if (LOcreate (&sql_file_loc) != OK) {
	 IIUGerr(E_XM0008_Create_Temp_Dir, UG_ERR_ERROR, 1, work_dir);
	 PCexit(FAIL);
      }

      STcopy(work_dir, directory);

#ifdef xDEBUG
      SIprintf ("sql file name: %s \n", sql_fname);
      SIprintf ("xml file name: %s \n", xmlfile);
#endif

      /* Execute the command impxml */	
      STprintf (buf, ERx( "impxml -d=\"%s\" -o=\"%s\" " ),  directory, sql_fname);

      /* encoding? */
      if ( (LOfroms(PATH & FILENAME, xmlfile, &xmlfile_loc) != OK)
          ||
	  (SIopen(&xmlfile_loc, "r", &xmlfile_read) != OK)
	  ||
	  (xmlfile_read == NULL)
	 )
      {
	  IIUGerr(E_XM0009_Cannot_Open_File, UG_ERR_ERROR, 1, xmlfile);
          PCexit(FAIL);
      }

      /* scan XML declaration for encoding, if any */
      if (stat = SIgetrec(dbuf, sizeof(dbuf) - 1, xmlfile_read) == OK)
      {
	  char 	*d = dbuf;
	  i4	i = 0;

	  for (d = dbuf; d != (dbuf + sizeof(dbuf)); d++)
	  {
	      if (MEcmp(d, ERx("encoding="), sizeof(ERx("encoding=")) - 1) == 0)
	      {
		  d += sizeof(ERx("encoding="));
		  while (MEcmp (d, "\'", sizeof(char)) && MEcmp(d, "\"", sizeof(char)))
		      MEcopy(d++, sizeof(char), &encode[i++]);
		  encode[i++] = MIN_CHAR;
		  encode[i] = EOS;
		  STcat(buf, ERx("-x="));
		  STcat(buf, encode);
		  break;
	      }
	  }
      }
      else if (stat != ENDFILE)
      {
          /* unable to read file, report error */
	  IIUGerr(E_XM000A_Cannot_Read_File, UG_ERR_ERROR, 1, xmlfile);
	  PCexit(FAIL);
      }

      stat = SIclose(xmlfile_read);

      STcat(buf, xmlfile);

#ifdef xDEBUG
      SIprintf ( " query send: %s \n", buf);
#endif

      /* 	Execute the command.  
      */

      if( PCcmdline((LOCATION *) NULL, buf, PC_WAIT, 
  		(LOCATION *)NULL, &err_code) != OK )
      {
	if (!debug)
	    LOdelete(&sql_file_loc);
	PCexit(FAIL);
      }

      /*
      **	we should run the sql script 
      **	sql dbname < new_filename
      */
      
      /* save the current location */
      LOcopy(&sql_file_loc, tmp_buf, &curr_loc);

      /* make a full location path to the location first */
      LOfroms(FILENAME, sql_fname, &tmp_buff_loc);
      LOstfile(&tmp_buff_loc, &curr_loc);
      LOcopy (&curr_loc, tmp_buf, &tmp_buff_loc);
      LOtos (&tmp_buff_loc, &tmp_dir);

#ifdef xDEBUG
      SIprintf ("sql file is: %s \n", tmp_dir);
#endif

      /* No space between < and input file for VMS */
      STprintf(buf, ERx( "sql -s %s %s %s %s <%s" ),
			database, user, password, groupid, tmp_dir);
#ifdef xDEBUG
      SIprintf (" query send: %s \n", buf);
#endif

      /*
      **	Execute the command.
      */

      if( PCcmdline((LOCATION *) NULL, buf, PC_WAIT, 
              (LOCATION *)NULL, &err_code) != OK )
      {
	if (!debug)
	    LOdelete(&sql_file_loc);
        PCexit(FAIL); 
      }

      /*
      **    Delete the location
      */
      if (!debug)
	LOdelete(&sql_file_loc);

      PCexit(OK);
}
Beispiel #26
0
/*{
** Name: dmv_rebtree_del - Redo the Delete of a btree key 
**
** Description:
**      This function adds a key to a btree index for the recovery of a
**	delete record operation.
**
** Inputs:
**      dmve				Pointer to dmve control block.
**      tabio				Pointer to table io control block
**      page				Pointer to the page to which to insert
**
** Outputs:
**	error				Pointer to Error return area
**	Returns:
**	    E_DB_OK
**	    E_DB_ERROR
**
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	14-dec-1992 (rogerk)
**	    Written for 6.5 recovery.
**	18-jan-1992 (rogerk)
**	    Add check in redo routine for case when null page pointer is
**	    passed because redo was found to be not needed.
**      26-apr-1993 (bryanp)
**          6.5 Cluster support:
**              Replace all uses of DM_LOG_ADDR with LG_LA or LG_LSN.
**	06-may-1996 (thaju02 & nanpr01)
**	    New page format support: change page header references to use
**	    macros.
**      22-nov-96 (stial01,dilma04)
**          Row Locking Project:
**          When calling dm1cxdel(), pass reclaim_space param
**      04-feb-97 (stial01)
**          Tuple headers are on LEAF and overflow (CHAIN) pages
**          Tuple headers are not on INDEX pages.
**      27-feb-97 (stial01)
**          dmv_rebtree_del() Space is reclaimed when redoing DELETE,
**          unless last entry on leaf page with overflow chain.
**          Init flag param for dm1cxdel()
**      07-apr-97 (stial01)
**          dmv_rebtree_del() NonUnique primary btree (V2) dups span leaf pages,
**          not overflow chain. Remove code skipping reclaim of overflow key
**      21-may-1997 (stial01)
**          Added flags arg to dm0p_unmutex call(s).
**	13-Jun-2006 (jenjo02)
**	    Clustered TIDs need not match, as long as the keys match.
*/
static DB_STATUS
dmv_rebtree_del(
DMVE_CB             *dmve,
DMP_TABLE_IO	    *tabio,
DMP_PINFO	    *pinfo,
DM_TID		    *bid)
{
    DM0L_BTDEL		*log_rec = (DM0L_BTDEL *)dmve->dmve_log_rec;
    DB_STATUS		status = E_DB_OK;
    DM_LINE_IDX		childkey;
    DM_LINE_IDX		childtid;
    DM_TID		deltid;
    i4			delpartno;
    i4			page_type = log_rec->btd_pg_type;
    char		*key;
    char		*key_ptr;
    i4		key_len;
    bool		index_update;
    bool		Clustered;
    i4		dmcx_flag;
    i4		ix_compressed;
    DMP_DCB             *dcb = dmve->dmve_dcb_ptr;
    i4			*err_code = &dmve->dmve_error.err_code;
    LG_LRI		lri;
    DMPP_PAGE		*page = pinfo->page;

    CLRDBERR(&dmve->dmve_error);

    /*
    ** If there is nothing to recover, just return.
    */
    if (page == NULL)
	return (E_DB_OK);

    key = &log_rec->btd_vbuf[0];

    index_update = ((DM1B_VPT_GET_PAGE_STAT_MACRO(page_type, page) & 
	DMPP_INDEX) != 0);
    Clustered = ((DM1B_VPT_GET_PAGE_STAT_MACRO(page_type, page) & 
	DMPP_CLUSTERED) != 0);
    ix_compressed = DM1CX_UNCOMPRESSED;
    if (log_rec->btd_cmp_type != TCB_C_NONE)
	ix_compressed = DM1CX_COMPRESSED;

    /*
    ** Deletes to non-leaf index pages actually effect more than one entry
    ** on the page.  The logged bid describes the entry from which the
    ** TID pointer is deleted.  The key entry is deleted from the previous
    ** position (if there is one).
    */
    if (index_update)
    {
	childtid = log_rec->btd_bid_child;
	childkey = log_rec->btd_bid_child;
    }
    else
    {
	childtid = bid->tid_tid.tid_line;
	childkey = bid->tid_tid.tid_line;
    }

    if (index_update && (childkey != 0))
	childkey--;

    /*
    ** Consistency Checks:
    **
    ** Verify that there is an entry at the indicated BID and that it
    ** matches the logged key, tid, partition entry.
    ** 
    */

    dm1cxrecptr(page_type, log_rec->btd_page_size, page, 
	childkey, &key_ptr);
    dm1cxtget(page_type, log_rec->btd_page_size, page, 
	childtid, &deltid, &delpartno);

    /*
    ** We can only validate the key size on compressed tables; otherwise
    ** we must assume that the logged value was the correct table key length.
    */
    key_len = log_rec->btd_key_size;
    if (ix_compressed != DM1CX_UNCOMPRESSED)
    {
	dm1cx_klen(page_type, log_rec->btd_page_size, page,
		childkey, &key_len);
    }

    /*
    ** Compare the key,tid pair we are about to delete with the one we logged
    ** to make sure they are identical.  If the keys don't match but the tids
    ** do, then we make an assumption here that the mismatch is most likely due
    ** to this check being wrong (we have garbage at the end of the tuple 
    ** buffer or we allowed some sort of non-logged update to the row) and 
    ** we continue with the operation after logging the unexpected condition.
    */
    if ((log_rec->btd_key_size != key_len) ||
	(MEcmp((PTR)key, (PTR)key_ptr, key_len) != 0) ||
	(!Clustered &&
	  (log_rec->btd_tid.tid_i4 != deltid.tid_i4 ||
	   log_rec->btd_partno != delpartno)) )
    {
	uleFormat(NULL, E_DM966A_DMVE_KEY_MISMATCH, (CL_ERR_DESC *)NULL, ULE_LOG, NULL,
	    (char *)NULL, (i4)0, (i4 *)NULL, err_code, 8, 
	    sizeof(DB_DB_NAME), tabio->tbio_dbname->db_db_name,
	    sizeof(DB_TAB_NAME), tabio->tbio_relid->db_tab_name,
	    sizeof(DB_OWN_NAME), tabio->tbio_relowner->db_own_name,
	    0, bid->tid_tid.tid_page, 0, bid->tid_tid.tid_line,
	    5, (index_update ? "INDEX" : "LEAF "),
	    0, log_rec->btd_bid.tid_tid.tid_page,
	    0, log_rec->btd_bid.tid_tid.tid_line);
	uleFormat(NULL, E_DM966B_DMVE_KEY_MISMATCH, (CL_ERR_DESC *)NULL, ULE_LOG, NULL,
	    (char *)NULL, (i4)0, (i4 *)NULL, err_code, 7, 
	    0, key_len, 0, log_rec->btd_key_size,
	    0, deltid.tid_tid.tid_page, 0, deltid.tid_tid.tid_line,
	    0, log_rec->btd_tid.tid_tid.tid_page,
	    0, log_rec->btd_tid.tid_tid.tid_line,
	    0, dmve->dmve_action);
	dmd_log(1, (PTR) log_rec, 4096);
	uleFormat(NULL, E_DM9653_REDO_BTREE_DEL, (CL_ERR_DESC *)NULL, ULE_LOG, NULL,
	    (char *)NULL, (i4)0, (i4 *)NULL, err_code, 0); 
    }

    /*
    ** Mutex the page while updating it.
    */
    dmveMutex(dmve, pinfo);

    /*
    ** Redo the delete operation.
    */
    for (;;)
    {
	/*
	** If redoing a delete to a non leaf page, save the tid value from the
	** entry we are about to delete from (the key's position) and write it
	** over the entry at the next position (effectively deleting the TID).
	*/
	if (index_update && (childkey != childtid))
	{
	    dm1cxtget(page_type, log_rec->btd_page_size, page, 
		childkey, &deltid, &delpartno);
	    status = dm1cxtput(page_type, log_rec->btd_page_size, 
		page, childtid, &deltid, delpartno);
	    if (status != E_DB_OK)
	    {
		dm1cxlog_error(E_DM93EB_BAD_INDEX_TPUT, (DMP_RCB *)NULL, page, 
			page_type, log_rec->btd_page_size, childtid);
		break;
	    }
	}

	/*
	** REDO recovery can usually reclaim space
	** (except REDO physical page lock)
	*/
	if (!index_update && page_type != TCB_PG_V1 &&
	    ((dcb->dcb_status & DCB_S_EXCLUSIVE) == 0) &&
	    (log_rec->btd_header.flags & DM0L_PHYS_LOCK))
	    dmcx_flag = 0;
	else
	    dmcx_flag = DM1CX_RECLAIM;

	status = dm1cxdel(page_type, log_rec->btd_page_size, page,
			DM1C_DIRECT, ix_compressed,
			&dmve->dmve_tran_id,
			LOG_ID_ID(dmve->dmve_log_id),
			(i4)0, dmcx_flag, childkey);
	if (status != E_DB_OK)
	{
	    dm1cxlog_error(E_DM93E2_BAD_INDEX_DEL, (DMP_RCB*)NULL, page, 
		       page_type, log_rec->btd_page_size, childkey);
	    break;
	}

	break;
    }

    /*
    ** Write the LSN, etc, of the Put log record to the updated page
    */
    DM0L_MAKE_LRI_FROM_LOG_RECORD(&lri, log_rec);
    DM1B_VPT_SET_PAGE_LRI_MACRO(page_type, page, &lri);
    DM1B_VPT_SET_PAGE_STAT_MACRO(page_type, page, DMPP_MODIFY);

    dmveUnMutex(dmve, pinfo);
    
    if (status != E_DB_OK)
    {
	SETDBERR(&dmve->dmve_error, 0, E_DM9653_REDO_BTREE_DEL);
	return(E_DB_ERROR);
    }

    return(E_DB_OK);
}
Beispiel #27
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 #28
0
/*{
** Name: psy_alarm - Dispatch security alarm qrymod routines
**
**  INTERNAL PSF call format: status = psy_alarm(&psy_cb, sess_cb);
**  EXTERNAL     call format: status = psy_call (PSY_ALARM, &psy_cb, sess_cb);
**
** Description:
**	This procedure checks the psy_alflag field of the PSY_CB
**	to determine which qrymod processing routine to call:
**		PSY_CALARM results in call to psy_calarm()
**		PSY_KALARM results in call to psy_kalarm()
**
**	This procedure is called for SQL language only.
**
** Inputs:
**      psy_cb
**	    .psy_alflag			location operation
**	sess_cb				Pointer to session control block
**					(Can be NULL)
**
** Outputs:
**      psy_cb
**	    .psy_error			Filled in if error happens
**	Returns:
**	    E_DB_OK			Function completed normally.
**	    E_DB_WARN			Function completed with warning(s);
**	    E_DB_ERROR			Function failed; non-catastrophic error
**	    E_DB_SEVERE			Function failed; catastrophic error
**	Exceptions:
**	    none
**
** Side Effects:
**	    None.
**
** History:
**	21-sep-89 (ralph)
**          written
**	29-nov-93 (robf)
**          Now really call psy_calarm/psy_kalarm()
*/
DB_STATUS
psy_alarm(
	PSY_CB             *psy_cb,
	PSS_SESBLK	   *sess_cb)
{
    DB_STATUS		status=E_DB_OK;
    i4		err_code;
    i4			user_status;
    char		dbname[DB_DB_MAXNAME];
    SCF_CB		scf_cb;
    SCF_SCI		sci_list[2];
    bool		loop=FALSE;
    DB_SECALARM		*alarm= &psy_cb->psy_tuple.psy_alarm;
    DB_STATUS		local_status;
    DB_ERROR		e_error;

    /* This code is called for SQL only */
    /* 
    ** Ensure we're connected to the iidbdb database for database/installation
    ** alarms, and have SECURITY privilege
    */

    if(alarm->dba_objtype==DBOB_DATABASE) 
    do
    {
	scf_cb.scf_length	= sizeof (SCF_CB);
	scf_cb.scf_type	= SCF_CB_TYPE;
	scf_cb.scf_facility	= DB_PSF_ID;
	scf_cb.scf_session	= sess_cb->pss_sessid;
	scf_cb.scf_ptr_union.scf_sci     = (SCI_LIST *) sci_list;
	scf_cb.scf_len_union.scf_ilength = 1;
	sci_list[0].sci_code    = SCI_DBNAME;
	sci_list[0].sci_length  = sizeof(dbname);
	sci_list[0].sci_aresult = (char *) dbname;
	sci_list[0].sci_rlength = NULL;

	status = scf_call(SCU_INFORMATION, &scf_cb);
	if (status != E_DB_OK)
	{
	    err_code = scf_cb.scf_error.err_code;
	    (VOID) psf_error(E_PS0D13_SCU_INFO_ERR, 0L,
			 PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	    status = (status > E_DB_SEVERE) ? status : E_DB_SEVERE;
	    return(status);
	}
	if (MEcmp((PTR)dbname, (PTR)DB_DBDB_NAME, sizeof(dbname)))
	{
	    /* Session not connected to iidbdb */
	    err_code = E_US18D4_6356_NOT_DBDB;
	    (VOID) psf_error(E_US18D4_6356_NOT_DBDB, 0L,
			     PSF_USERERR, &err_code, &psy_cb->psy_error, 1,
			     sizeof("CREATE/DROP SECURITY_ALARM ON DATABASE")-1,
			     "CREATE/DROP SECURITY_ALARM ON DATABASE");
	    status=E_DB_ERROR;
	    break;
	}
	if( !(sess_cb->pss_ustat & DU_USECURITY))
	{
		err_code = E_US18D5_6357_FORM_NOT_AUTH;
		(VOID) psf_error(E_US18D5_6357_FORM_NOT_AUTH, 0L,
			 PSF_USERERR, &err_code, &psy_cb->psy_error, 1,
			 sizeof("CREATE/DROP SECURITY_ALARM")-1,
			 "CREATE/DROP SECURITY_ALARM");
		status=E_DB_ERROR;
		break;
	}
    } while(loop);

    if (status!=E_DB_OK)
    {
	/*
	** Audit failure
	*/
	if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE )
	{
	    SXF_EVENT evtype;
	    i4   msgid;

	    if(alarm->dba_objtype==DBOB_DATABASE) 
		    evtype=SXF_E_DATABASE;
	    else
		    evtype=SXF_E_TABLE;

	    if(psy_cb->psy_alflag&PSY_CALARM)
		    msgid=I_SX202D_ALARM_CREATE;
	    else
		    msgid=I_SX202E_ALARM_DROP;

	    local_status = psy_secaudit(FALSE, sess_cb,
			    (char *)&alarm->dba_objname,
			    (DB_OWN_NAME *)NULL,
			    sizeof(alarm->dba_objname),
			    evtype,
			    msgid,
			    SXF_A_CONTROL|SXF_A_FAIL,
			    &e_error);
	}

       if(psy_cb->psy_alflag&PSY_CALARM)
       {
	    /*
	    ** Destroy query text for CREATE SECURITY_ALARM before
	    ** returning
	    */
	    DB_STATUS loc_status;
	    QSF_RCB	qsf_rb;

	    qsf_rb.qsf_lk_state	= QSO_EXLOCK;
	    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;

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

    /* Select the proper routine to process this request */

    switch (psy_cb->psy_alflag & (PSY_CALARM | PSY_KALARM))
    {
	case PSY_CALARM:
	    status = psy_calarm(psy_cb, sess_cb);
	    break;

	case PSY_KALARM:
	    status = psy_kalarm(psy_cb, sess_cb);
	    break;

	default:
	    status = E_DB_SEVERE;
	    err_code = E_PS0D49_INVALID_ALARM_OP;
	    (VOID) psf_error(E_PS0D49_INVALID_ALARM_OP, 0L,
		    PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	    break;
    }

    return    (status);
}
Beispiel #29
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 #30
0
/*{
** Name: psy_group  - Dispatch group identifier qrymod routines
**
**  INTERNAL PSF call format: status = psy_group(&psy_cb, sess_cb);
**  EXTERNAL     call format: status = psy_call (PSY_GROUP,&psy_cb, sess_cb);
**
** Description:
**	This procedure checks the psy_grpflag field of the PSY_CB
**	to determine which qrymod processing routine to call:
**		PSY_CGROUP results in call to psy_cgroup()
**		PSY_AGROUP results in call to psy_agroup()
**		PSY_DGROUP results in call to psy_dgroup()
**		PSY_KGROUP results in call to psy_kgroup()
**	This procedure is called for SQL language only.
**
** Inputs:
**      psy_cb
**	    .psy_grpflag		Group identifier operation
**	sess_cb				Pointer to session control block
**					(Can be NULL)
**
** Outputs:
**      psy_cb
**	    .psy_error			Filled in if error happens
**	Returns:
**	    E_DB_OK			Function completed normally.
**	    E_DB_WARN			Function completed with warning(s);
**	    E_DB_ERROR			Function failed; non-catastrophic error
**	    E_DB_SEVERE			Function failed; catastrophic error
**	Exceptions:
**	    none
**
** Side Effects:
**	    None.
**
** History:
**	12-mar-89 (ralph)
**          written
**	20-may-89 (ralph)
**	    Allow multiple groups to be specified.
**      29-jul-89 (jennifer)
**          Added auditing of failure to perform operation.
**	30-oct-89 (ralph)
**	    Use pss_ustat for authorization check.
**	10-mar-93 (markg)
**	    Fix bug where audit of failed group operations
**	    was coded incorrectly.
**	17-jun-93 (andre)
**	    changed interface of psy_secaudit() to accept PSS_SESBLK
**	16-aug-93 (stephenb)
**	    Changed call to psy_secaudit() to audit SXF_E_SECURITY instead
**	    of SXF_E_USER, group manipulation is a security event not a 
**	    user event.
**	18-may-1993 (robf)
**	    Replaced SUPERUSER priv.
**	    Add security label to psy_secaudit() call
**	2-nov-93 (robf)
**          Enforce MAINTAIN_USERS priv to access user groups.
*/
DB_STATUS
psy_group(
	PSY_CB             *psy_cb,
	PSS_SESBLK	   *sess_cb)
{
    DB_STATUS		status = E_DB_OK;
    i4		err_code;
    char		dbname[DB_DB_MAXNAME];
    SCF_CB		scf_cb;
    SCF_SCI		sci_list[1];
    bool		leave_loop = TRUE;

    /* This code is called for SQL only */

    /* Make sure user is authorized and connected to iidbdb */

    do
    {
	if (!(sess_cb->pss_ustat & DU_UMAINTAIN_USER))
	{
	    if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE )
	    {
		DB_ERROR	    e_error;
		i4		    access = 0;    		        
		i4         msgid;
		PSY_TBL	    *psy_tbl = (PSY_TBL *)psy_cb->psy_tblq.q_next;

		/* Audit that operation rejected. */
		if (psy_cb->psy_grpflag == PSY_CGROUP)
		{	
		    access = SXF_A_FAIL | SXF_A_CREATE;
		    msgid = I_SX2007_GROUP_CREATE;
		}
		else if (psy_cb->psy_grpflag == PSY_AGROUP)
		{
		    access = SXF_A_FAIL | SXF_A_ALTER;
		    msgid = I_SX2008_GROUP_MEM_CREATE;
		}
		else if (psy_cb->psy_grpflag == PSY_DGROUP)
		{
		    access = SXF_A_FAIL | SXF_A_ALTER;
		    msgid = I_SX200A_GROUP_MEM_DROP;
		}
		else if (psy_cb->psy_grpflag == PSY_KGROUP)
		{
		    access = SXF_A_FAIL | SXF_A_DROP;
		    msgid = I_SX2009_GROUP_DROP;
		}
		else
		{
		    err_code = E_PS0D40_INVALID_GRPID_OP;
		    status = E_DB_SEVERE;
		    (VOID) psf_error(E_PS0D40_INVALID_GRPID_OP, 0L,
			PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
		    break;
		}
		
		status = psy_secaudit(FALSE, sess_cb,
		  (char *)&psy_tbl->psy_tabnm,
		  (DB_OWN_NAME *)NULL,
		   sizeof(DB_TAB_NAME), 
		   SXF_E_SECURITY,
		   msgid, access, 
		   &e_error);
	    }

            err_code = E_US18D3_6355_NOT_AUTH;
            (VOID) psf_error(E_US18D3_6355_NOT_AUTH, 0L,
                             PSF_USERERR, &err_code, &psy_cb->psy_error, 1,
                             sizeof("CREATE/ALTER/DROP GROUP")-1,
                             "CREATE/ALTER/DROP GROUP");
	    status   = E_DB_ERROR;
	    break;

	}

	scf_cb.scf_length	= sizeof (SCF_CB);
	scf_cb.scf_type	= SCF_CB_TYPE;
	scf_cb.scf_facility	= DB_PSF_ID;
        scf_cb.scf_session	= sess_cb->pss_sessid;
        scf_cb.scf_ptr_union.scf_sci     = (SCI_LIST *) sci_list;
        scf_cb.scf_len_union.scf_ilength = 1;
        sci_list[0].sci_length  = sizeof(dbname);
        sci_list[0].sci_code    = SCI_DBNAME;
        sci_list[0].sci_aresult = (char *) dbname;
        sci_list[0].sci_rlength = NULL;

        status = scf_call(SCU_INFORMATION, &scf_cb);
        if (status != E_DB_OK)
        {
	    err_code = scf_cb.scf_error.err_code;
	    (VOID) psf_error(E_PS0D13_SCU_INFO_ERR, 0L,
			     PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	    status = (status > E_DB_SEVERE) ? status : E_DB_SEVERE;
	    break;
        }

	if (MEcmp((PTR)dbname, (PTR)DB_DBDB_NAME, sizeof(dbname)))
	{
	    /* Session not connected to iidbdb */
            err_code = E_US18D4_6356_NOT_DBDB;
            (VOID) psf_error(E_US18D4_6356_NOT_DBDB, 0L,
                             PSF_USERERR, &err_code, &psy_cb->psy_error, 1,
                             sizeof("CREATE/ALTER/DROP GROUP")-1,
                             "CREATE/ALTER/DROP GROUP");
	    status   = E_DB_ERROR;
	    break;
	    

	}

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

    /* Select the proper routine to process this request */

    if (status == E_DB_OK)
    switch (psy_cb->psy_grpflag)
    {
	case PSY_CGROUP:
	    status = psy_cgroup(psy_cb, sess_cb);
	    break;

	case PSY_AGROUP:
	    status = psy_agroup(psy_cb, sess_cb);
	    break;

	case PSY_DGROUP:
	    status = psy_dgroup(psy_cb, sess_cb);
	    break;

	case PSY_KGROUP:
	    status = psy_kgroup(psy_cb, sess_cb);
	    break;

	default:
	    err_code = E_PS0D40_INVALID_GRPID_OP;
	    status = E_DB_SEVERE;
	    (VOID) psf_error(E_PS0D40_INVALID_GRPID_OP, 0L,
		    PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	    break;
    }

    return    (status);
}