8
0
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:
asfernandes 2011-07-10 01:23:53 +00:00
parent 4301830af3
commit cd7c8dee95
27 changed files with 968 additions and 420 deletions

View File

@ -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:

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;
};

View File

@ -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 {

View File

@ -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;
};

View File

@ -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);
//------------------------------------------------------------------------------

View File

@ -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},

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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

View File

@ -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 = &parameters[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 = &parameter->prm_desc;
if (parameter->prm_mechanism == prm_mech_type_of)
PreparedStatement::generateBlr(&parameter->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);

View File

@ -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;

View File

@ -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&);

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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)
{