github.com/vc42/parquet-go@v0.0.0-20240320194221-1a9adb5f23f5/row.go (about) 1 package parquet 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "github.com/vc42/parquet-go/utils" 8 "io" 9 "reflect" 10 ) 11 12 const ( 13 defaultRowBufferSize = 20 14 ) 15 16 // Row represents a parquet row as a slice of values. 17 // 18 // Each value should embed a column index, repetition level, and definition 19 // level allowing the program to determine how to reconstruct the original 20 // object from the row. Repeated values share the same column index, their 21 // relative position of repeated values is represented by their relative 22 // position in the row. 23 type Row []Value 24 25 // Clone creates a copy of the row which shares no pointers. 26 // 27 // This method is useful to capture rows after a call to RowReader.ReadRows when 28 // values need to be retained before the next call to ReadRows or after the lifespan 29 // of the reader. 30 func (row Row) Clone() Row { 31 clone := make(Row, len(row)) 32 for i := range row { 33 clone[i] = row[i].Clone() 34 } 35 return clone 36 } 37 38 // Equal returns true if row and other contain the same sequence of values. 39 func (row Row) Equal(other Row) bool { 40 if len(row) != len(other) { 41 return false 42 } 43 for i := range row { 44 if !Equal(row[i], other[i]) { 45 return false 46 } 47 if row[i].repetitionLevel != other[i].repetitionLevel { 48 return false 49 } 50 if row[i].definitionLevel != other[i].definitionLevel { 51 return false 52 } 53 if row[i].columnIndex != other[i].columnIndex { 54 return false 55 } 56 } 57 return true 58 } 59 60 func (row Row) startsWith(columnIndex int16) bool { 61 return len(row) > 0 && row[0].Column() == int(columnIndex) 62 } 63 64 // RowSeeker is an interface implemented by readers of parquet rows which can be 65 // positioned at a specific row index. 66 type RowSeeker interface { 67 // Positions the stream on the given row index. 68 // 69 // Some implementations of the interface may only allow seeking forward. 70 // 71 // The method returns io.ErrClosedPipe if the stream had already been closed. 72 SeekToRow(int64) error 73 } 74 75 // RowReader reads a sequence of parquet rows. 76 type RowReader interface { 77 // Read rows from the reader, returning the number of rows read into the 78 // buffer, and any error that occurred. 79 // 80 // When all rows have been read, the reader returns io.EOF to indicate the 81 // end of the sequence. It is valid for the reader to return both a non-zero 82 // number of rows and a non-nil error (including io.EOF). 83 // 84 // The buffer of rows passed as argument will be used to store values of 85 // each row read from the reader. If the rows are not nil, the backing array 86 // of the slices will be used as an optimization to avoid re-allocating new 87 // arrays. 88 ReadRows([]Row) (int, error) 89 } 90 91 // RowReaderFrom reads parquet rows from reader. 92 type RowReaderFrom interface { 93 ReadRowsFrom(RowReader) (int64, error) 94 } 95 96 // RowReaderWithSchema is an extension of the RowReader interface which 97 // advertises the schema of rows returned by ReadRow calls. 98 type RowReaderWithSchema interface { 99 RowReader 100 Schema() *Schema 101 } 102 103 // RowReadSeeker is an interface implemented by row readers which support 104 // seeking to arbitrary row positions. 105 type RowReadSeeker interface { 106 RowReader 107 RowSeeker 108 } 109 110 // RowWriter writes parquet rows to an underlying medium. 111 type RowWriter interface { 112 // Writes rows to the writer, returning the number of rows written and any 113 // error that occurred. 114 // 115 // Because columnar operations operate on independent columns of values, 116 // writes of rows may not be atomic operations, and could result in some 117 // rows being partially written. The method returns the number of rows that 118 // were successfully written, but if an error occurs, values of the row(s) 119 // that failed to be written may have been partially committed to their 120 // columns. For that reason, applications should consider a write error as 121 // fatal and assume that they need to discard the state, they cannot retry 122 // the write nor recover the underlying file. 123 WriteRows([]Row) (int, error) 124 } 125 126 // RowWriterTo writes parquet rows to a writer. 127 type RowWriterTo interface { 128 WriteRowsTo(RowWriter) (int64, error) 129 } 130 131 // RowWriterWithSchema is an extension of the RowWriter interface which 132 // advertises the schema of rows expected to be passed to WriteRow calls. 133 type RowWriterWithSchema interface { 134 RowWriter 135 Schema() *Schema 136 } 137 138 type forwardRowSeeker struct { 139 rows RowReader 140 seek int64 141 index int64 142 } 143 144 func (r *forwardRowSeeker) ReadRows(rows []Row) (int, error) { 145 for { 146 n, err := r.rows.ReadRows(rows) 147 148 if n > 0 && r.index < r.seek { 149 skip := r.seek - r.index 150 r.index += int64(n) 151 if skip >= int64(n) { 152 continue 153 } 154 155 for i, j := 0, int(skip); j < n; i++ { 156 rows[i] = append(rows[i][:0], rows[j]...) 157 } 158 159 n -= int(skip) 160 } 161 162 return n, err 163 } 164 } 165 166 func (r *forwardRowSeeker) SeekToRow(rowIndex int64) error { 167 if rowIndex >= r.index { 168 r.seek = rowIndex 169 return nil 170 } 171 return fmt.Errorf("SeekToRow: %T does not implement parquet.RowSeeker: cannot seek backward from row %d to %d", r.rows, r.index, rowIndex) 172 } 173 174 // CopyRows copies rows from src to dst. 175 // 176 // The underlying types of src and dst are tested to determine if they expose 177 // information about the schema of rows that are read and expected to be 178 // written. If the schema information are available but do not match, the 179 // function will attempt to automatically convert the rows from the source 180 // schema to the destination. 181 // 182 // As an optimization, the src argument may implement RowWriterTo to bypass 183 // the default row copy logic and provide its own. The dst argument may also 184 // implement RowReaderFrom for the same purpose. 185 // 186 // The function returns the number of rows written, or any error encountered 187 // other than io.EOF. 188 func CopyRows(dst RowWriter, src RowReader) (int64, error) { 189 return copyRows(dst, src, nil) 190 } 191 192 func copyRows(dst RowWriter, src RowReader, buf []Row) (written int64, err error) { 193 targetSchema := targetSchemaOf(dst) 194 sourceSchema := sourceSchemaOf(src) 195 196 if targetSchema != nil && sourceSchema != nil { 197 if !nodesAreEqual(targetSchema, sourceSchema) { 198 conv, err := Convert(targetSchema, sourceSchema) 199 if err != nil { 200 return 0, err 201 } 202 // The conversion effectively disables a potential optimization 203 // if the source reader implemented RowWriterTo. It is a trade off 204 // we are making to optimize for safety rather than performance. 205 // 206 // Entering this code path should not be the common case tho, it is 207 // most often used when parquet schemas are evolving, but we expect 208 // that the majority of files of an application to be sharing a 209 // common schema. 210 src = ConvertRowReader(src, conv) 211 } 212 } 213 214 if wt, ok := src.(RowWriterTo); ok { 215 return wt.WriteRowsTo(dst) 216 } 217 218 if rf, ok := dst.(RowReaderFrom); ok { 219 return rf.ReadRowsFrom(src) 220 } 221 222 if len(buf) == 0 { 223 buf = make([]Row, defaultRowBufferSize) 224 } 225 226 defer clearRows(buf) 227 228 for { 229 rn, err := src.ReadRows(buf) 230 231 if rn > 0 { 232 wn, err := dst.WriteRows(buf[:rn]) 233 if err != nil { 234 return written, err 235 } 236 237 written += int64(wn) 238 } 239 240 if err != nil { 241 if errors.Is(err, io.EOF) { 242 err = nil 243 } 244 return written, err 245 } 246 247 if rn == 0 { 248 return written, io.ErrNoProgress 249 } 250 } 251 } 252 253 func clearRows(rows []Row) { 254 for i, values := range rows { 255 clearValues(values) 256 rows[i] = values[:0] 257 } 258 } 259 260 func sourceSchemaOf(r RowReader) *Schema { 261 if rrs, ok := r.(RowReaderWithSchema); ok { 262 return rrs.Schema() 263 } 264 return nil 265 } 266 267 func targetSchemaOf(w RowWriter) *Schema { 268 if rws, ok := w.(RowWriterWithSchema); ok { 269 return rws.Schema() 270 } 271 return nil 272 } 273 274 func errRowIndexOutOfBounds(rowIndex, rowCount int64) error { 275 return fmt.Errorf("row index out of bounds: %d/%d", rowIndex, rowCount) 276 } 277 278 func hasRepeatedRowValues(values []Value) bool { 279 for _, v := range values { 280 if v.repetitionLevel != 0 { 281 return true 282 } 283 } 284 return false 285 } 286 287 // repeatedRowLength gives the length of the repeated row starting at the 288 // beginning of the repetitionLevels slice. 289 func repeatedRowLength(repetitionLevels []byte) int { 290 // If a repetition level exists, at least one value is required to represent 291 // the column. 292 if len(repetitionLevels) > 0 { 293 // The subsequent levels will represent the start of a new record when 294 // they go back to zero. 295 if i := bytes.IndexByte(repetitionLevels[1:], 0); i >= 0 { 296 return i + 1 297 } 298 } 299 return len(repetitionLevels) 300 } 301 302 func countRowsOf(values []Value) (numRows int) { 303 if !hasRepeatedRowValues(values) { 304 return len(values) // Faster path when there are no repeated values. 305 } 306 if len(values) > 0 { 307 // The values may have not been at the start of a repeated row, 308 // it could be the continuation of a repeated row. Skip until we 309 // find the beginning of a row before starting to count how many 310 // rows there are. 311 if values[0].repetitionLevel != 0 { 312 _, values = splitRowValues(values) 313 } 314 for len(values) > 0 { 315 numRows++ 316 _, values = splitRowValues(values) 317 } 318 } 319 return numRows 320 } 321 322 func limitRowValues(values []Value, rowCount int) []Value { 323 if !hasRepeatedRowValues(values) { 324 if len(values) > rowCount { 325 values = values[:rowCount] 326 } 327 } else { 328 var row Row 329 var limit int 330 for len(values) > 0 { 331 row, values = splitRowValues(values) 332 limit += len(row) 333 } 334 values = values[:limit] 335 } 336 return values 337 } 338 339 func splitRowValues(values []Value) (head, tail []Value) { 340 for i, v := range values { 341 if v.repetitionLevel == 0 { 342 return values[:i+1], values[i+1:] 343 } 344 } 345 return values, nil 346 } 347 348 // ============================================================================= 349 // Functions returning closures are marked with "go:noinline" below to prevent 350 // losing naming information of the closure in stack traces. 351 // 352 // Because some of the functions are very short (simply return a closure), the 353 // compiler inlines when at their call site, which result in the closure being 354 // named something like parquet.deconstructFuncOf.func2 instead of the original 355 // parquet.deconstructFuncOfLeaf.func1; the latter being much more meaningful 356 // when reading CPU or memory profiles. 357 // ============================================================================= 358 359 type levels struct { 360 repetitionDepth byte 361 repetitionLevel byte 362 definitionLevel byte 363 } 364 365 type deconstructFunc func(Row, levels, reflect.Value) Row 366 367 func deconstructFuncOf(columnIndex int16, node Node) (int16, deconstructFunc) { 368 switch { 369 case node.Optional(): 370 return deconstructFuncOfOptional(columnIndex, node) 371 case node.Repeated(): 372 return deconstructFuncOfRepeated(columnIndex, node) 373 case isList(node): 374 return deconstructFuncOfList(columnIndex, node) 375 case isMap(node): 376 return deconstructFuncOfMap(columnIndex, node) 377 default: 378 return deconstructFuncOfRequired(columnIndex, node) 379 } 380 } 381 382 //go:noinline 383 func deconstructFuncOfOptional(columnIndex int16, node Node) (int16, deconstructFunc) { 384 columnIndex, deconstruct := deconstructFuncOf(columnIndex, Required(node)) 385 return columnIndex, func(row Row, levels levels, value reflect.Value) Row { 386 if value.IsValid() { 387 if value.IsZero() { 388 value = reflect.Value{} 389 } else { 390 if value.Kind() == reflect.Ptr { 391 value = value.Elem() 392 } 393 levels.definitionLevel++ 394 } 395 } 396 return deconstruct(row, levels, value) 397 } 398 } 399 400 //go:noinline 401 func deconstructFuncOfRepeated(columnIndex int16, node Node) (int16, deconstructFunc) { 402 columnIndex, deconstruct := deconstructFuncOf(columnIndex, Required(node)) 403 return columnIndex, func(row Row, levels levels, value reflect.Value) Row { 404 if !value.IsValid() || value.Len() == 0 { 405 return deconstruct(row, levels, reflect.Value{}) 406 } 407 408 levels.repetitionDepth++ 409 levels.definitionLevel++ 410 411 for i, n := 0, value.Len(); i < n; i++ { 412 row = deconstruct(row, levels, value.Index(i)) 413 levels.repetitionLevel = levels.repetitionDepth 414 } 415 416 return row 417 } 418 } 419 420 func deconstructFuncOfRequired(columnIndex int16, node Node) (int16, deconstructFunc) { 421 switch { 422 case node.Leaf(): 423 return deconstructFuncOfLeaf(columnIndex, node) 424 default: 425 return deconstructFuncOfGroup(columnIndex, node) 426 } 427 } 428 429 func deconstructFuncOfList(columnIndex int16, node Node) (int16, deconstructFunc) { 430 return deconstructFuncOf(columnIndex, Repeated(listElementOf(node))) 431 } 432 433 //go:noinline 434 func deconstructFuncOfMap(columnIndex int16, node Node) (int16, deconstructFunc) { 435 keyValue := mapKeyValueOf(node) 436 keyValueType := keyValue.GoType() 437 keyValueElem := keyValueType.Elem() 438 keyType := keyValueElem.Field(0).Type 439 valueType := keyValueElem.Field(1).Type 440 columnIndex, deconstruct := deconstructFuncOf(columnIndex, schemaOf(keyValueElem)) 441 return columnIndex, func(row Row, levels levels, mapValue reflect.Value) Row { 442 if !mapValue.IsValid() || mapValue.Len() == 0 { 443 return deconstruct(row, levels, reflect.Value{}) 444 } 445 446 levels.repetitionDepth++ 447 levels.definitionLevel++ 448 449 elem := reflect.New(keyValueElem).Elem() 450 k := elem.Field(0) 451 v := elem.Field(1) 452 453 for _, key := range mapValue.MapKeys() { 454 k.Set(key.Convert(keyType)) 455 v.Set(mapValue.MapIndex(key).Convert(valueType)) 456 row = deconstruct(row, levels, elem) 457 levels.repetitionLevel = levels.repetitionDepth 458 } 459 460 return row 461 } 462 } 463 464 //go:noinline 465 func deconstructFuncOfGroup(columnIndex int16, node Node) (int16, deconstructFunc) { 466 fields := node.Fields() 467 funcs := make([]deconstructFunc, len(fields)) 468 for i, field := range fields { 469 columnIndex, funcs[i] = deconstructFuncOf(columnIndex, field) 470 } 471 return columnIndex, func(row Row, levels levels, value reflect.Value) Row { 472 if value.IsValid() { 473 for i, f := range funcs { 474 row = f(row, levels, fields[i].Value(value)) 475 } 476 } else { 477 for _, f := range funcs { 478 row = f(row, levels, value) 479 } 480 } 481 return row 482 } 483 } 484 485 //go:noinline 486 func deconstructFuncOfLeaf(columnIndex int16, node Node) (int16, deconstructFunc) { 487 if columnIndex > MaxColumnIndex { 488 panic("row cannot be deconstructed because it has more than 127 columns") 489 } 490 kind := node.Type().Kind() 491 logicalType := node.Type().LogicalType() 492 valueColumnIndex := ^columnIndex 493 return columnIndex + 1, func(row Row, levels levels, value reflect.Value) Row { 494 v := Value{} 495 496 if value.IsValid() { 497 switch { 498 case value.Kind() == reflect.String && logicalType.Timestamp != nil: 499 value = reflect.ValueOf(utils.StringToTimeMs(value.String())) 500 case value.Kind() == reflect.String && logicalType.Date != nil: 501 value = reflect.ValueOf(utils.StringToDate(value.String())) 502 } 503 v = makeValue(kind, value) 504 } 505 506 v.repetitionLevel = levels.repetitionLevel 507 v.definitionLevel = levels.definitionLevel 508 v.columnIndex = valueColumnIndex 509 return append(row, v) 510 } 511 } 512 513 type reconstructFunc func(reflect.Value, levels, Row) (Row, error) 514 515 func reconstructFuncOf(columnIndex int16, node Node) (int16, reconstructFunc) { 516 switch { 517 case node.Optional(): 518 return reconstructFuncOfOptional(columnIndex, node) 519 case node.Repeated(): 520 return reconstructFuncOfRepeated(columnIndex, node) 521 case isList(node): 522 return reconstructFuncOfList(columnIndex, node) 523 case isMap(node): 524 return reconstructFuncOfMap(columnIndex, node) 525 default: 526 return reconstructFuncOfRequired(columnIndex, node) 527 } 528 } 529 530 //go:noinline 531 func reconstructFuncOfOptional(columnIndex int16, node Node) (int16, reconstructFunc) { 532 nextColumnIndex, reconstruct := reconstructFuncOf(columnIndex, Required(node)) 533 rowLength := nextColumnIndex - columnIndex 534 return nextColumnIndex, func(value reflect.Value, levels levels, row Row) (Row, error) { 535 if !row.startsWith(columnIndex) { 536 return row, fmt.Errorf("row is missing optional column %d", columnIndex) 537 } 538 if len(row) < int(rowLength) { 539 return row, fmt.Errorf("expected optional column %d to have at least %d values but got %d", columnIndex, rowLength, len(row)) 540 } 541 542 levels.definitionLevel++ 543 544 if row[0].definitionLevel < levels.definitionLevel { 545 value.Set(reflect.Zero(value.Type())) 546 return row[rowLength:], nil 547 } 548 549 if value.Kind() == reflect.Ptr { 550 if value.IsNil() { 551 value.Set(reflect.New(value.Type().Elem())) 552 } 553 value = value.Elem() 554 } 555 556 return reconstruct(value, levels, row) 557 } 558 } 559 560 //go:noinline 561 func reconstructFuncOfRepeated(columnIndex int16, node Node) (int16, reconstructFunc) { 562 nextColumnIndex, reconstruct := reconstructFuncOf(columnIndex, Required(node)) 563 rowLength := nextColumnIndex - columnIndex 564 return nextColumnIndex, func(value reflect.Value, lvls levels, row Row) (Row, error) { 565 t := value.Type() 566 c := value.Cap() 567 n := 0 568 if c > 0 { 569 value.Set(value.Slice(0, c)) 570 } else { 571 c = 10 572 value.Set(reflect.MakeSlice(t, c, c)) 573 } 574 if t.Elem().Kind() == reflect.Ptr { 575 for i := 0; i < c; i++ { 576 value.Index(i).Set(reflect.New(t.Elem().Elem())) 577 } 578 } 579 580 defer func() { 581 value.Set(value.Slice(0, n)) 582 }() 583 584 return reconstructRepeated(columnIndex, rowLength, lvls, row, func(levels levels, row Row) (Row, error) { 585 if n == c { 586 c *= 2 587 newValue := reflect.MakeSlice(t, c, c) 588 reflect.Copy(newValue, value) 589 value.Set(newValue) 590 } 591 row, err := reconstruct(value.Index(n), levels, row) 592 n++ 593 return row, err 594 }) 595 } 596 } 597 598 func reconstructRepeated(columnIndex, rowLength int16, levels levels, row Row, do func(levels, Row) (Row, error)) (Row, error) { 599 if !row.startsWith(columnIndex) { 600 return row, fmt.Errorf("row is missing repeated column %d: %+v", columnIndex, row) 601 } 602 if len(row) < int(rowLength) { 603 return row, fmt.Errorf("expected repeated column %d to have at least %d values but got %d", columnIndex, rowLength, len(row)) 604 } 605 606 levels.repetitionDepth++ 607 levels.definitionLevel++ 608 609 if row[0].definitionLevel < levels.definitionLevel { 610 return row[rowLength:], nil 611 } 612 613 var err error 614 for row.startsWith(columnIndex) && row[0].repetitionLevel == levels.repetitionLevel { 615 if row, err = do(levels, row); err != nil { 616 break 617 } 618 levels.repetitionLevel = levels.repetitionDepth 619 } 620 return row, err 621 } 622 623 func reconstructFuncOfRequired(columnIndex int16, node Node) (int16, reconstructFunc) { 624 switch { 625 case node.Leaf(): 626 return reconstructFuncOfLeaf(columnIndex, node) 627 default: 628 return reconstructFuncOfGroup(columnIndex, node) 629 } 630 } 631 632 func reconstructFuncOfList(columnIndex int16, node Node) (int16, reconstructFunc) { 633 return reconstructFuncOf(columnIndex, Repeated(listElementOf(node))) 634 } 635 636 //go:noinline 637 func reconstructFuncOfMap(columnIndex int16, node Node) (int16, reconstructFunc) { 638 keyValue := mapKeyValueOf(node) 639 keyValueType := keyValue.GoType() 640 keyValueElem := keyValueType.Elem() 641 keyValueZero := reflect.Zero(keyValueElem) 642 nextColumnIndex, reconstruct := reconstructFuncOf(columnIndex, schemaOf(keyValueElem)) 643 rowLength := nextColumnIndex - columnIndex 644 return nextColumnIndex, func(mapValue reflect.Value, lvls levels, row Row) (Row, error) { 645 t := mapValue.Type() 646 k := t.Key() 647 v := t.Elem() 648 649 if mapValue.IsNil() { 650 mapValue.Set(reflect.MakeMap(t)) 651 } 652 653 elem := reflect.New(keyValueElem).Elem() 654 return reconstructRepeated(columnIndex, rowLength, lvls, row, func(levels levels, row Row) (Row, error) { 655 row, err := reconstruct(elem, levels, row) 656 if err == nil { 657 mapValue.SetMapIndex(elem.Field(0).Convert(k), elem.Field(1).Convert(v)) 658 elem.Set(keyValueZero) 659 } 660 return row, err 661 }) 662 } 663 } 664 665 //go:noinline 666 func reconstructFuncOfGroup(columnIndex int16, node Node) (int16, reconstructFunc) { 667 fields := node.Fields() 668 funcs := make([]reconstructFunc, len(fields)) 669 columnIndexes := make([]int16, len(fields)) 670 671 for i, field := range fields { 672 columnIndex, funcs[i] = reconstructFuncOf(columnIndex, field) 673 columnIndexes[i] = columnIndex 674 } 675 676 return columnIndex, func(value reflect.Value, levels levels, row Row) (Row, error) { 677 var err error 678 679 for i, f := range funcs { 680 if row, err = f(fields[i].Value(value), levels, row); err != nil { 681 err = fmt.Errorf("%s → %w", fields[i].Name(), err) 682 break 683 } 684 } 685 686 return row, err 687 } 688 } 689 690 //go:noinline 691 func reconstructFuncOfLeaf(columnIndex int16, node Node) (int16, reconstructFunc) { 692 logicalType := node.Type().LogicalType() 693 return columnIndex + 1, func(value reflect.Value, _ levels, row Row) (Row, error) { 694 if !row.startsWith(columnIndex) { 695 return row, fmt.Errorf("no values found in parquet row for column %d", columnIndex) 696 } 697 switch { 698 case value.Kind() == reflect.String && logicalType.Timestamp != nil: 699 { 700 value.SetString(utils.TimeMsToString(row[0].Int64())) 701 return row[1:], nil 702 } 703 case value.Kind() == reflect.String && logicalType.Date != nil: 704 { 705 value.SetString(utils.DateToString(row[0].Int32())) 706 return row[1:], nil 707 } 708 } 709 return row[1:], assignValue(value, row[0]) 710 } 711 }