📄 test8.c
字号:
pIdxInfo->estimatedCost = cost; } else if( useIdx ){ /* Approximation of log2(nRow). */ for( ii=0; ii<(sizeof(int)*8); ii++ ){ if( nRow & (1<<ii) ){ pIdxInfo->estimatedCost = (double)ii; } } } else { pIdxInfo->estimatedCost = (double)nRow; } return rc;}/*** The xUpdate method for echo module virtual tables.** ** apData[0] apData[1] apData[2..]**** INTEGER DELETE **** INTEGER NULL (nCol args) UPDATE (do not set rowid)** INTEGER INTEGER (nCol args) UPDATE (with SET rowid = <arg1>)**** NULL NULL (nCol args) INSERT INTO (automatic rowid value)** NULL INTEGER (nCol args) INSERT (incl. rowid value)***/int echoUpdate( sqlite3_vtab *tab, int nData, sqlite3_value **apData, sqlite_int64 *pRowid){ echo_vtab *pVtab = (echo_vtab *)tab; sqlite3 *db = pVtab->db; int rc = SQLITE_OK; sqlite3_stmt *pStmt; char *z = 0; /* SQL statement to execute */ int bindArgZero = 0; /* True to bind apData[0] to sql var no. nData */ int bindArgOne = 0; /* True to bind apData[1] to sql var no. 1 */ int i; /* Counter variable used by for loops */ assert( nData==pVtab->nCol+2 || nData==1 ); /* Ticket #3083 - make sure we always start a transaction prior to ** making any changes to a virtual table */ assert( pVtab->inTransaction ); if( simulateVtabError(pVtab, "xUpdate") ){ return SQLITE_ERROR; } /* If apData[0] is an integer and nData>1 then do an UPDATE */ if( nData>1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){ char *zSep = " SET"; z = sqlite3_mprintf("UPDATE %Q", pVtab->zTableName); if( !z ){ rc = SQLITE_NOMEM; } bindArgOne = (apData[1] && sqlite3_value_type(apData[1])==SQLITE_INTEGER); bindArgZero = 1; if( bindArgOne ){ string_concat(&z, " SET rowid=?1 ", 0, &rc); zSep = ","; } for(i=2; i<nData; i++){ if( apData[i]==0 ) continue; string_concat(&z, sqlite3_mprintf( "%s %Q=?%d", zSep, pVtab->aCol[i-2], i), 1, &rc); zSep = ","; } string_concat(&z, sqlite3_mprintf(" WHERE rowid=?%d", nData), 1, &rc); } /* If apData[0] is an integer and nData==1 then do a DELETE */ else if( nData==1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){ z = sqlite3_mprintf("DELETE FROM %Q WHERE rowid = ?1", pVtab->zTableName); if( !z ){ rc = SQLITE_NOMEM; } bindArgZero = 1; } /* If the first argument is NULL and there are more than two args, INSERT */ else if( nData>2 && sqlite3_value_type(apData[0])==SQLITE_NULL ){ int ii; char *zInsert = 0; char *zValues = 0; zInsert = sqlite3_mprintf("INSERT INTO %Q (", pVtab->zTableName); if( !zInsert ){ rc = SQLITE_NOMEM; } if( sqlite3_value_type(apData[1])==SQLITE_INTEGER ){ bindArgOne = 1; zValues = sqlite3_mprintf("?"); string_concat(&zInsert, "rowid", 0, &rc); } assert((pVtab->nCol+2)==nData); for(ii=2; ii<nData; ii++){ string_concat(&zInsert, sqlite3_mprintf("%s%Q", zValues?", ":"", pVtab->aCol[ii-2]), 1, &rc); string_concat(&zValues, sqlite3_mprintf("%s?%d", zValues?", ":"", ii), 1, &rc); } string_concat(&z, zInsert, 1, &rc); string_concat(&z, ") VALUES(", 0, &rc); string_concat(&z, zValues, 1, &rc); string_concat(&z, ")", 0, &rc); } /* Anything else is an error */ else{ assert(0); return SQLITE_ERROR; } if( rc==SQLITE_OK ){ rc = sqlite3_prepare(db, z, -1, &pStmt, 0); } assert( rc!=SQLITE_OK || pStmt ); sqlite3_free(z); if( rc==SQLITE_OK ) { if( bindArgZero ){ sqlite3_bind_value(pStmt, nData, apData[0]); } if( bindArgOne ){ sqlite3_bind_value(pStmt, 1, apData[1]); } for(i=2; i<nData && rc==SQLITE_OK; i++){ if( apData[i] ) rc = sqlite3_bind_value(pStmt, i, apData[i]); } if( rc==SQLITE_OK ){ sqlite3_step(pStmt); rc = sqlite3_finalize(pStmt); }else{ sqlite3_finalize(pStmt); } } if( pRowid && rc==SQLITE_OK ){ *pRowid = sqlite3_last_insert_rowid(db); } if( rc!=SQLITE_OK ){ tab->zErrMsg = sqlite3_mprintf("echo-vtab-error: %s", sqlite3_errmsg(db)); } return rc;}/*** xBegin, xSync, xCommit and xRollback callbacks for echo module** virtual tables. Do nothing other than add the name of the callback** to the $::echo_module Tcl variable.*/static int echoTransactionCall(sqlite3_vtab *tab, const char *zCall){ char *z; echo_vtab *pVtab = (echo_vtab *)tab; z = sqlite3_mprintf("echo(%s)", pVtab->zTableName); if( z==0 ) return SQLITE_NOMEM; appendToEchoModule(pVtab->interp, zCall); appendToEchoModule(pVtab->interp, z); sqlite3_free(z); return SQLITE_OK;}static int echoBegin(sqlite3_vtab *tab){ int rc; echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; /* Ticket #3083 - do not start a transaction if we are already in ** a transaction */ assert( !pVtab->inTransaction ); if( simulateVtabError(pVtab, "xBegin") ){ return SQLITE_ERROR; } rc = echoTransactionCall(tab, "xBegin"); if( rc==SQLITE_OK ){ /* Check if the $::echo_module_begin_fail variable is defined. If it is, ** and it is set to the name of the real table underlying this virtual ** echo module table, then cause this xSync operation to fail. */ zVal = Tcl_GetVar(interp, "echo_module_begin_fail", TCL_GLOBAL_ONLY); if( zVal && 0==strcmp(zVal, pVtab->zTableName) ){ rc = SQLITE_ERROR; } } if( rc==SQLITE_OK ){ pVtab->inTransaction = 1; } return rc;}static int echoSync(sqlite3_vtab *tab){ int rc; echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; /* Ticket #3083 - Only call xSync if we have previously started a ** transaction */ assert( pVtab->inTransaction ); if( simulateVtabError(pVtab, "xSync") ){ return SQLITE_ERROR; } rc = echoTransactionCall(tab, "xSync"); if( rc==SQLITE_OK ){ /* Check if the $::echo_module_sync_fail variable is defined. If it is, ** and it is set to the name of the real table underlying this virtual ** echo module table, then cause this xSync operation to fail. */ zVal = Tcl_GetVar(interp, "echo_module_sync_fail", TCL_GLOBAL_ONLY); if( zVal && 0==strcmp(zVal, pVtab->zTableName) ){ rc = -1; } } return rc;}static int echoCommit(sqlite3_vtab *tab){ echo_vtab *pVtab = (echo_vtab*)tab; int rc; /* Ticket #3083 - Only call xCommit if we have previously started ** a transaction */ assert( pVtab->inTransaction ); if( simulateVtabError(pVtab, "xCommit") ){ return SQLITE_ERROR; } sqlite3BeginBenignMalloc(); rc = echoTransactionCall(tab, "xCommit"); sqlite3EndBenignMalloc(); pVtab->inTransaction = 0; return rc;}static int echoRollback(sqlite3_vtab *tab){ int rc; echo_vtab *pVtab = (echo_vtab*)tab; /* Ticket #3083 - Only call xRollback if we have previously started ** a transaction */ assert( pVtab->inTransaction ); rc = echoTransactionCall(tab, "xRollback"); pVtab->inTransaction = 0; return rc;}/*** Implementation of "GLOB" function on the echo module. Pass** all arguments to the ::echo_glob_overload procedure of TCL** and return the result of that procedure as a string.*/static void overloadedGlobFunction( sqlite3_context *pContext, int nArg, sqlite3_value **apArg){ Tcl_Interp *interp = sqlite3_user_data(pContext); Tcl_DString str; int i; int rc; Tcl_DStringInit(&str); Tcl_DStringAppendElement(&str, "::echo_glob_overload"); for(i=0; i<nArg; i++){ Tcl_DStringAppendElement(&str, (char*)sqlite3_value_text(apArg[i])); } rc = Tcl_Eval(interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); if( rc ){ sqlite3_result_error(pContext, Tcl_GetStringResult(interp), -1); }else{ sqlite3_result_text(pContext, Tcl_GetStringResult(interp), -1, SQLITE_TRANSIENT); } Tcl_ResetResult(interp);}/*** This is the xFindFunction implementation for the echo module.** SQLite calls this routine when the first argument of a function** is a column of an echo virtual table. This routine can optionally** override the implementation of that function. It will choose to** do so if the function is named "glob", and a TCL command named** ::echo_glob_overload exists.*/static int echoFindFunction( sqlite3_vtab *vtab, int nArg, const char *zFuncName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg){ echo_vtab *pVtab = (echo_vtab *)vtab; Tcl_Interp *interp = pVtab->interp; Tcl_CmdInfo info; if( strcmp(zFuncName,"glob")!=0 ){ return 0; } if( Tcl_GetCommandInfo(interp, "::echo_glob_overload", &info)==0 ){ return 0; } *pxFunc = overloadedGlobFunction; *ppArg = interp; return 1;}static int echoRename(sqlite3_vtab *vtab, const char *zNewName){ int rc = SQLITE_OK; echo_vtab *p = (echo_vtab *)vtab; if( simulateVtabError(p, "xRename") ){ return SQLITE_ERROR; } if( p->isPattern ){ int nThis = strlen(p->zThis); char *zSql = sqlite3MPrintf(0, "ALTER TABLE %s RENAME TO %s%s", p->zTableName, zNewName, &p->zTableName[nThis] ); rc = sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } return rc;}/*** A virtual table module that merely "echos" the contents of another** table (like an SQL VIEW).*/static sqlite3_module echoModule = { 0, /* iVersion */ echoCreate, echoConnect, echoBestIndex, echoDisconnect, echoDestroy, echoOpen, /* xOpen - open a cursor */ echoClose, /* xClose - close a cursor */ echoFilter, /* xFilter - configure scan constraints */ echoNext, /* xNext - advance a cursor */ echoEof, /* xEof */ echoColumn, /* xColumn - read data */ echoRowid, /* xRowid - read data */ echoUpdate, /* xUpdate - write data */ echoBegin, /* xBegin - begin transaction */ echoSync, /* xSync - sync transaction */ echoCommit, /* xCommit - commit transaction */ echoRollback, /* xRollback - rollback transaction */ echoFindFunction, /* xFindFunction - function overloading */ echoRename, /* xRename - rename the table */};/*** Decode a pointer to an sqlite3 object.*/extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);static void moduleDestroy(void *p){ sqlite3_free(p);}/*** Register the echo virtual table module.*/static int register_echo_module( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */){ sqlite3 *db; EchoModule *pMod; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; sqlite3_create_module_v2(db, "echo", &echoModule, (void*)pMod, moduleDestroy); return TCL_OK;}/*** Tcl interface to sqlite3_declare_vtab, invoked as follows from Tcl:**** sqlite3_declare_vtab DB SQL*/static int declare_vtab( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */){ sqlite3 *db; int rc; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB SQL"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_declare_vtab(db, Tcl_GetString(objv[2])); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); return TCL_ERROR; } return TCL_OK;}#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE *//*** Register commands with the TCL interpreter.*/int Sqlitetest8_Init(Tcl_Interp *interp){#ifndef SQLITE_OMIT_VIRTUALTABLE static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "register_echo_module", register_echo_module, 0 }, { "sqlite3_declare_vtab", declare_vtab, 0 }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, aObjCmd[i].clientData, 0); }#endif return TCL_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -