/*{ ** 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); }
/* 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); }
/*{ ** Name: psq_str_dmp - Dump a name ** ** Description: ** This function dumps a string for debugging purposes. Non-zero length ** implies that the string may have some trailing blanks which will be ** eliminated before pritning; otherwise it is assumed to be ** NULL-terminated. ** ** Inputs: ** str string to print ** len length; if non-zero, trailing blanks, if ** any will be eliminated; otherwise, it ** will be assumed to be NULL-terminated ** ** Outputs: ** None ** ** Returns: ** E_DB_OK Success ** E_DB_ERROR Non-catastrophic failure ** E_DB_FATAL Catastrophic failure ** ** Exceptions: ** none ** ** Side Effects: ** Sends output to terminal and/or log file. ** ** History: ** 26-nov-91 (andre) ** written */ DB_STATUS psq_str_dmp( u_char *str, i4 len) { STATUS status; if (len > 0) { status = TRdisplay("%.#s", (i4) psf_trmwhite(len, (char *) str), str); } else if (len == 0) { status = TRdisplay("%s", str); } else { return(E_DB_ERROR); } return((status == TR_OK) ? E_DB_OK : E_DB_ERROR); }
/*{ ** Name: psy_qrymod - Process views, permits, and integrities ** ** Description: ** This function applies the qrymod algorithm to user queries. ** This algorithm is well-described in the specific functions ** psyview.c, psyinteg.c, and psypermit.c. It MUST be applied ** in the order: views, integrities, permits. This is because ** permits are on base tables, not on views, and we don't want ** the extra qualifications stuck on by the permit process to ** affect the integrities. ** ** Rules modifications are applied after all other query mods. ** Rules processing (in psyrules.c) may add statement trees to rule lists ** maintained in sess_cb. ** ** Inputs: ** qtree The query tree to modify ** sess_cb Current session control block ** psq_cb Calling control block ** num_joins ptr to a var containing number of joins ** in the query tree ** ** Outputs: ** qtree Can be modified by views, permits, ** and integrities ** sess_cb All kinds of miscellaneous stuff ** that is too detailed to describe here ** psq_cb ** .err_blk Filled in if an error happens ** ** *num_joins Will be incremented if any of the views ** involved in the query or any permits ** applied use joins. ** ** *resp_mask if the qmode==PSQ_VIEW will contain ** indicators of whether the view appears ** to be updateable and/or grantable view ** ** Returns: ** E_DB_OK Success ** E_DB_FATAL Failure ** Exceptions: ** none ** ** Side Effects: ** Can allocate memory ** Catalog I/O ** ** History: ** 09-jul-86 (jeff) ** Adapted from 4.0 qrymod() function ** 02-sep-86 (seputis) ** used result relation from auxiliary table since RDF ptrs are NULLed ** 18-sep-86 (daved) ** the result relation in the session cb is not always the ** same as the one found in the user range table. this is because ** the one in the range table is accurate only in an append statement. ** thus, we will now change the session cb to point to the correct ** result relation. ** 2-apr-87 (daved) ** set a pss_permit flag in the range table for each used entry. ** psy_permit will clear this flag. Psy_view will set this flag ** in all range entries that a derived from a table that still has ** this flag set, else it will clear this flag for new entries. ** We will then call psy_permit again, to catch all the new entries. ** 24-sep-87 (stec) ** Change error handling - call psf_error. ** 25-oct-87 (stec) ** Remove transaction creation, this is now done by SCF. ** 26-jan-89 (neil) ** Now also calls psy_rules to fill in rule tree. ** 08-mar-89 (neil) ** Calls psy_rules with more arguments. ** 22-jun-89 (andre) ** remove call to psy_protect() before call to psy_view() since ** psy_view() was modified to call psy_protect() before performing ** query modification on SQL views not belonging to the user. ** Additionally, &qtree will not be passed to psy_view(), since there ** is no apparent reason to do so (we no longer attempt to assign to ** the corresponding argument inside of psy_view() ) ** 24-jul-89 (jennifer) ** For each statement, indicate that audit information is NULL. ** 08-sep-89 (andre) ** recieve and pass to psy_view() and psy_permit() ptr to a var ** containing number of joins in the query tree. ** 19-sep-90 (andre) ** as a result of changes in psy_view(), we no longer need to call ** psy_permit() from psy_qrymod(). ** 13-dec-90 (ralph) ** Move reset of pss_audit to before psy_view invocation (b34903) ** 11-mar-91 (andre) ** if qmode is PSQ_VIEW, pass PSQ_RETRIEVE to psy_view(), psy_integ(), ** and psy_rules() + do not try to copy pss_usrrange to pss_auxrng ** since psy_dview() already placed the range table entries into ** pss_auxrng. ** (this is a part of fix for bug 33038) ** 07-aug-91 (andre) ** if qmode is PSQ_VIEW do NOT translate it to PSQ_RETRIEVE + ** if qmode is PSQ_VIEW do not bother calling psy_integ() and ** psy_rules() ** ** Added resp_mask to the argument list. This mask will be used to ** communicate info to the caller of psy_qrymod(). psy_qrymod() itself ** will not contribute anything to the information, instead, it will ** pass it to other functions (initially only to psy_view()) which will ** be responsible for providing the actual information. ** 30-dec-92 (andre) ** when processing a view tree in the course of processing CREATE RULE ** on a view we do NOT want to do any permit, rule, or integrity ** checking ** 04-jan-93 (andre) ** if we are processing DELETE, INSERT, or UPDATE, and a table or a ** view being updated has rules defined on it, set PSS_CHECK_RULES in ** sess_cb->pss_resrng->pss_var_mask to remind psy_view() to call ** psy_rules() ** ** since psy_dview() is going away, and psl_cview() calls psy_qrymod() ** with range variables as they were entered in the grammar, we must ** copy the range table from pss_usrrange to pss_auxrng for define VIEW ** just as we do for all other QUEL statements ** ** In most cases psy_rules() will NO LONGER be called from ** psy_qrymod(). It will be called from psy_view() when processing ** INSERT, DELETE, or UPDATE. This change was necessary because now ** rules can be defined on views, and it seemed reasonable that rule ** checking (just like privilege checking) can be driven from ** psy_view(). The once exception occurs when we are processing UPDATE ** WHERE CURRENT OF - psy_view() will simply return when presented with ** this query mode, but there may be rules that apply to this ** statement. Consequently, psy_rules() will be called from ** psy_qrymod() only when psq_qmode == PSQ_REPCURS ** 08-jan-93 (rblumer) ** set flag to bypass permission checking for dummy set-input ** range variables. ** 30-mar-93 (rblumer) ** set check_perms to false for system-generated procedures ** and for (internal) queries with PSS_NO_CHECKPERMS set. ** 01-apr-93 (andre) ** (fix for bugs 50823, 50825, and 50899) ** do not copy QUEL range table to aux. range table when processing ** REPLACE CURSOR - the entry describing the table/view over ** which the cursor has been defined has already been placed into ** pss_auxrng ** 08-apr-93 (andre) ** do not call psy_rules() explicitly for PSQ_REPCURS. psy_view() will ** now handle PSQ_REPCURS and call psy_rules() when necessary. ** 09-apr-93 (andre) ** set PSS_CHECK_RULES in the pss_var_mask corresponding to the ** table/view being updated via a cursor ** 26-apr-93 (markg) ** If the server is running C2 then initialize each range ** entry to show that it needs to be audited. ** 5-jul-93 (robf) ** If server is C2 then initialize any result range table to show ** it needs to be audited. ** 14-sep-93 (robf) ** Add QUERY_SYSCAT check, disallowing direct querying of ** base catalogs without privilege. This is done here rather than ** lower down in view/permit processing since we want to allow ** access to views on base catalogs (e.g. standard catalogs) ** to go ahead. ** 13-oct-93 (robf) ** Add <st.h> ** 25-oct-93 (stephenb) ** If the server is running C2 then also initialize the result range ** entry to show that it needs to be audited. ** 13-dec-93 (robf) ** When checking for query_syscat privilege, allow for extended ** catalogs. Some catalogs (like iistar_cdbs) have both the ** DMT_CATALOG and DMT_EXTENDED_CAT bits set. In this case we allow ** access since this priv restricts base catalogs only. ** 09-feb-94 (andre) ** fix for bug 59595: ** we also need to forego checking permits if we are parsing a ** system-generated query ** 11-jul-94 (robf) ** Restrict direct queries to table extensions the same way ** as system catalogs, i.e. to those with SELECT_SYSCAT privilege. ** The rationale for this is that info in extensions is really ** part of the base table, and to present an appropriately ** protected view of the data access should be through the base ** table, not directly at the extension. */ DB_STATUS psy_qrymod( PST_QNODE *qtree, PSS_SESBLK *sess_cb, PSQ_CB *psq_cb, PST_J_ID *num_joins, i4 *resp_mask) { PSS_RNGTAB *resrng; PSS_USRRANGE *rngtab = &sess_cb->pss_auxrng; PSF_MSTREAM *mstream = &sess_cb->pss_ostream; DB_ERROR *err_blk = &psq_cb->psq_error; i4 qmode = psq_cb->psq_mode; DB_STATUS status; i4 i; i4 check_perms = TRUE; GLOBALREF PSF_SERVBLK *Psf_srvblk; i4 err_code; bool can_query_syscat=FALSE; *resp_mask = 0L; /* init the response mask */ /* ** avoid permit checking when processing RULE trees, ** or when parsing/reparsing a system-generated procedure, ** or when parsing a system-generated query (e.g. a query to check whether ** constraints hold on existing data) */ if ((psq_cb->psq_mode == PSQ_RULE) || ( (sess_cb->pss_dbp_flags & PSS_DBPROC) && (sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED)) || (psq_cb->psq_flag & PSQ_NO_CHECK_PERMS) || ( (psq_cb->psq_info != (PST_INFO *) NULL) && (psq_cb->psq_info->pst_execflags & PST_SYSTEM_GENERATED)) ) { check_perms = FALSE; } /* ** Can user directly query system catalogs ? ** Users with databse privilege QUERY_SYSCAT, or users with ** SECURITY subject privilege may directly query system cats */ if(psy_ckdbpr(psq_cb, DBPR_QUERY_SYSCAT)==E_DB_OK) can_query_syscat=TRUE; else if(sess_cb->pss_ustat&DU_USECURITY) can_query_syscat=TRUE; else can_query_syscat=FALSE; /* ** Reset pss_audit prior to calling psy_view. */ sess_cb->pss_audit = NULL; /* ** We don't want to clobber the user's view of the range table in ** the process of doing qrymod. Therefore, we will copy the user's ** range table to the auxiliary range table, and use that instead. */ /* don't need to copy range table for SQL because there are no range ** table entries that live longer than one statement ** ** REPLACE CURSOR places description of the table/view over which it is ** defined into pss_auxrng */ if ( sess_cb->pss_lang == DB_QUEL && qmode != PSQ_REPCURS) { status = pst_rgcopy(&sess_cb->pss_usrrange, rngtab, &sess_cb->pss_resrng, err_blk); if (DB_FAILURE_MACRO(status)) return (status); } for (i = 0; i < PST_NUMVARS; i++) { rngtab->pss_rngtab[i].pss_rgparent = -1; /* don't want to check permissions on ** set-input temporary tables */ if (rngtab->pss_rngtab[i].pss_rgtype == PST_SETINPUT) rngtab->pss_rngtab[i].pss_permit = FALSE; else rngtab->pss_rngtab[i].pss_permit = check_perms; /* ** See if this is a real base catalog. ** We special case iidbcapabilities since its marked as a base ** catalog, but gets directly queried (and needs to be ** accessed by frontends) */ if(rngtab->pss_rngtab[i].pss_used && rngtab->pss_rngtab[i].pss_rgno != -1 && rngtab->pss_rngtab[i].pss_tabdesc && (( (rngtab->pss_rngtab[i].pss_tabdesc->tbl_2_status_mask&DMT_TEXTENSION) ) || ( (rngtab->pss_rngtab[i].pss_tabdesc->tbl_status_mask&DMT_CATALOG) && !(rngtab->pss_rngtab[i].pss_tabdesc->tbl_status_mask&DMT_VIEW) && !(rngtab->pss_rngtab[i].pss_tabdesc->tbl_status_mask&DMT_EXTENDED_CAT) && STncasecmp((char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name, "iidbcapabilities", GL_MAXNAME)!=0 )) ) { /* ** This is a base catalog. */ if(!can_query_syscat) { /* ** Error, user can't query base catalogs. */ if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) (VOID)psy_secaudit( FALSE, sess_cb, (char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name, &rngtab->pss_rngtab[i].pss_tabdesc->tbl_owner, DB_MAXNAME, SXF_E_SECURITY, I_SX273B_QUERY_SYSCAT, (SXF_A_SELECT|SXF_A_FAIL), err_blk); (VOID) psf_error(E_PS035A_CANT_QUERY_SYSCAT, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(DB_NAME), (char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name), (char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name); return E_DB_ERROR; } } /* ** If this is a C2 server set the PSS_DOAUDIT flag ** for this entry. */ if (Psf_srvblk->psf_capabilities & PSF_C_C2SECURE) rngtab->pss_rngtab[i].pss_var_mask |= PSS_DOAUDIT; } if (resrng = sess_cb->pss_resrng) { /* don't want to check permissions ** on set-input temporary tables */ if (rngtab->pss_rngtab[i].pss_rgtype == PST_SETINPUT) rngtab->pss_rngtab[i].pss_permit = FALSE; else rngtab->pss_rngtab[i].pss_permit = check_perms; /* ** if processing DELETE, UPDATE, INSERT, or UPDATE/REPLACE cursor, and ** there are rules defined on the view/table being updated, set ** PSS_CHECK_RULES in pss_var_mask */ if ( ( qmode == PSQ_APPEND || qmode == PSQ_DELETE || qmode == PSQ_REPLACE || qmode == PSQ_REPCURS ) && resrng->pss_tabdesc->tbl_status_mask & DMT_RULE ) { resrng->pss_var_mask |= PSS_CHECK_RULES; } /* ** If this is a C2 server set the PSS_DOAUDIT flag ** for the result table. */ if (Psf_srvblk->psf_capabilities & PSF_C_C2SECURE) rngtab->pss_rsrng.pss_var_mask |= PSS_DOAUDIT; } /* Apply view processing */ status = psy_view(mstream, qtree, rngtab, qmode, sess_cb, err_blk, num_joins, resp_mask); if (DB_FAILURE_MACRO(status)) { return (status); } /* ** do not check for existing INTEGRITIES when processing trees as a ** part of CREATE/DEFINE VIEW or CREATE RULE processing */ if (qmode != PSQ_VIEW && qmode != PSQ_RULE) { /* Apply integrity processing */ status = psy_integ(mstream, qtree, rngtab, resrng, qmode, sess_cb, &qtree, err_blk); if (DB_FAILURE_MACRO(status)) { return (status); } } return (status); }
/*{ ** Name: PSQ_TCNVT - convert db_data_value to text form ** ** Description: ** This routine takes any user supplied db_data_value and converts ** it to the value's textual representation. This is required for the ** iiqrytext catalog. It is assumed that all datavalues can be written ** into a character representation. ** ** Inputs: ** sess_cb session control block ** .pss_adfcb adf session control block for output ** arguments. ** header Pointer to chain header ** dbval db_data_value ** result Place to put pointer to new piece ** err_blk Filled in if an error happens ** ** Outputs: ** result Filled in with pointer to chain element ** err_blk Filled in if an error happens ** Returns: ** E_DB_OK Success ** E_DB_ERROR Non-catastrophic failure ** E_DB_FATAL Catastrophic failure ** Exceptions: ** none ** ** Side Effects: ** Allocates memory ** ** History: ** 29-jun-87 (daved) ** written ** 28-jan-91 (andre) ** fix bug 35446: size of a new piece should include quotes, if they ** were added. ** 18-nov-91 (rog) ** Fixed bug 40869, et alia: the above fix missed adding the quotes ** to the total size and not just the piece size. ** 23-Sep-2009 (kiria01) b122578 ** Initialise the ADF_FN_BLK .adf_fi_desc and adf_dv_n members. ** 19-Aug-2010 (kschendel) b124282 ** Make sure fi-desc is always set to something. */ DB_STATUS psq_tcnvt( PSS_SESBLK *sess_cb, PTR header, DB_DATA_VALUE *dbval, PTR *result, DB_ERROR *err_blk) { PSQ_THEAD *hp; PSQ_TEXT *tp; i4 err_code; DB_STATUS status; ADF_CB *adf_cb; ADF_FN_BLK adffn; i4 dv_size; i4 count; char *cptr; char *quote_char; DB_TEXT_STRING *string; ADI_DT_NAME dt_fname; ADI_DT_NAME dt_tname; char f4_style; char f8_style; i4 f4_width; i4 f8_width; i4 f4_prec; i4 f8_prec; i4 totype; i4 is_string; hp = (PSQ_THEAD *) header; adf_cb = (ADF_CB *) sess_cb->pss_adfcb; status = E_DB_OK; totype = (DB_DT_ID) DB_LTXT_TYPE; adffn.adf_r_dv.db_datatype = totype; if (dbval->db_datatype == totype) dv_size = dbval->db_length; else dv_size = 0; /* JRBCMT -- PSF is not allowed to know this!! First of all, date is */ /* missing from the list below and decimal will soon need to be on it. */ /* But also, we need to fix this code so that it doesn't make */ /* assumptions about what types exist. I think the proper approach is */ /* to quote all non-intrinsic types, but this should be investigated. */ /* are we dealing with a string type (incoming). */ if (abs(dbval->db_datatype) == DB_INT_TYPE || abs(dbval->db_datatype) == DB_FLT_TYPE || abs(dbval->db_datatype) == DB_MNY_TYPE || abs(dbval->db_datatype) == DB_BOO_TYPE) { is_string = FALSE; quote_char = (char *) NULL; } else { is_string = TRUE; quote_char = (sess_cb->pss_lang == DB_SQL) ? "\'" : "\""; } /* set the floating point conversion display */ f4_style = adf_cb->adf_outarg.ad_f4style; f8_style = adf_cb->adf_outarg.ad_f8style; f4_width = adf_cb->adf_outarg.ad_f4width; f8_width = adf_cb->adf_outarg.ad_f8width; f4_prec = adf_cb->adf_outarg.ad_f4prec; f8_prec = adf_cb->adf_outarg.ad_f8prec; adf_cb->adf_outarg.ad_f4style = 'n'; adf_cb->adf_outarg.ad_f8style = 'n'; adf_cb->adf_outarg.ad_f4width = 20; adf_cb->adf_outarg.ad_f8width = 20; adf_cb->adf_outarg.ad_f4prec = 10; adf_cb->adf_outarg.ad_f8prec = 10; /* get the function instance id for this conversion */ status = adi_ficoerce(adf_cb, dbval->db_datatype, totype, &adffn.adf_fi_id); if (status != E_DB_OK) { goto exit; } /* determine the result size. */ status = adi_fidesc(adf_cb, adffn.adf_fi_id, &adffn.adf_fi_desc); if (status != E_DB_OK) { goto exit; } if (!dv_size) { /* Now lets fill in the datatype length info and allocate space for the ** data. */ status = adi_0calclen(adf_cb, &adffn.adf_fi_desc->adi_lenspec, 1, &dbval, &adffn.adf_r_dv); dv_size = adffn.adf_r_dv.db_length; if (status != E_DB_OK) { goto exit; } } /* if string, add room for quotes */ if (is_string) dv_size += 2 * CMbytecnt(quote_char); /* Allocate enough space for PSQ_TEXT structure containing piece */ hp->psq_tmem.ulm_psize = dv_size + sizeof(PSQ_TEXT) - 1; status = ulm_palloc(&hp->psq_tmem); if (status != E_DB_OK) { if (hp->psq_tmem.ulm_error.err_code == E_UL0005_NOMEM) { psf_error(E_PS0F02_MEMORY_FULL, 0L, PSF_CALLERR, &err_code, err_blk, 0); } else (VOID) psf_error(E_PS0371_ALLOC_TEXT_CHAIN, hp->psq_tmem.ulm_error.err_code, PSF_INTERR, &err_code, err_blk, 0); return (status); } *result = hp->psq_tmem.ulm_pptr; tp = (PSQ_TEXT*) *result; string = (DB_TEXT_STRING*) tp->psq_tval; /* Fill in text piece */ adffn.adf_r_dv.db_length = dv_size; adffn.adf_r_dv.db_data = (PTR) string; adffn.adf_dv_n = 1; STRUCT_ASSIGN_MACRO(*dbval, adffn.adf_1_dv); adffn.adf_pat_flags = AD_PAT_DOESNT_APPLY; if ((status = adf_func(adf_cb, &adffn)) != E_DB_OK) { goto exit; } /* CAUTION: entering tricky code. ** string is a variable containing a text datatype. We want to convert ** to a C datatype. We also want to add quote characters if the datatype ** was a string type. We grab the count from the string variable first. ** we can then use the 2 byte count for character data. */ count = string->db_t_count; cptr = (char *) string; if (is_string) { /* ** for strings, copy the opening quote (" or ', depending on language) */ CMcpychar(quote_char, cptr); cptr += CMbytecnt(quote_char); } MEcopy((PTR) string->db_t_text, count, (PTR) cptr); cptr += count; if (is_string) { /* ** for strings, copy the closing quote (" or ', depending on language) */ CMcpychar(quote_char, cptr); } /* if storing a string, do not forget to account for quotes (bug 35446) */ tp->psq_psize = (is_string) ? count + 2 * CMbytecnt(quote_char) : count; /* Hook it up to the chain */ tp->psq_next = (PSQ_TEXT *) NULL; if (hp->psq_last != (PSQ_TEXT *) NULL) { hp->psq_last->psq_next = tp; tp->psq_prev = hp->psq_last; } else { tp->psq_prev = NULL; } hp->psq_last = tp; if (hp->psq_first == (PSQ_TEXT *) NULL) hp->psq_first = tp; /* Add in the length to the total for the chain */ hp->psq_tsize += tp->psq_psize; exit: /* set the floating point conversion display */ adf_cb->adf_outarg.ad_f4style = f4_style; adf_cb->adf_outarg.ad_f8style = f8_style; adf_cb->adf_outarg.ad_f4width = f4_width; adf_cb->adf_outarg.ad_f8width = f8_width; adf_cb->adf_outarg.ad_f4prec = f4_prec; adf_cb->adf_outarg.ad_f8prec = f8_prec; if (status != E_DB_OK) { (VOID) adi_tyname(adf_cb, dbval->db_datatype, &dt_fname); (VOID) adi_tyname(adf_cb, totype, &dt_tname); (VOID) psf_error(2911L, 0L, PSF_USERERR, &err_code, err_blk, 3, sizeof (sess_cb->pss_lineno), &sess_cb->pss_lineno, psf_trmwhite(sizeof(dt_fname), (char *) &dt_fname), &dt_fname, psf_trmwhite(sizeof (dt_tname), (char *) &dt_tname), &dt_tname); return (E_DB_ERROR); } return (status); }
/* ** Name: psq_store_text - store query text in a contiguous block of QSF memory ** ** Description: ** Copy contents of a query text chain (prepended, if necessary with RANGE ** statements) into a contiguous block of QSF memory. Caller may specify ** that the text be stored in DB_TEXT_STRING format by setting ** return_db_text_string to TRUE; otherwise the function will return a i4 ** followed by query text. ** ** Input: ** rngtab if non-NULL, range statements will be ** generated for all entries of the range table ** that are active (pss_used && pss_rgno >= 0); ** should be non-NULL only for QUEL queries ** header Pointer to chain header ** mstream Pointer to opened memory stream ** return_db_text_string if TRUE, function will store text in ** DB_TEXT_STRING format; otherwise it will store ** it a a i4 (length) followed by text ** ** Output: ** result query text in specified format ** err_blk Filled in if an error happens ** ** Side efects: ** allocates memory ** ** Returns: ** E_DB_{OK,ERROR} ** ** History: ** 09-jan-93 (andre) ** written ** 29-jul-2001 (toumi01) ** problem found doing i64_aix port: ** (u_char *)'\n' should be (uchar)'\n' ** (u_char *)'\0' should be (uchar)'\0' ** 26-Oct-2009 (coomi01) b122714 ** Move psq_store_text() declarator to pshparse.h and make it public here. ** 24-Jun-2010 (kschendel) b123775 ** Correct a call to trim-whitespace. */ DB_STATUS psq_store_text( PSS_SESBLK *sess_cb, PSS_USRRANGE *rngtab, PTR header, PSF_MSTREAM *mstream, PTR *result, bool return_db_text_string, DB_ERROR *err_blk) { DB_STATUS status; i4 i; PSQ_THEAD *hp = (PSQ_THEAD *) header; i4 size = hp->psq_tsize; PSQ_TEXT *tp; PSS_RNGTAB *rngvar; u_char *out; if (rngtab) { /* ** allocate enough space for range statements. each range statement ** looks like range of 'rngname' is 'tabname'\n. ** Thus, max space is 14+2*DB_MAX_NAME. */ for (i = 0, rngvar = rngtab->pss_rngtab; i < PST_NUMVARS; i++, rngvar++) { /* Only look at range vars that are being used */ if (rngvar->pss_used && rngvar->pss_rgno >= 0) { size += ( 14 /* "range of is \n" */ + psf_trmwhite(DB_TAB_MAXNAME, rngvar->pss_rgname) + psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &rngvar->pss_tabname)); } } } if (return_db_text_string) { DB_TEXT_STRING *str; status = psf_malloc(sess_cb, mstream, size + sizeof(*str) - sizeof(u_char), result, err_blk); if (status != E_DB_OK) return (status); str = (DB_TEXT_STRING *) *result; /* ** store the total length of query text */ str->db_t_count = size; out = str->db_t_text; } else { /* Allocate a piece large enough for all the text + a i4 (count) */ status = psf_malloc(sess_cb, mstream, size + sizeof(i4), result, err_blk); if (status != E_DB_OK) return (status); out = (u_char *) *result; /* Copy the length into the buffer */ MEcopy((char *) &size, sizeof(size), (char *) out); out += sizeof(size); } /* Copy the pieces into the buffer; first put the range statements */ if (rngtab) { for (i = 0, rngvar = rngtab->pss_rngtab; i < PST_NUMVARS; i++, rngvar++) { /* Only look at range vars that are being used */ if (rngvar->pss_used && rngvar->pss_rgno >= 0) { i4 plen; STncpy( (char *)out, "range of ", 9); out += 9; /* add in range name */ plen = psf_trmwhite(DB_TAB_MAXNAME, rngvar->pss_rgname); STncpy( (char *)out, rngvar->pss_rgname, plen); out += plen; STncpy( (char *)out, " is ", 4); out += 4; plen = psf_trmwhite(DB_TAB_MAXNAME, rngvar->pss_tabname.db_tab_name); STncpy( (char *)out, (char *)&rngvar->pss_tabname, plen); out += plen; *out = (u_char)'\n'; out++; *out = (u_char)'\0'; } } } for (tp = hp->psq_first; tp != (PSQ_TEXT *) NULL; tp = tp->psq_next) { MEcopy((char *) tp->psq_tval, tp->psq_psize, (char *) out); out += tp->psq_psize; } return(E_DB_OK); }
/*{ ** Name: psy_seqperm - Check if the user/group/role has sequence permission. ** ** Description: ** This routine retrieves all protection tuples applicable to a given ** sequence until it establishes that the user posesses all privileges ** specified in *privs (SUCCESS) or until there are no more left (FAILURE). ** (The only privilege defined on sequences is NEXT - like SELECT) ** ** The routine assumes that if the current user is the same as the sequence ** owner, then no privileges need be checked. ** ** Inputs: ** rdf_cb RDF CB that was used to extract the ** original sequence. Note that the RDF ** operation type masks will be modified ** in this routine ** (rdr_types_mask will be set to ** RDR_PROTECT|RDR2_SEQUENCE) ** privs ptr to a map of privileges to verify ** DB_NEXT user must posess NEXT on sequence ** DB_GRANT_OPTION privilege(s) must be grantable ** sess_cb Session CB with various values plus: ** .pss_user User name. ** .pss_group Group name. ** .pss_aplid Application/role name. ** seq_info sequence descriptor ** qmode mode of the query ** grant_all TRUE if processing GRANT ALL; ** FALSE otherwise ** ** Outputs: ** privs if non-zero, indicates which privileges ** the user does not posess ** err_blk.err_code Filled in if an error happened: ** errors from RDF & other PSF utilities ** Returns: ** E_DB_OK Success ** E_DB_ERROR Failure ** Exceptions: ** none ** ** Side Effects: ** 1. Via RDF will also access iiprotect. ** ** History: ** 3-may-02 (inkdo01) ** Written for sequence support (cloned from psy_evperm). ** 24-apr-03 (inkdo01) ** Corrected "missing privilege" message. */ DB_STATUS psy_seqperm( RDF_CB *rdf_cb, i4 *privs, PSS_SESBLK *sess_cb, PSS_SEQINFO *seq_info, i4 qmode, i4 grant_all, DB_ERROR *err_blk) { RDR_RB *rdf_rb = &rdf_cb->rdf_rb; /* RDR request block */ #define PSY_RDF_SEQ 5 DB_PROTECTION seqprots[PSY_RDF_SEQ]; /* Set of returned tuples */ DB_PROTECTION *protup; /* Single tuple within set */ i4 tupcount; /* Number of tuples in scan */ DB_STATUS status; i4 save_privs = *privs, privs_wgo = (i4) 0; PSQ_OBJPRIV *seqpriv_element = (PSQ_OBJPRIV *) NULL; /* ** will be used to remember whether the ** <auth id> attempting to grant privilege(s) ** him/herself possesses any privilege on the ** object; ** will start off pessimistic, but may be reset ** to TRUE if we find at least one permit ** granting ANY privilege to <auth id> ** attempting to grant the privilege or to ** PUBLIC */ bool cant_access = TRUE; status = E_DB_OK; if (!MEcmp((PTR) &sess_cb->pss_user, (PTR) &seq_info->pss_seqown, sizeof(sess_cb->pss_user)) ) { /* owner of the sequence posesses all privileges on it */ *privs = (i4) 0; } if (!*privs) { /* no privileges to check or the sequence is owned by the current user */ return(E_DB_OK); } /* ** rdr_rec_access_id must be set before we try to scan a privilege list ** since under some circumstances we may skip all the way to saw_the_perms: ** and seqperm_exit, and code under seqperm_exit: relies on rdr_rec_access_id ** being set to NULL as indication that the tuple stream has not been opened */ rdf_rb->rdr_rec_access_id = NULL; /* ** if processing CREATE PROCEDURE, before scanning IIPROTECT to check if the ** user has the required privileges on the sequence, check if some of the ** privileges have already been checked. */ if (sess_cb->pss_dbp_flags & PSS_DBPROC) { bool missing; status = psy_check_objprivs(sess_cb, privs, &seqpriv_element, &sess_cb->pss_indep_objs.psq_objprivs, &missing, &seq_info->pss_seqid, sess_cb->pss_dependencies_stream, PSQ_OBJTYPE_IS_SEQUENCE, err_blk); if (DB_FAILURE_MACRO(status)) { return(status); } else if (missing) { if (sess_cb->pss_dbp_flags & PSS_DBPGRANT_OK) { /* dbproc is clearly ungrantable now */ sess_cb->pss_dbp_flags &= ~PSS_DBPGRANT_OK; } if (sess_cb->pss_dbp_flags & PSS_0DBPGRANT_CHECK) { /* ** if we determine that a user lacks some privilege(s) by ** scanning IIPROTECT, code under saw_the_perms expects ** priv to contain a map of privileges which could not be ** satisfied; ** if parsing a dbproc to determine its grantability, required ** privileges must be all grantable (so we OR DB_GRANT_OPTION ** into *privs); ** strictly speaking, it is unnecessary to OR DB_GRANT_OPTION ** into *privs, but I prefer to ensure that saw_the_perms: code ** does not have to figure out whether or not IIPROTECT was ** scanned */ *privs |= DB_GRANT_OPTION; } goto saw_the_perms; } else if (!*privs) { /* ** we were able to determine that the user posesses required ** privilege(s) based on information contained in independent ** privilege lists */ return(E_DB_OK); } } /* ** if we are parsing a dbproc to determine if its owner can grant permit on ** it, we definitely want all of the privileges WGO; ** when processing GRANT, caller is expected to set DB_GRANT_OPTION in ** *privs */ if (sess_cb->pss_dbp_flags & PSS_DBPROC) { if (sess_cb->pss_dbp_flags & PSS_0DBPGRANT_CHECK) { /* ** if parsing a dbproc to determine if it is grantable, user must be ** able to grant required privileges */ *privs |= DB_GRANT_OPTION; } else if (sess_cb->pss_dbp_flags & PSS_DBPGRANT_OK) { /* ** if we are processing a definition of a dbproc which appears to be ** grantable so far, we will check for existence of all required ** privileges WGO to ensure that it is, indeed, grantable. */ privs_wgo = *privs; } } /* ** Some RDF fields are already set in calling routine. Permit tuples are ** extracted by unique "dummy" table id. In the case of sequences there ** cannot be any caching of permissions (as there are no timestamps) so we ** pass in an iiprotect result tuple set (seqprots). */ STRUCT_ASSIGN_MACRO(seq_info->pss_seqid, rdf_rb->rdr_tabid); rdf_rb->rdr_types_mask = RDR_PROTECT; rdf_rb->rdr_2types_mask = RDR2_SEQUENCE; rdf_rb->rdr_instr = RDF_NO_INSTR; rdf_rb->rdr_update_op = RDR_OPEN; rdf_rb->rdr_qrymod_id = 0; /* Get all protect tuples */ rdf_cb->rdf_error.err_code = 0; /* For each group of permits */ while (rdf_cb->rdf_error.err_code == 0 && (*privs || privs_wgo)) { /* Get a set at a time */ rdf_rb->rdr_qtuple_count = PSY_RDF_SEQ; rdf_rb->rdr_qrytuple = (PTR) seqprots; /* Result block for tuples */ status = rdf_call(RDF_READTUPLES, (PTR) rdf_cb); rdf_rb->rdr_update_op = RDR_GETNEXT; if (status != E_DB_OK) { switch(rdf_cb->rdf_error.err_code) { case E_RD0011_NO_MORE_ROWS: status = E_DB_OK; break; case E_RD0013_NO_TUPLE_FOUND: status = E_DB_OK; continue; /* Will stop outer loop */ default: _VOID_ psf_rdf_error(RDF_READTUPLES, &rdf_cb->rdf_error, err_blk); goto seqperm_exit; } /* End switch error */ } /* If error */ /* For each permit tuple */ for (tupcount = 0, protup = seqprots; tupcount < rdf_rb->rdr_qtuple_count; tupcount++, protup++) { bool applies; i4 privs_found; /* check if the permit applies to this session */ status = psy_grantee_ok(sess_cb, protup, &applies, err_blk); if (DB_FAILURE_MACRO(status)) { goto seqperm_exit; } else if (!applies) { continue; } /* ** remember that the <auth id> attempting to grant a privilege ** possesses some privilege on the sequence */ if (qmode == PSQ_GRANT && cant_access) cant_access = FALSE; /* ** if some of the required privileges have not been satisfied yet, ** we will check for privileges in *privs; otherwise we will check ** for privileges in (privs_wgo|DB_GRANT_OPTION) */ privs_found = prochk((*privs) ? *privs : (privs_wgo | DB_GRANT_OPTION), (i4 *) NULL, protup, sess_cb); if (!privs_found) continue; /* mark the operations as having been handled */ *privs &= ~privs_found; /* ** if the newly found privileges are WGO and we are looking for ** all/some of them WGO, update the map of privileges WGO being ** sought */ if (protup->dbp_popset & DB_GRANT_OPTION && privs_found & privs_wgo) { privs_wgo &= ~privs_found; } /* ** check if all required privileges have been satisfied; ** note that DB_GRANT_OPTION bit does not get turned off when we ** find a tuple matching the required privileges since when we ** process GRANT ON SEQUENCE, more than one privilege may be required */ if (*privs && !(*privs & ~DB_GRANT_OPTION)) { *privs = (i4) 0; } if (!*privs && !privs_wgo) { /* ** all the required privileges have been satisfied and the ** required privileges WGO (if any) have been satisfied as ** well - we don't need to examine any more tuples */ break; } } /* For all tuples */ } /* While there are RDF tuples */ saw_the_perms: if ( sess_cb->pss_dbp_flags & PSS_DBPGRANT_OK && (privs_wgo || *privs & DB_GRANT_OPTION)) { /* ** we are processing a dbproc definition; until now the dbproc appeared ** to be grantable, but the user lacks the required privileges WGO on ** this sequence - mark the dbproc as non-grantable */ sess_cb->pss_dbp_flags &= ~PSS_DBPGRANT_OK; } /* ** if processing a dbproc, we will record the privileges which the current ** user posesses if ** - user posesses all the required privileges or ** - we were parsing the dbproc to determine if it is grantable (in ** which case the current dbproc will be marked as ungrantable, but ** the privilege information may come in handy when processing the ** next dbproc mentioned in the same GRANT statement.) ** ** NOTE: we do not build independent privilege list for system-generated ** dbprocs */ if ( sess_cb->pss_dbp_flags & PSS_DBPROC && ~sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED && (!*privs || sess_cb->pss_dbp_flags & PSS_0DBPGRANT_CHECK)) { if (save_privs & ~*privs) { if (seqpriv_element) { seqpriv_element->psq_privmap |= (save_privs & ~*privs); } else { /* create a new descriptor */ status = psy_insert_objpriv(sess_cb, &seq_info->pss_seqid, PSQ_OBJTYPE_IS_SEQUENCE, save_privs & ~*privs, sess_cb->pss_dependencies_stream, &sess_cb->pss_indep_objs.psq_objprivs, err_blk); if (DB_FAILURE_MACRO(status)) goto seqperm_exit; } } } if (*privs) { char buf[60]; /* buffer for missing privilege string */ i4 err_code; psy_prvmap_to_str((qmode == PSQ_GRANT) ? *privs & ~DB_GRANT_OPTION : *privs, buf, sess_cb->pss_lang); if (sess_cb->pss_dbp_flags & PSS_DBPROC) sess_cb->pss_dbp_flags |= PSS_MISSING_PRIV; if (qmode == PSQ_GRANT) { if (cant_access) { _VOID_ psf_error(E_US088F_2191_INACCESSIBLE_EVENT, 0L, PSF_USERERR, &err_code, err_blk, 3, sizeof("GRANT") - 1, "GRANT", psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &seq_info->pss_seqown), &seq_info->pss_seqown, psf_trmwhite(sizeof(DB_NAME), (char *) &seq_info->pss_seqname), &seq_info->pss_seqname); } else if (!grant_all) { /* privileges were specified explicitly */ _VOID_ psf_error(E_PS0551_INSUF_PRIV_GRANT_OBJ, 0L, PSF_USERERR, &err_code, err_blk, 3, STlength(buf), buf, psf_trmwhite(sizeof(DB_NAME), (char *) &seq_info->pss_seqname), &seq_info->pss_seqname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &seq_info->pss_seqown), &seq_info->pss_seqown); } else if (save_privs == *privs) { /* user entered GRANT ALL [PRIVILEGES] */ _VOID_ psf_error(E_PS0563_NOPRIV_ON_GRANT_EV, 0L, PSF_USERERR, &err_code, err_blk, 2, psf_trmwhite(sizeof(DB_NAME), (char *) &seq_info->pss_seqname), &seq_info->pss_seqname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &seq_info->pss_seqown), &seq_info->pss_seqown); } } else if ( sess_cb->pss_dbp_flags & PSS_DBPROC && sess_cb->pss_dbp_flags & PSS_0DBPGRANT_CHECK) { /* ** if we were processing a dbproc definition to determine if it ** is grantable, record those of required privileges which the ** current user does not posess */ _VOID_ psf_error(E_PS0557_DBPGRANT_LACK_EVPRIV, 0L, PSF_USERERR, &err_code, err_blk, 4, psf_trmwhite(sizeof(DB_NAME), (char *) &seq_info->pss_seqname), &seq_info->pss_seqname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &seq_info->pss_seqown), &seq_info->pss_seqown, psf_trmwhite(sizeof(DB_DBP_NAME), (char *) sess_cb->pss_dbpgrant_name), sess_cb->pss_dbpgrant_name, STlength(buf), buf); status = psy_insert_objpriv(sess_cb, &seq_info->pss_seqid, PSQ_OBJTYPE_IS_SEQUENCE | PSQ_MISSING_PRIVILEGE, save_privs & *privs, sess_cb->pss_dependencies_stream, &sess_cb->pss_indep_objs.psq_objprivs, err_blk); } else { char *op; op = "NEXT VALUE"; /* only one possible */ _VOID_ psf_error(E_PS0D3D_MISSING_SEQUENCE_PRIV, 0L, PSF_USERERR, &err_code, err_blk, 4, STlength(op), op, STlength(buf), buf, psf_trmwhite(sizeof(DB_NAME), (char *) &seq_info->pss_seqname), &seq_info->pss_seqname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &seq_info->pss_seqown), &seq_info->pss_seqown); } } seqperm_exit: /* Close iiprotect system catalog */ if (rdf_rb->rdr_rec_access_id != NULL) { DB_STATUS stat; rdf_rb->rdr_update_op = RDR_CLOSE; stat = rdf_call(RDF_READTUPLES, (PTR) rdf_cb); if (DB_FAILURE_MACRO(stat)) { _VOID_ psf_rdf_error(RDF_READTUPLES, &rdf_cb->rdf_error, err_blk); if (stat > status) { status = stat; } } } /* ** If user does not have privs we need to audit that they failed to perform ** the action on the event. */ if ( *privs && Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) { i4 msg_id; i4 accessmask = SXF_A_FAIL; /* determin action */ switch (qmode) { default: accessmask |= SXF_A_RAISE; msg_id = I_SX2704_RAISE_DBEVENT; break; } /* stat = psy_secaudit(FALSE, sess_cb, ev_info->pss_alert_name.dba_alert.db_name, &ev_info->pss_alert_name.dba_owner, sizeof(ev_info->pss_alert_name.dba_alert.db_name), SXF_E_EVENT, msg_id, accessmask, (PTR)&ev_info->pss_evsecid, DB_SECID_TYPE, &e_error); if (stat > status) status = stat; */ } return(status); } /* psy_seqperm */
/*{ ** Name: psy_gsequence - Get description of a sequence from RDF. ** ** Description: ** This routine calls RDF to return the iisequence tuple for a sequence, ** then moves certain columns into the PSS_SEQINFO structure for its caller. ** It is used by psl to verify the existence of a sequence referenced in ** a sequence operation (next/current value) and return definition information. ** ** Inputs: ** sess_cb Pointer to session control block. ** .pss_user User/owner of the event. ** seq_own Sequence owner (from syntax). ** seq_name Sequence name (from syntax). ** seq_mask flag field ** PSS_USRSEQ search for sequence owned by the current user ** PSS_DBASEQ search for sequence owned by the DBA ** (must not be set unless ** (seq_mask & PSS_USRSEQ)) ** PSS_INGSEQ search for sequence owned by $ingres ** (must not be set unless ** (seq_mask & PSS_USRSEQ)) ** PSS_SEQ_BY_OWNER search for sequence owned by the specified ** owner ** PSS_SEQ_BY_ID search for sequence by id ** NOTE: PSS_USRSEQ <==> !PSS_SEQ_BY_OWNER ** PSS_SEQ_BY_ID ==> !PSS_SEQ_BY_OWNER ** PSS_SEQ_BY_ID ==> !PSS_USRSEQ ** privs Pointer to privilege bit map (if we're to ** check privileges on this sequence) or NULL. ** qmode Query mode (for errors). ** grant_all Flag indicating GRANT ALL accompanied request. ** ** Outputs: ** seq_info Pointer to sequence information block ** .pss_seqname Sequence name. ** .pss_owner Sequence owner. ** .pss_seqid Internal sequence ID. ** .pss_dt Sequence value datatype. ** .pss_length Sequence value length. ** .pss_secid Sequence security ID. ** err_blk ** .err_code Filled in if an error happens: ** E_US1914_SEQ_NOT_FOUND Cannot find sequence definition. ** Generally, the error codes returned by RDF and QEU ** qrymod processing routines are passed back to the caller ** except where they are user errors (eg, sequence doesn't exist). ** ** Returns: ** E_DB_OK, E_DB_WARN, E_DB_ERROR, E_DB_FATAL ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 18-mar-02 (inkdo01) ** Cloned from psy_gevent for sequence support. ** 21-feb-03 (inkdo01) ** Add seq_mask to control iisequence retrieval. ** 24-apr-03 (inkdo01) ** Reset IISEQUENCE ptr for secondary calls to RDF. ** 24-apr-03 (inkdo01) ** Fix "not found" message for "drop sequence". ** 09-Mar-2010 (coomi01) b123351 ** Block users from dropping dba sequences. ** 29-Apr-2010 (coomi01) b123638 ** Backout the above change, then put in a test ** to prevent delete dba's sequence by non dba. ** This allows non-dba to find sequence for ** updating. ** 15-Oct-2010 (kschendel) SIR 124544 ** Update psl-command-string call. */ DB_STATUS psy_gsequence( PSS_SESBLK *sess_cb, DB_OWN_NAME *seq_own, DB_NAME *seq_name, i4 seq_mask, PSS_SEQINFO *seq_info, DB_IISEQUENCE *seqp, i4 *ret_flags, i4 *privs, i4 qmode, i4 grant_all, DB_ERROR *err_blk) { DB_STATUS status; RDF_CB rdf_seq; /* RDF for sequence */ DB_IISEQUENCE seqtuple; /* sequence tuple to retrieve into */ i4 err_code; bool leave_loop = TRUE; *ret_flags = 0; /* First retrieve sequence tuple from RDF */ if (seqp == NULL) seqp = &seqtuple; /* zero out RDF_CB and init common elements */ pst_rdfcb_init(&rdf_seq, sess_cb); /* init relevant elements */ { rdf_seq.rdf_rb.rdr_types_mask = RDR_BY_NAME; rdf_seq.rdf_rb.rdr_2types_mask = RDR2_SEQUENCE; MEmove(sizeof(DB_NAME), (PTR) seq_name, ' ', sizeof(DB_NAME), (PTR) &rdf_seq.rdf_rb.rdr_name.rdr_seqname); STRUCT_ASSIGN_MACRO((*seq_own), rdf_seq.rdf_rb.rdr_owner); } rdf_seq.rdf_rb.rdr_update_op = RDR_OPEN; rdf_seq.rdf_rb.rdr_qtuple_count = 1; rdf_seq.rdf_rb.rdr_qrytuple = (PTR) seqp; do /* something to break out of */ { status = rdf_call(RDF_GETINFO, (PTR) &rdf_seq); /* ** if caller specified sequence owner name, or ** the sequence was found, or ** an error other than "sequence not found" was encountered, ** bail out */ if ( seq_mask & PSS_SEQ_BY_OWNER || status == E_DB_OK || rdf_seq.rdf_error.err_code != E_RD0013_NO_TUPLE_FOUND ) break; /* ** if sequence was not found, and ** - caller requested that DBA's sequences be considered, and ** - user is not the DBA, ** - check we are not attempting to destroy the sequence. ** check if the sequence is owned by the DBA */ if ((qmode != PSQ_DSEQUENCE) && seq_mask & PSS_DBASEQ && MEcmp((PTR) &sess_cb->pss_dba.db_tab_own, (PTR) &sess_cb->pss_user, sizeof(DB_OWN_NAME)) ) { STRUCT_ASSIGN_MACRO(sess_cb->pss_dba.db_tab_own, rdf_seq.rdf_rb.rdr_owner); rdf_seq.rdf_rb.rdr_qtuple_count = 1; rdf_seq.rdf_rb.rdr_qrytuple = (PTR) &seqtuple; status = rdf_call(RDF_GETINFO, (PTR) &rdf_seq); if (status == E_DB_OK) STRUCT_ASSIGN_MACRO(seqtuple, *seqp); } /* ** if still not found, and ** - caller requested that sequences owned by $ingres be considered, and ** - user is not $ingres and ** - DBA is not $ingres, ** check if the sequence is owned by $ingres */ if ( status != E_DB_OK && rdf_seq.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND && seq_mask & PSS_INGSEQ ) { if ( MEcmp((PTR) &sess_cb->pss_user, (PTR) sess_cb->pss_cat_owner, sizeof(DB_OWN_NAME)) && MEcmp((PTR) &sess_cb->pss_dba.db_tab_own, (PTR) sess_cb->pss_cat_owner, sizeof(DB_OWN_NAME)) ) { STRUCT_ASSIGN_MACRO((*sess_cb->pss_cat_owner), rdf_seq.rdf_rb.rdr_owner); rdf_seq.rdf_rb.rdr_qtuple_count = 1; rdf_seq.rdf_rb.rdr_qrytuple = (PTR) &seqtuple; status = rdf_call(RDF_GETINFO, (PTR) &rdf_seq); if (status == E_DB_OK) STRUCT_ASSIGN_MACRO(seqtuple, *seqp); } } /* leave_loop has already been set to TRUE */ } while (!leave_loop); if (status != E_DB_OK) { if (rdf_seq.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND) { if (qmode == PSQ_ASEQUENCE || qmode == PSQ_DSEQUENCE) { _VOID_ psf_error(6419L, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(*seq_name), (PTR)seq_name), (PTR)seq_name); } else /* must be DML currval/nextval request */ { char qry[PSL_MAX_COMM_STRING]; i4 qry_len; psl_command_string(qmode, sess_cb, qry, &qry_len); _VOID_ psf_error(6420L, 0L, PSF_USERERR, &err_code, err_blk, 2, qry_len, qry, psf_trmwhite(sizeof(*seq_name), (char *) seq_name), (PTR) seq_name); } if (sess_cb->pss_dbp_flags & PSS_DBPROC) sess_cb->pss_dbp_flags |= PSS_MISSING_OBJ; *ret_flags |= PSS_MISSING_SEQUENCE; status = E_DB_OK; } else /* some other error */ { _VOID_ psf_rdf_error(RDF_GETINFO, &rdf_seq.rdf_error, err_blk); } return (status); } /* If RDF did not return the sequence tuple */ STRUCT_ASSIGN_MACRO(rdf_seq.rdf_rb.rdr_owner, (*seq_own)); /* copy back successful owner */ if (seq_info != NULL) { /* fill in a sequence descriptor */ STRUCT_ASSIGN_MACRO(seqp->dbs_name, seq_info->pss_seqname); STRUCT_ASSIGN_MACRO(seqp->dbs_owner, seq_info->pss_seqown); STRUCT_ASSIGN_MACRO(seqp->dbs_uniqueid, seq_info->pss_seqid); seq_info->pss_dt = seqp->dbs_type; seq_info->pss_length = seqp->dbs_length; seq_info->pss_prec = seqp->dbs_prec; } /* ** if we are parsing a dbproc and the sequence which we have just looked up ** is owned by the dbproc's owner, we will add the sequence to the dbproc's ** independent object list unless it has already been added. ** Note that only sequences owned by the current user will be included into ** the list of independent objects. ** ** NOTE: we do not build independent object list for system-generated ** dbprocs */ if ( sess_cb->pss_dbp_flags & PSS_DBPROC && ~sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED && !MEcmp((PTR) &sess_cb->pss_user, (PTR) &seqp->dbs_owner, sizeof(sess_cb->pss_user)) ) { status = pst_add_1indepobj(sess_cb, &seqp->dbs_uniqueid, PSQ_OBJTYPE_IS_SEQUENCE, (DB_DBP_NAME *) NULL, &sess_cb->pss_indep_objs.psq_objs, sess_cb->pss_dependencies_stream, err_blk); if (DB_FAILURE_MACRO(status)) { return(status); } } if (privs && *privs) { i4 privs_to_find = *privs; status = psy_seqperm(&rdf_seq, &privs_to_find, sess_cb, seq_info, qmode, grant_all, err_blk); if (DB_FAILURE_MACRO(status)) { return (status); } else if (privs_to_find) { if (grant_all && *privs != privs_to_find) { /* ** if we are processing GRANT ALL and psy_seqperm() has ** determined that the user may grant some but not all ** privileges on the sequence, reset the privilege map ** accordingly */ *privs &= ~(privs_to_find & ~((i4) DB_GRANT_OPTION)); } else { *ret_flags |= PSS_INSUF_SEQ_PRIVS; return(E_DB_OK); } } /* If no permission */ } return(E_DB_OK); }
/* ** Name: psl_lm3_setlockparm_name() - perform semantic action for SETLOCKPARM ** production when the characteristic value ** has been specified as a string ** ** Input: ** sess_cb PSF session CB ** pss_distrib DB_3_DDB_SESS if distributed thread ** pss_stmt_flags PSS_SET_LOCKMODE_SESS if SET LOCKMODE SESSION ** (distributed thread only) ** pss_object pointer to the root of a QSF object ** (of type (DMC_CB *) or (QEF_RCB *)). ** char_type characteristic type ** char_val value as specified by the user ** ** Output: ** err_blk filled in if an error occurred ** sess_cb PSF session CB ** pss_object characteristics of SETLOCKPARM filled in. ** ** Returns: ** E_DB_{OK, ERROR, SEVERE} ** ** Side effects: ** None ** ** History: ** 07-mar-91 (andre) ** plagiarized from SETLOCKPARM production ** 21-apr-92 (barbara) ** Added support for Sybil. For distributed thread, on ** SET LOCKMODE SESSION .. TIMEOUT we set timeout value ** specifically for QEF; all other options are passed to QEF ** in textual representation (see psl_lm5_setlockmode_distr) and ** are ignored in this function. ** 22-nov-1996 (dilma04) ** Row-level locking project: ** Add support for LEVEL=ROW. ** 24-jan-97 (dilma04) ** Fix bug 80115: report an error if trying to specify row locking ** for a system catalog or a table with 2k page size. ** 12-feb-97 (dilma04) ** Set Lockmode Cleanup: ** Change readlock values according to new definitions. ** 25-feb-99 (hayke02) ** When setting row level locking in STAR, we now do not check ** if the lockmode scope is table. This was causing a SIGSEGV ** because dmc_cb had not been set. This change fixes bug 95490. ** 31-May-2006 (kschendel) ** Allow level=row for catalogs, no reason to exclude it. ** 15-Jan-2010 (stial01) ** SIR 121619 MVCC: Add lock level MVCC */ DB_STATUS psl_lm3_setlockparm_name( i4 char_type, char *char_val, PSS_SESBLK *sess_cb, DB_ERROR *err_blk) { i4 err_code, err_no = 0L; DMC_CHAR_ENTRY *chr; DM_DATA *char_array; DMC_CB *dmc_cb; bool not_distr = ~sess_cb->pss_distrib & DB_3_DDB_SESS; i4 *val, dummy; if (not_distr) { char_array = &((DMC_CB *)sess_cb->pss_object)->dmc_char_array; dmc_cb = (DMC_CB *) sess_cb->pss_object; if (char_array->data_in_size / sizeof (DMC_CHAR_ENTRY) == MAX_LOCKMODE_CHARS) { (VOID) psf_error(5931L, 0L, PSF_USERERR, &err_code, err_blk, 0); return (E_DB_ERROR); /* non-zero return means error */ } chr = (DMC_CHAR_ENTRY *) ((char *) char_array->data_address + char_array->data_in_size); val = &chr->char_value; } else { val = &dummy; } switch (char_type) { case LOCKLEVEL: /* ** Acceptable values for locklevel are "row", "page", "table", ** "session", "system", "mvcc". */ if (not_distr) chr->char_id = DMC_C_LLEVEL; if (!STcompare(char_val, "page")) { *val = DMC_C_PAGE; } else if (!STcompare(char_val, "session")) { *val = DMC_C_SESSION; } else if (!STcompare(char_val, "system")) { *val = DMC_C_SYSTEM; } else if (!STcompare(char_val, "table")) { *val = DMC_C_TABLE; } else if (!STcompare(char_val, "row") || !STcompare(char_val, "mvcc")) { if (not_distr && (dmc_cb->dmc_sl_scope == DMC_SL_TABLE)) { DB_TAB_ID *tabid = &dmc_cb->dmc_table_id; PSS_RNGTAB *tbl = &sess_cb->pss_auxrng.pss_rsrng; if (tbl->pss_tabdesc->tbl_pg_type == DB_PG_V1) { (VOID) psf_error(E_PS03B0_ILLEGAL_ROW_LOCKING, 0L, PSF_USERERR, &err_code, err_blk, 2, STlength(char_val), char_val, psf_trmwhite(sizeof(tbl->pss_tabname), (char *) &tbl->pss_tabname), &tbl->pss_tabname); return (E_DB_ERROR); } } if (*char_val == 'r') *val = DMC_C_ROW; else *val = DMC_C_MVCC; } else { err_no = 5924L; } break; case READLOCK: /* ** Acceptable values for readlock are "nolock", "shared", ** "exclusive", "session", "system". */ if (not_distr) chr->char_id = DMC_C_LREADLOCK; if (!STcompare(char_val, "nolock")) { *val = DMC_C_READ_NOLOCK; } else if (!STcompare(char_val, "shared")) { *val = DMC_C_READ_SHARE; } else if (!STcompare(char_val, "exclusive")) { *val = DMC_C_READ_EXCLUSIVE; } else if (!STcompare(char_val, "session")) { *val = DMC_C_SESSION; } else if (!STcompare(char_val, "system")) { *val = DMC_C_SYSTEM; } else { err_no = 5925L; } break; case MAXLOCKS: /* ** Acceptable values for maxlocks are "session", "system". */ if (not_distr) chr->char_id = DMC_C_LMAXLOCKS; if (!STcompare(char_val, "session")) { *val = DMC_C_SESSION; } else if (!STcompare(char_val, "system")) { *val = DMC_C_SYSTEM; } else { err_no = 5926L; } break; case TIMEOUT: /* ** Acceptable values for timeout are "session" , "system", ** and "nowait". */ if (not_distr) { chr->char_id = DMC_C_LTIMEOUT; } else if (sess_cb->pss_stmt_flags & PSS_SET_LOCKMODE_SESS) { /* ** The distributed server is interested in the value from ** the SETLOCKKEY production when the SETLOCKSCOPE value ** is session. */ val = &((QEF_RCB *)sess_cb->pss_object)->qef_r3_ddb_req.qer_d14_ses_timeout; } if (!STcompare(char_val, "session")) { *val = DMC_C_SESSION; } else if (!STcompare(char_val, "system")) { *val = DMC_C_SYSTEM; } else if (!STcompare(char_val, "nowait")) { *val = DMC_C_NOWAIT; } else { err_no = 5927L; } break; default: /* Unknown "set lockmode" parameter */ (VOID) psf_error(E_PS0351_UNKNOWN_LOCKPARM, 0L, PSF_INTERR, &err_code, err_blk, 1, (i4) sizeof(char_type), &char_type); return (E_DB_SEVERE); /* non-zero return means error */ } if (err_no != 0L) { (VOID) psf_error(err_no, 0L, PSF_USERERR, &err_code, err_blk, 1, (i4) STlength(char_val), char_val); return (E_DB_ERROR); /* non-zero return means error */ } else { if (not_distr) char_array->data_in_size += sizeof (DMC_CHAR_ENTRY); } return(E_DB_OK); }
/*{ ** 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_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: psq_bgn_session - Begin a parser session. ** ** INTERNAL PSF call format: status = psq_bgn_session(&psq_cb, &sess_cb); ** ** EXTERNAL call format: status = psq_call(PSQ_BGN_SESSION, &psq_cb, &sess_cb); ** ** Description: ** The psq_bgn_session function begins a parser session. It should be ** called each time a new user connects to a server. There may be ** many parser sessions per database server. There should be one parser ** session for each invocation of the database system that is connected ** to the server. When starting a parser session, one has to tell it ** what query language to use, and other session parameters. ** ** Inputs: ** psq_cb ** .psq_qlang The query language to use. ** .psq_decimal ** .psf_decspec TRUE indicates that the decimal marker ** has been specified. FALSE means use the ** default (a "."). ** .psf_decimal The character to use as a decimal marker ** (if specified). ** .psq_distrib Indicator for whether distributed ** statements and constructs should be ** accepted. ** .psq_sessid Session id ** .psq_server address of server control block ** .psq_adf_cb Pointer to session's ADF_CB ** .psq_dbid Database id for this session. ** .psq_user User name of ** .psq_dba User name of dba ** .psq_group Group id of session ** .psq_aplid Application id of session ** .psq_flag bitmask containing the following flags: ** .psq_catupd TRUE means catalogs updateable ** .psq_warnings Set to TRUE if user wishes to see ** warnings on unsupported commands ** .psq_idxstruct Structure for creating new indexes ** (e.g. DB_ISAM_STORE) ** .psq_udbid Unique database id for this session. ** .psq_ustat User status flags from SCS_ICS ** .psq_dbxlate Case translation semantics for the db ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psq_cb ** .psq_error Error information ** .err_code What error occurred ** E_PS0000_OK Success ** E_PS0001_INTERNAL_ERROR Internal PSF problem ** E_PS0201_BAD_QLANG Bad query language specifier ** E_PS0203_NO_DECIMAL No decimal marker specified ** E_PS0204_BAD_DISTRIB Bad distributed ** specification ** E_PS0205_SRV_NOT_INIT Server not initialized ** E_PS0206_TOO_MANY_SESS Too many sessions at one ** time ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s) ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_SEVERE Session is to be aborted ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Causes memory to be allocated. ** Increments the session count in the server control block. ** ** History: ** 01-oct-85 (jeff) ** written ** 28-jul-86 (jeff) ** Added initialization of pss_catupd and pss_idxstruct ** 26-aug-86 (seputis) ** Removed definition of yaccstream ** 13-apr-87 (puree) ** Initialize prototype list for dynamic SQL. ** 24-apr-87 (stec) ** init pss_project. ** 11-may-87 (stec) ** store psq_udbid to pss_dbid. ** 04-sep-87 (stec) ** Added critical region code where needed. ** 02-oct-87 (stec) ** Added pss_journaling initialization. ** 13-jun-88 (stec) ** Added initialization of pss_ruset for DB procs. ** 08-mar-89 (andre) ** Copy dba_drop_all from PSQ_CB to PSS_SESBLK. ** 15-mar-89 (ralph) ** GRANT Enhancements, Phase 1: ** Copy psq_aplid to pss_aplid; ** Copy psq_group to pss_group. ** 16-mar-89 (neil) ** Initialized rule field. ** 27-jul-89 (jrb) ** Copy numeric literals flag into session cb. ** 27-oct-89 (ralph) ** Copy user status flags to session control block. ** 11-oct-89 (ralph) ** Initialize pss_rgset and pss_raset. ** 28-dec-89 (andre) ** Copy fips_mode from PSQ_CB to PSS_SESBLK. ** 13-feb-90 (andre) ** set scf_stype to SCU_EXCLUSIVE before calling scu_swait. ** 12-sep-90 (sandyh) ** Added support for session memory value calculated from psf ** memory startup parameter. ** 15-nov-90 (andre) ** check the return status after calling SCF to acquire or to release a ** semaphore. ** If an error occurred when trying to acquire the semaphore, return ** E_DB_SEVERE to abort the session. ** If an error occurred when trying to release the semaphore, return ** E_DB_FATAL to bring down the server. ** 17-may-91 (andre) ** store DBA name into sess_cb->pss_dbaname and NULL-terminate. ** 08-nov-91 (rblumer) ** merged from 6.4: 25-jul-91 (andre) ** if (psq_cb->psq_flag & PSQ_STRIP_NL_IN_STRCONST), set bit ** PSS_STRIP_NL_IN_STRCONST in sess_cb->pss_ses_flag. this will ** indicate that we are connected to an older FE, so the scanners ** will continue to strip NLs inside quoted strings; ** this is required to fix bug 38098 ** 14-jan-92 (barbara) ** Included ddb.h for Star. Updated to check for distributed ** specification. ** 26-feb-92 (andre) ** if PSQ_REPAIR_SYSCAT is set in psq_cb->psq_flag, set ** PSS_REPAIR_SYSCAT in sess_cb->pss_ses_flags ** 30-mar-1992 (bryanp) ** Fill in pss_sess_owner with a session-unique owner name for use ** by temporary tables which are owned by this session. ** 02-jun-92 (andre) ** initialize pss_dependencies_stream to NULL to avloid use of illegal ** address throughout the parser. ** 24-nov-92 (ralph) ** CREATE SCHEMA: ** Initialize pss_prvgoval ** 22-dec-92 (rblumer) ** initialize pointer for statement-level rule list. ** 14-jan-93 (andre) ** remember whether we are running UPGRADEDB - this will enable us to ** decide whether IIDEVICES can be dropped - which is needed by ** UPGRADEDB ** 15-mar-93 (ralph) ** DELIM_IDENT: initialize pss_dbxlate to zero ** 08-apr-93 (andre) ** names of rule list headers in sess_cb have changed (and their ** number has doubled) ** 26-mar-93 (ralph) ** DELIM_IDENT: Must initialize pss_dbxlate from psq_cb.psq_dbxlate ** and pss_cat_owner from psq_cat_owner. ** 10-aug-93 (andre) ** fixed cause of a compiler warning ** 08-sep-93 (swm) ** Changed sizeof(DB_SESSID) to sizeof(CS_SID) to reflect recent CL ** interface revision. ** 20-sep-93 (rogerk) ** Changed default table create semantics to be WITH JOURNALING. ** Initialized the pss_ses_flag setting to include PSS_JOURNALING ** which mimics the user requesting "set journaling" to indicate that ** tables created should be journaled. ** 08-oct-93 (rblumer) ** increased values allowed in pss_trace vector, using PSS_TVALS. ** 18-oct-93 (rogerk) ** Added support for journal default override. Check psf server ** control block flag for PSF_NO_JNL_DEFAULT override before setting ** the session parse flag to assume journaling on table creates. ** 15-nov-93 (andre) ** add code to initialize a newly added sess_cb->pss_flattening_flags ** 01-nov-93 (anitap) ** if PSQ_INGRES_PRIV is set in psq_cb->psq_flag, set ** PSS_INGRES_PRIV in sess_cb->pss_ses_flags. ** 17-dec-93 (rblumer) ** "FIPS mode" no longer exists. It was replaced some time ago by ** several feature-specific flags (e.g. flatten_nosingleton and ** direct_cursor_mode). So I removed all FIPS_MODE flags. ** 02-jan-94 (andre) ** if starting a local session, call DMF to determine whether the ** database to which we are connected is being journaled and record ** that information by setting (or not setting) PSS_JOURNALED_DB bit ** in pss_ses_flags ** 7-jan-94 (swm) ** Bug #58635 ** Added PTR cast for pss_owner which has changed type to PTR. ** 17-mar-94 (robf) ** Add support for PSQ_SELECT_ALL flag ** 13-Feb-1995 (canor01) ** initialize the pss_audit field in the session control block ** 09-Oct-1998 (jenjo02) ** Removed SCF semaphore functions, inlining the CS calls instead. ** 23-mar-1999 (thaju02) ** Modified '$Sess' to use #define DB_SESS_TEMP_OWNER. (B94067) ** 01-Dec-2000 (hanal04) Bug 100680 INGSRV 1123 ** If PSQ_RULE_UPD_PREFETCH is set turn on PSS_RULE_UPD_PREFETCH ** in the session control block to signify that we should use ** the prefetch stategy required to ensure consitent behaviour in ** updating rules fired by updates. ** 10-Jan-2001 (jenjo02) ** Remove callback to SCF to get session id and ADF_CB; ** *ADF_CB now supplied by scsinit in PSQ_CB. ** 30-Jan-2004 (schka24) ** Get rid of a type-cast warning on adf cb. ** 3-Feb-2005 (schka24) ** Num-literals renamed to parser-compat, fix here. ** 15-june-06 (dougi) ** Add support for "before" triggers. ** 30-aug-06 (thaju02) ** If PSQ_RULE_DEL_PREFETCH is set turn on PSS_RULE_DEL_PREFETCH ** in the session control block, for prefetch strategy to ** be applied for deletes. (B116355) ** 26-Oct-2009 (kiria01) SIR 121883 ** Scalar sub-query support: Added copy of ** psq_flag.PSQ_NOCHK_SINGLETON_CARD to session flag ** for defaulting SET CARDINALITY_CHECK ** November 2009 (stephenb) ** Batch execution; initilization of new fields. ** 29-apr-2010 (stephenb) ** Init batch_copy_optim. ** 04-may-2010 (miket) SIR 122403 ** Init new sess_cb->pss_stmt_flags2. ** 19-May-2010 (kiria01) b123766 ** Get cardinality check default from server block not psq_cb ** 21-Jul-2010 (kschendel) SIR 124104 ** Initialize default compression from facility cb. ** 14-Oct-2010 (kschendel) SIR 124544 ** Initialize default result structure from facility cb. ** 19-Nov-2010 (kiria01) SIR 124690 ** Add support for setting installation wide collation defaults. */ DB_STATUS psq_bgn_session( register PSQ_CB *psq_cb, register PSS_SESBLK *sess_cb) { i4 err_code; i4 i; DB_STATUS status = E_DB_OK; STATUS sem_status; i4 sem_errno; bool leave_loop = TRUE; ULM_RCB ulm_rcb; /* ** No error to begin with. */ psq_cb->psq_error.err_code = E_PS0000_OK; /* ** Do as much validity checking as possible before allocating any memory. ** That way, there won't be any cleaning up to do for the majority of ** errors. */ /* ** Check for server initialized. This code could be placed within ** critical region, but this is not necessary, since this is a flag ** test. */ if (!Psf_srvblk->psf_srvinit) { (VOID) psf_error(E_PS0205_SRV_NOT_INIT, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* ** Check for valid language spec. */ if (psq_cb->psq_qlang != DB_QUEL && psq_cb->psq_qlang != DB_SQL) { (VOID) psf_error(E_PS0201_BAD_QLANG, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* ** Check whether language is allowed in this server. This will be useful ** when we have configurable servers, where some query languages can be ** used and some can't. This code could be placed within a critical region ** but it is not necessary, since this is a flag test only. */ if ((psq_cb->psq_qlang & Psf_srvblk->psf_lang_allowed) == 0) { (VOID) psf_error(E_PS0202_QLANG_NOT_ALLOWED, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* ** Make sure that the decimal character is actually specified. */ if (!psq_cb->psq_decimal.db_decspec) { (VOID) psf_error(E_PS0203_NO_DECIMAL, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* Check distributed specification ** ** a=local_server, b=distrib_server, c=distrib_session ** ** a,b ** ** 00 01 11 10 ** ----------------- ** c | | | | | ** 0 | 1 | 1 | 0 | 0 | ** | | | | | ** ----------------- ==> ERROR ** | | | | | ** 1 | 1 | 0 | 0 | 1 | ** | | | | | ** ----------------- */ if ( !(psq_cb->psq_distrib & (DB_1_LOCAL_SVR | DB_3_DDB_SESS)) || ((~psq_cb->psq_distrib & DB_2_DISTRIB_SVR) && (psq_cb->psq_distrib & DB_3_DDB_SESS)) ) { psf_error(E_PS0204_BAD_DISTRIB, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error,0); return (E_DB_ERROR); } /* ** Check for too many sessions in server at one time. ** This code must be executed as a critical region. */ do /* something to break out of */ { /* get the semaphore */ if (sem_status = CSp_semaphore(1, &Psf_srvblk->psf_sem)) /* exclusive */ { status = E_DB_SEVERE; /* abort the session */ sem_errno = E_PS020A_BGNSES_GETSEM_FAILURE; break; } if (Psf_srvblk->psf_nmsess >= Psf_srvblk->psf_mxsess) { (VOID) psf_error(E_PS0208_TOO_MANY_SESS, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); status = E_DB_ERROR; break; } /* Increment the session count */ Psf_srvblk->psf_nmsess++; sess_cb->pss_psessid = ++Psf_srvblk->psf_sess_num; /* leave_loop has already been set to TRUE */ } while (!leave_loop); /* if semaphore has been successfully acquired, try to release it */ if (sem_status == OK) { if (sem_status = CSv_semaphore(&Psf_srvblk->psf_sem)) { status = E_DB_FATAL; /* bring down the server */ sem_errno = E_PS020B_BGNSES_RELSEM_FAILURE; } } /* ** if an error was encountered while trying to get or to release a ** semaphore, report it here */ if (sem_status != OK) { (VOID) psf_error(sem_errno, sem_status, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); } if (DB_FAILURE_MACRO(status)) { return(status); } /* ** Initialize the case translation semantics stuff */ sess_cb->pss_dbxlate = psq_cb->psq_dbxlate; sess_cb->pss_cat_owner = psq_cb->psq_cat_owner; /* ** Copy the user name and dba name to the session control block. */ STRUCT_ASSIGN_MACRO(psq_cb->psq_user.db_tab_own, sess_cb->pss_user); STRUCT_ASSIGN_MACRO(psq_cb->psq_dba, sess_cb->pss_dba); STRUCT_ASSIGN_MACRO(psq_cb->psq_group, sess_cb->pss_group); STRUCT_ASSIGN_MACRO(psq_cb->psq_aplid, sess_cb->pss_aplid); /* copy DBA name into sess_cb->pss_dbaname and NULL-terminate */ { u_i2 dba_name_len; dba_name_len = (u_i2) psf_trmwhite((u_i4) sizeof(sess_cb->pss_dba), (char *) &sess_cb->pss_dba); MEcopy((PTR) &sess_cb->pss_dba, dba_name_len, (PTR) sess_cb->pss_dbaname); sess_cb->pss_dbaname[dba_name_len] = EOS; } /* ** Build a DB_OWN_NAME which contains a session-unique owner name. This ** owner name will be used for temporary tables which are owned by this ** session. */ { char temp_sess_id[10]; STmove(DB_SESS_TEMP_OWNER, ' ', sizeof(sess_cb->pss_sess_owner), (char *)&sess_cb->pss_sess_owner); /* ** We can't convert directly into the sess_owner field because CVlx ** null-terminates the result, and we don't want the trailing null */ CVlx(sess_cb->pss_psessid, temp_sess_id); MEcopy(temp_sess_id, 8, &sess_cb->pss_sess_owner.db_own_name[5]); } /* ** Start with per-user quota of memory. Note that user may have overridden ** the default value at server startup in which case we will use calculated ** amount (pool/sessions); otherwise, default amount will be used. */ sess_cb->pss_memleft = (Psf_srvblk->psf_sess_mem) ? Psf_srvblk->psf_sess_mem : PSF_SESMEM; /* ** Initialize the user range table. */ if (pst_rginit(&sess_cb->pss_usrrange) != E_DB_OK) { return (E_DB_FATAL); } /* ** Initialize the auxiliary range table. */ if (pst_rginit(&sess_cb->pss_auxrng) != E_DB_OK) { return (E_DB_FATAL); } /* ** Open a memory stream for the symbol table. The symbol table is ** composed of a list of blocks. ** Allocate the symbol table at the same time. */ ulm_rcb.ulm_facility = DB_PSF_ID; ulm_rcb.ulm_poolid = Psf_srvblk->psf_poolid; ulm_rcb.ulm_blocksize = sizeof(PSS_SYMBLK); ulm_rcb.ulm_memleft = &sess_cb->pss_memleft; /* Set pointer to stream handle for ULM */ ulm_rcb.ulm_streamid_p = &sess_cb->pss_symstr; /* Open a private, thread-safe stream */ ulm_rcb.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC; ulm_rcb.ulm_psize = sizeof(PSS_SYMBLK); if (ulm_openstream(&ulm_rcb) != E_DB_OK) { if (ulm_rcb.ulm_error.err_code == E_UL0005_NOMEM) { (VOID) psf_error(E_PS0F02_MEMORY_FULL, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); } else { (VOID) psf_error(E_PS0A02_BADALLOC, ulm_rcb.ulm_error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); } return((ulm_rcb.ulm_error.err_code == E_UL0004_CORRUPT) ? E_DB_FATAL : E_DB_ERROR); } sess_cb->pss_symtab = (PSS_SYMBLK*) ulm_rcb.ulm_pptr; sess_cb->pss_symtab->pss_sbnext = (PSS_SYMBLK *) NULL; /* ** Allocate the YACC_CB. */ if ((status = psl_yalloc(sess_cb->pss_symstr, &sess_cb->pss_memleft, (PTR *) &sess_cb->pss_yacc, &psq_cb->psq_error)) != E_DB_OK) { /* ** If the allocation failed, remember to close the streams, so the ** memory associated with it will be freed. */ (VOID) ulm_closestream(&ulm_rcb); return (status); } /* ** Fill in the control block header. */ sess_cb->pss_next = (PSS_SESBLK *) NULL; sess_cb->pss_prev = (PSS_SESBLK *) NULL; sess_cb->pss_length = sizeof(PSS_SESBLK); sess_cb->pss_type = PSS_SBID; sess_cb->pss_owner = (PTR)DB_PSF_ID; sess_cb->pss_ascii_id = PSSSES_ID; /* ** Initialize the session control block. */ /* Save the session id */ sess_cb->pss_sessid = psq_cb->psq_sessid; /* Set pointer to session's ADF_CB */ sess_cb->pss_adfcb = (ADF_CB *) psq_cb->psq_adfcb; /* No cursors yet */ sess_cb->pss_numcursors = 0; /* Language has already been validated */ sess_cb->pss_lang = psq_cb->psq_qlang; /* Decimal spec has already been validated */ sess_cb->pss_decimal = psq_cb->psq_decimal.db_decimal; /* Distributed spec has already been validated */ sess_cb->pss_distrib = psq_cb->psq_distrib; /* Save the database id */ sess_cb->pss_dbid = psq_cb->psq_dbid; /* Save the unique database id */ sess_cb->pss_udbid = psq_cb->psq_udbid; /* Initialize QSF_RCB for use by psfmem.c functions */ sess_cb->pss_qsf_rcb.qsf_type = QSFRB_CB; sess_cb->pss_qsf_rcb.qsf_ascii_id = QSFRB_ASCII_ID; sess_cb->pss_qsf_rcb.qsf_length = sizeof(sess_cb->pss_qsf_rcb); sess_cb->pss_qsf_rcb.qsf_owner = (PTR)DB_PSF_ID; sess_cb->pss_qsf_rcb.qsf_sid = sess_cb->pss_sessid; /* ** so session reset all bit flags */ sess_cb->pss_stmt_flags = sess_cb->pss_stmt_flags2 = sess_cb->pss_dbp_flags = sess_cb->pss_ses_flag = 0L; sess_cb->pss_flattening_flags = 0; /* ** Default table create semantics are to assume journaling unless ** the PSF_NO_JNL_DEFAULT override is set. */ if ((Psf_srvblk->psf_flags & PSF_NO_JNL_DEFAULT) == 0) sess_cb->pss_ses_flag |= PSS_JOURNALING; /* catalog update flag */ if (psq_cb->psq_flag & PSQ_CATUPD) sess_cb->pss_ses_flag |= PSS_CATUPD; /* warnings on unsupported commands */ if (psq_cb->psq_flag & PSQ_WARNINGS) sess_cb->pss_ses_flag |= PSS_WARNINGS; /* INDICATE if the DBA may DROP everyone's tables */ if (psq_cb->psq_flag & PSQ_DBA_DROP_ALL) sess_cb->pss_ses_flag |= PSS_DBA_DROP_ALL; /* INDICATE if the session may SELECT everyone's tables */ if (psq_cb->psq_flag & PSQ_SELECT_ALL) sess_cb->pss_ses_flag |= PSS_SELECT_ALL; /* ** indicate that the session is allowed to INSERT/DELETE/UPDATE an index ** which is a catalog (but not an extended catalog */ if (psq_cb->psq_flag & PSQ_REPAIR_SYSCAT) sess_cb->pss_ses_flag |= PSS_REPAIR_SYSCAT; /* ** indicate that the session allows $ingres to drop/add constraint on ** tables owned by other users */ if (psq_cb->psq_flag & PSQ_INGRES_PRIV) sess_cb->pss_ses_flag |= PSS_INGRES_PRIV; if (psq_cb->psq_flag & PSQ_ROW_SEC_KEY) sess_cb->pss_ses_flag |= PSS_ROW_SEC_KEY; /* See if passwords, roles allowed */ if (psq_cb->psq_flag & PSQ_PASSWORD_NONE) sess_cb->pss_ses_flag |= PSS_PASSWORD_NONE; if (psq_cb->psq_flag & PSQ_ROLE_NONE) sess_cb->pss_ses_flag |= PSS_ROLE_NONE; if (psq_cb->psq_flag & PSQ_ROLE_NEED_PW) sess_cb->pss_ses_flag |= PSS_ROLE_NEED_PW; /* remember whether we are running UPGRADEDB */ if (psq_cb->psq_flag & PSQ_RUNNING_UPGRADEDB) sess_cb->pss_ses_flag |= PSS_RUNNING_UPGRADEDB; /* Pick up serverwide default for card check */ if (Psf_srvblk->psf_flags & PSF_NOCHK_SINGLETON_CARD) sess_cb->pss_ses_flag |= PSS_NOCHK_SINGLETON_CARD; /* Initialize pss_project. */ sess_cb->pss_ses_flag |= PSS_PROJECT; /* pss_project = TRUE */ /* init last statement */ sess_cb->pss_last_sname[0] = EOS; /* batch optimization switch starts undefined */ sess_cb->batch_copy_optim = PSS_BATCH_OPTIM_UNDEF; /* ** if starting a local session, determine whether the database is being ** journaled */ if (~psq_cb->psq_distrib & DB_3_DDB_SESS) { DMC_CB dmc_cb, *dmc = &dmc_cb; DMC_CHAR_ENTRY dmc_char; MEfill(sizeof(dmc_cb), (u_char) 0, (PTR) dmc); dmc->type = DMC_CONTROL_CB; dmc->length = sizeof(*dmc); dmc->dmc_op_type = DMC_DATABASE_OP; dmc->dmc_session_id = (PTR) sess_cb->pss_sessid; dmc->dmc_flags_mask = DMC_JOURNAL; dmc->dmc_char_array.data_address= (PTR) &dmc_char; dmc->dmc_char_array.data_out_size = sizeof(dmc_char); dmc->dmc_db_id = (char *) sess_cb->pss_dbid; status = dmf_call(DMC_SHOW, (PTR) dmc); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS020E_CANT_GET_DB_JOUR_STATUS, dmc->error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); return(status); } if (dmc_char.char_value == DMC_C_ON) { sess_cb->pss_ses_flag |= PSS_JOURNALED_DB; } } /* Save the storage structure for indexes */ sess_cb->pss_idxstruct = psq_cb->psq_idxstruct; /* Make session copy of parser compatability settings */ sess_cb->pss_parser_compat = psq_cb->psq_parser_compat; /* remember if NLs inside string constants need to be stripped */ if (psq_cb->psq_flag & PSQ_STRIP_NL_IN_STRCONST) sess_cb->pss_ses_flag |= PSS_STRIP_NL_IN_STRCONST; /* no rule tree yet */ sess_cb->pss_row_lvl_usr_rules = sess_cb->pss_row_lvl_sys_rules = sess_cb->pss_stmt_lvl_usr_rules = sess_cb->pss_stmt_lvl_sys_rules = sess_cb->pss_row_lvl_usr_before_rules = sess_cb->pss_row_lvl_sys_before_rules = sess_cb->pss_stmt_lvl_usr_before_rules = sess_cb->pss_stmt_lvl_sys_before_rules = (PST_STATEMENT *) NULL; if (psq_cb->psq_flag & PSQ_RULE_DEL_PREFETCH) sess_cb->pss_ses_flag |= PSS_RULE_DEL_PREFETCH; if(psq_cb->psq_flag2 & PSQ_RULE_UPD_PREFETCH) sess_cb->pss_ses_flag |= PSS_RULE_UPD_PREFETCH; /* copy user status flags to session control block */ sess_cb->pss_ustat = psq_cb->psq_ustat; /* ** Initialize lots of pointer to NULL because nothing is happening yet. */ sess_cb->pss_qbuf = sess_cb->pss_nxtchar = sess_cb->pss_prvtok = sess_cb->pss_bgnstmt = sess_cb->pss_endbuf = sess_cb->pss_prvgoval = (u_char *) NULL; /* initialize pss_audit */ sess_cb->pss_audit = NULL; for (i = 0; i < PSS_CURTABSIZE; i++) { sess_cb->pss_curstab.pss_curque[i] = (PSC_CURBLK *) NULL; } /* initialize prototype list for dynamic SQL */ sess_cb->pss_proto = (PST_PROTO *) NULL; /* ** pss_dependencies_stream, when not NULL, is expected to point at a valid ** stream descriptor. After closing the stream we always reset ** pss_dependencies_stream to NULL, but in some cases we may end up checking ** pss_dependencies_stream before ever opening (and closing it). As a ** result, you may end up using invalid address as a stream pointer. ** Initializing it here to NULL will ensure that it is non-NULL iff it ** points at a valid open stream descriptor. */ sess_cb->pss_dependencies_stream = (PSF_MSTREAM *) NULL; /* No trace flags set */ /* expect lint message */ ult_init_macro(&sess_cb->pss_trace, PSS_TBITS, PSS_TVALS, PSS_TVAO); /* Cursor id set to 0, no cursors open yet */ sess_cb->pss_crsid = 0; sess_cb->pss_create_compression = Psf_srvblk->psf_create_compression; /* SCF can pass a client requested result_structure, but if it ** doesn't, init from server default. */ if (psq_cb->psq_result_struct != 0) { sess_cb->pss_result_struct = psq_cb->psq_result_struct; sess_cb->pss_result_compression = psq_cb->psq_result_compression; } else { sess_cb->pss_result_struct = Psf_srvblk->psf_result_struct; sess_cb->pss_result_compression = Psf_srvblk->psf_result_compression; } if (psq_cb->psq_def_coll > DB_NOCOLLATION) sess_cb->pss_def_coll = psq_cb->psq_def_coll; else sess_cb->pss_def_coll = Psf_srvblk->psf_def_coll; if (psq_cb->psq_def_unicode_coll > DB_NOCOLLATION) sess_cb->pss_def_unicode_coll = psq_cb->psq_def_unicode_coll; else sess_cb->pss_def_unicode_coll = Psf_srvblk->psf_def_unicode_coll; return (E_DB_OK); }
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: psl_lm4_setlockparm_num() - perform semantic action for SETLOCKPARM ** production when the characteristic value ** has been specified as a number or a string ** constant containing a number ** ** Input: ** char_type characteristic type ** char_val value as specified by the user ** sess_cb PSF session CB ** pss_distrib DB_3_DDB_SESS if distributed thread ** pss_stmt_flags PSS_SET_LOCKMODE_SESS if SET LOCKMODE ** SESSION (distributed thread only) ** pss_object points to DMC_CB (or QEF_RCB) structure ** dmc_char_array characteristics array ** dmc_sl_scope scope of SET LOCKMODE ** pss_auxrng ** pss_rerng if setting lockmode on a table, table's ** description can be found here ** ** Output: ** err_blk filled in if an error occurred ** ** Returns: ** E_DB_{OK, ERROR, SEVERE} ** ** Side effects: ** None ** ** History: ** 07-mar-91 (andre) ** plagiarized from SETLOCKPARM production ** 21-apr-92 (barbara) ** Added support for Sybil. For distributed thread, on ** SET LOCKMODE SESSION .. TIMEOUT we set timeout value ** specifically for QEF. ** 19-oct-92 (barbara) ** Test for non_distrib before testing dmc_cb fields (because ** Star doesn't have valid dmc_cb). */ DB_STATUS psl_lm4_setlockparm_num( i4 char_type, i4 char_val, PSS_SESBLK *sess_cb, DB_ERROR *err_blk) { i4 err_code, err_no = 0L; DMC_CHAR_ENTRY *chr; DMC_CB *dmc_cb; bool not_distr = ~sess_cb->pss_distrib & DB_3_DDB_SESS; if (not_distr) { dmc_cb = (DMC_CB *) sess_cb->pss_object; if (dmc_cb->dmc_char_array.data_in_size / sizeof (DMC_CHAR_ENTRY) == MAX_LOCKMODE_CHARS) { (VOID) psf_error(5931L, 0L, PSF_USERERR, &err_code, err_blk, 0); return (E_DB_ERROR); /* non-zero return means error */ } chr = (DMC_CHAR_ENTRY *) ((char *) dmc_cb->dmc_char_array.data_address + dmc_cb->dmc_char_array.data_in_size); } switch (char_type) { case LOCKLEVEL: /* Can't set locklevel to a number */ err_no = 5924L; break; case READLOCK: /* Can't set readlocks to a number */ err_no = 5925L; break; case MAXLOCKS: if (not_distr) { chr->char_id = DMC_C_LMAXLOCKS; } break; case TIMEOUT: { extern PSF_SERVBLK *Psf_srvblk; /* ** if server was started with OPF flag which may result in ** deadlock when accesing SCONSUR catalogs, iihistogram, and ** iistatistics, we have to prevent user from specifying ** TIMEOUT=0 for any of these catalogs */ if (not_distr && Psf_srvblk->psf_flags & PSF_NO_ZERO_TIMEOUT && dmc_cb->dmc_sl_scope == DMC_SL_TABLE) { DB_TAB_ID *tabid = &dmc_cb->dmc_table_id; PSS_RNGTAB *tbl = &sess_cb->pss_auxrng.pss_rsrng; i4 mask = tbl->pss_tabdesc->tbl_status_mask; if (mask & DMT_CATALOG && char_val == 0L && (mask & DMT_CONCURRENCY || tabid->db_tab_base == DM_B_STATISTICS_TAB_ID && tabid->db_tab_index == DM_I_STATISTICS_TAB_ID || tabid->db_tab_base == DM_B_HISTOGRAM_TAB_ID && tabid->db_tab_index == DM_I_HISTOGRAM_TAB_ID ) ) { (VOID) psf_error(E_PS0352_ILLEGAL_0_TIMEOUT, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(tbl->pss_tabname), (char *) &tbl->pss_tabname), &tbl->pss_tabname); return (E_DB_ERROR); } } if (not_distr) { chr->char_id = DMC_C_LTIMEOUT; } else if (sess_cb->pss_stmt_flags & PSS_SET_LOCKMODE_SESS) { /* ** The distributed server is interested in the value from ** the SETLOCKKEY production when the SETLOCKSCOPE value ** was session; otherwise the set statement is just ** pased on to the LDBs. */ ((QEF_RCB*)sess_cb->pss_object)->qef_r3_ddb_req. qer_d14_ses_timeout = char_val; } break; } default: /* Unknown "set lockmode" parameter */ (VOID) psf_error(E_PS0351_UNKNOWN_LOCKPARM, 0L, PSF_INTERR, &err_code, err_blk, 1, (i4) sizeof(char_type), &char_type); return (E_DB_SEVERE); /* non-zero return means error */ } if (err_no != 0L) { char num_buf[30]; CVla((i4) char_val, num_buf); (VOID) psf_error(err_no, 0L, PSF_USERERR, &err_code, err_blk, 1, (i4) STlength(num_buf), num_buf); return (E_DB_ERROR); /* non-zero return means error */ } else if (not_distr) { chr->char_value = char_val; dmc_cb->dmc_char_array.data_in_size += sizeof (DMC_CHAR_ENTRY); } return(E_DB_OK); }
/*{ ** 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_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); }
/* ** NOTE: in SQL grammar target_list of a subselect is processed BEFORE the ** from_list; consequently, data types of target list elements are not ** known when we build RESDOM nodes for the target list elements of form ** [<corr_name>.]<col_name>. In psl_p_tlist(), we revisit the prototype ** tree and fill in the newly available information (type, length, ** precision, etc.) ** ** When making changes to pst_adresdom(), please take time to understand ** the effect these changes may have on the processing of prototype trees. */ DB_STATUS pst_adresdom( char *attname, PST_QNODE *left, PST_QNODE *right, PSS_SESBLK *cb, PSQ_CB *psq_cb, PST_QNODE **newnode) { DB_STATUS status; DMT_ATT_ENTRY *coldesc; DMT_ATT_ENTRY column; PSS_RNGTAB *resrange; char colname[sizeof(DB_ATT_NAME) + 1]; /* null term. */ PST_RSDM_NODE resdom; i4 err_code; PSC_RESCOL *rescol; ADF_CB *adf_scb; i2 null_adjust = 0; i4 temp_collID; /* Convert column name to a null-terminated string. */ (VOID) MEcopy((PTR) attname, sizeof(DB_ATT_NAME), (PTR) colname); colname[sizeof(DB_ATT_NAME)] = '\0'; (VOID) STtrmwhite(colname); /* For these operations, the result domain comes from the result table */ if (psq_cb->psq_mode == PSQ_APPEND || psq_cb->psq_mode == PSQ_PROT) { /* Get the result range variable */ if (psq_cb->psq_qlang == DB_SQL) { resrange = &cb->pss_auxrng.pss_rsrng; } else { resrange = &cb->pss_usrrange.pss_rsrng; } /* "tid" result column not allowed with these operations */ if (!STcasecmp(((*cb->pss_dbxlate & CUI_ID_REG_U) ? "TID" : "tid"), colname )) { psf_error(2100L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4, (i4) sizeof(cb->pss_lineno), &cb->pss_lineno, psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &resrange->pss_tabname), &resrange->pss_tabname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &resrange->pss_ownname), &resrange->pss_ownname, psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname); return (E_DB_ERROR); } /* Get the column description */ coldesc = pst_coldesc(resrange, (DB_ATT_NAME *) attname); if (coldesc == (DMT_ATT_ENTRY *) NULL) { psf_error(2100L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4, (i4) sizeof(cb->pss_lineno), &cb->pss_lineno, psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &resrange->pss_tabname), &resrange->pss_tabname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &resrange->pss_ownname), &resrange->pss_ownname, psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname); return (E_DB_ERROR); } if (coldesc->att_flags & DMU_F_SYS_MAINTAINED) { psf_error(E_US1900_6400_UPD_LOGKEY, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4, (i4) sizeof(cb->pss_lineno), &cb->pss_lineno, psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &resrange->pss_tabname), &resrange->pss_tabname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &resrange->pss_ownname), &resrange->pss_ownname, psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname); return (E_DB_ERROR); } } else if (psq_cb->psq_mode == PSQ_REPLACE) { /* ** For the "replace" command, use the result range variable that's ** in the normal user range table, not the special slot that's ** reserved for the result table in the append command. */ /* Get the result range variable */ resrange = cb->pss_resrng; /* "tid" result column not allowed with these operations */ if (!STcasecmp(((*cb->pss_dbxlate & CUI_ID_REG_U) ? "TID" : "tid"), colname)) { psf_error(2100L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4, (i4) sizeof(cb->pss_lineno), &cb->pss_lineno, psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &resrange->pss_tabname), &resrange->pss_tabname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &resrange->pss_ownname), &resrange->pss_ownname, psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname); return (E_DB_ERROR); } /* Get the column description */ coldesc = pst_coldesc(resrange, (DB_ATT_NAME *) attname); if (coldesc == (DMT_ATT_ENTRY *) NULL) { psf_error(2100L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4, (i4) sizeof(cb->pss_lineno), &cb->pss_lineno, psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &resrange->pss_tabname), &resrange->pss_tabname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &resrange->pss_ownname), &resrange->pss_ownname, psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname); return (E_DB_ERROR); } if (coldesc->att_flags & DMU_F_SYS_MAINTAINED) { psf_error(E_US1900_6400_UPD_LOGKEY, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 4, (i4) sizeof(cb->pss_lineno), &cb->pss_lineno, psf_trmwhite(sizeof(DB_TAB_NAME), (char *) &resrange->pss_tabname), &resrange->pss_tabname, psf_trmwhite(sizeof(DB_OWN_NAME), (char *) &resrange->pss_ownname), &resrange->pss_ownname, psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname); return (E_DB_ERROR); } } else if (psq_cb->psq_mode == PSQ_REPCURS) { /* ** For the "replace cursor" command, the info comes from the cursor ** control block. Cursor column list and update map should always ** specify same column set, so the second if statemnt (BTtest) could, ** perhaps, be removed. */ rescol = psq_ccol(cb->pss_crsr, (DB_ATT_NAME *) attname); if (rescol == (PSC_RESCOL *) NULL) { psf_error(2207L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 3, sizeof(cb->pss_lineno), &cb->pss_lineno, psf_trmwhite(DB_CURSOR_MAXNAME, cb->pss_crsr->psc_blkid.db_cur_name), cb->pss_crsr->psc_blkid.db_cur_name, psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname); return (E_DB_ERROR); } /* Make sure the column was declared "for update" */ if (!BTtest((i4) rescol->psc_attid.db_att_id, (char *) &cb->pss_crsr->psc_updmap)) { psf_error(2207L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 3, sizeof(cb->pss_lineno), &cb->pss_lineno, psf_trmwhite(DB_CURSOR_MAXNAME, cb->pss_crsr->psc_blkid.db_cur_name), cb->pss_crsr->psc_blkid.db_cur_name, psf_trmwhite(sizeof(DB_ATT_NAME), attname), attname); return (E_DB_ERROR); } /* Set up column descriptor */ coldesc = &column; MEcopy((char *) attname, sizeof(DB_ATT_NAME), (char *) &coldesc->att_name); #ifdef NO /* ** Count columns. Give error if too many. One extra for tid. */ cb->pss_rsdmno++; if (cb->pss_rsdmno > (DB_MAX_COLS + 1)) { psf_error(2130L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 1, (i4) sizeof(cb->pss_lineno), &cb->pss_lineno); return (E_DB_ERROR); } coldesc->att_number = cb->pss_rsdmno; #endif coldesc->att_number = rescol->psc_attid.db_att_id; coldesc->att_type = rescol->psc_type; coldesc->att_width = rescol->psc_len; coldesc->att_prec = rescol->psc_prec; coldesc->att_collID = -1; coldesc->att_geomtype = -1; coldesc->att_srid = -1; coldesc->att_encflags = 0; coldesc->att_encwid = 0; } else { /* ** In all other cases, just take the datatype info ** from the right child. */ coldesc = &column; MEcopy((char *) attname, sizeof(DB_ATT_NAME), (char *) &coldesc->att_name); /* ** Count columns. Give error if too many. One extra for tid. */ cb->pss_rsdmno++; if (cb->pss_rsdmno > (DB_MAX_COLS + 1)) { psf_error(2130L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 1, (i4) sizeof(cb->pss_lineno), &cb->pss_lineno); return (E_DB_ERROR); } coldesc->att_number = cb->pss_rsdmno; status = pst_rsdm_dt_resolve(right, coldesc, cb, psq_cb); if (DB_FAILURE_MACRO(status)) return(status); } /* Copy attribute information into PST_RSDM_NODE */ resdom.pst_rsno = coldesc->att_number; /* The two fields below are initialized for a common case. ** They are context sensitive and in many cases may have to be ** modified by the caller of this routine. */ resdom.pst_ntargno = resdom.pst_rsno; resdom.pst_ttargtype = PST_USER; resdom.pst_dmuflags = 0; /* Don't bother with the conversion id for now */ /* Not for update until we know otherwise */ resdom.pst_rsupdt = FALSE; resdom.pst_rsflags = PST_RS_PRINT; MEcopy((char *) &coldesc->att_name, sizeof(DB_ATT_NAME), (char *) resdom.pst_rsname); temp_collID = coldesc->att_collID; /* If client can not handle i8 INTs downgrade to i4 */ adf_scb = (ADF_CB *) cb->pss_adfcb; if ( !(adf_scb->adf_proto_level & AD_I8_PROTO) && (abs(coldesc->att_type) == DB_INT_TYPE) ) { if(coldesc->att_type < 0) { null_adjust = 1; } if((coldesc->att_width - null_adjust) == sizeof(i8)) { coldesc->att_width -= sizeof(i4); } } /* Now allocate the node */ status = pst_node(cb, &cb->pss_ostream, left, right, PST_RESDOM, (char *) &resdom, sizeof(PST_RSDM_NODE), (DB_DT_ID) coldesc->att_type, (i2) coldesc->att_prec, (i4) coldesc->att_width, (DB_ANYTYPE *) NULL, newnode, &psq_cb->psq_error, (i4) 0); if (status != E_DB_OK) { return (status); } (*newnode)->pst_sym.pst_dataval.db_collID = temp_collID; /* Remember the last result domain produced */ cb->pss_tlist = *newnode; return (E_DB_OK); }
/*{ ** Name: psy_kpermit - Destroy one or more permits on a database object ** (a table or a procedure or an event). ** ** INTERNAL PSF call format: status = psy_kpermit(&psy_cb, &sess_cb); ** ** EXTERNAL call format: status = psy_call(PSY_KPERMIT, &psy_cb, &sess_cb); ** ** Description: ** The psy_kpermit function removes the definition of one or more permits ** on a table, a procedure, or an event from all system relations ** (protect, tree, and iiqrytext). ** Optionally, one can tell this function to destroy all of the permits ** on a given table, procedure or event. ** ** Dropping all permits on a table is similar enough to dropping those on ** a procedure, so we will handle them together. On the other hand, when ** permit numbers are specified, processing is somewhat differen, e.g. ** we (at least for now) disallow dropping 0 and 1 on a dbproc. ** Events follow exactly the same model as procedures. ** Inputs: ** psy_cb ** .psy_tables[0] Id of table for which to destroy ** permit(s) ** .psy_numbs[] Id numbers of the permits to destroy ** (20 maximum) ** .psy_numnms Number of permit numbers given. Zero ** means to destroy all of the permits on ** the given table. ** .psy_tabname[0] Name of the table for which to destroy ** permit(s) ** .psy_grant PSY_PDROP if dropping permits on ** dbproc(s); ** PSY_TDROP if dropping permits on ** table(s). ** PSY_SDROP if dropping security alarms. ** PSY_EVDROP if dropping permits on ** event(s). ** sess_cb Pointer to session control block. ** ** Outputs: ** psy_cb ** .psy_error Filled in if an error happens ** .err_code What the error was ** E_PS0000_OK Success ** E_PS0001_USER_ERROR User made a mistake ** E_PS0002_INTERNAL_ERROR Internal inconsistency in PSF ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s) ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Deletes query tree representing predicate of permit from tree ** relation, query text of permit definition from iiqrytext relation, ** does a dmf alter table on the base table to indicate that there ** are no more permissions on it should that happen to be the case. ** ** History: ** 02-oct-85 (jeff) ** written ** 05-aug-88 (andre) ** modified for DROPping permits on dbprocs. ** 03-oct-88 (andre) ** Modify call to pst_rgent to pass 0 as a query mode since it is ** clearly not PSQ_DESTROY. ** 04-oct-88 (andre) ** Make sure that the highest status received is reported to caller ** 02-nov-89 (neil) ** Alerters: Changes for dropping permits on events. ** 16-jan-90 (ralph) ** Add integrity check for DROP PERMIT/SECURITY_ALARM: ** don't allow drop permit to drop a security alarm; ** don't allow drop security_alarm to drop a permit. ** Initialise status to E_DB_OK. ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 04-feb-91 (neil) ** Fix 2 error cases: ** 1. If pst_rgent returns E_PS0903_TAB_NOTFOUND then return this ** error to the user. Can happen through Dynamic SQL where you ** drop the table before you exec the statement that drops grant. ** 2. Allow E_RD0025_USER_ERROR from RDF_UPDATE and continue. ** 29-aug-91 (andre) ** Do not call RDF to destroy permits if the object is a QUEL view ** owned by the DBA. ** ** Until now we could safely assume that if a view is non-grantable and ** there are permits defined on it, then the view is a QUEL view owned ** by the DBA and the only permit defined on it is an access permit. ** With advent of GRANT WGO, there may be permits defined on views ** marked as non-grantable (since "grantable" means that the view is ** defined on top of the objects owned by its owner so that its owner ** can always grant access to the view) and grantable QUEL views will ** be marked as such (this way if a user creates an SQL view on top of ** his grantable QUEL view we are guaranteed that the new view is also ** grantable). By not trying to destroy permits on QUEL views owned by ** the DBA we will ensure that a user cannot destroy an access permit ** which gets created for QUEL views owned by the DBA. ** 16-jun-92 (barbara) ** Change interface to pst_rgent. ** 22-jul-92 (andre) ** permits 0 and 1 will no longer hold special meaning for tables; in ** the past they meant ALL/RETRIEVE TO ALL, but with introduction of ** grantable privileges, they will no longer be created. Whether ** permit numbers 0 and 1 will become available for regular permits ** needs to be decided, but one thing is for sure, psy_kpermit() will ** not need to know about it. ** ** If user is destroying all permits or security_alarms, set ** RDR_DROP_ALL over rdr_types_mask ** 27-jul-92 (andre) ** we may be told that we may not drop a permit or all permits because ** it would render some permit or object abandoned ** 03-aug-92 (barbara) ** Invalidate base table info from RDF cache. ** 07-aug-92 (teresa) ** RDF_INVALID must be called to invalidate the base object from RDF's ** relation cache as well as to remove any permit trees from RDF's ** qtree cache. ** 08-nov-92 (andre) ** having dropped ALL permits on PROCEDURE, remember to set ** RDR_PROCEDURE in rdf_inv_cb.rdf_rb.rdr_types_mask before calling ** RDF_INVALIDATE ** 26-apr-93 (markg) ** Fixed bug which caused AV when attempting to drop a ** security_alarm. The problem was caused by incorrectly ** referencing a NULL pointer when initializing a local variable. ** 10-aug-93 (andre) ** fixed cause of compiler warning ** 13-sep-93 (andre) ** PSF will no longer be in business of altering timestamps of tables ** (or underlying base tables of views) on which permit(s) or ** security_alarm(s) have been dropped - responsibility for this has ** been assumed by QEF */ DB_STATUS psy_kpermit( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; RDF_CB rdf_inv_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; DB_STATUS status = E_DB_OK; i4 err_code; i4 msgid; register i4 i; PSS_RNGTAB *rngvar; /* Fill in RDF control block */ pst_rdfcb_init(&rdf_cb, sess_cb); pst_rdfcb_init(&rdf_inv_cb, sess_cb); STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[0], rdf_rb->rdr_tabid); STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[0], rdf_inv_cb.rdf_rb.rdr_tabid); rdf_inv_cb.rdf_rb.rdr_types_mask = RDR_PROTECT; rdf_rb->rdr_update_op = RDR_DELETE; if (psy_cb->psy_grant == PSY_TDROP) /* dropping perm on a table */ { /* get range table entry for this table */ status = pst_rgent(sess_cb, &sess_cb->pss_auxrng, -1, "", PST_SHWID, (DB_TAB_NAME*) NULL, (DB_TAB_OWN*) NULL, &psy_cb->psy_tables[0], TRUE, &rngvar, (i4) 0, &psy_cb->psy_error); if (DB_FAILURE_MACRO(status)) { if (psy_cb->psy_error.err_code == E_PS0903_TAB_NOTFOUND) { (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); } return (status); } rdf_rb->rdr_types_mask = RDR_PROTECT; } else if (psy_cb->psy_grant == PSY_SDROP) /* dropping security alarm */ { rdf_rb->rdr_types_mask = RDR_SECALM; } else if (psy_cb->psy_grant == PSY_PDROP) /* dropping perm on a dbproc */ { DB_DBP_NAME *dbpname = (DB_DBP_NAME *) psy_cb->psy_tabname; /* save dbproc name and owner for RDF */ STRUCT_ASSIGN_MACRO(*dbpname, rdf_rb->rdr_name.rdr_prcname); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner); rdf_rb->rdr_types_mask = RDR_PROTECT | RDR_PROCEDURE; rdf_inv_cb.rdf_rb.rdr_types_mask |= RDR_PROCEDURE; } else if (psy_cb->psy_grant == PSY_EVDROP) /* dropping perm on event */ { DB_EVENT_NAME *evname = (DB_EVENT_NAME *)psy_cb->psy_tabname; /* Save event name and owner for RDF */ STRUCT_ASSIGN_MACRO(*evname, rdf_rb->rdr_name.rdr_evname); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner); rdf_rb->rdr_types_mask = RDR_PROTECT | RDR_EVENT; } /* Zero permit numbers means destroy all permits */ if (psy_cb->psy_numnms == 0) { /* ** Note that this block handles destroying all permits on ** a dbproc, event or a table or all security_alarms on a table */ /* ** check if user may drop permits (access permits get special ** treatment). If not, we are done. */ if (psy_cb->psy_grant == PSY_TDROP) { /* ** if this is a QUEL view owned by the DBA, avoid calling RDF since ** we need to rpevent a user from destroying access permit which is ** created on such views. */ if ( rngvar->pss_tabdesc->tbl_status_mask & DMT_VIEW && !MEcmp((PTR) &sess_cb->pss_dba, (PTR) &rngvar->pss_ownname, sizeof(DB_OWN_NAME)) ) { /* check if this is a QUEL view */ i4 issql = 0; status = psy_sqlview(rngvar, sess_cb, &psy_cb->psy_error, &issql); if (DB_FAILURE_MACRO(status)) { return(status); } if (!issql) { return(E_DB_OK); } } } /* tell RDF that we are dropping ALL permits or security_alarms */ rdf_rb->rdr_types_mask |= RDR_DROP_ALL; status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { switch (rdf_cb.rdf_error.err_code) { case E_RD0002_UNKNOWN_TBL: { (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); break; } case E_RD0201_PROC_NOT_FOUND: { (VOID) psf_error(E_PS0905_DBP_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); break; } case E_RD0210_ABANDONED_OBJECTS: { char *obj_type; i4 type_len; switch (psy_cb->psy_grant) { case PSY_TDROP: obj_type = "table"; type_len = sizeof("table") - 1; break; case PSY_PDROP: obj_type = "database procedure"; type_len = sizeof("database procedure") - 1; break; case PSY_EVDROP: obj_type = "dbevent"; type_len = sizeof("dbevent") - 1; break; default: obj_type = "UNKNOWN OBJECT TYPE"; type_len = sizeof("UNKNOWN OBJECT TYPE") - 1; break; } (VOID) psf_error(E_PS0564_ALLPROT_ABANDONED_OBJ, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 2, type_len, obj_type, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) psy_cb->psy_tabname), psy_cb->psy_tabname); break; } default: { /* Event errors are handled in QEF */ (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } } return (status); } /* ** Invalidate base object's infoblk from RDF cache; rdr_tabid ** already contains base table id; Call RDF to invalidate the ** base object. Then call again to invalidate any permit trees, ** set rdr_2_types mask for tree. */ status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); /* drop infoblk */ if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); return(status); } rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_CLASS; /* drop permit trees */ status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); return(status); } } else if (psy_cb->psy_grant == PSY_PDROP || psy_cb->psy_grant == PSY_EVDROP) { DB_STATUS stat; /* Run through permit numbers, destroying each one */ for (i = 0; i < psy_cb->psy_numnms; i++) { rdf_rb->rdr_qrymod_id = psy_cb->psy_numbs[i]; stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); /* remember the error to report later */ status = (status > stat) ? status : stat; if (DB_FAILURE_MACRO(status)) { switch (rdf_cb.rdf_error.err_code) { case E_RD0201_PROC_NOT_FOUND: { (VOID) psf_error(E_PS0905_DBP_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); break; } case E_RD0210_ABANDONED_OBJECTS: { char *obj_type; i4 type_len; if (psy_cb->psy_grant == PSY_PDROP) { obj_type = "database procedure"; type_len = sizeof("database procedure") - 1; } else { obj_type = "dbevent"; type_len = sizeof("dbevent") - 1; } (VOID) psf_error(E_PS0565_PROT_ABANDONED_OBJ, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 3, sizeof(psy_cb->psy_numbs[i]), psy_cb->psy_numbs + i, type_len, obj_type, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) psy_cb->psy_tabname), psy_cb->psy_tabname); break; } case E_RD0013_NO_TUPLE_FOUND: { (VOID) psf_error((i4) 5204, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof (rdf_rb->rdr_qrymod_id), &rdf_rb->rdr_qrymod_id); continue; } case E_RD0025_USER_ERROR: /* ** Warning already handled - may be repeated when ** we try some more updates (if this is a multi- ** permit drop). */ if (psy_cb->psy_grant == PSY_EVDROP) { status = E_DB_OK; continue; } /* else fall through */ default: { /* Event-specific errors are reported through QEF */ (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); break; } } return (status); } /* ** Invalidate base object's infoblk from RDF cache: rdr_tabid ** already contains base table id; rdr_sequence contains ** permit number; set rdr_2_types mask. */ rdf_inv_cb.rdf_rb.rdr_sequence = psy_cb->psy_numbs[i]; rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_ALIAS; status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); return(status); } } /* ** invalidate the relation cache entry that the permit was defined on */ rdf_inv_cb.rdf_rb.rdr_2types_mask &= ~RDR2_ALIAS; status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); return(status); } } else /* drop permit or security alarm on a table */ { DB_STATUS stat; bool cant_drop_perms = FALSE; if (psy_cb->psy_grant == PSY_TDROP) { i4 mask = rngvar->pss_tabdesc->tbl_status_mask; /* ** if this is a QUEL view owned by the DBA, avoid calling RDF since ** we need to rpevent a user from destroying access permit which is ** created on such views. Instead, we will act as if the tuple was ** not found by QEF (without actually calling it.) */ if ( mask & DMT_VIEW && !MEcmp((PTR) &sess_cb->pss_dba, (PTR) &rngvar->pss_ownname, sizeof(DB_OWN_NAME)) ) { /* check if this is a QUEL view */ i4 issql = 0; status = psy_sqlview(rngvar, sess_cb, &psy_cb->psy_error, &issql); if (DB_FAILURE_MACRO(status)) { return(status); } if (!issql) { cant_drop_perms = TRUE; /* errors will be reported later */ status = E_DB_ERROR; } } } /* Run through permit or security_alarm numbers, destroying each one */ for (i = 0; i < psy_cb->psy_numnms; i++) { if (cant_drop_perms) { (VOID) psf_error(5204L, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof (psy_cb->psy_numbs[i]), (PTR) &psy_cb->psy_numbs[i]); continue; } else { rdf_rb->rdr_qrymod_id = psy_cb->psy_numbs[i]; } stat = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); /* remember the error to report later */ status = (status > stat) ? status : stat; if (DB_FAILURE_MACRO(stat)) { switch (rdf_cb.rdf_error.err_code) { case E_RD0002_UNKNOWN_TBL: { (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) &psy_cb->psy_tabname[0]), &psy_cb->psy_tabname[0]); break; } case E_RD0210_ABANDONED_OBJECTS: { (VOID) psf_error(E_PS0565_PROT_ABANDONED_OBJ, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 3, sizeof(psy_cb->psy_numbs[i]), psy_cb->psy_numbs + i, sizeof("table") - 1, "table", psf_trmwhite(sizeof(psy_cb->psy_tabname[0]), (char *) psy_cb->psy_tabname), psy_cb->psy_tabname); break; } case E_RD0013_NO_TUPLE_FOUND: { if (psy_cb->psy_grant == PSY_SDROP) msgid = (i4)5213; else msgid = (i4)5204; (VOID) psf_error(msgid, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof (rdf_rb->rdr_qrymod_id), &rdf_rb->rdr_qrymod_id); continue; } default: { (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); break; } } return (status); } /* ** Invalidate base object's infoblk from RDF cache: rdr_tabid ** already contains base table id; rdr_sequence contains ** permit number (if not drop security alarm); set rdr_2_types mask. */ if (psy_cb->psy_grant == PSY_SDROP) { rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_KILLTREES; } else { rdf_inv_cb.rdf_rb.rdr_2types_mask |= RDR2_ALIAS; rdf_inv_cb.rdf_rb.rdr_types_mask = RDR_PROTECT; } status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); return(status); } } /* now invalidate the base object that the permit was defined on */ rdf_inv_cb.rdf_rb.rdr_2types_mask &= ~(RDR2_ALIAS | RDR2_KILLTREES); status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_inv_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_inv_cb.rdf_error, &psy_cb->psy_error); return(status); } } return (status); }
/*{ ** Name: psy_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); }