8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +01:00

Migrate external triggers to the new message-based style.

This commit is contained in:
asfernandes 2013-01-29 01:21:32 +00:00
parent cdc7e4cd64
commit dc8e42e9bb
24 changed files with 623 additions and 210 deletions

View File

@ -662,7 +662,7 @@ create procedure gen_rows (
FB_UDR_BEGIN_PROCEDURE(gen_rows)
FB_UDR_EXECUTE_DYNAMIC_PROCEDURE
{
MessageImpl inMessage(2, inMsg);
MessageImpl inMessage(2, in);
ParamDesc<ISC_LONG> startDesc(inMessage);
ParamDesc<ISC_LONG> endDesc(inMessage);
@ -795,7 +795,6 @@ FB_UDR_BEGIN_PROCEDURE(inc)
FB_UDR_END_PROCEDURE
//// TODO: Rework triggers.
/***
Sample usage:
@ -828,6 +827,11 @@ create trigger persons_replicate
after insert on persons
external name 'udrcpp_example!replicate!ds1'
engine udr;
create trigger persons_replicate2
after insert on persons
external name 'udrcpp_example!replicate_persons!ds1'
engine udr;
***/
FB_UDR_BEGIN_TRIGGER(replicate)
FB_UDR_TRIGGER(replicate)()
@ -863,7 +867,7 @@ FB_UDR_BEGIN_TRIGGER(replicate)
unsigned fieldsCount = fields->getCount(status);
ThrowError::check(status->get());
MessageImpl message(fieldsCount, newMsg);
MessageImpl message(fieldsCount, newFields);
ISC_STATUS_ARRAY statusVector = {0};
isc_db_handle dbHandle = getIscDbHandle(context);
@ -905,11 +909,11 @@ FB_UDR_BEGIN_TRIGGER(replicate)
const char* table = metadata->getTriggerTable(status);
ThrowError::check(status->get());
// Skip the first exclamation point, separing the module name and entry point.
// Skip the first exclamation point, separating the module name and entry point.
const char* info = strchr(metadata->getEntryPoint(status), '!');
ThrowError::check(status->get());
// Skip the second exclamation point, separing the entry point and the misc info (config).
// Skip the second exclamation point, separating the entry point and the misc info (config).
if (info)
info = strchr(info + 1, '!');
@ -1046,7 +1050,7 @@ FB_UDR_BEGIN_TRIGGER(replicate)
break;
case SQL_FLOAT:
var->sqltype = SQL_DOUBLE | (var->sqltype & 1);
var->sqltype = SQL_DOUBLE;
var->sqllen = sizeof(double);
// fall into
@ -1069,8 +1073,155 @@ FB_UDR_BEGIN_TRIGGER(replicate)
}
var->sqltype |= 1;
var->sqlind = new short;
*reinterpret_cast<short*>(var->sqlind) = -1;
var->sqlind = new short(-1);
}
delete [] outSqlDa->sqlvar[0].sqldata;
delete [] reinterpret_cast<char*>(outSqlDa);
initialized = true;
}
bool initialized;
XSQLDA* inSqlDa;
isc_stmt_handle stmtHandle;
FB_UDR_END_TRIGGER
FB_UDR_BEGIN_TRIGGER(replicate_persons)
FB_UDR_TRIGGER(replicate_persons)()
: initialized(false)
{
}
~FB_UDR_TRIGGER(replicate_persons)()
{
if (!initialized)
return;
delete [] reinterpret_cast<char*>(inSqlDa);
ISC_STATUS_ARRAY statusVector = {0};
isc_dsql_free_statement(statusVector, &stmtHandle, DSQL_drop);
}
FB_UDR_EXECUTE_MESSAGE_TRIGGER(
(FB_INTEGER, id, "ID")
(FB_VARCHAR(60 * 4), address, "ADDRESS")
(FB_VARCHAR(60 * 4), name, "NAME")
(FB_BLOB, info, "INFO")
)
{
inSqlDa->sqlvar[0].sqldata = reinterpret_cast<char*>(&newFields->id);
inSqlDa->sqlvar[0].sqlind = &newFields->idNull;
inSqlDa->sqlvar[1].sqldata = reinterpret_cast<char*>(&newFields->name.length);
inSqlDa->sqlvar[1].sqlind = &newFields->nameNull;
inSqlDa->sqlvar[2].sqldata = reinterpret_cast<char*>(&newFields->address.length);
inSqlDa->sqlvar[2].sqlind = &newFields->addressNull;
inSqlDa->sqlvar[3].sqldata = reinterpret_cast<char*>(&newFields->info);
inSqlDa->sqlvar[3].sqlind = &newFields->infoNull;
ISC_STATUS_ARRAY statusVector = {0};
isc_db_handle dbHandle = getIscDbHandle(context);
isc_tr_handle trHandle = getIscTrHandle(context);
ThrowError::check(isc_dsql_execute(statusVector, &trHandle, &stmtHandle, SQL_DIALECT_CURRENT,
inSqlDa), statusVector);
}
FB_UDR_INITIALIZE
{
ISC_STATUS_ARRAY statusVector = {0};
isc_db_handle dbHandle = getIscDbHandle(context);
isc_tr_handle trHandle = getIscTrHandle(context);
stmtHandle = 0;
ThrowError::check(isc_dsql_allocate_statement(statusVector, &dbHandle, &stmtHandle), statusVector);
ThrowError::check(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0,
"select data_source from replicate_config where name = ?",
SQL_DIALECT_CURRENT, NULL), statusVector);
AutoDispose<IStatus> status(master->getStatus());
const char* table = metadata->getTriggerTable(status);
ThrowError::check(status->get());
// Skip the first exclamation point, separating the module name and entry point.
const char* info = strchr(metadata->getEntryPoint(status), '!');
ThrowError::check(status->get());
// Skip the second exclamation point, separating the entry point and the misc info (config).
if (info)
info = strchr(info + 1, '!');
if (info)
++info;
else
info = "";
inSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]);
inSqlDa->version = SQLDA_VERSION1;
inSqlDa->sqln = 1;
ThrowError::check(isc_dsql_describe_bind(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa),
statusVector);
inSqlDa->sqlvar[0].sqldata = new char[sizeof(short) + inSqlDa->sqlvar[0].sqllen];
strncpy(inSqlDa->sqlvar[0].sqldata + sizeof(short), info, inSqlDa->sqlvar[0].sqllen);
*reinterpret_cast<short*>(inSqlDa->sqlvar[0].sqldata) = strlen(info);
XSQLDA* outSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]);
outSqlDa->version = SQLDA_VERSION1;
outSqlDa->sqln = 1;
ThrowError::check(isc_dsql_describe(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, outSqlDa),
statusVector);
outSqlDa->sqlvar[0].sqldata = new char[sizeof(short) + outSqlDa->sqlvar[0].sqllen + 1];
outSqlDa->sqlvar[0].sqldata[sizeof(short) + outSqlDa->sqlvar[0].sqllen] = '\0';
ThrowError::check(isc_dsql_execute2(statusVector, &trHandle, &stmtHandle, SQL_DIALECT_CURRENT,
inSqlDa, outSqlDa), statusVector);
ThrowError::check(isc_dsql_free_statement(statusVector, &stmtHandle, DSQL_unprepare), statusVector);
delete [] inSqlDa->sqlvar[0].sqldata;
delete [] reinterpret_cast<char*>(inSqlDa);
inSqlDa = NULL;
const IParametersMetadata* fields = metadata->getTriggerFields(status);
ThrowError::check(status->get());
unsigned count = fields->getCount(status);
ThrowError::check(status->get());
char buffer[65536];
strcpy(buffer,
"execute block (\n"
" id type of column PERSONS.ID = ?,\n"
" name type of column PERSONS.NAME = ?,\n"
" address type of column PERSONS.ADDRESS = ?,\n"
" info type of column PERSONS.INFO = ?\n"
")"
"as\n"
"begin\n"
" execute statement ('insert into persons (id, name, address, info)\n"
" values (?, ?, ?, ?)') (:id, :name, :address, :info)\n"
" on external data source '");
strcat(buffer, outSqlDa->sqlvar[0].sqldata + sizeof(short));
strcat(buffer, "';\nend");
ThrowError::check(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0, buffer,
SQL_DIALECT_CURRENT, NULL), statusVector);
inSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(4))]);
inSqlDa->version = SQLDA_VERSION1;
inSqlDa->sqln = 4;
ThrowError::check(isc_dsql_describe_bind(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa),
statusVector);
for (unsigned i = 0; i < 4; ++i)
{
XSQLVAR* var = &inSqlDa->sqlvar[i];
var->sqltype |= 1;
}
delete [] outSqlDa->sqlvar[0].sqldata;

