]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Proof of concept for a new sqlite3_function_needed() interface. need-function
authordrh <>
Fri, 7 Jul 2023 16:58:20 +0000 (16:58 +0000)
committerdrh <>
Fri, 7 Jul 2023 16:58:20 +0000 (16:58 +0000)
FossilOrigin-Name: cd67edc032983b5111ffcf6c73ca1308ef67cf2f16baa25788121827b3038d2f

manifest
manifest.uuid
src/callback.c
src/main.c
src/shell.c.in
src/sqlite.h.in
src/sqlite3ext.h
src/sqliteInt.h

index e66f8364553dadbb40959c7f39057403a43dc027..8be6987b7a1846db7f38cc0c4dec2c3cdab4c9ee 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C For\sthe\s"Valgrind"\stest\sscenario,\sset\sLONGDOUBLE_TYPE=double\sas\svalgrind\ndoes\snot\scorrectly\semulated\sextended\sprecision\son\sx64.
-D 2023-07-07T12:18:26.936
+C Proof\sof\sconcept\sfor\sa\snew\ssqlite3_function_needed()\sinterface.
+D 2023-07-07T16:58:20.565
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -580,7 +580,7 @@ F src/btree.c c0c93b6cb4dc133b528c1290bb4ad0f2414452f9a5758ff2b106af718874f39e
 F src/btree.h aa354b9bad4120af71e214666b35132712b8f2ec11869cb2315c52c81fad45cc
 F src/btreeInt.h 3b4eff7155c0cea6971dc51f62e3529934a15a6640ec607dd42a767e379cb3a9
 F src/build.c a8ae3b32d9aa9bbd2c0e97d7c0dd80def9fbca408425de1608f57ee6f47f45f4
-F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
+F src/callback.c 3520e686ab1d427f33cffb46d554d0a0a2a588866a195c69d1a17103b67dde18
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c 20507cc0b0a6c19cd882fcd0eaeda32ae6a4229fb4b024cfdf3183043d9b703d
 F src/date.c f73f203b3877cef866c60ab402aec2bf89597219b60635cf50cbe3c5e4533e94
@@ -600,7 +600,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
 F src/json.c 14c474fb1249a46eb44e878e2361f36abfe686b134039b0d1883d93d61505b4a
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
 F src/loadext.c 176d6b2cb18a6ad73b133db17f6fc351c4d9a2d510deebdb76c22bde9cfd1465
-F src/main.c 512b1d45bc556edf4471a845afb7ba79e64bd5b832ab222dc195c469534cd002
+F src/main.c d869b4032a2717b24ad0fd82266ea4d79304a25d942a4b332ff307009f6f10e3
 F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -638,11 +638,11 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 F src/select.c 3ab1186290a311a8ceed1286c0e286209f7fe97b2d02c7593258004ce295dd88
-F src/shell.c.in d320d8a13636de06d777cc1eab981caca304e175464e98183cf4ea68d93db818
-F src/sqlite.h.in f999ef3642f381d69679b2516b430dbcb6c5a2a951b7f5e43dc4751b474a5774
+F src/shell.c.in d6c9ac6ab2c56eac0009ad383f6fd31a410d4cfa04ddf5875496207773fc60b1
+F src/sqlite.h.in 287bce997bc287c251558b41ffb4ec025b98e7d0c74e3bf22c4919d2edb6d44c
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
-F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
-F src/sqliteInt.h f6c5470b7db42318a3de1115757e94b76570ad7697ac547823e01f1166756f1d
+F src/sqlite3ext.h 51ee0eff1f843bd233c3441d220812964d2166f3c5e5714e7a3d847a778310c4
+F src/sqliteInt.h 3323b237e3f951a4e0297ce797fb7e65bade820f04aa90876a3cf7c1eee029eb
 F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -2043,8 +2043,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 64e6bd1c25d8e1dbfe511cba1921ff052c0fa4fe410fc9ce4435700a70cb88b1
-R 938acc948a8d28aa6e5bbb237d21a380
+P d3532eaed1cc671d8149b1bd34ead2a88fb83502a2898a5f60aea0a7daf18958
+R d4ed9da3aa6365c836a379cf03c29a8d
+T *branch * need-function
+T *sym-need-function *
+T -sym-trunk *
 U drh
-Z 95c647057214d80d38fbb5e9ad4c9cbc
+Z e80e56952de95f04df4da782eb785cf5
 # Remove this line to create a well-formed Fossil manifest.
index 7718a55d23988aef0a7e713f2bafcacfd807e8d8..0b24384b5f12df25bbc04d706a72108e14967b25 100644 (file)
@@ -1 +1 @@
-d3532eaed1cc671d8149b1bd34ead2a88fb83502a2898a5f60aea0a7daf18958
\ No newline at end of file
+cd67edc032983b5111ffcf6c73ca1308ef67cf2f16baa25788121827b3038d2f
\ No newline at end of file
index c36d51a4ecf31e65a2a8f93cc576ea786c00b2de..c9e1a892bea03fa47f01d1093c8eace3b7f6c3dc 100644 (file)
@@ -474,7 +474,28 @@ FuncDef *sqlite3FindFunction(
 
   if( pBest && (pBest->xSFunc || createFlag) ){
     return pBest;
+  }else if( db->xFuncNeeded!=0 ){
+    int rc;
+    int (*xFN)(void*,sqlite3*,const char*,int,int) = db->xFuncNeeded;
+    db->xFuncNeeded = 0;
+    rc = xFN(db->pFuncNeededArg,db,zName,nArg,enc);
+    db->xFuncNeeded = xFN;
+    pBest = 0;
+    bestScore = 0;
+    if( rc==SQLITE_OK ){
+      p = (FuncDef*)sqlite3HashFind(&db->aFunc,zName);
+      while( p ){
+        int score = matchQuality(p, nArg, enc);
+        if( score>bestScore ){
+          pBest = p;
+          bestScore = score;
+        }
+        p = p->pNext;
+      }
+      return pBest;
+    }
   }
+       
   return 0;
 }
 
index 8f21af13eed745ab7172c80431bdffac79329144..355b0bdb95080985e9095206228abb5704d6ae9e 100644 (file)
@@ -1219,6 +1219,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
     db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
   }
 
+  /* Free the function-needed payload pointer */
+  if( db->xFuncNeededFree ) db->xFuncNeededFree(db->pFuncNeededArg);
+
   /* Force xDisconnect calls on all virtual tables */
   disconnectAllVtab(db);
 
@@ -3705,6 +3708,28 @@ int sqlite3_collation_needed16(
 }
 #endif /* SQLITE_OMIT_UTF16 */
 
+/*
+** Register a collation sequence factory callback with the database handle
+** db. Replace any previously installed collation sequence factory.
+*/
+int sqlite3_function_needed(
+  sqlite3 *db,
+  void *pFuncNeededArg,
+  int (*xFuncNeeded)(void*,sqlite3*,const char*,int,int),
+  void (*xFuncNeededFree)(void*)
+){
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
+  sqlite3_mutex_enter(db->mutex);
+  if( db->xFuncNeededFree ) db->xFuncNeededFree(db->pFuncNeededArg);
+  db->pFuncNeededArg = pFuncNeededArg;
+  db->xFuncNeeded = xFuncNeeded;
+  db->xFuncNeededFree = xFuncNeededFree;
+  sqlite3_mutex_leave(db->mutex);
+  return SQLITE_OK;
+}
+
 #ifndef SQLITE_OMIT_DEPRECATED
 /*
 ** This function is now an anachronism. It used to be used to recover from a
index 9165f21f71420220070274faebbb21facd12680a..5382c2b24c835f22327c2618bb71733df96cbbc9 100644 (file)
@@ -5383,6 +5383,57 @@ static void shellUSleepFunc(
 #define OPEN_DB_KEEPALIVE   0x001   /* Return after error if true */
 #define OPEN_DB_ZIPFILE     0x002   /* Open as ZIP if name matches *.zip */
 
