X7ROOT File Manager
Current Path:
/opt/hc_python/lib/python3.12/site-packages/mysqlx
opt
/
hc_python
/
lib
/
python3.12
/
site-packages
/
mysqlx
/
??
..
??
__init__.py
(8.76 KB)
??
__pycache__
??
authentication.py
(2.47 KB)
??
charsets.py
(12.04 KB)
??
compat.py
(1.85 KB)
??
connection.py
(16.16 KB)
??
constants.py
(1.82 KB)
??
crud.py
(16.72 KB)
??
dbdoc.py
(2.12 KB)
??
errorcode.py
(38.7 KB)
??
errors.py
(8.69 KB)
??
expr.py
(30.22 KB)
??
expr_unparser.py
(4.54 KB)
??
locales
??
protobuf
??
protocol.py
(15.74 KB)
??
result.py
(23.04 KB)
??
statement.py
(47.08 KB)
Editing: expr.py
# MySQL Connector/Python - MySQL driver written in Python. # Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most # MySQL Connectors. There are special exceptions to the terms and # conditions of the GPLv2 as it is applied to this software, see the # FOSS License Exception # <http://www.mysql.com/about/legal/licensing/foss-exception.html>. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA from .compat import STRING_TYPES, PY3 from .protobuf.mysqlx_datatypes_pb2 import Scalar from .protobuf.mysqlx_expr_pb2 import ColumnIdentifier, DocumentPathItem, Expr from .protobuf.mysqlx_crud_pb2 import Column, Order, Projection if PY3: xrange = range class TokenType: NOT = 1 AND = 2 OR = 3 XOR = 4 IS = 5 LPAREN = 6 RPAREN = 7 LSQBRACKET = 8 RSQBRACKET = 9 BETWEEN = 10 TRUE = 11 NULL = 12 FALSE = 13 IN = 14 LIKE = 15 INTERVAL = 16 REGEXP = 17 ESCAPE = 18 IDENT = 19 LSTRING = 20 LNUM = 21 DOT = 22 DOLLAR = 23 COMMA = 24 EQ = 25 NE = 26 GT = 27 GE = 28 LT = 29 LE = 30 BITAND = 31 BITOR = 32 BITXOR = 33 LSHIFT = 34 RSHIFT = 35 PLUS = 36 MINUS = 37 MUL = 38 DIV = 39 HEX = 40 BIN = 41 NEG = 42 BANG = 43 MICROSECOND = 44 SECOND = 45 MINUTE = 46 HOUR = 47 DAY = 48 WEEK = 49 MONTH = 50 QUARTER = 51 YEAR = 52 EROTEME = 53 DOUBLESTAR = 54 MOD = 55 COLON = 56 OROR = 57 ANDAND = 58 LCURLY = 59 RCURLY = 60 CAST = 61 DOTSTAR = 62 ORDERBY_ASC = 63 ORDERBY_DESC = 64 AS = 65 interval_units = set([ TokenType.MICROSECOND, TokenType.SECOND, TokenType.MINUTE, TokenType.HOUR, TokenType.DAY, TokenType.WEEK, TokenType.MONTH, TokenType.QUARTER, TokenType.YEAR]) # map of reserved word to token type reservedWords = { "and": TokenType.AND, "or": TokenType.OR, "xor": TokenType.XOR, "is": TokenType.IS, "not": TokenType.NOT, "like": TokenType.LIKE, "in": TokenType.IN, "regexp": TokenType.REGEXP, "between": TokenType.BETWEEN, "interval": TokenType.INTERVAL, "escape": TokenType.ESCAPE, "cast": TokenType.CAST, "div": TokenType.DIV, "hex": TokenType.HEX, "bin": TokenType.BIN, "true": TokenType.TRUE, "false": TokenType.FALSE, "null": TokenType.NULL, "second": TokenType.SECOND, "minute": TokenType.MINUTE, "hour": TokenType.HOUR, "day": TokenType.DAY, "week": TokenType.WEEK, "month": TokenType.MONTH, "quarter": TokenType.QUARTER, "year": TokenType.YEAR, "microsecond": TokenType.MICROSECOND, "asc": TokenType.ORDERBY_ASC, "desc": TokenType.ORDERBY_DESC, "as": TokenType.AS } class Token: def __init__(self, type, val, len=1): self.type = type self.val = val self.len = len def __repr__(self): return self.__str__() def __str__(self): if self.type == TokenType.IDENT or self.type == TokenType.LNUM or \ self.type == TokenType.LSTRING: return str(self.type) + "(" + self.val + ")" else: return str(self.type) # static protobuf helper functions def build_null_scalar(): return Scalar(type=Scalar.V_NULL) def build_double_scalar(d): return Scalar(type=Scalar.V_DOUBLE, v_double=d) def build_int_scalar(i): return Scalar(type=Scalar.V_SINT, v_signed_int=i) def build_string_scalar(s): if isinstance(s, STRING_TYPES): s = bytes(bytearray(s, "utf-8")) return Scalar(type=Scalar.V_STRING, v_string=Scalar.String(value=s)) def build_bool_scalar(b): s = Scalar() s.type = Scalar.V_BOOL s.v_bool = b return s def build_literal_expr(anyval): e = Expr() e.type = Expr.LITERAL e.literal.CopyFrom(anyval) return e def build_unary_op(name, param): e = Expr() e.type = Expr.OPERATOR e.operator.name = name e.operator.param.add().CopyFrom(param) return e def escape_literal(string): return string.replace('"', '""') class ExprParser: def __init__(self, string, allowRelational): self.string = string self.tokens = [] self.pos = 0 self._allowRelationalColumns = allowRelational self.placeholder_name_to_position = {} self.positional_placeholder_count = 0 self.lex() # convencience checker for lexer def next_char_is(self, i, c): return i + 1 < len(self.string) and self.string[i + 1] == c def lex_number(self, pos): # numeric literal start = pos found_dot = False while pos < len(self.string) and (self.string[pos].isdigit() or self.string[pos] == "."): if self.string[pos] == ".": if found_dot is True: raise ValueError("Invalid number. Found multiple '.'") found_dot = True # technically we allow more than one "." and let float()'s parsing # complain later pos = pos + 1 val = self.string[start:pos] t = Token(TokenType.LNUM, val, len(val)) return t def lex_alpha(self, i): start = i while i < len(self.string) and (self.string[i].isalnum() or self.string[i] == "_"): i = i + 1 val = self.string[start:i] try: token = Token(reservedWords[val.lower()], val.upper(), len(val)) except KeyError: token = Token(TokenType.IDENT, val, len(val)) return token def lex_quoted_token(self, i): quote_char = self.string[i] val = "" i += 1 start = i while i < len(self.string): c = self.string[i] if c == quote_char and i + 1 < len(self.string) and \ self.string[i + 1] != quote_char: # break if we have a quote char that's not double break elif c == quote_char or c == "\\": # this quote char has to be doubled if i + 1 >= len(self.string): break i = i + 1 val = val + self.string[i] else: val = val + c i = i + 1 if i >= len(self.string) or self.string[i] != quote_char: raise ValueError("Unterminated quoted string starting at {0}" "".format(start)) if quote_char == "`": return Token(TokenType.IDENT, val, len(val)+2) else: return Token(TokenType.LSTRING, val, len(val)+2) def lex(self): i = 0 while i < len(self.string): c = self.string[i] if c.isspace(): i += 1 continue elif c.isdigit(): token = self.lex_number(i) elif c.isalpha() or c == "_": token = self.lex_alpha(i) elif c == "?": token = Token(TokenType.EROTEME, c) elif c == ":": token = Token(TokenType.COLON, c) elif c == "{": token = Token(TokenType.LCURLY, c) elif c == "}": token = Token(TokenType.RCURLY, c) elif c == "+": token = Token(TokenType.PLUS, c) elif c == "-": Token(TokenType.MINUS, c) elif c == "*": if self.next_char_is(i, "*"): token = Token(TokenType.DOUBLESTAR, "**") else: token = Token(TokenType.MUL, c) elif c == "/": token = Token(TokenType.DIV, c) elif c == "$": token = Token(TokenType.DOLLAR, c) elif c == "%": token = Token(TokenType.MOD, c) elif c == "=": if self.next_char_is(i, "="): token = Token(TokenType.EQ, "==", 2) else: token = Token(TokenType.EQ, "==", 1) elif c == "&": if self.next_char_is(i, "&"): token = Token(TokenType.ANDAND, c) else: token = Token(TokenType.BITAND, c) elif c == "|": if self.next_char_is(i, "|"): token = Token(TokenType.OROR, "||") else: token = Token(TokenType.BITOR, c) elif c == "(": token = Token(TokenType.LPAREN, c) elif c == ")": token = Token(TokenType.RPAREN, c) elif c == "[": token = Token(TokenType.LSQBRACKET, c) elif c == "]": token = Token(TokenType.RSQBRACKET, c) elif c == "~": token = Token(TokenType.NEG, c) elif c == ",": token = Token(TokenType.COMMA, c) elif c == "!": if self.next_char_is(i, "="): token = Token(TokenType.NE, "!=") else: token = Token(TokenType.BANG, c) elif c == "<": if self.next_char_is(i, "<"): token = Token(TokenType.LSHIFT, "<<") elif self.next_char_is(i, "="): token = Token(TokenType.LE, "<=") else: token = Token(TokenType.LT, c) elif c == ">": if self.next_char_is(i, ">"): token = Token(TokenType.RSHIFT, ">>") elif self.next_char_is(i, "="): token = Token(TokenType.GE, ">=") else: token = Token(TokenType.GT, c) elif c == ".": if self.next_char_is(i, "*"): token = Token(TokenType.DOTSTAR, ".*") elif i + 1 < len(self.string) and self.string[i + 1].isdigit(): token = self.lex_number(i) else: token = Token(TokenType.DOT, c) elif c == '"' or c == "'" or c == "`": token = self.lex_quoted_token(i) else: raise ValueError("Unknown character at {0}".format(i)) self.tokens.append(token) i += token.len def assert_cur_token(self, type): if self.pos >= len(self.tokens): raise ValueError("Expected token type {0} at pos {1} but no " "tokens left".format(type, self.pos)) if self.tokens[self.pos].type != type: raise ValueError("Expected token type {0} at pos {1} but found " "type {2}".format(type, self.pos, self.tokens[self.pos])) def cur_token_type_is(self, type): return self.pos_token_type_is(self.pos, type) def next_token_type_is(self, type): return self.pos_token_type_is(self.pos + 1, type) def pos_token_type_is(self, pos, type): return pos < len(self.tokens) and self.tokens[pos].type == type def consume_token(self, type): self.assert_cur_token(type) v = self.tokens[self.pos].val self.pos = self.pos + 1 return v def paren_expr_list(self): """Parse a paren-bounded expression list for function arguments or IN list and return a list of Expr objects. """ exprs = [] self.consume_token(TokenType.LPAREN) if not self.cur_token_type_is(TokenType.RPAREN): exprs.append(self.expr()) while self.cur_token_type_is(TokenType.COMMA): self.pos = self.pos + 1 exprs.append(self.expr()) self.consume_token(TokenType.RPAREN) return exprs def identifier(self): self.assert_cur_token(TokenType.IDENT) id = Identifier() if self.next_token_type_is(TokenType.DOT): id.schema_name = self.consume_token(TokenType.IDENT) self.consume_token(TokenType.DOT) id.name = self.tokens[self.pos].val self.pos = self.pos + 1 return id def function_call(self): e = Expr() e.type = Expr.FUNC_CALL e.function_call.name.CopyFrom(self.identifier()) e.function_call.param.extend(self.paren_expr_list()) return e def docpath_member(self): self.consume_token(TokenType.DOT) token = self.tokens[self.pos] if token.type == TokenType.IDENT: if token.val.startswith('`') and token.val.endswith('`'): raise ValueError("{0} is not a valid JSON/ECMAScript " "identifier".format(token.value)) self.consume_token(TokenType.IDENT) memberName = token.val elif self.token.type == TokenType.LSTRING: self.consume_token(TokenType.LSTRING) memberName = token.val else: raise ValueError("Expected token type IDENT or LSTRING in JSON " "path at token pos {0}".format(self.pos)) item = DocumentPathItem(type=DocumentPathItem.MEMBER, value=memberName) return item def docpath_array_loc(self): self.consume_token(TokenType.LSQBRACKET) if self.cur_token_type_is(TokenType.MUL): self.consume_token(TokenType.RSQBRACKET) return DocumentPathItem(type=DocumentPathItem.ARRAY_INDEX_ASTERISK) elif self.cur_token_type_is(TokenType.LNUM): v = int(self.consume_token(TokenType.LNUM)) if v < 0: raise IndexError("Array index cannot be negative at {0}" "".format(self.pos)) self.consume_token(TokenType.RSQBRACKET) return DocumentPathItem(type=DocumentPathItem.ARRAY_INDEX, index=v) else: raise ValueError("Exception token type MUL or LNUM in JSON " "path array index at token pos {0}" "".format(self.pos)) def document_field(self): col = ColumnIdentifier() if self.cur_token_type_is(TokenType.IDENT): col.document_path.extend([ DocumentPathItem(type=DocumentPathItem.MEMBER, value=self.consume_token(TokenType.IDENT))]) col.document_path.extend(self.document_path()) return Expr(type=Expr.IDENT, identifier=col) def document_path(self): """Parse a JSON-style document path, like WL#7909, but prefix by @. instead of $. We parse this as a string because the protocol doesn't support it. (yet) """ docpath = [] while True: if self.cur_token_type_is(TokenType.DOT): docpath.append(self.docpath_member()) elif self.cur_token_type_is(TokenType.DOTSTAR): self.consume_token(TokenType.DOTSTAR) docpath.append(DocumentPathItem( type=DocumentPathItem.MEMBER_ASTERISK)) elif self.cur_token_type_is(TokenType.LSQBRACKET): docpath.append(self.docpath_array_loc()) elif self.cur_token_type_is(TokenType.DOUBLESTAR): self.consume_token(TokenType.DOUBLESTAR) docpath.append(DocumentPathItem( type=DocumentPathItem.DOUBLE_ASTERISK)) else: break items = len(docpath) if items > 0 and docpath[items-1].type == \ DocumentPathItem.DOUBLE_ASTERISK: raise ValueError("JSON path may not end in '**' at {0}" "".format(self.pos)) return docpath def column_identifier(self): parts = [] parts.append(self.consume_token(TokenType.IDENT)) while self.cur_token_type_is(TokenType.DOT): self.consume_token(TokenType.DOT) parts.append(self.consume_token(TokenType.IDENT)) if len(parts) > 3: raise ValueError("Too many parts to identifier at {0}" "".format(self.pos)) parts.reverse() colid = ColumnIdentifier() # clever way to apply them to the struct for i in xrange(0, len(parts)): if i == 0: colid.name = parts[0] elif i == 1: colid.table_name = parts[1] elif i == 2: colid.schema_name = parts[2] if self.cur_token_type_is(TokenType.DOLLAR): self.consume_token(TokenType.DOLLAR) colid.document_path = self.document_path() e = Expr() e.type = Expr.IDENT e.identifier.CopyFrom(colid) return e def next_token(self): if (self.pos >= len(self.tokens)): raise ValueError("Unexpected end of token stream") t = self.tokens[self.pos] self.pos += 1 return t def expect_token(self, token_type): t = self.next_token() if t.type != token_type: raise ValueError("Expected token type {0}".format(token_type)) def parse_json_doc(self): o = Object() def parse_place_holder(self, token): place_holder_name = "" if self.cur_token_type_is(TokenType.LNUM): place_holder_name = self.consume_token(TokenType.LNUM_INT) elif self.cur_token_type_is(TokenType.IDENT): place_holder_name = self.consume_token(TokenType.IDENT) elif token.type == TokenType.EROTEME: place_holder_name = str(self.positional_placeholder_count) else: raise ValueError("Invalid placeholder name at token pos {0}" "".format(self.pos)) place_holder_name = place_holder_name.lower() expr = Expr(type=Expr.PLACEHOLDER) if place_holder_name in self.placeholder_name_to_position: expr.position = \ self.placeholder_name_to_position[place_holder_name] else: expr.position = self.positional_placeholder_count self.placeholder_name_to_position[place_holder_name] = \ self.positional_placeholder_count self.positional_placeholder_count += 1 return expr def atomic_expr(self): """Parse an atomic expression and return a protobuf Expr object""" token = self.next_token() if token.type in [TokenType.EROTEME, TokenType.COLON]: return self.parse_place_holder(token) elif token.type == TokenType.LCURLY: return self.parse_json_doc() elif token.type == TokenType.CAST: # TODO implement pass pass elif token.type == TokenType.LPAREN: e = self.expr() self.expect_token(TokenType.RPAREN) return e elif token.type in [TokenType.PLUS, TokenType.MINUS]: pass elif token.type in [TokenType.PLUS, TokenType.MINUS]: peek = self.peek_token() if peek.type == TokenType.LNUM: self.tokens[self.pos].val = token.val + peek.val return self.atomic_expr() return build_unary_op(token.val, self.atomic_expr()) elif token.type in [TokenType.NOT, TokenType.NEG, TokenType.BANG]: return build_unary_op(token.val, self.atomic_expr()) elif token.type == TokenType.LSTRING: return build_literal_expr(build_string_scalar(token.val)) elif token.type == TokenType.NULL: return build_literal_expr(build_null_scalar()) elif token.type == TokenType.LNUM: if "." in token.val: return build_literal_expr( build_double_scalar(float(token.val))) else: return build_literal_expr(build_int_scalar(int(token.val))) elif token.type in [TokenType.TRUE, TokenType.FALSE]: return build_literal_expr( build_bool_scalar(token.type == TokenType.TRUE)) elif token.type == TokenType.DOLLAR: return self.document_field() elif token.type == TokenType.MUL: return self.starOperator() elif token.type == TokenType.IDENT: self.pos = self.pos - 1 # stay on the identifier if self.next_token_type_is(TokenType.LPAREN) or \ (self.next_token_type_is(TokenType.DOT) and self.pos_token_type_is(self.pos + 2, TokenType.IDENT) and self.pos_token_type_is(self.pos + 3, TokenType.LPAREN)): # Function call return self.function_call() else: return (self.document_field() if not self._allowRelationalColumns else self.column_identifier()) # if t.type == TokenType.EROTEME: # return build_literal_expr(build_string_scalar("?")) # elif t.type == TokenType.INTERVAL: # e = Expr() # e.type = Expr.OPERATOR # e.operator.name = "INTERVAL" # e.operator.param.add().CopyFrom(self.expr()) # # validate the interval units # if self.pos < len(self.tokens) and self.tokens[self.pos].type in interval_units: # pass # else: # raise StandardError("Expected interval units at " + str(self.pos)) # e.operator.param.add().CopyFrom(build_literal_expr(build_string_scalar(self.tokens[self.pos].val))) # self.pos = self.pos + 1 # return e raise ValueError("Unknown token type = {0} when expecting atomic " "expression at {1}".format(token.type, self.pos)) def parse_left_assoc_binary_op_expr(self, types, inner_parser): """Given a `set' of types and an Expr-returning inner parser function, parse a left associate binary operator expression""" lhs = inner_parser() while (self.pos < len(self.tokens) and self.tokens[self.pos].type in types): e = Expr() e.type = Expr.OPERATOR e.operator.name = self.tokens[self.pos].val e.operator.param.add().CopyFrom(lhs) self.pos = self.pos + 1 e.operator.param.add().CopyFrom(inner_parser()) lhs = e return lhs # operator precedence is implemented here def mul_div_expr(self): return self.parse_left_assoc_binary_op_expr( set([TokenType.MUL, TokenType.DIV, TokenType.MOD]), self.atomic_expr) def add_sub_expr(self): return self.parse_left_assoc_binary_op_expr( set([TokenType.PLUS, TokenType.MINUS]), self.mul_div_expr) def shift_expr(self): return self.parse_left_assoc_binary_op_expr( set([TokenType.LSHIFT, TokenType.RSHIFT]), self.add_sub_expr) def bit_expr(self): return self.parse_left_assoc_binary_op_expr( set([TokenType.BITAND, TokenType.BITOR, TokenType.BITXOR]), self.shift_expr) def comp_expr(self): return self.parse_left_assoc_binary_op_expr( set([TokenType.GE, TokenType.GT, TokenType.LE, TokenType.LT, TokenType.EQ, TokenType.NE]), self.bit_expr) def ilri_expr(self): lhs = self.comp_expr() is_not = False if self.cur_token_type_is(TokenType.NOT): is_not = True self.consume_token(TokenType.NOT) if self.pos < len(self.tokens): params = [lhs] op_name = self.tokens[self.pos].val if self.cur_token_type_is(TokenType.IS): self.consume_token(TokenType.IS) # for IS, NOT comes AFTER if self.cur_token_type_is(TokenType.NOT): is_not = True self.consume_token(TokenType.NOT) params.append(self.comp_expr()) elif self.cur_token_type_is(TokenType.IN): self.consume_token(TokenType.IN) params.extend(self.paren_expr_list()) elif self.cur_token_type_is(TokenType.LIKE): self.consume_token(TokenType.LIKE) params.append(self.comp_expr()) if self.cur_token_type_is(TokenType.ESCAPE): self.consume_token(TokenType.ESCAPE) params.append(self.comp_expr()) elif self.cur_token_type_is(TokenType.BETWEEN): self.consume_token(TokenType.BETWEEN) params.append(self.comp_expr()) self.consume_token(TokenType.AND) params.append(self.comp_expr()) elif self.cur_token_type_is(TokenType.REGEXP): self.consume_token(TokenType.REGEXP) params.append(self.comp_expr()) else: if is_not: raise ValueError("Unknown token after NOT as pos {0}" "".format(self.pos)) op_name = None # not an operator we're interested in if op_name: e = Expr() e.type = Expr.OPERATOR e.operator.name = op_name e.operator.param.extend(params) if is_not: # wrap if `NOT'-prefixed e = build_unary_op("NOT", e) lhs = e return lhs def and_expr(self): return self.parse_left_assoc_binary_op_expr( set([TokenType.AND, TokenType.ANDAND]), self.ilri_expr) def or_expr(self): return self.parse_left_assoc_binary_op_expr( set([TokenType.OR, TokenType.OROR]), self.and_expr) def expr(self): return self.or_expr() def parse_table_insert_field(self): return Column(name=self.consume_token(TokenType.IDENT)) def parse_table_update_field(self): return self.column_identifier().identifier def parse_table_select_projection(self): project_expr = [] first = True while self.pos < len(self.tokens): if not first: self.consume_token(TokenType.COMMA) first = False projection = Projection(source=self.expr()) if self.cur_token_type_is(TokenType.AS): self.consume_token(TokenType.AS) projection.alias = self.consume_token(TokenType.IDENT) else: self.pos -= 1 projection.alias = self.consume_token(TokenType.IDENT) project_expr.append(projection) return project_expr def parse_order_spec(self): order_specs = [] first = True while self.pos < len(self.tokens): if not first: self.consume_token(TokenType.COMMA) first = False order = Order(expr=self.expr()) if self.cur_token_type_is(TokenType.ORDERBY_ASC): order.direction = Order.ASC self.consume_token(TokenType.ORDERBY_ASC) elif self.cur_token_type_is(TokenType.ORDERBY_DESC): order.direction = Order.DESC self.consume_token(TokenType.ORDERBY_DESC) order_specs.append(order) return order_specs def parse_expr_list(self): expr_list = [] first = True while self.pos < len(self.tokens): if not first: self.consume_token(TokenType.COMMA) first = False expr_list.append(self.expr()) return expr_list def parseAndPrintExpr(expr_string, allowRelational=True): print(">>>>>>> parsing: {0}".format(expr_string)) p = ExprParser(expr_string, allowRelational) print(p.tokens) e = p.expr() print(e) def x_test(): parseAndPrintExpr("name like :name") return parseAndPrintExpr("10+1") parseAndPrintExpr("(abc == 1)") parseAndPrintExpr("(func(abc)=1)") parseAndPrintExpr("(abc = \"jess\")") parseAndPrintExpr("(abc = \"with \\\"\")") parseAndPrintExpr("(abc != .10)") parseAndPrintExpr("(abc != \"xyz\")") parseAndPrintExpr("a + b * c + d") parseAndPrintExpr("(a + b) * c + d") parseAndPrintExpr("(field not in ('a',func('b', 2.0),'c'))") parseAndPrintExpr("jess.age between 30 and death") parseAndPrintExpr("a + b * c + d") parseAndPrintExpr("x > 10 and Y >= -20") parseAndPrintExpr("a is true and b is null and C + 1 > 40 and " "(time = now() or hungry())") parseAndPrintExpr("a + b + -c > 2") parseAndPrintExpr("now () + b + c > 2") parseAndPrintExpr("now () + @b + c > 2") parseAndPrintExpr("now () - interval +2 day > some_other_time() or " "something_else IS NOT NULL") parseAndPrintExpr("\"two quotes to one\"\"\"") parseAndPrintExpr("'two quotes to one'''") parseAndPrintExpr("'different quote \"'") parseAndPrintExpr("\"different quote '\"") parseAndPrintExpr("`ident`") parseAndPrintExpr("`ident```") parseAndPrintExpr("`ident\"'`") parseAndPrintExpr("now () - interval -2 day") parseAndPrintExpr("? > x and func(?, ?, ?)") parseAndPrintExpr("a > now() + interval (2 + x) MiNuTe") parseAndPrintExpr("a between 1 and 2") parseAndPrintExpr("a not between 1 and 2") parseAndPrintExpr("a in (1,2,a.b(3),4,5,x)") parseAndPrintExpr("a not in (1,2,3,4,5,@x)") parseAndPrintExpr("a like b escape c") parseAndPrintExpr("a not like b escape c") parseAndPrintExpr("(1 + 3) in (3, 4, 5)") parseAndPrintExpr("`a crazy \"function\"``'name'`(1 + 3) in (3, 4, 5)") parseAndPrintExpr("`a crazy \"function\"``'name'`(1 + 3) in (3, 4, 5)") parseAndPrintExpr("a@.b", False) parseAndPrintExpr("a@.b[0][0].c**.d.\"a weird\\\"key name\"", False) parseAndPrintExpr("a@.*", False) parseAndPrintExpr("a@[0].*", False) parseAndPrintExpr("a@**[0].*", False) # x_test()
Upload File
Create Folder