///|
pub(all) struct Row {
rowid : Int64
values : Array[Value]
page_number : Int
} derive(Debug)
///|
pub extend Row with @debug.Debug::{to_repr}
///|
fn page_varint(
bytes : Bytes,
offset : Int,
usable : Int,
) -> (UInt64, Int) raise SqliteError {
if offset < 0 || offset >= usable {
raise Invalid("cell varint 起点越界")
}
let result = decode_varint(bytes, offset)
if result.1 > usable - offset {
raise Invalid("cell varint 跨越页面保留空间")
}
result
}
///|
/// 以 rowid 顺序读取普通表;limit 为零时不读取任何行。
pub fn Database::read_table(
self : Database,
root : Int,
limit? : Int = self.limits.max_rows,
) -> Array[Row] raise SqliteError {
if limit < 0 || limit > self.limits.max_rows {
raise LimitExceeded("行数请求超出资源限制")
}
let root_page = self.page(root)
if root_page.kind == IndexLeaf || root_page.kind == IndexInterior {
raise Unsupported(
"WITHOUT ROWID 表使用 index B-tree;请使用底层页面检查",
)
}
let rows : Array[Row] = []
if limit == 0 {
return rows
}
let stack : Array[(Int, Int, Int64?, Int64?)] = [(root, 1, None, None)]
let visited : Map[Int, Bool] = Map([])
let mut last_rowid : Int64? = None
while !stack.is_empty() {
let (number, depth, lower, upper) = stack.pop().unwrap()
if depth > self.limits.max_depth {
raise LimitExceeded("B-tree 深度超过限制")
}
if visited.contains(number) {
raise Invalid("B-tree 子页重复或形成环")
}
if visited.length() >= self.limits.max_pages {
raise LimitExceeded("B-tree 页数超过限制")
}
visited[number] = true
let page = self.page(number)
let bytes = self.read_page(number)
let usable = self.header.usable_size
match page.kind {
TableInterior => {
let children : Array[(Int, Int, Int64?, Int64?)] = []
let mut previous_key : Int64? = lower
for offset in page.cell_offsets {
if offset > usable - 4 {
raise Invalid("interior cell 子页指针越界")
}
let child = page_number(read_u32(bytes, offset))
let (bits, _) = page_varint(bytes, offset + 4, usable)
let key = bits.reinterpret_as_int64()
if previous_key is Some(previous) && key <= previous {
raise Invalid("interior rowid 未严格递增")
}
if upper is Some(bound) && key > bound {
raise Invalid("interior rowid 越过父页键范围")
}
if child < 1 || child > self.page_count {
raise Invalid("左子页越界")
}
children.push((child, depth + 1, previous_key, Some(key)))
previous_key = Some(key)
}
children.push(
(page.right_child.unwrap(), depth + 1, previous_key, upper),
)
// 栈按逆序加入子页,使输出遵循 B-tree 的键顺序。
for i = children.length() - 1; i >= 0; i = i - 1 {
stack.push(children[i])
}
}
TableLeaf =>
for offset in page.cell_offsets {
let (size_bits, size_bytes) = page_varint(bytes, offset, usable)
let payload_size = bounded_int(size_bits, "payload size")
let (rowid_bits, rowid_bytes) = page_varint(
bytes,
offset + size_bytes,
usable,
)
let rowid = rowid_bits.reinterpret_as_int64()
if lower is Some(bound) && rowid <= bound {
raise Invalid("叶页 rowid 低于父页键范围")
}
if upper is Some(bound) && rowid > bound {
raise Invalid("叶页 rowid 高于父页键范围")
}
if last_rowid is Some(previous) && rowid <= previous {
raise Invalid("叶页 rowid 未严格递增")
}
last_rowid = Some(rowid)
let payload = self.cell_payload(
bytes,
offset + size_bytes + rowid_bytes,
payload_size,
true,
)
rows.push({
rowid,
values: decode_record(payload, self.header.text_encoding),
page_number: number,
})
if rows.length() == limit {
// 显式的小 limit 返回前缀;默认资源上限到达后若仍有数据则报告限制。
if limit == self.limits.max_rows &&
(
offset != page.cell_offsets[page.cell_count - 1] ||
!stack.is_empty()
) {
raise LimitExceeded(
"表行数超过资源限制;请指定更小的 limit 读取前缀",
)
}
return rows
}
}
_ => raise Invalid("普通表 B-tree 中出现 index 页")
}
}
rows
}