persistentstorage/sqlite3api/TEST/SRC/test_tclvar.c
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 /*
       
     2 ** 2006 June 13
       
     3 **
       
     4 ** The author disclaims copyright to this source code.  In place of
       
     5 ** a legal notice, here is a blessing:
       
     6 **
       
     7 **    May you do good and not evil.
       
     8 **    May you find forgiveness for yourself and forgive others.
       
     9 **    May you share freely, never taking more than you give.
       
    10 **
       
    11 *************************************************************************
       
    12 ** Code for testing the virtual table interfaces.  This code
       
    13 ** is not included in the SQLite library.  It is used for automated
       
    14 ** testing of the SQLite library.
       
    15 **
       
    16 ** The emphasis of this file is a virtual table that provides
       
    17 ** access to TCL variables.
       
    18 **
       
    19 ** $Id: test_tclvar.c,v 1.17 2008/08/12 14:48:41 danielk1977 Exp $
       
    20 */
       
    21 #include "sqliteInt.h"
       
    22 #include "tcl.h"
       
    23 #include <stdlib.h>
       
    24 #include <string.h>
       
    25 
       
    26 #ifndef SQLITE_OMIT_VIRTUALTABLE
       
    27 
       
    28 typedef struct tclvar_vtab tclvar_vtab;
       
    29 typedef struct tclvar_cursor tclvar_cursor;
       
    30 
       
    31 /* 
       
    32 ** A tclvar virtual-table object 
       
    33 */
       
    34 struct tclvar_vtab {
       
    35   sqlite3_vtab base;
       
    36   Tcl_Interp *interp;
       
    37 };
       
    38 
       
    39 /* A tclvar cursor object */
       
    40 struct tclvar_cursor {
       
    41   sqlite3_vtab_cursor base;
       
    42 
       
    43   Tcl_Obj *pList1;     /* Result of [info vars ?pattern?] */
       
    44   Tcl_Obj *pList2;     /* Result of [array names [lindex $pList1 $i1]] */
       
    45   int i1;              /* Current item in pList1 */
       
    46   int i2;              /* Current item (if any) in pList2 */
       
    47 };
       
    48 
       
    49 /* Methods for the tclvar module */
       
    50 static int tclvarConnect(
       
    51   sqlite3 *db,
       
    52   void *pAux,
       
    53   int argc, const char *const*argv,
       
    54   sqlite3_vtab **ppVtab,
       
    55   char **pzErr
       
    56 ){
       
    57   tclvar_vtab *pVtab;
       
    58   static const char zSchema[] = 
       
    59      "CREATE TABLE whatever(name TEXT, arrayname TEXT, value TEXT)";
       
    60   pVtab = sqlite3MallocZero( sizeof(*pVtab) );
       
    61   if( pVtab==0 ) return SQLITE_NOMEM;
       
    62   *ppVtab = &pVtab->base;
       
    63   pVtab->interp = (Tcl_Interp *)pAux;
       
    64   sqlite3_declare_vtab(db, zSchema);
       
    65   return SQLITE_OK;
       
    66 }
       
    67 /* Note that for this virtual table, the xCreate and xConnect
       
    68 ** methods are identical. */
       
    69 
       
    70 static int tclvarDisconnect(sqlite3_vtab *pVtab){
       
    71   sqlite3_free(pVtab);
       
    72   return SQLITE_OK;
       
    73 }
       
    74 /* The xDisconnect and xDestroy methods are also the same */
       
    75 
       
    76 /*
       
    77 ** Open a new tclvar cursor.
       
    78 */
       
    79 static int tclvarOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
       
    80   tclvar_cursor *pCur;
       
    81   pCur = sqlite3MallocZero(sizeof(tclvar_cursor));
       
    82   *ppCursor = &pCur->base;
       
    83   return SQLITE_OK;
       
    84 }
       
    85 
       
    86 /*
       
    87 ** Close a tclvar cursor.
       
    88 */
       
    89 static int tclvarClose(sqlite3_vtab_cursor *cur){
       
    90   tclvar_cursor *pCur = (tclvar_cursor *)cur;
       
    91   if( pCur->pList1 ){
       
    92     Tcl_DecrRefCount(pCur->pList1);
       
    93   }
       
    94   if( pCur->pList2 ){
       
    95     Tcl_DecrRefCount(pCur->pList2);
       
    96   }
       
    97   sqlite3_free(pCur);
       
    98   return SQLITE_OK;
       
    99 }
       
   100 
       
   101 /*
       
   102 ** Returns 1 if data is ready, or 0 if not.
       
   103 */
       
   104 static int next2(Tcl_Interp *interp, tclvar_cursor *pCur, Tcl_Obj *pObj){
       
   105   Tcl_Obj *p;
       
   106 
       
   107   if( pObj ){
       
   108     if( !pCur->pList2 ){
       
   109       p = Tcl_NewStringObj("array names", -1);
       
   110       Tcl_IncrRefCount(p);
       
   111       Tcl_ListObjAppendElement(0, p, pObj);
       
   112       Tcl_EvalObjEx(interp, p, TCL_EVAL_GLOBAL);
       
   113       Tcl_DecrRefCount(p);
       
   114       pCur->pList2 = Tcl_GetObjResult(interp);
       
   115       Tcl_IncrRefCount(pCur->pList2);
       
   116       assert( pCur->i2==0 );
       
   117     }else{
       
   118       int n = 0;
       
   119       pCur->i2++;
       
   120       Tcl_ListObjLength(0, pCur->pList2, &n);
       
   121       if( pCur->i2>=n ){
       
   122         Tcl_DecrRefCount(pCur->pList2);
       
   123         pCur->pList2 = 0;
       
   124         pCur->i2 = 0;
       
   125         return 0;
       
   126       }
       
   127     }
       
   128   }
       
   129 
       
   130   return 1;
       
   131 }
       
   132 
       
   133 static int tclvarNext(sqlite3_vtab_cursor *cur){
       
   134   Tcl_Obj *pObj;
       
   135   int n = 0;
       
   136   int ok = 0;
       
   137 
       
   138   tclvar_cursor *pCur = (tclvar_cursor *)cur;
       
   139   Tcl_Interp *interp = ((tclvar_vtab *)(cur->pVtab))->interp;
       
   140 
       
   141   Tcl_ListObjLength(0, pCur->pList1, &n);
       
   142   while( !ok && pCur->i1<n ){
       
   143     Tcl_ListObjIndex(0, pCur->pList1, pCur->i1, &pObj);
       
   144     ok = next2(interp, pCur, pObj);
       
   145     if( !ok ){
       
   146       pCur->i1++;
       
   147     }
       
   148   }
       
   149 
       
   150   return 0;
       
   151 }
       
   152 
       
   153 static int tclvarFilter(
       
   154   sqlite3_vtab_cursor *pVtabCursor, 
       
   155   int idxNum, const char *idxStr,
       
   156   int argc, sqlite3_value **argv
       
   157 ){
       
   158   tclvar_cursor *pCur = (tclvar_cursor *)pVtabCursor;
       
   159   Tcl_Interp *interp = ((tclvar_vtab *)(pVtabCursor->pVtab))->interp;
       
   160 
       
   161   Tcl_Obj *p = Tcl_NewStringObj("info vars", -1);
       
   162   Tcl_IncrRefCount(p);
       
   163 
       
   164   assert( argc==0 || argc==1 );
       
   165   if( argc==1 ){
       
   166     Tcl_Obj *pArg = Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1);
       
   167     Tcl_ListObjAppendElement(0, p, pArg);
       
   168   }
       
   169   Tcl_EvalObjEx(interp, p, TCL_EVAL_GLOBAL);
       
   170   pCur->pList1 = Tcl_GetObjResult(interp);
       
   171   Tcl_IncrRefCount(pCur->pList1);
       
   172   assert( pCur->i1==0 && pCur->i2==0 && pCur->pList2==0 );
       
   173 
       
   174   Tcl_DecrRefCount(p);
       
   175   return tclvarNext(pVtabCursor);
       
   176 }
       
   177 
       
   178 static int tclvarColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
       
   179   Tcl_Obj *p1;
       
   180   Tcl_Obj *p2;
       
   181   const char *z1; 
       
   182   const char *z2 = "";
       
   183   tclvar_cursor *pCur = (tclvar_cursor*)cur;
       
   184   Tcl_Interp *interp = ((tclvar_vtab *)cur->pVtab)->interp;
       
   185 
       
   186   Tcl_ListObjIndex(interp, pCur->pList1, pCur->i1, &p1);
       
   187   Tcl_ListObjIndex(interp, pCur->pList2, pCur->i2, &p2);
       
   188   z1 = Tcl_GetString(p1);
       
   189   if( p2 ){
       
   190     z2 = Tcl_GetString(p2);
       
   191   }
       
   192   switch (i) {
       
   193     case 0: {
       
   194       sqlite3_result_text(ctx, z1, -1, SQLITE_TRANSIENT);
       
   195       break;
       
   196     }
       
   197     case 1: {
       
   198       sqlite3_result_text(ctx, z2, -1, SQLITE_TRANSIENT);
       
   199       break;
       
   200     }
       
   201     case 2: {
       
   202       Tcl_Obj *pVal = Tcl_GetVar2Ex(interp, z1, *z2?z2:0, TCL_GLOBAL_ONLY);
       
   203       sqlite3_result_text(ctx, Tcl_GetString(pVal), -1, SQLITE_TRANSIENT);
       
   204       break;
       
   205     }
       
   206   }
       
   207   return SQLITE_OK;
       
   208 }
       
   209 
       
   210 static int tclvarRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
       
   211   *pRowid = 0;
       
   212   return SQLITE_OK;
       
   213 }
       
   214 
       
   215 static int tclvarEof(sqlite3_vtab_cursor *cur){
       
   216   tclvar_cursor *pCur = (tclvar_cursor*)cur;
       
   217   return (pCur->pList2?0:1);
       
   218 }
       
   219 
       
   220 static int tclvarBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
       
   221   int ii;
       
   222 
       
   223   for(ii=0; ii<pIdxInfo->nConstraint; ii++){
       
   224     struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
       
   225     if( pCons->iColumn==0 && pCons->usable
       
   226            && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
       
   227       struct sqlite3_index_constraint_usage *pUsage;
       
   228       pUsage = &pIdxInfo->aConstraintUsage[ii];
       
   229       pUsage->omit = 0;
       
   230       pUsage->argvIndex = 1;
       
   231       return SQLITE_OK;
       
   232     }
       
   233   }
       
   234 
       
   235   for(ii=0; ii<pIdxInfo->nConstraint; ii++){
       
   236     struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
       
   237     if( pCons->iColumn==0 && pCons->usable
       
   238            && pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH ){
       
   239       struct sqlite3_index_constraint_usage *pUsage;
       
   240       pUsage = &pIdxInfo->aConstraintUsage[ii];
       
   241       pUsage->omit = 1;
       
   242       pUsage->argvIndex = 1;
       
   243       return SQLITE_OK;
       
   244     }
       
   245   }
       
   246 
       
   247   return SQLITE_OK;
       
   248 }
       
   249 
       
   250 /*
       
   251 ** A virtual table module that provides read-only access to a
       
   252 ** Tcl global variable namespace.
       
   253 */
       
   254 static sqlite3_module tclvarModule = {
       
   255   0,                         /* iVersion */
       
   256   tclvarConnect,
       
   257   tclvarConnect,
       
   258   tclvarBestIndex,
       
   259   tclvarDisconnect, 
       
   260   tclvarDisconnect,
       
   261   tclvarOpen,                  /* xOpen - open a cursor */
       
   262   tclvarClose,                 /* xClose - close a cursor */
       
   263   tclvarFilter,                /* xFilter - configure scan constraints */
       
   264   tclvarNext,                  /* xNext - advance a cursor */
       
   265   tclvarEof,                   /* xEof - check for end of scan */
       
   266   tclvarColumn,                /* xColumn - read data */
       
   267   tclvarRowid,                 /* xRowid - read data */
       
   268   0,                           /* xUpdate */
       
   269   0,                           /* xBegin */
       
   270   0,                           /* xSync */
       
   271   0,                           /* xCommit */
       
   272   0,                           /* xRollback */
       
   273   0,                           /* xFindMethod */
       
   274   0,                           /* xRename */
       
   275 };
       
   276 
       
   277 /*
       
   278 ** Decode a pointer to an sqlite3 object.
       
   279 */
       
   280 extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
       
   281 
       
   282 /*
       
   283 ** Register the echo virtual table module.
       
   284 */
       
   285 static int register_tclvar_module(
       
   286   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
       
   287   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   288   int objc,              /* Number of arguments */
       
   289   Tcl_Obj *CONST objv[]  /* Command arguments */
       
   290 ){
       
   291   sqlite3 *db;
       
   292   if( objc!=2 ){
       
   293     Tcl_WrongNumArgs(interp, 1, objv, "DB");
       
   294     return TCL_ERROR;
       
   295   }
       
   296   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
       
   297 #ifndef SQLITE_OMIT_VIRTUALTABLE
       
   298   sqlite3_create_module(db, "tclvar", &tclvarModule, (void *)interp);
       
   299 #endif
       
   300   return TCL_OK;
       
   301 }
       
   302 
       
   303 #endif
       
   304 
       
   305 
       
   306 /*
       
   307 ** Register commands with the TCL interpreter.
       
   308 */
       
   309 int Sqlitetesttclvar_Init(Tcl_Interp *interp){
       
   310 #ifndef SQLITE_OMIT_VIRTUALTABLE
       
   311   static struct {
       
   312      char *zName;
       
   313      Tcl_ObjCmdProc *xProc;
       
   314      void *clientData;
       
   315   } aObjCmd[] = {
       
   316      { "register_tclvar_module",   register_tclvar_module, 0 },
       
   317   };
       
   318   int i;
       
   319   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
       
   320     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 
       
   321         aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
       
   322   }
       
   323 #endif
       
   324   return TCL_OK;
       
   325 }