|
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
|
|