6847647dc4
FossilOrigin-Name: b8e536089b0e6dec500a28556f826c99b78d979615ba3bc01ed31ead1b2112df
283 lines
7.5 KiB
C
283 lines
7.5 KiB
C
/*
|
|
** 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;
|
|
}
|
|
|