diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 5 | ||||
-rw-r--r-- | src/parse.y | 14 | ||||
-rw-r--r-- | src/sqlite.h.in | 12 | ||||
-rw-r--r-- | src/tclsqlite.c | 42 | ||||
-rw-r--r-- | src/test1.c | 31 | ||||
-rw-r--r-- | src/tokenize.c | 50 | ||||
-rw-r--r-- | src/vdbeInt.h | 2 | ||||
-rw-r--r-- | src/vdbeapi.c | 27 | ||||
-rw-r--r-- | src/vdbeaux.c | 3 |
9 files changed, 158 insertions, 28 deletions
diff --git a/src/expr.c b/src/expr.c index a77787480..6e8a75ee4 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.155 2004/08/08 23:39:19 drh Exp $ +** $Id: expr.c,v 1.156 2004/08/20 16:02:39 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1162,6 +1162,9 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ } case TK_VARIABLE: { sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0); + if( pExpr->token.n>1 ){ + sqlite3VdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n); + } break; } case TK_LT: diff --git a/src/parse.y b/src/parse.y index 26f906cdd..528711e4c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.133 2004/08/19 15:12:26 drh Exp $ +** @(#) $Id: parse.y,v 1.134 2004/08/20 16:02:39 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -558,8 +558,16 @@ expr(A) ::= FLOAT(X). {A = sqlite3Expr(@X, 0, 0, &X);} expr(A) ::= STRING(X). {A = sqlite3Expr(@X, 0, 0, &X);} expr(A) ::= BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);} expr(A) ::= VARIABLE(X). { - A = sqlite3Expr(TK_VARIABLE, 0, 0, &X); - if( A ) A->iTable = ++pParse->nVar; + Token *pToken = &X; + Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken); + if( pExpr ){ + if( pToken->z[0]==':' ){ + int n = pExpr->iTable = atoi(&pToken->z[1]); + if( pParse->nVar<n ) pParse->nVar = n; + }else{ + pExpr->iTable = ++pParse->nVar; + } + } } expr(A) ::= ID(X) LP exprlist(Y) RP(E). { A = sqlite3ExprFunction(Y, &X); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index bb7bc9d01..270f13509 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.113 2004/08/14 17:10:12 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.114 2004/08/20 16:02:39 drh Exp $ */ #ifndef _SQLITE_H_ #define _SQLITE_H_ @@ -632,12 +632,18 @@ int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); /* ** Return the number of wildcards in a compiled SQL statement. This ** routine was added to support DBD::SQLite. -** -**** EXPERIMENTAL ***** */ int sqlite3_bind_parameter_count(sqlite3_stmt*); /* +** Return the name of the i-th parameter. Ordinary wildcards "?" are +** nameless and a NULL is returned. For wildcards of the form :N: or +** $vvvv the complete text of the wildcard is returned. +** NULL is returned if the index is out of range. +*/ +const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); + +/* ** Return the number of columns in the result set returned by the compiled ** SQL statement. This routine returns 0 if pStmt is an SQL statement ** that does not return data (for example an UPDATE). diff --git a/src/tclsqlite.c b/src/tclsqlite.c index ab6821e6f..33f741d1c 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,11 +11,12 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.98 2004/07/26 12:24:23 drh Exp $ +** $Id: tclsqlite.c,v 1.99 2004/08/20 16:02:39 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ #include "sqliteInt.h" +#include "hash.h" #include "tcl.h" #include <stdlib.h> #include <string.h> @@ -58,8 +59,9 @@ struct SqlCollate { ** that has been opened by the SQLite TCL interface. */ typedef struct SqliteDb SqliteDb; +typedef struct SqlStmt SqlStmt; struct SqliteDb { - sqlite *db; /* The "real" database structure */ + sqlite3 *db; /* The "real" database structure */ Tcl_Interp *interp; /* The interpreter used for this database */ char *zBusy; /* The busy callback routine */ char *zCommit; /* The commit hook callback routine */ @@ -70,21 +72,19 @@ struct SqliteDb { SqlCollate *pCollate; /* List of SQL collation functions */ int rc; /* Return code of most recent sqlite3_exec() */ Tcl_Obj *pCollateNeeded; /* Collation needed script */ + SqlStmt *pStmtList; /* List of all prepared statements */ }; /* -** An instance of this structure passes information thru the sqlite -** logic from the original TCL command into the callback routine. +** Each prepared statement is an instance of the following structure. */ -typedef struct CallbackData CallbackData; -struct CallbackData { - Tcl_Interp *interp; /* The TCL interpreter */ - char *zArray; /* The array into which data is written */ - Tcl_Obj *pCode; /* The code to execute for each row */ - int once; /* Set for first callback only */ - int tcl_rc; /* Return code from TCL script */ - int nColName; /* Number of entries in the azColName[] array */ - char **azColName; /* Column names translated to UTF-8 */ +struct SqlStmt { + SqliteDb *pDb; /* The database that this statement is part of */ + SqlStmt *pAll; /* Next statement in list of all for pDb */ + SqlStmt **ppPrev; /* Previous pAll pointer */ + sqlite3_stmt *pVm; /* Compiled statement. */ + int nBind; /* Number of bindings in this statement */ + char *azBindVar[1]; /* Name of variables for each binding */ }; /* @@ -117,10 +117,17 @@ static int DbEvalCallback3( } /* -** Called when the command is deleted. +** TCL calls this procedure when an sqlite3 database command is +** deleted. */ static void DbDeleteCmd(void *db){ SqliteDb *pDb = (SqliteDb*)db; + SqlStmt *pStmt, *pNextStmt; + for(pStmt=pDb->pStmtList; pStmt; pStmt=pNextStmt){ + pNextStmt = pStmt->pAll; + sqlite3_finalize(pStmt->pVm); + Tcl_Free(pStmt); + } sqlite3_close(pDb->db); while( pDb->pFunc ){ SqlFunc *pFunc = pDb->pFunc; @@ -280,6 +287,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv) SQLITE_TRANSIENT); } } + #ifndef SQLITE_OMIT_AUTHORIZATION /* ** This is the authentication function. It appends the authentication @@ -696,7 +704,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ } /* - ** $db eval $sql ?array { ...code... }? + ** $db eval $sql ?array? ?{ ...code... }? ** ** The SQL statement in $sql is evaluated. For each row, the values are ** placed in elements of the array named "array" and ...code... is executed. @@ -712,8 +720,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ Tcl_Obj *pRet = Tcl_NewObj(); Tcl_IncrRefCount(pRet); - if( objc!=5 && objc!=3 ){ - Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?"); + if( objc<3 || objc>5 || objc==4 ){ + Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?"); return TCL_ERROR; } diff --git a/src/test1.c b/src/test1.c index 3df370cdf..cb61c5ad8 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.97 2004/08/14 17:10:12 drh Exp $ +** $Id: test1.c,v 1.98 2004/08/20 16:02:39 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -1618,6 +1618,34 @@ static int test_bind_parameter_count( } /* +** Usage: sqlite3_bind_parameter_name STMT N +** +** Return the name of the Nth wildcard. The first wildcard is 1. +** An empty string is returned if N is out of range or if the wildcard +** is nameless. +*/ +static int test_bind_parameter_name( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_stmt *pStmt; + int i; + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "STMT N"); + return TCL_ERROR; + } + if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[2], &i) ) return TCL_ERROR; + Tcl_SetObjResult(interp, + Tcl_NewStringObj(sqlite3_bind_parameter_name(pStmt,i),-1) + ); + return TCL_OK; +} + +/* ** Usage: sqlite3_errcode DB ** ** Return the string representation of the most recent sqlite3_* API @@ -2409,6 +2437,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_bind_text16", test_bind_text16 ,0 }, { "sqlite3_bind_blob", test_bind_blob ,0 }, { "sqlite3_bind_parameter_count", test_bind_parameter_count, 0}, + { "sqlite3_bind_parameter_name", test_bind_parameter_name, 0}, { "sqlite3_errcode", test_errcode ,0 }, { "sqlite3_errmsg", test_errmsg ,0 }, { "sqlite3_errmsg16", test_errmsg16 ,0 }, diff --git a/src/tokenize.c b/src/tokenize.c index 401e7125f..b15b0b1b3 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.81 2004/08/08 23:39:19 drh Exp $ +** $Id: tokenize.c,v 1.82 2004/08/20 16:02:39 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -373,6 +373,54 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){ *tokenType = TK_VARIABLE; return 1; } + case ':': { + for(i=1; isdigit(z[i]); i++){} + if( i>1 && z[i]==':' ){ + *tokenType = TK_VARIABLE; + return i+1; + }else{ + *tokenType = TK_ILLEGAL; + return i; + } + } + case '$': { + int c; + if( z[1]=='{' ){ + int nBrace = 1; + for(i=2; (c=z[i])!=0 && nBrace; i++){ + if( c=='{' ){ + nBrace++; + }else if( c=='}' ){ + nBrace--; + } + } + *tokenType = c!=0 ? TK_VARIABLE : TK_ILLEGAL; + }else{ + int n = 0; + for(i=1; (c=z[i])!=0; i++){ + if( isalnum(c) || c=='_' ){ + n++; + }else if( c=='(' && n>0 ){ + do{ + i++; + }while( (c=z[i])!=0 && !isspace(c) && c!=')' ); + if( c==')' ){ + i++; + *tokenType = TK_VARIABLE; + }else{ + *tokenType = TK_ILLEGAL; + } + break; + }else if( c==':' && z[i+1]==':' ){ + i++; + }else{ + *tokenType = n==0 ? TK_ILLEGAL : TK_VARIABLE; + break; + } + } + } + return i; + } case 'x': case 'X': { if( z[1]=='\'' || z[1]=='"' ){ int delim = z[1]; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 72f528a28..c010b572c 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -316,6 +316,8 @@ struct Vdbe { char **azField; /* Data for each file field */ int nVar; /* Number of entries in apVar[] */ Mem *apVar; /* Values for the OP_Variable opcode. */ + char **azVar; /* Name of variables */ + int okVar; /* True if azVar[] has been initialized */ char *zLine; /* A single line from the input file */ int nLineAlloc; /* Number of spaces allocated for zLine */ int magic; /* Magic number for sanity checking */ diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 8c8c27816..09a1006b3 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -518,9 +518,32 @@ int sqlite3_bind_text16( /* ** Return the number of wildcards that can be potentially bound to. ** This routine is added to support DBD::SQLite. -** -******** EXPERIMENTAL ******* */ int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){ return ((Vdbe*)pStmt)->nVar; } + +/* +** Return the name of a wildcard parameter. Return NULL if the index +** is out of range or if the wildcard is unnamed. +** +** The result is always UTF-8. +*/ +const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){ + Vdbe *p = (Vdbe*)pStmt; + if( i<1 || i>p->nVar ){ + return 0; + } + if( !p->okVar ){ + int j; + Op *pOp; + for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){ + if( pOp->opcode==OP_Variable ){ + assert( pOp->p1>0 && pOp->p1<=p->nVar ); + p->azVar[pOp->p1-1] = pOp->p3; + } + } + p->okVar = 1; + } + return p->azVar[i-1]; +} diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 012159b17..9e7206205 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -574,9 +574,12 @@ void sqlite3VdbeMakeReady( p->aStack = sqliteMalloc( n*(sizeof(p->aStack[0])+sizeof(Mem*)) /* aStack, apArg */ + p->nVar*sizeof(Mem) /* apVar */ + + p->nVar*sizeof(char*) /* apVarName */ ); p->apArg = (Mem **)&p->aStack[n]; p->apVar = (Mem *)&p->apArg[n]; + p->azVar = (char**)&p->apVar[p->nVar]; + p->okVar = 0; for(n=0; n<p->nVar; n++){ p->apVar[n].flags = MEM_Null; } |