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

Rework on CORE-3238 - Makes GEN_UUID return a compliant RFC-4122 binary UUID.

Fixed CORE-3887 - CHAR_TO_UUID and UUID_TO_CHAR works different in big/little endian architectures - problem similar to CORE-2898.
This commit is contained in:
asfernandes 2012-07-10 16:00:27 +00:00
parent 007955fa59
commit e6169577fb
6 changed files with 69 additions and 168 deletions

View File

@ -246,36 +246,16 @@ Function:
Format:
CHAR_TO_UUID( <string> )
Notes:
If you have not used this function before, its usage is discouraged. CHAR_TO_UUID2 supersedes it.
Important (for big-endian servers):
It has been discovered that before Firebird 2.5.2, CHAR_TO_UUID and UUID_TO_CHAR works
incorrectly in big-endian servers. In these machines, bytes/characters are swapped and goes in
wrong positions when converting. This bug was fixed in 2.5.2 and 3.0, but that means these
functions now returns different values (for the same input parameter) than before.
Example:
select char_to_uuid('93519227-8D50-4E47-81AA-8F6678C096A1') from rdb$database;
See also: GEN_UUID, CHAR_TO_UUID2, UUID_TO_CHAR and UUID_TO_CHAR2
-------------
CHAR_TO_UUID2
-------------
Function:
Converts the CHAR(32) ASCII representation of an UUID
(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) to the CHAR(16) OCTETS
representation (optimized for storage).
Format:
CHAR_TO_UUID2( <string> )
Notes:
This function supersedes CHAR_TO_UUID. The difference between them is that CHAR_TO_UUID does a
byte-by-byte conversion of the ASCII string to the OCTETS one, while CHAR_TO_UUID2 converts
a RFC-4122 compliant ASCII UUID to a compliant OCTETS string.
Example:
select char_to_uuid2('93519227-8D50-4E47-81AA-8F6678C096A1') from rdb$database;
See also: GEN_UUID, UUID_TO_CHAR2
See also: GEN_UUID and UUID_TO_CHAR
---
@ -431,17 +411,17 @@ Function:
Format:
GEN_UUID()
Notes:
In Firebird 2.5.0 and 2.5.1, GEN_UUID was returning completely random strings. This is not
compliant with the RFC-4122 (UUID specification).
In Firebird 2.5.2 and 3.0 this was fixed. Now GEN_UUID returns a compliant UUID version 4
Important:
Before Firebird 2.5.2, GEN_UUID was returning completely random strings. This is not compliant
with the RFC-4122 (UUID specification).
This was fixed in Firebird 2.5.2 and 3.0. Now GEN_UUID returns a compliant UUID version 4
string, where some bits are reserved and the others are random. The string format of a compliant
UUID is XXXXXXXX-XXXX-4XXX-YXXX-XXXXXXXXXXXX, where 4 is fixed (version) and Y is 8, 9, A or B.
Example:
insert into records (id) value (gen_uuid());
See also: CHAR_TO_UUID, UUID_TO_CHAR, CHAR_TO_UUID2, UUID_TO_CHAR2
See also: CHAR_TO_UUID and UUID_TO_CHAR
----
@ -869,33 +849,13 @@ Function:
Format:
UUID_TO_CHAR( <string> )
Notes:
If you have not used this function before, its usage is discouraged. UUID_TO_CHAR2 supersedes it.
Important (for big-endian servers):
It has been discovered that before Firebird 2.5.2, CHAR_TO_UUID and UUID_TO_CHAR works
incorrectly in big-endian servers. In these machines, bytes/characters are swapped and goes in
wrong positions when converting. This bug was fixed in 2.5.2 and 3.0, but that means these
functions now returns different values (for the same input parameter) than before.
Example:
select uuid_to_char(gen_uuid()) from rdb$database;
See also: GEN_UUID, UUID_TO_CHAR2, CHAR_TO_UUID and CHAR_TO_UUID2
-------------
UUID_TO_CHAR2
-------------
Function:
Converts a CHAR(16) OCTETS UUID (that's returned by GEN_UUID) to the
CHAR(32) ASCII representation (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
Format:
UUID_TO_CHAR2( <string> )
Notes:
This function supersedes UUID_TO_CHAR. The difference between them is that UUID_TO_CHAR does a
byte-by-byte conversion of the OCTETS string to the ASCII one, while UUID_TO_CHAR2 converts
a RFC-4122 compliant OCTETS UUID to a compliant ASCII string. Also, UUID_TO_CHAR returns
upper-cased string and UUID_TO_CHAR2 returns lower-cased string.
Example:
select uuid_to_char2(gen_uuid()) from rdb$database;
See also: GEN_UUID, CHAR_TO_UUID2
See also: GEN_UUID and CHAR_TO_UUID

View File

@ -68,9 +68,7 @@ enum Function
funLPad,
funRPad,
funLnat,
funLog10,
funUuidBroken,
funUuidRfc
funLog10
};
enum TrigonFunction
@ -1433,40 +1431,19 @@ dsc* evlCharToUuid(Jrd::thread_db* tdbb, const SysFunction* function, Jrd::jrd_n
buffer[38] = '\0';
memcpy(buffer + 1, data, GUID_BODY_SIZE);
FB_GUID guid;
USHORT bytes[16];
sscanf(buffer, GUID_NEW_FORMAT,
&bytes[0], &bytes[1], &bytes[2], &bytes[3],
&bytes[4], &bytes[5], &bytes[6], &bytes[7],
&bytes[8], &bytes[9], &bytes[10], &bytes[11],
&bytes[12], &bytes[13], &bytes[14], &bytes[15]);
switch ((Function)(IPTR) function->misc)
{
case funUuidBroken:
StringToGuid(&guid, buffer, false);
break;
case funUuidRfc:
{
USHORT bytes[16];
sscanf(buffer, GUID_NEW_FORMAT_LOWER,
&bytes[0], &bytes[1], &bytes[2], &bytes[3],
&bytes[4], &bytes[5], &bytes[6], &bytes[7],
&bytes[8], &bytes[9], &bytes[10], &bytes[11],
&bytes[12], &bytes[13], &bytes[14], &bytes[15]);
guid.data1 = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
guid.data2 = (bytes[4] << 8) | bytes[5];
guid.data3 = (bytes[6] << 8) | bytes[7];
guid.data4[0] = bytes[8];
guid.data4[1] = bytes[9];
guid.data4[2] = bytes[10];
guid.data4[3] = bytes[11];
guid.data4[4] = bytes[12];
guid.data4[5] = bytes[13];
guid.data4[6] = bytes[14];
guid.data4[7] = bytes[15];
break;
}
}
UCHAR resultData[16];
for (unsigned i = 0; i < 16; ++i)
resultData[i] = (UCHAR) bytes[i];
dsc result;
result.makeText(16, ttype_binary, reinterpret_cast<UCHAR*>(guid.data));
result.makeText(16, ttype_binary, resultData);
EVL_make_value(tdbb, &result, impure);
return &impure->vlu_desc;
@ -1999,8 +1976,26 @@ dsc* evlGenUuid(Jrd::thread_db* tdbb, const SysFunction*, Jrd::jrd_nod* args,
GenerateGuid(&guid);
UCHAR data[16];
data[0] = (guid.data1 >> 24) & 0xFF;
data[1] = (guid.data1 >> 16) & 0xFF;
data[2] = (guid.data1 >> 8) & 0xFF;
data[3] = guid.data1 & 0xFF;
data[4] = (guid.data2 >> 8) & 0xFF;
data[5] = guid.data2 & 0xFF;
data[6] = (guid.data3 >> 8) & 0xFF;
data[7] = guid.data3 & 0xFF;
data[8] = guid.data4[0];
data[9] = guid.data4[1];
data[10] = guid.data4[2];
data[11] = guid.data4[3];
data[12] = guid.data4[4];
data[13] = guid.data4[5];
data[14] = guid.data4[6];
data[15] = guid.data4[7];
dsc result;
result.makeText(16, ttype_binary, reinterpret_cast<UCHAR*>(guid.data));
result.makeText(16, ttype_binary, data);
EVL_make_value(tdbb, &result, impure);
return &impure->vlu_desc;
@ -3319,27 +3314,12 @@ dsc* evlUuidToChar(Jrd::thread_db* tdbb, const SysFunction* function, Jrd::jrd_n
Arg::Str(function->name));
}
const FB_GUID* guid = reinterpret_cast<const FB_GUID*>(data);
char buffer[GUID_BUFF_SIZE];
switch ((Function)(IPTR) function->misc)
{
case funUuidBroken:
GuidToString(buffer, guid, false);
break;
case funUuidRfc:
sprintf(buffer, GUID_NEW_FORMAT_LOWER,
USHORT((guid->data1 >> 24) & 0xFF), USHORT((guid->data1 >> 16) & 0xFF),
USHORT((guid->data1 >> 8) & 0xFF), USHORT(guid->data1 & 0xFF),
USHORT((guid->data2 >> 8) & 0xFF), USHORT(guid->data2 & 0xFF),
USHORT((guid->data3 >> 8) & 0xFF), USHORT(guid->data3 & 0xFF),
USHORT(guid->data4[0]), USHORT(guid->data4[1]),
USHORT(guid->data4[2]), USHORT(guid->data4[3]),
USHORT(guid->data4[4]), USHORT(guid->data4[5]),
USHORT(guid->data4[6]), USHORT(guid->data4[7]));
break;
}
sprintf(buffer, GUID_NEW_FORMAT,
USHORT(data[0]), USHORT(data[1]), USHORT(data[2]), USHORT(data[3]), USHORT(data[4]),
USHORT(data[5]), USHORT(data[6]), USHORT(data[7]), USHORT(data[8]), USHORT(data[9]),
USHORT(data[10]), USHORT(data[11]), USHORT(data[12]), USHORT(data[13]), USHORT(data[14]),
USHORT(data[15]));
dsc result;
result.makeText(GUID_BODY_SIZE, ttype_ascii, reinterpret_cast<UCHAR*>(buffer) + 1);
@ -3374,8 +3354,7 @@ const SysFunction SysFunction::functions[] =
{"BIN_XOR", 2, -1, setParamsInteger, makeBin, evlBin, (void*) funBinXor},
{"CEIL", 1, 1, setParamsDouble, makeCeilFloor, evlCeil, NULL},
{"CEILING", 1, 1, setParamsDouble, makeCeilFloor, evlCeil, NULL},
{"CHAR_TO_UUID", 1, 1, setParamsCharToUuid, makeUuid, evlCharToUuid, (void*) funUuidBroken},
{"CHAR_TO_UUID2", 1, 1, setParamsCharToUuid, makeUuid, evlCharToUuid, (void*) funUuidRfc},
{"CHAR_TO_UUID", 1, 1, setParamsCharToUuid, makeUuid, evlCharToUuid, NULL},
{"COS", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCos},
{"COSH", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCosh},
{"COT", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCot},
@ -3410,8 +3389,7 @@ const SysFunction SysFunction::functions[] =
{"TAN", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfTan},
{"TANH", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfTanh},
{"TRUNC", 1, 2, setParamsRoundTrunc, makeTrunc, evlTrunc, NULL},
{"UUID_TO_CHAR", 1, 1, setParamsUuidToChar, makeUuidToChar, evlUuidToChar, (void*) funUuidBroken},
{"UUID_TO_CHAR2", 1, 1, setParamsUuidToChar, makeUuidToChar, evlUuidToChar, (void*) funUuidRfc},
{"UUID_TO_CHAR", 1, 1, setParamsUuidToChar, makeUuidToChar, evlUuidToChar, NULL},
{"", 0, 0, NULL, NULL, NULL, NULL}
};

View File

@ -39,10 +39,8 @@ const int GUID_BODY_SIZE = 36;
const char* const GUID_LEGACY_FORMAT =
"{%04hX%04hX-%04hX-%04hX-%04hX-%04hX%04hX%04hX}";
const char* const GUID_NEW_FORMAT_UPPER =
const char* const GUID_NEW_FORMAT =
"{%02hX%02hX%02hX%02hX-%02hX%02hX-%02hX%02hX-%02hX%02hX-%02hX%02hX%02hX%02hX%02hX%02hX}";
const char* const GUID_NEW_FORMAT_LOWER =
"{%02hx%02hx%02hx%02hx-%02hx%02hx-%02hx%02hx-%02hx%02hx-%02hx%02hx%02hx%02hx%02hx%02hx}";
struct FB_GUID
{
@ -63,56 +61,21 @@ struct FB_GUID
void GenerateRandomBytes(void* buffer, size_t size);
void GenerateGuid(FB_GUID* guid);
// These functions receive buffers of at least GUID_BUFF_SIZE length
// These functions receive buffers of at least GUID_BUFF_SIZE length.
// Warning: they are BROKEN in little-endian and should not be used on new code.
inline void GuidToString(char* buffer, const FB_GUID* guid, bool legacy)
inline void GuidToString(char* buffer, const FB_GUID* guid)
{
if (legacy) // nbackup guid
{
sprintf(buffer, GUID_LEGACY_FORMAT,
guid->data[0], guid->data[1], guid->data[2], guid->data[3],
guid->data[4], guid->data[5], guid->data[6], guid->data[7]);
}
else
{
sprintf(buffer, GUID_NEW_FORMAT_UPPER,
USHORT(guid->data[0] & 0xFF), USHORT(guid->data[0] >> 8),
USHORT(guid->data[1] & 0xFF), USHORT(guid->data[1] >> 8),
USHORT(guid->data[2] & 0xFF), USHORT(guid->data[2] >> 8),
USHORT(guid->data[3] & 0xFF), USHORT(guid->data[3] >> 8),
USHORT(guid->data[4] & 0xFF), USHORT(guid->data[4] >> 8),
USHORT(guid->data[5] & 0xFF), USHORT(guid->data[5] >> 8),
USHORT(guid->data[6] & 0xFF), USHORT(guid->data[6] >> 8),
USHORT(guid->data[7] & 0xFF), USHORT(guid->data[7] >> 8));
}
sprintf(buffer, GUID_LEGACY_FORMAT,
guid->data[0], guid->data[1], guid->data[2], guid->data[3],
guid->data[4], guid->data[5], guid->data[6], guid->data[7]);
}
inline void StringToGuid(FB_GUID* guid, const char* buffer, bool legacy)
inline void StringToGuid(FB_GUID* guid, const char* buffer)
{
if (legacy) // nbackup guid
{
sscanf(buffer, GUID_LEGACY_FORMAT,
&guid->data[0], &guid->data[1], &guid->data[2], &guid->data[3],
&guid->data[4], &guid->data[5], &guid->data[6], &guid->data[7]);
}
else
{
USHORT bytes[16];
sscanf(buffer, GUID_NEW_FORMAT_UPPER,
&bytes[0], &bytes[1], &bytes[2], &bytes[3],
&bytes[4], &bytes[5], &bytes[6], &bytes[7],
&bytes[8], &bytes[9], &bytes[10], &bytes[11],
&bytes[12], &bytes[13], &bytes[14], &bytes[15]);
guid->data[0] = bytes[0] | (bytes[1] << 8);
guid->data[1] = bytes[2] | (bytes[3] << 8);
guid->data[2] = bytes[4] | (bytes[5] << 8);
guid->data[3] = bytes[6] | (bytes[7] << 8);
guid->data[4] = bytes[8] | (bytes[9] << 8);
guid->data[5] = bytes[10] | (bytes[11] << 8);
guid->data[6] = bytes[12] | (bytes[13] << 8);
guid->data[7] = bytes[14] | (bytes[15] << 8);
}
sscanf(buffer, GUID_LEGACY_FORMAT,
&guid->data[0], &guid->data[1], &guid->data[2], &guid->data[3],
&guid->data[4], &guid->data[5], &guid->data[6], &guid->data[7]);
}
#endif

View File

@ -107,7 +107,7 @@ void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
GenerateGuid(&guid);
char* buff = session.ses_logfile.getBuffer(GUID_BUFF_SIZE);
GuidToString(buff, &guid, true);
GuidToString(buff, &guid);
session.ses_logfile.insert(0, "fb_trace.");
}

View File

@ -251,7 +251,7 @@ void PPG_print_header(const header_page* header, SLONG page,
case HDR_backup_guid:
{
char buff[GUID_BUFF_SIZE];
GuidToString(buff, reinterpret_cast<const FB_GUID*>(p + 2), true);
GuidToString(buff, reinterpret_cast<const FB_GUID*>(p + 2));
uSvc->printf(false, "\tDatabase backup GUID:\t%s\n", buff);
break;
}

View File

@ -890,7 +890,7 @@ void NBackup::backup_database(int level, const PathName& fname)
bh.version = 1;
bh.level = level;
bh.backup_guid = backup_guid;
StringToGuid(&bh.prev_guid, prev_guid, true);
StringToGuid(&bh.prev_guid, prev_guid);
bh.page_size = header->hdr_page_size;
bh.backup_scn = backup_scn;
bh.prev_scn = prev_scn;
@ -990,7 +990,7 @@ void NBackup::backup_database(int level, const PathName& fname)
in_sqlda->sqlvar[0].sqldata = (char*)&level;
in_sqlda->sqlvar[0].sqlind = &null_flag;
char temp[GUID_BUFF_SIZE];
GuidToString(temp, &backup_guid, true);
GuidToString(temp, &backup_guid);
in_sqlda->sqlvar[1].sqldata = temp;
in_sqlda->sqlvar[1].sqlind = &null_flag;
in_sqlda->sqlvar[2].sqldata = (char*)&backup_scn;