persistentstorage/sqlite3api/TEST/SRC/test_schema.c
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     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