Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.21.0 #416

Merged
merged 48 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
008dd27
bump version
ea-rus Oct 29, 2024
0796d8e
fix modulo precedence
ea-rus Oct 30, 2024
7bdddfa
Merge pull request #408 from mindsdb/fix-union
ea-rus Oct 30, 2024
fd1ae98
Merge pull request #409 from mindsdb/fix-modulo
ea-rus Oct 30, 2024
e487c93
support CAST(a AS decimal(10, 1))
ea-rus Oct 30, 2024
ec6751b
support CAST(a AS decimal(10, 1))
ea-rus Oct 30, 2024
e6b2356
classes for intersect, except
ea-rus Oct 30, 2024
fe27308
intersect, except
ea-rus Oct 30, 2024
d79cf77
tests for intersect, except
ea-rus Oct 30, 2024
d5eb2da
enabled test
ea-rus Oct 30, 2024
c50e06c
Merge pull request #410 from mindsdb/fix-cast-decimal
ea-rus Oct 31, 2024
cd2bf55
fix order with constant in join
ea-rus Oct 31, 2024
b735f13
get filters for fetching tables from previous table
ea-rus Oct 31, 2024
589b1f0
test fixes
ea-rus Nov 1, 2024
ef30b12
testing fixes
ea-rus Nov 1, 2024
61d8141
cte support
ea-rus Nov 1, 2024
b4b3263
rollback tests
ea-rus Nov 1, 2024
c5cb9df
test fixes
ea-rus Nov 1, 2024
e324f45
Merge branch 'optimize-join' into cte-support
ea-rus Nov 2, 2024
0f5dbb1
unit tests
ea-rus Nov 2, 2024
29ab045
Merge branch 'optimize-join' into cte-support
ea-rus Nov 2, 2024
c225895
tests
ea-rus Nov 2, 2024
5525c2c
Merge pull request #412 from mindsdb/optimize-join
ea-rus Nov 6, 2024
82cae5a
Merge branch 'staging' into cte-support
ea-rus Nov 6, 2024
e01c094
fix standard render 'interval': number have to be quoted
ea-rus Nov 6, 2024
63a206e
fix case with default value for sqlachemy render
ea-rus Nov 6, 2024
4a67a14
Merge branch 'cte-support' into parser_fixes
ea-rus Nov 6, 2024
57ba416
Merge pull request #413 from mindsdb/cte-support
ea-rus Nov 8, 2024
1aea939
Merge branch 'staging' into combining-queries
ea-rus Nov 8, 2024
c34fefc
planning render combining queries
ea-rus Nov 8, 2024
6c93ee0
fix parsing (.. union ..) union ..
ea-rus Nov 8, 2024
70146e8
cte with union
ea-rus Nov 10, 2024
fbb913d
combining queries traversal
ea-rus Nov 10, 2024
0db06c6
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED in window function
ea-rus Nov 10, 2024
8ac9fe2
simple form of case
ea-rus Nov 10, 2024
b65132d
query with cte to one integration
ea-rus Nov 10, 2024
65b3d05
Merge branch 'window-fix' into parser_fixes
ea-rus Nov 10, 2024
4298b66
fix case render
ea-rus Nov 10, 2024
6caf30a
Merge pull request #414 from mindsdb/parser_fixes
ea-rus Nov 11, 2024
ad6ee9d
test_case_simple_form
ea-rus Nov 11, 2024
2fb6ce4
window function test
ea-rus Nov 11, 2024
5e594fb
test single_integration
ea-rus Nov 11, 2024
fce61dc
fix window function
ea-rus Nov 11, 2024
fbc4315
Merge pull request #415 from mindsdb/window-fix
ea-rus Nov 11, 2024
c6983a2
plan union in single integration query
ea-rus Nov 11, 2024
64622e9
fix render select from union
ea-rus Nov 11, 2024
410c2f9
Merge pull request #411 from mindsdb/combining-queries
ea-rus Nov 11, 2024
5a7cf55
bump version
ea-rus Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mindsdb_sql/__about__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
__title__ = 'mindsdb_sql'
__package_name__ = 'mindsdb_sql'
__version__ = '0.20.0'
__version__ = '0.21.0'
__description__ = "Pure python SQL parser"
__email__ = "[email protected]"
__author__ = 'MindsDB Inc'
Expand Down
2 changes: 1 addition & 1 deletion mindsdb_sql/parser/ast/select/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .select import Select
from .common_table_expression import CommonTableExpression
from .union import Union
from .union import Union, Except, Intersect
from .constant import Constant, NullConstant, Last
from .star import Star
from .identifier import Identifier
Expand Down
14 changes: 12 additions & 2 deletions mindsdb_sql/parser/ast/select/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@


