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

Work in progress fixing external triggers.

This commit is contained in:
asfernandes 2013-03-23 21:12:27 +00:00
parent 1652cf93d7
commit b9bc308a72
8 changed files with 91 additions and 312 deletions

View File

@ -410,7 +410,6 @@ FB_UDR_BEGIN_PROCEDURE(inc)
FB_UDR_END_PROCEDURE FB_UDR_END_PROCEDURE
#if 0 //// FIXME:
/*** /***
Sample usage: Sample usage:
@ -460,52 +459,20 @@ FB_UDR_BEGIN_TRIGGER(replicate)
if (!initialized) if (!initialized)
return; return;
for (int i = 0; i < inSqlDa->sqln; ++i) StatusImpl status(master);
{
XSQLVAR* var = &inSqlDa->sqlvar[i];
delete [] var->sqldata;
delete var->sqlind;
}
delete [] reinterpret_cast<char*>(inSqlDa); triggerMetadata->release();
stmt->free(&status);
ISC_STATUS_ARRAY statusVector = {0};
isc_dsql_free_statement(statusVector, &stmtHandle, DSQL_drop);
} }
FB_UDR_EXECUTE_DYNAMIC_TRIGGER FB_UDR_EXECUTE_DYNAMIC_TRIGGER
{ {
///AutoDispose<IStatus> status(master->getStatus()); ITransaction* transaction = context->getTransaction(status);
const IParametersMetadata* fields = metadata->getTriggerFields(status);
StatusException::check(status->get()); StatusException::check(status->get());
unsigned fieldsCount = fields->getCount(status); // This will not work if the table has computed fields.
stmt->execute(status, transaction, triggerMetadata, newFields, NULL, NULL);
StatusException::check(status->get()); StatusException::check(status->get());
MessageImpl message(fieldsCount, newFields);
ISC_STATUS_ARRAY statusVector = {0};
isc_db_handle dbHandle = getIscDbHandle(context);
isc_tr_handle trHandle = getIscTrHandle(context);
for (unsigned i = 1; i <= fieldsCount; ++i)
{
ParamDesc<void*> field(message, fields);
XSQLVAR* var = &inSqlDa->sqlvar[i - 1];
if (message.isNull(field))
*var->sqlind = -1;
else
{
*var->sqlind = 0;
memcpy(var->sqldata, message[field], var->sqllen);
}
}
StatusException::check(isc_dsql_execute(statusVector, &trHandle, &stmtHandle, SQL_DIALECT_CURRENT,
inSqlDa), statusVector);
} }
FB_UDR_INITIALIZE FB_UDR_INITIALIZE
@ -514,8 +481,9 @@ FB_UDR_BEGIN_TRIGGER(replicate)
isc_db_handle dbHandle = getIscDbHandle(context); isc_db_handle dbHandle = getIscDbHandle(context);
isc_tr_handle trHandle = getIscTrHandle(context); isc_tr_handle trHandle = getIscTrHandle(context);
stmtHandle = 0; isc_stmt_handle stmtHandle = 0;
StatusException::check(isc_dsql_allocate_statement(statusVector, &dbHandle, &stmtHandle), statusVector); StatusException::check(isc_dsql_allocate_statement(statusVector, &dbHandle, &stmtHandle),
statusVector);
StatusException::check(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0, StatusException::check(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0,
"select data_source from replicate_config where name = ?", "select data_source from replicate_config where name = ?",
SQL_DIALECT_CURRENT, NULL), statusVector); SQL_DIALECT_CURRENT, NULL), statusVector);
@ -538,11 +506,11 @@ FB_UDR_BEGIN_TRIGGER(replicate)
else else
info = ""; info = "";
inSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]); XSQLDA* inSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]);
inSqlDa->version = SQLDA_VERSION1; inSqlDa->version = SQLDA_VERSION1;
inSqlDa->sqln = 1; inSqlDa->sqln = 1;
StatusException::check(isc_dsql_describe_bind(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa), StatusException::check(isc_dsql_describe_bind(statusVector, &stmtHandle,
statusVector); SQL_DIALECT_CURRENT, inSqlDa), statusVector);
inSqlDa->sqlvar[0].sqldata = new char[sizeof(short) + inSqlDa->sqlvar[0].sqllen]; inSqlDa->sqlvar[0].sqldata = new char[sizeof(short) + inSqlDa->sqlvar[0].sqllen];
strncpy(inSqlDa->sqlvar[0].sqldata + sizeof(short), info, 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); *reinterpret_cast<short*>(inSqlDa->sqlvar[0].sqldata) = strlen(info);
@ -550,23 +518,23 @@ FB_UDR_BEGIN_TRIGGER(replicate)
XSQLDA* outSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]); XSQLDA* outSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]);
outSqlDa->version = SQLDA_VERSION1; outSqlDa->version = SQLDA_VERSION1;
outSqlDa->sqln = 1; outSqlDa->sqln = 1;
StatusException::check(isc_dsql_describe(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, outSqlDa), StatusException::check(isc_dsql_describe(statusVector, &stmtHandle,
statusVector); SQL_DIALECT_CURRENT, outSqlDa), statusVector);
outSqlDa->sqlvar[0].sqldata = new char[sizeof(short) + outSqlDa->sqlvar[0].sqllen + 1]; outSqlDa->sqlvar[0].sqldata = new char[sizeof(short) + outSqlDa->sqlvar[0].sqllen + 1];
outSqlDa->sqlvar[0].sqldata[sizeof(short) + outSqlDa->sqlvar[0].sqllen] = '\0'; outSqlDa->sqlvar[0].sqldata[sizeof(short) + outSqlDa->sqlvar[0].sqllen] = '\0';
StatusException::check(isc_dsql_execute2(statusVector, &trHandle, &stmtHandle, SQL_DIALECT_CURRENT, StatusException::check(isc_dsql_execute2(statusVector, &trHandle, &stmtHandle,
inSqlDa, outSqlDa), statusVector); SQL_DIALECT_CURRENT, inSqlDa, outSqlDa), statusVector);
StatusException::check(isc_dsql_free_statement(statusVector, &stmtHandle, DSQL_unprepare), statusVector); StatusException::check(isc_dsql_free_statement(statusVector, &stmtHandle, DSQL_unprepare),
statusVector);
delete [] inSqlDa->sqlvar[0].sqldata; delete [] inSqlDa->sqlvar[0].sqldata;
delete [] reinterpret_cast<char*>(inSqlDa); delete [] reinterpret_cast<char*>(inSqlDa);
inSqlDa = NULL;
const IParametersMetadata* fields = metadata->getTriggerFields(status); triggerMetadata = metadata->getTriggerMetadata(status);
StatusException::check(status->get()); StatusException::check(status->get());
unsigned count = fields->getCount(status); unsigned count = triggerMetadata->getCount(status);
StatusException::check(status->get()); StatusException::check(status->get());
char buffer[65536]; char buffer[65536];
@ -577,7 +545,7 @@ FB_UDR_BEGIN_TRIGGER(replicate)
if (i > 0) if (i > 0)
strcat(buffer, ",\n"); strcat(buffer, ",\n");
const char* name = fields->getField(status, i); const char* name = triggerMetadata->getField(status, i);
StatusException::check(status->get()); StatusException::check(status->get());
strcat(buffer, " p"); strcat(buffer, " p");
@ -598,7 +566,7 @@ FB_UDR_BEGIN_TRIGGER(replicate)
if (i > 0) if (i > 0)
strcat(buffer, ", "); strcat(buffer, ", ");
const char* name = fields->getField(status, i); const char* name = triggerMetadata->getField(status, i);
StatusException::check(status->get()); StatusException::check(status->get());
strcat(buffer, "\""); strcat(buffer, "\"");
@ -629,68 +597,13 @@ FB_UDR_BEGIN_TRIGGER(replicate)
strcat(buffer, outSqlDa->sqlvar[0].sqldata + sizeof(short)); strcat(buffer, outSqlDa->sqlvar[0].sqldata + sizeof(short));
strcat(buffer, "';\nend"); strcat(buffer, "';\nend");
StatusException::check(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0, buffer, IAttachment* attachment = context->getAttachment(status);
SQL_DIALECT_CURRENT, NULL), statusVector); StatusException::check(status->get());
inSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(count))]); ITransaction* transaction = context->getTransaction(status);
inSqlDa->version = SQLDA_VERSION1; StatusException::check(status->get());
inSqlDa->sqln = count;
StatusException::check(isc_dsql_describe_bind(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa),
statusVector);
for (unsigned i = 0; i < count; ++i) stmt = attachment->prepare(status, transaction, 0, buffer, 3, 0);
{
XSQLVAR* var = &inSqlDa->sqlvar[i];
switch (var->sqltype & ~1)
{
case SQL_TEXT:
var->sqldata = new char[var->sqllen];
break;
case SQL_VARYING:
var->sqldata = new char[var->sqllen];
var->sqllen += sizeof(short);
break;
case SQL_SHORT:
var->sqldata = new char[sizeof(short)];
break;
case SQL_LONG:
var->sqldata = new char[sizeof(int32)];
break;
case SQL_INT64:
var->sqldata = new char[sizeof(int64)];
break;
case SQL_FLOAT:
var->sqltype = SQL_DOUBLE;
var->sqllen = sizeof(double);
// fall into
case SQL_DOUBLE:
var->sqldata = new char[sizeof(double)];
break;
case SQL_TYPE_DATE:
var->sqldata = new char[sizeof(ISC_DATE)];
break;
//// TODO: SQL_TIMESTAMP, SQL_TYPE_TIME
case SQL_BLOB:
var->sqldata = new char[sizeof(ISC_QUAD)];
break;
default:
assert(false);
}
var->sqltype |= 1;
var->sqlind = new short(-1);
}
delete [] outSqlDa->sqlvar[0].sqldata; delete [] outSqlDa->sqlvar[0].sqldata;
delete [] reinterpret_cast<char*>(outSqlDa); delete [] reinterpret_cast<char*>(outSqlDa);
@ -699,11 +612,12 @@ FB_UDR_BEGIN_TRIGGER(replicate)
} }
bool initialized; bool initialized;
XSQLDA* inSqlDa; IMessageMetadata* triggerMetadata;
isc_stmt_handle stmtHandle; IStatement* stmt;
FB_UDR_END_TRIGGER FB_UDR_END_TRIGGER
#if 0 //// FIXME:
FB_UDR_BEGIN_TRIGGER(replicate_persons) FB_UDR_BEGIN_TRIGGER(replicate_persons)
FB_UDR_TRIGGER(replicate_persons)() FB_UDR_TRIGGER(replicate_persons)()
: initialized(false) : initialized(false)

View File

@ -38,15 +38,6 @@ namespace Firebird {
class ExternalEngine; class ExternalEngine;
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. // Connection to current database in external engine.
// Context passed to ExternalEngine has SYSDBA privileges. // Context passed to ExternalEngine has SYSDBA privileges.
// Context passed to ExternalFunction, ExternalProcedure and ExternalTrigger // Context passed to ExternalFunction, ExternalProcedure and ExternalTrigger
@ -169,7 +160,7 @@ public:
virtual const char* FB_CARG getBody(IStatus* status) const = 0; virtual const char* FB_CARG getBody(IStatus* status) const = 0;
virtual IMessageMetadata* FB_CARG getInputMetadata(IStatus* status) const = 0; virtual IMessageMetadata* FB_CARG getInputMetadata(IStatus* status) const = 0;
virtual IMessageMetadata* FB_CARG getOutputMetadata(IStatus* status) const = 0; virtual IMessageMetadata* FB_CARG getOutputMetadata(IStatus* status) const = 0;
virtual const IMessageMetadata* FB_CARG getTriggerFields(IStatus* status) const = 0; virtual IMessageMetadata* FB_CARG getTriggerMetadata(IStatus* status) const = 0;
virtual const char* FB_CARG getTriggerTable(IStatus* status) const = 0; virtual const char* FB_CARG getTriggerTable(IStatus* status) const = 0;
virtual ExternalTrigger::Type FB_CARG getTriggerType(IStatus* status) const = 0; virtual ExternalTrigger::Type FB_CARG getTriggerType(IStatus* status) const = 0;
}; };
@ -203,7 +194,7 @@ public:
const IRoutineMetadata* metadata, const IRoutineMetadata* metadata,
IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) = 0; IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) = 0;
virtual ExternalTrigger* FB_CALL makeTrigger(IStatus* status, ExternalContext* context, virtual ExternalTrigger* FB_CALL makeTrigger(IStatus* status, ExternalContext* context,
const IRoutineMetadata* metadata, ITriggerMessage* triggerMsg) = 0; const IRoutineMetadata* metadata, IMetadataBuilder* fieldsBuilder) = 0;
}; };
#define FB_EXTERNAL_ENGINE_VERSION (FB_PLUGIN_VERSION + 6) #define FB_EXTERNAL_ENGINE_VERSION (FB_PLUGIN_VERSION + 6)

View File

@ -202,7 +202,7 @@ namespace Firebird
}; };
#define FB_UDR_EXECUTE_DYNAMIC_TRIGGER \ #define FB_UDR_EXECUTE_DYNAMIC_TRIGGER \
typedef void* FieldsMessage; \ FB_UDR__DYNAMIC_TYPE(FieldsMessage); \
\ \
FB_UDR__EXECUTE_TRIGGER FB_UDR__EXECUTE_TRIGGER
@ -219,13 +219,15 @@ namespace Firebird
{ \ { \
try \ try \
{ \ { \
internalExecute(status, context, action, (FieldsMessage*) oldFields, (FieldsMessage*) newFields); \ internalExecute(status, context, action, \
(FieldsMessage::Type*) oldFields, (FieldsMessage::Type*) newFields); \
} \ } \
FB_UDR__CATCH \ FB_UDR__CATCH \
} \ } \
\ \
void internalExecute(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \ void internalExecute(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \
::Firebird::ExternalTrigger::Action action, FieldsMessage* oldFields, FieldsMessage* newFields) ::Firebird::ExternalTrigger::Action action, \
FieldsMessage::Type* oldFields, FieldsMessage::Type* newFields)
#define FB_UDR_INITIALIZE \ #define FB_UDR_INITIALIZE \
@ -631,7 +633,7 @@ public:
} }
virtual void setup(IStatus* status, ExternalContext* /*context*/, virtual void setup(IStatus* status, ExternalContext* /*context*/,
const IRoutineMetadata* /*metadata*/, ITriggerMessage* fields) const IRoutineMetadata* /*metadata*/, IMetadataBuilder* fields)
{ {
T::FieldsMessage::setup(status, fields); T::FieldsMessage::setup(status, fields);
} }

