1 | /* |
2 | * PROGRAM: JRD Access Method |
3 | * MODULE: req.h |
4 | * DESCRIPTION: Request block definitions |
5 | * |
6 | * The contents of this file are subject to the Interbase Public |
7 | * License Version 1.0 (the "License"); you may not use this file |
8 | * except in compliance with the License. You may obtain a copy |
9 | * of the License at http://www.Inprise.com/IPL.html |
10 | * |
11 | * Software distributed under the License is distributed on an |
12 | * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express |
13 | * or implied. See the License for the specific language governing |
14 | * rights and limitations under the License. |
15 | * |
16 | * The Original Code was created by Inprise Corporation |
17 | * and its predecessors. Portions created by Inprise Corporation are |
18 | * Copyright (C) Inprise Corporation. |
19 | * |
20 | * All Rights Reserved. |
21 | * Contributor(s): ______________________________________. |
22 | * |
23 | * 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced |
24 | * exception handling in SPs/triggers, |
25 | * implemented ROWS_AFFECTED system variable |
26 | */ |
27 | |
28 | #ifndef JRD_REQ_H |
29 | #define JRD_REQ_H |
30 | |
31 | #include "../include/fb_blk.h" |
32 | |
33 | #include "../jrd/exe.h" |
34 | #include "../jrd/sort.h" |
35 | #include "../jrd/Attachment.h" |
36 | #include "../jrd/JrdStatement.h" |
37 | #include "../jrd/RecordNumber.h" |
38 | #include "../common/classes/stack.h" |
39 | #include "../common/classes/timestamp.h" |
40 | |
41 | namespace EDS { |
42 | class Statement; |
43 | } |
44 | |
45 | namespace Jrd { |
46 | |
47 | class Lock; |
48 | class Format; |
49 | class jrd_rel; |
50 | class jrd_prc; |
51 | class Record; |
52 | class ValueListNode; |
53 | template <typename T> class vec; |
54 | class jrd_tra; |
55 | class Savepoint; |
56 | class RecordSource; |
57 | class Cursor; |
58 | class thread_db; |
59 | |
60 | // record parameter block |
61 | |
62 | struct record_param |
63 | { |
64 | record_param() |
65 | : rpb_transaction_nr(0), rpb_relation(0), rpb_record(NULL), rpb_prior(NULL), |
66 | rpb_undo(NULL), rpb_format_number(0), |
67 | rpb_page(0), rpb_line(0), |
68 | rpb_f_page(0), rpb_f_line(0), |
69 | rpb_b_page(0), rpb_b_line(0), |
70 | rpb_address(NULL), rpb_length(0), rpb_flags(0), rpb_stream_flags(0), |
71 | rpb_org_scans(0), |
72 | rpb_window(DB_PAGE_SPACE, -1) |
73 | { |
74 | } |
75 | |
76 | RecordNumber rpb_number; // record number in relation |
77 | TraNumber rpb_transaction_nr; // transaction number |
78 | jrd_rel* rpb_relation; // relation of record |
79 | Record* rpb_record; // final record block |
80 | Record* rpb_prior; // prior record block if this is a delta record |
81 | Record* rpb_undo; // our first version of data if this is a second modification |
82 | USHORT rpb_format_number; // format number in relation |
83 | |
84 | ULONG rpb_page; // page number |
85 | USHORT rpb_line; // line number on page |
86 | |
87 | ULONG rpb_f_page; // fragment page number |
88 | USHORT rpb_f_line; // fragment line number on page |
89 | |
90 | ULONG rpb_b_page; // back page |
91 | USHORT rpb_b_line; // back line |
92 | |
93 | UCHAR* rpb_address; // address of record sans header |
94 | ULONG rpb_length; // length of record |
95 | USHORT rpb_flags; // record ODS flags replica |
96 | USHORT rpb_stream_flags; // stream flags |
97 | SSHORT rpb_org_scans; // relation scan count at stream open |
98 | |
99 | inline WIN& getWindow(thread_db* tdbb) |
100 | { |
101 | if (rpb_relation) { |
102 | rpb_window.win_page.setPageSpaceID(rpb_relation->getPages(tdbb)->rel_pg_space_id); |
103 | } |
104 | |
105 | return rpb_window; |
106 | } |
107 | |
108 | private: |
109 | struct win rpb_window; |
110 | }; |
111 | |
112 | // Record flags must be an exact replica of ODS record header flags |
113 | |
114 | const USHORT rpb_deleted = 1; |
115 | const USHORT rpb_chained = 2; |
116 | const USHORT rpb_fragment = 4; |
117 | const USHORT rpb_incomplete = 8; |
118 | const USHORT rpb_blob = 16; |
119 | const USHORT rpb_delta = 32; // prior version is a differences record |
120 | // rpb_large = 64 is missing |
121 | const USHORT rpb_damaged = 128; // record is busted |
122 | const USHORT rpb_gc_active = 256; // garbage collecting dead record version |
123 | const USHORT rpb_uk_modified= 512; // record key field values are changed |
124 | |
125 | // Stream flags |
126 | |
127 | const USHORT RPB_s_refetch = 0x01; // re-fetch required due to sort |
128 | const USHORT RPB_s_update = 0x02; // input stream fetched for update |
129 | const USHORT RPB_s_no_data = 0x04; // nobody is going to access the data |
130 | const USHORT RPB_s_undo_data = 0x08; // data got from undo log |
131 | const USHORT RPB_s_sweeper = 0x10; // garbage collector - skip swept pages |
132 | const USHORT RPB_s_refetch_no_undo = 0x20; // re-fetch required due to modify\erase, don't use undo data |
133 | |
134 | const unsigned int MAX_DIFFERENCES = 1024; // Max length of generated Differences string |
135 | // between two records |
136 | |
137 | // Store allocation policy types. Parameter to DPM_store() |
138 | |
139 | const USHORT DPM_primary = 1; // New primary record |
140 | const USHORT DPM_secondary = 2; // Chained version of primary record |
141 | const USHORT DPM_other = 3; // Independent (or don't care) record |
142 | |
143 | // Record block (holds data, remember data?) |
144 | |
145 | class Record : public pool_alloc_rpt<SCHAR, type_rec> |
146 | { |
147 | public: |
148 | explicit Record(MemoryPool& p) : rec_pool(p), rec_precedence(p) { } |
149 | // ASF: Record is memcopied in realloc_record (vio.cpp), starting at rec_format. |
150 | // rec_precedence has destructor, so don't move it to after rec_format. |
151 | MemoryPool& rec_pool; // pool where record to be expanded |
152 | PageStack rec_precedence; // stack of higher precedence pages/transactions |
153 | const Format* rec_format; // what the data looks like |
154 | ULONG rec_length; // how much there is |
155 | const Format* rec_fmt_bk; // backup format to cope with Borland's ill null signaling |
156 | UCHAR rec_flags; // misc record flags |
157 | RecordNumber rec_number; // original record_param number - used for undoing multiple updates |
158 | union |
159 | { |
160 | double rec_dummy; // this is to force next field to a double boundary |
161 | UCHAR rec_data[1]; // THIS VARIABLE MUST BE ALIGNED ON A DOUBLE BOUNDARY |
162 | }; |
163 | |
164 | void setNull(USHORT id) |
165 | { |
166 | rec_data[id >> 3] |= (1 << (id & 7)); |
167 | } |
168 | |
169 | void clearNull(USHORT id) |
170 | { |
171 | rec_data[id >> 3] &= ~(1 << (id & 7)); |
172 | } |
173 | |
174 | bool isNull(USHORT id) |
175 | { |
176 | return ((rec_data[id >> 3] & (1 << (id & 7))) != 0); |
177 | } |
178 | |
179 | void nullify() |
180 | { |
181 | // Zero the record buffer and initialize all fields to NULLs |
182 | const size_t null_bytes = (rec_format->fmt_count + 7) >> 3; |
183 | memset(rec_data, 0xFF, null_bytes); |
184 | memset(rec_data + null_bytes, 0, rec_length - null_bytes); |
185 | } |
186 | }; |
187 | |
188 | // rec_flags |
189 | |
190 | const UCHAR REC_same_tx = 1; // record inserted/updated and deleted by same tx |
191 | const UCHAR REC_gc_active = 2; // relation garbage collect record block in use |
192 | const UCHAR REC_new_version = 4; // savepoint created new record version and deleted it |
193 | |
194 | // List of active blobs controlled by request |
195 | |
196 | typedef Firebird::BePlusTree<ULONG, ULONG, MemoryPool> TempBlobIdTree; |
197 | |
198 | // Affected rows counter class |
199 | |
200 | class AffectedRows |
201 | { |
202 | public: |
203 | AffectedRows(); |
204 | |
205 | void clear(); |
206 | void bumpFetched(); |
207 | void bumpModified(bool); |
208 | |
209 | int getCount() const; |
210 | |
211 | private: |
212 | bool writeFlag; |
213 | int fetchedRows; |
214 | int modifiedRows; |
215 | }; |
216 | |
217 | // request block |
218 | |
219 | class jrd_req : public pool_alloc<type_req> |
220 | { |
221 | public: |
222 | jrd_req(Attachment* attachment, /*const*/ JrdStatement* aStatement, |
223 | Firebird::MemoryStats* parent_stats) |
224 | : statement(aStatement), |
225 | req_pool(statement->pool), |
226 | req_memory_stats(parent_stats), |
227 | req_blobs(req_pool), |
228 | req_stats(*req_pool), |
229 | req_base_stats(*req_pool), |
230 | req_ext_stmt(NULL), |
231 | req_cursors(*req_pool), |
232 | req_ext_resultset(NULL), |
233 | req_domain_validation(NULL), |
234 | req_auto_trans(*req_pool), |
235 | req_sorts(*req_pool), |
236 | req_rpb(*req_pool), |
237 | impureArea(*req_pool) |
238 | { |
239 | setAttachment(attachment); |
240 | req_rpb = statement->rpbsSetup; |
241 | impureArea.grow(statement->impureSize); |
242 | } |
243 | |
244 | /*const*/ JrdStatement* getStatement() const |
245 | { |
246 | return statement; |
247 | } |
248 | |
249 | void setAttachment(Attachment* newAttachment) |
250 | { |
251 | req_attachment = newAttachment; |
252 | charSetId = statement->flags & JrdStatement::FLAG_INTERNAL ? |
253 | CS_METADATA : req_attachment->att_charset; |
254 | } |
255 | |
256 | private: |
257 | /*const*/ JrdStatement* const statement; |
258 | |
259 | public: |
260 | MemoryPool* req_pool; |
261 | Attachment* req_attachment; // database attachment |
262 | SLONG req_id; // request identifier |
263 | USHORT req_incarnation; // incarnation number |
264 | Firebird::MemoryStats req_memory_stats; |
265 | |
266 | // Transaction pointer and doubly linked list pointers for requests in this |
267 | // transaction. Maintained by TRA_attach_request/TRA_detach_request. |
268 | jrd_tra* req_transaction; |
269 | jrd_req* req_tra_next; |
270 | jrd_req* req_tra_prev; |
271 | |
272 | jrd_req* req_caller; // Caller of this request |
273 | // This field may be used to reconstruct the whole call stack |
274 | TempBlobIdTree req_blobs; // Temporary BLOBs owned by this request |
275 | const StmtNode* req_message; // Current message for send/receive |
276 | |
277 | ULONG req_records_selected; // count of records selected by request (meeting selection criteria) |
278 | ULONG req_records_inserted; // count of records inserted by request |
279 | ULONG req_records_updated; // count of records updated by request |
280 | ULONG req_records_deleted; // count of records deleted by request |
281 | RuntimeStatistics req_stats; |
282 | RuntimeStatistics req_base_stats; |
283 | AffectedRows req_records_affected; // records affected by the last statement |
284 | |
285 | USHORT req_view_flags; // special flags for virtual ops on views |
286 | jrd_rel* req_top_view_store; // the top view in store(), if any |
287 | jrd_rel* req_top_view_modify; // the top view in modify(), if any |
288 | jrd_rel* req_top_view_erase; // the top view in erase(), if any |
289 | |
290 | const StmtNode* req_next; // next node for execution |
291 | EDS::Statement* req_ext_stmt; // head of list of active dynamic statements |
292 | Firebird::Array<const Cursor*> req_cursors; // named cursors |
293 | ExtEngineManager::ResultSet* req_ext_resultset; // external result set |
294 | USHORT req_label; // label for leave |
295 | ULONG req_flags; // misc request flags |
296 | Savepoint* req_proc_sav_point; // procedure savepoint list |
297 | Firebird::TimeStamp req_timestamp; // Start time of request |
298 | |
299 | Firebird::AutoPtr<Jrd::RuntimeStatistics> req_fetch_baseline; // State of request performance counters when we reported it last time |
300 | SINT64 req_fetch_elapsed; // Number of clock ticks spent while fetching rows for this request since we reported it last time |
301 | SINT64 req_fetch_rowcount; // Total number of rows returned by this request |
302 | jrd_req* req_proc_caller; // Procedure's caller request |
303 | const ValueListNode* req_proc_inputs; // and its node with input parameters |
304 | |
305 | ULONG req_src_line; |
306 | ULONG req_src_column; |
307 | |
308 | dsc* req_domain_validation; // Current VALUE for constraint validation |
309 | Firebird::Stack<jrd_tra*> req_auto_trans; // Autonomous transactions |
310 | SortOwner req_sorts; |
311 | Firebird::Array<record_param> req_rpb; // record parameter blocks |
312 | Firebird::Array<UCHAR> impureArea; // impure area |
313 | USHORT charSetId; // "client" character set of the request |
314 | |
315 | enum req_ta { |
316 | // Order should be maintained because the numbers are stored in BLR |
317 | // and should be in sync with ExternalTrigger::Action. |
318 | req_trigger_insert = 1, |
319 | req_trigger_update = 2, |
320 | req_trigger_delete = 3, |
321 | req_trigger_connect = 4, |
322 | req_trigger_disconnect = 5, |
323 | req_trigger_trans_start = 6, |
324 | req_trigger_trans_commit = 7, |
325 | req_trigger_trans_rollback = 8, |
326 | req_trigger_ddl = 9 |
327 | } req_trigger_action; // action that caused trigger to fire |
328 | |
329 | enum req_s { |
330 | req_evaluate, |
331 | req_return, |
332 | req_receive, |
333 | req_send, |
334 | req_proceed, |
335 | req_sync, |
336 | req_unwind |
337 | } req_operation; // operation for next node |
338 | |
339 | StatusXcp req_last_xcp; // last known exception |
340 | |
341 | template <typename T> T* getImpure(unsigned offset) |
342 | { |
343 | return reinterpret_cast<T*>(&impureArea[offset]); |
344 | } |
345 | |
346 | void adjustCallerStats() |
347 | { |
348 | if (req_caller) { |
349 | req_caller->req_stats.adjust(req_base_stats, req_stats); |
350 | } |
351 | req_base_stats.assign(req_stats); |
352 | } |
353 | }; |
354 | |
355 | // Flags for req_flags |
356 | const ULONG req_active = 0x1L; |
357 | const ULONG req_stall = 0x2L; |
358 | const ULONG req_leave = 0x4L; |
359 | const ULONG req_null = 0x8L; |
360 | const ULONG req_abort = 0x10L; |
361 | const ULONG req_error_handler = 0x20L; // looper is called to handle error |
362 | const ULONG req_warning = 0x40L; |
363 | const ULONG req_in_use = 0x80L; |
364 | const ULONG req_continue_loop = 0x100L; // PSQL continue statement |
365 | const ULONG req_proc_fetch = 0x200L; // Fetch from procedure in progress |
366 | const ULONG req_same_tx_upd = 0x400L; // record was updated by same transaction |
367 | const ULONG req_reserved = 0x800L; // Request reserved for client |
368 | |
369 | // Flags for req_view_flags |
370 | enum { |
371 | req_first_store_return = 0x1, |
372 | req_first_modify_return = 0x2, |
373 | req_first_erase_return = 0x4 |
374 | }; |
375 | |
376 | |
377 | // Index lock block |
378 | |
379 | class IndexLock : public pool_alloc<type_idl> |
380 | { |
381 | public: |
382 | IndexLock* idl_next; // Next index lock block for relation |
383 | Lock* idl_lock; // Lock block |
384 | jrd_rel* idl_relation; // Parent relation |
385 | USHORT idl_id; // Index id |
386 | USHORT idl_count; // Use count |
387 | }; |
388 | |
389 | |
390 | } //namespace Jrd |
391 | |
392 | #endif // JRD_REQ_H |
393 | |