@@ -246,6 +246,83 @@ class DecimalField {
246246 UInt32 scale;
247247};
248248
249+ // StringViewField wraps a StringView and provides deep copy semantics.
250+ // Since StringView is a non-owning view (only contains pointer and length),
251+ // we need to store the actual data in a String to ensure the Field owns the data.
252+ // This prevents dangling pointer issues when Field objects are copied or moved.
253+ class StringViewField {
254+ public:
255+ StringViewField () = default ;
256+ ~StringViewField () = default ;
257+
258+ // Construct from raw data - performs deep copy
259+ StringViewField (const char * data, size_t len) : _storage(data, len) {}
260+
261+ // Construct from StringView - performs deep copy
262+ StringViewField (const StringView& sv) : _storage(sv.data(), sv.size()) {}
263+
264+ // Copy constructor - deep copy
265+ StringViewField (const StringViewField& x) = default ;
266+
267+ // Move constructor
268+ StringViewField (StringViewField&& x) noexcept = default ;
269+
270+ // Copy assignment - deep copy
271+ StringViewField& operator =(const StringViewField& x) = default ;
272+
273+ // Move assignment
274+ StringViewField& operator =(StringViewField&& x) noexcept = default ;
275+
276+ // Access methods
277+ const char * data () const { return _storage.data (); }
278+ size_t size () const { return _storage.size (); }
279+ const String& get_string () const { return _storage; }
280+
281+ // Convert to StringView for compatibility
282+ StringView to_string_view () const { return {data (), static_cast <uint32_t >(size ())}; }
283+
284+ // Comparison operators - using binary comparison (memcmp) for VARBINARY semantics
285+ bool operator <(const StringViewField& r) const {
286+ int cmp = memcmp (_storage.data (), r._storage .data (),
287+ std::min (_storage.size (), r._storage .size ()));
288+ return cmp < 0 || (cmp == 0 && _storage.size () < r._storage .size ());
289+ }
290+ bool operator <=(const StringViewField& r) const { return !(r < *this ); }
291+ bool operator ==(const StringViewField& r) const {
292+ return _storage.size () == r._storage .size () &&
293+ memcmp (_storage.data (), r._storage .data (), _storage.size ()) == 0 ;
294+ }
295+ bool operator >(const StringViewField& r) const { return r < *this ; }
296+ bool operator >=(const StringViewField& r) const { return !(*this < r); }
297+ bool operator !=(const StringViewField& r) const { return !(*this == r); }
298+
299+ std::strong_ordering operator <=>(const StringViewField& r) const {
300+ size_t min_size = std::min (_storage.size (), r._storage .size ());
301+ int cmp = memcmp (_storage.data (), r._storage .data (), min_size);
302+ if (cmp < 0 ) {
303+ return std::strong_ordering::less;
304+ }
305+ if (cmp > 0 ) {
306+ return std::strong_ordering::greater;
307+ }
308+ // Prefixes are equal, compare lengths
309+ return _storage.size () <=> r._storage .size ();
310+ }
311+
312+ // Arithmetic operators (not commonly used but required by Field)
313+ const StringViewField& operator +=(const StringViewField& r) {
314+ _storage += r._storage ;
315+ return *this ;
316+ }
317+
318+ const StringViewField& operator -=(const StringViewField& r) {
319+ throw Exception (Status::FatalError (" Not support minus operation on StringViewField" ));
320+ }
321+
322+ private:
323+ String _storage; // Use String for deep copy and ownership
324+ };
325+
249326/* * 32 is enough. Round number is used for alignment and for better arithmetic inside std::vector.
250327 * NOTE: Actually, sizeof(std::string) is 32 when using libc++, so Field is 40 bytes.
251328 */
@@ -388,7 +465,7 @@ class Field {
388465 case PrimitiveType::TYPE_VARCHAR:
389466 return get<String>() <=> rhs.get <String>();
390467 case PrimitiveType::TYPE_VARBINARY:
391- return get<doris::StringView >() <=> rhs.get <doris::StringView >();
468+ return get<StringViewField >() <=> rhs.get <StringViewField >();
392469 case PrimitiveType::TYPE_DECIMAL32:
393470 return get<Decimal32>() <=> rhs.get <Decimal32>();
394471 case PrimitiveType::TYPE_DECIMAL64:
@@ -436,7 +513,7 @@ class Field {
436513 f (field.template get <String>());
437514 return ;
438515 case PrimitiveType::TYPE_VARBINARY:
439- f (field.template get <doris::StringView >());
516+ f (field.template get <StringViewField >());
440517 return ;
441518 case PrimitiveType::TYPE_JSONB:
442519 f (field.template get <JsonbField>());
@@ -487,11 +564,11 @@ class Field {
487564 std::string to_string () const ;
488565
489566private:
490- std::aligned_union_t <
491- DBMS_MIN_FIELD_SIZE - sizeof (PrimitiveType), Null, UInt64, UInt128, Int64, Int128, IPv6 ,
492- Float64, String, JsonbField, Array, Tuple, Map, VariantMap, DecimalField<Decimal32>,
493- DecimalField<Decimal64>, DecimalField<Decimal128V2>, DecimalField<Decimal128V3>,
494- DecimalField<Decimal256>, BitmapValue, HyperLogLog, QuantileState, doris::StringView >
567+ std::aligned_union_t <DBMS_MIN_FIELD_SIZE - sizeof (PrimitiveType), Null, UInt64, UInt128, Int64,
568+ Int128, IPv6, Float64, String, JsonbField, StringViewField, Array, Tuple ,
569+ Map, VariantMap, DecimalField<Decimal32>, DecimalField<Decimal64 >,
570+ DecimalField<Decimal128V2>, DecimalField<Decimal128V3>,
571+ DecimalField<Decimal256>, BitmapValue, HyperLogLog, QuantileState>
495572 storage;
496573
497574 PrimitiveType type;
@@ -645,6 +722,11 @@ struct NearestFieldTypeImpl<PackedInt128> {
645722 using Type = Int128;
646723};
647724
725+ template <>
726+ struct NearestFieldTypeImpl <doris::StringView> {
727+ using Type = StringViewField;
728+ };
729+
648730template <typename T>
649731decltype (auto ) cast_to_nearest_field_type(T&& x) {
650732 using U = NearestFieldType<std::decay_t <T>>;
0 commit comments