8
0
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:
Dmitry Yemanov 2020-04-07 14:39:19 +03:00
parent 53faf9e514
commit 2c436ff67d
7 changed files with 197 additions and 32 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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