| 256 | } |
| 257 | |
| 258 | static std::vector<UInt8> autoAssignNumberForEnum(const ASTPtr & arguments, bool allow_relative) |
| 259 | { |
| 260 | Int64 literal_child_assign_num = 1; |
| 261 | ASTs assign_number_child; |
| 262 | assign_number_child.reserve(arguments->children.size()); |
| 263 | /// Each rewritten element keeps a flag that tells `mergeEnumTypes` whether its assigned |
| 264 | /// number is a temporary relative placeholder or an explicit final value. |
| 265 | std::vector<UInt8> relative_flags; |
| 266 | if (allow_relative) |
| 267 | relative_flags.reserve(arguments->children.size()); |
| 268 | bool is_first_child = true; |
| 269 | size_t assign_count= 0; |
| 270 | bool leading_implicit = true; |
| 271 | |
| 272 | for (const ASTPtr & child : arguments->children) |
| 273 | { |
| 274 | if (child->as<ASTLiteral>()) |
| 275 | { |
| 276 | assign_count += !is_first_child; |
| 277 | /// Keep the addition signed and checked: Int64 + size_t would run unsigned (negative |
| 278 | /// base wraps to a huge UInt64), and a plain signed add overflows near Int64 max. |
| 279 | Int64 assign_num = 0; |
| 280 | if (common::addOverflow(literal_child_assign_num, static_cast<Int64>(assign_count), assign_num)) |
| 281 | throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, |
| 282 | "Auto-assigned value for Enum element overflows Int64 (base {} + offset {})", |
| 283 | literal_child_assign_num, assign_count); |
| 284 | ASTPtr func = makeASTOperator("equals", child, make_intrusive<ASTLiteral>(assign_num)); |
| 285 | assign_number_child.emplace_back(func); |
| 286 | if (allow_relative) |
| 287 | relative_flags.push_back(leading_implicit); |
| 288 | } |
| 289 | else if (child->as<ASTFunction>()) |
| 290 | { |
| 291 | if (is_first_child) |
| 292 | { |
| 293 | const auto literals = getEnumElementLiterals(child); |
| 294 | const auto * value_literal = literals.value_literal; |
| 295 | literal_child_assign_num = value_literal->value.safeGet<Int64>(); |
| 296 | } |
| 297 | assign_number_child.emplace_back(child); |
| 298 | if (allow_relative) |
| 299 | relative_flags.push_back(0); |
| 300 | leading_implicit = false; |
| 301 | } |
| 302 | else |
| 303 | throw Exception(ErrorCodes::UNEXPECTED_AST_STRUCTURE, |
| 304 | "Elements of Enum data type must be of form: " |
| 305 | "'name' = number or 'name', where name is string literal and number is an integer"); |
| 306 | |
| 307 | is_first_child = false; |
| 308 | } |
| 309 | |
| 310 | if (assign_count != 0 && assign_count != arguments->children.size() - 1) |
| 311 | throw Exception(ErrorCodes::UNEXPECTED_AST_STRUCTURE, |
| 312 | "All elements of Enum data type must be of form: " |
| 313 | "'name' = number or 'name', where name is string literal and number is an integer"); |
| 314 | |
| 315 | arguments->children = assign_number_child; |
no test coverage detected