📄 test8.c
字号:
/*** 2006 June 10**** 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.***************************************************************************** Code for testing the virtual table interfaces. This code** is not included in the SQLite library. It is used for automated** testing of the SQLite library.**** $Id: test8.c,v 1.48 2007/07/20 00:35:59 drh Exp $*/#include "sqliteInt.h"#include "tcl.h"#include "os.h"#include <stdlib.h>#include <string.h>#ifndef SQLITE_OMIT_VIRTUALTABLEtypedef struct echo_vtab echo_vtab;typedef struct echo_cursor echo_cursor;/*** The test module defined in this file uses four global Tcl variables to** commicate with test-scripts:**** $::echo_module** $::echo_module_sync_fail** $::echo_module_begin_fail** $::echo_module_cost**** The variable ::echo_module is a list. Each time one of the following** methods is called, one or more elements are appended to the list.** This is used for automated testing of virtual table modules.**** The ::echo_module_sync_fail variable is set by test scripts and read** by code in this file. If it is set to the name of a real table in the** the database, then all xSync operations on echo virtual tables that** use the named table as a backing store will fail.*//* ** An echo virtual-table object.**** echo.vtab.aIndex is an array of booleans. The nth entry is true if ** the nth column of the real table is the left-most column of an index** (implicit or otherwise). In other words, if SQLite can optimize** a query like "SELECT * FROM real_table WHERE col = ?".**** Member variable aCol[] contains copies of the column names of the real** table.*/struct echo_vtab { sqlite3_vtab base; Tcl_Interp *interp; /* Tcl interpreter containing debug variables */ sqlite3 *db; /* Database connection */ int isPattern; char *zThis; /* Name of the echo table */ char *zTableName; /* Name of the real table */ char *zLogName; /* Name of the log table */ int nCol; /* Number of columns in the real table */ int *aIndex; /* Array of size nCol. True if column has an index */ char **aCol; /* Array of size nCol. Column names */};/* An echo cursor object */struct echo_cursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt;};/*** Convert an SQL-style quoted string into a normal string by removing** the quote characters. The conversion is done in-place. If the** input does not begin with a quote character, then this routine** is a no-op.**** Examples:**** "abc" becomes abc** 'xyz' becomes xyz** [pqr] becomes pqr** `mno` becomes mno*/static void dequoteString(char *z){ int quote; int i, j; if( z==0 ) return; quote = z[0]; switch( quote ){ case '\'': break; case '"': break; case '`': break; /* For MySQL compatibility */ case '[': quote = ']'; break; /* For MS SqlServer compatibility */ default: return; } for(i=1, j=0; z[i]; i++){ if( z[i]==quote ){ if( z[i+1]==quote ){ z[j++] = quote; i++; }else{ z[j++] = 0; break; } }else{ z[j++] = z[i]; } }}/*** Retrieve the column names for the table named zTab via database** connection db. SQLITE_OK is returned on success, or an sqlite error** code otherwise.**** If successful, the number of columns is written to *pnCol. *paCol is** set to point at sqliteMalloc()'d space containing the array of** nCol column names. The caller is responsible for calling sqliteFree** on *paCol.*/static int getColumnNames( sqlite3 *db, const char *zTab, char ***paCol, int *pnCol){ char **aCol = 0; char *zSql; sqlite3_stmt *pStmt = 0; int rc = SQLITE_OK; int nCol = 0; /* Prepare the statement "SELECT * FROM <tbl>". The column names ** of the result set of the compiled SELECT will be the same as ** the column names of table <tbl>. */ zSql = sqlite3MPrintf("SELECT * FROM %Q", zTab); if( !zSql ){ rc = SQLITE_NOMEM; goto out; } rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); sqliteFree(zSql); if( rc==SQLITE_OK ){ int ii; int nBytes; char *zSpace; nCol = sqlite3_column_count(pStmt); /* Figure out how much space to allocate for the array of column names ** (including space for the strings themselves). Then allocate it. */ nBytes = sizeof(char *) * nCol; for(ii=0; ii<nCol; ii++){ nBytes += (strlen(sqlite3_column_name(pStmt, ii)) + 1); } aCol = (char **)sqliteMalloc(nBytes); if( !aCol ){ rc = SQLITE_NOMEM; goto out; } /* Copy the column names into the allocated space and set up the ** pointers in the aCol[] array. */ zSpace = (char *)(&aCol[nCol]); for(ii=0; ii<nCol; ii++){ aCol[ii] = zSpace; zSpace += sprintf(zSpace, "%s", sqlite3_column_name(pStmt, ii)); zSpace++; } assert( (zSpace-nBytes)==(char *)aCol ); } *paCol = aCol; *pnCol = nCol;out: sqlite3_finalize(pStmt); return rc;}/*** Parameter zTab is the name of a table in database db with nCol ** columns. This function allocates an array of integers nCol in ** size and populates it according to any implicit or explicit ** indices on table zTab.**** If successful, SQLITE_OK is returned and *paIndex set to point ** at the allocated array. Otherwise, an error code is returned.**** See comments associated with the member variable aIndex above ** "struct echo_vtab" for details of the contents of the array.*/static int getIndexArray( sqlite3 *db, /* Database connection */ const char *zTab, /* Name of table in database db */ int nCol, int **paIndex){ sqlite3_stmt *pStmt = 0; int *aIndex = 0; int rc; char *zSql; /* Allocate space for the index array */ aIndex = (int *)sqliteMalloc(sizeof(int) * nCol); if( !aIndex ){ rc = SQLITE_NOMEM; goto get_index_array_out; } /* Compile an sqlite pragma to loop through all indices on table zTab */ zSql = sqlite3MPrintf("PRAGMA index_list(%s)", zTab); if( !zSql ){ rc = SQLITE_NOMEM; goto get_index_array_out; } rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); sqliteFree(zSql); /* For each index, figure out the left-most column and set the ** corresponding entry in aIndex[] to 1. */ while( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zIdx = (const char *)sqlite3_column_text(pStmt, 1); sqlite3_stmt *pStmt2 = 0; zSql = sqlite3MPrintf("PRAGMA index_info(%s)", zIdx); if( !zSql ){ rc = SQLITE_NOMEM; goto get_index_array_out; } rc = sqlite3_prepare(db, zSql, -1, &pStmt2, 0); sqliteFree(zSql); if( pStmt2 && sqlite3_step(pStmt2)==SQLITE_ROW ){ int cid = sqlite3_column_int(pStmt2, 1); assert( cid>=0 && cid<nCol ); aIndex[cid] = 1; } if( pStmt2 ){ rc = sqlite3_finalize(pStmt2); } if( rc!=SQLITE_OK ){ goto get_index_array_out; } }get_index_array_out: if( pStmt ){ int rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ){ rc = rc2; } } if( rc!=SQLITE_OK ){ sqliteFree(aIndex); aIndex = 0; } *paIndex = aIndex; return rc;}/*** Global Tcl variable $echo_module is a list. This routine appends** the string element zArg to that list in interpreter interp.*/static void appendToEchoModule(Tcl_Interp *interp, const char *zArg){ int flags = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "echo_module", (zArg?zArg:""), flags);}/*** This function is called from within the echo-modules xCreate and** xConnect methods. The argc and argv arguments are copies of those ** passed to the calling method. This function is responsible for** calling sqlite3_declare_vtab() to declare the schema of the virtual** table being created or connected.**** If the constructor was passed just one argument, i.e.:**** CREATE TABLE t1 AS echo(t2);**** Then t2 is assumed to be the name of a *real* database table. The** schema of the virtual table is declared by passing a copy of the ** CREATE TABLE statement for the real table to sqlite3_declare_vtab().** Hence, the virtual table should have exactly the same column names and ** types as the real table.*/static int echoDeclareVtab( echo_vtab *pVtab, sqlite3 *db ){ int rc = SQLITE_OK; if( pVtab->zTableName ){ sqlite3_stmt *pStmt = 0; sqlite3_prepare(db, "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?", -1, &pStmt, 0); sqlite3_bind_text(pStmt, 1, pVtab->zTableName, -1, 0); if( sqlite3_step(pStmt)==SQLITE_ROW ){ int rc2; const char *zCreateTable = (const char *)sqlite3_column_text(pStmt, 0); rc = sqlite3_declare_vtab(db, zCreateTable); rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ){ rc = rc2; } } else { rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ){ rc = SQLITE_ERROR; } } if( rc==SQLITE_OK ){ rc = getColumnNames(db, pVtab->zTableName, &pVtab->aCol, &pVtab->nCol); } if( rc==SQLITE_OK ){ rc = getIndexArray(db, pVtab->zTableName, pVtab->nCol, &pVtab->aIndex); } } return rc;}/*** This function frees all runtime structures associated with the virtual** table pVtab.*/static int echoDestructor(sqlite3_vtab *pVtab){ echo_vtab *p = (echo_vtab*)pVtab; sqliteFree(p->aIndex); sqliteFree(p->aCol); sqliteFree(p->zThis); sqliteFree(p->zTableName); sqliteFree(p->zLogName); sqliteFree(p); return 0;}/*** This function is called to do the work of the xConnect() method -** to allocate the required in-memory structures for a newly connected** virtual table.*/static int echoConstructor( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr){ int i; echo_vtab *pVtab; /* Allocate the sqlite3_vtab/echo_vtab structure itself */ pVtab = sqliteMalloc( sizeof(*pVtab) ); if( !pVtab ){ return SQLITE_NOMEM; } pVtab->interp = (Tcl_Interp *)pAux; pVtab->db = db; /* Allocate echo_vtab.zThis */ pVtab->zThis = sqlite3MPrintf("%s", argv[2]); if( !pVtab->zThis ){ echoDestructor((sqlite3_vtab *)pVtab); return SQLITE_NOMEM; } /* Allocate echo_vtab.zTableName */ if( argc>3 ){ pVtab->zTableName = sqlite3MPrintf("%s", argv[3]); dequoteString(pVtab->zTableName); if( pVtab->zTableName && pVtab->zTableName[0]=='*' ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -