From e44446e855a9923e28315ef7acbe62b6e29b83ea Mon Sep 17 00:00:00 2001 From: hvlad Date: Fri, 10 Apr 2020 13:06:04 +0300 Subject: [PATCH] Some additional checks and documentation for new MAKE_DBKEY function. --- .../README.builtin_functions.txt | 65 +++++++++++++++++++ src/jrd/SysFunction.cpp | 35 ++++++---- 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/doc/sql.extensions/README.builtin_functions.txt b/doc/sql.extensions/README.builtin_functions.txt index 42ae1c45ef..cd1c0e9f54 100644 --- a/doc/sql.extensions/README.builtin_functions.txt +++ b/doc/sql.extensions/README.builtin_functions.txt @@ -693,6 +693,71 @@ Example: select lpad(x, 10) from y; +---------- +MAKE_DBKEY +---------- + +Function: + MAKE_DBKEY( relation, recnum [, dpnum [, ppnum]] ) + Creates DBKEY value using relation name or ID, record number, and, optionally, + logical number of data page and pointer page. + +Format: + MAKE_DBKEY( , [, [, ]] ) + +Notes: + 1) If the first argument (relation) is a string expression or literal, then + it's treated as a relation name and the engine searches for the + corresponding relation ID. The search is case-sensitive. + In the case of string literal, relation ID is evaluated at prepare time. + In the case of expression, relation ID is evaluated at execution time. + If the relation couldn't be found, then isc_relnotdef error is raised. + 2) If the first argument (relation) is a numeric expression or literal, then + it's treated as a relation ID and used "as is", without verification + against existing relations. + If the argument value is negative or greater than the maximum allowed + relation ID (65535 currently), then NULL is returned. + 3) Second argument (recnum) represents an absolute record number in relation + (if the next arguments -- dpnum and ppnum -- are missing), or a record + number relative to the first record, specified by the next arguments. + 4) Third argument (dpnum) is a logical number of data page in relation (if + the next argument -- ppnum -- is missing), or number of data page + relative to the first data page addressed by the given ppnum. + 5) Forth argument (ppnum) is a logical number of pointer page in relation. + 6) All numbers are zero-based. + Maximum allowed value for dpnum and ppnum is 2^32 (4294967296). + If dpnum is specified, then recnum could be negative. + If dpnum is missing and recnum is negative then NULL is returned. + If ppnum is specified, then dpnum could be negative. + If ppnum is missing and dpnum is negative then NULL is returned. + 7) If any of specified arguments has NULL value, the result is also NULL. + 8) First argument (relation) is described as INTEGER but could be overriden + by application as VARCHAR or CHAR. + recnum, dpnum and ppnum are described as BIGINT (64-bit signed integer). + +Examples: + + 1) Select record using relation name (note, relation name is in uppercase) + + select * from rdb$relations where rdb$db_key = make_dbkey('RDB$RELATIONS', 0) + + 2) Select record using relation ID + + select * from rdb$relations where rdb$db_key = make_dbkey(6, 0) + + 3) Select all records that physically reside at first data page in relation + + select * from rdb$relations + where rdb$db_key >= make_dbkey(6, 0, 0) + and rdb$db_key < make_dbkey(6, 0, 1) + + 4) Select all records that physically reside at first data page of 6th pointer + page at relation + + select * from SOMETABLE + where rdb$db_key >= make_dbkey('SOMETABLE', 0, 0, 5) + and rdb$db_key < make_dbkey('SOMETABLE', 0, 1, 5) + -------- MAXVALUE -------- diff --git a/src/jrd/SysFunction.cpp b/src/jrd/SysFunction.cpp index 4c4303ba11..fc19f1a72d 100644 --- a/src/jrd/SysFunction.cpp +++ b/src/jrd/SysFunction.cpp @@ -769,10 +769,10 @@ void setParamsMakeDbkey(DataTypeUtilBase*, const SysFunction*, int argsCount, ds args[1]->makeInt64(0); if (argsCount > 2 && args[2]->isUnknown()) - args[2]->makeLong(0); + args[2]->makeInt64(0); if (argsCount > 3 && args[3]->isUnknown()) - args[3]->makeLong(0); + args[3]->makeInt64(0); } @@ -847,14 +847,10 @@ 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); + result->setNullable(true); } + void makeDoubleResult(DataTypeUtilBase*, const SysFunction*, dsc* result, int argsCount, const dsc** args) { @@ -4862,7 +4858,7 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV else { const SLONG value = MOV_get_long(tdbb, argDsc, 0); - if (value > MAX_USHORT) // return NULL if the provided ID is too long + if (value < 0 || value > MAX_USHORT) // return NULL if the provided ID is too long return NULL; relId = (USHORT) value; @@ -4874,7 +4870,7 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV SINT64 recNo = MOV_get_int64(tdbb, argDsc, 0); - ULONG dpNum = MAX_ULONG, ppNum = MAX_ULONG; + SINT64 dpNum = 0, ppNum = 0; if (args.getCount() > 2) { @@ -4882,7 +4878,9 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV if (request->req_flags & req_null) return NULL; - dpNum = MOV_get_long(tdbb, argDsc, 0); + dpNum = MOV_get_int64(tdbb, argDsc, 0); + if (dpNum > MAX_ULONG) + return NULL; } if (args.getCount() > 3) @@ -4891,15 +4889,24 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV if (request->req_flags & req_null) return NULL; - ppNum = MOV_get_long(tdbb, argDsc, 0); + ppNum = MOV_get_int64(tdbb, argDsc, 0); + if (ppNum < 0 || ppNum > MAX_ULONG) + return NULL; } RecordNumber temp; if (args.getCount() == 4) - recNo += ((SINT64) ppNum * dbb->dbb_dp_per_pp + dpNum) * dbb->dbb_max_records; + recNo += (ppNum * dbb->dbb_dp_per_pp + dpNum) * dbb->dbb_max_records; else if (args.getCount() == 3) - recNo += (SINT64) dpNum * dbb->dbb_max_records; + { + if (dpNum < 0) + return NULL; + recNo += dpNum * dbb->dbb_max_records; + } + + if (recNo < 0) + return NULL; temp.setValue(recNo + 1);