📄 test8.c
字号:
char *z = sqlite3MPrintf("%s%s", argv[2], &(pVtab->zTableName[1])); sqliteFree(pVtab->zTableName); pVtab->zTableName = z; pVtab->isPattern = 1; } if( !pVtab->zTableName ){ echoDestructor((sqlite3_vtab *)pVtab); return SQLITE_NOMEM; } } /* Log the arguments to this function to Tcl var ::echo_module */ for(i=0; i<argc; i++){ appendToEchoModule(pVtab->interp, argv[i]); } /* Invoke sqlite3_declare_vtab and set up other members of the echo_vtab ** structure. If an error occurs, delete the sqlite3_vtab structure and ** return an error code. */ if( echoDeclareVtab(pVtab, db) ){ echoDestructor((sqlite3_vtab *)pVtab); return SQLITE_ERROR; } /* Success. Set *ppVtab and return */ *ppVtab = &pVtab->base; return SQLITE_OK;}/* ** Echo virtual table module xCreate method.*/static int echoCreate( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr){ int rc = SQLITE_OK; appendToEchoModule((Tcl_Interp *)(pAux), "xCreate"); rc = echoConstructor(db, pAux, argc, argv, ppVtab, pzErr); /* If there were two arguments passed to the module at the SQL level ** (i.e. "CREATE VIRTUAL TABLE tbl USING echo(arg1, arg2)"), then ** the second argument is used as a table name. Attempt to create ** such a table with a single column, "logmsg". This table will ** be used to log calls to the xUpdate method. It will be deleted ** when the virtual table is DROPed. ** ** Note: The main point of this is to test that we can drop tables ** from within an xDestroy method call. */ if( rc==SQLITE_OK && argc==5 ){ char *zSql; echo_vtab *pVtab = *(echo_vtab **)ppVtab; pVtab->zLogName = sqlite3MPrintf("%s", argv[4]); zSql = sqlite3MPrintf("CREATE TABLE %Q(logmsg)", pVtab->zLogName); rc = sqlite3_exec(db, zSql, 0, 0, 0); sqliteFree(zSql); } return rc;}/* ** Echo virtual table module xConnect method.*/static int echoConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr){ appendToEchoModule((Tcl_Interp *)(pAux), "xConnect"); return echoConstructor(db, pAux, argc, argv, ppVtab, pzErr);}/* ** Echo virtual table module xDisconnect method.*/static int echoDisconnect(sqlite3_vtab *pVtab){ appendToEchoModule(((echo_vtab *)pVtab)->interp, "xDisconnect"); return echoDestructor(pVtab);}/* ** Echo virtual table module xDestroy method.*/static int echoDestroy(sqlite3_vtab *pVtab){ int rc = SQLITE_OK; echo_vtab *p = (echo_vtab *)pVtab; appendToEchoModule(((echo_vtab *)pVtab)->interp, "xDestroy"); /* Drop the "log" table, if one exists (see echoCreate() for details) */ if( p && p->zLogName ){ char *zSql; zSql = sqlite3MPrintf("DROP TABLE %Q", p->zLogName); rc = sqlite3_exec(p->db, zSql, 0, 0, 0); sqliteFree(zSql); } if( rc==SQLITE_OK ){ rc = echoDestructor(pVtab); } return rc;}/* ** Echo virtual table module xOpen method.*/static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ echo_cursor *pCur; pCur = sqliteMalloc(sizeof(echo_cursor)); *ppCursor = (sqlite3_vtab_cursor *)pCur; return (pCur ? SQLITE_OK : SQLITE_NOMEM);}/* ** Echo virtual table module xClose method.*/static int echoClose(sqlite3_vtab_cursor *cur){ int rc; echo_cursor *pCur = (echo_cursor *)cur; sqlite3_stmt *pStmt = pCur->pStmt; pCur->pStmt = 0; sqliteFree(pCur); rc = sqlite3_finalize(pStmt); return rc;}/*** Return non-zero if the cursor does not currently point to a valid record** (i.e if the scan has finished), or zero otherwise.*/static int echoEof(sqlite3_vtab_cursor *cur){ return (((echo_cursor *)cur)->pStmt ? 0 : 1);}/* ** Echo virtual table module xNext method.*/static int echoNext(sqlite3_vtab_cursor *cur){ int rc; echo_cursor *pCur = (echo_cursor *)cur; rc = sqlite3_step(pCur->pStmt); if( rc==SQLITE_ROW ){ rc = SQLITE_OK; }else{ rc = sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0; } return rc;}/* ** Echo virtual table module xColumn method.*/static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ int iCol = i + 1; sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt; if( !pStmt ){ sqlite3_result_null(ctx); }else{ assert( sqlite3_data_count(pStmt)>iCol ); sqlite3_result_value(ctx, sqlite3_column_value(pStmt, iCol)); } return SQLITE_OK;}/* ** Echo virtual table module xRowid method.*/static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt; *pRowid = sqlite3_column_int64(pStmt, 0); return SQLITE_OK;}/*** Compute a simple hash of the null terminated string zString.**** This module uses only sqlite3_index_info.idxStr, not ** sqlite3_index_info.idxNum. So to test idxNum, when idxStr is set** in echoBestIndex(), idxNum is set to the corresponding hash value.** In echoFilter(), code assert()s that the supplied idxNum value is** indeed the hash of the supplied idxStr.*/static int hashString(const char *zString){ int val = 0; int ii; for(ii=0; zString[ii]; ii++){ val = (val << 3) + (int)zString[ii]; } return val;}/* ** Echo virtual table module xFilter method.*/static int echoFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv){ int rc; int i; echo_cursor *pCur = (echo_cursor *)pVtabCursor; echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab; sqlite3 *db = pVtab->db; /* Check that idxNum matches idxStr */ assert( idxNum==hashString(idxStr) ); /* Log arguments to the ::echo_module Tcl variable */ appendToEchoModule(pVtab->interp, "xFilter"); appendToEchoModule(pVtab->interp, idxStr); for(i=0; i<argc; i++){ appendToEchoModule(pVtab->interp, (const char*)sqlite3_value_text(argv[i])); } sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0; /* Prepare the SQL statement created by echoBestIndex and bind the ** runtime parameters passed to this function to it. */ rc = sqlite3_prepare(db, idxStr, -1, &pCur->pStmt, 0); assert( pCur->pStmt || rc!=SQLITE_OK ); for(i=0; rc==SQLITE_OK && i<argc; i++){ sqlite3_bind_value(pCur->pStmt, i+1, argv[i]); } /* If everything was successful, advance to the first row of the scan */ if( rc==SQLITE_OK ){ rc = echoNext(pVtabCursor); } return rc;}/*** A helper function used by echoUpdate() and echoBestIndex() for** manipulating strings in concert with the sqlite3_mprintf() function.**** Parameter pzStr points to a pointer to a string allocated with** sqlite3_mprintf. The second parameter, zAppend, points to another** string. The two strings are concatenated together and *pzStr** set to point at the result. The initial buffer pointed to by *pzStr** is deallocated via sqlite3_free().**** If the third argument, doFree, is true, then sqlite3_free() is** also called to free the buffer pointed to by zAppend.*/static void string_concat(char **pzStr, char *zAppend, int doFree){ char *zIn = *pzStr; if( zIn ){ char *zTemp = zIn; zIn = sqlite3_mprintf("%s%s", zIn, zAppend); sqlite3_free(zTemp); }else{ zIn = sqlite3_mprintf("%s", zAppend); } *pzStr = zIn; if( doFree ){ sqlite3_free(zAppend); }}/*** The echo module implements the subset of query constraints and sort** orders that may take advantage of SQLite indices on the underlying** real table. For example, if the real table is declared as:**** CREATE TABLE real(a, b, c);** CREATE INDEX real_index ON real(b);**** then the echo module handles WHERE or ORDER BY clauses that refer** to the column "b", but not "a" or "c". If a multi-column index is** present, only it's left most column is considered. **** This xBestIndex method encodes the proposed search strategy as** an SQL query on the real table underlying the virtual echo module ** table and stores the query in sqlite3_index_info.idxStr. The SQL** statement is of the form:**** SELECT rowid, * FROM <real-table> ?<where-clause>? ?<order-by-clause>?**** where the <where-clause> and <order-by-clause> are determined** by the contents of the structure pointed to by the pIdxInfo argument.*/static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; char *zQuery = 0; char *zNew; int nArg = 0; const char *zSep = "WHERE"; echo_vtab *pVtab = (echo_vtab *)tab; sqlite3_stmt *pStmt = 0; Tcl_Interp *interp = pVtab->interp; int nRow; int useIdx = 0; int rc = SQLITE_OK; int useCost = 0; double cost; /* Determine the number of rows in the table and store this value in local ** variable nRow. The 'estimated-cost' of the scan will be the number of ** rows in the table for a linear scan, or the log (base 2) of the ** number of rows if the proposed scan uses an index. */ if( Tcl_GetVar(interp, "echo_module_cost", TCL_GLOBAL_ONLY) ){ cost = atof(Tcl_GetVar(interp, "echo_module_cost", TCL_GLOBAL_ONLY)); useCost = 1; } else { zQuery = sqlite3_mprintf("SELECT count(*) FROM %Q", pVtab->zTableName); rc = sqlite3_prepare(pVtab->db, zQuery, -1, &pStmt, 0); sqlite3_free(zQuery); if( rc!=SQLITE_OK ){ return rc; } sqlite3_step(pStmt); nRow = sqlite3_column_int(pStmt, 0); rc = sqlite3_finalize(pStmt); if( rc!=SQLITE_OK ){ return rc; } } zQuery = sqlite3_mprintf("SELECT rowid, * FROM %Q", pVtab->zTableName); for(ii=0; ii<pIdxInfo->nConstraint; ii++){ const struct sqlite3_index_constraint *pConstraint; struct sqlite3_index_constraint_usage *pUsage; int iCol; pConstraint = &pIdxInfo->aConstraint[ii]; pUsage = &pIdxInfo->aConstraintUsage[ii]; iCol = pConstraint->iColumn; if( pVtab->aIndex[iCol] ){ char *zCol = pVtab->aCol[iCol]; char *zOp = 0; useIdx = 1; if( iCol<0 ){ zCol = "rowid"; } switch( pConstraint->op ){ case SQLITE_INDEX_CONSTRAINT_EQ: zOp = "="; break; case SQLITE_INDEX_CONSTRAINT_LT: zOp = "<"; break; case SQLITE_INDEX_CONSTRAINT_GT: zOp = ">"; break; case SQLITE_INDEX_CONSTRAINT_LE: zOp = "<="; break; case SQLITE_INDEX_CONSTRAINT_GE: zOp = ">="; break; case SQLITE_INDEX_CONSTRAINT_MATCH: zOp = "LIKE"; break; } if( zOp[0]=='L' ){ zNew = sqlite3_mprintf(" %s %s LIKE (SELECT '%%'||?||'%%')", zSep, zCol); } else { zNew = sqlite3_mprintf(" %s %s %s ?", zSep, zCol, zOp); } string_concat(&zQuery, zNew, 1); zSep = "AND"; pUsage->argvIndex = ++nArg; pUsage->omit = 1; } } /* If there is only one term in the ORDER BY clause, and it is ** on a column that this virtual table has an index for, then consume ** the ORDER BY clause. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -