summaryrefslogtreecommitdiff
path: root/ext/misc/wholenumber.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/misc/wholenumber.c')
-rw-r--r--ext/misc/wholenumber.c274
1 files changed, 274 insertions, 0 deletions
diff --git a/ext/misc/wholenumber.c b/ext/misc/wholenumber.c
new file mode 100644
index 0000000..63369c6
--- /dev/null
+++ b/ext/misc/wholenumber.c
@@ -0,0 +1,274 @@
+/*
+** 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;
+}