mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-31 10:43:02 +01:00
fc12495d0e
1. Never allocate empty statement - always use att->prepare() to create statement interface 2. Separated IStatement into 2 parts - statement itself and resultset. 3. Added stmt->openCursor() (and att->openCursor() for unprepared statements) to create IResultSet. 4. Always use IMessageMetadata (former IParametersMetadata) to pass message fromat info from client, therefore avoiding need in BLR generation in client applications.
650 lines
16 KiB
C++
650 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:
|
|
explicit AggregateSort(Firebird::MemoryPool& p)
|
|
: PermanentStorage(p),
|
|
length(0),
|
|
intl(false),
|
|
impure(0),
|
|
keyItems(p)
|
|
{
|
|
desc.clear();
|
|
}
|
|
|
|
dsc desc;
|
|
USHORT 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;
|
|
};
|
|
|
|
|
|
// index (in CompoundStmtNode) for external routine blr
|
|
const int e_extrout_input_message = 0;
|
|
const int e_extrout_output_message = 1;
|
|
const int e_extrout_input_message2 = 2;
|
|
const int e_extrout_output_message2 = 3;
|
|
const int e_extrout_input_assign = 4;
|
|
const int e_extrout_output_assign = 5;
|
|
|
|
// 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
|
|
jrd_prc* rsc_prc; // Procedure block
|
|
Collation* rsc_coll; // Collation block
|
|
Function* rsc_fun; // Function 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, jrd_prc* prc, Collation* coll)
|
|
: rsc_type(type), rsc_id(id), rsc_rel(rel), rsc_prc(prc), 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_view_id;
|
|
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_view_id != i2.acc_view_id)
|
|
return i1.acc_view_id > i2.acc_view_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_view_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), validationStmt(NULL)
|
|
{}
|
|
|
|
bool nullable;
|
|
NestConst<ValueExprNode> defaultValue;
|
|
NestConst<BoolExprNode> validationExpr;
|
|
NestConst<StmtNode> validationStmt;
|
|
};
|
|
|
|
struct ItemInfo
|
|
{
|
|
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)
|
|
{
|
|
}
|
|
|
|
bool isSpecial() const
|
|
{
|
|
return !nullable || fullDomain;
|
|
}
|
|
|
|
Firebird::MetaName name;
|
|
Firebird::MetaNamePair field;
|
|
bool nullable;
|
|
bool explicitCollation;
|
|
bool fullDomain;
|
|
};
|
|
|
|
struct RseOrExprNode
|
|
{
|
|
RseOrExprNode(ExprNode* aExprNode)
|
|
: exprNode(aExprNode),
|
|
rseNode(NULL)
|
|
{
|
|
}
|
|
|
|
RseOrExprNode(RseNode* aRseNode)
|
|
: exprNode(NULL),
|
|
rseNode(aRseNode)
|
|
{
|
|
}
|
|
|
|
ExprNode* exprNode;
|
|
RseNode* rseNode;
|
|
};
|
|
|
|
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>
|
|
{
|
|
CompilerScratch(MemoryPool& p, size_t len, const Firebird::MetaName& domain_validation)
|
|
: /*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
|
|
csb_external(p),
|
|
csb_access(p),
|
|
csb_resources(p),
|
|
csb_dependencies(p),
|
|
csb_fors(p),
|
|
csb_invariants(p),
|
|
csb_current_nodes(p),
|
|
csb_pool(p),
|
|
csb_map_field_info(p),
|
|
csb_map_item_info(p),
|
|
csb_message_pad(p),
|
|
csb_domain_validation(domain_validation),
|
|
subFunctions(p),
|
|
subProcedures(p),
|
|
csb_currentForNode(NULL),
|
|
csb_rpt(p, len)
|
|
{
|
|
csb_dbg_info = FB_NEW(p) Firebird::DbgInfo(p);
|
|
}
|
|
|
|
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;
|
|
};
|
|
|
|
static CompilerScratch* newCsb(MemoryPool& p, size_t len,
|
|
const Firebird::MetaName& domain_validation = Firebird::MetaName())
|
|
{
|
|
return FB_NEW(p) CompilerScratch(p, len, domain_validation);
|
|
}
|
|
|
|
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
|
|
|
|
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<ULONG*> csb_invariants; // stack of pointer to nodes invariant offsets
|
|
Firebird::Array<RseOrExprNode> csb_current_nodes; // RseNode's and other invariant
|
|
// candidates within whose scope we are
|
|
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;
|
|
unsigned blrVersion;
|
|
bool csb_validate_expr;
|
|
USHORT csb_remap_variable;
|
|
|
|
Firebird::GenericMap<Firebird::Left<Firebird::MetaName, DeclareSubFuncNode*> > subFunctions;
|
|
Firebird::GenericMap<Firebird::Left<Firebird::MetaName, DeclareSubProcNode*> > subProcedures;
|
|
|
|
ForNode* csb_currentForNode;
|
|
|
|
struct csb_repeat
|
|
{
|
|
// We must zero-initialize this one
|
|
csb_repeat();
|
|
|
|
void activate();
|
|
void deactivate();
|
|
|
|
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
|
|
{
|
|
ISC_STATUS_ARRAY status;
|
|
|
|
public:
|
|
StatusXcp();
|
|
|
|
void clear();
|
|
void init(const ISC_STATUS*);
|
|
void copyTo(ISC_STATUS*) const;
|
|
bool success() const;
|
|
SLONG as_gdscode() const;
|
|
SLONG as_sqlcode() const;
|
|
void as_sqlstate(char*) const;
|
|
};
|
|
|
|
// must correspond to the size of RDB$EXCEPTIONS.RDB$MESSAGE
|
|
// minus size of vary::vary_length (USHORT) since RDB$MESSAGE
|
|
// declared as varchar
|
|
const int XCP_MESSAGE_LENGTH = 1023 - sizeof(USHORT);
|
|
|
|
} // namespace Jrd
|
|
|
|
#endif // JRD_EXE_H
|