/ Check-in [d8bc6feb]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the carray() virtual table as a loadable extension.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d8bc6feb99938a2aa06142b217045e4b54c66bf1
User & Date: drh 2016-07-04 11:34:56
Context
2016-07-04
11:47
Add the sqlite3rbu_state() API. Used to determine the current state (creating OAL, ready to move OAL, incremental-checkpoint, finished or error) of an RBU operation. check-in: 0357875f user: dan tags: trunk
11:34
Add the carray() virtual table as a loadable extension. check-in: d8bc6feb user: drh tags: trunk
2016-07-03
02:35
Change the name of the intarray() extension to carray() and give it an optional third parameter that specifies the datatype as one of 'int32', 'int64', 'double', or 'char*'. 'int32' is the default. Closed-Leaf check-in: a204ba99 user: drh tags: prototype-int-array
2016-07-02
12:33
Fix a problem in table-valued functions on the RHS of an IN operator that occurs following an OOM error. check-in: bead151e user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to Makefile.in.

   412    412     $(TOP)/ext/session/test_session.c \
   413    413     $(TOP)/ext/rbu/test_rbu.c 
   414    414   
   415    415   # Statically linked extensions
   416    416   #
   417    417   TESTSRC += \
   418    418     $(TOP)/ext/misc/amatch.c \
          419  +  $(TOP)/ext/misc/carray.c \
   419    420     $(TOP)/ext/misc/closure.c \
   420    421     $(TOP)/ext/misc/csv.c \
   421    422     $(TOP)/ext/misc/eval.c \
   422    423     $(TOP)/ext/misc/fileio.c \
   423    424     $(TOP)/ext/misc/fuzzer.c \
   424    425     $(TOP)/ext/fts5/fts5_tcl.c \
   425    426     $(TOP)/ext/fts5/fts5_test_mi.c \

Changes to Makefile.msc.

  1288   1288     $(TOP)\ext\rbu\test_rbu.c \
  1289   1289     $(TOP)\ext\session\test_session.c
  1290   1290   
  1291   1291   # Statically linked extensions.
  1292   1292   #
  1293   1293   TESTEXT = \
  1294   1294     $(TOP)\ext\misc\amatch.c \
         1295  +  $(TOP)\ext\misc\carray.c \
  1295   1296     $(TOP)\ext\misc\closure.c \
  1296   1297     $(TOP)\ext\misc\csv.c \
  1297   1298     $(TOP)\ext\misc\eval.c \
  1298   1299     $(TOP)\ext\misc\fileio.c \
  1299   1300     $(TOP)\ext\misc\fuzzer.c \
  1300   1301     $(TOP)\ext\fts5\fts5_tcl.c \
  1301   1302     $(TOP)\ext\fts5\fts5_test_mi.c \

