mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
Add an experimental set of UUID processing functions as the uuid.c
extension in ext/misc/uuid.c. FossilOrigin-Name: 1a6e009372cf9571e540812c8607e95a86740112a1091f03e3f632339eccb629
This commit is contained in:
231
ext/misc/uuid.c
Normal file
231
ext/misc/uuid.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
** 2019-10-23
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements functions that handling RFC-4122 UUIDs
|
||||
** Three SQL functions are implemented:
|
||||
**
|
||||
** uuid() - generate a version 4 UUID as a string
|
||||
** uuid_str(X) - convert a UUID X into a well-formed UUID string
|
||||
** uuid_blob(X) - convert a UUID X into a 16-byte blob
|
||||
**
|
||||
** The output from uuid() and uuid_str(X) are always well-formed RFC-4122
|
||||
** UUID strings in this format:
|
||||
**
|
||||
** xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
|
||||
**
|
||||
** All of the 'x', 'M', and 'N' values are lower-case hexadecimal digits.
|
||||
** The M digit indicates the "version". For uuid()-generated UUIDs, the
|
||||
** version is always "4" (a random UUID). The upper three bits of N digit
|
||||
** are the "variant". This library only supports variant 1 (indicated
|
||||
** by values of N between '8' and 'b') as those are overwhelming the most
|
||||
** common. Other variants are for legacy compatibility only.
|
||||
**
|
||||
** The output of uuid_blob(X) is always a 16-byte blob. The UUID input
|
||||
** string is converted in network byte order (big-endian) in accordance
|
||||
** with RFC-4122 specifications for variant-1 UUIDs. Note that network
|
||||
** byte order is *always* used, even if the input self-identifies as a
|
||||
** variant-2 UUID.
|
||||
**
|
||||
** The input X to the uuid_str() and uuid_blob() functions can be either
|
||||
** a string or a BLOB. If it is a BLOB it must be exactly 16 bytes in
|
||||
** length or else a NULL is returned. If the input is a string it must
|
||||
** consist of 32 hexadecimal digits, upper or lower case, optionally
|
||||
** surrounded by {...} and with optional "-" characters interposed in the
|
||||
** middle. The flexibility of input is inspired by the PostgreSQL
|
||||
** implementation of UUID functions that accept in all of the following
|
||||
** formats:
|
||||
**
|
||||
** A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11
|
||||
** {a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}
|
||||
** a0eebc999c0b4ef8bb6d6bb9bd380a11
|
||||
** a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
|
||||
** {a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}
|
||||
**
|
||||
** If any of the above inputs are passed into uuid_str(), the output will
|
||||
** always be in the canonical RFC-4122 format:
|
||||
**
|
||||
** a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
|
||||
**
|
||||
** If the X input string has too few or too many digits or contains
|
||||
** stray characters other than {, }, or -, then NULL is returned.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if !defined(SQLITE_ASCII) && !defined(SQLITE_EBCDIC)
|
||||
# define SQLITE_ASCII 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Translate a single byte of Hex into an integer.
|
||||
** This routine only works if h really is a valid hexadecimal
|
||||
** character: 0..9a..fA..F
|
||||
*/
|
||||
static unsigned char sqlite3UuidHexToInt(int h){
|
||||
assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
|
||||
#ifdef SQLITE_ASCII
|
||||
h += 9*(1&(h>>6));
|
||||
#endif
|
||||
#ifdef SQLITE_EBCDIC
|
||||
h += 9*(1&~(h>>4));
|
||||
#endif
|
||||
return (unsigned char)(h & 0xf);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a 16-byte BLOB into a well-formed RFC-4122 UUID. The output
|
||||
** buffer zStr should be at least 37 bytes in length. The output will
|
||||
** be zero-terminated.
|
||||
*/
|
||||
static void sqlite3UuidBlobToStr(
|
||||
const unsigned char *aBlob, /* Input blob */
|
||||
unsigned char *zStr /* Write the answer here */
|
||||
){
|
||||
static const char zDigits[] = "0123456789abcdef";
|
||||
int i, k;
|
||||
unsigned char x;
|
||||
k = 0;
|
||||
for(i=0, k=0x550; i<16; i++, k=k>>1){
|
||||
if( k&1 ){
|
||||
zStr[0] = '-';
|
||||
zStr++;
|
||||
}
|
||||
x = aBlob[i];
|
||||
zStr[0] = zDigits[x>>4];
|
||||
zStr[1] = zDigits[x&0xf];
|
||||
zStr += 2;
|
||||
}
|
||||
*zStr = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to parse a zero-terminated input string zStr into a binary
|
||||
** UUID. Return 0 on success, or non-zero if the input string is not
|
||||
** parsable.
|
||||
*/
|
||||
static int sqlite3UuidStrToBlob(
|
||||
const unsigned char *zStr, /* Input string */
|
||||
unsigned char *aBlob /* Write results here */
|
||||
){
|
||||
int i;
|
||||
if( zStr[0]=='{' ) zStr++;
|
||||
for(i=0; i<16; i++){
|
||||
if( zStr[0]=='-' ) zStr++;
|
||||
if( isxdigit(zStr[0]) && isxdigit(zStr[1]) ){
|
||||
aBlob[i] = (sqlite3UuidHexToInt(zStr[0])<<4)
|
||||
+ sqlite3UuidHexToInt(zStr[1]);
|
||||
zStr += 2;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( zStr[0]=='}' ) zStr++;
|
||||
return zStr[0]!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Render sqlite3_value pIn as a 16-byte UUID blob. Return a pointer
|
||||
** to the blob, or NULL if the input is not well-formed.
|
||||
*/
|
||||
static const unsigned char *sqlite3UuidInputToBlob(
|
||||
sqlite3_value *pIn, /* Input text */
|
||||
unsigned char *pBuf /* output buffer */
|
||||
){
|
||||
switch( sqlite3_value_type(pIn) ){
|
||||
case SQLITE_TEXT: {
|
||||
const unsigned char *z = sqlite3_value_text(pIn);
|
||||
if( sqlite3UuidStrToBlob(z, pBuf) ) return 0;
|
||||
return pBuf;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n = sqlite3_value_bytes(pIn);
|
||||
return n==16 ? sqlite3_value_blob(pIn) : 0;
|
||||
}
|
||||
default: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Implementation of uuid() */
|
||||
static void sqlite3UuidFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned char aBlob[16];
|
||||
unsigned char zStr[37];
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
sqlite3_randomness(16, aBlob);
|
||||
aBlob[6] = (aBlob[6]&0x0f) + 0x40;
|
||||
aBlob[8] = (aBlob[8]&0x3f) + 0x80;
|
||||
sqlite3UuidBlobToStr(aBlob, zStr);
|
||||
sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/* Implementation of uuid_str() */
|
||||
static void sqlite3UuidStrFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned char aBlob[16];
|
||||
unsigned char zStr[37];
|
||||
const unsigned char *pBlob;
|
||||
(void)argc;
|
||||
pBlob = sqlite3UuidInputToBlob(argv[0], aBlob);
|
||||
if( pBlob==0 ) return;
|
||||
sqlite3UuidBlobToStr(pBlob, zStr);
|
||||
sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/* Implementation of uuid_blob() */
|
||||
static void sqlite3UuidBlobFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned char aBlob[16];
|
||||
const unsigned char *pBlob;
|
||||
(void)argc;
|
||||
pBlob = sqlite3UuidInputToBlob(argv[0], aBlob);
|
||||
if( pBlob==0 ) return;
|
||||
sqlite3_result_blob(context, pBlob, 16, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_uuid_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "uuid", 0, SQLITE_UTF8, 0,
|
||||
sqlite3UuidFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "uuid_str", 1, SQLITE_UTF8, 0,
|
||||
sqlite3UuidStrFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "uuid_blob", 1, SQLITE_UTF8, 0,
|
||||
sqlite3UuidBlobFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
11
manifest
11
manifest
@@ -1,5 +1,5 @@
|
||||
C When\sa\svector\scomparison\sappears\sin\sthe\sWHERE\sclause\sand\sthe\sconstraint\sside\nhas\sa\sCOLLATE\sclause\son\sthe\sfirst\sterm\sof\sthe\svector,\sbe\ssure\sto\shonor\sthat\nCOLLATE\sclause.\s\sTicket\s[135c9da7513e5a97].
|
||||
D 2019-10-23T18:09:39.550
|
||||
C Add\san\sexperimental\sset\sof\sUUID\sprocessing\sfunctions\sas\sthe\suuid.c\nextension\sin\sext/misc/uuid.c.
|
||||
D 2019-10-23T21:00:40.803
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -318,6 +318,7 @@ F ext/misc/stmt.c 8a8dc4675042e4551e4afe99b8d0cc7a4a2fc1a8dacc0a9ce1b1bbff145da9
|
||||
F ext/misc/templatevtab.c 8a16a91a5ceaccfcbd6aaaa56d46828806e460dd194965b3f77bf38f14b942c4
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/unionvtab.c 36237f0607ca954ac13a4a0e2d2ac40c33bc6e032a5f55f431713061ef1625f9
|
||||
F ext/misc/uuid.c db4db81e8c6a92ad6176ebd9f81dcb6870e331e1a286d0452f4319e3ba3df812
|
||||
F ext/misc/vfslog.c 3b25c2f56ba60788db247287be6ab024b53c4afffd412b4876db563389be0d35
|
||||
F ext/misc/vfsstat.c 77b5b4235c9f7f11eddf82487c0a422944ac2f132dafd5af3be7a68a057b1cdb
|
||||
F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae
|
||||
@@ -1847,7 +1848,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 5c118617cf08e17a6edfdfba86e3fc49132a780990b68b52724c2aaeac85f506
|
||||
R 24923192bf7ab8d42b7ba3bf0a0f6b7d
|
||||
P 978b2d20cf95d0b7143e3104ce1e9d5c85002867b554dc6b21deb528b730bbc7
|
||||
R 64938473a0a5ad3e464c05ab968a1d3f
|
||||
U drh
|
||||
Z 19f14a6ea97ac0c0f4e66fe45a2ec552
|
||||
Z 064b470a12983289ba0d29967199891d
|
||||
|
||||
@@ -1 +1 @@
|
||||
978b2d20cf95d0b7143e3104ce1e9d5c85002867b554dc6b21deb528b730bbc7
|
||||
1a6e009372cf9571e540812c8607e95a86740112a1091f03e3f632339eccb629
|
||||
Reference in New Issue
Block a user