/*{ ** Name: QEU_CLOSE - close an opened table ** ** External QEF call: status = qef_call(QEU_CLOSE, &qeu_cb); ** ** Description: ** Close a table opened through the QEU_OPEN command. ** ** Inputs: ** qeu_cb ** .qeu_eflag designate error handling semantis ** for user errors. ** QEF_INTERNAL return error code. ** QEF_EXTERNAL send message to user. ** .qeu_acc_id table access id ** ** Outputs: ** qeu_cb ** .error.err_code One of the following ** E_QE0000_OK ** E_QE0002_INTERNAL_ERROR ** E_QE0004_NO_TRANSACTION ** E_QE0007_NO_CURSOR ** E_QE0017_BAD_CB ** E_QE0018_BAD_PARAM_IN_CB ** Returns: ** E_DB_OK ** E_DB_ERROR caller error ** E_DB_FATAL internal error ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 27-may-86 (daved) ** written ** 14-may-87 (daved) ** zero the access id to cause an error in DMF if a table is ** closed twice. */ DB_STATUS qeu_close( QEF_CB *qef_cb, QEU_CB *qeu_cb) { i4 err; DMT_CB dmt_cb; DB_STATUS status; /* QEU_CLOSE is only valid in a transaction */ if (qef_cb->qef_stat == QEF_NOTRAN) { qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err, &qeu_cb->error, 0); return (E_DB_ERROR); } MEfill(sizeof(DMT_CB), 0, (PTR) &dmt_cb); dmt_cb.type = DMT_TABLE_CB; dmt_cb.length = sizeof(DMT_CB); dmt_cb.dmt_flags_mask = 0; dmt_cb.dmt_record_access_id = qeu_cb->qeu_acc_id; status = dmf_call(DMT_CLOSE, &dmt_cb); if (status != E_DB_OK) { qef_error(dmt_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0); } else qef_cb->qef_open_count--; qeu_cb->qeu_acc_id = (PTR) NULL; return (status); }
/* ** { ** Name: QEA_RUPDATE - update the current cursor ** ** External QEF call: status = qef_call(QEQ_REPLACE, &qef_rcb); ** ** Description: ** The current row in the named cursor (QP) is ** updated and sent to DMF ** ** Inputs: ** action Update current row of cursor action. ** qef_rcb ** assoc_dsh DSH for QP for cursor to be updated. ** reset ** state DSH_CT_INITIAL if this is an action call ** DSH_CT_CONTINUE for call back after processing ** a rule action list. ** ** Outputs: ** qef_rcb ** .qef_remnull SET if an aggregate computation found a NULL val ** .qef_rowcount number of rows replaced ** .qef_targcount number of attempted replaces ** .error.err_code one of the following ** E_QE0000_OK ** E_QE0017_BAD_CB ** E_QE0018_BAD_PARAM_IN_CB ** E_QE0019_NON_INTERNAL_FAIL ** E_QE0002_INTERNAL_ERROR ** E_QE0008_CURSOR_NOT_OPENED ** E_QE0021_NO_ROW ** E_QE0009_NO_PERMISSION ** E_QE000A_READ_ONLY ** E_QE0012_DUPLICATE_KEY ** E_QE0010_DUPLIATE_ROW ** E_QE0011_AMBIGUOUS_REPLACE ** E_QE0013_INTEGRITY_FAILED ** E_QE0024_TRANSACTION_ABORTED ** E_QE0034_LOCK_QUOTA_EXCEEDED ** E_QE0035_LOCK_RESOURCE_BUSY ** E_QE0036_LOCK_TIMER_EXPIRED ** E_QE002A_DEADLOCK ** Returns: ** E_DB_{OK,WARN,ERROR,FATAL} ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 11-JUN-86 (daved) ** written ** 22-may-87 (daved) ** catch cursor not positioned errors ** 14-oct-87 (puree) ** make sure that qen_error is called in case of E_DB_ERROR from ** qeq_validate. ** 02-feb-88 (puree) ** added reset flag to qeq_validate and all qea_xxxx call sequence. ** 29-aug-88 (puree) ** implement replace cursor by tid if the cursor was position on ** a secondary index table and by current position if the cursor ** is positioned on the base table. ** fix duplicate handling error. ** 12-oct-88 (puree) ** If a table validation fails during cursor replace, abort the ** cursor. ** 23-feb-89 (paul) ** Clean up qef_cb state before returning. ** 17-apr-89 (paul) ** Processing cursor updates integrated into qeq_query. Update cursor ** logic moved from qeq.c to this file (qearupd.c). This routine is ** a simplified version of what was previously called qeq_replace. ** 25-sep-89 (paul) ** Added support for using TIDs as parameters to procedures invoked ** from rules. ** 25-jan-90 (nancy) -- set status to E_DB_OK when replace cursor ** causes dups and duplicate handling is set to SKIP_DUPS. ** 29-jan-90 (nancy) -- fix bug 8388 (8575), use assoc dsh for replace ** by tid. ** 29-jun-90 (davebf) ** Handle rows which were accessed by TID only (bug 31113) ** 5-Nov-1993 (fred) ** Remove any remaining large object temporaries. ** 7-Apr-1994 (fred) ** Commented out large object removal pending better way... ** 7-nov-95 (inkdo01) ** Changes to replace QEN_ADF structure instances by pointers in ** QEF_AHD structures. ** 29-dec-03 (inkdo01) ** DSH is now parameter, "function" replaces "reset". ** 5-feb-04 (inkdo01) ** Add support for partitioned tables. ** 12-mar-04 (inkdo01) ** Fix to handle bigtids on byte-swapped machines. ** 19-mar-04 (inkdo01) ** Fix for bigtids and rules. ** 12-may-04 (inkdo01) ** Call qeq_part_open unconditionally - it'll determine whether ** partition cbs are already prepared. ** 8-Jul-2004 (schka24) ** Still some tid byte-ordering confusion on x86, make tid handling ** more portable. ** 26-aug-04 (inkdo01) ** Add global base array support for update buffer. ** 24-Feb-05 (hweho01) ** The copying of tid needs to be handled differently if ** TID_SWAP is defined, so the tid value can be preserved. ** Star #13864021. ** 28-Feb-2005 (schka24) ** Rework the above fix, it turns out that the underlying problem ** was the 4byte-tidp flag not getting set. Now that it's set ** properly, obey it here. Also, do partition opens against the ** cursor query, not the RUP -- it's the one with the valid list.. ** 18-Jul-2005 (schka24) ** Well, I fixed by-tid updates, but not true in-place updates! ** Use new ahd_ruporig machinery to get at the current partition ** number for in-place updating. ** 13-Dec-2005 (kschendel) ** Can count on qen-ade-cx now. ** 16-Jan-2006 (kschendel) ** Access qen-status thru xaddrs. ** 20-june-06 (dougi) ** Add support for BEFORE triggers. ** 1-Nov-2006 (kschendel) ** Some fixes to BEFORE triggers, make sure things are set up. ** 7-mar-2007 (dougi) ** Slight change to address the DMR_CB (broken by BEFORE changes). ** 8-Sep-2008 (kibro01) b120693 ** Remove unused action parameter from qeq_part_open ** 09-Sep-2009 (thaju02) B122374 ** If BEFORE trigger has been executed, do not use ahd_upd_colmap. ** ahd_upd_colmap may not reflect cols updated by the rule/proc. ** 15-Jan-2010 (jonj) ** SIR 121619 MVCC: If E_DM0029_ROW_UPDATE_CONFLICT returned, ** invalidate the QP and retry. ** 1-Jul-2010 (kschendel) b124004 ** Minor changes for RUP from scrollable keyset cursors; the ** fetched row is always in dsh-qef-output. */ DB_STATUS qea_rupdate( QEF_AHD *act, QEF_RCB *qef_rcb, QEE_DSH *dsh, QEE_DSH *assoc_dsh, i4 function, i4 state ) { i4 err; DB_STATUS status = E_DB_OK; QEF_CB *qef_cb = dsh->dsh_qefcb; ADF_CB *adfcb = dsh->dsh_adf_cb; DMR_CB *dmr_cb, *pdmr_cb; QEN_ADF *qen_adf; ADE_EXCB *ade_excb; PTR *assoc_cbs = assoc_dsh->dsh_cbs; PTR output, save_addr; char *tidinput; /* location of tid */ DB_TID8 oldbigtid, newbigtid; u_i2 oldpartno = 0; u_i2 newpartno = 0; i4 odmr_cb_ix; /* CB number of DMR_CB */ i4 orig_node; status = E_DB_OK; for (;;) { /* A cursor update affects only a single row. If we are called back */ /* after rules processing simply return. */ if (state == DSH_CT_CONTINUE) break; /* Address the DMR_CB used to access the row. The odmr_cb_ix is in ** the associated (cursor) QP context. We'll adjust for partitioning ** a bit later. */ odmr_cb_ix = act->qhd_obj.qhd_qep.ahd_odmr_cb; dmr_cb = (DMR_CB*) assoc_cbs[odmr_cb_ix]; if (status == DSH_CT_CONTINUE3) { /* Resuming from a BEFORE trigger, reset variables */ MEcopy(dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_tid], sizeof(DB_TID8), (PTR) &newbigtid); MEcopy(dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_tid], sizeof(DB_TID8), (PTR) &oldbigtid); oldpartno = oldbigtid.tid.tid_partno; newpartno = newbigtid.tid.tid_partno; output = dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_row]; if (act->qhd_obj.qhd_qep.ahd_part_def != NULL) dmr_cb = (DMR_CB *) assoc_cbs[odmr_cb_ix + oldpartno + 1]; } else { /* Normal path */ dsh->dsh_qef_remnull = 0; dsh->dsh_qef_rowcount = 0; /* Use fetch row for holding update row if need be */ output = assoc_dsh->dsh_row[assoc_dsh->dsh_qp_ptr->qp_fetch_ahd->qhd_obj.qhd_qep.ahd_ruprow]; /* make sure we have a positioned record */ if (assoc_dsh->dsh_positioned == FALSE) { /* no record could be valid in this action's updatable control block. ** Nor do we know what we will be looking at when we access the ** update control block index number */ dsh->dsh_error.err_code = E_QE0021_NO_ROW; status = E_DB_ERROR; break; } /* check that this query plan has update privilege */ if ((assoc_dsh->dsh_qp_ptr->qp_status & QEQP_UPDATE) == 0) { /* no permission */ dsh->dsh_error.err_code = E_QE0009_NO_PERMISSION; status = E_DB_ERROR; break; } if (qef_cb->qef_c1_distrib & DB_3_DDB_SESS) /* distributed? */ { /* DDB processing */ status = qeq_c5_replace(qef_rcb, dsh); if (status == E_DB_OK) dsh->dsh_qef_rowcount = 1; else dsh->dsh_qef_rowcount = 0; return(status); } /* LDB processing */ /* process the qualification expression */ qen_adf = act->qhd_obj.qhd_qep.ahd_constant; if (qen_adf != NULL) { ade_excb = (ADE_EXCB*) dsh->dsh_cbs[qen_adf->qen_pos]; if (dsh->dsh_qp_ptr->qp_status & QEQP_GLOBAL_BASEARRAY) dsh->dsh_row[qen_adf->qen_uoutput] = output; else ade_excb->excb_bases[ADE_ZBASE + qen_adf->qen_uoutput] = output; status = qen_execute_cx(dsh, ade_excb); if (status != E_DB_OK) break; /* handle condition where qualification failed. */ if (ade_excb->excb_value != ADE_TRUE) { dsh->dsh_qef_targcount = 1; dsh->dsh_qef_rowcount = 0; break; } } /* REPLACE THE TUPLE ** if the cursor is positioned on the base table (ahd_tidoffset is ** -1), replace the tuple at the current position. Otherwise the ** cursor must have been positioned via a secondary index. Get ** the tid, re-fetch the original row by tid, and replace the ** base table tuple by the tid. */ if (act->qhd_obj.qhd_qep.ahd_tidoffset == -1) { /* If partitioned, dig the current partition number out of ** the node status for the orig (or kjoin/tjoin) node that ** fetched the row in the first place. OPC has kindly put ** the node number of same into ahd_ruporig. */ if (act->qhd_obj.qhd_qep.ahd_part_def != NULL) { orig_node = act->qhd_obj.qhd_qep.ahd_ruporig; if (orig_node == -1) { TRdisplay("%@ qea_rupd: missing ahd_ruporig\n"); dsh->dsh_error.err_code = E_QE0002_INTERNAL_ERROR; status = E_DB_ERROR; break; } oldpartno = assoc_dsh->dsh_xaddrs[orig_node]-> qex_status->node_ppart_num; dmr_cb = (DMR_CB *) assoc_cbs[odmr_cb_ix + oldpartno + 1]; } dmr_cb->dmr_flags_mask = DMR_CURRENT_POS; } else { /* set the tid */ tidinput = (char *) assoc_dsh->dsh_row[act->qhd_obj.qhd_qep.ahd_tidrow] + act->qhd_obj.qhd_qep.ahd_tidoffset; if (act->qhd_obj.qhd_qep.ahd_qepflag & AHD_4BYTE_TIDP) { I4ASSIGN_MACRO(*tidinput, oldbigtid.tid_i4.tid ); oldbigtid.tid_i4.tpf = 0; } else { I8ASSIGN_MACRO(*tidinput, oldbigtid); } oldpartno = oldbigtid.tid.tid_partno; newpartno = oldpartno; /* Check for partitioning and set up DMR_CB. */ if (act->qhd_obj.qhd_qep.ahd_part_def) { /* Open against "get" action. The RUP action dmtix and ** flags are the same as the cursor's, thanks to OPC. */ status = qeq_part_open(qef_rcb, assoc_dsh, NULL, 0, odmr_cb_ix, act->qhd_obj.qhd_qep.ahd_dmtix, oldpartno); if (status != E_DB_OK) { dsh->dsh_error.err_code = assoc_dsh->dsh_error.err_code; return(status); } pdmr_cb = (DMR_CB *)assoc_cbs[odmr_cb_ix + oldpartno+1]; STRUCT_ASSIGN_MACRO(dmr_cb->dmr_data, pdmr_cb->dmr_data); dmr_cb = pdmr_cb; } dmr_cb->dmr_tid = oldbigtid.tid_i4.tid; dmr_cb->dmr_flags_mask = DMR_BY_TID; /* get the tuple to be updated. */ save_addr = dmr_cb->dmr_data.data_address; dmr_cb->dmr_data.data_address = output; status = dmf_call(DMR_GET, dmr_cb); dmr_cb->dmr_data.data_address = save_addr; if (status != E_DB_OK) { dsh->dsh_error.err_code = dmr_cb->error.err_code; return (status); } } /* If we have rules, save a copy of the row before updating */ if (act->qhd_obj.qhd_qep.ahd_after_act != NULL || act->qhd_obj.qhd_qep.ahd_before_act != NULL) { MEcopy(output, act->qhd_obj.qhd_qep.ahd_repsize, dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_row]); oldbigtid.tid_i4.tpf = 0; oldbigtid.tid_i4.tid = dmr_cb->dmr_tid; oldbigtid.tid.tid_partno = oldpartno; } /* process the update expression */ qen_adf = act->qhd_obj.qhd_qep.ahd_current; ade_excb = (ADE_EXCB*) dsh->dsh_cbs[qen_adf->qen_pos]; if (dsh->dsh_qp_ptr->qp_status & QEQP_GLOBAL_BASEARRAY) dsh->dsh_row[qen_adf->qen_uoutput] = output; else ade_excb->excb_bases[ADE_ZBASE+qen_adf->qen_uoutput] = output; status = qen_execute_cx(dsh, ade_excb); if (status != E_DB_OK) break; /* Check for partitioning and see if we changed target partition. */ if (act->qhd_obj.qhd_qep.ahd_part_def && (act->qhd_obj.qhd_qep.ahd_qepflag & AHD_PCOLS_UPDATE)) { status = adt_whichpart_no(adfcb, act->qhd_obj.qhd_qep.ahd_part_def, output, &newpartno); if (status != E_DB_OK) return(status); } /* Process BEFORE triggers (if any). */ if (act->qhd_obj.qhd_qep.ahd_before_act != NULL) { /* ** Place the TID in a known location so it can be used ** as a parameter to the procedure fired by the rule. */ newbigtid.tid_i4.tpf = 0; newbigtid.tid_i4.tid = dmr_cb->dmr_tid; newbigtid.tid.tid_partno = newpartno; MEcopy ((PTR)&newbigtid, sizeof(DB_TID8), dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_tid]); MEcopy ((PTR)&oldbigtid, sizeof(DB_TID8), dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_tid]); MEcopy(output, act->qhd_obj.qhd_qep.ahd_repsize, dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_row]); dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_ptr = act; dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_status = DSH_CT_CONTINUE3; dsh->dsh_depth_act++; dsh->dsh_act_ptr = act->qhd_obj.qhd_qep.ahd_before_act; dsh->dsh_error.err_code = E_QE0120_RULE_ACTION_LIST; status = E_DB_ERROR; break; } } /* end of !DSH_CT_CONTINUE3 */ state = DSH_CT_INITIAL; /* signal resumption after ** BEFORE trigger */ if (act->qhd_obj.qhd_qep.ahd_qepflag & AHD_PCOLS_UPDATE && oldpartno != newpartno) { /* Partition has changed for row in partitioned table. ** Delete from 1st partition and insert into next. ** We have to hope that DMF can keep it all straight. */ status = dmf_call(DMR_DELETE, dmr_cb); if (status != E_DB_OK) { if (dmr_cb->error.err_code == E_DM0055_NONEXT) dsh->dsh_error.err_code = 4599; else dsh->dsh_error.err_code = dmr_cb->error.err_code; break; } /* Get output partition DMR_CB, then do DMR_PUT. ** Don't change the fetching DSH's current dmr-cb in case ** we're running a true in-place cursor. */ status = qeq_part_open(qef_rcb, assoc_dsh, NULL, 0, odmr_cb_ix, act->qhd_obj.qhd_qep.ahd_dmtix, newpartno); if (status != E_DB_OK) { dsh->dsh_error.err_code = assoc_dsh->dsh_error.err_code; return(status); } dmr_cb = (DMR_CB *)assoc_cbs[odmr_cb_ix + newpartno+1]; dsh->dsh_qef_targcount = 1; /* Final preparation of new partition DMR_CB. */ dmr_cb->dmr_flags_mask = 0; dmr_cb->dmr_val_logkey = 0; dmr_cb->dmr_data.data_address = output; dmr_cb->dmr_data.data_in_size = act->qhd_obj.qhd_qep.ahd_repsize; if (act->qhd_obj.qhd_qep.ahd_duphandle != QEF_SKIP_DUP) dmr_cb->dmr_flags_mask |= DMR_DUP_ROLLBACK; status = dmf_call(DMR_PUT, dmr_cb); } else { dsh->dsh_qef_targcount = 1; if ((act->qhd_obj.qhd_qep.ahd_upd_colmap) && (act->qhd_obj.qhd_qep.ahd_before_act == NULL)) dmr_cb->dmr_attset = (char *)act->qhd_obj.qhd_qep.ahd_upd_colmap; else dmr_cb->dmr_attset = (char *)0; if (act->qhd_obj.qhd_qep.ahd_duphandle != QEF_SKIP_DUP) dmr_cb->dmr_flags_mask |= DMR_DUP_ROLLBACK; status = dmf_call(DMR_REPLACE, dmr_cb); } if (status == E_DB_OK || ((dmr_cb->error.err_code == E_DM0046_DUPLICATE_RECORD || dmr_cb->error.err_code == E_DM0045_DUPLICATE_KEY || dmr_cb->error.err_code == E_DM0048_SIDUPLICATE_KEY) && act->qhd_obj.qhd_qep.ahd_duphandle == QEF_SKIP_DUP)) { if (status == E_DB_OK) { dsh->dsh_qef_rowcount = 1; /* Look for rules to apply */ if (act->qhd_obj.qhd_qep.ahd_after_act != NULL) { /* ** Place the TID in a known location so it can be used ** as a parameter to the procedure fired by the rule. */ newbigtid.tid_i4.tpf = 0; newbigtid.tid_i4.tid = dmr_cb->dmr_tid; newbigtid.tid.tid_partno = newpartno; MEcopy ((PTR)&newbigtid, sizeof(DB_TID8), dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_tid]); MEcopy ((PTR)&oldbigtid, sizeof(DB_TID8), dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_tid]); MEcopy(output, act->qhd_obj.qhd_qep.ahd_repsize, dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_row]); dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_ptr = act; dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_status = DSH_CT_CONTINUE; dsh->dsh_depth_act++; dsh->dsh_act_ptr = act->qhd_obj.qhd_qep.ahd_after_act; dsh->dsh_error.err_code = E_QE0120_RULE_ACTION_LIST; status = E_DB_ERROR; break; } } else { dsh->dsh_qef_rowcount = 0; status = E_DB_OK; } break; } if (dmr_cb->error.err_code == E_DM0055_NONEXT) dsh->dsh_error.err_code = 4599; else if ( dmr_cb->error.err_code == E_DM0029_ROW_UPDATE_CONFLICT ) { dsh->dsh_qp_status |= DSH_QP_OBSOLETE; dsh->dsh_error.err_code = E_QE0023_INVALID_QUERY; status = E_DB_WARN; } else dsh->dsh_error.err_code = dmr_cb->error.err_code; break; } return (status); }
/*{ ** Name: qeu_cevent - Store event information for one event. ** ** External QEF call: status = qef_call(QEU_CEVENT, &qeuq_cb); ** ** Description: ** Add the event tuple and the event query text to the appropriate ** tables (iievent and iiqrytext). ** ** Most of the event tuple was filled by the parser from the CREATE EVENT ** statement, except that since this is the first access to iievent, ** the uniqueness of the event name (within the current user scope) is ** validated here. First, all events that have the same name and ** owner are fetched (the iievent table is hashed on name and owner ** so this is a singleton keyed retrieval). If there are any then ** the event is a duplicate and an error is returned. If this is ** unique then the event is entered into iievent. ** ** To allow permissions to apply to events, an event tuple includes ** a "dummy table id" (much like database procedures). This id is ** retrieved from DMU_GET_TABID. ** ** An internal qrytext id (time-stamp) is created and all the qrytext ** tuples associated with the event are entered into iiqrytext. ** Note that the size of CREATE EVENT query text is never likely to ** be more than one iiqrytext tuple, but the code allows more than ** one tuple in case a WITH clause is added in the future (extending ** the length of the statement). ** ** The current "create date" is retrieved from ADF (using date("now")). ** ** Inputs: ** qef_cb QEF session control block ** qeuq_cb ** .qeuq_eflag Designate error handling for user errors. ** QEF_INTERNAL Return error code. ** QEF_EXTERNAL Send message to user. ** .qeuq_cq Number of query text tuples. ** .qeuq_qry_tup Query text tuples. ** .qeuq_culd Number of event tuples. Must be 1. ** .qeuq_uld_tup Event tuple: ** .dbe_name Event name. ** .dbe_owner Event owner. ** .dbe_type Event type. ** The remaining fields are filled here. ** .qeuq_db_id Database id. ** .qeuq_d_id DMF session id. ** ** Outputs: ** qeuq_cb ** .error.err_code E_QE0002_INTERNAL_ERROR ** E_QE0017_BAD_CB ** E_QE0018_BAD_PARAM_IN_CB ** E_QE0022_ABORTED ** E_QE020A_EVENT_EXISTS (ret E_QE0025_USER_ERROR) ** Returns: ** E_DB_{OK, WARN, ERROR, FATAL} ** Exceptions: ** none ** ** History: ** 28-aug-89 (neil) ** Written for Terminator II/alerters. ** 09-feb-90 (neil) ** Added auditing functionality. ** 03-mar-90 (neil) ** Clear adf_constants before calling ADF. The problem was that the ** session CB may have been pointing at "old" data which had been ** reused for other things. ** 19-may-93 (anitap) ** Added support to create implicit schema for dbevent. ** 07-jul-93 (anitap) ** Added two arguments qef_rcb & qeuq_cb to qea_schema() instead of ** PTR. ** Changed assignment of flag to IMPLICIT_SCHEMA. ** 21-sep-93 (stephenb) ** Replace generic I_SX2032_EVENT_ACCESS with I_SX2032_EVENT_CREATE. ** 27-oct-93 (andre) ** As a part of fix for bug 51852 (which was reported in 6.4 but can ** and will manifest itself in 6.5 as soon as someone places some ** stress on the DBMS), we want to use the dbevent id (really ** guaranteed to be unique) instead of timestamps (allegedly unique, ** but in fact may be non-unique if several objects get created in ** rapid succession on a reasonably fast box) to identify IIQRYTEXT ** tuples associated with a given dbevent. This id (pumped through ** randomizing function) will be used to key into IIQRYTEXT */ DB_STATUS qeu_cevent( QEF_CB *qef_cb, QEUQ_CB *qeuq_cb) { DB_IIEVENT *evtuple; /* New event tuple */ DB_IIEVENT evtuple_temp; /* Tuple and */ DMR_ATTR_ENTRY evkey_array[2]; /* keys for uniqueness check */ DMR_ATTR_ENTRY *evkey_ptr_array[2]; DMU_CB dmu_cb; /* For unique table-id request */ DB_DATA_VALUE evcreate_dv; /* For create date */ DB_IIQRYTEXT *qtuple; /* Event text */ DB_TAB_ID randomized_id; i4 i; /* Querytext counter */ QEF_DATA *next; /* and data pointer */ DB_STATUS status, local_status; DB_ERROR e_error; i4 error; bool tbl_opened = FALSE; QEU_CB tranqeu; /* May need a transaction */ bool transtarted = FALSE; QEU_CB qeu; QEF_DATA qef_data; i4 flag = IMPLICIT_SCHEMA; QEF_RCB *qef_rcb = (QEF_RCB *)NULL; for (;;) /* Dummy for loop for error breaks */ { /* Validate CB and parameters */ if (qeuq_cb->qeuq_type != QEUQCB_CB || qeuq_cb->qeuq_length != sizeof(QEUQ_CB)) { status = E_DB_ERROR; error = E_QE0017_BAD_CB; break; } if ( (qeuq_cb->qeuq_cq == 0 || qeuq_cb->qeuq_qry_tup == NULL) || (qeuq_cb->qeuq_culd != 1 || qeuq_cb->qeuq_uld_tup == NULL) || (qeuq_cb->qeuq_db_id == NULL) || (qeuq_cb->qeuq_d_id == 0)) { status = E_DB_ERROR; error = E_QE0018_BAD_PARAM_IN_CB; break; } /* ** Check to see if transaction is in progress, if so set a local ** transaction, otherwise we'll use the user's transaction. */ if (qef_cb->qef_stat == QEF_NOTRAN) { tranqeu.qeu_type = QEUCB_CB; tranqeu.qeu_length = sizeof(QEUCB_CB); tranqeu.qeu_db_id = qeuq_cb->qeuq_db_id; tranqeu.qeu_d_id = qeuq_cb->qeuq_d_id; tranqeu.qeu_flag = 0; status = qeu_btran(qef_cb, &tranqeu); if (status != E_DB_OK) { error = tranqeu.error.err_code; break; } transtarted = TRUE; } /* Escalate the transaction to MST */ if (qef_cb->qef_auto == QEF_OFF) qef_cb->qef_stat = QEF_MSTRAN; evtuple = (DB_IIEVENT *)qeuq_cb->qeuq_uld_tup->dt_data; /* Validate that the event name/owner is unique */ qeu.qeu_type = QEUCB_CB; qeu.qeu_length = sizeof(QEUCB_CB); qeu.qeu_tab_id.db_tab_base = DM_B_EVENT_TAB_ID; qeu.qeu_tab_id.db_tab_index = DM_I_EVENT_TAB_ID; qeu.qeu_db_id = qeuq_cb->qeuq_db_id; qeu.qeu_lk_mode = DMT_IX; qeu.qeu_flag = DMT_U_DIRECT; qeu.qeu_access_mode = DMT_A_WRITE; qeu.qeu_mask = 0; status = qeu_open(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened = TRUE; /* Retrieve the same named/owned event - if not there then ok */ qeu.qeu_count = 1; qeu.qeu_tup_length = sizeof(DB_IIEVENT); qeu.qeu_output = &qef_data; qef_data.dt_next = NULL; qef_data.dt_size = sizeof(DB_IIEVENT); qef_data.dt_data = (PTR)&evtuple_temp; qeu.qeu_getnext = QEU_REPO; qeu.qeu_klen = 2; /* Keyed on name and owner */ qeu.qeu_key = evkey_ptr_array; evkey_ptr_array[0] = &evkey_array[0]; evkey_ptr_array[0]->attr_number = DM_1_EVENT_KEY; evkey_ptr_array[0]->attr_operator = DMR_OP_EQ; evkey_ptr_array[0]->attr_value = (char *)&evtuple->dbe_name; evkey_ptr_array[1] = &evkey_array[1]; evkey_ptr_array[1]->attr_number = DM_2_EVENT_KEY; evkey_ptr_array[1]->attr_operator = DMR_OP_EQ; evkey_ptr_array[1]->attr_value = (char *)&evtuple->dbe_owner; qeu.qeu_qual = NULL; qeu.qeu_qarg = NULL; status = qeu_get(qef_cb, &qeu); if (status == E_DB_OK) /* Found the same event! */ { (VOID)qef_error(E_QE020A_EVENT_EXISTS, 0L, E_DB_ERROR, &error, &qeuq_cb->error, 1, qec_trimwhite(sizeof(evtuple->dbe_name), (char *)&evtuple->dbe_name), (PTR)&evtuple->dbe_name); error = E_QE0025_USER_ERROR; break; } if (qeu.error.err_code != E_QE0015_NO_MORE_ROWS) { error = qeu.error.err_code; /* Some other error */ break; } /* The event is unique - append it */ status = E_DB_OK; /* ** Get unique event id (a table id) from DMF. This id enables ** permissions to be associated with the event. */ dmu_cb.type = DMU_UTILITY_CB; dmu_cb.length = sizeof(DMU_CB); dmu_cb.dmu_flags_mask = 0; dmu_cb.dmu_tran_id = qef_cb->qef_dmt_id; dmu_cb.dmu_db_id = qeuq_cb->qeuq_db_id; status = dmf_call(DMU_GET_TABID, &dmu_cb); if (status != E_DB_OK) { error = dmu_cb.error.err_code; break; } evtuple->dbe_uniqueid.db_tab_base = dmu_cb.dmu_tbl_id.db_tab_base; evtuple->dbe_uniqueid.db_tab_index = dmu_cb.dmu_tbl_id.db_tab_index; /* ** use dbevent id to generate randomized id which will be used to ** identify IIQRYTEXT tuples associated with this dbevent */ randomized_id.db_tab_base = ulb_rev_bits(evtuple->dbe_uniqueid.db_tab_base); randomized_id.db_tab_index = ulb_rev_bits(evtuple->dbe_uniqueid.db_tab_index); /* set text id to "randomized" id */ evtuple->dbe_txtid.db_qry_high_time = randomized_id.db_tab_base; evtuple->dbe_txtid.db_qry_low_time = randomized_id.db_tab_index; /* Get the create date of the event */ evcreate_dv.db_datatype = DB_DTE_TYPE; evcreate_dv.db_prec = 0; evcreate_dv.db_length = sizeof(DB_DATE); evcreate_dv.db_data = (PTR)&evtuple->dbe_create; evcreate_dv.db_collID = -1; qef_cb->qef_adf_cb->adf_constants = NULL; status = adu_datenow(qef_cb->qef_adf_cb, &evcreate_dv); if (status != E_DB_OK) { error = qeu.error.err_code; break; } /* Insert single event tuple */ qeu.qeu_count = 1; qeu.qeu_tup_length = sizeof(DB_IIEVENT); qeu.qeu_input = qeuq_cb->qeuq_uld_tup; /* Which points at evtuple */ status = qeu_append(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } status = qeu_close(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened = FALSE; /* ** Update all query text tuples with query id - validate list. Even ** though we will probably have just one text tuple this is set up ** for syntactic extensions to the CREATE EVENT statement. */ next = qeuq_cb->qeuq_qry_tup; for (i = 0; i < qeuq_cb->qeuq_cq; i++) { qtuple = (DB_IIQRYTEXT *)next->dt_data; next = next->dt_next; qtuple->dbq_txtid.db_qry_high_time = randomized_id.db_tab_base; qtuple->dbq_txtid.db_qry_low_time = randomized_id.db_tab_index; if (i < (qeuq_cb->qeuq_cq -1) && next == NULL) { error = E_QE0018_BAD_PARAM_IN_CB; status = E_DB_ERROR; break; } } /* for all query text tuples */ if (status != E_DB_OK) break; /* Insert all query text tuples */ qeu.qeu_tab_id.db_tab_base = DM_B_QRYTEXT_TAB_ID; qeu.qeu_tab_id.db_tab_index = 0L; qeu.qeu_mask = 0; status = qeu_open(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened = TRUE; qeu.qeu_count = qeuq_cb->qeuq_cq; qeu.qeu_tup_length = sizeof(DB_IIQRYTEXT); qeu.qeu_input = qeuq_cb->qeuq_qry_tup; status = qeu_append(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } status = qeu_close(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened = FALSE; status = qea_schema(qef_rcb, qeuq_cb, qef_cb, (DB_SCHEMA_NAME *)&evtuple->dbe_owner, flag); if (status != E_DB_OK) { error = qeuq_cb->error.err_code; break; } if (transtarted) /* If we started a transaction */ { status = qeu_etran(qef_cb, &tranqeu); if (status != E_DB_OK) { error = tranqeu.error.err_code; break; } } /* Audit CREATE EVENT */ if ( Qef_s_cb->qef_state & QEF_S_C2SECURE ) { status = qeu_secaudit(FALSE, qef_cb->qef_ses_id, evtuple->dbe_name.db_ev_name, &evtuple->dbe_owner, DB_EVENT_MAXNAME, SXF_E_EVENT, I_SX2032_EVENT_CREATE, SXF_A_SUCCESS | SXF_A_CREATE, &e_error); if (status != E_DB_OK) break; } qeuq_cb->error.err_code = E_QE0000_OK; return (E_DB_OK); } /* End dummy for */ /* call qef_error to handle error messages */ (VOID) qef_error(error, 0L, status, &error, &qeuq_cb->error, 0); /* Close off all the tables. */ local_status = E_DB_OK; if (tbl_opened) /* If system table opened, close it */ { local_status = qeu_close(qef_cb, &qeu); if (local_status != E_DB_OK) { (VOID) qef_error(qeu.error.err_code, 0L, local_status, &error, &qeuq_cb->error, 0); if (local_status > status) status = local_status; } } if (transtarted) /* If we started a transaction */ { local_status = qeu_atran(qef_cb, &tranqeu); if (local_status != E_DB_OK) { (VOID) qef_error(tranqeu.error.err_code, 0L, local_status, &error, &qeuq_cb->error, 0); if (local_status > status) status = local_status; } } return (status); } /* qeu_cevent */
/*{ ** Name: openTempTable - Open a temp table used for set input ** 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: ** qef_rcb ** tempTableNumber index to dsh temptable array for temporary ** table to be created. ** ** Outputs: ** Returns: ** E_DB_{OK,WARN,ERROR,FATAL} (from table creation) ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 18-jul-96 (inkdo01) ** Created. ** 29-oct-1998 (somsa01) ** If we are opening a Global Temporary Table, turn on the ** DMT_SESSION_TEMP flag in dmt_flags_mask before the open. ** (Bug #94059) ** 12-nov-1998 (somsa01) ** Added another parameter, and refined the check for a Global ** Session Temporary Table. (Bug #94059) ** 15-mar-04 (inkdo01) ** dsh_tempTables is now an array of ptrs. ** 13-Jul-2004 (schka24) ** Pass in dsh so we get the right one for sure. ** 30-Jul-2004 (jenjo02) ** Use dsh_dmt_id rather than qef_dmt_id transaction context. ** 4-Jun-2009 (kschendel) b122118 ** Use open-and-link utility. */ static DB_STATUS openTempTable( QEF_RCB *rcb, QEE_DSH *dsh, i4 tempTableNumber, bool gttparm ) { QEE_TEMP_TABLE *tempTable = dsh->dsh_tempTables[ tempTableNumber ]; DMT_CB *dmt = tempTable->tt_dmtcb; DMR_CB *dmr = tempTable->tt_dmrcb; DM_MDATA dm_mdata; DB_STATUS status = E_DB_OK; for (;;) /* something to break out of */ { /* create the table if it doesn't already exist */ if ( !( tempTable->tt_statusFlags & TT_CREATED ) ) { dmt->dmt_db_id = rcb->qef_db_id; dmt->dmt_tran_id = dsh->dsh_dmt_id; MEmove(8, (PTR) "$default", (char) ' ', sizeof(DB_LOC_NAME), (PTR) dmt->dmt_location.data_address); dmt->dmt_location.data_in_size = sizeof(DB_LOC_NAME); dmt->dmt_flags_mask = DMT_DBMS_REQUEST; if (gttparm) dmt->dmt_flags_mask |= DMT_SESSION_TEMP; dmr->dmr_flags_mask = 0; /* ** We assume that the sort key descriptor was set up ** earlier, probably at QEE time. */ if ( tempTable->tt_statusFlags & TT_PLEASE_SORT ) dmt->dmt_flags_mask |= DMT_LOAD; if ( tempTable->tt_statusFlags & TT_NO_DUPLICATES ) dmr->dmr_flags_mask |= DMR_NODUPLICATES; dmr->dmr_count = 1; dmr->dmr_s_estimated_records = TT_TUPLE_COUNT_GUESS; dmr->dmr_tid = 0; dm_mdata.data_address = dsh->dsh_row[ tempTable->tt_tuple ]; dm_mdata.data_size = dsh->dsh_qp_ptr->qp_row_len[ tempTable->tt_tuple ]; dmr->dmr_mdata = &dm_mdata; status = dmf_call(DMT_CREATE_TEMP, dmt); if (status != E_DB_OK) { if (dmt->error.err_code == E_DM0078_TABLE_EXISTS) { dsh->dsh_error.err_code = E_QE0050_TEMP_TABLE_EXISTS; status = E_DB_ERROR; } else { dsh->dsh_error.err_code = dmt->error.err_code; } break; } /* Open the temp table */ dmt->dmt_flags_mask = 0; if (gttparm) dmt->dmt_flags_mask |= DMT_SESSION_TEMP; dmt->dmt_sequence = dsh->dsh_stmt_no; dmt->dmt_access_mode = DMT_A_WRITE; dmt->dmt_lock_mode = DMT_X; dmt->dmt_update_mode = DMT_U_DIRECT; status = qen_openAndLink(dmt, dsh); if (status != E_DB_OK) { break; } tempTable->tt_statusFlags |= TT_CREATED; dmr->dmr_access_id = dmt->dmt_record_access_id; } /* end of table creation */ break; } /* end of code block */ 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); }
static DB_STATUS qen_ts_reset(QEE_DSH *dsh, QEN_NODE *node, QEN_STATUS *qen_status) { PTR *cbs = dsh->dsh_cbs; DMT_CB *dmt = (DMT_CB *)cbs[node->node_qen.qen_tsort.tsort_create]; DMR_CB *dmr_load = (DMR_CB*)cbs[node->node_qen.qen_tsort.tsort_load]; DB_STATUS status; QEN_SHD *shd = dsh->dsh_shd[node->node_qen.qen_tsort.tsort_shd]; /* Dump old data in the sort file: ** For QEF in-memory sort, Close the sort buffer memory stream */ if (qen_status->node_u.node_sort.node_sort_status == QEN0_QEF_SORT) { status = qen_u33_resetSortFile( shd, dsh ); if (status != E_DB_OK) return (status); qen_status->node_status = QEN0_INITIAL; } else { /* For DMF sort, call DMF to dump data in the sorter. */ if (dmt->dmt_record_access_id == (PTR)NULL) { /* ** A commit has closed the sort hold file. It should ** be initialised. */ qen_status->node_status = QEN0_INITIAL; } else { /* Pitch out contents of sort temp */ dmr_load->dmr_flags_mask = 0; status = dmf_call(DMR_DUMP_DATA, dmr_load); if (status != E_DB_OK) { dsh->dsh_error.err_code = dmr_load->error.err_code; return (status); } dmr_load->dmr_flags_mask = (node->node_qen.qen_tsort.tsort_dups | DMR_SORT_NOCOPY); dmr_load->dmr_count = 1; /* reset for subsequent loads */ /* Close the table and remove it from the ** dsh_open_dmtcbs list. */ dmt->dmt_flags_mask = 0; status = qen_closeAndUnlink(dmt, dsh); if (status != E_DB_OK) { dsh->dsh_error.err_code = dmt->error.err_code; return(status); } status = dmf_call(DMT_DELETE_TEMP, dmt); if (status) { dsh->dsh_error.err_code = dmt->error.err_code; return(status); } /* Having ended the dmse_sort the existing code ** for starting a new one on a reset assumes we ** would be in a QEF sort that ran out of memory. ** Switch back to an inital state with QEF sort. ** some of the following sorts actually run to ** completion under QEF sort anyway. */ qen_status->node_status = QEN0_INITIAL; qen_status->node_u.node_sort.node_sort_status = QEN0_QEF_SORT; } } /* make sure end-of-partition flag is off (it should be...) */ qen_status->node_status_flags &= QEN2_OPART_END; return (E_DB_OK); } /* qen_ts_reset */
static DB_STATUS qen_ts_dump( QEN_SHD *shd, QEE_DSH *dsh, QEN_NODE *node, i4 rowno, bool heap_sort, bool no_qef ) { PTR *cbs = dsh->dsh_cbs; DMT_CB *dmt = (DMT_CB *)cbs[node->node_qen.qen_tsort.tsort_create]; 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]; DMT_CHAR_ENTRY char_array[2]; DB_STATUS status; for (;;) /* to break off in case of error */ { /* Initialize the DMT_CB for the sorter table */ dmt->dmt_flags_mask = DMT_LOAD | DMT_DBMS_REQUEST; dmt->dmt_db_id = dsh->dsh_qefcb->qef_rcb->qef_db_id; dmt->dmt_tran_id = dsh->dsh_dmt_id; MEmove(8, (PTR) "$default", (char) ' ', sizeof(DB_LOC_NAME), (PTR) dmt->dmt_location.data_address); dmt->dmt_location.data_in_size = sizeof(DB_LOC_NAME); /* Initialize table attribute descriptors */ dmt->dmt_attr_array.ptr_address = (PTR) node->node_qen.qen_tsort.tsort_atts; dmt->dmt_attr_array.ptr_in_count = node->node_qen.qen_tsort.tsort_acount; dmt->dmt_attr_array.ptr_size = sizeof (DMF_ATTR_ENTRY); /* Initialize the the sort key descriptors */ dmt->dmt_key_array.ptr_address = (PTR) node->node_qen.qen_tsort.tsort_satts; dmt->dmt_key_array.ptr_in_count = node->node_qen.qen_tsort.tsort_scount; dmt->dmt_key_array.ptr_size = sizeof (DMT_KEY_ENTRY); /* Pass the page size */ char_array[0].char_id = DMT_C_PAGE_SIZE; char_array[0].char_value = node->node_qen.qen_tsort.tsort_pagesize; char_array[1].char_id = DMT_C_DUPLICATES; char_array[1].char_value = DMT_C_ON; /* duplicate rows allowed */ dmt->dmt_char_array.data_address = (PTR) &char_array; dmt->dmt_char_array.data_in_size = 2 * sizeof(DMT_CHAR_ENTRY); /* Create the sorter table */ status = dmf_call(DMT_CREATE_TEMP, dmt); if (status != E_DB_OK) { if (dmt->error.err_code == E_DM0078_TABLE_EXISTS) { dsh->dsh_error.err_code = E_QE0050_TEMP_TABLE_EXISTS; status = E_DB_ERROR; } else { dsh->dsh_error.err_code = dmt->error.err_code; } break; } /* Open the sorter table */ dmt->dmt_flags_mask = 0; dmt->dmt_sequence = dsh->dsh_stmt_no; dmt->dmt_access_mode = DMT_A_WRITE; dmt->dmt_lock_mode = DMT_X; dmt->dmt_update_mode = DMT_U_DIRECT; dmt->dmt_char_array.data_address = 0; dmt->dmt_char_array.data_in_size = 0; status = qen_openAndLink(dmt, dsh); if (status != E_DB_OK) { break; } /* Initialize the DMR_CB for loading the sorter */ dmr_load->dmr_access_id = dmt->dmt_record_access_id; dmr_load->dmr_count = 1; dmr_load->dmr_flags_mask = (node->node_qen.qen_tsort.tsort_dups | DMR_SORT_NOCOPY); dmr_load->dmr_s_estimated_records = node->qen_est_tuples; dmr_load->dmr_tid = 0; /* Initialize the DMR_CB for reading the sorter */ dmr_get->dmr_access_id = dmt->dmt_record_access_id; dmr_get->dmr_data.data_address = dsh->dsh_row[rowno]; dmr_get->dmr_data.data_in_size = dsh->dsh_qp_ptr->qp_row_len[rowno]; dmr_get->dmr_tid = 0; if (no_qef) break; /* leave, if nothing there */ /* If we have tuples in the in-memory sort buffer, load them into ** DMF sorter table now and write current tuple. */ if (heap_sort) status = qes_dump(dsh, shd, dmr_load); else status = qes_dumploop(dsh, shd, dmr_load); break; } /* end of error-break loop */ return (status); }
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); }
/*{ ** Name: qeu_dsecalarm - Drop single or all alarm definition. ** ** External QEF call: status = qef_call(QEU_DSECALM, &qeuq_cb); ** ** Description: ** Drop the alarm tuple, the alarm text from the appropriate tables ** (iisecalarm, iiqrytext and update the table "relstat" field. An ** alarm can be dropped either by name (when the DROP SECURITY_ALARM ** statement is issued) or by object id (when its associated object ** is dropped). ** ** When originating from the DROP SECURITY_ALARM statement the single ** alarm tuple is deleted based on its name - provided in the ** qeuq_uld_tup parameter. In this case the single alarm is fetched ** (to collect the text, table id) and deleted. If it wasn't ** found then an error is returned. ** ** When originating from a DROP TABLE statement (this is similar to ** the DROP INTEGRITY ON table ALL), all tuples that satisfy the ** table-id are fetched (to collect their text ids) and dropped. ** If none are found no error is returned. ** ** For each alarm that is dropped the text tuples are ** also dropped based on the ids collected from the fetched alarm. ** ** The way this routine works is the following: ** ** set up QEU CB's for iisecalarm, iiqrytext and open tables; ** if (DROP SECURITY_ALARM) then ** set up iisecalarm "qualified" name and owner; ** else ** set up iisecalarm "keyed" on DROP object id; ** endif; ** for (all alarm tuples found) loop ** get alarm tuple; ** if (not found) then ** if (DROP SECURITY_ALARM) then ** error - alarm does not exist; ** break; ** else ** clear error; ** break; ** endif; ** endif; ** set up iiqrytext keys based on alarm text id; ** for (all text tuples found) loop ** get text tuple; ** delete text tuple; ** endloop; ** delete current alarm tuple; ** if (DROP SECURITY_ALARM) then ** endloop; ** endif; ** endloop; ** close tables; ** ** Inputs: ** qef_cb QEF session control block ** qeuq_cb ** .qeuq_eflag Designate error handling for user errors. ** QEF_INTERNAL Return error code. ** QEF_EXTERNAL Send message to user. ** .qeuq_rtbl Table id of alarm - if DROP TABLE. If DROP ** SECURITY_ALARM then this is ignored. ** .qeuq_cr Must be 1 if DROP SECURITY_ALARM, 0 ** if DROP TABLE. ** .qeuq_uld_tup Alarm tuple to be deleted - if DROP ** SECURITY_ALARM, otherwise this is ignored: ** .dba_alarmname alarm name *or* ** .dba_alarmno Alarm number ** .qeuq_db_id Database id. ** .qeuq_d_id DMF session id. ** from_drop_alarm TRUE if called from DROP SECURITY_ALARM ** ** Outputs: ** qeuq_cb ** .error.err_code E_QE0002_INTERNAL_ERROR ** E_QE0017_BAD_CB ** E_QE0018_BAD_PARAM_IN_CB ** E_QE0022_ABORTED ** Returns: ** E_DB_{OK, WARN, ERROR, FATAL} ** Exceptions: ** none ** ** History: ** 26-nov-93 (robf) ** Written for Secure 2.0 ** 30-dec-93 (robf) ** Don't write audit records if called implicitly during drop ** of a table. ** 16-feb-94 (robf) ** Check DROP ALL flag from qeuq_cb.qeuq_permit_mask & QEU_DROP_ALL, ** so we loop appropriately when there are several alarms on ** the object to be dropped. */ DB_STATUS qeu_dsecalarm( QEF_CB *qef_cb, QEUQ_CB *qeuq_cb, bool from_drop_alarm) { QEU_CB tranqeu; /* For transaction request */ bool transtarted = FALSE; QEU_CB aqeu; /* For iisecalarm table */ QEF_DATA aqef_data; DB_SECALARM *atuple_name; /* Input tuple with name or id */ DB_SECALARM atuple; /* Tuple currently being deleted */ bool alarm_opened = FALSE; DMR_ATTR_ENTRY akey_array[3]; DMR_ATTR_ENTRY *akey_ptr_array[3]; QEU_CB qqeu; /* For iiqrytext table */ QEU_QUAL_PARAMS qparams; DB_IIQRYTEXT qtuple; QEF_DATA qqef_data; bool qtext_opened = FALSE; DMR_ATTR_ENTRY qkey_array[2]; DMR_ATTR_ENTRY *qkey_ptr_array[2]; bool drop_specific_alarm; /* TRUE if dropping a specific ** alarm */ char obj_type; char *alarm_name; DB_STATUS status, local_status; i4 error; DB_ERROR e_error; SXF_ACCESS access; SXF_EVENT evtype; DB_OWN_NAME objowner; for (;;) /* Dummy for loop for error breaks */ { MEfill(sizeof(objowner),' ',(PTR)&objowner); /* Validate CB and parameters */ if (qeuq_cb->qeuq_type != QEUQCB_CB || qeuq_cb->qeuq_length != sizeof(QEUQ_CB)) { status = E_DB_ERROR; error = E_QE0017_BAD_CB; break; } if ( (qeuq_cb->qeuq_rtbl == NULL && qeuq_cb->qeuq_cr == 0) || (qeuq_cb->qeuq_db_id == NULL) || (qeuq_cb->qeuq_d_id == 0)) { status = E_DB_ERROR; error = E_QE0018_BAD_PARAM_IN_CB; break; } drop_specific_alarm = from_drop_alarm; /* ** If passed DROP ALL then not dropping specific alarm */ if(qeuq_cb->qeuq_permit_mask & QEU_DROP_ALL) drop_specific_alarm=FALSE; /* ** Check to see if transaction is in progress, if so set a local ** transaction, otherwise we'll use the user's transaction. */ if (qef_cb->qef_stat == QEF_NOTRAN) { tranqeu.qeu_type = QEUCB_CB; tranqeu.qeu_length = sizeof(QEUCB_CB); tranqeu.qeu_db_id = qeuq_cb->qeuq_db_id; tranqeu.qeu_d_id = qeuq_cb->qeuq_d_id; tranqeu.qeu_flag = 0; tranqeu.qeu_mask = 0; status = qeu_btran(qef_cb, &tranqeu); if (status != E_DB_OK) { error = tranqeu.error.err_code; break; } transtarted = TRUE; } /* Escalate the transaction to MST */ if (qef_cb->qef_auto == QEF_OFF) qef_cb->qef_stat = QEF_MSTRAN; /* Open iisecalarm, iiqrytext tables */ aqeu.qeu_type = QEUCB_CB; aqeu.qeu_length = sizeof(QEUCB_CB); aqeu.qeu_db_id = qeuq_cb->qeuq_db_id; aqeu.qeu_lk_mode = DMT_IX; aqeu.qeu_flag = DMT_U_DIRECT; aqeu.qeu_access_mode = DMT_A_WRITE; aqeu.qeu_mask = 0; STRUCT_ASSIGN_MACRO(aqeu, qqeu); /* Quick initialization */ /* Open iisecalarm */ aqeu.qeu_tab_id.db_tab_base = DM_B_IISECALARM_TAB_ID; aqeu.qeu_tab_id.db_tab_index = DM_I_IISECALARM_TAB_ID; status = qeu_open(qef_cb, &aqeu); if (status != E_DB_OK) { error = aqeu.error.err_code; break; } alarm_opened = TRUE; qqeu.qeu_tab_id.db_tab_base = DM_B_QRYTEXT_TAB_ID; /* Open iiqrytext */ qqeu.qeu_tab_id.db_tab_index = DM_I_QRYTEXT_TAB_ID; status = qeu_open(qef_cb, &qqeu); if (status != E_DB_OK) { error = qqeu.error.err_code; break; } qtext_opened = TRUE; aqeu.qeu_count = 1; /* Initialize alarm-specific qeu */ aqeu.qeu_tup_length = sizeof(DB_SECALARM); aqeu.qeu_output = &aqef_data; aqef_data.dt_next = NULL; aqef_data.dt_size = sizeof(DB_SECALARM); aqef_data.dt_data = (PTR)&atuple; qqeu.qeu_count = 1; /* Initialize qtext-specific qeu */ qqeu.qeu_tup_length = sizeof(DB_IIQRYTEXT); qqeu.qeu_output = &qqef_data; qqef_data.dt_next = NULL; qqef_data.dt_size = sizeof(DB_IIQRYTEXT); qqef_data.dt_data = (PTR)&qtuple; /* ** If DROP SECURITY_ALARM then position iisecalarm table based on ** alarm name or numbr ** and drop the specific alarm (if we can't find it issue an error). ** Positioning is done via qeu_qalarm_by_name/id. ** If DROP TABLE then fetch and drop ALL alarms applied to the table. */ aqeu.qeu_getnext = QEU_REPO; if (from_drop_alarm) { /* ** Might be scanning for database/installation alarms ** or special DROP ALL processing. */ atuple_name = (DB_SECALARM *)qeuq_cb->qeuq_uld_tup->dt_data; alarm_name=(char*)&atuple_name->dba_alarmname; /* ** alarmno -1 indicates all alarms when qualifying */ if(qeuq_cb->qeuq_permit_mask & QEU_DROP_ALL) atuple_name->dba_alarmno= -1; /* Get alarm that matches alarm name (qualified) */ qparams.qeu_qparms[0] = (PTR) atuple_name; aqeu.qeu_klen = 0; /* Not keyed */ aqeu.qeu_qual = qeu_qalarm_by_name; aqeu.qeu_qarg = &qparams; } else /* DROP TABLE */ { /* Get alarm that applies to specific table id (keyed) */ obj_type=DBOB_TABLE; alarm_name="unknown"; aqeu.qeu_klen = 3; aqeu.qeu_key = akey_ptr_array; akey_ptr_array[0] = &akey_array[0]; akey_ptr_array[1] = &akey_array[1]; akey_ptr_array[2] = &akey_array[2]; akey_ptr_array[0]->attr_number = DM_1_IISECALARM_KEY; akey_ptr_array[0]->attr_operator = DMR_OP_EQ; akey_ptr_array[0]->attr_value = (char*)&obj_type; akey_ptr_array[1]->attr_number = DM_2_IISECALARM_KEY; akey_ptr_array[1]->attr_operator = DMR_OP_EQ; akey_ptr_array[1]->attr_value = (char *)&qeuq_cb->qeuq_rtbl->db_tab_base; akey_ptr_array[2]->attr_number = DM_3_IISECALARM_KEY; akey_ptr_array[2]->attr_operator = DMR_OP_EQ; akey_ptr_array[2]->attr_value = (char *)&qeuq_cb->qeuq_rtbl->db_tab_index; aqeu.qeu_qual = NULL; aqeu.qeu_qarg = NULL; } for (;;) /* For all alarm tuples found */ { status = qeu_get(qef_cb, &aqeu); if (status != E_DB_OK) { if (aqeu.error.err_code == E_QE0015_NO_MORE_ROWS) { if (drop_specific_alarm) { (VOID)qef_error(E_US2473_9331_ALARM_ABSENT, 0L, E_DB_ERROR, &error, &qeuq_cb->error, 1, qec_trimwhite(sizeof(atuple_name->dba_alarmname), alarm_name), (PTR)alarm_name); error = E_QE0000_OK; status=E_DB_OK; } else /* No [more] alarms for table */ { error = E_QE0000_OK; status = E_DB_OK; } } else /* Other error */ { error = aqeu.error.err_code; } break; } /* If no alarms found */ aqeu.qeu_getnext = QEU_NOREPO; aqeu.qeu_klen = 0; status = E_DB_OK; /* Postion iiqrytxt table for query id associated with this alarm */ qkey_ptr_array[0] = &qkey_array[0]; qkey_ptr_array[1] = &qkey_array[1]; qqeu.qeu_getnext = QEU_REPO; qqeu.qeu_klen = 2; qqeu.qeu_key = qkey_ptr_array; qkey_ptr_array[0]->attr_number = DM_1_QRYTEXT_KEY; qkey_ptr_array[0]->attr_operator = DMR_OP_EQ; qkey_ptr_array[0]->attr_value = (char *)&atuple.dba_txtid.db_qry_high_time; qkey_ptr_array[1]->attr_number = DM_2_QRYTEXT_KEY; qkey_ptr_array[1]->attr_operator = DMR_OP_EQ; qkey_ptr_array[1]->attr_value = (char *)&atuple.dba_txtid.db_qry_low_time; qqeu.qeu_qual = NULL; qqeu.qeu_qarg = NULL; for (;;) /* For all query text tuples */ { status = qeu_get(qef_cb, &qqeu); if (status != E_DB_OK) { error = qqeu.error.err_code; break; } qqeu.qeu_klen = 0; qqeu.qeu_getnext = QEU_NOREPO; status = qeu_delete(qef_cb, &qqeu); if (status != E_DB_OK) { error = qqeu.error.err_code; break; } } /* For all query text tuples */ if (error != E_QE0015_NO_MORE_ROWS) break; if(atuple.dba_objtype==DBOB_TABLE) { DMT_CHAR_ENTRY char_spec; DMT_CB dmt_cb; /* ** Alter the table relstat to flag alarms. This ** validates that the table exists and ensures that we ** get an exclusive lock on it. */ char_spec.char_id = DMT_C_ALARM; char_spec.char_value = DMT_C_ON; MEfill(sizeof(DMT_CB), 0, (PTR) &dmt_cb); dmt_cb.dmt_flags_mask = 0; dmt_cb.dmt_db_id = qeuq_cb->qeuq_db_id; dmt_cb.dmt_char_array.data_in_size = sizeof(DMT_CHAR_ENTRY); dmt_cb.dmt_char_array.data_address = (PTR)&char_spec; dmt_cb.length = sizeof(DMT_CB); dmt_cb.type = DMT_TABLE_CB; dmt_cb.dmt_id.db_tab_base = atuple.dba_objid.db_tab_base; dmt_cb.dmt_id.db_tab_index = atuple.dba_objid.db_tab_index; dmt_cb.dmt_tran_id = qef_cb->qef_dmt_id; status = dmf_call(DMT_ALTER, &dmt_cb); if (status != E_DB_OK) { error = dmt_cb.error.err_code; if (error == E_DM0054_NONEXISTENT_TABLE) { error = E_QE0025_USER_ERROR; status = E_DB_OK; /* Still remove the alarm */ } else { /* ** Some other error */ break; } } } else if(!(atuple.dba_flags&DBA_ALL_DBS)) { /* ** Check access to the database, also get the security label ** for later use */ status=qeu_db_exists(qef_cb, qeuq_cb, (DB_DB_NAME *)&atuple.dba_objname, SXF_A_CONTROL, &objowner); if(status==E_DB_ERROR) { /* Error, no access to database */ break; } else if (status==E_DB_WARN) { /* Database not found */ status=E_DB_ERROR; /* E_US2474_9332_ALARM_NO_DB */ (VOID)qef_error(9332, 0L, E_DB_ERROR, &error, &qeuq_cb->error, 1, qec_trimwhite(sizeof(atuple.dba_objname), (char *)&atuple.dba_objname), (PTR)&atuple.dba_objname); break; } } /* Now delete the current alarm tuple */ status = qeu_delete(qef_cb, &aqeu); if (status != E_DB_OK) { error = aqeu.error.err_code; break; } /* ** If doing a specific DROP SECURITY_ALARM we're done with this ** loop. ** Otherwise continue with next alarm applied to table. */ if (drop_specific_alarm) break; } /* For all alarm found */ if (status != E_DB_OK) break; break; } /* End dummy for loop */ /* Handle any error messages */ if (status != E_DB_OK) (VOID) qef_error(error, 0L, status, &error, &qeuq_cb->error, 0); /* Close off all the tables and transaction */ if (alarm_opened) { local_status = qeu_close(qef_cb, &aqeu); if (local_status != E_DB_OK) { (VOID) qef_error(aqeu.error.err_code, 0L, local_status, &error, &qeuq_cb->error, 0); if (local_status > status) status = local_status; } } if (qtext_opened) { local_status = qeu_close(qef_cb, &qqeu); if (local_status != E_DB_OK) { (VOID) qef_error(qqeu.error.err_code, 0L, local_status, &error, &qeuq_cb->error, 0); if (local_status > status) status = local_status; } } if (transtarted) { if (status == E_DB_OK) local_status = qeu_etran(qef_cb, &tranqeu); else local_status = qeu_atran(qef_cb, &tranqeu); if (local_status != E_DB_OK) { (VOID) qef_error(tranqeu.error.err_code, 0L, local_status, &error, &qeuq_cb->error, 0); if (local_status > status) status = local_status; } } /* ** Dropping an alarm is a control operation on the base object ** (database/table). */ if( from_drop_alarm==TRUE && Qef_s_cb->qef_state & QEF_S_C2SECURE ) { if(atuple.dba_objtype==DBOB_DATABASE) { evtype=SXF_E_DATABASE; /* ** Database label/owner should be set in db_exists request above */ } else { evtype=SXF_E_TABLE; } if(status==E_DB_OK) access=(SXF_A_CONTROL|SXF_A_SUCCESS); else access=(SXF_A_CONTROL|SXF_A_FAIL); if(qeu_secaudit(FALSE, qef_cb->qef_ses_id, (char *)&atuple.dba_objname, &objowner, sizeof(atuple.dba_objname), evtype, I_SX202E_ALARM_DROP, access, &e_error)!=E_DB_OK) { error = e_error.err_code; status=E_DB_ERROR; } } if(status!=E_DB_OK) { (VOID) qef_error(E_QE028C_DROP_ALARM_ERR, 0L, local_status, &error, &qeuq_cb->error, 0); qeuq_cb->error.err_code= E_QE0025_USER_ERROR; } return (status); } /* qeu_dsecalarm */
DB_STATUS qeu_csecalarm( QEF_CB *qef_cb, QEUQ_CB *qeuq_cb) { DB_IIQRYTEXT *qtuple; /* Alarm text */ DB_SECALARM *atuple; /* New alarm tuple */ DB_SECALARM atuple_temp; /* Tuple to check for uniqueness */ DB_STATUS status, local_status; i4 error=0; bool transtarted = FALSE; bool tbl_opened = FALSE; i4 i; /* Querytext tuple counter */ QEF_DATA *next; /* and data pointer */ QEU_CB tranqeu; QEU_CB qeu; QEU_QUAL_PARAMS qparams; DB_QRY_ID qryid; /* Ids for query text */ QEF_DATA qef_data; bool loop=FALSE; QEF_RCB qef_rcb; i4 number; DMR_ATTR_ENTRY akey_array[3]; DMR_ATTR_ENTRY *akey_ptr_array[3]; DMT_CHAR_ENTRY char_spec; /* DMT_ALTER specification */ DMT_CB dmt_cb; DB_ERROR e_error; SXF_ACCESS access; SXF_EVENT evtype; DB_OWN_NAME objowner; do { MEfill(sizeof(objowner),' ',(PTR)&objowner); /* Validate CB and parameters */ if (qeuq_cb->qeuq_type != QEUQCB_CB || qeuq_cb->qeuq_length != sizeof(QEUQ_CB)) { status = E_DB_ERROR; error = E_QE0017_BAD_CB; break; } if ( qeuq_cb->qeuq_cq == 0 || qeuq_cb->qeuq_qry_tup == NULL || ( qeuq_cb->qeuq_uld_tup == NULL) || (qeuq_cb->qeuq_db_id == NULL) || (qeuq_cb->qeuq_d_id == 0)) { status = E_DB_ERROR; error = E_QE0018_BAD_PARAM_IN_CB; break; } qef_rcb.qef_cb = qef_cb; qef_rcb.qef_db_id = qeuq_cb->qeuq_db_id; qef_cb->qef_dbid = qeuq_cb->qeuq_db_id; /* ** Check to see if transaction is in progress, if so set a local ** transaction, otherwise we'll use the user's transaction. */ if (qef_cb->qef_stat == QEF_NOTRAN) { tranqeu.qeu_type = QEUCB_CB; tranqeu.qeu_length = sizeof(QEUCB_CB); tranqeu.qeu_db_id = qeuq_cb->qeuq_db_id; tranqeu.qeu_d_id = qeuq_cb->qeuq_d_id; tranqeu.qeu_flag = 0; tranqeu.qeu_mask = 0; status = qeu_btran(qef_cb, &tranqeu); if (status != E_DB_OK) { error = tranqeu.error.err_code; break; } transtarted = TRUE; } /* Escalate the transaction to MST */ if (qef_cb->qef_auto == QEF_OFF) qef_cb->qef_stat = QEF_MSTRAN; atuple = (DB_SECALARM *)qeuq_cb->qeuq_uld_tup->dt_data; /* For database alarms, make sure the database exists */ if(atuple->dba_objtype==DBOB_DATABASE && !(atuple->dba_flags&DBA_ALL_DBS)) { status=qeu_db_exists(qef_cb, qeuq_cb, (DB_DB_NAME *)&atuple->dba_objname, SXF_A_CONTROL, &objowner); if(status==E_DB_ERROR) { /* Error checking database name */ break; } else if (status==E_DB_WARN) { /* Database not found */ status=E_DB_ERROR; /* E_US2474_9332_ALARM_NO_DB */ (VOID)qef_error(9332, 0L, E_DB_ERROR, &error, &qeuq_cb->error, 1, qec_trimwhite(sizeof(atuple->dba_objname), (char *)&atuple->dba_objname), (PTR)&atuple->dba_objname); break; } } else if(atuple->dba_objtype==DBOB_TABLE) { /* ** Alter the table relstat to flag alarms exist. This validates that ** the table exists and ensures that we get an exclusive lock on it. */ char_spec.char_id = DMT_C_ALARM; /* create alarm code */ char_spec.char_value = DMT_C_ON; MEfill(sizeof(DMT_CB), 0, (PTR) &dmt_cb); dmt_cb.dmt_flags_mask = 0; dmt_cb.dmt_db_id = qeuq_cb->qeuq_db_id; dmt_cb.dmt_char_array.data_in_size = sizeof(DMT_CHAR_ENTRY); dmt_cb.dmt_char_array.data_address = (PTR)&char_spec; dmt_cb.length = sizeof(DMT_CB); dmt_cb.type = DMT_TABLE_CB; dmt_cb.dmt_id.db_tab_base = atuple->dba_objid.db_tab_base; dmt_cb.dmt_id.db_tab_index = atuple->dba_objid.db_tab_index; dmt_cb.dmt_tran_id = qef_cb->qef_dmt_id; status = dmf_call(DMT_ALTER, &dmt_cb); if (status != E_DB_OK) { error = dmt_cb.error.err_code; break; } } /* Get a unique query id */ TMnow((SYSTIME *)&qryid); atuple->dba_txtid.db_qry_high_time = qryid.db_qry_high_time; atuple->dba_txtid.db_qry_low_time = qryid.db_qry_low_time; /* Get a unique alarm id */ status = qea_reserveID(&atuple->dba_alarmid, qef_cb, &qef_rcb.error); if (status != E_DB_OK) { error = qef_rcb.error.err_code; break; } /* ** Generate an alarm name if needed, all blanks indicates no ** name specified. This is required for uniqueness check below. */ if(!STskipblank( (char*)&atuple->dba_alarmname, sizeof(atuple->dba_alarmname))) { status=qeu_gen_alarm_name( atuple->dba_objtype, (char*)&atuple->dba_objname, &qef_rcb, &atuple->dba_alarmid, (char*)&atuple->dba_alarmname, &error); if(status!=E_DB_OK) break; } /* Validate that the alarm name is unique */ qeu.qeu_type = QEUCB_CB; qeu.qeu_length = sizeof(QEUCB_CB); qeu.qeu_tab_id.db_tab_base = DM_B_IISECALARM_TAB_ID; qeu.qeu_tab_id.db_tab_index = DM_I_IISECALARM_TAB_ID; qeu.qeu_db_id = qeuq_cb->qeuq_db_id; qeu.qeu_lk_mode = DMT_IX; qeu.qeu_flag = DMT_U_DIRECT; qeu.qeu_access_mode = DMT_A_WRITE; qeu.qeu_mask = 0; status = qeu_open(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened = TRUE; atuple->dba_alarmno=0; /* Retrieve the same named alarm - if not there then ok */ qeu.qeu_count = 1; qeu.qeu_tup_length = sizeof(DB_SECALARM); qeu.qeu_output = &qef_data; qef_data.dt_next = NULL; qef_data.dt_size = sizeof(DB_SECALARM); qef_data.dt_data = (PTR)&atuple_temp; qeu.qeu_getnext = QEU_REPO; qeu.qeu_klen = 0; /* Not keyed */ qparams.qeu_qparms[0] = (PTR) atuple; /* What we're looking for */ qeu.qeu_qual = qeu_qalarm_by_name; qeu.qeu_qarg = &qparams; status = qeu_get(qef_cb, &qeu); if (status == E_DB_OK) /* Found the same alarm! */ { (VOID)qef_error(E_US2472_9330_ALARM_EXISTS, 0L, E_DB_ERROR, &error, &qeuq_cb->error, 1, qec_trimwhite(sizeof(atuple->dba_alarmname), (char *)&atuple->dba_alarmname), (PTR)&atuple->dba_alarmname); error = E_QE0025_USER_ERROR; break; } if (qeu.error.err_code != E_QE0015_NO_MORE_ROWS) { /* Some other error */ error = qeu.error.err_code; break; } status = qeu_close(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened=FALSE; /* ** Generate a unique alarm number. This is primarily for ** backwards compatibility with "anonymous" alarms which had ** to be dropped by number, not name. */ status = qeu_open(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened = TRUE; qeu.qeu_count = 1; qeu.qeu_tup_length = sizeof(DB_SECALARM); qeu.qeu_input = &qef_data; qeu.qeu_output = &qef_data; qef_data.dt_next = 0; qef_data.dt_size = sizeof(DB_SECALARM); qef_data.dt_data = (PTR) &atuple_temp; qeu.qeu_getnext = QEU_REPO; qeu.qeu_klen = 3; qeu.qeu_key = akey_ptr_array; akey_ptr_array[0] = &akey_array[0]; akey_ptr_array[1] = &akey_array[1]; akey_ptr_array[2] = &akey_array[2]; akey_ptr_array[0]->attr_number = DM_1_IISECALARM_KEY; akey_ptr_array[0]->attr_operator = DMR_OP_EQ; akey_ptr_array[0]->attr_value = (char*) &atuple->dba_objtype; akey_ptr_array[1]->attr_number = DM_2_IISECALARM_KEY; akey_ptr_array[1]->attr_operator = DMR_OP_EQ; akey_ptr_array[1]->attr_value = (char*) &atuple->dba_objid.db_tab_base; akey_ptr_array[2]->attr_number = DM_3_IISECALARM_KEY; akey_ptr_array[2]->attr_operator = DMR_OP_EQ; akey_ptr_array[2]->attr_value = (char*) &atuple->dba_objid.db_tab_index; qeu.qeu_qual = 0; qeu.qeu_qarg = 0; /* ** Get all alarm tuples for this object ** and determine the next alarm number. */ status = E_DB_OK; number = 0; while (status == E_DB_OK) { status = qeu_get(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } qeu.qeu_getnext = QEU_NOREPO; qeu.qeu_klen = 0; if (atuple_temp.dba_alarmno > number) number = atuple_temp.dba_alarmno; } if (error != E_QE0015_NO_MORE_ROWS) break; /* ** We have to add 1 to derive the next alarm number. */ atuple->dba_alarmno=number+1; /* Save the alarm tuple */ status = E_DB_OK; /* Insert single alarm tuple */ qeu.qeu_count = 1; qeu.qeu_tup_length = sizeof(DB_SECALARM); qeu.qeu_input = qeuq_cb->qeuq_uld_tup; status = qeu_append(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } status = qeu_close(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened = FALSE; /* Update all query text tuples with query id - validate list */ next = qeuq_cb->qeuq_qry_tup; for (i = 0; i < qeuq_cb->qeuq_cq; i++) { qtuple = (DB_IIQRYTEXT *)next->dt_data; next = next->dt_next; qtuple->dbq_txtid.db_qry_high_time = qryid.db_qry_high_time; qtuple->dbq_txtid.db_qry_low_time = qryid.db_qry_low_time; if (i < (qeuq_cb->qeuq_cq -1) && next == NULL) { error = E_QE0018_BAD_PARAM_IN_CB; status = E_DB_ERROR; break; } } /* for all query text tuples */ if (status != E_DB_OK) break; /* Insert all query text tuples */ qeu.qeu_tab_id.db_tab_base = DM_B_QRYTEXT_TAB_ID; qeu.qeu_tab_id.db_tab_index = 0L; status = qeu_open(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened = TRUE; qeu.qeu_count = qeuq_cb->qeuq_cq; qeu.qeu_tup_length = sizeof(DB_IIQRYTEXT); qeu.qeu_input = qeuq_cb->qeuq_qry_tup; status = qeu_append(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } status = qeu_close(qef_cb, &qeu); if (status != E_DB_OK) { error = qeu.error.err_code; break; } tbl_opened = FALSE; if (transtarted) /* If we started a transaction */ { status = qeu_etran(qef_cb, &tranqeu); if (status != E_DB_OK) { error = tranqeu.error.err_code; break; } } } while(loop); /* call qef_error to handle error messages */ if(error) (VOID) qef_error(error, 0L, status, &error, &qeuq_cb->error, 0); /* Close off all the tables. */ local_status = E_DB_OK; if (tbl_opened) /* If system table opened, close it */ { local_status = qeu_close(qef_cb, &qeu); if (local_status != E_DB_OK) { (VOID) qef_error(qeu.error.err_code, 0L, local_status, &error, &qeuq_cb->error, 0); if (local_status > status) status = local_status; } } if (transtarted) /* If we started a transaction */ { local_status = qeu_atran(qef_cb, &tranqeu); if (local_status != E_DB_OK) { (VOID) qef_error(tranqeu.error.err_code, 0L, local_status, &error, &qeuq_cb->error, 0); if (local_status > status) status = local_status; } } if ( Qef_s_cb->qef_state & QEF_S_C2SECURE ) { if(atuple->dba_objtype==DBOB_DATABASE) { evtype=SXF_E_DATABASE; } else { evtype=SXF_E_TABLE; } /* ** Creating an alarm is a control operation on the base object ** (database/table) */ if(status==E_DB_OK) access=(SXF_A_CONTROL|SXF_A_SUCCESS); else access=(SXF_A_CONTROL|SXF_A_FAIL); if(qeu_secaudit(FALSE, qef_cb->qef_ses_id, (char *)&atuple->dba_objname, &objowner, sizeof(atuple->dba_objname), evtype, I_SX202D_ALARM_CREATE, access, &e_error)!=E_DB_OK) { error = e_error.err_code; status=E_DB_ERROR; } } /* ** Log QEF create error */ if(status!=E_DB_OK) { (VOID) qef_error(E_QE028B_CREATE_ALARM_ERR, 0L, local_status, &error, &qeuq_cb->error, 0); qeuq_cb->error.err_code= E_QE0025_USER_ERROR; } return (status); } /* qeu_csecalarm */
/*{ ** Name: QEU_OPEN - open a table ** ** External QEF call: status = qef_call(QEU_OPEN, &qeu_cb); ** ** Description: ** A table is opened. A transaction must be in progress when ** this routine is called. This routine must be called before any ** of qeu_delete, qeu_append or qeu_get is called. ** Tables are opened without DMT_NOWAIT being set and are opened for ** direct update. ** ** Inputs: ** qeu_cb ** .qeu_flag zero or QEU_SHOW_STAT ** indicates if internal request for ** statistics. ** .qeu_eflag designate error handling semantis ** for user errors. ** QEF_INTERNAL return error code. ** QEF_EXTERNAL send message to user. ** .qeu_tab_id table id ** .qeu_db_id database id ** .qeu_lk_mode lock mode ** DMT_X exclusive table lock ** DMT_S shared table lock ** DMT_IX exclusive page lock ** DMT_IS shared table lock ** DMT_SIX shared table lock with ability ** to exclusive lock pages ** .qeu_access_mode access mode ** DMT_A_READ ** DMT_A_WRITE ** ** Outputs: ** qeu_cb ** .qeu_acc_id table access id ** .error.err_code One of the following ** E_QE0000_OK ** E_QE0002_INTERNAL_ERROR ** E_QE0004_NO_TRANSACTION ** E_QE0017_BAD_CB ** E_QE0018_BAD_PARAM_IN_CB ** E_QE0022_ABORTED ** <DMF error messages> ** Returns: ** E_DB_OK ** E_DB_ERROR caller error ** E_DB_FATAL internal error ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 27-may-86 (daved) ** written ** 18-jul-89 (jennifer) ** Added a flag to indicate that an internal request ** for statistical information is being requested. ** This solves a B1 security problem where statistics ** could be unpredicatable if B1 labels were checked. ** For an internal request they aren't checked, for a ** normal query on the iihistogram and iistatistics ** table they are checked. ** 23-jan-91 (seputis) ** added support for timeout and maxlocks ** 25-mar-99 (shust01) ** Initialized dmt_mustlock. On rare occasions storage happened ** to be equal to a 1 (TRUE), causing locks to be taken out even ** though readlock=nolock was set. ** 07-mar-2000 (gupsh01) ** Do not handle error E_DM006A_TRAN_ACCESS_CONFLICT here as it will ** be handled by the calling facility. (BUG 100777). ** 14-feb-03 (inkdo01) ** Special check for non-existant iisequence catalog, so message ** can be issued that database doesn't support sequences. ** */ DB_STATUS qeu_open( QEF_CB *qef_cb, QEU_CB *qeu_cb) { DMT_CB dmt_cb; DB_STATUS status; i4 err; DMT_CHAR_ENTRY lockmode[2]; i4 lockcount; MEfill(sizeof(DMT_CB), 0, (PTR) &dmt_cb); dmt_cb.type = DMT_TABLE_CB; dmt_cb.length = sizeof(DMT_CB); dmt_cb.dmt_db_id = qeu_cb->qeu_db_id; STRUCT_ASSIGN_MACRO(qeu_cb->qeu_tab_id, dmt_cb.dmt_id); dmt_cb.dmt_flags_mask = 0; if (qeu_cb->qeu_flag & QEU_SHOW_STAT) dmt_cb.dmt_flags_mask |= DMT_SHOW_STAT; if (qeu_cb->qeu_flag & QEU_BYPASS_PRIV) dmt_cb.dmt_flags_mask |= DMT_DBMS_REQUEST; dmt_cb.dmt_lock_mode = qeu_cb->qeu_lk_mode; dmt_cb.dmt_update_mode = DMT_U_DIRECT; dmt_cb.dmt_mustlock = FALSE; dmt_cb.dmt_access_mode = qeu_cb->qeu_access_mode; lockcount = 0; if (qeu_cb->qeu_mask & QEU_TIMEOUT) { lockmode[lockcount].char_id = DMT_C_TIMEOUT_LOCK; lockmode[lockcount].char_value = qeu_cb->qeu_timeout; lockcount++; } if (qeu_cb->qeu_mask & QEU_MAXLOCKS) { lockmode[lockcount].char_id = DMT_C_PG_LOCKS_MAX; lockmode[lockcount].char_value = qeu_cb->qeu_maxlocks; lockcount++; } if (lockcount > 0) { dmt_cb.dmt_char_array.data_address = (PTR)lockmode; dmt_cb.dmt_char_array.data_in_size = sizeof(lockmode[0]) * lockcount; dmt_cb.dmt_char_array.data_out_size = 0; } else dmt_cb.dmt_char_array.data_in_size = 0; dmt_cb.dmt_sequence = qef_cb->qef_stmt; /* QEU_OPEN is only valid in a transaction */ if (qef_cb->qef_stat == QEF_NOTRAN) { qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err, &qeu_cb->error, 0); return (E_DB_ERROR); } dmt_cb.dmt_tran_id = qef_cb->qef_dmt_id; status = dmf_call(DMT_OPEN, &dmt_cb); if (status == E_DB_OK) { qeu_cb->qeu_acc_id = dmt_cb.dmt_record_access_id; qef_cb->qef_open_count++; } else { /* ** Do not handle the dmf error E_DM006A_TRAN_ACCESS_CONFLICT here ** as it is being handled by the calling facility BUG: 100777 **/ if (dmt_cb.error.err_code == E_DM006A_TRAN_ACCESS_CONFLICT) { qeu_cb->error.err_code = dmt_cb.error.err_code; qeu_cb->error.err_data = dmt_cb.error.err_data; } else if (dmt_cb.error.err_code == E_DM0054_NONEXISTENT_TABLE && qeu_cb->qeu_tab_id.db_tab_base == DM_B_SEQ_TAB_ID) qef_error(E_QE00A1_IISEQ_NOTDEFINED, 0L, status, &err, &qeu_cb->error, 0); else qef_error(dmt_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0); } return (status); }
/*{ ** Name: QEU_GET - get tuples from an open table ** ** External QEF call: status = qef_call(QEU_GET, &qeu_cb); ** ** Description: ** Tuples are retrieved from an open table. ** ** Inputs: ** qeu_cb ** .qeu_eflag designate error handling semantis ** for user errors. ** QEF_INTERNAL return error code. ** QEF_EXTERNAL send message to user. ** .qeu_acc_id table access id ** .qeu_tup_length length of retrieved tuple ** .qeu_count number of tuples to retrieve ** .qeu_getnext reposition ** QEU_REPO repostion using key ** QEU_NOREPO continue from previous call to ** this routine ** .qeu_klen length of key - number of entries ** .qeu_key key for retrieve ** .qeu_qual qualification function ** .qeu_qarg argument to qualification function ** .qeu_flag operation qualifier ** QEU_BY_TID get tuple by TID - will only be ** considered if !QEU_REPO ** .qeu_tid contains TID of the tuple to be ** retrieved ** .qeu_output output buffer ** <qeu_key> is a pointer to an array of pointers of type DMR_ATTR_ENTRY ** .attr_number ** .attr_operation ** .attr_value_ptr ** ** Outputs: ** qeu_cb ** .qeu_count number of tuples retrieved ** .error.err_code One of the following ** E_QE0000_OK ** E_QE0002_INTERNAL_ERROR ** E_QE0004_NO_TRANSACTION ** E_QE0007_NO_CURSOR ** E_QE0017_BAD_CB ** E_QE0018_BAD_PARAM_IN_CB ** E_QE0015_NO_MORE_ROWS ** E_QE0022_ABORTED ** E_QE0015_NO_MORE_ROWS ** .qeu_output output buffer ** Returns: ** E_DB_OK ** E_DB_WARN ** E_DB_ERROR caller error ** E_DB_FATAL internal error ** Exceptions: ** none ** ** Side Effects: ** the output buffers are filled in ** ** History: ** 27-may-86 (daved) ** written ** 31-jul-86 (jennifer) ** Modified qeu_get to not allocate output ** from memory stream, but to assume output ** array is already initialized. ** 20-aug-86 (jennifer) ** When dmf returns nonext, then qef must ** return no-more-rows. ** 10-oct-87 (puree) ** Same as above even during positioning. ** 04-jan-90 (andre) ** return tid of the last tuple which was successfully read in ** QU_CB->qeu_tid ** 17-jun-92 (andre) ** add support for retrieval by TID - qeu_gentext should NOT be set to ** QEU_REPO ** 27-jul-96 (ramra01) ** Alter table project: Position only flag on qeu_get. ** 11-Apr-2008 (kschendel) ** Revised DMF qualification requirements, simplified for QEU. */ DB_STATUS qeu_get( QEF_CB *qef_cb, QEU_CB *qeu_cb) { i4 err; DMR_CB dmr_cb; i4 count; /* number of tuples returned */ i4 i; DB_STATUS status; PTR tuple; QEF_DATA *dataptr; count = qeu_cb->qeu_count; /* number of rows to get */ qeu_cb->qeu_count = 0; /* QEU_GET is only valid in a transaction */ if (qef_cb->qef_stat == QEF_NOTRAN) { qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err, &qeu_cb->error, 0); return (E_DB_ERROR); } dmr_cb.type = DMR_RECORD_CB; dmr_cb.length = sizeof(DMR_CB); dmr_cb.dmr_access_id = qeu_cb->qeu_acc_id; dmr_cb.dmr_tid = 0; /* not used */ dmr_cb.dmr_q_fcn = NULL; /* if positioning the cursor */ if (qeu_cb->qeu_getnext == QEU_REPO) { /* if there is a key, position by qual. Else, position all records */ if (qeu_cb->qeu_klen == 0) dmr_cb.dmr_position_type = DMR_ALL; else { /* set the keys */ dmr_cb.dmr_position_type = DMR_QUAL; dmr_cb.dmr_attr_desc.ptr_address = (PTR) qeu_cb->qeu_key; dmr_cb.dmr_attr_desc.ptr_in_count = qeu_cb->qeu_klen; dmr_cb.dmr_attr_desc.ptr_size = sizeof (DMR_ATTR_ENTRY); dmr_cb.dmr_s_estimated_records = -1; } /* row qualifier */ dmr_cb.dmr_q_fcn = (DB_STATUS (*)(void *,void *)) qeu_cb->qeu_qual; dmr_cb.dmr_q_arg = (PTR) qeu_cb->qeu_qarg; if (qeu_cb->qeu_qual != NULL) { dmr_cb.dmr_q_rowaddr = &qeu_cb->qeu_qarg->qeu_rowaddr; dmr_cb.dmr_q_retval = &qeu_cb->qeu_qarg->qeu_retval; } dmr_cb.dmr_flags_mask = 0; status = dmf_call(DMR_POSITION, &dmr_cb); if (status != E_DB_OK) { if (dmr_cb.error.err_code == E_DM0055_NONEXT) qeu_cb->error.err_code = E_QE0015_NO_MORE_ROWS; else { qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0); } return (status); } } if (qeu_cb->qeu_flag & QEU_POSITION_ONLY) return (E_DB_OK); /* We can now start getting records */ /* point to space for the first tuple */ /* the tuple length will not change. Tell DMF about it */ dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_tup_length; /* assign the beginning of the output chain */ dataptr = qeu_cb->qeu_output; tuple = dataptr->dt_data; i = 0; /* ** if qeu_getnexdt was not set to QEU_REPO and QEU_BY_TID was set in ** qeu_flag, tell dmr_get() to get a tuple with specified TID; otherwise ** tell it to get the next row */ if (qeu_cb->qeu_getnext != QEU_REPO && qeu_cb->qeu_flag & QEU_BY_TID) { dmr_cb.dmr_flags_mask = DMR_BY_TID; dmr_cb.dmr_tid = qeu_cb->qeu_tid; } else { dmr_cb.dmr_flags_mask = DMR_NEXT; } for (;;) { /* get the tuple */ dmr_cb.dmr_data.data_address = tuple; status = dmf_call(DMR_GET, &dmr_cb); if (status != E_DB_OK) { if (dmr_cb.error.err_code == E_DM0055_NONEXT) { qeu_cb->error.err_code = E_QE0015_NO_MORE_ROWS; break; } else { qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0); return (status); } } /* save TID of the last tuple read */ qeu_cb->qeu_tid = dmr_cb.dmr_tid; /* ** get space for next tuple - if retrieving by TID we never want to get ** more than one tuple */ if (++i < count && dmr_cb.dmr_flags_mask != DMR_BY_TID) { /* move to next entry in the output chain */ dataptr = dataptr->dt_next; tuple = dataptr->dt_data; } else break; } /* assign output value */ qeu_cb->qeu_count = i; return (status); }
/*{ ** Name: QEU_DELETE - delete tuples from a table ** ** External QEF call: status = qef_call(QEU_DELETE, &qeu_cb); ** ** Description: ** Tuples are deleted from a table opened with the QEU_OPEN ** command. If no qualification is given, the current tuple is ** deleted. ** ** Inputs: ** qeu_cb ** .qeu_eflag designate error handling semantis ** for user errors. ** QEF_INTERNAL return error code. ** QEF_EXTERNAL send message to user. ** .qeu_acc_id table access id ** .qeu_tup_length tuple length of the table ** Only required for keyed delete ** .qeu_qual qualification function ** .qeu_qarg argument to qualification function ** .qeu_klen length of key - number of entries ** .qeu_key key for delete ** <qeu_key> is a pointer to an array of pointers of type DMR_ATTR_ENTRY ** .attr_number ** .attr_operation ** .attr_value_ptr ** .qeu_flag operation qualifier ** QEU_BY_TID remove tuple whose TID is in qeu_tid ** .qeu_tid contains TID of the tuple to be ** removed if (qeu_flag & QEU_BY_TID) ** ** Outputs: ** qeu_cb ** .qeu_count number of tuples retrieved ** .error.err_code One of the following ** E_QE0000_OK ** E_QE0002_INTERNAL_ERROR ** E_QE0004_NO_TRANSACTION ** E_QE0007_NO_CURSOR ** E_QE0017_BAD_CB ** E_QE0018_BAD_PARAM_IN_CB ** Returns: ** E_DB_OK ** E_DB_ERROR caller error ** E_DB_FATAL internal error ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 27-may-86 (daved) ** written ** 02-sep-86 (jennifer) ** Modified qeu_delete to return a count of tuples ** deleted. ** 21-oct-86 (daved) ** did above fix for case where dmf returns no more rows. ** 22-dec-86 (daved) ** return OK if deleting keyed records ** 10-dec-87 (puree) ** Converted all ulm_palloc to qec_palloc ** 04-jan-91 (andre) ** added functionality to delete tuples by TID ** 18-jun-92 (andre) ** do not allocate memory unless we will actually be reading tuples, ** i.e. if a key is specified ** 06-mar-96 (nanpr01) ** removed the dependency on DB_MAXTUP for increased tuple size ** project. Also added the check to make sure tuple size is set ** whoever called this routine. Also tuple size consistency is ** checked iff qeu_klen > 0. ** 24-Jan-2001 (jenjo02) ** Ensure that memory stream is closed before returning. ** 11-Apr-2008 (kschendel) ** Revised DMF qualification requirements, simplified for QEU. */ DB_STATUS qeu_delete( QEF_CB *qef_cb, QEU_CB *qeu_cb) { i4 err; i4 count; DMR_CB dmr_cb; DB_STATUS status; GLOBALREF QEF_S_CB *Qef_s_cb; ULM_RCB ulm; /* so we don't need to allocate a tuple buffer ** as a stack variable, use dynamic memory */ count = 0; qeu_cb->qeu_count = 0; qeu_cb->error.err_code = E_QE0000_OK; /* QEU_DELETE is only valid in a transaction */ if (qef_cb->qef_stat == QEF_NOTRAN) { qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err, &qeu_cb->error, 0); return (E_DB_ERROR); } dmr_cb.type = DMR_RECORD_CB; dmr_cb.length = sizeof(DMR_CB); dmr_cb.dmr_access_id = qeu_cb->qeu_acc_id; dmr_cb.dmr_q_fcn = NULL; /* position the cursor */ /* if there is a key, position by qual. Else, position all records */ if (qeu_cb->qeu_klen) { if (qeu_cb->qeu_tup_length <= 0) { qef_error(E_QE0018_BAD_PARAM_IN_CB, 0L, E_DB_ERROR, &err, &qeu_cb->error, 0); return (E_DB_ERROR); } /* allocate memory for a tuple only if planning to call qeu_get() */ STRUCT_ASSIGN_MACRO(Qef_s_cb->qef_d_ulmcb, ulm); /* Open stream and allocate tuple memory in one action */ ulm.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC; ulm.ulm_psize = ulm.ulm_blocksize = qeu_cb->qeu_tup_length; if ((status = qec_mopen(&ulm)) != E_DB_OK) { qef_error(E_QE001E_NO_MEM, 0L, E_DB_ERROR, &err, &qeu_cb->error, 0); return (status); } /* set the keys */ dmr_cb.dmr_position_type = DMR_QUAL; dmr_cb.dmr_attr_desc.ptr_address = (PTR) qeu_cb->qeu_key; dmr_cb.dmr_attr_desc.ptr_in_count = qeu_cb->qeu_klen; dmr_cb.dmr_attr_desc.ptr_size = sizeof (DMR_ATTR_ENTRY); dmr_cb.dmr_s_estimated_records = -1; /* row qualifier */ dmr_cb.dmr_q_fcn = (DB_STATUS (*)(void *,void *)) qeu_cb->qeu_qual; dmr_cb.dmr_q_arg = (PTR) qeu_cb->qeu_qarg; if (qeu_cb->qeu_qual != NULL) { dmr_cb.dmr_q_rowaddr = &qeu_cb->qeu_qarg->qeu_rowaddr; dmr_cb.dmr_q_retval = &qeu_cb->qeu_qarg->qeu_retval; } dmr_cb.dmr_flags_mask = 0; status = dmf_call(DMR_POSITION, &dmr_cb); if (status != E_DB_OK) { ulm_closestream(&ulm); if (dmr_cb.error.err_code == E_DM0055_NONEXT) return (E_DB_OK); qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0); return (status); } /* the tuple length will not change. Tell DMF about it */ dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_tup_length; dmr_cb.dmr_data.data_address = ulm.ulm_pptr; } for (;;) { if (qeu_cb->qeu_klen) { /* get the tuple */ dmr_cb.dmr_flags_mask = DMR_NEXT; status = dmf_call(DMR_GET, &dmr_cb); if (status != E_DB_OK) { if (dmr_cb.error.err_code == E_DM0055_NONEXT) { status = E_DB_OK; break; } else { qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0); } break; } } /* ** delete the tuple: if deleting by TID, copy qeu_tid to dmr_tid and set ** dmr_flags_mask to DMR_BY_TID */ if (qeu_cb->qeu_flag & QEU_BY_TID) { dmr_cb.dmr_flags_mask = DMR_BY_TID; dmr_cb.dmr_tid = qeu_cb->qeu_tid; } /* otherwise delete the current tuple */ else { dmr_cb.dmr_flags_mask = DMR_CURRENT_POS; } status = dmf_call(DMR_DELETE, &dmr_cb); if (status != E_DB_OK) { qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0); break; } count++; if (qeu_cb->qeu_klen == 0) { /* we are only deleting current tuple */ break; } } if (qeu_cb->qeu_klen) { /* don't try to close a stream unless it was opened */ ulm_closestream(&ulm); } qeu_cb->qeu_count = count; return (status); }
/*{ ** Name: QEU_APPEND - append rows to table ** ** External QEF call: status = qef_call(QEU_APPEND, &qeu_cb); ** ** Description: ** This routine appends N tuples to an opened table. The table ** must have been opened with the QEU_OPEN command. This operation ** is valid only in an internal transaction (see QET.C). ** ** Inputs: ** qeu_cb ** .qeu_eflag designate error handling semantis ** for user errors. ** QEF_INTERNAL return error code. ** QEF_EXTERNAL send message to user. ** .qeu_acc_id table access id ** .qeu_count number of tuples to append ** .qeu_tup_length lenth of each tuple ** .qeu_input input buffer ** ** ** Outputs: ** qeu_cb ** .qeu_count Number of tuples appended ** .error.err_code One of the following ** E_QE0000_OK ** E_QE0002_INTERNAL_ERROR ** E_QE0004_NO_TRANSACTION ** E_QE0007_NO_CURSOR ** E_QE0017_BAD_CB ** E_QE0018_BAD_PARAM_IN_CB ** Returns: ** E_DB_OK ** E_DB_ERROR caller error ** E_DB_FATAL internal error ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 27-may-86 (daved) ** written ** 14-jul-93 (ed) ** replacing <dbms.h> by <gl.h> <sl.h> <iicommon.h> <dbdbms.h> ** 26-jul-93 (walt) ** Initialize the local variable "status" in qeu_append to E_DB_OK. ** If there are no rows to append it's possible to hit the closing ** return(status) statement without ever assigning status a ** non-garbage value. ** 01-feb-94 (stial01) ** BUG 66409: copy from is hanging if DM0151_SI_DUPLICATE_KEY_STMT, ** If this error occurs process it like the other duplicate errors. */ DB_STATUS qeu_append( QEF_CB *qef_cb, QEU_CB *qeu_cb) { i4 err; DMR_CB dmr_cb; i4 count; /* number of tuples to appended */ DB_STATUS status = E_DB_OK; QEF_DATA *dataptr; i4 i; i4 num_appended; /* number of tuples appended */ count = qeu_cb->qeu_count; qeu_cb->qeu_count = 0; /* QEU_APPEND is only valid in a transaction */ if (qef_cb->qef_stat == QEF_NOTRAN) { qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err, &qeu_cb->error, 0); return (E_DB_ERROR); } dmr_cb.type = DMR_RECORD_CB; dmr_cb.length = sizeof(DMR_CB); dmr_cb.dmr_flags_mask = 0; dmr_cb.dmr_access_id = qeu_cb->qeu_acc_id; dmr_cb.dmr_tid = 0; /* not used */ dataptr = qeu_cb->qeu_input; /* start appending rows */ num_appended = 0; for (i = 0; i < count; i++) { dmr_cb.dmr_data.data_address = dataptr->dt_data; dmr_cb.dmr_data.data_in_size = dataptr->dt_size; status = dmf_call(DMR_PUT, &dmr_cb); if (status != E_DB_OK) { /* *** FIXME *** This is insanely stupid -- dup rows/keys ** are just ignored. That was bad enough for COPY FROM, ** which no longer comes here, but it seems that a bunch of ** the QEU hurlers EXPECT a silent success on dup key/row. ** Someday, root that crap out, and allow this routine to ** treat errors in some rational manner... */ if (dmr_cb.error.err_code == E_DM0046_DUPLICATE_RECORD || dmr_cb.error.err_code == E_DM0045_DUPLICATE_KEY || dmr_cb.error.err_code == E_DM0048_SIDUPLICATE_KEY || dmr_cb.error.err_code == E_DM0150_DUPLICATE_KEY_STMT || dmr_cb.error.err_code == E_DM0151_SIDUPLICATE_KEY_STMT) { status = E_DB_OK; qeu_cb->error.err_code = dmr_cb.error.err_code; } else { qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0); return (status); } } else { /* successful append */ num_appended++; } /* next next record */ dataptr = dataptr->dt_next; } /* tell user how many rows were appended */ qeu_cb->qeu_count = num_appended; return (status); }
/*{ ** Name: QEU_REPLACE - replace tuple(s) in a table ** ** External QEF call: status = qef_call(QEU_REPLACE, &qeu_cb); ** ** Description: ** A tuple is replaced in a table opened with the QEU_OPEN ** command. ** If QEU_BY_TID is specified, ** the tuple with specified TID is repalced ** else if qeu_cb->kqeu_klen > 0 ** qeu_f_qual points to a function which will both determine whether the ** tuple should be updated and make appropriate changes to the tuple ** passed to it ** else ** replace the tuple which was read by position as specified by the caller ** ** Inputs: ** qeu_cb ** .qeu_eflag designate error handling semantis ** for user errors. ** QEF_INTERNAL return error code. ** QEF_EXTERNAL send message to user. ** .qeu_acc_id table access id ** .qeu_tup_length lenth of a tuple ** .qeu_input buffer containing new values for the ** tuple being replaced ** .qeu_qual qualification function for DMF ** .qeu_qarg argument to (*qeu_qual) () ** .qeu_klen length of key ** .qeu_key key for update ** <qeu_key> is a pointer to an array of pointers of type DMR_ATTR_ENTRY ** .attr_number ** .attr_operation ** .attr_value_ptr ** .qeu_flag operation qualifier ** QEU_BY_TID replace tuple whose TID is in ** qeu_tid ** .qeu_tid contains TID of the tuple to be ** replaced if (qeu_flag & QEU_BY_TID) ** .qeu_f_qual if !(qeu_klen > 0) this must point ** at a function which will decide ** whether and how the current tuple ** must be replaced ** .qeu_f_qarg argument to (*qeu_f_qual) () ** ** Outputs: ** qeu_cb ** .qeu_count number of tuples updated ** .error.err_code One of the following ** E_QE0000_OK ** E_QE0002_INTERNAL_ERROR ** E_QE0004_NO_TRANSACTION ** E_QE0007_NO_CURSOR ** E_QE0017_BAD_CB ** E_QE0018_BAD_PARAM_IN_CB ** Returns: ** E_DB_OK ** E_DB_ERROR caller error ** E_DB_FATAL internal error ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 18-jun-92 (andre) ** written ** 22-jun-92 (andre) ** changed the function to allow update one row by tid or to update ** multiple rows subject to qualification function ** 24-jun-92 (andre) ** another change to allow update of prepositioned tuple ** 13-sep-93 (robf) ** Extended to handle update multiple rows without ** requiring a key position. This is signalled when qeu_klen==0 ** and qeu_qual != NULL and qeu_f_qual!=NULL ** 30-nov-93 (robf) ** When updating multiple rows, keep going after first update. ** 24-Jan-2001 (jenjo02) ** Ensure that memory stream is closed before returning. ** 11-Apr-2008 (kschendel) ** Revised DMF qualification requirements, simplified for QEU. */ DB_STATUS qeu_replace( QEF_CB *qef_cb, QEU_CB *qeu_cb) { i4 err = 0L; DMR_CB dmr_cb; DB_STATUS status; GLOBALREF QEF_S_CB *Qef_s_cb; ULM_RCB ulm; i4 (*repl_func)(void *, void *); bool position_all=FALSE; bool mem_opened=FALSE; if (qeu_cb->qeu_flag & QEU_BY_TID) { /* ** if update_by_tid, no key(s), qualification function, or qualification ** function parameters should be passed; ** qeu_cb->qeu_input must point at a structure containing a ptr to the ** new value for the tuple of specified size */ if (qeu_cb->qeu_klen || qeu_cb->qeu_qual || qeu_cb->qeu_qarg || qeu_cb->qeu_f_qual || qeu_cb->qeu_f_qarg || !qeu_cb->qeu_input || !qeu_cb->qeu_input->dt_data || !qeu_cb->qeu_input->dt_size) { err = E_QE0018_BAD_PARAM_IN_CB; status = E_DB_ERROR; } } else if (qeu_cb->qeu_klen==0 && (repl_func = qeu_cb->qeu_f_qual) != NULL && qeu_cb->qeu_qual) { position_all=TRUE; /* ** Request to replace all qualifying in table, without key ** positioning */ if (!qeu_cb->qeu_qarg || !qeu_cb->qeu_f_qarg ) { err = E_QE0018_BAD_PARAM_IN_CB; status = E_DB_ERROR; } } else if (qeu_cb->qeu_klen == 0) { /* ** if asked to update the current tuple, no qualification function, or ** qualification function parameters should be passed; ** qeu_cb->qeu_input must point at a structure containing a ptr to ** the new value for the tuple of specified size */ if (qeu_cb->qeu_qual || qeu_cb->qeu_qarg || qeu_cb->qeu_f_qual || qeu_cb->qeu_f_qarg || !qeu_cb->qeu_input || !qeu_cb->qeu_input->dt_data || !qeu_cb->qeu_input->dt_size) { err = E_QE0018_BAD_PARAM_IN_CB; status = E_DB_ERROR; } } else if ((repl_func = qeu_cb->qeu_f_qual) == NULL) { /* ** if caller supplied a key, must specify the function which ** will determine whether and how the tuple must be updated */ err = E_QE0018_BAD_PARAM_IN_CB; status = E_DB_ERROR; } if (err) { (VOID) qef_error(err, 0L, status, &err, &qeu_cb->error, 0); return(status); } qeu_cb->qeu_count = 0; qeu_cb->error.err_code = E_QE0000_OK; /* QEU_REPLACE is only valid in a transaction */ if (qef_cb->qef_stat == QEF_NOTRAN) { qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err, &qeu_cb->error, 0); return (E_DB_ERROR); } dmr_cb.type = DMR_RECORD_CB; dmr_cb.length = sizeof(DMR_CB); dmr_cb.dmr_access_id = qeu_cb->qeu_acc_id; dmr_cb.dmr_q_fcn = NULL; /* if replacing by key, position the cursor */ if (qeu_cb->qeu_klen || position_all) { /* allocate memory for a tuple only if planning to call qeu_get() */ STRUCT_ASSIGN_MACRO(Qef_s_cb->qef_d_ulmcb, ulm); /* Open stream and allocate tuple memory in one action */ ulm.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC; ulm.ulm_psize = ulm.ulm_blocksize = qeu_cb->qeu_tup_length; if ((status = qec_mopen(&ulm)) != E_DB_OK) { qef_error(E_QE001E_NO_MEM, 0L, E_DB_ERROR, &err, &qeu_cb->error, 0); return (status); } mem_opened=TRUE; /* set the keys */ if(position_all) { dmr_cb.dmr_position_type = DMR_ALL; } else { dmr_cb.dmr_position_type = DMR_QUAL; dmr_cb.dmr_attr_desc.ptr_address = (PTR) qeu_cb->qeu_key; dmr_cb.dmr_attr_desc.ptr_in_count = qeu_cb->qeu_klen; dmr_cb.dmr_attr_desc.ptr_size = sizeof (DMR_ATTR_ENTRY); dmr_cb.dmr_s_estimated_records = -1; } /* row qualifier */ dmr_cb.dmr_q_fcn = (DB_STATUS (*)(void *,void *)) qeu_cb->qeu_qual; dmr_cb.dmr_q_arg = (PTR) qeu_cb->qeu_qarg; if (qeu_cb->qeu_qual != NULL) { dmr_cb.dmr_q_rowaddr = &qeu_cb->qeu_qarg->qeu_rowaddr; dmr_cb.dmr_q_retval = &qeu_cb->qeu_qarg->qeu_retval; } dmr_cb.dmr_flags_mask = 0; status = dmf_call(DMR_POSITION, &dmr_cb); if (status != E_DB_OK) { ulm_closestream(&ulm); if (dmr_cb.error.err_code == E_DM0055_NONEXT) return (E_DB_OK); qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0); return (status); } /* the tuple length will not change. Tell DMF about it */ dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_tup_length; dmr_cb.dmr_data.data_address = ulm.ulm_pptr; } else { /* ** make dmr_data point at the new value for the tuple */ dmr_cb.dmr_data.data_address = qeu_cb->qeu_input->dt_data; dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_input->dt_size; /* ** if (qeu_flag & QEU_BY_TID) ** indicate to dmr_replace() that we are replacing by tid ** else ** indicate to dmr_replace to replace the current tuple */ if (qeu_cb->qeu_flag & QEU_BY_TID) { dmr_cb.dmr_flags_mask = DMR_BY_TID; dmr_cb.dmr_tid = qeu_cb->qeu_tid; } else { dmr_cb.dmr_flags_mask = DMR_CURRENT_POS; } } for (;;) { if (qeu_cb->qeu_klen || position_all) { i4 ret_val; /* get the tuple */ dmr_cb.dmr_flags_mask = DMR_NEXT; status = dmf_call(DMR_GET, &dmr_cb); if (status != E_DB_OK) { if (dmr_cb.error.err_code == E_DM0055_NONEXT) { status = E_DB_OK; } else { err = dmr_cb.error.err_code; } break; } /* ** let caller's function determine whether and how the tuple must be ** changed; QEU_F_RETURN indicates that we must proceed; QEU_F_NEXT ** says "skip this tuple" */ ret_val = (*repl_func) (dmr_cb.dmr_data.data_address, qeu_cb->qeu_f_qarg); if (ret_val != QEU_F_RETURN) { continue; } /* will replace the current tuple */ dmr_cb.dmr_flags_mask = DMR_CURRENT_POS; } dmr_cb.dmr_attset = NULL; status = dmf_call(DMR_REPLACE, &dmr_cb); if (status != E_DB_OK) { err = dmr_cb.error.err_code; break; } else { qeu_cb->qeu_count++; } if (qeu_cb->qeu_klen == 0 && !position_all) { /* we were replacing a tuple by tid and are done */ break; } } if (status != E_DB_OK) { qef_error(err, 0L, status, &err, &qeu_cb->error, 0); } if (mem_opened) { /* don't try to close a stream unless it was opened */ ulm_closestream(&ulm); } return (status); }
/*{ ** Name: psq_bgn_session - Begin a parser session. ** ** INTERNAL PSF call format: status = psq_bgn_session(&psq_cb, &sess_cb); ** ** EXTERNAL call format: status = psq_call(PSQ_BGN_SESSION, &psq_cb, &sess_cb); ** ** Description: ** The psq_bgn_session function begins a parser session. It should be ** called each time a new user connects to a server. There may be ** many parser sessions per database server. There should be one parser ** session for each invocation of the database system that is connected ** to the server. When starting a parser session, one has to tell it ** what query language to use, and other session parameters. ** ** Inputs: ** psq_cb ** .psq_qlang The query language to use. ** .psq_decimal ** .psf_decspec TRUE indicates that the decimal marker ** has been specified. FALSE means use the ** default (a "."). ** .psf_decimal The character to use as a decimal marker ** (if specified). ** .psq_distrib Indicator for whether distributed ** statements and constructs should be ** accepted. ** .psq_sessid Session id ** .psq_server address of server control block ** .psq_adf_cb Pointer to session's ADF_CB ** .psq_dbid Database id for this session. ** .psq_user User name of ** .psq_dba User name of dba ** .psq_group Group id of session ** .psq_aplid Application id of session ** .psq_flag bitmask containing the following flags: ** .psq_catupd TRUE means catalogs updateable ** .psq_warnings Set to TRUE if user wishes to see ** warnings on unsupported commands ** .psq_idxstruct Structure for creating new indexes ** (e.g. DB_ISAM_STORE) ** .psq_udbid Unique database id for this session. ** .psq_ustat User status flags from SCS_ICS ** .psq_dbxlate Case translation semantics for the db ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psq_cb ** .psq_error Error information ** .err_code What error occurred ** E_PS0000_OK Success ** E_PS0001_INTERNAL_ERROR Internal PSF problem ** E_PS0201_BAD_QLANG Bad query language specifier ** E_PS0203_NO_DECIMAL No decimal marker specified ** E_PS0204_BAD_DISTRIB Bad distributed ** specification ** E_PS0205_SRV_NOT_INIT Server not initialized ** E_PS0206_TOO_MANY_SESS Too many sessions at one ** time ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s) ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_SEVERE Session is to be aborted ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Causes memory to be allocated. ** Increments the session count in the server control block. ** ** History: ** 01-oct-85 (jeff) ** written ** 28-jul-86 (jeff) ** Added initialization of pss_catupd and pss_idxstruct ** 26-aug-86 (seputis) ** Removed definition of yaccstream ** 13-apr-87 (puree) ** Initialize prototype list for dynamic SQL. ** 24-apr-87 (stec) ** init pss_project. ** 11-may-87 (stec) ** store psq_udbid to pss_dbid. ** 04-sep-87 (stec) ** Added critical region code where needed. ** 02-oct-87 (stec) ** Added pss_journaling initialization. ** 13-jun-88 (stec) ** Added initialization of pss_ruset for DB procs. ** 08-mar-89 (andre) ** Copy dba_drop_all from PSQ_CB to PSS_SESBLK. ** 15-mar-89 (ralph) ** GRANT Enhancements, Phase 1: ** Copy psq_aplid to pss_aplid; ** Copy psq_group to pss_group. ** 16-mar-89 (neil) ** Initialized rule field. ** 27-jul-89 (jrb) ** Copy numeric literals flag into session cb. ** 27-oct-89 (ralph) ** Copy user status flags to session control block. ** 11-oct-89 (ralph) ** Initialize pss_rgset and pss_raset. ** 28-dec-89 (andre) ** Copy fips_mode from PSQ_CB to PSS_SESBLK. ** 13-feb-90 (andre) ** set scf_stype to SCU_EXCLUSIVE before calling scu_swait. ** 12-sep-90 (sandyh) ** Added support for session memory value calculated from psf ** memory startup parameter. ** 15-nov-90 (andre) ** check the return status after calling SCF to acquire or to release a ** semaphore. ** If an error occurred when trying to acquire the semaphore, return ** E_DB_SEVERE to abort the session. ** If an error occurred when trying to release the semaphore, return ** E_DB_FATAL to bring down the server. ** 17-may-91 (andre) ** store DBA name into sess_cb->pss_dbaname and NULL-terminate. ** 08-nov-91 (rblumer) ** merged from 6.4: 25-jul-91 (andre) ** if (psq_cb->psq_flag & PSQ_STRIP_NL_IN_STRCONST), set bit ** PSS_STRIP_NL_IN_STRCONST in sess_cb->pss_ses_flag. this will ** indicate that we are connected to an older FE, so the scanners ** will continue to strip NLs inside quoted strings; ** this is required to fix bug 38098 ** 14-jan-92 (barbara) ** Included ddb.h for Star. Updated to check for distributed ** specification. ** 26-feb-92 (andre) ** if PSQ_REPAIR_SYSCAT is set in psq_cb->psq_flag, set ** PSS_REPAIR_SYSCAT in sess_cb->pss_ses_flags ** 30-mar-1992 (bryanp) ** Fill in pss_sess_owner with a session-unique owner name for use ** by temporary tables which are owned by this session. ** 02-jun-92 (andre) ** initialize pss_dependencies_stream to NULL to avloid use of illegal ** address throughout the parser. ** 24-nov-92 (ralph) ** CREATE SCHEMA: ** Initialize pss_prvgoval ** 22-dec-92 (rblumer) ** initialize pointer for statement-level rule list. ** 14-jan-93 (andre) ** remember whether we are running UPGRADEDB - this will enable us to ** decide whether IIDEVICES can be dropped - which is needed by ** UPGRADEDB ** 15-mar-93 (ralph) ** DELIM_IDENT: initialize pss_dbxlate to zero ** 08-apr-93 (andre) ** names of rule list headers in sess_cb have changed (and their ** number has doubled) ** 26-mar-93 (ralph) ** DELIM_IDENT: Must initialize pss_dbxlate from psq_cb.psq_dbxlate ** and pss_cat_owner from psq_cat_owner. ** 10-aug-93 (andre) ** fixed cause of a compiler warning ** 08-sep-93 (swm) ** Changed sizeof(DB_SESSID) to sizeof(CS_SID) to reflect recent CL ** interface revision. ** 20-sep-93 (rogerk) ** Changed default table create semantics to be WITH JOURNALING. ** Initialized the pss_ses_flag setting to include PSS_JOURNALING ** which mimics the user requesting "set journaling" to indicate that ** tables created should be journaled. ** 08-oct-93 (rblumer) ** increased values allowed in pss_trace vector, using PSS_TVALS. ** 18-oct-93 (rogerk) ** Added support for journal default override. Check psf server ** control block flag for PSF_NO_JNL_DEFAULT override before setting ** the session parse flag to assume journaling on table creates. ** 15-nov-93 (andre) ** add code to initialize a newly added sess_cb->pss_flattening_flags ** 01-nov-93 (anitap) ** if PSQ_INGRES_PRIV is set in psq_cb->psq_flag, set ** PSS_INGRES_PRIV in sess_cb->pss_ses_flags. ** 17-dec-93 (rblumer) ** "FIPS mode" no longer exists. It was replaced some time ago by ** several feature-specific flags (e.g. flatten_nosingleton and ** direct_cursor_mode). So I removed all FIPS_MODE flags. ** 02-jan-94 (andre) ** if starting a local session, call DMF to determine whether the ** database to which we are connected is being journaled and record ** that information by setting (or not setting) PSS_JOURNALED_DB bit ** in pss_ses_flags ** 7-jan-94 (swm) ** Bug #58635 ** Added PTR cast for pss_owner which has changed type to PTR. ** 17-mar-94 (robf) ** Add support for PSQ_SELECT_ALL flag ** 13-Feb-1995 (canor01) ** initialize the pss_audit field in the session control block ** 09-Oct-1998 (jenjo02) ** Removed SCF semaphore functions, inlining the CS calls instead. ** 23-mar-1999 (thaju02) ** Modified '$Sess' to use #define DB_SESS_TEMP_OWNER. (B94067) ** 01-Dec-2000 (hanal04) Bug 100680 INGSRV 1123 ** If PSQ_RULE_UPD_PREFETCH is set turn on PSS_RULE_UPD_PREFETCH ** in the session control block to signify that we should use ** the prefetch stategy required to ensure consitent behaviour in ** updating rules fired by updates. ** 10-Jan-2001 (jenjo02) ** Remove callback to SCF to get session id and ADF_CB; ** *ADF_CB now supplied by scsinit in PSQ_CB. ** 30-Jan-2004 (schka24) ** Get rid of a type-cast warning on adf cb. ** 3-Feb-2005 (schka24) ** Num-literals renamed to parser-compat, fix here. ** 15-june-06 (dougi) ** Add support for "before" triggers. ** 30-aug-06 (thaju02) ** If PSQ_RULE_DEL_PREFETCH is set turn on PSS_RULE_DEL_PREFETCH ** in the session control block, for prefetch strategy to ** be applied for deletes. (B116355) ** 26-Oct-2009 (kiria01) SIR 121883 ** Scalar sub-query support: Added copy of ** psq_flag.PSQ_NOCHK_SINGLETON_CARD to session flag ** for defaulting SET CARDINALITY_CHECK ** November 2009 (stephenb) ** Batch execution; initilization of new fields. ** 29-apr-2010 (stephenb) ** Init batch_copy_optim. ** 04-may-2010 (miket) SIR 122403 ** Init new sess_cb->pss_stmt_flags2. ** 19-May-2010 (kiria01) b123766 ** Get cardinality check default from server block not psq_cb ** 21-Jul-2010 (kschendel) SIR 124104 ** Initialize default compression from facility cb. ** 14-Oct-2010 (kschendel) SIR 124544 ** Initialize default result structure from facility cb. ** 19-Nov-2010 (kiria01) SIR 124690 ** Add support for setting installation wide collation defaults. */ DB_STATUS psq_bgn_session( register PSQ_CB *psq_cb, register PSS_SESBLK *sess_cb) { i4 err_code; i4 i; DB_STATUS status = E_DB_OK; STATUS sem_status; i4 sem_errno; bool leave_loop = TRUE; ULM_RCB ulm_rcb; /* ** No error to begin with. */ psq_cb->psq_error.err_code = E_PS0000_OK; /* ** Do as much validity checking as possible before allocating any memory. ** That way, there won't be any cleaning up to do for the majority of ** errors. */ /* ** Check for server initialized. This code could be placed within ** critical region, but this is not necessary, since this is a flag ** test. */ if (!Psf_srvblk->psf_srvinit) { (VOID) psf_error(E_PS0205_SRV_NOT_INIT, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* ** Check for valid language spec. */ if (psq_cb->psq_qlang != DB_QUEL && psq_cb->psq_qlang != DB_SQL) { (VOID) psf_error(E_PS0201_BAD_QLANG, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* ** Check whether language is allowed in this server. This will be useful ** when we have configurable servers, where some query languages can be ** used and some can't. This code could be placed within a critical region ** but it is not necessary, since this is a flag test only. */ if ((psq_cb->psq_qlang & Psf_srvblk->psf_lang_allowed) == 0) { (VOID) psf_error(E_PS0202_QLANG_NOT_ALLOWED, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* ** Make sure that the decimal character is actually specified. */ if (!psq_cb->psq_decimal.db_decspec) { (VOID) psf_error(E_PS0203_NO_DECIMAL, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); return (E_DB_ERROR); } /* Check distributed specification ** ** a=local_server, b=distrib_server, c=distrib_session ** ** a,b ** ** 00 01 11 10 ** ----------------- ** c | | | | | ** 0 | 1 | 1 | 0 | 0 | ** | | | | | ** ----------------- ==> ERROR ** | | | | | ** 1 | 1 | 0 | 0 | 1 | ** | | | | | ** ----------------- */ if ( !(psq_cb->psq_distrib & (DB_1_LOCAL_SVR | DB_3_DDB_SESS)) || ((~psq_cb->psq_distrib & DB_2_DISTRIB_SVR) && (psq_cb->psq_distrib & DB_3_DDB_SESS)) ) { psf_error(E_PS0204_BAD_DISTRIB, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error,0); return (E_DB_ERROR); } /* ** Check for too many sessions in server at one time. ** This code must be executed as a critical region. */ do /* something to break out of */ { /* get the semaphore */ if (sem_status = CSp_semaphore(1, &Psf_srvblk->psf_sem)) /* exclusive */ { status = E_DB_SEVERE; /* abort the session */ sem_errno = E_PS020A_BGNSES_GETSEM_FAILURE; break; } if (Psf_srvblk->psf_nmsess >= Psf_srvblk->psf_mxsess) { (VOID) psf_error(E_PS0208_TOO_MANY_SESS, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); status = E_DB_ERROR; break; } /* Increment the session count */ Psf_srvblk->psf_nmsess++; sess_cb->pss_psessid = ++Psf_srvblk->psf_sess_num; /* leave_loop has already been set to TRUE */ } while (!leave_loop); /* if semaphore has been successfully acquired, try to release it */ if (sem_status == OK) { if (sem_status = CSv_semaphore(&Psf_srvblk->psf_sem)) { status = E_DB_FATAL; /* bring down the server */ sem_errno = E_PS020B_BGNSES_RELSEM_FAILURE; } } /* ** if an error was encountered while trying to get or to release a ** semaphore, report it here */ if (sem_status != OK) { (VOID) psf_error(sem_errno, sem_status, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); } if (DB_FAILURE_MACRO(status)) { return(status); } /* ** Initialize the case translation semantics stuff */ sess_cb->pss_dbxlate = psq_cb->psq_dbxlate; sess_cb->pss_cat_owner = psq_cb->psq_cat_owner; /* ** Copy the user name and dba name to the session control block. */ STRUCT_ASSIGN_MACRO(psq_cb->psq_user.db_tab_own, sess_cb->pss_user); STRUCT_ASSIGN_MACRO(psq_cb->psq_dba, sess_cb->pss_dba); STRUCT_ASSIGN_MACRO(psq_cb->psq_group, sess_cb->pss_group); STRUCT_ASSIGN_MACRO(psq_cb->psq_aplid, sess_cb->pss_aplid); /* copy DBA name into sess_cb->pss_dbaname and NULL-terminate */ { u_i2 dba_name_len; dba_name_len = (u_i2) psf_trmwhite((u_i4) sizeof(sess_cb->pss_dba), (char *) &sess_cb->pss_dba); MEcopy((PTR) &sess_cb->pss_dba, dba_name_len, (PTR) sess_cb->pss_dbaname); sess_cb->pss_dbaname[dba_name_len] = EOS; } /* ** Build a DB_OWN_NAME which contains a session-unique owner name. This ** owner name will be used for temporary tables which are owned by this ** session. */ { char temp_sess_id[10]; STmove(DB_SESS_TEMP_OWNER, ' ', sizeof(sess_cb->pss_sess_owner), (char *)&sess_cb->pss_sess_owner); /* ** We can't convert directly into the sess_owner field because CVlx ** null-terminates the result, and we don't want the trailing null */ CVlx(sess_cb->pss_psessid, temp_sess_id); MEcopy(temp_sess_id, 8, &sess_cb->pss_sess_owner.db_own_name[5]); } /* ** Start with per-user quota of memory. Note that user may have overridden ** the default value at server startup in which case we will use calculated ** amount (pool/sessions); otherwise, default amount will be used. */ sess_cb->pss_memleft = (Psf_srvblk->psf_sess_mem) ? Psf_srvblk->psf_sess_mem : PSF_SESMEM; /* ** Initialize the user range table. */ if (pst_rginit(&sess_cb->pss_usrrange) != E_DB_OK) { return (E_DB_FATAL); } /* ** Initialize the auxiliary range table. */ if (pst_rginit(&sess_cb->pss_auxrng) != E_DB_OK) { return (E_DB_FATAL); } /* ** Open a memory stream for the symbol table. The symbol table is ** composed of a list of blocks. ** Allocate the symbol table at the same time. */ ulm_rcb.ulm_facility = DB_PSF_ID; ulm_rcb.ulm_poolid = Psf_srvblk->psf_poolid; ulm_rcb.ulm_blocksize = sizeof(PSS_SYMBLK); ulm_rcb.ulm_memleft = &sess_cb->pss_memleft; /* Set pointer to stream handle for ULM */ ulm_rcb.ulm_streamid_p = &sess_cb->pss_symstr; /* Open a private, thread-safe stream */ ulm_rcb.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC; ulm_rcb.ulm_psize = sizeof(PSS_SYMBLK); if (ulm_openstream(&ulm_rcb) != E_DB_OK) { if (ulm_rcb.ulm_error.err_code == E_UL0005_NOMEM) { (VOID) psf_error(E_PS0F02_MEMORY_FULL, 0L, PSF_CALLERR, &err_code, &psq_cb->psq_error, 0); } else { (VOID) psf_error(E_PS0A02_BADALLOC, ulm_rcb.ulm_error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); } return((ulm_rcb.ulm_error.err_code == E_UL0004_CORRUPT) ? E_DB_FATAL : E_DB_ERROR); } sess_cb->pss_symtab = (PSS_SYMBLK*) ulm_rcb.ulm_pptr; sess_cb->pss_symtab->pss_sbnext = (PSS_SYMBLK *) NULL; /* ** Allocate the YACC_CB. */ if ((status = psl_yalloc(sess_cb->pss_symstr, &sess_cb->pss_memleft, (PTR *) &sess_cb->pss_yacc, &psq_cb->psq_error)) != E_DB_OK) { /* ** If the allocation failed, remember to close the streams, so the ** memory associated with it will be freed. */ (VOID) ulm_closestream(&ulm_rcb); return (status); } /* ** Fill in the control block header. */ sess_cb->pss_next = (PSS_SESBLK *) NULL; sess_cb->pss_prev = (PSS_SESBLK *) NULL; sess_cb->pss_length = sizeof(PSS_SESBLK); sess_cb->pss_type = PSS_SBID; sess_cb->pss_owner = (PTR)DB_PSF_ID; sess_cb->pss_ascii_id = PSSSES_ID; /* ** Initialize the session control block. */ /* Save the session id */ sess_cb->pss_sessid = psq_cb->psq_sessid; /* Set pointer to session's ADF_CB */ sess_cb->pss_adfcb = (ADF_CB *) psq_cb->psq_adfcb; /* No cursors yet */ sess_cb->pss_numcursors = 0; /* Language has already been validated */ sess_cb->pss_lang = psq_cb->psq_qlang; /* Decimal spec has already been validated */ sess_cb->pss_decimal = psq_cb->psq_decimal.db_decimal; /* Distributed spec has already been validated */ sess_cb->pss_distrib = psq_cb->psq_distrib; /* Save the database id */ sess_cb->pss_dbid = psq_cb->psq_dbid; /* Save the unique database id */ sess_cb->pss_udbid = psq_cb->psq_udbid; /* Initialize QSF_RCB for use by psfmem.c functions */ sess_cb->pss_qsf_rcb.qsf_type = QSFRB_CB; sess_cb->pss_qsf_rcb.qsf_ascii_id = QSFRB_ASCII_ID; sess_cb->pss_qsf_rcb.qsf_length = sizeof(sess_cb->pss_qsf_rcb); sess_cb->pss_qsf_rcb.qsf_owner = (PTR)DB_PSF_ID; sess_cb->pss_qsf_rcb.qsf_sid = sess_cb->pss_sessid; /* ** so session reset all bit flags */ sess_cb->pss_stmt_flags = sess_cb->pss_stmt_flags2 = sess_cb->pss_dbp_flags = sess_cb->pss_ses_flag = 0L; sess_cb->pss_flattening_flags = 0; /* ** Default table create semantics are to assume journaling unless ** the PSF_NO_JNL_DEFAULT override is set. */ if ((Psf_srvblk->psf_flags & PSF_NO_JNL_DEFAULT) == 0) sess_cb->pss_ses_flag |= PSS_JOURNALING; /* catalog update flag */ if (psq_cb->psq_flag & PSQ_CATUPD) sess_cb->pss_ses_flag |= PSS_CATUPD; /* warnings on unsupported commands */ if (psq_cb->psq_flag & PSQ_WARNINGS) sess_cb->pss_ses_flag |= PSS_WARNINGS; /* INDICATE if the DBA may DROP everyone's tables */ if (psq_cb->psq_flag & PSQ_DBA_DROP_ALL) sess_cb->pss_ses_flag |= PSS_DBA_DROP_ALL; /* INDICATE if the session may SELECT everyone's tables */ if (psq_cb->psq_flag & PSQ_SELECT_ALL) sess_cb->pss_ses_flag |= PSS_SELECT_ALL; /* ** indicate that the session is allowed to INSERT/DELETE/UPDATE an index ** which is a catalog (but not an extended catalog */ if (psq_cb->psq_flag & PSQ_REPAIR_SYSCAT) sess_cb->pss_ses_flag |= PSS_REPAIR_SYSCAT; /* ** indicate that the session allows $ingres to drop/add constraint on ** tables owned by other users */ if (psq_cb->psq_flag & PSQ_INGRES_PRIV) sess_cb->pss_ses_flag |= PSS_INGRES_PRIV; if (psq_cb->psq_flag & PSQ_ROW_SEC_KEY) sess_cb->pss_ses_flag |= PSS_ROW_SEC_KEY; /* See if passwords, roles allowed */ if (psq_cb->psq_flag & PSQ_PASSWORD_NONE) sess_cb->pss_ses_flag |= PSS_PASSWORD_NONE; if (psq_cb->psq_flag & PSQ_ROLE_NONE) sess_cb->pss_ses_flag |= PSS_ROLE_NONE; if (psq_cb->psq_flag & PSQ_ROLE_NEED_PW) sess_cb->pss_ses_flag |= PSS_ROLE_NEED_PW; /* remember whether we are running UPGRADEDB */ if (psq_cb->psq_flag & PSQ_RUNNING_UPGRADEDB) sess_cb->pss_ses_flag |= PSS_RUNNING_UPGRADEDB; /* Pick up serverwide default for card check */ if (Psf_srvblk->psf_flags & PSF_NOCHK_SINGLETON_CARD) sess_cb->pss_ses_flag |= PSS_NOCHK_SINGLETON_CARD; /* Initialize pss_project. */ sess_cb->pss_ses_flag |= PSS_PROJECT; /* pss_project = TRUE */ /* init last statement */ sess_cb->pss_last_sname[0] = EOS; /* batch optimization switch starts undefined */ sess_cb->batch_copy_optim = PSS_BATCH_OPTIM_UNDEF; /* ** if starting a local session, determine whether the database is being ** journaled */ if (~psq_cb->psq_distrib & DB_3_DDB_SESS) { DMC_CB dmc_cb, *dmc = &dmc_cb; DMC_CHAR_ENTRY dmc_char; MEfill(sizeof(dmc_cb), (u_char) 0, (PTR) dmc); dmc->type = DMC_CONTROL_CB; dmc->length = sizeof(*dmc); dmc->dmc_op_type = DMC_DATABASE_OP; dmc->dmc_session_id = (PTR) sess_cb->pss_sessid; dmc->dmc_flags_mask = DMC_JOURNAL; dmc->dmc_char_array.data_address= (PTR) &dmc_char; dmc->dmc_char_array.data_out_size = sizeof(dmc_char); dmc->dmc_db_id = (char *) sess_cb->pss_dbid; status = dmf_call(DMC_SHOW, (PTR) dmc); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS020E_CANT_GET_DB_JOUR_STATUS, dmc->error.err_code, PSF_INTERR, &err_code, &psq_cb->psq_error, 0); return(status); } if (dmc_char.char_value == DMC_C_ON) { sess_cb->pss_ses_flag |= PSS_JOURNALED_DB; } } /* Save the storage structure for indexes */ sess_cb->pss_idxstruct = psq_cb->psq_idxstruct; /* Make session copy of parser compatability settings */ sess_cb->pss_parser_compat = psq_cb->psq_parser_compat; /* remember if NLs inside string constants need to be stripped */ if (psq_cb->psq_flag & PSQ_STRIP_NL_IN_STRCONST) sess_cb->pss_ses_flag |= PSS_STRIP_NL_IN_STRCONST; /* no rule tree yet */ sess_cb->pss_row_lvl_usr_rules = sess_cb->pss_row_lvl_sys_rules = sess_cb->pss_stmt_lvl_usr_rules = sess_cb->pss_stmt_lvl_sys_rules = sess_cb->pss_row_lvl_usr_before_rules = sess_cb->pss_row_lvl_sys_before_rules = sess_cb->pss_stmt_lvl_usr_before_rules = sess_cb->pss_stmt_lvl_sys_before_rules = (PST_STATEMENT *) NULL; if (psq_cb->psq_flag & PSQ_RULE_DEL_PREFETCH) sess_cb->pss_ses_flag |= PSS_RULE_DEL_PREFETCH; if(psq_cb->psq_flag2 & PSQ_RULE_UPD_PREFETCH) sess_cb->pss_ses_flag |= PSS_RULE_UPD_PREFETCH; /* copy user status flags to session control block */ sess_cb->pss_ustat = psq_cb->psq_ustat; /* ** Initialize lots of pointer to NULL because nothing is happening yet. */ sess_cb->pss_qbuf = sess_cb->pss_nxtchar = sess_cb->pss_prvtok = sess_cb->pss_bgnstmt = sess_cb->pss_endbuf = sess_cb->pss_prvgoval = (u_char *) NULL; /* initialize pss_audit */ sess_cb->pss_audit = NULL; for (i = 0; i < PSS_CURTABSIZE; i++) { sess_cb->pss_curstab.pss_curque[i] = (PSC_CURBLK *) NULL; } /* initialize prototype list for dynamic SQL */ sess_cb->pss_proto = (PST_PROTO *) NULL; /* ** pss_dependencies_stream, when not NULL, is expected to point at a valid ** stream descriptor. After closing the stream we always reset ** pss_dependencies_stream to NULL, but in some cases we may end up checking ** pss_dependencies_stream before ever opening (and closing it). As a ** result, you may end up using invalid address as a stream pointer. ** Initializing it here to NULL will ensure that it is non-NULL iff it ** points at a valid open stream descriptor. */ sess_cb->pss_dependencies_stream = (PSF_MSTREAM *) NULL; /* No trace flags set */ /* expect lint message */ ult_init_macro(&sess_cb->pss_trace, PSS_TBITS, PSS_TVALS, PSS_TVAO); /* Cursor id set to 0, no cursors open yet */ sess_cb->pss_crsid = 0; sess_cb->pss_create_compression = Psf_srvblk->psf_create_compression; /* SCF can pass a client requested result_structure, but if it ** doesn't, init from server default. */ if (psq_cb->psq_result_struct != 0) { sess_cb->pss_result_struct = psq_cb->psq_result_struct; sess_cb->pss_result_compression = psq_cb->psq_result_compression; } else { sess_cb->pss_result_struct = Psf_srvblk->psf_result_struct; sess_cb->pss_result_compression = Psf_srvblk->psf_result_compression; } if (psq_cb->psq_def_coll > DB_NOCOLLATION) sess_cb->pss_def_coll = psq_cb->psq_def_coll; else sess_cb->pss_def_coll = Psf_srvblk->psf_def_coll; if (psq_cb->psq_def_unicode_coll > DB_NOCOLLATION) sess_cb->pss_def_unicode_coll = psq_cb->psq_def_unicode_coll; else sess_cb->pss_def_unicode_coll = Psf_srvblk->psf_def_unicode_coll; return (E_DB_OK); }