Changed-lines coverage: PR changed C/C++ lines covered by tests: 85.31% (1852/2171) Uncovered changed code (with context): ================================================================================ programs/client/FuzzLoop.cpp ================================================================================ --- uncovered block 171-171 --- 169 | if (orig_ast->as()) 170 | { >> 171 | return true; 172 | } 173 | --- uncovered block 178-184 --- 176 | || client_context->getSettingsRef()[Setting::dialect] == DB::Dialect::trino) 177 | { >> 178 | return true; 179 | } 180 | if (auto * q = orig_ast->as()) 181 | { >> 182 | if (auto * set_dialect = q->changes.tryGet("dialect"); >> 183 | set_dialect && (set_dialect->safeGet() == "kusto" || set_dialect->safeGet() == "trino")) >> 184 | return true; 185 | } 186 | ================================================================================ src/Client/LocalConnection.cpp ================================================================================ --- uncovered block 329-333 --- 327 | parser = std::make_unique(end, settings[Setting::allow_settings_after_format_in_insert]); 328 | else if (dialect == Dialect::prql) >> 329 | parser = std::make_unique(settings[Setting::max_query_size], settings[Setting::max_parser_depth], settings[Setting::max_parser_backtracks]); 330 | else if (dialect == Dialect::promql) >> 331 | parser = std::make_unique(settings[Setting::promql_database], settings[Setting::promql_table], Field{settings[Setting::promql_evaluation_time]}); 332 | else if (dialect == Dialect::trino) >> 333 | parser = std::make_unique(settings[Setting::max_query_size], settings[Setting::max_parser_depth], settings[Setting::max_parser_backtracks], end, settings[Setting::allow_experimental_trino_dialect]); 334 | else 335 | parser = std::make_unique(end, settings[Setting::allow_settings_after_format_in_insert], settings[Setting::implicit_select]); ================================================================================ src/Parsers/Trino/ParserTrinoQuery.cpp ================================================================================ --- uncovered block 97-99 --- 95 | if (!is_inline_data_tail && tokenIsKeyword(token, "FORMAT")) 96 | { >> 97 | Pos next = pos; >> 98 | ++next; >> 99 | is_inline_data_tail = next.isValid() && next->type == TokenType::BareWord; 100 | } 101 | if (is_inline_data_tail) --- uncovered block 114-125 --- 112 | 113 | if (!delegate_to_standard_parser && !pos->isEnd() && pos->type != TokenType::Semicolon) >> 114 | throw Exception( >> 115 | ErrorCodes::SYNTAX_ERROR, >> 116 | "Cannot tokenize the query in the Trino dialect: {} at position {}", >> 117 | getErrorTokenDescription(pos->type), >> 118 | pos->begin - begin + 1); 119 | 120 | if (tokens.empty()) >> 121 | return false; 122 | 123 | const size_t statement_size = static_cast(statement_end - begin); 124 | if (max_query_size && statement_size > max_query_size) >> 125 | throw Exception(ErrorCodes::SYNTAX_ERROR, "Query size {} exceeds max_query_size {}", statement_size, max_query_size); 126 | 127 | if (delegate_to_standard_parser) --- uncovered block 132-132 --- 130 | ParserQuery standard_parser(raw_end); 131 | if (!standard_parser.parse(pos, node, expected)) >> 132 | return false; 133 | mapTrinoFunctions(node); 134 | return true; --- uncovered block 161-161 --- 159 | true); 160 | if (!node) >> 161 | throw Exception(ErrorCodes::SYNTAX_ERROR, "{}", error_message); 162 | mapTrinoFunctions(node); 163 | return true; --- uncovered block 196-196 --- 194 | /// This is unreachable as long as such statements are delegated above. 195 | if (const auto * insert = node->as(); insert && insert->data) >> 196 | throw Exception(ErrorCodes::NOT_IMPLEMENTED, "INSERT with inline data is not supported in this form in the Trino dialect"); 197 | 198 | mapTrinoFunctions(node); ================================================================================ src/Parsers/Trino/TrinoFunctionMapper.cpp ================================================================================ --- uncovered block 67-67 --- 65 | { 66 | if (arguments.empty()) >> 67 | throwWrongArguments(function, "at least one argument"); 68 | ASTPtr lambda = arguments.back(); 69 | arguments.pop_back(); --- uncovered block 79-88 --- 77 | const auto * lambda = ast->as(); 78 | if (!lambda || lambda->name != "lambda" || !lambda->arguments || lambda->arguments->children.size() != 2) >> 79 | return false; 80 | const auto * tuple = lambda->arguments->children[0]->as(); 81 | if (!tuple || !tuple->arguments) >> 82 | return false; 83 | parameters.clear(); 84 | for (const auto & parameter : tuple->arguments->children) 85 | { 86 | const auto * identifier = parameter->as(); 87 | if (!identifier) >> 88 | return false; 89 | parameters.push_back(identifier->name()); 90 | } --- uncovered block 126-129 --- 124 | String name = Poco::toLower(function->name); 125 | if (name != "cast" && name != "accuratecastornull") >> 126 | return nullptr; 127 | const auto * type = function->arguments->children[1]->as(); 128 | if (!type || type->value.getType() != Field::Types::String || Poco::toUpper(type->value.safeGet()) != "JSON") >> 129 | return nullptr; 130 | return function->arguments->children[0]; 131 | } --- uncovered block 150-150 --- 148 | const String & path = literal->value.safeGet(); 149 | if (path.empty() || path[0] != '$') >> 150 | return false; 151 | 152 | parts.clear(); --- uncovered block 162-162 --- 160 | ++pos; 161 | if (pos == key_begin) >> 162 | return false; 163 | parts.push_back(make_intrusive(path.substr(key_begin, pos - key_begin))); 164 | } --- uncovered block 176-176 --- 174 | ++pos; 175 | if (pos + 1 >= path.size() || path[pos] != quote || path[pos + 1] != ']') >> 176 | return false; 177 | parts.push_back(make_intrusive(path.substr(key_begin, pos - key_begin))); 178 | pos += 2; --- uncovered block 192-192 --- 190 | } 191 | else >> 192 | return false; 193 | } 194 | return !parts.empty(); --- uncovered block 206-206 --- 204 | function.children.push_back(function.arguments); 205 | if (function.window_definition) >> 206 | function.children.push_back(function.window_definition); 207 | } 208 | --- uncovered block 215-221 --- 213 | if (!from.isWindowFunction()) 214 | return; >> 215 | auto * target = to->as(); >> 216 | target->setIsWindowFunction(true); >> 217 | target->window_name = from.window_name; >> 218 | if (from.window_definition) 219 | { >> 220 | target->window_definition = from.window_definition; >> 221 | target->children.push_back(target->window_definition); 222 | } 223 | } --- uncovered block 228-228 --- 226 | { 227 | if (function.isWindowFunction()) >> 228 | throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Trino function {} is not supported as a window function", function.name); 229 | } 230 | --- uncovered block 235-241 --- 233 | void replaceIdentifier(ASTPtr & ast, const String & name, const ASTPtr & replacement) 234 | { >> 235 | if (const auto * identifier = ast->as(); identifier && identifier->name() == name) 236 | { >> 237 | ast = replacement->clone(); >> 238 | return; 239 | } >> 240 | for (auto & child : ast->children) >> 241 | replaceIdentifier(child, name, replacement); 242 | } 243 | --- uncovered block 420-422 --- 418 | {"zip_with", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 419 | { >> 420 | requireArguments(function, arguments, 3, 3, "(array, array, function)"); >> 421 | moveLambdaToFront(function, arguments, "arrayMap"); >> 422 | }}, 423 | {"array_first", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 424 | { --- uncovered block 432-432 --- 430 | } 431 | else >> 432 | moveLambdaToFront(function, arguments, "arrayFirstOrNull"); 433 | }}, 434 | {"array_last", [](ASTPtr &, ASTFunction & function, ASTs & arguments) --- uncovered block 439-440 --- 437 | if (arguments.size() == 1) 438 | { >> 439 | function.name = "arrayElementOrNull"; >> 440 | arguments.push_back(make_intrusive(Int64(-1))); 441 | } 442 | else --- uncovered block 458-458 --- 456 | ASTPtr body; 457 | if (!tryGetLambda(arguments[3], parameters, body) || parameters.size() != 1) >> 458 | throwWrongArguments(function, "a one-argument output lambda"); 459 | ASTPtr fold = makeFunctionWithArguments("arrayFold", {arguments[2], arguments[0], arguments[1]}); 460 | if (const auto * body_identifier = body->as(); body_identifier && body_identifier->name() == parameters[0]) --- uncovered block 465-478 --- 463 | return; 464 | } >> 465 | ASTPtr result = body->clone(); >> 466 | replaceIdentifier(result, parameters[0], fold); >> 467 | node = result; >> 468 | }}, 469 | {"transform_keys", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 470 | { >> 471 | requireArguments(function, arguments, 2, 2, "(map, function)"); >> 472 | std::vector parameters; >> 473 | ASTPtr body; >> 474 | if (!tryGetLambda(arguments[1], parameters, body) || parameters.size() != 2) >> 475 | throwWrongArguments(function, "a two-argument lambda"); >> 476 | ASTPtr pair = makeFunctionWithArguments("tuple", {body, make_intrusive(parameters[1])}); >> 477 | node = makeFunctionWithArguments("mapApply", {makeLambda(parameters, pair), arguments[0]}); >> 478 | }}, 479 | {"transform_values", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 480 | { --- uncovered block 485-485 --- 483 | ASTPtr body; 484 | if (!tryGetLambda(arguments[1], parameters, body) || parameters.size() != 2) >> 485 | throwWrongArguments(function, "a two-argument lambda"); 486 | ASTPtr pair = makeFunctionWithArguments("tuple", {make_intrusive(parameters[0]), body}); 487 | node = makeFunctionWithArguments("mapApply", {makeLambda(parameters, pair), arguments[0]}); --- uncovered block 498-498 --- 496 | ASTPtr values; 497 | if (arguments.size() == 2) >> 498 | values = arguments[1]; /// The concat_ws(separator, array) form. 499 | else 500 | values = makeFunctionWithArguments("array", ASTs(arguments.begin() + 1, arguments.end())); --- uncovered block 524-527 --- 522 | {"split_to_map", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 523 | { >> 524 | requireArguments(function, arguments, 3, 3, "(string, entryDelimiter, keyValueDelimiter)"); >> 525 | function.name = "extractKeyValuePairs"; >> 526 | std::swap(arguments[1], arguments[2]); >> 527 | }}, 528 | {"strpos", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 529 | { --- uncovered block 548-551 --- 546 | const auto * identifier = arguments[1]->as(); 547 | if (!identifier) >> 548 | throwWrongArguments(function, "NFC, NFD, NFKC or NFKD as the normalization form"); 549 | form = Poco::toUpper(identifier->name()); 550 | if (form != "NFC" && form != "NFD" && form != "NFKC" && form != "NFKD") >> 551 | throwWrongArguments(function, "NFC, NFD, NFKC or NFKD as the normalization form"); 552 | arguments.pop_back(); 553 | } --- uncovered block 568-568 --- 566 | /// Trino log(b, x) = log_b(x); ClickHouse log is the natural logarithm. 567 | if (arguments.size() != 2) >> 568 | return; 569 | node = makeFunctionWithArguments( 570 | "divide", --- uncovered block 624-647 --- 622 | {"from_iso8601_timestamp", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 623 | { >> 624 | requireArguments(function, arguments, 1, 1, "(string)"); >> 625 | function.name = "parseDateTime64BestEffort"; >> 626 | arguments.push_back(make_intrusive(UInt64(3))); >> 627 | }}, 628 | {"from_iso8601_timestamp_nanos", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 629 | { >> 630 | requireArguments(function, arguments, 1, 1, "(string)"); >> 631 | function.name = "parseDateTime64BestEffort"; >> 632 | arguments.push_back(make_intrusive(UInt64(9))); >> 633 | }}, 634 | {"with_timezone", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 635 | { >> 636 | requireArguments(function, arguments, 2, 2, "(timestamp, zone)"); 637 | /// Reinterprets the wall-clock reading in the given zone. >> 638 | node = makeFunctionWithArguments( >> 639 | "toDateTime64", >> 640 | {makeFunctionWithArguments("toString", {arguments[0]}), make_intrusive(UInt64(3)), arguments[1]}); >> 641 | }}, 642 | {"to_iso8601", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 643 | { >> 644 | requireArguments(function, arguments, 1, 1, "(timestamp)"); >> 645 | function.name = "formatDateTime"; >> 646 | arguments.push_back(make_intrusive(String("%Y-%m-%dT%H:%i:%S"))); >> 647 | }}, 648 | {"timezone", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 649 | { --- uncovered block 655-656 --- 653 | if (arguments.size() != 1) 654 | return; >> 655 | function.name = "timezoneOf"; >> 656 | }}, 657 | {"current_timestamp", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 658 | { --- uncovered block 728-731 --- 726 | {"trim_array", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 727 | { >> 728 | requireArguments(function, arguments, 2, 2, "(array, count)"); >> 729 | ASTPtr new_size = makeFunctionWithArguments("minus", {makeFunctionWithArguments("length", {arguments[0]}), arguments[1]}); >> 730 | node = makeFunctionWithArguments("arrayResize", {arguments[0], new_size}); >> 731 | }}, 732 | 733 | /// Maps. --- uncovered block 803-803 --- 801 | } 802 | if (width < 2 || width > 64) >> 803 | throwWrongArguments(function, "a constant bit width between 2 and 64"); 804 | /// An arbitrary width counts the bits of the value truncated to the 805 | /// low `width` bits of its two's complement representation. --- uncovered block 817-844 --- 815 | {"xxhash64", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 816 | { >> 817 | requireArguments(function, arguments, 1, 1, "(binary)"); >> 818 | node = makeFunctionWithArguments( >> 819 | "reverse", {makeFunctionWithArguments("reinterpretAsFixedString", {makeFunctionWithArguments("xxHash64", {arguments[0]})})}); >> 820 | }}, 821 | {"hmac_md5", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 822 | { >> 823 | requireArguments(function, arguments, 2, 2, "(binary, key)"); >> 824 | function.name = "HMAC"; >> 825 | arguments.insert(arguments.begin(), make_intrusive(String("md5"))); >> 826 | }}, 827 | {"hmac_sha1", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 828 | { >> 829 | requireArguments(function, arguments, 2, 2, "(binary, key)"); >> 830 | function.name = "HMAC"; >> 831 | arguments.insert(arguments.begin(), make_intrusive(String("sha1"))); >> 832 | }}, 833 | {"hmac_sha256", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 834 | { >> 835 | requireArguments(function, arguments, 2, 2, "(binary, key)"); >> 836 | function.name = "HMAC"; >> 837 | arguments.insert(arguments.begin(), make_intrusive(String("sha256"))); >> 838 | }}, 839 | {"hmac_sha512", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 840 | { >> 841 | requireArguments(function, arguments, 2, 2, "(binary, key)"); >> 842 | function.name = "HMAC"; >> 843 | arguments.insert(arguments.begin(), make_intrusive(String("sha512"))); >> 844 | }}, 845 | {"from_big_endian_32", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 846 | { --- uncovered block 857-860 --- 855 | {"to_big_endian_32", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 856 | { >> 857 | requireArguments(function, arguments, 1, 1, "(integer)"); >> 858 | node = makeFunctionWithArguments( >> 859 | "reverse", {makeFunctionWithArguments("reinterpretAsFixedString", {makeFunctionWithArguments("toInt32", {arguments[0]})})}); >> 860 | }}, 861 | {"to_big_endian_64", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 862 | { --- uncovered block 906-915 --- 904 | {"regexp_extract_all", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 905 | { >> 906 | requireArguments(function, arguments, 2, 3, "(string, pattern[, group])"); >> 907 | if (arguments.size() == 2) 908 | { >> 909 | function.name = "extractAll"; >> 910 | return; 911 | } >> 912 | node = makeFunctionWithArguments( >> 913 | "arrayElement", >> 914 | {makeFunctionWithArguments("extractAllGroupsHorizontal", {arguments[0], arguments[1]}), arguments[2]}); >> 915 | }}, 916 | {"regexp_replace", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 917 | { --- uncovered block 1000-1003 --- 998 | {"json_value", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 999 | { >> 1000 | requireArguments(function, arguments, 2, 2, "(json, json_path)"); >> 1001 | unwrapJSONArgument(arguments); >> 1002 | function.name = "JSON_VALUE"; >> 1003 | }}, 1004 | {"json_query", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 1005 | { --- uncovered block 1043-1050 --- 1041 | const auto * index = arguments[1]->as(); 1042 | if (!index) >> 1043 | throwWrongArguments(function, "a constant index"); 1044 | ASTPtr translated_index; 1045 | if (index->value.getType() == Field::Types::UInt64) 1046 | translated_index = make_intrusive(index->value.safeGet() + 1); >> 1047 | else if (index->value.getType() == Field::Types::Int64 && index->value.safeGet() < 0) >> 1048 | translated_index = make_intrusive(index->value); 1049 | else >> 1050 | throwWrongArguments(function, "a constant index"); 1051 | node = makeFunctionWithArguments("JSONExtractRaw", {arguments[0], translated_index}); 1052 | }}, --- uncovered block 1085-1085 --- 1083 | const auto * value = arguments[1]->as(); 1084 | if (!value) >> 1085 | throwWrongArguments(function, "a constant scalar value"); 1086 | String element_type; 1087 | ASTPtr needle = arguments[1]; --- uncovered block 1102-1103 --- 1100 | needle = makeFunctionWithArguments("toFloat64", {needle}); 1101 | break; >> 1102 | default: >> 1103 | throwWrongArguments(function, "a constant scalar value"); 1104 | } 1105 | node = makeFunctionWithArguments( --- uncovered block 1144-1147 --- 1142 | {"checksum", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 1143 | { >> 1144 | requireNotWindow(function); >> 1145 | requireArguments(function, arguments, 1, 1, "(value)"); >> 1146 | node = makeFunctionWithArguments("groupBitXor", {makeFunctionWithArguments("sipHash64", {arguments[0]})}); >> 1147 | }}, 1148 | {"geometric_mean", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 1149 | { --- uncovered block 1206-1219 --- 1204 | {"regr_slope", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 1205 | { >> 1206 | requireNotWindow(function); >> 1207 | requireArguments(function, arguments, 2, 2, "(y, x)"); >> 1208 | node = makeFunctionWithArguments( >> 1209 | "tupleElement", >> 1210 | {makeFunctionWithArguments("simpleLinearRegression", {arguments[1], arguments[0]}), make_intrusive(UInt64(1))}); >> 1211 | }}, 1212 | {"regr_intercept", [](ASTPtr & node, ASTFunction & function, ASTs & arguments) 1213 | { >> 1214 | requireNotWindow(function); >> 1215 | requireArguments(function, arguments, 2, 2, "(y, x)"); >> 1216 | node = makeFunctionWithArguments( >> 1217 | "tupleElement", >> 1218 | {makeFunctionWithArguments("simpleLinearRegression", {arguments[1], arguments[0]}), make_intrusive(UInt64(2))}); >> 1219 | }}, 1220 | {"min", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 1221 | { --- uncovered block 1244-1246 --- 1242 | {"row", [](ASTPtr &, ASTFunction & function, ASTs & arguments) 1243 | { >> 1244 | function.name = "tuple"; >> 1245 | UNUSED(arguments); >> 1246 | }}, 1247 | }; 1248 | return rewriters; --- uncovered block 1273-1274 --- 1271 | if (name == "last_value") 1272 | { >> 1273 | function.name = "last_value_respect_nulls"; >> 1274 | return; 1275 | } 1276 | } --- uncovered block 1301-1314 --- 1299 | if (!function.arguments) 1300 | { >> 1301 | ASTs no_arguments; >> 1302 | it->second(node, function, no_arguments); 1303 | } 1304 | else 1305 | it->second(node, function, function.arguments->children); 1306 | 1307 | if (node.get() != original_node && !alias.empty()) >> 1308 | node->setAlias(alias); 1309 | } 1310 | 1311 | void visit(ASTPtr & node) 1312 | { 1313 | if (!node) >> 1314 | return; 1315 | 1316 | for (auto & child : node->children) ================================================================================ src/Parsers/Trino/TrinoSyntaxTranslator.cpp ================================================================================ --- uncovered block 196-196 --- 194 | } 195 | } >> 196 | return tokens.size(); 197 | } 198 | --- uncovered block 206-206 --- 204 | { 205 | while (idx < tokens.size() && tokens[idx].type == TokenType::OpeningRoundBracket) >> 206 | ++idx; 207 | if (idx >= tokens.size() || tokens[idx].type != TokenType::BareWord || !isTypeAt(idx + 1, TokenType::OpeningRoundBracket)) 208 | return false; --- uncovered block 233-233 --- 231 | const size_t close = findMatchingParen(open); 232 | if (close == tokens.size()) >> 233 | return false; 234 | /// The last top-level AS separates the expression from the type. 235 | size_t depth = 0; --- uncovered block 253-253 --- 251 | } 252 | >> 253 | return false; 254 | } 255 | --- uncovered block 358-360 --- 356 | if (token.type == TokenType::Comma && isKeywordAt(i + 1, "UNNEST") && isTypeAt(i + 2, TokenType::OpeningRoundBracket)) 357 | { >> 358 | ++i; >> 359 | translateUnnest(i, end_idx, UnnestKind::ArrayJoin); >> 360 | return; 361 | } 362 | --- uncovered block 372-372 --- 370 | { 371 | if (isKeywordAt(close + 3, "AS")) >> 372 | throwNotSupported(tokens[close + 1], "Row field expansion .* with column aliases", ""); 373 | changed = true; 374 | String inner = translateSubRange(i + 1, close, /*type_context=*/ false); --- uncovered block 395-395 --- 393 | return; 394 | } >> 395 | throwNotSupported(token, "Row field expansion with .*", "Parenthesize the expression: (expr).*"); 396 | } 397 | --- uncovered block 535-537 --- 533 | if (tokenIsKeyword(token, "JOIN") && isKeywordAt(i + 1, "UNNEST") && isTypeAt(i + 2, TokenType::OpeningRoundBracket)) 534 | { >> 535 | ++i; >> 536 | translateUnnest(i, end_idx, UnnestKind::ArrayJoin); >> 537 | return; 538 | } 539 | --- uncovered block 555-558 --- 553 | 554 | if (tokenIsKeyword(token, "UNNEST") && isTypeAt(i + 1, TokenType::OpeningRoundBracket)) >> 555 | throwNotSupported( >> 556 | token, >> 557 | "This form of UNNEST", >> 558 | "Only FROM UNNEST(...), [CROSS/INNER/LEFT] JOIN UNNEST(...) and comma-separated UNNEST(...) are translated."); 559 | 560 | /// OFFSET n [ROW|ROWS] [LIMIT m | FETCH ...] -> LIMIT m OFFSET n --- uncovered block 586-586 --- 584 | if (tokenIsKeyword(token, "VALUES") 585 | && (i == 0 || isKeywordAt(i - 1, "ALL") || isKeywordAt(i - 1, "DISTINCT") || isKeywordAt(i - 1, "UNION") >> 586 | || isKeywordAt(i - 1, "INTERSECT") || isKeywordAt(i - 1, "EXCEPT"))) 587 | { 588 | translateValuesStatement(i, end_idx); --- uncovered block 720-723 --- 718 | if (tokenIsKeyword(token, "AUTO") && i >= 2 && tokenIsKeyword(tokens[i - 1], "BY") && tokenIsKeyword(tokens[i - 2], "GROUP")) 719 | { >> 720 | changed = true; >> 721 | emitText("ALL"); >> 722 | ++i; >> 723 | return; 724 | } 725 | --- uncovered block 733-736 --- 731 | || isKeywordAt(i - 1, "DISTINCT"))) 732 | { >> 733 | changed = true; >> 734 | emitText("SELECT * FROM"); >> 735 | ++i; >> 736 | return; 737 | } 738 | --- uncovered block 778-781 --- 776 | if (i == 0 && tokenIsKeyword(token, "SET") && isKeywordAt(i + 1, "SESSION")) 777 | { >> 778 | changed = true; >> 779 | emitToken(token); >> 780 | i += 2; >> 781 | return; 782 | } 783 | --- uncovered block 794-794 --- 792 | const Token & literal = tokens[i + 1]; 793 | if (literal.size() < 2) >> 794 | return false; 795 | std::string_view text(literal.begin + 1, literal.size() - 2); 796 | --- uncovered block 817-820 --- 815 | } 816 | else >> 817 | return false; 818 | } 819 | if (digits == 0 || digits > 76) >> 820 | return false; 821 | 822 | changed = true; --- uncovered block 837-837 --- 835 | const Token & literal = tokens[i + 1]; 836 | if (literal.size() < 2) >> 837 | return false; 838 | String text(literal.begin + 1, literal.size() - 2); 839 | --- uncovered block 853-853 --- 851 | } 852 | if (parts.size() < 2 || parts.size() > 3 || text.contains('\'') || text.contains('\\')) >> 853 | return false; 854 | 855 | size_t scale = 0; --- uncovered block 863-864 --- 861 | if (std::count(parts[1].begin(), parts[1].end(), ':') == 1) 862 | { >> 863 | parts[1] += ":00"; >> 864 | added_seconds = true; 865 | } 866 | WARNING: Failed to get start time for [Print Uncovered Code] - start time and duration won't be set --- Coverage counts --- Lines : baseline 1,039,748/1,175,441 -> current 1,042,246/1,178,210 (delta +2,498 / +2,769) Functions : baseline 836,245/908,615 -> current 836,432/908,797 (delta +187 / +182) Branches : baseline 344,770/426,854 -> current 345,951/428,366 (delta +1,181 / +1,512)