Added ext/misc/carray.c.

            1  +/*
            2  +** 2016-06-29
            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 demonstrates how to create a table-valued-function that
           14  +** returns the values in a C-language array.
           15  +** Examples:
           16  +**
           17  +**      SELECT * FROM array($ptr,5)
           18  +**
           19  +** The query above returns 5 integers contained in a C-language array
           20  +** at the address $ptr.  $ptr is a pointer to the array of integers that
           21  +** has been cast to an integer.
           22  +**
           23  +** There is an optional third parameter to determine the datatype of
           24  +** the C-language array.  Allowed values of the third parameter are
           25  +** 'int32', 'int64', 'double', 'char*'.  Example:
           26  +**
           27  +**      SELECT * FROM array($ptr,10,'char*');
           28  +**
           29  +** HOW IT WORKS
           30  +**
           31  +** The carray "function" is really a virtual table with the
           32  +** following schema:
           33  +**
           34  +**     CREATE TABLE carray(
           35  +**       value,
           36  +**       pointer HIDDEN,
           37  +**       count HIDDEN,
           38  +**       ctype TEXT HIDDEN
           39  +**     );
           40  +**
           41  +** If the hidden columns "pointer" and "count" are unconstrained, then 
           42  +** the virtual table has no rows.  Otherwise, the virtual table interprets
           43  +** the integer value of "pointer" as a pointer to the array and "count"
           44  +** as the number of elements in the array.  The virtual table steps through
           45  +** the array, element by element.
           46  +*/
           47  +#include "sqlite3ext.h"
           48  +SQLITE_EXTENSION_INIT1
           49  +#include <assert.h>
           50  +#include <string.h>
           51  +
           52  +#ifndef SQLITE_OMIT_VIRTUALTABLE
           53  +
           54  +/*
           55  +** Allowed datatypes
           56  +*/
           57  +#define CARRAY_INT32    0
           58  +#define CARRAY_INT64    1
           59  +#define CARRAY_DOUBLE   2
           60  +#define CARRAY_TEXT     3
           61  +
           62  +/*
           63  +** Names of types
           64  +*/
           65  +static const char *azType[] = { "int32", "int64", "double", "char*" };
           66  +
           67  +
           68  +/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
           69  +** serve as the underlying representation of a cursor that scans
           70  +** over rows of the result
           71  +*/
           72  +typedef struct carray_cursor carray_cursor;
           73  +struct carray_cursor {
           74  +  sqlite3_vtab_cursor base;  /* Base class - must be first */
           75  +  sqlite3_int64 iRowid;      /* The rowid */
           76  +  sqlite3_int64 iPtr;        /* Pointer to array of values */
           77  +  sqlite3_int64 iCnt;        /* Number of integers in the array */
           78  +  unsigned char eType;       /* One of the CARRAY_type values */
           79  +};
           80  +
           81  +/*
           82  +** The carrayConnect() method is invoked to create a new
           83  +** carray_vtab that describes the carray virtual table.
           84  +**
           85  +** Think of this routine as the constructor for carray_vtab objects.
           86  +**
           87  +** All this routine needs to do is:
           88  +**
           89  +**    (1) Allocate the carray_vtab object and initialize all fields.
           90  +**
           91  +**    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
           92  +**        result set of queries against carray will look like.
           93  +*/
           94  +static int carrayConnect(
           95  +  sqlite3 *db,
           96  +  void *pAux,
           97  +  int argc, const char *const*argv,
           98  +  sqlite3_vtab **ppVtab,
           99  +  char **pzErr
          100  +){
          101  +  sqlite3_vtab *pNew;
          102  +  int rc;
          103  +
          104  +/* Column numbers */
          105  +#define CARRAY_COLUMN_VALUE   0
          106  +#define CARRAY_COLUMN_POINTER 1
          107  +#define CARRAY_COLUMN_COUNT   2
          108  +#define CARRAY_COLUMN_CTYPE   3
          109  +
          110  +  rc = sqlite3_declare_vtab(db,
          111  +     "CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)");
          112  +  if( rc==SQLITE_OK ){
          113  +    pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
          114  +    if( pNew==0 ) return SQLITE_NOMEM;
          115  +    memset(pNew, 0, sizeof(*pNew));
          116  +  }
          117  +  return rc;
          118  +}
          119  +
          120  +/*
          121  +** This method is the destructor for carray_cursor objects.
          122  +*/
          123  +static int carrayDisconnect(sqlite3_vtab *pVtab){
          124  +  sqlite3_free(pVtab);
          125  +  return SQLITE_OK;
          126  +}
          127  +
          128  +/*
          129  +** Constructor for a new carray_cursor object.
          130  +*/
          131  +static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
          132  +  carray_cursor *pCur;
          133  +  pCur = sqlite3_malloc( sizeof(*pCur) );
          134  +  if( pCur==0 ) return SQLITE_NOMEM;
          135  +  memset(pCur, 0, sizeof(*pCur));
          136  +  *ppCursor = &pCur->base;
          137  +  return SQLITE_OK;
          138  +}
          139  +
          140  +/*
          141  +** Destructor for a carray_cursor.
          142  +*/
          143  +static int carrayClose(sqlite3_vtab_cursor *cur){
          144  +  sqlite3_free(cur);
          145  +  return SQLITE_OK;
          146  +}
          147  +
          148  +
          149  +/*
          150  +** Advance a carray_cursor to its next row of output.
          151  +*/
          152  +static int carrayNext(sqlite3_vtab_cursor *cur){
          153  +  carray_cursor *pCur = (carray_cursor*)cur;
          154  +  pCur->iRowid++;
          155  +  return SQLITE_OK;
          156  +}
          157  +
          158  +/*
          159  +** Return values of columns for the row at which the carray_cursor
          160  +** is currently pointing.
          161  +*/
          162  +static int carrayColumn(
          163  +  sqlite3_vtab_cursor *cur,   /* The cursor */
          164  +  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
          165  +  int i                       /* Which column to return */
          166  +){
          167  +  carray_cursor *pCur = (carray_cursor*)cur;
          168  +  sqlite3_int64 x = 0;
          169  +  switch( i ){
          170  +    case CARRAY_COLUMN_POINTER:   x = pCur->iPtr;   break;
          171  +    case CARRAY_COLUMN_COUNT:     x = pCur->iCnt;   break;
          172  +    case CARRAY_COLUMN_CTYPE: {
          173  +      sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
          174  +      return SQLITE_OK;
          175  +    }
          176  +    default: {
          177  +      switch( pCur->eType ){
          178  +        case CARRAY_INT32: {
          179  +          int *p = (int*)pCur->iPtr;
          180  +          sqlite3_result_int(ctx, p[pCur->iRowid-1]);
          181  +          return SQLITE_OK;
          182  +        }
          183  +        case CARRAY_INT64: {
          184  +          sqlite3_int64 *p = (sqlite3_int64*)pCur->iPtr;
          185  +          sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
          186  +          return SQLITE_OK;
          187  +        }
          188  +        case CARRAY_DOUBLE: {
          189  +          double *p = (double*)pCur->iPtr;
          190  +          sqlite3_result_double(ctx, p[pCur->iRowid-1]);
          191  +          return SQLITE_OK;
          192  +        }
          193  +        case CARRAY_TEXT: {
          194  +          const char **p = (const char**)pCur->iPtr;
          195  +          sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
          196  +          return SQLITE_OK;
          197  +        }
          198  +      }
          199  +    }
          200  +  }
          201  +  sqlite3_result_int64(ctx, x);
          202  +  return SQLITE_OK;
          203  +}
          204  +
          205  +/*
          206  +** Return the rowid for the current row.  In this implementation, the
          207  +** rowid is the same as the output value.
          208  +*/
          209  +static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
          210  +  carray_cursor *pCur = (carray_cursor*)cur;
          211  +  *pRowid = pCur->iRowid;
          212  +  return SQLITE_OK;
          213  +}
          214  +
          215  +/*
          216  +** Return TRUE if the cursor has been moved off of the last
          217  +** row of output.
          218  +*/
          219  +static int carrayEof(sqlite3_vtab_cursor *cur){
          220  +  carray_cursor *pCur = (carray_cursor*)cur;
          221  +  return pCur->iRowid>pCur->iCnt;
          222  +}
          223  +
          224  +/*
          225  +** This method is called to "rewind" the carray_cursor object back
          226  +** to the first row of output.
          227  +*/
          228  +static int carrayFilter(
          229  +  sqlite3_vtab_cursor *pVtabCursor, 
          230  +  int idxNum, const char *idxStr,
          231  +  int argc, sqlite3_value **argv
          232  +){
          233  +  carray_cursor *pCur = (carray_cursor *)pVtabCursor;
          234  +  if( idxNum ){
          235  +    pCur->iPtr = sqlite3_value_int64(argv[0]);
          236  +    pCur->iCnt = sqlite3_value_int64(argv[1]);
          237  +    if( idxNum<3 ){
          238  +      pCur->eType = CARRAY_INT32;
          239  +    }else{
          240  +      int i;
          241  +      const char *zType = (const char*)sqlite3_value_text(argv[2]);
          242  +      for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
          243  +        if( sqlite3_stricmp(zType, azType[i])==0 ) break;
          244  +      }
          245  +      if( i>=sizeof(azType)/sizeof(azType[0]) ){
          246  +        pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
          247  +          "unknown datatype: %Q", zType);
          248  +        return SQLITE_ERROR;
          249  +      }else{
          250  +        pCur->eType = i;
          251  +      }
          252  +    }
          253  +  }else{
          254  +    pCur->iPtr = 0;
          255  +    pCur->iCnt = 0;
          256  +  }
          257  +  pCur->iRowid = 1;
          258  +  return SQLITE_OK;
          259  +}
          260  +
          261  +/*
          262  +** SQLite will invoke this method one or more times while planning a query
          263  +** that uses the carray virtual table.  This routine needs to create
          264  +** a query plan for each invocation and compute an estimated cost for that
          265  +** plan.
          266  +**
          267  +** In this implementation idxNum is used to represent the
          268  +** query plan.  idxStr is unused.
          269  +**
          270  +** idxNum is 2 if the pointer= and count= constraints exist,
          271  +** 3 if the ctype= constraint also exists, and is 0 otherwise.
          272  +** If idxNum is 0, then carray becomes an empty table.
          273  +*/
          274  +static int carrayBestIndex(
          275  +  sqlite3_vtab *tab,
          276  +  sqlite3_index_info *pIdxInfo
          277  +){
          278  +  int i;                 /* Loop over constraints */
          279  +  int ptrIdx = -1;       /* Index of the pointer= constraint, or -1 if none */
          280  +  int cntIdx = -1;       /* Index of the count= constraint, or -1 if none */
          281  +  int ctypeIdx = -1;     /* Index of the ctype= constraint, or -1 if none */
          282  +
          283  +  const struct sqlite3_index_constraint *pConstraint;
          284  +  pConstraint = pIdxInfo->aConstraint;
          285  +  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
          286  +    if( pConstraint->usable==0 ) continue;
          287  +    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
          288  +    switch( pConstraint->iColumn ){
          289  +      case CARRAY_COLUMN_POINTER:
          290  +        ptrIdx = i;
          291  +        break;
          292  +      case CARRAY_COLUMN_COUNT:
          293  +        cntIdx = i;
          294  +        break;
          295  +      case CARRAY_COLUMN_CTYPE:
          296  +        ctypeIdx = i;
          297  +        break;
          298  +    }
          299  +  }
          300  +  if( ptrIdx>=0 && cntIdx>=0 ){
          301  +    pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
          302  +    pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
          303  +    pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
          304  +    pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
          305  +    pIdxInfo->estimatedCost = (double)1;
          306  +    pIdxInfo->estimatedRows = (double)100;
          307  +    pIdxInfo->idxNum = 2;
          308  +    if( ctypeIdx>=0 ){
          309  +      pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
          310  +      pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
          311  +      pIdxInfo->idxNum = 3;
          312  +    }
          313  +  }else{
          314  +    pIdxInfo->estimatedCost = (double)2147483647;
          315  +    pIdxInfo->estimatedRows = (double)2147483647;
          316  +    pIdxInfo->idxNum = 0;
          317  +  }
          318  +  return SQLITE_OK;
          319  +}
          320  +
          321  +/*
          322  +** This following structure defines all the methods for the 
          323  +** carray virtual table.
          324  +*/
          325  +static sqlite3_module carrayModule = {
          326  +  0,                         /* iVersion */
          327  +  0,                         /* xCreate */
          328  +  carrayConnect,             /* xConnect */
          329  +  carrayBestIndex,           /* xBestIndex */
          330  +  carrayDisconnect,          /* xDisconnect */
          331  +  0,                         /* xDestroy */
          332  +  carrayOpen,                /* xOpen - open a cursor */
          333  +  carrayClose,               /* xClose - close a cursor */
          334  +  carrayFilter,              /* xFilter - configure scan constraints */
          335  +  carrayNext,                /* xNext - advance a cursor */
          336  +  carrayEof,                 /* xEof - check for end of scan */
          337  +  carrayColumn,              /* xColumn - read data */
          338  +  carrayRowid,               /* xRowid - read data */
          339  +  0,                         /* xUpdate */
          340  +  0,                         /* xBegin */
          341  +  0,                         /* xSync */
          342  +  0,                         /* xCommit */
          343  +  0,                         /* xRollback */
          344  +  0,                         /* xFindMethod */
          345  +  0,                         /* xRename */
          346  +};
          347  +
          348  +#endif /* SQLITE_OMIT_VIRTUALTABLE */
          349  +
          350  +#ifdef _WIN32
          351  +__declspec(dllexport)
          352  +#endif
          353  +int sqlite3_carray_init(
          354  +  sqlite3 *db, 
          355  +  char **pzErrMsg, 
          356  +  const sqlite3_api_routines *pApi
          357  +){
          358  +  int rc = SQLITE_OK;
          359  +  SQLITE_EXTENSION_INIT2(pApi);
          360  +#ifndef SQLITE_OMIT_VIRTUALTABLE
          361  +  if( sqlite3_libversion_number()<3008012 ){
          362  +    *pzErrMsg = sqlite3_mprintf(
          363  +        "carray() requires SQLite 3.8.12 or later");
          364  +    return SQLITE_ERROR;
          365  +  }
          366  +  rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
          367  +#endif
          368  +  return rc;
          369  +}

