/* ** 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 "sqliteInt.h" #include /* 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 /* ** Register commands with the TCL interpreter. */ int Sqlitetestschemapool_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "register_schemapool_module", register_schemapool_module, 0 }, }; int i; for(i=0; i