sql-code-graph 1.35.1__tar.gz → 1.35.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/PKG-INFO +1 -1
- sql_code_graph-1.35.2/plan/metrics/pr_c_merge_after.json +31 -0
- sql_code_graph-1.35.2/plan/metrics/pr_c_merge_before.json +31 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/pyproject.toml +1 -1
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/__init__.py +1 -1
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/parsers/base.py +193 -18
- sql_code_graph-1.35.2/src/sqlcg/parsers/dynamic_name.py +170 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_skip_counts_integration.py +12 -10
- sql_code_graph-1.35.2/tests/snowflake/E16/test_e16.py +59 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/test_plan_review_gates.py +9 -12
- sql_code_graph-1.35.2/tests/unit/test_dynamic_name_resolution.py +148 -0
- sql_code_graph-1.35.2/tests/unit/test_merge_column_lineage.py +154 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/uv.lock +1 -1
- sql_code_graph-1.35.1/tests/snowflake/E16/test_e16.py +0 -51
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.claude/agents/api-documenter.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.claude/agents/architect-planner.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.claude/agents/architect-reviewer.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.claude/agents/code-reviewer.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.claude/agents/developer.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.claude/agents/plan-reviewer.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.claude/agents/sprint-planner.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.github/workflows/benchmark.yml +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.github/workflows/e2e-tests.yml +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.github/workflows/release.yml +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.github/workflows/test.yml +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.gitignore +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.pre-commit-config.yaml +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/.sqlcgignore +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/ARCHITECTURE_REVIEW.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/ARCHITECTURE_REVIEW_ARCHIVE.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/CHANGELOG.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/CLAUDE.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/README.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/docs/AIRBNB_PARSE_REPORT.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/docs/cli.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/docs/getting-started.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/docs/releasing-pypi.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/e2e_firstuser_report.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/e2e_run_20260528_101413.output +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/main.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/WORKFLOW.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/measurements/pr2_catalog_load_eval.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/measurements/pr3_repo_native_plateau.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/measurements/pr4_transform_kinds.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/measurements/pr5_extraction_recall_taxonomy.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/measurements/sprint_08_changelogs_fullindex.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/measurements/sprint_08_fullcorpus_index.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/createkind_dwh_after.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/createkind_dwh_before.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/gain_1.29.0_05c6943.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/gain_1.30.0_2c8ac25.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/gain_1.30.1_26271fc.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/gain_1.31.0_a40c837.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/gain_1.32.0_c1bec3c.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/lineage5_dwh_after_pr5.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/lineage5_dwh_before_master.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/pr4_star_promote_after.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/pr4_star_promote_before.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/pr_b_phantom_after.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/pr_b_phantom_before.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/schema_comparison_with_schema.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/schema_comparison_without_schema.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/sprint_08_changelogs_fullindex.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/sprint_08_fullcorpus_index.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/metrics/sprint_pool_300s_plan.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/column_coverage_diagnostic.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/column_coverage_findings.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/dwh_graph_analysis.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/dwh_positional_insert_column_blindspot.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/feature_acceptance_dwh.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/graph_health_sprint_postmortem.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/island_lever_live_verification.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/issue38_pr2_live_acceptance.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/issue38_pr3_live_acceptance.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/lineage_identity_sprint_postmortem.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/pr_impact_followups_2026-06-14.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/sprint_03_v0.3.1_postmortem.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/sprint_3.1_postmortem.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/reports/v1_14_dialect_query_config_postmortem.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/research/blueprint.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/research/coverage_parse_failure_diagnosis.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/research/investigation_e5_e4.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/research/observed_usage_overlay_query_history_tableau.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/research/parse_diagnostics.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/research/parsing_errors_experiment.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/research/snowflake_en_test_suite.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/research/sql_only_coverage_lever_post_pr2.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/research/sqlcg.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/bundle_claude_skill.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/ci_tests_pool_flake_fix.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/column_lineage_recall_metric.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/coverage_p1_p3_p4.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/coverage_p1_p5_metric.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/coverage_parse_failures.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/diff-impact-producer-file.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/e8_dual_emission.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/feature_34_unused_presentation_segregation.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/feature_35_external_downstream_injection.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/feature_F2_bundle_claude_skill.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/feature_kuzu_to_duckdb_migration.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/fix_backward_self_heal_index_at_sha.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/fix_downstream_sink_location.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/fix_dynamic_table_parsing.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/fix_expand_qualify_perf.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/fix_firstuser_findings.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/fix_issue29_live_test_followups.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/fix_schema_case_mismatch.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/gain_coverage_metrics.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/graph_health_catalog_and_metrics.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/hygiene_config_path_and_survivors.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/issue-38-backfill-cte-bridge.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/issue-38-residual-source-extraction.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/issue-38-selects-from-island-lever.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/living_codebase_resync.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/mcp_server_self_healing.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/positional_insert_clone_blindspot.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_01.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_01_deployment_pypi.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_02.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_02_v0.3.0_core.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_03.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_04_column_lineage.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_04_column_lineage_fix.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_05_star_resolution.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_06_lineage_coverage.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_07_open_ecodes.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_07_perf_and_live_test.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_08_perf_upsert.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_09_lineage_coverage.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_10_anchor_tools.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_11_v1.0.2_bugfix.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_12_v1.1.0.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_13_v1.1.0_cluster_b.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_lineage_identity_and_session_context.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/sprint_postmortem_fixes.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/temp_table_namespacing.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/trust_layer.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/unfilled_table_impact.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/v1.1.0_cluster_b_provenance_trust.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/v1.1.0_live_graph_freshness.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/v1.1.1_batch_upsert_perf.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/v1.14.0_dialect_and_query_config_fixes.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/v1_1_2_bugfix.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/v1_1_3_union_cte_star.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/v1_2_0_read_proxy.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/v1_2_1_bugfix.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/plan/sprints/version-parity-and-restart.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/profile.html +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/pyrightconfig.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/scripts/collect_parse_errors.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/scripts/column_coverage_check.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/scripts/generate_cli_docs.sh +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/__main__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/analyze.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/catalog.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/db.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/find.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/gain.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/git.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/index.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/install.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/mcp.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/reindex.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/report.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/uninstall.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/viz.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/commands/watch.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/coverage.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/cli/main.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/config.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/duckdb_backend.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/freshness.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/graph_db.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/jobs.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/noise_match.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/queries.cypher +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/queries.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/queries.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/schema.cypher +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/core/schema.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/indexer/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/indexer/dbt_adapter.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/indexer/error_classify.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/indexer/git_delta.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/indexer/indexer.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/indexer/pool.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/indexer/walker.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/indexer/watcher.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/lineage/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/lineage/aggregator.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/lineage/schema_resolver.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/metrics/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/metrics/store.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/parsers/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/parsers/ansi_parser.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/parsers/bigquery_parser.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/parsers/postgres_parser.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/parsers/registry.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/parsers/snowflake_parser.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/parsers/tsql_parser.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/control.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/exceptions.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/models.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/noise_filter.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/read_client.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/selfheal.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/server.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/skill.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/tools.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/server/writer.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/utils/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/utils/hashing.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/utils/ignore.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/utils/logging.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/viz/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/viz/assets/force-graph.min.js +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/viz/assets/template.html +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/viz/data.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/viz/render.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/src/sqlcg/viz/tags.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/adversarial/200_join.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/adversarial/500_union.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/bench_indexer.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/conftest.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/case_normalization.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/colon_cast.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/colon_reserved_word.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/copy_into.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/create_procedure.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/identifier_dynamic.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/lateral_flatten.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/qualify.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/scripting_block.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/golden_corpus/snowflake/three_part.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/tpch/q01.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/tpch/q02.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/tpch/q03.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/tpch/q04.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/benchmarks/tpch/q05.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/conftest.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/conftest.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_F2_skill_install_e2e.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_airbnb_e2e.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_cli_index.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_empty_impact_cli_e2e.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_git_hook_install.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_golden_lineage.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_mcp_lifecycle.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_mcp_tools.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_parse_diagnostics_cli.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_pr_impact_cli_e2e.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_selfheal_e2e.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_star_resolution_e2e.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_viz_cli_e2e.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/e2e/test_watch.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/dim_hosts_cleansed.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/dim_listings_cleansed.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/fct_reviews.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/mart_fullmoon_reviews.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/raw_hosts.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/raw_listings.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/raw_reviews.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/src_hosts.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/src_listings.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/airbnb/src_reviews.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/bigquery/.gitkeep +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/duckdb_parity/kuzu_reference.json +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/jaffle_shop/customers.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/jaffle_shop/orders.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/jaffle_shop/raw_orders.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/snowflake/base_tables.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/snowflake/reports.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/snowflake/views.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/star_corpus/ddl_src.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/star_corpus/ddl_tgt.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/star_corpus/etl_alias_star.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/star_corpus/etl_star.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/synthetic/base_tables.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/synthetic/reports.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/fixtures/synthetic/views.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/snowflake/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/snowflake/test_insert_select.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/snowflake/test_qualify_bare_tables_command_guard_integration.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_T34_presentation_segregation.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_T35_external_consumers.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_analyze_case_fold.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_anchor_tools.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_backfill_impact_consistency.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_bare_column_cte_lineage.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_bulk_upsert.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_case_split_seed_regression.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_catalog_kind_upgrade.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_catalog_load_integration.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_cli_index_clear_before_rebuild.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_column_coverage_patterns.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_column_lineage_e2e.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_coverage_metrics_integration.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_cross_file_lineage.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_cte_key_namespacing_integration.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_cte_recall_guard.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_cte_schema_alias_guard.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_cte_source_node_invariant.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_dialect_auto_resolution.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_dialect_matrix.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_duckdb_parity.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_e36_xfile_regression_guard.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_empty_impact_blast_radius.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_empty_index_rollback_guard.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_freshness_mcp.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_gating_join_retrofit.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_hygiene_config_root_reconciliation.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_identity_counters_integration.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_impact_consumer_parity.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_index_degraded_files_metric.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_index_filter_node_exclusion.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_indexer_batching.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_indexer_commits.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_indexer_to_graph.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_issue38_cte_insert_regression.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_join_col_resolution.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_key_normalization_chokepoint.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_live_anchors.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_mvcc_rebuild.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_non_table_create_coverage_no_regression.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_non_table_create_kind_in_graph.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_parse_diagnostics.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_phantom_non_table_create_node.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_pr1_confidence_reason.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_pr2_source_location.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_pr3_kind_tagging.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_pr_impact_integration.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_qualify_failed_persist.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_read_via_server.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_readonly_under_lock.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_reindex_via_server.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_repo_relative_cte_namespaces.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_resolvable_write_col_edges_integration.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_resync.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_selects_from_completeness.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_selects_from_cte_body_source.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_selects_from_subscope_source.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_single_writer_queue.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_star_promote_temp_columns.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_star_resolution.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_temp_table_lineage.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_temp_table_namespacing.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_tool_version_stamp_integration.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_union_cte_star_recall_guard.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_usage_derived_catalog.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_use_schema_session_context_integration.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_user_surface_recall_guard.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_v141_surface_guards.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_v1_14_0_dialect_and_query_config_fixes.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_view_kind_in_graph.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_viz_data_build.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_write_memory_ceiling.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/perf/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/perf/test_perf.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E10/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E11/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E12/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E12/e12_json_path.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E12/e12_lateral_flatten.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E12/test_e12.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E13/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E14/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E15/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E16/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E16/e16_merge.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E16/e16_merge_delete.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E17/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E18/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E18/e18_decode.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E18/e18_iff_decode.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E18/e18_nvl2.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E18/test_e18.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E19/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E2/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E2/e2_expr_alias.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E2/e2_function_alias.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E2/e2_multiply_alias.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E2/test_e2.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E20/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E21/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E21/e21_alias_forward_ref.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E21/e21_three_level_chain.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E21/test_e21.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E22/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E23/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E23/e23_stored_proc.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E23/e23_stored_proc_multi.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E23/test_e23.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E24/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E25/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E25/e25_cross_db.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E25/e25_two_part.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E25/test_e25.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E25/test_e25_full_id.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E26/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E27/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E27/e27_nested_udf.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E27/e27_udf.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E27/test_e27.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E28/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E29/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E3/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E3/e3_alter_table.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E3/e3_create_sequence.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E3/e3_ddl_only.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E3/test_e3.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E30/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E31/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E32/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E33/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E34/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E35/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E36/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E36/e36_temp_multi_use.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E36/e36_temp_table.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E36/test_e36.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E36/test_e36_xfile.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E37/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E38/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E4/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E4/e4_execute_immediate.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E4/e4_if_not_exists.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E4/e4_unexpected_token.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E4/e4_unpivot.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E4/test_e4.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E5/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E5/e5_cte_missing_source.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E5/e5_multi_cte.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E5/e5_nested_cte.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E5/test_e5.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E5/test_e5_cte_projection.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E8/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E8/e8_dynamic_sources.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E8/e8_seq_nextval.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E8/e8_uuid.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E8/test_e8.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E9/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_aggregates/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_aggregates/fixture_sum_absent_cross_schema.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_aggregates/fixture_sum_case_when.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_aggregates/fixture_sum_present_source.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_aggregates/test_e_aggregates.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_date_functions/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_date_functions/fixture_date_aliased.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_date_functions/fixture_date_unaliased.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_date_functions/fixture_datediff_unaliased.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_date_functions/fixture_year_unaliased.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/E_date_functions/test_e_date_functions.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/README.md +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/anchors/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/anchors/fixture_etl.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/anchors/fixture_omloopsnelheid.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/anchors/fixture_semantic.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/anchors/fixture_source.sql +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/anchors/test_anchor_ma_aantal_op_order.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/anchors/test_anchor_omloopsnelheid.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/snowflake/conftest.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/snowflake/__init__.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/snowflake/test_qualify_bare_tables_command_guard.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/snowflake/test_scripting_noise.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_BugB_escalation_uses_init_path.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_BugC_hook_upgrade.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_F2_install_skill.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_F2_skill_render.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_F2_uninstall_skill.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_T09_01_qualify_once.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_T09_02_ddl_skip.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_T09_04_subprocess_isolate.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_T09_06_log_verbosity.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_T35_config_external_consumers.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_aggregator.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_aggregator_skip.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_analyze_case_fold.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_base_parser.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_branch_monitor.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_bulk_upsert_invariant.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_canonical_target_resolution.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_catalog_csv_parsing.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_catalog_missing_warning.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_classify_non_table_create_kind.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_cli.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_cli_doc_flag_staleness.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_cli_help.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_clone_positional_insert_blindspot.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_closure_depth.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_column_lineage_wiring.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_config.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_coverage_metrics.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_cte_key_namespacing.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_cte_source_gap_metric.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_data_models.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_db_info.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_db_info_coverage.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_db_path_isolation_fixture.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_doc_links.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_doc_markdown_link_existence.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_dominant_cause.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_duckdb_backend.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_duckdb_backend_shared.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_e5_view_alias_resolution.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_e8_dual_emission.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_e8_temp_chain_key_mismatch.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_empty_propagation_unit.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_extract_select_output_columns.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_file_ignore_defaults.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_find_cmd.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_firstuser_findings.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_freshness_helper.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_gain_coverage.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_gain_ratio.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_gating_join_field_docstrings.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_git_delta.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_git_hooks.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_git_hooks_notify.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_graph_backend.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_graph_completeness_invariant.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_hard_kill_pool.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_has_column_precedence_upsert.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_hook_reindex_detach.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_hygiene_config_warning.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_identity_counters.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_include_working_tree.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_index_cmd.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_index_filter_config.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_index_flags.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_index_progress.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_index_summary_degraded_metric.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_indexer_progress.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_indexer_quality.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_install.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_install_message.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_issue_63_readonly_lock.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_jobs.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_join_col_resolve_marker.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_judgement.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_lineage_conversion.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_literal_column_skip.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_mcp_best_practices.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_mcp_control.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_mcp_stdio_smoke.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_metrics.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_noise_filter.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_normalize_keys.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_parse_failed_classification.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_parse_file_dependency_filter.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_parse_quality.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_parser.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_perf_scaling_guard.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_phantom_non_table_create_source.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_pr07_observability.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_pr6_execute_immediate_unwrap.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_pr_impact_unit.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_qualify_failed_unit.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_queries_loader.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_read_client.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_repo_relative_cte_namespaces.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_resolvable_write_col_edges_unit.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_resolve_join_columns_sql.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_resolve_pass2_passes_dependency_filter.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_schema_resolver.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_selects_from_completeness_unit.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_selfheal_detector.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_selfheal_pr1_messages.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_selfheal_reexec.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_selfheal_watcher.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_server.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_skip_counts_persistence.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_snowflake_strip_alter_set_tag.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_sprint_06_t04_t05.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_star_resolution_unit.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_star_schema_unit.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_submit_feedback.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_subprocess_isolate.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_t02_expression_name_extraction.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_t03_ddl_skip.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_temp_table_namespacing.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_timeout_cancel.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_tool_version_stamp.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_tools_hints.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_tools_warnings.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_transform_kind_classification.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_uninstall.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_unknown_sentinel_skip.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_unqualified_fallback.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_upsert_batch_invariant.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_use_schema_session_context.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_version_parity.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_view_classification.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_viz_config_schemas.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_viz_facets.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_viz_render_self_contained.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_walker.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_watcher.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_worker_error_classification.py +0 -0
- {sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/unit/test_writer_queue.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sql-code-graph
|
|
3
|
-
Version: 1.35.
|
|
3
|
+
Version: 1.35.2
|
|
4
4
|
Summary: SQL code graph analyzer and lineage tracer
|
|
5
5
|
Project-URL: Homepage, https://github.com/Warhorze/sql-code-graph
|
|
6
6
|
Project-URL: Repository, https://github.com/Warhorze/sql-code-graph
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{"total_calls": 1616, "last_7d_calls": 1616, "index_runs": 5, "feedback_tp": 0,
|
|
2
|
+
"feedback_total": 0, "top_tools": [{"name": "execute_sql", "count": 544},
|
|
3
|
+
{"name": "trace_column_lineage", "count": 425}, {"name":
|
|
4
|
+
"list_dialects_and_repos", "count": 139}], "execute_sql_ratio": 0.34,
|
|
5
|
+
"parse_quality": {"sqlglot": 5166, "scripting": 20, "dynamic_sql": 3},
|
|
6
|
+
"coverage": {"catalogued_tables": 5800, "total_tables": 6552, "good_edges":
|
|
7
|
+
52678, "total_edges": 60826, "phantom_edges": 12241, "blindspot_tables": 628,
|
|
8
|
+
"good_edges_strict": 48151, "edge_health_strict_pct": 79.16,
|
|
9
|
+
"good_edges_scoped": 37471, "total_edges_scoped": 38020,
|
|
10
|
+
"edge_health_scoped_pct": 98.56, "phantom_confirmed": 11701,
|
|
11
|
+
"phantom_contradicted": 352, "phantom_unverified": 188, "top_blindspot_tables":
|
|
12
|
+
[{"table": "ba.wtfa_kpi_datum_klant", "bad_edges": 70}, {"table":
|
|
13
|
+
"ba.wtfs_voorraad_dagstand", "bad_edges": 55}, {"table":
|
|
14
|
+
"ba.wtfs_voorraad_zondagstand", "bad_edges": 55}, {"table":
|
|
15
|
+
"da.rtgmd_postnl_customer_usage", "bad_edges": 43}, {"table":
|
|
16
|
+
"da.rtgmd_postnl_athome_3s", "bad_edges": 33}, {"table":
|
|
17
|
+
"wtfe_kpi_voorraad_artikel_voorraadlocatie", "bad_edges": 32}, {"table":
|
|
18
|
+
"da.rtgmd_postnl_facturen", "bad_edges": 30}, {"table": "da.hthyb_pages",
|
|
19
|
+
"bad_edges": 23}, {"table": "da.rtgmd_dhb_extra_kosten", "bad_edges": 19},
|
|
20
|
+
{"table": "da.hthyb_page_brandplacement", "bad_edges": 17}],
|
|
21
|
+
"blindspot_tables_for_80pct": 17, "files_indexed": 1335, "indexed_sha":
|
|
22
|
+
"fdf1b551a34601a6cf3ce1c8b9f76e27ce2753e6", "db_path": "/tmp/mergec_after.db",
|
|
23
|
+
"index_timestamp": 1781470021.8137639, "degraded_parse_total": 5189,
|
|
24
|
+
"degraded_parse_queries": 27, "degraded_parse_by_dir": {"etl": {"degraded": 8,
|
|
25
|
+
"total": 2776}, "ddl": {"degraded": 19, "total": 2413}},
|
|
26
|
+
"zero_edge_write_queries": 1028, "total_write_queries": 2323,
|
|
27
|
+
"cte_key_collisions": 0, "rescuable_unqualified_edges": 125,
|
|
28
|
+
"info_schema_has_column_rows": 100193, "cte_source_gap_writes": 0,
|
|
29
|
+
"resolvable_write_col_edges": 36936, "transitive_col_edges": 4178,
|
|
30
|
+
"qualify_failed_statements": 9, "tool_version_stale": false,
|
|
31
|
+
"indexed_tool_version": "1.35.2", "running_tool_version": "1.35.2"}}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{"total_calls": 1616, "last_7d_calls": 1616, "index_runs": 5, "feedback_tp": 0,
|
|
2
|
+
"feedback_total": 0, "top_tools": [{"name": "execute_sql", "count": 544},
|
|
3
|
+
{"name": "trace_column_lineage", "count": 425}, {"name":
|
|
4
|
+
"list_dialects_and_repos", "count": 139}], "execute_sql_ratio": 0.34,
|
|
5
|
+
"parse_quality": {"sqlglot": 5166, "scripting": 20, "dynamic_sql": 3},
|
|
6
|
+
"coverage": {"catalogued_tables": 5800, "total_tables": 6552, "good_edges":
|
|
7
|
+
52671, "total_edges": 60819, "phantom_edges": 12241, "blindspot_tables": 628,
|
|
8
|
+
"good_edges_strict": 48140, "edge_health_strict_pct": 79.15,
|
|
9
|
+
"good_edges_scoped": 37460, "total_edges_scoped": 38009,
|
|
10
|
+
"edge_health_scoped_pct": 98.56, "phantom_confirmed": 11701,
|
|
11
|
+
"phantom_contradicted": 352, "phantom_unverified": 188, "top_blindspot_tables":
|
|
12
|
+
[{"table": "ba.wtfa_kpi_datum_klant", "bad_edges": 70}, {"table":
|
|
13
|
+
"ba.wtfs_voorraad_dagstand", "bad_edges": 55}, {"table":
|
|
14
|
+
"ba.wtfs_voorraad_zondagstand", "bad_edges": 55}, {"table":
|
|
15
|
+
"da.rtgmd_postnl_customer_usage", "bad_edges": 43}, {"table":
|
|
16
|
+
"da.rtgmd_postnl_athome_3s", "bad_edges": 33}, {"table":
|
|
17
|
+
"wtfe_kpi_voorraad_artikel_voorraadlocatie", "bad_edges": 32}, {"table":
|
|
18
|
+
"da.rtgmd_postnl_facturen", "bad_edges": 30}, {"table": "da.hthyb_pages",
|
|
19
|
+
"bad_edges": 23}, {"table": "da.rtgmd_dhb_extra_kosten", "bad_edges": 19},
|
|
20
|
+
{"table": "da.hthyb_page_brandplacement", "bad_edges": 17}],
|
|
21
|
+
"blindspot_tables_for_80pct": 17, "files_indexed": 1335, "indexed_sha":
|
|
22
|
+
"fdf1b551a34601a6cf3ce1c8b9f76e27ce2753e6", "db_path": "/tmp/mergec_before.db",
|
|
23
|
+
"index_timestamp": 1781469837.2725205, "degraded_parse_total": 5189,
|
|
24
|
+
"degraded_parse_queries": 20, "degraded_parse_by_dir": {"etl": {"degraded": 1,
|
|
25
|
+
"total": 2776}, "ddl": {"degraded": 19, "total": 2413}},
|
|
26
|
+
"zero_edge_write_queries": 1034, "total_write_queries": 2323,
|
|
27
|
+
"cte_key_collisions": 0, "rescuable_unqualified_edges": 125,
|
|
28
|
+
"info_schema_has_column_rows": 100193, "cte_source_gap_writes": 0,
|
|
29
|
+
"resolvable_write_col_edges": 36936, "transitive_col_edges": 4182,
|
|
30
|
+
"qualify_failed_statements": 9, "tool_version_stale": false,
|
|
31
|
+
"indexed_tool_version": "1.35.1", "running_tool_version": "1.35.1"}}
|
|
@@ -637,12 +637,14 @@ class SqlParser(ABC):
|
|
|
637
637
|
"""Return True if `_extract_column_lineage` would attempt extraction for `stmt`.
|
|
638
638
|
|
|
639
639
|
Mirrors the type/body checks `_extract_column_lineage` (below, this class)
|
|
640
|
-
already performs: only `exp.Select`, `exp.Insert` with a `SELECT` body,
|
|
641
|
-
`exp.Create` with a `Select`/`Subquery` body (CTAS / CREATE VIEW AS SELECT)
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
640
|
+
already performs: only `exp.Select`, `exp.Insert` with a `SELECT` body,
|
|
641
|
+
`exp.Create` with a `Select`/`Subquery` body (CTAS / CREATE VIEW AS SELECT),
|
|
642
|
+
and `exp.Merge` (column edges extracted structurally from its WHEN clauses —
|
|
643
|
+
see `_extract_merge_lineage`, plan/sprints/sprint_snowflake_lineage_patterns.md
|
|
644
|
+
PR-C) can ever produce column-lineage edges. Everything else (Update, Delete,
|
|
645
|
+
Use, Set, Comment, Drop, Alter, Command, TruncateTable, CREATE ...
|
|
646
|
+
LIKE/CLONE/column-defs, INSERT ... VALUES) is structurally lineage-free
|
|
647
|
+
regardless of `build_scope`'s outcome.
|
|
646
648
|
|
|
647
649
|
Used by `AnsiParser._parse_statement` to avoid marking `parse_failed=True`
|
|
648
650
|
for statement kinds that were never going to produce column lineage in the
|
|
@@ -658,8 +660,185 @@ class SqlParser(ABC):
|
|
|
658
660
|
return isinstance(stmt.expression, exp.Select)
|
|
659
661
|
if isinstance(stmt, exp.Create):
|
|
660
662
|
return isinstance(stmt.expression, (exp.Select, exp.Subquery))
|
|
663
|
+
if isinstance(stmt, exp.Merge):
|
|
664
|
+
return True
|
|
661
665
|
return False
|
|
662
666
|
|
|
667
|
+
def _extract_merge_lineage(
|
|
668
|
+
self,
|
|
669
|
+
stmt: Any,
|
|
670
|
+
dst_table: "TableRef | None",
|
|
671
|
+
query_sources: list["TableRef"] | None,
|
|
672
|
+
out: ParsedFile,
|
|
673
|
+
) -> list[LineageEdge]:
|
|
674
|
+
"""Extract column-level lineage from a MERGE statement's WHEN clauses.
|
|
675
|
+
|
|
676
|
+
MERGE column edges cannot come from sqlglot's ``lineage()`` (it does not model
|
|
677
|
+
MERGE branches), but the ``WHEN MATCHED ... UPDATE SET`` and
|
|
678
|
+
``WHEN NOT MATCHED ... INSERT (cols) VALUES (vals)`` clauses are structurally
|
|
679
|
+
extractable by a direct AST walk. This method performs that walk: it is bounded
|
|
680
|
+
and runs ONCE PER MERGE statement — it NEVER calls ``sg_lineage``, ``qualify``,
|
|
681
|
+
``build_scope`` or ``exp.expand`` (AC-C7,
|
|
682
|
+
plan/sprints/sprint_snowflake_lineage_patterns.md PR-C).
|
|
683
|
+
|
|
684
|
+
Resolution model:
|
|
685
|
+
- The MERGE target (``stmt.this``) and source (``stmt.args['using']``) are both
|
|
686
|
+
captured in ``query_sources`` as already-qualified TableRefs (the table-grain
|
|
687
|
+
path does NOT split them into target/sources for MERGE — ``dst_table`` is
|
|
688
|
+
``None`` here, so AC-C3's shipped table-grain behaviour is preserved). This
|
|
689
|
+
method matches ``stmt.this``/``using`` back to those refs by alias+name to
|
|
690
|
+
identify which is the target and which the source(s), then builds an
|
|
691
|
+
alias -> TableRef map over both.
|
|
692
|
+
- MATCHED UPDATE: each ``exp.EQ`` is ``target_col = source_expr``; the dst is a
|
|
693
|
+
column on the target, the src columns are every ``exp.Column`` in the RHS
|
|
694
|
+
(multi-source expressions emit one edge per source column — AC-C4). A
|
|
695
|
+
pure-literal RHS (no ``exp.Column``) contributes no edge (AC-C5) — mirrors the
|
|
696
|
+
pure-literal skip invariant.
|
|
697
|
+
- NOT MATCHED INSERT: ``then.this`` is the target column tuple, ``then.expression``
|
|
698
|
+
the values tuple; zip positionally and emit per source column. An INSERT with
|
|
699
|
+
no column list (``then.this is None``) is skip-and-logged
|
|
700
|
+
(``col_lineage_skip:merge_no_collist:``) — NO positional DDL fallback (gate
|
|
701
|
+
decision: positional guessing risks wrong edges).
|
|
702
|
+
|
|
703
|
+
Args:
|
|
704
|
+
stmt: the ``exp.Merge`` AST node.
|
|
705
|
+
dst_table: the resolved INSERT/CREATE target TableRef from the caller. For
|
|
706
|
+
MERGE this is ``None`` (the table-grain path leaves the target in
|
|
707
|
+
``query_sources``); the target is recovered here from ``stmt.this``.
|
|
708
|
+
query_sources: resolved table refs for the MERGE (target + ``USING``
|
|
709
|
+
source(s)), each carrying its ``.alias``, fully qualified.
|
|
710
|
+
out: ParsedFile, for skip/unresolved error records.
|
|
711
|
+
|
|
712
|
+
Returns:
|
|
713
|
+
List of LineageEdge (may be empty).
|
|
714
|
+
"""
|
|
715
|
+
import sqlglot.expressions as exp
|
|
716
|
+
|
|
717
|
+
edges: list[LineageEdge] = []
|
|
718
|
+
refs = list(query_sources or [])
|
|
719
|
+
if dst_table is not None:
|
|
720
|
+
refs.append(dst_table)
|
|
721
|
+
|
|
722
|
+
# Identify the MERGE target ref by matching stmt.this against the resolved refs.
|
|
723
|
+
# `_real_tables` does not preserve the AST alias on the TableRef, so match on the
|
|
724
|
+
# AST target's name (and alias, as a fallback) against each ref's name/alias.
|
|
725
|
+
# The remaining refs are the USING source(s).
|
|
726
|
+
target_ast = stmt.this if isinstance(stmt.this, exp.Table) else None
|
|
727
|
+
target_keys: set[str] = set()
|
|
728
|
+
if target_ast is not None:
|
|
729
|
+
if target_ast.name:
|
|
730
|
+
target_keys.add(target_ast.name.lower())
|
|
731
|
+
if target_ast.alias:
|
|
732
|
+
target_keys.add(target_ast.alias.lower())
|
|
733
|
+
|
|
734
|
+
def _ref_keys(ref: TableRef) -> set[str]:
|
|
735
|
+
keys: set[str] = set()
|
|
736
|
+
if ref.alias:
|
|
737
|
+
keys.add(ref.alias.lower())
|
|
738
|
+
if ref.name:
|
|
739
|
+
keys.add(ref.name.lower())
|
|
740
|
+
return keys
|
|
741
|
+
|
|
742
|
+
target_ref: TableRef | None = None
|
|
743
|
+
if target_keys:
|
|
744
|
+
for ref in refs:
|
|
745
|
+
if target_keys & _ref_keys(ref):
|
|
746
|
+
target_ref = ref
|
|
747
|
+
break
|
|
748
|
+
if target_ref is None:
|
|
749
|
+
label = ".".join(sorted(target_keys)) or "<unknown>"
|
|
750
|
+
out.errors.append(f"col_lineage_skip:merge_no_target:{label}")
|
|
751
|
+
return edges
|
|
752
|
+
|
|
753
|
+
source_refs = [r for r in refs if r is not target_ref]
|
|
754
|
+
|
|
755
|
+
# Build an alias/name -> TableRef map over the target + USING source(s).
|
|
756
|
+
# MERGE column references qualify by the table alias (e.g. `target.name`,
|
|
757
|
+
# `s.name`). `_real_tables` strips the alias from the resolved TableRef, so the
|
|
758
|
+
# alias is recovered from the AST nodes (target=stmt.this, source=using) and
|
|
759
|
+
# mapped to its resolved ref. Bare table names are registered as a fallback.
|
|
760
|
+
alias_map: dict[str, TableRef] = {}
|
|
761
|
+
|
|
762
|
+
def _register(ref: TableRef | None, ast_node: Any) -> None:
|
|
763
|
+
if ref is None:
|
|
764
|
+
return
|
|
765
|
+
if isinstance(ast_node, exp.Table) and ast_node.alias:
|
|
766
|
+
alias_map.setdefault(ast_node.alias.lower(), ref)
|
|
767
|
+
if ref.alias:
|
|
768
|
+
alias_map.setdefault(ref.alias.lower(), ref)
|
|
769
|
+
if ref.name:
|
|
770
|
+
alias_map.setdefault(ref.name.lower(), ref)
|
|
771
|
+
|
|
772
|
+
using_ast = stmt.args.get("using")
|
|
773
|
+
_register(target_ref, target_ast)
|
|
774
|
+
for src in source_refs:
|
|
775
|
+
_register(src, using_ast if len(source_refs) == 1 else None)
|
|
776
|
+
|
|
777
|
+
def _resolve_table(col: Any) -> TableRef | None:
|
|
778
|
+
"""Resolve the owning TableRef of a source column reference."""
|
|
779
|
+
tbl_name = col.table
|
|
780
|
+
if tbl_name:
|
|
781
|
+
return alias_map.get(tbl_name.lower())
|
|
782
|
+
# Unqualified RHS column — attribute to the lone source when unambiguous.
|
|
783
|
+
if len(source_refs) == 1:
|
|
784
|
+
return source_refs[0]
|
|
785
|
+
return None
|
|
786
|
+
|
|
787
|
+
def _emit(target_col_name: str, rhs: Any, transform: str) -> None:
|
|
788
|
+
"""Emit one edge per source ``exp.Column`` found in ``rhs``."""
|
|
789
|
+
if not target_col_name:
|
|
790
|
+
return
|
|
791
|
+
cols = list(rhs.find_all(exp.Column)) if rhs is not None else []
|
|
792
|
+
if not cols:
|
|
793
|
+
# Pure-literal / no source column — no edge (AC-C5).
|
|
794
|
+
return
|
|
795
|
+
dst_ref = ColumnRef(table=target_ref, name=target_col_name)
|
|
796
|
+
for col in cols:
|
|
797
|
+
src_table = _resolve_table(col)
|
|
798
|
+
if src_table is None:
|
|
799
|
+
out.errors.append(
|
|
800
|
+
f"col_lineage_skip:merge_unresolved:{col.table or ''}.{col.name}"
|
|
801
|
+
)
|
|
802
|
+
continue
|
|
803
|
+
edges.append(
|
|
804
|
+
LineageEdge(
|
|
805
|
+
src=ColumnRef(table=src_table, name=col.name),
|
|
806
|
+
dst=dst_ref,
|
|
807
|
+
transform=transform,
|
|
808
|
+
)
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
for when in stmt.find_all(exp.When):
|
|
812
|
+
then = when.args.get("then")
|
|
813
|
+
if isinstance(then, exp.Update):
|
|
814
|
+
# WHEN MATCHED THEN UPDATE SET target.a = s.a, target.b = s.x + s.y
|
|
815
|
+
for eq in then.expressions:
|
|
816
|
+
if not isinstance(eq, exp.EQ):
|
|
817
|
+
continue
|
|
818
|
+
lhs = eq.this
|
|
819
|
+
if not isinstance(lhs, exp.Column):
|
|
820
|
+
continue
|
|
821
|
+
_emit(lhs.name, eq.expression, "MERGE_UPDATE")
|
|
822
|
+
elif isinstance(then, exp.Insert):
|
|
823
|
+
# WHEN NOT MATCHED THEN INSERT (cols) VALUES (vals)
|
|
824
|
+
target_cols = then.this
|
|
825
|
+
values = then.expression
|
|
826
|
+
if target_cols is None:
|
|
827
|
+
# INSERT VALUES with no column list — skip-and-log, no positional
|
|
828
|
+
# DDL fallback (gate decision: positional guessing risks wrong edges).
|
|
829
|
+
out.errors.append(f"col_lineage_skip:merge_no_collist:{target_ref.full_id}")
|
|
830
|
+
continue
|
|
831
|
+
col_exprs = list(getattr(target_cols, "expressions", []) or [])
|
|
832
|
+
val_exprs = list(getattr(values, "expressions", []) or [])
|
|
833
|
+
# Positional alignment of (cols) with VALUES (...); a malformed MERGE
|
|
834
|
+
# with mismatched arities zips to the shorter list rather than raising.
|
|
835
|
+
for target_col, value in zip(col_exprs, val_exprs, strict=False):
|
|
836
|
+
if not isinstance(target_col, exp.Column):
|
|
837
|
+
continue
|
|
838
|
+
_emit(target_col.name, value, "MERGE_INSERT")
|
|
839
|
+
|
|
840
|
+
return edges
|
|
841
|
+
|
|
663
842
|
def _real_tables(self, scope: Any) -> list[TableRef]:
|
|
664
843
|
"""Return real (non-CTE) tables referenced in a scope.
|
|
665
844
|
|
|
@@ -1117,19 +1296,15 @@ class SqlParser(ABC):
|
|
|
1117
1296
|
join_col_resolves: list[JoinColResolve] = []
|
|
1118
1297
|
_qualify_failed: bool = False
|
|
1119
1298
|
|
|
1120
|
-
#
|
|
1121
|
-
# sqlglot's lineage()
|
|
1122
|
-
#
|
|
1123
|
-
#
|
|
1299
|
+
# MERGE column lineage (un-defer T-07-06,
|
|
1300
|
+
# plan/sprints/sprint_snowflake_lineage_patterns.md PR-C). sqlglot's lineage()
|
|
1301
|
+
# API does not handle MERGE branches, but the WHEN MATCHED UPDATE SET / WHEN NOT
|
|
1302
|
+
# MATCHED INSERT VALUES clauses are structurally extractable by a direct AST walk.
|
|
1303
|
+
# This is a bounded once-per-statement path that NEVER calls sg_lineage / qualify /
|
|
1304
|
+
# build_scope / exp.expand (AC-C7).
|
|
1124
1305
|
if isinstance(stmt, exp.Merge):
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
try:
|
|
1128
|
-
dst_name = stmt.this.name
|
|
1129
|
-
except Exception:
|
|
1130
|
-
dst_name = None
|
|
1131
|
-
out.errors.append(f"col_lineage_skip:merge_branch:{dst_name or '<unknown>'}")
|
|
1132
|
-
return LineageExtraction(edges=edges, star_sources=star_sources)
|
|
1306
|
+
merge_edges = self._extract_merge_lineage(stmt, dst_table, query_sources, out)
|
|
1307
|
+
return LineageExtraction(edges=merge_edges, star_sources=star_sources)
|
|
1133
1308
|
|
|
1134
1309
|
# Only extract column lineage for certain statement types
|
|
1135
1310
|
if not isinstance(stmt, (exp.Select, exp.Insert, exp.Create)):
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""Dialect-agnostic bounded constant-fold of dynamic table-name expressions.
|
|
2
|
+
|
|
3
|
+
This is the pure core of the "generic variable-name resolution" feature
|
|
4
|
+
(``plan/sprints/feature_generic_var_name_resolution.md``). It partially folds a
|
|
5
|
+
string-valued expression AST (string literals, ``||`` / ``CONCAT``, and 1-hop
|
|
6
|
+
``$var`` references) into a concrete ``[catalog.]db.name`` table reference,
|
|
7
|
+
recovering the statically-determined trailing identifier components while
|
|
8
|
+
honestly giving up when the name cannot be determined.
|
|
9
|
+
|
|
10
|
+
No parser/indexer state is touched here: ``resolve_dynamic_name`` is a pure
|
|
11
|
+
function, fully unit-testable in isolation. PR-2 wires it into the Snowflake
|
|
12
|
+
parser via a sink predicate; this module ships unwired.
|
|
13
|
+
|
|
14
|
+
Fold classification:
|
|
15
|
+
|
|
16
|
+
* **LIT (resolvable):** ``exp.Literal`` (string), ``exp.DPipe`` / ``exp.Concat``
|
|
17
|
+
over folds, and a 1-hop ``$var`` whose RHS (looked up in ``var_env`` exactly
|
|
18
|
+
once) itself folds to a leading constant prefix.
|
|
19
|
+
* **OPAQUE (unresolvable):** runtime functions (``current_database()``,
|
|
20
|
+
``split_part(...)``, ``current_warehouse()``, any ``exp.Func`` /
|
|
21
|
+
``exp.Anonymous`` that is not a pure string op), scalar subqueries that are not
|
|
22
|
+
a single-projection of folds, bind parameters (``exp.Placeholder``), and any
|
|
23
|
+
``$var`` reference at chain depth >= 2.
|
|
24
|
+
|
|
25
|
+
Name extraction interprets the fold as ``[catalog.]db.name`` (name-last,
|
|
26
|
+
dot-split): it keeps the rightmost statically-determined ``db.name`` tail,
|
|
27
|
+
wildcards (drops) a leading OPAQUE catalog, keeps a static *literal* catalog, and
|
|
28
|
+
returns ``None`` when the whole thing is opaque / the tail is a bare name / the
|
|
29
|
+
tail lacks a resolvable ``db.name``.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
from dataclasses import dataclass
|
|
35
|
+
|
|
36
|
+
import sqlglot.expressions as exp
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True)
|
|
40
|
+
class _Lit:
|
|
41
|
+
"""A statically-known string segment of the folded expression."""
|
|
42
|
+
|
|
43
|
+
text: str
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True)
|
|
47
|
+
class _Opaque:
|
|
48
|
+
"""A runtime-determined segment that cannot be folded statically."""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
_Part = _Lit | _Opaque
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _fold_parts(
|
|
55
|
+
node: exp.Expression, # type: ignore[attr-defined]
|
|
56
|
+
var_env: dict[str, exp.Expression], # type: ignore[attr-defined]
|
|
57
|
+
*,
|
|
58
|
+
chain_depth: int,
|
|
59
|
+
) -> list[_Part]:
|
|
60
|
+
"""Fold ``node`` into an ordered list of LIT / OPAQUE parts.
|
|
61
|
+
|
|
62
|
+
Descends string-concatenation structure (``||`` / ``CONCAT``), single-
|
|
63
|
+
projection subqueries and parentheses; resolves 1-hop ``$var`` references
|
|
64
|
+
against ``var_env``; classifies everything else OPAQUE.
|
|
65
|
+
"""
|
|
66
|
+
# Unwrap a single-projection (SELECT ...) scalar subquery / paren.
|
|
67
|
+
if isinstance(node, exp.Subquery):
|
|
68
|
+
return _fold_parts(node.this, var_env, chain_depth=chain_depth)
|
|
69
|
+
if isinstance(node, exp.Paren):
|
|
70
|
+
return _fold_parts(node.this, var_env, chain_depth=chain_depth)
|
|
71
|
+
if isinstance(node, exp.Select):
|
|
72
|
+
projections = node.expressions
|
|
73
|
+
if len(projections) != 1:
|
|
74
|
+
return [_Opaque()]
|
|
75
|
+
return _fold_parts(projections[0], var_env, chain_depth=chain_depth)
|
|
76
|
+
|
|
77
|
+
# String concatenation: DPipe is binary (left-nested), Concat is n-ary.
|
|
78
|
+
if isinstance(node, exp.DPipe):
|
|
79
|
+
return _fold_parts(node.this, var_env, chain_depth=chain_depth) + _fold_parts(
|
|
80
|
+
node.expression, var_env, chain_depth=chain_depth
|
|
81
|
+
)
|
|
82
|
+
if isinstance(node, exp.Concat):
|
|
83
|
+
parts: list[_Part] = []
|
|
84
|
+
for child in node.expressions:
|
|
85
|
+
parts.extend(_fold_parts(child, var_env, chain_depth=chain_depth))
|
|
86
|
+
return parts
|
|
87
|
+
|
|
88
|
+
# Concrete string literal.
|
|
89
|
+
if isinstance(node, exp.Literal) and node.is_string:
|
|
90
|
+
return [_Lit(node.this)]
|
|
91
|
+
|
|
92
|
+
# 1-hop $var reference.
|
|
93
|
+
if isinstance(node, exp.Parameter):
|
|
94
|
+
var = node.this
|
|
95
|
+
name = var.name if isinstance(var, exp.Var) else None
|
|
96
|
+
if name is None or chain_depth < 1:
|
|
97
|
+
return [_Opaque()]
|
|
98
|
+
rhs = var_env.get(name.lower())
|
|
99
|
+
if rhs is None:
|
|
100
|
+
return [_Opaque()]
|
|
101
|
+
# Resolve exactly one hop: the looked-up RHS may not itself follow
|
|
102
|
+
# further $vars (depth-2 is OPAQUE because chain_depth drops to 0).
|
|
103
|
+
return _fold_parts(rhs, var_env, chain_depth=chain_depth - 1)
|
|
104
|
+
|
|
105
|
+
# Everything else (runtime funcs, bind params, non-fold subqueries) is opaque.
|
|
106
|
+
return [_Opaque()]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def resolve_dynamic_name(
|
|
110
|
+
rhs_expr: exp.Expression, # type: ignore[attr-defined]
|
|
111
|
+
var_env: dict[str, exp.Expression], # type: ignore[attr-defined]
|
|
112
|
+
*,
|
|
113
|
+
chain_depth: int = 1,
|
|
114
|
+
) -> exp.Table | None:
|
|
115
|
+
"""Bounded partial constant-fold of a string-expression AST into a TableRef.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
rhs_expr: the RHS expression assigned to the dynamic name (the AST that
|
|
119
|
+
the ``IDENTIFIER($var)`` sink dereferences).
|
|
120
|
+
var_env: lowercased var name -> its RHS AST, for 1-hop chain resolution.
|
|
121
|
+
chain_depth: max var-lookup hops (default 1; corpus max is 1). A var
|
|
122
|
+
whose value references another var resolves only the first hop.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
An ``exp.Table`` for the resolvable trailing identifier components, or
|
|
126
|
+
``None`` to give up honestly (caller leaves the sink dropped).
|
|
127
|
+
"""
|
|
128
|
+
parts = _fold_parts(rhs_expr, var_env, chain_depth=chain_depth)
|
|
129
|
+
|
|
130
|
+
if not parts:
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
# Take the rightmost contiguous run of LIT parts (the static suffix), noting
|
|
134
|
+
# whether an OPAQUE segment sits immediately before that run (catalog
|
|
135
|
+
# position is then runtime-determined).
|
|
136
|
+
suffix_lits: list[str] = []
|
|
137
|
+
opaque_precedes_suffix = False
|
|
138
|
+
for part in reversed(parts):
|
|
139
|
+
if isinstance(part, _Lit):
|
|
140
|
+
suffix_lits.append(part.text)
|
|
141
|
+
else:
|
|
142
|
+
opaque_precedes_suffix = True
|
|
143
|
+
break
|
|
144
|
+
suffix_lits.reverse()
|
|
145
|
+
|
|
146
|
+
if not suffix_lits:
|
|
147
|
+
# All-opaque (no static tail at all).
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
suffix = "".join(suffix_lits)
|
|
151
|
+
table = exp.to_table(suffix, dialect="snowflake")
|
|
152
|
+
|
|
153
|
+
# A resolvable object id needs at least db.name (schema.table). A bare name
|
|
154
|
+
# (no db) is a give-up: we never guess the schema/table. A missing name (tail
|
|
155
|
+
# ends on a dot) is likewise unresolvable.
|
|
156
|
+
if table.db == "" or table.name == "":
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
# Catalog policy:
|
|
160
|
+
# - literal catalog present in the static suffix (3-part name) -> KEEP it.
|
|
161
|
+
# - an OPAQUE segment precedes the suffix (the catalog slot came from a
|
|
162
|
+
# runtime segment) -> wildcard / drop the catalog (emit catalog-less
|
|
163
|
+
# db.name) so the node merges with DDL / plain-SQL refs to the same table.
|
|
164
|
+
# to_table already yields catalog='' when the static suffix had no catalog
|
|
165
|
+
# component (e.g. '.EMP.APPLICATION_FIELDS' or 'DHB.KOSTEN'); the explicit
|
|
166
|
+
# drop only matters when an opaque prefix sits before a literal 3-part tail.
|
|
167
|
+
if opaque_precedes_suffix and table.catalog != "":
|
|
168
|
+
table.set("catalog", None)
|
|
169
|
+
|
|
170
|
+
return table
|
{sql_code_graph-1.35.1 → sql_code_graph-1.35.2}/tests/integration/test_skip_counts_integration.py
RENAMED
|
@@ -181,15 +181,17 @@ def test_skip_counts_queryable_across_corpus(db, tmp_path):
|
|
|
181
181
|
def test_skip_counts_index_full_file_populates_column(db, tmp_path):
|
|
182
182
|
"""Indexing a real SQL file through the full index_repo path persists skip_counts.
|
|
183
183
|
|
|
184
|
-
Uses a Snowflake SQL fixture with a MERGE
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
Uses a Snowflake SQL fixture with a MERGE whose NOT MATCHED INSERT omits a column
|
|
185
|
+
list (guaranteed to emit col_lineage_skip:merge_no_collist:* — see
|
|
186
|
+
plan/sprints/sprint_snowflake_lineage_patterns.md PR-C) to verify the end-to-end
|
|
187
|
+
path from parse → normalize_keys → _build_file_rows → upsert_nodes_bulk →
|
|
188
|
+
File.skip_counts.
|
|
187
189
|
"""
|
|
188
|
-
# MERGE
|
|
190
|
+
# A no-column-list MERGE INSERT emits col_lineage_skip:merge_no_collist:*
|
|
189
191
|
sql = (
|
|
190
192
|
"CREATE TABLE src (a INT, b INT);\n"
|
|
191
193
|
"MERGE INTO tgt USING src ON tgt.a = src.a\n"
|
|
192
|
-
"WHEN MATCHED THEN
|
|
194
|
+
"WHEN NOT MATCHED THEN INSERT VALUES (src.a, src.b);\n"
|
|
193
195
|
)
|
|
194
196
|
sql_file = tmp_path / "merge_fixture.sf.sql"
|
|
195
197
|
sql_file.write_text(sql)
|
|
@@ -201,15 +203,15 @@ def test_skip_counts_index_full_file_populates_column(db, tmp_path):
|
|
|
201
203
|
{"path": str(sql_file)},
|
|
202
204
|
)
|
|
203
205
|
assert len(rows) == 1, f"File row not found for {sql_file}"
|
|
204
|
-
# MERGE emits at least one
|
|
206
|
+
# The no-collist MERGE INSERT emits at least one merge_no_collist skip
|
|
205
207
|
raw = rows[0]["skip_counts"]
|
|
206
208
|
assert raw is not None, (
|
|
207
|
-
"skip_counts must be non-null for a file containing a MERGE
|
|
208
|
-
f"(expected col_lineage_skip:
|
|
209
|
+
"skip_counts must be non-null for a file containing a no-collist MERGE INSERT "
|
|
210
|
+
f"(expected col_lineage_skip:merge_no_collist:*). Got NULL. File: {sql_file}"
|
|
209
211
|
)
|
|
210
212
|
counts = json.loads(raw)
|
|
211
|
-
assert counts.get("
|
|
212
|
-
f"Expected
|
|
213
|
+
assert counts.get("merge_no_collist", 0) >= 1, (
|
|
214
|
+
f"Expected merge_no_collist >= 1 in skip_counts. Got {counts!r}"
|
|
213
215
|
)
|
|
214
216
|
|
|
215
217
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""E16: MERGE multi-branch column lineage (structural extraction).
|
|
2
|
+
|
|
3
|
+
MERGE statements now produce column lineage via a direct AST walk of their
|
|
4
|
+
``WHEN MATCHED ... UPDATE SET`` / ``WHEN NOT MATCHED ... INSERT (cols) VALUES (...)``
|
|
5
|
+
clauses — sqlglot's ``lineage()`` API does not visit MERGE branches, so this is a
|
|
6
|
+
dedicated structural path (no ``sg_lineage`` / ``qualify``).
|
|
7
|
+
|
|
8
|
+
Un-defers the E16/T-07-06 deferral. See
|
|
9
|
+
plan/sprints/sprint_snowflake_lineage_patterns.md PR-C
|
|
10
|
+
([plan doc](../../../plan/sprints/sprint_snowflake_lineage_patterns.md)) and the
|
|
11
|
+
E{n} taxonomy (plan/sprints/sprint_07_open_ecodes.md § T-07-06) for history.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from tests.snowflake.conftest import edges, parse
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_e16_merge_match_and_insert(parser):
|
|
20
|
+
"""MATCHED UPDATE and NOT MATCHED INSERT each emit a column edge.
|
|
21
|
+
|
|
22
|
+
`UPDATE SET col = src.col_a` -> `src.col_a -> dst.col` (MERGE_UPDATE);
|
|
23
|
+
`INSERT (col) VALUES (src.col_b)` -> `src.col_b -> dst.col` (MERGE_INSERT).
|
|
24
|
+
"""
|
|
25
|
+
sql = Path(__file__).with_name("e16_merge.sql").read_text()
|
|
26
|
+
result = parse(parser, sql, "e16_merge.sql")
|
|
27
|
+
|
|
28
|
+
all_edges = set(edges(result))
|
|
29
|
+
assert ("src", "col_a", "dst", "col") in all_edges, (
|
|
30
|
+
f"E16: MATCHED UPDATE edge missing; got {all_edges}"
|
|
31
|
+
)
|
|
32
|
+
assert ("src", "col_b", "dst", "col") in all_edges, (
|
|
33
|
+
f"E16: NOT MATCHED INSERT edge missing; got {all_edges}"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# No deferred-skip noise should remain for an extractable MERGE.
|
|
37
|
+
assert not any("col_lineage_skip:merge_branch" in e for e in result.errors), (
|
|
38
|
+
f"MERGE no longer defers; got errors: {result.errors}"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_e16_merge_delete(parser):
|
|
43
|
+
"""A DELETE branch yields no edge; the UPDATE/INSERT branches still do.
|
|
44
|
+
|
|
45
|
+
`WHEN MATCHED ... THEN DELETE` has no column assignment, so it contributes no
|
|
46
|
+
edge, while the MATCHED UPDATE and NOT MATCHED INSERT branches still resolve.
|
|
47
|
+
"""
|
|
48
|
+
sql = Path(__file__).with_name("e16_merge_delete.sql").read_text()
|
|
49
|
+
result = parse(parser, sql, "e16_merge_delete.sql")
|
|
50
|
+
|
|
51
|
+
all_edges = set(edges(result))
|
|
52
|
+
assert ("src", "col_a", "dst", "col") in all_edges, (
|
|
53
|
+
f"E16: MATCHED UPDATE edge missing alongside DELETE branch; got {all_edges}"
|
|
54
|
+
)
|
|
55
|
+
assert ("src", "col_b", "dst", "col") in all_edges, (
|
|
56
|
+
f"E16: NOT MATCHED INSERT edge missing alongside DELETE branch; got {all_edges}"
|
|
57
|
+
)
|
|
58
|
+
# The DELETE branch assigns no column, so it must not add a phantom edge.
|
|
59
|
+
assert len(all_edges) == 2, f"E16: DELETE branch should add no edge; got {all_edges}"
|
|
@@ -60,14 +60,14 @@ def test_plan_review_e3_ddl_quality_allows_scripting_fallback():
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
# ---------------------------------------------------------------------------
|
|
63
|
-
# BLOCKER-2 (E16): MERGE produces
|
|
63
|
+
# BLOCKER-2 (E16): MERGE now produces column lineage (T-07-06 un-deferred)
|
|
64
64
|
# ---------------------------------------------------------------------------
|
|
65
|
-
def
|
|
66
|
-
"""E16 MERGE
|
|
65
|
+
def test_plan_review_e16_merge_captures_both_branches():
|
|
66
|
+
"""E16 MERGE captures both the MATCHED UPDATE and NOT MATCHED INSERT branches.
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
This is the inversion of the earlier zero-edge gate: MERGE column lineage is
|
|
69
|
+
now extracted structurally (plan/sprints/sprint_snowflake_lineage_patterns.md
|
|
70
|
+
PR-C), so both branches resolve src col_a / col_b -> dst.col.
|
|
71
71
|
"""
|
|
72
72
|
p = _parser()
|
|
73
73
|
sql = (
|
|
@@ -77,12 +77,9 @@ def test_plan_review_e16_merge_produces_zero_edges():
|
|
|
77
77
|
)
|
|
78
78
|
result = p.parse_file(Path("test_e16.sql"), sql)
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
assert
|
|
83
|
-
"E16: MERGE currently produces no column lineage; "
|
|
84
|
-
"if this fails, E16 was partially fixed and the test must be updated"
|
|
85
|
-
)
|
|
80
|
+
edges = set(_edges(result))
|
|
81
|
+
assert ("src", "col_a", "dst", "col") in edges, edges
|
|
82
|
+
assert ("src", "col_b", "dst", "col") in edges, edges
|
|
86
83
|
|
|
87
84
|
|
|
88
85
|
# ---------------------------------------------------------------------------
|