mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Add scalar SQL function unhex().
FossilOrigin-Name: 890e9629a7480138c9c1d3acc2d1e7b3c05e0d156e5c5fba428bc1aeb790fbfb
This commit is contained in:
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\sa\sproblem\swith\susing\sfts3\sauxiliary\sfunctions\swith\sexpressions\slike\s"E\sAND\s...",\swhere\sE\sis\sa\sNEAR\sexpression\sthat\sconsists\sentirely\sof\sdeferred\stokens.
|
||||
D 2023-01-24T11:24:28.082
|
||||
C Add\sscalar\sSQL\sfunction\sunhex().
|
||||
D 2023-01-24T20:17:43.328
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -573,7 +573,7 @@ F src/delete.c 86573edae75e3d3e9a8b590d87db8e47222103029df4f3e11fa56044459b514e
|
||||
F src/expr.c 204af6a83c191f5ac19ec4af6ecc546f188cc2dd1c76fc5280982f710ec4b9c4
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 722f20779f5342a787922deded3628d8c74b5249cab04098cf17ee2f2aaff002
|
||||
F src/func.c 68f610a44962814a4ba593fc95137a6682cb7e65086f22167e167b75ee3432e7
|
||||
F src/func.c 0bf5b82df41ffa1afe2bc67c3d0d361761c56c9e1785c999e24a15ba04c28d2b
|
||||
F src/global.c e06ff8e0acd85aec13563c9ecb44fbbf38232ccf73594998fd880b92d619594b
|
||||
F src/hash.c c6af5f96a7a76d000f07c5402c48c318c2566beecdee9e78b9d9f60ce7119565
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
@ -976,7 +976,7 @@ F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
|
||||
F test/expr.test 5c06696478212e5a04e04b043f993373f6f8e5ce5a80f5548a84703b123b6caa
|
||||
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
|
||||
F test/exprfault.test 497cc0b8fe6a677f49b55cb485e040f709ec2834b84f25912fe9c2dfeeda33db
|
||||
F test/exprfault.test da33606d799718e2f8e34efd0e5858884a1ad87f608774c552a7f5517cc27181
|
||||
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
|
||||
F test/external_reader.test c7d34694f1b25c32d866f56ac80c1e29edddc42b4ef90cad589263ffac2cde0c
|
||||
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
|
||||
@ -1758,6 +1758,7 @@ F test/tt3_vacuum.c 71b254cde1fc49d6c8c44efd54f4668f3e57d7b3a8f4601ade069f75a999
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unhex.test 47b547f4b35e4f6525ecac7c7839bd3ae4eb4613d4e8932592eff55da83308f1
|
||||
F test/unionall.test eb9afa030897af75fd2f0dd28354ef63c8a5897b6c76aa1f15acae61a12eabcf
|
||||
F test/unionall2.test 71e8fa08d5699d50dc9f9dc0c9799c2e7a6bb7931a330d369307a4df7f157fa1
|
||||
F test/unionallfault.test 652bfbb630e6c43135965dc1e8f0a9a791da83aec885d626a632fe1909c56f73
|
||||
@ -2043,8 +2044,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 48bb7c88787bf5de1d70cf3cc81ada38c6c02e476dbdff12c8676c6d5ee19aed
|
||||
R da240f1feb163c267019691c0e1aa949
|
||||
P 39bfae4c4698a13e07c4a0725f2790955e03b601fe64e17a000c691def1bdcb8 66c8562690b19f17972589611810e1dccad3a48777acb05208289c1f77076f71
|
||||
R e4f755d732b8075e7847f3615f7f161a
|
||||
T +closed 66c8562690b19f17972589611810e1dccad3a48777acb05208289c1f77076f71
|
||||
U dan
|
||||
Z a4ad18532eeaa7e5926d4df8858c0bf9
|
||||
Z b2c1f41f5ac4263ca444db1f00dc6050
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
39bfae4c4698a13e07c4a0725f2790955e03b601fe64e17a000c691def1bdcb8
|
||||
890e9629a7480138c9c1d3acc2d1e7b3c05e0d156e5c5fba428bc1aeb790fbfb
|
92
src/func.c
92
src/func.c
@ -1223,6 +1223,96 @@ static void hexFunc(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
@ -2287,6 +2377,8 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
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 ),
|
||||
|
@ -31,5 +31,15 @@ do_faultsim_test 1.1 -faults oom* -prep {
|
||||
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
|
||||
|
102
test/unhex.test
Normal file
102
test/unhex.test
Normal file
@ -0,0 +1,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
|
||||
|
||||
|
Reference in New Issue
Block a user