| 849 | |
| 850 | template <typename T> |
| 851 | void SQLParser::parseWhereCondition(Tokenizer& parser, T&& firstArg, OpType op) { |
| 852 | std::optional<functions::FunctionVariant> function; |
| 853 | |
| 854 | auto tryToParseFunction = [&](const auto& name) { |
| 855 | if (auto tok = parser.PeekToken(); tok.Text() == "(") { |
| 856 | function.emplace(functions::Function::FromSQL(name, parser)); |
| 857 | } |
| 858 | }; |
| 859 | |
| 860 | if constexpr (std::is_constructible_v<std::string, T>) { |
| 861 | tryToParseFunction(firstArg); |
| 862 | } |
| 863 | |
| 864 | auto setWhereCondition = [this, &firstArg, &function](OpType op, CondType condition, VariantArray&& values) { |
| 865 | if (function.has_value()) { |
| 866 | query_.NextOp(op).Where(std::move(function.value()), condition, std::move(values)); |
| 867 | } else { |
| 868 | query_.NextOp(op).Where(std::forward<T>(firstArg), condition, std::move(values)); |
| 869 | } |
| 870 | }; |
| 871 | |
| 872 | // Operator |
| 873 | CondType condition{parseCondition(parser, op)}; |
| 874 | |
| 875 | // Value |
| 876 | if (ctx_.autocompleteMode) { |
| 877 | std::ignore = peekSqlToken(parser, WhereFieldValueSqlToken, false); |
| 878 | } |
| 879 | auto tok = parser.NextToken(); |
| 880 | if (iequals(tok.Text(), "null"sv) || iequals(tok.Text(), "empty"sv)) { |
| 881 | setWhereCondition(op, CondEmpty, VariantArray{}); |
| 882 | } else if (iequals(tok.Text(), "not"sv)) { |
| 883 | tok = peekSqlToken(parser, WhereFieldNegateValueSqlToken, false); |
| 884 | if (!iequals(tok.Text(), "null"sv) && !iequals(tok.Text(), "empty"sv)) { |
| 885 | const auto range = parser.Where(tok); |
| 886 | throw SqlParserError(range, "Expected NULL, but found '{}' in query, {}", tok.Text(), range); |
| 887 | } |
| 888 | setWhereCondition(op, CondAny, VariantArray{}); |
| 889 | tok = parser.NextToken(Tokenizer::Flags::NoFlags); |
| 890 | } else if (tok.Text() == "("sv) { |
| 891 | if constexpr (!std::is_same_v<T, Query>) { |
| 892 | if (iequals(peekSqlToken(parser, WhereFieldValueOrSubquerySqlToken, false).Text(), "select"sv) && |
| 893 | !isCondition(parser.PeekSecondToken().Text())) { |
| 894 | if (function.has_value()) { |
| 895 | query_.NextOp(op).Where(std::move(function.value()), condition, parseSubQuery(parser)); |
| 896 | } else { |
| 897 | query_.NextOp(op).Where(std::forward<T>(firstArg), condition, parseSubQuery(parser)); |
| 898 | } |
| 899 | return; |
| 900 | } |
| 901 | } |
| 902 | VariantArray values{parseValues(parser)}; |
| 903 | setWhereCondition(op, condition, std::move(values)); |
| 904 | } else if (tok.Type() != TokenName || iequals(tok.Text(), "true"sv) || iequals(tok.Text(), "false"sv)) { |
| 905 | setWhereCondition(op, condition, {Token2kv(tok, parser, CompositeAllowed_True, FieldAllowed_False, NullAllowed_True)}); |
| 906 | } else { |
| 907 | if constexpr (std::is_same_v<T, Query>) { |
| 908 | tryToParseFunction(tok.Text()); |
nothing calls this directly
no test coverage detected