1 /* 2 ** 2019-10-23 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ****************************************************************************** 12 ** 13 ** This SQLite extension implements functions that handling RFC-4122 UUIDs 14 ** Three SQL functions are implemented: 15 ** 16 ** uuid() - generate a version 4 UUID as a string 17 ** uuid_str(X) - convert a UUID X into a well-formed UUID string 18 ** uuid_blob(X) - convert a UUID X into a 16-byte blob 19 ** 20 ** The output from uuid() and uuid_str(X) are always well-formed RFC-4122 21 ** UUID strings in this format: 22 ** 23 ** xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx 24 ** 25 ** All of the 'x', 'M', and 'N' values are lower-case hexadecimal digits. 26 ** The M digit indicates the "version". For uuid()-generated UUIDs, the 27 ** version is always "4" (a random UUID). The upper three bits of N digit 28 ** are the "variant". This library only supports variant 1 (indicated 29 ** by values of N between '8' and 'b') as those are overwhelming the most 30 ** common. Other variants are for legacy compatibility only. 31 ** 32 ** The output of uuid_blob(X) is always a 16-byte blob. The UUID input 33 ** string is converted in network byte order (big-endian) in accordance 34 ** with RFC-4122 specifications for variant-1 UUIDs. Note that network 35 ** byte order is *always* used, even if the input self-identifies as a 36 ** variant-2 UUID. 37 ** 38 ** The input X to the uuid_str() and uuid_blob() functions can be either 39 ** a string or a BLOB. If it is a BLOB it must be exactly 16 bytes in 40 ** length or else a NULL is returned. If the input is a string it must 41 ** consist of 32 hexadecimal digits, upper or lower case, optionally 42 ** surrounded by {...} and with optional "-" characters interposed in the 43 ** middle. The flexibility of input is inspired by the PostgreSQL 44 ** implementation of UUID functions that accept in all of the following 45 ** formats: 46 ** 47 ** A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11 48 ** {a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11} 49 ** a0eebc999c0b4ef8bb6d6bb9bd380a11 50 ** a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11 51 ** {a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11} 52 ** 53 ** If any of the above inputs are passed into uuid_str(), the output will 54 ** always be in the canonical RFC-4122 format: 55 ** 56 ** a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 57 ** 58 ** If the X input string has too few or too many digits or contains 59 ** stray characters other than {, }, or -, then NULL is returned. 60 */ 61 #include "sqlite3ext.h" 62 SQLITE_EXTENSION_INIT1 63 #include <assert.h> 64 #include <string.h> 65 #include <ctype.h> 66 67 #if !defined(SQLITE_ASCII) && !defined(SQLITE_EBCDIC) 68 # define SQLITE_ASCII 1 69 #endif 70 71 /* 72 ** Translate a single byte of Hex into an integer. 73 ** This routine only works if h really is a valid hexadecimal 74 ** character: 0..9a..fA..F 75 */ 76 static unsigned char sqlite3UuidHexToInt(int h){ 77 assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); 78 #ifdef SQLITE_ASCII 79 h += 9*(1&(h>>6)); 80 #endif 81 #ifdef SQLITE_EBCDIC 82 h += 9*(1&~(h>>4)); 83 #endif 84 return (unsigned char)(h & 0xf); 85 } 86 87 /* 88 ** Convert a 16-byte BLOB into a well-formed RFC-4122 UUID. The output 89 ** buffer zStr should be at least 37 bytes in length. The output will 90 ** be zero-terminated. 91 */ 92 static void sqlite3UuidBlobToStr( 93 const unsigned char *aBlob, /* Input blob */ 94 unsigned char *zStr /* Write the answer here */ 95 ){ 96 static const char zDigits[] = "0123456789abcdef"; 97 int i, k; 98 unsigned char x; 99 k = 0; 100 for(i=0, k=0x550; i<16; i++, k=k>>1){ 101 if( k&1 ){ 102 zStr[0] = '-'; 103 zStr++; 104 } 105 x = aBlob[i]; 106 zStr[0] = zDigits[x>>4]; 107 zStr[1] = zDigits[x&0xf]; 108 zStr += 2; 109 } 110 *zStr = 0; 111 } 112 113 /* 114 ** Attempt to parse a zero-terminated input string zStr into a binary 115 ** UUID. Return 0 on success, or non-zero if the input string is not 116 ** parsable. 117 */ 118 static int sqlite3UuidStrToBlob( 119 const unsigned char *zStr, /* Input string */ 120 unsigned char *aBlob /* Write results here */ 121 ){ 122 int i; 123 if( zStr[0]=='{' ) zStr++; 124 for(i=0; i<16; i++){ 125 if( zStr[0]=='-' ) zStr++; 126 if( isxdigit(zStr[0]) && isxdigit(zStr[1]) ){ 127 aBlob[i] = (sqlite3UuidHexToInt(zStr[0])<<4) 128 + sqlite3UuidHexToInt(zStr[1]); 129 zStr += 2; 130 }else{ 131 return 1; 132 } 133 } 134 if( zStr[0]=='}' ) zStr++; 135 return zStr[0]!=0; 136 } 137 138 /* 139 ** Render sqlite3_value pIn as a 16-byte UUID blob. Return a pointer 140 ** to the blob, or NULL if the input is not well-formed. 141 */ 142 static const unsigned char *sqlite3UuidInputToBlob( 143 sqlite3_value *pIn, /* Input text */ 144 unsigned char *pBuf /* output buffer */ 145 ){ 146 switch( sqlite3_value_type(pIn) ){ 147 case SQLITE_TEXT: { 148 const unsigned char *z = sqlite3_value_text(pIn); 149 if( sqlite3UuidStrToBlob(z, pBuf) ) return 0; 150 return pBuf; 151 } 152 case SQLITE_BLOB: { 153 int n = sqlite3_value_bytes(pIn); 154 return n==16 ? sqlite3_value_blob(pIn) : 0; 155 } 156 default: { 157 return 0; 158 } 159 } 160 } 161 162 /* Implementation of uuid() */ 163 static void sqlite3UuidFunc( 164 sqlite3_context *context, 165 int argc, 166 sqlite3_value **argv 167 ){ 168 unsigned char aBlob[16]; 169 unsigned char zStr[37]; 170 (void)argc; 171 (void)argv; 172 sqlite3_randomness(16, aBlob); 173 aBlob[6] = (aBlob[6]&0x0f) + 0x40; 174 aBlob[8] = (aBlob[8]&0x3f) + 0x80; 175 sqlite3UuidBlobToStr(aBlob, zStr); 176 sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT); 177 } 178 179 /* Implementation of uuid_str() */ 180 static void sqlite3UuidStrFunc( 181 sqlite3_context *context, 182 int argc, 183 sqlite3_value **argv 184 ){ 185 unsigned char aBlob[16]; 186 unsigned char zStr[37]; 187 const unsigned char *pBlob; 188 (void)argc; 189 pBlob = sqlite3UuidInputToBlob(argv[0], aBlob); 190 if( pBlob==0 ) return; 191 sqlite3UuidBlobToStr(pBlob, zStr); 192 sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT); 193 } 194 195 /* Implementation of uuid_blob() */ 196 static void sqlite3UuidBlobFunc( 197 sqlite3_context *context, 198 int argc, 199 sqlite3_value **argv 200 ){ 201 unsigned char aBlob[16]; 202 const unsigned char *pBlob; 203 (void)argc; 204 pBlob = sqlite3UuidInputToBlob(argv[0], aBlob); 205 if( pBlob==0 ) return; 206 sqlite3_result_blob(context, pBlob, 16, SQLITE_TRANSIENT); 207 } 208 209 #ifdef _WIN32 210 __declspec(dllexport) 211 #endif 212 int sqlite3_uuid_init( 213 sqlite3 *db, 214 char **pzErrMsg, 215 const sqlite3_api_routines *pApi 216 ){ 217 int rc = SQLITE_OK; 218 SQLITE_EXTENSION_INIT2(pApi); 219 (void)pzErrMsg; /* Unused parameter */ 220 rc = sqlite3_create_function(db, "uuid", 0, SQLITE_UTF8|SQLITE_INNOCUOUS, 0, 221 sqlite3UuidFunc, 0, 0); 222 if( rc==SQLITE_OK ){ 223 rc = sqlite3_create_function(db, "uuid_str", 1, 224 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 225 0, sqlite3UuidStrFunc, 0, 0); 226 } 227 if( rc==SQLITE_OK ){ 228 rc = sqlite3_create_function(db, "uuid_blob", 1, 229 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 230 0, sqlite3UuidBlobFunc, 0, 0); 231 } 232 return rc; 233 } 234