/*{ ** Name: psy_create_synonym - Insert a tuple into IISYNONYM. ** ** Description: ** Call RDF_UPDATE to insert a tuple into IISYNONYM. ** Inputs: ** psy_cb PSY control block. ** sess_cb PSF session control block. ** Outputs: ** Exceptions: ** none ** Returns: ** E_DB_OK synonym tuple has been inserted successfully; ** error status from RDF otherwise ** ** Side Effects: ** Modifies system catalogs. ** ** History: ** 19-apr-90 (andre) ** Created. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 03-aug-92 (barbara) ** Invalidate base object's infoblk from the RDF cache. ** 10-aug-93 (andre) ** fixed causes of compiler warnings */ DB_STATUS psy_create_synonym( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_STATUS status; i4 err_code; /* Initialize the RDF request block. */ pst_rdfcb_init(&rdf_cb, sess_cb); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner); rdf_rb->rdr_2types_mask = (RDF_TYPES) RDR2_SYNONYM; rdf_rb->rdr_update_op = RDR_APPEND; rdf_rb->rdr_qrytuple = psy_cb->psy_tupptr; rdf_rb->rdr_tabid.db_tab_base = DM_B_SYNONYM_TAB_ID; rdf_rb->rdr_tabid.db_tab_index = DM_I_SYNONYM_TAB_ID; /* Insert a tuple into IISYNONYM */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0143_CREATE_SYNONYM) { DB_IISYNONYM *syn = (DB_IISYNONYM *) psy_cb->psy_tupptr; (VOID) psf_error(E_PS0454_CREATE_SYN_ERROR, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(DB_SYNNAME), (char *) &syn->db_synname), &syn->db_synname); } else { (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } return (status); } /* Invalidate the base object's info block from the RDF cache */ { DB_IISYNONYM *syn_tuple = (DB_IISYNONYM *) psy_cb->psy_tupptr; pst_rdfcb_init(&rdf_cb, sess_cb); STRUCT_ASSIGN_MACRO(syn_tuple->db_syntab_id, rdf_rb->rdr_tabid); status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } } return (status); }
DB_STATUS psy_csequence( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_STATUS status; /* Assign user */ STRUCT_ASSIGN_MACRO(sess_cb->pss_user, psy_cb->psy_tuple.psy_sequence.dbs_owner); /* zero out RDF_CB and init common elements */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_l_querytext = 0; rdf_rb->rdr_querytext = NULL; rdf_rb->rdr_2types_mask = RDR2_SEQUENCE; /* Sequence definition */ rdf_rb->rdr_update_op = RDR_APPEND; rdf_rb->rdr_qrytuple = (PTR)&psy_cb->psy_tuple.psy_sequence; /* sequence tup */ /* Create new sequence in iisequence */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (status != E_DB_OK) { _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } /* If RDF error */ return (status); } /* psy_csequence */
DB_STATUS psy_asequence( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_IISEQUENCE *newseqp; DB_STATUS status; newseqp = &psy_cb->psy_tuple.psy_sequence; /* update values */ /* zero out RDF_CB and init common elements */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_l_querytext = 0; rdf_rb->rdr_querytext = NULL; rdf_rb->rdr_2types_mask = RDR2_SEQUENCE; /* Sequence definition */ rdf_rb->rdr_update_op = RDR_REPLACE; rdf_rb->rdr_qrytuple = (PTR)newseqp; /* modified iisequence tuple */ /* Update existing sequence in iisequence. */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (status != E_DB_OK) { _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } /* If RDF error */ return (status); } /* psy_asequence */
/*{ ** Name: psy_kuser - Destroy user ** ** INTERNAL PSF call format: status = psy_kuser(&psy_cb, sess_cb); ** ** Description: ** This procedure deletes a user. If the ** user does not exist, the statement is aborted. ** If the user does exist, the associated ** iiuser tuple is deleted. ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_usrq user list ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_INFO Function completed with warning(s). ** E_DB_WARN One ore more roles were rejected. ** E_DB_ERROR Function failed; non-catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Removed tuples from iiuser. ** ** History: ** 04-sep-89 (ralph) ** written ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR */ DB_STATUS psy_kuser( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status, stat; RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DU_USER ustuple; register DU_USER *ustup = &ustuple; PSY_USR *psy_usr; /* This code is called for SQL only */ /* ** Fill in the part of RDF request block that will be constant. */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_update_op = RDR_DELETE; rdf_rb->rdr_status = DB_SQL; rdf_rb->rdr_types_mask = RDR_USER; rdf_rb->rdr_qrytuple = (PTR) ustup; rdf_rb->rdr_qtuple_count = 1; ustup->du_gid = 0; ustup->du_mid = 0; ustup->du_status = 0; ustup->du_flagsmask = 0; MEfill(sizeof(ustup->du_group), (u_char)' ', (PTR)&ustup->du_group); status = E_DB_OK; for (psy_usr = (PSY_USR *) psy_cb->psy_usrq.q_next; psy_usr != (PSY_USR *) &psy_cb->psy_usrq; psy_usr = (PSY_USR *) psy_usr->queue.q_next ) { /* STRUCT_ASSIGN_MACRO(psy_usr->psy_usrnm, ustup->du_name); */ MEcopy((PTR)&psy_usr->psy_usrnm, sizeof(ustup->du_name), (PTR)&ustup->du_name); stat = rdf_call(RDF_UPDATE, (PTR)&rdf_cb); status = (stat > status) ? stat : status; if (DB_FAILURE_MACRO(stat)) break; } if (DB_FAILURE_MACRO(status)) (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); return (status); }
/*{ ** Name: psy_kgroup - Destroy group ** ** INTERNAL PSF call format: status = psy_kgroup(&psy_cb, sess_cb); ** ** Description: ** This procedure deletes group identifiers. No members can be ** in the group to be deleted. If members exist in a group, ** the group is not deleted. ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_tblq head of group queue ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_INFO Function completed with message(s). ** E_DB_WARN One or more groups were rejected. ** E_DB_ERROR Function failed; non-catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Removed tuples from iiusergroup. ** ** History: ** 13-mar-89 (ralph) ** written ** 20-may-89 (ralph) ** Allow multiple groups to be specified. ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR */ DB_STATUS psy_kgroup( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status, stat; RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_USERGROUP ugtuple; register DB_USERGROUP *ugtup = &ugtuple; PSY_TBL *psy_tbl; PSY_USR *psy_usr; /* This code is called for SQL only */ /* ** Fill in the part of RDF request block that will be constant. */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_update_op = RDR_DELETE; rdf_rb->rdr_status = DB_SQL; rdf_rb->rdr_types_mask = RDR_GROUP; rdf_rb->rdr_qrytuple = (PTR) ugtup; rdf_rb->rdr_qtuple_count = 1; MEfill(sizeof(DB_OWN_NAME), (u_char)' ', (PTR)&ugtup->dbug_member); MEfill(sizeof(ugtup->dbug_reserve), (u_char)' ', (PTR)ugtup->dbug_reserve); status = E_DB_OK; for (psy_tbl = (PSY_TBL *) psy_cb->psy_tblq.q_next; psy_tbl != (PSY_TBL *) &psy_cb->psy_tblq; psy_tbl = (PSY_TBL *) psy_tbl->queue.q_next ) { /* STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabnm, ugtup->dbug_group); */ MEcopy((PTR)&psy_tbl->psy_tabnm, sizeof(ugtup->dbug_group), (PTR)&ugtup->dbug_group); stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); status = (stat > status) ? stat : status; if (DB_FAILURE_MACRO(stat)) break; } if (DB_FAILURE_MACRO(status)) (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); return (status); }
/* PSY_SQLVIEW - IS THIS AN SQL VIEW ** ** Description: ** This routine takes a range entry and determines if it is an ** SQL view. This routine assumes that we know that the range entry ** refers to a view. ** ** History: ** 29-sep-92 (andre) ** RDF may choose to allocate a new info block and return its address ** in rdf_info_blk - we need to copy it over to pss_rdrinfo to avoid ** memory leak and other assorted unpleasantries */ DB_STATUS psy_sqlview( PSS_RNGTAB *rngvar, PSS_SESBLK *sess_cb, DB_ERROR *err_blk, i4 *issql) { DB_STATUS status = E_DB_OK; RDF_CB rdf_cb; PST_PROCEDURE *pnode; PST_QTREE *vtree; i4 err_code; *issql = FALSE; pst_rdfcb_init(&rdf_cb, sess_cb); STRUCT_ASSIGN_MACRO(rngvar->pss_tabid, rdf_cb.rdf_rb.rdr_tabid); rdf_cb.rdf_rb.rdr_types_mask = RDR_VIEW | RDR_QTREE ; rdf_cb.rdf_rb.rdr_qtuple_count = 1; rdf_cb.rdf_info_blk = rngvar->pss_rdrinfo; status = rdf_call(RDF_GETINFO, (PTR) &rdf_cb); /* ** RDF may choose to allocate a new info block and return its address in ** rdf_info_blk - we need to copy it over to pss_rdrinfo to avoid memory ** leak and other assorted unpleasantries */ rngvar->pss_rdrinfo = rdf_cb.rdf_info_blk; if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { (VOID) psf_error(E_PS0903_TAB_NOTFOUND, rdf_cb.rdf_error.err_code, PSF_INTERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &rngvar->pss_tabname), &rngvar->pss_tabname); } else { (VOID) psf_rdf_error(RDF_GETINFO, &rdf_cb.rdf_error, err_blk); } return (status); } pnode = (PST_PROCEDURE *) rdf_cb.rdf_info_blk->rdr_view->qry_root_node; vtree = pnode->pst_stmts->pst_specific.pst_tree; if (vtree->pst_qtree->pst_sym.pst_value.pst_s_root.pst_qlang == DB_SQL) *issql = TRUE; return (status); }
DB_STATUS psy_dsequence( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_STATUS status; /* Fill in the RDF request block */ /* first zero it out and fill in common elements */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_2types_mask = RDR2_SEQUENCE; /*Sequence delettion */ rdf_rb->rdr_update_op = RDR_DELETE; rdf_rb->rdr_qrytuple = (PTR)&psy_cb->psy_tuple.psy_sequence; /* sequence tup */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); /* Destroy sequence */ if (status != E_DB_OK) _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); return (status); } /* psy_dsequence */
/*{ ** Name: opv_tproc - Load RDF defs for table procedure range table entry ** ** Description: ** This function allocates and formats simulated RDF structures for ** a table procedure, including result column descriptors that are ** used to resolve "column" references to the procedure. ** ** Inputs: ** sess_cb Pointer to session control block ** rngtable Pointer to the user range table ** scope scope that range variable belongs in ** -1 means don't care. ** corrname Correlation name of table procedure ** dbp Ptr to PSF procedure descriptor ** rngvar Place to put pointer to new range ** variable ** root Ptr to RESDOM list of parameter specs ** err_blk Place to put error information ** ** Outputs: ** rngvar Set to point to the range variable ** err_blk Filled in if an error happens ** Returns: ** E_DB_OK Success ** E_DB_ERROR Non-catastrophic failure ** E_DB_FATAL Catastrophic failure ** Exceptions: ** none ** ** Side Effects: ** Can allocate memory ** ** History: ** 17-april-2008 (dougi) ** Written for table procedures(semi-cloned from pst_stproc). ** 15-dec-2008 (dougi) BUG 121381 ** Fix computation of result column offsets. */ DB_STATUS opv_tproc( OPS_STATE *global, OPV_IGVARS gvar, OPV_GRV *grvp, PST_RNGENTRY *rngentry) { DMT_ATT_ENTRY **attarray, *attrp; DMT_ATT_ENTRY **parmarray, **rescarray; DMT_TBL_ENTRY *tblptr; RDR_INFO *rdrinfop; QEF_DATA *qp; RDF_CB *rdf_cb; RDR_RB *rdf_rb; DB_PROCEDURE *dbp; DB_DBP_NAME proc_name; DB_OWN_NAME proc_owner; i4 parameterCount, rescolCount, resrowWidth; u_i4 created; i4 i, j, totlen, offset; DB_STATUS status; i4 err_code; /* First retrieve iiprocedure row using id from range table entry. */ rdf_cb = &global->ops_rangetab.opv_rdfcb; rdf_rb = &rdf_cb->rdf_rb; STRUCT_ASSIGN_MACRO(rngentry->pst_rngvar, rdf_rb->rdr_tabid); rdf_rb->rdr_types_mask = RDR_PROCEDURE; rdf_rb->rdr_2types_mask = 0; rdf_rb->rdr_instr = RDF_NO_INSTR; /* ** need to set rdf_info_blk to NULL for otherwise RDF assumes that we ** already have the info_block */ rdf_cb->rdf_info_blk = (RDR_INFO *) NULL; status = rdf_call(RDF_GETINFO, rdf_cb); if (DB_FAILURE_MACRO(status)) { (VOID) opx_verror(status, E_OP0004_RDF_GETDESC, rdf_cb->rdf_error.err_code); } dbp = rdf_cb->rdf_info_blk->rdr_dbp; /* Before proceeding - assure this is the same proc that we think it is. */ if (rngentry->pst_timestamp.db_tab_high_time != dbp->db_created) { /* If not, bounce back to SCF to re-parse query. */ opx_vrecover(E_DB_ERROR, E_OP008F_RDF_MISMATCH, rdf_cb->rdf_error.err_code); } /* Save procedure stuff for later. */ parameterCount = dbp->db_parameterCount; rescolCount = dbp->db_rescolCount; resrowWidth = dbp->db_resrowWidth; created = dbp->db_created; STRUCT_ASSIGN_MACRO(dbp->db_dbpname, proc_name); STRUCT_ASSIGN_MACRO(dbp->db_owner, proc_owner); /* Allocate attr descriptors and address from ptr arrays. */ i = dbp->db_parameterCount + dbp->db_rescolCount; attarray = (DMT_ATT_ENTRY **) opu_memory(global, (sizeof(PTR) + sizeof(DMT_ATT_ENTRY)) * i + sizeof(PTR)); /* 1 extra ptr because array is 1-origin */ /* Set up attr pointer arrays for both parms and result columns. */ for (j = 1, attrp = (DMT_ATT_ENTRY *)&attarray[i+1], attarray[0] = (DMT_ATT_ENTRY *)NULL; j <= i; j++, attrp = &attrp[1]) { attarray[j] = attrp; MEfill(sizeof(DMT_ATT_ENTRY), (u_char)0, (char *)attrp); } rescarray = attarray; parmarray = &attarray[rescolCount+1]; /* Load iiprocedure_parameter rows for both parms and result cols. */ rdf_rb->rdr_types_mask = 0; rdf_rb->rdr_2types_mask = RDR2_PROCEDURE_PARAMETERS; rdf_rb->rdr_instr = RDF_NO_INSTR; rdf_rb->rdr_update_op = RDR_OPEN; rdf_rb->rdr_qrymod_id = 0; /* get all tuples */ rdf_rb->rdr_qtuple_count = 20; /* get 20 at a time */ rdf_cb->rdf_error.err_code = 0; /* ** must set rdr_rec_access_id since otherwise RDF will barf when we ** try to RDR_OPEN */ rdf_rb->rdr_rec_access_id = NULL; while (rdf_cb->rdf_error.err_code == 0) { status = rdf_call(RDF_READTUPLES, rdf_cb); rdf_rb->rdr_update_op = RDR_GETNEXT; /* Must not use DB_FAILURE_MACRO because E_RD0011 returns ** E_DB_WARN that would be missed. */ 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; default: opx_error(E_OP0013_READ_TUPLES); break; } /* switch */ } /* if status != E_DB_OK */ /* For each dbproc parameter tuple */ for (qp = rdf_cb->rdf_info_blk->rdr_pptuples->qrym_data, j = 0; j < rdf_cb->rdf_info_blk->rdr_pptuples->qrym_cnt; qp = qp->dt_next, j++) { DB_PROCEDURE_PARAMETER *param_tup = (DB_PROCEDURE_PARAMETER *) qp->dt_data; if (i-- == 0) { opx_error(E_OP0013_READ_TUPLES); } if (param_tup->dbpp_flags & DBPP_RESULT_COL) { attrp = rescarray[param_tup->dbpp_number]; attrp->att_number = param_tup->dbpp_number; } else { attrp = parmarray[param_tup->dbpp_number-1]; attrp->att_flags = DMT_F_TPROCPARM; attrp->att_number = param_tup->dbpp_number + dbp->db_rescolCount; } STRUCT_ASSIGN_MACRO(param_tup->dbpp_name, attrp->att_name); attrp->att_type = param_tup->dbpp_datatype; attrp->att_width = param_tup->dbpp_length; attrp->att_prec = param_tup->dbpp_precision; attrp->att_offset = param_tup->dbpp_offset; } } /* Reset result column offsets to remove effect of parms. */ offset = rescarray[1]->att_offset; for (j = 1; j <= rescolCount; j++) rescarray[j]->att_offset -= offset; if (rdf_rb->rdr_rec_access_id != NULL) { rdf_rb->rdr_update_op = RDR_CLOSE; status = rdf_call(RDF_READTUPLES, rdf_cb); if (DB_FAILURE_MACRO(status)) { opx_error(E_OP0013_READ_TUPLES); } } /* now unfix the dbproc description */ rdf_rb->rdr_types_mask = RDR_PROCEDURE | RDR_BY_NAME; rdf_rb->rdr_2types_mask = 0; rdf_rb->rdr_instr = RDF_NO_INSTR; status = rdf_call(RDF_UNFIX, rdf_cb); if (DB_FAILURE_MACRO(status)) { opx_error(E_OP008D_RDF_UNFIX); } /* Allocate table descriptor. */ tblptr = (DMT_TBL_ENTRY *) opu_memory(global, sizeof(DMT_TBL_ENTRY)); /* Allocate RDR_INFO block. */ rdrinfop = (RDR_INFO *) opu_memory(global, sizeof(RDR_INFO)+sizeof(PTR)); /* Now format them all. */ MEfill(sizeof(DMT_TBL_ENTRY), (u_char) 0, tblptr); MEcopy((char *)&proc_name.db_dbp_name, sizeof(DB_DBP_NAME), (char *)&tblptr->tbl_name.db_tab_name); STRUCT_ASSIGN_MACRO(proc_owner, tblptr->tbl_owner); MEfill(sizeof(DB_LOC_NAME), (u_char)' ', (char *)&tblptr->tbl_location); tblptr->tbl_attr_count = rescolCount + parameterCount; tblptr->tbl_width = resrowWidth; tblptr->tbl_date_modified.db_tab_high_time = created; tblptr->tbl_storage_type = DB_TPROC_STORE; /* Load cost parameters (if there). */ tblptr->tbl_record_count = (dbp->db_estRows) ? dbp->db_estRows : DBP_ROWEST; tblptr->tbl_page_count = (dbp->db_estCost) ? dbp->db_estCost : DBP_DIOEST; tblptr->tbl_pgsize = 2048; /* All the other DMT_TBL_ENTRY fields are being left 0 until ** something happens that suggests other values. */ /* Finally fill in the RDR_INFO structure. */ MEfill(sizeof(RDR_INFO), (u_char) 0, rdrinfop); rdrinfop->rdr_rel = tblptr; rdrinfop->rdr_attr = rescarray; rdrinfop->rdr_no_attr = tblptr->tbl_attr_count; rdrinfop->rdr_dbp = dbp; grvp->opv_relation = rdrinfop; BTset((i4)gvar, (char *)&global->ops_rangetab.opv_mrdf); /* indicate ** that RDF info is fixed */ grvp->opv_gmask |= OPV_TPROC; global->ops_gmask |= OPS_TPROCS; /* show query has table procs */ return (E_DB_OK); }
/*{ ** 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: psy_kproc - Drop a database procedure definition from ** the system catalogs. ** ** Description: ** ** Inputs: ** ** Outputs: ** Exceptions: ** none ** ** Side Effects: ** Modifies system catalogs. ** ** History: ** 27-apr-88 (stec) ** Created. ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 12-jun-90 (andre) ** when trying to destroy a dbproc QEP, use "private" alias, which is ** always defined as opposed to the "public" alias which would not be ** defined if the dbproc is not grantable. ** 06-aug-92 (teresa) ** change interface to invalidate procedure by name, owner. ** must set rdr_flags_mask = RDR_PROCEDURE when invalidating the ** procedure cache object. ** 07-nov-92 (andre) ** we will no longer create private aliases for dbproc QPs ** 16-jun-94 (andre) ** it is dangerous to cast a (char *) into a (DB_CURSOR_ID *) and then ** dereference the resulting pointer because the chat ptr may not be ** pointing at memory not aligned on an appopriate boundary. Instead, ** we will allocate a DB_CURSOR_ID structure on the stack, initialize ** it and MEcopy() it into the char array */ DB_STATUS psy_kproc( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_STATUS status, stat; i4 err_code; pst_rdfcb_init(&rdf_cb, sess_cb); (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME), (PTR)&rdf_rb->rdr_name.rdr_prcname); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner); rdf_rb->rdr_types_mask = RDR_PROCEDURE; rdf_rb->rdr_update_op = RDR_DELETE; status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND) { /* Retry */ psy_cb->psy_error.err_code = E_PS0008_RETRY; } else { (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); return (status); } } /* Try to destroy the procedure QP in QSF if things went OK. */ if (DB_SUCCESS_MACRO(status)) { QSF_RCB qsf_rb; PSS_DBPALIAS dbpid; DB_CURSOR_ID dbp_curs_id; /* Initialize the header of 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; qsf_rb.qsf_feobj_id.qso_type = QSO_ALIAS_OBJ; qsf_rb.qsf_feobj_id.qso_lname = sizeof(dbpid); /* Identify the object first */ dbp_curs_id.db_cursor_id[0] = dbp_curs_id.db_cursor_id[1] = 0; (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], DB_TAB_MAXNAME, (PTR)dbp_curs_id.db_cur_name); MEcopy((PTR) &dbp_curs_id, sizeof(DB_CURSOR_ID), (PTR) dbpid); (VOID) MEcopy((PTR) &sess_cb->pss_user, DB_OWN_MAXNAME, (PTR) (dbpid + sizeof(DB_CURSOR_ID))); I4ASSIGN_MACRO(sess_cb->pss_udbid, *(i4 *) (dbpid + sizeof(DB_CURSOR_ID) + DB_OWN_MAXNAME)); (VOID)MEcopy((PTR) dbpid, sizeof(dbpid), (PTR) qsf_rb.qsf_feobj_id.qso_name); /* See if QEP for the alias already exists. */ qsf_rb.qsf_lk_state = QSO_SHLOCK; stat = qsf_call(QSO_JUST_TRANS, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { if (qsf_rb.qsf_error.err_code != E_QS0019_UNKNOWN_OBJ) { (VOID) psf_error(E_PS037A_QSF_TRANS_ERR, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (stat > status) status = stat; goto exit; } else { /* Nothing to destroy, QP not in QSF */ goto exit; } } /* Now destroy the ALIAS and the QP objects in QSF */ 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, &psy_cb->psy_error, 0); if (stat > status) status = stat; } } /* Invalidate procedure object from RDF cache */ pst_rdfcb_init(&rdf_cb, sess_cb); (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME), (PTR)&rdf_rb->rdr_name.rdr_prcname); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner); rdf_rb->rdr_types_mask = RDR_PROCEDURE; 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: return (status); }
/*{ ** Name: psy_cproc - Create a database procedure definition in ** the system catalogs. ** ** Description: ** ** Inputs: ** ** Outputs: ** Exceptions: ** none ** ** Side Effects: ** Modifies system catalogs. ** ** History: ** 27-apr-88 (stec) ** Created. ** 23-aug-88 (stec) ** Added comments, initialize new fields in DB_PROCEDURE. ** 26-apr-89 (andre) ** For internal procedures, set db_mask[0] to DB_IPROC. ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 12-jun-90 (andre) ** when trying to destroy a dbproc QEP, use "private" alias, which is ** always defined as opposed to the "public" alias which would not be ** defined if the dbproc is not grantable. ** 04-mar-92 (andre) ** set DB_ACTIVE_DBP in db_mask[0] to indicate that the dbproc is not ** abandoned. If the dbproc is grantable, set DB_DBPGRANT_OK in ** db_mask[0]. ** 18-may-92 (andre) ** call psy_dbp_status() to verify that the new dbproc is not abandoned ** and trust psy_dbp_status() to determine whether the dbproc is ** grantable or just active. ** 19-may-92 (andre) ** in pslsgram.yi, pss_dependencies_stream was opened to collect info ** about objects/privileges on which the new dbproc depends; ** this stream must be closed before leaving this function since the ** dependence information will be of no use once we return ** 01-jun-92 (andre) ** pass information about objects/privileges on which the new database ** procedure depends to QEF. ** 26-jun-92 (andre) ** enter information about the dbproc into IIPROCEDURE and the list of ** objects and privileges on which it depends into IIDBDEPENDS and ** IIPRIV respectively before calling psy_dbp_status() to determine ** whether it is active. This is necessary since otherwise it would be ** impossible to create mutually recursive database procedures (if P1 ** calls P2 and we are trying to create P2 calling P1, psy_dbp_status() ** will report that P1 is dormant and prevent us from creating P2) ** ** Since we won't know whether the dbproc is active and/or grantable ** until psy_dbp_status() is done, we will set only DB_DBP_INDEP_LIST ** bit in IIPROCEDURE.dbp_mask1 here, unless the independent ** object/privilege list is empty, in which case there is no reason to ** call psy_dbp_status(), so we will set DB_DBPGRANT_OK and ** DB_ACTIVE_DBP bits in IIPROCEDURE.dbp_mask1. ** ** If the independent object/privilege list is not empty and the ** procedure is not dormant, psy_dbp_status() will set appropriate bits ** (DB_DBPGRANT_OK and/or DB_ACTIVE_DBP) in IIPROCEDURE.dbp_mask1 once ** it has determined whether the dbproc is active or grantable ** 09-sep-92 (andre) ** psy_dbp_status() no longer accepts or returns an indicator of ** whether cache had to be flushed in psy_dbp_priv_check() ** 07-nov-92 (andre) ** we will no longer create private aliases for dbproc QPs ** 22-feb-93 (rblumer) ** initialize new RDF proc_param variables for both normal and ** set-input procedures; reverse order of MEcopy and I4assign in ** QP cleanup code so that qsf id gets set up correctly. ** 13-apr-93 (andre) ** if creating a system-generated procedure, independent ** object/privilege list will be empty - QEF will insert IIDBDEPENDS ** tuple recording dependence of the dbproc on a constraint (for ** constraint-enforcing dbprocs) or view (for CHECK OPTION-enforcing ** dbprocs.) Here we will set bits indicating that there will be ** independent object list and that the dbproc is active but not ** grantable (we don't want the user to grant privileges on ** system-generated dbprocs) ** 01-sep-93 (andre) ** in the course of parsing a dbproc definition, we will try to ** determine id of a base table on which the dbproc depends; here we ** will copy it into proctuple.dbPdbp_ubt_id to ensure that it gets ** inserted into IIPROCEDURE ** 22-oct-93 (rblumer) ** normal procedures will now have their parameters inserted into the ** catalogs (previously just set-input procedures did); changed ** initialization of db_parameterCount, rdr_proc_param_cnt and ** rdr_proc_params to work for both types of procedures. ** 30-apr-94 (andre) ** fix for bug 61087: ** proctuple.db_mask[0] was being set before proctuple was MEfill'd ** with NULLCHAR; moved the line initializing proctuple.db_mask[0] ** below call to MEfill() ** 16-jun-94 (andre) ** Bug #64395 ** it is dangerous to cast a (char *) into a (DB_CURSOR_ID *) and then ** dereference the resulting pointer because the chat ptr may not be ** pointing at memory not aligned on an appopriate boundary. Instead, ** we will allocate a DB_CURSOR_ID structure on the stack, initialize ** it and MEcopy() it into the char array ** 19-june-06 (dougi) ** Add DBP_DATA_CHANGE flag for BEFORE trigger validation. ** 28-march-2008 (dougi) ** Changes to support table procedures and named result row elements. ** 4-feb-2009 (dougi) ** Tidy up computation of table procedure result row length. ** 30-mar-2009 (toumi01) b121871 ** Rewrite and simplify the computation of table procedure input ** and output parameter count and width (fixes a logic error that ** caused the result width to be decremented by the width of the ** first result parameter when there were no input parameters). */ DB_STATUS psy_cproc( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; i4 textlen; QSF_RCB qsf_rb; DB_PROCEDURE proctuple; DB_STATUS status, stat; i4 err_code; PSY_TBL dbp_descr; i4 dbp_mask[2]; bool empty_indep_list, rowproc; /* If this is a recreate case, and this code gets called ** just return since there is no work to be done, not even ** recovery of resources. */ if (sess_cb->pss_dbp_flags & PSS_RECREATE) return(E_DB_OK); /* determine if the new dbproc depends on any object or privileges */ if ( sess_cb->pss_indep_objs.psq_objs || sess_cb->pss_indep_objs.psq_objprivs || sess_cb->pss_indep_objs.psq_colprivs ) { empty_indep_list = FALSE; } else { empty_indep_list = TRUE; } /* ** Initialize the header of the QSF control block ** NOTE: it is important that we init qsf_rb before calling ** psy_dbp_status() - if the dbproc cannot be created, code under ** exit: will expect the control block set up for deleting the query ** text QSF object and the query plan QSF object */ qsf_rb.qsf_type = QSFRB_CB; qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rb.qsf_length = sizeof(qsf_rb); qsf_rb.qsf_owner = (PTR)DB_PSF_ID; qsf_rb.qsf_sid = sess_cb->pss_sessid; STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); /* Retrieve info about the procedure text object */ status = qsf_call(QSO_INFO, &qsf_rb); if (DB_FAILURE_MACRO(status)) { goto exit; } /* Get the text length. */ MEcopy((PTR) qsf_rb.qsf_root, sizeof(i4), (PTR) &textlen); /* Initialize the II_PROCEDURE tuple. */ MEfill(sizeof(proctuple), NULLCHAR, (PTR) &proctuple); (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME), (PTR)&proctuple.db_dbpname); /* Current user is the owner. */ STRUCT_ASSIGN_MACRO(sess_cb->pss_user, proctuple.db_owner); proctuple.db_txtlen = textlen; TMnow((SYSTIME *) &proctuple.db_txtid); /* ** if the independent object/privilege list is non-empty, we will set ** DB_DBP_INDEP_LIST bit and leave it to psy_dbp_status() to set the ** remaining bits, if appropriate; otherwise we will set DB_DBPGRANT_OK and ** DB_ACTIVE_DBP bits and avoid calling psy_dbp_status() ** ** if creating a system-generated dbproc, mark the dbproc ACTIVE and ** indicate that there is independent object list (there is not one at this ** point, but QEF will insert IIDBDEPENDS tuple recording dependence of the ** dbproc on a constraint (for constraint-enforcing dbprocs) or view (for ** CHECK OPTION-enforcingdbprocs.) */ /* If working on internal dbproc, set DB_IPROC in db_mask[0] */ if (sess_cb->pss_dbp_flags & PSS_IPROC) proctuple.db_mask[0] |= DB_IPROC; if (sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED) proctuple.db_mask[0] |= DBP_SYSTEM_GENERATED | DB_ACTIVE_DBP | DB_DBP_INDEP_LIST; else if (empty_indep_list) proctuple.db_mask[0] |= DB_DBPGRANT_OK | DB_ACTIVE_DBP; else proctuple.db_mask[0] |= DB_DBP_INDEP_LIST; if (sess_cb->pss_dbp_flags & PSS_SET_INPUT_PARAM) proctuple.db_mask[0] |= DBP_SETINPUT; if (sess_cb->pss_dbp_flags & PSS_NOT_DROPPABLE) proctuple.db_mask[0] |= DBP_NOT_DROPPABLE; if (sess_cb->pss_dbp_flags & PSS_SUPPORTS_CONS) proctuple.db_mask[0] |= DBP_CONS; if (sess_cb->pss_dbp_flags & PSS_DATA_CHANGE) proctuple.db_mask[0] |= DBP_DATA_CHANGE; if (sess_cb->pss_dbp_flags & PSS_OUT_PARMS) proctuple.db_mask[0] |= DBP_OUT_PARMS; if (sess_cb->pss_dbp_flags & PSS_TX_STMT) proctuple.db_mask[0] |= DBP_TX_STMT; if (sess_cb->pss_dbp_flags & PSS_ROW_PROC) { rowproc = TRUE; proctuple.db_mask[0] |= DBP_ROW_PROC; } else rowproc = FALSE; proctuple.db_mask[1] = 0; /* ** if we were able to determine id of a base table on which this dbproc will ** depend, copy it into proctuple */ proctuple.db_dbp_ubt_id.db_tab_base = sess_cb->pss_dbp_ubt_id.db_tab_base; proctuple.db_dbp_ubt_id.db_tab_index = sess_cb->pss_dbp_ubt_id.db_tab_index; /* db_procid to be filled in by RDF or QEF */ proctuple.db_parameterCount = 0; proctuple.db_recordWidth = 0; proctuple.db_rescolCount = 0; proctuple.db_resrowWidth = 0; if (sess_cb->pss_procparmlist != (QEF_DATA *) NULL) { DB_PROCEDURE_PARAMETER *param_tuple; QEF_DATA *listptr; /* compute count and total width of input and result parameters */ for (listptr = sess_cb->pss_procparmlist; listptr != (QEF_DATA *) NULL; listptr = listptr->dt_next) { param_tuple = (DB_PROCEDURE_PARAMETER *)listptr->dt_data; if (param_tuple->dbpp_flags & DBPP_RESULT_COL) { proctuple.db_rescolCount++; proctuple.db_resrowWidth = param_tuple->dbpp_offset + param_tuple->dbpp_length; } else { proctuple.db_parameterCount++; proctuple.db_recordWidth = param_tuple->dbpp_offset + param_tuple->dbpp_length; } } if (proctuple.db_rescolCount > 0) proctuple.db_resrowWidth -= proctuple.db_recordWidth; } /* Initialize the RDF request block. */ pst_rdfcb_init(&rdf_cb, sess_cb); (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME), (PTR)&rdf_rb->rdr_name.rdr_prcname); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner); rdf_rb->rdr_types_mask = RDR_PROCEDURE; rdf_rb->rdr_update_op = RDR_APPEND; rdf_rb->rdr_qrytuple = (PTR) &proctuple; rdf_rb->rdr_l_querytext = textlen; rdf_rb->rdr_querytext = ((char *) qsf_rb.qsf_root) + sizeof(i4); /* ** pass information about objects/privileges on which the new database ** procedure depends to QEF */ sess_cb->pss_indep_objs.psq_grantee = &sess_cb->pss_user; rdf_rb->rdr_indep = (PTR) &sess_cb->pss_indep_objs; /* fill in the description of the procedure's parameters ** (which RDF/QEF will store into iiprocedure_parameter); */ rdf_rb->rdr_proc_param_cnt = proctuple.db_parameterCount + proctuple.db_rescolCount; rdf_rb->rdr_proc_params = sess_cb->pss_procparmlist; /* Create a new procedure in the system catalogs */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0137_DUPLICATE_PROCS) { /* Retry */ psy_cb->psy_error.err_code = E_PS0008_RETRY; } else { (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } goto exit; } /* ** if the independent object/privilege list is non-empty, verify that the ** dbproc we are about to create is not abandoned; strictly speaking, as ** long as the independent object list is empty, we are guaranteed that the ** dbproc is not abandoned (user posesses required privileges), but we will ** take an extra step and try to determine whether it is grantable */ if (!empty_indep_list) { MEcopy((PTR) psy_cb->psy_tabname, sizeof(DB_DBP_NAME), (PTR) &dbp_descr.psy_tabnm); dbp_descr.psy_tabid.db_tab_base = proctuple.db_procid.db_tab_base; dbp_descr.psy_tabid.db_tab_index = proctuple.db_procid.db_tab_index; status = psy_dbp_status(&dbp_descr, sess_cb, (PSF_QUEUE *) NULL, (i4) PSQ_CREDBP, dbp_mask, &psy_cb->psy_error); if (DB_FAILURE_MACRO(status)) { goto exit; } } exit: /* ** close the memory stream which was used to allocate descriptors of ** objects/privileges on which the new dbproc depends */ stat = psf_mclose(sess_cb, sess_cb->pss_dependencies_stream, &psy_cb->psy_error); if (DB_FAILURE_MACRO(stat) && stat > status) status = stat; /* ** ensure that no one tries to use the stream that is no longer valid */ sess_cb->pss_dependencies_stream = (PSF_MSTREAM *) NULL; /* Get a lock on the query text from QSF */ qsf_rb.qsf_lk_state = QSO_EXLOCK; stat = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0A08_CANTLOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (stat > status) status = stat; } else { /* Now destroy the query text */ 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, &psy_cb->psy_error, 0); if (stat > status) status = stat; } } /* Destroy the procedure QP in QSF if things went wrong. */ if (DB_FAILURE_MACRO(status)) { PSS_DBPALIAS dbpid; DB_CURSOR_ID dbp_curs_id; qsf_rb.qsf_feobj_id.qso_type = QSO_ALIAS_OBJ; qsf_rb.qsf_feobj_id.qso_lname = sizeof(dbpid); /* Identify the object first */ dbp_curs_id.db_cursor_id[0] = dbp_curs_id.db_cursor_id[1] = 0; (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], DB_TAB_MAXNAME, (PTR)dbp_curs_id.db_cur_name); MEcopy((PTR) &dbp_curs_id, sizeof(DB_CURSOR_ID), (PTR) dbpid); (VOID) MEcopy((PTR) &sess_cb->pss_user, DB_OWN_MAXNAME, (PTR) (dbpid + sizeof(DB_CURSOR_ID))); I4ASSIGN_MACRO(sess_cb->pss_udbid, *(i4 *) (dbpid + sizeof(DB_CURSOR_ID) + DB_OWN_MAXNAME)); (VOID)MEcopy((PTR) dbpid, sizeof(dbpid), (PTR) qsf_rb.qsf_feobj_id.qso_name); /* See if QP for the alias already exists. */ qsf_rb.qsf_lk_state = QSO_SHLOCK; stat = qsf_call(QSO_JUST_TRANS, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { if (qsf_rb.qsf_error.err_code != E_QS0019_UNKNOWN_OBJ) { (VOID) psf_error(E_PS037A_QSF_TRANS_ERR, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (stat > status) status = stat; goto exit1; } else { /* QP disappeared, which is alright. */ goto exit1; } } /* Now destroy the QP object in QSF */ 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, &psy_cb->psy_error, 0); if (stat > status) status = stat; } } exit1: return (status); }
/* ** History: ** 26-jul-1993 (bryanp) ** Fixed error handling in release_cb following dmxe_pass_abort call. ** 01-Oct-2004 (jenjo02) ** With Factotum threads, scb_oq_next will be empty ** but xcb_odcb_ptr will be correct when calling ** dmxe_pass_abort(). ** 6-Jul-2006 (kschendel) ** Pass the db id to RDF in the right place. ** 16-Nov-2009 (kschendel) SIR 122890 ** Update destroy-temp call parameters. ** 15-Jan-2010 (jonj) ** SIR 121619 MVCC: Deallocate lctx, jctx if allocated. ** 14-Apr-2010 (kschendel) SIR 123485 ** Force a BLOB query-end during cleanup. */ static DB_STATUS release_cb( DMC_CB *dmc, DML_SCB *scb) { DML_XCB *xcb; DMP_DCB *dcb; DMP_RCB *rcb; i4 error,local_error; CL_ERR_DESC clerror; DB_STATUS status; DML_ODCB *odcb; DML_SPCB *spcb; DML_XCCB *xccb; DB_TAB_ID tbl_id; CLRDBERR(&dmc->error); while (scb->scb_x_next != (DML_XCB *) &scb->scb_x_next) { /* Get next XCB. */ xcb = (DML_XCB *) scb->scb_x_next; odcb = (DML_ODCB *) xcb->xcb_odcb_ptr; /* Remove blob Locator context */ if (scb->scb_lloc_cxt) dm0m_deallocate((DM_OBJECT **)&scb->scb_lloc_cxt); /* Close off any in-flight DMPE stuff */ status = dmpe_query_end(TRUE, TRUE, &dmc->error); if ( status != E_DB_OK ) { SETDBERR(&dmc->error, 0, E_DM0106_ERROR_ENDING_SESSION); return (E_DB_FATAL); } /* Remove blob PCB's */ while (xcb->xcb_pcb_list != NULL) dmpe_deallocate(xcb->xcb_pcb_list); /* Close all open tables and destroy all open temporary tables. */ while (xcb->xcb_rq_next != (DMP_RCB*) &xcb->xcb_rq_next) { /* Get next RCB. */ rcb = (DMP_RCB *)((char *)xcb->xcb_rq_next - (char *)&(((DMP_RCB*)0)->rcb_xq_next)); /* Remove from the XCB. */ rcb->rcb_xq_next->rcb_q_prev = rcb->rcb_xq_prev; rcb->rcb_xq_prev->rcb_q_next = rcb->rcb_xq_next; /* Remember DCB and table id of a temporary. */ dcb = 0; if (rcb->rcb_tcb_ptr->tcb_temporary == TCB_TEMPORARY) { dcb = rcb->rcb_tcb_ptr->tcb_dcb_ptr; tbl_id = rcb->rcb_tcb_ptr->tcb_rel.reltid; } /* Deallocate the RCB. */ status = dm2t_close(rcb, (i4)0, &dmc->error); if (status != E_DB_OK) { if ((dmc->error.err_code != E_DM004B_LOCK_QUOTA_EXCEEDED) && (dmc->error.err_code != E_DM0042_DEADLOCK) && (dmc->error.err_code != E_DM004D_LOCK_TIMER_EXPIRED) && (dmc->error.err_code != E_DM004A_INTERNAL_ERROR)) { uleFormat( &dmc->error, 0, NULL, ULE_LOG , NULL, (char * )NULL, 0L, (i4 *)NULL, &local_error, 0); SETDBERR(&dmc->error, 0, E_DM0106_ERROR_ENDING_SESSION); } return (E_DB_FATAL); } /* Now destroy the TCB if it's a temporary. */ /* I can't be bothered to change this code to run off of the ** xccb list, so can't use dmt-destroy-temp. (schka24) ** I may regret this if it turns out that factotum can get ** here -- could end up deleting session temp... */ if (dcb) { RDF_CB rdfcb; /* RDF doesn't use its end-session call, and anyway ** we know the table ID and it doesn't. Toss the ** table out of RDF so that it's not clogging up the ** RDF-works. This also ensures that nobody will accidently ** find the table by ID in RDF if the ID is reused. ** (Unlikely, but possible.) ** Zero in rdr_fcb says don't send invalidate dbevents ** to other servers. Zero in the rdfcb rdf_info_blk says ** we don't have anything fixed. */ MEfill(sizeof(RDF_CB), 0, &rdfcb); STRUCT_ASSIGN_MACRO(tbl_id, rdfcb.rdf_rb.rdr_tabid); rdfcb.rdf_rb.rdr_session_id = scb->scb_sid; rdfcb.rdf_rb.rdr_unique_dbid = dcb->dcb_id; rdfcb.rdf_rb.rdr_db_id = (PTR) odcb; /* Ignore error on this call */ (void) rdf_call(RDF_INVALIDATE, &rdfcb); /* ** Another RCB, yet to be deleted, could still be referencing ** the TCB. Handle the associated error from destroy as normal ** in this case. */ status = dm2t_destroy_temp_tcb(scb->scb_lock_list, dcb, &tbl_id, &dmc->error); if (status != E_DB_OK && dmc->error.err_code != E_DM005D_TABLE_ACCESS_CONFLICT) { uleFormat( &dmc->error, 0, NULL, ULE_LOG , NULL, (char * )NULL, 0L, (i4 *)NULL, &local_error, 0); SETDBERR(&dmc->error, 0, E_DM0106_ERROR_ENDING_SESSION); return (E_DB_FATAL); } } } /* One more time after table closes, guarantees BQCB's deleted */ status = dmpe_query_end(TRUE, FALSE, &dmc->error); if ( status != E_DB_OK ) { SETDBERR(&dmc->error, 0, E_DM0106_ERROR_ENDING_SESSION); return (E_DB_FATAL); } /* Remove SPCBs. */ while (xcb->xcb_sq_next != (DML_SPCB*) &xcb->xcb_sq_next) { /* Get next SPCB. */ spcb = xcb->xcb_sq_next; /* Remove SPCB from XCB queue. */ spcb->spcb_q_next->spcb_q_prev = spcb->spcb_q_prev; spcb->spcb_q_prev->spcb_q_next = spcb->spcb_q_next; /* Deallocate the SPCB. */ dm0m_deallocate((DM_OBJECT **)&spcb); } /* Remove XCCBs. */ while (xcb->xcb_cq_next != (DML_XCCB*)&xcb->xcb_cq_next) { /* Get pend XCCB */ xccb = xcb->xcb_cq_next; /* Remove from queue. */ xccb->xccb_q_next->xccb_q_prev = xccb->xccb_q_prev; xccb->xccb_q_prev->xccb_q_next = xccb->xccb_q_next; /* Deallocate. */ dm0m_deallocate((DM_OBJECT **)&xccb); } /* Deallocate lctx, jctx if allocated */ if ( xcb->xcb_lctx_ptr ) dm0m_deallocate(&xcb->xcb_lctx_ptr); if ( xcb->xcb_jctx_ptr ) { /* Close any open jnl file, deallocate jctx */ status = dm0j_close(&xcb->xcb_jctx_ptr, &dmc->error); if ( status ) { SETDBERR(&dmc->error, 0, E_DM0106_ERROR_ENDING_SESSION); return (E_DB_FATAL); } } /* ** Since we are deallocating a session which has an open transaction, ** we signal the RCP to abort the transaction for us before deallocating ** its context. ** ** Call dmxe to flush any required pages from the Buffer Manager and ** to make the abort request to the RCP. ** ** The LG context will be freed up by the RCP when the abort is ** complete. ** ** Reference the DB opened on the XCB, not SCB; if this ** is a Factotum thread, scb_oq_next will be empty, ** but xcb_odcb_ptr will be valid. ** Likewise, use xcb_lk_id rather than scb_lock_list. */ /* XXXX log error message about why pass abort is called */ status = dmxe_pass_abort(xcb->xcb_log_id, xcb->xcb_lk_id, &xcb->xcb_tran_id, odcb->odcb_dcb_ptr->dcb_id, &dmc->error); if (status) { /* XXXX May want to dmd_check here */ uleFormat(&dmc->error, 0, NULL, ULE_LOG, NULL, NULL, 0, NULL, &error, 0); SETDBERR(&dmc->error, 0, E_DM0106_ERROR_ENDING_SESSION); return (E_DB_FATAL); } /* Remove XCB from SCB queue. */ xcb->xcb_q_next->xcb_q_prev = xcb->xcb_q_prev; xcb->xcb_q_prev->xcb_q_next = xcb->xcb_q_next; scb->scb_x_ref_count--; dm0m_deallocate((DM_OBJECT **)&xcb); } /* Close all the opened database of the session. */ while (scb->scb_oq_next != (DML_ODCB *) &scb->scb_oq_next) { /* Get next ODCB. */ odcb = (DML_ODCB *) scb->scb_oq_next; status = dm2d_close_db(odcb->odcb_dcb_ptr, scb->scb_lock_list, DM2D_NLG | DM2D_NLK_SESS, &dmc->error); if (status != E_DB_OK) { if (dmc->error.err_code > E_DM_INTERNAL) { uleFormat( &dmc->error, 0, NULL, ULE_LOG , NULL, (char * )NULL, 0L, (i4 *)NULL, &local_error, 0); SETDBERR(&dmc->error, 0, E_DM0106_ERROR_ENDING_SESSION); } return (E_DB_FATAL); } scb->scb_o_ref_count--; odcb->odcb_q_next->odcb_q_prev = odcb->odcb_q_prev; odcb->odcb_q_prev->odcb_q_next = odcb->odcb_q_next; dm0s_mrelease(&odcb->odcb_cq_mutex); dm0m_deallocate((DM_OBJECT **)&odcb); } return(E_DB_OK); }
/*{ ** 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_kinteg - Destroy one or more integrities for a table. ** ** INTERNAL PSF call format: status = psy_kinteg(&psy_cb, sess_cb); ** ** EXTERNAL call format: status = psy_call(PSY_KINTEG, &psy_cb, sess_cb); ** ** Description: ** The psy_kinteg function removes the definitions of one or more ** integrities on a table from the system relations (integrities, ** tree, and iiqrytext). ** Optionally, one can tell this function to destroy all of the ** integrities on the given table. ** ** Inputs: ** psy_cb ** .psy_tables[0] Id of table from which to remove ** integrities ** .psy_numbs[] Array of integrity id numbers telling ** which integrities to destroy (at most ** 20) ** .psy_numnms Number telling how many integrity ** numbers there are. Zero means to ** destroy all of the integrities ** on the given table. ** .psy_tabname[0] Name of table from which to remove ** integrities ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if an error happens ** .err_code What the error was ** E_PS0000_OK Success ** E_PS0001_USER_ERROR User made a mistake ** E_PS0002_INTERNAL_ERROR Internal inconsistency in PSF ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s) ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Removes query tree(s) representing predicates of integrities from ** tree relation, text of defining query (or queries) from iiqrytext ** relation, rows defining integrity (or integrities) from integrities ** relation. If there are no more integrities on this table, will ** use DMF alter table function to indicate this. ** ** History: ** 02-oct-85 (jeff) ** written ** 30-aug-88 (andre) ** check if the user specified integrity 0 to be deleted, ** and if so, warn that it doesn't exist (this will prevent someone ** from inadvertently deleting all integrities by specifying that ** integrity 0 be deleted.) ** 30-aug-88 (andre) ** When looking at individual integrities, return E_DB_ERROR if any ** errors were found when processing individual integrities. ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 03-aug-1992 (barbara) ** Call pst_rdfcb_init to initialize RDF_CB before calling RDF. ** Invalidate infoblk from RDF cache after dropping integrity. ** 07-aug-92 (teresa) ** RDF_INVALID must be called for the base object that the ** integrity was defined on as well as for the integrity trees. ** 14-sep-92 (barbara) ** Set type field and tableid in the RDF cb used to invalidate ** the cached entries. ** 14-jul-93 (ed) ** replacing <dbms.h> by <gl.h> <sl.h> <iicommon.h> <dbdbms.h> ** 10-aug-93 (andre) ** removed declaration of rdf_call() ** 30-sep-93 (stephenb) ** Pass tablename from psy_cb to rdf_rb, so that we can use the ** information to audit in QEF. */ DB_STATUS psy_kinteg( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; RDF_CB rdf_inv_cb; /* For invalidation */ register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_STATUS status = E_DB_OK; i4 err_code; register i4 i; /* Fill in RDF control block */ pst_rdfcb_init(&rdf_cb, sess_cb); pst_rdfcb_init(&rdf_inv_cb, sess_cb); STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[0], rdf_rb->rdr_tabid); STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[0], rdf_inv_cb.rdf_rb.rdr_tabid); rdf_rb->rdr_types_mask = RDR_INTEGRITIES; rdf_inv_cb.rdf_rb.rdr_types_mask = RDR_INTEGRITIES; rdf_rb->rdr_update_op = RDR_DELETE; rdf_rb->rdr_name.rdr_tabname = psy_cb->psy_tabname[0]; /* No integrity numbers means destroy all integrities. */ if (psy_cb->psy_numnms == 0) { /* Zero integrity number means destroy all integs. */ rdf_rb->rdr_qrymod_id = 0; status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); } else { (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } return (status); } /* Invalidate table info from RDF cache */ /* first invalidate the object from the relation cache */ status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); /* now invalidate any integrity trees from the cache */ rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_CLASS; status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); } else { DB_STATUS stat; /* Run through the integrity numbers, destroying each one */ for (i = 0; i < psy_cb->psy_numnms; i++) { /* if user specified 0, complain and proceed with next integrity # */ if ((rdf_rb->rdr_qrymod_id = psy_cb->psy_numbs[i]) == 0) { /* remember error to report later */ status = (status > E_DB_ERROR) ? status : E_DB_ERROR; (VOID) psf_error(5203, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof (rdf_rb->rdr_qrymod_id), &rdf_rb->rdr_qrymod_id); continue; } stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); /* remember the highest status seen so far */ status = (status > stat) ? status : stat; if (DB_FAILURE_MACRO(stat)) { switch (rdf_cb.rdf_error.err_code) { case E_RD0002_UNKNOWN_TBL: (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); break; case E_RD0013_NO_TUPLE_FOUND: (VOID) psf_error(5203, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof (rdf_rb->rdr_qrymod_id), &rdf_rb->rdr_qrymod_id); continue; default: (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } return (status); } /* invalidate the integrity tree from the cache. */ rdf_inv_cb.rdf_rb.rdr_sequence = psy_cb->psy_numbs[i]; rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_ALIAS; status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); break; } } /* now invalidate the integrity base object from the relation cache */ if (DB_SUCCESS_MACRO(status)) { rdf_inv_cb.rdf_rb.rdr_sequence = 0; rdf_inv_cb.rdf_rb.rdr_2types_mask &= ~RDR2_ALIAS; status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); } } } return (status); }
/*{ ** Name: psy_aprofile - Alter profile ** ** Description: ** This procedure alters an iiprofile tuple. If the ** user does not exist, the statement is aborted. ** If the user does exist, the associated ** iiprofile tuple is replaced. ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_usrq user list ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_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: ** Replaces tuples in iiuser. ** ** History: ** 27-aug-93 (robf) ** Written */ static DB_STATUS psy_aprofile( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status, stat; RDF_CB rdf_cb; i4 err_code; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; struct { DU_PROFILE protuple; DU_PROFILE protuple2; } usparam; register DU_PROFILE *protup = &usparam.protuple; register DU_PROFILE *protup2 = &usparam.protuple2; PSY_USR *psy_usr; SCF_CB scf_cb; SCF_CB scf_cb2; DB_DATA_VALUE db_data; DB_DATE dateval; FUNC_EXTERN DB_STATUS rdf_call(); FUNC_EXTERN DB_STATUS scf_call(); /* This code is called for SQL only */ /* ** Fill in the part of RDF request block that will be constant. */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_update_op = RDR_REPLACE; rdf_rb->rdr_status = DB_SQL; rdf_rb->rdr_2types_mask = RDR2_PROFILE; rdf_rb->rdr_qrytuple = (PTR) protup; rdf_rb->rdr_qtuple_count = 1; protup->du_flagsmask = 0; if(psy_cb->psy_usflag& PSY_USRDEFPRIV) { protup->du_defpriv = psy_cb->psy_usdefprivs; protup->du_flagsmask|= DU_UDEFPRIV; /* Add default=all indicator */ if(psy_cb->psy_usflag & PSY_USRDEFALL) protup->du_flagsmask|=DU_UDEFALL; /* if user has specified nodefault_privileges we ** store this flag to negotiate the final status ** of default privileges. */ if (psy_cb->psy_usflag & PSY_UNODEFPRIV) protup->du_flagsmask|= DU_UNODEFPRIV; } else protup->du_defpriv = 0; /* ** Expiration date, may be empty */ if(psy_cb->psy_usflag& PSY_USREXPDATE) { /* ** Date already formatted earlier */ MECOPY_CONST_MACRO((PTR)&psy_cb->psy_date, sizeof(DB_DATE), (PTR)&protup->du_expdate); protup->du_flagsmask|= DU_UEXPDATE; } else { /* ** Initialize to the empty date */ db_data.db_datatype = DB_DTE_TYPE; db_data.db_prec = 0; db_data.db_length = DB_DTE_LEN; db_data.db_data = (PTR)&protup->du_expdate; status = adc_getempty(sess_cb->pss_adfcb, &db_data); if(status) return status; } /* ** Check if adding, deleting, or setting privileges */ protup->du_status = (i4) psy_cb->psy_usprivs; if (psy_cb->psy_usflag & PSY_USRAPRIVS) protup->du_flagsmask |= DU_UAPRIV; else if (psy_cb->psy_usflag & PSY_USRDPRIVS) protup->du_flagsmask |= DU_UDPRIV; else if (psy_cb->psy_usflag & PSY_USRPRIVS) protup->du_flagsmask |= DU_UPRIV; else protup->du_status = 0; /* ** Check if updating security audit options */ if (psy_cb->psy_usflag & PSY_USRSECAUDIT) { if(psy_cb->psy_ussecaudit & PSY_USAU_ALL_EVENTS) protup->du_flagsmask |= DU_UALLEVENTS; else protup->du_flagsmask |= DU_UDEFEVENTS; if (psy_cb->psy_ussecaudit & PSY_USAU_QRYTEXT) protup->du_flagsmask |= DU_UQRYTEXT; else protup->du_flagsmask |= DU_UNOQRYTEXT; } if (psy_cb->psy_usflag & PSY_USRDEFGRP) { MEcopy((PTR)&psy_cb->psy_usgroup, sizeof(protup->du_group), (PTR)&protup->du_group); protup->du_flagsmask|= DU_UGROUP; } else { MEfill(sizeof(protup->du_group), (u_char)' ', (PTR)&protup->du_group); } status = E_DB_OK; for (psy_usr = (PSY_USR *) psy_cb->psy_usrq.q_next; psy_usr != (PSY_USR *) &psy_cb->psy_usrq; psy_usr = (PSY_USR *) psy_usr->queue.q_next ) { /* STRUCT_ASSIGN_MACRO(psy_usr->psy_usrnm, protup->du_name); */ MEcopy((PTR)&psy_usr->psy_usrnm, sizeof(protup->du_name), (PTR)&protup->du_name); stat = rdf_call(RDF_UPDATE, (PTR)&rdf_cb); status = (stat > status) ? stat : status; if (DB_FAILURE_MACRO(stat)) break; } if (DB_FAILURE_MACRO(status)) (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); return (status); }
/*{ ** Name: psy_auser - Alter user ** ** INTERNAL PSF call format: status = psy_auser(&psy_cb, sess_cb); ** ** Description: ** This procedure alters an iiuser tuple. If the ** user does not exist, the statement is aborted. ** If the user does exist, the associated ** iiuser tuple is replaced. ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_usrq user list ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_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: ** Replaces tuples in iiuser. ** ** History: ** 04-sep-89 (ralph) ** written ** 16-jan-90 (ralph) ** add support for user passwords ** 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) ** add support for oldpassword (as in ALTER USER OLDPASSWORD = '******') ** 12-apr-95 (forky01) ** Apply default privs when only privs specified to allow backward ** compatibility to fix Secure 2.0 code. ** 28-jul-2003 (gupsh01) ** Added check for case when noprivileges have been added and ** nodefault_privileges is not specified, with a profile in alter ** user statement. */ DB_STATUS psy_auser( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status, stat; RDF_CB rdf_cb; i4 err_code; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; struct { DU_USER ustuple; DU_USER ustuple2; } usparam; register DU_USER *ustup = &usparam.ustuple; register DU_USER *ustup2 = &usparam.ustuple2; PSY_USR *psy_usr; bool encrypt; bool encrypt2; SCF_CB scf_cb; SCF_CB scf_cb2; DB_DATA_VALUE db_data; DB_DATE dateval; /* This code is called for SQL only */ /* ** Fill in the part of RDF request block that will be constant. */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_update_op = RDR_REPLACE; rdf_rb->rdr_status = DB_SQL; rdf_rb->rdr_types_mask = RDR_USER; rdf_rb->rdr_qrytuple = (PTR) ustup; rdf_rb->rdr_qtuple_count = 1; ustup->du_gid = 0; ustup->du_mid = 0; ustup->du_flagsmask = 0; /* User profile */ if(psy_cb->psy_usflag& PSY_USRPROFILE) { MECOPY_CONST_MACRO((PTR)&psy_cb->psy_usprofile, sizeof(psy_cb->psy_usprofile), (PTR)&ustup->du_profile); ustup->du_flagsmask|= DU_UHASPROFILE; } else { MEfill(sizeof(ustup->du_profile), (u_char)' ', (PTR)&ustup->du_profile); } if ((psy_cb->psy_usflag& PSY_USRPROFILE) && (psy_cb->psy_usflag& PSY_USRPRIVS) && (psy_cb->psy_usflag& PSY_UNOPRIVS) && !(psy_cb->psy_usflag & PSY_UNODEFPRIV)) { /* If alter user has PSY_UNOPRIVS specified and ** we have provided a profile for this user ** but we have not set the nodefault_privileges ** specified, We should return an error. profile ** may have default_privileges, which will be ** inherited by the user with noprivileges. */ err_code = E_US1968_6504_UNOPRIV_WDEFAULT; (VOID) psf_error( E_US1968_6504_UNOPRIV_WDEFAULT, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 0); status = E_DB_ERROR; return(status); } if(psy_cb->psy_usflag& PSY_USRDEFPRIV) { ustup->du_defpriv = psy_cb->psy_usdefprivs; ustup->du_flagsmask|= DU_UDEFPRIV; /* Add default=all indicator */ if(psy_cb->psy_usflag & PSY_USRDEFALL) ustup->du_flagsmask|=DU_UDEFALL; /* set value of nodefault_privileges flag */ if (psy_cb->psy_usflag & PSY_UNODEFPRIV) ustup->du_flagsmask|= DU_UNODEFPRIV; } else { /* ** If no default specified use all privileges */ if (psy_cb->psy_usflag & PSY_USRPRIVS) ustup->du_defpriv = (i4)psy_cb->psy_usprivs; else ustup->du_defpriv = 0; } /* ** Expiration date, may be empty */ if(psy_cb->psy_usflag& PSY_USREXPDATE) { /* ** Date already formatted earlier */ MECOPY_CONST_MACRO((PTR)&psy_cb->psy_date, sizeof(DB_DATE), (PTR)&ustup->du_expdate); ustup->du_flagsmask|= DU_UEXPDATE; } else { /* ** Initialize to the empty date */ db_data.db_datatype = DB_DTE_TYPE; db_data.db_prec = 0; db_data.db_length = DB_DTE_LEN; db_data.db_data = (PTR)&ustup->du_expdate; status = adc_getempty(sess_cb->pss_adfcb, &db_data); if(status) return status; } /* ** Check if adding, deleting, or setting privileges */ ustup->du_status = (i4) psy_cb->psy_usprivs; if (psy_cb->psy_usflag & PSY_USRAPRIVS) ustup->du_flagsmask |= DU_UAPRIV; else if (psy_cb->psy_usflag & PSY_USRDPRIVS) ustup->du_flagsmask |= DU_UDPRIV; else if (psy_cb->psy_usflag & PSY_USRPRIVS) ustup->du_flagsmask |= DU_UPRIV; else ustup->du_status = 0; /* ** Check if updating security audit options */ if (psy_cb->psy_usflag & PSY_USRSECAUDIT) { if(psy_cb->psy_ussecaudit & PSY_USAU_ALL_EVENTS) ustup->du_flagsmask |= DU_UALLEVENTS; else ustup->du_flagsmask |= DU_UDEFEVENTS; if (psy_cb->psy_ussecaudit & PSY_USAU_QRYTEXT) ustup->du_flagsmask |= DU_UQRYTEXT; else ustup->du_flagsmask |= DU_UNOQRYTEXT; } if (psy_cb->psy_usflag & PSY_USRDEFGRP) { MEcopy((PTR)&psy_cb->psy_usgroup, sizeof(ustup->du_group), (PTR)&ustup->du_group); ustup->du_flagsmask|= DU_UGROUP; } else { MEfill(sizeof(ustup->du_group), (u_char)' ', (PTR)&ustup->du_group); } encrypt = (STskipblank((char *)&psy_cb->psy_apass, (i4)sizeof(psy_cb->psy_apass)) != NULL); if (encrypt) { 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_nbr_union.scf_xpasskey = (PTR)&ustup->du_name; scf_cb.scf_ptr_union.scf_xpassword = (PTR)&ustup->du_pass; scf_cb.scf_len_union.scf_xpwdlen = sizeof(ustup->du_pass); } else STRUCT_ASSIGN_MACRO(psy_cb->psy_apass, ustup->du_pass); if (psy_cb->psy_usflag & PSY_USRPASS) { ustup->du_flagsmask|= DU_UPASS; if (psy_cb->psy_usflag & PSY_USREXTPASS) ustup->du_flagsmask |= DU_UEXTPASS; } else { MEfill(sizeof(ustup->du_pass), (u_char)' ', (PTR)&ustup->du_pass); } encrypt2 = (STskipblank((char *)&psy_cb->psy_bpass, (i4)sizeof(psy_cb->psy_bpass)) != NULL); if (encrypt2) { scf_cb2.scf_length = sizeof (SCF_CB); scf_cb2.scf_type = SCF_CB_TYPE; scf_cb2.scf_facility = DB_PSF_ID; scf_cb2.scf_session = sess_cb->pss_sessid; scf_cb2.scf_nbr_union.scf_xpasskey = (PTR)&ustup->du_name; scf_cb2.scf_ptr_union.scf_xpassword = (PTR)&ustup2->du_pass; scf_cb2.scf_len_union.scf_xpwdlen = sizeof(ustup2->du_pass); } else STRUCT_ASSIGN_MACRO(psy_cb->psy_bpass, ustup2->du_pass); if (psy_cb->psy_usflag & PSY_USROLDPASS) ustup->du_flagsmask|= DU_UOLDPASS; else { MEfill(sizeof(ustup2->du_pass), (u_char)' ', (PTR)&ustup2->du_pass); } status = E_DB_OK; for (psy_usr = (PSY_USR *) psy_cb->psy_usrq.q_next; psy_usr != (PSY_USR *) &psy_cb->psy_usrq; psy_usr = (PSY_USR *) psy_usr->queue.q_next ) { /* STRUCT_ASSIGN_MACRO(psy_usr->psy_usrnm, ustup->du_name); */ MEcopy((PTR)&psy_usr->psy_usrnm, sizeof(ustup->du_name), (PTR)&ustup->du_name); /* Encrypt the password if nonblank and not already hex value */ if (encrypt) { STRUCT_ASSIGN_MACRO(psy_cb->psy_apass, ustup->du_pass); if(!(psy_cb->psy_usflag & PSY_HEXPASS)) { status = scf_call(SCU_XENCODE, &scf_cb); if (status != E_DB_OK) { err_code = scf_cb.scf_error.err_code; (VOID) psf_error(E_PS0D43_XENCODE_ERROR, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); status = (status > E_DB_SEVERE) ? status : E_DB_SEVERE; return(status); } } } if (encrypt2) { STRUCT_ASSIGN_MACRO(psy_cb->psy_bpass, ustup2->du_pass); status = scf_call(SCU_XENCODE, &scf_cb2); if (status != E_DB_OK) { err_code = scf_cb2.scf_error.err_code; (VOID) psf_error(E_PS0D43_XENCODE_ERROR, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); status = (status > E_DB_SEVERE) ? status : E_DB_SEVERE; return(status); } } stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); status = (stat > status) ? stat : status; if (DB_FAILURE_MACRO(stat)) break; } if (DB_FAILURE_MACRO(status)) (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); return (status); }
/*{ ** Name: ops_deallocate - deallocate resources for an optimization ** ** Description: ** This routine will deallocate the resources used for an optimization. ** Resources include any memory requested from the optimizer memory pool ** and any RDF cache objects which were locked in the global range ** table ** ** Inputs: ** global ptr to global state variable ** report TRUE if errors should be reported ** via the user's control block. ** partial_dbp partial deallocation required for ** statement within a procedure ** ** Outputs: ** Returns: ** VOID ** Exceptions: ** none ** ** Side Effects: ** memory resources released, RDF unfixed, ** QSF query tree memory released ** ** History: ** 29-jun-86 (seputis) ** initial creation ** 8-nov-88 (seputis) ** if no query run trace point is set then destroy the QP since ** SCF assumes optimizer cleans up after error ** 8-nov-88 (seputis) ** turn off CPU accounting if was off originally ** 28-jan-91 (seputis) ** added support for OPF ACTIVE flag ** 20-jul-93 (ed) ** changed name ops_lock for solaris, due to OS conflict ** 29-jul-93 (andre) ** rdr_types_mask must be initialized (to RDR_RELATION) before ** calling RDF_UNFIX. Otherwise RDF may end up complaining because we ** ask it to destroy a relation cache entry while RDR_PROCEDURE bit is ** set. ** 12-aug-93 (swm) ** Cast first parameter of CSaltr_session() to CS_SID to match ** revised CL interface specification. ** 02-Jun-1997 (shero03) ** Update the saved rdf_info_block after calling RDF. ** 02-Aug-2001 (hanal04) Bug 105360 INGSRV 1505 ** Plug the RDF memory leak introduced by inkdo01's new ** function oph_temphist(). ** 17-Dec-2003 (jenjo02) ** Added (CS_SID)NULL to CScnd_signal prototype. ** 6-Feb-2006 (kschendel) ** Fix some squirrely looking code that purported to avoid dangling ** references, but didn't really. (No symptoms known.) ** 14-nov-2007 (dougi) ** Add support for cached dynamic query plans. ** 20-may-2008 (dougi) ** Add support for table procedures. ** 29-may-2009 (wanfr01) Bug 122125 ** Need to add dbid to cache_dynamic queries for db uniqueness */ VOID ops_deallocate( OPS_STATE *global, bool report, bool partial_dbp) { DB_STATUS finalstatus; /* this status is returned to the user ** - it will contain the first error ** during resource deallocation */ DB_ERROR error; /* error code from offending facility */ finalstatus = E_DB_OK; error.err_code = 0; { /* close any fixed RDF objects - deallocate prior to closing the ** global memory stream */ OPV_IGVARS gvar; /* index into global range variable ** table */ OPV_GRT *gbase; /* ptr to base of array of ptrs ** to global range table elements */ OPV_IGVARS maxgvar; /* number of global range table ** elements allocated */ RDF_CB *rdfcb; /* ptr to rdf control block used ** unfix the relation info */ OPV_GBMVARS *rdfmap; /* ptr to map of global range ** variables which have RDF info ** fixed */ gbase = global->ops_rangetab.opv_base; maxgvar = global->ops_rangetab.opv_gv; rdfcb = &global->ops_rangetab.opv_rdfcb; rdfmap = &global->ops_rangetab.opv_mrdf; /* ** rdr_types_mask needs to be initialized - since we will be unfixing ** relation entries, RDR_RELATION seems like a good choice, although 0 ** would suffice as well */ rdfcb->rdf_rb.rdr_types_mask = RDR_RELATION; if (global->ops_cstate.opc_relation) { /* OPC allocates a RDF descriptor for cursors so deallocate ** if this is the case */ DB_STATUS opcrdfstatus; /* RDF return status */ rdfcb->rdf_info_blk = global->ops_cstate.opc_relation; opcrdfstatus = rdf_call( RDF_UNFIX, (PTR)rdfcb ); if ( (DB_FAILURE_MACRO(opcrdfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = opcrdfstatus; error.err_code = rdfcb->rdf_error.err_code; } global->ops_cstate.opc_relation = NULL; } if (maxgvar) { for ( gvar = -1; (gvar = BTnext((i4)gvar, (char *)rdfmap, (i4)maxgvar)) >=0;) { OPV_GRV *gvarp; /* ptr to global range variable to ** be deallocated */ if ((gvarp = gbase->opv_grv[gvar]) /* NULL if not allocated */ && (gvarp->opv_relation) /* not NULL if RDF has been ** called for this range variable */ && !(gvarp->opv_gmask & OPV_TPROC) /* not table procedure */ ) { /* if this element has been allocated and if it has an RDF ** cache element associated with it */ DB_STATUS rdfstatus; /* RDF return status */ gbase->opv_grv[gvar] = NULL; /* so we do not try to deallocate ** twice in case of an error */ rdfcb->rdf_info_blk = gvarp->opv_relation; rdfstatus = rdf_call( RDF_UNFIX, (PTR)rdfcb ); if ( (DB_FAILURE_MACRO(rdfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = rdfstatus; error.err_code = rdfcb->rdf_error.err_code; } gvarp->opv_relation = NULL; } if ((gvarp) && (gvarp->opv_ttmodel)) { /* if this element has been allocated and if it has an RDF ** cache element associated with a persistent table ** which provides histogram models. */ DB_STATUS rdfstatus; /* RDF return status */ rdfcb->rdf_info_blk = gvarp->opv_ttmodel; gvarp->opv_ttmodel = NULL; rdfstatus = rdf_call( RDF_UNFIX, (PTR)rdfcb ); if ( (DB_FAILURE_MACRO(rdfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = rdfstatus; error.err_code = rdfcb->rdf_error.err_code; } } } global->ops_rangetab.opv_gv = 0; } } if (partial_dbp) return; /* only deallocate the global range table ** for DBP, and keep the memory streams ** until the end */ if (global->ops_estate.opn_statistics && global->ops_estate.opn_reset_statistics) { /* statistics CPU accounting was turned on, and needs to be reset */ STATUS cs_status; i4 turn_off; turn_off = FALSE; /* turn off accounting */ global->ops_estate.opn_statistics = FALSE; cs_status = CSaltr_session((CS_SID)0, CS_AS_CPUSTATS, (PTR)&turn_off); if (cs_status != OK) { finalstatus = E_DB_ERROR; error.err_code = cs_status; } } /* deallocate ULM memory stream */ if (global->ops_mstate.ops_streamid == NULL) /* non-zero if allocated */ { /* check if ULM stream does not exist then this deallocation has ** already occurred so just return */ return; } else { DB_STATUS ulm1status;/* ULM return status */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_streamid; /* ulm will NULL ops_streamid */ ulm1status = ulm_closestream( &global->ops_mstate.ops_ulmrcb ); if ( (DB_FAILURE_MACRO(ulm1status)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = ulm1status; error.err_code = global->ops_mstate.ops_ulmrcb.ulm_error.err_code; } } /* deallocate ULM temp buffer memory stream */ if ( global->ops_mstate.ops_tstreamid ) /* non-zero if allocated */ { DB_STATUS ulm2status; /* ULM return status */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_tstreamid; /* ulm will NULL ops_tstreamid */ ulm2status = ulm_closestream( &global->ops_mstate.ops_ulmrcb ); if ( (DB_FAILURE_MACRO(ulm2status)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = ulm2status; error.err_code = global->ops_mstate.ops_ulmrcb.ulm_error.err_code; } } /* deallocate OPC ULM buffer memory stream */ if ( global->ops_mstate.ops_sstreamid ) /* non-zero if allocated */ { DB_STATUS ulm3status; /* ULM return status */ global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_sstreamid; /* ulm will NULL ops_sstreamid */ ulm3status = ulm_closestream( &global->ops_mstate.ops_ulmrcb ); if ( (DB_FAILURE_MACRO(ulm3status)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = ulm3status; error.err_code = global->ops_mstate.ops_ulmrcb.ulm_error.err_code; } } if (!report #ifdef OPT_F032_NOEXECUTE || /* if trace flag is set then cleanup QSF memory since optimizer will ** generate an error to SCF and SCF assumes optimizer will cleanup */ (global->ops_cb->ops_check && (opt_strace( global->ops_cb, OPT_F032_NOEXECUTE) || opt_strace( global->ops_cb, OPT_F023_NOCOMP) ) ) #endif ) { /* an error or an asychronous abort has occurred so destroy the plan ** or shared plan , FIXME destroy the shared plan in the earlier ** exception handler */ DB_STATUS qsfqpstatus; /* QSF return status */ if(global->ops_qpinit) { /* deallocate QSF object for query plan if another error has occurred ** - in this case OPC has already created a new QP handle and has ** gotten a lock on it */ STRUCT_ASSIGN_MACRO(global->ops_caller_cb->opf_qep, global->ops_qsfcb.qsf_obj_id); /* get ** query plan id */ global->ops_qsfcb.qsf_lk_id = global->ops_qplk_id; /* get lock id for ** QSF */ qsfqpstatus = ops_qsfdestroy(global); /* destroy the query plan */ if ( (DB_FAILURE_MACRO(qsfqpstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = qsfqpstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } else { /* OPC has not been reached so need to check for shared query plan */ if (!global->ops_procedure) { /* get query tree if it has not already been retrieved */ qsfqpstatus = ops_gqtree(global); if ( (DB_FAILURE_MACRO(qsfqpstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = qsfqpstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } if (global->ops_qheader && (global->ops_qheader->pst_mask1 & PST_RPTQRY)) { /* shared query plan possible */ if (global->ops_procedure->pst_flags & PST_REPEAT_DYNAMIC) { char *p; global->ops_qsfcb.qsf_obj_id.qso_lname = sizeof(DB_CURSOR_ID) + sizeof(i4); MEfill(sizeof(global->ops_qsfcb.qsf_obj_id.qso_name), 0, global->ops_qsfcb.qsf_obj_id.qso_name); MEcopy((PTR)&global->ops_procedure-> pst_dbpid.db_cursor_id[0], sizeof (global->ops_procedure-> pst_dbpid.db_cursor_id[0]), (PTR)global->ops_qsfcb.qsf_obj_id.qso_name); p = (char *) global->ops_qsfcb.qsf_obj_id.qso_name + 2*sizeof(i4); MEcopy((PTR)"qp", sizeof("qp"), p); p = (char *) global->ops_qsfcb.qsf_obj_id.qso_name + sizeof(DB_CURSOR_ID); I4ASSIGN_MACRO(global->ops_caller_cb->opf_udbid, *(i4 *) p); } else /* must be proc or regular repeat query */ { global->ops_qsfcb.qsf_obj_id.qso_lname = sizeof (global->ops_procedure->pst_dbpid); MEcopy((PTR)&global->ops_procedure->pst_dbpid, sizeof (global->ops_procedure->pst_dbpid), (PTR)&global->ops_qsfcb.qsf_obj_id.qso_name[0]); } global->ops_qsfcb.qsf_obj_id.qso_type = QSO_QP_OBJ; global->ops_qsfcb.qsf_lk_state = QSO_SHLOCK; qsfqpstatus = qsf_call(QSO_GETHANDLE, &global->ops_qsfcb); if (DB_SUCCESS_MACRO(qsfqpstatus)) { qsfqpstatus = ops_qsfdestroy( global ); if ( (DB_FAILURE_MACRO(qsfqpstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = qsfqpstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } else if (global->ops_qsfcb.qsf_error.err_code != E_QS0019_UNKNOWN_OBJ) { /* if object is not found then this is not a shared query */ finalstatus = qsfqpstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } } } /* release QSF memory allocated to query tree, make sure that this ** is done after the QP has been processed since pst_rptqry is still ** needed for above block */ { DB_STATUS qsfstatus; /* QSF return status */ STRUCT_ASSIGN_MACRO(global->ops_caller_cb->opf_query_tree, global->ops_qsfcb.qsf_obj_id); /* get ** query tree id */ global->ops_qsfcb.qsf_lk_id = global->ops_lk_id; /* get lock id for ** QSF */ qsfstatus = ops_qsfdestroy( global ); if ( (DB_FAILURE_MACRO(qsfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) ) { finalstatus = qsfstatus; error.err_code = global->ops_qsfcb.qsf_error.err_code; } } /* signal that the session is exiting OPF and that another thread may enter */ if (global->ops_cb->ops_smask & OPS_MCONDITION) { DB_STATUS lockstatus; OPG_CB *servercb; servercb = global->ops_cb->ops_server; global->ops_cb->ops_smask &= (~OPS_MCONDITION); lockstatus = ops_exlock(global->ops_caller_cb, &servercb->opg_semaphore); /* check if server ** thread is available, obtain ** semaphore lock on critical variable */ servercb->opg_activeuser--; /* since exit is about to occur, and memory ** has already been deallocated, allow another ** user to enter OPF */ servercb->opg_waitinguser--; /* since exit is about to occur, and memory ** has already been deallocated, allow another ** user to enter OPF */ if (DB_FAILURE_MACRO(lockstatus) && (DB_SUCCESS_MACRO(finalstatus))) { finalstatus = lockstatus; error.err_code = global->ops_caller_cb->opf_errorblock.err_data; } else { if (servercb->opg_waitinguser > servercb->opg_activeuser) { STATUS csstatus; csstatus = CScnd_signal(&servercb->opg_condition, (CS_SID)NULL); /* signal only if some users are waiting */ if ((csstatus != OK) && (DB_SUCCESS_MACRO(finalstatus))) { finalstatus = E_DB_ERROR; error.err_code = csstatus; } } lockstatus = ops_unlock(global->ops_caller_cb, &servercb->opg_semaphore); /* check if server ** thread is available */ if (DB_FAILURE_MACRO(lockstatus) && (DB_SUCCESS_MACRO(finalstatus))) { finalstatus = lockstatus; error.err_code = global->ops_caller_cb->opf_errorblock.err_data; } } } if (DB_FAILURE_MACRO(finalstatus)) { if (report) opx_verror( finalstatus, E_OP0084_DEALLOCATION, error.err_code); /* report ** error and generate an exception */ else opx_rverror(global->ops_cb->ops_callercb, finalstatus, E_OP0084_DEALLOCATION, error.err_code); /* report error only but do not generate an ** exception */ } }
/*{ ** Name: psy_reregister - REREGISTER a STAR object. ** ** INTERNAL PSF call format: status = psy_reregister(&psy_cb, &sess_cb); ** ** EXTERNAL call format: status = psy_call(PSY_REREGISTER, &psy_cb, ** &sess_cb); ** ** Description: ** The psy_reregister function will call QEF to REREGISTER a STAR object. ** QED_DDL_INFO block has been already prepared, so there is very little to ** do here. ** ** Inputs: ** psy_cb ** .psy_dmucb ptr to QED_DDL_INFO ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** .err_code What the error was ** E_PS0000_OK Success ** E_PS0001_USER_ERROR User made a mistake ** E_PS0002_INTERNAL_ERROR Internal inconsistency in PSF ** E_PS0003_INTERRUPTED User interrupt ** E_PS0005_USER_MUST_ABORT User must abort xact ** E_PS0008_RETRY Query should be retried. ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s) ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** STAR object will be dropped and recreated with the SAME object id. ** RDF cache entry for this object will be destroyed. ** History: ** 04-apr-89 (andre) ** written ** 15-jun-92 (barbara) ** All psy functions called from psy_call pass the same parameters. ** Add session control block to fit in with this scheme. ** 03-aug-92 (barbara) ** Invalidate registered object from RDF cache. ** 07-dec-92 (andre) ** address of psy_dmucb (which is overloaded with the address of a ** QED_DDL_INFO) will be stored in QEU_CB.qeu_ddl_info instead ** of overloading qeu_qso. ** 10-aug-93 (andre) ** fixed the cause of a compiler warning */ DB_STATUS psy_reregister( PSY_CB *psy_cb, PSS_SESBLK *sess_cb, QEU_CB *qeu_cb) { char *ddb_obj_name; i4 err_code; RDF_CB rdf_cb; RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_STATUS status; qeu_cb->qeu_d_cb = (PTR) NULL; qeu_cb->qeu_ddl_info = psy_cb->psy_dmucb; qeu_cb->qeu_d_op = QED_RLINK; status = qef_call(QEU_DBU, ( PTR ) qeu_cb); if (DB_FAILURE_MACRO(status)) { switch (qeu_cb->error.err_code) { /* object unknown */ case E_QE0031_NONEXISTENT_TABLE: { ddb_obj_name = ((QED_DDL_INFO *) psy_cb->psy_dmucb)->qed_d1_obj_name; (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error,1, psf_trmwhite(sizeof(DD_OBJ_NAME), ddb_obj_name), ddb_obj_name); break; } /* interrupt */ case E_QE0022_QUERY_ABORTED: { (VOID) psf_error(E_PS0003_INTERRUPTED, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error,0); break; } /* should be retried */ case E_QE0023_INVALID_QUERY: { psy_cb->psy_error.err_code = E_PS0008_RETRY; break; } /* user has some other locks on the object */ case E_QE0051_TABLE_ACCESS_CONFLICT: { (VOID) psf_error(E_PS0D21_QEF_ERROR, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error,0); break; } /* resource related */ case E_QE000D_NO_MEMORY_LEFT: case E_QE000E_ACTIVE_COUNT_EXCEEDED: case E_QE000F_OUT_OF_OTHER_RESOURCES: case E_QE001E_NO_MEM: { (VOID) psf_error(E_PS0D23_QEF_ERROR, qeu_cb->error.err_code, PSF_USERERR, &err_code, &psy_cb->psy_error,0); break; } /* lock timer */ case E_QE0035_LOCK_RESOURCE_BUSY: case E_QE0036_LOCK_TIMER_EXPIRED: { (VOID) psf_error(4702L, qeu_cb->error.err_code, PSF_USERERR, &err_code, &psy_cb->psy_error,0); break; } /* resource quota */ case E_QE0052_RESOURCE_QUOTA_EXCEED: case E_QE0067_DB_OPEN_QUOTA_EXCEEDED: case E_QE0068_DB_QUOTA_EXCEEDED: case E_QE006B_SESSION_QUOTA_EXCEEDED: { (VOID) psf_error(4707L, qeu_cb->error.err_code, PSF_USERERR, &err_code, &psy_cb->psy_error,0); break; } /* log full */ case E_QE0024_TRANSACTION_ABORTED: { (VOID) psf_error(4706L, qeu_cb->error.err_code, PSF_USERERR, &err_code, &psy_cb->psy_error,0); break; } /* deadlock */ case E_QE002A_DEADLOCK: { (VOID) psf_error(4700L, qeu_cb->error.err_code, PSF_USERERR, &err_code, &psy_cb->psy_error,0); break; } /* lock quota */ case E_QE0034_LOCK_QUOTA_EXCEEDED: { (VOID) psf_error(4705L, qeu_cb->error.err_code, PSF_USERERR, &err_code, &psy_cb->psy_error,0); break; } /* inconsistent database */ case E_QE0099_DB_INCONSISTENT: { (VOID) psf_error(38L, qeu_cb->error.err_code, PSF_USERERR, &err_code, &psy_cb->psy_error,0); break; } case E_QE0025_USER_ERROR: { psy_cb->psy_error.err_code = E_PS0001_USER_ERROR; break; } default: { (VOID) psf_error(E_PS0D20_QEF_ERROR, qeu_cb->error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error,0); } } return (status); } /* Invalidate registered object from RDF cache */ { QED_DDL_INFO *ddl_info = (QED_DDL_INFO *)psy_cb->psy_dmucb; pst_rdfcb_init(&rdf_cb, sess_cb); STRUCT_ASSIGN_MACRO(ddl_info->qed_d7_obj_id, rdf_rb->rdr_tabid); status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } } return (status); }
/*{ ** 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); }
DB_STATUS psy_calarm( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; RDR_RB *rdf_rb = &rdf_cb.rdf_rb; i4 textlen; /* Length of query text */ QSF_RCB qsf_rb; DB_STATUS status, loc_status; i4 err_code; DB_SECALARM *alarm= &psy_cb->psy_tuple.psy_alarm; /* Fill in QSF request to lock text */ qsf_rb.qsf_type = QSFRB_CB; qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rb.qsf_length = sizeof(qsf_rb); qsf_rb.qsf_owner = (PTR)DB_PSF_ID; qsf_rb.qsf_sid = sess_cb->pss_sessid; /* Initialize RDF_CB */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_types_mask = RDR_SECALM; /* Alarm definition */ rdf_rb->rdr_update_op = RDR_APPEND; rdf_rb->rdr_qrytuple = (PTR)&psy_cb->psy_tuple.psy_alarm; /* Alarm tuple */ /* ** Get the query text from QSF. QSF has stored the text ** as a {nat, string} pair - maybe not be aligned. */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); status = qsf_call(QSO_INFO, &qsf_rb); if (status != E_DB_OK) { psf_error(E_PS0D19_QSF_INFO, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); goto cleanup; } MEcopy((PTR)qsf_rb.qsf_root, sizeof(i4), (PTR)&textlen); rdf_rb->rdr_l_querytext = textlen; rdf_rb->rdr_querytext = ((char *)qsf_rb.qsf_root) + sizeof(i4); rdf_rb->rdr_tabid.db_tab_base=alarm->dba_objid.db_tab_base; /* ** Check type of alarm, and handle accordingly. ** Main difference is where/how subjects are handled: ** - Named alarms have a single subject, which has already been ** resolved in psl. Alarms to public are handled here also ** - Anonymous alarms (old style) may have multiple subjects. These ** operate much like permits, and are split into several alarms, one ** for each subject. */ if(STskipblank((char*)&alarm->dba_alarmname, sizeof(alarm->dba_alarmname)) ==NULL && (alarm->dba_subjtype==DBGR_USER || alarm->dba_subjtype==DBGR_APLID || alarm->dba_subjtype==DBGR_GROUP) ) { PSY_USR *psy_usr; u_char *subj_name; i4 subj_name_len; u_char delim_subj_name[DB_MAX_DELIMID]; /* ** Anonymous alarms. ** We loop over each subject, updating the query text for ** each subject and creating the alarm. */ psy_usr = (PSY_USR *) psy_cb->psy_usrq.q_next; do { subj_name = (u_char *) &psy_usr->psy_usrnm; subj_name_len = (i4) psf_trmwhite(sizeof(psy_usr->psy_usrnm), (char *) subj_name); if (~psy_usr->psy_usr_flags & PSY_REGID_USRSPEC) { status = psl_norm_id_2_delim_id(&subj_name, &subj_name_len, delim_subj_name, &psy_cb->psy_error); if (DB_FAILURE_MACRO(status)) return status; } if (subj_name_len < DB_MAX_DELIMID) subj_name[ subj_name_len ] = EOS; STmove((char*)subj_name, ' ', DB_MAX_DELIMID, rdf_rb->rdr_querytext + psy_cb->psy_noncol_grantee_off); STmove((char*)subj_name, ' ', sizeof(alarm->dba_subjname), (char*)&alarm->dba_subjname); /* Reset alarm name in case filled in by RDF/QEF */ MEfill(sizeof(alarm->dba_alarmname), ' ', (PTR)&alarm->dba_alarmname); /* Create a new alarm in iisecalarm */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (status != E_DB_OK) { if ( rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); } else { _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } goto cleanup; } /* If RDF error */ /* Next subject */ psy_usr = (PSY_USR *) psy_usr->queue.q_next; } while (psy_usr != (PSY_USR *) &psy_cb->psy_usrq); } else { /* Named alarms */ /* Create a new alarm in iisecalarm */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (status != E_DB_OK) { if ( rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); } else { _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } goto cleanup; } /* If RDF error */ } cleanup: qsf_rb.qsf_lk_state = QSO_EXLOCK; /* Destroy query text - lock it first */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); loc_status = qsf_call(QSO_LOCK, &qsf_rb); if (loc_status != E_DB_OK) { psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (loc_status > status) status = loc_status; } loc_status = qsf_call(QSO_DESTROY, &qsf_rb); if (loc_status != E_DB_OK) { psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (loc_status > status) status = loc_status; } /* Invalidate tableinfo from RDF cache if table object */ if(psy_cb->psy_gtype==DBOB_TABLE) { pst_rdfcb_init(&rdf_cb, sess_cb); STRUCT_ASSIGN_MACRO(alarm->dba_objid, rdf_rb->rdr_tabid); loc_status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(loc_status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); if (loc_status > status) status = loc_status; } } return (status); } /* psy_calarm */
/*{ ** Name: psy_drop_synonym - Drop an IISYNONYM tuple. ** ** Description: ** Call RDF_UPDATE to delete a tuple from IISYNONYM. ** Inputs: ** psy_cb PSY control block. ** sess_cb PSF session control block. ** Outputs: ** Exceptions: ** none ** Returns: ** E_DB_OK synonym tuple has been deleted successfully; ** error status from RDF otherwise ** ** Side Effects: ** Modifies system catalogs. ** ** History: ** 19-apr-90 (andre) ** Created. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 03-aug-92 (barbara) ** Invalidate base table infoblk from RDF's cache. ** 10-aug-93 (andre) ** fixed causes of compiler warnings ** 13-sep-93 (andre) ** QEF will assume responsibility for altering timestamps of tables ** (or underlying tables of views) synonym(s) on which have been ** dropped. We will supply QEF with the id of the object on which ** the synonym was defined ** 22-oct-93 (andre) ** In the unlikely event that RDF's cache entry for the synonym named ** in the DROP SYNONYM statement is stale and the synonym no longer ** exists, RDF will return E_RD014A_NONEXISTENT_SYNONYM which we will ** translate into 2753L */ DB_STATUS psy_drop_synonym( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; RDF_CB rdf_inv_cb; DB_IISYNONYM syn_tuple; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_STATUS status; register i4 syn_count; i4 err_code; /* Initialize the RDF request block. */ pst_rdfcb_init(&rdf_cb, sess_cb); pst_rdfcb_init(&rdf_inv_cb, sess_cb); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner); rdf_rb->rdr_2types_mask = (RDF_TYPES) RDR2_SYNONYM; rdf_rb->rdr_update_op = RDR_DELETE; rdf_rb->rdr_qrytuple = (PTR) &syn_tuple; rdf_rb->rdr_tabid.db_tab_base = DM_B_SYNONYM_TAB_ID; rdf_rb->rdr_tabid.db_tab_index = DM_I_SYNONYM_TAB_ID; MEmove(sizeof(DB_OWN_NAME), (char *)&sess_cb->pss_user, ' ', sizeof(DB_SYNOWN), (char *)&syn_tuple.db_synowner); for (syn_count = 0; syn_count < psy_cb->psy_numtabs; syn_count++) { /* store synonym name in the tuple */ MEmove(sizeof(DB_TAB_NAME), (char *)(psy_cb->psy_tabname + syn_count), ' ', sizeof(DB_SYNNAME), (char *)&syn_tuple.db_synname); syn_tuple.db_syntab_id.db_tab_base = psy_cb->psy_tables[syn_count].db_tab_base; syn_tuple.db_syntab_id.db_tab_index = psy_cb->psy_tables[syn_count].db_tab_index; /* Drop a tuple from IISYNONYM */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0144_DROP_SYNONYM) { (VOID) psf_error(E_PS0456_DROP_SYN_ERROR, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(DB_SYNNAME), (char *) &syn_tuple.db_synname), &syn_tuple.db_synname); } else if (rdf_cb.rdf_error.err_code == E_RD014A_NONEXISTENT_SYNONYM) { /* ** looks like RDF cache entry was stale - tell user that ** synonym did not exist and proceed on to the next entry */ status = E_DB_OK; (VOID) psf_error(2753L, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 2, sizeof("DROP SYNONYM") - 1, "DROP SYNONYM", psf_trmwhite(sizeof(DB_SYNNAME), (char *) &syn_tuple.db_synname), &syn_tuple.db_synname); continue; } else { (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } break; } STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[syn_count], rdf_inv_cb.rdf_rb.rdr_tabid); status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); break; } } return (status); }
/*{ ** Name: opv_parser - init global range table element given parser varno ** ** Description: ** This routine will initialize the global range table element in OPF ** corresponding to the PSF range table element. ** ** Inputs: ** global ptr to global range table ** gvar element in parser range table ** which is referenced in query ** ** Outputs: ** global->ops_rangetab.opv_base[gvar] initialize corresponding element ** in optimizer range table ** Returns: ** VOID ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 2-jul-86 (seputis) ** initial creation ** 6-nov-88 (seputis) ** change RDF invalidation to include all indexes on base relation ** since this is only notification that OPF gets that its' time ** stamp is out of date ** 25-sep-89 (seputis) ** - made addition to timestamp check, to refresh if this is a ** multi-variable query and the tuple count is zero ** 9-nov-89 (seputis) ** - added OPA_NOVID initialization for b8160, and corrected ** sep 25 fix for timestamps ** 12-jan-90 (seputis) ** - detect table ID's which are the same for different range vars ** 26-feb-91 (seputis) ** - add improved diagnostics for b35862 ** 31-dec-91 (seputis) ** - flush cache entry if tuple count is zero and more than one ** range table entry, since aggregate queries and flattened queries ** are not getting handled. ** 12-feb-93 (jhahn) ** Added support for statement level rules. (FIPS) ** 12-apr-93 (ed) ** - fix bug 50673, relax range variable check for larger OPF table ** 7-dec-93 (ed) ** b56139 - add OPZ_TIDHISTO to mark tid attributes which ** need histograms,... needed since target list is traversed ** earlier than before ** 16-feb-95 (inkdo01) ** b66907 - check for explicit refs to inconsistent tabs/idxes ** 23-feb-95 (wolf) ** Recent addition of MEcopy call should have been accompanied by ** an include of me.h ** 10-aug-98 (stial01) ** opv_parser() Remove code to invalidate indexes. The invalidate ** table that follows will do the job. Invalidate indexes by table id ** can get E_OP008E_RDF_INVALIDATE, E_RD0045_ULH_ACCESS ** 31-oct-1998 (nanpr01) ** Reset the rdfcb->infoblk ptr before checking the error code. ** 18-june-99 (inkdo01) ** Init opv_ttmodel for temp table model histogram feature. ** 19-Jan-2000 (thaju02) ** relation descriptor may be out of date and contain a stale ** secondary index count, use rdfcb->rdf_info_block->rdr_no_index ** which reflects the number of index entries in the rdr_indx ** array. (b100060) ** 17-Jan-2004 (schka24) ** Rename RDR_BLD_KEY to RDR_BLD_PHYS. ** 3-Sep-2005 (schka24) ** Remove if-0'ed out section that included a ref to a member ** that is going away (opv_ghist). ** 17-Nov-2005 (schka24) ** Don't propagate RDF invalidates that we cause. Our RDF cache ** is out of date but that's not other servers' problem. ** 14-Mar-2007 (kschendel) SIR 122513 ** Light "partitioned" flag if partitioned table seen. ** 18-april-2008 (dougi) ** Add support for table procedures. ** 8-Jul-2010 (wanfr01) b123949 ** If rdf_gdesc failed with an error, don't use the column ** information - it may not be fully initialized. */ bool opv_parser( OPS_STATE *global, OPV_IGVARS gvar, OPS_SQTYPE sqtype, bool rdfinfo, bool psf_table, bool abort) { OPV_GRT *gbase; /* ptr to base of global range table */ # ifdef E_OP0387_VARNO if ((gvar < 0) || ((gvar >= PST_NUMVARS) && (gvar >= OPV_MAXVAR))) opx_error(E_OP0387_VARNO ); /* range var out of range - ** consistency check */ # endif gbase = global->ops_rangetab.opv_base; /* get base of global range table ** ptr to array of ptrs */ if ( !gbase->opv_grv[gvar] ) { /* if global range variable element has not been allocated */ OPV_GRV *grvp; /* ptr to new range var element */ if (global->ops_rangetab.opv_gv <= gvar) global->ops_rangetab.opv_gv = gvar+1; /* update the largest range ** table element assigned so far */ grvp = (OPV_GRV *) opu_memory(global, sizeof( OPV_GRV ) ); /* save ** and allocate ptr to global ** var */ /* Explicitly zero out the grv entry */ MEfill(sizeof(*grvp), (u_char)0, (PTR)grvp); grvp->opv_qrt = gvar; /* save index to ** parser range table element */ grvp->opv_created = sqtype; /* save global range table type */ grvp->opv_gvid = OPA_NOVID; /* if this base table was implicitly ** referenced then the view id of the ** explicitly reference view will be ** saved */ grvp->opv_siteid = OPD_NOSITE; /* initialize distributed site location */ grvp->opv_same = OPV_NOGVAR; /* used to map tables with similiar ** IDs */ grvp->opv_compare = OPV_NOGVAR; /* used to map tables with similiar ** IDs */ grvp->opv_ttmodel = NULL; /* RDR_INFO ptr for temp table model ** histograms */ gbase->opv_grv[gvar] = grvp; /* place into table */ /* get RDF information about the table */ if (rdfinfo) { RDF_CB *rdfcb; /* ptr to RDF control block which ** has proper db_id and sessionid ** info */ PST_RNGENTRY *rngentry; /* ptr to parse tree range entry */ DB_STATUS status; /* RDF return status */ i4 ituple; rdfcb = &global->ops_rangetab.opv_rdfcb; if (psf_table) { /* Snag table procedures and handle them elsewhere. */ if ((rngentry = global->ops_qheader->pst_rangetab[gvar]) ->pst_rgtype == PST_TPROC) { if (opv_tproc(global, gvar, grvp, rngentry) == E_DB_OK) return(FALSE); else return(TRUE); } STRUCT_ASSIGN_MACRO(global->ops_qheader->pst_rangetab[gvar]-> pst_rngvar, rdfcb->rdf_rb.rdr_tabid); /* need ** table id from parser's table */ #if 0 if ((BTnext((i4)-1, (char *)&rangep->pst_outer_rel, (i4)BITS_IN(rangep->pst_outer_rel)) >= 0) || (BTnext((i4)-1, (char *)&rangep->pst_inner_rel, (i4)BITS_IN(rangep->pst_outer_rel)) >= 0) ) grvp->opv_gmask |= OPV_GOJVAR; /* mark whether this ** variable is within the scope of an ** outer join */ /* OPV_GOJVAR is not reliably set since the subquery bitmap should be tested ** also for an aggregate temp, multi-to-one mappings may exist for global range ** variables */ #endif if (global->ops_qheader->pst_rangetab[gvar]-> pst_rgtype == PST_SETINPUT) grvp->opv_gmask |= OPV_SETINPUT; /* is this the set input ** parameter for a procedure */ rdfcb->rdf_rb.rdr_types_mask = RDR_RELATION | RDR_INDEXES | 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_KEY info. The ** attribute info does not need to ** requested if RDF is changed. ** - ask for indexes so that ** invalidating the cache can also ** invalidate any indexes in the ** cache */ /* When we're ready to enable column comparison stats, uncomment the following statement. ** rdfcb->rdf_rb.rdr_2types_mask = RDR2_COLCOMPARE; /* column ** comparison stats, too */ } rdfcb->rdf_info_blk = NULL; /* get new ptr to info ** associated with global var */ status = rdf_call( RDF_GETDESC, (PTR)rdfcb); grvp->opv_relation = rdfcb->rdf_info_blk; /* save ptr to ** new info block */ if ((status != E_RD0000_OK) && (rdfcb->rdf_error.err_code != E_RD026A_OBJ_INDEXCOUNT) /* this ** is a check for distributed ** index information, which could ** be inconsistent but should not ** cause the query to be aborted ** it will cause indexes to be ** avoided */ ) { gbase->opv_grv[gvar] = NULL; if (abort) opx_verror( status, E_OP0004_RDF_GETDESC, rdfcb->rdf_error.err_code); else { return (TRUE); /* indicate failure to get RDF ** descriptor */ } } BTset( (i4)gvar, (char *)&global->ops_rangetab.opv_mrdf); /* indicate ** that RDF information is fixed */ /* Check table and all associated indexes to see if there is a ** statement level index associated with this variable */ if (grvp->opv_relation->rdr_rel->tbl_2_status_mask & DMT_STATEMENT_LEVEL_UNIQUE) grvp->opv_gmask |= OPV_STATEMENT_LEVEL_UNIQUE; for( ituple = grvp->opv_relation->rdr_no_index; ituple-- ;) { if (grvp->opv_relation->rdr_indx[ituple]->idx_status & DMT_I_STATEMENT_LEVEL_UNIQUE) grvp->opv_gmask |= OPV_STATEMENT_LEVEL_UNIQUE; } if (psf_table) { /* check if timestamp matches and invalidate RDF cache ** date of last modify do not match, this is only done ** for tables passed by PSF, the other tables should ** be dependent on the PSF time stamp */ DB_TAB_TIMESTAMP *timeptr; /* ptr to last modify ** date that RDF has cached */ DB_TAB_TIMESTAMP *psftimeptr; /* ptr to last modify ** date which parser used for the ** table */ psftimeptr = &global->ops_qheader->pst_rangetab[gvar]-> pst_timestamp; timeptr = &grvp->opv_relation->rdr_rel->tbl_date_modified; if (timeptr->db_tab_high_time != psftimeptr->db_tab_high_time || timeptr->db_tab_low_time != psftimeptr->db_tab_low_time || ( !grvp->opv_relation->rdr_rel->tbl_record_count && (global->ops_qheader->pst_rngvar_count > 1) ) /* special zero tuple count ** case check to see if tuple count ** is way off, i.e. a table create ** followed by a number of appends ** will cause a 0 tuple count, check ** for more than one variable since ** refresh is only useful when joins occur */ ) { PTR save_fcb = rdfcb->rdf_rb.rdr_fcb; /* Don't propagate this invalidate to other DBMS servers. ** There's no reason to think that they are as out of ** date as we are. (plus this might be a session temp ** which is strictly local!) */ rdfcb->rdf_rb.rdr_fcb = NULL; status = rdf_call( RDF_INVALIDATE, (PTR)rdfcb); rdfcb->rdf_rb.rdr_fcb = save_fcb; # ifdef E_OP008E_RDF_INVALIDATE if (status != E_RD0000_OK) opx_verror( E_DB_ERROR, E_OP008E_RDF_INVALIDATE, rdfcb->rdf_error.err_code); # endif status = rdf_call( RDF_GETDESC, (PTR)rdfcb); grvp->opv_relation = rdfcb->rdf_info_blk; /* save ptr to ** new info block */ if (status != E_RD0000_OK) { gbase->opv_grv[gvar] = NULL; opx_verror( E_DB_ERROR, E_OP0004_RDF_GETDESC, rdfcb->rdf_error.err_code); } timeptr = &grvp->opv_relation->rdr_rel->tbl_date_modified; if (timeptr->db_tab_high_time != psftimeptr->db_tab_high_time || timeptr->db_tab_low_time != psftimeptr->db_tab_low_time ) opx_vrecover( E_DB_ERROR, E_OP008F_RDF_MISMATCH, rdfcb->rdf_error.err_code); /* PSF timestamp is ** still out of date, so tell ** SCF to reparse the query */ } { /* search thru existing tables to discover if any ** tables have the same table ID */ OPV_IGVARS gvno; DB_TAB_ID *tabidp; OPV_IGVARS target_vno; tabidp = &global->ops_qheader->pst_rangetab[gvar]->pst_rngvar; target_vno = OPV_NOGVAR; for (gvno = 0; gvno < OPV_MAXVAR; gvno++) { OPV_GRV *grv1p; grv1p = gbase->opv_grv[gvno]; if (grv1p && grv1p->opv_relation) { DB_TAB_ID *gtabidp; if (gvno == gvar) continue; gtabidp = &grv1p->opv_relation->rdr_rel->tbl_id; if ((tabidp->db_tab_base == gtabidp->db_tab_base) && (tabidp->db_tab_index == gtabidp->db_tab_index) ) { /* found 2 table ID's which are identical */ global->ops_gmask |= OPS_IDSAME; if (target_vno == OPV_NOGVAR) { /* map all table id's vars to the lowest ** global range number of the group */ if (gvno > gvar) target_vno = gvar; else target_vno = gvno; } grv1p->opv_same = target_vno; grvp->opv_same = target_vno; if (target_vno != gvar) break; } } } } } if (global->ops_cb->ops_smask & OPS_MDISTRIBUTED) opd_addsite(global, grvp); /* add site information if a ** distributed thread */ /* Check for partitioned table, turns on additional ** analysis after enumeration. */ if (grvp->opv_relation != NULL && grvp->opv_relation->rdr_parts != NULL) global->ops_gmask |= OPS_PARTITION; if (grvp->opv_relation && grvp->opv_relation->rdr_rel-> tbl_2_status_mask & DMT_INCONSIST) /* check for inconsistent table ** (due to partial back/recov) */ { OPT_NAME tabname; i2 i; MEcopy(&grvp->opv_relation->rdr_rel->tbl_name, sizeof(grvp->opv_relation->rdr_rel->tbl_name), &tabname); /* table name is msg token */ for (i = sizeof(grvp->opv_relation->rdr_rel->tbl_name); i > 1 && tabname.buf[i-1] == ' '; i--); tabname.buf[i] = 0; /* lop blanks off name */ opx_1perror(E_OP009A_INCONSISTENT_TAB,(PTR)&tabname); } } else grvp->opv_relation = NULL; /* set to NULL if not used */ } return(FALSE); }
/*{ ** Name: psy_dbpriv - GRANT/REVOKE database privileges ** ** INTERNAL PSF call format: status = psy_dbpriv(&psy_cb, sess_cb); ** EXTERNAL call format: status = psy_call (PSY_DBPRIV,&psy_cb, sess_cb); ** ** Description: ** This procedure is sued to grant and revoke database privileges. ** A template iidbpriv tuple is built and shipped to RDF. ** Eventually, the tuple is added/merged into iidbpriv. ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_usrq list of grantees ** .psy_tblq list of objects ** .psy_gtype grantee type ** .psy_grant statement type (GRANT or REVOKE) ** .psy_fl_dbpriv control flags ** .psy_qdio_limit query I/O limit ** .psy_qrow_limit query row limit ** .psy_qcpu_limit query CPU limit ** .psy_qpage_limit query page limit ** .psy_qcost_limit query cost limit ** .psy_idle_limit idle time limit ** .psy_connect_limit connect time limit ** .psy_priority_limit priority limit ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s); ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_SEVERE Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** None. ** ** History: ** 10-apr-89 (ralph) ** written ** 06-jun-89 (ralph) ** corrected unix portability problems ** 24-jun-89 (ralph) ** corrected internal error message ** 06-sep-89 (ralph) ** added support for GRANT/REVOKE ON ALL DATABASES ** removed DBGR_DEFAULT ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 19-jul-92 (andre) ** changes were made to enable a user to specify privileges to PUBLIC ** along with one or more user authorization identifiers ** 10-aug-93 (andre) ** fixed cause of a compiler warning */ DB_STATUS psy_dbpriv( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status = E_DB_OK; DB_STATUS stat; i4 err_code; RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_PRIVILEGES dbprtuple; register DB_PRIVILEGES *dbprtup = &dbprtuple; PSY_USR *psy_usr; PSY_TBL *psy_tbl; bool grant_to_public; bool leave_loop = TRUE; /* This code is called for SQL only */ do { /* Fill in the RDF request block */ pst_rdfcb_init(&rdf_cb, sess_cb); if (psy_cb->psy_grant == PSY_DGRANT) rdf_rb->rdr_update_op = RDR_APPEND; else if (psy_cb->psy_grant == PSY_DREVOKE) rdf_rb->rdr_update_op = RDR_DELETE; else { /* Invalid operation specified in psy_grant */ err_code = E_PS0D45_INVALID_GRANT_OP; (VOID) psf_error(E_PS0D45_INVALID_GRANT_OP, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); status = E_DB_ERROR; break; } rdf_rb->rdr_status = DB_SQL; rdf_rb->rdr_types_mask = RDR_DBPRIV; rdf_rb->rdr_qrytuple = (PTR) dbprtup; rdf_rb->rdr_qtuple_count = 1; /* Initialize the template iidbpriv tuple */ dbprtup->dbpr_gtype = psy_cb->psy_gtype; dbprtup->dbpr_control = psy_cb->psy_ctl_dbpriv; dbprtup->dbpr_dbflags = 0; dbprtup->dbpr_flags = psy_cb->psy_fl_dbpriv; dbprtup->dbpr_qrow_limit = psy_cb->psy_qrow_limit; dbprtup->dbpr_qdio_limit = psy_cb->psy_qdio_limit; dbprtup->dbpr_qcpu_limit = psy_cb->psy_qcpu_limit; dbprtup->dbpr_qpage_limit = psy_cb->psy_qpage_limit; dbprtup->dbpr_qcost_limit = psy_cb->psy_qcost_limit; dbprtup->dbpr_connect_time_limit = psy_cb->psy_connect_limit; dbprtup->dbpr_idle_time_limit = psy_cb->psy_idle_limit; dbprtup->dbpr_priority_limit = psy_cb->psy_priority_limit; MEfill(sizeof(dbprtup->dbpr_database), (u_char) ' ', (PTR) &dbprtup->dbpr_database); MEfill(sizeof(dbprtup->dbpr_reserve), (u_char) ' ', (PTR) dbprtup->dbpr_reserve); /* Point to first database object, if any */ psy_tbl = (PSY_TBL *)psy_cb->psy_tblq.q_next; /* No database objects means GRANT/REVOKE ON ALL DATABASES */ if (psy_tbl == (PSY_TBL *) &psy_cb->psy_tblq) dbprtup->dbpr_dbflags |= DBPR_ALLDBS; /* ** Pass the template tuples to RDF for each database/grantee. ** RDF/QEF will return E_DB_INFO if a database/grantee is rejected, ** or E_DB_WARN is a database is rejected. Anything worse than ** E_DB_WARN is a fatal error. */ /* Process each database/grantee */ for (;;) { /* ** Copy in database name if one was provided. ** None will be provided if ON ALL DATABASES was specified. */ if (psy_tbl != (PSY_TBL *) &psy_cb->psy_tblq) MEcopy((PTR)&psy_tbl->psy_tabnm, sizeof(dbprtup->dbpr_database), (PTR)&dbprtup->dbpr_database); grant_to_public = (psy_cb->psy_flags & PSY_PUBLIC) != 0; psy_usr = (PSY_USR *) psy_cb->psy_usrq.q_next; do { if (grant_to_public) { /* ** user specified TO/FROM PUBLIC, possibly along with other ** user auth ids; we will process TO/FROM PUBLIC first */ dbprtup->dbpr_gtype = DBGR_PUBLIC; MEmove(sizeof("public") - 1, (PTR) "public", ' ', sizeof(dbprtup->dbpr_gname), (PTR) &dbprtup->dbpr_gname); } else { STRUCT_ASSIGN_MACRO(psy_usr->psy_usrnm, dbprtup->dbpr_gname); } stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); status = (stat > status) ? stat : status; if (stat > E_DB_INFO) break; if (grant_to_public) { dbprtup->dbpr_gtype = psy_cb->psy_gtype; /* ** remember that we have processed GRANT TO PUBLIC on this ** database or on the installation */ grant_to_public = FALSE; } else { psy_usr = (PSY_USR *) psy_usr->queue.q_next; } } while (psy_usr != (PSY_USR *) &psy_cb->psy_usrq); /* Break out if failure */ if (DB_FAILURE_MACRO(status)) break; /* Point to next database object */ psy_tbl = (PSY_TBL *) psy_tbl->queue.q_next; /* Break out if no more objects */ if (psy_tbl == (PSY_TBL *) &psy_cb->psy_tblq) break; } /* We are done */ /* leave_loop has already been set to TRUE */ } while (!leave_loop); if (DB_FAILURE_MACRO(status)) (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); return (status); }
/*{ ** Name: psy_kuser - Destroy profile ** ** Description: ** This procedure deletes a profile. If the ** profile does not exist, the statement is aborted. ** If the user does exist, the associated ** iiprofile tuple is deleted. ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_usrq user list ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_INFO Function completed with warning(s). ** E_DB_WARN One ore more roles were rejected. ** E_DB_ERROR Function failed; non-catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Removed tuples from iiuser. ** ** History: ** 27-aug-93 (robf) ** written */ static DB_STATUS psy_kprofile( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status, stat; RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DU_PROFILE protuple; register DU_PROFILE *protup = &protuple; PSY_USR *psy_usr; FUNC_EXTERN DB_STATUS rdf_call(); /* This code is called for SQL only */ /* ** Fill in the part of RDF request block that will be constant. */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_update_op = RDR_DELETE; rdf_rb->rdr_status = DB_SQL; rdf_rb->rdr_2types_mask = RDR2_PROFILE; rdf_rb->rdr_qrytuple = (PTR) protup; rdf_rb->rdr_qtuple_count = 1; protup->du_status = 0; protup->du_flagsmask = 0; /* ** Pass on RESTRICT/CASCADE processsing. RESTRICT is the default, */ if (psy_cb->psy_usflag & PSY_USRCASCADE) protup->du_flagsmask|= DU_UCASCADE; MEfill(sizeof(protup->du_group), (u_char)' ', (PTR)&protup->du_group); status = E_DB_OK; for (psy_usr = (PSY_USR *) psy_cb->psy_usrq.q_next; psy_usr != (PSY_USR *) &psy_cb->psy_usrq; psy_usr = (PSY_USR *) psy_usr->queue.q_next ) { /* STRUCT_ASSIGN_MACRO(psy_usr->psy_usrnm, protup->du_name); */ MEcopy((PTR)&psy_usr->psy_usrnm, sizeof(protup->du_name), (PTR)&protup->du_name); stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); status = (stat > status) ? stat : status; if (DB_FAILURE_MACRO(stat)) break; } if (DB_FAILURE_MACRO(status)) (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); return (status); }
/*{ ** Name: psy_integ - Apply integrity constraints ** ** Description: ** This function applies integrity constraints. It gets the constraints ** from RDF and puts them in the query where appropriate. ** ** Inputs: ** mstream QSF memory stream to allocate from ** root Root of query tree to constrain ** rngtab Pointer to the range table ** resvar Pointer to the result range variable ** qmode Query mode of user's query ** sess_cb session control block ** result Place to put pointer to constrained tree ** err_blk Filled in if an error happens ** ** Outputs: ** root Integrity constraints may be appended ** result Filled in with pointer to constrained ** tree ** err_blk Filled in if an error happened ** Returns: ** E_DB_OK Success ** E_DB_ERROR Failure ** Exceptions: ** none ** ** Side Effects: ** Allocates memory ** ** History: ** 19-jun-86 (jeff) ** Adapted from integrity.c in 4.0. ** 02-sep-86 (seputis) ** changes for new RDF interface ** fixed bug for no integrity case ** 04-dec-86 (daved) ** process define and replace cursor. Use copy of saved qual for ** replace cursor. ** 03-dec-87 (stec) ** Change psy_apql interface. ** 11-may-88 (stec) ** Make changes for db procs. ** 06-feb-89 (ralph) ** Modified to use DB_COL_WORDS*2 as extent of dset array ** 23-Feb-89 (andre) ** Changed the way the tree consisting of qualifications obtained from ** the integrity trees is constructed and merged with the ** qualifications found in the original tree. ** 18-may-89 (neil) ** Use session memory for cursors with integrities (bug fix). ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 04-sep-90 (andre) ** fixed bug 32976: for OPEN CURSOR (qmode==PSQ_DEFCURS) we need to ** compare attribute number(s) found in the integrity ** tuple with attribute number found in the VAR ** node(s) found in the portion of the target list ** which was built to represent the FOR UPDATE list ** (such node(s) are right children of RESDOM nodes ** with pst_rsupdt set to TRUE; note that for ** RESDOM nodes built to represent the real target ** list of SELECT, this field is set to FALSE.) ** 29-sep-92 (andre) ** RDF may choose to allocate a new info block and return its address ** in rdf_info_blk - we need to copy it over to pss_rdrinfo to avoid ** memory leak and other assorted unpleasantries ** 05-dec-92 (rblumer) ** ignore FIPS constraints during INGRES integrity processing ** 10-jan-93 (andre) ** after calling rdf_call() for IIINTEGRITY tuples, compare status to ** E_DB_OK instead of using DB_FAILURE_MACRO() since if there are fewer ** than 20 rows, rdf_call() sets err_code to E_RD0011 and status to ** E_DB_WARN ** 10-Feb-93 (Teresa) ** Changed RDF_GETINFO to RDF_READTUPLES for new RDF I/F ** 23-May-1997 (shero03) ** Save the rdr_info_blk after an UNFIX ** 22-Jul-2004 (schka24) ** Delete old ifdef'ed out normalization call ** 28-nov-2007 (dougi) ** Add PSQ_REPDYN to PSQ_DEFCURS test (cached dynamic). */ DB_STATUS psy_integ( PSF_MSTREAM *mstream, PST_QNODE *root, PSS_USRRANGE *rngtab, PSS_RNGTAB *resvar, i4 qmode, PSS_SESBLK *sess_cb, PST_QNODE **result, DB_ERROR *err_blk) { register PST_QNODE *r; PSC_CURBLK *curblk = sess_cb->pss_crsr; CS_SID sessid = sess_cb->pss_sessid; PTR db_id = sess_cb->pss_dbid; i2 dset[DB_COL_WORDS*2]; i2 doms; i2 *domset; bool subset; PST_QNODE *p; register i4 i; PST_QNODE *iqual; PST_QNODE **tmp1; DB_INTEGRITY *inttup; i4 err_code; PST_QTREE *qtree; PST_PROCEDURE *pnode; DB_STATUS status = E_DB_OK; i4 found; RDF_CB rdf_cb; QEF_DATA *qp; RDF_CB rdf_tree_cb; PSS_DUPRB dup_rb; i4 tupcount; i4 map[PST_NUMVARS]; /* Map for reassigning varnos */ r = root; /* Initialize fields in dup_rb */ dup_rb.pss_op_mask = 0; dup_rb.pss_num_joins = PST_NOJOIN; dup_rb.pss_tree_info = (i4 *) NULL; dup_rb.pss_mstream = mstream; dup_rb.pss_err_blk = err_blk; if (qmode == PSQ_REPCURS) { if (!curblk->psc_integ) { *result = r; return (E_DB_OK); } /* ** On a replace cursor, get the query tree that was stored in the ** cursor control block. */ /* copy the qual fragment so we can change below. */ dup_rb.pss_tree = curblk->psc_integ; dup_rb.pss_dup = &iqual; status = pst_treedup(sess_cb, &dup_rb); if (DB_FAILURE_MACRO(status)) { return (status); } } else { /* ** Check to see if we should apply the integrity ** algorithm. ** ** This means checking to insure that we have an update ** and seeing if any integrity constraints apply. */ if ( resvar == 0 || (resvar->pss_tabdesc->tbl_status_mask & DMT_INTEGRITIES) == 0 ) { *result = r; return (E_DB_OK); } /* ** Create a set of the domains updated in this query. */ for (i = 0; i < DB_COL_WORDS*2; i++) dset[i] = 0; for (p = r->pst_left, doms = 0; p != (PST_QNODE *) NULL && p->pst_sym.pst_type != PST_TREE; p = p->pst_left) { if (p->pst_sym.pst_type != PST_RESDOM) { psf_error(E_PS0D0C_NOT_RESDOM, 0L, PSF_INTERR, &err_code, err_blk, 0); return (E_DB_SEVERE); } /* ** if we are defining a cursor, RESDOM numbers are meaningless as ** at best they reflect position of an attribute in the target list ** of a subselect or, at worst, they are set to 1 for all columns ** mentioned in the FOR UPDATE LIST. We really are interested only ** in the VAR nodes which are children of RESDOM nodes built to ** repersent columns appearing in the FOR UPDATE list, so we will ** skip over RESDOM nodes which represent a true subselect ** (i.e. pst_rsupdt == FALSE) */ if (qmode == PSQ_DEFCURS) { if (p->pst_sym.pst_value.pst_s_rsdm.pst_rsupdt) { PST_QNODE *r_child = p->pst_right; /* ** this RESDOM was built to represent the column in the FOR ** UPDATE list */ /* ** make sure the right child is a VAR node; otherwise flag ** an error */ if (r_child == (PST_QNODE *) NULL || r_child->pst_sym.pst_type != PST_VAR) { psf_error(E_PS0C04_BAD_TREE, 0L, PSF_INTERR, &err_code, err_blk, 0); return (E_DB_SEVERE); } BTset((i4) r_child-> pst_sym.pst_value.pst_s_var.pst_atno.db_att_id, (char *) dset); ++doms; } } else { BTset((i4) p->pst_sym.pst_value.pst_s_rsdm.pst_rsno, (char *) dset); ++doms; } } /* ** Note if we are appending a subset of the relation's domains. ** If we are, we'll need to be extra careful to avoid violating ** constraints on those attributes not being explicitly appended: */ subset = ((doms < resvar->pss_tabdesc->tbl_attr_count) && (qmode == PSQ_APPEND)); /* ** Scan integrity catalog for possible tuples. If found, ** include them in the integrity qualification. */ iqual = (PST_QNODE *) NULL; /* Set up constant part of rdf query tree control block */ pst_rdfcb_init(&rdf_tree_cb, sess_cb); STRUCT_ASSIGN_MACRO(resvar->pss_tabid, rdf_tree_cb.rdf_rb.rdr_tabid); rdf_tree_cb.rdf_rb.rdr_types_mask = RDR_INTEGRITIES | RDR_QTREE; rdf_tree_cb.rdf_rb.rdr_qtuple_count = 1; /* Get 1 integ tree at a time */ rdf_tree_cb.rdf_info_blk = resvar->pss_rdrinfo; /* Get all integrity tuples */ pst_rdfcb_init(&rdf_cb, sess_cb); STRUCT_ASSIGN_MACRO(resvar->pss_tabid, rdf_cb.rdf_rb.rdr_tabid); rdf_cb.rdf_rb.rdr_types_mask = RDR_INTEGRITIES; rdf_cb.rdf_rb.rdr_update_op = RDR_OPEN; rdf_cb.rdf_rb.rdr_rec_access_id = NULL; rdf_cb.rdf_rb.rdr_qtuple_count = 20; /* Get 20 integrities at a time */ rdf_cb.rdf_info_blk = resvar->pss_rdrinfo; /* For each group of 20 integrities */ while (rdf_cb.rdf_error.err_code == 0) { status = rdf_call(RDF_READTUPLES, (PTR) &rdf_cb); /* ** RDF may choose to allocate a new info block and return its address ** in rdf_info_blk - we need to copy it over to pss_rdrinfo to avoid ** memory leak and other assorted unpleasantries */ if (rdf_cb.rdf_info_blk != resvar->pss_rdrinfo) { resvar->pss_rdrinfo = rdf_tree_cb.rdf_info_blk = rdf_cb.rdf_info_blk; } /* ** Must not use DB_FAILURE_MACRO because E_RD0011 returns E_DB_WARN ** that would be missed. */ if (status != E_DB_OK) { if ( rdf_cb.rdf_error.err_code == E_RD0011_NO_MORE_ROWS || rdf_cb.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND) { status = E_DB_OK; if (rdf_cb.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND) continue; } else if (rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { (VOID) psf_error(2117L, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &resvar->pss_tabname), &resvar->pss_tabname); status = E_DB_ERROR; goto exit; } else { (VOID) psf_rdf_error(RDF_READTUPLES, &rdf_cb.rdf_error, err_blk); goto exit; } } rdf_cb.rdf_rb.rdr_update_op = RDR_GETNEXT; /* FOR EACH INTEGRITY */ for ( qp = rdf_cb.rdf_info_blk->rdr_ituples->qrym_data, tupcount = 0; tupcount < rdf_cb.rdf_info_blk->rdr_ituples->qrym_cnt; qp = qp->dt_next, tupcount++ ) { inttup = (DB_INTEGRITY*) qp->dt_data; /* ** Ignore FIPS constraints (i.e. SQL92 constraints) ** (they are implemented via rules instead) */ if (inttup->dbi_consflags != 0) { continue; } /* check for some domain set overlap */ domset = (i2*) inttup->dbi_columns.db_domset; for (i = 0; i < DB_COL_WORDS*2; i++) { if ((dset[i] & domset[i]) != 0) break; } /* ** Check for appends where defaults don't satisfy integrity. */ if ((i >= DB_COL_WORDS*2) && !subset) { continue; } /* Get integrity tree and make qtree point to it */ STRUCT_ASSIGN_MACRO(inttup->dbi_tree, rdf_tree_cb.rdf_rb.rdr_tree_id); rdf_tree_cb.rdf_rb.rdr_qrymod_id = inttup->dbi_number; rdf_tree_cb.rdf_rb.rdr_update_op = 0; rdf_tree_cb.rdf_rb.rdr_rec_access_id = NULL; rdf_tree_cb.rdf_info_blk = resvar->pss_rdrinfo; rdf_tree_cb.rdf_rb.rdr_integrity = NULL; STRUCT_ASSIGN_MACRO(inttup->dbi_tabid, rdf_tree_cb.rdf_rb.rdr_tabid); rdf_tree_cb.rdf_rb.rdr_sequence = inttup->dbi_number; status = rdf_call(RDF_GETINFO, (PTR) &rdf_tree_cb); /* ** RDF may choose to allocate a new info block and return its ** address in rdf_info_blk - we need to copy it over to pss_rdrinfo ** to avoid memory leak and other assorted unpleasantries */ if (rdf_tree_cb.rdf_info_blk != resvar->pss_rdrinfo) { resvar->pss_rdrinfo = rdf_cb.rdf_info_blk = rdf_tree_cb.rdf_info_blk; } if (DB_FAILURE_MACRO(status)) { if (rdf_tree_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &resvar->pss_tabname), &resvar->pss_tabname); } else { (VOID) psf_rdf_error(RDF_GETINFO, &rdf_tree_cb.rdf_error, err_blk); } goto exit; } pnode = (PST_PROCEDURE *) rdf_tree_cb.rdf_rb.rdr_integrity->qry_root_node; qtree = pnode->pst_stmts->pst_specific.pst_tree; /* trim off (null) target list */ p = qtree->pst_qtree->pst_right; /* use a copy of the qtree because the qtree is in RDF memory */ dup_rb.pss_tree = qtree->pst_qtree->pst_right; dup_rb.pss_dup = &p; status = pst_treedup(sess_cb, &dup_rb); { /* unfix the query tree no matter what the above status is */ DB_STATUS temp_status; temp_status = rdf_call(RDF_UNFIX, (PTR) &rdf_tree_cb); resvar->pss_rdrinfo = rdf_cb.rdf_info_blk = rdf_tree_cb.rdf_info_blk; if (DB_FAILURE_MACRO(temp_status)) { (VOID) psf_rdf_error(RDF_UNFIX, &rdf_tree_cb.rdf_error, err_blk); status = temp_status; } } if (DB_FAILURE_MACRO(status)) goto exit; /* close integrity file */ /* ** Make the result variable for the integrity the same as the result ** variable for the user query. ** I AM NOT SURE THE FOLLOWING COMMENT APPLIES SO I AM MERGING ** THE RANGE VAR FOR APPENDS. ** This is not done for append because ** append doesn't have a result range variable. */ for (i = 0; i < PST_NUMVARS; i++) map[i] = i; i = inttup->dbi_resvar; map[i] = resvar->pss_rgno; status = psy_mapvars(p, map, err_blk); if (DB_FAILURE_MACRO(status)) goto exit; /* add to integrity qual */ if (iqual == NULL) { status = pst_node(sess_cb, mstream, p, (PST_QNODE *) NULL, PST_AND, (PTR) NULL, sizeof(PST_OP_NODE), DB_NODT, (i2) 0, (i4) 0, (DB_ANYTYPE *) NULL, &iqual, err_blk, (i4) 0); if (DB_FAILURE_MACRO(status)) goto exit; /* close integrity file */ /* ** Note that tmp1 will contain address of the pst_right ptr ** of the bottom AND node in the tree constructed from the ** qualifications found in the integrities */ tmp1 = &iqual->pst_right; } else { PST_QNODE *newnode; status = pst_node(sess_cb, mstream, p, iqual, PST_AND, (PTR) NULL, sizeof(PST_OP_NODE), DB_NODT, (i2) 0, (i4) 0, (DB_ANYTYPE *) NULL, &newnode, err_blk, (i4) 0); if (DB_FAILURE_MACRO(status)) goto exit; /* close integrity file */ iqual = newnode; } } } if (rdf_cb.rdf_rb.rdr_rec_access_id != NULL) { DB_STATUS temp_status; /* unfix integrity tuples */ rdf_cb.rdf_rb.rdr_update_op = RDR_CLOSE; temp_status = rdf_call(RDF_READTUPLES, (PTR) &rdf_cb); resvar->pss_rdrinfo = rdf_tree_cb.rdf_info_blk = rdf_cb.rdf_info_blk; if (DB_FAILURE_MACRO(temp_status)) { (VOID) psf_rdf_error(RDF_READTUPLES, &rdf_cb.rdf_error, err_blk); status = temp_status; } } } if (qmode == PSQ_DEFCURS || qmode == PSQ_REPDYN) { /* ** On a "define cursor", keep a copy of the integrity qualification ** for later use. */ if (iqual == NULL) { curblk->psc_integ = (PST_QNODE *) NULL; } else { status = pst_trdup(curblk->psc_stream, iqual, &curblk->psc_integ, &sess_cb->pss_memleft, err_blk); if (DB_FAILURE_MACRO(status)) { return (status); } } } else { /* ** Clean up the integrity qualification so that it will merge ** nicely into the tree, and then append it to the user's ** qualification. */ if (iqual != NULL) { /* replace VAR nodes by corresponding user afcn from user's ** query. For example, if the integ says r.a > 1 and the user's ** query says resdom 4 = 4 + 3, the integ is modified to 4 + 3 > 1. ** ** The following paragraph refers to the case where an integrity ** refers to a variable not updated in the target list. ** ** If there is no resdom for r.a, if the user didn't specify r.a ** in the target list of the query, and the query is an append, ** r.a > 1 is replaced with 'default val for col a' > 1. If the ** query is a replace statement, we do nothing because r.a will ** be retrieved but is not in the targ list. We will be verifying ** what we know should already hold (ie the integrity constraint). ** If we have replace cursor, we wan't to replace r.a with a value ** so a retrieve can be avoided on the replace command. We can't ** have col a = 5 where r.a > 1. We do, however, have the value r.a ** in the row to be updated. QEF has this value. We replace r.a with ** a curval node that refers to the value r.a. */ /* will pass dup_rb, but first null out pss_tree and pss_dup */ dup_rb.pss_tree = (PST_QNODE *) NULL; dup_rb.pss_dup = (PST_QNODE **) NULL; status = psy_subsvars(sess_cb, &iqual, resvar, r->pst_left, qmode, (PST_QNODE *) NULL, resvar, (i4) 0, qmode, &curblk->psc_blkid, &found, &dup_rb); if (DB_FAILURE_MACRO(status)) { return (status); } /* ** for REPLACE CURSOR, we need to traverse down the pst_right's ** until we encounter NULL in place of which we will append the ** qualification from the ROOT ** Note that iqual is guaranteed to be an AND node with BOP for a ** left child and either AND or NULL for the right child. */ if (qmode == PSQ_REPCURS) { for (tmp1 = &iqual->pst_right; (*tmp1) != (PST_QNODE *) NULL; tmp1 = &(*tmp1)->pst_right) ; } /* ** append qualification from the tree to the integrities and ** make the result the new qualification for the tree */ (*tmp1) = r->pst_right; r->pst_right = iqual; } } exit: if ((qmode != PSQ_REPCURS) && (rdf_cb.rdf_rb.rdr_rec_access_id != NULL)) { DB_STATUS temp_status; /* unfix integrity tuples */ rdf_cb.rdf_rb.rdr_update_op = RDR_CLOSE; temp_status = rdf_call(RDF_READTUPLES, (PTR) &rdf_cb); resvar->pss_rdrinfo = rdf_tree_cb.rdf_info_blk = rdf_cb.rdf_info_blk; if (DB_FAILURE_MACRO(temp_status)) { (VOID) psf_rdf_error(RDF_READTUPLES, &rdf_cb.rdf_error, err_blk); status = temp_status; } } if (status == E_DB_OK) { *result = r; } return (status); }
/*{ ** 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); }
/*{ ** 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 */
DB_STATUS psy_kalarm( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; RDR_RB *rdf_rb = &rdf_cb.rdf_rb; RDF_CB rdf_inv_cb; DB_STATUS status; DB_SECALARM *atuple= &psy_cb->psy_tuple.psy_alarm; i4 i; PSY_OBJ *psy_obj; bool loop=FALSE; /* Fill in the RDF request blocks */ pst_rdfcb_init(&rdf_cb, sess_cb); rdf_rb->rdr_types_mask = RDR_SECALM; /* Alarm deletion */ rdf_rb->rdr_update_op = RDR_DELETE; rdf_rb->rdr_qrytuple = (PTR)atuple;/* Alarm tuple */ pst_rdfcb_init(&rdf_inv_cb, sess_cb); rdf_inv_cb.rdf_rb.rdr_types_mask |= RDR_SECALM; do { /* ** Loop through each alarm in turn deleting them. ** User may have specified alarms by name or by number, or by all */ if (psy_cb->psy_numnms == 0 && (PSY_OBJ*)psy_cb->psy_objq.q_next == (PSY_OBJ*)&psy_cb->psy_objq) { /* ** Drop all alarms on the indicated object */ rdf_rb->rdr_types_mask |= RDR_DROP_ALL; STmove(ERx("all alarms"),' ', sizeof(atuple->dba_alarmname), (char*)&atuple->dba_alarmname); status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); /* Destroy alarm */ if (status != E_DB_OK) { _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } } if(psy_cb->psy_numnms) { /* ** Dropping alarms by number, so walk through all numbers dropping. */ for (i=0;i <psy_cb->psy_numnms; i++) { char tmpstr[64]; CVla((i4)psy_cb->psy_numbs[i],tmpstr); STmove(tmpstr,' ', sizeof(atuple->dba_alarmname), (char*)&atuple->dba_alarmname); atuple->dba_alarmno=psy_cb->psy_numbs[i]; status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (status != E_DB_OK) { _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); break; } } } if((PSY_OBJ*)psy_cb->psy_objq.q_next!= (PSY_OBJ*)&psy_cb->psy_objq) { /* ** Dropping alarms by name, so walk through all names dropping */ for (psy_obj = (PSY_OBJ *) psy_cb->psy_objq.q_next; psy_obj != (PSY_OBJ *) &psy_cb->psy_objq; psy_obj = (PSY_OBJ *) psy_obj->queue.q_next ) { MEcopy((PTR)&psy_obj->psy_objnm, sizeof(atuple->dba_alarmname), (PTR)&atuple->dba_alarmname); atuple->dba_alarmno=0; status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);/* Destroy alarm */ if (status != E_DB_OK) { _VOID_ psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); break; } } } } while(loop); if(status==E_DB_OK && atuple->dba_objtype==DBOB_TABLE) { /* ** Invalidate table infoblk from RDF cache. */ STRUCT_ASSIGN_MACRO(atuple->dba_objid, rdf_inv_cb.rdf_rb.rdr_tabid); 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); } } return (status); } /* psy_kalarm */