Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/js/internal/sql/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,16 @@ class SQLResultArray<T> extends PublicArray<T> {

static [Symbol.toStringTag] = "SQLResults";

constructor(values: T[] = []) {
super(...values);
constructor(values?: T[]) {
super();

// Not super(...values): spreading puts every row on the JS stack, which overflows
// once a result set has a few hundred thousand rows.
if (values) {
for (let i = 0, length = values.length; i < length; i++) {
$putByValDirect(this, i, values[i]);
}
}

// match postgres's result array, in this way for in will not list the
// properties and .map will not return undefined command and count
Expand Down
29 changes: 29 additions & 0 deletions test/js/sql/sqlite-sql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2030,6 +2030,35 @@ describe("Performance & Edge Cases", () => {
await sql.close();
});

test(
"returns result sets with more rows than a call can take as arguments",
async () => {
await using sql = new SQL("sqlite://:memory:");

// JavaScriptCore refuses to spread more than 0x100000 arguments into one call, so a result
// set this size fails no matter how much stack is free if the rows are spread into the result.
const rowCount = 0x100000 + 1;
const rows = await sql`
WITH RECURSIVE counter(n) AS (SELECT 1 UNION ALL SELECT n + 1 FROM counter WHERE n < ${rowCount})
SELECT n FROM counter
`;

expect({
length: rows.length,
count: rows.count,
first: rows[0],
last: rows[rowCount - 1],
}).toEqual({
length: rowCount,
count: rowCount,
first: { n: 1 },
last: { n: rowCount },
});
},
// bun:sqlite needs several seconds to build a million row objects in a debug build.
isDebug ? 60_000 : 10_000,
);

test("handles many columns", async () => {
const sql = new SQL(":memory:");

Expand Down
Loading