-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
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
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
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
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.
-d3532eaed1cc671d8149b1bd34ead2a88fb83502a2898a5f60aea0a7daf18958
\ No newline at end of file
+cd67edc032983b5111ffcf6c73ca1308ef67cf2f16baa25788121827b3038d2f
\ No newline at end of file
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;
}
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);
}
#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
#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.
}
#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);
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
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);
};
/*
#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)
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;