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