Skip to content

Commit 15652ad

Browse files
authored
Fix virtual table limit offset (WiseLibs#873)
* Don't care limit and offset constraints of user-defined virtual tables * Add a test case for WiseLibs#872
1 parent 0c42307 commit 15652ad

File tree

4 files changed

+46
-8
lines changed

4 files changed

+46
-8
lines changed

src/better_sqlite3.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,13 @@ int CustomTable::xBestIndex (sqlite3_vtab * vtab, sqlite3_index_info * output)
17481748
auto item = output->aConstraint[i];
17491749

17501750

1751+
1752+
1753+
1754+
if (item.op == SQLITE_INDEX_CONSTRAINT_LIMIT || item.op == SQLITE_INDEX_CONSTRAINT_OFFSET) {
1755+
continue;
1756+
}
1757+
17511758
if (item.iColumn >= 0 && item.iColumn < parameter_count) {
17521759
if (item.op != SQLITE_INDEX_CONSTRAINT_EQ) {
17531760
sqlite3_free(vtab->zErrMsg);
@@ -1782,9 +1789,9 @@ int CustomTable::xBestIndex (sqlite3_vtab * vtab, sqlite3_index_info * output)
17821789
output->estimatedCost = output->estimatedRows = 1000000000 / (argument_count + 1);
17831790
return SQLITE_OK;
17841791
}
1785-
#line 387 "./src/util/custom-table.lzz"
1792+
#line 394 "./src/util/custom-table.lzz"
17861793
void CustomTable::PropagateJSError ()
1787-
#line 387 "./src/util/custom-table.lzz"
1794+
#line 394 "./src/util/custom-table.lzz"
17881795
{
17891796
assert(db->GetState()->was_js_error == false);
17901797
db->GetState()->was_js_error = true;

src/better_sqlite3.hpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -666,17 +666,17 @@ class CustomTable
666666
static int xRowid (sqlite3_vtab_cursor * cursor, sqlite_int64 * output);
667667
#line 343 "./src/util/custom-table.lzz"
668668
static int xBestIndex (sqlite3_vtab * vtab, sqlite3_index_info * output);
669-
#line 387 "./src/util/custom-table.lzz"
669+
#line 394 "./src/util/custom-table.lzz"
670670
void PropagateJSError ();
671-
#line 392 "./src/util/custom-table.lzz"
671+
#line 399 "./src/util/custom-table.lzz"
672672
Addon * const addon;
673-
#line 393 "./src/util/custom-table.lzz"
673+
#line 400 "./src/util/custom-table.lzz"
674674
v8::Isolate * const isolate;
675-
#line 394 "./src/util/custom-table.lzz"
675+
#line 401 "./src/util/custom-table.lzz"
676676
Database * const db;
677-
#line 395 "./src/util/custom-table.lzz"
677+
#line 402 "./src/util/custom-table.lzz"
678678
std::string const name;
679-
#line 396 "./src/util/custom-table.lzz"
679+
#line 403 "./src/util/custom-table.lzz"
680680
CopyablePersistent <v8::Function> const factory;
681681
};
682682
#line 65 "./src/util/data.lzz"

src/util/custom-table.lzz

+7
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,13 @@ private:
348348
for (int i = 0, len = output->nConstraint; i < len; ++i) {
349349
auto item = output->aConstraint[i];
350350

351+
// The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET
352+
// operators have no left-hand operand, and so for those operators the
353+
// corresponding item.iColumn is meaningless.
354+
// We don't care those constraints.
355+
if (item.op == SQLITE_INDEX_CONSTRAINT_LIMIT || item.op == SQLITE_INDEX_CONSTRAINT_OFFSET) {
356+
continue;
357+
}
351358
// We only care about constraints on parameters, not regular columns.
352359
if (item.iColumn >= 0 && item.iColumn < parameter_count) {
353360
if (item.op != SQLITE_INDEX_CONSTRAINT_EQ) {

test/34.database.table.js

+24
Original file line numberDiff line numberDiff line change
@@ -668,4 +668,28 @@ describe('Database#table()', function () {
668668
throw new TypeError('Expected the statement to throw an exception');
669669
});
670670
});
671+
it('should correctly handle limit and offset clause', function () {
672+
let lastValue;
673+
this.db.table('vtab', {
674+
columns: ['x'],
675+
*rows() {
676+
lastValue = 1;
677+
yield { x: lastValue };
678+
lastValue = 2;
679+
yield { x: lastValue };
680+
lastValue = 3;
681+
yield { x: lastValue };
682+
lastValue = null;
683+
},
684+
});
685+
expect(this.db.prepare('SELECT * FROM vtab LIMIT 1').all())
686+
.to.deep.equal([{ x: 1 }]);
687+
expect(lastValue).to.equal(1);
688+
expect(this.db.prepare('SELECT * FROM vtab LIMIT 1 OFFSET 2').all())
689+
.to.deep.equal([{ x: 3 }]);
690+
expect(lastValue).to.equal(3);
691+
expect(this.db.prepare('SELECT * FROM vtab LIMIT 100 OFFSET 1').all())
692+
.to.deep.equal([{ x: 2 }, { x: 3 }]);
693+
expect(lastValue).to.be.null;
694+
});
671695
});

0 commit comments

Comments
 (0)