From b9bb7c187e5cc9cce7d4e6fac38533339e865f33 Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 11 Jun 2006 23:41:55 +0000 Subject: [PATCH] Progress toward CREATE VIRTUAL TABLE. Still not even close to working... (CVS 3211) FossilOrigin-Name: 898ec36b4102aaa03979f8f5c510936e57e2ae48 --- Makefile.in | 7 +- main.mk | 7 +- manifest | 55 ++++++------ manifest.uuid | 2 +- src/build.c | 23 +++-- src/delete.c | 4 +- src/expr.c | 14 +-- src/insert.c | 4 +- src/main.c | 8 +- src/parse.y | 19 +++-- src/select.c | 96 ++++++++++----------- src/sqlite.h.in | 8 +- src/sqliteInt.h | 53 ++++++++---- src/tclsqlite.c | 4 +- src/test1.c | 8 +- src/test8.c | 136 ++++++++++++++++++++++++++++++ src/tokenize.c | 5 +- src/update.c | 4 +- src/vdbe.c | 38 +++++++-- src/vdbe.h | 4 +- src/vtab.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++ src/where.c | 6 +- test/insert.test | 4 +- test/select6.test | 4 +- test/view.test | 10 +-- test/vtab1.test | 53 ++++++++++++ 26 files changed, 637 insertions(+), 150 deletions(-) create mode 100644 src/test8.c create mode 100644 src/vtab.c create mode 100644 test/vtab1.test diff --git a/Makefile.in b/Makefile.in index 5c600c6c1e..26ada6818d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -130,7 +130,7 @@ LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \ select.lo table.lo tokenize.lo trigger.lo update.lo \ util.lo vacuum.lo \ vdbe.lo vdbeapi.lo vdbeaux.lo vdbefifo.lo vdbemem.lo \ - where.lo utf.lo legacy.lo + where.lo utf.lo legacy.lo vtab.lo # All of the source code files. # @@ -184,6 +184,7 @@ SRC = \ $(TOP)/src/vdbefifo.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbeInt.h \ + $(TOP)/src/vtab.c \ $(TOP)/src/where.c # Source code to the test files. @@ -206,6 +207,7 @@ TESTSRC = \ $(TOP)/src/test5.c \ $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ + $(TOP)/src/test8.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_server.c \ @@ -435,6 +437,9 @@ vdbefifo.lo: $(TOP)/src/vdbefifo.c $(VDBEHDR) vdbemem.lo: $(TOP)/src/vdbemem.c $(VDBEHDR) $(LTCOMPILE) -c $(TOP)/src/vdbemem.c +vtab.lo: $(TOP)/src/vtab.c $(VDBEHDR) + $(LTCOMPILE) -c $(TOP)/src/vtab.c + where.lo: $(TOP)/src/where.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/where.c diff --git a/main.mk b/main.mk index c51b7aa1db..5a0233d6b5 100644 --- a/main.mk +++ b/main.mk @@ -63,7 +63,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \ select.o table.o tclsqlite.o tokenize.o trigger.o \ update.o util.o vacuum.o \ vdbe.o vdbeapi.o vdbeaux.o vdbefifo.o vdbemem.o \ - where.o utf.o legacy.o + where.o utf.o legacy.o vtab.o # All of the source code files. # @@ -117,6 +117,7 @@ SRC = \ $(TOP)/src/vdbefifo.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbeInt.h \ + $(TOP)/src/vtab.c \ $(TOP)/src/where.c # Source code to the test files. @@ -139,6 +140,7 @@ TESTSRC = \ $(TOP)/src/test5.c \ $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ + $(TOP)/src/test8.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_server.c \ @@ -360,6 +362,9 @@ vdbefifo.o: $(TOP)/src/vdbefifo.c $(VDBEHDR) vdbemem.o: $(TOP)/src/vdbemem.c $(VDBEHDR) $(TCCX) -c $(TOP)/src/vdbemem.c +vtab.o: $(TOP)/src/vtab.c $(VDBEHDR) + $(TCCX) -c $(TOP)/src/vtab.c + where.o: $(TOP)/src/where.c $(HDR) $(TCCX) -c $(TOP)/src/where.c diff --git a/manifest b/manifest index d87618f2c1..6a0c4f192a 100644 --- a/manifest +++ b/manifest @@ -1,6 +1,6 @@ -C Basic\sparsing\sof\sCREATE\sVIRTUAL\sTABLE\sstatements.\s(CVS\s3210) -D 2006-06-10T13:29:32 -F Makefile.in 50d948a8c4eda30ebb5799b661bd4c2de11824d0 +C Progress\stoward\sCREATE\sVIRTUAL\sTABLE.\s\sStill\snot\seven\sclose\sto\sworking...\s(CVS\s3211) +D 2006-06-11T23:41:55 +F Makefile.in 56fd6261e83f60724e6dcd764e06ab68cbd53909 F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F VERSION 301ed2b2c08f5cca242ea56e50a9ed0264a3eb76 @@ -19,7 +19,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826 -F main.mk 9a328281e0d992dcbbf502ec868793dca0a1d7b9 +F main.mk a7796b31f0d7e16ea57ff00ac88b97befe519977 F mkdll.sh 919df5efde876194e3102c6ebc60657d38949909 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5 @@ -36,20 +36,20 @@ F src/attach.c 27a31d3b89d7ebb5b358847607b1ec795384123c F src/auth.c 9ae84d2d94eb96195e04515715e08e85963e96c2 F src/btree.c ed343b3dbcbc7da9ac481ef2b98c4239fe6d9629 F src/btree.h 40055cfc09defd1146bc5b922399c035f969e56d -F src/build.c a64e4765ca1148e191742af306db5b70d821d0c9 +F src/build.c f541d3e9afed5eb8a397353b2b54c23d8d531e97 F src/callback.c fd9bb39f7ff6b52bad8365617abc61c720640429 F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 F src/date.c cd2bd5d1ebc6fa12d6312f69789ae5b0a2766f2e -F src/delete.c 2dea1a83e6ef534346e74fd03114d3a7b16f08fc +F src/delete.c f9a8c7837adb4bb4810a698a041a88d5ec7bfa9a F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c f1ad18d0b7bb3abbf09cb30871ae6e7618447bc5 +F src/expr.c 3ea9b26c6cdb7bcf0715c1b6aa0f7f5e813f61eb F src/func.c acbbf533b55221f26760798d99b37de3ac5678fe F src/hash.c 449f3d6620193aa557f5d86cbc5cc6b87702b185 F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564 -F src/insert.c 1ae4b8ff5549497808e1b57b9243abcb599fd02f +F src/insert.c 2c3eeb4bcde13c1006824ef14953c2fdad31cf36 F src/legacy.c fa15d505dd4e45044177ee4d1c6aeaf8c836d390 F src/loadext.c 528a3c130ca32b83609593605ebeec235de4e55b -F src/main.c 0147dbf7ba04563749aef77ef709b78dd86d6771 +F src/main.c f4397bf95216496e49db2153789788f4b1207b91 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/os.c 59f05de8c5777c34876607114a2fbe55ae578235 F src/os.h 46fad85c707ad8643622bab9d894a642940850aa @@ -64,43 +64,45 @@ F src/os_win.c c6976ae50b61fb5b7dce399e578aa1865f02b84f F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c ddd05666bb89808a516baef2c186d6a75887ae90 F src/pager.h 43f32f3847421f7502cfbb66f4eb2302b8033818 -F src/parse.y 79c324627c8145d307a80a13fb18be1d1d63dff8 +F src/parse.y 05cd1419b625df99ea9776e2c767d2a792d84345 F src/pragma.c 27d5e395c5d950931c7ac4fe610e7c2993e2fa55 F src/prepare.c bbf12d3147116b284b157232efaef3bbe5df08fc F src/printf.c 7029e5f7344a478394a02c52837ff296ee1ab240 F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261 -F src/select.c 8daba07a04a6d41f5267ea8353324cbe5a210e14 +F src/select.c 38eda11d950ed5e631ea9054f84a4a8b9e9b39d8 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c b9eb3ed4d3ab41fbf630eabb602f3c9d20fc737a -F src/sqlite.h.in fadc690a16e8da1215d3f4bdf6a2501e41516c25 +F src/sqlite.h.in ca30260d7815ee68be410e1fa0bd1f131c86cf10 F src/sqlite3ext.h 127bd394c8eea481f2ac9b754bf399dbfc818b75 -F src/sqliteInt.h c1c752970e90570750be529d9d22111211614381 +F src/sqliteInt.h 90957da628f83fa7d57c35b239573496642393c0 F src/table.c f64ec4fbfe333f8df925bc6ba494f55e05b0e75e -F src/tclsqlite.c 5ae9f08f7af7fe80d38fbccc4f5359f272643af1 -F src/test1.c becd9202b733debc607b5aec43002769730e1f71 +F src/tclsqlite.c 0b2a04cfc1b4298adfbe90a754cfbbe207aca11a +F src/test1.c 88291fa6674dcd409b1c9d76d3119151d4b81a50 F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b F src/test3.c 86e99724ee898b119ed575ef9f98618afe7e5e5d F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3 +F src/test8.c 210f2109333e3373a1cb814e22e7b6b33e1e0a20 F src/test_async.c e3deaedd4d86a56391b81808fde9e44fbd92f1d3 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3 F src/test_server.c a6460daed0b92ecbc2531b6dc73717470e7a648c -F src/tokenize.c 91dc520980c0e2fb9265046adf8b7a86eff881dd +F src/tokenize.c 279c62792222e0ae6efc4f7609bc47301dde1ef3 F src/trigger.c 48bbb94c11954c8e132efcc04478efe8304c4196 -F src/update.c 34add66fcd3301b33b6e4c4c813f4e408f7ee4a0 +F src/update.c 0186f09414a6578156d40666becc964f85c2a616 F src/utf.c ab81ac59084ff1c07d421eb1a0a84ec809603b44 F src/util.c ca6ee72772c0f5dc04d2e0ab1973fd3b6a9bf79d F src/vacuum.c 5b37d0f436f8e1ffacd17934e44720b38d2247f9 -F src/vdbe.c a4c970bd74a5af20bf4627f704a634ceff8ff68d -F src/vdbe.h 44ff995a8b4e87016794095273e9e7300f0001bb +F src/vdbe.c 2547e931baf0f35cc8df77fdb18004a9f987bc6a +F src/vdbe.h 190d85a37658c2397be75a4c70bbc02ebc4ec0ba F src/vdbeInt.h 85cd5f81d38edb1b8f4786f407c77a7a3ba636fb F src/vdbeapi.c 7dc662e7c905ce666bb506dced932e0307115cbf F src/vdbeaux.c 4002e6b19d7c9719cb81f9797316b9ad118e4370 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3 -F src/where.c 06ec443109d8aec7be6d491ef31f72bc08af2c75 +F src/vtab.c 4ace1448bdba6a13d93c7642aa66447f8a5cd63c +F src/where.c 3dc5269ba552c0db39247f6bbc98b312ae786863 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/all.test 5df90d015ca63fcef2a4b62c24f7316b66c4bfd4 @@ -175,7 +177,7 @@ F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d F test/index.test e65df12bed94b2903ee89987115e1578687e9266 F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test f66718cd92ce1216819d47e6a156755e4b2c4ca1 -F test/insert.test b4d43f8e75e203fe51bc06cacf3636081903dcd1 +F test/insert.test 42e26d9192f36859938765e6817fb957cf19532b F test/insert2.test 5a20e1ace5fa0800b58d28284212290189b49aed F test/insert3.test 0096bd9766f94f4fa06ef712658e590b782cb44f F test/interrupt.test cd24dc5bedd02325be4bfa5d6209fae01c465157 @@ -231,7 +233,7 @@ F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3 F test/select3.test 33c78663e6b1b41220dcec4eb6affb1a05001ffe F test/select4.test d0280e3b6d760d1cff0fcc2a65ecb0611aec3df2 F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce -F test/select6.test d8ea108b65607399580f2765df0aee5e464b0fd8 +F test/select6.test a4e97b713b096f17414f50d078ec4efe7dc43253 F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6 F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5 F test/shared.test 0ed247941236788c255b3b29b5a82d5ca71b6432 @@ -284,7 +286,8 @@ F test/utf16align.test 7360e84472095518c56746f76b1f9d4dce99fb4d F test/vacuum.test 37f998b841cb335397c26d9bbc3457182af2565f F test/vacuum2.test 5aea8c88a65cb29f7d175296e7c819c6158d838c F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 -F test/view.test b0aeb933cc9dc5bb44d87f3859f3763d770f0153 +F test/view.test 16e2774fe35e47a07ac4471b7f0bcc948b1aa6d5 +F test/vtab1.test 9029c3ef19f1db3eebb2554b4db12e04b39a30ca F test/where.test ee7c9a6659b07e1ee61177f6e7ff71565ee2c9df F test/where2.test a16476a5913e75cf65b38f2daa6157a6b7791394 F test/where3.test 3b5ad2c58069e12be2bd86bc5e211a82810521aa @@ -360,7 +363,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 39e3427813135601a7417c96e55b410fa89ac1f5 -R ca50c82454da9812f6118b6e9d547ee0 +P 66370cb99bd93abb33e1e8433672da45e1795f78 +R 9ff37f743d5a6a690e7a66e29bc79ec5 U drh -Z 20f490cb0723888395733c25c97f6fa4 +Z 6146abfd990542c70d1912af93fdb676 diff --git a/manifest.uuid b/manifest.uuid index cd1dbfe70c..cb8e1fd491 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -66370cb99bd93abb33e1e8433672da45e1795f78 \ No newline at end of file +898ec36b4102aaa03979f8f5c510936e57e2ae48 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 74cf00accc..0be7c92f94 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.395 2006/06/10 13:29:32 drh Exp $ +** $Id: build.c,v 1.396 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" #include @@ -533,12 +533,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ #ifndef SQLITE_OMIT_CHECK sqlite3ExprDelete(pTable->pCheck); #endif -#ifndef SQLITE_OMIT_MODULE - sqliteFree(pTable->zModuleName); - if( pTable->pMod && pTable->pVTab ){ - pTable->pMod->xDisconnect(pTable->pVTab); - } -#endif SQLITE_OMIT_MODULE + sqlite3VtabClear(pTable); sqliteFree(pTable); } @@ -810,10 +805,7 @@ void sqlite3StartTable( goto begin_table_error; } pTable->zName = zName; - pTable->nCol = 0; - pTable->aCol = 0; pTable->iPKey = -1; - pTable->pIndex = 0; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nRef = 1; if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable); @@ -1378,7 +1370,7 @@ void sqlite3EndTable( assert( !db->init.busy || !pSelect ); - iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + iDb = sqlite3SchemaToIndex(db, p->pSchema); #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. @@ -1974,7 +1966,14 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ /* Remove the table entry from SQLite's internal schema and modify ** the schema cookie. */ - sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( pTab->isEphem ){ + sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0); + }else +#endif + { + sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); + } sqlite3ChangeCookie(db, v, iDb); } sqliteViewResetAll(db, iDb); diff --git a/src/delete.c b/src/delete.c index 237c0f19d2..e16597d8af 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.122 2006/02/24 02:53:50 drh Exp $ +** $Id: delete.c,v 1.123 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" @@ -190,7 +190,7 @@ void sqlite3DeleteFrom( */ if( isView ){ Select *pView = sqlite3SelectDup(pTab->pSelect); - sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0); + sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } diff --git a/src/expr.c b/src/expr.c index 0577737a38..5a721ab854 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.258 2006/05/23 23:22:29 drh Exp $ +** $Id: expr.c,v 1.259 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" #include @@ -547,12 +547,12 @@ Select *sqlite3SelectDup(Select *p){ pNew->iOffset = -1; pNew->isResolved = p->isResolved; pNew->isAgg = p->isAgg; - pNew->usesVirt = 0; + pNew->usesEphm = 0; pNew->disallowOrderBy = 0; pNew->pRightmost = 0; - pNew->addrOpenVirt[0] = -1; - pNew->addrOpenVirt[1] = -1; - pNew->addrOpenVirt[2] = -1; + pNew->addrOpenEphm[0] = -1; + pNew->addrOpenEphm[1] = -1; + pNew->addrOpenEphm[2] = -1; return pNew; } #else @@ -1316,7 +1316,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ case TK_IN: { char affinity; KeyInfo keyInfo; - int addr; /* Address of OP_OpenVirtual instruction */ + int addr; /* Address of OP_OpenEphemeral instruction */ affinity = sqlite3ExprAffinity(pExpr->pLeft); @@ -1334,7 +1334,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ ** is used. */ pExpr->iTable = pParse->nTab++; - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, pExpr->iTable, 0); + addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, pExpr->iTable, 0); memset(&keyInfo, 0, sizeof(keyInfo)); keyInfo.nField = 1; sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1); diff --git a/src/insert.c b/src/insert.c index c8c5090e9e..295d753d34 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.164 2006/03/15 16:26:10 drh Exp $ +** $Id: insert.c,v 1.165 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" @@ -371,7 +371,7 @@ void sqlite3Insert( ** back up and execute the SELECT code above. */ sqlite3VdbeJumpHere(v, iInitCode); - sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0); + sqlite3VdbeAddOp(v, OP_OpenEphemeral, srcTab, 0); sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn); sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop); sqlite3VdbeResolveLabel(v, iCleanup); diff --git a/src/main.c b/src/main.c index 9d6cbd9713..6eb047df63 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.341 2006/06/08 15:48:01 drh Exp $ +** $Id: main.c,v 1.342 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -159,6 +159,9 @@ int sqlite3_close(sqlite3 *db){ sqliteFree(pColl); } sqlite3HashClear(&db->aCollSeq); +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3HashClear(&db->aModule); +#endif sqlite3HashClear(&db->aFunc); sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ @@ -818,6 +821,9 @@ static int openDatabase( db->flags |= SQLITE_ShortColNames; sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0); +#endif /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary diff --git a/src/parse.y b/src/parse.y index 922d4730b8..ce3a69dba3 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.201 2006/06/10 13:29:33 drh Exp $ +** @(#) $Id: parse.y,v 1.202 2006/06/11 23:41:55 drh Exp $ */ // All token codes are small integers with #defines that begin with "TK_" @@ -1062,11 +1062,18 @@ kwcolumn_opt ::= COLUMNKW. //////////////////////// CREATE VIRTUAL TABLE ... ///////////////////////////// %ifndef SQLITE_OMIT_VIRTUALTABLE -cmd ::= CREATE VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z) vtabargsopt. -vtabargsopt ::= . -vtabargsopt ::= LP vtabarglist RP. +cmd ::= create_vtab. {sqlite3VtabFinishParse(pParse,0);} +cmd ::= create_vtab LP vtabarglist RP(X). {sqlite3VtabFinishParse(pParse,&X);} +create_vtab ::= CREATE VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). { + sqlite3VtabBeginParse(pParse, &X, &Y, &Z); +} vtabarglist ::= vtabarg. vtabarglist ::= vtabarglist COMMA vtabarg. -vtabarg ::= ANY. -vtabarg ::= vtabarg ANY. +vtabarg ::= . {sqlite3VtabArgInit(pParse);} +vtabarg ::= vtabarg vtabargtoken. +vtabargtoken ::= ANY(X). {sqlite3VtabArgExtend(pParse,&X);} +vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);} +lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);} +anylist ::= . +anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);} %endif diff --git a/src/select.c b/src/select.c index 2fda134007..5dd23d46fb 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.313 2006/04/26 17:39:34 drh Exp $ +** $Id: select.c,v 1.314 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" @@ -72,9 +72,9 @@ Select *sqlite3SelectNew( pNew->pOffset = pOffset; pNew->iLimit = -1; pNew->iOffset = -1; - pNew->addrOpenVirt[0] = -1; - pNew->addrOpenVirt[1] = -1; - pNew->addrOpenVirt[2] = -1; + pNew->addrOpenEphm[0] = -1; + pNew->addrOpenEphm[1] = -1; + pNew->addrOpenEphm[2] = -1; if( pNew==&standin) { clearSelect(pNew); pNew = 0; @@ -522,7 +522,7 @@ static int selectInnerLoop( /* Store the result as data using a unique key. */ case SRT_Table: - case SRT_VirtualTab: { + case SRT_EphemTab: { sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p); @@ -705,7 +705,7 @@ static void generateSortTail( sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1); switch( eDest ){ case SRT_Table: - case SRT_VirtualTab: { + case SRT_EphemTab: { sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Insert, iParm, 0); @@ -1201,11 +1201,11 @@ static int prepSelectStmt(Parse *pParse, Select *p){ if( pTab==0 ){ return 1; } - /* The isTransient flag indicates that the Table structure has been + /* The isEphem flag indicates that the Table structure has been ** dynamically allocated and may be freed at any time. In other words, ** pTab is not pointing to a persistent table structure that defines ** part of the schema. */ - pTab->isTransient = 1; + pTab->isEphem = 1; #endif }else{ /* An ordinary table or view name in the FROM clause */ @@ -1538,10 +1538,10 @@ static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){ int addr; assert( pOrderBy->iECursor==0 ); pOrderBy->iECursor = pParse->nTab++; - addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenVirtual, + addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenEphemeral, pOrderBy->iECursor, pOrderBy->nExpr+1); - assert( p->addrOpenVirt[2] == -1 ); - p->addrOpenVirt[2] = addr; + assert( p->addrOpenEphm[2] == -1 ); + p->addrOpenEphm[2] = addr; } } @@ -1647,10 +1647,10 @@ static int multiSelect( /* Create the destination temporary table if necessary */ - if( eDest==SRT_VirtualTab ){ + if( eDest==SRT_EphemTab ){ assert( p->pEList ); assert( nSetP2addrOpenVirt[0] == -1 ); - p->addrOpenVirt[0] = addr; - p->pRightmost->usesVirt = 1; + assert( p->addrOpenEphm[0] == -1 ); + p->addrOpenEphm[0] = addr; + p->pRightmost->usesEphm = 1; } createSortingIndex(pParse, p, pOrderBy); assert( p->pEList ); @@ -1808,10 +1808,10 @@ static int multiSelect( } createSortingIndex(pParse, p, pOrderBy); - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab1, 0); - assert( p->addrOpenVirt[0] == -1 ); - p->addrOpenVirt[0] = addr; - p->pRightmost->usesVirt = 1; + addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab1, 0); + assert( p->addrOpenEphm[0] == -1 ); + p->addrOpenEphm[0] = addr; + p->pRightmost->usesEphm = 1; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". @@ -1823,9 +1823,9 @@ static int multiSelect( /* Code the current SELECT into temporary table "tab2" */ - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab2, 0); - assert( p->addrOpenVirt[1] == -1 ); - p->addrOpenVirt[1] = addr; + addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab2, 0); + assert( p->addrOpenEphm[1] == -1 ); + p->addrOpenEphm[1] = addr; p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; @@ -1899,7 +1899,7 @@ static int multiSelect( ** SELECT might also skip this part if it has no ORDER BY clause and ** no temp tables are required. */ - if( pOrderBy || p->usesVirt ){ + if( pOrderBy || p->usesEphm ){ int i; /* Loop counter */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ Select *pLoop; /* For looping through SELECT statements */ @@ -1925,11 +1925,11 @@ static int multiSelect( for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ for(i=0; i<2; i++){ - int addr = pLoop->addrOpenVirt[i]; + int addr = pLoop->addrOpenEphm[i]; if( addr<0 ){ /* If [0] is unused then [1] is also unused. So we can ** always safely abort as soon as the first unused slot is found */ - assert( pLoop->addrOpenVirt[1]<0 ); + assert( pLoop->addrOpenEphm[1]<0 ); break; } sqlite3VdbeChangeP2(v, addr, nCol); @@ -1959,8 +1959,8 @@ static int multiSelect( *pSortOrder = pOTerm->sortOrder; } assert( p->pRightmost==p ); - assert( p->addrOpenVirt[2]>=0 ); - addr = p->addrOpenVirt[2]; + assert( p->addrOpenEphm[2]>=0 ); + addr = p->addrOpenEphm[2]; sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2); pKeyInfo->nField = nOrderByExpr; sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); @@ -2394,8 +2394,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ /* If the output is destined for a temporary table, open that table. */ - if( eDest==SRT_VirtualTab ){ - sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 1); + if( eDest==SRT_EphemTab ){ + sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 1); } /* Generating code to find the min or the max. Basically all we have @@ -2404,7 +2404,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ ** or last entry in the main table. */ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - assert( iDb>=0 || pTab->isTransient ); + assert( iDb>=0 || pTab->isEphem ); sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); base = pSrc->a[0].iCursor; @@ -2631,7 +2631,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ pFunc->iDistinct = -1; }else{ KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList); - sqlite3VdbeOp3(v, OP_OpenVirtual, pFunc->iDistinct, 0, + sqlite3VdbeOp3(v, OP_OpenEphemeral, pFunc->iDistinct, 0, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); } } @@ -2780,7 +2780,7 @@ int sqlite3Select( int isDistinct; /* True if the DISTINCT keyword is present */ int distinct; /* Table to use for the distinct set */ int rc = 1; /* Value to return from this function */ - int addrSortIndex; /* Address of an OP_OpenVirtual instruction */ + int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ @@ -2868,7 +2868,7 @@ int sqlite3Select( }else{ needRestoreContext = 0; } - sqlite3Select(pParse, pItem->pSelect, SRT_VirtualTab, + sqlite3Select(pParse, pItem->pSelect, SRT_EphemTab, pItem->iCursor, p, i, &isAgg, 0); if( needRestoreContext ){ pParse->zAuthContext = zSavedAuthContext; @@ -2908,7 +2908,7 @@ int sqlite3Select( ** ** This sorting index might end up being unused if the data can be ** extracted in pre-sorted order. If that is the case, then the - ** OP_OpenVirtual instruction will be changed to an OP_Noop once + ** OP_OpenEphemeral instruction will be changed to an OP_Noop once ** we figure out that the sorting index is not needed. The addrSortIndex ** variable is used to facilitate that change. */ @@ -2925,8 +2925,8 @@ int sqlite3Select( } pKeyInfo = keyInfoFromExprList(pParse, pOrderBy); pOrderBy->iECursor = pParse->nTab++; - p->addrOpenVirt[2] = addrSortIndex = - sqlite3VdbeOp3(v, OP_OpenVirtual, pOrderBy->iECursor, pOrderBy->nExpr+2, + p->addrOpenEphm[2] = addrSortIndex = + sqlite3VdbeOp3(v, OP_OpenEphemeral, pOrderBy->iECursor, pOrderBy->nExpr+2, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); }else{ addrSortIndex = -1; @@ -2934,8 +2934,8 @@ int sqlite3Select( /* If the output is destined for a temporary table, open that table. */ - if( eDest==SRT_VirtualTab ){ - sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr); + if( eDest==SRT_EphemTab ){ + sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, pEList->nExpr); } /* Set the limiter. @@ -2949,7 +2949,7 @@ int sqlite3Select( KeyInfo *pKeyInfo; distinct = pParse->nTab++; pKeyInfo = keyInfoFromExprList(pParse, p->pEList); - sqlite3VdbeOp3(v, OP_OpenVirtual, distinct, 0, + sqlite3VdbeOp3(v, OP_OpenEphemeral, distinct, 0, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); }else{ distinct = -1; @@ -2963,13 +2963,13 @@ int sqlite3Select( pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy); if( pWInfo==0 ) goto select_end; - /* If sorting index that was created by a prior OP_OpenVirtual - ** instruction ended up not being needed, then change the OP_OpenVirtual + /* If sorting index that was created by a prior OP_OpenEphemeral + ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ if( addrSortIndex>=0 && pOrderBy==0 ){ sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); - p->addrOpenVirt[2] = -1; + p->addrOpenEphm[2] = -1; } /* Use the standard inner loop @@ -3003,7 +3003,7 @@ int sqlite3Select( int addrGroupByChange; /* Code that runs when any GROUP BY term changes */ int addrProcessRow; /* Code to process a single input row */ int addrEnd; /* End of all processing */ - int addrSortingIdx; /* The OP_OpenVirtual for the sorting index */ + int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ int addrReset; /* Subroutine for resetting the accumulator */ addrEnd = sqlite3VdbeMakeLabel(v); @@ -3050,13 +3050,13 @@ int sqlite3Select( /* If there is a GROUP BY clause we might need a sorting index to ** implement it. Allocate that sorting index now. If it turns out - ** that we do not need it after all, the OpenVirtual instruction + ** that we do not need it after all, the OpenEphemeral instruction ** will be converted into a Noop. */ sAggInfo.sortingIdx = pParse->nTab++; pKeyInfo = keyInfoFromExprList(pParse, pGroupBy); addrSortingIdx = - sqlite3VdbeOp3(v, OP_OpenVirtual, sAggInfo.sortingIdx, + sqlite3VdbeOp3(v, OP_OpenEphemeral, sAggInfo.sortingIdx, sAggInfo.nSortingColumn, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); @@ -3119,7 +3119,7 @@ int sqlite3Select( if( pWInfo==0 ) goto select_end; if( pGroupBy==0 ){ /* The optimizer is able to deliver rows in group by order so - ** we do not have to sort. The OP_OpenVirtual table will be + ** we do not have to sort. The OP_OpenEphemeral table will be ** cancelled later because we still need to use the pKeyInfo */ pGroupBy = p->pGroupBy; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 6a25f67cc5..3f8a6d7be9 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.167 2006/06/10 13:29:33 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.168 2006/06/11 23:41:56 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -1517,6 +1517,7 @@ typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; typedef struct sqlite3_module sqlite3_module; struct sqlite3_module { int iVersion; + const char *zName; void *pAux; int (*xCreate)(sqlite3*, const sqlite3_module *pModule, int argc, char **argv, @@ -1568,6 +1569,11 @@ struct sqlite3_index_info { #define SQLITE_INDEX_CONSTRAINT_LT 5 #define SQLITE_INDEX_CONSTRAINT_GE 6 #define SQLITE_INDEX_CONSTRAINT_MATCH 7 +int sqlite3_create_module( + sqlite3 *db, + const char *zName, + const sqlite3_module * +); /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 6e78e07826..9a2de48755 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.496 2006/06/10 13:29:33 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.497 2006/06/11 23:41:56 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -490,13 +490,13 @@ struct sqlite3 { void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif -#ifndef SQLITE_OMIT_GLOBALRECOVER - sqlite3 *pNext; /* Linked list of open db handles. */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + Hash aModule; /* populated by sqlite3_create_module() */ #endif Hash aFunc; /* All functions that can be in SQL exprs */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ - int busyTimeout; /* Busy handler timeout, in msec */ + int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ #ifdef SQLITE_SSE sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */ @@ -672,7 +672,7 @@ struct CollSeq { ** Table.tnum is the page number for the root BTree page of the table in the ** database file. If Table.iDb is the index of the database table backend ** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that -** holds temporary tables and indices. If Table.isTransient +** holds temporary tables and indices. If Table.isEphem ** is true, then the table is stored in a file that is automatically deleted ** when the VDBE cursor to the table is closed. In this case Table.tnum ** refers VDBE cursor number that holds the table open, not to the root @@ -689,7 +689,7 @@ struct Table { int tnum; /* Root BTree node for this table (see note above) */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ u8 readOnly; /* True if this table should not be written by the user */ - u8 isTransient; /* True if automatically deleted when VDBE finishes */ + u8 isEphem; /* True if created using OP_OpenEphermeral */ u8 hasPrimKey; /* True if there exists a primary key */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ u8 autoInc; /* True if the integer primary key is autoincrement */ @@ -704,10 +704,12 @@ struct Table { int addColOffset; /* Offset in CREATE TABLE statement to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE - char *zModuleName; /* Name of module implementing this virtual table */ - sqlite3_module *pMod; /* Pointer to the implementation of the module */ - sqlite3_vtab *pVTab; /* Pointer to the module instance */ - u8 needCreate; /* Need to call pMod->xCreate() */ + sqlite3_module *pModule; /* Pointer to the implementation of the module */ + sqlite3_vtab *pVtab; /* Pointer to the module instance */ + int nModuleArg; /* Number of arguments to the module */ + char **azModuleArg; /* Text of all module args. [0] is module name */ + u8 needCreate; /* Need to call pMod->xCreate() */ + u8 isVirtual; /* True if this is a virtual table */ #endif Schema *pSchema; }; @@ -903,7 +905,7 @@ struct AggInfo { Expr *pExpr; /* Expression encoding the function */ FuncDef *pFunc; /* The aggregate function implementation */ int iMem; /* Memory location that acts as accumulator */ - int iDistinct; /* Virtual table used to enforce DISTINCT */ + int iDistinct; /* Ephermeral table used to enforce DISTINCT */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ int nFuncAlloc; /* Number of slots allocated for aFunc[] */ @@ -1171,14 +1173,14 @@ struct NameContext { ** offset). But later on, nLimit and nOffset become the memory locations ** in the VDBE that record the limit and offset counters. ** -** addrOpenVirt[] entries contain the address of OP_OpenVirtual opcodes. +** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes. ** These addresses must be stored so that we can go back and fill in ** the P3_KEYINFO and P2 parameters later. Neither the KeyInfo nor ** the number of columns in P2 can be computed at the same time -** as the OP_OpenVirtual instruction is coded because not +** as the OP_OpenEphm instruction is coded because not ** enough information about the compound query is known at that point. -** The KeyInfo for addrOpenVirt[0] and [1] contains collating sequences -** for the result set. The KeyInfo for addrOpenVirt[2] contains collating +** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences +** for the result set. The KeyInfo for addrOpenTran[2] contains collating ** sequences for the ORDER BY clause. */ struct Select { @@ -1187,7 +1189,7 @@ struct Select { u8 isDistinct; /* True if the DISTINCT keyword is present */ u8 isResolved; /* True once sqlite3SelectResolve() has run. */ u8 isAgg; /* True if this is an aggregate query */ - u8 usesVirt; /* True if uses an OpenVirtual opcode */ + u8 usesEphm; /* True if uses an OpenEphemeral opcode */ u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ @@ -1199,7 +1201,7 @@ struct Select { Expr *pLimit; /* LIMIT expression. NULL means not used. */ Expr *pOffset; /* OFFSET expression. NULL means not used. */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ - int addrOpenVirt[3]; /* OP_OpenVirtual opcodes related to this select */ + int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */ }; /* @@ -1216,7 +1218,7 @@ struct Select { #define SRT_Mem 5 /* Store result in a memory cell */ #define SRT_Set 6 /* Store non-null results as keys in an index */ #define SRT_Table 7 /* Store result as data with an automatic rowid */ -#define SRT_VirtualTab 8 /* Create virtual table and store like SRT_Table */ +#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */ #define SRT_Subroutine 9 /* Call a subroutine to handle results */ #define SRT_Exists 10 /* Store 1 if the result is not empty */ @@ -1277,6 +1279,11 @@ struct Parse { Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ TriggerStack *trigStack; /* Trigger actions being coded */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + int nArgAlloc; /* Number of bytes allocated for zArg[] */ + int nArgUsed; /* Number of bytes of zArg[] used so far */ + char *zArg; /* Complete text of a module argument */ +#endif }; /* @@ -1774,6 +1781,16 @@ void sqlite3CloseExtensions(sqlite3*); #define sqlite3ThreadSafeFree sqlite3FreeX #endif +#ifdef SQLITE_OMIT_VIRTUALTABLE +# define sqlite3VtabClear(X) +#else + void sqlite3VtabClear(Table*); +#endif +void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); +void sqlite3VtabFinishParse(Parse*, Token*); +void sqlite3VtabArgInit(Parse*); +void sqlite3VtabArgExtend(Parse*, Token*); + #ifdef SQLITE_SSE #include "sseInt.h" #endif diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 875890d818..07783c1e48 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.156 2006/05/10 14:39:14 drh Exp $ +** $Id: tclsqlite.c,v 1.157 2006/06/11 23:41:56 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -2151,6 +2151,7 @@ int TCLSH_MAIN(int argc, char **argv){ extern int Sqlitetest5_Init(Tcl_Interp*); extern int Sqlitetest6_Init(Tcl_Interp*); extern int Sqlitetest7_Init(Tcl_Interp*); + extern int Sqlitetest8_Init(Tcl_Interp*); extern int Md5_Init(Tcl_Interp*); extern int Sqlitetestsse_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); @@ -2162,6 +2163,7 @@ int TCLSH_MAIN(int argc, char **argv){ Sqlitetest5_Init(interp); Sqlitetest6_Init(interp); Sqlitetest7_Init(interp); + Sqlitetest8_Init(interp); Sqlitetestasync_Init(interp); Md5_Init(interp); #ifdef SQLITE_SSE diff --git a/src/test1.c b/src/test1.c index 01dc6d7821..0c18ea1292 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.209 2006/03/19 13:00:25 drh Exp $ +** $Id: test1.c,v 1.210 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -3538,6 +3538,12 @@ static void set_options(Tcl_Interp *interp){ #else Tcl_SetVar2(interp, "sqlite_options", "view", "1", TCL_GLOBAL_ONLY); #endif + +#ifdef SQLITE_OMIT_VIRTUALTABLE + Tcl_SetVar2(interp, "sqlite_options", "vtab", "0", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "vtab", "1", TCL_GLOBAL_ONLY); +#endif } /* diff --git a/src/test8.c b/src/test8.c new file mode 100644 index 0000000000..c0d08a4695 --- /dev/null +++ b/src/test8.c @@ -0,0 +1,136 @@ +/* +** 2006 June 10 +** +** 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. +** +************************************************************************* +** Code for testing the virtual table interfaces. This code +** is not included in the SQLite library. It is used for automated +** testing of the SQLite library. +** +** $Id: test8.c,v 1.1 2006/06/11 23:41:56 drh Exp $ +*/ +#include "sqliteInt.h" +#include "tcl.h" +#include "os.h" +#include +#include + +/* Methods for the echo module */ +static int echoCreate( + sqlite3 *db, + const sqlite3_module *pModule, + int argc, char **argv, + sqlite3_vtab **ppVtab +){ + int i; + Tcl_Interp *interp = pModule->pAux; + *ppVtab = pModule->pAux; + + Tcl_SetVar(interp, "echo_module", "xCreate", TCL_GLOBAL_ONLY); + for(i=0; ipAux; + *ppVtab = pModule->pAux; + + Tcl_SetVar(interp, "echo_module", "xConnect", TCL_GLOBAL_ONLY); + for(i=0; iaTableLock = 0; pParse->nTableLock = 0; } +#endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqliteFree(pParse->zArg); #endif sqlite3DeleteTable(pParse->db, pParse->pNewTable); sqlite3DeleteTrigger(pParse->pNewTrigger); diff --git a/src/update.c b/src/update.c index b3cd7aed09..f1662eb1a8 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.123 2006/02/24 02:53:50 drh Exp $ +** $Id: update.c,v 1.124 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" @@ -268,7 +268,7 @@ void sqlite3Update( if( isView ){ Select *pView; pView = sqlite3SelectDup(pTab->pSelect); - sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0); + sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } diff --git a/src/vdbe.c b/src/vdbe.c index fc6fd97ef5..a85d303153 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.550 2006/06/03 18:04:17 drh Exp $ +** $Id: vdbe.c,v 1.551 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -2640,9 +2640,9 @@ case OP_OpenWrite: { /* no-push */ break; } -/* Opcode: OpenVirtual P1 P2 P3 +/* Opcode: OpenEphemeral P1 P2 P3 ** -** Open a new cursor P1 to a transient or virtual table. +** Open a new cursor P1 to a transient table. ** The cursor is always opened read/write even if ** the main database is read-only. The transient or virtual ** table is deleted automatically when the cursor is closed. @@ -2651,8 +2651,14 @@ case OP_OpenWrite: { /* no-push */ ** The cursor points to a BTree table if P3==0 and to a BTree index ** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure ** that defines the format of keys in the index. +** +** This opcode was once called OpenTemp. But that created +** confusion because the term "temp table", might refer either +** to a TEMP table at the SQL level, or to a table opened by +** this opcode. Then this opcode was call OpenVirtual. But +** that created confusion with the whole virtual-table idea. */ -case OP_OpenVirtual: { /* no-push */ +case OP_OpenEphemeral: { /* no-push */ int i = pOp->p1; Cursor *pCx; assert( i>=0 ); @@ -4525,7 +4531,29 @@ case OP_TableLock: { /* no-push */ } break; } -#endif /* SHARED_OMIT_SHARED_CACHE */ +#endif /* SQLITE_OMIT_SHARED_CACHE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VCreate * * P3 +** +** P3 is the name of a virtual table. Call the xCreate method for +** that table. +*/ +case OP_VCreate: { + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VDestroy * * P3 +** +** P3 is the name of a virtual table. Call the xCreate method for +** that table. +*/ +case OP_VDestroy: { + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ /* An other opcode is illegal... */ diff --git a/src/vdbe.h b/src/vdbe.h index 46045423d6..3097022f62 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.102 2006/03/17 13:56:34 drh Exp $ +** $Id: vdbe.h,v 1.103 2006/06/11 23:41:56 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -69,7 +69,7 @@ typedef struct VdbeOpList VdbeOpList; #define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */ #define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */ #define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */ -#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */ +#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */ /* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure ** is made. That copy is freed when the Vdbe is finalized. But if the diff --git a/src/vtab.c b/src/vtab.c new file mode 100644 index 0000000000..d7d7515bd0 --- /dev/null +++ b/src/vtab.c @@ -0,0 +1,211 @@ +/* +** 2006 June 10 +** +** 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 contains code used to help implement virtual tables. +** +** $Id: vtab.c,v 1.1 2006/06/11 23:41:56 drh Exp $ +*/ +#ifndef SQLITE_OMIT_VIRTUALTABLE +#include "sqliteInt.h" + +/* +** External API function used to create a new virtual-table module. +*/ +int sqlite3_create_module( + sqlite3 *db, /* Database in which module is registered */ + const char *zName, /* Name assigned to this module */ + const sqlite3_module *pModule /* The definition of the module */ +){ + sqlite3HashInsert(&db->aModule, zName, strlen(zName), (void*)pModule); + sqlite3ResetInternalSchema(db, 0); + return SQLITE_OK; +} + + +/* +** Clear any and all virtual-table information from the Table record. +** This routine is called, for example, just before deleting the Table +** record. +*/ +void sqlite3VtabClear(Table *p){ + if( p->pVtab ){ + assert( p->pModule!=0 ); + p->pModule->xDisconnect(p->pVtab); + } + if( p->azModuleArg ){ + int i; + for(i=0; inModuleArg; i++){ + sqliteFree(p->azModuleArg[i]); + } + sqliteFree(p->azModuleArg); + } +} + +/* +** Add a new module argument to pTable->azModuleArg[]. +** The string is not copied - the pointer is stored. The +** string will be freed automatically when the table is +** deleted. +*/ +static void addModuleArgument(Table *pTable, char *zArg){ + int i = pTable->nModuleArg++; + pTable->azModuleArg = sqliteRealloc(pTable->azModuleArg, + sizeof(char*)*(pTable->nModuleArg+1)); + if( pTable->azModuleArg==0 ){ + pTable->nModuleArg = 0; + sqliteFree(zArg); + }else{ + pTable->azModuleArg[i] = zArg; + pTable->azModuleArg[i+1] = 0; + } +} + +/* +** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE +** statement. The module name has been parsed, but the optional list +** of parameters that follow the module name are still pending. +*/ +void sqlite3VtabBeginParse( + Parse *pParse, /* Parsing context */ + Token *pName1, /* Name of new table, or database name */ + Token *pName2, /* Name of new table or NULL */ + Token *pModuleName /* Name of the module for the virtual table */ +){ + Table *pTable; /* The new virtual table */ + + sqlite3StartTable(pParse, pName1, pName2, 0, 0, 0); + pTable = pParse->pNewTable; + if( pTable==0 ) return; + pTable->isVirtual = 1; + pTable->nModuleArg = 0; + addModuleArgument(pTable, sqlite3NameFromToken(pModuleName)); + pParse->sNameToken.n = pModuleName->z + pModuleName->n - pName1->z; +} + +/* +** This routine takes the module argument that has been accumulating +** in pParse->zArg[] and appends it to the list of arguments on the +** virtual table currently under construction in pParse->pTable. +*/ +static void addArgumentToVtab(Parse *pParse){ + if( pParse->nArgUsed && pParse->pNewTable ){ + addModuleArgument(pParse->pNewTable, sqliteStrDup(pParse->zArg)); + } + pParse->nArgUsed = 0; +} + +/* +** The parser calls this routine after the CREATE VIRTUAL TABLE statement +** has been completely parsed. +*/ +void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ + Table *pTab; /* The table being constructed */ + sqlite3 *db; /* The database connection */ + char *zModule; /* The module name of the table: USING modulename */ + + addArgumentToVtab(pParse); + sqliteFree(pParse->zArg); + pParse->zArg = 0; + pParse->nArgAlloc = 0; + + /* Lookup the module name. */ + pTab = pParse->pNewTable; + if( pTab==0 ) return; + db = pParse->db; + if( pTab->nModuleArg<1 ) return; + pParse->pNewTable = 0; + zModule = pTab->azModuleArg[0]; + pTab->pModule = (sqlite3_module*)sqlite3HashFind(&db->aModule, + zModule, strlen(zModule)); + + /* If the CREATE VIRTUAL TABLE statement is being entered for the + ** first time (in other words if the virtual table is actually being + ** created now instead of just being read out of sqlite_master) then + ** do additional initialization work and store the statement text + ** in the sqlite_master table. + */ + if( !db->init.busy ){ + char *zStmt; + int iDb; + Vdbe *v; + if( pTab->pModule==0 ){ + sqlite3ErrorMsg(pParse, "unknown module: %s", zModule); + } + + /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ + if( pEnd ){ + pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n; + } + zStmt = sqlite3MPrintf("CREATE VIRTUAL TABLE %T", &pParse->sNameToken); + + /* A slot for the record has already been allocated in the + ** SQLITE_MASTER table. We just need to update that slot with all + ** the information we've collected. The rowid for the preallocated + ** slot is the top the stack. + */ + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + sqlite3NestedParse(pParse, + "UPDATE %Q.%s " + "SET type='table', name=%Q, tbl_name=%Q, rootpage=NULL, sql=%Q " + "WHERE rowid=#0", + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), + pTab->zName, + pTab->zName, + zStmt + ); + sqliteFree(zStmt); + v = sqlite3GetVdbe(pParse); + sqlite3VdbeOp3(v, OP_VCreate, 0, 0, pTab->zName, P3_DYNAMIC); + sqlite3ChangeCookie(db, v, iDb); + } + + /* If we are rereading the sqlite_master table and we happen to + ** currently know the module for the new table, create an + ** sqlite3_vtab instance. + */ + else if( pTab->pModule ){ + sqlite3_module *pMod = pTab->pModule; + assert( pMod->xConnect ); + pMod->xConnect(db, pMod, pTab->nModuleArg, pTab->azModuleArg, &pTab->pVtab); + } +} + +/* +** The parser calls this routine when it sees the first token +** of an argument to the module name in a CREATE VIRTUAL TABLE statement. +*/ +void sqlite3VtabArgInit(Parse *pParse){ + addArgumentToVtab(pParse); + pParse->nArgUsed = 0; +} + +/* +** The parser calls this routine for each token after the first token +** in an argument to the module name in a CREATE VIRTUAL TABLE statement. +*/ +void sqlite3VtabArgExtend(Parse *pParse, Token *p){ + if( pParse->nArgUsed + p->n + 2 >= pParse->nArgAlloc ){ + pParse->nArgAlloc = pParse->nArgAlloc*2 + p->n + 200; + pParse->zArg = sqliteRealloc(pParse->zArg, pParse->nArgAlloc); + if( pParse->zArg==0 ){ + pParse->nArgAlloc = 0; + return; + } + } + if( pParse->nArgUsed ){ + pParse->zArg[pParse->nArgUsed++] = ' '; + } + memcpy(&pParse->zArg[pParse->nArgUsed], p->z, p->n); + pParse->nArgUsed += p->n; + pParse->zArg[pParse->nArgUsed] = 0; +} + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/src/where.c b/src/where.c index 4ba6338edd..515ed4421f 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.209 2006/06/06 11:45:55 drh Exp $ +** $Id: where.c,v 1.210 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" @@ -1601,7 +1601,7 @@ WhereInfo *sqlite3WhereBegin( pTabItem = &pTabList->a[pLevel->iFrom]; pTab = pTabItem->pTab; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - if( pTab->isTransient || pTab->pSelect ) continue; + if( pTab->isEphem || pTab->pSelect ) continue; if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){ sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead); if( pTab->nCol<(sizeof(Bitmask)*8) ){ @@ -2087,7 +2087,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); - if( pTab->isTransient || pTab->pSelect ) continue; + if( pTab->isEphem || pTab->pSelect ) continue; if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp(v, OP_Close, pTabItem->iCursor, 0); } diff --git a/test/insert.test b/test/insert.test index b7d815c32b..723a47d15d 100644 --- a/test/insert.test +++ b/test/insert.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the INSERT statement. # -# $Id: insert.test,v 1.29 2006/01/17 09:35:02 danielk1977 Exp $ +# $Id: insert.test,v 1.30 2006/06/11 23:41:56 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -247,7 +247,7 @@ ifcapable tempdb { set x [execsql { EXPLAIN INSERT INTO t4 SELECT x+2 FROM t4; }] - expr {[lsearch $x OpenVirtual]>0} + expr {[lsearch $x OpenEphemeral]>0} } {1} } diff --git a/test/select6.test b/test/select6.test index a8682eab86..5b1ee89802 100644 --- a/test/select6.test +++ b/test/select6.test @@ -12,7 +12,7 @@ # focus of this file is testing SELECT statements that contain # subqueries in their FROM clause. # -# $Id: select6.test,v 1.23 2006/01/23 07:52:41 danielk1977 Exp $ +# $Id: select6.test,v 1.24 2006/06/11 23:41:56 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -382,7 +382,7 @@ ifcapable {!explain} { # sqliteFlattenSubquery() routine in select.c is doing its job. # proc is_flat {sql} { - return [expr 0>[lsearch [execsql "EXPLAIN $sql"] OpenVirtual]] + return [expr 0>[lsearch [execsql "EXPLAIN $sql"] OpenEphemeral]] } # Check that the flattener works correctly for deeply nested subqueries diff --git a/test/view.test b/test/view.test index 6502c1dbc2..19c33f9d4f 100644 --- a/test/view.test +++ b/test/view.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing VIEW statements. # -# $Id: view.test,v 1.31 2006/03/26 01:21:23 drh Exp $ +# $Id: view.test,v 1.32 2006/06/11 23:41:56 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -219,7 +219,7 @@ ifcapable {explain} { do_test view-5.3 { lsearch [execsql { EXPLAIN SELECT * FROM v5; - }] OpenVirtual + }] OpenEphemeral } {-1} do_test view-5.4 { execsql { @@ -229,7 +229,7 @@ do_test view-5.4 { do_test view-5.5 { lsearch [execsql { EXPLAIN SELECT * FROM v5 AS a, t2 AS b WHERE a.w=b.y; - }] OpenVirtual + }] OpenEphemeral } {-1} do_test view-5.6 { execsql { @@ -239,7 +239,7 @@ do_test view-5.6 { do_test view-5.7 { lsearch [execsql { EXPLAIN SELECT * FROM t2 AS b, v5 AS a WHERE a.w=b.y; - }] OpenVirtual + }] OpenEphemeral } {-1} do_test view-5.8 { execsql { @@ -249,7 +249,7 @@ do_test view-5.8 { do_test view-5.9 { lsearch [execsql { EXPLAIN SELECT * FROM t1 AS a, v5 AS b, t2 AS c WHERE a.x=b.v AND b.w=c.y; - }] OpenVirtual + }] OpenEphemeral } {-1} } ;# endif explain diff --git a/test/vtab1.test b/test/vtab1.test new file mode 100644 index 0000000000..18e034f159 --- /dev/null +++ b/test/vtab1.test @@ -0,0 +1,53 @@ +# 2006 June 10 +# +# 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 creating and dropping virtual tables. +# +# $Id: vtab1.test,v 1.1 2006/06/11 23:41:56 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# We cannot create a virtual table if the module has not +# been registered. +# +do_test vtab1-1.1 { + catchsql { + CREATE VIRTUAL TABLE t1 USING echo; + } +} {1 {unknown module: echo}} +do_test vtab1-1.2 { + execsql { + SELECT name FROM sqlite_master ORDER BY 1 + } +} {} + +# After we register the echo module, we are allowed to create +# virtual tables using that module. +# +do_test vtab1-1.3 { + register_echo_module [sqlite3_connection_pointer db] +execsql {pragma vdbe_listing=on; pragma vdbe_trace=on} + catchsql { + CREATE VIRTUAL TABLE t1 USING echo; + } +} {0 {}} +do_test vtab1-1.4 { + set echo_module +} {xCreate echo} +do_test vtab1-1.5 { + execsql { + SELECT name, sql FROM sqlite_master ORDER BY 1 + } +} {t1 {CREATE VIRTUAL TABLE t1 USING echo}} + + +finish_test