diff options
author | drh <> | 2022-01-22 00:18:01 +0000 |
---|---|---|
committer | drh <> | 2022-01-22 00:18:01 +0000 |
commit | ec778d27241d54be6967a2d1eb44cf549507f728 (patch) | |
tree | f8d2f0217f8b3235cfcf55984a0b71b178029317 /src | |
parent | 4d7f335e8bd4773befdb73e7c0a42b6f773726f9 (diff) | |
download | sqlite-ec778d27241d54be6967a2d1eb44cf549507f728.tar.gz sqlite-ec778d27241d54be6967a2d1eb44cf549507f728.zip |
An initial attempt to implement sqlite3_vtab_distinct().
FossilOrigin-Name: d571262d2345bb11e71bef395cf078e5d7303b974b38b4e319adda6194ccc1c5
Diffstat (limited to 'src')
-rw-r--r-- | src/loadext.c | 1 | ||||
-rw-r--r-- | src/sqlite.h.in | 22 | ||||
-rw-r--r-- | src/sqlite3ext.h | 2 | ||||
-rw-r--r-- | src/where.c | 28 |
4 files changed, 48 insertions, 5 deletions
diff --git a/src/loadext.c b/src/loadext.c index c917e11c8..a4aad7e74 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -488,6 +488,7 @@ static const sqlite3_api_routines sqlite3Apis = { /* Version 3.38.0 and later */ sqlite3_error_offset, sqlite3_vtab_rhs_value, + sqlite3_vtab_distinct, }; /* True if x is the directory separator character diff --git a/src/sqlite.h.in b/src/sqlite.h.in index ca27742cb..1e7891112 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -9504,6 +9504,28 @@ int sqlite3_vtab_nochange(sqlite3_context*); SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); /* +** CAPI3REF: Determine if virtual table query is DISTINCT +** METHOD: sqlite3_index_info +** +** This API may only be used from within an xBestIndex() callback. The +** results of calling it from outside of an xBestIndex() callback are +** undefined and probably harmful. +** +** ^The sqlite3_vtab_distinct() returns an integer that is either 0, 1, or +** 2. ^The sqlite3_vtab_distinct() interface returns 0 if SQLite needs the +** output rows sorted as defined by the nOrderBy and aOrderBy fields of the +** [sqlite3_index_info] object P. ^The sqlite3_vtab_distinct() interface +** returns 1 if SQLite needs all rows to be returned and for equivalent rows +** to be adjacent to one another, but if it does not require that the rows +** be sorted. ^The sqlite3_vtab_distinct() interface returns 2 if SQLite only +** needs the virtual table to return rows that are distinct for the columns +** identified by the nOrderBy and aOrderBy fields of the [sqlite3_index_info] +** object. If rows are returned that differ in any of the columns identified +** by the nOrderBy and aOrderBy fields, then all such rows should be adjacent. +*/ +int sqlite3_vtab_distinct(sqlite3_index_info*); + +/* ** CAPI3REF: Constraint values in xBestIndex() ** METHOD: sqlite3_index_info ** diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 580078b6d..88010b9d8 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -347,6 +347,7 @@ struct sqlite3_api_routines { /* Version 3.38.0 and later */ int (*error_offset)(sqlite3*); int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**); + int (*vtab_distinct)(sqlite3_index_info*); }; /* @@ -661,6 +662,7 @@ typedef int (*sqlite3_loadext_entry)( /* Version 3.38.0 and later */ #define sqlite3_error_offset sqlite3_api->error_offset #define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value +#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/src/where.c b/src/where.c index 3fa7a921d..fe262b36e 100644 --- a/src/where.c +++ b/src/where.c @@ -32,6 +32,7 @@ typedef struct HiddenIndexInfo HiddenIndexInfo; struct HiddenIndexInfo { WhereClause *pWC; /* The Where clause being analyzed */ Parse *pParse; /* The parsing context */ + int eDistinct; /* Value to return from sqlite3_vtab_distinct() */ sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST ** because extra space is allocated to hold up ** to nTerm such values */ @@ -1101,15 +1102,15 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( ** by passing the pointer returned by this function to freeIndexInfo(). */ static sqlite3_index_info *allocateIndexInfo( - Parse *pParse, /* The parsing context */ + WhereInfo *pWInfo, /* The WHERE clause */ WhereClause *pWC, /* The WHERE clause being analyzed */ Bitmask mUnusable, /* Ignore terms with these prereqs */ SrcItem *pSrc, /* The FROM clause term that is the vtab */ - ExprList *pOrderBy, /* The ORDER BY clause */ u16 *pmNoOmit /* Mask of terms not to omit */ ){ int i, j; int nTerm; + Parse *pParse = pWInfo->pParse; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_orderby *pIdxOrderBy; struct sqlite3_index_constraint_usage *pUsage; @@ -1119,7 +1120,9 @@ static sqlite3_index_info *allocateIndexInfo( sqlite3_index_info *pIdxInfo; u16 mNoOmit = 0; const Table *pTab; - + int eDistinct = 0; + ExprList *pOrderBy = pWInfo->pOrderBy; + assert( pSrc!=0 ); pTab = pSrc->pTab; assert( pTab!=0 ); @@ -1203,6 +1206,9 @@ static sqlite3_index_info *allocateIndexInfo( } if( i==n){ nOrderBy = n; + if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) ){ + eDistinct = 1; + } } } @@ -1225,6 +1231,7 @@ static sqlite3_index_info *allocateIndexInfo( pIdxInfo->aConstraintUsage = pUsage; pHidden->pWC = pWC; pHidden->pParse = pParse; + pHidden->eDistinct = eDistinct; for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ u16 op; if( (pTerm->wtFlags & TERM_OK)==0 ) continue; @@ -3691,6 +3698,18 @@ int sqlite3_vtab_rhs_value( return rc; } + +/* +** Return true if ORDER BY clause may be handled as DISTINCT. +*/ +int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){ + HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + assert( pHidden->eDistinct==0 + || pHidden->eDistinct==1 + || pHidden->eDistinct==2 ); + return pHidden->eDistinct; +} + /* ** Add all WhereLoop objects for a table of the join identified by ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. @@ -3740,8 +3759,7 @@ static int whereLoopAddVirtual( pNew = pBuilder->pNew; pSrc = &pWInfo->pTabList->a[pNew->iTab]; assert( IsVirtual(pSrc->pTab) ); - p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy, - &mNoOmit); + p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit); if( p==0 ) return SQLITE_NOMEM_BKPT; pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; |