aboutsummaryrefslogtreecommitdiff
path: root/src/tclsqlite.c
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2002-09-14 13:47:32 +0000
committerdrh <drh@noemail.net>2002-09-14 13:47:32 +0000
commitcabb0819714a045d8c4c54edc5d8da8d7bdf82a6 (patch)
treeae5e9aefe79ed33c99a736eb6bc920fa67d83078 /src/tclsqlite.c
parent41a3bd0a019aeaf9d4b13777ed9e837b6cf78d80 (diff)
downloadsqlite-cabb0819714a045d8c4c54edc5d8da8d7bdf82a6.tar.gz
sqlite-cabb0819714a045d8c4c54edc5d8da8d7bdf82a6.zip
Do not put a write lock on the main database file when writing to a temporary
table. (CVS 750) FossilOrigin-Name: 3f253afe15d4f7392555f340a41d780d1248087f
Diffstat (limited to 'src/tclsqlite.c')
-rw-r--r--src/tclsqlite.c79
1 files changed, 74 insertions, 5 deletions
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 8fe2ab908..9037bdac6 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -11,7 +11,7 @@
*************************************************************************
** A TCL Interface to SQLite
**
-** $Id: tclsqlite.c,v 1.41 2002/09/03 19:43:24 drh Exp $
+** $Id: tclsqlite.c,v 1.42 2002/09/14 13:47:32 drh Exp $
*/
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
@@ -32,6 +32,17 @@
#endif
/*
+** New SQL functions can be created as TCL scripts. Each such function
+** is described by an instance of the following structure.
+*/
+typedef struct SqlFunc SqlFunc;
+struct SqlFunc {
+ Tcl_Interp *interp; /* The TCL interpret to execute the function */
+ char *zScript; /* The script to be run */
+ SqlFunc *pNext; /* Next function on the list of them all */
+};
+
+/*
** There is one instance of this structure for each SQLite database
** that has been opened by the SQLite TCL interface.
*/
@@ -40,6 +51,7 @@ struct SqliteDb {
sqlite *db; /* The "real" database structure */
Tcl_Interp *interp; /* The interpreter used for this database */
char *zBusy; /* The busy callback routine */
+ SqlFunc *pFunc; /* List of SQL functions */
};
/*
@@ -239,6 +251,11 @@ static int DbEvalCallback2(
static void DbDeleteCmd(void *db){
SqliteDb *pDb = (SqliteDb*)db;
sqlite_close(pDb->db);
+ while( pDb->pFunc ){
+ SqlFunc *pFunc = pDb->pFunc;
+ pDb->pFunc = pFunc->pNext;
+ Tcl_Free((char*)pFunc);
+ }
if( pDb->zBusy ){
Tcl_Free(pDb->zBusy);
}
@@ -271,6 +288,29 @@ static int DbBusyHandler(void *cd, const char *zTable, int nTries){
}
/*
+** This routine is called to evaluate an SQL function implemented
+** using TCL script.
+*/
+static void tclSqlFunc(sqlite_func *context, int argc, const char **argv){
+ SqlFunc *p = sqlite_user_data(context);
+ Tcl_DString cmd;
+ int i;
+ int rc;
+
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, p->zScript, -1);
+ for(i=0; i<argc; i++){
+ Tcl_DStringAppendElement(&cmd, argv[i] ? argv[i] : "");
+ }
+ rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
+ if( rc ){
+ sqlite_set_result_error(context, Tcl_GetStringResult(p->interp), -1);
+ }else{
+ sqlite_set_result_string(context, Tcl_GetStringResult(p->interp), -1);
+ }
+}
+
+/*
** The "sqlite" command below creates a new Tcl command for each
** connection it opens to an SQLite database. This routine is invoked
** whenever one of those connection-specific commands is executed
@@ -288,13 +328,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int choice;
static const char *DB_strs[] = {
"busy", "changes", "close",
- "complete", "eval", "last_insert_rowid",
- "open_aux_file", "timeout", 0
+ "complete", "eval", "function",
+ "last_insert_rowid", "open_aux_file", "timeout",
+ 0
};
enum DB_enum {
DB_BUSY, DB_CHANGES, DB_CLOSE,
- DB_COMPLETE, DB_EVAL, DB_LAST_INSERT_ROWID,
- DB_OPEN_AUX_FILE, DB_TIMEOUT,
+ DB_COMPLETE, DB_EVAL, DB_FUNCTION,
+ DB_LAST_INSERT_ROWID, DB_OPEN_AUX_FILE, DB_TIMEOUT,
};
if( objc<2 ){
@@ -469,6 +510,34 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
+ ** $db function NAME SCRIPT
+ **
+ ** Create a new SQL function called NAME. Whenever that function is
+ ** called, invoke SCRIPT to evaluate the function.
+ */
+ case DB_FUNCTION: {
+ SqlFunc *pFunc;
+ char *zName;
+ char *zScript;
+ int nScript;
+ if( objc!=4 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
+ return TCL_ERROR;
+ }
+ zName = Tcl_GetStringFromObj(objv[2], 0);
+ zScript = Tcl_GetStringFromObj(objv[3], &nScript);
+ pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 );
+ if( pFunc==0 ) return TCL_ERROR;
+ pFunc->interp = interp;
+ pFunc->pNext = pDb->pFunc;
+ pFunc->zScript = (char*)&pFunc[1];
+ strcpy(pFunc->zScript, zScript);
+ sqlite_create_function(pDb->db, zName, -1, tclSqlFunc, pFunc);
+ sqlite_function_type(pDb->db, zName, SQLITE_NUMERIC);
+ break;
+ }
+
+ /*
** $db last_insert_rowid
**
** Return an integer which is the ROWID for the most recent insert.