)]}'
{
  "commit": "d6f1b7f67087bd86f2e0fe6e1b6c897b7e569926",
  "tree": "7c8e723de4c82fd28634dc50cf06591c0c88189a",
  "parents": [
    "a29e2810b1ac5a9e4c3e553879b683a6a1902c8b"
  ],
  "author": {
    "name": "Greg Felice",
    "email": "gregfelice@gmail.com",
    "time": "Mon Apr 06 11:34:47 2026 -0400"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Mon Apr 06 08:34:47 2026 -0700"
  },
  "message": "Fix MATCH on brand-new label after CREATE returning 0 rows (#2341)\n\n* Fix MATCH on brand-new label after CREATE returning 0 rows (issue #2193)\n\nWhen CREATE introduces a new label and a subsequent MATCH references it\n(e.g., CREATE (:Person) WITH ... MATCH (p:Person)), the query returns\n0 rows on first execution but works on the second.\n\nRoot cause: match_check_valid_label() in transform_cypher_match() runs\nbefore transform_prev_cypher_clause() processes the predecessor chain.\nSince CREATE has not yet executed its transform (which creates the label\ntable as a side effect), the label is not in the cache and the check\ngenerates a One-Time Filter: false plan that returns no rows.\n\nFix: Skip the early label validity check when the predecessor clause\nchain contains a data-modifying operation (CREATE, SET, DELETE, MERGE).\nAfter transform_prev_cypher_clause() completes and any new labels exist\nin the cache, run a deferred label check. If the labels are still\ninvalid at that point, generate an empty result via makeBoolConst(false).\n\nThis preserves the existing behavior for MATCH without DML predecessors\n(e.g., MATCH-MATCH chains still get the early check and proper error\nmessages for invalid labels).\n\nDepends on: PR #2340 (clause_chain_has_dml helper)\n\nCo-Authored-By: Claude Opus 4.6 \u003cnoreply@anthropic.com\u003e\n\n* Address review feedback: fix variable registration for deferred label check\n\nWhen the deferred label validity check (DML predecessor + non-existent\nlabel) found an invalid label, the code skipped transform_match_pattern()\nentirely, which meant MATCH-introduced variables were never registered\nin the namespace. This would cause errors if a later clause referenced\nthose variables (e.g., RETURN p).\n\nFix: mirror the early-check strategy by injecting a paradoxical WHERE\n(true \u003d false) and always calling transform_match_pattern(). Variables\nget registered normally; zero rows are returned via the impossible qual.\n\nAlso add ORDER BY to multi-row regression tests for deterministic output,\nand add a test case for DML predecessor + non-existent label + returning\na MATCH-introduced variable.\n\nCo-Authored-By: Claude Opus 4.6 \u003cnoreply@anthropic.com\u003e\n\n* Address Copilot review: DRY false-where helper, cache has_dml, ORDER BY in tests\n\n- Factor duplicated WHERE true\u003dfalse construction into\n  make_false_where_clause() helper (used in both early and deferred\n  label validation paths)\n- Compute clause_chain_has_dml() once and reuse, avoiding repeated\n  clause chain traversal\n- Add ORDER BY to the single-CREATE City regression test for\n  deterministic result ordering\n\n* Address Copilot review: volatile false predicate, DML side-effect test\n\n1. Prevent plan elimination of DML predecessor: replace constant\n   (true \u003d false) with volatile (random() IS NULL) in the deferred\n   label check path. PG\u0027s planner can constant-fold the former into\n   a One-Time Filter: false, skipping the DML scan entirely.\n\n2. Unify make_false_where_clause(bool volatile_needed): merge the\n   constant and volatile variants into a single parameterized\n   function. Call sites are now self-documenting:\n   - make_false_where_clause(false) for non-DML path\n   - make_false_where_clause(true) for DML predecessor path\n\n3. Document why add_volatile_wrapper() cannot be reused here (it\n   operates post-transform at the Expr level and returns agtype,\n   while the WHERE clause is built at the parse-tree level).\n\n4. Add regression test verifying CREATE side effects persist when\n   MATCH references a non-existent label after a DML predecessor.\n\nAll regression tests pass (cypher_match: ok).\n\nCo-Authored-By: Claude Opus 4.6 \u003cnoreply@anthropic.com\u003e\n\n* Replace non-ASCII em dashes with -- in C comments\n\nASCII-only codebase convention; avoids encoding/tooling issues.\n\nCo-Authored-By: Claude Opus 4.6 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 4.6 \u003cnoreply@anthropic.com\u003e",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "94315f1349c79d0e721117be442387513c267869",
      "old_mode": 33188,
      "old_path": "regress/expected/cypher_match.out",
      "new_id": "2f01d5163779fe4d85829b5762a39fa1094e0b7c",
      "new_mode": 33188,
      "new_path": "regress/expected/cypher_match.out"
    },
    {
      "type": "modify",
      "old_id": "d14f45f10f6d66b8e4a1c680053d9fe268ca23a7",
      "old_mode": 33188,
      "old_path": "regress/sql/cypher_match.sql",
      "new_id": "410d097bb687bd5cb60d325bae3f7e3da4db64e7",
      "new_mode": 33188,
      "new_path": "regress/sql/cypher_match.sql"
    },
    {
      "type": "modify",
      "old_id": "6f06bbb82c8e14285cd12d15cede1f8f8e697184",
      "old_mode": 33188,
      "old_path": "src/backend/parser/cypher_clause.c",
      "new_id": "e5540aa3e63d1503fb68fb5005463d8bf417a3b5",
      "new_mode": 33188,
      "new_path": "src/backend/parser/cypher_clause.c"
    }
  ]
}