Changes to main.mk.

   320    320     $(TOP)/src/test_windirent.c \
   321    321     $(TOP)/src/test_wsd.c
   322    322   
   323    323   # Extensions to be statically loaded.
   324    324   #
   325    325   TESTSRC += \
   326    326     $(TOP)/ext/misc/amatch.c \
          327  +  $(TOP)/ext/misc/carray.c \
   327    328     $(TOP)/ext/misc/closure.c \
   328    329     $(TOP)/ext/misc/csv.c \
   329    330     $(TOP)/ext/misc/eval.c \
   330    331     $(TOP)/ext/misc/fileio.c \
   331    332     $(TOP)/ext/misc/fuzzer.c \
   332    333     $(TOP)/ext/misc/ieee754.c \
   333    334     $(TOP)/ext/misc/nextchar.c \

Changes to src/test1.c.

  3236   3236     if( rc!=SQLITE_OK ){
  3237   3237       return TCL_ERROR;
  3238   3238     }
  3239   3239   
  3240   3240     return TCL_OK;
  3241   3241   }
  3242   3242   
         3243  +
         3244  +/*
         3245  +** Usage:   intarray_addr  INT  ...
         3246  +**
         3247  +** Return the address of a C-language array of 32-bit integers.
         3248  +**
         3249  +** Space to hold the array is obtained from malloc().  Call this procedure once
         3250  +** with no arguments in order to release memory.  Each call to this procedure
         3251  +** overwrites the previous array.
         3252  +*/
         3253  +static int test_intarray_addr(
         3254  +  void * clientData,
         3255  +  Tcl_Interp *interp,
         3256  +  int objc,
         3257  +  Tcl_Obj *CONST objv[]
         3258  +){
         3259  +  int i;
         3260  +  static int *p = 0;
         3261  +
         3262  +  sqlite3_free(p);
         3263  +  p = 0;
         3264  +  if( objc>1 ){
         3265  +    p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
         3266  +    if( p==0 ) return TCL_ERROR;
         3267  +    for(i=0; i<objc-1; i++){
         3268  +      if( Tcl_GetIntFromObj(interp, objv[1+i], &p[i]) ){
         3269  +        sqlite3_free(p);
         3270  +        p = 0;
         3271  +        return TCL_ERROR;
         3272  +      }
         3273  +    }
         3274  +  }  
         3275  +  Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
         3276  +  return TCL_OK;
         3277  +}
         3278  +/*
         3279  +** Usage:   intarray_addr  INT  ...
         3280  +**
         3281  +** Return the address of a C-language array of 32-bit integers.
         3282  +**
         3283  +** Space to hold the array is obtained from malloc().  Call this procedure once
         3284  +** with no arguments in order to release memory.  Each call to this procedure
         3285  +** overwrites the previous array.
         3286  +*/
         3287  +static int test_int64array_addr(
         3288  +  void * clientData,
         3289  +  Tcl_Interp *interp,
         3290  +  int objc,
         3291  +  Tcl_Obj *CONST objv[]
         3292  +){
         3293  +  int i;
         3294  +  static sqlite3_int64 *p = 0;
         3295  +
         3296  +  sqlite3_free(p);
         3297  +  p = 0;
         3298  +  if( objc>1 ){
         3299  +    p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
         3300  +    if( p==0 ) return TCL_ERROR;
         3301  +    for(i=0; i<objc-1; i++){
         3302  +      if( Tcl_GetWideIntFromObj(interp, objv[1+i], &p[i]) ){
         3303  +        sqlite3_free(p);
         3304  +        p = 0;
         3305  +        return TCL_ERROR;
         3306  +      }
         3307  +    }
         3308  +  }  
         3309  +  Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
         3310  +  return TCL_OK;
         3311  +}
         3312  +/*
         3313  +** Usage:   doublearray_addr  INT  ...
         3314  +**
         3315  +** Return the address of a C-language array of doubles.
         3316  +**
         3317  +** Space to hold the array is obtained from malloc().  Call this procedure once
         3318  +** with no arguments in order to release memory.  Each call to this procedure
         3319  +** overwrites the previous array.
         3320  +*/
         3321  +static int test_doublearray_addr(
         3322  +  void * clientData,
         3323  +  Tcl_Interp *interp,
         3324  +  int objc,
         3325  +  Tcl_Obj *CONST objv[]
         3326  +){
         3327  +  int i;
         3328  +  static double *p = 0;
         3329  +
         3330  +  sqlite3_free(p);
         3331  +  p = 0;
         3332  +  if( objc>1 ){
         3333  +    p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
         3334  +    if( p==0 ) return TCL_ERROR;
         3335  +    for(i=0; i<objc-1; i++){
         3336  +      if( Tcl_GetDoubleFromObj(interp, objv[1+i], &p[i]) ){
         3337  +        sqlite3_free(p);
         3338  +        p = 0;
         3339  +        return TCL_ERROR;
         3340  +      }
         3341  +    }
         3342  +  }  
         3343  +  Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
         3344  +  return TCL_OK;
         3345  +}
         3346  +/*
         3347  +** Usage:   textarray_addr  TEXT ...
         3348  +**
         3349  +** Return the address of a C-language array of strings.
         3350  +**
         3351  +** Space to hold the array is obtained from malloc().  Call this procedure once
         3352  +** with no arguments in order to release memory.  Each call to this procedure
         3353  +** overwrites the previous array.
         3354  +*/
         3355  +static int test_textarray_addr(
         3356  +  void * clientData,
         3357  +  Tcl_Interp *interp,
         3358  +  int objc,
         3359  +  Tcl_Obj *CONST objv[]
         3360  +){
         3361  +  int i;
         3362  +  static int n = 0;
         3363  +  static char **p = 0;
         3364  +
         3365  +  for(i=0; i<n; i++) sqlite3_free(p[i]);
         3366  +  sqlite3_free(p);
         3367  +  p = 0;
         3368  +  if( objc>1 ){
         3369  +    p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
         3370  +    if( p==0 ) return TCL_ERROR;
         3371  +    for(i=0; i<objc-1; i++){
         3372  +      p[i] = sqlite3_mprintf("%s", Tcl_GetString(objv[1+i]));
         3373  +    }
         3374  +  }  
         3375  +  Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
         3376  +  return TCL_OK;
         3377  +}
         3378  +
  3243   3379   
  3244   3380   /*
  3245   3381   ** Usage:   sqlite3_bind_int64  STMT N VALUE
  3246   3382   **
  3247   3383   ** Test the sqlite3_bind_int64 interface.  STMT is a prepared statement.
  3248   3384   ** N is the index of a wildcard in the prepared statement.  This command
  3249   3385   ** binds a 64-bit integer VALUE to that wildcard.
................................................................................
  6579   6715   static int tclLoadStaticExtensionCmd(
  6580   6716     void * clientData,
  6581   6717     Tcl_Interp *interp,
  6582   6718     int objc,
  6583   6719     Tcl_Obj *CONST objv[]
  6584   6720   ){
  6585   6721     extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
         6722  +  extern int sqlite3_carray_init(sqlite3*,char**,const sqlite3_api_routines*);
  6586   6723     extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
  6587   6724     extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*);
  6588   6725     extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
  6589   6726     extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
  6590   6727     extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
  6591   6728     extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
  6592   6729     extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
................................................................................
  6597   6734     extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
  6598   6735     extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
  6599   6736     static const struct {
  6600   6737       const char *zExtName;
  6601   6738       int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
  6602   6739     } aExtension[] = {
  6603   6740       { "amatch",                sqlite3_amatch_init               },
         6741  +    { "carray",                sqlite3_carray_init               },
  6604   6742       { "closure",               sqlite3_closure_init              },
  6605   6743       { "csv",                   sqlite3_csv_init                  },
  6606   6744       { "eval",                  sqlite3_eval_init                 },
  6607   6745       { "fileio",                sqlite3_fileio_init               },
  6608   6746       { "fuzzer",                sqlite3_fuzzer_init               },
  6609   6747       { "ieee754",               sqlite3_ieee_init                 },
  6610   6748       { "nextchar",              sqlite3_nextchar_init             },
................................................................................
  7091   7229        Tcl_ObjCmdProc *xProc;
  7092   7230        void *clientData;
  7093   7231     } aObjCmd[] = {
  7094   7232        { "sqlite3_db_config",             test_sqlite3_db_config, 0 },
  7095   7233        { "bad_behavior",                  test_bad_behavior,  (void*)&iZero },
  7096   7234        { "register_dbstat_vtab",          test_register_dbstat_vtab  },
  7097   7235        { "sqlite3_connection_pointer",    get_sqlite_pointer, 0 },
         7236  +     { "intarray_addr",                 test_intarray_addr, 0 },
         7237  +     { "int64array_addr",               test_int64array_addr, 0 },
         7238  +     { "doublearray_addr",              test_doublearray_addr, 0 },
         7239  +     { "textarray_addr",                test_textarray_addr, 0 },
  7098   7240        { "sqlite3_bind_int",              test_bind_int,      0 },
  7099   7241        { "sqlite3_bind_zeroblob",         test_bind_zeroblob, 0 },
  7100   7242        { "sqlite3_bind_zeroblob64",       test_bind_zeroblob64, 0 },
  7101   7243        { "sqlite3_bind_int64",            test_bind_int64,    0 },
  7102   7244        { "sqlite3_bind_double",           test_bind_double,   0 },
  7103   7245        { "sqlite3_bind_null",             test_bind_null     ,0 },
  7104   7246        { "sqlite3_bind_text",             test_bind_text     ,0 },

Changes to test/tabfunc01.test.

    18     18   set testprefix tabfunc01
    19     19   
    20     20   ifcapable !vtab {
    21     21     finish_test
    22     22     return
    23     23   }
    24     24   load_static_extension db series
           25  +load_static_extension db carray
    25     26   
    26     27   do_execsql_test tabfunc01-1.1 {
    27     28     SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2;
    28     29   } {1 | 3 | 5 | 7 | 9 |}
    29     30   do_execsql_test tabfunc01-1.2 {
    30     31     SELECT *, '|' FROM generate_series LIMIT 5;
    31     32   } {0 | 1 | 2 | 3 | 4 |}
................................................................................
   140    141   do_execsql_test tabfunc01-600 {
   141    142     CREATE TABLE t600(a INTEGER PRIMARY KEY, b TEXT);
   142    143     WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
   143    144       INSERT INTO t600(a,b) SELECT x, printf('(%03d)',x) FROM c;
   144    145     SELECT b FROM t600 WHERE a IN generate_series(2,52,10);
   145    146   } {(002) (012) (022) (032) (042) (052)}
   146    147   
          148  +
          149  +do_test tabfunc01-700 {
          150  +  set PTR [intarray_addr 5 7 13 17 23]
          151  +  db eval {
          152  +    SELECT b FROM t600, carray($PTR,5) WHERE a=value;
          153  +  }
          154  +} {(005) (007) (013) (017) (023)}
          155  +do_test tabfunc01-701 {
          156  +  db eval {
          157  +    SELECT b FROM t600 WHERE a IN carray($PTR,5,'int32');
          158  +  }
          159  +} {(005) (007) (013) (017) (023)}
          160  +do_test tabfunc01-702 {
          161  +  db eval {
          162  +    SELECT b FROM t600 WHERE a IN carray($PTR,4,'int32');
          163  +  }
          164  +} {(005) (007) (013) (017)}
          165  +do_catchsql_test tabfunc01-710 {
          166  +  SELECT b FROM t600 WHERE a IN carray($PTR,5,'int33');
          167  +} {1 {unknown datatype: 'int33'}}
          168  +
          169  +do_test tabfunc01-720 {
          170  +  set PTR [int64array_addr 5 7 13 17 23]
          171  +  db eval {
          172  +    SELECT b FROM t600, carray($PTR,5,'int64') WHERE a=value;
          173  +  }
          174  +} {(005) (007) (013) (017) (023)}
          175  +
          176  +do_test tabfunc01-730 {
          177  +  set PTR [doublearray_addr 5.0 7.0 13.0 17.0 23.0]
          178  +  db eval {
          179  +    SELECT b FROM t600, carray($PTR,5,'double') WHERE a=value;
          180  +  }
          181  +} {(005) (007) (013) (017) (023)}
          182  +
          183  +do_test tabfunc01-740 {
          184  +  set PTR [textarray_addr 5 7 13 17 23]
          185  +  db eval {
          186  +    SELECT b FROM t600, carray($PTR,5,'char*') WHERE a=value;
          187  +  }
          188  +} {(005) (007) (013) (017) (023)}
          189  +
          190  +
          191  +intarray_addr
          192  +int64array_addr
          193  +doublearray_addr
          194  +textarray_addr
          195  +
   147    196   finish_test