Skip to content

Commit 3f0562a

Browse files
authored
Merge pull request #81 from mindsdb/union-in-in
Fix insert from select with using
2 parents c9d98bf + 4383c20 commit 3f0562a

File tree

4 files changed

+82
-19
lines changed

4 files changed

+82
-19
lines changed

mindsdb_sql_parser/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__title__ = 'mindsdb_sql_parser'
22
__package_name__ = 'mindsdb_sql_parser'
3-
__version__ = '0.13.5'
3+
__version__ = '0.13.6'
44
__description__ = "Mindsdb SQL parser"
55
__email__ = "jorge@mindsdb.com"
66
__author__ = 'MindsDB Inc'

mindsdb_sql_parser/parser.py

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,11 @@ def create_agent(self, p):
210210
params=params,
211211
if_not_exists=p.if_not_exists_or_empty
212212
)
213-
213+
214214
@_('DROP AGENT if_exists_or_empty identifier')
215215
def drop_agent(self, p):
216216
return DropAgent(name=p.identifier, if_exists=p.if_exists_or_empty)
217-
217+
218218
@_('UPDATE AGENT identifier SET kw_parameter_list')
219219
@_('ALTER AGENT identifier USING kw_parameter_list')
220220
def update_agent(self, p):
@@ -667,11 +667,13 @@ def update(self, p):
667667
from_select=p.select)
668668

