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] |