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 */
sqlite3UuidHexToInt(int h)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 */
sqlite3UuidBlobToStr(const unsigned char * aBlob,unsigned char * zStr)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 */
sqlite3UuidStrToBlob(const unsigned char * zStr,unsigned char * aBlob)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 */
sqlite3UuidInputToBlob(sqlite3_value * pIn,unsigned char * pBuf)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() */
sqlite3UuidFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)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() */
sqlite3UuidStrFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)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() */
sqlite3UuidBlobFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)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
sqlite3_uuid_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)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