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:
drh 2003-01-28 23:13:10 +00:00
parent 70c15b48ae
commit b86ccfb26e
12 changed files with 880 additions and 342 deletions

View File

@ -1,5 +1,5 @@
C Added\ssection\son\scomments.\nCorrected\sbroken\s</p>\send\stags.\s(CVS\s851)
D 2003-01-26T15:28:18
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-28T23:13:11
F Makefile.in 6606854b1512f185b8e8c779b8d7fc2750463d64
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -21,7 +21,7 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
F src/auth.c 9c2db0bc7707f2d2e227f47e3d557b41d44ade75
F src/btree.c eb4f430b062500d7533c031097d3ff8824eca3ba
F src/btree.h 17710339f7a8f46e3c7d6d0d4648ef19c584ffda
F src/build.c d6716dae74cccdcb9db6d05f65f7994762aa6d9f
F src/build.c 1a4c0d71863f0aa0be7e5a2148b103c3e761c771
F src/delete.c cbd499f3f9297504c42e328af89bef1a2113d04c
F src/encode.c faf03741efe921755ec371cf4a6984536de00042
F src/expr.c 382839b92cb66a34cfa71cf1d2bc8fb818226c90
@ -29,32 +29,32 @@ F src/func.c 90c583f0b91220f7cd411a2407deaf9327245d63
F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
F src/insert.c db954e955970795819145a3649fd2ad116a58890
F src/main.c ad3193c56da5acd31bc6cd48aa50dae1962d7c78
F src/main.c c58cdfb5f0c1938e78d47584e88799b77091700c
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
F src/os.c ed27e178e0c4b71f2807da81b8851f0fadc50778
F src/os.h afa3e096213bad86845f8bdca81a9e917505e401
F src/pager.c 95f5c5c775ed47e837ce02b407d80527d93e6c43
F src/pager.h 540833e8cb826b80ce2e39aa917deee5e12db626
F src/parse.y a4fbfbe3c4254c96dae8c33264fb54af755a3770
F src/parse.y aea0819c07ec9c81b810039df9be9d5705b1e497
F src/printf.c e8e9a0605602cb1a3a2dc754e0978fa9064ecee7
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c c3c0b8263587d290592dca8b4371b5c1162ca684
F src/shell.c cbb29252f0bd7b144d1e3126e64e17e5a314f2fd
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 90657185cff387069d17c5b876a87a6a7a3b6f10
F src/sqliteInt.h 1d614e04f3c439d7bb60a65f821f8ec53ef6a7e8
F src/sqlite.h.in ace5c971df379f07ade9ae4b2066cc18ee8b6cfa
F src/sqliteInt.h 576855338db3e3673605bd08b32a5a8cb3f57cf8
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
F src/tclsqlite.c 9f2c00a92338c51171ded8943bd42d77f7e69e64
F src/test1.c 921e5dda494f836d2ebea703bd5b239a7cc963d0
F src/test1.c c00a4e561287da1976149fe156748253bd8926e7
F src/test2.c 03f05e984c8e2f2badc44644d42baf72b249096b
F src/test3.c c12ea7f1c3fbbd58904e81e6cb10ad424e6fc728
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
F src/tokenize.c 7ac1c33e0149647c9eb5959c48992df6906d4809
F src/tokenize.c 0ba74091f432b79687fc7fbecc9e9087bfb40a56
F src/trigger.c da142decd2808bc39e801f3bb1f161dbc2bd4005
F src/update.c f06afa9bf1f777d17702e0f6e33cf44c44bc4f75
F src/util.c e23f8ffc654923e18f8db2d8e0de97c166fca20f
F src/vdbe.c 7796485aa510c89aa378a11d3fbeb6fcf3893433
F src/vdbe.h 754eba497cfe0c3e352b9c101ab2f811f10d0a55
F src/vdbe.c 899b59df8a6d91020c3d5c54a817fb669f98176b
F src/vdbe.h 30b808a32f8d66e9948d0a9931f1e1037d2ec2ad
F src/where.c 5bf7f1e1d756ab3d25a18b24bb42106cb8e14d18
F test/all.test 873d30e25a41b3aa48fec5633a7ec1816e107029
F test/auth.test 95aeda24f76b6fd028bdb3d6ae1e30b153d942fe
@ -110,7 +110,7 @@ F test/tester.tcl 6f603d90881bd835ea27c568a7fecaa57dce91cc
F test/trans.test 10b53c77e2cc4ad9529c15fdcb390b8d5722ea65
F test/trigger1.test ec1da76e1a9f618deb96e505f459dcf8a23f2247
F test/trigger2.test ee346d8c612e7f847c9543058f1b89d094d27ffb
F test/trigger3.test 5958cdb44e95842298436cb61d5de5251ec2d28e
F test/trigger3.test 870afef7997a5b86bf3ea893ce0c2e85d6356c72
F test/trigger4.test 9a5c1406344d743020c2753ae8d6dfe6eb75f818
F test/unique.test 572aa791327c1e8d797932263e9d67f176cfdb44
F test/update.test 7ffb062d580a972e7870d0f51d5af3ab9bfeae08
@ -154,7 +154,7 @@ F www/speed.tcl 4d463e2aea41f688ed320a937f93ff885be918c3
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P bdba796f3b89690ab5d53a9e16924383ef72657c
R 2fbda7b77729464b96834537506192f2
U jplyon
Z 22282820ee286f511aad4850aeea1aad
P c957f4f0c6b486f25bc567dafeed186f91c8c315
R fba6d74be1d355dfd1b4bac9d5e01203
U drh
Z 6e26856c68db7a18e1f9ce32bbc7b32d

