From: drh <> Date: Thu, 18 Dec 2025 12:49:44 +0000 (+0000) Subject: Enhance the vt02.c test virtual table with the ability to process X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=93c6b19f927fb3b7dada47f48fdf41e55a0de834;p=thirdparty%2Fsqlite.git Enhance the vt02.c test virtual table with the ability to process ORDER BY DESC. FossilOrigin-Name: 35461a8d5a103e373e5b38b3974a3bb1074e914e862825108713b36bef04b6bd --- diff --git a/manifest b/manifest index f0e2b70faa..07625c3692 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sreturn\svalue\sof\ssqlite3_vtab_distinct()\sin\scases\swhere\sa\svirtual\stable\squery\shas\ssimilar\sGROUP\sBY\sand\sORDER\sBY\sexpression\slists. -D 2025-12-17T21:00:06.696 +C Enhance\sthe\svt02.c\stest\svirtual\stable\swith\sthe\sability\sto\sprocess\nORDER\sBY\sDESC. +D 2025-12-18T12:49:44.221 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -1948,7 +1948,7 @@ F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 F test/view.test 3c23d7a068e9e4a0c4e6907498042772adea725f0630c3d9638ffd4e5a08b92b F test/view2.test db32c8138b5b556f610b35dfddd38c5a58a292f07fda5281eedb0851b2672679 F test/view3.test ad8a8290ee2b55ff6ce66c9ef1ce3f1e47926273a3814e1c425293e128a95456 -F test/vt02.c 5b44ac67b1a283fedecf2d6e2ceda61e7a157f01d44dcb4490dcb1e87d057060 +F test/vt02.c 49f327ddd077c52eab87d20f8c7267fd9f716aa4bcb8f449a9b62e8d9e8b0c90 F test/vt100-a.sql a3e188a118ca78c08b41681a4db6d0f353e554ceb33f1573b1872d16e2d30596 F test/vtab1.test 09a72330d0f31eda2ffaa828b06a6b917fb86250ee72de0301570af725774c07 F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082 @@ -2187,8 +2187,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7986a35d27fe0cfd7d9a3bfec0ee0d1c5556b24d571bb68c35dd5eb7251e423c -R 06ffa773b4d06150e51f5a59f3ea234b -U dan -Z 5b36ed65d69bc38cf13ab6a46675d3e9 +P d017ae8640f24543ad5bf37a3e514c1e919730b8c686255c61890448ba22b3e1 +R faaecd2038048c73b75d6f197dafc3f9 +U drh +Z 1008e4c9d6dee7b8022617033f94919d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8f170058c1..806c5eb9bb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d017ae8640f24543ad5bf37a3e514c1e919730b8c686255c61890448ba22b3e1 +35461a8d5a103e373e5b38b3974a3bb1074e914e862825108713b36bef04b6bd diff --git a/test/vt02.c b/test/vt02.c index 06fade0969..e82549d6b0 100644 --- a/test/vt02.c +++ b/test/vt02.c @@ -45,8 +45,29 @@ ** a=... AND b=... AND c=... ** a=... AND b=... AND c=... AND d=... ** -** Various ORDER BY constraints are also recognized and consumed. The -** OFFSET constraint is recognized and consumed. +** The table will also recognize IN constraints on column D using the +** sqlite3_vtab_in_first() and sqlite3_vtab_in_next() interfaces: +** +** a=... AND d IN (...) +** a=... AND b=... AND d IN (...) +** a=... AND b=... AND c=... AND d IN (...) +** +** Various ORDER BY constraints are also recognized and consumed. +** +** ORDER BY x +** ORDER BY a +** ORDER BY a, b +** ORDER BY a, b, c +** ORDER BY a, b, c, d +** +** The above also work if every term is DESC rather than ASC. However, +** the orderByConsumed is not set if there are a mixture of ASC and DESC +** terms in the ORDER BY clause. +** +** The sqlite3_vtab_distinct() interface is used to recognize DISTINCT +** and GROUP BY constraints and consume the corresponding sorting requirements. +** +** The OFFSET constraint is recognized and consumed. ** ** ## TABLE-VALUED FUNCTION ** @@ -136,14 +157,12 @@ ** ## COMPILING AND RUNNING ** ** This file can also be compiled separately as a loadable extension -** for SQLite (as long as the -DTH3_VERSION is not defined). To compile as a -** loadable extension do his: -** -** gcc -Wall -g -shared -fPIC -I. -DSQLITE_DEBUG vt02.c -o vt02.so -** -** Or on Windows: +** for SQLite (as long as the -DTH3_VERSION is not defined). To compile as a +** loadable extension do something like this: ** -** cl vt02.c -link -dll -out:vt02.dll +** (linux) gcc -shared -fPIC -I. vt02.c -o vt02.so +** (mac) clang -dynamiclib -fPIC -I. vt02.c -o vt02.dylib +** (windows) cl vt02.c -link -dll -out:vt02.dll ** ** Then load into the CLI using: ** @@ -167,6 +186,7 @@ ** 2x increment by 100 ** 3x increment by 1000 ** 1xx Use offset provided by argv[N] +** 1xxx Reverse output order (to implement ORDER BY ... DESC) */ #ifndef TH3_VERSION /* These bits for separate compilation as a loadable extension, only */ @@ -203,6 +223,7 @@ struct vt02_cur { sqlite3_vtab_cursor parent; /* Base class. Must be first */ sqlite3_int64 i; /* Current entry */ sqlite3_int64 iEof; /* Indicate EOF when reaching this value */ + sqlite3_int64 iMin; /* EOF if dropping below this value */ int iIncr; /* Amount by which to increment */ unsigned int mD; /* Mask of allowed D-column values */ }; @@ -292,7 +313,7 @@ static int vt02Close(sqlite3_vtab_cursor *pCursor){ */ static int vt02Eof(sqlite3_vtab_cursor *pCursor){ vt02_cur *pCur = (vt02_cur*)pCursor; - return pCur->i<0 || pCur->i>=pCur->iEof; + return pCur->iiMin || pCur->i>=pCur->iEof; } /* Advance the cursor to the next row in the table @@ -301,8 +322,8 @@ static int vt02Next(sqlite3_vtab_cursor *pCursor){ vt02_cur *pCur = (vt02_cur*)pCursor; do{ pCur->i += pCur->iIncr; - if( pCur->i<0 ) pCur->i = pCur->iEof; - }while( (pCur->mD & (1<<(pCur->i%10)))==0 && pCur->iiEof ); + if( pCur->iiMin || pCur->i>=pCur->iEof ) break; + }while( (pCur->mD & (1<<(pCur->i%10)))==0 ); return SQLITE_OK; } @@ -324,6 +345,7 @@ static int vt02Next(sqlite3_vtab_cursor *pCursor){ ** 2x increment by 100 ** 3x increment by 1000 ** 1xx Use offset provided by argv[N] +** 1xxx Output rows in reverse order */ static int vt02Filter( sqlite3_vtab_cursor *pCursor, /* The cursor to rewind */ @@ -334,11 +356,17 @@ static int vt02Filter( ){ vt02_cur *pCur = (vt02_cur*)pCursor; /* The vt02 cursor */ int bUseOffset = 0; /* True to use OFFSET value */ + int bReverse = 0; /* Output rows in reverse order */ int iArg = 0; /* argv[] values used so far */ int iOrigIdxNum = idxNum; /* Original value for idxNum */ pCur->iIncr = 1; + pCur->iMin = 0; pCur->mD = 0x3ff; + if( idxNum>=1000 ){ + bReverse = 1; + idxNum -= 1000; + } if( idxNum>=100 ){ bUseOffset = 1; idxNum -= 100; @@ -416,9 +444,17 @@ static int vt02Filter( }else{ goto vt02_bad_idxnum; } + if( bReverse ){ + sqlite3_int64 x; + x = pCur->i + ((pCur->iEof - pCur->i)/pCur->iIncr)*pCur->iIncr; + if( x>=pCur->iEof ) x -= pCur->iIncr; + pCur->iIncr = -pCur->iIncr; + pCur->iMin = pCur->i; + pCur->i = x; + } if( bUseOffset ){ int nSkip = sqlite3_value_int(argv[iArg]); - while( nSkip-- > 0 && pCur->iiEof ) vt02Next(pCursor); + while( nSkip-- > 0 && !vt02Eof(pCursor) ) vt02Next(pCursor); } return SQLITE_OK; @@ -838,24 +874,38 @@ static int vt02BestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ ** the same answer. */ if( pInfo->nOrderBy>0 && (flags & VT02_NO_SORT_OPT)==0 ){ + int eDistinct = sqlite3_vtab_distinct(pInfo); if( pInfo->idxNum==1 ){ /* There will only be one row of output. So it is always sorted. */ pInfo->orderByConsumed = 1; }else - if( pInfo->aOrderBy[0].iColumn<=0 - && pInfo->aOrderBy[0].desc==0 - ){ - /* First column of order by is X ascending */ + if( pInfo->aOrderBy[0].iColumn<=0 ){ + /* First column of order by is X */ + if( pInfo->aOrderBy[0].desc ){ + pInfo->idxNum += 1000; /* Reverse output order */ + } pInfo->orderByConsumed = 1; }else - if( sqlite3_vtab_distinct(pInfo)>=1 ){ + if( eDistinct>=1 ){ unsigned int x = 0; + int nDesc = 0; + int nAsc = 0; for(i=0; inOrderBy; i++){ int iCol = pInfo->aOrderBy[i].iColumn; if( iCol<0 ) iCol = 0; + if( pInfo->aOrderBy[i].desc ){ + nDesc++; + }else{ + nAsc++; + } x |= 1<0 && nAsc>0 ){ + if( eDistinct!=1 ) eDistinct = -999; /* Never set orderByConsumed */ + }else if( nAsc==0 ){ + pInfo->idxNum += 1000; /* Reverse output order */ + } + if( eDistinct==2 ){ /* DISTINCT */ if( x==0x02 ){ /* DISTINCT A */ pInfo->idxNum += 30; @@ -875,7 +925,7 @@ static int vt02BestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ /* DISTINCT A,B,C,D */ pInfo->orderByConsumed = 1; } - }else{ + }else if( eDistinct>=1 ){ /* GROUP BY or (DISTINCT and ORDER BY) */ if( x==0x02 ){ /* GROUP BY A */ pInfo->orderByConsumed = 1; @@ -901,7 +951,7 @@ static int vt02BestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ pInfo->needToFreeIdxStr = 1; } if( flags & VT02_BAD_IDXNUM ){ - pInfo->idxNum += 1000; + pInfo->idxNum += 10000; } if( iOffset>=0 ){