⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclsqlite.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*** 2001 September 15**** The author disclaims copyright to this source code.  In place of** a legal notice, here is a blessing:****    May you do good and not evil.**    May you find forgiveness for yourself and forgive others.**    May you share freely, never taking more than you give.***************************************************************************** A TCL Interface to SQLite**** $Id: tclsqlite.c,v 1.125 2005/05/20 09:40:56 danielk1977 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>#include <assert.h>#define NUM_PREPARED_STMTS 10#define MAX_PREPARED_STMTS 100/*** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we** have to do a translation when going between the two.  Set the ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do** this translation.  */#if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8)# define UTF_TRANSLATION_NEEDED 1#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 */};/*** New collation sequences function can be created as TCL scripts.  Each such** function is described by an instance of the following structure.*/typedef struct SqlCollate SqlCollate;struct SqlCollate {  Tcl_Interp *interp;   /* The TCL interpret to execute the function */  char *zScript;        /* The script to be run */  SqlCollate *pNext;       /* Next function on the list of them all */};/*** Prepared statements are cached for faster execution.  Each prepared** statement is described by an instance of the following structure.*/typedef struct SqlPreparedStmt SqlPreparedStmt;struct SqlPreparedStmt {  SqlPreparedStmt *pNext;  /* Next in linked list */  SqlPreparedStmt *pPrev;  /* Previous on the list */  sqlite3_stmt *pStmt;     /* The prepared statement */  int nSql;                /* chars in zSql[] */  char zSql[1];            /* Text of the SQL statement */};/*** 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 {  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 */  char *zTrace;         /* The trace callback routine */  char *zProgress;      /* The progress callback routine */  char *zAuth;          /* The authorization callback routine */  char *zNull;          /* Text to substitute for an SQL NULL value */  SqlFunc *pFunc;       /* List of SQL functions */  SqlCollate *pCollate; /* List of SQL collation functions */  int rc;               /* Return code of most recent sqlite3_exec() */  Tcl_Obj *pCollateNeeded;  /* Collation needed script */  SqlPreparedStmt *stmtList; /* List of prepared statements*/  SqlPreparedStmt *stmtLast; /* Last statement in the list */  int maxStmt;               /* The next maximum number of stmtList */  int nStmt;                 /* Number of statements in stmtList */};/*** Finalize and free a list of prepared statements*/static void flushStmtCache( SqliteDb *pDb ){  SqlPreparedStmt *pPreStmt;  while(  pDb->stmtList ){    sqlite3_finalize( pDb->stmtList->pStmt );    pPreStmt = pDb->stmtList;    pDb->stmtList = pDb->stmtList->pNext;    Tcl_Free( (char*)pPreStmt );  }  pDb->nStmt = 0;  pDb->stmtLast = 0;}/*** TCL calls this procedure when an sqlite3 database command is** deleted.*/static void DbDeleteCmd(void *db){  SqliteDb *pDb = (SqliteDb*)db;  flushStmtCache(pDb);  sqlite3_close(pDb->db);  while( pDb->pFunc ){    SqlFunc *pFunc = pDb->pFunc;    pDb->pFunc = pFunc->pNext;    Tcl_Free((char*)pFunc);  }  while( pDb->pCollate ){    SqlCollate *pCollate = pDb->pCollate;    pDb->pCollate = pCollate->pNext;    Tcl_Free((char*)pCollate);  }  if( pDb->zBusy ){    Tcl_Free(pDb->zBusy);  }  if( pDb->zTrace ){    Tcl_Free(pDb->zTrace);  }  if( pDb->zAuth ){    Tcl_Free(pDb->zAuth);  }  if( pDb->zNull ){    Tcl_Free(pDb->zNull);  }  Tcl_Free((char*)pDb);}/*** This routine is called when a database file is locked while trying** to execute SQL.*/static int DbBusyHandler(void *cd, int nTries){  SqliteDb *pDb = (SqliteDb*)cd;  int rc;  char zVal[30];  char *zCmd;  Tcl_DString cmd;  Tcl_DStringInit(&cmd);  Tcl_DStringAppend(&cmd, pDb->zBusy, -1);  sprintf(zVal, "%d", nTries);  Tcl_DStringAppendElement(&cmd, zVal);  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;}/*** This routine is invoked as the 'progress callback' for the database.*/static int DbProgressHandler(void *cd){  SqliteDb *pDb = (SqliteDb*)cd;  int rc;  assert( pDb->zProgress );  rc = Tcl_Eval(pDb->interp, pDb->zProgress);  if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){    return 1;  }  return 0;}/*** This routine is called by the SQLite trace handler whenever a new** block of SQL is executed.  The TCL script in pDb->zTrace is executed.*/static void DbTraceHandler(void *cd, const char *zSql){  SqliteDb *pDb = (SqliteDb*)cd;  Tcl_DString str;  Tcl_DStringInit(&str);  Tcl_DStringAppend(&str, pDb->zTrace, -1);  Tcl_DStringAppendElement(&str, zSql);  Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));  Tcl_DStringFree(&str);  Tcl_ResetResult(pDb->interp);}/*** This routine is called when a transaction is committed.  The** TCL script in pDb->zCommit is executed.  If it returns non-zero or** if it throws an exception, the transaction is rolled back instead** of being committed.*/static int DbCommitHandler(void *cd){  SqliteDb *pDb = (SqliteDb*)cd;  int rc;  rc = Tcl_Eval(pDb->interp, pDb->zCommit);  if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){    return 1;  }  return 0;}static void tclCollateNeeded(  void *pCtx,  sqlite3 *db,  int enc,  const char *zName){  SqliteDb *pDb = (SqliteDb *)pCtx;  Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded);  Tcl_IncrRefCount(pScript);  Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1));  Tcl_EvalObjEx(pDb->interp, pScript, 0);  Tcl_DecrRefCount(pScript);}/*** This routine is called to evaluate an SQL collation function implemented** using TCL script.*/static int tclSqlCollate(  void *pCtx,  int nA,  const void *zA,  int nB,  const void *zB){  SqlCollate *p = (SqlCollate *)pCtx;  Tcl_Obj *pCmd;  pCmd = Tcl_NewStringObj(p->zScript, -1);  Tcl_IncrRefCount(pCmd);  Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA));  Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB));  Tcl_EvalObjEx(p->interp, pCmd, 0);  Tcl_DecrRefCount(pCmd);  return (atoi(Tcl_GetStringResult(p->interp)));}/*** This routine is called to evaluate an SQL function implemented** using TCL script.*/static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){  SqlFunc *p = sqlite3_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++){    if( SQLITE_NULL==sqlite3_value_type(argv[i]) ){      Tcl_DStringAppendElement(&cmd, "");    }else{      Tcl_DStringAppendElement(&cmd, sqlite3_value_text(argv[i]));    }  }  rc = Tcl_EvalEx(p->interp, Tcl_DStringValue(&cmd), Tcl_DStringLength(&cmd),                  TCL_EVAL_DIRECT);  Tcl_DStringFree(&cmd);  if( rc && rc!=TCL_RETURN ){    sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);   }else{    Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);    int n;    u8 *data;    char *zType = pVar->typePtr ? pVar->typePtr->name : "";    char c = zType[0];    if( c=='b' && strcmp(zType,"bytearray")==0 ){      data = Tcl_GetByteArrayFromObj(pVar, &n);      sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT);    }else if( (c=='b' && strcmp(zType,"boolean")==0) ||          (c=='i' && strcmp(zType,"int")==0) ){      Tcl_GetIntFromObj(0, pVar, &n);      sqlite3_result_int(context, n);    }else if( c=='d' && strcmp(zType,"double")==0 ){      double r;      Tcl_GetDoubleFromObj(0, pVar, &r);      sqlite3_result_double(context, r);    }else{      data = Tcl_GetStringFromObj(pVar, &n);      sqlite3_result_text(context, data, n, SQLITE_TRANSIENT);    }  }}#ifndef SQLITE_OMIT_AUTHORIZATION/*** This is the authentication function.  It appends the authentication** type code and the two arguments to zCmd[] then invokes the result** on the interpreter.  The reply is examined to determine if the** authentication fails or succeeds.*/static int auth_callback(  void *pArg,  int code,  const char *zArg1,  const char *zArg2,  const char *zArg3,  const char *zArg4){  char *zCode;  Tcl_DString str;  int rc;  const char *zReply;  SqliteDb *pDb = (SqliteDb*)pArg;  switch( code ){    case SQLITE_COPY              : zCode="SQLITE_COPY"; break;    case SQLITE_CREATE_INDEX      : zCode="SQLITE_CREATE_INDEX"; break;    case SQLITE_CREATE_TABLE      : zCode="SQLITE_CREATE_TABLE"; break;    case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;    case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;    case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;    case SQLITE_CREATE_TEMP_VIEW  : zCode="SQLITE_CREATE_TEMP_VIEW"; break;    case SQLITE_CREATE_TRIGGER    : zCode="SQLITE_CREATE_TRIGGER"; break;    case SQLITE_CREATE_VIEW       : zCode="SQLITE_CREATE_VIEW"; break;    case SQLITE_DELETE            : zCode="SQLITE_DELETE"; break;    case SQLITE_DROP_INDEX        : zCode="SQLITE_DROP_INDEX"; break;    case SQLITE_DROP_TABLE        : zCode="SQLITE_DROP_TABLE"; break;    case SQLITE_DROP_TEMP_INDEX   : zCode="SQLITE_DROP_TEMP_INDEX"; break;    case SQLITE_DROP_TEMP_TABLE   : zCode="SQLITE_DROP_TEMP_TABLE"; break;    case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;    case SQLITE_DROP_TEMP_VIEW    : zCode="SQLITE_DROP_TEMP_VIEW"; break;    case SQLITE_DROP_TRIGGER      : zCode="SQLITE_DROP_TRIGGER"; break;    case SQLITE_DROP_VIEW         : zCode="SQLITE_DROP_VIEW"; break;    case SQLITE_INSERT            : zCode="SQLITE_INSERT"; break;    case SQLITE_PRAGMA            : zCode="SQLITE_PRAGMA"; break;    case SQLITE_READ              : zCode="SQLITE_READ"; break;    case SQLITE_SELECT            : zCode="SQLITE_SELECT"; break;    case SQLITE_TRANSACTION       : zCode="SQLITE_TRANSACTION"; break;    case SQLITE_UPDATE            : zCode="SQLITE_UPDATE"; break;    case SQLITE_ATTACH            : zCode="SQLITE_ATTACH"; break;    case SQLITE_DETACH            : zCode="SQLITE_DETACH"; break;    case SQLITE_ALTER_TABLE       : zCode="SQLITE_ALTER_TABLE"; break;    case SQLITE_REINDEX           : zCode="SQLITE_REINDEX"; break;    default                       : zCode="????"; break;  }  Tcl_DStringInit(&str);  Tcl_DStringAppend(&str, pDb->zAuth, -1);  Tcl_DStringAppendElement(&str, zCode);  Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");  Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");  Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");  Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");  rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));  Tcl_DStringFree(&str);  zReply = Tcl_GetStringResult(pDb->interp);  if( strcmp(zReply,"SQLITE_OK")==0 ){    rc = SQLITE_OK;  }else if( strcmp(zReply,"SQLITE_DENY")==0 ){    rc = SQLITE_DENY;  }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){    rc = SQLITE_IGNORE;  }else{    rc = 999;  }  return rc;}#endif /* SQLITE_OMIT_AUTHORIZATION *//*** zText is a pointer to text obtained via an sqlite3_result_text()** or similar interface. This routine returns a Tcl string object, ** reference count set to 0, containing the text. If a translation** between iso8859 and UTF-8 is required, it is preformed.*/static Tcl_Obj *dbTextToObj(char const *zText){  Tcl_Obj *pVal;#ifdef UTF_TRANSLATION_NEEDED  Tcl_DString dCol;  Tcl_DStringInit(&dCol);  Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol);  pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);  Tcl_DStringFree(&dCol);#else  pVal = Tcl_NewStringObj(zText, -1);#endif  return pVal;}/*** This routine reads a line of text from FILE in, stores** the text in memory obtained from malloc() and returns a pointer** to the text.  NULL is returned at end of file, or if malloc()** fails.**** The interface is like "readline" but no command-line editing** is done.**** copied from shell.c from '.import' command*/static char *local_getline(char *zPrompt, FILE *in){  char *zLine;  int nLine;  int n;  int eol;  nLine = 100;  zLine = malloc( nLine );  if( zLine==0 ) return 0;  n = 0;  eol = 0;  while( !eol ){    if( n+100>nLine ){      nLine = nLine*2 + 100;      zLine = realloc(zLine, nLine);      if( zLine==0 ) return 0;    }    if( fgets(&zLine[n], nLine - n, in)==0 ){      if( n==0 ){        free(zLine);        return 0;      }      zLine[n] = 0;      eol = 1;      break;    }    while( zLine[n] ){ n++; }    if( n>0 && zLine[n-1]=='\n' ){      n--;      zLine[n] = 0;      eol = 1;    }  }  zLine = realloc( zLine, n+1 );  return zLine;}/*** 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** in Tcl.  For example, if you run Tcl code like this:****       sqlite3 db1  "my_database"**       db1 close**** The first command opens a connection to the "my_database" database** and calls that connection "db1".  The second command causes this** subroutine to be invoked.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -