| 930 | |
| 931 | template <SQLParser::Nested nested> |
| 932 | void SQLParser::parseWhere(Tokenizer& parser, TokenizerRange whereLocation) { |
| 933 | auto tok = peekSqlToken(parser, nested == Nested::Yes ? NestedWhereFieldSqlToken : WhereFieldSqlToken, false); |
| 934 | |
| 935 | OpType nextOp = OpAnd; |
| 936 | if (iequals(tok.Text(), "not"sv)) { |
| 937 | nextOp = OpNot; |
| 938 | parser.SkipToken(); |
| 939 | } |
| 940 | int openBracketsCount = 0; |
| 941 | bool expectSecondLogicalOperand = false; |
| 942 | auto throwIfExpectSecondLogicalOperand = [&tok, &parser, &expectSecondLogicalOperand]() { |
| 943 | if (expectSecondLogicalOperand) { |
| 944 | const auto range = parser.Where(tok); |
| 945 | throw SqlParserError(range, "Expected second logical operand, but found '{}' in query '{}'", tok.Text(), range); |
| 946 | } |
| 947 | }; |
| 948 | while (!parser.End()) { |
| 949 | tok = peekSqlToken(parser, nested == Nested::Yes ? NestedWhereFieldSqlToken : WhereFieldSqlToken, false); |
| 950 | parser.SkipToken(Tokenizer::Flags::NoFlags); |
| 951 | while (tok.Type() == TokenName && iequals(tok.Text(), "equal_position"sv)) { |
| 952 | parseEqualPositions(parser); |
| 953 | tok = peekSqlToken(parser, nested == Nested::Yes ? NestedWhereFieldSqlToken : WhereFieldSqlToken, false); |
| 954 | parser.SkipToken(Tokenizer::Flags::NoFlags); |
| 955 | } |
| 956 | expectSecondLogicalOperand = false; |
| 957 | if (tok.Text() == "("sv) { |
| 958 | tok = peekSqlToken(parser, nested == Nested::Yes ? NestedWhereFieldSqlToken : WhereFieldOrSubquerySqlToken, false); |
| 959 | // isCondition(parser.peek_second_token().text() to distinguish the token type operator 'select' or field with name 'select' |
| 960 | if (nested == Nested::No && iequals(tok.Text(), "select"sv) && !isCondition(parser.PeekSecondToken().Text())) { |
| 961 | parseWhereCondition(parser, parseSubQuery(parser), nextOp); |
| 962 | nextOp = OpAnd; |
| 963 | } else { |
| 964 | if (nextOp != OpAnd && iequals(tok.Text(), "left"sv)) { |
| 965 | const auto range = parser.Where(tok); |
| 966 | throw SqlParserError(range, "Left join with {} operation, {}", OpTypeToStr(nextOp), range); |
| 967 | } |
| 968 | query_.NextOp(nextOp); |
| 969 | query_.OpenBracket(); |
| 970 | ++openBracketsCount; |
| 971 | if (iequals(tok.Text(), "not"sv)) { |
| 972 | nextOp = OpNot; |
| 973 | parser.SkipToken(); |
| 974 | } else { |
| 975 | nextOp = OpAnd; |
| 976 | } |
| 977 | continue; |
| 978 | } |
| 979 | } else if (tok.Type() == TokenName) { |
| 980 | const auto nextToken = parser.PeekToken(); |
| 981 | if (iequals(tok.Text(), "st_dwithin"sv) && nextToken.Text() == "("sv) { |
| 982 | parseDWithin(parser, nextOp); |
| 983 | } else if (iequals(tok.Text(), "knn"sv) && nextToken.Text() == "("sv) { |
| 984 | parseKnn(parser, nextOp); |
| 985 | } else if constexpr (nested == Nested::No) { |
| 986 | if (iequals(tok.Text(), "join"sv)) { |
| 987 | parseJoin(JoinType::LeftJoin, parser); |
| 988 | } else if (iequals(tok.Text(), "left"sv)) { |
| 989 | if (nextOp != OpAnd) { |
nothing calls this directly
no test coverage detected