Skip to content

Commit 3f03222

Browse files
authored
Merge branch 'mindsdb:main' into issue-fix-parameterized-queries
2 parents ab7370b + b88c45a commit 3f03222

File tree

7 files changed

+54
-31
lines changed

7 files changed

+54
-31
lines changed

.github/workflows/pypi.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ jobs:
99
deploy_to_pypi:
1010
name: Publish to PyPI
1111
runs-on: ubuntu-latest
12+
permissions:
13+
contents: read
1214
if: github.actor != 'mindsdbadmin'
1315
steps:
1416
- uses: actions/checkout@v4
1517
- name: Set up Python
16-
uses: actions/setup-python@v5.1.0
18+
uses: actions/setup-python@v5.6.0
1719
with:
1820
python-version: ${{ vars.CI_PYTHON_VERSION }}
1921
- name: Install dependencies

.github/workflows/test.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ on:
88
jobs:
99
test:
1010
runs-on: ${{ matrix.os }}
11+
permissions:
12+
contents: read
1113
strategy:
1214
matrix:
1315
os: [ubuntu-latest, windows-latest]
14-
python-version: [3.8,3.9,'3.10']
16+
python-version: ["3.9","3.10","3.11","3.12","3.13"]
1517
steps:
16-
- uses: actions/checkout@v2
18+
- uses: actions/checkout@v4
1719
- name: Set up Python ${{ matrix.python-version }}
18-
uses: actions/setup-python@v2
20+
uses: actions/setup-python@v5.6.0
1921
with:
2022
python-version: ${{ matrix.python-version }}
2123
- name: Install dependencies
@@ -35,11 +37,11 @@ jobs:
3537
permissions:
3638
pull-requests: write
3739
steps:
38-
- uses: actions/checkout@v3
39-
- name: Set up Python 3.8
40-
uses: actions/setup-python@v2
40+
- uses: actions/checkout@v4
41+
- name: Set up Python 3.9
42+
uses: actions/setup-python@v5.6.0
4143
with:
42-
python-version: 3.8
44+
python-version: 3.9
4345

4446
- name: Install dependencies
4547
run: |

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.10.0'
3+
__version__ = '0.10.1'
44
__description__ = "Mindsdb SQL parser"
55
__email__ = "[email protected]"
66
__author__ = 'MindsDB Inc'

mindsdb_sql_parser/ast/select/union.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ def __init__(self,
99
left,
1010
right,
1111
unique=True,
12+
distinct_key=False,
1213
*args, **kwargs):
1314
super().__init__(*args, **kwargs)
1415
self.left = left
1516
self.right = right
1617
self.unique = unique
18+
self.distinct_key = distinct_key
1719

1820
if self.alias:
1921
self.parentheses = True
@@ -26,7 +28,7 @@ def to_tree(self, *args, level=0, **kwargs):
2628
right_str = f'\n{ind1}right=\n{self.right.to_tree(level=level + 2)},'
2729

2830
cls_name = self.__class__.__name__
29-
out_str = f'{ind}{cls_name}(unique={repr(self.unique)},' \
31+
out_str = f'{ind}{cls_name}(unique={repr(self.unique)}, distinct_key={repr(self.distinct_key)}' \
3032
f'{left_str}' \
3133
f'{right_str}' \
3234
f'\n{ind})'
@@ -38,6 +40,8 @@ def get_string(self, *args, **kwargs):
3840
keyword = self.operation
3941
if not self.unique:
4042
keyword += ' ALL'
43+
if self.distinct_key:
44+
keyword += ' DISTINCT'
4145
out_str = f"""{left_str}\n{keyword}\n{right_str}"""
4246

4347
return out_str

