/ Check-in [a99fa94d]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Update the carray() and remember() extension functions so that they user the new sqlite3_value_pointer() interface.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | bind-pointer
Files: files | file ages | folders
SHA3-256: a99fa94db7185b8eaf3c9b184cb1479f8b3d5781f71f1717a4b3f2dd1d184fe4
User & Date: drh 2017-06-30 23:46:16
Context
2017-07-07
14:26
Merge recent enhancements from trunk. check-in: 73d0fc02 user: drh tags: bind-pointer
2017-06-30
23:46
Update the carray() and remember() extension functions so that they user the new sqlite3_value_pointer() interface. check-in: a99fa94d user: drh tags: bind-pointer
23:09
Add APIs for binding pointers that can be used by app-defined functions. check-in: d9f4a831 user: drh tags: bind-pointer
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/misc/carray.c.

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
...
341
342
343
344
345
346
347




























348
349
350
351
352
353
354
...
355
356
357
358
359
360
361





362

363
364
** serve as the underlying representation of a cursor that scans
** over rows of the result
*/
typedef struct carray_cursor carray_cursor;
struct carray_cursor {
  sqlite3_vtab_cursor base;  /* Base class - must be first */
  sqlite3_int64 iRowid;      /* The rowid */
  sqlite3_int64 iPtr;        /* Pointer to array of values */
  sqlite3_int64 iCnt;        /* Number of integers in the array */
  unsigned char eType;       /* One of the CARRAY_type values */
};

/*
** The carrayConnect() method is invoked to create a new
** carray_vtab that describes the carray virtual table.
................................................................................
  sqlite3_vtab_cursor *cur,   /* The cursor */
  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
  int i                       /* Which column to return */
){
  carray_cursor *pCur = (carray_cursor*)cur;
  sqlite3_int64 x = 0;
  switch( i ){
    case CARRAY_COLUMN_POINTER:   x = pCur->iPtr;   break;
    case CARRAY_COLUMN_COUNT:     x = pCur->iCnt;   break;
    case CARRAY_COLUMN_CTYPE: {
      sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
      return SQLITE_OK;
    }
    default: {
      switch( pCur->eType ){
        case CARRAY_INT32: {
          int *p = (int*)pCur->iPtr;
          sqlite3_result_int(ctx, p[pCur->iRowid-1]);
          return SQLITE_OK;
        }
        case CARRAY_INT64: {
          sqlite3_int64 *p = (sqlite3_int64*)pCur->iPtr;
          sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
          return SQLITE_OK;
        }
        case CARRAY_DOUBLE: {
          double *p = (double*)pCur->iPtr;
          sqlite3_result_double(ctx, p[pCur->iRowid-1]);
          return SQLITE_OK;
        }
        case CARRAY_TEXT: {
          const char **p = (const char**)pCur->iPtr;
          sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
          return SQLITE_OK;
        }
      }
    }
  }
  sqlite3_result_int64(ctx, x);
................................................................................
static int carrayFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  carray_cursor *pCur = (carray_cursor *)pVtabCursor;
  if( idxNum ){
    pCur->iPtr = sqlite3_value_int64(argv[0]);
    pCur->iCnt = sqlite3_value_int64(argv[1]);
    if( idxNum<3 ){
      pCur->eType = CARRAY_INT32;
    }else{
      unsigned char i;
      const char *zType = (const char*)sqlite3_value_text(argv[2]);
      for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
        if( sqlite3_stricmp(zType, azType[i])==0 ) break;
................................................................................
          "unknown datatype: %Q", zType);
        return SQLITE_ERROR;
      }else{
        pCur->eType = i;
      }
    }
  }else{
    pCur->iPtr = 0;
    pCur->iCnt = 0;
  }
  pCur->iRowid = 1;
  return SQLITE_OK;
}

/*
................................................................................
  0,                         /* xSync */
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
};





























#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_carray_init(
  sqlite3 *db, 
................................................................................
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  rc = sqlite3_create_module(db, "carray", &carrayModule, 0);





#endif

  return rc;
}







|







 







|








|




|




|




|







 







|
|







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
|
>


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
...
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
** serve as the underlying representation of a cursor that scans
** over rows of the result
*/
typedef struct carray_cursor carray_cursor;
struct carray_cursor {
  sqlite3_vtab_cursor base;  /* Base class - must be first */
  sqlite3_int64 iRowid;      /* The rowid */
  void *pPtr;                /* Pointer to the array of values */
  sqlite3_int64 iCnt;        /* Number of integers in the array */
  unsigned char eType;       /* One of the CARRAY_type values */
};

