1 | /* |
2 | * PROGRAM: JRD Access Method |
3 | * MODULE: exe.h |
4 | * DESCRIPTION: Execution 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 | * 2001.07.28: Added rse_skip to class RecordSelExpr to support LIMIT. |
24 | * 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced |
25 | * exception handling in SPs/triggers, |
26 | * implemented ROWS_AFFECTED system variable |
27 | * 2002.10.21 Nickolay Samofatov: Added support for explicit pessimistic locks |
28 | * 2002.10.29 Nickolay Samofatov: Added support for savepoints |
29 | * Adriano dos Santos Fernandes |
30 | */ |
31 | |
32 | #ifndef JRD_EXE_H |
33 | #define JRD_EXE_H |
34 | |
35 | #include "../jrd/blb.h" |
36 | #include "../jrd/Relation.h" |
37 | #include "../common/classes/array.h" |
38 | #include "../common/classes/MetaName.h" |
39 | #include "../common/classes/NestConst.h" |
40 | |
41 | #include "gen/iberror.h" |
42 | |
43 | #include "../common/dsc.h" |
44 | #include "../jrd/rse.h" |
45 | |
46 | #include "../jrd/err_proto.h" |
47 | #include "../jrd/scl.h" |
48 | #include "../jrd/sbm.h" |
49 | #include "../jrd/sort.h" |
50 | |
51 | #include "../jrd/DebugInterface.h" |
52 | #include "../common/classes/BlrReader.h" |
53 | #include "../dsql/Nodes.h" |
54 | #include "../dsql/Visitors.h" |
55 | |
56 | // This macro enables DSQL tracing code |
57 | //#define CMP_DEBUG |
58 | |
59 | #ifdef CMP_DEBUG |
60 | DEFINE_TRACE_ROUTINE(cmp_trace); |
61 | #define CMP_TRACE(args) cmp_trace args |
62 | #else |
63 | #define CMP_TRACE(args) // nothing |
64 | #endif |
65 | |
66 | class VaryingString; |
67 | struct dsc; |
68 | |
69 | namespace Jrd { |
70 | |
71 | class jrd_rel; |
72 | class Sort; |
73 | struct sort_key_def; |
74 | template <typename T> class vec; |
75 | class jrd_prc; |
76 | class Collation; |
77 | struct index_desc; |
78 | struct IndexDescAlloc; |
79 | class Format; |
80 | class ForNode; |
81 | class Cursor; |
82 | class DeclareSubFuncNode; |
83 | class DeclareSubProcNode; |
84 | class DeclareVariableNode; |
85 | class MessageNode; |
86 | class PlanNode; |
87 | class RecordSource; |
88 | |
89 | // Types of nulls placement for each column in sort order |
90 | const int rse_nulls_default = 0; |
91 | const int rse_nulls_first = 1; |
92 | const int rse_nulls_last = 2; |
93 | |
94 | |
95 | // Aggregate Sort Block (for DISTINCT aggregates) |
96 | |
97 | class AggregateSort : protected Firebird::PermanentStorage |
98 | { |
99 | public: |
100 | explicit AggregateSort(Firebird::MemoryPool& p) |
101 | : PermanentStorage(p), |
102 | length(0), |
103 | intl(false), |
104 | impure(0), |
105 | keyItems(p) |
106 | { |
107 | desc.clear(); |
108 | } |
109 | |
110 | dsc desc; |
111 | ULONG length; |
112 | bool intl; |
113 | ULONG impure; |
114 | Firebird::HalfStaticArray<sort_key_def, 2> keyItems; |
115 | }; |
116 | |
117 | // Inversion (i.e. nod_index) impure area |
118 | |
119 | struct impure_inversion |
120 | { |
121 | RecordBitmap* inv_bitmap; |
122 | }; |
123 | |
124 | |
125 | // AggregateSort impure area |
126 | |
127 | struct impure_agg_sort |
128 | { |
129 | Sort* iasb_sort; |
130 | }; |
131 | |
132 | |
133 | // Request resources |
134 | |
135 | struct Resource |
136 | { |
137 | enum rsc_s |
138 | { |
139 | rsc_relation, |
140 | rsc_procedure, |
141 | rsc_index, |
142 | rsc_collation, |
143 | rsc_function |
144 | }; |
145 | |
146 | rsc_s rsc_type; |
147 | USHORT rsc_id; // Id of the resource |
148 | jrd_rel* rsc_rel; // Relation block |
149 | Routine* rsc_routine; // Routine block |
150 | Collation* rsc_coll; // Collation block |
151 | |
152 | static bool greaterThan(const Resource& i1, const Resource& i2) |
153 | { |
154 | // A few places of the engine depend on fact that rsc_type |
155 | // is the first field in ResourceList ordering |
156 | if (i1.rsc_type != i2.rsc_type) |
157 | return i1.rsc_type > i2.rsc_type; |
158 | if (i1.rsc_type == rsc_index) |
159 | { |
160 | // Sort by relation ID for now |
161 | if (i1.rsc_rel->rel_id != i2.rsc_rel->rel_id) |
162 | return i1.rsc_rel->rel_id > i2.rsc_rel->rel_id; |
163 | } |
164 | return i1.rsc_id > i2.rsc_id; |
165 | } |
166 | |
167 | Resource(rsc_s type, USHORT id, jrd_rel* rel, Routine* routine, Collation* coll) |
168 | : rsc_type(type), rsc_id(id), rsc_rel(rel), rsc_routine(routine), rsc_coll(coll) |
169 | { } |
170 | }; |
171 | |
172 | typedef Firebird::SortedArray<Resource, Firebird::EmptyStorage<Resource>, |
173 | Resource, Firebird::DefaultKeyValue<Resource>, Resource> ResourceList; |
174 | |
175 | // Access items |
176 | // In case we start to use MetaName with required pool parameter, |
177 | // access item to be reworked! |
178 | // This struct seems better located in scl.h. |
179 | |
180 | struct AccessItem |
181 | { |
182 | Firebird::MetaName acc_security_name; |
183 | SLONG acc_view_id; |
184 | Firebird::MetaName acc_name, acc_r_name; |
185 | SLONG acc_type; |
186 | SecurityClass::flags_t acc_mask; |
187 | |
188 | static bool greaterThan(const AccessItem& i1, const AccessItem& i2) |
189 | { |
190 | int v; |
191 | |
192 | /* CVC: Disabled this horrible hack. |
193 | // Relations and procedures should be sorted before |
194 | // columns, hence such a tricky inverted condition |
195 | if ((v = -strcmp(i1.acc_type, i2.acc_type)) != 0) |
196 | return v > 0; |
197 | */ |
198 | if (i1.acc_type != i2.acc_type) |
199 | return i1.acc_type > i2.acc_type; |
200 | |
201 | if ((v = i1.acc_security_name.compare(i2.acc_security_name)) != 0) |
202 | return v > 0; |
203 | |
204 | if (i1.acc_view_id != i2.acc_view_id) |
205 | return i1.acc_view_id > i2.acc_view_id; |
206 | |
207 | if (i1.acc_mask != i2.acc_mask) |
208 | return i1.acc_mask > i2.acc_mask; |
209 | |
210 | if ((v = i1.acc_name.compare(i2.acc_name)) != 0) |
211 | return v > 0; |
212 | |
213 | if ((v = i1.acc_r_name.compare(i2.acc_r_name)) != 0) |
214 | return v > 0; |
215 | |
216 | return false; // Equal |
217 | } |
218 | |
219 | AccessItem(const Firebird::MetaName& security_name, SLONG view_id, |
220 | const Firebird::MetaName& name, SLONG type, |
221 | SecurityClass::flags_t mask, const Firebird::MetaName& relName) |
222 | : acc_security_name(security_name), acc_view_id(view_id), acc_name(name), |
223 | acc_r_name(relName), acc_type(type), acc_mask(mask) |
224 | {} |
225 | }; |
226 | |
227 | typedef Firebird::SortedArray<AccessItem, Firebird::EmptyStorage<AccessItem>, |
228 | AccessItem, Firebird::DefaultKeyValue<AccessItem>, AccessItem> AccessItemList; |
229 | |
230 | // Triggers and procedures the request accesses |
231 | struct ExternalAccess |
232 | { |
233 | enum exa_act |
234 | { |
235 | exa_procedure, |
236 | exa_function, |
237 | exa_insert, |
238 | exa_update, |
239 | exa_delete |
240 | }; |
241 | exa_act exa_action; |
242 | USHORT exa_prc_id; |
243 | USHORT exa_fun_id; |
244 | USHORT exa_rel_id; |
245 | USHORT exa_view_id; |
246 | |
247 | // Procedure |
248 | ExternalAccess(exa_act action, USHORT id) : |
249 | exa_action(action), |
250 | exa_prc_id(action == exa_procedure ? id : 0), |
251 | exa_fun_id(action == exa_function ? id : 0), |
252 | exa_rel_id(0), exa_view_id(0) |
253 | { } |
254 | |
255 | // Trigger |
256 | ExternalAccess(exa_act action, USHORT rel_id, USHORT view_id) : |
257 | exa_action(action), exa_prc_id(0), exa_fun_id(0), |
258 | exa_rel_id(rel_id), exa_view_id(view_id) |
259 | { } |
260 | |
261 | static bool greaterThan(const ExternalAccess& i1, const ExternalAccess& i2) |
262 | { |
263 | if (i1.exa_action != i2.exa_action) |
264 | return i1.exa_action > i2.exa_action; |
265 | if (i1.exa_prc_id != i2.exa_prc_id) |
266 | return i1.exa_prc_id > i2.exa_prc_id; |
267 | if (i1.exa_fun_id != i2.exa_fun_id) |
268 | return i1.exa_fun_id > i2.exa_fun_id; |
269 | if (i1.exa_rel_id != i2.exa_rel_id) |
270 | return i1.exa_rel_id > i2.exa_rel_id; |
271 | if (i1.exa_view_id != i2.exa_view_id) |
272 | return i1.exa_view_id > i2.exa_view_id; |
273 | return false; // Equal |
274 | } |
275 | }; |
276 | |
277 | typedef Firebird::SortedArray<ExternalAccess, Firebird::EmptyStorage<ExternalAccess>, |
278 | ExternalAccess, Firebird::DefaultKeyValue<ExternalAccess>, ExternalAccess> ExternalAccessList; |
279 | |
280 | // The three structs below are used for domains DEFAULT and constraints in PSQL |
281 | struct Item |
282 | { |
283 | enum Type |
284 | { |
285 | TYPE_VARIABLE, |
286 | TYPE_PARAMETER, |
287 | TYPE_CAST |
288 | }; |
289 | |
290 | Item(Type aType, UCHAR aSubType, USHORT aIndex) |
291 | : type(aType), |
292 | subType(aSubType), |
293 | index(aIndex) |
294 | { |
295 | } |
296 | |
297 | Item(Type aType, USHORT aIndex = 0) |
298 | : type(aType), |
299 | subType(0), |
300 | index(aIndex) |
301 | { |
302 | } |
303 | |
304 | Type type; |
305 | UCHAR subType; |
306 | USHORT index; |
307 | |
308 | bool operator >(const Item& x) const |
309 | { |
310 | if (type == x.type) |
311 | { |
312 | if (subType == x.subType) |
313 | return index > x.index; |
314 | |
315 | return subType > x.subType; |
316 | } |
317 | |
318 | return type > x.type; |
319 | } |
320 | }; |
321 | |
322 | struct FieldInfo |
323 | { |
324 | FieldInfo() |
325 | : nullable(false), defaultValue(NULL), validationExpr(NULL) |
326 | {} |
327 | |
328 | bool nullable; |
329 | NestConst<ValueExprNode> defaultValue; |
330 | NestConst<BoolExprNode> validationExpr; |
331 | }; |
332 | |
333 | struct ItemInfo |
334 | { |
335 | ItemInfo(MemoryPool& p, const ItemInfo& o) |
336 | : name(p, o.name), |
337 | field(p, o.field), |
338 | nullable(o.nullable), |
339 | explicitCollation(o.explicitCollation), |
340 | fullDomain(o.fullDomain) |
341 | { |
342 | } |
343 | |
344 | explicit ItemInfo(MemoryPool& p) |
345 | : name(p), |
346 | field(p), |
347 | nullable(true), |
348 | explicitCollation(false), |
349 | fullDomain(false) |
350 | { |
351 | } |
352 | |
353 | ItemInfo() |
354 | : name(), |
355 | field(), |
356 | nullable(true), |
357 | explicitCollation(false), |
358 | fullDomain(false) |
359 | { |
360 | } |
361 | |
362 | bool isSpecial() const |
363 | { |
364 | return !nullable || fullDomain; |
365 | } |
366 | |
367 | Firebird::MetaName name; |
368 | Firebird::MetaNamePair field; |
369 | bool nullable; |
370 | bool explicitCollation; |
371 | bool fullDomain; |
372 | }; |
373 | |
374 | struct RseOrExprNode |
375 | { |
376 | RseOrExprNode(ExprNode* aExprNode) |
377 | : exprNode(aExprNode), |
378 | rseNode(NULL) |
379 | { |
380 | } |
381 | |
382 | RseOrExprNode(RseNode* aRseNode) |
383 | : exprNode(NULL), |
384 | rseNode(aRseNode) |
385 | { |
386 | } |
387 | |
388 | ExprNode* exprNode; |
389 | RseNode* rseNode; |
390 | }; |
391 | |
392 | typedef Firebird::GenericMap<Firebird::Pair<Firebird::Left<Firebird::MetaNamePair, FieldInfo> > > |
393 | MapFieldInfo; |
394 | typedef Firebird::GenericMap<Firebird::Pair<Firebird::Right<Item, ItemInfo> > > MapItemInfo; |
395 | |
396 | // Compile scratch block |
397 | |
398 | class CompilerScratch : public pool_alloc<type_csb> |
399 | { |
400 | CompilerScratch(MemoryPool& p, size_t len, const Firebird::MetaName& domain_validation) |
401 | : /*csb_node(0), |
402 | csb_variables(0), |
403 | csb_dependencies(0), |
404 | csb_count(0), |
405 | csb_n_stream(0), |
406 | csb_msg_number(0), |
407 | csb_impure(0), |
408 | csb_g_flags(0),*/ |
409 | #ifdef CMP_DEBUG |
410 | csb_dump(p), |
411 | #endif |
412 | csb_external(p), |
413 | csb_access(p), |
414 | csb_resources(p), |
415 | csb_dependencies(p), |
416 | csb_fors(p), |
417 | csb_invariants(p), |
418 | csb_current_nodes(p), |
419 | csb_pool(p), |
420 | csb_map_field_info(p), |
421 | csb_map_item_info(p), |
422 | csb_message_pad(p), |
423 | csb_domain_validation(domain_validation), |
424 | subFunctions(p), |
425 | subProcedures(p), |
426 | csb_currentForNode(NULL), |
427 | csb_rpt(p, len) |
428 | { |
429 | csb_dbg_info = FB_NEW(p) Firebird::DbgInfo(p); |
430 | } |
431 | |
432 | public: |
433 | struct Dependency |
434 | { |
435 | explicit Dependency(int aObjType) |
436 | { |
437 | memset(this, 0, sizeof(*this)); |
438 | objType = aObjType; |
439 | } |
440 | |
441 | int objType; |
442 | |
443 | union |
444 | { |
445 | jrd_rel* relation; |
446 | const Function* function; |
447 | const jrd_prc* procedure; |
448 | const Firebird::MetaName* name; |
449 | SLONG number; |
450 | }; |
451 | |
452 | const Firebird::MetaName* subName; |
453 | SLONG subNumber; |
454 | }; |
455 | |
456 | static CompilerScratch* newCsb(MemoryPool& p, size_t len, |
457 | const Firebird::MetaName& domain_validation = Firebird::MetaName()) |
458 | { |
459 | return FB_NEW(p) CompilerScratch(p, len, domain_validation); |
460 | } |
461 | |
462 | StreamType nextStream(bool check = true) |
463 | { |
464 | if (csb_n_stream >= MAX_STREAMS && check) |
465 | { |
466 | ERR_post(Firebird::Arg::Gds(isc_too_many_contexts)); |
467 | } |
468 | return csb_n_stream++; |
469 | } |
470 | |
471 | #ifdef CMP_DEBUG |
472 | void dump(const char* format, ...) |
473 | { |
474 | va_list params; |
475 | va_start(params, format); |
476 | |
477 | Firebird::string s; |
478 | s.vprintf(format, params); |
479 | |
480 | va_end(params); |
481 | |
482 | csb_dump += s; |
483 | } |
484 | |
485 | Firebird::string csb_dump; |
486 | #endif |
487 | |
488 | Firebird::BlrReader csb_blr_reader; |
489 | DmlNode* csb_node; |
490 | ExternalAccessList csb_external; // Access to outside procedures/triggers to be checked |
491 | AccessItemList csb_access; // Access items to be checked |
492 | vec<DeclareVariableNode*>* csb_variables; // Vector of variables, if any |
493 | ResourceList csb_resources; // Resources (relations and indexes) |
494 | Firebird::Array<Dependency> csb_dependencies; // objects that this statement depends upon |
495 | Firebird::Array<const RecordSource*> csb_fors; // record sources |
496 | Firebird::Array<ULONG*> csb_invariants; // stack of pointer to nodes invariant offsets |
497 | Firebird::Array<RseOrExprNode> csb_current_nodes; // RseNode's and other invariant |
498 | // candidates within whose scope we are |
499 | StreamType csb_n_stream; // Next available stream |
500 | USHORT csb_msg_number; // Highest used message number |
501 | ULONG csb_impure; // Next offset into impure area |
502 | USHORT csb_g_flags; |
503 | MemoryPool& csb_pool; // Memory pool to be used by csb |
504 | Firebird::AutoPtr<Firebird::DbgInfo> csb_dbg_info; // Debug information |
505 | MapFieldInfo csb_map_field_info; // Map field name to field info |
506 | MapItemInfo csb_map_item_info; // Map item to item info |
507 | |
508 | // Map of message number to field number to pad for external routines. |
509 | Firebird::GenericMap<Firebird::Pair<Firebird::NonPooled<USHORT, USHORT> > > csb_message_pad; |
510 | |
511 | Firebird::MetaName csb_domain_validation; // Parsing domain constraint in PSQL |
512 | |
513 | // used in cmp.cpp/pass1 |
514 | jrd_rel* csb_view; |
515 | StreamType csb_view_stream; |
516 | unsigned blrVersion; |
517 | USHORT csb_remap_variable; |
518 | bool csb_validate_expr; |
519 | bool csb_returning_expr; |
520 | |
521 | Firebird::GenericMap<Firebird::Left<Firebird::MetaName, DeclareSubFuncNode*> > subFunctions; |
522 | Firebird::GenericMap<Firebird::Left<Firebird::MetaName, DeclareSubProcNode*> > subProcedures; |
523 | |
524 | ForNode* csb_currentForNode; |
525 | |
526 | struct csb_repeat |
527 | { |
528 | // We must zero-initialize this one |
529 | csb_repeat(); |
530 | |
531 | void activate(); |
532 | void deactivate(); |
533 | |
534 | StreamType csb_stream; // Map user context to internal stream |
535 | StreamType csb_view_stream; // stream number for view relation, below |
536 | USHORT csb_flags; |
537 | USHORT csb_indices; // Number of indices |
538 | |
539 | jrd_rel* csb_relation; |
540 | Firebird::string* csb_alias; // SQL alias name for this instance of relation |
541 | jrd_prc* csb_procedure; |
542 | jrd_rel* csb_view; // parent view |
543 | |
544 | IndexDescAlloc* csb_idx; // Packed description of indices |
545 | MessageNode* csb_message; // Msg for send/receive |
546 | const Format* csb_format; // Default Format for stream |
547 | Format* csb_internal_format; // Statement internal format |
548 | UInt32Bitmap* csb_fields; // Fields referenced |
549 | double csb_cardinality; // Cardinality of relation |
550 | PlanNode* csb_plan; // user-specified plan for this relation |
551 | StreamType* csb_map; // Stream map for views |
552 | RecordSource** csb_rsb_ptr; // point to rsb for nod_stream |
553 | }; |
554 | |
555 | typedef csb_repeat* rpt_itr; |
556 | typedef const csb_repeat* rpt_const_itr; |
557 | Firebird::HalfStaticArray<csb_repeat, 5> csb_rpt; |
558 | }; |
559 | |
560 | // We must zero-initialize this one |
561 | inline CompilerScratch::csb_repeat::csb_repeat() |
562 | : csb_stream(0), |
563 | csb_view_stream(0), |
564 | csb_flags(0), |
565 | csb_indices(0), |
566 | csb_relation(0), |
567 | csb_alias(0), |
568 | csb_procedure(0), |
569 | csb_view(0), |
570 | csb_idx(0), |
571 | csb_message(0), |
572 | csb_format(0), |
573 | csb_internal_format(0), |
574 | csb_fields(0), |
575 | csb_cardinality(0.0), // TMN: Non-natural cardinality?! |
576 | csb_plan(0), |
577 | csb_map(0), |
578 | csb_rsb_ptr(0) |
579 | { |
580 | } |
581 | |
582 | // CompilerScratch.csb_g_flags' values. |
583 | const int csb_internal = 1; // "csb_g_flag" switch |
584 | const int csb_get_dependencies = 2; // we are retrieving dependencies |
585 | const int csb_ignore_perm = 4; // ignore permissions checks |
586 | //const int csb_blr_version4 = 8; // the BLR is of version 4 |
587 | const int csb_pre_trigger = 16; // this is a BEFORE trigger |
588 | const int csb_post_trigger = 32; // this is an AFTER trigger |
589 | const int csb_validation = 64; // we're in a validation expression (RDB hack) |
590 | const int csb_reuse_context = 128; // allow context reusage |
591 | const int csb_subroutine = 256; // sub routine |
592 | |
593 | // CompilerScratch.csb_rpt[].csb_flags's values. |
594 | const int csb_active = 1; // stream is active |
595 | const int csb_used = 2; // context has already been defined (BLR parsing only) |
596 | const int csb_view_update = 4; // view update w/wo trigger is in progress |
597 | const int csb_trigger = 8; // NEW or OLD context in trigger |
598 | const int csb_no_dbkey = 16; // stream doesn't have a dbkey |
599 | const int csb_store = 32; // we are processing a store statement |
600 | const int csb_modify = 64; // we are processing a modify |
601 | const int csb_sub_stream = 128; // a sub-stream of the RSE being processed |
602 | const int csb_erase = 256; // we are processing an erase |
603 | const int csb_unmatched = 512; // stream has conjuncts unmatched by any index |
604 | const int csb_update = 1024; // erase or modify for relation |
605 | |
606 | inline void CompilerScratch::csb_repeat::activate() |
607 | { |
608 | csb_flags |= csb_active; |
609 | } |
610 | |
611 | inline void CompilerScratch::csb_repeat::deactivate() |
612 | { |
613 | csb_flags &= ~csb_active; |
614 | } |
615 | |
616 | |
617 | class StatusXcp |
618 | { |
619 | ISC_STATUS_ARRAY status; |
620 | |
621 | public: |
622 | StatusXcp(); |
623 | |
624 | void clear(); |
625 | void init(const ISC_STATUS*); |
626 | void copyTo(ISC_STATUS*) const; |
627 | bool success() const; |
628 | SLONG as_gdscode() const; |
629 | SLONG as_sqlcode() const; |
630 | void as_sqlstate(char*) const; |
631 | }; |
632 | |
633 | // must correspond to the declared size of RDB$EXCEPTIONS.RDB$MESSAGE |
634 | const unsigned XCP_MESSAGE_LENGTH = 1023; |
635 | |
636 | } // namespace Jrd |
637 | |
638 | #endif // JRD_EXE_H |
639 | |