8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +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

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