///|
/// 嵌套记录装配(M2):把 shredded 叶列槽位流按 Delta schema 树装配成 Cell。
///
/// 规则(标准 Parquet def/rep 语义):
/// - rep == 0 开启一条新记录;
/// - 槽位的 def < 某字段自身的 def level ⇔ 该字段在此次出现中为 null;
/// - list 条目边界:rep == 该字段 repetition level(首条目 rep == 外层 rep);
/// - map 条目 = key(REQUIRED)+ value(可空)各 1 槽。
/// 所有游标在同一子树内严格同步前进,每装配一个实例恰好消费该子树的全部槽位。
///|
priv struct LeafCursor {
leaf : @parquet.LeafColumn
mut pos : Int
}
///|
fn LeafCursor::peek_def(self : LeafCursor) -> Int32 {
self.leaf.def_levels[self.pos]
}
///|
fn LeafCursor::peek_rep(self : LeafCursor) -> Int32 {
self.leaf.rep_levels[self.pos]
}
///|
fn LeafCursor::at_end(self : LeafCursor) -> Bool {
self.pos >= self.leaf.def_levels.length()
}
///|
/// 将叶列按根字段名分桶(path[0] == 字段名),保持文件顺序
fn cursors_under_field(
cursors : Array[LeafCursor],
name : String,
) -> Array[LeafCursor] {
let out : Array[LeafCursor] = []
for c in cursors {
if c.leaf.path.length() > 0 && c.leaf.path[0] == name {
out.push(c)
}
}
out
}
///|
/// struct 子字段的光标:路径中最后一个分量等于子字段名
fn cursors_under_child(
cursors : Array[LeafCursor],
name : String,
) -> Array[LeafCursor] {
let out : Array[LeafCursor] = []
for c in cursors {
let n = c.leaf.path.length()
if n > 0 && c.leaf.path[n - 1] == name {
out.push(c)
}
}
out
}
///|
/// map 的 key / value 光标
fn cursor_for_key(cursors : Array[LeafCursor]) -> LeafCursor raise DeltaError {
for c in cursors {
let n = c.leaf.path.length()
if n > 0 && c.leaf.path[n - 1] == "key" {
return c
}
}
raise DeltaError::Unsupported(
"map column is missing its 'key' leaf in the parquet schema",
)
}
///|
fn cursor_for_value(
cursors : Array[LeafCursor],
) -> LeafCursor raise DeltaError {
for c in cursors {
let n = c.leaf.path.length()
if n > 0 && c.leaf.path[n - 1] == "value" {
return c
}
}
raise DeltaError::Unsupported(
"map column is missing its 'value' leaf in the parquet schema",
)
}
///|
/// 把 parquet 原始值转成 Cell(按叶列物理类型)
fn shred_value_to_cell(v : @parquet.Value) -> Cell {
match v {
@parquet.Int32(x) => CellI32(x)
@parquet.Int64(x) => CellI64(x)
@parquet.TimestampMicros(x) => CellTs(x)
@parquet.Float(x) => CellF32(x)
@parquet.Double(x) => CellF64(x)
@parquet.Boolean(x) => CellBool(x)
@parquet.String(x) => CellStr(x)
@parquet.Binary(x) => CellBin(x)
@parquet.Null => CellNull
}
}
///|
/// 消费所有游标各 1 槽(对应"该字段为 null"的一次出现)
fn skip_all_null(cursors : Array[LeafCursor]) -> Unit raise DeltaError {
for c in cursors {
if c.at_end() {
raise DeltaError::ParseError(
"parquet level stream ended early while reading a null slot",
)
}
c.pos = c.pos + 1
}
}
///|
/// 装配一个字段实例。cursors 为该字段子树下的全部叶游标(非空)。
/// field_def:该字段"非空"对应的 def level;field_rep:外层 repetition level。
fn assemble_cell(
ty : DeltaType,
cursors : Array[LeafCursor],
field_def : Int32,
field_rep : Int32,
) -> Cell raise DeltaError {
if cursors.length() == 0 {
raise DeltaError::Unsupported(
"delta schema field has no matching parquet leaf column",
)
}
match ty {
NestedType(kind~, fields~) =>
if kind == "struct" {
assemble_struct(fields, cursors, field_def, field_rep)
} else if kind == "array" {
assemble_list(fields, cursors, field_def, field_rep)
} else if kind == "map" {
assemble_map(fields, cursors, field_def, field_rep)
} else {
raise DeltaError::Unsupported("unknown nested kind '\{kind}'")
}
_ => {
// 原始类型:本字段直接对应 1 个叶、1 个槽
let c = cursors[0]
if c.at_end() {
raise DeltaError::ParseError("parquet level stream ended early")
}
if !parquet_type_matches(ty, c.leaf.column_type) {
raise DeltaError::ParseError(
"parquet column '\{path_text(c.leaf.path)}' is \{c.leaf.column_type} but the Delta schema declares \{delta_type_name(ty)}",
)
}
let def = c.peek_def()
let cell = if def == c.leaf.max_definition_level {
shred_value_to_cell(c.leaf.values[c.pos])
} else {
CellNull
}
c.pos = c.pos + 1
cell
}
}
}
///|
fn assemble_struct(
fields : Array[DeltaField],
cursors : Array[LeafCursor],
field_def : Int32,
field_rep : Int32,
) -> Cell raise DeltaError {
let c0 = cursors[0]
if c0.at_end() {
raise DeltaError::ParseError("parquet level stream ended early")
}
// 任一后代槽位的 def < field_def ⇔ 整个 struct 为 null(各后代恰好 1 槽)
if c0.peek_def() < field_def {
skip_all_null(cursors)
return CellNull
}
let members : Array[(String, Cell)] = []
for f in fields {
let child_cursors = cursors_under_child(cursors, f.name)
let child_def = field_def + (if f.nullable { 1 } else { 0 })
let cell = assemble_cell(f.type_, child_cursors, child_def, field_rep)
members.push((f.name, cell))
}
CellStruct(members)
}
///|
/// 标准 3-level LIST:字段(optional) -> repeated 组 -> 元素。
/// list 为空:所有后代各 1 槽且 def == field_def;null:def < field_def。
fn assemble_list(
fields : Array[DeltaField],
cursors : Array[LeafCursor],
field_def : Int32,
field_rep : Int32,
) -> Cell raise DeltaError {
let c0 = cursors[0]
if c0.at_end() {
raise DeltaError::ParseError("parquet level stream ended early")
}
let def0 = c0.peek_def()
if def0 < field_def {
skip_all_null(cursors)
return CellNull
}
if def0 == field_def {
// list 非空组但无条目(空 list)
skip_all_null(cursors)
return CellList([])
}
let entry_def = field_def + 1
let entry_rep = field_rep + 1
let element = fields[0]
let items : Array[Cell] = []
let mut first = true
while true {
if c0.at_end() {
break
}
let rep0 = c0.peek_rep()
if !first && rep0 <= field_rep {
// 下一个槽位属于外层(新条目边界之外)
break
}
if first && rep0 < field_rep {
// 首条目的 rep 应为 field_rep(新记录)——更深表示流错位
raise DeltaError::ParseError(
"unexpected repetition level \{rep0} at list entry boundary",
)
}
let cell = assemble_cell(element.type_, cursors, entry_def, entry_rep)
items.push(cell)
first = false
}
CellList(items)
}
///|
/// MAP:字段(optional) -> key_value(repeated) -> key(REQUIRED) + value(可空)。
fn assemble_map(
fields : Array[DeltaField],
cursors : Array[LeafCursor],
field_def : Int32,
field_rep : Int32,
) -> Cell raise DeltaError {
if fields.length() != 2 {
raise DeltaError::Unsupported("map field must declare key and value types")
}
let key_ty = fields[0].type_
let value_field = fields[1]
let c0 = cursors[0]
if c0.at_end() {
raise DeltaError::ParseError("parquet level stream ended early")
}
let def0 = c0.peek_def()
if def0 < field_def {
skip_all_null(cursors)
return CellNull
}
if def0 == field_def {
skip_all_null(cursors)
return CellMap([])
}
let entry_def = field_def + 1
let entry_rep = field_rep + 1
let key_cursors = [cursor_for_key(cursors)]
let value_cursors = [cursor_for_value(cursors)]
let entries : Array[(Cell, Cell)] = []
let mut first = true
while true {
if c0.at_end() {
break
}
let rep0 = c0.peek_rep()
if !first && rep0 <= field_rep {
break
}
if first && rep0 < field_rep {
raise DeltaError::ParseError(
"unexpected repetition level \{rep0} at map entry boundary",
)
}
// key:REQUIRED,存在即 def == entry_def
let key_cell = assemble_cell(key_ty, key_cursors, entry_def, entry_rep)
let value_cell = assemble_cell(
value_field.type_,
value_cursors,
entry_def + (if value_field.nullable { 1 } else { 0 }),
entry_rep,
)
entries.push((key_cell, value_cell))
first = false
}
CellMap(entries)
}
///|
fn path_text(path : Array[String]) -> String {
let sb = StringBuilder()
let mut i = 0
while i < path.length() {
if i > 0 {
sb.write_char('.')
}
sb.write_string(path[i])
i = i + 1
}
sb.to_string()
}
///|
/// 从 shredded 叶列 + Delta schema 装配出全部行(列式结果,行数 = row_count)。
/// 返回与 schema.fields 顺序一致的列。
pub fn shred_rows(
schema : DeltaSchema,
leaves : Array[@parquet.LeafColumn],
row_count : Int32,
) -> Array[Array[Cell]] raise DeltaError {
let cursors : Array[LeafCursor] = []
for leaf in leaves {
cursors.push({ leaf, pos: 0 })
}
let columns : Array[Array[Cell]] = []
for f in schema.fields {
let field_cursors = cursors_under_field(cursors, f.name)
let field_def = if f.nullable { 1 } else { 0 }
let column : Array[Cell] = []
for _ in 0.. 0 && !field_cursors[0].at_end() {
// 顶层字段:新记录由 rep == 0 起始;空游标(整列无槽)按 null 处理
let cell = assemble_cell(f.type_, field_cursors, field_def, 0)
column.push(cell)
} else {
column.push(CellNull)
}
}
columns.push(column)
}
// Delta schema 是读取事实的来源:不属于任何根字段的 parquet 叶列
// (schema 演进后残留的列)直接忽略;被引用的列必须装配干净。
for c in cursors {
let mut referenced = false
for f in schema.fields {
if c.leaf.path.length() > 0 && c.leaf.path[0] == f.name {
referenced = true
}
}
if referenced && !c.at_end() {
raise DeltaError::ParseError(
"parquet column '\{path_text(c.leaf.path)}' has unconsumed slots after assembly",
)
}
}
columns
}
///|
fn schema_has_nested(schema : DeltaSchema) -> Bool {
for f in schema.fields {
if f.type_ is NestedType(..) {
return true
}
}
false
}
///|
/// 嵌套 schema 的读取路径:shredded 解码(值 + def/rep levels)后按 Delta
/// schema 树装配。文件遍历、limit 语义与分区列补齐与扁平路径一致。
pub fn read_snapshot_shredded(
root : String,
snapshot : Snapshot,
limit : Int32?,
) -> ReadResult raise DeltaError {
let fields = snapshot.metadata.schema.fields
let columns : Array[ReadColumn] = []
for f in fields {
columns.push({ name: f.name, type_: f.type_, cells: [] })
}
let max_rows = match limit {
Some(l) => l
None => 1000000000
}
let mut row_count = 0
let mut files_read = 0
for file in snapshot.files {
if row_count >= max_rows {
break
}
let path = root + "/" + file.path
let data = @fs.read_file_to_bytes(path) catch {
@fs.IOError(msg) =>
raise DeltaError::IoError("cannot read '\{file.path}': \{msg}")
}
let (leaves, file_rows) = @parquet.read_bytes_shredded(data) catch {
@parquet.Unsupported(msg) =>
raise DeltaError::Unsupported("cannot read '\{file.path}': \{msg}")
@parquet.InvalidData(msg) =>
raise DeltaError::ParseError("corrupt parquet '\{file.path}': \{msg}")
@parquet.Io(msg) =>
raise DeltaError::IoError("cannot read '\{file.path}': \{msg}")
}
files_read = files_read + 1
let assembled = shred_rows(snapshot.metadata.schema, leaves, file_rows)
let remaining = max_rows - row_count
let take = if file_rows < remaining { file_rows } else { remaining }
let mut idx = 0
while idx < fields.length() {
match partition_value_of(file, fields[idx].name) {
Some(raw) => {
let cell = cell_from_partition(fields[idx].type_, raw)
let mut r = 0
while r < take {
columns[idx].cells.push(cell)
r = r + 1
}
}
None => {
let mut r = 0
while r < take {
columns[idx].cells.push(assembled[idx][r])
r = r + 1
}
}
}
idx = idx + 1
}
row_count = row_count + take
}
{ columns, row_count, files_read }
}