Add the optional non-found-callback to the swarm-vtab.
FossilOrigin-Name: a94e2f600bc766fb459418e674b842628ba21e27cf9942c00cd533507d7b35fe
This commit is contained in:
parent
d83e082524
commit
a5aed4b10b
@ -36,7 +36,7 @@
|
||||
**
|
||||
** A "unionvtab" virtual table is created as follows:
|
||||
**
|
||||
** CREATE VIRTUAL TABLE <name> USING unionvtab(<sql statement>);
|
||||
** CREATE VIRTUAL TABLE <name> USING unionvtab(<sql-statement>);
|
||||
**
|
||||
** The implementation evalutes <sql statement> whenever a unionvtab virtual
|
||||
** table is created or opened. It should return one row for each source
|
||||
@ -58,12 +58,15 @@
|
||||
**
|
||||
** A "swarmvtab" virtual table is created similarly to a unionvtab table:
|
||||
**
|
||||
** CREATE VIRTUAL TABLE <name> USING swarmvtab(<sql statement>);
|
||||
** CREATE VIRTUAL TABLE <name>
|
||||
** USING swarmvtab(<sql-statement>, <callback>);
|
||||
**
|
||||
** The difference is that for a swarmvtab table, the first column returned
|
||||
** by the <sql statement> must return a path or URI that can be used to open
|
||||
** the database file containing the source table.
|
||||
**
|
||||
** the database file containing the source table. The <callback> option
|
||||
** is optional. If included, it is the name of an application-defined
|
||||
** SQL function that is invoked with the URI of the file, if the file
|
||||
** does not already exist on disk.
|
||||
*/
|
||||
|
||||
#include "sqlite3ext.h"
|
||||
@ -143,6 +146,7 @@ struct UnionTab {
|
||||
|
||||
/* Used by swarmvtab only */
|
||||
char *zSourceStr; /* Expected unionSourceToStr() value */
|
||||
char *zNotFoundCallback; /* UDF to invoke if file not found on open */
|
||||
UnionSrc *pClosable; /* First in list of closable sources */
|
||||
int nOpen; /* Current number of open sources */
|
||||
int nMaxOpen; /* Maximum number of open sources */
|
||||
@ -379,6 +383,7 @@ static int unionDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_close(pSrc->db);
|
||||
}
|
||||
sqlite3_free(pTab->zSourceStr);
|
||||
sqlite3_free(pTab->zNotFoundCallback);
|
||||
sqlite3_free(pTab->aSrc);
|
||||
sqlite3_free(pTab);
|
||||
}
|
||||
@ -491,6 +496,35 @@ static int unionSourceCheck(UnionTab *pTab, char **pzErr){
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to open the swarmvtab database. If initially unable, invoke the
|
||||
** not-found callback UDF and then try again.
|
||||
*/
|
||||
static int unionOpenDatabaseInner(UnionTab *pTab, UnionSrc *pSrc, char **pzErr){
|
||||
int rc = SQLITE_OK;
|
||||
static const int openFlags =
|
||||
SQLITE_OPEN_READONLY | SQLITE_OPEN_URI;
|
||||
rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
|
||||
if( rc==SQLITE_OK ) return rc;
|
||||
if( pTab->zNotFoundCallback ){
|
||||
char *zSql = sqlite3_mprintf("SELECT \"%w\"(%Q);",
|
||||
pTab->zNotFoundCallback, pSrc->zFile);
|
||||
if( zSql==0 ){
|
||||
*pzErr = sqlite3_mprintf("out of memory");
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqlite3_exec(pTab->db, zSql, 0, 0, pzErr);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(pSrc->db));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function may only be called for swarmvtab tables. The results of
|
||||
** calling it on a unionvtab table are undefined.
|
||||
@ -513,10 +547,8 @@ static int unionOpenDatabase(UnionTab *pTab, int iSrc, char **pzErr){
|
||||
assert( pTab->bSwarm && iSrc<pTab->nSrc );
|
||||
if( pSrc->db==0 ){
|
||||
unionCloseSources(pTab, pTab->nMaxOpen-1);
|
||||
rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, SQLITE_OPEN_READONLY, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(pSrc->db));
|
||||
}else{
|
||||
rc = unionOpenDatabaseInner(pTab, pSrc, pzErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
char *z = unionSourceToStr(&rc, pTab, pSrc, pzErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pTab->zSourceStr==0 ){
|
||||
@ -598,10 +630,11 @@ static int unionFinalizeCsrStmt(UnionCsr *pCsr){
|
||||
**
|
||||
** The argv[] array contains the following:
|
||||
**
|
||||
** argv[0] -> module name ("unionvtab")
|
||||
** argv[0] -> module name ("unionvtab" or "swarmvtab")
|
||||
** argv[1] -> database name
|
||||
** argv[2] -> table name
|
||||
** argv[3] -> SQL statement
|
||||
** argv[4] -> not-found callback UDF name
|
||||
*/
|
||||
static int unionConnect(
|
||||
sqlite3 *db,
|
||||
@ -619,7 +652,7 @@ static int unionConnect(
|
||||
/* unionvtab tables may only be created in the temp schema */
|
||||
*pzErr = sqlite3_mprintf("%s tables must be created in TEMP schema", zVtab);
|
||||
rc = SQLITE_ERROR;
|
||||
}else if( argc!=4 ){
|
||||
}else if( argc!=4 && argc!=5 ){
|
||||
*pzErr = sqlite3_mprintf("wrong number of arguments for %s", zVtab);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
@ -685,6 +718,12 @@ static int unionConnect(
|
||||
unionFinalize(&rc, pStmt, pzErr);
|
||||
pStmt = 0;
|
||||
|
||||
/* Capture the not-found callback UDF name */
|
||||
if( argc>=5 ){
|
||||
pTab->zNotFoundCallback = unionStrdup(&rc, argv[4]);
|
||||
unionDequote(pTab->zNotFoundCallback);
|
||||
}
|
||||
|
||||
/* It is an error if the SELECT statement returned zero rows. If only
|
||||
** because there is no way to determine the schema of the virtual
|
||||
** table in this case. */
|
||||
|
15
manifest
15
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sfurther\stest\scases\sfor\sswarmvtab.\sAnd\sminor\scode\schanges.
|
||||
D 2017-08-04T17:39:13.161
|
||||
C Add\sthe\soptional\snon-found-callback\sto\sthe\sswarm-vtab.
|
||||
D 2017-08-04T20:15:08.335
|
||||
F Makefile.in d9873c9925917cca9990ee24be17eb9613a668012c85a343aef7e5536ae266e8
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 02b469e9dcd5b7ee63fc1fb05babc174260ee4cfa4e0ef2e48c3c6801567a016
|
||||
@ -281,7 +281,7 @@ F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c a4723b6aff748a417b5091b68a46443265c40f0d
|
||||
F ext/misc/stmt.c 6f16443abb3551e3f5813bb13ba19a30e7032830015b0f92fe0c0453045c0a11
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/unionvtab.c c30398ece1cfe07d97334acdf3bd0f082782b493af254557f389c8fc1635aa7f
|
||||
F ext/misc/unionvtab.c cd472d02a7a0c77a3cecdd3cc995cd37fa902be845cd6b1c36a66da4ce0db99a
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vfsstat.c bf10ef0bc51e1ad6756629e1edb142f7a8db1178
|
||||
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
|
||||
@ -1232,6 +1232,7 @@ F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
|
||||
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
|
||||
F test/swarmvtab.test fbb2415797477588337a54e3bc0ff8e1981d325d22b9e75a527438e79d926a6a
|
||||
F test/swarmvtab2.test 038ef9bcad6fd2fb9e395196080cf23e223ddb1219015049a61540c161bc577d
|
||||
F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
|
||||
F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
|
||||
F test/sync2.test 6be8ed007fa063b147773c1982b5bdba97a32badc536bdc6077eff5cf8710ece
|
||||
@ -1641,7 +1642,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 7ae20eac83fc053dc1bbc42501dd41f77445a6b9a33cfa42b899fc7a18c637ab
|
||||
R f110030d9eaed7a6ec593149c64799ea
|
||||
U dan
|
||||
Z 1047b1cef8ad6de0923837acad2fcea1
|
||||
P 0f82d3b9dd5bd2e34a984c78e4a4a87921cf3e15b01b611133378c0ea9901010
|
||||
R 77c16cf4cab7b7344ed73948b800d412
|
||||
U drh
|
||||
Z 7560f1ef26bd2571437b3895f1c10f52
|
||||
|
@ -1 +1 @@
|
||||
0f82d3b9dd5bd2e34a984c78e4a4a87921cf3e15b01b611133378c0ea9901010
|
||||
a94e2f600bc766fb459418e674b842628ba21e27cf9942c00cd533507d7b35fe
|
74
test/swarmvtab2.test
Normal file
74
test/swarmvtab2.test
Normal file
@ -0,0 +1,74 @@
|
||||
# 2017-07-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 the "swarmvtab" extension
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix swarmvtab
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
db close
|
||||
foreach name [glob -nocomplain test*.db] {
|
||||
forcedelete $name
|
||||
}
|
||||
sqlite3 db test.db
|
||||
load_static_extension db unionvtab
|
||||
proc create_database {filename} {
|
||||
sqlite3 dbx $filename
|
||||
set num [regsub -all {[^0-9]+} $filename {}]
|
||||
set num [string trimleft $num 0]
|
||||
set start [expr {$num*1000}]
|
||||
set end [expr {$start+999}]
|
||||
dbx eval {
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY,b);
|
||||
WITH RECURSIVE c(x) AS (
|
||||
VALUES($start) UNION ALL SELECT x+1 FROM c WHERE x<$end
|
||||
)
|
||||
INSERT INTO t2(a,b) SELECT x, printf('**%05d**',x) FROM c;
|
||||
}
|
||||
dbx close
|
||||
}
|
||||
db func create_database create_database
|
||||
do_execsql_test 100 {
|
||||
CREATE TABLE t1(filename, tablename, istart, iend);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<99)
|
||||
INSERT INTO t1 SELECT printf('test%03d.db',x),'t2',x*1000,x*1000+999 FROM c;
|
||||
CREATE VIRTUAL TABLE temp.v1 USING swarmvtab(
|
||||
'SELECT * FROM t1', 'create_database'
|
||||
);
|
||||
} {}
|
||||
do_execsql_test 110 {
|
||||
SELECT b FROM v1 WHERE a=3875;
|
||||
} {**03875**}
|
||||
do_test 120 {
|
||||
lsort [glob -nocomplain test?*.db]
|
||||
} {test001.db test003.db}
|
||||
do_execsql_test 130 {
|
||||
SELECT b FROM v1 WHERE a BETWEEN 3999 AND 4000 ORDER BY a;
|
||||
} {**03999** **04000**}
|
||||
do_test 140 {
|
||||
lsort [glob -nocomplain test?*.db]
|
||||
} {test001.db test003.db test004.db}
|
||||
do_execsql_test 150 {
|
||||
SELECT b FROM v1 WHERE a>=99998;
|
||||
} {**99998** **99999**}
|
||||
do_test 160 {
|
||||
lsort -dictionary [glob -nocomplain test?*.db]
|
||||
} {test001.db test003.db test004.db test099.db}
|
||||
|
||||
finish_test
|
Loading…
Reference in New Issue
Block a user