Add test_schema.c, containing a module for viewing the database schema via a virtual table. (CVS 3257)

FossilOrigin-Name: de8d32ac71a6e113e83b952813424cb3fb5a2e59
This commit is contained in:
danielk1977 2006-06-15 15:59:19 +00:00
parent d6e8dd00ac
commit 954ce99c62
6 changed files with 359 additions and 10 deletions

View 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 \

View File

@ -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 \

View File

@ -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

View File

@ -1 +1 @@
25c475087892fea83bce9d140b46651793b85a86
de8d32ac71a6e113e83b952813424cb3fb5a2e59

View 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);

344
src/test_schema.c Normal file
View File

@ -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