View File

@ -58,7 +58,7 @@ class TriggerFactory
{ {
public: public:
virtual void setup(IStatus* status, ExternalContext* context, const IRoutineMetadata* metadata, virtual void setup(IStatus* status, ExternalContext* context, const IRoutineMetadata* metadata,
ITriggerMessage* fields) = 0; IMetadataBuilder* fieldsBuilder) = 0;
virtual ExternalTrigger* FB_CALL newItem(IStatus* status, ExternalContext* context, virtual ExternalTrigger* FB_CALL newItem(IStatus* status, ExternalContext* context,
const IRoutineMetadata* metadata) = 0; const IRoutineMetadata* metadata) = 0;
}; };

View File

@ -61,6 +61,7 @@ namespace Jrd {
static MakeUpgradeInfo<> upInfo; static MakeUpgradeInfo<> upInfo;
// Create a Format based on a IMessageMetadata.
static Format* createFormat(MemoryPool& pool, IMessageMetadata* params) static Format* createFormat(MemoryPool& pool, IMessageMetadata* params)
{ {
LocalStatus status; LocalStatus status;
@ -227,11 +228,22 @@ ExtEngineManager::ExternalContextImpl::ExternalContextImpl(thread_db* tdbb,
//// TODO: admin rights //// TODO: admin rights
clientCharSet = INTL_charset_lookup(tdbb, internalAttachment->att_client_charset)->getName(); clientCharSet = INTL_charset_lookup(tdbb, internalAttachment->att_client_charset)->getName();
internalAttachment->att_interface->addRef();
externalAttachment = MasterInterfacePtr()->registerAttachment(JProvider::getInstance(),
internalAttachment->att_interface);
} }
ExtEngineManager::ExternalContextImpl::~ExternalContextImpl() ExtEngineManager::ExternalContextImpl::~ExternalContextImpl()
{ {
releaseTransaction(); releaseTransaction();
if (externalAttachment)
{
externalAttachment->release();
externalAttachment = NULL;
}
} }
void ExtEngineManager::ExternalContextImpl::releaseTransaction() void ExtEngineManager::ExternalContextImpl::releaseTransaction()
@ -242,12 +254,6 @@ void ExtEngineManager::ExternalContextImpl::releaseTransaction()
externalTransaction = NULL; externalTransaction = NULL;
} }
if (externalAttachment)
{
externalAttachment->release();
externalAttachment = NULL;
}
internalTransaction = NULL; internalTransaction = NULL;
} }
@ -259,23 +265,13 @@ void ExtEngineManager::ExternalContextImpl::setTransaction(thread_db* tdbb)
return; return;
releaseTransaction(); releaseTransaction();
fb_assert(!externalAttachment && !externalTransaction); fb_assert(!externalTransaction);
MasterInterfacePtr master;
if (internalAttachment)
{
internalAttachment->att_interface->addRef();
externalAttachment = master->registerAttachment(JProvider::getInstance(),
internalAttachment->att_interface);
}
if ((internalTransaction = newTransaction)) if ((internalTransaction = newTransaction))
{ {
internalTransaction->getInterface()->addRef(); internalTransaction->getInterface()->addRef();
externalTransaction = master->registerTransaction(externalAttachment, externalTransaction = MasterInterfacePtr()->registerTransaction(externalAttachment,
internalTransaction->getInterface()); internalTransaction->getInterface());
} }
} }
@ -470,7 +466,7 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb)
ExtEngineManager::Trigger::Trigger(thread_db* tdbb, MemoryPool& pool, ExtEngineManager* aExtManager, ExtEngineManager::Trigger::Trigger(thread_db* tdbb, MemoryPool& pool, ExtEngineManager* aExtManager,
ExternalEngine* aEngine, RoutineMetadata* aMetadata, TriggerMessage& fieldsMsg, ExternalEngine* aEngine, RoutineMetadata* aMetadata,
ExternalTrigger* aTrigger, const Jrd::Trigger* aTrg) ExternalTrigger* aTrigger, const Jrd::Trigger* aTrg)
: extManager(aExtManager), : extManager(aExtManager),
engine(aEngine), engine(aEngine),
@ -487,121 +483,10 @@ ExtEngineManager::Trigger::Trigger(thread_db* tdbb, MemoryPool& pool, ExtEngineM
if (relation) if (relation)
{ {
bool blrPresent = fieldsMsg.blr.hasData(); format = createFormat(pool, metadata->triggerFields);
Format* relFormat = relation->rel_current_format;
GenericMap<Left<MetaName, USHORT> > fieldsMap;
for (size_t i = 0; i < relation->rel_fields->count(); ++i) for (unsigned i = 0; i < format->fmt_count / 2; ++i)
{ fieldsPos.add(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(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*) (IPTR) 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(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*) (IPTR) 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);
} }
} }
@ -836,12 +721,12 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, Jrd::Function* udf,
LocalStatus status; LocalStatus status;
RefPtr<IMetadataBuilder> inBuilder(metadata->inputParameters->getBuilder(&status)); RefPtr<IMetadataBuilder> inBuilder(metadata->inputParameters->getBuilder(&status));
inBuilder->release();
status.check(); status.check();
inBuilder->release();
RefPtr<IMetadataBuilder> outBuilder(metadata->outputParameters->getBuilder(&status)); RefPtr<IMetadataBuilder> outBuilder(metadata->outputParameters->getBuilder(&status));
outBuilder->release();
status.check(); status.check();
outBuilder->release();
ExternalFunction* externalFunction; ExternalFunction* externalFunction;
@ -937,12 +822,12 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, jrd_prc* prc,
LocalStatus status; LocalStatus status;
RefPtr<IMetadataBuilder> inBuilder(metadata->inputParameters->getBuilder(&status)); RefPtr<IMetadataBuilder> inBuilder(metadata->inputParameters->getBuilder(&status));
inBuilder->release();
status.check(); status.check();
inBuilder->release();
RefPtr<IMetadataBuilder> outBuilder(metadata->outputParameters->getBuilder(&status)); RefPtr<IMetadataBuilder> outBuilder(metadata->outputParameters->getBuilder(&status));
outBuilder->release();
status.check(); status.check();
outBuilder->release();
ExternalProcedure* externalProcedure; ExternalProcedure* externalProcedure;
@ -984,7 +869,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, jrd_prc* prc,
} }
ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const Jrd::Trigger* trg, void ExtEngineManager::makeTrigger(thread_db* tdbb, Jrd::Trigger* trg,
const MetaName& engine, const string& entryPoint, const string& body, const MetaName& engine, const string& entryPoint, const string& body,
ExternalTrigger::Type type) ExternalTrigger::Type type)
{ {
@ -1031,10 +916,20 @@ ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const
item.length = sqlLen; item.length = sqlLen;
item.scale = sqlScale; item.scale = sqlScale;
item.nullable = !field->fld_not_null; item.nullable = !field->fld_not_null;
item.finished = true;
} }
} }
TriggerMessage fieldsMsg(pool); LocalStatus status;
RefPtr<IMetadataBuilder> fieldsBuilder(relation ?
metadata->triggerFields->getBuilder(&status) : NULL);
if (relation)
{
status.check();
fieldsBuilder->release();
}
ExternalTrigger* externalTrigger; ExternalTrigger* externalTrigger;
{ // scope { // scope
@ -1042,7 +937,7 @@ ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const
LocalStatus status; LocalStatus status;
externalTrigger = attInfo->engine->makeTrigger(&status, attInfo->context, metadata, externalTrigger = attInfo->engine->makeTrigger(&status, attInfo->context, metadata,
&fieldsMsg); fieldsBuilder);
status.check(); status.check();
if (!externalTrigger) if (!externalTrigger)
@ -1050,12 +945,18 @@ ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const
status_exception::raise( status_exception::raise(
Arg::Gds(isc_eem_trig_not_returned) << trg->name << engine); Arg::Gds(isc_eem_trig_not_returned) << trg->name << engine);
} }
if (relation)
{
metadata->triggerFields = fieldsBuilder->getMetadata(&status);
status.check();
}
} }
try try
{ {
return FB_NEW(getPool()) Trigger(tdbb, pool, this, attInfo->engine, metadata.release(), trg->extTrigger = FB_NEW(getPool()) Trigger(tdbb, pool, this, attInfo->engine,
fieldsMsg, externalTrigger, trg); metadata.release(), externalTrigger, trg);
} }
catch (...) catch (...)
{ {

View File

@ -52,35 +52,6 @@ struct impure_value;
struct record_param; struct record_param;
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 class ExtEngineManager : public Firebird::PermanentStorage
{ {
private: private:
@ -136,7 +107,7 @@ private:
return getMetadata(outputParameters); return getMetadata(outputParameters);
} }
virtual Firebird::IMessageMetadata* FB_CARG getTriggerFields( virtual Firebird::IMessageMetadata* FB_CARG getTriggerMetadata(
Firebird::IStatus* /*status*/) const Firebird::IStatus* /*status*/) const
{ {
return getMetadata(triggerFields); return getMetadata(triggerFields);
@ -304,7 +275,7 @@ public:
{ {
public: public:
Trigger(thread_db* tdbb, MemoryPool& pool, ExtEngineManager* aExtManager, Trigger(thread_db* tdbb, MemoryPool& pool, ExtEngineManager* aExtManager,
Firebird::ExternalEngine* aEngine, RoutineMetadata* aMetadata, TriggerMessage& fieldsMsg, Firebird::ExternalEngine* aEngine, RoutineMetadata* aMetadata,
Firebird::ExternalTrigger* aTrigger, const Jrd::Trigger* aTrg); Firebird::ExternalTrigger* aTrigger, const Jrd::Trigger* aTrg);
~Trigger(); ~Trigger();
@ -346,7 +317,7 @@ public:
void makeProcedure(thread_db* tdbb, jrd_prc* prc, void makeProcedure(thread_db* tdbb, jrd_prc* prc,
const Firebird::MetaName& engine, const Firebird::string& entryPoint, const Firebird::MetaName& engine, const Firebird::string& entryPoint,
const Firebird::string& body); const Firebird::string& body);
Trigger* makeTrigger(thread_db* tdbb, const Jrd::Trigger* trg, void makeTrigger(thread_db* tdbb, Jrd::Trigger* trg,
const Firebird::MetaName& engine, const Firebird::string& entryPoint, const Firebird::MetaName& engine, const Firebird::string& entryPoint,
const Firebird::string& body, Firebird::ExternalTrigger::Type type); const Firebird::string& body, Firebird::ExternalTrigger::Type type);

View File

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

View File

@ -157,7 +157,7 @@ public:
virtual ExternalProcedure* FB_CALL makeProcedure(IStatus* status, ExternalContext* context, virtual ExternalProcedure* FB_CALL makeProcedure(IStatus* status, ExternalContext* context,
const IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder); const IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder);
virtual ExternalTrigger* FB_CALL makeTrigger(IStatus* status, ExternalContext* context, virtual ExternalTrigger* FB_CALL makeTrigger(IStatus* status, ExternalContext* context,
const IRoutineMetadata* metadata, ITriggerMessage* fieldsMsg); const IRoutineMetadata* metadata, IMetadataBuilder* fieldsBuilder);
public: public:
virtual void FB_CALL dispose(); virtual void FB_CALL dispose();
@ -355,7 +355,7 @@ class SharedTrigger : public ExternalTrigger
{ {
public: public:
SharedTrigger(IStatus* status, Engine* aEngine, ExternalContext* context, SharedTrigger(IStatus* status, Engine* aEngine, ExternalContext* context,
const IRoutineMetadata* aMetadata, ITriggerMessage* fieldsMsg) const IRoutineMetadata* aMetadata, IMetadataBuilder* fieldsBuilder)
: engine(aEngine), : engine(aEngine),
metadata(aMetadata), metadata(aMetadata),
moduleName(*getDefaultMemoryPool()), moduleName(*getDefaultMemoryPool()),
@ -365,7 +365,7 @@ public:
{ {
engine->loadModule(metadata, &moduleName, &entryPoint); engine->loadModule(metadata, &moduleName, &entryPoint);
TriggerNode* node = engine->findNode<TriggerNode>(registeredTriggers, moduleName, entryPoint); TriggerNode* node = engine->findNode<TriggerNode>(registeredTriggers, moduleName, entryPoint);
node->factory->setup(status, context, metadata, fieldsMsg); node->factory->setup(status, context, metadata, fieldsBuilder);
} }
virtual ~SharedTrigger() virtual ~SharedTrigger()
@ -715,11 +715,11 @@ ExternalProcedure* FB_CALL Engine::makeProcedure(IStatus* status, ExternalContex
ExternalTrigger* FB_CALL Engine::makeTrigger(IStatus* status, ExternalContext* context, ExternalTrigger* FB_CALL Engine::makeTrigger(IStatus* status, ExternalContext* context,
const IRoutineMetadata* metadata, ITriggerMessage* fieldsMsg) const IRoutineMetadata* metadata, IMetadataBuilder* fieldsBuilder)
{ {
try try
{ {
return new SharedTrigger(status, this, context, metadata, fieldsMsg); return new SharedTrigger(status, this, context, metadata, fieldsBuilder);
} }
catch (const StatusException& e) catch (const StatusException& e)
{ {