mindsdb_sql_parser/parser.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,25 +1061,35 @@ def database_engine(self, p):
10611061
@_('select UNION select',
10621062
'union UNION select',
10631063
'select UNION ALL select',
1064-
'union UNION ALL select')
1064+
'union UNION ALL select',
1065+
'select UNION DISTINCT select',
1066+
'union UNION DISTINCT select')
10651067
def union(self, p):
10661068
unique = not hasattr(p, 'ALL')
1067-
return Union(left=p[0], right=p[2] if unique else p[3], unique=unique)
1069+
distinct_key = hasattr(p, 'DISTINCT')
1070+
return Union(left=p[0], right=p[-1], unique=unique, distinct_key=distinct_key)
10681071

10691072
@_('select INTERSECT select',
10701073
'union INTERSECT select',
10711074
'select INTERSECT ALL select',
1072-
'union INTERSECT ALL select')
1075+
'union INTERSECT ALL select',
1076+
'select INTERSECT DISTINCT select',
1077+
'union INTERSECT DISTINCT select')
10731078
def union(self, p):
10741079
unique = not hasattr(p, 'ALL')
1075-
return Intersect(left=p[0], right=p[2] if unique else p[3], unique=unique)
1080+
distinct_key = hasattr(p, 'DISTINCT')
1081+
return Intersect(left=p[0], right=p[-1], unique=unique, distinct_key=distinct_key)
1082+
10761083
@_('select EXCEPT select',
10771084
'union EXCEPT select',
10781085
'select EXCEPT ALL select',
1079-
'union EXCEPT ALL select')
1086+
'union EXCEPT ALL select',
1087+
'select EXCEPT DISTINCT select',
1088+
'union EXCEPT DISTINCT select')
10801089
def union(self, p):
10811090
unique = not hasattr(p, 'ALL')
1082-
return Except(left=p[0], right=p[2] if unique else p[3], unique=unique)
1091+
distinct_key = hasattr(p, 'DISTINCT')
1092+
return Except(left=p[0], right=p[-1], unique=unique, distinct_key=distinct_key)
10831093

10841094
# tableau
10851095
@_('LPAREN select RPAREN')

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def run(self):
3232
"Programming Language :: Python :: 3",
3333
"Operating System :: OS Independent",
3434
],
35-
python_requires=">=3.6",
35+
python_requires=">=3.9",
3636
cmdclass={
3737
'build': Build
3838
},

tests/test_base_sql/test_union.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,26 @@ def test_single_select_error(self):
1212

1313
def test_union_base(self):
1414
for keyword, cls in {'union': Union, 'intersect': Intersect, 'except': Except}.items():
15-
sql = f"""SELECT col1 FROM tab1
16-
{keyword}
17-
SELECT col1 FROM tab2"""
15+
for rule in ['', 'distinct']:
16+
sql = f"""SELECT col1 FROM tab1
17+
{keyword} {rule}
18+
SELECT col1 FROM tab2"""
1819

19-
ast = parse_sql(sql)
20-
expected_ast = cls(unique=True,
21-
left=Select(targets=[Identifier('col1')],
22-
from_table=Identifier(parts=['tab1']),
23-
),
24-
right=Select(targets=[Identifier('col1')],
25-
from_table=Identifier(parts=['tab2']),
26-
),
27-
)
28-
assert ast.to_tree() == expected_ast.to_tree()
29-
assert str(ast) == str(expected_ast)
20+
ast = parse_sql(sql)
21+
expected_ast = cls(
22+
unique=True,
23+
distinct_key=rule == 'distinct',
24+
left=Select(
25+
targets=[Identifier('col1')],
26+
from_table=Identifier(parts=['tab1']),
27+
),
28+
right=Select(
29+
targets=[Identifier('col1')],
30+
from_table=Identifier(parts=['tab2']),
31+
),
32+
)
33+
assert ast.to_tree() == expected_ast.to_tree()
34+
assert str(ast) == str(expected_ast)
3035

3136
def test_union_all(self):
3237
for keyword, cls in {'union': Union, 'intersect': Intersect, 'except': Except}.items():

0 commit comments

Comments
 (0)