const char *zTbl, /* Name of content table */
const char ***pazCol, /* OUT: Malloc'd array of column names */
int *pnCol, /* OUT: Size of array *pazCol */
- int *pnStr /* OUT: Bytes of string content */
+ int *pnStr, /* OUT: Bytes of string content */
+ char **pzErr /* OUT: error message */
){
int rc = SQLITE_OK; /* Return code */
char *zSql; /* "SELECT *" statement on zTbl */
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
}
sqlite3_free(zSql);
if( nCol==0 ){
sqlite3_free((void*)aCol);
aCol = 0;
- rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString);
+ rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr);
/* If a languageid= option was specified, remove the language id
** column from the aCol[] array. */
-C Add\sthe\s".open"\scommand\sto\sthe\scommand-line\sshell.\nCherrypick\sfrom\s[21eccb919441].
-D 2015-05-21T00:50:37.386
+C Do\snot\sallow\svirtual\stable\sconstructors\sto\sbe\scalled\srecursively.\nCherrypick\s[0a72726da21581ab]
+D 2015-05-21T01:04:17.693
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c a62e09140c00f9c401efca661e7f2ae9909194f6
+F ext/fts3/fts3.c a2a545a38d9d4d2574608da189284b5f8ba00d6d
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h d1d7f964ddee067bcd16a6af4ba7ecf66220056d
F ext/fts3/fts3_aux.c 5205182bd8f372782597888156404766edf5781e
F src/vdbemem.c fb0ac964ccbcd94f595eb993c05bfd9c52468a4a
F src/vdbesort.c b25814d385895544ebc8118245c8311ded7f81c9
F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843
-F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847
+F src/vtab.c a078fb78c0f7bfa4a365495badf53581d512b648
F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2
F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659
F test/fts4aa.test 6e7f90420b837b2c685f3bcbe84c868492d40a68
-F test/fts4content.test 17b2360f7d1a9a7e5aa8022783f5c5731b6dfd4f
+F test/fts4content.test 655e5036c98272c93d8ec0eb8c6b7100928faeae
F test/fts4langid.test 2081c357bb6f170f34ef8e08c6abb88002b95c69
F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P 00bb9c9ce4f465e6ac321ced2a9d0062dc364669
-Q +21eccb919441bd111ba414dde3f00862822e2c99
-R feff229c300afcfceea2f853e4bccd1c
-T *branch * branch-3.7.11
-T *sym-branch-3.7.11 *
-T -sym-trunk *
+P a71e2a72c592f014051a00af9c7cb5c390612cb2
+Q +0a72726da21581ab16cb3e964bd825b8f2e931e4
+R 8a644e69b3a7726913eb23696e1937e1
U drh
-Z 03df1d8360641e51d6edb83127f6df82
+Z 95187feec4c184bfd6cb010b3ad956ea
-a71e2a72c592f014051a00af9c7cb5c390612cb2
\ No newline at end of file
+0f0694e4245083f6abb4ce104c39add45f2eb71a
\ No newline at end of file
struct VtabCtx {
Table *pTab;
VTable *pVTable;
+ VtabCtx *pPrior; /* Parent context (if any) */
+ int bDeclared; /* True after sqlite3_declare_vtab() is called */
};
/*
const char *const*azArg = (const char *const*)pTab->azModuleArg;
int nArg = pTab->nModuleArg;
char *zErr = 0;
- char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
+ char *zModuleName;
+ VtabCtx *pCtx;
+
+ /* Check that the virtual-table is not already being initialized */
+ for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
+ if( pCtx->pTab==pTab ){
+ *pzErr = sqlite3MPrintf(db,
+ "vtable constructor called recursively: %s", pTab->zName
+ );
+ return SQLITE_LOCKED;
+ }
+ }
+ zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
if( !zModuleName ){
return SQLITE_NOMEM;
}
assert( xConstruct );
sCtx.pTab = pTab;
sCtx.pVTable = pVTable;
+ sCtx.pPrior = db->pVtabCtx;
+ sCtx.bDeclared = 0;
db->pVtabCtx = &sCtx;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
- db->pVtabCtx = 0;
+ db->pVtabCtx = sCtx.pPrior;
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
+ assert( sCtx.pTab==pTab );
if( SQLITE_OK!=rc ){
if( zErr==0 ){
** the sqlite3_vtab object if successful. */
pVTable->pVtab->pModule = pMod->pModule;
pVTable->nRef = 1;
- if( sCtx.pTab ){
+ if( sCtx.bDeclared==0 ){
const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
sqlite3VtabUnlock(pVTable);
** virtual table module.
*/
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
+ VtabCtx *pCtx = db->pVtabCtx;
Parse *pParse;
-
int rc = SQLITE_OK;
Table *pTab;
char *zErr = 0;
sqlite3_mutex_enter(db->mutex);
- if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
+ if( !pCtx || pCtx->bDeclared ){
sqlite3Error(db, SQLITE_MISUSE, 0);
sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE_BKPT;
}
+ pTab = pCtx->pTab;
assert( (pTab->tabFlags & TF_Virtual)!=0 );
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
pParse->pNewTable->nCol = 0;
pParse->pNewTable->aCol = 0;
}
- db->pVtabCtx->pTab = 0;
+ pCtx->bDeclared = 1;
}else{
sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
# 8.* - Test that if the content=xxx and prefix options are used together,
# the 'rebuild' command still works.
#
+# 11.* - Test that circular references (e.g. "t1(content=t1)") are
+# detected.
+#
do_execsql_test 1.1.1 {
CREATE TABLE t1(a, b, c);
#
do_catchsql_test 6.1.1 {
CREATE VIRTUAL TABLE ft7 USING fts4(content=t7);
-} {1 {vtable constructor failed: ft7}}
+} {1 {no such table: main.t7}}
do_execsql_test 6.2.1 {
CREATE TABLE t7(one, two);
}
do_catchsql_test 6.2.4 {
SELECT * FROM ft7;
-} {1 {vtable constructor failed: ft7}}
+} {1 {no such table: main.t7}}
do_execsql_test 6.2.5 {
CREATE TABLE t7(x, y);
INSERT INTO t7 VALUES('A B', 'B A');
do_execsql_test 8.5 { SELECT rowid FROM ft10 WHERE b MATCH 'abav*'; } {3}
do_execsql_test 8.6 { SELECT rowid FROM ft10 WHERE ft10 MATCH 'abas*'; } {1}
+#-------------------------------------------------------------------------
+# Test cases 9.*
+#
+reset_db
+register_echo_module [sqlite3_connection_pointer db]
+
+do_execsql_test 9.1 {
+ CREATE TABLE tbl1(a, b);
+ INSERT INTO tbl1 VALUES('a b', 'c d');
+ INSERT INTO tbl1 VALUES('e f', 'a b');
+ CREATE VIRTUAL TABLE e1 USING echo(tbl1);
+ CREATE VIRTUAL TABLE ft1 USING fts4(content=e1);
+ INSERT INTO ft1(ft1) VALUES('rebuild');
+}
+
+do_execsql_test 9.2 {
+ SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'e'
+} {2 {e f} {a b}}
+
+do_execsql_test 9.3 {
+ SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'a'
+} {1 {a b} {c d} 2 {e f} {a b}}
+
+do_execsql_test 9.4 {
+ DELETE FROM ft1 WHERE docid=1;
+}
+
+do_execsql_test 9.5 {
+ SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'a'
+} {2 {e f} {a b}}
+
+do_execsql_test 9.6 {
+ INSERT INTO ft1(ft1) VALUES('rebuild');
+ SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'a'
+} {1 {a b} {c d} 2 {e f} {a b}}
+
+#-------------------------------------------------------------------------
+# Test cases 11.*
+#
+reset_db
+
+do_catchsql_test 11.1 {
+ CREATE VIRTUAL TABLE x1 USING fts4(content=x1);
+} {1 {vtable constructor called recursively: x1}}
+
finish_test