]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
An initial attempt to implement sqlite3_vtab_distinct().
authordrh <>
Sat, 22 Jan 2022 00:18:01 +0000 (00:18 +0000)
committerdrh <>
Sat, 22 Jan 2022 00:18:01 +0000 (00:18 +0000)
FossilOrigin-Name: d571262d2345bb11e71bef395cf078e5d7303b974b38b4e319adda6194ccc1c5

ext/misc/qpvtab.c
manifest
manifest.uuid
src/loadext.c
src/sqlite.h.in
src/sqlite3ext.h
src/where.c
test/vtabdistinct.test [new file with mode: 0644]

index 6c145ffd17c9eaec845d843b87b608235723ad42..828a5ba1b8e5980a9a09c673446d6fac4c31205f 100644 (file)
@@ -372,6 +372,8 @@ static int qpvtabBestIndex(
       pIdxInfo->aOrderBy[i].desc
     );
   }
+  sqlite3_str_appendf(pStr, "sqlite3_vtab_distinct,%d,,,,\n", 
+                      sqlite3_vtab_distinct(pIdxInfo));
   sqlite3_str_appendf(pStr, "idxFlags,%d,,,,\n", pIdxInfo->idxFlags);
   sqlite3_str_appendf(pStr, "colUsed,%d,,,,\n", (int)pIdxInfo->colUsed);
   pIdxInfo->estimatedCost = (double)10;
index 577199e3ba07847465fc7f5dd32dc2b81bb61659..cc182828321e95cd2f8f546713b0f280353a1748 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Update\sevidence\smarks\sfor\sthe\slatest\schanges\sto\sthe\sdocumentation.
-D 2022-01-21T19:26:18.123
+C An\sinitial\sattempt\sto\simplement\ssqlite3_vtab_distinct().
+D 2022-01-22T00:18:01.617
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -316,7 +316,7 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1
 F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f
 F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
 F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
-F ext/misc/qpvtab.c d40b07a8c341d16629010c3e8d8801f1477f70d6257e052973a8ddf14c07cd8d
+F ext/misc/qpvtab.c c662fa0a452ad286e49b6c83ac917600656b2eb47d2225ff6185c56bf80cf8d2
 F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386
 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
 F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
@@ -515,7 +515,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
 F src/insert.c e528416ff5d86fc5d656ea6a26f03fde39836b6175f93048c32a03cb2ee16743
 F src/json.c 78fdec9af3a8bfb5ae685707b2701276fec1942b8f5f26689b2701debe32bcd2
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
-F src/loadext.c 9a693eb89575af5d54b025c1e927b2ea8114bbeee3db346e8abc81676dd82160
+F src/loadext.c 657534339585ac234839e5187aa51d8802f292e0771c4f874b3af1f1223f81e2
 F src/main.c 2b6b0dbfeb14d4bb57e368604b0736b2aa42b51b00339d399b01d6b1fc9b4960
 F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
@@ -554,9 +554,9 @@ F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027
 F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e
-F src/sqlite.h.in 67e49a50bb29e3af86d2b3606af6b3fe20a0d09cf326cc574d632d878c0696d6
+F src/sqlite.h.in 1335c91f118ed8490ab8661becf8ad7d29fe531149464d72ccc095290c872e86
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
-F src/sqlite3ext.h 234b5ff5c20512a116b14d6d08e23caeb68667749f8a94117779a9d38afc7e5c
+F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
 F src/sqliteInt.h 21a31abf60222f50c1d654cdc27ad9d4040249f0341129dd8286b8b5b32bcd30
 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
@@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
 F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
 F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
-F src/where.c eb54405957c295e0706cbaea74f9e7cbb3d3dfdefe35d243440d2b4cbf601f0c
+F src/where.c 7df767249645ba428b8a217278319028c679f48f2daecac8461ae6e2d281cd6d
 F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be
 F src/wherecode.c a0a5138b28550dd95916435283c507aa6bf24607ef38a0a18011e6626684330a
 F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3
@@ -1724,6 +1724,7 @@ F test/vtabK.test 13293177528fada1235c0112db0d187d754af1355c5a39371abd365104e3af
 F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783
 F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65
 F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
+F test/vtabdistinct.test e35a8c91cd9e2a1130eb708376e33aa38511b880fb7c1691387d3e9ec57d9157
 F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12
 F test/vtabrhs1.test c138346be341916ecc9d918dcfc2657d27bce211a350a82b01d62d224b167b56
 F test/wal.test b7cc6984709f54afbf8441747ced1f646af120bf0c1b1d847bfa39306fbea089
@@ -1940,8 +1941,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 2f5dc7a9eed89baf6814e9e123354b262c806c853dee1243c93286c564b9aba8
-R fe7b9dd51502fbf713e5aec593679235
+P 19247e919fab9748cae561cb12c4c3c106064390a37e32e724d9a9066cfaff8e
+R dfc70e19d986a79e444a3389314d1aa6
+T *branch * sqlite3_vtab_distinct
+T *sym-sqlite3_vtab_distinct *
+T -sym-trunk *
 U drh
-Z 6c89130f8a98285b65b9e81e57d8e5fd
+Z 502f02fc5994424f0d3cd19482ecaf51
 # Remove this line to create a well-formed Fossil manifest.
index 7a58964939d27cae96dcf9d650a9c84986d6b917..7744a710a7d82d5282d6634343693b07f0ac3078 100644 (file)
@@ -1 +1 @@
-19247e919fab9748cae561cb12c4c3c106064390a37e32e724d9a9066cfaff8e
\ No newline at end of file
+d571262d2345bb11e71bef395cf078e5d7303b974b38b4e319adda6194ccc1c5
\ No newline at end of file
index c917e11c8eef4accf3d69e8cdc68ad05eaed7100..a4aad7e7483d5fdb1c04e6a6ac8a6efb38002faf 100644 (file)
@@ -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
index ca27742cb1f6910d3b5574e9921f2b705ccfdb7a..1e78911129495df3bc59a592e8e5da6625b6ca19 100644 (file)
@@ -9503,6 +9503,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
index 580078b6d08e19b28ccbcc790e3e137d040e99c9..88010b9d8d3f8c99f0030c91e6dc6477c91367d3 100644 (file)
@@ -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)
index 3fa7a921de899df93b06ccc294569749a120b83e..fe262b36e1f7664913a2d12b7d5d564eb8255853 100644 (file)
@@ -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;
diff --git a/test/vtabdistinct.test b/test/vtabdistinct.test
new file mode 100644 (file)
index 0000000..63fa156
--- /dev/null
@@ -0,0 +1,36 @@
+# 2022-01-21
+#
+# 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 tests for sqlite3_vtab_distinct() interface.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix vtabdistinct
+
+ifcapable !vtab {
+  finish_test
+  return
+}
+load_static_extension db qpvtab
+
+do_execsql_test 1.1 {
+  SELECT ix FROM qpvtab WHERE vn='sqlite3_vtab_distinct';
+} {0}
+do_execsql_test 1.2 {
+  SELECT DISTINCT ix FROM qpvtab WHERE vn='sqlite3_vtab_distinct';
+} {1}
+do_execsql_test 1.3 {
+  SELECT distinct vn, ix FROM qpvtab(3)
+   WHERE +vn IN ('sqlite3_vtab_distinct','nOrderBy');
+} {nOrderBy 2 sqlite3_vtab_distinct 1}
+
+finish_test