sqlite_extensions-uuid 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,233 @@
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
+ }
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SqliteExtensions
4
+ module UUID
5
+ def self.to_path
6
+ spec = Gem.loaded_specs["sqlite_extensions-uuid"]
7
+ File.join(spec.require_path, "sqlite_extensions/uuid/uuid")
8
+ end
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sqlite_extensions-uuid
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mark Delk
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-12-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sqlite3
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.4.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.4.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: debug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake-compiler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ - jethrodaniel@gmail.com
100
+ executables: []
101
+ extensions:
102
+ - ext/sqlite_extensions/uuid/extconf.rb
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ext/sqlite_extensions/uuid/extconf.rb
106
+ - ext/sqlite_extensions/uuid/sqlite3.h
107
+ - ext/sqlite_extensions/uuid/sqlite3ext.h
108
+ - ext/sqlite_extensions/uuid/uuid.c
109
+ - lib/sqlite_extensions/uuid.rb
110
+ homepage: https://github.com/jethrodaniel/sqlite_extensions-uuid
111
+ licenses:
112
+ - MIT
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 3.0.0
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubygems_version: 3.5.21
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: SQLite's UUID v4 extension, packaged as a gem
133
+ test_files: []