From: <asf...@us...> - 2011-06-01 01:45:03
|
Revision: 53068 http://firebird.svn.sourceforge.net/firebird/?rev=53068&view=rev Author: asfernandes Date: 2011-06-01 01:44:54 +0000 (Wed, 01 Jun 2011) Log Message: ----------- Work in progress on the external engines API changes. Modified Paths: -------------- firebird/trunk/builds/posix/Makefile.in.plugins_examples firebird/trunk/builds/win32/msvc10/engine.vcxproj firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters firebird/trunk/builds/win32/msvc8/engine.vcproj firebird/trunk/builds/win32/msvc9/engine.vcproj firebird/trunk/examples/udr/UdrCppExample.cpp firebird/trunk/src/common/dsc.cpp firebird/trunk/src/common/dsc.h firebird/trunk/src/dsql/dsql.cpp firebird/trunk/src/include/FirebirdApi.h firebird/trunk/src/include/FirebirdExternalApi.h firebird/trunk/src/include/FirebirdUdrCpp.h firebird/trunk/src/jrd/ExtEngineManager.cpp firebird/trunk/src/jrd/ExtEngineManager.h firebird/trunk/src/jrd/Function.epp firebird/trunk/src/jrd/cmp.cpp firebird/trunk/src/jrd/exe.cpp firebird/trunk/src/jrd/req.h firebird/trunk/src/plugins/udr_engine/UdrEngine.cpp firebird/trunk/src/yvalve/YObjects.h Removed Paths: ------------- firebird/trunk/src/jrd/ValueImpl.cpp firebird/trunk/src/jrd/ValueImpl.h firebird/trunk/src/jrd/ValuesImpl.cpp firebird/trunk/src/jrd/ValuesImpl.h Modified: firebird/trunk/builds/posix/Makefile.in.plugins_examples =================================================================== --- firebird/trunk/builds/posix/Makefile.in.plugins_examples 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/builds/posix/Makefile.in.plugins_examples 2011-06-01 01:44:54 UTC (rev 53068) @@ -59,10 +59,12 @@ $(PLUGINS)/udr/$(LIB_PREFIX)udrcpp_example.$(SHRLIB_EXT): $(UDR_Objects) ifeq ($(PLATFORM),DARWIN) - $(LIB_LINK) $(LIB_BUNDLE_OPTIONS) -o $@ $^ @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ + $(LIB_LINK) $(LIB_BUNDLE_OPTIONS) -o $@ $^ @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ \ + $(FIREBIRD_LIBRARY_LINK) else $(LIB_LINK) $(LIB_LINK_OPTIONS) $(LIB_LINK_SONAME)udrcpp_example.$(SHRLIB_EXT) \ -$(LIB_PATH_OPTS) -o $@ $^ $(THR_LIBS) $(PLUGINS)/$(LIB_PREFIX)udr_engine.$(SHRLIB_EXT) + $(LIB_PATH_OPTS) -o $@ $^ $(THR_LIBS) $(PLUGINS)/$(LIB_PREFIX)udr_engine.$(SHRLIB_EXT) \ + $(FIREBIRD_LIBRARY_LINK) endif include $(ROOT)/gen/make.shared.targets Modified: firebird/trunk/builds/win32/msvc10/engine.vcxproj =================================================================== --- firebird/trunk/builds/win32/msvc10/engine.vcxproj 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/builds/win32/msvc10/engine.vcxproj 2011-06-01 01:44:54 UTC (rev 53068) @@ -153,8 +153,6 @@ <ClCompile Include="..\..\..\src\jrd\trace\TraceService.cpp" /> <ClCompile Include="..\..\..\src\jrd\UserManagement.cpp" /> <ClCompile Include="..\..\..\src\jrd\validation.cpp" /> - <ClCompile Include="..\..\..\src\jrd\ValueImpl.cpp" /> - <ClCompile Include="..\..\..\src\jrd\ValuesImpl.cpp" /> <ClCompile Include="..\..\..\src\jrd\vio.cpp" /> <ClCompile Include="..\..\..\src\jrd\VirtualTable.cpp" /> <ClCompile Include="..\..\..\src\lock\lock.cpp" /> @@ -339,8 +337,6 @@ <ClInclude Include="..\..\..\src\jrd\types.h" /> <ClInclude Include="..\..\..\src\jrd\UserManagement.h" /> <ClInclude Include="..\..\..\src\jrd\val.h" /> - <ClInclude Include="..\..\..\src\jrd\ValueImpl.h" /> - <ClInclude Include="..\..\..\src\jrd\ValuesImpl.h" /> <ClInclude Include="..\..\..\src\jrd\val_proto.h" /> <ClInclude Include="..\..\..\src\jrd\vio_debug.h" /> <ClInclude Include="..\..\..\src\jrd\vio_proto.h" /> @@ -562,4 +558,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> Modified: firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters =================================================================== --- firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters 2011-06-01 01:44:54 UTC (rev 53068) @@ -384,12 +384,6 @@ <ClCompile Include="..\..\..\src\jrd\validation.cpp"> <Filter>JRD files</Filter> </ClCompile> - <ClCompile Include="..\..\..\src\jrd\ValueImpl.cpp"> - <Filter>JRD files</Filter> - </ClCompile> - <ClCompile Include="..\..\..\src\jrd\ValuesImpl.cpp"> - <Filter>JRD files</Filter> - </ClCompile> <ClCompile Include="..\..\..\src\jrd\vio.cpp"> <Filter>JRD files</Filter> </ClCompile> @@ -1001,12 +995,6 @@ <ClInclude Include="..\..\..\src\jrd\val_proto.h"> <Filter>Header files</Filter> </ClInclude> - <ClInclude Include="..\..\..\src\jrd\ValueImpl.h"> - <Filter>Header files</Filter> - </ClInclude> - <ClInclude Include="..\..\..\src\jrd\ValuesImpl.h"> - <Filter>Header files</Filter> - </ClInclude> <ClInclude Include="..\..\..\src\jrd\vio_debug.h"> <Filter>Header files</Filter> </ClInclude> @@ -1082,4 +1070,4 @@ <Filter>Resource files</Filter> </ResourceCompile> </ItemGroup> -</Project> \ No newline at end of file +</Project> Modified: firebird/trunk/builds/win32/msvc8/engine.vcproj =================================================================== --- firebird/trunk/builds/win32/msvc8/engine.vcproj 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/builds/win32/msvc8/engine.vcproj 2011-06-01 01:44:54 UTC (rev 53068) @@ -588,14 +588,6 @@ > </File> <File - RelativePath="..\..\..\src\jrd\ValueImpl.cpp" - > - </File> - <File - RelativePath="..\..\..\src\jrd\ValuesImpl.cpp" - > - </File> - <File RelativePath="..\..\..\src\jrd\vio.cpp" > </File> @@ -1668,14 +1660,6 @@ > </File> <File - RelativePath="..\..\..\src\jrd\ValueImpl.h" - > - </File> - <File - RelativePath="..\..\..\src\jrd\ValuesImpl.h" - > - </File> - <File RelativePath="..\..\..\src\jrd\vio_debug.h" > </File> Modified: firebird/trunk/builds/win32/msvc9/engine.vcproj =================================================================== --- firebird/trunk/builds/win32/msvc9/engine.vcproj 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/builds/win32/msvc9/engine.vcproj 2011-06-01 01:44:54 UTC (rev 53068) @@ -588,14 +588,6 @@ > </File> <File - RelativePath="..\..\..\src\jrd\ValueImpl.cpp" - > - </File> - <File - RelativePath="..\..\..\src\jrd\ValuesImpl.cpp" - > - </File> - <File RelativePath="..\..\..\src\jrd\vio.cpp" > </File> @@ -1668,14 +1660,6 @@ > </File> <File - RelativePath="..\..\..\src\jrd\ValueImpl.h" - > - </File> - <File - RelativePath="..\..\..\src\jrd\ValuesImpl.h" - > - </File> - <File RelativePath="..\..\..\src\jrd\vio_debug.h" > </File> Modified: firebird/trunk/examples/udr/UdrCppExample.cpp =================================================================== --- firebird/trunk/examples/udr/UdrCppExample.cpp 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/examples/udr/UdrCppExample.cpp 2011-06-01 01:44:54 UTC (rev 53068) @@ -30,28 +30,6 @@ using namespace Firebird::Udr; -typedef IMaster* (ISC_EXPORT *FuncGetMasterInterface)(); - -typedef ISC_LONG (ISC_EXPORT_VARARG *FuncEventBlock)(ISC_UCHAR**, ISC_UCHAR**, ISC_USHORT, ...); -typedef ISC_STATUS (ISC_EXPORT *FuncWaitForEvent)(ISC_STATUS*, isc_db_handle*, - short, const ISC_UCHAR*, ISC_UCHAR*); -typedef void (ISC_EXPORT *FuncEventCounts)(ISC_ULONG*, short, ISC_UCHAR*, const ISC_UCHAR*); - -typedef ISC_STATUS (ISC_EXPORT *FuncDsqlAllocateStatement)(ISC_STATUS*, isc_db_handle*, - isc_stmt_handle*); -typedef ISC_STATUS (ISC_EXPORT *FuncDsqlDescribe)(ISC_STATUS*, isc_stmt_handle*, unsigned short, - XSQLDA*); -typedef ISC_STATUS (ISC_EXPORT *FuncDsqlDescribeBind)(ISC_STATUS*, isc_stmt_handle*, unsigned short, - XSQLDA*); -typedef ISC_STATUS (ISC_EXPORT *FuncDsqlExecute)(ISC_STATUS*, isc_tr_handle*, isc_stmt_handle*, - unsigned short, XSQLDA*); -typedef ISC_STATUS (ISC_EXPORT *FuncDsqlExecute2)(ISC_STATUS*, isc_tr_handle*, isc_stmt_handle*, - unsigned short, XSQLDA*, XSQLDA*); -typedef ISC_STATUS (ISC_EXPORT *FuncDsqlFreeStatement)(ISC_STATUS*, isc_stmt_handle*, unsigned short); -typedef ISC_STATUS (ISC_EXPORT *FuncDsqlPrepare)(ISC_STATUS*, isc_tr_handle*, isc_stmt_handle*, - unsigned short, const ISC_SCHAR*, unsigned short, XSQLDA*); - - namespace { template <typename T> @@ -133,10 +111,461 @@ } +static IMaster* master = fb_get_master_interface(); + + +//------------------------------------------------------------------------------ + + +class MessageImpl; + +class ParamDescBase +{ +public: + ParamDescBase() + : pos(0), + nullPos(0) + { + } + + unsigned pos; + unsigned nullPos; +}; + +template <class T> +class ParamDesc : public ParamDescBase +{ +}; + +template <> +class ParamDesc<void*> : public ParamDescBase +{ +public: + ParamDesc(MessageImpl& message, const Firebird::IParametersMetadata* aParams); + + unsigned align(unsigned size, unsigned aIndex) + { + index = aIndex; + + AutoDispose<IStatus> status(master->getStatus()); + + switch ((type = params->getType(status, index))) + { + case SQL_SHORT: + size = FB_ALIGN(size, sizeof(ISC_SHORT)); + break; + + case SQL_LONG: + size = FB_ALIGN(size, sizeof(ISC_LONG)); + break; + + case SQL_INT64: + size = FB_ALIGN(size, sizeof(ISC_INT64)); + break; + + case SQL_FLOAT: + size = FB_ALIGN(size, sizeof(float)); + break; + + case SQL_DOUBLE: + size = FB_ALIGN(size, sizeof(double)); + break; + + case SQL_BLOB: + size = FB_ALIGN(size, sizeof(ISC_QUAD)); + break; + + case SQL_TEXT: + case SQL_VARYING: + size = FB_ALIGN(size, sizeof(ISC_USHORT)); + break; + + default: + assert(false); + break; + } + + return size; + } + + unsigned addBlr(ISC_UCHAR*& blr) + { + AutoDispose<IStatus> status(master->getStatus()); + unsigned ret; + + switch (type) + { + case SQL_SHORT: + { + unsigned scale = params->getScale(status, index); + *blr++ = blr_short; + *blr++ = scale; + ret = sizeof(ISC_SHORT); + break; + } + + case SQL_LONG: + { + unsigned scale = params->getScale(status, index); + *blr++ = blr_long; + *blr++ = scale; + ret = sizeof(ISC_LONG); + break; + } + + case SQL_INT64: + { + unsigned scale = params->getScale(status, index); + *blr++ = blr_int64; + *blr++ = scale; + ret = sizeof(ISC_INT64); + break; + } + + case SQL_FLOAT: + *blr++ = blr_float; + ret = sizeof(float); + break; + + case SQL_DOUBLE: + *blr++ = blr_double; + ret = sizeof(double); + break; + + case SQL_BLOB: + *blr++ = blr_blob2; + *blr++ = 0; + *blr++ = 0; + *blr++ = 0; + *blr++ = 0; + ret = sizeof(ISC_QUAD); + break; + + case SQL_TEXT: + case SQL_VARYING: + { + unsigned length = params->getLength(status, index); + *blr++ = blr_varying; + *blr++ = length & 0xFF; + *blr++ = (length >> 8) & 0xFF; + ret = sizeof(ISC_USHORT) + length; + break; + } + + default: + assert(false); + ret = 0; + break; + } + + return ret; + } + + unsigned getType() const + { + return type; + } + +private: + const Firebird::IParametersMetadata* params; + unsigned type; + unsigned index; +}; + +class MessageImpl : public Firebird::FbMessage +{ +public: + MessageImpl(unsigned aItemCount, ISC_UCHAR* aBuffer = NULL) + : itemCount(aItemCount * 2), + freeBuffer(!aBuffer), + items(0) + { + static const ISC_UCHAR HEADER[] = { + blr_version5, + blr_begin, + blr_message, 0, 0, 0 + }; + + blrLength = 0; + blr = blrPos = new ISC_UCHAR[sizeof(HEADER) + 10 * itemCount + 2]; + bufferLength = 0; + buffer = aBuffer; + + memcpy(blrPos, HEADER, sizeof(HEADER)); + blrPos += sizeof(HEADER); + } + + ~MessageImpl() + { + if (freeBuffer && buffer) + delete [] buffer; + + if (blr) + delete [] blr; + } + + template <typename T> + void add(ParamDesc<T>& paramDesc) + { + if (items >= itemCount) + return; // return an error, this is already constructed message + + bufferLength = paramDesc.align(bufferLength, items / 2); + paramDesc.pos = bufferLength; + bufferLength += paramDesc.addBlr(blrPos); + + bufferLength = FB_ALIGN(bufferLength, sizeof(ISC_SHORT)); + paramDesc.nullPos = bufferLength; + bufferLength += sizeof(ISC_SHORT); + + *blrPos++ = blr_short; + *blrPos++ = 0; + + items += 2; + + if (items == itemCount) + { + *blrPos++ = blr_end; + *blrPos++ = blr_eoc; + + blrLength = blrPos - blr; + + ISC_UCHAR* blrStart = blrPos - blrLength; + blrStart[4] = items & 0xFF; + blrStart[5] = (items >> 8) & 0xFF; + + if (!buffer) + { + buffer = new ISC_UCHAR[bufferLength]; + memset(buffer, 0, bufferLength); + } + } + } + + bool isNull(const ParamDescBase& index) + { + return *(ISC_SHORT*) (buffer + index.nullPos); + } + + void setNull(const ParamDescBase& index, bool null) + { + *(ISC_SHORT*) (buffer + index.nullPos) = (ISC_SHORT) null; + } + + template <typename T> T& operator [](const ParamDesc<T>& index) + { + return *(T*) (buffer + index.pos); + } + + void* operator [](const ParamDesc<void*>& index) + { + return buffer + index.pos; + } + +public: + unsigned itemCount; + bool freeBuffer; + unsigned items; + ISC_UCHAR* blrPos; +}; + +template <> +class ParamDesc<ISC_SHORT> : public ParamDescBase +{ +public: + ParamDesc(MessageImpl& message, ISC_UCHAR aScale = 0) + : scale(aScale) + { + message.add(*this); + } + + unsigned align(unsigned size, unsigned /*index*/) + { + return FB_ALIGN(size, sizeof(ISC_SHORT)); + } + + unsigned addBlr(ISC_UCHAR*& blr) + { + *blr++ = blr_short; + *blr++ = scale; + return sizeof(ISC_SHORT); + } + +private: + ISC_UCHAR scale; +}; + +template <> +class ParamDesc<ISC_LONG> : public ParamDescBase +{ +public: + ParamDesc(MessageImpl& message, ISC_UCHAR aScale = 0) + : scale(aScale) + { + message.add(*this); + } + + unsigned align(unsigned size, unsigned /*index*/) + { + return FB_ALIGN(size, sizeof(ISC_LONG)); + } + + unsigned addBlr(ISC_UCHAR*& blr) + { + *blr++ = blr_long; + *blr++ = scale; + return sizeof(ISC_LONG); + } + +private: + ISC_UCHAR scale; +}; + +template <> +class ParamDesc<ISC_INT64> : public ParamDescBase +{ +public: + ParamDesc(MessageImpl& message, ISC_UCHAR aScale = 0) + : scale(aScale) + { + message.add(*this); + } + + unsigned align(unsigned size, unsigned /*index*/) + { + return FB_ALIGN(size, sizeof(ISC_INT64)); + } + + unsigned addBlr(ISC_UCHAR*& blr) + { + *blr++ = blr_int64; + *blr++ = scale; + return sizeof(ISC_INT64); + } + +private: + ISC_UCHAR scale; +}; + +template <> +class ParamDesc<float> : public ParamDescBase +{ +public: + ParamDesc(MessageImpl& message) + { + message.add(*this); + } + + unsigned align(unsigned size, unsigned /*index*/) + { + return FB_ALIGN(size, sizeof(float)); + } + + unsigned addBlr(ISC_UCHAR*& blr) + { + *blr++ = blr_float; + return sizeof(float); + } +}; + +template <> +class ParamDesc<double> : public ParamDescBase +{ +public: + ParamDesc(MessageImpl& message) + { + message.add(*this); + } + + unsigned align(unsigned size, unsigned /*index*/) + { + return FB_ALIGN(size, sizeof(double)); + } + + unsigned addBlr(ISC_UCHAR*& blr) + { + *blr++ = blr_double; + return sizeof(double); + } +}; + +template <> +class ParamDesc<ISC_QUAD> : public ParamDescBase +{ +public: + ParamDesc(MessageImpl& message) + { + message.add(*this); + } + + unsigned align(unsigned size, unsigned /*index*/) + { + return FB_ALIGN(size, sizeof(ISC_QUAD)); + } + + unsigned addBlr(ISC_UCHAR*& blr) + { + *blr++ = blr_blob2; + *blr++ = 0; + *blr++ = 0; + *blr++ = 0; + *blr++ = 0; + return sizeof(ISC_QUAD); + } +}; + +struct FbString +{ + ISC_USHORT length; + char str[1]; +}; + +template <> +class ParamDesc<FbString> : public ParamDescBase +{ +public: + ParamDesc(MessageImpl& message, ISC_USHORT aLength) + : length(aLength) + { + message.add(*this); + } + + unsigned align(unsigned size, unsigned /*index*/) + { + return FB_ALIGN(size, sizeof(ISC_USHORT)); + } + + unsigned addBlr(ISC_UCHAR*& blr) + { + *blr++ = blr_varying; + *blr++ = length & 0xFF; + *blr++ = (length >> 8) & 0xFF; + return sizeof(ISC_USHORT) + length; + } + +private: + ISC_USHORT length; +}; + +//// TODO: boolean, date, time, timestamp + +//-------------------------------------- + +inline ParamDesc<void*>::ParamDesc(MessageImpl& message, const Firebird::IParametersMetadata* aParams) + : params(aParams), + type(0) +{ + message.add(*this); +} + + +//------------------------------------------------------------------------------ + + /*** create function wait_event ( - event_name varchar(31) character set ascii -) returns integer + event_name varchar(31) character set ascii not null +) returns integer not null external name 'udrcpp_example!wait_event' engine udr; ***/ @@ -211,91 +640,110 @@ ~FB_UDR_TRIGGER(replicate)(); private: - void initialize(ExternalContext* context, Values* values); + void initialize(ExternalContext* context); bool initialized; XSQLDA* inSqlDa; isc_stmt_handle stmtHandle; - - // ISC entry points - FuncGetMasterInterface funcGetMasterInterface; - FuncDsqlAllocateStatement funcDsqlAllocateStatement; - FuncDsqlDescribe funcDsqlDescribe; - FuncDsqlDescribeBind funcDsqlDescribeBind; - FuncDsqlExecute funcDsqlExecute; - FuncDsqlExecute2 funcDsqlExecute2; - FuncDsqlFreeStatement funcDsqlFreeStatement; - FuncDsqlPrepare funcDsqlPrepare; +#if 0 + IStatement* stmt; +#endif FB_UDR_END_DECLARE_TRIGGER(replicate) FB_UDR_BEGIN_FUNCTION(wait_event) { - // ISC entry points - FuncEventBlock funcEventBlock = (FuncEventBlock) getEntryPoint(context, "isc_event_block"); - FuncWaitForEvent funcWaitForEvent = (FuncWaitForEvent) getEntryPoint(context, "isc_wait_for_event"); - FuncEventCounts funcEventCounts = (FuncEventCounts) getEntryPoint(context, "isc_event_counts"); + MessageImpl inMessage(1, inMsg); + ParamDesc<FbString> nameDesc(inMessage, 31); - Value* val = params->getValue(ThrowError(), 1); + FbString& name = inMessage[nameDesc]; - const char* s = val->getString(ThrowError()); + char* s = new char[name.length + 1]; + memcpy(s, name.str, name.length); + s[name.length] = '\0'; unsigned char* eveBuffer; unsigned char* eveResult; - int eveLen = funcEventBlock(&eveBuffer, &eveResult, 1, s); + int eveLen = isc_event_block(&eveBuffer, &eveResult, 1, s); + delete [] s; + ISC_STATUS_ARRAY statusVector = {0}; isc_db_handle dbHandle = getIscDbHandle(context); ISC_ULONG counter = 0; - ThrowError::check(funcWaitForEvent(statusVector, &dbHandle, eveLen, eveBuffer, eveResult), + ThrowError::check(isc_wait_for_event(statusVector, &dbHandle, eveLen, eveBuffer, eveResult), statusVector); - funcEventCounts(&counter, eveLen, eveBuffer, eveResult); - ThrowError::check(funcWaitForEvent(statusVector, &dbHandle, eveLen, eveBuffer, eveResult), + isc_event_counts(&counter, eveLen, eveBuffer, eveResult); + ThrowError::check(isc_wait_for_event(statusVector, &dbHandle, eveLen, eveBuffer, eveResult), statusVector); - funcEventCounts(&counter, eveLen, eveBuffer, eveResult); + isc_event_counts(&counter, eveLen, eveBuffer, eveResult); isc_free((char*) eveBuffer); isc_free((char*) eveResult); - // returns the counter - result->setInt(ThrowError(), counter); + MessageImpl outMessage(1, outMsg); + ParamDesc<ISC_LONG> retDesc(outMessage); + + outMessage[retDesc] = counter; } FB_UDR_END_FUNCTION(wait_event) FB_UDR_BEGIN_FUNCTION(sum_args) { - unsigned count = params->getCount(); + AutoDispose<IStatus> status(master->getStatus()); + + const IParametersMetadata* params = metadata->getInputParameters(status); + ThrowError::check(status->get()); + + unsigned count = params->getCount(status); + ThrowError::check(status->get()); + + MessageImpl inMessage(count, inMsg); + + MessageImpl outMessage(1, outMsg); + ParamDesc<ISC_LONG> retDesc(outMessage); + int ret = 0; for (unsigned i = 0; i < count; ++i) { - Value* val = params->getValue(ThrowError(), i + 1); - ret += val->getInt(ThrowError()); + ParamDesc<ISC_LONG> numDesc(inMessage); + + if (inMessage.isNull(numDesc)) + { + outMessage.setNull(retDesc, true); + return; + } + else + ret += inMessage[numDesc]; } - result->setInt(ThrowError(), ret); + outMessage[retDesc] = ret; } FB_UDR_END_FUNCTION(sum_args) FB_UDR_BEGIN_PROCEDURE(gen_rows) { - Value* valStart = params->getValue(ThrowError(), 1); - Value* valEnd = params->getValue(ThrowError(), 2); + MessageImpl inMessage(2, inMsg); + ParamDesc<ISC_LONG> startDesc(inMessage); + ParamDesc<ISC_LONG> endDesc(inMessage); - counter = valStart->getInt(ThrowError()); - end = valEnd->getInt(ThrowError()); + counter = inMessage[startDesc]; + end = inMessage[endDesc]; } FB_UDR_FETCH_PROCEDURE(gen_rows) { if (counter > end) return false; - Value* ret = results->getValue(ThrowError(), 1); - ret->setInt(ThrowError(), counter++); + MessageImpl outMessage(1, outMsg); + ParamDesc<ISC_LONG> retDesc(outMessage); + outMessage[retDesc] = counter++; + return true; } FB_UDR_END_PROCEDURE(gen_rows) @@ -321,36 +769,24 @@ delete [] reinterpret_cast<char*>(inSqlDa); ISC_STATUS_ARRAY statusVector = {0}; - funcDsqlFreeStatement(statusVector, &stmtHandle, DSQL_drop); + isc_dsql_free_statement(statusVector, &stmtHandle, DSQL_drop); } -void FB_UDR_TRIGGER(replicate)::initialize(ExternalContext* context, Values* values) +void FB_UDR_TRIGGER(replicate)::initialize(ExternalContext* context) { if (initialized) return; - // ISC entry points - funcGetMasterInterface = (FuncGetMasterInterface) getEntryPoint(context, "fb_get_master_interface"); - funcDsqlAllocateStatement = (FuncDsqlAllocateStatement) - getEntryPoint(context, "isc_dsql_allocate_statement"); - funcDsqlDescribe = (FuncDsqlDescribe) getEntryPoint(context, "isc_dsql_describe"); - funcDsqlDescribeBind = (FuncDsqlDescribeBind) getEntryPoint(context, "isc_dsql_describe_bind"); - funcDsqlExecute = (FuncDsqlExecute) getEntryPoint(context, "isc_dsql_execute"); - funcDsqlExecute2 = (FuncDsqlExecute2) getEntryPoint(context, "isc_dsql_execute2"); - funcDsqlFreeStatement = (FuncDsqlFreeStatement) getEntryPoint(context, "isc_dsql_free_statement"); - funcDsqlPrepare = (FuncDsqlPrepare) getEntryPoint(context, "isc_dsql_prepare"); - ISC_STATUS_ARRAY statusVector = {0}; isc_db_handle dbHandle = getIscDbHandle(context); isc_tr_handle trHandle = getIscTrHandle(context); stmtHandle = 0; - ThrowError::check(funcDsqlAllocateStatement(statusVector, &dbHandle, &stmtHandle), statusVector); - ThrowError::check(funcDsqlPrepare(statusVector, &trHandle, &stmtHandle, 0, + ThrowError::check(isc_dsql_allocate_statement(statusVector, &dbHandle, &stmtHandle), statusVector); + ThrowError::check(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0, "select data_source from replicate_config where name = ?", SQL_DIALECT_CURRENT, NULL), statusVector); - IMaster* master(funcGetMasterInterface()); AutoDispose<IStatus> status(master->getStatus()); const char* table = metadata->getTriggerTable(status); @@ -372,7 +808,7 @@ inSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]); inSqlDa->version = SQLDA_VERSION1; inSqlDa->sqln = 1; - ThrowError::check(funcDsqlDescribeBind(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa), + ThrowError::check(isc_dsql_describe_bind(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa), statusVector); inSqlDa->sqlvar[0].sqldata = new char[sizeof(short) + inSqlDa->sqlvar[0].sqllen]; strncpy(inSqlDa->sqlvar[0].sqldata + sizeof(short), info, inSqlDa->sqlvar[0].sqllen); @@ -381,31 +817,35 @@ XSQLDA* outSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(1))]); outSqlDa->version = SQLDA_VERSION1; outSqlDa->sqln = 1; - ThrowError::check(funcDsqlDescribe(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, outSqlDa), + ThrowError::check(isc_dsql_describe(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, outSqlDa), statusVector); outSqlDa->sqlvar[0].sqldata = new char[sizeof(short) + outSqlDa->sqlvar[0].sqllen + 1]; outSqlDa->sqlvar[0].sqldata[sizeof(short) + outSqlDa->sqlvar[0].sqllen] = '\0'; - ThrowError::check(funcDsqlExecute2(statusVector, &trHandle, &stmtHandle, SQL_DIALECT_CURRENT, + ThrowError::check(isc_dsql_execute2(statusVector, &trHandle, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa, outSqlDa), statusVector); - ThrowError::check(funcDsqlFreeStatement(statusVector, &stmtHandle, DSQL_unprepare), statusVector); + ThrowError::check(isc_dsql_free_statement(statusVector, &stmtHandle, DSQL_unprepare), statusVector); delete [] inSqlDa->sqlvar[0].sqldata; delete [] reinterpret_cast<char*>(inSqlDa); inSqlDa = NULL; - int count = values->getCount(); + const IParametersMetadata* fields = metadata->getTriggerFields(status); + ThrowError::check(status->get()); + unsigned count = fields->getCount(status); + ThrowError::check(status->get()); + char buffer[65536]; strcpy(buffer, "execute block (\n"); - for (int i = 1; i <= count; ++i) + for (unsigned i = 0; i < count; ++i) { - if (i > 1) + if (i > 0) strcat(buffer, ",\n"); - Value* val = values->getValue(ThrowError(), i); - const char* name = val->getName(ThrowError()); + const char* name = fields->getField(status, i); + ThrowError::check(status->get()); strcat(buffer, " p"); sprintf(buffer + strlen(buffer), "%d type of column \"%s\".\"%s\" = ?", i, table, name); @@ -420,13 +860,13 @@ strcat(buffer, table); strcat(buffer, "\" ("); - for (int i = 1; i <= count; ++i) + for (unsigned i = 0; i < count; ++i) { - if (i > 1) + if (i > 0) strcat(buffer, ", "); - Value* val = values->getValue(ThrowError(), i); - const char* name = val->getName(ThrowError()); + const char* name = fields->getField(status, i); + ThrowError::check(status->get()); strcat(buffer, "\""); strcat(buffer, name); @@ -435,18 +875,18 @@ strcat(buffer, ") values ("); - for (int i = 1; i <= count; ++i) + for (unsigned i = 0; i < count; ++i) { - if (i > 1) + if (i > 0) strcat(buffer, ", "); strcat(buffer, "?"); } strcat(buffer, ")') ("); - for (int i = 1; i <= count; ++i) + for (unsigned i = 0; i < count; ++i) { - if (i > 1) + if (i > 0) strcat(buffer, ", "); strcat(buffer, ":p"); sprintf(buffer + strlen(buffer), "%d", i); @@ -456,27 +896,28 @@ strcat(buffer, outSqlDa->sqlvar[0].sqldata + sizeof(short)); strcat(buffer, "';\nend"); - ThrowError::check(funcDsqlPrepare(statusVector, &trHandle, &stmtHandle, 0, buffer, + ThrowError::check(isc_dsql_prepare(statusVector, &trHandle, &stmtHandle, 0, buffer, SQL_DIALECT_CURRENT, NULL), statusVector); inSqlDa = reinterpret_cast<XSQLDA*>(new char[(XSQLDA_LENGTH(count))]); inSqlDa->version = SQLDA_VERSION1; inSqlDa->sqln = count; - ThrowError::check(funcDsqlDescribeBind(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa), + ThrowError::check(isc_dsql_describe_bind(statusVector, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa), statusVector); - for (int i = 0; i < count; ++i) + for (unsigned i = 0; i < count; ++i) { XSQLVAR* var = &inSqlDa->sqlvar[i]; switch (var->sqltype & ~1) { case SQL_TEXT: - var->sqltype = SQL_VARYING | (var->sqltype & 1); - // fall into + var->sqldata = new char[var->sqllen]; + break; case SQL_VARYING: - var->sqldata = new char[sizeof(short) + var->sqllen]; + var->sqldata = new char[var->sqllen]; + var->sqllen += sizeof(short); break; case SQL_SHORT: @@ -493,6 +934,7 @@ case SQL_FLOAT: var->sqltype = SQL_DOUBLE | (var->sqltype & 1); + var->sqllen = sizeof(double); // fall into case SQL_DOUBLE: @@ -526,75 +968,38 @@ FB_UDR_BEGIN_TRIGGER(replicate) { - Values* values = newValues; + initialize(context); - initialize(context, values); + AutoDispose<IStatus> status(master->getStatus()); - int count = values->getCount(); + const IParametersMetadata* fields = metadata->getTriggerFields(status); + ThrowError::check(status->get()); + unsigned fieldsCount = fields->getCount(status); + ThrowError::check(status->get()); + + MessageImpl message(fieldsCount, newMsg); + ISC_STATUS_ARRAY statusVector = {0}; isc_db_handle dbHandle = getIscDbHandle(context); isc_tr_handle trHandle = getIscTrHandle(context); - for (int i = 1; i <= count; ++i) + for (unsigned i = 1; i <= fieldsCount; ++i) { + ParamDesc<void*> field(message, fields); + XSQLVAR* var = &inSqlDa->sqlvar[i - 1]; - Value* val = values->getValue(ThrowError(), i); - if (val->isNull()) - { + if (message.isNull(field)) *var->sqlind = -1; - continue; - } else + { *var->sqlind = 0; - - switch (var->sqltype & ~1) - { - case SQL_VARYING: - { - unsigned len; - const char* s = val->getString(ThrowError(), &len); - *reinterpret_cast<unsigned short*>(var->sqldata) = len; - memcpy(var->sqldata + sizeof(unsigned short), s, len); - break; - } - - case SQL_SHORT: - *reinterpret_cast<short*>(var->sqldata) = (short) val->getInt( - ThrowError(), var->sqlscale); - break; - - case SQL_LONG: - *reinterpret_cast<int32*>(var->sqldata) = val->getInt(ThrowError(), var->sqlscale); - break; - - case SQL_INT64: - *reinterpret_cast<int64*>(var->sqldata) = val->getBigInt(ThrowError(), var->sqlscale); - break; - - case SQL_DOUBLE: - *reinterpret_cast<double*>(var->sqldata) = val->getDouble(ThrowError()); - break; - - case SQL_BLOB: - { - int64 blobId = val->getBlobId(ThrowError()); - ISC_QUAD quad; - quad.gds_quad_low = ISC_ULONG(blobId); - quad.gds_quad_high = ISC_ULONG(blobId >> 32); - *reinterpret_cast<ISC_QUAD*>(var->sqldata) = quad; - break; - } - - //// TODO: SQL_TYPE_DATE, SQL_TIMESTAMP, SQL_TYPE_TIME - - default: - assert(false); + memcpy(var->sqldata, message[field], var->sqllen); } } - ThrowError::check(funcDsqlExecute(statusVector, &trHandle, &stmtHandle, SQL_DIALECT_CURRENT, + ThrowError::check(isc_dsql_execute(statusVector, &trHandle, &stmtHandle, SQL_DIALECT_CURRENT, inSqlDa), statusVector); } FB_UDR_END_TRIGGER(replicate) Modified: firebird/trunk/src/common/dsc.cpp =================================================================== --- firebird/trunk/src/common/dsc.cpp 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/src/common/dsc.cpp 2011-06-01 01:44:54 UTC (rev 53068) @@ -34,7 +34,9 @@ #include "../common/gdsassert.h" #include "../common/dsc_proto.h" +using namespace Firebird; + // When converting non-text values to text, how many bytes to allocate // for holding the text image of the value. @@ -1171,6 +1173,96 @@ } +void dsc::getSqlInfo(SLONG* sqlLength, SLONG* sqlSubType, SLONG* sqlScale, SLONG* sqlType) const +{ + *sqlLength = dsc_length; + *sqlSubType = 0; + *sqlScale = 0; + *sqlType = 0; + + switch (dsc_dtype) + { + case dtype_real: + *sqlType = SQL_FLOAT; + break; + + case dtype_array: + *sqlType = SQL_ARRAY; + break; + + case dtype_timestamp: + *sqlType = SQL_TIMESTAMP; + break; + + case dtype_sql_date: + *sqlType = SQL_TYPE_DATE; + break; + + case dtype_sql_time: + *sqlType = SQL_TYPE_TIME; + break; + + case dtype_double: + *sqlType = SQL_DOUBLE; + *sqlScale = dsc_scale; + break; + + case dtype_text: + *sqlType = SQL_TEXT; + *sqlSubType = dsc_sub_type; + break; + + case dtype_blob: + *sqlType = SQL_BLOB; + *sqlSubType = dsc_sub_type; + *sqlScale = dsc_scale; + break; + + case dtype_varying: + *sqlType = SQL_VARYING; + *sqlLength -= sizeof(USHORT); + *sqlSubType = dsc_sub_type; + break; + + case dtype_short: + case dtype_long: + case dtype_int64: + switch (dsc_dtype) + { + case dtype_short: + *sqlType = SQL_SHORT; + break; + + case dtype_long: + *sqlType = SQL_LONG; + break; + + default: + *sqlType = SQL_INT64; + } + + *sqlScale = dsc_scale; + if (dsc_sub_type) + *sqlSubType = dsc_sub_type; + break; + + case dtype_quad: + *sqlType = SQL_QUAD; + *sqlScale = dsc_scale; + break; + + case dtype_boolean: + *sqlType = SQL_BOOLEAN; + break; + + default: + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-804) << + Arg::Gds(isc_dsql_datatype_err)); + } +} + + #ifdef DEV_BUILD void dsc::address32bit() const { Modified: firebird/trunk/src/common/dsc.h =================================================================== --- firebird/trunk/src/common/dsc.h 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/src/common/dsc.h 2011-06-01 01:44:54 UTC (rev 53068) @@ -348,6 +348,7 @@ #endif const char* typeToText() const; + void getSqlInfo(SLONG* sqlLength, SLONG* sqlSubType, SLONG* sqlScale, SLONG* sqlType) const; #endif // __cpluplus } DSC; Modified: firebird/trunk/src/dsql/dsql.cpp =================================================================== --- firebird/trunk/src/dsql/dsql.cpp 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/src/dsql/dsql.cpp 2011-06-01 01:44:54 UTC (rev 53068) @@ -2621,95 +2621,21 @@ if (param->par_index >= first_index) { - SLONG sql_len = param->par_desc.dsc_length; - SLONG sql_sub_type = 0; - SLONG sql_scale = 0; - SLONG sql_type = 0; + SLONG sql_len, sql_sub_type, sql_scale, sql_type; + param->par_desc.getSqlInfo(&sql_len, &sql_sub_type, &sql_scale, &sql_type); - switch (param->par_desc.dsc_dtype) + if (input_message && param->par_desc.dsc_dtype == dtype_text && + (param->par_desc.dsc_flags & DSC_null)) { - case dtype_real: - sql_type = SQL_FLOAT; - break; - case dtype_array: - sql_type = SQL_ARRAY; - break; - - case dtype_timestamp: - sql_type = SQL_TIMESTAMP; - break; - case dtype_sql_date: - sql_type = SQL_TYPE_DATE; - break; - case dtype_sql_time: - sql_type = SQL_TYPE_TIME; - break; - - case dtype_double: - sql_type = SQL_DOUBLE; - sql_scale = param->par_desc.dsc_scale; - break; - - case dtype_text: - if (input_message && (param->par_desc.dsc_flags & DSC_null)) - { - sql_type = SQL_NULL; - sql_len = 0; - } - else - { - sql_type = SQL_TEXT; - sql_sub_type = param->par_desc.dsc_sub_type; - } - break; - - case dtype_blob: - sql_type = SQL_BLOB; - sql_sub_type = param->par_desc.dsc_sub_type; - sql_scale = param->par_desc.dsc_scale; - break; - - case dtype_varying: - sql_type = param->par_is_text ? SQL_TEXT : SQL_VARYING; - sql_len -= sizeof(USHORT); - sql_sub_type = param->par_desc.dsc_sub_type; - break; - - case dtype_short: - case dtype_long: - case dtype_int64: - switch (param->par_desc.dsc_dtype) - { - case dtype_short: - sql_type = SQL_SHORT; - break; - case dtype_long: - sql_type = SQL_LONG; - break; - default: - sql_type = SQL_INT64; - } - sql_scale = param->par_desc.dsc_scale; - if (param->par_desc.dsc_sub_type) - sql_sub_type = param->par_desc.dsc_sub_type; - break; - - case dtype_quad: - sql_type = SQL_QUAD; - sql_scale = param->par_desc.dsc_scale; - break; - - case dtype_boolean: - sql_type = SQL_BOOLEAN; - break; - - default: - ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) << - Arg::Gds(isc_dsql_datatype_err)); + sql_type = SQL_NULL; + sql_len = 0; + sql_sub_type = 0; } + else if (param->par_desc.dsc_dtype == dtype_varying && param->par_is_text) + sql_type = SQL_TEXT; if (sql_type && (param->par_desc.dsc_flags & DSC_nullable)) - sql_type++; + sql_type |= 0x1; for (const UCHAR* describe = items; describe < end_describe;) { Modified: firebird/trunk/src/include/FirebirdApi.h =================================================================== --- firebird/trunk/src/include/FirebirdApi.h 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/src/include/FirebirdApi.h 2011-06-01 01:44:54 UTC (rev 53068) @@ -61,30 +61,6 @@ #endif -struct Date -{ - int year; - int month; - int day; -}; - - -struct Time -{ - int hours; - int minutes; - int seconds; - int fractions; -}; - - -struct DateTime //// FIXME: rename to TimeStamp -{ - Date date; - Time time; -}; - - class Error { public: @@ -102,102 +78,6 @@ }; -// Represents a parameter or column. -class Value -{ -public: - // data types - enum Type - { - TYPE_SMALLINT = 1, - TYPE_INTEGER, - TYPE_BIGINT, - TYPE_DOUBLE, - TYPE_CHAR, - TYPE_VARCHAR, - TYPE_BLOB, - TYPE_DATE, - TYPE_TIME, - TYPE_TIMESTAMP - }; - -public: - // Get parameter or column name. - virtual const char* FB_CALL getName(Error* error) const = 0; - - virtual Type FB_CALL getType(Error* error) const = 0; - virtual const char* FB_CALL getCharSet(Error* error) const = 0; - - // Get BLOB sub-type. - virtual int FB_CALL getSubType(Error* error) const = 0; - - // Get numeric precision or maximum string length. - virtual int FB_CALL getPrecision(Error* error) const = 0; - - virtual int FB_CALL getScale(Error* error) const = 0; - virtual bool FB_CALL isNullable(Error* error) const = 0; - - virtual bool FB_CALL isNull() const = 0; - virtual void FB_CALL setNull(Error* error) = 0; - - virtual void FB_CALL copyFrom(Error* error, const Value* from) = 0; - - virtual int16 FB_CALL getSmallInt(Error* error, int scale = 0, bool* isNull = FB_NULL) const = 0; - virtual void FB_CALL setSmallInt(Error* error, int16 value, int scale = 0) = 0; - - virtual int32 FB_CALL getInt(Error* error, int scale = 0, bool* isNull = FB_NULL) const = 0; - virtual void FB_CALL setInt(Error* error, int32 value, int scale = 0) = 0; - - virtual int64 FB_CALL getBigInt(Error* error, int scale = 0, bool* isNull = FB_NULL) const = 0; - virtual void FB_CALL setBigInt(Error* error, int64 value, int scale = 0) = 0; - - virtual double FB_CALL getDouble(Error* error, bool* isNull = FB_NULL) const = 0; - virtual void FB_CALL setDouble(Error* error, double value) = 0; - - virtual const char* FB_CALL getString(Error* error, uint* strLength = FB_NULL, - bool* isNull = FB_NULL) const = 0; - virtual void FB_CALL setString(Error* error, const char* str, uint strLength) = 0; - - virtual int64 FB_CALL getBlobId(Error* error, bool* isNull = FB_NULL) const = 0; - virtual void FB_CALL setBlobId(Error* error, int64 value) = 0; - - virtual void FB_CALL getDate(Error* error, Date* value, bool* isNull = FB_NULL) const = 0; - virtual void FB_CALL setDate(Error* error, const Date* value) = 0; - - virtual void FB_CALL getTime(Error* error, Time* value, bool* isNull = FB_NULL) const = 0; - virtual void FB_CALL setTime(Error* error, const Time* value) = 0; - - virtual void FB_CALL getTimeStamp(Error* error, DateTime* value, bool* isNull = FB_NULL) const = 0; - virtual void FB_CALL setTimeStamp(Error* error, const DateTime* value) = 0; -}; - - -// A queue associated with a Values. Could be used for batching processing. -class ValuesQueue : public Disposable -{ -public: - virtual void FB_CALL enqueue(Error* error) = 0; // Enqueue the current Values. - virtual bool FB_CALL dequeue(Error* error) = 0; // Dequeue in Values. -}; - - -// Represents a group of parameters or columns. -class Values -{ -public: - virtual uint FB_CALL getCount() const = 0; - virtual uint FB_CALL getIndexByName(Error* error, const char* name) const = 0; - - // Get a given value. The first value is at index 1. - virtual Value* FB_CALL getValue(Error* error, uint index) const = 0; - - virtual Value* FB_CALL getValueByName(Error* error, const char* name) const = 0; - - // Creates a queue associated with this Values. - virtual ValuesQueue* FB_CALL createQueue(Error* error) = 0; -}; - - } // namespace Firebird Modified: firebird/trunk/src/include/FirebirdExternalApi.h =================================================================== --- firebird/trunk/src/include/FirebirdExternalApi.h 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/src/include/FirebirdExternalApi.h 2011-06-01 01:44:54 UTC (rev 53068) @@ -95,8 +95,8 @@ virtual void FB_CALL getCharSet(Error* error, ExternalContext* context, Utf8* name, uint nameSize) = 0; - virtual void FB_CALL execute(Error* error, ExternalContext* context, Values* params, - Value* result) = 0; + virtual void FB_CALL execute(Error* error, ExternalContext* context, + UCHAR* inMsg, UCHAR* outMsg) = 0; }; @@ -113,7 +113,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, - Values* params, Values* results) = 0; + UCHAR* inMsg, UCHAR* outMsg) = 0; }; @@ -148,7 +148,7 @@ Utf8* name, uint nameSize) = 0; virtual void FB_CALL execute(Error* error, ExternalContext* context, - Action action, const Values* oldValues, Values* newValues) = 0; + Action action, UCHAR* oldMsg, UCHAR* newMsg) = 0; }; @@ -159,10 +159,13 @@ virtual const char* FB_CARG getName(IStatus* status) const = 0; virtual const char* FB_CARG getEntryPoint(IStatus* status) const = 0; virtual const char* FB_CARG getBody(IStatus* status) const = 0; + virtual const IParametersMetadata* FB_CARG getInputParameters(IStatus* status) const = 0; + virtual const IParametersMetadata* FB_CARG getOutputParameters(IStatus* status) const = 0; + virtual const IParametersMetadata* FB_CARG getTriggerFields(IStatus* status) const = 0; virtual const char* FB_CARG getTriggerTable(IStatus* status) const = 0; virtual ExternalTrigger::Type FB_CARG getTriggerType(IStatus* status) const = 0; }; -#define FB_ROUTINE_METADATA_VERSION (FB_VERSIONED_VERSION + 6) +#define FB_ROUTINE_METADATA_VERSION (FB_VERSIONED_VERSION + 9) // In SuperServer, shared by all attachments to one database and disposed when last (non-external) Modified: firebird/trunk/src/include/FirebirdUdrCpp.h =================================================================== --- firebird/trunk/src/include/FirebirdUdrCpp.h 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/src/include/FirebirdUdrCpp.h 2011-06-01 01:44:54 UTC (rev 53068) @@ -50,7 +50,7 @@ { \ public: \ virtual void FB_CALL execute(::Firebird::Error* error, ::Firebird::ExternalContext* context, \ - ::Firebird::Values* params, ::Firebird::Value* result); \ + UCHAR* inMsg, UCHAR* outMsg); \ private: #define FB_UDR_END_DECLARE_FUNCTION(name) \ @@ -62,7 +62,7 @@ #define FB_UDR_BEGIN_FUNCTION(name) \ void FB_CALL FB_UDR_FUNCTION(name)::execute(::Firebird::Error* error, \ - ::Firebird::ExternalContext* context, ::Firebird::Values* params, ::Firebird::Value* result) \ + ::Firebird::ExternalContext* context, UCHAR* inMsg, UCHAR* outMsg) \ { \ try \ { @@ -90,8 +90,7 @@ { \ public: \ virtual ::Firebird::ExternalResultSet* FB_CALL open(::Firebird::Error* error, \ - ::Firebird::ExternalContext* context, ::Firebird::Values* params, \ - ::Firebird::Values* results); \ + ::Firebird::ExternalContext* context, UCHAR* inMsg, UCHAR* outMsg); \ #define FB_UDR_END_DECLARE_PROCEDURE(name) \ }; @@ -104,8 +103,8 @@ class ResultSet##name : public ::Firebird::Udr::ResultSet \ { \ public: \ - ResultSet##name(::Firebird::Error* error, ::Firebird::ExternalContext* context, \ - ::Firebird::Values* params, ::Firebird::Values* results); \ + ResultSet##name(::Firebird::Error* error, ::Firebird::ExternalContext* context, \ + ::Firebird::Udr::Procedure* procedure, UCHAR* inMsg, UCHAR* outMsg); \ \ public: \ virtual bool FB_CALL fetch(::Firebird::Error* error); \ @@ -125,15 +124,14 @@ #define FB_UDR_BEGIN_PROCEDURE(name) \ ::Firebird::ExternalResultSet* FB_CALL Proc##name::open(::Firebird::Error* error, \ - ::Firebird::ExternalContext* context, ::Firebird::Values* params, \ - ::Firebird::Values* results) \ + ::Firebird::ExternalContext* context, UCHAR* inMsg, UCHAR* outMsg) \ { \ - return new ResultSet##name(error, context, params, results); \ + return new ResultSet##name(error, context, this, inMsg, outMsg); \ } \ \ ResultSet##name::ResultSet##name(::Firebird::Error* error, ::Firebird::ExternalContext* context, \ - ::Firebird::Values* params, ::Firebird::Values* results) \ - : ResultSet(context, params, results) \ + ::Firebird::Udr::Procedure* procedure, UCHAR* inMsg, UCHAR* outMsg) \ + : ResultSet(context, procedure, inMsg, outMsg) \ { \ try \ { @@ -183,8 +181,7 @@ { \ public: \ virtual void FB_CALL execute(::Firebird::Error* error, ::Firebird::ExternalContext* context, \ - ::Firebird::ExternalTrigger::Action action, const ::Firebird::Values* oldValues, \ - ::Firebird::Values* newValues); \ + ::Firebird::ExternalTrigger::Action action, UCHAR* oldMsg, UCHAR* newMsg); \ private: #define FB_UDR_END_DECLARE_TRIGGER(name) \ @@ -197,7 +194,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, \ - const ::Firebird::Values* oldValues, ::Firebird::Values* newValues) \ + UCHAR* oldMsg, UCHAR* newMsg) \ { \ try \ { @@ -429,6 +426,9 @@ }; +class Procedure; + + class Helper { public: @@ -460,11 +460,12 @@ class ResultSet : public ExternalResultSet, public Helper { public: - ResultSet(Firebird::ExternalContext* aContext, Firebird::Values* aParams, - Firebird::Values* aResults) + ResultSet(Firebird::ExternalContext* aContext, Firebird::Udr::Procedure* aProcedure, + UCHAR* aInMsg, UCHAR* aOutMsg) : context(aContext), - params(aParams), - results(aResults) + procedure(aProcedure), + inMsg(aInMsg), + outMsg(aOutMsg) { } @@ -480,8 +481,9 @@ protected: Firebird::ExternalContext* context; - Firebird::Values* params; - Firebird::Values* results; + Firebird::Udr::Procedure* procedure; + UCHAR* inMsg; + UCHAR* outMsg; }; Modified: firebird/trunk/src/jrd/ExtEngineManager.cpp =================================================================== --- firebird/trunk/src/jrd/ExtEngineManager.cpp 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/src/jrd/ExtEngineManager.cpp 2011-06-01 01:44:54 UTC (rev 53068) @@ -26,10 +26,9 @@ #include "inf_pub.h" #include "../jrd/ExtEngineManager.h" #include "../jrd/ErrorImpl.h" -#include "../jrd/ValueImpl.h" -#include "../jrd/ValuesImpl.h" #include "../dsql/sqlda_pub.h" #include "../common/dsc.h" +#include "../jrd/align.h" #include "../jrd/jrd.h" #include "../jrd/exe.h" #include "../jrd/req.h" @@ -305,8 +304,7 @@ } -void ExtEngineManager::Function::execute(thread_db* tdbb, const NestValueArray& args, - impure_value* impure) const +void ExtEngineManager::Function::execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg) const { EngineAttachmentInfo* attInfo = extManager->getEngineAttachment(tdbb, engine); ContextManager<ExternalFunction> ctxManager(tdbb, attInfo, function, @@ -314,70 +312,9 @@ CallerName(obj_udf, udf->getName().identifier) : CallerName(obj_package_header, udf->getName().package))); - impure->vlu_desc.dsc_flags = DSC_null; - MemoryPool& pool = *tdbb->getDefaultPool(); - ValueImpl result(pool, &impure->vlu_desc, "", true); + Attachment::Checkout attCout(tdbb->getAttachment()); - HalfStaticArray<impure_value, 32> impureArgs; - - jrd_req* request = tdbb->getRequest(); - impure_value* impureArgsPtr = impureArgs.getBuffer(args.getCount()); - - try - { - ValuesImpl params(pool, args.getCount()); - - for (size_t i = 0; i < args.getCount(); ++i) - { - impureArgsPtr->vlu_desc = udf->fun_args[i + 1].fun_parameter->prm_desc; - - if (impureArgsPtr->vlu_desc.isText()) - { - impureArgsPtr->vlu_string = - FB_NEW_RPT(pool, impureArgsPtr->vlu_desc.getStringLength()) VaryingString(); - impureArgsPtr->vlu_desc.dsc_address = (UCHAR*) impureArgsPtr->vlu_string; - } - else - { - impureArgsPtr->vlu_string = NULL; - impureArgsPtr->vlu_desc.dsc_address = (UCHAR*) &impureArgsPtr->vlu_misc; - } - - dsc* arg = EVL_expr(tdbb, request, args[i]); - - if (request->req_flags & req_null) - impureArgsPtr->vlu_desc.dsc_flags = DSC_null; - else - { - MOV_move(tdbb, arg, &impureArgsPtr->vlu_desc); - INTL_adjust_text_descriptor(tdbb, &impureArgsPtr->vlu_desc); - } - - params.getValue(i + 1)->make(&impureArgsPtr->vlu_desc, "", true); - - ++impureArgsPtr; - } - - { // scope - Attachment::Checkout attCout(tdbb->getAttachment()); - function->execute(RaiseError(), attInfo->context, ¶ms, &result); - } - } - catch (...) - { - for (size_t i = 0; i < args.getCount(); ++i) - delete impureArgs[i].vlu_string; - - throw; - } - - for (size_t i = 0; i < args.getCount(); ++i) - delete impureArgs[i].vlu_string; - - if (result.isNull()) - request->req_flags |= req_null; - else - request->req_flags &= ~req_null; + function->execute(RaiseError(), attInfo->context, inMsg, outMsg); } @@ -405,17 +342,17 @@ ExtEngineManager::ResultSet* ExtEngineManager::Procedure::open(thread_db* tdbb, - ValuesImpl* inputParams, ValuesImpl* outputParams) const + UCHAR* inMsg, UCHAR* outMsg) const { - return FB_NEW(*tdbb->getDefaultPool()) ResultSet(tdbb, inputParams, outputParams, this); + return FB_NEW(*tdbb->getDefaultPool()) ResultSet(tdbb, inMsg, outMsg, this); } //--------------------- -ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, ValuesImpl* inputParams, - ValuesImpl* outputParams, const ExtEngineManager::Procedure* aProcedure) +ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg, + const ExtEngineManager::Procedure* aProcedure) : procedure(aProcedure), attachment(tdbb->getAttachment()), firstFetch(true) @@ -430,8 +367,7 @@ Attachment::Checkout attCout(attachment); - resultSet = procedure->procedure->open(RaiseError(), attInfo->context, inputParams, - outputParams); + resultSet = procedure->procedure->open(RaiseError(), attInfo->context, inMsg, outMsg); } @@ -494,82 +430,95 @@ ContextManager<ExternalTrigger> ctxManager(tdbb, attInfo, trigger, CallerName(obj_trigger, trg->name)); - Array<dsc*> descs; - try + // ASF: Using Array instead of HalfStaticArray to not need to do alignment hacks here. + Array<UCHAR> oldMsg; + Array<UCHAR> newMsg; + + if (oldRpb) + setValues(tdbb, oldMsg, oldRpb); + + if (newRpb) + setValues(tdbb, newMsg, newRpb); + + Attachment::Checkout attCout(tdbb->getAttachment()); + + trigger->execute(RaiseError(), attInfo->context, action, + (oldRpb ? oldMsg.begin() : NULL), (newRpb ? newMsg.begin() : NULL)); + + if (newRpb) { - MemoryPool& pool = *tdbb->getDefaultPool(); - AutoPtr<ValuesImpl> oldValues, newValues; - int valueOldCount = 0; - int valueNewCount = 0; + Record* record = newRpb->rpb_record; + const Format* format = record->rec_format; + const UCHAR* msg = newMsg.begin(); + unsigned pos = 0; - if (oldRpb) - valueOldCount = setValues(tdbb, pool, oldValues, descs, oldRpb); + for (unsigned i = 0; i < format->fmt_count; ++i) + { + if (format->fmt_desc[i].dsc_dtype == dtype_unknown) + continue; - if (newRpb) - valueNewCount = setValues(tdbb, pool, newValues, descs, newRpb); + dsc desc; + bool readonly = !EVL_field(newRpb->rpb_relation, record, i, &desc) && + desc.dsc_address && !(desc.dsc_flags & DSC_null); - { // scope - Attachment::Checkout attCout(tdbb->getAttachment()); + unsigned align = type_alignments[desc.dsc_dtype]; + if (align) + pos = FB_ALIGN(pos, align); - trigger->execute(RaiseError(), attInfo->context, action, oldValues, newValues); + unsigned dataPos = pos; + pos += desc.dsc_length; - for (int i = 1; i <= valueNewCount; ++i) + align = type_alignments[dtype_short]; + if (align) + pos = FB_ALIGN(pos, align); + + if (!readonly) { - ValueImpl* val = newValues->getValue(i); - - if (val->isNull()) - SET_NULL(newRpb->rpb_record, val->getFieldNumber()); + if (*(USHORT*) &msg[pos]) + SET_NULL(record, i); else - CLEAR_NULL(newRpb->rpb_record, val->getFieldNumber()); + { + memcpy(desc.dsc_address, msg + dataPos, desc.dsc_length); + CLEAR_NULL(record, i); + } } + + pos += sizeof(USHORT); } } - catch (...) - { - for (size_t i = 0; i < descs.getCount(); ++i) - delete descs[i]; - throw; - } - - for (size_t i = 0; i < descs.getCount(); ++i) - delete descs[i]; } -int ExtEngineManager::Trigger::setValues(thread_db* /*tdbb*/, MemoryPool& pool, - AutoPtr<ValuesImpl>& values, Array<dsc*>& descs, +void ExtEngineManager::Trigger::setValues(thread_db* /*tdbb*/, Array<UCHAR>& msgBuffer, record_param* rpb) const { if (!rpb || !rpb->rpb_record) - return 0; + return; Record* record = rpb->rpb_record; const Format* format = record->rec_format; - values = FB_NEW(pool) ValuesImpl(pool, format->fmt_count); + for (unsigned i = 0; i < format->fmt_count; ++i) + { + if (format->fmt_desc[i].dsc_dtype == dtype_unknown) + continue; - int start = descs.getCount(); - descs.resize(start + format->fmt_count); + dsc desc; + EVL_field(rpb->rpb_relation, record, i, &desc); - int j = 0; + unsigned align = type_alignments[desc.dsc_dtype]; + if (align) + msgBuffer.resize(FB_ALIGN(msgBuffer.getCount(), align)); - for (int i = 0; i < format->fmt_count; ++i) - { - descs[start + i] = FB_NEW(pool) dsc; + msgBuffer.add(desc.dsc_address, desc.dsc_length); - if (format->fmt_desc[i].dsc_dtype != dtype_unknown) - { - EVL_field(rpb->rpb_relation, record, i, descs[start + i]); + align = type_alignments[dtype_short]; + if (align) + msgBuffer.resize(FB_ALIGN(msgBuffer.getCount(), align)); - jrd_fld* field = (*rpb->rpb_relation->rel_fields)[i]; - fb_assert(field); - - values->getValue(j + 1)->make(descs[start + i], field->fld_name, true, i); - ++j; - } + USHORT nullFlag = (desc.dsc_flags & DSC_null) != 0; + msgBuffer.add((UCHAR*) &nullFlag, sizeof(nullFlag)); } - - return j; } @@ -654,13 +603,36 @@ CallerName(obj_udf, udf->getName().identifier) : CallerName(obj_package_header, udf->getName().package))); - MemoryPool& pool = *tdbb->getDefaultPool(); + ///MemoryPool& pool = *tdbb->getDefaultPool(); + MemoryPool& pool = *getDefaultMemoryPool(); + AutoPtr<RoutineMetadata> metadata(FB_NEW(pool) RoutineMetadata(pool)); metadata->package = udf->getName().package; metadata->name = udf->getName().identifier; metadata->entryPoint = entryPointTrimmed; metadata->body = body; + metadata->inputParameters = FB_NEW(pool) StatementMetadata::Parameters(pool); + metadata->outputParameters = FB_NEW(pool) StatementMetadata::Parameters(pool); + for (Array<Jrd::Function::Argument>::const_iterator i = udf->fun_args.begin(); + i != udf->fun_args.end(); + ++i) + { + SLONG sqlLen, sqlSubType, sqlScale, sqlType; + i->fun_parameter->prm_desc.getSqlInfo(&sqlLen, &sqlSubType, &sqlScale, &sqlType); + + StatementMetadata::Parameters::Item& item = i == udf->fun_args.begin() ? + metadata->outputParameters->items.add() : + metadata->inputParameters->items.add(); + + item.field = i->fun_parameter->prm_name.c_str(); + item.type = sqlType; + item.subType = sqlSubType; + item.length = sqlLen; + item.scale = sqlScale; + item.nullable = i->fun_parameter->prm_nullable; + } + ExternalFunction* externalFunction; { // scope @@ -702,13 +674,41 @@ CallerName(obj_procedure, prc->getName().identifier) : CallerName(obj_package_header, prc->getName().package))); - MemoryPool& pool = *tdbb->getDefaultPool(); + ///MemoryPool& pool = *tdbb->getDefaultPool(); + MemoryPool& pool = *getDefaultMemoryPool(); + AutoPtr<RoutineMetadata> metadata(FB_NEW(pool) RoutineMetadata(pool)); metadata->package = prc->getName().package; metadata->name = prc->getName().identifier; metadata->entryPoint = entryPointTrimmed; metadata->body = body; + metadata->inputParameters = FB_NEW(pool) StatementMetadata::Parameters(pool); + metadata->outputParameters = FB_NEW(pool) StatementMetadata::Parameters(pool); + const Array<NestConst<Parameter> >* parameters[] = {&prc->prc_input_fields, &prc->prc_output_fields}; + + for (unsigned i = 0; i < 2; ++i) + { + for (Array<NestConst<Parameter> >::const_iterator j = parameters[i]->begin(); + j != parameters[i]->end(); + ++j) + { + SLONG sqlLen, sqlSubType, sqlScale, sqlType; + (*j)->prm_desc.getSqlInfo(&sqlLen, &sqlSubType, &sqlScale, &sqlType); + + StatementMetadata::Parameters::Item& item = i == 1 ? + metadata->outputParameters->items.add() : + metadata->inputParameters->items.add(); + + item.field = (*j)->prm_name.c_str(); + item.type = sqlType; + item.subType = sqlSubType; + item.length = sqlLen; + item.scale = sqlScale; + item.nullable = (*j)->prm_nullable; + } + } + ExternalProcedure* externalProcedure; { // scope @@ -748,7 +748,9 @@ ContextManager<ExternalTrigger> ctxManager(tdbb, attInfo, attInfo->adminCharSet, CallerName(obj_trigger, trg->name)); - MemoryPool& pool = *tdbb->getDefaultPool(); + ///MemoryPool& pool = *tdbb->getDefaultPool(); + MemoryPool& pool = *getDefaultMemoryPool(); + AutoPtr<RoutineMetadata> metadata(FB_NEW(pool) RoutineMetadata(pool)); metadata->name = trg->name; metadata->entryPoint = entryPointTrimmed; @@ -756,7 +758,29 @@ metadata->triggerType = type; if (trg->relation) metadata->triggerTable = trg->relation->rel_name; + metadata->triggerFields = FB_NEW(pool) StatementMetadata::Parameters(pool); + jrd_rel* relation = trg->relation; + Format* relFormat = relation->rel_current_format; + + for (size_t i = 0; i < relation->rel_fields->count(); ++i) + { + jrd_fld* field = (*relation->rel_fields)[i]; + if (!field) + continue; + + SLONG sqlLen, sqlSubType, sqlScale, sqlType; + relFormat->fmt_desc[i].getSqlInfo(&sqlLen, &sqlSubType, &sqlScale, &sqlType); + + StatementMetadata::Parameters::Item& item = metadata->triggerFields->items.add(); + item.field = field->fld_name.c_str(); + item.type = sqlType; + item.subType = sqlSubType; + item.length = sqlLen; + item.scale = sqlScale; + item.nullable = !field->fld_not_null; + } + ExternalTrigger* externalTrigger; { // scope Modified: firebird/trunk/src/jrd/ExtEngineManager.h =================================================================== --- firebird/trunk/src/jrd/ExtEngineManager.h 2011-05-31 16:19:47 UTC (rev 53067) +++ firebird/trunk/src/jrd/ExtEngineManager.h 2011-06-01 01:44:54 UTC (rev 53068) @@ -34,7 +34,7 @@ #include "../common/classes/auto.h" #include "../common/classes/rwlock.h" #include "../common/classes/ImplementHelper.h" -///#include "../dsql/Nodes.h" +#include "../common/StatementMetadata.h" struct dsc; @@ -49,8 +49,6 @@ class Trigger; class Function; class ValueExprNode; -class ValueImpl; -class ValuesImpl; struct impure_value; struct record_param; @@ -97,6 +95,24 @@ return body.c_str(); } + virtual const Firebird::IParametersMetadata* FB_CARG getInputParameters( + Firebird::IStatus* /*status*/) const + { + return inputParameters; + } + + virtual const Firebird::IParametersMetadata* FB_CARG getOutputParameters( + Firebird::IStatus* /*status*/) const + { + return outputParameters; + } + + virtual const Firebird::IParametersMetadata* FB_CARG getTriggerFields( + Firebird::IStatus* /*status*/) const + { + return triggerFields; + } + virtual const char* FB_CARG getTriggerTable(Firebird::IStatus* /*status*/) const { return triggerTable.c_str(); @@ -112,6 +128,9 @@ Firebird::MetaName name; Firebird::string entryPoint; Firebird::string body; + Firebird::AutoPtr<Firebird::StatementMetadata::Parameters> inputParameters; + Firebird::AutoPtr<Firebird::StatementMetadata::Parameters> outputParameters; + Firebird::AutoPtr<Firebird::StatementMetadata::Parameters> triggerFields; Firebird::MetaName triggerTable; Firebird::ExternalTrigger::Type triggerType; }; @@ -190,8 +209,7 @@ const Jrd::Function* aUdf); ~Function(); - void execute(thread_db* tdbb, const Firebird::Array<NestConst<ValueExprNode> >& args, - impure_value* impure) const; + void execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg) const; private: ExtEngineManager* extManager; @@ -214,7 +232,7 @@ const jrd_prc* aPrc); ~Procedure(); - ResultSet* open(thread_db* tdbb, ValuesImpl* inputParams, ValuesImpl* outputParams) const; + ResultSet* open(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg) const; private: ExtEngineManager* extManager; @@ -230,8 +248,7 @@ class ResultSet { public: - Re... [truncated message content] |