275 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| ** 2011 April 02
 | |
| **
 | |
| ** The author disclaims copyright to this source code.  In place of
 | |
| ** a legal notice, here is a blessing:
 | |
| **
 | |
| **    May you do good and not evil.
 | |
| **    May you find forgiveness for yourself and forgive others.
 | |
| **    May you share freely, never taking more than you give.
 | |
| **
 | |
| *************************************************************************
 | |
| **
 | |
| ** This file implements a virtual table that returns the whole numbers
 | |
| ** between 1 and 4294967295, inclusive.
 | |
| **
 | |
| ** Example:
 | |
| **
 | |
| **     CREATE VIRTUAL TABLE nums USING wholenumber;
 | |
| **     SELECT value FROM nums WHERE value<10;
 | |
| **
 | |
| ** Results in:
 | |
| **
 | |
| **     1 2 3 4 5 6 7 8 9
 | |
| */
 | |
| #include "sqlite3ext.h"
 | |
| SQLITE_EXTENSION_INIT1
 | |
| #include <assert.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #ifndef SQLITE_OMIT_VIRTUALTABLE
 | |
| 
 | |
| 
 | |
| /* A wholenumber cursor object */
 | |
| typedef struct wholenumber_cursor wholenumber_cursor;
 | |
| struct wholenumber_cursor {
 | |
|   sqlite3_vtab_cursor base;  /* Base class - must be first */
 | |
|   sqlite3_int64 iValue;      /* Current value */
 | |
|   sqlite3_int64 mxValue;     /* Maximum value */
 | |
| };
 | |
| 
 | |
| /* Methods for the wholenumber module */
 | |
