sql-code-graph 1.35.2__tar.gz → 1.36.0__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.2 → sql_code_graph-1.36.0}/PKG-INFO +1 -1
- sql_code_graph-1.36.0/plan/sprints/feature_generic_var_name_resolution.md +518 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/pyproject.toml +1 -1
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/__init__.py +1 -1
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/indexer/indexer.py +61 -9
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/parsers/bigquery_parser.py +5 -1
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/parsers/registry.py +7 -3
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/parsers/snowflake_parser.py +114 -4
- sql_code_graph-1.36.0/tests/integration/snowflake/test_identifier_var_sink_resolution_integration.py +96 -0
- sql_code_graph-1.36.0/tests/integration/test_incremental_reindex_parity.py +278 -0
- sql_code_graph-1.36.0/tests/unit/test_identifier_var_sink_resolution.py +201 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_perf_scaling_guard.py +76 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_subprocess_isolate.py +3 -3
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_timeout_cancel.py +2 -2
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/uv.lock +1 -1
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.claude/agents/api-documenter.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.claude/agents/architect-planner.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.claude/agents/architect-reviewer.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.claude/agents/code-reviewer.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.claude/agents/developer.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.claude/agents/plan-reviewer.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.claude/agents/sprint-planner.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.github/workflows/benchmark.yml +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.github/workflows/e2e-tests.yml +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.github/workflows/release.yml +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.github/workflows/test.yml +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.gitignore +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.pre-commit-config.yaml +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/.sqlcgignore +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/ARCHITECTURE_REVIEW.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/ARCHITECTURE_REVIEW_ARCHIVE.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/CHANGELOG.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/CLAUDE.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/README.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/docs/AIRBNB_PARSE_REPORT.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/docs/cli.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/docs/getting-started.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/docs/releasing-pypi.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/e2e_firstuser_report.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/e2e_run_20260528_101413.output +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/main.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/WORKFLOW.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/measurements/pr2_catalog_load_eval.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/measurements/pr3_repo_native_plateau.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/measurements/pr4_transform_kinds.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/measurements/pr5_extraction_recall_taxonomy.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/measurements/sprint_08_changelogs_fullindex.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/measurements/sprint_08_fullcorpus_index.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/createkind_dwh_after.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/createkind_dwh_before.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/gain_1.29.0_05c6943.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/gain_1.30.0_2c8ac25.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/gain_1.30.1_26271fc.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/gain_1.31.0_a40c837.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/gain_1.32.0_c1bec3c.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/lineage5_dwh_after_pr5.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/lineage5_dwh_before_master.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/pr4_star_promote_after.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/pr4_star_promote_before.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/pr_b_phantom_after.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/pr_b_phantom_before.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/pr_c_merge_after.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/pr_c_merge_before.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/schema_comparison_with_schema.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/schema_comparison_without_schema.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/sprint_08_changelogs_fullindex.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/sprint_08_fullcorpus_index.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/metrics/sprint_pool_300s_plan.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/column_coverage_diagnostic.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/column_coverage_findings.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/dwh_graph_analysis.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/dwh_positional_insert_column_blindspot.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/feature_acceptance_dwh.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/graph_health_sprint_postmortem.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/island_lever_live_verification.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/issue38_pr2_live_acceptance.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/issue38_pr3_live_acceptance.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/lineage_identity_sprint_postmortem.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/pr_impact_followups_2026-06-14.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/sprint_03_v0.3.1_postmortem.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/sprint_3.1_postmortem.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/reports/v1_14_dialect_query_config_postmortem.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/research/blueprint.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/research/coverage_parse_failure_diagnosis.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/research/investigation_e5_e4.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/research/observed_usage_overlay_query_history_tableau.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/research/parse_diagnostics.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/research/parsing_errors_experiment.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/research/snowflake_en_test_suite.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/research/sql_only_coverage_lever_post_pr2.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/research/sqlcg.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/bundle_claude_skill.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/ci_tests_pool_flake_fix.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/column_lineage_recall_metric.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/coverage_p1_p3_p4.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/coverage_p1_p5_metric.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/coverage_parse_failures.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/diff-impact-producer-file.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/e8_dual_emission.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/feature_34_unused_presentation_segregation.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/feature_35_external_downstream_injection.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/feature_F2_bundle_claude_skill.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/feature_kuzu_to_duckdb_migration.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/fix_backward_self_heal_index_at_sha.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/fix_downstream_sink_location.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/fix_dynamic_table_parsing.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/fix_expand_qualify_perf.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/fix_firstuser_findings.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/fix_issue29_live_test_followups.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/fix_schema_case_mismatch.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/gain_coverage_metrics.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/graph_health_catalog_and_metrics.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/hygiene_config_path_and_survivors.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/issue-38-backfill-cte-bridge.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/issue-38-residual-source-extraction.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/issue-38-selects-from-island-lever.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/living_codebase_resync.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/mcp_server_self_healing.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/positional_insert_clone_blindspot.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_01.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_01_deployment_pypi.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_02.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_02_v0.3.0_core.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_03.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_04_column_lineage.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_04_column_lineage_fix.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_05_star_resolution.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_06_lineage_coverage.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_07_open_ecodes.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_07_perf_and_live_test.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_08_perf_upsert.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_09_lineage_coverage.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_10_anchor_tools.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_11_v1.0.2_bugfix.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_12_v1.1.0.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_13_v1.1.0_cluster_b.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_lineage_identity_and_session_context.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/sprint_postmortem_fixes.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/temp_table_namespacing.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/trust_layer.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/unfilled_table_impact.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/v1.1.0_cluster_b_provenance_trust.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/v1.1.0_live_graph_freshness.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/v1.1.1_batch_upsert_perf.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/v1.14.0_dialect_and_query_config_fixes.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/v1_1_2_bugfix.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/v1_1_3_union_cte_star.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/v1_2_0_read_proxy.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/v1_2_1_bugfix.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/plan/sprints/version-parity-and-restart.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/profile.html +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/pyrightconfig.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/scripts/collect_parse_errors.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/scripts/column_coverage_check.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/scripts/generate_cli_docs.sh +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/__main__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/analyze.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/catalog.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/db.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/find.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/gain.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/git.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/index.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/install.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/mcp.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/reindex.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/report.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/uninstall.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/viz.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/watch.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/coverage.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/cli/main.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/config.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/duckdb_backend.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/freshness.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/graph_db.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/jobs.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/noise_match.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/queries.cypher +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/queries.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/queries.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/schema.cypher +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/core/schema.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/indexer/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/indexer/dbt_adapter.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/indexer/error_classify.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/indexer/git_delta.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/indexer/pool.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/indexer/walker.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/indexer/watcher.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/lineage/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/lineage/aggregator.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/lineage/schema_resolver.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/metrics/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/metrics/store.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/parsers/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/parsers/ansi_parser.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/parsers/base.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/parsers/dynamic_name.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/parsers/postgres_parser.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/parsers/tsql_parser.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/control.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/exceptions.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/models.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/noise_filter.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/read_client.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/selfheal.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/server.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/skill.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/tools.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/server/writer.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/utils/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/utils/hashing.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/utils/ignore.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/utils/logging.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/viz/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/viz/assets/force-graph.min.js +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/viz/assets/template.html +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/viz/data.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/viz/render.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/src/sqlcg/viz/tags.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/adversarial/200_join.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/adversarial/500_union.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/bench_indexer.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/conftest.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/case_normalization.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/colon_cast.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/colon_reserved_word.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/copy_into.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/create_procedure.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/identifier_dynamic.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/lateral_flatten.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/qualify.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/scripting_block.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/three_part.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q01.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q02.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q03.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q04.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q05.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/conftest.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/conftest.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_F2_skill_install_e2e.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_airbnb_e2e.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_cli_index.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_empty_impact_cli_e2e.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_git_hook_install.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_golden_lineage.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_mcp_lifecycle.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_mcp_tools.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_parse_diagnostics_cli.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_pr_impact_cli_e2e.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_selfheal_e2e.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_star_resolution_e2e.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_viz_cli_e2e.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/e2e/test_watch.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/dim_hosts_cleansed.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/dim_listings_cleansed.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/fct_reviews.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/mart_fullmoon_reviews.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/raw_hosts.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/raw_listings.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/raw_reviews.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/src_hosts.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/src_listings.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/src_reviews.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/bigquery/.gitkeep +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/duckdb_parity/kuzu_reference.json +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/jaffle_shop/customers.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/jaffle_shop/orders.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/jaffle_shop/raw_orders.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/snowflake/base_tables.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/snowflake/reports.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/snowflake/views.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/star_corpus/ddl_src.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/star_corpus/ddl_tgt.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/star_corpus/etl_alias_star.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/star_corpus/etl_star.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/synthetic/base_tables.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/synthetic/reports.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/fixtures/synthetic/views.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/snowflake/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/snowflake/test_insert_select.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/snowflake/test_qualify_bare_tables_command_guard_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_T34_presentation_segregation.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_T35_external_consumers.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_analyze_case_fold.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_anchor_tools.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_backfill_impact_consistency.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_bare_column_cte_lineage.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_bulk_upsert.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_case_split_seed_regression.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_catalog_kind_upgrade.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_catalog_load_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_cli_index_clear_before_rebuild.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_column_coverage_patterns.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_column_lineage_e2e.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_coverage_metrics_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_cross_file_lineage.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_cte_key_namespacing_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_cte_recall_guard.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_cte_schema_alias_guard.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_cte_source_node_invariant.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_dialect_auto_resolution.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_dialect_matrix.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_duckdb_parity.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_e36_xfile_regression_guard.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_empty_impact_blast_radius.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_empty_index_rollback_guard.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_freshness_mcp.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_gating_join_retrofit.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_hygiene_config_root_reconciliation.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_identity_counters_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_impact_consumer_parity.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_index_degraded_files_metric.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_index_filter_node_exclusion.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_indexer_batching.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_indexer_commits.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_indexer_to_graph.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_issue38_cte_insert_regression.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_join_col_resolution.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_key_normalization_chokepoint.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_live_anchors.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_mvcc_rebuild.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_non_table_create_coverage_no_regression.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_non_table_create_kind_in_graph.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_parse_diagnostics.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_phantom_non_table_create_node.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_pr1_confidence_reason.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_pr2_source_location.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_pr3_kind_tagging.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_pr_impact_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_qualify_failed_persist.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_read_via_server.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_readonly_under_lock.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_reindex_via_server.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_repo_relative_cte_namespaces.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_resolvable_write_col_edges_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_resync.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_selects_from_completeness.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_selects_from_cte_body_source.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_selects_from_subscope_source.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_single_writer_queue.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_skip_counts_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_star_promote_temp_columns.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_star_resolution.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_temp_table_lineage.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_temp_table_namespacing.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_tool_version_stamp_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_union_cte_star_recall_guard.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_usage_derived_catalog.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_use_schema_session_context_integration.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_user_surface_recall_guard.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_v141_surface_guards.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_v1_14_0_dialect_and_query_config_fixes.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_view_kind_in_graph.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_viz_data_build.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/integration/test_write_memory_ceiling.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/perf/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/perf/test_perf.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E10/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E11/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E12/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E12/e12_json_path.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E12/e12_lateral_flatten.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E12/test_e12.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E13/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E14/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E15/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E16/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E16/e16_merge.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E16/e16_merge_delete.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E16/test_e16.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E17/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E18/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E18/e18_decode.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E18/e18_iff_decode.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E18/e18_nvl2.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E18/test_e18.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E19/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E2/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E2/e2_expr_alias.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E2/e2_function_alias.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E2/e2_multiply_alias.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E2/test_e2.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E20/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E21/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E21/e21_alias_forward_ref.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E21/e21_three_level_chain.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E21/test_e21.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E22/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E23/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E23/e23_stored_proc.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E23/e23_stored_proc_multi.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E23/test_e23.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E24/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E25/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E25/e25_cross_db.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E25/e25_two_part.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E25/test_e25.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E25/test_e25_full_id.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E26/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E27/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E27/e27_nested_udf.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E27/e27_udf.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E27/test_e27.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E28/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E29/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E3/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E3/e3_alter_table.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E3/e3_create_sequence.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E3/e3_ddl_only.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E3/test_e3.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E30/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E31/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E32/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E33/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E34/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E35/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E36/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E36/e36_temp_multi_use.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E36/e36_temp_table.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E36/test_e36.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E36/test_e36_xfile.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E37/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E38/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E4/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E4/e4_execute_immediate.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E4/e4_if_not_exists.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E4/e4_unexpected_token.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E4/e4_unpivot.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E4/test_e4.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E5/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E5/e5_cte_missing_source.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E5/e5_multi_cte.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E5/e5_nested_cte.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E5/test_e5.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E5/test_e5_cte_projection.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E8/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E8/e8_dynamic_sources.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E8/e8_seq_nextval.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E8/e8_uuid.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E8/test_e8.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E9/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/fixture_sum_absent_cross_schema.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/fixture_sum_case_when.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/fixture_sum_present_source.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/test_e_aggregates.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/fixture_date_aliased.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/fixture_date_unaliased.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/fixture_datediff_unaliased.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/fixture_year_unaliased.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/test_e_date_functions.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/README.md +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/anchors/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/anchors/fixture_etl.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/anchors/fixture_omloopsnelheid.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/anchors/fixture_semantic.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/anchors/fixture_source.sql +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/anchors/test_anchor_ma_aantal_op_order.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/anchors/test_anchor_omloopsnelheid.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/conftest.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/snowflake/test_plan_review_gates.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/snowflake/__init__.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/snowflake/test_qualify_bare_tables_command_guard.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/snowflake/test_scripting_noise.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_BugB_escalation_uses_init_path.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_BugC_hook_upgrade.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_F2_install_skill.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_F2_skill_render.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_F2_uninstall_skill.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_T09_01_qualify_once.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_T09_02_ddl_skip.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_T09_04_subprocess_isolate.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_T09_06_log_verbosity.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_T35_config_external_consumers.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_aggregator.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_aggregator_skip.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_analyze_case_fold.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_base_parser.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_branch_monitor.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_bulk_upsert_invariant.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_canonical_target_resolution.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_catalog_csv_parsing.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_catalog_missing_warning.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_classify_non_table_create_kind.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_cli.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_cli_doc_flag_staleness.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_cli_help.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_clone_positional_insert_blindspot.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_closure_depth.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_column_lineage_wiring.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_config.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_coverage_metrics.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_cte_key_namespacing.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_cte_source_gap_metric.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_data_models.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_db_info.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_db_info_coverage.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_db_path_isolation_fixture.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_doc_links.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_doc_markdown_link_existence.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_dominant_cause.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_duckdb_backend.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_duckdb_backend_shared.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_dynamic_name_resolution.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_e5_view_alias_resolution.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_e8_dual_emission.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_e8_temp_chain_key_mismatch.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_empty_propagation_unit.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_extract_select_output_columns.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_file_ignore_defaults.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_find_cmd.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_firstuser_findings.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_freshness_helper.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_gain_coverage.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_gain_ratio.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_gating_join_field_docstrings.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_git_delta.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_git_hooks.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_git_hooks_notify.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_graph_backend.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_graph_completeness_invariant.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_hard_kill_pool.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_has_column_precedence_upsert.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_hook_reindex_detach.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_hygiene_config_warning.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_identity_counters.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_include_working_tree.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_index_cmd.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_index_filter_config.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_index_flags.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_index_progress.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_index_summary_degraded_metric.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_indexer_progress.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_indexer_quality.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_install.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_install_message.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_issue_63_readonly_lock.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_jobs.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_join_col_resolve_marker.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_judgement.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_lineage_conversion.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_literal_column_skip.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_mcp_best_practices.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_mcp_control.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_mcp_stdio_smoke.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_merge_column_lineage.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_metrics.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_noise_filter.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_normalize_keys.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_parse_failed_classification.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_parse_file_dependency_filter.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_parse_quality.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_parser.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_phantom_non_table_create_source.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_pr07_observability.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_pr6_execute_immediate_unwrap.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_pr_impact_unit.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_qualify_failed_unit.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_queries_loader.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_read_client.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_repo_relative_cte_namespaces.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_resolvable_write_col_edges_unit.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_resolve_join_columns_sql.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_resolve_pass2_passes_dependency_filter.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_schema_resolver.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_selects_from_completeness_unit.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_selfheal_detector.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_selfheal_pr1_messages.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_selfheal_reexec.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_selfheal_watcher.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_server.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_skip_counts_persistence.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_snowflake_strip_alter_set_tag.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_sprint_06_t04_t05.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_star_resolution_unit.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_star_schema_unit.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_submit_feedback.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_t02_expression_name_extraction.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_t03_ddl_skip.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_temp_table_namespacing.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_tool_version_stamp.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_tools_hints.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_tools_warnings.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_transform_kind_classification.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_uninstall.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_unknown_sentinel_skip.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_unqualified_fallback.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_upsert_batch_invariant.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_use_schema_session_context.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_version_parity.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_view_classification.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_viz_config_schemas.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_viz_facets.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_viz_render_self_contained.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_walker.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_watcher.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/tests/unit/test_worker_error_classification.py +0 -0
- {sql_code_graph-1.35.2 → sql_code_graph-1.36.0}/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.
|
|
3
|
+
Version: 1.36.0
|
|
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,518 @@
|
|
|
1
|
+
# Feature Plan: Generic variable-name resolution for dynamic table names
|
|
2
|
+
|
|
3
|
+
**Status:** REVIEWED (plan-reviewer gate 2026-06-14 — VERDICT REVIEWED, no blockers. Both load-bearing
|
|
4
|
+
checks PROVEN empirically: (1) fold-core catalog rule correct — `to_table('DHB.KOSTEN')`→cat='' (wildcard
|
|
5
|
+
opaque catalog), `to_table('PRD_DB.DHB.KOSTEN')`→cat='PRD_DB' (KEEP literal catalog), bare `KOSTEN`→give-up;
|
|
6
|
+
(2) flow-gate structurally enforced — `ALTER WAREHOUSE`/`CALL` parse to `exp.Command`, never `exp.Table`, so
|
|
7
|
+
the demand-driven resolver auto-excludes them. Forks: F1 accept (env-param + keep-literal-catalog + PR-3
|
|
8
|
+
zero-collision assert), F2 absorb PR-A scaffolding into PR-2, F3 chain-depth=1, F4 two pre-scan maps.
|
|
9
|
+
**3 corrections to FOLD AT PR-2:** (a) master is v1.35.1 → next MINOR = **v1.36.0** (not 1.35.0); (b) sink
|
|
10
|
+
predicate must match `IDENTIFIER` CASE-INSENSITIVELY (`table.this.name == 'IDENTIFIER'` is UPPERCASE — else
|
|
11
|
+
matches nothing and PR-2 tests silently pass-as-noop); (c) PR-1 bind-param→OPAQUE fixture asserts via
|
|
12
|
+
`exp.Placeholder`. Anchors verified on master: pre-scan snowflake_parser.py:355-364, wiring :428,
|
|
13
|
+
EXEC-IMMEDIATE var :640/655 (file now 976 lines, re-grep at impl). READY — PR-1 → PR-2 → PR-3.)
|
|
14
|
+
**Source study:** `git show research/generic-var-name-resolution:plan/research/generic_variable_name_resolution.md` (commit `60635c7`, VERDICT **HOLDS**)
|
|
15
|
+
**Foundation (dropped):** [`fix/identifier-var-indirection`](src/sqlcg/parsers/snowflake_parser.py) commit `0f655d0` — handles the LITERAL case only; this feature extends "is the RHS a literal?" → "FOLD the RHS".
|
|
16
|
+
**Branch:** `plan/generic-var-name-resolution`
|
|
17
|
+
**Target version:** **MINOR** — new lineage capability (no break). Master is **v1.34.3** at planning time (see [Version note](#version-note)); plan targets **v1.35.0**, reconcile the exact number at merge.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Summary
|
|
22
|
+
|
|
23
|
+
Generic, bounded constant-propagation of string-valued Snowflake session variables to
|
|
24
|
+
resolve dynamic table names (`IDENTIFIER($var)` in DML position), recovering ~187
|
|
25
|
+
currently-dropped DML-context references across ~136 files at `schema.table` grain.
|
|
26
|
+
A dialect-agnostic fold core does the work; only a one-line Snowflake sink predicate is
|
|
27
|
+
dialect-coupled.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Version note
|
|
32
|
+
|
|
33
|
+
The dispatch brief says "master ~v1.35.x / v1.35.0+". The actual current master at
|
|
34
|
+
planning time is **v1.34.3** ([`pyproject.toml`](pyproject.toml), confirmed via
|
|
35
|
+
`git show master:pyproject.toml`). The worktree this plan was authored alongside carried
|
|
36
|
+
unrelated in-flight work bumped to 1.34.4, which is **not** master. Treat the version as
|
|
37
|
+
**the next MINOR after whatever master is at merge** — currently `v1.35.0`. Reconcile at
|
|
38
|
+
merge time, as the project's release notes routinely do (e.g. the v10/1.33.0 collision).
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Scope
|
|
43
|
+
|
|
44
|
+
### In Scope
|
|
45
|
+
|
|
46
|
+
- A dialect-agnostic `resolve_dynamic_name(rhs_expr, var_env, *, chain_depth=1)` that
|
|
47
|
+
partial-constant-folds a string-expression AST: string literals, `||`/`CONCAT`,
|
|
48
|
+
1-hop `$var` chains; marks runtime funcs / scalar subqueries / bind params OPAQUE;
|
|
49
|
+
interprets the fold as `[catalog.]db.name` (name-last, dot-split); keeps the
|
|
50
|
+
statically-determined trailing components; wildcards a leading OPAQUE catalog but
|
|
51
|
+
keeps a static literal catalog; gives up honestly otherwise.
|
|
52
|
+
- A Snowflake-only sink predicate `is_dynamic_name_sink(table)` recognising
|
|
53
|
+
`IDENTIFIER($var)` (an `exp.Anonymous` named `identifier` wrapping an
|
|
54
|
+
`exp.Parameter`) **in a table position** (FROM/JOIN/INTO/UPDATE/MERGE/USING).
|
|
55
|
+
- Landing PR-A's scaffolding (the literal-only `_resolve_identifier_tables` + the
|
|
56
|
+
`exp.Set` / `exp.PropertyEQ` var pre-scan) and rewiring it to call the fold core;
|
|
57
|
+
extending the pre-scan to store the **RHS AST**, not just literal strings.
|
|
58
|
+
- A perf-guard counter so the fold stays once-per-statement (no qualify/expand/sg_lineage).
|
|
59
|
+
- Live-DWH `gain --json` before/after acceptance with the no-literal-catalog-collision
|
|
60
|
+
assertion.
|
|
61
|
+
|
|
62
|
+
### Non-Goals
|
|
63
|
+
|
|
64
|
+
- **Other-dialect dynamic-SQL sinks** (T-SQL `sp_executesql` / `EXEC(@sql)`, Postgres
|
|
65
|
+
`format()`+`EXECUTE`, Spark string-built names). The core is built generic so a later
|
|
66
|
+
dialect adds only its own `is_dynamic_name_sink`; **no other predicate ships here.**
|
|
67
|
+
- The 40 scalar-subquery delta vars that are genuinely runtime-dynamic (no static tail)
|
|
68
|
+
stay unresolved — they hit the honest give-up.
|
|
69
|
+
- A general dataflow interpreter / fixpoint var resolution / chain depth > 1
|
|
70
|
+
(corpus max is 1; see [The bound](#the-bound-flow-gate--enforced-limits)).
|
|
71
|
+
- `ALTER WAREHOUSE IDENTIFIER()` (`exp.Command`), `CALL …($v)` proc-args, scalar/WHERE
|
|
72
|
+
vars — these are excluded **structurally** (the walk visits `exp.Table` sinks only);
|
|
73
|
+
preserve that auto-exclusion, do not add a name blocklist.
|
|
74
|
+
- Parse-time schema feeding into `exp.expand()`/`qualify()` (forbidden by CLAUDE.md).
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Design
|
|
79
|
+
|
|
80
|
+
### Fold-core API (dialect-agnostic)
|
|
81
|
+
|
|
82
|
+
Suggested home: a new module [`parsers/dynamic_name.py`](src/sqlcg/parsers/) (the study's
|
|
83
|
+
preference; keeps `base.py` lean and the seam obvious). Pure function, no parser state.
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
def resolve_dynamic_name(
|
|
87
|
+
rhs_expr: exp.Expression,
|
|
88
|
+
var_env: dict[str, exp.Expression], # lowercased var name → its RHS AST
|
|
89
|
+
*,
|
|
90
|
+
chain_depth: int = 1,
|
|
91
|
+
) -> exp.Table | None:
|
|
92
|
+
"""Bounded partial constant-fold of a string-expression AST into a TableRef.
|
|
93
|
+
|
|
94
|
+
Returns an exp.Table for the resolvable trailing identifier components, or None
|
|
95
|
+
(give up honestly — caller leaves the sink dropped, today's behaviour).
|
|
96
|
+
"""
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Fold rules (the OPAQUE/LIT classification)
|
|
100
|
+
|
|
101
|
+
Fold the RHS into an ordered list of parts, each `LIT(s)` or `OPAQUE`:
|
|
102
|
+
|
|
103
|
+
- Descend through `exp.Subquery` / `exp.Select` **single-projection only**,
|
|
104
|
+
`exp.Paren`, `exp.DPipe`, `exp.Concat`.
|
|
105
|
+
- `exp.Literal(is_string=True)` → `LIT(s)`.
|
|
106
|
+
- `exp.Parameter`→`exp.Var` (`$other_var`): look it up in `var_env` **once** (chain
|
|
107
|
+
depth 1); fold that RHS one level; if it folds to a leading constant prefix use it,
|
|
108
|
+
else `OPAQUE`. Do **not** re-follow `$vars` discovered inside that value
|
|
109
|
+
(chain-depth bound).
|
|
110
|
+
- Everything else — runtime funcs (`exp.CurrentDatabase`, `current_warehouse`,
|
|
111
|
+
`current_schema`), `exp.SplitPart`, `exp.Substring`, a scalar subquery that is not a
|
|
112
|
+
pure single-projection of folds, a bind param (`?`, `:x`), an unresolved/undefined var
|
|
113
|
+
→ `OPAQUE`.
|
|
114
|
+
|
|
115
|
+
#### Name-extraction rules (the keep/wildcard/give-up policy)
|
|
116
|
+
|
|
117
|
+
A SQL object id is `[catalog.]db.name`, dot-separated, **name-last**. From the folded
|
|
118
|
+
parts:
|
|
119
|
+
|
|
120
|
+
1. Take the **rightmost run of `LIT` parts** (the static suffix), concatenate, and
|
|
121
|
+
`to_table(suffix, dialect=...)` it.
|
|
122
|
+
2. **KEEP the statically-determined trailing components.** The tail is normally
|
|
123
|
+
`.db.name` (= `schema.table`); the leading catalog position is OPAQUE.
|
|
124
|
+
3. **Wildcard / drop a leading OPAQUE catalog** → emit `db.name` with empty catalog.
|
|
125
|
+
This is the existing catalog-less identity (`to_table('DHB.KOSTEN')` → cat='' db=DHB
|
|
126
|
+
name=KOSTEN, **probed live**), so the resolved node **merges** with DDL / plain-SQL
|
|
127
|
+
refs to the same table.
|
|
128
|
+
4. **KEEP a static literal catalog when present.** If the fold yields a fully-literal
|
|
129
|
+
`catalog.schema.table` (no OPAQUE in the leading position), do NOT collapse it —
|
|
130
|
+
`to_table('PRD_DB.DHB.KOSTEN')` → cat=PRD_DB (**probed live**). This is the cross-DB
|
|
131
|
+
safety valve ([fork F1](#design-forks-needing-a-maintainer-decision)).
|
|
132
|
+
5. **Give up honestly** (return `None`) when: the result is all-OPAQUE; the static tail
|
|
133
|
+
has no dot (a bare name like `'TMP_TABLE_DATASET'`); or the tail lacks a resolvable
|
|
134
|
+
`db.name`. Never emit a guessed/partial edge — silence over a wrong edge.
|
|
135
|
+
|
|
136
|
+
#### Worked folds (from the study; the PR-1 fixture spec, behaviourally)
|
|
137
|
+
|
|
138
|
+
| RHS | Parts | Result |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| `'DL_' \|\| split_part(current_database(),'_',2) \|\| '.DHB.KOSTEN'` | `LIT('DL_'),OPAQUE,LIT('.DHB.KOSTEN')` | `DHB.KOSTEN` (cat='') |
|
|
141
|
+
| `(SELECT 'DL_' \|\| split_part(...) \|\| '.DHB.KOSTEN')` | same (descend Subquery) | `DHB.KOSTEN` (cat='') |
|
|
142
|
+
| `$ODS_DB \|\| '.ods.ig_stibat'` where `ODS_DB`→OPAQUE | `OPAQUE,LIT('.ods.ig_stibat')` | `ods.ig_stibat` (cat='') |
|
|
143
|
+
| `'TMP_TABLE_DATASET'` | `LIT('TMP_TABLE_DATASET')` | **give up** (bare name) |
|
|
144
|
+
| all-runtime, no literal tail | `OPAQUE…` | **give up** |
|
|
145
|
+
| `'PRD_DB.DHB.KOSTEN'` (literal catalog) | `LIT(...)` | `PRD_DB.DHB.KOSTEN` (cat KEPT) |
|
|
146
|
+
|
|
147
|
+
### Sink predicate (the only dialect-specific piece)
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
# SnowflakeParser
|
|
151
|
+
@staticmethod
|
|
152
|
+
def is_dynamic_name_sink(table: exp.Table) -> exp.Expression | None:
|
|
153
|
+
"""Return the $var Parameter to resolve if `table` is IDENTIFIER($var) in a
|
|
154
|
+
table position, else None. Snowflake's IDENTIFIER() is the dynamic-name sink:
|
|
155
|
+
exp.Table.this == exp.Anonymous(name='identifier') wrapping an exp.Parameter."""
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- Returns the `exp.Parameter` (the `$var`) when `table.this` is an `exp.Anonymous` named
|
|
159
|
+
`identifier` wrapping a Parameter; else `None`.
|
|
160
|
+
- Base/ANSI parser: no override → no generic sink ships (Non-Goal).
|
|
161
|
+
- **Why this auto-excludes the 91 `ALTER WAREHOUSE` cases + proc-args + WHERE vars:**
|
|
162
|
+
those never parse to an `exp.Table` (`ALTER WAREHOUSE IDENTIFIER()` → `exp.Command`;
|
|
163
|
+
`CALL …($v)` arg is a Parameter not a Table). The resolver only walks `exp.Table`
|
|
164
|
+
sinks, so they are never even asked. This structural gate is the bound — **do not
|
|
165
|
+
replace it with a name blocklist.**
|
|
166
|
+
|
|
167
|
+
### Var pre-scan (RHS-AST, extends PR-A)
|
|
168
|
+
|
|
169
|
+
PR-A's pre-scan (on its branch; on **current master** lines **355-364** cover only
|
|
170
|
+
`PropertyEQ`) stores `var name → literal string`. Extend it to store
|
|
171
|
+
`var name → RHS AST` so the fold can run on demand:
|
|
172
|
+
|
|
173
|
+
- `exp.PropertyEQ` (`var := <expr>`) — store `stmt.expression` (the AST), not just when
|
|
174
|
+
it is an `exp.Literal`.
|
|
175
|
+
- `exp.Set` ▸ `exp.SetItem(kind=VARIABLE)` ▸ `exp.EQ(Column, <expr>)` — store
|
|
176
|
+
`eq.expression` (the AST). This is the **session-variable** form the DWH actually uses;
|
|
177
|
+
PR-A added the `exp.Set` branch on its branch but stored only literals.
|
|
178
|
+
- **Last-write-wins** in file source order (study §3.4: only reassignment-looking case is
|
|
179
|
+
the UPDATE-column trap, which is `exp.Update`, structurally distinct — never captured).
|
|
180
|
+
- Keep the existing literal-string map used by the EXECUTE IMMEDIATE path
|
|
181
|
+
([`snowflake_parser.py`](src/sqlcg/parsers/snowflake_parser.py) lines **639-651**,
|
|
182
|
+
`_recover_execute_immediate` / `_EXEC_IMMEDIATE_VAR_RE`, and `_inner_stmts_from_command`
|
|
183
|
+
at line **655**) **untouched** — that path needs the resolved string, not the AST; do
|
|
184
|
+
not regress it. Either keep two maps, or derive the literal map from the AST map for the
|
|
185
|
+
literal-only entries. See [fork F4](#design-forks-needing-a-maintainer-decision).
|
|
186
|
+
|
|
187
|
+
### Wiring
|
|
188
|
+
|
|
189
|
+
Rewire `_resolve_identifier_tables` (the literal-only method on PR-A's branch) to:
|
|
190
|
+
1. `for table in stmt.find_all(exp.Table)`,
|
|
191
|
+
2. `param = self.is_dynamic_name_sink(table)`; if `None`, continue,
|
|
192
|
+
3. `new = resolve_dynamic_name(var_env[param.name.lower()], var_env)`; if `None`,
|
|
193
|
+
continue (leave dropped),
|
|
194
|
+
4. preserve the FROM/INSERT `alias`, `table.replace(new)`.
|
|
195
|
+
|
|
196
|
+
Call it **before** `_qualify_bare_tables` (as PR-A does, current master ~line **427**) so
|
|
197
|
+
a catalog-less resolved tail still inherits the active `USE SCHEMA` prefix.
|
|
198
|
+
|
|
199
|
+
### Data Models / API surface
|
|
200
|
+
|
|
201
|
+
- No graph-schema change. Resolved nodes are ordinary `SqlTable` `db.name` refs that
|
|
202
|
+
merge with existing identities.
|
|
203
|
+
- No CLI change. No new MCP tool. `gain` already reports the coverage metrics used in PR-3.
|
|
204
|
+
|
|
205
|
+
### Dependencies
|
|
206
|
+
|
|
207
|
+
- sqlglot AST nodes only (`exp.DPipe`, `exp.Concat`, `exp.Subquery`, `exp.Literal`,
|
|
208
|
+
`exp.Parameter`, `exp.Var`, `exp.Anonymous`, `exp.Set`, `exp.SetItem`, `exp.EQ`,
|
|
209
|
+
`exp.PropertyEQ`, `exp.CurrentDatabase`, `exp.SplitPart`, `exp.Substring`) — all
|
|
210
|
+
confirmed present in the study §3.2.
|
|
211
|
+
- PR-A scaffolding on `fix/identifier-var-indirection` (NOT yet on master — see
|
|
212
|
+
[fork F2](#design-forks-needing-a-maintainer-decision)).
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Implementation Steps
|
|
217
|
+
|
|
218
|
+
### PR-1 — Generic fold core + exhaustive unit fixtures (no wiring)
|
|
219
|
+
|
|
220
|
+
**Scope:** Pure `resolve_dynamic_name` (fold + extract + opaque-wildcard + give-up).
|
|
221
|
+
No parser change, no sink predicate — falsifiable in isolation.
|
|
222
|
+
|
|
223
|
+
**Files:**
|
|
224
|
+
- `src/sqlcg/parsers/dynamic_name.py` (new) — the core.
|
|
225
|
+
- `tests/unit/test_dynamic_name_resolution.py` (new) — fixtures below.
|
|
226
|
+
|
|
227
|
+
**Anchor (re-confirmed against current master, v1.34.3):** none in the hot path; this is
|
|
228
|
+
a new module. The empty-id drop it works around is in
|
|
229
|
+
[`base.py`](src/sqlcg/parsers/base.py) (`full_id` lines ~95-99 + the reject-empty rule)
|
|
230
|
+
— unchanged by this PR.
|
|
231
|
+
|
|
232
|
+
**Acceptance (each a behaviour, not a code):**
|
|
233
|
+
- direct-concat fold → `DHB.KOSTEN`, catalog empty.
|
|
234
|
+
- `(SELECT …)`-wrapped concat → same `DHB.KOSTEN` (descends Subquery/Select).
|
|
235
|
+
- 1-hop `$var` chain (`$ODS_DB || '.ods.ig_stibat'`, `ODS_DB`→OPAQUE) → `ods.ig_stibat`.
|
|
236
|
+
- all-opaque RHS (only `current_database()`/`split_part`) → returns `None`.
|
|
237
|
+
- bare-name give-up (`'TMP_TABLE_DATASET'`, no dot) → returns `None`.
|
|
238
|
+
- dynamic-schema give-up (OPAQUE in the schema/name position, tail has no static
|
|
239
|
+
`db.name`) → returns `None`.
|
|
240
|
+
- literal-catalog-keep (`'PRD_DB.DHB.KOSTEN'`) → catalog `PRD_DB` retained, NOT collapsed.
|
|
241
|
+
- chain-depth bound: a `$a` whose value references `$b` resolves only `$a`'s one hop;
|
|
242
|
+
`$b` is not re-followed (assert the depth-2 ref stays OPAQUE).
|
|
243
|
+
|
|
244
|
+
**Version:** none on its own (lands with the trio). **Metric impact:** none (no wiring).
|
|
245
|
+
|
|
246
|
+
**Frozen-perf note:** new module, not on the parser hot path; the four frozen suites
|
|
247
|
+
([`test_T09_01_qualify_once.py`](tests/unit/test_T09_01_qualify_once.py),
|
|
248
|
+
[`test_bulk_upsert_invariant.py`](tests/unit/test_bulk_upsert_invariant.py),
|
|
249
|
+
[`test_upsert_batch_invariant.py`](tests/unit/test_upsert_batch_invariant.py),
|
|
250
|
+
[`test_perf_scaling_guard.py`](tests/unit/test_perf_scaling_guard.py)) are untouched and
|
|
251
|
+
must stay green.
|
|
252
|
+
|
|
253
|
+
### PR-2 — Snowflake sink predicate + wiring + RHS-AST pre-scan + perf counter
|
|
254
|
+
|
|
255
|
+
**Scope:** Land PR-A's scaffolding, add `is_dynamic_name_sink`, extend the pre-scan to
|
|
256
|
+
store RHS ASTs, rewire `_resolve_identifier_tables` to call the PR-1 core, add a
|
|
257
|
+
perf-guard counter.
|
|
258
|
+
|
|
259
|
+
**Files:**
|
|
260
|
+
- `src/sqlcg/parsers/snowflake_parser.py` — pre-scan (master lines **355-364**, currently
|
|
261
|
+
`PropertyEQ`-only; add the `exp.Set` branch and switch both to store ASTs);
|
|
262
|
+
`is_dynamic_name_sink` (new static method); `_resolve_identifier_tables` (port from
|
|
263
|
+
PR-A branch + rewire to the core); wiring call before `_qualify_bare_tables`
|
|
264
|
+
(master ~line **427**).
|
|
265
|
+
- `tests/unit/test_perf_scaling_guard.py` — add a `resolve_dynamic_name` op counter to
|
|
266
|
+
the `count_hot_ops()` context (the file's established counter pattern; see the
|
|
267
|
+
`sg_lineage`/`build_scope`/`traverse_scope` axes ~lines **226-253**); assert it stays
|
|
268
|
+
flat when column count doubles AND fires once per `IDENTIFIER` sink, not per column.
|
|
269
|
+
- `tests/unit/test_identifier_var_indirection.py` + the integration test
|
|
270
|
+
(`tests/integration/snowflake/test_identifier_var_indirection_integration.py`) — port
|
|
271
|
+
from PR-A branch, extend with fold cases.
|
|
272
|
+
|
|
273
|
+
**Anchors (re-confirmed against current master, v1.34.3):**
|
|
274
|
+
- Pre-scan: [`snowflake_parser.py`](src/sqlcg/parsers/snowflake_parser.py) lines
|
|
275
|
+
**355-364** (`var_literals` dict, `PropertyEQ` branch only). The `exp.Set` branch and
|
|
276
|
+
`_resolve_identifier_tables` method do **NOT** exist on master — they are PR-A-branch
|
|
277
|
+
only (confirmed: `git show master:… | grep _resolve_identifier_tables` → empty).
|
|
278
|
+
- Wiring point: before `_qualify_bare_tables(stmt, current_schema)`, master line **427**.
|
|
279
|
+
- EXECUTE IMMEDIATE var path to NOT regress: lines **639-651**
|
|
280
|
+
(`_recover_execute_immediate`, `_EXEC_IMMEDIATE_VAR_RE`) and `_inner_stmts_from_command`
|
|
281
|
+
line **655** — these consume the literal-string map; the AST-map change must keep them
|
|
282
|
+
working.
|
|
283
|
+
|
|
284
|
+
**Acceptance:**
|
|
285
|
+
- `SET v='DL_'||split_part(current_database(),'_',2)||'.DHB.KOSTEN'; FROM identifier($v)`
|
|
286
|
+
→ a `DHB.KOSTEN` source edge with non-empty `full_id` (no empty-id leak).
|
|
287
|
+
- INSERT INTO `identifier($v)` target resolves the write target.
|
|
288
|
+
- JOIN `identifier($v)` resolves.
|
|
289
|
+
- MERGE INTO `identifier($v)` resolves.
|
|
290
|
+
- `ALTER WAREHOUSE IDENTIFIER($w)` produces **no** resolved table (stays `exp.Command`).
|
|
291
|
+
- `CALL MA.MERGE_PREDICTION($SRC_TABLE_NAME, …)` arg produces **no** resolved table.
|
|
292
|
+
- 1-hop chain (`$ODS_DB || '.ods.ig_stibat'`) resolves end-to-end through the parser.
|
|
293
|
+
- A file with no `IDENTIFIER` sink: edge output unchanged (no-op path).
|
|
294
|
+
|
|
295
|
+
**Version:** ships the capability → **v1.35.0** (MINOR). Bump
|
|
296
|
+
[`pyproject.toml`](pyproject.toml) + [`src/sqlcg/__init__.py`](src/sqlcg/__init__.py) +
|
|
297
|
+
`uv lock` in the feature branch per CLAUDE.md release steps.
|
|
298
|
+
|
|
299
|
+
**Metric impact:** wiring active; real gain measured in PR-3.
|
|
300
|
+
|
|
301
|
+
**Frozen-perf note:** the fold is once-per-statement on demand — no qualify / build_scope
|
|
302
|
+
/ exp.expand / sg_lineage, no per-column op. All four frozen suites must stay green; the
|
|
303
|
+
new counter pins the fold's once-per-statement behaviour (a **behavioural** assertion, per
|
|
304
|
+
CLAUDE.md guidance, not a volume count that hides in a too-simple fixture).
|
|
305
|
+
|
|
306
|
+
**Grep-confirmed call sites (required before PR opens):**
|
|
307
|
+
- `resolve_dynamic_name` called from `_resolve_identifier_tables`.
|
|
308
|
+
- `is_dynamic_name_sink` called from `_resolve_identifier_tables`.
|
|
309
|
+
- `_resolve_identifier_tables` called from the file-level statement loop (master ~line
|
|
310
|
+
427 area), before `_qualify_bare_tables`.
|
|
311
|
+
- the RHS-AST pre-scan map read by both `_resolve_identifier_tables` and (literal subset)
|
|
312
|
+
the EXECUTE IMMEDIATE path.
|
|
313
|
+
No method ships defined-but-uncalled.
|
|
314
|
+
|
|
315
|
+
### PR-3 — Live-DWH acceptance + `gain --json` before/after
|
|
316
|
+
|
|
317
|
+
**Scope:** Index the real DWH (`/home/ignwrad/Projects/dwh`) on master and on the feature
|
|
318
|
+
branch; record `sqlcg gain --json` before/after; assert the gain and no regression.
|
|
319
|
+
|
|
320
|
+
**Files:**
|
|
321
|
+
- `plan/metrics/generic_var_name_before_v1.34.3.json` (or the actual master version).
|
|
322
|
+
- `plan/metrics/generic_var_name_after_v1.35.0.json`.
|
|
323
|
+
- `plan/metrics/generic_var_name_gain_context.md` (before/after narrative + the
|
|
324
|
+
catalog-wildcard assumption documented + DWH timing).
|
|
325
|
+
|
|
326
|
+
**Acceptance (run by the planner during compliance, or the DWH tester):**
|
|
327
|
+
- **~136 files gain edges** that previously had none from their `IDENTIFIER($var)` sink
|
|
328
|
+
(count files whose primary FROM/INSERT target newly resolves).
|
|
329
|
+
- **No regression:** `good_edges_strict` and `good_edges_scoped` must **not drop** vs the
|
|
330
|
+
before baseline.
|
|
331
|
+
- **No-literal-catalog-collision assertion** (the study's decisive safety check): assert
|
|
332
|
+
that no two **distinct literal-catalog** tables were merged into one node by the
|
|
333
|
+
wildcard. The wildcard only fires when the catalog position is OPAQUE; a fully-literal
|
|
334
|
+
`catalog.schema.table` keeps its catalog (PR-1 rule 4), so distinct literal catalogs
|
|
335
|
+
cannot collapse. Verify the corpus still has **zero** fully-literal
|
|
336
|
+
`catalog.schema.table` references that would collide (study §3.4 found zero) — record
|
|
337
|
+
the grep result in the context doc.
|
|
338
|
+
|
|
339
|
+
**Version:** none (metrics/docs only); merges with the trio under v1.35.0.
|
|
340
|
+
|
|
341
|
+
**Metric impact:** the headline — ~187 DML refs / ~136 files recovered; record the exact
|
|
342
|
+
delta.
|
|
343
|
+
|
|
344
|
+
**Frozen-perf note:** confirm DWH index time stays within the project's measured baseline
|
|
345
|
+
(~210-256s, CLAUDE.md memory) — the fold adds only an O(nodes-in-RHS) walk per
|
|
346
|
+
`IDENTIFIER` sink. Record the timing in the context doc.
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Test Strategy
|
|
351
|
+
|
|
352
|
+
- **Unit (PR-1):** the eight fold/extract behaviours above, each named
|
|
353
|
+
`test_<behaviour>_<scenario>_<expected>`, docstring linking this plan. Pure-function,
|
|
354
|
+
no parser, no graph.
|
|
355
|
+
- **Unit (PR-2):** sink-predicate positive (FROM/JOIN/INSERT/MERGE) and negative
|
|
356
|
+
(ALTER WAREHOUSE → Command, CALL-arg) cases; end-to-end parse → edge assertions on
|
|
357
|
+
observable `full_id` pairs (the PR-A test pattern: assert edge `src.full_id` /
|
|
358
|
+
`dst.full_id`, and that no empty-id endpoint leaks).
|
|
359
|
+
- **Perf (PR-2):** extend `count_hot_ops()` with a `resolve_dynamic_name` counter; assert
|
|
360
|
+
it is flat under doubled columns and fires once per sink (behavioural, not volume).
|
|
361
|
+
- **Integration (PR-2):** real in-memory DuckDB, a Snowflake file with a folded
|
|
362
|
+
`IDENTIFIER($v)` source and target, assert the SELECTS_FROM + column-lineage edges land
|
|
363
|
+
with the resolved `db.name`.
|
|
364
|
+
- **Live acceptance (PR-3):** `gain --json` before/after on the DWH; the three PR-3
|
|
365
|
+
acceptance assertions above.
|
|
366
|
+
|
|
367
|
+
> Tests describe the behaviour they verify. The developer names them
|
|
368
|
+
> `test_<unit>_<scenario>_<expected>` and links this plan in the docstring. No opaque
|
|
369
|
+
> case codes are seeded here.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Acceptance Criteria
|
|
374
|
+
|
|
375
|
+
- [ ] `resolve_dynamic_name` folds literal/concat/`(SELECT …)`/1-hop-chain to the correct
|
|
376
|
+
catalog-empty `db.name`; gives up (returns `None`) on all-opaque, bare-name, and
|
|
377
|
+
dynamic-schema inputs; keeps a static literal catalog. (PR-1 unit tests pass.)
|
|
378
|
+
- [ ] `is_dynamic_name_sink` returns the `$var` Parameter for `IDENTIFIER($v)` in a table
|
|
379
|
+
position and `None` otherwise; `ALTER WAREHOUSE` and `CALL`-arg never resolve.
|
|
380
|
+
(PR-2 unit tests pass.)
|
|
381
|
+
- [ ] `FROM/INSERT/JOIN/MERGE identifier($v)` with a folded RHS emits a real edge whose
|
|
382
|
+
endpoints have non-empty `full_id`; no empty-id endpoint leaks. (PR-2 tests pass.)
|
|
383
|
+
- [ ] The four frozen perf suites stay green; the new `resolve_dynamic_name` counter stays
|
|
384
|
+
flat when columns double and fires once per sink. (PR-2.)
|
|
385
|
+
- [ ] EXECUTE IMMEDIATE literal-var path (lines 639-651 / `_inner_stmts_from_command`) is
|
|
386
|
+
not regressed by the RHS-AST pre-scan change. (PR-2 — existing tests stay green.)
|
|
387
|
+
- [ ] Live DWH: ~136 files gain edges; `good_edges_strict` / `good_edges_scoped` do not
|
|
388
|
+
drop; no distinct-literal-catalog collision (grep confirms zero literal
|
|
389
|
+
`catalog.schema.table` refs). (PR-3 — metrics recorded.)
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## The bound (flow-gate + enforced limits)
|
|
394
|
+
|
|
395
|
+
This is **not** "resolve all variables". Four enforced gates (study §2.3):
|
|
396
|
+
|
|
397
|
+
1. **Flow gate — string var → table-position sink only.** The fold fires only when a var
|
|
398
|
+
is dereferenced in an `exp.Table` sink via `is_dynamic_name_sink`. Demand-driven: start
|
|
399
|
+
at the sink, resolve backwards; `SET` definitions are never enumerated.
|
|
400
|
+
2. **Fold-depth bound.** Structural recursion over one RHS AST, no fixpoint, no SQL
|
|
401
|
+
execution. O(nodes-in-RHS).
|
|
402
|
+
3. **Chain-depth bound = 1** (default, configurable param). One lookup hop into `var_env`;
|
|
403
|
+
the looked-up value's own `$vars` are not re-followed. Corpus max is 1.
|
|
404
|
+
4. **Give-up-honestly.** All-opaque / no `db.name` tail / unbound var → leave the sink
|
|
405
|
+
dropped (today's behaviour). Silence over a wrong edge.
|
|
406
|
+
|
|
407
|
+
Gates (1)+(4) are the structural answer to the maintainer's "resolve all variables" worry:
|
|
408
|
+
we resolve the **one** name a table sink demands, fold what is constant, and stop.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Risks and Mitigations
|
|
413
|
+
|
|
414
|
+
| Risk | Mitigation |
|
|
415
|
+
|---|---|
|
|
416
|
+
| Catalog-wildcard collapse merges distinct cross-DB tables | KEEP a static literal catalog (PR-1 rule 4); the wildcard only fires on an OPAQUE catalog. PR-3 asserts zero literal `catalog.schema.table` refs to collide with (study §3.4 = zero). Document the env-parameterisation assumption (fork F1). |
|
|
417
|
+
| RHS-AST pre-scan regresses the EXECUTE IMMEDIATE literal path | Keep the literal-string map intact (or derive it); existing tests for lines 639-651 stay green (acceptance criterion). |
|
|
418
|
+
| Over-reach (a var resolving where it should not) | Structural flow gate — non-`exp.Table` sinks never reach the resolver; verified for ALTER WAREHOUSE / CALL / WHERE. Do not add a name blocklist that could rot. |
|
|
419
|
+
| Fold starts scaling with column/edge count | New perf-guard counter pins once-per-statement / once-per-sink, behaviourally. |
|
|
420
|
+
| Branch-scoped reassigned vars | Last-write-wins in source order; none in corpus (study §3.4). Acceptable (better than dropping). |
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## Design forks needing a maintainer decision
|
|
425
|
+
|
|
426
|
+
### F1 — Catalog-wildcard env-parameterisation ASSUMPTION (document, do not block)
|
|
427
|
+
|
|
428
|
+
Collapsing every DB's `DHB.KOSTEN` into one catalog-less node is **correct** in a
|
|
429
|
+
single-warehouse, env-parameterised setup (DEV/TST/ACC/PRD are the *same* logical table)
|
|
430
|
+
and **safe here** because the corpus has zero fully-literal `catalog.schema.table`
|
|
431
|
+
references to collide with (study §3.4). It would be **wrong** in a true cross-DB topology
|
|
432
|
+
where `PROD_DB.DHB.KOSTEN` and `STAGING_DB.DHB.KOSTEN` are distinct *and* referenced
|
|
433
|
+
literally. **Decision needed:** accept the env-parameterisation assumption (recommended —
|
|
434
|
+
it matches the existing catalog-less identity behaviour, and PR-1 rule 4 already keeps a
|
|
435
|
+
*static* literal catalog), and document it in the PR-3 context doc + the postmortem. No
|
|
436
|
+
code gate beyond rule 4 is proposed; flag if the maintainer wants a hard config switch.
|
|
437
|
+
|
|
438
|
+
### F2 — PR-A landing strategy (genuine fork — pick one)
|
|
439
|
+
|
|
440
|
+
PR-A (`fix/identifier-var-indirection`, the literal-only scaffolding) is **NOT merged to
|
|
441
|
+
master** and its referenced plan (`sprint_snowflake_lineage_patterns.md`) does not exist on
|
|
442
|
+
master. Two options:
|
|
443
|
+
|
|
444
|
+
- **Option A (recommended):** absorb PR-A's scaffolding directly into PR-2 of this feature
|
|
445
|
+
(port `_resolve_identifier_tables` + the `exp.Set` pre-scan branch + the two test files),
|
|
446
|
+
rewiring to the fold core in the same PR. The literal case becomes a special case of the
|
|
447
|
+
fold (a single `LIT` part), so PR-A as a standalone literal-only PR adds little value and
|
|
448
|
+
would resolve **zero** real DWH cases (study §1).
|
|
449
|
+
- **Option B:** merge PR-A first as-is (literal-only), then this feature extends it. Costs
|
|
450
|
+
an extra round-trip for a PR the study says resolves zero real corpus cases on its own.
|
|
451
|
+
|
|
452
|
+
**Recommendation: Option A** — fold the literal case into PR-2. Maintainer to confirm.
|
|
453
|
+
|
|
454
|
+
### F3 — Chain depth > 1
|
|
455
|
+
|
|
456
|
+
Planner found **no** chain deeper than 1 hop in the corpus (study §3.4 re-confirmed). The
|
|
457
|
+
`chain_depth` param defaults to 1 and is the enforced bound. No fork unless the maintainer
|
|
458
|
+
wants depth > 1 pre-emptively — **not recommended** (would only fold more OPAQUE here).
|
|
459
|
+
|
|
460
|
+
### F4 — Pre-scan map shape (minor)
|
|
461
|
+
|
|
462
|
+
Keep two maps (literal-string for EXECUTE IMMEDIATE + RHS-AST for the fold), or one AST
|
|
463
|
+
map with a literal-string accessor. Recommend **two maps** for clarity / zero regression
|
|
464
|
+
risk to the EXECUTE IMMEDIATE path. Plan-reviewer to confirm the minimal-risk shape.
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
### Deviations
|
|
469
|
+
|
|
470
|
+
#### Deviation 1: PR-1 was not on master at PR-2 implementation time
|
|
471
|
+
- **Reason**: The PR-2 dispatch brief stated "PR-1 (the fold core) is ALREADY MERGED
|
|
472
|
+
to master" and that `src/sqlcg/parsers/dynamic_name.py` exists on master. On
|
|
473
|
+
inspection master (v1.35.1, commit `a530c6b`) did **not** contain
|
|
474
|
+
`dynamic_name.py`; PR-1 lives unmerged on branch `feat/generic-var-fold-core`
|
|
475
|
+
(commit `34d68c4`), cleanly stacked on master with no open PR.
|
|
476
|
+
- **Change**: The PR-2 branch `feat/generic-var-sink-rewire` was created off
|
|
477
|
+
`feat/generic-var-fold-core` (PR-1) rather than off master, so the fold core is
|
|
478
|
+
present. PR-1's commit was left byte-for-byte unchanged; all PR-2 work sits in
|
|
479
|
+
commits on top. PR-2 must therefore merge AFTER (or together with) PR-1.
|
|
480
|
+
- **Impact**: No code-scope change. The PR diff against master includes PR-1's
|
|
481
|
+
`dynamic_name.py` + its 12 unit fixtures as the base commit. Reviewer/merger
|
|
482
|
+
should land PR-1 first or merge this branch as the combined PR-1+PR-2 unit.
|
|
483
|
+
- **Date**: 2026-06-14
|
|
484
|
+
|
|
485
|
+
#### Deviation 2: `exp.Set` statements are NOT suppressed
|
|
486
|
+
- **Reason**: The plan's var-pre-scan section described capturing `exp.Set` RHS ASTs;
|
|
487
|
+
an initial implementation also suppressed the `SET var = <expr>` statement (mirroring
|
|
488
|
+
the existing `exp.PropertyEQ` suppression). That regressed the pre-existing contract
|
|
489
|
+
`test_set_session_variable_not_parse_failed`, which asserts `SET var = 5;` yields
|
|
490
|
+
exactly one OTHER-kind, non-parse-failed statement (not zero).
|
|
491
|
+
- **Change**: The RHS-AST pre-scan still captures `exp.Set` assignments into `var_rhs`
|
|
492
|
+
(independent of statement emission), but the `exp.Set` statement flows through to be
|
|
493
|
+
emitted as OTHER, exactly as before this feature. Only `exp.PropertyEQ` remains
|
|
494
|
+
suppressed (unchanged pre-existing behaviour).
|
|
495
|
+
- **Impact**: No effect on IDENTIFIER resolution (the pre-scan runs first). Preserves
|
|
496
|
+
the parse-classification contract. Net: one fewer suppression than the plan implied.
|
|
497
|
+
- **Date**: 2026-06-14
|
|
498
|
+
|
|
499
|
+
#### Deviation 3: `registry.register` made generic to preserve concrete parser type
|
|
500
|
+
- **Reason**: `is_dynamic_name_sink` is defined only on `SnowflakeParser`. The
|
|
501
|
+
`@register` decorator's signature `decorator(cls: type[SqlParser]) -> type[SqlParser]`
|
|
502
|
+
narrowed `SnowflakeParser` to `type[SqlParser]`, so pyright rejected
|
|
503
|
+
`SnowflakeParser.is_dynamic_name_sink` access in the new tests.
|
|
504
|
+
- **Change**: `register`'s inner decorator now uses a `TypeVar` bound to
|
|
505
|
+
`type[SqlParser]`, returning the class with its concrete type preserved. The class is
|
|
506
|
+
still returned unchanged at runtime.
|
|
507
|
+
- **Impact**: Pure type-checker improvement; no runtime behaviour change. Benefits any
|
|
508
|
+
future dialect-specific static method, not just this feature.
|
|
509
|
+
- **Date**: 2026-06-14
|
|
510
|
+
|
|
511
|
+
#### Note: pre-existing pyright errors in `tests/unit/test_perf_scaling_guard.py`
|
|
512
|
+
The src-only pyright gate (`.pre-commit-config.yaml` `files: ^src/`) is clean (0 errors).
|
|
513
|
+
`uv run pyright` over the test tree reports 6 `reportPrivateImportUsage` errors for
|
|
514
|
+
`sqlglot.expressions.Expression` annotations on lines 100–188 of
|
|
515
|
+
`test_perf_scaling_guard.py`. These pre-exist on the PR-1 base commit (`34d68c4`,
|
|
516
|
+
verified: 7 such errors before any PR-2 edit) and are not in code this PR added; the
|
|
517
|
+
test files are outside the type-check gate. Left as-is to match the file's existing
|
|
518
|
+
convention.
|