]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add test_schema.c, containing a module for viewing the database schema via a virtual...
authordanielk1977 <danielk1977@noemail.net>
Thu, 15 Jun 2006 15:59:19 +0000 (15:59 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Thu, 15 Jun 2006 15:59:19 +0000 (15:59 +0000)
FossilOrigin-Name: de8d32ac71a6e113e83b952813424cb3fb5a2e59

Makefile.in
main.mk
manifest
manifest.uuid
src/tclsqlite.c
src/test_schema.c [new file with mode: 0644]

index 706246e062acbe8d05882ab3e81dafb507ac60f9..90fc1c2dd25b819e87718eb8ee652fc6ac39bb90 100644 (file)
@@ -210,6 +210,7 @@ TESTSRC = \
   $(TOP)/src/test8.c \
   $(TOP)/src/test_async.c \
   $(TOP)/src/test_md5.c \
+  $(TOP)/src/test_schema.c \
   $(TOP)/src/test_server.c \
   $(TOP)/src/test_tclvar.c \
   $(TOP)/src/utf.c \
diff --git a/main.mk b/main.mk
index 1691de31466bd3da62c497dfb7d47a45526b4715..05a53dd0d360ab8bad067680da74df32d23e2b5a 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -143,6 +143,7 @@ TESTSRC = \
   $(TOP)/src/test8.c \
   $(TOP)/src/test_async.c \
   $(TOP)/src/test_md5.c \
+  $(TOP)/src/test_schema.c \
   $(TOP)/src/test_server.c \
   $(TOP)/src/test_tclvar.c \
   $(TOP)/src/utf.c \
index f482728c418eb0d61f57f538ad6374b3059664da..8c806f035f307107fa2bcc66bc289ad3f27148f6 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,6 +1,6 @@
-C Add\scolumn_value,\sdeclare_vtab\sand\screate_module\sto\sthe\sfunction\stable\sused\sby\sdynamic\sextensions.\s(CVS\s3256)
-D 2006-06-15T15:38:42
-F Makefile.in 200f6dc376ecfd9b01e5359c4e0c10c02f649b34
+C Add\stest_schema.c,\scontaining\sa\smodule\sfor\sviewing\sthe\sdatabase\sschema\svia\sa\svirtual\stable.\s(CVS\s3257)
+D 2006-06-15T15:59:19
+F Makefile.in f839b470345d3cb4b0644068474623fe2464b5d3
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
 F VERSION 301ed2b2c08f5cca242ea56e50a9ed0264a3eb76
@@ -19,7 +19,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826
-F main.mk 3fe86a381432abf3ba96d0276ea85618bcf9e5a1
+F main.mk 5dbef60b29006c0bc3fd9ce78c846f38750302e2
 F mkdll.sh 919df5efde876194e3102c6ebc60657d38949909
 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
 F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5
@@ -76,7 +76,7 @@ F src/sqlite.h.in 1dc44da025da28a011d11ad1608c11a951047fab
 F src/sqlite3ext.h fc8647211af0caa9d8e49ab31624b357c1332380
 F src/sqliteInt.h 5eb64f1dd9a8b237d147962bc57637d87e044ff4
 F src/table.c f64ec4fbfe333f8df925bc6ba494f55e05b0e75e
-F src/tclsqlite.c 4ad22f354b6e4e137889000e9f585a0590ca39c5
+F src/tclsqlite.c c03bf44bd9f629d4c8d6545788c647b2e846b523
 F src/test1.c 40f20775903bc76d3be3e7c026dddcbc221c1cb0
 F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b
 F src/test3.c 86e99724ee898b119ed575ef9f98618afe7e5e5d
@@ -88,6 +88,7 @@ F src/test8.c 9579de4645c9b8be3f8de217224bcf9280da9b6a
 F src/test_async.c e3deaedd4d86a56391b81808fde9e44fbd92f1d3
 F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8
 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3
+F src/test_schema.c 533a9ed125a4676a22a20d9e87e6379989d901e9
 F src/test_server.c a6460daed0b92ecbc2531b6dc73717470e7a648c
 F src/test_tclvar.c c52f67fbe06d32804af2ba9a2d7aadfc15f5910c
 F src/tokenize.c 6ebcafa6622839968dda4418a7b6945f277a128f
@@ -366,7 +367,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P fe3e70a7275d68acb6fb8ea5d62bed3e9d8d2766
-R 47a8b2f6537c22850ce9af0f2e0f04a2
+P 25c475087892fea83bce9d140b46651793b85a86
+R fb8cae10b8c9b6f899ced712e7826fd2
 U danielk1977
-Z ec60b2bf5c12236743a6bbfcf541f438
+Z 593d3f2a16cc3c6c0ea1ba4705d0de74
index 11aca19e88b53c89e798685494c1d7dbbd797842..fa97314ddaaa8a807b22fb7f83d1e300b47fceaa 100644 (file)
@@ -1 +1 @@
-25c475087892fea83bce9d140b46651793b85a86
\ No newline at end of file
+de8d32ac71a6e113e83b952813424cb3fb5a2e59
\ No newline at end of file
index 9c3890b99af6375f40f66264ebcf32f7def48b89..f988926f423a0545fa4412d19518375cf145decf 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** A TCL Interface to SQLite
 **
-** $Id: tclsqlite.c,v 1.158 2006/06/13 23:51:35 drh Exp $
+** $Id: tclsqlite.c,v 1.159 2006/06/15 15:59:20 danielk1977 Exp $
 */
 #ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */
 
@@ -2156,6 +2156,7 @@ int TCLSH_MAIN(int argc, char **argv){
     extern int Sqlitetestsse_Init(Tcl_Interp*);
     extern int Sqlitetestasync_Init(Tcl_Interp*);
     extern int Sqlitetesttclvar_Init(Tcl_Interp*);
+    extern int Sqlitetestschema_Init(Tcl_Interp*);
 
     Sqlitetest1_Init(interp);
     Sqlitetest2_Init(interp);
@@ -2167,6 +2168,7 @@ int TCLSH_MAIN(int argc, char **argv){
     Sqlitetest8_Init(interp);
     Sqlitetestasync_Init(interp);
     Sqlitetesttclvar_Init(interp);
+    Sqlitetestschema_Init(interp);
     Md5_Init(interp);
 #ifdef SQLITE_SSE
     Sqlitetestsse_Init(interp);
diff --git a/src/test_schema.c b/src/test_schema.c
new file mode 100644 (file)
index 0000000..85a75f1
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+** 2006 June 10
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** Code for testing the virtual table interfaces.  This code
+** is not included in the SQLite library.  It is used for automated
+** testing of the SQLite library.
+**
+** $Id: test_schema.c,v 1.1 2006/06/15 15:59:20 danielk1977 Exp $
+*/
+
+/* The code in this file defines a sqlite3 module that provides
+** a read-only view of the current database schema. There is one
+** row in the schema table for each column in the database.
+*/
+#define SCHEMA \
+"CREATE TABLE x("                                                            \
+  "database,"          /* Name of database (i.e. main, temp etc.) */         \
+  "tablename,"         /* Name of table */                                   \
+  "cid,"               /* Column number (from left-to-right, 0 upward) */    \
+  "name,"              /* Column name */                                     \
+  "type,"              /* Specified type (i.e. VARCHAR(32)) */               \
+  "not_null,"          /* Boolean. True if NOT NULL was specified */         \
+  "dflt_value,"        /* Default value for this column */                   \
+  "pk"                 /* True if this column is part of the primary key */  \
+")"
+
+/* If SQLITE_TEST is defined this code is preprocessed for use as part
+** of the sqlite test binary "testfixture". Otherwise it is preprocessed
+** to be compiled into an sqlite dynamic extension.
+*/
+#ifdef SQLITE_TEST
+  #include "sqliteInt.h"
+  #include "tcl.h"
+  #define MALLOC(x) sqliteRawMalloc(x) 
+  #define FREE(x)   sqliteFree(x)
+#else
+  #include "sqlite3ext.h"
+  SQLITE_EXTENSION_INIT1
+  #define MALLOC(x) malloc(x) 
+  #define FREE(x)   free(x)
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+typedef struct schema_vtab schema_vtab;
+typedef struct schema_cursor schema_cursor;
+
+/* A schema table object */
+struct schema_vtab {
+  sqlite3_vtab base;
+  sqlite3 *db;
+};
+
+/* A schema table cursor object */
+struct schema_cursor {
+  sqlite3_vtab_cursor base;
+  sqlite3_stmt *pDbList;
+  sqlite3_stmt *pTableList;
+  sqlite3_stmt *pColumnList;
+  int rowid;
+};
+
+/*
+** Table destructor for the schema module.
+*/
+static int schemaDestroy(sqlite3_vtab *pVtab){
+  FREE(pVtab);
+  return 0;
+}
+
+/*
+** Table constructor for the schema module.
+*/
+static int schemaCreate(
+  sqlite3 *db,
+  void *pAux,
+  int argc, char **argv,
+  sqlite3_vtab **ppVtab
+){
+  int rc = SQLITE_NOMEM;
+  schema_vtab *pVtab = MALLOC(sizeof(schema_vtab));
+  if( pVtab ){
+    memset(pVtab, 0, sizeof(schema_vtab));
+    pVtab->db = db;
+    rc = sqlite3_declare_vtab(db, SCHEMA);
+  }
+  *ppVtab = (sqlite3_vtab *)pVtab;
+  return rc;
+}
+
+/*
+** Open a new cursor on the schema table.
+*/
+static int schemaOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+  int rc = SQLITE_NOMEM;
+  schema_cursor *pCur;
+  pCur = MALLOC(sizeof(schema_cursor));
+  if( pCur ){
+    memset(pCur, 0, sizeof(schema_cursor));
+    *ppCursor = (sqlite3_vtab_cursor *)pCur;
+    rc = SQLITE_OK;
+  }
+  return rc;
+}
+
+/*
+** Close a schema table cursor.
+*/
+static int schemaClose(sqlite3_vtab_cursor *cur){
+  schema_cursor *pCur = (schema_cursor *)cur;
+  sqlite3_finalize(pCur->pDbList);
+  sqlite3_finalize(pCur->pTableList);
+  sqlite3_finalize(pCur->pColumnList);
+  FREE(pCur);
+  return SQLITE_OK;
+}
+
+/*
+** Retrieve a column of data.
+*/
+static int schemaColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
+  schema_cursor *pCur = (schema_cursor *)cur;
+  switch( i ){
+    case 0:
+      sqlite3_result_value(ctx, sqlite3_column_value(pCur->pDbList, 1));
+      break;
+    case 1:
+      sqlite3_result_value(ctx, sqlite3_column_value(pCur->pTableList, 0));
+      break;
+    default:
+      sqlite3_result_value(ctx, sqlite3_column_value(pCur->pColumnList, i-2));
+      break;
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Retrieve the current rowid.
+*/
+static int schemaRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+  schema_cursor *pCur = (schema_cursor *)cur;
+  *pRowid = pCur->rowid;
+  return SQLITE_OK;
+}
+
+static int finalize(sqlite3_stmt **ppStmt){
+  int rc = sqlite3_finalize(*ppStmt);
+  *ppStmt = 0;
+  return rc;
+}
+
+/*
+** Advance the cursor to the next row.
+*/
+static int schemaNext(sqlite3_vtab_cursor *cur){
+  int rc;
+  schema_cursor *pCur = (schema_cursor *)cur;
+  schema_vtab *pVtab = (schema_vtab *)(cur->pVtab);
+  char *zSql = 0;
+
+  while( !pCur->pColumnList || SQLITE_ROW!=sqlite3_step(pCur->pColumnList) ){
+    if( SQLITE_OK!=(rc = finalize(&pCur->pColumnList)) ) goto fail;
+
+    while( !pCur->pTableList || SQLITE_ROW!=sqlite3_step(pCur->pTableList) ){
+      if( SQLITE_OK!=(rc = finalize(&pCur->pTableList)) ) goto fail;
+
+      assert(pCur->pDbList);
+      while( SQLITE_ROW!=sqlite3_step(pCur->pDbList) ){
+        if( SQLITE_OK!=(rc = finalize(&pCur->pDbList)) ) goto fail;
+        return 0;
+      }
+
+      /* Set zSql to the SQL to pull the list of tables from the 
+      ** sqlite_master (or sqlite_temp_master) table of the database
+      ** identfied by the row pointed to by the SQL statement pCur->pDbList
+      ** (iterating through a "PRAGMA database_list;" statement).
+      */
+      if( sqlite3_column_int(pCur->pDbList, 0)==1 ){
+        zSql = sqlite3_mprintf(
+            "SELECT name FROM sqlite_temp_master WHERE type='table'"
+        );
+      }else{
+        sqlite3_stmt *pDbList = pCur->pDbList;
+        zSql = sqlite3_mprintf(
+            "SELECT name FROM %Q.sqlite_master WHERE type='table'",
+             sqlite3_column_text(pDbList, 1)
+        );
+      }
+      if( !zSql ){
+        rc = SQLITE_NOMEM;
+        goto fail;
+      }
+
+      rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pTableList, 0);
+      sqlite3_free(zSql);
+      if( rc!=SQLITE_OK ) goto fail;
+    }
+
+    /* Set zSql to the SQL to the table_info pragma for the table currently
+    ** identified by the rows pointed to by statements pCur->pDbList and
+    ** pCur->pTableList.
+    */
+    zSql = sqlite3_mprintf("PRAGMA %Q.table_info(%Q)", 
+        sqlite3_column_text(pCur->pDbList, 1),
+        sqlite3_column_text(pCur->pTableList, 0)
+    );
+
+    if( !zSql ){
+      rc = SQLITE_NOMEM;
+      goto fail;
+    }
+    rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pColumnList, 0);
+    sqlite3_free(zSql);
+    if( rc!=SQLITE_OK ) goto fail;
+  }
+  pCur->rowid++;
+
+fail:
+  /* TODO: Handle rc */
+  return 1;
+}
+
+/*
+** Reset a schema table cursor.
+*/
+static int schemaFilter(
+  sqlite3_vtab_cursor *pVtabCursor, 
+  int idxNum, const char *idxStr,
+  int argc, sqlite3_value **argv
+){
+  int rc;
+  schema_vtab *pVtab = (schema_vtab *)(pVtabCursor->pVtab);
+  schema_cursor *pCur = (schema_cursor *)pVtabCursor;
+  pCur->rowid = 0;
+  finalize(&pCur->pTableList);
+  finalize(&pCur->pColumnList);
+  finalize(&pCur->pDbList);
+  rc = sqlite3_prepare(pVtab->db,"PRAGMA database_list", -1, &pCur->pDbList, 0);
+  return (rc==SQLITE_OK ? schemaNext(pVtabCursor) : rc);
+}
+
+/*
+** Analyse the WHERE condition.
+*/
+static int schemaBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+  return SQLITE_OK;
+}
+
+/*
+** A virtual table module that merely echos method calls into TCL
+** variables.
+*/
+static sqlite3_module schemaModule = {
+  0,                           /* iVersion */
+  "schema",                    /* zName */
+  schemaCreate,
+  schemaCreate,
+  schemaBestIndex,
+  schemaDestroy,
+  schemaDestroy,
+  schemaOpen,                  /* xOpen - open a cursor */
+  schemaClose,                 /* xClose - close a cursor */
+  schemaFilter,                /* xFilter - configure scan constraints */
+  schemaNext,                  /* xNext - advance a cursor */
+  schemaColumn,                /* xColumn - read data */
+  schemaRowid,                 /* xRowid - read data */
+};
+
+
+#ifdef SQLITE_TEST
+
+/*
+** Decode a pointer to an sqlite3 object.
+*/
+static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
+  *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
+  return TCL_OK;
+}
+
+/*
+** Register the schema virtual table module.
+*/
+static int register_schema_module(
+  ClientData clientData, /* Not used */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  sqlite3 *db;
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "DB");
+    return TCL_ERROR;
+  }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  sqlite3_create_module(db, "schema", &schemaModule, 0);
+#endif
+  return TCL_OK;
+}
+
+/*
+** Register commands with the TCL interpreter.
+*/
+int Sqlitetestschema_Init(Tcl_Interp *interp){
+  static struct {
+     char *zName;
+     Tcl_ObjCmdProc *xProc;
+     void *clientData;
+  } aObjCmd[] = {
+     { "register_schema_module", register_schema_module, 0 },
+  };
+  int i;
+  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
+    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 
+        aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
+  }
+  return TCL_OK;
+}
+
+#else
+
+/*
+** Extension load function.
+*/
+int schema_init(
+  sqlite3 *db, 
+  char **pzErrMsg, 
+  const sqlite3_api_routines *pApi
+){
+  SQLITE_EXTENSION_INIT2(pApi);
+  sqlite3_create_module(db, "schema", &schemaModule, 0);
+  return 0;
+}
+
+#endif