class Case(ASTNode):
def __init__(self, rules, default=None, *args, **kwargs):
def __init__(self, rules, default=None, arg=None, *args, **kwargs):
super().__init__(*args, **kwargs)

# structure:
# [
# [ condition, result ]
# ]
self.arg = arg
self.rules = rules
self.default = default

Expand All @@ -36,7 +37,12 @@ def to_tree(self, *args, level=0, **kwargs):
if self.default is not None:
default_str = f'{ind1}default => {self.default.to_string()}\n'

arg_str = ''
if self.arg is not None:
arg_str = f'{ind1}arg => {self.arg.to_string()}\n'

return f'{ind}Case(\n' \
f'{arg_str}'\
f'{rules_str}\n' \
f'{default_str}' \
f'{ind})'
Expand All @@ -53,4 +59,8 @@ def get_string(self, *args, alias=True, **kwargs):
default_str = ''
if self.default is not None:
default_str = f' ELSE {self.default.to_string()}'
return f"CASE {rules_str}{default_str} END"

arg_str = ''
if self.arg is not None:
arg_str = f'{self.arg.to_string()} '
return f"CASE {arg_str}{rules_str}{default_str} END"
13 changes: 10 additions & 3 deletions mindsdb_sql/parser/ast/select/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,13 @@ def get_string(self, *args, **kwargs):


class WindowFunction(ASTNode):
def __init__(self, function, partition=None, order_by=None, alias=None):
def __init__(self, function, partition=None, order_by=None, alias=None, modifier=None):
super().__init__()
self.function = function
self.partition = partition
self.order_by = order_by
self.alias = alias
self.modifier = modifier

def to_tree(self, *args, level=0, **kwargs):
fnc_str = self.function.to_tree(level=level+2)
Expand Down Expand Up @@ -143,7 +144,8 @@ def to_string(self, *args, **kwargs):
alias_str = self.alias.to_string()
else:
alias_str = ''
return f'{fnc_str} over({partition_str} {order_str}) {alias_str}'
modifier_str = ' ' + self.modifier if self.modifier else ''
return f'{fnc_str} over({partition_str} {order_str}{modifier_str}) {alias_str}'


class Object(ASTNode):
Expand Down Expand Up @@ -177,7 +179,12 @@ def __init__(self, info):
super().__init__(op='interval', args=[info, ])

def get_string(self, *args, **kwargs):
return f'INTERVAL {self.args[0]}'

arg = self.args[0]
items = arg.split(' ', maxsplit=1)
# quote first element
items[0] = f"'{items[0]}'"
return "INTERVAL " + " ".join(items)

def to_tree(self, *args, level=0, **kwargs):
return self.get_string( *args, **kwargs)
Expand Down
11 changes: 6 additions & 5 deletions mindsdb_sql/parser/ast/select/type_cast.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@


class TypeCast(ASTNode):
def __init__(self, type_name, arg, length=None, *args, **kwargs):
def __init__(self, type_name, arg, precision=None, *args, **kwargs):
super().__init__(*args, **kwargs)

self.type_name = type_name
self.arg = arg
self.length = length
self.precision = precision

def to_tree(self, *args, level=0, **kwargs):
out_str = indent(level) + f'TypeCast(type_name={repr(self.type_name)}, length={self.length}, arg=\n{indent(level+1)}{self.arg.to_tree()})'
out_str = indent(level) + f'TypeCast(type_name={repr(self.type_name)}, precision={self.precision}, arg=\n{indent(level+1)}{self.arg.to_tree()})'
return out_str

def get_string(self, *args, **kwargs):
type_name = self.type_name
if self.length is not None:
type_name += f'({self.length})'
if self.precision is not None:
precision = map(str, self.precision)
type_name += f'({",".join(precision)})'
return f'CAST({str(self.arg)} AS {type_name})'
22 changes: 19 additions & 3 deletions mindsdb_sql/parser/ast/select/union.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from mindsdb_sql.parser.utils import indent


class Union(ASTNode):
class CombiningQuery(ASTNode):
operation = None

