aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c5
-rw-r--r--src/parse.y14
-rw-r--r--src/sqlite.h.in12
-rw-r--r--src/tclsqlite.c42
-rw-r--r--src/test1.c31
-rw-r--r--src/tokenize.c50
-rw-r--r--src/vdbeInt.h2
-rw-r--r--src/vdbeapi.c27
-rw-r--r--src/vdbeaux.c3
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;
}