os/persistentdata/persistentstorage/sqlite3api/TEST/SRC/test_tclvar.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 }