View File

@ -1504,6 +1504,10 @@ C --
PARAMETER (GDS__null_spb = 335545045)
INTEGER*4 GDS__max_args_exceeded
PARAMETER (GDS__max_args_exceeded = 335545046)
INTEGER*4 GDS__ee_blr_mismatch_names_count
PARAMETER (GDS__ee_blr_mismatch_names_count = 335545047)
INTEGER*4 GDS__ee_blr_mismatch_name_not_found
PARAMETER (GDS__ee_blr_mismatch_name_not_found = 335545048)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -759,6 +759,8 @@ const
gds_no_providers = 335545044;
gds_null_spb = 335545045;
gds_max_args_exceeded = 335545046;
gds_ee_blr_mismatch_names_count = 335545047;
gds_ee_blr_mismatch_name_not_found = 335545048;
gds_gfix_db_name = 335740929;
gds_gfix_invalid_sw = 335740930;
gds_gfix_incmp_sw = 335740932;

View File

@ -10764,11 +10764,11 @@ dsc* UdfCallNode::execute(thread_db* tdbb, jrd_req* request) const
dsc* const srcDesc = EVL_expr(tdbb, request, *sourcePtr);
if (srcDesc && !(request->req_flags & req_null))
{
*nullPtr = FALSE;
*nullPtr = 0;
MOV_move(tdbb, srcDesc, &argDesc);
}
else
*nullPtr = TRUE;
*nullPtr = -1;
}
}

View File

@ -38,12 +38,21 @@ namespace Firebird {
class ExternalEngine;
struct BlrMessage
class IRoutineMessage : public IVersioned
{
const unsigned char* blr;
unsigned int blrLength;
unsigned int bufferLength;
public:
virtual void FB_CARG set(const unsigned char* blr, unsigned blrLength, unsigned bufferLength) = 0;
};
#define FB_ROUTINE_MESSAGE_VERSION (FB_VERSIONED_VERSION + 1)
class ITriggerMessage : public IVersioned
{
public:
virtual void FB_CARG set(const unsigned char* blr, unsigned blrLength, unsigned bufferLength,
const char** names, unsigned count) = 0;
};
#define FB_TRIGGER_MESSAGE_VERSION (FB_VERSIONED_VERSION + 1)
// Connection to current database in external engine.
@ -193,11 +202,11 @@ 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, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
const IRoutineMetadata* metadata, IRoutineMessage* inMsg, IRoutineMessage* outMsg) = 0;
virtual ExternalProcedure* FB_CALL makeProcedure(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
const IRoutineMetadata* metadata, IRoutineMessage* inMsg, IRoutineMessage* outMsg) = 0;
virtual ExternalTrigger* FB_CALL makeTrigger(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata) = 0;
const IRoutineMetadata* metadata, ITriggerMessage* triggerMsg) = 0;
};
#define FB_EXTERNAL_ENGINE_VERSION (FB_PLUGIN_VERSION + 6)

View File