View File

@ -1 +1 @@
c957f4f0c6b486f25bc567dafeed186f91c8c315
065fa818ffc8d7562889172acea16e4e44e773ef

View File

@ -25,7 +25,7 @@
** ROLLBACK
** 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 <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
** 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){
int rc = SQLITE_OK;
sqlite *db = pParse->db;
Vdbe *v = pParse->pVdbe;
int (*xCallback)(void*,int,char**,char**);
if( sqlite_malloc_failed ) return;
if( pParse->pVdbe && pParse->nErr==0 ){
if( pParse->explain ){
rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg,
&pParse->zErrMsg);
db->next_cookie = db->schema_cookie;
}else{
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
sqliteVdbeTrace(pParse->pVdbe, trace);
rc = sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg,
&pParse->zErrMsg, db->pBusyArg,
db->xBusyCallback);
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 ){
rc = sqliteVdbeList(v);
db->next_cookie = db->schema_cookie;
}else{
sqliteVdbeExec(v);
}
rc = sqliteVdbeFinalize(v, &pParse->zErrMsg);
if( rc ) pParse->nErr++;
sqliteVdbeDelete(v);
pParse->pVdbe = 0;
pParse->rc = rc;
if( rc ) pParse->nErr++;
}else{
pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
}
sqliteVdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
pParse->colNamesSet = 0;
pParse->rc = rc;
pParse->schemaVerified = 0;
}
pParse->nTab = 0;

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.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 "os.h"
@ -69,6 +69,7 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
sParse.initFlag = 1;
sParse.isTemp = argv[4][0] - '0';
sParse.newTnum = atoi(argv[2]);
sParse.useCallback = 1;
sqliteRunParser(&sParse, argv[3], pData->pzErrMsg);
}else{
/* 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.pArg = (void*)&initData;
sParse.initFlag = 1;
sParse.useCallback = 1;
sqliteRunParser(&sParse,
db->file_format>=2 ? init_script : older_init_script,
pzErrMsg);
@ -584,29 +586,23 @@ int sqlite_complete(const char *zSql){
}
/*
** 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.
** This routine does the work of either sqlite_exec() or sqlite_compile().
** It works like sqlite_exec() if pVm==NULL and it works like sqlite_compile()
** otherwise.
*/
int sqlite_exec(
static int sqliteMain(
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 */
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;
if( pzErrMsg ) *pzErrMsg = 0;
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 ){
int rc, cnt = 1;
while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY
@ -633,6 +629,10 @@ int sqlite_exec(
sParse.pBe = db->pBe;
sParse.xCallback = xCallback;
sParse.pArg = pArg;
sParse.useCallback = ppVm==0;
#ifndef SQLITE_OMIT_TRACE
if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
#endif
sqliteRunParser(&sParse, zSql, pzErrMsg);
if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", 0);
@ -650,6 +650,11 @@ int sqlite_exec(
sqliteResetInternalSchema(db);
}
db->recursionDepth--;
if( sParse.useCallback==0 ){
assert( ppVm );
*ppVm = sParse.pVdbe;
*pzTail = &sParse.sLastToken.z[sParse.sLastToken.n];
}
if( sqliteSafetyOff(db) ) goto exec_misuse;
return sParse.rc;
@ -662,6 +667,59 @@ exec_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
** argument.

View File

@ -14,15 +14,22 @@
** the parser. Lemon will also generate a header file containing
** 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_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
sqliteSetString(&pParse->zErrMsg,"syntax error",0);
pParse->sErrToken = TOKEN;
if( pParse->zErrMsg==0 ){
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
%include {

View File

@ -12,17 +12,12 @@
** This header file defines the interface that the SQLite library
** 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_
#define _SQLITE_H_
#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++.
*/
@ -30,6 +25,11 @@
extern "C" {
#endif
/*
** The version of the SQLite library.
*/
#define SQLITE_VERSION "--VERS--"
/*
** 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
@ -73,7 +73,7 @@ typedef struct sqlite sqlite;
** The Truth: As currently implemented, all databases are opened
** for writing all the time. Maybe someday we will provide the
** 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);
@ -118,7 +118,8 @@ typedef int (*sqlite_callback)(void*,int,char**, char**);
** message is written into memory obtained from malloc() and
** *errmsg is made to point to that message. The calling function
** 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
** 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_ERROR 1 /* SQL error or missing database */
@ -164,6 +165,8 @@ int sqlite_exec(
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#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
@ -501,10 +504,11 @@ int sqlite_aggregate_count(sqlite_func*);
/*
** This routine registers a callback with the SQLite library. The
** callback is invoked for every attempt to access a column of a table
** in the database. The callback returns SQLITE_OK if access is allowed,
** SQLITE_DENY if the entire SQL statement should be aborted with an error
** and SQLITE_IGNORE if the column should be treated as a NULL value.
** callback is invoked (at compile-time, not at run-time) for each
** attempt to access a column of a table in the database. The callback
** returns SQLITE_OK if access is allowed, SQLITE_DENY if the entire
** 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(
sqlite*,
@ -555,17 +559,127 @@ int sqlite_set_authorizer(
#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().
** This function can be used (for example) to generate a log file of all
** SQL executed against a database.
** Register a function that is called at every invocation of sqlite_exec()
** or sqlite_compile(). This function can be used (for example) to generate
** a log file of all SQL executed against a database.
*/
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
** 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
** 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);

View File

@ -11,7 +11,7 @@
*************************************************************************
** 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 "sqlite.h"
@ -748,6 +748,7 @@ struct Parse {
u8 schemaVerified; /* True if an OP_VerifySchema has been coded someplace
** other than after an OP_Transaction */
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 nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */

View File

@ -13,13 +13,35 @@
** is not included in the SQLite library. It is used for automated
** 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 "tcl.h"
#include <stdlib.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
**
@ -45,7 +67,7 @@ static int sqlite_test_open(
free(zErr);
return TCL_ERROR;
}
sprintf(zBuf,"%d",(int)db);
sprintf(zBuf,"%p", db);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
@ -91,7 +113,7 @@ static int test_exec_printf(
" DB FORMAT STRING", 0);
return TCL_ERROR;
}
db = (sqlite*)strtol(argv[1], 0, 0);
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
Tcl_DStringInit(&str);
rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
sprintf(zBuf, "%d", rc);
@ -128,7 +150,7 @@ static int test_get_table_printf(
" DB FORMAT STRING", 0);
return TCL_ERROR;
}
db = (sqlite*)strtol(argv[1], 0, 0);
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
Tcl_DStringInit(&str);
rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
&zErr, argv[3]);
@ -169,7 +191,7 @@ static int test_last_rowid(
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
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));
Tcl_AppendResult(interp, zBuf, 0);
return SQLITE_OK;
@ -192,7 +214,7 @@ static int sqlite_test_close(
" FILENAME\"", 0);
return TCL_ERROR;
}
db = (sqlite*)strtol(argv[1], 0, 0);
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
sqlite_close(db);
return TCL_OK;
}
@ -251,7 +273,7 @@ static int test_create_function(
" FILENAME\"", 0);
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_sqlite_exec", 1, sqliteExecFunc, db);
return TCL_OK;
@ -300,7 +322,7 @@ static int test_create_aggregate(
" FILENAME\"", 0);
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", 1, countStep, countFinalize, 0);
return TCL_OK;
@ -497,7 +519,7 @@ static int test_register_func(
" DB FUNCTION-NAME", 0);
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);
if( rc!=0 ){
Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
@ -550,7 +572,7 @@ static int sqlite_datatypes(
" DB SQL", 0);
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);
if( rc!=0 && rc!=SQLITE_ABORT ){
Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
@ -659,7 +681,7 @@ static int test_set_authorizer(
" DB CALLBACK\"", 0);
return TCL_ERROR;
}
db = (sqlite*)strtol(argv[1], 0, 0);
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
zCmd = argv[2];
if( zCmd[0]==0 ){
sqlite_set_authorizer(db, 0, 0);
@ -677,6 +699,131 @@ static int test_set_authorizer(
}
#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.
*/
@ -706,6 +853,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
{ "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
#endif
{ "sqlite_compile", (Tcl_CmdProc*)test_compile },
{ "sqlite_step", (Tcl_CmdProc*)test_step },
{ "sqlite_finalize", (Tcl_CmdProc*)test_finalize },
};
int i;

View File

@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the
** 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 "os.h"
@ -406,6 +406,8 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int nErr = 0;
int i;
void *pEngine;
int tokenType;
int lastTokenParsed = -1;
sqlite *db = pParse->db;
extern void *sqliteParserAlloc(void*(*)(int));
extern void sqliteParserFree(void*, void(*)(void*));
@ -421,7 +423,6 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
}
pParse->sLastToken.dyn = 0;
while( sqlite_malloc_failed==0 && zSql[i]!=0 ){
int tokenType;
assert( i>=0 );
pParse->sLastToken.z = &zSql[i];
@ -446,19 +447,8 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
}
default: {
sqliteParser(pEngine, tokenType, 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;
goto abort_parse;
}else if( pParse->rc!=SQLITE_OK ){
sqliteSetString(pzErrMsg, sqlite_error_string(pParse->rc), 0);
nErr++;
lastTokenParsed = tokenType;
if( pParse->rc!=SQLITE_OK ){
goto abort_parse;
}
break;
@ -466,31 +456,26 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
}
}
abort_parse:
if( zSql[i]==0 && nErr==0 ){
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;
if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
if( lastTokenParsed!=TK_SEMI ){
sqliteParser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
}
sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
}
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( pzErrMsg ){
sqliteFree(*pzErrMsg);
if( pzErrMsg && *pzErrMsg==0 ){
*pzErrMsg = pParse->zErrMsg;
}else{
sqliteFree(pParse->zErrMsg);
}
pParse->zErrMsg = 0;
if( !nErr ) nErr++;
}
if( pParse->pVdbe ){
if( pParse->pVdbe && (pParse->useCallback || pParse->nErr>0) ){
sqliteVdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
}
@ -498,7 +483,7 @@ abort_parse:
sqliteDeleteTable(pParse->db, pParse->pNewTable);
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;
}
return nErr;

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.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_
#define _SQLITE_VDBE_H_
@ -62,6 +62,13 @@ typedef struct VdbeOp VdbeOp;
*/
#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"
** 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 sqliteVdbeMakeLabel(Vdbe*);
void sqliteVdbeDelete(Vdbe*);
int sqliteVdbeExec(Vdbe*,sqlite_callback,void*,char**,void*,
int(*)(void*,const char*,int));
int sqliteVdbeList(Vdbe*,sqlite_callback,void*,char**);
void sqliteVdbeMakeReady(Vdbe*,sqlite_callback,void*,int);
int sqliteVdbeExec(Vdbe*);
int sqliteVdbeList(Vdbe*);
int sqliteVdbeFinalize(Vdbe*,char**);
void sqliteVdbeResolveLabel(Vdbe*, int);
int sqliteVdbeCurrentAddr(Vdbe*);
void sqliteVdbeTrace(Vdbe*,FILE*);

View File

@ -36,7 +36,6 @@ do_test trigger3-1.1 {
INSERT INTO tbl VALUES (1, 5, 6);
}
} {1 {Trigger abort}}
do_test trigger3-1.2 {
execsql {
SELECT * FROM tbl;