aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2022-01-22 00:18:01 +0000
committerdrh <>2022-01-22 00:18:01 +0000
commitec778d27241d54be6967a2d1eb44cf549507f728 (patch)
treef8d2f0217f8b3235cfcf55984a0b71b178029317 /src
parent4d7f335e8bd4773befdb73e7c0a42b6f773726f9 (diff)
downloadsqlite-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.c1
-rw-r--r--src/sqlite.h.in22
-rw-r--r--src/sqlite3ext.h2
-rw-r--r--src/where.c28
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;