+/*
+** Unknown function callback
+*/
+static int shellUnknownFunction(
+  void *pUserData,
+  sqlite3 *db,
+  const char *zFunc,
+  int nArg,
+  int enc
+){
+  ShellState *p = (ShellState*)pUserData;
+  (void)enc;
+  (void)nArg;
+  if( sqlite3_stricmp(zFunc,"strtod")==0 ){
+    sqlite3_create_function(db, "strtod", 1, SQLITE_UTF8, 0,
+                            shellStrtod, 0, 0);
+  }else
+  if( sqlite3_stricmp(zFunc,"dtostr")==0 ){
+    sqlite3_create_function(db, "dtostr", 1, SQLITE_UTF8, 0,
+                            shellDtostr, 0, 0);
+    sqlite3_create_function(db, "dtostr", 2, SQLITE_UTF8, 0,
+                            shellDtostr, 0, 0);
+  }else
+  if( sqlite3_stricmp(zFunc,"shell_add_schema")==0 ){
+    sqlite3_create_function(db, "shell_add_schema", 3, SQLITE_UTF8, 0,
+                            shellAddSchemaName, 0, 0);
+  }else
+  if( sqlite3_stricmp(zFunc,"shell_module_schema")==0 ){
+    sqlite3_create_function(db, "shell_module_schema", 1, SQLITE_UTF8, 0,
+                            shellModuleSchema, 0, 0);
+  }else
+  if( sqlite3_stricmp(zFunc,"shell_putsnl")==0 ){
+    sqlite3_create_function(db, "shell_putsnl", 1, SQLITE_UTF8, p,
+                            shellPutsFunc, 0, 0);
+  }else
+  if( sqlite3_stricmp(zFunc,"usleep")==0 ){
+    sqlite3_create_function(db, "usleep",1,SQLITE_UTF8,0,
+                            shellUSleepFunc, 0, 0);
+  }
+#ifndef SQLITE_NOHAVE_SYSTEM
+  else
+  if( sqlite3_stricmp(zFunc,"edit")==0 ){
+    sqlite3_create_function(db, "edit", 1, SQLITE_UTF8, 0,
+                            editFunc, 0, 0);
+    sqlite3_create_function(db, "edit", 2, SQLITE_UTF8, 0,
+                            editFunc, 0, 0);
+  }
+#endif
+  return SQLITE_OK;
+}
+
 /*
 ** Make sure the database is open.  If it is not, then open it.  If
 ** the database fails to open, print an error message and exit.
@@ -5503,27 +5554,9 @@ static void open_db(ShellState *p, int openFlags){
     }
 #endif
 
-    sqlite3_create_function(p->db, "strtod", 1, SQLITE_UTF8, 0,
-                            shellStrtod, 0, 0);
-    sqlite3_create_function(p->db, "dtostr", 1, SQLITE_UTF8, 0,
-                            shellDtostr, 0, 0);
-    sqlite3_create_function(p->db, "dtostr", 2, SQLITE_UTF8, 0,
-                            shellDtostr, 0, 0);
-    sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
-                            shellAddSchemaName, 0, 0);
-    sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
-                            shellModuleSchema, 0, 0);
-    sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
-                            shellPutsFunc, 0, 0);
-    sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0,
-                            shellUSleepFunc, 0, 0);
-#ifndef SQLITE_NOHAVE_SYSTEM
-    sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
-                            editFunc, 0, 0);
-    sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
-                            editFunc, 0, 0);
-#endif
+    sqlite3_function_needed(p->db, p, shellUnknownFunction, 0);
 
     if( p->openMode==SHELL_OPEN_ZIPFILE ){
       char *zSql = sqlite3_mprintf(
          "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename);
index 59d9986c5210844b38b444661ef78cd3917c5b12..dfe3d97de44569c7660c292d7abdf4331a0846a5 100644 (file)
@@ -6206,6 +6206,54 @@ int sqlite3_create_collation16(
   int(*xCompare)(void*,int,const void*,int,const void*)
 );
 
+/*
+** CAPI3REF: Function Needed Callbacks
+** METHOD: sqlite3
+**
+** The sqlite3_function_needed(D,P,C,X) interface registers a callback
+** function C which is invoked whenever the SQL parser encounters an
+** unknown SQL function.  The callback may optionally register a suitable
+** implementation for that unknown function (using [sqlite3_create_function()]
+** or similar), in which case parsing will continue normally.  In this way,
+** applications with hundreds or thousands of seldom-used application defined
+** SQL functions can avoid having register them at start-up and instead
+** register each function if and only if it it actually gets used.
+**
+** ^If the callback function C has been registered using the
+** sqlite3_function_needed(D,P,C,X), then whenever the SQL parser encounters
+** an unknown SQL function, it will invoke the C callback with 5 arguments:
+** P, D, F, N, E.  P is a copy of the generic pointer P parameter to
+** the original sqlite3_function_needed() call that registered the
+** callback.  D is the database connection.  F is the name of the unknown
+** function (UTF-8 encoded and zero-terminated but in an arbitrary case).
+** N is the number of arguments on the F function.
+** E is the preferred text encoding.
+**
+** If the C callback registers a new function with the correct
+** name and number of arguments and if the callback returns SQLITE_OK, then
+** the newly registered function is used and parsing continues.  If an
+** appropriate function does not get registered, or if the callback returns
+** anything other than SQLITE_OK, then an "unknown function" error is generated
+** as normal.
+**
+** Only a single function-needed callback is supported per database connection.
+** Each call to sqlite3_function_needed() replaces the callback identified
+** by the previous call to sqlite3_function_needed().  The function-needed
+** callback mechanism may be disabled by invoking sqlite3_function_needed(D,P,C,X)
+** using a NULL pointer for the C parameter.
+**
+** The X argument to sqlite3_function_needed(D,P,C,X) is an optional
+** destructor for generic pointer parameter P.  If X and C are both not NULL,
+** then X(P) is invoked when the database connection closes or at the next
+** call to sqlite3_function_needed().
+*/
+int sqlite3_function_needed(
+  sqlite3*,
+  void*,
+  int(*)(void*,sqlite3*,const char*,int,int),
+  void(*)(void*)
+);
+
 /*
 ** CAPI3REF: Collation Needed Callbacks
 ** METHOD: sqlite3
index 19e030028adfeb18e524dc4ad7cae3f294a8db81..450e8ab0ff649d84e8fe06e77dffa82e80d9d775 100644 (file)
@@ -361,6 +361,8 @@ struct sqlite3_api_routines {
   int (*value_encoding)(sqlite3_value*);
   /* Version 3.41.0 and later */
   int (*is_interrupted)(sqlite3*);
+  /* Version 3.43.0 and later */
+  int (*function_needed)(sqlite3*,void*,const char*,int,int);
 };
 
 /*
@@ -689,6 +691,8 @@ typedef int (*sqlite3_loadext_entry)(
 #define sqlite3_value_encoding         sqlite3_api->value_encoding
 /* Version 3.41.0 and later */
 #define sqlite3_is_interrupted         sqlite3_api->is_interrupted
+/* Version 3.43.0 and later */
+#define sqlite3_function_needed        sqlite3_api->function_needed
 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
 
 #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
index 8eae8d166ad1363ca8a1ceb9e795ec5c5a6d9ead..4773c1345815994cae613636ac485d86977bcf93 100644 (file)
@@ -1674,6 +1674,9 @@ struct sqlite3 {
   int (*xWalCallback)(void *, sqlite3 *, const char *, int);
   void *pWalArg;
 #endif
+  int(*xFuncNeeded)(void*,sqlite3*,const char*,int,int);
+  void *pFuncNeededArg;
+  void(*xFuncNeededFree)(void*);
   void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
   void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
   void *pCollNeededArg;