mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 10:00:38 +01:00
Added system function to compose a DBKEY. Committed on behalf of Vlad Khorsun.
This commit is contained in:
parent
53faf9e514
commit
2c436ff67d
@ -316,6 +316,14 @@ typedef struct dsc
|
||||
dsc_address = (UCHAR*) address;
|
||||
}
|
||||
|
||||
void makeDbkey(void* address = NULL)
|
||||
{
|
||||
clear();
|
||||
dsc_dtype = dtype_dbkey;
|
||||
dsc_length = sizeof(ISC_QUAD);
|
||||
dsc_address = (UCHAR*) address;
|
||||
}
|
||||
|
||||
void makeDouble(double* address = NULL)
|
||||
{
|
||||
clear();
|
||||
|
@ -290,6 +290,7 @@ static const TOK tokens[] =
|
||||
{TOK_LOWER, "LOWER", false},
|
||||
{TOK_LPAD, "LPAD", true},
|
||||
{TOK_LPARAM, "LPARAM", true},
|
||||
{TOK_MAKE_DBKEY, "MAKE_DBKEY", true},
|
||||
{TOK_MANUAL, "MANUAL", true},
|
||||
{TOK_MAPPING, "MAPPING", true},
|
||||
{TOK_MATCHED, "MATCHED", true},
|
||||
|
@ -12162,28 +12162,54 @@ ValueExprNode* SysFuncCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
|
||||
node->function = SysFunction::lookup(name);
|
||||
|
||||
if (node->function && node->function->setParamsFunc)
|
||||
if (node->function)
|
||||
{
|
||||
ValueListNode* inList = node->args;
|
||||
Array<dsc*> argsArray;
|
||||
|
||||
for (unsigned int i = 0; i < inList->items.getCount(); ++i)
|
||||
if (name == "MAKE_DBKEY")
|
||||
{
|
||||
ValueExprNode* p = inList->items[i];
|
||||
DsqlDescMaker::fromNode(dsqlScratch, &p->nodDesc, p);
|
||||
argsArray.add(&p->nodDesc);
|
||||
// Special handling for system function MAKE_DBKEY:
|
||||
// convert constant relation name into ID at the parsing time
|
||||
|
||||
auto literal = nodeAs<LiteralNode>(node->args->items[0]);
|
||||
|
||||
if (literal && literal->litDesc.isText())
|
||||
{
|
||||
const MetaName relName = literal->getText();
|
||||
|
||||
const dsql_rel* const relation =
|
||||
METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, relName);
|
||||
|
||||
if (!relation)
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
||||
Arg::Gds(isc_dsql_command_err) <<
|
||||
Arg::Gds(isc_dsql_table_not_found) << relName);
|
||||
}
|
||||
|
||||
node->args->items[0] = MAKE_const_slong(relation->rel_id);
|
||||
}
|
||||
}
|
||||
|
||||
DSqlDataTypeUtil dataTypeUtil(dsqlScratch);
|
||||
node->function->setParamsFunc(&dataTypeUtil, node->function,
|
||||
argsArray.getCount(), argsArray.begin());
|
||||
|
||||
for (unsigned int i = 0; i < inList->items.getCount(); ++i)
|
||||
if (node->function->setParamsFunc)
|
||||
{
|
||||
ValueExprNode* p = inList->items[i];
|
||||
PASS1_set_parameter_type(dsqlScratch, p,
|
||||
[&] (dsc* desc) { *desc = p->nodDesc; },
|
||||
false);
|
||||
Array<dsc*> argsArray;
|
||||
|
||||
for (auto& item : node->args->items)
|
||||
{
|
||||
DsqlDescMaker::fromNode(dsqlScratch, &item->nodDesc, item);
|
||||
argsArray.add(&item->nodDesc);
|
||||
}
|
||||
|
||||
DSqlDataTypeUtil dataTypeUtil(dsqlScratch);
|
||||
node->function->setParamsFunc(&dataTypeUtil, node->function,
|
||||
argsArray.getCount(), argsArray.begin());
|
||||
|
||||
for (auto& item : node->args->items)
|
||||
{
|
||||
PASS1_set_parameter_type(dsqlScratch, item,
|
||||
[&] (dsc* desc) { *desc = item->nodDesc; },
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -923,6 +923,12 @@ public:
|
||||
return *reinterpret_cast<SLONG*>(litDesc.dsc_address);
|
||||
}
|
||||
|
||||
const char* getText() const
|
||||
{
|
||||
fb_assert(litDesc.dsc_dtype == dtype_text);
|
||||
return reinterpret_cast<const char*>(litDesc.dsc_address);
|
||||
}
|
||||
|
||||
void fixMinSInt64(MemoryPool& pool);
|
||||
|
||||
public:
|
||||
|
@ -622,6 +622,7 @@ using namespace Firebird;
|
||||
%token <metaNamePtr> LOCALTIME
|
||||
%token <metaNamePtr> LOCALTIMESTAMP
|
||||
%token <metaNamePtr> LPARAM
|
||||
%token <metaNamePtr> MAKE_DBKEY
|
||||
%token <metaNamePtr> MESSAGE
|
||||
%token <metaNamePtr> MODE
|
||||
%token <metaNamePtr> NATIVE
|
||||
@ -8000,6 +8001,7 @@ system_function_std_syntax
|
||||
| LOG
|
||||
| LOG10
|
||||
| LPAD
|
||||
| MAKE_DBKEY
|
||||
| MAXVALUE
|
||||
| MINVALUE
|
||||
| MOD
|
||||
@ -8889,6 +8891,7 @@ non_reserved_word
|
||||
| LEGACY
|
||||
| LIFETIME
|
||||
| LPARAM
|
||||
| MAKE_DBKEY
|
||||
| MESSAGE
|
||||
| MODE
|
||||
| NATIVE
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "../common/cvt.h"
|
||||
#include "../jrd/evl_proto.h"
|
||||
#include "../jrd/intl_proto.h"
|
||||
#include "../jrd/met_proto.h"
|
||||
#include "../jrd/mov_proto.h"
|
||||
#include "../jrd/pag_proto.h"
|
||||
#include "../jrd/tra_proto.h"
|
||||
@ -194,21 +195,23 @@ void setParamsCharToUuid(DataTypeUtilBase* dataTypeUtil, const SysFunction* func
|
||||
void setParamsDateAdd(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsDateDiff(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsEncrypt(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args);
|
||||
void setParamsFirstLastDay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsGetSetContext(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsMakeDbkey(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsOverlay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsPosition(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsRoundTrunc(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsRsaEncrypt(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args);
|
||||
void setParamsRsaPublic(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args);
|
||||
void setParamsRsaSign(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args);
|
||||
void setParamsRsaVerify(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args);
|
||||
void setParamsFirstLastDay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsGetSetContext(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsOverlay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsPosition(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsRoundTrunc(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
void setParamsUuidToChar(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
|
||||
|
||||
// generic make functions
|
||||
void makeDoubleResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeDbkeyResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeDblDecResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeDecFloatResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeDoubleResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeFromListResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeInt64Result(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeLongResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
@ -288,6 +291,7 @@ dsc* evlHash(thread_db* tdbb, const SysFunction* function, const NestValueArray&
|
||||
dsc* evlLeft(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
|
||||
dsc* evlLnLog10(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
|
||||
dsc* evlLog(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
|
||||
dsc* evlMakeDbkey(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, Jrd::impure_value* impure);
|
||||
dsc* evlMaxMinValue(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
|
||||
dsc* evlMod(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
|
||||
dsc* evlOverlay(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
|
||||
@ -754,6 +758,24 @@ void setParamsGetSetContext(DataTypeUtilBase*, const SysFunction*, int argsCount
|
||||
}
|
||||
|
||||
|
||||
void setParamsMakeDbkey(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args)
|
||||
{
|
||||
// MAKE_DBKEY ( REL_NAME | REL_ID, RECNUM [, DPNUM [, PPNUM] ] )
|
||||
|
||||
if (args[0]->isUnknown())
|
||||
args[0]->makeLong(0);
|
||||
|
||||
if (args[1]->isUnknown())
|
||||
args[1]->makeInt64(0);
|
||||
|
||||
if (argsCount > 2 && args[2]->isUnknown())
|
||||
args[2]->makeLong(0);
|
||||
|
||||
if (argsCount > 3 && args[3]->isUnknown())
|
||||
args[3]->makeLong(0);
|
||||
}
|
||||
|
||||
|
||||
void setParamsOverlay(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args)
|
||||
{
|
||||
if (argsCount >= 3)
|
||||
@ -821,6 +843,18 @@ void setParamsUuidToChar(DataTypeUtilBase*, const SysFunction*, int argsCount, d
|
||||
}
|
||||
|
||||
|
||||
void makeDbkeyResult(DataTypeUtilBase*, const SysFunction*, dsc* result,
|
||||
int argsCount, const dsc** args)
|
||||
{
|
||||
result->makeText(8, ttype_binary);
|
||||
|
||||
bool isNullable;
|
||||
if (initResult(result, argsCount, args, &isNullable))
|
||||
return;
|
||||
|
||||
result->setNullable(isNullable);
|
||||
}
|
||||
|
||||
void makeDoubleResult(DataTypeUtilBase*, const SysFunction*, dsc* result,
|
||||
int argsCount, const dsc** args)
|
||||
{
|
||||
@ -4799,6 +4833,95 @@ dsc* evlNormDec(thread_db* tdbb, const SysFunction* function, const NestValueArr
|
||||
}
|
||||
|
||||
|
||||
dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestValueArray& args, Jrd::impure_value* impure)
|
||||
{
|
||||
// MAKE_DBKEY ( REL_NAME | REL_ID, RECNUM [, DPNUM [, PPNUM] ] )
|
||||
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
jrd_req* const request = tdbb->getRequest();
|
||||
|
||||
fb_assert(args.getCount() >= 2 && args.getCount() <= 4);
|
||||
|
||||
dsc* argDsc = EVL_expr(tdbb, request, args[0]);
|
||||
if (request->req_flags & req_null) // return NULL if relation is NULL
|
||||
return NULL;
|
||||
|
||||
USHORT relId;
|
||||
|
||||
if (argDsc->isText())
|
||||
{
|
||||
MetaName relName;
|
||||
MOV_get_metaname(tdbb, argDsc, relName);
|
||||
|
||||
const jrd_rel* const relation = MET_lookup_relation(tdbb, relName);
|
||||
if (!relation)
|
||||
(Arg::Gds(isc_relnotdef) << Arg::Str(relName)).raise();
|
||||
|
||||
relId = relation->rel_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
const SLONG value = MOV_get_long(tdbb, argDsc, 0);
|
||||
if (value > MAX_USHORT) // return NULL if the provided ID is too long
|
||||
return NULL;
|
||||
|
||||
relId = (USHORT) value;
|
||||
}
|
||||
|
||||
argDsc = EVL_expr(tdbb, request, args[1]);
|
||||
if (request->req_flags & req_null)
|
||||
return NULL;
|
||||
|
||||
SINT64 recNo = MOV_get_int64(tdbb, argDsc, 0);
|
||||
|
||||
ULONG dpNum = MAX_ULONG, ppNum = MAX_ULONG;
|
||||
|
||||
if (args.getCount() > 2)
|
||||
{
|
||||
argDsc = EVL_expr(tdbb, request, args[2]);
|
||||
if (request->req_flags & req_null)
|
||||
return NULL;
|
||||
|
||||
dpNum = MOV_get_long(tdbb, argDsc, 0);
|
||||
}
|
||||
|
||||
if (args.getCount() > 3)
|
||||
{
|
||||
argDsc = EVL_expr(tdbb, request, args[3]);
|
||||
if (request->req_flags & req_null)
|
||||
return NULL;
|
||||
|
||||
ppNum = MOV_get_long(tdbb, argDsc, 0);
|
||||
}
|
||||
|
||||
RecordNumber temp;
|
||||
|
||||
if (args.getCount() == 4)
|
||||
recNo += ((SINT64) ppNum * dbb->dbb_dp_per_pp + dpNum) * dbb->dbb_max_records;
|
||||
else if (args.getCount() == 3)
|
||||
recNo += (SINT64) dpNum * dbb->dbb_max_records;
|
||||
|
||||
temp.setValue(recNo + 1);
|
||||
|
||||
RecordNumber::Packed dbkey;
|
||||
memset(&dbkey, 0, sizeof(dbkey));
|
||||
temp.bid_encode(&dbkey);
|
||||
dbkey.bid_relation_id = relId;
|
||||
|
||||
dsc dscKey;
|
||||
dscKey.makeDbkey(&dbkey);
|
||||
|
||||
UCHAR buffer[sizeof(dbkey)];
|
||||
dsc result;
|
||||
result.makeText(sizeof(dbkey), ttype_binary, buffer);
|
||||
|
||||
MOV_move(tdbb, &dscKey, &result);
|
||||
EVL_make_value(tdbb, &result, impure);
|
||||
|
||||
return &impure->vlu_desc;
|
||||
}
|
||||
|
||||
|
||||
dsc* evlMaxMinValue(thread_db* tdbb, const SysFunction* function, const NestValueArray& args,
|
||||
impure_value*)
|
||||
{
|
||||
@ -6102,6 +6225,7 @@ const SysFunction SysFunction::functions[] =
|
||||
{"LOG", 2, 2, setParamsDblDec, makeDblDecResult, evlLog, NULL},
|
||||
{"LOG10", 1, 1, setParamsDblDec, makeDblDecResult, evlLnLog10, (void*) funLog10},
|
||||
{"LPAD", 2, 3, setParamsSecondInteger, makePad, evlPad, (void*) funLPad},
|
||||
{"MAKE_DBKEY", 2, 4, setParamsMakeDbkey, makeDbkeyResult, evlMakeDbkey, NULL},
|
||||
{"MAXVALUE", 1, -1, setParamsFromList, makeFromListResult, evlMaxMinValue, (void*) funMaxValue},
|
||||
{"MINVALUE", 1, -1, setParamsFromList, makeFromListResult, evlMaxMinValue, (void*) funMinValue},
|
||||
{"MOD", 2, 2, setParamsFromList, makeMod, evlMod, NULL},
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include "firebird.h"
|
||||
#include "../common/gdsassert.h"
|
||||
#include "../common/classes/VaryStr.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/val.h"
|
||||
#include "../jrd/intl.h"
|
||||
@ -171,16 +172,12 @@ void MOV_get_metaname(Jrd::thread_db* tdbb, const dsc* desc, MetaName& name)
|
||||
* to the user-supplied object.
|
||||
*
|
||||
**************************************/
|
||||
USHORT ttype;
|
||||
UCHAR* ptr = NULL;
|
||||
|
||||
const USHORT length = CVT_get_string_ptr(desc, &ttype, &ptr, NULL, 0, tdbb->getAttachment()->att_dec_status);
|
||||
|
||||
fb_assert(ptr);
|
||||
fb_assert(length <= MAX_SQL_IDENTIFIER_LEN);
|
||||
fb_assert(ttype == ttype_ascii || ttype == ttype_metadata);
|
||||
|
||||
name.assign(reinterpret_cast<char*>(ptr), length);
|
||||
VaryStr<MAX_SQL_IDENTIFIER_SIZE> temp;
|
||||
const char* str = NULL;
|
||||
const auto len = MOV_make_string(tdbb, desc, ttype_metadata, &str,
|
||||
&temp, MAX_SQL_IDENTIFIER_SIZE);
|
||||
name.assign(str, len);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user