// Copyright 2023 PingCAP, 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. #include #include #include namespace DB::ErrorCodes { extern const int LOGICAL_ERROR; } namespace TiDB { using DB::Field; /// Operations to be done on datum. /// Most generic one that does nothing. template struct DatumOp { static void unflatten(const Field &, std::optional &) {} static void flatten(const Field &, std::optional &) {} static bool overflow(const Field &, const ColumnInfo &) { return false; } }; /// Specialized for integer types less than 64 bit, checks overflow. template struct DatumOp< tp, typename std::enable_if::type> { static void unflatten(const Field &, std::optional &) {} static void flatten(const Field &, std::optional &) {} static bool overflow(const Field & field, const ColumnInfo & column_info) { if constexpr (tp == TypeTiny) return concreteOverflow(field, column_info); if constexpr (tp == TypeShort) return concreteOverflow(field, column_info); if constexpr (tp == TypeLong || tp == TypeInt24) return concreteOverflow(field, column_info); } private: template static inline bool concreteOverflow(const Field & field, const ColumnInfo & column_info) { if (column_info.hasUnsignedFlag()) // Unsigned checking by bitwise compare. return field.get() != ext::bit_cast(static_cast>(field.get())); else // Signed checking by arithmetical cast. return field.get() != static_cast(static_cast>(field.get())); } }; /// Specialized for Enum, using unflatten/flatten to transform UInt to Int back and forth. template struct DatumOp::type> { static void unflatten(const Field & orig, std::optional & copy) { copy = static_cast(orig.get()); } static void flatten(const Field & orig, std::optional & copy) { copy = static_cast(orig.get()); } static bool overflow(const Field &, const ColumnInfo &) { return false; } }; DatumFlat::DatumFlat(const DB::Field & field, TP tp) : DatumBase(field, tp) { if (orig.isNull()) return; switch (tp) { #ifdef M #error "Please undefine macro M first." #endif #define M(tt, v, cf, ct) \ case Type##tt: \ DatumOp::unflatten(orig, copy); \ break; COLUMN_TYPES(M) #undef M } } bool DatumFlat::invalidNull(const ColumnInfo & column_info) { return column_info.hasNotNullFlag() && orig.isNull(); } bool DatumFlat::overflow(const ColumnInfo & column_info) { if (orig.isNull()) return false; switch (tp) { #ifdef M #error "Please undefine macro M first." #endif #define M(tt, v, cf, ct) \ case Type##tt: \ return DatumOp::overflow(field(), column_info); COLUMN_TYPES(M) #undef M } throw DB::Exception("Shouldn't reach here", DB::ErrorCodes::LOGICAL_ERROR); } DatumBumpy::DatumBumpy(const DB::Field & field, TP tp) : DatumBase(field, tp) { if (orig.isNull()) return; switch (tp) { #ifdef M #error "Please undefine macro M first." #endif #define M(tt, v, cf, ct) \ case Type##tt: \ DatumOp::flatten(orig, copy); \ break; COLUMN_TYPES(M) #undef M } } }; // namespace TiDB