#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>
typedef struct vtablog_vtab vtablog_vtab;
struct vtablog_vtab {
sqlite3_vtab base;
int nRow;
int iInst;
int nCursor;
};
typedef struct vtablog_cursor vtablog_cursor;
struct vtablog_cursor {
sqlite3_vtab_cursor base;
int iCursor;
sqlite3_int64 iRowid;
};
static const char *vtablog_skip_whitespace(const char *z){
while( isspace((unsigned char)z[0]) ) z++;
return z;
}
static void vtablog_trim_whitespace(char *z){
size_t n = strlen(z);
while( n>0 && isspace((unsigned char)z[n]) ) n--;
z[n] = 0;
}
static void vtablog_dequote(char *z){
int j;
char cQuote = z[0];
size_t i, n;
if( cQuote!='\'' && cQuote!='"' ) return;
n = strlen(z);
if( n<2 || z[n-1]!=z[0] ) return;
for(i=1, j=0; i<n-1; i++){
if( z[i]==cQuote && z[i+1]==cQuote ) i++;
z[j++] = z[i];
}
z[j] = 0;
}
static const char *vtablog_parameter(const char *zTag, int nTag, const char *z){
z = vtablog_skip_whitespace(z);
if( strncmp(zTag, z, nTag)!=0 ) return 0;
z = vtablog_skip_whitespace(z+nTag);
if( z[0]!='=' ) return 0;
return vtablog_skip_whitespace(z+1);
}
static int vtablog_string_parameter(
char **pzErr,
const char *zParam,
const char *zArg,
char **pzVal
){
const char *zValue;
zValue = vtablog_parameter(zParam,(int)strlen(zParam),zArg);
if( zValue==0 ) return 0;
if( *pzVal ){
*pzErr = sqlite3_mprintf("more than one '%s' parameter", zParam);
return 1;
}
*pzVal = sqlite3_mprintf("%s", zValue);
if( *pzVal==0 ){
*pzErr = sqlite3_mprintf("out of memory");
return 1;
}
vtablog_trim_whitespace(*pzVal);
vtablog_dequote(*pzVal);
return 0;
}
#if 0#endif
static int vtablogConnectCreate(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr,
int isCreate
){
static int nInst = 0;
vtablog_vtab *pNew;
int i;
int rc;
int iInst = ++nInst;
char *zSchema = 0;
char *zNRow = 0;
printf("vtablog%s(tab=%d):\n", isCreate ? "Create" : "Connect", iInst);
printf(" argc=%d\n", argc);
for(i=0; i<argc; i++){
printf(" argv[%d] = ", i);
if( argv[i] ){
printf("[%s]\n", argv[i]);
}else{
printf("NULL\n");
}
}
for(i=3; i<argc; i++){
const char *z = argv[i];
if( vtablog_string_parameter(pzErr, "schema", z, &zSchema) ){
return SQLITE_ERROR;
}
if( vtablog_string_parameter(pzErr, "rows", z, &zNRow) ){
return SQLITE_ERROR;
}
}
if( zSchema==0 ){
*pzErr = sqlite3_mprintf("no schema defined");
return SQLITE_ERROR;
}
rc = sqlite3_declare_vtab(db, zSchema);
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
pNew->nRow = 10;
if( zNRow ) pNew->nRow = atoi(zNRow);
pNew->iInst = iInst;
}
return rc;
}
static int vtablogCreate(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
return vtablogConnectCreate(db,pAux,argc,argv,ppVtab,pzErr,1);
}
static int vtablogConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
return vtablogConnectCreate(db,pAux,argc,argv,ppVtab,pzErr,0);
}
static int vtablogDisconnect(sqlite3_vtab *pVtab){
vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
printf("vtablogDisconnect(%d)\n", pTab->iInst);
sqlite3_free(pVtab);
return SQLITE_OK;
}
static int vtablogDestroy(sqlite3_vtab *pVtab){
vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
printf("vtablogDestroy(%d)\n", pTab->iInst);
sqlite3_free(pVtab);
return SQLITE_OK;
}
static int vtablogOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
vtablog_vtab *pTab = (vtablog_vtab*)p;
vtablog_cursor *pCur;
printf("vtablogOpen(tab=%d, cursor=%d)\n", pTab->iInst, ++pTab->nCursor);
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->iCursor = pTab->nCursor;
*ppCursor = &pCur->base;
return SQLITE_OK;
}
static int vtablogClose(sqlite3_vtab_cursor *cur){
vtablog_cursor *pCur = (vtablog_cursor*)cur;
vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
printf("vtablogClose(tab=%d, cursor=%d)\n", pTab->iInst, pCur->iCursor);
sqlite3_free(cur);
return SQLITE_OK;
}
static int vtablogNext(sqlite3_vtab_cursor *cur){
vtablog_cursor *pCur = (vtablog_cursor*)cur;
vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
printf("vtablogNext(tab=%d, cursor=%d) rowid %d -> %d\n",
pTab->iInst, pCur->iCursor, (int)pCur->iRowid, (int)pCur->iRowid+1);
pCur->iRowid++;
return SQLITE_OK;
}
static int vtablogColumn(
sqlite3_vtab_cursor *cur,
sqlite3_context *ctx,
int i
){
vtablog_cursor *pCur = (vtablog_cursor*)cur;
vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
char zVal[50];
if( i<26 ){
sqlite3_snprintf(sizeof(zVal),zVal,"%c%d",
"abcdefghijklmnopqrstuvwyz"[i], pCur->iRowid);
}else{
sqlite3_snprintf(sizeof(zVal),zVal,"{%d}%d", i, pCur->iRowid);
}
printf("vtablogColumn(tab=%d, cursor=%d, i=%d): [%s]\n",
pTab->iInst, pCur->iCursor, i, zVal);
sqlite3_result_text(ctx, zVal, -1, SQLITE_TRANSIENT);
return SQLITE_OK;
}
static int vtablogRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
vtablog_cursor *pCur = (vtablog_cursor*)cur;
vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
printf("vtablogRowid(tab=%d, cursor=%d): %d\n",
pTab->iInst, pCur->iCursor, (int)pCur->iRowid);
*pRowid = pCur->iRowid;
return SQLITE_OK;
}
static int vtablogEof(sqlite3_vtab_cursor *cur){
vtablog_cursor *pCur = (vtablog_cursor*)cur;
vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
int rc = pCur->iRowid >= pTab->nRow;
printf("vtablogEof(tab=%d, cursor=%d): %d\n",
pTab->iInst, pCur->iCursor, rc);
return rc;
}
static void vtablogQuote(sqlite3_value *p){
char z[50];
switch( sqlite3_value_type(p) ){
case SQLITE_NULL: {
printf("NULL");
break;
}
case SQLITE_INTEGER: {
sqlite3_snprintf(50,z,"%lld", sqlite3_value_int64(p));
printf("%s", z);
break;
}
case SQLITE_FLOAT: {
sqlite3_snprintf(50,z,"%!.20g", sqlite3_value_double(p));
printf("%s", z);
break;
}
case SQLITE_BLOB: {
int n = sqlite3_value_bytes(p);
const unsigned char *z = (const unsigned char*)sqlite3_value_blob(p);
int i;
printf("x'");
for(i=0; i<n; i++) printf("%02x", z[i]);
printf("'");
break;
}
case SQLITE_TEXT: {
const char *z = (const char*)sqlite3_value_text(p);
int i;
char c;
for(i=0; (c = z[i])!=0 && c!='\''; i++){}
if( c==0 ){
printf("'%s'",z);
}else{
printf("'");
while( *z ){
for(i=0; (c = z[i])!=0 && c!='\''; i++){}
if( c=='\'' ) i++;
if( i ){
printf("%.*s", i, z);
z += i;
}
if( c=='\'' ){
printf("'");
continue;
}
if( c==0 ){
break;
}
z++;
}
printf("'");
}
break;
}
}
}
static int vtablogFilter(
sqlite3_vtab_cursor *cur,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
vtablog_cursor *pCur = (vtablog_cursor *)cur;
vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
printf("vtablogFilter(tab=%d, cursor=%d):\n", pTab->iInst, pCur->iCursor);
pCur->iRowid = 0;
return SQLITE_OK;
}
static int vtablogBestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
vtablog_vtab *pTab = (vtablog_vtab*)tab;
printf("vtablogBestIndex(tab=%d):\n", pTab->iInst);
pIdxInfo->estimatedCost = (double)500;
pIdxInfo->estimatedRows = 500;
return SQLITE_OK;
}
static int vtablogUpdate(
sqlite3_vtab *tab,
int argc,
sqlite3_value **argv,
sqlite_int64 *pRowid
){
vtablog_vtab *pTab = (vtablog_vtab*)tab;
int i;
printf("vtablogUpdate(tab=%d):\n", pTab->iInst);
printf(" argc=%d\n", argc);
for(i=0; i<argc; i++){
printf(" argv[%d]=", i);
vtablogQuote(argv[i]);
printf("\n");
}
return SQLITE_OK;
}
static sqlite3_module vtablogModule = {
0,
vtablogCreate,
vtablogConnect,
vtablogBestIndex,
vtablogDisconnect,
vtablogDestroy,
vtablogOpen,
vtablogClose,
vtablogFilter,
vtablogNext,
vtablogEof,
vtablogColumn,
vtablogRowid,
vtablogUpdate,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_vtablog_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc;
SQLITE_EXTENSION_INIT2(pApi);
rc = sqlite3_create_module(db, "vtablog", &vtablogModule, 0);
return rc;
}