1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Use doclist-indexes with "ORDER BY rowid ASC" fts5 queries as well.

FossilOrigin-Name: d028ba6589f3122b635474c2683c0f93d5bc6c7c
This commit is contained in:
dan
2014-08-05 19:00:22 +00:00
parent 9a67058a63
commit d5997d80cb
6 changed files with 260 additions and 170 deletions

View File

@ -550,18 +550,23 @@ struct Fts5NodeIter {
** of a doclist-index record.
**
** pData:
** A reference to the dlidx record.
** Record containing the doclist-index data.
**
** bEof:
** Set to true once iterator has reached EOF.
**
** iOff:
** Set to the current offset within record pData.
*/
struct Fts5DlidxIter {
Fts5Data *pData; /* Data for doclist index, if any */
int iOff; /* Current offset into pDlidx */
int bRowidValid; /* iRowid is valid */
int bEof; /* At EOF already */
int iFirstOff; /* Used by reverse iterators only */
/* Output variables */
int iLeafPgno; /* Page number of current leaf page */
int bZero; /* True if current leaf has no rowids */
i64 iRowid; /* If bZero==0, first rowid on leaf */
i64 iRowid; /* First rowid on leaf iLeafPgno */
};
@ -1124,14 +1129,83 @@ static void fts5NodeIterFree(Fts5NodeIter *pIter){
}
/*
** Return non-zero if EOF is reached.
** The iterator passed as the first argument has the following fields set
** as follows. This function sets up the rest of the iterator so that it
** points to the first rowid in the doclist-index.
**
** pData: pointer to doclist-index record,
** iLeafPgno: page number that this doclist-index is associated with.
*/
static int fts5DlidxIterNext(Fts5DlidxIter *pIter, int bRev){
if( bRev ){
static int fts5DlidxIterFirst(Fts5DlidxIter *pIter){
Fts5Data *pData = pIter->pData;
int i;
assert( pIter->pData );
assert( pIter->iLeafPgno>0 );
/* Count the number of leading 0x00 bytes. Then set iLeafPgno. */
for(i=0; i<pData->n; i++){
if( pData->p[i] ) break;
}
pIter->iLeafPgno += (i+1);
pIter->iOff = i;
/* Unless we are already at the end of the doclist-index, load the first
** rowid value. */
if( pIter->iOff<pData->n ){
pIter->iOff += getVarint(&pData->p[pIter->iOff], (u64*)&pIter->iRowid);
}else{
pIter->bEof = 1;
}
pIter->iFirstOff = pIter->iOff;
return pIter->bEof;
}
/*
** Advance the iterator passed as the only argument.
*/
static int fts5DlidxIterNext(Fts5DlidxIter *pIter){
Fts5Data *pData = pIter->pData;
int iOff;
for(iOff=pIter->iOff; iOff<pData->n; iOff++){
if( pData->p[iOff] ) break;
}
if( iOff<pData->n ){
i64 iVal;
pIter->iLeafPgno += (iOff - pIter->iOff) + 1;
iOff += getVarint(&pData->p[iOff], (u64*)&iVal);
pIter->iRowid -= iVal;
pIter->iOff = iOff;
}else{
pIter->bEof = 1;
}
return pIter->bEof;
}
static int fts5DlidxIterEof(Fts5Index *p, Fts5DlidxIter *pIter){
return (p->rc!=SQLITE_OK || pIter->bEof);
}
static void fts5DlidxIterLast(Fts5DlidxIter *pIter){
if( fts5DlidxIterFirst(pIter)==0 ){
while( 0==fts5DlidxIterNext(pIter) );
pIter->bEof = 0;
}
}
static int fts5DlidxIterPrev(Fts5DlidxIter *pIter){
int iOff = pIter->iOff;
int iLimit;
assert( pIter->bEof==0 );
if( iOff<=pIter->iFirstOff ){
pIter->bEof = 1;
}else{
u8 *a = pIter->pData->p;
i64 iVal;
int iLimit;
/* Currently iOff points to the first byte of a varint. This block
** decrements iOff until it points to the first byte of the previous
@ -1141,53 +1215,19 @@ static int fts5DlidxIterNext(Fts5DlidxIter *pIter, int bRev){
for(iOff--; iOff>iLimit; iOff--){
if( (a[iOff-1] & 0x80)==0 ) break;
}
pIter->iOff = iOff;
if( iOff<=0 ){
pIter->bEof = 1;
return 1;
}
getVarint(&a[iOff], (u64*)&iVal);
if( iVal==0 ){
pIter->bZero = 1;
}else if( iOff==0 ){
pIter->iRowid = iVal;
}else{
pIter->iRowid += iVal;
}
pIter->iLeafPgno--;
}else{
i64 iVal;
if( pIter->iOff>=pIter->pData->n ){
pIter->bEof = 1;
return 1;
while( a[iOff-1]==0x00 ){
iOff--;
pIter->iLeafPgno--;
}
pIter->iOff += getVarint(&pIter->pData->p[pIter->iOff], (u64*)&iVal);
if( iVal==0 ){
pIter->bZero = 1;
}else{
pIter->bZero = 0;
if( pIter->bRowidValid ){
pIter->iRowid -= iVal;
}else{
pIter->bRowidValid = 1;
pIter->iRowid = iVal;
}
}
pIter->iLeafPgno++;
}
return 0;
pIter->iOff = iOff;
}
static void fts5DlidxIterLast(Fts5DlidxIter *pIter){
while( 0==fts5DlidxIterNext(pIter, 0) );
assert( pIter->iOff==pIter->pData->n && pIter->bEof==1 );
pIter->bEof = 0;
}
static int fts5DlidxIterEof(Fts5Index *p, Fts5DlidxIter *pIter){
return (p->rc!=SQLITE_OK || pIter->bEof);
return pIter->bEof;
}
static void fts5DlidxIterInit(
@ -1213,10 +1253,9 @@ static void fts5DlidxIterInit(
}
pIter->pData = pDlidx;
pIter->iLeafPgno = iLeafPgno;
if( bRev==0 ){
fts5DlidxIterNext(pIter, 0);
fts5DlidxIterFirst(pIter);
}else{
fts5DlidxIterLast(pIter);
}
@ -1438,44 +1477,6 @@ static void fts5SegIterNext(
pIter->iRowid += iDelta;
}else{
fts5SegIterReverseNewPage(p, pIter);
#if 0
fts5DataRelease(pIter->pLeaf);
pIter->pLeaf = 0;
while( p->rc==SQLITE_OK && pIter->iLeafPgno>pIter->iTermLeafPgno ){
Fts5Data *pNew;
pIter->iLeafPgno--;
pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID(
pIter->iIdx, pIter->pSeg->iSegid, 0, pIter->iLeafPgno
));
if( pNew ){
if( pIter->iLeafPgno==pIter->iTermLeafPgno ){
if( pIter->iTermLeafOffset<pNew->n ){
pIter->pLeaf = pNew;
pIter->iLeafOffset = pIter->iTermLeafOffset;
}
}else{
int iRowidOff, dummy;
fts5LeafHeader(pNew, &iRowidOff, &dummy);
if( iRowidOff ){
pIter->pLeaf = pNew;
pIter->iLeafOffset = iRowidOff;
}
}
if( pIter->pLeaf ){
u8 *a = &pIter->pLeaf->p[pIter->iLeafOffset];
pIter->iLeafOffset += getVarint(a, (u64*)&pIter->iRowid);
break;
}else{
fts5DataRelease(pNew);
}
}
}
if( pIter->pLeaf ){
fts5SegIterReverseInitPage(p, pIter);
}
#endif
}
}else{
Fts5Data *pLeaf = pIter->pLeaf;
@ -1555,6 +1556,11 @@ static void fts5SegIterReverse(Fts5Index *p, int iIdx, Fts5SegIter *pIter){
/* Move to the page that contains the last rowid in this doclist. */
pLeaf = pIter->pLeaf;
if( pIter->pDlidx ){
int iSegid = pIter->pSeg->iSegid;
pgnoLast = pIter->pDlidx->iLeafPgno;
pLast = fts5DataRead(p, FTS5_SEGMENT_ROWID(iIdx, iSegid, 0, pgnoLast));
}else{
while( iOff<pLeaf->n ){
int nPos;
i64 iDelta;
@ -1595,6 +1601,7 @@ static void fts5SegIterReverse(Fts5Index *p, int iIdx, Fts5SegIter *pIter){
}
}
}
}
/* If pLast is NULL at this point, then the last rowid for this doclist
** lies on the page currently indicated by the iterator. In this case
@ -1615,7 +1622,6 @@ static void fts5SegIterReverse(Fts5Index *p, int iIdx, Fts5SegIter *pIter){
}
fts5SegIterReverseInitPage(p, pIter);
pIter->flags |= FTS5_SEGITER_REVERSE;
}
/*
@ -1733,6 +1739,9 @@ static void fts5SegIterSeekInit(
if( bGe==0 ){
pIter->flags |= FTS5_SEGITER_ONETERM;
if( pIter->pLeaf ){
if( flags & FTS5INDEX_QUERY_ASC ){
pIter->flags |= FTS5_SEGITER_REVERSE;
}
if( bDlidx ){
fts5SegIterLoadDlidx(p, iIdx, pIter);
}
@ -1879,37 +1888,44 @@ static void fts5SegIterNextFrom(
int bRev = (pIter->flags & FTS5_SEGITER_REVERSE);
Fts5DlidxIter *pDlidx = pIter->pDlidx;
int iLeafPgno = pIter->iLeafPgno;
int bMove = 1;
assert( pIter->flags & FTS5_SEGITER_ONETERM );
assert( pIter->pDlidx );
assert( pIter->pLeaf );
if( bRev==0 ){
while( fts5DlidxIterEof(p, pDlidx)==0 && iMatch<pDlidx->iRowid ){
if( pDlidx->bZero==0 ) iLeafPgno = pDlidx->iLeafPgno;
fts5DlidxIterNext(pDlidx, 0);
iLeafPgno = pDlidx->iLeafPgno;
fts5DlidxIterNext(pDlidx);
}
assert( iLeafPgno>=pIter->iLeafPgno || p->rc );
if( iLeafPgno>pIter->iLeafPgno ){
fts5SegIterGotoPage(p, pIter, iLeafPgno);
bMove = 0;
}
}else if( 0 ){
}else{
assert( iMatch>pIter->iRowid );
while( fts5DlidxIterEof(p, pDlidx)==0 && iMatch>pDlidx->iRowid ){
fts5DlidxIterNext(pDlidx, 0);
if( pDlidx->bZero==0 ) iLeafPgno = pDlidx->iLeafPgno;
fts5DlidxIterPrev(pDlidx);
}
assert( iLeafPgno<=pIter->iLeafPgno || p->rc );
iLeafPgno = pDlidx->iLeafPgno;
assert( fts5DlidxIterEof(p, pDlidx) || iLeafPgno<=pIter->iLeafPgno );
if( iLeafPgno<pIter->iLeafPgno ){
fts5SegIterGotoPage(p, pIter, iLeafPgno);
pIter->iLeafPgno = iLeafPgno+1;
fts5SegIterReverseNewPage(p, pIter);
bMove = 0;
}
}
while( 1 ){
fts5SegIterNext(p, pIter);
if( bMove ) fts5SegIterNext(p, pIter);
if( pIter->pLeaf==0 ) break;
if( bRev==0 && pIter->iRowid<=iMatch ) break;
if( bRev!=0 && pIter->iRowid>=iMatch ) break;
bMove = 1;
}
}
@ -3377,7 +3393,50 @@ static void fts5BtreeIterFree(Fts5BtreeIter *pIter){
fts5BufferFree(&pIter->term);
}
/*
** This function is purely an internal test. It does not contribute to
** FTS functionality, or even the integrity-check, in any way.
**
** Instead, it tests that the same set of pgno/rowid combinations are
** visited regardless of whether the doclist-index identified by parameters
** iIdx/iSegid/iLeaf is iterated in forwards or reverse order.
*/
#ifdef SQLITE_DEBUG
static void fts5DlidxIterTestReverse(
Fts5Index *p,
int iIdx, /* Index to load doclist-index from */
int iSegid, /* Segment id to load from */
int iLeaf /* Load doclist-index for this leaf */
){
Fts5DlidxIter *pDlidx = 0;
i64 cksum1 = 13;
i64 cksum2 = 13;
for(fts5DlidxIterInit(p, 0, iIdx, iSegid, iLeaf, &pDlidx);
fts5DlidxIterEof(p, pDlidx)==0;
fts5DlidxIterNext(pDlidx)
){
cksum1 = (cksum1 ^ ( (i64)(pDlidx->iLeafPgno) << 32 ));
cksum1 = (cksum1 ^ pDlidx->iRowid);
}
fts5DlidxIterFree(pDlidx);
pDlidx = 0;
for(fts5DlidxIterInit(p, 1, iIdx, iSegid, iLeaf, &pDlidx);
fts5DlidxIterEof(p, pDlidx)==0;
fts5DlidxIterPrev(pDlidx)
){
cksum2 = (cksum2 ^ ( (i64)(pDlidx->iLeafPgno) << 32 ));
cksum2 = (cksum2 ^ pDlidx->iRowid);
}
fts5DlidxIterFree(pDlidx);
pDlidx = 0;
if( p->rc==SQLITE_OK && cksum1!=cksum2 ) p->rc = FTS5_CORRUPT;
}
#else
# define fts5DlidxIterTestReverse(w,x,y,z)
#endif
static void fts5IndexIntegrityCheckSegment(
Fts5Index *p, /* FTS5 backend object */
@ -3421,7 +3480,6 @@ static void fts5IndexIntegrityCheckSegment(
fts5DataRelease(pLeaf);
if( p->rc ) break;
/* Now check that the iter.nEmpty leaves following the current leaf
** (a) exist and (b) contain no terms. */
for(i=1; p->rc==SQLITE_OK && i<=iter.nEmpty; i++){
@ -3435,35 +3493,52 @@ static void fts5IndexIntegrityCheckSegment(
/* If there is a doclist-index, check that it looks right. */
if( iter.bDlidx ){
Fts5DlidxIter *pDlidx = 0; /* For iterating through doclist index */
int nEntry = 0;
int iPrevLeaf = iter.iLeaf;
int iSegid = pSeg->iSegid;
int bRev = 0;
int iPg;
i64 iKey;
for(fts5DlidxIterInit(p, bRev, iIdx, iSegid, iter.iLeaf, &pDlidx);
for(fts5DlidxIterInit(p, 0, iIdx, iSegid, iter.iLeaf, &pDlidx);
fts5DlidxIterEof(p, pDlidx)==0;
fts5DlidxIterNext(pDlidx, bRev)
fts5DlidxIterNext(pDlidx)
){
i64 iKey = FTS5_SEGMENT_ROWID(iIdx, iSegid, 0, pDlidx->iLeafPgno);
/* Check any rowid-less pages that occur before the current leaf. */
for(iPg=iPrevLeaf+1; iPg<pDlidx->iLeafPgno; iPg++){
iKey = FTS5_SEGMENT_ROWID(iIdx, iSegid, 0, iPg);
pLeaf = fts5DataRead(p, iKey);
if( pLeaf ){
int iRowidOff = fts5GetU16(&pLeaf->p[0]);
if( pDlidx->bZero ){
if( iRowidOff!=0 ) p->rc = FTS5_CORRUPT;
}else{
i64 iRowid;
getVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
if( iRowid!=pDlidx->iRowid ) p->rc = FTS5_CORRUPT;
}
if( fts5GetU16(&pLeaf->p[0])!=0 ) p->rc = FTS5_CORRUPT;
fts5DataRelease(pLeaf);
}
nEntry++;
}
iPrevLeaf = pDlidx->iLeafPgno;
/* Check that the leaf page indicated by the iterator really does
** contain the rowid suggested by the same. */
iKey = FTS5_SEGMENT_ROWID(iIdx, iSegid, 0, pDlidx->iLeafPgno);
pLeaf = fts5DataRead(p, iKey);
if( pLeaf ){
i64 iRowid;
int iRowidOff = fts5GetU16(&pLeaf->p[0]);
getVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
if( iRowid!=pDlidx->iRowid ) p->rc = FTS5_CORRUPT;
fts5DataRelease(pLeaf);
}
/* Check that the doclist-index was the right length */
if( p->rc==SQLITE_OK && nEntry!=iter.nEmpty && nEntry!=iter.nEmpty+1 ){
p->rc = FTS5_CORRUPT;
}
for(iPg=iPrevLeaf+1; iPg<=(iter.iLeaf + iter.nEmpty); iPg++){
iKey = FTS5_SEGMENT_ROWID(iIdx, iSegid, 0, iPg);
pLeaf = fts5DataRead(p, iKey);
if( pLeaf ){
if( fts5GetU16(&pLeaf->p[0])!=0 ) p->rc = FTS5_CORRUPT;
fts5DataRelease(pLeaf);
}
}
fts5DlidxIterFree(pDlidx);
fts5DlidxIterTestReverse(p, iIdx, iSegid, iter.iLeaf);
}
}

View File

@ -1,5 +1,5 @@
C Fix\sfts5_index.c\sto\suse\sdoclist-indexes\swhen\spossible.\sOnly\ssome\scases\swork\sso\sfar.
D 2014-08-04T20:07:40.532
C Use\sdoclist-indexes\swith\s"ORDER\sBY\srowid\sASC"\sfts5\squeries\sas\swell.
D 2014-08-05T19:00:22.438
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -110,7 +110,7 @@ F ext/fts5/fts5_aux.c 366057c7186bc3615deb5ecc0ff61de50b6d2dbc
F ext/fts5/fts5_buffer.c 248c61ac9fec001602efc72a45704f3b8d367c00
F ext/fts5/fts5_config.c f4ebf143e141b8c77355e3b15aba81b7be51d710
F ext/fts5/fts5_expr.c 9402474456732ddb5019f83a77907852f108a96a
F ext/fts5/fts5_index.c 3578823a9a43fcc77ce46c7f6efddfd155544053
F ext/fts5/fts5_index.c 40d9086948d6f1420a078bd9fb0b5372e54ec791
F ext/fts5/fts5_storage.c 2866e7e1de9dc851756c3a9c76b6e1d75e0facb7
F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
@ -595,14 +595,14 @@ F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
F test/fts4merge4.test d895b1057a7798b67e03455d0fa50e9ea836c47b
F test/fts4noti.test 524807f0c36d49deea7920cdd4cd687408b58849
F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36
F test/fts5aa.test f54245091fee924030722234070fcba95a493549
F test/fts5aa.test 2d136b61c4523ec018699e59b35c005313569b9e
F test/fts5ab.test dc04ed48cf93ca957d174406e6c192f2ff4f3397
F test/fts5ac.test 9be418d037763f4cc5d86f4239db41fc86bb4f85
F test/fts5ac.test 399533fe52b7383053368ab8ba01ae182391e5d7
F test/fts5ad.test 2ed38bbc865678cb2905247120d02ebba7f20e07
F test/fts5ae.test cb37b3135a00d3afd5492ec534ecf654be5ff69e
F test/fts5af.test 9ebe23aa3875896076952c7bc6e8308813a63c74
F test/fts5ag.test 0747bf3bade16d5165810cf891f875933b28b420
F test/fts5ah.test ca1f12b5738992c2edbdeb6c16133d41cfb9c031
F test/fts5ah.test 009b993a9b7ebc43f84c10e53bd778b1dc8ffbe7
F test/fts5ea.test ff43b40f8879ba50b82def70f2ab67c195d1a1d4
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
@ -1199,7 +1199,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P b8864da95db2c0e611116304d607e35a86c9247d
R 2807aba63fb0a8821d708dc4cbc7f577
P 90b82d3ef613b2915e0e280dc1d2e5a2b617d59c
R 0266e2e08ce753d75d582fc91e12512e
U dan
Z 6114a7973c3151dffa74bd597b78489f
Z 1a32a19af984c36e1b27a239a8950f8a

View File

@ -1 +1 @@
90b82d3ef613b2915e0e280dc1d2e5a2b617d59c
d028ba6589f3122b635474c2683c0f93d5bc6c7c

View File

@ -148,6 +148,7 @@ do_execsql_test 6.2 {
#-------------------------------------------------------------------------
#
reset_db
expr srand(0)
do_execsql_test 7.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x,y,z);
INSERT INTO t1(t1) VALUES('pgsz=32');
@ -173,7 +174,7 @@ proc dump_structure {} {
for {set i 1} {$i <= 10} {incr i} {
do_test 7.$i {
for {set j 0} {$j < 100} {incr j} {
for {set j 0} {$j < 10} {incr j} {
set x [doc]
set y [doc]
set z [doc]

View File

@ -364,6 +364,10 @@ foreach {tn expr tclexpr} {
#-------------------------------------------------------------------------
#
do_execsql_test 6.integrity {
INSERT INTO xx(xx) VALUES('integrity-check');
}
#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM xx_data} {puts $r}
foreach {bAsc sql} {
0 {SELECT rowid FROM xx WHERE xx MATCH $expr}
1 {SELECT rowid FROM xx WHERE xx MATCH $expr ORDER BY rowid ASC}

View File

@ -53,6 +53,12 @@ proc reads {} {
db one {SELECT t1 FROM t1 WHERE t1 MATCH '*reads'}
}
proc execsql_reads {sql} {
set nRead [reads]
execsql $sql
expr [reads] - $nRead
}
do_test 1.4 {
set nRead [reads]
execsql { SELECT rowid FROM t1 WHERE t1 MATCH 'x' }
@ -60,6 +66,14 @@ do_test 1.4 {
expr $nReadX>1000
} {1}
do_test 1.5 {
set fwd [execsql_reads {SELECT rowid FROM t1 WHERE t1 MATCH 'x' }]
set bwd [execsql_reads {
SELECT rowid FROM t1 WHERE t1 MATCH 'x' ORDER BY 1 ASC
}]
expr {$bwd < $fwd + 10}
} {1}
foreach {tn q res} "
1 { SELECT rowid FROM t1 WHERE t1 MATCH 'w + x' } [list $W]
2 { SELECT rowid FROM t1 WHERE t1 MATCH 'x + w' } [list $W]
@ -67,22 +81,18 @@ foreach {tn q res} "
4 { SELECT rowid FROM t1 WHERE t1 MATCH 'y AND x' } [list $Y]
" {
do_test 1.5.$tn.1 {
set nRead [reads]
execsql $q
set n [expr [reads] - $nRead]
do_test 1.6.$tn.1 {
set n [execsql_reads $q]
expr {$n < ($nReadX / 10)}
} {1}
do_test 1.5.$tn.2 {
set nRead [reads]
execsql "$q ORDER BY rowid ASC"
set n [expr [reads] - $nRead]
do_test 1.6.$tn.2 {
set n [execsql_reads "$q ORDER BY rowid ASC"]
expr {$n < ($nReadX / 10)}
} {1}
do_execsql_test 1.5.$tn.3 $q [lsort -int -decr $res]
do_execsql_test 1.5.$tn.4 "$q ORDER BY rowid ASC" [lsort -int -incr $res]
do_execsql_test 1.6.$tn.3 $q [lsort -int -decr $res]
do_execsql_test 1.6.$tn.4 "$q ORDER BY rowid ASC" [lsort -int -incr $res]
}
#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t1_data} {puts $r}