AryaWu/sqlite
0
1/*2** 2006 June 103**4** The author disclaims copyright to this source code. In place of5** a legal notice, here is a blessing:6**7** May you do good and not evil.8** May you find forgiveness for yourself and forgive others.9** May you share freely, never taking more than you give.10**11*************************************************************************12** Code for testing the virtual table interfaces. This code13** is not included in the SQLite library. It is used for automated14** testing of the SQLite library.15*/16 17/* The code in this file defines a sqlite3 virtual-table module that18** provides a read-only view of the current database schema. There is one19** row in the schema table for each column in the database schema.20*/21#define SCHEMA \22"CREATE TABLE x(" \23 "database," /* Name of database (i.e. main, temp etc.) */ \24 "tablename," /* Name of table */ \25 "cid," /* Column number (from left-to-right, 0 upward) */ \26 "name," /* Column name */ \27 "type," /* Specified type (i.e. VARCHAR(32)) */ \28 "not_null," /* Boolean. True if NOT NULL was specified */ \29 "dflt_value," /* Default value for this column */ \30 "pk" /* True if this column is part of the primary key */ \31")"32 33/* If SQLITE_TEST is defined this code is preprocessed for use as part34** of the sqlite test binary "testfixture". Otherwise it is preprocessed35** to be compiled into an sqlite dynamic extension.36*/37#ifdef SQLITE_TEST38# include "sqliteInt.h"39# include "tclsqlite.h"40#else41# include "sqlite3ext.h"42 SQLITE_EXTENSION_INIT143#endif44 45#include <stdlib.h>46#include <string.h>47#include <assert.h>48 49typedef struct schema_vtab schema_vtab;50typedef struct schema_cursor schema_cursor;51 52/* A schema table object */53struct schema_vtab {54 sqlite3_vtab base;55 sqlite3 *db;56};57 58/* A schema table cursor object */59struct schema_cursor {60 sqlite3_vtab_cursor base;61 sqlite3_stmt *pDbList;62 sqlite3_stmt *pTableList;63 sqlite3_stmt *pColumnList;64 int rowid;65};66 67/*68** None of this works unless we have virtual tables.69*/70#ifndef SQLITE_OMIT_VIRTUALTABLE71 72/*73** Table destructor for the schema module.74*/75static int schemaDestroy(sqlite3_vtab *pVtab){76 sqlite3_free(pVtab);77 return 0;78}79 80/*81** Table constructor for the schema module.82*/83static int schemaCreate(84 sqlite3 *db,85 void *pAux,86 int argc, const char *const*argv,87 sqlite3_vtab **ppVtab,88 char **pzErr89){90 int rc = SQLITE_NOMEM;91 schema_vtab *pVtab = sqlite3_malloc(sizeof(schema_vtab));92 if( pVtab ){93 memset(pVtab, 0, sizeof(schema_vtab));94 pVtab->db = db;95#ifndef SQLITE_OMIT_VIRTUALTABLE96 rc = sqlite3_declare_vtab(db, SCHEMA);97#endif98 }99 *ppVtab = (sqlite3_vtab *)pVtab;100 return rc;101}102 103/*104** Open a new cursor on the schema table.105*/106static int schemaOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){107 int rc = SQLITE_NOMEM;108 schema_cursor *pCur;109 pCur = sqlite3_malloc(sizeof(schema_cursor));110 if( pCur ){111 memset(pCur, 0, sizeof(schema_cursor));112 *ppCursor = (sqlite3_vtab_cursor *)pCur;113 rc = SQLITE_OK;114 }115 return rc;116}117 118/*119** Close a schema table cursor.120*/121static int schemaClose(sqlite3_vtab_cursor *cur){122 schema_cursor *pCur = (schema_cursor *)cur;123 sqlite3_finalize(pCur->pDbList);124 sqlite3_finalize(pCur->pTableList);125 sqlite3_finalize(pCur->pColumnList);126 sqlite3_free(pCur);127 return SQLITE_OK;128}129 130/*131** Retrieve a column of data.132*/133static int schemaColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){134 schema_cursor *pCur = (schema_cursor *)cur;135 switch( i ){136 case 0:137 sqlite3_result_value(ctx, sqlite3_column_value(pCur->pDbList, 1));138 break;139 case 1:140 sqlite3_result_value(ctx, sqlite3_column_value(pCur->pTableList, 0));141 break;142 default:143 sqlite3_result_value(ctx, sqlite3_column_value(pCur->pColumnList, i-2));144 break;145 }146 return SQLITE_OK;147}148 149/*150** Retrieve the current rowid.151*/152static int schemaRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){153 schema_cursor *pCur = (schema_cursor *)cur;154 *pRowid = pCur->rowid;155 return SQLITE_OK;156}157 158static int finalize(sqlite3_stmt **ppStmt){159 int rc = sqlite3_finalize(*ppStmt);160 *ppStmt = 0;161 return rc;162}163 164static int schemaEof(sqlite3_vtab_cursor *cur){165 schema_cursor *pCur = (schema_cursor *)cur;166 return (pCur->pDbList ? 0 : 1);167}168 169/*170** Advance the cursor to the next row.171*/172static int schemaNext(sqlite3_vtab_cursor *cur){173 int rc = SQLITE_OK;174 schema_cursor *pCur = (schema_cursor *)cur;175 schema_vtab *pVtab = (schema_vtab *)(cur->pVtab);176 char *zSql = 0;177 178 while( !pCur->pColumnList || SQLITE_ROW!=sqlite3_step(pCur->pColumnList) ){179 if( SQLITE_OK!=(rc = finalize(&pCur->pColumnList)) ) goto next_exit;180 181 while( !pCur->pTableList || SQLITE_ROW!=sqlite3_step(pCur->pTableList) ){182 if( SQLITE_OK!=(rc = finalize(&pCur->pTableList)) ) goto next_exit;183 184 assert(pCur->pDbList);185 while( SQLITE_ROW!=sqlite3_step(pCur->pDbList) ){186 rc = finalize(&pCur->pDbList);187 goto next_exit;188 }189 190 /* Set zSql to the SQL to pull the list of tables from the 191 ** sqlite_schema (or sqlite_temp_schema) table of the database192 ** identified by the row pointed to by the SQL statement pCur->pDbList193 ** (iterating through a "PRAGMA database_list;" statement).194 */195 if( sqlite3_column_int(pCur->pDbList, 0)==1 ){196 zSql = sqlite3_mprintf(197 "SELECT name FROM sqlite_temp_schema WHERE type='table'"198 );199 }else{200 sqlite3_stmt *pDbList = pCur->pDbList;201 zSql = sqlite3_mprintf(202 "SELECT name FROM %Q.sqlite_schema WHERE type='table'",203 sqlite3_column_text(pDbList, 1)204 );205 }206 if( !zSql ){207 rc = SQLITE_NOMEM;208 goto next_exit;209 }210 211 rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pTableList, 0);212 sqlite3_free(zSql);213 if( rc!=SQLITE_OK ) goto next_exit;214 }215 216 /* Set zSql to the SQL to the table_info pragma for the table currently217 ** identified by the rows pointed to by statements pCur->pDbList and218 ** pCur->pTableList.219 */220 zSql = sqlite3_mprintf("PRAGMA %Q.table_info(%Q)", 221 sqlite3_column_text(pCur->pDbList, 1),222 sqlite3_column_text(pCur->pTableList, 0)223 );224 225 if( !zSql ){226 rc = SQLITE_NOMEM;227 goto next_exit;228 }229 rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pColumnList, 0);230 sqlite3_free(zSql);231 if( rc!=SQLITE_OK ) goto next_exit;232 }233 pCur->rowid++;234 235next_exit:236 /* TODO: Handle rc */237 return rc;238}239 240/*241** Reset a schema table cursor.242*/243static int schemaFilter(244 sqlite3_vtab_cursor *pVtabCursor, 245 int idxNum, const char *idxStr,246 int argc, sqlite3_value **argv247){248 int rc;249 schema_vtab *pVtab = (schema_vtab *)(pVtabCursor->pVtab);250 schema_cursor *pCur = (schema_cursor *)pVtabCursor;251 pCur->rowid = 0;252 finalize(&pCur->pTableList);253 finalize(&pCur->pColumnList);254 finalize(&pCur->pDbList);255 rc = sqlite3_prepare(pVtab->db,"PRAGMA database_list", -1, &pCur->pDbList, 0);256 return (rc==SQLITE_OK ? schemaNext(pVtabCursor) : rc);257}258 259/*260** Analyse the WHERE condition.261*/262static int schemaBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){263 return SQLITE_OK;264}265 266/*267** A virtual table module that merely echos method calls into TCL268** variables.269*/270static sqlite3_module schemaModule = {271 0, /* iVersion */272 schemaCreate,273 schemaCreate,274 schemaBestIndex,275 schemaDestroy,276 schemaDestroy,277 schemaOpen, /* xOpen - open a cursor */278 schemaClose, /* xClose - close a cursor */279 schemaFilter, /* xFilter - configure scan constraints */280 schemaNext, /* xNext - advance a cursor */281 schemaEof, /* xEof */282 schemaColumn, /* xColumn - read data */283 schemaRowid, /* xRowid - read data */284 0, /* xUpdate */285 0, /* xBegin */286 0, /* xSync */287 0, /* xCommit */288 0, /* xRollback */289 0, /* xFindMethod */290 0, /* xRename */291 0, /* xSavepoint */292 0, /* xRelease */293 0, /* xRollbackTo */294 0, /* xShadowName */295 0 /* xIntegrity */296};297 298#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */299 300#ifdef SQLITE_TEST301 302/*303** Decode a pointer to an sqlite3 object.304*/305extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);306 307/*308** Register the schema virtual table module.309*/310static int SQLITE_TCLAPI register_schema_module(311 ClientData clientData, /* Not used */312 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */313 int objc, /* Number of arguments */314 Tcl_Obj *CONST objv[] /* Command arguments */315){316 sqlite3 *db;317 if( objc!=2 ){318 Tcl_WrongNumArgs(interp, 1, objv, "DB");319 return TCL_ERROR;320 }321 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;322#ifndef SQLITE_OMIT_VIRTUALTABLE323 sqlite3_create_module(db, "schema", &schemaModule, 0);324#endif325 return TCL_OK;326}327 328/*329** Register commands with the TCL interpreter.330*/331int Sqlitetestschema_Init(Tcl_Interp *interp){332 static struct {333 char *zName;334 Tcl_ObjCmdProc *xProc;335 void *clientData;336 } aObjCmd[] = {337 { "register_schema_module", register_schema_module, 0 },338 };339 int i;340 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){341 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 342 aObjCmd[i].xProc, aObjCmd[i].clientData, 0);343 }344 return TCL_OK;345}346 347#else348 349/*350** Extension load function.351*/352#ifdef _WIN32353__declspec(dllexport)354#endif355int sqlite3_schema_init(356 sqlite3 *db, 357 char **pzErrMsg, 358 const sqlite3_api_routines *pApi359){360 SQLITE_EXTENSION_INIT2(pApi);361#ifndef SQLITE_OMIT_VIRTUALTABLE362 sqlite3_create_module(db, "schema", &schemaModule, 0);363#endif364 return 0;365}366 367#endif368 