]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Allow the SQLITE_DETERMINISTIC flag to be ORed into the preferred text encoding
authordrh <drh@noemail.net>
Sat, 14 Dec 2013 13:44:22 +0000 (13:44 +0000)
committerdrh <drh@noemail.net>
Sat, 14 Dec 2013 13:44:22 +0000 (13:44 +0000)
of application-defined functions, to mark the function as deterministic.

FossilOrigin-Name: 5716fc2341ddd8cf64139e7168597f864da4e10b

manifest
manifest.uuid
src/callback.c
src/main.c
src/sqlite.h.in
src/test1.c
test/func5.test

index 1c9fdc84012ad8ef05d088297a4f359d339fb1c5..92e7b53f9fb2ccee803c033a92086f2894e37fff 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Performance\soptimizations\sin\sthe\spager_write()\sroutine\sof\spager.c.
-D 2013-12-13T20:45:50.607
+C Allow\sthe\sSQLITE_DETERMINISTIC\sflag\sto\sbe\sORed\sinto\sthe\spreferred\stext\sencoding\nof\sapplication-defined\sfunctions,\sto\smark\sthe\sfunction\sas\sdeterministic.
+D 2013-12-14T13:44:22.886
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -170,7 +170,7 @@ F src/btree.c 11e29ef8cf16a42925fde036bcffbeffd9cc82df
 F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9
 F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
 F src/build.c 47ef8209e56d840d2b35b8a243c6ee567ad52bda
-F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
+F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
 F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
@@ -188,7 +188,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
 F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
 F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
-F src/main.c fafd3cd2a6c1211c29b9ef36b4af978ef01279ef
+F src/main.c 45e08d8ca4808625c4512a14898e9c61553e3d2a
 F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
@@ -221,7 +221,7 @@ F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
 F src/select.c d41381d80a22d3a83352aeca274cccf264ac277a
 F src/shell.c 18924f6ccfa70da98bf9e388bab512c0fd1e792e
-F src/sqlite.h.in 592057b6b3881573c2d516bad30fb20171f16b05
+F src/sqlite.h.in 4ef56464aeaa3785a2c5ca37fb3a0fb229d68b2e
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
 F src/sqliteInt.h 3c1c14a551b019c94e1addcb67d92dd14a62e058
@@ -229,7 +229,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
 F src/tclsqlite.c 651b10698c87bbc3ae5772e2491e3444c5bbf153
-F src/test1.c 760e0419705f712d80595f47199568cd7e3b57a4
+F src/test1.c 633e5e6a116acf4473b9289240bcceb5320a9d93
 F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
 F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
@@ -577,7 +577,7 @@ F test/func.test 00667bbeac044d007f6f021af1b9f6150f0c7ff8
 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
 F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a
 F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
-F test/func5.test 1435dd313c0bae70d6af089c97a2a997fc5d0e53
+F test/func5.test cdd224400bc3e48d891827cc913a57051a426fa4
 F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
 F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
 F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
@@ -1146,7 +1146,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P e50ff39a93a51b5a5be4f0e82a76104b81c9e2a4
-R 5bf1150c318417a348672020b2f63094
+P bc5febef921bd12ca7760e9d07d3be0e67140320
+R 08fd6b0f6ffb77c364a2bec4efb57810
 U drh
-Z 1b9c31d5f496c5b0319085d207729750
+Z d2313ea9b793ebbfa6428f7e8b022d58
index 1ecaf09f412bb0c602a7929c89a5e73abe0e8db2..0d64591d7bbff8e7c3c5336ad8b61d5e1064b9b5 100644 (file)
@@ -1 +1 @@
-bc5febef921bd12ca7760e9d07d3be0e67140320
\ No newline at end of file
+5716fc2341ddd8cf64139e7168597f864da4e10b
\ No newline at end of file
index 66fa490894abc0fe7bc1548649a4eca49b1d5b6d..260fe806bb48967e2431facfac48a3976c186fb4 100644 (file)
@@ -357,7 +357,6 @@ FuncDef *sqlite3FindFunction(
 
   assert( nArg>=(-2) );
   assert( nArg>=(-1) || createFlag==0 );
-  assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
   h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
 
   /* First search for a match amongst the application-defined functions.
index 09e3bb879fd6e16aafbb19e6c22c4b2ca59d744c..32e4dee7f010371740ce27853cfac6393337bb62 100644 (file)
@@ -1370,6 +1370,7 @@ int sqlite3CreateFunc(
 ){
   FuncDef *p;
   int nName;
+  int extraFlags;
 
   assert( sqlite3_mutex_held(db->mutex) );
   if( zFunctionName==0 ||
@@ -1380,6 +1381,10 @@ int sqlite3CreateFunc(
       (255<(nName = sqlite3Strlen30( zFunctionName))) ){
     return SQLITE_MISUSE_BKPT;
   }
+
+  assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
+  extraFlags = enc &  SQLITE_DETERMINISTIC;
+  enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
   
 #ifndef SQLITE_OMIT_UTF16
   /* If SQLITE_UTF16 is specified as the encoding type, transform this
@@ -1393,10 +1398,10 @@ int sqlite3CreateFunc(
     enc = SQLITE_UTF16NATIVE;
   }else if( enc==SQLITE_ANY ){
     int rc;
-    rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
+    rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
          pUserData, xFunc, xStep, xFinal, pDestructor);
     if( rc==SQLITE_OK ){
-      rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
+      rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
           pUserData, xFunc, xStep, xFinal, pDestructor);
     }
     if( rc!=SQLITE_OK ){
@@ -1439,7 +1444,8 @@ int sqlite3CreateFunc(
     pDestructor->nRef++;
   }
   p->pDestructor = pDestructor;
-  p->funcFlags &= SQLITE_FUNC_ENCMASK;
+  p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
+  testcase( p->funcFlags & SQLITE_DETERMINISTIC );
   p->xFunc = xFunc;
   p->xStep = xStep;
   p->xFinalize = xFinal;
index b9f4defed70fed275fe8308b24782007b1e04eaf..7b0e648bfcfd55ba34ed2da3fe577933afbdae50 100644 (file)
@@ -3977,15 +3977,24 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
 **
 ** ^The fourth parameter, eTextRep, specifies what
 ** [SQLITE_UTF8 | text encoding] this SQL function prefers for
-** its parameters.  Every SQL function implementation must be able to work
-** with UTF-8, UTF-16le, or UTF-16be.  But some implementations may be
-** more efficient with one encoding than another.  ^An application may
-** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
-** times with the same function but with different values of eTextRep.
+** its parameters.  The application should set this parameter to
+** [SQLITE_UTF16LE] if the function implementation invokes 
+** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the
+** implementation invokes [sqlite3_value_text16be()] on an input, or
+** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8]
+** otherwise.  ^The same SQL function may be registered multiple times using
+** different preferred text encodings, with different implementations for
+** each encoding.
 ** ^When multiple implementations of the same function are available, SQLite
 ** will pick the one that involves the least amount of data conversion.
-** If there is only a single implementation which does not care what text
-** encoding is used, then the fourth argument should be [SQLITE_ANY].
+**
+** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC]
+** to signal that the function will always return the same result given
+** the same inputs within a single SQL statement.  Most SQL functions are
+** deterministic.  The built-in [random()] SQL function is an example of a
+** function that is not deterministic.  The SQLite query planner is able to
+** perform additional optimizations on deterministic functions, so use
+** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
 **
 ** ^(The fifth parameter is an arbitrary pointer.  The implementation of the
 ** function can gain access to this pointer using [sqlite3_user_data()].)^
@@ -4071,9 +4080,19 @@ int sqlite3_create_function_v2(
 #define SQLITE_UTF16LE        2
 #define SQLITE_UTF16BE        3
 #define SQLITE_UTF16          4    /* Use native byte order */
-#define SQLITE_ANY            5    /* sqlite3_create_function only */
+#define SQLITE_ANY            5    /* Deprecated */
 #define SQLITE_UTF16_ALIGNED  8    /* sqlite3_create_collation only */
 
+/*
+** CAPI3REF: Function Flags
+**
+** These constants may be ORed together with the 
+** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
+** to [sqlite3_create_function()], [sqlite3_create_function16()], or
+** [sqlite3_create_function_v2()].
+*/
+#define SQLITE_DETERMINISTIC    0x800
+
 /*
 ** CAPI3REF: Deprecated Functions
 ** DEPRECATED
index e0c16e13aef799e85b41bf35910c830a555899be..a96b2986610420ff866d7a7b9bc2a1bc51c82cb2 100644 (file)
@@ -942,9 +942,21 @@ static void ptrChngFunction(
   sqlite3_result_int(context, p1!=p2);
 }
 
+/*
+** This SQL function returns a different answer each time it is called, even if
+** the arguments are the same.
+*/
+static void nondeterministicFunction(
+  sqlite3_context *context, 
+  int argc,  
+  sqlite3_value **argv
+){
+  static int cnt = 0;
+  sqlite3_result_int(context, cnt++);
+}
 
 /*
-** Usage:  sqlite_test_create_function DB
+** Usage:  sqlite3_create_function DB
 **
 ** Call the sqlite3_create_function API on the given database in order
 ** to create a function named "x_coalesce".  This function does the same thing
@@ -973,16 +985,16 @@ static int test_create_function(
     return TCL_ERROR;
   }
   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
-  rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0, 
+  rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0, 
         t1_ifnullFunc, 0, 0);
   if( rc==SQLITE_OK ){
-    rc = sqlite3_create_function(db, "hex8", 1, SQLITE_ANY, 0, 
-          hex8Func, 0, 0);
+    rc = sqlite3_create_function(db, "hex8", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+          0, hex8Func, 0, 0);
   }
 #ifndef SQLITE_OMIT_UTF16
   if( rc==SQLITE_OK ){
-    rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, 0, 
-          hex16Func, 0, 0);
+    rc = sqlite3_create_function(db, "hex16", 1, SQLITE_UTF16 | SQLITE_DETERMINISTIC,
+          0, hex16Func, 0, 0);
   }
 #endif
   if( rc==SQLITE_OK ){
@@ -994,6 +1006,19 @@ static int test_create_function(
           ptrChngFunction, 0, 0);
   }
 
+  /* Functions counter1() and counter2() have the same implementation - they
+  ** both return an ascending integer with each call.  But counter1() is marked
+  ** as non-deterministic and counter2() is marked as deterministic.
+  */
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_function(db, "counter1", -1, SQLITE_UTF8,
+          0, nondeterministicFunction, 0, 0);
+  }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_function(db, "counter2", -1, SQLITE_UTF8|SQLITE_DETERMINISTIC,
+          0, nondeterministicFunction, 0, 0);
+  }
+
 #ifndef SQLITE_OMIT_UTF16
   /* Use the sqlite3_create_function16() API here. Mainly for fun, but also 
   ** because it is not tested anywhere else. */
index 83ecb785db06cf92bc059bf33d8c1bde5c029274..bfd545b4e3041c5b358440cce0f0370ff071581d 100644 (file)
@@ -9,13 +9,15 @@
 #
 #*************************************************************************
 #
-# Verify that constant string expressions that get factored into initializing
-# code are not reused between function parameters and other values in the
-# VDBE program, as the function might have changed the encoding.
+# Testing of function factoring and the SQLITE_DETERMINISTIC flag.
 #
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
+# Verify that constant string expressions that get factored into initializing
+# code are not reused between function parameters and other values in the
+# VDBE program, as the function might have changed the encoding.
+#
 do_execsql_test func5-1.1 {
   PRAGMA encoding=UTF16le;
   CREATE TABLE t1(x,a,b,c);
@@ -30,4 +32,32 @@ do_execsql_test func5-1.2 {
   SELECT x FROM t1 WHERE a='abcdefg' OR c=instr('abcdefg',b) ORDER BY +x;
 } {2 4}
 
+# Verify that SQLITE_DETERMINISTIC functions get factored out of the
+# evaluation loop whereas non-deterministic functions do not.  counter1()
+# is marked as non-deterministic and so is not factored out of the loop,
+# and it really is non-deterministic, returning a different result each
+# time.  But counter2() is marked as deterministic, so it does get factored
+# out of the loop.  counter2() has the same implementation as counter1(),
+# returning a different result on each invocation, but because it is 
+# only invoked once outside of the loop, it appears to return the same
+# result multiple times.
+#
+do_execsql_test func5-2.1 {
+  CREATE TABLE t2(x,y);
+  INSERT INTO t2 VALUES(1,2),(3,4),(5,6),(7,8);
+  SELECT x, y FROM t2 WHERE x+5=5+x ORDER BY +x;
+} {1 2 3 4 5 6 7 8}
+sqlite3_create_function db
+do_execsql_test func5-2.2 {
+  SELECT x, y FROM t2
+   WHERE x+counter1('hello')=counter1('hello')+x
+   ORDER BY +x;
+} {}
+do_execsql_test func5-2.3 {
+  SELECT x, y FROM t2
+   WHERE x+counter2('hello')=counter2('hello')+x
+   ORDER BY +x;
+} {1 2 3 4 5 6 7 8}
+
+
 finish_test