669669
# INSERT
670-
@_('INSERT INTO identifier LPAREN column_list RPAREN union',
670+
@_('INSERT INTO identifier LPAREN column_list RPAREN select',
671+
'INSERT INTO identifier LPAREN column_list RPAREN union',
672+
'INSERT INTO identifier select',
671673
'INSERT INTO identifier union')
672674
def insert(self, p):
673675
columns = getattr(p, 'column_list', None)
674-
query = p.union
676+
query = p.select if hasattr(p, 'select') else p.union
675677
return Insert(table=p.identifier, columns=columns, from_select=query)
676678

677679
@_('INSERT INTO identifier LPAREN column_list RPAREN VALUES expr_list_set',
@@ -1084,38 +1086,49 @@ def database_engine(self, p):
10841086
return {'identifier':p.identifier, 'engine':engine, 'if_not_exists':p.if_not_exists_or_empty}
10851087

10861088
# Combining
1087-
@_('union UNION select',
1089+
@_('select UNION select',
1090+
'union UNION select',
1091+
'select UNION ALL select',
10881092
'union UNION ALL select',
1093+
'select UNION DISTINCT select',
10891094
'union UNION DISTINCT select')
10901095
def union(self, p):
10911096
unique = not hasattr(p, 'ALL')
10921097
distinct_key = hasattr(p, 'DISTINCT')
10931098
return Union(left=p[0], right=p[-1], unique=unique, distinct_key=distinct_key)
10941099

1095-
@_('union INTERSECT select',
1100+
@_('select INTERSECT select',
1101+
'union INTERSECT select',
1102+
'select INTERSECT ALL select',
10961103
'union INTERSECT ALL select',
1104+
'select INTERSECT DISTINCT select',
10971105
'union INTERSECT DISTINCT select')
10981106
def union(self, p):
10991107
unique = not hasattr(p, 'ALL')
11001108
distinct_key = hasattr(p, 'DISTINCT')
11011109
return Intersect(left=p[0], right=p[-1], unique=unique, distinct_key=distinct_key)
11021110

1103-
@_('union EXCEPT select',
1111+
@_('select EXCEPT select',
1112+
'union EXCEPT select',
1113+
'select EXCEPT ALL select',
11041114
'union EXCEPT ALL select',
1115+
'select EXCEPT DISTINCT select',
11051116
'union EXCEPT DISTINCT select')
11061117
def union(self, p):
11071118
unique = not hasattr(p, 'ALL')
11081119
distinct_key = hasattr(p, 'DISTINCT')
11091120
return Except(left=p[0], right=p[-1], unique=unique, distinct_key=distinct_key)
11101121

11111122
# tableau
1112-
@_('LPAREN union RPAREN')
1113-
def union(self, p):
1123+
@_('LPAREN select RPAREN')
1124+
def select(self, p):
11141125
return p[1]
11151126

1116-
@_('select')
1127+
@_('LPAREN union RPAREN')
11171128
def union(self, p):
1118-
return p[0]
1129+
node = p[1]
1130+
node.parentheses = True
1131+
return node
11191132

11201133
# WITH
11211134
@_('ctes select')
@@ -1124,7 +1137,8 @@ def select(self, p):
11241137
select.cte = p.ctes
11251138
return select
11261139

1127-
@_('ctes COMMA identifier cte_columns_or_nothing AS LPAREN union RPAREN')
1140+
@_('ctes COMMA identifier cte_columns_or_nothing AS LPAREN select RPAREN',
1141+
'ctes COMMA identifier cte_columns_or_nothing AS LPAREN union RPAREN')
11281142
def ctes(self, p):
11291143
ctes = p.ctes
11301144
ctes = ctes + [
@@ -1135,7 +1149,8 @@ def ctes(self, p):
11351149
]
11361150
return ctes
11371151

1138-
@_('WITH identifier cte_columns_or_nothing AS LPAREN union RPAREN')
1152+
@_('WITH identifier cte_columns_or_nothing AS LPAREN select RPAREN',
1153+
'WITH identifier cte_columns_or_nothing AS LPAREN union RPAREN')
11391154
def ctes(self, p):
11401155
return [
11411156
CommonTableExpression(
@@ -1508,11 +1523,12 @@ def window(self, p):
15081523

15091524
# OPERATIONS
15101525

1511-
@_('LPAREN union RPAREN')
1526+
@_('LPAREN select RPAREN',
1527+
'LPAREN union RPAREN')
15121528
def expr(self, p):
1513-
union = p.union
1514-
union.parentheses = True
1515-
return union
1529+
node = p[1]
1530+
node.parentheses = True
1531+
return node
15161532

15171533
@_('LPAREN expr RPAREN')
15181534
def expr(self, p):

tests/test_base_sql/test_union.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,33 @@ def test_union_alias(self):
8080
assert ast.to_tree() == expected_ast.to_tree()
8181
assert str(ast) == str(expected_ast)
8282

83+
def test_union_alias_parens(self):
84+
sql = f'''
85+
SELECT * FROM (
86+
(
87+
SELECT col1 FROM tab1
88+
UNION
89+
SELECT col1 FROM tab2
90+
)
91+
UNION
92+
SELECT col1 FROM tab3
93+
) AS tt
94+
'''
95+
ast = parse_sql(sql)
96+
97+
expected_ast = Select(
98+
targets=[Star()],
99+
from_table=Union(
100+
left=Union(
101+
left=Select(targets=[Identifier('col1')], from_table=Identifier('tab1')),
102+
right=Select(targets=[Identifier('col1')], from_table=Identifier('tab2')),
103+
parentheses=True
104+
),
105+
right=Select(targets=[Identifier('col1')], from_table=Identifier('tab3')),
106+
parentheses=True,
107+
alias=Identifier('tt')
108+
)
109+
)
110+
111+
assert str(ast) == str(expected_ast)
112+
assert ast.to_tree() == expected_ast.to_tree()

tests/test_mindsdb/test_selects.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def test_select_using(self):
7171
using p1=1, p2='2', p3=column
7272
"""
7373
ast = parse_sql(sql)
74-
expected_ast = Select(
74+
expected_select = Select(
7575
targets=[Identifier('status')],
7676
from_table=Identifier('tbl1'),
7777
group_by=[Constant(1)],
@@ -82,6 +82,23 @@ def test_select_using(self):
8282
}
8383
)
8484

85+
assert str(ast) == str(expected_select)
86+
assert ast.to_tree() == expected_select.to_tree()
87+
88+
sql = """
89+
insert into int2.table2
90+
(
91+
SELECT status FROM tbl1
92+
group by 1
93+
)
94+
using p1=1, p2='2', p3=column
95+
"""
96+
ast = parse_sql(sql)
97+
expected_ast = Insert(
98+
table=Identifier('int2.table2'),
99+
from_select=expected_select
100+
)
101+
85102
assert str(ast) == str(expected_ast)
86103
assert ast.to_tree() == expected_ast.to_tree()
87104

0 commit comments

Comments
 (0)