mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 09:20:39 +01:00
Work in progress on the external engines API changes.
This commit is contained in:
parent
ebd923423b
commit
7ad98cd292
@ -59,10 +59,12 @@ udrcpp_example: $(PLUGINS)/udr/$(LIB_PREFIX)udrcpp_example.$(SHRLIB_EXT)
|
||||
|
||||
$(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
|
||||
|
@ -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>
|
||||
</Project>
|
||||
|
@ -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>
|
||||
</Project>
|
||||
|
@ -587,14 +587,6 @@
|
||||
RelativePath="..\..\..\src\jrd\validation.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\ValueImpl.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\ValuesImpl.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\vio.cpp"
|
||||
>
|
||||
@ -1667,14 +1659,6 @@
|
||||
RelativePath="..\..\..\src\jrd\val_proto.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\ValueImpl.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\ValuesImpl.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\vio_debug.h"
|
||||
>
|
||||
|
@ -587,14 +587,6 @@
|
||||
RelativePath="..\..\..\src\jrd\validation.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\ValueImpl.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\ValuesImpl.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\vio.cpp"
|
||||
>
|
||||
@ -1667,14 +1659,6 @@
|
||||
RelativePath="..\..\..\src\jrd\val_proto.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\ValueImpl.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\ValuesImpl.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\vio_debug.h"
|
||||
>
|
||||
|
@ -30,28 +30,6 @@ using namespace Firebird;
|
||||
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 @@ namespace
|
||||
}
|
||||
|
||||
|
||||
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,90 +640,109 @@ public:
|
||||
~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;
|
||||
}
|
||||
@ -321,36 +769,24 @@ FB_UDR_TRIGGER(replicate)::~FB_UDR_TRIGGER(replicate)()
|
||||
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 @@ void FB_UDR_TRIGGER(replicate)::initialize(ExternalContext* context, Values* val
|
||||
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 @@ void FB_UDR_TRIGGER(replicate)::initialize(ExternalContext* context, Values* val
|
||||
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 @@ void FB_UDR_TRIGGER(replicate)::initialize(ExternalContext* context, Values* val
|
||||
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 @@ void FB_UDR_TRIGGER(replicate)::initialize(ExternalContext* context, Values* val
|
||||
|
||||
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 @@ void FB_UDR_TRIGGER(replicate)::initialize(ExternalContext* context, Values* val
|
||||
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 @@ void FB_UDR_TRIGGER(replicate)::initialize(ExternalContext* context, Values* val
|
||||
|
||||
case SQL_FLOAT:
|
||||
var->sqltype = SQL_DOUBLE | (var->sqltype & 1);
|
||||
var->sqllen = sizeof(double);
|
||||
// fall into
|
||||
|
||||
case SQL_DOUBLE:
|
||||
@ -526,75 +968,38 @@ void FB_UDR_TRIGGER(replicate)::initialize(ExternalContext* context, Values* val
|
||||
|
||||
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);
|
||||
*var->sqlind = 0;
|
||||
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)
|
||||
|
@ -34,6 +34,8 @@
|
||||
#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 @@ const char* dsc::typeToText() const
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -348,6 +348,7 @@ typedef struct dsc
|
||||
#endif
|
||||
|
||||
const char* typeToText() const;
|
||||
void getSqlInfo(SLONG* sqlLength, SLONG* sqlSubType, SLONG* sqlScale, SLONG* sqlType) const;
|
||||
#endif // __cpluplus
|
||||
} DSC;
|
||||
|
||||
|
@ -2621,95 +2621,21 @@ static UCHAR* var_info(const dsql_msg* message,
|
||||
|
||||
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;)
|
||||
{
|
||||
|
@ -61,30 +61,6 @@ typedef void* Handle;
|
||||
#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 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
|
@ -95,8 +95,8 @@ public:
|
||||
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 @@ public:
|
||||
// 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 @@ public:
|
||||
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 @@ public:
|
||||
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)
|
||||
|
@ -50,7 +50,7 @@ namespace Firebird
|
||||
{ \
|
||||
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 @@ namespace Firebird
|
||||
|
||||
#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 @@ namespace Firebird
|
||||
{ \
|
||||
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 @@ namespace Firebird
|
||||
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 @@ namespace Firebird
|
||||
|
||||
#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 @@ namespace Firebird
|
||||
{ \
|
||||
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 @@ namespace Firebird
|
||||
#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 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class Procedure;
|
||||
|
||||
|
||||
class Helper
|
||||
{
|
||||
public:
|
||||
@ -460,11 +460,12 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
protected:
|
||||
Firebird::ExternalContext* context;
|
||||
Firebird::Values* params;
|
||||
Firebird::Values* results;
|
||||
Firebird::Udr::Procedure* procedure;
|
||||
UCHAR* inMsg;
|
||||
UCHAR* outMsg;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 @@ ExtEngineManager::Function::~Function()
|
||||
}
|
||||
|
||||
|
||||
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 @@ void ExtEngineManager::Function::execute(thread_db* tdbb, const NestValueArray&
|
||||
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::Procedure::~Procedure()
|
||||
|
||||
|
||||
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 @@ ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, ValuesImpl* inputParams,
|
||||
|
||||
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 @@ void ExtEngineManager::Trigger::execute(thread_db* tdbb, ExternalTrigger::Action
|
||||
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);
|
||||
|
||||
int start = descs.getCount();
|
||||
descs.resize(start + format->fmt_count);
|
||||
|
||||
int j = 0;
|
||||
|
||||
for (int i = 0; i < format->fmt_count; ++i)
|
||||
for (unsigned i = 0; i < format->fmt_count; ++i)
|
||||
{
|
||||
descs[start + i] = FB_NEW(pool) dsc;
|
||||
if (format->fmt_desc[i].dsc_dtype == dtype_unknown)
|
||||
continue;
|
||||
|
||||
if (format->fmt_desc[i].dsc_dtype != dtype_unknown)
|
||||
{
|
||||
EVL_field(rpb->rpb_relation, record, i, descs[start + i]);
|
||||
dsc desc;
|
||||
EVL_field(rpb->rpb_relation, record, i, &desc);
|
||||
|
||||
jrd_fld* field = (*rpb->rpb_relation->rel_fields)[i];
|
||||
fb_assert(field);
|
||||
unsigned align = type_alignments[desc.dsc_dtype];
|
||||
if (align)
|
||||
msgBuffer.resize(FB_ALIGN(msgBuffer.getCount(), align));
|
||||
|
||||
values->getValue(j + 1)->make(descs[start + i], field->fld_name, true, i);
|
||||
++j;
|
||||
}
|
||||
msgBuffer.add(desc.dsc_address, desc.dsc_length);
|
||||
|
||||
align = type_alignments[dtype_short];
|
||||
if (align)
|
||||
msgBuffer.resize(FB_ALIGN(msgBuffer.getCount(), align));
|
||||
|
||||
USHORT nullFlag = (desc.dsc_flags & DSC_null) != 0;
|
||||
msgBuffer.add((UCHAR*) &nullFlag, sizeof(nullFlag));
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
@ -654,12 +603,35 @@ ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, cons
|
||||
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;
|
||||
|
||||
@ -702,12 +674,40 @@ ExtEngineManager::Procedure* ExtEngineManager::makeProcedure(thread_db* tdbb, co
|
||||
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;
|
||||
|
||||
@ -748,7 +748,9 @@ ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const
|
||||
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,6 +758,28 @@ ExtEngineManager::Trigger* ExtEngineManager::makeTrigger(thread_db* tdbb, const
|
||||
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;
|
||||
|
||||
|
@ -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 Format;
|
||||
class Trigger;
|
||||
class Function;
|
||||
class ValueExprNode;
|
||||
class ValueImpl;
|
||||
class ValuesImpl;
|
||||
struct impure_value;
|
||||
struct record_param;
|
||||
|
||||
@ -97,6 +95,24 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
class ResultSet
|
||||
{
|
||||
public:
|
||||
ResultSet(thread_db* tdbb, ValuesImpl* inputParams, ValuesImpl* outputParams,
|
||||
const Procedure* aProcedure);
|
||||
ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg, const Procedure* aProcedure);
|
||||
~ResultSet();
|
||||
|
||||
bool fetch(thread_db* tdbb);
|
||||
@ -259,9 +276,7 @@ public:
|
||||
record_param* oldRpb, record_param* newRpb) const;
|
||||
|
||||
private:
|
||||
int setValues(thread_db* tdbb, Firebird::MemoryPool& pool,
|
||||
Firebird::AutoPtr<ValuesImpl>& values, Firebird::Array<dsc*>& descs,
|
||||
record_param* rpb) const;
|
||||
void setValues(thread_db* tdbb, Firebird::Array<UCHAR>& msgBuffer, record_param* rpb) const;
|
||||
|
||||
ExtEngineManager* extManager;
|
||||
Firebird::ExternalEngine* engine;
|
||||
|
@ -394,6 +394,8 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
{
|
||||
function->setImplemented(false);
|
||||
}
|
||||
|
||||
function->makeFormat();
|
||||
}
|
||||
else if (!X.RDB$FUNCTION_BLR.NULL)
|
||||
{
|
||||
@ -553,7 +555,7 @@ ULONG Function::allocateImpure(CompilerScratch* csb) const
|
||||
{
|
||||
const ULONG impure = CMP_impure(csb, sizeof(impure_value));
|
||||
|
||||
if (getStatement())
|
||||
if (fun_external || getStatement())
|
||||
{
|
||||
if (fun_in_msg_format.fmt_count)
|
||||
{
|
||||
@ -709,14 +711,8 @@ dsc* Function::execute(thread_db* tdbb, const NestValueArray& args, impure_value
|
||||
// Evaluate the function
|
||||
|
||||
if (fun_entrypoint)
|
||||
{
|
||||
FUN_evaluate(tdbb, this, args, value);
|
||||
}
|
||||
else if (fun_external)
|
||||
{
|
||||
fun_external->execute(tdbb, args, value);
|
||||
}
|
||||
else if (getStatement())
|
||||
else if (fun_external || getStatement())
|
||||
{
|
||||
fb_assert(!fun_return_arg);
|
||||
fb_assert(args.getCount() == fun_inputs);
|
||||
@ -746,68 +742,69 @@ dsc* Function::execute(thread_db* tdbb, const NestValueArray& args, impure_value
|
||||
MOV_move(tdbb, src_desc, &arg_desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
*reinterpret_cast<SSHORT*>(null_ptr) = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
jrd_req* const new_request = getStatement()->findRequest(tdbb);
|
||||
|
||||
try
|
||||
if (fun_external)
|
||||
fun_external->execute(tdbb, in_msg, out_msg);
|
||||
else
|
||||
{
|
||||
// Save the old pool
|
||||
Jrd::ContextPoolHolder context(tdbb, request->req_pool);
|
||||
jrd_req* const new_request = getStatement()->findRequest(tdbb);
|
||||
|
||||
jrd_tra* const transaction = request->req_transaction;
|
||||
const SLONG save_point_number = transaction->tra_save_point ?
|
||||
transaction->tra_save_point->sav_number : 0;
|
||||
|
||||
new_request->req_timestamp = request->req_timestamp;
|
||||
|
||||
EXE_start(tdbb, new_request, transaction);
|
||||
|
||||
if (in_msg_length)
|
||||
try
|
||||
{
|
||||
EXE_send(tdbb, new_request, 0, in_msg_length, in_msg);
|
||||
}
|
||||
// Save the old pool
|
||||
Jrd::ContextPoolHolder context(tdbb, request->req_pool);
|
||||
|
||||
fb_assert(out_msg_length);
|
||||
EXE_receive(tdbb, new_request, 1, out_msg_length, out_msg);
|
||||
jrd_tra* const transaction = request->req_transaction;
|
||||
const SLONG save_point_number = transaction->tra_save_point ?
|
||||
transaction->tra_save_point->sav_number : 0;
|
||||
|
||||
// Clean up all savepoints started during execution of the function
|
||||
new_request->req_timestamp = request->req_timestamp;
|
||||
|
||||
if (transaction != attachment->getSysTransaction())
|
||||
{
|
||||
for (const Savepoint* save_point = transaction->tra_save_point;
|
||||
save_point && save_point_number < save_point->sav_number;
|
||||
save_point = transaction->tra_save_point)
|
||||
EXE_start(tdbb, new_request, transaction);
|
||||
|
||||
if (in_msg_length)
|
||||
{
|
||||
VIO_verb_cleanup(tdbb, transaction);
|
||||
EXE_send(tdbb, new_request, 0, in_msg_length, in_msg);
|
||||
}
|
||||
|
||||
fb_assert(out_msg_length);
|
||||
EXE_receive(tdbb, new_request, 1, out_msg_length, out_msg);
|
||||
|
||||
// Clean up all savepoints started during execution of the function
|
||||
|
||||
if (transaction != attachment->getSysTransaction())
|
||||
{
|
||||
for (const Savepoint* save_point = transaction->tra_save_point;
|
||||
save_point && save_point_number < save_point->sav_number;
|
||||
save_point = transaction->tra_save_point)
|
||||
{
|
||||
VIO_verb_cleanup(tdbb, transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
tdbb->setRequest(request);
|
||||
EXE_unwind(tdbb, new_request);
|
||||
new_request->req_attachment = NULL;
|
||||
new_request->req_flags &= ~req_in_use;
|
||||
throw;
|
||||
}
|
||||
|
||||
tdbb->setRequest(request);
|
||||
EXE_unwind(tdbb, new_request);
|
||||
new_request->req_attachment = NULL;
|
||||
new_request->req_flags &= ~req_in_use;
|
||||
throw;
|
||||
}
|
||||
|
||||
tdbb->setRequest(request);
|
||||
EXE_unwind(tdbb, new_request);
|
||||
new_request->req_attachment = NULL;
|
||||
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))
|
||||
{
|
||||
request->req_flags |= req_null;
|
||||
}
|
||||
else
|
||||
{
|
||||
dsc arg_desc = fun_args[fun_return_arg].fun_parameter->prm_desc;
|
||||
@ -817,9 +814,7 @@ dsc* Function::execute(thread_db* tdbb, const NestValueArray& args, impure_value
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fb_assert(false);
|
||||
}
|
||||
|
||||
// If the function is declared as invariant, mark it as computed
|
||||
|
||||
|
@ -1,675 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Adriano dos Santos Fernandes
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#include "firebird.h"
|
||||
#include "../jrd/ValueImpl.h"
|
||||
#include "../jrd/ErrorImpl.h"
|
||||
#include "../jrd/intl_classes.h"
|
||||
#include "../jrd/DataTypeUtil.h"
|
||||
#include "../jrd/intl_proto.h"
|
||||
#include "../jrd/mov_proto.h"
|
||||
#include "../jrd/Attachment.h"
|
||||
|
||||
using namespace Firebird;
|
||||
using Firebird::uint;
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
|
||||
USHORT ValueMover::getClientCharSet() const
|
||||
{
|
||||
thread_db* tdbb = getThreadData();
|
||||
return tdbb->getAttachment()->att_charset;
|
||||
}
|
||||
|
||||
|
||||
void ValueMover::getClientCharSetName(Firebird::MetaName& name) const
|
||||
{
|
||||
thread_db* tdbb = getThreadData();
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
|
||||
CharSet* cs = INTL_charset_lookup(tdbb, tdbb->getAttachment()->att_charset);
|
||||
name = cs->getName();
|
||||
}
|
||||
|
||||
|
||||
int ValueMover::getMaxBytesPerChar(USHORT charSet) const
|
||||
{
|
||||
thread_db* tdbb = getThreadData();
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
|
||||
return DataTypeUtil(tdbb).maxBytesPerChar(charSet);
|
||||
}
|
||||
|
||||
|
||||
const char* ValueMover::getString(const ValueImpl* value, const dsc* desc, MoveBuffer& buffer,
|
||||
uint* strLength, bool* isNull) const
|
||||
{
|
||||
if (value->isNull())
|
||||
{
|
||||
if (isNull)
|
||||
*isNull = true;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (isNull)
|
||||
*isNull = false;
|
||||
|
||||
thread_db* tdbb = getThreadData();
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
USHORT charSet = tdbb->getAttachment()->att_charset;
|
||||
|
||||
UCHAR* temp = NULL;
|
||||
int len = MOV_make_string2(tdbb, desc, charSet, &temp, buffer, false);
|
||||
|
||||
if (temp == buffer.begin())
|
||||
buffer.resize(len + 1);
|
||||
else
|
||||
memcpy(buffer.getBuffer(len + 1), temp, len);
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
if (strLength)
|
||||
*strLength = len;
|
||||
|
||||
return (const char*) buffer.begin();
|
||||
}
|
||||
|
||||
|
||||
void ValueMover::getValue(const ValueImpl* value, const dsc* desc, dsc* target, bool* isNull) const
|
||||
{
|
||||
if (value->isNull())
|
||||
{
|
||||
if (isNull)
|
||||
*isNull = true;
|
||||
else
|
||||
status_exception::raise(Arg::Gds(isc_unexpected_null));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isNull)
|
||||
*isNull = false;
|
||||
|
||||
thread_db* tdbb = getThreadData();
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
|
||||
MOV_move(tdbb, const_cast<dsc*>(desc), target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ValueMover::setValue(dsc* desc, USHORT* nullFlag, dsc* from) const
|
||||
{
|
||||
thread_db* tdbb = getThreadData();
|
||||
Attachment::SyncGuard attGuard(tdbb->getAttachment());
|
||||
|
||||
MOV_move(tdbb, from, desc);
|
||||
*nullFlag &= ~DSC_null;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
|
||||
ValueImpl::ValueImpl(MemoryPool& p, const dsc* aDesc, const Firebird::MetaName& aName, bool aNullable)
|
||||
: PermanentStorage(p),
|
||||
name(p),
|
||||
fieldNumber(0),
|
||||
buffer(p),
|
||||
charSetName(p)
|
||||
{
|
||||
make(aDesc, aName, aNullable);
|
||||
}
|
||||
|
||||
|
||||
ValueImpl::ValueImpl(MemoryPool& p, const Format* format, unsigned index, UCHAR* msg,
|
||||
const Firebird::MetaName& aName, bool aNullable)
|
||||
: PermanentStorage(p),
|
||||
name(p),
|
||||
fieldNumber(0),
|
||||
buffer(p),
|
||||
charSetName(p)
|
||||
{
|
||||
make(format, index, msg, aName, aNullable);
|
||||
}
|
||||
|
||||
|
||||
ValueImpl::ValueImpl(MemoryPool& p)
|
||||
: PermanentStorage(p),
|
||||
nullFlag(NULL),
|
||||
name(p),
|
||||
buffer(p)
|
||||
{
|
||||
desc.clear();
|
||||
}
|
||||
|
||||
|
||||
void ValueImpl::make(const dsc* aDesc, const Firebird::MetaName& aName, bool aNullable,
|
||||
USHORT aFieldNumber)
|
||||
{
|
||||
desc = *aDesc;
|
||||
nullFlag = &desc.dsc_flags;
|
||||
|
||||
name = aName;
|
||||
nullable = aNullable;
|
||||
fieldNumber = aFieldNumber;
|
||||
}
|
||||
|
||||
|
||||
void ValueImpl::make(const Format* format, unsigned index, UCHAR* msg,
|
||||
const Firebird::MetaName& aName, bool aNullable, USHORT aFieldNumber)
|
||||
{
|
||||
fb_assert(index * 2 < format->fmt_count);
|
||||
|
||||
desc = format->fmt_desc[index * 2];
|
||||
desc.dsc_address = msg + (IPTR) desc.dsc_address;
|
||||
|
||||
const dsc* nullDesc = &format->fmt_desc[index * 2 + 1];
|
||||
fb_assert(nullDesc->dsc_dtype == dtype_short);
|
||||
nullFlag = (USHORT*) (msg + (IPTR) nullDesc->dsc_address);
|
||||
|
||||
name = aName;
|
||||
nullable = aNullable;
|
||||
fieldNumber = aFieldNumber;
|
||||
}
|
||||
|
||||
|
||||
const char* FB_CALL ValueImpl::getName(Error* /*error*/) const
|
||||
{
|
||||
return name.c_str();
|
||||
}
|
||||
|
||||
|
||||
Value::Type FB_CALL ValueImpl::getType(Error* error) const
|
||||
{
|
||||
switch (desc.dsc_dtype)
|
||||
{
|
||||
case dtype_byte:
|
||||
case dtype_short:
|
||||
return TYPE_SMALLINT;
|
||||
|
||||
case dtype_long:
|
||||
return TYPE_INTEGER;
|
||||
|
||||
case dtype_int64:
|
||||
return TYPE_BIGINT;
|
||||
|
||||
case dtype_real:
|
||||
case dtype_double:
|
||||
case dtype_d_float:
|
||||
return TYPE_DOUBLE;
|
||||
|
||||
case dtype_text:
|
||||
return TYPE_CHAR;
|
||||
|
||||
case dtype_cstring:
|
||||
case dtype_varying:
|
||||
return TYPE_VARCHAR;
|
||||
|
||||
case dtype_blob:
|
||||
case dtype_quad:
|
||||
return TYPE_BLOB;
|
||||
|
||||
case dtype_sql_date:
|
||||
return TYPE_DATE;
|
||||
|
||||
case dtype_sql_time:
|
||||
return TYPE_TIME;
|
||||
|
||||
case dtype_timestamp:
|
||||
return TYPE_TIMESTAMP;
|
||||
|
||||
default:
|
||||
ISC_STATUS status[] = {isc_arg_gds, isc_wish_list, 0};
|
||||
ErrorImpl::statusVectorToError(status, error);
|
||||
return (Type) 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char* FB_CALL ValueImpl::getCharSet(Error* /*error*/) const
|
||||
{
|
||||
if ((desc.isText() || desc.isBlob()) && charSetName.isEmpty())
|
||||
mover.getClientCharSetName(charSetName);
|
||||
|
||||
return charSetName.c_str();
|
||||
}
|
||||
|
||||
|
||||
int FB_CALL ValueImpl::getSubType(Error* /*error*/) const
|
||||
{
|
||||
if (desc.isBlob())
|
||||
return desc.getBlobSubType();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int FB_CALL ValueImpl::getPrecision(Error* error) const
|
||||
{
|
||||
try
|
||||
{
|
||||
if (desc.isText())
|
||||
return desc.getStringLength() / mover.getMaxBytesPerChar(desc.getCharSet());
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
catch (const Exception& e)
|
||||
{
|
||||
ErrorImpl::exceptionToError(e, error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int FB_CALL ValueImpl::getScale(Error* /*error*/) const
|
||||
{
|
||||
return desc.dsc_scale;
|
||||
}
|
||||
|
||||
|
||||
bool FB_CALL ValueImpl::isNullable(Error* /*error*/) const
|
||||
{
|
||||
return nullable;
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setNull(Error* error)
|
||||
{
|
||||
if (isNullable(error))
|
||||
setNull();
|
||||
else
|
||||
{
|
||||
string text;
|
||||
text.printf("parameter %s", name.c_str());
|
||||
|
||||
ISC_STATUS status[] = {
|
||||
isc_arg_gds, isc_not_valid_for,
|
||||
isc_arg_string, (ISC_STATUS) text.c_str(),
|
||||
isc_arg_string, (ISC_STATUS) NULL_STRING_MARK,
|
||||
0};
|
||||
ErrorImpl::statusVectorToError(status, error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::copyFrom(Error* error, const Value* from)
|
||||
{
|
||||
if (from->isNull())
|
||||
setNull(error);
|
||||
else
|
||||
{
|
||||
switch (from->getType(error))
|
||||
{
|
||||
case TYPE_SMALLINT:
|
||||
case TYPE_INTEGER:
|
||||
case TYPE_BIGINT:
|
||||
{
|
||||
DelegateError err(error);
|
||||
int scale = from->getScale(error);
|
||||
int64 value = from->getBigInt(&err, scale);
|
||||
if (!err.isRaised())
|
||||
setBigInt(error, value, scale);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_DOUBLE:
|
||||
{
|
||||
DelegateError err(error);
|
||||
double value = from->getDouble(&err);
|
||||
if (!err.isRaised())
|
||||
setDouble(error, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_BLOB:
|
||||
{
|
||||
DelegateError err(error);
|
||||
int64 id = from->getBlobId(&err);
|
||||
if (!err.isRaised())
|
||||
setBlobId(error, id);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_DATE:
|
||||
{
|
||||
DelegateError err(error);
|
||||
Date value;
|
||||
from->getDate(&err, &value);
|
||||
if (!err.isRaised())
|
||||
setDate(error, &value);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_TIME:
|
||||
{
|
||||
DelegateError err(error);
|
||||
Time value;
|
||||
from->getTime(&err, &value);
|
||||
if (!err.isRaised())
|
||||
setTime(error, &value);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_TIMESTAMP:
|
||||
{
|
||||
DelegateError err(error);
|
||||
DateTime value;
|
||||
from->getTimeStamp(&err, &value);
|
||||
if (!err.isRaised())
|
||||
setTimeStamp(error, &value);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_CHAR:
|
||||
case TYPE_VARCHAR:
|
||||
default:
|
||||
{
|
||||
uint len;
|
||||
const char* p = from->getString(error, &len);
|
||||
if (p)
|
||||
setString(error, p, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int16 FB_CALL ValueImpl::getSmallInt(Error* error, int scale, bool* isNull) const
|
||||
{
|
||||
SSHORT value = 0;
|
||||
dsc target;
|
||||
target.makeShort(scale, &value);
|
||||
getValue(error, &target, isNull);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setSmallInt(Error* error, int16 value, int scale)
|
||||
{
|
||||
SSHORT val = value;
|
||||
dsc from;
|
||||
from.makeShort(scale, &val);
|
||||
setValue(error, &from);
|
||||
}
|
||||
|
||||
|
||||
int32 FB_CALL ValueImpl::getInt(Error* error, int scale, bool* isNull) const
|
||||
{
|
||||
SLONG value = 0;
|
||||
dsc target;
|
||||
target.makeLong(scale, &value);
|
||||
getValue(error, &target, isNull);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setInt(Error* error, int32 value, int scale)
|
||||
{
|
||||
SLONG val = value;
|
||||
dsc from;
|
||||
from.makeLong(scale, &val);
|
||||
setValue(error, &from);
|
||||
}
|
||||
|
||||
|
||||
int64 FB_CALL ValueImpl::getBigInt(Error* error, int scale, bool* isNull) const
|
||||
{
|
||||
SINT64 value = 0;
|
||||
dsc target;
|
||||
target.makeInt64(scale, &value);
|
||||
getValue(error, &target, isNull);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setBigInt(Error* error, int64 value, int scale)
|
||||
{
|
||||
dsc from;
|
||||
from.makeInt64(scale, &value);
|
||||
setValue(error, &from);
|
||||
}
|
||||
|
||||
|
||||
double FB_CALL ValueImpl::getDouble(Error* error, bool* isNull) const
|
||||
{
|
||||
double value = 0;
|
||||
dsc target;
|
||||
target.makeDouble(&value);
|
||||
getValue(error, &target, isNull);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setDouble(Error* error, double value)
|
||||
{
|
||||
dsc from;
|
||||
from.makeDouble(&value);
|
||||
setValue(error, &from);
|
||||
}
|
||||
|
||||
|
||||
const char* FB_CALL ValueImpl::getString(Error* /*error*/, uint* strLength, bool* isNull) const
|
||||
{
|
||||
return mover.getString(this, &desc, buffer, strLength, isNull);
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setString(Error* error, const char* str, uint strLength)
|
||||
{
|
||||
dsc from;
|
||||
from.makeText(strLength, mover.getClientCharSet(), (UCHAR*) str);
|
||||
setValue(error, &from);
|
||||
}
|
||||
|
||||
|
||||
Firebird::int64 FB_CALL ValueImpl::getBlobId(Error* error, bool* isNull) const
|
||||
{
|
||||
if (!desc.isBlob())
|
||||
{
|
||||
Arg::Gds vector(isc_type_notcompat_blob);
|
||||
vector << desc.typeToText();
|
||||
ErrorImpl::statusVectorToError(vector.value(), error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64 blobId;
|
||||
|
||||
if (this->isNull())
|
||||
blobId = 0;
|
||||
else
|
||||
{
|
||||
ISC_QUAD quad = *(ISC_QUAD*) desc.dsc_address;
|
||||
blobId = quad.gds_quad_low | ((int64) quad.gds_quad_high << 32);
|
||||
}
|
||||
|
||||
if (isNull)
|
||||
*isNull = blobId == 0;
|
||||
|
||||
return blobId;
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setBlobId(Error* error, Firebird::int64 value)
|
||||
{
|
||||
bid bid;
|
||||
bid.bid_quad.bid_quad_low = value;
|
||||
bid.bid_quad.bid_quad_high = value >> 32;
|
||||
|
||||
dsc from;
|
||||
from.makeBlob(desc.getBlobSubType(), mover.getClientCharSet(), reinterpret_cast<ISC_QUAD*>(&bid));
|
||||
|
||||
setValue(error, &from);
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::getDate(Error* error, Date* value, bool* isNull) const
|
||||
{
|
||||
DelegateError err(error);
|
||||
|
||||
GDS_DATE gdsDate;
|
||||
dsc target;
|
||||
target.makeDate(&gdsDate);
|
||||
getValue(&err, &target, isNull);
|
||||
|
||||
if (!err.isRaised())
|
||||
{
|
||||
tm t;
|
||||
TimeStamp::decode_date(gdsDate, &t);
|
||||
|
||||
value->year = t.tm_year + 1900;
|
||||
value->month = t.tm_mon + 1;
|
||||
value->day = t.tm_mday;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setDate(Error* error, const Date* value)
|
||||
{
|
||||
tm t;
|
||||
t.tm_year = value->year - 1900;
|
||||
t.tm_mon = value->month - 1;
|
||||
t.tm_mday = value->day;
|
||||
|
||||
GDS_DATE gdsDate = TimeStamp::encode_date(&t);
|
||||
|
||||
tm t2;
|
||||
TimeStamp::decode_date(gdsDate, &t2);
|
||||
|
||||
if (t2.tm_year != t.tm_year || t2.tm_mon != t.tm_mon || t2.tm_mday != t.tm_mday)
|
||||
{
|
||||
Arg::Gds vector(isc_invalid_date_val);
|
||||
ErrorImpl::statusVectorToError(vector.value(), error);
|
||||
return;
|
||||
}
|
||||
|
||||
dsc from;
|
||||
from.makeDate(&gdsDate);
|
||||
setValue(error, &from);
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::getTime(Error* error, Time* value, bool* isNull) const
|
||||
{
|
||||
DelegateError err(error);
|
||||
|
||||
GDS_TIME gdsTime;
|
||||
dsc target;
|
||||
target.makeTime(&gdsTime);
|
||||
getValue(&err, &target, isNull);
|
||||
|
||||
if (!err.isRaised())
|
||||
{
|
||||
TimeStamp::decode_time(gdsTime, &value->hours, &value->minutes,
|
||||
&value->seconds, &value->fractions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setTime(Error* error, const Time* value)
|
||||
{
|
||||
GDS_TIME gdsTime;
|
||||
gdsTime = TimeStamp::encode_time(value->hours, value->minutes, value->seconds, value->fractions);
|
||||
|
||||
Time t2;
|
||||
TimeStamp::decode_time(gdsTime, &t2.hours, &t2.minutes, &t2.seconds, &t2.fractions);
|
||||
if (t2.hours != value->hours || t2.minutes != value->minutes ||
|
||||
t2.seconds != value->seconds || t2.fractions != value->fractions)
|
||||
{
|
||||
Arg::Gds vector(isc_invalid_time_val);
|
||||
ErrorImpl::statusVectorToError(vector.value(), error);
|
||||
return;
|
||||
}
|
||||
|
||||
dsc from;
|
||||
from.makeTime(&gdsTime);
|
||||
setValue(error, &from);
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::getTimeStamp(Error* error, DateTime* value, bool* isNull) const
|
||||
{
|
||||
DelegateError err(error);
|
||||
|
||||
GDS_TIMESTAMP gdsTimeStamp;
|
||||
dsc target;
|
||||
target.makeTimestamp(&gdsTimeStamp);
|
||||
getValue(&err, &target, isNull);
|
||||
|
||||
if (!err.isRaised())
|
||||
{
|
||||
tm t;
|
||||
TimeStamp::decode_date(gdsTimeStamp.timestamp_date, &t);
|
||||
TimeStamp::decode_time(gdsTimeStamp.timestamp_time, &value->time.hours,
|
||||
&value->time.minutes, &value->time.seconds, &value->time.fractions);
|
||||
|
||||
value->date.year = t.tm_year + 1900;
|
||||
value->date.month = t.tm_mon + 1;
|
||||
value->date.day = t.tm_mday;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValueImpl::setTimeStamp(Error* error, const DateTime* value)
|
||||
{
|
||||
tm t;
|
||||
t.tm_year = value->date.year - 1900;
|
||||
t.tm_mon = value->date.month - 1;
|
||||
t.tm_mday = value->date.day;
|
||||
|
||||
GDS_TIMESTAMP gdsTimeStamp;
|
||||
gdsTimeStamp.timestamp_date = TimeStamp::encode_date(&t);
|
||||
gdsTimeStamp.timestamp_time = TimeStamp::encode_time(value->time.hours,
|
||||
value->time.minutes, value->time.seconds, value->time.fractions);
|
||||
|
||||
DateTime timeStamp2;
|
||||
TimeStamp::decode_time(gdsTimeStamp.timestamp_time, &timeStamp2.time.hours,
|
||||
&timeStamp2.time.minutes, &timeStamp2.time.seconds, &timeStamp2.time.fractions);
|
||||
|
||||
tm t2;
|
||||
//TimeStamp(gdsTimeStamp).decode(&t2);
|
||||
TimeStamp::decode_date(gdsTimeStamp.timestamp_date, &t2);
|
||||
|
||||
if (timeStamp2.time.hours != value->time.hours ||
|
||||
timeStamp2.time.minutes != value->time.minutes ||
|
||||
timeStamp2.time.seconds != value->time.seconds ||
|
||||
timeStamp2.time.fractions != value->time.fractions ||
|
||||
t2.tm_year != t.tm_year ||
|
||||
t2.tm_mon != t.tm_mon ||
|
||||
t2.tm_mday != t.tm_mday)
|
||||
{
|
||||
Arg::Gds vector(isc_invalid_timestamp_val);
|
||||
ErrorImpl::statusVectorToError(vector.value(), error);
|
||||
return;
|
||||
}
|
||||
|
||||
dsc from;
|
||||
from.makeTimestamp(&gdsTimeStamp);
|
||||
setValue(error, &from);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Jrd
|
@ -1,191 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Adriano dos Santos Fernandes
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#ifndef JRD_VALUE_IMPL_H
|
||||
#define JRD_VALUE_IMPL_H
|
||||
|
||||
#include "FirebirdApi.h"
|
||||
#include "FirebirdExternalApi.h"
|
||||
#include "../common/common.h"
|
||||
#include "../common/dsc.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/ErrorImpl.h"
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
class ValueImpl;
|
||||
|
||||
|
||||
class ValueMover
|
||||
{
|
||||
public:
|
||||
USHORT getClientCharSet() const;
|
||||
void getClientCharSetName(Firebird::MetaName& name) const;
|
||||
int getMaxBytesPerChar(USHORT charSet) const;
|
||||
|
||||
const char* getString(const ValueImpl* value, const dsc* desc, MoveBuffer& buffer,
|
||||
Firebird::uint* strLength, bool* isNull) const;
|
||||
|
||||
void getValue(const ValueImpl* value, const dsc* desc, dsc* target, bool* isNull) const;
|
||||
void setValue(dsc* desc, USHORT* nullFlag, dsc* from) const;
|
||||
|
||||
static inline thread_db* getThreadData()
|
||||
{
|
||||
return JRD_get_thread_data();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ValueImpl : public Firebird::Value, Firebird::PermanentStorage
|
||||
{
|
||||
public:
|
||||
ValueImpl(Firebird::MemoryPool& p, const dsc* aDesc,
|
||||
const Firebird::MetaName& aName, bool aNullable);
|
||||
ValueImpl(Firebird::MemoryPool& p, const Format* format, unsigned index, UCHAR* msg,
|
||||
const Firebird::MetaName& aName, bool aNullable);
|
||||
explicit ValueImpl(Firebird::MemoryPool& p);
|
||||
|
||||
virtual ~ValueImpl()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
ValueImpl(const ValueImpl&);
|
||||
ValueImpl& operator =(const ValueImpl&);
|
||||
|
||||
public:
|
||||
// used in triggers code
|
||||
USHORT getFieldNumber() const
|
||||
{
|
||||
return fieldNumber;
|
||||
}
|
||||
|
||||
dsc& getDesc()
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
|
||||
void setNull()
|
||||
{
|
||||
*nullFlag |= DSC_null;
|
||||
}
|
||||
|
||||
void make(const dsc* aDesc, const Firebird::MetaName& aName, bool aNullable,
|
||||
USHORT aFieldNumber = 0);
|
||||
void make(const Format* format, unsigned index, UCHAR* msg, const Firebird::MetaName& aName,
|
||||
bool aNullable, USHORT aFieldNumber = 0);
|
||||
|
||||
public:
|
||||
virtual const char* FB_CALL getName(Firebird::Error* error) const;
|
||||
virtual Type FB_CALL getType(Firebird::Error* error) const;
|
||||
virtual const char* FB_CALL getCharSet(Firebird::Error* error) const;
|
||||
virtual int FB_CALL getSubType(Firebird::Error* error) const;
|
||||
virtual int FB_CALL getPrecision(Firebird::Error* error) const;
|
||||
virtual int FB_CALL getScale(Firebird::Error* error) const;
|
||||
virtual bool FB_CALL isNullable(Firebird::Error* error) const;
|
||||
|
||||
virtual bool FB_CALL isNull() const
|
||||
{
|
||||
return *nullFlag & DSC_null;
|
||||
}
|
||||
|
||||
virtual void FB_CALL setNull(Firebird::Error* error);
|
||||
|
||||
virtual void FB_CALL copyFrom(Firebird::Error* error, const Firebird::Value* from);
|
||||
|
||||
virtual Firebird::int16 FB_CALL getSmallInt(Firebird::Error* error, int scale = 0,
|
||||
bool* isNull = FB_NULL) const;
|
||||
virtual void FB_CALL setSmallInt(Firebird::Error* error, Firebird::int16 value, int scale = 0);
|
||||
|
||||
virtual Firebird::int32 FB_CALL getInt(Firebird::Error* error, int scale = 0,
|
||||
bool* isNull = FB_NULL) const;
|
||||
virtual void FB_CALL setInt(Firebird::Error* error, Firebird::int32 value, int scale = 0);
|
||||
|
||||
virtual Firebird::int64 FB_CALL getBigInt(Firebird::Error* error, int scale = 0,
|
||||
bool* isNull = FB_NULL) const;
|
||||
virtual void FB_CALL setBigInt(Firebird::Error* error, Firebird::int64 value, int scale = 0);
|
||||
|
||||
virtual double FB_CALL getDouble(Firebird::Error* error, bool* isNull = FB_NULL) const;
|
||||
virtual void FB_CALL setDouble(Firebird::Error* error, double value);
|
||||
|
||||
virtual const char* FB_CALL getString(Firebird::Error* error,
|
||||
Firebird::uint* strLength = FB_NULL, bool* isNull = FB_NULL) const;
|
||||
virtual void FB_CALL setString(Firebird::Error* error, const char* str,
|
||||
Firebird::uint strLength);
|
||||
|
||||
virtual Firebird::int64 FB_CALL getBlobId(Firebird::Error* error,
|
||||
bool* isNull = FB_NULL) const;
|
||||
virtual void FB_CALL setBlobId(Firebird::Error* error, Firebird::int64 value);
|
||||
|
||||
virtual void FB_CALL getDate(Firebird::Error* error, Firebird::Date* value,
|
||||
bool* isNull = FB_NULL) const;
|
||||
virtual void FB_CALL setDate(Firebird::Error* error, const Firebird::Date* value);
|
||||
|
||||
virtual void FB_CALL getTime(Firebird::Error* error, Firebird::Time* value,
|
||||
bool* isNull = FB_NULL) const;
|
||||
virtual void FB_CALL setTime(Firebird::Error* error, const Firebird::Time* value);
|
||||
|
||||
virtual void FB_CALL getTimeStamp(Firebird::Error* error, Firebird::DateTime* value,
|
||||
bool* isNull = FB_NULL) const;
|
||||
virtual void FB_CALL setTimeStamp(Firebird::Error* error, const Firebird::DateTime* value);
|
||||
|
||||
private:
|
||||
void getValue(Firebird::Error* error, dsc* target, bool* isNull) const
|
||||
{
|
||||
try
|
||||
{
|
||||
mover.getValue(this, &desc, target, isNull);
|
||||
}
|
||||
catch (const Firebird::Exception& ex)
|
||||
{
|
||||
ErrorImpl::exceptionToError(ex, error);
|
||||
}
|
||||
}
|
||||
|
||||
void setValue(Firebird::Error* error, dsc* from)
|
||||
{
|
||||
try
|
||||
{
|
||||
mover.setValue(&desc, nullFlag, from);
|
||||
}
|
||||
catch (const Firebird::Exception& ex)
|
||||
{
|
||||
ErrorImpl::exceptionToError(ex, error);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
dsc desc;
|
||||
USHORT* nullFlag;
|
||||
Firebird::MetaName name;
|
||||
bool nullable;
|
||||
USHORT fieldNumber;
|
||||
mutable MoveBuffer buffer;
|
||||
mutable Firebird::MetaName charSetName;
|
||||
ValueMover mover;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Jrd
|
||||
|
||||
#endif // JRD_VALUE_IMPL_H
|
@ -1,236 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Adriano dos Santos Fernandes
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#include "firebird.h"
|
||||
#include "../jrd/ValuesImpl.h"
|
||||
#include "../jrd/ErrorImpl.h"
|
||||
#include "../jrd/mov_proto.h"
|
||||
#include "../jrd/align.h"
|
||||
|
||||
using namespace Firebird;
|
||||
using Firebird::uint;
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
|
||||
ValuesImpl::IndividualQueue::IndividualQueue(MemoryPool& p, Error* /*error*/, ValuesImpl* aValues)
|
||||
: PermanentStorage(p),
|
||||
values(aValues),
|
||||
valueCount(values->getCount()),
|
||||
recordSize(0),
|
||||
records(p),
|
||||
enqueuePos(0),
|
||||
recordNumber(0)
|
||||
{
|
||||
for (uint i = 1; i <= valueCount; ++i)
|
||||
{
|
||||
ValueImpl* value = values->getValue(i);
|
||||
const dsc& desc = value->getDesc();
|
||||
|
||||
USHORT align = type_alignments[desc.dsc_dtype];
|
||||
if (align)
|
||||
recordSize = FB_ALIGN(recordSize, align);
|
||||
|
||||
recordSize += desc.dsc_length;
|
||||
}
|
||||
|
||||
nullsStart = recordSize;
|
||||
recordSize += valueCount / 8 + 1;
|
||||
}
|
||||
|
||||
|
||||
ValuesImpl::IndividualQueue::~IndividualQueue()
|
||||
{
|
||||
for (Array<UCHAR*>::iterator end = records.end(), i = records.begin(); i != end; ++i)
|
||||
delete [] *i;
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValuesImpl::IndividualQueue::enqueue(Error* /*error*/)
|
||||
{
|
||||
const size_t recordCount = records.getCount();
|
||||
UCHAR* const buffer = (enqueuePos < recordCount ?
|
||||
records[enqueuePos] : FB_NEW(getPool()) UCHAR[recordSize]);
|
||||
UCHAR* nullsBuffer = buffer + nullsStart;
|
||||
uint pos = 0;
|
||||
|
||||
for (uint i = 1; i <= valueCount; ++i)
|
||||
{
|
||||
ValueImpl* value = values->getValue(i);
|
||||
const dsc& desc = value->getDesc();
|
||||
|
||||
USHORT align = type_alignments[desc.dsc_dtype];
|
||||
if (align)
|
||||
pos = FB_ALIGN(pos, align);
|
||||
|
||||
if (value->isNull())
|
||||
nullsBuffer[(i - 1) >> 3] |= 1 << ((i - 1) & 7);
|
||||
else
|
||||
{
|
||||
nullsBuffer[(i - 1) >> 3] &= ~(1 << ((i - 1) & 7));
|
||||
memcpy(buffer + pos, desc.dsc_address, desc.dsc_length);
|
||||
}
|
||||
|
||||
pos += desc.dsc_length;
|
||||
}
|
||||
|
||||
if (enqueuePos++ >= recordCount)
|
||||
records.push(buffer);
|
||||
}
|
||||
|
||||
|
||||
bool FB_CALL ValuesImpl::IndividualQueue::dequeue(Error* /*error*/)
|
||||
{
|
||||
if (recordNumber == enqueuePos)
|
||||
return false;
|
||||
|
||||
const UCHAR* buffer = records[recordNumber++];
|
||||
const UCHAR* nullsBuffer = buffer + nullsStart;
|
||||
uint pos = 0;
|
||||
|
||||
for (uint i = 1; i <= valueCount; ++i)
|
||||
{
|
||||
ValueImpl* value = values->getValue(i);
|
||||
dsc& desc = value->getDesc();
|
||||
|
||||
USHORT align = type_alignments[desc.dsc_dtype];
|
||||
if (align)
|
||||
pos = FB_ALIGN(pos, align);
|
||||
|
||||
if (nullsBuffer[(i - 1) >> 3] & (1 << ((i - 1) & 7)))
|
||||
desc.dsc_flags |= DSC_null;
|
||||
else
|
||||
{
|
||||
memcpy(desc.dsc_address, buffer + pos, desc.dsc_length);
|
||||
desc.dsc_flags &= ~DSC_null;
|
||||
}
|
||||
|
||||
pos += desc.dsc_length;
|
||||
}
|
||||
|
||||
if (recordNumber == enqueuePos)
|
||||
{
|
||||
recordNumber = 0;
|
||||
enqueuePos = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//---------------------
|
||||
|
||||
|
||||
ValuesImpl::MsgQueue::MsgQueue(MemoryPool& p, Error* /*error*/, UCHAR* aMsg, unsigned aMsgLength)
|
||||
: PermanentStorage(p),
|
||||
msg(aMsg),
|
||||
msgLength(aMsgLength),
|
||||
records(p),
|
||||
enqueuePos(0),
|
||||
recordNumber(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ValuesImpl::MsgQueue::~MsgQueue()
|
||||
{
|
||||
for (Array<UCHAR*>::iterator end = records.end(), i = records.begin(); i != end; ++i)
|
||||
delete [] *i;
|
||||
}
|
||||
|
||||
|
||||
void FB_CALL ValuesImpl::MsgQueue::enqueue(Error* /*error*/)
|
||||
{
|
||||
const size_t recordCount = records.getCount();
|
||||
UCHAR* buffer = (enqueuePos < recordCount ?
|
||||
records[enqueuePos] : FB_NEW(getPool()) UCHAR[msgLength]);
|
||||
|
||||
memcpy(buffer, msg, msgLength);
|
||||
|
||||
if (enqueuePos++ >= recordCount)
|
||||
records.push(buffer);
|
||||
}
|
||||
|
||||
|
||||
bool FB_CALL ValuesImpl::MsgQueue::dequeue(Error* /*error*/)
|
||||
{
|
||||
if (recordNumber == enqueuePos)
|
||||
return false;
|
||||
|
||||
const UCHAR* buffer = records[recordNumber++];
|
||||
memcpy(msg, buffer, msgLength);
|
||||
|
||||
if (recordNumber == enqueuePos)
|
||||
{
|
||||
recordNumber = 0;
|
||||
enqueuePos = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//---------------------
|
||||
|
||||
|
||||
Firebird::uint FB_CALL ValuesImpl::getIndexByName(Error* error, const char* name) const
|
||||
{
|
||||
const string nameStr(name);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
{
|
||||
const char* valName = (*values)[i].getName(error);
|
||||
|
||||
if (valName)
|
||||
{
|
||||
if (nameStr == valName)
|
||||
return i + 1;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Value* FB_CALL ValuesImpl::getValueByName(Error* error, const char* name) const
|
||||
{
|
||||
int index = getIndexByName(error, name);
|
||||
|
||||
if (index > 0)
|
||||
return getValue(error, index);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ValuesQueue* FB_CALL ValuesImpl::createQueue(Error* error)
|
||||
{
|
||||
if (msg)
|
||||
return new MsgQueue(getPool(), error, msg, msgLength);
|
||||
|
||||
return new IndividualQueue(getPool(), error, this);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Jrd
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Adriano dos Santos Fernandes
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#ifndef JRD_VALUES_IMPL_H
|
||||
#define JRD_VALUES_IMPL_H
|
||||
|
||||
#include "FirebirdApi.h"
|
||||
#include "FirebirdExternalApi.h"
|
||||
#include "../jrd/ValueImpl.h"
|
||||
#include "../common/classes/auto.h"
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
|
||||
class ValuesImpl : public Firebird::Values, public Firebird::PermanentStorage
|
||||
{
|
||||
private:
|
||||
// ValuesQueue used for Values composed by independent fields. This is slower.
|
||||
class IndividualQueue : public Firebird::ValuesQueue, public Firebird::PermanentStorage
|
||||
{
|
||||
public:
|
||||
IndividualQueue(Firebird::MemoryPool& p, Firebird::Error* error, ValuesImpl* aValues);
|
||||
virtual ~IndividualQueue();
|
||||
|
||||
public:
|
||||
virtual void FB_CALL dispose(Firebird::Error* /*error*/)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
virtual void FB_CALL enqueue(Firebird::Error* error);
|
||||
virtual bool FB_CALL dequeue(Firebird::Error* error);
|
||||
|
||||
private:
|
||||
ValuesImpl* values;
|
||||
Firebird::uint valueCount;
|
||||
Firebird::uint recordSize;
|
||||
Firebird::Array<UCHAR*> records;
|
||||
Firebird::uint enqueuePos;
|
||||
Firebird::uint recordNumber;
|
||||
Firebird::uint nullsStart;
|
||||
};
|
||||
|
||||
// ValuesQueue used for Values composed by fields of a message. This is faster.
|
||||
class MsgQueue : public Firebird::ValuesQueue, public Firebird::PermanentStorage
|
||||
{
|
||||
public:
|
||||
MsgQueue(Firebird::MemoryPool& p, Firebird::Error* error, UCHAR* aMsg, unsigned aMsgLength);
|
||||
virtual ~MsgQueue();
|
||||
|
||||
public:
|
||||
virtual void FB_CALL dispose(Firebird::Error* /*error*/)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
virtual void FB_CALL enqueue(Firebird::Error* error);
|
||||
virtual bool FB_CALL dequeue(Firebird::Error* error);
|
||||
|
||||
private:
|
||||
UCHAR* msg;
|
||||
unsigned msgLength;
|
||||
Firebird::Array<UCHAR*> records;
|
||||
Firebird::uint enqueuePos;
|
||||
Firebird::uint recordNumber;
|
||||
};
|
||||
|
||||
public:
|
||||
ValuesImpl(Firebird::MemoryPool& p, Firebird::uint aCount)
|
||||
: PermanentStorage(p),
|
||||
msg(NULL),
|
||||
msgLength(0),
|
||||
valuesArray(p),
|
||||
count(aCount)
|
||||
{
|
||||
while (aCount-- > 0)
|
||||
valuesArray.add();
|
||||
|
||||
values = &valuesArray;
|
||||
}
|
||||
|
||||
ValuesImpl(Firebird::MemoryPool& p, const Format* format, UCHAR* aMsg,
|
||||
const Firebird::Array<NestConst<Parameter> >& parameters)
|
||||
: PermanentStorage(p),
|
||||
msg(aMsg),
|
||||
msgLength(format->fmt_length),
|
||||
valuesArray(p),
|
||||
count(format->fmt_count / 2)
|
||||
{
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
{
|
||||
const Parameter* parameter = parameters[i];
|
||||
valuesArray.add().make(format, i, msg, parameter->prm_name, parameter->prm_nullable);
|
||||
}
|
||||
|
||||
values = &valuesArray;
|
||||
}
|
||||
|
||||
virtual ~ValuesImpl()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
ValuesImpl(const ValuesImpl&);
|
||||
ValuesImpl& operator =(const ValuesImpl&);
|
||||
|
||||
public:
|
||||
Jrd::ValueImpl* getValue(Firebird::uint index) const
|
||||
{
|
||||
fb_assert(index >= 1 && index <= count);
|
||||
return values->getPointer(index - 1);
|
||||
}
|
||||
|
||||
void setNull()
|
||||
{
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
(*values)[i].setNull();
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Firebird::uint FB_CALL getCount() const
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
virtual Firebird::uint FB_CALL getIndexByName(Firebird::Error* error, const char* name) const;
|
||||
|
||||
virtual Jrd::ValueImpl* FB_CALL getValue(Firebird::Error* error, Firebird::uint index) const
|
||||
{
|
||||
if (index >= 1 && index <= count)
|
||||
return getValue(index);
|
||||
|
||||
error->addCode(isc_invalid_index_val);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual Firebird::Value* FB_CALL getValueByName(Firebird::Error* error,
|
||||
const char* name) const;
|
||||
|
||||
virtual Firebird::ValuesQueue* FB_CALL createQueue(Firebird::Error* error);
|
||||
|
||||
private:
|
||||
UCHAR* msg;
|
||||
unsigned msgLength;
|
||||
Firebird::ObjectsArray<ValueImpl> valuesArray;
|
||||
Firebird::ObjectsArray<ValueImpl>* values;
|
||||
Firebird::uint count;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Jrd
|
||||
|
||||
#endif // JRD_VALUES_IMPL_H
|
@ -88,7 +88,6 @@
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../dsql/Nodes.h"
|
||||
#include "../jrd/RecordSourceNodes.h"
|
||||
#include "../jrd/ValuesImpl.h"
|
||||
#include "../jrd/recsrc/RecordSource.h"
|
||||
#include "../jrd/recsrc/Cursor.h"
|
||||
#include "../jrd/Function.h"
|
||||
|
@ -109,7 +109,6 @@
|
||||
#include "../jrd/trace/TraceJrdHelpers.h"
|
||||
|
||||
#include "../dsql/Nodes.h"
|
||||
#include "../jrd/ValuesImpl.h"
|
||||
#include "../jrd/recsrc/RecordSource.h"
|
||||
#include "../jrd/recsrc/Cursor.h"
|
||||
#include "../jrd/Function.h"
|
||||
@ -729,12 +728,6 @@ void EXE_release(thread_db* tdbb, jrd_req* request)
|
||||
|
||||
EXE_unwind(tdbb, request);
|
||||
|
||||
delete request->inputParams;
|
||||
request->inputParams = NULL;
|
||||
|
||||
delete request->outputParams;
|
||||
request->outputParams = NULL;
|
||||
|
||||
// system requests are released after all attachments gone and with
|
||||
// req_attachment not cleared
|
||||
|
||||
@ -1420,25 +1413,10 @@ const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* no
|
||||
list->statements[i].getObject()));
|
||||
}
|
||||
|
||||
if (!request->inputParams)
|
||||
{
|
||||
UCHAR* inMsg = request->getImpure<UCHAR>(request->req_message->impureOffset);
|
||||
UCHAR* inMsg = request->getImpure<UCHAR>(request->req_message->impureOffset);
|
||||
|
||||
request->inputParams = FB_NEW(*request->req_pool) ValuesImpl(
|
||||
*request->req_pool, format, inMsg,
|
||||
statement->procedure->prc_input_fields);
|
||||
}
|
||||
|
||||
if (!request->outputParams)
|
||||
{
|
||||
request->outputParams = FB_NEW(*request->req_pool) ValuesImpl(
|
||||
*request->req_pool, outFormat, outMsg,
|
||||
statement->procedure->prc_output_fields);
|
||||
request->outputParams->setNull();
|
||||
}
|
||||
|
||||
request->resultSet = statement->procedure->getExternal()->open(tdbb,
|
||||
request->inputParams, request->outputParams);
|
||||
request->resultSet = statement->procedure->getExternal()->open(
|
||||
tdbb, inMsg, outMsg);
|
||||
}
|
||||
|
||||
request->req_message = outMsgNode;
|
||||
|
@ -296,8 +296,6 @@ public:
|
||||
dsc* req_domain_validation; // Current VALUE for constraint validation
|
||||
Firebird::Stack<jrd_tra*> req_auto_trans; // Autonomous transactions
|
||||
ExtEngineManager::ResultSet* resultSet; // external procedure result set
|
||||
ValuesImpl* inputParams; // external procedure input values
|
||||
ValuesImpl* outputParams; // external procedure output values
|
||||
SortOwner req_sorts;
|
||||
Firebird::Array<record_param> req_rpb; // record parameter blocks
|
||||
Firebird::Array<UCHAR> impureArea; // impure area
|
||||
|
@ -247,13 +247,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FB_CALL execute(Error* error, ExternalContext* context, Values* params,
|
||||
Value* result)
|
||||
virtual void FB_CALL execute(Error* error, ExternalContext* context, UCHAR* inMsg, UCHAR* outMsg)
|
||||
{
|
||||
ExternalFunction* function = engine->getChild<FunctionNode, ExternalFunction>(
|
||||
children, this, context, registeredFunctions, engine->functions, moduleName);
|
||||
if (function)
|
||||
function->execute(error, context, params, result);
|
||||
function->execute(error, context, inMsg, outMsg);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -274,6 +273,7 @@ class SharedProcedure : public ExternalProcedure
|
||||
public:
|
||||
SharedProcedure(Engine* aEngine, const IRoutineMetadata* aMetadata)
|
||||
: engine(aEngine),
|
||||
metadata(aMetadata),
|
||||
moduleName(*getDefaultMemoryPool()),
|
||||
entryPoint(*getDefaultMemoryPool()),
|
||||
info(*getDefaultMemoryPool()),
|
||||
@ -314,13 +314,13 @@ public:
|
||||
}
|
||||
|
||||
virtual ExternalResultSet* FB_CALL open(Error* error, ExternalContext* context,
|
||||
Values* params, Values* results)
|
||||
UCHAR* inMsg, UCHAR* outMsg)
|
||||
{
|
||||
try
|
||||
{
|
||||
ExternalProcedure* procedure = engine->getChild<ProcedureNode, ExternalProcedure>(
|
||||
children, this, context, registeredProcedures, engine->procedures, moduleName);
|
||||
return procedure ? procedure->open(error, context, params, results) : NULL;
|
||||
return procedure ? procedure->open(error, context, inMsg, outMsg) : NULL;
|
||||
}
|
||||
catch (const ThrowError::Exception& e)
|
||||
{
|
||||
@ -388,12 +388,12 @@ public:
|
||||
}
|
||||
|
||||
virtual void FB_CALL execute(Error* error, ExternalContext* context,
|
||||
ExternalTrigger::Action action, const Values* oldValues, Values* newValues)
|
||||
ExternalTrigger::Action action, UCHAR* oldMsg, UCHAR* newMsg)
|
||||
{
|
||||
ExternalTrigger* trigger = engine->getChild<TriggerNode, ExternalTrigger>(
|
||||
children, this, context, registeredTriggers, engine->triggers, moduleName);
|
||||
if (trigger)
|
||||
trigger->execute(error, context, action, oldValues, newValues);
|
||||
trigger->execute(error, context, action, oldMsg, newMsg);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -130,9 +130,6 @@ public:
|
||||
|
||||
if (next)
|
||||
{
|
||||
// destroy() was not called - BUG in callers code !!!
|
||||
fb_assert_continue(false);
|
||||
|
||||
++this->refCounter; // to be decremented in destroy()
|
||||
++this->refCounter; // to avoid recursion
|
||||
impl->destroy(); // destroy() must call release()
|
||||
|
Loading…
Reference in New Issue
Block a user