mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 09:20:39 +01:00
Use the BLR message definition of external procedures and functions.
This commit is contained in:
parent
4301830af3
commit
cd7c8dee95
@ -289,7 +289,7 @@ public:
|
||||
blrLength = 0;
|
||||
blr = blrPos = new ISC_UCHAR[sizeof(HEADER) + 10 * itemCount + 2];
|
||||
bufferLength = 0;
|
||||
buffer = (ISC_UCHAR*) aBuffer;
|
||||
buffer = static_cast<ISC_UCHAR*>(aBuffer);
|
||||
|
||||
memcpy(blrPos, HEADER, sizeof(HEADER));
|
||||
blrPos += sizeof(HEADER);
|
||||
@ -795,6 +795,7 @@ FB_UDR_BEGIN_PROCEDURE(inc)
|
||||
FB_UDR_END_PROCEDURE
|
||||
|
||||
|
||||
//// TODO: Rework triggers.
|
||||
/***
|
||||
Sample usage:
|
||||
|
||||
|
@ -1462,6 +1462,10 @@ C --
|
||||
PARAMETER (GDS__sysf_argscant_both_be_zero = 335545024)
|
||||
INTEGER*4 GDS__spb_no_id
|
||||
PARAMETER (GDS__spb_no_id = 335545025)
|
||||
INTEGER*4 GDS__ee_blr_mismatch_null
|
||||
PARAMETER (GDS__ee_blr_mismatch_null = 335545026)
|
||||
INTEGER*4 GDS__ee_blr_mismatch_length
|
||||
PARAMETER (GDS__ee_blr_mismatch_length = 335545027)
|
||||
INTEGER*4 GDS__gfix_db_name
|
||||
PARAMETER (GDS__gfix_db_name = 335740929)
|
||||
INTEGER*4 GDS__gfix_invalid_sw
|
||||
|
@ -738,6 +738,8 @@ const
|
||||
gds_invalid_boolean_usage = 335545023;
|
||||
gds_sysf_argscant_both_be_zero = 335545024;
|
||||
gds_spb_no_id = 335545025;
|
||||
gds_ee_blr_mismatch_null = 335545026;
|
||||
gds_ee_blr_mismatch_length = 335545027;
|
||||
gds_gfix_db_name = 335740929;
|
||||
gds_gfix_invalid_sw = 335740930;
|
||||
gds_gfix_incmp_sw = 335740932;
|
||||
|
@ -1448,7 +1448,7 @@ void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch
|
||||
ARG.RDB$COLLATION_ID.NULL = TRUE;
|
||||
|
||||
ARG.RDB$ARGUMENT_MECHANISM.NULL = FALSE;
|
||||
ARG.RDB$ARGUMENT_MECHANISM = (USHORT) (parameter.fullDomain || parameter.typeOfName.isEmpty() ?
|
||||
ARG.RDB$ARGUMENT_MECHANISM = (USHORT) (parameter.fullDomain ?
|
||||
prm_mech_normal : prm_mech_type_of);
|
||||
|
||||
if (parameter.notNull)
|
||||
@ -2226,7 +2226,7 @@ void CreateAlterProcedureNode::storeParameter(thread_db* tdbb, DsqlCompilerScrat
|
||||
PRM.RDB$PARAMETER_TYPE = type;
|
||||
|
||||
PRM.RDB$PARAMETER_MECHANISM.NULL = FALSE;
|
||||
PRM.RDB$PARAMETER_MECHANISM = (USHORT) (parameter.fullDomain || parameter.typeOfName.isEmpty() ?
|
||||
PRM.RDB$PARAMETER_MECHANISM = (USHORT) (parameter.fullDomain ?
|
||||
prm_mech_normal : prm_mech_type_of);
|
||||
|
||||
PRM.RDB$NULL_FLAG.NULL = !parameter.notNull;
|
||||
|
@ -43,6 +43,14 @@ class ExternalEngine;
|
||||
const int EXTERNAL_VERSION_1 = 1;
|
||||
|
||||
|
||||
struct BlrMessage
|
||||
{
|
||||
const unsigned char* blr;
|
||||
unsigned int blrLength;
|
||||
unsigned int bufferLength;
|
||||
};
|
||||
|
||||
|
||||
// Connection to current database in external engine.
|
||||
// Context passed to ExternalEngine has SYSDBA privileges.
|
||||
// Context passed to ExternalFunction, ExternalProcedure and ExternalTrigger
|
||||
@ -97,7 +105,7 @@ public:
|
||||
Utf8* name, uint nameSize) = 0;
|
||||
|
||||
virtual void FB_CALL execute(Error* error, ExternalContext* context,
|
||||
UCHAR* inMsg, UCHAR* outMsg) = 0;
|
||||
void* inMsg, void* outMsg) = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -114,7 +122,7 @@ public:
|
||||
// Returning NULL results in a result set of one record.
|
||||
// Procedures without output parameters should return NULL.
|
||||
virtual ExternalResultSet* FB_CALL open(Error* error, ExternalContext* context,
|
||||
UCHAR* inMsg, UCHAR* outMsg) = 0;
|
||||
void* inMsg, void* outMsg) = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -149,7 +157,7 @@ public:
|
||||
Utf8* name, uint nameSize) = 0;
|
||||
|
||||
virtual void FB_CALL execute(Error* error, ExternalContext* context,
|
||||
Action action, UCHAR* oldMsg, UCHAR* newMsg) = 0;
|
||||
Action action, void* oldMsg, void* newMsg) = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -192,9 +200,9 @@ public:
|
||||
// Called when engine wants to load object in the cache. Objects are disposed when
|
||||
// going out of the cache.
|
||||
virtual ExternalFunction* FB_CALL makeFunction(Error* error, ExternalContext* context,
|
||||
const IRoutineMetadata* metadata) = 0;
|
||||
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
|
||||
virtual ExternalProcedure* FB_CALL makeProcedure(Error* error, ExternalContext* context,
|
||||
const IRoutineMetadata* metadata) = 0;
|
||||
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
|
||||
virtual ExternalTrigger* FB_CALL makeTrigger(Error* error, ExternalContext* context,
|
||||
const IRoutineMetadata* metadata) = 0;
|
||||
};
|
||||
|
@ -37,8 +37,7 @@
|
||||
#define FB_MESSAGE_I(name, fields) \
|
||||
struct name \
|
||||
{ \
|
||||
/* TODO: use it */ \
|
||||
static const unsigned char* BLR() \
|
||||
static const unsigned char* getBlr(unsigned* length) \
|
||||
{ \
|
||||
static const unsigned char blr[] = { \
|
||||
blr_version5, \
|
||||
@ -50,10 +49,11 @@
|
||||
blr_end, \
|
||||
blr_eoc \
|
||||
}; \
|
||||
*length = sizeof(blr); \
|
||||
return blr; \
|
||||
} \
|
||||
\
|
||||
static unsigned SIZE() \
|
||||
static unsigned getSize() \
|
||||
{ \
|
||||
return (unsigned)(size_t) (&((name*) 0)->FB_BOOST_PP_CAT( \
|
||||
FB_BOOST_PP_TUPLE_ELEM(2, 1, \
|
||||
@ -79,7 +79,7 @@
|
||||
#define FB_BLR_FB_SMALLINT FB_BLR_FB_SCALED_SMALLINT(0)
|
||||
#define FB_BLR_FB_INTEGER FB_BLR_FB_SCALED_INTEGER(0)
|
||||
#define FB_BLR_FB_BIGINT FB_BLR_FB_SCALED_BIGINT(0)
|
||||
#define FB_BLR_FB_VARCHAR(len) blr_varying, (len) & 0xFF, (len) >> 8
|
||||
#define FB_BLR_FB_VARCHAR(len) blr_varying2, 0, 0, (len) & 0xFF, (len) >> 8
|
||||
|
||||
#define FB_TYPE_FB_SCALED_SMALLINT(x) ISC_SHORT
|
||||
#define FB_TYPE_FB_SCALED_INTEGER(x) ISC_LONG
|
||||
@ -87,7 +87,7 @@
|
||||
#define FB_TYPE_FB_SMALLINT ISC_SHORT
|
||||
#define FB_TYPE_FB_INTEGER ISC_LONG
|
||||
#define FB_TYPE_FB_BIGINT ISC_INT64
|
||||
#define FB_TYPE_FB_VARCHAR(len) FbVarChar<(len)>
|
||||
#define FB_TYPE_FB_VARCHAR(len) ::Firebird::FbVarChar<(len)>
|
||||
|
||||
|
||||
namespace Firebird {
|
||||
|
@ -75,7 +75,7 @@ namespace Firebird
|
||||
|
||||
#define FB_UDR_EXECUTE__FUNCTION \
|
||||
virtual void FB_CALL execute(::Firebird::Error* error, ::Firebird::ExternalContext* context, \
|
||||
UCHAR* inMsg, UCHAR* outMsg) \
|
||||
void* inMsg, void* outMsg) \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
@ -131,7 +131,7 @@ namespace Firebird
|
||||
|
||||
#define FB_UDR_EXECUTE__PROCEDURE \
|
||||
virtual ::Firebird::ExternalResultSet* FB_CALL open(::Firebird::Error* error, \
|
||||
::Firebird::ExternalContext* context, UCHAR* inMsg, UCHAR* outMsg) \
|
||||
::Firebird::ExternalContext* context, void* inMsg, void* outMsg) \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
@ -192,7 +192,7 @@ namespace Firebird
|
||||
{ \
|
||||
public: \
|
||||
virtual void FB_CALL execute(::Firebird::Error* error, ::Firebird::ExternalContext* context, \
|
||||
::Firebird::ExternalTrigger::Action action, UCHAR* oldMsg, UCHAR* newMsg);
|
||||
::Firebird::ExternalTrigger::Action action, void* oldMsg, void* newMsg);
|
||||
|
||||
#define FB_UDR_END_DECLARE_TRIGGER(name) \
|
||||
};
|
||||
@ -204,7 +204,7 @@ namespace Firebird
|
||||
#define FB_UDR_BEGIN_TRIGGER(name) \
|
||||
void FB_CALL FB_UDR_TRIGGER(name)::execute(::Firebird::Error* error, \
|
||||
::Firebird::ExternalContext* context, ::Firebird::ExternalTrigger::Action action, \
|
||||
UCHAR* oldMsg, UCHAR* newMsg) \
|
||||
void* oldMsg, void* newMsg) \
|
||||
{ \
|
||||
try \
|
||||
{
|
||||
@ -459,11 +459,6 @@ public:
|
||||
ThrowError::check(status);
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void* getEntryPoint(ExternalContext* /*context*/, const char* entryPoint)
|
||||
{
|
||||
return fbUdrGetFunction(entryPoint);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -602,16 +597,15 @@ public:
|
||||
template <typename T> class FunctionFactoryImpl : public FunctionFactory
|
||||
{
|
||||
public:
|
||||
explicit FunctionFactoryImpl(const char* aName)
|
||||
: name(aName)
|
||||
explicit FunctionFactoryImpl(const char* name)
|
||||
{
|
||||
fbUdrRegFunction(this);
|
||||
fbUdrRegFunction(name, this);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual const char* FB_CALL getName()
|
||||
virtual void setup(const IRoutineMetadata* /*metadata*/, BlrMessage* inBlr, BlrMessage* outBlr)
|
||||
{
|
||||
return name;
|
||||
setBlr(inBlr, (typename T::InMessage*) 0);
|
||||
setBlr(outBlr, (typename T::OutMessage*) 0);
|
||||
}
|
||||
|
||||
virtual ExternalFunction* FB_CALL newItem(const IRoutineMetadata* metadata)
|
||||
@ -620,23 +614,30 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
const char* name;
|
||||
template <typename MessageType> void setBlr(BlrMessage* blrMessage, MessageType*)
|
||||
{
|
||||
blrMessage->blr = MessageType::getBlr(&blrMessage->blrLength);
|
||||
blrMessage->bufferLength = MessageType::getSize();
|
||||
}
|
||||
|
||||
void setBlr(BlrMessage* blrMessage, void**)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T> class ProcedureFactoryImpl : public ProcedureFactory
|
||||
{
|
||||
public:
|
||||
explicit ProcedureFactoryImpl(const char* aName)
|
||||
: name(aName)
|
||||
explicit ProcedureFactoryImpl(const char* name)
|
||||
{
|
||||
fbUdrRegProcedure(this);
|
||||
fbUdrRegProcedure(name, this);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual const char* FB_CALL getName()
|
||||
virtual void setup(const IRoutineMetadata* /*metadata*/, BlrMessage* inBlr, BlrMessage* outBlr)
|
||||
{
|
||||
return name;
|
||||
setBlr(inBlr, (typename T::InMessage*) 0);
|
||||
setBlr(outBlr, (typename T::OutMessage*) 0);
|
||||
}
|
||||
|
||||
virtual ExternalProcedure* FB_CALL newItem(const IRoutineMetadata* metadata)
|
||||
@ -645,32 +646,34 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
const char* name;
|
||||
template <typename MessageType> void setBlr(BlrMessage* blrMessage, MessageType*)
|
||||
{
|
||||
blrMessage->blr = MessageType::getBlr(&blrMessage->blrLength);
|
||||
blrMessage->bufferLength = MessageType::getSize();
|
||||
}
|
||||
|
||||
void setBlr(BlrMessage* blrMessage, void**)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T> class TriggerFactoryImpl : public TriggerFactory
|
||||
{
|
||||
public:
|
||||
explicit TriggerFactoryImpl(const char* aName)
|
||||
: name(aName)
|
||||
explicit TriggerFactoryImpl(const char* name)
|
||||
{
|
||||
fbUdrRegTrigger(this);
|
||||
fbUdrRegTrigger(name, this);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual const char* FB_CALL getName()
|
||||
virtual void setup(const IRoutineMetadata* /*metadata*/)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
virtual ExternalTrigger* FB_CALL newItem(const IRoutineMetadata* metadata)
|
||||
{
|
||||
return new(metadata) Routine<T>;
|
||||
}
|
||||
|
||||
private:
|
||||
const char* name;
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,30 +39,29 @@ namespace Firebird
|
||||
class FunctionFactory
|
||||
{
|
||||
public:
|
||||
virtual const char* FB_CALL getName() = 0;
|
||||
virtual void setup(const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
|
||||
virtual ExternalFunction* FB_CALL newItem(const IRoutineMetadata* metadata) = 0;
|
||||
};
|
||||
|
||||
class ProcedureFactory
|
||||
{
|
||||
public:
|
||||
virtual const char* FB_CALL getName() = 0;
|
||||
virtual void setup(const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
|
||||
virtual ExternalProcedure* FB_CALL newItem(const IRoutineMetadata* metadata) = 0;
|
||||
};
|
||||
|
||||
class TriggerFactory
|
||||
{
|
||||
public:
|
||||
virtual const char* FB_CALL getName() = 0;
|
||||
virtual void setup(const IRoutineMetadata* metadata) = 0;
|
||||
virtual ExternalTrigger* FB_CALL newItem(const IRoutineMetadata* metadata) = 0;
|
||||
};
|
||||
|
||||
|
||||
// Routine registration functions.
|
||||
extern "C" void fbUdrRegFunction(FunctionFactory* factory);
|
||||
extern "C" void fbUdrRegProcedure(ProcedureFactory* factory);
|
||||
extern "C" void fbUdrRegTrigger(TriggerFactory* factory);
|
||||
extern "C" void* fbUdrGetFunction(const char* symbol);
|
||||
extern "C" void fbUdrRegFunction(const char* name, FunctionFactory* factory);
|
||||
extern "C" void fbUdrRegProcedure(const char* name, ProcedureFactory* factory);
|
||||
extern "C" void fbUdrRegTrigger(const char* name, TriggerFactory* factory);
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -727,6 +727,8 @@ static const struct {
|
||||
{"invalid_boolean_usage", 335545023},
|
||||
{"sysf_argscant_both_be_zero", 335545024},
|
||||
{"spb_no_id", 335545025},
|
||||
{"ee_blr_mismatch_null", 335545026},
|
||||
{"ee_blr_mismatch_length", 335545027},
|
||||
{"gfix_db_name", 335740929},
|
||||
{"gfix_invalid_sw", 335740930},
|
||||
{"gfix_incmp_sw", 335740932},
|
||||
|
@ -761,6 +761,8 @@ const ISC_STATUS isc_cannot_copy_stmt = 335545022L;
|
||||
const ISC_STATUS isc_invalid_boolean_usage = 335545023L;
|
||||
const ISC_STATUS isc_sysf_argscant_both_be_zero = 335545024L;
|
||||
const ISC_STATUS isc_spb_no_id = 335545025L;
|
||||
const ISC_STATUS isc_ee_blr_mismatch_null = 335545026L;
|
||||
const ISC_STATUS isc_ee_blr_mismatch_length = 335545027L;
|
||||
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
||||
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
||||
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
||||
@ -1180,7 +1182,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
|
||||
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
||||
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
||||
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
||||
const ISC_STATUS isc_err_max = 1124;
|
||||
const ISC_STATUS isc_err_max = 1126;
|
||||
|
||||
#else /* c definitions */
|
||||
|
||||
@ -1911,6 +1913,8 @@ const ISC_STATUS isc_err_max = 1124;
|
||||
#define isc_invalid_boolean_usage 335545023L
|
||||
#define isc_sysf_argscant_both_be_zero 335545024L
|
||||
#define isc_spb_no_id 335545025L
|
||||
#define isc_ee_blr_mismatch_null 335545026L
|
||||
#define isc_ee_blr_mismatch_length 335545027L
|
||||
#define isc_gfix_db_name 335740929L
|
||||
#define isc_gfix_invalid_sw 335740930L
|
||||
#define isc_gfix_incmp_sw 335740932L
|
||||
@ -2330,7 +2334,7 @@ const ISC_STATUS isc_err_max = 1124;
|
||||
#define isc_trace_switch_param_miss 337182758L
|
||||
#define isc_trace_param_act_notcompat 337182759L
|
||||
#define isc_trace_mandatory_switch_miss 337182760L
|
||||
#define isc_err_max 1124
|
||||
#define isc_err_max 1126
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -730,6 +730,8 @@ Data source : @4"}, /* eds_statement */
|
||||
{335545023, "Invalid usage of boolean expression"}, /* invalid_boolean_usage */
|
||||
{335545024, "Arguments for @1 cannot both be zero"}, /* sysf_argscant_both_be_zero */
|
||||
{335545025, "missing service ID in spb"}, /* spb_no_id */
|
||||
{335545026, "External BLR message mismatch: invalid null descriptor at field @1"}, /* ee_blr_mismatch_null */
|
||||
{335545027, "External BLR message mismatch: length = @1, expected @2"}, /* ee_blr_mismatch_length */
|
||||
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
||||
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
||||
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
||||
|
@ -726,6 +726,8 @@ static const struct {
|
||||
{335545023, -104}, /* 703 invalid_boolean_usage */
|
||||
{335545024, -833}, /* 704 sysf_argscant_both_be_zero */
|
||||
{335545025, -901}, /* 705 spb_no_id */
|
||||
{335545026, -901}, /* 706 ee_blr_mismatch_null */
|
||||
{335545027, -901}, /* 707 ee_blr_mismatch_length */
|
||||
{335740929, -901}, /* 1 gfix_db_name */
|
||||
{335740930, -901}, /* 2 gfix_invalid_sw */
|
||||
{335740932, -901}, /* 4 gfix_incmp_sw */
|
||||
|
@ -726,6 +726,8 @@ static const struct {
|
||||
{335545023, "22000"}, // 703 invalid_boolean_usage
|
||||
{335545024, "42000"}, // 704 sysf_argscant_both_be_zero
|
||||
{335545025, "HY000"}, // 705 spb_no_id
|
||||
{335545026, "42000"}, // 706 ee_blr_mismatch_null
|
||||
{335545027, "42000"}, // 707 ee_blr_mismatch_length
|
||||
{335740929, "00000"}, // 1 gfix_db_name
|
||||
{335740930, "00000"}, // 2 gfix_invalid_sw
|
||||
{335740932, "00000"}, // 4 gfix_incmp_sw
|
||||
|
@ -103,6 +103,40 @@ public:
|
||||
return high * 256 + low;
|
||||
}
|
||||
|
||||
UCHAR checkByte(UCHAR expected)
|
||||
{
|
||||
using namespace Firebird;
|
||||
|
||||
UCHAR byte = getByte();
|
||||
|
||||
if (byte != expected)
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_syntaxerr) <<
|
||||
Arg::Num(expected) <<
|
||||
Arg::Num(getOffset() - 1) <<
|
||||
Arg::Num(byte));
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
USHORT checkWord(USHORT expected)
|
||||
{
|
||||
using namespace Firebird;
|
||||
|
||||
USHORT word = getWord();
|
||||
|
||||
if (word != expected)
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_syntaxerr) <<
|
||||
Arg::Num(expected) <<
|
||||
Arg::Num(getOffset() - 2) <<
|
||||
Arg::Num(word));
|
||||
}
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
private:
|
||||
const UCHAR* start;
|
||||
const UCHAR* end;
|
||||
|
@ -594,7 +594,8 @@ void ExtEngineManager::closeAttachment(thread_db* tdbb, Attachment* attachment)
|
||||
|
||||
|
||||
ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, const Jrd::Function* udf,
|
||||
const MetaName& engine, const string& entryPoint, const string& body)
|
||||
const MetaName& engine, const string& entryPoint, const string& body,
|
||||
BlrMessage* inBlr, BlrMessage* outBlr)
|
||||
{
|
||||
string entryPointTrimmed = entryPoint;
|
||||
entryPointTrimmed.trim();
|
||||
@ -640,7 +641,8 @@ ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, cons
|
||||
{ // scope
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
|
||||
externalFunction = attInfo->engine->makeFunction(RaiseError(), attInfo->context, metadata);
|
||||
externalFunction = attInfo->engine->makeFunction(RaiseError(), attInfo->context, metadata,
|
||||
inBlr, outBlr);
|
||||
|
||||
if (!externalFunction)
|
||||
{
|
||||
@ -665,7 +667,8 @@ ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, cons
|
||||
|
||||
|
||||
ExtEngineManager::Procedure* ExtEngineManager::makeProcedure(thread_db* tdbb, const jrd_prc* prc,
|
||||
const MetaName& engine, const string& entryPoint, const string& body)
|
||||
const MetaName& engine, const string& entryPoint, const string& body,
|
||||
BlrMessage* inBlr, BlrMessage* outBlr)
|
||||
{
|
||||
string entryPointTrimmed = entryPoint;
|
||||
entryPointTrimmed.trim();
|
||||
@ -716,7 +719,8 @@ ExtEngineManager::Procedure* ExtEngineManager::makeProcedure(thread_db* tdbb, co
|
||||
{ // scope
|
||||
Attachment::Checkout attCout(tdbb->getAttachment());
|
||||
|
||||
externalProcedure = attInfo->engine->makeProcedure(RaiseError(), attInfo->context, metadata);
|
||||
externalProcedure = attInfo->engine->makeProcedure(RaiseError(), attInfo->context, metadata,
|
||||
inBlr, outBlr);
|
||||
|
||||
if (!externalProcedure)
|
||||
{
|
||||
|
@ -304,10 +304,10 @@ public:
|
||||
|
||||
Function* makeFunction(thread_db* tdbb, const Jrd::Function* udf,
|
||||
const Firebird::MetaName& engine, const Firebird::string& entryPoint,
|
||||
const Firebird::string& body);
|
||||
const Firebird::string& body, Firebird::BlrMessage* inBlr, Firebird::BlrMessage* outBlr);
|
||||
Procedure* makeProcedure(thread_db* tdbb, const jrd_prc* prc,
|
||||
const Firebird::MetaName& engine, const Firebird::string& entryPoint,
|
||||
const Firebird::string& body);
|
||||
const Firebird::string& body, Firebird::BlrMessage* inBlr, Firebird::BlrMessage* outBlr);
|
||||
Trigger* makeTrigger(thread_db* tdbb, const Jrd::Trigger* trg,
|
||||
const Firebird::MetaName& engine, const Firebird::string& entryPoint,
|
||||
const Firebird::string& body, Firebird::ExternalTrigger::Type type);
|
||||
|
@ -386,16 +386,25 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
body.getBuffer(1)[0] = 0;
|
||||
}
|
||||
|
||||
BlrMessage inBlr;
|
||||
inBlr.blr = NULL;
|
||||
inBlr.blrLength = 0;
|
||||
inBlr.bufferLength = 0;
|
||||
|
||||
BlrMessage outBlr;
|
||||
outBlr.blr = NULL;
|
||||
outBlr.blrLength = 0;
|
||||
outBlr.bufferLength = 0;
|
||||
|
||||
function->fun_external =
|
||||
dbb->dbb_extManager.makeFunction(tdbb, function, X.RDB$ENGINE_NAME,
|
||||
(X.RDB$ENTRYPOINT.NULL ? "" : X.RDB$ENTRYPOINT), (char*) body.begin());
|
||||
(X.RDB$ENTRYPOINT.NULL ? "" : X.RDB$ENTRYPOINT), (char*) body.begin(),
|
||||
&inBlr, &outBlr);
|
||||
|
||||
if (!function->fun_external)
|
||||
{
|
||||
function->setImplemented(false);
|
||||
}
|
||||
|
||||
function->makeFormat();
|
||||
function->makeFormat(tdbb, (inBlr.blr ? &inBlr : NULL), (outBlr.blr ? &outBlr : NULL));
|
||||
}
|
||||
else if (!X.RDB$FUNCTION_BLR.NULL)
|
||||
{
|
||||
@ -427,7 +436,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
throw;
|
||||
}
|
||||
|
||||
function->makeFormat();
|
||||
function->makeFormat(tdbb, NULL, NULL);
|
||||
}
|
||||
else if (!X.RDB$MODULE_NAME.NULL && !X.RDB$ENTRYPOINT.NULL)
|
||||
{
|
||||
@ -566,6 +575,23 @@ ULONG Function::allocateImpure(CompilerScratch* csb) const
|
||||
fb_assert(fun_out_msg_format.fmt_count == 2);
|
||||
fb_assert(fun_out_msg_format.fmt_length);
|
||||
CMP_impure(csb, fun_out_msg_format.fmt_length);
|
||||
|
||||
if (fun_in_msg_format2.fmt_count)
|
||||
{
|
||||
fb_assert(fun_in_msg_format2.fmt_length);
|
||||
CMP_impure(csb, fun_in_msg_format2.fmt_length);
|
||||
}
|
||||
|
||||
fb_assert(fun_out_msg_format2.fmt_count == 2 ||
|
||||
(fun_out_msg_format2.fmt_length == 0 && fun_out_msg_format2.fmt_count == 0));
|
||||
|
||||
if (fun_out_msg_format2.fmt_length)
|
||||
{
|
||||
fb_assert(fun_out_msg_format2.fmt_count == 2);
|
||||
CMP_impure(csb, fun_out_msg_format2.fmt_length);
|
||||
}
|
||||
else
|
||||
fb_assert(fun_out_msg_format2.fmt_count == 0);
|
||||
}
|
||||
|
||||
return impure;
|
||||
@ -719,34 +745,77 @@ dsc* Function::execute(thread_db* tdbb, const NestValueArray& args, impure_value
|
||||
|
||||
Jrd::Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
const ULONG in_msg_length = fun_in_msg_format.fmt_length;
|
||||
const ULONG out_msg_length = fun_out_msg_format.fmt_length;
|
||||
const ULONG inMsgLength = fun_in_msg_format.fmt_length;
|
||||
const ULONG outMsgLength = fun_out_msg_format.fmt_length;
|
||||
|
||||
UCHAR* const impure = reinterpret_cast<UCHAR*>(value);
|
||||
UCHAR* const in_msg = (UCHAR*) FB_ALIGN((IPTR) impure + sizeof(impure_value), FB_ALIGNMENT);
|
||||
UCHAR* const out_msg = (UCHAR*) FB_ALIGN((IPTR) in_msg + in_msg_length, FB_ALIGNMENT);
|
||||
UCHAR* const inMsg = (UCHAR*) FB_ALIGN((IPTR) impure + sizeof(impure_value), FB_ALIGNMENT);
|
||||
UCHAR* const outMsg = (UCHAR*) FB_ALIGN((IPTR) inMsg + inMsgLength, FB_ALIGNMENT);
|
||||
|
||||
const ULONG inMsgLength2 = fun_in_msg_format2.fmt_length;
|
||||
const ULONG outMsgLength2 = fun_out_msg_format2.fmt_length;
|
||||
UCHAR* const inMsg2 = inMsgLength2 ?
|
||||
(UCHAR*) FB_ALIGN((IPTR) outMsg + outMsgLength, FB_ALIGNMENT) : inMsg;
|
||||
UCHAR* const outMsg2 = outMsgLength2 ?
|
||||
(UCHAR*) FB_ALIGN((IPTR) inMsg2 + inMsgLength2, FB_ALIGNMENT) : outMsg;
|
||||
|
||||
for (USHORT i = 0; i < fun_inputs; i++)
|
||||
{
|
||||
const ULONG arg_offset = (IPTR) fun_in_msg_format.fmt_desc[i * 2].dsc_address;
|
||||
const ULONG null_offset = (IPTR) fun_in_msg_format.fmt_desc[i * 2 + 1].dsc_address;
|
||||
UCHAR* const null_ptr = in_msg + null_offset;
|
||||
const ULONG argOffset = (IPTR) fun_in_msg_format.fmt_desc[i * 2].dsc_address;
|
||||
const ULONG nullOffset = (IPTR) fun_in_msg_format.fmt_desc[i * 2 + 1].dsc_address;
|
||||
SSHORT* const nullPtr = reinterpret_cast<SSHORT*>(inMsg + nullOffset);
|
||||
dsc argDesc = fun_args[i + 1].fun_parameter->prm_desc;
|
||||
argDesc.dsc_address = inMsg + argOffset;
|
||||
|
||||
dsc* const src_desc = EVL_expr(tdbb, request, args[i]);
|
||||
if (src_desc && !(request->req_flags & req_null))
|
||||
//// TODO: Validate constraints for external.
|
||||
dsc* const srcDesc = EVL_expr(tdbb, request, args[i]);
|
||||
if (srcDesc && !(request->req_flags & req_null))
|
||||
{
|
||||
*reinterpret_cast<SSHORT*>(null_ptr) = FALSE;
|
||||
|
||||
dsc arg_desc = fun_args[i + 1].fun_parameter->prm_desc;
|
||||
arg_desc.dsc_address = in_msg + arg_offset;
|
||||
MOV_move(tdbb, src_desc, &arg_desc);
|
||||
*nullPtr = FALSE;
|
||||
MOV_move(tdbb, srcDesc, &argDesc);
|
||||
}
|
||||
else
|
||||
*reinterpret_cast<SSHORT*>(null_ptr) = TRUE;
|
||||
*nullPtr = TRUE;
|
||||
|
||||
if (fun_external && inMsgLength2)
|
||||
{
|
||||
const ULONG argOffset2 = (IPTR) fun_in_msg_format2.fmt_desc[i * 2].dsc_address;
|
||||
const ULONG nullOffset2 = (IPTR) fun_in_msg_format2.fmt_desc[i * 2 + 1].dsc_address;
|
||||
SSHORT* const nullPtr2 = reinterpret_cast<SSHORT*>(inMsg2 + nullOffset2);
|
||||
|
||||
if (!(*nullPtr2 = *nullPtr))
|
||||
{
|
||||
dsc argDesc2 = fun_in_msg_format2.fmt_desc[i * 2];
|
||||
argDesc2.dsc_address = inMsg2 + argOffset2;
|
||||
MOV_move(tdbb, &argDesc, &argDesc2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ULONG argOffset = (IPTR) fun_out_msg_format.fmt_desc[0].dsc_address;
|
||||
const ULONG nullOffset = (IPTR) fun_out_msg_format.fmt_desc[1].dsc_address;
|
||||
SSHORT* const nullPtr = reinterpret_cast<SSHORT*>(outMsg + nullOffset);
|
||||
dsc argDesc = fun_args[fun_return_arg].fun_parameter->prm_desc;
|
||||
argDesc.dsc_address = outMsg + argOffset;
|
||||
|
||||
if (fun_external)
|
||||
fun_external->execute(tdbb, in_msg, out_msg);
|
||||
{
|
||||
fun_external->execute(tdbb, inMsg2, outMsg2);
|
||||
|
||||
if (outMsgLength2)
|
||||
{
|
||||
const ULONG argOffset2 = (IPTR) fun_out_msg_format2.fmt_desc[0].dsc_address;
|
||||
const ULONG nullOffset2 = (IPTR) fun_out_msg_format2.fmt_desc[1].dsc_address;
|
||||
SSHORT* const nullPtr2 = reinterpret_cast<SSHORT*>(outMsg2 + nullOffset2);
|
||||
|
||||
if (!(*nullPtr = *nullPtr2))
|
||||
{
|
||||
dsc argDesc2 = fun_out_msg_format2.fmt_desc[0];
|
||||
argDesc2.dsc_address = outMsg2 + argOffset2;
|
||||
MOV_move(tdbb, &argDesc2, &argDesc);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jrd_req* const new_request = getStatement()->findRequest(tdbb);
|
||||
@ -764,13 +833,11 @@ dsc* Function::execute(thread_db* tdbb, const NestValueArray& args, impure_value
|
||||
|
||||
EXE_start(tdbb, new_request, transaction);
|
||||
|
||||
if (in_msg_length)
|
||||
{
|
||||
EXE_send(tdbb, new_request, 0, in_msg_length, in_msg);
|
||||
}
|
||||
if (inMsgLength)
|
||||
EXE_send(tdbb, new_request, 0, inMsgLength, inMsg);
|
||||
|
||||
fb_assert(out_msg_length);
|
||||
EXE_receive(tdbb, new_request, 1, out_msg_length, out_msg);
|
||||
fb_assert(outMsgLength);
|
||||
EXE_receive(tdbb, new_request, 1, outMsgLength, outMsg);
|
||||
|
||||
// Clean up all savepoints started during execution of the function
|
||||
|
||||
@ -799,18 +866,13 @@ dsc* Function::execute(thread_db* tdbb, const NestValueArray& args, impure_value
|
||||
new_request->req_flags &= ~req_in_use;
|
||||
}
|
||||
|
||||
const ULONG arg_offset = (IPTR) fun_out_msg_format.fmt_desc[0].dsc_address;
|
||||
const ULONG null_offset = (IPTR) fun_out_msg_format.fmt_desc[1].dsc_address;
|
||||
|
||||
UCHAR* const null_ptr = out_msg + null_offset;
|
||||
if (*reinterpret_cast<SSHORT*>(null_ptr))
|
||||
//// TODO: Validate constraints for external.
|
||||
if (*nullPtr)
|
||||
request->req_flags |= req_null;
|
||||
else
|
||||
{
|
||||
dsc arg_desc = fun_args[fun_return_arg].fun_parameter->prm_desc;
|
||||
arg_desc.dsc_address = out_msg + arg_offset;
|
||||
request->req_flags &= ~req_null;
|
||||
MOV_move(tdbb, &arg_desc, &value->vlu_desc);
|
||||
MOV_move(tdbb, &argDesc, &value->vlu_desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -841,15 +903,105 @@ USHORT Function::incrementAlterCount()
|
||||
return ++fun_alter_count;
|
||||
}
|
||||
|
||||
void Function::makeFormat()
|
||||
void Function::makeFormat(thread_db* tdbb, const BlrMessage* inBlr, const BlrMessage* outBlr)
|
||||
{
|
||||
// Input format
|
||||
|
||||
const USHORT count = fun_inputs * 2;
|
||||
bool messageNeeded = false;
|
||||
ULONG offset = 0;
|
||||
UCHAR maxAlignment = 0;
|
||||
USHORT count;
|
||||
|
||||
dsc shortDesc;
|
||||
shortDesc.makeShort(0);
|
||||
|
||||
if (inBlr)
|
||||
{
|
||||
BlrReader reader(inBlr->blr, inBlr->blrLength);
|
||||
|
||||
reader.checkByte(blr_version5);
|
||||
reader.checkByte(blr_begin);
|
||||
reader.checkByte(blr_message);
|
||||
reader.getByte(); // message number: ignore it
|
||||
count = reader.checkWord(fun_inputs * 2);
|
||||
|
||||
fun_in_msg_format2.fmt_desc.resize(count);
|
||||
fun_in_msg_format2.fmt_count = count;
|
||||
|
||||
for (unsigned i = 0; i < count / 2; ++i)
|
||||
{
|
||||
dsc* desc = &fun_in_msg_format2.fmt_desc[i * 2];
|
||||
PAR_datatype(tdbb, reader, desc);
|
||||
|
||||
if (desc->dsc_dtype >= dtype_aligned)
|
||||
{
|
||||
maxAlignment = MAX(maxAlignment, type_alignments[desc->dsc_dtype]);
|
||||
offset = FB_ALIGN(offset, type_alignments[desc->dsc_dtype]);
|
||||
}
|
||||
|
||||
desc->dsc_address = (UCHAR*)(IPTR) offset;
|
||||
offset += desc->dsc_length;
|
||||
|
||||
const dsc* prmDesc = &fun_args[i + 1].fun_parameter->prm_desc;
|
||||
|
||||
if (desc->isText() && desc->getCharSet() == CS_NONE)
|
||||
desc->setTextType(prmDesc->getTextType());
|
||||
desc->setNullable(prmDesc->isNullable());
|
||||
|
||||
messageNeeded |= !DSC_EQUIV(desc, prmDesc, false);
|
||||
|
||||
++desc;
|
||||
PAR_datatype(tdbb, reader, desc);
|
||||
|
||||
if (!DSC_EQUIV(desc, &shortDesc, false))
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_ee_blr_mismatch_null) <<
|
||||
Arg::Num(i * 2 + 1));
|
||||
}
|
||||
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT));
|
||||
desc->dsc_address = (UCHAR*)(IPTR) offset;
|
||||
offset += sizeof(SSHORT);
|
||||
|
||||
messageNeeded |= !DSC_EQUIV(desc, &shortDesc, false);
|
||||
}
|
||||
|
||||
reader.checkByte(blr_end);
|
||||
reader.checkByte(blr_eoc);
|
||||
|
||||
if (offset != inBlr->bufferLength)
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_ee_blr_mismatch_length) <<
|
||||
Arg::Num(inBlr->bufferLength) <<
|
||||
Arg::Num(offset));
|
||||
}
|
||||
|
||||
if (messageNeeded)
|
||||
{
|
||||
// Pad the external message.
|
||||
offset = FB_ALIGN(offset, MAX(maxAlignment, sizeof(SSHORT)));
|
||||
|
||||
if (offset > MAX_MESSAGE_SIZE)
|
||||
status_exception::raise(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig));
|
||||
|
||||
fun_in_msg_format2.fmt_length = offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The external and internal messages are compatible, so there is no need to create a new one.
|
||||
fun_in_msg_format2.fmt_desc.clear();
|
||||
fun_in_msg_format2.fmt_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
count = fun_inputs * 2;
|
||||
fun_in_msg_format.fmt_desc.resize(count);
|
||||
fun_in_msg_format.fmt_count = count;
|
||||
|
||||
ULONG offset = 0;
|
||||
offset = 0;
|
||||
maxAlignment = 0;
|
||||
|
||||
for (USHORT i = 0; i < fun_inputs; i++)
|
||||
{
|
||||
@ -857,8 +1009,10 @@ void Function::makeFormat()
|
||||
|
||||
if (arg_desc.dsc_dtype >= dtype_aligned)
|
||||
{
|
||||
maxAlignment = MAX(maxAlignment, type_alignments[arg_desc.dsc_dtype]);
|
||||
offset = FB_ALIGN(offset, type_alignments[arg_desc.dsc_dtype]);
|
||||
}
|
||||
|
||||
arg_desc.dsc_address = (UCHAR*)(IPTR) offset;
|
||||
offset += arg_desc.dsc_length;
|
||||
fun_in_msg_format.fmt_desc[i * 2] = arg_desc;
|
||||
@ -870,23 +1024,100 @@ void Function::makeFormat()
|
||||
fun_in_msg_format.fmt_desc[i * 2 + 1] = arg_desc;
|
||||
}
|
||||
|
||||
if (offset > MAX_MESSAGE_SIZE)
|
||||
if (!messageNeeded)
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig));
|
||||
// This message will be used by external. Pad it.
|
||||
offset = FB_ALIGN(offset, MAX(maxAlignment, sizeof(SSHORT)));
|
||||
}
|
||||
|
||||
if (offset > MAX_MESSAGE_SIZE)
|
||||
status_exception::raise(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig));
|
||||
|
||||
fun_in_msg_format.fmt_length = offset;
|
||||
|
||||
// Output format
|
||||
|
||||
messageNeeded = false;
|
||||
|
||||
if (outBlr)
|
||||
{
|
||||
BlrReader reader(outBlr->blr, outBlr->blrLength);
|
||||
|
||||
reader.checkByte(blr_version5);
|
||||
reader.checkByte(blr_begin);
|
||||
reader.checkByte(blr_message);
|
||||
reader.getByte(); // message number: ignore it
|
||||
count = reader.checkWord(2);
|
||||
|
||||
fun_out_msg_format2.fmt_desc.resize(2);
|
||||
fun_out_msg_format2.fmt_count = 2;
|
||||
|
||||
offset = 0;
|
||||
|
||||
dsc* desc = &fun_out_msg_format2.fmt_desc[0];
|
||||
PAR_datatype(tdbb, reader, desc);
|
||||
|
||||
if (desc->dsc_dtype >= dtype_aligned)
|
||||
offset = FB_ALIGN(offset, type_alignments[desc->dsc_dtype]);
|
||||
|
||||
desc->dsc_address = (UCHAR*)(IPTR) offset;
|
||||
offset += desc->dsc_length;
|
||||
|
||||
const dsc* prmDesc = &fun_args[fun_return_arg].fun_parameter->prm_desc;
|
||||
|
||||
if (desc->isText() && desc->getCharSet() == CS_NONE)
|
||||
desc->setTextType(prmDesc->getTextType());
|
||||
desc->setNullable(prmDesc->isNullable());
|
||||
|
||||
messageNeeded |= !DSC_EQUIV(desc, prmDesc, false);
|
||||
|
||||
++desc;
|
||||
PAR_datatype(tdbb, reader, desc);
|
||||
|
||||
if (!DSC_EQUIV(desc, &shortDesc, false))
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_ee_blr_mismatch_null) <<
|
||||
Arg::Num(1));
|
||||
}
|
||||
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT));
|
||||
desc->dsc_address = (UCHAR*)(IPTR) offset;
|
||||
offset += sizeof(SSHORT);
|
||||
|
||||
messageNeeded |= !DSC_EQUIV(desc, &shortDesc, false);
|
||||
|
||||
reader.checkByte(blr_end);
|
||||
reader.checkByte(blr_eoc);
|
||||
|
||||
if (offset != outBlr->bufferLength)
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_ee_blr_mismatch_length) <<
|
||||
Arg::Num(outBlr->bufferLength) <<
|
||||
Arg::Num(offset));
|
||||
}
|
||||
|
||||
// Pad the external message.
|
||||
offset = FB_ALIGN(offset,
|
||||
MAX(type_alignments[fun_out_msg_format2.fmt_desc[0].dsc_dtype], sizeof(SSHORT)));
|
||||
|
||||
if (messageNeeded)
|
||||
fun_out_msg_format2.fmt_length = offset;
|
||||
else
|
||||
{
|
||||
// The external and internal messages are compatible, so there is no need to create a new one.
|
||||
fun_out_msg_format2.fmt_desc.clear();
|
||||
fun_out_msg_format2.fmt_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fun_out_msg_format.fmt_desc.resize(2);
|
||||
fun_out_msg_format.fmt_count = 2;
|
||||
|
||||
offset = 0;
|
||||
|
||||
dsc ret_desc = fun_args[fun_return_arg].fun_parameter->prm_desc;
|
||||
ret_desc.dsc_address = (UCHAR*)(IPTR) offset;
|
||||
offset += ret_desc.dsc_length;
|
||||
ret_desc.dsc_address = (UCHAR*)(IPTR) 0;
|
||||
offset = ret_desc.dsc_length;
|
||||
fun_out_msg_format.fmt_desc[0] = ret_desc;
|
||||
|
||||
ret_desc.makeShort(0);
|
||||
@ -895,5 +1126,13 @@ void Function::makeFormat()
|
||||
offset += sizeof(SSHORT);
|
||||
fun_out_msg_format.fmt_desc[1] = ret_desc;
|
||||
|
||||
if (!messageNeeded)
|
||||
{
|
||||
// This message will be used by external. Pad it.
|
||||
offset = FB_ALIGN(offset,
|
||||
MAX(type_alignments[fun_args[fun_return_arg].fun_parameter->prm_desc.dsc_dtype],
|
||||
sizeof(SSHORT)));
|
||||
}
|
||||
|
||||
fun_out_msg_format.fmt_length = offset;
|
||||
}
|
||||
|
@ -75,6 +75,8 @@ namespace Jrd
|
||||
fun_temp_length(0),
|
||||
fun_in_msg_format(p, 0),
|
||||
fun_out_msg_format(p, 0),
|
||||
fun_in_msg_format2(p, 0),
|
||||
fun_out_msg_format2(p, 0),
|
||||
fun_args(p),
|
||||
fun_flags(0),
|
||||
fun_use_count(0),
|
||||
@ -86,7 +88,8 @@ namespace Jrd
|
||||
{
|
||||
}
|
||||
|
||||
void makeFormat();
|
||||
void makeFormat(thread_db* tdbb, const Firebird::BlrMessage* inBlr,
|
||||
const Firebird::BlrMessage* outBlr);
|
||||
|
||||
static Function* loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT flags);
|
||||
static int blockingAst(void*);
|
||||
@ -111,6 +114,8 @@ namespace Jrd
|
||||
|
||||
Format fun_in_msg_format;
|
||||
Format fun_out_msg_format;
|
||||
Format fun_in_msg_format2;
|
||||
Format fun_out_msg_format2;
|
||||
|
||||
Firebird::Array<Argument> fun_args;
|
||||
|
||||
|
192
src/jrd/exe.cpp
192
src/jrd/exe.cpp
@ -202,6 +202,7 @@ void StatusXcp::as_sqlstate(char* sqlstate) const
|
||||
fb_sqlstate(sqlstate, status);
|
||||
}
|
||||
|
||||
static void execute_ext_procedure(thread_db* tdbb, jrd_req* request);
|
||||
static void execute_looper(thread_db*, jrd_req*, jrd_tra*, jrd_req::req_s);
|
||||
static void looper_seh(thread_db*, jrd_req*);
|
||||
static void release_blobs(thread_db*, jrd_req*);
|
||||
@ -1048,6 +1049,107 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request)
|
||||
}
|
||||
|
||||
|
||||
// Execute an external procedure.
|
||||
static void execute_ext_procedure(thread_db* tdbb, jrd_req* request)
|
||||
{
|
||||
const JrdStatement* statement = request->getStatement();
|
||||
|
||||
fb_assert(statement->topNode->kind == DmlNode::KIND_STATEMENT);
|
||||
const CompoundStmtNode* extStmts = StmtNode::as<CompoundStmtNode>(
|
||||
static_cast<const StmtNode*>(statement->topNode));
|
||||
fb_assert(extStmts);
|
||||
|
||||
switch (request->req_operation)
|
||||
{
|
||||
case jrd_req::req_evaluate:
|
||||
request->req_message = extStmts->statements[e_extproc_input_message]->as<MessageNode>();
|
||||
request->req_flags |= req_stall;
|
||||
request->req_operation = jrd_req::req_receive;
|
||||
break;
|
||||
|
||||
case jrd_req::req_sync:
|
||||
{
|
||||
const MessageNode* outMsgNode =
|
||||
extStmts->statements[e_extproc_output_message]->as<MessageNode>();
|
||||
fb_assert(outMsgNode);
|
||||
|
||||
const Format* outFormat = outMsgNode->format;
|
||||
|
||||
if (!request->resultSet)
|
||||
{
|
||||
const MessageNode* inMsgNode =
|
||||
extStmts->statements[e_extproc_input_message]->as<MessageNode>();
|
||||
fb_assert(inMsgNode && request->req_message == inMsgNode);
|
||||
|
||||
const CompoundStmtNode* list =
|
||||
extStmts->statements[e_extproc_input_assign]->as<CompoundStmtNode>();
|
||||
fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
|
||||
|
||||
const Format* format = inMsgNode->format;
|
||||
|
||||
// Clear the flags from the input message.
|
||||
USHORT* impure_flags = request->getImpure<USHORT>(inMsgNode->impureFlags);
|
||||
memset(impure_flags, 0, sizeof(USHORT) * format->fmt_count);
|
||||
|
||||
// Clear the flags from the output message.
|
||||
impure_flags = request->getImpure<USHORT>(outMsgNode->impureFlags);
|
||||
memset(impure_flags, 0, sizeof(USHORT) * outFormat->fmt_count);
|
||||
|
||||
// Validate/move input parameters.
|
||||
for (size_t i = 0; i < list->statements.getCount(); ++i)
|
||||
{
|
||||
EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
|
||||
list->statements[i].getObject()));
|
||||
}
|
||||
|
||||
const MessageNode* inMsgNode2 =
|
||||
extStmts->statements[e_extproc_input_message2]->as<MessageNode>();
|
||||
if (!inMsgNode2)
|
||||
inMsgNode2 = inMsgNode;
|
||||
|
||||
const MessageNode* outMsgNode2 =
|
||||
extStmts->statements[e_extproc_output_message2]->as<MessageNode>();
|
||||
if (!outMsgNode2)
|
||||
outMsgNode2 = outMsgNode;
|
||||
|
||||
UCHAR* inMsg = request->getImpure<UCHAR>(inMsgNode2->impureOffset);
|
||||
UCHAR* outMsg = request->getImpure<UCHAR>(outMsgNode2->impureOffset);
|
||||
|
||||
request->resultSet = statement->procedure->getExternal()->open(tdbb, inMsg, outMsg);
|
||||
}
|
||||
|
||||
request->req_message = outMsgNode;
|
||||
bool result = request->resultSet->fetch(tdbb);
|
||||
UCHAR* outMsg = request->getImpure<UCHAR>(outMsgNode->impureOffset);
|
||||
|
||||
// Set the eof flag.
|
||||
const dsc& eofDesc = outFormat->fmt_desc[outFormat->fmt_count - 1];
|
||||
fb_assert(eofDesc.dsc_dtype == dtype_short);
|
||||
*((SSHORT*)(UCHAR*) (outMsg + (IPTR) eofDesc.dsc_address)) = (SSHORT) result;
|
||||
|
||||
const CompoundStmtNode* list =
|
||||
extStmts->statements[e_extproc_output_assign]->as<CompoundStmtNode>();
|
||||
fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
|
||||
|
||||
if (result)
|
||||
{
|
||||
// Validate/move output parameters.
|
||||
for (size_t i = 0; i < list->statements.getCount(); ++i)
|
||||
{
|
||||
EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
|
||||
list->statements[i].getObject()));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void execute_looper(thread_db* tdbb,
|
||||
jrd_req* request,
|
||||
@ -1362,100 +1464,12 @@ const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* no
|
||||
else
|
||||
break;
|
||||
|
||||
fb_assert(statement->topNode->kind == DmlNode::KIND_STATEMENT);
|
||||
const CompoundStmtNode* extStmts = StmtNode::as<CompoundStmtNode>(
|
||||
static_cast<const StmtNode*>(statement->topNode));
|
||||
fb_assert(extStmts);
|
||||
|
||||
switch (request->req_operation)
|
||||
{
|
||||
case jrd_req::req_evaluate:
|
||||
request->req_message = extStmts->statements[e_extproc_input_message]->as<MessageNode>();
|
||||
request->req_flags |= req_stall;
|
||||
request->req_operation = jrd_req::req_receive;
|
||||
break;
|
||||
|
||||
case jrd_req::req_sync:
|
||||
{
|
||||
const MessageNode* outMsgNode =
|
||||
extStmts->statements[e_extproc_output_message]->as<MessageNode>();
|
||||
fb_assert(outMsgNode);
|
||||
|
||||
const Format* outFormat = outMsgNode->format;
|
||||
UCHAR* outMsg = request->getImpure<UCHAR>(outMsgNode->impureOffset);
|
||||
|
||||
if (!request->resultSet)
|
||||
{
|
||||
// input message
|
||||
const MessageNode* inMsgNode =
|
||||
extStmts->statements[e_extproc_input_message]->as<MessageNode>();
|
||||
fb_assert(inMsgNode);
|
||||
fb_assert(request->req_message == inMsgNode);
|
||||
|
||||
const CompoundStmtNode* list =
|
||||
extStmts->statements[e_extproc_input_assign]->as<CompoundStmtNode>();
|
||||
fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
|
||||
|
||||
const Format* format = inMsgNode->format;
|
||||
|
||||
// clear the flags from the input message
|
||||
USHORT* impure_flags = request->getImpure<USHORT>(inMsgNode->impureFlags);
|
||||
memset(impure_flags, 0, sizeof(USHORT) * format->fmt_count);
|
||||
|
||||
// clear the flags from the output message
|
||||
impure_flags = request->getImpure<USHORT>(outMsgNode->impureFlags);
|
||||
memset(impure_flags, 0, sizeof(USHORT) * outFormat->fmt_count);
|
||||
|
||||
// validate input parameters
|
||||
for (size_t i = 0; i < list->statements.getCount(); ++i)
|
||||
{
|
||||
EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
|
||||
list->statements[i].getObject()));
|
||||
}
|
||||
|
||||
UCHAR* inMsg = request->getImpure<UCHAR>(request->req_message->impureOffset);
|
||||
|
||||
request->resultSet = statement->procedure->getExternal()->open(
|
||||
tdbb, inMsg, outMsg);
|
||||
}
|
||||
|
||||
request->req_message = outMsgNode;
|
||||
bool result = request->resultSet->fetch(tdbb);
|
||||
|
||||
// end flag
|
||||
const dsc& eofDesc = outFormat->fmt_desc[outFormat->fmt_count - 1];
|
||||
fb_assert(eofDesc.dsc_dtype == dtype_short);
|
||||
*((SSHORT*) (UCHAR*) (outMsg + (IPTR) eofDesc.dsc_address)) = (SSHORT) result;
|
||||
|
||||
const CompoundStmtNode* list =
|
||||
extStmts->statements[e_extproc_output_assign]->as<CompoundStmtNode>();
|
||||
fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
|
||||
|
||||
if (result)
|
||||
{
|
||||
// validate output parameters
|
||||
for (size_t i = 0; i < list->statements.getCount(); ++i)
|
||||
{
|
||||
EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
|
||||
list->statements[i].getObject()));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
execute_ext_procedure(tdbb, request);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (request->req_operation == jrd_req::req_evaluate && (--tdbb->tdbb_quantum < 0))
|
||||
{
|
||||
JRD_reschedule(tdbb, 0, true);
|
||||
}
|
||||
|
||||
if (request->req_operation == jrd_req::req_evaluate && node->hasLineColumn)
|
||||
{
|
||||
|
@ -130,8 +130,10 @@ struct impure_agg_sort
|
||||
// index (in CompoundStmtNode) for external procedure blr
|
||||
const int e_extproc_input_message = 0;
|
||||
const int e_extproc_output_message = 1;
|
||||
const int e_extproc_input_assign = 2;
|
||||
const int e_extproc_output_assign = 3;
|
||||
const int e_extproc_input_message2 = 2;
|
||||
const int e_extproc_output_message2 = 3;
|
||||
const int e_extproc_input_assign = 4;
|
||||
const int e_extproc_output_assign = 5;
|
||||
|
||||
// Request resources
|
||||
|
||||
|
327
src/jrd/met.epp
327
src/jrd/met.epp
@ -125,7 +125,8 @@ static void make_relation_scope_name(const TEXT*, const USHORT, string& str);
|
||||
static ValueExprNode* parse_field_default_blr(thread_db* tdbb, bid* blob_id);
|
||||
static void parse_field_validation_blr(thread_db* tdbb, bid* blob_id, const MetaName name,
|
||||
BoolExprNode** expr, StmtNode** stmt);
|
||||
static void parse_procedure_blr(thread_db*, jrd_prc*, bid*, CompilerScratch*, bool);
|
||||
static void parse_procedure_blr(thread_db*, jrd_prc*, bid*, CompilerScratch*, bool,
|
||||
const BlrMessage& extInBlr, const BlrMessage& extOutBlr);
|
||||
static void par_messages(thread_db*, const UCHAR* const, USHORT, jrd_prc*, CompilerScratch*);
|
||||
static bool resolve_charset_and_collation(thread_db*, USHORT*, const UCHAR*, const UCHAR*);
|
||||
static void save_trigger_data(thread_db*, trig_vec**, jrd_rel*, JrdStatement*, blb*, bid*,
|
||||
@ -3000,6 +3001,38 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
}
|
||||
END_FOR
|
||||
|
||||
BlrMessage inBlr;
|
||||
inBlr.blr = NULL;
|
||||
inBlr.blrLength = 0;
|
||||
inBlr.bufferLength = 0;
|
||||
|
||||
BlrMessage outBlr;
|
||||
outBlr.blr = NULL;
|
||||
outBlr.blrLength = 0;
|
||||
outBlr.bufferLength = 0;
|
||||
|
||||
const bool external = !P.RDB$ENGINE_NAME.NULL; // ODS_12_0
|
||||
|
||||
if (external)
|
||||
{
|
||||
HalfStaticArray<char, 512> body;
|
||||
|
||||
if (!P.RDB$PROCEDURE_SOURCE.NULL)
|
||||
{
|
||||
blb* blob = BLB_open(tdbb, attachment->getSysTransaction(),
|
||||
&P.RDB$PROCEDURE_SOURCE);
|
||||
ULONG len = BLB_get_data(tdbb, blob,
|
||||
(UCHAR*) body.getBuffer(blob->blb_length + 1), blob->blb_length + 1);
|
||||
body.begin()[MIN(blob->blb_length, len)] = '\0';
|
||||
}
|
||||
else
|
||||
body.getBuffer(1)[0] = '\0';
|
||||
|
||||
procedure->setExternal(dbb->dbb_extManager.makeProcedure(
|
||||
tdbb, procedure, P.RDB$ENGINE_NAME,
|
||||
(P.RDB$ENTRYPOINT.NULL ? "" : P.RDB$ENTRYPOINT), body.begin(), &inBlr, &outBlr));
|
||||
}
|
||||
|
||||
Array<NestConst<Parameter> >& paramArray = procedure->prc_output_fields;
|
||||
|
||||
if (paramArray.hasData() && paramArray[0])
|
||||
@ -3029,7 +3062,6 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
}
|
||||
|
||||
prc_t prc_type = prc_legacy;
|
||||
const bool external = !P.RDB$ENGINE_NAME.NULL; // ODS_12_0
|
||||
|
||||
MemoryPool* csb_pool = attachment->createPool();
|
||||
|
||||
@ -3048,7 +3080,8 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
try
|
||||
{
|
||||
parse_procedure_blr(tdbb, procedure,
|
||||
(P.RDB$PROCEDURE_BLR.NULL ? NULL : &P.RDB$PROCEDURE_BLR), csb, external);
|
||||
(P.RDB$PROCEDURE_BLR.NULL ? NULL : &P.RDB$PROCEDURE_BLR), csb, external,
|
||||
inBlr, outBlr);
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
@ -3080,26 +3113,6 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
delete csb;
|
||||
} // scope
|
||||
|
||||
if (external)
|
||||
{
|
||||
HalfStaticArray<char, 512> body;
|
||||
|
||||
if (!P.RDB$PROCEDURE_SOURCE.NULL)
|
||||
{
|
||||
blb* blob = BLB_open(tdbb, attachment->getSysTransaction(),
|
||||
&P.RDB$PROCEDURE_SOURCE);
|
||||
ULONG len = BLB_get_data(tdbb, blob,
|
||||
(UCHAR*) body.getBuffer(blob->blb_length + 1), blob->blb_length + 1);
|
||||
body.begin()[MIN(blob->blb_length, len)] = '\0';
|
||||
}
|
||||
else
|
||||
body.getBuffer(1)[0] = '\0';
|
||||
|
||||
procedure->setExternal(dbb->dbb_extManager.makeProcedure(
|
||||
tdbb, procedure, P.RDB$ENGINE_NAME,
|
||||
(P.RDB$ENTRYPOINT.NULL ? "" : P.RDB$ENTRYPOINT), body.begin()));
|
||||
}
|
||||
|
||||
if (P.RDB$VALID_BLR.NULL || P.RDB$VALID_BLR == FALSE)
|
||||
valid_blr = false;
|
||||
}
|
||||
@ -3135,11 +3148,19 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
catch (const Exception&)
|
||||
{
|
||||
procedure->prc_flags &= ~(PRC_being_scanned | PRC_scanned);
|
||||
|
||||
if (procedure->getExternal())
|
||||
{
|
||||
delete procedure->getExternal();
|
||||
procedure->setExternal(NULL);
|
||||
}
|
||||
|
||||
if (procedure->prc_existence_lock)
|
||||
{
|
||||
LCK_release(tdbb, procedure->prc_existence_lock);
|
||||
procedure->prc_existence_lock = NULL;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
@ -4371,20 +4392,128 @@ static void parse_field_validation_blr(thread_db* tdbb, bid* blob_id, const Meta
|
||||
|
||||
|
||||
// Generate BLR message for external procedures
|
||||
static void gen_ext_message(UCharBuffer& blr, UCHAR message,
|
||||
const Array<NestConst<Parameter> >& parameters)
|
||||
static bool gen_ext_message(thread_db* tdbb, UCharBuffer& blr, UCHAR message, UCHAR message2,
|
||||
const Array<NestConst<Parameter> >& parameters, const BlrMessage& extBlr,
|
||||
UCharBuffer& appendBlr)
|
||||
{
|
||||
size_t count = parameters.getCount();
|
||||
count = count * 2 + message;
|
||||
size_t prevAppendBlrSize = appendBlr.getCount();
|
||||
bool messageNeeded = false;
|
||||
size_t count = 0;
|
||||
size_t countPos = 0;
|
||||
ULONG offset = 0;
|
||||
UCHAR maxAlignment = 0;
|
||||
|
||||
dsc shortDesc;
|
||||
shortDesc.makeShort(0);
|
||||
|
||||
if (extBlr.blr)
|
||||
{
|
||||
BlrReader reader(extBlr.blr, extBlr.blrLength);
|
||||
|
||||
reader.checkByte(blr_version5);
|
||||
reader.checkByte(blr_begin);
|
||||
reader.checkByte(blr_message);
|
||||
reader.getByte(); // message number: ignore it
|
||||
count = reader.checkWord(parameters.getCount() * 2);
|
||||
|
||||
appendBlr.add(blr_message);
|
||||
appendBlr.add(message2);
|
||||
countPos = appendBlr.getCount();
|
||||
appendBlr.add(UCHAR(count)); // parameters (with nulls)
|
||||
appendBlr.add(UCHAR(count >> 8));
|
||||
|
||||
for (unsigned i = 0; i < count / 2; ++i)
|
||||
{
|
||||
dsc desc;
|
||||
PAR_datatype(tdbb, reader, &desc);
|
||||
PreparedStatement::generateBlr(&desc, appendBlr);
|
||||
|
||||
if (desc.dsc_dtype >= dtype_aligned)
|
||||
{
|
||||
maxAlignment = MAX(maxAlignment, type_alignments[desc.dsc_dtype]);
|
||||
offset = FB_ALIGN(offset, type_alignments[desc.dsc_dtype]);
|
||||
}
|
||||
|
||||
offset += desc.dsc_length;
|
||||
|
||||
const dsc* prmDesc = ¶meters[i]->prm_desc;
|
||||
|
||||
if (desc.isText() && desc.getCharSet() == CS_NONE)
|
||||
desc.setTextType(prmDesc->getTextType());
|
||||
desc.setNullable(prmDesc->isNullable());
|
||||
|
||||
messageNeeded |= !DSC_EQUIV(&desc, prmDesc, false);
|
||||
|
||||
PAR_datatype(tdbb, reader, &desc);
|
||||
|
||||
if (!DSC_EQUIV(&desc, &shortDesc, false))
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_ee_blr_mismatch_null) <<
|
||||
Arg::Num(i * 2 + 1));
|
||||
}
|
||||
|
||||
PreparedStatement::generateBlr(&desc, appendBlr);
|
||||
|
||||
if (desc.dsc_dtype >= dtype_aligned)
|
||||
{
|
||||
maxAlignment = MAX(maxAlignment, type_alignments[desc.dsc_dtype]);
|
||||
offset = FB_ALIGN(offset, type_alignments[desc.dsc_dtype]);
|
||||
}
|
||||
|
||||
offset += desc.dsc_length;
|
||||
|
||||
messageNeeded |= !DSC_EQUIV(&desc, &shortDesc, false);
|
||||
}
|
||||
|
||||
reader.checkByte(blr_end);
|
||||
reader.checkByte(blr_eoc);
|
||||
|
||||
if (offset != extBlr.bufferLength)
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_ee_blr_mismatch_length) <<
|
||||
Arg::Num(extBlr.bufferLength) <<
|
||||
Arg::Num(offset));
|
||||
}
|
||||
}
|
||||
|
||||
if (messageNeeded)
|
||||
{
|
||||
// Pad the external message.
|
||||
ULONG pad = FB_ALIGN(offset, maxAlignment) - offset;
|
||||
|
||||
if (pad != 0)
|
||||
{
|
||||
++count;
|
||||
appendBlr[countPos] = UCHAR(count);
|
||||
appendBlr[countPos + 1] = UCHAR(count >> 8);
|
||||
|
||||
dsc desc;
|
||||
desc.makeText(pad, 0);
|
||||
PreparedStatement::generateBlr(&desc, appendBlr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The external and internal messages are compatible, so there is no need to create a new one.
|
||||
appendBlr.shrink(prevAppendBlrSize);
|
||||
appendBlr.add(blr_begin);
|
||||
appendBlr.add(blr_end);
|
||||
}
|
||||
|
||||
// Input message is 0 and output message is 1. Output message need the eof (+1) field.
|
||||
count = parameters.getCount() * 2 + message;
|
||||
fb_assert(count < MAX_USHORT);
|
||||
|
||||
blr.add(blr_message); // e_extproc_input_message, e_extproc_output_message
|
||||
blr.add(message);
|
||||
blr.add(count); // parameters (with nulls)
|
||||
blr.add(count >> 8);
|
||||
countPos = blr.getCount();
|
||||
blr.add(UCHAR(count)); // parameters (with nulls)
|
||||
blr.add(UCHAR(count >> 8));
|
||||
|
||||
dsc shortDesc;
|
||||
shortDesc.makeShort(0);
|
||||
offset = 0;
|
||||
maxAlignment = 0;
|
||||
|
||||
for (const NestConst<Parameter>* i = parameters.begin(); i != parameters.end(); ++i)
|
||||
{
|
||||
@ -4393,8 +4522,10 @@ static void gen_ext_message(UCharBuffer& blr, UCHAR message,
|
||||
if (!parameter->prm_nullable)
|
||||
blr.add(blr_not_nullable);
|
||||
|
||||
const dsc* desc = ¶meter->prm_desc;
|
||||
|
||||
if (parameter->prm_mechanism == prm_mech_type_of)
|
||||
PreparedStatement::generateBlr(¶meter->prm_desc, blr);
|
||||
PreparedStatement::generateBlr(desc, blr);
|
||||
else
|
||||
{
|
||||
fb_assert(parameter->prm_mechanism == prm_mech_normal);
|
||||
@ -4422,16 +4553,43 @@ static void gen_ext_message(UCharBuffer& blr, UCHAR message,
|
||||
}
|
||||
}
|
||||
|
||||
if (desc->dsc_dtype >= dtype_aligned)
|
||||
{
|
||||
maxAlignment = MAX(maxAlignment, type_alignments[desc->dsc_dtype]);
|
||||
offset = FB_ALIGN(offset, type_alignments[desc->dsc_dtype]);
|
||||
}
|
||||
|
||||
offset += desc->dsc_length;
|
||||
|
||||
PreparedStatement::generateBlr(&shortDesc, blr); // null flag
|
||||
|
||||
maxAlignment = MAX(maxAlignment, sizeof(SSHORT));
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT)) + shortDesc.dsc_length;
|
||||
}
|
||||
|
||||
if (!messageNeeded)
|
||||
{
|
||||
// This message will be used by external. Pad it if needed.
|
||||
ULONG pad = FB_ALIGN(offset, maxAlignment) - offset;
|
||||
|
||||
if (pad != 0)
|
||||
{
|
||||
++count;
|
||||
blr[countPos] = UCHAR(count);
|
||||
blr[countPos + 1] = UCHAR(count >> 8);
|
||||
|
||||
dsc desc;
|
||||
desc.makeText(pad, 0);
|
||||
PreparedStatement::generateBlr(&desc, blr);
|
||||
}
|
||||
}
|
||||
|
||||
return messageNeeded;
|
||||
}
|
||||
|
||||
|
||||
static void parse_procedure_blr(thread_db* tdbb,
|
||||
jrd_prc* procedure,
|
||||
bid* blob_id,
|
||||
CompilerScratch* csb,
|
||||
bool external)
|
||||
static void parse_procedure_blr(thread_db* tdbb, jrd_prc* procedure, bid* blob_id,
|
||||
CompilerScratch* csb, bool external, const BlrMessage& extInBlr, const BlrMessage& extOutBlr)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -4453,28 +4611,52 @@ static void parse_procedure_blr(thread_db* tdbb,
|
||||
tmp.add(blr_version5);
|
||||
tmp.add(blr_begin);
|
||||
|
||||
// ASF: Generate input messages even when number of parameters is 0
|
||||
// because we'll use hardcoded message number (0 and 1) in execution.
|
||||
gen_ext_message(tmp, 0, procedure->prc_input_fields); // input message
|
||||
gen_ext_message(tmp, 1, procedure->prc_output_fields); // output message
|
||||
// ASF: Generate nodes even when they could be avoided, because we will use hardoced
|
||||
// message and statement numbers. See e_extproc_*.
|
||||
|
||||
UCharBuffer appendBlr;
|
||||
|
||||
bool genExtIn = gen_ext_message(tdbb, tmp, e_extproc_input_message, e_extproc_input_message2,
|
||||
procedure->prc_input_fields, extInBlr, appendBlr);
|
||||
bool genExtOut = gen_ext_message(tdbb, tmp, e_extproc_output_message, e_extproc_output_message2,
|
||||
procedure->prc_output_fields, extOutBlr, appendBlr);
|
||||
|
||||
dsc shortDesc;
|
||||
shortDesc.makeShort(0);
|
||||
PreparedStatement::generateBlr(&shortDesc, tmp); // end flag
|
||||
PreparedStatement::generateBlr(&shortDesc, tmp); // end flag for the output message
|
||||
|
||||
tmp.join(appendBlr);
|
||||
|
||||
tmp.add(blr_begin); // e_extproc_input_assign
|
||||
|
||||
fb_assert(procedure->prc_input_fields.getCount() < MAX_USHORT / 2);
|
||||
for (USHORT i = 0; i < procedure->prc_input_fields.getCount(); ++i)
|
||||
for (size_t i = 0; i < procedure->prc_input_fields.getCount(); ++i)
|
||||
{
|
||||
tmp.add(blr_assignment);
|
||||
tmp.add(blr_parameter2);
|
||||
tmp.add(0); // input message
|
||||
tmp.add((i * 2));
|
||||
tmp.add((i * 2) >> 8);
|
||||
tmp.add((i * 2) + 1); // null indicator
|
||||
tmp.add(((i * 2) + 1) >> 8);
|
||||
tmp.add(blr_null);
|
||||
const Parameter* parameter = procedure->prc_input_fields[i];
|
||||
|
||||
if (genExtIn || parameter->prm_mechanism != prm_mech_type_of || !parameter->prm_nullable)
|
||||
{
|
||||
tmp.add(blr_assignment);
|
||||
|
||||
tmp.add(blr_parameter2);
|
||||
tmp.add(e_extproc_input_message);
|
||||
tmp.add(UCHAR(i * 2));
|
||||
tmp.add(UCHAR((i * 2) >> 8));
|
||||
tmp.add(UCHAR((i * 2) + 1)); // null indicator
|
||||
tmp.add(UCHAR(((i * 2) + 1) >> 8));
|
||||
|
||||
if (genExtIn)
|
||||
{
|
||||
tmp.add(blr_parameter2);
|
||||
tmp.add(e_extproc_input_message2);
|
||||
tmp.add(UCHAR(i * 2));
|
||||
tmp.add(UCHAR((i * 2) >> 8));
|
||||
tmp.add(UCHAR((i * 2) + 1)); // null indicator
|
||||
tmp.add(UCHAR(((i * 2) + 1) >> 8));
|
||||
}
|
||||
else
|
||||
tmp.add(blr_null);
|
||||
}
|
||||
}
|
||||
|
||||
tmp.add(blr_end);
|
||||
@ -4482,16 +4664,41 @@ static void parse_procedure_blr(thread_db* tdbb,
|
||||
tmp.add(blr_begin); // e_extproc_output_assign
|
||||
|
||||
fb_assert(procedure->prc_output_fields.getCount() < MAX_USHORT / 2);
|
||||
for (USHORT i = 0; i < procedure->prc_output_fields.getCount(); ++i)
|
||||
for (size_t i = 0; i < procedure->prc_output_fields.getCount(); ++i)
|
||||
{
|
||||
tmp.add(blr_assignment);
|
||||
tmp.add(blr_parameter2);
|
||||
tmp.add(1); // output message
|
||||
tmp.add((i * 2));
|
||||
tmp.add((i * 2) >> 8);
|
||||
tmp.add((i * 2) + 1); // null indicator
|
||||
tmp.add(((i * 2) + 1) >> 8);
|
||||
tmp.add(blr_null);
|
||||
const Parameter* parameter = procedure->prc_output_fields[i];
|
||||
|
||||
if (genExtOut || parameter->prm_mechanism != prm_mech_type_of || !parameter->prm_nullable)
|
||||
{
|
||||
tmp.add(blr_assignment);
|
||||
|
||||
if (genExtOut)
|
||||
{
|
||||
tmp.add(blr_parameter2);
|
||||
tmp.add(e_extproc_output_message2);
|
||||
tmp.add(UCHAR(i * 2));
|
||||
tmp.add(UCHAR((i * 2) >> 8));
|
||||
tmp.add(UCHAR((i * 2) + 1)); // null indicator
|
||||
tmp.add(UCHAR(((i * 2) + 1) >> 8));
|
||||
|
||||
tmp.add(blr_parameter2);
|
||||
tmp.add(e_extproc_output_message);
|
||||
tmp.add(UCHAR(i * 2));
|
||||
tmp.add(UCHAR((i * 2) >> 8));
|
||||
tmp.add(UCHAR((i * 2) + 1)); // null indicator
|
||||
tmp.add(UCHAR(((i * 2) + 1) >> 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.add(blr_parameter2);
|
||||
tmp.add(e_extproc_output_message);
|
||||
tmp.add(UCHAR(i * 2));
|
||||
tmp.add(UCHAR((i * 2) >> 8));
|
||||
tmp.add(UCHAR((i * 2) + 1)); // null indicator
|
||||
tmp.add(UCHAR(((i * 2) + 1) >> 8));
|
||||
tmp.add(blr_null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tmp.add(blr_end);
|
||||
|
281
src/jrd/par.cpp
281
src/jrd/par.cpp
@ -81,6 +81,7 @@ using namespace Firebird;
|
||||
static NodeParseFunc blr_parsers[256] = {NULL};
|
||||
|
||||
|
||||
static void par_error(BlrReader& blrReader, const Arg::StatusVector& v, bool isSyntaxError = true);
|
||||
static PlanNode* par_plan(thread_db*, CompilerScratch*);
|
||||
|
||||
|
||||
@ -328,19 +329,123 @@ void PAR_validation_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, UL
|
||||
}
|
||||
|
||||
|
||||
USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, DSC* desc, ItemInfo* itemInfo)
|
||||
// Parse a BLR datatype. Return the alignment requirements of the datatype.
|
||||
USHORT PAR_datatype(thread_db* tdbb, BlrReader& blrReader, dsc* desc)
|
||||
{
|
||||
desc->clear();
|
||||
|
||||
const USHORT dtype = blrReader.getByte();
|
||||
USHORT textType;
|
||||
|
||||
switch (dtype)
|
||||
{
|
||||
case blr_text:
|
||||
desc->makeText(blrReader.getWord(), ttype_dynamic);
|
||||
desc->dsc_flags |= DSC_no_subtype;
|
||||
break;
|
||||
|
||||
case blr_cstring:
|
||||
desc->dsc_dtype = dtype_cstring;
|
||||
desc->dsc_flags |= DSC_no_subtype;
|
||||
desc->dsc_length = blrReader.getWord();
|
||||
desc->setTextType(ttype_dynamic);
|
||||
break;
|
||||
|
||||
case blr_varying:
|
||||
desc->makeVarying(blrReader.getWord(), ttype_dynamic);
|
||||
desc->dsc_flags |= DSC_no_subtype;
|
||||
break;
|
||||
|
||||
case blr_text2:
|
||||
textType = blrReader.getWord();
|
||||
desc->makeText(blrReader.getWord(), textType);
|
||||
break;
|
||||
|
||||
case blr_cstring2:
|
||||
desc->dsc_dtype = dtype_cstring;
|
||||
desc->setTextType(blrReader.getWord());
|
||||
desc->dsc_length = blrReader.getWord();
|
||||
break;
|
||||
|
||||
case blr_varying2:
|
||||
textType = blrReader.getWord();
|
||||
desc->makeVarying(blrReader.getWord(), textType);
|
||||
break;
|
||||
|
||||
case blr_short:
|
||||
desc->dsc_dtype = dtype_short;
|
||||
desc->dsc_length = sizeof(SSHORT);
|
||||
desc->dsc_scale = (int) blrReader.getByte();
|
||||
break;
|
||||
|
||||
case blr_long:
|
||||
desc->dsc_dtype = dtype_long;
|
||||
desc->dsc_length = sizeof(SLONG);
|
||||
desc->dsc_scale = (int) blrReader.getByte();
|
||||
break;
|
||||
|
||||
case blr_int64:
|
||||
desc->dsc_dtype = dtype_int64;
|
||||
desc->dsc_length = sizeof(SINT64);
|
||||
desc->dsc_scale = (int) blrReader.getByte();
|
||||
break;
|
||||
|
||||
case blr_quad:
|
||||
desc->dsc_dtype = dtype_quad;
|
||||
desc->dsc_length = sizeof(ISC_QUAD);
|
||||
desc->dsc_scale = (int) blrReader.getByte();
|
||||
break;
|
||||
|
||||
case blr_float:
|
||||
desc->dsc_dtype = dtype_real;
|
||||
desc->dsc_length = sizeof(float);
|
||||
break;
|
||||
|
||||
case blr_timestamp:
|
||||
desc->dsc_dtype = dtype_timestamp;
|
||||
desc->dsc_length = sizeof(ISC_QUAD);
|
||||
break;
|
||||
|
||||
case blr_sql_date:
|
||||
desc->dsc_dtype = dtype_sql_date;
|
||||
desc->dsc_length = type_lengths[dtype_sql_date];
|
||||
break;
|
||||
|
||||
case blr_sql_time:
|
||||
desc->dsc_dtype = dtype_sql_time;
|
||||
desc->dsc_length = type_lengths[dtype_sql_time];
|
||||
break;
|
||||
|
||||
case blr_double:
|
||||
case blr_d_float:
|
||||
desc->dsc_dtype = dtype_double;
|
||||
desc->dsc_length = sizeof(double);
|
||||
break;
|
||||
|
||||
case blr_blob2:
|
||||
desc->dsc_dtype = dtype_blob;
|
||||
desc->dsc_length = sizeof(ISC_QUAD);
|
||||
desc->dsc_sub_type = blrReader.getWord();
|
||||
textType = blrReader.getWord();
|
||||
desc->dsc_scale = textType & 0xFF; // BLOB character set
|
||||
desc->dsc_flags = textType & 0xFF00; // BLOB collation
|
||||
break;
|
||||
|
||||
case blr_bool:
|
||||
desc->makeBoolean();
|
||||
break;
|
||||
|
||||
default:
|
||||
par_error(blrReader, Arg::Gds(isc_datnotsup));
|
||||
}
|
||||
|
||||
return type_alignments[desc->dsc_dtype];
|
||||
}
|
||||
|
||||
|
||||
// Parse a BLR descriptor. Return the alignment requirements of the datatype.
|
||||
USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* itemInfo)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* P A R _ d e s c
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Parse a BLR descriptor. Return the alignment requirements
|
||||
* of the datatype.
|
||||
*
|
||||
**************************************/
|
||||
if (itemInfo)
|
||||
{
|
||||
itemInfo->nullable = true;
|
||||
@ -348,123 +453,21 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, DSC* desc, ItemInfo* item
|
||||
itemInfo->fullDomain = false;
|
||||
}
|
||||
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_address = NULL;
|
||||
desc->dsc_flags = 0;
|
||||
desc->clear();
|
||||
|
||||
const USHORT dtype = csb->csb_blr_reader.getByte();
|
||||
USHORT textType;
|
||||
|
||||
switch (dtype)
|
||||
{
|
||||
case blr_not_nullable:
|
||||
PAR_desc(tdbb, csb, desc, itemInfo);
|
||||
if (itemInfo)
|
||||
itemInfo->nullable = false;
|
||||
break;
|
||||
|
||||
case blr_text:
|
||||
desc->makeText(csb->csb_blr_reader.getWord(), ttype_dynamic);
|
||||
desc->dsc_flags |= DSC_no_subtype;
|
||||
break;
|
||||
|
||||
case blr_cstring:
|
||||
desc->dsc_dtype = dtype_cstring;
|
||||
desc->dsc_flags |= DSC_no_subtype;
|
||||
desc->dsc_length = csb->csb_blr_reader.getWord();
|
||||
desc->setTextType(ttype_dynamic);
|
||||
break;
|
||||
|
||||
case blr_varying:
|
||||
desc->makeVarying(csb->csb_blr_reader.getWord(), ttype_dynamic);
|
||||
desc->dsc_flags |= DSC_no_subtype;
|
||||
break;
|
||||
|
||||
case blr_text2:
|
||||
textType = csb->csb_blr_reader.getWord();
|
||||
desc->makeText(csb->csb_blr_reader.getWord(), textType);
|
||||
break;
|
||||
|
||||
case blr_cstring2:
|
||||
desc->dsc_dtype = dtype_cstring;
|
||||
desc->setTextType(csb->csb_blr_reader.getWord());
|
||||
desc->dsc_length = csb->csb_blr_reader.getWord();
|
||||
break;
|
||||
|
||||
case blr_varying2:
|
||||
textType = csb->csb_blr_reader.getWord();
|
||||
desc->makeVarying(csb->csb_blr_reader.getWord(), textType);
|
||||
break;
|
||||
|
||||
case blr_short:
|
||||
desc->dsc_dtype = dtype_short;
|
||||
desc->dsc_length = sizeof(SSHORT);
|
||||
desc->dsc_scale = (int) csb->csb_blr_reader.getByte();
|
||||
break;
|
||||
|
||||
case blr_long:
|
||||
desc->dsc_dtype = dtype_long;
|
||||
desc->dsc_length = sizeof(SLONG);
|
||||
desc->dsc_scale = (int) csb->csb_blr_reader.getByte();
|
||||
break;
|
||||
|
||||
case blr_int64:
|
||||
desc->dsc_dtype = dtype_int64;
|
||||
desc->dsc_length = sizeof(SINT64);
|
||||
desc->dsc_scale = (int) csb->csb_blr_reader.getByte();
|
||||
break;
|
||||
|
||||
case blr_quad:
|
||||
desc->dsc_dtype = dtype_quad;
|
||||
desc->dsc_length = sizeof(ISC_QUAD);
|
||||
desc->dsc_scale = (int) csb->csb_blr_reader.getByte();
|
||||
break;
|
||||
|
||||
case blr_float:
|
||||
desc->dsc_dtype = dtype_real;
|
||||
desc->dsc_length = sizeof(float);
|
||||
break;
|
||||
|
||||
case blr_timestamp:
|
||||
desc->dsc_dtype = dtype_timestamp;
|
||||
desc->dsc_length = sizeof(ISC_QUAD);
|
||||
break;
|
||||
|
||||
case blr_sql_date:
|
||||
desc->dsc_dtype = dtype_sql_date;
|
||||
desc->dsc_length = type_lengths[dtype_sql_date];
|
||||
break;
|
||||
|
||||
case blr_sql_time:
|
||||
desc->dsc_dtype = dtype_sql_time;
|
||||
desc->dsc_length = type_lengths[dtype_sql_time];
|
||||
break;
|
||||
|
||||
case blr_double:
|
||||
case blr_d_float:
|
||||
desc->dsc_dtype = dtype_double;
|
||||
desc->dsc_length = sizeof(double);
|
||||
break;
|
||||
|
||||
case blr_blob2:
|
||||
{
|
||||
desc->dsc_dtype = dtype_blob;
|
||||
desc->dsc_length = sizeof(ISC_QUAD);
|
||||
desc->dsc_sub_type = csb->csb_blr_reader.getWord();
|
||||
|
||||
USHORT ttype = csb->csb_blr_reader.getWord();
|
||||
desc->dsc_scale = ttype & 0xFF; // BLOB character set
|
||||
desc->dsc_flags = ttype & 0xFF00; // BLOB collation
|
||||
case blr_not_nullable:
|
||||
PAR_desc(tdbb, csb, desc, itemInfo);
|
||||
if (itemInfo)
|
||||
itemInfo->nullable = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case blr_bool:
|
||||
desc->makeBoolean();
|
||||
break;
|
||||
|
||||
case blr_domain_name:
|
||||
case blr_domain_name2:
|
||||
case blr_domain_name:
|
||||
case blr_domain_name2:
|
||||
{
|
||||
bool fullDomain = (csb->csb_blr_reader.getByte() == blr_domain_full);
|
||||
MetaName* name = FB_NEW(csb->csb_pool) MetaName(csb->csb_pool);
|
||||
@ -522,8 +525,8 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, DSC* desc, ItemInfo* item
|
||||
break;
|
||||
}
|
||||
|
||||
case blr_column_name:
|
||||
case blr_column_name2:
|
||||
case blr_column_name:
|
||||
case blr_column_name2:
|
||||
{
|
||||
const bool fullDomain = (csb->csb_blr_reader.getByte() == blr_domain_full);
|
||||
MetaName* relationName = FB_NEW(csb->csb_pool) MetaName(csb->csb_pool);
|
||||
@ -584,8 +587,10 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, DSC* desc, ItemInfo* item
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
PAR_error(csb, Arg::Gds(isc_datnotsup));
|
||||
default:
|
||||
csb->csb_blr_reader.seekBackward(1);
|
||||
PAR_datatype(tdbb, csb->csb_blr_reader, desc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (desc->getTextType() != CS_NONE)
|
||||
@ -765,18 +770,9 @@ void PAR_register(UCHAR blr, NodeParseFunc parseFunc)
|
||||
}
|
||||
|
||||
|
||||
void PAR_error(CompilerScratch* csb, const Arg::StatusVector& v, bool isSyntaxError)
|
||||
// We've got a blr error other than a syntax error. Handle it.
|
||||
static void par_error(BlrReader& blrReader, const Arg::StatusVector& v, bool isSyntaxError)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* P A R _ e r r o r
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* We've got a blr error other than a syntax error. Handle it.
|
||||
*
|
||||
**************************************/
|
||||
fb_assert(v.value()[0] == isc_arg_gds);
|
||||
|
||||
// Don't bother to pass tdbb for error handling
|
||||
@ -784,9 +780,9 @@ void PAR_error(CompilerScratch* csb, const Arg::StatusVector& v, bool isSyntaxEr
|
||||
|
||||
if (isSyntaxError)
|
||||
{
|
||||
csb->csb_blr_reader.seekBackward(1);
|
||||
blrReader.seekBackward(1);
|
||||
Arg::Gds p(isc_invalid_blr);
|
||||
p << Arg::Num(csb->csb_blr_reader.getOffset());
|
||||
p << Arg::Num(blrReader.getOffset());
|
||||
p.append(v);
|
||||
p.copyTo(tdbb->tdbb_status_vector);
|
||||
}
|
||||
@ -799,6 +795,12 @@ void PAR_error(CompilerScratch* csb, const Arg::StatusVector& v, bool isSyntaxEr
|
||||
ERR_punt();
|
||||
}
|
||||
|
||||
// We've got a blr error other than a syntax error. Handle it.
|
||||
void PAR_error(CompilerScratch* csb, const Arg::StatusVector& v, bool isSyntaxError)
|
||||
{
|
||||
par_error(csb->csb_blr_reader, v, isSyntaxError);
|
||||
}
|
||||
|
||||
|
||||
// Look for named field in procedure output fields.
|
||||
SSHORT PAR_find_proc_field(const jrd_prc* procedure, const Firebird::MetaName& name)
|
||||
@ -1622,6 +1624,9 @@ DmlNode* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb)
|
||||
return PAR_parseRecordSource(tdbb, csb);
|
||||
}
|
||||
|
||||
if (!blr_parsers[blr_operator])
|
||||
PAR_syntax_error(csb, "valid BLR code");
|
||||
|
||||
DmlNode* node = blr_parsers[blr_operator](tdbb, *tdbb->getDefaultPool(), csb, blr_operator);
|
||||
size_t pos = 0;
|
||||
|
||||
|
@ -53,6 +53,7 @@ void PAR_validation_blr(Jrd::thread_db*, Jrd::jrd_rel*, const UCHAR* blr,
|
||||
SSHORT PAR_context(Jrd::CompilerScratch*, SSHORT*);
|
||||
void PAR_dependency(Jrd::thread_db*, Jrd::CompilerScratch*, SSHORT, SSHORT,
|
||||
const Firebird::MetaName&);
|
||||
USHORT PAR_datatype(Jrd::thread_db*, Jrd::BlrReader&, dsc*);
|
||||
USHORT PAR_desc(Jrd::thread_db*, Jrd::CompilerScratch*, dsc*, Jrd::ItemInfo* = NULL);
|
||||
void PAR_error(Jrd::CompilerScratch*, const Firebird::Arg::StatusVector&, bool isSyntaxError = true);
|
||||
SSHORT PAR_find_proc_field(const Jrd::jrd_prc*, const Firebird::MetaName&);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
||||
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
||||
--
|
||||
('2011-06-10 16:23:31', 'JRD', 0, 706)
|
||||
('2011-07-07 12:33:00', 'JRD', 0, 708)
|
||||
('2010-03-15 06:59:09', 'QLI', 1, 531)
|
||||
--
|
||||
--('2008-11-28 20:27:04', 'GDEF', 2, 346)
|
||||
|
@ -813,6 +813,8 @@ Data source : @4', NULL, NULL)
|
||||
('invalid_boolean_usage', NULL, NULL, NULL, 0, 703, NULL, 'Invalid usage of boolean expression', NULL, NULL);
|
||||
('sysf_argscant_both_be_zero', 'evlAtan2', 'SysFunction.cpp', NULL, 0, 704, NULL, 'Arguments for @1 cannot both be zero', NULL, NULL)
|
||||
('spb_no_id', 'Service::start', 'svc.c', NULL, 0, 705, NULL, 'missing service ID in spb', NULL, NULL);
|
||||
('ee_blr_mismatch_null', NULL, 'met.epp', NULL, 0, 706, NULL, 'External BLR message mismatch: invalid null descriptor at field @1', NULL, NULL)
|
||||
('ee_blr_mismatch_length', NULL, 'met.epp', NULL, 0, 707, NULL, 'External BLR message mismatch: length = @1, expected @2', NULL, NULL)
|
||||
-- QLI
|
||||
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
||||
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
||||
|
@ -711,6 +711,8 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
||||
(-104, '22', '000', 0, 703, 'invalid_boolean_usage', NULL, NULL)
|
||||
(-833, '42', '000', 0, 704, 'sysf_argscant_both_be_zero', NULL, NULL)
|
||||
(-901, 'HY', '000', 0, 705, 'spb_no_id', NULL, NULL)
|
||||
(-901, '42', '000', 0, 706, 'ee_blr_mismatch_null', NULL, NULL)
|
||||
(-901, '42', '000', 0, 707, 'ee_blr_mismatch_length', NULL, NULL)
|
||||
-- GFIX
|
||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||
|
@ -48,10 +48,12 @@ namespace Firebird
|
||||
struct Node
|
||||
{
|
||||
Node()
|
||||
: module(*getDefaultMemoryPool())
|
||||
: name(*getDefaultMemoryPool()),
|
||||
module(*getDefaultMemoryPool())
|
||||
{
|
||||
}
|
||||
|
||||
string name;
|
||||
PathName module;
|
||||
};
|
||||
|
||||
@ -151,9 +153,9 @@ public:
|
||||
virtual void FB_CALL openAttachment(Error* error, ExternalContext* context);
|
||||
virtual void FB_CALL closeAttachment(Error* error, ExternalContext* context);
|
||||
virtual ExternalFunction* FB_CALL makeFunction(Error* error, ExternalContext* context,
|
||||
const IRoutineMetadata* metadata);
|
||||
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr);
|
||||
virtual ExternalProcedure* FB_CALL makeProcedure(Error* error, ExternalContext* context,
|
||||
const IRoutineMetadata* metadata);
|
||||
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr);
|
||||
virtual ExternalTrigger* FB_CALL makeTrigger(Error* error, ExternalContext* context,
|
||||
const IRoutineMetadata* metadata);
|
||||
|
||||
@ -204,7 +206,8 @@ static TriggerNode* registeredTriggers = NULL;
|
||||
class SharedFunction : public ExternalFunction
|
||||
{
|
||||
public:
|
||||
SharedFunction(Engine* aEngine, const IRoutineMetadata* aMetadata)
|
||||
SharedFunction(Engine* aEngine, const IRoutineMetadata* aMetadata,
|
||||
BlrMessage* inBlr, BlrMessage* outBlr)
|
||||
: engine(aEngine),
|
||||
metadata(aMetadata),
|
||||
moduleName(*getDefaultMemoryPool()),
|
||||
@ -213,7 +216,8 @@ public:
|
||||
children(*getDefaultMemoryPool())
|
||||
{
|
||||
engine->loadModule(metadata, &moduleName, &entryPoint);
|
||||
engine->findNode<FunctionNode>(registeredFunctions, moduleName, entryPoint);
|
||||
FunctionNode* node = engine->findNode<FunctionNode>(registeredFunctions, moduleName, entryPoint);
|
||||
node->factory->setup(metadata, inBlr, outBlr);
|
||||
}
|
||||
|
||||
virtual ~SharedFunction()
|
||||
@ -246,7 +250,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FB_CALL execute(Error* error, ExternalContext* context, UCHAR* inMsg, UCHAR* outMsg)
|
||||
virtual void FB_CALL execute(Error* error, ExternalContext* context, void* inMsg, void* outMsg)
|
||||
{
|
||||
ExternalFunction* function = engine->getChild<FunctionNode, ExternalFunction>(
|
||||
children, this, context, registeredFunctions, engine->functions, moduleName);
|
||||
@ -270,7 +274,8 @@ public:
|
||||
class SharedProcedure : public ExternalProcedure
|
||||
{
|
||||
public:
|
||||
SharedProcedure(Engine* aEngine, const IRoutineMetadata* aMetadata)
|
||||
SharedProcedure(Engine* aEngine, const IRoutineMetadata* aMetadata,
|
||||
BlrMessage* inBlr, BlrMessage* outBlr)
|
||||
: engine(aEngine),
|
||||
metadata(aMetadata),
|
||||
moduleName(*getDefaultMemoryPool()),
|
||||
@ -279,7 +284,8 @@ public:
|
||||
children(*getDefaultMemoryPool())
|
||||
{
|
||||
engine->loadModule(metadata, &moduleName, &entryPoint);
|
||||
engine->findNode<ProcedureNode>(registeredProcedures, moduleName, entryPoint);
|
||||
ProcedureNode* node = engine->findNode<ProcedureNode>(registeredProcedures, moduleName, entryPoint);
|
||||
node->factory->setup(metadata, inBlr, outBlr);
|
||||
}
|
||||
|
||||
virtual ~SharedProcedure()
|
||||
@ -313,7 +319,7 @@ public:
|
||||
}
|
||||
|
||||
virtual ExternalResultSet* FB_CALL open(Error* error, ExternalContext* context,
|
||||
UCHAR* inMsg, UCHAR* outMsg)
|
||||
void* inMsg, void* outMsg)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -353,7 +359,8 @@ public:
|
||||
children(*getDefaultMemoryPool())
|
||||
{
|
||||
engine->loadModule(metadata, &moduleName, &entryPoint);
|
||||
engine->findNode<TriggerNode>(registeredTriggers, moduleName, entryPoint);
|
||||
TriggerNode* node = engine->findNode<TriggerNode>(registeredTriggers, moduleName, entryPoint);
|
||||
node->factory->setup(metadata);
|
||||
}
|
||||
|
||||
virtual ~SharedTrigger()
|
||||
@ -387,7 +394,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void FB_CALL execute(Error* error, ExternalContext* context,
|
||||
ExternalTrigger::Action action, UCHAR* oldMsg, UCHAR* newMsg)
|
||||
ExternalTrigger::Action action, void* oldMsg, void* newMsg)
|
||||
{
|
||||
ExternalTrigger* trigger = engine->getChild<TriggerNode, ExternalTrigger>(
|
||||
children, this, context, registeredTriggers, engine->triggers, moduleName);
|
||||
@ -408,9 +415,10 @@ public:
|
||||
//--------------------------------------
|
||||
|
||||
|
||||
extern "C" void fbUdrRegFunction(FunctionFactory* factory)
|
||||
extern "C" void fbUdrRegFunction(const char* name, FunctionFactory* factory)
|
||||
{
|
||||
FunctionNode* node = new FunctionNode();
|
||||
node->name = name;
|
||||
node->module = loadingModule();
|
||||
node->factory = factory;
|
||||
node->next = registeredFunctions;
|
||||
@ -418,9 +426,10 @@ extern "C" void fbUdrRegFunction(FunctionFactory* factory)
|
||||
}
|
||||
|
||||
|
||||
extern "C" void fbUdrRegProcedure(ProcedureFactory* factory)
|
||||
extern "C" void fbUdrRegProcedure(const char* name, ProcedureFactory* factory)
|
||||
{
|
||||
ProcedureNode* node = new ProcedureNode();
|
||||
node->name = name;
|
||||
node->module = loadingModule();
|
||||
node->factory = factory;
|
||||
node->next = registeredProcedures;
|
||||
@ -428,9 +437,10 @@ extern "C" void fbUdrRegProcedure(ProcedureFactory* factory)
|
||||
}
|
||||
|
||||
|
||||
extern "C" void fbUdrRegTrigger(TriggerFactory* factory)
|
||||
extern "C" void fbUdrRegTrigger(const char* name, TriggerFactory* factory)
|
||||
{
|
||||
TriggerNode* node = new TriggerNode();
|
||||
node->name = name;
|
||||
node->module = loadingModule();
|
||||
node->factory = factory;
|
||||
node->next = registeredTriggers;
|
||||
@ -438,12 +448,6 @@ extern "C" void fbUdrRegTrigger(TriggerFactory* factory)
|
||||
}
|
||||
|
||||
|
||||
extern "C" void* fbUdrGetFunction(const char* symbol)
|
||||
{
|
||||
return libraryModule->findSymbol(symbol);
|
||||
}
|
||||
|
||||
|
||||
ModulesMap::~ModulesMap()
|
||||
{
|
||||
FunctionNode* func = registeredFunctions;
|
||||
@ -600,7 +604,7 @@ template <typename T> T* Engine::findNode(T* nodes, const PathName& moduleName,
|
||||
{
|
||||
for (T* node = nodes; node; node = node->next)
|
||||
{
|
||||
if (node->module == moduleName && entryPoint == node->factory->getName())
|
||||
if (node->module == moduleName && entryPoint == node->name)
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -679,11 +683,11 @@ void FB_CALL Engine::closeAttachment(Error* error, ExternalContext* context)
|
||||
|
||||
|
||||
ExternalFunction* FB_CALL Engine::makeFunction(Error* error, ExternalContext* /*context*/,
|
||||
const IRoutineMetadata* metadata)
|
||||
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new SharedFunction(this, metadata);
|
||||
return new SharedFunction(this, metadata, inBlr, outBlr);
|
||||
}
|
||||
catch (const ThrowError::Exception& e)
|
||||
{
|
||||
@ -694,11 +698,11 @@ ExternalFunction* FB_CALL Engine::makeFunction(Error* error, ExternalContext* /*
|
||||
|
||||
|
||||
ExternalProcedure* FB_CALL Engine::makeProcedure(Error* error, ExternalContext* /*context*/,
|
||||
const IRoutineMetadata* metadata)
|
||||
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new SharedProcedure(this, metadata);
|
||||
return new SharedProcedure(this, metadata, inBlr, outBlr);
|
||||
}
|
||||
catch (const ThrowError::Exception& e)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user