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
41namespace EDS {
42class Statement;
43}
44
45namespace Jrd {
46
47class Lock;
48class Format;
49class jrd_rel;
50class jrd_prc;
51class Record;
52class ValueListNode;
53template <typename T> class vec;
54class jrd_tra;
55class Savepoint;
56class RecordSource;
57class Cursor;
58class thread_db;
59
60// record parameter block
61
62struct 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
108private:
109 struct win rpb_window;
110};
111
112// Record flags must be an exact replica of ODS record header flags
113
114const USHORT rpb_deleted = 1;
115const USHORT rpb_chained = 2;
116const USHORT rpb_fragment = 4;
117const USHORT rpb_incomplete = 8;
118const USHORT rpb_blob = 16;
119const USHORT rpb_delta = 32; // prior version is a differences record
120// rpb_large = 64 is missing
121const USHORT rpb_damaged = 128; // record is busted
122const USHORT rpb_gc_active = 256; // garbage collecting dead record version
123const USHORT rpb_uk_modified= 512; // record key field values are changed
124
125// Stream flags
126
127const USHORT RPB_s_refetch = 0x01; // re-fetch required due to sort
128const USHORT RPB_s_update = 0x02; // input stream fetched for update
129const USHORT RPB_s_no_data = 0x04; // nobody is going to access the data
130const USHORT RPB_s_undo_data = 0x08; // data got from undo log
131const USHORT RPB_s_sweeper = 0x10; // garbage collector - skip swept pages
132const USHORT RPB_s_refetch_no_undo = 0x20; // re-fetch required due to modify\erase, don't use undo data
133
134const 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
139const USHORT DPM_primary = 1; // New primary record
140const USHORT DPM_secondary = 2; // Chained version of primary record
141const USHORT DPM_other = 3; // Independent (or don't care) record
142
143// Record block (holds data, remember data?)
144
145class Record : public pool_alloc_rpt<SCHAR, type_rec>
146{
147public:
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
190const UCHAR REC_same_tx = 1; // record inserted/updated and deleted by same tx
191const UCHAR REC_gc_active = 2; // relation garbage collect record block in use
192const UCHAR REC_new_version = 4; // savepoint created new record version and deleted it
193
194// List of active blobs controlled by request
195
196typedef Firebird::BePlusTree<ULONG, ULONG, MemoryPool> TempBlobIdTree;
197
198// Affected rows counter class
199
200class AffectedRows
201{
202public:
203 AffectedRows();
204
205 void clear();
206 void bumpFetched();
207 void bumpModified(bool);
208
209 int getCount() const;
210
211private:
212 bool writeFlag;
213 int fetchedRows;
214 int modifiedRows;
215};
216
217// request block
218
219class jrd_req : public pool_alloc<type_req>
220{
221public:
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
256private:
257 /*const*/ JrdStatement* const statement;
258
259public:
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
356const ULONG req_active = 0x1L;
357const ULONG req_stall = 0x2L;
358const ULONG req_leave = 0x4L;
359const ULONG req_null = 0x8L;
360const ULONG req_abort = 0x10L;
361const ULONG req_error_handler = 0x20L; // looper is called to handle error
362const ULONG req_warning = 0x40L;
363const ULONG req_in_use = 0x80L;
364const ULONG req_continue_loop = 0x100L; // PSQL continue statement
365const ULONG req_proc_fetch = 0x200L; // Fetch from procedure in progress
366const ULONG req_same_tx_upd = 0x400L; // record was updated by same transaction
367const ULONG req_reserved = 0x800L; // Request reserved for client
368
369// Flags for req_view_flags
370enum {
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
379class IndexLock : public pool_alloc<type_idl>
380{
381public:
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