/*
** The carrayConnect() method is invoked to create a new
** carray_vtab that describes the carray virtual table.
................................................................................
  sqlite3_vtab_cursor *cur,   /* The cursor */
  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
  int i                       /* Which column to return */
){
  carray_cursor *pCur = (carray_cursor*)cur;
  sqlite3_int64 x = 0;
  switch( i ){
    case CARRAY_COLUMN_POINTER:   return SQLITE_OK;
    case CARRAY_COLUMN_COUNT:     x = pCur->iCnt;   break;
    case CARRAY_COLUMN_CTYPE: {
      sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
      return SQLITE_OK;
    }
    default: {
      switch( pCur->eType ){
        case CARRAY_INT32: {
          int *p = (int*)pCur->pPtr;
          sqlite3_result_int(ctx, p[pCur->iRowid-1]);
          return SQLITE_OK;
        }
        case CARRAY_INT64: {
          sqlite3_int64 *p = (sqlite3_int64*)pCur->pPtr;
          sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
          return SQLITE_OK;
        }
        case CARRAY_DOUBLE: {
          double *p = (double*)pCur->pPtr;
          sqlite3_result_double(ctx, p[pCur->iRowid-1]);
          return SQLITE_OK;
        }
        case CARRAY_TEXT: {
          const char **p = (const char**)pCur->pPtr;
          sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
          return SQLITE_OK;
        }
      }
    }
  }
  sqlite3_result_int64(ctx, x);
................................................................................
static int carrayFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  carray_cursor *pCur = (carray_cursor *)pVtabCursor;
  if( idxNum ){
    pCur->pPtr = sqlite3_value_pointer(argv[0]);
    pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
    if( idxNum<3 ){
      pCur->eType = CARRAY_INT32;
    }else{
      unsigned char i;
      const char *zType = (const char*)sqlite3_value_text(argv[2]);
      for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
        if( sqlite3_stricmp(zType, azType[i])==0 ) break;
................................................................................
          "unknown datatype: %Q", zType);
        return SQLITE_ERROR;
      }else{
        pCur->eType = i;
      }
    }
  }else{
    pCur->pPtr = 0;
    pCur->iCnt = 0;
  }
  pCur->iRowid = 1;
  return SQLITE_OK;
}

/*
................................................................................
  0,                         /* xSync */
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
};

/*
** For testing purpose in the TCL test harness, we need a method for
** setting the pointer value.  The inttoptr(X) SQL function accomplishes
** this.  Tcl script will bind an integer to X and the inttoptr() SQL
** function will use sqlite3_result_pointer() to convert that integer into
** a pointer.
**
** This is for testing on TCL only.
*/
#ifdef SQLITE_TEST
static void inttoptrFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  void *p;
  sqlite3_int64 i64;
  i64 = sqlite3_value_int64(argv[0]);
  if( sizeof(i64)==sizeof(p) ){
    memcpy(&p, &i64, sizeof(p));
  }else{
    int i32 = i64 & 0xffffffff;
    memcpy(&p, &i32, sizeof(p));
  }
  sqlite3_result_pointer(context, p);
}
#endif /* SQLITE_TEST */

#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_carray_init(
  sqlite3 *db, 
................................................................................
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
#ifdef SQLITE_TEST
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
                                 inttoptrFunc, 0, 0);
  }
#endif /* SQLITE_TEST */
#endif /* SQLITE_OMIT_VIRTUALTABLE */
  return rc;
}

