Skip to content

Commit 4ba0256

Browse files
committed
Add migration script to warn
1 parent ffab514 commit 4ba0256

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""
2+
This script's goal is to warn users if there are two adjacent expressions in a SQL
3+
model that are equivalent.
4+
5+
Context:
6+
7+
We used to include `Semicolon` expressions in the model's state, which led to a bug
8+
where the expression preceding the semicolon would be duplicated in pre_statements
9+
or post_statements. For example, the query in the model below would be incorrectly
10+
included in its post_statements list:
11+
12+
```
13+
MODEL (
14+
name test
15+
);
16+
17+
SELECT 1 AS c;
18+
19+
-- foo
20+
```
21+
22+
We now don't include `Semicolon` expressions in the model's state, which fixes this
23+
issue, but unfortunately migrating existing snapshots is not possible because we do
24+
not have a signal in state to detect whether an expression was incorrectly duplicated.
25+
26+
If a SQL model suffered from this issue, then there would be two adjacent equivalent
27+
expressions in it, so we use that as a heuristic to warn the user accordingly.
28+
"""
29+
30+
import json
31+
32+
from sqlglot import exp
33+
34+
from sqlmesh.core.console import get_console
35+
36+
37+
def migrate(state_sync, **kwargs): # type: ignore
38+
engine_adapter = state_sync.engine_adapter
39+
schema = state_sync.schema
40+
snapshots_table = "_snapshots"
41+
if schema:
42+
snapshots_table = f"{schema}.{snapshots_table}"
43+
44+
warning = (
45+
"SQLMesh detected that it may not be able to fully migrate the state database. This should not impact "
46+
"the migration process, but may result in unexpected changes being reported by the next `sqlmesh plan` "
47+
"command. Please run `sqlmesh diff prod` after the migration has completed, before making any new "
48+
"changes. If any unexpected changes are reported, consider running a forward-only plan to apply these "
49+
"changes and avoid unnecessary backfills: sqlmesh plan prod --forward-only. "
50+
"See https://sqlmesh.readthedocs.io/en/stable/concepts/plans/#forward-only-plans for more details.\n"
51+
)
52+
53+
for (snapshot,) in engine_adapter.fetchall(
54+
exp.select("snapshot").from_(snapshots_table), quote_identifiers=True
55+
):
56+
parsed_snapshot = json.loads(snapshot)
57+
node = parsed_snapshot["node"]
58+
59+
if node.get("source_type") == "sql":
60+
expressions = [
61+
*node.get("pre_statements", []),
62+
node["query"],
63+
*node.get("post_statements", []),
64+
]
65+
for e1, e2 in zip(expressions, expressions[1:]):
66+
if e1 == e2:
67+
get_console().log_warning(warning)
68+
return

0 commit comments

Comments
 (0)