modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test_intarray.c (about)

     1  /*
     2  ** 2009 November 10
     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  **
    13  ** This file implements a read-only VIRTUAL TABLE that contains the
    14  ** content of a C-language array of integer values.  See the corresponding
    15  ** header file for full details.
    16  */
    17  #include "test_intarray.h"
    18  #include <string.h>
    19  #include <assert.h>
    20  
    21  
    22  /*
    23  ** Definition of the sqlite3_intarray object.
    24  **
    25  ** The internal representation of an intarray object is subject
    26  ** to change, is not externally visible, and should be used by
    27  ** the implementation of intarray only.  This object is opaque
    28  ** to users.
    29  */
    30  struct sqlite3_intarray {
    31    int n;                    /* Number of elements in the array */
    32    sqlite3_int64 *a;         /* Contents of the array */
    33    void (*xFree)(void*);     /* Function used to free a[] */
    34  };
    35  
    36  /* Objects used internally by the virtual table implementation */
    37  typedef struct intarray_vtab intarray_vtab;
    38  typedef struct intarray_cursor intarray_cursor;
    39  
    40  /* An intarray table object */
    41  struct intarray_vtab {
    42    sqlite3_vtab base;            /* Base class */
    43    sqlite3_intarray *pContent;   /* Content of the integer array */
    44  };
    45  
    46  /* An intarray cursor object */
    47  struct intarray_cursor {
    48    sqlite3_vtab_cursor base;    /* Base class */
    49    int i;                       /* Current cursor position */
    50  };
    51  
    52  /*
    53  ** None of this works unless we have virtual tables.
    54  */
    55  #ifndef SQLITE_OMIT_VIRTUALTABLE
    56  
    57  /*
    58  ** Free an sqlite3_intarray object.
    59  */
    60  static void intarrayFree(sqlite3_intarray *p){
    61    if( p->xFree ){
    62      p->xFree(p->a);
    63    }
    64    sqlite3_free(p);
    65  }
    66  
    67  /*
    68  ** Table destructor for the intarray module.
    69  */
    70  static int intarrayDestroy(sqlite3_vtab *p){
    71    intarray_vtab *pVtab = (intarray_vtab*)p;
    72    sqlite3_free(pVtab);
    73    return 0;
    74  }
    75  
    76  /*
    77  ** Table constructor for the intarray module.
    78  */
    79  static int intarrayCreate(
    80    sqlite3 *db,              /* Database where module is created */
    81    void *pAux,               /* clientdata for the module */
    82    int argc,                 /* Number of arguments */
    83    const char *const*argv,   /* Value for all arguments */
    84    sqlite3_vtab **ppVtab,    /* Write the new virtual table object here */
    85    char **pzErr              /* Put error message text here */
    86  ){
    87    int rc = SQLITE_NOMEM;
    88    intarray_vtab *pVtab = sqlite3_malloc64(sizeof(intarray_vtab));
    89  
    90    if( pVtab ){
    91      memset(pVtab, 0, sizeof(intarray_vtab));
    92      pVtab->pContent = (sqlite3_intarray*)pAux;
    93      rc = sqlite3_declare_vtab(db, "CREATE TABLE x(value INTEGER PRIMARY KEY)");
    94    }
    95    *ppVtab = (sqlite3_vtab *)pVtab;
    96    return rc;
    97  }
    98  
    99  /*
   100  ** Open a new cursor on the intarray table.
   101  */
   102  static int intarrayOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
   103    int rc = SQLITE_NOMEM;
   104    intarray_cursor *pCur;
   105    pCur = sqlite3_malloc64(sizeof(intarray_cursor));
   106    if( pCur ){
   107      memset(pCur, 0, sizeof(intarray_cursor));
   108      *ppCursor = (sqlite3_vtab_cursor *)pCur;
   109      rc = SQLITE_OK;
   110    }
   111    return rc;
   112  }
   113  
   114  /*
   115  ** Close a intarray table cursor.
   116  */
   117  static int intarrayClose(sqlite3_vtab_cursor *cur){
   118    intarray_cursor *pCur = (intarray_cursor *)cur;
   119    sqlite3_free(pCur);
   120    return SQLITE_OK;
   121  }
   122  
   123  /*
   124  ** Retrieve a column of data.
   125  */
   126  static int intarrayColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
   127    intarray_cursor *pCur = (intarray_cursor*)cur;
   128    intarray_vtab *pVtab = (intarray_vtab*)cur->pVtab;
   129    if( pCur->i>=0 && pCur->i<pVtab->pContent->n ){
   130      sqlite3_result_int64(ctx, pVtab->pContent->a[pCur->i]);
   131    }
   132    return SQLITE_OK;
   133  }
   134  
   135  /*
   136  ** Retrieve the current rowid.
   137  */
   138  static int intarrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
   139    intarray_cursor *pCur = (intarray_cursor *)cur;
   140    *pRowid = pCur->i;
   141    return SQLITE_OK;
   142  }
   143  
   144  static int intarrayEof(sqlite3_vtab_cursor *cur){
   145    intarray_cursor *pCur = (intarray_cursor *)cur;
   146    intarray_vtab *pVtab = (intarray_vtab *)cur->pVtab;
   147    return pCur->i>=pVtab->pContent->n;
   148  }
   149  
   150  /*
   151  ** Advance the cursor to the next row.
   152  */
   153  static int intarrayNext(sqlite3_vtab_cursor *cur){
   154    intarray_cursor *pCur = (intarray_cursor *)cur;
   155    pCur->i++;
   156    return SQLITE_OK;
   157  }
   158  
   159  /*
   160  ** Reset a intarray table cursor.
   161  */
   162  static int intarrayFilter(
   163    sqlite3_vtab_cursor *pVtabCursor, 
   164    int idxNum, const char *idxStr,
   165    int argc, sqlite3_value **argv
   166  ){
   167    intarray_cursor *pCur = (intarray_cursor *)pVtabCursor;
   168    pCur->i = 0;
   169    return SQLITE_OK;
   170  }
   171  
   172  /*
   173  ** Analyse the WHERE condition.
   174  */
   175  static int intarrayBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
   176    return SQLITE_OK;
   177  }
   178  
   179  /*
   180  ** A virtual table module that merely echos method calls into TCL
   181  ** variables.
   182  */
   183  static sqlite3_module intarrayModule = {
   184    0,                           /* iVersion */
   185    intarrayCreate,              /* xCreate - create a new virtual table */
   186    intarrayCreate,              /* xConnect - connect to an existing vtab */
   187    intarrayBestIndex,           /* xBestIndex - find the best query index */
   188    intarrayDestroy,             /* xDisconnect - disconnect a vtab */
   189    intarrayDestroy,             /* xDestroy - destroy a vtab */
   190    intarrayOpen,                /* xOpen - open a cursor */
   191    intarrayClose,               /* xClose - close a cursor */
   192    intarrayFilter,              /* xFilter - configure scan constraints */
   193    intarrayNext,                /* xNext - advance a cursor */
   194    intarrayEof,                 /* xEof */
   195    intarrayColumn,              /* xColumn - read data */
   196    intarrayRowid,               /* xRowid - read data */
   197    0,                           /* xUpdate */
   198    0,                           /* xBegin */
   199    0,                           /* xSync */
   200    0,                           /* xCommit */
   201    0,                           /* xRollback */
   202    0,                           /* xFindMethod */
   203    0,                           /* xRename */
   204  };
   205  
   206  #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
   207  
   208  /*
   209  ** Invoke this routine to create a specific instance of an intarray object.
   210  ** The new intarray object is returned by the 3rd parameter.
   211  **
   212  ** Each intarray object corresponds to a virtual table in the TEMP table
   213  ** with a name of zName.
   214  **
   215  ** Destroy the intarray object by dropping the virtual table.  If not done
   216  ** explicitly by the application, the virtual table will be dropped implicitly
   217  ** by the system when the database connection is closed.
   218  */
   219  SQLITE_API int sqlite3_intarray_create(
   220    sqlite3 *db,
   221    const char *zName,
   222    sqlite3_intarray **ppReturn
   223  ){
   224    int rc = SQLITE_OK;
   225  #ifndef SQLITE_OMIT_VIRTUALTABLE
   226    sqlite3_intarray *p;
   227  
   228    *ppReturn = p = sqlite3_malloc64( sizeof(*p) );
   229    if( p==0 ){
   230      return SQLITE_NOMEM;
   231    }
   232    memset(p, 0, sizeof(*p));
   233    rc = sqlite3_create_module_v2(db, zName, &intarrayModule, p,
   234                                  (void(*)(void*))intarrayFree);
   235    if( rc==SQLITE_OK ){
   236      char *zSql;
   237      zSql = sqlite3_mprintf("CREATE VIRTUAL TABLE temp.%Q USING %Q",
   238                             zName, zName);
   239      rc = sqlite3_exec(db, zSql, 0, 0, 0);
   240      sqlite3_free(zSql);
   241    }
   242  #endif
   243    return rc;
   244  }
   245  
   246  /*
   247  ** Bind a new array array of integers to a specific intarray object.
   248  **
   249  ** The array of integers bound must be unchanged for the duration of
   250  ** any query against the corresponding virtual table.  If the integer
   251  ** array does change or is deallocated undefined behavior will result.
   252  */
   253  SQLITE_API int sqlite3_intarray_bind(
   254    sqlite3_intarray *pIntArray,   /* The intarray object to bind to */
   255    int nElements,                 /* Number of elements in the intarray */
   256    sqlite3_int64 *aElements,      /* Content of the intarray */
   257    void (*xFree)(void*)           /* How to dispose of the intarray when done */
   258  ){
   259    if( pIntArray->xFree ){
   260      pIntArray->xFree(pIntArray->a);
   261    }
   262    pIntArray->n = nElements;
   263    pIntArray->a = aElements;
   264    pIntArray->xFree = xFree;
   265    return SQLITE_OK;
   266  }
   267  
   268  
   269  /*****************************************************************************
   270  ** Everything below is interface for testing this module.
   271  */
   272  #ifdef SQLITE_TEST
   273  #if defined(INCLUDE_SQLITE_TCL_H)
   274  #  include "sqlite_tcl.h"
   275  #else
   276  #  include "tcl.h"
   277  #  ifndef SQLITE_TCLAPI
   278  #    define SQLITE_TCLAPI
   279  #  endif
   280  #endif
   281  
   282  /*
   283  ** Routines to encode and decode pointers
   284  */
   285  extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
   286  extern void *sqlite3TestTextToPtr(const char*);
   287  extern int sqlite3TestMakePointerStr(Tcl_Interp*, char *zPtr, void*);
   288  extern const char *sqlite3ErrName(int);
   289  
   290  /*
   291  **    sqlite3_intarray_create  DB  NAME
   292  **
   293  ** Invoke the sqlite3_intarray_create interface.  A string that becomes
   294  ** the first parameter to sqlite3_intarray_bind.
   295  */
   296  static int SQLITE_TCLAPI test_intarray_create(
   297    ClientData clientData, /* Not used */
   298    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   299    int objc,              /* Number of arguments */
   300    Tcl_Obj *CONST objv[]  /* Command arguments */
   301  ){
   302    sqlite3 *db;
   303    const char *zName;
   304    sqlite3_intarray *pArray;
   305    int rc = SQLITE_OK;
   306    char zPtr[100];
   307  
   308    if( objc!=3 ){
   309      Tcl_WrongNumArgs(interp, 1, objv, "DB");
   310      return TCL_ERROR;
   311    }
   312    if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
   313    zName = Tcl_GetString(objv[2]);
   314  #ifndef SQLITE_OMIT_VIRTUALTABLE
   315    rc = sqlite3_intarray_create(db, zName, &pArray);
   316  #endif
   317    if( rc!=SQLITE_OK ){
   318      assert( pArray==0 );
   319      Tcl_AppendResult(interp, sqlite3ErrName(rc), (char*)0);
   320      return TCL_ERROR;
   321    }
   322    sqlite3TestMakePointerStr(interp, zPtr, pArray);
   323    Tcl_AppendResult(interp, zPtr, (char*)0);
   324    return TCL_OK;
   325  }
   326  
   327  /*
   328  **    sqlite3_intarray_bind  INTARRAY  ?VALUE ...?
   329  **
   330  ** Invoke the sqlite3_intarray_bind interface on the given array of integers.
   331  */
   332  static int SQLITE_TCLAPI test_intarray_bind(
   333    ClientData clientData, /* Not used */
   334    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   335    int objc,              /* Number of arguments */
   336    Tcl_Obj *CONST objv[]  /* Command arguments */
   337  ){
   338    sqlite3_intarray *pArray;
   339    int rc = SQLITE_OK;
   340    int i, n;
   341    sqlite3_int64 *a;
   342  
   343    if( objc<2 ){
   344      Tcl_WrongNumArgs(interp, 1, objv, "INTARRAY");
   345      return TCL_ERROR;
   346    }
   347    pArray = (sqlite3_intarray*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
   348    n = objc - 2;
   349  #ifndef SQLITE_OMIT_VIRTUALTABLE
   350    a = sqlite3_malloc64( sizeof(a[0])*n );
   351    if( a==0 ){
   352      Tcl_AppendResult(interp, "SQLITE_NOMEM", (char*)0);
   353      return TCL_ERROR;
   354    }
   355    for(i=0; i<n; i++){
   356      Tcl_WideInt x = 0;
   357      Tcl_GetWideIntFromObj(0, objv[i+2], &x);
   358      a[i] = x;
   359    }
   360    rc = sqlite3_intarray_bind(pArray, n, a, sqlite3_free);
   361    if( rc!=SQLITE_OK ){
   362      Tcl_AppendResult(interp, sqlite3ErrName(rc), (char*)0);
   363      return TCL_ERROR;
   364    }
   365  #endif
   366    return TCL_OK;
   367  }
   368  
   369  /*
   370  ** Register commands with the TCL interpreter.
   371  */
   372  int Sqlitetestintarray_Init(Tcl_Interp *interp){
   373    static struct {
   374       char *zName;
   375       Tcl_ObjCmdProc *xProc;
   376       void *clientData;
   377    } aObjCmd[] = {
   378       { "sqlite3_intarray_create", test_intarray_create, 0 },
   379       { "sqlite3_intarray_bind", test_intarray_bind, 0 },
   380    };
   381    int i;
   382    for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
   383      Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 
   384          aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
   385    }
   386    return TCL_OK;
   387  }
   388  
   389  #endif /* SQLITE_TEST */