ibessonov commented on code in PR #5686: URL: https://github.com/apache/ignite-3/pull/5686#discussion_r2071394218
########## modules/storage-api/src/main/java/org/apache/ignite/internal/storage/util/StorageUtils.java: ########## @@ -291,4 +292,19 @@ public static BinaryTupleComparator binaryTupleComparator(List<StorageSortedInde return new BinaryTupleComparator(columnCollation, columnTypes); } + + /** + * Creates a comparator for a Sorted Index identified by the given columns descriptors. + */ + public static PartialBinaryTupleComparator partialBinaryTupleComparator(List<StorageSortedIndexColumnDescriptor> columns) { + List<CatalogColumnCollation> columnCollation = new ArrayList<>(columns.size()); + List<NativeType> columnTypes = new ArrayList<>(columns.size()); + + for (StorageSortedIndexColumnDescriptor col : columns) { + columnCollation.add(CatalogColumnCollation.get(col.asc(), !col.asc())); Review Comment: Please add a comment that would explain why `nullsFirst` is `!col.asc()`, it's not really obvious ########## modules/core/src/main/java/org/apache/ignite/internal/util/ByteUtils.java: ########## @@ -412,4 +413,23 @@ public static UUID bytesToUuid(byte[] bytes, int offset) { return new UUID(higher, lower); } + + /** + * Truncates a byte array to the size specified. + * + * @param bytes Origin byte array. + * @param maxLength Length of truncate. + * @return Truncated array. + */ + public static byte @Nullable [] trimToSize(byte[] bytes, int maxLength) { + if (bytes == null) { + return null; + } + + if (maxLength <= 0) { + return new byte[0]; Review Comment: ```suggestion return ArrayUtils.BYTE_EMPTY_ARRAY; ``` ########## modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTupleComparatorUtils.java: ########## @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.schema; + +import static java.lang.Integer.signum; +import static org.apache.ignite.internal.binarytuple.BinaryTupleCommon.EQUALITY_FLAG; +import static org.apache.ignite.internal.lang.IgniteStringFormatter.format; + +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.util.Arrays; +import org.apache.ignite.internal.binarytuple.BinaryTupleReader; +import org.apache.ignite.internal.type.NativeTypeSpec; + +/** + * The utility class has methods to use to compare fields in binary representation. + */ +class BinaryTupleComparatorUtils { + /** + * Compares individual fields of two tuples using ascending order. + */ + @SuppressWarnings("DataFlowIssue") + static int compareFieldValue(NativeTypeSpec typeSpec, BinaryTupleReader tuple1, int index1, BinaryTupleReader tuple2, int index2) { + switch (typeSpec) { + case INT8: + case BOOLEAN: + return Byte.compare(tuple1.byteValue(index1), tuple2.byteValue(index2)); + + case INT16: + return Short.compare(tuple1.shortValue(index1), tuple2.shortValue(index2)); + + case INT32: + return Integer.compare(tuple1.intValue(index1), tuple2.intValue(index2)); + + case INT64: + return Long.compare(tuple1.longValue(index1), tuple2.longValue(index2)); + + case FLOAT: + return Float.compare(tuple1.floatValue(index1), tuple2.floatValue(index2)); + + case DOUBLE: + return Double.compare(tuple1.doubleValue(index1), tuple2.doubleValue(index2)); + + case BYTES: + return Arrays.compareUnsigned(tuple1.bytesValue(index1), tuple2.bytesValue(index2)); + + case UUID: + return tuple1.uuidValue(index1).compareTo(tuple2.uuidValue(index2)); + + case STRING: + return tuple1.stringValue(index1).compareTo(tuple2.stringValue(index2)); + + case DECIMAL: + BigDecimal numeric1 = tuple1.decimalValue(index1, Integer.MIN_VALUE); + BigDecimal numeric2 = tuple2.decimalValue(index2, Integer.MIN_VALUE); + + return numeric1.compareTo(numeric2); + + case TIMESTAMP: + return tuple1.timestampValue(index1).compareTo(tuple2.timestampValue(index2)); + + case DATE: + return tuple1.dateValue(index1).compareTo(tuple2.dateValue(index2)); + + case TIME: + return tuple1.timeValue(index1).compareTo(tuple2.timeValue(index2)); + + case DATETIME: + return tuple1.dateTimeValue(index1).compareTo(tuple2.dateTimeValue(index2)); + + default: + throw new IllegalArgumentException(format("Unsupported column type in binary tuple comparator. [type={}]", typeSpec)); + } + } + + static boolean isFlagSet(ByteBuffer tuple, int flag) { + return (tuple.get(0) & flag) != 0; + } + + static int equalityFlag(ByteBuffer tuple) { + return isFlagSet(tuple, EQUALITY_FLAG) ? 1 : -1; + } + + /** + * Compares a value in a binary tuple, interpreted as a string, with a given string. + * The comparison can be performed as case-sensitive or case-insensitive. + * The method first attempts a fast comparison for ASCII sequences and falls back + * to Unicode comparison if non-ASCII characters are detected. + * + * @param tuple The BinaryTupleReader containing the tuple to be compared. + * @param colIndex The column index in the tuple to retrieve the value for comparison. + * @param cmp The string to compare the value in the tuple against. + * @param ignoreCase Flag indicating whether the comparison should ignore case differences. + * @return 0 if the strings are equal, a negative value if the tuple string is lexicographically + * less than the given string, or a positive value if it is greater. + */ + static int compareAsString(BinaryTupleReader tuple, int colIndex, String cmp, boolean ignoreCase) { + tuple.seek(colIndex); + int begin = tuple.begin(); + int end = tuple.end(); + + ByteBuffer buf = tuple.byteBuffer(); + int fullSrtLength = end - begin; + int trimmedSize = Math.min(fullSrtLength, buf.capacity() - begin); + byte[] bytes = new byte[trimmedSize]; + + buf.duplicate().position(begin).limit(begin + trimmedSize).get(bytes); + + char[] cmpArray = cmp.toCharArray(); Review Comment: I'm not really convinced that we need to copy these arrays, especially in case of `cmpArray`. I presume that version without copying was slower, is that the case? Please add some small comment -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@ignite.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org