Changes to ext/misc/remember.c.

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
*/
static void rememberFunc(
  sqlite3_context *pCtx,
  int argc,
  sqlite3_value **argv
){
  sqlite3_int64 v;
  sqlite3_int64 ptr;
  assert( argc==2 );
  v = sqlite3_value_int64(argv[0]);
  ptr = sqlite3_value_int64(argv[1]);
  *((sqlite3_int64*)ptr) = v;
  sqlite3_result_int64(pCtx, v);
}

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_remember_init(







|


|
|







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
*/
static void rememberFunc(
  sqlite3_context *pCtx,
  int argc,
  sqlite3_value **argv
){
  sqlite3_int64 v;
  sqlite3_int64 *ptr;
  assert( argc==2 );
  v = sqlite3_value_int64(argv[0]);
  ptr = sqlite3_value_pointer(argv[1]);
  if( ptr ) *ptr = v;
  sqlite3_result_int64(pCtx, v);
}

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_remember_init(

Changes to test/tabfunc01.test.

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  SELECT b FROM t600 WHERE a IN generate_series(2,52,10);
} {(002) (012) (022) (032) (042) (052)}


do_test tabfunc01-700 {
  set PTR1 [intarray_addr 5 7 13 17 23]
  db eval {
    SELECT b FROM t600, carray($PTR1,5) WHERE a=value;
  }
} {(005) (007) (013) (017) (023)}
do_test tabfunc01-701 {
  db eval {
    SELECT b FROM t600 WHERE a IN carray($PTR1,5,'int32');
  }
} {(005) (007) (013) (017) (023)}
do_test tabfunc01-702 {
  db eval {
    SELECT b FROM t600 WHERE a IN carray($PTR1,4,'int32');
  }
} {(005) (007) (013) (017)}
do_catchsql_test tabfunc01-710 {
  SELECT b FROM t600 WHERE a IN carray($PTR1,5,'int33');
} {1 {unknown datatype: 'int33'}}

do_test tabfunc01-720 {
  set PTR2 [int64array_addr 5 7 13 17 23]
  db eval {
    SELECT b FROM t600, carray($PTR2,5,'int64') WHERE a=value;
  }
} {(005) (007) (013) (017) (023)}
do_test tabfunc01-721 {
  db eval {
    SELECT remember(123,$PTR2);
    SELECT value FROM carray($PTR2,5,'int64');
  }
} {123 123 7 13 17 23}
do_test tabfunc01-722 {
  set PTR3 [expr {$PTR2+16}]
  db eval {
    SELECT remember(987,$PTR3);
    SELECT value FROM carray($PTR2,5,'int64');
  }
} {987 123 7 987 17 23}

do_test tabfunc01-730 {
  set PTR4 [doublearray_addr 5.0 7.0 13.0 17.0 23.0]
  db eval {
    SELECT b FROM t600, carray($PTR4,5,'double') WHERE a=value;
  }
} {(005) (007) (013) (017) (023)}

do_test tabfunc01-740 {
  set PTR5 [textarray_addr x5 x7 x13 x17 x23]
  db eval {

    SELECT b FROM t600, carray($PTR5,5,'char*') WHERE a=trim(value,'x');
  }
} {(005) (007) (013) (017) (023)}

do_test tabfunc01-750 {
  db eval {
    SELECT aa.value, bb.value, '|'
      FROM carray($PTR4,5,'double') AS aa
      JOIN carray($PTR5,5,'char*') AS bb ON aa.rowid=bb.rowid;
  }
} {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |}

# Free up memory allocations
intarray_addr
int64array_addr
doublearray_addr
textarray_addr

finish_test







|




|




|



|





|




|
|





|
|






|






>
|






|
|










146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  SELECT b FROM t600 WHERE a IN generate_series(2,52,10);
} {(002) (012) (022) (032) (042) (052)}


do_test tabfunc01-700 {
  set PTR1 [intarray_addr 5 7 13 17 23]
  db eval {
    SELECT b FROM t600, carray(inttoptr($PTR1),5) WHERE a=value;
  }
} {(005) (007) (013) (017) (023)}
do_test tabfunc01-701 {
  db eval {
    SELECT b FROM t600 WHERE a IN carray(inttoptr($PTR1),5,'int32');
  }
} {(005) (007) (013) (017) (023)}
do_test tabfunc01-702 {
  db eval {
    SELECT b FROM t600 WHERE a IN carray(inttoptr($PTR1),4,'int32');
  }
} {(005) (007) (013) (017)}
do_catchsql_test tabfunc01-710 {
  SELECT b FROM t600 WHERE a IN carray(inttoptr($PTR1),5,'int33');
} {1 {unknown datatype: 'int33'}}

do_test tabfunc01-720 {
  set PTR2 [int64array_addr 5 7 13 17 23]
  db eval {
    SELECT b FROM t600, carray(inttoptr($PTR2),5,'int64') WHERE a=value;
  }
} {(005) (007) (013) (017) (023)}
do_test tabfunc01-721 {
  db eval {
    SELECT remember(123,inttoptr($PTR2));
    SELECT value FROM carray(inttoptr($PTR2),5,'int64');
  }
} {123 123 7 13 17 23}
do_test tabfunc01-722 {
  set PTR3 [expr {$PTR2+16}]
  db eval {
    SELECT remember(987,inttoptr($PTR3));
    SELECT value FROM carray(inttoptr($PTR2),5,'int64');
  }
} {987 123 7 987 17 23}

do_test tabfunc01-730 {
  set PTR4 [doublearray_addr 5.0 7.0 13.0 17.0 23.0]
  db eval {
    SELECT b FROM t600, carray(inttoptr($PTR4),5,'double') WHERE a=value;
  }
} {(005) (007) (013) (017) (023)}

do_test tabfunc01-740 {
  set PTR5 [textarray_addr x5 x7 x13 x17 x23]
  db eval {
    SELECT b FROM t600, carray(inttoptr($PTR5),5,'char*')
     WHERE a=trim(value,'x');
  }
} {(005) (007) (013) (017) (023)}

do_test tabfunc01-750 {
  db eval {
    SELECT aa.value, bb.value, '|'
      FROM carray(inttoptr($PTR4),5,'double') AS aa
      JOIN carray(inttoptr($PTR5),5,'char*') AS bb ON aa.rowid=bb.rowid;
  }
} {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |}

# Free up memory allocations
intarray_addr
int64array_addr
doublearray_addr
textarray_addr

finish_test