/*{ ** 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); }
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); }
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 ); }
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() */
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); }
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 ); }
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); }
/*{ ** 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 */
/*{ ** 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); }
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); }
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 */
/*{ ** 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 */ }
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 */
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); }
/*{ ** 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); }
/*{ ** 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); }
/*{ ** 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); } } }
/*{ ** 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 ); }
/*{ ** 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); }
/*{ ** 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 = ␣ } if (tc2 < endtc2) { lc2 = tc2; CMnext(tc2); } else { lc2 = ␣ } /* 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); }
/*{ ** 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); }
/*{ ** 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 */ }
/*{ ** 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); }
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)
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); }
/*{ ** 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); }
/*{ ** 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); }
/*{ ** 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); }
/*{ ** 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); }
/*{ ** 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); }