def __init__(self,
left,
Expand All @@ -24,7 +25,8 @@ def to_tree(self, *args, level=0, **kwargs):
left_str = f'\n{ind1}left=\n{self.left.to_tree(level=level + 2)},'
right_str = f'\n{ind1}right=\n{self.right.to_tree(level=level + 2)},'

out_str = f'{ind}Union(unique={repr(self.unique)},' \
cls_name = self.__class__.__name__
out_str = f'{ind}{cls_name}(unique={repr(self.unique)},' \
f'{left_str}' \
f'{right_str}' \
f'\n{ind})'
Expand All @@ -33,7 +35,21 @@ def to_tree(self, *args, level=0, **kwargs):
def get_string(self, *args, **kwargs):
left_str = str(self.left)
right_str = str(self.right)
keyword = 'UNION' if self.unique else 'UNION ALL'
keyword = self.operation
if not self.unique:
keyword += ' ALL'
out_str = f"""{left_str}\n{keyword}\n{right_str}"""

return out_str


class Union(CombiningQuery):
operation = 'UNION'


class Intersect(CombiningQuery):
operation = 'INTERSECT'


class Except(CombiningQuery):
operation = 'EXCEPT'
4 changes: 3 additions & 1 deletion mindsdb_sql/parser/dialects/mindsdb/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class MindsDBLexer(Lexer):

JOIN, INNER, OUTER, CROSS, LEFT, RIGHT, ON,

UNION, ALL,
UNION, ALL, INTERSECT, EXCEPT,

# CASE
CASE, ELSE, END, THEN, WHEN,
Expand Down Expand Up @@ -238,6 +238,8 @@ class MindsDBLexer(Lexer):
# UNION

UNION = r'\bUNION\b'
INTERSECT = r'\bINTERSECT\b'
EXCEPT = r'\bEXCEPT\b'
ALL = r'\bALL\b'

# CASE
Expand Down
69 changes: 53 additions & 16 deletions mindsdb_sql/parser/dialects/mindsdb/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class MindsDBParser(Parser):
('nonassoc', LESS, LEQ, GREATER, GEQ, IN, NOT_IN, BETWEEN, IS, IS_NOT, NOT_LIKE, LIKE),
('left', JSON_GET),
('left', PLUS, MINUS),
('left', STAR, DIVIDE, TYPECAST),
('left', STAR, DIVIDE, TYPECAST, MODULO),
('right', UMINUS), # Unary minus operator, unary not

)
Expand All @@ -68,9 +68,9 @@ class MindsDBParser(Parser):
'drop_predictor',
'drop_datasource',
'drop_dataset',
'union',
'select',
'insert',
'union',
'update',
'delete',
'evaluate',
Expand Down Expand Up @@ -615,10 +615,13 @@ def update(self, p):

# INSERT
@_('INSERT INTO identifier LPAREN column_list RPAREN select',
'INSERT INTO identifier select')
'INSERT INTO identifier LPAREN column_list RPAREN union',
'INSERT INTO identifier select',
'INSERT INTO identifier union')
def insert(self, p):
columns = getattr(p, 'column_list', None)
return Insert(table=p.identifier, columns=columns, from_select=p.select)
query = p.select if hasattr(p, 'select') else p.union
return Insert(table=p.identifier, columns=columns, from_select=query)

@_('INSERT INTO identifier LPAREN column_list RPAREN VALUES expr_list_set',
'INSERT INTO identifier VALUES expr_list_set')
Expand Down Expand Up @@ -999,21 +1002,35 @@ def database_engine(self, p):
engine = p.string
return {'identifier':p.identifier, 'engine':engine, 'if_not_exists':p.if_not_exists_or_empty}

# UNION / UNION ALL
# Combining
@_('select UNION select',
'union UNION select')
'union UNION select',
'select UNION ALL select',
'union UNION ALL select')
def union(self, p):
return Union(left=p[0], right=p[2], unique=True)
unique = not hasattr(p, 'ALL')
return Union(left=p[0], right=p[2] if unique else p[3], unique=unique)

@_('select UNION ALL select',
'union UNION ALL select',)
@_('select INTERSECT select',
'union INTERSECT select',
'select INTERSECT ALL select',
'union INTERSECT ALL select')
def union(self, p):
unique = not hasattr(p, 'ALL')
return Intersect(left=p[0], right=p[2] if unique else p[3], unique=unique)
@_('select EXCEPT select',
'union EXCEPT select',
'select EXCEPT ALL select',
'union EXCEPT ALL select')
def union(self, p):
return Union(left=p[0], right=p[3], unique=False)
unique = not hasattr(p, 'ALL')
return Except(left=p[0], right=p[2] if unique else p[3], unique=unique)

