4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
11 *************************************************************************
13 ** This file implements a read-only VIRTUAL TABLE that contains the
14 ** content of a C-language array of integer values. See the corresponding
15 ** header file for full details.
17 ** This virtual table is used for internal testing of SQLite only. It is
18 ** not recommended for use in production. For a similar virtual table that
19 ** is production-ready, see the "carray" virtual table over in ext/misc.
21 #include "test_intarray.h"
27 ** Definition of the sqlite3_intarray object.
29 ** The internal representation of an intarray object is subject
30 ** to change, is not externally visible, and should be used by
31 ** the implementation of intarray only. This object is opaque
34 struct sqlite3_intarray
{
35 int n
; /* Number of elements in the array */
36 sqlite3_int64
*a
; /* Contents of the array */
37 void (*xFree
)(void*); /* Function used to free a[] */
40 /* Objects used internally by the virtual table implementation */
41 typedef struct intarray_vtab intarray_vtab
;
42 typedef struct intarray_cursor intarray_cursor
;
44 /* An intarray table object */
45 struct intarray_vtab
{
46 sqlite3_vtab base
; /* Base class */
47 sqlite3_intarray
*pContent
; /* Content of the integer array */
50 /* An intarray cursor object */
51 struct intarray_cursor
{
52 sqlite3_vtab_cursor base
; /* Base class */
53 int i
; /* Current cursor position */
57 ** None of this works unless we have virtual tables.
59 #ifndef SQLITE_OMIT_VIRTUALTABLE
62 ** Free an sqlite3_intarray object.
64 static void intarrayFree(sqlite3_intarray
*p
){
72 ** Table destructor for the intarray module.
74 static int intarrayDestroy(sqlite3_vtab
*p
){
75 intarray_vtab
*pVtab
= (intarray_vtab
*)p
;
81 ** Table constructor for the intarray module.
83 static int intarrayCreate(
84 sqlite3
*db
, /* Database where module is created */
85 void *pAux
, /* clientdata for the module */
86 int argc
, /* Number of arguments */
87 const char *const*argv
, /* Value for all arguments */
88 sqlite3_vtab
**ppVtab
, /* Write the new virtual table object here */
89 char **pzErr
/* Put error message text here */
91 int rc
= SQLITE_NOMEM
;
92 intarray_vtab
*pVtab
= sqlite3_malloc64(sizeof(intarray_vtab
));
95 memset(pVtab
, 0, sizeof(intarray_vtab
));
96 pVtab
->pContent
= (sqlite3_intarray
*)pAux
;
97 rc
= sqlite3_declare_vtab(db
, "CREATE TABLE x(value INTEGER PRIMARY KEY)");
99 *ppVtab
= (sqlite3_vtab
*)pVtab
;
104 ** Open a new cursor on the intarray table.
106 static int intarrayOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
107 int rc
= SQLITE_NOMEM
;
108 intarray_cursor
*pCur
;
109 pCur
= sqlite3_malloc64(sizeof(intarray_cursor
));
111 memset(pCur
, 0, sizeof(intarray_cursor
));
112 *ppCursor
= (sqlite3_vtab_cursor
*)pCur
;
119 ** Close a intarray table cursor.
121 static int intarrayClose(sqlite3_vtab_cursor
*cur
){
122 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
128 ** Retrieve a column of data.
130 static int intarrayColumn(sqlite3_vtab_cursor
*cur
, sqlite3_context
*ctx
, int i
){
131 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
132 intarray_vtab
*pVtab
= (intarray_vtab
*)cur
->pVtab
;
133 if( pCur
->i
>=0 && pCur
->i
<pVtab
->pContent
->n
){
134 sqlite3_result_int64(ctx
, pVtab
->pContent
->a
[pCur
->i
]);
140 ** Retrieve the current rowid.
142 static int intarrayRowid(sqlite3_vtab_cursor
*cur
, sqlite_int64
*pRowid
){
143 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
148 static int intarrayEof(sqlite3_vtab_cursor
*cur
){
149 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
150 intarray_vtab
*pVtab
= (intarray_vtab
*)cur
->pVtab
;
151 return pCur
->i
>=pVtab
->pContent
->n
;
155 ** Advance the cursor to the next row.
157 static int intarrayNext(sqlite3_vtab_cursor
*cur
){
158 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
164 ** Reset a intarray table cursor.
166 static int intarrayFilter(
167 sqlite3_vtab_cursor
*pVtabCursor
,
168 int idxNum
, const char *idxStr
,
169 int argc
, sqlite3_value
**argv
171 intarray_cursor
*pCur
= (intarray_cursor
*)pVtabCursor
;
177 ** Analyse the WHERE condition.
179 static int intarrayBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
184 ** A virtual table module that merely echos method calls into TCL
187 static sqlite3_module intarrayModule
= {
189 intarrayCreate
, /* xCreate - create a new virtual table */
190 intarrayCreate
, /* xConnect - connect to an existing vtab */
191 intarrayBestIndex
, /* xBestIndex - find the best query index */
192 intarrayDestroy
, /* xDisconnect - disconnect a vtab */
193 intarrayDestroy
, /* xDestroy - destroy a vtab */
194 intarrayOpen
, /* xOpen - open a cursor */
195 intarrayClose
, /* xClose - close a cursor */
196 intarrayFilter
, /* xFilter - configure scan constraints */
197 intarrayNext
, /* xNext - advance a cursor */
198 intarrayEof
, /* xEof */
199 intarrayColumn
, /* xColumn - read data */
200 intarrayRowid
, /* xRowid - read data */
215 #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
218 ** Invoke this routine to create a specific instance of an intarray object.
219 ** The new intarray object is returned by the 3rd parameter.
221 ** Each intarray object corresponds to a virtual table in the TEMP table
222 ** with a name of zName.
224 ** Destroy the intarray object by dropping the virtual table. If not done
225 ** explicitly by the application, the virtual table will be dropped implicitly
226 ** by the system when the database connection is closed.
228 SQLITE_API
int sqlite3_intarray_create(
231 sqlite3_intarray
**ppReturn
234 #ifndef SQLITE_OMIT_VIRTUALTABLE
237 *ppReturn
= p
= sqlite3_malloc64( sizeof(*p
) );
241 memset(p
, 0, sizeof(*p
));
242 rc
= sqlite3_create_module_v2(db
, zName
, &intarrayModule
, p
,
243 (void(*)(void*))intarrayFree
);
246 zSql
= sqlite3_mprintf("CREATE VIRTUAL TABLE temp.%Q USING %Q",
248 rc
= sqlite3_exec(db
, zSql
, 0, 0, 0);
256 ** Bind a new array array of integers to a specific intarray object.
258 ** The array of integers bound must be unchanged for the duration of
259 ** any query against the corresponding virtual table. If the integer
260 ** array does change or is deallocated undefined behavior will result.
262 SQLITE_API
int sqlite3_intarray_bind(
263 sqlite3_intarray
*pIntArray
, /* The intarray object to bind to */
264 int nElements
, /* Number of elements in the intarray */
265 sqlite3_int64
*aElements
, /* Content of the intarray */
266 void (*xFree
)(void*) /* How to dispose of the intarray when done */
268 if( pIntArray
->xFree
){
269 pIntArray
->xFree(pIntArray
->a
);
271 pIntArray
->n
= nElements
;
272 pIntArray
->a
= aElements
;
273 pIntArray
->xFree
= xFree
;
278 /*****************************************************************************
279 ** Everything below is interface for testing this module.
282 #if defined(INCLUDE_SQLITE_TCL_H)
283 # include "sqlite_tcl.h"
286 # ifndef SQLITE_TCLAPI
287 # define SQLITE_TCLAPI
292 ** Routines to encode and decode pointers
294 extern int getDbPointer(Tcl_Interp
*interp
, const char *zA
, sqlite3
**ppDb
);
295 extern void *sqlite3TestTextToPtr(const char*);
296 extern int sqlite3TestMakePointerStr(Tcl_Interp
*, char *zPtr
, void*);
297 extern const char *sqlite3ErrName(int);
300 ** sqlite3_intarray_create DB NAME
302 ** Invoke the sqlite3_intarray_create interface. A string that becomes
303 ** the first parameter to sqlite3_intarray_bind.
305 static int SQLITE_TCLAPI
test_intarray_create(
306 ClientData clientData
, /* Not used */
307 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
308 int objc
, /* Number of arguments */
309 Tcl_Obj
*CONST objv
[] /* Command arguments */
313 sqlite3_intarray
*pArray
;
318 Tcl_WrongNumArgs(interp
, 1, objv
, "DB");
321 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
322 zName
= Tcl_GetString(objv
[2]);
323 #ifndef SQLITE_OMIT_VIRTUALTABLE
324 rc
= sqlite3_intarray_create(db
, zName
, &pArray
);
327 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), (char*)0);
330 sqlite3TestMakePointerStr(interp
, zPtr
, pArray
);
331 Tcl_AppendResult(interp
, zPtr
, (char*)0);
336 ** sqlite3_intarray_bind INTARRAY ?VALUE ...?
338 ** Invoke the sqlite3_intarray_bind interface on the given array of integers.
340 static int SQLITE_TCLAPI
test_intarray_bind(
341 ClientData clientData
, /* Not used */
342 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
343 int objc
, /* Number of arguments */
344 Tcl_Obj
*CONST objv
[] /* Command arguments */
346 sqlite3_intarray
*pArray
;
352 Tcl_WrongNumArgs(interp
, 1, objv
, "INTARRAY");
355 pArray
= (sqlite3_intarray
*)sqlite3TestTextToPtr(Tcl_GetString(objv
[1]));
357 #ifndef SQLITE_OMIT_VIRTUALTABLE
358 a
= sqlite3_malloc64( sizeof(a
[0])*n
);
360 Tcl_AppendResult(interp
, "SQLITE_NOMEM", (char*)0);
365 Tcl_GetWideIntFromObj(0, objv
[i
+2], &x
);
368 rc
= sqlite3_intarray_bind(pArray
, n
, a
, sqlite3_free
);
370 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), (char*)0);
378 ** Register commands with the TCL interpreter.
380 int Sqlitetestintarray_Init(Tcl_Interp
*interp
){
383 Tcl_ObjCmdProc
*xProc
;
386 { "sqlite3_intarray_create", test_intarray_create
, 0 },
387 { "sqlite3_intarray_bind", test_intarray_bind
, 0 },
390 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
391 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
,
392 aObjCmd
[i
].xProc
, aObjCmd
[i
].clientData
, 0);
397 #endif /* SQLITE_TEST */