DB_STATUS qeq_c2_delete( QEF_RCB *v_qer_p, QEE_DSH *i_dsh_p ) { DB_STATUS status = E_DB_OK; QES_DDB_SES *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses; QES_QRY_SES *qss_p = & dds_p->qes_d8_union.u2_qry_ses; QEE_DDB_CB *qee_p = i_dsh_p->dsh_ddb_cb; QEF_QP_CB *qp_p = i_dsh_p->dsh_qp_ptr; QEQ_DDQ_CB *ddq_p = & qp_p->qp_ddq_cb; bool log_qry_55 = FALSE, log_err_59 = FALSE; i4 i4_1, i4_2; RQR_CB rqr, *rqr_p = & rqr; if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55, & i4_1, & i4_2)) { log_qry_55 = TRUE; qeq_p34_del_csr(v_qer_p, i_dsh_p); } if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59, & i4_1, & i4_2)) log_err_59 = TRUE; /* 2. set up to call RQR_DELETE */ MEfill(sizeof(rqr), '\0', (PTR) & rqr); rqr_p->rqr_session = dds_p->qes_d3_rqs_p; /* RQF session id */ rqr_p->rqr_tabl_name = ddq_p->qeq_d7_deltable; rqr_p->rqr_own_name = ddq_p->qeq_d9_delown; /* pass owner/table name for ** CURSOR DELETE */ rqr_p->rqr_timeout = QEK_0_TIME_QUANTUM; rqr_p->rqr_q_language = qss_p->qes_q2_lang; rqr_p->rqr_1_site = qss_p->qes_q3_ldb_p; STRUCT_ASSIGN_MACRO(qee_p->qee_d5_local_qid, rqr_p->rqr_qid); qss_p->qes_q1_qry_status |= QES_03Q_PHASE2; /* enter phase 2 for update */ status = qed_u3_rqf_call(RQR_DELETE, rqr_p, v_qer_p); if (status) { if (log_err_59 && ! log_qry_55) qeq_p34_del_csr(v_qer_p, i_dsh_p); } else { qss_p->qes_q1_qry_status &= ~QES_03Q_PHASE2; /* enter phase 2 for update */ v_qer_p->qef_rowcount = rqr_p->rqr_tupcount; v_qer_p->qef_count = rqr_p->rqr_tupcount; } return(status); }
/*{ ** Name: sxf_chk_sess_trace - Checks if a session trace flag is set. ** ** Description: ** Checks to see if a session trace flag is set. ** ** Inputs: ** None ** ** Outputs: ** Returns: ** bool ** ** History: ** 5-jul-93 (robf) ** Created */ bool sxf_chk_sess_trace(i4 flag) { DB_STATUS status; SXF_SCB *scb; i4 err_code; i4 val1,val2; /* ** Only check if there is tracing ** This saves the call to SCF if no tracing is needed */ if(sxf_tracing_on==FALSE) return FALSE; /* ** Get session id */ status = sxau_get_scb(&scb, &err_code); if( status!=E_DB_OK) { return FALSE; } /* ** Check if trace flag is set */ if(ult_check_macro(&scb->sxf_trace, flag, &val1, &val2)) return TRUE; else return FALSE; }
/*{ ** Name: psy_put - Put characters in blocks for output ** ** Description: ** This function buffers up characters to be sent to the user by SCF. ** It puts as much of the current request in the current block as ** possible. If there is any overflow, it allocates another block and ** puts the excess there. It keeps doing this until all the input is ** used up. ** ** Inputs: ** mstream Memory stream to use for allocating ** blocks. ** inbuf Characters to send to user ** len Number of chars to send to user ** block Pointer to pointer to block to use ** err_blk Filled in if an error happens ** ** Outputs: ** block Filled in with string to send to user. ** A new block may be allocated and this ** pointer modified to point to new one. ** err_blk Filled in if an error happened ** Returns: ** E_DB_OK Success ** E_DB_FATAL Failure ** Exceptions: ** none ** ** Side Effects: ** Can allocate memory ** ** History: ** 15-jul-86 (jeff) ** written */ DB_STATUS psy_put( PSF_MSTREAM *mstream, register char *inbuf, register i4 len, PSY_QTEXT **block, DB_ERROR *err_blk) { i4 tocopy; i4 left; char *outplace; PSY_QTEXT *newblock; DB_STATUS status; #ifdef xDEBUG i4 val1, val2; /* tracing temps */ PSS_SESBLK *sess_cb; sess_cb = psf_sesscb(); #endif while (len > 0) { /* Copy as much of input as will fit in current block */ left = PSY_QTSIZE - (*block)->psy_qcount; tocopy = len > left ? left : len; outplace = (*block)->psy_qtext + (*block)->psy_qcount; #ifdef xDEBUG if (ult_check_macro(&sess_cb->pss_trace, PSS_PSY_PUT_TRACE, &val1, &val2)) { TRdisplay("%.#s", tocopy, inbuf); } #endif MEcopy(inbuf, tocopy, outplace); len -= tocopy; (*block)->psy_qcount += tocopy; inbuf += tocopy; /* If there is more input, create another block and link it up */ if (len > 0) { status = psy_txtalloc(mstream, &newblock, err_blk); if (DB_FAILURE_MACRO(status)) return (status); (*block)->psy_qnext = newblock; /* Use the new block until a new one is allocated */ *block = newblock; } } return (E_DB_OK); }
/* ** Name: qeu_evraise ** ** Description: ** This routine raises an event, it processes the external request ** QEU_RAISE_EVENT, typically when raising the event associated with ** a security alarm. ** ** Note this *does* do event tracing (SET PRINTEVENTS/LOGEVENTS) ** but does *not* do security checks/auditing on the operation, this ** is assumed to be handled at a higher level. ** ** Inputs: ** qef_rcb.evname - Event name ** qef_rcb.evowner - Event owner ** qef_rcb.evtext - Event text ** qef_rcb.ev_l_text- Length of text ** ** History: ** 26-nov-93 (robf) ** Created for secure 2.0 ** 12-Jan-1998 (kinpa04/merja01) ** Remove (i4) casting of session id. This caused the ** session ID to get truncated on axp_osf while raising events. ** 10-Jan-2001 (jenjo02) ** We know this session's id; pass it to SCF. ** 30-Dec-2005 (kschendel) ** Update call to qef-adf-error. ** */ DB_STATUS qeu_evraise( QEF_CB *qef_cb, QEF_RCB *qef_rcb ) { DB_DATA_VALUE tm; /* Timestamp */ DB_DATE tm_date; SCF_ALERT scfa; SCF_CB scf_cb; SCF_SCI sci_list[1]; DB_ALERT_NAME alert; i4 err; char *errstr; DB_STATUS status=E_DB_OK; i4 tr1 = 0, tr2 = 0; /* Dummy trace values */ /* ** Build alert name */ STRUCT_ASSIGN_MACRO(*qef_rcb->qef_evname, alert.dba_alert); STRUCT_ASSIGN_MACRO(*qef_rcb->qef_evowner, alert.dba_owner); scf_cb.scf_length = sizeof(SCF_CB); scf_cb.scf_type = SCF_CB_TYPE; scf_cb.scf_facility = DB_QEF_ID; scf_cb.scf_session = qef_cb->qef_ses_id; /* Get the database name */ scf_cb.scf_ptr_union.scf_sci = (SCI_LIST *) sci_list; scf_cb.scf_len_union.scf_ilength = 1; sci_list[0].sci_length = sizeof(DB_DB_NAME); sci_list[0].sci_code = SCI_DBNAME; sci_list[0].sci_aresult = (char *) &alert.dba_dbname; sci_list[0].sci_rlength = NULL; status = scf_call(SCU_INFORMATION, &scf_cb); if (status != E_DB_OK) { _VOID_ qef_error(E_QE022F_SCU_INFO_ERROR, 0L, status, &err, &qef_rcb->error, 0); return E_DB_ERROR; } /* Format SCF event request block */ scf_cb.scf_ptr_union.scf_alert_parms = &scfa; scfa.scfa_name = &alert; scfa.scfa_text_length = 0; scfa.scfa_user_text = NULL; scfa.scfa_flags = 0; if (qef_rcb->qef_ev_l_text > 0) /* No need for empty strings */ { if (qef_rcb->qef_ev_l_text > DB_EVDATA_MAX) qef_rcb->qef_ev_l_text = DB_EVDATA_MAX; scfa.scfa_text_length = qef_rcb->qef_ev_l_text; scfa.scfa_user_text = qef_rcb->qef_evtext; } tm.db_datatype = DB_DTE_TYPE; /* Get time stamp for the event */ tm.db_prec = 0; tm.db_length = sizeof(tm_date); tm.db_data = (PTR)&tm_date; tm.db_collID = -1; status = adu_datenow(qef_cb->qef_adf_cb, &tm); if (status != E_DB_OK) { if ((status = qef_adf_error(&qef_cb->qef_adf_cb->adf_errcb, status, qef_cb, &qef_rcb->error)) != E_DB_OK) return (status); } scfa.scfa_when = &tm_date; /* If tracing and/or logging events then display event information */ if (ult_check_macro(&qef_cb->qef_trace, QEF_T_EVENTS, &tr1, &tr2)) qea_evtrace(qef_rcb, QEF_T_EVENTS, &alert, &tm, (i4)qef_rcb->qef_ev_l_text, (char*)qef_rcb->qef_evtext); if (ult_check_macro(&qef_cb->qef_trace, QEF_T_LGEVENTS, &tr1, &tr2)) qea_evtrace(qef_rcb, QEF_T_LGEVENTS, &alert, &tm, 0, (char *)NULL); /* ** Raise the event in SCF */ status = scf_call(SCE_RAISE, &scf_cb); if (status != E_DB_OK) { char *enm, *onm; /* Event and owner names */ enm = (char *)&alert.dba_alert; onm = (char *)&alert.dba_owner; errstr="RAISE"; switch (scf_cb.scf_error.err_code) { case E_SC0270_NO_EVENT_MESSAGE: _VOID_ qef_error(E_QE019A_EVENT_MESSAGE, 0L, status, &err, &qef_rcb->error, 1, (i4)STlength(errstr), errstr); break; case E_SC0280_NO_ALERT_INIT: _VOID_ qef_error(E_QE0200_NO_EVENTS, 0L, status, &err, &qef_rcb->error, 1, (i4)STlength(errstr), errstr); break; default: _VOID_ qef_error(E_QE020F_EVENT_SCF_FAIL, 0L, status, &err, &qef_rcb->error, 4, (i4)STlength(errstr), errstr, (i4)sizeof(i4), (PTR)&scf_cb.scf_error.err_code, qec_trimwhite(DB_OWN_MAXNAME, onm), onm, qec_trimwhite(DB_EVENT_MAXNAME, enm), enm); break; } qef_rcb->error.err_code = E_QE0025_USER_ERROR; status = E_DB_ERROR; } /* If SCF not ok */ return status; }
/*{ ** Name: QEA_CALLPROC - call the named procedure ** ** Description: ** The current execution environment is saved and an ** environment is created in which to execute the ** named procedure. ** ** This procedure is only called when a nested procedure is invoked. ** This can occur the first time through, or if the procedure is not ** found (LOAD_QP) or the plan was deemed invalid (INVALID_QUERY) then ** the procedure is re-entered in this routine. ** ** If rules are turned off (QEF_T_NORULES) then this procedure returns ** immediately. ** ** Inputs: ** action Callproc action header ** qef_rcb ** call_dsh DSH doing the callproc ** function unused ** state unused ** ** Outputs: ** call_dsh ** .error.err_code one of the following ** E_QE0119_LOAD_QP - Load a procedure QP ** E_QE0125_RULES_INHIBIT - Rules are turned off. ** E_QE0000_OK ** Returns: ** E_DB_{OK,WARN,ERROR,FATAL} ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 20-apr-89 (paul) ** Moved from qeq.c ** 09-may-89 (neil) ** Added rule name tracing. ** 26-may-89 (paul) ** Increase statement #, cleanup DSH on error recovery. ** 31-may-89 (neil) ** Cleanup tracing; modify when context count is set; reset "saved ** resource" bit if procedure is loaded. ** 23-jun-89 (neil) ** Extended trace for nested procedures: Indicate procedure nesting ** level and rule depth. ** 26-sep-89 (neil) ** Support for SET NORULES. ** 02-jan-90 (neil) ** DSH initialization error handling improved to indicate problem ** specifics. ** 03-jan-90 (ralph) ** Change interface to QSO_JUST_TRANS ** 10-jan-90 (neil) ** Improved DSH cleanup on DSH initialization errors. Made sure ** to confirm allocation error, and to pass a FALSE "release" flag ** to qeq_cleanup. ** 09-feb-90 (neil) ** Auditing cleanup: only audit the firing of rules and only if ** auditing is on (for performance). ** 09-nov-92 (jhahn) ** Added handling for byrefs. ** 14-dec-92 (jhahn) ** Cleaned up handling of byrefs. ** 12-feb-93 (jhahn) ** Added support for statement level rules. (FIPS) ** 24-mar-93 (jhahn) ** Various fixes for support of statement level rules. (FIPS) ** 02-apr-93 (jhahn) ** Made set input procedures called from rules bump qef_rule_depth. ** 01-may-93 (jhahn) ** Undid above change. Instead added new action QEA_INVOKE_RULE. ** 06-jul-93 (robf) ** Pass security label to qeu_secaudit ** 01-sep-93 (jhahn) ** Added support for multiple query plans for set input procedures. ** 7-jan-94 (swm) ** Bug #58635 ** Added PTR cast for qsf_owner which has changed type to PTR. ** 18-may-94 (anitap) ** Bug #63465 ** If error in nested procedure, the whole transaction was being ** rolled back. ** 7-nov-95 (inkdo01) ** Changes to replace QEN_ADF structure instances by pointers in ** QEF_AHD structures. ** 24-jul-96 (inkdo01) ** Added support of global temp table proc parms. ** 4-mar-97 (inkdo01) ** Added display of error QE030B (row rule calls SET OF proc). ** 23-may-97 (inkdo01) ** Change QE030B to only pass procname, since it is mapped to a ** US error in qeferror, anyway. ** 17-aug-99 (thaju02) ** initialize dmt_show.db_tab_id.db_tab_base to 0 prior to calling ** dmt_show, to avoid falsely reporting E_QE0018. (b98431) ** 27-apr-01 (inkdo01) ** Add code to detect nested/dynamic calls to row procs. ** 15-mar-04 (inkdo01) ** dsh_tempTables is now an array of ptrs. ** 17-mar-04 (inkdo01) ** We be fixin' a bug in error handlin' when qeq_dsh() doesn't ** return a dsh. ** 13-may-04 (inkdo01) ** Preserve status across qeq_cleanup calls. ** 18-may-04 (inkdo01) ** Quick fix to eliminate QE0018 when QE030D (US09AF) happens. ** 13-Jul-2004 (schka24) ** Straighten out which dsh is used where, fix loss of error ** code when finding called qp leading to QE0018. ** 13-Dec-2005 (kschendel) ** Inlined QEN_ADF changed to pointer, fix here. ** 29-May-2008 (gefei01) ** Prototype change for qeq_dsh(). ** 22-Apr-2009 (hanal04) Bug 121970 ** In printrule tracing print the ahd_pcount not qef_pcount ** which is set to zero if we are in a sub-procedure. ** 21-Jun-2010 (kschendel) b123775 ** Combine is-tproc and in-progress args to qeq-dsh. ** Make dbp alias a real QSO_NAME. */ DB_STATUS qea_callproc( QEF_AHD *act, QEF_RCB *qef_rcb, QEE_DSH *call_dsh, i4 function, /* Unused */ i4 state ) /* Unused */ { i4 err; DB_STATUS status = E_DB_OK, savestat; QEF_CB *qef_cb = call_dsh->dsh_qefcb; PTR *cbs = call_dsh->dsh_cbs; QEE_DSH *proc_dsh; /* DSH for called dbp */ QEN_ADF *qen_adf; ADE_EXCB *ade_excb; QSF_RCB qsf_rcb; i4 tr1 = 0, tr2 = 0; /* Dummy trace values */ DB_ERROR e_error; /* To pass to qeu_secaudit */ i4 page_count; bool is_deferred = act->qhd_obj.qhd_callproc.ahd_proc_temptable != NULL; bool gttparm = act->qhd_obj.qhd_callproc.ahd_gttid.db_tab_base != 0; bool need_cleanup = FALSE; bool need_release; bool from_rule = act->qhd_obj.qhd_callproc.ahd_rulename.db_name[0] != EOS; QEE_TEMP_TABLE *proc_temptable; char *cbuf = qef_cb->qef_trfmt; i4 cbufsize = qef_cb->qef_trsize; i4 open_count; do { /* ** This action is called back if a request to CREATE a QP for a ** CALLPROC fails. In this case we just continue with error processing. ** No need for another error as CLEAN_RSRC is only set if a client on ** the outside issued an error knowing we have a stacked environment. ** (Note: as of the 123775 fixes, we shouldn't ever get here with ** CLEAN_RSRC set, since qeq-query no longer attempts to execute ** the action from the sequencer callback. I'm leaving the code ** here for now, though.) */ if ((qef_rcb->qef_intstate & QEF_CLEAN_RSRC) != 0) { call_dsh->dsh_error.err_code = E_QE0025_USER_ERROR; qef_rcb->qef_intstate &= ~QEF_CLEAN_RSRC; status = E_DB_ERROR; break; } if (is_deferred) { proc_temptable = call_dsh->dsh_tempTables[act->qhd_obj.qhd_callproc .ahd_proc_temptable->ttb_tempTableIndex]; if (proc_temptable->tt_statusFlags & TT_EMPTY) if (from_rule) break; /* empty ttab in statement rule - ** nothing to do at all */ else status = openTempTable(qef_rcb, call_dsh, act->qhd_obj.qhd_callproc .ahd_proc_temptable->ttb_tempTableIndex, gttparm); else status = qen_rewindTempTable(call_dsh, act->qhd_obj. qhd_callproc.ahd_proc_temptable->ttb_tempTableIndex); if (status != E_DB_OK) break; } /* If called from a rule & SET NORULES is on, then inhibit execution */ if ( from_rule && ult_check_macro(&qef_cb->qef_trace, QEF_T_NORULES, &tr1, &tr2) ) { /* Trace inhibited rule if required */ if (ult_check_macro(&qef_cb->qef_trace, QEF_T_RULES, &tr1, &tr2)) { char *rn = act->qhd_obj.qhd_callproc.ahd_rulename.db_name; STprintf(cbuf, "PRINTRULES: Rule '%.*s' suppressed\n", qec_trimwhite(DB_RULE_MAXNAME, rn), rn); qec_tprintf(qef_rcb, cbufsize, cbuf); } call_dsh->dsh_error.err_code = E_QE0125_RULES_INHIBIT; status = E_DB_ERROR; break; } /* If rules off */ /* ** Security audit rule firing - check that is first time (not ** recreation), is a rule and, for performance, that we really ** need to audit. */ if ( (qef_rcb->qef_intstate & QEF_DBPROC_QP) == 0 && (act->qhd_obj.qhd_callproc.ahd_rulename.db_name[0] != EOS) && (Qef_s_cb->qef_state & QEF_S_C2SECURE) ) { status = qeu_secaudit(FALSE, qef_cb->qef_ses_id, act->qhd_obj.qhd_callproc.ahd_rulename.db_name, (DB_OWN_NAME *)&act->qhd_obj.qhd_callproc.ahd_ruleowner, sizeof(act->qhd_obj.qhd_callproc.ahd_rulename), SXF_E_RULE, I_SX202F_RULE_ACCESS, SXF_A_SUCCESS | SXF_A_EXECUTE, &e_error); if (status != E_DB_OK) { call_dsh->dsh_error.err_code = e_error.err_code; break; } } /* Actually execute a CALLPROC. */ /* We generate an actual parameter list, save the current */ /* execution context, stack the DSH and setup the new */ /* execution context. Processing then continues with the */ /* new QP. */ /* Save the current execution context as represented by */ /* QEF_RCB and the current DSH. */ STRUCT_ASSIGN_MACRO(*qef_rcb, *call_dsh->dsh_saved_rcb); call_dsh->dsh_act_ptr = act; qen_adf = act->qhd_obj.qhd_callproc.ahd_procparams; if (qen_adf != NULL) { /* Compute the actual parameters for this procedure */ /* call. */ qef_rcb->qef_pcount = act->qhd_obj.qhd_callproc.ahd_pcount; ade_excb = (ADE_EXCB *)cbs[qen_adf->qen_pos]; ade_excb->excb_seg = ADE_SMAIN; status = ade_execute_cx(call_dsh->dsh_adf_cb, ade_excb); if (status != E_DB_OK) { status = qef_adf_error(&call_dsh->dsh_adf_cb->adf_errcb, status, qef_cb, &call_dsh->dsh_error); if (status != E_DB_OK) break; } } else { /* No actual parameters */ qef_rcb->qef_pcount = 0; } /* ** If tracing rules and first time through then display ** rule/procedure information. */ if ((qef_rcb->qef_intstate & QEF_DBPROC_QP) == 0) { if (ult_check_macro(&qef_cb->qef_trace, QEF_T_RULES, &tr1, &tr2)) { char *rn, *pn; /* Rule/procedure names */ rn = act->qhd_obj.qhd_callproc.ahd_rulename.db_name; pn = act->qhd_obj.qhd_callproc.ahd_dbpalias.qso_n_id.db_cur_name; /* Tailor trace for rules vs nested procedures */ STprintf(cbuf, *rn == EOS ? "PRINTRULES 1: Executing procedure '%.*s'\n" : "PRINTRULES 1: Executing procedure '%.*s' from rule '%.*s'\n", qec_trimwhite(DB_DBP_MAXNAME, pn), pn, qec_trimwhite(DB_RULE_MAXNAME, rn), rn); qec_tprintf(qef_rcb, cbufsize, cbuf); STprintf(cbuf, "PRINTRULES 2: Rule/procedure depth = %d/%d, parameters passed = %d\n", qef_rcb->qef_rule_depth, qef_rcb->qef_context_cnt + 1, act->qhd_obj.qhd_callproc.ahd_pcount); qec_tprintf(qef_rcb, cbufsize, cbuf); } /* If tracing rules */ } /* ** Indicate that we have nested one more level, generate an error if ** we are nested too deeply. Context count is actually set later. */ if (qef_cb->qef_max_stack < qef_rcb->qef_context_cnt + 1) { status = E_DB_ERROR; qef_error(E_QE0208_EXCEED_MAX_CALL_DEPTH, 0L, status, &err, &call_dsh->dsh_error, 1, sizeof(qef_cb->qef_max_stack), &qef_cb->qef_max_stack); call_dsh->dsh_error.err_code = E_QE0122_ALREADY_REPORTED; break; } if (gttparm) { STRUCT_ASSIGN_MACRO(act->qhd_obj.qhd_callproc.ahd_gttid, qef_rcb->qef_setInputId); /* copy temptab ID */ page_count = 1; is_deferred = TRUE; } else if (is_deferred) { DMT_CB *dmt_cb = proc_temptable->tt_dmtcb; DMT_SHW_CB dmt_show; DMT_TBL_ENTRY dmt_tbl_entry; dmt_show.type = DMT_SH_CB; dmt_show.length = sizeof(DMT_SHW_CB); dmt_show.dmt_session_id = qef_cb->qef_ses_id; dmt_show.dmt_db_id = qef_rcb->qef_db_id; dmt_show.dmt_tab_id.db_tab_base = 0; dmt_show.dmt_flags_mask = DMT_M_TABLE | DMT_M_ACCESS_ID; dmt_show.dmt_char_array.data_address = NULL; dmt_show.dmt_table.data_address = (PTR) &dmt_tbl_entry; dmt_show.dmt_table.data_in_size = sizeof(DMT_TBL_ENTRY); dmt_show.dmt_record_access_id = dmt_cb->dmt_record_access_id; status = dmf_call(DMT_SHOW, &dmt_show); if (status != E_DB_OK) { STRUCT_ASSIGN_MACRO(dmt_show.error, call_dsh->dsh_error); break; } page_count = dmt_tbl_entry.tbl_page_count; STRUCT_ASSIGN_MACRO(dmt_cb->dmt_id, qef_rcb->qef_setInputId); } else { page_count = -1; MEfill(sizeof(DB_TAB_ID), (u_char)0, (PTR)&qef_rcb->qef_setInputId); } STRUCT_ASSIGN_MACRO(act->qhd_obj.qhd_callproc.ahd_procedureID, qef_rcb->qef_dbpId); /* Get the id of the procedure to call */ STRUCT_ASSIGN_MACRO(act->qhd_obj.qhd_callproc.ahd_dbpalias.qso_n_id, qef_rcb->qef_qp); qef_rcb->qef_qso_handle = NULL; /* Set the full name of the procedure into the RCB in case */ /* we have to call PSF to define the procedure. */ qef_rcb->qef_dbpname = act->qhd_obj.qhd_callproc.ahd_dbpalias; /* Lookup this procedure name as a QSF alias. At this time */ /* we do not have a valid DB_CURSOR_ID because we do not */ /* have the timestamp for the QP object. Ask QSF to look */ /* this up for us. If found, we continue executing, if not */ /* return to SCF to define this procedure. */ qsf_rcb.qsf_type = QSFRB_CB; qsf_rcb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rcb.qsf_length = sizeof(QSF_RCB); qsf_rcb.qsf_owner = (PTR)DB_QEF_ID; qsf_rcb.qsf_sid = qef_rcb->qef_cb->qef_ses_id; qsf_rcb.qsf_feobj_id.qso_type = QSO_ALIAS_OBJ; qsf_rcb.qsf_feobj_id.qso_lname = sizeof(qsf_rcb.qsf_feobj_id.qso_name); MEcopy((PTR)&act->qhd_obj.qhd_callproc.ahd_dbpalias, sizeof(qsf_rcb.qsf_feobj_id.qso_name), (PTR)qsf_rcb.qsf_feobj_id.qso_name); qsf_rcb.qsf_lk_state = QSO_FREE; status = qsf_call(QSO_JUST_TRANS, &qsf_rcb); if (DB_FAILURE_MACRO(status)) { /* No such procedure in QSF, ask SCF to define it */ /* Tell SCF to call us back even if the porcedure */ /* cannot be loaded. We will need to clean up */ qef_rcb->qef_intstate |= QEF_DBPROC_QP; call_dsh->dsh_error.err_code = E_QE0119_LOAD_QP; break; } else { /* ** The procedure was found - make sure "saved" bit isn't on for ** the scope of this execution. It may get turned back on if ** the QP or DSH is found to be invalid but then we'll re-enter ** here (to try again) and turn it off. */ qef_rcb->qef_intstate &= ~QEF_DBPROC_QP; } /* Increase context count now that we've loaded the QP */ qef_rcb->qef_context_cnt++; /* Procedure in QSF, load the timestamp into the QEF_RCB */ /* to allow normal QEF processing to continue. */ MEcopy((PTR)qsf_rcb.qsf_obj_id.qso_name, sizeof(DB_CURSOR_ID), (PTR)&qef_rcb->qef_qp); status = qeq_dsh(qef_rcb, 0 , &proc_dsh, QEQDSH_IN_PROGRESS, page_count); if (DB_FAILURE_MACRO(status)) { char *rn, *pn; /* Rule/procedure names */ STRUCT_ASSIGN_MACRO(qef_rcb->error, call_dsh->dsh_error); if (call_dsh->dsh_error.err_code == E_QE0023_INVALID_QUERY) { /* No such procedure in QSF, ask SCF to define it */ /* Tell SCF to call us back even if the porcedure */ /* cannot be loaded. We will need to clean up */ qef_cb->qef_dsh = (PTR) call_dsh; qef_rcb->qef_qp = call_dsh->dsh_saved_rcb->qef_qp; qef_rcb->qef_intstate |= QEF_DBPROC_QP; call_dsh->dsh_error.err_code = E_QE0119_LOAD_QP; qef_rcb->qef_context_cnt--; break; } /* ** The QP DSH is invalid for some reason. Generate error and return. ** If any allocation error then change to useful error message. */ if ( call_dsh->dsh_error.err_code == E_UL0005_NOMEM || call_dsh->dsh_error.err_code == E_QS0001_NOMEM || call_dsh->dsh_error.err_code == E_QE001E_NO_MEM || call_dsh->dsh_error.err_code == E_QE000D_NO_MEMORY_LEFT || call_dsh->dsh_error.err_code == E_QE030B_RULE_PROC_MISMATCH) { pn = act->qhd_obj.qhd_callproc.ahd_dbpalias.qso_n_id.db_cur_name; rn = act->qhd_obj.qhd_callproc.ahd_rulename.db_name; if (*rn == EOS) rn = "NULL "; if (call_dsh->dsh_error.err_code == E_QE030B_RULE_PROC_MISMATCH) qef_error(E_QE030B_RULE_PROC_MISMATCH, 0L, status, &err, &call_dsh->dsh_error, 1, /* qec_trimwhite(DB_RULE_MAXNAME, rn), rn, */ qec_trimwhite(DB_DBP_MAXNAME, pn), pn); else qef_error(E_QE0199_CALL_ALLOC, 0L, status, &err, &call_dsh->dsh_error, 3, qec_trimwhite(DB_DBP_MAXNAME, pn), pn, qec_trimwhite(DB_RULE_MAXNAME, rn), rn, sizeof(qef_rcb->qef_context_cnt),&qef_rcb->qef_context_cnt); call_dsh->dsh_error.err_code = E_QE0122_ALREADY_REPORTED; } /* ** Now clean up and restore to state before routine entry. ** Pass in FALSE for release as if the DSH is NULL we do NOT want ** to cause cleanup to release all DSH's for this session ** (qee_cleanup). If the DSH is not NULL it will be cleaned up at ** the end of the query. */ need_cleanup = TRUE; need_release = FALSE; break; } if (proc_dsh->dsh_qp_ptr->qp_status & QEQP_ROWPROC) { char *pn; /* Row producing procs cannot be invoked by QEA_CALLPROC (which ** implies either nested proc call or dynamic SQL proc call). */ pn = act->qhd_obj.qhd_callproc.ahd_dbpalias.qso_n_id.db_cur_name; qef_error(E_QE030D_NESTED_ROWPROCS, 0L, E_DB_ERROR, &err, &call_dsh->dsh_error, 1, qec_trimwhite(DB_DBP_MAXNAME, pn), pn); status = E_DB_ERROR; break; } /* Found QP and DSH, stack old context */ proc_dsh->dsh_stack = call_dsh; proc_dsh->dsh_stmt_no = qef_cb->qef_stmt++; qef_cb->qef_dsh = (PTR) proc_dsh; qef_cb->qef_open_count++; /* Initialize procedure parameters (& user params - even if wrong) */ if (proc_dsh->dsh_qp_ptr->qp_ndbp_params != 0 || qef_rcb->qef_pcount > 0) { status = qee_dbparam(qef_rcb, proc_dsh, call_dsh, act->qhd_obj.qhd_callproc.ahd_params, act->qhd_obj.qhd_callproc.ahd_pcount, TRUE); if (DB_FAILURE_MACRO(status)) { /* If we fail after acquiring the DSH, we need to */ /* deallocate the DSH and recover back to the original */ /* calling state. */ STRUCT_ASSIGN_MACRO(proc_dsh->dsh_error, call_dsh->dsh_error); qef_cb->qef_open_count--; need_cleanup = TRUE; need_release = TRUE; break; } } if (is_deferred) { /* FIXME should error if it's null */ if (proc_dsh->dsh_qp_ptr->qp_setInput != NULL) STRUCT_ASSIGN_MACRO(qef_rcb->qef_setInputId, * (DB_TAB_ID *)(proc_dsh->dsh_row[proc_dsh->dsh_qp_ptr-> qp_setInput->vl_tab_id_index])); } } while (FALSE); if (need_cleanup) { /* error in a nested DB procedure, abort up to the beginning of the ** procedure if there are no other cursors opened. We ** guarantee that by decrementing the qef_open_count. If the ** count becomes zero, qeq_cleanup will abort to the last internal ** savepoint. Fix for bug 63465. */ savestat = status; open_count = qef_cb->qef_open_count; while (qef_cb->qef_open_count > 0) qef_cb->qef_open_count--; status = qeq_cleanup(qef_rcb, status, need_release); status = savestat; qef_cb->qef_open_count = open_count; qef_cb->qef_dsh = (PTR) call_dsh; qef_rcb->qef_context_cnt--; qef_rcb->qef_pcount = call_dsh->dsh_saved_rcb->qef_pcount; qef_rcb->qef_usr_param = call_dsh->dsh_saved_rcb->qef_usr_param; qef_rcb->qef_qp = call_dsh->dsh_saved_rcb->qef_qp; qef_rcb->qef_qso_handle = call_dsh->dsh_saved_rcb->qef_qso_handle; call_dsh->dsh_qef_rowcount = call_dsh->dsh_saved_rcb->qef_rowcount; call_dsh->dsh_qef_targcount = call_dsh->dsh_saved_rcb->qef_targcount; call_dsh->dsh_qef_output = call_dsh->dsh_saved_rcb->qef_output; call_dsh->dsh_qef_count = call_dsh->dsh_saved_rcb->qef_count; } return (status); }
/*{ ** Name: adu_rdm1_setup - Setup for Redeem an ADF_COUPON ** ** Description: ** This routine performs the initialization for the redeeming of ** a coupon. This amount primarily to initializing the ** ADP_LO_WKSP function instance private and shared (adw_fip & ** adw_shared, respectively). This routine also moves the ** appropriate peripheral header into the output area. ** ** Since this routine moves the peripheral header to the output ** area, in the case where the original call to this routine has ** insufficient space for the output header, this routine may be ** called more than once. We note this since it is "unusual" for ** the initialization routine to be called more than one time for ** an object. In the case where the original space is of ** insufficent size, then this routine will return an indication ** that the output area is full, and will move nothing into it. ** Thus, this routine considers it a call-protocol error to be ** called a second time with insufficient space. ** ** Inputs: ** adf_scb The session's control block (ptr). ** result_dv Pointer to DB_DATA_VALUE for ** result. ** coupon_dv Pointer to DB_DATA_VALUE ** describing the input coupon to ** be redeemed. ** workspace_dv Pointer to DB_DATA_VALUE ** describing redeem's workspace. ** continuation Continuation indicator. 0 ** indicates the first call, else ** not the first call. ** ** Outputs: ** adf_scb->adf_error Filled as appropriate. ** *result_dv->db_data Setup with beginning of peripheral ** data type. ** *workspace_dv->db_data Initialized for ongoing redeem work. ** Returns: ** DB_STATUS ** Exceptions: ** None. ** ** Side Effects: ** None. ** ** History: ** 02-dec-1992 (fred) ** Coded. Created from adu_redeem prototype in support of ** OME large objects. ** 8-Apr-1993 (fred) ** Fixed bug in zero length large object handling. For large ** objects of zero length which are not nullable, the length ** should not include the null-value-byte. ** 12-Oct-1993 (fred) ** Removed call to ADP_INFORMATION -- subsumed by ** adi_per_under(). ** 10-sep-1998 (schte01) ** Modified I4ASSIGN for axp_osf to pass the value, not the address ** of the value, to be assigned. This worked under the -oldc ** compiler option and got compile errors under -newc. ** 28-jul-1999 (thaju02) ** If the coupon stipulates that the data is not null, then ** the minimum result buffer length must be large enough to ** hold one byte of data along with all necessary info ** (ADP_HDR_SIZE + nextsegmarker(i4) + 2byteseglenindicator ** + 1byteofdata). Given a buffer with only 18 bytes of space ** available, 12 bytes are filled with peripheral header info ** in adu_rdm1_setup and 4 bytes are filled with the next ** segment marker in adu_redeem. In adc_lvch_xform, the 2 ** byte segment length indicator is initially set to zero ** in the result buffer. If there is no space left in the ** result buffer for segment data, we flush the buffer. In ** the front end, upon receiving this result buffer, the ** next segment marker indicates that there is data following, ** yet the length is zero; terminal monitor infinitely loops. ** (b98104) ** 12-aug-99 (stial01) ** adu_rdm1_setup() 'blob_work' arg to adi_per_under should be ** NULL before redeem. ** 24-may-2000 (stial01) ** adu_rdm1_setup() clear null indicator if not null (B101656) ** [@history_template@]... */ DB_STATUS static adu_rdm1_setup(ADF_CB *adf_scb, DB_DATA_VALUE *result_dv, DB_DATA_VALUE *coupon_dv, ADP_LO_WKSP *work, i4 for_gca) { DB_STATUS status; ADP_PERIPHERAL *p = (ADP_PERIPHERAL *) result_dv->db_data; DB_DT_ID dtid = ADI_DT_MAP_MACRO(abs(result_dv->db_datatype)); i4 min_size; bool isnull = 0; if (coupon_dv->db_datatype < 0) work->adw_fip.fip_null_bytes = 1; else work->adw_fip.fip_null_bytes = 0; if (ult_check_macro(&Adf_globs->Adf_trvect, ADF_011_RDM_TO_V_STYLE, &dummy1, &dummy2)) { work->adw_fip.fip_test_mode = 1; work->adw_fip.fip_test_length = ADP_TST_VLENGTH + work->adw_fip.fip_null_bytes; work->adw_fip.fip_test_sent = 0; } else { work->adw_fip.fip_test_mode = 0; } work->adw_shared.shd_exp_action = ADW_START; work->adw_fip.fip_done = FALSE; /* ** Fool the main routine into getting us an input segment. Make ** look like the input segement is all used up. */ work->adw_shared.shd_type = coupon_dv->db_datatype; work->adw_shared.shd_i_area = (char *) 0; work->adw_shared.shd_i_used = work->adw_shared.shd_i_length = 0; work->adw_shared.shd_o_used = ADP_HDR_SIZE; work->adw_shared.shd_o_length = result_dv->db_length; work->adw_shared.shd_o_area = (char *) result_dv->db_data; if (work->adw_shared.shd_o_length > MAXI2) { TRdisplay("adu_rdm1_setup shd_o_length %d MAX %d\n", work->adw_shared.shd_o_length, MAXI2); return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0)); } work->adw_shared.shd_l0_check = work->adw_shared.shd_l1_check = 0; work->adw_fip.fip_pop_cb.pop_continuation = ADP_C_BEGIN_MASK; work->adw_fip.fip_pop_cb.pop_user_arg = (PTR) 0; work->adw_fip.fip_pop_cb.pop_type = (ADP_POP_TYPE); work->adw_fip.fip_pop_cb.pop_length = sizeof(ADP_POP_CB); work->adw_fip.fip_pop_cb.pop_ascii_id = ADP_POP_ASCII_ID; work->adw_fip.fip_pop_cb.pop_temporary = ADP_POP_PERMANENT; work->adw_fip.fip_pop_cb.pop_coupon = coupon_dv; work->adw_fip.fip_pop_cb.pop_segment = &work->adw_fip.fip_seg_dv; work->adw_fip.fip_pop_cb.pop_underdv = &work->adw_fip.fip_under_dv; status = adi_per_under(adf_scb, result_dv->db_datatype, &work->adw_fip.fip_under_dv); if (status) { return(adu_error(adf_scb, E_AD7000_ADP_BAD_INFO, 0)); } STRUCT_ASSIGN_MACRO(work->adw_fip.fip_under_dv, work->adw_fip.fip_seg_dv); work->adw_fip.fip_seg_dv.db_data = (char *) ((char *) work + sizeof(ADP_LO_WKSP)); if (ADI_ISNULL_MACRO(coupon_dv) || ((((ADP_PERIPHERAL *)coupon_dv->db_data)->per_length0 == 0) && (((ADP_PERIPHERAL *) coupon_dv->db_data)->per_length1 == 0))) isnull = 1; if (isnull) /* hdr + segment indicator + sizeof(null byte) */ min_size = ADP_HDR_SIZE + sizeof(i4) + work->adw_fip.fip_null_bytes; else /* hdr + segment indicator + segment length + segment single byte */ min_size = ADP_HDR_SIZE + sizeof(i4) + sizeof(i2) + sizeof(char); if (result_dv->db_length >= min_size) { if (for_gca) work->adw_shared.shd_out_tag = ADP_P_GCA; else work->adw_shared.shd_out_tag = ADP_P_DATA; I4ASSIGN_MACRO(work->adw_shared.shd_out_tag, p->per_tag); work->adw_shared.shd_out_segmented = (work->adw_shared.shd_out_tag != ADP_P_DATA); I4ASSIGN_MACRO( ((ADP_PERIPHERAL *) coupon_dv->db_data)->per_tag, work->adw_shared.shd_inp_tag); work->adw_shared.shd_inp_segmented = (work->adw_shared.shd_inp_tag != ADP_P_DATA); I4ASSIGN_MACRO( ((ADP_PERIPHERAL *) coupon_dv->db_data)->per_length0, p->per_length0); I4ASSIGN_MACRO(p->per_length0, work->adw_fip.fip_l0_value); I4ASSIGN_MACRO(((ADP_PERIPHERAL *) coupon_dv->db_data)->per_length1, p->per_length1); I4ASSIGN_MACRO(p->per_length1, work->adw_fip.fip_l1_value); work->adw_fip.fip_state = ADW_F_RUNNING; } else if (work->adw_fip.fip_state != ADW_F_STARTING) { work->adw_fip.fip_state = ADW_F_STARTING; result_dv->db_length = 0; adf_scb->adf_errcb.ad_errcode = E_AD0002_INCOMPLETE; return(E_DB_INFO); } else { return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0)); } if (isnull) { if (work->adw_fip.fip_test_mode) { ((DB_TEXT_STRING *) p)->db_t_count = (i2) 0; if (result_dv->db_length >= (work->adw_fip.fip_test_length - work->adw_fip.fip_test_sent)) { result_dv->db_length = work->adw_fip.fip_test_length - work->adw_fip.fip_test_sent; work->adw_fip.fip_test_sent = work->adw_fip.fip_test_length; } else { work->adw_fip.fip_state = ADW_F_DONE_NEED_NULL; work->adw_fip.fip_test_sent += result_dv->db_length; adf_scb->adf_errcb.ad_errcode = E_AD0002_INCOMPLETE; return(E_DB_INFO); } } else { i4 zero = 0; /* ** Insert GCA mark that says there is no segment. */ #if defined(axp_osf) || defined(ris_u64) || defined(LP64) || \ defined(axp_lnx) /* ** We want to init the GCA field after the header, but ** on axp_osf this is not the same as the start of the ** coupon, because 8-byte alignment causes a slack 4-byte ** integer to be between the header and the coupon. See ** adu_redeem above for a different way this field is set ** to 1 when we have real data (not null). The addressing ** of this field should really be standardized in such a ** way that contiguous layout of 4-byte aligned fields is ** not assumed. */ I4ASSIGN_MACRO(zero,*((char *)p + ADP_HDR_SIZE)); #endif I4ASSIGN_MACRO(zero, p->per_value); result_dv->db_length = ADP_NULL_PERIPH_SIZE; if (work->adw_shared.shd_type > 0) result_dv->db_length -= 1; } if (ADI_ISNULL_MACRO(coupon_dv)) ADF_SETNULL_MACRO(result_dv); else ADF_CLRNULL_MACRO(result_dv); adf_scb->adf_errcb.ad_errcode = E_DB_OK; work->adw_fip.fip_done = TRUE; return(E_DB_OK); } if (work->adw_fip.fip_test_mode) { i4 segment_count; i4 length1; i2 count; I4ASSIGN_MACRO(p->per_length1, length1); I4ASSIGN_MACRO(p->per_length0, segment_count); if (!segment_count) segment_count = ADP_TST_SEG_CNT; count = min( ADP_TST_VLENGTH, (i2) (length1 + (segment_count * (sizeof(i4) + sizeof(i2))) + sizeof(i4) /* no more segments */ + work->adw_shared.shd_o_used) ) - sizeof(i2); I2ASSIGN_MACRO(count, ((DB_TEXT_STRING *) p)->db_t_count); } return(E_DB_OK); }
/*{ ** Name: rdf_trace - Call RDF trace operation. ** ** External call format: status = rdf_trace(&db_debug_cb) ** ** Description: ** This function is the standard entry point to RDF for setting and ** clearing tracepoints(the "set trace point" command). Because RDF ** is a service facility, trace point for RDF can only be set on ** the server basis. There is no session level trace point. ** Db_debug_cb is the tracing control block that contains the trace ** flag information. ** ** See file <rdftrace.h> for a description of all possible ** RDF trace points. ** ** Inputs: ** debug_cb Pointer to a DB_DEBUG_CB ** .db_trswitch What operation to perform ** DB_TR_NOCHANGE None ** DB_TR_ON Turn on a tracepoint ** DB_TR_OFF Turn off a tracepoint ** .db_trace_point Trace point ID(the flag number) ** .db_value_count The number of values specified in ** the value array ** .db_vals[2] Optional values, to be interpreted ** differently for each tracepoint ** Outputs: ** none ** ** Returns: ** E_DB_OK Function completed normally. ** E_DB_ERROR Function failed due to error by caller; ** E_DB_FATAL Function failed due to some internal ** problem; ** Exceptions: ** none ** ** Side Effects: ** The trace vector in the server control block of RDF will be updated ** to contain the trace information. The trace information will be persist ** throughout the life of the server. ** ** History: ** 15-apr-86 (ac) ** written ** 02-mar-87 (puree) ** replace global server control block with global pointer. ** 14-dec-1989 (teg) ** modify to go get svcb from SCF instead of using a global pointer ** to it. ** 16-jul-92 (teresa) ** prototypes ** 16-sep-92 (teresa) ** implement trace points rd3 and rd4 to clear ldbdesc cache. ** 22-apr-94 (teresa) ** added trace points rd11 and rd12 to dump memory statistics or all ** statistics. This is an action trace point -- the dump occurs when ** the trace point is selected rather than during query execution. ** 20-nov-2007 (thaju02) ** If trace point RD0022/RDU_CHECKSUM specified, invalidate ** relcache. Entries need rdr_checksum to be calc/init'd ** otherwise E_RD010D errors may be reported. (B119499) */ DB_STATUS rdf_trace(DB_DEBUG_CB *debug_cb) { i4 flag; i4 firstval; i4 secondval; DB_STATUS status; i4 trace_scope; /* assure flag is legal */ flag = debug_cb->db_trace_point; if (flag >= RDF_NB) { return (E_DB_ERROR); } /* There can be UP TO two values, but maybe they weren't given */ firstval = (debug_cb->db_value_count > 0) ? debug_cb->db_vals[0] : 0L; secondval = (debug_cb->db_value_count > 1) ? debug_cb->db_vals[1] : 0L; /* see if this is an action trace. Action traces require an immediate ** action rather than turning trace flags on/off/etc. */ if ( (debug_cb->db_trswitch==DB_TR_ON) && (flag <= RD_ACT_MAX) ) { /* see which action is requested. Not all actions are implemented ** yet, so its possible that this call may become a no-opt */ switch (flag) { case RD0001: case RD0002: case RD0003: case RD0004: case RD0005: case RD0010: status=rdt_clear_cache(flag); if (DB_FAILURE_MACRO(status)) { return(E_DB_ERROR); } break; case RD0011: /* dump memory info. This trace is used by tech support when ** debugging out of memory errors. */ TRdisplay("\n...............................................\n"); TRdisplay("RDF Cache Memory Available: %d\n",Rdi_svcb->rdv_memleft); TRdisplay("RDF memory cache size : %d\n", Rdi_svcb->rdv_pool_size); TRdisplay("Max number of objects allowed on Cache:\n"); TRdisplay(" RELcache: %d, QTREE Cache: %d, \n", Rdi_svcb->rdv_cnt0_rdesc, Rdi_svcb->rdv_cnt1_qtree); TRdisplay(" LDBDesc Cache %d, DEFAULTS cache: %d\n", Rdi_svcb->rdv_cnt2_dist, Rdi_svcb->rdv_cnt3_default); TRdisplay("Hashids:\n"); TRdisplay(" RELcache: %d, QTREE Cache: %d, \n", Rdi_svcb->rdv_rdesc_hashid, Rdi_svcb->rdv_qtree_hashid); TRdisplay(" LDBDesc Cache %d, DEFAULTS cache: %d\n", Rdi_svcb->rdv_dist_hashid, Rdi_svcb->rdv_def_hashid); TRdisplay("...............................................\n"); break; case RD0012: /* dump all of the RDF statistics */ rdf_report ( &Rdi_svcb->rdvstat ); break; default: break; } } else { /* ** determine if this is a session wide trace or a server wide trace ** and process accordingly */ trace_scope = trace_type(flag); if (trace_scope == SVR_WIDE_TRACE) { /* turn trace on in svcb ** ** Three possible actions: Turn on flag, turn it off, or do nothing. */ switch (debug_cb->db_trswitch) { case DB_TR_ON: if ((flag == RD0022) && !(ult_check_macro(&Rdi_svcb->rdf_trace, flag, &firstval, &secondval))) { /* setting RDU_CHECKSUM */ RDF_GLOBAL global; RDF_CB rdfcb; RDI_FCB fcb; global.rdfcb = &rdfcb; rdfcb.rdf_rb.rdr_fcb = (PTR)&fcb; rdfcb.rdf_info_blk = NULL; rdfcb.rdf_rb.rdr_db_id = NULL; rdfcb.rdf_rb.rdr_types_mask = 0; rdfcb.rdf_rb.rdr_2types_mask = 0; CSget_sid(&rdfcb.rdf_rb.rdr_session_id); fcb.rdi_fac_id = DB_RDF_ID; status = rdf_invalidate(&global, &rdfcb); if (DB_FAILURE_MACRO(status)) return(E_DB_ERROR); } ult_set_macro(&Rdi_svcb->rdf_trace, flag, firstval, secondval); break; case DB_TR_OFF: ult_clear_macro(&Rdi_svcb->rdf_trace, flag); break; case DB_TR_NOCHANGE: /* Do nothing */ break; default: return (E_DB_ERROR); }; } else { CS_SID sid; RDF_SESS_CB *rdf_sess_cb; /* ** this trace point is session specific, so use the session control ** block for this trace point. */ CSget_sid(&sid); rdf_sess_cb = GET_RDF_SESSCB(sid); /* ** Three possible actions: Turn on flag, turn it off, or do nothing. */ switch (debug_cb->db_trswitch) { case DB_TR_ON: ult_set_macro(&rdf_sess_cb->rds_strace, flag, firstval, secondval); break; case DB_TR_OFF: ult_clear_macro(&rdf_sess_cb->rds_strace, flag); break; case DB_TR_NOCHANGE: /* Do nothing */ break; default: return (E_DB_ERROR); } } } return (E_DB_OK); }
DB_STATUS qen_tsort( QEN_NODE *node, QEF_RCB *qef_rcb, QEE_DSH *dsh, i4 function ) { QEF_CB *qef_cb = dsh->dsh_qefcb; PTR *cbs = dsh->dsh_cbs; ADE_EXCB *ade_excb; DMR_CB *dmr_load = (DMR_CB*)cbs[node->node_qen.qen_tsort.tsort_load]; DMR_CB *dmr_get = (DMR_CB*) cbs[node->node_qen.qen_tsort.tsort_get]; QEN_NODE *out_node = node->node_qen.qen_tsort.tsort_out; QEE_XADDRS *node_xaddrs = dsh->dsh_xaddrs[node->qen_num]; QEN_STATUS *qen_status = node_xaddrs->qex_status; QEN_SHD *shd = dsh->dsh_shd[node->node_qen.qen_tsort.tsort_shd]; DB_STATUS status; bool reset = FALSE; bool heap_sort = TRUE, no_qef = FALSE; i4 rowno; i4 out_func = NO_FUNC; DM_MDATA dm_mdata; i4 val1; i4 val2; TIMERSTAT timerstat; i4 loop_cntr = 0; if (function != 0) { if (function & FUNC_RESET) { reset = TRUE; out_func = FUNC_RESET; } /* Do open processing, if required. Only if this is the root node ** of the query tree do we continue executing the function. */ if ((function & TOP_OPEN || function & MID_OPEN) && !(qen_status->node_status_flags & QEN1_NODE_OPEN)) { status = (*out_node->qen_func)(out_node, qef_rcb, dsh, MID_OPEN); qen_status->node_status_flags = QEN1_NODE_OPEN; if (function & MID_OPEN) return(E_DB_OK); function &= ~TOP_OPEN; } /* Do close processing, if required. */ if (function & FUNC_CLOSE) { if (!(qen_status->node_status_flags & QEN8_NODE_CLOSED)) { status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_CLOSE); qen_status->node_status_flags = (qen_status->node_status_flags & ~QEN1_NODE_OPEN) | QEN8_NODE_CLOSED; } return(E_DB_OK); } if (function & FUNC_EOGROUP) { /* End of partition group request ends our sort if we're returning ** rows. If we aren't in the middle of returning rows, pass the ** EOG request on down so that the child skips the upcoming group ** and moves on to the next one. */ if (qen_status->node_status == QEN3_GET_NEXT_INNER) { status = qen_ts_reset(dsh, node, qen_status); /* FIXME we should do better at remembering whether this ** sort load got EOF or EOG, and pass it on up now. At ** present (Apr '07), tsorts aren't very common except under ** merge join plans, where early eof detection doesn't ** matter much. (the tsort is on the outer side.) ** For now, pass EOG back up, if we're really at EOF caller ** will find out soon enough. */ if (status == E_DB_OK) { status = E_DB_WARN; dsh->dsh_error.err_code = E_QE00A5_END_OF_PARTITION; } } else { status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_EOGROUP); /* Pass resulting EOF or EOG indication in dsh up to caller */ } return(status); } } /* if function != 0 */ /* Check for cancel, context switch if not MT */ CScancelCheck(dsh->dsh_sid); if (QEF_CHECK_FOR_INTERRUPT(qef_cb, dsh) == E_DB_ERROR) return (E_DB_ERROR); /* If the trace point qe90 is turned on then gather cpu and dio stats */ if (dsh->dsh_qp_stats) { qen_bcost_begin(dsh, &timerstat, qen_status); } if (node->node_qen.qen_tsort.tsort_dups == DMR_NODUPLICATES && ult_check_macro(&qef_cb->qef_trace, 92, &val1, &val2)) heap_sort = FALSE; if (ult_check_macro(&qef_cb->qef_trace, 94, &val1, &val2)) { no_qef = TRUE; qen_status->node_u.node_sort.node_sort_status = QEN9_DMF_SORT; } #ifdef xDEBUG (VOID) qe2_chk_qp(dsh); #endif for (;;) /* to break off in case of error */ { if (reset && qen_status->node_status != QEN0_INITIAL) { status = qen_ts_reset(dsh, node, qen_status); if (status != E_DB_OK) break; } /* If NO MORE ROWS from this node, just return */ if (qen_status->node_status == QEN4_NO_MORE_ROWS) { dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS; status = E_DB_WARN; break; } rowno = node->node_qen.qen_tsort.tsort_mat->qen_output; ade_excb = node_xaddrs->qex_otmat; /* If this is the first time execution, or if the node is reset, ** initialize the sorter. If this is not, just go get a tuple. */ if (qen_status->node_status == QEN0_INITIAL || qen_status->node_status == QEN1_EXECUTED) { if (qen_status->node_status == QEN0_INITIAL) { if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT) { status = qes_init(dsh, shd, node, rowno, node->node_qen.qen_tsort.tsort_dups); if (status != E_DB_OK) { if (dsh->dsh_error.err_code == E_QE000D_NO_MEMORY_LEFT) { /* out of space, convert it to DMF sort */ qen_status->node_u.node_sort.node_sort_status = QEN9_DMF_SORT; status = E_DB_OK; } else { break; } } } if (qen_status->node_u.node_sort.node_sort_status == QEN9_DMF_SORT) { status = qen_ts_dump(shd, dsh, node, rowno, heap_sort, no_qef); if (status != E_DB_OK) break; } if (node->node_qen.qen_tsort.tsort_pqual != NULL) qeq_join_pqreset(dsh, node->node_qen.qen_tsort.tsort_pqual); qen_status->node_status = QEN1_EXECUTED; } /* Common code for QEN0_INITIAL and QEN1_EXECUTED */ /* Get dm_mdata ready for DMF loading */ dm_mdata.data_address = dsh->dsh_row[rowno]; dm_mdata.data_size = dsh->dsh_qp_ptr->qp_row_len[rowno]; dmr_load->dmr_mdata = &dm_mdata; dsh->dsh_qp_status |= DSH_SORT; /* Get rows from the underneath node and append them to the ** sorter */ for (;;) { /* fetch rows */ status = (*out_node->qen_func)(out_node, qef_rcb, dsh, out_func); out_func = NO_FUNC; if (status != E_DB_OK) { /* the error.err_code field in qef_rcb should already be ** filled in. */ if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS) { status = E_DB_OK; } else if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION && (node->qen_flags & QEN_PART_SEPARATE)) { /* End of rows from partitioning group. Flag the ** fact and make it look like regular "eof". */ qen_status->node_status_flags |= QEN2_OPART_END; dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS; status = E_DB_OK; } break; } /* project the attributes into sort tuple row */ status = qen_execute_cx(dsh, ade_excb); if (status != E_DB_OK) break; /* If we're generating partition qualifications on behalf ** of a parent FSM join, eval against this row. */ if (node->node_qen.qen_tsort.tsort_pqual != NULL) { status = qeq_join_pquals(dsh, node->node_qen.qen_tsort.tsort_pqual); if (status != E_DB_OK) break; } /* append the sort tuple into the sorter - note periodic ** differences between heap sort and trace point mandated ** insert sort */ if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT) { if (heap_sort) status = qes_putheap(dsh, shd, node->node_qen.qen_tsort.tsort_cmplist, node->node_qen.qen_tsort.tsort_scount); else status = qes_insert(dsh, shd, node->node_qen.qen_tsort.tsort_cmplist, node->node_qen.qen_tsort.tsort_scount); if (status != E_DB_OK && dsh->dsh_error.err_code == E_QE000D_NO_MEMORY_LEFT) { /* out of space, convert it to DMF sort */ qen_status->node_u.node_sort.node_sort_status = QEN9_DMF_SORT; status = qen_ts_dump(shd, dsh, node, rowno, heap_sort, no_qef); } if (status != E_DB_OK) break; } if(qen_status->node_u.node_sort.node_sort_status == QEN9_DMF_SORT) { status = dmf_call(DMR_LOAD, dmr_load); if (status != E_DB_OK) { dsh->dsh_error.err_code = dmr_load->error.err_code; break; } } if (!(Qef_s_cb->qef_state & QEF_S_IS_MT) && (loop_cntr++ >1000)) { /* On an Internal threaded system, after processing 1000 rows ** give another thread a chance. */ loop_cntr = 0; CSswitch(); } } if (status != E_DB_OK) break; /* End of loading loop */ /* Finish up join-time part qual if we're doing it */ if (node->node_qen.qen_tsort.tsort_pqual != NULL) { qeq_join_pqeof(dsh, node->node_qen.qen_tsort.tsort_pqual); } if(qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT) { if (!heap_sort) qes_endsort(dsh, shd); /* prep return of tups */ } else /* DMF */ { /* Tell DMF that there are no more rows */ dmr_load->dmr_flags_mask = (DMR_ENDLOAD | DMR_SORT_NOCOPY); status = dmf_call(DMR_LOAD, dmr_load); if (status != E_DB_OK) { dsh->dsh_error.err_code = dmr_load->error.err_code; break; } /* position the table for reading sorted tuples */ dmr_get->dmr_flags_mask = DMR_SORTGET; dmr_get->dmr_position_type = DMR_ALL; status = dmf_call(DMR_POSITION, dmr_get); if (status != E_DB_OK) { dsh->dsh_error.err_code = dmr_get->error.err_code; break; } } /* Mark the node is ready to return tuples */ qen_status->node_status = QEN3_GET_NEXT_INNER; } /* ** Return a tuple from the sorter to the caller. */ if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT) { if (heap_sort) { status = qes_getheap(dsh, shd, node->node_qen.qen_tsort.tsort_cmplist, node->node_qen.qen_tsort.tsort_scount); if (status != E_DB_OK) { if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS) { qen_status->node_status = QEN4_NO_MORE_ROWS; status = E_DB_WARN; } break; } } else { /* rows come straight from pointer array */ /* Check for the end of buffer */ if (shd->shd_next_tup == shd->shd_tup_cnt) { qen_status->node_status = QEN4_NO_MORE_ROWS; dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS; status = E_DB_WARN; break; } /* Copy tuple to the row buffer */ MEcopy((PTR)(shd->shd_vector[shd->shd_next_tup]), shd->shd_width, (PTR)shd->shd_row); ++shd->shd_next_tup; status = E_DB_OK; } } else { dmr_get->dmr_flags_mask = (DMR_NEXT | DMR_SORTGET); status = dmf_call(DMR_GET, dmr_get); if (status != E_DB_OK) { if (dmr_get->error.err_code == E_DM0055_NONEXT) { qen_status->node_status = QEN4_NO_MORE_ROWS; dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS; status = E_DB_WARN; } else { dsh->dsh_error.err_code = dmr_get->error.err_code; } break; } } /* status has to be OK here */ /* Increment the count of rows that this node has returned */ qen_status->node_rcount++; dsh->dsh_error.err_code = 0; /* print tracing information DO NOT xDEBUG THIS */ if (node->qen_prow && (ult_check_macro(&qef_cb->qef_trace, 100+node->qen_num, &val1, &val2) || ult_check_macro(&qef_cb->qef_trace, 99, &val1, &val2) ) ) { (void) qen_print_row(node, qef_rcb, dsh); } break; } /* end of error-break loop */ #ifdef xDEBUG (VOID) qe2_chk_qp(dsh); #endif if (dsh->dsh_qp_stats) { qen_ecost_end(dsh, &timerstat, qen_status); } dsh->dsh_qp_status &= ~DSH_SORT; if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS && (qen_status->node_status_flags & QEN2_OPART_END)) { /* If this was just the end of a partition, reset error code ** to notify the caller. */ qen_status->node_status_flags &= ~QEN2_OPART_END; dsh->dsh_error.err_code = E_QE00A5_END_OF_PARTITION; status = E_DB_WARN; } return (status); }
DB_STATUS qel_c0_cre_lnk( QEF_RCB *v_qer_p ) { DB_STATUS status; QEF_CB *qef_cb = v_qer_p->qef_cb; QES_DDB_SES *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses; QED_DDL_INFO *ddl_p = & v_qer_p->qef_r3_ddb_req.qer_d7_ddl_info; DD_0LDB_PLUS *plus_p = & ddl_p->qed_d6_tab_info_p-> dd_t9_ldb_p->dd_i2_ldb_plus; DD_CAPS *caps_p = & plus_p->dd_p3_ldb_caps; DD_LDB_DESC ldb, /* for replicating LDB desc */ *ldb_p = & ldb, *cdb_p = & dds_p->qes_d4_ddb_p-> dd_d3_cdb_info.dd_i1_ldb_desc, *ddl_ldb_p = & ddl_p->qed_d6_tab_info_p-> dd_t9_ldb_p->dd_i1_ldb_desc; QEC_D9_TABLEINFO tabinfo; /* used for table info of link */ QEC_D2_LDBIDS ldbids; /* used for internal LDB id info */ QEC_D5_LONG_LDBNAMES longnames; /* used for excessively long LDB ** name */ QEC_L16_TABLES tables; /* used for IITABLES-style info */ QEC_D6_OBJECTS objects; /* used for object info */ QEC_L6_INDEXES indexes; QEC_MIN_CAP_LVLS pre_mins, aft_mins; QEC_LINK link, /* used as global control block */ *link_p = & link; QEQ_1CAN_QRY del, ins, sel, upd, /* used for ordering canned query */ *upd_p = & upd; u_i4 len; SYSTIME now; bool log_ddl_56 = FALSE, log_err_59 = FALSE; i4 i4_1, i4_2; QEC_INDEX_ID ndx_ids[QEK_0MAX_NDX_COUNT + 1]; /* working space for index ids */ RQB_BIND rq_bind[QEC_CAT_COL_COUNT_MAX + 1]; QEC_D7_OBJECT_BASE obj_base, *base_p = & obj_base; i4 xact_mode; char *cbuf = v_qer_p->qef_cb->qef_trfmt; i4 cbufsize = v_qer_p->qef_cb->qef_trsize; if (ult_check_macro(& qef_cb->qef_trace, QEF_TRACE_DDB_LOG_DDL_56, & i4_1, & i4_2)) { log_ddl_56 = TRUE; } if (ult_check_macro(& qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59, & i4_1, & i4_2)) { log_err_59 = TRUE; } sel.qeq_c2_rqf_bind_p = rq_bind; /* must set up */ del.qeq_c2_rqf_bind_p = (RQB_BIND *) NULL; ins.qeq_c2_rqf_bind_p = (RQB_BIND *) NULL; upd.qeq_c2_rqf_bind_p = (RQB_BIND *) NULL; /* 1. set up control block */ if (dds_p->qes_d7_ses_state == QES_4ST_REFRESH) /* REGISTER WITH REFRESH ? */ STRUCT_ASSIGN_MACRO(ddl_p->qed_d7_obj_id, tabinfo.d9_1_obj_id); /* yes */ else /* no */ { tabinfo.d9_1_obj_id.db_tab_base = 0; /* unknown */ tabinfo.d9_1_obj_id.db_tab_index = 0; /* always 0 for non-index */ } link_p->qec_1_ddl_info_p = ddl_p; link_p->qec_2_tableinfo_p = & tabinfo; link_p->qec_3_ldb_id = 0; link_p->qec_4_col_cnt = 0; MEfill(DB_DB_MAXNAME, ' ', link_p->qec_5_ldb_alias); link_p->qec_6_select_p = & sel; link_p->qec_7_ldbids_p = & ldbids; link_p->qec_8_longnames_p = & longnames; link_p->qec_9_tables_p = & tables; link_p->qec_10_haves = QEC_07_CREATE; if (caps_p->dd_c6_name_case == DD_2CASE_UPPER) link_p->qec_10_haves |= QEC_06_UPPER_LDB; if (caps_p->dd_c1_ldb_caps & DD_7CAP_USE_PHYSICAL_SOURCE) link_p->qec_10_haves |= QEC_10_USE_PHY_SRC; if (caps_p->dd_c2_ldb_caps & DD_201CAP_DIFF_ARCH) link_p->qec_10_haves |= QEC_11_LDB_DIFF_ARCH; /* make a copy of the LDB descriptor for non-$ingrs access if necessary */ if (ddl_ldb_p->dd_l1_ingres_b) { /* make a copy for non-$ingres access */ STRUCT_ASSIGN_MACRO(*ddl_ldb_p, ldb); ldb_p->dd_l1_ingres_b = FALSE; ldb_p->dd_l5_ldb_id = DD_0_IS_UNASSIGNED; } else { /* use provided LDB descriptor but determine if LDB has a long name */ qed_u0_trimtail( ddl_ldb_p->dd_l3_ldb_name, (u_i4) DD_256_MAXDBNAME, ldb_p->dd_l3_ldb_name); len = STlength(ldb_p->dd_l3_ldb_name); if (len > DB_DB_MAXNAME) link_p->qec_10_haves |= QEC_04_LONG_LDBNAME; ldb_p = ddl_ldb_p; } link_p->qec_11_ldb_obj_cnt = 0; link_p->qec_12_indexes_p = & indexes; link_p->qec_13_objects_p = & objects; link_p->qec_15_ndx_cnt = 0; link_p->qec_16_ndx_ids_p = ndx_ids; link_p->qec_19_ldb_p = ldb_p; link_p->qec_20_rqf_bind_p = rq_bind; link_p->qec_21_delete_p = & del; link_p->qec_22_insert_p = & ins; link_p->qec_23_update_p = & upd; status = qed_u8_gmt_now(v_qer_p, link_p->qec_24_cur_time); if (status) return(status); link_p->qec_24_cur_time[DD_25_DATE_SIZE] = EOS; link_p->qec_25_pre_mins_p = & pre_mins; link_p->qec_26_aft_mins_p = & aft_mins; link_p->qec_27_select_cnt = 0; link_p->qec_28_iistats_cnt = 0; TMnow(& now); link_p->qec_17_ts1 = now.TM_secs; link_p->qec_18_ts2 = now.TM_msecs; /* 2. inform TPF of update intention on CDB (note that only CREATE does ** LDB retrievals */ /* 2.1 2PC is required if DDL concurrency is off. */ if (dds_p->qes_d9_ctl_info & QES_01CTL_DDL_CONCURRENCY_ON) xact_mode = QEK_4TPF_1PC; else xact_mode = QEK_3TPF_UPDATE; status = qet_t5_register(v_qer_p, cdb_p, DB_SQL, xact_mode); if (status) return(status); if (log_ddl_56) { /* display beginning, CDB and LDB info */ STprintf(cbuf, "\n%s %p: %s REGISTRATION begins%s\n", IIQE_61_qefsess, (PTR) v_qer_p->qef_cb, IIQE_65_tracing, IIQE_62_3dots); qec_tprintf(v_qer_p, cbufsize, cbuf); STprintf(cbuf, "%s %p: ...the CDB:\n", IIQE_61_qefsess, (PTR) v_qer_p->qef_cb); qec_tprintf(v_qer_p, cbufsize, cbuf); qed_w1_prt_ldbdesc(v_qer_p, cdb_p); STprintf(cbuf, "%s %p: ...the LDB:\n", IIQE_61_qefsess, (PTR) v_qer_p->qef_cb); qec_tprintf(v_qer_p, cbufsize, cbuf); qed_w1_prt_ldbdesc(v_qer_p, ldb_p); STprintf(cbuf, "\n"); qec_tprintf(v_qer_p, cbufsize, cbuf); } /* 3. update OBJECT_BASE in II_DD_DB_OBJECT_BASE */ upd_p->qeq_c1_can_id = UPD_716_DD_DDB_OBJECT_BASE; upd_p->qeq_c3_ptr_u.d7_object_base_p = base_p; upd_p->qeq_c4_ldb_p = cdb_p; status = qel_u1_update(v_qer_p, link_p); if (status) goto END_TRACING; /* 4. enter phase 1: set up necessary information */ status = qel_c1_cre_p1(v_qer_p, link_p); if (status) goto END_TRACING; /* 2. enter phase 2: promote information into STAR catalogs */ status = qel_c2_cre_p2(v_qer_p, link_p); if (status) v_qer_p->qef_cb->qef_abort = TRUE; END_TRACING: if (log_ddl_56) { /* display end tracing message */ STprintf(cbuf, "%s %p: %s REGISTRATION ends\n\n", IIQE_61_qefsess, (PTR) v_qer_p->qef_cb, IIQE_65_tracing); qec_tprintf(v_qer_p, cbufsize, cbuf); } return(status); }
DB_STATUS tpd_s3_send_sps_to_ldb( TPR_CB *v_tpr_p, TPD_LX_CB *v1_lxcb_p) { DB_STATUS status = E_DB_OK; TPD_SS_CB *sscb_p = (TPD_SS_CB *) v_tpr_p->tpr_session; TPD_DX_CB *dxcb_p = & sscb_p->tss_dx_cb; TPD_LM_CB *splm_p = & dxcb_p->tdx_23_sp_ulmcb; TPD_SP_CB *spcb_p = (TPD_SP_CB *) splm_p->tlm_3_frst_ptr; i4 i; RQR_CB rqr_cb; bool trace_svpt_103 = FALSE, trace_err_104 = FALSE; i4 i4_1, i4_2; char svpt_name[sizeof(DB_SP_NAME) + 1], qrytxt[100]; if (spcb_p == NULL /* no savepoints ? */ || v1_lxcb_p->tlx_sp_cnt >= splm_p->tlm_2_cnt) /* LDB has seen all savepoints ? */ return(E_DB_OK); /* yes, nothing to do */ /* skip the privileged CDB if DDL concurrency is ON, an "autocommit" ** condition */ if (sscb_p->tss_ddl_cc && v1_lxcb_p->tlx_site.dd_l1_ingres_b) return(E_DB_OK); /* nothing to do */ if (ult_check_macro(& sscb_p->tss_3_trace_vector, TSS_TRACE_SVPT_103, & i4_1, & i4_2)) { trace_svpt_103 = TRUE; } if (ult_check_macro(& sscb_p->tss_3_trace_vector, TSS_TRACE_ERROR_104, & i4_1, & i4_2)) { trace_err_104 = TRUE; } /* pre-set static parameters to call RQF */ rqr_cb.rqr_timeout = 0; rqr_cb.rqr_q_language = v_tpr_p->tpr_lang_type; rqr_cb.rqr_session = sscb_p->tss_rqf; /* query length to be set below when constructed */ rqr_cb.rqr_msg.dd_p2_pkt_p = qrytxt; rqr_cb.rqr_msg.dd_p3_nxt_p = NULL; rqr_cb.rqr_1_site = & v1_lxcb_p->tlx_site; rqr_cb.rqr_dv_cnt = 0; rqr_cb.rqr_dv_p = (DB_DATA_VALUE *) NULL; /* position at the first savepoint not yet sent to the site */ if (v1_lxcb_p->tlx_sp_cnt > 0) for (i = 0; spcb_p != NULL && i < v1_lxcb_p->tlx_sp_cnt; ++i) spcb_p = spcb_p->tsp_4_next_p; /* advance to the next savepoint */ while (spcb_p != NULL) { /* set up dynamic parameters to request current savepoint */ /* construct query for current savepoint on the fly */ tpd_u0_trimtail((char *) & spcb_p->tsp_1_name, sizeof(DB_SP_NAME), svpt_name); if (v_tpr_p->tpr_lang_type == DB_QUEL) STprintf(qrytxt, "%s %s;", IITP_10_savepoint_p, svpt_name); else STprintf(qrytxt, "%s %s;", IITP_10_savepoint_p, svpt_name); rqr_cb.rqr_msg.dd_p1_len = (i4) STlength(qrytxt); if (trace_svpt_103) tpd_p5_prt_tpfqry(v_tpr_p, qrytxt, & v1_lxcb_p->tlx_site, TPD_0TO_FE); status = tpd_u4_rqf_call(RQR_QUERY, & rqr_cb, v_tpr_p); if (status) { if (trace_err_104) tpd_p5_prt_tpfqry(v_tpr_p, qrytxt, & v1_lxcb_p->tlx_site, TPD_0TO_FE); return(status); } spcb_p = spcb_p->tsp_4_next_p; /* advance to next savepoint */ } v1_lxcb_p->tlx_sp_cnt = splm_p->tlm_2_cnt; /* all savepoints are now known to site */ return(E_DB_OK); }
DB_STATUS qeq_c4_open( QEF_RCB *v_qer_p, QEE_DSH *v_dsh_p ) { DB_STATUS status = E_DB_OK; QEF_CB *qef_cb = v_qer_p->qef_cb; QEF_AHD *act_p = (QEF_AHD *) NULL, *def_act_p = (QEF_AHD *) NULL; i4 def_act_cnt = 0, get_act_cnt = 0, lnk_act_cnt = 0; QEQ_D1_QRY *sub_p = (QEQ_D1_QRY *) NULL; bool read_b = FALSE, last_b = FALSE, val_qp_51 = FALSE, log_qry_55 = FALSE, log_err_59 = FALSE; i4 i4_1, i4_2; if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55, & i4_1, & i4_2)) { log_qry_55 = TRUE; qeq_p31_opn_csr(v_qer_p, v_dsh_p);; } if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59, & i4_1, & i4_2)) log_err_59 = TRUE; /* verify that the following conditions are true of the query plan: ** ** 1) there is exactly one last QEA_D7_OPN action, ** 2) there are no QEA_D2_GET, QEA_D4_LNK actions, ** 3) there are no read actions */ act_p = v_dsh_p->dsh_qp_ptr->qp_ahd; while (act_p != (QEF_AHD *) NULL) { if (act_p->ahd_atype == QEA_D7_OPN) { def_act_cnt++; if (act_p->ahd_next == (QEF_AHD *) NULL) last_b = TRUE; } else if (act_p->ahd_atype == QEA_D2_GET) get_act_cnt++; else if (act_p->ahd_atype == QEA_D4_LNK) lnk_act_cnt++; else if (act_p->ahd_atype == QEA_D1_QRY) { sub_p = & act_p->qhd_obj.qhd_d1_qry; if (sub_p->qeq_q3_ctl_info & QEQ_001_READ_TUPLES) read_b = TRUE; } act_p = act_p->ahd_next; } if (! last_b || def_act_cnt != 1 || get_act_cnt != 0 || lnk_act_cnt != 0 || read_b) { if (log_err_59 && !log_qry_55) qeq_p31_opn_csr(v_qer_p, v_dsh_p);; status = qed_u2_set_interr(E_QE1999_BAD_QP, & v_qer_p->error); return(status); } qee_d1_qid(v_dsh_p); /* generate query id for ** sending to LDB */ /* process each action in the QP */ for (act_p = v_dsh_p->dsh_qp_ptr->qp_ahd; act_p != (QEF_AHD *)NULL; act_p = act_p->ahd_next) { /* check for deferred cursor, only one at a time is allowed */ if (act_p->ahd_flags & QEA_DEF) { v_dsh_p->dsh_qp_status |= DSH_DEFERRED_CURSOR; if (qef_cb->qef_defr_curs) { qed_u10_trap(); v_qer_p->error.err_code = E_QE0026_DEFERRED_EXISTS; return(E_DB_ERROR); } } switch (act_p->ahd_atype) { case QEA_D1_QRY: case QEA_D8_CRE: case QEA_D9_UPD: status = qeq_d1_qry_act(v_qer_p, & act_p); if (status) qed_u10_trap(); break; case QEA_D3_XFR: status = qeq_d5_xfr_act(v_qer_p, act_p); if (status) qed_u10_trap(); break; case QEA_D6_AGG: status = qeq_d10_agg_act(v_qer_p, act_p); if (status) qed_u10_trap(); break; case QEA_D7_OPN: def_act_p = act_p; /* keep track */ status = qeq_d8_def_act(v_qer_p, act_p); if (status) qed_u10_trap(); break; default: status = qed_u1_gen_interr(& v_qer_p->error); qed_u10_trap(); break; } if (! status) v_dsh_p->dsh_act_ptr = act_p; /* promote to current dsh */ } /* cleanup done by caller */ v_dsh_p->dsh_act_ptr = def_act_p; /* pt to define action */ return (status); }
DB_STATUS qeq_c3_fetch( QEF_RCB *v_qer_p, QEE_DSH *i_dsh_p ) { DB_STATUS status = E_DB_OK; QES_DDB_SES *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses; QES_QRY_SES *qss_p = & dds_p->qes_d8_union.u2_qry_ses; QEE_DDB_CB *qee_p = i_dsh_p->dsh_ddb_cb; /* QEF_QP_CB *qph_p = ((QEE+DSH *)(v_qer_p->qef_cb->qef_dsh))->dsh_qp_ptr; */ bool log_qry_55 = FALSE, log_err_59 = FALSE; i4 i4_1, i4_2; TPR_CB tpr, *tpr_p = & tpr; RQR_CB rqr, *rqr_p = & rqr; if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55, & i4_1, & i4_2)) { log_qry_55 = TRUE; qeq_p33_fet_csr(v_qer_p, i_dsh_p); } if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59, & i4_1, & i4_2)) log_err_59 = TRUE; if (! (qee_p->qee_d3_status & QEE_03Q_DEF)) { /* cursor either not opened or closed */ status = qed_u1_gen_interr(& v_qer_p->error); return(status); } if (qee_p->qee_d3_status & QEE_04Q_EOD) { /* no more data */ v_qer_p->qef_rowcount = 0; /* must return E_QE0015_NO_MORE_ROWS to signal exhaustion of data */ v_qer_p->error.err_code = E_QE0015_NO_MORE_ROWS; return(E_DB_WARN); } /* ** 1. set up to call TPF for read operation ** MEfill(sizeof(tpr), '\0', (PTR) & tpr); tpr_p->tpr_session = dds_p->qes_d2_tps_p; ** TPF session id ** tpr_p->tpr_rqf = dds_p->qes_d3_rqs_p; ** RQF session id ** tpr_p->tpr_lang_type = qss_p->qes_q2_lang; tpr_p->tpr_site = & qee_p->qee_d11_ldbdesc; status = qed_u17_tpf_call(TPF_READ_DML, tpr_p, v_qer_p); if (status) { return(status); } */ /* 2. set up to call RQF to load data */ MEfill(sizeof(rqr), '\0', (PTR) & rqr); rqr_p->rqr_session = dds_p->qes_d3_rqs_p; /* RQF session id */ rqr_p->rqr_q_language = qss_p->qes_q2_lang; rqr_p->rqr_timeout = QEK_0_TIME_QUANTUM; rqr_p->rqr_1_site = & qee_p->qee_d11_ldbdesc; STRUCT_ASSIGN_MACRO(qee_p->qee_d5_local_qid, rqr_p->rqr_qid); rqr_p->rqr_inv_parms = (PTR) v_qer_p->qef_param; /* 3. relay SCF parameters */ rqr_p->rqr_tupcount = v_qer_p->qef_rowcount; rqr_p->rqr_tupdata = (PTR) v_qer_p->qef_output; rqr_p->rqr_tupdesc_p = (PTR) NULL; status = qed_u3_rqf_call(RQR_FETCH, rqr_p, v_qer_p); if (status) { if (log_err_59 && !log_qry_55) qeq_p33_fet_csr(v_qer_p, i_dsh_p); /* it is assumed that RQF has repaired itself before returning */ dds_p->qes_d7_ses_state = QES_0ST_NONE; /* reset */ STRUCT_ASSIGN_MACRO(rqr_p->rqr_error, v_qer_p->error); return(status); } if (rqr_p->rqr_end_of_data) qee_p->qee_d3_status |= QEE_04Q_EOD; /* must set */ /* return data gotten so far */ v_qer_p->qef_rowcount = rqr_p->rqr_tupcount; v_qer_p->qef_count = rqr_p->rqr_count; if ((v_qer_p->qef_rowcount == 0) || (v_qer_p->qef_count == 0)) { /* no more data */ qee_p->qee_d3_status |= QEE_04Q_EOD; /* must set */ /* must return E_QE0015_NO_MORE_ROWS to signal no more data for ** subquery */ v_qer_p->error.err_code = E_QE0015_NO_MORE_ROWS; return(E_DB_WARN); } else if ((v_qer_p->qef_rowcount == 0) && (v_qer_p->qef_count != 0)) { /* Here we emulate an incomplete condition */ v_qer_p->error.err_code = E_AD0002_INCOMPLETE; return(E_DB_INFO); } return(E_DB_OK); }
DB_STATUS qeq_c1_close( QEF_RCB *v_qer_p, QEE_DSH *i_dsh_p ) { DB_STATUS status; QES_DDB_SES *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses; QEE_DDB_CB *qee_p = i_dsh_p->dsh_ddb_cb; /* QES_QRY_SES *qss_p = & dds_p->qes_d8_union.u2_qry_ses; QEF_QP_CB *qp_p = dsh_p->dsh_qp_ptr; */ QEQ_D1_QRY *sub_p = & i_dsh_p->dsh_act_ptr->qhd_obj.qhd_d1_qry; bool log_qry_55 = FALSE, log_err_59 = FALSE; i4 i4_1, i4_2; RQR_CB rqr, *rqr_p = & rqr; if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55, & i4_1, & i4_2)) { log_qry_55 = TRUE; qeq_p31_opn_csr(v_qer_p, i_dsh_p); } if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59, & i4_1, & i4_2)) log_err_59 = TRUE; /* ** Do actual close only if marked opened. We could be interrupted ** between when qef_open_count is incremented, and the actual open */ if (!(qee_p->qee_d3_status & QEE_03Q_DEF)) return (E_DB_OK); MEfill(sizeof(rqr), '\0', (PTR) & rqr); rqr_p->rqr_session = dds_p->qes_d3_rqs_p; /* RQF session id */ rqr_p->rqr_q_language = sub_p->qeq_q1_lang; rqr_p->rqr_timeout = sub_p->qeq_q2_quantum; rqr_p->rqr_1_site = sub_p->qeq_q5_ldb_p; rqr_p->rqr_tmp = qee_p->qee_d1_tmp_p; STRUCT_ASSIGN_MACRO(qee_p->qee_d5_local_qid, rqr_p->rqr_qid); rqr_p->rqr_inv_parms = (PTR) NULL; status = qed_u3_rqf_call(RQR_CLOSE, rqr_p, v_qer_p); if (status) { if (log_err_59 && !log_qry_55) qeq_p31_opn_csr(v_qer_p, i_dsh_p); return(status); } qee_p->qee_d3_status &= ~QEE_03Q_DEF; /* cursor closed */ return(E_DB_OK); }
DB_STATUS qen_fsmjoin( QEN_NODE *node, QEF_RCB *qef_rcb, QEE_DSH *dsh, i4 function ) { QEF_CB *qef_cb = dsh->dsh_qefcb; DMR_CB *dmrcb; QEN_NODE *out_node = node->node_qen.qen_sjoin.sjn_out; QEN_NODE *in_node = node->node_qen.qen_sjoin.sjn_inner; QEE_XADDRS *node_xaddrs = dsh->dsh_xaddrs[node->qen_num]; QEN_STATUS *qen_status = node_xaddrs->qex_status; ADE_EXCB *ade_excb; ADE_EXCB *jqual_excb = node_xaddrs->qex_jqual; QEN_HOLD *qen_hold; QEN_HOLD *ijFlagsHold = (QEN_HOLD *)NULL; QEN_SHD *qen_shd; QEN_SHD *ijFlagsShd; DB_STATUS status = E_DB_OK; bool reset = FALSE; bool out_reset = FALSE; bool in_reset = FALSE; bool ojoin = (node->node_qen.qen_sjoin.sjn_oj != NULL); bool ljoin = FALSE; bool rjoin = FALSE; bool innerTupleJoined; bool rematerializeInnerTuple = TRUE; /* During full joins, the last driving tuple may left ** join. This 0s all special eqcs from the ** re-scannable stream. The current re-scannable ** tuple will right join. To recover the state of ** its special eqcs, simply re-materialize the inner ** tuple. That's what this variable is for. */ i4 new_to_old; i4 join_result; i4 val1; i4 val2; TIMERSTAT timerstat; bool potential_card_violation = FALSE; #ifdef xDEBUG (VOID) qe2_chk_qp(dsh); #endif if (function != 0) { if (function & FUNC_RESET) { reset = in_reset = out_reset = TRUE; } /* Do open processing, if required. Only if this is the root node ** of the query tree do we continue executing the function. */ if ((function & TOP_OPEN || function & MID_OPEN) && !(qen_status->node_status_flags & QEN1_NODE_OPEN)) { status = (*out_node->qen_func)(out_node, qef_rcb, dsh, MID_OPEN); status = (*in_node->qen_func)(in_node, qef_rcb, dsh, MID_OPEN); qen_status->node_status_flags |= QEN1_NODE_OPEN; if (function & MID_OPEN) return(E_DB_OK); function &= ~TOP_OPEN; } /* Do close processing, if required. */ if (function & FUNC_CLOSE) { if (!(qen_status->node_status_flags & QEN8_NODE_CLOSED)) { /* Ideally we would clean up all of our own shd crap here ** instead of making qee do it... */ status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_CLOSE); status = (*in_node->qen_func)(in_node, qef_rcb, dsh, FUNC_CLOSE); qen_status->node_status_flags = (qen_status->node_status_flags & ~QEN1_NODE_OPEN) | QEN8_NODE_CLOSED; } return(E_DB_OK); } /* End of partition group call just gets passed down. */ if (function & FUNC_EOGROUP) { status = (*out_node->qen_func)(out_node, qef_rcb, dsh, FUNC_EOGROUP); status = (*in_node->qen_func)(in_node, qef_rcb, dsh, FUNC_EOGROUP); return(E_DB_OK); } } /* if function */ /* If the trace point qe90 is turned on then gather cpu and dio stats */ if (dsh->dsh_qp_stats) { qen_bcost_begin(dsh, &timerstat, qen_status); } /* Check for cancel, context switch if not MT */ CScancelCheck(dsh->dsh_sid); if (QEF_CHECK_FOR_INTERRUPT(qef_cb, dsh) == E_DB_ERROR) return (E_DB_ERROR); dsh->dsh_error.err_code = E_QE0000_OK; qen_hold = dsh->dsh_hold[node->node_qen.qen_sjoin.sjn_hfile]; qen_shd = dsh->dsh_shd[dsh->dsh_qp_ptr->qp_sort_cnt + node->node_qen.qen_sjoin.sjn_hfile]; if( ojoin && node->node_qen.qen_sjoin.sjn_oj->oj_ijFlagsFile >= 0 ) { ijFlagsHold = dsh->dsh_hold[node->node_qen.qen_sjoin.sjn_oj->oj_ijFlagsFile]; ijFlagsShd = dsh->dsh_shd[dsh->dsh_qp_ptr->qp_sort_cnt + node->node_qen.qen_sjoin.sjn_oj->oj_ijFlagsFile]; } if ( ojoin ) switch(node->node_qen.qen_sjoin.sjn_oj->oj_jntype) { case DB_LEFT_JOIN: ljoin = TRUE; break; case DB_RIGHT_JOIN: rjoin = TRUE; break; case DB_FULL_JOIN: ljoin = TRUE; rjoin = TRUE; break; default: break; } /* If the node is to be reset, dump the hold file and reset the ** inner/outer nodes */ loop_reset: if (reset) { if (qen_status->node_status != QEN0_INITIAL && in_node->qen_type != QE_SORT) { /* reset in memory or dump dmf hold if it has been created */ status = qen_u9_dump_hold(qen_hold, dsh, qen_shd); if(status) goto errexit; qen_hold->hold_medium = HMED_IN_MEMORY; /* set back to mem */ } qen_hold->hold_buffer_status = HFILE6_BUF_EMPTY; if ( qen_status->node_status != QEN0_INITIAL && ijFlagsHold ) { /* dump tid hold file if it has been created */ status = qen_u9_dump_hold( ijFlagsHold, dsh, ijFlagsShd ); if(status) goto errexit; ijFlagsHold->hold_medium = HMED_IN_MEMORY; /* set back to mem */ } qen_status->node_status = QEN0_INITIAL; /* reset = reintialize */ qen_status->node_u.node_join.node_inner_status = QEN0_INITIAL; qen_status->node_u.node_join.node_outer_status = QEN0_INITIAL; qen_status->node_u.node_join.node_outer_count = 0; qen_status->node_access = ( QEN_READ_NEXT_OUTER | QEN_READ_NEXT_INNER | QEN_OUTER_HAS_JOINED ); } if (qen_status->node_status == QEN0_INITIAL) { qen_status->node_u.node_join.node_outer_status = QEN0_INITIAL; /* set num entries in mem_hold in case we build one */ /* this may not be a hard number in future */ /* qen_shd->shd_tup_cnt = 20; */ /* by setting it to -1, the required memory will be configured to */ /* suit the condition. if it is < 20, it will use the dmf hold mem*/ /* ramra01 19-oct-94 */ qen_shd->shd_tup_cnt = -1; if( ijFlagsHold ) { ijFlagsHold->hold_status = HFILE0_NOFILE; /* default */ ijFlagsHold->hold_status2 = 0; /* default */ ijFlagsHold->hold_medium = HMED_IN_MEMORY; /* default */ /* in case we build a hold file ** tell qen_u1_append to calculate its size in memory ** or go to DMF hold */ ijFlagsShd->shd_tup_cnt = -1; } if(rjoin) { /* consistency check */ if( !ijFlagsHold ) { /* rjoin and no hold file for inner join flags */ dsh->dsh_error.err_code = E_QE0002_INTERNAL_ERROR; status = E_DB_ERROR; goto errexit; } } qen_status->node_access = ( QEN_READ_NEXT_OUTER | QEN_READ_NEXT_INNER | QEN_OUTER_HAS_JOINED ); } for (;;) /* The loop */ { status = E_DB_OK; /********************************************************* ** ** LOGIC TO READ FROM THE OUTER TUPLE STREAM ** ** ** *********************************************************/ if( qen_status->node_access & QEN_READ_NEXT_OUTER ) { /* ** If the previous outer tuple did not inner join with ** any inner tuples, then it's an outer join. Return ** it along with nulls for the right side if it passes ** the WHERE clause. */ if ( ljoin && !( qen_status->node_access & QEN_OUTER_HAS_JOINED ) ) { /* ** Set the "outer has joined" flag so that if we emit ** a left join, we won't come back into this conditional ** the next time through this fmsjoin node. */ qen_status->node_access |= QEN_OUTER_HAS_JOINED; /* now execute oj_lnull */ status = qen_execute_cx(dsh, node_xaddrs->qex_lnull); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ /* Execute jqual restriction, if any */ if ( jqual_excb == NULL) break; /* emit a left join */ else { status = qen_execute_cx(dsh, jqual_excb); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ if (jqual_excb->excb_value == ADE_TRUE) break; /* emit a left join */ } } /* endif previous outer did not join */ qen_status->node_access &= ~( QEN_READ_NEXT_OUTER | QEN_OUTER_HAS_JOINED ); /* get a new outer */ newouter: if ( qen_status->node_u.node_join.node_outer_status == QEN8_OUTER_EOF ) { status = E_DB_WARN; dsh->dsh_error.err_code = E_QE0015_NO_MORE_ROWS; } else /* this is where we actually read the outer stream! */ { status = (*out_node->qen_func)(out_node, qef_rcb, dsh, (out_reset) ? FUNC_RESET : NO_FUNC); if (status == E_DB_OK) qen_status->node_u.node_join.node_outer_count++; } out_reset = FALSE; /* a little error handling. check for end of outer stream */ if (status != E_DB_OK) { if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS || dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION && node->qen_flags & QEN_PART_SEPARATE) { /* If no outer rows were read and we're doing partition ** grouping, skip the next inner partition to re-sync. */ if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION && qen_status->node_u.node_join.node_outer_count <= 0) if (!rjoin) { if (node->qen_flags & QEN_PART_SEPARATE) { status = (*in_node->qen_func)(in_node, qef_rcb, dsh, FUNC_EOGROUP); if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION) qen_status->node_status_flags |= QEN4_IPART_END; /* if just EOPartition, flag it */ } goto errexit; } qen_status->node_access |= QEN_OUTER_HAS_JOINED; qen_status->node_u.node_join.node_outer_status = QEN8_OUTER_EOF; if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION) qen_status->node_status_flags |= QEN2_OPART_END; /* if just EOPartition, flag it */ /* ** If ( the inner stream is exhausted and there's nothing ** to rescan ) or we're not right joining, ** then there are no more tuples to return. This should ** be the only way to end this fsmjoin node. */ if ( INNER_STREAM_EXHAUSTED || rjoin == FALSE ) { qen_status->node_status = QEN4_NO_MORE_ROWS; break; /* done */ } else /* we must check some more inner tuples */ { dsh->dsh_error.err_code = 0; /*reset*/ if(qen_status->node_status == QEN0_INITIAL) /* empty */ { qen_status->node_status = QEN1_EXECUTED; qen_hold->hold_status = HFILE0_NOFILE; qen_hold->hold_status2 = 0; qen_hold->hold_medium = HMED_IN_MEMORY; if(in_node->qen_type == QE_SORT) { status = qen_u32_dosort(in_node, qef_rcb, dsh, qen_status, qen_hold, qen_shd, (in_reset) ? FUNC_RESET : NO_FUNC); if(status) goto errexit; } in_reset = FALSE; } /* endif first time through */ } /* endif no more inner tuples to check */ } else if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION) { /* No more rows in partitioning group - read from ** next group. */ out_reset = TRUE; goto newouter; } else /* return error from reading outer stream */ { break; } } /* end of error handling for outer stream EOF */ if(qen_status->node_status == QEN0_INITIAL) { qen_status->node_status = QEN1_EXECUTED; /* init done */ qen_hold->hold_status = HFILE0_NOFILE; /* default */ qen_hold->hold_status2 = 0; /* default */ qen_hold->hold_medium = HMED_IN_MEMORY; /* default */ if(in_node->qen_type == QE_SORT) { status = qen_u32_dosort(in_node, qef_rcb, dsh, qen_status, qen_hold, qen_shd, (in_reset) ? FUNC_RESET : NO_FUNC); if(status) goto errexit; in_reset = FALSE; } /* now materialize the first join key */ status = qen_execute_cx(dsh, node_xaddrs->qex_okmat); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ } /* If not the first time */ else { if ( qen_status->node_u.node_join.node_outer_status == QEN8_OUTER_EOF ) { new_to_old = NEW_GT_OLD; } else /* outer not at EOF */ { /* compare the old outer key to the new one. */ new_to_old = ADE_1EQ2; if ((ade_excb = node_xaddrs->qex_kcompare) != NULL) { status = qen_execute_cx(dsh, ade_excb); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ new_to_old = ade_excb->excb_cmp; } /* Materialize the new outer key if the old and the ** new outer keys are not equal */ if (new_to_old != ADE_1EQ2) { status = qen_execute_cx(dsh, node_xaddrs->qex_okmat); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ } else if ((node->qen_flags & QEN_CARD_MASK) == QEN_CARD_01L) { /* Right outer - note cardinality */ potential_card_violation = (new_to_old == ADE_1EQ2); } } /* endif outer not at EOF */ /* ** If there are inner tuples to rescan, decide whether ** to thumb through them again or dump them. */ if ( qen_status->node_access & QEN_RESCAN_MARKED ) { if ( new_to_old == ADE_1EQ2 ) { status = repositionInnerStream( node, dsh ); if(status != E_DB_OK) break; /* to error */ continue; } else /* key has changed */ { if ( rjoin ) { status = repositionInnerStream( node, dsh ); if(status != E_DB_OK) break; /* to error */ qen_status->node_access |= QEN_LOOKING_FOR_RIGHT_JOINS; continue; /* to get a new inner */ } else /* don't have to return right joins */ { status = clearHoldFiles( node, dsh ); if(status != E_DB_OK) break; /* to error */ } } /* endif comparison of new and old keys */ } /* endif there are inner tuples to rescan */ } /* end first or subsequent times */ } /* end if read_outer */ /********************************************************* ** ** LOGIC TO READ FROM THE INNER TUPLE STREAM ** ** *********************************************************/ if( qen_status->node_access & QEN_READ_NEXT_INNER ) { qen_status->node_access &= ~QEN_READ_NEXT_INNER; if ( !INNER_STREAM_EXHAUSTED ) { /* ** If we're rescanning the hold files and will eventually ** have to look for right joins, read from the hold file ** of inner join flags. */ if ( rjoin && ( ijFlagsHold->hold_status2 & HFILE_REPOSITIONED ) ) { if (qen_u40_readInnerJoinFlag( ijFlagsHold, dsh, ijFlagsShd, &innerTupleJoined ) != E_DB_OK) { /* ** If innerJoinFlags is exhausted and we were ** looking for right joins, then we've found ** all the right joins for this key. Dump the ** hold files. */ if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS) { /* Hold file ends, mark this. Continue reading. */ ijFlagsHold->hold_buffer_status = HFILE6_BUF_EMPTY; ijFlagsHold->hold_status = HFILE2_AT_EOF; if ( qen_status->node_access & QEN_LOOKING_FOR_RIGHT_JOINS ) { qen_status->node_access &= ~( QEN_LOOKING_FOR_RIGHT_JOINS | QEN_READ_NEXT_OUTER ); qen_status->node_access |= QEN_READ_NEXT_INNER; status = clearHoldFiles( node, dsh ); if(status != E_DB_OK) break; /* to error */ continue; /* get next inner */ } } else /* other errors are fatal */ { break; } } /* endif innerJoinFlags read wasn't OK */ } /* endif rjoin and rescanning hold files */ /* Read from hold file if it is positioned */ if (qen_hold->hold_status == HFILE3_POSITIONED) { if (qen_u4_read_positioned(qen_hold, dsh, qen_shd) != E_DB_OK) { if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS) { /* Hold file ends, must read from inner node */ qen_hold->hold_buffer_status = HFILE6_BUF_EMPTY; qen_hold->hold_status = HFILE2_AT_EOF; dsh->dsh_error.err_code = 0; qen_status->node_access |= QEN_READ_NEXT_INNER; if (node->qen_flags & QEN_PART_SEPARATE && !(qen_hold->hold_status2 & HFILE_LAST_PARTITION)) { qen_status->node_status_flags |= QEN4_IPART_END; dsh->dsh_error.err_code = E_QE00A5_END_OF_PARTITION; } continue; /* to read a new inner */ } else /* other, presumably fatal error */ { break; } } /* end if hold end */ if(in_node->qen_type == QE_SORT) /* if hold from sort */ { /* Materialize the inner tuple from sort's row buffer into my row buffer. */ status = qen_execute_cx(dsh, node_xaddrs->qex_itmat); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ rematerializeInnerTuple = FALSE; } /* end if hold from sort */ qen_hold->hold_buffer_status = HFILE7_FROM_HOLD; } /* end if positioned */ /* if not EOF on stream */ else if (qen_status->node_u.node_join.node_inner_status != QEN11_INNER_ENDS) { if(qen_hold->unget_status) /* if occupied */ { /* put unget in row buffer */ MEcopy((PTR)qen_hold->unget_buffer, qen_shd->shd_width, (PTR)qen_shd->shd_row); qen_hold->unget_status = 0; /* set no unget */ qen_hold->hold_buffer_status = HFILE8_FROM_INNER; } else /* get new from stream */ { newinner: status = (*in_node->qen_func)(in_node, qef_rcb, dsh, (in_reset) ? FUNC_RESET : NO_FUNC); in_reset = FALSE; if (status != E_DB_OK) { if (dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS || dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION && (node->qen_flags & QEN_PART_SEPARATE)) { qen_hold->hold_buffer_status = HFILE6_BUF_EMPTY; if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION) qen_status->node_status_flags |= QEN4_IPART_END; /* if just EOPartition, flag it */ /* mark EOF on stream */ qen_status->node_u.node_join.node_inner_status = QEN11_INNER_ENDS; if(qen_hold->hold_status == HFILE2_AT_EOF || qen_hold->hold_status == HFILE0_NOFILE || qen_hold->hold_status == HFILE1_EMPTY ) { qen_status->node_u.node_join.node_hold_stream = QEN5_HOLD_STREAM_EOF; } } else if (dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION) { /* No more rows in partitioning group - read ** from next group. */ in_reset = TRUE; goto newinner; } else { break; /* other, fatal error */ } } else /* inner tuple successfully read */ { /* Materialize the inner tuple into row buffer. */ status = qen_execute_cx(dsh, node_xaddrs->qex_itmat); if (status != E_DB_OK) goto errexit; qen_hold->hold_buffer_status = HFILE8_FROM_INNER; rematerializeInnerTuple = FALSE; } } /* end if unget occupied */ } /* end of read from hold/inner */ } /* endif inner stream not exhausted */ } /* end if read_inner */ /*************************************************************** ** ** LOOK FOR RIGHT JOINS ** ** ***************************************************************/ if ( qen_status->node_access & QEN_LOOKING_FOR_RIGHT_JOINS ) { qen_status->node_access &= ~QEN_READ_NEXT_OUTER; qen_status->node_access |= QEN_READ_NEXT_INNER; if ( innerTupleJoined == FALSE ) { status = qen_execute_cx(dsh, node_xaddrs->qex_rnull); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ if (jqual_excb == NULL) break; /* return right join */ else { status = qen_execute_cx(dsh, jqual_excb); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ if (jqual_excb->excb_value == ADE_TRUE) break; /* to return right join */ } } /* endif inner tuple joined with some outer */ continue; /* evaluate next inner tuple for right joins */ } /* endif looking for right joins */ /*************************************************************** ** ** COMPARE THE INNER AND OUTER JOIN KEYS ** ** ***************************************************************/ if ( INNER_STREAM_EXHAUSTED || qen_hold->hold_buffer_status == HFILE6_BUF_EMPTY ) { join_result = OUTER_LT_INNER; } else if(qen_status->node_u.node_join.node_outer_status == QEN8_OUTER_EOF) { join_result = OUTER_GT_INNER; } else /* we have an inner and outer. join them on the join key. */ { join_result = ADE_1EQ2; if ((ade_excb = node_xaddrs->qex_joinkey) != NULL) { status = qen_execute_cx(dsh, ade_excb); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ join_result = ade_excb->excb_cmp; } if (join_result == ADE_BOTHNULL) { join_result = OUTER_GT_INNER; } else if (join_result == ADE_1ISNULL) { join_result = OUTER_GT_INNER; } else if (join_result == ADE_2ISNULL) { join_result = OUTER_LT_INNER; } } /* endif we have inner and outer */ /*************************************************************** ** ** OUTER AND INNER KEYS NOW JOINED. PERFORM OTHER ** QUALIFICATIONS NOW. EMIT JOINS WHERE APPROPRIATE. ** ***************************************************************/ if (join_result == OUTER_LT_INNER) { qen_status->node_access |= QEN_READ_NEXT_OUTER; qen_status->node_access &= ~QEN_READ_NEXT_INNER; continue; /* get next outer */ } if ( join_result == OUTER_GT_INNER ) { qen_status->node_access &= ~QEN_READ_NEXT_OUTER; qen_status->node_access |= QEN_READ_NEXT_INNER; if ( rjoin ) { /* rematerialize inner tuple if the ultimate outer tuple ** just left joined. rematerialization will reset the ** special equivalence classes from the inner stream. */ if ( rematerializeInnerTuple == TRUE ) { status = qen_execute_cx(dsh, node_xaddrs->qex_itmat); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ rematerializeInnerTuple = FALSE; } /* execute oj_rnull */ status = qen_execute_cx(dsh, node_xaddrs->qex_rnull); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ if (jqual_excb == NULL) break; /* return right join */ else { status = qen_execute_cx(dsh, jqual_excb); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ if (jqual_excb->excb_value == ADE_TRUE) break; /* to return right join */ } } continue; /* get next inner */ } /* endif outer greater than inner */ /* We come to this point when joinkey returns OUTER_EQ_INNER */ if ( join_result != OUTER_EQ_INNER ) { /* consistency check */ dsh->dsh_error.err_code = E_QE0002_INTERNAL_ERROR; status = E_DB_ERROR; goto errexit; } /* end consistency check */ if (qen_hold->hold_buffer_status == HFILE8_FROM_INNER) { /* append to hold */ status = qen_u1_append(qen_hold, qen_shd, dsh); if(status) break; /* to return error */ } /* If this is the first inner that joins with the current ** outer, save the hold file TID so we can reposition it later. */ if ( !( qen_status->node_access & QEN_RESCAN_MARKED ) ) { if ( qen_u5_save_position(qen_hold, qen_shd) ) goto errexit; qen_status->node_access |= QEN_RESCAN_MARKED; } else if ((node->qen_flags & QEN_CARD_MASK) == QEN_CARD_01R && (qen_status->node_access & QEN_OUTER_HAS_JOINED) != 0) { /* Left outer - note cardinality */ potential_card_violation = TRUE; } qen_status->node_access &= ~QEN_READ_NEXT_OUTER; qen_status->node_access |= QEN_READ_NEXT_INNER; /* execute OQUAL */ ade_excb = node_xaddrs->qex_onqual; status = qen_execute_cx(dsh, ade_excb); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ if (ade_excb == NULL || ade_excb->excb_value == ADE_TRUE) { /* not OJ, or OQUAL succeeds. Remember that a join occurred. */ qen_status->node_access |= QEN_OUTER_HAS_JOINED; if ( rjoin ) { if ( status = qen_u41_storeInnerJoinFlag( ijFlagsHold, ijFlagsShd, dsh, innerTupleJoined, ( i4 ) TRUE ) ) goto errexit; /* error */ } /* set the special eqcs to "inner join" state */ status = qen_execute_cx(dsh, node_xaddrs->qex_eqmat); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ if (jqual_excb != NULL) { status = qen_execute_cx(dsh, jqual_excb); if (status != E_DB_OK) goto errexit; /* if ade error, return error */ } if( jqual_excb == NULL || jqual_excb->excb_value == ADE_TRUE) { /* JQUAL succeeds */ if(node->node_qen.qen_sjoin.sjn_kuniq) /* if kuniq */ { /* make next entry read new outer bit not new inner */ qen_status->node_access |= QEN_READ_NEXT_OUTER; qen_status->node_access &= ~QEN_READ_NEXT_INNER; } /* endif key unique */ if (potential_card_violation) { /* We only want to act on seltype violation after ** qualification and that is now. */ qen_status->node_status = QEN7_FAILED; dsh->dsh_error.err_code = E_QE004C_NOT_ZEROONE_ROWS; status = E_DB_ERROR; goto errexit; } break; /* emit inner join */ } } else /* OQUAL failed */ { if ( rjoin ) { if ( status = qen_u41_storeInnerJoinFlag( ijFlagsHold, ijFlagsShd, dsh, innerTupleJoined, ( i4 ) FALSE ) ) goto errexit; /* error */ } } /* end check of OQUAL status */ /* OQUAL or JQUAL failed. Get next inner. */ continue; } /* end of get loop */ /******************************************************************** ** ** CLEANUP. MATERIALIZE FUNCTION ATTRIBUTES. ERROR EXIT WHEN ** APPROPRIATE. ** ********************************************************************/ if (status == E_DB_OK) { status = qen_execute_cx(dsh, node_xaddrs->qex_fatts); if (status != E_DB_OK) goto errexit; /* Increment the count of rows that this node has returned */ qen_status->node_rcount++; /* print tracing information DO NOT xDEBUG THIS */ if (node->qen_prow != NULL && (ult_check_macro(&qef_cb->qef_trace, 100+node->qen_num, &val1, &val2) || ult_check_macro(&qef_cb->qef_trace, 99, &val1, &val2) ) ) { if (status == E_DB_OK) { status = qen_print_row(node, qef_rcb, dsh); if (status != E_DB_OK) { goto errexit; } } } #ifdef xDEBUG (VOID) qe2_chk_qp(dsh); #endif } else { if(in_node->qen_type == QE_SORT) /* if sort child */ /* release the memory now if in memory */ { qen_u31_release_mem(qen_hold, dsh, dsh->dsh_shd[in_node->node_qen.qen_sort.sort_shd] ); } else if(qen_hold) /* if hold file */ { /* release our hold file, if in memory */ qen_u31_release_mem(qen_hold, dsh, qen_shd ); } } errexit: if ((dsh->dsh_error.err_code == E_QE0015_NO_MORE_ROWS || dsh->dsh_error.err_code == E_QE00A5_END_OF_PARTITION) && (qen_status->node_status_flags & (QEN2_OPART_END | QEN4_IPART_END))) { /* Restart using next partitioning group. */ out_reset = in_reset = reset = TRUE; qen_status->node_status_flags &= ~(QEN2_OPART_END | QEN4_IPART_END); goto loop_reset; } if (dsh->dsh_qp_stats) { qen_ecost_end(dsh, &timerstat, qen_status); } return (status); }
DB_STATUS tpd_s4_abort_to_svpt( TPR_CB *v_tpr_p, i4 i_new_svpt_cnt, DB_SP_NAME *i_svpt_name_p) { DB_STATUS status = E_DB_OK; DB_ERROR save_err; bool ok = TRUE; /* indicate whether all aborts are OK */ TPD_SS_CB *sscb_p = (TPD_SS_CB *) v_tpr_p->tpr_session; TPD_DX_CB *dxcb_p = & sscb_p->tss_dx_cb; /* transaction context */ TPD_LM_CB *splm_p = & dxcb_p->tdx_23_sp_ulmcb, *lxlm_p = & dxcb_p->tdx_22_lx_ulmcb; TPD_LX_CB *lxcb_p = NULL; TPD_SP_CB *spcb_p = NULL; i4 i, j; bool trace_svpt_103 = FALSE, trace_err_104 = FALSE; i4 i4_1, i4_2; RQR_CB rqr_cb; /* RQF request control block */ char svpt_name[sizeof(DB_SP_NAME) + 1], qrytxt[100]; if (ult_check_macro(& sscb_p->tss_3_trace_vector, TSS_TRACE_SVPT_103, & i4_1, & i4_2)) { trace_svpt_103 = TRUE; } if (ult_check_macro(& sscb_p->tss_3_trace_vector, TSS_TRACE_ERROR_104, & i4_1, & i4_2)) { trace_err_104 = TRUE; } rqr_cb.rqr_q_language = v_tpr_p->tpr_lang_type; rqr_cb.rqr_session = sscb_p->tss_rqf; rqr_cb.rqr_dv_cnt = 0; rqr_cb.rqr_dv_p = (DB_DATA_VALUE *) NULL; tpd_u0_trimtail(i_svpt_name_p, sizeof(DB_SP_NAME), svpt_name); if (v_tpr_p->tpr_lang_type == DB_QUEL) STprintf(qrytxt, "%s %s;", IITP_11_abort_to_p, svpt_name); else STprintf(qrytxt, "%s %s;", IITP_12_rollback_to_p, svpt_name); rqr_cb.rqr_msg.dd_p1_len = (i4) STlength(qrytxt); rqr_cb.rqr_msg.dd_p2_pkt_p = qrytxt; rqr_cb.rqr_msg.dd_p3_nxt_p = NULL; /* loop through each site to abort to this savepoint if known to the site */ lxcb_p = (TPD_LX_CB *) lxlm_p->tlm_3_frst_ptr; i = 0; while (lxcb_p != (TPD_LX_CB *) NULL && status == E_DB_OK) { if (i_new_svpt_cnt <= lxcb_p->tlx_sp_cnt) /* LDB has knowledge of this ** savepoint */ { /* set up to inform of rollback to this savepoint */ rqr_cb.rqr_1_site = & lxcb_p->tlx_site; /* skip CDB if DDL_CONCURRENCY is ON */ if (! (sscb_p->tss_ddl_cc && rqr_cb.rqr_1_site->dd_l1_ingres_b)) { rqr_cb.rqr_dv_cnt = 0; rqr_cb.rqr_dv_p = (DB_DATA_VALUE *) NULL; rqr_cb.rqr_timeout = 0; if (trace_svpt_103) tpd_p5_prt_tpfqry(v_tpr_p, qrytxt, & lxcb_p->tlx_site, TPD_0TO_FE); status = tpd_u4_rqf_call(RQR_QUERY, & rqr_cb, v_tpr_p); if (status) { if (trace_err_104) tpd_p5_prt_tpfqry(v_tpr_p, qrytxt, & lxcb_p->tlx_site, TPD_0TO_FE); STRUCT_ASSIGN_MACRO(v_tpr_p->tpr_error, save_err); ok = FALSE; } lxcb_p->tlx_20_flags |= LX_01FLAG_REG; /* Register.. */ } lxcb_p->tlx_sp_cnt = i_new_svpt_cnt; /* these are all savepoints ** the LDB has knowledge of */ } lxcb_p = lxcb_p->tlx_22_next_p; ++i; /* debugging aid */ } /* update to reflect fewer outstanding session savepoints if necessary */ if (i_new_svpt_cnt < splm_p->tlm_2_cnt) { spcb_p = (TPD_SP_CB *) splm_p->tlm_3_frst_ptr; for (i = 1; (spcb_p != (TPD_SP_CB *) NULL) && (i < i_new_svpt_cnt); ++i) { if (spcb_p != (TPD_SP_CB *) NULL) spcb_p = spcb_p->tsp_4_next_p; } if (i != i_new_svpt_cnt) ok = FALSE; else { /* update to reflect */ spcb_p->tsp_4_next_p = (TPD_SP_CB *) NULL; splm_p->tlm_4_last_ptr = (PTR) spcb_p; splm_p->tlm_2_cnt = i_new_svpt_cnt; } } if (ok) return(E_DB_OK); else { STRUCT_ASSIGN_MACRO(save_err, v_tpr_p->tpr_error); return(E_DB_ERROR); } }
/*{ ** Name: psq_parseqry - Parse a query and return a data structure ** ** INTERNAL PSF call format: status = psq_parseqry(&psq_cb, &sess_cb); ** ** EXTERNAL call format: status = psq_call(PSQ_PARSEQRY, &psq_cb, &sess_cb); ** ** Description: ** This function will parse a query in QSF memory. It will return a ** data structure (such as a query tree), and a code telling what kind of ** query was just parsed (e.g. a copy statement). This code will be ** called the "query mode". For qrymod definitions, it will store a ** modified version of the query text in QSF, for later insertion in the ** iiqrytext system relation. ** ** This function will check the syntax of each statement, and will perform ** some semantic validations. The syntax checking will be rather simple: ** each statement will either be right or wrong, and a syntax error will ** cause the whole go block to be aborted. Semantic checks will be more ** complicated; some of them will cause warnings (which will allow the ** statement to continue), and some will cause errors (causing the ** statement to be aborted). It should be noted that the semantic checks ** will not be the same in the Jupiter version as in previous versions; ** in the Jupiter version, for instance, the parser won't check for whether ** the statement is valid inside a multi-query transaction. ** ** Sometimes it will be found that the definition of a view, permit, or ** integrity is out of date. When this happens, this function will return ** an error status saying so, and an id for finding the query text in the ** iiqrytext relation, so that the definition can be re-parsed and ** re-stored. Accordingly, this function has an option by which one can ** tell it to get the query text out of the iiqrytext relation instead of ** QSF. ** ** When a statement is parsed that creates a new cursor, the parser will ** assign a cursor id to the cursor, create a cursor control block ** containing information about the cursor, and return the cursor id inside ** with the query tree representing the cursor. This cursor id will be ** used throughout the session to uniquely identify the cursor. When a ** "close cursor" statement is parsed, the parser will deallocate the ** control block associated with the cursor. ** ** The parser will automatically apply view, permit, and integrity ** processing to any data manipulation query it parses. This will not ** require a separate call to the parser. ** ** Multi-statement go blocks are no longer allowed, as they used to be in ** previous versions. This parser can handle only one statement at a time. ** ** Inputs: ** psq_cb ** .psq_qid A unique identifier for getting the ** query text from QSF. ** .psq_iiqrytext TRUE means to get the query text from ** the iiqrytext relation, not QSF. ** .psq_txtid Query text id key into iiqrytext ** relation; used only if above is true. ** sess_cb Pointer to the session control block ** ** Outputs: ** psq_cb ** .psq_qlang The language of the query text. ** .psq_mode The query mode (a code telling what ** kind of query was just parsed). ** .psq_result QSF id for the data structure produced ** (query tree, or control block stored as ** QEP). ** .psq_txtid Query text id key into iiqrytext ** relation; filled in if some qrymod ** object needs redefining. ** .psq_mnyfmt Set on a "set money_format" or ** "set money_prec" statement ** .psq_dtefmt Set on a "set date_format" statement ** .psq_decimal Set on a "set decimal" statement ** .psq_error Standard error block ** E_PS0000_OK Success ** E_PS0001_USER_ERROR Mistake by user ** E_PS0002_INTERNAL_ERROR Internal inconsistency inside PSF ** E_PS0B01_OUTDATED_VIEW View out of date; must re-define ** E_PS0B02_OUTDATED_PERMIT Permit out of date; must re-define ** E_PS0B03_OUTDATED_INTEG Integrity out of date; must re-def. ** E_PS0B04_CANT_GET_TEXT Can't get query text ** .psq_txtout QSF id for the create procedure stmt to ** be stored in the system catalog. ** ** 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 query tree or control block in QSF. ** Can open a cursor. ** ** History: ** 01-oct-85 (jeff) ** written ** 19-sep-86 (daved) ** end of qry should point to last char. This char should be a space. ** this makes the scanner's job easier ** 27-jan-87 (daved) ** add the printqry set command. ** 02-oct-87 (stec) ** Removed pss_journaling flag initialization; ** must be initialized in psqbgnses.c ** 19-jan-88 (stec) ** Changed initialization od pst_resloc. ** 25-may-88 (stec) ** Made changes in connection with DB procedures. ** QSF object of QP type has to be destroyed if ** translate_or_define worked for CREATE PROCEDURE. ** 23-aug-88 (stec) ** Initialize qso_handle in QSO_OBIDs in psq_cb. ** 21-apr-89 (neil) ** Extracted some initialization (psq_cbinit) from psq_parseqry to ** allow it to be called from other routines as well. ** 11-dec-89 (ralph) ** Change interface to QSO for dbprocs ** 12-sep-90 (teresa) ** fix faulty pss_retry logic. ** 15-jun-92 (barbara) ** Sybil merge. Pass in sess control block to pst_clrrng. ** 23-nov-92 (barbara) ** For Star, accept range statement as the one and only allowable ** QUEL statement. This is to support old FE's which use the range ** statement as a quick way to ascertain table existence. FEs of ** >= 6.5 vintage use a table_resolve() function, so at some point ** we can remove the QUEL range table statement support for Star. ** 24-nov-92 (ralph) ** CREATE SCHEMA: ** Initialize pss_prvgoval ** 22-dec-92 (rblumer) ** clean up after pss_tchain2 just like pss_tchain. ** 25-may-93 (rog) ** Move clean-up/exit code into psq_cbreturn() and then call it. ** 11-oct-93 (swm) ** Bug #56448 ** Declared trbuf for psf_display() to pass to TRformat. ** TRformat removes `\n' chars, so to ensure that psf_scctrace() ** outputs a logical line (which it is supposed to do), we allocate ** a buffer with one extra char for NL and will hide it from TRformat ** by specifying length of 1 byte less. The NL char will be inserted ** at the end of the message by psf_scctrace(). ** 16-mar-94 (andre) ** if performing an internal PSF retry and trace point ps129 (same as *8 SET PRINTQRY) is set, instead of redisplaying the query we will *8 tell the user that we are retrying the last query. ** 28-feb-2005 (wanfr01) ** Bug 64899, INGSRV87 ** Add stack overflow handler for TRU64. ** 17-mar-06 (dougi) ** Init pss_hintcount to 0 for optimizer hints project. ** 23-june-06 (dougi) ** Init pss_stmtno to 1 for procedure debugging. ** 05-sep-06 (toumi01) ** Init pss_stmtno to 0 (to match new "help procedure" numbering) ** lest we point, PC register like, to the _following_ statement. ** 15-Sep-2008 (kibro01) b120571 ** Use same session ID as available in iimonitor ** 16-Sep-2008 (kibro01) b120571 ** Remove compilation error from cast of sessid ** 16-Feb-2009 (kibro01) b121674 ** Add version to SESSION BEGINS message in sc930 and give out ** data type of parameters. ** 10-Jul-2009 (kibro01) b122299 ** Increase the version number due to dates being printed out now. ** 15-Jul-2009 (kibro01) b122172 ** Change QUERY or QUEL to REQUERY or REQUEL when a DB procedure is ** reparsed due to being invalidated. ** 23-Jul-2009 (kibro01) b122172 ** Separate the print_qry_buffer logic to avoid stack size problems. ** 3-Aug-2009 (kibro01) b122393 ** Use print_qry_buffer_ptr to avoid inlining. ** 4-Aug-2009 (kibro01) b122172 ** Allow REQUERY/REQUEL through even if the RECREATE flag is set so ** we get the useful debug output. ** 28-Oct-2009 (maspa05) b122725 ** ult_print_tracefile now uses integer constants instead of string ** for type parameter - SC930_LTYPE_PARM instead of "PARM" and so on ** Also moved function definitions for SC930 tracing to ulf.h ** The functions involved were - ult_always_trace, ult_open_tracefile ** ult_print_tracefile and ult_close_tracefile */ DB_STATUS psq_parseqry( register PSQ_CB *psq_cb, register PSS_SESBLK *sess_cb) { DB_STATUS status; DB_STATUS ret_val; QSF_RCB qsf_rb; i4 err_code; PSQ_QDESC *qdesc; i4 val1 = 0; i4 val2 = 0; i4 i; char trbuf[PSF_MAX_TEXT + 1]; /* last char for `\n' */ if ((status = psq_cbinit(psq_cb, sess_cb)) != E_DB_OK) return (status); /* ** The following is particular to queries that must be parsed. ** Get query text from QSF and put it in session control block ** Initialize the qbuf, nextchar, prevtok, and bgnstmt pointers */ qsf_rb.qsf_type = QSFRB_CB; qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rb.qsf_length = sizeof(qsf_rb); qsf_rb.qsf_owner = (PTR)DB_PSF_ID; qsf_rb.qsf_sid = sess_cb->pss_sessid; qsf_rb.qsf_obj_id.qso_handle = psq_cb->psq_qid; status = qsf_call(QSO_INFO, &qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0B04_CANT_GET_TEXT, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } qdesc = (PSQ_QDESC*) qsf_rb.qsf_root; /* print the qry buffer as long as this isn't a retry ** - although allow through the RECREATE case since it's useful ** for debugging to log reparsing an object */ if ((ult_always_trace() & SC930_TRACE) && ( ((sess_cb->pss_retry & PSS_REFRESH_CACHE)==0) || (sess_cb->pss_dbp_flags & PSS_RECREATE) != 0 ) ) { (*print_qry_buffer_ptr)(psq_cb, qdesc, sess_cb); } if (ult_check_macro(&sess_cb->pss_trace, PSS_PRINT_QRY_TRACE, &val1, &val2)) { if (psf_in_retry(sess_cb, psq_cb)) { psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "\n...retrying last query...\n"); } else { psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "\nQUERY BUFFER:\n"); psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "%.#s\n", qdesc->psq_qrysize, qdesc->psq_qrytext); psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "\nQUERY PARAMETERS:\n"); for (i = 0; i < qdesc->psq_dnum; i++) { psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "Parameter : %d\n", i); adu_2prvalue(psf_relay, qdesc->psq_qrydata[i]); psf_display(psf_scctrace, 0, trbuf, sizeof(trbuf) - 1, "\n"); } } } sess_cb->pss_bgnstmt = (u_char*) qdesc->psq_qrytext; sess_cb->pss_prvgoval = (u_char*) NULL; sess_cb->pss_prvtok = (u_char*) qdesc->psq_qrytext; sess_cb->pss_qbuf = (u_char*) qdesc->psq_qrytext; sess_cb->pss_nxtchar = (u_char*) qdesc->psq_qrytext; sess_cb->pss_endbuf = sess_cb->pss_qbuf + qdesc->psq_qrysize - 1; sess_cb->pss_dmax = qdesc->psq_dnum; sess_cb->pss_qrydata = qdesc->psq_qrydata; *sess_cb->pss_endbuf = ' '; sess_cb->pss_lineno = 1; /* Start out at line one */ sess_cb->pss_stmtno = 0; /* and statement at zero */ sess_cb->pss_dval = 0; sess_cb->pss_hintcount = 0; psl_yinit(sess_cb); if (psq_cb->psq_qlang == DB_QUEL) { if (sess_cb->pss_distrib & DB_3_DDB_SESS) { char *c; char *r = "range"; /* skip leading white space chars, if any */ for (c = qdesc->psq_qrytext; c <= (char *) sess_cb->pss_endbuf && CMwhite(c); CMnext(c) ) ; /* compare the first word with "range" */ for (; *r != EOS && c <= (char *) sess_cb->pss_endbuf && !CMcmpnocase(c,r); CMnext(c), CMnext(r) ) ; /* ** we will go on to parse this statement iff ** 1) first non-white chars are "range" AND ** 2) 'e' is followed by a white space */ if (*r != EOS || c >= (char *) sess_cb->pss_endbuf || !CMwhite(c)) { (VOID) psf_error(5212L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error,0); return(E_DB_ERROR); } } sess_cb->pss_parser = pslparse; } else { sess_cb->pss_parser = pslsparse; } IIEXtry { status = (*sess_cb->pss_parser)(sess_cb, psq_cb); } IIEXcatch(pthread_stackovf_e) { (VOID) psf_error(5212L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error,0); } IIEXendtry ret_val = psq_cbreturn(psq_cb, sess_cb, status); return (ret_val); }
/*{ ** 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); }
DB_STATUS qeq_c5_replace( QEF_RCB *v_qer_p, QEE_DSH *i_dsh_p ) { DB_STATUS status = E_DB_OK; QEE_DSH *ree_p = i_dsh_p->dsh_aqp_dsh; /* must use update dsh for ** cursor */ QEE_DDB_CB *uee_p = ree_p->dsh_ddb_cb; QES_DDB_SES *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses; QES_QRY_SES *qss_p = & dds_p->qes_d8_union.u2_qry_ses; QEQ_DDQ_CB *ddq_p = & i_dsh_p->dsh_qp_ptr->qp_ddq_cb; QEF_AHD *act_p = i_dsh_p->dsh_qp_ptr->qp_ahd; QEQ_D1_QRY *sub_p = & act_p->qhd_obj.qhd_d1_qry; bool log_qry_55 = FALSE, log_err_59 = FALSE; i4 i4_1, i4_2; TPR_CB tpr, *tpr_p = & tpr; RQR_CB rqr, *rqr_p = & rqr; if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_QRY_55, & i4_1, & i4_2)) { log_qry_55 = TRUE; qeq_p35_upd_csr(v_qer_p, i_dsh_p); } if (ult_check_macro(& v_qer_p->qef_cb->qef_trace, QEF_TRACE_DDB_LOG_ERR_59, & i4_1, & i4_2)) log_err_59 = TRUE; /* 2. then set up to call RQF to replace */ MEfill(sizeof(rqr), '\0', (PTR) & rqr); rqr_p->rqr_session = dds_p->qes_d3_rqs_p; /* RQF session id */ rqr_p->rqr_q_language = qss_p->qes_q2_lang; rqr_p->rqr_timeout = sub_p->qeq_q2_quantum; STRUCT_ASSIGN_MACRO(*sub_p->qeq_q4_seg_p->qeq_s2_pkt_p, rqr_p->rqr_msg); rqr_p->rqr_1_site = sub_p->qeq_q5_ldb_p; if (sub_p->qeq_q8_dv_cnt == 0) { rqr_p->rqr_dv_cnt = v_qer_p->qef_pcount; rqr_p->rqr_dv_p = (DB_DATA_VALUE *) v_qer_p->qef_param; /* pass array base */ } else { rqr_p->rqr_dv_cnt = ddq_p->qeq_d4_total_cnt; rqr_p->rqr_dv_p = ddq_p->qeq_d6_fixed_data; /* rqr_p->rqr_dv_p = uee_p->qee_d7_dv_p + 1;*/ /* 1-based, make 0-based */ } rqr_p->rqr_qid_first = sub_p->qeq_q12_qid_first; STRUCT_ASSIGN_MACRO(uee_p->qee_d5_local_qid, rqr_p->rqr_qid); rqr_p->rqr_tmp = uee_p->qee_d1_tmp_p; qss_p->qes_q1_qry_status |= QES_03Q_PHASE2; /* enter phase 2 for update */ status = qed_u3_rqf_call(RQR_UPDATE, rqr_p, v_qer_p); if (status) { if (log_err_59 && !log_qry_55) qeq_p35_upd_csr(v_qer_p, i_dsh_p); return(status); } else qss_p->qes_q1_qry_status &= ~QES_03Q_PHASE2; v_qer_p->qef_rowcount = rqr_p->rqr_tupcount; v_qer_p->qef_count = rqr_p->rqr_tupcount; /* return update row count */ return(E_DB_OK); }