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 */
210 #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
213 ** Invoke this routine to create a specific instance of an intarray object.
214 ** The new intarray object is returned by the 3rd parameter.
216 ** Each intarray object corresponds to a virtual table in the TEMP table
217 ** with a name of zName.
219 ** Destroy the intarray object by dropping the virtual table. If not done
220 ** explicitly by the application, the virtual table will be dropped implicitly
221 ** by the system when the database connection is closed.
223 SQLITE_API
int sqlite3_intarray_create(
226 sqlite3_intarray
**ppReturn
229 #ifndef SQLITE_OMIT_VIRTUALTABLE
232 *ppReturn
= p
= sqlite3_malloc64( sizeof(*p
) );
236 memset(p
, 0, sizeof(*p
));
237 rc
= sqlite3_create_module_v2(db
, zName
, &intarrayModule
, p
,
238 (void(*)(void*))intarrayFree
);
241 zSql
= sqlite3_mprintf("CREATE VIRTUAL TABLE temp.%Q USING %Q",
243 rc
= sqlite3_exec(db
, zSql
, 0, 0, 0);
251 ** Bind a new array array of integers to a specific intarray object.
253 ** The array of integers bound must be unchanged for the duration of
254 ** any query against the corresponding virtual table. If the integer
255 ** array does change or is deallocated undefined behavior will result.
257 SQLITE_API
int sqlite3_intarray_bind(
258 sqlite3_intarray
*pIntArray
, /* The intarray object to bind to */
259 int nElements
, /* Number of elements in the intarray */
260 sqlite3_int64
*aElements
, /* Content of the intarray */
261 void (*xFree
)(void*) /* How to dispose of the intarray when done */
263 if( pIntArray
->xFree
){
264 pIntArray
->xFree(pIntArray
->a
);
266 pIntArray
->n
= nElements
;
267 pIntArray
->a
= aElements
;
268 pIntArray
->xFree
= xFree
;
273 /*****************************************************************************
274 ** Everything below is interface for testing this module.
277 #if defined(INCLUDE_SQLITE_TCL_H)
278 # include "sqlite_tcl.h"
281 # ifndef SQLITE_TCLAPI
282 # define SQLITE_TCLAPI
287 ** Routines to encode and decode pointers
289 extern int getDbPointer(Tcl_Interp
*interp
, const char *zA
, sqlite3
**ppDb
);
290 extern void *sqlite3TestTextToPtr(const char*);
291 extern int sqlite3TestMakePointerStr(Tcl_Interp
*, char *zPtr
, void*);
292 extern const char *sqlite3ErrName(int);
295 ** sqlite3_intarray_create DB NAME
297 ** Invoke the sqlite3_intarray_create interface. A string that becomes
298 ** the first parameter to sqlite3_intarray_bind.
300 static int SQLITE_TCLAPI
test_intarray_create(
301 ClientData clientData
, /* Not used */
302 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
303 int objc
, /* Number of arguments */
304 Tcl_Obj
*CONST objv
[] /* Command arguments */
308 sqlite3_intarray
*pArray
;
313 Tcl_WrongNumArgs(interp
, 1, objv
, "DB");
316 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
317 zName
= Tcl_GetString(objv
[2]);
318 #ifndef SQLITE_OMIT_VIRTUALTABLE
319 rc
= sqlite3_intarray_create(db
, zName
, &pArray
);
322 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), (char*)0);
325 sqlite3TestMakePointerStr(interp
, zPtr
, pArray
);
326 Tcl_AppendResult(interp
, zPtr
, (char*)0);
331 ** sqlite3_intarray_bind INTARRAY ?VALUE ...?
333 ** Invoke the sqlite3_intarray_bind interface on the given array of integers.
335 static int SQLITE_TCLAPI
test_intarray_bind(
336 ClientData clientData
, /* Not used */
337 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
338 int objc
, /* Number of arguments */
339 Tcl_Obj
*CONST objv
[] /* Command arguments */
341 sqlite3_intarray
*pArray
;
347 Tcl_WrongNumArgs(interp
, 1, objv
, "INTARRAY");
350 pArray
= (sqlite3_intarray
*)sqlite3TestTextToPtr(Tcl_GetString(objv
[1]));
352 #ifndef SQLITE_OMIT_VIRTUALTABLE
353 a
= sqlite3_malloc64( sizeof(a
[0])*n
);
355 Tcl_AppendResult(interp
, "SQLITE_NOMEM", (char*)0);
360 Tcl_GetWideIntFromObj(0, objv
[i
+2], &x
);
363 rc
= sqlite3_intarray_bind(pArray
, n
, a
, sqlite3_free
);
365 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), (char*)0);
373 ** Register commands with the TCL interpreter.
375 int Sqlitetestintarray_Init(Tcl_Interp
*interp
){
378 Tcl_ObjCmdProc
*xProc
;
381 { "sqlite3_intarray_create", test_intarray_create
, 0 },
382 { "sqlite3_intarray_bind", test_intarray_bind
, 0 },
385 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
386 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
,
387 aObjCmd
[i
].xProc
, aObjCmd
[i
].clientData
, 0);
392 #endif /* SQLITE_TEST */