1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

:-) (CVS 125)

FossilOrigin-Name: ab9c533a3a256ca9d59a6a580c6064c903d962a5
This commit is contained in:
drh
2000-08-04 13:49:02 +00:00
parent 60bfa67829
commit bec3f4022f
7 changed files with 156 additions and 35 deletions

View File

@ -23,13 +23,24 @@
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.5 2000/06/04 12:58:38 drh Exp $
** $Id: tclsqlite.c,v 1.6 2000/08/04 13:49:02 drh Exp $
*/
#include "sqlite.h"
#include <tcl.h>
#include <stdlib.h>
#include <string.h>
/*
** There is one instance of this structure for each SQLite database
** that has been opened by the SQLite TCL interface.
*/
typedef struct SqliteDb SqliteDb;
struct SqliteDb {
sqlite *db; /* The "real" database structure */
Tcl_Interp *interp; /* The interpreter used for this database */
char *zBusy; /* The name of the busy callback routine */
};
/*
** An instance of this structure passes information thru the sqlite
** logic from the original TCL command into the callback routine.
@ -81,7 +92,38 @@ static int DbEvalCallback(
** Called when the command is deleted.
*/
static void DbDeleteCmd(void *db){
sqlite_close((sqlite*)db);
SqliteDb *pDb = (SqliteDb*)db;
sqlite_close(pDb->db);
if( pDb->zBusy ){
Tcl_Free(pDb->zBusy);
}
Tcl_Free((char*)pDb);
}
/*
** This routine is called when a database file is locked while trying
** to execute SQL.
*/
static int DbBusyHandler(void *cd, const char *zTable, int nTries){
SqliteDb *pDb = (SqliteDb*)cd;
int rc;
char zVal[30];
char *zCmd;
char *zResult;
Tcl_DString cmd;
Tcl_DStringInit(&cmd);
Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
Tcl_DStringAppendElement(&cmd, zTable);
sprintf(zVal, " %d", nTries);
Tcl_DStringAppend(&cmd, zVal, -1);
zCmd = Tcl_DStringValue(&cmd);
rc = Tcl_Eval(pDb->interp, zCmd);
Tcl_DStringFree(&cmd);
if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
return 0;
}
return 1;
}
/*
@ -100,7 +142,7 @@ static void DbDeleteCmd(void *db){
static int DbCmd(void *cd, Tcl_Interp *interp, int argc, char **argv){
char *z;
int n, c;
sqlite *db = cd;
SqliteDb *pDb = (SqliteDb*)cd;
if( argc<2 ){
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" SUBCOMMAND ...\"", 0);
@ -110,6 +152,38 @@ static int DbCmd(void *cd, Tcl_Interp *interp, int argc, char **argv){
n = strlen(z);
c = z[0];
/* $db busy ?CALLBACK?
**
** Invoke the given callback if an SQL statement attempts to open
** a locked database file.
*/
if( c=='b' && strncmp(z,"busy",n)==0 ){
if( argc>3 ){
Tcl_AppendResult(interp,"wrong # args: should be \"",
argv[0], " busy ?CALLBACK?", 0);
return TCL_ERROR;
}else if( argc==2 ){
if( pDb->zBusy ){
Tcl_AppendResult(interp, pDb->zBusy, 0);
}
}else{
if( pDb->zBusy ){
Tcl_Free(pDb->zBusy);
pDb->zBusy = 0;
}
if( argv[2][0] ){
pDb->zBusy = Tcl_Alloc( strlen(argv[2]) + 1 );
if( pDb->zBusy ){
strcpy(pDb->zBusy, argv[2]);
}
}
if( pDb->zBusy ){
pDb->interp = interp;
sqlite_busy_handler(pDb->db, DbBusyHandler, pDb);
}
}
}else
/* $db close
**
** Shutdown the database
@ -139,7 +213,7 @@ static int DbCmd(void *cd, Tcl_Interp *interp, int argc, char **argv){
** $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.
** 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.
@ -154,26 +228,43 @@ static int DbCmd(void *cd, Tcl_Interp *interp, int argc, char **argv){
" eval SQL ?ARRAY-NAME CODE?", 0);
return TCL_ERROR;
}
pDb->interp = interp;
if( argc==5 ){
cbData.interp = interp;
cbData.once = 1;
cbData.zArray = argv[3];
cbData.zCode = argv[4];
zErrMsg = 0;
rc = sqlite_exec(db, argv[2], DbEvalCallback, &cbData, &zErrMsg);
rc = sqlite_exec(pDb->db, argv[2], DbEvalCallback, &cbData, &zErrMsg);
}else{
rc = sqlite_exec(db, argv[2], 0, 0, &zErrMsg);
rc = sqlite_exec(pDb->db, argv[2], 0, 0, &zErrMsg);
}
if( zErrMsg ){
Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
free(zErrMsg);
}
return rc;
}
}else
/*
** $db timeout MILLESECONDS
**
** Delay for the number of milliseconds specified when a file is locked.
*/
if( c=='t' && strncmp(z,"timeout",n)==0 ){
int ms;
if( argc!=3 ){
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" timeout MILLISECONDS", 0);
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR;
sqlite_busy_timeout(pDb->db, ms);
}else
/* The default
*/
else{
{
Tcl_AppendResult(interp,"unknown subcommand \"", z,
"\" - should be one of: close complete eval", 0);
return TCL_ERROR;
@ -197,7 +288,7 @@ static int DbCmd(void *cd, Tcl_Interp *interp, int argc, char **argv){
*/
static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
int mode;
sqlite *p;
SqliteDb *p;
char *zErrMsg;
if( argc!=3 && argc!=4 ){
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
@ -210,13 +301,20 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
return TCL_ERROR;
}
zErrMsg = 0;
p = sqlite_open(argv[2], mode, &zErrMsg);
p = Tcl_Alloc( sizeof(*p) );
if( p==0 ){
Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
return TCL_ERROR;
}
memset(p, 0, sizeof(*p));
p->db = sqlite_open(argv[2], mode, &zErrMsg);
if( p->db==0 ){
Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
Tcl_Free((char*)p);
free(zErrMsg);
return TCL_ERROR;
}
Tcl_CreateCommand(interp, argv[1], DbCmd, p, DbDeleteCmd);
Tcl_CreateCommand(interp, argv[1], DbCmd, (char*)p, DbDeleteCmd);
return TCL_OK;
}