@ -30,54 +30,66 @@
#include <string.h>
#define FB_MESSAGE(name, fields) \
FB_MESSAGE_I(name, FB_BOOST_PP_CAT(FB_MESSAGE_X fields, 0))
struct name \
{ \
FB_MESSAGE_I(name, 2, FB_BOOST_PP_CAT(FB_MESSAGE_X fields, 0)) \
}
#define FB_MESSAGE_X(x, y) ((x, y)) FB_MESSAGE_Y
#define FB_MESSAGE_Y(x, y) ((x, y)) FB_MESSAGE_X
#define FB_MESSAGE_X0
#define FB_MESSAGE_Y0
#define FB_MESSAGE_I(name, fields) \
#define FB_TRIGGER_MESSAGE(name, fields) \
struct name \
{ \
static const unsigned char* getBlr(unsigned* length) \
{ \
static const unsigned char blr[] = { \
blr_version5, \
blr_begin, \
blr_message, 0, \
(2 * (FB_BOOST_PP_SEQ_SIZE(fields))) & 0xFF, \
(2 * (FB_BOOST_PP_SEQ_SIZE(fields))) >> 8, \
FB_BOOST_PP_SEQ_FOR_EACH_I(FB_MESSAGE_BLR, _, fields) \
blr_end, \
blr_eoc \
}; \
*length = sizeof(blr); \
return blr; \
} \
\
static unsigned getSize() \
{ \
return (unsigned)(size_t) (&((name*) 0)->FB_BOOST_PP_CAT( \
FB_BOOST_PP_TUPLE_ELEM(2, 1, \
FB_BOOST_PP_SEQ_ELEM(FB_BOOST_PP_DEC(FB_BOOST_PP_SEQ_SIZE(fields)), fields)), \
Null) - 0) + sizeof(ISC_SHORT); \
} \
\
void clear() \
{ \
memset(this, 0, sizeof(*this)); \
} \
\
FB_BOOST_PP_SEQ_FOR_EACH_I(FB_MESSAGE_FIELD, _, fields) \
FB_MESSAGE_I(name, 3, FB_BOOST_PP_CAT(FB_TRIGGER_MESSAGE_X fields, 0)) \
FB_TRIGGER_MESSAGE_NAMES_I(name, 3, FB_BOOST_PP_CAT(FB_TRIGGER_MESSAGE_NAMES_X fields, 0)) \
}
#define FB_TRIGGER_MESSAGE_X(x, y, z) ((x, y, z)) FB_TRIGGER_MESSAGE_Y
#define FB_TRIGGER_MESSAGE_Y(x, y, z) ((x, y, z)) FB_TRIGGER_MESSAGE_X
#define FB_TRIGGER_MESSAGE_X0
#define FB_TRIGGER_MESSAGE_Y0
#define FB_MESSAGE_I(name, size, fields) \
static const unsigned char* getBlr(unsigned* length) \
{ \
static const unsigned char blr[] = { \
blr_version5, \
blr_begin, \
blr_message, 0, \
(2 * (FB_BOOST_PP_SEQ_SIZE(fields))) & 0xFF, \
(2 * (FB_BOOST_PP_SEQ_SIZE(fields))) >> 8, \
FB_BOOST_PP_SEQ_FOR_EACH_I(FB_MESSAGE_BLR, size, fields) \
blr_end, \
blr_eoc \
}; \
*length = sizeof(blr); \
return blr; \
} \
\
static unsigned getSize() \
{ \
return (unsigned)(size_t) (&((name*) 0)->FB_BOOST_PP_CAT( \
FB_BOOST_PP_TUPLE_ELEM(size, 1, \
FB_BOOST_PP_SEQ_ELEM(FB_BOOST_PP_DEC(FB_BOOST_PP_SEQ_SIZE(fields)), fields)), \
Null) - 0) + sizeof(ISC_SHORT); \
} \
\
void clear() \
{ \
memset(this, 0, sizeof(*this)); \
} \
\
FB_BOOST_PP_SEQ_FOR_EACH_I(FB_MESSAGE_FIELD, size, fields)
#define FB_MESSAGE_FIELD(r, _, i, xy) \
FB_BOOST_PP_CAT(FB_TYPE_, FB_BOOST_PP_TUPLE_ELEM(2, 0, xy)) FB_BOOST_PP_TUPLE_ELEM(2, 1, xy); \
ISC_SHORT FB_BOOST_PP_CAT(FB_BOOST_PP_TUPLE_ELEM(2, 1, xy), Null);
FB_BOOST_PP_CAT(FB_TYPE_, FB_BOOST_PP_TUPLE_ELEM(_, 0, xy)) FB_BOOST_PP_TUPLE_ELEM(_, 1, xy); \
ISC_SHORT FB_BOOST_PP_CAT(FB_BOOST_PP_TUPLE_ELEM(_, 1, xy), Null);
#define FB_MESSAGE_BLR(r, _, i, xy) \
FB_BOOST_PP_CAT(FB_BLR_, FB_BOOST_PP_TUPLE_ELEM(2, 0, xy)), \
FB_BOOST_PP_CAT(FB_BLR_, FB_BOOST_PP_TUPLE_ELEM(_, 0, xy)), \
FB_BLR_FB_SMALLINT,
#define FB_BLR_FB_SCALED_SMALLINT(scale) blr_short, (scale)
@ -126,6 +138,44 @@
} \
}
#define FB_TRIGGER_MESSAGE_DESC(name, fields) \
FB_TRIGGER_MESSAGE(name, fields); \
struct name##Desc : public name \
{ \
::Firebird::FbMessage desc; \
\
name##Desc() \
{ \
desc.blr = getBlr(&desc.blrLength); \
desc.buffer = (unsigned char*) this; \
desc.bufferLength = getSize(); \
} \
}
#define FB_TRIGGER_MESSAGE_NAMES(name, fields) \
FB_TRIGGER_MESSAGE_NAMES_I(name, 3, FB_BOOST_PP_CAT(FB_TRIGGER_MESSAGE_NAMES_X fields, 0))
#define FB_TRIGGER_MESSAGE_NAMES_X(x, y, z) ((x, y, z)) FB_TRIGGER_MESSAGE_NAMES_Y
#define FB_TRIGGER_MESSAGE_NAMES_Y(x, y, z) ((x, y, z)) FB_TRIGGER_MESSAGE_NAMES_X
#define FB_TRIGGER_MESSAGE_NAMES_X0
#define FB_TRIGGER_MESSAGE_NAMES_Y0
#define FB_TRIGGER_MESSAGE_NAMES_I(name, size, fields) \
static const char** getNames(unsigned* count) \
{ \
*count = FB_BOOST_PP_SEQ_SIZE(fields); \
\
static const char* names[] = { \
FB_BOOST_PP_SEQ_FOR_EACH_I(FB_TRIGGER_MESSAGE_NAME, size, fields) \
NULL \
}; \
\
return names; \
}
#define FB_TRIGGER_MESSAGE_NAME(r, _, i, xy) \
FB_BOOST_PP_TUPLE_ELEM(_, 2, xy),
namespace Firebird {

View File

@ -86,11 +86,11 @@ namespace Firebird
#define FB_UDR_EXECUTE__FUNCTION \
virtual void FB_CALL execute(::Firebird::Error* error, ::Firebird::ExternalContext* context, \
void* inMsg, void* outMsg) \
void* in, void* out) \
{ \
try \
{ \
internalExecute(error, context, (InMessage*) inMsg, (OutMessage*) outMsg); \
internalExecute(error, context, (InMessage*) in, (OutMessage*) out); \
} \
FB_UDR__CATCH \
} \
@ -151,11 +151,11 @@ namespace Firebird
#define FB_UDR_EXECUTE__PROCEDURE \
virtual ::Firebird::ExternalResultSet* FB_CALL open(::Firebird::Error* error, \
::Firebird::ExternalContext* context, void* inMsg, void* outMsg) \
::Firebird::ExternalContext* context, void* in, void* out) \
{ \
try \
{ \
return new ResultSet(error, context, this, (InMessage*) inMsg, (OutMessage*) outMsg); \
return new ResultSet(error, context, this, (InMessage*) in, (OutMessage*) out); \
} \
FB_UDR__CATCH \
\
@ -166,9 +166,9 @@ namespace Firebird
{ \
public: \
ResultSet(::Firebird::Error* error, ::Firebird::ExternalContext* context, \
This* procedure, InMessage* inMsg, OutMessage* outMsg) \
This* const procedure, InMessage* const in, OutMessage* const out) \
: ::Firebird::Udr::ResultSet<ResultSet, This, InMessage, OutMessage>( \
context, procedure, inMsg, outMsg)
context, procedure, in, out)
#define FB_UDR_FETCH_PROCEDURE \
virtual bool FB_CALL fetch(::Firebird::Error* error) \
@ -202,21 +202,30 @@ namespace Firebird
};
#define FB_UDR_EXECUTE_DYNAMIC_TRIGGER \
typedef void* FieldsMessage; \
\
FB_UDR_EXECUTE__TRIGGER
#define FB_UDR_EXECUTE_MESSAGE_TRIGGER(fields) \
FB_TRIGGER_MESSAGE(FieldsMessage, \
fields \
); \
\
FB_UDR_EXECUTE__TRIGGER
#define FB_UDR_EXECUTE__TRIGGER \
virtual void FB_CALL execute(::Firebird::Error* error, ::Firebird::ExternalContext* context, \
::Firebird::ExternalTrigger::Action action, void* oldMsg, void* newMsg) \
::Firebird::ExternalTrigger::Action action, void* oldFields, void* newFields) \
{ \
try \
{ \
internalExecute(error, context, action, oldMsg, newMsg); \
internalExecute(error, context, action, (FieldsMessage*) oldFields, (FieldsMessage*) newFields); \
} \
FB_UDR__CATCH \
} \
\
void internalExecute(::Firebird::Error* error, ::Firebird::ExternalContext* context, \
::Firebird::ExternalTrigger::Action action, void* oldMsg, void* newMsg)
::Firebird::ExternalTrigger::Action action, FieldsMessage* oldFields, FieldsMessage* newFields)
#define FB_UDR_INITIALIZE \
@ -499,10 +508,10 @@ public:
}
protected:
Firebird::ExternalContext* context;
Procedure* procedure;
InMessage* in;
OutMessage* out;
Firebird::ExternalContext* const context;
Procedure* const procedure;
InMessage* const in;
OutMessage* const out;
};
@ -620,10 +629,10 @@ public:
}
virtual void setup(Error* /*error*/, ExternalContext* /*context*/,
const IRoutineMetadata* /*metadata*/, BlrMessage* inBlr, BlrMessage* outBlr)
const IRoutineMetadata* /*metadata*/, IRoutineMessage* in, IRoutineMessage* out)
{
setBlr(inBlr, (typename T::InMessage*) 0);
setBlr(outBlr, (typename T::OutMessage*) 0);
setBlr(in, (typename T::InMessage*) 0);
setBlr(out, (typename T::OutMessage*) 0);
}
virtual ExternalFunction* FB_CALL newItem(Error* error, ExternalContext* context,
@ -635,13 +644,14 @@ public:
}
private:
template <typename MessageType> void setBlr(BlrMessage* blrMessage, MessageType*)
template <typename MessageType> void setBlr(IRoutineMessage* blrMessage, MessageType*)
{
blrMessage->blr = MessageType::getBlr(&blrMessage->blrLength);
blrMessage->bufferLength = MessageType::getSize();
unsigned blrLength;
const unsigned char* blr = MessageType::getBlr(&blrLength);
blrMessage->set(blr, blrLength, MessageType::getSize());
}
void setBlr(BlrMessage* blrMessage, void**)
void setBlr(IRoutineMessage* /*blrMessage*/, void**)
{
}
};
@ -656,10 +666,10 @@ public:
}
virtual void setup(Error* /*error*/, ExternalContext* /*context*/,
const IRoutineMetadata* /*metadata*/, BlrMessage* inBlr, BlrMessage* outBlr)
const IRoutineMetadata* /*metadata*/, IRoutineMessage* in, IRoutineMessage* out)
{
setBlr(inBlr, (typename T::InMessage*) 0);
setBlr(outBlr, (typename T::OutMessage*) 0);
setBlr(in, (typename T::InMessage*) 0);
setBlr(out, (typename T::OutMessage*) 0);
}
virtual ExternalProcedure* FB_CALL newItem(Error* error, ExternalContext* context,
@ -671,13 +681,14 @@ public:
}
private:
template <typename MessageType> void setBlr(BlrMessage* blrMessage, MessageType*)
template <typename MessageType> void setBlr(IRoutineMessage* blrMessage, MessageType*)
{
blrMessage->blr = MessageType::getBlr(&blrMessage->blrLength);
blrMessage->bufferLength = MessageType::getSize();
unsigned blrLength;
const unsigned char* blr = MessageType::getBlr(&blrLength);
blrMessage->set(blr, blrLength, MessageType::getSize());
}
void setBlr(BlrMessage* blrMessage, void**)
void setBlr(IRoutineMessage* /*blrMessage*/, void**)
{
}
};
@ -692,8 +703,9 @@ public:
}
virtual void setup(Error* /*error*/, ExternalContext* /*context*/,
const IRoutineMetadata* /*metadata*/)
const IRoutineMetadata* /*metadata*/, ITriggerMessage* fields)
{
setBlr(fields, (typename T::FieldsMessage*) 0);
}
virtual ExternalTrigger* FB_CALL newItem(Error* error, ExternalContext* context,
@ -703,6 +715,20 @@ public:
obj->initialize(error, context);
return obj;
}
private:
template <typename MessageType> void setBlr(ITriggerMessage* blrMessage, MessageType*)
{
unsigned blrLength, namesCount;
const unsigned char* blr = MessageType::getBlr(&blrLength);
const char** names = MessageType::getNames(&namesCount);
blrMessage->set(blr, blrLength, MessageType::getSize(), names, namesCount);
}
void setBlr(ITriggerMessage* /*blrMessage*/, void**)
{
}
};

