Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 1 addition & 2 deletions dissect/database/sqlite3/sqlite3.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,6 @@ def data(self) -> bytes:
if not self._data:
offset = self._offset + self._record_offset
page_data = self.page.data
page_size = self.page.sqlite.page_size

if self.size <= self.max_payload_size:
size = max(self.size, 4)
Expand Down Expand Up @@ -545,7 +544,7 @@ def data(self) -> bytes:
# overflow_size is the size of the page data without the
# extra 4 bytes for the next overflow page, so it needs to
# be added.
data_size = min(overflow_size + 4, page_size)
data_size = min(overflow_size + 4, self.page.sqlite.usable_page_size)
page_buf = self.page.sqlite.raw_page(overflow_page)[:data_size]

overflow_page = c_sqlite3.uint32(page_buf[:4])
Expand Down
3 changes: 3 additions & 0 deletions tests/_data/sqlite3/overflow.db
Git LFS file not shown
32 changes: 32 additions & 0 deletions tests/sqlite3/test_sqlite3.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest

from dissect.database.sqlite3 import sqlite3
from tests._util import absolute_path

if TYPE_CHECKING:
from pathlib import Path
Expand Down Expand Up @@ -93,3 +94,34 @@ def test_empty(empty_db: BinaryIO) -> None:

assert s.encoding == "utf-8"
assert len(list(s.tables())) == 0


def test_cell_overflow_reserved_page_size_regression() -> None:
"""Test if we handle databases with reserve_bytes greater than 0 correctly.

This test case emulates a database with a page size of 4kb and with reserve_bytes set to 32.
We then commit a row to a dummy table with a value of 8kb, forcing a cell overflow to a new page.

Test data generated using:

$ sqlite3 example.db
SQLite version 3.45.1 2024-01-30 16:01:20
Enter ".help" for usage hints.
sqlite> .filectrl reserve_bytes 32
32
sqlite> VACUUM;
sqlite> CREATE TABLE foo ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "text" TEXT NOT NULL);
sqlite> .quit

$ python
>>> import sqlite3
>>> con = sqlite3.connect("example.db"); cur = con.cursor()
>>> cur.execute('INSERT INTO foo VALUES (1, ?)', ("A" * 8192,))
>>> con.commit(); con.close()
"""

db = sqlite3.SQLite3(absolute_path("_data/sqlite3/overflow.db"))
assert db.header.reserved_size == 32
assert db.header.page_size == 4096
assert db.usable_page_size == db.header.page_size - db.header.reserved_size
assert db.table("foo").row(0).text == "A" * 8192
Loading