def select(self, p): select = p.select if select.offset is not None: raise ParsingException(f'OFFSET already specified for this query') ensure_select_keyword_order(select, 'OFFSET') if not isinstance(p.constant.value, int): raise ParsingException( f'OFFSET must be an integer value, got: {p.constant.value}') select.offset = p.constant return select
def result_column(self, p): col = p.result_column if col.alias: raise ParsingException( f'Attempt to provide two aliases for {str(col)}') col.alias = p.identifier return col
def select(self, p): select = p.select ensure_select_keyword_order(select, 'LIMIT') if not isinstance(p.constant.value, int): raise ParsingException( f'LIMIT must be an integer value, got: {p.constant.value}') select.limit = p.constant return select
def __init__(self, name, url, *args, **kwargs): super().__init__(*args, **kwargs) url_ = urlparse(url) if url_.scheme not in ('http', 'https'): raise ParsingException(f'Wrong url scheme: {url_.scheme}') self.url = url self.name = name
def delete(self, p): where = getattr(p, 'expr', None) if where is not None and not isinstance(where, Operation): raise ParsingException( f"WHERE must contain an operation that evaluates to a boolean, got: {str(where)}" ) return Delete(table=p.from_table, where=where)
def select(self, p): select = p.select ensure_select_keyword_order(select, 'WHERE') where_expr = p.expr if not isinstance(where_expr, Operation): raise ParsingException( f"WHERE must contain an operation that evaluates to a boolean, got: {str(where_expr)}" ) select.where = where_expr return select
def select(self, p): select = p.select ensure_select_keyword_order(select, 'HAVING') having = p.expr if not isinstance(having, Operation): raise ParsingException( f"HAVING must contain an operation that evaluates to a boolean, got: {str(having)}" ) select.having = having return select
def result_column(self, p): col = p.result_column if col.alias: raise ParsingException( f'Attempt to provide two aliases for {str(col)}') if hasattr(p, 'dquote_string'): alias = Identifier(p.dquote_string) else: alias = p.identifier col.alias = alias return col
def select(self, p): select = p.select ensure_select_keyword_order(select, 'LIMIT') if not isinstance(p.constant0.value, int) or not isinstance( p.constant1.value, int): raise ParsingException( f'LIMIT must have integer arguments, got: {p.constant0.value}, {p.constant1.value}' ) select.offset = p.constant0 select.limit = p.constant1 return select
def ensure_select_keyword_order(select, operation): op_to_attr = { 'FROM': select.from_table, 'WHERE': select.where, 'GROUP BY': select.group_by, 'HAVING': select.having, 'ORDER BY': select.order_by, 'LIMIT': select.limit, 'OFFSET': select.offset, 'MODE': select.mode, } requirements = { 'WHERE': ['FROM'], 'GROUP BY': ['FROM'], 'ORDER BY': ['FROM'], # 'HAVING': ['GROUP BY'], } precedence = [ 'FROM', 'WHERE', 'GROUP BY', 'HAVING', 'ORDER BY', 'LIMIT', 'OFFSET', 'MODE' ] if op_to_attr[operation]: raise ParsingException( f"Duplicate {operation} clause. Only one {operation} allowed per SELECT." ) op_requires = requirements.get(operation, []) for req in op_requires: if not op_to_attr[req]: raise ParsingException(f"{operation} requires {req}") op_precedence_pos = precedence.index(operation) for next_op in precedence[op_precedence_pos:]: if op_to_attr[next_op]: raise ParsingException(f"{operation} must go after {next_op}")
def get_lexer_parser(dialect): if dialect == 'sqlite': from mindsdb_sql.parser.lexer import SQLLexer from mindsdb_sql.parser.parser import SQLParser lexer, parser = SQLLexer(), SQLParser() elif dialect == 'mysql': from mindsdb_sql.parser.dialects.mysql.lexer import MySQLLexer from mindsdb_sql.parser.dialects.mysql.parser import MySQLParser lexer, parser = MySQLLexer(), MySQLParser() elif dialect == 'mindsdb': from mindsdb_sql.parser.dialects.mindsdb.lexer import MindsDBLexer from mindsdb_sql.parser.dialects.mindsdb.parser import MindsDBParser lexer, parser = MindsDBLexer(), MindsDBParser() else: raise ParsingException(f'Unknown dialect {dialect}. Available options are: sqlite, mysql.') return lexer, parser
def set(self, p): if not p.id.lower() == 'names': raise ParsingException(f'Expected "SET names", got "SET {p.id}"') if isinstance(p[2], Constant): arg = Identifier(p[2].value) else: # is identifier arg = p[2] params = {} if hasattr(p, 'COLLATE'): if isinstance(p[4], Constant): val = p[4] else: val = SpecialConstant('DEFAULT') params['COLLATE'] = val return Set(category=p.id.lower(), arg=arg, params=params)
def error(self, p): if p: raise ParsingException( f"Syntax error at token {p.type}: \"{p.value}\"") else: raise ParsingException("Syntax error at EOF")
def set(self, p): if not p.id.lower() == 'names': raise ParsingException(f'Expected "SET names", got "SET {p.id}"') return Set(category=p.id.lower(), arg=p.identifier)