mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 10:00:38 +01:00
UDR C++ interface and examples improvements.
This commit is contained in:
parent
f3dc865cbf
commit
fc9b47b63d
@ -194,10 +194,15 @@ create function wait_event (
|
||||
engine udr;
|
||||
***/
|
||||
FB_UDR_BEGIN_FUNCTION(wait_event)
|
||||
FB_UDR_EXECUTE_MESSAGE_FUNCTION(
|
||||
FB_MESSAGE(InMessage,
|
||||
(FB_VARCHAR(31 * 4), name)
|
||||
,
|
||||
(FB_INTEGER, result))
|
||||
);
|
||||
|
||||
FB_MESSAGE(OutMessage,
|
||||
(FB_INTEGER, result)
|
||||
);
|
||||
|
||||
FB_UDR_EXECUTE_FUNCTION
|
||||
{
|
||||
char* s = new char[in->name.length + 1];
|
||||
memcpy(s, in->name.str, in->name.length);
|
||||
@ -213,11 +218,11 @@ FB_UDR_BEGIN_FUNCTION(wait_event)
|
||||
isc_db_handle dbHandle = getIscDbHandle(context);
|
||||
ISC_ULONG counter = 0;
|
||||
|
||||
StatusException::check(isc_wait_for_event(statusVector, &dbHandle, eveLen, eveBuffer, eveResult),
|
||||
statusVector);
|
||||
StatusException::checkStatus(isc_wait_for_event(
|
||||
statusVector, &dbHandle, eveLen, eveBuffer, eveResult), statusVector);
|
||||
isc_event_counts(&counter, eveLen, eveBuffer, eveResult);
|
||||
StatusException::check(isc_wait_for_event(statusVector, &dbHandle, eveLen, eveBuffer, eveResult),
|
||||
statusVector);
|
||||
StatusException::checkStatus(isc_wait_for_event(
|
||||
statusVector, &dbHandle, eveLen, eveBuffer, eveResult), statusVector);
|
||||
isc_event_counts(&counter, eveLen, eveBuffer, eveResult);
|
||||
|
||||
isc_free((char*) eveBuffer);
|
||||
@ -239,15 +244,17 @@ create function sum_args (
|
||||
engine udr;
|
||||
***/
|
||||
FB_UDR_BEGIN_FUNCTION(sum_args)
|
||||
FB_UDR_INITIALIZE
|
||||
// Without InMessage/OutMessage definitions, messages will be byte-based.
|
||||
|
||||
FB_UDR_CONSTRUCTOR
|
||||
// , inCount(0)
|
||||
{
|
||||
// Get input metadata.
|
||||
AutoRelease<IMessageMetadata> inMetadata(metadata->getInputMetadata(status));
|
||||
StatusException::check(status->get());
|
||||
AutoRelease<IMessageMetadata> inMetadata(StatusException::check(status,
|
||||
metadata->getInputMetadata(status)));
|
||||
|
||||
// Get count of input parameters.
|
||||
inCount = inMetadata->getCount(status);
|
||||
StatusException::check(status->get());
|
||||
inCount = StatusException::check(status, inMetadata->getCount(status));
|
||||
|
||||
inNullOffsets.reset(new unsigned[inCount]);
|
||||
inOffsets.reset(new unsigned[inCount]);
|
||||
@ -255,37 +262,33 @@ FB_UDR_BEGIN_FUNCTION(sum_args)
|
||||
for (unsigned i = 0; i < inCount; ++i)
|
||||
{
|
||||
// Get null offset of the i-th input parameter.
|
||||
inNullOffsets[i] = inMetadata->getNullOffset(status, i);
|
||||
StatusException::check(status->get());
|
||||
inNullOffsets[i] = StatusException::check(status, inMetadata->getNullOffset(status, i));
|
||||
|
||||
// Get the offset of the i-th input parameter.
|
||||
inOffsets[i] = inMetadata->getOffset(status, i);
|
||||
StatusException::check(status->get());
|
||||
inOffsets[i] = StatusException::check(status, inMetadata->getOffset(status, i));
|
||||
}
|
||||
|
||||
// Get output metadata.
|
||||
AutoRelease<IMessageMetadata> outMetadata(metadata->getOutputMetadata(status));
|
||||
StatusException::check(status->get());
|
||||
AutoRelease<IMessageMetadata> outMetadata(StatusException::check(status,
|
||||
metadata->getOutputMetadata(status)));
|
||||
|
||||
// Get null offset of the return value.
|
||||
outNullOffset = outMetadata->getNullOffset(status, 0);
|
||||
StatusException::check(status->get());
|
||||
outNullOffset = StatusException::check(status, outMetadata->getNullOffset(status, 0));
|
||||
|
||||
// Get offset of the return value.
|
||||
outOffset = outMetadata->getOffset(status, 0);
|
||||
StatusException::check(status->get());
|
||||
outOffset = StatusException::check(status, outMetadata->getOffset(status, 0));
|
||||
}
|
||||
|
||||
// This function requires the INTEGER parameters and return value, otherwise it will crash.
|
||||
// Metadata is inspected dynamically (in execute). This is not the fastest method.
|
||||
FB_UDR_EXECUTE_DYNAMIC_FUNCTION
|
||||
FB_UDR_EXECUTE_FUNCTION
|
||||
{
|
||||
*(ISC_SHORT*) (out + outNullOffset) = FB_FALSE;
|
||||
|
||||
// Get a reference to the return value.
|
||||
ISC_LONG& ret = *(ISC_LONG*) (out + outOffset);
|
||||
|
||||
// By default, the return value is 0.
|
||||
// The return value is automatically initialized to 0.
|
||||
///ret = 0;
|
||||
|
||||
for (unsigned i = 0; i < inCount; ++i)
|
||||
@ -321,38 +324,34 @@ create procedure gen_rows (
|
||||
engine udr;
|
||||
***/
|
||||
FB_UDR_BEGIN_PROCEDURE(gen_rows)
|
||||
// Without InMessage/OutMessage definitions, messages will be byte-based.
|
||||
|
||||
// Procedure variables.
|
||||
unsigned inOffsetStart, inOffsetEnd, outNullOffset, outOffset;
|
||||
|
||||
// Get offsets once per procedure.
|
||||
FB_UDR_CONSTRUCTOR
|
||||
{
|
||||
AutoRelease<IMessageMetadata> inMetadata(StatusException::check(status,
|
||||
metadata->getInputMetadata(status)));
|
||||
|
||||
inOffsetStart = StatusException::check(status, inMetadata->getOffset(status, 0));
|
||||
inOffsetEnd = StatusException::check(status, inMetadata->getOffset(status, 1));
|
||||
|
||||
AutoRelease<IMessageMetadata> outMetadata(StatusException::check(status,
|
||||
metadata->getOutputMetadata(status)));
|
||||
|
||||
outNullOffset = StatusException::check(status, outMetadata->getNullOffset(status, 0));
|
||||
outOffset = StatusException::check(status, outMetadata->getOffset(status, 0));
|
||||
}
|
||||
|
||||
/*** Procedure destructor.
|
||||
~FB_UDR_PROCEDURE(gen_rows)()
|
||||
FB_UDR_DESTRUCTOR
|
||||
{
|
||||
}
|
||||
***/
|
||||
|
||||
// Get offsets once per procedure.
|
||||
FB_UDR_INITIALIZE
|
||||
{
|
||||
AutoRelease<IMessageMetadata> inMetadata(metadata->getInputMetadata(status));
|
||||
StatusException::check(status->get());
|
||||
|
||||
inOffsetStart = inMetadata->getOffset(status, 0);
|
||||
StatusException::check(status->get());
|
||||
|
||||
inOffsetEnd = inMetadata->getOffset(status, 1);
|
||||
StatusException::check(status->get());
|
||||
|
||||
AutoRelease<IMessageMetadata> outMetadata(metadata->getOutputMetadata(status));
|
||||
StatusException::check(status->get());
|
||||
|
||||
outNullOffset = outMetadata->getNullOffset(status, 0);
|
||||
StatusException::check(status->get());
|
||||
|
||||
outOffset = outMetadata->getOffset(status, 0);
|
||||
StatusException::check(status->get());
|
||||
}
|
||||
|
||||
FB_UDR_EXECUTE_DYNAMIC_PROCEDURE
|
||||
FB_UDR_EXECUTE_PROCEDURE
|
||||
{
|
||||
counter = *(ISC_LONG*) (in + procedure->inOffsetStart);
|
||||
end = *(ISC_LONG*) (in + procedure->inOffsetEnd);
|
||||
@ -360,13 +359,14 @@ FB_UDR_BEGIN_PROCEDURE(gen_rows)
|
||||
*(ISC_SHORT*) (out + procedure->outNullOffset) = FB_FALSE;
|
||||
}
|
||||
|
||||
// After procedure's execute definition, starts the result set definition.
|
||||
|
||||
FB_UDR_FETCH_PROCEDURE
|
||||
{
|
||||
if (counter > end)
|
||||
return false;
|
||||
|
||||
*(ISC_LONG*) (out + procedure->outOffset) = counter++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -393,11 +393,16 @@ create procedure gen_rows2 (
|
||||
engine udr;
|
||||
***/
|
||||
FB_UDR_BEGIN_PROCEDURE(gen_rows2)
|
||||
FB_UDR_EXECUTE_MESSAGE_PROCEDURE(
|
||||
FB_MESSAGE(InMessage,
|
||||
(FB_INTEGER, start)
|
||||
(FB_INTEGER, end)
|
||||
,
|
||||
(FB_INTEGER, result))
|
||||
);
|
||||
|
||||
FB_MESSAGE(OutMessage,
|
||||
(FB_INTEGER, result)
|
||||
);
|
||||
|
||||
FB_UDR_EXECUTE_PROCEDURE
|
||||
{
|
||||
out->resultNull = FB_FALSE;
|
||||
out->result = in->start - 1;
|
||||
@ -428,33 +433,36 @@ create procedure inc (
|
||||
// metadata object.
|
||||
// n3 and n4 are on the ResultSet scope, i.e., each procedure execution have they own instances.
|
||||
FB_UDR_BEGIN_PROCEDURE(inc)
|
||||
FB_MESSAGE(InMessage,
|
||||
(FB_INTEGER, count)
|
||||
);
|
||||
|
||||
FB_MESSAGE(OutMessage,
|
||||
(FB_INTEGER, n0)
|
||||
(FB_INTEGER, n1)
|
||||
(FB_INTEGER, n2)
|
||||
(FB_INTEGER, n3)
|
||||
(FB_INTEGER, n4)
|
||||
);
|
||||
|
||||
ISC_LONG n1;
|
||||
|
||||
// This is how a procedure (class) initializer is written.
|
||||
// ResultSet variables are not accessible here.
|
||||
// If there is nothing to initialize, it can be completelly suppressed.
|
||||
FB_UDR_PROCEDURE(inc)()
|
||||
: n1(0),
|
||||
FB_UDR_CONSTRUCTOR
|
||||
, n1(0),
|
||||
n2(0)
|
||||
{
|
||||
}
|
||||
|
||||
ISC_LONG n2;
|
||||
|
||||
// FB_UDR_EXECUTE_MESSAGE_PROCEDURE or FB_UDR_EXECUTE_DYNAMIC_PROCEDURE starts the ResultSet scope.
|
||||
FB_UDR_EXECUTE_MESSAGE_PROCEDURE(
|
||||
(FB_INTEGER, count)
|
||||
,
|
||||
(FB_INTEGER, n0)
|
||||
(FB_INTEGER, n1)
|
||||
(FB_INTEGER, n2)
|
||||
(FB_INTEGER, n3)
|
||||
(FB_INTEGER, n4))
|
||||
// This is the ResultSet (class) initializer. If there is nothing to initialize, the comma
|
||||
// should be suppressed.
|
||||
,
|
||||
n3(procedure->n1), // n3 will start with the next value for n1 of the last execution
|
||||
n4(0)
|
||||
// FB_UDR_EXECUTE_PROCEDURE starts the ResultSet scope.
|
||||
FB_UDR_EXECUTE_PROCEDURE
|
||||
// This is the ResultSet (class) initializer.
|
||||
, n3(procedure->n1), // n3 will start with the next value for n1 of the last execution
|
||||
n4(0)
|
||||
{
|
||||
out->n0Null = out->n1Null = out->n2Null = out->n3Null = out->n4Null = FB_FALSE;
|
||||
|
||||
@ -472,8 +480,7 @@ FB_UDR_BEGIN_PROCEDURE(inc)
|
||||
|
||||
ISC_LONG n3;
|
||||
|
||||
// FB_UDR_FETCH must be always after FB_UDR_EXECUTE_MESSAGE_PROCEDURE or
|
||||
// FB_UDR_EXECUTE_DYNAMIC_PROCEDURE.
|
||||
// FB_UDR_FETCH_PROCEDURE must be always after FB_UDR_EXECUTE_PROCEDURE.
|
||||
FB_UDR_FETCH_PROCEDURE
|
||||
{
|
||||
if (out->n0++ <= in->count)
|
||||
@ -531,48 +538,27 @@ create trigger persons_replicate2
|
||||
engine udr;
|
||||
***/
|
||||
FB_UDR_BEGIN_TRIGGER(replicate)
|
||||
/***
|
||||
FB_UDR_TRIGGER(replicate)()
|
||||
: initialized(false)
|
||||
{
|
||||
}
|
||||
// Without FieldsMessage definition, messages will be byte-based.
|
||||
|
||||
~FB_UDR_TRIGGER(replicate)()
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
}
|
||||
***/
|
||||
|
||||
FB_UDR_EXECUTE_DYNAMIC_TRIGGER
|
||||
{
|
||||
ITransaction* transaction = context->getTransaction(status);
|
||||
StatusException::check(status->get());
|
||||
|
||||
// This will not work if the table has computed fields.
|
||||
stmt->execute(status, transaction, triggerMetadata, newFields, NULL, NULL);
|
||||
StatusException::check(status->get());
|
||||
}
|
||||
|
||||
FB_UDR_INITIALIZE
|
||||
FB_UDR_CONSTRUCTOR
|
||||
, triggerMetadata(StatusException::check(status, metadata->getTriggerMetadata(status)))
|
||||
{
|
||||
ISC_STATUS_ARRAY statusVector = {0};
|
||||
isc_db_handle dbHandle = getIscDbHandle(context);
|
||||
isc_tr_handle trHandle = getIscTrHandle(context);
|
||||
|
||||
isc_stmt_handle stmtHandle = 0;
|
||||
StatusException::check(isc_dsql_allocate_statement(statusVector, &dbHandle, &stmtHandle),
|
||||
statusVector);
|
||||
StatusException::check(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0,
|
||||
StatusException::checkStatus(isc_dsql_allocate_statement(
|
||||
statusVector, &dbHandle, &stmtHandle), statusVector);
|
||||
StatusException::checkStatus(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0,
|
||||
"select data_source from replicate_config where name = ?",
|
||||
SQL_DIALECT_CURRENT, NULL), statusVector);
|
||||
|
||||
const char* table = metadata->getTriggerTable(status);
|
||||
StatusException::check(status->get());
|
||||
const char* table = StatusException::check(status, metadata->getTriggerTable(status));
|
||||
|
||||
// Skip the first exclamation point, separating the module name and entry point.
|
||||
const char* info = strchr(metadata->getEntryPoint(status), '!');
|
||||
StatusException::check(status->get());
|
||||
const char* info = StatusException::check(status,
|
||||
strchr(metadata->getEntryPoint(status), '!'));
|
||||
|
||||
// Skip the second exclamation point, separating the entry point and the misc info (config).
|
||||
if (info)
|
||||
@ -586,7 +572,7 @@ FB_UDR_BEGIN_TRIGGER(replicate)
|
||||
XSQLDA* inSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]);
|
||||
inSqlDa->version = SQLDA_VERSION1;
|
||||
inSqlDa->sqln = 1;
|
||||
StatusException::check(isc_dsql_describe_bind(statusVector, &stmtHandle,
|
||||
StatusException::checkStatus(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);
|
||||
@ -595,24 +581,20 @@ FB_UDR_BEGIN_TRIGGER(replicate)
|
||||
XSQLDA* outSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]);
|
||||
outSqlDa->version = SQLDA_VERSION1;
|
||||
outSqlDa->sqln = 1;
|
||||
StatusException::check(isc_dsql_describe(statusVector, &stmtHandle,
|
||||
StatusException::checkStatus(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';
|
||||
|
||||
StatusException::check(isc_dsql_execute2(statusVector, &trHandle, &stmtHandle,
|
||||
StatusException::checkStatus(isc_dsql_execute2(statusVector, &trHandle, &stmtHandle,
|
||||
SQL_DIALECT_CURRENT, inSqlDa, outSqlDa), statusVector);
|
||||
StatusException::check(isc_dsql_free_statement(statusVector, &stmtHandle, DSQL_unprepare),
|
||||
statusVector);
|
||||
StatusException::checkStatus(isc_dsql_free_statement(
|
||||
statusVector, &stmtHandle, DSQL_unprepare), statusVector);
|
||||
|
||||
delete [] inSqlDa->sqlvar[0].sqldata;
|
||||
delete [] reinterpret_cast<char*>(inSqlDa);
|
||||
|
||||
triggerMetadata.reset(metadata->getTriggerMetadata(status));
|
||||
StatusException::check(status->get());
|
||||
|
||||
unsigned count = triggerMetadata->getCount(status);
|
||||
StatusException::check(status->get());
|
||||
unsigned count = StatusException::check(status, triggerMetadata->getCount(status));
|
||||
|
||||
char buffer[65536];
|
||||
strcpy(buffer, "execute block (\n");
|
||||
@ -622,8 +604,7 @@ FB_UDR_BEGIN_TRIGGER(replicate)
|
||||
if (i > 0)
|
||||
strcat(buffer, ",\n");
|
||||
|
||||
const char* name = triggerMetadata->getField(status, i);
|
||||
StatusException::check(status->get());
|
||||
const char* name = StatusException::check(status, triggerMetadata->getField(status, i));
|
||||
|
||||
strcat(buffer, " p");
|
||||
sprintf(buffer + strlen(buffer), "%d type of column \"%s\".\"%s\" = ?", i, table, name);
|
||||
@ -643,8 +624,7 @@ FB_UDR_BEGIN_TRIGGER(replicate)
|
||||
if (i > 0)
|
||||
strcat(buffer, ", ");
|
||||
|
||||
const char* name = triggerMetadata->getField(status, i);
|
||||
StatusException::check(status->get());
|
||||
const char* name = StatusException::check(status, triggerMetadata->getField(status, i));
|
||||
|
||||
strcat(buffer, "\"");
|
||||
strcat(buffer, name);
|
||||
@ -674,75 +654,65 @@ FB_UDR_BEGIN_TRIGGER(replicate)
|
||||
strcat(buffer, outSqlDa->sqlvar[0].sqldata + sizeof(short));
|
||||
strcat(buffer, "';\nend");
|
||||
|
||||
IAttachment* attachment = context->getAttachment(status);
|
||||
StatusException::check(status->get());
|
||||
IAttachment* attachment = StatusException::check(status, context->getAttachment(status));
|
||||
ITransaction* transaction = StatusException::check(status, context->getTransaction(status));
|
||||
|
||||
ITransaction* transaction = context->getTransaction(status);
|
||||
StatusException::check(status->get());
|
||||
|
||||
stmt.reset(attachment->prepare(status, transaction, 0, buffer, SQL_DIALECT_CURRENT, 0));
|
||||
stmt.reset(StatusException::check(status,
|
||||
attachment->prepare(status, transaction, 0, buffer, SQL_DIALECT_CURRENT, 0)));
|
||||
|
||||
delete [] outSqlDa->sqlvar[0].sqldata;
|
||||
delete [] reinterpret_cast<char*>(outSqlDa);
|
||||
|
||||
///initialized = true;
|
||||
}
|
||||
|
||||
///bool initialized;
|
||||
/***
|
||||
FB_UDR_DESTRUCTOR
|
||||
{
|
||||
}
|
||||
***/
|
||||
|
||||
FB_UDR_EXECUTE_TRIGGER
|
||||
{
|
||||
ITransaction* transaction = StatusException::check(status, context->getTransaction(status));
|
||||
|
||||
// This will not work if the table has computed fields.
|
||||
stmt->execute(status, transaction, triggerMetadata, newFields, NULL, NULL);
|
||||
StatusException::check(status->get());
|
||||
}
|
||||
|
||||
AutoRelease<IMessageMetadata> triggerMetadata;
|
||||
AutoRelease<IStatement> stmt;
|
||||
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;
|
||||
}
|
||||
***/
|
||||
|
||||
// Order of fields does not need to match the fields order in the table, but it should match
|
||||
// the order of fields in the SQL command constructed in the initialization.
|
||||
FB_UDR_EXECUTE_MESSAGE_TRIGGER(
|
||||
FB_TRIGGER_MESSAGE(FieldsMessage,
|
||||
(FB_INTEGER, id, "ID")
|
||||
(FB_BLOB, info, "INFO")
|
||||
(FB_VARCHAR(60 * 4), address, "ADDRESS")
|
||||
(FB_VARCHAR(60 * 4), name, "NAME")
|
||||
)
|
||||
{
|
||||
ITransaction* transaction = context->getTransaction(status);
|
||||
StatusException::check(status->get());
|
||||
);
|
||||
|
||||
stmt->execute(status, transaction, triggerMetadata, newFields, NULL, NULL);
|
||||
StatusException::check(status->get());
|
||||
}
|
||||
|
||||
FB_UDR_INITIALIZE
|
||||
FB_UDR_CONSTRUCTOR
|
||||
, triggerMetadata(StatusException::check(status, metadata->getTriggerMetadata(status)))
|
||||
{
|
||||
ISC_STATUS_ARRAY statusVector = {0};
|
||||
isc_db_handle dbHandle = getIscDbHandle(context);
|
||||
isc_tr_handle trHandle = getIscTrHandle(context);
|
||||
|
||||
isc_stmt_handle stmtHandle = 0;
|
||||
StatusException::check(isc_dsql_allocate_statement(statusVector, &dbHandle, &stmtHandle),
|
||||
statusVector);
|
||||
StatusException::check(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0,
|
||||
StatusException::checkStatus(isc_dsql_allocate_statement(
|
||||
statusVector, &dbHandle, &stmtHandle), statusVector);
|
||||
StatusException::checkStatus(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0,
|
||||
"select data_source from replicate_config where name = ?",
|
||||
SQL_DIALECT_CURRENT, NULL), statusVector);
|
||||
|
||||
const char* table = metadata->getTriggerTable(status);
|
||||
StatusException::check(status->get());
|
||||
const char* table = StatusException::check(status, metadata->getTriggerTable(status));
|
||||
|
||||
// Skip the first exclamation point, separating the module name and entry point.
|
||||
const char* info = strchr(metadata->getEntryPoint(status), '!');
|
||||
StatusException::check(status->get());
|
||||
const char* info = StatusException::check(status,
|
||||
strchr(metadata->getEntryPoint(status), '!'));
|
||||
|
||||
// Skip the second exclamation point, separating the entry point and the misc info (config).
|
||||
if (info)
|
||||
@ -756,8 +726,8 @@ FB_UDR_BEGIN_TRIGGER(replicate_persons)
|
||||
XSQLDA* inSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]);
|
||||
inSqlDa->version = SQLDA_VERSION1;
|
||||
inSqlDa->sqln = 1;
|
||||
StatusException::check(isc_dsql_describe_bind(statusVector, &stmtHandle,
|
||||
SQL_DIALECT_CURRENT, inSqlDa), statusVector);
|
||||
StatusException::checkStatus(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);
|
||||
@ -765,22 +735,19 @@ FB_UDR_BEGIN_TRIGGER(replicate_persons)
|
||||
XSQLDA* outSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]);
|
||||
outSqlDa->version = SQLDA_VERSION1;
|
||||
outSqlDa->sqln = 1;
|
||||
StatusException::check(isc_dsql_describe(statusVector, &stmtHandle,
|
||||
SQL_DIALECT_CURRENT, outSqlDa), statusVector);
|
||||
StatusException::checkStatus(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';
|
||||
|
||||
StatusException::check(isc_dsql_execute2(statusVector, &trHandle, &stmtHandle,
|
||||
StatusException::checkStatus(isc_dsql_execute2(statusVector, &trHandle, &stmtHandle,
|
||||
SQL_DIALECT_CURRENT, inSqlDa, outSqlDa), statusVector);
|
||||
StatusException::check(isc_dsql_free_statement(statusVector, &stmtHandle, DSQL_unprepare),
|
||||
statusVector);
|
||||
StatusException::checkStatus(isc_dsql_free_statement(
|
||||
statusVector, &stmtHandle, DSQL_unprepare), statusVector);
|
||||
|
||||
delete [] inSqlDa->sqlvar[0].sqldata;
|
||||
delete [] reinterpret_cast<char*>(inSqlDa);
|
||||
|
||||
triggerMetadata.reset(metadata->getTriggerMetadata(status));
|
||||
StatusException::check(status->get());
|
||||
|
||||
char buffer[65536];
|
||||
strcpy(buffer,
|
||||
"execute block (\n"
|
||||
@ -797,21 +764,30 @@ FB_UDR_BEGIN_TRIGGER(replicate_persons)
|
||||
strcat(buffer, outSqlDa->sqlvar[0].sqldata + sizeof(short));
|
||||
strcat(buffer, "';\nend");
|
||||
|
||||
IAttachment* attachment = context->getAttachment(status);
|
||||
StatusException::check(status->get());
|
||||
IAttachment* attachment = StatusException::check(status, context->getAttachment(status));
|
||||
ITransaction* transaction = StatusException::check(status, context->getTransaction(status));
|
||||
|
||||
ITransaction* transaction = context->getTransaction(status);
|
||||
StatusException::check(status->get());
|
||||
|
||||
stmt.reset(attachment->prepare(status, transaction, 0, buffer, SQL_DIALECT_CURRENT, 0));
|
||||
stmt.reset(StatusException::check(status,
|
||||
attachment->prepare(status, transaction, 0, buffer, SQL_DIALECT_CURRENT, 0)));
|
||||
|
||||
delete [] outSqlDa->sqlvar[0].sqldata;
|
||||
delete [] reinterpret_cast<char*>(outSqlDa);
|
||||
|
||||
///initialized = true;
|
||||
}
|
||||
|
||||
///bool initialized;
|
||||
/***
|
||||
FB_UDR_DESTRUCTOR
|
||||
{
|
||||
}
|
||||
***/
|
||||
|
||||
FB_UDR_EXECUTE_TRIGGER
|
||||
{
|
||||
ITransaction* transaction = StatusException::check(status, context->getTransaction(status));
|
||||
|
||||
stmt->execute(status, transaction, triggerMetadata, newFields, NULL, NULL);
|
||||
StatusException::check(status->get());
|
||||
}
|
||||
|
||||
AutoRelease<IMessageMetadata> triggerMetadata;
|
||||
AutoRelease<IStatement> stmt;
|
||||
FB_UDR_END_TRIGGER
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
class ExternalResultSet : public IDisposable
|
||||
{
|
||||
public:
|
||||
virtual bool FB_CARG fetch(IStatus* status) = 0;
|
||||
virtual FB_BOOLEAN FB_CARG fetch(IStatus* status) = 0;
|
||||
};
|
||||
|
||||
#define FB_EXTERNAL_RESULT_SET_VERSION (FB_DISPOSABLE_VERSION + 1)
|
||||
|
@ -40,51 +40,23 @@ namespace Firebird
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define FB_UDR_FUNCTION(name) Func##name
|
||||
#define FB_UDR_PROCEDURE(name) Proc##name
|
||||
#define FB_UDR_TRIGGER(name) Trig##name
|
||||
|
||||
|
||||
#define FB_UDR_BEGIN_FUNCTION(name) \
|
||||
class FB_UDR_FUNCTION(name); \
|
||||
\
|
||||
::Firebird::Udr::FunctionFactoryImpl<FB_UDR_FUNCTION(name)> FuncFactory##name(#name); \
|
||||
\
|
||||
class FB_UDR_FUNCTION(name) : public ::Firebird::Udr::Function<FB_UDR_FUNCTION(name)> \
|
||||
namespace Func##name \
|
||||
{ \
|
||||
public: \
|
||||
void initialize(::Firebird::IStatus* /*status*/, void*) \
|
||||
class Impl; \
|
||||
\
|
||||
static ::Firebird::Udr::FunctionFactoryImpl<Impl> factory(#name); \
|
||||
\
|
||||
class Impl : public ::Firebird::Udr::Function<Impl> \
|
||||
{ \
|
||||
}
|
||||
public: \
|
||||
FB__UDR_COMMON_IMPL
|
||||
|
||||
#define FB_UDR_END_FUNCTION \
|
||||
};
|
||||
}; \
|
||||
}
|
||||
|
||||
#define FB_UDR_EXECUTE_DYNAMIC_FUNCTION \
|
||||
FB__UDR_DYNAMIC_TYPE(InMessage); \
|
||||
FB__UDR_DYNAMIC_TYPE(OutMessage); \
|
||||
\
|
||||
FB__UDR_EXECUTE_FUNCTION
|
||||
|
||||
#define FB_UDR_EXECUTE_MESSAGE_FUNCTION(inputs, output) \
|
||||
FB_MESSAGE(InMessage, \
|
||||
inputs \
|
||||
); \
|
||||
FB_MESSAGE(OutMessage, \
|
||||
output \
|
||||
); \
|
||||
\
|
||||
FB__UDR_EXECUTE_FUNCTION
|
||||
|
||||
#define FB_UDR_EXECUTE_MESSAGE_FUNCTION_OUT(outputs) \
|
||||
FB__UDR_DYNAMIC_TYPE(InMessage); \
|
||||
FB_MESSAGE(OutMessage, \
|
||||
outputs \
|
||||
); \
|
||||
\
|
||||
FB__UDR_EXECUTE_FUNCTION
|
||||
|
||||
#define FB__UDR_EXECUTE_FUNCTION \
|
||||
#define FB_UDR_EXECUTE_FUNCTION \
|
||||
virtual void FB_CARG execute(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \
|
||||
void* in, void* out) \
|
||||
{ \
|
||||
@ -100,56 +72,23 @@ namespace Firebird
|
||||
|
||||
|
||||
#define FB_UDR_BEGIN_PROCEDURE(name) \
|
||||
class FB_UDR_PROCEDURE(name); \
|
||||
\
|
||||
::Firebird::Udr::ProcedureFactoryImpl<FB_UDR_PROCEDURE(name)> ProcFactory##name(#name); \
|
||||
\
|
||||
class FB_UDR_PROCEDURE(name) : public ::Firebird::Udr::Procedure<FB_UDR_PROCEDURE(name)> \
|
||||
namespace Proc##name \
|
||||
{ \
|
||||
public: \
|
||||
typedef FB_UDR_PROCEDURE(name) This; \
|
||||
class Impl; \
|
||||
\
|
||||
void initialize(::Firebird::IStatus* /*status*/, void*) \
|
||||
static ::Firebird::Udr::ProcedureFactoryImpl<Impl> factory(#name); \
|
||||
\
|
||||
class Impl : public ::Firebird::Udr::Procedure<Impl> \
|
||||
{ \
|
||||
}
|
||||
public: \
|
||||
FB__UDR_COMMON_IMPL
|
||||
|
||||
#define FB_UDR_END_PROCEDURE \
|
||||
}; \
|
||||
}; \
|
||||
};
|
||||
}
|
||||
|
||||
#define FB_UDR_EXECUTE_DYNAMIC_PROCEDURE \
|
||||
FB__UDR_DYNAMIC_TYPE(InMessage); \
|
||||
FB__UDR_DYNAMIC_TYPE(OutMessage); \
|
||||
\
|
||||
FB__UDR_EXECUTE_PROCEDURE
|
||||
|
||||
#define FB_UDR_EXECUTE_MESSAGE_PROCEDURE(inputs, outputs) \
|
||||
FB_MESSAGE(InMessage, \
|
||||
inputs \
|
||||
); \
|
||||
FB_MESSAGE(OutMessage, \
|
||||
outputs \
|
||||
); \
|
||||
\
|
||||
FB__UDR_EXECUTE_PROCEDURE
|
||||
|
||||
#define FB_UDR_EXECUTE_MESSAGE_PROCEDURE_IN(inputs) \
|
||||
FB_MESSAGE(InMessage, \
|
||||
inputs \
|
||||
); \
|
||||
FB__UDR_DYNAMIC_TYPE(OutMessage); \
|
||||
\
|
||||
FB__UDR_EXECUTE_PROCEDURE
|
||||
|
||||
#define FB_UDR_EXECUTE_MESSAGE_PROCEDURE_OUT(outputs) \
|
||||
FB__UDR_DYNAMIC_TYPE(InMessage); \
|
||||
FB_MESSAGE(OutMessage, \
|
||||
outputs \
|
||||
); \
|
||||
\
|
||||
FB__UDR_EXECUTE_PROCEDURE
|
||||
|
||||
#define FB__UDR_EXECUTE_PROCEDURE \
|
||||
#define FB_UDR_EXECUTE_PROCEDURE \
|
||||
virtual ::Firebird::ExternalResultSet* FB_CARG open(::Firebird::IStatus* status, \
|
||||
::Firebird::ExternalContext* context, void* in, void* out) \
|
||||
{ \
|
||||
@ -159,61 +98,49 @@ namespace Firebird
|
||||
} \
|
||||
FB__UDR_CATCH \
|
||||
\
|
||||
return 0; \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
class ResultSet : public ::Firebird::Udr::ResultSet<ResultSet, This, InMessage, OutMessage> \
|
||||
class ResultSet : public ::Firebird::Udr::ResultSet<ResultSet, Impl, InMessage, OutMessage> \
|
||||
{ \
|
||||
public: \
|
||||
ResultSet(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \
|
||||
This* const procedure, InMessage::Type* const in, OutMessage::Type* const out) \
|
||||
: ::Firebird::Udr::ResultSet<ResultSet, This, InMessage, OutMessage>( \
|
||||
Impl* const procedure, InMessage::Type* const in, OutMessage::Type* const out) \
|
||||
: ::Firebird::Udr::ResultSet<ResultSet, Impl, InMessage, OutMessage>( \
|
||||
context, procedure, in, out)
|
||||
|
||||
#define FB_UDR_FETCH_PROCEDURE \
|
||||
virtual bool FB_CARG fetch(::Firebird::IStatus* status) \
|
||||
virtual FB_BOOLEAN FB_CARG fetch(::Firebird::IStatus* status) \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
return internalFetch(status); \
|
||||
return (FB_BOOLEAN) internalFetch(status); \
|
||||
} \
|
||||
FB__UDR_CATCH \
|
||||
\
|
||||
return 0; \
|
||||
return FB_FALSE; \
|
||||
} \
|
||||
\
|
||||
bool internalFetch(::Firebird::IStatus* status)
|
||||
|
||||
|
||||
#define FB_UDR_BEGIN_TRIGGER(name) \
|
||||
class FB_UDR_TRIGGER(name); \
|
||||
\
|
||||
::Firebird::Udr::TriggerFactoryImpl<FB_UDR_TRIGGER(name)> TrigFactory##name(#name); \
|
||||
\
|
||||
class FB_UDR_TRIGGER(name) : public ::Firebird::Udr::Trigger<FB_UDR_TRIGGER(name)> \
|
||||
namespace Trig##name \
|
||||
{ \
|
||||
public: \
|
||||
class Impl; \
|
||||
\
|
||||
void initialize(::Firebird::IStatus* /*status*/, void*) \
|
||||
static ::Firebird::Udr::TriggerFactoryImpl<Impl> factory(#name); \
|
||||
\
|
||||
class Impl : public ::Firebird::Udr::Trigger<Impl> \
|
||||
{ \
|
||||
}
|
||||
public: \
|
||||
FB__UDR_COMMON_IMPL
|
||||
|
||||
#define FB_UDR_END_TRIGGER \
|
||||
};
|
||||
}; \
|
||||
}
|
||||
|
||||
#define FB_UDR_EXECUTE_DYNAMIC_TRIGGER \
|
||||
FB__UDR_DYNAMIC_TYPE(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 \
|
||||
#define FB_UDR_EXECUTE_TRIGGER \
|
||||
virtual void FB_CARG execute(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \
|
||||
::Firebird::ExternalTrigger::Action action, void* oldFields, void* newFields) \
|
||||
{ \
|
||||
@ -230,27 +157,34 @@ namespace Firebird
|
||||
FieldsMessage::Type* oldFields, FieldsMessage::Type* newFields)
|
||||
|
||||
|
||||
#define FB_UDR_INITIALIZE \
|
||||
void initialize(::Firebird::IStatus* status, ExternalContext* context) \
|
||||
#define FB_UDR_CONSTRUCTOR \
|
||||
Impl(::Firebird::IStatus* const status, ExternalContext* const context, \
|
||||
const IRoutineMetadata* const metadata__) \
|
||||
: master(context->getMaster()), \
|
||||
metadata(metadata__)
|
||||
|
||||
#define FB_UDR_DESTRUCTOR \
|
||||
~Impl()
|
||||
|
||||
|
||||
#define FB__UDR_COMMON_IMPL \
|
||||
Impl(const void* const, ExternalContext* const context, \
|
||||
const IRoutineMetadata* const aMetadata) \
|
||||
: master(context->getMaster()), \
|
||||
metadata(aMetadata) \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
internalInitialize(status, context); \
|
||||
} \
|
||||
FB__UDR_CATCH \
|
||||
} \
|
||||
\
|
||||
void internalInitialize(::Firebird::IStatus* status, ::Firebird::ExternalContext* context)
|
||||
IMaster* master; \
|
||||
const IRoutineMetadata* metadata;
|
||||
|
||||
|
||||
#define FB__UDR_DYNAMIC_TYPE(name) \
|
||||
#define FB__UDR_COMMON_TYPE(name) \
|
||||
struct name \
|
||||
{ \
|
||||
typedef unsigned char Type; \
|
||||
static void setup(::Firebird::IStatus*, ::Firebird::IMetadataBuilder*) {} \
|
||||
}
|
||||
|
||||
|
||||
#define FB__UDR_CATCH \
|
||||
catch (const ::Firebird::Udr::StatusException& e) \
|
||||
{ \
|
||||
@ -313,7 +247,7 @@ public:
|
||||
throw StatusException(vector);
|
||||
}
|
||||
|
||||
static void check(ISC_STATUS status, const ISC_STATUS* vector)
|
||||
static void checkStatus(ISC_STATUS status, const ISC_STATUS* vector)
|
||||
{
|
||||
if (status == 0)
|
||||
return;
|
||||
@ -321,6 +255,13 @@ public:
|
||||
check(vector);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T check(IStatus* status, T value)
|
||||
{
|
||||
check(status->get());
|
||||
return value;
|
||||
}
|
||||
|
||||
public:
|
||||
const ISC_STATUS* getStatusVector() const
|
||||
{
|
||||
@ -479,22 +420,13 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
// This class is used to fix an apparent bug with clang, where the object is wrongly initialized
|
||||
// and overwrites the members set in the operator new.
|
||||
template <typename T>
|
||||
class Routine : public T
|
||||
{
|
||||
public:
|
||||
Routine()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename This>
|
||||
class Function : public ExternalFunction, public Helper
|
||||
{
|
||||
public:
|
||||
FB__UDR_COMMON_TYPE(InMessage);
|
||||
FB__UDR_COMMON_TYPE(OutMessage);
|
||||
|
||||
virtual int FB_CARG getVersion()
|
||||
{
|
||||
return FB_EXTERNAL_FUNCTION_VERSION;
|
||||
@ -514,23 +446,6 @@ public:
|
||||
Utf8* /*name*/, uint /*nameSize*/)
|
||||
{
|
||||
}
|
||||
|
||||
void* operator new(size_t size, IMaster* master, const IRoutineMetadata* metadata)
|
||||
{
|
||||
Function* p = reinterpret_cast<Function*>(::new char[size]);
|
||||
p->master = master;
|
||||
p->metadata = metadata;
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete(void* p)
|
||||
{
|
||||
::delete [] static_cast<char*>(p);
|
||||
}
|
||||
|
||||
public:
|
||||
IMaster* master;
|
||||
const IRoutineMetadata* metadata;
|
||||
};
|
||||
|
||||
|
||||
@ -538,6 +453,9 @@ template <typename This>
|
||||
class Procedure : public ExternalProcedure, public Helper
|
||||
{
|
||||
public:
|
||||
FB__UDR_COMMON_TYPE(InMessage);
|
||||
FB__UDR_COMMON_TYPE(OutMessage);
|
||||
|
||||
virtual int FB_CARG getVersion()
|
||||
{
|
||||
return FB_EXTERNAL_PROCEDURE_VERSION;
|
||||
@ -557,23 +475,6 @@ public:
|
||||
Utf8* /*name*/, uint /*nameSize*/)
|
||||
{
|
||||
}
|
||||
|
||||
void* operator new(size_t size, IMaster* master, const IRoutineMetadata* metadata)
|
||||
{
|
||||
Procedure* p = reinterpret_cast<Procedure*>(::new char[size]);
|
||||
p->master = master;
|
||||
p->metadata = metadata;
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete(void* p)
|
||||
{
|
||||
::delete [] static_cast<char*>(p);
|
||||
}
|
||||
|
||||
public:
|
||||
IMaster* master;
|
||||
const IRoutineMetadata* metadata;
|
||||
};
|
||||
|
||||
|
||||
@ -581,6 +482,8 @@ template <typename This>
|
||||
class Trigger : public ExternalTrigger, public Helper
|
||||
{
|
||||
public:
|
||||
FB__UDR_COMMON_TYPE(FieldsMessage);
|
||||
|
||||
virtual int FB_CARG getVersion()
|
||||
{
|
||||
return FB_EXTERNAL_TRIGGER_VERSION;
|
||||
@ -600,23 +503,6 @@ public:
|
||||
Utf8* /*name*/, uint /*nameSize*/)
|
||||
{
|
||||
}
|
||||
|
||||
void* operator new(size_t size, IMaster* master, const IRoutineMetadata* metadata)
|
||||
{
|
||||
Trigger* p = reinterpret_cast<Trigger*>(::new char[size]);
|
||||
p->master = master;
|
||||
p->metadata = metadata;
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete(void* p)
|
||||
{
|
||||
::delete [] static_cast<char*>(p);
|
||||
}
|
||||
|
||||
public:
|
||||
IMaster* master;
|
||||
const IRoutineMetadata* metadata;
|
||||
};
|
||||
|
||||
|
||||
@ -638,9 +524,13 @@ public:
|
||||
virtual ExternalFunction* FB_CARG newItem(IStatus* status, ExternalContext* context,
|
||||
const IRoutineMetadata* metadata)
|
||||
{
|
||||
T* obj = new(context->getMaster(), metadata) Routine<T>;
|
||||
obj->initialize(status, context);
|
||||
return obj;
|
||||
try
|
||||
{
|
||||
return new T(status, context, metadata);
|
||||
}
|
||||
FB__UDR_CATCH
|
||||
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
@ -663,9 +553,13 @@ public:
|
||||
virtual ExternalProcedure* FB_CARG newItem(IStatus* status, ExternalContext* context,
|
||||
const IRoutineMetadata* metadata)
|
||||
{
|
||||
T* obj = new(context->getMaster(), metadata) Routine<T>;
|
||||
obj->initialize(status, context);
|
||||
return obj;
|
||||
try
|
||||
{
|
||||
return new T(status, context, metadata);
|
||||
}
|
||||
FB__UDR_CATCH
|
||||
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
@ -687,9 +581,13 @@ public:
|
||||
virtual ExternalTrigger* FB_CARG newItem(IStatus* status, ExternalContext* context,
|
||||
const IRoutineMetadata* metadata)
|
||||
{
|
||||
T* obj = new(context->getMaster(), metadata) Routine<T>;
|
||||
obj->initialize(status, context);
|
||||
return obj;
|
||||
try
|
||||
{
|
||||
return new T(status, context, metadata);
|
||||
}
|
||||
FB__UDR_CATCH
|
||||
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user