Repository: parquet-go/parquet-go
Pull request #109 (2024-02-02 13:15:23)

Bug: Respect current page offset in reslice
Currently if you reslice a boolean page it will not respect it's internal bit offset into the first byte. The impact is that if you slice a boolean page multiple times on values that are not byte aligned the page will return misaligned values when reading.


Patch:
diff --git a/column.go b/column.go
index b0efc7a..c2733eb 100644
--- a/column.go
+++ b/column.go
@@ -784,10 +784,8 @@ func (c *Column) decodeDictionary(header DictionaryPageHeader, page *buffer, siz
 		pageEncoding = format.Plain
 	}
 
-	// Dictionaries always have PLAIN encoding, so we need to allocate offsets for the decoded page.
 	numValues := int(header.NumValues())
-	dictBufferSize := pageType.EstimateDecodeSize(numValues, pageData, LookupEncoding(pageEncoding))
-	values := pageType.NewValues(make([]byte, 0, dictBufferSize), make([]uint32, 0, numValues))
+	values := pageType.NewValues(nil, nil)
 	values, err := pageType.Decode(values, pageData, LookupEncoding(pageEncoding))
 	if err != nil {
 		return nil, err
diff --git a/column_buffer.go b/column_buffer.go
index bc40cc3..16a4def 100644
--- a/column_buffer.go
+++ b/column_buffer.go
@@ -91,16 +91,12 @@ type columnLevels struct {
 	definitionLevel byte
 }
 
-func columnIndexOfNullable(base ColumnBuffer, maxDefinitionLevel byte, definitionLevels []byte) (ColumnIndex, error) {
-	index, err := base.ColumnIndex()
-	if err != nil {
-		return nil, err
-	}
+func columnIndexOfNullable(base ColumnBuffer, maxDefinitionLevel byte, definitionLevels []byte) ColumnIndex {
 	return &nullableColumnIndex{
-		ColumnIndex:        index,
+		ColumnIndex:        base.ColumnIndex(),
 		maxDefinitionLevel: maxDefinitionLevel,
 		definitionLevels:   definitionLevels,
-	}, nil
+	}
 }
 
 type nullableColumnIndex struct {
@@ -191,11 +187,11 @@ func (col *optionalColumnBuffer) NumValues() int64 {
 	return int64(len(col.definitionLevels))
 }
 
-func (col *optionalColumnBuffer) ColumnIndex() (ColumnIndex, error) {
+func (col *optionalColumnBuffer) ColumnIndex() ColumnIndex {
 	return columnIndexOfNullable(col.base, col.maxDefinitionLevel, col.definitionLevels)
 }
 
-func (col *optionalColumnBuffer) OffsetIndex() (OffsetIndex, error) {
+func (col *optionalColumnBuffer) OffsetIndex() OffsetIndex {
 	return col.base.OffsetIndex()
 }
 
@@ -481,11 +477,11 @@ func (col *repeatedColumnBuffer) NumValues() int64 {
 	return int64(len(col.definitionLevels))
 }
 
-func (col *repeatedColumnBuffer) ColumnIndex() (ColumnIndex, error) {
+func (col *repeatedColumnBuffer) ColumnIndex() ColumnIndex {
 	return columnIndexOfNullable(col.base, col.maxDefinitionLevel, col.definitionLevels)
 }
 
-func (col *repeatedColumnBuffer) OffsetIndex() (OffsetIndex, error) {
+func (col *repeatedColumnBuffer) OffsetIndex() OffsetIndex {
 	return col.base.OffsetIndex()
 }
 
@@ -766,12 +762,12 @@ func (col *booleanColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *booleanColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return booleanColumnIndex{&col.booleanPage}, nil
+func (col *booleanColumnBuffer) ColumnIndex() ColumnIndex {
+	return booleanColumnIndex{&col.booleanPage}
 }
 
-func (col *booleanColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return booleanOffsetIndex{&col.booleanPage}, nil
+func (col *booleanColumnBuffer) OffsetIndex() OffsetIndex {
+	return booleanOffsetIndex{&col.booleanPage}
 }
 
 func (col *booleanColumnBuffer) BloomFilter() BloomFilter { return nil }
@@ -926,13 +922,9 @@ func (col *int32ColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *int32ColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return int32ColumnIndex{&col.int32Page}, nil
-}
+func (col *int32ColumnBuffer) ColumnIndex() ColumnIndex { return int32ColumnIndex{&col.int32Page} }
 
-func (col *int32ColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return int32OffsetIndex{&col.int32Page}, nil
-}
+func (col *int32ColumnBuffer) OffsetIndex() OffsetIndex { return int32OffsetIndex{&col.int32Page} }
 
 func (col *int32ColumnBuffer) BloomFilter() BloomFilter { return nil }
 
@@ -1025,13 +1017,9 @@ func (col *int64ColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *int64ColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return int64ColumnIndex{&col.int64Page}, nil
-}
+func (col *int64ColumnBuffer) ColumnIndex() ColumnIndex { return int64ColumnIndex{&col.int64Page} }
 
-func (col *int64ColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return int64OffsetIndex{&col.int64Page}, nil
-}
+func (col *int64ColumnBuffer) OffsetIndex() OffsetIndex { return int64OffsetIndex{&col.int64Page} }
 
 func (col *int64ColumnBuffer) BloomFilter() BloomFilter { return nil }
 
@@ -1123,13 +1111,9 @@ func (col *int96ColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *int96ColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return int96ColumnIndex{&col.int96Page}, nil
-}
+func (col *int96ColumnBuffer) ColumnIndex() ColumnIndex { return int96ColumnIndex{&col.int96Page} }
 
-func (col *int96ColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return int96OffsetIndex{&col.int96Page}, nil
-}
+func (col *int96ColumnBuffer) OffsetIndex() OffsetIndex { return int96OffsetIndex{&col.int96Page} }
 
 func (col *int96ColumnBuffer) BloomFilter() BloomFilter { return nil }
 
@@ -1220,13 +1204,9 @@ func (col *floatColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *floatColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return floatColumnIndex{&col.floatPage}, nil
-}
+func (col *floatColumnBuffer) ColumnIndex() ColumnIndex { return floatColumnIndex{&col.floatPage} }
 
-func (col *floatColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return floatOffsetIndex{&col.floatPage}, nil
-}
+func (col *floatColumnBuffer) OffsetIndex() OffsetIndex { return floatOffsetIndex{&col.floatPage} }
 
 func (col *floatColumnBuffer) BloomFilter() BloomFilter { return nil }
 
@@ -1318,13 +1298,9 @@ func (col *doubleColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *doubleColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return doubleColumnIndex{&col.doublePage}, nil
-}
+func (col *doubleColumnBuffer) ColumnIndex() ColumnIndex { return doubleColumnIndex{&col.doublePage} }
 
-func (col *doubleColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return doubleOffsetIndex{&col.doublePage}, nil
-}
+func (col *doubleColumnBuffer) OffsetIndex() OffsetIndex { return doubleOffsetIndex{&col.doublePage} }
 
 func (col *doubleColumnBuffer) BloomFilter() BloomFilter { return nil }
 
@@ -1430,12 +1406,12 @@ func (col *byteArrayColumnBuffer) cloneLengths() []uint32 {
 	return lengths
 }
 
-func (col *byteArrayColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return byteArrayColumnIndex{&col.byteArrayPage}, nil
+func (col *byteArrayColumnBuffer) ColumnIndex() ColumnIndex {
+	return byteArrayColumnIndex{&col.byteArrayPage}
 }
 
-func (col *byteArrayColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return byteArrayOffsetIndex{&col.byteArrayPage}, nil
+func (col *byteArrayColumnBuffer) OffsetIndex() OffsetIndex {
+	return byteArrayOffsetIndex{&col.byteArrayPage}
 }
 
 func (col *byteArrayColumnBuffer) BloomFilter() BloomFilter { return nil }
@@ -1590,12 +1566,12 @@ func (col *fixedLenByteArrayColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *fixedLenByteArrayColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return fixedLenByteArrayColumnIndex{&col.fixedLenByteArrayPage}, nil
+func (col *fixedLenByteArrayColumnBuffer) ColumnIndex() ColumnIndex {
+	return fixedLenByteArrayColumnIndex{&col.fixedLenByteArrayPage}
 }
 
-func (col *fixedLenByteArrayColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return fixedLenByteArrayOffsetIndex{&col.fixedLenByteArrayPage}, nil
+func (col *fixedLenByteArrayColumnBuffer) OffsetIndex() OffsetIndex {
+	return fixedLenByteArrayOffsetIndex{&col.fixedLenByteArrayPage}
 }
 
 func (col *fixedLenByteArrayColumnBuffer) BloomFilter() BloomFilter { return nil }
@@ -1710,13 +1686,9 @@ func (col *uint32ColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *uint32ColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return uint32ColumnIndex{&col.uint32Page}, nil
-}
+func (col *uint32ColumnBuffer) ColumnIndex() ColumnIndex { return uint32ColumnIndex{&col.uint32Page} }
 
-func (col *uint32ColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return uint32OffsetIndex{&col.uint32Page}, nil
-}
+func (col *uint32ColumnBuffer) OffsetIndex() OffsetIndex { return uint32OffsetIndex{&col.uint32Page} }
 
 func (col *uint32ColumnBuffer) BloomFilter() BloomFilter { return nil }
 
@@ -1808,13 +1780,9 @@ func (col *uint64ColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *uint64ColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return uint64ColumnIndex{&col.uint64Page}, nil
-}
+func (col *uint64ColumnBuffer) ColumnIndex() ColumnIndex { return uint64ColumnIndex{&col.uint64Page} }
 
-func (col *uint64ColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return uint64OffsetIndex{&col.uint64Page}, nil
-}
+func (col *uint64ColumnBuffer) OffsetIndex() OffsetIndex { return uint64OffsetIndex{&col.uint64Page} }
 
 func (col *uint64ColumnBuffer) BloomFilter() BloomFilter { return nil }
 
@@ -1906,12 +1874,12 @@ func (col *be128ColumnBuffer) Clone() ColumnBuffer {
 	}
 }
 
-func (col *be128ColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return be128ColumnIndex{&col.be128Page}, nil
+func (col *be128ColumnBuffer) ColumnIndex() ColumnIndex {
+	return be128ColumnIndex{&col.be128Page}
 }
 
-func (col *be128ColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return be128OffsetIndex{&col.be128Page}, nil
+func (col *be128ColumnBuffer) OffsetIndex() OffsetIndex {
+	return be128OffsetIndex{&col.be128Page}
 }
 
 func (col *be128ColumnBuffer) BloomFilter() BloomFilter { return nil }
diff --git a/column_chunk.go b/column_chunk.go
index ad1afb2..6d45b79 100644
--- a/column_chunk.go
+++ b/column_chunk.go
@@ -1,15 +1,9 @@
 package parquet
 
 import (
-	"errors"
 	"io"
 )
 
-var (
-	ErrMissingColumnIndex = errors.New("missing column index")
-	ErrMissingOffsetIndex = errors.New("missing offset index")
-)
-
 // The ColumnChunk interface represents individual columns of a row group.
 type ColumnChunk interface {
 	// Returns the column type.
@@ -28,17 +22,9 @@ type ColumnChunk interface {
 	// Note that the returned value may be the same across calls to these
 	// methods, programs must treat those as read-only.
 	//
-	// If the column chunk does not have a column or offset index, the methods return
-	// ErrMissingColumnIndex or ErrMissingOffsetIndex respectively.
-	//
-	// Prior to v0.20, these methods did not return an error because the page index
-	// for a file was either fully read when the file was opened, or skipped
-	// completely using the parquet.SkipPageIndex option. Version v0.20 introduced a
-	// change that the page index can be read on-demand at any time, even if a file
-	// was opened with the parquet.SkipPageIndex option. Since reading the page index
-	// can fail, these methods now return an error.
-	ColumnIndex() (ColumnIndex, error)
-	OffsetIndex() (OffsetIndex, error)
+	// If the column chunk does not have a page index, the methods return nil.
+	ColumnIndex() ColumnIndex
+	OffsetIndex() OffsetIndex
 	BloomFilter() BloomFilter
 
 	// Returns the number of values in the column chunk.
diff --git a/column_index.go b/column_index.go
index 38914c3..dcc2ec1 100644
--- a/column_index.go
+++ b/column_index.go
@@ -288,13 +288,9 @@ func (i *baseColumnIndexer) observe(numValues, numNulls int64) {
 }
 
 func (i *baseColumnIndexer) columnIndex(minValues, maxValues [][]byte, minOrder, maxOrder int) format.ColumnIndex {
-	nullPages := make([]bool, len(i.nullPages))
-	copy(nullPages, i.nullPages)
-	nullCounts := make([]int64, len(i.nullCounts))
-	copy(nullCounts, i.nullCounts)
 	return format.ColumnIndex{
-		NullPages:     nullPages,
-		NullCounts:    nullCounts,
+		NullPages:     i.nullPages,
+		NullCounts:    i.nullCounts,
 		MinValues:     minValues,
 		MaxValues:     maxValues,
 		BoundaryOrder: boundaryOrderOf(minOrder, maxOrder),
diff --git a/compare.go b/compare.go
index b503eab..5486c47 100644
--- a/compare.go
+++ b/compare.go
@@ -2,7 +2,6 @@ package parquet
 
 import (
 	"encoding/binary"
-	"sync"
 
 	"github.com/parquet-go/parquet-go/deprecated"
 )
@@ -259,8 +258,6 @@ func compareRowsFuncOfColumnIndexes(leafColumns []leafColumn, sortingColumns []S
 	}
 }
 
-var columnPool = &sync.Pool{New: func() any { return make([][2]int32, 0, 128) }}
-
 //go:noinline
 func compareRowsFuncOfColumnValues(leafColumns []leafColumn, sortingColumns []SortingColumn) func(Row, Row) int {
 	highestColumnIndex := int16(0)
@@ -292,14 +289,8 @@ func compareRowsFuncOfColumnValues(leafColumns []leafColumn, sortingColumns []So
 	}
 
 	return func(row1, row2 Row) int {
-		columns1 := columnPool.Get().([][2]int32)
-		columns2 := columnPool.Get().([][2]int32)
-		defer func() {
-			columns1 = columns1[:0]
-			columns2 = columns2[:0]
-			columnPool.Put(columns1)
-			columnPool.Put(columns2)
-		}()
+		columns1 := make([][2]int32, 0, 64)
+		columns2 := make([][2]int32, 0, 64)
 
 		i1 := 0
 		i2 := 0
diff --git a/convert.go b/convert.go
index 8b31573..2f87be8 100644
--- a/convert.go
+++ b/convert.go
@@ -451,13 +451,13 @@ type missingColumnChunk struct {
 	numNulls  int64
 }
 
-func (c *missingColumnChunk) Type() Type                        { return c.typ }
-func (c *missingColumnChunk) Column() int                       { return int(c.column) }
-func (c *missingColumnChunk) Pages() Pages                      { return onePage(missingPage{c}) }
-func (c *missingColumnChunk) ColumnIndex() (ColumnIndex, error) { return missingColumnIndex{c}, nil }
-func (c *missingColumnChunk) OffsetIndex() (OffsetIndex, error) { return missingOffsetIndex{}, nil }
-func (c *missingColumnChunk) BloomFilter() BloomFilter          { return missingBloomFilter{} }
-func (c *missingColumnChunk) NumValues() int64                  { return c.numValues }
+func (c *missingColumnChunk) Type() Type               { return c.typ }
+func (c *missingColumnChunk) Column() int              { return int(c.column) }
+func (c *missingColumnChunk) Pages() Pages             { return onePage(missingPage{c}) }
+func (c *missingColumnChunk) ColumnIndex() ColumnIndex { return missingColumnIndex{c} }
+func (c *missingColumnChunk) OffsetIndex() OffsetIndex { return missingOffsetIndex{} }
+func (c *missingColumnChunk) BloomFilter() BloomFilter { return missingBloomFilter{} }
+func (c *missingColumnChunk) NumValues() int64         { return 0 }
 
 type missingColumnIndex struct{ *missingColumnChunk }
 
@@ -490,22 +490,12 @@ func (p missingPage) NumRows() int64                    { return p.numRows }
 func (p missingPage) NumValues() int64                  { return p.numValues }
 func (p missingPage) NumNulls() int64                   { return p.numNulls }
 func (p missingPage) Bounds() (min, max Value, ok bool) { return }
-func (p missingPage) Slice(i, j int64) Page {
-	return missingPage{
-		&missingColumnChunk{
-			typ:       p.typ,
-			column:    p.column,
-			numRows:   j - i,
-			numValues: j - i,
-			numNulls:  j - i,
-		},
-	}
-}
-func (p missingPage) Size() int64              { return 0 }
-func (p missingPage) RepetitionLevels() []byte { return nil }
-func (p missingPage) DefinitionLevels() []byte { return nil }
-func (p missingPage) Data() encoding.Values    { return p.typ.NewValues(nil, nil) }
-func (p missingPage) Values() ValueReader      { return &missingPageValues{page: p} }
+func (p missingPage) Slice(i, j int64) Page             { return p }
+func (p missingPage) Size() int64                       { return 0 }
+func (p missingPage) RepetitionLevels() []byte          { return nil }
+func (p missingPage) DefinitionLevels() []byte          { return nil }
+func (p missingPage) Data() encoding.Values             { return p.typ.NewValues(nil, nil) }
+func (p missingPage) Values() ValueReader               { return &missingPageValues{page: p} }
 
 type missingPageValues struct {
 	page missingPage
diff --git a/dictionary.go b/dictionary.go
index 3bf2d97..a807e8b 100644
--- a/dictionary.go
+++ b/dictionary.go
@@ -1363,13 +1363,9 @@ func (col *indexedColumnBuffer) Clone() ColumnBuffer {
 
 func (col *indexedColumnBuffer) Type() Type { return col.typ.Type }
 
-func (col *indexedColumnBuffer) ColumnIndex() (ColumnIndex, error) {
-	return indexedColumnIndex{col}, nil
-}
+func (col *indexedColumnBuffer) ColumnIndex() ColumnIndex { return indexedColumnIndex{col} }
 
-func (col *indexedColumnBuffer) OffsetIndex() (OffsetIndex, error) {
-	return indexedOffsetIndex{col}, nil
-}
+func (col *indexedColumnBuffer) OffsetIndex() OffsetIndex { return indexedOffsetIndex{col} }
 
 func (col *indexedColumnBuffer) BloomFilter() BloomFilter { return nil }
 
diff --git a/file.go b/file.go
index 791eb51..e02aa36 100644
--- a/file.go
+++ b/file.go
@@ -10,9 +10,8 @@ import (
 	"strings"
 	"sync"
 
-	"github.com/segmentio/encoding/thrift"
-
 	"github.com/parquet-go/parquet-go/format"
+	"github.com/segmentio/encoding/thrift"
 )
 
 const (
@@ -461,24 +460,18 @@ func (c *fileColumnChunk) Pages() Pages {
 	return r
 }
 
-func (c *fileColumnChunk) ColumnIndex() (ColumnIndex, error) {
-	if err := c.readColumnIndex(); err != nil {
-		return nil, err
-	}
-	if c.columnIndex == nil || c.chunk.ColumnIndexOffset == 0 {
-		return nil, ErrMissingColumnIndex
+func (c *fileColumnChunk) ColumnIndex() ColumnIndex {
+	if c.columnIndex == nil {
+		return nil
 	}
-	return fileColumnIndex{c}, nil
+	return fileColumnIndex{c}
 }
 
-func (c *fileColumnChunk) OffsetIndex() (OffsetIndex, error) {
-	if err := c.readOffsetIndex(); err != nil {
-		return nil, err
-	}
-	if c.offsetIndex == nil || c.chunk.OffsetIndexOffset == 0 {
-		return nil, ErrMissingOffsetIndex
+func (c *fileColumnChunk) OffsetIndex() OffsetIndex {
+	if c.offsetIndex == nil {
+		return nil
 	}
-	return (*fileOffsetIndex)(c.offsetIndex), nil
+	return (*fileOffsetIndex)(c.offsetIndex)
 }
 
 func (c *fileColumnChunk) BloomFilter() BloomFilter {
@@ -492,50 +485,6 @@ func (c *fileColumnChunk) NumValues() int64 {
 	return c.chunk.MetaData.NumValues
 }
 
-func (c *fileColumnChunk) readColumnIndex() error {
-	if c.columnIndex != nil {
-		return nil
-	}
-	chunkMeta := c.file.metadata.RowGroups[c.rowGroup.Ordinal].Columns[c.Column()]
-	offset, length := chunkMeta.ColumnIndexOffset, chunkMeta.ColumnIndexLength
-	if offset == 0 {
-		return nil
-	}
-
-	indexData := make([]byte, int(length))
-	var columnIndex format.ColumnIndex
-	if _, err := readAt(c.file.reader, indexData, offset); err != nil {
-		return fmt.Errorf("read %d bytes column index at offset %d: %w", length, offset, err)
-	}
-	if err := thrift.Unmarshal(&c.file.protocol, indexData, &columnIndex); err != nil {
-		return fmt.Errorf("decode column index: rowGroup=%d columnChunk=%d/%d: %w", c.rowGroup.Ordinal, c.Column(), len(c.rowGroup.Columns), err)
-	}
-	c.columnIndex = &columnIndex
-	return nil
-}
-
-func (c *fileColumnChunk) readOffsetIndex() error {
-	if c.offsetIndex != nil {
-		return nil
-	}
-	chunkMeta := c.file.metadata.RowGroups[c.rowGroup.Ordinal].Columns[c.Column()]
-	offset, length := chunkMeta.OffsetIndexOffset, chunkMeta.OffsetIndexLength
-	if offset == 0 {
-		return nil
-	}
-
-	indexData := make([]byte, int(length))
-	var offsetIndex format.OffsetIndex
-	if _, err := readAt(c.file.reader, indexData, offset); err != nil {
-		return fmt.Errorf("read %d bytes offset index at offset %d: %w", length, offset, err)
-	}
-	if err := thrift.Unmarshal(&c.file.protocol, indexData, &offsetIndex); err != nil {
-		return fmt.Errorf("decode offset index: rowGroup=%d columnChunk=%d/%d: %w", c.rowGroup.Ordinal, c.Column(), len(c.rowGroup.Columns), err)
-	}
-	c.offsetIndex = &offsetIndex
-	return nil
-}
-
 type filePages struct {
 	chunk    *fileColumnChunk
 	rbuf     *bufio.Reader
diff --git a/go.mod b/go.mod
index bd2c9b0..d7c8e05 100644
--- a/go.mod
+++ b/go.mod
@@ -10,14 +10,8 @@ require (
 	github.com/olekukonko/tablewriter v0.0.5
 	github.com/pierrec/lz4/v4 v4.1.18
 	github.com/segmentio/encoding v0.3.6
-	github.com/stretchr/testify v1.8.4
 	golang.org/x/sys v0.10.0
 	google.golang.org/protobuf v1.30.0
 )
 
-require (
-	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/mattn/go-runewidth v0.0.9 // indirect
-	github.com/pmezard/go-difflib v1.0.0 // indirect
-	gopkg.in/yaml.v3 v3.0.1 // indirect
-)
+require github.com/mattn/go-runewidth v0.0.9 // indirect
diff --git a/go.sum b/go.sum
index 6b2fb10..97f3c36 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,5 @@
 github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
 github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -17,13 +15,9 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
 github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
 github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg=
 github.com/segmentio/encoding v0.3.6 h1:E6lVLyDPseWEulBmCmAKPanDd3jiyGDo5gMcugCRwZQ=
 github.com/segmentio/encoding v0.3.6/go.mod h1:n0JeuIqEQrQoPDGsjo8UNd1iA0U8d8+oHAA4E3G3OxM=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
 golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -32,7 +26,3 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/merge.go b/merge.go
index f100788..cc8df4a 100644
--- a/merge.go
+++ b/merge.go
@@ -350,7 +350,7 @@ func (m *mergeBuffer) setup(rows []Rows, compare func(Row, Row) int) {
 		extra := size - len(m.buffer)
 		b := make([][]Row, extra)
 		for i := range b {
-			b[i] = make([]Row, 0, mergeBufferSize)
+			b[i] = make([]Row, mergeBufferSize)
 		}
 		m.buffer = append(m.buffer, b...)
 		m.head = append(m.head, make([]int, extra)...)
@@ -379,11 +379,6 @@ func (m *mergeBuffer) release() {
 func (m *mergeBuffer) fill() error {
 	m.len = len(m.rows)
 	for i := range m.rows {
-		if m.head[i] < len(m.buffer[i]) {
-			// There is still rows data in m.buffer[i]. Skip filling the row buffer until
-			// all rows have been read.
-			continue
-		}
 		m.head[i] = 0
 		m.buffer[i] = m.buffer[i][:mergeBufferSize]
 		n, err := m.rows[i].ReadRows(m.buffer[i])
diff --git a/multi_row_group.go b/multi_row_group.go
index b68c878..e645c29 100644
--- a/multi_row_group.go
+++ b/multi_row_group.go
@@ -140,14 +140,14 @@ func (c *multiColumnChunk) Pages() Pages {
 	return &multiPages{column: c}
 }
 
-func (c *multiColumnChunk) ColumnIndex() (ColumnIndex, error) {
+func (c *multiColumnChunk) ColumnIndex() ColumnIndex {
 	// TODO: implement
-	return nil, nil
+	return nil
 }
 
-func (c *multiColumnChunk) OffsetIndex() (OffsetIndex, error) {
+func (c *multiColumnChunk) OffsetIndex() OffsetIndex {
 	// TODO: implement
-	return nil, nil
+	return nil
 }
 
 func (c *multiColumnChunk) BloomFilter() BloomFilter {
diff --git a/page.go b/page.go
index 1ebeac9..0c3ef03 100644
--- a/page.go
+++ b/page.go
@@ -585,17 +585,20 @@ func (page *booleanPage) Bounds() (min, max Value, ok bool) {
 }
 
 func (page *booleanPage) Slice(i, j int64) Page {
-	off := i / 8
-	end := j / 8
+	lowWithOffset := i + int64(page.offset)
+	highWithOffset := j + int64(page.offset)
 
-	if (j % 8) != 0 {
+	off := lowWithOffset / 8
+	end := highWithOffset / 8
+
+	if (highWithOffset % 8) != 0 {
 		end++
 	}
 
 	return &booleanPage{
 		typ:         page.typ,
 		bits:        page.bits[off:end],
-		offset:      int32(i % 8),
+		offset:      int32(lowWithOffset % 8),
 		numValues:   int32(j - i),
 		columnIndex: page.columnIndex,
 	}
diff --git a/row_buffer.go b/row_buffer.go
index 9f98e4d..00f93db 100644
--- a/row_buffer.go
+++ b/row_buffer.go
@@ -180,9 +180,9 @@ func (c *rowBufferColumnChunk) Column() int { return c.page.Column() }
 
 func (c *rowBufferColumnChunk) Pages() Pages { return onePage(&c.page) }
 
-func (c *rowBufferColumnChunk) ColumnIndex() (ColumnIndex, error) { return nil, nil }
+func (c *rowBufferColumnChunk) ColumnIndex() ColumnIndex { return nil }
 
-func (c *rowBufferColumnChunk) OffsetIndex() (OffsetIndex, error) { return nil, nil }
+func (c *rowBufferColumnChunk) OffsetIndex() OffsetIndex { return nil }
 
 func (c *rowBufferColumnChunk) BloomFilter() BloomFilter { return nil }
 
diff --git a/row_group.go b/row_group.go
index cf11bfc..6976ab5 100644
--- a/row_group.go
+++ b/row_group.go
@@ -462,11 +462,11 @@ func (c *seekColumnChunk) Pages() Pages {
 	return pages
 }
 
-func (c *seekColumnChunk) ColumnIndex() (ColumnIndex, error) {
+func (c *seekColumnChunk) ColumnIndex() ColumnIndex {
 	return c.base.ColumnIndex()
 }
 
-func (c *seekColumnChunk) OffsetIndex() (OffsetIndex, error) {
+func (c *seekColumnChunk) OffsetIndex() OffsetIndex {
 	return c.base.OffsetIndex()
 }
 
@@ -510,13 +510,13 @@ type emptyColumnChunk struct {
 	column int16
 }
 
-func (c *emptyColumnChunk) Type() Type                        { return c.typ }
-func (c *emptyColumnChunk) Column() int                       { return int(c.column) }
-func (c *emptyColumnChunk) Pages() Pages                      { return emptyPages{} }
-func (c *emptyColumnChunk) ColumnIndex() (ColumnIndex, error) { return emptyColumnIndex{}, nil }
-func (c *emptyColumnChunk) OffsetIndex() (OffsetIndex, error) { return emptyOffsetIndex{}, nil }
-func (c *emptyColumnChunk) BloomFilter() BloomFilter          { return emptyBloomFilter{} }
-func (c *emptyColumnChunk) NumValues() int64                  { return 0 }
+func (c *emptyColumnChunk) Type() Type               { return c.typ }
+func (c *emptyColumnChunk) Column() int              { return int(c.column) }
+func (c *emptyColumnChunk) Pages() Pages             { return emptyPages{} }
+func (c *emptyColumnChunk) ColumnIndex() ColumnIndex { return emptyColumnIndex{} }
+func (c *emptyColumnChunk) OffsetIndex() OffsetIndex { return emptyOffsetIndex{} }
+func (c *emptyColumnChunk) BloomFilter() BloomFilter { return emptyBloomFilter{} }
+func (c *emptyColumnChunk) NumValues() int64         { return 0 }
 
 type emptyBloomFilter struct{}
 


Test patch:
diff --git a/column_index_test.go b/column_index_test.go
index 3ecf08f..10ce032 100644
--- a/column_index_test.go
+++ b/column_index_test.go
@@ -4,7 +4,6 @@ import (
 	"testing"
 
 	"github.com/parquet-go/parquet-go"
-	"github.com/stretchr/testify/require"
 )
 
 func TestBinaryColumnIndexMinMax(t *testing.T) {
@@ -59,38 +58,3 @@ func TestBinaryColumnIndexMinMax(t *testing.T) {
 		}
 	}
 }
-
-func Test_ColumnIndexReuse(t *testing.T) {
-	min := "a"
-	max := "z"
-	indexer := parquet.ByteArrayType.NewColumnIndexer(16)
-	indexer.IndexPage(100, 0,
-		parquet.ValueOf(min),
-		parquet.ValueOf(max),
-	)
-	before := indexer.ColumnIndex()
-	require.Equal(t, 1, len(before.NullPages))
-	require.False(t, before.NullPages[0])
-
-	// Reset the indexer. Should be safe for reuse.
-	indexer.Reset()
-
-	// Index two pages that are both nul pages, expect the previous index to not have changed.
-	indexer.IndexPage(100, 100,
-		parquet.ValueOf(min),
-		parquet.ValueOf(max),
-	)
-	indexer.IndexPage(10, 10,
-		parquet.ValueOf(min),
-		parquet.ValueOf(max),
-	)
-	after := indexer.ColumnIndex()
-
-	require.Equal(t, 2, len(after.NullPages))
-	require.True(t, after.NullPages[0])
-	require.True(t, after.NullPages[1])
-
-	// Validate null pages of the previous index.
-	require.Equal(t, 1, len(before.NullPages))
-	require.False(t, before.NullPages[0])
-}
diff --git a/column_test.go b/column_test.go
index e32ca4a..c84d4a1 100644
--- a/column_test.go
+++ b/column_test.go
@@ -6,7 +6,6 @@ import (
 	"testing"
 
 	"github.com/google/uuid"
-
 	"github.com/parquet-go/parquet-go"
 	"github.com/parquet-go/parquet-go/deprecated"
 	"github.com/parquet-go/parquet-go/format"
@@ -140,7 +139,7 @@ func checkRowGroupColumnIndex(rowGroup parquet.RowGroup) error {
 
 func checkColumnChunkColumnIndex(columnChunk parquet.ColumnChunk) error {
 	columnType := columnChunk.Type()
-	columnIndex, _ := columnChunk.ColumnIndex()
+	columnIndex := columnChunk.ColumnIndex()
 	numPages := columnIndex.NumPages()
 	pagesRead := 0
 	stats := newColumnStats(columnType)
@@ -226,7 +225,7 @@ func checkRowGroupOffsetIndex(rowGroup parquet.RowGroup) error {
 }
 
 func checkColumnChunkOffsetIndex(columnChunk parquet.ColumnChunk) error {
-	offsetIndex, _ := columnChunk.OffsetIndex()
+	offsetIndex := columnChunk.OffsetIndex()
 	numPages := offsetIndex.NumPages()
 	pagesRead := 0
 	rowIndex := int64(0)
@@ -290,7 +289,7 @@ func checkFileColumnIndex(f *parquet.File) error {
 	columnIndexes := f.ColumnIndexes()
 	i := 0
 	return forEachColumnChunk(f, func(col *parquet.Column, chunk parquet.ColumnChunk) error {
-		columnIndex, _ := chunk.ColumnIndex()
+		columnIndex := chunk.ColumnIndex()
 		if n := columnIndex.NumPages(); n <= 0 {
 			return fmt.Errorf("invalid number of pages found in the column index: %d", n)
 		}
@@ -357,7 +356,7 @@ func checkFileOffsetIndex(f *parquet.File) error {
 	offsetIndexes := f.OffsetIndexes()
 	i := 0
 	return forEachColumnChunk(f, func(col *parquet.Column, chunk parquet.ColumnChunk) error {
-		offsetIndex, _ := chunk.OffsetIndex()
+		offsetIndex := chunk.OffsetIndex()
 		if n := offsetIndex.NumPages(); n <= 0 {
 			return fmt.Errorf("invalid number of pages found in the offset index: %d", n)
 		}
diff --git a/convert_test.go b/convert_test.go
index 5187298..dc01e0e 100644
--- a/convert_test.go
+++ b/convert_test.go
@@ -1190,47 +1190,3 @@ func TestConvertValue(t *testing.T) {
 		})
 	}
 }
-
-func TestMissingColumnChunk(t *testing.T) {
-	type stringRow struct{ StringVal string }
-	schema := parquet.SchemaOf(&stringRow{})
-	buffer := parquet.NewGenericBuffer[stringRow](schema)
-	if _, err := buffer.Write([]stringRow{{"hello"}, {"world"}}); err != nil {
-		t.Fatal(err)
-	}
-
-	type boolRow struct{ BoolValue bool }
-	conv := convertMissingColumn{
-		schema: parquet.SchemaOf(&boolRow{}),
-	}
-	boolRowGroup := parquet.ConvertRowGroup(buffer, conv)
-	chunk := boolRowGroup.ColumnChunks()[0]
-
-	t.Run("chunk values", func(t *testing.T) {
-		if chunk.NumValues() != buffer.NumRows() {
-			t.Fatal("chunk values mismatch, got", chunk.NumValues(), "want", buffer.NumRows())
-		}
-	})
-
-	t.Run("slice page", func(t *testing.T) {
-		page, err := chunk.Pages().ReadPage()
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		if page.NumValues() != buffer.NumRows() {
-			t.Fatalf("page size mismatch: want = %d, got = %d", buffer.NumRows(), page.NumValues())
-		}
-		if size := page.Slice(0, 1).NumValues(); size != 1 {
-			t.Fatalf("page slice size mismatch: want = %d, got = %d", 1, size)
-		}
-	})
-}
-
-type convertMissingColumn struct {
-	schema *parquet.Schema
-}
-
-func (m convertMissingColumn) Column(_ int) int                        { return -1 }
-func (m convertMissingColumn) Schema() *parquet.Schema                 { return m.schema }
-func (m convertMissingColumn) Convert(rows []parquet.Row) (int, error) { return len(rows), nil }
diff --git a/dictionary_test.go b/dictionary_test.go
index 191c7cf..5442c7e 100644
--- a/dictionary_test.go
+++ b/dictionary_test.go
@@ -257,7 +257,7 @@ func TestIssue312(t *testing.T) {
 			rowGroup := testCase.getRowGroup(t)
 
 			chunk := rowGroup.ColumnChunks()[0]
-			idx, _ := chunk.ColumnIndex()
+			idx := chunk.ColumnIndex()
 			val := idx.MinValue(0)
 			columnType := chunk.Type()
 			values := columnType.NewValues(val.Bytes(), []uint32{0, uint32(len(val.Bytes()))})
diff --git a/file_test.go b/file_test.go
index 10d4e64..e8f1242 100644
--- a/file_test.go
+++ b/file_test.go
@@ -1,7 +1,6 @@
 package parquet_test
 
 import (
-	"errors"
 	"io"
 	"os"
 	"path/filepath"
@@ -53,72 +52,6 @@ func TestOpenFile(t *testing.T) {
 	}
 }
 
-func TestOpenFileWithoutPageIndex(t *testing.T) {
-	for _, path := range testdataFiles {
-		t.Run(path, func(t *testing.T) {
-			f, err := os.Open(path)
-			if err != nil {
-				t.Fatal(err)
-			}
-			defer f.Close()
-
-			s, err := f.Stat()
-			if err != nil {
-				t.Fatal(err)
-			}
-
-			fileWithIndex, err := parquet.OpenFile(f, s.Size())
-			if err != nil {
-				t.Fatal(err)
-			}
-			fileWithoutIndex, err := parquet.OpenFile(f, s.Size(), parquet.SkipPageIndex(true))
-			if err != nil {
-				t.Fatal(err)
-			}
-
-			if size := fileWithoutIndex.Size(); size != s.Size() {
-				t.Errorf("file size mismatch: want=%d got=%d", s.Size(), size)
-			}
-
-			for iRowGroup, rowGroup := range fileWithoutIndex.RowGroups() {
-				for iChunk, chunk := range rowGroup.ColumnChunks() {
-					chunkMeta := fileWithoutIndex.Metadata().RowGroups[iRowGroup].Columns[iChunk].MetaData
-
-					preloadedColumnIndex, pErr := fileWithIndex.RowGroups()[iRowGroup].ColumnChunks()[iChunk].ColumnIndex()
-					if errors.Is(pErr, parquet.ErrMissingColumnIndex) && chunkMeta.IndexPageOffset != 0 {
-						t.Errorf("get column index for %s: %s", chunkMeta.PathInSchema[0], pErr)
-					}
-					columnIndex, err := chunk.ColumnIndex()
-					if errors.Is(err, parquet.ErrMissingColumnIndex) && chunkMeta.IndexPageOffset != 0 {
-						t.Errorf("get column index for %s: %s", chunkMeta.PathInSchema[0], err)
-					}
-					if !errors.Is(err, pErr) {
-						t.Errorf("mismatch when opening file with and without index, chunk=%d, row group=%d", iChunk, iRowGroup)
-					}
-					if preloadedColumnIndex == nil && columnIndex != nil || preloadedColumnIndex != nil && columnIndex == nil {
-						t.Errorf("mismatch when opening file with and without index, chunk=%d, row group=%d", iChunk, iRowGroup)
-					}
-
-					preloadedOffsetIndex, pErr := fileWithIndex.RowGroups()[iRowGroup].ColumnChunks()[iChunk].OffsetIndex()
-					if errors.Is(pErr, parquet.ErrMissingOffsetIndex) && chunkMeta.IndexPageOffset != 0 {
-						t.Errorf("get offset index for %s: %s", chunkMeta.PathInSchema[0], pErr)
-					}
-					offsetIndex, err := chunk.OffsetIndex()
-					if errors.Is(err, parquet.ErrMissingOffsetIndex) && chunkMeta.IndexPageOffset != 0 {
-						t.Errorf("get offset index for %s: %s", chunkMeta.PathInSchema[0], err)
-					}
-					if !errors.Is(err, pErr) {
-						t.Errorf("mismatch when opening file with and without index, chunk=%d, row group=%d", iChunk, iRowGroup)
-					}
-					if preloadedOffsetIndex == nil && offsetIndex != nil || preloadedOffsetIndex != nil && offsetIndex == nil {
-						t.Errorf("mismatch when opening file with and without index, chunk=%d, row group=%d", iChunk, iRowGroup)
-					}
-				}
-			}
-		})
-	}
-}
-
 func printColumns(t *testing.T, col *parquet.Column, indent string) {
 	if t.Failed() {
 		return
diff --git a/page_test.go b/page_test.go
index 6c77d7a..abe2eda 100644
--- a/page_test.go
+++ b/page_test.go
@@ -497,3 +497,71 @@ func TestRepeatedPageTrailingNulls(t *testing.T) {
 		t.Errorf("wrong number of rows read: got=%d want=%d", n, len(records))
 	}
 }
+
+func TestReslicingBooleanPage(t *testing.T) {
+	type testStruct struct {
+		B bool `parquet:"b"`
+	}
+
+	numValues := 100
+	expected := []*testStruct{}
+	for i := 0; i < numValues; i++ {
+		expected = append(expected, &testStruct{B: i%2 == 0})
+	}
+
+	buf := new(bytes.Buffer)
+	writer := parquet.NewGenericWriter[*testStruct](buf)
+	_, err := writer.Write(expected)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = writer.Close()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	reader := bytes.NewReader(buf.Bytes())
+	pf, err := parquet.OpenFile(reader, reader.Size())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// grab the page we wrote above
+	rg := pf.RowGroups()[0]
+	cc := rg.ColumnChunks()
+	pgs := cc[0].Pages()
+
+	pg, err := pgs.ReadPage()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// continue reslicing and reading the values
+	sliceEvery := 3
+	for i := 0; i < numValues-1; i += sliceEvery {
+		vs := make([]parquet.Value, numValues)
+
+		low := int64(sliceEvery)
+		high := int64(numValues - i)
+
+		if low >= high {
+			break
+		}
+
+		// slice the page
+		pg = pg.Slice(low, high)
+		v := pg.Values()
+		v.ReadValues(vs)
+
+		// and the expected values with the same low/high
+		expected = expected[low:high]
+
+		// confirm values match
+		for n, exp := range expected {
+			if exp.B != vs[n].Boolean() {
+				t.Fatalf("unexpected value: %v at pos: %d", vs[n], n)
+			}
+			n++
+		}
+	}
+}
diff --git a/parquet_test.go b/parquet_test.go
index 432df63..1180647 100644
--- a/parquet_test.go
+++ b/parquet_test.go
@@ -170,12 +170,8 @@ func ExampleSearch() {
 	rowGroup := file.RowGroups()[0]
 	firstNameColChunk := rowGroup.ColumnChunks()[0]
 
-	columnIndex, err := firstNameColChunk.ColumnIndex()
-	if err != nil {
-		log.Fatal(err)
-	}
-	found := parquet.Search(columnIndex, parquet.ValueOf("Luke"), parquet.ByteArrayType)
-	offsetIndex, _ := firstNameColChunk.OffsetIndex()
+	found := parquet.Search(firstNameColChunk.ColumnIndex(), parquet.ValueOf("Luke"), parquet.ByteArrayType)
+	offsetIndex := firstNameColChunk.OffsetIndex()
 	fmt.Printf("numPages: %d\n", offsetIndex.NumPages())
 	fmt.Printf("result found in page: %d\n", found)
 	if found < offsetIndex.NumPages() {
diff --git a/sorting_test.go b/sorting_test.go
index f2ea144..5eaf328 100644
--- a/sorting_test.go
+++ b/sorting_test.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"encoding/binary"
 	"math/rand"
-	"os"
 	"reflect"
 	"sort"
 	"testing"
@@ -258,61 +257,3 @@ func assertRowsEqualByRow[T any](t *testing.T, rowsGot, rowsWant []T) {
 		t.Error(count, "rows mismatched out of", len(rowsWant), "total")
 	}
 }
-
-func TestIssue_82(t *testing.T) {
-	type Record struct {
-		A string `parquet:"a"`
-	}
-
-	fi, err := os.Open("testdata/lz4_raw_compressed_larger.parquet")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer fi.Close()
-
-	stat, err := fi.Stat()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	fl, err := parquet.OpenFile(fi, stat.Size())
-	if err != nil {
-		t.Fatal(err)
-	}
-	groups := fl.RowGroups()
-	if expect, got := 1, len(groups); expect != got {
-		t.Fatalf("expected %d row groups got %d", expect, got)
-	}
-
-	fr := parquet.NewRowGroupReader(groups[0])
-
-	var out bytes.Buffer
-
-	pw := parquet.NewSortingWriter[Record](
-		&out,
-		1000,
-		parquet.SortingWriterConfig(
-			parquet.SortingColumns(parquet.Ascending("a")),
-		),
-	)
-
-	if _, err := parquet.CopyRows(pw, fr); err != nil {
-		t.Fatal(err)
-	}
-
-	if err := pw.Close(); err != nil {
-		t.Fatal(err)
-	}
-	rowsWant, err := parquet.Read[Record](fl, stat.Size())
-	if err != nil {
-		t.Fatal(err)
-	}
-	rowsGot, err := parquet.Read[Record](bytes.NewReader(out.Bytes()), int64(out.Len()))
-	if err != nil {
-		t.Fatal(err)
-	}
-	sort.Slice(rowsWant, func(i, j int) bool {
-		return rowsWant[i].A < rowsWant[j].A
-	})
-	assertRowsEqualByRow(t, rowsGot, rowsWant)
-}