/ Check-in [a204ba99]
Login

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

Overview
Comment: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.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | prototype-int-array
Files: files | file ages | folders
SHA1: a204ba99db34b356acb259189158a32d2df25da0
User & Date: drh 2016-07-03 02:35:47
Context
2016-07-04
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
20:57
Fix an off-by-one comparison in the intarray() virtual table. Get the intarray() virtual table tests working using the legacy makefile. check-in: 7c3d441f user: drh tags: prototype-int-array
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace 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/array.c \
          419  +  $(TOP)/ext/misc/carray.c \
   420    420     $(TOP)/ext/misc/closure.c \
   421    421     $(TOP)/ext/misc/csv.c \
   422    422     $(TOP)/ext/misc/eval.c \
   423    423     $(TOP)/ext/misc/fileio.c \
   424    424     $(TOP)/ext/misc/fuzzer.c \
   425    425     $(TOP)/ext/fts5/fts5_tcl.c \
   426    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 \

Name change from ext/misc/array.c to ext/misc/carray.c.

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

Changes to src/test1.c.

  3238   3238     }
  3239   3239   
  3240   3240     return TCL_OK;
  3241   3241   }
  3242   3242   
  3243   3243   
  3244   3244   /*
  3245         -** Usage:   sqlite3_bind_intarray  STMT N INT  ...
         3245  +** Usage:   intarray_addr  INT  ...
  3246   3246   **
  3247         -** Create a C-language array of integers from the arguments.  Bind a pointer
  3248         -** to this array to the NAME parameter of STMT.
         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.
  3249   3252   */
  3250         -static int test_bind_intarray(
         3253  +static int test_intarray_addr(
  3251   3254     void * clientData,
  3252   3255     Tcl_Interp *interp,
  3253   3256     int objc,
  3254   3257     Tcl_Obj *CONST objv[]
  3255   3258   ){
  3256         -  sqlite3_stmt *pStmt;
  3257         -  int idx;
  3258   3259     int i;
  3259   3260     static int *p = 0;
  3260   3261   
  3261   3262     sqlite3_free(p);
  3262   3263     p = 0;
  3263         -  if( objc<4 ){
  3264         -    Tcl_AppendResult(interp, "wrong # args: should be \"",
  3265         -        Tcl_GetStringFromObj(objv[0], 0), " STMT NAME INT...", 0);
  3266         -    return TCL_ERROR;
  3267         -  }
  3268         -
  3269         -  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  3270         -  if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
  3271         -  p = sqlite3_malloc( sizeof(int)*(objc-3) );
  3272         -  if( p==0 ) return TCL_ERROR;
  3273         -  for(i=0; i<objc-3; i++){
  3274         -    if( Tcl_GetIntFromObj(interp, objv[3+i], &p[i]) ){
  3275         -      sqlite3_free(p);
  3276         -      return TCL_ERROR;
         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]));
  3277   3373       }
  3278   3374     }  
  3279         -  sqlite3_bind_int64(pStmt, idx, (sqlite3_int64)p);
         3375  +  Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
  3280   3376     return TCL_OK;
  3281   3377   }
  3282   3378   
  3283   3379   
  3284   3380   /*
  3285   3381   ** Usage:   sqlite3_bind_int64  STMT N VALUE
  3286   3382   **
................................................................................
  6619   6715   static int tclLoadStaticExtensionCmd(
  6620   6716     void * clientData,
  6621   6717     Tcl_Interp *interp,
  6622   6718     int objc,
  6623   6719     Tcl_Obj *CONST objv[]
  6624   6720   ){
  6625   6721     extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
  6626         -  extern int sqlite3_array_init(sqlite3*,char**,const sqlite3_api_routines*);
         6722  +  extern int sqlite3_carray_init(sqlite3*,char**,const sqlite3_api_routines*);
  6627   6723     extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
  6628   6724     extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*);
  6629   6725     extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
  6630   6726     extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
  6631   6727     extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
  6632   6728     extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
  6633   6729     extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
................................................................................
  6638   6734     extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
  6639   6735     extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
  6640   6736     static const struct {
  6641   6737       const char *zExtName;
  6642   6738       int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
  6643   6739     } aExtension[] = {
  6644   6740       { "amatch",                sqlite3_amatch_init               },
  6645         -    { "array",                 sqlite3_array_init                },
         6741  +    { "carray",                sqlite3_carray_init               },
  6646   6742       { "closure",               sqlite3_closure_init              },
  6647   6743       { "csv",                   sqlite3_csv_init                  },
  6648   6744       { "eval",                  sqlite3_eval_init                 },
  6649   6745       { "fileio",                sqlite3_fileio_init               },
  6650   6746       { "fuzzer",                sqlite3_fuzzer_init               },
  6651   6747       { "ieee754",               sqlite3_ieee_init                 },
  6652   6748       { "nextchar",              sqlite3_nextchar_init             },
................................................................................
  7133   7229        Tcl_ObjCmdProc *xProc;
  7134   7230        void *clientData;
  7135   7231     } aObjCmd[] = {
  7136   7232        { "sqlite3_db_config",             test_sqlite3_db_config, 0 },
  7137   7233        { "bad_behavior",                  test_bad_behavior,  (void*)&iZero },
  7138   7234        { "register_dbstat_vtab",          test_register_dbstat_vtab  },
  7139   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 },
  7140   7240        { "sqlite3_bind_int",              test_bind_int,      0 },
  7141         -     { "sqlite3_bind_intarray",         test_bind_intarray, 0 },
  7142   7241        { "sqlite3_bind_zeroblob",         test_bind_zeroblob, 0 },
  7143   7242        { "sqlite3_bind_zeroblob64",       test_bind_zeroblob64, 0 },
  7144   7243        { "sqlite3_bind_int64",            test_bind_int64,    0 },
  7145   7244        { "sqlite3_bind_double",           test_bind_double,   0 },
  7146   7245        { "sqlite3_bind_null",             test_bind_null     ,0 },
  7147   7246        { "sqlite3_bind_text",             test_bind_text     ,0 },
  7148   7247        { "sqlite3_bind_text16",           test_bind_text16   ,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 array
           25  +load_static_extension db carray
    26     26   
    27     27   do_execsql_test tabfunc01-1.1 {
    28     28     SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2;
    29     29   } {1 | 3 | 5 | 7 | 9 |}
    30     30   do_execsql_test tabfunc01-1.2 {
    31     31     SELECT *, '|' FROM generate_series LIMIT 5;
    32     32   } {0 | 1 | 2 | 3 | 4 |}
................................................................................
   142    142     CREATE TABLE t600(a INTEGER PRIMARY KEY, b TEXT);
   143    143     WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
   144    144       INSERT INTO t600(a,b) SELECT x, printf('(%03d)',x) FROM c;
   145    145     SELECT b FROM t600 WHERE a IN generate_series(2,52,10);
   146    146   } {(002) (012) (022) (032) (042) (052)}
   147    147   
   148    148   
   149         -do_test tabfunc01-600 {
   150         -  set TAIL {}
   151         -  set VM [sqlite3_prepare db {SELECT * FROM intarray(?2,?3)} -1 TAIL]
   152         -  set TAIL
   153         -} {}
   154         -do_test tabfunc01-610 {
   155         -  sqlite3_bind_intarray $VM 2 11 22 33 44 55
   156         -  sqlite3_bind_int $VM 3 4
   157         -  sqlite3_step $VM
   158         -} SQLITE_ROW
   159         -do_test tabfunc01-620 {
   160         -  sqlite3_column_int $VM 0
   161         -} 11
   162         -do_test tabfunc01-621 {
   163         -  sqlite3_step $VM
   164         -  sqlite3_column_int $VM 0
   165         -} 22
   166         -sqlite3_finalize $VM
          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)}
   167    182   
   168         -do_test tabfunc01-650 {
          183  +do_test tabfunc01-740 {
          184  +  set PTR [textarray_addr 5 7 13 17 23]
   169    185     db eval {
   170         -    DROP TABLE IF EXISTS t6;
   171         -    CREATE TABLE t6(x INTEGER PRIMARY KEY, y BLOB);
   172         -    WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
   173         -      INSERT INTO t6(x,y) SELECT x, randomblob(x) FROM c;
          186  +    SELECT b FROM t600, carray($PTR,5,'char*') WHERE a=value;
   174    187     }
   175         -  set TAIL {}
   176         -  set VM [sqlite3_prepare db {
   177         -     SELECT length(y) FROM t6 WHERE x IN (SELECT value FROM intarray(?1,3));
   178         -  } -1 TAIL]
   179         -  string trim $TAIL
   180         -} {}
   181         -do_test tabfunc01-660 {
   182         -  sqlite3_bind_intarray $VM 1 11 22 33 44 55
   183         -  sqlite3_step $VM
   184         -} SQLITE_ROW
   185         -do_test tabfunc01-661 {
   186         -  sqlite3_column_int $VM 0
   187         -} 11
   188         -sqlite3_finalize $VM
          188  +} {(005) (007) (013) (017) (023)}
          189  +
   189    190   
   190         -do_test tabfunc01-670 {
   191         -  set TAIL {}
   192         -  set VM [sqlite3_prepare db {
   193         -     SELECT length(y) FROM t6 WHERE x IN intarray(?1,3);
   194         -  } -1 TAIL]
   195         -  string trim $TAIL
   196         -} {}
   197         -do_test tabfunc01-671 {
   198         -  sqlite3_bind_intarray $VM 1 11 22 33 44 55
   199         -  sqlite3_step $VM
   200         -} SQLITE_ROW
   201         -do_test tabfunc01-672 {
   202         -  sqlite3_column_int $VM 0
   203         -} 11
   204         -do_test tabfunc01-673 {
   205         -  sqlite3_step $VM
   206         -  sqlite3_column_int $VM 0
   207         -} 22
   208         -do_test tabfunc01-674 {
   209         -  sqlite3_step $VM
   210         -  sqlite3_column_int $VM 0
   211         -} 33
   212         -do_test tabfunc01-675 {
   213         -  sqlite3_step $VM
   214         -} {SQLITE_DONE}
   215         -sqlite3_finalize $VM
   216         -
   217         -catch {sqlite3_bind_intarray}
          191  +intarray_addr
          192  +int64array_addr
          193  +doublearray_addr
          194  +textarray_addr
   218    195   
   219    196   finish_test