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 #include "test_intarray.h"
23 ** Definition of the sqlite3_intarray object.
25 ** The internal representation of an intarray object is subject
26 ** to change, is not externally visible, and should be used by
27 ** the implementation of intarray only. This object is opaque
30 struct sqlite3_intarray
{
31 int n
; /* Number of elements in the array */
32 sqlite3_int64
*a
; /* Contents of the array */
33 void (*xFree
)(void*); /* Function used to free a[] */
36 /* Objects used internally by the virtual table implementation */
37 typedef struct intarray_vtab intarray_vtab
;
38 typedef struct intarray_cursor intarray_cursor
;
40 /* An intarray table object */
41 struct intarray_vtab
{
42 sqlite3_vtab base
; /* Base class */
43 sqlite3_intarray
*pContent
; /* Content of the integer array */
46 /* An intarray cursor object */
47 struct intarray_cursor
{
48 sqlite3_vtab_cursor base
; /* Base class */
49 int i
; /* Current cursor position */
53 ** None of this works unless we have virtual tables.
55 #ifndef SQLITE_OMIT_VIRTUALTABLE
58 ** Free an sqlite3_intarray object.
60 static void intarrayFree(sqlite3_intarray
*p
){
68 ** Table destructor for the intarray module.
70 static int intarrayDestroy(sqlite3_vtab
*p
){
71 intarray_vtab
*pVtab
= (intarray_vtab
*)p
;
77 ** Table constructor for the intarray module.
79 static int intarrayCreate(
80 sqlite3
*db
, /* Database where module is created */
81 void *pAux
, /* clientdata for the module */
82 int argc
, /* Number of arguments */
83 const char *const*argv
, /* Value for all arguments */
84 sqlite3_vtab
**ppVtab
, /* Write the new virtual table object here */
85 char **pzErr
/* Put error message text here */
87 int rc
= SQLITE_NOMEM
;
88 intarray_vtab
*pVtab
= sqlite3_malloc64(sizeof(intarray_vtab
));
91 memset(pVtab
, 0, sizeof(intarray_vtab
));
92 pVtab
->pContent
= (sqlite3_intarray
*)pAux
;
93 rc
= sqlite3_declare_vtab(db
, "CREATE TABLE x(value INTEGER PRIMARY KEY)");
95 *ppVtab
= (sqlite3_vtab
*)pVtab
;
100 ** Open a new cursor on the intarray table.
102 static int intarrayOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
103 int rc
= SQLITE_NOMEM
;
104 intarray_cursor
*pCur
;
105 pCur
= sqlite3_malloc64(sizeof(intarray_cursor
));
107 memset(pCur
, 0, sizeof(intarray_cursor
));
108 *ppCursor
= (sqlite3_vtab_cursor
*)pCur
;
115 ** Close a intarray table cursor.
117 static int intarrayClose(sqlite3_vtab_cursor
*cur
){
118 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
124 ** Retrieve a column of data.
126 static int intarrayColumn(sqlite3_vtab_cursor
*cur
, sqlite3_context
*ctx
, int i
){
127 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
128 intarray_vtab
*pVtab
= (intarray_vtab
*)cur
->pVtab
;
129 if( pCur
->i
>=0 && pCur
->i
<pVtab
->pContent
->n
){
130 sqlite3_result_int64(ctx
, pVtab
->pContent
->a
[pCur
->i
]);
136 ** Retrieve the current rowid.
138 static int intarrayRowid(sqlite3_vtab_cursor
*cur
, sqlite_int64
*pRowid
){
139 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
144 static int intarrayEof(sqlite3_vtab_cursor
*cur
){
145 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
146 intarray_vtab
*pVtab
= (intarray_vtab
*)cur
->pVtab
;
147 return pCur
->i
>=pVtab
->pContent
->n
;
151 ** Advance the cursor to the next row.
153 static int intarrayNext(sqlite3_vtab_cursor
*cur
){
154 intarray_cursor
*pCur
= (intarray_cursor
*)cur
;
160 ** Reset a intarray table cursor.
162 static int intarrayFilter(
163 sqlite3_vtab_cursor
*pVtabCursor
,
164 int idxNum
, const char *idxStr
,
165 int argc
, sqlite3_value
**argv
167 intarray_cursor
*pCur
= (intarray_cursor
*)pVtabCursor
;
173 ** Analyse the WHERE condition.
175 static int intarrayBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
180 ** A virtual table module that merely echos method calls into TCL
183 static sqlite3_module intarrayModule
= {
185 intarrayCreate
, /* xCreate - create a new virtual table */
186 intarrayCreate
, /* xConnect - connect to an existing vtab */
187 intarrayBestIndex
, /* xBestIndex - find the best query index */
188 intarrayDestroy
, /* xDisconnect - disconnect a vtab */
189 intarrayDestroy
, /* xDestroy - destroy a vtab */
190 intarrayOpen
, /* xOpen - open a cursor */
191 intarrayClose
, /* xClose - close a cursor */
192 intarrayFilter
, /* xFilter - configure scan constraints */
193 intarrayNext
, /* xNext - advance a cursor */
194 intarrayEof
, /* xEof */
195 intarrayColumn
, /* xColumn - read data */
196 intarrayRowid
, /* xRowid - read data */
206 #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
209 ** Invoke this routine to create a specific instance of an intarray object.
210 ** The new intarray object is returned by the 3rd parameter.
212 ** Each intarray object corresponds to a virtual table in the TEMP table
213 ** with a name of zName.
215 ** Destroy the intarray object by dropping the virtual table. If not done
216 ** explicitly by the application, the virtual table will be dropped implicitly
217 ** by the system when the database connection is closed.
219 SQLITE_API
int sqlite3_intarray_create(
222 sqlite3_intarray
**ppReturn
225 #ifndef SQLITE_OMIT_VIRTUALTABLE
228 *ppReturn
= p
= sqlite3_malloc64( sizeof(*p
) );
232 memset(p
, 0, sizeof(*p
));
233 rc
= sqlite3_create_module_v2(db
, zName
, &intarrayModule
, p
,
234 (void(*)(void*))intarrayFree
);
237 zSql
= sqlite3_mprintf("CREATE VIRTUAL TABLE temp.%Q USING %Q",
239 rc
= sqlite3_exec(db
, zSql
, 0, 0, 0);
247 ** Bind a new array array of integers to a specific intarray object.
249 ** The array of integers bound must be unchanged for the duration of
250 ** any query against the corresponding virtual table. If the integer
251 ** array does change or is deallocated undefined behavior will result.
253 SQLITE_API
int sqlite3_intarray_bind(
254 sqlite3_intarray
*pIntArray
, /* The intarray object to bind to */
255 int nElements
, /* Number of elements in the intarray */
256 sqlite3_int64
*aElements
, /* Content of the intarray */
257 void (*xFree
)(void*) /* How to dispose of the intarray when done */
259 if( pIntArray
->xFree
){
260 pIntArray
->xFree(pIntArray
->a
);
262 pIntArray
->n
= nElements
;
263 pIntArray
->a
= aElements
;
264 pIntArray
->xFree
= xFree
;
269 /*****************************************************************************
270 ** Everything below is interface for testing this module.
273 #if defined(INCLUDE_SQLITE_TCL_H)
274 # include "sqlite_tcl.h"
277 # ifndef SQLITE_TCLAPI
278 # define SQLITE_TCLAPI
283 ** Routines to encode and decode pointers
285 extern int getDbPointer(Tcl_Interp
*interp
, const char *zA
, sqlite3
**ppDb
);
286 extern void *sqlite3TestTextToPtr(const char*);
287 extern int sqlite3TestMakePointerStr(Tcl_Interp
*, char *zPtr
, void*);
288 extern const char *sqlite3ErrName(int);
291 ** sqlite3_intarray_create DB NAME
293 ** Invoke the sqlite3_intarray_create interface. A string that becomes
294 ** the first parameter to sqlite3_intarray_bind.
296 static int SQLITE_TCLAPI
test_intarray_create(
297 ClientData clientData
, /* Not used */
298 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
299 int objc
, /* Number of arguments */
300 Tcl_Obj
*CONST objv
[] /* Command arguments */
304 sqlite3_intarray
*pArray
;
309 Tcl_WrongNumArgs(interp
, 1, objv
, "DB");
312 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
313 zName
= Tcl_GetString(objv
[2]);
314 #ifndef SQLITE_OMIT_VIRTUALTABLE
315 rc
= sqlite3_intarray_create(db
, zName
, &pArray
);
319 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), (char*)0);
322 sqlite3TestMakePointerStr(interp
, zPtr
, pArray
);
323 Tcl_AppendResult(interp
, zPtr
, (char*)0);
328 ** sqlite3_intarray_bind INTARRAY ?VALUE ...?
330 ** Invoke the sqlite3_intarray_bind interface on the given array of integers.
332 static int SQLITE_TCLAPI
test_intarray_bind(
333 ClientData clientData
, /* Not used */
334 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
335 int objc
, /* Number of arguments */
336 Tcl_Obj
*CONST objv
[] /* Command arguments */
338 sqlite3_intarray
*pArray
;
344 Tcl_WrongNumArgs(interp
, 1, objv
, "INTARRAY");
347 pArray
= (sqlite3_intarray
*)sqlite3TestTextToPtr(Tcl_GetString(objv
[1]));
349 #ifndef SQLITE_OMIT_VIRTUALTABLE
350 a
= sqlite3_malloc64( sizeof(a
[0])*n
);
352 Tcl_AppendResult(interp
, "SQLITE_NOMEM", (char*)0);
357 Tcl_GetWideIntFromObj(0, objv
[i
+2], &x
);
360 rc
= sqlite3_intarray_bind(pArray
, n
, a
, sqlite3_free
);
362 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), (char*)0);
370 ** Register commands with the TCL interpreter.
372 int Sqlitetestintarray_Init(Tcl_Interp
*interp
){
375 Tcl_ObjCmdProc
*xProc
;
378 { "sqlite3_intarray_create", test_intarray_create
, 0 },
379 { "sqlite3_intarray_bind", test_intarray_bind
, 0 },
382 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
383 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
,
384 aObjCmd
[i
].xProc
, aObjCmd
[i
].clientData
, 0);
389 #endif /* SQLITE_TEST */