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.15 2008/07/07 14:50:14 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 ** None of this works unless we have virtual tables. 71 */ 72 #ifndef SQLITE_OMIT_VIRTUALTABLE 73 74 /* 75 ** Table destructor for the schema module. 76 */ 77 static int schemaDestroy(sqlite3_vtab *pVtab){ 78 sqlite3_free(pVtab); 79 return 0; 80 } 81 82 /* 83 ** Table constructor for the schema module. 84 */ 85 static int schemaCreate( 86 sqlite3 *db, 87 void *pAux, 88 int argc, const char *const*argv, 89 sqlite3_vtab **ppVtab, 90 char **pzErr 91 ){ 92 int rc = SQLITE_NOMEM; 93 schema_vtab *pVtab = sqlite3_malloc(sizeof(schema_vtab)); 94 if( pVtab ){ 95 memset(pVtab, 0, sizeof(schema_vtab)); 96 pVtab->db = db; 97 #ifndef SQLITE_OMIT_VIRTUALTABLE 98 rc = sqlite3_declare_vtab(db, SCHEMA); 99 #endif 100 } 101 *ppVtab = (sqlite3_vtab *)pVtab; 102 return rc; 103 } 104 105 /* 106 ** Open a new cursor on the schema table. 107 */ 108 static int schemaOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ 109 int rc = SQLITE_NOMEM; 110 schema_cursor *pCur; 111 pCur = sqlite3_malloc(sizeof(schema_cursor)); 112 if( pCur ){ 113 memset(pCur, 0, sizeof(schema_cursor)); 114 *ppCursor = (sqlite3_vtab_cursor *)pCur; 115 rc = SQLITE_OK; 116 } 117 return rc; 118 } 119 120 /* 121 ** Close a schema table cursor. 122 */ 123 static int schemaClose(sqlite3_vtab_cursor *cur){ 124 schema_cursor *pCur = (schema_cursor *)cur; 125 sqlite3_finalize(pCur->pDbList); 126 sqlite3_finalize(pCur->pTableList); 127 sqlite3_finalize(pCur->pColumnList); 128 sqlite3_free(pCur); 129 return SQLITE_OK; 130 } 131 132 /* 133 ** Retrieve a column of data. 134 */ 135 static int schemaColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ 136 schema_cursor *pCur = (schema_cursor *)cur; 137 switch( i ){ 138 case 0: 139 sqlite3_result_value(ctx, sqlite3_column_value(pCur->pDbList, 1)); 140 break; 141 case 1: 142 sqlite3_result_value(ctx, sqlite3_column_value(pCur->pTableList, 0)); 143 break; 144 default: 145 sqlite3_result_value(ctx, sqlite3_column_value(pCur->pColumnList, i-2)); 146 break; 147 } 148 return SQLITE_OK; 149 } 150 151 /* 152 ** Retrieve the current rowid. 153 */ 154 static int schemaRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ 155 schema_cursor *pCur = (schema_cursor *)cur; 156 *pRowid = pCur->rowid; 157 return SQLITE_OK; 158 } 159 160 static int finalize(sqlite3_stmt **ppStmt){ 161 int rc = sqlite3_finalize(*ppStmt); 162 *ppStmt = 0; 163 return rc; 164 } 165 166 static int schemaEof(sqlite3_vtab_cursor *cur){ 167 schema_cursor *pCur = (schema_cursor *)cur; 168 return (pCur->pDbList ? 0 : 1); 169 } 170 171 /* 172 ** Advance the cursor to the next row. 173 */ 174 static int schemaNext(sqlite3_vtab_cursor *cur){ 175 int rc = SQLITE_OK; 176 schema_cursor *pCur = (schema_cursor *)cur; 177 schema_vtab *pVtab = (schema_vtab *)(cur->pVtab); 178 char *zSql = 0; 179 180 while( !pCur->pColumnList || SQLITE_ROW!=sqlite3_step(pCur->pColumnList) ){ 181 if( SQLITE_OK!=(rc = finalize(&pCur->pColumnList)) ) goto next_exit; 182 183 while( !pCur->pTableList || SQLITE_ROW!=sqlite3_step(pCur->pTableList) ){ 184 if( SQLITE_OK!=(rc = finalize(&pCur->pTableList)) ) goto next_exit; 185 186 assert(pCur->pDbList); 187 while( SQLITE_ROW!=sqlite3_step(pCur->pDbList) ){ 188 rc = finalize(&pCur->pDbList); 189 goto next_exit; 190 } 191 192 /* Set zSql to the SQL to pull the list of tables from the 193 ** sqlite_master (or sqlite_temp_master) table of the database 194 ** identfied by the row pointed to by the SQL statement pCur->pDbList 195 ** (iterating through a "PRAGMA database_list;" statement). 196 */ 197 if( sqlite3_column_int(pCur->pDbList, 0)==1 ){ 198 zSql = sqlite3_mprintf( 199 "SELECT name FROM sqlite_temp_master WHERE type='table'" 200 ); 201 }else{ 202 sqlite3_stmt *pDbList = pCur->pDbList; 203 zSql = sqlite3_mprintf( 204 "SELECT name FROM %Q.sqlite_master WHERE type='table'", 205 sqlite3_column_text(pDbList, 1) 206 ); 207 } 208 if( !zSql ){ 209 rc = SQLITE_NOMEM; 210 goto next_exit; 211 } 212 213 rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pTableList, 0); 214 sqlite3_free(zSql); 215 if( rc!=SQLITE_OK ) goto next_exit; 216 } 217 218 /* Set zSql to the SQL to the table_info pragma for the table currently 219 ** identified by the rows pointed to by statements pCur->pDbList and 220 ** pCur->pTableList. 221 */ 222 zSql = sqlite3_mprintf("PRAGMA %Q.table_info(%Q)", 223 sqlite3_column_text(pCur->pDbList, 1), 224 sqlite3_column_text(pCur->pTableList, 0) 225 ); 226 227 if( !zSql ){ 228 rc = SQLITE_NOMEM; 229 goto next_exit; 230 } 231 rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pColumnList, 0); 232 sqlite3_free(zSql); 233 if( rc!=SQLITE_OK ) goto next_exit; 234 } 235 pCur->rowid++; 236 237 next_exit: 238 /* TODO: Handle rc */ 239 return rc; 240 } 241 242 /* 243 ** Reset a schema table cursor. 244 */ 245 static int schemaFilter( 246 sqlite3_vtab_cursor *pVtabCursor, 247 int idxNum, const char *idxStr, 248 int argc, sqlite3_value **argv 249 ){ 250 int rc; 251 schema_vtab *pVtab = (schema_vtab *)(pVtabCursor->pVtab); 252 schema_cursor *pCur = (schema_cursor *)pVtabCursor; 253 pCur->rowid = 0; 254 finalize(&pCur->pTableList); 255 finalize(&pCur->pColumnList); 256 finalize(&pCur->pDbList); 257 rc = sqlite3_prepare(pVtab->db,"PRAGMA database_list", -1, &pCur->pDbList, 0); 258 return (rc==SQLITE_OK ? schemaNext(pVtabCursor) : rc); 259 } 260 261 /* 262 ** Analyse the WHERE condition. 263 */ 264 static int schemaBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 265 return SQLITE_OK; 266 } 267 268 /* 269 ** A virtual table module that merely echos method calls into TCL 270 ** variables. 271 */ 272 static sqlite3_module schemaModule = { 273 0, /* iVersion */ 274 schemaCreate, 275 schemaCreate, 276 schemaBestIndex, 277 schemaDestroy, 278 schemaDestroy, 279 schemaOpen, /* xOpen - open a cursor */ 280 schemaClose, /* xClose - close a cursor */ 281 schemaFilter, /* xFilter - configure scan constraints */ 282 schemaNext, /* xNext - advance a cursor */ 283 schemaEof, /* xEof */ 284 schemaColumn, /* xColumn - read data */ 285 schemaRowid, /* xRowid - read data */ 286 0, /* xUpdate */ 287 0, /* xBegin */ 288 0, /* xSync */ 289 0, /* xCommit */ 290 0, /* xRollback */ 291 0, /* xFindMethod */ 292 0, /* xRename */ 293 }; 294 295 #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ 296 297 #ifdef SQLITE_TEST 298 299 /* 300 ** Decode a pointer to an sqlite3 object. 301 */ 302 extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); 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