containsWriteCTE reports whether any common table expression in the tree is data-modifying. Fail-safe by construction — a whitelist, not a denylist: a CTE term is read-only ONLY if it is an *ast.SelectStmt, which is how pg models SELECT, VALUES, TABLE, set operations and WITH RECURSIVE. Anything els
(node ast.Node)
| 105 | // INSERT/UPDATE/DELETE/MERGE today, or any write node added to the grammar |
| 106 | // tomorrow — counts as a write, so the next forgotten write type fails closed. |
| 107 | func containsWriteCTE(node ast.Node) bool { |
| 108 | found := false |
| 109 | ast.Inspect(node, func(n ast.Node) bool { |
| 110 | if found { |
| 111 | return false |
| 112 | } |
| 113 | if cte, ok := n.(*ast.CommonTableExpr); ok { |
| 114 | if _, isSelect := cte.Ctequery.(*ast.SelectStmt); !isSelect { |
| 115 | found = true |
| 116 | return false |
| 117 | } |
| 118 | } |
| 119 | return true |
| 120 | }) |
| 121 | return found |
| 122 | } |