8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 16:43:03 +01:00

Some additional checks and documentation for new MAKE_DBKEY function.

This commit is contained in:
hvlad 2020-04-10 13:06:04 +03:00
parent 92d01afe95
commit e44446e855
2 changed files with 86 additions and 14 deletions

View File

@ -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( <value>, <number> [, <number> [, <number>]] )
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
--------

View File

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