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

📄 tclsqlite.c

📁 sqlite-3.4.1,嵌入式数据库.是一个功能强大的开源数据库,给学习和研发以及小型公司的发展带来了全所未有的好处.
💻 C
📖 第 1 页 / 共 5 页
字号:
/*** 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.  Append this file to sqlite3.c and** compile the whole thing to build a TCL-enabled version of SQLite.**** $Id: tclsqlite.c,v 1.193 2007/06/26 22:55:38 drh Exp $*/#include "tcl.h"#include <errno.h>/*** Some additional include files are needed if this file is not** appended to the amalgamation.*/#ifndef SQLITE_AMALGAMATION# include "sqliteInt.h"# include "hash.h"# include <stdlib.h># include <string.h># include <assert.h># include <ctype.h>#endif/* * Windows needs to know which symbols to export.  Unix does not. * BUILD_sqlite should be undefined for Unix. */#ifdef BUILD_sqlite#undef TCL_STORAGE_CLASS#define TCL_STORAGE_CLASS DLLEXPORT#endif /* BUILD_sqlite */#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 */  Tcl_Obj *pScript;     /* The Tcl_Obj representation of the script */  int useEvalObjv;      /* True if it is safe to use Tcl_EvalObjv */  char *zName;          /* Name of this function */  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 */};typedef struct IncrblobChannel IncrblobChannel;/*** 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. MUST BE FIRST */  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 *zProfile;            /* The profile 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 */  Tcl_Obj *pUpdateHook;      /* Update hook script (if any) */  Tcl_Obj *pRollbackHook;    /* Rollback hook script (if any) */  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 */  IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */};struct IncrblobChannel {  sqlite3_blob *pBlob;      /* sqlite3 blob handle */  SqliteDb *pDb;            /* Associated database connection */  int iSeek;                /* Current seek offset */  Tcl_Channel channel;      /* Channel identifier */  IncrblobChannel *pNext;   /* Linked list of all open incrblob channels */  IncrblobChannel *pPrev;   /* Linked list of all open incrblob channels */};#ifndef SQLITE_OMIT_INCRBLOB/*** Close all incrblob channels opened using database connection pDb.** This is called when shutting down the database connection.*/static void closeIncrblobChannels(SqliteDb *pDb){  IncrblobChannel *p;  IncrblobChannel *pNext;  for(p=pDb->pIncrblob; p; p=pNext){    pNext = p->pNext;    /* Note: Calling unregister here call Tcl_Close on the incrblob channel,     ** which deletes the IncrblobChannel structure at *p. So do not    ** call Tcl_Free() here.    */    Tcl_UnregisterChannel(pDb->interp, p->channel);  }}/*** Close an incremental blob channel.*/static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){  IncrblobChannel *p = (IncrblobChannel *)instanceData;  int rc = sqlite3_blob_close(p->pBlob);  sqlite3 *db = p->pDb->db;  /* Remove the channel from the SqliteDb.pIncrblob list. */  if( p->pNext ){    p->pNext->pPrev = p->pPrev;  }  if( p->pPrev ){    p->pPrev->pNext = p->pNext;  }  if( p->pDb->pIncrblob==p ){    p->pDb->pIncrblob = p->pNext;  }  /* Free the IncrblobChannel structure */  Tcl_Free((char *)p);  if( rc!=SQLITE_OK ){    Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);    return TCL_ERROR;  }  return TCL_OK;}/*** Read data from an incremental blob channel.*/static int incrblobInput(  ClientData instanceData,   char *buf,   int bufSize,  int *errorCodePtr){  IncrblobChannel *p = (IncrblobChannel *)instanceData;  int nRead = bufSize;         /* Number of bytes to read */  int nBlob;                   /* Total size of the blob */  int rc;                      /* sqlite error code */  nBlob = sqlite3_blob_bytes(p->pBlob);  if( (p->iSeek+nRead)>nBlob ){    nRead = nBlob-p->iSeek;  }  if( nRead<=0 ){    return 0;  }  rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek);  if( rc!=SQLITE_OK ){    *errorCodePtr = rc;    return -1;  }  p->iSeek += nRead;  return nRead;}/*** Write data to an incremental blob channel.*/static int incrblobOutput(  ClientData instanceData,   CONST char *buf,   int toWrite,  int *errorCodePtr){  IncrblobChannel *p = (IncrblobChannel *)instanceData;  int nWrite = toWrite;        /* Number of bytes to write */  int nBlob;                   /* Total size of the blob */  int rc;                      /* sqlite error code */  nBlob = sqlite3_blob_bytes(p->pBlob);  if( (p->iSeek+nWrite)>nBlob ){    *errorCodePtr = EINVAL;    return -1;  }  if( nWrite<=0 ){    return 0;  }  rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek);  if( rc!=SQLITE_OK ){    *errorCodePtr = EIO;    return -1;  }  p->iSeek += nWrite;  return nWrite;}/*** Seek an incremental blob channel.*/static int incrblobSeek(  ClientData instanceData,   long offset,  int seekMode,  int *errorCodePtr){  IncrblobChannel *p = (IncrblobChannel *)instanceData;  switch( seekMode ){    case SEEK_SET:      p->iSeek = offset;      break;    case SEEK_CUR:      p->iSeek += offset;      break;    case SEEK_END:      p->iSeek = sqlite3_blob_bytes(p->pBlob) + offset;      break;    default: assert(!"Bad seekMode");  }  return p->iSeek;}static void incrblobWatch(ClientData instanceData, int mode){   /* NO-OP */ }static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){  return TCL_ERROR;}static Tcl_ChannelType IncrblobChannelType = {  "incrblob",                        /* typeName                             */  TCL_CHANNEL_VERSION_2,             /* version                              */  incrblobClose,                     /* closeProc                            */  incrblobInput,                     /* inputProc                            */  incrblobOutput,                    /* outputProc                           */  incrblobSeek,                      /* seekProc                             */  0,                                 /* setOptionProc                        */  0,                                 /* getOptionProc                        */  incrblobWatch,                     /* watchProc (this is a no-op)          */  incrblobHandle,                    /* getHandleProc (always returns error) */  0,                                 /* close2Proc                           */  0,                                 /* blockModeProc                        */  0,                                 /* flushProc                            */  0,                                 /* handlerProc                          */  0,                                 /* wideSeekProc                         */};/*** Create a new incrblob channel.*/static int createIncrblobChannel(  Tcl_Interp *interp,   SqliteDb *pDb,   const char *zDb,  const char *zTable,   const char *zColumn,   sqlite_int64 iRow,  int isReadonly){  IncrblobChannel *p;  sqlite3 *db = pDb->db;  sqlite3_blob *pBlob;  int rc;  int flags = TCL_READABLE|(isReadonly ? 0 : TCL_WRITABLE);  /* This variable is used to name the channels: "incrblob_[incr count]" */  static int count = 0;  char zChannel[64];  rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob);  if( rc!=SQLITE_OK ){    Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);    return TCL_ERROR;  }  p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel));  p->iSeek = 0;  p->pBlob = pBlob;  sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count);  p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags);  Tcl_RegisterChannel(interp, p->channel);  /* Link the new channel into the SqliteDb.pIncrblob list. */  p->pNext = pDb->pIncrblob;  p->pPrev = 0;  if( p->pNext ){    p->pNext->pPrev = p;  }  pDb->pIncrblob = p;  p->pDb = pDb;  Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE);  return TCL_OK;}#else  /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */  #define closeIncrblobChannels(pDb)#endif/*** Look at the script prefix in pCmd.  We will be executing this script** after first appending one or more arguments.  This routine analyzes** the script to see if it is safe to use Tcl_EvalObjv() on the script** rather than the more general Tcl_EvalEx().  Tcl_EvalObjv() is much** faster.**** Scripts that are safe to use with Tcl_EvalObjv() consists of a** command name followed by zero or more arguments with no [...] or $** or {...} or ; to be seen anywhere.  Most callback scripts consist** of just a single procedure name and they meet this requirement.*/static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){  /* We could try to do something with Tcl_Parse().  But we will instead  ** just do a search for forbidden characters.  If any of the forbidden  ** characters appear in pCmd, we will report the string as unsafe.  */  const char *z;  int n;  z = Tcl_GetStringFromObj(pCmd, &n);  while( n-- > 0 ){    int c = *(z++);    if( c=='$' || c=='[' || c==';' ) return 0;  }  return 1;}/*** Find an SqlFunc structure with the given name.  Or create a new** one if an existing one cannot be found.  Return a pointer to the** structure.*/static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){  SqlFunc *p, *pNew;  int i;  pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + strlen(zName) + 1 );  pNew->zName = (char*)&pNew[1];  for(i=0; zName[i]; i++){ pNew->zName[i] = tolower(zName[i]); }  pNew->zName[i] = 0;  for(p=pDb->pFunc; p; p=p->pNext){     if( strcmp(p->zName, pNew->zName)==0 ){      Tcl_Free((char*)pNew);      return p;    }  }  pNew->interp = pDb->interp;  pNew->pScript = 0;  pNew->pNext = pDb->pFunc;  pDb->pFunc = pNew;  return pNew;}/*** 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);

⌨️ 快捷键说明

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