8
0
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:
asfernandes 2011-06-01 01:44:54 +00:00
parent ebd923423b
commit 7ad98cd292
24 changed files with 923 additions and 1929 deletions

View File

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

View File

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

View File

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

View File

@ -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"
>

View File

@ -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"
>

View File

@ -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)

View File

@ -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
{

View File

@ -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;

View File

@ -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;)
{

View File

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

View File

@ -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)

View File

@ -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;
};

View File

@ -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, &params, &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;

View File

@ -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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"

View File

@ -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;

View File

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

View File

@ -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:

View File

@ -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()