Skip to content

Commit 7b5fc43

Browse files
authored
fix(NoTicket): vendor sqlparse CASE...END fix to allow PyPI publishing (#494)
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. The vendored code is identical to the fixed version from that PR, up to formatting, quote style, and comments.
1 parent 34140f1 commit 7b5fc43

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,
@@ -22,6 +26,78 @@
2226
NotSupportedError,
2327
)
2428

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

0 commit comments

Comments
 (0)