aboutsummaryrefslogtreecommitdiff
path: root/src/tclsqlite.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tclsqlite.c')
-rw-r--r--src/tclsqlite.c173
1 files changed, 71 insertions, 102 deletions
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index bcc2f0ef6..e907878d0 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -11,7 +11,7 @@
*************************************************************************
** A TCL Interface to SQLite
**
-** $Id: tclsqlite.c,v 1.104 2004/09/06 17:24:13 drh Exp $
+** $Id: tclsqlite.c,v 1.105 2004/09/07 13:20:35 drh Exp $
*/
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
@@ -74,35 +74,6 @@ struct SqliteDb {
};
/*
-** This is a second alternative callback for database queries. A the
-** first column of the first row of the result is made the TCL result.
-*/
-static int DbEvalCallback3(
- void *clientData, /* An instance of CallbackData */
- int nCol, /* Number of columns in the result */
- char ** azCol, /* Data for each column */
- char ** azN /* Name for each column */
-){
- Tcl_Interp *interp = (Tcl_Interp*)clientData;
- Tcl_Obj *pElem;
- if( azCol==0 ) return 1;
- if( nCol==0 ) return 1;
-#ifdef UTF_TRANSLATION_NEEDED
- {
- Tcl_DString dCol;
- Tcl_DStringInit(&dCol);
- Tcl_ExternalToUtfDString(NULL, azCol[0], -1, &dCol);
- pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
- Tcl_DStringFree(&dCol);
- }
-#else
- pElem = Tcl_NewStringObj(azCol[0], -1);
-#endif
- Tcl_SetObjResult(interp, pElem);
- return 1;
-}
-
-/*
** TCL calls this procedure when an sqlite3 database command is
** deleted.
*/
@@ -496,48 +467,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
- /* $db progress ?N CALLBACK?
- **
- ** Invoke the given callback every N virtual machine opcodes while executing
- ** queries.
- */
- case DB_PROGRESS: {
- if( objc==2 ){
- if( pDb->zProgress ){
- Tcl_AppendResult(interp, pDb->zProgress, 0);
- }
- }else if( objc==4 ){
- char *zProgress;
- int len;
- int N;
- if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
- return TCL_ERROR;
- };
- if( pDb->zProgress ){
- Tcl_Free(pDb->zProgress);
- }
- zProgress = Tcl_GetStringFromObj(objv[3], &len);
- if( zProgress && len>0 ){
- pDb->zProgress = Tcl_Alloc( len + 1 );
- strcpy(pDb->zProgress, zProgress);
- }else{
- pDb->zProgress = 0;
- }
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- if( pDb->zProgress ){
- pDb->interp = interp;
- sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb);
- }else{
- sqlite3_progress_handler(pDb->db, 0, 0, 0);
- }
-#endif
- }else{
- Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK");
- return TCL_ERROR;
- }
- break;
- }
-
/* $db changes
**
** Return the number of rows that were modified, inserted, or deleted by
@@ -685,13 +614,18 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/*
** $db eval $sql ?array? ?{ ...code... }?
+ ** $db onecolumn $sql
**
** 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.
** If "array" and "code" are omitted, then no callback is every invoked.
** If "array" is an empty string, then the values are placed in variables
** that have the same name as the fields extracted by the query.
+ **
+ ** The onecolumn method is the equivalent of:
+ ** lindex [$db eval $sql] 0
*/
+ case DB_ONECOLUMN:
case DB_EVAL: {
char const *zSql; /* Next SQL statement to execute */
char const *zLeft; /* What is left after first stmt in zSql */
@@ -701,13 +635,21 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_Obj **apParm; /* Parameters that need a Tcl_DecrRefCount() */
int nParm; /* Number of entries used in apParm[] */
Tcl_Obj *aParm[10]; /* Static space for apParm[] in the common case */
+ Tcl_Obj *pRet; /* Value to be returned */
- Tcl_Obj *pRet = Tcl_NewObj();
- Tcl_IncrRefCount(pRet);
-
- if( objc<3 || objc>5 ){
- Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?");
- return TCL_ERROR;
+ if( choice==DB_ONECOLUMN ){
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "SQL");
+ return TCL_ERROR;
+ }
+ pRet = 0;
+ }else{
+ if( objc<3 || objc>5 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?");
+ return TCL_ERROR;
+ }
+ pRet = Tcl_NewObj();
+ Tcl_IncrRefCount(pRet);
}
if( objc==3 ){
pArray = pScript = 0;
@@ -784,7 +726,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
}
}
-
/* Compute column names */
nCol = sqlite3_column_count(pStmt);
@@ -848,6 +789,12 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else{
Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0);
}
+ }else if( choice==DB_ONECOLUMN ){
+ if( pRet==0 ){
+ pRet = pVal;
+ Tcl_IncrRefCount(pRet);
+ }
+ goto end_step;
}else{
Tcl_ListObjAppendElement(interp, pRet, pVal);
}
@@ -858,6 +805,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
if( rc!=TCL_ERROR ) rc = TCL_OK;
}
}
+ end_step:
/* Free the column name objects */
if( pScript ){
@@ -892,10 +840,12 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
Tcl_DecrRefCount(objv[2]);
- if( rc==TCL_OK ){
- Tcl_SetObjResult(interp, pRet);
+ if( pRet ){
+ if( rc==TCL_OK ){
+ Tcl_SetObjResult(interp, pRet);
+ }
+ Tcl_DecrRefCount(pRet);
}
- Tcl_DecrRefCount(pRet);
break;
}
@@ -949,29 +899,48 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
- ** $db onecolumn SQL
- **
- ** Return a single column from a single row of the given SQL query.
+ ** The DB_ONECOLUMN method is implemented together with DB_EVAL.
*/
- case DB_ONECOLUMN: {
- char *zSql;
- char *zErrMsg = 0;
- if( objc!=3 ){
- Tcl_WrongNumArgs(interp, 2, objv, "SQL");
+
+ /* $db progress ?N CALLBACK?
+ **
+ ** Invoke the given callback every N virtual machine opcodes while executing
+ ** queries.
+ */
+ case DB_PROGRESS: {
+ if( objc==2 ){
+ if( pDb->zProgress ){
+ Tcl_AppendResult(interp, pDb->zProgress, 0);
+ }
+ }else if( objc==4 ){
+ char *zProgress;
+ int len;
+ int N;
+ if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
+ return TCL_ERROR;
+ };
+ if( pDb->zProgress ){
+ Tcl_Free(pDb->zProgress);
+ }
+ zProgress = Tcl_GetStringFromObj(objv[3], &len);
+ if( zProgress && len>0 ){
+ pDb->zProgress = Tcl_Alloc( len + 1 );
+ strcpy(pDb->zProgress, zProgress);
+ }else{
+ pDb->zProgress = 0;
+ }
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ if( pDb->zProgress ){
+ pDb->interp = interp;
+ sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb);
+ }else{
+ sqlite3_progress_handler(pDb->db, 0, 0, 0);
+ }
+#endif
+ }else{
+ Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK");
return TCL_ERROR;
}
- zSql = Tcl_GetStringFromObj(objv[2], 0);
- rc = sqlite3_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg);
- if( rc==SQLITE_ABORT ){
- rc = SQLITE_OK;
- }else if( zErrMsg ){
- Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
- free(zErrMsg);
- rc = TCL_ERROR;
- }else if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
- rc = TCL_ERROR;
- }
break;
}