Skip to content

Commit 66ce219

Browse files
committed
fix(NoTicket): vendor sqlparse CASE...END fix to allow PyPI publishing
Replace git dependency on lorenzhs/sqlparse fork with a monkey-patch of StatementSplitter._change_splitlevel in statement_formatter.py. The upstream sqlparse project isn't very active and the fix for CASE...END level tracking (andialbrecht/sqlparse#839) was not yet released. PyPI rejects packages with VCS dependencies, so vendoring the fix inline unblocks publishing.
1 parent 34140f1 commit 66ce219

2 files changed

Lines changed: 77 additions & 1 deletion

File tree

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ install_requires =
3636
pydantic[dotenv]>=1.8.2,<3.0.0
3737
python-dateutil>=2.8.2
3838
readerwriterlock>=1.0.9
39-
sqlparse@git+https://github.com/lorenzhs/sqlparse.git@8d379386c1c3e103ee67ef6582ea1b7c2296aa5b
39+
sqlparse>=0.5.5
4040
trio>=0.22.0
4141
truststore>=0.10;python_version>="3.10"
4242
python_requires = >=3.9

src/firebolt/common/statement_formatter.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
from typing import Dict, List, Optional, Sequence, Union
44

55
from sqlparse import parse as parse_sql # type: ignore
6+
from sqlparse import tokens as _T
7+
from sqlparse.engine.statement_splitter import (
8+
StatementSplitter as _StatementSplitter,
9+
)
610
from sqlparse.sql import ( # type: ignore
711
Comment,
812
Comparison,
@@ -15,6 +19,78 @@
1519
from sqlparse.tokens import Whitespace # type: ignore
1620
from sqlparse.tokens import Token as TokenType # type: ignore
1721

22+
23+
def _patched_change_splitlevel(self, ttype, value): # type: ignore[no-untyped-def]
24+
"""Patched version of StatementSplitter._change_splitlevel.
25+
26+
Fixes CASE...END level tracking outside of CREATE blocks.
27+
See: https://github.com/andialbrecht/sqlparse/pull/839
28+
"""
29+
if ttype is _T.Punctuation and value == "(":
30+
return 1
31+
elif ttype is _T.Punctuation and value == ")":
32+
return -1
33+
elif ttype not in _T.Keyword:
34+
return 0
35+
36+
unified = value.upper()
37+
38+
if ttype is _T.Keyword.DDL and unified.startswith("CREATE"):
39+
self._is_create = True
40+
return 0
41+
42+
if unified == "DECLARE" and self._is_create and self._begin_depth == 0:
43+
self._in_declare = True
44+
return 1
45+
46+
if unified == "BEGIN":
47+
self._begin_depth += 1
48+
self._seen_begin = True
49+
if self._is_create:
50+
return 1
51+
return 0
52+
53+
if (
54+
self._seen_begin
55+
and (ttype is _T.Keyword or ttype is _T.Name)
56+
and unified
57+
in (
58+
"TRANSACTION",
59+
"WORK",
60+
"TRAN",
61+
"DISTRIBUTED",
62+
"DEFERRED",
63+
"IMMEDIATE",
64+
"EXCLUSIVE",
65+
)
66+
):
67+
self._begin_depth = max(0, self._begin_depth - 1)
68+
self._seen_begin = False
69+
return 0
70+
71+
if unified == "END":
72+
if not self._in_case:
73+
self._begin_depth = max(0, self._begin_depth - 1)
74+
else:
75+
self._in_case = False
76+
return -1
77+
78+
if unified == "CASE":
79+
self._in_case = True
80+
return 1
81+
82+
if unified in ("IF", "FOR", "WHILE") and self._is_create and self._begin_depth > 0:
83+
return 1
84+
85+
if unified in ("END IF", "END FOR", "END WHILE"):
86+
return -1
87+
88+
return 0
89+
90+
91+
_StatementSplitter._change_splitlevel = _patched_change_splitlevel # type: ignore[method-assign]
92+
93+
1894
from firebolt.common._types import ParameterType, SetParameter
1995
from firebolt.utils.exception import (
2096
DataError,

0 commit comments

Comments
 (0)