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
60DEFINE_TRACE_ROUTINE(cmp_trace);
61#define CMP_TRACE(args) cmp_trace args
62#else
63#define CMP_TRACE(args) // nothing
64#endif
65
66class VaryingString;
67struct dsc;
68
69namespace Jrd {
70
71class jrd_rel;
72class Sort;
73struct sort_key_def;
74template <typename T> class vec;
75class jrd_prc;
76class Collation;
77struct index_desc;
78struct IndexDescAlloc;
79class Format;
80class ForNode;
81class Cursor;
82class DeclareSubFuncNode;
83class DeclareSubProcNode;
84class DeclareVariableNode;
85class MessageNode;
86class PlanNode;
87class RecordSource;
88
89// Types of nulls placement for each column in sort order
90const int rse_nulls_default = 0;
91const int rse_nulls_first = 1;
92const int rse_nulls_last = 2;
93
94
95// Aggregate Sort Block (for DISTINCT aggregates)
96
97class AggregateSort : protected Firebird::PermanentStorage
98{
99public:
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
119struct impure_inversion
120{
121 RecordBitmap* inv_bitmap;
122};
123
124
125// AggregateSort impure area
126
127struct impure_agg_sort
128{
129 Sort* iasb_sort;
130};
131
132
133// Request resources
134
135struct 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
172typedef 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
180struct 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
227typedef Firebird::SortedArray<AccessItem, Firebird::EmptyStorage<AccessItem>,
228 AccessItem, Firebird::DefaultKeyValue<AccessItem>, AccessItem> AccessItemList;
229
230// Triggers and procedures the request accesses
231struct 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
277typedef 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
281struct 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
322struct 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
333struct 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
374struct 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
392typedef Firebird::GenericMap<Firebird::Pair<Firebird::Left<Firebird::MetaNamePair, FieldInfo> > >
393 MapFieldInfo;
394typedef Firebird::GenericMap<Firebird::Pair<Firebird::Right<Item, ItemInfo> > > MapItemInfo;
395
396// Compile scratch block
397
398class 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
432public:
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
561inline 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.
583const int csb_internal = 1; // "csb_g_flag" switch
584const int csb_get_dependencies = 2; // we are retrieving dependencies
585const int csb_ignore_perm = 4; // ignore permissions checks
586//const int csb_blr_version4 = 8; // the BLR is of version 4
587const int csb_pre_trigger = 16; // this is a BEFORE trigger
588const int csb_post_trigger = 32; // this is an AFTER trigger
589const int csb_validation = 64; // we're in a validation expression (RDB hack)
590const int csb_reuse_context = 128; // allow context reusage
591const int csb_subroutine = 256; // sub routine
592
593// CompilerScratch.csb_rpt[].csb_flags's values.
594const int csb_active = 1; // stream is active
595const int csb_used = 2; // context has already been defined (BLR parsing only)
596const int csb_view_update = 4; // view update w/wo trigger is in progress
597const int csb_trigger = 8; // NEW or OLD context in trigger
598const int csb_no_dbkey = 16; // stream doesn't have a dbkey
599const int csb_store = 32; // we are processing a store statement
600const int csb_modify = 64; // we are processing a modify
601const int csb_sub_stream = 128; // a sub-stream of the RSE being processed
602const int csb_erase = 256; // we are processing an erase
603const int csb_unmatched = 512; // stream has conjuncts unmatched by any index
604const int csb_update = 1024; // erase or modify for relation
605
606inline void CompilerScratch::csb_repeat::activate()
607{
608 csb_flags |= csb_active;
609}
610
611inline void CompilerScratch::csb_repeat::deactivate()
612{
613 csb_flags &= ~csb_active;
614}
615
616
617class StatusXcp
618{
619 ISC_STATUS_ARRAY status;
620
621public:
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
634const unsigned XCP_MESSAGE_LENGTH = 1023;
635
636} // namespace Jrd
637
638#endif // JRD_EXE_H
639