8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-25 00:03:03 +01:00
firebird-mirror/src/jrd/exe.h

649 lines
16 KiB
C++

/*
* PROGRAM: JRD Access Method
* MODULE: exe.h
* DESCRIPTION: Execution block definitions
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2001.07.28: Added rse_skip to class RecordSelExpr to support LIMIT.
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
* 2002.10.21 Nickolay Samofatov: Added support for explicit pessimistic locks
* 2002.10.29 Nickolay Samofatov: Added support for savepoints
* Adriano dos Santos Fernandes
*/
#ifndef JRD_EXE_H
#define JRD_EXE_H
#include "../jrd/blb.h"
#include "../jrd/Relation.h"
#include "../common/classes/array.h"
#include "../common/classes/MetaName.h"
#include "../common/classes/NestConst.h"
#include "gen/iberror.h"
#include "../common/dsc.h"
#include "../jrd/rse.h"
#include "../jrd/err_proto.h"
#include "../jrd/scl.h"
#include "../jrd/sbm.h"
#include "../jrd/sort.h"
#include "../jrd/DebugInterface.h"
#include "../common/classes/BlrReader.h"
#include "../dsql/Nodes.h"
#include "../dsql/Visitors.h"
// This macro enables DSQL tracing code
//#define CMP_DEBUG
#ifdef CMP_DEBUG
DEFINE_TRACE_ROUTINE(cmp_trace);
#define CMP_TRACE(args) cmp_trace args
#else
#define CMP_TRACE(args) // nothing
#endif
class VaryingString;
struct dsc;
namespace Jrd {
class jrd_rel;
class Sort;
struct sort_key_def;
template <typename T> class vec;
class jrd_prc;
class Collation;
struct index_desc;
struct IndexDescAlloc;
class Format;
class ForNode;
class Cursor;
class DeclareSubFuncNode;
class DeclareSubProcNode;
class DeclareVariableNode;
class MessageNode;
class PlanNode;
class RecordSource;
// Types of nulls placement for each column in sort order
const int rse_nulls_default = 0;
const int rse_nulls_first = 1;
const int rse_nulls_last = 2;
// Aggregate Sort Block (for DISTINCT aggregates)
class AggregateSort : protected Firebird::PermanentStorage, public Printable
{
public:
explicit AggregateSort(Firebird::MemoryPool& p)
: PermanentStorage(p),
length(0),
intl(false),
impure(0),
keyItems(p)
{
desc.clear();
}
public:
virtual Firebird::string internalPrint(NodePrinter& printer) const
{
return "AggregateSort";
}
public:
dsc desc;
ULONG length;
bool intl;
ULONG impure;
Firebird::HalfStaticArray<sort_key_def, 2> keyItems;
};
// Inversion (i.e. nod_index) impure area
struct impure_inversion
{
RecordBitmap* inv_bitmap;
};
// AggregateSort impure area
struct impure_agg_sort
{
Sort* iasb_sort;
ULONG iasb_dummy;
};
// Request resources
struct Resource
{
enum rsc_s
{
rsc_relation,
rsc_procedure,
rsc_index,
rsc_collation,
rsc_function
};
rsc_s rsc_type;
USHORT rsc_id; // Id of the resource
jrd_rel* rsc_rel; // Relation block
Routine* rsc_routine; // Routine block
Collation* rsc_coll; // Collation block
static bool greaterThan(const Resource& i1, const Resource& i2)
{
// A few places of the engine depend on fact that rsc_type
// is the first field in ResourceList ordering
if (i1.rsc_type != i2.rsc_type)
return i1.rsc_type > i2.rsc_type;
if (i1.rsc_type == rsc_index)
{
// Sort by relation ID for now
if (i1.rsc_rel->rel_id != i2.rsc_rel->rel_id)
return i1.rsc_rel->rel_id > i2.rsc_rel->rel_id;
}
return i1.rsc_id > i2.rsc_id;
}
Resource(rsc_s type, USHORT id, jrd_rel* rel, Routine* routine, Collation* coll)
: rsc_type(type), rsc_id(id), rsc_rel(rel), rsc_routine(routine), rsc_coll(coll)
{ }
};
typedef Firebird::SortedArray<Resource, Firebird::EmptyStorage<Resource>,
Resource, Firebird::DefaultKeyValue<Resource>, Resource> ResourceList;
// Access items
// In case we start to use MetaName with required pool parameter,
// access item to be reworked!
// This struct seems better located in scl.h.
struct AccessItem
{
Firebird::MetaName acc_security_name;
SLONG acc_ss_rel_id; // Relation Id which owner will be used to check permissions
Firebird::MetaName acc_name, acc_r_name;
SLONG acc_type;
SecurityClass::flags_t acc_mask;
static bool greaterThan(const AccessItem& i1, const AccessItem& i2)
{
int v;
/* CVC: Disabled this horrible hack.
// Relations and procedures should be sorted before
// columns, hence such a tricky inverted condition
if ((v = -strcmp(i1.acc_type, i2.acc_type)) != 0)
return v > 0;
*/
if (i1.acc_type != i2.acc_type)
return i1.acc_type > i2.acc_type;
if ((v = i1.acc_security_name.compare(i2.acc_security_name)) != 0)
return v > 0;
if (i1.acc_ss_rel_id != i2.acc_ss_rel_id)
return i1.acc_ss_rel_id > i2.acc_ss_rel_id;
if (i1.acc_mask != i2.acc_mask)
return i1.acc_mask > i2.acc_mask;
if ((v = i1.acc_name.compare(i2.acc_name)) != 0)
return v > 0;
if ((v = i1.acc_r_name.compare(i2.acc_r_name)) != 0)
return v > 0;
return false; // Equal
}
AccessItem(const Firebird::MetaName& security_name, SLONG view_id,
const Firebird::MetaName& name, SLONG type,
SecurityClass::flags_t mask, const Firebird::MetaName& relName)
: acc_security_name(security_name), acc_ss_rel_id(view_id), acc_name(name),
acc_r_name(relName), acc_type(type), acc_mask(mask)
{}
};
typedef Firebird::SortedArray<AccessItem, Firebird::EmptyStorage<AccessItem>,
AccessItem, Firebird::DefaultKeyValue<AccessItem>, AccessItem> AccessItemList;
// Triggers and procedures the request accesses
struct ExternalAccess
{
enum exa_act
{
exa_procedure,
exa_function,
exa_insert,
exa_update,
exa_delete
};
exa_act exa_action;
USHORT exa_prc_id;
USHORT exa_fun_id;
USHORT exa_rel_id;
USHORT exa_view_id;
// Procedure
ExternalAccess(exa_act action, USHORT id) :
exa_action(action),
exa_prc_id(action == exa_procedure ? id : 0),
exa_fun_id(action == exa_function ? id : 0),
exa_rel_id(0), exa_view_id(0)
{ }
// Trigger
ExternalAccess(exa_act action, USHORT rel_id, USHORT view_id) :
exa_action(action), exa_prc_id(0), exa_fun_id(0),
exa_rel_id(rel_id), exa_view_id(view_id)
{ }
static bool greaterThan(const ExternalAccess& i1, const ExternalAccess& i2)
{
if (i1.exa_action != i2.exa_action)
return i1.exa_action > i2.exa_action;
if (i1.exa_prc_id != i2.exa_prc_id)
return i1.exa_prc_id > i2.exa_prc_id;
if (i1.exa_fun_id != i2.exa_fun_id)
return i1.exa_fun_id > i2.exa_fun_id;
if (i1.exa_rel_id != i2.exa_rel_id)
return i1.exa_rel_id > i2.exa_rel_id;
if (i1.exa_view_id != i2.exa_view_id)
return i1.exa_view_id > i2.exa_view_id;
return false; // Equal
}
};
typedef Firebird::SortedArray<ExternalAccess, Firebird::EmptyStorage<ExternalAccess>,
ExternalAccess, Firebird::DefaultKeyValue<ExternalAccess>, ExternalAccess> ExternalAccessList;
// The three structs below are used for domains DEFAULT and constraints in PSQL
struct Item
{
enum Type
{
TYPE_VARIABLE,
TYPE_PARAMETER,
TYPE_CAST
};
Item(Type aType, UCHAR aSubType, USHORT aIndex)
: type(aType),
subType(aSubType),
index(aIndex)
{
}
Item(Type aType, USHORT aIndex = 0)
: type(aType),
subType(0),
index(aIndex)
{
}
Type type;
UCHAR subType;
USHORT index;
bool operator >(const Item& x) const
{
if (type == x.type)
{
if (subType == x.subType)
return index > x.index;
return subType > x.subType;
}
return type > x.type;
}
};
struct FieldInfo
{
FieldInfo()
: nullable(false), defaultValue(NULL), validationExpr(NULL)
{}
bool nullable;
NestConst<ValueExprNode> defaultValue;
NestConst<BoolExprNode> validationExpr;
};
class ItemInfo : public Printable
{
public:
ItemInfo(MemoryPool& p, const ItemInfo& o)
: name(p, o.name),
field(p, o.field),
nullable(o.nullable),
explicitCollation(o.explicitCollation),
fullDomain(o.fullDomain)
{
}
explicit ItemInfo(MemoryPool& p)
: name(p),
field(p),
nullable(true),
explicitCollation(false),
fullDomain(false)
{
}
ItemInfo()
: name(),
field(),
nullable(true),
explicitCollation(false),
fullDomain(false)
{
}
public:
bool isSpecial() const
{
return !nullable || fullDomain;
}
virtual Firebird::string internalPrint(NodePrinter& printer) const
{
/*** FIXME-PRINT:
NODE_PRINT(printer, name);
NODE_PRINT(printer, field);
NODE_PRINT(printer, nullable);
NODE_PRINT(printer, explicitCollation);
NODE_PRINT(printer, fullDomain);
***/
return "ItemInfo";
}
public:
Firebird::MetaName name;
Firebird::MetaNamePair field;
bool nullable;
bool explicitCollation;
bool fullDomain;
};
typedef Firebird::GenericMap<Firebird::Pair<Firebird::Left<Firebird::MetaNamePair, FieldInfo> > >
MapFieldInfo;
typedef Firebird::GenericMap<Firebird::Pair<Firebird::Right<Item, ItemInfo> > > MapItemInfo;
// Compile scratch block
class CompilerScratch : public pool_alloc<type_csb>
{
public:
struct Dependency
{
explicit Dependency(int aObjType)
{
memset(this, 0, sizeof(*this));
objType = aObjType;
}
int objType;
union
{
jrd_rel* relation;
const Function* function;
const jrd_prc* procedure;
const Firebird::MetaName* name;
SLONG number;
};
const Firebird::MetaName* subName;
SLONG subNumber;
};
explicit CompilerScratch(MemoryPool& p, CompilerScratch* aMainCsb = NULL)
: /*csb_node(0),
csb_variables(0),
csb_dependencies(0),
csb_count(0),
csb_n_stream(0),
csb_msg_number(0),
csb_impure(0),
csb_g_flags(0),*/
#ifdef CMP_DEBUG
csb_dump(p),
#endif
mainCsb(aMainCsb),
csb_external(p),
csb_access(p),
csb_resources(p),
csb_dependencies(p),
csb_fors(p),
csb_cursors(p),
csb_invariants(p),
csb_current_nodes(p),
csb_computing_fields(p),
csb_pool(p),
csb_map_field_info(p),
csb_map_item_info(p),
csb_message_pad(p),
subFunctions(p),
subProcedures(p),
csb_currentForNode(NULL),
csb_currentDMLNode(NULL),
csb_rpt(p)
{
csb_dbg_info = FB_NEW_POOL(p) Firebird::DbgInfo(p);
}
StreamType nextStream(bool check = true)
{
if (csb_n_stream >= MAX_STREAMS && check)
ERR_post(Firebird::Arg::Gds(isc_too_many_contexts));
return csb_n_stream++;
}
#ifdef CMP_DEBUG
void dump(const char* format, ...)
{
va_list params;
va_start(params, format);
Firebird::string s;
s.vprintf(format, params);
va_end(params);
csb_dump += s;
}
Firebird::string csb_dump;
#endif
CompilerScratch* mainCsb;
Firebird::BlrReader csb_blr_reader;
DmlNode* csb_node;
ExternalAccessList csb_external; // Access to outside procedures/triggers to be checked
AccessItemList csb_access; // Access items to be checked
vec<DeclareVariableNode*>* csb_variables; // Vector of variables, if any
ResourceList csb_resources; // Resources (relations and indexes)
Firebird::Array<Dependency> csb_dependencies; // objects that this statement depends upon
Firebird::Array<const RecordSource*> csb_fors; // record sources
Firebird::Array<const Cursor*> csb_cursors; // named cursors
Firebird::Array<ULONG*> csb_invariants; // stack of pointer to nodes invariant offsets
Firebird::Array<ExprNode*> csb_current_nodes; // RseNode's and other invariant
// candidates within whose scope we are
Firebird::SortedArray<jrd_fld*> csb_computing_fields; // Computed fields being compiled
StreamType csb_n_stream; // Next available stream
USHORT csb_msg_number; // Highest used message number
ULONG csb_impure; // Next offset into impure area
USHORT csb_g_flags;
MemoryPool& csb_pool; // Memory pool to be used by csb
Firebird::AutoPtr<Firebird::DbgInfo> csb_dbg_info; // Debug information
MapFieldInfo csb_map_field_info; // Map field name to field info
MapItemInfo csb_map_item_info; // Map item to item info
// Map of message number to field number to pad for external routines.
Firebird::GenericMap<Firebird::Pair<Firebird::NonPooled<USHORT, USHORT> > > csb_message_pad;
Firebird::MetaName csb_domain_validation; // Parsing domain constraint in PSQL
// used in cmp.cpp/pass1
jrd_rel* csb_view;
StreamType csb_view_stream;
jrd_rel* csb_parent_relation;
unsigned blrVersion;
USHORT csb_remap_variable;
bool csb_validate_expr;
bool csb_returning_expr;
Firebird::GenericMap<Firebird::Left<Firebird::MetaName, DeclareSubFuncNode*> > subFunctions;
Firebird::GenericMap<Firebird::Left<Firebird::MetaName, DeclareSubProcNode*> > subProcedures;
ForNode* csb_currentForNode;
StmtNode* csb_currentDMLNode; // could be StoreNode or ModifyNode
struct csb_repeat
{
// We must zero-initialize this one
csb_repeat();
void activate();
void deactivate();
Nullable<USHORT> csb_cursor_number; // Cursor number for this stream
StreamType csb_stream; // Map user context to internal stream
StreamType csb_view_stream; // stream number for view relation, below
USHORT csb_flags;
USHORT csb_indices; // Number of indices
jrd_rel* csb_relation;
Firebird::string* csb_alias; // SQL alias name for this instance of relation
jrd_prc* csb_procedure;
jrd_rel* csb_view; // parent view
IndexDescAlloc* csb_idx; // Packed description of indices
MessageNode* csb_message; // Msg for send/receive
const Format* csb_format; // Default Format for stream
Format* csb_internal_format; // Statement internal format
UInt32Bitmap* csb_fields; // Fields referenced
double csb_cardinality; // Cardinality of relation
PlanNode* csb_plan; // user-specified plan for this relation
StreamType* csb_map; // Stream map for views
RecordSource** csb_rsb_ptr; // point to rsb for nod_stream
};
typedef csb_repeat* rpt_itr;
typedef const csb_repeat* rpt_const_itr;
Firebird::HalfStaticArray<csb_repeat, 5> csb_rpt;
};
// We must zero-initialize this one
inline CompilerScratch::csb_repeat::csb_repeat()
: csb_stream(0),
csb_view_stream(0),
csb_flags(0),
csb_indices(0),
csb_relation(0),
csb_alias(0),
csb_procedure(0),
csb_view(0),
csb_idx(0),
csb_message(0),
csb_format(0),
csb_internal_format(0),
csb_fields(0),
csb_cardinality(0.0), // TMN: Non-natural cardinality?!
csb_plan(0),
csb_map(0),
csb_rsb_ptr(0)
{
}
// CompilerScratch.csb_g_flags' values.
const int csb_internal = 1; // "csb_g_flag" switch
const int csb_get_dependencies = 2; // we are retrieving dependencies
const int csb_ignore_perm = 4; // ignore permissions checks
//const int csb_blr_version4 = 8; // the BLR is of version 4
const int csb_pre_trigger = 16; // this is a BEFORE trigger
const int csb_post_trigger = 32; // this is an AFTER trigger
const int csb_validation = 64; // we're in a validation expression (RDB hack)
const int csb_reuse_context = 128; // allow context reusage
const int csb_subroutine = 256; // sub routine
// CompilerScratch.csb_rpt[].csb_flags's values.
const int csb_active = 1; // stream is active
const int csb_used = 2; // context has already been defined (BLR parsing only)
const int csb_view_update = 4; // view update w/wo trigger is in progress
const int csb_trigger = 8; // NEW or OLD context in trigger
const int csb_no_dbkey = 16; // stream doesn't have a dbkey
const int csb_store = 32; // we are processing a store statement
const int csb_modify = 64; // we are processing a modify
const int csb_sub_stream = 128; // a sub-stream of the RSE being processed
const int csb_erase = 256; // we are processing an erase
const int csb_unmatched = 512; // stream has conjuncts unmatched by any index
const int csb_update = 1024; // erase or modify for relation
inline void CompilerScratch::csb_repeat::activate()
{
csb_flags |= csb_active;
}
inline void CompilerScratch::csb_repeat::deactivate()
{
csb_flags &= ~csb_active;
}
class StatusXcp
{
FbLocalStatus status;
public:
StatusXcp();
void clear();
void init(const Jrd::FbStatusVector*);
void copyTo(Jrd::FbStatusVector*) const;
bool success() const;
SLONG as_gdscode() const;
SLONG as_sqlcode() const;
void as_sqlstate(char*) const;
SLONG as_xcpcode() const;
Firebird::string as_text() const;
};
// must correspond to the declared size of RDB$EXCEPTIONS.RDB$MESSAGE
const unsigned XCP_MESSAGE_LENGTH = 1023;
} // namespace Jrd
#endif // JRD_EXE_H