/* * Minio Cloud Storage, (C) 2018 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package parquet import ( "bytes" "errors" "fmt" "math" "github.com/minio/minio/pkg/s3select/internal/parquet-go/gen-go/parquet" ) func i64sToi32s(i64s []int64) (i32s []int32) { i32s = make([]int32, len(i64s)) for i := range i64s { i32s[i] = int32(i64s[i]) } return i32s } func readBitPacked(reader *bytes.Reader, header, bitWidth uint64) (result []int64, err error) { count := header * 8 if count == 0 { return result, nil } if bitWidth == 0 { return make([]int64, count), nil } data := make([]byte, header*bitWidth) if _, err = reader.Read(data); err != nil { return nil, err } var val, used, left, b uint64 valNeedBits := bitWidth i := -1 for { if left <= 0 { i++ if i >= len(data) { break } b = uint64(data[i]) left = 8 used = 0 } if left >= valNeedBits { val |= ((b >> used) & ((1 << valNeedBits) - 1)) << (bitWidth - valNeedBits) result = append(result, int64(val)) val = 0 left -= valNeedBits used += valNeedBits valNeedBits = bitWidth } else { val |= (b >> used) << (bitWidth - valNeedBits) valNeedBits -= left left = 0 } } return result, nil } func readBools(reader *bytes.Reader, count uint64) (result []bool, err error) { i64s, err := readBitPacked(reader, count, 1) if err != nil { return nil, err } var i uint64 for i = 0; i < count; i++ { result = append(result, i64s[i] > 0) } return result, nil } func readInt32s(reader *bytes.Reader, count uint64) (result []int32, err error) { buf := make([]byte, 4) var i uint64 for i = 0; i < count; i++ { if _, err = reader.Read(buf); err != nil { return nil, err } result = append(result, int32(bytesToUint32(buf))) } return result, nil } func readInt64s(reader *bytes.Reader, count uint64) (result []int64, err error) { buf := make([]byte, 8) var i uint64 for i = 0; i < count; i++ { if _, err = reader.Read(buf); err != nil { return nil, err } result = append(result, int64(bytesToUint64(buf))) } return result, nil } func readInt96s(reader *bytes.Reader, count uint64) (result [][]byte, err error) { var i uint64 for i = 0; i < count; i++ { buf := make([]byte, 12) if _, err = reader.Read(buf); err != nil { return nil, err } result = append(result, buf) } return result, nil } func readFloats(reader *bytes.Reader, count uint64) (result []float32, err error) { buf := make([]byte, 4) var i uint64 for i = 0; i < count; i++ { if _, err = reader.Read(buf); err != nil { return nil, err } result = append(result, math.Float32frombits(bytesToUint32(buf))) } return result, nil } func readDoubles(reader *bytes.Reader, count uint64) (result []float64, err error) { buf := make([]byte, 8) var i uint64 for i = 0; i < count; i++ { if _, err = reader.Read(buf); err != nil { return nil, err } result = append(result, math.Float64frombits(bytesToUint64(buf))) } return result, nil } func readByteArrays(reader *bytes.Reader, count uint64) (result [][]byte, err error) { buf := make([]byte, 4) var length uint32 var data []byte var i uint64 for i = 0; i < count; i++ { if _, err = reader.Read(buf); err != nil { return nil, err } length = bytesToUint32(buf) data = make([]byte, length) if length > 0 { if _, err = reader.Read(data); err != nil { return nil, err } } result = append(result, data) } return result, nil } func readFixedLenByteArrays(reader *bytes.Reader, count, length uint64) (result [][]byte, err error) { var i uint64 for i = 0; i < count; i++ { data := make([]byte, length) if _, err = reader.Read(data); err != nil { return nil, err } result = append(result, data) } return result, nil } func readValues(reader *bytes.Reader, dataType parquet.Type, count, length uint64) (interface{}, error) { switch dataType { case parquet.Type_BOOLEAN: return readBools(reader, count) case parquet.Type_INT32: return readInt32s(reader, count) case parquet.Type_INT64: return readInt64s(reader, count) case parquet.Type_INT96: return readInt96s(reader, count) case parquet.Type_FLOAT: return readFloats(reader, count) case parquet.Type_DOUBLE: return readDoubles(reader, count) case parquet.Type_BYTE_ARRAY: return readByteArrays(reader, count) case parquet.Type_FIXED_LEN_BYTE_ARRAY: return readFixedLenByteArrays(reader, count, length) } return nil, fmt.Errorf("unknown parquet type %v", dataType) } func readUnsignedVarInt(reader *bytes.Reader) (v uint64, err error) { var b byte var shift uint64 for { if b, err = reader.ReadByte(); err != nil { return 0, err } if v |= ((uint64(b) & 0x7F) << shift); b&0x80 == 0 { break } shift += 7 } return v, nil } func readRLE(reader *bytes.Reader, header, bitWidth uint64) (result []int64, err error) { width := (bitWidth + 7) / 8 data := make([]byte, width) if width > 0 { if _, err = reader.Read(data); err != nil { return nil, err } } if width < 4 { data = append(data, make([]byte, 4-width)...) } val := int64(bytesToUint32(data)) count := header >> 1 if count > math.MaxInt64/8 { // 8 bytes/element. return nil, errors.New("parquet: size too large") } result = make([]int64, count) for i := range result { result[i] = val } return result, nil } func readRLEBitPackedHybrid(reader *bytes.Reader, length, bitWidth uint64) (result []int64, err error) { if length <= 0 { var i32s []int32 i32s, err = readInt32s(reader, 1) if err != nil { return nil, err } if i32s[0] < 0 { return nil, errors.New("parquet: negative RLEBitPackedHybrid length") } length = uint64(i32s[0]) } buf := make([]byte, length) if _, err = reader.Read(buf); err != nil { return nil, err } reader = bytes.NewReader(buf) for reader.Len() > 0 { header, err := readUnsignedVarInt(reader) if err != nil { return nil, err } var i64s []int64 if header&1 == 0 { i64s, err = readRLE(reader, header, bitWidth) } else { i64s, err = readBitPacked(reader, header>>1, bitWidth) } if err != nil { return nil, err } result = append(result, i64s...) } return result, nil } func readDeltaBinaryPackedInt(reader *bytes.Reader) (result []int64, err error) { blockSize, err := readUnsignedVarInt(reader) if err != nil { return nil, err } numMiniblocksInBlock, err := readUnsignedVarInt(reader) if err != nil { return nil, err } numValues, err := readUnsignedVarInt(reader) if err != nil { return nil, err } firstValueZigZag, err := readUnsignedVarInt(reader) if err != nil { return nil, err } v := int64(firstValueZigZag>>1) ^ (-int64(firstValueZigZag & 1)) result = append(result, v) if numMiniblocksInBlock == 0 { return nil, errors.New("parquet: zero mini blocks in block") } numValuesInMiniBlock := blockSize / numMiniblocksInBlock bitWidths := make([]uint64, numMiniblocksInBlock) for uint64(len(result)) < numValues { minDeltaZigZag, err := readUnsignedVarInt(reader) if err != nil { return nil, err } for i := 0; uint64(i) < numMiniblocksInBlock; i++ { b, err := reader.ReadByte() if err != nil { return nil, err } bitWidths[i] = uint64(b) } minDelta := int64(minDeltaZigZag>>1) ^ (-int64(minDeltaZigZag & 1)) for i := 0; uint64(i) < numMiniblocksInBlock; i++ { i64s, err := readBitPacked(reader, numValuesInMiniBlock/8, bitWidths[i]) if err != nil { return nil, err } for j := range i64s { v += i64s[j] + minDelta result = append(result, v) } } } return result[:numValues], nil } func readDeltaLengthByteArrays(reader *bytes.Reader) (result [][]byte, err error) { i64s, err := readDeltaBinaryPackedInt(reader) if err != nil { return nil, err } for i := 0; i < len(i64s); i++ { arrays, err := readFixedLenByteArrays(reader, 1, uint64(i64s[i])) if err != nil { return nil, err } result = append(result, arrays[0]) } return result, nil } func readDeltaByteArrays(reader *bytes.Reader) (result [][]byte, err error) { i64s, err := readDeltaBinaryPackedInt(reader) if err != nil { return nil, err } suffixes, err := readDeltaLengthByteArrays(reader) if err != nil { return nil, err } result = append(result, suffixes[0]) for i := 1; i < len(i64s); i++ { prefixLength := i64s[i] val := append([]byte{}, result[i-1][:prefixLength]...) val = append(val, suffixes[i]...) result = append(result, val) } return result, nil } func readDataPageValues( bytesReader *bytes.Reader, encoding parquet.Encoding, dataType parquet.Type, convertedType parquet.ConvertedType, count, bitWidth uint64, ) (result interface{}, resultDataType parquet.Type, err error) { switch encoding { case parquet.Encoding_PLAIN: result, err = readValues(bytesReader, dataType, count, bitWidth) return result, dataType, err case parquet.Encoding_PLAIN_DICTIONARY: b, err := bytesReader.ReadByte() if err != nil { return nil, -1, err } i64s, err := readRLEBitPackedHybrid(bytesReader, uint64(bytesReader.Len()), uint64(b)) if err != nil { return nil, -1, err } if len(i64s) < int(count) || count > math.MaxInt64/8 { return nil, -1, errors.New("parquet: value out of range") } return i64s[:count], parquet.Type_INT64, nil case parquet.Encoding_RLE: i64s, err := readRLEBitPackedHybrid(bytesReader, 0, bitWidth) if err != nil { return nil, -1, err } if len(i64s) < int(count) || count > math.MaxInt64/8 { return nil, -1, errors.New("parquet: value out of range") } i64s = i64s[:count] if dataType == parquet.Type_INT32 { return i64sToi32s(i64s), parquet.Type_INT32, nil } return i64s, parquet.Type_INT64, nil case parquet.Encoding_BIT_PACKED: return nil, -1, fmt.Errorf("deprecated parquet encoding %v", parquet.Encoding_BIT_PACKED) case parquet.Encoding_DELTA_BINARY_PACKED: i64s, err := readDeltaBinaryPackedInt(bytesReader) if err != nil { return nil, -1, err } if len(i64s) < int(count) || count > math.MaxInt64/8 { return nil, -1, errors.New("parquet: value out of range") } i64s = i64s[:count] if dataType == parquet.Type_INT32 { return i64sToi32s(i64s), parquet.Type_INT32, nil } return i64s, parquet.Type_INT64, nil case parquet.Encoding_DELTA_LENGTH_BYTE_ARRAY: byteSlices, err := readDeltaLengthByteArrays(bytesReader) if err != nil { return nil, -1, err } if len(byteSlices) < int(count) || count > math.MaxInt64/24 { return nil, -1, errors.New("parquet: value out of range") } return byteSlices[:count], parquet.Type_FIXED_LEN_BYTE_ARRAY, nil case parquet.Encoding_DELTA_BYTE_ARRAY: byteSlices, err := readDeltaByteArrays(bytesReader) if err != nil { return nil, -1, err } if len(byteSlices) < int(count) || count > math.MaxInt64/24 { return nil, -1, errors.New("parquet: value out of range") } return byteSlices[:count], parquet.Type_FIXED_LEN_BYTE_ARRAY, nil } return nil, -1, fmt.Errorf("unsupported parquet encoding %v", encoding) }