|
21 | 21 | #include "paimon/common/memory/memory_slice_output.h" |
22 | 22 | #include "paimon/common/utils/date_time_utils.h" |
23 | 23 | #include "paimon/common/utils/field_type_utils.h" |
| 24 | +#include "paimon/common/utils/fields_comparator.h" |
24 | 25 | #include "paimon/common/utils/preconditions.h" |
25 | 26 | #include "paimon/data/decimal.h" |
26 | 27 | #include "paimon/data/timestamp.h" |
@@ -195,6 +196,66 @@ Result<Literal> KeySerializer::DeserializeKey(const MemorySlice& slice, |
195 | 196 |
|
196 | 197 | MemorySlice::SliceComparator KeySerializer::CreateComparator( |
197 | 198 | const std::shared_ptr<arrow::DataType>& type, const std::shared_ptr<MemoryPool>& pool) { |
| 199 | + // Fast paths for integer and string types: direct value comparison without Literal |
| 200 | + // deserialization, avoiding heap allocations entirely. |
| 201 | + switch (type->id()) { |
| 202 | + case arrow::Type::type::STRING: |
| 203 | + return [](const MemorySlice& a, const MemorySlice& b) -> Result<int32_t> { |
| 204 | + std::string_view sv_a = a.ReadStringView(); |
| 205 | + std::string_view sv_b = b.ReadStringView(); |
| 206 | + int32_t cmp = sv_a.compare(sv_b); |
| 207 | + return cmp == 0 ? 0 : (cmp > 0 ? 1 : -1); |
| 208 | + }; |
| 209 | + case arrow::Type::type::BOOL: |
| 210 | + case arrow::Type::type::INT8: |
| 211 | + return [](const MemorySlice& a, const MemorySlice& b) -> Result<int32_t> { |
| 212 | + int8_t va = a.ReadByte(0); |
| 213 | + int8_t vb = b.ReadByte(0); |
| 214 | + return (va < vb) ? -1 : (va > vb ? 1 : 0); |
| 215 | + }; |
| 216 | + case arrow::Type::type::INT16: |
| 217 | + return [](const MemorySlice& a, const MemorySlice& b) -> Result<int32_t> { |
| 218 | + int16_t va = a.ReadShort(0); |
| 219 | + int16_t vb = b.ReadShort(0); |
| 220 | + return (va < vb) ? -1 : (va > vb ? 1 : 0); |
| 221 | + }; |
| 222 | + case arrow::Type::type::INT32: |
| 223 | + case arrow::Type::type::DATE32: |
| 224 | + return [](const MemorySlice& a, const MemorySlice& b) -> Result<int32_t> { |
| 225 | + int32_t va = a.ReadInt(0); |
| 226 | + int32_t vb = b.ReadInt(0); |
| 227 | + return (va < vb) ? -1 : (va > vb ? 1 : 0); |
| 228 | + }; |
| 229 | + case arrow::Type::type::INT64: |
| 230 | + return [](const MemorySlice& a, const MemorySlice& b) -> Result<int32_t> { |
| 231 | + int64_t va = a.ReadLong(0); |
| 232 | + int64_t vb = b.ReadLong(0); |
| 233 | + return (va < vb) ? -1 : (va > vb ? 1 : 0); |
| 234 | + }; |
| 235 | + case arrow::Type::type::FLOAT: |
| 236 | + return [](const MemorySlice& a, const MemorySlice& b) -> Result<int32_t> { |
| 237 | + int32_t ia = a.ReadInt(0); |
| 238 | + int32_t ib = b.ReadInt(0); |
| 239 | + float fa, fb; |
| 240 | + memcpy(&fa, &ia, sizeof(float)); |
| 241 | + memcpy(&fb, &ib, sizeof(float)); |
| 242 | + return FieldsComparator::CompareFloatingPoint(fa, fb); |
| 243 | + }; |
| 244 | + case arrow::Type::type::DOUBLE: |
| 245 | + return [](const MemorySlice& a, const MemorySlice& b) -> Result<int32_t> { |
| 246 | + int64_t ia = a.ReadLong(0); |
| 247 | + int64_t ib = b.ReadLong(0); |
| 248 | + double da, db; |
| 249 | + memcpy(&da, &ia, sizeof(double)); |
| 250 | + memcpy(&db, &ib, sizeof(double)); |
| 251 | + return FieldsComparator::CompareFloatingPoint(da, db); |
| 252 | + }; |
| 253 | + default: |
| 254 | + break; |
| 255 | + } |
| 256 | + |
| 257 | + // Fallback for complex types (TIMESTAMP, DECIMAL, etc.): |
| 258 | + // deserialize to Literal and compare. |
198 | 259 | return |
199 | 260 | [pool = pool, type = type](const MemorySlice& a, const MemorySlice& b) -> Result<int32_t> { |
200 | 261 | PAIMON_ASSIGN_OR_RAISE(Literal la, DeserializeKey(a, type, pool.get())); |
|
0 commit comments