mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
The callback-free API is now working, though much more testing is need. (CVS 853)
FossilOrigin-Name: 162b259188e6967fe9c3722da26b81aab5655d83
This commit is contained in:
11
src/main.c
11
src/main.c
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.110 2003/01/28 23:13:12 drh Exp $
|
||||
** $Id: main.c,v 1.111 2003/01/29 14:06:08 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -622,8 +622,7 @@ static int sqliteMain(
|
||||
sqliteSetString(pzErrMsg, "obsolete database file format", 0);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if( db->recursionDepth==0 ){ db->nChange = 0; }
|
||||
db->recursionDepth++;
|
||||
if( db->pVdbe==0 ){ db->nChange = 0; }
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sParse.pBe = db->pBe;
|
||||
@ -642,6 +641,7 @@ static int sqliteMain(
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
sqliteResetInternalSchema(db);
|
||||
}
|
||||
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
|
||||
if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
|
||||
sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), 0);
|
||||
}
|
||||
@ -649,11 +649,10 @@ static int sqliteMain(
|
||||
if( sParse.rc==SQLITE_SCHEMA ){
|
||||
sqliteResetInternalSchema(db);
|
||||
}
|
||||
db->recursionDepth--;
|
||||
if( sParse.useCallback==0 ){
|
||||
assert( ppVm );
|
||||
*ppVm = sParse.pVdbe;
|
||||
*pzTail = &sParse.sLastToken.z[sParse.sLastToken.n];
|
||||
*ppVm = (sqlite_vm*)sParse.pVdbe;
|
||||
*pzTail = sParse.zTail;
|
||||
}
|
||||
if( sqliteSafetyOff(db) ) goto exec_misuse;
|
||||
return sParse.rc;
|
||||
|
14
src/select.c
14
src/select.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.123 2003/01/19 03:59:47 drh Exp $
|
||||
** $Id: select.c,v 1.124 2003/01/29 14:06:09 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -697,7 +697,9 @@ static void generateColumnTypes(
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int i;
|
||||
if( (pParse->db->flags & SQLITE_ReportTypes)==0 ) return;
|
||||
if( pParse->useCallback && (pParse->db->flags & SQLITE_ReportTypes)==0 ){
|
||||
return;
|
||||
}
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
Expr *p = pEList->a[i].pExpr;
|
||||
char *zType = 0;
|
||||
@ -1456,7 +1458,9 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
|
||||
/* Issue a null callback if that is what the user wants.
|
||||
*/
|
||||
if( (pParse->db->flags & SQLITE_NullCallback)!=0 && eDest==SRT_Callback ){
|
||||
if( eDest==SRT_Callback &&
|
||||
(pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0)
|
||||
){
|
||||
sqliteVdbeAddOp(v, OP_NullCallback, p->pEList->nExpr, 0);
|
||||
}
|
||||
return 0;
|
||||
@ -2306,7 +2310,9 @@ int sqliteSelect(
|
||||
|
||||
/* Issue a null callback if that is what the user wants.
|
||||
*/
|
||||
if( (pParse->db->flags & SQLITE_NullCallback)!=0 && eDest==SRT_Callback ){
|
||||
if( eDest==SRT_Callback &&
|
||||
(pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0)
|
||||
){
|
||||
sqliteVdbeAddOp(v, OP_NullCallback, pEList->nExpr, 0);
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.40 2003/01/28 23:13:12 drh Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.41 2003/01/29 14:06:09 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_H_
|
||||
#define _SQLITE_H_
|
||||
@ -588,6 +588,8 @@ typedef struct sqlite_vm sqlite_vm;
|
||||
**
|
||||
** *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 the input text contained no SQL (if the input is and empty string or
|
||||
** a comment) then *ppVm is 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
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.157 2003/01/28 23:13:12 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.158 2003/01/29 14:06:09 drh Exp $
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "sqlite.h"
|
||||
@ -224,7 +224,7 @@ struct sqlite {
|
||||
int onError; /* Default conflict algorithm */
|
||||
int magic; /* Magic number for detect library misuse */
|
||||
int nChange; /* Number of rows changed */
|
||||
int recursionDepth; /* Number of nested calls to sqlite_exec() */
|
||||
struct Vdbe *pVdbe; /* List of active virtual machines */
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
void (*xTrace)(void*,const char*); /* Trace function */
|
||||
void *pTraceArg; /* Argument to the trace function */
|
||||
@ -737,6 +737,7 @@ struct Parse {
|
||||
Token sErrToken; /* The token at which the error occurred */
|
||||
Token sFirstToken; /* The first token parsed */
|
||||
Token sLastToken; /* The last token parsed */
|
||||
const char *zTail; /* All SQL text past the last semicolon parsed */
|
||||
Table *pNewTable; /* A table being constructed by CREATE TABLE */
|
||||
Vdbe *pVdbe; /* An engine for executing database bytecode */
|
||||
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
|
||||
|
20
src/test1.c
20
src/test1.c
@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test1.c,v 1.17 2003/01/28 23:13:12 drh Exp $
|
||||
** $Id: test1.c,v 1.18 2003/01/29 14:06:09 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
@ -733,8 +733,10 @@ static int test_compile(
|
||||
sqlite_freemem(zErr);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sprintf(zBuf, "%p", vm);
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
if( vm ){
|
||||
sprintf(zBuf, "%p", vm);
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
}
|
||||
Tcl_SetVar(interp, argv[3], zTail, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
@ -765,7 +767,7 @@ static int test_step(
|
||||
}
|
||||
if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
|
||||
rc = sqlite_step(vm, &N, &azValue, &azColName);
|
||||
if( rc==SQLITE_DONE || SQLITE_ROW ){
|
||||
if( rc==SQLITE_DONE || rc==SQLITE_ROW ){
|
||||
sprintf(zBuf, "%d", N);
|
||||
Tcl_SetVar(interp, argv[2], zBuf, 0);
|
||||
Tcl_SetVar(interp, argv[3], "", 0);
|
||||
@ -777,15 +779,15 @@ static int test_step(
|
||||
}
|
||||
Tcl_SetVar(interp, argv[4], "", 0);
|
||||
for(i=0; i<N*2; i++){
|
||||
Tcl_SetVar(interp, argv[4], azValue[i] ? azValue[i] : "",
|
||||
Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[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_BUSY: zRc = "SQLITE_BUSY"; break;
|
||||
case SQLITE_ROW: zRc = "SQLITE_ROW"; break;
|
||||
case SQLITE_ERROR: zRc = "SQLITE_ERROR"; break;
|
||||
case SQLITE_MISUSE: zRc = "SQLITE_MISUSE"; break;
|
||||
default: zRc = "unknown"; break;
|
||||
}
|
||||
@ -809,7 +811,7 @@ static int test_finalize(
|
||||
char *zErrMsg = 0;
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" VM NVAR VALUEVAR COLNAMEVAR", 0);
|
||||
" VM\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
|
||||
|
@ -15,7 +15,7 @@
|
||||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
**
|
||||
** $Id: tokenize.c,v 1.54 2003/01/28 23:13:12 drh Exp $
|
||||
** $Id: tokenize.c,v 1.55 2003/01/29 14:06:09 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -422,6 +422,7 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
return 1;
|
||||
}
|
||||
pParse->sLastToken.dyn = 0;
|
||||
pParse->zTail = zSql;
|
||||
while( sqlite_malloc_failed==0 && zSql[i]!=0 ){
|
||||
|
||||
assert( i>=0 );
|
||||
@ -445,6 +446,10 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
nErr++;
|
||||
goto abort_parse;
|
||||
}
|
||||
case TK_SEMI: {
|
||||
pParse->zTail = &zSql[i];
|
||||
/* Fall thru into the default case */
|
||||
}
|
||||
default: {
|
||||
sqliteParser(pEngine, tokenType, pParse->sLastToken, pParse);
|
||||
lastTokenParsed = tokenType;
|
||||
@ -459,6 +464,7 @@ abort_parse:
|
||||
if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
|
||||
if( lastTokenParsed!=TK_SEMI ){
|
||||
sqliteParser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
|
||||
pParse->zTail = &zSql[i];
|
||||
}
|
||||
sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.56 2003/01/14 00:44:09 drh Exp $
|
||||
** $Id: util.c,v 1.57 2003/01/29 14:06:09 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
@ -1196,7 +1196,7 @@ int sqliteSafetyOff(sqlite *db){
|
||||
** at the wrong time or in the wrong sequence.
|
||||
*/
|
||||
int sqliteSafetyCheck(sqlite *db){
|
||||
if( db->recursionDepth ){
|
||||
if( db->pVdbe!=0 ){
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
40
src/vdbe.c
40
src/vdbe.c
@ -36,7 +36,7 @@
|
||||
** in this file for details. If in doubt, do not deviate from existing
|
||||
** commenting and indentation practices when changing or adding code.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.200 2003/01/28 23:13:12 drh Exp $
|
||||
** $Id: vdbe.c,v 1.201 2003/01/29 14:06:09 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -242,6 +242,7 @@ struct Keylist {
|
||||
*/
|
||||
struct Vdbe {
|
||||
sqlite *db; /* The whole database */
|
||||
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
Btree *pBt; /* Opaque context structure used by DB backend */
|
||||
FILE *trace; /* Write an execution trace here, if not NULL */
|
||||
int nOp; /* Number of instructions in the program */
|
||||
@ -316,6 +317,12 @@ Vdbe *sqliteVdbeCreate(sqlite *db){
|
||||
if( p==0 ) return 0;
|
||||
p->pBt = db->pBe;
|
||||
p->db = db;
|
||||
if( db->pVdbe ){
|
||||
db->pVdbe->pPrev = p;
|
||||
}
|
||||
p->pNext = db->pVdbe;
|
||||
p->pPrev = 0;
|
||||
db->pVdbe = p;
|
||||
p->magic = VDBE_MAGIC_INIT;
|
||||
return p;
|
||||
}
|
||||
@ -763,17 +770,22 @@ int sqlite_step(
|
||||
const char ***pazColName /* OUT: Column names and datatypes */
|
||||
){
|
||||
Vdbe *p = (Vdbe*)pVm;
|
||||
sqlite *db;
|
||||
int rc;
|
||||
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
db = p->db;
|
||||
if( sqliteSafetyOn(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
if( p->explain ){
|
||||
rc = sqliteVdbeList(p);
|
||||
}else{
|
||||
rc = sqliteVdbeExec(p);
|
||||
}
|
||||
if( rc!=SQLITE_DONE ){
|
||||
if( rc==SQLITE_DONE || rc==SQLITE_ROW ){
|
||||
*pazColName = (const char**)p->azColName;
|
||||
*pN = p->nResColumn;
|
||||
}else{
|
||||
@ -785,6 +797,9 @@ int sqlite_step(
|
||||
}else{
|
||||
*pazValue = 0;
|
||||
}
|
||||
if( sqliteSafetyOff(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1191,6 +1206,16 @@ void sqliteVdbeDelete(Vdbe *p){
|
||||
int i;
|
||||
if( p==0 ) return;
|
||||
Cleanup(p);
|
||||
if( p->pPrev ){
|
||||
p->pPrev->pNext = p->pNext;
|
||||
}else{
|
||||
assert( p->db->pVdbe==p );
|
||||
p->db->pVdbe = p->pNext;
|
||||
}
|
||||
if( p->pNext ){
|
||||
p->pNext->pPrev = p->pPrev;
|
||||
}
|
||||
p->pPrev = p->pNext = 0;
|
||||
if( p->nOpAlloc==0 ){
|
||||
p->aOp = 0;
|
||||
p->nOp = 0;
|
||||
@ -1255,7 +1280,7 @@ int sqliteVdbeList(
|
||||
p->pc = i+1;
|
||||
p->azResColumn = p->zStack;
|
||||
p->nResColumn = 5;
|
||||
return SQLITE_CALLBACK;
|
||||
return SQLITE_ROW;
|
||||
}
|
||||
if( sqliteSafetyOff(db) ){
|
||||
p->rc = SQLITE_MISUSE;
|
||||
@ -1453,7 +1478,7 @@ __inline__ unsigned long long int hwtime(void){
|
||||
**
|
||||
** The behavior of sqliteVdbeExec() is influenced by the parameters to
|
||||
** this routine. If xCallback is NULL, then sqliteVdbeExec() will return
|
||||
** with SQLITE_CALLBACK whenever there is a row of the result set ready
|
||||
** with SQLITE_ROW whenever there is a row of the result set ready
|
||||
** to be delivered. p->azResColumn will point to the row and
|
||||
** p->nResColumn gives the number of columns in the row. If xCallback
|
||||
** is not NULL, then the xCallback() routine is invoked to process each
|
||||
@ -1523,7 +1548,7 @@ void sqliteVdbeMakeReady(
|
||||
**
|
||||
** 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.
|
||||
** SQLITE_ROW.
|
||||
**
|
||||
** 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
|
||||
@ -1887,7 +1912,7 @@ case OP_Callback: {
|
||||
p->nResColumn = pOp->p1;
|
||||
p->popStack = pOp->p1;
|
||||
p->pc = pc + 1;
|
||||
return SQLITE_CALLBACK;
|
||||
return SQLITE_ROW;
|
||||
}
|
||||
if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
|
||||
if( p->xCallback(p->pCbArg, pOp->p1, &zStack[i], p->azColName)!=0 ){
|
||||
@ -1926,6 +1951,7 @@ case OP_NullCallback: {
|
||||
p->nCallback++;
|
||||
if( sqlite_malloc_failed ) goto no_mem;
|
||||
}
|
||||
p->nResColumn = pOp->p1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4843,7 +4869,7 @@ case OP_SortCallback: {
|
||||
p->azResColumn = (char**)zStack[i];
|
||||
p->nResColumn = pOp->p1;
|
||||
p->popStack = 1;
|
||||
return SQLITE_CALLBACK;
|
||||
return SQLITE_ROW;
|
||||
}else{
|
||||
if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
|
||||
if( p->xCallback(p->pCbArg, pOp->p1, (char**)zStack[i], p->azColName)!=0 ){
|
||||
|
@ -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.62 2003/01/28 23:13:13 drh Exp $
|
||||
** $Id: vdbe.h,v 1.63 2003/01/29 14:06:10 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@ -62,13 +62,6 @@ 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.
|
||||
|
Reference in New Issue
Block a user