Fossil SCM

fossil-scm / src / carray.c
Blame History Raw 524 lines
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 carray($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.
21
** The pointer value must be assigned to $ptr using the
22
** sqlite3_bind_pointer() interface with a pointer type of "carray".
23
** For example:
24
**
25
** static int aX[] = { 53, 9, 17, 2231, 4, 99 };
26
** int i = sqlite3_bind_parameter_index(pStmt, "$ptr");
27
** sqlite3_bind_pointer(pStmt, i, aX, "carray", 0);
28
**
29
** There is an optional third parameter to determine the datatype of
30
** the C-language array. Allowed values of the third parameter are
31
** 'int32', 'int64', 'double', 'char*'. Example:
32
**
33
** SELECT * FROM carray($ptr,10,'char*');
34
**
35
** The default value of the third parameter is 'int32'.
36
**
37
** HOW IT WORKS
38
**
39
** The carray "function" is really a virtual table with the
40
** following schema:
41
**
42
** CREATE TABLE carray(
43
** value,
44
** pointer HIDDEN,
45
** count HIDDEN,
46
** ctype TEXT HIDDEN
47
** );
48
**
49
** If the hidden columns "pointer" and "count" are unconstrained, then
50
** the virtual table has no rows. Otherwise, the virtual table interprets
51
** the integer value of "pointer" as a pointer to the array and "count"
52
** as the number of elements in the array. The virtual table steps through
53
** the array, element by element.
54
*/
55
#define SQLITE_CORE
56
#include "sqlite3.h"
57
#include <assert.h>
58
#include <string.h>
59
#include "carray.h"
60
61
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
62
** Must exactly match the definitions in carray.h.
63
*/
64
#if INTERFACE
65
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
66
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
67
#define CARRAY_DOUBLE 2 /* Data is doubles */
68
#define CARRAY_TEXT 3 /* Data is char* */
69
#endif /* INTERFACE */
70
71
#ifndef SQLITE_OMIT_VIRTUALTABLE
72
73
/*
74
** Names of allowed datatypes
75
*/
76
static const char *azType[] = { "int32", "int64", "double", "char*" };
77
78
/*
79
** Structure used to hold the sqlite3_carray_bind() information
80
*/
81
typedef struct carray_bind carray_bind;
82
struct carray_bind {
83
void *aData; /* The data */
84
int nData; /* Number of elements */
85
int mFlags; /* Control flags */
86
void (*xDel)(void*); /* Destructor for aData */
87
};
88
89
90
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
91
** serve as the underlying representation of a cursor that scans
92
** over rows of the result
93
*/
94
typedef struct carray_cursor carray_cursor;
95
struct carray_cursor {
96
sqlite3_vtab_cursor base; /* Base class - must be first */
97
sqlite3_int64 iRowid; /* The rowid */
98
void *pPtr; /* Pointer to the array of values */
99
sqlite3_int64 iCnt; /* Number of integers in the array */
100
unsigned char eType; /* One of the CARRAY_type values */
101
};
102
103
/*
104
** The carrayConnect() method is invoked to create a new
105
** carray_vtab that describes the carray virtual table.
106
**
107
** Think of this routine as the constructor for carray_vtab objects.
108
**
109
** All this routine needs to do is:
110
**
111
** (1) Allocate the carray_vtab object and initialize all fields.
112
**
113
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
114
** result set of queries against carray will look like.
115
*/
116
static int carrayConnect(
117
sqlite3 *db,
118
void *pAux,
119
int argc, const char *const*argv,
120
sqlite3_vtab **ppVtab,
121
char **pzErr
122
){
123
sqlite3_vtab *pNew;
124
int rc;
125
126
/* Column numbers */
127
#define CARRAY_COLUMN_VALUE 0
128
#define CARRAY_COLUMN_POINTER 1
129
#define CARRAY_COLUMN_COUNT 2
130
#define CARRAY_COLUMN_CTYPE 3
131
132
rc = sqlite3_declare_vtab(db,
133
"CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)");
134
if( rc==SQLITE_OK ){
135
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
136
if( pNew==0 ) return SQLITE_NOMEM;
137
memset(pNew, 0, sizeof(*pNew));
138
}
139
return rc;
140
}
141
142
/*
143
** This method is the destructor for carray_cursor objects.
144
*/
145
static int carrayDisconnect(sqlite3_vtab *pVtab){
146
sqlite3_free(pVtab);
147
return SQLITE_OK;
148
}
149
150
/*
151
** Constructor for a new carray_cursor object.
152
*/
153
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
154
carray_cursor *pCur;
155
pCur = sqlite3_malloc( sizeof(*pCur) );
156
if( pCur==0 ) return SQLITE_NOMEM;
157
memset(pCur, 0, sizeof(*pCur));
158
*ppCursor = &pCur->base;
159
return SQLITE_OK;
160
}
161
162
/*
163
** Destructor for a carray_cursor.
164
*/
165
static int carrayClose(sqlite3_vtab_cursor *cur){
166
sqlite3_free(cur);
167
return SQLITE_OK;
168
}
169
170
171
/*
172
** Advance a carray_cursor to its next row of output.
173
*/
174
static int carrayNext(sqlite3_vtab_cursor *cur){
175
carray_cursor *pCur = (carray_cursor*)cur;
176
pCur->iRowid++;
177
return SQLITE_OK;
178
}
179
180
/*
181
** Return values of columns for the row at which the carray_cursor
182
** is currently pointing.
183
*/
184
static int carrayColumn(
185
sqlite3_vtab_cursor *cur, /* The cursor */
186
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
187
int i /* Which column to return */
188
){
189
carray_cursor *pCur = (carray_cursor*)cur;
190
sqlite3_int64 x = 0;
191
switch( i ){
192
case CARRAY_COLUMN_POINTER: return SQLITE_OK;
193
case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break;
194
case CARRAY_COLUMN_CTYPE: {
195
sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
196
return SQLITE_OK;
197
}
198
default: {
199
switch( pCur->eType ){
200
case CARRAY_INT32: {
201
int *p = (int*)pCur->pPtr;
202
sqlite3_result_int(ctx, p[pCur->iRowid-1]);
203
return SQLITE_OK;
204
}
205
case CARRAY_INT64: {
206
sqlite3_int64 *p = (sqlite3_int64*)pCur->pPtr;
207
sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
208
return SQLITE_OK;
209
}
210
case CARRAY_DOUBLE: {
211
double *p = (double*)pCur->pPtr;
212
sqlite3_result_double(ctx, p[pCur->iRowid-1]);
213
return SQLITE_OK;
214
}
215
case CARRAY_TEXT: {
216
const char **p = (const char**)pCur->pPtr;
217
sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
218
return SQLITE_OK;
219
}
220
}
221
}
222
}
223
sqlite3_result_int64(ctx, x);
224
return SQLITE_OK;
225
}
226
227
/*
228
** Return the rowid for the current row. In this implementation, the
229
** rowid is the same as the output value.
230
*/
231
static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
232
carray_cursor *pCur = (carray_cursor*)cur;
233
*pRowid = pCur->iRowid;
234
return SQLITE_OK;
235
}
236
237
/*
238
** Return TRUE if the cursor has been moved off of the last
239
** row of output.
240
*/
241
static int carrayEof(sqlite3_vtab_cursor *cur){
242
carray_cursor *pCur = (carray_cursor*)cur;
243
return pCur->iRowid>pCur->iCnt;
244
}
245
246
/*
247
** This method is called to "rewind" the carray_cursor object back
248
** to the first row of output.
249
*/
250
static int carrayFilter(
251
sqlite3_vtab_cursor *pVtabCursor,
252
int idxNum, const char *idxStr,
253
int argc, sqlite3_value **argv
254
){
255
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
256
pCur->pPtr = 0;
257
pCur->iCnt = 0;
258
switch( idxNum ){
259
case 1: {
260
carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind");
261
if( pBind==0 ) break;
262
pCur->pPtr = pBind->aData;
263
pCur->iCnt = pBind->nData;
264
pCur->eType = pBind->mFlags & 0x03;
265
break;
266
}
267
case 2:
268
case 3: {
269
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
270
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
271
if( idxNum<3 ){
272
pCur->eType = CARRAY_INT32;
273
}else{
274
unsigned char i;
275
const char *zType = (const char*)sqlite3_value_text(argv[2]);
276
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
277
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
278
}
279
if( i>=sizeof(azType)/sizeof(azType[0]) ){
280
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
281
"unknown datatype: %Q", zType);
282
return SQLITE_ERROR;
283
}else{
284
pCur->eType = i;
285
}
286
}
287
break;
288
}
289
}
290
pCur->iRowid = 1;
291
return SQLITE_OK;
292
}
293
294
/*
295
** SQLite will invoke this method one or more times while planning a query
296
** that uses the carray virtual table. This routine needs to create
297
** a query plan for each invocation and compute an estimated cost for that
298
** plan.
299
**
300
** In this implementation idxNum is used to represent the
301
** query plan. idxStr is unused.
302
**
303
** idxNum is:
304
**
305
** 1 If only the pointer= constraint exists. In this case, the
306
** parameter must be bound using sqlite3_carray_bind().
307
**
308
** 2 if the pointer= and count= constraints exist.
309
**
310
** 3 if the ctype= constraint also exists.
311
**
312
** idxNum is 0 otherwise and carray becomes an empty table.
313
*/
314
static int carrayBestIndex(
315
sqlite3_vtab *tab,
316
sqlite3_index_info *pIdxInfo
317
){
318
int i; /* Loop over constraints */
319
int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */
320
int cntIdx = -1; /* Index of the count= constraint, or -1 if none */
321
int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */
322
323
const struct sqlite3_index_constraint *pConstraint;
324
pConstraint = pIdxInfo->aConstraint;
325
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
326
if( pConstraint->usable==0 ) continue;
327
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
328
switch( pConstraint->iColumn ){
329
case CARRAY_COLUMN_POINTER:
330
ptrIdx = i;
331
break;
332
case CARRAY_COLUMN_COUNT:
333
cntIdx = i;
334
break;
335
case CARRAY_COLUMN_CTYPE:
336
ctypeIdx = i;
337
break;
338
}
339
}
340
if( ptrIdx>=0 ){
341
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
342
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
343
pIdxInfo->estimatedCost = (double)1;
344
pIdxInfo->estimatedRows = 100;
345
pIdxInfo->idxNum = 1;
346
if( cntIdx>=0 ){
347
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
348
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
349
pIdxInfo->idxNum = 2;
350
if( ctypeIdx>=0 ){
351
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
352
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
353
pIdxInfo->idxNum = 3;
354
}
355
}
356
}else{
357
pIdxInfo->estimatedCost = (double)2147483647;
358
pIdxInfo->estimatedRows = 2147483647;
359
pIdxInfo->idxNum = 0;
360
}
361
return SQLITE_OK;
362
}
363
364
/*
365
** This following structure defines all the methods for the
366
** carray virtual table.
367
*/
368
static sqlite3_module carrayModule = {
369
0, /* iVersion */
370
0, /* xCreate */
371
carrayConnect, /* xConnect */
372
carrayBestIndex, /* xBestIndex */
373
carrayDisconnect, /* xDisconnect */
374
0, /* xDestroy */
375
carrayOpen, /* xOpen - open a cursor */
376
carrayClose, /* xClose - close a cursor */
377
carrayFilter, /* xFilter - configure scan constraints */
378
carrayNext, /* xNext - advance a cursor */
379
carrayEof, /* xEof - check for end of scan */
380
carrayColumn, /* xColumn - read data */
381
carrayRowid, /* xRowid - read data */
382
0, /* xUpdate */
383
0, /* xBegin */
384
0, /* xSync */
385
0, /* xCommit */
386
0, /* xRollback */
387
0, /* xFindMethod */
388
0, /* xRename */
389
};
390
391
/*
392
** Destructor for the carray_bind object
393
*/
394
static void carrayBindDel(void *pPtr){
395
carray_bind *p = (carray_bind*)pPtr;
396
if( p->xDel!=SQLITE_STATIC ){
397
p->xDel(p->aData);
398
}
399
sqlite3_free(p);
400
}
401
402
/*
403
** Invoke this interface in order to bind to the single-argument
404
** version of CARRAY().
405
*/
406
#ifdef _WIN32
407
__declspec(dllexport)
408
#endif
409
int sqlite3_carray_bind(
410
sqlite3_stmt *pStmt,
411
int idx,
412
void *aData,
413
int nData,
414
int mFlags,
415
void (*xDestroy)(void*)
416
){
417
carray_bind *pNew;
418
int i;
419
pNew = sqlite3_malloc64(sizeof(*pNew));
420
if( pNew==0 ){
421
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
422
xDestroy(aData);
423
}
424
return SQLITE_NOMEM;
425
}
426
pNew->nData = nData;
427
pNew->mFlags = mFlags;
428
if( xDestroy==SQLITE_TRANSIENT ){
429
sqlite3_int64 sz = nData;
430
switch( mFlags & 0x03 ){
431
case CARRAY_INT32: sz *= 4; break;
432
case CARRAY_INT64: sz *= 8; break;
433
case CARRAY_DOUBLE: sz *= 8; break;
434
case CARRAY_TEXT: sz *= sizeof(char*); break;
435
}
436
if( (mFlags & 0x03)==CARRAY_TEXT ){
437
for(i=0; i<nData; i++){
438
const char *z = ((char**)aData)[i];
439
if( z ) sz += strlen(z) + 1;
440
}
441
}
442
pNew->aData = sqlite3_malloc64( sz );
443
if( pNew->aData==0 ){
444
sqlite3_free(pNew);
445
return SQLITE_NOMEM;
446
}
447
if( (mFlags & 0x03)==CARRAY_TEXT ){
448
char **az = (char**)pNew->aData;
449
char *z = (char*)&az[nData];
450
for(i=0; i<nData; i++){
451
const char *zData = ((char**)aData)[i];
452
sqlite3_int64 n;
453
if( zData==0 ){
454
az[i] = 0;
455
continue;
456
}
457
az[i] = z;
458
n = strlen(zData);
459
memcpy(z, zData, n+1);
460
z += n+1;
461
}
462
}else{
463
memcpy(pNew->aData, aData, sz*nData);
464
}
465
pNew->xDel = sqlite3_free;
466
}else{
467
pNew->aData = aData;
468
pNew->xDel = xDestroy;
469
}
470
return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
471
}
472
473
474
/*
475
** For testing purpose in the TCL test harness, we need a method for
476
** setting the pointer value. The inttoptr(X) SQL function accomplishes
477
** this. Tcl script will bind an integer to X and the inttoptr() SQL
478
** function will use sqlite3_result_pointer() to convert that integer into
479
** a pointer.
480
**
481
** This is for testing on TCL only.
482
*/
483
#ifdef SQLITE_TEST
484
static void inttoptrFunc(
485
sqlite3_context *context,
486
int argc,
487
sqlite3_value **argv
488
){
489
void *p;
490
sqlite3_int64 i64;
491
i64 = sqlite3_value_int64(argv[0]);
492
if( sizeof(i64)==sizeof(p) ){
493
memcpy(&p, &i64, sizeof(p));
494
}else{
495
int i32 = i64 & 0xffffffff;
496
memcpy(&p, &i32, sizeof(p));
497
}
498
sqlite3_result_pointer(context, p, "carray", 0);
499
}
500
#endif /* SQLITE_TEST */
501
502
#endif /* SQLITE_OMIT_VIRTUALTABLE */
503
504
#ifdef _WIN32
505
__declspec(dllexport)
506
#endif
507
int sqlite3_carray_init(
508
sqlite3 *db,
509
char **pzErrMsg,
510
const sqlite3_api_routines *pApi
511
){
512
int rc = SQLITE_OK;
513
#ifndef SQLITE_OMIT_VIRTUALTABLE
514
rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
515
#ifdef SQLITE_TEST
516
if( rc==SQLITE_OK ){
517
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
518
inttoptrFunc, 0, 0);
519
}
520
#endif /* SQLITE_TEST */
521
#endif /* SQLITE_OMIT_VIRTUALTABLE */
522
return rc;
523
}
524

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button