# tableau
@_('LPAREN select RPAREN')
@_('LPAREN union RPAREN')
def select(self, p):
return p.select
return p[1]

# WITH
@_('ctes select')
Expand All @@ -1033,13 +1050,14 @@ def ctes(self, p):
]
return ctes

@_('WITH identifier cte_columns_or_nothing AS LPAREN select RPAREN')
@_('WITH identifier cte_columns_or_nothing AS LPAREN select RPAREN',
'WITH identifier cte_columns_or_nothing AS LPAREN union RPAREN')
def ctes(self, p):
return [
CommonTableExpression(
name=p.identifier,
columns=p.cte_columns_or_nothing,
query=p.select)
query=p[5])
]

@_('empty')
Expand Down Expand Up @@ -1334,6 +1352,15 @@ def column_list(self, p):
def case(self, p):
return Case(rules=p.case_conditions, default=getattr(p, 'expr', None))

@_('CASE expr case_conditions ELSE expr END',
'CASE expr case_conditions END')
def case(self, p):
if hasattr(p, 'expr'):
arg, default = p.expr, None
else:
arg, default = p.expr0, p.expr1
return Case(rules=p.case_conditions, default=default, arg=arg)

@_('case_condition',
'case_conditions case_condition')
def case_conditions(self, p):
Expand All @@ -1346,13 +1373,18 @@ def case_condition(self, p):
return [p.expr0, p.expr1]

# Window function
@_('function OVER LPAREN window RPAREN')
@_('expr OVER LPAREN window RPAREN',
'expr OVER LPAREN window id BETWEEN id id AND id id RPAREN')
def window_function(self, p):

modifier = None
if hasattr(p, 'BETWEEN'):
modifier = f'{p.id0} BETWEEN {p.id1} {p.id2} AND {p.id3} {p.id4}'
return WindowFunction(
function=p.function,
function=p.expr,
order_by=p.window.get('order_by'),
partition=p.window.get('partition'),
modifier=modifier,
)

@_('window PARTITION_BY expr_list')
Expand Down Expand Up @@ -1469,8 +1501,13 @@ def expr_list_or_nothing(self, p):
pass

@_('CAST LPAREN expr AS id LPAREN integer RPAREN RPAREN')
@_('CAST LPAREN expr AS id LPAREN integer COMMA integer RPAREN RPAREN')
def expr(self, p):
return TypeCast(arg=p.expr, type_name=str(p.id), length=p.integer)
if hasattr(p, 'integer'):
precision=[p.integer]
else:
precision=[p.integer0, p.integer1]
return TypeCast(arg=p.expr, type_name=str(p.id), precision=precision)

@_('CAST LPAREN expr AS id RPAREN')
def expr(self, p):
Expand Down
7 changes: 6 additions & 1 deletion mindsdb_sql/parser/dialects/mysql/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,8 +821,13 @@ def expr_list_or_nothing(self, p):
pass

@_('CAST LPAREN expr AS id LPAREN integer RPAREN RPAREN')
@_('CAST LPAREN expr AS id LPAREN integer COMMA integer RPAREN RPAREN')
def expr(self, p):
return TypeCast(arg=p.expr, type_name=str(p.id), length=p.integer)
if hasattr(p, 'integer'):
precision=[p.integer]
else:
precision=[p.integer0, p.integer1]
return TypeCast(arg=p.expr, type_name=str(p.id), precision=precision)

@_('CAST LPAREN expr AS id RPAREN')
def expr(self, p):
Expand Down
7 changes: 6 additions & 1 deletion mindsdb_sql/parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,8 +581,13 @@ def expr_list_or_nothing(self, p):
pass

@_('CAST LPAREN expr AS id LPAREN integer RPAREN RPAREN')
@_('CAST LPAREN expr AS id LPAREN integer COMMA integer RPAREN RPAREN')
def expr(self, p):
return TypeCast(arg=p.expr, type_name=str(p.id), length=p.integer)
if hasattr(p, 'integer'):
precision=[p.integer]
else:
precision=[p.integer0, p.integer1]
return TypeCast(arg=p.expr, type_name=str(p.id), precision=precision)

@_('CAST LPAREN expr AS id RPAREN')
def expr(self, p):
Expand Down
Loading
Loading