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:
parent
1652cf93d7
commit
b9bc308a72
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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 (...)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user