mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
First code for the new callback-free API. All regression tests pass but the
new API is mostly untested and is unlikely to work. (CVS 852) FossilOrigin-Name: 065fa818ffc8d7562889172acea16e4e44e773ef
This commit is contained in:
32
manifest
32
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Added\ssection\son\scomments.\nCorrected\sbroken\s</p>\send\stags.\s(CVS\s851)
|
C First\scode\sfor\sthe\snew\scallback-free\sAPI.\s\sAll\sregression\stests\spass\sbut\sthe\nnew\sAPI\sis\smostly\suntested\sand\sis\sunlikely\sto\swork.\s(CVS\s852)
|
||||||
D 2003-01-26T15:28:18
|
D 2003-01-28T23:13:11
|
||||||
F Makefile.in 6606854b1512f185b8e8c779b8d7fc2750463d64
|
F Makefile.in 6606854b1512f185b8e8c779b8d7fc2750463d64
|
||||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||||
@@ -21,7 +21,7 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
|
|||||||
F src/auth.c 9c2db0bc7707f2d2e227f47e3d557b41d44ade75
|
F src/auth.c 9c2db0bc7707f2d2e227f47e3d557b41d44ade75
|
||||||
F src/btree.c eb4f430b062500d7533c031097d3ff8824eca3ba
|
F src/btree.c eb4f430b062500d7533c031097d3ff8824eca3ba
|
||||||
F src/btree.h 17710339f7a8f46e3c7d6d0d4648ef19c584ffda
|
F src/btree.h 17710339f7a8f46e3c7d6d0d4648ef19c584ffda
|
||||||
F src/build.c d6716dae74cccdcb9db6d05f65f7994762aa6d9f
|
F src/build.c 1a4c0d71863f0aa0be7e5a2148b103c3e761c771
|
||||||
F src/delete.c cbd499f3f9297504c42e328af89bef1a2113d04c
|
F src/delete.c cbd499f3f9297504c42e328af89bef1a2113d04c
|
||||||
F src/encode.c faf03741efe921755ec371cf4a6984536de00042
|
F src/encode.c faf03741efe921755ec371cf4a6984536de00042
|
||||||
F src/expr.c 382839b92cb66a34cfa71cf1d2bc8fb818226c90
|
F src/expr.c 382839b92cb66a34cfa71cf1d2bc8fb818226c90
|
||||||
@@ -29,32 +29,32 @@ F src/func.c 90c583f0b91220f7cd411a2407deaf9327245d63
|
|||||||
F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
|
F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
|
||||||
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
|
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
|
||||||
F src/insert.c db954e955970795819145a3649fd2ad116a58890
|
F src/insert.c db954e955970795819145a3649fd2ad116a58890
|
||||||
F src/main.c ad3193c56da5acd31bc6cd48aa50dae1962d7c78
|
F src/main.c c58cdfb5f0c1938e78d47584e88799b77091700c
|
||||||
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
|
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
|
||||||
F src/os.c ed27e178e0c4b71f2807da81b8851f0fadc50778
|
F src/os.c ed27e178e0c4b71f2807da81b8851f0fadc50778
|
||||||
F src/os.h afa3e096213bad86845f8bdca81a9e917505e401
|
F src/os.h afa3e096213bad86845f8bdca81a9e917505e401
|
||||||
F src/pager.c 95f5c5c775ed47e837ce02b407d80527d93e6c43
|
F src/pager.c 95f5c5c775ed47e837ce02b407d80527d93e6c43
|
||||||
F src/pager.h 540833e8cb826b80ce2e39aa917deee5e12db626
|
F src/pager.h 540833e8cb826b80ce2e39aa917deee5e12db626
|
||||||
F src/parse.y a4fbfbe3c4254c96dae8c33264fb54af755a3770
|
F src/parse.y aea0819c07ec9c81b810039df9be9d5705b1e497
|
||||||
F src/printf.c e8e9a0605602cb1a3a2dc754e0978fa9064ecee7
|
F src/printf.c e8e9a0605602cb1a3a2dc754e0978fa9064ecee7
|
||||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||||
F src/select.c c3c0b8263587d290592dca8b4371b5c1162ca684
|
F src/select.c c3c0b8263587d290592dca8b4371b5c1162ca684
|
||||||
F src/shell.c cbb29252f0bd7b144d1e3126e64e17e5a314f2fd
|
F src/shell.c cbb29252f0bd7b144d1e3126e64e17e5a314f2fd
|
||||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||||
F src/sqlite.h.in 90657185cff387069d17c5b876a87a6a7a3b6f10
|
F src/sqlite.h.in ace5c971df379f07ade9ae4b2066cc18ee8b6cfa
|
||||||
F src/sqliteInt.h 1d614e04f3c439d7bb60a65f821f8ec53ef6a7e8
|
F src/sqliteInt.h 576855338db3e3673605bd08b32a5a8cb3f57cf8
|
||||||
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
|
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
|
||||||
F src/tclsqlite.c 9f2c00a92338c51171ded8943bd42d77f7e69e64
|
F src/tclsqlite.c 9f2c00a92338c51171ded8943bd42d77f7e69e64
|
||||||
F src/test1.c 921e5dda494f836d2ebea703bd5b239a7cc963d0
|
F src/test1.c c00a4e561287da1976149fe156748253bd8926e7
|
||||||
F src/test2.c 03f05e984c8e2f2badc44644d42baf72b249096b
|
F src/test2.c 03f05e984c8e2f2badc44644d42baf72b249096b
|
||||||
F src/test3.c c12ea7f1c3fbbd58904e81e6cb10ad424e6fc728
|
F src/test3.c c12ea7f1c3fbbd58904e81e6cb10ad424e6fc728
|
||||||
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
|
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
|
||||||
F src/tokenize.c 7ac1c33e0149647c9eb5959c48992df6906d4809
|
F src/tokenize.c 0ba74091f432b79687fc7fbecc9e9087bfb40a56
|
||||||
F src/trigger.c da142decd2808bc39e801f3bb1f161dbc2bd4005
|
F src/trigger.c da142decd2808bc39e801f3bb1f161dbc2bd4005
|
||||||
F src/update.c f06afa9bf1f777d17702e0f6e33cf44c44bc4f75
|
F src/update.c f06afa9bf1f777d17702e0f6e33cf44c44bc4f75
|
||||||
F src/util.c e23f8ffc654923e18f8db2d8e0de97c166fca20f
|
F src/util.c e23f8ffc654923e18f8db2d8e0de97c166fca20f
|
||||||
F src/vdbe.c 7796485aa510c89aa378a11d3fbeb6fcf3893433
|
F src/vdbe.c 899b59df8a6d91020c3d5c54a817fb669f98176b
|
||||||
F src/vdbe.h 754eba497cfe0c3e352b9c101ab2f811f10d0a55
|
F src/vdbe.h 30b808a32f8d66e9948d0a9931f1e1037d2ec2ad
|
||||||
F src/where.c 5bf7f1e1d756ab3d25a18b24bb42106cb8e14d18
|
F src/where.c 5bf7f1e1d756ab3d25a18b24bb42106cb8e14d18
|
||||||
F test/all.test 873d30e25a41b3aa48fec5633a7ec1816e107029
|
F test/all.test 873d30e25a41b3aa48fec5633a7ec1816e107029
|
||||||
F test/auth.test 95aeda24f76b6fd028bdb3d6ae1e30b153d942fe
|
F test/auth.test 95aeda24f76b6fd028bdb3d6ae1e30b153d942fe
|
||||||
@@ -110,7 +110,7 @@ F test/tester.tcl 6f603d90881bd835ea27c568a7fecaa57dce91cc
|
|||||||
F test/trans.test 10b53c77e2cc4ad9529c15fdcb390b8d5722ea65
|
F test/trans.test 10b53c77e2cc4ad9529c15fdcb390b8d5722ea65
|
||||||
F test/trigger1.test ec1da76e1a9f618deb96e505f459dcf8a23f2247
|
F test/trigger1.test ec1da76e1a9f618deb96e505f459dcf8a23f2247
|
||||||
F test/trigger2.test ee346d8c612e7f847c9543058f1b89d094d27ffb
|
F test/trigger2.test ee346d8c612e7f847c9543058f1b89d094d27ffb
|
||||||
F test/trigger3.test 5958cdb44e95842298436cb61d5de5251ec2d28e
|
F test/trigger3.test 870afef7997a5b86bf3ea893ce0c2e85d6356c72
|
||||||
F test/trigger4.test 9a5c1406344d743020c2753ae8d6dfe6eb75f818
|
F test/trigger4.test 9a5c1406344d743020c2753ae8d6dfe6eb75f818
|
||||||
F test/unique.test 572aa791327c1e8d797932263e9d67f176cfdb44
|
F test/unique.test 572aa791327c1e8d797932263e9d67f176cfdb44
|
||||||
F test/update.test 7ffb062d580a972e7870d0f51d5af3ab9bfeae08
|
F test/update.test 7ffb062d580a972e7870d0f51d5af3ab9bfeae08
|
||||||
@@ -154,7 +154,7 @@ F www/speed.tcl 4d463e2aea41f688ed320a937f93ff885be918c3
|
|||||||
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
|
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
|
||||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||||
P bdba796f3b89690ab5d53a9e16924383ef72657c
|
P c957f4f0c6b486f25bc567dafeed186f91c8c315
|
||||||
R 2fbda7b77729464b96834537506192f2
|
R fba6d74be1d355dfd1b4bac9d5e01203
|
||||||
U jplyon
|
U drh
|
||||||
Z 22282820ee286f511aad4850aeea1aad
|
Z 6e26856c68db7a18e1f9ce32bbc7b32d
|
||||||
|
@@ -1 +1 @@
|
|||||||
c957f4f0c6b486f25bc567dafeed186f91c8c315
|
065fa818ffc8d7562889172acea16e4e44e773ef
|
44
src/build.c
44
src/build.c
@@ -25,7 +25,7 @@
|
|||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
** PRAGMA
|
** PRAGMA
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.125 2003/01/25 14:34:23 drh Exp $
|
** $Id: build.c,v 1.126 2003/01/28 23:13:11 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -48,6 +48,17 @@ void sqliteBeginParse(Parse *pParse, int explainFlag){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This is a fake callback procedure used when sqlite_exec() is
|
||||||
|
** invoked with a NULL callback pointer. If we pass a NULL callback
|
||||||
|
** pointer into sqliteVdbeExec() it will return at every OP_Callback,
|
||||||
|
** which we do not want it to do. So we substitute a pointer to this
|
||||||
|
** procedure in place of the NULL.
|
||||||
|
*/
|
||||||
|
static int fakeCallback(void *NotUsed, int n, char **az1, char **az2){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine is called after a single SQL statement has been
|
** This routine is called after a single SQL statement has been
|
||||||
** parsed and we want to execute the VDBE code to implement
|
** parsed and we want to execute the VDBE code to implement
|
||||||
@@ -61,24 +72,33 @@ void sqliteBeginParse(Parse *pParse, int explainFlag){
|
|||||||
void sqliteExec(Parse *pParse){
|
void sqliteExec(Parse *pParse){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
sqlite *db = pParse->db;
|
sqlite *db = pParse->db;
|
||||||
|
Vdbe *v = pParse->pVdbe;
|
||||||
|
int (*xCallback)(void*,int,char**,char**);
|
||||||
|
|
||||||
if( sqlite_malloc_failed ) return;
|
if( sqlite_malloc_failed ) return;
|
||||||
if( pParse->pVdbe && pParse->nErr==0 ){
|
xCallback = pParse->xCallback;
|
||||||
|
if( xCallback==0 && pParse->useCallback ) xCallback = fakeCallback;
|
||||||
|
if( v && pParse->nErr==0 ){
|
||||||
|
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
||||||
|
sqliteVdbeTrace(v, trace);
|
||||||
|
sqliteVdbeMakeReady(v, xCallback, pParse->pArg, pParse->explain);
|
||||||
|
if( pParse->useCallback ){
|
||||||
if( pParse->explain ){
|
if( pParse->explain ){
|
||||||
rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg,
|
rc = sqliteVdbeList(v);
|
||||||
&pParse->zErrMsg);
|
|
||||||
db->next_cookie = db->schema_cookie;
|
db->next_cookie = db->schema_cookie;
|
||||||
}else{
|
}else{
|
||||||
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
sqliteVdbeExec(v);
|
||||||
sqliteVdbeTrace(pParse->pVdbe, trace);
|
|
||||||
rc = sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg,
|
|
||||||
&pParse->zErrMsg, db->pBusyArg,
|
|
||||||
db->xBusyCallback);
|
|
||||||
if( rc ) pParse->nErr++;
|
|
||||||
}
|
}
|
||||||
sqliteVdbeDelete(pParse->pVdbe);
|
rc = sqliteVdbeFinalize(v, &pParse->zErrMsg);
|
||||||
|
if( rc ) pParse->nErr++;
|
||||||
|
sqliteVdbeDelete(v);
|
||||||
pParse->pVdbe = 0;
|
pParse->pVdbe = 0;
|
||||||
pParse->colNamesSet = 0;
|
|
||||||
pParse->rc = rc;
|
pParse->rc = rc;
|
||||||
|
if( rc ) pParse->nErr++;
|
||||||
|
}else{
|
||||||
|
pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
|
||||||
|
}
|
||||||
|
pParse->colNamesSet = 0;
|
||||||
pParse->schemaVerified = 0;
|
pParse->schemaVerified = 0;
|
||||||
}
|
}
|
||||||
pParse->nTab = 0;
|
pParse->nTab = 0;
|
||||||
|
86
src/main.c
86
src/main.c
@@ -14,7 +14,7 @@
|
|||||||
** other files are for internal use by SQLite and should not be
|
** other files are for internal use by SQLite and should not be
|
||||||
** accessed by users of the library.
|
** accessed by users of the library.
|
||||||
**
|
**
|
||||||
** $Id: main.c,v 1.109 2003/01/19 03:59:47 drh Exp $
|
** $Id: main.c,v 1.110 2003/01/28 23:13:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@@ -69,6 +69,7 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
|
|||||||
sParse.initFlag = 1;
|
sParse.initFlag = 1;
|
||||||
sParse.isTemp = argv[4][0] - '0';
|
sParse.isTemp = argv[4][0] - '0';
|
||||||
sParse.newTnum = atoi(argv[2]);
|
sParse.newTnum = atoi(argv[2]);
|
||||||
|
sParse.useCallback = 1;
|
||||||
sqliteRunParser(&sParse, argv[3], pData->pzErrMsg);
|
sqliteRunParser(&sParse, argv[3], pData->pzErrMsg);
|
||||||
}else{
|
}else{
|
||||||
/* If the SQL column is blank it means this is an index that
|
/* If the SQL column is blank it means this is an index that
|
||||||
@@ -297,6 +298,7 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
|
|||||||
sParse.xCallback = sqliteInitCallback;
|
sParse.xCallback = sqliteInitCallback;
|
||||||
sParse.pArg = (void*)&initData;
|
sParse.pArg = (void*)&initData;
|
||||||
sParse.initFlag = 1;
|
sParse.initFlag = 1;
|
||||||
|
sParse.useCallback = 1;
|
||||||
sqliteRunParser(&sParse,
|
sqliteRunParser(&sParse,
|
||||||
db->file_format>=2 ? init_script : older_init_script,
|
db->file_format>=2 ? init_script : older_init_script,
|
||||||
pzErrMsg);
|
pzErrMsg);
|
||||||
@@ -584,29 +586,23 @@ int sqlite_complete(const char *zSql){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Execute SQL code. Return one of the SQLITE_ success/failure
|
** This routine does the work of either sqlite_exec() or sqlite_compile().
|
||||||
** codes. Also write an error message into memory obtained from
|
** It works like sqlite_exec() if pVm==NULL and it works like sqlite_compile()
|
||||||
** malloc() and make *pzErrMsg point to that message.
|
** otherwise.
|
||||||
**
|
|
||||||
** If the SQL is a query, then for each row in the query result
|
|
||||||
** the xCallback() function is called. pArg becomes the first
|
|
||||||
** argument to xCallback(). If xCallback=NULL then no callback
|
|
||||||
** is invoked, even for queries.
|
|
||||||
*/
|
*/
|
||||||
int sqlite_exec(
|
static int sqliteMain(
|
||||||
sqlite *db, /* The database on which the SQL executes */
|
sqlite *db, /* The database on which the SQL executes */
|
||||||
const char *zSql, /* The SQL to be executed */
|
const char *zSql, /* The SQL to be executed */
|
||||||
sqlite_callback xCallback, /* Invoke this callback routine */
|
sqlite_callback xCallback, /* Invoke this callback routine */
|
||||||
void *pArg, /* First argument to xCallback() */
|
void *pArg, /* First argument to xCallback() */
|
||||||
char **pzErrMsg /* Write error messages here */
|
const char **pzTail, /* OUT: Next statement after the first */
|
||||||
|
sqlite_vm **ppVm, /* OUT: The virtual machine */
|
||||||
|
char **pzErrMsg /* OUT: Write error messages here */
|
||||||
){
|
){
|
||||||
Parse sParse;
|
Parse sParse;
|
||||||
|
|
||||||
if( pzErrMsg ) *pzErrMsg = 0;
|
if( pzErrMsg ) *pzErrMsg = 0;
|
||||||
if( sqliteSafetyOn(db) ) goto exec_misuse;
|
if( sqliteSafetyOn(db) ) goto exec_misuse;
|
||||||
#ifndef SQLITE_OMIT_TRACE
|
|
||||||
if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
|
|
||||||
#endif
|
|
||||||
if( (db->flags & SQLITE_Initialized)==0 ){
|
if( (db->flags & SQLITE_Initialized)==0 ){
|
||||||
int rc, cnt = 1;
|
int rc, cnt = 1;
|
||||||
while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY
|
while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY
|
||||||
@@ -633,6 +629,10 @@ int sqlite_exec(
|
|||||||
sParse.pBe = db->pBe;
|
sParse.pBe = db->pBe;
|
||||||
sParse.xCallback = xCallback;
|
sParse.xCallback = xCallback;
|
||||||
sParse.pArg = pArg;
|
sParse.pArg = pArg;
|
||||||
|
sParse.useCallback = ppVm==0;
|
||||||
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
|
if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
|
||||||
|
#endif
|
||||||
sqliteRunParser(&sParse, zSql, pzErrMsg);
|
sqliteRunParser(&sParse, zSql, pzErrMsg);
|
||||||
if( sqlite_malloc_failed ){
|
if( sqlite_malloc_failed ){
|
||||||
sqliteSetString(pzErrMsg, "out of memory", 0);
|
sqliteSetString(pzErrMsg, "out of memory", 0);
|
||||||
@@ -650,6 +650,11 @@ int sqlite_exec(
|
|||||||
sqliteResetInternalSchema(db);
|
sqliteResetInternalSchema(db);
|
||||||
}
|
}
|
||||||
db->recursionDepth--;
|
db->recursionDepth--;
|
||||||
|
if( sParse.useCallback==0 ){
|
||||||
|
assert( ppVm );
|
||||||
|
*ppVm = sParse.pVdbe;
|
||||||
|
*pzTail = &sParse.sLastToken.z[sParse.sLastToken.n];
|
||||||
|
}
|
||||||
if( sqliteSafetyOff(db) ) goto exec_misuse;
|
if( sqliteSafetyOff(db) ) goto exec_misuse;
|
||||||
return sParse.rc;
|
return sParse.rc;
|
||||||
|
|
||||||
@@ -662,6 +667,59 @@ exec_misuse:
|
|||||||
return SQLITE_MISUSE;
|
return SQLITE_MISUSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Execute SQL code. Return one of the SQLITE_ success/failure
|
||||||
|
** codes. Also write an error message into memory obtained from
|
||||||
|
** malloc() and make *pzErrMsg point to that message.
|
||||||
|
**
|
||||||
|
** If the SQL is a query, then for each row in the query result
|
||||||
|
** the xCallback() function is called. pArg becomes the first
|
||||||
|
** argument to xCallback(). If xCallback=NULL then no callback
|
||||||
|
** is invoked, even for queries.
|
||||||
|
*/
|
||||||
|
int sqlite_exec(
|
||||||
|
sqlite *db, /* The database on which the SQL executes */
|
||||||
|
const char *zSql, /* The SQL to be executed */
|
||||||
|
sqlite_callback xCallback, /* Invoke this callback routine */
|
||||||
|
void *pArg, /* First argument to xCallback() */
|
||||||
|
char **pzErrMsg /* Write error messages here */
|
||||||
|
){
|
||||||
|
return sqliteMain(db, zSql, xCallback, pArg, 0, 0, pzErrMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Compile a single statement of SQL into a virtual machine. Return one
|
||||||
|
** of the SQLITE_ success/failure codes. Also write an error message into
|
||||||
|
** memory obtained from malloc() and make *pzErrMsg point to that message.
|
||||||
|
*/
|
||||||
|
int sqlite_compile(
|
||||||
|
sqlite *db, /* The database on which the SQL executes */
|
||||||
|
const char *zSql, /* The SQL to be executed */
|
||||||
|
const char **pzTail, /* OUT: Next statement after the first */
|
||||||
|
sqlite_vm **ppVm, /* OUT: The virtual machine */
|
||||||
|
char **pzErrMsg /* OUT: Write error messages here */
|
||||||
|
){
|
||||||
|
return sqliteMain(db, zSql, 0, 0, pzTail, ppVm, pzErrMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following routine destroys a virtual machine that is created by
|
||||||
|
** the sqlite_compile() routine.
|
||||||
|
**
|
||||||
|
** The integer returned is an SQLITE_ success/failure code that describes
|
||||||
|
** the result of executing the virtual machine. An error message is
|
||||||
|
** written into memory obtained from malloc and *pzErrMsg is made to
|
||||||
|
** point to that error if pzErrMsg is not NULL. The calling routine
|
||||||
|
** should use sqlite_freemem() to delete the message when it has finished
|
||||||
|
** with it.
|
||||||
|
*/
|
||||||
|
int sqlite_finalize(
|
||||||
|
sqlite_vm *pVm, /* The virtual machine to be destroyed */
|
||||||
|
char **pzErrMsg /* OUT: Write error messages here */
|
||||||
|
){
|
||||||
|
return sqliteVdbeFinalize((Vdbe*)pVm, pzErrMsg);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return a static string that describes the kind of error specified in the
|
** Return a static string that describes the kind of error specified in the
|
||||||
** argument.
|
** argument.
|
||||||
|
13
src/parse.y
13
src/parse.y
@@ -14,15 +14,22 @@
|
|||||||
** the parser. Lemon will also generate a header file containing
|
** the parser. Lemon will also generate a header file containing
|
||||||
** numeric codes for all of the tokens.
|
** numeric codes for all of the tokens.
|
||||||
**
|
**
|
||||||
** @(#) $Id: parse.y,v 1.88 2003/01/18 20:11:07 drh Exp $
|
** @(#) $Id: parse.y,v 1.89 2003/01/28 23:13:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
%token_prefix TK_
|
%token_prefix TK_
|
||||||
%token_type {Token}
|
%token_type {Token}
|
||||||
%default_type {Token}
|
%default_type {Token}
|
||||||
%extra_argument {Parse *pParse}
|
%extra_argument {Parse *pParse}
|
||||||
%syntax_error {
|
%syntax_error {
|
||||||
sqliteSetString(&pParse->zErrMsg,"syntax error",0);
|
if( pParse->zErrMsg==0 ){
|
||||||
pParse->sErrToken = TOKEN;
|
if( TOKEN.z[0] ){
|
||||||
|
sqliteSetNString(&pParse->zErrMsg,
|
||||||
|
"near \"", -1, TOKEN.z, TOKEN.n, "\": syntax error", -1, 0);
|
||||||
|
}else{
|
||||||
|
sqliteSetString(&pParse->zErrMsg, "incomplete SQL statement", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pParse->nErr++;
|
||||||
}
|
}
|
||||||
%name sqliteParser
|
%name sqliteParser
|
||||||
%include {
|
%include {
|
||||||
|
146
src/sqlite.h.in
146
src/sqlite.h.in
@@ -12,17 +12,12 @@
|
|||||||
** This header file defines the interface that the SQLite library
|
** This header file defines the interface that the SQLite library
|
||||||
** presents to client programs.
|
** presents to client programs.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqlite.h.in,v 1.39 2003/01/16 16:28:54 drh Exp $
|
** @(#) $Id: sqlite.h.in,v 1.40 2003/01/28 23:13:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_H_
|
#ifndef _SQLITE_H_
|
||||||
#define _SQLITE_H_
|
#define _SQLITE_H_
|
||||||
#include <stdarg.h> /* Needed for the definition of va_list */
|
#include <stdarg.h> /* Needed for the definition of va_list */
|
||||||
|
|
||||||
/*
|
|
||||||
** The version of the SQLite library.
|
|
||||||
*/
|
|
||||||
#define SQLITE_VERSION "--VERS--"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Make sure we can call this stuff from C++.
|
** Make sure we can call this stuff from C++.
|
||||||
*/
|
*/
|
||||||
@@ -30,6 +25,11 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The version of the SQLite library.
|
||||||
|
*/
|
||||||
|
#define SQLITE_VERSION "--VERS--"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The version string is also compiled into the library so that a program
|
** The version string is also compiled into the library so that a program
|
||||||
** can check to make sure that the lib*.a file and the *.h file are from
|
** can check to make sure that the lib*.a file and the *.h file are from
|
||||||
@@ -73,7 +73,7 @@ typedef struct sqlite sqlite;
|
|||||||
** The Truth: As currently implemented, all databases are opened
|
** The Truth: As currently implemented, all databases are opened
|
||||||
** for writing all the time. Maybe someday we will provide the
|
** for writing all the time. Maybe someday we will provide the
|
||||||
** ability to open a database readonly. The mode parameters is
|
** ability to open a database readonly. The mode parameters is
|
||||||
** provide in anticipation of that enhancement.
|
** provided in anticipation of that enhancement.
|
||||||
*/
|
*/
|
||||||
sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
|
sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
|
||||||
|
|
||||||
@@ -118,7 +118,8 @@ typedef int (*sqlite_callback)(void*,int,char**, char**);
|
|||||||
** message is written into memory obtained from malloc() and
|
** message is written into memory obtained from malloc() and
|
||||||
** *errmsg is made to point to that message. The calling function
|
** *errmsg is made to point to that message. The calling function
|
||||||
** is responsible for freeing the memory that holds the error
|
** is responsible for freeing the memory that holds the error
|
||||||
** message. If errmsg==NULL, then no error message is ever written.
|
** message. Use sqlite_freemem() for this. If errmsg==NULL,
|
||||||
|
** then no error message is ever written.
|
||||||
**
|
**
|
||||||
** The return value is is SQLITE_OK if there are no errors and
|
** The return value is is SQLITE_OK if there are no errors and
|
||||||
** some other return code if there is an error. The particular
|
** some other return code if there is an error. The particular
|
||||||
@@ -138,7 +139,7 @@ int sqlite_exec(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return values for sqlite_exec()
|
** Return values for sqlite_exec() and sqlite_step()
|
||||||
*/
|
*/
|
||||||
#define SQLITE_OK 0 /* Successful result */
|
#define SQLITE_OK 0 /* Successful result */
|
||||||
#define SQLITE_ERROR 1 /* SQL error or missing database */
|
#define SQLITE_ERROR 1 /* SQL error or missing database */
|
||||||
@@ -164,6 +165,8 @@ int sqlite_exec(
|
|||||||
#define SQLITE_MISUSE 21 /* Library used incorrectly */
|
#define SQLITE_MISUSE 21 /* Library used incorrectly */
|
||||||
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
|
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
|
||||||
#define SQLITE_AUTH 23 /* Authorization denied */
|
#define SQLITE_AUTH 23 /* Authorization denied */
|
||||||
|
#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
|
||||||
|
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Each entry in an SQLite table has a unique integer key. (The key is
|
** Each entry in an SQLite table has a unique integer key. (The key is
|
||||||
@@ -501,10 +504,11 @@ int sqlite_aggregate_count(sqlite_func*);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine registers a callback with the SQLite library. The
|
** This routine registers a callback with the SQLite library. The
|
||||||
** callback is invoked for every attempt to access a column of a table
|
** callback is invoked (at compile-time, not at run-time) for each
|
||||||
** in the database. The callback returns SQLITE_OK if access is allowed,
|
** attempt to access a column of a table in the database. The callback
|
||||||
** SQLITE_DENY if the entire SQL statement should be aborted with an error
|
** returns SQLITE_OK if access is allowed, SQLITE_DENY if the entire
|
||||||
** and SQLITE_IGNORE if the column should be treated as a NULL value.
|
** SQL statement should be aborted with an error and SQLITE_IGNORE
|
||||||
|
** if the column should be treated as a NULL value.
|
||||||
*/
|
*/
|
||||||
int sqlite_set_authorizer(
|
int sqlite_set_authorizer(
|
||||||
sqlite*,
|
sqlite*,
|
||||||
@@ -555,17 +559,127 @@ int sqlite_set_authorizer(
|
|||||||
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
|
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Register a function that is called at every invocation of sqlite_exec().
|
** Register a function that is called at every invocation of sqlite_exec()
|
||||||
** This function can be used (for example) to generate a log file of all
|
** or sqlite_compile(). This function can be used (for example) to generate
|
||||||
** SQL executed against a database.
|
** a log file of all SQL executed against a database.
|
||||||
*/
|
*/
|
||||||
void *sqlite_trace(sqlite*, void(*xTrace)(void*,const char*), void*);
|
void *sqlite_trace(sqlite*, void(*xTrace)(void*,const char*), void*);
|
||||||
|
|
||||||
|
/*** The Callback-Free API
|
||||||
|
**
|
||||||
|
** The following routines implement a new way to access SQLite that does not
|
||||||
|
** involve the use of callbacks.
|
||||||
|
**
|
||||||
|
** An sqlite_vm is an opaque object that represents a single SQL statement
|
||||||
|
** that is ready to be executed.
|
||||||
|
*/
|
||||||
|
typedef struct sqlite_vm sqlite_vm;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** To execute an SQLite query without the use of callbacks, you first have
|
||||||
|
** to compile the SQL using this routine. The 1st parameter "db" is a pointer
|
||||||
|
** to an sqlite object obtained from sqlite_open(). The 2nd parameter
|
||||||
|
** "zSql" is the text of the SQL to be compiled. The remaining parameters
|
||||||
|
** are all outputs.
|
||||||
|
**
|
||||||
|
** *pzTail is made to point to the first character past the end of the first
|
||||||
|
** SQL statement in zSql. This routine only compiles the first statement
|
||||||
|
** in zSql, so *pzTail is left pointing to what remains uncompiled.
|
||||||
|
**
|
||||||
|
** *ppVm is left pointing to a "virtual machine" that can be used to execute
|
||||||
|
** the compiled statement. Or if there is an error, *ppVm may be set to NULL.
|
||||||
|
**
|
||||||
|
** If any errors are detected during compilation, an error message is written
|
||||||
|
** into space obtained from malloc() and *pzErrMsg is made to point to that
|
||||||
|
** error message. The calling routine is responsible for freeing the text
|
||||||
|
** of this message when it has finished with it. Use sqlite_freemem() to
|
||||||
|
** free the message. pzErrMsg may be NULL in which case no error message
|
||||||
|
** will be generated.
|
||||||
|
**
|
||||||
|
** On success, SQLITE_OK is returned. Otherwise and error code is returned.
|
||||||
|
*/
|
||||||
|
int sqlite_compile(
|
||||||
|
sqlite *db, /* The open database */
|
||||||
|
const char *zSql, /* SQL statement to be compiled */
|
||||||
|
const char **pzTail, /* OUT: uncompiled tail of zSql */
|
||||||
|
sqlite_vm **ppVm, /* OUT: the virtual machine to execute zSql */
|
||||||
|
char **pzErrmsg /* OUT: Error message. */
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** After an SQL statement has been compiled, it is handed to this routine
|
||||||
|
** to be executed. This routine executes the statement as far as it can
|
||||||
|
** go then returns. The return value will be one of SQLITE_DONE,
|
||||||
|
** SQLITE_ERROR, SQLITE_BUSY, SQLITE_ROW, or SQLITE_MISUSE.
|
||||||
|
**
|
||||||
|
** SQLITE_DONE means that the execute of the SQL statement is complete
|
||||||
|
** an no errors have occurred. sqlite_step() should not be called again
|
||||||
|
** for the same virtual machine. *pN is set to the number of columns in
|
||||||
|
** the result set and *pazColName is set to an array of strings that
|
||||||
|
** describe the column names and datatypes. The name of the i-th column
|
||||||
|
** is (*pazColName)[i] and the datatype of the i-th column is
|
||||||
|
** (*pazColName)[i+*pN]. *pazValue is set to NULL.
|
||||||
|
**
|
||||||
|
** SQLITE_ERROR means that the virtual machine encountered a run-time
|
||||||
|
** error. sqlite_step() should not be called again for the same
|
||||||
|
** virtual machine. *pN is set to 0 and *pazColName and *pazValue are set
|
||||||
|
** to NULL. Use sqlite_finalize() to obtain the specific error code
|
||||||
|
** and the error message text for the error.
|
||||||
|
**
|
||||||
|
** SQLITE_BUSY means that an attempt to open the database failed because
|
||||||
|
** another thread or process is holding a lock. The calling routine
|
||||||
|
** can try again to open the database by calling sqlite_step() again.
|
||||||
|
** The return code will only be SQLITE_BUSY if no busy handler is registered
|
||||||
|
** using the sqlite_busy_handler() or sqlite_busy_timeout() routines. If
|
||||||
|
** a busy handler callback has been registered but returns 0, then this
|
||||||
|
** routine will return SQLITE_ERROR and sqltie_finalize() will return
|
||||||
|
** SQLITE_BUSY when it is called.
|
||||||
|
**
|
||||||
|
** SQLITE_ROW means that a single row of the result is now available.
|
||||||
|
** The data is contained in *pazValue. The value of the i-th column is
|
||||||
|
** (*azValue)[i]. *pN and *pazColName are set as described in SQLITE_DONE.
|
||||||
|
** Invoke sqlite_step() again to advance to the next row.
|
||||||
|
**
|
||||||
|
** SQLITE_MISUSE is returned if sqlite_step() is called incorrectly.
|
||||||
|
** For example, if you call sqlite_step() after the virtual machine
|
||||||
|
** has halted (after a prior call to sqlite_step() has returned SQLITE_DONE)
|
||||||
|
** or if you call sqlite_step() with an incorrectly initialized virtual
|
||||||
|
** machine or a virtual machine that has been deleted or that is associated
|
||||||
|
** with an sqlite structure that has been closed.
|
||||||
|
*/
|
||||||
|
int sqlite_step(
|
||||||
|
sqlite_vm *pVm, /* The virtual machine to execute */
|
||||||
|
int *pN, /* OUT: Number of columns in result */
|
||||||
|
const char ***pazValue, /* OUT: Column data */
|
||||||
|
const char ***pazColName /* OUT: Column names and datatypes */
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine is called to delete a virtual machine after it has finished
|
||||||
|
** executing. The return value is the result code. SQLITE_OK is returned
|
||||||
|
** if the statement executed successfully and some other value is returned if
|
||||||
|
** there was any kind of error. If an error occurred and pzErrMsg is not
|
||||||
|
** NULL, then an error message is written into memory obtained from malloc()
|
||||||
|
** and *pzErrMsg is made to point to that error message. The calling routine
|
||||||
|
** should use sqlite_freemem() to delete this message when it has finished
|
||||||
|
** with it.
|
||||||
|
**
|
||||||
|
** This routine can be called at any point during the execution of the
|
||||||
|
** virtual machine. If the virtual machine has not completed execution
|
||||||
|
** when this routine is called, that is like encountering an error or
|
||||||
|
** an interrupt. (See sqlite_interrupt().) Incomplete updates may be
|
||||||
|
** rolled back and transactions cancelled, depending on the circumstances,
|
||||||
|
** and the result code returned will be SQLITE_ABORT.
|
||||||
|
*/
|
||||||
|
int sqlite_finalize(sqlite_vm*, char **pzErrMsg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Attempt to open the file named in the argument as the auxiliary database
|
** Attempt to open the file named in the argument as the auxiliary database
|
||||||
** file. The auxiliary database file is used to store TEMP tables. But
|
** file. The auxiliary database file is used to store TEMP tables. But
|
||||||
** by using this API, it is possible to trick SQLite into opening two
|
** by using this API, it is possible to trick SQLite into opening two
|
||||||
** separate databases and acting on them as if they were one.
|
** separate databases and acting on them as if they were one.
|
||||||
|
**
|
||||||
|
****** THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE. ******
|
||||||
*/
|
*/
|
||||||
int sqlite_open_aux_file(sqlite *db, const char *zName, char **pzErrMsg);
|
int sqlite_open_aux_file(sqlite *db, const char *zName, char **pzErrMsg);
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.156 2003/01/18 20:11:07 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.157 2003/01/28 23:13:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
@@ -748,6 +748,7 @@ struct Parse {
|
|||||||
u8 schemaVerified; /* True if an OP_VerifySchema has been coded someplace
|
u8 schemaVerified; /* True if an OP_VerifySchema has been coded someplace
|
||||||
** other than after an OP_Transaction */
|
** other than after an OP_Transaction */
|
||||||
u8 isTemp; /* True if parsing temporary tables */
|
u8 isTemp; /* True if parsing temporary tables */
|
||||||
|
u8 useCallback; /* True if callbacks should be used to report results */
|
||||||
int newTnum; /* Table number to use when reparsing CREATE TABLEs */
|
int newTnum; /* Table number to use when reparsing CREATE TABLEs */
|
||||||
int nErr; /* Number of errors seen */
|
int nErr; /* Number of errors seen */
|
||||||
int nTab; /* Number of previously allocated VDBE cursors */
|
int nTab; /* Number of previously allocated VDBE cursors */
|
||||||
|
172
src/test1.c
172
src/test1.c
@@ -13,13 +13,35 @@
|
|||||||
** is not included in the SQLite library. It is used for automated
|
** is not included in the SQLite library. It is used for automated
|
||||||
** testing of the SQLite library.
|
** testing of the SQLite library.
|
||||||
**
|
**
|
||||||
** $Id: test1.c,v 1.16 2003/01/13 23:27:33 drh Exp $
|
** $Id: test1.c,v 1.17 2003/01/28 23:13:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "tcl.h"
|
#include "tcl.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Decode a pointer to an sqlite object.
|
||||||
|
*/
|
||||||
|
static int getDbPointer(Tcl_Interp *interp, const char *zArg, sqlite **ppDb){
|
||||||
|
if( sscanf(zArg, "%p", (void**)ppDb)!=1 ){
|
||||||
|
Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Decode a pointer to an sqlite_vm object.
|
||||||
|
*/
|
||||||
|
static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){
|
||||||
|
if( sscanf(zArg, "%p", (void**)ppVm)!=1 ){
|
||||||
|
Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: sqlite_open filename
|
** Usage: sqlite_open filename
|
||||||
**
|
**
|
||||||
@@ -45,7 +67,7 @@ static int sqlite_test_open(
|
|||||||
free(zErr);
|
free(zErr);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
sprintf(zBuf,"%d",(int)db);
|
sprintf(zBuf,"%p", db);
|
||||||
Tcl_AppendResult(interp, zBuf, 0);
|
Tcl_AppendResult(interp, zBuf, 0);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
@@ -91,7 +113,7 @@ static int test_exec_printf(
|
|||||||
" DB FORMAT STRING", 0);
|
" DB FORMAT STRING", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
db = (sqlite*)strtol(argv[1], 0, 0);
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
Tcl_DStringInit(&str);
|
Tcl_DStringInit(&str);
|
||||||
rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
|
rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
|
||||||
sprintf(zBuf, "%d", rc);
|
sprintf(zBuf, "%d", rc);
|
||||||
@@ -128,7 +150,7 @@ static int test_get_table_printf(
|
|||||||
" DB FORMAT STRING", 0);
|
" DB FORMAT STRING", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
db = (sqlite*)strtol(argv[1], 0, 0);
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
Tcl_DStringInit(&str);
|
Tcl_DStringInit(&str);
|
||||||
rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
|
rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
|
||||||
&zErr, argv[3]);
|
&zErr, argv[3]);
|
||||||
@@ -169,7 +191,7 @@ static int test_last_rowid(
|
|||||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
db = (sqlite*)strtol(argv[1], 0, 0);
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
sprintf(zBuf, "%d", sqlite_last_insert_rowid(db));
|
sprintf(zBuf, "%d", sqlite_last_insert_rowid(db));
|
||||||
Tcl_AppendResult(interp, zBuf, 0);
|
Tcl_AppendResult(interp, zBuf, 0);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
@@ -192,7 +214,7 @@ static int sqlite_test_close(
|
|||||||
" FILENAME\"", 0);
|
" FILENAME\"", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
db = (sqlite*)strtol(argv[1], 0, 0);
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
sqlite_close(db);
|
sqlite_close(db);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
@@ -251,7 +273,7 @@ static int test_create_function(
|
|||||||
" FILENAME\"", 0);
|
" FILENAME\"", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
db = (sqlite*)strtol(argv[1], 0, 0);
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
|
sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
|
||||||
sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
|
sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
@@ -300,7 +322,7 @@ static int test_create_aggregate(
|
|||||||
" FILENAME\"", 0);
|
" FILENAME\"", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
db = (sqlite*)strtol(argv[1], 0, 0);
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
|
sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
|
||||||
sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
|
sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
@@ -497,7 +519,7 @@ static int test_register_func(
|
|||||||
" DB FUNCTION-NAME", 0);
|
" DB FUNCTION-NAME", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
db = (sqlite*)strtol(argv[1], 0, 0);
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
rc = sqlite_create_function(db, argv[2], -1, testFunc, 0);
|
rc = sqlite_create_function(db, argv[2], -1, testFunc, 0);
|
||||||
if( rc!=0 ){
|
if( rc!=0 ){
|
||||||
Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
|
Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
|
||||||
@@ -550,7 +572,7 @@ static int sqlite_datatypes(
|
|||||||
" DB SQL", 0);
|
" DB SQL", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
db = (sqlite*)strtol(argv[1], 0, 0);
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0);
|
rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0);
|
||||||
if( rc!=0 && rc!=SQLITE_ABORT ){
|
if( rc!=0 && rc!=SQLITE_ABORT ){
|
||||||
Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
|
Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
|
||||||
@@ -659,7 +681,7 @@ static int test_set_authorizer(
|
|||||||
" DB CALLBACK\"", 0);
|
" DB CALLBACK\"", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
db = (sqlite*)strtol(argv[1], 0, 0);
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
zCmd = argv[2];
|
zCmd = argv[2];
|
||||||
if( zCmd[0]==0 ){
|
if( zCmd[0]==0 ){
|
||||||
sqlite_set_authorizer(db, 0, 0);
|
sqlite_set_authorizer(db, 0, 0);
|
||||||
@@ -677,6 +699,131 @@ static int test_set_authorizer(
|
|||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Usage: sqlite_compile DB SQL TAILVAR
|
||||||
|
**
|
||||||
|
** Attempt to compile an SQL statement. Return a pointer to the virtual
|
||||||
|
** machine used to execute that statement. Unprocessed SQL is written
|
||||||
|
** into TAILVAR.
|
||||||
|
*/
|
||||||
|
static int test_compile(
|
||||||
|
void *NotUsed,
|
||||||
|
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||||
|
int argc, /* Number of arguments */
|
||||||
|
char **argv /* Text of each argument */
|
||||||
|
){
|
||||||
|
sqlite *db;
|
||||||
|
sqlite_vm *vm;
|
||||||
|
int rc;
|
||||||
|
char *zErr = 0;
|
||||||
|
const char *zTail;
|
||||||
|
char zBuf[50];
|
||||||
|
if( argc!=4 ){
|
||||||
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||||
|
" DB SQL TAILVAR", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
|
rc = sqlite_compile(db, argv[2], &zTail, &vm, &zErr);
|
||||||
|
if( rc ){
|
||||||
|
assert( vm==0 );
|
||||||
|
sprintf(zBuf, "(%d) ", rc);
|
||||||
|
Tcl_AppendResult(interp, zBuf, zErr, 0);
|
||||||
|
sqlite_freemem(zErr);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
sprintf(zBuf, "%p", vm);
|
||||||
|
Tcl_AppendResult(interp, zBuf, 0);
|
||||||
|
Tcl_SetVar(interp, argv[3], zTail, 0);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Usage: sqlite_step VM NVAR VALUEVAR COLNAMEVAR
|
||||||
|
**
|
||||||
|
** Step a virtual machine. Return a the result code as a string.
|
||||||
|
** Column results are written into three variables.
|
||||||
|
*/
|
||||||
|
static int test_step(
|
||||||
|
void *NotUsed,
|
||||||
|
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||||
|
int argc, /* Number of arguments */
|
||||||
|
char **argv /* Text of each argument */
|
||||||
|
){
|
||||||
|
sqlite_vm *vm;
|
||||||
|
int rc, i;
|
||||||
|
const char **azValue;
|
||||||
|
const char **azColName;
|
||||||
|
int N;
|
||||||
|
char *zRc;
|
||||||
|
char zBuf[50];
|
||||||
|
if( argc!=5 ){
|
||||||
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||||
|
" VM NVAR VALUEVAR COLNAMEVAR", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
|
||||||
|
rc = sqlite_step(vm, &N, &azValue, &azColName);
|
||||||
|
if( rc==SQLITE_DONE || SQLITE_ROW ){
|
||||||
|
sprintf(zBuf, "%d", N);
|
||||||
|
Tcl_SetVar(interp, argv[2], zBuf, 0);
|
||||||
|
Tcl_SetVar(interp, argv[3], "", 0);
|
||||||
|
if( rc==SQLITE_ROW ){
|
||||||
|
for(i=0; i<N; i++){
|
||||||
|
Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "",
|
||||||
|
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tcl_SetVar(interp, argv[4], "", 0);
|
||||||
|
for(i=0; i<N*2; i++){
|
||||||
|
Tcl_SetVar(interp, argv[4], azValue[i] ? azValue[i] : "",
|
||||||
|
TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch( rc ){
|
||||||
|
case SQLITE_DONE: zRc = "SQLITE_DONE"; break;
|
||||||
|
case SQLITE_BUSY: zRc = "SQLITE_DONE"; break;
|
||||||
|
case SQLITE_ROW: zRc = "SQLITE_DONE"; break;
|
||||||
|
case SQLITE_ERROR: zRc = "SQLITE_DONE"; break;
|
||||||
|
case SQLITE_MISUSE: zRc = "SQLITE_MISUSE"; break;
|
||||||
|
default: zRc = "unknown"; break;
|
||||||
|
}
|
||||||
|
Tcl_AppendResult(interp, zRc, 0);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Usage: sqlite_finalize VM
|
||||||
|
**
|
||||||
|
** Shutdown a virtual machine.
|
||||||
|
*/
|
||||||
|
static int test_finalize(
|
||||||
|
void *NotUsed,
|
||||||
|
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||||
|
int argc, /* Number of arguments */
|
||||||
|
char **argv /* Text of each argument */
|
||||||
|
){
|
||||||
|
sqlite_vm *vm;
|
||||||
|
int rc;
|
||||||
|
char *zErrMsg = 0;
|
||||||
|
if( argc!=2 ){
|
||||||
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||||
|
" VM NVAR VALUEVAR COLNAMEVAR", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
|
||||||
|
rc = sqlite_finalize(vm, &zErrMsg);
|
||||||
|
if( rc ){
|
||||||
|
char zBuf[50];
|
||||||
|
sprintf(zBuf, "(%d) ", rc);
|
||||||
|
Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
|
||||||
|
sqlite_freemem(zErrMsg);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Register commands with the TCL interpreter.
|
** Register commands with the TCL interpreter.
|
||||||
*/
|
*/
|
||||||
@@ -706,6 +853,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||||||
{ "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
|
{ "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
|
||||||
{ "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
|
{ "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
|
||||||
#endif
|
#endif
|
||||||
|
{ "sqlite_compile", (Tcl_CmdProc*)test_compile },
|
||||||
|
{ "sqlite_step", (Tcl_CmdProc*)test_step },
|
||||||
|
{ "sqlite_finalize", (Tcl_CmdProc*)test_finalize },
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
** individual tokens and sends those tokens one-by-one over to the
|
** individual tokens and sends those tokens one-by-one over to the
|
||||||
** parser for analysis.
|
** parser for analysis.
|
||||||
**
|
**
|
||||||
** $Id: tokenize.c,v 1.53 2003/01/07 02:47:48 drh Exp $
|
** $Id: tokenize.c,v 1.54 2003/01/28 23:13:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@@ -406,6 +406,8 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
|||||||
int nErr = 0;
|
int nErr = 0;
|
||||||
int i;
|
int i;
|
||||||
void *pEngine;
|
void *pEngine;
|
||||||
|
int tokenType;
|
||||||
|
int lastTokenParsed = -1;
|
||||||
sqlite *db = pParse->db;
|
sqlite *db = pParse->db;
|
||||||
extern void *sqliteParserAlloc(void*(*)(int));
|
extern void *sqliteParserAlloc(void*(*)(int));
|
||||||
extern void sqliteParserFree(void*, void(*)(void*));
|
extern void sqliteParserFree(void*, void(*)(void*));
|
||||||
@@ -421,7 +423,6 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
|||||||
}
|
}
|
||||||
pParse->sLastToken.dyn = 0;
|
pParse->sLastToken.dyn = 0;
|
||||||
while( sqlite_malloc_failed==0 && zSql[i]!=0 ){
|
while( sqlite_malloc_failed==0 && zSql[i]!=0 ){
|
||||||
int tokenType;
|
|
||||||
|
|
||||||
assert( i>=0 );
|
assert( i>=0 );
|
||||||
pParse->sLastToken.z = &zSql[i];
|
pParse->sLastToken.z = &zSql[i];
|
||||||
@@ -446,19 +447,8 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
|||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
sqliteParser(pEngine, tokenType, pParse->sLastToken, pParse);
|
sqliteParser(pEngine, tokenType, pParse->sLastToken, pParse);
|
||||||
if( pParse->zErrMsg && pParse->sErrToken.z ){
|
lastTokenParsed = tokenType;
|
||||||
sqliteSetNString(pzErrMsg, "near \"", -1,
|
if( pParse->rc!=SQLITE_OK ){
|
||||||
pParse->sErrToken.z, pParse->sErrToken.n,
|
|
||||||
"\": ", -1,
|
|
||||||
pParse->zErrMsg, -1,
|
|
||||||
0);
|
|
||||||
nErr++;
|
|
||||||
sqliteFree(pParse->zErrMsg);
|
|
||||||
pParse->zErrMsg = 0;
|
|
||||||
goto abort_parse;
|
|
||||||
}else if( pParse->rc!=SQLITE_OK ){
|
|
||||||
sqliteSetString(pzErrMsg, sqlite_error_string(pParse->rc), 0);
|
|
||||||
nErr++;
|
|
||||||
goto abort_parse;
|
goto abort_parse;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -466,31 +456,26 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
abort_parse:
|
abort_parse:
|
||||||
if( zSql[i]==0 && nErr==0 ){
|
if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
|
||||||
|
if( lastTokenParsed!=TK_SEMI ){
|
||||||
sqliteParser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
|
sqliteParser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
|
||||||
sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
|
|
||||||
if( pParse->zErrMsg && pParse->sErrToken.z ){
|
|
||||||
sqliteSetNString(pzErrMsg, "near \"", -1,
|
|
||||||
pParse->sErrToken.z, pParse->sErrToken.n,
|
|
||||||
"\": ", -1,
|
|
||||||
pParse->zErrMsg, -1,
|
|
||||||
0);
|
|
||||||
nErr++;
|
|
||||||
sqliteFree(pParse->zErrMsg);
|
|
||||||
pParse->zErrMsg = 0;
|
|
||||||
}
|
}
|
||||||
|
sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
|
||||||
}
|
}
|
||||||
sqliteParserFree(pEngine, free);
|
sqliteParserFree(pEngine, free);
|
||||||
|
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
|
||||||
|
sqliteSetString(&pParse->zErrMsg, sqlite_error_string(pParse->rc), 0);
|
||||||
|
}
|
||||||
if( pParse->zErrMsg ){
|
if( pParse->zErrMsg ){
|
||||||
if( pzErrMsg ){
|
if( pzErrMsg && *pzErrMsg==0 ){
|
||||||
sqliteFree(*pzErrMsg);
|
|
||||||
*pzErrMsg = pParse->zErrMsg;
|
*pzErrMsg = pParse->zErrMsg;
|
||||||
}else{
|
}else{
|
||||||
sqliteFree(pParse->zErrMsg);
|
sqliteFree(pParse->zErrMsg);
|
||||||
}
|
}
|
||||||
|
pParse->zErrMsg = 0;
|
||||||
if( !nErr ) nErr++;
|
if( !nErr ) nErr++;
|
||||||
}
|
}
|
||||||
if( pParse->pVdbe ){
|
if( pParse->pVdbe && (pParse->useCallback || pParse->nErr>0) ){
|
||||||
sqliteVdbeDelete(pParse->pVdbe);
|
sqliteVdbeDelete(pParse->pVdbe);
|
||||||
pParse->pVdbe = 0;
|
pParse->pVdbe = 0;
|
||||||
}
|
}
|
||||||
@@ -498,7 +483,7 @@ abort_parse:
|
|||||||
sqliteDeleteTable(pParse->db, pParse->pNewTable);
|
sqliteDeleteTable(pParse->db, pParse->pNewTable);
|
||||||
pParse->pNewTable = 0;
|
pParse->pNewTable = 0;
|
||||||
}
|
}
|
||||||
if( nErr>0 && pParse->rc==SQLITE_OK ){
|
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
|
||||||
pParse->rc = SQLITE_ERROR;
|
pParse->rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
return nErr;
|
return nErr;
|
||||||
|
628
src/vdbe.c
628
src/vdbe.c
@@ -36,7 +36,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** commenting and indentation practices when changing or adding code.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.199 2003/01/19 03:59:47 drh Exp $
|
** $Id: vdbe.c,v 1.200 2003/01/28 23:13:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -234,7 +234,11 @@ struct Keylist {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** An instance of the virtual machine
|
** An instance of the virtual machine. This structure contains the complete
|
||||||
|
** state of the virtual machine.
|
||||||
|
**
|
||||||
|
** The "sqlite_vm" structure pointer that is returned by sqlite_compile()
|
||||||
|
** is really a pointer to an instance of this structure.
|
||||||
*/
|
*/
|
||||||
struct Vdbe {
|
struct Vdbe {
|
||||||
sqlite *db; /* The whole database */
|
sqlite *db; /* The whole database */
|
||||||
@@ -252,12 +256,12 @@ struct Vdbe {
|
|||||||
char **azColName; /* Becomes the 4th parameter to callbacks */
|
char **azColName; /* Becomes the 4th parameter to callbacks */
|
||||||
int nCursor; /* Number of slots in aCsr[] */
|
int nCursor; /* Number of slots in aCsr[] */
|
||||||
Cursor *aCsr; /* One element of this array for each open cursor */
|
Cursor *aCsr; /* One element of this array for each open cursor */
|
||||||
Keylist *pList; /* A list of ROWIDs */
|
|
||||||
Sorter *pSort; /* A linked list of objects to be sorted */
|
Sorter *pSort; /* A linked list of objects to be sorted */
|
||||||
FILE *pFile; /* At most one open file handler */
|
FILE *pFile; /* At most one open file handler */
|
||||||
int nField; /* Number of file fields */
|
int nField; /* Number of file fields */
|
||||||
char **azField; /* Data for each file field */
|
char **azField; /* Data for each file field */
|
||||||
char *zLine; /* A single line from the input file */
|
char *zLine; /* A single line from the input file */
|
||||||
|
int magic; /* Magic number for sanity checking */
|
||||||
int nLineAlloc; /* Number of spaces allocated for zLine */
|
int nLineAlloc; /* Number of spaces allocated for zLine */
|
||||||
int nMem; /* Number of memory locations currently allocated */
|
int nMem; /* Number of memory locations currently allocated */
|
||||||
Mem *aMem; /* The memory locations */
|
Mem *aMem; /* The memory locations */
|
||||||
@@ -265,10 +269,34 @@ struct Vdbe {
|
|||||||
int nSet; /* Number of sets allocated */
|
int nSet; /* Number of sets allocated */
|
||||||
Set *aSet; /* An array of sets */
|
Set *aSet; /* An array of sets */
|
||||||
int nCallback; /* Number of callbacks invoked so far */
|
int nCallback; /* Number of callbacks invoked so far */
|
||||||
|
Keylist *pList; /* A list of ROWIDs */
|
||||||
int keylistStackDepth; /* The size of the "keylist" stack */
|
int keylistStackDepth; /* The size of the "keylist" stack */
|
||||||
Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
|
Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
|
||||||
|
int pc; /* The program counter */
|
||||||
|
int rc; /* Value to return */
|
||||||
|
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
|
||||||
|
int errorAction; /* Recovery action to do in case of an error */
|
||||||
|
int undoTransOnError; /* If error, either ROLLBACK or COMMIT */
|
||||||
|
int inTempTrans; /* True if temp database is transactioned */
|
||||||
|
int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
|
||||||
|
int returnDepth; /* Next unused element in returnStack[] */
|
||||||
|
int nResColumn; /* Number of columns in one row of the result set */
|
||||||
|
char **azResColumn; /* Values for one row of result */
|
||||||
|
int (*xCallback)(void*,int,char**,char**); /* Callback for SELECT results */
|
||||||
|
void *pCbArg; /* First argument to xCallback() */
|
||||||
|
int popStack; /* Pop the stack this much on entry to VdbeExec() */
|
||||||
|
char *zErrMsg; /* Error message written here */
|
||||||
|
u8 explain; /* True if EXPLAIN present on SQL command */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following are allowed values for Vdbe.magic
|
||||||
|
*/
|
||||||
|
#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */
|
||||||
|
#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */
|
||||||
|
#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
|
||||||
|
#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** When debugging the code generator in a symbolic debugger, one can
|
** When debugging the code generator in a symbolic debugger, one can
|
||||||
** set the sqlite_vdbe_addop_trace to 1 and all opcodes will be printed
|
** set the sqlite_vdbe_addop_trace to 1 and all opcodes will be printed
|
||||||
@@ -288,6 +316,7 @@ Vdbe *sqliteVdbeCreate(sqlite *db){
|
|||||||
if( p==0 ) return 0;
|
if( p==0 ) return 0;
|
||||||
p->pBt = db->pBe;
|
p->pBt = db->pBe;
|
||||||
p->db = db;
|
p->db = db;
|
||||||
|
p->magic = VDBE_MAGIC_INIT;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,6 +348,7 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
|||||||
|
|
||||||
i = p->nOp;
|
i = p->nOp;
|
||||||
p->nOp++;
|
p->nOp++;
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( i>=p->nOpAlloc ){
|
if( i>=p->nOpAlloc ){
|
||||||
int oldSize = p->nOpAlloc;
|
int oldSize = p->nOpAlloc;
|
||||||
Op *aNew;
|
Op *aNew;
|
||||||
@@ -360,6 +390,7 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
|||||||
int sqliteVdbeMakeLabel(Vdbe *p){
|
int sqliteVdbeMakeLabel(Vdbe *p){
|
||||||
int i;
|
int i;
|
||||||
i = p->nLabel++;
|
i = p->nLabel++;
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( i>=p->nLabelAlloc ){
|
if( i>=p->nLabelAlloc ){
|
||||||
int *aNew;
|
int *aNew;
|
||||||
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
|
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
|
||||||
@@ -385,6 +416,7 @@ int sqliteVdbeMakeLabel(Vdbe *p){
|
|||||||
*/
|
*/
|
||||||
void sqliteVdbeResolveLabel(Vdbe *p, int x){
|
void sqliteVdbeResolveLabel(Vdbe *p, int x){
|
||||||
int j;
|
int j;
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( x<0 && (-x)<=p->nLabel && p->aOp ){
|
if( x<0 && (-x)<=p->nLabel && p->aOp ){
|
||||||
if( p->aLabel[-1-x]==p->nOp ) return;
|
if( p->aLabel[-1-x]==p->nOp ) return;
|
||||||
assert( p->aLabel[-1-x]<0 );
|
assert( p->aLabel[-1-x]<0 );
|
||||||
@@ -399,6 +431,7 @@ void sqliteVdbeResolveLabel(Vdbe *p, int x){
|
|||||||
** Return the address of the next instruction to be inserted.
|
** Return the address of the next instruction to be inserted.
|
||||||
*/
|
*/
|
||||||
int sqliteVdbeCurrentAddr(Vdbe *p){
|
int sqliteVdbeCurrentAddr(Vdbe *p){
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
return p->nOp;
|
return p->nOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,6 +441,7 @@ int sqliteVdbeCurrentAddr(Vdbe *p){
|
|||||||
*/
|
*/
|
||||||
int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){
|
int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){
|
||||||
int addr;
|
int addr;
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( p->nOp + nOp >= p->nOpAlloc ){
|
if( p->nOp + nOp >= p->nOpAlloc ){
|
||||||
int oldSize = p->nOpAlloc;
|
int oldSize = p->nOpAlloc;
|
||||||
Op *aNew;
|
Op *aNew;
|
||||||
@@ -444,6 +478,7 @@ int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){
|
|||||||
** few minor changes to the program.
|
** few minor changes to the program.
|
||||||
*/
|
*/
|
||||||
void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){
|
void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( p && addr>=0 && p->nOp>addr && p->aOp ){
|
if( p && addr>=0 && p->nOp>addr && p->aOp ){
|
||||||
p->aOp[addr].p1 = val;
|
p->aOp[addr].p1 = val;
|
||||||
}
|
}
|
||||||
@@ -455,6 +490,7 @@ void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){
|
|||||||
*/
|
*/
|
||||||
void sqliteVdbeChangeP2(Vdbe *p, int addr, int val){
|
void sqliteVdbeChangeP2(Vdbe *p, int addr, int val){
|
||||||
assert( val>=0 );
|
assert( val>=0 );
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( p && addr>=0 && p->nOp>addr && p->aOp ){
|
if( p && addr>=0 && p->nOp>addr && p->aOp ){
|
||||||
p->aOp[addr].p2 = val;
|
p->aOp[addr].p2 = val;
|
||||||
}
|
}
|
||||||
@@ -479,6 +515,7 @@ void sqliteVdbeChangeP2(Vdbe *p, int addr, int val){
|
|||||||
*/
|
*/
|
||||||
void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
||||||
Op *pOp;
|
Op *pOp;
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( p==0 || p->aOp==0 ) return;
|
if( p==0 || p->aOp==0 ) return;
|
||||||
if( addr<0 || addr>=p->nOp ){
|
if( addr<0 || addr>=p->nOp ){
|
||||||
addr = p->nOp - 1;
|
addr = p->nOp - 1;
|
||||||
@@ -512,6 +549,7 @@ void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
|||||||
*/
|
*/
|
||||||
void sqliteVdbeDequoteP3(Vdbe *p, int addr){
|
void sqliteVdbeDequoteP3(Vdbe *p, int addr){
|
||||||
Op *pOp;
|
Op *pOp;
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( p->aOp==0 || addr<0 || addr>=p->nOp ) return;
|
if( p->aOp==0 || addr<0 || addr>=p->nOp ) return;
|
||||||
pOp = &p->aOp[addr];
|
pOp = &p->aOp[addr];
|
||||||
if( pOp->p3==0 || pOp->p3[0]==0 ) return;
|
if( pOp->p3==0 || pOp->p3[0]==0 ) return;
|
||||||
@@ -532,6 +570,7 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
|
|||||||
char *z;
|
char *z;
|
||||||
int i, j;
|
int i, j;
|
||||||
Op *pOp;
|
Op *pOp;
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( p->aOp==0 || addr<0 || addr>=p->nOp ) return;
|
if( p->aOp==0 || addr<0 || addr>=p->nOp ) return;
|
||||||
pOp = &p->aOp[addr];
|
pOp = &p->aOp[addr];
|
||||||
if( pOp->p3type==P3_POINTER ){
|
if( pOp->p3type==P3_POINTER ){
|
||||||
@@ -563,6 +602,7 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
|
|||||||
*/
|
*/
|
||||||
int sqliteVdbeFindOp(Vdbe *p, int op, int p2){
|
int sqliteVdbeFindOp(Vdbe *p, int op, int p2){
|
||||||
int i;
|
int i;
|
||||||
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
for(i=0; i<p->nOp; i++){
|
for(i=0; i<p->nOp; i++){
|
||||||
if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return 1;
|
if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return 1;
|
||||||
}
|
}
|
||||||
@@ -688,6 +728,66 @@ int sqlite_aggregate_count(sqlite_func *p){
|
|||||||
return p->cnt;
|
return p->cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Advance the virtual machine to the next output row.
|
||||||
|
**
|
||||||
|
** The return vale will be either SQLITE_BUSY, SQLITE_DONE, or
|
||||||
|
** SQLITE_ROW.
|
||||||
|
**
|
||||||
|
** SQLITE_BUSY means that the virtual machine attempted to open
|
||||||
|
** a locked database and there is no busy callback registered.
|
||||||
|
** Call sqlite_step() again to retry the open. *pN is set to 0
|
||||||
|
** and *pazColName and *pazValue are both set to NULL.
|
||||||
|
**
|
||||||
|
** SQLITE_DONE means that the virtual machine has finished
|
||||||
|
** executing. sqlite_step() should not be called again on this
|
||||||
|
** virtual machine. *pN and *pazColName are set appropriately
|
||||||
|
** but *pazValue is set to NULL.
|
||||||
|
**
|
||||||
|
** SQLITE_ROW means that the virtual machine has generated another
|
||||||
|
** row of the result set. *pN is set to the number of columns in
|
||||||
|
** the row. *pazColName is set to the names of the columns followed
|
||||||
|
** by the column datatypes. *pazValue is set to the values of each
|
||||||
|
** column in the row. The value of the i-th column is (*pazValue)[i].
|
||||||
|
** The name of the i-th column is (*pazColName)[i] and the datatype
|
||||||
|
** of the i-th column is (*pazColName)[i+*pN].
|
||||||
|
**
|
||||||
|
** If a run-time error is encountered, SQLITE_DONE is returned. You
|
||||||
|
** can access the error code and error message using the sqlite_finalize()
|
||||||
|
** routine.
|
||||||
|
*/
|
||||||
|
int sqlite_step(
|
||||||
|
sqlite_vm *pVm, /* The virtual machine to execute */
|
||||||
|
int *pN, /* OUT: Number of columns in result */
|
||||||
|
const char ***pazValue, /* OUT: Column data */
|
||||||
|
const char ***pazColName /* OUT: Column names and datatypes */
|
||||||
|
){
|
||||||
|
Vdbe *p = (Vdbe*)pVm;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||||
|
return SQLITE_MISUSE;
|
||||||
|
}
|
||||||
|
if( p->explain ){
|
||||||
|
rc = sqliteVdbeList(p);
|
||||||
|
}else{
|
||||||
|
rc = sqliteVdbeExec(p);
|
||||||
|
}
|
||||||
|
if( rc!=SQLITE_DONE ){
|
||||||
|
*pazColName = (const char**)p->azColName;
|
||||||
|
*pN = p->nResColumn;
|
||||||
|
}else{
|
||||||
|
*pN = 0;
|
||||||
|
*pazColName = 0;
|
||||||
|
}
|
||||||
|
if( rc==SQLITE_ROW ){
|
||||||
|
*pazValue = (const char**)p->azResColumn;
|
||||||
|
}else{
|
||||||
|
*pazValue = 0;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Reset an Agg structure. Delete all its contents.
|
** Reset an Agg structure. Delete all its contents.
|
||||||
**
|
**
|
||||||
@@ -1079,6 +1179,9 @@ static void Cleanup(Vdbe *p){
|
|||||||
p->keylistStackDepth = 0;
|
p->keylistStackDepth = 0;
|
||||||
p->keylistStack = 0;
|
p->keylistStack = 0;
|
||||||
}
|
}
|
||||||
|
sqliteFree(p->zErrMsg);
|
||||||
|
p->zErrMsg = 0;
|
||||||
|
p->magic = VDBE_MAGIC_DEAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1111,61 +1214,61 @@ void sqliteVdbeDelete(Vdbe *p){
|
|||||||
** This feature is used to implement "EXPLAIN".
|
** This feature is used to implement "EXPLAIN".
|
||||||
*/
|
*/
|
||||||
int sqliteVdbeList(
|
int sqliteVdbeList(
|
||||||
Vdbe *p, /* The VDBE */
|
Vdbe *p /* The VDBE */
|
||||||
sqlite_callback xCallback, /* The callback */
|
|
||||||
void *pArg, /* 1st argument to callback */
|
|
||||||
char **pzErrMsg /* Error msg written here */
|
|
||||||
){
|
){
|
||||||
sqlite *db = p->db;
|
sqlite *db = p->db;
|
||||||
int i, rc;
|
int i;
|
||||||
char *azValue[6];
|
|
||||||
char zAddr[20];
|
|
||||||
char zP1[20];
|
|
||||||
char zP2[20];
|
|
||||||
char zP3[40];
|
|
||||||
static char *azColumnNames[] = {
|
static char *azColumnNames[] = {
|
||||||
"addr", "opcode", "p1", "p2", "p3", 0
|
"addr", "opcode", "p1", "p2", "p3",
|
||||||
|
"int", "text", "int", "int", "text",
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
if( xCallback==0 ) return 0;
|
assert( p->popStack==0 );
|
||||||
azValue[0] = zAddr;
|
assert( p->explain );
|
||||||
azValue[2] = zP1;
|
p->azColName = azColumnNames;
|
||||||
azValue[3] = zP2;
|
p->azResColumn = p->zStack;
|
||||||
azValue[5] = 0;
|
for(i=0; i<5; i++) p->zStack[i] = p->aStack[i].z;
|
||||||
rc = SQLITE_OK;
|
p->rc = SQLITE_OK;
|
||||||
for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
|
for(i=p->pc; p->rc==SQLITE_OK && i<p->nOp; i++){
|
||||||
if( db->flags & SQLITE_Interrupt ){
|
if( db->flags & SQLITE_Interrupt ){
|
||||||
db->flags &= ~SQLITE_Interrupt;
|
db->flags &= ~SQLITE_Interrupt;
|
||||||
if( db->magic!=SQLITE_MAGIC_BUSY ){
|
if( db->magic!=SQLITE_MAGIC_BUSY ){
|
||||||
rc = SQLITE_MISUSE;
|
p->rc = SQLITE_MISUSE;
|
||||||
}else{
|
}else{
|
||||||
rc = SQLITE_INTERRUPT;
|
p->rc = SQLITE_INTERRUPT;
|
||||||
}
|
}
|
||||||
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
|
sqliteSetString(&p->zErrMsg, sqlite_error_string(p->rc), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sprintf(zAddr,"%d",i);
|
sprintf(p->zStack[0],"%d",i);
|
||||||
sprintf(zP1,"%d", p->aOp[i].p1);
|
sprintf(p->zStack[2],"%d", p->aOp[i].p1);
|
||||||
sprintf(zP2,"%d", p->aOp[i].p2);
|
sprintf(p->zStack[3],"%d", p->aOp[i].p2);
|
||||||
if( p->aOp[i].p3type==P3_POINTER ){
|
if( p->aOp[i].p3type==P3_POINTER ){
|
||||||
sprintf(zP3, "ptr(%#x)", (int)p->aOp[i].p3);
|
sprintf(p->aStack[4].z, "ptr(%#x)", (int)p->aOp[i].p3);
|
||||||
azValue[4] = zP3;
|
p->zStack[4] = p->aStack[4].z;
|
||||||
}else{
|
}else{
|
||||||
azValue[4] = p->aOp[i].p3;
|
p->zStack[4] = p->aOp[i].p3;
|
||||||
|
}
|
||||||
|
p->zStack[1] = sqliteOpcodeNames[p->aOp[i].opcode];
|
||||||
|
if( p->xCallback==0 ){
|
||||||
|
p->pc = i+1;
|
||||||
|
p->azResColumn = p->zStack;
|
||||||
|
p->nResColumn = 5;
|
||||||
|
return SQLITE_CALLBACK;
|
||||||
}
|
}
|
||||||
azValue[1] = sqliteOpcodeNames[p->aOp[i].opcode];
|
|
||||||
if( sqliteSafetyOff(db) ){
|
if( sqliteSafetyOff(db) ){
|
||||||
rc = SQLITE_MISUSE;
|
p->rc = SQLITE_MISUSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if( xCallback(pArg, 5, azValue, azColumnNames) ){
|
if( p->xCallback(p->pCbArg, 5, p->zStack, p->azColName) ){
|
||||||
rc = SQLITE_ABORT;
|
p->rc = SQLITE_ABORT;
|
||||||
}
|
}
|
||||||
if( sqliteSafetyOn(db) ){
|
if( sqliteSafetyOn(db) ){
|
||||||
rc = SQLITE_MISUSE;
|
p->rc = SQLITE_MISUSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return p->rc==SQLITE_OK ? SQLITE_OK : SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1343,57 +1446,34 @@ __inline__ unsigned long long int hwtime(void){
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Execute the program in the VDBE.
|
** Prepare a virtual machine for execution. This involves things such
|
||||||
|
** as allocating stack space and initializing the program counter.
|
||||||
|
** After the VDBE has be prepped, it can be executed by one or more
|
||||||
|
** calls to sqliteVdbeExec().
|
||||||
**
|
**
|
||||||
** If an error occurs, an error message is written to memory obtained
|
** The behavior of sqliteVdbeExec() is influenced by the parameters to
|
||||||
** from sqliteMalloc() and *pzErrMsg is made to point to that memory.
|
** this routine. If xCallback is NULL, then sqliteVdbeExec() will return
|
||||||
** The return parameter is the number of errors.
|
** with SQLITE_CALLBACK whenever there is a row of the result set ready
|
||||||
**
|
** to be delivered. p->azResColumn will point to the row and
|
||||||
** If the callback ever returns non-zero, then the program exits
|
** p->nResColumn gives the number of columns in the row. If xCallback
|
||||||
** immediately. There will be no error message but the function
|
** is not NULL, then the xCallback() routine is invoked to process each
|
||||||
** does return SQLITE_ABORT.
|
** row in the result set.
|
||||||
**
|
|
||||||
** A memory allocation error causes this routine to return SQLITE_NOMEM
|
|
||||||
** and abandon furture processing.
|
|
||||||
**
|
|
||||||
** Other fatal errors return SQLITE_ERROR.
|
|
||||||
**
|
|
||||||
** If a database file could not be opened because it is locked by
|
|
||||||
** another database instance, then the xBusy() callback is invoked
|
|
||||||
** with pBusyArg as its first argument, the name of the table as the
|
|
||||||
** second argument, and the number of times the open has been attempted
|
|
||||||
** as the third argument. The xBusy() callback will typically wait
|
|
||||||
** for the database file to be openable, then return. If xBusy()
|
|
||||||
** returns non-zero, another attempt is made to open the file. If
|
|
||||||
** xBusy() returns zero, or if xBusy is NULL, then execution halts
|
|
||||||
** and this routine returns SQLITE_BUSY.
|
|
||||||
*/
|
*/
|
||||||
int sqliteVdbeExec(
|
void sqliteVdbeMakeReady(
|
||||||
Vdbe *p, /* The VDBE */
|
Vdbe *p, /* The VDBE */
|
||||||
sqlite_callback xCallback, /* The callback */
|
sqlite_callback xCallback, /* Result callback */
|
||||||
void *pArg, /* 1st argument to callback */
|
void *pCallbackArg, /* 1st argument to xCallback() */
|
||||||
char **pzErrMsg, /* Error msg written here */
|
int isExplain /* True if the EXPLAIN keywords is present */
|
||||||
void *pBusyArg, /* 1st argument to the busy callback */
|
|
||||||
int (*xBusy)(void*,const char*,int) /* Called when a file is busy */
|
|
||||||
){
|
){
|
||||||
int pc; /* The program counter */
|
int n;
|
||||||
Op *pOp; /* Current operation */
|
|
||||||
int rc; /* Value to return */
|
assert( p!=0 );
|
||||||
Btree *pBt = p->pBt; /* The backend driver */
|
assert( p->aStack==0 );
|
||||||
sqlite *db = p->db; /* The database */
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
char **zStack; /* Text stack */
|
|
||||||
Stack *aStack; /* Additional stack information */
|
/* Add a HALT instruction to the very end of the program.
|
||||||
unsigned uniqueCnt = 0; /* Used by OP_MakeRecord when P2!=0 */
|
*/
|
||||||
int errorAction = OE_Abort; /* Recovery action to do in case of an error */
|
sqliteVdbeAddOp(p, OP_Halt, 0, 0);
|
||||||
int undoTransOnError = 0; /* If error, either ROLLBACK or COMMIT */
|
|
||||||
int inTempTrans = 0; /* True if temp database is transactioned */
|
|
||||||
char zBuf[100]; /* Space to sprintf() an integer */
|
|
||||||
int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
|
|
||||||
int returnDepth = 0; /* Next unused element in returnStack[] */
|
|
||||||
#ifdef VDBE_PROFILE
|
|
||||||
unsigned long long start;
|
|
||||||
int origPc;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* No instruction ever pushes more than a single element onto the
|
/* No instruction ever pushes more than a single element onto the
|
||||||
** stack. And the stack never grows on successive executions of the
|
** stack. And the stack never grows on successive executions of the
|
||||||
@@ -1402,35 +1482,95 @@ int sqliteVdbeExec(
|
|||||||
**
|
**
|
||||||
** Allocation all the stack space we will ever need.
|
** Allocation all the stack space we will ever need.
|
||||||
*/
|
*/
|
||||||
sqliteVdbeAddOp(p, OP_Halt, 0, 0);
|
n = isExplain ? 10 : p->nOp;
|
||||||
aStack = sqliteMalloc( p->nOp*(sizeof(aStack[0]) + 2*sizeof(char*)) );
|
p->aStack = sqliteMalloc( n*(sizeof(p->aStack[0]) + 2*sizeof(char*)) );
|
||||||
p->aStack = aStack;
|
p->zStack = (char**)&p->aStack[n];
|
||||||
zStack = p->zStack = (char**)&aStack[p->nOp];
|
p->azColName = (char**)&p->zStack[n];
|
||||||
p->azColName = (char**)&zStack[p->nOp];
|
|
||||||
p->tos = -1;
|
|
||||||
#ifdef VDBE_PROFILE
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for(i=0; i<p->nOp; i++){
|
|
||||||
p->aOp[i].cnt = 0;
|
|
||||||
p->aOp[i].cycles = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Initialize the aggregrate hash table.
|
|
||||||
*/
|
|
||||||
sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0);
|
sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0);
|
||||||
p->agg.pSearch = 0;
|
p->agg.pSearch = 0;
|
||||||
|
|
||||||
rc = SQLITE_OK;
|
|
||||||
#ifdef MEMORY_DEBUG
|
#ifdef MEMORY_DEBUG
|
||||||
if( access("vdbe_trace",0)==0 ){
|
if( access("vdbe_trace",0)==0 ){
|
||||||
p->trace = stdout;
|
p->trace = stdout;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
p->tos = -1;
|
||||||
|
p->pc = 0;
|
||||||
|
p->rc = SQLITE_OK;
|
||||||
|
p->uniqueCnt = 0;
|
||||||
|
p->returnDepth = 0;
|
||||||
|
p->errorAction = OE_Abort;
|
||||||
|
p->undoTransOnError = 0;
|
||||||
|
p->xCallback = xCallback;
|
||||||
|
p->pCbArg = pCallbackArg;
|
||||||
|
p->popStack = 0;
|
||||||
|
p->explain = isExplain;
|
||||||
|
p->magic = VDBE_MAGIC_RUN;
|
||||||
|
#ifdef VDBE_PROFILE
|
||||||
|
for(i=0; i<p->nOp; i++){
|
||||||
|
p->aOp[i].cnt = 0;
|
||||||
|
p->aOp[i].cycles = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Execute as much of a VDBE program as we can then return.
|
||||||
|
**
|
||||||
|
** sqliteVdbeMakeReady() must be called before this routine in order to
|
||||||
|
** close the program with a final OP_Halt and to set up the callbacks
|
||||||
|
** and the error message pointer.
|
||||||
|
**
|
||||||
|
** Whenever a row or result data is available, this routine will either
|
||||||
|
** invoke the result callback (if there is one) or return with
|
||||||
|
** SQLITE_CALLBACK.
|
||||||
|
**
|
||||||
|
** If an attempt is made to open a locked database, then this routine
|
||||||
|
** will either invoke the busy callback (if there is one) or it will
|
||||||
|
** return SQLITE_BUSY.
|
||||||
|
**
|
||||||
|
** If an error occurs, an error message is written to memory obtained
|
||||||
|
** from sqliteMalloc() and p->zErrMsg is made to point to that memory.
|
||||||
|
** The error code is stored in p->rc and this routine returns SQLITE_ERROR.
|
||||||
|
**
|
||||||
|
** If the callback ever returns non-zero, then the program exits
|
||||||
|
** immediately. There will be no error message but the p->rc field is
|
||||||
|
** set to SQLITE_ABORT and this routine will return SQLITE_ERROR.
|
||||||
|
**
|
||||||
|
** A memory allocation error causes p->rc to be set SQLITE_NOMEM and this
|
||||||
|
** routien to return SQLITE_ERROR.
|
||||||
|
**
|
||||||
|
** Other fatal errors return SQLITE_ERROR.
|
||||||
|
**
|
||||||
|
** After this routine has finished, sqliteVdbeFinalize() should be
|
||||||
|
** used to clean up the mess that was left behind.
|
||||||
|
*/
|
||||||
|
int sqliteVdbeExec(
|
||||||
|
Vdbe *p /* The VDBE */
|
||||||
|
){
|
||||||
|
int pc; /* The program counter */
|
||||||
|
Op *pOp; /* Current operation */
|
||||||
|
int rc = SQLITE_OK; /* Value to return */
|
||||||
|
Btree *pBt = p->pBt; /* The backend driver */
|
||||||
|
sqlite *db = p->db; /* The database */
|
||||||
|
char **zStack = p->zStack; /* Text stack */
|
||||||
|
Stack *aStack = p->aStack; /* Additional stack information */
|
||||||
|
char zBuf[100]; /* Space to sprintf() an integer */
|
||||||
|
#ifdef VDBE_PROFILE
|
||||||
|
unsigned long long start; /* CPU clock count at start of opcode */
|
||||||
|
int origPc; /* Program counter at start of opcode */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
|
||||||
|
assert( db->magic==SQLITE_MAGIC_BUSY );
|
||||||
|
assert( p->rc==SQLITE_OK );
|
||||||
|
assert( p->explain==0 );
|
||||||
if( sqlite_malloc_failed ) goto no_mem;
|
if( sqlite_malloc_failed ) goto no_mem;
|
||||||
for(pc=0; rc==SQLITE_OK; pc++){
|
if( p->popStack ){
|
||||||
|
PopStack(p, p->popStack);
|
||||||
|
p->popStack = 0;
|
||||||
|
}
|
||||||
|
for(pc=p->pc; rc==SQLITE_OK; pc++){
|
||||||
assert( pc>=0 && pc<p->nOp );
|
assert( pc>=0 && pc<p->nOp );
|
||||||
#ifdef VDBE_PROFILE
|
#ifdef VDBE_PROFILE
|
||||||
origPc = pc;
|
origPc = pc;
|
||||||
@@ -1500,12 +1640,12 @@ case OP_Goto: {
|
|||||||
** with a fatal error.
|
** with a fatal error.
|
||||||
*/
|
*/
|
||||||
case OP_Gosub: {
|
case OP_Gosub: {
|
||||||
if( returnDepth>=sizeof(returnStack)/sizeof(returnStack[0]) ){
|
if( p->returnDepth>=sizeof(p->returnStack)/sizeof(p->returnStack[0]) ){
|
||||||
sqliteSetString(pzErrMsg, "return address stack overflow", 0);
|
sqliteSetString(&p->zErrMsg, "return address stack overflow", 0);
|
||||||
rc = SQLITE_INTERNAL;
|
p->rc = SQLITE_INTERNAL;
|
||||||
goto cleanup;
|
return SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
returnStack[returnDepth++] = pc+1;
|
p->returnStack[p->returnDepth++] = pc+1;
|
||||||
pc = pOp->p2 - 1;
|
pc = pOp->p2 - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1517,13 +1657,13 @@ case OP_Gosub: {
|
|||||||
** processing aborts with a fatal error.
|
** processing aborts with a fatal error.
|
||||||
*/
|
*/
|
||||||
case OP_Return: {
|
case OP_Return: {
|
||||||
if( returnDepth<=0 ){
|
if( p->returnDepth<=0 ){
|
||||||
sqliteSetString(pzErrMsg, "return address stack underflow", 0);
|
sqliteSetString(&p->zErrMsg, "return address stack underflow", 0);
|
||||||
rc = SQLITE_INTERNAL;
|
p->rc = SQLITE_INTERNAL;
|
||||||
goto cleanup;
|
return SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
returnDepth--;
|
p->returnDepth--;
|
||||||
pc = returnStack[returnDepth] - 1;
|
pc = p->returnStack[p->returnDepth] - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1546,16 +1686,16 @@ case OP_Return: {
|
|||||||
*/
|
*/
|
||||||
case OP_Halt: {
|
case OP_Halt: {
|
||||||
if( pOp->p1!=SQLITE_OK ){
|
if( pOp->p1!=SQLITE_OK ){
|
||||||
rc = pOp->p1;
|
p->rc = pOp->p1;
|
||||||
errorAction = pOp->p2;
|
p->errorAction = pOp->p2;
|
||||||
if( pOp->p3 ){
|
if( pOp->p3 ){
|
||||||
sqliteSetString(pzErrMsg, pOp->p3, 0);
|
sqliteSetString(&p->zErrMsg, pOp->p3, 0);
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
goto abort_due_to_error;
|
|
||||||
}else{
|
}else{
|
||||||
goto cleanup;
|
p->rc = SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
p->magic = VDBE_MAGIC_HALT;
|
||||||
|
return SQLITE_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: Integer P1 * P3
|
/* Opcode: Integer P1 * P3
|
||||||
@@ -1742,14 +1882,19 @@ case OP_Callback: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
zStack[p->tos+1] = 0;
|
zStack[p->tos+1] = 0;
|
||||||
if( xCallback!=0 ){
|
if( p->xCallback==0 ){
|
||||||
|
p->azResColumn = &zStack[i];
|
||||||
|
p->nResColumn = pOp->p1;
|
||||||
|
p->popStack = pOp->p1;
|
||||||
|
p->pc = pc + 1;
|
||||||
|
return SQLITE_CALLBACK;
|
||||||
|
}
|
||||||
if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
|
if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
|
||||||
if( xCallback(pArg, pOp->p1, &zStack[i], p->azColName)!=0 ){
|
if( p->xCallback(p->pCbArg, pOp->p1, &zStack[i], p->azColName)!=0 ){
|
||||||
rc = SQLITE_ABORT;
|
rc = SQLITE_ABORT;
|
||||||
}
|
}
|
||||||
if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
|
if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
|
||||||
p->nCallback++;
|
p->nCallback++;
|
||||||
}
|
|
||||||
PopStack(p, pOp->p1);
|
PopStack(p, pOp->p1);
|
||||||
if( sqlite_malloc_failed ) goto no_mem;
|
if( sqlite_malloc_failed ) goto no_mem;
|
||||||
break;
|
break;
|
||||||
@@ -1772,15 +1917,15 @@ case OP_Callback: {
|
|||||||
** in cases where the result set is empty.
|
** in cases where the result set is empty.
|
||||||
*/
|
*/
|
||||||
case OP_NullCallback: {
|
case OP_NullCallback: {
|
||||||
if( xCallback!=0 && p->nCallback==0 ){
|
if( p->nCallback==0 && p->xCallback!=0 ){
|
||||||
if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
|
if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
|
||||||
if( xCallback(pArg, pOp->p1, 0, p->azColName)!=0 ){
|
if( p->xCallback(p->pCbArg, pOp->p1, 0, p->azColName)!=0 ){
|
||||||
rc = SQLITE_ABORT;
|
rc = SQLITE_ABORT;
|
||||||
}
|
}
|
||||||
if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
|
if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
|
||||||
p->nCallback++;
|
p->nCallback++;
|
||||||
}
|
|
||||||
if( sqlite_malloc_failed ) goto no_mem;
|
if( sqlite_malloc_failed ) goto no_mem;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2005,7 +2150,7 @@ case OP_Function: {
|
|||||||
zStack[p->tos] = 0;
|
zStack[p->tos] = 0;
|
||||||
}
|
}
|
||||||
if( ctx.isError ){
|
if( ctx.isError ){
|
||||||
sqliteSetString(pzErrMsg,
|
sqliteSetString(&p->zErrMsg,
|
||||||
zStack[p->tos] ? zStack[p->tos] : "user function error", 0);
|
zStack[p->tos] ? zStack[p->tos] : "user function error", 0);
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
@@ -2725,7 +2870,7 @@ case OP_MakeRecord: {
|
|||||||
nByte += aStack[i].n;
|
nByte += aStack[i].n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( addUnique ) nByte += sizeof(uniqueCnt);
|
if( addUnique ) nByte += sizeof(p->uniqueCnt);
|
||||||
if( nByte + nField + 1 < 256 ){
|
if( nByte + nField + 1 < 256 ){
|
||||||
idxWidth = 1;
|
idxWidth = 1;
|
||||||
}else if( nByte + 2*nField + 2 < 65536 ){
|
}else if( nByte + 2*nField + 2 < 65536 ){
|
||||||
@@ -2745,7 +2890,7 @@ case OP_MakeRecord: {
|
|||||||
if( zNewRecord==0 ) goto no_mem;
|
if( zNewRecord==0 ) goto no_mem;
|
||||||
}
|
}
|
||||||
j = 0;
|
j = 0;
|
||||||
addr = idxWidth*(nField+1) + addUnique*sizeof(uniqueCnt);
|
addr = idxWidth*(nField+1) + addUnique*sizeof(p->uniqueCnt);
|
||||||
for(i=p->tos-nField+1; i<=p->tos; i++){
|
for(i=p->tos-nField+1; i<=p->tos; i++){
|
||||||
zNewRecord[j++] = addr & 0xff;
|
zNewRecord[j++] = addr & 0xff;
|
||||||
if( idxWidth>1 ){
|
if( idxWidth>1 ){
|
||||||
@@ -2766,9 +2911,9 @@ case OP_MakeRecord: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( addUnique ){
|
if( addUnique ){
|
||||||
memcpy(&zNewRecord[j], &uniqueCnt, sizeof(uniqueCnt));
|
memcpy(&zNewRecord[j], &p->uniqueCnt, sizeof(p->uniqueCnt));
|
||||||
uniqueCnt++;
|
p->uniqueCnt++;
|
||||||
j += sizeof(uniqueCnt);
|
j += sizeof(p->uniqueCnt);
|
||||||
}
|
}
|
||||||
for(i=p->tos-nField+1; i<=p->tos; i++){
|
for(i=p->tos-nField+1; i<=p->tos; i++){
|
||||||
if( (aStack[i].flags & STK_Null)==0 ){
|
if( (aStack[i].flags & STK_Null)==0 ){
|
||||||
@@ -3006,20 +3151,25 @@ case OP_Checkpoint: {
|
|||||||
** can be made to the database.
|
** can be made to the database.
|
||||||
*/
|
*/
|
||||||
case OP_Transaction: {
|
case OP_Transaction: {
|
||||||
int busy = 0;
|
int busy = 1;
|
||||||
if( db->pBeTemp && !inTempTrans ){
|
if( db->pBeTemp && !p->inTempTrans ){
|
||||||
rc = sqliteBtreeBeginTrans(db->pBeTemp);
|
rc = sqliteBtreeBeginTrans(db->pBeTemp);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
inTempTrans = 1;
|
p->inTempTrans = 1;
|
||||||
}
|
}
|
||||||
if( pOp->p1==0 ) do{
|
while( pOp->p1==0 && busy ){
|
||||||
rc = sqliteBtreeBeginTrans(pBt);
|
rc = sqliteBtreeBeginTrans(pBt);
|
||||||
switch( rc ){
|
switch( rc ){
|
||||||
case SQLITE_BUSY: {
|
case SQLITE_BUSY: {
|
||||||
if( xBusy==0 || (*xBusy)(pBusyArg, "", ++busy)==0 ){
|
if( db->xBusyCallback==0 ){
|
||||||
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
|
p->pc = pc;
|
||||||
|
p->undoTransOnError = 1;
|
||||||
|
p->rc = SQLITE_BUSY;
|
||||||
|
return SQLITE_BUSY;
|
||||||
|
}else if( (*db->xBusyCallback)(db->pBusyArg, "", busy++)==0 ){
|
||||||
|
sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), 0);
|
||||||
busy = 0;
|
busy = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3029,7 +3179,7 @@ case OP_Transaction: {
|
|||||||
/* Fall thru into the next case */
|
/* Fall thru into the next case */
|
||||||
}
|
}
|
||||||
case SQLITE_OK: {
|
case SQLITE_OK: {
|
||||||
inTempTrans = 0;
|
p->inTempTrans = 0;
|
||||||
busy = 0;
|
busy = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3037,8 +3187,8 @@ case OP_Transaction: {
|
|||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}while( busy );
|
}
|
||||||
undoTransOnError = 1;
|
p->undoTransOnError = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3052,7 +3202,7 @@ case OP_Transaction: {
|
|||||||
*/
|
*/
|
||||||
case OP_Commit: {
|
case OP_Commit: {
|
||||||
if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
|
if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
|
||||||
rc = inTempTrans ? SQLITE_OK : sqliteBtreeCommit(pBt);
|
rc = p->inTempTrans ? SQLITE_OK : sqliteBtreeCommit(pBt);
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
sqliteCommitInternalChanges(db);
|
sqliteCommitInternalChanges(db);
|
||||||
@@ -3061,7 +3211,7 @@ case OP_Commit: {
|
|||||||
sqliteBtreeRollback(pBt);
|
sqliteBtreeRollback(pBt);
|
||||||
sqliteRollbackInternalChanges(db);
|
sqliteRollbackInternalChanges(db);
|
||||||
}
|
}
|
||||||
inTempTrans = 0;
|
p->inTempTrans = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3162,7 +3312,7 @@ case OP_VerifyCookie: {
|
|||||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||||
if( rc==SQLITE_OK && aMeta[1+pOp->p2]!=pOp->p1 ){
|
if( rc==SQLITE_OK && aMeta[1+pOp->p2]!=pOp->p1 ){
|
||||||
sqliteSetString(pzErrMsg, "database schema has changed", 0);
|
sqliteSetString(&p->zErrMsg, "database schema has changed", 0);
|
||||||
rc = SQLITE_SCHEMA;
|
rc = SQLITE_SCHEMA;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3241,9 +3391,9 @@ case OP_Open: {
|
|||||||
p2 = p->aStack[tos].i;
|
p2 = p->aStack[tos].i;
|
||||||
POPSTACK;
|
POPSTACK;
|
||||||
if( p2<2 ){
|
if( p2<2 ){
|
||||||
sqliteSetString(pzErrMsg, "root page number less than 2", 0);
|
sqliteSetString(&p->zErrMsg, "root page number less than 2", 0);
|
||||||
rc = SQLITE_INTERNAL;
|
rc = SQLITE_INTERNAL;
|
||||||
goto cleanup;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VERIFY( if( i<0 ) goto bad_instruction; )
|
VERIFY( if( i<0 ) goto bad_instruction; )
|
||||||
@@ -3256,8 +3406,12 @@ case OP_Open: {
|
|||||||
rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
|
rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
|
||||||
switch( rc ){
|
switch( rc ){
|
||||||
case SQLITE_BUSY: {
|
case SQLITE_BUSY: {
|
||||||
if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
|
if( db->xBusyCallback==0 ){
|
||||||
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
|
p->pc = pc;
|
||||||
|
p->rc = SQLITE_BUSY;
|
||||||
|
return SQLITE_BUSY;
|
||||||
|
}else if( (*db->xBusyCallback)(db->pBusyArg, pOp->p3, ++busy)==0 ){
|
||||||
|
sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), 0);
|
||||||
busy = 0;
|
busy = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3271,6 +3425,9 @@ case OP_Open: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}while( busy );
|
}while( busy );
|
||||||
|
if( p2<=0 ){
|
||||||
|
POPSTACK;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4124,7 +4281,7 @@ case OP_IdxPut: {
|
|||||||
){
|
){
|
||||||
rc = SQLITE_CONSTRAINT;
|
rc = SQLITE_CONSTRAINT;
|
||||||
if( pOp->p3 && pOp->p3[0] ){
|
if( pOp->p3 && pOp->p3[0] ){
|
||||||
sqliteSetString(pzErrMsg, "duplicate index entry: ", pOp->p3,0);
|
sqliteSetString(&p->zErrMsg, "duplicate index entry: ", pOp->p3,0);
|
||||||
}
|
}
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
@@ -4681,9 +4838,15 @@ case OP_SortNext: {
|
|||||||
case OP_SortCallback: {
|
case OP_SortCallback: {
|
||||||
int i = p->tos;
|
int i = p->tos;
|
||||||
VERIFY( if( i<0 ) goto not_enough_stack; )
|
VERIFY( if( i<0 ) goto not_enough_stack; )
|
||||||
if( xCallback!=0 ){
|
if( p->xCallback==0 ){
|
||||||
|
p->pc = pc+1;
|
||||||
|
p->azResColumn = (char**)zStack[i];
|
||||||
|
p->nResColumn = pOp->p1;
|
||||||
|
p->popStack = 1;
|
||||||
|
return SQLITE_CALLBACK;
|
||||||
|
}else{
|
||||||
if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
|
if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
|
||||||
if( xCallback(pArg, pOp->p1, (char**)zStack[i], p->azColName)!=0 ){
|
if( p->xCallback(p->pCbArg, pOp->p1, (char**)zStack[i], p->azColName)!=0 ){
|
||||||
rc = SQLITE_ABORT;
|
rc = SQLITE_ABORT;
|
||||||
}
|
}
|
||||||
if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
|
if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
|
||||||
@@ -4720,9 +4883,8 @@ case OP_FileOpen: {
|
|||||||
p->pFile = fopen(pOp->p3, "r");
|
p->pFile = fopen(pOp->p3, "r");
|
||||||
}
|
}
|
||||||
if( p->pFile==0 ){
|
if( p->pFile==0 ){
|
||||||
sqliteSetString(pzErrMsg,"unable to open file: ", pOp->p3, 0);
|
sqliteSetString(&p->zErrMsg,"unable to open file: ", pOp->p3, 0);
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -5309,7 +5471,7 @@ case OP_SetNext: {
|
|||||||
*/
|
*/
|
||||||
default: {
|
default: {
|
||||||
sprintf(zBuf,"%d",pOp->opcode);
|
sprintf(zBuf,"%d",pOp->opcode);
|
||||||
sqliteSetString(pzErrMsg, "unknown opcode ", zBuf, 0);
|
sqliteSetString(&p->zErrMsg, "unknown opcode ", zBuf, 0);
|
||||||
rc = SQLITE_INTERNAL;
|
rc = SQLITE_INTERNAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -5341,7 +5503,7 @@ default: {
|
|||||||
*/
|
*/
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if( pc<-1 || pc>=p->nOp ){
|
if( pc<-1 || pc>=p->nOp ){
|
||||||
sqliteSetString(pzErrMsg, "jump destination out of range", 0);
|
sqliteSetString(&p->zErrMsg, "jump destination out of range", 0);
|
||||||
rc = SQLITE_INTERNAL;
|
rc = SQLITE_INTERNAL;
|
||||||
}
|
}
|
||||||
if( p->trace && p->tos>=0 ){
|
if( p->trace && p->tos>=0 ){
|
||||||
@@ -5394,14 +5556,101 @@ default: {
|
|||||||
fprintf(p->trace,"\n");
|
fprintf(p->trace,"\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
} /* The end of the for(;;) loop the loops through opcodes */
|
||||||
|
|
||||||
cleanup:
|
/* If we reach this point, it means that execution is finished.
|
||||||
|
*/
|
||||||
|
vdbe_halt:
|
||||||
|
if( rc ){
|
||||||
|
p->rc = rc;
|
||||||
|
rc = SQLITE_ERROR;
|
||||||
|
}else{
|
||||||
|
rc = SQLITE_DONE;
|
||||||
|
}
|
||||||
|
p->magic = VDBE_MAGIC_HALT;
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Jump to here if a malloc() fails. It's hard to get a malloc()
|
||||||
|
** to fail on a modern VM computer, so this code is untested.
|
||||||
|
*/
|
||||||
|
no_mem:
|
||||||
|
sqliteSetString(&p->zErrMsg, "out of memory", 0);
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
|
goto vdbe_halt;
|
||||||
|
|
||||||
|
/* Jump to here for an SQLITE_MISUSE error.
|
||||||
|
*/
|
||||||
|
abort_due_to_misuse:
|
||||||
|
rc = SQLITE_MISUSE;
|
||||||
|
/* Fall thru into abort_due_to_error */
|
||||||
|
|
||||||
|
/* Jump to here for any other kind of fatal error. The "rc" variable
|
||||||
|
** should hold the error number.
|
||||||
|
*/
|
||||||
|
abort_due_to_error:
|
||||||
|
sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), 0);
|
||||||
|
goto vdbe_halt;
|
||||||
|
|
||||||
|
/* Jump to here if the sqlite_interrupt() API sets the interrupt
|
||||||
|
** flag.
|
||||||
|
*/
|
||||||
|
abort_due_to_interrupt:
|
||||||
|
assert( db->flags & SQLITE_Interrupt );
|
||||||
|
db->flags &= ~SQLITE_Interrupt;
|
||||||
|
if( db->magic!=SQLITE_MAGIC_BUSY ){
|
||||||
|
rc = SQLITE_MISUSE;
|
||||||
|
}else{
|
||||||
|
rc = SQLITE_INTERRUPT;
|
||||||
|
}
|
||||||
|
sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), 0);
|
||||||
|
goto vdbe_halt;
|
||||||
|
|
||||||
|
/* Jump to here if a operator is encountered that requires more stack
|
||||||
|
** operands than are currently available on the stack.
|
||||||
|
*/
|
||||||
|
not_enough_stack:
|
||||||
|
sprintf(zBuf,"%d",pc);
|
||||||
|
sqliteSetString(&p->zErrMsg, "too few operands on stack at ", zBuf, 0);
|
||||||
|
rc = SQLITE_INTERNAL;
|
||||||
|
goto vdbe_halt;
|
||||||
|
|
||||||
|
/* Jump here if an illegal or illformed instruction is executed.
|
||||||
|
*/
|
||||||
|
VERIFY(
|
||||||
|
bad_instruction:
|
||||||
|
sprintf(zBuf,"%d",pc);
|
||||||
|
sqliteSetString(&p->zErrMsg, "illegal operation at ", zBuf, 0);
|
||||||
|
rc = SQLITE_INTERNAL;
|
||||||
|
goto vdbe_halt;
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Clean up the VDBE after execution. Return an integer which is the
|
||||||
|
** result code.
|
||||||
|
*/
|
||||||
|
int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
|
||||||
|
sqlite *db = p->db;
|
||||||
|
Btree *pBt = p->pBt;
|
||||||
|
|
||||||
|
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
|
||||||
|
sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0);
|
||||||
|
return SQLITE_MISUSE;
|
||||||
|
}
|
||||||
|
if( p->zErrMsg ){
|
||||||
|
if( pzErrMsg && *pzErrMsg==0 ){
|
||||||
|
*pzErrMsg = p->zErrMsg;
|
||||||
|
}else{
|
||||||
|
sqliteFree(p->zErrMsg);
|
||||||
|
}
|
||||||
|
p->zErrMsg = 0;
|
||||||
|
}
|
||||||
Cleanup(p);
|
Cleanup(p);
|
||||||
if( rc!=SQLITE_OK ){
|
if( p->rc!=SQLITE_OK ){
|
||||||
switch( errorAction ){
|
switch( p->errorAction ){
|
||||||
case OE_Abort: {
|
case OE_Abort: {
|
||||||
if( !undoTransOnError ){
|
if( !p->undoTransOnError ){
|
||||||
sqliteBtreeRollbackCkpt(pBt);
|
sqliteBtreeRollbackCkpt(pBt);
|
||||||
if( db->pBeTemp ) sqliteBtreeRollbackCkpt(db->pBeTemp);
|
if( db->pBeTemp ) sqliteBtreeRollbackCkpt(db->pBeTemp);
|
||||||
break;
|
break;
|
||||||
@@ -5416,7 +5665,7 @@ cleanup:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
if( undoTransOnError ){
|
if( p->undoTransOnError ){
|
||||||
sqliteBtreeCommit(pBt);
|
sqliteBtreeCommit(pBt);
|
||||||
if( db->pBeTemp ) sqliteBtreeCommit(db->pBeTemp);
|
if( db->pBeTemp ) sqliteBtreeCommit(db->pBeTemp);
|
||||||
db->flags &= ~SQLITE_InTrans;
|
db->flags &= ~SQLITE_InTrans;
|
||||||
@@ -5429,7 +5678,7 @@ cleanup:
|
|||||||
}
|
}
|
||||||
sqliteBtreeCommitCkpt(pBt);
|
sqliteBtreeCommitCkpt(pBt);
|
||||||
if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
|
if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
|
||||||
assert( p->tos<pc || sqlite_malloc_failed==1 );
|
assert( p->tos<p->pc || sqlite_malloc_failed==1 );
|
||||||
#ifdef VDBE_PROFILE
|
#ifdef VDBE_PROFILE
|
||||||
{
|
{
|
||||||
FILE *out = fopen("vdbe_profile.out", "a");
|
FILE *out = fopen("vdbe_profile.out", "a");
|
||||||
@@ -5452,58 +5701,5 @@ cleanup:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return rc;
|
return p->rc;
|
||||||
|
|
||||||
/* Jump to here if a malloc() fails. It's hard to get a malloc()
|
|
||||||
** to fail on a modern VM computer, so this code is untested.
|
|
||||||
*/
|
|
||||||
no_mem:
|
|
||||||
sqliteSetString(pzErrMsg, "out of memory", 0);
|
|
||||||
rc = SQLITE_NOMEM;
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* Jump to here for an SQLITE_MISUSE error.
|
|
||||||
*/
|
|
||||||
abort_due_to_misuse:
|
|
||||||
rc = SQLITE_MISUSE;
|
|
||||||
/* Fall thru into abort_due_to_error */
|
|
||||||
|
|
||||||
/* Jump to here for any other kind of fatal error. The "rc" variable
|
|
||||||
** should hold the error number.
|
|
||||||
*/
|
|
||||||
abort_due_to_error:
|
|
||||||
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* Jump to here if the sqlite_interrupt() API sets the interrupt
|
|
||||||
** flag.
|
|
||||||
*/
|
|
||||||
abort_due_to_interrupt:
|
|
||||||
assert( db->flags & SQLITE_Interrupt );
|
|
||||||
db->flags &= ~SQLITE_Interrupt;
|
|
||||||
if( db->magic!=SQLITE_MAGIC_BUSY ){
|
|
||||||
rc = SQLITE_MISUSE;
|
|
||||||
}else{
|
|
||||||
rc = SQLITE_INTERRUPT;
|
|
||||||
}
|
|
||||||
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* Jump to here if a operator is encountered that requires more stack
|
|
||||||
** operands than are currently available on the stack.
|
|
||||||
*/
|
|
||||||
not_enough_stack:
|
|
||||||
sprintf(zBuf,"%d",pc);
|
|
||||||
sqliteSetString(pzErrMsg, "too few operands on stack at ", zBuf, 0);
|
|
||||||
rc = SQLITE_INTERNAL;
|
|
||||||
|
|
||||||
/* Jump here if an illegal or illformed instruction is executed.
|
|
||||||
*/
|
|
||||||
VERIFY(
|
|
||||||
bad_instruction:
|
|
||||||
sprintf(zBuf,"%d",pc);
|
|
||||||
sqliteSetString(pzErrMsg, "illegal operation at ", zBuf, 0);
|
|
||||||
rc = SQLITE_INTERNAL;
|
|
||||||
goto cleanup;
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
16
src/vdbe.h
16
src/vdbe.h
@@ -15,7 +15,7 @@
|
|||||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||||
** simple program to access and modify the underlying database.
|
** simple program to access and modify the underlying database.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.h,v 1.61 2003/01/01 23:06:21 drh Exp $
|
** $Id: vdbe.h,v 1.62 2003/01/28 23:13:13 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_VDBE_H_
|
#ifndef _SQLITE_VDBE_H_
|
||||||
#define _SQLITE_VDBE_H_
|
#define _SQLITE_VDBE_H_
|
||||||
@@ -62,6 +62,13 @@ typedef struct VdbeOp VdbeOp;
|
|||||||
*/
|
*/
|
||||||
#define ADDR(X) (-1-(X))
|
#define ADDR(X) (-1-(X))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The sqliteVdbeExec() routine can return any of the normal SQLite return
|
||||||
|
** codes defined in sqlite.h. But it can also return the following
|
||||||
|
** additional values:
|
||||||
|
*/
|
||||||
|
#define SQLITE_CALLBACK 100 /* sqliteVdbeExec() hit an OP_Callback */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The makefile scans the vdbe.c source file and creates the "opcodes.h"
|
** The makefile scans the vdbe.c source file and creates the "opcodes.h"
|
||||||
** header file that defines a number for each opcode used by the VDBE.
|
** header file that defines a number for each opcode used by the VDBE.
|
||||||
@@ -83,9 +90,10 @@ void sqliteVdbeDequoteP3(Vdbe*, int addr);
|
|||||||
int sqliteVdbeFindOp(Vdbe*, int, int);
|
int sqliteVdbeFindOp(Vdbe*, int, int);
|
||||||
int sqliteVdbeMakeLabel(Vdbe*);
|
int sqliteVdbeMakeLabel(Vdbe*);
|
||||||
void sqliteVdbeDelete(Vdbe*);
|
void sqliteVdbeDelete(Vdbe*);
|
||||||
int sqliteVdbeExec(Vdbe*,sqlite_callback,void*,char**,void*,
|
void sqliteVdbeMakeReady(Vdbe*,sqlite_callback,void*,int);
|
||||||
int(*)(void*,const char*,int));
|
int sqliteVdbeExec(Vdbe*);
|
||||||
int sqliteVdbeList(Vdbe*,sqlite_callback,void*,char**);
|
int sqliteVdbeList(Vdbe*);
|
||||||
|
int sqliteVdbeFinalize(Vdbe*,char**);
|
||||||
void sqliteVdbeResolveLabel(Vdbe*, int);
|
void sqliteVdbeResolveLabel(Vdbe*, int);
|
||||||
int sqliteVdbeCurrentAddr(Vdbe*);
|
int sqliteVdbeCurrentAddr(Vdbe*);
|
||||||
void sqliteVdbeTrace(Vdbe*,FILE*);
|
void sqliteVdbeTrace(Vdbe*,FILE*);
|
||||||
|
@@ -36,7 +36,6 @@ do_test trigger3-1.1 {
|
|||||||
INSERT INTO tbl VALUES (1, 5, 6);
|
INSERT INTO tbl VALUES (1, 5, 6);
|
||||||
}
|
}
|
||||||
} {1 {Trigger abort}}
|
} {1 {Trigger abort}}
|
||||||
|
|
||||||
do_test trigger3-1.2 {
|
do_test trigger3-1.2 {
|
||||||
execsql {
|
execsql {
|
||||||
SELECT * FROM tbl;
|
SELECT * FROM tbl;
|
||||||
|
Reference in New Issue
Block a user