xref: /sqlite-3.40.0/src/test_schema.c (revision 17435752)
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