📄 test8.c
字号:
if( pIdxInfo->nOrderBy==1 && pVtab->aIndex[pIdxInfo->aOrderBy->iColumn] ){ int iCol = pIdxInfo->aOrderBy->iColumn; char *zCol = pVtab->aCol[iCol]; char *zDir = pIdxInfo->aOrderBy->desc?"DESC":"ASC"; if( iCol<0 ){ zCol = "rowid"; } zNew = sqlite3_mprintf(" ORDER BY %s %s", zCol, zDir); string_concat(&zQuery, zNew, 1); pIdxInfo->orderByConsumed = 1; } appendToEchoModule(pVtab->interp, "xBestIndex");; appendToEchoModule(pVtab->interp, zQuery); pIdxInfo->idxNum = hashString(zQuery); pIdxInfo->idxStr = zQuery; pIdxInfo->needToFreeIdxStr = 1; if (useCost) { 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 ); /* 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); bindArgOne = (apData[1] && sqlite3_value_type(apData[1])==SQLITE_INTEGER); bindArgZero = 1; if( bindArgOne ){ string_concat(&z, " SET rowid=?1 ", 0); 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); zSep = ","; } string_concat(&z, sqlite3_mprintf(" WHERE rowid=?%d", nData), 0); } /* 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); 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( sqlite3_value_type(apData[1])==SQLITE_INTEGER ){ bindArgOne = 1; zValues = sqlite3_mprintf("?"); string_concat(&zInsert, "rowid", 0); } assert((pVtab->nCol+2)==nData); for(ii=2; ii<nData; ii++){ string_concat(&zInsert, sqlite3_mprintf("%s%Q", zValues?", ":"", pVtab->aCol[ii-2]), 1); string_concat(&zValues, sqlite3_mprintf("%s?%d", zValues?", ":"", ii), 1); } string_concat(&z, zInsert, 1); string_concat(&z, ") VALUES(", 0); string_concat(&z, zValues, 1); string_concat(&z, ")", 0); } /* Anything else is an error */ else{ assert(0); return SQLITE_ERROR; } 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; i++){ if( apData[i] ) sqlite3_bind_value(pStmt, i, apData[i]); } sqlite3_step(pStmt); rc = sqlite3_finalize(pStmt); } if( pRowid && rc==SQLITE_OK ){ *pRowid = sqlite3_last_insert_rowid(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); appendToEchoModule(pVtab->interp, zCall); appendToEchoModule(pVtab->interp, z); sqlite3_free(z); return SQLITE_OK;}static int echoBegin(sqlite3_vtab *tab){ echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; echoTransactionCall(tab, "xBegin"); /* 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) ){ return SQLITE_ERROR; } return SQLITE_OK;}static int echoSync(sqlite3_vtab *tab){ echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; echoTransactionCall(tab, "xSync"); /* 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) ){ return -1; } return SQLITE_OK;}static int echoCommit(sqlite3_vtab *tab){ return echoTransactionCall(tab, "xCommit");}static int echoRollback(sqlite3_vtab *tab){ return echoTransactionCall(tab, "xRollback");}/*** 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( p->isPattern ){ int nThis = strlen(p->zThis); char *zSql = sqlite3MPrintf("ALTER TABLE %s RENAME TO %s%s", p->zTableName, zNewName, &p->zTableName[nThis] ); rc = sqlite3_exec(p->db, zSql, 0, 0, 0); sqliteFree(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.*/static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){ *ppDb = (sqlite3*)sqlite3TextToPtr(zA); return TCL_OK;}/*** 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; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; sqlite3_create_module(db, "echo", &echoModule, (void *)interp); 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){ static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = {#ifndef SQLITE_OMIT_VIRTUALTABLE { "register_echo_module", register_echo_module, 0 }, { "sqlite3_declare_vtab", declare_vtab, 0 },#endif }; 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); } return TCL_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -