Fixes #31790: upgrade collate-sqllineage to 2.1.7 for UPDATE and MERGE column lineage - #31885
Conversation
2.1.4 produces no column lineage for UPDATE and MERGE. Table lineage still resolves, so the gap is quiet: the graph looks populated while every column edge on those statements is missing. 2.1.7 also clears one of the sqlparse>=0.6.0 ceilings tracked in the issue. Update the lineage tests to assert the correct lineage instead of the empty result that encoded the old limitation. Two shapes are still unresolved upstream and stay marked xfail with the correct lineage asserted.
There was a problem hiding this comment.
Pull request overview
This PR upgrades the ingestion dependency collate-sqllineage to improve column-lineage extraction (notably for UPDATE/MERGE) and removes the now-redundant sqlparse override layer from the ingestion operator Docker images, updating unit tests to assert correct lineage outputs.
Changes:
- Bump
collate-sqllineagefrom2.1.4to2.1.7iningestion/setup.py. - Remove the explicit
sqlparse==0.6.0override/install gate from ingestion operator image Dockerfiles. - Update/extend lineage unit tests (including
xfailcases) to assert correctUPDATE/MERGEcolumn lineage.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| ingestion/setup.py | Upgrades collate-sqllineage pin to 2.1.7. |
| ingestion/operators/docker/Dockerfile | Removes the sqlparse override layer from the operator runtime image build. |
| ingestion/operators/docker/Dockerfile.ci | Removes the sqlparse override layer from the operator CI image build. |
| ingestion/tests/unit/lineage/queries/test_complex_query_patterns.py | Updates UPDATE/MERGE tests to assert correct column lineage; adds xfail coverage for known upstream gaps. |
| ingestion/tests/unit/lineage/queries/test_specific_dialect_queries.py | Disables SqlGlot for Postgres DDL lineage tests where it raises on unsupported statements. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
✅ Playwright Results — workflow succeededValidated commit ✅ 110 passed · ❌ 0 failed · 🟡 0 flaky · ⏭️ 0 skipped · 🧰 0 lifecycle flaky PerformanceBlocking targets: ✅ met · Optimization targets: 🟡 in progress Shard-job maxima below are not the full workflow wall time; the linked run includes build, fixture, planning, and reporting. 🕒 Full workflow signal wall (to summary) 46m 11s ⏱️ Max setup 4m 38s · max shard execution 12m 54s · max shard-job elapsed before upload 17m 44s · reporting 4s 🌐 217.03 requests/attempt · 1.79 app boots/UI scenario · 0.00% common-shard skew Optimization targets still in progress:
How to debug locally# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip # view trace |
…vention Greptile flagged that whole-test xfails also cover the table-lineage and parser checks, so an unrelated regression reports as XFAIL instead of failing. Use the per-parser flags the rest of the file already uses. merge_06 asserts the one edge all three parsers resolve, with a comment on why the two window ORDER BY edges are missing. merge_10 goes back to an empty expectation with SqlGlot and SqlParse disabled and their specific errors named, plus skip_graph_check on the table assertion since SqlGlot and SqlFluff build different internal shapes for the recursion.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (2)
ingestion/tests/unit/lineage/queries/test_complex_query_patterns.py:6343
- This block documents the semantically correct column lineage for the recursive CTE case (employees.employee_id -> reporting_chain/top_level_manager) but still asserts
[]and disables SqlGlot for column lineage. Withassert_column_lineage_equal’s exact set comparison, the test will fail if/when SqlGlot (or another parser) starts returning the correct edges (it will appear as “extra” lineage). Consider asserting the correct lineage and marking the current mismatch as an expected failure (xfail) limited to the column-lineage assertion, while keeping SqlGlot enabled so the test can start passing once the upstream behavior is fixed.
assert_column_lineage_equal(
query,
[],
dialect=Dialect.POSTGRES.value,
# SqlGlot: traces to employees but adds manager_id as a source of the chain
ingestion/tests/unit/lineage/queries/test_complex_query_patterns.py:6093
- This test currently asserts only the single
employees.salary -> employee_rankings.dept_avg_salaryedge while explicitly documenting thatsalary_rankandsalary_percentilehave no lineage “yet”. Becauseassert_column_lineage_equaldoes an exact set comparison, the test will start failing as soon as any parser begins emitting those missing edges (an improvement). If the intent is to track an upstream gap without blocking the suite (as described in the PR), consider asserting the full expected lineage and marking the current mismatch as an expected failure (xfail) scoped just to the column-lineage assertion.
This issue also appears on line 6339 of the same file.
assert_column_lineage_equal(
query,
[
(
TestColumnQualifierTuple("salary", "employees"),
Code Review ✅ ApprovedUpgrades collate-sqllineage to 2.1.7 and removes the manual sqlparse image override, resolving column lineage gaps for UPDATE and MERGE statements. No issues found. OptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (2)
ingestion/setup.py:183
- Bumping
collate-sqllineageto 2.1.7 pulls insqlparse==0.6.0, but the repo’s Airflow constraints still pinsqlparse==0.5.5(seeingestion/airflow-constraints-3.3.0.txt:649).ingestion/Dockerfile.ciinstalls the ingestion package under that constraints file (pip install "." --constraint ...), so this dependency change will make that image build fail with an unsatisfiable constraint unless the constraints pin (or its usage) is updated.
"requests>=2.32.4",
"requests-aws4auth~=1.1", # Only depends on requests as external package. Leaving as base.
"sqlalchemy>=2.0.0,<3",
"collate-sqllineage==2.1.7",
"tabulate==0.9.0",
"tenacity>=8.0,<10",
ingestion/tests/unit/lineage/queries/test_complex_query_patterns.py:6091
- PR description says the window-function and recursive-CTE UPDATE cases are asserted with correct lineage and marked
xfail(strict=False), but this test file contains no xfail markers and currently asserts only the partial lineage that the parsers emit (or[]). If the intent is to surface XPASS when upstream fixes these, these tests need an explicit xfail + the correct expected lineage; otherwise the PR description should be updated to match the actual strategy.
# All three window expressions read employees.salary through the "ranked" subquery.
# Only AVG(salary) resolves, because it reads salary as a function argument. RANK()
# and PERCENT_RANK() read it through OVER (ORDER BY salary), which no parser treats
# as a source column, so salary_rank and salary_percentile have no edge yet.
assert_column_lineage_equal(
query,
[
|



Describe your changes:
Fixes #31790
I upgraded
collate-sqllineagefrom 2.1.4 to 2.1.7 and removed thesqlparseoverride layer from the ingestion operator images, because 2.1.7 declaressqlparse==0.6.0as a real dependency so the resolver now does the job the override was doing by hand.That closes #31790. All four advisories (CVE-2026-54284, CVE-2026-59893, CVE-2026-71491, CVE-2026-59894) are fixed only in sqlparse 0.6.0, and 2.1.7 is the first collate-sqllineage release that both pins 0.6.0 and is co-installable with dbt-core. Of the three ceilings the issue lists, collate-sqllineage's own pin is lifted by this upgrade, and dbt-core's resolved upstream in 1.12.3 (
sqlparse<0.7.0,>=0.5.5), which pip now selects on its own with no floor needed here.The override is deleted rather than kept as belt-and-braces because it was
pip install --no-depsplus a fail-closed import gate: it printed a resolver-conflict ERROR on every build and leftpip checkpermanently unsatisfied. With the dependency declared properly none of that is needed, and leaving it in place would keep the noise for no benefit.2.1.7 also fixes real lineage bugs. 2.1.4 produces no column lineage at all for
UPDATEandMERGE. Table lineage still resolves, so the gap is quiet: the graph looks populated while every column edge on those statements is missing. Two regressions that shipped in 2.1.6 were found while validating this upgrade and are fixed in 2.1.7: SqlParse returned hash-order dependent column lineage for UPDATE, and SqlGlot leaked the UPDATE target alias into the graph as a phantom table. 2.1.7 additionally resolves JOIN and CTE aliases inUPDATE ... FROM, closing a case where SqlGlot returned empty column lineage while SqlFluff and SqlParse both resolved it correctly. That one lost lineage in production, sinceLineageParsertakes the first parser that does not raise and SqlGlot was neither raising nor producing anything.Type of change:
High-level design:
The tests are the substantive part of this PR.
They previously asserted
[]for these statements, which documented the 2.1.4 limitation rather than the correct answer. They now assert the semantically correct and complete column lineage, with any parser that cannot produce it disabled and the reason recorded inline. Where no parser produces the correct lineage the test asserts it anyway and is markedxfail(strict=False), so it reports XPASS the moment upstream closes the gap rather than silently continuing to pass on a wrong expectation.That direction was chosen over the alternative of asserting whatever the parsers currently emit. Several parser outputs here are wrong rather than merely incomplete (wildcard edges, a target column named after an aggregate expression), and freezing those into expectations would make the suite defend the bugs.
Tests:
Use cases covered
UPDATE ... FROM <cte>, resolved through the CTE to the base tableUPDATE ... FROM (subquery) JOIN ..., including the joined table sourceUPDATEwith correlated subqueries inSETUPDATEwhoseSETexpression reads the target's own aliasSET client_min_messages=noticeand similar DDL, which correctly yields no lineageUnit tests
ingestion/tests/unit/lineage/queries/test_complex_query_patterns.pyingestion/tests/unit/lineage/queries/test_specific_dialect_queries.pyResult against the published 2.1.7, stable across
PYTHONHASHSEED0/1/42/2024:The 2.1.4 baseline was
386 passed, which reconciles as 384 passed plus the 2 xfailed.Five tests that previously asserted
[]now assert real lineage and pass:test_update_with_join_and_cteprice_historytraced through the CTEtest_update_merge_01_update_with_join_and_column_mappinglatest_prices.new_price -> products.current_price -> products.price_change_percent, which exercises the alias fixtest_update_merge_02_update_with_ctesalestraced through the CTEtest_update_merge_04_update_from_multiple_tablessales.quantityand the joinedsuppliers.lead_time_daystest_update_merge_08_update_with_correlated_subqueryreviewscolumn to its ownproductscolumnPer-parser skips across these seven tests dropped from 17 to 7, and
test_update_with_join_and_cteandtest_update_merge_02_update_with_cteare now fully skip free: all three parsers enabled, cross-parser graph check enabled.Two remain
xfail(strict=False)with the correct lineage asserted, so they surface as XPASS once upstream closes them:test_update_merge_06_update_with_window_functions: columns read throughOVER (ORDER BY salary)produce no edge on any parser. OnlyAVG(salary), which reads it as a function argument, resolves.test_update_merge_10_update_with_recursive_cte: SqlGlot traces the recursive CTE but over-reports, SqlFluff produces nothing, SqlParse stops at the CTE.Backend integration tests
Ingestion integration tests
Playwright (UI) tests
Manual testing performed
sqlparse==0.6.0,requires_python>=3.10, so the image override is redundant.PYTHONHASHSEEDvalues to confirm the non-determinism is gone. Failure counts on 2.1.6 varied run to run; on 2.1.7 they are identical every run.LineageParserend to end thatUPDATE ... FROM <cte>now returns column edges instead of an empty result.UI screen recording / screenshots:
Not applicable.
Checklist:
Fixes <issue-number>: <short explanation>Fixes #<issue-number>above.Greptile Summary
The PR upgrades
collate-sqllineageand removes the ingestion-operator images’ manualsqlparseoverride. It also updates lineage expectations for UPDATE statements and adjusts parser participation where implementations still disagree.collate-sqllineagefrom 2.1.4 to 2.1.7.sqlparseinstallation and build-time parser gate from both operator Dockerfiles.Confidence Score: 5/5
The PR appears safe to merge because no blocking failure remains from the previously reported issue.
No blocking failure remains.
Important Files Changed
collate-sqllineageto 2.1.7.sqlparseoverride and its build-time validation gate.Reviews (3): Last reviewed commit: "Merge branch 'main' into upgrade-collate..." | Re-trigger Greptile