diff --git a/src/include/firebird/FirebirdInterface.idl b/src/include/firebird/FirebirdInterface.idl index 0e97fe2661a..243299e1d0b 100644 --- a/src/include/firebird/FirebirdInterface.idl +++ b/src/include/firebird/FirebirdInterface.idl @@ -1243,6 +1243,10 @@ version: // 4.0 Beta1 => 4.0 Beta2 uint* fractions, uint timeZoneBufferLength, string timeZoneBuffer); void decodeTimeStampTzEx(Status status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, uint* year, uint* month, uint* day, uint* hours, uint* minutes, uint* seconds, uint* fractions, uint timeZoneBufferLength, string timeZoneBuffer); + +version: // 4.0.6 => 4.0.7, 5.0.3 => 5.0.4 + void convert(Status status, uint sourceType, uint sourceScale, uint sourceLength, const void* source, + uint targetType, uint targetScale, uint targetLength, void* target); } interface OffsetsCallback : Versioned diff --git a/src/include/firebird/IdlFbInterfaces.h b/src/include/firebird/IdlFbInterfaces.h index e2955e6b08c..4a03742fbc3 100644 --- a/src/include/firebird/IdlFbInterfaces.h +++ b/src/include/firebird/IdlFbInterfaces.h @@ -4764,7 +4764,7 @@ namespace Firebird } }; -#define FIREBIRD_IUTIL_VERSION 4u +#define FIREBIRD_IUTIL_VERSION 5u class IUtil : public IVersioned { @@ -4793,6 +4793,7 @@ namespace Firebird IInt128* (CLOOP_CARG *getInt128)(IUtil* self, IStatus* status) CLOOP_NOEXCEPT; void (CLOOP_CARG *decodeTimeTzEx)(IUtil* self, IStatus* status, const ISC_TIME_TZ_EX* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) CLOOP_NOEXCEPT; void (CLOOP_CARG *decodeTimeStampTzEx)(IUtil* self, IStatus* status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) CLOOP_NOEXCEPT; + void (CLOOP_CARG *convert)(IUtil* self, IStatus* status, unsigned sourceType, unsigned sourceScale, unsigned sourceLength, const void* source, unsigned targetType, unsigned targetScale, unsigned targetLength, void* target) CLOOP_NOEXCEPT; }; protected: @@ -5013,6 +5014,19 @@ namespace Firebird static_cast(this->cloopVTable)->decodeTimeStampTzEx(this, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); StatusType::checkException(status); } + + template void convert(StatusType* status, unsigned sourceType, unsigned sourceScale, unsigned sourceLength, const void* source, unsigned targetType, unsigned targetScale, unsigned targetLength, void* target) + { + if (cloopVTable->version < 5) + { + StatusType::setVersionError(status, "IUtil", cloopVTable->version, 5); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->convert(this, status, sourceType, sourceScale, sourceLength, source, targetType, targetScale, targetLength, target); + StatusType::checkException(status); + } }; #define FIREBIRD_IOFFSETS_CALLBACK_VERSION 2u @@ -16228,6 +16242,7 @@ namespace Firebird this->getInt128 = &Name::cloopgetInt128Dispatcher; this->decodeTimeTzEx = &Name::cloopdecodeTimeTzExDispatcher; this->decodeTimeStampTzEx = &Name::cloopdecodeTimeStampTzExDispatcher; + this->convert = &Name::cloopconvertDispatcher; } } vTable; @@ -16539,6 +16554,20 @@ namespace Firebird StatusType::catchException(&status2); } } + + static void CLOOP_CARG cloopconvertDispatcher(IUtil* self, IStatus* status, unsigned sourceType, unsigned sourceScale, unsigned sourceLength, const void* source, unsigned targetType, unsigned targetScale, unsigned targetLength, void* target) CLOOP_NOEXCEPT + { + StatusType status2(status); + + try + { + static_cast(self)->Name::convert(&status2, sourceType, sourceScale, sourceLength, source, targetType, targetScale, targetLength, target); + } + catch (...) + { + StatusType::catchException(&status2); + } + } }; template > > @@ -16576,6 +16605,7 @@ namespace Firebird virtual IInt128* getInt128(StatusType* status) = 0; virtual void decodeTimeTzEx(StatusType* status, const ISC_TIME_TZ_EX* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) = 0; virtual void decodeTimeStampTzEx(StatusType* status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) = 0; + virtual void convert(StatusType* status, unsigned sourceType, unsigned sourceScale, unsigned sourceLength, const void* source, unsigned targetType, unsigned targetScale, unsigned targetLength, void* target) = 0; }; template diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index b8cc2719450..cbea97df52b 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -567,6 +567,7 @@ ISC_TIMESTAMP_TZ_EX = record IUtil_getInt128Ptr = function(this: IUtil; status: IStatus): IInt128; cdecl; IUtil_decodeTimeTzExPtr = procedure(this: IUtil; status: IStatus; timeTz: ISC_TIME_TZ_EXPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); cdecl; IUtil_decodeTimeStampTzExPtr = procedure(this: IUtil; status: IStatus; timeStampTz: ISC_TIMESTAMP_TZ_EXPtr; year: CardinalPtr; month: CardinalPtr; day: CardinalPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); cdecl; + IUtil_convertPtr = procedure(this: IUtil; status: IStatus; sourceType: Cardinal; sourceScale: Cardinal; sourceLength: Cardinal; source: Pointer; targetType: Cardinal; targetScale: Cardinal; targetLength: Cardinal; target: Pointer); cdecl; IOffsetsCallback_setOffsetPtr = procedure(this: IOffsetsCallback; status: IStatus; index: Cardinal; offset: Cardinal; nullOffset: Cardinal); cdecl; IXpbBuilder_clearPtr = procedure(this: IXpbBuilder; status: IStatus); cdecl; IXpbBuilder_removeCurrentPtr = procedure(this: IXpbBuilder; status: IStatus); cdecl; @@ -2788,10 +2789,11 @@ UtilVTable = class(VersionedVTable) getInt128: IUtil_getInt128Ptr; decodeTimeTzEx: IUtil_decodeTimeTzExPtr; decodeTimeStampTzEx: IUtil_decodeTimeStampTzExPtr; + convert: IUtil_convertPtr; end; IUtil = class(IVersioned) - const VERSION = 4; + const VERSION = 5; procedure getFbVersion(status: IStatus; att: IAttachment; callback: IVersionCallback); procedure loadBlob(status: IStatus; blobId: ISC_QUADPtr; att: IAttachment; tra: ITransaction; file_: PAnsiChar; txt: Boolean); @@ -2815,6 +2817,7 @@ IUtil = class(IVersioned) function getInt128(status: IStatus): IInt128; procedure decodeTimeTzEx(status: IStatus; timeTz: ISC_TIME_TZ_EXPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); procedure decodeTimeStampTzEx(status: IStatus; timeStampTz: ISC_TIMESTAMP_TZ_EXPtr; year: CardinalPtr; month: CardinalPtr; day: CardinalPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); + procedure convert(status: IStatus; sourceType: Cardinal; sourceScale: Cardinal; sourceLength: Cardinal; source: Pointer; targetType: Cardinal; targetScale: Cardinal; targetLength: Cardinal; target: Pointer); end; IUtilImpl = class(IUtil) @@ -2842,6 +2845,7 @@ IUtilImpl = class(IUtil) function getInt128(status: IStatus): IInt128; virtual; abstract; procedure decodeTimeTzEx(status: IStatus; timeTz: ISC_TIME_TZ_EXPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); virtual; abstract; procedure decodeTimeStampTzEx(status: IStatus; timeStampTz: ISC_TIMESTAMP_TZ_EXPtr; year: CardinalPtr; month: CardinalPtr; day: CardinalPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); virtual; abstract; + procedure convert(status: IStatus; sourceType: Cardinal; sourceScale: Cardinal; sourceLength: Cardinal; source: Pointer; targetType: Cardinal; targetScale: Cardinal; targetLength: Cardinal; target: Pointer); virtual; abstract; end; OffsetsCallbackVTable = class(VersionedVTable) @@ -8714,6 +8718,17 @@ procedure IUtil.decodeTimeStampTzEx(status: IStatus; timeStampTz: ISC_TIMESTAMP_ FbException.checkException(status); end; +procedure IUtil.convert(status: IStatus; sourceType: Cardinal; sourceScale: Cardinal; sourceLength: Cardinal; source: Pointer; targetType: Cardinal; targetScale: Cardinal; targetLength: Cardinal; target: Pointer); +begin + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 5); + end + else begin + UtilVTable(vTable).convert(Self, status, sourceType, sourceScale, sourceLength, source, targetType, targetScale, targetLength, target); + end; + FbException.checkException(status); +end; + procedure IOffsetsCallback.setOffset(status: IStatus; index: Cardinal; offset: Cardinal; nullOffset: Cardinal); begin OffsetsCallbackVTable(vTable).setOffset(Self, status, index, offset, nullOffset); @@ -14633,6 +14648,15 @@ procedure IUtilImpl_decodeTimeStampTzExDispatcher(this: IUtil; status: IStatus; end end; +procedure IUtilImpl_convertDispatcher(this: IUtil; status: IStatus; sourceType: Cardinal; sourceScale: Cardinal; sourceLength: Cardinal; source: Pointer; targetType: Cardinal; targetScale: Cardinal; targetLength: Cardinal; target: Pointer); cdecl; +begin + try + IUtilImpl(this).convert(status, sourceType, sourceScale, sourceLength, source, targetType, targetScale, targetLength, target); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IUtilImpl_vTable: UtilVTable; @@ -17894,7 +17918,7 @@ initialization IVersionCallbackImpl_vTable.callback := @IVersionCallbackImpl_callbackDispatcher; IUtilImpl_vTable := UtilVTable.create; - IUtilImpl_vTable.version := 4; + IUtilImpl_vTable.version := 5; IUtilImpl_vTable.getFbVersion := @IUtilImpl_getFbVersionDispatcher; IUtilImpl_vTable.loadBlob := @IUtilImpl_loadBlobDispatcher; IUtilImpl_vTable.dumpBlob := @IUtilImpl_dumpBlobDispatcher; @@ -17917,6 +17941,7 @@ initialization IUtilImpl_vTable.getInt128 := @IUtilImpl_getInt128Dispatcher; IUtilImpl_vTable.decodeTimeTzEx := @IUtilImpl_decodeTimeTzExDispatcher; IUtilImpl_vTable.decodeTimeStampTzEx := @IUtilImpl_decodeTimeStampTzExDispatcher; + IUtilImpl_vTable.convert := @IUtilImpl_convertDispatcher; IOffsetsCallbackImpl_vTable := OffsetsCallbackVTable.create; IOffsetsCallbackImpl_vTable.version := 2; diff --git a/src/yvalve/YObjects.h b/src/yvalve/YObjects.h index ddc77be45c3..d90c66e3c63 100644 --- a/src/yvalve/YObjects.h +++ b/src/yvalve/YObjects.h @@ -724,6 +724,10 @@ class UtilInterface final : void decodeTimeStampTzEx(Firebird::CheckStatusWrapper* status, const ISC_TIMESTAMP_TZ_EX* timeStampEx, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer); + + void convert(Firebird::CheckStatusWrapper* status, + unsigned sourceType, unsigned sourceScale, unsigned sourceLength, const void* source, + unsigned targetType, unsigned targetScale, unsigned targetLength, void* target); }; } // namespace Why diff --git a/src/yvalve/utl.cpp b/src/yvalve/utl.cpp index c58408c49b4..f2be7cf93fb 100644 --- a/src/yvalve/utl.cpp +++ b/src/yvalve/utl.cpp @@ -799,6 +799,43 @@ void UtilInterface::encodeTimeStampTz(CheckStatusWrapper* status, ISC_TIMESTAMP_ } } +void UtilInterface::convert(Firebird::CheckStatusWrapper* status, + unsigned sourceType, unsigned sourceScale, unsigned sourceLength, const void* source, + unsigned targetType, unsigned targetScale, unsigned targetLength, void* target) +{ + dsc sourceDesc; + memset(&sourceDesc, 0, sizeof(sourceDesc)); + sourceDesc.dsc_dtype = fb_utils::sqlTypeToDscType(sourceType); + sourceDesc.dsc_scale = sourceScale; + sourceDesc.dsc_length = sourceLength; + if (sourceDesc.isText()) + sourceDesc.setTextType(CS_dynamic); + sourceDesc.dsc_address = (UCHAR*) source; + + dsc targetDesc; + memset(&targetDesc, 0, sizeof(targetDesc)); + targetDesc.dsc_dtype = fb_utils::sqlTypeToDscType(targetType); + targetDesc.dsc_scale = targetScale; + targetDesc.dsc_length = targetLength; + if (targetDesc.isText()) + targetDesc.setTextType(CS_dynamic); + targetDesc.dsc_address = static_cast(target); + + try + { + CVT_move(&sourceDesc, &targetDesc, 0, + [](const Arg::StatusVector& status) + { + status.raise(); + } + ); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } +} + ISC_DATE UtilInterface::encodeDate(unsigned year, unsigned month, unsigned day) { tm times;