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

📄 tclsqlite.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
*/static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){  SqliteDb *pDb = (SqliteDb*)cd;  int choice;  int rc = TCL_OK;  static const char *DB_strs[] = {    "authorizer",         "busy",              "cache",    "changes",            "close",             "collate",    "collation_needed",   "commit_hook",       "complete",    "copy",               "errorcode",         "eval",    "function",           "last_insert_rowid", "nullvalue",    "onecolumn",          "progress",          "rekey",    "timeout",            "total_changes",     "trace",    "version",    0                      };  enum DB_enum {    DB_AUTHORIZER,        DB_BUSY,             DB_CACHE,    DB_CHANGES,           DB_CLOSE,            DB_COLLATE,    DB_COLLATION_NEEDED,  DB_COMMIT_HOOK,      DB_COMPLETE,    DB_COPY,              DB_ERRORCODE,        DB_EVAL,    DB_FUNCTION,          DB_LAST_INSERT_ROWID,DB_NULLVALUE,    DB_ONECOLUMN,         DB_PROGRESS,         DB_REKEY,    DB_TIMEOUT,           DB_TOTAL_CHANGES,    DB_TRACE,    DB_VERSION  };  /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */  if( objc<2 ){    Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");    return TCL_ERROR;  }  if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){    return TCL_ERROR;  }  switch( (enum DB_enum)choice ){  /*    $db authorizer ?CALLBACK?  **  ** Invoke the given callback to authorize each SQL operation as it is  ** compiled.  5 arguments are appended to the callback before it is  ** invoked:  **  **   (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...)  **   (2) First descriptive name (depends on authorization type)  **   (3) Second descriptive name  **   (4) Name of the database (ex: "main", "temp")  **   (5) Name of trigger that is doing the access  **  ** The callback should return on of the following strings: SQLITE_OK,  ** SQLITE_IGNORE, or SQLITE_DENY.  Any other return value is an error.  **  ** If this method is invoked with no arguments, the current authorization  ** callback string is returned.  */  case DB_AUTHORIZER: {#ifdef SQLITE_OMIT_AUTHORIZATION    Tcl_AppendResult(interp, "authorization not available in this build", 0);    return TCL_ERROR;#else    if( objc>3 ){      Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");      return TCL_ERROR;    }else if( objc==2 ){      if( pDb->zAuth ){        Tcl_AppendResult(interp, pDb->zAuth, 0);      }    }else{      char *zAuth;      int len;      if( pDb->zAuth ){        Tcl_Free(pDb->zAuth);      }      zAuth = Tcl_GetStringFromObj(objv[2], &len);      if( zAuth && len>0 ){        pDb->zAuth = Tcl_Alloc( len + 1 );        strcpy(pDb->zAuth, zAuth);      }else{        pDb->zAuth = 0;      }      if( pDb->zAuth ){        pDb->interp = interp;        sqlite3_set_authorizer(pDb->db, auth_callback, pDb);      }else{        sqlite3_set_authorizer(pDb->db, 0, 0);      }    }#endif    break;  }  /*    $db busy ?CALLBACK?  **  ** Invoke the given callback if an SQL statement attempts to open  ** a locked database file.  */  case DB_BUSY: {    if( objc>3 ){      Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK");      return TCL_ERROR;    }else if( objc==2 ){      if( pDb->zBusy ){        Tcl_AppendResult(interp, pDb->zBusy, 0);      }    }else{      char *zBusy;      int len;      if( pDb->zBusy ){        Tcl_Free(pDb->zBusy);      }      zBusy = Tcl_GetStringFromObj(objv[2], &len);      if( zBusy && len>0 ){        pDb->zBusy = Tcl_Alloc( len + 1 );        strcpy(pDb->zBusy, zBusy);      }else{        pDb->zBusy = 0;      }      if( pDb->zBusy ){        pDb->interp = interp;        sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb);      }else{        sqlite3_busy_handler(pDb->db, 0, 0);      }    }    break;  }  /*     $db cache flush  **     $db cache size n  **  ** Flush the prepared statement cache, or set the maximum number of  ** cached statements.  */  case DB_CACHE: {    char *subCmd;    int n;    if( objc<=2 ){      Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?");      return TCL_ERROR;    }    subCmd = Tcl_GetStringFromObj( objv[2], 0 );    if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){      if( objc!=3 ){        Tcl_WrongNumArgs(interp, 2, objv, "flush");        return TCL_ERROR;      }else{        flushStmtCache( pDb );      }    }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){      if( objc!=4 ){        Tcl_WrongNumArgs(interp, 2, objv, "size n");        return TCL_ERROR;      }else{        if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){          Tcl_AppendResult( interp, "cannot convert \"",                Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0);          return TCL_ERROR;        }else{          if( n<0 ){            flushStmtCache( pDb );            n = 0;          }else if( n>MAX_PREPARED_STMTS ){            n = MAX_PREPARED_STMTS;          }          pDb->maxStmt = n;        }      }    }else{      Tcl_AppendResult( interp, "bad option \"",           Tcl_GetStringFromObj(objv[0],0), "\": must be flush or size", 0);      return TCL_ERROR;    }    break;  }  /*     $db changes  **  ** Return the number of rows that were modified, inserted, or deleted by  ** the most recent INSERT, UPDATE or DELETE statement, not including   ** any changes made by trigger programs.  */  case DB_CHANGES: {    Tcl_Obj *pResult;    if( objc!=2 ){      Tcl_WrongNumArgs(interp, 2, objv, "");      return TCL_ERROR;    }    pResult = Tcl_GetObjResult(interp);    Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db));    break;  }  /*    $db close  **  ** Shutdown the database  */  case DB_CLOSE: {    Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));    break;  }  /*    $db commit_hook ?CALLBACK?  **  ** Invoke the given callback just before committing every SQL transaction.  ** If the callback throws an exception or returns non-zero, then the  ** transaction is aborted.  If CALLBACK is an empty string, the callback  ** is disabled.  */  case DB_COMMIT_HOOK: {    if( objc>3 ){      Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");      return TCL_ERROR;    }else if( objc==2 ){      if( pDb->zCommit ){        Tcl_AppendResult(interp, pDb->zCommit, 0);      }    }else{      char *zCommit;      int len;      if( pDb->zCommit ){        Tcl_Free(pDb->zCommit);      }      zCommit = Tcl_GetStringFromObj(objv[2], &len);      if( zCommit && len>0 ){        pDb->zCommit = Tcl_Alloc( len + 1 );        strcpy(pDb->zCommit, zCommit);      }else{        pDb->zCommit = 0;      }      if( pDb->zCommit ){        pDb->interp = interp;        sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb);      }else{        sqlite3_commit_hook(pDb->db, 0, 0);      }    }    break;  }  /*  **     $db collate NAME SCRIPT  **  ** Create a new SQL collation function called NAME.  Whenever  ** that function is called, invoke SCRIPT to evaluate the function.  */  case DB_COLLATE: {    SqlCollate *pCollate;    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);    pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );    if( pCollate==0 ) return TCL_ERROR;    pCollate->interp = interp;    pCollate->pNext = pDb->pCollate;    pCollate->zScript = (char*)&pCollate[1];    pDb->pCollate = pCollate;    strcpy(pCollate->zScript, zScript);    if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,         pCollate, tclSqlCollate) ){      Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);      return TCL_ERROR;    }    break;  }  /*  **     $db collation_needed SCRIPT  **  ** Create a new SQL collation function called NAME.  Whenever  ** that function is called, invoke SCRIPT to evaluate the function.  */  case DB_COLLATION_NEEDED: {    if( objc!=3 ){      Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT");      return TCL_ERROR;    }    if( pDb->pCollateNeeded ){      Tcl_DecrRefCount(pDb->pCollateNeeded);    }    pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]);    Tcl_IncrRefCount(pDb->pCollateNeeded);    sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded);    break;  }  /*    $db complete SQL  **  ** Return TRUE if SQL is a complete SQL statement.  Return FALSE if  ** additional lines of input are needed.  This is similar to the  ** built-in "info complete" command of Tcl.  */  case DB_COMPLETE: {#ifndef SQLITE_OMIT_COMPLETE    Tcl_Obj *pResult;    int isComplete;    if( objc!=3 ){      Tcl_WrongNumArgs(interp, 2, objv, "SQL");      return TCL_ERROR;    }    isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) );    pResult = Tcl_GetObjResult(interp);    Tcl_SetBooleanObj(pResult, isComplete);#endif    break;  }  /*  **    $db errorcode  **  ** Return the numeric error code that was returned by the most recent  ** call to sqlite3_exec().  */  case DB_ERRORCODE: {    Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db)));    break;  }     /*  **    $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 */    sqlite3_stmt *pStmt;   /* Compiled SQL statment */    Tcl_Obj *pArray;       /* Name of array into which results are written */    Tcl_Obj *pScript;      /* Script to run for each result set */    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 */    SqlPreparedStmt *pPreStmt;  /* Pointer to a prepared statement */    int rc2;    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;    }else if( objc==4 ){      pArray = 0;      pScript = objv[3];    }else{      pArray = objv[3];      if( Tcl_GetString(pArray)[0]==0 ) pArray = 0;      pScript = objv[4];    }    Tcl_IncrRefCount(objv[2]);    zSql = Tcl_GetStringFromObj(objv[2], 0);    while( rc==TCL_OK && zSql[0] ){      int i;                     /* Loop counter */      int nVar;                  /* Number of bind parameters in the pStmt */      int nCol;                  /* Number of columns in the result set */      Tcl_Obj **apColName = 0;   /* Array of column names */      int len;                   /* String length of zSql */        /* Try to find a SQL statement that has already been compiled and      ** which matches the next sequence of SQL.      */      pStmt = 0;      pPreStmt = pDb->stmtList;      len = strlen(zSql);      if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){        flushStmtCache(pDb);        pPreStmt = 0;      }      for(; pPreStmt; pPreStmt=pPreStmt->pNext){        int n = pPreStmt->nSql;        if( len>=n             && memcmp(pPreStmt->zSql, zSql, n)==0            && (zSql[n]==0 || zSql[n-1]==';')        ){          pStmt = pPreStmt->pStmt;          zLeft = &zSql[pPreStmt->nSql];          /* When a prepared statement is found, unlink it from the          ** cache list.  It will later be added back to the beginning          ** of the cache list in order to implement LRU replacement.          */          if( pPreStmt->pPrev ){            pPreStmt->pPrev->pNext = pPreStmt->pNext;          }else{            pDb->stmtList = pPreStmt->pNext;          }          if( pPreStmt->pNext ){            pPreStmt->pNext->pPrev = pPreStmt->pPrev;          }else{            pDb->stmtLast = pPreStmt->pPrev;          }          pDb->nStmt--;          break;        }      }        /* If no prepared statement was found.  Compile the SQL text      */      if( pStmt==0 ){        if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){          Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));          rc = TCL_ERROR;          break;        }        if( pStmt==0 ){          if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){            /* A compile-time error in the statement            */            Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));            rc = TCL_ERROR;            break;          }else{            /* The statement was a no-op.  Continue to the next statement            ** in the SQL string.            */            zSql = zLeft;            continue;          }        }        assert( pPreStmt==0 );      }      /* Bind values to parameters that begin with $ or :      */        nVar = sqlite3_bind_parameter_count(pStmt);      nParm = 0;      if( nVar>sizeof(aParm)/sizeof(aParm[0]) ){        apParm = (Tcl_Obj**)Tcl_Alloc(nVar*sizeof(apParm[0]));      }else{        apParm = aParm;

⌨️ 快捷键说明

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