modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test_schema.c (about)

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