]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add scalar function "prefix_length()" to ext/misc/prefixes.c.
authordan <dan@noemail.net>
Mon, 14 Jan 2019 20:44:00 +0000 (20:44 +0000)
committerdan <dan@noemail.net>
Mon, 14 Jan 2019 20:44:00 +0000 (20:44 +0000)
FossilOrigin-Name: 0bf1550507d9d3c8a41f8a50db3a59bf808f0a4e24637dc0905d35579305eca7

Makefile.in
Makefile.msc
ext/misc/prefixes.c
main.mk
manifest
manifest.uuid
src/test1.c
test/prefixes.test [new file with mode: 0644]

index 4eec340b0f6df8faac6b0b56864b24d700d3771b..219fc4f0cadfd7612467c7672d6645cc5f92da27 100644 (file)
@@ -452,6 +452,7 @@ TESTSRC += \
   $(TOP)/ext/misc/nextchar.c \
   $(TOP)/ext/misc/normalize.c \
   $(TOP)/ext/misc/percentile.c \
+  $(TOP)/ext/misc/prefixes.c \
   $(TOP)/ext/misc/regexp.c \
   $(TOP)/ext/misc/remember.c \
   $(TOP)/ext/misc/series.c \
index 179215ecf4c119c971b6bb95cfa6f46c1886a8b9..a4f0e1ef64af1876b2352bbef228f8e449f7cb0d 100644 (file)
@@ -1527,6 +1527,7 @@ TESTEXT = \
   $(TOP)\ext\misc\nextchar.c \
   $(TOP)\ext\misc\normalize.c \
   $(TOP)\ext\misc\percentile.c \
+  $(TOP)\ext\misc\prefixes.c \
   $(TOP)\ext\misc\regexp.c \
   $(TOP)\ext\misc\remember.c \
   $(TOP)\ext\misc\series.c \
index b74cb61a6731551b2311f5a8aeef8110a5b87a06..a2f5b3289de2569b2d3f89c7a965d7b7cb4ba09e 100644 (file)
@@ -249,6 +249,53 @@ static sqlite3_module prefixesModule = {
   /* xShadowName */ 0
 };
 
+/*
+** This is a copy of the SQLITE_SKIP_UTF8(zIn) macro in sqliteInt.h.
+**
+** Assuming zIn points to the first byte of a UTF-8 character,
+** advance zIn to point to the first byte of the next UTF-8 character.
+*/
+#define PREFIX_SKIP_UTF8(zIn) {                        \
+  if( (*(zIn++))>=0xc0 ){                              \
+    while( (*zIn & 0xc0)==0x80 ){ zIn++; }             \
+  }                                                    \
+}
+
+/*
+** Implementation of function prefix_length(). This function accepts two
+** strings as arguments and returns the length in characters (not bytes), 
+** of the longest prefix shared by the two strings. For example:
+**
+**   prefix_length('abcdxxx', 'abcyy') == 3
+**   prefix_length('abcdxxx', 'bcyyy') == 0
+**   prefix_length('abcdxxx', 'ab')    == 2
+**   prefix_length('ab',      'abcd')  == 2
+**
+** This function assumes the input is well-formed utf-8. If it is not,
+** it is possible for this function to return -1.
+*/
+static void prefixLengthFunc(
+  sqlite3_context *ctx,
+  int nVal,
+  sqlite3_value **apVal
+){
+  int nByte;                      /* Number of bytes to compare */
+  int nRet = 0;                   /* Return value */
+  const unsigned char *zL = sqlite3_value_text(apVal[0]);
+  const unsigned char *zR = sqlite3_value_text(apVal[1]);
+  int nL = sqlite3_value_bytes(apVal[0]);
+  int nR = sqlite3_value_bytes(apVal[1]);
+  int i;
+
+  nByte = (nL > nR ? nL : nR);
+  for(i=0; i<nByte; i++){
+    if( zL[i]!=zR[i] ) break;
+    if( (zL[i] & 0xC0)!=0x80 ) nRet++;
+  }
+
+  if( (zL[i] & 0xC0)==0x80 ) nRet--;
+  sqlite3_result_int(ctx, nRet);
+}
 
 #ifdef _WIN32
 __declspec(dllexport)
@@ -261,5 +308,10 @@ int sqlite3_prefixes_init(
   int rc = SQLITE_OK;
   SQLITE_EXTENSION_INIT2(pApi);
   rc = sqlite3_create_module(db, "prefixes", &prefixesModule, 0);
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_function(
+        db, "prefix_length", 2, SQLITE_UTF8, 0, prefixLengthFunc, 0, 0
+    );
+  }
   return rc;
 }
diff --git a/main.mk b/main.mk
index 9ec0a6dbe6b3d09e71e6cf676fc1a13230bbc125..474d710b5d59b26104c419d8fdb39bd6434ef2a2 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -369,6 +369,7 @@ TESTSRC += \
   $(TOP)/ext/misc/nextchar.c \
   $(TOP)/ext/misc/normalize.c \
   $(TOP)/ext/misc/percentile.c \
+  $(TOP)/ext/misc/prefixes.c \
   $(TOP)/ext/misc/regexp.c \
   $(TOP)/ext/misc/remember.c \
   $(TOP)/ext/misc/series.c \
index 424e846b4faa9f0929cc7ab35d1fda89d584e860..6b9aea40c0ffcc6178c0d09bb8f2adca6f4ab6f7 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,10 +1,10 @@
-C Fix\sa\sproblem\scausing\ssome\sTcl\stest\scases\sto\sfail\swith\serrors\slike\s"expected:\s[<multiline-whitespace>],\sgot:\s[]".
-D 2019-01-14T19:13:30.596
+C Add\sscalar\sfunction\s"prefix_length()"\sto\sext/misc/prefixes.c.
+D 2019-01-14T20:44:00.309
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
-F Makefile.in 45a3fef4d325ac0220c2172aeec4e4321da351f073f3b8e8ddea655f49ef6f2b
+F Makefile.in 2a9d0331ab57c68173a4c2fe9046fe89c4d916a888e04dd7a2d36958c2bff777
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
-F Makefile.msc 3c4c7e94419ff28cb68850188c9d153b343aed4c5ebed5965426232ed67ff9d9
+F Makefile.msc 54c5921b0c65c49ea8fb5010e763c181526d6cdc1109c7ab7115c4f5bb71e13c
 F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee
 F VERSION 453e2f4529ca208196d5567db28d549d7151f79efd33f6e6cfe6e613e583a0be
 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@@ -295,7 +295,7 @@ F ext/misc/mmapwarm.c 8c5fe90d807a23e44a8b93e96e8b812b19b300d5fd8c1d40a4fd1d8224
 F ext/misc/nextchar.c 279f80fe8ef5ba413242e2704e246503ac601f005eefb180d19e6c920338a0ba
 F ext/misc/normalize.c b4290464f542bae7a97b43f15bd197949b833ffd668b7c313631bd5d4610212c
 F ext/misc/percentile.c a6a1594c104da2d0ceab38fe609eb2f65529272377827f6f8a2b5c9fa6119e7e
-F ext/misc/prefixes.c ac95cf723927b9e4b6f2b45eec743986259e3c2618f92ffa9fd780e13c75f70e
+F ext/misc/prefixes.c 1eb85b7b64b8adf5cbb18a72c51a8f2910a7bc0fd5fbc81a9213ba4af2d51811
 F ext/misc/regexp.c 79345bf03496155a640ee0300d3307296761cebb5e115b4e342cc2fb5861ec10
 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
 F ext/misc/rot13.c 540a169cb0d74f15522a8930b0cccdcb37a4fd071d219a5a083a319fc6e8db77
@@ -435,7 +435,7 @@ F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e6
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 8456b6b4a5ecdb7b6b59283236b3be6393bc7eed6cbda3bcf1d552e1a63e03ff
+F main.mk 20d344434cec07680fb7d7e66f6401b0f3bf915277018ac93d229b8f73678216
 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -523,7 +523,7 @@ F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6
 F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
 F src/tclsqlite.c e72862a271348d779672b45a730c33fd0c535e630ff927e8ce4a0c908d1d28c6
-F src/test1.c f78dcd39d5cad63d33306bb963354f976007968bc95c45bc9fdfaeb2e1ec0eae
+F src/test1.c 64cdc914a77102e008dfae7adaa4ded54c2d4953d1464ea8709805a2aab755eb
 F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
 F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
@@ -1199,6 +1199,7 @@ F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c
 F test/pragma4.test 52d8186f9e8d09b87189432cdd401dfa66d0b32445e837fa19046c8ae7621b0e
 F test/pragma5.test 824ce6ced5d6b7ec71abe37fc6005ff836fe39d638273dc5192b39864b9ee983
 F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
+F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
 F test/printf.test a3e559bc9d922e7fe44e9d05c6965fee34fe3bc28300a4248c6a063425246ffd
 F test/printf2.test 30b5dd0b4b992dc5626496846ecce17ff592cacbcb11c3e589f3ac4d7e129dae
 F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
@@ -1799,7 +1800,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P f0fd2163fc23a555ef03af43294a14fcabae6921f52e64c979286c745b4f6218
-R 238e457d65f075aa5a49baa7e28c3f0b
+P 11b8a4cba747ca214fe3506caa3b711c87be4d55412754e673cc0603afefb086
+R 32ab1d3eba68373a1b0b1f4de28ca909
 U dan
-Z 9ed1f14f70bf3f4d25df868a0ff2534c
+Z fb1a50e31aa836559e45fed0b6204d9c
index a9f6a5e40873791fd524c2b3dcbea1f4c0eeafac..e315bc4b42a650bfd76c0705f3d054b9ee3393b7 100644 (file)
@@ -1 +1 @@
-11b8a4cba747ca214fe3506caa3b711c87be4d55412754e673cc0603afefb086
\ No newline at end of file
+0bf1550507d9d3c8a41f8a50db3a59bf808f0a4e24637dc0905d35579305eca7
\ No newline at end of file
index def9c7e2fdff6231b0f26253075db3ce7a6ee2e1..1fd48fec6bbbbbdb4103bf4b09387a541bc28773 100644 (file)
@@ -7141,6 +7141,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
   extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
   extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
   extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*);
+  extern int sqlite3_prefixes_init(sqlite3*,char**,const sqlite3_api_routines*);
   extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
   extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*);
   extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*);
@@ -7166,6 +7167,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
     { "ieee754",               sqlite3_ieee_init                 },
     { "nextchar",              sqlite3_nextchar_init             },
     { "percentile",            sqlite3_percentile_init           },
+    { "prefixes",              sqlite3_prefixes_init             },
     { "regexp",                sqlite3_regexp_init               },
     { "remember",              sqlite3_remember_init             },
     { "series",                sqlite3_series_init               },
diff --git a/test/prefixes.test b/test/prefixes.test
new file mode 100644 (file)
index 0000000..2080905
--- /dev/null
@@ -0,0 +1,88 @@
+# 2018-01-15
+#
+# 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.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is prefixes.c extension
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix unionvtab
+
+ifcapable !vtab {
+  finish_test
+  return
+}
+
+load_static_extension db prefixes
+
+foreach {tn zLeft zRight expected} {
+  1 abcdxxx abcyy    3
+  2 abcdxxx bcyyy    0
+  3 abcdxxx ab       2
+  4 ab      abcd     2
+
+  5 "xyz\u1234xz" "xyz\u1234xy" 5
+  6 "xyz\u1234"   "xyz\u1234xy" 4
+  7 "xyz\u1234"   "xyz\u1234"   4
+  8 "xyz\u1234xy" "xyz\u1234"   4
+  9 "xyz\u1234xy" "xyz\u1233"   3
+ 10 "xyz\u1234xy" "xyz\u1235"   3
+} {
+  do_execsql_test 1.$tn { SELECT prefix_length($zLeft, $zRight) } $expected
+}
+
+
+do_execsql_test 2.0 {
+  CREATE TABLE t1(k TEXT UNIQUE, v INTEGER);
+  INSERT INTO t1 VALUES
+    ('aback', 1),
+    ('abaft', 2),
+    ('abandon', 3),
+    ('abandoned', 4),
+    ('abandoning', 5),
+    ('abandonment', 6),
+    ('abandons', 7),
+    ('abase', 8),
+    ('abased', 9),
+    ('abasement', 10),
+    ('abasements', 11),
+    ('abases', 12),
+    ('abash', 13),
+    ('abashed', 14),
+    ('abashes', 15),
+    ('abashing', 16),
+    ('abasing', 17),
+    ('abate', 18),
+    ('abated', 19),
+    ('abatement', 20),
+    ('abatements', 21);
+}
+
+foreach {tn INPUT expected} {
+  1 abatementt   abatement
+  2 abashet      abash
+  3 abandonio    abandon
+  4 abasemenu    abase
+} {
+  do_execsql_test 2.$tn {
+    WITH finder(str) AS (
+      SELECT (SELECT max(k) FROM t1 WHERE k<=$INPUT)
+        UNION ALL
+        SELECT (
+          SELECT max(k) FROM t1 
+          WHERE k<=substr($INPUT, 1, prefix_length(finder.str, $INPUT))
+        ) FROM finder WHERE length(finder.str)>0
+      )
+    SELECT str FROM finder WHERE length(str)==prefix_length(str, $INPUT) LIMIT 1
+  } $expected
+}
+
+finish_test