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