github.com/apache/arrow/go/v14@v14.0.2/parquet/metadata/stat_compare_test.go (about)

     1  // Licensed to the Apache Software Foundation (ASF) under one
     2  // or more contributor license agreements.  See the NOTICE file
     3  // distributed with this work for additional information
     4  // regarding copyright ownership.  The ASF licenses this file
     5  // to you under the Apache License, Version 2.0 (the
     6  // "License"); you may not use this file except in compliance
     7  // with the License.  You may obtain a copy of the License at
     8  //
     9  // http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package metadata
    18  
    19  import (
    20  	"encoding/binary"
    21  	"testing"
    22  
    23  	"github.com/apache/arrow/go/v14/parquet"
    24  	"github.com/apache/arrow/go/v14/parquet/schema"
    25  	"github.com/stretchr/testify/assert"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  func TestSignedByteArrayCompare(t *testing.T) {
    30  	s := ByteArrayStatistics{
    31  		statistics: statistics{
    32  			order: schema.SortSIGNED,
    33  		},
    34  	}
    35  
    36  	// signed byte array comparison is only used for Decimal comparison.
    37  	// when decimals are encoded as byte arrays they use twos compliment
    38  	// big-endian encoded values. Comparisons of byte arrays of unequal
    39  	// types need to handle sign extension.
    40  
    41  	tests := []struct {
    42  		b     []byte
    43  		order int
    44  	}{
    45  		{[]byte{0x80, 0x80, 0, 0}, 0},
    46  		{[]byte{ /*0xFF,*/ 0x80, 0, 0}, 1},
    47  		{[]byte{0xFF, 0x80, 0, 0}, 1},
    48  		{[]byte{ /*0xFF,*/ 0xFF, 0x01, 0}, 2},
    49  		{[]byte{ /*0xFF, 0xFF,*/ 0x80, 0}, 3},
    50  		{[]byte{ /*0xFF,*/ 0xFF, 0x80, 0}, 3},
    51  		{[]byte{0xFF, 0xFF, 0x80, 0}, 3},
    52  		{[]byte{ /*0xFF,0xFF,0xFF,*/ 0x80}, 4},
    53  		{[]byte{ /*0xFF,0xFF,0xFF*/ 0xFF}, 5},
    54  		{[]byte{ /*0, 0,*/ 0x01, 0x01}, 6},
    55  		{[]byte{ /*0,*/ 0, 0x01, 0x01}, 6},
    56  		{[]byte{0, 0, 0x01, 0x01}, 6},
    57  		{[]byte{ /*0,*/ 0x01, 0x01, 0}, 7},
    58  		{[]byte{0x01, 0x01, 0, 0}, 8},
    59  	}
    60  
    61  	for i, tt := range tests {
    62  		// empty array is always the smallest
    63  		assert.Truef(t, s.less(parquet.ByteArray{}, parquet.ByteArray(tt.b)), "case: %d", i)
    64  		assert.Falsef(t, s.less(parquet.ByteArray(tt.b), parquet.ByteArray{}), "case: %d", i)
    65  		// equals is always false
    66  		assert.Falsef(t, s.less(parquet.ByteArray(tt.b), parquet.ByteArray(tt.b)), "case: %d", i)
    67  
    68  		for j, case2 := range tests {
    69  			var fn func(assert.TestingT, bool, string, ...interface{}) bool
    70  			if tt.order < case2.order {
    71  				fn = assert.Truef
    72  			} else {
    73  				fn = assert.Falsef
    74  			}
    75  			fn(t, s.less(parquet.ByteArray(tt.b), parquet.ByteArray(case2.b)),
    76  				"%d (order: %d) %d (order: %d)", i, tt.order, j, case2.order)
    77  		}
    78  	}
    79  }
    80  
    81  func TestUnsignedByteArrayCompare(t *testing.T) {
    82  	s := ByteArrayStatistics{
    83  		statistics: statistics{
    84  			order: schema.SortUNSIGNED,
    85  		},
    86  	}
    87  
    88  	s1ba := parquet.ByteArray("arrange")
    89  	s2ba := parquet.ByteArray("arrangement")
    90  	assert.True(t, s.less(s1ba, s2ba))
    91  
    92  	// multi-byte utf-8 characters
    93  	s1ba = parquet.ByteArray("braten")
    94  	s2ba = parquet.ByteArray("bügeln")
    95  	assert.True(t, s.less(s1ba, s2ba))
    96  
    97  	s1ba = parquet.ByteArray("ünk123456") // ü = 252
    98  	s2ba = parquet.ByteArray("ănk123456") // ă = 259
    99  	assert.True(t, s.less(s1ba, s2ba))
   100  }
   101  
   102  func TestSignedCompareFLBA(t *testing.T) {
   103  	s := FixedLenByteArrayStatistics{
   104  		statistics: statistics{order: schema.SortSIGNED},
   105  	}
   106  
   107  	values := []parquet.FixedLenByteArray{
   108  		[]byte{0x80, 0, 0, 0},
   109  		[]byte{0xFF, 0xFF, 0x01, 0},
   110  		[]byte{0xFF, 0xFF, 0x80, 0},
   111  		[]byte{0xFF, 0xFF, 0xFF, 0x80},
   112  		[]byte{0xFF, 0xFF, 0xFF, 0xFF},
   113  		[]byte{0, 0, 0x01, 0x01},
   114  		[]byte{0, 0x01, 0x01, 0},
   115  		[]byte{0x01, 0x01, 0, 0},
   116  	}
   117  
   118  	for i, v := range values {
   119  		assert.Falsef(t, s.less(v, v), "%d", i)
   120  		for j, v2 := range values[i+1:] {
   121  			assert.Truef(t, s.less(v, v2), "%d %d", i, j)
   122  			assert.Falsef(t, s.less(v2, v), "%d %d", j, i)
   123  		}
   124  	}
   125  }
   126  
   127  func TestUnsignedCompareFLBA(t *testing.T) {
   128  	s := FixedLenByteArrayStatistics{
   129  		statistics: statistics{order: schema.SortUNSIGNED},
   130  	}
   131  
   132  	s1flba := parquet.FixedLenByteArray("Anti123456")
   133  	s2flba := parquet.FixedLenByteArray("Bunkd123456")
   134  	assert.True(t, s.less(s1flba, s2flba))
   135  
   136  	s1flba = parquet.FixedLenByteArray("Bunk123456")
   137  	s2flba = parquet.FixedLenByteArray("Bünk123456")
   138  	assert.True(t, s.less(s1flba, s2flba))
   139  }
   140  
   141  func TestSignedCompareInt96(t *testing.T) {
   142  	s := Int96Statistics{
   143  		statistics: statistics{order: schema.SortSIGNED},
   144  	}
   145  
   146  	val := -14
   147  
   148  	var (
   149  		a   = parquet.NewInt96([3]uint32{1, 41, 14})
   150  		b   = parquet.NewInt96([3]uint32{1, 41, 42})
   151  		aa  = parquet.NewInt96([3]uint32{1, 41, 14})
   152  		bb  = parquet.NewInt96([3]uint32{1, 41, 14})
   153  		aaa = parquet.NewInt96([3]uint32{1, 41, uint32(val)})
   154  		bbb = parquet.NewInt96([3]uint32{1, 41, 42})
   155  	)
   156  
   157  	assert.True(t, s.less(a, b))
   158  	assert.True(t, !s.less(aa, bb) && !s.less(bb, aa))
   159  	assert.True(t, s.less(aaa, bbb))
   160  }
   161  
   162  func TestUnsignedCompareInt96(t *testing.T) {
   163  	s := Int96Statistics{
   164  		statistics: statistics{order: schema.SortUNSIGNED},
   165  	}
   166  
   167  	valb := -41
   168  	valbb := -14
   169  
   170  	var (
   171  		a   = parquet.NewInt96([3]uint32{1, 41, 14})
   172  		b   = parquet.NewInt96([3]uint32{1, uint32(valb), 42})
   173  		aa  = parquet.NewInt96([3]uint32{1, 41, 14})
   174  		bb  = parquet.NewInt96([3]uint32{1, 41, uint32(valbb)})
   175  		aaa parquet.Int96
   176  		bbb parquet.Int96
   177  	)
   178  
   179  	assert.True(t, s.less(a, b))
   180  	assert.True(t, s.less(aa, bb))
   181  
   182  	binary.LittleEndian.PutUint32(aaa[8:], 2451545) // 2000-01-01
   183  	binary.LittleEndian.PutUint32(bbb[8:], 2451546) // 2000-01-02
   184  	// 12 hours + 34 minutes + 56 seconds
   185  	aaa.SetNanoSeconds(45296000000000)
   186  	// 12 hours + 34 minutes + 50 seconds
   187  	bbb.SetNanoSeconds(45290000000000)
   188  	assert.True(t, s.less(aaa, bbb))
   189  
   190  	binary.LittleEndian.PutUint32(aaa[8:], 2451545) // 2000-01-01
   191  	binary.LittleEndian.PutUint32(bbb[8:], 2451545) // 2000-01-01
   192  	// 11 hours + 34 minutes + 56 seconds
   193  	aaa.SetNanoSeconds(41696000000000)
   194  	// 12 hours + 34 minutes + 50 seconds
   195  	bbb.SetNanoSeconds(45290000000000)
   196  	assert.True(t, s.less(aaa, bbb))
   197  
   198  	binary.LittleEndian.PutUint32(aaa[8:], 2451545) // 2000-01-01
   199  	binary.LittleEndian.PutUint32(bbb[8:], 2451545) // 2000-01-01
   200  	// 12 hours + 34 minutes + 55 seconds
   201  	aaa.SetNanoSeconds(45295000000000)
   202  	// 12 hours + 34 minutes + 56 seconds
   203  	bbb.SetNanoSeconds(45296000000000)
   204  	assert.True(t, s.less(aaa, bbb))
   205  }
   206  
   207  func TestCompareSignedInt64(t *testing.T) {
   208  	var (
   209  		a   int64 = 1
   210  		b   int64 = 4
   211  		aa  int64 = 1
   212  		bb  int64 = 1
   213  		aaa int64 = -1
   214  		bbb int64 = 1
   215  	)
   216  
   217  	n := schema.NewInt64Node("signedint64", parquet.Repetitions.Required, -1)
   218  	descr := schema.NewColumn(n, 0, 0)
   219  	s := NewStatistics(descr, nil).(*Int64Statistics)
   220  
   221  	assert.True(t, s.less(a, b))
   222  	assert.True(t, !s.less(aa, bb) && !s.less(bb, aa))
   223  	assert.True(t, s.less(aaa, bbb))
   224  }
   225  
   226  func TestCompareUnsignedInt64(t *testing.T) {
   227  	var (
   228  		a   int64 = 1
   229  		b   int64 = 4
   230  		aa  int64 = 1
   231  		bb  int64 = 1
   232  		aaa int64 = 1
   233  		bbb int64 = -1
   234  	)
   235  
   236  	n, err := schema.NewPrimitiveNodeConverted("unsigned int64", parquet.Repetitions.Required, parquet.Types.Int64, schema.ConvertedTypes.Uint64, 0, 0, 0, 0)
   237  	require.NoError(t, err)
   238  	descr := schema.NewColumn(n, 0, 0)
   239  
   240  	assert.Equal(t, schema.SortUNSIGNED, descr.SortOrder())
   241  	s := NewStatistics(descr, nil).(*Int64Statistics)
   242  
   243  	assert.True(t, s.less(a, b))
   244  	assert.True(t, !s.less(aa, bb) && !s.less(bb, aa))
   245  	assert.True(t, s.less(aaa, bbb))
   246  }
   247  
   248  func TestCompareUnsignedInt32(t *testing.T) {
   249  	var (
   250  		a   int32 = 1
   251  		b   int32 = 4
   252  		aa  int32 = 1
   253  		bb  int32 = 1
   254  		aaa int32 = 1
   255  		bbb int32 = -1
   256  	)
   257  
   258  	n, err := schema.NewPrimitiveNodeConverted("unsigned int32", parquet.Repetitions.Required, parquet.Types.Int32, schema.ConvertedTypes.Uint32, 0, 0, 0, 0)
   259  	require.NoError(t, err)
   260  	descr := schema.NewColumn(n, 0, 0)
   261  
   262  	assert.Equal(t, schema.SortUNSIGNED, descr.SortOrder())
   263  	s := NewStatistics(descr, nil).(*Int32Statistics)
   264  
   265  	assert.True(t, s.less(a, b))
   266  	assert.True(t, !s.less(aa, bb) && !s.less(bb, aa))
   267  	assert.True(t, s.less(aaa, bbb))
   268  }