| OLD | NEW | 
 | (Empty) | 
|    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 } |  | 
| OLD | NEW |