|
From: <asf...@us...> - 2011-07-10 01:24:02
|
Revision: 53285
http://firebird.svn.sourceforge.net/firebird/?rev=53285&view=rev
Author: asfernandes
Date: 2011-07-10 01:23:53 +0000 (Sun, 10 Jul 2011)
Log Message:
-----------
Use the BLR message definition of external procedures and functions.
Modified Paths:
--------------
firebird/trunk/examples/udr/UdrCppExample.cpp
firebird/trunk/lang_helpers/gds_codes.ftn
firebird/trunk/lang_helpers/gds_codes.pas
firebird/trunk/src/dsql/DdlNodes.epp
firebird/trunk/src/include/firebird/ExternalEngine.h
firebird/trunk/src/include/firebird/Message.h
firebird/trunk/src/include/firebird/UdrCppEngine.h
firebird/trunk/src/include/firebird/UdrEngine.h
firebird/trunk/src/include/gen/codetext.h
firebird/trunk/src/include/gen/iberror.h
firebird/trunk/src/include/gen/msgs.h
firebird/trunk/src/include/gen/sql_code.h
firebird/trunk/src/include/gen/sql_state.h
firebird/trunk/src/jrd/BlrReader.h
firebird/trunk/src/jrd/ExtEngineManager.cpp
firebird/trunk/src/jrd/ExtEngineManager.h
firebird/trunk/src/jrd/Function.epp
firebird/trunk/src/jrd/Function.h
firebird/trunk/src/jrd/exe.cpp
firebird/trunk/src/jrd/exe.h
firebird/trunk/src/jrd/met.epp
firebird/trunk/src/jrd/par.cpp
firebird/trunk/src/jrd/par_proto.h
firebird/trunk/src/msgs/facilities2.sql
firebird/trunk/src/msgs/messages2.sql
firebird/trunk/src/msgs/system_errors2.sql
firebird/trunk/src/plugins/udr_engine/UdrEngine.cpp
Modified: firebird/trunk/examples/udr/UdrCppExample.cpp
===================================================================
--- firebird/trunk/examples/udr/UdrCppExample.cpp 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/examples/udr/UdrCppExample.cpp 2011-07-10 01:23:53 UTC (rev 53285)
@@ -289,7 +289,7 @@
blrLength = 0;
blr = blrPos = new ISC_UCHAR[sizeof(HEADER) + 10 * itemCount + 2];
bufferLength = 0;
- buffer = (ISC_UCHAR*) aBuffer;
+ buffer = static_cast<ISC_UCHAR*>(aBuffer);
memcpy(blrPos, HEADER, sizeof(HEADER));
blrPos += sizeof(HEADER);
@@ -795,6 +795,7 @@
FB_UDR_END_PROCEDURE
+//// TODO: Rework triggers.
/***
Sample usage:
Modified: firebird/trunk/lang_helpers/gds_codes.ftn
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.ftn 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/lang_helpers/gds_codes.ftn 2011-07-10 01:23:53 UTC (rev 53285)
@@ -1462,6 +1462,10 @@
PARAMETER (GDS__sysf_argscant_both_be_zero = 335545024)
INTEGER*4 GDS__spb_no_id
PARAMETER (GDS__spb_no_id = 335545025)
+ INTEGER*4 GDS__ee_blr_mismatch_null
+ PARAMETER (GDS__ee_blr_mismatch_null = 335545026)
+ INTEGER*4 GDS__ee_blr_mismatch_length
+ PARAMETER (GDS__ee_blr_mismatch_length = 335545027)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw
Modified: firebird/trunk/lang_helpers/gds_codes.pas
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.pas 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/lang_helpers/gds_codes.pas 2011-07-10 01:23:53 UTC (rev 53285)
@@ -738,6 +738,8 @@
gds_invalid_boolean_usage = 335545023;
gds_sysf_argscant_both_be_zero = 335545024;
gds_spb_no_id = 335545025;
+ gds_ee_blr_mismatch_null = 335545026;
+ gds_ee_blr_mismatch_length = 335545027;
gds_gfix_db_name = 335740929;
gds_gfix_invalid_sw = 335740930;
gds_gfix_incmp_sw = 335740932;
Modified: firebird/trunk/src/dsql/DdlNodes.epp
===================================================================
--- firebird/trunk/src/dsql/DdlNodes.epp 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/dsql/DdlNodes.epp 2011-07-10 01:23:53 UTC (rev 53285)
@@ -1448,7 +1448,7 @@
ARG.RDB$COLLATION_ID.NULL = TRUE;
ARG.RDB$ARGUMENT_MECHANISM.NULL = FALSE;
- ARG.RDB$ARGUMENT_MECHANISM = (USHORT) (parameter.fullDomain || parameter.typeOfName.isEmpty() ?
+ ARG.RDB$ARGUMENT_MECHANISM = (USHORT) (parameter.fullDomain ?
prm_mech_normal : prm_mech_type_of);
if (parameter.notNull)
@@ -2226,7 +2226,7 @@
PRM.RDB$PARAMETER_TYPE = type;
PRM.RDB$PARAMETER_MECHANISM.NULL = FALSE;
- PRM.RDB$PARAMETER_MECHANISM = (USHORT) (parameter.fullDomain || parameter.typeOfName.isEmpty() ?
+ PRM.RDB$PARAMETER_MECHANISM = (USHORT) (parameter.fullDomain ?
prm_mech_normal : prm_mech_type_of);
PRM.RDB$NULL_FLAG.NULL = !parameter.notNull;
Modified: firebird/trunk/src/include/firebird/ExternalEngine.h
===================================================================
--- firebird/trunk/src/include/firebird/ExternalEngine.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/include/firebird/ExternalEngine.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -43,6 +43,14 @@
const int EXTERNAL_VERSION_1 = 1;
+struct BlrMessage
+{
+ const unsigned char* blr;
+ unsigned int blrLength;
+ unsigned int bufferLength;
+};
+
+
// Connection to current database in external engine.
// Context passed to ExternalEngine has SYSDBA privileges.
// Context passed to ExternalFunction, ExternalProcedure and ExternalTrigger
@@ -97,7 +105,7 @@
Utf8* name, uint nameSize) = 0;
virtual void FB_CALL execute(Error* error, ExternalContext* context,
- UCHAR* inMsg, UCHAR* outMsg) = 0;
+ void* inMsg, void* outMsg) = 0;
};
@@ -114,7 +122,7 @@
// Returning NULL results in a result set of one record.
// Procedures without output parameters should return NULL.
virtual ExternalResultSet* FB_CALL open(Error* error, ExternalContext* context,
- UCHAR* inMsg, UCHAR* outMsg) = 0;
+ void* inMsg, void* outMsg) = 0;
};
@@ -149,7 +157,7 @@
Utf8* name, uint nameSize) = 0;
virtual void FB_CALL execute(Error* error, ExternalContext* context,
- Action action, UCHAR* oldMsg, UCHAR* newMsg) = 0;
+ Action action, void* oldMsg, void* newMsg) = 0;
};
@@ -192,9 +200,9 @@
// Called when engine wants to load object in the cache. Objects are disposed when
// going out of the cache.
virtual ExternalFunction* FB_CALL makeFunction(Error* error, ExternalContext* context,
- const IRoutineMetadata* metadata) = 0;
+ const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
virtual ExternalProcedure* FB_CALL makeProcedure(Error* error, ExternalContext* context,
- const IRoutineMetadata* metadata) = 0;
+ const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
virtual ExternalTrigger* FB_CALL makeTrigger(Error* error, ExternalContext* context,
const IRoutineMetadata* metadata) = 0;
};
Modified: firebird/trunk/src/include/firebird/Message.h
===================================================================
--- firebird/trunk/src/include/firebird/Message.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/include/firebird/Message.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -37,8 +37,7 @@
#define FB_MESSAGE_I(name, fields) \
struct name \
{ \
- /* TODO: use it */ \
- static const unsigned char* BLR() \
+ static const unsigned char* getBlr(unsigned* length) \
{ \
static const unsigned char blr[] = { \
blr_version5, \
@@ -50,10 +49,11 @@
blr_end, \
blr_eoc \
}; \
+ *length = sizeof(blr); \
return blr; \
} \
\
- static unsigned SIZE() \
+ static unsigned getSize() \
{ \
return (unsigned)(size_t) (&((name*) 0)->FB_BOOST_PP_CAT( \
FB_BOOST_PP_TUPLE_ELEM(2, 1, \
@@ -79,7 +79,7 @@
#define FB_BLR_FB_SMALLINT FB_BLR_FB_SCALED_SMALLINT(0)
#define FB_BLR_FB_INTEGER FB_BLR_FB_SCALED_INTEGER(0)
#define FB_BLR_FB_BIGINT FB_BLR_FB_SCALED_BIGINT(0)
-#define FB_BLR_FB_VARCHAR(len) blr_varying, (len) & 0xFF, (len) >> 8
+#define FB_BLR_FB_VARCHAR(len) blr_varying2, 0, 0, (len) & 0xFF, (len) >> 8
#define FB_TYPE_FB_SCALED_SMALLINT(x) ISC_SHORT
#define FB_TYPE_FB_SCALED_INTEGER(x) ISC_LONG
@@ -87,7 +87,7 @@
#define FB_TYPE_FB_SMALLINT ISC_SHORT
#define FB_TYPE_FB_INTEGER ISC_LONG
#define FB_TYPE_FB_BIGINT ISC_INT64
-#define FB_TYPE_FB_VARCHAR(len) FbVarChar<(len)>
+#define FB_TYPE_FB_VARCHAR(len) ::Firebird::FbVarChar<(len)>
namespace Firebird {
Modified: firebird/trunk/src/include/firebird/UdrCppEngine.h
===================================================================
--- firebird/trunk/src/include/firebird/UdrCppEngine.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/include/firebird/UdrCppEngine.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -75,7 +75,7 @@
#define FB_UDR_EXECUTE__FUNCTION \
virtual void FB_CALL execute(::Firebird::Error* error, ::Firebird::ExternalContext* context, \
- UCHAR* inMsg, UCHAR* outMsg) \
+ void* inMsg, void* outMsg) \
{ \
try \
{ \
@@ -131,7 +131,7 @@
#define FB_UDR_EXECUTE__PROCEDURE \
virtual ::Firebird::ExternalResultSet* FB_CALL open(::Firebird::Error* error, \
- ::Firebird::ExternalContext* context, UCHAR* inMsg, UCHAR* outMsg) \
+ ::Firebird::ExternalContext* context, void* inMsg, void* outMsg) \
{ \
try \
{ \
@@ -192,7 +192,7 @@
{ \
public: \
virtual void FB_CALL execute(::Firebird::Error* error, ::Firebird::ExternalContext* context, \
- ::Firebird::ExternalTrigger::Action action, UCHAR* oldMsg, UCHAR* newMsg);
+ ::Firebird::ExternalTrigger::Action action, void* oldMsg, void* newMsg);
#define FB_UDR_END_DECLARE_TRIGGER(name) \
};
@@ -204,7 +204,7 @@
#define FB_UDR_BEGIN_TRIGGER(name) \
void FB_CALL FB_UDR_TRIGGER(name)::execute(::Firebird::Error* error, \
::Firebird::ExternalContext* context, ::Firebird::ExternalTrigger::Action action, \
- UCHAR* oldMsg, UCHAR* newMsg) \
+ void* oldMsg, void* newMsg) \
{ \
try \
{
@@ -459,11 +459,6 @@
ThrowError::check(status);
return handle;
}
-
- static void* getEntryPoint(ExternalContext* /*context*/, const char* entryPoint)
- {
- return fbUdrGetFunction(entryPoint);
- }
};
@@ -602,16 +597,15 @@
template <typename T> class FunctionFactoryImpl : public FunctionFactory
{
public:
- explicit FunctionFactoryImpl(const char* aName)
- : name(aName)
+ explicit FunctionFactoryImpl(const char* name)
{
- fbUdrRegFunction(this);
+ fbUdrRegFunction(name, this);
}
-public:
- virtual const char* FB_CALL getName()
+ virtual void setup(const IRoutineMetadata* /*metadata*/, BlrMessage* inBlr, BlrMessage* outBlr)
{
- return name;
+ setBlr(inBlr, (typename T::InMessage*) 0);
+ setBlr(outBlr, (typename T::OutMessage*) 0);
}
virtual ExternalFunction* FB_CALL newItem(const IRoutineMetadata* metadata)
@@ -620,23 +614,30 @@
}
private:
- const char* name;
+ template <typename MessageType> void setBlr(BlrMessage* blrMessage, MessageType*)
+ {
+ blrMessage->blr = MessageType::getBlr(&blrMessage->blrLength);
+ blrMessage->bufferLength = MessageType::getSize();
+ }
+
+ void setBlr(BlrMessage* blrMessage, void**)
+ {
+ }
};
template <typename T> class ProcedureFactoryImpl : public ProcedureFactory
{
public:
- explicit ProcedureFactoryImpl(const char* aName)
- : name(aName)
+ explicit ProcedureFactoryImpl(const char* name)
{
- fbUdrRegProcedure(this);
+ fbUdrRegProcedure(name, this);
}
-public:
- virtual const char* FB_CALL getName()
+ virtual void setup(const IRoutineMetadata* /*metadata*/, BlrMessage* inBlr, BlrMessage* outBlr)
{
- return name;
+ setBlr(inBlr, (typename T::InMessage*) 0);
+ setBlr(outBlr, (typename T::OutMessage*) 0);
}
virtual ExternalProcedure* FB_CALL newItem(const IRoutineMetadata* metadata)
@@ -645,32 +646,34 @@
}
private:
- const char* name;
+ template <typename MessageType> void setBlr(BlrMessage* blrMessage, MessageType*)
+ {
+ blrMessage->blr = MessageType::getBlr(&blrMessage->blrLength);
+ blrMessage->bufferLength = MessageType::getSize();
+ }
+
+ void setBlr(BlrMessage* blrMessage, void**)
+ {
+ }
};
template <typename T> class TriggerFactoryImpl : public TriggerFactory
{
public:
- explicit TriggerFactoryImpl(const char* aName)
- : name(aName)
+ explicit TriggerFactoryImpl(const char* name)
{
- fbUdrRegTrigger(this);
+ fbUdrRegTrigger(name, this);
}
-public:
- virtual const char* FB_CALL getName()
+ virtual void setup(const IRoutineMetadata* /*metadata*/)
{
- return name;
}
virtual ExternalTrigger* FB_CALL newItem(const IRoutineMetadata* metadata)
{
return new(metadata) Routine<T>;
}
-
-private:
- const char* name;
};
Modified: firebird/trunk/src/include/firebird/UdrEngine.h
===================================================================
--- firebird/trunk/src/include/firebird/UdrEngine.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/include/firebird/UdrEngine.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -39,30 +39,29 @@
class FunctionFactory
{
public:
- virtual const char* FB_CALL getName() = 0;
+ virtual void setup(const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
virtual ExternalFunction* FB_CALL newItem(const IRoutineMetadata* metadata) = 0;
};
class ProcedureFactory
{
public:
- virtual const char* FB_CALL getName() = 0;
+ virtual void setup(const IRoutineMetadata* metadata, BlrMessage* inBlr, BlrMessage* outBlr) = 0;
virtual ExternalProcedure* FB_CALL newItem(const IRoutineMetadata* metadata) = 0;
};
class TriggerFactory
{
public:
- virtual const char* FB_CALL getName() = 0;
+ virtual void setup(const IRoutineMetadata* metadata) = 0;
virtual ExternalTrigger* FB_CALL newItem(const IRoutineMetadata* metadata) = 0;
};
// Routine registration functions.
-extern "C" void fbUdrRegFunction(FunctionFactory* factory);
-extern "C" void fbUdrRegProcedure(ProcedureFactory* factory);
-extern "C" void fbUdrRegTrigger(TriggerFactory* factory);
-extern "C" void* fbUdrGetFunction(const char* symbol);
+extern "C" void fbUdrRegFunction(const char* name, FunctionFactory* factory);
+extern "C" void fbUdrRegProcedure(const char* name, ProcedureFactory* factory);
+extern "C" void fbUdrRegTrigger(const char* name, TriggerFactory* factory);
//------------------------------------------------------------------------------
Modified: firebird/trunk/src/include/gen/codetext.h
===================================================================
--- firebird/trunk/src/include/gen/codetext.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/include/gen/codetext.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -727,6 +727,8 @@
{"invalid_boolean_usage", 335545023},
{"sysf_argscant_both_be_zero", 335545024},
{"spb_no_id", 335545025},
+ {"ee_blr_mismatch_null", 335545026},
+ {"ee_blr_mismatch_length", 335545027},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},
Modified: firebird/trunk/src/include/gen/iberror.h
===================================================================
--- firebird/trunk/src/include/gen/iberror.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/include/gen/iberror.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -761,6 +761,8 @@
const ISC_STATUS isc_invalid_boolean_usage = 335545023L;
const ISC_STATUS isc_sysf_argscant_both_be_zero = 335545024L;
const ISC_STATUS isc_spb_no_id = 335545025L;
+const ISC_STATUS isc_ee_blr_mismatch_null = 335545026L;
+const ISC_STATUS isc_ee_blr_mismatch_length = 335545027L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@@ -1180,7 +1182,7 @@
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
-const ISC_STATUS isc_err_max = 1124;
+const ISC_STATUS isc_err_max = 1126;
#else /* c definitions */
@@ -1911,6 +1913,8 @@
#define isc_invalid_boolean_usage 335545023L
#define isc_sysf_argscant_both_be_zero 335545024L
#define isc_spb_no_id 335545025L
+#define isc_ee_blr_mismatch_null 335545026L
+#define isc_ee_blr_mismatch_length 335545027L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@@ -2330,7 +2334,7 @@
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
-#define isc_err_max 1124
+#define isc_err_max 1126
#endif
Modified: firebird/trunk/src/include/gen/msgs.h
===================================================================
--- firebird/trunk/src/include/gen/msgs.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/include/gen/msgs.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -730,6 +730,8 @@
{335545023, "Invalid usage of boolean expression"}, /* invalid_boolean_usage */
{335545024, "Arguments for @1 cannot both be zero"}, /* sysf_argscant_both_be_zero */
{335545025, "missing service ID in spb"}, /* spb_no_id */
+ {335545026, "External BLR message mismatch: invalid null descriptor at field @1"}, /* ee_blr_mismatch_null */
+ {335545027, "External BLR message mismatch: length = @1, expected @2"}, /* ee_blr_mismatch_length */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
Modified: firebird/trunk/src/include/gen/sql_code.h
===================================================================
--- firebird/trunk/src/include/gen/sql_code.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/include/gen/sql_code.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -726,6 +726,8 @@
{335545023, -104}, /* 703 invalid_boolean_usage */
{335545024, -833}, /* 704 sysf_argscant_both_be_zero */
{335545025, -901}, /* 705 spb_no_id */
+ {335545026, -901}, /* 706 ee_blr_mismatch_null */
+ {335545027, -901}, /* 707 ee_blr_mismatch_length */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */
Modified: firebird/trunk/src/include/gen/sql_state.h
===================================================================
--- firebird/trunk/src/include/gen/sql_state.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/include/gen/sql_state.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -726,6 +726,8 @@
{335545023, "22000"}, // 703 invalid_boolean_usage
{335545024, "42000"}, // 704 sysf_argscant_both_be_zero
{335545025, "HY000"}, // 705 spb_no_id
+ {335545026, "42000"}, // 706 ee_blr_mismatch_null
+ {335545027, "42000"}, // 707 ee_blr_mismatch_length
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw
Modified: firebird/trunk/src/jrd/BlrReader.h
===================================================================
--- firebird/trunk/src/jrd/BlrReader.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/jrd/BlrReader.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -103,6 +103,40 @@
return high * 256 + low;
}
+ UCHAR checkByte(UCHAR expected)
+ {
+ using namespace Firebird;
+
+ UCHAR byte = getByte();
+
+ if (byte != expected)
+ {
+ status_exception::raise(Arg::Gds(isc_syntaxerr) <<
+ Arg::Num(expected) <<
+ Arg::Num(getOffset() - 1) <<
+ Arg::Num(byte));
+ }
+
+ return byte;
+ }
+
+ USHORT checkWord(USHORT expected)
+ {
+ using namespace Firebird;
+
+ USHORT word = getWord();
+
+ if (word != expected)
+ {
+ status_exception::raise(Arg::Gds(isc_syntaxerr) <<
+ Arg::Num(expected) <<
+ Arg::Num(getOffset() - 2) <<
+ Arg::Num(word));
+ }
+
+ return word;
+ }
+
private:
const UCHAR* start;
const UCHAR* end;
Modified: firebird/trunk/src/jrd/ExtEngineManager.cpp
===================================================================
--- firebird/trunk/src/jrd/ExtEngineManager.cpp 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/jrd/ExtEngineManager.cpp 2011-07-10 01:23:53 UTC (rev 53285)
@@ -594,7 +594,8 @@
ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, const Jrd::Function* udf,
- const MetaName& engine, const string& entryPoint, const string& body)
+ const MetaName& engine, const string& entryPoint, const string& body,
+ BlrMessage* inBlr, BlrMessage* outBlr)
{
string entryPointTrimmed = entryPoint;
entryPointTrimmed.trim();
@@ -640,7 +641,8 @@
{ // scope
Attachment::Checkout attCout(tdbb->getAttachment());
- externalFunction = attInfo->engine->makeFunction(RaiseError(), attInfo->context, metadata);
+ externalFunction = attInfo->engine->makeFunction(RaiseError(), attInfo->context, metadata,
+ inBlr, outBlr);
if (!externalFunction)
{
@@ -665,7 +667,8 @@
ExtEngineManager::Procedure* ExtEngineManager::makeProcedure(thread_db* tdbb, const jrd_prc* prc,
- const MetaName& engine, const string& entryPoint, const string& body)
+ const MetaName& engine, const string& entryPoint, const string& body,
+ BlrMessage* inBlr, BlrMessage* outBlr)
{
string entryPointTrimmed = entryPoint;
entryPointTrimmed.trim();
@@ -716,7 +719,8 @@
{ // scope
Attachment::Checkout attCout(tdbb->getAttachment());
- externalProcedure = attInfo->engine->makeProcedure(RaiseError(), attInfo->context, metadata);
+ externalProcedure = attInfo->engine->makeProcedure(RaiseError(), attInfo->context, metadata,
+ inBlr, outBlr);
if (!externalProcedure)
{
Modified: firebird/trunk/src/jrd/ExtEngineManager.h
===================================================================
--- firebird/trunk/src/jrd/ExtEngineManager.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/jrd/ExtEngineManager.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -304,10 +304,10 @@
Function* makeFunction(thread_db* tdbb, const Jrd::Function* udf,
const Firebird::MetaName& engine, const Firebird::string& entryPoint,
- const Firebird::string& body);
+ const Firebird::string& body, Firebird::BlrMessage* inBlr, Firebird::BlrMessage* outBlr);
Procedure* makeProcedure(thread_db* tdbb, const jrd_prc* prc,
const Firebird::MetaName& engine, const Firebird::string& entryPoint,
- const Firebird::string& body);
+ const Firebird::string& body, Firebird::BlrMessage* inBlr, Firebird::BlrMessage* outBlr);
Trigger* makeTrigger(thread_db* tdbb, const Jrd::Trigger* trg,
const Firebird::MetaName& engine, const Firebird::string& entryPoint,
const Firebird::string& body, Firebird::ExternalTrigger::Type type);
Modified: firebird/trunk/src/jrd/Function.epp
===================================================================
--- firebird/trunk/src/jrd/Function.epp 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/jrd/Function.epp 2011-07-10 01:23:53 UTC (rev 53285)
@@ -386,16 +386,25 @@
body.getBuffer(1)[0] = 0;
}
+ BlrMessage inBlr;
+ inBlr.blr = NULL;
+ inBlr.blrLength = 0;
+ inBlr.bufferLength = 0;
+
+ BlrMessage outBlr;
+ outBlr.blr = NULL;
+ outBlr.blrLength = 0;
+ outBlr.bufferLength = 0;
+
function->fun_external =
dbb->dbb_extManager.makeFunction(tdbb, function, X.RDB$ENGINE_NAME,
- (X.RDB$ENTRYPOINT.NULL ? "" : X.RDB$ENTRYPOINT), (char*) body.begin());
+ (X.RDB$ENTRYPOINT.NULL ? "" : X.RDB$ENTRYPOINT), (char*) body.begin(),
+ &inBlr, &outBlr);
if (!function->fun_external)
- {
function->setImplemented(false);
- }
- function->makeFormat();
+ function->makeFormat(tdbb, (inBlr.blr ? &inBlr : NULL), (outBlr.blr ? &outBlr : NULL));
}
else if (!X.RDB$FUNCTION_BLR.NULL)
{
@@ -427,7 +436,7 @@
throw;
}
- function->makeFormat();
+ function->makeFormat(tdbb, NULL, NULL);
}
else if (!X.RDB$MODULE_NAME.NULL && !X.RDB$ENTRYPOINT.NULL)
{
@@ -566,6 +575,23 @@
fb_assert(fun_out_msg_format.fmt_count == 2);
fb_assert(fun_out_msg_format.fmt_length);
CMP_impure(csb, fun_out_msg_format.fmt_length);
+
+ if (fun_in_msg_format2.fmt_count)
+ {
+ fb_assert(fun_in_msg_format2.fmt_length);
+ CMP_impure(csb, fun_in_msg_format2.fmt_length);
+ }
+
+ fb_assert(fun_out_msg_format2.fmt_count == 2 ||
+ (fun_out_msg_format2.fmt_length == 0 && fun_out_msg_format2.fmt_count == 0));
+
+ if (fun_out_msg_format2.fmt_length)
+ {
+ fb_assert(fun_out_msg_format2.fmt_count == 2);
+ CMP_impure(csb, fun_out_msg_format2.fmt_length);
+ }
+ else
+ fb_assert(fun_out_msg_format2.fmt_count == 0);
}
return impure;
@@ -719,34 +745,77 @@
Jrd::Attachment* attachment = tdbb->getAttachment();
- const ULONG in_msg_length = fun_in_msg_format.fmt_length;
- const ULONG out_msg_length = fun_out_msg_format.fmt_length;
+ const ULONG inMsgLength = fun_in_msg_format.fmt_length;
+ const ULONG outMsgLength = fun_out_msg_format.fmt_length;
UCHAR* const impure = reinterpret_cast<UCHAR*>(value);
- UCHAR* const in_msg = (UCHAR*) FB_ALIGN((IPTR) impure + sizeof(impure_value), FB_ALIGNMENT);
- UCHAR* const out_msg = (UCHAR*) FB_ALIGN((IPTR) in_msg + in_msg_length, FB_ALIGNMENT);
+ UCHAR* const inMsg = (UCHAR*) FB_ALIGN((IPTR) impure + sizeof(impure_value), FB_ALIGNMENT);
+ UCHAR* const outMsg = (UCHAR*) FB_ALIGN((IPTR) inMsg + inMsgLength, FB_ALIGNMENT);
+ const ULONG inMsgLength2 = fun_in_msg_format2.fmt_length;
+ const ULONG outMsgLength2 = fun_out_msg_format2.fmt_length;
+ UCHAR* const inMsg2 = inMsgLength2 ?
+ (UCHAR*) FB_ALIGN((IPTR) outMsg + outMsgLength, FB_ALIGNMENT) : inMsg;
+ UCHAR* const outMsg2 = outMsgLength2 ?
+ (UCHAR*) FB_ALIGN((IPTR) inMsg2 + inMsgLength2, FB_ALIGNMENT) : outMsg;
+
for (USHORT i = 0; i < fun_inputs; i++)
{
- const ULONG arg_offset = (IPTR) fun_in_msg_format.fmt_desc[i * 2].dsc_address;
- const ULONG null_offset = (IPTR) fun_in_msg_format.fmt_desc[i * 2 + 1].dsc_address;
- UCHAR* const null_ptr = in_msg + null_offset;
+ const ULONG argOffset = (IPTR) fun_in_msg_format.fmt_desc[i * 2].dsc_address;
+ const ULONG nullOffset = (IPTR) fun_in_msg_format.fmt_desc[i * 2 + 1].dsc_address;
+ SSHORT* const nullPtr = reinterpret_cast<SSHORT*>(inMsg + nullOffset);
+ dsc argDesc = fun_args[i + 1].fun_parameter->prm_desc;
+ argDesc.dsc_address = inMsg + argOffset;
- dsc* const src_desc = EVL_expr(tdbb, request, args[i]);
- if (src_desc && !(request->req_flags & req_null))
+ //// TODO: Validate constraints for external.
+ dsc* const srcDesc = EVL_expr(tdbb, request, args[i]);
+ if (srcDesc && !(request->req_flags & req_null))
{
- *reinterpret_cast<SSHORT*>(null_ptr) = FALSE;
+ *nullPtr = FALSE;
+ MOV_move(tdbb, srcDesc, &argDesc);
+ }
+ else
+ *nullPtr = TRUE;
- dsc arg_desc = fun_args[i + 1].fun_parameter->prm_desc;
- arg_desc.dsc_address = in_msg + arg_offset;
- MOV_move(tdbb, src_desc, &arg_desc);
+ if (fun_external && inMsgLength2)
+ {
+ const ULONG argOffset2 = (IPTR) fun_in_msg_format2.fmt_desc[i * 2].dsc_address;
+ const ULONG nullOffset2 = (IPTR) fun_in_msg_format2.fmt_desc[i * 2 + 1].dsc_address;
+ SSHORT* const nullPtr2 = reinterpret_cast<SSHORT*>(inMsg2 + nullOffset2);
+
+ if (!(*nullPtr2 = *nullPtr))
+ {
+ dsc argDesc2 = fun_in_msg_format2.fmt_desc[i * 2];
+ argDesc2.dsc_address = inMsg2 + argOffset2;
+ MOV_move(tdbb, &argDesc, &argDesc2);
+ }
}
- else
- *reinterpret_cast<SSHORT*>(null_ptr) = TRUE;
}
+ const ULONG argOffset = (IPTR) fun_out_msg_format.fmt_desc[0].dsc_address;
+ const ULONG nullOffset = (IPTR) fun_out_msg_format.fmt_desc[1].dsc_address;
+ SSHORT* const nullPtr = reinterpret_cast<SSHORT*>(outMsg + nullOffset);
+ dsc argDesc = fun_args[fun_return_arg].fun_parameter->prm_desc;
+ argDesc.dsc_address = outMsg + argOffset;
+
if (fun_external)
- fun_external->execute(tdbb, in_msg, out_msg);
+ {
+ fun_external->execute(tdbb, inMsg2, outMsg2);
+
+ if (outMsgLength2)
+ {
+ const ULONG argOffset2 = (IPTR) fun_out_msg_format2.fmt_desc[0].dsc_address;
+ const ULONG nullOffset2 = (IPTR) fun_out_msg_format2.fmt_desc[1].dsc_address;
+ SSHORT* const nullPtr2 = reinterpret_cast<SSHORT*>(outMsg2 + nullOffset2);
+
+ if (!(*nullPtr = *nullPtr2))
+ {
+ dsc argDesc2 = fun_out_msg_format2.fmt_desc[0];
+ argDesc2.dsc_address = outMsg2 + argOffset2;
+ MOV_move(tdbb, &argDesc2, &argDesc);
+ }
+ }
+ }
else
{
jrd_req* const new_request = getStatement()->findRequest(tdbb);
@@ -764,13 +833,11 @@
EXE_start(tdbb, new_request, transaction);
- if (in_msg_length)
- {
- EXE_send(tdbb, new_request, 0, in_msg_length, in_msg);
- }
+ if (inMsgLength)
+ EXE_send(tdbb, new_request, 0, inMsgLength, inMsg);
- fb_assert(out_msg_length);
- EXE_receive(tdbb, new_request, 1, out_msg_length, out_msg);
+ fb_assert(outMsgLength);
+ EXE_receive(tdbb, new_request, 1, outMsgLength, outMsg);
// Clean up all savepoints started during execution of the function
@@ -799,18 +866,13 @@
new_request->req_flags &= ~req_in_use;
}
- const ULONG arg_offset = (IPTR) fun_out_msg_format.fmt_desc[0].dsc_address;
- const ULONG null_offset = (IPTR) fun_out_msg_format.fmt_desc[1].dsc_address;
-
- UCHAR* const null_ptr = out_msg + null_offset;
- if (*reinterpret_cast<SSHORT*>(null_ptr))
+ //// TODO: Validate constraints for external.
+ if (*nullPtr)
request->req_flags |= req_null;
else
{
- dsc arg_desc = fun_args[fun_return_arg].fun_parameter->prm_desc;
- arg_desc.dsc_address = out_msg + arg_offset;
request->req_flags &= ~req_null;
- MOV_move(tdbb, &arg_desc, &value->vlu_desc);
+ MOV_move(tdbb, &argDesc, &value->vlu_desc);
}
}
else
@@ -841,15 +903,105 @@
return ++fun_alter_count;
}
-void Function::makeFormat()
+void Function::makeFormat(thread_db* tdbb, const BlrMessage* inBlr, const BlrMessage* outBlr)
{
// Input format
- const USHORT count = fun_inputs * 2;
+ bool messageNeeded = false;
+ ULONG offset = 0;
+ UCHAR maxAlignment = 0;
+ USHORT count;
+
+ dsc shortDesc;
+ shortDesc.makeShort(0);
+
+ if (inBlr)
+ {
+ BlrReader reader(inBlr->blr, inBlr->blrLength);
+
+ reader.checkByte(blr_version5);
+ reader.checkByte(blr_begin);
+ reader.checkByte(blr_message);
+ reader.getByte(); // message number: ignore it
+ count = reader.checkWord(fun_inputs * 2);
+
+ fun_in_msg_format2.fmt_desc.resize(count);
+ fun_in_msg_format2.fmt_count = count;
+
+ for (unsigned i = 0; i < count / 2; ++i)
+ {
+ dsc* desc = &fun_in_msg_format2.fmt_desc[i * 2];
+ PAR_datatype(tdbb, reader, desc);
+
+ if (desc->dsc_dtype >= dtype_aligned)
+ {
+ maxAlignment = MAX(maxAlignment, type_alignments[desc->dsc_dtype]);
+ offset = FB_ALIGN(offset, type_alignments[desc->dsc_dtype]);
+ }
+
+ desc->dsc_address = (UCHAR*)(IPTR) offset;
+ offset += desc->dsc_length;
+
+ const dsc* prmDesc = &fun_args[i + 1].fun_parameter->prm_desc;
+
+ if (desc->isText() && desc->getCharSet() == CS_NONE)
+ desc->setTextType(prmDesc->getTextType());
+ desc->setNullable(prmDesc->isNullable());
+
+ messageNeeded |= !DSC_EQUIV(desc, prmDesc, false);
+
+ ++desc;
+ PAR_datatype(tdbb, reader, desc);
+
+ if (!DSC_EQUIV(desc, &shortDesc, false))
+ {
+ status_exception::raise(
+ Arg::Gds(isc_ee_blr_mismatch_null) <<
+ Arg::Num(i * 2 + 1));
+ }
+
+ offset = FB_ALIGN(offset, sizeof(SSHORT));
+ desc->dsc_address = (UCHAR*)(IPTR) offset;
+ offset += sizeof(SSHORT);
+
+ messageNeeded |= !DSC_EQUIV(desc, &shortDesc, false);
+ }
+
+ reader.checkByte(blr_end);
+ reader.checkByte(blr_eoc);
+
+ if (offset != inBlr->bufferLength)
+ {
+ status_exception::raise(
+ Arg::Gds(isc_ee_blr_mismatch_length) <<
+ Arg::Num(inBlr->bufferLength) <<
+ Arg::Num(offset));
+ }
+
+ if (messageNeeded)
+ {
+ // Pad the external message.
+ offset = FB_ALIGN(offset, MAX(maxAlignment, sizeof(SSHORT)));
+
+ if (offset > MAX_MESSAGE_SIZE)
+ status_exception::raise(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig));
+
+ fun_in_msg_format2.fmt_length = offset;
+ }
+ else
+ {
+ // The external and internal messages are compatible, so there is no need to create a new one.
+ fun_in_msg_format2.fmt_desc.clear();
+ fun_in_msg_format2.fmt_count = 0;
+ }
+ }
+
+ count = fun_inputs * 2;
fun_in_msg_format.fmt_desc.resize(count);
fun_in_msg_format.fmt_count = count;
- ULONG offset = 0;
+ offset = 0;
+ maxAlignment = 0;
for (USHORT i = 0; i < fun_inputs; i++)
{
@@ -857,8 +1009,10 @@
if (arg_desc.dsc_dtype >= dtype_aligned)
{
+ maxAlignment = MAX(maxAlignment, type_alignments[arg_desc.dsc_dtype]);
offset = FB_ALIGN(offset, type_alignments[arg_desc.dsc_dtype]);
}
+
arg_desc.dsc_address = (UCHAR*)(IPTR) offset;
offset += arg_desc.dsc_length;
fun_in_msg_format.fmt_desc[i * 2] = arg_desc;
@@ -870,23 +1024,100 @@
fun_in_msg_format.fmt_desc[i * 2 + 1] = arg_desc;
}
- if (offset > MAX_MESSAGE_SIZE)
+ if (!messageNeeded)
{
- status_exception::raise(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig));
+ // This message will be used by external. Pad it.
+ offset = FB_ALIGN(offset, MAX(maxAlignment, sizeof(SSHORT)));
}
+ if (offset > MAX_MESSAGE_SIZE)
+ status_exception::raise(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig));
+
fun_in_msg_format.fmt_length = offset;
// Output format
+ messageNeeded = false;
+
+ if (outBlr)
+ {
+ BlrReader reader(outBlr->blr, outBlr->blrLength);
+
+ reader.checkByte(blr_version5);
+ reader.checkByte(blr_begin);
+ reader.checkByte(blr_message);
+ reader.getByte(); // message number: ignore it
+ count = reader.checkWord(2);
+
+ fun_out_msg_format2.fmt_desc.resize(2);
+ fun_out_msg_format2.fmt_count = 2;
+
+ offset = 0;
+
+ dsc* desc = &fun_out_msg_format2.fmt_desc[0];
+ PAR_datatype(tdbb, reader, desc);
+
+ if (desc->dsc_dtype >= dtype_aligned)
+ offset = FB_ALIGN(offset, type_alignments[desc->dsc_dtype]);
+
+ desc->dsc_address = (UCHAR*)(IPTR) offset;
+ offset += desc->dsc_length;
+
+ const dsc* prmDesc = &fun_args[fun_return_arg].fun_parameter->prm_desc;
+
+ if (desc->isText() && desc->getCharSet() == CS_NONE)
+ desc->setTextType(prmDesc->getTextType());
+ desc->setNullable(prmDesc->isNullable());
+
+ messageNeeded |= !DSC_EQUIV(desc, prmDesc, false);
+
+ ++desc;
+ PAR_datatype(tdbb, reader, desc);
+
+ if (!DSC_EQUIV(desc, &shortDesc, false))
+ {
+ status_exception::raise(
+ Arg::Gds(isc_ee_blr_mismatch_null) <<
+ Arg::Num(1));
+ }
+
+ offset = FB_ALIGN(offset, sizeof(SSHORT));
+ desc->dsc_address = (UCHAR*)(IPTR) offset;
+ offset += sizeof(SSHORT);
+
+ messageNeeded |= !DSC_EQUIV(desc, &shortDesc, false);
+
+ reader.checkByte(blr_end);
+ reader.checkByte(blr_eoc);
+
+ if (offset != outBlr->bufferLength)
+ {
+ status_exception::raise(
+ Arg::Gds(isc_ee_blr_mismatch_length) <<
+ Arg::Num(outBlr->bufferLength) <<
+ Arg::Num(offset));
+ }
+
+ // Pad the external message.
+ offset = FB_ALIGN(offset,
+ MAX(type_alignments[fun_out_msg_format2.fmt_desc[0].dsc_dtype], sizeof(SSHORT)));
+
+ if (messageNeeded)
+ fun_out_msg_format2.fmt_length = offset;
+ else
+ {
+ // The external and internal messages are compatible, so there is no need to create a new one.
+ fun_out_msg_format2.fmt_desc.clear();
+ fun_out_msg_format2.fmt_count = 0;
+ }
+ }
+
fun_out_msg_format.fmt_desc.resize(2);
fun_out_msg_format.fmt_count = 2;
- offset = 0;
-
dsc ret_desc = fun_args[fun_return_arg].fun_parameter->prm_desc;
- ret_desc.dsc_address = (UCHAR*)(IPTR) offset;
- offset += ret_desc.dsc_length;
+ ret_desc.dsc_address = (UCHAR*)(IPTR) 0;
+ offset = ret_desc.dsc_length;
fun_out_msg_format.fmt_desc[0] = ret_desc;
ret_desc.makeShort(0);
@@ -895,5 +1126,13 @@
offset += sizeof(SSHORT);
fun_out_msg_format.fmt_desc[1] = ret_desc;
+ if (!messageNeeded)
+ {
+ // This message will be used by external. Pad it.
+ offset = FB_ALIGN(offset,
+ MAX(type_alignments[fun_args[fun_return_arg].fun_parameter->prm_desc.dsc_dtype],
+ sizeof(SSHORT)));
+ }
+
fun_out_msg_format.fmt_length = offset;
}
Modified: firebird/trunk/src/jrd/Function.h
===================================================================
--- firebird/trunk/src/jrd/Function.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/jrd/Function.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -75,6 +75,8 @@
fun_temp_length(0),
fun_in_msg_format(p, 0),
fun_out_msg_format(p, 0),
+ fun_in_msg_format2(p, 0),
+ fun_out_msg_format2(p, 0),
fun_args(p),
fun_flags(0),
fun_use_count(0),
@@ -86,7 +88,8 @@
{
}
- void makeFormat();
+ void makeFormat(thread_db* tdbb, const Firebird::BlrMessage* inBlr,
+ const Firebird::BlrMessage* outBlr);
static Function* loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT flags);
static int blockingAst(void*);
@@ -111,6 +114,8 @@
Format fun_in_msg_format;
Format fun_out_msg_format;
+ Format fun_in_msg_format2;
+ Format fun_out_msg_format2;
Firebird::Array<Argument> fun_args;
Modified: firebird/trunk/src/jrd/exe.cpp
===================================================================
--- firebird/trunk/src/jrd/exe.cpp 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/jrd/exe.cpp 2011-07-10 01:23:53 UTC (rev 53285)
@@ -202,6 +202,7 @@
fb_sqlstate(sqlstate, status);
}
+static void execute_ext_procedure(thread_db* tdbb, jrd_req* request);
static void execute_looper(thread_db*, jrd_req*, jrd_tra*, jrd_req::req_s);
static void looper_seh(thread_db*, jrd_req*);
static void release_blobs(thread_db*, jrd_req*);
@@ -1048,7 +1049,108 @@
}
+// Execute an external procedure.
+static void execute_ext_procedure(thread_db* tdbb, jrd_req* request)
+{
+ const JrdStatement* statement = request->getStatement();
+ fb_assert(statement->topNode->kind == DmlNode::KIND_STATEMENT);
+ const CompoundStmtNode* extStmts = StmtNode::as<CompoundStmtNode>(
+ static_cast<const StmtNode*>(statement->topNode));
+ fb_assert(extStmts);
+
+ switch (request->req_operation)
+ {
+ case jrd_req::req_evaluate:
+ request->req_message = extStmts->statements[e_extproc_input_message]->as<MessageNode>();
+ request->req_flags |= req_stall;
+ request->req_operation = jrd_req::req_receive;
+ break;
+
+ case jrd_req::req_sync:
+ {
+ const MessageNode* outMsgNode =
+ extStmts->statements[e_extproc_output_message]->as<MessageNode>();
+ fb_assert(outMsgNode);
+
+ const Format* outFormat = outMsgNode->format;
+
+ if (!request->resultSet)
+ {
+ const MessageNode* inMsgNode =
+ extStmts->statements[e_extproc_input_message]->as<MessageNode>();
+ fb_assert(inMsgNode && request->req_message == inMsgNode);
+
+ const CompoundStmtNode* list =
+ extStmts->statements[e_extproc_input_assign]->as<CompoundStmtNode>();
+ fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
+
+ const Format* format = inMsgNode->format;
+
+ // Clear the flags from the input message.
+ USHORT* impure_flags = request->getImpure<USHORT>(inMsgNode->impureFlags);
+ memset(impure_flags, 0, sizeof(USHORT) * format->fmt_count);
+
+ // Clear the flags from the output message.
+ impure_flags = request->getImpure<USHORT>(outMsgNode->impureFlags);
+ memset(impure_flags, 0, sizeof(USHORT) * outFormat->fmt_count);
+
+ // Validate/move input parameters.
+ for (size_t i = 0; i < list->statements.getCount(); ++i)
+ {
+ EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
+ list->statements[i].getObject()));
+ }
+
+ const MessageNode* inMsgNode2 =
+ extStmts->statements[e_extproc_input_message2]->as<MessageNode>();
+ if (!inMsgNode2)
+ inMsgNode2 = inMsgNode;
+
+ const MessageNode* outMsgNode2 =
+ extStmts->statements[e_extproc_output_message2]->as<MessageNode>();
+ if (!outMsgNode2)
+ outMsgNode2 = outMsgNode;
+
+ UCHAR* inMsg = request->getImpure<UCHAR>(inMsgNode2->impureOffset);
+ UCHAR* outMsg = request->getImpure<UCHAR>(outMsgNode2->impureOffset);
+
+ request->resultSet = statement->procedure->getExternal()->open(tdbb, inMsg, outMsg);
+ }
+
+ request->req_message = outMsgNode;
+ bool result = request->resultSet->fetch(tdbb);
+ UCHAR* outMsg = request->getImpure<UCHAR>(outMsgNode->impureOffset);
+
+ // Set the eof flag.
+ const dsc& eofDesc = outFormat->fmt_desc[outFormat->fmt_count - 1];
+ fb_assert(eofDesc.dsc_dtype == dtype_short);
+ *((SSHORT*)(UCHAR*) (outMsg + (IPTR) eofDesc.dsc_address)) = (SSHORT) result;
+
+ const CompoundStmtNode* list =
+ extStmts->statements[e_extproc_output_assign]->as<CompoundStmtNode>();
+ fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
+
+ if (result)
+ {
+ // Validate/move output parameters.
+ for (size_t i = 0; i < list->statements.getCount(); ++i)
+ {
+ EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
+ list->statements[i].getObject()));
+ }
+ }
+
+ break;
+ }
+
+ default:
+ fb_assert(false);
+ break;
+ }
+}
+
+
static void execute_looper(thread_db* tdbb,
jrd_req* request,
jrd_tra* transaction, jrd_req::req_s next_state)
@@ -1362,100 +1464,12 @@
else
break;
- fb_assert(statement->topNode->kind == DmlNode::KIND_STATEMENT);
- const CompoundStmtNode* extStmts = StmtNode::as<CompoundStmtNode>(
- static_cast<const StmtNode*>(statement->topNode));
- fb_assert(extStmts);
-
- switch (request->req_operation)
- {
- case jrd_req::req_evaluate:
- request->req_message = extStmts->statements[e_extproc_input_message]->as<MessageNode>();
- request->req_flags |= req_stall;
- request->req_operation = jrd_req::req_receive;
- break;
-
- case jrd_req::req_sync:
- {
- const MessageNode* outMsgNode =
- extStmts->statements[e_extproc_output_message]->as<MessageNode>();
- fb_assert(outMsgNode);
-
- const Format* outFormat = outMsgNode->format;
- UCHAR* outMsg = request->getImpure<UCHAR>(outMsgNode->impureOffset);
-
- if (!request->resultSet)
- {
- // input message
- const MessageNode* inMsgNode =
- extStmts->statements[e_extproc_input_message]->as<MessageNode>();
- fb_assert(inMsgNode);
- fb_assert(request->req_message == inMsgNode);
-
- const CompoundStmtNode* list =
- extStmts->statements[e_extproc_input_assign]->as<CompoundStmtNode>();
- fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
-
- const Format* format = inMsgNode->format;
-
- // clear the flags from the input message
- USHORT* impure_flags = request->getImpure<USHORT>(inMsgNode->impureFlags);
- memset(impure_flags, 0, sizeof(USHORT) * format->fmt_count);
-
- // clear the flags from the output message
- impure_flags = request->getImpure<USHORT>(outMsgNode->impureFlags);
- memset(impure_flags, 0, sizeof(USHORT) * outFormat->fmt_count);
-
- // validate input parameters
- for (size_t i = 0; i < list->statements.getCount(); ++i)
- {
- EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
- list->statements[i].getObject()));
- }
-
- UCHAR* inMsg = request->getImpure<UCHAR>(request->req_message->impureOffset);
-
- request->resultSet = statement->procedure->getExternal()->open(
- tdbb, inMsg, outMsg);
- }
-
- request->req_message = outMsgNode;
- bool result = request->resultSet->fetch(tdbb);
-
- // end flag
- const dsc& eofDesc = outFormat->fmt_desc[outFormat->fmt_count - 1];
- fb_assert(eofDesc.dsc_dtype == dtype_short);
- *((SSHORT*) (UCHAR*) (outMsg + (IPTR) eofDesc.dsc_address)) = (SSHORT) result;
-
- const CompoundStmtNode* list =
- extStmts->statements[e_extproc_output_assign]->as<CompoundStmtNode>();
- fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
-
- if (result)
- {
- // validate output parameters
- for (size_t i = 0; i < list->statements.getCount(); ++i)
- {
- EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
- list->statements[i].getObject()));
- }
- }
-
- break;
- }
-
- default:
- fb_assert(false);
- break;
- }
-
+ execute_ext_procedure(tdbb, request);
goto end;
}
if (request->req_operation == jrd_req::req_evaluate && (--tdbb->tdbb_quantum < 0))
- {
JRD_reschedule(tdbb, 0, true);
- }
if (request->req_operation == jrd_req::req_evaluate && node->hasLineColumn)
{
Modified: firebird/trunk/src/jrd/exe.h
===================================================================
--- firebird/trunk/src/jrd/exe.h 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/jrd/exe.h 2011-07-10 01:23:53 UTC (rev 53285)
@@ -130,8 +130,10 @@
// index (in CompoundStmtNode) for external procedure blr
const int e_extproc_input_message = 0;
const int e_extproc_output_message = 1;
-const int e_extproc_input_assign = 2;
-const int e_extproc_output_assign = 3;
+const int e_extproc_input_message2 = 2;
+const int e_extproc_output_message2 = 3;
+const int e_extproc_input_assign = 4;
+const int e_extproc_output_assign = 5;
// Request resources
Modified: firebird/trunk/src/jrd/met.epp
===================================================================
--- firebird/trunk/src/jrd/met.epp 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/jrd/met.epp 2011-07-10 01:23:53 UTC (rev 53285)
@@ -125,7 +125,8 @@
static ValueExprNode* parse_field_default_blr(thread_db* tdbb, bid* blob_id);
static void parse_field_validation_blr(thread_db* tdbb, bid* blob_id, const MetaName name,
BoolExprNode** expr, StmtNode** stmt);
-static void parse_procedure_blr(thread_db*, jrd_prc*, bid*, CompilerScratch*, bool);
+static void parse_procedure_blr(thread_db*, jrd_prc*, bid*, CompilerScratch*, bool,
+ const BlrMessage& extInBlr, const BlrMessage& extOutBlr);
static void par_messages(thread_db*, const UCHAR* const, USHORT, jrd_prc*, CompilerScratch*);
static bool resolve_charset_and_collation(thread_db*, USHORT*, const UCHAR*, const UCHAR*);
static void save_trigger_data(thread_db*, trig_vec**, jrd_rel*, JrdStatement*, blb*, bid*,
@@ -3000,6 +3001,38 @@
}
END_FOR
+ BlrMessage inBlr;
+ inBlr.blr = NULL;
+ inBlr.blrLength = 0;
+ inBlr.bufferLength = 0;
+
+ BlrMessage outBlr;
+ outBlr.blr = NULL;
+ outBlr.blrLength = 0;
+ outBlr.bufferLength = 0;
+
+ const bool external = !P.RDB$ENGINE_NAME.NULL; // ODS_12_0
+
+ if (external)
+ {
+ HalfStaticArray<char, 512> body;
+
+ if (!P.RDB$PROCEDURE_SOURCE.NULL)
+ {
+ blb* blob = BLB_open(tdbb, attachment->getSysTransaction(),
+ &P.RDB$PROCEDURE_SOURCE);
+ ULONG len = BLB_get_data(tdbb, blob,
+ (UCHAR*) body.getBuffer(blob->blb_length + 1), blob->blb_length + 1);
+ body.begin()[MIN(blob->blb_length, len)] = '\0';
+ }
+ else
+ body.getBuffer(1)[0] = '\0';
+
+ procedure->setExternal(dbb->dbb_extManager.makeProcedure(
+ tdbb, procedure, P.RDB$ENGINE_NAME,
+ (P.RDB$ENTRYPOINT.NULL ? "" : P.RDB$ENTRYPOINT), body.begin(), &inBlr, &outBlr));
+ }
+
Array<NestConst<Parameter> >& paramArray = procedure->prc_output_fields;
if (paramArray.hasData() && paramArray[0])
@@ -3029,7 +3062,6 @@
}
prc_t prc_type = prc_legacy;
- const bool external = !P.RDB$ENGINE_NAME.NULL; // ODS_12_0
MemoryPool* csb_pool = attachment->createPool();
@@ -3048,7 +3080,8 @@
try
{
parse_procedure_blr(tdbb, procedure,
- (P.RDB$PROCEDURE_BLR.NULL ? NULL : &P.RDB$PROCEDURE_BLR), csb, external);
+ (P.RDB$PROCEDURE_BLR.NULL ? NULL : &P.RDB$PROCEDURE_BLR), csb, external,
+ inBlr, outBlr);
}
catch (const Exception&)
{
@@ -3080,26 +3113,6 @@
delete csb;
} // scope
- if (external)
- {
- HalfStaticArray<char, 512> body;
-
- if (!P.RDB$PROCEDURE_SOURCE.NULL)
- {
- blb* blob = BLB_open(tdbb, attachment->getSysTransaction(),
- &P.RDB$PROCEDURE_SOURCE);
- ULONG len = BLB_get_data(tdbb, blob,
- (UCHAR*) body.getBuffer(blob->blb_length + 1), blob->blb_length + 1);
- body.begin()[MIN(blob->blb_length, len)] = '\0';
- }
- else
- body.getBuffer(1)[0] = '\0';
-
- procedure->setExternal(dbb->dbb_extManager.makeProcedure(
- tdbb, procedure, P.RDB$ENGINE_NAME,
- (P.RDB$ENTRYPOINT.NULL ? "" : P.RDB$ENTRYPOINT), body.begin()));
- }
-
if (P.RDB$VALID_BLR.NULL || P.RDB$VALID_BLR == FALSE)
valid_blr = false;
}
@@ -3135,11 +3148,19 @@
catch (const Exception&)
{
procedure->prc_flags &= ~(PRC_being_scanned | PRC_scanned);
+
+ if (procedure->getExternal())
+ {
+ delete procedure->getExternal();
+ procedure->setExternal(NULL);
+ }
+
if (procedure->prc_existence_lock)
{
LCK_release(tdbb, procedure->prc_existence_lock);
procedure->prc_existence_lock = NULL;
}
+
throw;
}
@@ -4371,20 +4392,128 @@
// Generate BLR message for external procedures
-static void gen_ext_message(UCharBuffer& blr, UCHAR message,
- const Array<NestConst<Parameter> >& parameters)
+static bool gen_ext_message(thread_db* tdbb, UCharBuffer& blr, UCHAR message, UCHAR message2,
+ const Array<NestConst<Parameter> >& parameters, const BlrMessage& extBlr,
+ UCharBuffer& appendBlr)
{
- size_t count = parameters.getCount();
- count = count * 2 + message;
+ size_t prevAppendBlrSize = appendBlr.getCount();
+ bool messageNeeded = false;
+ size_t count = 0;
+ size_t countPos = 0;
+ ULONG offset = 0;
+ UCHAR maxAlignment = 0;
+
+ dsc shortDesc;
+ shortDesc.makeShort(0);
+
+ if (extBlr.blr)
+ {
+ BlrReader reader(extBlr.blr, extBlr.blrLength);
+
+ reader.checkByte(blr_version5);
+ reader.checkByte(blr_begin);
+ reader.checkByte(blr_message);
+ reader.getByte(); // message number: ignore it
+ count = reader.checkWord(parameters.getCount() * 2);
+
+ appendBlr.add(blr_message);
+ appendBlr.add(message2);
+ countPos = appendBlr.getCount();
+ appendBlr.add(UCHAR(count)); // parameters (with nulls)
+ appendBlr.add(UCHAR(count >> 8));
+
+ for (unsigned i = 0; i < count / 2; ++i)
+ {
+ dsc desc;
+ PAR_datatype(tdbb, reader, &desc);
+ PreparedStatement::generateBlr(&desc, appendBlr);
+
+ if (desc.dsc_dtype >= dtype_aligned)
+ {
+ maxAlignment = MAX(maxAlignment, type_alignments[desc.dsc_dtype]);
+ offset = FB_ALIGN(offset, type_alignments[desc.dsc_dtype]);
+ }
+
+ offset += desc.dsc_length;
+
+ const dsc* prmDesc = ¶meters[i]->prm_desc;
+
+ if (desc.isText() && desc.getCharSet() == CS_NONE)
+ desc.setTextType(prmDesc->getTextType());
+ desc.setNullable(prmDesc->isNullable());
+
+ messageNeeded |= !DSC_EQUIV(&desc, prmDesc, false);
+
+ PAR_datatype(tdbb, reader, &desc);
+
+ if (!DSC_EQUIV(&desc, &shortDesc, false))
+ {
+ status_exception::raise(
+ Arg::Gds(isc_ee_blr_mismatch_null) <<
+ Arg::Num(i * 2 + 1));
+ }
+
+ PreparedStatement::generateBlr(&desc, appendBlr);
+
+ if (desc.dsc_dtype >= dtype_aligned)
+ {
+ maxAlignment = MAX(maxAlignment, type_alignments[desc.dsc_dtype]);
+ offset = FB_ALIGN(offset, type_alignments[desc.dsc_dtype]);
+ }
+
+ offset += desc.dsc_length;
+
+ messageNeeded |= !DSC_EQUIV(&desc, &shortDesc, false);
+ }
+
+ reader.checkByte(blr_end);
+ reader.checkByte(blr_eoc);
+
+ if (offset != extBlr.bufferLength)
+ {
+ status_exception::raise(
+ Arg::Gds(isc_ee_blr_mismatch_length) <<
+ Arg::Num(extBlr.bufferLength) <<
+ Arg::Num(offset));
+ }
+ }
+
+ if (messageNeeded)
+ {
+ // Pad the external message.
+ ULONG pad = FB_ALIGN(offset, maxAlignment) - offset;
+
+ if (pad != 0)
+ {
+ ++count;
+ appendBlr[countPos] = UCHAR(count);
+ appendBlr[countPos + 1] = UCHAR(count >> 8);
+
+ dsc desc;
+ desc.makeText(pad, 0);
+ PreparedStatement::generateBlr(&desc, appendBlr);
+ }
+ }
+ else
+ {
+ // The external and internal messages are compatible, so there is no need to create a new one.
+ appendBlr.shrink(prevAppendBlrSize);
+ appendBlr.add(blr_begin);
+ appendBlr.add(blr_end);
+ }
+
+ // Input message is 0 and output message is 1. Output message need the eof (+1) field.
+ count = parameters.getCount() * 2 + message;
fb_assert(count < MAX_USHORT);
blr.add(blr_message); // e_extproc_input_message, e_extproc_output_message
blr.add(message);
- blr.add(count); // parameters (with nulls)
- blr.add(count >> 8);
+ countPos = blr.getCount();
+ blr.add(UCHAR(count)); // parameters (with nulls)
+ blr.add(UCHAR(count >> 8));
- dsc shortDesc;
- shortDesc.makeShort(0);
+ offset = 0;
+ maxAlignment = 0;
for (const NestConst<Parameter>* i = parameters.begin(); i != parameters.end(); ++i)
{
@@ -4393,8 +4522,10 @@
if (!parameter->prm_nullable)
blr.add(blr_not_nullable);
+ const dsc* desc = ¶meter->prm_desc;
+
if (parameter->prm_mechanism == prm_mech_type_of)
- PreparedStatement::generateBlr(¶meter->prm_desc, blr);
+ PreparedStatement::generateBlr(desc, blr);
else
{
fb_assert(parameter->prm_mechanism == prm_mech_normal);
@@ -4422,16 +4553,43 @@
}
}
+ if (desc->dsc_dtype >= dtype_aligned)
+ {
+ maxAlignment = MAX(maxAlignment, type_alignments[desc->dsc_dtype]);
+ offset = FB_ALIGN(offset, type_alignments[desc->dsc_dtype]);
+ }
+
+ offset += desc->dsc_length;
+
PreparedStatement::generateBlr(&shortDesc, blr); // null flag
+
+ maxAlignment = MAX(maxAlignment, sizeof(SSHORT));
+ offset = FB_ALIGN(offset, sizeof(SSHORT)) + shortDesc.dsc_length;
}
+
+ if (!messageNeeded)
+ {
+ // This message will be used by external. Pad it if needed.
+ ULONG pad = FB_ALIGN(offset, maxAlignment) - offset;
+
+ if (pad != 0)
+ {
+ ++count;
+ blr[countPos] = UCHAR(count);
+ blr[countPos + 1] = UCHAR(count >> 8);
+
+ dsc desc;
+ desc.makeText(pad, 0);
+ PreparedStatement::generateBlr(&desc, blr);
+ }
+ }
+
+ return messageNeeded;
}
-static void parse_procedure_blr(thread_db* tdbb,
- jrd_prc* procedure,
- bid* blob_id,
- CompilerScratch* csb,
- bool external)
+static void parse_procedure_blr(thread_db* tdbb, jrd_prc* procedure, bid* blob_id,
+ CompilerScratch* csb, bool external, const BlrMessage& extInBlr, const BlrMessage& extOutBlr)
{
/**************************************
*
@@ -4453,28 +4611,52 @@
tmp.add(blr_version5);
tmp.add(blr_begin);
- // ASF: Generate input messages even when number of parameters is 0
- // because we'll use hardcoded message number (0 and 1) in execution.
- gen_ext_message(tmp, 0, procedure->prc_input_fields); // input message
- gen_ext_message(tmp, 1, procedure->prc_output_fields); // output message
+ // ASF: Generate nodes even when they could be avoided, because we will use hardoced
+ // message and statement numbers. See e_extproc_*.
+ UCharBuffer appendBlr;
+
+ bool genExtIn = gen_ext_message(tdbb, tmp, e_extproc_input_message, e_extproc_input_message2,
+ procedure->prc_input_fields, extInBlr, appendBlr);
+ bool genExtOut = gen_ext_message(tdbb, tmp, e_extproc_output_message, e_extproc_output_message2,
+ procedure->prc_output_fields, extOutBlr, appendBlr);
+
dsc shortDesc;
shortDesc.makeShort(0);
- PreparedStatement::generateBlr(&shortDesc, tmp); // end flag
+ PreparedStatement::generateBlr(&shortDesc, tmp); // end flag for the output message
+ tmp.join(appendBlr);
+
tmp.add(blr_begin); // e_extproc_input_assign
fb_assert(procedure->prc_input_fields.getCount() < MAX_USHORT / 2);
- for (USHORT i = 0; i < procedure->prc_input_fields.getCount(); ++i)
+ for (size_t i = 0; i < procedure->prc_input_fields.getCount(); ++i)
{
- tmp.add(blr_assignment);
- tmp.add(blr_parameter2);
- tmp.add(0); // input message
- tmp.add((i * 2));
- tmp.add((i * 2) >> 8);
- tmp.add((i * 2) + 1); // null indicator
- tmp.add(((i * 2) + 1) >> 8);
- tmp.add(blr_null);
+ const Parameter* parameter = procedure->prc_input_fields[i];
+
+ if (genExtIn || parameter->prm_mechanism != prm_mech_type_of || !parameter->prm_nullable)
+ {
+ tmp.add(blr_assignment);
+
+ tmp.add(blr_parameter2);
+ tmp.add(e_extproc_input_message);
+ tmp.add(UCHAR(i * 2));
+ tmp.add(UCHAR((i * 2) >> 8));
+ tmp.add(UCHAR((i * 2) + 1)); // null indicator
+ tmp.add(UCHAR(((i * 2) + 1) >> 8));
+
+ if (genExtIn)
+ {
+ tmp.add(blr_parameter2);
+ tmp.add(e_extproc_input_message2);
+ tmp.add(UCHAR(i * 2));
+ tmp.add(UCHAR((i * 2) >> 8));
+ tmp.add(UCHAR((i * 2) + 1)); // null indicator
+ tmp.add(UCHAR(((i * 2) + 1) >> 8));
+ }
+ else
+ tmp.add(blr_null);
+ }
}
tmp.add(blr_end);
@@ -4482,16 +4664,41 @@
tmp.add(blr_begin); // e_extproc_output_assign
fb_assert(procedure->prc_output_fields.getCount() < MAX_USHORT / 2);
- for (USHORT i = 0; i < procedure->prc_output_fields.getCount(); ++i)
+ for (size_t i = 0; i < procedure->prc_output_fields.getCount(); ++i)
{
- tmp.add(blr_assignment);
- tmp.add(blr_parameter2);
- tmp.add(1); // output message
- tmp.add((i * 2));
- tmp.add((i * 2) >> 8);
- tmp.add((i * 2) + 1); // null indicator
- tmp.add(((i * 2) + 1) >> 8);
- tmp.add(blr_null);
+ const Parameter* parameter = procedure->prc_output_fields[i];
+
+ if (genExtOut || parameter->prm_mechanism != prm_mech_type_of || !parameter->prm_nullable)
+ {
+ tmp.add(blr_assignment);
+
+ if (genExtOut)
+ {
+ tmp.add(blr_parameter2);
+ tmp.add(e_extproc_output_message2);
+ tmp.add(UCHAR(i * 2));
+ tmp.add(UCHAR((i * 2) >> 8));
+ tmp.add(UCHAR((i * 2) + 1)); // null indicator
+ tmp.add(UCHAR(((i * 2) + 1) >> 8));
+
+ tmp.add(blr_parameter2);
+ tmp.add(e_extproc_output_message);
+ tmp.add(UCHAR(i * 2));
+ tmp.add(UCHAR((i * 2) >> 8));
+ tmp.add(UCHAR((i * 2) + 1)); // null indicator
+ tmp.add(UCHAR(((i * 2) + 1) >> 8));
+ }
+ else
+ {
+ tmp.add(blr_parameter2);
+ tmp.add(e_extproc_output_message);
+ tmp.add(UCHAR(i * 2));
+ tmp.add(UCHAR((i * 2) >> 8));
+ tmp.add(UCHAR((i * 2) + 1)); // null indicator
+ tmp.add(UCHAR(((i * 2) + 1) >> 8));
+ tmp.add(blr_null);
+ }
+ }
}
tmp.add(blr_end);
Modified: firebird/trunk/src/jrd/par.cpp
===================================================================
--- firebird/trunk/src/jrd/par.cpp 2011-07-09 04:17:52 UTC (rev 53284)
+++ firebird/trunk/src/jrd/par.cpp 2011-07-10 01:23:53 UTC (rev 53285)
@@ -81,6 +81,7 @@
static NodeParseFunc blr_parsers[256] = {NULL};
+static void par_error(BlrReader& blrReader, const Arg::StatusVector& v, bool isSyntaxError = true);
static PlanNode* par_plan(thread_db*, CompilerScratch*);
@@ -328,143 +329,145 @@
}
-USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, DSC* desc, ItemInfo* itemInfo)
+// Parse a BLR datatype. Return the alignment requirements of the datatype.
+USHORT PAR_datatype(thread_db* tdbb, BlrReader& blrReader, dsc* desc)
{
-/**************************************
- *
- * P A R _ d e s c
- *
- **************************************
- *
- * Functional description
- * Parse a BLR descriptor. Return the alignment requirements
- * of the datatype.
- *
- **************************************/
- if (itemInfo)
- {
- itemInfo->nullable = true;
- itemInfo->explicitCollation = false;
- itemInfo->fullDomain = false;
- }
+ desc->clear();
- desc->dsc_scale = 0;
- desc->dsc_sub_type = 0;
- desc->dsc_address = NULL;
- desc->dsc_flags = 0;
-
- const USHORT dtype = csb->csb_blr_reader.getByte();
+ const USHORT dtype = blrReader.getByte();
USHORT textType;
switch (dtype)
{
- case blr_not_nullable:
- PAR_desc(tdbb, csb, desc, itemInfo);
- if (itemInfo)
- itemInfo->nullable = false;
- break;
+ case blr_text:
+ desc->makeText(blrReader.getWord(), ttype_dynamic);
+ desc->dsc_flags |= DSC_no_subtype;
+ break;
- case blr_text:
- desc->makeText(csb->csb_blr_reader.getWord(), ttype_dynamic);
- desc->dsc_flags |= DSC_no_subtype;
- break;
+ case blr_cstring:
+ desc->dsc_dtype = dtype_cstring;
+ desc->dsc_flags |= DSC_no_subtype;
+ desc->dsc_length = blrReader.getWord();
+ desc-...
[truncated message content] |