Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add scalar SQL function unhex(). |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
890e9629a7480138c9c1d3acc2d1e7b3 |
User & Date: | dan 2023-01-24 20:17:43 |
Context
2023-01-25
| ||
13:42 | Fix another problem with fts3/4 auxiliary functions and NEAR expressions that consist entirely of deferred tokens. (check-in: a8c91c13 user: dan tags: trunk) | |
2023-01-24
| ||
20:17 | Add scalar SQL function unhex(). (check-in: 890e9629 user: dan tags: trunk) | |
17:19 | Update unhex() to allow a second argument, specifying a set of characters that are permitted to appear between pairs of hexadecimal digits. (Closed-Leaf check-in: 66c85626 user: dan tags: unhex-function) | |
11:24 | Fix a problem with using fts3 auxiliary functions with expressions like "E AND ...", where E is a NEAR expression that consists entirely of deferred tokens. (check-in: 39bfae4c user: dan tags: trunk) | |
Changes
Changes to src/func.c.
︙ | ︙ | |||
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 | *(z++) = hexdigits[(c>>4)&0xf]; *(z++) = hexdigits[c&0xf]; } *z = 0; sqlite3_result_text(context, zHex, n*2, sqlite3_free); } } /* ** The zeroblob(N) function returns a zero-filled blob of size N bytes. */ static void zeroblobFunc( sqlite3_context *context, int argc, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 | *(z++) = hexdigits[(c>>4)&0xf]; *(z++) = hexdigits[c&0xf]; } *z = 0; sqlite3_result_text(context, zHex, n*2, sqlite3_free); } } /* ** Buffer zStr contains nStr bytes of utf-8 encoded text. Return 1 if zStr ** contains character ch, or 0 if it does not. */ static int strContainsChar(const u8 *zStr, int nStr, u32 ch){ const u8 *zEnd = &zStr[nStr]; const u8 *z = zStr; while( z<zEnd ){ u32 tst = Utf8Read(z); if( tst==ch ) return 1; } return 0; } /* ** The unhex() function. This function may be invoked with either one or ** two arguments. In both cases the first argument is interpreted as text ** a text value containing a set of pairs of hexadecimal digits which are ** decoded and returned as a blob. ** ** If there is only a single argument, then it must consist only of an ** even number of hexadeximal digits. Otherwise, return NULL. ** ** Or, if there is a second argument, then any character that appears in ** the second argument is also allowed to appear between pairs of hexadecimal ** digits in the first argument. If any other character appears in the ** first argument, or if one of the allowed characters appears between ** two hexadecimal digits that make up a single byte, NULL is returned. ** ** The following expressions are all true: ** ** unhex('ABCD') IS x'ABCD' ** unhex('AB CD') IS NULL ** unhex('AB CD', ' ') IS x'ABCD' ** unhex('A BCD', ' ') IS NULL */ static void unhexFunc( sqlite3_context *pCtx, int argc, sqlite3_value **argv ){ const u8 *zPass = (const u8*)""; int nPass = 0; const u8 *zHex = sqlite3_value_text(argv[0]); int nHex = sqlite3_value_bytes(argv[0]); #ifdef SQLITE_DEBUG const u8 *zEnd = &zHex[nHex]; #endif u8 *pBlob = 0; u8 *p = 0; assert( argc==1 || argc==2 ); if( argc==2 ){ zPass = sqlite3_value_text(argv[1]); nPass = sqlite3_value_bytes(argv[1]); } if( !zHex || !zPass ) return; p = pBlob = contextMalloc(pCtx, (nHex/2)+1); if( pBlob ){ u8 c; /* Most significant digit of next byte */ u8 d; /* Least significant digit of next byte */ while( (c = *zHex)!=0x00 ){ while( !sqlite3Isxdigit(c) ){ u32 ch = Utf8Read(zHex); assert( zHex<=zEnd ); if( !strContainsChar(zPass, nPass, ch) ) goto unhex_null; c = *zHex; if( c==0x00 ) goto unhex_done; } zHex++; assert( *zEnd==0x00 ); assert( zHex<=zEnd ); d = *(zHex++); if( !sqlite3Isxdigit(d) ) goto unhex_null; *(p++) = (sqlite3HexToInt(c)<<4) | sqlite3HexToInt(d); } } unhex_done: sqlite3_result_blob(pCtx, pBlob, (p - pBlob), sqlite3_free); return; unhex_null: sqlite3_free(pBlob); return; } /* ** The zeroblob(N) function returns a zero-filled blob of size N bytes. */ static void zeroblobFunc( sqlite3_context *context, int argc, |
︙ | ︙ | |||
2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 | #ifndef SQLITE_OMIT_FLOATING_POINT FUNCTION(round, 1, 0, 0, roundFunc ), FUNCTION(round, 2, 0, 0, roundFunc ), #endif FUNCTION(upper, 1, 0, 0, upperFunc ), FUNCTION(lower, 1, 0, 0, lowerFunc ), FUNCTION(hex, 1, 0, 0, hexFunc ), INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), | > > | 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 | #ifndef SQLITE_OMIT_FLOATING_POINT FUNCTION(round, 1, 0, 0, roundFunc ), FUNCTION(round, 2, 0, 0, roundFunc ), #endif FUNCTION(upper, 1, 0, 0, upperFunc ), FUNCTION(lower, 1, 0, 0, lowerFunc ), FUNCTION(hex, 1, 0, 0, hexFunc ), FUNCTION(unhex, 1, 0, 0, unhexFunc ), FUNCTION(unhex, 2, 0, 0, unhexFunc ), INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), |
︙ | ︙ |
Changes to test/exprfault.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 | } -body { execsql { SELECT a = ( SELECT d FROM (SELECT d FROM t2) ) FROM t1 } } -test { faultsim_test_result {0 {}} } finish_test | > > > > > > > > > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | } -body { execsql { SELECT a = ( SELECT d FROM (SELECT d FROM t2) ) FROM t1 } } -test { faultsim_test_result {0 {}} } do_faultsim_test 2 -faults oom* -prep { faultsim_restore_and_reopen } -body { execsql { SELECT hex ( unhex('ABCDEF') ); } } -test { faultsim_test_result {0 ABCDEF} } finish_test |
Added test/unhex.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | # 2023 January 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. # #*********************************************************************** # set testdir [file dirname $argv0] source [file join $testdir tester.tcl] set testprefix unhex foreach {tn hex} { 1 0000 2 FFFF 3 0123456789ABCDEF } { do_execsql_test 1.$tn.1 { SELECT hex( unhex( $hex ) ); } $hex do_execsql_test 1.$tn.2 { SELECT hex( unhex( lower( $hex ) ) ); } $hex } do_execsql_test 2.0 { SELECT typeof( unhex('') ), length( unhex('') ); } {blob 0} foreach {tn hex} { 1 ABC 2 hello 3 123456x7 4 0xff } { do_execsql_test 2.$tn { SELECT unhex( $hex ) IS NULL; } 1 } do_catchsql_test 3.0 { SELECT unhex(); } {1 {wrong number of arguments to function unhex()}} do_catchsql_test 3.1 { SELECT unhex('ABCD', '1234', ''); } {1 {wrong number of arguments to function unhex()}} #-------------------------------------------------------------------------- # Test the 2-argument version. # foreach {tn hex} { 1 "FFFF ABCD" 2 "FFFF ABCD" 3 "FFFFABCD " 4 " FFFFABCD" 5 "--FFFF AB- -CD- " 6 "--" 7 " --" } { set out "" foreach x [split $hex ""] { if {[string is xdigit $x]} { append out $x } } do_execsql_test 5.$tn.1 { SELECT hex( unhex($hex, ' -') ); } [list $out] } do_execsql_test 6.0 { SELECT typeof( unhex(' ', ' -') ), length( unhex('-', ' -') ); } {blob 0} do_execsql_test 6.1 " SELECT hex( unhex('\u0E01ABCD\u0E02', '\uE01\uE02') ) " {ABCD} do_execsql_test 6.2 " SELECT typeof( unhex('\u0E01ABCD\u0E02', '\uE03\uE02') ) " {null} do_execsql_test 6.3 " SELECT hex( unhex('\u0E01AB CD\uE02\uE01', '\uE01 \uE02') ) " {ABCD} #-------------------------------------------------------------------------- # Test that if either argument is NULL, the returned value is also NULL. # do_execsql_test 6.4.1 { SELECT typeof(unhex(NULL)) } {null} do_execsql_test 6.4.2 { SELECT typeof(unhex(NULL, ' ')) } {null} do_execsql_test 6.4.3 { SELECT typeof(unhex('1234', NULL)) } {null} finish_test |