#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
typedef struct tcl_vtab tcl_vtab;
typedef struct tcl_cursor tcl_cursor;
typedef struct TestFindFunction TestFindFunction;
struct tcl_vtab {
sqlite3_vtab base;
Tcl_Interp *interp;
Tcl_Obj *pCmd;
TestFindFunction *pFindFunctionList;
sqlite3 *db;
};
struct tcl_cursor {
sqlite3_vtab_cursor base;
sqlite3_stmt *pStmt;
};
struct TestFindFunction {
tcl_vtab *pTab;
const char *zName;
TestFindFunction *pNext;
};
static void tclDequote(char *z){
char q = z[0];
if( q=='[' || q=='\'' || q=='"' || q=='`' ){
int iIn = 1;
int iOut = 0;
if( q=='[' ) q = ']';
while( ALWAYS(z[iIn]) ){
if( z[iIn]==q ){
if( z[iIn+1]!=q ){
iIn++;
break;
}else{
iIn += 2;
z[iOut++] = q;
}
}else{
z[iOut++] = z[iIn++];
}
}
z[iOut] = '\0';
}
}
static int tclConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
Tcl_Interp *interp = (Tcl_Interp*)pAux;
tcl_vtab *pTab = 0;
char *zCmd = 0;
Tcl_Obj *pScript = 0;
int rc = SQLITE_OK;
if( argc!=4 ){
*pzErr = sqlite3_mprintf("wrong number of arguments");
return SQLITE_ERROR;
}
zCmd = sqlite3_malloc64(strlen(argv[3])+1);
pTab = (tcl_vtab*)sqlite3_malloc64(sizeof(tcl_vtab));
if( zCmd && pTab ){
memcpy(zCmd, argv[3], strlen(argv[3])+1);
tclDequote(zCmd);
memset(pTab, 0, sizeof(tcl_vtab));
pTab->pCmd = Tcl_NewStringObj(zCmd, -1);
pTab->interp = interp;
pTab->db = db;
Tcl_IncrRefCount(pTab->pCmd);
pScript = Tcl_DuplicateObj(pTab->pCmd);
Tcl_IncrRefCount(pScript);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xConnect", -1));
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
if( rc!=TCL_OK ){
*pzErr = sqlite3_mprintf("%s", Tcl_GetStringResult(interp));
rc = SQLITE_ERROR;
}else{
rc = sqlite3_declare_vtab(db, Tcl_GetStringResult(interp));
}
if( rc!=SQLITE_OK ){
sqlite3_free(pTab);
pTab = 0;
}
}else{
rc = SQLITE_NOMEM;
}
sqlite3_free(zCmd);
*ppVtab = &pTab->base;
return rc;
}
static int tclDisconnect(sqlite3_vtab *pVtab){
tcl_vtab *pTab = (tcl_vtab*)pVtab;
while( pTab->pFindFunctionList ){
TestFindFunction *p = pTab->pFindFunctionList;
pTab->pFindFunctionList = p->pNext;
sqlite3_free(p);
}
Tcl_DecrRefCount(pTab->pCmd);
sqlite3_free(pTab);
return SQLITE_OK;
}
static int tclOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
tcl_cursor *pCur;
pCur = sqlite3_malloc(sizeof(tcl_cursor));
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(tcl_cursor));
*ppCursor = &pCur->base;
return SQLITE_OK;
}
static int tclClose(sqlite3_vtab_cursor *cur){
tcl_cursor *pCur = (tcl_cursor *)cur;
if( pCur ){
sqlite3_finalize(pCur->pStmt);
sqlite3_free(pCur);
}
return SQLITE_OK;
}
static int tclNext(sqlite3_vtab_cursor *pVtabCursor){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
if( pCsr->pStmt ){
tcl_vtab *pTab = (tcl_vtab*)(pVtabCursor->pVtab);
int rc = sqlite3_step(pCsr->pStmt);
if( rc!=SQLITE_ROW ){
const char *zErr;
rc = sqlite3_finalize(pCsr->pStmt);
pCsr->pStmt = 0;
if( rc!=SQLITE_OK ){
zErr = sqlite3_errmsg(pTab->db);
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}
}
}
return SQLITE_OK;
}
static int tclFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
tcl_vtab *pTab = (tcl_vtab*)(pVtabCursor->pVtab);
Tcl_Interp *interp = pTab->interp;
Tcl_Obj *pScript;
Tcl_Obj *pArg;
int ii;
int rc;
pScript = Tcl_DuplicateObj(pTab->pCmd);
Tcl_IncrRefCount(pScript);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xFilter", -1));
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewIntObj(idxNum));
if( idxStr ){
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(idxStr, -1));
}else{
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("", -1));
}
pArg = Tcl_NewObj();
Tcl_IncrRefCount(pArg);
for(ii=0; ii<argc; ii++){
const char *zVal = (const char*)sqlite3_value_text(argv[ii]);
Tcl_Obj *pVal;
if( zVal==0 ){
sqlite3_value *pMem;
pVal = Tcl_NewObj();
for(rc=sqlite3_vtab_in_first(argv[ii], &pMem);
rc==SQLITE_OK && pMem;
rc=sqlite3_vtab_in_next(argv[ii], &pMem)
){
Tcl_Obj *pVal2 = 0;
zVal = (const char*)sqlite3_value_text(pMem);
if( zVal ){
pVal2 = Tcl_NewStringObj(zVal, -1);
}else{
pVal2 = Tcl_NewObj();
}
Tcl_ListObjAppendElement(interp, pVal, pVal2);
}
}else{
pVal = Tcl_NewStringObj(zVal, -1);
}
Tcl_ListObjAppendElement(interp, pArg, pVal);
}
Tcl_ListObjAppendElement(interp, pScript, pArg);
Tcl_DecrRefCount(pArg);
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
if( rc!=TCL_OK ){
const char *zErr = Tcl_GetStringResult(interp);
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}else{
Tcl_Obj *pRes = Tcl_GetObjResult(interp);
Tcl_Obj **apElem = 0;
int nElem;
rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
if( rc!=TCL_OK ){
const char *zErr = Tcl_GetStringResult(interp);
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}else{
for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
const char *zCmd = Tcl_GetString(apElem[ii]);
Tcl_Obj *p = apElem[ii+1];
if( sqlite3_stricmp("sql", zCmd)==0 ){
const char *zSql = Tcl_GetString(p);
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
if( rc!=SQLITE_OK ){
const char *zErr = sqlite3_errmsg(pTab->db);
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zErr);
}
}else{
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zCmd);
}
}
}
}
if( rc==SQLITE_OK ){
rc = tclNext(pVtabCursor);
}
return rc;
}
static int tclColumn(
sqlite3_vtab_cursor *pVtabCursor,
sqlite3_context *ctx,
int i
){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, i+1));
return SQLITE_OK;
}
static int tclRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
*pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
return SQLITE_OK;
}
static int tclEof(sqlite3_vtab_cursor *pVtabCursor){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
return (pCsr->pStmt==0);
}
static void testBestIndexObjConstraints(
Tcl_Interp *interp,
sqlite3_index_info *pIdxInfo
){
int ii;
Tcl_Obj *pRes = Tcl_NewObj();
Tcl_IncrRefCount(pRes);
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
Tcl_Obj *pElem = Tcl_NewObj();
const char *zOp = 0;
Tcl_IncrRefCount(pElem);
switch( pCons->op ){
case SQLITE_INDEX_CONSTRAINT_EQ:
zOp = "eq"; break;
case SQLITE_INDEX_CONSTRAINT_GT:
zOp = "gt"; break;
case SQLITE_INDEX_CONSTRAINT_LE:
zOp = "le"; break;
case SQLITE_INDEX_CONSTRAINT_LT:
zOp = "lt"; break;
case SQLITE_INDEX_CONSTRAINT_GE:
zOp = "ge"; break;
case SQLITE_INDEX_CONSTRAINT_MATCH:
zOp = "match"; break;
case SQLITE_INDEX_CONSTRAINT_LIKE:
zOp = "like"; break;
case SQLITE_INDEX_CONSTRAINT_GLOB:
zOp = "glob"; break;
case SQLITE_INDEX_CONSTRAINT_REGEXP:
zOp = "regexp"; break;
case SQLITE_INDEX_CONSTRAINT_NE:
zOp = "ne"; break;
case SQLITE_INDEX_CONSTRAINT_ISNOT:
zOp = "isnot"; break;
case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
zOp = "isnotnull"; break;
case SQLITE_INDEX_CONSTRAINT_ISNULL:
zOp = "isnull"; break;
case SQLITE_INDEX_CONSTRAINT_IS:
zOp = "is"; break;
case SQLITE_INDEX_CONSTRAINT_LIMIT:
zOp = "limit"; break;
case SQLITE_INDEX_CONSTRAINT_OFFSET:
zOp = "offset"; break;
}
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1));
if( zOp ){
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zOp, -1));
}else{
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->op));
}
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->iColumn));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("usable", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->usable));
Tcl_ListObjAppendElement(0, pRes, pElem);
Tcl_DecrRefCount(pElem);
}
Tcl_SetObjResult(interp, pRes);
Tcl_DecrRefCount(pRes);
}
static void testBestIndexObjOrderby(
Tcl_Interp *interp,
sqlite3_index_info *pIdxInfo
){
int ii;
Tcl_Obj *pRes = Tcl_NewObj();
Tcl_IncrRefCount(pRes);
for(ii=0; ii<pIdxInfo->nOrderBy; ii++){
struct sqlite3_index_orderby const *pOrder = &pIdxInfo->aOrderBy[ii];
Tcl_Obj *pElem = Tcl_NewObj();
Tcl_IncrRefCount(pElem);
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->iColumn));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("desc", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->desc));
Tcl_ListObjAppendElement(0, pRes, pElem);
Tcl_DecrRefCount(pElem);
}
Tcl_SetObjResult(interp, pRes);
Tcl_DecrRefCount(pRes);
}
static int SQLITE_TCLAPI testBestIndexObj(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
const char *azSub[] = {
"constraints",
"orderby",
"mask",
"distinct",
"in",
"rhs_value",
0
};
int ii;
sqlite3_index_info *pIdxInfo = (sqlite3_index_info*)clientData;
if( objc<2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND");
return TCL_ERROR;
}
if( Tcl_GetIndexFromObj(interp, objv[1], azSub, "sub-command", 0, &ii) ){
return TCL_ERROR;
}
if( ii<4 && objc!=2 ){
Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR;
}
if( ii==4 && objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "INDEX BOOLEAN");
return TCL_ERROR;
}
if( ii==5 && objc!=3 && objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "INDEX ?DEFAULT?");
return TCL_ERROR;
}
switch( ii ){
case 0: assert( sqlite3_stricmp(azSub[ii], "constraints")==0 );
testBestIndexObjConstraints(interp, pIdxInfo);
break;
case 1: assert( sqlite3_stricmp(azSub[ii], "orderby")==0 );
testBestIndexObjOrderby(interp, pIdxInfo);
break;
case 2: assert( sqlite3_stricmp(azSub[ii], "mask")==0 );
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(pIdxInfo->colUsed));
break;
case 3: assert( sqlite3_stricmp(azSub[ii], "distinct")==0 ); {
int bDistinct = sqlite3_vtab_distinct(pIdxInfo);
Tcl_SetObjResult(interp, Tcl_NewIntObj(bDistinct));
break;
}
case 4: assert( sqlite3_stricmp(azSub[ii], "in")==0 ); {
int iCons;
int bHandle;
if( Tcl_GetIntFromObj(interp, objv[2], &iCons)
|| Tcl_GetBooleanFromObj(interp, objv[3], &bHandle)
){
return TCL_ERROR;
}
Tcl_SetObjResult(interp,
Tcl_NewIntObj(sqlite3_vtab_in(pIdxInfo, iCons, bHandle))
);
break;
}
case 5: assert( sqlite3_stricmp(azSub[ii], "rhs_value")==0 ); {
int iCons = 0;
int rc;
sqlite3_value *pVal = 0;
const char *zVal = "";
if( Tcl_GetIntFromObj(interp, objv[2], &iCons) ){
return TCL_ERROR;
}
rc = sqlite3_vtab_rhs_value(pIdxInfo, iCons, &pVal);
if( rc!=SQLITE_OK && rc!=SQLITE_NOTFOUND ){
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
return TCL_ERROR;
}
if( pVal ){
zVal = (const char*)sqlite3_value_text(pVal);
}else if( objc==4 ){
zVal = Tcl_GetString(objv[3]);
}
Tcl_SetObjResult(interp, Tcl_NewStringObj(zVal, -1));
break;
}
}
return TCL_OK;
}
static int tclBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
tcl_vtab *pTab = (tcl_vtab*)tab;
Tcl_Interp *interp = pTab->interp;
int rc = SQLITE_OK;
static int iNext = 43;
char zHdl[24];
Tcl_Obj *pScript;
pScript = Tcl_DuplicateObj(pTab->pCmd);
Tcl_IncrRefCount(pScript);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xBestIndex", -1));
sqlite3_snprintf(sizeof(zHdl), zHdl, "bestindex%d", iNext++);
Tcl_CreateObjCommand(interp, zHdl, testBestIndexObj, pIdxInfo, 0);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(zHdl, -1));
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
Tcl_DeleteCommand(interp, zHdl);
Tcl_DecrRefCount(pScript);
if( rc!=TCL_OK ){
const char *zErr = Tcl_GetStringResult(interp);
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}else{
Tcl_Obj *pRes = Tcl_GetObjResult(interp);
Tcl_Obj **apElem = 0;
int nElem;
rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
if( rc!=TCL_OK ){
const char *zErr = Tcl_GetStringResult(interp);
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}else{
int ii;
int iArgv = 1;
for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
const char *zCmd = Tcl_GetString(apElem[ii]);
Tcl_Obj *p = apElem[ii+1];
if( sqlite3_stricmp("cost", zCmd)==0 ){
rc = Tcl_GetDoubleFromObj(interp, p, &pIdxInfo->estimatedCost);
}else
if( sqlite3_stricmp("orderby", zCmd)==0 ){
rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->orderByConsumed);
}else
if( sqlite3_stricmp("idxnum", zCmd)==0 ){
rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->idxNum);
}else
if( sqlite3_stricmp("idxstr", zCmd)==0 ){
sqlite3_free(pIdxInfo->idxStr);
pIdxInfo->idxStr = sqlite3_mprintf("%s", Tcl_GetString(p));
pIdxInfo->needToFreeIdxStr = 1;
}else
if( sqlite3_stricmp("rows", zCmd)==0 ){
Tcl_WideInt x = 0;
rc = Tcl_GetWideIntFromObj(interp, p, &x);
pIdxInfo->estimatedRows = (tRowcnt)x;
}else
if( sqlite3_stricmp("use", zCmd)==0
|| sqlite3_stricmp("omit", zCmd)==0
){
int iCons;
rc = Tcl_GetIntFromObj(interp, p, &iCons);
if( rc==SQLITE_OK ){
if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %d", iCons);
}else{
int bOmit = (zCmd[0]=='o' || zCmd[0]=='O');
pIdxInfo->aConstraintUsage[iCons].argvIndex = iArgv++;
pIdxInfo->aConstraintUsage[iCons].omit = bOmit;
}
}
}else{
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zCmd);
}
if( rc!=SQLITE_OK && pTab->base.zErrMsg==0 ){
const char *zErr = Tcl_GetStringResult(interp);
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}
}
}
}
return rc;
}
static void tclFunction(sqlite3_context *pCtx, int nArg, sqlite3_value **apArg){
TestFindFunction *p = (TestFindFunction*)sqlite3_user_data(pCtx);
Tcl_Interp *interp = p->pTab->interp;
Tcl_Obj *pScript = 0;
Tcl_Obj *pRet = 0;
int ii;
pScript = Tcl_DuplicateObj(p->pTab->pCmd);
Tcl_IncrRefCount(pScript);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("function", -1));
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(p->zName, -1));
for(ii=0; ii<nArg; ii++){
const char *zArg = (const char*)sqlite3_value_text(apArg[ii]);
Tcl_ListObjAppendElement(interp, pScript,
(zArg ? Tcl_NewStringObj(zArg, -1) : Tcl_NewObj())
);
}
Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
Tcl_DecrRefCount(pScript);
pRet = Tcl_GetObjResult(interp);
sqlite3_result_text(pCtx, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT);
}
static int tclFindFunction(
sqlite3_vtab *tab,
int nArg,
const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg
){
int iRet = 0;
tcl_vtab *pTab = (tcl_vtab*)tab;
Tcl_Interp *interp = pTab->interp;
Tcl_Obj *pScript = 0;
int rc = SQLITE_OK;
pScript = Tcl_DuplicateObj(pTab->pCmd);
Tcl_IncrRefCount(pScript);
Tcl_ListObjAppendElement(
interp, pScript, Tcl_NewStringObj("xFindFunction", -1)
);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewIntObj(nArg));
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(zName, -1));
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
Tcl_DecrRefCount(pScript);
if( rc==SQLITE_OK ){
Tcl_Obj *pObj = Tcl_GetObjResult(interp);
if( Tcl_GetIntFromObj(interp, pObj, &iRet) ){
rc = SQLITE_ERROR;
}else if( iRet>0 ){
sqlite3_int64 nName = strlen(zName);
sqlite3_int64 nByte = nName + 1 + sizeof(TestFindFunction);
TestFindFunction *pNew = 0;
pNew = (TestFindFunction*)sqlite3_malloc64(nByte);
if( pNew==0 ){
iRet = 0;
}else{
memset(pNew, 0, nByte);
pNew->zName = (const char*)&pNew[1];
memcpy((char*)pNew->zName, zName, nName);
pNew->pTab = pTab;
pNew->pNext = pTab->pFindFunctionList;
pTab->pFindFunctionList = pNew;
*ppArg = (void*)pNew;
*pxFunc = tclFunction;
}
}
}
return iRet;
}
static sqlite3_module tclModule = {
0,
tclConnect,
tclConnect,
tclBestIndex,
tclDisconnect,
tclDisconnect,
tclOpen,
tclClose,
tclFilter,
tclNext,
tclEof,
tclColumn,
tclRowid,
0,
0,
0,
0,
0,
tclFindFunction,
0,
};
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
static int SQLITE_TCLAPI register_tcl_module(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
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, "tcl", &tclModule, (void *)interp);
#endif
return TCL_OK;
}
#endif
int Sqlitetesttcl_Init(Tcl_Interp *interp){
#ifndef SQLITE_OMIT_VIRTUALTABLE
static struct {
char *zName;
Tcl_ObjCmdProc *xProc;
void *clientData;
} aObjCmd[] = {
{ "register_tcl_module", register_tcl_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
return TCL_OK;
}