Annotation of embedaddon/sqlite3/src/test_intarray.c, revision 1.1
1.1 ! misho 1: /*
! 2: ** 2009 November 10
! 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 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.
! 16: */
! 17: #include "test_intarray.h"
! 18: #include <string.h>
! 19: #include <assert.h>
! 20:
! 21:
! 22: /*
! 23: ** Definition of the sqlite3_intarray object.
! 24: **
! 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
! 28: ** to users.
! 29: */
! 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[] */
! 34: };
! 35:
! 36: /* Objects used internally by the virtual table implementation */
! 37: typedef struct intarray_vtab intarray_vtab;
! 38: typedef struct intarray_cursor intarray_cursor;
! 39:
! 40: /* A intarray table object */
! 41: struct intarray_vtab {
! 42: sqlite3_vtab base; /* Base class */
! 43: sqlite3_intarray *pContent; /* Content of the integer array */
! 44: };
! 45:
! 46: /* A intarray cursor object */
! 47: struct intarray_cursor {
! 48: sqlite3_vtab_cursor base; /* Base class */
! 49: int i; /* Current cursor position */
! 50: };
! 51:
! 52: /*
! 53: ** None of this works unless we have virtual tables.
! 54: */
! 55: #ifndef SQLITE_OMIT_VIRTUALTABLE
! 56:
! 57: /*
! 58: ** Free an sqlite3_intarray object.
! 59: */
! 60: static void intarrayFree(sqlite3_intarray *p){
! 61: if( p->xFree ){
! 62: p->xFree(p->a);
! 63: }
! 64: sqlite3_free(p);
! 65: }
! 66:
! 67: /*
! 68: ** Table destructor for the intarray module.
! 69: */
! 70: static int intarrayDestroy(sqlite3_vtab *p){
! 71: intarray_vtab *pVtab = (intarray_vtab*)p;
! 72: sqlite3_free(pVtab);
! 73: return 0;
! 74: }
! 75:
! 76: /*
! 77: ** Table constructor for the intarray module.
! 78: */
! 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 */
! 86: ){
! 87: int rc = SQLITE_NOMEM;
! 88: intarray_vtab *pVtab = sqlite3_malloc(sizeof(intarray_vtab));
! 89:
! 90: if( pVtab ){
! 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)");
! 94: }
! 95: *ppVtab = (sqlite3_vtab *)pVtab;
! 96: return rc;
! 97: }
! 98:
! 99: /*
! 100: ** Open a new cursor on the intarray table.
! 101: */
! 102: static int intarrayOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
! 103: int rc = SQLITE_NOMEM;
! 104: intarray_cursor *pCur;
! 105: pCur = sqlite3_malloc(sizeof(intarray_cursor));
! 106: if( pCur ){
! 107: memset(pCur, 0, sizeof(intarray_cursor));
! 108: *ppCursor = (sqlite3_vtab_cursor *)pCur;
! 109: rc = SQLITE_OK;
! 110: }
! 111: return rc;
! 112: }
! 113:
! 114: /*
! 115: ** Close a intarray table cursor.
! 116: */
! 117: static int intarrayClose(sqlite3_vtab_cursor *cur){
! 118: intarray_cursor *pCur = (intarray_cursor *)cur;
! 119: sqlite3_free(pCur);
! 120: return SQLITE_OK;
! 121: }
! 122:
! 123: /*
! 124: ** Retrieve a column of data.
! 125: */
! 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]);
! 131: }
! 132: return SQLITE_OK;
! 133: }
! 134:
! 135: /*
! 136: ** Retrieve the current rowid.
! 137: */
! 138: static int intarrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
! 139: intarray_cursor *pCur = (intarray_cursor *)cur;
! 140: *pRowid = pCur->i;
! 141: return SQLITE_OK;
! 142: }
! 143:
! 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;
! 148: }
! 149:
! 150: /*
! 151: ** Advance the cursor to the next row.
! 152: */
! 153: static int intarrayNext(sqlite3_vtab_cursor *cur){
! 154: intarray_cursor *pCur = (intarray_cursor *)cur;
! 155: pCur->i++;
! 156: return SQLITE_OK;
! 157: }
! 158:
! 159: /*
! 160: ** Reset a intarray table cursor.
! 161: */
! 162: static int intarrayFilter(
! 163: sqlite3_vtab_cursor *pVtabCursor,
! 164: int idxNum, const char *idxStr,
! 165: int argc, sqlite3_value **argv
! 166: ){
! 167: intarray_cursor *pCur = (intarray_cursor *)pVtabCursor;
! 168: pCur->i = 0;
! 169: return SQLITE_OK;
! 170: }
! 171:
! 172: /*
! 173: ** Analyse the WHERE condition.
! 174: */
! 175: static int intarrayBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
! 176: return SQLITE_OK;
! 177: }
! 178:
! 179: /*
! 180: ** A virtual table module that merely echos method calls into TCL
! 181: ** variables.
! 182: */
! 183: static sqlite3_module intarrayModule = {
! 184: 0, /* iVersion */
! 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 */
! 197: 0, /* xUpdate */
! 198: 0, /* xBegin */
! 199: 0, /* xSync */
! 200: 0, /* xCommit */
! 201: 0, /* xRollback */
! 202: 0, /* xFindMethod */
! 203: 0, /* xRename */
! 204: };
! 205:
! 206: #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
! 207:
! 208: /*
! 209: ** Invoke this routine to create a specific instance of an intarray object.
! 210: ** The new intarray object is returned by the 3rd parameter.
! 211: **
! 212: ** Each intarray object corresponds to a virtual table in the TEMP table
! 213: ** with a name of zName.
! 214: **
! 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.
! 218: */
! 219: int sqlite3_intarray_create(
! 220: sqlite3 *db,
! 221: const char *zName,
! 222: sqlite3_intarray **ppReturn
! 223: ){
! 224: int rc = SQLITE_OK;
! 225: #ifndef SQLITE_OMIT_VIRTUALTABLE
! 226: sqlite3_intarray *p;
! 227:
! 228: *ppReturn = p = sqlite3_malloc( sizeof(*p) );
! 229: if( p==0 ){
! 230: return SQLITE_NOMEM;
! 231: }
! 232: memset(p, 0, sizeof(*p));
! 233: rc = sqlite3_create_module_v2(db, zName, &intarrayModule, p,
! 234: (void(*)(void*))intarrayFree);
! 235: if( rc==SQLITE_OK ){
! 236: char *zSql;
! 237: zSql = sqlite3_mprintf("CREATE VIRTUAL TABLE temp.%Q USING %Q",
! 238: zName, zName);
! 239: rc = sqlite3_exec(db, zSql, 0, 0, 0);
! 240: sqlite3_free(zSql);
! 241: }
! 242: #endif
! 243: return rc;
! 244: }
! 245:
! 246: /*
! 247: ** Bind a new array array of integers to a specific intarray object.
! 248: **
! 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.
! 252: */
! 253: 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 */
! 258: ){
! 259: if( pIntArray->xFree ){
! 260: pIntArray->xFree(pIntArray->a);
! 261: }
! 262: pIntArray->n = nElements;
! 263: pIntArray->a = aElements;
! 264: pIntArray->xFree = xFree;
! 265: return SQLITE_OK;
! 266: }
! 267:
! 268:
! 269: /*****************************************************************************
! 270: ** Everything below is interface for testing this module.
! 271: */
! 272: #ifdef SQLITE_TEST
! 273: #include <tcl.h>
! 274:
! 275: /*
! 276: ** Routines to encode and decode pointers
! 277: */
! 278: extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
! 279: extern void *sqlite3TestTextToPtr(const char*);
! 280: extern int sqlite3TestMakePointerStr(Tcl_Interp*, char *zPtr, void*);
! 281: extern const char *sqlite3TestErrorName(int);
! 282:
! 283: /*
! 284: ** sqlite3_intarray_create DB NAME
! 285: **
! 286: ** Invoke the sqlite3_intarray_create interface. A string that becomes
! 287: ** the first parameter to sqlite3_intarray_bind.
! 288: */
! 289: static int test_intarray_create(
! 290: ClientData clientData, /* Not used */
! 291: Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
! 292: int objc, /* Number of arguments */
! 293: Tcl_Obj *CONST objv[] /* Command arguments */
! 294: ){
! 295: sqlite3 *db;
! 296: const char *zName;
! 297: sqlite3_intarray *pArray;
! 298: int rc = SQLITE_OK;
! 299: char zPtr[100];
! 300:
! 301: if( objc!=3 ){
! 302: Tcl_WrongNumArgs(interp, 1, objv, "DB");
! 303: return TCL_ERROR;
! 304: }
! 305: if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
! 306: zName = Tcl_GetString(objv[2]);
! 307: #ifndef SQLITE_OMIT_VIRTUALTABLE
! 308: rc = sqlite3_intarray_create(db, zName, &pArray);
! 309: #endif
! 310: if( rc!=SQLITE_OK ){
! 311: assert( pArray==0 );
! 312: Tcl_AppendResult(interp, sqlite3TestErrorName(rc), (char*)0);
! 313: return TCL_ERROR;
! 314: }
! 315: sqlite3TestMakePointerStr(interp, zPtr, pArray);
! 316: Tcl_AppendResult(interp, zPtr, (char*)0);
! 317: return TCL_OK;
! 318: }
! 319:
! 320: /*
! 321: ** sqlite3_intarray_bind INTARRAY ?VALUE ...?
! 322: **
! 323: ** Invoke the sqlite3_intarray_bind interface on the given array of integers.
! 324: */
! 325: static int test_intarray_bind(
! 326: ClientData clientData, /* Not used */
! 327: Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
! 328: int objc, /* Number of arguments */
! 329: Tcl_Obj *CONST objv[] /* Command arguments */
! 330: ){
! 331: sqlite3_intarray *pArray;
! 332: int rc = SQLITE_OK;
! 333: int i, n;
! 334: sqlite3_int64 *a;
! 335:
! 336: if( objc<2 ){
! 337: Tcl_WrongNumArgs(interp, 1, objv, "INTARRAY");
! 338: return TCL_ERROR;
! 339: }
! 340: pArray = (sqlite3_intarray*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
! 341: n = objc - 2;
! 342: #ifndef SQLITE_OMIT_VIRTUALTABLE
! 343: a = sqlite3_malloc( sizeof(a[0])*n );
! 344: if( a==0 ){
! 345: Tcl_AppendResult(interp, "SQLITE_NOMEM", (char*)0);
! 346: return TCL_ERROR;
! 347: }
! 348: for(i=0; i<n; i++){
! 349: a[i] = 0;
! 350: Tcl_GetWideIntFromObj(0, objv[i+2], &a[i]);
! 351: }
! 352: rc = sqlite3_intarray_bind(pArray, n, a, sqlite3_free);
! 353: if( rc!=SQLITE_OK ){
! 354: Tcl_AppendResult(interp, sqlite3TestErrorName(rc), (char*)0);
! 355: return TCL_ERROR;
! 356: }
! 357: #endif
! 358: return TCL_OK;
! 359: }
! 360:
! 361: /*
! 362: ** Register commands with the TCL interpreter.
! 363: */
! 364: int Sqlitetestintarray_Init(Tcl_Interp *interp){
! 365: static struct {
! 366: char *zName;
! 367: Tcl_ObjCmdProc *xProc;
! 368: void *clientData;
! 369: } aObjCmd[] = {
! 370: { "sqlite3_intarray_create", test_intarray_create, 0 },
! 371: { "sqlite3_intarray_bind", test_intarray_bind, 0 },
! 372: };
! 373: int i;
! 374: for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
! 375: Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
! 376: aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
! 377: }
! 378: return TCL_OK;
! 379: }
! 380:
! 381: #endif /* SQLITE_TEST */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>