/*
** 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.
*/
/*
** None of this works unless we have virtual tables.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_TEST)
#include <tcl.h>
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
#include "sqliteInt.h"
/* The code in this file defines a sqlite3 virtual-table module with
** the following schema.
*/
#define SCHEMAPOOL_SCHEMA \
"CREATE TABLE x(" \
" cksum INTEGER, " \
" nref INTEGER, " \
" nschema INTEGER, " \
" ndelete INTEGER " \
")"
#define SCHEMAPOOL_NFIELD 4
typedef struct schemapool_vtab schemapool_vtab;
typedef struct schemapool_cursor schemapool_cursor;
/* A schema table object */
struct schemapool_vtab {
sqlite3_vtab base;
};
/* A schema table cursor object */
struct schemapool_cursor {
sqlite3_vtab_cursor base;
sqlite3_int64 *aData;
int iRow;
int nRow;
};
/*
** Table destructor for the schema module.
*/
static int schemaPoolDestroy(sqlite3_vtab *pVtab){
sqlite3_free(pVtab);
return 0;
}
/*
** Table constructor for the schema module.
*/
static int schemaPoolCreate(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
int rc = SQLITE_NOMEM;
schemapool_vtab *pVtab = sqlite3_malloc(sizeof(schemapool_vtab));
if( pVtab ){
memset(pVtab, 0, sizeof(schemapool_vtab));
rc = sqlite3_declare_vtab(db, SCHEMAPOOL_SCHEMA);
if( rc!=SQLITE_OK ){
sqlite3_free(pVtab);
pVtab = 0;
}
}
*ppVtab = (sqlite3_vtab *)pVtab;
return rc;
}
/*
** Open a new cursor on the schema table.
*/
static int schemaPoolOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
int rc = SQLITE_NOMEM;
schemapool_cursor *pCur;
pCur = sqlite3_malloc(sizeof(schemapool_cursor));
if( pCur ){
memset(pCur, 0, sizeof(schemapool_cursor));
*ppCursor = (sqlite3_vtab_cursor*)pCur;
rc = SQLITE_OK;
}
return rc;
}
/*
** Close a schema table cursor.
*/
static int schemaPoolClose(sqlite3_vtab_cursor *cur){
schemapool_cursor *pCur = (schemapool_cursor*)cur;
sqlite3_free(pCur->aData);
sqlite3_free(pCur);
return SQLITE_OK;
}
/*
** Retrieve a column of data.
*/
static int schemaPoolColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
schemapool_cursor *pCur = (schemapool_cursor*)cur;
assert( i==0 || i==1 || i==2 || i==3 );
sqlite3_result_int64(ctx, pCur->aData[pCur->iRow*SCHEMAPOOL_NFIELD + i]);
return SQLITE_OK;
}
/*
** Retrieve the current rowid.
*/
static int schemaPoolRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
schemapool_cursor *pCur = (schemapool_cursor*)cur;
*pRowid = pCur->iRow + 1;
return SQLITE_OK;
}
static int schemaPoolEof(sqlite3_vtab_cursor *cur){
schemapool_cursor *pCur = (schemapool_cursor*)cur;
return pCur->iRow>=pCur->nRow;
}
/*
** Advance the cursor to the next row.
*/
static int schemaPoolNext(sqlite3_vtab_cursor *cur){
schemapool_cursor *pCur = (schemapool_cursor*)cur;
pCur->iRow++;
return SQLITE_OK;
}
struct SchemaPool {
int nRef; /* Number of pointers to this object */
int nDelete; /* Schema objects deleted by ReleaseAll() */
u64 cksum; /* Checksum for this Schema contents */
Schema *pSchema; /* Linked list of Schema objects */
Schema sSchema; /* The single dummy schema object */
SchemaPool *pNext; /* Next element in schemaPoolList */
};
extern SchemaPool *sqlite3SchemaPoolList(void);
/*
** Reset a schemaPool table cursor.
*/
static int schemaPoolFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
SchemaPool *pSPool;
schemapool_cursor *pCur = (schemapool_cursor*)pVtabCursor;
sqlite3_free(pCur->aData);
pCur->aData = 0;
pCur->nRow = 0;
pCur->iRow = 0;
for(pSPool = sqlite3SchemaPoolList(); pSPool; pSPool=pSPool->pNext){
pCur->nRow++;
}
if( pCur->nRow ){
int iRow = 0;
int nByte = SCHEMAPOOL_NFIELD * pCur->nRow * sizeof(i64);
pCur->aData = (i64*)sqlite3_malloc(nByte);
if( pCur->aData==0 ) return SQLITE_NOMEM;
for(pSPool = sqlite3SchemaPoolList(); pSPool; pSPool=pSPool->pNext){
Schema *p;
i64 nSchema = 0;
for(p=pSPool->pSchema; p; p=p->pNext){
nSchema++;
}
pCur->aData[0 + iRow*SCHEMAPOOL_NFIELD] = pSPool->cksum;
pCur->aData[1 + iRow*SCHEMAPOOL_NFIELD] = (i64)pSPool->nRef;
pCur->aData[2 + iRow*SCHEMAPOOL_NFIELD] = nSchema;
pCur->aData[3 + iRow*SCHEMAPOOL_NFIELD] = (i64)pSPool->nDelete;
iRow++;
}
}
return SQLITE_OK;
}
/*
** Analyse the WHERE condition.
*/
static int schemaPoolBestIndex(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 schemaPoolModule = {
0, /* iVersion */
schemaPoolCreate,
schemaPoolCreate,
schemaPoolBestIndex,
schemaPoolDestroy,
schemaPoolDestroy,
schemaPoolOpen, /* xOpen - open a cursor */
schemaPoolClose, /* xClose - close a cursor */
schemaPoolFilter, /* xFilter - configure scan constraints */
schemaPoolNext, /* xNext - advance a cursor */
schemaPoolEof, /* xEof */
schemaPoolColumn, /* xColumn - read data */
schemaPoolRowid, /* xRowid - read data */
0, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
};
/*
** Decode a pointer to an sqlite3 object.
*/
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
/*
** Register the schema virtual table module.
*/
static int SQLITE_TCLAPI register_schemapool_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;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3_create_module(db, "schemapool", &schemaPoolModule, 0);
#endif
return TCL_OK;
}
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_TEST) */
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetestschemapool_Init(Tcl_Interp *interp){
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
static struct {
char *zName;
Tcl_ObjCmdProc *xProc;
void *clientData;
} aObjCmd[] = {
{ "register_schemapool_module", register_schemapool_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);
}
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
return TCL_OK;
}