View File

@ -40,7 +40,7 @@ class FunctionFactory
{
public:
virtual void setup(Error* error, ExternalContext* context, const IRoutineMetadata* metadata,
BlrMessage* inBlr, BlrMessage* outBlr) = 0;
IRoutineMessage* in, IRoutineMessage* out) = 0;
virtual ExternalFunction* FB_CALL newItem(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata) = 0;
};
@ -49,7 +49,7 @@ class ProcedureFactory
{
public:
virtual void setup(Error* error, ExternalContext* context, const IRoutineMetadata* metadata,
BlrMessage* inBlr, BlrMessage* outBlr) = 0;
IRoutineMessage* in, IRoutineMessage* out) = 0;
virtual ExternalProcedure* FB_CALL newItem(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata) = 0;
};
@ -57,7 +57,8 @@ public:
class TriggerFactory
{
public:
virtual void setup(Error* error, ExternalContext* context, const IRoutineMetadata* metadata) = 0;
virtual void setup(Error* error, ExternalContext* context, const IRoutineMetadata* metadata,
ITriggerMessage* fields) = 0;
virtual ExternalTrigger* FB_CALL newItem(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata) = 0;
};

View File

@ -748,6 +748,8 @@ static const struct {
{"no_providers", 335545044},
{"null_spb", 335545045},
{"max_args_exceeded", 335545046},
{"ee_blr_mismatch_names_count", 335545047},
{"ee_blr_mismatch_name_not_found", 335545048},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -782,6 +782,8 @@ const ISC_STATUS isc_decrypt_error = 335545043L;
const ISC_STATUS isc_no_providers = 335545044L;
const ISC_STATUS isc_null_spb = 335545045L;
const ISC_STATUS isc_max_args_exceeded = 335545046L;
const ISC_STATUS isc_ee_blr_mismatch_names_count = 335545047L;
const ISC_STATUS isc_ee_blr_mismatch_name_not_found = 335545048L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1226,7 +1228,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 = 1170;
const ISC_STATUS isc_err_max = 1172;
#else /* c definitions */
@ -1978,6 +1980,8 @@ const ISC_STATUS isc_err_max = 1170;
#define isc_no_providers 335545044L
#define isc_null_spb 335545045L
#define isc_max_args_exceeded 335545046L
#define isc_ee_blr_mismatch_names_count 335545047L
#define isc_ee_blr_mismatch_name_not_found 335545048L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2422,7 +2426,7 @@ const ISC_STATUS isc_err_max = 1170;
#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 1170
#define isc_err_max 1172
#endif

View File

@ -751,6 +751,8 @@ Data source : @4"}, /* eds_statement */
{335545044, "No providers loaded"}, /* no_providers */
{335545045, "NULL data with non-zero SPB length"}, /* null_spb */
{335545046, "Maximum (@1) number of arguments exceeded for function @2"}, /* max_args_exceeded */
{335545047, "External BLR message mismatch: names count = @1, blr count = @2"}, /* ee_blr_mismatch_names_count */
{335545048, "External BLR message mismatch: name @1 not found"}, /* ee_blr_mismatch_name_not_found */
{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

@ -747,6 +747,8 @@ static const struct {
{335545044, -902}, /* 724 no_providers */
{335545045, -104}, /* 725 null_spb */
{335545046, -833}, /* 726 max_args_exceeded */
{335545047, -901}, /* 727 ee_blr_mismatch_names_count */
{335545048, -901}, /* 728 ee_blr_mismatch_name_not_found */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -747,6 +747,8 @@ static const struct {
{335545044, "39000"}, // 724 no_providers
{335545045, "42818"}, // 725 null_spb
{335545046, "42000"}, // 726 max_args_exceeded
{335545047, "42000"}, // 727 ee_blr_mismatch_names_count
{335545048, "42000"}, // 728 ee_blr_mismatch_name_not_found
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -41,6 +41,7 @@
#include "../jrd/intl_proto.h"
#include "../jrd/met_proto.h"
#include "../jrd/mov_proto.h"
#include "../jrd/par_proto.h"
#include "../jrd/thread_proto.h"
#include "../jrd/Function.h"
#include "../common/isc_proto.h"
@ -408,16 +409,140 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb)
//---------------------
ExtEngineManager::Trigger::Trigger(thread_db* tdbb, ExtEngineManager* aExtManager,
ExternalEngine* aEngine, RoutineMetadata* aMetadata, ExternalTrigger* aTrigger,
const Jrd::Trigger* aTrg)
ExtEngineManager::Trigger::Trigger(thread_db* tdbb, MemoryPool& pool, ExtEngineManager* aExtManager,
ExternalEngine* aEngine, RoutineMetadata* aMetadata, TriggerMessage& fieldsMsg,
ExternalTrigger* aTrigger, const Jrd::Trigger* aTrg)
: extManager(aExtManager),
engine(aEngine),
metadata(aMetadata),
trigger(aTrigger),
trg(aTrg),
fieldsPos(pool),
database(tdbb->getDatabase())
{
dsc shortDesc;
shortDesc.makeShort(0);
jrd_rel* relation = trg->relation;
if (relation)
{
bool blrPresent = fieldsMsg.blr.hasData();
Format* relFormat = relation->rel_current_format;
GenericMap<Left<MetaName, USHORT> > fieldsMap;
for (size_t i = 0; i < relation->rel_fields->count(); ++i)
{
jrd_fld* field = (*relation->rel_fields)[i];
if (!field)
continue;
fieldsMap.put(field->fld_name, (USHORT) i);
}
BlrReader reader(fieldsMsg.blr.begin(), fieldsMsg.blr.getCount());
ULONG offset = 0;
USHORT maxAlignment = 0;
USHORT count;
if (blrPresent)
{
reader.checkByte(blr_version5);
reader.checkByte(blr_begin);
reader.checkByte(blr_message);
reader.getByte(); // message number: ignore it
count = reader.getWord();
if (count != 2 * fieldsMsg.names.getCount())
{
status_exception::raise(
Arg::Gds(isc_ee_blr_mismatch_names_count) <<
Arg::Num(fieldsMsg.names.getCount()) <<
Arg::Num(count));
}
}
else
count = fieldsMap.count() * 2;
format.reset(Format::newFormat(pool, count));
for (unsigned i = 0; i < count / 2; ++i)
{
dsc* desc = &format->fmt_desc[i * 2];
if (blrPresent)
{
USHORT pos;
if (!fieldsMap.get(fieldsMsg.names[i], pos))
{
status_exception::raise(
Arg::Gds(isc_ee_blr_mismatch_name_not_found) <<
Arg::Str(fieldsMsg.names[i]));
}
fieldsPos.add(pos);
PAR_datatype(tdbb, reader, desc);
}
else
{
fieldsPos.add(i);
*desc = relFormat->fmt_desc[i];
}
USHORT align = type_alignments[desc->dsc_dtype];
maxAlignment = MAX(maxAlignment, align);
offset = FB_ALIGN(offset, align);
desc->dsc_address = (UCHAR*) offset;
offset += desc->dsc_length;
const dsc* fieldDesc = &relFormat->fmt_desc[i];
if (desc->isText() && desc->getCharSet() == CS_NONE)
desc->setTextType(fieldDesc->getTextType());
desc->setNullable(fieldDesc->isNullable());
++desc;
if (blrPresent)
{
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));
}
}
else
*desc = shortDesc;
align = type_alignments[desc->dsc_dtype];
maxAlignment = MAX(maxAlignment, align);
offset = FB_ALIGN(offset, align);
desc->dsc_address = (UCHAR*) offset;
offset += desc->dsc_length;
}
if (blrPresent)
{
reader.checkByte(blr_end);
reader.checkByte(blr_eoc);
if (offset != fieldsMsg.bufferLength)
{
status_exception::raise(
Arg::Gds(isc_ee_blr_mismatch_length) <<
Arg::Num(fieldsMsg.bufferLength) <<
Arg::Num(offset));
}
}
format->fmt_length = FB_ALIGN(offset, maxAlignment);
}
}
@ -444,85 +569,73 @@ void ExtEngineManager::Trigger::execute(thread_db* tdbb, ExternalTrigger::Action
if (newRpb)
setValues(tdbb, newMsg, newRpb);
Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION);
{ // scope
Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION);
trigger->execute(RaiseError(), attInfo->context, action,
(oldRpb ? oldMsg.begin() : NULL), (newRpb ? newMsg.begin() : NULL));
trigger->execute(RaiseError(), attInfo->context, action,
(oldRpb ? oldMsg.begin() : NULL), (newRpb ? newMsg.begin() : NULL));
}
if (newRpb)
{
// Move data back from the message to the record.
Record* record = newRpb->rpb_record;
const Format* format = record->rec_format;
const UCHAR* msg = newMsg.begin();
unsigned pos = 0;
UCHAR* p = newMsg.begin();
for (unsigned i = 0; i < format->fmt_count; ++i)
for (unsigned i = 0; i < format->fmt_count / 2; ++i)
{
if (format->fmt_desc[i].dsc_dtype == dtype_unknown)
continue;
USHORT fieldPos = fieldsPos[i];
dsc desc;
bool readonly = !EVL_field(newRpb->rpb_relation, record, i, &desc) &&
desc.dsc_address && !(desc.dsc_flags & DSC_null);
unsigned align = type_alignments[desc.dsc_dtype];
if (align)
pos = FB_ALIGN(pos, align);
const unsigned dataPos = pos;
pos += desc.dsc_length;
align = type_alignments[dtype_short];
if (align)
pos = FB_ALIGN(pos, align);
dsc target;
bool readonly = !EVL_field(newRpb->rpb_relation, record, fieldPos, &target) &&
target.dsc_address && !(target.dsc_flags & DSC_null);
if (!readonly)
{
if (*(USHORT*) &msg[pos])
SET_NULL(record, i);
else
{
memcpy(desc.dsc_address, msg + dataPos, desc.dsc_length);
CLEAR_NULL(record, i);
}
}
SSHORT* nullSource = (SSHORT*) (p + (IPTR) format->fmt_desc[i * 2 + 1].dsc_address);
pos += sizeof(USHORT);
if (*nullSource == 0)
{
dsc source = format->fmt_desc[i * 2];
source.dsc_address += (IPTR) p;
MOV_move(tdbb, &source, &target);
CLEAR_NULL(record, fieldPos);
}
else
SET_NULL(record, fieldPos);
}
}
}
}
void ExtEngineManager::Trigger::setValues(thread_db* /*tdbb*/, Array<UCHAR>& msgBuffer,
void ExtEngineManager::Trigger::setValues(thread_db* tdbb, Array<UCHAR>& msgBuffer,
record_param* rpb) const
{
if (!rpb || !rpb->rpb_record)
return;
Record* record = rpb->rpb_record;
const Format* format = record->rec_format;
UCHAR* p = msgBuffer.getBuffer(format->fmt_length);
///memset(p, 0, format->fmt_length);
for (unsigned i = 0; i < format->fmt_count; ++i)
for (unsigned i = 0; i < format->fmt_count / 2; ++i)
{
if (format->fmt_desc[i].dsc_dtype == dtype_unknown)
continue;
USHORT fieldPos = fieldsPos[i];
dsc desc;
EVL_field(rpb->rpb_relation, record, i, &desc);
dsc source;
EVL_field(rpb->rpb_relation, rpb->rpb_record, fieldPos, &source);
// CVC: I'm not sure why it's not important to check EVL_field's result.
unsigned align = type_alignments[desc.dsc_dtype];
if (align)
msgBuffer.resize(FB_ALIGN(msgBuffer.getCount(), align));
SSHORT* nullTarget = (SSHORT*) (p + (IPTR) format->fmt_desc[i * 2 + 1].dsc_address);
*nullTarget = (source.dsc_flags & DSC_null) != 0 ? -1 : 0;
msgBuffer.add(desc.dsc_address, desc.dsc_length);
align = type_alignments[dtype_short];
if (align)
msgBuffer.resize(FB_ALIGN(msgBuffer.getCount(), align));
USHORT nullFlag = (desc.dsc_flags & DSC_null) != 0;
msgBuffer.add((UCHAR*) &nullFlag, sizeof(nullFlag));
if (*nullTarget == 0)
{
dsc target = format->fmt_desc[i * 2];
target.dsc_address += (IPTR) p;
MOV_move(tdbb, &source, &target);
}
}
}
@ -598,7 +711,7 @@ 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,
BlrMessage* inBlr, BlrMessage* outBlr)
RoutineMessage* inMsg, RoutineMessage* outMsg)
{
string entryPointTrimmed = entryPoint;
entryPointTrimmed.trim();
@ -657,7 +770,7 @@ ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, cons
Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION);
externalFunction = attInfo->engine->makeFunction(RaiseError(), attInfo->context, metadata,
inBlr, outBlr);
inMsg, outMsg);
if (!externalFunction)
{
@ -683,7 +796,7 @@ 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,
BlrMessage* inBlr, BlrMessage* outBlr)
RoutineMessage* inMsg, RoutineMessage* outMsg)
{
string entryPointTrimmed = entryPoint;
entryPointTrimmed.trim();
@ -736,7 +849,7 @@ ExtEngineManager::Procedure* ExtEngineManager::makeProcedure(thread_db* tdbb, co
Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION);
externalProcedure = attInfo->engine->makeProcedure(RaiseError(), attInfo->context, metadata,
inBlr, outBlr);
inMsg, outMsg);
if (!externalProcedure)
{
@ -761,7 +874,8 @@ ExtEngineManager::Procedure* ExtEngineManager::makeProcedure(thread_db* tdbb, co
ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const Jrd::Trigger* trg,
const MetaName& engine, const string& entryPoint, const string& body, ExternalTrigger::Type type)
const MetaName& engine, const string& entryPoint, const string& body,
ExternalTrigger::Type type)
{
string entryPointTrimmed = entryPoint;
entryPointTrimmed.trim();
@ -807,12 +921,14 @@ ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const
}
}
TriggerMessage fieldsMsg(pool);
ExternalTrigger* externalTrigger;
{ // scope
Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION);
externalTrigger = attInfo->engine->makeTrigger(RaiseError(), attInfo->context, metadata);
externalTrigger = attInfo->engine->makeTrigger(RaiseError(), attInfo->context, metadata,
&fieldsMsg);
if (!externalTrigger)
{
@ -823,8 +939,8 @@ ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const
try
{
return FB_NEW(getPool()) Trigger(tdbb, this, attInfo->engine, metadata.release(),
externalTrigger, trg);
return FB_NEW(getPool()) Trigger(tdbb, pool, this, attInfo->engine, metadata.release(),
fieldsMsg, externalTrigger, trg);
}
catch (...)
{

View File

@ -52,6 +52,58 @@ struct impure_value;
struct record_param;
class RoutineMessage :
public Firebird::VersionedIface<Firebird::IRoutineMessage, FB_ROUTINE_MESSAGE_VERSION>,
public Firebird::PermanentStorage
{
public:
explicit RoutineMessage(MemoryPool& pool)
: PermanentStorage(pool),
blr(pool),
bufferLength(0)
{
}
virtual void FB_CARG set(const unsigned char* aBlr, unsigned aBlrLength, unsigned aBufferLength)
{
blr.assign(aBlr, aBlrLength);
bufferLength = aBufferLength;
}
public:
Firebird::Array<UCHAR> blr;
unsigned bufferLength;
};
class TriggerMessage :
public Firebird::VersionedIface<Firebird::ITriggerMessage, FB_TRIGGER_MESSAGE_VERSION>,
public Firebird::PermanentStorage
{
public:
explicit TriggerMessage(MemoryPool& pool)
: PermanentStorage(pool),
names(pool),
blr(pool),
bufferLength(0)
{
}
virtual void FB_CARG set(const unsigned char* aBlr, unsigned aBlrLength, unsigned aBufferLength,
const char** aNames, unsigned aCount)
{
blr.assign(aBlr, aBlrLength);
bufferLength = aBufferLength;
for (unsigned i = 0; i < aCount; ++i)
names.add(aNames[i]);
}
public:
Firebird::ObjectsArray<Firebird::string> names;
Firebird::Array<UCHAR> blr;
unsigned bufferLength;
};
class ExtEngineManager : public Firebird::PermanentStorage
{
private:
@ -59,8 +111,9 @@ private:
template <typename T> class ContextManager;
class TransactionImpl;
class RoutineMetadata : public Firebird::VersionedIface<Firebird::IRoutineMetadata, FB_ROUTINE_METADATA_VERSION>,
public Firebird::PermanentStorage
class RoutineMetadata :
public Firebird::VersionedIface<Firebird::IRoutineMetadata, FB_ROUTINE_METADATA_VERSION>,
public Firebird::PermanentStorage
{
public:
explicit RoutineMetadata(MemoryPool& pool)
@ -264,11 +317,9 @@ public:
class Trigger
{
public:
Trigger(thread_db* tdbb, ExtEngineManager* aExtManager,
Firebird::ExternalEngine* aEngine,
RoutineMetadata* aMetadata,
Firebird::ExternalTrigger* aTrigger,
const Jrd::Trigger* aTrg);
Trigger(thread_db* tdbb, MemoryPool& pool, ExtEngineManager* aExtManager,
Firebird::ExternalEngine* aEngine, RoutineMetadata* aMetadata, TriggerMessage& fieldsMsg,
Firebird::ExternalTrigger* aTrigger, const Jrd::Trigger* aTrg);
~Trigger();
void execute(thread_db* tdbb, Firebird::ExternalTrigger::Action action,
@ -280,8 +331,10 @@ public:
ExtEngineManager* extManager;
Firebird::ExternalEngine* engine;
Firebird::AutoPtr<RoutineMetadata> metadata;
Firebird::AutoPtr<Format> format;
Firebird::ExternalTrigger* trigger;
const Jrd::Trigger* trg;
Firebird::Array<USHORT> fieldsPos;
Database* database;
};
@ -303,10 +356,10 @@ public:
Function* makeFunction(thread_db* tdbb, const Jrd::Function* udf,
const Firebird::MetaName& engine, const Firebird::string& entryPoint,
const Firebird::string& body, Firebird::BlrMessage* inBlr, Firebird::BlrMessage* outBlr);
const Firebird::string& body, RoutineMessage* inMsg, RoutineMessage* outMsg);
Procedure* makeProcedure(thread_db* tdbb, const jrd_prc* prc,
const Firebird::MetaName& engine, const Firebird::string& entryPoint,
const Firebird::string& body, Firebird::BlrMessage* inBlr, Firebird::BlrMessage* outBlr);
const Firebird::string& body, RoutineMessage* inMsg, RoutineMessage* outMsg);
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

@ -374,15 +374,8 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
function->fun_external = NULL;
function->setStatement(NULL);
BlrMessage inBlr;
inBlr.blr = NULL;
inBlr.blrLength = 0;
inBlr.bufferLength = 0;
BlrMessage outBlr;
outBlr.blr = NULL;
outBlr.blrLength = 0;
outBlr.bufferLength = 0;
RoutineMessage inMsg(*attachment->att_pool);
RoutineMessage outMsg(*attachment->att_pool);
if (!X.RDB$ENGINE_NAME.NULL || !X.RDB$FUNCTION_BLR.NULL)
{
@ -403,7 +396,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
function->fun_external =
dbb->dbb_extManager.makeFunction(tdbb, function, X.RDB$ENGINE_NAME,
(X.RDB$ENTRYPOINT.NULL ? "" : X.RDB$ENTRYPOINT), (char*) body.begin(),
&inBlr, &outBlr);
&inMsg, &outMsg);
if (!function->fun_external)
function->setDefined(false);
@ -422,7 +415,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
try
{
MET_parse_routine_blr(tdbb, function, &X.RDB$FUNCTION_BLR, csb,
!X.RDB$ENGINE_NAME.NULL, inBlr, outBlr);
!X.RDB$ENGINE_NAME.NULL, inMsg, outMsg);
}
catch (const Exception&)
{

View File

@ -5651,7 +5651,7 @@ static bool modify_function(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
try
{
BlrMessage dummy;
RoutineMessage dummy(*csb_pool);
MET_parse_routine_blr(tdbb, function, &FUN.RDB$FUNCTION_BLR, csb, false,
dummy, dummy);

View File

@ -642,10 +642,9 @@ void Trigger::compile(thread_db* tdbb)
return;
extTrigger = dbb->dbb_extManager.makeTrigger(tdbb, this, engine, entryPoint, extBody.c_str(),
(relation ? (type & 1 ?
Firebird::ExternalTrigger::TYPE_BEFORE :
Firebird::ExternalTrigger::TYPE_AFTER) :
Firebird::ExternalTrigger::TYPE_DATABASE));
(relation ?
(type & 1 ? ExternalTrigger::TYPE_BEFORE : ExternalTrigger::TYPE_AFTER) :
Firebird::ExternalTrigger::TYPE_DATABASE));
}
void Trigger::release(thread_db* tdbb)

View File

@ -2975,15 +2975,8 @@ 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;
RoutineMessage inMsg(*tdbb->getDefaultPool());
RoutineMessage outMsg(*tdbb->getDefaultPool());
const bool external = !P.RDB$ENGINE_NAME.NULL; // ODS_12_0
@ -3004,7 +2997,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
procedure->setExternal(dbb->dbb_extManager.makeProcedure(
tdbb, procedure, P.RDB$ENGINE_NAME,
(P.RDB$ENTRYPOINT.NULL ? "" : P.RDB$ENTRYPOINT), body.begin(), &inBlr, &outBlr));
(P.RDB$ENTRYPOINT.NULL ? "" : P.RDB$ENTRYPOINT), body.begin(), &inMsg, &outMsg));
}
Array<NestConst<Parameter> >& paramArray = procedure->getOutputFields();
@ -3055,7 +3048,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
{
MET_parse_routine_blr(tdbb, procedure,
(P.RDB$PROCEDURE_BLR.NULL ? NULL : &P.RDB$PROCEDURE_BLR), csb, external,
inBlr, outBlr);
inMsg, outMsg);
}
catch (const Exception&)
{
@ -4304,7 +4297,7 @@ static void parse_field_validation_blr(thread_db* tdbb, bid* blob_id, const Meta
// Generate BLR message for external procedures
static bool gen_ext_message(thread_db* tdbb, CompilerScratch* csb, UCharBuffer& blr, UCHAR message,
UCHAR message2, const Array<NestConst<Parameter> >& parameters, const BlrMessage& extBlr,
UCHAR message2, const Array<NestConst<Parameter> >& parameters, const RoutineMessage& extMsg,
UCharBuffer& appendBlr)
{
const size_t prevAppendBlrSize = appendBlr.getCount();
@ -4315,9 +4308,9 @@ static bool gen_ext_message(thread_db* tdbb, CompilerScratch* csb, UCharBuffer&
dsc shortDesc;
shortDesc.makeShort(0);
if (extBlr.blr)
if (extMsg.blr.hasData())
{
BlrReader reader(extBlr.blr, extBlr.blrLength);
BlrReader reader(extMsg.blr.begin(), extMsg.blr.getCount());
reader.checkByte(blr_version5);
reader.checkByte(blr_begin);
@ -4372,11 +4365,11 @@ static bool gen_ext_message(thread_db* tdbb, CompilerScratch* csb, UCharBuffer&
reader.checkByte(blr_end);
reader.checkByte(blr_eoc);
if (offset != extBlr.bufferLength)
if (offset != extMsg.bufferLength)
{
status_exception::raise(
Arg::Gds(isc_ee_blr_mismatch_length) <<
Arg::Num(extBlr.bufferLength) <<
Arg::Num(extMsg.bufferLength) <<
Arg::Num(offset));
}
}
@ -4458,8 +4451,8 @@ static bool gen_ext_message(thread_db* tdbb, CompilerScratch* csb, UCharBuffer&
// Parse routine BLR.
void MET_parse_routine_blr(thread_db* tdbb, Routine* routine, bid* blob_id,
CompilerScratch* csb, bool external, const BlrMessage& extInBlr, const BlrMessage& extOutBlr)
void MET_parse_routine_blr(thread_db* tdbb, Routine* routine, bid* blob_id, CompilerScratch* csb,
bool external, const RoutineMessage& extInMsg, const RoutineMessage& extOutMsg)
{
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
@ -4477,9 +4470,9 @@ void MET_parse_routine_blr(thread_db* tdbb, Routine* routine, bid* blob_id,
UCharBuffer appendBlr;
bool genExtIn = gen_ext_message(tdbb, csb, tmp, e_extrout_input_message,
e_extrout_input_message2, routine->getInputFields(), extInBlr, appendBlr);
e_extrout_input_message2, routine->getInputFields(), extInMsg, appendBlr);
bool genExtOut = gen_ext_message(tdbb, csb, tmp, e_extrout_output_message,
e_extrout_output_message2, routine->getOutputFields(), extOutBlr, appendBlr);
e_extrout_output_message2, routine->getOutputFields(), extOutMsg, appendBlr);
dsc shortDesc;
shortDesc.makeShort(0);

View File

@ -104,8 +104,8 @@ void MET_par_messages(Jrd::thread_db*, const UCHAR* const, ULONG,
Jrd::DmlNode* MET_parse_blob(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::bid*, Jrd::CompilerScratch**,
Jrd::JrdStatement**, bool, bool);
void MET_parse_routine_blr(Jrd::thread_db*, Jrd::Routine*, Jrd::bid*, Jrd::CompilerScratch*,
bool, const Firebird::BlrMessage& extInBlr,
const Firebird::BlrMessage& extOutBlr);
bool, const Jrd::RoutineMessage& extInMsg,
const Jrd::RoutineMessage& extOutMsg);
void MET_parse_sys_trigger(Jrd::thread_db*, Jrd::jrd_rel*);
void MET_post_existence(Jrd::thread_db*, Jrd::jrd_rel*);
void MET_prepare(Jrd::thread_db*, Jrd::jrd_tra*, USHORT, const UCHAR*);

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 (?, ?, ?, ?);
--
('2012-09-20 12:25:00', 'JRD', 0, 727)
('2013-01-27 13:00:00', 'JRD', 0, 729)
('2012-01-23 20:10:30', 'QLI', 1, 532)
('2009-07-16 05:26:11', 'GFIX', 3, 121)
('1996-11-07 13:39:40', 'GPRE', 4, 1)

View File

@ -834,6 +834,8 @@ Data source : @4', NULL, NULL)
('no_providers', NULL, 'why.cpp', NULL, 0, 724, NULL, 'No providers loaded', NULL, NULL);
('null_spb', NULL, 'why.cpp', NULL, 0, 725, NULL, 'NULL data with non-zero SPB length', NULL, NULL);
('max_args_exceeded', NULL, 'ExprNodes.cpp', NULL, 0, 726, NULL, 'Maximum (@1) number of arguments exceeded for function @2', NULL, NULL)
('ee_blr_mismatch_names_count', NULL, 'ExtEngineManager.cpp', NULL, 0, 727, NULL, 'External BLR message mismatch: names count = @1, blr count = @2', NULL, NULL)
('ee_blr_mismatch_name_not_found', NULL, 'ExtEngineManager.cpp', NULL, 0, 728, NULL, 'External BLR message mismatch: name @1 not found', 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

@ -733,6 +733,8 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-902, '39', '000', 0, 724, 'no_providers', NULL, NULL)
(-104, '42', '818', 0, 725, 'null_spb', NULL, NULL)
(-833, '42', '000', 0, 726, 'max_args_exceeded', NULL, NULL)
(-901, '42', '000', 0, 727, 'ee_blr_mismatch_names_count', NULL, NULL)
(-901, '42', '000', 0, 728, 'ee_blr_mismatch_name_not_found', 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

@ -153,11 +153,11 @@ 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, BlrMessage* inBlr, BlrMessage* outBlr);
const IRoutineMetadata* metadata, IRoutineMessage* inMsg, IRoutineMessage* outMsg);
virtual ExternalProcedure* FB_CALL makeProcedure(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr);
const IRoutineMetadata* metadata, IRoutineMessage* inMsg, IRoutineMessage* outMsg);
virtual ExternalTrigger* FB_CALL makeTrigger(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata);
const IRoutineMetadata* metadata, ITriggerMessage* fieldsMsg);
public:
virtual void FB_CALL dispose(Error* error);
@ -207,7 +207,7 @@ class SharedFunction : public ExternalFunction
{
public:
SharedFunction(Error* error, Engine* aEngine, ExternalContext* context,
const IRoutineMetadata* aMetadata, BlrMessage* inBlr, BlrMessage* outBlr)
const IRoutineMetadata* aMetadata, IRoutineMessage* inMsg, IRoutineMessage* outMsg)
: engine(aEngine),
metadata(aMetadata),
moduleName(*getDefaultMemoryPool()),
@ -217,7 +217,7 @@ public:
{
engine->loadModule(metadata, &moduleName, &entryPoint);
FunctionNode* node = engine->findNode<FunctionNode>(registeredFunctions, moduleName, entryPoint);
node->factory->setup(error, context, metadata, inBlr, outBlr);
node->factory->setup(error, context, metadata, inMsg, outMsg);
}
virtual ~SharedFunction()
@ -275,7 +275,7 @@ class SharedProcedure : public ExternalProcedure
{
public:
SharedProcedure(Error* error, Engine* aEngine, ExternalContext* context,
const IRoutineMetadata* aMetadata, BlrMessage* inBlr, BlrMessage* outBlr)
const IRoutineMetadata* aMetadata, IRoutineMessage* inMsg, IRoutineMessage* outMsg)
: engine(aEngine),
metadata(aMetadata),
moduleName(*getDefaultMemoryPool()),
@ -285,7 +285,7 @@ public:
{
engine->loadModule(metadata, &moduleName, &entryPoint);
ProcedureNode* node = engine->findNode<ProcedureNode>(registeredProcedures, moduleName, entryPoint);
node->factory->setup(error, context, metadata, inBlr, outBlr);
node->factory->setup(error, context, metadata, inMsg, outMsg);
}
virtual ~SharedProcedure()
@ -351,7 +351,7 @@ class SharedTrigger : public ExternalTrigger
{
public:
SharedTrigger(Error* error, Engine* aEngine, ExternalContext* context,
const IRoutineMetadata* aMetadata)
const IRoutineMetadata* aMetadata, ITriggerMessage* fieldsMsg)
: engine(aEngine),
metadata(aMetadata),
moduleName(*getDefaultMemoryPool()),
@ -361,7 +361,7 @@ public:
{
engine->loadModule(metadata, &moduleName, &entryPoint);
TriggerNode* node = engine->findNode<TriggerNode>(registeredTriggers, moduleName, entryPoint);
node->factory->setup(error, context, metadata);
node->factory->setup(error, context, metadata, fieldsMsg);
}
virtual ~SharedTrigger()
@ -681,11 +681,11 @@ void FB_CALL Engine::closeAttachment(Error* error, ExternalContext* context)
ExternalFunction* FB_CALL Engine::makeFunction(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr)
const IRoutineMetadata* metadata, IRoutineMessage* inMsg, IRoutineMessage* outMsg)
{
try
{
return new SharedFunction(error, this, context, metadata, inBlr, outBlr);
return new SharedFunction(error, this, context, metadata, inMsg, outMsg);
}
catch (const ThrowError::Exception& e)
{
@ -696,11 +696,11 @@ ExternalFunction* FB_CALL Engine::makeFunction(Error* error, ExternalContext* co
ExternalProcedure* FB_CALL Engine::makeProcedure(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr)
const IRoutineMetadata* metadata, IRoutineMessage* inMsg, IRoutineMessage* outMsg)
{
try
{
return new SharedProcedure(error, this, context, metadata, inBlr, outBlr);
return new SharedProcedure(error, this, context, metadata, inMsg, outMsg);
}
catch (const ThrowError::Exception& e)
{
@ -711,11 +711,11 @@ ExternalProcedure* FB_CALL Engine::makeProcedure(Error* error, ExternalContext*
ExternalTrigger* FB_CALL Engine::makeTrigger(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata)
const IRoutineMetadata* metadata, ITriggerMessage* fieldsMsg)
{
try
{
return new SharedTrigger(error, this, context, metadata);
return new SharedTrigger(error, this, context, metadata, fieldsMsg);
}
catch (const ThrowError::Exception& e)
{