| static int wholenumberConnect(
 | |
|   sqlite3 *db,
 | |
|   void *pAux,
 | |
|   int argc, const char *const*argv,
 | |
|   sqlite3_vtab **ppVtab,
 | |
|   char **pzErr
 | |
| ){
 | |
|   sqlite3_vtab *pNew;
 | |
|   pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
 | |
|   if( pNew==0 ) return SQLITE_NOMEM;
 | |
|   sqlite3_declare_vtab(db, "CREATE TABLE x(value)");
 | |
|   memset(pNew, 0, sizeof(*pNew));
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| /* Note that for this virtual table, the xCreate and xConnect
 | |
| ** methods are identical. */
 | |
| 
 | |
| static int wholenumberDisconnect(sqlite3_vtab *pVtab){
 | |
|   sqlite3_free(pVtab);
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| /* The xDisconnect and xDestroy methods are also the same */
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** Open a new wholenumber cursor.
 | |
| */
 | |
| static int wholenumberOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
 | |
|   wholenumber_cursor *pCur;
 | |
|   pCur = sqlite3_malloc( sizeof(*pCur) );
 | |
|   if( pCur==0 ) return SQLITE_NOMEM;
 | |
|   memset(pCur, 0, sizeof(*pCur));
 | |
|   *ppCursor = &pCur->base;
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Close a wholenumber cursor.
 | |
| */
 | |
| static int wholenumberClose(sqlite3_vtab_cursor *cur){
 | |
|   sqlite3_free(cur);
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** Advance a cursor to its next row of output
 | |
| */
 | |
| static int wholenumberNext(sqlite3_vtab_cursor *cur){
 | |
|   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
 | |
|   pCur->iValue++;
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Return the value associated with a wholenumber.
 | |
| */
 | |
| static int wholenumberColumn(
 | |
|   sqlite3_vtab_cursor *cur,
 | |
|   sqlite3_context *ctx,
 | |
|   int i
 | |
| ){
 | |
|   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
 | |
|   sqlite3_result_int64(ctx, pCur->iValue);
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** The rowid.
 | |
| */
 | |
| static int wholenumberRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
 | |
|   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
 | |
|   *pRowid = pCur->iValue;
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** When the wholenumber_cursor.rLimit value is 0 or less, that is a signal
 | |
| ** that the cursor has nothing more to output.
 | |
| */
 | |
| static int wholenumberEof(sqlite3_vtab_cursor *cur){
 | |
|   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
 | |
|   return pCur->iValue>pCur->mxValue || pCur->iValue==0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Called to "rewind" a cursor back to the beginning so that
 | |
| ** it starts its output over again.  Always called at least once
 | |
| ** prior to any wholenumberColumn, wholenumberRowid, or wholenumberEof call.
 | |
| **
 | |
| **    idxNum   Constraints
 | |
| **    ------   ---------------------
 | |
| **      0      (none)
 | |
| **      1      value > $argv0
 | |
| **      2      value >= $argv0
 | |
| **      4      value < $argv0
 | |
| **      8      value <= $argv0
 | |
| **
 | |
| **      5      value > $argv0 AND value < $argv1
 | |
| **      6      value >= $argv0 AND value < $argv1
 | |
| **      9      value > $argv0 AND value <= $argv1
 | |
| **     10      value >= $argv0 AND value <= $argv1
 | |
| */
 | |
| static int wholenumberFilter(
 | |
|   sqlite3_vtab_cursor *pVtabCursor, 
 | |
|   int idxNum, const char *idxStr,
 | |
|   int argc, sqlite3_value **argv
 | |
| ){
 | |
|   wholenumber_cursor *pCur = (wholenumber_cursor *)pVtabCursor;
 | |
|   sqlite3_int64 v;
 | |
|   int i = 0;
 | |
|   pCur->iValue = 1;
 | |
|   pCur->mxValue = 0xffffffff;  /* 4294967295 */
 | |
|   if( idxNum & 3 ){
 | |
|     v = sqlite3_value_int64(argv[0]) + (idxNum&1);
 | |
|     if( v>pCur->iValue && v<=pCur->mxValue ) pCur->iValue = v;
 | |
|     i++;
 | |
|   }
 | |
|   if( idxNum & 12 ){
 | |
|     v = sqlite3_value_int64(argv[i]) - ((idxNum>>2)&1);
 | |
|     if( v>=pCur->iValue && v<pCur->mxValue ) pCur->mxValue = v;
 | |
|   }
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Search for terms of these forms:
 | |
| **
 | |
| **  (1)  value > $value
 | |
| **  (2)  value >= $value
 | |
| **  (4)  value < $value
 | |
| **  (8)  value <= $value
 | |
| **
 | |
| ** idxNum is an ORed combination of 1 or 2 with 4 or 8.
 | |
| */
 | |
| static int wholenumberBestIndex(
 | |
|   sqlite3_vtab *tab,
 | |
|   sqlite3_index_info *pIdxInfo
 | |
| ){
 | |
|   int i;
 | |
|   int idxNum = 0;
 | |
|   int argvIdx = 1;
 | |
|   int ltIdx = -1;
 | |
|   int gtIdx = -1;
 | |
|   const struct sqlite3_index_constraint *pConstraint;
 | |
|   pConstraint = pIdxInfo->aConstraint;
 | |
|   for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
 | |
|     if( pConstraint->usable==0 ) continue;
 | |
|     if( (idxNum & 3)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_GT ){
 | |
|       idxNum |= 1;
 | |
|       ltIdx = i;
 | |
|     }
 | |
|     if( (idxNum & 3)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_GE ){
 | |
|       idxNum |= 2;
 | |
|       ltIdx = i;
 | |
|     }
 | |
|     if( (idxNum & 12)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){
 | |
|       idxNum |= 4;
 | |
|       gtIdx = i;
 | |
|     }
 | |
|     if( (idxNum & 12)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE ){
 | |
|       idxNum |= 8;
 | |
|       gtIdx = i;
 | |
|     }
 | |
|   }
 | |
|   pIdxInfo->idxNum = idxNum;
 | |
|   if( ltIdx>=0 ){
 | |
|     pIdxInfo->aConstraintUsage[ltIdx].argvIndex = argvIdx++;
 | |
|     pIdxInfo->aConstraintUsage[ltIdx].omit = 1;
 | |
|   }
 | |
|   if( gtIdx>=0 ){
 | |
|     pIdxInfo->aConstraintUsage[gtIdx].argvIndex = argvIdx;
 | |
|     pIdxInfo->aConstraintUsage[gtIdx].omit = 1;
 | |
|   }
 | |
|   if( pIdxInfo->nOrderBy==1
 | |
|    && pIdxInfo->aOrderBy[0].desc==0
 | |
|   ){
 | |
|     pIdxInfo->orderByConsumed = 1;
 | |
|   }
 | |
|   if( (idxNum & 12)==0 ){
 | |
|     pIdxInfo->estimatedCost = (double)100000000;
 | |
|   }else if( (idxNum & 3)==0 ){
 | |
|     pIdxInfo->estimatedCost = (double)5;
 | |
|   }else{
 | |
|     pIdxInfo->estimatedCost = (double)1;
 | |
|   }
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** A virtual table module that provides read-only access to a
 | |
| ** Tcl global variable namespace.
 | |
| */
 | |
| static sqlite3_module wholenumberModule = {
 | |
|   0,                         /* iVersion */
 | |
|   wholenumberConnect,
 | |
|   wholenumberConnect,
 | |
|   wholenumberBestIndex,
 | |
|   wholenumberDisconnect, 
 | |
|   wholenumberDisconnect,
 | |
|   wholenumberOpen,           /* xOpen - open a cursor */
 | |
|   wholenumberClose,          /* xClose - close a cursor */
 | |
|   wholenumberFilter,         /* xFilter - configure scan constraints */
 | |
|   wholenumberNext,           /* xNext - advance a cursor */
 | |
|   wholenumberEof,            /* xEof - check for end of scan */
 | |
|   wholenumberColumn,         /* xColumn - read data */
 | |
|   wholenumberRowid,          /* xRowid - read data */
 | |
|   0,                         /* xUpdate */
 | |
|   0,                         /* xBegin */
 | |
|   0,                         /* xSync */
 | |
|   0,                         /* xCommit */
 | |
|   0,                         /* xRollback */
 | |
|   0,                         /* xFindMethod */
 | |
|   0,                         /* xRename */
 | |
| };
 | |
| 
 | |
| #endif /* SQLITE_OMIT_VIRTUALTABLE */
 | |
| 
 | |
| #ifdef _WIN32
 | |
| __declspec(dllexport)
 | |
| #endif
 | |
| int sqlite3_wholenumber_init(
 | |
|   sqlite3 *db, 
 | |
|   char **pzErrMsg, 
 | |
|   const sqlite3_api_routines *pApi
 | |
| ){
 | |
|   int rc = SQLITE_OK;
 | |
|   SQLITE_EXTENSION_INIT2(pApi);
 | |
| #ifndef SQLITE_OMIT_VIRTUALTABLE
 | |
|   rc = sqlite3_create_module(db, "wholenumber", &wholenumberModule, 0);
 | |
| #endif
 | |
|   return rc;
 | |
| }
 | 
