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

Feature #6798 - Add built-in functions UNICODE_CHAR and UNICODE_VAL to convert between Unicode code point and character.

This commit is contained in:
Adriano dos Santos Fernandes 2021-05-14 11:19:09 -03:00
parent d0eac02bb9
commit 3b372197e4
4 changed files with 153 additions and 7 deletions

View File

@ -721,22 +721,22 @@ 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.
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
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
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
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.
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.
@ -763,7 +763,7 @@ Examples:
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
4) Select all records that physically reside at first data page of 6th pointer
page at relation
select * from SOMETABLE
@ -1255,6 +1255,41 @@ Example:
3) select trunc(987.65, 1), trunc(987.65, -1) from rdb$database; -- returns 987.60, 980.00
------------
UNICODE_CHAR
------------
Function:
Returns the UNICODE character with the specified code point.
Format:
UNICODE_CHAR( <number> )
Notes:
Argument to UNICODE_CHAR must be a valid UTF-32 code point not in the range of
high/low surrogates (0xD800 to 0xDFFF). Otherwise it throws an error.
Example:
select unicode_char(x) from y;
-----------
UNICODE_VAL
-----------
Function:
Returns the UTF-32 code point of the first character of the specified string.
Format:
UNICODE_VAL( <string> )
Notes:
Returns 0 if the string is empty.
Example:
select unicode_val(x) from y;
------------
UUID_TO_CHAR
------------

View File

@ -507,6 +507,8 @@ static const TOK tokens[] =
{TOK_UNBOUNDED, "UNBOUNDED", false},
{TOK_UNCOMMITTED, "UNCOMMITTED", true},
{TOK_UNDO, "UNDO", true},
{TOK_UNICODE_CHAR, "UNICODE_CHAR", true},
{TOK_UNICODE_VAL, "UNICODE_VAL", true},
{TOK_UNION, "UNION", false},
{TOK_UNIQUE, "UNIQUE", false},
{TOK_UNKNOWN, "UNKNOWN", false},

View File

@ -677,6 +677,11 @@ using namespace Firebird;
%token <metaNamePtr> CLEAR
%token <metaNamePtr> OLDEST
// tokens added for Firebird 5.0
%token <metaNamePtr> UNICODE_CHAR
%token <metaNamePtr> UNICODE_VAL
// precedence declarations for expression evaluation
%left OR
@ -8134,6 +8139,8 @@ system_function_std_syntax
| TAN
| TANH
| TRUNC
| UNICODE_CHAR
| UNICODE_VAL
| UUID_TO_CHAR
| QUANTIZE
| TOTALORDER
@ -9040,6 +9047,8 @@ non_reserved_word
| TOTALORDER
| TRAPS
| ZONE
| UNICODE_CHAR // added in FB 5.0
| UNICODE_VAL
;
%%

View File

