mirror of
https://github.com/hanzoai/traces.git
synced 2026-10-30 18:20:41 +00:00
* niliter * mewo * it kinda works..? * no events and links * rebase * move conditions around - added more test assertions * clean up * testing remove this * add nil value handling * lint * fix ast condition * update test examples * fix tests * select all should print nil for dedicated columns with nil values * remove prints * fixed comments * lint * remove not needed params * add support for vparquet3 and vparquet5 * vparquet2 shakefist * fix test and lint * add support for links and events * fix nil iterator returning last row and add test * rebase, lint, changelog, docs * fix test * fix test, add column chunk null check * logic to return correct rn for events and links and return attr key in response * fix test from rebase * fix column name for wellknown and custom attr * one more from vparquet3
156 lines
3.8 KiB
Go
156 lines
3.8 KiB
Go
package parquetquery
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
pq "github.com/parquet-go/parquet-go"
|
|
)
|
|
|
|
// NilSyncIterator copies all functions of the sync iterator with just the next() function being different
|
|
type NilSyncIterator struct {
|
|
SyncIterator
|
|
lastRowNumberReturned RowNumber
|
|
valueFound bool
|
|
}
|
|
|
|
var _ Iterator = (*NilSyncIterator)(nil)
|
|
|
|
func NewNilSyncIterator(ctx context.Context, rgs []pq.RowGroup, column int, opts ...SyncIteratorOpt) *NilSyncIterator {
|
|
// Create the sync iterator
|
|
syncIterator := NewSyncIterator(ctx, rgs, column, opts...)
|
|
|
|
i := &NilSyncIterator{
|
|
SyncIterator: *syncIterator,
|
|
lastRowNumberReturned: EmptyRowNumber(),
|
|
valueFound: false,
|
|
}
|
|
|
|
return i
|
|
}
|
|
|
|
func (c *NilSyncIterator) String() string {
|
|
filter := "nil"
|
|
if c.filter != nil {
|
|
filter = c.filter.String()
|
|
}
|
|
return fmt.Sprintf("NilSyncIterator: %s : %s", c.columnName, filter)
|
|
}
|
|
|
|
func (c *NilSyncIterator) Next() (*IteratorResult, error) {
|
|
rn, _, err := c.next()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !rn.Valid() {
|
|
return nil, nil
|
|
}
|
|
|
|
nilValue := pq.ValueOf(nil)
|
|
v := &nilValue
|
|
return c.makeResult(rn, v), nil
|
|
}
|
|
|
|
func (c *NilSyncIterator) next() (RowNumber, *pq.Value, error) {
|
|
var lastValue *pq.Value
|
|
lastRowNumber := EmptyRowNumber()
|
|
for {
|
|
if c.currRowGroup == nil {
|
|
rg, minRN, maxRN := c.popRowGroup()
|
|
if rg == nil {
|
|
// no more rows, return last row if we still haven't found the value
|
|
if lastValue != nil && !c.valueFound && lastRowNumber.Valid() && !EqualRowNumber(lastValue.DefinitionLevel(), c.lastRowNumberReturned, lastRowNumber) {
|
|
c.lastRowNumberReturned = lastRowNumber
|
|
return lastRowNumber, lastValue, nil
|
|
}
|
|
return EmptyRowNumber(), nil, nil
|
|
}
|
|
|
|
cc := &ColumnChunkHelper{ColumnChunk: rg.ColumnChunks()[c.column]}
|
|
if c.filter != nil && !c.filter.KeepColumnChunk(cc) {
|
|
cc.Close()
|
|
continue
|
|
}
|
|
|
|
c.setRowGroup(rg, minRN, maxRN, cc)
|
|
}
|
|
|
|
if c.currPage == nil {
|
|
pg, err := c.currChunk.NextPage()
|
|
if pg == nil || errors.Is(err, io.EOF) {
|
|
// This row group is exhausted
|
|
c.closeCurrRowGroup()
|
|
continue
|
|
}
|
|
if err != nil {
|
|
return EmptyRowNumber(), nil, err
|
|
}
|
|
if c.filter != nil && !c.filter.KeepPage(pg) {
|
|
// This page filtered out
|
|
c.curr.Skip(pg.NumRows())
|
|
pq.Release(pg)
|
|
continue
|
|
}
|
|
c.setPage(pg)
|
|
}
|
|
|
|
// Read next batch of values if needed
|
|
if c.currBuf == nil {
|
|
c.currBuf = syncIteratorPoolGet(c.readSize, 0)
|
|
}
|
|
|
|
if c.currBufN >= len(c.currBuf) || len(c.currBuf) == 0 {
|
|
c.currBuf = c.currBuf[:cap(c.currBuf)]
|
|
n, err := c.currValues.ReadValues(c.currBuf)
|
|
if err != nil && !errors.Is(err, io.EOF) {
|
|
return EmptyRowNumber(), nil, err
|
|
}
|
|
c.currBuf = c.currBuf[:n]
|
|
c.currBufN = 0
|
|
if n == 0 {
|
|
// This value reader and page are exhausted.
|
|
c.setPage(nil)
|
|
continue
|
|
}
|
|
}
|
|
|
|
// Consume current buffer until empty
|
|
for c.currBufN < len(c.currBuf) {
|
|
v := &c.currBuf[c.currBufN]
|
|
|
|
if v.RepetitionLevel() < v.DefinitionLevel() && !v.IsNull() {
|
|
// moving on to the next level higher than value level
|
|
// so if we haven't seen the value yet, it does not exist
|
|
// check if we've already returned this row so we can properly next()
|
|
if !c.valueFound && lastRowNumber.Valid() && !EqualRowNumber(c.maxDefinitionLevel, c.lastRowNumberReturned, c.curr) {
|
|
c.lastRowNumberReturned = lastRowNumber
|
|
return lastRowNumber, lastValue, nil
|
|
}
|
|
// new level reset
|
|
c.valueFound = false
|
|
}
|
|
|
|
// Inspect all values to track the current row number,
|
|
// even if the value is filtered out next.
|
|
c.curr.Next(v.RepetitionLevel(), v.DefinitionLevel(), c.maxDefinitionLevel)
|
|
c.currBufN++
|
|
c.currPageN++
|
|
|
|
if v.IsNull() {
|
|
continue
|
|
}
|
|
|
|
if c.filter != nil && c.filter.KeepValue(*v) {
|
|
c.valueFound = true
|
|
}
|
|
|
|
lastValue = v
|
|
lastRowNumber = c.curr
|
|
continue
|
|
}
|
|
}
|
|
}
|