Index: ext/misc/carray.c ================================================================== --- ext/misc/carray.c +++ ext/misc/carray.c @@ -23,10 +23,18 @@ ** There is an optional third parameter to determine the datatype of ** the C-language array. Allowed values of the third parameter are ** 'int32', 'int64', 'double', 'char*'. Example: ** ** SELECT * FROM carray($ptr,10,'char*'); +** +** There is a second table-valued funnction named "carrray_asc" that works +** exactly like carray except that it requires the values in the $ptr array +** to be in ascending order. Queries involving ORDER BY clauses can sometimes +** be a little faster with carray_asc compared to plain carray. However, if +** the application provides carray_asc($ptr) with a $ptr array in which the +** elements are not in ascending order, then incorrect query results might +** result. ** ** HOW IT WORKS ** ** The carray "function" is really a virtual table with the ** following schema: @@ -62,10 +70,24 @@ /* ** Names of types */ static const char *azType[] = { "int32", "int64", "double", "char*" }; +/* carray_vtab is a subclass of sqlite3_vtab containing carray-specific +** extensions. +*/ +typedef struct carray_vtab carray_vtab; +struct carray_vtab { + sqlite3_vtab base; /* Base class - must be first */ + unsigned int mFlags; /* Operational flags */ +}; + +/* +** Possible values for carray_vtab.mFlags +*/ +#define CARRAY_ASC 0x0001 /* Values are always in ascending order */ + /* carray_cursor is a subclass of sqlite3_vtab_cursor which will ** serve as the underlying representation of a cursor that scans ** over rows of the result */ @@ -96,11 +118,11 @@ void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ - sqlite3_vtab *pNew; + carray_vtab *pNew; int rc; /* Column numbers */ #define CARRAY_COLUMN_VALUE 0 #define CARRAY_COLUMN_POINTER 1 @@ -108,13 +130,15 @@ #define CARRAY_COLUMN_CTYPE 3 rc = sqlite3_declare_vtab(db, "CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)"); if( rc==SQLITE_OK ){ - pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); + pNew = sqlite3_malloc( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); + if( pAux ) pNew->mFlags = *(unsigned int*)pAux; } return rc; } /* @@ -303,10 +327,17 @@ pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2; pIdxInfo->aConstraintUsage[cntIdx].omit = 1; pIdxInfo->estimatedCost = (double)1; pIdxInfo->estimatedRows = 100; pIdxInfo->idxNum = 2; + if( pIdxInfo->nOrderBy==1 + && pIdxInfo->aOrderBy[0].iColumn==0 + && pIdxInfo->aOrderBy[0].desc==0 + && (((carray_vtab*)tab)->mFlags & CARRAY_ASC)!=0 + ){ + pIdxInfo->orderByConsumed = 1; + } if( ctypeIdx>=0 ){ pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3; pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1; pIdxInfo->idxNum = 3; } @@ -354,11 +385,16 @@ sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; + static const unsigned int mAscFlags = CARRAY_ASC; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE rc = sqlite3_create_module(db, "carray", &carrayModule, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_module(db, "carray_asc", &carrayModule, + (void*)&mAscFlags); + } #endif return rc; } Index: test/tabfunc01.test ================================================================== --- test/tabfunc01.test +++ test/tabfunc01.test @@ -161,10 +161,35 @@ do_test tabfunc01-702 { db eval { SELECT b FROM t600 WHERE a IN carray($PTR1,4,'int32'); } } {(005) (007) (013) (017)} +do_test tabfunc01-703 { + db eval { + SELECT value FROM carray($PTR1, 5) ORDER BY value; + } +} {5 7 13 17 23} +do_test tabfunc01-703x {db status sort} 1 +do_test tabfunc01-704 { + db eval { + SELECT value FROM carray_asc($PTR1, 5) ORDER BY value; + } +} {5 7 13 17 23} +do_test tabfunc01-704x {db status sort} 0 +do_test tabfunc01-705 { + db eval { + SELECT value FROM carray($PTR1, 5) ORDER BY value DESC; + } +} {23 17 13 7 5} +do_test tabfunc01-705x {db status sort} 1 +do_test tabfunc01-706 { + db eval { + SELECT value FROM carray_asc($PTR1, 5) ORDER BY value DESC; + } +} {23 17 13 7 5} +do_test tabfunc01-706x {db status sort} 1 + do_catchsql_test tabfunc01-710 { SELECT b FROM t600 WHERE a IN carray($PTR1,5,'int33'); } {1 {unknown datatype: 'int33'}} do_test tabfunc01-720 {