@ -237,6 +237,7 @@ void setParamsRsaEncrypt(DataTypeUtilBase*, const SysFunction*, int argsCount, d
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 setParamsUnicodeVal(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
void setParamsUuidToChar(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
// generic make functions
@ -280,6 +281,7 @@ void makeRsaPrivate(DataTypeUtilBase* dataTypeUtil, const SysFunction* function,
void makeRsaPublic(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
void makeRsaSign(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
void makeTrunc(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
void makeUnicodeChar(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
void makeUuid(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
void makeUuidToChar(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
@ -338,6 +340,8 @@ dsc* evlSign(thread_db* tdbb, const SysFunction* function, const NestValueArray&
dsc* evlSqrt(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlSystemPrivilege(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlTrunc(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlUnicodeChar(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlUnicodeVal(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlUuidToChar(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
@ -645,6 +649,13 @@ void setParamsDateDiff(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc
}
void setParamsUnicodeVal(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args)
{
if (argsCount >= 1 && args[0]->isUnknown())
args[0]->makeText(4, CS_UTF8);
}
void setParamVarying(dsc* param, USHORT textType, bool condition)
{
if (!param)
@ -1734,6 +1745,24 @@ void makeTrunc(DataTypeUtilBase*, const SysFunction* function, dsc* result,
}
void makeUnicodeChar(DataTypeUtilBase*, const SysFunction* function, dsc* result,
int argsCount, const dsc** args)
{
fb_assert(argsCount == function->minArgCount);
const dsc* value = args[0];
if (value->isNull())
{
result->makeNullString();
return;
}
result->makeText(4, ttype_utf8);
result->setNullable(value->isNullable());
}
void makeUuid(DataTypeUtilBase*, const SysFunction* function, dsc* result,
int argsCount, const dsc** args)
{
@ -6331,6 +6360,75 @@ dsc* evlSystemPrivilege(thread_db* tdbb, const SysFunction*, const NestValueArra
return &impure->vlu_desc;
}
dsc* evlUnicodeChar(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
impure_value* impure)
{
fb_assert(args.getCount() == 1);
jrd_req* request = tdbb->getRequest();
const dsc* value = EVL_expr(tdbb, request, args[0]);
if (request->req_flags & req_null) // return NULL if value is NULL
return NULL;
const UChar32 code = MOV_get_long(tdbb, value, 0);
if (U8_LENGTH(code) == 0)
status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_malformed_string));
UCHAR buffer[4];
int len = 0;
U8_APPEND_UNSAFE(buffer, len, code);
dsc result;
result.makeText(len, ttype_utf8, buffer);
EVL_make_value(tdbb, &result, impure);
return &impure->vlu_desc;
}
dsc* evlUnicodeVal(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
impure_value* impure)
{
fb_assert(args.getCount() == 1);
jrd_req* request = tdbb->getRequest();
const dsc* value = EVL_expr(tdbb, request, args[0]);
if (request->req_flags & req_null) // return NULL if value is NULL
return NULL;
MoveBuffer buffer;
UCHAR* str;
int len = MOV_make_string2(tdbb, value, CS_UTF8, &str, buffer);
USHORT dst[2];
USHORT errCode = 0;
ULONG errPosition;
ULONG dstLen = UnicodeUtil::utf8ToUtf16(len, str, sizeof(dst), dst, &errCode, &errPosition);
if (errCode != 0 && errCode != CS_TRUNCATION_ERROR)
status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_transliteration_failed));
if (dstLen == 0)
impure->vlu_misc.vlu_long = 0;
else if (dstLen == 2 || !U_IS_SURROGATE(dst[0]))
impure->vlu_misc.vlu_long = dst[0];
else if (dstLen == 4 && U16_IS_LEAD(dst[0]) && U16_IS_TRAIL(dst[1]))
impure->vlu_misc.vlu_long = U16_GET_SUPPLEMENTARY(dst[0], dst[1]);
else
{
fb_assert(false);
impure->vlu_misc.vlu_long = 0;
}
impure->vlu_desc.makeLong(0, &impure->vlu_misc.vlu_long);
return &impure->vlu_desc;
}
} // anonymous namespace
@ -6417,6 +6515,8 @@ const SysFunction SysFunction::functions[] =
{"TANH", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfTanh},
{"TOTALORDER", 2, 2, setParamsDecFloat, makeShortResult, evlCompare, (void*) funTotalOrd},
{"TRUNC", 1, 2, setParamsRoundTrunc, makeTrunc, evlTrunc, NULL},
{"UNICODE_CHAR", 1, 1, setParamsInteger, makeUnicodeChar, evlUnicodeChar, NULL},
{"UNICODE_VAL", 1, 1, setParamsUnicodeVal, makeLongResult, evlUnicodeVal, NULL},
{"UUID_TO_CHAR", 1, 1, setParamsUuidToChar, makeUuidToChar, evlUuidToChar, NULL},
{"", 0, 0, NULL, NULL, NULL, NULL}
};