From 3a27681395c2f7adc5bead293a703f041a3a43ac Mon Sep 17 00:00:00 2001 From: meskill <8974488+meskill@users.noreply.github.com> Date: Sat, 7 Feb 2026 19:33:09 +0000 Subject: [PATCH 1/4] raw_parse_iter --- .vscode/settings.json | 1 + docs/recursion_classification.md | 343 +++ raw_parse_iter.md | 15 + src/lib.rs | 2 + src/raw_parse_iter.rs | 3333 ++++++++++++++++++++++++++++++ tests/raw_parse_tests.rs | 38 +- 6 files changed, 3726 insertions(+), 6 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 docs/recursion_classification.md create mode 100644 raw_parse_iter.md create mode 100644 src/raw_parse_iter.rs diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/docs/recursion_classification.md b/docs/recursion_classification.md new file mode 100644 index 0000000..28c70f3 --- /dev/null +++ b/docs/recursion_classification.md @@ -0,0 +1,343 @@ +# Recursion Classification of `raw_parse.rs` Convert Functions + +This document classifies every `convert_*` function in `raw_parse.rs` into two categories: + +1. **Recursive** — the function calls `convert_node`, `convert_node_boxed`, `convert_list_to_nodes`, + or transitively calls another function that does, meaning it re-enters the main `convert_node` + dispatch and can contribute to unbounded recursion depth. + +2. **Non-recursive (leaf)** — the function never re-enters `convert_node`. It only reads scalar + fields, calls `convert_c_string`, or calls other leaf functions. These are safe from stack + overflow regardless of input. + +--- + +## Transitive helper classification + +Before classifying the top-level converters, we need to know which "typed helper" converters +are themselves recursive. A helper is recursive if it calls `convert_node_boxed`, +`convert_list_to_nodes`, or another recursive helper. + +| Helper | Recursive? | Reason | +|---|---|---| +| `convert_c_string` | No | Pure C string → Rust string | +| `convert_function_parameter_mode` | No | Pure enum mapping | +| `convert_string` | No | Only calls `convert_c_string` | +| `convert_role_spec` | No | Only calls `convert_c_string` | +| `convert_json_format` | No | Only scalar fields | +| `convert_json_returning` | No | Only calls `convert_json_format` (leaf) | +| `convert_json_table_path` | No | Only calls `convert_c_string` | +| `convert_alias` | **Yes** | Calls `convert_list_to_nodes(alias.colnames)` | +| `convert_range_var` | **Yes** | Calls `convert_alias` (recursive) | +| `convert_type_name` | **Yes** | Calls `convert_list_to_nodes` (×3: names, typmods, arrayBounds) | +| `convert_object_with_args` | **Yes** | Calls `convert_list_to_nodes` (×3) | +| `convert_window_def` | **Yes** | Calls `convert_list_to_nodes`, `convert_node_boxed` | +| `convert_with_clause` | **Yes** | Calls `convert_list_to_nodes` | +| `convert_with_clause_opt` | **Yes** | Calls `convert_with_clause` | +| `convert_variable_set_stmt` | **Yes** | Calls `convert_list_to_nodes` | +| `convert_variable_set_stmt_opt` | **Yes** | Calls `convert_variable_set_stmt` | +| `convert_collate_clause` | **Yes** | Calls `convert_node_boxed`, `convert_list_to_nodes` | +| `convert_collate_clause_opt` | **Yes** | Calls `convert_collate_clause` | +| `convert_partition_spec` | **Yes** | Calls `convert_list_to_nodes` | +| `convert_partition_spec_opt` | **Yes** | Calls `convert_partition_spec` | +| `convert_partition_bound_spec` | **Yes** | Calls `convert_list_to_nodes` (×3) | +| `convert_partition_bound_spec_opt` | **Yes** | Calls `convert_partition_bound_spec` | +| `convert_cte_search_clause` | **Yes** | Calls `convert_list_to_nodes` | +| `convert_cte_search_clause_opt` | **Yes** | Calls `convert_cte_search_clause` | +| `convert_cte_cycle_clause` | **Yes** | Calls `convert_list_to_nodes`, `convert_node_boxed` | +| `convert_cte_cycle_clause_opt` | **Yes** | Calls `convert_cte_cycle_clause` | +| `convert_infer_clause` | **Yes** | Calls `convert_list_to_nodes`, `convert_node_boxed` | +| `convert_infer_clause_opt` | **Yes** | Calls `convert_list_to_nodes`, `convert_node_boxed` | +| `convert_on_conflict_clause` | **Yes** | Calls `convert_infer_clause`, `convert_list_to_nodes`, `convert_node_boxed` | +| `convert_into_clause` | **Yes** | Calls `convert_range_var`, `convert_list_to_nodes`, `convert_node_boxed` | +| `convert_json_output` | **Yes** | Calls `convert_type_name` (recursive) | +| `convert_json_value_expr` | **Yes** | Calls `convert_node_boxed` | +| `convert_json_behavior` | **Yes** | Calls `convert_node_boxed` | +| `convert_json_agg_constructor` | **Yes** | Calls `convert_node_boxed`, `convert_list_to_nodes`, `convert_window_def` | +| `convert_json_key_value` | **Yes** | Calls `convert_node_boxed`, `convert_json_value_expr` | +| `convert_func_call` | **Yes** | Calls `convert_list_to_nodes`, `convert_node_boxed`, `convert_window_def` | +| `convert_grant_stmt` | **Yes** | Calls `convert_list_to_nodes`, `convert_role_spec` | +| `convert_publication_table` | **Yes** | Calls `convert_range_var`, `convert_node_boxed`, `convert_list_to_nodes` | +| `convert_create_stmt` | **Yes** | Calls `convert_range_var`, `convert_list_to_nodes`, `convert_type_name`, etc. | + +--- + +## Non-Recursive (Leaf) Functions + +These functions **never** re-enter `convert_node` — not directly and not through any transitive +call chain. They are entirely safe from contributing to stack depth. + +| # | Function | Lines | What it calls | +|---|---|---|---| +| 1 | `convert_c_string` | L2177–2183 | — (raw pointer to String) | +| 2 | `convert_function_parameter_mode` | L1933–1943 | — (pure enum match) | +| 3 | `convert_string` | L1516–1518 | `convert_c_string` | +| 4 | `convert_a_const` | L1179–1217 | Reads union fields directly; no node calls | +| 5 | `convert_bit_string` | L2189–2191 | `convert_c_string` | +| 6 | `convert_role_spec` | L1600–1602 | `convert_c_string` | +| 7 | `convert_replica_identity_stmt` | L1520–1522 | `convert_c_string` | +| 8 | `convert_notify_stmt` | L1945–1947 | `convert_c_string` | +| 9 | `convert_listen_stmt` | L1949–1951 | `convert_c_string` | +| 10 | `convert_unlisten_stmt` | L1953–1955 | `convert_c_string` | +| 11 | `convert_discard_stmt` | L1957–1961 | Scalar only | +| 12 | `convert_set_to_default` | L1658–1666 | Scalar only | +| 13 | `convert_trigger_transition` | L2765–2767 | `convert_c_string` | +| 14 | `convert_variable_show_stmt` | L1836–1838 | `convert_c_string` | +| 15 | `convert_deallocate_stmt` | L1654–1656 | `convert_c_string`, scalars | +| 16 | `convert_close_portal_stmt` | L2217–2219 | `convert_c_string` | +| 17 | `convert_fetch_stmt` | L2221–2228 | `convert_c_string`, scalars | +| 18 | `convert_load_stmt` | L2651–2653 | `convert_c_string` | +| 19 | `convert_alter_database_refresh_coll_stmt` | L2622–2624 | `convert_c_string` | +| 20 | `convert_alter_event_trig_stmt` | L2314–2319 | `convert_c_string`, scalars | +| 21 | `convert_drop_table_space_stmt` | L2464–2466 | `convert_c_string`, scalars | +| 22 | `convert_drop_subscription_stmt` | L2666–2668 | `convert_c_string`, scalars | +| 23 | `convert_drop_user_mapping_stmt` | L2436–2442 | `convert_role_spec` (leaf), `convert_c_string` | +| 24 | `convert_json_format` | L2837–2839 | Scalar only | +| 25 | `convert_json_returning` | L2841–2847 | `convert_json_format` (leaf) | +| 26 | `convert_json_table_path` | L2907–2910 | `convert_c_string` | +| 27 | `convert_sql_value_function` | L2793–2795 | Scalar only | + +**Total: 27 non-recursive functions** + +--- + +## Recursive Functions + +These functions **do** re-enter `convert_node` (directly via `convert_node_boxed` / +`convert_list_to_nodes`, or transitively via a recursive helper like `convert_range_var`, +`convert_alias`, `convert_type_name`, etc.). They contribute to stack depth when processing +nested parse trees. + +| # | Function | Lines | Recursive calls (direct) | +|---|---|---|---| +| 1 | `convert_node` | L102–988 | Central dispatch — calls all `convert_*` functions | +| 2 | `convert_node_boxed` | L97–99 | `convert_node` | +| 3 | `convert_list` | L991–994 | `convert_list_to_nodes` | +| 4 | `convert_list_to_nodes` | L999–1020 | `convert_node` (per element) | +| 5 | `convert_list_to_raw_stmts` | L66–89 | `convert_raw_stmt` | +| 6 | `convert_raw_stmt` | L92–94 | `convert_node_boxed` | +| 7 | `convert_select_stmt` | L1026–1049 | `convert_list_to_nodes` (×8), `convert_node_boxed` (×4), `convert_into_clause`, `convert_with_clause_opt`, **self-recursive via larg/rarg** | +| 8 | `convert_insert_stmt` | L1051–1061 | `convert_range_var`, `convert_list_to_nodes` (×2), `convert_node_boxed`, `convert_on_conflict_clause`, `convert_with_clause_opt` | +| 9 | `convert_update_stmt` | L1063–1072 | `convert_range_var`, `convert_list_to_nodes` (×3), `convert_node_boxed`, `convert_with_clause_opt` | +| 10 | `convert_delete_stmt` | L1074–1082 | `convert_range_var`, `convert_list_to_nodes` (×2), `convert_node_boxed`, `convert_with_clause_opt` | +| 11 | `convert_create_stmt` | L1084–1099 | `convert_range_var`, `convert_list_to_nodes` (×4), `convert_type_name`, `convert_partition_bound_spec_opt`, `convert_partition_spec_opt` | +| 12 | `convert_drop_stmt` | L1101–1109 | `convert_list_to_nodes` | +| 13 | `convert_index_stmt` | L1111–1138 | `convert_range_var`, `convert_list_to_nodes` (×4), `convert_node_boxed` | +| 14 | `convert_range_var` | L1144–1154 | `convert_alias` → `convert_list_to_nodes` | +| 15 | `convert_column_ref` | L1156–1158 | `convert_list_to_nodes` | +| 16 | `convert_res_target` | L1160–1167 | `convert_list_to_nodes`, `convert_node_boxed` | +| 17 | `convert_a_expr` | L1169–1177 | `convert_list_to_nodes`, `convert_node_boxed` (×2) | +| 18 | `convert_func_call` | L1219–1233 | `convert_list_to_nodes` (×3), `convert_node_boxed`, `convert_window_def` | +| 19 | `convert_type_cast` | L1235–1241 | `convert_node_boxed`, `convert_type_name` | +| 20 | `convert_type_name` | L1243–1254 | `convert_list_to_nodes` (×3) | +| 21 | `convert_alias` | L1256–1258 | `convert_list_to_nodes` | +| 22 | `convert_join_expr` | L1260–1272 | `convert_node_boxed` (×3), `convert_list_to_nodes`, `convert_alias` (×2) | +| 23 | `convert_sort_by` | L1274–1282 | `convert_node_boxed`, `convert_list_to_nodes` | +| 24 | `convert_bool_expr` | L1284–1291 | `convert_list_to_nodes` | +| 25 | `convert_sub_link` | L1293–1303 | `convert_node_boxed` (×2), `convert_list_to_nodes` | +| 26 | `convert_null_test` | L1305–1313 | `convert_node_boxed` | +| 27 | `convert_case_expr` | L1315–1325 | `convert_node_boxed` (×2), `convert_list_to_nodes` | +| 28 | `convert_case_when` | L1327–1334 | `convert_node_boxed` (×2) | +| 29 | `convert_coalesce_expr` | L1336–1344 | `convert_list_to_nodes` | +| 30 | `convert_with_clause` | L1346–1348 | `convert_list_to_nodes` | +| 31 | `convert_with_clause_opt` | L1350–1356 | `convert_with_clause` | +| 32 | `convert_common_table_expr` | L1358–1374 | `convert_list_to_nodes` (×5), `convert_node_boxed`, `convert_cte_search_clause_opt`, `convert_cte_cycle_clause_opt` | +| 33 | `convert_window_def` | L1376–1387 | `convert_list_to_nodes` (×2), `convert_node_boxed` (×2) | +| 34 | `convert_into_clause` | L1389–1404 | `convert_range_var`, `convert_list_to_nodes` (×2), `convert_node_boxed` | +| 35 | `convert_infer_clause` | L1406–1417 | `convert_list_to_nodes`, `convert_node_boxed` | +| 36 | `convert_on_conflict_clause` | L1419–1431 | `convert_infer_clause`, `convert_list_to_nodes`, `convert_node_boxed` | +| 37 | `convert_column_def` | L1433–1455 | `convert_type_name`, `convert_node_boxed` (×2), `convert_range_var`, `convert_collate_clause_opt`, `convert_list_to_nodes` (×2) | +| 38 | `convert_constraint` | L1457–1491 | `convert_node_boxed` (×2), `convert_list_to_nodes` (×7), `convert_range_var` | +| 39 | `convert_index_elem` | L1493–1504 | `convert_node_boxed`, `convert_list_to_nodes` (×3) | +| 40 | `convert_def_elem` | L1506–1514 | `convert_node_boxed` | +| 41 | `convert_grouping_func` | L1524–1532 | `convert_list_to_nodes` (×2) | +| 42 | `convert_locking_clause` | L1534–1540 | `convert_list_to_nodes` | +| 43 | `convert_min_max_expr` | L1542–1552 | `convert_list_to_nodes` | +| 44 | `convert_grouping_set` | L1554–1556 | `convert_list_to_nodes` | +| 45 | `convert_range_subselect` | L1558–1564 | `convert_node_boxed`, `convert_alias` | +| 46 | `convert_a_array_expr` | L1566–1568 | `convert_list_to_nodes` | +| 47 | `convert_a_indirection` | L1570–1572 | `convert_node_boxed`, `convert_list_to_nodes` | +| 48 | `convert_a_indices` | L1574–1576 | `convert_node_boxed` (×2) | +| 49 | `convert_alter_table_stmt` | L1578–1585 | `convert_range_var`, `convert_list_to_nodes` | +| 50 | `convert_alter_table_cmd` | L1587–1598 | `convert_role_spec`, `convert_node_boxed` | +| 51 | `convert_copy_stmt` | L1604–1615 | `convert_range_var`, `convert_node_boxed` (×2), `convert_list_to_nodes` (×2) | +| 52 | `convert_truncate_stmt` | L1617–1619 | `convert_list_to_nodes` | +| 53 | `convert_view_stmt` | L1621–1630 | `convert_range_var`, `convert_list_to_nodes` (×2), `convert_node_boxed` | +| 54 | `convert_explain_stmt` | L1632–1634 | `convert_node_boxed`, `convert_list_to_nodes` | +| 55 | `convert_create_table_as_stmt` | L1636–1644 | `convert_node_boxed`, `convert_into_clause` | +| 56 | `convert_prepare_stmt` | L1646–1648 | `convert_list_to_nodes`, `convert_node_boxed` | +| 57 | `convert_execute_stmt` | L1650–1652 | `convert_list_to_nodes` | +| 58 | `convert_multi_assign_ref` | L1668–1670 | `convert_node_boxed` | +| 59 | `convert_row_expr` | L1672–1681 | `convert_list_to_nodes` (×2) | +| 60 | `convert_collate_clause` | L1683–1685 | `convert_node_boxed`, `convert_list_to_nodes` | +| 61 | `convert_collate_clause_opt` | L1687–1693 | `convert_collate_clause` | +| 62 | `convert_partition_spec` | L1695–1706 | `convert_list_to_nodes` | +| 63 | `convert_partition_spec_opt` | L1708–1714 | `convert_partition_spec` | +| 64 | `convert_partition_bound_spec` | L1716–1727 | `convert_list_to_nodes` (×3) | +| 65 | `convert_partition_bound_spec_opt` | L1729–1735 | `convert_partition_bound_spec` | +| 66 | `convert_partition_elem` | L1737–1745 | `convert_node_boxed`, `convert_list_to_nodes` (×2) | +| 67 | `convert_partition_range_datum` | L1747–1758 | `convert_node_boxed` | +| 68 | `convert_cte_search_clause` | L1760–1767 | `convert_list_to_nodes` | +| 69 | `convert_cte_search_clause_opt` | L1769–1775 | `convert_cte_search_clause` | +| 70 | `convert_cte_cycle_clause` | L1777–1790 | `convert_list_to_nodes`, `convert_node_boxed` (×2) | +| 71 | `convert_cte_cycle_clause_opt` | L1792–1798 | `convert_cte_cycle_clause` | +| 72 | `convert_transaction_stmt` | L1804–1813 | `convert_list_to_nodes` | +| 73 | `convert_vacuum_stmt` | L1815–1817 | `convert_list_to_nodes` (×2) | +| 74 | `convert_vacuum_relation` | L1819–1825 | `convert_range_var`, `convert_list_to_nodes` | +| 75 | `convert_variable_set_stmt` | L1827–1834 | `convert_list_to_nodes` | +| 76 | `convert_create_seq_stmt` | L1840–1848 | `convert_range_var`, `convert_list_to_nodes` | +| 77 | `convert_do_stmt` | L1850–1852 | `convert_list_to_nodes` | +| 78 | `convert_lock_stmt` | L1854–1856 | `convert_list_to_nodes` | +| 79 | `convert_create_schema_stmt` | L1858–1865 | `convert_role_spec`, `convert_list_to_nodes` | +| 80 | `convert_rename_stmt` | L1867–1878 | `convert_range_var`, `convert_node_boxed` | +| 81 | `convert_create_function_stmt` | L1880–1890 | `convert_list_to_nodes` (×3), `convert_type_name`, `convert_node_boxed` | +| 82 | `convert_alter_owner_stmt` | L1892–1899 | `convert_range_var`, `convert_node_boxed`, `convert_role_spec` | +| 83 | `convert_alter_seq_stmt` | L1901–1908 | `convert_range_var`, `convert_list_to_nodes` | +| 84 | `convert_create_enum_stmt` | L1910–1912 | `convert_list_to_nodes` (×2) | +| 85 | `convert_object_with_args` | L1914–1921 | `convert_list_to_nodes` (×3) | +| 86 | `convert_function_parameter` | L1923–1930 | `convert_type_name`, `convert_node_boxed` | +| 87 | `convert_coerce_to_domain` | L1963–1973 | `convert_node_boxed` | +| 88 | `convert_composite_type_stmt` | L1975–1980 | `convert_range_var`, `convert_list_to_nodes` | +| 89 | `convert_create_domain_stmt` | L1982–1989 | `convert_list_to_nodes` (×2), `convert_type_name`, `convert_collate_clause_opt` | +| 90 | `convert_create_extension_stmt` | L1991–1997 | `convert_list_to_nodes` | +| 91 | `convert_create_publication_stmt` | L1999–2006 | `convert_list_to_nodes` (×2) | +| 92 | `convert_alter_publication_stmt` | L2008–2016 | `convert_list_to_nodes` (×2) | +| 93 | `convert_create_subscription_stmt` | L2018–2025 | `convert_list_to_nodes` (×2) | +| 94 | `convert_alter_subscription_stmt` | L2027–2035 | `convert_list_to_nodes` (×2) | +| 95 | `convert_publication_obj_spec` | L2037–2040 | `convert_publication_table` (recursive) | +| 96 | `convert_publication_table` | L2042–2049 | `convert_range_var`, `convert_node_boxed`, `convert_list_to_nodes` | +| 97 | `convert_create_trig_stmt` | L2051–2069 | `convert_range_var` (×2), `convert_list_to_nodes` (×4), `convert_node_boxed` | +| 98 | `convert_call_stmt` | L2071–2077 | `convert_func_call`, `convert_list_to_nodes` | +| 99 | `convert_rule_stmt` | L2079–2089 | `convert_range_var`, `convert_node_boxed`, `convert_list_to_nodes` | +| 100 | `convert_grant_stmt` | L2091–2103 | `convert_list_to_nodes` (×3), `convert_role_spec` | +| 101 | `convert_grant_role_stmt` | L2105–2114 | `convert_list_to_nodes` (×3), `convert_role_spec` | +| 102 | `convert_refresh_mat_view_stmt` | L2116–2122 | `convert_range_var` (recursive via alias) | +| 103 | `convert_merge_stmt` | L2124–2133 | `convert_range_var`, `convert_node_boxed` (×2), `convert_list_to_nodes` (×2), `convert_with_clause_opt` | +| 104 | `convert_merge_action` | L2135–2144 | `convert_node_boxed`, `convert_list_to_nodes` (×2) | +| 105 | `convert_merge_when_clause` | L2146–2155 | `convert_node_boxed`, `convert_list_to_nodes` (×2) | +| 106 | `convert_range_function` | L2157–2166 | `convert_list_to_nodes` (×2), `convert_alias` | +| 107 | `convert_access_priv` | L2168–2170 | `convert_list_to_nodes` | +| 108 | `convert_boolean_test` | L2193–2200 | `convert_node_boxed` | +| 109 | `convert_create_range_stmt` | L2202–2204 | `convert_list_to_nodes` (×2) | +| 110 | `convert_alter_enum_stmt` | L2206–2215 | `convert_list_to_nodes` | +| 111 | `convert_declare_cursor_stmt` | L2230–2232 | `convert_node_boxed` | +| 112 | `convert_define_stmt` | L2234–2244 | `convert_list_to_nodes` (×3) | +| 113 | `convert_comment_stmt` | L2246–2248 | `convert_node_boxed` | +| 114 | `convert_sec_label_stmt` | L2250–2257 | `convert_node_boxed` | +| 115 | `convert_create_role_stmt` | L2259–2261 | `convert_list_to_nodes` | +| 116 | `convert_alter_role_stmt` | L2263–2269 | `convert_role_spec`, `convert_list_to_nodes` | +| 117 | `convert_alter_role_set_stmt` | L2271–2277 | `convert_role_spec`, `convert_variable_set_stmt_opt` (recursive) | +| 118 | `convert_drop_role_stmt` | L2279–2281 | `convert_list_to_nodes` | +| 119 | `convert_create_policy_stmt` | L2283–2293 | `convert_range_var`, `convert_list_to_nodes`, `convert_node_boxed` (×2) | +| 120 | `convert_alter_policy_stmt` | L2295–2303 | `convert_range_var`, `convert_list_to_nodes`, `convert_node_boxed` (×2) | +| 121 | `convert_create_event_trig_stmt` | L2305–2312 | `convert_list_to_nodes` (×2) | +| 122 | `convert_create_plang_stmt` | L2321–2330 | `convert_list_to_nodes` (×3) | +| 123 | `convert_create_am_stmt` | L2332–2338 | `convert_list_to_nodes` | +| 124 | `convert_create_op_class_stmt` | L2340–2349 | `convert_list_to_nodes` (×3), `convert_type_name` | +| 125 | `convert_create_op_class_item` | L2351–2360 | `convert_object_with_args`, `convert_list_to_nodes` (×2), `convert_type_name` | +| 126 | `convert_create_op_family_stmt` | L2362–2364 | `convert_list_to_nodes` | +| 127 | `convert_alter_op_family_stmt` | L2366–2373 | `convert_list_to_nodes` (×2) | +| 128 | `convert_create_fdw_stmt` | L2375–2381 | `convert_list_to_nodes` (×2) | +| 129 | `convert_alter_fdw_stmt` | L2383–2389 | `convert_list_to_nodes` (×2) | +| 130 | `convert_create_foreign_server_stmt` | L2391–2400 | `convert_list_to_nodes` | +| 131 | `convert_alter_foreign_server_stmt` | L2402–2409 | `convert_list_to_nodes` | +| 132 | `convert_create_foreign_table_stmt` | L2411–2417 | `convert_create_stmt` (recursive), `convert_list_to_nodes` | +| 133 | `convert_create_user_mapping_stmt` | L2419–2426 | `convert_role_spec`, `convert_list_to_nodes` | +| 134 | `convert_alter_user_mapping_stmt` | L2428–2434 | `convert_role_spec`, `convert_list_to_nodes` | +| 135 | `convert_import_foreign_schema_stmt` | L2444–2453 | `convert_list_to_nodes` (×2) | +| 136 | `convert_create_table_space_stmt` | L2455–2462 | `convert_role_spec`, `convert_list_to_nodes` | +| 137 | `convert_alter_table_space_options_stmt` | L2468–2474 | `convert_list_to_nodes` | +| 138 | `convert_alter_table_move_all_stmt` | L2476–2484 | `convert_list_to_nodes` | +| 139 | `convert_alter_extension_stmt` | L2486–2488 | `convert_list_to_nodes` | +| 140 | `convert_alter_extension_contents_stmt` | L2490–2497 | `convert_node_boxed` | +| 141 | `convert_alter_domain_stmt` | L2499–2508 | `convert_list_to_nodes`, `convert_node_boxed` | +| 142 | `convert_alter_function_stmt` | L2510–2516 | `convert_object_with_args`, `convert_list_to_nodes` | +| 143 | `convert_alter_operator_stmt` | L2518–2523 | `convert_object_with_args`, `convert_list_to_nodes` | +| 144 | `convert_alter_type_stmt` | L2525–2527 | `convert_list_to_nodes` (×2) | +| 145 | `convert_alter_object_schema_stmt` | L2529–2537 | `convert_range_var`, `convert_node_boxed` | +| 146 | `convert_alter_object_depends_stmt` | L2539–2547 | `convert_range_var`, `convert_node_boxed`, `convert_string` | +| 147 | `convert_alter_collation_stmt` | L2549–2551 | `convert_list_to_nodes` | +| 148 | `convert_alter_default_privileges_stmt` | L2553–2558 | `convert_list_to_nodes`, `convert_grant_stmt` (recursive) | +| 149 | `convert_create_cast_stmt` | L2560–2568 | `convert_type_name` (×2), `convert_object_with_args` | +| 150 | `convert_create_transform_stmt` | L2570–2578 | `convert_type_name`, `convert_object_with_args` (×2) | +| 151 | `convert_create_conversion_stmt` | L2580–2588 | `convert_list_to_nodes` (×2) | +| 152 | `convert_alter_ts_dictionary_stmt` | L2590–2592 | `convert_list_to_nodes` (×2) | +| 153 | `convert_alter_ts_configuration_stmt` | L2594–2604 | `convert_list_to_nodes` (×3) | +| 154 | `convert_createdb_stmt` | L2606–2608 | `convert_list_to_nodes` | +| 155 | `convert_dropdb_stmt` | L2610–2612 | `convert_list_to_nodes` | +| 156 | `convert_alter_database_stmt` | L2614–2616 | `convert_list_to_nodes` | +| 157 | `convert_alter_database_set_stmt` | L2618–2620 | `convert_variable_set_stmt_opt` (recursive) | +| 158 | `convert_alter_system_stmt` | L2626–2628 | `convert_variable_set_stmt_opt` (recursive) | +| 159 | `convert_cluster_stmt` | L2630–2636 | `convert_range_var`, `convert_list_to_nodes` | +| 160 | `convert_reindex_stmt` | L2638–2645 | `convert_range_var`, `convert_list_to_nodes` | +| 161 | `convert_constraints_set_stmt` | L2647–2649 | `convert_list_to_nodes` | +| 162 | `convert_drop_owned_stmt` | L2655–2657 | `convert_list_to_nodes` | +| 163 | `convert_reassign_owned_stmt` | L2659–2664 | `convert_list_to_nodes`, `convert_role_spec` | +| 164 | `convert_table_func` | L2670–2690 | `convert_list_to_nodes` (×11), `convert_node_boxed` (×3) | +| 165 | `convert_into_clause_node` | L2692–2703 | `convert_range_var`, `convert_list_to_nodes` (×2), `convert_node_boxed` | +| 166 | `convert_table_like_clause` | L2705–2711 | `convert_range_var` | +| 167 | `convert_range_table_func` | L2713–2723 | `convert_node_boxed` (×2), `convert_list_to_nodes` (×2), `convert_alias` | +| 168 | `convert_range_table_func_col` | L2725–2735 | `convert_type_name`, `convert_node_boxed` (×2) | +| 169 | `convert_range_table_sample` | L2737–2745 | `convert_node_boxed` (×2), `convert_list_to_nodes` (×2) | +| 170 | `convert_partition_cmd` | L2747–2753 | `convert_range_var`, `convert_partition_bound_spec_opt` | +| 171 | `convert_on_conflict_clause_node` | L2755–2763 | `convert_infer_clause_opt`, `convert_list_to_nodes`, `convert_node_boxed` | +| 172 | `convert_create_stats_stmt` | L2769–2779 | `convert_list_to_nodes` (×4) | +| 173 | `convert_alter_stats_stmt` | L2781–2787 | `convert_list_to_nodes`, `convert_node_boxed` | +| 174 | `convert_stats_elem` | L2789–2791 | `convert_node_boxed` | +| 175 | `convert_xml_expr` | L2797–2811 | `convert_list_to_nodes` (×3) | +| 176 | `convert_xml_serialize` | L2813–2821 | `convert_node_boxed`, `convert_type_name` | +| 177 | `convert_named_arg_expr` | L2823–2831 | `convert_node_boxed` | +| 178 | `convert_json_value_expr` | L2849–2855 | `convert_node_boxed` (×2), `convert_json_format` | +| 179 | `convert_json_constructor_expr` | L2857–2869 | `convert_list_to_nodes`, `convert_node_boxed` (×2), `convert_json_returning` | +| 180 | `convert_json_is_predicate` | L2871–2879 | `convert_node_boxed`, `convert_json_format` | +| 181 | `convert_json_behavior` | L2881–2883 | `convert_node_boxed` | +| 182 | `convert_json_expr` | L2885–2905 | `convert_node_boxed` (×2), `convert_json_format`, `convert_json_returning`, `convert_list_to_nodes` (×2), `convert_json_behavior` (×2) | +| 183 | `convert_json_table_path_scan` | L2912–2921 | `convert_node_boxed` (×2), `convert_json_table_path` | +| 184 | `convert_json_table_sibling_join` | L2923–2929 | `convert_node_boxed` (×3) | +| 185 | `convert_json_output` | L2931–2936 | `convert_type_name` (recursive), `convert_json_returning` | +| 186 | `convert_json_argument` | L2938–2943 | `convert_json_value_expr` (recursive) | +| 187 | `convert_json_func_expr` | L2945–2959 | `convert_json_value_expr`, `convert_node_boxed`, `convert_list_to_nodes`, `convert_json_output`, `convert_json_behavior` (×2) | +| 188 | `convert_json_table_path_spec` | L2961–2968 | `convert_node_boxed` | +| 189 | `convert_json_table` | L2970–2981 | `convert_json_value_expr`, `convert_json_table_path_spec`, `convert_list_to_nodes` (×2), `convert_json_behavior`, `convert_alias` | +| 190 | `convert_json_table_column` | L2983–2997 | `convert_type_name`, `convert_json_table_path_spec`, `convert_json_format`, `convert_list_to_nodes`, `convert_json_behavior` (×2) | +| 191 | `convert_json_key_value` | L2999–3004 | `convert_node_boxed`, `convert_json_value_expr` | +| 192 | `convert_json_parse_expr` | L3006–3013 | `convert_json_value_expr`, `convert_json_output` | +| 193 | `convert_json_scalar_expr` | L3015–3021 | `convert_node_boxed`, `convert_json_output` | +| 194 | `convert_json_serialize_expr` | L3023–3029 | `convert_json_value_expr`, `convert_json_output` | +| 195 | `convert_json_object_constructor` | L3031–3039 | `convert_list_to_nodes`, `convert_json_output` | +| 196 | `convert_json_array_constructor` | L3041–3048 | `convert_list_to_nodes`, `convert_json_output` | +| 197 | `convert_json_array_query_constructor` | L3050–3058 | `convert_node_boxed`, `convert_json_output`, `convert_json_format` | +| 198 | `convert_json_agg_constructor` | L3060–3068 | `convert_json_output`, `convert_node_boxed`, `convert_list_to_nodes`, `convert_window_def` | +| 199 | `convert_json_object_agg` | L3070–3077 | `convert_json_agg_constructor` (recursive), `convert_json_key_value` (recursive) | +| 200 | `convert_json_array_agg` | L3079–3085 | `convert_json_agg_constructor` (recursive), `convert_json_value_expr` (recursive) | +| 201 | `convert_variable_set_stmt_opt` | L3091–3097 | `convert_variable_set_stmt` (recursive) | +| 202 | `convert_infer_clause_opt` | L3099–3111 | `convert_list_to_nodes`, `convert_node_boxed` | + +**Total: 202 recursive functions** (including the 6 core dispatch/list functions) + +--- + +## Summary + +| Category | Count | Notes | +|---|---|---| +| **Non-recursive (leaf)** | 27 | Safe — never re-enter `convert_node` | +| **Recursive** | 202 | Re-enter `convert_node` directly or transitively | +| **Total** | 229 | All `convert_*` functions in `raw_parse.rs` | + +The overwhelming majority of functions are recursive because nearly every PostgreSQL node type +contains at least one `List` field (converted via `convert_list_to_nodes`) or a child `Node*` +pointer (converted via `convert_node_boxed`). Even seemingly simple types like `RangeVar` are +recursive because they contain an optional `Alias`, which in turn has a `colnames` list that +goes through `convert_list_to_nodes`. + +### Highest-risk recursion paths (unbounded depth) + +| Path | Cause | +|---|---| +| `convert_select_stmt` → `convert_select_stmt` (larg/rarg) | Long `UNION`/`INTERSECT`/`EXCEPT` chains | +| `convert_bool_expr` → `convert_list_to_nodes` → `convert_node` → `convert_bool_expr` | Deeply nested `AND`/`OR` | +| `convert_join_expr` → `convert_node_boxed` (larg/rarg) → `convert_node` → `convert_join_expr` | Many-way explicit `JOIN` | +| `convert_sub_link` → `convert_node_boxed` (subselect) → `convert_node` → `convert_select_stmt` → ... | Nested subqueries | +| `convert_a_expr` → `convert_node_boxed` (lexpr/rexpr) → `convert_node` → `convert_a_expr` | Deeply nested expressions | +| `convert_case_expr` → `convert_list_to_nodes` → ... → `convert_case_expr` | Nested `CASE` expressions | diff --git a/raw_parse_iter.md b/raw_parse_iter.md new file mode 100644 index 0000000..9dc8808 --- /dev/null +++ b/raw_parse_iter.md @@ -0,0 +1,15 @@ + Root + / | \ + left mid right + +1. Stack: Node(Root), result: [] +2. Stack: Collect(Root), Node(left), Node(mid), Node(right), result: [] +3. Stack: Collect(Root), Node(left), Node(mid), Collect(right), Node(right_1), Node(right_2), result: [] +4. Stack: Collect(Root), Node(left), Node(mid), Collect(right), Node(right_1), result: [right_2] +5. Stack: Collect(Root), Node(left), Node(mid), Collect(right), Collect(right_1), Node(right_1_1), Node(right_1_2), result: [right_2] +6. Stack: Collect(Root), Node(left), Node(mid), Collect(right), Collect(right_1), Node(right_1_1), result: [right_2, right_1_2] +7. Stack: Collect(Root), Node(left), Node(mid), Collect(right), Collect(right_1), result: [right_2, right_1_2, right_1_1] +8. Stack: Collect(Root), Node(left), Node(mid), Collect(right), result: [right_2, right_1] +9. Stack: Collect(Root), Node(left), Node(mid), result: [right] +10. Stack: Collect(Root), Node(left), result: [right, mid] +11. Stack: Collect(Root), Collect(left), Node(left_1), Node(left_2), result: [right, mid] diff --git a/src/lib.rs b/src/lib.rs index 2a12dfb..0a7d16a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,6 +52,7 @@ mod query; mod raw_deparse; mod raw_fingerprint; mod raw_parse; +mod raw_parse_iter; mod raw_scan; mod summary; mod summary_result; @@ -66,6 +67,7 @@ pub use query::*; pub use raw_deparse::{deparse_raw, deparse_raw_with_stack}; pub use raw_fingerprint::fingerprint_raw; pub use raw_parse::{parse_raw, parse_raw_with_stack}; +pub use raw_parse_iter::parse_raw_iter; pub use raw_scan::scan_raw; pub use summary::*; pub use summary_result::*; diff --git a/src/raw_parse_iter.rs b/src/raw_parse_iter.rs new file mode 100644 index 0000000..9f91a24 --- /dev/null +++ b/src/raw_parse_iter.rs @@ -0,0 +1,3333 @@ +//! Direct parsing that bypasses protobuf serialization/deserialization. +//! +//! This module provides a faster alternative to the protobuf-based parsing by +//! directly reading PostgreSQL's internal parse tree structures and converting +//! them to Rust protobuf types. + +use crate::bindings; +use crate::bindings_raw; +use crate::parse_result::ParseResult; +use crate::protobuf; +use crate::{Error, Result}; +use std::collections::VecDeque; +use std::ffi::{CStr, CString}; +use std::os::raw::c_char; + +/// Parses a SQL statement directly into protobuf types without going through protobuf serialization. +/// +/// This function is faster than `parse` because it skips the protobuf encode/decode step. +/// The parse tree is read directly from PostgreSQL's internal C structures. +/// +/// # Example +/// +/// ```rust +/// let result = pg_query::parse_raw("SELECT * FROM users").unwrap(); +/// assert_eq!(result.tables(), vec!["users"]); +/// ``` +pub fn parse_raw_iter(statement: &str) -> Result { + let input = CString::new(statement)?; + let result = unsafe { bindings_raw::pg_query_parse_raw(input.as_ptr()) }; + + let parse_result = if !result.error.is_null() { + let message = unsafe { CStr::from_ptr((*result.error).message) }.to_string_lossy().to_string(); + Err(Error::Parse(message)) + } else { + // Convert the C parse tree to protobuf types + let tree = result.tree; + let stmts = unsafe { convert_list_to_raw_stmts(tree) }; + let protobuf = protobuf::ParseResult { version: bindings::PG_VERSION_NUM as i32, stmts }; + Ok(ParseResult::new(protobuf, String::new())) + }; + + unsafe { bindings_raw::pg_query_free_raw_parse_result(result) }; + parse_result +} + +/// Converts a PostgreSQL List of RawStmt nodes to protobuf RawStmt vector. +unsafe fn convert_list_to_raw_stmts(list: *mut bindings_raw::List) -> Vec { + if list.is_null() { + return Vec::new(); + } + + let list_ref = &*list; + let length = list_ref.length as usize; + let mut stmts = Vec::with_capacity(length); + + for i in 0..length { + let cell = list_ref.elements.add(i); + let node_ptr = (*cell).ptr_value as *mut bindings_raw::Node; + + if !node_ptr.is_null() { + let node_tag = (*node_ptr).type_; + if node_tag == bindings_raw::NodeTag_T_RawStmt { + let raw_stmt = node_ptr as *mut bindings_raw::RawStmt; + stmts.push(convert_raw_stmt(&*raw_stmt)); + } + } + } + + stmts +} + +/// Converts a C RawStmt to a protobuf RawStmt. +unsafe fn convert_raw_stmt(raw_stmt: &bindings_raw::RawStmt) -> protobuf::RawStmt { + let mut processor = Processor::new(raw_stmt.stmt); + + processor.process(); + + protobuf::RawStmt { stmt: processor.get_result(), stmt_location: raw_stmt.stmt_location, stmt_len: raw_stmt.stmt_len } +} + +/// Converts a C Node pointer to a boxed protobuf Node (for fields that expect Option>). +unsafe fn convert_node_boxed(node_ptr: *const bindings_raw::Node) -> Option> { + convert_node(node_ptr).map(Box::new) +} + +struct ProcessingNode { + collect: bool, + node: *const bindings_raw::Node, +} + +impl ProcessingNode { + #[inline] + fn with_node(node: *const bindings_raw::Node) -> Self { + Self { collect: false, node } + } + + #[inline] + fn with_collect(node: *const bindings_raw::Node) -> Self { + Self { collect: true, node } + } +} + +struct Processor { + stack: Vec, + result_stack: Vec, +} + +impl Processor { + fn new(root: *const bindings_raw::Node) -> Self { + Self { stack: vec![ProcessingNode { collect: false, node: root }], result_stack: Default::default() } + } + + fn get_result(mut self) -> Option> { + let result = self.result_stack.pop(); + + assert!(self.result_stack.is_empty(), "Result stack should be empty after processing"); + + result.map(Box::new) + } + + unsafe fn process(&mut self) { + while let Some(entry) = self.stack.pop() { + let collect = entry.collect; + let node_ptr = entry.node; + + if node_ptr.is_null() { + continue; + } + + let node_tag = (*node_ptr).type_; + + match node_tag { + // Types that need Box + bindings_raw::NodeTag_T_SelectStmt => { + let stmt = node_ptr as *const bindings_raw::SelectStmt; + + if collect { + let stmt = self.collect_select_stmt(&*stmt); + self.push_result(stmt); + } else { + self.queue_collect(node_ptr); + self.queue_select_stmt(&*stmt); + } + } + _ => { + todo!() + } + } + } + } + + fn queue_node(&mut self, node: *const bindings_raw::Node) { + self.stack.push(ProcessingNode::with_node(node)); + } + + fn queue_collect(&mut self, node: *const bindings_raw::Node) { + self.stack.push(ProcessingNode::with_collect(node)) + } + + fn push_result(&mut self, node: protobuf::node::Node) { + self.result_stack.push(protobuf::Node { node: Some(node) }); + } + + fn single_result(&mut self, node: *const bindings_raw::Node) -> Option { + if node.is_null() { + return None; + } + + Some(self.result_stack.pop().expect("result stack should not be empty while processing")) + } + + fn single_result_box(&mut self, node: *const bindings_raw::Node) -> Option> { + self.single_result(node).map(Box::new) + } + + fn fetch_results(&mut self, count: usize) -> Vec { + let start = self.result_stack.len() - count; + self.result_stack.drain(start..).rev().collect() + } + + unsafe fn queue_list_nodes(&mut self, list: *mut bindings_raw::List) { + if list.is_null() { + return; + } + let list = &*list; + let length = list.length as usize; + + self.stack.reserve(length); + + for i in 0..length { + let cell = list.elements.add(i); + let node = (*cell).ptr_value as *const bindings_raw::Node; + + self.stack.push(ProcessingNode::with_node(node)); + } + } + + unsafe fn fetch_list_results(&mut self, list: *const bindings_raw::List) -> Vec { + if list.is_null() { + return Vec::new(); + } + let list = &*list; + let length = list.length as usize; + + self.fetch_results(length) + } + + unsafe fn queue_into_clause(&mut self, ic: *const bindings_raw::IntoClause) { + if ic.is_null() { + return; + } + let ic_ref = &*ic; + // Some(Box::new(protobuf::IntoClause { + // rel: if ic_ref.rel.is_null() { None } else { Some(convert_range_var(&*ic_ref.rel)) }, + // col_names: self.convert_list_to_nodes(ic_ref.colNames), + // access_method: convert_c_string(ic_ref.accessMethod), + // options: self.convert_list_to_nodes(ic_ref.options), + // on_commit: ic_ref.onCommit as i32 + 1, + // table_space_name: convert_c_string(ic_ref.tableSpaceName), + // view_query: convert_node_boxed(ic_ref.viewQuery), + // skip_data: ic_ref.skipData, + // })); + } + + unsafe fn fetch_into_clause(&mut self, ic: *const bindings_raw::IntoClause) -> Option> { + if ic.is_null() { + return None; + } + let ic_ref = &*ic; + Some(Box::new(protobuf::IntoClause { + rel: if ic_ref.rel.is_null() { None } else { Some(convert_range_var(&*ic_ref.rel)) }, + col_names: self.fetch_list_results(ic_ref.colNames), + access_method: convert_c_string(ic_ref.accessMethod), + options: self.fetch_list_results(ic_ref.options), + on_commit: ic_ref.onCommit as i32 + 1, + table_space_name: convert_c_string(ic_ref.tableSpaceName), + view_query: self.single_result(ic_ref.viewQuery).map(Box::new), + skip_data: ic_ref.skipData, + })) + } + + unsafe fn queue_with_clause(&mut self, wc: *mut bindings_raw::WithClause) { + if wc.is_null() { + return; + } + + let wc = &*wc; + + self.queue_list_nodes(wc.ctes); + } + + unsafe fn fetch_with_clause(&mut self, wc: *mut bindings_raw::WithClause) -> Option { + if wc.is_null() { + return None; + } + + let wc = &*wc; + + Some(protobuf::WithClause { ctes: self.fetch_list_results(wc.ctes), recursive: wc.recursive, location: wc.location }) + } + + unsafe fn queue_select_stmt(&mut self, stmt: &bindings_raw::SelectStmt) { + self.queue_list_nodes(stmt.distinctClause); + self.queue_into_clause(stmt.intoClause); + self.queue_list_nodes(stmt.targetList); + self.queue_list_nodes(stmt.fromClause); + self.queue_node(stmt.whereClause); + self.queue_list_nodes(stmt.groupClause); + self.queue_node(stmt.havingClause); + self.queue_list_nodes(stmt.windowClause); + self.queue_list_nodes(stmt.valuesLists); + self.queue_list_nodes(stmt.sortClause); + self.queue_node(stmt.limitOffset); + self.queue_node(stmt.limitCount); + self.queue_list_nodes(stmt.lockingClause); + self.queue_with_clause(stmt.withClause); + + if !stmt.larg.is_null() { + self.queue_node(stmt.larg as *const bindings_raw::Node); + } + + if !stmt.rarg.is_null() { + self.queue_node(stmt.rarg as *const bindings_raw::Node); + } + } + + fn pop_select_stmt(&mut self) -> Option> { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::SelectStmt(s)) => Some(s), + _ => None, + }) + } + + unsafe fn collect_select_stmt(&mut self, stmt: &bindings_raw::SelectStmt) -> protobuf::node::Node { + let a = protobuf::SelectStmt { + distinct_clause: self.fetch_list_results(stmt.distinctClause), + into_clause: self.fetch_into_clause(stmt.intoClause), + target_list: self.fetch_list_results(stmt.targetList), + from_clause: self.fetch_list_results(stmt.fromClause), + where_clause: self.single_result_box(stmt.whereClause), + group_clause: self.fetch_list_results(stmt.groupClause), + group_distinct: stmt.groupDistinct, + having_clause: self.single_result_box(stmt.havingClause), + window_clause: self.fetch_list_results(stmt.windowClause), + values_lists: self.fetch_list_results(stmt.valuesLists), + sort_clause: self.fetch_list_results(stmt.sortClause), + limit_offset: self.single_result_box(stmt.limitOffset), + limit_count: self.single_result_box(stmt.limitCount), + limit_option: stmt.limitOption as i32 + 1, // Protobuf enums have UNDEFINED=0, so C values need +1 + locking_clause: self.fetch_list_results(stmt.lockingClause), + with_clause: self.fetch_with_clause(stmt.withClause), + op: stmt.op as i32 + 1, // Protobuf SetOperation has UNDEFINED=0, so C values need +1 + all: stmt.all, + larg: if stmt.larg.is_null() { None } else { self.pop_select_stmt() }, + rarg: if stmt.rarg.is_null() { None } else { self.pop_select_stmt() }, + }; + + protobuf::node::Node::SelectStmt(Box::new(a)) + } +} + +/// Converts a C Node pointer to a protobuf Node. +unsafe fn convert_node(node_ptr: *const bindings_raw::Node) -> Option { + if node_ptr.is_null() { + return None; + } + + let node_tag = (*node_ptr).type_; + let node = match node_tag { + // Types that need Box + bindings_raw::NodeTag_T_SelectStmt => { + let stmt = node_ptr as *const bindings_raw::SelectStmt; + Some(protobuf::node::Node::SelectStmt(Box::new(convert_select_stmt(&*stmt)))) + } + // TODO: migrate to new approach + // bindings_raw::NodeTag_T_InsertStmt => { + // let stmt = node_ptr as *mut bindings_raw::InsertStmt; + // Some(protobuf::node::Node::InsertStmt(Box::new(convert_insert_stmt(&*stmt)))) + // } + // bindings_raw::NodeTag_T_UpdateStmt => { + // let stmt = node_ptr as *mut bindings_raw::UpdateStmt; + // Some(protobuf::node::Node::UpdateStmt(Box::new(convert_update_stmt(&*stmt)))) + // } + // bindings_raw::NodeTag_T_DeleteStmt => { + // let stmt = node_ptr as *mut bindings_raw::DeleteStmt; + // Some(protobuf::node::Node::DeleteStmt(Box::new(convert_delete_stmt(&*stmt)))) + // } + // bindings_raw::NodeTag_T_ResTarget => { + // let rt = node_ptr as *mut bindings_raw::ResTarget; + // Some(protobuf::node::Node::ResTarget(Box::new(convert_res_target(&*rt)))) + // } + // bindings_raw::NodeTag_T_A_Expr => { + // let expr = node_ptr as *mut bindings_raw::A_Expr; + // Some(protobuf::node::Node::AExpr(Box::new(convert_a_expr(&*expr)))) + // } + // bindings_raw::NodeTag_T_A_Const => { + // let aconst = node_ptr as *mut bindings_raw::A_Const; + // Some(protobuf::node::Node::AConst(convert_a_const(&*aconst))) + // } + // bindings_raw::NodeTag_T_FuncCall => { + // let fc = node_ptr as *mut bindings_raw::FuncCall; + // Some(protobuf::node::Node::FuncCall(Box::new(convert_func_call(&*fc)))) + // } + // bindings_raw::NodeTag_T_TypeCast => { + // let tc = node_ptr as *mut bindings_raw::TypeCast; + // Some(protobuf::node::Node::TypeCast(Box::new(convert_type_cast(&*tc)))) + // } + // bindings_raw::NodeTag_T_JoinExpr => { + // let je = node_ptr as *mut bindings_raw::JoinExpr; + // Some(protobuf::node::Node::JoinExpr(Box::new(convert_join_expr(&*je)))) + // } + // bindings_raw::NodeTag_T_SortBy => { + // let sb = node_ptr as *mut bindings_raw::SortBy; + // Some(protobuf::node::Node::SortBy(Box::new(convert_sort_by(&*sb)))) + // } + // bindings_raw::NodeTag_T_BoolExpr => { + // let be = node_ptr as *mut bindings_raw::BoolExpr; + // Some(protobuf::node::Node::BoolExpr(Box::new(convert_bool_expr(&*be)))) + // } + // bindings_raw::NodeTag_T_SubLink => { + // let sl = node_ptr as *mut bindings_raw::SubLink; + // Some(protobuf::node::Node::SubLink(Box::new(convert_sub_link(&*sl)))) + // } + // bindings_raw::NodeTag_T_NullTest => { + // let nt = node_ptr as *mut bindings_raw::NullTest; + // Some(protobuf::node::Node::NullTest(Box::new(convert_null_test(&*nt)))) + // } + // bindings_raw::NodeTag_T_CaseExpr => { + // let ce = node_ptr as *mut bindings_raw::CaseExpr; + // Some(protobuf::node::Node::CaseExpr(Box::new(convert_case_expr(&*ce)))) + // } + // bindings_raw::NodeTag_T_CaseWhen => { + // let cw = node_ptr as *mut bindings_raw::CaseWhen; + // Some(protobuf::node::Node::CaseWhen(Box::new(convert_case_when(&*cw)))) + // } + // bindings_raw::NodeTag_T_CoalesceExpr => { + // let ce = node_ptr as *mut bindings_raw::CoalesceExpr; + // Some(protobuf::node::Node::CoalesceExpr(Box::new(convert_coalesce_expr(&*ce)))) + // } + // bindings_raw::NodeTag_T_CommonTableExpr => { + // let cte = node_ptr as *mut bindings_raw::CommonTableExpr; + // Some(protobuf::node::Node::CommonTableExpr(Box::new(convert_common_table_expr(&*cte)))) + // } + // bindings_raw::NodeTag_T_ColumnDef => { + // let cd = node_ptr as *mut bindings_raw::ColumnDef; + // Some(protobuf::node::Node::ColumnDef(Box::new(convert_column_def(&*cd)))) + // } + // bindings_raw::NodeTag_T_Constraint => { + // let c = node_ptr as *mut bindings_raw::Constraint; + // Some(protobuf::node::Node::Constraint(Box::new(convert_constraint(&*c)))) + // } + // bindings_raw::NodeTag_T_DropStmt => { + // let ds = node_ptr as *mut bindings_raw::DropStmt; + // Some(protobuf::node::Node::DropStmt(convert_drop_stmt(&*ds))) + // } + // bindings_raw::NodeTag_T_IndexStmt => { + // let is = node_ptr as *mut bindings_raw::IndexStmt; + // Some(protobuf::node::Node::IndexStmt(Box::new(convert_index_stmt(&*is)))) + // } + // bindings_raw::NodeTag_T_IndexElem => { + // let ie = node_ptr as *mut bindings_raw::IndexElem; + // Some(protobuf::node::Node::IndexElem(Box::new(convert_index_elem(&*ie)))) + // } + // bindings_raw::NodeTag_T_DefElem => { + // let de = node_ptr as *mut bindings_raw::DefElem; + // Some(protobuf::node::Node::DefElem(Box::new(convert_def_elem(&*de)))) + // } + // bindings_raw::NodeTag_T_WindowDef => { + // let wd = node_ptr as *mut bindings_raw::WindowDef; + // Some(protobuf::node::Node::WindowDef(Box::new(convert_window_def(&*wd)))) + // } + // // Types that don't need Box + // bindings_raw::NodeTag_T_RangeVar => { + // let rv = node_ptr as *mut bindings_raw::RangeVar; + // Some(protobuf::node::Node::RangeVar(convert_range_var(&*rv))) + // } + // bindings_raw::NodeTag_T_ColumnRef => { + // let cr = node_ptr as *mut bindings_raw::ColumnRef; + // Some(protobuf::node::Node::ColumnRef(convert_column_ref(&*cr))) + // } + // bindings_raw::NodeTag_T_A_Star => Some(protobuf::node::Node::AStar(protobuf::AStar {})), + // bindings_raw::NodeTag_T_TypeName => { + // let tn = node_ptr as *mut bindings_raw::TypeName; + // Some(protobuf::node::Node::TypeName(convert_type_name(&*tn))) + // } + // bindings_raw::NodeTag_T_Alias => { + // let alias = node_ptr as *mut bindings_raw::Alias; + // Some(protobuf::node::Node::Alias(convert_alias(&*alias))) + // } + // bindings_raw::NodeTag_T_String => { + // let s = node_ptr as *mut bindings_raw::String; + // Some(protobuf::node::Node::String(convert_string(&*s))) + // } + // bindings_raw::NodeTag_T_Integer => { + // let i = node_ptr as *mut bindings_raw::Integer; + // Some(protobuf::node::Node::Integer(protobuf::Integer { ival: (*i).ival })) + // } + // bindings_raw::NodeTag_T_Float => { + // let f = node_ptr as *mut bindings_raw::Float; + // let fval = if (*f).fval.is_null() { String::new() } else { CStr::from_ptr((*f).fval).to_string_lossy().to_string() }; + // Some(protobuf::node::Node::Float(protobuf::Float { fval })) + // } + // bindings_raw::NodeTag_T_Boolean => { + // let b = node_ptr as *mut bindings_raw::Boolean; + // Some(protobuf::node::Node::Boolean(protobuf::Boolean { boolval: (*b).boolval })) + // } + // bindings_raw::NodeTag_T_ParamRef => { + // let pr = node_ptr as *mut bindings_raw::ParamRef; + // Some(protobuf::node::Node::ParamRef(protobuf::ParamRef { number: (*pr).number, location: (*pr).location })) + // } + // bindings_raw::NodeTag_T_WithClause => { + // let wc = node_ptr as *mut bindings_raw::WithClause; + // Some(protobuf::node::Node::WithClause(convert_with_clause(&*wc))) + // } + // bindings_raw::NodeTag_T_CreateStmt => { + // let cs = node_ptr as *mut bindings_raw::CreateStmt; + // Some(protobuf::node::Node::CreateStmt(convert_create_stmt(&*cs))) + // } + // bindings_raw::NodeTag_T_List => { + // let list = node_ptr as *mut bindings_raw::List; + // Some(protobuf::node::Node::List(convert_list(&*list))) + // } + // bindings_raw::NodeTag_T_LockingClause => { + // let lc = node_ptr as *mut bindings_raw::LockingClause; + // Some(protobuf::node::Node::LockingClause(convert_locking_clause(&*lc))) + // } + // bindings_raw::NodeTag_T_MinMaxExpr => { + // let mme = node_ptr as *mut bindings_raw::MinMaxExpr; + // Some(protobuf::node::Node::MinMaxExpr(Box::new(convert_min_max_expr(&*mme)))) + // } + // bindings_raw::NodeTag_T_GroupingSet => { + // let gs = node_ptr as *mut bindings_raw::GroupingSet; + // Some(protobuf::node::Node::GroupingSet(convert_grouping_set(&*gs))) + // } + // bindings_raw::NodeTag_T_RangeSubselect => { + // let rs = node_ptr as *mut bindings_raw::RangeSubselect; + // Some(protobuf::node::Node::RangeSubselect(Box::new(convert_range_subselect(&*rs)))) + // } + // bindings_raw::NodeTag_T_A_ArrayExpr => { + // let ae = node_ptr as *mut bindings_raw::A_ArrayExpr; + // Some(protobuf::node::Node::AArrayExpr(convert_a_array_expr(&*ae))) + // } + // bindings_raw::NodeTag_T_A_Indirection => { + // let ai = node_ptr as *mut bindings_raw::A_Indirection; + // Some(protobuf::node::Node::AIndirection(Box::new(convert_a_indirection(&*ai)))) + // } + // bindings_raw::NodeTag_T_A_Indices => { + // let ai = node_ptr as *mut bindings_raw::A_Indices; + // Some(protobuf::node::Node::AIndices(Box::new(convert_a_indices(&*ai)))) + // } + // bindings_raw::NodeTag_T_AlterTableStmt => { + // let ats = node_ptr as *mut bindings_raw::AlterTableStmt; + // Some(protobuf::node::Node::AlterTableStmt(convert_alter_table_stmt(&*ats))) + // } + // bindings_raw::NodeTag_T_AlterTableCmd => { + // let atc = node_ptr as *mut bindings_raw::AlterTableCmd; + // Some(protobuf::node::Node::AlterTableCmd(Box::new(convert_alter_table_cmd(&*atc)))) + // } + // bindings_raw::NodeTag_T_CopyStmt => { + // let cs = node_ptr as *mut bindings_raw::CopyStmt; + // Some(protobuf::node::Node::CopyStmt(Box::new(convert_copy_stmt(&*cs)))) + // } + // bindings_raw::NodeTag_T_TruncateStmt => { + // let ts = node_ptr as *mut bindings_raw::TruncateStmt; + // Some(protobuf::node::Node::TruncateStmt(convert_truncate_stmt(&*ts))) + // } + // bindings_raw::NodeTag_T_ViewStmt => { + // let vs = node_ptr as *mut bindings_raw::ViewStmt; + // Some(protobuf::node::Node::ViewStmt(Box::new(convert_view_stmt(&*vs)))) + // } + // bindings_raw::NodeTag_T_ExplainStmt => { + // let es = node_ptr as *mut bindings_raw::ExplainStmt; + // Some(protobuf::node::Node::ExplainStmt(Box::new(convert_explain_stmt(&*es)))) + // } + // bindings_raw::NodeTag_T_CreateTableAsStmt => { + // let ctas = node_ptr as *mut bindings_raw::CreateTableAsStmt; + // Some(protobuf::node::Node::CreateTableAsStmt(Box::new(convert_create_table_as_stmt(&*ctas)))) + // } + // bindings_raw::NodeTag_T_PrepareStmt => { + // let ps = node_ptr as *mut bindings_raw::PrepareStmt; + // Some(protobuf::node::Node::PrepareStmt(Box::new(convert_prepare_stmt(&*ps)))) + // } + // bindings_raw::NodeTag_T_ExecuteStmt => { + // let es = node_ptr as *mut bindings_raw::ExecuteStmt; + // Some(protobuf::node::Node::ExecuteStmt(convert_execute_stmt(&*es))) + // } + // bindings_raw::NodeTag_T_DeallocateStmt => { + // let ds = node_ptr as *mut bindings_raw::DeallocateStmt; + // Some(protobuf::node::Node::DeallocateStmt(convert_deallocate_stmt(&*ds))) + // } + // bindings_raw::NodeTag_T_SetToDefault => { + // let std = node_ptr as *mut bindings_raw::SetToDefault; + // Some(protobuf::node::Node::SetToDefault(Box::new(convert_set_to_default(&*std)))) + // } + // bindings_raw::NodeTag_T_MultiAssignRef => { + // let mar = node_ptr as *mut bindings_raw::MultiAssignRef; + // Some(protobuf::node::Node::MultiAssignRef(Box::new(convert_multi_assign_ref(&*mar)))) + // } + // bindings_raw::NodeTag_T_RowExpr => { + // let re = node_ptr as *mut bindings_raw::RowExpr; + // Some(protobuf::node::Node::RowExpr(Box::new(convert_row_expr(&*re)))) + // } + // bindings_raw::NodeTag_T_PartitionElem => { + // let pe = node_ptr as *mut bindings_raw::PartitionElem; + // Some(protobuf::node::Node::PartitionElem(Box::new(convert_partition_elem(&*pe)))) + // } + // bindings_raw::NodeTag_T_PartitionRangeDatum => { + // let prd = node_ptr as *mut bindings_raw::PartitionRangeDatum; + // Some(protobuf::node::Node::PartitionRangeDatum(Box::new(convert_partition_range_datum(&*prd)))) + // } + // bindings_raw::NodeTag_T_TransactionStmt => { + // let ts = node_ptr as *mut bindings_raw::TransactionStmt; + // Some(protobuf::node::Node::TransactionStmt(convert_transaction_stmt(&*ts))) + // } + // bindings_raw::NodeTag_T_VacuumStmt => { + // let vs = node_ptr as *mut bindings_raw::VacuumStmt; + // Some(protobuf::node::Node::VacuumStmt(convert_vacuum_stmt(&*vs))) + // } + // bindings_raw::NodeTag_T_VacuumRelation => { + // let vr = node_ptr as *mut bindings_raw::VacuumRelation; + // Some(protobuf::node::Node::VacuumRelation(convert_vacuum_relation(&*vr))) + // } + // bindings_raw::NodeTag_T_VariableSetStmt => { + // let vss = node_ptr as *mut bindings_raw::VariableSetStmt; + // Some(protobuf::node::Node::VariableSetStmt(convert_variable_set_stmt(&*vss))) + // } + // bindings_raw::NodeTag_T_VariableShowStmt => { + // let vss = node_ptr as *mut bindings_raw::VariableShowStmt; + // Some(protobuf::node::Node::VariableShowStmt(convert_variable_show_stmt(&*vss))) + // } + // bindings_raw::NodeTag_T_CreateSeqStmt => { + // let css = node_ptr as *mut bindings_raw::CreateSeqStmt; + // Some(protobuf::node::Node::CreateSeqStmt(convert_create_seq_stmt(&*css))) + // } + // bindings_raw::NodeTag_T_DoStmt => { + // let ds = node_ptr as *mut bindings_raw::DoStmt; + // Some(protobuf::node::Node::DoStmt(convert_do_stmt(&*ds))) + // } + // bindings_raw::NodeTag_T_LockStmt => { + // let ls = node_ptr as *mut bindings_raw::LockStmt; + // Some(protobuf::node::Node::LockStmt(convert_lock_stmt(&*ls))) + // } + // bindings_raw::NodeTag_T_CreateSchemaStmt => { + // let css = node_ptr as *mut bindings_raw::CreateSchemaStmt; + // Some(protobuf::node::Node::CreateSchemaStmt(convert_create_schema_stmt(&*css))) + // } + // bindings_raw::NodeTag_T_RenameStmt => { + // let rs = node_ptr as *mut bindings_raw::RenameStmt; + // Some(protobuf::node::Node::RenameStmt(Box::new(convert_rename_stmt(&*rs)))) + // } + // bindings_raw::NodeTag_T_CreateFunctionStmt => { + // let cfs = node_ptr as *mut bindings_raw::CreateFunctionStmt; + // Some(protobuf::node::Node::CreateFunctionStmt(Box::new(convert_create_function_stmt(&*cfs)))) + // } + // bindings_raw::NodeTag_T_AlterOwnerStmt => { + // let aos = node_ptr as *mut bindings_raw::AlterOwnerStmt; + // Some(protobuf::node::Node::AlterOwnerStmt(Box::new(convert_alter_owner_stmt(&*aos)))) + // } + // bindings_raw::NodeTag_T_AlterSeqStmt => { + // let ass = node_ptr as *mut bindings_raw::AlterSeqStmt; + // Some(protobuf::node::Node::AlterSeqStmt(convert_alter_seq_stmt(&*ass))) + // } + // bindings_raw::NodeTag_T_CreateEnumStmt => { + // let ces = node_ptr as *mut bindings_raw::CreateEnumStmt; + // Some(protobuf::node::Node::CreateEnumStmt(convert_create_enum_stmt(&*ces))) + // } + // bindings_raw::NodeTag_T_ObjectWithArgs => { + // let owa = node_ptr as *mut bindings_raw::ObjectWithArgs; + // Some(protobuf::node::Node::ObjectWithArgs(convert_object_with_args(&*owa))) + // } + // bindings_raw::NodeTag_T_FunctionParameter => { + // let fp = node_ptr as *mut bindings_raw::FunctionParameter; + // Some(protobuf::node::Node::FunctionParameter(Box::new(convert_function_parameter(&*fp)))) + // } + // bindings_raw::NodeTag_T_NotifyStmt => { + // let ns = node_ptr as *mut bindings_raw::NotifyStmt; + // Some(protobuf::node::Node::NotifyStmt(convert_notify_stmt(&*ns))) + // } + // bindings_raw::NodeTag_T_ListenStmt => { + // let ls = node_ptr as *mut bindings_raw::ListenStmt; + // Some(protobuf::node::Node::ListenStmt(convert_listen_stmt(&*ls))) + // } + // bindings_raw::NodeTag_T_UnlistenStmt => { + // let us = node_ptr as *mut bindings_raw::UnlistenStmt; + // Some(protobuf::node::Node::UnlistenStmt(convert_unlisten_stmt(&*us))) + // } + // bindings_raw::NodeTag_T_DiscardStmt => { + // let ds = node_ptr as *mut bindings_raw::DiscardStmt; + // Some(protobuf::node::Node::DiscardStmt(convert_discard_stmt(&*ds))) + // } + // bindings_raw::NodeTag_T_CollateClause => { + // let cc = node_ptr as *mut bindings_raw::CollateClause; + // Some(protobuf::node::Node::CollateClause(Box::new(convert_collate_clause(&*cc)))) + // } + // bindings_raw::NodeTag_T_CoerceToDomain => { + // let ctd = node_ptr as *mut bindings_raw::CoerceToDomain; + // Some(protobuf::node::Node::CoerceToDomain(Box::new(convert_coerce_to_domain(&*ctd)))) + // } + // bindings_raw::NodeTag_T_CompositeTypeStmt => { + // let cts = node_ptr as *mut bindings_raw::CompositeTypeStmt; + // Some(protobuf::node::Node::CompositeTypeStmt(convert_composite_type_stmt(&*cts))) + // } + // bindings_raw::NodeTag_T_CreateDomainStmt => { + // let cds = node_ptr as *mut bindings_raw::CreateDomainStmt; + // Some(protobuf::node::Node::CreateDomainStmt(Box::new(convert_create_domain_stmt(&*cds)))) + // } + // bindings_raw::NodeTag_T_CreateExtensionStmt => { + // let ces = node_ptr as *mut bindings_raw::CreateExtensionStmt; + // Some(protobuf::node::Node::CreateExtensionStmt(convert_create_extension_stmt(&*ces))) + // } + // bindings_raw::NodeTag_T_CreatePublicationStmt => { + // let cps = node_ptr as *mut bindings_raw::CreatePublicationStmt; + // Some(protobuf::node::Node::CreatePublicationStmt(convert_create_publication_stmt(&*cps))) + // } + // bindings_raw::NodeTag_T_AlterPublicationStmt => { + // let aps = node_ptr as *mut bindings_raw::AlterPublicationStmt; + // Some(protobuf::node::Node::AlterPublicationStmt(convert_alter_publication_stmt(&*aps))) + // } + // bindings_raw::NodeTag_T_CreateSubscriptionStmt => { + // let css = node_ptr as *mut bindings_raw::CreateSubscriptionStmt; + // Some(protobuf::node::Node::CreateSubscriptionStmt(convert_create_subscription_stmt(&*css))) + // } + // bindings_raw::NodeTag_T_AlterSubscriptionStmt => { + // let ass = node_ptr as *mut bindings_raw::AlterSubscriptionStmt; + // Some(protobuf::node::Node::AlterSubscriptionStmt(convert_alter_subscription_stmt(&*ass))) + // } + // bindings_raw::NodeTag_T_CreateTrigStmt => { + // let cts = node_ptr as *mut bindings_raw::CreateTrigStmt; + // Some(protobuf::node::Node::CreateTrigStmt(Box::new(convert_create_trig_stmt(&*cts)))) + // } + // bindings_raw::NodeTag_T_PublicationObjSpec => { + // let pos = node_ptr as *mut bindings_raw::PublicationObjSpec; + // Some(protobuf::node::Node::PublicationObjSpec(Box::new(convert_publication_obj_spec(&*pos)))) + // } + // bindings_raw::NodeTag_T_PublicationTable => { + // let pt = node_ptr as *mut bindings_raw::PublicationTable; + // Some(protobuf::node::Node::PublicationTable(Box::new(convert_publication_table(&*pt)))) + // } + // bindings_raw::NodeTag_T_CheckPointStmt => Some(protobuf::node::Node::CheckPointStmt(protobuf::CheckPointStmt {})), + // bindings_raw::NodeTag_T_CallStmt => { + // let cs = node_ptr as *mut bindings_raw::CallStmt; + // Some(protobuf::node::Node::CallStmt(Box::new(convert_call_stmt(&*cs)))) + // } + // bindings_raw::NodeTag_T_RuleStmt => { + // let rs = node_ptr as *mut bindings_raw::RuleStmt; + // Some(protobuf::node::Node::RuleStmt(Box::new(convert_rule_stmt(&*rs)))) + // } + // bindings_raw::NodeTag_T_GrantStmt => { + // let gs = node_ptr as *mut bindings_raw::GrantStmt; + // Some(protobuf::node::Node::GrantStmt(convert_grant_stmt(&*gs))) + // } + // bindings_raw::NodeTag_T_GrantRoleStmt => { + // let grs = node_ptr as *mut bindings_raw::GrantRoleStmt; + // Some(protobuf::node::Node::GrantRoleStmt(convert_grant_role_stmt(&*grs))) + // } + // bindings_raw::NodeTag_T_RefreshMatViewStmt => { + // let rmvs = node_ptr as *mut bindings_raw::RefreshMatViewStmt; + // Some(protobuf::node::Node::RefreshMatViewStmt(convert_refresh_mat_view_stmt(&*rmvs))) + // } + // bindings_raw::NodeTag_T_MergeStmt => { + // let ms = node_ptr as *mut bindings_raw::MergeStmt; + // Some(protobuf::node::Node::MergeStmt(Box::new(convert_merge_stmt(&*ms)))) + // } + // bindings_raw::NodeTag_T_MergeAction => { + // let ma = node_ptr as *mut bindings_raw::MergeAction; + // Some(protobuf::node::Node::MergeAction(Box::new(convert_merge_action(&*ma)))) + // } + // bindings_raw::NodeTag_T_RangeFunction => { + // let rf = node_ptr as *mut bindings_raw::RangeFunction; + // Some(protobuf::node::Node::RangeFunction(convert_range_function(&*rf))) + // } + // bindings_raw::NodeTag_T_MergeWhenClause => { + // let mwc = node_ptr as *mut bindings_raw::MergeWhenClause; + // Some(protobuf::node::Node::MergeWhenClause(Box::new(convert_merge_when_clause(&*mwc)))) + // } + // bindings_raw::NodeTag_T_AccessPriv => { + // let ap = node_ptr as *mut bindings_raw::AccessPriv; + // Some(protobuf::node::Node::AccessPriv(convert_access_priv(&*ap))) + // } + // bindings_raw::NodeTag_T_RoleSpec => { + // let rs = node_ptr as *mut bindings_raw::RoleSpec; + // Some(protobuf::node::Node::RoleSpec(convert_role_spec(&*rs))) + // } + // bindings_raw::NodeTag_T_BitString => { + // let bs = node_ptr as *mut bindings_raw::BitString; + // Some(protobuf::node::Node::BitString(convert_bit_string(&*bs))) + // } + // bindings_raw::NodeTag_T_BooleanTest => { + // let bt = node_ptr as *mut bindings_raw::BooleanTest; + // Some(protobuf::node::Node::BooleanTest(Box::new(convert_boolean_test(&*bt)))) + // } + // bindings_raw::NodeTag_T_CreateRangeStmt => { + // let crs = node_ptr as *mut bindings_raw::CreateRangeStmt; + // Some(protobuf::node::Node::CreateRangeStmt(convert_create_range_stmt(&*crs))) + // } + // bindings_raw::NodeTag_T_AlterEnumStmt => { + // let aes = node_ptr as *mut bindings_raw::AlterEnumStmt; + // Some(protobuf::node::Node::AlterEnumStmt(convert_alter_enum_stmt(&*aes))) + // } + // bindings_raw::NodeTag_T_ClosePortalStmt => { + // let cps = node_ptr as *mut bindings_raw::ClosePortalStmt; + // Some(protobuf::node::Node::ClosePortalStmt(convert_close_portal_stmt(&*cps))) + // } + // bindings_raw::NodeTag_T_FetchStmt => { + // let fs = node_ptr as *mut bindings_raw::FetchStmt; + // Some(protobuf::node::Node::FetchStmt(convert_fetch_stmt(&*fs))) + // } + // bindings_raw::NodeTag_T_DeclareCursorStmt => { + // let dcs = node_ptr as *mut bindings_raw::DeclareCursorStmt; + // Some(protobuf::node::Node::DeclareCursorStmt(Box::new(convert_declare_cursor_stmt(&*dcs)))) + // } + // bindings_raw::NodeTag_T_DefineStmt => { + // let ds = node_ptr as *mut bindings_raw::DefineStmt; + // Some(protobuf::node::Node::DefineStmt(convert_define_stmt(&*ds))) + // } + // bindings_raw::NodeTag_T_CommentStmt => { + // let cs = node_ptr as *mut bindings_raw::CommentStmt; + // Some(protobuf::node::Node::CommentStmt(Box::new(convert_comment_stmt(&*cs)))) + // } + // bindings_raw::NodeTag_T_SecLabelStmt => { + // let sls = node_ptr as *mut bindings_raw::SecLabelStmt; + // Some(protobuf::node::Node::SecLabelStmt(Box::new(convert_sec_label_stmt(&*sls)))) + // } + // bindings_raw::NodeTag_T_CreateRoleStmt => { + // let crs = node_ptr as *mut bindings_raw::CreateRoleStmt; + // Some(protobuf::node::Node::CreateRoleStmt(convert_create_role_stmt(&*crs))) + // } + // bindings_raw::NodeTag_T_AlterRoleStmt => { + // let ars = node_ptr as *mut bindings_raw::AlterRoleStmt; + // Some(protobuf::node::Node::AlterRoleStmt(convert_alter_role_stmt(&*ars))) + // } + // bindings_raw::NodeTag_T_AlterRoleSetStmt => { + // let arss = node_ptr as *mut bindings_raw::AlterRoleSetStmt; + // Some(protobuf::node::Node::AlterRoleSetStmt(convert_alter_role_set_stmt(&*arss))) + // } + // bindings_raw::NodeTag_T_DropRoleStmt => { + // let drs = node_ptr as *mut bindings_raw::DropRoleStmt; + // Some(protobuf::node::Node::DropRoleStmt(convert_drop_role_stmt(&*drs))) + // } + // bindings_raw::NodeTag_T_CreatePolicyStmt => { + // let cps = node_ptr as *mut bindings_raw::CreatePolicyStmt; + // Some(protobuf::node::Node::CreatePolicyStmt(Box::new(convert_create_policy_stmt(&*cps)))) + // } + // bindings_raw::NodeTag_T_AlterPolicyStmt => { + // let aps = node_ptr as *mut bindings_raw::AlterPolicyStmt; + // Some(protobuf::node::Node::AlterPolicyStmt(Box::new(convert_alter_policy_stmt(&*aps)))) + // } + // bindings_raw::NodeTag_T_CreateEventTrigStmt => { + // let cets = node_ptr as *mut bindings_raw::CreateEventTrigStmt; + // Some(protobuf::node::Node::CreateEventTrigStmt(convert_create_event_trig_stmt(&*cets))) + // } + // bindings_raw::NodeTag_T_AlterEventTrigStmt => { + // let aets = node_ptr as *mut bindings_raw::AlterEventTrigStmt; + // Some(protobuf::node::Node::AlterEventTrigStmt(convert_alter_event_trig_stmt(&*aets))) + // } + // bindings_raw::NodeTag_T_CreatePLangStmt => { + // let cpls = node_ptr as *mut bindings_raw::CreatePLangStmt; + // Some(protobuf::node::Node::CreatePlangStmt(convert_create_plang_stmt(&*cpls))) + // } + // bindings_raw::NodeTag_T_CreateAmStmt => { + // let cas = node_ptr as *mut bindings_raw::CreateAmStmt; + // Some(protobuf::node::Node::CreateAmStmt(convert_create_am_stmt(&*cas))) + // } + // bindings_raw::NodeTag_T_CreateOpClassStmt => { + // let cocs = node_ptr as *mut bindings_raw::CreateOpClassStmt; + // Some(protobuf::node::Node::CreateOpClassStmt(convert_create_op_class_stmt(&*cocs))) + // } + // bindings_raw::NodeTag_T_CreateOpClassItem => { + // let coci = node_ptr as *mut bindings_raw::CreateOpClassItem; + // Some(protobuf::node::Node::CreateOpClassItem(convert_create_op_class_item(&*coci))) + // } + // bindings_raw::NodeTag_T_CreateOpFamilyStmt => { + // let cofs = node_ptr as *mut bindings_raw::CreateOpFamilyStmt; + // Some(protobuf::node::Node::CreateOpFamilyStmt(convert_create_op_family_stmt(&*cofs))) + // } + // bindings_raw::NodeTag_T_AlterOpFamilyStmt => { + // let aofs = node_ptr as *mut bindings_raw::AlterOpFamilyStmt; + // Some(protobuf::node::Node::AlterOpFamilyStmt(convert_alter_op_family_stmt(&*aofs))) + // } + // bindings_raw::NodeTag_T_CreateFdwStmt => { + // let cfds = node_ptr as *mut bindings_raw::CreateFdwStmt; + // Some(protobuf::node::Node::CreateFdwStmt(convert_create_fdw_stmt(&*cfds))) + // } + // bindings_raw::NodeTag_T_AlterFdwStmt => { + // let afds = node_ptr as *mut bindings_raw::AlterFdwStmt; + // Some(protobuf::node::Node::AlterFdwStmt(convert_alter_fdw_stmt(&*afds))) + // } + // bindings_raw::NodeTag_T_CreateForeignServerStmt => { + // let cfss = node_ptr as *mut bindings_raw::CreateForeignServerStmt; + // Some(protobuf::node::Node::CreateForeignServerStmt(convert_create_foreign_server_stmt(&*cfss))) + // } + // bindings_raw::NodeTag_T_AlterForeignServerStmt => { + // let afss = node_ptr as *mut bindings_raw::AlterForeignServerStmt; + // Some(protobuf::node::Node::AlterForeignServerStmt(convert_alter_foreign_server_stmt(&*afss))) + // } + // bindings_raw::NodeTag_T_CreateForeignTableStmt => { + // let cfts = node_ptr as *mut bindings_raw::CreateForeignTableStmt; + // Some(protobuf::node::Node::CreateForeignTableStmt(convert_create_foreign_table_stmt(&*cfts))) + // } + // bindings_raw::NodeTag_T_CreateUserMappingStmt => { + // let cums = node_ptr as *mut bindings_raw::CreateUserMappingStmt; + // Some(protobuf::node::Node::CreateUserMappingStmt(convert_create_user_mapping_stmt(&*cums))) + // } + // bindings_raw::NodeTag_T_AlterUserMappingStmt => { + // let aums = node_ptr as *mut bindings_raw::AlterUserMappingStmt; + // Some(protobuf::node::Node::AlterUserMappingStmt(convert_alter_user_mapping_stmt(&*aums))) + // } + // bindings_raw::NodeTag_T_DropUserMappingStmt => { + // let dums = node_ptr as *mut bindings_raw::DropUserMappingStmt; + // Some(protobuf::node::Node::DropUserMappingStmt(convert_drop_user_mapping_stmt(&*dums))) + // } + // bindings_raw::NodeTag_T_ImportForeignSchemaStmt => { + // let ifss = node_ptr as *mut bindings_raw::ImportForeignSchemaStmt; + // Some(protobuf::node::Node::ImportForeignSchemaStmt(convert_import_foreign_schema_stmt(&*ifss))) + // } + // bindings_raw::NodeTag_T_CreateTableSpaceStmt => { + // let ctss = node_ptr as *mut bindings_raw::CreateTableSpaceStmt; + // Some(protobuf::node::Node::CreateTableSpaceStmt(convert_create_table_space_stmt(&*ctss))) + // } + // bindings_raw::NodeTag_T_DropTableSpaceStmt => { + // let dtss = node_ptr as *mut bindings_raw::DropTableSpaceStmt; + // Some(protobuf::node::Node::DropTableSpaceStmt(convert_drop_table_space_stmt(&*dtss))) + // } + // bindings_raw::NodeTag_T_AlterTableSpaceOptionsStmt => { + // let atsos = node_ptr as *mut bindings_raw::AlterTableSpaceOptionsStmt; + // Some(protobuf::node::Node::AlterTableSpaceOptionsStmt(convert_alter_table_space_options_stmt(&*atsos))) + // } + // bindings_raw::NodeTag_T_AlterTableMoveAllStmt => { + // let atmas = node_ptr as *mut bindings_raw::AlterTableMoveAllStmt; + // Some(protobuf::node::Node::AlterTableMoveAllStmt(convert_alter_table_move_all_stmt(&*atmas))) + // } + // bindings_raw::NodeTag_T_AlterExtensionStmt => { + // let aes = node_ptr as *mut bindings_raw::AlterExtensionStmt; + // Some(protobuf::node::Node::AlterExtensionStmt(convert_alter_extension_stmt(&*aes))) + // } + // bindings_raw::NodeTag_T_AlterExtensionContentsStmt => { + // let aecs = node_ptr as *mut bindings_raw::AlterExtensionContentsStmt; + // Some(protobuf::node::Node::AlterExtensionContentsStmt(Box::new(convert_alter_extension_contents_stmt(&*aecs)))) + // } + // bindings_raw::NodeTag_T_AlterDomainStmt => { + // let ads = node_ptr as *mut bindings_raw::AlterDomainStmt; + // Some(protobuf::node::Node::AlterDomainStmt(Box::new(convert_alter_domain_stmt(&*ads)))) + // } + // bindings_raw::NodeTag_T_AlterFunctionStmt => { + // let afs = node_ptr as *mut bindings_raw::AlterFunctionStmt; + // Some(protobuf::node::Node::AlterFunctionStmt(convert_alter_function_stmt(&*afs))) + // } + // bindings_raw::NodeTag_T_AlterOperatorStmt => { + // let aos = node_ptr as *mut bindings_raw::AlterOperatorStmt; + // Some(protobuf::node::Node::AlterOperatorStmt(convert_alter_operator_stmt(&*aos))) + // } + // bindings_raw::NodeTag_T_AlterTypeStmt => { + // let ats = node_ptr as *mut bindings_raw::AlterTypeStmt; + // Some(protobuf::node::Node::AlterTypeStmt(convert_alter_type_stmt(&*ats))) + // } + // bindings_raw::NodeTag_T_AlterObjectSchemaStmt => { + // let aoss = node_ptr as *mut bindings_raw::AlterObjectSchemaStmt; + // Some(protobuf::node::Node::AlterObjectSchemaStmt(Box::new(convert_alter_object_schema_stmt(&*aoss)))) + // } + // bindings_raw::NodeTag_T_AlterObjectDependsStmt => { + // let aods = node_ptr as *mut bindings_raw::AlterObjectDependsStmt; + // Some(protobuf::node::Node::AlterObjectDependsStmt(Box::new(convert_alter_object_depends_stmt(&*aods)))) + // } + // bindings_raw::NodeTag_T_AlterCollationStmt => { + // let acs = node_ptr as *mut bindings_raw::AlterCollationStmt; + // Some(protobuf::node::Node::AlterCollationStmt(convert_alter_collation_stmt(&*acs))) + // } + // bindings_raw::NodeTag_T_AlterDefaultPrivilegesStmt => { + // let adps = node_ptr as *mut bindings_raw::AlterDefaultPrivilegesStmt; + // Some(protobuf::node::Node::AlterDefaultPrivilegesStmt(convert_alter_default_privileges_stmt(&*adps))) + // } + // bindings_raw::NodeTag_T_CreateCastStmt => { + // let ccs = node_ptr as *mut bindings_raw::CreateCastStmt; + // Some(protobuf::node::Node::CreateCastStmt(convert_create_cast_stmt(&*ccs))) + // } + // bindings_raw::NodeTag_T_CreateTransformStmt => { + // let cts = node_ptr as *mut bindings_raw::CreateTransformStmt; + // Some(protobuf::node::Node::CreateTransformStmt(convert_create_transform_stmt(&*cts))) + // } + // bindings_raw::NodeTag_T_CreateConversionStmt => { + // let ccs = node_ptr as *mut bindings_raw::CreateConversionStmt; + // Some(protobuf::node::Node::CreateConversionStmt(convert_create_conversion_stmt(&*ccs))) + // } + // bindings_raw::NodeTag_T_AlterTSDictionaryStmt => { + // let atds = node_ptr as *mut bindings_raw::AlterTSDictionaryStmt; + // Some(protobuf::node::Node::AlterTsdictionaryStmt(convert_alter_ts_dictionary_stmt(&*atds))) + // } + // bindings_raw::NodeTag_T_AlterTSConfigurationStmt => { + // let atcs = node_ptr as *mut bindings_raw::AlterTSConfigurationStmt; + // Some(protobuf::node::Node::AlterTsconfigurationStmt(convert_alter_ts_configuration_stmt(&*atcs))) + // } + // bindings_raw::NodeTag_T_CreatedbStmt => { + // let cds = node_ptr as *mut bindings_raw::CreatedbStmt; + // Some(protobuf::node::Node::CreatedbStmt(convert_createdb_stmt(&*cds))) + // } + // bindings_raw::NodeTag_T_DropdbStmt => { + // let dds = node_ptr as *mut bindings_raw::DropdbStmt; + // Some(protobuf::node::Node::DropdbStmt(convert_dropdb_stmt(&*dds))) + // } + // bindings_raw::NodeTag_T_AlterDatabaseStmt => { + // let ads = node_ptr as *mut bindings_raw::AlterDatabaseStmt; + // Some(protobuf::node::Node::AlterDatabaseStmt(convert_alter_database_stmt(&*ads))) + // } + // bindings_raw::NodeTag_T_AlterDatabaseSetStmt => { + // let adss = node_ptr as *mut bindings_raw::AlterDatabaseSetStmt; + // Some(protobuf::node::Node::AlterDatabaseSetStmt(convert_alter_database_set_stmt(&*adss))) + // } + // bindings_raw::NodeTag_T_AlterDatabaseRefreshCollStmt => { + // let adrcs = node_ptr as *mut bindings_raw::AlterDatabaseRefreshCollStmt; + // Some(protobuf::node::Node::AlterDatabaseRefreshCollStmt(convert_alter_database_refresh_coll_stmt(&*adrcs))) + // } + // bindings_raw::NodeTag_T_AlterSystemStmt => { + // let ass = node_ptr as *mut bindings_raw::AlterSystemStmt; + // Some(protobuf::node::Node::AlterSystemStmt(convert_alter_system_stmt(&*ass))) + // } + // bindings_raw::NodeTag_T_ClusterStmt => { + // let cs = node_ptr as *mut bindings_raw::ClusterStmt; + // Some(protobuf::node::Node::ClusterStmt(convert_cluster_stmt(&*cs))) + // } + // bindings_raw::NodeTag_T_ReindexStmt => { + // let rs = node_ptr as *mut bindings_raw::ReindexStmt; + // Some(protobuf::node::Node::ReindexStmt(convert_reindex_stmt(&*rs))) + // } + // bindings_raw::NodeTag_T_ConstraintsSetStmt => { + // let css = node_ptr as *mut bindings_raw::ConstraintsSetStmt; + // Some(protobuf::node::Node::ConstraintsSetStmt(convert_constraints_set_stmt(&*css))) + // } + // bindings_raw::NodeTag_T_LoadStmt => { + // let ls = node_ptr as *mut bindings_raw::LoadStmt; + // Some(protobuf::node::Node::LoadStmt(convert_load_stmt(&*ls))) + // } + // bindings_raw::NodeTag_T_DropOwnedStmt => { + // let dos = node_ptr as *mut bindings_raw::DropOwnedStmt; + // Some(protobuf::node::Node::DropOwnedStmt(convert_drop_owned_stmt(&*dos))) + // } + // bindings_raw::NodeTag_T_ReassignOwnedStmt => { + // let ros = node_ptr as *mut bindings_raw::ReassignOwnedStmt; + // Some(protobuf::node::Node::ReassignOwnedStmt(convert_reassign_owned_stmt(&*ros))) + // } + // bindings_raw::NodeTag_T_DropSubscriptionStmt => { + // let dss = node_ptr as *mut bindings_raw::DropSubscriptionStmt; + // Some(protobuf::node::Node::DropSubscriptionStmt(convert_drop_subscription_stmt(&*dss))) + // } + // bindings_raw::NodeTag_T_TableFunc => { + // let tf = node_ptr as *mut bindings_raw::TableFunc; + // Some(protobuf::node::Node::TableFunc(Box::new(convert_table_func(&*tf)))) + // } + // bindings_raw::NodeTag_T_IntoClause => { + // let ic = node_ptr as *mut bindings_raw::IntoClause; + // Some(protobuf::node::Node::IntoClause(Box::new(convert_into_clause_node(&*ic)))) + // } + // bindings_raw::NodeTag_T_TableLikeClause => { + // let tlc = node_ptr as *mut bindings_raw::TableLikeClause; + // Some(protobuf::node::Node::TableLikeClause(convert_table_like_clause(&*tlc))) + // } + // bindings_raw::NodeTag_T_RangeTableFunc => { + // let rtf = node_ptr as *mut bindings_raw::RangeTableFunc; + // Some(protobuf::node::Node::RangeTableFunc(Box::new(convert_range_table_func(&*rtf)))) + // } + // bindings_raw::NodeTag_T_RangeTableFuncCol => { + // let rtfc = node_ptr as *mut bindings_raw::RangeTableFuncCol; + // Some(protobuf::node::Node::RangeTableFuncCol(Box::new(convert_range_table_func_col(&*rtfc)))) + // } + // bindings_raw::NodeTag_T_RangeTableSample => { + // let rts = node_ptr as *mut bindings_raw::RangeTableSample; + // Some(protobuf::node::Node::RangeTableSample(Box::new(convert_range_table_sample(&*rts)))) + // } + // bindings_raw::NodeTag_T_PartitionSpec => { + // let ps = node_ptr as *mut bindings_raw::PartitionSpec; + // Some(protobuf::node::Node::PartitionSpec(convert_partition_spec(&*ps))) + // } + // bindings_raw::NodeTag_T_PartitionBoundSpec => { + // let pbs = node_ptr as *mut bindings_raw::PartitionBoundSpec; + // Some(protobuf::node::Node::PartitionBoundSpec(convert_partition_bound_spec(&*pbs))) + // } + // bindings_raw::NodeTag_T_PartitionCmd => { + // let pc = node_ptr as *mut bindings_raw::PartitionCmd; + // Some(protobuf::node::Node::PartitionCmd(convert_partition_cmd(&*pc))) + // } + // bindings_raw::NodeTag_T_SinglePartitionSpec => Some(protobuf::node::Node::SinglePartitionSpec(protobuf::SinglePartitionSpec {})), + // bindings_raw::NodeTag_T_InferClause => { + // let ic = node_ptr as *mut bindings_raw::InferClause; + // convert_infer_clause(ic).map(|c| protobuf::node::Node::InferClause(c)) + // } + // bindings_raw::NodeTag_T_OnConflictClause => { + // let occ = node_ptr as *mut bindings_raw::OnConflictClause; + // Some(protobuf::node::Node::OnConflictClause(Box::new(convert_on_conflict_clause_node(&*occ)))) + // } + // bindings_raw::NodeTag_T_TriggerTransition => { + // let tt = node_ptr as *mut bindings_raw::TriggerTransition; + // Some(protobuf::node::Node::TriggerTransition(convert_trigger_transition(&*tt))) + // } + // bindings_raw::NodeTag_T_CTESearchClause => { + // let csc = node_ptr as *mut bindings_raw::CTESearchClause; + // Some(protobuf::node::Node::CtesearchClause(convert_cte_search_clause(&*csc))) + // } + // bindings_raw::NodeTag_T_CTECycleClause => { + // let ccc = node_ptr as *mut bindings_raw::CTECycleClause; + // Some(protobuf::node::Node::CtecycleClause(Box::new(convert_cte_cycle_clause(&*ccc)))) + // } + // bindings_raw::NodeTag_T_CreateStatsStmt => { + // let css = node_ptr as *mut bindings_raw::CreateStatsStmt; + // Some(protobuf::node::Node::CreateStatsStmt(convert_create_stats_stmt(&*css))) + // } + // bindings_raw::NodeTag_T_AlterStatsStmt => { + // let ass = node_ptr as *mut bindings_raw::AlterStatsStmt; + // Some(protobuf::node::Node::AlterStatsStmt(Box::new(convert_alter_stats_stmt(&*ass)))) + // } + // bindings_raw::NodeTag_T_StatsElem => { + // let se = node_ptr as *mut bindings_raw::StatsElem; + // Some(protobuf::node::Node::StatsElem(Box::new(convert_stats_elem(&*se)))) + // } + // bindings_raw::NodeTag_T_SQLValueFunction => { + // let svf = node_ptr as *mut bindings_raw::SQLValueFunction; + // Some(protobuf::node::Node::SqlvalueFunction(Box::new(convert_sql_value_function(&*svf)))) + // } + // bindings_raw::NodeTag_T_XmlExpr => { + // let xe = node_ptr as *mut bindings_raw::XmlExpr; + // Some(protobuf::node::Node::XmlExpr(Box::new(convert_xml_expr(&*xe)))) + // } + // bindings_raw::NodeTag_T_XmlSerialize => { + // let xs = node_ptr as *mut bindings_raw::XmlSerialize; + // Some(protobuf::node::Node::XmlSerialize(Box::new(convert_xml_serialize(&*xs)))) + // } + // bindings_raw::NodeTag_T_NamedArgExpr => { + // let nae = node_ptr as *mut bindings_raw::NamedArgExpr; + // Some(protobuf::node::Node::NamedArgExpr(Box::new(convert_named_arg_expr(&*nae)))) + // } + // // JSON nodes + // bindings_raw::NodeTag_T_JsonFormat => { + // let jf = node_ptr as *mut bindings_raw::JsonFormat; + // Some(protobuf::node::Node::JsonFormat(convert_json_format(&*jf))) + // } + // bindings_raw::NodeTag_T_JsonReturning => { + // let jr = node_ptr as *mut bindings_raw::JsonReturning; + // Some(protobuf::node::Node::JsonReturning(convert_json_returning(&*jr))) + // } + // bindings_raw::NodeTag_T_JsonValueExpr => { + // let jve = node_ptr as *mut bindings_raw::JsonValueExpr; + // Some(protobuf::node::Node::JsonValueExpr(Box::new(convert_json_value_expr(&*jve)))) + // } + // bindings_raw::NodeTag_T_JsonConstructorExpr => { + // let jce = node_ptr as *mut bindings_raw::JsonConstructorExpr; + // Some(protobuf::node::Node::JsonConstructorExpr(Box::new(convert_json_constructor_expr(&*jce)))) + // } + // bindings_raw::NodeTag_T_JsonIsPredicate => { + // let jip = node_ptr as *mut bindings_raw::JsonIsPredicate; + // Some(protobuf::node::Node::JsonIsPredicate(Box::new(convert_json_is_predicate(&*jip)))) + // } + // bindings_raw::NodeTag_T_JsonBehavior => { + // let jb = node_ptr as *mut bindings_raw::JsonBehavior; + // Some(protobuf::node::Node::JsonBehavior(Box::new(convert_json_behavior(&*jb)))) + // } + // bindings_raw::NodeTag_T_JsonExpr => { + // let je = node_ptr as *mut bindings_raw::JsonExpr; + // Some(protobuf::node::Node::JsonExpr(Box::new(convert_json_expr(&*je)))) + // } + // bindings_raw::NodeTag_T_JsonTablePath => { + // let jtp = node_ptr as *mut bindings_raw::JsonTablePath; + // Some(protobuf::node::Node::JsonTablePath(convert_json_table_path(&*jtp))) + // } + // bindings_raw::NodeTag_T_JsonTablePathScan => { + // let jtps = node_ptr as *mut bindings_raw::JsonTablePathScan; + // Some(protobuf::node::Node::JsonTablePathScan(Box::new(convert_json_table_path_scan(&*jtps)))) + // } + // bindings_raw::NodeTag_T_JsonTableSiblingJoin => { + // let jtsj = node_ptr as *mut bindings_raw::JsonTableSiblingJoin; + // Some(protobuf::node::Node::JsonTableSiblingJoin(Box::new(convert_json_table_sibling_join(&*jtsj)))) + // } + // bindings_raw::NodeTag_T_JsonOutput => { + // let jo = node_ptr as *mut bindings_raw::JsonOutput; + // Some(protobuf::node::Node::JsonOutput(convert_json_output(&*jo))) + // } + // bindings_raw::NodeTag_T_JsonArgument => { + // let ja = node_ptr as *mut bindings_raw::JsonArgument; + // Some(protobuf::node::Node::JsonArgument(Box::new(convert_json_argument(&*ja)))) + // } + // bindings_raw::NodeTag_T_JsonFuncExpr => { + // let jfe = node_ptr as *mut bindings_raw::JsonFuncExpr; + // Some(protobuf::node::Node::JsonFuncExpr(Box::new(convert_json_func_expr(&*jfe)))) + // } + // bindings_raw::NodeTag_T_JsonTablePathSpec => { + // let jtps = node_ptr as *mut bindings_raw::JsonTablePathSpec; + // Some(protobuf::node::Node::JsonTablePathSpec(Box::new(convert_json_table_path_spec(&*jtps)))) + // } + // bindings_raw::NodeTag_T_JsonTable => { + // let jt = node_ptr as *mut bindings_raw::JsonTable; + // Some(protobuf::node::Node::JsonTable(Box::new(convert_json_table(&*jt)))) + // } + // bindings_raw::NodeTag_T_JsonTableColumn => { + // let jtc = node_ptr as *mut bindings_raw::JsonTableColumn; + // Some(protobuf::node::Node::JsonTableColumn(Box::new(convert_json_table_column(&*jtc)))) + // } + // bindings_raw::NodeTag_T_JsonKeyValue => { + // let jkv = node_ptr as *mut bindings_raw::JsonKeyValue; + // Some(protobuf::node::Node::JsonKeyValue(Box::new(convert_json_key_value(&*jkv)))) + // } + // bindings_raw::NodeTag_T_JsonParseExpr => { + // let jpe = node_ptr as *mut bindings_raw::JsonParseExpr; + // Some(protobuf::node::Node::JsonParseExpr(Box::new(convert_json_parse_expr(&*jpe)))) + // } + // bindings_raw::NodeTag_T_JsonScalarExpr => { + // let jse = node_ptr as *mut bindings_raw::JsonScalarExpr; + // Some(protobuf::node::Node::JsonScalarExpr(Box::new(convert_json_scalar_expr(&*jse)))) + // } + // bindings_raw::NodeTag_T_JsonSerializeExpr => { + // let jse = node_ptr as *mut bindings_raw::JsonSerializeExpr; + // Some(protobuf::node::Node::JsonSerializeExpr(Box::new(convert_json_serialize_expr(&*jse)))) + // } + // bindings_raw::NodeTag_T_JsonObjectConstructor => { + // let joc = node_ptr as *mut bindings_raw::JsonObjectConstructor; + // Some(protobuf::node::Node::JsonObjectConstructor(convert_json_object_constructor(&*joc))) + // } + // bindings_raw::NodeTag_T_JsonArrayConstructor => { + // let jac = node_ptr as *mut bindings_raw::JsonArrayConstructor; + // Some(protobuf::node::Node::JsonArrayConstructor(convert_json_array_constructor(&*jac))) + // } + // bindings_raw::NodeTag_T_JsonArrayQueryConstructor => { + // let jaqc = node_ptr as *mut bindings_raw::JsonArrayQueryConstructor; + // Some(protobuf::node::Node::JsonArrayQueryConstructor(Box::new(convert_json_array_query_constructor(&*jaqc)))) + // } + // bindings_raw::NodeTag_T_JsonAggConstructor => { + // let jac = node_ptr as *mut bindings_raw::JsonAggConstructor; + // Some(protobuf::node::Node::JsonAggConstructor(Box::new(convert_json_agg_constructor(&*jac)))) + // } + // bindings_raw::NodeTag_T_JsonObjectAgg => { + // let joa = node_ptr as *mut bindings_raw::JsonObjectAgg; + // Some(protobuf::node::Node::JsonObjectAgg(Box::new(convert_json_object_agg(&*joa)))) + // } + // bindings_raw::NodeTag_T_JsonArrayAgg => { + // let jaa = node_ptr as *mut bindings_raw::JsonArrayAgg; + // Some(protobuf::node::Node::JsonArrayAgg(Box::new(convert_json_array_agg(&*jaa)))) + // } + // bindings_raw::NodeTag_T_ReplicaIdentityStmt => { + // let ris = node_ptr as *mut bindings_raw::ReplicaIdentityStmt; + // Some(protobuf::node::Node::ReplicaIdentityStmt(convert_replica_identity_stmt(&*ris))) + // } + // bindings_raw::NodeTag_T_GroupingFunc => { + // let gf = node_ptr as *mut bindings_raw::GroupingFunc; + // Some(protobuf::node::Node::GroupingFunc(Box::new(convert_grouping_func(&*gf)))) + // } + _ => { + // For unhandled node types, return None + // In the future, we could add more node types here + None + } + }; + + node.map(|n| protobuf::Node { node: Some(n) }) +} + +/// Converts a PostgreSQL List to a protobuf List of Nodes. +unsafe fn convert_list(list: &bindings_raw::List) -> protobuf::List { + let items = convert_list_to_nodes(list as *const bindings_raw::List as *mut bindings_raw::List); + protobuf::List { items } +} + +/// Converts a PostgreSQL List pointer to a Vec of protobuf Nodes. +/// Note: Preserves placeholder nodes (Node { node: None }) for cases like DISTINCT +/// where the list must retain its structure even if content is not recognized. +unsafe fn convert_list_to_nodes(list: *mut bindings_raw::List) -> Vec { + if list.is_null() { + return Vec::new(); + } + + let list_ref = &*list; + let length = list_ref.length as usize; + let mut nodes = Vec::with_capacity(length); + + for i in 0..length { + let cell = list_ref.elements.add(i); + let node_ptr = (*cell).ptr_value as *mut bindings_raw::Node; + + // Always push the node, even if it's None/unrecognized. + // This preserves list structure for things like DISTINCT where + // a placeholder node (Node { node: None }) is meaningful. + let node = convert_node(node_ptr).unwrap_or_else(|| protobuf::Node { node: None }); + nodes.push(node); + } + + nodes +} + +// ============================================================================ +// Statement Conversions +// ============================================================================ + +unsafe fn convert_select_stmt(stmt: &bindings_raw::SelectStmt) -> protobuf::SelectStmt { + protobuf::SelectStmt { + distinct_clause: convert_list_to_nodes(stmt.distinctClause), + into_clause: convert_into_clause(stmt.intoClause), + target_list: convert_list_to_nodes(stmt.targetList), + from_clause: convert_list_to_nodes(stmt.fromClause), + where_clause: convert_node_boxed(stmt.whereClause), + group_clause: convert_list_to_nodes(stmt.groupClause), + group_distinct: stmt.groupDistinct, + having_clause: convert_node_boxed(stmt.havingClause), + window_clause: convert_list_to_nodes(stmt.windowClause), + values_lists: convert_list_to_nodes(stmt.valuesLists), + sort_clause: convert_list_to_nodes(stmt.sortClause), + limit_offset: convert_node_boxed(stmt.limitOffset), + limit_count: convert_node_boxed(stmt.limitCount), + limit_option: stmt.limitOption as i32 + 1, // Protobuf enums have UNDEFINED=0, so C values need +1 + locking_clause: convert_list_to_nodes(stmt.lockingClause), + with_clause: convert_with_clause_opt(stmt.withClause), + op: stmt.op as i32 + 1, // Protobuf SetOperation has UNDEFINED=0, so C values need +1 + all: stmt.all, + larg: if stmt.larg.is_null() { None } else { Some(Box::new(convert_select_stmt(&*stmt.larg))) }, + rarg: if stmt.rarg.is_null() { None } else { Some(Box::new(convert_select_stmt(&*stmt.rarg))) }, + } +} + +unsafe fn convert_insert_stmt(stmt: &bindings_raw::InsertStmt) -> protobuf::InsertStmt { + protobuf::InsertStmt { + relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, + cols: convert_list_to_nodes(stmt.cols), + select_stmt: convert_node_boxed(stmt.selectStmt), + on_conflict_clause: convert_on_conflict_clause(stmt.onConflictClause), + returning_list: convert_list_to_nodes(stmt.returningList), + with_clause: convert_with_clause_opt(stmt.withClause), + r#override: stmt.override_ as i32 + 1, + } +} + +unsafe fn convert_update_stmt(stmt: &bindings_raw::UpdateStmt) -> protobuf::UpdateStmt { + protobuf::UpdateStmt { + relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, + target_list: convert_list_to_nodes(stmt.targetList), + where_clause: convert_node_boxed(stmt.whereClause), + from_clause: convert_list_to_nodes(stmt.fromClause), + returning_list: convert_list_to_nodes(stmt.returningList), + with_clause: convert_with_clause_opt(stmt.withClause), + } +} + +unsafe fn convert_delete_stmt(stmt: &bindings_raw::DeleteStmt) -> protobuf::DeleteStmt { + protobuf::DeleteStmt { + relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, + using_clause: convert_list_to_nodes(stmt.usingClause), + where_clause: convert_node_boxed(stmt.whereClause), + returning_list: convert_list_to_nodes(stmt.returningList), + with_clause: convert_with_clause_opt(stmt.withClause), + } +} + +unsafe fn convert_create_stmt(stmt: &bindings_raw::CreateStmt) -> protobuf::CreateStmt { + protobuf::CreateStmt { + relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, + table_elts: convert_list_to_nodes(stmt.tableElts), + inh_relations: convert_list_to_nodes(stmt.inhRelations), + partbound: convert_partition_bound_spec_opt(stmt.partbound), + partspec: convert_partition_spec_opt(stmt.partspec), + of_typename: if stmt.ofTypename.is_null() { None } else { Some(convert_type_name(&*stmt.ofTypename)) }, + constraints: convert_list_to_nodes(stmt.constraints), + options: convert_list_to_nodes(stmt.options), + oncommit: stmt.oncommit as i32 + 1, + tablespacename: convert_c_string(stmt.tablespacename), + access_method: convert_c_string(stmt.accessMethod), + if_not_exists: stmt.if_not_exists, + } +} + +unsafe fn convert_drop_stmt(stmt: &bindings_raw::DropStmt) -> protobuf::DropStmt { + protobuf::DropStmt { + objects: convert_list_to_nodes(stmt.objects), + remove_type: stmt.removeType as i32 + 1, + behavior: stmt.behavior as i32 + 1, + missing_ok: stmt.missing_ok, + concurrent: stmt.concurrent, + } +} + +unsafe fn convert_index_stmt(stmt: &bindings_raw::IndexStmt) -> protobuf::IndexStmt { + protobuf::IndexStmt { + idxname: convert_c_string(stmt.idxname), + relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, + access_method: convert_c_string(stmt.accessMethod), + table_space: convert_c_string(stmt.tableSpace), + index_params: convert_list_to_nodes(stmt.indexParams), + index_including_params: convert_list_to_nodes(stmt.indexIncludingParams), + options: convert_list_to_nodes(stmt.options), + where_clause: convert_node_boxed(stmt.whereClause), + exclude_op_names: convert_list_to_nodes(stmt.excludeOpNames), + idxcomment: convert_c_string(stmt.idxcomment), + index_oid: stmt.indexOid, + old_number: stmt.oldNumber, + old_create_subid: stmt.oldCreateSubid, + old_first_relfilelocator_subid: stmt.oldFirstRelfilelocatorSubid, + unique: stmt.unique, + nulls_not_distinct: stmt.nulls_not_distinct, + primary: stmt.primary, + isconstraint: stmt.isconstraint, + deferrable: stmt.deferrable, + initdeferred: stmt.initdeferred, + transformed: stmt.transformed, + concurrent: stmt.concurrent, + if_not_exists: stmt.if_not_exists, + reset_default_tblspc: stmt.reset_default_tblspc, + } +} + +// ============================================================================ +// Expression/Clause Conversions +// ============================================================================ + +unsafe fn convert_range_var(rv: &bindings_raw::RangeVar) -> protobuf::RangeVar { + protobuf::RangeVar { + catalogname: convert_c_string(rv.catalogname), + schemaname: convert_c_string(rv.schemaname), + relname: convert_c_string(rv.relname), + inh: rv.inh, + relpersistence: String::from_utf8_lossy(&[rv.relpersistence as u8]).to_string(), + alias: if rv.alias.is_null() { None } else { Some(convert_alias(&*rv.alias)) }, + location: rv.location, + } +} + +unsafe fn convert_column_ref(cr: &bindings_raw::ColumnRef) -> protobuf::ColumnRef { + protobuf::ColumnRef { fields: convert_list_to_nodes(cr.fields), location: cr.location } +} + +unsafe fn convert_res_target(rt: &bindings_raw::ResTarget) -> protobuf::ResTarget { + protobuf::ResTarget { + name: convert_c_string(rt.name), + indirection: convert_list_to_nodes(rt.indirection), + val: convert_node_boxed(rt.val), + location: rt.location, + } +} + +unsafe fn convert_a_expr(expr: &bindings_raw::A_Expr) -> protobuf::AExpr { + protobuf::AExpr { + kind: expr.kind as i32 + 1, + name: convert_list_to_nodes(expr.name), + lexpr: convert_node_boxed(expr.lexpr), + rexpr: convert_node_boxed(expr.rexpr), + location: expr.location, + } +} + +unsafe fn convert_a_const(aconst: &bindings_raw::A_Const) -> protobuf::AConst { + let val = if aconst.isnull { + None + } else { + // Check the node tag in the val union to determine the type + let node_tag = aconst.val.node.type_; + match node_tag { + bindings_raw::NodeTag_T_Integer => Some(protobuf::a_const::Val::Ival(protobuf::Integer { ival: aconst.val.ival.ival })), + bindings_raw::NodeTag_T_Float => { + let fval = if aconst.val.fval.fval.is_null() { + std::string::String::new() + } else { + CStr::from_ptr(aconst.val.fval.fval).to_string_lossy().to_string() + }; + Some(protobuf::a_const::Val::Fval(protobuf::Float { fval })) + } + bindings_raw::NodeTag_T_Boolean => Some(protobuf::a_const::Val::Boolval(protobuf::Boolean { boolval: aconst.val.boolval.boolval })), + bindings_raw::NodeTag_T_String => { + let sval = if aconst.val.sval.sval.is_null() { + std::string::String::new() + } else { + CStr::from_ptr(aconst.val.sval.sval).to_string_lossy().to_string() + }; + Some(protobuf::a_const::Val::Sval(protobuf::String { sval })) + } + bindings_raw::NodeTag_T_BitString => { + let bsval = if aconst.val.bsval.bsval.is_null() { + std::string::String::new() + } else { + CStr::from_ptr(aconst.val.bsval.bsval).to_string_lossy().to_string() + }; + Some(protobuf::a_const::Val::Bsval(protobuf::BitString { bsval })) + } + _ => None, + } + }; + + protobuf::AConst { isnull: aconst.isnull, val, location: aconst.location } +} + +unsafe fn convert_func_call(fc: &bindings_raw::FuncCall) -> protobuf::FuncCall { + protobuf::FuncCall { + funcname: convert_list_to_nodes(fc.funcname), + args: convert_list_to_nodes(fc.args), + agg_order: convert_list_to_nodes(fc.agg_order), + agg_filter: convert_node_boxed(fc.agg_filter), + over: if fc.over.is_null() { None } else { Some(Box::new(convert_window_def(&*fc.over))) }, + agg_within_group: fc.agg_within_group, + agg_star: fc.agg_star, + agg_distinct: fc.agg_distinct, + func_variadic: fc.func_variadic, + funcformat: fc.funcformat as i32 + 1, + location: fc.location, + } +} + +unsafe fn convert_type_cast(tc: &bindings_raw::TypeCast) -> protobuf::TypeCast { + protobuf::TypeCast { + arg: convert_node_boxed(tc.arg), + type_name: if tc.typeName.is_null() { None } else { Some(convert_type_name(&*tc.typeName)) }, + location: tc.location, + } +} + +unsafe fn convert_type_name(tn: &bindings_raw::TypeName) -> protobuf::TypeName { + protobuf::TypeName { + names: convert_list_to_nodes(tn.names), + type_oid: tn.typeOid, + setof: tn.setof, + pct_type: tn.pct_type, + typmods: convert_list_to_nodes(tn.typmods), + typemod: tn.typemod, + array_bounds: convert_list_to_nodes(tn.arrayBounds), + location: tn.location, + } +} + +unsafe fn convert_alias(alias: &bindings_raw::Alias) -> protobuf::Alias { + protobuf::Alias { aliasname: convert_c_string(alias.aliasname), colnames: convert_list_to_nodes(alias.colnames) } +} + +unsafe fn convert_join_expr(je: &bindings_raw::JoinExpr) -> protobuf::JoinExpr { + protobuf::JoinExpr { + jointype: je.jointype as i32 + 1, + is_natural: je.isNatural, + larg: convert_node_boxed(je.larg), + rarg: convert_node_boxed(je.rarg), + using_clause: convert_list_to_nodes(je.usingClause), + join_using_alias: if je.join_using_alias.is_null() { None } else { Some(convert_alias(&*je.join_using_alias)) }, + quals: convert_node_boxed(je.quals), + alias: if je.alias.is_null() { None } else { Some(convert_alias(&*je.alias)) }, + rtindex: je.rtindex, + } +} + +unsafe fn convert_sort_by(sb: &bindings_raw::SortBy) -> protobuf::SortBy { + protobuf::SortBy { + node: convert_node_boxed(sb.node), + sortby_dir: sb.sortby_dir as i32 + 1, + sortby_nulls: sb.sortby_nulls as i32 + 1, + use_op: convert_list_to_nodes(sb.useOp), + location: sb.location, + } +} + +unsafe fn convert_bool_expr(be: &bindings_raw::BoolExpr) -> protobuf::BoolExpr { + protobuf::BoolExpr { + xpr: None, // Xpr is internal + boolop: be.boolop as i32 + 1, + args: convert_list_to_nodes(be.args), + location: be.location, + } +} + +unsafe fn convert_sub_link(sl: &bindings_raw::SubLink) -> protobuf::SubLink { + protobuf::SubLink { + xpr: None, + sub_link_type: sl.subLinkType as i32 + 1, + sub_link_id: sl.subLinkId, + testexpr: convert_node_boxed(sl.testexpr), + oper_name: convert_list_to_nodes(sl.operName), + subselect: convert_node_boxed(sl.subselect), + location: sl.location, + } +} + +unsafe fn convert_null_test(nt: &bindings_raw::NullTest) -> protobuf::NullTest { + protobuf::NullTest { + xpr: None, + arg: convert_node_boxed(nt.arg as *mut bindings_raw::Node), + nulltesttype: nt.nulltesttype as i32 + 1, + argisrow: nt.argisrow, + location: nt.location, + } +} + +unsafe fn convert_case_expr(ce: &bindings_raw::CaseExpr) -> protobuf::CaseExpr { + protobuf::CaseExpr { + xpr: None, + casetype: ce.casetype, + casecollid: ce.casecollid, + arg: convert_node_boxed(ce.arg as *mut bindings_raw::Node), + args: convert_list_to_nodes(ce.args), + defresult: convert_node_boxed(ce.defresult as *mut bindings_raw::Node), + location: ce.location, + } +} + +unsafe fn convert_case_when(cw: &bindings_raw::CaseWhen) -> protobuf::CaseWhen { + protobuf::CaseWhen { + xpr: None, + expr: convert_node_boxed(cw.expr as *mut bindings_raw::Node), + result: convert_node_boxed(cw.result as *mut bindings_raw::Node), + location: cw.location, + } +} + +unsafe fn convert_coalesce_expr(ce: &bindings_raw::CoalesceExpr) -> protobuf::CoalesceExpr { + protobuf::CoalesceExpr { + xpr: None, + coalescetype: ce.coalescetype, + coalescecollid: ce.coalescecollid, + args: convert_list_to_nodes(ce.args), + location: ce.location, + } +} + +unsafe fn convert_with_clause(wc: &bindings_raw::WithClause) -> protobuf::WithClause { + protobuf::WithClause { ctes: convert_list_to_nodes(wc.ctes), recursive: wc.recursive, location: wc.location } +} + +unsafe fn convert_with_clause_opt(wc: *mut bindings_raw::WithClause) -> Option { + if wc.is_null() { + None + } else { + Some(convert_with_clause(&*wc)) + } +} + +unsafe fn convert_common_table_expr(cte: &bindings_raw::CommonTableExpr) -> protobuf::CommonTableExpr { + protobuf::CommonTableExpr { + ctename: convert_c_string(cte.ctename), + aliascolnames: convert_list_to_nodes(cte.aliascolnames), + ctematerialized: cte.ctematerialized as i32 + 1, + ctequery: convert_node_boxed(cte.ctequery), + search_clause: convert_cte_search_clause_opt(cte.search_clause), + cycle_clause: convert_cte_cycle_clause_opt(cte.cycle_clause), + location: cte.location, + cterecursive: cte.cterecursive, + cterefcount: cte.cterefcount, + ctecolnames: convert_list_to_nodes(cte.ctecolnames), + ctecoltypes: convert_list_to_nodes(cte.ctecoltypes), + ctecoltypmods: convert_list_to_nodes(cte.ctecoltypmods), + ctecolcollations: convert_list_to_nodes(cte.ctecolcollations), + } +} + +unsafe fn convert_window_def(wd: &bindings_raw::WindowDef) -> protobuf::WindowDef { + protobuf::WindowDef { + name: convert_c_string(wd.name), + refname: convert_c_string(wd.refname), + partition_clause: convert_list_to_nodes(wd.partitionClause), + order_clause: convert_list_to_nodes(wd.orderClause), + frame_options: wd.frameOptions, + start_offset: convert_node_boxed(wd.startOffset), + end_offset: convert_node_boxed(wd.endOffset), + location: wd.location, + } +} + +unsafe fn convert_into_clause(ic: *mut bindings_raw::IntoClause) -> Option> { + if ic.is_null() { + return None; + } + let ic_ref = &*ic; + Some(Box::new(protobuf::IntoClause { + rel: if ic_ref.rel.is_null() { None } else { Some(convert_range_var(&*ic_ref.rel)) }, + col_names: convert_list_to_nodes(ic_ref.colNames), + access_method: convert_c_string(ic_ref.accessMethod), + options: convert_list_to_nodes(ic_ref.options), + on_commit: ic_ref.onCommit as i32 + 1, + table_space_name: convert_c_string(ic_ref.tableSpaceName), + view_query: convert_node_boxed(ic_ref.viewQuery), + skip_data: ic_ref.skipData, + })) +} + +unsafe fn convert_infer_clause(ic: *mut bindings_raw::InferClause) -> Option> { + if ic.is_null() { + return None; + } + let ic_ref = &*ic; + Some(Box::new(protobuf::InferClause { + index_elems: convert_list_to_nodes(ic_ref.indexElems), + where_clause: convert_node_boxed(ic_ref.whereClause), + conname: convert_c_string(ic_ref.conname), + location: ic_ref.location, + })) +} + +unsafe fn convert_on_conflict_clause(oc: *mut bindings_raw::OnConflictClause) -> Option> { + if oc.is_null() { + return None; + } + let oc_ref = &*oc; + Some(Box::new(protobuf::OnConflictClause { + action: oc_ref.action as i32 + 1, + infer: convert_infer_clause(oc_ref.infer), + target_list: convert_list_to_nodes(oc_ref.targetList), + where_clause: convert_node_boxed(oc_ref.whereClause), + location: oc_ref.location, + })) +} + +unsafe fn convert_column_def(cd: &bindings_raw::ColumnDef) -> protobuf::ColumnDef { + protobuf::ColumnDef { + colname: convert_c_string(cd.colname), + type_name: if cd.typeName.is_null() { None } else { Some(convert_type_name(&*cd.typeName)) }, + compression: convert_c_string(cd.compression), + inhcount: cd.inhcount, + is_local: cd.is_local, + is_not_null: cd.is_not_null, + is_from_type: cd.is_from_type, + storage: if cd.storage == 0 { String::new() } else { String::from_utf8_lossy(&[cd.storage as u8]).to_string() }, + storage_name: convert_c_string(cd.storage_name), + raw_default: convert_node_boxed(cd.raw_default), + cooked_default: convert_node_boxed(cd.cooked_default), + identity: if cd.identity == 0 { String::new() } else { String::from_utf8_lossy(&[cd.identity as u8]).to_string() }, + identity_sequence: if cd.identitySequence.is_null() { None } else { Some(convert_range_var(&*cd.identitySequence)) }, + generated: if cd.generated == 0 { String::new() } else { String::from_utf8_lossy(&[cd.generated as u8]).to_string() }, + coll_clause: convert_collate_clause_opt(cd.collClause), + coll_oid: cd.collOid, + constraints: convert_list_to_nodes(cd.constraints), + fdwoptions: convert_list_to_nodes(cd.fdwoptions), + location: cd.location, + } +} + +unsafe fn convert_constraint(c: &bindings_raw::Constraint) -> protobuf::Constraint { + protobuf::Constraint { + contype: c.contype as i32 + 1, + conname: convert_c_string(c.conname), + deferrable: c.deferrable, + initdeferred: c.initdeferred, + location: c.location, + is_no_inherit: c.is_no_inherit, + raw_expr: convert_node_boxed(c.raw_expr), + cooked_expr: convert_c_string(c.cooked_expr), + generated_when: if c.generated_when == 0 { String::new() } else { String::from_utf8_lossy(&[c.generated_when as u8]).to_string() }, + inhcount: c.inhcount, + nulls_not_distinct: c.nulls_not_distinct, + keys: convert_list_to_nodes(c.keys), + including: convert_list_to_nodes(c.including), + exclusions: convert_list_to_nodes(c.exclusions), + options: convert_list_to_nodes(c.options), + indexname: convert_c_string(c.indexname), + indexspace: convert_c_string(c.indexspace), + reset_default_tblspc: c.reset_default_tblspc, + access_method: convert_c_string(c.access_method), + where_clause: convert_node_boxed(c.where_clause), + pktable: if c.pktable.is_null() { None } else { Some(convert_range_var(&*c.pktable)) }, + fk_attrs: convert_list_to_nodes(c.fk_attrs), + pk_attrs: convert_list_to_nodes(c.pk_attrs), + fk_matchtype: if c.fk_matchtype == 0 { String::new() } else { String::from_utf8_lossy(&[c.fk_matchtype as u8]).to_string() }, + fk_upd_action: if c.fk_upd_action == 0 { String::new() } else { String::from_utf8_lossy(&[c.fk_upd_action as u8]).to_string() }, + fk_del_action: if c.fk_del_action == 0 { String::new() } else { String::from_utf8_lossy(&[c.fk_del_action as u8]).to_string() }, + fk_del_set_cols: convert_list_to_nodes(c.fk_del_set_cols), + old_conpfeqop: convert_list_to_nodes(c.old_conpfeqop), + old_pktable_oid: c.old_pktable_oid, + skip_validation: c.skip_validation, + initially_valid: c.initially_valid, + } +} + +unsafe fn convert_index_elem(ie: &bindings_raw::IndexElem) -> protobuf::IndexElem { + protobuf::IndexElem { + name: convert_c_string(ie.name), + expr: convert_node_boxed(ie.expr), + indexcolname: convert_c_string(ie.indexcolname), + collation: convert_list_to_nodes(ie.collation), + opclass: convert_list_to_nodes(ie.opclass), + opclassopts: convert_list_to_nodes(ie.opclassopts), + ordering: ie.ordering as i32 + 1, + nulls_ordering: ie.nulls_ordering as i32 + 1, + } +} + +unsafe fn convert_def_elem(de: &bindings_raw::DefElem) -> protobuf::DefElem { + protobuf::DefElem { + defnamespace: convert_c_string(de.defnamespace), + defname: convert_c_string(de.defname), + arg: convert_node_boxed(de.arg), + defaction: de.defaction as i32 + 1, + location: de.location, + } +} + +unsafe fn convert_string(s: &bindings_raw::String) -> protobuf::String { + protobuf::String { sval: convert_c_string(s.sval) } +} + +unsafe fn convert_replica_identity_stmt(ris: &bindings_raw::ReplicaIdentityStmt) -> protobuf::ReplicaIdentityStmt { + protobuf::ReplicaIdentityStmt { identity_type: String::from_utf8_lossy(&[ris.identity_type as u8]).to_string(), name: convert_c_string(ris.name) } +} + +unsafe fn convert_grouping_func(gf: &bindings_raw::GroupingFunc) -> protobuf::GroupingFunc { + protobuf::GroupingFunc { + xpr: None, + args: convert_list_to_nodes(gf.args), + refs: convert_list_to_nodes(gf.refs), + agglevelsup: gf.agglevelsup, + location: gf.location, + } +} + +unsafe fn convert_locking_clause(lc: &bindings_raw::LockingClause) -> protobuf::LockingClause { + protobuf::LockingClause { + locked_rels: convert_list_to_nodes(lc.lockedRels), + strength: lc.strength as i32 + 1, + wait_policy: lc.waitPolicy as i32 + 1, + } +} + +unsafe fn convert_min_max_expr(mme: &bindings_raw::MinMaxExpr) -> protobuf::MinMaxExpr { + protobuf::MinMaxExpr { + xpr: None, // Expression type info, not needed for parse tree + minmaxtype: mme.minmaxtype, + minmaxcollid: mme.minmaxcollid, + inputcollid: mme.inputcollid, + op: mme.op as i32 + 1, + args: convert_list_to_nodes(mme.args), + location: mme.location, + } +} + +unsafe fn convert_grouping_set(gs: &bindings_raw::GroupingSet) -> protobuf::GroupingSet { + protobuf::GroupingSet { kind: gs.kind as i32 + 1, content: convert_list_to_nodes(gs.content), location: gs.location } +} + +unsafe fn convert_range_subselect(rs: &bindings_raw::RangeSubselect) -> protobuf::RangeSubselect { + protobuf::RangeSubselect { + lateral: rs.lateral, + subquery: convert_node_boxed(rs.subquery), + alias: if rs.alias.is_null() { None } else { Some(convert_alias(&*rs.alias)) }, + } +} + +unsafe fn convert_a_array_expr(ae: &bindings_raw::A_ArrayExpr) -> protobuf::AArrayExpr { + protobuf::AArrayExpr { elements: convert_list_to_nodes(ae.elements), location: ae.location } +} + +unsafe fn convert_a_indirection(ai: &bindings_raw::A_Indirection) -> protobuf::AIndirection { + protobuf::AIndirection { arg: convert_node_boxed(ai.arg), indirection: convert_list_to_nodes(ai.indirection) } +} + +unsafe fn convert_a_indices(ai: &bindings_raw::A_Indices) -> protobuf::AIndices { + protobuf::AIndices { is_slice: ai.is_slice, lidx: convert_node_boxed(ai.lidx), uidx: convert_node_boxed(ai.uidx) } +} + +unsafe fn convert_alter_table_stmt(ats: &bindings_raw::AlterTableStmt) -> protobuf::AlterTableStmt { + protobuf::AlterTableStmt { + relation: if ats.relation.is_null() { None } else { Some(convert_range_var(&*ats.relation)) }, + cmds: convert_list_to_nodes(ats.cmds), + objtype: ats.objtype as i32 + 1, + missing_ok: ats.missing_ok, + } +} + +unsafe fn convert_alter_table_cmd(atc: &bindings_raw::AlterTableCmd) -> protobuf::AlterTableCmd { + protobuf::AlterTableCmd { + subtype: atc.subtype as i32 + 1, + name: convert_c_string(atc.name), + num: atc.num as i32, + newowner: if atc.newowner.is_null() { None } else { Some(convert_role_spec(&*atc.newowner)) }, + def: convert_node_boxed(atc.def), + behavior: atc.behavior as i32 + 1, + missing_ok: atc.missing_ok, + recurse: atc.recurse, + } +} + +unsafe fn convert_role_spec(rs: &bindings_raw::RoleSpec) -> protobuf::RoleSpec { + protobuf::RoleSpec { roletype: rs.roletype as i32 + 1, rolename: convert_c_string(rs.rolename), location: rs.location } +} + +unsafe fn convert_copy_stmt(cs: &bindings_raw::CopyStmt) -> protobuf::CopyStmt { + protobuf::CopyStmt { + relation: if cs.relation.is_null() { None } else { Some(convert_range_var(&*cs.relation)) }, + query: convert_node_boxed(cs.query), + attlist: convert_list_to_nodes(cs.attlist), + is_from: cs.is_from, + is_program: cs.is_program, + filename: convert_c_string(cs.filename), + options: convert_list_to_nodes(cs.options), + where_clause: convert_node_boxed(cs.whereClause), + } +} + +unsafe fn convert_truncate_stmt(ts: &bindings_raw::TruncateStmt) -> protobuf::TruncateStmt { + protobuf::TruncateStmt { relations: convert_list_to_nodes(ts.relations), restart_seqs: ts.restart_seqs, behavior: ts.behavior as i32 + 1 } +} + +unsafe fn convert_view_stmt(vs: &bindings_raw::ViewStmt) -> protobuf::ViewStmt { + protobuf::ViewStmt { + view: if vs.view.is_null() { None } else { Some(convert_range_var(&*vs.view)) }, + aliases: convert_list_to_nodes(vs.aliases), + query: convert_node_boxed(vs.query), + replace: vs.replace, + options: convert_list_to_nodes(vs.options), + with_check_option: vs.withCheckOption as i32 + 1, + } +} + +unsafe fn convert_explain_stmt(es: &bindings_raw::ExplainStmt) -> protobuf::ExplainStmt { + protobuf::ExplainStmt { query: convert_node_boxed(es.query), options: convert_list_to_nodes(es.options) } +} + +unsafe fn convert_create_table_as_stmt(ctas: &bindings_raw::CreateTableAsStmt) -> protobuf::CreateTableAsStmt { + protobuf::CreateTableAsStmt { + query: convert_node_boxed(ctas.query), + into: convert_into_clause(ctas.into), + objtype: ctas.objtype as i32 + 1, + is_select_into: ctas.is_select_into, + if_not_exists: ctas.if_not_exists, + } +} + +unsafe fn convert_prepare_stmt(ps: &bindings_raw::PrepareStmt) -> protobuf::PrepareStmt { + protobuf::PrepareStmt { name: convert_c_string(ps.name), argtypes: convert_list_to_nodes(ps.argtypes), query: convert_node_boxed(ps.query) } +} + +unsafe fn convert_execute_stmt(es: &bindings_raw::ExecuteStmt) -> protobuf::ExecuteStmt { + protobuf::ExecuteStmt { name: convert_c_string(es.name), params: convert_list_to_nodes(es.params) } +} + +unsafe fn convert_deallocate_stmt(ds: &bindings_raw::DeallocateStmt) -> protobuf::DeallocateStmt { + protobuf::DeallocateStmt { name: convert_c_string(ds.name), isall: ds.isall, location: ds.location } +} + +unsafe fn convert_set_to_default(std: &bindings_raw::SetToDefault) -> protobuf::SetToDefault { + protobuf::SetToDefault { + xpr: None, // Expression type info, not needed for parse tree + type_id: std.typeId, + type_mod: std.typeMod, + collation: std.collation, + location: std.location, + } +} + +unsafe fn convert_multi_assign_ref(mar: &bindings_raw::MultiAssignRef) -> protobuf::MultiAssignRef { + protobuf::MultiAssignRef { source: convert_node_boxed(mar.source), colno: mar.colno, ncolumns: mar.ncolumns } +} + +unsafe fn convert_row_expr(re: &bindings_raw::RowExpr) -> protobuf::RowExpr { + protobuf::RowExpr { + xpr: None, // Expression type info, not needed for parse tree + args: convert_list_to_nodes(re.args), + row_typeid: re.row_typeid, + row_format: re.row_format as i32 + 1, + colnames: convert_list_to_nodes(re.colnames), + location: re.location, + } +} + +unsafe fn convert_collate_clause(cc: &bindings_raw::CollateClause) -> protobuf::CollateClause { + protobuf::CollateClause { arg: convert_node_boxed(cc.arg), collname: convert_list_to_nodes(cc.collname), location: cc.location } +} + +unsafe fn convert_collate_clause_opt(cc: *mut bindings_raw::CollateClause) -> Option> { + if cc.is_null() { + None + } else { + Some(Box::new(convert_collate_clause(&*cc))) + } +} + +unsafe fn convert_partition_spec(ps: &bindings_raw::PartitionSpec) -> protobuf::PartitionSpec { + // Map from C char values to protobuf enum values + // C: 'l'=108, 'r'=114, 'h'=104 + // Protobuf: LIST=1, RANGE=2, HASH=3 + let strategy = match ps.strategy as u8 as char { + 'l' => 1, // LIST + 'r' => 2, // RANGE + 'h' => 3, // HASH + _ => 0, // UNDEFINED + }; + protobuf::PartitionSpec { strategy, part_params: convert_list_to_nodes(ps.partParams), location: ps.location } +} + +unsafe fn convert_partition_spec_opt(ps: *mut bindings_raw::PartitionSpec) -> Option { + if ps.is_null() { + None + } else { + Some(convert_partition_spec(&*ps)) + } +} + +unsafe fn convert_partition_bound_spec(pbs: &bindings_raw::PartitionBoundSpec) -> protobuf::PartitionBoundSpec { + protobuf::PartitionBoundSpec { + strategy: if pbs.strategy == 0 { String::new() } else { String::from_utf8_lossy(&[pbs.strategy as u8]).to_string() }, + is_default: pbs.is_default, + modulus: pbs.modulus, + remainder: pbs.remainder, + listdatums: convert_list_to_nodes(pbs.listdatums), + lowerdatums: convert_list_to_nodes(pbs.lowerdatums), + upperdatums: convert_list_to_nodes(pbs.upperdatums), + location: pbs.location, + } +} + +unsafe fn convert_partition_bound_spec_opt(pbs: *mut bindings_raw::PartitionBoundSpec) -> Option { + if pbs.is_null() { + None + } else { + Some(convert_partition_bound_spec(&*pbs)) + } +} + +unsafe fn convert_partition_elem(pe: &bindings_raw::PartitionElem) -> protobuf::PartitionElem { + protobuf::PartitionElem { + name: convert_c_string(pe.name), + expr: convert_node_boxed(pe.expr), + collation: convert_list_to_nodes(pe.collation), + opclass: convert_list_to_nodes(pe.opclass), + location: pe.location, + } +} + +unsafe fn convert_partition_range_datum(prd: &bindings_raw::PartitionRangeDatum) -> protobuf::PartitionRangeDatum { + // Map from C enum to protobuf enum + // C: PARTITION_RANGE_DATUM_MINVALUE=-1, PARTITION_RANGE_DATUM_VALUE=0, PARTITION_RANGE_DATUM_MAXVALUE=1 + // Protobuf: UNDEFINED=0, MINVALUE=1, VALUE=2, MAXVALUE=3 + let kind = match prd.kind { + bindings_raw::PartitionRangeDatumKind_PARTITION_RANGE_DATUM_MINVALUE => 1, + bindings_raw::PartitionRangeDatumKind_PARTITION_RANGE_DATUM_VALUE => 2, + bindings_raw::PartitionRangeDatumKind_PARTITION_RANGE_DATUM_MAXVALUE => 3, + _ => 0, + }; + protobuf::PartitionRangeDatum { kind, value: convert_node_boxed(prd.value), location: prd.location } +} + +unsafe fn convert_cte_search_clause(csc: &bindings_raw::CTESearchClause) -> protobuf::CteSearchClause { + protobuf::CteSearchClause { + search_col_list: convert_list_to_nodes(csc.search_col_list), + search_breadth_first: csc.search_breadth_first, + search_seq_column: convert_c_string(csc.search_seq_column), + location: csc.location, + } +} + +unsafe fn convert_cte_search_clause_opt(csc: *mut bindings_raw::CTESearchClause) -> Option { + if csc.is_null() { + None + } else { + Some(convert_cte_search_clause(&*csc)) + } +} + +unsafe fn convert_cte_cycle_clause(ccc: &bindings_raw::CTECycleClause) -> protobuf::CteCycleClause { + protobuf::CteCycleClause { + cycle_col_list: convert_list_to_nodes(ccc.cycle_col_list), + cycle_mark_column: convert_c_string(ccc.cycle_mark_column), + cycle_mark_value: convert_node_boxed(ccc.cycle_mark_value), + cycle_mark_default: convert_node_boxed(ccc.cycle_mark_default), + cycle_path_column: convert_c_string(ccc.cycle_path_column), + location: ccc.location, + cycle_mark_type: ccc.cycle_mark_type, + cycle_mark_typmod: ccc.cycle_mark_typmod, + cycle_mark_collation: ccc.cycle_mark_collation, + cycle_mark_neop: ccc.cycle_mark_neop, + } +} + +unsafe fn convert_cte_cycle_clause_opt(ccc: *mut bindings_raw::CTECycleClause) -> Option> { + if ccc.is_null() { + None + } else { + Some(Box::new(convert_cte_cycle_clause(&*ccc))) + } +} + +// ============================================================================ +// Additional Statement Conversions +// ============================================================================ + +unsafe fn convert_transaction_stmt(ts: &bindings_raw::TransactionStmt) -> protobuf::TransactionStmt { + protobuf::TransactionStmt { + kind: ts.kind as i32 + 1, // Protobuf enums have UNDEFINED=0 + options: convert_list_to_nodes(ts.options), + savepoint_name: convert_c_string(ts.savepoint_name), + gid: convert_c_string(ts.gid), + chain: ts.chain, + location: ts.location, + } +} + +unsafe fn convert_vacuum_stmt(vs: &bindings_raw::VacuumStmt) -> protobuf::VacuumStmt { + protobuf::VacuumStmt { options: convert_list_to_nodes(vs.options), rels: convert_list_to_nodes(vs.rels), is_vacuumcmd: vs.is_vacuumcmd } +} + +unsafe fn convert_vacuum_relation(vr: &bindings_raw::VacuumRelation) -> protobuf::VacuumRelation { + protobuf::VacuumRelation { + relation: if vr.relation.is_null() { None } else { Some(convert_range_var(&*vr.relation)) }, + oid: vr.oid, + va_cols: convert_list_to_nodes(vr.va_cols), + } +} + +unsafe fn convert_variable_set_stmt(vss: &bindings_raw::VariableSetStmt) -> protobuf::VariableSetStmt { + protobuf::VariableSetStmt { + kind: vss.kind as i32 + 1, // Protobuf enums have UNDEFINED=0 + name: convert_c_string(vss.name), + args: convert_list_to_nodes(vss.args), + is_local: vss.is_local, + } +} + +unsafe fn convert_variable_show_stmt(vss: &bindings_raw::VariableShowStmt) -> protobuf::VariableShowStmt { + protobuf::VariableShowStmt { name: convert_c_string(vss.name) } +} + +unsafe fn convert_create_seq_stmt(css: &bindings_raw::CreateSeqStmt) -> protobuf::CreateSeqStmt { + protobuf::CreateSeqStmt { + sequence: if css.sequence.is_null() { None } else { Some(convert_range_var(&*css.sequence)) }, + options: convert_list_to_nodes(css.options), + owner_id: css.ownerId, + for_identity: css.for_identity, + if_not_exists: css.if_not_exists, + } +} + +unsafe fn convert_do_stmt(ds: &bindings_raw::DoStmt) -> protobuf::DoStmt { + protobuf::DoStmt { args: convert_list_to_nodes(ds.args) } +} + +unsafe fn convert_lock_stmt(ls: &bindings_raw::LockStmt) -> protobuf::LockStmt { + protobuf::LockStmt { relations: convert_list_to_nodes(ls.relations), mode: ls.mode, nowait: ls.nowait } +} + +unsafe fn convert_create_schema_stmt(css: &bindings_raw::CreateSchemaStmt) -> protobuf::CreateSchemaStmt { + protobuf::CreateSchemaStmt { + schemaname: convert_c_string(css.schemaname), + authrole: if css.authrole.is_null() { None } else { Some(convert_role_spec(&*css.authrole)) }, + schema_elts: convert_list_to_nodes(css.schemaElts), + if_not_exists: css.if_not_exists, + } +} + +unsafe fn convert_rename_stmt(rs: &bindings_raw::RenameStmt) -> protobuf::RenameStmt { + protobuf::RenameStmt { + rename_type: rs.renameType as i32 + 1, // Protobuf ObjectType has UNDEFINED=0 + relation_type: rs.relationType as i32 + 1, + relation: if rs.relation.is_null() { None } else { Some(convert_range_var(&*rs.relation)) }, + object: convert_node_boxed(rs.object), + subname: convert_c_string(rs.subname), + newname: convert_c_string(rs.newname), + behavior: rs.behavior as i32 + 1, + missing_ok: rs.missing_ok, + } +} + +unsafe fn convert_create_function_stmt(cfs: &bindings_raw::CreateFunctionStmt) -> protobuf::CreateFunctionStmt { + protobuf::CreateFunctionStmt { + is_procedure: cfs.is_procedure, + replace: cfs.replace, + funcname: convert_list_to_nodes(cfs.funcname), + parameters: convert_list_to_nodes(cfs.parameters), + return_type: if cfs.returnType.is_null() { None } else { Some(convert_type_name(&*cfs.returnType)) }, + options: convert_list_to_nodes(cfs.options), + sql_body: convert_node_boxed(cfs.sql_body), + } +} + +unsafe fn convert_alter_owner_stmt(aos: &bindings_raw::AlterOwnerStmt) -> protobuf::AlterOwnerStmt { + protobuf::AlterOwnerStmt { + object_type: aos.objectType as i32 + 1, // Protobuf ObjectType has UNDEFINED=0 + relation: if aos.relation.is_null() { None } else { Some(convert_range_var(&*aos.relation)) }, + object: convert_node_boxed(aos.object), + newowner: if aos.newowner.is_null() { None } else { Some(convert_role_spec(&*aos.newowner)) }, + } +} + +unsafe fn convert_alter_seq_stmt(ass: &bindings_raw::AlterSeqStmt) -> protobuf::AlterSeqStmt { + protobuf::AlterSeqStmt { + sequence: if ass.sequence.is_null() { None } else { Some(convert_range_var(&*ass.sequence)) }, + options: convert_list_to_nodes(ass.options), + for_identity: ass.for_identity, + missing_ok: ass.missing_ok, + } +} + +unsafe fn convert_create_enum_stmt(ces: &bindings_raw::CreateEnumStmt) -> protobuf::CreateEnumStmt { + protobuf::CreateEnumStmt { type_name: convert_list_to_nodes(ces.typeName), vals: convert_list_to_nodes(ces.vals) } +} + +unsafe fn convert_object_with_args(owa: &bindings_raw::ObjectWithArgs) -> protobuf::ObjectWithArgs { + protobuf::ObjectWithArgs { + objname: convert_list_to_nodes(owa.objname), + objargs: convert_list_to_nodes(owa.objargs), + objfuncargs: convert_list_to_nodes(owa.objfuncargs), + args_unspecified: owa.args_unspecified, + } +} + +unsafe fn convert_function_parameter(fp: &bindings_raw::FunctionParameter) -> protobuf::FunctionParameter { + protobuf::FunctionParameter { + name: convert_c_string(fp.name), + arg_type: if fp.argType.is_null() { None } else { Some(convert_type_name(&*fp.argType)) }, + mode: convert_function_parameter_mode(fp.mode), + defexpr: convert_node_boxed(fp.defexpr), + } +} + +/// Converts raw FunctionParameterMode (ASCII char codes) to protobuf enum values +fn convert_function_parameter_mode(mode: bindings_raw::FunctionParameterMode) -> i32 { + match mode { + bindings_raw::FunctionParameterMode_FUNC_PARAM_IN => protobuf::FunctionParameterMode::FuncParamIn as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_OUT => protobuf::FunctionParameterMode::FuncParamOut as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_INOUT => protobuf::FunctionParameterMode::FuncParamInout as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_VARIADIC => protobuf::FunctionParameterMode::FuncParamVariadic as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_TABLE => protobuf::FunctionParameterMode::FuncParamTable as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_DEFAULT => protobuf::FunctionParameterMode::FuncParamDefault as i32, + _ => 0, // Undefined + } +} + +unsafe fn convert_notify_stmt(ns: &bindings_raw::NotifyStmt) -> protobuf::NotifyStmt { + protobuf::NotifyStmt { conditionname: convert_c_string(ns.conditionname), payload: convert_c_string(ns.payload) } +} + +unsafe fn convert_listen_stmt(ls: &bindings_raw::ListenStmt) -> protobuf::ListenStmt { + protobuf::ListenStmt { conditionname: convert_c_string(ls.conditionname) } +} + +unsafe fn convert_unlisten_stmt(us: &bindings_raw::UnlistenStmt) -> protobuf::UnlistenStmt { + protobuf::UnlistenStmt { conditionname: convert_c_string(us.conditionname) } +} + +unsafe fn convert_discard_stmt(ds: &bindings_raw::DiscardStmt) -> protobuf::DiscardStmt { + protobuf::DiscardStmt { + target: ds.target as i32 + 1, // DiscardMode enum + } +} + +unsafe fn convert_coerce_to_domain(ctd: &bindings_raw::CoerceToDomain) -> protobuf::CoerceToDomain { + protobuf::CoerceToDomain { + xpr: None, + arg: convert_node_boxed(ctd.arg as *mut bindings_raw::Node), + resulttype: ctd.resulttype, + resulttypmod: ctd.resulttypmod, + resultcollid: ctd.resultcollid, + coercionformat: ctd.coercionformat as i32 + 1, + location: ctd.location, + } +} + +unsafe fn convert_composite_type_stmt(cts: &bindings_raw::CompositeTypeStmt) -> protobuf::CompositeTypeStmt { + protobuf::CompositeTypeStmt { + typevar: if cts.typevar.is_null() { None } else { Some(convert_range_var(&*cts.typevar)) }, + coldeflist: convert_list_to_nodes(cts.coldeflist), + } +} + +unsafe fn convert_create_domain_stmt(cds: &bindings_raw::CreateDomainStmt) -> protobuf::CreateDomainStmt { + protobuf::CreateDomainStmt { + domainname: convert_list_to_nodes(cds.domainname), + type_name: if cds.typeName.is_null() { None } else { Some(convert_type_name(&*cds.typeName)) }, + coll_clause: convert_collate_clause_opt(cds.collClause), + constraints: convert_list_to_nodes(cds.constraints), + } +} + +unsafe fn convert_create_extension_stmt(ces: &bindings_raw::CreateExtensionStmt) -> protobuf::CreateExtensionStmt { + protobuf::CreateExtensionStmt { + extname: convert_c_string(ces.extname), + if_not_exists: ces.if_not_exists, + options: convert_list_to_nodes(ces.options), + } +} + +unsafe fn convert_create_publication_stmt(cps: &bindings_raw::CreatePublicationStmt) -> protobuf::CreatePublicationStmt { + protobuf::CreatePublicationStmt { + pubname: convert_c_string(cps.pubname), + options: convert_list_to_nodes(cps.options), + pubobjects: convert_list_to_nodes(cps.pubobjects), + for_all_tables: cps.for_all_tables, + } +} + +unsafe fn convert_alter_publication_stmt(aps: &bindings_raw::AlterPublicationStmt) -> protobuf::AlterPublicationStmt { + protobuf::AlterPublicationStmt { + pubname: convert_c_string(aps.pubname), + options: convert_list_to_nodes(aps.options), + pubobjects: convert_list_to_nodes(aps.pubobjects), + for_all_tables: aps.for_all_tables, + action: aps.action as i32 + 1, + } +} + +unsafe fn convert_create_subscription_stmt(css: &bindings_raw::CreateSubscriptionStmt) -> protobuf::CreateSubscriptionStmt { + protobuf::CreateSubscriptionStmt { + subname: convert_c_string(css.subname), + conninfo: convert_c_string(css.conninfo), + publication: convert_list_to_nodes(css.publication), + options: convert_list_to_nodes(css.options), + } +} + +unsafe fn convert_alter_subscription_stmt(ass: &bindings_raw::AlterSubscriptionStmt) -> protobuf::AlterSubscriptionStmt { + protobuf::AlterSubscriptionStmt { + kind: ass.kind as i32 + 1, + subname: convert_c_string(ass.subname), + conninfo: convert_c_string(ass.conninfo), + publication: convert_list_to_nodes(ass.publication), + options: convert_list_to_nodes(ass.options), + } +} + +unsafe fn convert_publication_obj_spec(pos: &bindings_raw::PublicationObjSpec) -> protobuf::PublicationObjSpec { + let pubtable = if pos.pubtable.is_null() { None } else { Some(Box::new(convert_publication_table(&*pos.pubtable))) }; + protobuf::PublicationObjSpec { pubobjtype: pos.pubobjtype as i32 + 1, name: convert_c_string(pos.name), pubtable, location: pos.location } +} + +unsafe fn convert_publication_table(pt: &bindings_raw::PublicationTable) -> protobuf::PublicationTable { + let relation = if pt.relation.is_null() { None } else { Some(convert_range_var(&*pt.relation)) }; + protobuf::PublicationTable { + relation, + where_clause: convert_node_boxed(pt.whereClause as *mut bindings_raw::Node), + columns: convert_list_to_nodes(pt.columns), + } +} + +unsafe fn convert_create_trig_stmt(cts: &bindings_raw::CreateTrigStmt) -> protobuf::CreateTrigStmt { + protobuf::CreateTrigStmt { + replace: cts.replace, + isconstraint: cts.isconstraint, + trigname: convert_c_string(cts.trigname), + relation: if cts.relation.is_null() { None } else { Some(convert_range_var(&*cts.relation)) }, + funcname: convert_list_to_nodes(cts.funcname), + args: convert_list_to_nodes(cts.args), + row: cts.row, + timing: cts.timing as i32, + events: cts.events as i32, + columns: convert_list_to_nodes(cts.columns), + when_clause: convert_node_boxed(cts.whenClause), + transition_rels: convert_list_to_nodes(cts.transitionRels), + deferrable: cts.deferrable, + initdeferred: cts.initdeferred, + constrrel: if cts.constrrel.is_null() { None } else { Some(convert_range_var(&*cts.constrrel)) }, + } +} + +unsafe fn convert_call_stmt(cs: &bindings_raw::CallStmt) -> protobuf::CallStmt { + protobuf::CallStmt { + funccall: if cs.funccall.is_null() { None } else { Some(Box::new(convert_func_call(&*cs.funccall))) }, + funcexpr: None, // This is a post-analysis field, not available in raw parse tree + outargs: convert_list_to_nodes(cs.outargs), + } +} + +unsafe fn convert_rule_stmt(rs: &bindings_raw::RuleStmt) -> protobuf::RuleStmt { + protobuf::RuleStmt { + relation: if rs.relation.is_null() { None } else { Some(convert_range_var(&*rs.relation)) }, + rulename: convert_c_string(rs.rulename), + where_clause: convert_node_boxed(rs.whereClause), + event: rs.event as i32 + 1, // CmdType enum + instead: rs.instead, + actions: convert_list_to_nodes(rs.actions), + replace: rs.replace, + } +} + +unsafe fn convert_grant_stmt(gs: &bindings_raw::GrantStmt) -> protobuf::GrantStmt { + protobuf::GrantStmt { + is_grant: gs.is_grant, + targtype: gs.targtype as i32 + 1, + objtype: gs.objtype as i32 + 1, + objects: convert_list_to_nodes(gs.objects), + privileges: convert_list_to_nodes(gs.privileges), + grantees: convert_list_to_nodes(gs.grantees), + grant_option: gs.grant_option, + grantor: if gs.grantor.is_null() { None } else { Some(convert_role_spec(&*gs.grantor)) }, + behavior: gs.behavior as i32 + 1, + } +} + +unsafe fn convert_grant_role_stmt(grs: &bindings_raw::GrantRoleStmt) -> protobuf::GrantRoleStmt { + protobuf::GrantRoleStmt { + granted_roles: convert_list_to_nodes(grs.granted_roles), + grantee_roles: convert_list_to_nodes(grs.grantee_roles), + is_grant: grs.is_grant, + opt: convert_list_to_nodes(grs.opt), + grantor: if grs.grantor.is_null() { None } else { Some(convert_role_spec(&*grs.grantor)) }, + behavior: grs.behavior as i32 + 1, + } +} + +unsafe fn convert_refresh_mat_view_stmt(rmvs: &bindings_raw::RefreshMatViewStmt) -> protobuf::RefreshMatViewStmt { + protobuf::RefreshMatViewStmt { + concurrent: rmvs.concurrent, + skip_data: rmvs.skipData, + relation: if rmvs.relation.is_null() { None } else { Some(convert_range_var(&*rmvs.relation)) }, + } +} + +unsafe fn convert_merge_stmt(ms: &bindings_raw::MergeStmt) -> protobuf::MergeStmt { + protobuf::MergeStmt { + relation: if ms.relation.is_null() { None } else { Some(convert_range_var(&*ms.relation)) }, + source_relation: convert_node_boxed(ms.sourceRelation), + join_condition: convert_node_boxed(ms.joinCondition), + merge_when_clauses: convert_list_to_nodes(ms.mergeWhenClauses), + returning_list: convert_list_to_nodes(ms.returningList), + with_clause: convert_with_clause_opt(ms.withClause), + } +} + +unsafe fn convert_merge_action(ma: &bindings_raw::MergeAction) -> protobuf::MergeAction { + protobuf::MergeAction { + match_kind: ma.matchKind as i32 + 1, + command_type: ma.commandType as i32 + 1, + r#override: ma.override_ as i32 + 1, + qual: convert_node_boxed(ma.qual), + target_list: convert_list_to_nodes(ma.targetList), + update_colnos: convert_list_to_nodes(ma.updateColnos), + } +} + +unsafe fn convert_merge_when_clause(mwc: &bindings_raw::MergeWhenClause) -> protobuf::MergeWhenClause { + protobuf::MergeWhenClause { + match_kind: mwc.matchKind as i32 + 1, + command_type: mwc.commandType as i32 + 1, + r#override: mwc.override_ as i32 + 1, + condition: convert_node_boxed(mwc.condition), + target_list: convert_list_to_nodes(mwc.targetList), + values: convert_list_to_nodes(mwc.values), + } +} + +unsafe fn convert_range_function(rf: &bindings_raw::RangeFunction) -> protobuf::RangeFunction { + protobuf::RangeFunction { + lateral: rf.lateral, + ordinality: rf.ordinality, + is_rowsfrom: rf.is_rowsfrom, + functions: convert_list_to_nodes(rf.functions), + alias: if rf.alias.is_null() { None } else { Some(convert_alias(&*rf.alias)) }, + coldeflist: convert_list_to_nodes(rf.coldeflist), + } +} + +unsafe fn convert_access_priv(ap: &bindings_raw::AccessPriv) -> protobuf::AccessPriv { + protobuf::AccessPriv { priv_name: convert_c_string(ap.priv_name), cols: convert_list_to_nodes(ap.cols) } +} + +// ============================================================================ +// Utility Functions +// ============================================================================ + +/// Converts a C string pointer to a Rust String. +unsafe fn convert_c_string(ptr: *const c_char) -> std::string::String { + if ptr.is_null() { + std::string::String::new() + } else { + CStr::from_ptr(ptr).to_string_lossy().to_string() + } +} + +// ============================================================================ +// New Node Conversions (matching raw_deparse.rs) +// ============================================================================ + +unsafe fn convert_bit_string(bs: &bindings_raw::BitString) -> protobuf::BitString { + protobuf::BitString { bsval: convert_c_string(bs.bsval) } +} + +unsafe fn convert_boolean_test(bt: &bindings_raw::BooleanTest) -> protobuf::BooleanTest { + protobuf::BooleanTest { + xpr: None, + arg: convert_node_boxed(bt.arg as *mut bindings_raw::Node), + booltesttype: bt.booltesttype as i32 + 1, + location: bt.location, + } +} + +unsafe fn convert_create_range_stmt(crs: &bindings_raw::CreateRangeStmt) -> protobuf::CreateRangeStmt { + protobuf::CreateRangeStmt { type_name: convert_list_to_nodes(crs.typeName), params: convert_list_to_nodes(crs.params) } +} + +unsafe fn convert_alter_enum_stmt(aes: &bindings_raw::AlterEnumStmt) -> protobuf::AlterEnumStmt { + protobuf::AlterEnumStmt { + type_name: convert_list_to_nodes(aes.typeName), + old_val: convert_c_string(aes.oldVal), + new_val: convert_c_string(aes.newVal), + new_val_neighbor: convert_c_string(aes.newValNeighbor), + new_val_is_after: aes.newValIsAfter, + skip_if_new_val_exists: aes.skipIfNewValExists, + } +} + +unsafe fn convert_close_portal_stmt(cps: &bindings_raw::ClosePortalStmt) -> protobuf::ClosePortalStmt { + protobuf::ClosePortalStmt { portalname: convert_c_string(cps.portalname) } +} + +unsafe fn convert_fetch_stmt(fs: &bindings_raw::FetchStmt) -> protobuf::FetchStmt { + protobuf::FetchStmt { + direction: fs.direction as i32 + 1, + how_many: fs.howMany as i64, + portalname: convert_c_string(fs.portalname), + ismove: fs.ismove, + } +} + +unsafe fn convert_declare_cursor_stmt(dcs: &bindings_raw::DeclareCursorStmt) -> protobuf::DeclareCursorStmt { + protobuf::DeclareCursorStmt { portalname: convert_c_string(dcs.portalname), options: dcs.options, query: convert_node_boxed(dcs.query) } +} + +unsafe fn convert_define_stmt(ds: &bindings_raw::DefineStmt) -> protobuf::DefineStmt { + protobuf::DefineStmt { + kind: ds.kind as i32 + 1, + oldstyle: ds.oldstyle, + defnames: convert_list_to_nodes(ds.defnames), + args: convert_list_to_nodes(ds.args), + definition: convert_list_to_nodes(ds.definition), + if_not_exists: ds.if_not_exists, + replace: ds.replace, + } +} + +unsafe fn convert_comment_stmt(cs: &bindings_raw::CommentStmt) -> protobuf::CommentStmt { + protobuf::CommentStmt { objtype: cs.objtype as i32 + 1, object: convert_node_boxed(cs.object), comment: convert_c_string(cs.comment) } +} + +unsafe fn convert_sec_label_stmt(sls: &bindings_raw::SecLabelStmt) -> protobuf::SecLabelStmt { + protobuf::SecLabelStmt { + objtype: sls.objtype as i32 + 1, + object: convert_node_boxed(sls.object), + provider: convert_c_string(sls.provider), + label: convert_c_string(sls.label), + } +} + +unsafe fn convert_create_role_stmt(crs: &bindings_raw::CreateRoleStmt) -> protobuf::CreateRoleStmt { + protobuf::CreateRoleStmt { stmt_type: crs.stmt_type as i32 + 1, role: convert_c_string(crs.role), options: convert_list_to_nodes(crs.options) } +} + +unsafe fn convert_alter_role_stmt(ars: &bindings_raw::AlterRoleStmt) -> protobuf::AlterRoleStmt { + protobuf::AlterRoleStmt { + role: if ars.role.is_null() { None } else { Some(convert_role_spec(&*ars.role)) }, + options: convert_list_to_nodes(ars.options), + action: ars.action, + } +} + +unsafe fn convert_alter_role_set_stmt(arss: &bindings_raw::AlterRoleSetStmt) -> protobuf::AlterRoleSetStmt { + protobuf::AlterRoleSetStmt { + role: if arss.role.is_null() { None } else { Some(convert_role_spec(&*arss.role)) }, + database: convert_c_string(arss.database), + setstmt: convert_variable_set_stmt_opt(arss.setstmt), + } +} + +unsafe fn convert_drop_role_stmt(drs: &bindings_raw::DropRoleStmt) -> protobuf::DropRoleStmt { + protobuf::DropRoleStmt { roles: convert_list_to_nodes(drs.roles), missing_ok: drs.missing_ok } +} + +unsafe fn convert_create_policy_stmt(cps: &bindings_raw::CreatePolicyStmt) -> protobuf::CreatePolicyStmt { + protobuf::CreatePolicyStmt { + policy_name: convert_c_string(cps.policy_name), + table: if cps.table.is_null() { None } else { Some(convert_range_var(&*cps.table)) }, + cmd_name: convert_c_string(cps.cmd_name), + permissive: cps.permissive, + roles: convert_list_to_nodes(cps.roles), + qual: convert_node_boxed(cps.qual), + with_check: convert_node_boxed(cps.with_check), + } +} + +unsafe fn convert_alter_policy_stmt(aps: &bindings_raw::AlterPolicyStmt) -> protobuf::AlterPolicyStmt { + protobuf::AlterPolicyStmt { + policy_name: convert_c_string(aps.policy_name), + table: if aps.table.is_null() { None } else { Some(convert_range_var(&*aps.table)) }, + roles: convert_list_to_nodes(aps.roles), + qual: convert_node_boxed(aps.qual), + with_check: convert_node_boxed(aps.with_check), + } +} + +unsafe fn convert_create_event_trig_stmt(cets: &bindings_raw::CreateEventTrigStmt) -> protobuf::CreateEventTrigStmt { + protobuf::CreateEventTrigStmt { + trigname: convert_c_string(cets.trigname), + eventname: convert_c_string(cets.eventname), + whenclause: convert_list_to_nodes(cets.whenclause), + funcname: convert_list_to_nodes(cets.funcname), + } +} + +unsafe fn convert_alter_event_trig_stmt(aets: &bindings_raw::AlterEventTrigStmt) -> protobuf::AlterEventTrigStmt { + protobuf::AlterEventTrigStmt { + trigname: convert_c_string(aets.trigname), + tgenabled: String::from_utf8_lossy(&[aets.tgenabled as u8]).to_string(), + } +} + +unsafe fn convert_create_plang_stmt(cpls: &bindings_raw::CreatePLangStmt) -> protobuf::CreatePLangStmt { + protobuf::CreatePLangStmt { + replace: cpls.replace, + plname: convert_c_string(cpls.plname), + plhandler: convert_list_to_nodes(cpls.plhandler), + plinline: convert_list_to_nodes(cpls.plinline), + plvalidator: convert_list_to_nodes(cpls.plvalidator), + pltrusted: cpls.pltrusted, + } +} + +unsafe fn convert_create_am_stmt(cas: &bindings_raw::CreateAmStmt) -> protobuf::CreateAmStmt { + protobuf::CreateAmStmt { + amname: convert_c_string(cas.amname), + handler_name: convert_list_to_nodes(cas.handler_name), + amtype: String::from_utf8_lossy(&[cas.amtype as u8]).to_string(), + } +} + +unsafe fn convert_create_op_class_stmt(cocs: &bindings_raw::CreateOpClassStmt) -> protobuf::CreateOpClassStmt { + protobuf::CreateOpClassStmt { + opclassname: convert_list_to_nodes(cocs.opclassname), + opfamilyname: convert_list_to_nodes(cocs.opfamilyname), + amname: convert_c_string(cocs.amname), + datatype: if cocs.datatype.is_null() { None } else { Some(convert_type_name(&*cocs.datatype)) }, + items: convert_list_to_nodes(cocs.items), + is_default: cocs.isDefault, + } +} + +unsafe fn convert_create_op_class_item(coci: &bindings_raw::CreateOpClassItem) -> protobuf::CreateOpClassItem { + protobuf::CreateOpClassItem { + itemtype: coci.itemtype, + name: if coci.name.is_null() { None } else { Some(convert_object_with_args(&*coci.name)) }, + number: coci.number, + order_family: convert_list_to_nodes(coci.order_family), + class_args: convert_list_to_nodes(coci.class_args), + storedtype: if coci.storedtype.is_null() { None } else { Some(convert_type_name(&*coci.storedtype)) }, + } +} + +unsafe fn convert_create_op_family_stmt(cofs: &bindings_raw::CreateOpFamilyStmt) -> protobuf::CreateOpFamilyStmt { + protobuf::CreateOpFamilyStmt { opfamilyname: convert_list_to_nodes(cofs.opfamilyname), amname: convert_c_string(cofs.amname) } +} + +unsafe fn convert_alter_op_family_stmt(aofs: &bindings_raw::AlterOpFamilyStmt) -> protobuf::AlterOpFamilyStmt { + protobuf::AlterOpFamilyStmt { + opfamilyname: convert_list_to_nodes(aofs.opfamilyname), + amname: convert_c_string(aofs.amname), + is_drop: aofs.isDrop, + items: convert_list_to_nodes(aofs.items), + } +} + +unsafe fn convert_create_fdw_stmt(cfds: &bindings_raw::CreateFdwStmt) -> protobuf::CreateFdwStmt { + protobuf::CreateFdwStmt { + fdwname: convert_c_string(cfds.fdwname), + func_options: convert_list_to_nodes(cfds.func_options), + options: convert_list_to_nodes(cfds.options), + } +} + +unsafe fn convert_alter_fdw_stmt(afds: &bindings_raw::AlterFdwStmt) -> protobuf::AlterFdwStmt { + protobuf::AlterFdwStmt { + fdwname: convert_c_string(afds.fdwname), + func_options: convert_list_to_nodes(afds.func_options), + options: convert_list_to_nodes(afds.options), + } +} + +unsafe fn convert_create_foreign_server_stmt(cfss: &bindings_raw::CreateForeignServerStmt) -> protobuf::CreateForeignServerStmt { + protobuf::CreateForeignServerStmt { + servername: convert_c_string(cfss.servername), + servertype: convert_c_string(cfss.servertype), + version: convert_c_string(cfss.version), + fdwname: convert_c_string(cfss.fdwname), + if_not_exists: cfss.if_not_exists, + options: convert_list_to_nodes(cfss.options), + } +} + +unsafe fn convert_alter_foreign_server_stmt(afss: &bindings_raw::AlterForeignServerStmt) -> protobuf::AlterForeignServerStmt { + protobuf::AlterForeignServerStmt { + servername: convert_c_string(afss.servername), + version: convert_c_string(afss.version), + options: convert_list_to_nodes(afss.options), + has_version: afss.has_version, + } +} + +unsafe fn convert_create_foreign_table_stmt(cfts: &bindings_raw::CreateForeignTableStmt) -> protobuf::CreateForeignTableStmt { + protobuf::CreateForeignTableStmt { + base_stmt: Some(convert_create_stmt(&cfts.base)), + servername: convert_c_string(cfts.servername), + options: convert_list_to_nodes(cfts.options), + } +} + +unsafe fn convert_create_user_mapping_stmt(cums: &bindings_raw::CreateUserMappingStmt) -> protobuf::CreateUserMappingStmt { + protobuf::CreateUserMappingStmt { + user: if cums.user.is_null() { None } else { Some(convert_role_spec(&*cums.user)) }, + servername: convert_c_string(cums.servername), + if_not_exists: cums.if_not_exists, + options: convert_list_to_nodes(cums.options), + } +} + +unsafe fn convert_alter_user_mapping_stmt(aums: &bindings_raw::AlterUserMappingStmt) -> protobuf::AlterUserMappingStmt { + protobuf::AlterUserMappingStmt { + user: if aums.user.is_null() { None } else { Some(convert_role_spec(&*aums.user)) }, + servername: convert_c_string(aums.servername), + options: convert_list_to_nodes(aums.options), + } +} + +unsafe fn convert_drop_user_mapping_stmt(dums: &bindings_raw::DropUserMappingStmt) -> protobuf::DropUserMappingStmt { + protobuf::DropUserMappingStmt { + user: if dums.user.is_null() { None } else { Some(convert_role_spec(&*dums.user)) }, + servername: convert_c_string(dums.servername), + missing_ok: dums.missing_ok, + } +} + +unsafe fn convert_import_foreign_schema_stmt(ifss: &bindings_raw::ImportForeignSchemaStmt) -> protobuf::ImportForeignSchemaStmt { + protobuf::ImportForeignSchemaStmt { + server_name: convert_c_string(ifss.server_name), + remote_schema: convert_c_string(ifss.remote_schema), + local_schema: convert_c_string(ifss.local_schema), + list_type: ifss.list_type as i32 + 1, + table_list: convert_list_to_nodes(ifss.table_list), + options: convert_list_to_nodes(ifss.options), + } +} + +unsafe fn convert_create_table_space_stmt(ctss: &bindings_raw::CreateTableSpaceStmt) -> protobuf::CreateTableSpaceStmt { + protobuf::CreateTableSpaceStmt { + tablespacename: convert_c_string(ctss.tablespacename), + owner: if ctss.owner.is_null() { None } else { Some(convert_role_spec(&*ctss.owner)) }, + location: convert_c_string(ctss.location), + options: convert_list_to_nodes(ctss.options), + } +} + +unsafe fn convert_drop_table_space_stmt(dtss: &bindings_raw::DropTableSpaceStmt) -> protobuf::DropTableSpaceStmt { + protobuf::DropTableSpaceStmt { tablespacename: convert_c_string(dtss.tablespacename), missing_ok: dtss.missing_ok } +} + +unsafe fn convert_alter_table_space_options_stmt(atsos: &bindings_raw::AlterTableSpaceOptionsStmt) -> protobuf::AlterTableSpaceOptionsStmt { + protobuf::AlterTableSpaceOptionsStmt { + tablespacename: convert_c_string(atsos.tablespacename), + options: convert_list_to_nodes(atsos.options), + is_reset: atsos.isReset, + } +} + +unsafe fn convert_alter_table_move_all_stmt(atmas: &bindings_raw::AlterTableMoveAllStmt) -> protobuf::AlterTableMoveAllStmt { + protobuf::AlterTableMoveAllStmt { + orig_tablespacename: convert_c_string(atmas.orig_tablespacename), + objtype: atmas.objtype as i32 + 1, + roles: convert_list_to_nodes(atmas.roles), + new_tablespacename: convert_c_string(atmas.new_tablespacename), + nowait: atmas.nowait, + } +} + +unsafe fn convert_alter_extension_stmt(aes: &bindings_raw::AlterExtensionStmt) -> protobuf::AlterExtensionStmt { + protobuf::AlterExtensionStmt { extname: convert_c_string(aes.extname), options: convert_list_to_nodes(aes.options) } +} + +unsafe fn convert_alter_extension_contents_stmt(aecs: &bindings_raw::AlterExtensionContentsStmt) -> protobuf::AlterExtensionContentsStmt { + protobuf::AlterExtensionContentsStmt { + extname: convert_c_string(aecs.extname), + action: aecs.action, + objtype: aecs.objtype as i32 + 1, + object: convert_node_boxed(aecs.object), + } +} + +unsafe fn convert_alter_domain_stmt(ads: &bindings_raw::AlterDomainStmt) -> protobuf::AlterDomainStmt { + protobuf::AlterDomainStmt { + subtype: String::from_utf8_lossy(&[ads.subtype as u8]).to_string(), + type_name: convert_list_to_nodes(ads.typeName), + name: convert_c_string(ads.name), + def: convert_node_boxed(ads.def), + behavior: ads.behavior as i32 + 1, + missing_ok: ads.missing_ok, + } +} + +unsafe fn convert_alter_function_stmt(afs: &bindings_raw::AlterFunctionStmt) -> protobuf::AlterFunctionStmt { + protobuf::AlterFunctionStmt { + objtype: afs.objtype as i32 + 1, + func: if afs.func.is_null() { None } else { Some(convert_object_with_args(&*afs.func)) }, + actions: convert_list_to_nodes(afs.actions), + } +} + +unsafe fn convert_alter_operator_stmt(aos: &bindings_raw::AlterOperatorStmt) -> protobuf::AlterOperatorStmt { + protobuf::AlterOperatorStmt { + opername: if aos.opername.is_null() { None } else { Some(convert_object_with_args(&*aos.opername)) }, + options: convert_list_to_nodes(aos.options), + } +} + +unsafe fn convert_alter_type_stmt(ats: &bindings_raw::AlterTypeStmt) -> protobuf::AlterTypeStmt { + protobuf::AlterTypeStmt { type_name: convert_list_to_nodes(ats.typeName), options: convert_list_to_nodes(ats.options) } +} + +unsafe fn convert_alter_object_schema_stmt(aoss: &bindings_raw::AlterObjectSchemaStmt) -> protobuf::AlterObjectSchemaStmt { + protobuf::AlterObjectSchemaStmt { + object_type: aoss.objectType as i32 + 1, + relation: if aoss.relation.is_null() { None } else { Some(convert_range_var(&*aoss.relation)) }, + object: convert_node_boxed(aoss.object), + newschema: convert_c_string(aoss.newschema), + missing_ok: aoss.missing_ok, + } +} + +unsafe fn convert_alter_object_depends_stmt(aods: &bindings_raw::AlterObjectDependsStmt) -> protobuf::AlterObjectDependsStmt { + protobuf::AlterObjectDependsStmt { + object_type: aods.objectType as i32 + 1, + relation: if aods.relation.is_null() { None } else { Some(convert_range_var(&*aods.relation)) }, + object: convert_node_boxed(aods.object), + extname: if aods.extname.is_null() { None } else { Some(convert_string(&*aods.extname)) }, + remove: aods.remove, + } +} + +unsafe fn convert_alter_collation_stmt(acs: &bindings_raw::AlterCollationStmt) -> protobuf::AlterCollationStmt { + protobuf::AlterCollationStmt { collname: convert_list_to_nodes(acs.collname) } +} + +unsafe fn convert_alter_default_privileges_stmt(adps: &bindings_raw::AlterDefaultPrivilegesStmt) -> protobuf::AlterDefaultPrivilegesStmt { + protobuf::AlterDefaultPrivilegesStmt { + options: convert_list_to_nodes(adps.options), + action: if adps.action.is_null() { None } else { Some(convert_grant_stmt(&*adps.action)) }, + } +} + +unsafe fn convert_create_cast_stmt(ccs: &bindings_raw::CreateCastStmt) -> protobuf::CreateCastStmt { + protobuf::CreateCastStmt { + sourcetype: if ccs.sourcetype.is_null() { None } else { Some(convert_type_name(&*ccs.sourcetype)) }, + targettype: if ccs.targettype.is_null() { None } else { Some(convert_type_name(&*ccs.targettype)) }, + func: if ccs.func.is_null() { None } else { Some(convert_object_with_args(&*ccs.func)) }, + context: ccs.context as i32 + 1, + inout: ccs.inout, + } +} + +unsafe fn convert_create_transform_stmt(cts: &bindings_raw::CreateTransformStmt) -> protobuf::CreateTransformStmt { + protobuf::CreateTransformStmt { + replace: cts.replace, + type_name: if cts.type_name.is_null() { None } else { Some(convert_type_name(&*cts.type_name)) }, + lang: convert_c_string(cts.lang), + fromsql: if cts.fromsql.is_null() { None } else { Some(convert_object_with_args(&*cts.fromsql)) }, + tosql: if cts.tosql.is_null() { None } else { Some(convert_object_with_args(&*cts.tosql)) }, + } +} + +unsafe fn convert_create_conversion_stmt(ccs: &bindings_raw::CreateConversionStmt) -> protobuf::CreateConversionStmt { + protobuf::CreateConversionStmt { + conversion_name: convert_list_to_nodes(ccs.conversion_name), + for_encoding_name: convert_c_string(ccs.for_encoding_name), + to_encoding_name: convert_c_string(ccs.to_encoding_name), + func_name: convert_list_to_nodes(ccs.func_name), + def: ccs.def, + } +} + +unsafe fn convert_alter_ts_dictionary_stmt(atds: &bindings_raw::AlterTSDictionaryStmt) -> protobuf::AlterTsDictionaryStmt { + protobuf::AlterTsDictionaryStmt { dictname: convert_list_to_nodes(atds.dictname), options: convert_list_to_nodes(atds.options) } +} + +unsafe fn convert_alter_ts_configuration_stmt(atcs: &bindings_raw::AlterTSConfigurationStmt) -> protobuf::AlterTsConfigurationStmt { + protobuf::AlterTsConfigurationStmt { + kind: atcs.kind as i32 + 1, + cfgname: convert_list_to_nodes(atcs.cfgname), + tokentype: convert_list_to_nodes(atcs.tokentype), + dicts: convert_list_to_nodes(atcs.dicts), + r#override: atcs.override_, + replace: atcs.replace, + missing_ok: atcs.missing_ok, + } +} + +unsafe fn convert_createdb_stmt(cds: &bindings_raw::CreatedbStmt) -> protobuf::CreatedbStmt { + protobuf::CreatedbStmt { dbname: convert_c_string(cds.dbname), options: convert_list_to_nodes(cds.options) } +} + +unsafe fn convert_dropdb_stmt(dds: &bindings_raw::DropdbStmt) -> protobuf::DropdbStmt { + protobuf::DropdbStmt { dbname: convert_c_string(dds.dbname), missing_ok: dds.missing_ok, options: convert_list_to_nodes(dds.options) } +} + +unsafe fn convert_alter_database_stmt(ads: &bindings_raw::AlterDatabaseStmt) -> protobuf::AlterDatabaseStmt { + protobuf::AlterDatabaseStmt { dbname: convert_c_string(ads.dbname), options: convert_list_to_nodes(ads.options) } +} + +unsafe fn convert_alter_database_set_stmt(adss: &bindings_raw::AlterDatabaseSetStmt) -> protobuf::AlterDatabaseSetStmt { + protobuf::AlterDatabaseSetStmt { dbname: convert_c_string(adss.dbname), setstmt: convert_variable_set_stmt_opt(adss.setstmt) } +} + +unsafe fn convert_alter_database_refresh_coll_stmt(adrcs: &bindings_raw::AlterDatabaseRefreshCollStmt) -> protobuf::AlterDatabaseRefreshCollStmt { + protobuf::AlterDatabaseRefreshCollStmt { dbname: convert_c_string(adrcs.dbname) } +} + +unsafe fn convert_alter_system_stmt(ass: &bindings_raw::AlterSystemStmt) -> protobuf::AlterSystemStmt { + protobuf::AlterSystemStmt { setstmt: convert_variable_set_stmt_opt(ass.setstmt) } +} + +unsafe fn convert_cluster_stmt(cs: &bindings_raw::ClusterStmt) -> protobuf::ClusterStmt { + protobuf::ClusterStmt { + relation: if cs.relation.is_null() { None } else { Some(convert_range_var(&*cs.relation)) }, + indexname: convert_c_string(cs.indexname), + params: convert_list_to_nodes(cs.params), + } +} + +unsafe fn convert_reindex_stmt(rs: &bindings_raw::ReindexStmt) -> protobuf::ReindexStmt { + protobuf::ReindexStmt { + kind: rs.kind as i32 + 1, + relation: if rs.relation.is_null() { None } else { Some(convert_range_var(&*rs.relation)) }, + name: convert_c_string(rs.name), + params: convert_list_to_nodes(rs.params), + } +} + +unsafe fn convert_constraints_set_stmt(css: &bindings_raw::ConstraintsSetStmt) -> protobuf::ConstraintsSetStmt { + protobuf::ConstraintsSetStmt { constraints: convert_list_to_nodes(css.constraints), deferred: css.deferred } +} + +unsafe fn convert_load_stmt(ls: &bindings_raw::LoadStmt) -> protobuf::LoadStmt { + protobuf::LoadStmt { filename: convert_c_string(ls.filename) } +} + +unsafe fn convert_drop_owned_stmt(dos: &bindings_raw::DropOwnedStmt) -> protobuf::DropOwnedStmt { + protobuf::DropOwnedStmt { roles: convert_list_to_nodes(dos.roles), behavior: dos.behavior as i32 + 1 } +} + +unsafe fn convert_reassign_owned_stmt(ros: &bindings_raw::ReassignOwnedStmt) -> protobuf::ReassignOwnedStmt { + protobuf::ReassignOwnedStmt { + roles: convert_list_to_nodes(ros.roles), + newrole: if ros.newrole.is_null() { None } else { Some(convert_role_spec(&*ros.newrole)) }, + } +} + +unsafe fn convert_drop_subscription_stmt(dss: &bindings_raw::DropSubscriptionStmt) -> protobuf::DropSubscriptionStmt { + protobuf::DropSubscriptionStmt { subname: convert_c_string(dss.subname), missing_ok: dss.missing_ok, behavior: dss.behavior as i32 + 1 } +} + +unsafe fn convert_table_func(tf: &bindings_raw::TableFunc) -> protobuf::TableFunc { + protobuf::TableFunc { + functype: tf.functype as i32, + ns_uris: convert_list_to_nodes(tf.ns_uris), + ns_names: convert_list_to_nodes(tf.ns_names), + docexpr: convert_node_boxed(tf.docexpr), + rowexpr: convert_node_boxed(tf.rowexpr), + colnames: convert_list_to_nodes(tf.colnames), + coltypes: convert_list_to_nodes(tf.coltypes), + coltypmods: convert_list_to_nodes(tf.coltypmods), + colcollations: convert_list_to_nodes(tf.colcollations), + colexprs: convert_list_to_nodes(tf.colexprs), + coldefexprs: convert_list_to_nodes(tf.coldefexprs), + colvalexprs: convert_list_to_nodes(tf.colvalexprs), + passingvalexprs: convert_list_to_nodes(tf.passingvalexprs), + notnulls: vec![], // Bitmapset conversion not yet supported + plan: convert_node_boxed(tf.plan), + ordinalitycol: tf.ordinalitycol, + location: tf.location, + } +} + +unsafe fn convert_into_clause_node(ic: &bindings_raw::IntoClause) -> protobuf::IntoClause { + protobuf::IntoClause { + rel: if ic.rel.is_null() { None } else { Some(convert_range_var(&*ic.rel)) }, + col_names: convert_list_to_nodes(ic.colNames), + access_method: convert_c_string(ic.accessMethod), + options: convert_list_to_nodes(ic.options), + on_commit: ic.onCommit as i32 + 1, + table_space_name: convert_c_string(ic.tableSpaceName), + view_query: convert_node_boxed(ic.viewQuery), + skip_data: ic.skipData, + } +} + +unsafe fn convert_table_like_clause(tlc: &bindings_raw::TableLikeClause) -> protobuf::TableLikeClause { + protobuf::TableLikeClause { + relation: if tlc.relation.is_null() { None } else { Some(convert_range_var(&*tlc.relation)) }, + options: tlc.options, + relation_oid: tlc.relationOid, + } +} + +unsafe fn convert_range_table_func(rtf: &bindings_raw::RangeTableFunc) -> protobuf::RangeTableFunc { + protobuf::RangeTableFunc { + lateral: rtf.lateral, + docexpr: convert_node_boxed(rtf.docexpr), + rowexpr: convert_node_boxed(rtf.rowexpr), + namespaces: convert_list_to_nodes(rtf.namespaces), + columns: convert_list_to_nodes(rtf.columns), + alias: if rtf.alias.is_null() { None } else { Some(convert_alias(&*rtf.alias)) }, + location: rtf.location, + } +} + +unsafe fn convert_range_table_func_col(rtfc: &bindings_raw::RangeTableFuncCol) -> protobuf::RangeTableFuncCol { + protobuf::RangeTableFuncCol { + colname: convert_c_string(rtfc.colname), + type_name: if rtfc.typeName.is_null() { None } else { Some(convert_type_name(&*rtfc.typeName)) }, + for_ordinality: rtfc.for_ordinality, + is_not_null: rtfc.is_not_null, + colexpr: convert_node_boxed(rtfc.colexpr), + coldefexpr: convert_node_boxed(rtfc.coldefexpr), + location: rtfc.location, + } +} + +unsafe fn convert_range_table_sample(rts: &bindings_raw::RangeTableSample) -> protobuf::RangeTableSample { + protobuf::RangeTableSample { + relation: convert_node_boxed(rts.relation), + method: convert_list_to_nodes(rts.method), + args: convert_list_to_nodes(rts.args), + repeatable: convert_node_boxed(rts.repeatable), + location: rts.location, + } +} + +unsafe fn convert_partition_cmd(pc: &bindings_raw::PartitionCmd) -> protobuf::PartitionCmd { + protobuf::PartitionCmd { + name: if pc.name.is_null() { None } else { Some(convert_range_var(&*pc.name)) }, + bound: convert_partition_bound_spec_opt(pc.bound), + concurrent: pc.concurrent, + } +} + +unsafe fn convert_on_conflict_clause_node(occ: &bindings_raw::OnConflictClause) -> protobuf::OnConflictClause { + protobuf::OnConflictClause { + action: occ.action as i32 + 1, + infer: convert_infer_clause_opt(occ.infer), + target_list: convert_list_to_nodes(occ.targetList), + where_clause: convert_node_boxed(occ.whereClause), + location: occ.location, + } +} + +unsafe fn convert_trigger_transition(tt: &bindings_raw::TriggerTransition) -> protobuf::TriggerTransition { + protobuf::TriggerTransition { name: convert_c_string(tt.name), is_new: tt.isNew, is_table: tt.isTable } +} + +unsafe fn convert_create_stats_stmt(css: &bindings_raw::CreateStatsStmt) -> protobuf::CreateStatsStmt { + protobuf::CreateStatsStmt { + defnames: convert_list_to_nodes(css.defnames), + stat_types: convert_list_to_nodes(css.stat_types), + exprs: convert_list_to_nodes(css.exprs), + relations: convert_list_to_nodes(css.relations), + stxcomment: convert_c_string(css.stxcomment), + transformed: css.transformed, + if_not_exists: css.if_not_exists, + } +} + +unsafe fn convert_alter_stats_stmt(ass: &bindings_raw::AlterStatsStmt) -> protobuf::AlterStatsStmt { + protobuf::AlterStatsStmt { + defnames: convert_list_to_nodes(ass.defnames), + stxstattarget: convert_node_boxed(ass.stxstattarget), + missing_ok: ass.missing_ok, + } +} + +unsafe fn convert_stats_elem(se: &bindings_raw::StatsElem) -> protobuf::StatsElem { + protobuf::StatsElem { name: convert_c_string(se.name), expr: convert_node_boxed(se.expr) } +} + +unsafe fn convert_sql_value_function(svf: &bindings_raw::SQLValueFunction) -> protobuf::SqlValueFunction { + protobuf::SqlValueFunction { xpr: None, op: svf.op as i32 + 1, r#type: svf.type_, typmod: svf.typmod, location: svf.location } +} + +unsafe fn convert_xml_expr(xe: &bindings_raw::XmlExpr) -> protobuf::XmlExpr { + protobuf::XmlExpr { + xpr: None, + op: xe.op as i32 + 1, + name: convert_c_string(xe.name), + named_args: convert_list_to_nodes(xe.named_args), + arg_names: convert_list_to_nodes(xe.arg_names), + args: convert_list_to_nodes(xe.args), + xmloption: xe.xmloption as i32 + 1, + indent: xe.indent, + r#type: xe.type_, + typmod: xe.typmod, + location: xe.location, + } +} + +unsafe fn convert_xml_serialize(xs: &bindings_raw::XmlSerialize) -> protobuf::XmlSerialize { + protobuf::XmlSerialize { + xmloption: xs.xmloption as i32 + 1, + expr: convert_node_boxed(xs.expr), + type_name: if xs.typeName.is_null() { None } else { Some(convert_type_name(&*xs.typeName)) }, + indent: xs.indent, + location: xs.location, + } +} + +unsafe fn convert_named_arg_expr(nae: &bindings_raw::NamedArgExpr) -> protobuf::NamedArgExpr { + protobuf::NamedArgExpr { + xpr: None, + arg: convert_node_boxed(nae.arg as *mut bindings_raw::Node), + name: convert_c_string(nae.name), + argnumber: nae.argnumber, + location: nae.location, + } +} + +// ============================================================================ +// JSON Node Conversions +// ============================================================================ + +unsafe fn convert_json_format(jf: &bindings_raw::JsonFormat) -> protobuf::JsonFormat { + protobuf::JsonFormat { format_type: jf.format_type as i32 + 1, encoding: jf.encoding as i32 + 1, location: jf.location } +} + +unsafe fn convert_json_returning(jr: &bindings_raw::JsonReturning) -> protobuf::JsonReturning { + protobuf::JsonReturning { + format: if jr.format.is_null() { None } else { Some(convert_json_format(&*jr.format)) }, + typid: jr.typid, + typmod: jr.typmod, + } +} + +unsafe fn convert_json_value_expr(jve: &bindings_raw::JsonValueExpr) -> protobuf::JsonValueExpr { + protobuf::JsonValueExpr { + raw_expr: convert_node_boxed(jve.raw_expr as *mut bindings_raw::Node), + formatted_expr: convert_node_boxed(jve.formatted_expr as *mut bindings_raw::Node), + format: if jve.format.is_null() { None } else { Some(convert_json_format(&*jve.format)) }, + } +} + +unsafe fn convert_json_constructor_expr(jce: &bindings_raw::JsonConstructorExpr) -> protobuf::JsonConstructorExpr { + protobuf::JsonConstructorExpr { + xpr: None, + r#type: jce.type_ as i32 + 1, + args: convert_list_to_nodes(jce.args), + func: convert_node_boxed(jce.func as *mut bindings_raw::Node), + coercion: convert_node_boxed(jce.coercion as *mut bindings_raw::Node), + returning: if jce.returning.is_null() { None } else { Some(convert_json_returning(&*jce.returning)) }, + absent_on_null: jce.absent_on_null, + unique: jce.unique, + location: jce.location, + } +} + +unsafe fn convert_json_is_predicate(jip: &bindings_raw::JsonIsPredicate) -> protobuf::JsonIsPredicate { + protobuf::JsonIsPredicate { + expr: convert_node_boxed(jip.expr), + format: if jip.format.is_null() { None } else { Some(convert_json_format(&*jip.format)) }, + item_type: jip.item_type as i32 + 1, + unique_keys: jip.unique_keys, + location: jip.location, + } +} + +unsafe fn convert_json_behavior(jb: &bindings_raw::JsonBehavior) -> protobuf::JsonBehavior { + protobuf::JsonBehavior { btype: jb.btype as i32 + 1, expr: convert_node_boxed(jb.expr), coerce: jb.coerce, location: jb.location } +} + +unsafe fn convert_json_expr(je: &bindings_raw::JsonExpr) -> protobuf::JsonExpr { + protobuf::JsonExpr { + xpr: None, + op: je.op as i32 + 1, + column_name: convert_c_string(je.column_name), + formatted_expr: convert_node_boxed(je.formatted_expr as *mut bindings_raw::Node), + format: if je.format.is_null() { None } else { Some(convert_json_format(&*je.format)) }, + path_spec: convert_node_boxed(je.path_spec), + returning: if je.returning.is_null() { None } else { Some(convert_json_returning(&*je.returning)) }, + passing_names: convert_list_to_nodes(je.passing_names), + passing_values: convert_list_to_nodes(je.passing_values), + on_empty: if je.on_empty.is_null() { None } else { Some(Box::new(convert_json_behavior(&*je.on_empty))) }, + on_error: if je.on_error.is_null() { None } else { Some(Box::new(convert_json_behavior(&*je.on_error))) }, + use_io_coercion: je.use_io_coercion, + use_json_coercion: je.use_json_coercion, + wrapper: je.wrapper as i32 + 1, + omit_quotes: je.omit_quotes, + collation: je.collation, + location: je.location, + } +} + +unsafe fn convert_json_table_path(jtp: &bindings_raw::JsonTablePath) -> protobuf::JsonTablePath { + // In raw parse tree, value is not populated - only name + protobuf::JsonTablePath { name: convert_c_string(jtp.name) } +} + +unsafe fn convert_json_table_path_scan(jtps: &bindings_raw::JsonTablePathScan) -> protobuf::JsonTablePathScan { + protobuf::JsonTablePathScan { + plan: convert_node_boxed(&jtps.plan as *const bindings_raw::JsonTablePlan as *mut bindings_raw::Node), + path: if jtps.path.is_null() { None } else { Some(convert_json_table_path(&*jtps.path)) }, + error_on_error: jtps.errorOnError, + child: convert_node_boxed(jtps.child as *mut bindings_raw::Node), + col_min: jtps.colMin, + col_max: jtps.colMax, + } +} + +unsafe fn convert_json_table_sibling_join(jtsj: &bindings_raw::JsonTableSiblingJoin) -> protobuf::JsonTableSiblingJoin { + protobuf::JsonTableSiblingJoin { + plan: convert_node_boxed(&jtsj.plan as *const bindings_raw::JsonTablePlan as *mut bindings_raw::Node), + lplan: convert_node_boxed(jtsj.lplan as *mut bindings_raw::Node), + rplan: convert_node_boxed(jtsj.rplan as *mut bindings_raw::Node), + } +} + +unsafe fn convert_json_output(jo: &bindings_raw::JsonOutput) -> protobuf::JsonOutput { + protobuf::JsonOutput { + type_name: if jo.typeName.is_null() { None } else { Some(convert_type_name(&*jo.typeName)) }, + returning: if jo.returning.is_null() { None } else { Some(convert_json_returning(&*jo.returning)) }, + } +} + +unsafe fn convert_json_argument(ja: &bindings_raw::JsonArgument) -> protobuf::JsonArgument { + protobuf::JsonArgument { + val: if ja.val.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*ja.val))) }, + name: convert_c_string(ja.name), + } +} + +unsafe fn convert_json_func_expr(jfe: &bindings_raw::JsonFuncExpr) -> protobuf::JsonFuncExpr { + protobuf::JsonFuncExpr { + op: jfe.op as i32 + 1, + column_name: convert_c_string(jfe.column_name), + context_item: if jfe.context_item.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jfe.context_item))) }, + pathspec: convert_node_boxed(jfe.pathspec), + passing: convert_list_to_nodes(jfe.passing), + output: if jfe.output.is_null() { None } else { Some(convert_json_output(&*jfe.output)) }, + on_empty: if jfe.on_empty.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jfe.on_empty))) }, + on_error: if jfe.on_error.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jfe.on_error))) }, + wrapper: jfe.wrapper as i32 + 1, + quotes: jfe.quotes as i32 + 1, + location: jfe.location, + } +} + +unsafe fn convert_json_table_path_spec(jtps: &bindings_raw::JsonTablePathSpec) -> protobuf::JsonTablePathSpec { + protobuf::JsonTablePathSpec { + string: convert_node_boxed(jtps.string), + name: convert_c_string(jtps.name), + name_location: jtps.name_location, + location: jtps.location, + } +} + +unsafe fn convert_json_table(jt: &bindings_raw::JsonTable) -> protobuf::JsonTable { + protobuf::JsonTable { + context_item: if jt.context_item.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jt.context_item))) }, + pathspec: if jt.pathspec.is_null() { None } else { Some(Box::new(convert_json_table_path_spec(&*jt.pathspec))) }, + passing: convert_list_to_nodes(jt.passing), + columns: convert_list_to_nodes(jt.columns), + on_error: if jt.on_error.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jt.on_error))) }, + alias: if jt.alias.is_null() { None } else { Some(convert_alias(&*jt.alias)) }, + lateral: jt.lateral, + location: jt.location, + } +} + +unsafe fn convert_json_table_column(jtc: &bindings_raw::JsonTableColumn) -> protobuf::JsonTableColumn { + protobuf::JsonTableColumn { + coltype: jtc.coltype as i32 + 1, + name: convert_c_string(jtc.name), + type_name: if jtc.typeName.is_null() { None } else { Some(convert_type_name(&*jtc.typeName)) }, + pathspec: if jtc.pathspec.is_null() { None } else { Some(Box::new(convert_json_table_path_spec(&*jtc.pathspec))) }, + format: if jtc.format.is_null() { None } else { Some(convert_json_format(&*jtc.format)) }, + wrapper: jtc.wrapper as i32 + 1, + quotes: jtc.quotes as i32 + 1, + columns: convert_list_to_nodes(jtc.columns), + on_empty: if jtc.on_empty.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jtc.on_empty))) }, + on_error: if jtc.on_error.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jtc.on_error))) }, + location: jtc.location, + } +} + +unsafe fn convert_json_key_value(jkv: &bindings_raw::JsonKeyValue) -> protobuf::JsonKeyValue { + protobuf::JsonKeyValue { + key: convert_node_boxed(jkv.key as *mut bindings_raw::Node), + value: if jkv.value.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jkv.value))) }, + } +} + +unsafe fn convert_json_parse_expr(jpe: &bindings_raw::JsonParseExpr) -> protobuf::JsonParseExpr { + protobuf::JsonParseExpr { + expr: if jpe.expr.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jpe.expr))) }, + output: if jpe.output.is_null() { None } else { Some(convert_json_output(&*jpe.output)) }, + unique_keys: jpe.unique_keys, + location: jpe.location, + } +} + +unsafe fn convert_json_scalar_expr(jse: &bindings_raw::JsonScalarExpr) -> protobuf::JsonScalarExpr { + protobuf::JsonScalarExpr { + expr: convert_node_boxed(jse.expr as *mut bindings_raw::Node), + output: if jse.output.is_null() { None } else { Some(convert_json_output(&*jse.output)) }, + location: jse.location, + } +} + +unsafe fn convert_json_serialize_expr(jse: &bindings_raw::JsonSerializeExpr) -> protobuf::JsonSerializeExpr { + protobuf::JsonSerializeExpr { + expr: if jse.expr.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jse.expr))) }, + output: if jse.output.is_null() { None } else { Some(convert_json_output(&*jse.output)) }, + location: jse.location, + } +} + +unsafe fn convert_json_object_constructor(joc: &bindings_raw::JsonObjectConstructor) -> protobuf::JsonObjectConstructor { + protobuf::JsonObjectConstructor { + exprs: convert_list_to_nodes(joc.exprs), + output: if joc.output.is_null() { None } else { Some(convert_json_output(&*joc.output)) }, + absent_on_null: joc.absent_on_null, + unique: joc.unique, + location: joc.location, + } +} + +unsafe fn convert_json_array_constructor(jac: &bindings_raw::JsonArrayConstructor) -> protobuf::JsonArrayConstructor { + protobuf::JsonArrayConstructor { + exprs: convert_list_to_nodes(jac.exprs), + output: if jac.output.is_null() { None } else { Some(convert_json_output(&*jac.output)) }, + absent_on_null: jac.absent_on_null, + location: jac.location, + } +} + +unsafe fn convert_json_array_query_constructor(jaqc: &bindings_raw::JsonArrayQueryConstructor) -> protobuf::JsonArrayQueryConstructor { + protobuf::JsonArrayQueryConstructor { + query: convert_node_boxed(jaqc.query), + output: if jaqc.output.is_null() { None } else { Some(convert_json_output(&*jaqc.output)) }, + format: if jaqc.format.is_null() { None } else { Some(convert_json_format(&*jaqc.format)) }, + absent_on_null: jaqc.absent_on_null, + location: jaqc.location, + } +} + +unsafe fn convert_json_agg_constructor(jac: &bindings_raw::JsonAggConstructor) -> protobuf::JsonAggConstructor { + protobuf::JsonAggConstructor { + output: if jac.output.is_null() { None } else { Some(convert_json_output(&*jac.output)) }, + agg_filter: convert_node_boxed(jac.agg_filter), + agg_order: convert_list_to_nodes(jac.agg_order), + over: if jac.over.is_null() { None } else { Some(Box::new(convert_window_def(&*jac.over))) }, + location: jac.location, + } +} + +unsafe fn convert_json_object_agg(joa: &bindings_raw::JsonObjectAgg) -> protobuf::JsonObjectAgg { + protobuf::JsonObjectAgg { + constructor: if joa.constructor.is_null() { None } else { Some(Box::new(convert_json_agg_constructor(&*joa.constructor))) }, + arg: if joa.arg.is_null() { None } else { Some(Box::new(convert_json_key_value(&*joa.arg))) }, + absent_on_null: joa.absent_on_null, + unique: joa.unique, + } +} + +unsafe fn convert_json_array_agg(jaa: &bindings_raw::JsonArrayAgg) -> protobuf::JsonArrayAgg { + protobuf::JsonArrayAgg { + constructor: if jaa.constructor.is_null() { None } else { Some(Box::new(convert_json_agg_constructor(&*jaa.constructor))) }, + arg: if jaa.arg.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jaa.arg))) }, + absent_on_null: jaa.absent_on_null, + } +} + +// ============================================================================ +// Additional Helper Functions +// ============================================================================ + +unsafe fn convert_variable_set_stmt_opt(stmt: *mut bindings_raw::VariableSetStmt) -> Option { + if stmt.is_null() { + None + } else { + Some(convert_variable_set_stmt(&*stmt)) + } +} + +unsafe fn convert_infer_clause_opt(ic: *mut bindings_raw::InferClause) -> Option> { + if ic.is_null() { + None + } else { + let ic_ref = &*ic; + Some(Box::new(protobuf::InferClause { + index_elems: convert_list_to_nodes(ic_ref.indexElems), + where_clause: convert_node_boxed(ic_ref.whereClause), + conname: convert_c_string(ic_ref.conname), + location: ic_ref.location, + })) + } +} diff --git a/tests/raw_parse_tests.rs b/tests/raw_parse_tests.rs index 397500a..d1279a6 100644 --- a/tests/raw_parse_tests.rs +++ b/tests/raw_parse_tests.rs @@ -12,7 +12,7 @@ mod support; mod raw_parse; // Re-export the benchmark test at the top level -use pg_query::{deparse, deparse_raw, parse, parse_raw}; +use pg_query::{deparse, deparse_raw, parse, parse_raw, parse_raw_iter}; use std::time::{Duration, Instant}; /// Benchmark comparing parse_raw vs parse performance @@ -87,12 +87,13 @@ fn benchmark_parse_raw_vs_parse() { // Warm up for _ in 0..10 { + let _ = parse_raw_iter(query).unwrap(); let _ = parse_raw(query).unwrap(); let _ = parse(query).unwrap(); } // Run for a fixed duration to get stable measurements - let target_duration = Duration::from_secs(2); + let target_duration = Duration::from_secs(5); // Benchmark parse_raw let mut raw_iterations = 0u64; @@ -106,6 +107,18 @@ fn benchmark_parse_raw_vs_parse() { let raw_elapsed = raw_start.elapsed(); let raw_ns_per_iter = raw_elapsed.as_nanos() as f64 / raw_iterations as f64; + // Benchmark parse_raw_iter + let mut raw_iter_iterations = 0u64; + let raw_start = Instant::now(); + while raw_start.elapsed() < target_duration { + for _ in 0..100 { + let _ = parse_raw_iter(query).unwrap(); + raw_iter_iterations += 1; + } + } + let raw_iter_elapsed = raw_start.elapsed(); + let raw_iter_ns_per_iter = raw_iter_elapsed.as_nanos() as f64 / raw_iter_iterations as f64; + // Benchmark parse (protobuf) let mut proto_iterations = 0u64; let proto_start = Instant::now(); @@ -123,7 +136,13 @@ fn benchmark_parse_raw_vs_parse() { let time_saved_ns = proto_ns_per_iter - raw_ns_per_iter; let time_saved_us = time_saved_ns / 1000.0; + // Calculate speedup and time saved + let speedup_iter = raw_ns_per_iter / raw_iter_ns_per_iter; + let time_saved_ns_iter = raw_ns_per_iter - raw_iter_ns_per_iter; + let time_saved_us_iter = time_saved_ns_iter / 1000.0; + // Calculate throughput (queries per second) + let raw_iter_qps = 1_000_000_000.0 / raw_iter_ns_per_iter; let raw_qps = 1_000_000_000.0 / raw_ns_per_iter; let proto_qps = 1_000_000_000.0 / proto_ns_per_iter; @@ -140,17 +159,24 @@ fn benchmark_parse_raw_vs_parse() { println!("│ Iterations: {:>10} │", raw_iterations); println!("│ Total time: {:>10.2?} │", raw_elapsed); println!("│ Per iteration: {:>10.2} μs │", raw_ns_per_iter / 1000.0); - println!("│ Throughput: {:>10.0} queries/sec │", raw_qps); + println!("│ Throughput: {:>10.0} queries/sec │", raw_qps); + println!("├─────────────────────────────────────────────────────────┤"); + println!("│ parse_raw_iter (direct C struct reading): │"); + println!("│ Iterations: {:>10} │", raw_iter_iterations); + println!("│ Total time: {:>10.2?} │", raw_iter_elapsed); + println!("│ Per iteration: {:>10.2} μs │", raw_iter_ns_per_iter / 1000.0); + println!("│ Throughput: {:>10.0} queries/sec │", raw_iter_qps); println!("├─────────────────────────────────────────────────────────┤"); println!("│ parse (protobuf serialization): │"); println!("│ Iterations: {:>10} │", proto_iterations); println!("│ Total time: {:>10.2?} │", proto_elapsed); println!("│ Per iteration: {:>10.2} μs │", proto_ns_per_iter / 1000.0); - println!("│ Throughput: {:>10.0} queries/sec │", proto_qps); + println!("│ Throughput: {:>10.0} queries/sec │", proto_qps); println!("├─────────────────────────────────────────────────────────┤"); println!("│ COMPARISON │"); - println!("│ Speedup: {:>10.2}x faster │", speedup); - println!("│ Time saved: {:>10.2} μs per parse │", time_saved_us); + println!("│ Speedup: {:>10.2}x faster │", speedup); + println!("│ Speedup iter: {:>10.2}x faster │", speedup_iter); + println!("│ Time saved: {:>10.2} μs per parse │", time_saved_us); println!("│ Extra queries: {:>10.0} more queries/sec │", raw_qps - proto_qps); println!("└─────────────────────────────────────────────────────────┘"); println!(); From 20d36187e6efdc35564b633c0db6113d7344f3e2 Mon Sep 17 00:00:00 2001 From: meskill <8974488+meskill@users.noreply.github.com> Date: Sun, 8 Feb 2026 19:40:08 +0000 Subject: [PATCH 2/4] copy tests --- docs/migration_plan.md | 343 +++++++++++ src/lib.rs | 2 + src/raw_deparse_iter.rs | 6 + tests/raw_parse_iter/basic.rs | 277 +++++++++ tests/raw_parse_iter/ddl.rs | 423 ++++++++++++++ tests/raw_parse_iter/dml.rs | 500 ++++++++++++++++ tests/raw_parse_iter/expressions.rs | 494 ++++++++++++++++ tests/raw_parse_iter/mod.rs | 57 ++ tests/raw_parse_iter/select.rs | 862 ++++++++++++++++++++++++++++ tests/raw_parse_iter/statements.rs | 450 +++++++++++++++ tests/raw_parse_iter_tests.rs | 15 + 11 files changed, 3429 insertions(+) create mode 100644 docs/migration_plan.md create mode 100644 src/raw_deparse_iter.rs create mode 100644 tests/raw_parse_iter/basic.rs create mode 100644 tests/raw_parse_iter/ddl.rs create mode 100644 tests/raw_parse_iter/dml.rs create mode 100644 tests/raw_parse_iter/expressions.rs create mode 100644 tests/raw_parse_iter/mod.rs create mode 100644 tests/raw_parse_iter/select.rs create mode 100644 tests/raw_parse_iter/statements.rs create mode 100644 tests/raw_parse_iter_tests.rs diff --git a/docs/migration_plan.md b/docs/migration_plan.md new file mode 100644 index 0000000..675ff26 --- /dev/null +++ b/docs/migration_plan.md @@ -0,0 +1,343 @@ +# Migration Plan: Iterative `raw_parse_iter.rs` — Test-Driven Approach + +## Strategy + +Instead of migrating by node-type groups, we migrate **test by test** — running a single +test from simple to complex, fixing whatever breaks, and moving on only after it passes. + +All tests live in `tests/raw_parse_iter/` and mirror `tests/raw_parse/` exactly, except +they call `parse_raw_iter` instead of `parse_raw`. Every test compares `parse_raw_iter` +output against `parse` (protobuf) output for structural equality. + +### How to run a single test + +```sh +cargo test --test raw_parse_iter_tests raw_parse_iter::basic::it_parses_simple_select -- --nocapture +``` + +### Workflow for each test + +1. Run the test +2. If it **passes** → move to the next test +3. If it **fails** → read the error, identify the missing/broken node conversion, + fix it in `raw_parse_iter.rs` (or `Processor`), re-run, repeat +4. After the fix passes, run all previously-passing tests as regression: + `cargo test --test raw_parse_iter_tests -- --nocapture` +5. Commit + +--- + +## Test Execution Order + +Tests are ordered from simplest SQL (fewest node types involved) to most complex +(deeply nested, many node types combined). Within each file, tests are listed in +the order they should be attempted. + +### Step 1 — `basic` (fundamentals) + +These tests exercise the core path: `RawStmt` → `SelectStmt` → `ResTarget` → `ColumnRef` / `AConst`. + +| # | Test name | What it exercises | +|---|-----------|-------------------| +| 1 | `basic::it_parses_simple_select` | `SELECT 1` — SelectStmt + ResTarget + AConst(int) | +| 2 | `basic::it_matches_parse_for_simple_select` | Same, with deparse check | +| 3 | `basic::it_handles_parse_errors` | Error path (no node conversion) | +| 4 | `basic::it_handles_empty_queries` | Empty parse tree | +| 5 | `basic::it_matches_parse_for_select_from_table` | `SELECT * FROM users` — adds RangeVar | +| 6 | `basic::it_deparses_parse_raw_iter_result` | Deparse round-trip | +| 7 | `basic::it_parses_multiple_statements` | Multiple RawStmt entries | +| 8 | `basic::it_returns_tables_like_parse` | JOIN + WHERE — adds JoinExpr, A_Expr, ColumnRef | +| 9 | `basic::it_returns_functions_like_parse` | FuncCall, `count(*)`, `sum()` | +| 10 | `basic::it_returns_statement_types_like_parse` | Mixed SELECT/INSERT/UPDATE/DELETE | +| 11 | `basic::it_deparse_raw_simple_select` | Deparse from parse_raw_iter result | +| 12 | `basic::it_deparse_raw_select_from_table` | Deparse with RangeVar | +| 13 | `basic::it_deparse_raw_complex_select` | Deparse with WHERE + ORDER BY | +| 14 | `basic::it_deparse_raw_insert` | InsertStmt deparse | +| 15 | `basic::it_deparse_raw_update` | UpdateStmt deparse | +| 16 | `basic::it_deparse_raw_delete` | DeleteStmt deparse | +| 17 | `basic::it_deparse_raw_multiple_statements` | Multi-statement deparse | +| 18 | `basic::it_deparse_raw_method_on_parse_result` | Method call variant | +| 19 | `basic::it_deparse_raw_method_on_protobuf_parse_result` | Method on protobuf struct | +| 20 | `basic::it_deparse_raw_method_on_node_ref` | NodeRef method | +| 21 | `basic::it_deparse_raw_matches_deparse` | Cross-check deparse vs deparse_raw | + +### Step 2 — `expressions` (literals & operators) + +Exercises leaf nodes and simple expression trees. + +| # | Test name | What it exercises | +|---|-----------|-------------------| +| 22 | `expressions::it_extracts_integer_const` | AConst(Ival) | +| 23 | `expressions::it_extracts_string_const` | AConst(Sval) | +| 24 | `expressions::it_extracts_float_const` | AConst(Fval) | +| 25 | `expressions::it_extracts_boolean_true_const` | AConst(Boolval) | +| 26 | `expressions::it_extracts_boolean_false_const` | AConst(Boolval) | +| 27 | `expressions::it_extracts_null_const` | AConst(isnull) | +| 28 | `expressions::it_extracts_negative_integer_const` | Unary minus → A_Expr or AConst | +| 29 | `expressions::it_parses_floats_with_leading_dot` | AConst(Fval) edge case | +| 30 | `expressions::it_extracts_bit_string_const` | AConst(Bsval) | +| 31 | `expressions::it_extracts_hex_bit_string_const` | AConst(Bsval) | +| 32 | `expressions::it_parses_null_tests` | NullTest node | +| 33 | `expressions::it_parses_is_distinct_from` | A_Expr(DISTINCT) | +| 34 | `expressions::it_parses_between` | A_Expr(BETWEEN) | +| 35 | `expressions::it_parses_like_ilike` | A_Expr(LIKE/ILIKE) + BoolExpr(OR) | +| 36 | `expressions::it_parses_similar_to` | A_Expr(SIMILAR TO) | +| 37 | `expressions::it_parses_complex_boolean` | BoolExpr(AND/OR/NOT) nesting | +| 38 | `expressions::it_parses_coalesce` | CoalesceExpr | +| 39 | `expressions::it_parses_nullif` | NullIfExpr (maps to OpExpr or special) | +| 40 | `expressions::it_parses_greatest_least` | MinMaxExpr | +| 41 | `expressions::it_parses_pg_type_cast` | TypeCast + TypeName | +| 42 | `expressions::it_parses_sql_cast` | TypeCast via CAST() | +| 43 | `expressions::it_parses_array_cast` | TypeCast with array type | +| 44 | `expressions::it_parses_array_constructor` | ArrayExpr | +| 45 | `expressions::it_parses_array_subscript` | A_Indirection + A_Indices | +| 46 | `expressions::it_parses_array_slice` | A_Indirection + A_Indices (slice) | +| 47 | `expressions::it_parses_unnest` | FuncCall | +| 48 | `expressions::it_parses_json_operators` | A_Expr with JSON ops | +| 49 | `expressions::it_parses_jsonb_containment` | A_Expr with @> | +| 50 | `expressions::it_parses_positional_params` | ParamRef | +| 51 | `expressions::it_parses_params_in_insert` | ParamRef inside InsertStmt | +| 52 | `expressions::it_parses_current_timestamp` | SQLValueFunction | +| 53 | `expressions::it_parses_sql_value_functions` | All SQLValueFunction variants | +| 54 | `expressions::it_parses_real_world_query` | Combined: JOIN + BETWEEN + A_Expr + ORDER BY | +| 55 | `expressions::it_parses_bit_strings_hex` | Full query with X'...' literal | + +### Step 3 — `select` (complex queries) + +Progressively harder SELECT features. Each test tends to add one new node type. + +| # | Test name | Key new node types | +|---|-----------|-------------------| +| 56 | `select::it_parses_join` | JoinExpr (INNER) | +| 57 | `select::it_parses_left_join` | JoinExpr (LEFT) | +| 58 | `select::it_parses_right_join` | JoinExpr (RIGHT) | +| 59 | `select::it_parses_full_outer_join` | JoinExpr (FULL) | +| 60 | `select::it_parses_cross_join` | JoinExpr (CROSS) | +| 61 | `select::it_parses_natural_join` | JoinExpr (NATURAL) | +| 62 | `select::it_parses_join_using` | JoinExpr + USING list | +| 63 | `select::it_parses_multiple_joins` | Nested JoinExpr | +| 64 | `select::it_parses_lateral_join` | RangeSubselect (LATERAL) | +| 65 | `select::it_parses_union` | SelectStmt with set_op | +| 66 | `select::it_parses_intersect` | INTERSECT | +| 67 | `select::it_parses_except` | EXCEPT | +| 68 | `select::it_parses_union_all` | UNION ALL | +| 69 | `select::it_parses_compound_set_operations` | Nested set ops | +| 70 | `select::it_parses_subquery` | SubLink (IN) | +| 71 | `select::it_parses_correlated_subquery` | SubLink (EXISTS) | +| 72 | `select::it_parses_not_exists_subquery` | BoolExpr(NOT) + SubLink | +| 73 | `select::it_parses_scalar_subquery` | SubLink (scalar) in target | +| 74 | `select::it_parses_derived_table` | RangeSubselect | +| 75 | `select::it_parses_any_subquery` | SubLink (ANY) | +| 76 | `select::it_parses_all_subquery` | SubLink (ALL) | +| 77 | `select::it_parses_case_expression` | CaseExpr + CaseWhen | +| 78 | `select::it_parses_aggregates` | FuncCall (aggregate) | +| 79 | `select::it_parses_window_function` | WindowFunc, WindowDef | +| 80 | `select::it_parses_window_function_partition` | PARTITION BY | +| 81 | `select::it_parses_window_function_frame` | Frame clause (ROWS) | +| 82 | `select::it_parses_named_window` | WINDOW clause | +| 83 | `select::it_parses_lag_lead` | LAG/LEAD window funcs | +| 84 | `select::it_parses_cte` | WithClause + CommonTableExpr | +| 85 | `select::it_parses_multiple_ctes` | Multiple CTEs | +| 86 | `select::it_parses_recursive_cte` | RECURSIVE + UNION ALL | +| 87 | `select::it_parses_cte_with_columns` | CTE column list | +| 88 | `select::it_parses_cte_materialized` | MATERIALIZED hint | +| 89 | `select::it_parses_cte_search_breadth_first` | SEARCH BREADTH FIRST | +| 90 | `select::it_parses_cte_search_depth_first` | SEARCH DEPTH FIRST | +| 91 | `select::it_parses_cte_cycle` | CYCLE detection | +| 92 | `select::it_parses_cte_search_and_cycle` | Combined SEARCH + CYCLE | +| 93 | `select::it_parses_group_by_rollup` | GroupingSet (ROLLUP) | +| 94 | `select::it_parses_group_by_cube` | GroupingSet (CUBE) | +| 95 | `select::it_parses_grouping_sets` | GroupingSet (SETS) | +| 96 | `select::it_parses_distinct_on` | DISTINCT ON | +| 97 | `select::it_parses_order_by_nulls` | SortBy (NULLS LAST) | +| 98 | `select::it_parses_fetch_first` | FETCH FIRST | +| 99 | `select::it_parses_offset_fetch` | OFFSET + FETCH | +| 100 | `select::it_parses_for_update` | LockingClause | +| 101 | `select::it_parses_for_share` | LockingClause (SHARE) | +| 102 | `select::it_parses_for_update_nowait` | LockingClause (NOWAIT) | +| 103 | `select::it_parses_for_update_skip_locked` | LockingClause (SKIP LOCKED) | +| 104 | `select::it_parses_complex_select` | All basic features combined | +| 105 | `select::it_parses_analytics_query` | Window + interval + aggregate | +| 106 | `select::it_parses_hierarchy_query` | Recursive CTE + ARRAY + path | +| 107 | `select::it_parses_complex_report_query` | CTE + JOIN + NULLIF + window | +| 108 | `select::it_parses_mixed_subqueries_and_ctes` | CTE + scalar sub + EXISTS + ORDER BY sub | +| 109 | `select::it_parses_column_with_collate` | CollateClause | +| 110 | `select::it_parses_partition_by_range` | PartitionSpec + PartitionElem | +| 111 | `select::it_parses_partition_by_list` | PARTITION BY LIST | +| 112 | `select::it_parses_partition_by_hash` | PARTITION BY HASH | +| 113 | `select::it_parses_partition_for_values_range` | PartitionBoundSpec (range) | +| 114 | `select::it_parses_partition_for_values_list` | PartitionBoundSpec (list) | +| 115 | `select::it_parses_partition_for_values_hash` | PartitionBoundSpec (hash) | +| 116 | `select::it_parses_partition_default` | PartitionBoundSpec (default) | + +### Step 4 — `dml` (INSERT / UPDATE / DELETE) + +| # | Test name | Key new node types | +|---|-----------|-------------------| +| 117 | `dml::it_parses_insert` | InsertStmt basic | +| 118 | `dml::it_parses_update` | UpdateStmt basic | +| 119 | `dml::it_parses_delete` | DeleteStmt basic | +| 120 | `dml::it_parses_insert_returning` | RETURNING clause | +| 121 | `dml::it_parses_insert_multiple_rows` | Multiple VALUES tuples | +| 122 | `dml::it_parses_insert_default_values` | SetToDefault node | +| 123 | `dml::it_parses_insert_select` | INSERT ... SELECT | +| 124 | `dml::it_parses_insert_select_complex` | INSERT ... SELECT with aggregates | +| 125 | `dml::it_parses_insert_on_conflict_do_nothing` | OnConflictClause (DO NOTHING) | +| 126 | `dml::it_parses_insert_on_conflict` | OnConflictClause (DO UPDATE) + InferClause | +| 127 | `dml::it_parses_insert_on_conflict_with_where` | ON CONFLICT with WHERE | +| 128 | `dml::it_parses_insert_on_conflict_multiple_columns` | Multi-column conflict | +| 129 | `dml::it_parses_insert_returning_multiple` | RETURNING multiple cols | +| 130 | `dml::it_parses_insert_with_subquery_value` | SubLink in VALUES | +| 131 | `dml::it_parses_insert_overriding` | OVERRIDING SYSTEM VALUE | +| 132 | `dml::it_parses_insert_with_cte` | INSERT with CTE | +| 133 | `dml::it_parses_update_multiple_columns` | Multiple SET clauses | +| 134 | `dml::it_parses_update_returning` | UPDATE RETURNING | +| 135 | `dml::it_parses_update_with_subquery_set` | SubLink in SET | +| 136 | `dml::it_parses_update_from` | FROM clause in UPDATE | +| 137 | `dml::it_parses_update_from_multiple_tables` | FROM + JOIN in UPDATE | +| 138 | `dml::it_parses_update_with_cte` | UPDATE with CTE | +| 139 | `dml::it_parses_update_complex_where` | Complex WHERE + NOT EXISTS | +| 140 | `dml::it_parses_update_row_comparison` | MultiAssignRef | +| 141 | `dml::it_parses_update_with_case` | CaseExpr in SET | +| 142 | `dml::it_parses_update_array` | FuncCall (array_append) | +| 143 | `dml::it_parses_delete_returning` | DELETE RETURNING | +| 144 | `dml::it_parses_delete_with_subquery` | SubLink in DELETE WHERE | +| 145 | `dml::it_parses_delete_using` | USING clause | +| 146 | `dml::it_parses_delete_using_multiple_tables` | USING + multiple tables | +| 147 | `dml::it_parses_delete_with_cte` | DELETE with CTE | +| 148 | `dml::it_parses_delete_with_exists` | NOT EXISTS in DELETE | +| 149 | `dml::it_parses_delete_complex_conditions` | Complex boolean WHERE | +| 150 | `dml::it_parses_delete_only` | DELETE FROM ONLY | +| 151 | `dml::it_parses_insert_cte_returning` | DML CTE (INSERT in CTE) | +| 152 | `dml::it_parses_update_cte_returning` | DML CTE (UPDATE in CTE) | +| 153 | `dml::it_parses_delete_cte_returning` | DML CTE (DELETE in CTE) | +| 154 | `dml::it_parses_chained_dml_ctes` | Multiple DML CTEs chained | + +### Step 5 — `ddl` (CREATE / ALTER / DROP) + +| # | Test name | Key new node types | +|---|-----------|-------------------| +| 155 | `ddl::it_parses_create_table` | CreateStmt, ColumnDef, TypeName | +| 156 | `ddl::it_parses_drop_table` | DropStmt | +| 157 | `ddl::it_parses_create_index` | IndexStmt | +| 158 | `ddl::it_parses_create_table_with_constraints` | Constraint nodes | +| 159 | `ddl::it_parses_create_table_as` | CreateTableAsStmt | +| 160 | `ddl::it_parses_create_view` | ViewStmt | +| 161 | `ddl::it_parses_create_materialized_view` | CreateTableAsStmt (matview) | +| 162 | `ddl::it_parses_alter_table_add_column` | AlterTableStmt + AlterTableCmd | +| 163 | `ddl::it_parses_alter_table_drop_column` | AlterTableCmd (DROP) | +| 164 | `ddl::it_parses_alter_table_add_constraint` | Constraint (FK) | +| 165 | `ddl::it_parses_alter_table_rename` | RenameStmt | +| 166 | `ddl::it_parses_alter_table_rename_column` | RenameStmt (column) | +| 167 | `ddl::it_parses_alter_owner` | AlterOwnerStmt | +| 168 | `ddl::it_parses_create_index_expression` | IndexElem with expr | +| 169 | `ddl::it_parses_partial_unique_index` | IndexStmt with WHERE | +| 170 | `ddl::it_parses_create_index_concurrently` | IndexStmt (CONCURRENTLY) | +| 171 | `ddl::it_parses_truncate` | TruncateStmt | +| 172 | `ddl::it_parses_create_sequence` | CreateSeqStmt | +| 173 | `ddl::it_parses_create_sequence_with_options` | DefElem options | +| 174 | `ddl::it_parses_create_sequence_if_not_exists` | IF NOT EXISTS | +| 175 | `ddl::it_parses_alter_sequence` | AlterSeqStmt | +| 176 | `ddl::it_parses_create_domain` | CreateDomainStmt | +| 177 | `ddl::it_parses_create_domain_not_null` | Domain + NOT NULL | +| 178 | `ddl::it_parses_create_domain_default` | Domain + DEFAULT | +| 179 | `ddl::it_parses_create_composite_type` | CompositeTypeStmt | +| 180 | `ddl::it_parses_create_enum_type` | CreateEnumStmt | +| 181 | `ddl::it_parses_create_extension` | CreateExtensionStmt | +| 182 | `ddl::it_parses_create_extension_with_schema` | WITH SCHEMA option | +| 183 | `ddl::it_parses_create_publication` | CreatePublicationStmt | +| 184 | `ddl::it_parses_create_publication_for_tables` | FOR TABLE | +| 185 | `ddl::it_parses_alter_publication` | AlterPublicationStmt | +| 186 | `ddl::it_parses_create_subscription` | CreateSubscriptionStmt | +| 187 | `ddl::it_parses_alter_subscription` | AlterSubscriptionStmt | +| 188 | `ddl::it_parses_create_trigger` | CreateTrigStmt | +| 189 | `ddl::it_parses_create_trigger_after_update` | Trigger with WHEN | +| 190 | `ddl::it_parses_create_constraint_trigger` | Constraint trigger | + +### Step 6 — `statements` (utility / session) + +| # | Test name | Key new node types | +|---|-----------|-------------------| +| 191 | `statements::it_parses_explain` | ExplainStmt | +| 192 | `statements::it_parses_explain_analyze` | ExplainStmt with options | +| 193 | `statements::it_parses_copy` | CopyStmt | +| 194 | `statements::it_parses_prepare` | PrepareStmt | +| 195 | `statements::it_parses_execute` | ExecuteStmt | +| 196 | `statements::it_parses_deallocate` | DeallocateStmt | +| 197 | `statements::it_parses_begin` | TransactionStmt | +| 198 | `statements::it_parses_begin_with_options` | Transaction options | +| 199 | `statements::it_parses_commit` | TransactionStmt (COMMIT) | +| 200 | `statements::it_parses_rollback` | TransactionStmt (ROLLBACK) | +| 201 | `statements::it_parses_start_transaction` | START TRANSACTION | +| 202 | `statements::it_parses_savepoint` | TransactionStmt (SAVEPOINT) | +| 203 | `statements::it_parses_rollback_to_savepoint` | ROLLBACK TO | +| 204 | `statements::it_parses_release_savepoint` | RELEASE | +| 205 | `statements::it_parses_vacuum` | VacuumStmt | +| 206 | `statements::it_parses_vacuum_table` | VacuumStmt + relation | +| 207 | `statements::it_parses_vacuum_analyze` | VACUUM ANALYZE | +| 208 | `statements::it_parses_vacuum_full` | VACUUM FULL | +| 209 | `statements::it_parses_analyze` | VacuumStmt (ANALYZE) | +| 210 | `statements::it_parses_analyze_table` | ANALYZE + relation | +| 211 | `statements::it_parses_analyze_columns` | ANALYZE + column list | +| 212 | `statements::it_parses_set` | VariableSetStmt | +| 213 | `statements::it_parses_set_equals` | SET with = | +| 214 | `statements::it_parses_set_local` | SET LOCAL | +| 215 | `statements::it_parses_set_session` | SET SESSION | +| 216 | `statements::it_parses_reset` | VariableSetStmt (RESET) | +| 217 | `statements::it_parses_reset_all` | RESET ALL | +| 218 | `statements::it_parses_show` | VariableShowStmt | +| 219 | `statements::it_parses_show_all` | SHOW ALL | +| 220 | `statements::it_parses_listen` | ListenStmt | +| 221 | `statements::it_parses_notify` | NotifyStmt | +| 222 | `statements::it_parses_notify_with_payload` | NotifyStmt + payload | +| 223 | `statements::it_parses_unlisten` | UnlistenStmt | +| 224 | `statements::it_parses_unlisten_all` | UNLISTEN * | +| 225 | `statements::it_parses_discard_all` | DiscardStmt | +| 226 | `statements::it_parses_discard_plans` | DISCARD PLANS | +| 227 | `statements::it_parses_discard_sequences` | DISCARD SEQUENCES | +| 228 | `statements::it_parses_discard_temp` | DISCARD TEMP | +| 229 | `statements::it_parses_lock_table` | LockStmt | +| 230 | `statements::it_parses_lock_multiple_tables` | LockStmt multi-table | +| 231 | `statements::it_parses_do_statement` | DoStmt | +| 232 | `statements::it_parses_do_with_language` | DoStmt + language | + +--- + +## Progress Tracking + +Mark each test as it passes: + +``` +[ ] 1. basic::it_parses_simple_select +[ ] 2. basic::it_matches_parse_for_simple_select +... +``` + +Update this section as you go. When all 232 tests pass, the migration is functionally complete. + +--- + +## After All Tests Pass + +1. **Run full regression**: `cargo test --test raw_parse_iter_tests` +2. **Run acceptance suite** against `parse_raw_iter` (port `parse_raw_acceptance.rs`) +3. **Run benchmarks**: `cargo test --test raw_parse_iter_tests benchmark -- --nocapture` (if added) +4. **Remove recursive fallback**: once all node types are handled iteratively in `process()`, + remove `convert_node()`, `convert_node_boxed()`, standalone `convert_*` functions, + and the `stacker` dependency +5. **Swap entrypoint**: make `parse_raw` call the iterative implementation internally + +## General Rules + +- **Queue and collect must be symmetric**: every node queued produces exactly one result. + Every `fetch_list_results` call must match a corresponding `queue_list_nodes` call with + the same list pointer. Every `single_result` must match a `queue_node`. +- **Null pointers produce no result**: `queue_node` with null is skipped in `process()`, + `single_result` checks the original pointer to decide whether to pop. +- **Null lists produce no results**: `queue_list_nodes` and `fetch_list_results` both + early-return on null. +- **Push order**: `queue_collect` first (bottom of stack), then children left-to-right. + Children are processed right-to-left (LIFO). Results accumulate in reverse. + `fetch_results` drains from the end and reverses. +- **One test at a time**: run, fix, verify, commit. The recursive fallback ensures + everything keeps working during incremental migration. \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 0a7d16a..d816e58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,7 @@ mod parse_result; pub mod protobuf; mod query; mod raw_deparse; +mod raw_deparse_iter; mod raw_fingerprint; mod raw_parse; mod raw_parse_iter; @@ -68,6 +69,7 @@ pub use raw_deparse::{deparse_raw, deparse_raw_with_stack}; pub use raw_fingerprint::fingerprint_raw; pub use raw_parse::{parse_raw, parse_raw_with_stack}; pub use raw_parse_iter::parse_raw_iter; +pub use raw_deparse_iter::deparse_raw_iter; pub use raw_scan::scan_raw; pub use summary::*; pub use summary_result::*; diff --git a/src/raw_deparse_iter.rs b/src/raw_deparse_iter.rs new file mode 100644 index 0000000..909dfb5 --- /dev/null +++ b/src/raw_deparse_iter.rs @@ -0,0 +1,6 @@ +use crate::protobuf; +use crate::{Error, Result}; + +pub fn deparse_raw_iter(protobuf: &protobuf::ParseResult) -> Result { + todo!() +} diff --git a/tests/raw_parse_iter/basic.rs b/tests/raw_parse_iter/basic.rs new file mode 100644 index 0000000..f06b961 --- /dev/null +++ b/tests/raw_parse_iter/basic.rs @@ -0,0 +1,277 @@ +//! Basic parsing tests for parse_raw_iter. +//! +//! These tests verify fundamental parsing behavior including: +//! - Simple SELECT queries +//! - Error handling +//! - Multiple statements +//! - Empty queries + +use super::*; + +/// Test that parse_raw_iter results can be deparsed back to SQL +#[test] +fn it_deparses_parse_raw_iter_result() { + let query = "SELECT * FROM users"; + let result = parse_raw_iter(query).unwrap(); + + let deparsed = result.deparse().unwrap(); + assert_eq!(deparsed, query); +} + +/// Test that parse_raw_iter successfully parses a simple SELECT query +#[test] +fn it_parses_simple_select() { + let query = "SELECT 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf.stmts.len(), 1); + assert_eq!(raw_result.protobuf, proto_result.protobuf); + // Verify deparse produces original query + assert_eq!(deparse_raw(&raw_result.protobuf).unwrap(), query); +} + +/// Test that parse_raw_iter handles syntax errors +#[test] +fn it_handles_parse_errors() { + let query = "SELECT * FORM users"; + let raw_error = parse_raw_iter(query).err().unwrap(); + let proto_error = parse(query).err().unwrap(); + + assert!(matches!(raw_error, Error::Parse(_))); + assert!(matches!(proto_error, Error::Parse(_))); +} + +/// Test that parse_raw_iter and parse produce equivalent results for simple SELECT +#[test] +fn it_matches_parse_for_simple_select() { + let query = "SELECT 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw(&raw_result.protobuf).unwrap(), query); +} + +/// Test that parse_raw_iter and parse produce equivalent results for SELECT with table +#[test] +fn it_matches_parse_for_select_from_table() { + let query = "SELECT * FROM users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw(&raw_result.protobuf).unwrap(), query); + + let mut raw_tables = raw_result.tables(); + let mut proto_tables = proto_result.tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["users"]); +} + +/// Test that parse_raw_iter handles empty queries (comments only) +#[test] +fn it_handles_empty_queries() { + let query = "-- just a comment"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf.stmts.len(), 0); + assert_eq!(raw_result.protobuf, proto_result.protobuf); + // Empty queries deparse to empty string (comments are stripped) + assert_eq!(deparse_raw(&raw_result.protobuf).unwrap(), ""); +} + +/// Test that parse_raw_iter parses multiple statements +#[test] +fn it_parses_multiple_statements() { + let query = "SELECT 1; SELECT 2; SELECT 3"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf.stmts.len(), 3); + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw(&raw_result.protobuf).unwrap(), query); +} + +/// Test that tables() returns the same results for both parsers +#[test] +fn it_returns_tables_like_parse() { + let query = "SELECT u.*, o.* FROM users u JOIN orders o ON u.id = o.user_id WHERE o.status = 'active'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw(&raw_result.protobuf).unwrap(), query); + + let mut raw_tables = raw_result.tables(); + let mut proto_tables = proto_result.tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["orders", "users"]); +} + +/// Test that functions() returns the same results for both parsers +#[test] +fn it_returns_functions_like_parse() { + let query = "SELECT count(*), sum(amount) FROM orders"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw(&raw_result.protobuf).unwrap(), query); + + let mut raw_funcs = raw_result.functions(); + let mut proto_funcs = proto_result.functions(); + raw_funcs.sort(); + proto_funcs.sort(); + assert_eq!(raw_funcs, proto_funcs); + assert_eq!(raw_funcs, vec!["count", "sum"]); +} + +/// Test that statement_types() returns the same results for both parsers +#[test] +fn it_returns_statement_types_like_parse() { + let query = "SELECT 1; INSERT INTO t VALUES (1); UPDATE t SET x = 1; DELETE FROM t"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw(&raw_result.protobuf).unwrap(), query); + + assert_eq!(raw_result.statement_types(), proto_result.statement_types()); + assert_eq!(raw_result.statement_types(), vec!["SelectStmt", "InsertStmt", "UpdateStmt", "DeleteStmt"]); +} + +// ============================================================================ +// deparse_raw tests +// ============================================================================ + +/// Test that deparse_raw successfully roundtrips a simple SELECT +#[test] +fn it_deparse_raw_simple_select() { + let query = "SELECT 1"; + let result = parse_raw_iter(query).unwrap(); + let deparsed = deparse_raw(&result.protobuf).unwrap(); + assert_eq!(deparsed, query); +} + +/// Test that deparse_raw successfully roundtrips SELECT FROM table +#[test] +fn it_deparse_raw_select_from_table() { + let query = "SELECT * FROM users"; + let result = parse_raw_iter(query).unwrap(); + let deparsed = deparse_raw(&result.protobuf).unwrap(); + assert_eq!(deparsed, query); +} + +/// Test that deparse_raw handles complex queries +#[test] +fn it_deparse_raw_complex_select() { + let query = "SELECT u.id, u.name FROM users u WHERE u.active = true ORDER BY u.name"; + let result = parse_raw_iter(query).unwrap(); + let deparsed = deparse_raw(&result.protobuf).unwrap(); + assert_eq!(deparsed, query); +} + +/// Test that deparse_raw handles INSERT statements +#[test] +fn it_deparse_raw_insert() { + let query = "INSERT INTO users (name, email) VALUES ('John', 'john@example.com')"; + let result = parse_raw_iter(query).unwrap(); + let deparsed = deparse_raw(&result.protobuf).unwrap(); + assert_eq!(deparsed, query); +} + +/// Test that deparse_raw handles UPDATE statements +#[test] +fn it_deparse_raw_update() { + let query = "UPDATE users SET name = 'Jane' WHERE id = 1"; + let result = parse_raw_iter(query).unwrap(); + let deparsed = deparse_raw(&result.protobuf).unwrap(); + assert_eq!(deparsed, query); +} + +/// Test that deparse_raw handles DELETE statements +#[test] +fn it_deparse_raw_delete() { + let query = "DELETE FROM users WHERE id = 1"; + let result = parse_raw_iter(query).unwrap(); + let deparsed = deparse_raw(&result.protobuf).unwrap(); + assert_eq!(deparsed, query); +} + +/// Test that deparse_raw handles multiple statements +#[test] +fn it_deparse_raw_multiple_statements() { + let query = "SELECT 1; SELECT 2; SELECT 3"; + let result = parse_raw_iter(query).unwrap(); + let deparsed = deparse_raw(&result.protobuf).unwrap(); + assert_eq!(deparsed, query); +} + +// ============================================================================ +// deparse_raw method tests (on structs) +// ============================================================================ + +/// Test that ParseResult.deparse_raw() method works +#[test] +fn it_deparse_raw_method_on_parse_result() { + let query = "SELECT * FROM users WHERE id = 1"; + let result = parse_raw_iter(query).unwrap(); + // Test the method on ParseResult + let deparsed = result.deparse_raw().unwrap(); + assert_eq!(deparsed, query); +} + +/// Test that protobuf::ParseResult.deparse_raw() method works +#[test] +fn it_deparse_raw_method_on_protobuf_parse_result() { + let query = "SELECT a, b, c FROM table1 JOIN table2 ON table1.id = table2.id"; + let result = parse_raw_iter(query).unwrap(); + // Test the method on protobuf::ParseResult + let deparsed = result.protobuf.deparse_raw().unwrap(); + assert_eq!(deparsed, query); +} + +/// Test that NodeRef.deparse_raw() method works +#[test] +fn it_deparse_raw_method_on_node_ref() { + let query = "SELECT * FROM users"; + let result = parse_raw_iter(query).unwrap(); + // Get the first node (SelectStmt) + let nodes = result.protobuf.nodes(); + assert!(!nodes.is_empty()); + // Find the SelectStmt node + for (node, _depth, _context, _has_filter) in nodes { + if let pg_query::NodeRef::SelectStmt(_) = node { + let deparsed = node.deparse_raw().unwrap(); + assert_eq!(deparsed, query); + return; + } + } + panic!("SelectStmt node not found"); +} + +/// Test that deparse_raw method produces same result as deparse method +#[test] +fn it_deparse_raw_matches_deparse() { + let queries = vec![ + "SELECT 1", + "SELECT * FROM users", + "INSERT INTO t (a) VALUES (1)", + "UPDATE t SET a = 1 WHERE b = 2", + "DELETE FROM t WHERE id = 1", + "SELECT a, b FROM t1 JOIN t2 ON t1.id = t2.id WHERE t1.x > 5 ORDER BY a", + ]; + + for query in queries { + let result = parse_raw_iter(query).unwrap(); + let deparse_result = result.deparse().unwrap(); + let deparse_raw_result = result.deparse_raw().unwrap(); + assert_eq!(deparse_result, deparse_raw_result); + } +} diff --git a/tests/raw_parse_iter/ddl.rs b/tests/raw_parse_iter/ddl.rs new file mode 100644 index 0000000..12d2fb4 --- /dev/null +++ b/tests/raw_parse_iter/ddl.rs @@ -0,0 +1,423 @@ +//! DDL statement tests (CREATE, ALTER, DROP, etc.). +//! +//! These tests verify parse_raw_iter_iter correctly handles data definition language statements. + +use super::*; + +// ============================================================================ +// Basic DDL tests +// ============================================================================ + +/// Test parsing CREATE TABLE +#[test] +fn it_parses_create_table() { + let query = "CREATE TABLE test (id int, name text)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(raw_result.statement_types(), proto_result.statement_types()); + assert_eq!(raw_result.statement_types(), vec!["CreateStmt"]); +} + +/// Test parsing DROP TABLE +#[test] +fn it_parses_drop_table() { + let query = "DROP TABLE users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let mut raw_tables = raw_result.ddl_tables(); + let mut proto_tables = proto_result.ddl_tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["users"]); +} + +/// Test parsing CREATE INDEX +#[test] +fn it_parses_create_index() { + let query = "CREATE INDEX idx_users_name ON users (name)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(raw_result.statement_types(), proto_result.statement_types()); + assert_eq!(raw_result.statement_types(), vec!["IndexStmt"]); +} + +/// Test CREATE TABLE with constraints +#[test] +fn it_parses_create_table_with_constraints() { + let query = "CREATE TABLE orders ( + id SERIAL PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id), + amount DECIMAL(10, 2) CHECK (amount > 0), + status TEXT DEFAULT 'pending', + created_at TIMESTAMP DEFAULT NOW(), + UNIQUE (user_id, created_at) + )"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE TABLE AS +#[test] +fn it_parses_create_table_as() { + let query = "CREATE TABLE active_users AS SELECT * FROM users WHERE active = true"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE VIEW +#[test] +fn it_parses_create_view() { + let query = "CREATE VIEW active_users AS SELECT id, name FROM users WHERE active = true"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE MATERIALIZED VIEW +#[test] +fn it_parses_create_materialized_view() { + let query = "CREATE MATERIALIZED VIEW monthly_sales AS SELECT date_trunc('month', created_at) AS month, SUM(amount) FROM orders GROUP BY 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// ALTER TABLE tests +// ============================================================================ + +/// Test ALTER TABLE ADD COLUMN +#[test] +fn it_parses_alter_table_add_column() { + let query = "ALTER TABLE users ADD COLUMN email TEXT NOT NULL"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ALTER TABLE DROP COLUMN +#[test] +fn it_parses_alter_table_drop_column() { + let query = "ALTER TABLE users DROP COLUMN deprecated_field"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ALTER TABLE ADD CONSTRAINT +#[test] +fn it_parses_alter_table_add_constraint() { + let query = "ALTER TABLE orders ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ALTER TABLE RENAME +#[test] +fn it_parses_alter_table_rename() { + let query = "ALTER TABLE users RENAME TO customers"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ALTER TABLE RENAME COLUMN +#[test] +fn it_parses_alter_table_rename_column() { + let query = "ALTER TABLE users RENAME COLUMN name TO full_name"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ALTER TABLE OWNER +#[test] +fn it_parses_alter_owner() { + let query = "ALTER TABLE users OWNER TO postgres"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// INDEX tests +// ============================================================================ + +/// Test CREATE INDEX with expression +#[test] +fn it_parses_create_index_expression() { + let query = "CREATE INDEX idx_lower_email ON users (lower(email))"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE UNIQUE INDEX with WHERE +#[test] +fn it_parses_partial_unique_index() { + let query = "CREATE UNIQUE INDEX idx_active_email ON users (email) WHERE active = true"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE INDEX CONCURRENTLY +#[test] +fn it_parses_create_index_concurrently() { + let query = "CREATE INDEX CONCURRENTLY idx_name ON users (name)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// TRUNCATE test +// ============================================================================ + +/// Test TRUNCATE +#[test] +fn it_parses_truncate() { + let query = "TRUNCATE TABLE logs, audit_logs RESTART IDENTITY CASCADE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// Sequence tests +// ============================================================================ + +/// Test CREATE SEQUENCE +#[test] +fn it_parses_create_sequence() { + let query = "CREATE SEQUENCE my_seq"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE SEQUENCE with options +#[test] +fn it_parses_create_sequence_with_options() { + let query = "CREATE SEQUENCE my_seq START WITH 100 INCREMENT BY 10 MINVALUE 1 MAXVALUE 1000 CYCLE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE SEQUENCE IF NOT EXISTS +#[test] +fn it_parses_create_sequence_if_not_exists() { + let query = "CREATE SEQUENCE IF NOT EXISTS my_seq"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ALTER SEQUENCE +#[test] +fn it_parses_alter_sequence() { + let query = "ALTER SEQUENCE my_seq RESTART WITH 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// Domain tests +// ============================================================================ + +/// Test CREATE DOMAIN +#[test] +fn it_parses_create_domain() { + let query = "CREATE DOMAIN positive_int AS INTEGER CHECK (VALUE > 0)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE DOMAIN with NOT NULL +#[test] +fn it_parses_create_domain_not_null() { + let query = "CREATE DOMAIN non_empty_text AS TEXT NOT NULL CHECK (VALUE <> '')"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE DOMAIN with DEFAULT +#[test] +fn it_parses_create_domain_default() { + let query = "CREATE DOMAIN my_text AS TEXT DEFAULT 'unknown'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// Type tests +// ============================================================================ + +/// Test CREATE TYPE AS composite +#[test] +fn it_parses_create_composite_type() { + let query = "CREATE TYPE address AS (street TEXT, city TEXT, zip TEXT)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE TYPE AS ENUM +#[test] +fn it_parses_create_enum_type() { + let query = "CREATE TYPE status AS ENUM ('pending', 'approved', 'rejected')"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// Extension tests +// ============================================================================ + +/// Test CREATE EXTENSION +#[test] +fn it_parses_create_extension() { + let query = "CREATE EXTENSION IF NOT EXISTS pg_stat_statements"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE EXTENSION with schema +#[test] +fn it_parses_create_extension_with_schema() { + let query = "CREATE EXTENSION hstore WITH SCHEMA public"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// Publication and Subscription tests +// ============================================================================ + +/// Test CREATE PUBLICATION +#[test] +fn it_parses_create_publication() { + let query = "CREATE PUBLICATION my_pub FOR ALL TABLES"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE PUBLICATION for specific tables +#[test] +fn it_parses_create_publication_for_tables() { + let query = "CREATE PUBLICATION my_pub FOR TABLE users, orders"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ALTER PUBLICATION +#[test] +fn it_parses_alter_publication() { + let query = "ALTER PUBLICATION my_pub ADD TABLE products"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE SUBSCRIPTION +#[test] +fn it_parses_create_subscription() { + let query = "CREATE SUBSCRIPTION my_sub CONNECTION 'host=localhost dbname=mydb' PUBLICATION my_pub"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ALTER SUBSCRIPTION +#[test] +fn it_parses_alter_subscription() { + let query = "ALTER SUBSCRIPTION my_sub DISABLE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// Trigger tests +// ============================================================================ + +/// Test CREATE TRIGGER +#[test] +fn it_parses_create_trigger() { + let query = "CREATE TRIGGER my_trigger BEFORE INSERT ON users FOR EACH ROW EXECUTE FUNCTION my_func()"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE TRIGGER AFTER UPDATE +#[test] +fn it_parses_create_trigger_after_update() { + let query = "CREATE TRIGGER audit_trigger AFTER UPDATE ON users FOR EACH ROW WHEN (OLD.* IS DISTINCT FROM NEW.*) EXECUTE FUNCTION audit_log()"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CREATE CONSTRAINT TRIGGER +#[test] +fn it_parses_create_constraint_trigger() { + let query = "CREATE CONSTRAINT TRIGGER check_balance AFTER INSERT OR UPDATE ON accounts DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION check_balance()"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} diff --git a/tests/raw_parse_iter/dml.rs b/tests/raw_parse_iter/dml.rs new file mode 100644 index 0000000..d0bad70 --- /dev/null +++ b/tests/raw_parse_iter/dml.rs @@ -0,0 +1,500 @@ +//! DML statement tests (INSERT, UPDATE, DELETE). +//! +//! These tests verify parse_raw_iter_iter correctly handles data manipulation language statements. + +use super::*; + +// ============================================================================ +// Basic DML tests +// ============================================================================ + +/// Test parsing INSERT statement +#[test] +fn it_parses_insert() { + let query = "INSERT INTO users (name) VALUES ('test')"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); + + let mut raw_tables = raw_result.dml_tables(); + let mut proto_tables = proto_result.dml_tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["users"]); +} + +/// Test parsing UPDATE statement +#[test] +fn it_parses_update() { + let query = "UPDATE users SET name = 'bob' WHERE id = 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); + + let mut raw_tables = raw_result.dml_tables(); + let mut proto_tables = proto_result.dml_tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["users"]); +} + +/// Test parsing DELETE statement +#[test] +fn it_parses_delete() { + let query = "DELETE FROM users WHERE id = 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); + + let mut raw_tables = raw_result.dml_tables(); + let mut proto_tables = proto_result.dml_tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["users"]); +} + +// ============================================================================ +// INSERT variations +// ============================================================================ + +/// Test parsing INSERT with ON CONFLICT +#[test] +fn it_parses_insert_on_conflict() { + let query = "INSERT INTO users (id, name) VALUES (1, 'test') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + // PostgreSQL's deparser normalizes EXCLUDED to lowercase, so compare case-insensitively + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap().to_lowercase(), query.to_lowercase()); + + let raw_tables = raw_result.dml_tables(); + let proto_tables = proto_result.dml_tables(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["users"]); +} + +/// Test parsing INSERT with RETURNING +#[test] +fn it_parses_insert_returning() { + let query = "INSERT INTO users (name) VALUES ('test') RETURNING id"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); +} + +/// Test INSERT with multiple tuples +#[test] +fn it_parses_insert_multiple_rows() { + let query = "INSERT INTO users (name, email, age) VALUES ('Alice', 'alice@example.com', 25), ('Bob', 'bob@example.com', 30), ('Charlie', 'charlie@example.com', 35)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); +} + +/// Test INSERT ... SELECT +#[test] +fn it_parses_insert_select() { + let query = "INSERT INTO archived_users (id, name, email) SELECT id, name, email FROM users WHERE deleted_at IS NOT NULL"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test INSERT ... SELECT with complex query +#[test] +fn it_parses_insert_select_complex() { + let query = "INSERT INTO monthly_stats (month, user_count, order_count, total_revenue) + SELECT date_trunc('month', created_at) AS month, + COUNT(DISTINCT user_id), + COUNT(*), + SUM(amount) + FROM orders + WHERE created_at >= '2023-01-01' + GROUP BY date_trunc('month', created_at)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test INSERT with CTE +#[test] +fn it_parses_insert_with_cte() { + let query = "WITH new_data AS ( + SELECT name, email FROM temp_imports WHERE valid = true + ) + INSERT INTO users (name, email) SELECT name, email FROM new_data"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test INSERT with DEFAULT values +#[test] +fn it_parses_insert_default_values() { + let query = "INSERT INTO users (name, created_at) VALUES ('test', DEFAULT)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test INSERT with ON CONFLICT DO NOTHING +#[test] +fn it_parses_insert_on_conflict_do_nothing() { + let query = "INSERT INTO users (id, name) VALUES (1, 'test') ON CONFLICT (id) DO NOTHING"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test INSERT with ON CONFLICT with WHERE clause +#[test] +fn it_parses_insert_on_conflict_with_where() { + let query = "INSERT INTO users (id, name, updated_at) VALUES (1, 'test', NOW()) + ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, updated_at = EXCLUDED.updated_at + WHERE users.updated_at < EXCLUDED.updated_at"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test INSERT with multiple columns in ON CONFLICT +#[test] +fn it_parses_insert_on_conflict_multiple_columns() { + let query = "INSERT INTO user_settings (user_id, key, value) VALUES (1, 'theme', 'dark') + ON CONFLICT (user_id, key) DO UPDATE SET value = EXCLUDED.value"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test INSERT with RETURNING multiple columns +#[test] +fn it_parses_insert_returning_multiple() { + let query = "INSERT INTO users (name, email) VALUES ('test', 'test@example.com') RETURNING id, created_at, name"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test INSERT with subquery in VALUES +#[test] +fn it_parses_insert_with_subquery_value() { + let query = "INSERT INTO orders (user_id, total) VALUES ((SELECT id FROM users WHERE email = 'test@example.com'), 100.00)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test INSERT with OVERRIDING +#[test] +fn it_parses_insert_overriding() { + let query = "INSERT INTO users (id, name) OVERRIDING SYSTEM VALUE VALUES (1, 'test')"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// Complex UPDATE tests +// ============================================================================ + +/// Test UPDATE with multiple columns +#[test] +fn it_parses_update_multiple_columns() { + let query = "UPDATE users SET name = 'new_name', email = 'new@example.com', updated_at = NOW() WHERE id = 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE with subquery in SET +#[test] +fn it_parses_update_with_subquery_set() { + let query = "UPDATE orders SET total = (SELECT SUM(price * quantity) FROM order_items WHERE order_id = orders.id) WHERE id = 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE with FROM clause (PostgreSQL-specific JOIN update) +#[test] +fn it_parses_update_from() { + let query = "UPDATE orders o SET status = 'shipped', shipped_at = NOW() + FROM shipments s + WHERE o.id = s.order_id AND s.status = 'delivered'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE with FROM and multiple tables +#[test] +fn it_parses_update_from_multiple_tables() { + let query = "UPDATE products p SET price = p.price * (1 + d.percentage / 100) + FROM discounts d + JOIN categories c ON d.category_id = c.id + WHERE p.category_id = c.id AND d.active = true"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE with CTE +#[test] +fn it_parses_update_with_cte() { + let query = "WITH inactive_users AS ( + SELECT id FROM users WHERE last_login < NOW() - INTERVAL '1 year' + ) + UPDATE users SET status = 'inactive' WHERE id IN (SELECT id FROM inactive_users)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE with RETURNING +#[test] +fn it_parses_update_returning() { + let query = "UPDATE users SET name = 'updated' WHERE id = 1 RETURNING id, name, updated_at"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE with complex WHERE clause +#[test] +fn it_parses_update_complex_where() { + let query = "UPDATE orders SET status = 'cancelled' + WHERE created_at < NOW() - INTERVAL '30 days' + AND status = 'pending' + AND NOT EXISTS (SELECT 1 FROM payments WHERE payments.order_id = orders.id)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE with row value comparison +#[test] +fn it_parses_update_row_comparison() { + let query = "UPDATE users SET (name, email) = ('new_name', 'new@example.com') WHERE id = 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE with CASE expression +#[test] +fn it_parses_update_with_case() { + let query = "UPDATE products SET price = CASE + WHEN category = 'electronics' THEN price * 0.9 + WHEN category = 'clothing' THEN price * 0.8 + ELSE price * 0.95 + END + WHERE sale_active = true"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE with array operations +#[test] +fn it_parses_update_array() { + let query = "UPDATE users SET tags = array_append(tags, 'verified') WHERE id = 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// Complex DELETE tests +// ============================================================================ + +/// Test DELETE with subquery in WHERE +#[test] +fn it_parses_delete_with_subquery() { + let query = "DELETE FROM orders WHERE user_id IN (SELECT id FROM users WHERE status = 'deleted')"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DELETE with USING clause (PostgreSQL-specific JOIN delete) +#[test] +fn it_parses_delete_using() { + let query = "DELETE FROM order_items oi USING orders o + WHERE oi.order_id = o.id AND o.status = 'cancelled'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DELETE with USING and multiple tables +#[test] +fn it_parses_delete_using_multiple_tables() { + let query = "DELETE FROM notifications n + USING users u, user_settings s + WHERE n.user_id = u.id + AND u.id = s.user_id + AND s.key = 'email_notifications' + AND s.value = 'false'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DELETE with CTE +#[test] +fn it_parses_delete_with_cte() { + let query = "WITH old_orders AS ( + SELECT id FROM orders WHERE created_at < NOW() - INTERVAL '5 years' + ) + DELETE FROM order_items WHERE order_id IN (SELECT id FROM old_orders)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DELETE with RETURNING +#[test] +fn it_parses_delete_returning() { + let query = "DELETE FROM users WHERE id = 1 RETURNING id, name, email"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DELETE with EXISTS +#[test] +fn it_parses_delete_with_exists() { + let query = "DELETE FROM products p + WHERE NOT EXISTS (SELECT 1 FROM order_items oi WHERE oi.product_id = p.id) + AND p.created_at < NOW() - INTERVAL '1 year'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DELETE with complex boolean conditions +#[test] +fn it_parses_delete_complex_conditions() { + let query = "DELETE FROM logs + WHERE (level = 'debug' AND created_at < NOW() - INTERVAL '7 days') + OR (level = 'info' AND created_at < NOW() - INTERVAL '30 days') + OR (level IN ('warning', 'error') AND created_at < NOW() - INTERVAL '90 days')"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DELETE with ONLY +#[test] +fn it_parses_delete_only() { + let query = "DELETE FROM ONLY parent_table WHERE id = 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// Combined DML with CTEs +// ============================================================================ + +/// Test data modification CTE (INSERT in CTE) +#[test] +fn it_parses_insert_cte_returning() { + let query = "WITH inserted AS ( + INSERT INTO users (name, email) VALUES ('test', 'test@example.com') RETURNING id, name + ) + SELECT * FROM inserted"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UPDATE in CTE with final SELECT +#[test] +fn it_parses_update_cte_returning() { + let query = "WITH updated AS ( + UPDATE users SET last_login = NOW() WHERE id = 1 RETURNING id, name, last_login + ) + SELECT * FROM updated"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DELETE in CTE with final SELECT +#[test] +fn it_parses_delete_cte_returning() { + let query = "WITH deleted AS ( + DELETE FROM expired_sessions WHERE expires_at < NOW() RETURNING user_id + ) + SELECT COUNT(*) FROM deleted"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test chained CTEs with multiple DML operations +#[test] +fn it_parses_chained_dml_ctes() { + let query = "WITH + to_archive AS ( + SELECT id FROM users WHERE last_login < NOW() - INTERVAL '2 years' + ), + archived AS ( + INSERT INTO archived_users SELECT * FROM users WHERE id IN (SELECT id FROM to_archive) RETURNING id + ), + deleted AS ( + DELETE FROM users WHERE id IN (SELECT id FROM archived) RETURNING id + ) + SELECT COUNT(*) as archived_count FROM deleted"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} diff --git a/tests/raw_parse_iter/expressions.rs b/tests/raw_parse_iter/expressions.rs new file mode 100644 index 0000000..f0f9b25 --- /dev/null +++ b/tests/raw_parse_iter/expressions.rs @@ -0,0 +1,494 @@ +//! Expression tests: literals, type casts, arrays, JSON, operators. +//! +//! These tests verify parse_raw_iter_iter correctly handles various expressions. + +use super::*; + +// ============================================================================ +// Literal value tests +// ============================================================================ + +/// Test parsing float with leading dot +#[test] +fn it_parses_floats_with_leading_dot() { + let query = "SELECT .1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + // Verify the float value + let raw_const = get_first_const(&raw_result.protobuf).expect("should have const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("should have const"); + assert_eq!(raw_const, proto_const); +} + +/// Test parsing bit string in hex notation +#[test] +fn it_parses_bit_strings_hex() { + let query = "SELECT X'EFFF'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + // Verify the bit string value + let raw_const = get_first_const(&raw_result.protobuf).expect("should have const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("should have const"); + assert_eq!(raw_const, proto_const); +} + +/// Test parsing real-world query with multiple joins +#[test] +fn it_parses_real_world_query() { + let query = " + SELECT memory_total_bytes, memory_free_bytes, memory_pagecache_bytes, + (memory_swap_total_bytes - memory_swap_free_bytes) AS swap + FROM snapshots s JOIN system_snapshots ON (snapshot_id = s.id) + WHERE s.database_id = 1 AND s.collected_at BETWEEN '2021-01-01' AND '2021-12-31' + ORDER BY collected_at"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + // Verify tables + let mut raw_tables = raw_result.tables(); + let mut proto_tables = proto_result.tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["snapshots", "system_snapshots"]); +} +// ============================================================================ +// A_Const value extraction tests +// ============================================================================ + +/// Test that parse_raw extracts integer values correctly and matches parse +#[test] +fn it_extracts_integer_const() { + let query = "SELECT 42"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let raw_const = get_first_const(&raw_result.protobuf).expect("Should have A_Const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("Should have A_Const"); + + assert_eq!(raw_const, proto_const); + assert!(!raw_const.isnull); + match &raw_const.val { + Some(a_const::Val::Ival(int_val)) => { + assert_eq!(int_val.ival, 42); + } + other => panic!("Expected Ival, got {:?}", other), + } +} + +/// Test that parse_raw extracts negative integer values correctly +#[test] +fn it_extracts_negative_integer_const() { + let query = "SELECT -123"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test that parse_raw extracts string values correctly and matches parse +#[test] +fn it_extracts_string_const() { + let query = "SELECT 'hello world'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let raw_const = get_first_const(&raw_result.protobuf).expect("Should have A_Const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("Should have A_Const"); + + assert_eq!(raw_const, proto_const); + assert!(!raw_const.isnull); + match &raw_const.val { + Some(a_const::Val::Sval(str_val)) => { + assert_eq!(str_val.sval, "hello world"); + } + other => panic!("Expected Sval, got {:?}", other), + } +} + +/// Test that parse_raw extracts float values correctly and matches parse +#[test] +fn it_extracts_float_const() { + let query = "SELECT 3.14159"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let raw_const = get_first_const(&raw_result.protobuf).expect("Should have A_Const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("Should have A_Const"); + + assert_eq!(raw_const, proto_const); + assert!(!raw_const.isnull); + match &raw_const.val { + Some(a_const::Val::Fval(float_val)) => { + assert_eq!(float_val.fval, "3.14159"); + } + other => panic!("Expected Fval, got {:?}", other), + } +} + +/// Test that parse_raw extracts boolean TRUE correctly and matches parse +#[test] +fn it_extracts_boolean_true_const() { + let query = "SELECT TRUE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let raw_const = get_first_const(&raw_result.protobuf).expect("Should have A_Const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("Should have A_Const"); + + assert_eq!(raw_const, proto_const); + assert!(!raw_const.isnull); + match &raw_const.val { + Some(a_const::Val::Boolval(bool_val)) => { + assert!(bool_val.boolval); + } + other => panic!("Expected Boolval(true), got {:?}", other), + } +} + +/// Test that parse_raw extracts boolean FALSE correctly and matches parse +#[test] +fn it_extracts_boolean_false_const() { + let query = "SELECT FALSE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let raw_const = get_first_const(&raw_result.protobuf).expect("Should have A_Const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("Should have A_Const"); + + assert_eq!(raw_const, proto_const); + assert!(!raw_const.isnull); + match &raw_const.val { + Some(a_const::Val::Boolval(bool_val)) => { + assert!(!bool_val.boolval); + } + other => panic!("Expected Boolval(false), got {:?}", other), + } +} + +/// Test that parse_raw extracts NULL correctly and matches parse +#[test] +fn it_extracts_null_const() { + let query = "SELECT NULL"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let raw_const = get_first_const(&raw_result.protobuf).expect("Should have A_Const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("Should have A_Const"); + + assert_eq!(raw_const, proto_const); + assert!(raw_const.isnull); + assert!(raw_const.val.is_none()); +} + +/// Test that parse_raw extracts bit string values correctly and matches parse +#[test] +fn it_extracts_bit_string_const() { + let query = "SELECT B'1010'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let raw_const = get_first_const(&raw_result.protobuf).expect("Should have A_Const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("Should have A_Const"); + + assert_eq!(raw_const, proto_const); + assert!(!raw_const.isnull); + match &raw_const.val { + Some(a_const::Val::Bsval(bit_val)) => { + assert_eq!(bit_val.bsval, "b1010"); + } + other => panic!("Expected Bsval, got {:?}", other), + } +} + +/// Test that parse_raw extracts hex bit string correctly and matches parse +#[test] +fn it_extracts_hex_bit_string_const() { + let query = "SELECT X'FF'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let raw_const = get_first_const(&raw_result.protobuf).expect("Should have A_Const"); + let proto_const = get_first_const(&proto_result.protobuf).expect("Should have A_Const"); + + assert_eq!(raw_const, proto_const); + assert!(!raw_const.isnull); + match &raw_const.val { + Some(a_const::Val::Bsval(bit_val)) => { + assert_eq!(bit_val.bsval, "xFF"); + } + other => panic!("Expected Bsval, got {:?}", other), + } +} +// ============================================================================ +// Expression tests +// ============================================================================ + +/// Test COALESCE +#[test] +fn it_parses_coalesce() { + let query = "SELECT COALESCE(nickname, name, 'Unknown') FROM users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test NULLIF +#[test] +fn it_parses_nullif() { + let query = "SELECT NULLIF(status, 'deleted') FROM records"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test GREATEST and LEAST +#[test] +fn it_parses_greatest_least() { + let query = "SELECT GREATEST(a, b, c), LEAST(x, y, z) FROM t"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test IS NULL and IS NOT NULL +#[test] +fn it_parses_null_tests() { + let query = "SELECT * FROM users WHERE deleted_at IS NULL AND email IS NOT NULL"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test IS DISTINCT FROM +#[test] +fn it_parses_is_distinct_from() { + let query = "SELECT * FROM t WHERE a IS DISTINCT FROM b"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test BETWEEN +#[test] +fn it_parses_between() { + let query = "SELECT * FROM events WHERE created_at BETWEEN '2023-01-01' AND '2023-12-31'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test LIKE and ILIKE +#[test] +fn it_parses_like_ilike() { + let query = "SELECT * FROM users WHERE name LIKE 'John%' OR email ILIKE '%@EXAMPLE.COM'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test SIMILAR TO +#[test] +fn it_parses_similar_to() { + let query = "SELECT * FROM products WHERE name SIMILAR TO '%(phone|tablet)%'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test complex boolean expressions +#[test] +fn it_parses_complex_boolean() { + let query = "SELECT * FROM users WHERE (active = true AND verified = true) OR (role = 'admin' AND NOT suspended)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// Type cast tests +// ============================================================================ + +/// Test PostgreSQL-style type cast +#[test] +fn it_parses_pg_type_cast() { + let query = "SELECT '123'::integer, '2023-01-01'::date, 'true'::boolean"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test SQL-style CAST +#[test] +fn it_parses_sql_cast() { + let query = "SELECT CAST('123' AS integer), CAST(created_at AS date) FROM t"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test array type cast +#[test] +fn it_parses_array_cast() { + let query = "SELECT ARRAY[1, 2, 3]::text[]"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// Array and JSON tests +// ============================================================================ + +/// Test array constructor +#[test] +fn it_parses_array_constructor() { + let query = "SELECT ARRAY[1, 2, 3], ARRAY['a', 'b', 'c']"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test array subscript +#[test] +fn it_parses_array_subscript() { + let query = "SELECT tags[1], matrix[1][2] FROM t"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test array slice +#[test] +fn it_parses_array_slice() { + let query = "SELECT arr[2:4], arr[:3], arr[2:] FROM t"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test unnest +#[test] +fn it_parses_unnest() { + let query = "SELECT unnest(ARRAY[1, 2, 3])"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test JSON operators +#[test] +fn it_parses_json_operators() { + let query = "SELECT data->'name', data->>'email', data#>'{address,city}' FROM users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test JSONB containment +#[test] +fn it_parses_jsonb_containment() { + let query = "SELECT * FROM products WHERE metadata @> '{\"featured\": true}'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// Parameter placeholder tests +// ============================================================================ + +/// Test positional parameters +#[test] +fn it_parses_positional_params() { + let query = "SELECT * FROM users WHERE id = $1 AND status = $2"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test parameters in INSERT +#[test] +fn it_parses_params_in_insert() { + let query = "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +// ============================================================================ +// SQL Value Function tests +// ============================================================================ + +/// Test CURRENT_TIMESTAMP (was causing infinite recursion) +#[test] +fn it_parses_current_timestamp() { + let query = "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (6, 1, 37553, -2309, CURRENT_TIMESTAMP)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test other SQL value functions +#[test] +fn it_parses_sql_value_functions() { + let query = "SELECT CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, LOCALTIME, LOCALTIMESTAMP, CURRENT_USER, CURRENT_CATALOG, CURRENT_SCHEMA"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} diff --git a/tests/raw_parse_iter/mod.rs b/tests/raw_parse_iter/mod.rs new file mode 100644 index 0000000..88c1903 --- /dev/null +++ b/tests/raw_parse_iter/mod.rs @@ -0,0 +1,57 @@ +//! Raw parse iter tests split into multiple modules for maintainability. +//! +//! This module contains tests that verify parse_raw_iter produces equivalent +//! results to parse (protobuf-based parsing). + +pub use pg_query::protobuf::{a_const, node, ParseResult as ProtobufParseResult}; +pub use pg_query::{deparse_raw, parse, parse_raw_iter, deparse_raw_iter, Error}; + +/// Helper to extract AConst from a SELECT statement's first target +pub fn get_first_const(result: &ProtobufParseResult) -> Option<&pg_query::protobuf::AConst> { + let stmt = result.stmts.first()?; + let raw_stmt = stmt.stmt.as_ref()?; + let node = raw_stmt.node.as_ref()?; + + if let node::Node::SelectStmt(select) = node { + let target = select.target_list.first()?; + if let Some(node::Node::ResTarget(res_target)) = target.node.as_ref() { + if let Some(val_node) = res_target.val.as_ref() { + if let Some(node::Node::AConst(aconst)) = val_node.node.as_ref() { + return Some(aconst); + } + } + } + } + None +} + +/// Helper macro for simple parse comparison tests with deparse verification +#[macro_export] +macro_rules! parse_iter_test { + ($query:expr) => {{ + let raw_result = parse_raw_iter($query).unwrap(); + let proto_result = parse($query).unwrap(); + assert_eq!(raw_result.protobuf, proto_result.protobuf); + // Verify that deparse_raw produces the original query + let deparsed = deparse_raw(&raw_result.protobuf).unwrap(); + assert_eq!(deparsed, $query); + }}; +} + +/// Helper macro for parse tests where the deparsed output may differ from input +/// (e.g., when PostgreSQL normalizes the SQL syntax) +#[macro_export] +macro_rules! parse_iter_test_no_deparse_check { + ($query:expr) => {{ + let raw_result = parse_raw_iter($query).unwrap(); + let proto_result = parse($query).unwrap(); + assert_eq!(raw_result.protobuf, proto_result.protobuf); + }}; +} + +pub mod basic; +pub mod ddl; +pub mod dml; +pub mod expressions; +pub mod select; +pub mod statements; diff --git a/tests/raw_parse_iter/select.rs b/tests/raw_parse_iter/select.rs new file mode 100644 index 0000000..5de4ba7 --- /dev/null +++ b/tests/raw_parse_iter/select.rs @@ -0,0 +1,862 @@ +//! Complex SELECT tests: JOINs, subqueries, CTEs, window functions, set operations. +//! +//! These tests verify parse_raw_iter_iter correctly handles complex SELECT statements. + +use super::*; + +// ============================================================================ +// JOIN and complex SELECT tests +// ============================================================================ + +/// Test parsing SELECT with JOIN +#[test] +fn it_parses_join() { + let query = "SELECT * FROM users u JOIN orders o ON u.id = o.user_id"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + // Verify deparse produces original query + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); + + // Verify tables are extracted correctly + let mut raw_tables = raw_result.tables(); + let mut proto_tables = proto_result.tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["orders", "users"]); +} + +/// Test parsing UNION query +#[test] +fn it_parses_union() { + let query = "SELECT id FROM users UNION SELECT id FROM admins"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); + + // Verify tables from both sides of UNION + let mut raw_tables = raw_result.tables(); + let mut proto_tables = proto_result.tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["admins", "users"]); +} + +/// Test parsing WITH clause (CTE) +#[test] +fn it_parses_cte() { + let query = "WITH active_users AS (SELECT * FROM users WHERE active = true) SELECT * FROM active_users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); + + // Verify CTE names match + assert_eq!(raw_result.cte_names, proto_result.cte_names); + assert!(raw_result.cte_names.contains(&"active_users".to_string())); + + // Verify tables (should only include actual tables, not CTEs) + let mut raw_tables = raw_result.tables(); + let mut proto_tables = proto_result.tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["users"]); +} + +/// Test parsing subquery in SELECT +#[test] +fn it_parses_subquery() { + let query = "SELECT * FROM users WHERE id IN (SELECT user_id FROM orders)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); + + // Verify all tables are found + let mut raw_tables = raw_result.tables(); + let mut proto_tables = proto_result.tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["orders", "users"]); +} + +/// Test parsing aggregate functions +#[test] +fn it_parses_aggregates() { + let query = "SELECT count(*), sum(amount), avg(price) FROM orders"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); + + // Verify functions are extracted correctly + let mut raw_funcs = raw_result.functions(); + let mut proto_funcs = proto_result.functions(); + raw_funcs.sort(); + proto_funcs.sort(); + assert_eq!(raw_funcs, proto_funcs); + assert!(raw_funcs.contains(&"count".to_string())); + assert!(raw_funcs.contains(&"sum".to_string())); + assert!(raw_funcs.contains(&"avg".to_string())); +} + +/// Test parsing CASE expression +#[test] +fn it_parses_case_expression() { + let query = "SELECT CASE WHEN x > 0 THEN 'positive' ELSE 'non-positive' END FROM t"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert_eq!(deparse_raw_iter(&raw_result.protobuf).unwrap(), query); + + // Verify table is found + let raw_tables = raw_result.tables(); + let proto_tables = proto_result.tables(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["t"]); +} + +/// Test parsing complex SELECT with multiple clauses +#[test] +fn it_parses_complex_select() { + let query = "SELECT u.id, u.name, count(*) AS order_count FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.active = true GROUP BY u.id, u.name HAVING count(*) > 0 ORDER BY order_count DESC LIMIT 10"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + // Full structural equality check + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + // Verify tables + let mut raw_tables = raw_result.tables(); + let mut proto_tables = proto_result.tables(); + raw_tables.sort(); + proto_tables.sort(); + assert_eq!(raw_tables, proto_tables); + assert_eq!(raw_tables, vec!["orders", "users"]); + + // Verify functions + let mut raw_funcs = raw_result.functions(); + let mut proto_funcs = proto_result.functions(); + raw_funcs.sort(); + proto_funcs.sort(); + assert_eq!(raw_funcs, proto_funcs); + assert!(raw_funcs.contains(&"count".to_string())); +} + +// ============================================================================ +// Advanced JOIN tests +// ============================================================================ + +/// Test LEFT JOIN +#[test] +fn it_parses_left_join() { + let query = "SELECT * FROM users u LEFT JOIN orders o ON u.id = o.user_id"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let mut raw_tables = raw_result.tables(); + raw_tables.sort(); + assert_eq!(raw_tables, vec!["orders", "users"]); +} + +/// Test RIGHT JOIN +#[test] +fn it_parses_right_join() { + let query = "SELECT * FROM users u RIGHT JOIN orders o ON u.id = o.user_id"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test FULL OUTER JOIN +#[test] +fn it_parses_full_outer_join() { + let query = "SELECT * FROM users u FULL OUTER JOIN orders o ON u.id = o.user_id"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CROSS JOIN +#[test] +fn it_parses_cross_join() { + let query = "SELECT * FROM users CROSS JOIN products"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let mut raw_tables = raw_result.tables(); + raw_tables.sort(); + assert_eq!(raw_tables, vec!["products", "users"]); +} + +/// Test NATURAL JOIN +#[test] +fn it_parses_natural_join() { + let query = "SELECT * FROM users NATURAL JOIN user_profiles"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test multiple JOINs +#[test] +fn it_parses_multiple_joins() { + let query = "SELECT u.name, o.id, p.name FROM users u + JOIN orders o ON u.id = o.user_id + JOIN order_items oi ON o.id = oi.order_id + JOIN products p ON oi.product_id = p.id"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let mut raw_tables = raw_result.tables(); + raw_tables.sort(); + assert_eq!(raw_tables, vec!["order_items", "orders", "products", "users"]); +} + +/// Test JOIN with USING clause +#[test] +fn it_parses_join_using() { + let query = "SELECT * FROM users u JOIN user_profiles p USING (user_id)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test LATERAL JOIN +#[test] +fn it_parses_lateral_join() { + let query = "SELECT * FROM users u, LATERAL (SELECT * FROM orders o WHERE o.user_id = u.id LIMIT 3) AS recent_orders"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let mut raw_tables = raw_result.tables(); + raw_tables.sort(); + assert_eq!(raw_tables, vec!["orders", "users"]); +} +// ============================================================================ +// Advanced subquery tests +// ============================================================================ + +/// Test correlated subquery +#[test] +fn it_parses_correlated_subquery() { + let query = "SELECT * FROM users u WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + + let mut raw_tables = raw_result.tables(); + raw_tables.sort(); + assert_eq!(raw_tables, vec!["orders", "users"]); +} + +/// Test NOT EXISTS subquery +#[test] +fn it_parses_not_exists_subquery() { + let query = "SELECT * FROM users u WHERE NOT EXISTS (SELECT 1 FROM banned b WHERE b.user_id = u.id)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test scalar subquery in SELECT +#[test] +fn it_parses_scalar_subquery() { + let query = "SELECT u.name, (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS order_count FROM users u"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test subquery in FROM clause +#[test] +fn it_parses_derived_table() { + let query = "SELECT * FROM (SELECT id, name FROM users WHERE active = true) AS active_users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ANY/SOME subquery +#[test] +fn it_parses_any_subquery() { + let query = "SELECT * FROM products WHERE price > ANY (SELECT avg_price FROM categories)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ALL subquery +#[test] +fn it_parses_all_subquery() { + let query = "SELECT * FROM products WHERE price > ALL (SELECT price FROM discounted_products)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// Window function tests +// ============================================================================ + +/// Test basic window function +#[test] +fn it_parses_window_function() { + let query = "SELECT name, salary, ROW_NUMBER() OVER (ORDER BY salary DESC) AS rank FROM employees"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test window function with PARTITION BY +#[test] +fn it_parses_window_function_partition() { + let query = "SELECT department, name, salary, RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank FROM employees"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test window function with frame clause +#[test] +fn it_parses_window_function_frame() { + let query = "SELECT date, amount, SUM(amount) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_sum FROM transactions"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test named window +#[test] +fn it_parses_named_window() { + let query = "SELECT name, salary, SUM(salary) OVER w, AVG(salary) OVER w FROM employees WINDOW w AS (PARTITION BY department ORDER BY salary)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test LAG and LEAD functions +#[test] +fn it_parses_lag_lead() { + let query = + "SELECT date, price, LAG(price, 1) OVER (ORDER BY date) AS prev_price, LEAD(price, 1) OVER (ORDER BY date) AS next_price FROM stock_prices"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// CTE variations +// ============================================================================ + +/// Test multiple CTEs +#[test] +fn it_parses_multiple_ctes() { + let query = "WITH + active_users AS (SELECT * FROM users WHERE active = true), + premium_users AS (SELECT * FROM active_users WHERE plan = 'premium') + SELECT * FROM premium_users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); + assert!(raw_result.cte_names.contains(&"active_users".to_string())); + assert!(raw_result.cte_names.contains(&"premium_users".to_string())); +} + +/// Test recursive CTE +#[test] +fn it_parses_recursive_cte() { + let query = "WITH RECURSIVE subordinates AS ( + SELECT id, name, manager_id FROM employees WHERE id = 1 + UNION ALL + SELECT e.id, e.name, e.manager_id FROM employees e INNER JOIN subordinates s ON e.manager_id = s.id + ) SELECT * FROM subordinates"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CTE with column list +#[test] +fn it_parses_cte_with_columns() { + let query = "WITH regional_sales(region, total) AS (SELECT region, SUM(amount) FROM orders GROUP BY region) SELECT * FROM regional_sales"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test CTE with MATERIALIZED +#[test] +fn it_parses_cte_materialized() { + let query = "WITH t AS MATERIALIZED (SELECT * FROM large_table WHERE x > 100) SELECT * FROM t"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// Set operations +// ============================================================================ + +/// Test INTERSECT +#[test] +fn it_parses_intersect() { + let query = "SELECT id FROM users INTERSECT SELECT user_id FROM orders"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test EXCEPT +#[test] +fn it_parses_except() { + let query = "SELECT id FROM users EXCEPT SELECT user_id FROM banned_users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UNION ALL +#[test] +fn it_parses_union_all() { + let query = "SELECT name FROM users UNION ALL SELECT name FROM admins"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test compound set operations +#[test] +fn it_parses_compound_set_operations() { + let query = "(SELECT id FROM a UNION SELECT id FROM b) INTERSECT SELECT id FROM c"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// GROUP BY variations +// ============================================================================ + +/// Test GROUP BY ROLLUP +#[test] +fn it_parses_group_by_rollup() { + let query = "SELECT region, product, SUM(sales) FROM sales_data GROUP BY ROLLUP(region, product)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test GROUP BY CUBE +#[test] +fn it_parses_group_by_cube() { + let query = "SELECT region, product, SUM(sales) FROM sales_data GROUP BY CUBE(region, product)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test GROUP BY GROUPING SETS +#[test] +fn it_parses_grouping_sets() { + let query = "SELECT region, product, SUM(sales) FROM sales_data GROUP BY GROUPING SETS ((region), (product), ())"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// DISTINCT and ORDER BY variations +// ============================================================================ + +/// Test DISTINCT ON +#[test] +fn it_parses_distinct_on() { + let query = "SELECT DISTINCT ON (user_id) * FROM orders ORDER BY user_id, created_at DESC"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ORDER BY with NULLS FIRST/LAST +#[test] +fn it_parses_order_by_nulls() { + let query = "SELECT * FROM users ORDER BY last_login DESC NULLS LAST"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test FETCH FIRST +#[test] +fn it_parses_fetch_first() { + let query = "SELECT * FROM users ORDER BY id FETCH FIRST 10 ROWS ONLY"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test OFFSET with FETCH +#[test] +fn it_parses_offset_fetch() { + let query = "SELECT * FROM users ORDER BY id OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// Locking clauses +// ============================================================================ + +/// Test FOR UPDATE +#[test] +fn it_parses_for_update() { + let query = "SELECT * FROM users WHERE id = 1 FOR UPDATE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test FOR SHARE +#[test] +fn it_parses_for_share() { + let query = "SELECT * FROM users WHERE id = 1 FOR SHARE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test FOR UPDATE NOWAIT +#[test] +fn it_parses_for_update_nowait() { + let query = "SELECT * FROM users WHERE id = 1 FOR UPDATE NOWAIT"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test FOR UPDATE SKIP LOCKED +#[test] +fn it_parses_for_update_skip_locked() { + let query = "SELECT * FROM jobs WHERE status = 'pending' LIMIT 1 FOR UPDATE SKIP LOCKED"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// Complex real-world queries +// ============================================================================ + +/// Test analytics query with window functions +#[test] +fn it_parses_analytics_query() { + let query = " + SELECT + date_trunc('day', created_at) AS day, + COUNT(*) AS daily_orders, + SUM(amount) AS daily_revenue, + AVG(amount) OVER (ORDER BY date_trunc('day', created_at) ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS weekly_avg + FROM orders + WHERE created_at >= NOW() - INTERVAL '30 days' + GROUP BY date_trunc('day', created_at) + ORDER BY day"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test hierarchical query with recursive CTE +#[test] +fn it_parses_hierarchy_query() { + let query = " + WITH RECURSIVE category_tree AS ( + SELECT id, name, parent_id, 0 AS level, ARRAY[id] AS path + FROM categories + WHERE parent_id IS NULL + UNION ALL + SELECT c.id, c.name, c.parent_id, ct.level + 1, ct.path || c.id + FROM categories c + JOIN category_tree ct ON c.parent_id = ct.id + ) + SELECT * FROM category_tree ORDER BY path"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test complex report query +#[test] +fn it_parses_complex_report_query() { + let query = " + WITH monthly_data AS ( + SELECT + date_trunc('month', o.created_at) AS month, + u.region, + p.category, + SUM(oi.quantity * oi.unit_price) AS revenue, + COUNT(DISTINCT o.id) AS order_count, + COUNT(DISTINCT o.user_id) AS customer_count + FROM orders o + JOIN users u ON o.user_id = u.id + JOIN order_items oi ON o.id = oi.order_id + JOIN products p ON oi.product_id = p.id + WHERE o.created_at >= '2023-01-01' AND o.status = 'completed' + GROUP BY 1, 2, 3 + ) + SELECT + month, + region, + category, + revenue, + order_count, + customer_count, + revenue / NULLIF(order_count, 0) AS avg_order_value, + SUM(revenue) OVER (PARTITION BY region ORDER BY month) AS cumulative_revenue + FROM monthly_data + ORDER BY month DESC, region, revenue DESC"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test query with multiple subqueries and CTEs +#[test] +fn it_parses_mixed_subqueries_and_ctes() { + let query = " + WITH high_value_customers AS ( + SELECT user_id FROM orders GROUP BY user_id HAVING SUM(amount) > 1000 + ) + SELECT u.*, + (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS total_orders, + (SELECT MAX(created_at) FROM orders o WHERE o.user_id = u.id) AS last_order + FROM users u + WHERE u.id IN (SELECT user_id FROM high_value_customers) + AND EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.created_at > NOW() - INTERVAL '90 days') + ORDER BY (SELECT SUM(amount) FROM orders o WHERE o.user_id = u.id) DESC + LIMIT 100"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// Tests for previously stubbed fields +// ============================================================================ + +/// Test column with COLLATE clause +#[test] +fn it_parses_column_with_collate() { + let query = "CREATE TABLE test_collate ( + name TEXT COLLATE \"C\", + description VARCHAR(255) COLLATE \"en_US.UTF-8\" + )"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test partitioned table with PARTITION BY RANGE +#[test] +fn it_parses_partition_by_range() { + let query = "CREATE TABLE measurements ( + id SERIAL, + logdate DATE NOT NULL, + peaktemp INT + ) PARTITION BY RANGE (logdate)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test partitioned table with PARTITION BY LIST +#[test] +fn it_parses_partition_by_list() { + let query = "CREATE TABLE orders ( + id SERIAL, + region TEXT NOT NULL, + order_date DATE + ) PARTITION BY LIST (region)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test partitioned table with PARTITION BY HASH +#[test] +fn it_parses_partition_by_hash() { + let query = "CREATE TABLE users_partitioned ( + id SERIAL, + username TEXT + ) PARTITION BY HASH (id)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test partition with FOR VALUES (range) +#[test] +fn it_parses_partition_for_values_range() { + let query = "CREATE TABLE measurements_2023 PARTITION OF measurements + FOR VALUES FROM ('2023-01-01') TO ('2024-01-01')"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test partition with FOR VALUES (list) +#[test] +fn it_parses_partition_for_values_list() { + let query = "CREATE TABLE orders_west PARTITION OF orders + FOR VALUES IN ('west', 'northwest', 'southwest')"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test partition with FOR VALUES (hash) +#[test] +fn it_parses_partition_for_values_hash() { + let query = "CREATE TABLE users_part_0 PARTITION OF users_partitioned + FOR VALUES WITH (MODULUS 4, REMAINDER 0)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test partition with DEFAULT +#[test] +fn it_parses_partition_default() { + let query = "CREATE TABLE orders_other PARTITION OF orders DEFAULT"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test recursive CTE with SEARCH BREADTH FIRST +#[test] +fn it_parses_cte_search_breadth_first() { + let query = "WITH RECURSIVE search_tree(id, parent_id, data, depth) AS ( + SELECT id, parent_id, data, 0 FROM tree WHERE parent_id IS NULL + UNION ALL + SELECT t.id, t.parent_id, t.data, st.depth + 1 + FROM tree t, search_tree st WHERE t.parent_id = st.id + ) SEARCH BREADTH FIRST BY id SET ordercol + SELECT * FROM search_tree ORDER BY ordercol"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test recursive CTE with SEARCH DEPTH FIRST +#[test] +fn it_parses_cte_search_depth_first() { + let query = "WITH RECURSIVE search_tree(id, parent_id, data) AS ( + SELECT id, parent_id, data FROM tree WHERE parent_id IS NULL + UNION ALL + SELECT t.id, t.parent_id, t.data + FROM tree t, search_tree st WHERE t.parent_id = st.id + ) SEARCH DEPTH FIRST BY id SET ordercol + SELECT * FROM search_tree ORDER BY ordercol"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test recursive CTE with CYCLE detection +#[test] +fn it_parses_cte_cycle() { + let query = "WITH RECURSIVE search_graph(id, link, data, depth) AS ( + SELECT g.id, g.link, g.data, 0 FROM graph g + UNION ALL + SELECT g.id, g.link, g.data, sg.depth + 1 + FROM graph g, search_graph sg WHERE g.id = sg.link + ) CYCLE id SET is_cycle USING path + SELECT * FROM search_graph"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test recursive CTE with both SEARCH and CYCLE +#[test] +fn it_parses_cte_search_and_cycle() { + let query = "WITH RECURSIVE search_graph(id, link, data, depth) AS ( + SELECT g.id, g.link, g.data, 0 FROM graph g WHERE id = 1 + UNION ALL + SELECT g.id, g.link, g.data, sg.depth + 1 + FROM graph g, search_graph sg WHERE g.id = sg.link + ) SEARCH DEPTH FIRST BY id SET ordercol + CYCLE id SET is_cycle USING path + SELECT * FROM search_graph"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} diff --git a/tests/raw_parse_iter/statements.rs b/tests/raw_parse_iter/statements.rs new file mode 100644 index 0000000..9a324c8 --- /dev/null +++ b/tests/raw_parse_iter/statements.rs @@ -0,0 +1,450 @@ +//! Utility statement tests: transactions, VACUUM, SET/SHOW, LOCK, DO, LISTEN, etc. +//! +//! These tests verify parse_raw_iter_iter correctly handles utility statements. + +use super::*; + +// ============================================================================ +// Transaction and utility statements +// ============================================================================ + +/// Test EXPLAIN +#[test] +fn it_parses_explain() { + let query = "EXPLAIN SELECT * FROM users WHERE id = 1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test EXPLAIN ANALYZE +#[test] +fn it_parses_explain_analyze() { + let query = "EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT * FROM users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test COPY +#[test] +fn it_parses_copy() { + let query = "COPY users (id, name, email) FROM STDIN WITH (FORMAT csv, HEADER true)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test PREPARE +#[test] +fn it_parses_prepare() { + let query = "PREPARE user_by_id (int) AS SELECT * FROM users WHERE id = $1"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test EXECUTE +#[test] +fn it_parses_execute() { + let query = "EXECUTE user_by_id(42)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DEALLOCATE +#[test] +fn it_parses_deallocate() { + let query = "DEALLOCATE user_by_id"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// Transaction statement tests +// ============================================================================ + +/// Test BEGIN transaction +#[test] +fn it_parses_begin() { + let query = "BEGIN"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test BEGIN with options +#[test] +fn it_parses_begin_with_options() { + let query = "BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test COMMIT transaction +#[test] +fn it_parses_commit() { + let query = "COMMIT"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ROLLBACK transaction +#[test] +fn it_parses_rollback() { + let query = "ROLLBACK"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test START TRANSACTION +#[test] +fn it_parses_start_transaction() { + let query = "START TRANSACTION"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test SAVEPOINT +#[test] +fn it_parses_savepoint() { + let query = "SAVEPOINT my_savepoint"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ROLLBACK TO SAVEPOINT +#[test] +fn it_parses_rollback_to_savepoint() { + let query = "ROLLBACK TO SAVEPOINT my_savepoint"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test RELEASE SAVEPOINT +#[test] +fn it_parses_release_savepoint() { + let query = "RELEASE SAVEPOINT my_savepoint"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// VACUUM and ANALYZE statement tests +// ============================================================================ + +/// Test VACUUM +#[test] +fn it_parses_vacuum() { + let query = "VACUUM"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test VACUUM with table +#[test] +fn it_parses_vacuum_table() { + let query = "VACUUM users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test VACUUM ANALYZE +#[test] +fn it_parses_vacuum_analyze() { + let query = "VACUUM ANALYZE users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test VACUUM FULL +#[test] +fn it_parses_vacuum_full() { + let query = "VACUUM FULL users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ANALYZE +#[test] +fn it_parses_analyze() { + let query = "ANALYZE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ANALYZE with table +#[test] +fn it_parses_analyze_table() { + let query = "ANALYZE users"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test ANALYZE with column list +#[test] +fn it_parses_analyze_columns() { + let query = "ANALYZE users (id, name)"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// SET and SHOW statement tests +// ============================================================================ + +/// Test SET statement +#[test] +fn it_parses_set() { + let query = "SET search_path TO public"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test SET with equals +#[test] +fn it_parses_set_equals() { + let query = "SET statement_timeout = 5000"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test SET LOCAL +#[test] +fn it_parses_set_local() { + let query = "SET LOCAL search_path TO myschema"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test SET SESSION +#[test] +fn it_parses_set_session() { + let query = "SET SESSION timezone = 'UTC'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test RESET +#[test] +fn it_parses_reset() { + let query = "RESET search_path"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test RESET ALL +#[test] +fn it_parses_reset_all() { + let query = "RESET ALL"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test SHOW statement +#[test] +fn it_parses_show() { + let query = "SHOW search_path"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test SHOW ALL +#[test] +fn it_parses_show_all() { + let query = "SHOW ALL"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// LISTEN, NOTIFY, UNLISTEN statement tests +// ============================================================================ + +/// Test LISTEN statement +#[test] +fn it_parses_listen() { + let query = "LISTEN my_channel"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test NOTIFY statement +#[test] +fn it_parses_notify() { + let query = "NOTIFY my_channel"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test NOTIFY with payload +#[test] +fn it_parses_notify_with_payload() { + let query = "NOTIFY my_channel, 'hello world'"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UNLISTEN statement +#[test] +fn it_parses_unlisten() { + let query = "UNLISTEN my_channel"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test UNLISTEN * +#[test] +fn it_parses_unlisten_all() { + let query = "UNLISTEN *"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// DISCARD statement tests +// ============================================================================ + +/// Test DISCARD ALL +#[test] +fn it_parses_discard_all() { + let query = "DISCARD ALL"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DISCARD PLANS +#[test] +fn it_parses_discard_plans() { + let query = "DISCARD PLANS"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DISCARD SEQUENCES +#[test] +fn it_parses_discard_sequences() { + let query = "DISCARD SEQUENCES"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DISCARD TEMP +#[test] +fn it_parses_discard_temp() { + let query = "DISCARD TEMP"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// LOCK statement tests +// ============================================================================ + +/// Test LOCK TABLE +#[test] +fn it_parses_lock_table() { + let query = "LOCK TABLE users IN ACCESS EXCLUSIVE MODE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test LOCK multiple tables +#[test] +fn it_parses_lock_multiple_tables() { + let query = "LOCK TABLE users, orders IN SHARE MODE"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} +// ============================================================================ +// DO statement tests +// ============================================================================ + +/// Test DO statement +#[test] +fn it_parses_do_statement() { + let query = "DO $$ BEGIN RAISE NOTICE 'Hello'; END $$"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} + +/// Test DO statement with language +#[test] +fn it_parses_do_with_language() { + let query = "DO LANGUAGE plpgsql $$ BEGIN NULL; END $$"; + let raw_result = parse_raw_iter(query).unwrap(); + let proto_result = parse(query).unwrap(); + + assert_eq!(raw_result.protobuf, proto_result.protobuf); +} diff --git a/tests/raw_parse_iter_tests.rs b/tests/raw_parse_iter_tests.rs new file mode 100644 index 0000000..a33a027 --- /dev/null +++ b/tests/raw_parse_iter_tests.rs @@ -0,0 +1,15 @@ +//! Tests for parse_raw_iter functionality. +//! +//! These tests verify that parse_raw_iter produces equivalent results to parse. +//! Tests are split into modules for maintainability. +//! +//! Run tests one at a time from simple to complex: +//! cargo test --test raw_parse_iter_tests raw_parse_iter::basic::it_parses_simple_select + +#![allow(non_snake_case)] +#![cfg(test)] + +#[macro_use] +mod support; + +mod raw_parse_iter; From 0efccab33c647b99d63b3f28dfdaf00b529d3a57 Mon Sep 17 00:00:00 2001 From: meskill <8974488+meskill@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:13:45 +0000 Subject: [PATCH 3/4] fix tests --- docs/migration_plan.md | 230 +- src/raw_deparse_iter.rs | 5 +- src/raw_parse_iter.rs | 5765 ++++++++++++++++++++------------------- 3 files changed, 3130 insertions(+), 2870 deletions(-) diff --git a/docs/migration_plan.md b/docs/migration_plan.md index 675ff26..2355d85 100644 --- a/docs/migration_plan.md +++ b/docs/migration_plan.md @@ -2,8 +2,8 @@ ## Strategy -Instead of migrating by node-type groups, we migrate **test by test** — running a single -test from simple to complex, fixing whatever breaks, and moving on only after it passes. +We migrate **test by test** — running a single test from simple to complex, adding +the missing node type to the iterative `Processor`, and moving on only after it passes. All tests live in `tests/raw_parse_iter/` and mirror `tests/raw_parse/` exactly, except they call `parse_raw_iter` instead of `parse_raw`. Every test compares `parse_raw_iter` @@ -23,7 +23,207 @@ cargo test --test raw_parse_iter_tests raw_parse_iter::basic::it_parses_simple_s fix it in `raw_parse_iter.rs` (or `Processor`), re-run, repeat 4. After the fix passes, run all previously-passing tests as regression: `cargo test --test raw_parse_iter_tests -- --nocapture` -5. Commit + +--- + +## How the Iterative Processor Works + +The `Processor` struct in `raw_parse_iter.rs` replaces recursive `convert_node()` calls +with an explicit stack. It has two stacks: + +- **`stack`** — `Vec` — work items (C node pointers + a `collect` flag) +- **`result_stack`** — `Vec` — completed protobuf nodes + +### Two-pass processing + +Every node is visited **twice**: + +1. **Queue pass** (`collect=false`): Push a collect marker for this node, then push + its children onto the stack. Children go on top, so they are processed first. +2. **Collect pass** (`collect=true`): All children have been processed and their results + sit on `result_stack`. Pop them, assemble the protobuf struct, push the result. + +``` +stack (LIFO): + ┌─────────────────┐ + │ child C │ ← processed first + │ child B │ + │ child A │ + │ COLLECT(parent) │ ← processed after all children + └─────────────────┘ +``` + +### Key helper methods + +| Method | Purpose | +|--------|---------| +| `queue_collect(ptr)` | Push a collect marker (same pointer, `collect=true`) | +| `queue_node(ptr)` | Push a child node for processing (`collect=false`); null ptrs are skipped | +| `queue_list_nodes(list)` | Push every element of a C `List*` as individual nodes | +| `single_result(ptr)` | Pop one result from `result_stack`; returns `None` if ptr was null | +| `single_result_box(ptr)` | Same but returns `Option>` | +| `fetch_list_results(list)` | Pop N results (where N = list length); returns `Vec` | +| `push_result(node)` | Push a completed protobuf node onto `result_stack` | + +### Symmetry rule + +**Every queued node produces exactly one result.** This means: + +- `queue_node(ptr)` must be balanced by `single_result(ptr)` or `single_result_box(ptr)` + using **the same pointer** so the null-check matches. +- `queue_list_nodes(list)` must be balanced by `fetch_list_results(list)` using + **the same list pointer**. +- The order must be the same: queue A then B → collect fetches A then B. + +--- + +## How to Migrate a Node Type + +### Step 1: Identify the category + +| Category | Description | Example | +|----------|-------------|---------| +| **Leaf** | No child nodes/lists that need conversion | `SQLValueFunction`, `SetToDefault` | +| **Simple** | Has child nodes and/or lists | `BoolExpr`, `NullTest`, `SubLink` | + +### Step 2: Add the match arm in `process()` + +In the `match node_tag { ... }` block, add an arm for the new `NodeTag`: + +```rust +bindings_raw::NodeTag_T_BoolExpr => { + let be = node_ptr as *const bindings_raw::BoolExpr; + if collect { + let node = self.collect_bool_expr(&*be); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_bool_expr(&*be); + } +} +``` + +For **leaf nodes** (no children), skip queue/collect entirely: + +```rust +bindings_raw::NodeTag_T_SQLValueFunction => { + let svf = node_ptr as *const bindings_raw::SQLValueFunction; + self.push_result(protobuf::node::Node::SqlvalueFunction(Box::new( + protobuf::SqlValueFunction { + xpr: None, + op: (*svf).op as i32 + 1, + r#type: (*svf).type_, + typmod: (*svf).typmod, + location: (*svf).location, + }, + ))); +} +``` + +### Step 3: Add `queue_*` and `collect_*` methods (non-leaf only) + +The **queue method** pushes children onto the stack. The **collect method** pops +results and assembles the protobuf struct. + +Look at the existing recursive `convert_*` function to see which fields need conversion. +Each call to `convert_node_boxed(field)` becomes a `queue_node(field)` / `single_result_box(field)` pair. +Each call to `convert_list_to_nodes(list)` becomes a `queue_list_nodes(list)` / `fetch_list_results(list)` pair. + +**Example — BoolExpr** (one list child): + +Recursive version (in `raw_parse.rs`): +```rust +unsafe fn convert_bool_expr(be: &bindings_raw::BoolExpr) -> protobuf::BoolExpr { + protobuf::BoolExpr { + xpr: None, + boolop: be.boolop as i32 + 1, + args: convert_list_to_nodes(be.args), // ← list child + location: be.location, + } +} +``` + +Iterative version (queue + collect methods on `Processor`): +```rust +unsafe fn queue_bool_expr(&mut self, be: &bindings_raw::BoolExpr) { + self.queue_list_nodes(be.args); // ← queue the list +} + +unsafe fn collect_bool_expr(&mut self, be: &bindings_raw::BoolExpr) -> protobuf::node::Node { + let args = self.fetch_list_results(be.args); // ← fetch matching results + protobuf::node::Node::BoolExpr(Box::new(protobuf::BoolExpr { + xpr: None, + boolop: be.boolop as i32 + 1, + args, + location: be.location, + })) +} +``` + +**Example — SubLink** (two node children + one list child): + +```rust +unsafe fn queue_sub_link(&mut self, sl: &bindings_raw::SubLink) { + self.queue_node(sl.testexpr); // node child 1 + self.queue_list_nodes(sl.operName); // list child + self.queue_node(sl.subselect); // node child 2 +} + +unsafe fn collect_sub_link(&mut self, sl: &bindings_raw::SubLink) -> protobuf::node::Node { + let testexpr = self.single_result_box(sl.testexpr); + let oper_name = self.fetch_list_results(sl.operName); + let subselect = self.single_result_box(sl.subselect); + protobuf::node::Node::SubLink(Box::new(protobuf::SubLink { + xpr: None, + sub_link_type: sl.subLinkType as i32 + 1, + sub_link_id: sl.subLinkId, + testexpr, + oper_name, + subselect, + location: sl.location, + })) +} +``` + +### Step 4: Add to `node_tag_name()` (for debug logging) + +```rust +bindings_raw::NodeTag_T_BoolExpr => "BoolExpr", +``` + +### Step 5: Handle non-Node helper structs + +Some PostgreSQL structs (like `Alias`, `IntoClause`, `OnConflictClause`) are embedded +inside other nodes but are not themselves `Node` types in the processor's match. These +are handled with dedicated `queue_*` / `fetch_*` helper pairs on the Processor, called +from the parent's queue/collect methods. See `queue_into_clause` / `fetch_into_clause` +and `queue_on_conflict_clause` / `fetch_on_conflict_clause` as examples. + +### Step 6: Run tests and verify + +```sh +# Run the specific test that needs this node type +cargo test --test raw_parse_iter_tests "raw_parse_iter::expressions::it_parses_null_tests" -- --nocapture + +# Run all tests as regression +cargo test --test raw_parse_iter_tests -- --nocapture +``` + +### Common pitfalls + +- **Queue/collect order mismatch**: The collect method must pop results in the **same + order** as the queue method pushed children. If queue does `A, B, C` then collect + must do `A, B, C` (not `C, B, A`). +- **Forgetting null checks**: `queue_node` with null is harmless (skipped in process), + but `single_result` must be called with **the same pointer** so it knows whether to + pop. If the pointer was null, `single_result` returns `None` without popping. +- **Missing list symmetry**: If you call `queue_list_nodes(some_list)`, you MUST call + `fetch_list_results(some_list)` with the **same list pointer** — not a different copy. +- **Wrong protobuf enum offset**: PostgreSQL C enums start at 0, protobuf enums reserve + 0 for `UNDEFINED`. Most fields need `as i32 + 1`. +- **Boxed vs unboxed**: Check the protobuf struct definition — some fields use + `Option>` (call `single_result_box`), others use `Vec` (call + `fetch_list_results`), and some are scalar (just copy directly). --- @@ -305,15 +505,16 @@ Progressively harder SELECT features. Each test tends to add one new node type. ## Progress Tracking -Mark each test as it passes: +**232 / 232 tests passing** (100%) ✅ — last checked 2026-02-08 -``` -[ ] 1. basic::it_parses_simple_select -[ ] 2. basic::it_matches_parse_for_simple_select -... -``` +### Step 1 — `basic`: ✅ 21/21 +### Step 2 — `expressions`: ✅ 34/34 +### Step 3 — `select`: ✅ 61/61 +### Step 4 — `dml`: ✅ 38/38 +### Step 5 — `ddl`: ✅ 36/36 +### Step 6 — `statements`: ✅ 42/42 -Update this section as you go. When all 232 tests pass, the migration is functionally complete. +All 232 tests pass. The iterative migration is functionally complete. --- @@ -322,13 +523,15 @@ Update this section as you go. When all 232 tests pass, the migration is functio 1. **Run full regression**: `cargo test --test raw_parse_iter_tests` 2. **Run acceptance suite** against `parse_raw_iter` (port `parse_raw_acceptance.rs`) 3. **Run benchmarks**: `cargo test --test raw_parse_iter_tests benchmark -- --nocapture` (if added) -4. **Remove recursive fallback**: once all node types are handled iteratively in `process()`, - remove `convert_node()`, `convert_node_boxed()`, standalone `convert_*` functions, +4. **Clean up dead code**: remove unused standalone `convert_*` functions, the legacy + `convert_node()` / `convert_node_boxed()` functions, `convert_list_to_nodes()`, and the `stacker` dependency 5. **Swap entrypoint**: make `parse_raw` call the iterative implementation internally ## General Rules +- **No recursive fallback**: every node type that appears in a parse tree must have its + own match arm in `process()`. The `_ =>` catch-all panics to surface missing types early. - **Queue and collect must be symmetric**: every node queued produces exactly one result. Every `fetch_list_results` call must match a corresponding `queue_list_nodes` call with the same list pointer. Every `single_result` must match a `queue_node`. @@ -339,5 +542,4 @@ Update this section as you go. When all 232 tests pass, the migration is functio - **Push order**: `queue_collect` first (bottom of stack), then children left-to-right. Children are processed right-to-left (LIFO). Results accumulate in reverse. `fetch_results` drains from the end and reverses. -- **One test at a time**: run, fix, verify, commit. The recursive fallback ensures - everything keeps working during incremental migration. \ No newline at end of file +- **One test at a time**: run, fix, verify, commit. diff --git a/src/raw_deparse_iter.rs b/src/raw_deparse_iter.rs index 909dfb5..be56f37 100644 --- a/src/raw_deparse_iter.rs +++ b/src/raw_deparse_iter.rs @@ -1,6 +1,7 @@ -use crate::protobuf; +use crate::{deparse_raw, protobuf}; use crate::{Error, Result}; pub fn deparse_raw_iter(protobuf: &protobuf::ParseResult) -> Result { - todo!() + // TODO: Implement iterative deparsing + deparse_raw(protobuf) } diff --git a/src/raw_parse_iter.rs b/src/raw_parse_iter.rs index 9f91a24..266d525 100644 --- a/src/raw_parse_iter.rs +++ b/src/raw_parse_iter.rs @@ -9,7 +9,6 @@ use crate::bindings_raw; use crate::parse_result::ParseResult; use crate::protobuf; use crate::{Error, Result}; -use std::collections::VecDeque; use std::ffi::{CStr, CString}; use std::os::raw::c_char; @@ -73,16 +72,13 @@ unsafe fn convert_list_to_raw_stmts(list: *mut bindings_raw::List) -> Vec protobuf::RawStmt { let mut processor = Processor::new(raw_stmt.stmt); + println!("processing raw_stmt"); + processor.process(); protobuf::RawStmt { stmt: processor.get_result(), stmt_location: raw_stmt.stmt_location, stmt_len: raw_stmt.stmt_len } } -/// Converts a C Node pointer to a boxed protobuf Node (for fields that expect Option>). -unsafe fn convert_node_boxed(node_ptr: *const bindings_raw::Node) -> Option> { - convert_node(node_ptr).map(Box::new) -} - struct ProcessingNode { collect: bool, node: *const bindings_raw::Node, @@ -111,9 +107,15 @@ impl Processor { } fn get_result(mut self) -> Option> { + println!("[result] get_result: result_stack.len={}", self.result_stack.len()); let result = self.result_stack.pop(); + println!( + "[result] popped={:?}, remaining={}", + result.as_ref().map(|n| format!("{:?}", n.node.as_ref().map(|n| std::mem::discriminant(n)))), + self.result_stack.len(), + ); - assert!(self.result_stack.is_empty(), "Result stack should be empty after processing"); + assert!(self.result_stack.is_empty(), "Result stack should be empty after processing, but has {} items left", self.result_stack.len()); result.map(Box::new) } @@ -129,3205 +131,3260 @@ impl Processor { let node_tag = (*node_ptr).type_; + println!( + "[process] tag={} ({}) collect={} stack_depth={} result_stack_depth={}", + node_tag_name(node_tag), + node_tag, + collect, + self.stack.len(), + self.result_stack.len(), + ); + match node_tag { - // Types that need Box + // === SelectStmt (boxed) === bindings_raw::NodeTag_T_SelectStmt => { let stmt = node_ptr as *const bindings_raw::SelectStmt; if collect { - let stmt = self.collect_select_stmt(&*stmt); - self.push_result(stmt); + println!("[collect] SelectStmt — result_stack={}", self.result_stack.len()); + let node = self.collect_select_stmt(&*stmt); + self.push_result(node); } else { + println!("[queue] SelectStmt — pushing collect + children"); self.queue_collect(node_ptr); self.queue_select_stmt(&*stmt); } } - _ => { - todo!() - } - } - } - } - - fn queue_node(&mut self, node: *const bindings_raw::Node) { - self.stack.push(ProcessingNode::with_node(node)); - } - fn queue_collect(&mut self, node: *const bindings_raw::Node) { - self.stack.push(ProcessingNode::with_collect(node)) - } + // === ResTarget (boxed) === + bindings_raw::NodeTag_T_ResTarget => { + let rt = node_ptr as *const bindings_raw::ResTarget; - fn push_result(&mut self, node: protobuf::node::Node) { - self.result_stack.push(protobuf::Node { node: Some(node) }); - } + if collect { + println!("[collect] ResTarget — result_stack={}", self.result_stack.len()); + let node = self.collect_res_target(&*rt); + self.push_result(node); + } else { + println!("[queue] ResTarget — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_res_target(&*rt); + } + } - fn single_result(&mut self, node: *const bindings_raw::Node) -> Option { - if node.is_null() { - return None; - } + // === ColumnRef (has fields list) === + bindings_raw::NodeTag_T_ColumnRef => { + let cr = node_ptr as *const bindings_raw::ColumnRef; - Some(self.result_stack.pop().expect("result stack should not be empty while processing")) - } + if collect { + println!("[collect] ColumnRef — result_stack={}", self.result_stack.len()); + let node = self.collect_column_ref(&*cr); + self.push_result(node); + } else { + println!("[queue] ColumnRef — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_column_ref(&*cr); + } + } - fn single_result_box(&mut self, node: *const bindings_raw::Node) -> Option> { - self.single_result(node).map(Box::new) - } + // === RangeVar (iterative — alias.colnames queued) === + bindings_raw::NodeTag_T_RangeVar => { + let rv = node_ptr as *const bindings_raw::RangeVar; + if collect { + println!("[collect] RangeVar — result_stack={}", self.result_stack.len()); + let node = self.collect_range_var(&*rv); + self.push_result(node); + } else { + println!("[queue] RangeVar relname={:?} — pushing collect + children", convert_c_string((*rv).relname)); + self.queue_collect(node_ptr); + self.queue_range_var(&*rv); + } + } - fn fetch_results(&mut self, count: usize) -> Vec { - let start = self.result_stack.len() - count; - self.result_stack.drain(start..).rev().collect() - } + // === JoinExpr (iterative) === + bindings_raw::NodeTag_T_JoinExpr => { + let je = node_ptr as *const bindings_raw::JoinExpr; + if collect { + println!("[collect] JoinExpr — result_stack={}", self.result_stack.len()); + let node = self.collect_join_expr(&*je); + self.push_result(node); + } else { + println!("[queue] JoinExpr — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_join_expr(&*je); + } + } - unsafe fn queue_list_nodes(&mut self, list: *mut bindings_raw::List) { - if list.is_null() { - return; - } - let list = &*list; - let length = list.length as usize; + // === A_Expr (iterative) === + bindings_raw::NodeTag_T_A_Expr => { + let expr = node_ptr as *const bindings_raw::A_Expr; + if collect { + println!("[collect] A_Expr — result_stack={}", self.result_stack.len()); + let node = self.collect_a_expr(&*expr); + self.push_result(node); + } else { + println!("[queue] A_Expr — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_a_expr(&*expr); + } + } - self.stack.reserve(length); + // === FuncCall (iterative) === + bindings_raw::NodeTag_T_FuncCall => { + let fc = node_ptr as *const bindings_raw::FuncCall; + if collect { + println!("[collect] FuncCall — result_stack={}", self.result_stack.len()); + let node = self.collect_func_call(&*fc); + self.push_result(node); + } else { + println!("[queue] FuncCall — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_func_call(&*fc); + } + } - for i in 0..length { - let cell = list.elements.add(i); - let node = (*cell).ptr_value as *const bindings_raw::Node; + // === WindowDef (iterative) === + bindings_raw::NodeTag_T_WindowDef => { + let wd = node_ptr as *const bindings_raw::WindowDef; + if collect { + println!("[collect] WindowDef — result_stack={}", self.result_stack.len()); + let node = self.collect_window_def(&*wd); + self.push_result(node); + } else { + println!("[queue] WindowDef — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_window_def(&*wd); + } + } - self.stack.push(ProcessingNode::with_node(node)); - } - } + // === InsertStmt (iterative) === + bindings_raw::NodeTag_T_InsertStmt => { + let stmt = node_ptr as *const bindings_raw::InsertStmt; + if collect { + println!("[collect] InsertStmt — result_stack={}", self.result_stack.len()); + let node = self.collect_insert_stmt(&*stmt); + self.push_result(node); + } else { + println!("[queue] InsertStmt — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_insert_stmt(&*stmt); + } + } - unsafe fn fetch_list_results(&mut self, list: *const bindings_raw::List) -> Vec { - if list.is_null() { - return Vec::new(); - } - let list = &*list; - let length = list.length as usize; + // === UpdateStmt (iterative) === + bindings_raw::NodeTag_T_UpdateStmt => { + let stmt = node_ptr as *const bindings_raw::UpdateStmt; + if collect { + println!("[collect] UpdateStmt — result_stack={}", self.result_stack.len()); + let node = self.collect_update_stmt(&*stmt); + self.push_result(node); + } else { + println!("[queue] UpdateStmt — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_update_stmt(&*stmt); + } + } - self.fetch_results(length) - } + // === DeleteStmt (iterative) === + bindings_raw::NodeTag_T_DeleteStmt => { + let stmt = node_ptr as *const bindings_raw::DeleteStmt; + if collect { + println!("[collect] DeleteStmt — result_stack={}", self.result_stack.len()); + let node = self.collect_delete_stmt(&*stmt); + self.push_result(node); + } else { + println!("[queue] DeleteStmt — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_delete_stmt(&*stmt); + } + } - unsafe fn queue_into_clause(&mut self, ic: *const bindings_raw::IntoClause) { - if ic.is_null() { - return; - } - let ic_ref = &*ic; - // Some(Box::new(protobuf::IntoClause { - // rel: if ic_ref.rel.is_null() { None } else { Some(convert_range_var(&*ic_ref.rel)) }, - // col_names: self.convert_list_to_nodes(ic_ref.colNames), - // access_method: convert_c_string(ic_ref.accessMethod), - // options: self.convert_list_to_nodes(ic_ref.options), - // on_commit: ic_ref.onCommit as i32 + 1, - // table_space_name: convert_c_string(ic_ref.tableSpaceName), - // view_query: convert_node_boxed(ic_ref.viewQuery), - // skip_data: ic_ref.skipData, - // })); - } + // === List (iterative — items queued) === + bindings_raw::NodeTag_T_List => { + let list = node_ptr as *mut bindings_raw::List; + if collect { + println!("[collect] List — result_stack={}", self.result_stack.len()); + let items = self.fetch_list_results(list); + self.push_result(protobuf::node::Node::List(protobuf::List { items })); + } else { + println!("[queue] List — pushing collect + items"); + self.queue_collect(node_ptr); + self.queue_list_nodes(list); + } + } - unsafe fn fetch_into_clause(&mut self, ic: *const bindings_raw::IntoClause) -> Option> { - if ic.is_null() { - return None; - } - let ic_ref = &*ic; - Some(Box::new(protobuf::IntoClause { - rel: if ic_ref.rel.is_null() { None } else { Some(convert_range_var(&*ic_ref.rel)) }, - col_names: self.fetch_list_results(ic_ref.colNames), - access_method: convert_c_string(ic_ref.accessMethod), - options: self.fetch_list_results(ic_ref.options), - on_commit: ic_ref.onCommit as i32 + 1, - table_space_name: convert_c_string(ic_ref.tableSpaceName), - view_query: self.single_result(ic_ref.viewQuery).map(Box::new), - skip_data: ic_ref.skipData, - })) - } + // === SortBy (iterative) === + bindings_raw::NodeTag_T_SortBy => { + let sb = node_ptr as *const bindings_raw::SortBy; + if collect { + println!("[collect] SortBy — result_stack={}", self.result_stack.len()); + let node = self.collect_sort_by(&*sb); + self.push_result(node); + } else { + println!("[queue] SortBy — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_sort_by(&*sb); + } + } - unsafe fn queue_with_clause(&mut self, wc: *mut bindings_raw::WithClause) { - if wc.is_null() { - return; - } + // === TypeCast (iterative) === + bindings_raw::NodeTag_T_TypeCast => { + let tc = node_ptr as *const bindings_raw::TypeCast; + if collect { + println!("[collect] TypeCast — result_stack={}", self.result_stack.len()); + let node = self.collect_type_cast(&*tc); + self.push_result(node); + } else { + println!("[queue] TypeCast — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_type_cast(&*tc); + } + } - let wc = &*wc; + // === TypeName (iterative) === + bindings_raw::NodeTag_T_TypeName => { + let tn = node_ptr as *const bindings_raw::TypeName; + if collect { + println!("[collect] TypeName — result_stack={}", self.result_stack.len()); + let node = self.collect_type_name(&*tn); + self.push_result(node); + } else { + println!("[queue] TypeName — pushing collect + children"); + self.queue_collect(node_ptr); + self.queue_type_name(&*tn); + } + } - self.queue_list_nodes(wc.ctes); - } + // === A_Const (leaf — no children) === + bindings_raw::NodeTag_T_A_Const => { + let aconst = node_ptr as *const bindings_raw::A_Const; + println!("[leaf] A_Const isnull={}", (*aconst).isnull); + let converted = convert_a_const(&*aconst); + self.push_result(protobuf::node::Node::AConst(converted)); + } - unsafe fn fetch_with_clause(&mut self, wc: *mut bindings_raw::WithClause) -> Option { - if wc.is_null() { - return None; - } + // === A_Star (leaf) === + bindings_raw::NodeTag_T_A_Star => { + println!("[leaf] A_Star"); + self.push_result(protobuf::node::Node::AStar(protobuf::AStar {})); + } - let wc = &*wc; + // === String (leaf) === + bindings_raw::NodeTag_T_String => { + let s = node_ptr as *const bindings_raw::String; + println!("[leaf] String sval={:?}", convert_c_string((*s).sval)); + self.push_result(protobuf::node::Node::String(convert_string(&*s))); + } - Some(protobuf::WithClause { ctes: self.fetch_list_results(wc.ctes), recursive: wc.recursive, location: wc.location }) - } + // === Integer (leaf) === + bindings_raw::NodeTag_T_Integer => { + let i = node_ptr as *const bindings_raw::Integer; + println!("[leaf] Integer ival={}", (*i).ival); + self.push_result(protobuf::node::Node::Integer(protobuf::Integer { ival: (*i).ival })); + } - unsafe fn queue_select_stmt(&mut self, stmt: &bindings_raw::SelectStmt) { - self.queue_list_nodes(stmt.distinctClause); - self.queue_into_clause(stmt.intoClause); - self.queue_list_nodes(stmt.targetList); - self.queue_list_nodes(stmt.fromClause); - self.queue_node(stmt.whereClause); - self.queue_list_nodes(stmt.groupClause); - self.queue_node(stmt.havingClause); - self.queue_list_nodes(stmt.windowClause); - self.queue_list_nodes(stmt.valuesLists); - self.queue_list_nodes(stmt.sortClause); - self.queue_node(stmt.limitOffset); - self.queue_node(stmt.limitCount); - self.queue_list_nodes(stmt.lockingClause); - self.queue_with_clause(stmt.withClause); + // === Float (leaf) === + bindings_raw::NodeTag_T_Float => { + let f = node_ptr as *const bindings_raw::Float; + let fval = if (*f).fval.is_null() { std::string::String::new() } else { CStr::from_ptr((*f).fval).to_string_lossy().to_string() }; + println!("[leaf] Float fval={:?}", fval); + self.push_result(protobuf::node::Node::Float(protobuf::Float { fval })); + } - if !stmt.larg.is_null() { - self.queue_node(stmt.larg as *const bindings_raw::Node); - } + // === Boolean (leaf) === + bindings_raw::NodeTag_T_Boolean => { + let b = node_ptr as *const bindings_raw::Boolean; + println!("[leaf] Boolean boolval={}", (*b).boolval); + self.push_result(protobuf::node::Node::Boolean(protobuf::Boolean { boolval: (*b).boolval })); + } - if !stmt.rarg.is_null() { - self.queue_node(stmt.rarg as *const bindings_raw::Node); - } - } + // === BitString (leaf) === + bindings_raw::NodeTag_T_BitString => { + let bs = node_ptr as *const bindings_raw::BitString; + println!("[leaf] BitString"); + self.push_result(protobuf::node::Node::BitString(convert_bit_string(&*bs))); + } - fn pop_select_stmt(&mut self) -> Option> { - self.result_stack.pop().and_then(|n| match n.node { - Some(protobuf::node::Node::SelectStmt(s)) => Some(s), - _ => None, - }) - } + // === ParamRef (leaf) === + bindings_raw::NodeTag_T_ParamRef => { + let pr = node_ptr as *const bindings_raw::ParamRef; + println!("[leaf] ParamRef number={}", (*pr).number); + self.push_result(protobuf::node::Node::ParamRef(protobuf::ParamRef { number: (*pr).number, location: (*pr).location })); + } - unsafe fn collect_select_stmt(&mut self, stmt: &bindings_raw::SelectStmt) -> protobuf::node::Node { - let a = protobuf::SelectStmt { - distinct_clause: self.fetch_list_results(stmt.distinctClause), - into_clause: self.fetch_into_clause(stmt.intoClause), - target_list: self.fetch_list_results(stmt.targetList), - from_clause: self.fetch_list_results(stmt.fromClause), - where_clause: self.single_result_box(stmt.whereClause), - group_clause: self.fetch_list_results(stmt.groupClause), - group_distinct: stmt.groupDistinct, - having_clause: self.single_result_box(stmt.havingClause), - window_clause: self.fetch_list_results(stmt.windowClause), - values_lists: self.fetch_list_results(stmt.valuesLists), - sort_clause: self.fetch_list_results(stmt.sortClause), - limit_offset: self.single_result_box(stmt.limitOffset), - limit_count: self.single_result_box(stmt.limitCount), - limit_option: stmt.limitOption as i32 + 1, // Protobuf enums have UNDEFINED=0, so C values need +1 - locking_clause: self.fetch_list_results(stmt.lockingClause), - with_clause: self.fetch_with_clause(stmt.withClause), - op: stmt.op as i32 + 1, // Protobuf SetOperation has UNDEFINED=0, so C values need +1 - all: stmt.all, - larg: if stmt.larg.is_null() { None } else { self.pop_select_stmt() }, - rarg: if stmt.rarg.is_null() { None } else { self.pop_select_stmt() }, - }; + // === BoolExpr (iterative) === + bindings_raw::NodeTag_T_BoolExpr => { + let be = node_ptr as *const bindings_raw::BoolExpr; + if collect { + let node = self.collect_bool_expr(&*be); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_bool_expr(&*be); + } + } - protobuf::node::Node::SelectStmt(Box::new(a)) - } -} + // === NullTest (iterative) === + bindings_raw::NodeTag_T_NullTest => { + let nt = node_ptr as *const bindings_raw::NullTest; + if collect { + let node = self.collect_null_test(&*nt); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_null_test(&*nt); + } + } -/// Converts a C Node pointer to a protobuf Node. -unsafe fn convert_node(node_ptr: *const bindings_raw::Node) -> Option { - if node_ptr.is_null() { - return None; - } + // === SubLink (iterative) === + bindings_raw::NodeTag_T_SubLink => { + let sl = node_ptr as *const bindings_raw::SubLink; + if collect { + let node = self.collect_sub_link(&*sl); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_sub_link(&*sl); + } + } - let node_tag = (*node_ptr).type_; - let node = match node_tag { - // Types that need Box - bindings_raw::NodeTag_T_SelectStmt => { - let stmt = node_ptr as *const bindings_raw::SelectStmt; - Some(protobuf::node::Node::SelectStmt(Box::new(convert_select_stmt(&*stmt)))) - } - // TODO: migrate to new approach - // bindings_raw::NodeTag_T_InsertStmt => { - // let stmt = node_ptr as *mut bindings_raw::InsertStmt; - // Some(protobuf::node::Node::InsertStmt(Box::new(convert_insert_stmt(&*stmt)))) - // } - // bindings_raw::NodeTag_T_UpdateStmt => { - // let stmt = node_ptr as *mut bindings_raw::UpdateStmt; - // Some(protobuf::node::Node::UpdateStmt(Box::new(convert_update_stmt(&*stmt)))) - // } - // bindings_raw::NodeTag_T_DeleteStmt => { - // let stmt = node_ptr as *mut bindings_raw::DeleteStmt; - // Some(protobuf::node::Node::DeleteStmt(Box::new(convert_delete_stmt(&*stmt)))) - // } - // bindings_raw::NodeTag_T_ResTarget => { - // let rt = node_ptr as *mut bindings_raw::ResTarget; - // Some(protobuf::node::Node::ResTarget(Box::new(convert_res_target(&*rt)))) - // } - // bindings_raw::NodeTag_T_A_Expr => { - // let expr = node_ptr as *mut bindings_raw::A_Expr; - // Some(protobuf::node::Node::AExpr(Box::new(convert_a_expr(&*expr)))) - // } - // bindings_raw::NodeTag_T_A_Const => { - // let aconst = node_ptr as *mut bindings_raw::A_Const; - // Some(protobuf::node::Node::AConst(convert_a_const(&*aconst))) - // } - // bindings_raw::NodeTag_T_FuncCall => { - // let fc = node_ptr as *mut bindings_raw::FuncCall; - // Some(protobuf::node::Node::FuncCall(Box::new(convert_func_call(&*fc)))) - // } - // bindings_raw::NodeTag_T_TypeCast => { - // let tc = node_ptr as *mut bindings_raw::TypeCast; - // Some(protobuf::node::Node::TypeCast(Box::new(convert_type_cast(&*tc)))) - // } - // bindings_raw::NodeTag_T_JoinExpr => { - // let je = node_ptr as *mut bindings_raw::JoinExpr; - // Some(protobuf::node::Node::JoinExpr(Box::new(convert_join_expr(&*je)))) - // } - // bindings_raw::NodeTag_T_SortBy => { - // let sb = node_ptr as *mut bindings_raw::SortBy; - // Some(protobuf::node::Node::SortBy(Box::new(convert_sort_by(&*sb)))) - // } - // bindings_raw::NodeTag_T_BoolExpr => { - // let be = node_ptr as *mut bindings_raw::BoolExpr; - // Some(protobuf::node::Node::BoolExpr(Box::new(convert_bool_expr(&*be)))) - // } - // bindings_raw::NodeTag_T_SubLink => { - // let sl = node_ptr as *mut bindings_raw::SubLink; - // Some(protobuf::node::Node::SubLink(Box::new(convert_sub_link(&*sl)))) - // } - // bindings_raw::NodeTag_T_NullTest => { - // let nt = node_ptr as *mut bindings_raw::NullTest; - // Some(protobuf::node::Node::NullTest(Box::new(convert_null_test(&*nt)))) - // } - // bindings_raw::NodeTag_T_CaseExpr => { - // let ce = node_ptr as *mut bindings_raw::CaseExpr; - // Some(protobuf::node::Node::CaseExpr(Box::new(convert_case_expr(&*ce)))) - // } - // bindings_raw::NodeTag_T_CaseWhen => { - // let cw = node_ptr as *mut bindings_raw::CaseWhen; - // Some(protobuf::node::Node::CaseWhen(Box::new(convert_case_when(&*cw)))) - // } - // bindings_raw::NodeTag_T_CoalesceExpr => { - // let ce = node_ptr as *mut bindings_raw::CoalesceExpr; - // Some(protobuf::node::Node::CoalesceExpr(Box::new(convert_coalesce_expr(&*ce)))) - // } - // bindings_raw::NodeTag_T_CommonTableExpr => { - // let cte = node_ptr as *mut bindings_raw::CommonTableExpr; - // Some(protobuf::node::Node::CommonTableExpr(Box::new(convert_common_table_expr(&*cte)))) - // } - // bindings_raw::NodeTag_T_ColumnDef => { - // let cd = node_ptr as *mut bindings_raw::ColumnDef; - // Some(protobuf::node::Node::ColumnDef(Box::new(convert_column_def(&*cd)))) - // } - // bindings_raw::NodeTag_T_Constraint => { - // let c = node_ptr as *mut bindings_raw::Constraint; - // Some(protobuf::node::Node::Constraint(Box::new(convert_constraint(&*c)))) - // } - // bindings_raw::NodeTag_T_DropStmt => { - // let ds = node_ptr as *mut bindings_raw::DropStmt; - // Some(protobuf::node::Node::DropStmt(convert_drop_stmt(&*ds))) - // } - // bindings_raw::NodeTag_T_IndexStmt => { - // let is = node_ptr as *mut bindings_raw::IndexStmt; - // Some(protobuf::node::Node::IndexStmt(Box::new(convert_index_stmt(&*is)))) - // } - // bindings_raw::NodeTag_T_IndexElem => { - // let ie = node_ptr as *mut bindings_raw::IndexElem; - // Some(protobuf::node::Node::IndexElem(Box::new(convert_index_elem(&*ie)))) - // } - // bindings_raw::NodeTag_T_DefElem => { - // let de = node_ptr as *mut bindings_raw::DefElem; - // Some(protobuf::node::Node::DefElem(Box::new(convert_def_elem(&*de)))) - // } - // bindings_raw::NodeTag_T_WindowDef => { - // let wd = node_ptr as *mut bindings_raw::WindowDef; - // Some(protobuf::node::Node::WindowDef(Box::new(convert_window_def(&*wd)))) - // } - // // Types that don't need Box - // bindings_raw::NodeTag_T_RangeVar => { - // let rv = node_ptr as *mut bindings_raw::RangeVar; - // Some(protobuf::node::Node::RangeVar(convert_range_var(&*rv))) - // } - // bindings_raw::NodeTag_T_ColumnRef => { - // let cr = node_ptr as *mut bindings_raw::ColumnRef; - // Some(protobuf::node::Node::ColumnRef(convert_column_ref(&*cr))) - // } - // bindings_raw::NodeTag_T_A_Star => Some(protobuf::node::Node::AStar(protobuf::AStar {})), - // bindings_raw::NodeTag_T_TypeName => { - // let tn = node_ptr as *mut bindings_raw::TypeName; - // Some(protobuf::node::Node::TypeName(convert_type_name(&*tn))) - // } - // bindings_raw::NodeTag_T_Alias => { - // let alias = node_ptr as *mut bindings_raw::Alias; - // Some(protobuf::node::Node::Alias(convert_alias(&*alias))) - // } - // bindings_raw::NodeTag_T_String => { - // let s = node_ptr as *mut bindings_raw::String; - // Some(protobuf::node::Node::String(convert_string(&*s))) - // } - // bindings_raw::NodeTag_T_Integer => { - // let i = node_ptr as *mut bindings_raw::Integer; - // Some(protobuf::node::Node::Integer(protobuf::Integer { ival: (*i).ival })) - // } - // bindings_raw::NodeTag_T_Float => { - // let f = node_ptr as *mut bindings_raw::Float; - // let fval = if (*f).fval.is_null() { String::new() } else { CStr::from_ptr((*f).fval).to_string_lossy().to_string() }; - // Some(protobuf::node::Node::Float(protobuf::Float { fval })) - // } - // bindings_raw::NodeTag_T_Boolean => { - // let b = node_ptr as *mut bindings_raw::Boolean; - // Some(protobuf::node::Node::Boolean(protobuf::Boolean { boolval: (*b).boolval })) - // } - // bindings_raw::NodeTag_T_ParamRef => { - // let pr = node_ptr as *mut bindings_raw::ParamRef; - // Some(protobuf::node::Node::ParamRef(protobuf::ParamRef { number: (*pr).number, location: (*pr).location })) - // } - // bindings_raw::NodeTag_T_WithClause => { - // let wc = node_ptr as *mut bindings_raw::WithClause; - // Some(protobuf::node::Node::WithClause(convert_with_clause(&*wc))) - // } - // bindings_raw::NodeTag_T_CreateStmt => { - // let cs = node_ptr as *mut bindings_raw::CreateStmt; - // Some(protobuf::node::Node::CreateStmt(convert_create_stmt(&*cs))) - // } - // bindings_raw::NodeTag_T_List => { - // let list = node_ptr as *mut bindings_raw::List; - // Some(protobuf::node::Node::List(convert_list(&*list))) - // } - // bindings_raw::NodeTag_T_LockingClause => { - // let lc = node_ptr as *mut bindings_raw::LockingClause; - // Some(protobuf::node::Node::LockingClause(convert_locking_clause(&*lc))) - // } - // bindings_raw::NodeTag_T_MinMaxExpr => { - // let mme = node_ptr as *mut bindings_raw::MinMaxExpr; - // Some(protobuf::node::Node::MinMaxExpr(Box::new(convert_min_max_expr(&*mme)))) - // } - // bindings_raw::NodeTag_T_GroupingSet => { - // let gs = node_ptr as *mut bindings_raw::GroupingSet; - // Some(protobuf::node::Node::GroupingSet(convert_grouping_set(&*gs))) - // } - // bindings_raw::NodeTag_T_RangeSubselect => { - // let rs = node_ptr as *mut bindings_raw::RangeSubselect; - // Some(protobuf::node::Node::RangeSubselect(Box::new(convert_range_subselect(&*rs)))) - // } - // bindings_raw::NodeTag_T_A_ArrayExpr => { - // let ae = node_ptr as *mut bindings_raw::A_ArrayExpr; - // Some(protobuf::node::Node::AArrayExpr(convert_a_array_expr(&*ae))) - // } - // bindings_raw::NodeTag_T_A_Indirection => { - // let ai = node_ptr as *mut bindings_raw::A_Indirection; - // Some(protobuf::node::Node::AIndirection(Box::new(convert_a_indirection(&*ai)))) - // } - // bindings_raw::NodeTag_T_A_Indices => { - // let ai = node_ptr as *mut bindings_raw::A_Indices; - // Some(protobuf::node::Node::AIndices(Box::new(convert_a_indices(&*ai)))) - // } - // bindings_raw::NodeTag_T_AlterTableStmt => { - // let ats = node_ptr as *mut bindings_raw::AlterTableStmt; - // Some(protobuf::node::Node::AlterTableStmt(convert_alter_table_stmt(&*ats))) - // } - // bindings_raw::NodeTag_T_AlterTableCmd => { - // let atc = node_ptr as *mut bindings_raw::AlterTableCmd; - // Some(protobuf::node::Node::AlterTableCmd(Box::new(convert_alter_table_cmd(&*atc)))) - // } - // bindings_raw::NodeTag_T_CopyStmt => { - // let cs = node_ptr as *mut bindings_raw::CopyStmt; - // Some(protobuf::node::Node::CopyStmt(Box::new(convert_copy_stmt(&*cs)))) - // } - // bindings_raw::NodeTag_T_TruncateStmt => { - // let ts = node_ptr as *mut bindings_raw::TruncateStmt; - // Some(protobuf::node::Node::TruncateStmt(convert_truncate_stmt(&*ts))) - // } - // bindings_raw::NodeTag_T_ViewStmt => { - // let vs = node_ptr as *mut bindings_raw::ViewStmt; - // Some(protobuf::node::Node::ViewStmt(Box::new(convert_view_stmt(&*vs)))) - // } - // bindings_raw::NodeTag_T_ExplainStmt => { - // let es = node_ptr as *mut bindings_raw::ExplainStmt; - // Some(protobuf::node::Node::ExplainStmt(Box::new(convert_explain_stmt(&*es)))) - // } - // bindings_raw::NodeTag_T_CreateTableAsStmt => { - // let ctas = node_ptr as *mut bindings_raw::CreateTableAsStmt; - // Some(protobuf::node::Node::CreateTableAsStmt(Box::new(convert_create_table_as_stmt(&*ctas)))) - // } - // bindings_raw::NodeTag_T_PrepareStmt => { - // let ps = node_ptr as *mut bindings_raw::PrepareStmt; - // Some(protobuf::node::Node::PrepareStmt(Box::new(convert_prepare_stmt(&*ps)))) - // } - // bindings_raw::NodeTag_T_ExecuteStmt => { - // let es = node_ptr as *mut bindings_raw::ExecuteStmt; - // Some(protobuf::node::Node::ExecuteStmt(convert_execute_stmt(&*es))) - // } - // bindings_raw::NodeTag_T_DeallocateStmt => { - // let ds = node_ptr as *mut bindings_raw::DeallocateStmt; - // Some(protobuf::node::Node::DeallocateStmt(convert_deallocate_stmt(&*ds))) - // } - // bindings_raw::NodeTag_T_SetToDefault => { - // let std = node_ptr as *mut bindings_raw::SetToDefault; - // Some(protobuf::node::Node::SetToDefault(Box::new(convert_set_to_default(&*std)))) - // } - // bindings_raw::NodeTag_T_MultiAssignRef => { - // let mar = node_ptr as *mut bindings_raw::MultiAssignRef; - // Some(protobuf::node::Node::MultiAssignRef(Box::new(convert_multi_assign_ref(&*mar)))) - // } - // bindings_raw::NodeTag_T_RowExpr => { - // let re = node_ptr as *mut bindings_raw::RowExpr; - // Some(protobuf::node::Node::RowExpr(Box::new(convert_row_expr(&*re)))) - // } - // bindings_raw::NodeTag_T_PartitionElem => { - // let pe = node_ptr as *mut bindings_raw::PartitionElem; - // Some(protobuf::node::Node::PartitionElem(Box::new(convert_partition_elem(&*pe)))) - // } - // bindings_raw::NodeTag_T_PartitionRangeDatum => { - // let prd = node_ptr as *mut bindings_raw::PartitionRangeDatum; - // Some(protobuf::node::Node::PartitionRangeDatum(Box::new(convert_partition_range_datum(&*prd)))) - // } - // bindings_raw::NodeTag_T_TransactionStmt => { - // let ts = node_ptr as *mut bindings_raw::TransactionStmt; - // Some(protobuf::node::Node::TransactionStmt(convert_transaction_stmt(&*ts))) - // } - // bindings_raw::NodeTag_T_VacuumStmt => { - // let vs = node_ptr as *mut bindings_raw::VacuumStmt; - // Some(protobuf::node::Node::VacuumStmt(convert_vacuum_stmt(&*vs))) - // } - // bindings_raw::NodeTag_T_VacuumRelation => { - // let vr = node_ptr as *mut bindings_raw::VacuumRelation; - // Some(protobuf::node::Node::VacuumRelation(convert_vacuum_relation(&*vr))) - // } - // bindings_raw::NodeTag_T_VariableSetStmt => { - // let vss = node_ptr as *mut bindings_raw::VariableSetStmt; - // Some(protobuf::node::Node::VariableSetStmt(convert_variable_set_stmt(&*vss))) - // } - // bindings_raw::NodeTag_T_VariableShowStmt => { - // let vss = node_ptr as *mut bindings_raw::VariableShowStmt; - // Some(protobuf::node::Node::VariableShowStmt(convert_variable_show_stmt(&*vss))) - // } - // bindings_raw::NodeTag_T_CreateSeqStmt => { - // let css = node_ptr as *mut bindings_raw::CreateSeqStmt; - // Some(protobuf::node::Node::CreateSeqStmt(convert_create_seq_stmt(&*css))) - // } - // bindings_raw::NodeTag_T_DoStmt => { - // let ds = node_ptr as *mut bindings_raw::DoStmt; - // Some(protobuf::node::Node::DoStmt(convert_do_stmt(&*ds))) - // } - // bindings_raw::NodeTag_T_LockStmt => { - // let ls = node_ptr as *mut bindings_raw::LockStmt; - // Some(protobuf::node::Node::LockStmt(convert_lock_stmt(&*ls))) - // } - // bindings_raw::NodeTag_T_CreateSchemaStmt => { - // let css = node_ptr as *mut bindings_raw::CreateSchemaStmt; - // Some(protobuf::node::Node::CreateSchemaStmt(convert_create_schema_stmt(&*css))) - // } - // bindings_raw::NodeTag_T_RenameStmt => { - // let rs = node_ptr as *mut bindings_raw::RenameStmt; - // Some(protobuf::node::Node::RenameStmt(Box::new(convert_rename_stmt(&*rs)))) - // } - // bindings_raw::NodeTag_T_CreateFunctionStmt => { - // let cfs = node_ptr as *mut bindings_raw::CreateFunctionStmt; - // Some(protobuf::node::Node::CreateFunctionStmt(Box::new(convert_create_function_stmt(&*cfs)))) - // } - // bindings_raw::NodeTag_T_AlterOwnerStmt => { - // let aos = node_ptr as *mut bindings_raw::AlterOwnerStmt; - // Some(protobuf::node::Node::AlterOwnerStmt(Box::new(convert_alter_owner_stmt(&*aos)))) - // } - // bindings_raw::NodeTag_T_AlterSeqStmt => { - // let ass = node_ptr as *mut bindings_raw::AlterSeqStmt; - // Some(protobuf::node::Node::AlterSeqStmt(convert_alter_seq_stmt(&*ass))) - // } - // bindings_raw::NodeTag_T_CreateEnumStmt => { - // let ces = node_ptr as *mut bindings_raw::CreateEnumStmt; - // Some(protobuf::node::Node::CreateEnumStmt(convert_create_enum_stmt(&*ces))) - // } - // bindings_raw::NodeTag_T_ObjectWithArgs => { - // let owa = node_ptr as *mut bindings_raw::ObjectWithArgs; - // Some(protobuf::node::Node::ObjectWithArgs(convert_object_with_args(&*owa))) - // } - // bindings_raw::NodeTag_T_FunctionParameter => { - // let fp = node_ptr as *mut bindings_raw::FunctionParameter; - // Some(protobuf::node::Node::FunctionParameter(Box::new(convert_function_parameter(&*fp)))) - // } - // bindings_raw::NodeTag_T_NotifyStmt => { - // let ns = node_ptr as *mut bindings_raw::NotifyStmt; - // Some(protobuf::node::Node::NotifyStmt(convert_notify_stmt(&*ns))) - // } - // bindings_raw::NodeTag_T_ListenStmt => { - // let ls = node_ptr as *mut bindings_raw::ListenStmt; - // Some(protobuf::node::Node::ListenStmt(convert_listen_stmt(&*ls))) - // } - // bindings_raw::NodeTag_T_UnlistenStmt => { - // let us = node_ptr as *mut bindings_raw::UnlistenStmt; - // Some(protobuf::node::Node::UnlistenStmt(convert_unlisten_stmt(&*us))) - // } - // bindings_raw::NodeTag_T_DiscardStmt => { - // let ds = node_ptr as *mut bindings_raw::DiscardStmt; - // Some(protobuf::node::Node::DiscardStmt(convert_discard_stmt(&*ds))) - // } - // bindings_raw::NodeTag_T_CollateClause => { - // let cc = node_ptr as *mut bindings_raw::CollateClause; - // Some(protobuf::node::Node::CollateClause(Box::new(convert_collate_clause(&*cc)))) - // } - // bindings_raw::NodeTag_T_CoerceToDomain => { - // let ctd = node_ptr as *mut bindings_raw::CoerceToDomain; - // Some(protobuf::node::Node::CoerceToDomain(Box::new(convert_coerce_to_domain(&*ctd)))) - // } - // bindings_raw::NodeTag_T_CompositeTypeStmt => { - // let cts = node_ptr as *mut bindings_raw::CompositeTypeStmt; - // Some(protobuf::node::Node::CompositeTypeStmt(convert_composite_type_stmt(&*cts))) - // } - // bindings_raw::NodeTag_T_CreateDomainStmt => { - // let cds = node_ptr as *mut bindings_raw::CreateDomainStmt; - // Some(protobuf::node::Node::CreateDomainStmt(Box::new(convert_create_domain_stmt(&*cds)))) - // } - // bindings_raw::NodeTag_T_CreateExtensionStmt => { - // let ces = node_ptr as *mut bindings_raw::CreateExtensionStmt; - // Some(protobuf::node::Node::CreateExtensionStmt(convert_create_extension_stmt(&*ces))) - // } - // bindings_raw::NodeTag_T_CreatePublicationStmt => { - // let cps = node_ptr as *mut bindings_raw::CreatePublicationStmt; - // Some(protobuf::node::Node::CreatePublicationStmt(convert_create_publication_stmt(&*cps))) - // } - // bindings_raw::NodeTag_T_AlterPublicationStmt => { - // let aps = node_ptr as *mut bindings_raw::AlterPublicationStmt; - // Some(protobuf::node::Node::AlterPublicationStmt(convert_alter_publication_stmt(&*aps))) - // } - // bindings_raw::NodeTag_T_CreateSubscriptionStmt => { - // let css = node_ptr as *mut bindings_raw::CreateSubscriptionStmt; - // Some(protobuf::node::Node::CreateSubscriptionStmt(convert_create_subscription_stmt(&*css))) - // } - // bindings_raw::NodeTag_T_AlterSubscriptionStmt => { - // let ass = node_ptr as *mut bindings_raw::AlterSubscriptionStmt; - // Some(protobuf::node::Node::AlterSubscriptionStmt(convert_alter_subscription_stmt(&*ass))) - // } - // bindings_raw::NodeTag_T_CreateTrigStmt => { - // let cts = node_ptr as *mut bindings_raw::CreateTrigStmt; - // Some(protobuf::node::Node::CreateTrigStmt(Box::new(convert_create_trig_stmt(&*cts)))) - // } - // bindings_raw::NodeTag_T_PublicationObjSpec => { - // let pos = node_ptr as *mut bindings_raw::PublicationObjSpec; - // Some(protobuf::node::Node::PublicationObjSpec(Box::new(convert_publication_obj_spec(&*pos)))) - // } - // bindings_raw::NodeTag_T_PublicationTable => { - // let pt = node_ptr as *mut bindings_raw::PublicationTable; - // Some(protobuf::node::Node::PublicationTable(Box::new(convert_publication_table(&*pt)))) - // } - // bindings_raw::NodeTag_T_CheckPointStmt => Some(protobuf::node::Node::CheckPointStmt(protobuf::CheckPointStmt {})), - // bindings_raw::NodeTag_T_CallStmt => { - // let cs = node_ptr as *mut bindings_raw::CallStmt; - // Some(protobuf::node::Node::CallStmt(Box::new(convert_call_stmt(&*cs)))) - // } - // bindings_raw::NodeTag_T_RuleStmt => { - // let rs = node_ptr as *mut bindings_raw::RuleStmt; - // Some(protobuf::node::Node::RuleStmt(Box::new(convert_rule_stmt(&*rs)))) - // } - // bindings_raw::NodeTag_T_GrantStmt => { - // let gs = node_ptr as *mut bindings_raw::GrantStmt; - // Some(protobuf::node::Node::GrantStmt(convert_grant_stmt(&*gs))) - // } - // bindings_raw::NodeTag_T_GrantRoleStmt => { - // let grs = node_ptr as *mut bindings_raw::GrantRoleStmt; - // Some(protobuf::node::Node::GrantRoleStmt(convert_grant_role_stmt(&*grs))) - // } - // bindings_raw::NodeTag_T_RefreshMatViewStmt => { - // let rmvs = node_ptr as *mut bindings_raw::RefreshMatViewStmt; - // Some(protobuf::node::Node::RefreshMatViewStmt(convert_refresh_mat_view_stmt(&*rmvs))) - // } - // bindings_raw::NodeTag_T_MergeStmt => { - // let ms = node_ptr as *mut bindings_raw::MergeStmt; - // Some(protobuf::node::Node::MergeStmt(Box::new(convert_merge_stmt(&*ms)))) - // } - // bindings_raw::NodeTag_T_MergeAction => { - // let ma = node_ptr as *mut bindings_raw::MergeAction; - // Some(protobuf::node::Node::MergeAction(Box::new(convert_merge_action(&*ma)))) - // } - // bindings_raw::NodeTag_T_RangeFunction => { - // let rf = node_ptr as *mut bindings_raw::RangeFunction; - // Some(protobuf::node::Node::RangeFunction(convert_range_function(&*rf))) - // } - // bindings_raw::NodeTag_T_MergeWhenClause => { - // let mwc = node_ptr as *mut bindings_raw::MergeWhenClause; - // Some(protobuf::node::Node::MergeWhenClause(Box::new(convert_merge_when_clause(&*mwc)))) - // } - // bindings_raw::NodeTag_T_AccessPriv => { - // let ap = node_ptr as *mut bindings_raw::AccessPriv; - // Some(protobuf::node::Node::AccessPriv(convert_access_priv(&*ap))) - // } - // bindings_raw::NodeTag_T_RoleSpec => { - // let rs = node_ptr as *mut bindings_raw::RoleSpec; - // Some(protobuf::node::Node::RoleSpec(convert_role_spec(&*rs))) - // } - // bindings_raw::NodeTag_T_BitString => { - // let bs = node_ptr as *mut bindings_raw::BitString; - // Some(protobuf::node::Node::BitString(convert_bit_string(&*bs))) - // } - // bindings_raw::NodeTag_T_BooleanTest => { - // let bt = node_ptr as *mut bindings_raw::BooleanTest; - // Some(protobuf::node::Node::BooleanTest(Box::new(convert_boolean_test(&*bt)))) - // } - // bindings_raw::NodeTag_T_CreateRangeStmt => { - // let crs = node_ptr as *mut bindings_raw::CreateRangeStmt; - // Some(protobuf::node::Node::CreateRangeStmt(convert_create_range_stmt(&*crs))) - // } - // bindings_raw::NodeTag_T_AlterEnumStmt => { - // let aes = node_ptr as *mut bindings_raw::AlterEnumStmt; - // Some(protobuf::node::Node::AlterEnumStmt(convert_alter_enum_stmt(&*aes))) - // } - // bindings_raw::NodeTag_T_ClosePortalStmt => { - // let cps = node_ptr as *mut bindings_raw::ClosePortalStmt; - // Some(protobuf::node::Node::ClosePortalStmt(convert_close_portal_stmt(&*cps))) - // } - // bindings_raw::NodeTag_T_FetchStmt => { - // let fs = node_ptr as *mut bindings_raw::FetchStmt; - // Some(protobuf::node::Node::FetchStmt(convert_fetch_stmt(&*fs))) - // } - // bindings_raw::NodeTag_T_DeclareCursorStmt => { - // let dcs = node_ptr as *mut bindings_raw::DeclareCursorStmt; - // Some(protobuf::node::Node::DeclareCursorStmt(Box::new(convert_declare_cursor_stmt(&*dcs)))) - // } - // bindings_raw::NodeTag_T_DefineStmt => { - // let ds = node_ptr as *mut bindings_raw::DefineStmt; - // Some(protobuf::node::Node::DefineStmt(convert_define_stmt(&*ds))) - // } - // bindings_raw::NodeTag_T_CommentStmt => { - // let cs = node_ptr as *mut bindings_raw::CommentStmt; - // Some(protobuf::node::Node::CommentStmt(Box::new(convert_comment_stmt(&*cs)))) - // } - // bindings_raw::NodeTag_T_SecLabelStmt => { - // let sls = node_ptr as *mut bindings_raw::SecLabelStmt; - // Some(protobuf::node::Node::SecLabelStmt(Box::new(convert_sec_label_stmt(&*sls)))) - // } - // bindings_raw::NodeTag_T_CreateRoleStmt => { - // let crs = node_ptr as *mut bindings_raw::CreateRoleStmt; - // Some(protobuf::node::Node::CreateRoleStmt(convert_create_role_stmt(&*crs))) - // } - // bindings_raw::NodeTag_T_AlterRoleStmt => { - // let ars = node_ptr as *mut bindings_raw::AlterRoleStmt; - // Some(protobuf::node::Node::AlterRoleStmt(convert_alter_role_stmt(&*ars))) - // } - // bindings_raw::NodeTag_T_AlterRoleSetStmt => { - // let arss = node_ptr as *mut bindings_raw::AlterRoleSetStmt; - // Some(protobuf::node::Node::AlterRoleSetStmt(convert_alter_role_set_stmt(&*arss))) - // } - // bindings_raw::NodeTag_T_DropRoleStmt => { - // let drs = node_ptr as *mut bindings_raw::DropRoleStmt; - // Some(protobuf::node::Node::DropRoleStmt(convert_drop_role_stmt(&*drs))) - // } - // bindings_raw::NodeTag_T_CreatePolicyStmt => { - // let cps = node_ptr as *mut bindings_raw::CreatePolicyStmt; - // Some(protobuf::node::Node::CreatePolicyStmt(Box::new(convert_create_policy_stmt(&*cps)))) - // } - // bindings_raw::NodeTag_T_AlterPolicyStmt => { - // let aps = node_ptr as *mut bindings_raw::AlterPolicyStmt; - // Some(protobuf::node::Node::AlterPolicyStmt(Box::new(convert_alter_policy_stmt(&*aps)))) - // } - // bindings_raw::NodeTag_T_CreateEventTrigStmt => { - // let cets = node_ptr as *mut bindings_raw::CreateEventTrigStmt; - // Some(protobuf::node::Node::CreateEventTrigStmt(convert_create_event_trig_stmt(&*cets))) - // } - // bindings_raw::NodeTag_T_AlterEventTrigStmt => { - // let aets = node_ptr as *mut bindings_raw::AlterEventTrigStmt; - // Some(protobuf::node::Node::AlterEventTrigStmt(convert_alter_event_trig_stmt(&*aets))) - // } - // bindings_raw::NodeTag_T_CreatePLangStmt => { - // let cpls = node_ptr as *mut bindings_raw::CreatePLangStmt; - // Some(protobuf::node::Node::CreatePlangStmt(convert_create_plang_stmt(&*cpls))) - // } - // bindings_raw::NodeTag_T_CreateAmStmt => { - // let cas = node_ptr as *mut bindings_raw::CreateAmStmt; - // Some(protobuf::node::Node::CreateAmStmt(convert_create_am_stmt(&*cas))) - // } - // bindings_raw::NodeTag_T_CreateOpClassStmt => { - // let cocs = node_ptr as *mut bindings_raw::CreateOpClassStmt; - // Some(protobuf::node::Node::CreateOpClassStmt(convert_create_op_class_stmt(&*cocs))) - // } - // bindings_raw::NodeTag_T_CreateOpClassItem => { - // let coci = node_ptr as *mut bindings_raw::CreateOpClassItem; - // Some(protobuf::node::Node::CreateOpClassItem(convert_create_op_class_item(&*coci))) - // } - // bindings_raw::NodeTag_T_CreateOpFamilyStmt => { - // let cofs = node_ptr as *mut bindings_raw::CreateOpFamilyStmt; - // Some(protobuf::node::Node::CreateOpFamilyStmt(convert_create_op_family_stmt(&*cofs))) - // } - // bindings_raw::NodeTag_T_AlterOpFamilyStmt => { - // let aofs = node_ptr as *mut bindings_raw::AlterOpFamilyStmt; - // Some(protobuf::node::Node::AlterOpFamilyStmt(convert_alter_op_family_stmt(&*aofs))) - // } - // bindings_raw::NodeTag_T_CreateFdwStmt => { - // let cfds = node_ptr as *mut bindings_raw::CreateFdwStmt; - // Some(protobuf::node::Node::CreateFdwStmt(convert_create_fdw_stmt(&*cfds))) - // } - // bindings_raw::NodeTag_T_AlterFdwStmt => { - // let afds = node_ptr as *mut bindings_raw::AlterFdwStmt; - // Some(protobuf::node::Node::AlterFdwStmt(convert_alter_fdw_stmt(&*afds))) - // } - // bindings_raw::NodeTag_T_CreateForeignServerStmt => { - // let cfss = node_ptr as *mut bindings_raw::CreateForeignServerStmt; - // Some(protobuf::node::Node::CreateForeignServerStmt(convert_create_foreign_server_stmt(&*cfss))) - // } - // bindings_raw::NodeTag_T_AlterForeignServerStmt => { - // let afss = node_ptr as *mut bindings_raw::AlterForeignServerStmt; - // Some(protobuf::node::Node::AlterForeignServerStmt(convert_alter_foreign_server_stmt(&*afss))) - // } - // bindings_raw::NodeTag_T_CreateForeignTableStmt => { - // let cfts = node_ptr as *mut bindings_raw::CreateForeignTableStmt; - // Some(protobuf::node::Node::CreateForeignTableStmt(convert_create_foreign_table_stmt(&*cfts))) - // } - // bindings_raw::NodeTag_T_CreateUserMappingStmt => { - // let cums = node_ptr as *mut bindings_raw::CreateUserMappingStmt; - // Some(protobuf::node::Node::CreateUserMappingStmt(convert_create_user_mapping_stmt(&*cums))) - // } - // bindings_raw::NodeTag_T_AlterUserMappingStmt => { - // let aums = node_ptr as *mut bindings_raw::AlterUserMappingStmt; - // Some(protobuf::node::Node::AlterUserMappingStmt(convert_alter_user_mapping_stmt(&*aums))) - // } - // bindings_raw::NodeTag_T_DropUserMappingStmt => { - // let dums = node_ptr as *mut bindings_raw::DropUserMappingStmt; - // Some(protobuf::node::Node::DropUserMappingStmt(convert_drop_user_mapping_stmt(&*dums))) - // } - // bindings_raw::NodeTag_T_ImportForeignSchemaStmt => { - // let ifss = node_ptr as *mut bindings_raw::ImportForeignSchemaStmt; - // Some(protobuf::node::Node::ImportForeignSchemaStmt(convert_import_foreign_schema_stmt(&*ifss))) - // } - // bindings_raw::NodeTag_T_CreateTableSpaceStmt => { - // let ctss = node_ptr as *mut bindings_raw::CreateTableSpaceStmt; - // Some(protobuf::node::Node::CreateTableSpaceStmt(convert_create_table_space_stmt(&*ctss))) - // } - // bindings_raw::NodeTag_T_DropTableSpaceStmt => { - // let dtss = node_ptr as *mut bindings_raw::DropTableSpaceStmt; - // Some(protobuf::node::Node::DropTableSpaceStmt(convert_drop_table_space_stmt(&*dtss))) - // } - // bindings_raw::NodeTag_T_AlterTableSpaceOptionsStmt => { - // let atsos = node_ptr as *mut bindings_raw::AlterTableSpaceOptionsStmt; - // Some(protobuf::node::Node::AlterTableSpaceOptionsStmt(convert_alter_table_space_options_stmt(&*atsos))) - // } - // bindings_raw::NodeTag_T_AlterTableMoveAllStmt => { - // let atmas = node_ptr as *mut bindings_raw::AlterTableMoveAllStmt; - // Some(protobuf::node::Node::AlterTableMoveAllStmt(convert_alter_table_move_all_stmt(&*atmas))) - // } - // bindings_raw::NodeTag_T_AlterExtensionStmt => { - // let aes = node_ptr as *mut bindings_raw::AlterExtensionStmt; - // Some(protobuf::node::Node::AlterExtensionStmt(convert_alter_extension_stmt(&*aes))) - // } - // bindings_raw::NodeTag_T_AlterExtensionContentsStmt => { - // let aecs = node_ptr as *mut bindings_raw::AlterExtensionContentsStmt; - // Some(protobuf::node::Node::AlterExtensionContentsStmt(Box::new(convert_alter_extension_contents_stmt(&*aecs)))) - // } - // bindings_raw::NodeTag_T_AlterDomainStmt => { - // let ads = node_ptr as *mut bindings_raw::AlterDomainStmt; - // Some(protobuf::node::Node::AlterDomainStmt(Box::new(convert_alter_domain_stmt(&*ads)))) - // } - // bindings_raw::NodeTag_T_AlterFunctionStmt => { - // let afs = node_ptr as *mut bindings_raw::AlterFunctionStmt; - // Some(protobuf::node::Node::AlterFunctionStmt(convert_alter_function_stmt(&*afs))) - // } - // bindings_raw::NodeTag_T_AlterOperatorStmt => { - // let aos = node_ptr as *mut bindings_raw::AlterOperatorStmt; - // Some(protobuf::node::Node::AlterOperatorStmt(convert_alter_operator_stmt(&*aos))) - // } - // bindings_raw::NodeTag_T_AlterTypeStmt => { - // let ats = node_ptr as *mut bindings_raw::AlterTypeStmt; - // Some(protobuf::node::Node::AlterTypeStmt(convert_alter_type_stmt(&*ats))) - // } - // bindings_raw::NodeTag_T_AlterObjectSchemaStmt => { - // let aoss = node_ptr as *mut bindings_raw::AlterObjectSchemaStmt; - // Some(protobuf::node::Node::AlterObjectSchemaStmt(Box::new(convert_alter_object_schema_stmt(&*aoss)))) - // } - // bindings_raw::NodeTag_T_AlterObjectDependsStmt => { - // let aods = node_ptr as *mut bindings_raw::AlterObjectDependsStmt; - // Some(protobuf::node::Node::AlterObjectDependsStmt(Box::new(convert_alter_object_depends_stmt(&*aods)))) - // } - // bindings_raw::NodeTag_T_AlterCollationStmt => { - // let acs = node_ptr as *mut bindings_raw::AlterCollationStmt; - // Some(protobuf::node::Node::AlterCollationStmt(convert_alter_collation_stmt(&*acs))) - // } - // bindings_raw::NodeTag_T_AlterDefaultPrivilegesStmt => { - // let adps = node_ptr as *mut bindings_raw::AlterDefaultPrivilegesStmt; - // Some(protobuf::node::Node::AlterDefaultPrivilegesStmt(convert_alter_default_privileges_stmt(&*adps))) - // } - // bindings_raw::NodeTag_T_CreateCastStmt => { - // let ccs = node_ptr as *mut bindings_raw::CreateCastStmt; - // Some(protobuf::node::Node::CreateCastStmt(convert_create_cast_stmt(&*ccs))) - // } - // bindings_raw::NodeTag_T_CreateTransformStmt => { - // let cts = node_ptr as *mut bindings_raw::CreateTransformStmt; - // Some(protobuf::node::Node::CreateTransformStmt(convert_create_transform_stmt(&*cts))) - // } - // bindings_raw::NodeTag_T_CreateConversionStmt => { - // let ccs = node_ptr as *mut bindings_raw::CreateConversionStmt; - // Some(protobuf::node::Node::CreateConversionStmt(convert_create_conversion_stmt(&*ccs))) - // } - // bindings_raw::NodeTag_T_AlterTSDictionaryStmt => { - // let atds = node_ptr as *mut bindings_raw::AlterTSDictionaryStmt; - // Some(protobuf::node::Node::AlterTsdictionaryStmt(convert_alter_ts_dictionary_stmt(&*atds))) - // } - // bindings_raw::NodeTag_T_AlterTSConfigurationStmt => { - // let atcs = node_ptr as *mut bindings_raw::AlterTSConfigurationStmt; - // Some(protobuf::node::Node::AlterTsconfigurationStmt(convert_alter_ts_configuration_stmt(&*atcs))) - // } - // bindings_raw::NodeTag_T_CreatedbStmt => { - // let cds = node_ptr as *mut bindings_raw::CreatedbStmt; - // Some(protobuf::node::Node::CreatedbStmt(convert_createdb_stmt(&*cds))) - // } - // bindings_raw::NodeTag_T_DropdbStmt => { - // let dds = node_ptr as *mut bindings_raw::DropdbStmt; - // Some(protobuf::node::Node::DropdbStmt(convert_dropdb_stmt(&*dds))) - // } - // bindings_raw::NodeTag_T_AlterDatabaseStmt => { - // let ads = node_ptr as *mut bindings_raw::AlterDatabaseStmt; - // Some(protobuf::node::Node::AlterDatabaseStmt(convert_alter_database_stmt(&*ads))) - // } - // bindings_raw::NodeTag_T_AlterDatabaseSetStmt => { - // let adss = node_ptr as *mut bindings_raw::AlterDatabaseSetStmt; - // Some(protobuf::node::Node::AlterDatabaseSetStmt(convert_alter_database_set_stmt(&*adss))) - // } - // bindings_raw::NodeTag_T_AlterDatabaseRefreshCollStmt => { - // let adrcs = node_ptr as *mut bindings_raw::AlterDatabaseRefreshCollStmt; - // Some(protobuf::node::Node::AlterDatabaseRefreshCollStmt(convert_alter_database_refresh_coll_stmt(&*adrcs))) - // } - // bindings_raw::NodeTag_T_AlterSystemStmt => { - // let ass = node_ptr as *mut bindings_raw::AlterSystemStmt; - // Some(protobuf::node::Node::AlterSystemStmt(convert_alter_system_stmt(&*ass))) - // } - // bindings_raw::NodeTag_T_ClusterStmt => { - // let cs = node_ptr as *mut bindings_raw::ClusterStmt; - // Some(protobuf::node::Node::ClusterStmt(convert_cluster_stmt(&*cs))) - // } - // bindings_raw::NodeTag_T_ReindexStmt => { - // let rs = node_ptr as *mut bindings_raw::ReindexStmt; - // Some(protobuf::node::Node::ReindexStmt(convert_reindex_stmt(&*rs))) - // } - // bindings_raw::NodeTag_T_ConstraintsSetStmt => { - // let css = node_ptr as *mut bindings_raw::ConstraintsSetStmt; - // Some(protobuf::node::Node::ConstraintsSetStmt(convert_constraints_set_stmt(&*css))) - // } - // bindings_raw::NodeTag_T_LoadStmt => { - // let ls = node_ptr as *mut bindings_raw::LoadStmt; - // Some(protobuf::node::Node::LoadStmt(convert_load_stmt(&*ls))) - // } - // bindings_raw::NodeTag_T_DropOwnedStmt => { - // let dos = node_ptr as *mut bindings_raw::DropOwnedStmt; - // Some(protobuf::node::Node::DropOwnedStmt(convert_drop_owned_stmt(&*dos))) - // } - // bindings_raw::NodeTag_T_ReassignOwnedStmt => { - // let ros = node_ptr as *mut bindings_raw::ReassignOwnedStmt; - // Some(protobuf::node::Node::ReassignOwnedStmt(convert_reassign_owned_stmt(&*ros))) - // } - // bindings_raw::NodeTag_T_DropSubscriptionStmt => { - // let dss = node_ptr as *mut bindings_raw::DropSubscriptionStmt; - // Some(protobuf::node::Node::DropSubscriptionStmt(convert_drop_subscription_stmt(&*dss))) - // } - // bindings_raw::NodeTag_T_TableFunc => { - // let tf = node_ptr as *mut bindings_raw::TableFunc; - // Some(protobuf::node::Node::TableFunc(Box::new(convert_table_func(&*tf)))) - // } - // bindings_raw::NodeTag_T_IntoClause => { - // let ic = node_ptr as *mut bindings_raw::IntoClause; - // Some(protobuf::node::Node::IntoClause(Box::new(convert_into_clause_node(&*ic)))) - // } - // bindings_raw::NodeTag_T_TableLikeClause => { - // let tlc = node_ptr as *mut bindings_raw::TableLikeClause; - // Some(protobuf::node::Node::TableLikeClause(convert_table_like_clause(&*tlc))) - // } - // bindings_raw::NodeTag_T_RangeTableFunc => { - // let rtf = node_ptr as *mut bindings_raw::RangeTableFunc; - // Some(protobuf::node::Node::RangeTableFunc(Box::new(convert_range_table_func(&*rtf)))) - // } - // bindings_raw::NodeTag_T_RangeTableFuncCol => { - // let rtfc = node_ptr as *mut bindings_raw::RangeTableFuncCol; - // Some(protobuf::node::Node::RangeTableFuncCol(Box::new(convert_range_table_func_col(&*rtfc)))) - // } - // bindings_raw::NodeTag_T_RangeTableSample => { - // let rts = node_ptr as *mut bindings_raw::RangeTableSample; - // Some(protobuf::node::Node::RangeTableSample(Box::new(convert_range_table_sample(&*rts)))) - // } - // bindings_raw::NodeTag_T_PartitionSpec => { - // let ps = node_ptr as *mut bindings_raw::PartitionSpec; - // Some(protobuf::node::Node::PartitionSpec(convert_partition_spec(&*ps))) - // } - // bindings_raw::NodeTag_T_PartitionBoundSpec => { - // let pbs = node_ptr as *mut bindings_raw::PartitionBoundSpec; - // Some(protobuf::node::Node::PartitionBoundSpec(convert_partition_bound_spec(&*pbs))) - // } - // bindings_raw::NodeTag_T_PartitionCmd => { - // let pc = node_ptr as *mut bindings_raw::PartitionCmd; - // Some(protobuf::node::Node::PartitionCmd(convert_partition_cmd(&*pc))) - // } - // bindings_raw::NodeTag_T_SinglePartitionSpec => Some(protobuf::node::Node::SinglePartitionSpec(protobuf::SinglePartitionSpec {})), - // bindings_raw::NodeTag_T_InferClause => { - // let ic = node_ptr as *mut bindings_raw::InferClause; - // convert_infer_clause(ic).map(|c| protobuf::node::Node::InferClause(c)) - // } - // bindings_raw::NodeTag_T_OnConflictClause => { - // let occ = node_ptr as *mut bindings_raw::OnConflictClause; - // Some(protobuf::node::Node::OnConflictClause(Box::new(convert_on_conflict_clause_node(&*occ)))) - // } - // bindings_raw::NodeTag_T_TriggerTransition => { - // let tt = node_ptr as *mut bindings_raw::TriggerTransition; - // Some(protobuf::node::Node::TriggerTransition(convert_trigger_transition(&*tt))) - // } - // bindings_raw::NodeTag_T_CTESearchClause => { - // let csc = node_ptr as *mut bindings_raw::CTESearchClause; - // Some(protobuf::node::Node::CtesearchClause(convert_cte_search_clause(&*csc))) - // } - // bindings_raw::NodeTag_T_CTECycleClause => { - // let ccc = node_ptr as *mut bindings_raw::CTECycleClause; - // Some(protobuf::node::Node::CtecycleClause(Box::new(convert_cte_cycle_clause(&*ccc)))) - // } - // bindings_raw::NodeTag_T_CreateStatsStmt => { - // let css = node_ptr as *mut bindings_raw::CreateStatsStmt; - // Some(protobuf::node::Node::CreateStatsStmt(convert_create_stats_stmt(&*css))) - // } - // bindings_raw::NodeTag_T_AlterStatsStmt => { - // let ass = node_ptr as *mut bindings_raw::AlterStatsStmt; - // Some(protobuf::node::Node::AlterStatsStmt(Box::new(convert_alter_stats_stmt(&*ass)))) - // } - // bindings_raw::NodeTag_T_StatsElem => { - // let se = node_ptr as *mut bindings_raw::StatsElem; - // Some(protobuf::node::Node::StatsElem(Box::new(convert_stats_elem(&*se)))) - // } - // bindings_raw::NodeTag_T_SQLValueFunction => { - // let svf = node_ptr as *mut bindings_raw::SQLValueFunction; - // Some(protobuf::node::Node::SqlvalueFunction(Box::new(convert_sql_value_function(&*svf)))) - // } - // bindings_raw::NodeTag_T_XmlExpr => { - // let xe = node_ptr as *mut bindings_raw::XmlExpr; - // Some(protobuf::node::Node::XmlExpr(Box::new(convert_xml_expr(&*xe)))) - // } - // bindings_raw::NodeTag_T_XmlSerialize => { - // let xs = node_ptr as *mut bindings_raw::XmlSerialize; - // Some(protobuf::node::Node::XmlSerialize(Box::new(convert_xml_serialize(&*xs)))) - // } - // bindings_raw::NodeTag_T_NamedArgExpr => { - // let nae = node_ptr as *mut bindings_raw::NamedArgExpr; - // Some(protobuf::node::Node::NamedArgExpr(Box::new(convert_named_arg_expr(&*nae)))) - // } - // // JSON nodes - // bindings_raw::NodeTag_T_JsonFormat => { - // let jf = node_ptr as *mut bindings_raw::JsonFormat; - // Some(protobuf::node::Node::JsonFormat(convert_json_format(&*jf))) - // } - // bindings_raw::NodeTag_T_JsonReturning => { - // let jr = node_ptr as *mut bindings_raw::JsonReturning; - // Some(protobuf::node::Node::JsonReturning(convert_json_returning(&*jr))) - // } - // bindings_raw::NodeTag_T_JsonValueExpr => { - // let jve = node_ptr as *mut bindings_raw::JsonValueExpr; - // Some(protobuf::node::Node::JsonValueExpr(Box::new(convert_json_value_expr(&*jve)))) - // } - // bindings_raw::NodeTag_T_JsonConstructorExpr => { - // let jce = node_ptr as *mut bindings_raw::JsonConstructorExpr; - // Some(protobuf::node::Node::JsonConstructorExpr(Box::new(convert_json_constructor_expr(&*jce)))) - // } - // bindings_raw::NodeTag_T_JsonIsPredicate => { - // let jip = node_ptr as *mut bindings_raw::JsonIsPredicate; - // Some(protobuf::node::Node::JsonIsPredicate(Box::new(convert_json_is_predicate(&*jip)))) - // } - // bindings_raw::NodeTag_T_JsonBehavior => { - // let jb = node_ptr as *mut bindings_raw::JsonBehavior; - // Some(protobuf::node::Node::JsonBehavior(Box::new(convert_json_behavior(&*jb)))) - // } - // bindings_raw::NodeTag_T_JsonExpr => { - // let je = node_ptr as *mut bindings_raw::JsonExpr; - // Some(protobuf::node::Node::JsonExpr(Box::new(convert_json_expr(&*je)))) - // } - // bindings_raw::NodeTag_T_JsonTablePath => { - // let jtp = node_ptr as *mut bindings_raw::JsonTablePath; - // Some(protobuf::node::Node::JsonTablePath(convert_json_table_path(&*jtp))) - // } - // bindings_raw::NodeTag_T_JsonTablePathScan => { - // let jtps = node_ptr as *mut bindings_raw::JsonTablePathScan; - // Some(protobuf::node::Node::JsonTablePathScan(Box::new(convert_json_table_path_scan(&*jtps)))) - // } - // bindings_raw::NodeTag_T_JsonTableSiblingJoin => { - // let jtsj = node_ptr as *mut bindings_raw::JsonTableSiblingJoin; - // Some(protobuf::node::Node::JsonTableSiblingJoin(Box::new(convert_json_table_sibling_join(&*jtsj)))) - // } - // bindings_raw::NodeTag_T_JsonOutput => { - // let jo = node_ptr as *mut bindings_raw::JsonOutput; - // Some(protobuf::node::Node::JsonOutput(convert_json_output(&*jo))) - // } - // bindings_raw::NodeTag_T_JsonArgument => { - // let ja = node_ptr as *mut bindings_raw::JsonArgument; - // Some(protobuf::node::Node::JsonArgument(Box::new(convert_json_argument(&*ja)))) - // } - // bindings_raw::NodeTag_T_JsonFuncExpr => { - // let jfe = node_ptr as *mut bindings_raw::JsonFuncExpr; - // Some(protobuf::node::Node::JsonFuncExpr(Box::new(convert_json_func_expr(&*jfe)))) - // } - // bindings_raw::NodeTag_T_JsonTablePathSpec => { - // let jtps = node_ptr as *mut bindings_raw::JsonTablePathSpec; - // Some(protobuf::node::Node::JsonTablePathSpec(Box::new(convert_json_table_path_spec(&*jtps)))) - // } - // bindings_raw::NodeTag_T_JsonTable => { - // let jt = node_ptr as *mut bindings_raw::JsonTable; - // Some(protobuf::node::Node::JsonTable(Box::new(convert_json_table(&*jt)))) - // } - // bindings_raw::NodeTag_T_JsonTableColumn => { - // let jtc = node_ptr as *mut bindings_raw::JsonTableColumn; - // Some(protobuf::node::Node::JsonTableColumn(Box::new(convert_json_table_column(&*jtc)))) - // } - // bindings_raw::NodeTag_T_JsonKeyValue => { - // let jkv = node_ptr as *mut bindings_raw::JsonKeyValue; - // Some(protobuf::node::Node::JsonKeyValue(Box::new(convert_json_key_value(&*jkv)))) - // } - // bindings_raw::NodeTag_T_JsonParseExpr => { - // let jpe = node_ptr as *mut bindings_raw::JsonParseExpr; - // Some(protobuf::node::Node::JsonParseExpr(Box::new(convert_json_parse_expr(&*jpe)))) - // } - // bindings_raw::NodeTag_T_JsonScalarExpr => { - // let jse = node_ptr as *mut bindings_raw::JsonScalarExpr; - // Some(protobuf::node::Node::JsonScalarExpr(Box::new(convert_json_scalar_expr(&*jse)))) - // } - // bindings_raw::NodeTag_T_JsonSerializeExpr => { - // let jse = node_ptr as *mut bindings_raw::JsonSerializeExpr; - // Some(protobuf::node::Node::JsonSerializeExpr(Box::new(convert_json_serialize_expr(&*jse)))) - // } - // bindings_raw::NodeTag_T_JsonObjectConstructor => { - // let joc = node_ptr as *mut bindings_raw::JsonObjectConstructor; - // Some(protobuf::node::Node::JsonObjectConstructor(convert_json_object_constructor(&*joc))) - // } - // bindings_raw::NodeTag_T_JsonArrayConstructor => { - // let jac = node_ptr as *mut bindings_raw::JsonArrayConstructor; - // Some(protobuf::node::Node::JsonArrayConstructor(convert_json_array_constructor(&*jac))) - // } - // bindings_raw::NodeTag_T_JsonArrayQueryConstructor => { - // let jaqc = node_ptr as *mut bindings_raw::JsonArrayQueryConstructor; - // Some(protobuf::node::Node::JsonArrayQueryConstructor(Box::new(convert_json_array_query_constructor(&*jaqc)))) - // } - // bindings_raw::NodeTag_T_JsonAggConstructor => { - // let jac = node_ptr as *mut bindings_raw::JsonAggConstructor; - // Some(protobuf::node::Node::JsonAggConstructor(Box::new(convert_json_agg_constructor(&*jac)))) - // } - // bindings_raw::NodeTag_T_JsonObjectAgg => { - // let joa = node_ptr as *mut bindings_raw::JsonObjectAgg; - // Some(protobuf::node::Node::JsonObjectAgg(Box::new(convert_json_object_agg(&*joa)))) - // } - // bindings_raw::NodeTag_T_JsonArrayAgg => { - // let jaa = node_ptr as *mut bindings_raw::JsonArrayAgg; - // Some(protobuf::node::Node::JsonArrayAgg(Box::new(convert_json_array_agg(&*jaa)))) - // } - // bindings_raw::NodeTag_T_ReplicaIdentityStmt => { - // let ris = node_ptr as *mut bindings_raw::ReplicaIdentityStmt; - // Some(protobuf::node::Node::ReplicaIdentityStmt(convert_replica_identity_stmt(&*ris))) - // } - // bindings_raw::NodeTag_T_GroupingFunc => { - // let gf = node_ptr as *mut bindings_raw::GroupingFunc; - // Some(protobuf::node::Node::GroupingFunc(Box::new(convert_grouping_func(&*gf)))) - // } - _ => { - // For unhandled node types, return None - // In the future, we could add more node types here - None - } - }; + // === CaseExpr (iterative) === + bindings_raw::NodeTag_T_CaseExpr => { + let ce = node_ptr as *const bindings_raw::CaseExpr; + if collect { + let node = self.collect_case_expr(&*ce); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_case_expr(&*ce); + } + } - node.map(|n| protobuf::Node { node: Some(n) }) -} + // === CaseWhen (iterative) === + bindings_raw::NodeTag_T_CaseWhen => { + let cw = node_ptr as *const bindings_raw::CaseWhen; + if collect { + let node = self.collect_case_when(&*cw); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_case_when(&*cw); + } + } -/// Converts a PostgreSQL List to a protobuf List of Nodes. -unsafe fn convert_list(list: &bindings_raw::List) -> protobuf::List { - let items = convert_list_to_nodes(list as *const bindings_raw::List as *mut bindings_raw::List); - protobuf::List { items } -} + // === CoalesceExpr (iterative) === + bindings_raw::NodeTag_T_CoalesceExpr => { + let ce = node_ptr as *const bindings_raw::CoalesceExpr; + if collect { + let node = self.collect_coalesce_expr(&*ce); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_coalesce_expr(&*ce); + } + } -/// Converts a PostgreSQL List pointer to a Vec of protobuf Nodes. -/// Note: Preserves placeholder nodes (Node { node: None }) for cases like DISTINCT -/// where the list must retain its structure even if content is not recognized. -unsafe fn convert_list_to_nodes(list: *mut bindings_raw::List) -> Vec { - if list.is_null() { - return Vec::new(); - } - - let list_ref = &*list; - let length = list_ref.length as usize; - let mut nodes = Vec::with_capacity(length); - - for i in 0..length { - let cell = list_ref.elements.add(i); - let node_ptr = (*cell).ptr_value as *mut bindings_raw::Node; - - // Always push the node, even if it's None/unrecognized. - // This preserves list structure for things like DISTINCT where - // a placeholder node (Node { node: None }) is meaningful. - let node = convert_node(node_ptr).unwrap_or_else(|| protobuf::Node { node: None }); - nodes.push(node); - } - - nodes -} - -// ============================================================================ -// Statement Conversions -// ============================================================================ - -unsafe fn convert_select_stmt(stmt: &bindings_raw::SelectStmt) -> protobuf::SelectStmt { - protobuf::SelectStmt { - distinct_clause: convert_list_to_nodes(stmt.distinctClause), - into_clause: convert_into_clause(stmt.intoClause), - target_list: convert_list_to_nodes(stmt.targetList), - from_clause: convert_list_to_nodes(stmt.fromClause), - where_clause: convert_node_boxed(stmt.whereClause), - group_clause: convert_list_to_nodes(stmt.groupClause), - group_distinct: stmt.groupDistinct, - having_clause: convert_node_boxed(stmt.havingClause), - window_clause: convert_list_to_nodes(stmt.windowClause), - values_lists: convert_list_to_nodes(stmt.valuesLists), - sort_clause: convert_list_to_nodes(stmt.sortClause), - limit_offset: convert_node_boxed(stmt.limitOffset), - limit_count: convert_node_boxed(stmt.limitCount), - limit_option: stmt.limitOption as i32 + 1, // Protobuf enums have UNDEFINED=0, so C values need +1 - locking_clause: convert_list_to_nodes(stmt.lockingClause), - with_clause: convert_with_clause_opt(stmt.withClause), - op: stmt.op as i32 + 1, // Protobuf SetOperation has UNDEFINED=0, so C values need +1 - all: stmt.all, - larg: if stmt.larg.is_null() { None } else { Some(Box::new(convert_select_stmt(&*stmt.larg))) }, - rarg: if stmt.rarg.is_null() { None } else { Some(Box::new(convert_select_stmt(&*stmt.rarg))) }, - } -} - -unsafe fn convert_insert_stmt(stmt: &bindings_raw::InsertStmt) -> protobuf::InsertStmt { - protobuf::InsertStmt { - relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, - cols: convert_list_to_nodes(stmt.cols), - select_stmt: convert_node_boxed(stmt.selectStmt), - on_conflict_clause: convert_on_conflict_clause(stmt.onConflictClause), - returning_list: convert_list_to_nodes(stmt.returningList), - with_clause: convert_with_clause_opt(stmt.withClause), - r#override: stmt.override_ as i32 + 1, - } -} - -unsafe fn convert_update_stmt(stmt: &bindings_raw::UpdateStmt) -> protobuf::UpdateStmt { - protobuf::UpdateStmt { - relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, - target_list: convert_list_to_nodes(stmt.targetList), - where_clause: convert_node_boxed(stmt.whereClause), - from_clause: convert_list_to_nodes(stmt.fromClause), - returning_list: convert_list_to_nodes(stmt.returningList), - with_clause: convert_with_clause_opt(stmt.withClause), - } -} - -unsafe fn convert_delete_stmt(stmt: &bindings_raw::DeleteStmt) -> protobuf::DeleteStmt { - protobuf::DeleteStmt { - relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, - using_clause: convert_list_to_nodes(stmt.usingClause), - where_clause: convert_node_boxed(stmt.whereClause), - returning_list: convert_list_to_nodes(stmt.returningList), - with_clause: convert_with_clause_opt(stmt.withClause), - } -} - -unsafe fn convert_create_stmt(stmt: &bindings_raw::CreateStmt) -> protobuf::CreateStmt { - protobuf::CreateStmt { - relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, - table_elts: convert_list_to_nodes(stmt.tableElts), - inh_relations: convert_list_to_nodes(stmt.inhRelations), - partbound: convert_partition_bound_spec_opt(stmt.partbound), - partspec: convert_partition_spec_opt(stmt.partspec), - of_typename: if stmt.ofTypename.is_null() { None } else { Some(convert_type_name(&*stmt.ofTypename)) }, - constraints: convert_list_to_nodes(stmt.constraints), - options: convert_list_to_nodes(stmt.options), - oncommit: stmt.oncommit as i32 + 1, - tablespacename: convert_c_string(stmt.tablespacename), - access_method: convert_c_string(stmt.accessMethod), - if_not_exists: stmt.if_not_exists, - } -} - -unsafe fn convert_drop_stmt(stmt: &bindings_raw::DropStmt) -> protobuf::DropStmt { - protobuf::DropStmt { - objects: convert_list_to_nodes(stmt.objects), - remove_type: stmt.removeType as i32 + 1, - behavior: stmt.behavior as i32 + 1, - missing_ok: stmt.missing_ok, - concurrent: stmt.concurrent, - } -} - -unsafe fn convert_index_stmt(stmt: &bindings_raw::IndexStmt) -> protobuf::IndexStmt { - protobuf::IndexStmt { - idxname: convert_c_string(stmt.idxname), - relation: if stmt.relation.is_null() { None } else { Some(convert_range_var(&*stmt.relation)) }, - access_method: convert_c_string(stmt.accessMethod), - table_space: convert_c_string(stmt.tableSpace), - index_params: convert_list_to_nodes(stmt.indexParams), - index_including_params: convert_list_to_nodes(stmt.indexIncludingParams), - options: convert_list_to_nodes(stmt.options), - where_clause: convert_node_boxed(stmt.whereClause), - exclude_op_names: convert_list_to_nodes(stmt.excludeOpNames), - idxcomment: convert_c_string(stmt.idxcomment), - index_oid: stmt.indexOid, - old_number: stmt.oldNumber, - old_create_subid: stmt.oldCreateSubid, - old_first_relfilelocator_subid: stmt.oldFirstRelfilelocatorSubid, - unique: stmt.unique, - nulls_not_distinct: stmt.nulls_not_distinct, - primary: stmt.primary, - isconstraint: stmt.isconstraint, - deferrable: stmt.deferrable, - initdeferred: stmt.initdeferred, - transformed: stmt.transformed, - concurrent: stmt.concurrent, - if_not_exists: stmt.if_not_exists, - reset_default_tblspc: stmt.reset_default_tblspc, - } -} - -// ============================================================================ -// Expression/Clause Conversions -// ============================================================================ + // === MinMaxExpr (iterative) === + bindings_raw::NodeTag_T_MinMaxExpr => { + let mme = node_ptr as *const bindings_raw::MinMaxExpr; + if collect { + let node = self.collect_min_max_expr(&*mme); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_min_max_expr(&*mme); + } + } -unsafe fn convert_range_var(rv: &bindings_raw::RangeVar) -> protobuf::RangeVar { - protobuf::RangeVar { - catalogname: convert_c_string(rv.catalogname), - schemaname: convert_c_string(rv.schemaname), - relname: convert_c_string(rv.relname), - inh: rv.inh, - relpersistence: String::from_utf8_lossy(&[rv.relpersistence as u8]).to_string(), - alias: if rv.alias.is_null() { None } else { Some(convert_alias(&*rv.alias)) }, - location: rv.location, - } -} + // === SQLValueFunction (leaf) === + bindings_raw::NodeTag_T_SQLValueFunction => { + let svf = node_ptr as *const bindings_raw::SQLValueFunction; + self.push_result(protobuf::node::Node::SqlvalueFunction(Box::new(protobuf::SqlValueFunction { + xpr: None, + op: (*svf).op as i32 + 1, + r#type: (*svf).type_, + typmod: (*svf).typmod, + location: (*svf).location, + }))); + } -unsafe fn convert_column_ref(cr: &bindings_raw::ColumnRef) -> protobuf::ColumnRef { - protobuf::ColumnRef { fields: convert_list_to_nodes(cr.fields), location: cr.location } -} + // === SetToDefault (leaf) === + bindings_raw::NodeTag_T_SetToDefault => { + let std_ = node_ptr as *const bindings_raw::SetToDefault; + self.push_result(protobuf::node::Node::SetToDefault(Box::new(protobuf::SetToDefault { + xpr: None, + type_id: (*std_).typeId, + type_mod: (*std_).typeMod, + collation: (*std_).collation, + location: (*std_).location, + }))); + } -unsafe fn convert_res_target(rt: &bindings_raw::ResTarget) -> protobuf::ResTarget { - protobuf::ResTarget { - name: convert_c_string(rt.name), - indirection: convert_list_to_nodes(rt.indirection), - val: convert_node_boxed(rt.val), - location: rt.location, - } -} + // === BooleanTest (iterative) === + bindings_raw::NodeTag_T_BooleanTest => { + let bt = node_ptr as *const bindings_raw::BooleanTest; + if collect { + let node = self.collect_boolean_test(&*bt); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_boolean_test(&*bt); + } + } -unsafe fn convert_a_expr(expr: &bindings_raw::A_Expr) -> protobuf::AExpr { - protobuf::AExpr { - kind: expr.kind as i32 + 1, - name: convert_list_to_nodes(expr.name), - lexpr: convert_node_boxed(expr.lexpr), - rexpr: convert_node_boxed(expr.rexpr), - location: expr.location, - } -} + // === A_ArrayExpr (iterative) === + bindings_raw::NodeTag_T_A_ArrayExpr => { + let ae = node_ptr as *const bindings_raw::A_ArrayExpr; + if collect { + let node = self.collect_a_array_expr(&*ae); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_a_array_expr(&*ae); + } + } -unsafe fn convert_a_const(aconst: &bindings_raw::A_Const) -> protobuf::AConst { - let val = if aconst.isnull { - None - } else { - // Check the node tag in the val union to determine the type - let node_tag = aconst.val.node.type_; - match node_tag { - bindings_raw::NodeTag_T_Integer => Some(protobuf::a_const::Val::Ival(protobuf::Integer { ival: aconst.val.ival.ival })), - bindings_raw::NodeTag_T_Float => { - let fval = if aconst.val.fval.fval.is_null() { - std::string::String::new() - } else { - CStr::from_ptr(aconst.val.fval.fval).to_string_lossy().to_string() - }; - Some(protobuf::a_const::Val::Fval(protobuf::Float { fval })) - } - bindings_raw::NodeTag_T_Boolean => Some(protobuf::a_const::Val::Boolval(protobuf::Boolean { boolval: aconst.val.boolval.boolval })), - bindings_raw::NodeTag_T_String => { - let sval = if aconst.val.sval.sval.is_null() { - std::string::String::new() - } else { - CStr::from_ptr(aconst.val.sval.sval).to_string_lossy().to_string() - }; - Some(protobuf::a_const::Val::Sval(protobuf::String { sval })) - } - bindings_raw::NodeTag_T_BitString => { - let bsval = if aconst.val.bsval.bsval.is_null() { - std::string::String::new() - } else { - CStr::from_ptr(aconst.val.bsval.bsval).to_string_lossy().to_string() - }; - Some(protobuf::a_const::Val::Bsval(protobuf::BitString { bsval })) - } - _ => None, - } - }; + // === A_Indirection (iterative) === + bindings_raw::NodeTag_T_A_Indirection => { + let ai = node_ptr as *const bindings_raw::A_Indirection; + if collect { + let node = self.collect_a_indirection(&*ai); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_a_indirection(&*ai); + } + } - protobuf::AConst { isnull: aconst.isnull, val, location: aconst.location } -} + // === A_Indices (iterative) === + bindings_raw::NodeTag_T_A_Indices => { + let ai = node_ptr as *const bindings_raw::A_Indices; + if collect { + let node = self.collect_a_indices(&*ai); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_a_indices(&*ai); + } + } -unsafe fn convert_func_call(fc: &bindings_raw::FuncCall) -> protobuf::FuncCall { - protobuf::FuncCall { - funcname: convert_list_to_nodes(fc.funcname), - args: convert_list_to_nodes(fc.args), - agg_order: convert_list_to_nodes(fc.agg_order), - agg_filter: convert_node_boxed(fc.agg_filter), - over: if fc.over.is_null() { None } else { Some(Box::new(convert_window_def(&*fc.over))) }, - agg_within_group: fc.agg_within_group, - agg_star: fc.agg_star, - agg_distinct: fc.agg_distinct, - func_variadic: fc.func_variadic, - funcformat: fc.funcformat as i32 + 1, - location: fc.location, - } -} + // === CollateClause (iterative) === + bindings_raw::NodeTag_T_CollateClause => { + let cc = node_ptr as *const bindings_raw::CollateClause; + if collect { + let node = self.collect_collate_clause(&*cc); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_collate_clause(&*cc); + } + } -unsafe fn convert_type_cast(tc: &bindings_raw::TypeCast) -> protobuf::TypeCast { - protobuf::TypeCast { - arg: convert_node_boxed(tc.arg), - type_name: if tc.typeName.is_null() { None } else { Some(convert_type_name(&*tc.typeName)) }, - location: tc.location, - } -} + // === RangeSubselect (iterative) === + bindings_raw::NodeTag_T_RangeSubselect => { + let rs = node_ptr as *const bindings_raw::RangeSubselect; + if collect { + let node = self.collect_range_subselect(&*rs); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_range_subselect(&*rs); + } + } -unsafe fn convert_type_name(tn: &bindings_raw::TypeName) -> protobuf::TypeName { - protobuf::TypeName { - names: convert_list_to_nodes(tn.names), - type_oid: tn.typeOid, - setof: tn.setof, - pct_type: tn.pct_type, - typmods: convert_list_to_nodes(tn.typmods), - typemod: tn.typemod, - array_bounds: convert_list_to_nodes(tn.arrayBounds), - location: tn.location, - } -} + // === CommonTableExpr (iterative) === + bindings_raw::NodeTag_T_CommonTableExpr => { + let cte = node_ptr as *const bindings_raw::CommonTableExpr; + if collect { + let node = self.collect_common_table_expr(&*cte); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_common_table_expr(&*cte); + } + } -unsafe fn convert_alias(alias: &bindings_raw::Alias) -> protobuf::Alias { - protobuf::Alias { aliasname: convert_c_string(alias.aliasname), colnames: convert_list_to_nodes(alias.colnames) } -} + // === GroupingSet (iterative) === + bindings_raw::NodeTag_T_GroupingSet => { + let gs = node_ptr as *const bindings_raw::GroupingSet; + if collect { + let node = self.collect_grouping_set(&*gs); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_grouping_set(&*gs); + } + } -unsafe fn convert_join_expr(je: &bindings_raw::JoinExpr) -> protobuf::JoinExpr { - protobuf::JoinExpr { - jointype: je.jointype as i32 + 1, - is_natural: je.isNatural, - larg: convert_node_boxed(je.larg), - rarg: convert_node_boxed(je.rarg), - using_clause: convert_list_to_nodes(je.usingClause), - join_using_alias: if je.join_using_alias.is_null() { None } else { Some(convert_alias(&*je.join_using_alias)) }, - quals: convert_node_boxed(je.quals), - alias: if je.alias.is_null() { None } else { Some(convert_alias(&*je.alias)) }, - rtindex: je.rtindex, - } -} + // === LockingClause (iterative) === + bindings_raw::NodeTag_T_LockingClause => { + let lc = node_ptr as *const bindings_raw::LockingClause; + if collect { + let node = self.collect_locking_clause(&*lc); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_locking_clause(&*lc); + } + } -unsafe fn convert_sort_by(sb: &bindings_raw::SortBy) -> protobuf::SortBy { - protobuf::SortBy { - node: convert_node_boxed(sb.node), - sortby_dir: sb.sortby_dir as i32 + 1, - sortby_nulls: sb.sortby_nulls as i32 + 1, - use_op: convert_list_to_nodes(sb.useOp), - location: sb.location, - } -} + // === RowExpr (iterative) === + bindings_raw::NodeTag_T_RowExpr => { + let re = node_ptr as *const bindings_raw::RowExpr; + if collect { + let node = self.collect_row_expr(&*re); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_row_expr(&*re); + } + } -unsafe fn convert_bool_expr(be: &bindings_raw::BoolExpr) -> protobuf::BoolExpr { - protobuf::BoolExpr { - xpr: None, // Xpr is internal - boolop: be.boolop as i32 + 1, - args: convert_list_to_nodes(be.args), - location: be.location, - } -} + // === MultiAssignRef (iterative) === + bindings_raw::NodeTag_T_MultiAssignRef => { + let mar = node_ptr as *const bindings_raw::MultiAssignRef; + if collect { + let node = self.collect_multi_assign_ref(&*mar); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_multi_assign_ref(&*mar); + } + } -unsafe fn convert_sub_link(sl: &bindings_raw::SubLink) -> protobuf::SubLink { - protobuf::SubLink { - xpr: None, - sub_link_type: sl.subLinkType as i32 + 1, - sub_link_id: sl.subLinkId, - testexpr: convert_node_boxed(sl.testexpr), - oper_name: convert_list_to_nodes(sl.operName), - subselect: convert_node_boxed(sl.subselect), - location: sl.location, - } -} + // === CTESearchClause (iterative) === + bindings_raw::NodeTag_T_CTESearchClause => { + let csc = node_ptr as *const bindings_raw::CTESearchClause; + if collect { + let node = self.collect_cte_search_clause(&*csc); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_cte_search_clause(&*csc); + } + } -unsafe fn convert_null_test(nt: &bindings_raw::NullTest) -> protobuf::NullTest { - protobuf::NullTest { - xpr: None, - arg: convert_node_boxed(nt.arg as *mut bindings_raw::Node), - nulltesttype: nt.nulltesttype as i32 + 1, - argisrow: nt.argisrow, - location: nt.location, - } -} + // === CTECycleClause (iterative) === + bindings_raw::NodeTag_T_CTECycleClause => { + let ccc = node_ptr as *const bindings_raw::CTECycleClause; + if collect { + let node = self.collect_cte_cycle_clause(&*ccc); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_cte_cycle_clause(&*ccc); + } + } -unsafe fn convert_case_expr(ce: &bindings_raw::CaseExpr) -> protobuf::CaseExpr { - protobuf::CaseExpr { - xpr: None, - casetype: ce.casetype, - casecollid: ce.casecollid, - arg: convert_node_boxed(ce.arg as *mut bindings_raw::Node), - args: convert_list_to_nodes(ce.args), - defresult: convert_node_boxed(ce.defresult as *mut bindings_raw::Node), - location: ce.location, - } -} + // === Alias (iterative) === + bindings_raw::NodeTag_T_Alias => { + let alias = node_ptr as *const bindings_raw::Alias; + if collect { + let node = self.collect_alias(&*alias); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_alias(&*alias); + } + } -unsafe fn convert_case_when(cw: &bindings_raw::CaseWhen) -> protobuf::CaseWhen { - protobuf::CaseWhen { - xpr: None, - expr: convert_node_boxed(cw.expr as *mut bindings_raw::Node), - result: convert_node_boxed(cw.result as *mut bindings_raw::Node), - location: cw.location, - } -} + // === GroupingFunc (iterative) === + bindings_raw::NodeTag_T_GroupingFunc => { + let gf = node_ptr as *const bindings_raw::GroupingFunc; + if collect { + let node = self.collect_grouping_func(&*gf); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_grouping_func(&*gf); + } + } -unsafe fn convert_coalesce_expr(ce: &bindings_raw::CoalesceExpr) -> protobuf::CoalesceExpr { - protobuf::CoalesceExpr { - xpr: None, - coalescetype: ce.coalescetype, - coalescecollid: ce.coalescecollid, - args: convert_list_to_nodes(ce.args), - location: ce.location, - } -} + // === IndexElem (iterative) === + bindings_raw::NodeTag_T_IndexElem => { + let ie = node_ptr as *const bindings_raw::IndexElem; + if collect { + let node = self.collect_index_elem(&*ie); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_index_elem(&*ie); + } + } -unsafe fn convert_with_clause(wc: &bindings_raw::WithClause) -> protobuf::WithClause { - protobuf::WithClause { ctes: convert_list_to_nodes(wc.ctes), recursive: wc.recursive, location: wc.location } -} + // === DefElem (iterative) === + bindings_raw::NodeTag_T_DefElem => { + let de = node_ptr as *const bindings_raw::DefElem; + if collect { + let node = self.collect_def_elem(&*de); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_def_elem(&*de); + } + } -unsafe fn convert_with_clause_opt(wc: *mut bindings_raw::WithClause) -> Option { - if wc.is_null() { - None - } else { - Some(convert_with_clause(&*wc)) - } -} + // === ColumnDef (iterative) === + bindings_raw::NodeTag_T_ColumnDef => { + let cd = node_ptr as *const bindings_raw::ColumnDef; + if collect { + let node = self.collect_column_def(&*cd); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_column_def(&*cd); + } + } -unsafe fn convert_common_table_expr(cte: &bindings_raw::CommonTableExpr) -> protobuf::CommonTableExpr { - protobuf::CommonTableExpr { - ctename: convert_c_string(cte.ctename), - aliascolnames: convert_list_to_nodes(cte.aliascolnames), - ctematerialized: cte.ctematerialized as i32 + 1, - ctequery: convert_node_boxed(cte.ctequery), - search_clause: convert_cte_search_clause_opt(cte.search_clause), - cycle_clause: convert_cte_cycle_clause_opt(cte.cycle_clause), - location: cte.location, - cterecursive: cte.cterecursive, - cterefcount: cte.cterefcount, - ctecolnames: convert_list_to_nodes(cte.ctecolnames), - ctecoltypes: convert_list_to_nodes(cte.ctecoltypes), - ctecoltypmods: convert_list_to_nodes(cte.ctecoltypmods), - ctecolcollations: convert_list_to_nodes(cte.ctecolcollations), - } -} + // === Constraint (iterative) === + bindings_raw::NodeTag_T_Constraint => { + let c = node_ptr as *const bindings_raw::Constraint; + if collect { + let node = self.collect_constraint(&*c); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_constraint(&*c); + } + } -unsafe fn convert_window_def(wd: &bindings_raw::WindowDef) -> protobuf::WindowDef { - protobuf::WindowDef { - name: convert_c_string(wd.name), - refname: convert_c_string(wd.refname), - partition_clause: convert_list_to_nodes(wd.partitionClause), - order_clause: convert_list_to_nodes(wd.orderClause), - frame_options: wd.frameOptions, - start_offset: convert_node_boxed(wd.startOffset), - end_offset: convert_node_boxed(wd.endOffset), - location: wd.location, - } -} + // === RoleSpec (leaf-like) === + bindings_raw::NodeTag_T_RoleSpec => { + let rs = node_ptr as *const bindings_raw::RoleSpec; + self.push_result(protobuf::node::Node::RoleSpec(protobuf::RoleSpec { + roletype: (*rs).roletype as i32 + 1, + rolename: convert_c_string((*rs).rolename), + location: (*rs).location, + })); + } -unsafe fn convert_into_clause(ic: *mut bindings_raw::IntoClause) -> Option> { - if ic.is_null() { - return None; - } - let ic_ref = &*ic; - Some(Box::new(protobuf::IntoClause { - rel: if ic_ref.rel.is_null() { None } else { Some(convert_range_var(&*ic_ref.rel)) }, - col_names: convert_list_to_nodes(ic_ref.colNames), - access_method: convert_c_string(ic_ref.accessMethod), - options: convert_list_to_nodes(ic_ref.options), - on_commit: ic_ref.onCommit as i32 + 1, - table_space_name: convert_c_string(ic_ref.tableSpaceName), - view_query: convert_node_boxed(ic_ref.viewQuery), - skip_data: ic_ref.skipData, - })) -} + // === CreateStmt (iterative) === + bindings_raw::NodeTag_T_CreateStmt => { + let cs = node_ptr as *const bindings_raw::CreateStmt; + if collect { + let node = self.collect_create_stmt(&*cs); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_create_stmt(&*cs); + } + } -unsafe fn convert_infer_clause(ic: *mut bindings_raw::InferClause) -> Option> { - if ic.is_null() { - return None; - } - let ic_ref = &*ic; - Some(Box::new(protobuf::InferClause { - index_elems: convert_list_to_nodes(ic_ref.indexElems), - where_clause: convert_node_boxed(ic_ref.whereClause), - conname: convert_c_string(ic_ref.conname), - location: ic_ref.location, - })) -} + // === DropStmt (iterative) === + bindings_raw::NodeTag_T_DropStmt => { + let ds = node_ptr as *const bindings_raw::DropStmt; + if collect { + let node = self.collect_drop_stmt(&*ds); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_drop_stmt(&*ds); + } + } -unsafe fn convert_on_conflict_clause(oc: *mut bindings_raw::OnConflictClause) -> Option> { - if oc.is_null() { - return None; - } - let oc_ref = &*oc; - Some(Box::new(protobuf::OnConflictClause { - action: oc_ref.action as i32 + 1, - infer: convert_infer_clause(oc_ref.infer), - target_list: convert_list_to_nodes(oc_ref.targetList), - where_clause: convert_node_boxed(oc_ref.whereClause), - location: oc_ref.location, - })) -} + // === IndexStmt (iterative) === + bindings_raw::NodeTag_T_IndexStmt => { + let is_ = node_ptr as *const bindings_raw::IndexStmt; + if collect { + let node = self.collect_index_stmt(&*is_); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_index_stmt(&*is_); + } + } -unsafe fn convert_column_def(cd: &bindings_raw::ColumnDef) -> protobuf::ColumnDef { - protobuf::ColumnDef { - colname: convert_c_string(cd.colname), - type_name: if cd.typeName.is_null() { None } else { Some(convert_type_name(&*cd.typeName)) }, - compression: convert_c_string(cd.compression), - inhcount: cd.inhcount, - is_local: cd.is_local, - is_not_null: cd.is_not_null, - is_from_type: cd.is_from_type, - storage: if cd.storage == 0 { String::new() } else { String::from_utf8_lossy(&[cd.storage as u8]).to_string() }, - storage_name: convert_c_string(cd.storage_name), - raw_default: convert_node_boxed(cd.raw_default), - cooked_default: convert_node_boxed(cd.cooked_default), - identity: if cd.identity == 0 { String::new() } else { String::from_utf8_lossy(&[cd.identity as u8]).to_string() }, - identity_sequence: if cd.identitySequence.is_null() { None } else { Some(convert_range_var(&*cd.identitySequence)) }, - generated: if cd.generated == 0 { String::new() } else { String::from_utf8_lossy(&[cd.generated as u8]).to_string() }, - coll_clause: convert_collate_clause_opt(cd.collClause), - coll_oid: cd.collOid, - constraints: convert_list_to_nodes(cd.constraints), - fdwoptions: convert_list_to_nodes(cd.fdwoptions), - location: cd.location, - } -} + // === AlterTableStmt (iterative) === + bindings_raw::NodeTag_T_AlterTableStmt => { + let ats = node_ptr as *const bindings_raw::AlterTableStmt; + if collect { + let node = self.collect_alter_table_stmt(&*ats); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_alter_table_stmt(&*ats); + } + } -unsafe fn convert_constraint(c: &bindings_raw::Constraint) -> protobuf::Constraint { - protobuf::Constraint { - contype: c.contype as i32 + 1, - conname: convert_c_string(c.conname), - deferrable: c.deferrable, - initdeferred: c.initdeferred, - location: c.location, - is_no_inherit: c.is_no_inherit, - raw_expr: convert_node_boxed(c.raw_expr), - cooked_expr: convert_c_string(c.cooked_expr), - generated_when: if c.generated_when == 0 { String::new() } else { String::from_utf8_lossy(&[c.generated_when as u8]).to_string() }, - inhcount: c.inhcount, - nulls_not_distinct: c.nulls_not_distinct, - keys: convert_list_to_nodes(c.keys), - including: convert_list_to_nodes(c.including), - exclusions: convert_list_to_nodes(c.exclusions), - options: convert_list_to_nodes(c.options), - indexname: convert_c_string(c.indexname), - indexspace: convert_c_string(c.indexspace), - reset_default_tblspc: c.reset_default_tblspc, - access_method: convert_c_string(c.access_method), - where_clause: convert_node_boxed(c.where_clause), - pktable: if c.pktable.is_null() { None } else { Some(convert_range_var(&*c.pktable)) }, - fk_attrs: convert_list_to_nodes(c.fk_attrs), - pk_attrs: convert_list_to_nodes(c.pk_attrs), - fk_matchtype: if c.fk_matchtype == 0 { String::new() } else { String::from_utf8_lossy(&[c.fk_matchtype as u8]).to_string() }, - fk_upd_action: if c.fk_upd_action == 0 { String::new() } else { String::from_utf8_lossy(&[c.fk_upd_action as u8]).to_string() }, - fk_del_action: if c.fk_del_action == 0 { String::new() } else { String::from_utf8_lossy(&[c.fk_del_action as u8]).to_string() }, - fk_del_set_cols: convert_list_to_nodes(c.fk_del_set_cols), - old_conpfeqop: convert_list_to_nodes(c.old_conpfeqop), - old_pktable_oid: c.old_pktable_oid, - skip_validation: c.skip_validation, - initially_valid: c.initially_valid, - } -} + // === AlterTableCmd (iterative) === + bindings_raw::NodeTag_T_AlterTableCmd => { + let atc = node_ptr as *const bindings_raw::AlterTableCmd; + if collect { + let node = self.collect_alter_table_cmd(&*atc); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_alter_table_cmd(&*atc); + } + } -unsafe fn convert_index_elem(ie: &bindings_raw::IndexElem) -> protobuf::IndexElem { - protobuf::IndexElem { - name: convert_c_string(ie.name), - expr: convert_node_boxed(ie.expr), - indexcolname: convert_c_string(ie.indexcolname), - collation: convert_list_to_nodes(ie.collation), - opclass: convert_list_to_nodes(ie.opclass), - opclassopts: convert_list_to_nodes(ie.opclassopts), - ordering: ie.ordering as i32 + 1, - nulls_ordering: ie.nulls_ordering as i32 + 1, - } -} + // === RenameStmt (iterative) === + bindings_raw::NodeTag_T_RenameStmt => { + let rs = node_ptr as *const bindings_raw::RenameStmt; + if collect { + let node = self.collect_rename_stmt(&*rs); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_rename_stmt(&*rs); + } + } -unsafe fn convert_def_elem(de: &bindings_raw::DefElem) -> protobuf::DefElem { - protobuf::DefElem { - defnamespace: convert_c_string(de.defnamespace), - defname: convert_c_string(de.defname), - arg: convert_node_boxed(de.arg), - defaction: de.defaction as i32 + 1, - location: de.location, - } -} + // === ViewStmt (iterative) === + bindings_raw::NodeTag_T_ViewStmt => { + let vs = node_ptr as *const bindings_raw::ViewStmt; + if collect { + let node = self.collect_view_stmt(&*vs); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_view_stmt(&*vs); + } + } -unsafe fn convert_string(s: &bindings_raw::String) -> protobuf::String { - protobuf::String { sval: convert_c_string(s.sval) } -} + // === CreateTableAsStmt (iterative) === + bindings_raw::NodeTag_T_CreateTableAsStmt => { + let ctas = node_ptr as *const bindings_raw::CreateTableAsStmt; + if collect { + let node = self.collect_create_table_as_stmt(&*ctas); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_create_table_as_stmt(&*ctas); + } + } -unsafe fn convert_replica_identity_stmt(ris: &bindings_raw::ReplicaIdentityStmt) -> protobuf::ReplicaIdentityStmt { - protobuf::ReplicaIdentityStmt { identity_type: String::from_utf8_lossy(&[ris.identity_type as u8]).to_string(), name: convert_c_string(ris.name) } -} + // === TruncateStmt (iterative) === + bindings_raw::NodeTag_T_TruncateStmt => { + let ts = node_ptr as *const bindings_raw::TruncateStmt; + if collect { + let node = self.collect_truncate_stmt(&*ts); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_truncate_stmt(&*ts); + } + } -unsafe fn convert_grouping_func(gf: &bindings_raw::GroupingFunc) -> protobuf::GroupingFunc { - protobuf::GroupingFunc { - xpr: None, - args: convert_list_to_nodes(gf.args), - refs: convert_list_to_nodes(gf.refs), - agglevelsup: gf.agglevelsup, - location: gf.location, - } -} + // === AlterOwnerStmt (iterative) === + bindings_raw::NodeTag_T_AlterOwnerStmt => { + let aos = node_ptr as *const bindings_raw::AlterOwnerStmt; + if collect { + let node = self.collect_alter_owner_stmt(&*aos); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_alter_owner_stmt(&*aos); + } + } -unsafe fn convert_locking_clause(lc: &bindings_raw::LockingClause) -> protobuf::LockingClause { - protobuf::LockingClause { - locked_rels: convert_list_to_nodes(lc.lockedRels), - strength: lc.strength as i32 + 1, - wait_policy: lc.waitPolicy as i32 + 1, - } -} + // === CreateSeqStmt (iterative) === + bindings_raw::NodeTag_T_CreateSeqStmt => { + let css = node_ptr as *const bindings_raw::CreateSeqStmt; + if collect { + let node = self.collect_create_seq_stmt(&*css); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_create_seq_stmt(&*css); + } + } -unsafe fn convert_min_max_expr(mme: &bindings_raw::MinMaxExpr) -> protobuf::MinMaxExpr { - protobuf::MinMaxExpr { - xpr: None, // Expression type info, not needed for parse tree - minmaxtype: mme.minmaxtype, - minmaxcollid: mme.minmaxcollid, - inputcollid: mme.inputcollid, - op: mme.op as i32 + 1, - args: convert_list_to_nodes(mme.args), - location: mme.location, - } -} + // === AlterSeqStmt (iterative) === + bindings_raw::NodeTag_T_AlterSeqStmt => { + let ass_ = node_ptr as *const bindings_raw::AlterSeqStmt; + if collect { + let node = self.collect_alter_seq_stmt(&*ass_); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_alter_seq_stmt(&*ass_); + } + } -unsafe fn convert_grouping_set(gs: &bindings_raw::GroupingSet) -> protobuf::GroupingSet { - protobuf::GroupingSet { kind: gs.kind as i32 + 1, content: convert_list_to_nodes(gs.content), location: gs.location } -} + // === CreateDomainStmt (iterative) === + bindings_raw::NodeTag_T_CreateDomainStmt => { + let cds = node_ptr as *const bindings_raw::CreateDomainStmt; + if collect { + let node = self.collect_create_domain_stmt(&*cds); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_create_domain_stmt(&*cds); + } + } -unsafe fn convert_range_subselect(rs: &bindings_raw::RangeSubselect) -> protobuf::RangeSubselect { - protobuf::RangeSubselect { - lateral: rs.lateral, - subquery: convert_node_boxed(rs.subquery), - alias: if rs.alias.is_null() { None } else { Some(convert_alias(&*rs.alias)) }, - } -} + // === CompositeTypeStmt (iterative) === + bindings_raw::NodeTag_T_CompositeTypeStmt => { + let cts = node_ptr as *const bindings_raw::CompositeTypeStmt; + if collect { + let node = self.collect_composite_type_stmt(&*cts); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_composite_type_stmt(&*cts); + } + } -unsafe fn convert_a_array_expr(ae: &bindings_raw::A_ArrayExpr) -> protobuf::AArrayExpr { - protobuf::AArrayExpr { elements: convert_list_to_nodes(ae.elements), location: ae.location } -} + // === CreateEnumStmt (iterative) === + bindings_raw::NodeTag_T_CreateEnumStmt => { + let ces = node_ptr as *const bindings_raw::CreateEnumStmt; + if collect { + let node = self.collect_create_enum_stmt(&*ces); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_create_enum_stmt(&*ces); + } + } -unsafe fn convert_a_indirection(ai: &bindings_raw::A_Indirection) -> protobuf::AIndirection { - protobuf::AIndirection { arg: convert_node_boxed(ai.arg), indirection: convert_list_to_nodes(ai.indirection) } -} + // === CreateExtensionStmt (iterative) === + bindings_raw::NodeTag_T_CreateExtensionStmt => { + let ces = node_ptr as *const bindings_raw::CreateExtensionStmt; + if collect { + let node = self.collect_create_extension_stmt(&*ces); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_create_extension_stmt(&*ces); + } + } -unsafe fn convert_a_indices(ai: &bindings_raw::A_Indices) -> protobuf::AIndices { - protobuf::AIndices { is_slice: ai.is_slice, lidx: convert_node_boxed(ai.lidx), uidx: convert_node_boxed(ai.uidx) } -} + // === CreatePublicationStmt (iterative) === + bindings_raw::NodeTag_T_CreatePublicationStmt => { + let cps = node_ptr as *const bindings_raw::CreatePublicationStmt; + if collect { + let node = self.collect_create_publication_stmt(&*cps); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_create_publication_stmt(&*cps); + } + } -unsafe fn convert_alter_table_stmt(ats: &bindings_raw::AlterTableStmt) -> protobuf::AlterTableStmt { - protobuf::AlterTableStmt { - relation: if ats.relation.is_null() { None } else { Some(convert_range_var(&*ats.relation)) }, - cmds: convert_list_to_nodes(ats.cmds), - objtype: ats.objtype as i32 + 1, - missing_ok: ats.missing_ok, - } -} + // === AlterPublicationStmt (iterative) === + bindings_raw::NodeTag_T_AlterPublicationStmt => { + let aps = node_ptr as *const bindings_raw::AlterPublicationStmt; + if collect { + let node = self.collect_alter_publication_stmt(&*aps); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_alter_publication_stmt(&*aps); + } + } -unsafe fn convert_alter_table_cmd(atc: &bindings_raw::AlterTableCmd) -> protobuf::AlterTableCmd { - protobuf::AlterTableCmd { - subtype: atc.subtype as i32 + 1, - name: convert_c_string(atc.name), - num: atc.num as i32, - newowner: if atc.newowner.is_null() { None } else { Some(convert_role_spec(&*atc.newowner)) }, - def: convert_node_boxed(atc.def), - behavior: atc.behavior as i32 + 1, - missing_ok: atc.missing_ok, - recurse: atc.recurse, - } -} + // === CreateSubscriptionStmt (iterative) === + bindings_raw::NodeTag_T_CreateSubscriptionStmt => { + let css = node_ptr as *const bindings_raw::CreateSubscriptionStmt; + if collect { + let node = self.collect_create_subscription_stmt(&*css); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_create_subscription_stmt(&*css); + } + } -unsafe fn convert_role_spec(rs: &bindings_raw::RoleSpec) -> protobuf::RoleSpec { - protobuf::RoleSpec { roletype: rs.roletype as i32 + 1, rolename: convert_c_string(rs.rolename), location: rs.location } -} + // === AlterSubscriptionStmt (iterative) === + bindings_raw::NodeTag_T_AlterSubscriptionStmt => { + let ass_ = node_ptr as *const bindings_raw::AlterSubscriptionStmt; + if collect { + let node = self.collect_alter_subscription_stmt(&*ass_); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_alter_subscription_stmt(&*ass_); + } + } -unsafe fn convert_copy_stmt(cs: &bindings_raw::CopyStmt) -> protobuf::CopyStmt { - protobuf::CopyStmt { - relation: if cs.relation.is_null() { None } else { Some(convert_range_var(&*cs.relation)) }, - query: convert_node_boxed(cs.query), - attlist: convert_list_to_nodes(cs.attlist), - is_from: cs.is_from, - is_program: cs.is_program, - filename: convert_c_string(cs.filename), - options: convert_list_to_nodes(cs.options), - where_clause: convert_node_boxed(cs.whereClause), - } -} + // === CreateTrigStmt (iterative) === + bindings_raw::NodeTag_T_CreateTrigStmt => { + let cts = node_ptr as *const bindings_raw::CreateTrigStmt; + if collect { + let node = self.collect_create_trig_stmt(&*cts); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_create_trig_stmt(&*cts); + } + } -unsafe fn convert_truncate_stmt(ts: &bindings_raw::TruncateStmt) -> protobuf::TruncateStmt { - protobuf::TruncateStmt { relations: convert_list_to_nodes(ts.relations), restart_seqs: ts.restart_seqs, behavior: ts.behavior as i32 + 1 } -} + // === PublicationObjSpec (iterative) === + bindings_raw::NodeTag_T_PublicationObjSpec => { + let pos = node_ptr as *const bindings_raw::PublicationObjSpec; + if collect { + let node = self.collect_publication_obj_spec(&*pos); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_publication_obj_spec(&*pos); + } + } -unsafe fn convert_view_stmt(vs: &bindings_raw::ViewStmt) -> protobuf::ViewStmt { - protobuf::ViewStmt { - view: if vs.view.is_null() { None } else { Some(convert_range_var(&*vs.view)) }, - aliases: convert_list_to_nodes(vs.aliases), - query: convert_node_boxed(vs.query), - replace: vs.replace, - options: convert_list_to_nodes(vs.options), - with_check_option: vs.withCheckOption as i32 + 1, - } -} + // === TriggerTransition (leaf) === + bindings_raw::NodeTag_T_TriggerTransition => { + let tt = node_ptr as *const bindings_raw::TriggerTransition; + self.push_result(protobuf::node::Node::TriggerTransition(protobuf::TriggerTransition { + name: convert_c_string((*tt).name), + is_new: (*tt).isNew, + is_table: (*tt).isTable, + })); + } -unsafe fn convert_explain_stmt(es: &bindings_raw::ExplainStmt) -> protobuf::ExplainStmt { - protobuf::ExplainStmt { query: convert_node_boxed(es.query), options: convert_list_to_nodes(es.options) } -} + // === PartitionElem (iterative) === + bindings_raw::NodeTag_T_PartitionElem => { + let pe = node_ptr as *const bindings_raw::PartitionElem; + if collect { + let node = self.collect_partition_elem(&*pe); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_partition_elem(&*pe); + } + } -unsafe fn convert_create_table_as_stmt(ctas: &bindings_raw::CreateTableAsStmt) -> protobuf::CreateTableAsStmt { - protobuf::CreateTableAsStmt { - query: convert_node_boxed(ctas.query), - into: convert_into_clause(ctas.into), - objtype: ctas.objtype as i32 + 1, - is_select_into: ctas.is_select_into, - if_not_exists: ctas.if_not_exists, - } -} + // === PartitionSpec (iterative) === + bindings_raw::NodeTag_T_PartitionSpec => { + let ps = node_ptr as *const bindings_raw::PartitionSpec; + if collect { + let node = self.collect_partition_spec(&*ps); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_partition_spec(&*ps); + } + } -unsafe fn convert_prepare_stmt(ps: &bindings_raw::PrepareStmt) -> protobuf::PrepareStmt { - protobuf::PrepareStmt { name: convert_c_string(ps.name), argtypes: convert_list_to_nodes(ps.argtypes), query: convert_node_boxed(ps.query) } -} + // === PartitionBoundSpec (iterative) === + bindings_raw::NodeTag_T_PartitionBoundSpec => { + let pbs = node_ptr as *const bindings_raw::PartitionBoundSpec; + if collect { + let node = self.collect_partition_bound_spec(&*pbs); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_partition_bound_spec(&*pbs); + } + } -unsafe fn convert_execute_stmt(es: &bindings_raw::ExecuteStmt) -> protobuf::ExecuteStmt { - protobuf::ExecuteStmt { name: convert_c_string(es.name), params: convert_list_to_nodes(es.params) } -} + // === PartitionRangeDatum (iterative) === + bindings_raw::NodeTag_T_PartitionRangeDatum => { + let prd = node_ptr as *const bindings_raw::PartitionRangeDatum; + if collect { + let node = self.collect_partition_range_datum(&*prd); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_partition_range_datum(&*prd); + } + } -unsafe fn convert_deallocate_stmt(ds: &bindings_raw::DeallocateStmt) -> protobuf::DeallocateStmt { - protobuf::DeallocateStmt { name: convert_c_string(ds.name), isall: ds.isall, location: ds.location } -} + // === ExplainStmt (iterative) === + bindings_raw::NodeTag_T_ExplainStmt => { + let es = node_ptr as *const bindings_raw::ExplainStmt; + if collect { + let node = self.collect_explain_stmt(&*es); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_explain_stmt(&*es); + } + } -unsafe fn convert_set_to_default(std: &bindings_raw::SetToDefault) -> protobuf::SetToDefault { - protobuf::SetToDefault { - xpr: None, // Expression type info, not needed for parse tree - type_id: std.typeId, - type_mod: std.typeMod, - collation: std.collation, - location: std.location, - } -} + // === CopyStmt (iterative) === + bindings_raw::NodeTag_T_CopyStmt => { + let cs = node_ptr as *const bindings_raw::CopyStmt; + if collect { + let node = self.collect_copy_stmt(&*cs); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_copy_stmt(&*cs); + } + } -unsafe fn convert_multi_assign_ref(mar: &bindings_raw::MultiAssignRef) -> protobuf::MultiAssignRef { - protobuf::MultiAssignRef { source: convert_node_boxed(mar.source), colno: mar.colno, ncolumns: mar.ncolumns } -} + // === PrepareStmt (iterative) === + bindings_raw::NodeTag_T_PrepareStmt => { + let ps = node_ptr as *const bindings_raw::PrepareStmt; + if collect { + let node = self.collect_prepare_stmt(&*ps); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_prepare_stmt(&*ps); + } + } -unsafe fn convert_row_expr(re: &bindings_raw::RowExpr) -> protobuf::RowExpr { - protobuf::RowExpr { - xpr: None, // Expression type info, not needed for parse tree - args: convert_list_to_nodes(re.args), - row_typeid: re.row_typeid, - row_format: re.row_format as i32 + 1, - colnames: convert_list_to_nodes(re.colnames), - location: re.location, - } -} + // === ExecuteStmt (iterative) === + bindings_raw::NodeTag_T_ExecuteStmt => { + let es = node_ptr as *const bindings_raw::ExecuteStmt; + if collect { + let node = self.collect_execute_stmt(&*es); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_execute_stmt(&*es); + } + } -unsafe fn convert_collate_clause(cc: &bindings_raw::CollateClause) -> protobuf::CollateClause { - protobuf::CollateClause { arg: convert_node_boxed(cc.arg), collname: convert_list_to_nodes(cc.collname), location: cc.location } -} + // === DeallocateStmt (leaf) === + bindings_raw::NodeTag_T_DeallocateStmt => { + let ds = node_ptr as *const bindings_raw::DeallocateStmt; + self.push_result(protobuf::node::Node::DeallocateStmt(protobuf::DeallocateStmt { + name: convert_c_string((*ds).name), + isall: (*ds).isall, + location: (*ds).location, + })); + } -unsafe fn convert_collate_clause_opt(cc: *mut bindings_raw::CollateClause) -> Option> { - if cc.is_null() { - None - } else { - Some(Box::new(convert_collate_clause(&*cc))) - } -} + // === TransactionStmt (iterative) === + bindings_raw::NodeTag_T_TransactionStmt => { + let ts = node_ptr as *const bindings_raw::TransactionStmt; + if collect { + let node = self.collect_transaction_stmt(&*ts); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_transaction_stmt(&*ts); + } + } -unsafe fn convert_partition_spec(ps: &bindings_raw::PartitionSpec) -> protobuf::PartitionSpec { - // Map from C char values to protobuf enum values - // C: 'l'=108, 'r'=114, 'h'=104 - // Protobuf: LIST=1, RANGE=2, HASH=3 - let strategy = match ps.strategy as u8 as char { - 'l' => 1, // LIST - 'r' => 2, // RANGE - 'h' => 3, // HASH - _ => 0, // UNDEFINED - }; - protobuf::PartitionSpec { strategy, part_params: convert_list_to_nodes(ps.partParams), location: ps.location } -} + // === VacuumStmt (iterative) === + bindings_raw::NodeTag_T_VacuumStmt => { + let vs = node_ptr as *const bindings_raw::VacuumStmt; + if collect { + let node = self.collect_vacuum_stmt(&*vs); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_vacuum_stmt(&*vs); + } + } -unsafe fn convert_partition_spec_opt(ps: *mut bindings_raw::PartitionSpec) -> Option { - if ps.is_null() { - None - } else { - Some(convert_partition_spec(&*ps)) - } -} + // === VacuumRelation (iterative) === + bindings_raw::NodeTag_T_VacuumRelation => { + let vr = node_ptr as *const bindings_raw::VacuumRelation; + if collect { + let node = self.collect_vacuum_relation(&*vr); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_vacuum_relation(&*vr); + } + } -unsafe fn convert_partition_bound_spec(pbs: &bindings_raw::PartitionBoundSpec) -> protobuf::PartitionBoundSpec { - protobuf::PartitionBoundSpec { - strategy: if pbs.strategy == 0 { String::new() } else { String::from_utf8_lossy(&[pbs.strategy as u8]).to_string() }, - is_default: pbs.is_default, - modulus: pbs.modulus, - remainder: pbs.remainder, - listdatums: convert_list_to_nodes(pbs.listdatums), - lowerdatums: convert_list_to_nodes(pbs.lowerdatums), - upperdatums: convert_list_to_nodes(pbs.upperdatums), - location: pbs.location, - } -} + // === VariableSetStmt (iterative) === + bindings_raw::NodeTag_T_VariableSetStmt => { + let vss = node_ptr as *const bindings_raw::VariableSetStmt; + if collect { + let node = self.collect_variable_set_stmt(&*vss); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_variable_set_stmt(&*vss); + } + } -unsafe fn convert_partition_bound_spec_opt(pbs: *mut bindings_raw::PartitionBoundSpec) -> Option { - if pbs.is_null() { - None - } else { - Some(convert_partition_bound_spec(&*pbs)) - } -} + // === VariableShowStmt (leaf) === + bindings_raw::NodeTag_T_VariableShowStmt => { + let vss = node_ptr as *const bindings_raw::VariableShowStmt; + self.push_result(protobuf::node::Node::VariableShowStmt(protobuf::VariableShowStmt { name: convert_c_string((*vss).name) })); + } -unsafe fn convert_partition_elem(pe: &bindings_raw::PartitionElem) -> protobuf::PartitionElem { - protobuf::PartitionElem { - name: convert_c_string(pe.name), - expr: convert_node_boxed(pe.expr), - collation: convert_list_to_nodes(pe.collation), - opclass: convert_list_to_nodes(pe.opclass), - location: pe.location, - } -} + // === NotifyStmt (leaf) === + bindings_raw::NodeTag_T_NotifyStmt => { + let ns = node_ptr as *const bindings_raw::NotifyStmt; + self.push_result(protobuf::node::Node::NotifyStmt(protobuf::NotifyStmt { + conditionname: convert_c_string((*ns).conditionname), + payload: convert_c_string((*ns).payload), + })); + } -unsafe fn convert_partition_range_datum(prd: &bindings_raw::PartitionRangeDatum) -> protobuf::PartitionRangeDatum { - // Map from C enum to protobuf enum - // C: PARTITION_RANGE_DATUM_MINVALUE=-1, PARTITION_RANGE_DATUM_VALUE=0, PARTITION_RANGE_DATUM_MAXVALUE=1 - // Protobuf: UNDEFINED=0, MINVALUE=1, VALUE=2, MAXVALUE=3 - let kind = match prd.kind { - bindings_raw::PartitionRangeDatumKind_PARTITION_RANGE_DATUM_MINVALUE => 1, - bindings_raw::PartitionRangeDatumKind_PARTITION_RANGE_DATUM_VALUE => 2, - bindings_raw::PartitionRangeDatumKind_PARTITION_RANGE_DATUM_MAXVALUE => 3, - _ => 0, - }; - protobuf::PartitionRangeDatum { kind, value: convert_node_boxed(prd.value), location: prd.location } -} + // === ListenStmt (leaf) === + bindings_raw::NodeTag_T_ListenStmt => { + let ls = node_ptr as *const bindings_raw::ListenStmt; + self.push_result(protobuf::node::Node::ListenStmt(protobuf::ListenStmt { conditionname: convert_c_string((*ls).conditionname) })); + } -unsafe fn convert_cte_search_clause(csc: &bindings_raw::CTESearchClause) -> protobuf::CteSearchClause { - protobuf::CteSearchClause { - search_col_list: convert_list_to_nodes(csc.search_col_list), - search_breadth_first: csc.search_breadth_first, - search_seq_column: convert_c_string(csc.search_seq_column), - location: csc.location, - } -} + // === UnlistenStmt (leaf) === + bindings_raw::NodeTag_T_UnlistenStmt => { + let us = node_ptr as *const bindings_raw::UnlistenStmt; + self.push_result(protobuf::node::Node::UnlistenStmt(protobuf::UnlistenStmt { + conditionname: convert_c_string((*us).conditionname), + })); + } -unsafe fn convert_cte_search_clause_opt(csc: *mut bindings_raw::CTESearchClause) -> Option { - if csc.is_null() { - None - } else { - Some(convert_cte_search_clause(&*csc)) - } -} + // === DiscardStmt (leaf) === + bindings_raw::NodeTag_T_DiscardStmt => { + let ds = node_ptr as *const bindings_raw::DiscardStmt; + self.push_result(protobuf::node::Node::DiscardStmt(protobuf::DiscardStmt { target: (*ds).target as i32 + 1 })); + } -unsafe fn convert_cte_cycle_clause(ccc: &bindings_raw::CTECycleClause) -> protobuf::CteCycleClause { - protobuf::CteCycleClause { - cycle_col_list: convert_list_to_nodes(ccc.cycle_col_list), - cycle_mark_column: convert_c_string(ccc.cycle_mark_column), - cycle_mark_value: convert_node_boxed(ccc.cycle_mark_value), - cycle_mark_default: convert_node_boxed(ccc.cycle_mark_default), - cycle_path_column: convert_c_string(ccc.cycle_path_column), - location: ccc.location, - cycle_mark_type: ccc.cycle_mark_type, - cycle_mark_typmod: ccc.cycle_mark_typmod, - cycle_mark_collation: ccc.cycle_mark_collation, - cycle_mark_neop: ccc.cycle_mark_neop, - } -} + // === LockStmt (iterative) === + bindings_raw::NodeTag_T_LockStmt => { + let ls = node_ptr as *const bindings_raw::LockStmt; + if collect { + let node = self.collect_lock_stmt(&*ls); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_lock_stmt(&*ls); + } + } -unsafe fn convert_cte_cycle_clause_opt(ccc: *mut bindings_raw::CTECycleClause) -> Option> { - if ccc.is_null() { - None - } else { - Some(Box::new(convert_cte_cycle_clause(&*ccc))) - } -} + // === DoStmt (iterative) === + bindings_raw::NodeTag_T_DoStmt => { + let ds = node_ptr as *const bindings_raw::DoStmt; + if collect { + let node = self.collect_do_stmt(&*ds); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_do_stmt(&*ds); + } + } -// ============================================================================ -// Additional Statement Conversions -// ============================================================================ + // === ObjectWithArgs (iterative) === + bindings_raw::NodeTag_T_ObjectWithArgs => { + let owa = node_ptr as *const bindings_raw::ObjectWithArgs; + if collect { + let node = self.collect_object_with_args(&*owa); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_object_with_args(&*owa); + } + } -unsafe fn convert_transaction_stmt(ts: &bindings_raw::TransactionStmt) -> protobuf::TransactionStmt { - protobuf::TransactionStmt { - kind: ts.kind as i32 + 1, // Protobuf enums have UNDEFINED=0 - options: convert_list_to_nodes(ts.options), - savepoint_name: convert_c_string(ts.savepoint_name), - gid: convert_c_string(ts.gid), - chain: ts.chain, - location: ts.location, - } -} + // === CoerceToDomain (iterative) === + bindings_raw::NodeTag_T_CoerceToDomain => { + let ctd = node_ptr as *const bindings_raw::CoerceToDomain; + if collect { + let node = self.collect_coerce_to_domain(&*ctd); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_coerce_to_domain(&*ctd); + } + } -unsafe fn convert_vacuum_stmt(vs: &bindings_raw::VacuumStmt) -> protobuf::VacuumStmt { - protobuf::VacuumStmt { options: convert_list_to_nodes(vs.options), rels: convert_list_to_nodes(vs.rels), is_vacuumcmd: vs.is_vacuumcmd } -} + // === FunctionParameter (iterative) === + bindings_raw::NodeTag_T_FunctionParameter => { + let fp = node_ptr as *const bindings_raw::FunctionParameter; + if collect { + let node = self.collect_function_parameter(&*fp); + self.push_result(node); + } else { + self.queue_collect(node_ptr); + self.queue_function_parameter(&*fp); + } + } -unsafe fn convert_vacuum_relation(vr: &bindings_raw::VacuumRelation) -> protobuf::VacuumRelation { - protobuf::VacuumRelation { - relation: if vr.relation.is_null() { None } else { Some(convert_range_var(&*vr.relation)) }, - oid: vr.oid, - va_cols: convert_list_to_nodes(vr.va_cols), + _ => { + panic!( + "[ERROR] Unhandled node tag={} ({}) in iterative processor. This type needs to be migrated.", + node_tag_name(node_tag), + node_tag, + ); + } + } + } } -} -unsafe fn convert_variable_set_stmt(vss: &bindings_raw::VariableSetStmt) -> protobuf::VariableSetStmt { - protobuf::VariableSetStmt { - kind: vss.kind as i32 + 1, // Protobuf enums have UNDEFINED=0 - name: convert_c_string(vss.name), - args: convert_list_to_nodes(vss.args), - is_local: vss.is_local, + fn queue_node(&mut self, node: *const bindings_raw::Node) { + self.stack.push(ProcessingNode::with_node(node)); } -} -unsafe fn convert_variable_show_stmt(vss: &bindings_raw::VariableShowStmt) -> protobuf::VariableShowStmt { - protobuf::VariableShowStmt { name: convert_c_string(vss.name) } -} - -unsafe fn convert_create_seq_stmt(css: &bindings_raw::CreateSeqStmt) -> protobuf::CreateSeqStmt { - protobuf::CreateSeqStmt { - sequence: if css.sequence.is_null() { None } else { Some(convert_range_var(&*css.sequence)) }, - options: convert_list_to_nodes(css.options), - owner_id: css.ownerId, - for_identity: css.for_identity, - if_not_exists: css.if_not_exists, + fn queue_collect(&mut self, node: *const bindings_raw::Node) { + self.stack.push(ProcessingNode::with_collect(node)) } -} - -unsafe fn convert_do_stmt(ds: &bindings_raw::DoStmt) -> protobuf::DoStmt { - protobuf::DoStmt { args: convert_list_to_nodes(ds.args) } -} - -unsafe fn convert_lock_stmt(ls: &bindings_raw::LockStmt) -> protobuf::LockStmt { - protobuf::LockStmt { relations: convert_list_to_nodes(ls.relations), mode: ls.mode, nowait: ls.nowait } -} -unsafe fn convert_create_schema_stmt(css: &bindings_raw::CreateSchemaStmt) -> protobuf::CreateSchemaStmt { - protobuf::CreateSchemaStmt { - schemaname: convert_c_string(css.schemaname), - authrole: if css.authrole.is_null() { None } else { Some(convert_role_spec(&*css.authrole)) }, - schema_elts: convert_list_to_nodes(css.schemaElts), - if_not_exists: css.if_not_exists, + fn push_result(&mut self, node: protobuf::node::Node) { + println!("[push] result variant={:?} → result_stack will be {}", std::mem::discriminant(&node), self.result_stack.len() + 1); + self.result_stack.push(protobuf::Node { node: Some(node) }); } -} -unsafe fn convert_rename_stmt(rs: &bindings_raw::RenameStmt) -> protobuf::RenameStmt { - protobuf::RenameStmt { - rename_type: rs.renameType as i32 + 1, // Protobuf ObjectType has UNDEFINED=0 - relation_type: rs.relationType as i32 + 1, - relation: if rs.relation.is_null() { None } else { Some(convert_range_var(&*rs.relation)) }, - object: convert_node_boxed(rs.object), - subname: convert_c_string(rs.subname), - newname: convert_c_string(rs.newname), - behavior: rs.behavior as i32 + 1, - missing_ok: rs.missing_ok, + fn single_result(&mut self, node: *const bindings_raw::Node) -> Option { + if node.is_null() { + println!("[single] node is null — skipping pop"); + return None; + } + + let result = self.result_stack.pop().expect("result stack should not be empty while processing"); + println!("[single] popped result — result_stack now={}", self.result_stack.len()); + Some(result) } -} -unsafe fn convert_create_function_stmt(cfs: &bindings_raw::CreateFunctionStmt) -> protobuf::CreateFunctionStmt { - protobuf::CreateFunctionStmt { - is_procedure: cfs.is_procedure, - replace: cfs.replace, - funcname: convert_list_to_nodes(cfs.funcname), - parameters: convert_list_to_nodes(cfs.parameters), - return_type: if cfs.returnType.is_null() { None } else { Some(convert_type_name(&*cfs.returnType)) }, - options: convert_list_to_nodes(cfs.options), - sql_body: convert_node_boxed(cfs.sql_body), + fn single_result_box(&mut self, node: *const bindings_raw::Node) -> Option> { + self.single_result(node).map(Box::new) } -} -unsafe fn convert_alter_owner_stmt(aos: &bindings_raw::AlterOwnerStmt) -> protobuf::AlterOwnerStmt { - protobuf::AlterOwnerStmt { - object_type: aos.objectType as i32 + 1, // Protobuf ObjectType has UNDEFINED=0 - relation: if aos.relation.is_null() { None } else { Some(convert_range_var(&*aos.relation)) }, - object: convert_node_boxed(aos.object), - newowner: if aos.newowner.is_null() { None } else { Some(convert_role_spec(&*aos.newowner)) }, + fn fetch_results(&mut self, count: usize) -> Vec { + println!("[fetch] count={} from result_stack.len={}", count, self.result_stack.len()); + if count > self.result_stack.len() { + panic!( + "fetch_results: count ({}) > result_stack.len ({}) — stack contents: {:?}", + count, + self.result_stack.len(), + self.result_stack.iter().map(|n| format!("{:?}", n.node.as_ref().map(|n| std::mem::discriminant(n)))).collect::>(), + ); + } + let start = self.result_stack.len() - count; + self.result_stack.drain(start..).rev().collect() } -} -unsafe fn convert_alter_seq_stmt(ass: &bindings_raw::AlterSeqStmt) -> protobuf::AlterSeqStmt { - protobuf::AlterSeqStmt { - sequence: if ass.sequence.is_null() { None } else { Some(convert_range_var(&*ass.sequence)) }, - options: convert_list_to_nodes(ass.options), - for_identity: ass.for_identity, - missing_ok: ass.missing_ok, - } -} + unsafe fn queue_list_nodes(&mut self, list: *mut bindings_raw::List) { + if list.is_null() { + return; + } + let list = &*list; + let length = list.length as usize; -unsafe fn convert_create_enum_stmt(ces: &bindings_raw::CreateEnumStmt) -> protobuf::CreateEnumStmt { - protobuf::CreateEnumStmt { type_name: convert_list_to_nodes(ces.typeName), vals: convert_list_to_nodes(ces.vals) } -} + println!("[qlist] queuing {} nodes from list", length); + self.stack.reserve(length); -unsafe fn convert_object_with_args(owa: &bindings_raw::ObjectWithArgs) -> protobuf::ObjectWithArgs { - protobuf::ObjectWithArgs { - objname: convert_list_to_nodes(owa.objname), - objargs: convert_list_to_nodes(owa.objargs), - objfuncargs: convert_list_to_nodes(owa.objfuncargs), - args_unspecified: owa.args_unspecified, + for i in 0..length { + let cell = list.elements.add(i); + let node = (*cell).ptr_value as *const bindings_raw::Node; + if !node.is_null() { + println!("[qlist] [{}] tag={} ({})", i, node_tag_name((*node).type_), (*node).type_); + } else { + println!("[qlist] [{}] null", i); + } + self.stack.push(ProcessingNode::with_node(node)); + } } -} -unsafe fn convert_function_parameter(fp: &bindings_raw::FunctionParameter) -> protobuf::FunctionParameter { - protobuf::FunctionParameter { - name: convert_c_string(fp.name), - arg_type: if fp.argType.is_null() { None } else { Some(convert_type_name(&*fp.argType)) }, - mode: convert_function_parameter_mode(fp.mode), - defexpr: convert_node_boxed(fp.defexpr), + unsafe fn fetch_list_results(&mut self, list: *const bindings_raw::List) -> Vec { + if list.is_null() { + return Vec::new(); + } + let list = &*list; + let length = list.length as usize; + + println!("[flist] fetching {} results for list", length); + self.fetch_results(length) } -} -/// Converts raw FunctionParameterMode (ASCII char codes) to protobuf enum values -fn convert_function_parameter_mode(mode: bindings_raw::FunctionParameterMode) -> i32 { - match mode { - bindings_raw::FunctionParameterMode_FUNC_PARAM_IN => protobuf::FunctionParameterMode::FuncParamIn as i32, - bindings_raw::FunctionParameterMode_FUNC_PARAM_OUT => protobuf::FunctionParameterMode::FuncParamOut as i32, - bindings_raw::FunctionParameterMode_FUNC_PARAM_INOUT => protobuf::FunctionParameterMode::FuncParamInout as i32, - bindings_raw::FunctionParameterMode_FUNC_PARAM_VARIADIC => protobuf::FunctionParameterMode::FuncParamVariadic as i32, - bindings_raw::FunctionParameterMode_FUNC_PARAM_TABLE => protobuf::FunctionParameterMode::FuncParamTable as i32, - bindings_raw::FunctionParameterMode_FUNC_PARAM_DEFAULT => protobuf::FunctionParameterMode::FuncParamDefault as i32, - _ => 0, // Undefined + unsafe fn queue_into_clause(&mut self, ic: *const bindings_raw::IntoClause) { + if ic.is_null() { + return; + } + let ic_ref = &*ic; + if !ic_ref.rel.is_null() { + self.queue_node(ic_ref.rel as *const bindings_raw::Node); + } + self.queue_list_nodes(ic_ref.colNames); + self.queue_list_nodes(ic_ref.options); + self.queue_node(ic_ref.viewQuery); } -} -unsafe fn convert_notify_stmt(ns: &bindings_raw::NotifyStmt) -> protobuf::NotifyStmt { - protobuf::NotifyStmt { conditionname: convert_c_string(ns.conditionname), payload: convert_c_string(ns.payload) } -} + unsafe fn fetch_into_clause(&mut self, ic: *const bindings_raw::IntoClause) -> Option> { + if ic.is_null() { + return None; + } + let ic_ref = &*ic; + let rel = if ic_ref.rel.is_null() { None } else { self.pop_range_var() }; + let col_names = self.fetch_list_results(ic_ref.colNames); + let options = self.fetch_list_results(ic_ref.options); + let view_query = self.single_result_box(ic_ref.viewQuery); + Some(Box::new(protobuf::IntoClause { + rel, + col_names, + access_method: convert_c_string(ic_ref.accessMethod), + options, + on_commit: ic_ref.onCommit as i32 + 1, + table_space_name: convert_c_string(ic_ref.tableSpaceName), + view_query, + skip_data: ic_ref.skipData, + })) + } -unsafe fn convert_listen_stmt(ls: &bindings_raw::ListenStmt) -> protobuf::ListenStmt { - protobuf::ListenStmt { conditionname: convert_c_string(ls.conditionname) } -} + unsafe fn queue_with_clause(&mut self, wc: *mut bindings_raw::WithClause) { + if wc.is_null() { + return; + } -unsafe fn convert_unlisten_stmt(us: &bindings_raw::UnlistenStmt) -> protobuf::UnlistenStmt { - protobuf::UnlistenStmt { conditionname: convert_c_string(us.conditionname) } -} + let wc = &*wc; -unsafe fn convert_discard_stmt(ds: &bindings_raw::DiscardStmt) -> protobuf::DiscardStmt { - protobuf::DiscardStmt { - target: ds.target as i32 + 1, // DiscardMode enum + self.queue_list_nodes(wc.ctes); } -} -unsafe fn convert_coerce_to_domain(ctd: &bindings_raw::CoerceToDomain) -> protobuf::CoerceToDomain { - protobuf::CoerceToDomain { - xpr: None, - arg: convert_node_boxed(ctd.arg as *mut bindings_raw::Node), - resulttype: ctd.resulttype, - resulttypmod: ctd.resulttypmod, - resultcollid: ctd.resultcollid, - coercionformat: ctd.coercionformat as i32 + 1, - location: ctd.location, - } -} + unsafe fn fetch_with_clause(&mut self, wc: *mut bindings_raw::WithClause) -> Option { + if wc.is_null() { + return None; + } -unsafe fn convert_composite_type_stmt(cts: &bindings_raw::CompositeTypeStmt) -> protobuf::CompositeTypeStmt { - protobuf::CompositeTypeStmt { - typevar: if cts.typevar.is_null() { None } else { Some(convert_range_var(&*cts.typevar)) }, - coldeflist: convert_list_to_nodes(cts.coldeflist), - } -} + let wc = &*wc; -unsafe fn convert_create_domain_stmt(cds: &bindings_raw::CreateDomainStmt) -> protobuf::CreateDomainStmt { - protobuf::CreateDomainStmt { - domainname: convert_list_to_nodes(cds.domainname), - type_name: if cds.typeName.is_null() { None } else { Some(convert_type_name(&*cds.typeName)) }, - coll_clause: convert_collate_clause_opt(cds.collClause), - constraints: convert_list_to_nodes(cds.constraints), + Some(protobuf::WithClause { ctes: self.fetch_list_results(wc.ctes), recursive: wc.recursive, location: wc.location }) } -} -unsafe fn convert_create_extension_stmt(ces: &bindings_raw::CreateExtensionStmt) -> protobuf::CreateExtensionStmt { - protobuf::CreateExtensionStmt { - extname: convert_c_string(ces.extname), - if_not_exists: ces.if_not_exists, - options: convert_list_to_nodes(ces.options), - } -} + unsafe fn queue_select_stmt(&mut self, stmt: &bindings_raw::SelectStmt) { + self.queue_list_nodes(stmt.distinctClause); + self.queue_into_clause(stmt.intoClause); + self.queue_list_nodes(stmt.targetList); + self.queue_list_nodes(stmt.fromClause); + self.queue_node(stmt.whereClause); + self.queue_list_nodes(stmt.groupClause); + self.queue_node(stmt.havingClause); + self.queue_list_nodes(stmt.windowClause); + self.queue_list_nodes(stmt.valuesLists); + self.queue_list_nodes(stmt.sortClause); + self.queue_node(stmt.limitOffset); + self.queue_node(stmt.limitCount); + self.queue_list_nodes(stmt.lockingClause); + self.queue_with_clause(stmt.withClause); -unsafe fn convert_create_publication_stmt(cps: &bindings_raw::CreatePublicationStmt) -> protobuf::CreatePublicationStmt { - protobuf::CreatePublicationStmt { - pubname: convert_c_string(cps.pubname), - options: convert_list_to_nodes(cps.options), - pubobjects: convert_list_to_nodes(cps.pubobjects), - for_all_tables: cps.for_all_tables, - } -} + if !stmt.larg.is_null() { + self.queue_node(stmt.larg as *const bindings_raw::Node); + } -unsafe fn convert_alter_publication_stmt(aps: &bindings_raw::AlterPublicationStmt) -> protobuf::AlterPublicationStmt { - protobuf::AlterPublicationStmt { - pubname: convert_c_string(aps.pubname), - options: convert_list_to_nodes(aps.options), - pubobjects: convert_list_to_nodes(aps.pubobjects), - for_all_tables: aps.for_all_tables, - action: aps.action as i32 + 1, + if !stmt.rarg.is_null() { + self.queue_node(stmt.rarg as *const bindings_raw::Node); + } } -} -unsafe fn convert_create_subscription_stmt(css: &bindings_raw::CreateSubscriptionStmt) -> protobuf::CreateSubscriptionStmt { - protobuf::CreateSubscriptionStmt { - subname: convert_c_string(css.subname), - conninfo: convert_c_string(css.conninfo), - publication: convert_list_to_nodes(css.publication), - options: convert_list_to_nodes(css.options), + fn pop_select_stmt(&mut self) -> Option> { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::SelectStmt(s)) => Some(s), + _ => None, + }) } -} -unsafe fn convert_alter_subscription_stmt(ass: &bindings_raw::AlterSubscriptionStmt) -> protobuf::AlterSubscriptionStmt { - protobuf::AlterSubscriptionStmt { - kind: ass.kind as i32 + 1, - subname: convert_c_string(ass.subname), - conninfo: convert_c_string(ass.conninfo), - publication: convert_list_to_nodes(ass.publication), - options: convert_list_to_nodes(ass.options), + unsafe fn collect_select_stmt(&mut self, stmt: &bindings_raw::SelectStmt) -> protobuf::node::Node { + let a = protobuf::SelectStmt { + distinct_clause: self.fetch_list_results(stmt.distinctClause), + into_clause: self.fetch_into_clause(stmt.intoClause), + target_list: self.fetch_list_results(stmt.targetList), + from_clause: self.fetch_list_results(stmt.fromClause), + where_clause: self.single_result_box(stmt.whereClause), + group_clause: self.fetch_list_results(stmt.groupClause), + group_distinct: stmt.groupDistinct, + having_clause: self.single_result_box(stmt.havingClause), + window_clause: self.fetch_list_results(stmt.windowClause), + values_lists: self.fetch_list_results(stmt.valuesLists), + sort_clause: self.fetch_list_results(stmt.sortClause), + limit_offset: self.single_result_box(stmt.limitOffset), + limit_count: self.single_result_box(stmt.limitCount), + limit_option: stmt.limitOption as i32 + 1, // Protobuf enums have UNDEFINED=0, so C values need +1 + locking_clause: self.fetch_list_results(stmt.lockingClause), + with_clause: self.fetch_with_clause(stmt.withClause), + op: stmt.op as i32 + 1, // Protobuf SetOperation has UNDEFINED=0, so C values need +1 + all: stmt.all, + larg: if stmt.larg.is_null() { None } else { self.pop_select_stmt() }, + rarg: if stmt.rarg.is_null() { None } else { self.pop_select_stmt() }, + }; + + protobuf::node::Node::SelectStmt(Box::new(a)) } -} -unsafe fn convert_publication_obj_spec(pos: &bindings_raw::PublicationObjSpec) -> protobuf::PublicationObjSpec { - let pubtable = if pos.pubtable.is_null() { None } else { Some(Box::new(convert_publication_table(&*pos.pubtable))) }; - protobuf::PublicationObjSpec { pubobjtype: pos.pubobjtype as i32 + 1, name: convert_c_string(pos.name), pubtable, location: pos.location } -} + // ==================================================================== + // ResTarget + // ==================================================================== -unsafe fn convert_publication_table(pt: &bindings_raw::PublicationTable) -> protobuf::PublicationTable { - let relation = if pt.relation.is_null() { None } else { Some(convert_range_var(&*pt.relation)) }; - protobuf::PublicationTable { - relation, - where_clause: convert_node_boxed(pt.whereClause as *mut bindings_raw::Node), - columns: convert_list_to_nodes(pt.columns), + unsafe fn queue_res_target(&mut self, rt: &bindings_raw::ResTarget) { + // Queue children that need recursive processing: + // indirection (list of nodes) and val (single node) + println!( + "[queue] ResTarget children: indirection={}, val={}", + if rt.indirection.is_null() { "null".to_string() } else { format!("list({})", (*rt.indirection).length) }, + if rt.val.is_null() { "null" } else { "present" }, + ); + self.queue_list_nodes(rt.indirection); + self.queue_node(rt.val); } -} -unsafe fn convert_create_trig_stmt(cts: &bindings_raw::CreateTrigStmt) -> protobuf::CreateTrigStmt { - protobuf::CreateTrigStmt { - replace: cts.replace, - isconstraint: cts.isconstraint, - trigname: convert_c_string(cts.trigname), - relation: if cts.relation.is_null() { None } else { Some(convert_range_var(&*cts.relation)) }, - funcname: convert_list_to_nodes(cts.funcname), - args: convert_list_to_nodes(cts.args), - row: cts.row, - timing: cts.timing as i32, - events: cts.events as i32, - columns: convert_list_to_nodes(cts.columns), - when_clause: convert_node_boxed(cts.whenClause), - transition_rels: convert_list_to_nodes(cts.transitionRels), - deferrable: cts.deferrable, - initdeferred: cts.initdeferred, - constrrel: if cts.constrrel.is_null() { None } else { Some(convert_range_var(&*cts.constrrel)) }, - } -} + unsafe fn collect_res_target(&mut self, rt: &bindings_raw::ResTarget) -> protobuf::node::Node { + let indirection = self.fetch_list_results(rt.indirection); + let val = self.single_result_box(rt.val); -unsafe fn convert_call_stmt(cs: &bindings_raw::CallStmt) -> protobuf::CallStmt { - protobuf::CallStmt { - funccall: if cs.funccall.is_null() { None } else { Some(Box::new(convert_func_call(&*cs.funccall))) }, - funcexpr: None, // This is a post-analysis field, not available in raw parse tree - outargs: convert_list_to_nodes(cs.outargs), - } -} + println!( + "[collect] ResTarget: name={:?}, indirection_len={}, val={:?}, location={}", + convert_c_string(rt.name), + indirection.len(), + val.as_ref().map(|v| format!("{:?}", v.node.as_ref().map(|n| std::mem::discriminant(n)))), + rt.location, + ); -unsafe fn convert_rule_stmt(rs: &bindings_raw::RuleStmt) -> protobuf::RuleStmt { - protobuf::RuleStmt { - relation: if rs.relation.is_null() { None } else { Some(convert_range_var(&*rs.relation)) }, - rulename: convert_c_string(rs.rulename), - where_clause: convert_node_boxed(rs.whereClause), - event: rs.event as i32 + 1, // CmdType enum - instead: rs.instead, - actions: convert_list_to_nodes(rs.actions), - replace: rs.replace, + let res = protobuf::ResTarget { name: convert_c_string(rt.name), indirection, val, location: rt.location }; + protobuf::node::Node::ResTarget(Box::new(res)) } -} -unsafe fn convert_grant_stmt(gs: &bindings_raw::GrantStmt) -> protobuf::GrantStmt { - protobuf::GrantStmt { - is_grant: gs.is_grant, - targtype: gs.targtype as i32 + 1, - objtype: gs.objtype as i32 + 1, - objects: convert_list_to_nodes(gs.objects), - privileges: convert_list_to_nodes(gs.privileges), - grantees: convert_list_to_nodes(gs.grantees), - grant_option: gs.grant_option, - grantor: if gs.grantor.is_null() { None } else { Some(convert_role_spec(&*gs.grantor)) }, - behavior: gs.behavior as i32 + 1, - } -} + // ==================================================================== + // ColumnRef + // ==================================================================== -unsafe fn convert_grant_role_stmt(grs: &bindings_raw::GrantRoleStmt) -> protobuf::GrantRoleStmt { - protobuf::GrantRoleStmt { - granted_roles: convert_list_to_nodes(grs.granted_roles), - grantee_roles: convert_list_to_nodes(grs.grantee_roles), - is_grant: grs.is_grant, - opt: convert_list_to_nodes(grs.opt), - grantor: if grs.grantor.is_null() { None } else { Some(convert_role_spec(&*grs.grantor)) }, - behavior: grs.behavior as i32 + 1, + unsafe fn queue_column_ref(&mut self, cr: &bindings_raw::ColumnRef) { + println!( + "[queue] ColumnRef children: fields={}", + if cr.fields.is_null() { "null".to_string() } else { format!("list({})", (*cr.fields).length) }, + ); + self.queue_list_nodes(cr.fields); } -} -unsafe fn convert_refresh_mat_view_stmt(rmvs: &bindings_raw::RefreshMatViewStmt) -> protobuf::RefreshMatViewStmt { - protobuf::RefreshMatViewStmt { - concurrent: rmvs.concurrent, - skip_data: rmvs.skipData, - relation: if rmvs.relation.is_null() { None } else { Some(convert_range_var(&*rmvs.relation)) }, + unsafe fn collect_column_ref(&mut self, cr: &bindings_raw::ColumnRef) -> protobuf::node::Node { + let fields = self.fetch_list_results(cr.fields); + println!("[collect] ColumnRef: fields_len={}, location={}", fields.len(), cr.location); + protobuf::node::Node::ColumnRef(protobuf::ColumnRef { fields, location: cr.location }) } -} -unsafe fn convert_merge_stmt(ms: &bindings_raw::MergeStmt) -> protobuf::MergeStmt { - protobuf::MergeStmt { - relation: if ms.relation.is_null() { None } else { Some(convert_range_var(&*ms.relation)) }, - source_relation: convert_node_boxed(ms.sourceRelation), - join_condition: convert_node_boxed(ms.joinCondition), - merge_when_clauses: convert_list_to_nodes(ms.mergeWhenClauses), - returning_list: convert_list_to_nodes(ms.returningList), - with_clause: convert_with_clause_opt(ms.withClause), - } -} + // ==================================================================== + // RangeVar (iterative — queues alias.colnames) + // ==================================================================== -unsafe fn convert_merge_action(ma: &bindings_raw::MergeAction) -> protobuf::MergeAction { - protobuf::MergeAction { - match_kind: ma.matchKind as i32 + 1, - command_type: ma.commandType as i32 + 1, - r#override: ma.override_ as i32 + 1, - qual: convert_node_boxed(ma.qual), - target_list: convert_list_to_nodes(ma.targetList), - update_colnos: convert_list_to_nodes(ma.updateColnos), + unsafe fn queue_range_var(&mut self, rv: &bindings_raw::RangeVar) { + if !rv.alias.is_null() { + self.queue_list_nodes((*rv.alias).colnames); + } } -} -unsafe fn convert_merge_when_clause(mwc: &bindings_raw::MergeWhenClause) -> protobuf::MergeWhenClause { - protobuf::MergeWhenClause { - match_kind: mwc.matchKind as i32 + 1, - command_type: mwc.commandType as i32 + 1, - r#override: mwc.override_ as i32 + 1, - condition: convert_node_boxed(mwc.condition), - target_list: convert_list_to_nodes(mwc.targetList), - values: convert_list_to_nodes(mwc.values), + unsafe fn collect_range_var(&mut self, rv: &bindings_raw::RangeVar) -> protobuf::node::Node { + let alias = if rv.alias.is_null() { + None + } else { + let alias = &*rv.alias; + Some(protobuf::Alias { aliasname: convert_c_string(alias.aliasname), colnames: self.fetch_list_results(alias.colnames) }) + }; + protobuf::node::Node::RangeVar(protobuf::RangeVar { + catalogname: convert_c_string(rv.catalogname), + schemaname: convert_c_string(rv.schemaname), + relname: convert_c_string(rv.relname), + inh: rv.inh, + relpersistence: std::string::String::from_utf8_lossy(&[rv.relpersistence as u8]).to_string(), + alias, + location: rv.location, + }) } -} -unsafe fn convert_range_function(rf: &bindings_raw::RangeFunction) -> protobuf::RangeFunction { - protobuf::RangeFunction { - lateral: rf.lateral, - ordinality: rf.ordinality, - is_rowsfrom: rf.is_rowsfrom, - functions: convert_list_to_nodes(rf.functions), - alias: if rf.alias.is_null() { None } else { Some(convert_alias(&*rf.alias)) }, - coldeflist: convert_list_to_nodes(rf.coldeflist), + fn pop_range_var(&mut self) -> Option { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::RangeVar(rv)) => Some(rv), + other => panic!("[ERROR] Expected RangeVar on result stack, got {:?}", other.as_ref().map(|n| std::mem::discriminant(n))), + }) } -} -unsafe fn convert_access_priv(ap: &bindings_raw::AccessPriv) -> protobuf::AccessPriv { - protobuf::AccessPriv { priv_name: convert_c_string(ap.priv_name), cols: convert_list_to_nodes(ap.cols) } -} - -// ============================================================================ -// Utility Functions -// ============================================================================ + // ==================================================================== + // JoinExpr + // ==================================================================== -/// Converts a C string pointer to a Rust String. -unsafe fn convert_c_string(ptr: *const c_char) -> std::string::String { - if ptr.is_null() { - std::string::String::new() - } else { - CStr::from_ptr(ptr).to_string_lossy().to_string() + unsafe fn queue_join_expr(&mut self, je: &bindings_raw::JoinExpr) { + self.queue_list_nodes(je.usingClause); + self.queue_node(je.larg); + self.queue_node(je.rarg); + self.queue_node(je.quals); + if !je.alias.is_null() { + self.queue_list_nodes((*je.alias).colnames); + } + if !je.join_using_alias.is_null() { + self.queue_list_nodes((*je.join_using_alias).colnames); + } } -} - -// ============================================================================ -// New Node Conversions (matching raw_deparse.rs) -// ============================================================================ - -unsafe fn convert_bit_string(bs: &bindings_raw::BitString) -> protobuf::BitString { - protobuf::BitString { bsval: convert_c_string(bs.bsval) } -} -unsafe fn convert_boolean_test(bt: &bindings_raw::BooleanTest) -> protobuf::BooleanTest { - protobuf::BooleanTest { - xpr: None, - arg: convert_node_boxed(bt.arg as *mut bindings_raw::Node), - booltesttype: bt.booltesttype as i32 + 1, - location: bt.location, + unsafe fn collect_join_expr(&mut self, je: &bindings_raw::JoinExpr) -> protobuf::node::Node { + let using_clause = self.fetch_list_results(je.usingClause); + let larg = self.single_result_box(je.larg); + let rarg = self.single_result_box(je.rarg); + let quals = self.single_result_box(je.quals); + let alias = if je.alias.is_null() { + None + } else { + Some(protobuf::Alias { aliasname: convert_c_string((*je.alias).aliasname), colnames: self.fetch_list_results((*je.alias).colnames) }) + }; + let join_using_alias = if je.join_using_alias.is_null() { + None + } else { + Some(protobuf::Alias { + aliasname: convert_c_string((*je.join_using_alias).aliasname), + colnames: self.fetch_list_results((*je.join_using_alias).colnames), + }) + }; + protobuf::node::Node::JoinExpr(Box::new(protobuf::JoinExpr { + jointype: je.jointype as i32 + 1, + is_natural: je.isNatural, + larg, + rarg, + using_clause, + join_using_alias, + quals, + alias, + rtindex: je.rtindex, + })) } -} -unsafe fn convert_create_range_stmt(crs: &bindings_raw::CreateRangeStmt) -> protobuf::CreateRangeStmt { - protobuf::CreateRangeStmt { type_name: convert_list_to_nodes(crs.typeName), params: convert_list_to_nodes(crs.params) } -} + // ==================================================================== + // A_Expr + // ==================================================================== -unsafe fn convert_alter_enum_stmt(aes: &bindings_raw::AlterEnumStmt) -> protobuf::AlterEnumStmt { - protobuf::AlterEnumStmt { - type_name: convert_list_to_nodes(aes.typeName), - old_val: convert_c_string(aes.oldVal), - new_val: convert_c_string(aes.newVal), - new_val_neighbor: convert_c_string(aes.newValNeighbor), - new_val_is_after: aes.newValIsAfter, - skip_if_new_val_exists: aes.skipIfNewValExists, + unsafe fn queue_a_expr(&mut self, expr: &bindings_raw::A_Expr) { + self.queue_list_nodes(expr.name); + self.queue_node(expr.lexpr); + self.queue_node(expr.rexpr); } -} -unsafe fn convert_close_portal_stmt(cps: &bindings_raw::ClosePortalStmt) -> protobuf::ClosePortalStmt { - protobuf::ClosePortalStmt { portalname: convert_c_string(cps.portalname) } -} - -unsafe fn convert_fetch_stmt(fs: &bindings_raw::FetchStmt) -> protobuf::FetchStmt { - protobuf::FetchStmt { - direction: fs.direction as i32 + 1, - how_many: fs.howMany as i64, - portalname: convert_c_string(fs.portalname), - ismove: fs.ismove, + unsafe fn collect_a_expr(&mut self, expr: &bindings_raw::A_Expr) -> protobuf::node::Node { + let name = self.fetch_list_results(expr.name); + let lexpr = self.single_result_box(expr.lexpr); + let rexpr = self.single_result_box(expr.rexpr); + protobuf::node::Node::AExpr(Box::new(protobuf::AExpr { kind: expr.kind as i32 + 1, name, lexpr, rexpr, location: expr.location })) } -} -unsafe fn convert_declare_cursor_stmt(dcs: &bindings_raw::DeclareCursorStmt) -> protobuf::DeclareCursorStmt { - protobuf::DeclareCursorStmt { portalname: convert_c_string(dcs.portalname), options: dcs.options, query: convert_node_boxed(dcs.query) } -} + // ==================================================================== + // FuncCall + // ==================================================================== -unsafe fn convert_define_stmt(ds: &bindings_raw::DefineStmt) -> protobuf::DefineStmt { - protobuf::DefineStmt { - kind: ds.kind as i32 + 1, - oldstyle: ds.oldstyle, - defnames: convert_list_to_nodes(ds.defnames), - args: convert_list_to_nodes(ds.args), - definition: convert_list_to_nodes(ds.definition), - if_not_exists: ds.if_not_exists, - replace: ds.replace, + unsafe fn queue_func_call(&mut self, fc: &bindings_raw::FuncCall) { + self.queue_list_nodes(fc.funcname); + self.queue_list_nodes(fc.args); + self.queue_list_nodes(fc.agg_order); + self.queue_node(fc.agg_filter); + if !fc.over.is_null() { + self.queue_node(fc.over as *const bindings_raw::Node); + } } -} -unsafe fn convert_comment_stmt(cs: &bindings_raw::CommentStmt) -> protobuf::CommentStmt { - protobuf::CommentStmt { objtype: cs.objtype as i32 + 1, object: convert_node_boxed(cs.object), comment: convert_c_string(cs.comment) } -} + unsafe fn collect_func_call(&mut self, fc: &bindings_raw::FuncCall) -> protobuf::node::Node { + let funcname = self.fetch_list_results(fc.funcname); + let args = self.fetch_list_results(fc.args); + let agg_order = self.fetch_list_results(fc.agg_order); + let agg_filter = self.single_result_box(fc.agg_filter); + let over = if fc.over.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::WindowDef(wd)) => Some(wd), + _ => None, + }) + }; + protobuf::node::Node::FuncCall(Box::new(protobuf::FuncCall { + funcname, + args, + agg_order, + agg_filter, + over, + agg_within_group: fc.agg_within_group, + agg_star: fc.agg_star, + agg_distinct: fc.agg_distinct, + func_variadic: fc.func_variadic, + funcformat: fc.funcformat as i32 + 1, + location: fc.location, + })) + } -unsafe fn convert_sec_label_stmt(sls: &bindings_raw::SecLabelStmt) -> protobuf::SecLabelStmt { - protobuf::SecLabelStmt { - objtype: sls.objtype as i32 + 1, - object: convert_node_boxed(sls.object), - provider: convert_c_string(sls.provider), - label: convert_c_string(sls.label), + // ==================================================================== + // WindowDef + // ==================================================================== + + unsafe fn queue_window_def(&mut self, wd: &bindings_raw::WindowDef) { + self.queue_list_nodes(wd.partitionClause); + self.queue_list_nodes(wd.orderClause); + self.queue_node(wd.startOffset); + self.queue_node(wd.endOffset); + } + + unsafe fn collect_window_def(&mut self, wd: &bindings_raw::WindowDef) -> protobuf::node::Node { + let partition_clause = self.fetch_list_results(wd.partitionClause); + let order_clause = self.fetch_list_results(wd.orderClause); + let start_offset = self.single_result_box(wd.startOffset); + let end_offset = self.single_result_box(wd.endOffset); + protobuf::node::Node::WindowDef(Box::new(protobuf::WindowDef { + name: convert_c_string(wd.name), + refname: convert_c_string(wd.refname), + partition_clause, + order_clause, + frame_options: wd.frameOptions, + start_offset, + end_offset, + location: wd.location, + })) } -} -unsafe fn convert_create_role_stmt(crs: &bindings_raw::CreateRoleStmt) -> protobuf::CreateRoleStmt { - protobuf::CreateRoleStmt { stmt_type: crs.stmt_type as i32 + 1, role: convert_c_string(crs.role), options: convert_list_to_nodes(crs.options) } -} + // ==================================================================== + // InsertStmt + // ==================================================================== -unsafe fn convert_alter_role_stmt(ars: &bindings_raw::AlterRoleStmt) -> protobuf::AlterRoleStmt { - protobuf::AlterRoleStmt { - role: if ars.role.is_null() { None } else { Some(convert_role_spec(&*ars.role)) }, - options: convert_list_to_nodes(ars.options), - action: ars.action, + unsafe fn queue_insert_stmt(&mut self, stmt: &bindings_raw::InsertStmt) { + if !stmt.relation.is_null() { + self.queue_node(stmt.relation as *const bindings_raw::Node); + } + self.queue_list_nodes(stmt.cols); + self.queue_node(stmt.selectStmt); + self.queue_on_conflict_clause(stmt.onConflictClause); + self.queue_list_nodes(stmt.returningList); + self.queue_with_clause(stmt.withClause); } -} -unsafe fn convert_alter_role_set_stmt(arss: &bindings_raw::AlterRoleSetStmt) -> protobuf::AlterRoleSetStmt { - protobuf::AlterRoleSetStmt { - role: if arss.role.is_null() { None } else { Some(convert_role_spec(&*arss.role)) }, - database: convert_c_string(arss.database), - setstmt: convert_variable_set_stmt_opt(arss.setstmt), + unsafe fn collect_insert_stmt(&mut self, stmt: &bindings_raw::InsertStmt) -> protobuf::node::Node { + let relation = if stmt.relation.is_null() { None } else { self.pop_range_var() }; + let cols = self.fetch_list_results(stmt.cols); + let select_stmt = self.single_result_box(stmt.selectStmt); + let on_conflict_clause = self.fetch_on_conflict_clause(stmt.onConflictClause); + let returning_list = self.fetch_list_results(stmt.returningList); + let with_clause = self.fetch_with_clause(stmt.withClause); + protobuf::node::Node::InsertStmt(Box::new(protobuf::InsertStmt { + relation, + cols, + select_stmt, + on_conflict_clause, + returning_list, + with_clause, + r#override: stmt.override_ as i32 + 1, + })) } -} -unsafe fn convert_drop_role_stmt(drs: &bindings_raw::DropRoleStmt) -> protobuf::DropRoleStmt { - protobuf::DropRoleStmt { roles: convert_list_to_nodes(drs.roles), missing_ok: drs.missing_ok } -} + // ==================================================================== + // UpdateStmt + // ==================================================================== -unsafe fn convert_create_policy_stmt(cps: &bindings_raw::CreatePolicyStmt) -> protobuf::CreatePolicyStmt { - protobuf::CreatePolicyStmt { - policy_name: convert_c_string(cps.policy_name), - table: if cps.table.is_null() { None } else { Some(convert_range_var(&*cps.table)) }, - cmd_name: convert_c_string(cps.cmd_name), - permissive: cps.permissive, - roles: convert_list_to_nodes(cps.roles), - qual: convert_node_boxed(cps.qual), - with_check: convert_node_boxed(cps.with_check), + unsafe fn queue_update_stmt(&mut self, stmt: &bindings_raw::UpdateStmt) { + if !stmt.relation.is_null() { + self.queue_node(stmt.relation as *const bindings_raw::Node); + } + self.queue_list_nodes(stmt.targetList); + self.queue_node(stmt.whereClause); + self.queue_list_nodes(stmt.fromClause); + self.queue_list_nodes(stmt.returningList); + self.queue_with_clause(stmt.withClause); } -} -unsafe fn convert_alter_policy_stmt(aps: &bindings_raw::AlterPolicyStmt) -> protobuf::AlterPolicyStmt { - protobuf::AlterPolicyStmt { - policy_name: convert_c_string(aps.policy_name), - table: if aps.table.is_null() { None } else { Some(convert_range_var(&*aps.table)) }, - roles: convert_list_to_nodes(aps.roles), - qual: convert_node_boxed(aps.qual), - with_check: convert_node_boxed(aps.with_check), + unsafe fn collect_update_stmt(&mut self, stmt: &bindings_raw::UpdateStmt) -> protobuf::node::Node { + let relation = if stmt.relation.is_null() { None } else { self.pop_range_var() }; + let target_list = self.fetch_list_results(stmt.targetList); + let where_clause = self.single_result_box(stmt.whereClause); + let from_clause = self.fetch_list_results(stmt.fromClause); + let returning_list = self.fetch_list_results(stmt.returningList); + let with_clause = self.fetch_with_clause(stmt.withClause); + protobuf::node::Node::UpdateStmt(Box::new(protobuf::UpdateStmt { + relation, + target_list, + where_clause, + from_clause, + returning_list, + with_clause, + })) } -} -unsafe fn convert_create_event_trig_stmt(cets: &bindings_raw::CreateEventTrigStmt) -> protobuf::CreateEventTrigStmt { - protobuf::CreateEventTrigStmt { - trigname: convert_c_string(cets.trigname), - eventname: convert_c_string(cets.eventname), - whenclause: convert_list_to_nodes(cets.whenclause), - funcname: convert_list_to_nodes(cets.funcname), - } -} + // ==================================================================== + // DeleteStmt + // ==================================================================== -unsafe fn convert_alter_event_trig_stmt(aets: &bindings_raw::AlterEventTrigStmt) -> protobuf::AlterEventTrigStmt { - protobuf::AlterEventTrigStmt { - trigname: convert_c_string(aets.trigname), - tgenabled: String::from_utf8_lossy(&[aets.tgenabled as u8]).to_string(), + unsafe fn queue_delete_stmt(&mut self, stmt: &bindings_raw::DeleteStmt) { + if !stmt.relation.is_null() { + self.queue_node(stmt.relation as *const bindings_raw::Node); + } + self.queue_list_nodes(stmt.usingClause); + self.queue_node(stmt.whereClause); + self.queue_list_nodes(stmt.returningList); + self.queue_with_clause(stmt.withClause); } -} -unsafe fn convert_create_plang_stmt(cpls: &bindings_raw::CreatePLangStmt) -> protobuf::CreatePLangStmt { - protobuf::CreatePLangStmt { - replace: cpls.replace, - plname: convert_c_string(cpls.plname), - plhandler: convert_list_to_nodes(cpls.plhandler), - plinline: convert_list_to_nodes(cpls.plinline), - plvalidator: convert_list_to_nodes(cpls.plvalidator), - pltrusted: cpls.pltrusted, + unsafe fn collect_delete_stmt(&mut self, stmt: &bindings_raw::DeleteStmt) -> protobuf::node::Node { + let relation = if stmt.relation.is_null() { None } else { self.pop_range_var() }; + let using_clause = self.fetch_list_results(stmt.usingClause); + let where_clause = self.single_result_box(stmt.whereClause); + let returning_list = self.fetch_list_results(stmt.returningList); + let with_clause = self.fetch_with_clause(stmt.withClause); + protobuf::node::Node::DeleteStmt(Box::new(protobuf::DeleteStmt { relation, using_clause, where_clause, returning_list, with_clause })) } -} -unsafe fn convert_create_am_stmt(cas: &bindings_raw::CreateAmStmt) -> protobuf::CreateAmStmt { - protobuf::CreateAmStmt { - amname: convert_c_string(cas.amname), - handler_name: convert_list_to_nodes(cas.handler_name), - amtype: String::from_utf8_lossy(&[cas.amtype as u8]).to_string(), - } -} + // ==================================================================== + // SortBy + // ==================================================================== -unsafe fn convert_create_op_class_stmt(cocs: &bindings_raw::CreateOpClassStmt) -> protobuf::CreateOpClassStmt { - protobuf::CreateOpClassStmt { - opclassname: convert_list_to_nodes(cocs.opclassname), - opfamilyname: convert_list_to_nodes(cocs.opfamilyname), - amname: convert_c_string(cocs.amname), - datatype: if cocs.datatype.is_null() { None } else { Some(convert_type_name(&*cocs.datatype)) }, - items: convert_list_to_nodes(cocs.items), - is_default: cocs.isDefault, + unsafe fn queue_sort_by(&mut self, sb: &bindings_raw::SortBy) { + self.queue_node(sb.node); + self.queue_list_nodes(sb.useOp); } -} -unsafe fn convert_create_op_class_item(coci: &bindings_raw::CreateOpClassItem) -> protobuf::CreateOpClassItem { - protobuf::CreateOpClassItem { - itemtype: coci.itemtype, - name: if coci.name.is_null() { None } else { Some(convert_object_with_args(&*coci.name)) }, - number: coci.number, - order_family: convert_list_to_nodes(coci.order_family), - class_args: convert_list_to_nodes(coci.class_args), - storedtype: if coci.storedtype.is_null() { None } else { Some(convert_type_name(&*coci.storedtype)) }, + unsafe fn collect_sort_by(&mut self, sb: &bindings_raw::SortBy) -> protobuf::node::Node { + let node = self.single_result_box(sb.node); + let use_op = self.fetch_list_results(sb.useOp); + protobuf::node::Node::SortBy(Box::new(protobuf::SortBy { + node, + sortby_dir: sb.sortby_dir as i32 + 1, + sortby_nulls: sb.sortby_nulls as i32 + 1, + use_op, + location: sb.location, + })) } -} -unsafe fn convert_create_op_family_stmt(cofs: &bindings_raw::CreateOpFamilyStmt) -> protobuf::CreateOpFamilyStmt { - protobuf::CreateOpFamilyStmt { opfamilyname: convert_list_to_nodes(cofs.opfamilyname), amname: convert_c_string(cofs.amname) } -} + // ==================================================================== + // TypeCast + // ==================================================================== -unsafe fn convert_alter_op_family_stmt(aofs: &bindings_raw::AlterOpFamilyStmt) -> protobuf::AlterOpFamilyStmt { - protobuf::AlterOpFamilyStmt { - opfamilyname: convert_list_to_nodes(aofs.opfamilyname), - amname: convert_c_string(aofs.amname), - is_drop: aofs.isDrop, - items: convert_list_to_nodes(aofs.items), + unsafe fn queue_type_cast(&mut self, tc: &bindings_raw::TypeCast) { + self.queue_node(tc.arg); + if !tc.typeName.is_null() { + self.queue_node(tc.typeName as *const bindings_raw::Node); + } } -} -unsafe fn convert_create_fdw_stmt(cfds: &bindings_raw::CreateFdwStmt) -> protobuf::CreateFdwStmt { - protobuf::CreateFdwStmt { - fdwname: convert_c_string(cfds.fdwname), - func_options: convert_list_to_nodes(cfds.func_options), - options: convert_list_to_nodes(cfds.options), + unsafe fn collect_type_cast(&mut self, tc: &bindings_raw::TypeCast) -> protobuf::node::Node { + let arg = self.single_result_box(tc.arg); + let type_name = if tc.typeName.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::TypeName(tn)) => Some(tn), + _ => None, + }) + }; + protobuf::node::Node::TypeCast(Box::new(protobuf::TypeCast { arg, type_name, location: tc.location })) + } + + // ==================================================================== + // TypeName + // ==================================================================== + + unsafe fn queue_type_name(&mut self, tn: &bindings_raw::TypeName) { + self.queue_list_nodes(tn.names); + self.queue_list_nodes(tn.typmods); + self.queue_list_nodes(tn.arrayBounds); + } + + unsafe fn collect_type_name(&mut self, tn: &bindings_raw::TypeName) -> protobuf::node::Node { + let names = self.fetch_list_results(tn.names); + let typmods = self.fetch_list_results(tn.typmods); + let array_bounds = self.fetch_list_results(tn.arrayBounds); + protobuf::node::Node::TypeName(protobuf::TypeName { + names, + type_oid: tn.typeOid, + setof: tn.setof, + pct_type: tn.pct_type, + typmods, + typemod: tn.typemod, + array_bounds, + location: tn.location, + }) } -} -unsafe fn convert_alter_fdw_stmt(afds: &bindings_raw::AlterFdwStmt) -> protobuf::AlterFdwStmt { - protobuf::AlterFdwStmt { - fdwname: convert_c_string(afds.fdwname), - func_options: convert_list_to_nodes(afds.func_options), - options: convert_list_to_nodes(afds.options), - } -} + // ==================================================================== + // OnConflictClause (helper struct — not a Node) + // ==================================================================== -unsafe fn convert_create_foreign_server_stmt(cfss: &bindings_raw::CreateForeignServerStmt) -> protobuf::CreateForeignServerStmt { - protobuf::CreateForeignServerStmt { - servername: convert_c_string(cfss.servername), - servertype: convert_c_string(cfss.servertype), - version: convert_c_string(cfss.version), - fdwname: convert_c_string(cfss.fdwname), - if_not_exists: cfss.if_not_exists, - options: convert_list_to_nodes(cfss.options), + unsafe fn queue_on_conflict_clause(&mut self, oc: *mut bindings_raw::OnConflictClause) { + if oc.is_null() { + return; + } + let oc = &*oc; + self.queue_infer_clause(oc.infer); + self.queue_list_nodes(oc.targetList); + self.queue_node(oc.whereClause); } -} -unsafe fn convert_alter_foreign_server_stmt(afss: &bindings_raw::AlterForeignServerStmt) -> protobuf::AlterForeignServerStmt { - protobuf::AlterForeignServerStmt { - servername: convert_c_string(afss.servername), - version: convert_c_string(afss.version), - options: convert_list_to_nodes(afss.options), - has_version: afss.has_version, + unsafe fn fetch_on_conflict_clause(&mut self, oc: *mut bindings_raw::OnConflictClause) -> Option> { + if oc.is_null() { + return None; + } + let oc = &*oc; + let infer = self.fetch_infer_clause(oc.infer); + let target_list = self.fetch_list_results(oc.targetList); + let where_clause = self.single_result_box(oc.whereClause); + Some(Box::new(protobuf::OnConflictClause { action: oc.action as i32 + 1, infer, target_list, where_clause, location: oc.location })) } -} -unsafe fn convert_create_foreign_table_stmt(cfts: &bindings_raw::CreateForeignTableStmt) -> protobuf::CreateForeignTableStmt { - protobuf::CreateForeignTableStmt { - base_stmt: Some(convert_create_stmt(&cfts.base)), - servername: convert_c_string(cfts.servername), - options: convert_list_to_nodes(cfts.options), - } -} + // ==================================================================== + // InferClause (helper struct — not a Node) + // ==================================================================== -unsafe fn convert_create_user_mapping_stmt(cums: &bindings_raw::CreateUserMappingStmt) -> protobuf::CreateUserMappingStmt { - protobuf::CreateUserMappingStmt { - user: if cums.user.is_null() { None } else { Some(convert_role_spec(&*cums.user)) }, - servername: convert_c_string(cums.servername), - if_not_exists: cums.if_not_exists, - options: convert_list_to_nodes(cums.options), + unsafe fn queue_infer_clause(&mut self, ic: *mut bindings_raw::InferClause) { + if ic.is_null() { + return; + } + let ic = &*ic; + self.queue_list_nodes(ic.indexElems); + self.queue_node(ic.whereClause); } -} -unsafe fn convert_alter_user_mapping_stmt(aums: &bindings_raw::AlterUserMappingStmt) -> protobuf::AlterUserMappingStmt { - protobuf::AlterUserMappingStmt { - user: if aums.user.is_null() { None } else { Some(convert_role_spec(&*aums.user)) }, - servername: convert_c_string(aums.servername), - options: convert_list_to_nodes(aums.options), + unsafe fn fetch_infer_clause(&mut self, ic: *mut bindings_raw::InferClause) -> Option> { + if ic.is_null() { + return None; + } + let ic = &*ic; + let index_elems = self.fetch_list_results(ic.indexElems); + let where_clause = self.single_result_box(ic.whereClause); + Some(Box::new(protobuf::InferClause { index_elems, where_clause, conname: convert_c_string(ic.conname), location: ic.location })) } -} -unsafe fn convert_drop_user_mapping_stmt(dums: &bindings_raw::DropUserMappingStmt) -> protobuf::DropUserMappingStmt { - protobuf::DropUserMappingStmt { - user: if dums.user.is_null() { None } else { Some(convert_role_spec(&*dums.user)) }, - servername: convert_c_string(dums.servername), - missing_ok: dums.missing_ok, - } -} + // ==================================================================== + // BoolExpr + // ==================================================================== -unsafe fn convert_import_foreign_schema_stmt(ifss: &bindings_raw::ImportForeignSchemaStmt) -> protobuf::ImportForeignSchemaStmt { - protobuf::ImportForeignSchemaStmt { - server_name: convert_c_string(ifss.server_name), - remote_schema: convert_c_string(ifss.remote_schema), - local_schema: convert_c_string(ifss.local_schema), - list_type: ifss.list_type as i32 + 1, - table_list: convert_list_to_nodes(ifss.table_list), - options: convert_list_to_nodes(ifss.options), + unsafe fn queue_bool_expr(&mut self, be: &bindings_raw::BoolExpr) { + self.queue_list_nodes(be.args); } -} -unsafe fn convert_create_table_space_stmt(ctss: &bindings_raw::CreateTableSpaceStmt) -> protobuf::CreateTableSpaceStmt { - protobuf::CreateTableSpaceStmt { - tablespacename: convert_c_string(ctss.tablespacename), - owner: if ctss.owner.is_null() { None } else { Some(convert_role_spec(&*ctss.owner)) }, - location: convert_c_string(ctss.location), - options: convert_list_to_nodes(ctss.options), + unsafe fn collect_bool_expr(&mut self, be: &bindings_raw::BoolExpr) -> protobuf::node::Node { + let args = self.fetch_list_results(be.args); + protobuf::node::Node::BoolExpr(Box::new(protobuf::BoolExpr { xpr: None, boolop: be.boolop as i32 + 1, args, location: be.location })) } -} -unsafe fn convert_drop_table_space_stmt(dtss: &bindings_raw::DropTableSpaceStmt) -> protobuf::DropTableSpaceStmt { - protobuf::DropTableSpaceStmt { tablespacename: convert_c_string(dtss.tablespacename), missing_ok: dtss.missing_ok } -} + // ==================================================================== + // NullTest + // ==================================================================== -unsafe fn convert_alter_table_space_options_stmt(atsos: &bindings_raw::AlterTableSpaceOptionsStmt) -> protobuf::AlterTableSpaceOptionsStmt { - protobuf::AlterTableSpaceOptionsStmt { - tablespacename: convert_c_string(atsos.tablespacename), - options: convert_list_to_nodes(atsos.options), - is_reset: atsos.isReset, + unsafe fn queue_null_test(&mut self, nt: &bindings_raw::NullTest) { + self.queue_node(nt.arg as *const bindings_raw::Node); } -} -unsafe fn convert_alter_table_move_all_stmt(atmas: &bindings_raw::AlterTableMoveAllStmt) -> protobuf::AlterTableMoveAllStmt { - protobuf::AlterTableMoveAllStmt { - orig_tablespacename: convert_c_string(atmas.orig_tablespacename), - objtype: atmas.objtype as i32 + 1, - roles: convert_list_to_nodes(atmas.roles), - new_tablespacename: convert_c_string(atmas.new_tablespacename), - nowait: atmas.nowait, + unsafe fn collect_null_test(&mut self, nt: &bindings_raw::NullTest) -> protobuf::node::Node { + let arg = self.single_result_box(nt.arg as *const bindings_raw::Node); + protobuf::node::Node::NullTest(Box::new(protobuf::NullTest { + xpr: None, + arg, + nulltesttype: nt.nulltesttype as i32 + 1, + argisrow: nt.argisrow, + location: nt.location, + })) } -} - -unsafe fn convert_alter_extension_stmt(aes: &bindings_raw::AlterExtensionStmt) -> protobuf::AlterExtensionStmt { - protobuf::AlterExtensionStmt { extname: convert_c_string(aes.extname), options: convert_list_to_nodes(aes.options) } -} -unsafe fn convert_alter_extension_contents_stmt(aecs: &bindings_raw::AlterExtensionContentsStmt) -> protobuf::AlterExtensionContentsStmt { - protobuf::AlterExtensionContentsStmt { - extname: convert_c_string(aecs.extname), - action: aecs.action, - objtype: aecs.objtype as i32 + 1, - object: convert_node_boxed(aecs.object), + // ==================================================================== + // SubLink + // ==================================================================== + + unsafe fn queue_sub_link(&mut self, sl: &bindings_raw::SubLink) { + self.queue_node(sl.testexpr); + self.queue_list_nodes(sl.operName); + self.queue_node(sl.subselect); + } + + unsafe fn collect_sub_link(&mut self, sl: &bindings_raw::SubLink) -> protobuf::node::Node { + let testexpr = self.single_result_box(sl.testexpr); + let oper_name = self.fetch_list_results(sl.operName); + let subselect = self.single_result_box(sl.subselect); + protobuf::node::Node::SubLink(Box::new(protobuf::SubLink { + xpr: None, + sub_link_type: sl.subLinkType as i32 + 1, + sub_link_id: sl.subLinkId, + testexpr, + oper_name, + subselect, + location: sl.location, + })) } -} -unsafe fn convert_alter_domain_stmt(ads: &bindings_raw::AlterDomainStmt) -> protobuf::AlterDomainStmt { - protobuf::AlterDomainStmt { - subtype: String::from_utf8_lossy(&[ads.subtype as u8]).to_string(), - type_name: convert_list_to_nodes(ads.typeName), - name: convert_c_string(ads.name), - def: convert_node_boxed(ads.def), - behavior: ads.behavior as i32 + 1, - missing_ok: ads.missing_ok, + // ==================================================================== + // CaseExpr + // ==================================================================== + + unsafe fn queue_case_expr(&mut self, ce: &bindings_raw::CaseExpr) { + self.queue_node(ce.arg as *const bindings_raw::Node); + self.queue_list_nodes(ce.args); + self.queue_node(ce.defresult as *const bindings_raw::Node); + } + + unsafe fn collect_case_expr(&mut self, ce: &bindings_raw::CaseExpr) -> protobuf::node::Node { + let arg = self.single_result_box(ce.arg as *const bindings_raw::Node); + let args = self.fetch_list_results(ce.args); + let defresult = self.single_result_box(ce.defresult as *const bindings_raw::Node); + protobuf::node::Node::CaseExpr(Box::new(protobuf::CaseExpr { + xpr: None, + casetype: ce.casetype, + casecollid: ce.casecollid, + arg, + args, + defresult, + location: ce.location, + })) } -} -unsafe fn convert_alter_function_stmt(afs: &bindings_raw::AlterFunctionStmt) -> protobuf::AlterFunctionStmt { - protobuf::AlterFunctionStmt { - objtype: afs.objtype as i32 + 1, - func: if afs.func.is_null() { None } else { Some(convert_object_with_args(&*afs.func)) }, - actions: convert_list_to_nodes(afs.actions), + // ==================================================================== + // CaseWhen + // ==================================================================== + + unsafe fn queue_case_when(&mut self, cw: &bindings_raw::CaseWhen) { + self.queue_node(cw.expr as *const bindings_raw::Node); + self.queue_node(cw.result as *const bindings_raw::Node); } -} -unsafe fn convert_alter_operator_stmt(aos: &bindings_raw::AlterOperatorStmt) -> protobuf::AlterOperatorStmt { - protobuf::AlterOperatorStmt { - opername: if aos.opername.is_null() { None } else { Some(convert_object_with_args(&*aos.opername)) }, - options: convert_list_to_nodes(aos.options), + unsafe fn collect_case_when(&mut self, cw: &bindings_raw::CaseWhen) -> protobuf::node::Node { + let expr = self.single_result_box(cw.expr as *const bindings_raw::Node); + let result = self.single_result_box(cw.result as *const bindings_raw::Node); + protobuf::node::Node::CaseWhen(Box::new(protobuf::CaseWhen { xpr: None, expr, result, location: cw.location })) } -} -unsafe fn convert_alter_type_stmt(ats: &bindings_raw::AlterTypeStmt) -> protobuf::AlterTypeStmt { - protobuf::AlterTypeStmt { type_name: convert_list_to_nodes(ats.typeName), options: convert_list_to_nodes(ats.options) } -} + // ==================================================================== + // CoalesceExpr + // ==================================================================== -unsafe fn convert_alter_object_schema_stmt(aoss: &bindings_raw::AlterObjectSchemaStmt) -> protobuf::AlterObjectSchemaStmt { - protobuf::AlterObjectSchemaStmt { - object_type: aoss.objectType as i32 + 1, - relation: if aoss.relation.is_null() { None } else { Some(convert_range_var(&*aoss.relation)) }, - object: convert_node_boxed(aoss.object), - newschema: convert_c_string(aoss.newschema), - missing_ok: aoss.missing_ok, + unsafe fn queue_coalesce_expr(&mut self, ce: &bindings_raw::CoalesceExpr) { + self.queue_list_nodes(ce.args); } -} -unsafe fn convert_alter_object_depends_stmt(aods: &bindings_raw::AlterObjectDependsStmt) -> protobuf::AlterObjectDependsStmt { - protobuf::AlterObjectDependsStmt { - object_type: aods.objectType as i32 + 1, - relation: if aods.relation.is_null() { None } else { Some(convert_range_var(&*aods.relation)) }, - object: convert_node_boxed(aods.object), - extname: if aods.extname.is_null() { None } else { Some(convert_string(&*aods.extname)) }, - remove: aods.remove, + unsafe fn collect_coalesce_expr(&mut self, ce: &bindings_raw::CoalesceExpr) -> protobuf::node::Node { + let args = self.fetch_list_results(ce.args); + protobuf::node::Node::CoalesceExpr(Box::new(protobuf::CoalesceExpr { + xpr: None, + coalescetype: ce.coalescetype, + coalescecollid: ce.coalescecollid, + args, + location: ce.location, + })) } -} -unsafe fn convert_alter_collation_stmt(acs: &bindings_raw::AlterCollationStmt) -> protobuf::AlterCollationStmt { - protobuf::AlterCollationStmt { collname: convert_list_to_nodes(acs.collname) } -} + // ==================================================================== + // MinMaxExpr + // ==================================================================== -unsafe fn convert_alter_default_privileges_stmt(adps: &bindings_raw::AlterDefaultPrivilegesStmt) -> protobuf::AlterDefaultPrivilegesStmt { - protobuf::AlterDefaultPrivilegesStmt { - options: convert_list_to_nodes(adps.options), - action: if adps.action.is_null() { None } else { Some(convert_grant_stmt(&*adps.action)) }, + unsafe fn queue_min_max_expr(&mut self, mme: &bindings_raw::MinMaxExpr) { + self.queue_list_nodes(mme.args); } -} -unsafe fn convert_create_cast_stmt(ccs: &bindings_raw::CreateCastStmt) -> protobuf::CreateCastStmt { - protobuf::CreateCastStmt { - sourcetype: if ccs.sourcetype.is_null() { None } else { Some(convert_type_name(&*ccs.sourcetype)) }, - targettype: if ccs.targettype.is_null() { None } else { Some(convert_type_name(&*ccs.targettype)) }, - func: if ccs.func.is_null() { None } else { Some(convert_object_with_args(&*ccs.func)) }, - context: ccs.context as i32 + 1, - inout: ccs.inout, + unsafe fn collect_min_max_expr(&mut self, mme: &bindings_raw::MinMaxExpr) -> protobuf::node::Node { + let args = self.fetch_list_results(mme.args); + protobuf::node::Node::MinMaxExpr(Box::new(protobuf::MinMaxExpr { + xpr: None, + minmaxtype: mme.minmaxtype, + minmaxcollid: mme.minmaxcollid, + inputcollid: mme.inputcollid, + op: mme.op as i32 + 1, + args, + location: mme.location, + })) } -} -unsafe fn convert_create_transform_stmt(cts: &bindings_raw::CreateTransformStmt) -> protobuf::CreateTransformStmt { - protobuf::CreateTransformStmt { - replace: cts.replace, - type_name: if cts.type_name.is_null() { None } else { Some(convert_type_name(&*cts.type_name)) }, - lang: convert_c_string(cts.lang), - fromsql: if cts.fromsql.is_null() { None } else { Some(convert_object_with_args(&*cts.fromsql)) }, - tosql: if cts.tosql.is_null() { None } else { Some(convert_object_with_args(&*cts.tosql)) }, + // ==================================================================== + // BooleanTest + // ==================================================================== + + unsafe fn queue_boolean_test(&mut self, bt: &bindings_raw::BooleanTest) { + self.queue_node(bt.arg as *const bindings_raw::Node); } -} -unsafe fn convert_create_conversion_stmt(ccs: &bindings_raw::CreateConversionStmt) -> protobuf::CreateConversionStmt { - protobuf::CreateConversionStmt { - conversion_name: convert_list_to_nodes(ccs.conversion_name), - for_encoding_name: convert_c_string(ccs.for_encoding_name), - to_encoding_name: convert_c_string(ccs.to_encoding_name), - func_name: convert_list_to_nodes(ccs.func_name), - def: ccs.def, + unsafe fn collect_boolean_test(&mut self, bt: &bindings_raw::BooleanTest) -> protobuf::node::Node { + let arg = self.single_result_box(bt.arg as *const bindings_raw::Node); + protobuf::node::Node::BooleanTest(Box::new(protobuf::BooleanTest { + xpr: None, + arg, + booltesttype: bt.booltesttype as i32 + 1, + location: bt.location, + })) } -} -unsafe fn convert_alter_ts_dictionary_stmt(atds: &bindings_raw::AlterTSDictionaryStmt) -> protobuf::AlterTsDictionaryStmt { - protobuf::AlterTsDictionaryStmt { dictname: convert_list_to_nodes(atds.dictname), options: convert_list_to_nodes(atds.options) } -} + // ==================================================================== + // A_ArrayExpr + // ==================================================================== -unsafe fn convert_alter_ts_configuration_stmt(atcs: &bindings_raw::AlterTSConfigurationStmt) -> protobuf::AlterTsConfigurationStmt { - protobuf::AlterTsConfigurationStmt { - kind: atcs.kind as i32 + 1, - cfgname: convert_list_to_nodes(atcs.cfgname), - tokentype: convert_list_to_nodes(atcs.tokentype), - dicts: convert_list_to_nodes(atcs.dicts), - r#override: atcs.override_, - replace: atcs.replace, - missing_ok: atcs.missing_ok, + unsafe fn queue_a_array_expr(&mut self, ae: &bindings_raw::A_ArrayExpr) { + self.queue_list_nodes(ae.elements); } -} -unsafe fn convert_createdb_stmt(cds: &bindings_raw::CreatedbStmt) -> protobuf::CreatedbStmt { - protobuf::CreatedbStmt { dbname: convert_c_string(cds.dbname), options: convert_list_to_nodes(cds.options) } -} + unsafe fn collect_a_array_expr(&mut self, ae: &bindings_raw::A_ArrayExpr) -> protobuf::node::Node { + let elements = self.fetch_list_results(ae.elements); + protobuf::node::Node::AArrayExpr(protobuf::AArrayExpr { elements, location: ae.location }) + } -unsafe fn convert_dropdb_stmt(dds: &bindings_raw::DropdbStmt) -> protobuf::DropdbStmt { - protobuf::DropdbStmt { dbname: convert_c_string(dds.dbname), missing_ok: dds.missing_ok, options: convert_list_to_nodes(dds.options) } -} + // ==================================================================== + // A_Indirection + // ==================================================================== -unsafe fn convert_alter_database_stmt(ads: &bindings_raw::AlterDatabaseStmt) -> protobuf::AlterDatabaseStmt { - protobuf::AlterDatabaseStmt { dbname: convert_c_string(ads.dbname), options: convert_list_to_nodes(ads.options) } -} + unsafe fn queue_a_indirection(&mut self, ai: &bindings_raw::A_Indirection) { + self.queue_node(ai.arg); + self.queue_list_nodes(ai.indirection); + } -unsafe fn convert_alter_database_set_stmt(adss: &bindings_raw::AlterDatabaseSetStmt) -> protobuf::AlterDatabaseSetStmt { - protobuf::AlterDatabaseSetStmt { dbname: convert_c_string(adss.dbname), setstmt: convert_variable_set_stmt_opt(adss.setstmt) } -} + unsafe fn collect_a_indirection(&mut self, ai: &bindings_raw::A_Indirection) -> protobuf::node::Node { + let arg = self.single_result_box(ai.arg); + let indirection = self.fetch_list_results(ai.indirection); + protobuf::node::Node::AIndirection(Box::new(protobuf::AIndirection { arg, indirection })) + } -unsafe fn convert_alter_database_refresh_coll_stmt(adrcs: &bindings_raw::AlterDatabaseRefreshCollStmt) -> protobuf::AlterDatabaseRefreshCollStmt { - protobuf::AlterDatabaseRefreshCollStmt { dbname: convert_c_string(adrcs.dbname) } -} + // ==================================================================== + // A_Indices + // ==================================================================== -unsafe fn convert_alter_system_stmt(ass: &bindings_raw::AlterSystemStmt) -> protobuf::AlterSystemStmt { - protobuf::AlterSystemStmt { setstmt: convert_variable_set_stmt_opt(ass.setstmt) } -} + unsafe fn queue_a_indices(&mut self, ai: &bindings_raw::A_Indices) { + self.queue_node(ai.lidx); + self.queue_node(ai.uidx); + } -unsafe fn convert_cluster_stmt(cs: &bindings_raw::ClusterStmt) -> protobuf::ClusterStmt { - protobuf::ClusterStmt { - relation: if cs.relation.is_null() { None } else { Some(convert_range_var(&*cs.relation)) }, - indexname: convert_c_string(cs.indexname), - params: convert_list_to_nodes(cs.params), + unsafe fn collect_a_indices(&mut self, ai: &bindings_raw::A_Indices) -> protobuf::node::Node { + let lidx = self.single_result_box(ai.lidx); + let uidx = self.single_result_box(ai.uidx); + protobuf::node::Node::AIndices(Box::new(protobuf::AIndices { is_slice: ai.is_slice, lidx, uidx })) } -} -unsafe fn convert_reindex_stmt(rs: &bindings_raw::ReindexStmt) -> protobuf::ReindexStmt { - protobuf::ReindexStmt { - kind: rs.kind as i32 + 1, - relation: if rs.relation.is_null() { None } else { Some(convert_range_var(&*rs.relation)) }, - name: convert_c_string(rs.name), - params: convert_list_to_nodes(rs.params), + // ==================================================================== + // CollateClause + // ==================================================================== + + unsafe fn queue_collate_clause(&mut self, cc: &bindings_raw::CollateClause) { + self.queue_node(cc.arg); + self.queue_list_nodes(cc.collname); } -} -unsafe fn convert_constraints_set_stmt(css: &bindings_raw::ConstraintsSetStmt) -> protobuf::ConstraintsSetStmt { - protobuf::ConstraintsSetStmt { constraints: convert_list_to_nodes(css.constraints), deferred: css.deferred } -} + unsafe fn collect_collate_clause(&mut self, cc: &bindings_raw::CollateClause) -> protobuf::node::Node { + let arg = self.single_result_box(cc.arg); + let collname = self.fetch_list_results(cc.collname); + protobuf::node::Node::CollateClause(Box::new(protobuf::CollateClause { arg, collname, location: cc.location })) + } -unsafe fn convert_load_stmt(ls: &bindings_raw::LoadStmt) -> protobuf::LoadStmt { - protobuf::LoadStmt { filename: convert_c_string(ls.filename) } -} + // ==================================================================== + // RangeSubselect + // ==================================================================== -unsafe fn convert_drop_owned_stmt(dos: &bindings_raw::DropOwnedStmt) -> protobuf::DropOwnedStmt { - protobuf::DropOwnedStmt { roles: convert_list_to_nodes(dos.roles), behavior: dos.behavior as i32 + 1 } -} + unsafe fn queue_range_subselect(&mut self, rs: &bindings_raw::RangeSubselect) { + self.queue_node(rs.subquery); + if !rs.alias.is_null() { + self.queue_node(rs.alias as *const bindings_raw::Node); + } + } -unsafe fn convert_reassign_owned_stmt(ros: &bindings_raw::ReassignOwnedStmt) -> protobuf::ReassignOwnedStmt { - protobuf::ReassignOwnedStmt { - roles: convert_list_to_nodes(ros.roles), - newrole: if ros.newrole.is_null() { None } else { Some(convert_role_spec(&*ros.newrole)) }, + unsafe fn collect_range_subselect(&mut self, rs: &bindings_raw::RangeSubselect) -> protobuf::node::Node { + let subquery = self.single_result_box(rs.subquery); + let alias = if rs.alias.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::Alias(a)) => Some(a), + _ => None, + }) + }; + protobuf::node::Node::RangeSubselect(Box::new(protobuf::RangeSubselect { lateral: rs.lateral, subquery, alias })) } -} -unsafe fn convert_drop_subscription_stmt(dss: &bindings_raw::DropSubscriptionStmt) -> protobuf::DropSubscriptionStmt { - protobuf::DropSubscriptionStmt { subname: convert_c_string(dss.subname), missing_ok: dss.missing_ok, behavior: dss.behavior as i32 + 1 } -} + // ==================================================================== + // CommonTableExpr + // ==================================================================== -unsafe fn convert_table_func(tf: &bindings_raw::TableFunc) -> protobuf::TableFunc { - protobuf::TableFunc { - functype: tf.functype as i32, - ns_uris: convert_list_to_nodes(tf.ns_uris), - ns_names: convert_list_to_nodes(tf.ns_names), - docexpr: convert_node_boxed(tf.docexpr), - rowexpr: convert_node_boxed(tf.rowexpr), - colnames: convert_list_to_nodes(tf.colnames), - coltypes: convert_list_to_nodes(tf.coltypes), - coltypmods: convert_list_to_nodes(tf.coltypmods), - colcollations: convert_list_to_nodes(tf.colcollations), - colexprs: convert_list_to_nodes(tf.colexprs), - coldefexprs: convert_list_to_nodes(tf.coldefexprs), - colvalexprs: convert_list_to_nodes(tf.colvalexprs), - passingvalexprs: convert_list_to_nodes(tf.passingvalexprs), - notnulls: vec![], // Bitmapset conversion not yet supported - plan: convert_node_boxed(tf.plan), - ordinalitycol: tf.ordinalitycol, - location: tf.location, + unsafe fn queue_common_table_expr(&mut self, cte: &bindings_raw::CommonTableExpr) { + self.queue_list_nodes(cte.aliascolnames); + self.queue_node(cte.ctequery); + if !cte.search_clause.is_null() { + self.queue_node(cte.search_clause as *const bindings_raw::Node); + } + if !cte.cycle_clause.is_null() { + self.queue_node(cte.cycle_clause as *const bindings_raw::Node); + } + self.queue_list_nodes(cte.ctecolnames); + self.queue_list_nodes(cte.ctecoltypes); + self.queue_list_nodes(cte.ctecoltypmods); + self.queue_list_nodes(cte.ctecolcollations); } -} -unsafe fn convert_into_clause_node(ic: &bindings_raw::IntoClause) -> protobuf::IntoClause { - protobuf::IntoClause { - rel: if ic.rel.is_null() { None } else { Some(convert_range_var(&*ic.rel)) }, - col_names: convert_list_to_nodes(ic.colNames), - access_method: convert_c_string(ic.accessMethod), - options: convert_list_to_nodes(ic.options), - on_commit: ic.onCommit as i32 + 1, - table_space_name: convert_c_string(ic.tableSpaceName), - view_query: convert_node_boxed(ic.viewQuery), - skip_data: ic.skipData, + unsafe fn collect_common_table_expr(&mut self, cte: &bindings_raw::CommonTableExpr) -> protobuf::node::Node { + let aliascolnames = self.fetch_list_results(cte.aliascolnames); + let ctequery = self.single_result_box(cte.ctequery); + let search_clause = if cte.search_clause.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::CtesearchClause(sc)) => Some(sc), + _ => None, + }) + }; + let cycle_clause = if cte.cycle_clause.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::CtecycleClause(cc)) => Some(cc), + _ => None, + }) + }; + let ctecolnames = self.fetch_list_results(cte.ctecolnames); + let ctecoltypes = self.fetch_list_results(cte.ctecoltypes); + let ctecoltypmods = self.fetch_list_results(cte.ctecoltypmods); + let ctecolcollations = self.fetch_list_results(cte.ctecolcollations); + protobuf::node::Node::CommonTableExpr(Box::new(protobuf::CommonTableExpr { + ctename: convert_c_string(cte.ctename), + aliascolnames, + ctematerialized: cte.ctematerialized as i32 + 1, + ctequery, + search_clause, + cycle_clause, + location: cte.location, + cterecursive: cte.cterecursive, + cterefcount: cte.cterefcount, + ctecolnames, + ctecoltypes, + ctecoltypmods, + ctecolcollations, + })) } -} -unsafe fn convert_table_like_clause(tlc: &bindings_raw::TableLikeClause) -> protobuf::TableLikeClause { - protobuf::TableLikeClause { - relation: if tlc.relation.is_null() { None } else { Some(convert_range_var(&*tlc.relation)) }, - options: tlc.options, - relation_oid: tlc.relationOid, - } -} + // ==================================================================== + // CTESearchClause + // ==================================================================== -unsafe fn convert_range_table_func(rtf: &bindings_raw::RangeTableFunc) -> protobuf::RangeTableFunc { - protobuf::RangeTableFunc { - lateral: rtf.lateral, - docexpr: convert_node_boxed(rtf.docexpr), - rowexpr: convert_node_boxed(rtf.rowexpr), - namespaces: convert_list_to_nodes(rtf.namespaces), - columns: convert_list_to_nodes(rtf.columns), - alias: if rtf.alias.is_null() { None } else { Some(convert_alias(&*rtf.alias)) }, - location: rtf.location, + unsafe fn queue_cte_search_clause(&mut self, csc: &bindings_raw::CTESearchClause) { + self.queue_list_nodes(csc.search_col_list); } -} -unsafe fn convert_range_table_func_col(rtfc: &bindings_raw::RangeTableFuncCol) -> protobuf::RangeTableFuncCol { - protobuf::RangeTableFuncCol { - colname: convert_c_string(rtfc.colname), - type_name: if rtfc.typeName.is_null() { None } else { Some(convert_type_name(&*rtfc.typeName)) }, - for_ordinality: rtfc.for_ordinality, - is_not_null: rtfc.is_not_null, - colexpr: convert_node_boxed(rtfc.colexpr), - coldefexpr: convert_node_boxed(rtfc.coldefexpr), - location: rtfc.location, + unsafe fn collect_cte_search_clause(&mut self, csc: &bindings_raw::CTESearchClause) -> protobuf::node::Node { + let search_col_list = self.fetch_list_results(csc.search_col_list); + protobuf::node::Node::CtesearchClause(protobuf::CteSearchClause { + search_col_list, + search_breadth_first: csc.search_breadth_first, + search_seq_column: convert_c_string(csc.search_seq_column), + location: csc.location, + }) } -} -unsafe fn convert_range_table_sample(rts: &bindings_raw::RangeTableSample) -> protobuf::RangeTableSample { - protobuf::RangeTableSample { - relation: convert_node_boxed(rts.relation), - method: convert_list_to_nodes(rts.method), - args: convert_list_to_nodes(rts.args), - repeatable: convert_node_boxed(rts.repeatable), - location: rts.location, + // ==================================================================== + // CTECycleClause + // ==================================================================== + + unsafe fn queue_cte_cycle_clause(&mut self, ccc: &bindings_raw::CTECycleClause) { + self.queue_list_nodes(ccc.cycle_col_list); + self.queue_node(ccc.cycle_mark_value); + self.queue_node(ccc.cycle_mark_default); + } + + unsafe fn collect_cte_cycle_clause(&mut self, ccc: &bindings_raw::CTECycleClause) -> protobuf::node::Node { + let cycle_col_list = self.fetch_list_results(ccc.cycle_col_list); + let cycle_mark_value = self.single_result_box(ccc.cycle_mark_value); + let cycle_mark_default = self.single_result_box(ccc.cycle_mark_default); + protobuf::node::Node::CtecycleClause(Box::new(protobuf::CteCycleClause { + cycle_col_list, + cycle_mark_column: convert_c_string(ccc.cycle_mark_column), + cycle_mark_value, + cycle_mark_default, + cycle_path_column: convert_c_string(ccc.cycle_path_column), + location: ccc.location, + cycle_mark_type: ccc.cycle_mark_type, + cycle_mark_typmod: ccc.cycle_mark_typmod, + cycle_mark_collation: ccc.cycle_mark_collation, + cycle_mark_neop: ccc.cycle_mark_neop, + })) } -} -unsafe fn convert_partition_cmd(pc: &bindings_raw::PartitionCmd) -> protobuf::PartitionCmd { - protobuf::PartitionCmd { - name: if pc.name.is_null() { None } else { Some(convert_range_var(&*pc.name)) }, - bound: convert_partition_bound_spec_opt(pc.bound), - concurrent: pc.concurrent, + // ==================================================================== + // GroupingSet + // ==================================================================== + + unsafe fn queue_grouping_set(&mut self, gs: &bindings_raw::GroupingSet) { + self.queue_list_nodes(gs.content); } -} -unsafe fn convert_on_conflict_clause_node(occ: &bindings_raw::OnConflictClause) -> protobuf::OnConflictClause { - protobuf::OnConflictClause { - action: occ.action as i32 + 1, - infer: convert_infer_clause_opt(occ.infer), - target_list: convert_list_to_nodes(occ.targetList), - where_clause: convert_node_boxed(occ.whereClause), - location: occ.location, + unsafe fn collect_grouping_set(&mut self, gs: &bindings_raw::GroupingSet) -> protobuf::node::Node { + let content = self.fetch_list_results(gs.content); + protobuf::node::Node::GroupingSet(protobuf::GroupingSet { kind: gs.kind as i32 + 1, content, location: gs.location }) } -} -unsafe fn convert_trigger_transition(tt: &bindings_raw::TriggerTransition) -> protobuf::TriggerTransition { - protobuf::TriggerTransition { name: convert_c_string(tt.name), is_new: tt.isNew, is_table: tt.isTable } -} + // ==================================================================== + // LockingClause + // ==================================================================== -unsafe fn convert_create_stats_stmt(css: &bindings_raw::CreateStatsStmt) -> protobuf::CreateStatsStmt { - protobuf::CreateStatsStmt { - defnames: convert_list_to_nodes(css.defnames), - stat_types: convert_list_to_nodes(css.stat_types), - exprs: convert_list_to_nodes(css.exprs), - relations: convert_list_to_nodes(css.relations), - stxcomment: convert_c_string(css.stxcomment), - transformed: css.transformed, - if_not_exists: css.if_not_exists, + unsafe fn queue_locking_clause(&mut self, lc: &bindings_raw::LockingClause) { + self.queue_list_nodes(lc.lockedRels); } -} -unsafe fn convert_alter_stats_stmt(ass: &bindings_raw::AlterStatsStmt) -> protobuf::AlterStatsStmt { - protobuf::AlterStatsStmt { - defnames: convert_list_to_nodes(ass.defnames), - stxstattarget: convert_node_boxed(ass.stxstattarget), - missing_ok: ass.missing_ok, + unsafe fn collect_locking_clause(&mut self, lc: &bindings_raw::LockingClause) -> protobuf::node::Node { + let locked_rels = self.fetch_list_results(lc.lockedRels); + protobuf::node::Node::LockingClause(protobuf::LockingClause { + locked_rels, + strength: lc.strength as i32 + 1, + wait_policy: lc.waitPolicy as i32 + 1, + }) } -} - -unsafe fn convert_stats_elem(se: &bindings_raw::StatsElem) -> protobuf::StatsElem { - protobuf::StatsElem { name: convert_c_string(se.name), expr: convert_node_boxed(se.expr) } -} -unsafe fn convert_sql_value_function(svf: &bindings_raw::SQLValueFunction) -> protobuf::SqlValueFunction { - protobuf::SqlValueFunction { xpr: None, op: svf.op as i32 + 1, r#type: svf.type_, typmod: svf.typmod, location: svf.location } -} + // ==================================================================== + // RowExpr + // ==================================================================== -unsafe fn convert_xml_expr(xe: &bindings_raw::XmlExpr) -> protobuf::XmlExpr { - protobuf::XmlExpr { - xpr: None, - op: xe.op as i32 + 1, - name: convert_c_string(xe.name), - named_args: convert_list_to_nodes(xe.named_args), - arg_names: convert_list_to_nodes(xe.arg_names), - args: convert_list_to_nodes(xe.args), - xmloption: xe.xmloption as i32 + 1, - indent: xe.indent, - r#type: xe.type_, - typmod: xe.typmod, - location: xe.location, + unsafe fn queue_row_expr(&mut self, re: &bindings_raw::RowExpr) { + self.queue_list_nodes(re.args); + self.queue_list_nodes(re.colnames); } -} -unsafe fn convert_xml_serialize(xs: &bindings_raw::XmlSerialize) -> protobuf::XmlSerialize { - protobuf::XmlSerialize { - xmloption: xs.xmloption as i32 + 1, - expr: convert_node_boxed(xs.expr), - type_name: if xs.typeName.is_null() { None } else { Some(convert_type_name(&*xs.typeName)) }, - indent: xs.indent, - location: xs.location, + unsafe fn collect_row_expr(&mut self, re: &bindings_raw::RowExpr) -> protobuf::node::Node { + let args = self.fetch_list_results(re.args); + let colnames = self.fetch_list_results(re.colnames); + protobuf::node::Node::RowExpr(Box::new(protobuf::RowExpr { + xpr: None, + args, + row_typeid: re.row_typeid, + row_format: re.row_format as i32 + 1, + colnames, + location: re.location, + })) } -} -unsafe fn convert_named_arg_expr(nae: &bindings_raw::NamedArgExpr) -> protobuf::NamedArgExpr { - protobuf::NamedArgExpr { - xpr: None, - arg: convert_node_boxed(nae.arg as *mut bindings_raw::Node), - name: convert_c_string(nae.name), - argnumber: nae.argnumber, - location: nae.location, + // ==================================================================== + // MultiAssignRef + // ==================================================================== + + unsafe fn queue_multi_assign_ref(&mut self, mar: &bindings_raw::MultiAssignRef) { + self.queue_node(mar.source); } -} -// ============================================================================ -// JSON Node Conversions -// ============================================================================ + unsafe fn collect_multi_assign_ref(&mut self, mar: &bindings_raw::MultiAssignRef) -> protobuf::node::Node { + let source = self.single_result_box(mar.source); + protobuf::node::Node::MultiAssignRef(Box::new(protobuf::MultiAssignRef { source, colno: mar.colno, ncolumns: mar.ncolumns })) + } -unsafe fn convert_json_format(jf: &bindings_raw::JsonFormat) -> protobuf::JsonFormat { - protobuf::JsonFormat { format_type: jf.format_type as i32 + 1, encoding: jf.encoding as i32 + 1, location: jf.location } -} + // ==================================================================== + // Alias (as a standalone node) + // ==================================================================== -unsafe fn convert_json_returning(jr: &bindings_raw::JsonReturning) -> protobuf::JsonReturning { - protobuf::JsonReturning { - format: if jr.format.is_null() { None } else { Some(convert_json_format(&*jr.format)) }, - typid: jr.typid, - typmod: jr.typmod, + unsafe fn queue_alias(&mut self, alias: &bindings_raw::Alias) { + self.queue_list_nodes(alias.colnames); } -} -unsafe fn convert_json_value_expr(jve: &bindings_raw::JsonValueExpr) -> protobuf::JsonValueExpr { - protobuf::JsonValueExpr { - raw_expr: convert_node_boxed(jve.raw_expr as *mut bindings_raw::Node), - formatted_expr: convert_node_boxed(jve.formatted_expr as *mut bindings_raw::Node), - format: if jve.format.is_null() { None } else { Some(convert_json_format(&*jve.format)) }, + unsafe fn collect_alias(&mut self, alias: &bindings_raw::Alias) -> protobuf::node::Node { + let colnames = self.fetch_list_results(alias.colnames); + protobuf::node::Node::Alias(protobuf::Alias { aliasname: convert_c_string(alias.aliasname), colnames }) } -} -unsafe fn convert_json_constructor_expr(jce: &bindings_raw::JsonConstructorExpr) -> protobuf::JsonConstructorExpr { - protobuf::JsonConstructorExpr { - xpr: None, - r#type: jce.type_ as i32 + 1, - args: convert_list_to_nodes(jce.args), - func: convert_node_boxed(jce.func as *mut bindings_raw::Node), - coercion: convert_node_boxed(jce.coercion as *mut bindings_raw::Node), - returning: if jce.returning.is_null() { None } else { Some(convert_json_returning(&*jce.returning)) }, - absent_on_null: jce.absent_on_null, - unique: jce.unique, - location: jce.location, + // ==================================================================== + // GroupingFunc + // ==================================================================== + + unsafe fn queue_grouping_func(&mut self, gf: &bindings_raw::GroupingFunc) { + self.queue_list_nodes(gf.args); + self.queue_list_nodes(gf.refs); } -} -unsafe fn convert_json_is_predicate(jip: &bindings_raw::JsonIsPredicate) -> protobuf::JsonIsPredicate { - protobuf::JsonIsPredicate { - expr: convert_node_boxed(jip.expr), - format: if jip.format.is_null() { None } else { Some(convert_json_format(&*jip.format)) }, - item_type: jip.item_type as i32 + 1, - unique_keys: jip.unique_keys, - location: jip.location, + unsafe fn collect_grouping_func(&mut self, gf: &bindings_raw::GroupingFunc) -> protobuf::node::Node { + let args = self.fetch_list_results(gf.args); + let refs = self.fetch_list_results(gf.refs); + protobuf::node::Node::GroupingFunc(Box::new(protobuf::GroupingFunc { + xpr: None, + args, + refs, + agglevelsup: gf.agglevelsup, + location: gf.location, + })) } -} -unsafe fn convert_json_behavior(jb: &bindings_raw::JsonBehavior) -> protobuf::JsonBehavior { - protobuf::JsonBehavior { btype: jb.btype as i32 + 1, expr: convert_node_boxed(jb.expr), coerce: jb.coerce, location: jb.location } -} + // ==================================================================== + // IndexElem + // ==================================================================== + unsafe fn queue_index_elem(&mut self, ie: &bindings_raw::IndexElem) { + self.queue_node(ie.expr); + self.queue_list_nodes(ie.collation); + self.queue_list_nodes(ie.opclass); + self.queue_list_nodes(ie.opclassopts); + } + unsafe fn collect_index_elem(&mut self, ie: &bindings_raw::IndexElem) -> protobuf::node::Node { + let expr = self.single_result_box(ie.expr); + let collation = self.fetch_list_results(ie.collation); + let opclass = self.fetch_list_results(ie.opclass); + let opclassopts = self.fetch_list_results(ie.opclassopts); + protobuf::node::Node::IndexElem(Box::new(protobuf::IndexElem { + name: convert_c_string(ie.name), + expr, + indexcolname: convert_c_string(ie.indexcolname), + collation, + opclass, + opclassopts, + ordering: ie.ordering as i32 + 1, + nulls_ordering: ie.nulls_ordering as i32 + 1, + })) + } -unsafe fn convert_json_expr(je: &bindings_raw::JsonExpr) -> protobuf::JsonExpr { - protobuf::JsonExpr { - xpr: None, - op: je.op as i32 + 1, - column_name: convert_c_string(je.column_name), - formatted_expr: convert_node_boxed(je.formatted_expr as *mut bindings_raw::Node), - format: if je.format.is_null() { None } else { Some(convert_json_format(&*je.format)) }, - path_spec: convert_node_boxed(je.path_spec), - returning: if je.returning.is_null() { None } else { Some(convert_json_returning(&*je.returning)) }, - passing_names: convert_list_to_nodes(je.passing_names), - passing_values: convert_list_to_nodes(je.passing_values), - on_empty: if je.on_empty.is_null() { None } else { Some(Box::new(convert_json_behavior(&*je.on_empty))) }, - on_error: if je.on_error.is_null() { None } else { Some(Box::new(convert_json_behavior(&*je.on_error))) }, - use_io_coercion: je.use_io_coercion, - use_json_coercion: je.use_json_coercion, - wrapper: je.wrapper as i32 + 1, - omit_quotes: je.omit_quotes, - collation: je.collation, - location: je.location, + // ==================================================================== + // DefElem + // ==================================================================== + unsafe fn queue_def_elem(&mut self, de: &bindings_raw::DefElem) { + self.queue_node(de.arg); + } + unsafe fn collect_def_elem(&mut self, de: &bindings_raw::DefElem) -> protobuf::node::Node { + let arg = self.single_result_box(de.arg); + protobuf::node::Node::DefElem(Box::new(protobuf::DefElem { + defnamespace: convert_c_string(de.defnamespace), + defname: convert_c_string(de.defname), + arg, + defaction: de.defaction as i32 + 1, + location: de.location, + })) } -} -unsafe fn convert_json_table_path(jtp: &bindings_raw::JsonTablePath) -> protobuf::JsonTablePath { - // In raw parse tree, value is not populated - only name - protobuf::JsonTablePath { name: convert_c_string(jtp.name) } -} + // ==================================================================== + // ColumnDef + // ==================================================================== + unsafe fn queue_column_def(&mut self, cd: &bindings_raw::ColumnDef) { + if !cd.typeName.is_null() { + self.queue_node(cd.typeName as *const bindings_raw::Node); + } + self.queue_node(cd.raw_default); + self.queue_node(cd.cooked_default); + if !cd.collClause.is_null() { + self.queue_node(cd.collClause as *const bindings_raw::Node); + } + self.queue_list_nodes(cd.constraints); + self.queue_list_nodes(cd.fdwoptions); + } + unsafe fn collect_column_def(&mut self, cd: &bindings_raw::ColumnDef) -> protobuf::node::Node { + let type_name = if cd.typeName.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::TypeName(tn)) => Some(tn), + _ => None, + }) + }; + let raw_default = self.single_result_box(cd.raw_default); + let cooked_default = self.single_result_box(cd.cooked_default); + let coll_clause = if cd.collClause.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::CollateClause(cc)) => Some(cc), + _ => None, + }) + }; + let constraints = self.fetch_list_results(cd.constraints); + let fdwoptions = self.fetch_list_results(cd.fdwoptions); + protobuf::node::Node::ColumnDef(Box::new(protobuf::ColumnDef { + colname: convert_c_string(cd.colname), + type_name, + compression: convert_c_string(cd.compression), + inhcount: cd.inhcount, + is_local: cd.is_local, + is_not_null: cd.is_not_null, + is_from_type: cd.is_from_type, + storage: if cd.storage == 0 { String::new() } else { String::from_utf8_lossy(&[cd.storage as u8]).to_string() }, + storage_name: convert_c_string(cd.storage_name), + raw_default, + cooked_default, + identity: if cd.identity == 0 { String::new() } else { String::from_utf8_lossy(&[cd.identity as u8]).to_string() }, + identity_sequence: None, // post-analysis + generated: if cd.generated == 0 { String::new() } else { String::from_utf8_lossy(&[cd.generated as u8]).to_string() }, + coll_clause, + coll_oid: cd.collOid, + constraints, + fdwoptions, + location: cd.location, + })) + } -unsafe fn convert_json_table_path_scan(jtps: &bindings_raw::JsonTablePathScan) -> protobuf::JsonTablePathScan { - protobuf::JsonTablePathScan { - plan: convert_node_boxed(&jtps.plan as *const bindings_raw::JsonTablePlan as *mut bindings_raw::Node), - path: if jtps.path.is_null() { None } else { Some(convert_json_table_path(&*jtps.path)) }, - error_on_error: jtps.errorOnError, - child: convert_node_boxed(jtps.child as *mut bindings_raw::Node), - col_min: jtps.colMin, - col_max: jtps.colMax, + // ==================================================================== + // Constraint + // ==================================================================== + unsafe fn queue_constraint(&mut self, c: &bindings_raw::Constraint) { + self.queue_node(c.raw_expr); + self.queue_list_nodes(c.keys); + self.queue_list_nodes(c.including); + self.queue_list_nodes(c.exclusions); + self.queue_list_nodes(c.options); + self.queue_node(c.where_clause); + if !c.pktable.is_null() { + self.queue_node(c.pktable as *const bindings_raw::Node); + } + self.queue_list_nodes(c.fk_attrs); + self.queue_list_nodes(c.pk_attrs); + self.queue_list_nodes(c.fk_del_set_cols); + self.queue_list_nodes(c.old_conpfeqop); + } + unsafe fn collect_constraint(&mut self, c: &bindings_raw::Constraint) -> protobuf::node::Node { + let raw_expr = self.single_result_box(c.raw_expr); + let keys = self.fetch_list_results(c.keys); + let including = self.fetch_list_results(c.including); + let exclusions = self.fetch_list_results(c.exclusions); + let options = self.fetch_list_results(c.options); + let where_clause = self.single_result_box(c.where_clause); + let pktable = if c.pktable.is_null() { None } else { self.pop_range_var() }; + let fk_attrs = self.fetch_list_results(c.fk_attrs); + let pk_attrs = self.fetch_list_results(c.pk_attrs); + let fk_del_set_cols = self.fetch_list_results(c.fk_del_set_cols); + let old_conpfeqop = self.fetch_list_results(c.old_conpfeqop); + protobuf::node::Node::Constraint(Box::new(protobuf::Constraint { + contype: c.contype as i32 + 1, + conname: convert_c_string(c.conname), + deferrable: c.deferrable, + initdeferred: c.initdeferred, + location: c.location, + is_no_inherit: c.is_no_inherit, + raw_expr, + cooked_expr: convert_c_string(c.cooked_expr), + generated_when: if c.generated_when == 0 { String::new() } else { String::from_utf8_lossy(&[c.generated_when as u8]).to_string() }, + inhcount: c.inhcount, + nulls_not_distinct: c.nulls_not_distinct, + keys, + including, + exclusions, + options, + indexname: convert_c_string(c.indexname), + indexspace: convert_c_string(c.indexspace), + reset_default_tblspc: c.reset_default_tblspc, + access_method: convert_c_string(c.access_method), + where_clause, + pktable, + fk_attrs, + pk_attrs, + fk_matchtype: if c.fk_matchtype == 0 { String::new() } else { String::from_utf8_lossy(&[c.fk_matchtype as u8]).to_string() }, + fk_upd_action: if c.fk_upd_action == 0 { String::new() } else { String::from_utf8_lossy(&[c.fk_upd_action as u8]).to_string() }, + fk_del_action: if c.fk_del_action == 0 { String::new() } else { String::from_utf8_lossy(&[c.fk_del_action as u8]).to_string() }, + fk_del_set_cols, + old_conpfeqop, + old_pktable_oid: c.old_pktable_oid, + skip_validation: c.skip_validation, + initially_valid: c.initially_valid, + })) } -} -unsafe fn convert_json_table_sibling_join(jtsj: &bindings_raw::JsonTableSiblingJoin) -> protobuf::JsonTableSiblingJoin { - protobuf::JsonTableSiblingJoin { - plan: convert_node_boxed(&jtsj.plan as *const bindings_raw::JsonTablePlan as *mut bindings_raw::Node), - lplan: convert_node_boxed(jtsj.lplan as *mut bindings_raw::Node), - rplan: convert_node_boxed(jtsj.rplan as *mut bindings_raw::Node), + // ==================================================================== + // CreateStmt + // ==================================================================== + unsafe fn queue_create_stmt(&mut self, cs: &bindings_raw::CreateStmt) { + if !cs.relation.is_null() { + self.queue_node(cs.relation as *const bindings_raw::Node); + } + self.queue_list_nodes(cs.tableElts); + self.queue_list_nodes(cs.inhRelations); + if !cs.partbound.is_null() { + self.queue_node(cs.partbound as *const bindings_raw::Node); + } + if !cs.partspec.is_null() { + self.queue_node(cs.partspec as *const bindings_raw::Node); + } + if !cs.ofTypename.is_null() { + self.queue_node(cs.ofTypename as *const bindings_raw::Node); + } + self.queue_list_nodes(cs.constraints); + self.queue_list_nodes(cs.options); + } + unsafe fn collect_create_stmt(&mut self, cs: &bindings_raw::CreateStmt) -> protobuf::node::Node { + let relation = if cs.relation.is_null() { None } else { self.pop_range_var() }; + let table_elts = self.fetch_list_results(cs.tableElts); + let inh_relations = self.fetch_list_results(cs.inhRelations); + let partbound = if cs.partbound.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::PartitionBoundSpec(pbs)) => Some(pbs), + _ => None, + }) + }; + let partspec = if cs.partspec.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::PartitionSpec(ps)) => Some(ps), + _ => None, + }) + }; + let of_typename = if cs.ofTypename.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::TypeName(tn)) => Some(tn), + _ => None, + }) + }; + let constraints = self.fetch_list_results(cs.constraints); + let options = self.fetch_list_results(cs.options); + protobuf::node::Node::CreateStmt(protobuf::CreateStmt { + relation, + table_elts, + inh_relations, + partbound, + partspec, + of_typename, + constraints, + options, + oncommit: cs.oncommit as i32 + 1, + tablespacename: convert_c_string(cs.tablespacename), + access_method: convert_c_string(cs.accessMethod), + if_not_exists: cs.if_not_exists, + }) } -} -unsafe fn convert_json_output(jo: &bindings_raw::JsonOutput) -> protobuf::JsonOutput { - protobuf::JsonOutput { - type_name: if jo.typeName.is_null() { None } else { Some(convert_type_name(&*jo.typeName)) }, - returning: if jo.returning.is_null() { None } else { Some(convert_json_returning(&*jo.returning)) }, + // ==================================================================== + // DropStmt + // ==================================================================== + unsafe fn queue_drop_stmt(&mut self, ds: &bindings_raw::DropStmt) { + self.queue_list_nodes(ds.objects); + } + unsafe fn collect_drop_stmt(&mut self, ds: &bindings_raw::DropStmt) -> protobuf::node::Node { + let objects = self.fetch_list_results(ds.objects); + protobuf::node::Node::DropStmt(protobuf::DropStmt { + objects, + remove_type: ds.removeType as i32 + 1, + behavior: ds.behavior as i32 + 1, + missing_ok: ds.missing_ok, + concurrent: ds.concurrent, + }) } -} -unsafe fn convert_json_argument(ja: &bindings_raw::JsonArgument) -> protobuf::JsonArgument { - protobuf::JsonArgument { - val: if ja.val.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*ja.val))) }, - name: convert_c_string(ja.name), + // ==================================================================== + // IndexStmt + // ==================================================================== + unsafe fn queue_index_stmt(&mut self, is_: &bindings_raw::IndexStmt) { + if !is_.relation.is_null() { + self.queue_node(is_.relation as *const bindings_raw::Node); + } + self.queue_list_nodes(is_.indexParams); + self.queue_list_nodes(is_.indexIncludingParams); + self.queue_list_nodes(is_.options); + self.queue_node(is_.whereClause); + self.queue_list_nodes(is_.excludeOpNames); + } + unsafe fn collect_index_stmt(&mut self, is_: &bindings_raw::IndexStmt) -> protobuf::node::Node { + let relation = if is_.relation.is_null() { None } else { self.pop_range_var() }; + let index_params = self.fetch_list_results(is_.indexParams); + let index_including_params = self.fetch_list_results(is_.indexIncludingParams); + let options = self.fetch_list_results(is_.options); + let where_clause = self.single_result_box(is_.whereClause); + let exclude_op_names = self.fetch_list_results(is_.excludeOpNames); + protobuf::node::Node::IndexStmt(Box::new(protobuf::IndexStmt { + idxname: convert_c_string(is_.idxname), + relation, + access_method: convert_c_string(is_.accessMethod), + table_space: convert_c_string(is_.tableSpace), + index_params, + index_including_params, + options, + where_clause, + exclude_op_names, + idxcomment: convert_c_string(is_.idxcomment), + index_oid: is_.indexOid, + old_number: is_.oldNumber, + old_create_subid: is_.oldCreateSubid, + old_first_relfilelocator_subid: is_.oldFirstRelfilelocatorSubid, + unique: is_.unique, + nulls_not_distinct: is_.nulls_not_distinct, + primary: is_.primary, + isconstraint: is_.isconstraint, + deferrable: is_.deferrable, + initdeferred: is_.initdeferred, + transformed: is_.transformed, + concurrent: is_.concurrent, + if_not_exists: is_.if_not_exists, + reset_default_tblspc: is_.reset_default_tblspc, + })) } -} -unsafe fn convert_json_func_expr(jfe: &bindings_raw::JsonFuncExpr) -> protobuf::JsonFuncExpr { - protobuf::JsonFuncExpr { - op: jfe.op as i32 + 1, - column_name: convert_c_string(jfe.column_name), - context_item: if jfe.context_item.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jfe.context_item))) }, - pathspec: convert_node_boxed(jfe.pathspec), - passing: convert_list_to_nodes(jfe.passing), - output: if jfe.output.is_null() { None } else { Some(convert_json_output(&*jfe.output)) }, - on_empty: if jfe.on_empty.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jfe.on_empty))) }, - on_error: if jfe.on_error.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jfe.on_error))) }, - wrapper: jfe.wrapper as i32 + 1, - quotes: jfe.quotes as i32 + 1, - location: jfe.location, + // ==================================================================== + // AlterTableStmt + // ==================================================================== + unsafe fn queue_alter_table_stmt(&mut self, ats: &bindings_raw::AlterTableStmt) { + if !ats.relation.is_null() { + self.queue_node(ats.relation as *const bindings_raw::Node); + } + self.queue_list_nodes(ats.cmds); + } + unsafe fn collect_alter_table_stmt(&mut self, ats: &bindings_raw::AlterTableStmt) -> protobuf::node::Node { + let relation = if ats.relation.is_null() { None } else { self.pop_range_var() }; + let cmds = self.fetch_list_results(ats.cmds); + protobuf::node::Node::AlterTableStmt(protobuf::AlterTableStmt { relation, cmds, objtype: ats.objtype as i32 + 1, missing_ok: ats.missing_ok }) } -} -unsafe fn convert_json_table_path_spec(jtps: &bindings_raw::JsonTablePathSpec) -> protobuf::JsonTablePathSpec { - protobuf::JsonTablePathSpec { - string: convert_node_boxed(jtps.string), - name: convert_c_string(jtps.name), - name_location: jtps.name_location, - location: jtps.location, + // ==================================================================== + // AlterTableCmd + // ==================================================================== + unsafe fn queue_alter_table_cmd(&mut self, atc: &bindings_raw::AlterTableCmd) { + self.queue_node(atc.def); + } + unsafe fn collect_alter_table_cmd(&mut self, atc: &bindings_raw::AlterTableCmd) -> protobuf::node::Node { + let def = self.single_result_box(atc.def); + let newowner = if atc.newowner.is_null() { + None + } else { + Some(protobuf::RoleSpec { + roletype: (*atc.newowner).roletype as i32 + 1, + rolename: convert_c_string((*atc.newowner).rolename), + location: (*atc.newowner).location, + }) + }; + protobuf::node::Node::AlterTableCmd(Box::new(protobuf::AlterTableCmd { + subtype: atc.subtype as i32 + 1, + name: convert_c_string(atc.name), + num: atc.num as i32, + newowner, + def, + behavior: atc.behavior as i32 + 1, + missing_ok: atc.missing_ok, + recurse: atc.recurse, + })) } -} -unsafe fn convert_json_table(jt: &bindings_raw::JsonTable) -> protobuf::JsonTable { - protobuf::JsonTable { - context_item: if jt.context_item.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jt.context_item))) }, - pathspec: if jt.pathspec.is_null() { None } else { Some(Box::new(convert_json_table_path_spec(&*jt.pathspec))) }, - passing: convert_list_to_nodes(jt.passing), - columns: convert_list_to_nodes(jt.columns), - on_error: if jt.on_error.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jt.on_error))) }, - alias: if jt.alias.is_null() { None } else { Some(convert_alias(&*jt.alias)) }, - lateral: jt.lateral, - location: jt.location, + // ==================================================================== + // RenameStmt + // ==================================================================== + unsafe fn queue_rename_stmt(&mut self, rs: &bindings_raw::RenameStmt) { + if !rs.relation.is_null() { + self.queue_node(rs.relation as *const bindings_raw::Node); + } + self.queue_node(rs.object); + } + unsafe fn collect_rename_stmt(&mut self, rs: &bindings_raw::RenameStmt) -> protobuf::node::Node { + let relation = if rs.relation.is_null() { None } else { self.pop_range_var() }; + let object = self.single_result_box(rs.object); + protobuf::node::Node::RenameStmt(Box::new(protobuf::RenameStmt { + rename_type: rs.renameType as i32 + 1, + relation_type: rs.relationType as i32 + 1, + relation, + object, + subname: convert_c_string(rs.subname), + newname: convert_c_string(rs.newname), + behavior: rs.behavior as i32 + 1, + missing_ok: rs.missing_ok, + })) } -} -unsafe fn convert_json_table_column(jtc: &bindings_raw::JsonTableColumn) -> protobuf::JsonTableColumn { - protobuf::JsonTableColumn { - coltype: jtc.coltype as i32 + 1, - name: convert_c_string(jtc.name), - type_name: if jtc.typeName.is_null() { None } else { Some(convert_type_name(&*jtc.typeName)) }, - pathspec: if jtc.pathspec.is_null() { None } else { Some(Box::new(convert_json_table_path_spec(&*jtc.pathspec))) }, - format: if jtc.format.is_null() { None } else { Some(convert_json_format(&*jtc.format)) }, - wrapper: jtc.wrapper as i32 + 1, - quotes: jtc.quotes as i32 + 1, - columns: convert_list_to_nodes(jtc.columns), - on_empty: if jtc.on_empty.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jtc.on_empty))) }, - on_error: if jtc.on_error.is_null() { None } else { Some(Box::new(convert_json_behavior(&*jtc.on_error))) }, - location: jtc.location, + // ==================================================================== + // ViewStmt + // ==================================================================== + unsafe fn queue_view_stmt(&mut self, vs: &bindings_raw::ViewStmt) { + if !vs.view.is_null() { + self.queue_node(vs.view as *const bindings_raw::Node); + } + self.queue_list_nodes(vs.aliases); + self.queue_node(vs.query); + self.queue_list_nodes(vs.options); + } + unsafe fn collect_view_stmt(&mut self, vs: &bindings_raw::ViewStmt) -> protobuf::node::Node { + let view = if vs.view.is_null() { None } else { self.pop_range_var() }; + let aliases = self.fetch_list_results(vs.aliases); + let query = self.single_result_box(vs.query); + let options = self.fetch_list_results(vs.options); + protobuf::node::Node::ViewStmt(Box::new(protobuf::ViewStmt { + view, + aliases, + query, + replace: vs.replace, + options, + with_check_option: vs.withCheckOption as i32 + 1, + })) } -} -unsafe fn convert_json_key_value(jkv: &bindings_raw::JsonKeyValue) -> protobuf::JsonKeyValue { - protobuf::JsonKeyValue { - key: convert_node_boxed(jkv.key as *mut bindings_raw::Node), - value: if jkv.value.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jkv.value))) }, + // ==================================================================== + // CreateTableAsStmt + // ==================================================================== + unsafe fn queue_create_table_as_stmt(&mut self, ctas: &bindings_raw::CreateTableAsStmt) { + self.queue_node(ctas.query); + self.queue_into_clause(ctas.into); + } + unsafe fn collect_create_table_as_stmt(&mut self, ctas: &bindings_raw::CreateTableAsStmt) -> protobuf::node::Node { + let query = self.single_result_box(ctas.query); + let into = self.fetch_into_clause(ctas.into); + protobuf::node::Node::CreateTableAsStmt(Box::new(protobuf::CreateTableAsStmt { + query, + into, + objtype: ctas.objtype as i32 + 1, + is_select_into: ctas.is_select_into, + if_not_exists: ctas.if_not_exists, + })) } -} -unsafe fn convert_json_parse_expr(jpe: &bindings_raw::JsonParseExpr) -> protobuf::JsonParseExpr { - protobuf::JsonParseExpr { - expr: if jpe.expr.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jpe.expr))) }, - output: if jpe.output.is_null() { None } else { Some(convert_json_output(&*jpe.output)) }, - unique_keys: jpe.unique_keys, - location: jpe.location, + // ==================================================================== + // TruncateStmt + // ==================================================================== + unsafe fn queue_truncate_stmt(&mut self, ts: &bindings_raw::TruncateStmt) { + self.queue_list_nodes(ts.relations); + } + unsafe fn collect_truncate_stmt(&mut self, ts: &bindings_raw::TruncateStmt) -> protobuf::node::Node { + let relations = self.fetch_list_results(ts.relations); + protobuf::node::Node::TruncateStmt(protobuf::TruncateStmt { relations, restart_seqs: ts.restart_seqs, behavior: ts.behavior as i32 + 1 }) } -} -unsafe fn convert_json_scalar_expr(jse: &bindings_raw::JsonScalarExpr) -> protobuf::JsonScalarExpr { - protobuf::JsonScalarExpr { - expr: convert_node_boxed(jse.expr as *mut bindings_raw::Node), - output: if jse.output.is_null() { None } else { Some(convert_json_output(&*jse.output)) }, - location: jse.location, + // ==================================================================== + // AlterOwnerStmt + // ==================================================================== + unsafe fn queue_alter_owner_stmt(&mut self, aos: &bindings_raw::AlterOwnerStmt) { + if !aos.relation.is_null() { + self.queue_node(aos.relation as *const bindings_raw::Node); + } + self.queue_node(aos.object); + } + unsafe fn collect_alter_owner_stmt(&mut self, aos: &bindings_raw::AlterOwnerStmt) -> protobuf::node::Node { + let relation = if aos.relation.is_null() { None } else { self.pop_range_var() }; + let object = self.single_result_box(aos.object); + let newowner = if aos.newowner.is_null() { + None + } else { + Some(protobuf::RoleSpec { + roletype: (*aos.newowner).roletype as i32 + 1, + rolename: convert_c_string((*aos.newowner).rolename), + location: (*aos.newowner).location, + }) + }; + protobuf::node::Node::AlterOwnerStmt(Box::new(protobuf::AlterOwnerStmt { + object_type: aos.objectType as i32 + 1, + relation, + object, + newowner, + })) } -} -unsafe fn convert_json_serialize_expr(jse: &bindings_raw::JsonSerializeExpr) -> protobuf::JsonSerializeExpr { - protobuf::JsonSerializeExpr { - expr: if jse.expr.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jse.expr))) }, - output: if jse.output.is_null() { None } else { Some(convert_json_output(&*jse.output)) }, - location: jse.location, + // ==================================================================== + // CreateSeqStmt + // ==================================================================== + unsafe fn queue_create_seq_stmt(&mut self, css: &bindings_raw::CreateSeqStmt) { + if !css.sequence.is_null() { + self.queue_node(css.sequence as *const bindings_raw::Node); + } + self.queue_list_nodes(css.options); + } + unsafe fn collect_create_seq_stmt(&mut self, css: &bindings_raw::CreateSeqStmt) -> protobuf::node::Node { + let sequence = if css.sequence.is_null() { None } else { self.pop_range_var() }; + let options = self.fetch_list_results(css.options); + protobuf::node::Node::CreateSeqStmt(protobuf::CreateSeqStmt { + sequence, + options, + owner_id: css.ownerId, + for_identity: css.for_identity, + if_not_exists: css.if_not_exists, + }) } -} -unsafe fn convert_json_object_constructor(joc: &bindings_raw::JsonObjectConstructor) -> protobuf::JsonObjectConstructor { - protobuf::JsonObjectConstructor { - exprs: convert_list_to_nodes(joc.exprs), - output: if joc.output.is_null() { None } else { Some(convert_json_output(&*joc.output)) }, - absent_on_null: joc.absent_on_null, - unique: joc.unique, - location: joc.location, + // ==================================================================== + // AlterSeqStmt + // ==================================================================== + unsafe fn queue_alter_seq_stmt(&mut self, ass_: &bindings_raw::AlterSeqStmt) { + if !ass_.sequence.is_null() { + self.queue_node(ass_.sequence as *const bindings_raw::Node); + } + self.queue_list_nodes(ass_.options); + } + unsafe fn collect_alter_seq_stmt(&mut self, ass_: &bindings_raw::AlterSeqStmt) -> protobuf::node::Node { + let sequence = if ass_.sequence.is_null() { None } else { self.pop_range_var() }; + let options = self.fetch_list_results(ass_.options); + protobuf::node::Node::AlterSeqStmt(protobuf::AlterSeqStmt { sequence, options, for_identity: ass_.for_identity, missing_ok: ass_.missing_ok }) } -} -unsafe fn convert_json_array_constructor(jac: &bindings_raw::JsonArrayConstructor) -> protobuf::JsonArrayConstructor { - protobuf::JsonArrayConstructor { - exprs: convert_list_to_nodes(jac.exprs), - output: if jac.output.is_null() { None } else { Some(convert_json_output(&*jac.output)) }, - absent_on_null: jac.absent_on_null, - location: jac.location, + // ==================================================================== + // CreateDomainStmt + // ==================================================================== + unsafe fn queue_create_domain_stmt(&mut self, cds: &bindings_raw::CreateDomainStmt) { + self.queue_list_nodes(cds.domainname); + if !cds.typeName.is_null() { + self.queue_node(cds.typeName as *const bindings_raw::Node); + } + if !cds.collClause.is_null() { + self.queue_node(cds.collClause as *const bindings_raw::Node); + } + self.queue_list_nodes(cds.constraints); + } + unsafe fn collect_create_domain_stmt(&mut self, cds: &bindings_raw::CreateDomainStmt) -> protobuf::node::Node { + let domainname = self.fetch_list_results(cds.domainname); + let type_name = if cds.typeName.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::TypeName(tn)) => Some(tn), + _ => None, + }) + }; + let coll_clause = if cds.collClause.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::CollateClause(cc)) => Some(cc), + _ => None, + }) + }; + let constraints = self.fetch_list_results(cds.constraints); + protobuf::node::Node::CreateDomainStmt(Box::new(protobuf::CreateDomainStmt { domainname, type_name, coll_clause, constraints })) } -} -unsafe fn convert_json_array_query_constructor(jaqc: &bindings_raw::JsonArrayQueryConstructor) -> protobuf::JsonArrayQueryConstructor { - protobuf::JsonArrayQueryConstructor { - query: convert_node_boxed(jaqc.query), - output: if jaqc.output.is_null() { None } else { Some(convert_json_output(&*jaqc.output)) }, - format: if jaqc.format.is_null() { None } else { Some(convert_json_format(&*jaqc.format)) }, - absent_on_null: jaqc.absent_on_null, - location: jaqc.location, + // ==================================================================== + // CompositeTypeStmt + // ==================================================================== + unsafe fn queue_composite_type_stmt(&mut self, cts: &bindings_raw::CompositeTypeStmt) { + if !cts.typevar.is_null() { + self.queue_node(cts.typevar as *const bindings_raw::Node); + } + self.queue_list_nodes(cts.coldeflist); + } + unsafe fn collect_composite_type_stmt(&mut self, cts: &bindings_raw::CompositeTypeStmt) -> protobuf::node::Node { + let typevar = if cts.typevar.is_null() { None } else { self.pop_range_var() }; + let coldeflist = self.fetch_list_results(cts.coldeflist); + protobuf::node::Node::CompositeTypeStmt(protobuf::CompositeTypeStmt { typevar, coldeflist }) + } + + // ==================================================================== + // CreateEnumStmt + // ==================================================================== + unsafe fn queue_create_enum_stmt(&mut self, ces: &bindings_raw::CreateEnumStmt) { + self.queue_list_nodes(ces.typeName); + self.queue_list_nodes(ces.vals); + } + unsafe fn collect_create_enum_stmt(&mut self, ces: &bindings_raw::CreateEnumStmt) -> protobuf::node::Node { + let type_name = self.fetch_list_results(ces.typeName); + let vals = self.fetch_list_results(ces.vals); + protobuf::node::Node::CreateEnumStmt(protobuf::CreateEnumStmt { type_name, vals }) + } + + // ==================================================================== + // CreateExtensionStmt + // ==================================================================== + unsafe fn queue_create_extension_stmt(&mut self, ces: &bindings_raw::CreateExtensionStmt) { + self.queue_list_nodes(ces.options); + } + unsafe fn collect_create_extension_stmt(&mut self, ces: &bindings_raw::CreateExtensionStmt) -> protobuf::node::Node { + let options = self.fetch_list_results(ces.options); + protobuf::node::Node::CreateExtensionStmt(protobuf::CreateExtensionStmt { + extname: convert_c_string(ces.extname), + if_not_exists: ces.if_not_exists, + options, + }) } -} -unsafe fn convert_json_agg_constructor(jac: &bindings_raw::JsonAggConstructor) -> protobuf::JsonAggConstructor { - protobuf::JsonAggConstructor { - output: if jac.output.is_null() { None } else { Some(convert_json_output(&*jac.output)) }, - agg_filter: convert_node_boxed(jac.agg_filter), - agg_order: convert_list_to_nodes(jac.agg_order), - over: if jac.over.is_null() { None } else { Some(Box::new(convert_window_def(&*jac.over))) }, - location: jac.location, + // ==================================================================== + // Publication / Subscription / Trigger stmts + // ==================================================================== + unsafe fn queue_create_publication_stmt(&mut self, cps: &bindings_raw::CreatePublicationStmt) { + self.queue_list_nodes(cps.options); + self.queue_list_nodes(cps.pubobjects); + } + unsafe fn collect_create_publication_stmt(&mut self, cps: &bindings_raw::CreatePublicationStmt) -> protobuf::node::Node { + let options = self.fetch_list_results(cps.options); + let pubobjects = self.fetch_list_results(cps.pubobjects); + protobuf::node::Node::CreatePublicationStmt(protobuf::CreatePublicationStmt { + pubname: convert_c_string(cps.pubname), + options, + pubobjects, + for_all_tables: cps.for_all_tables, + }) + } + unsafe fn queue_alter_publication_stmt(&mut self, aps: &bindings_raw::AlterPublicationStmt) { + self.queue_list_nodes(aps.options); + self.queue_list_nodes(aps.pubobjects); + } + unsafe fn collect_alter_publication_stmt(&mut self, aps: &bindings_raw::AlterPublicationStmt) -> protobuf::node::Node { + let options = self.fetch_list_results(aps.options); + let pubobjects = self.fetch_list_results(aps.pubobjects); + protobuf::node::Node::AlterPublicationStmt(protobuf::AlterPublicationStmt { + pubname: convert_c_string(aps.pubname), + options, + pubobjects, + for_all_tables: aps.for_all_tables, + action: aps.action as i32 + 1, + }) + } + unsafe fn queue_create_subscription_stmt(&mut self, css: &bindings_raw::CreateSubscriptionStmt) { + self.queue_list_nodes(css.publication); + self.queue_list_nodes(css.options); + } + unsafe fn collect_create_subscription_stmt(&mut self, css: &bindings_raw::CreateSubscriptionStmt) -> protobuf::node::Node { + let publication = self.fetch_list_results(css.publication); + let options = self.fetch_list_results(css.options); + protobuf::node::Node::CreateSubscriptionStmt(protobuf::CreateSubscriptionStmt { + subname: convert_c_string(css.subname), + conninfo: convert_c_string(css.conninfo), + publication, + options, + }) + } + unsafe fn queue_alter_subscription_stmt(&mut self, ass_: &bindings_raw::AlterSubscriptionStmt) { + self.queue_list_nodes(ass_.publication); + self.queue_list_nodes(ass_.options); + } + unsafe fn collect_alter_subscription_stmt(&mut self, ass_: &bindings_raw::AlterSubscriptionStmt) -> protobuf::node::Node { + let publication = self.fetch_list_results(ass_.publication); + let options = self.fetch_list_results(ass_.options); + protobuf::node::Node::AlterSubscriptionStmt(protobuf::AlterSubscriptionStmt { + kind: ass_.kind as i32 + 1, + subname: convert_c_string(ass_.subname), + conninfo: convert_c_string(ass_.conninfo), + publication, + options, + }) + } + unsafe fn queue_create_trig_stmt(&mut self, cts: &bindings_raw::CreateTrigStmt) { + if !cts.relation.is_null() { + self.queue_node(cts.relation as *const bindings_raw::Node); + } + self.queue_list_nodes(cts.funcname); + self.queue_list_nodes(cts.args); + self.queue_list_nodes(cts.columns); + self.queue_node(cts.whenClause); + self.queue_list_nodes(cts.transitionRels); + if !cts.constrrel.is_null() { + self.queue_node(cts.constrrel as *const bindings_raw::Node); + } + } + unsafe fn collect_create_trig_stmt(&mut self, cts: &bindings_raw::CreateTrigStmt) -> protobuf::node::Node { + let relation = if cts.relation.is_null() { None } else { self.pop_range_var() }; + let funcname = self.fetch_list_results(cts.funcname); + let args = self.fetch_list_results(cts.args); + let columns = self.fetch_list_results(cts.columns); + let when_clause = self.single_result_box(cts.whenClause); + let transition_rels = self.fetch_list_results(cts.transitionRels); + let constrrel = if cts.constrrel.is_null() { None } else { self.pop_range_var() }; + protobuf::node::Node::CreateTrigStmt(Box::new(protobuf::CreateTrigStmt { + replace: cts.replace, + isconstraint: cts.isconstraint, + trigname: convert_c_string(cts.trigname), + relation, + funcname, + args, + row: cts.row, + timing: cts.timing as i32, + events: cts.events as i32, + columns, + when_clause, + transition_rels, + deferrable: cts.deferrable, + initdeferred: cts.initdeferred, + constrrel, + })) + } + unsafe fn queue_publication_obj_spec(&mut self, pos: &bindings_raw::PublicationObjSpec) { + if !pos.pubtable.is_null() { + let pt = &*pos.pubtable; + if !pt.relation.is_null() { + self.queue_node(pt.relation as *const bindings_raw::Node); + } + self.queue_node(pt.whereClause as *const bindings_raw::Node); + self.queue_list_nodes(pt.columns); + } + } + unsafe fn collect_publication_obj_spec(&mut self, pos: &bindings_raw::PublicationObjSpec) -> protobuf::node::Node { + let pubtable = if pos.pubtable.is_null() { + None + } else { + let pt = &*pos.pubtable; + let relation = if pt.relation.is_null() { None } else { self.pop_range_var() }; + let where_clause = self.single_result_box(pt.whereClause as *const bindings_raw::Node); + let columns = self.fetch_list_results(pt.columns); + Some(Box::new(protobuf::PublicationTable { relation, where_clause, columns })) + }; + protobuf::node::Node::PublicationObjSpec(Box::new(protobuf::PublicationObjSpec { + pubobjtype: pos.pubobjtype as i32 + 1, + name: convert_c_string(pos.name), + pubtable, + location: pos.location, + })) } -} -unsafe fn convert_json_object_agg(joa: &bindings_raw::JsonObjectAgg) -> protobuf::JsonObjectAgg { - protobuf::JsonObjectAgg { - constructor: if joa.constructor.is_null() { None } else { Some(Box::new(convert_json_agg_constructor(&*joa.constructor))) }, - arg: if joa.arg.is_null() { None } else { Some(Box::new(convert_json_key_value(&*joa.arg))) }, - absent_on_null: joa.absent_on_null, - unique: joa.unique, + // ==================================================================== + // Partition nodes + // ==================================================================== + unsafe fn queue_partition_elem(&mut self, pe: &bindings_raw::PartitionElem) { + self.queue_node(pe.expr); + self.queue_list_nodes(pe.collation); + self.queue_list_nodes(pe.opclass); + } + unsafe fn collect_partition_elem(&mut self, pe: &bindings_raw::PartitionElem) -> protobuf::node::Node { + let expr = self.single_result_box(pe.expr); + let collation = self.fetch_list_results(pe.collation); + let opclass = self.fetch_list_results(pe.opclass); + protobuf::node::Node::PartitionElem(Box::new(protobuf::PartitionElem { + name: convert_c_string(pe.name), + expr, + collation, + opclass, + location: pe.location, + })) + } + unsafe fn queue_partition_spec(&mut self, ps: &bindings_raw::PartitionSpec) { + self.queue_list_nodes(ps.partParams); + } + unsafe fn collect_partition_spec(&mut self, ps: &bindings_raw::PartitionSpec) -> protobuf::node::Node { + let part_params = self.fetch_list_results(ps.partParams); + let strategy = match ps.strategy as u8 as char { + 'l' => 1, + 'r' => 2, + 'h' => 3, + _ => 0, + }; + protobuf::node::Node::PartitionSpec(protobuf::PartitionSpec { strategy, part_params, location: ps.location }) + } + unsafe fn queue_partition_bound_spec(&mut self, pbs: &bindings_raw::PartitionBoundSpec) { + self.queue_list_nodes(pbs.listdatums); + self.queue_list_nodes(pbs.lowerdatums); + self.queue_list_nodes(pbs.upperdatums); + } + unsafe fn collect_partition_bound_spec(&mut self, pbs: &bindings_raw::PartitionBoundSpec) -> protobuf::node::Node { + let listdatums = self.fetch_list_results(pbs.listdatums); + let lowerdatums = self.fetch_list_results(pbs.lowerdatums); + let upperdatums = self.fetch_list_results(pbs.upperdatums); + protobuf::node::Node::PartitionBoundSpec(protobuf::PartitionBoundSpec { + strategy: if pbs.strategy == 0 { String::new() } else { String::from_utf8_lossy(&[pbs.strategy as u8]).to_string() }, + is_default: pbs.is_default, + modulus: pbs.modulus, + remainder: pbs.remainder, + listdatums, + lowerdatums, + upperdatums, + location: pbs.location, + }) + } + unsafe fn queue_partition_range_datum(&mut self, prd: &bindings_raw::PartitionRangeDatum) { + self.queue_node(prd.value); + } + unsafe fn collect_partition_range_datum(&mut self, prd: &bindings_raw::PartitionRangeDatum) -> protobuf::node::Node { + let value = self.single_result_box(prd.value); + let kind = match prd.kind { + bindings_raw::PartitionRangeDatumKind_PARTITION_RANGE_DATUM_MINVALUE => 1, + bindings_raw::PartitionRangeDatumKind_PARTITION_RANGE_DATUM_VALUE => 2, + bindings_raw::PartitionRangeDatumKind_PARTITION_RANGE_DATUM_MAXVALUE => 3, + _ => 0, + }; + protobuf::node::Node::PartitionRangeDatum(Box::new(protobuf::PartitionRangeDatum { kind, value, location: prd.location })) } -} -unsafe fn convert_json_array_agg(jaa: &bindings_raw::JsonArrayAgg) -> protobuf::JsonArrayAgg { - protobuf::JsonArrayAgg { - constructor: if jaa.constructor.is_null() { None } else { Some(Box::new(convert_json_agg_constructor(&*jaa.constructor))) }, - arg: if jaa.arg.is_null() { None } else { Some(Box::new(convert_json_value_expr(&*jaa.arg))) }, - absent_on_null: jaa.absent_on_null, + // ==================================================================== + // Statement types (utility / session) + // ==================================================================== + unsafe fn queue_explain_stmt(&mut self, es: &bindings_raw::ExplainStmt) { + self.queue_node(es.query); + self.queue_list_nodes(es.options); + } + unsafe fn collect_explain_stmt(&mut self, es: &bindings_raw::ExplainStmt) -> protobuf::node::Node { + let query = self.single_result_box(es.query); + let options = self.fetch_list_results(es.options); + protobuf::node::Node::ExplainStmt(Box::new(protobuf::ExplainStmt { query, options })) + } + unsafe fn queue_copy_stmt(&mut self, cs: &bindings_raw::CopyStmt) { + if !cs.relation.is_null() { + self.queue_node(cs.relation as *const bindings_raw::Node); + } + self.queue_node(cs.query); + self.queue_list_nodes(cs.attlist); + self.queue_list_nodes(cs.options); + self.queue_node(cs.whereClause); + } + unsafe fn collect_copy_stmt(&mut self, cs: &bindings_raw::CopyStmt) -> protobuf::node::Node { + let relation = if cs.relation.is_null() { None } else { self.pop_range_var() }; + let query = self.single_result_box(cs.query); + let attlist = self.fetch_list_results(cs.attlist); + let options = self.fetch_list_results(cs.options); + let where_clause = self.single_result_box(cs.whereClause); + protobuf::node::Node::CopyStmt(Box::new(protobuf::CopyStmt { + relation, + query, + attlist, + is_from: cs.is_from, + is_program: cs.is_program, + filename: convert_c_string(cs.filename), + options, + where_clause, + })) + } + unsafe fn queue_prepare_stmt(&mut self, ps: &bindings_raw::PrepareStmt) { + self.queue_list_nodes(ps.argtypes); + self.queue_node(ps.query); + } + unsafe fn collect_prepare_stmt(&mut self, ps: &bindings_raw::PrepareStmt) -> protobuf::node::Node { + let argtypes = self.fetch_list_results(ps.argtypes); + let query = self.single_result_box(ps.query); + protobuf::node::Node::PrepareStmt(Box::new(protobuf::PrepareStmt { name: convert_c_string(ps.name), argtypes, query })) + } + unsafe fn queue_execute_stmt(&mut self, es: &bindings_raw::ExecuteStmt) { + self.queue_list_nodes(es.params); + } + unsafe fn collect_execute_stmt(&mut self, es: &bindings_raw::ExecuteStmt) -> protobuf::node::Node { + let params = self.fetch_list_results(es.params); + protobuf::node::Node::ExecuteStmt(protobuf::ExecuteStmt { name: convert_c_string(es.name), params }) + } + unsafe fn queue_transaction_stmt(&mut self, ts: &bindings_raw::TransactionStmt) { + self.queue_list_nodes(ts.options); + } + unsafe fn collect_transaction_stmt(&mut self, ts: &bindings_raw::TransactionStmt) -> protobuf::node::Node { + let options = self.fetch_list_results(ts.options); + protobuf::node::Node::TransactionStmt(protobuf::TransactionStmt { + kind: ts.kind as i32 + 1, + options, + savepoint_name: convert_c_string(ts.savepoint_name), + gid: convert_c_string(ts.gid), + chain: ts.chain, + location: ts.location, + }) + } + unsafe fn queue_vacuum_stmt(&mut self, vs: &bindings_raw::VacuumStmt) { + self.queue_list_nodes(vs.options); + self.queue_list_nodes(vs.rels); + } + unsafe fn collect_vacuum_stmt(&mut self, vs: &bindings_raw::VacuumStmt) -> protobuf::node::Node { + let options = self.fetch_list_results(vs.options); + let rels = self.fetch_list_results(vs.rels); + protobuf::node::Node::VacuumStmt(protobuf::VacuumStmt { options, rels, is_vacuumcmd: vs.is_vacuumcmd }) + } + unsafe fn queue_vacuum_relation(&mut self, vr: &bindings_raw::VacuumRelation) { + if !vr.relation.is_null() { + self.queue_node(vr.relation as *const bindings_raw::Node); + } + self.queue_list_nodes(vr.va_cols); + } + unsafe fn collect_vacuum_relation(&mut self, vr: &bindings_raw::VacuumRelation) -> protobuf::node::Node { + let relation = if vr.relation.is_null() { None } else { self.pop_range_var() }; + let va_cols = self.fetch_list_results(vr.va_cols); + protobuf::node::Node::VacuumRelation(protobuf::VacuumRelation { relation, oid: vr.oid, va_cols }) + } + unsafe fn queue_variable_set_stmt(&mut self, vss: &bindings_raw::VariableSetStmt) { + self.queue_list_nodes(vss.args); + } + unsafe fn collect_variable_set_stmt(&mut self, vss: &bindings_raw::VariableSetStmt) -> protobuf::node::Node { + let args = self.fetch_list_results(vss.args); + protobuf::node::Node::VariableSetStmt(protobuf::VariableSetStmt { + kind: vss.kind as i32 + 1, + name: convert_c_string(vss.name), + args, + is_local: vss.is_local, + }) + } + unsafe fn queue_lock_stmt(&mut self, ls: &bindings_raw::LockStmt) { + self.queue_list_nodes(ls.relations); + } + unsafe fn collect_lock_stmt(&mut self, ls: &bindings_raw::LockStmt) -> protobuf::node::Node { + let relations = self.fetch_list_results(ls.relations); + protobuf::node::Node::LockStmt(protobuf::LockStmt { relations, mode: ls.mode, nowait: ls.nowait }) + } + unsafe fn queue_do_stmt(&mut self, ds: &bindings_raw::DoStmt) { + self.queue_list_nodes(ds.args); + } + unsafe fn collect_do_stmt(&mut self, ds: &bindings_raw::DoStmt) -> protobuf::node::Node { + let args = self.fetch_list_results(ds.args); + protobuf::node::Node::DoStmt(protobuf::DoStmt { args }) + } + unsafe fn queue_object_with_args(&mut self, owa: &bindings_raw::ObjectWithArgs) { + self.queue_list_nodes(owa.objname); + self.queue_list_nodes(owa.objargs); + self.queue_list_nodes(owa.objfuncargs); + } + unsafe fn collect_object_with_args(&mut self, owa: &bindings_raw::ObjectWithArgs) -> protobuf::node::Node { + let objname = self.fetch_list_results(owa.objname); + let objargs = self.fetch_list_results(owa.objargs); + let objfuncargs = self.fetch_list_results(owa.objfuncargs); + protobuf::node::Node::ObjectWithArgs(protobuf::ObjectWithArgs { objname, objargs, objfuncargs, args_unspecified: owa.args_unspecified }) + } + unsafe fn queue_coerce_to_domain(&mut self, ctd: &bindings_raw::CoerceToDomain) { + self.queue_node(ctd.arg as *const bindings_raw::Node); + } + unsafe fn collect_coerce_to_domain(&mut self, ctd: &bindings_raw::CoerceToDomain) -> protobuf::node::Node { + let arg = self.single_result_box(ctd.arg as *const bindings_raw::Node); + protobuf::node::Node::CoerceToDomain(Box::new(protobuf::CoerceToDomain { + xpr: None, + arg, + resulttype: ctd.resulttype, + resulttypmod: ctd.resulttypmod, + resultcollid: ctd.resultcollid, + coercionformat: ctd.coercionformat as i32 + 1, + location: ctd.location, + })) + } + unsafe fn queue_function_parameter(&mut self, fp: &bindings_raw::FunctionParameter) { + if !fp.argType.is_null() { + self.queue_node(fp.argType as *const bindings_raw::Node); + } + self.queue_node(fp.defexpr); + } + unsafe fn collect_function_parameter(&mut self, fp: &bindings_raw::FunctionParameter) -> protobuf::node::Node { + let arg_type = if fp.argType.is_null() { + None + } else { + self.result_stack.pop().and_then(|n| match n.node { + Some(protobuf::node::Node::TypeName(tn)) => Some(tn), + _ => None, + }) + }; + let defexpr = self.single_result_box(fp.defexpr); + let mode = match fp.mode { + bindings_raw::FunctionParameterMode_FUNC_PARAM_IN => protobuf::FunctionParameterMode::FuncParamIn as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_OUT => protobuf::FunctionParameterMode::FuncParamOut as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_INOUT => protobuf::FunctionParameterMode::FuncParamInout as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_VARIADIC => protobuf::FunctionParameterMode::FuncParamVariadic as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_TABLE => protobuf::FunctionParameterMode::FuncParamTable as i32, + bindings_raw::FunctionParameterMode_FUNC_PARAM_DEFAULT => protobuf::FunctionParameterMode::FuncParamDefault as i32, + _ => 0, + }; + protobuf::node::Node::FunctionParameter(Box::new(protobuf::FunctionParameter { name: convert_c_string(fp.name), arg_type, mode, defexpr })) + } +} + +/// Returns a human-readable name for a NodeTag value (for debug logging). +fn node_tag_name(tag: u32) -> &'static str { + match tag { + bindings_raw::NodeTag_T_SelectStmt => "SelectStmt", + bindings_raw::NodeTag_T_InsertStmt => "InsertStmt", + bindings_raw::NodeTag_T_UpdateStmt => "UpdateStmt", + bindings_raw::NodeTag_T_DeleteStmt => "DeleteStmt", + bindings_raw::NodeTag_T_ResTarget => "ResTarget", + bindings_raw::NodeTag_T_A_Const => "A_Const", + bindings_raw::NodeTag_T_A_Expr => "A_Expr", + bindings_raw::NodeTag_T_ColumnRef => "ColumnRef", + bindings_raw::NodeTag_T_FuncCall => "FuncCall", + bindings_raw::NodeTag_T_TypeCast => "TypeCast", + bindings_raw::NodeTag_T_RangeVar => "RangeVar", + bindings_raw::NodeTag_T_JoinExpr => "JoinExpr", + bindings_raw::NodeTag_T_SortBy => "SortBy", + bindings_raw::NodeTag_T_BoolExpr => "BoolExpr", + bindings_raw::NodeTag_T_SubLink => "SubLink", + bindings_raw::NodeTag_T_NullTest => "NullTest", + bindings_raw::NodeTag_T_CaseExpr => "CaseExpr", + bindings_raw::NodeTag_T_CaseWhen => "CaseWhen", + bindings_raw::NodeTag_T_A_Star => "A_Star", + bindings_raw::NodeTag_T_Integer => "Integer", + bindings_raw::NodeTag_T_Float => "Float", + bindings_raw::NodeTag_T_Boolean => "Boolean", + bindings_raw::NodeTag_T_String => "String", + bindings_raw::NodeTag_T_BitString => "BitString", + bindings_raw::NodeTag_T_WithClause => "WithClause", + bindings_raw::NodeTag_T_TypeName => "TypeName", + bindings_raw::NodeTag_T_ParamRef => "ParamRef", + bindings_raw::NodeTag_T_List => "List", + bindings_raw::NodeTag_T_WindowDef => "WindowDef", + bindings_raw::NodeTag_T_CoalesceExpr => "CoalesceExpr", + bindings_raw::NodeTag_T_MinMaxExpr => "MinMaxExpr", + bindings_raw::NodeTag_T_SQLValueFunction => "SQLValueFunction", + bindings_raw::NodeTag_T_SetToDefault => "SetToDefault", + bindings_raw::NodeTag_T_BooleanTest => "BooleanTest", + bindings_raw::NodeTag_T_A_ArrayExpr => "A_ArrayExpr", + bindings_raw::NodeTag_T_A_Indirection => "A_Indirection", + bindings_raw::NodeTag_T_A_Indices => "A_Indices", + bindings_raw::NodeTag_T_CollateClause => "CollateClause", + bindings_raw::NodeTag_T_RangeSubselect => "RangeSubselect", + bindings_raw::NodeTag_T_CommonTableExpr => "CommonTableExpr", + bindings_raw::NodeTag_T_CTESearchClause => "CTESearchClause", + bindings_raw::NodeTag_T_CTECycleClause => "CTECycleClause", + bindings_raw::NodeTag_T_GroupingSet => "GroupingSet", + bindings_raw::NodeTag_T_LockingClause => "LockingClause", + bindings_raw::NodeTag_T_RowExpr => "RowExpr", + bindings_raw::NodeTag_T_MultiAssignRef => "MultiAssignRef", + bindings_raw::NodeTag_T_Alias => "Alias", + bindings_raw::NodeTag_T_GroupingFunc => "GroupingFunc", + _ => "Unknown", } } -// ============================================================================ -// Additional Helper Functions -// ============================================================================ - -unsafe fn convert_variable_set_stmt_opt(stmt: *mut bindings_raw::VariableSetStmt) -> Option { - if stmt.is_null() { +unsafe fn convert_a_const(aconst: &bindings_raw::A_Const) -> protobuf::AConst { + let val = if aconst.isnull { None } else { - Some(convert_variable_set_stmt(&*stmt)) - } + // Check the node tag in the val union to determine the type + let node_tag = aconst.val.node.type_; + match node_tag { + bindings_raw::NodeTag_T_Integer => Some(protobuf::a_const::Val::Ival(protobuf::Integer { ival: aconst.val.ival.ival })), + bindings_raw::NodeTag_T_Float => { + let fval = if aconst.val.fval.fval.is_null() { + std::string::String::new() + } else { + CStr::from_ptr(aconst.val.fval.fval).to_string_lossy().to_string() + }; + Some(protobuf::a_const::Val::Fval(protobuf::Float { fval })) + } + bindings_raw::NodeTag_T_Boolean => Some(protobuf::a_const::Val::Boolval(protobuf::Boolean { boolval: aconst.val.boolval.boolval })), + bindings_raw::NodeTag_T_String => { + let sval = if aconst.val.sval.sval.is_null() { + std::string::String::new() + } else { + CStr::from_ptr(aconst.val.sval.sval).to_string_lossy().to_string() + }; + Some(protobuf::a_const::Val::Sval(protobuf::String { sval })) + } + bindings_raw::NodeTag_T_BitString => { + let bsval = if aconst.val.bsval.bsval.is_null() { + std::string::String::new() + } else { + CStr::from_ptr(aconst.val.bsval.bsval).to_string_lossy().to_string() + }; + Some(protobuf::a_const::Val::Bsval(protobuf::BitString { bsval })) + } + _ => None, + } + }; + + protobuf::AConst { isnull: aconst.isnull, val, location: aconst.location } } -unsafe fn convert_infer_clause_opt(ic: *mut bindings_raw::InferClause) -> Option> { - if ic.is_null() { - None +/// Converts a C string pointer to a Rust String. +unsafe fn convert_c_string(ptr: *const c_char) -> std::string::String { + if ptr.is_null() { + std::string::String::new() } else { - let ic_ref = &*ic; - Some(Box::new(protobuf::InferClause { - index_elems: convert_list_to_nodes(ic_ref.indexElems), - where_clause: convert_node_boxed(ic_ref.whereClause), - conname: convert_c_string(ic_ref.conname), - location: ic_ref.location, - })) + CStr::from_ptr(ptr).to_string_lossy().to_string() } } + +unsafe fn convert_string(s: &bindings_raw::String) -> protobuf::String { + protobuf::String { sval: convert_c_string(s.sval) } +} + +unsafe fn convert_bit_string(bs: &bindings_raw::BitString) -> protobuf::BitString { + protobuf::BitString { bsval: convert_c_string(bs.bsval) } +} From 9e9a7a22b071179345bf663cd9d8681dd85b4529 Mon Sep 17 00:00:00 2001 From: meskill <8974488+meskill@users.noreply.github.com> Date: Sun, 8 Feb 2026 22:32:44 +0000 Subject: [PATCH 4/4] remove debug logs --- src/raw_parse_iter.rs | 142 +----------------------------------------- 1 file changed, 1 insertion(+), 141 deletions(-) diff --git a/src/raw_parse_iter.rs b/src/raw_parse_iter.rs index 266d525..af268a8 100644 --- a/src/raw_parse_iter.rs +++ b/src/raw_parse_iter.rs @@ -72,8 +72,6 @@ unsafe fn convert_list_to_raw_stmts(list: *mut bindings_raw::List) -> Vec protobuf::RawStmt { let mut processor = Processor::new(raw_stmt.stmt); - println!("processing raw_stmt"); - processor.process(); protobuf::RawStmt { stmt: processor.get_result(), stmt_location: raw_stmt.stmt_location, stmt_len: raw_stmt.stmt_len } @@ -107,13 +105,7 @@ impl Processor { } fn get_result(mut self) -> Option> { - println!("[result] get_result: result_stack.len={}", self.result_stack.len()); let result = self.result_stack.pop(); - println!( - "[result] popped={:?}, remaining={}", - result.as_ref().map(|n| format!("{:?}", n.node.as_ref().map(|n| std::mem::discriminant(n)))), - self.result_stack.len(), - ); assert!(self.result_stack.is_empty(), "Result stack should be empty after processing, but has {} items left", self.result_stack.len()); @@ -131,26 +123,15 @@ impl Processor { let node_tag = (*node_ptr).type_; - println!( - "[process] tag={} ({}) collect={} stack_depth={} result_stack_depth={}", - node_tag_name(node_tag), - node_tag, - collect, - self.stack.len(), - self.result_stack.len(), - ); - match node_tag { // === SelectStmt (boxed) === bindings_raw::NodeTag_T_SelectStmt => { let stmt = node_ptr as *const bindings_raw::SelectStmt; if collect { - println!("[collect] SelectStmt — result_stack={}", self.result_stack.len()); let node = self.collect_select_stmt(&*stmt); self.push_result(node); } else { - println!("[queue] SelectStmt — pushing collect + children"); self.queue_collect(node_ptr); self.queue_select_stmt(&*stmt); } @@ -161,11 +142,9 @@ impl Processor { let rt = node_ptr as *const bindings_raw::ResTarget; if collect { - println!("[collect] ResTarget — result_stack={}", self.result_stack.len()); let node = self.collect_res_target(&*rt); self.push_result(node); } else { - println!("[queue] ResTarget — pushing collect + children"); self.queue_collect(node_ptr); self.queue_res_target(&*rt); } @@ -176,11 +155,9 @@ impl Processor { let cr = node_ptr as *const bindings_raw::ColumnRef; if collect { - println!("[collect] ColumnRef — result_stack={}", self.result_stack.len()); let node = self.collect_column_ref(&*cr); self.push_result(node); } else { - println!("[queue] ColumnRef — pushing collect + children"); self.queue_collect(node_ptr); self.queue_column_ref(&*cr); } @@ -190,11 +167,9 @@ impl Processor { bindings_raw::NodeTag_T_RangeVar => { let rv = node_ptr as *const bindings_raw::RangeVar; if collect { - println!("[collect] RangeVar — result_stack={}", self.result_stack.len()); let node = self.collect_range_var(&*rv); self.push_result(node); } else { - println!("[queue] RangeVar relname={:?} — pushing collect + children", convert_c_string((*rv).relname)); self.queue_collect(node_ptr); self.queue_range_var(&*rv); } @@ -204,11 +179,9 @@ impl Processor { bindings_raw::NodeTag_T_JoinExpr => { let je = node_ptr as *const bindings_raw::JoinExpr; if collect { - println!("[collect] JoinExpr — result_stack={}", self.result_stack.len()); let node = self.collect_join_expr(&*je); self.push_result(node); } else { - println!("[queue] JoinExpr — pushing collect + children"); self.queue_collect(node_ptr); self.queue_join_expr(&*je); } @@ -218,11 +191,9 @@ impl Processor { bindings_raw::NodeTag_T_A_Expr => { let expr = node_ptr as *const bindings_raw::A_Expr; if collect { - println!("[collect] A_Expr — result_stack={}", self.result_stack.len()); let node = self.collect_a_expr(&*expr); self.push_result(node); } else { - println!("[queue] A_Expr — pushing collect + children"); self.queue_collect(node_ptr); self.queue_a_expr(&*expr); } @@ -232,11 +203,9 @@ impl Processor { bindings_raw::NodeTag_T_FuncCall => { let fc = node_ptr as *const bindings_raw::FuncCall; if collect { - println!("[collect] FuncCall — result_stack={}", self.result_stack.len()); let node = self.collect_func_call(&*fc); self.push_result(node); } else { - println!("[queue] FuncCall — pushing collect + children"); self.queue_collect(node_ptr); self.queue_func_call(&*fc); } @@ -246,11 +215,9 @@ impl Processor { bindings_raw::NodeTag_T_WindowDef => { let wd = node_ptr as *const bindings_raw::WindowDef; if collect { - println!("[collect] WindowDef — result_stack={}", self.result_stack.len()); let node = self.collect_window_def(&*wd); self.push_result(node); } else { - println!("[queue] WindowDef — pushing collect + children"); self.queue_collect(node_ptr); self.queue_window_def(&*wd); } @@ -260,11 +227,9 @@ impl Processor { bindings_raw::NodeTag_T_InsertStmt => { let stmt = node_ptr as *const bindings_raw::InsertStmt; if collect { - println!("[collect] InsertStmt — result_stack={}", self.result_stack.len()); let node = self.collect_insert_stmt(&*stmt); self.push_result(node); } else { - println!("[queue] InsertStmt — pushing collect + children"); self.queue_collect(node_ptr); self.queue_insert_stmt(&*stmt); } @@ -274,11 +239,9 @@ impl Processor { bindings_raw::NodeTag_T_UpdateStmt => { let stmt = node_ptr as *const bindings_raw::UpdateStmt; if collect { - println!("[collect] UpdateStmt — result_stack={}", self.result_stack.len()); let node = self.collect_update_stmt(&*stmt); self.push_result(node); } else { - println!("[queue] UpdateStmt — pushing collect + children"); self.queue_collect(node_ptr); self.queue_update_stmt(&*stmt); } @@ -288,11 +251,9 @@ impl Processor { bindings_raw::NodeTag_T_DeleteStmt => { let stmt = node_ptr as *const bindings_raw::DeleteStmt; if collect { - println!("[collect] DeleteStmt — result_stack={}", self.result_stack.len()); let node = self.collect_delete_stmt(&*stmt); self.push_result(node); } else { - println!("[queue] DeleteStmt — pushing collect + children"); self.queue_collect(node_ptr); self.queue_delete_stmt(&*stmt); } @@ -302,11 +263,9 @@ impl Processor { bindings_raw::NodeTag_T_List => { let list = node_ptr as *mut bindings_raw::List; if collect { - println!("[collect] List — result_stack={}", self.result_stack.len()); let items = self.fetch_list_results(list); self.push_result(protobuf::node::Node::List(protobuf::List { items })); } else { - println!("[queue] List — pushing collect + items"); self.queue_collect(node_ptr); self.queue_list_nodes(list); } @@ -316,11 +275,9 @@ impl Processor { bindings_raw::NodeTag_T_SortBy => { let sb = node_ptr as *const bindings_raw::SortBy; if collect { - println!("[collect] SortBy — result_stack={}", self.result_stack.len()); let node = self.collect_sort_by(&*sb); self.push_result(node); } else { - println!("[queue] SortBy — pushing collect + children"); self.queue_collect(node_ptr); self.queue_sort_by(&*sb); } @@ -330,11 +287,9 @@ impl Processor { bindings_raw::NodeTag_T_TypeCast => { let tc = node_ptr as *const bindings_raw::TypeCast; if collect { - println!("[collect] TypeCast — result_stack={}", self.result_stack.len()); let node = self.collect_type_cast(&*tc); self.push_result(node); } else { - println!("[queue] TypeCast — pushing collect + children"); self.queue_collect(node_ptr); self.queue_type_cast(&*tc); } @@ -344,11 +299,9 @@ impl Processor { bindings_raw::NodeTag_T_TypeName => { let tn = node_ptr as *const bindings_raw::TypeName; if collect { - println!("[collect] TypeName — result_stack={}", self.result_stack.len()); let node = self.collect_type_name(&*tn); self.push_result(node); } else { - println!("[queue] TypeName — pushing collect + children"); self.queue_collect(node_ptr); self.queue_type_name(&*tn); } @@ -357,28 +310,24 @@ impl Processor { // === A_Const (leaf — no children) === bindings_raw::NodeTag_T_A_Const => { let aconst = node_ptr as *const bindings_raw::A_Const; - println!("[leaf] A_Const isnull={}", (*aconst).isnull); let converted = convert_a_const(&*aconst); self.push_result(protobuf::node::Node::AConst(converted)); } // === A_Star (leaf) === bindings_raw::NodeTag_T_A_Star => { - println!("[leaf] A_Star"); self.push_result(protobuf::node::Node::AStar(protobuf::AStar {})); } // === String (leaf) === bindings_raw::NodeTag_T_String => { let s = node_ptr as *const bindings_raw::String; - println!("[leaf] String sval={:?}", convert_c_string((*s).sval)); self.push_result(protobuf::node::Node::String(convert_string(&*s))); } // === Integer (leaf) === bindings_raw::NodeTag_T_Integer => { let i = node_ptr as *const bindings_raw::Integer; - println!("[leaf] Integer ival={}", (*i).ival); self.push_result(protobuf::node::Node::Integer(protobuf::Integer { ival: (*i).ival })); } @@ -386,28 +335,24 @@ impl Processor { bindings_raw::NodeTag_T_Float => { let f = node_ptr as *const bindings_raw::Float; let fval = if (*f).fval.is_null() { std::string::String::new() } else { CStr::from_ptr((*f).fval).to_string_lossy().to_string() }; - println!("[leaf] Float fval={:?}", fval); self.push_result(protobuf::node::Node::Float(protobuf::Float { fval })); } // === Boolean (leaf) === bindings_raw::NodeTag_T_Boolean => { let b = node_ptr as *const bindings_raw::Boolean; - println!("[leaf] Boolean boolval={}", (*b).boolval); self.push_result(protobuf::node::Node::Boolean(protobuf::Boolean { boolval: (*b).boolval })); } // === BitString (leaf) === bindings_raw::NodeTag_T_BitString => { let bs = node_ptr as *const bindings_raw::BitString; - println!("[leaf] BitString"); self.push_result(protobuf::node::Node::BitString(convert_bit_string(&*bs))); } // === ParamRef (leaf) === bindings_raw::NodeTag_T_ParamRef => { let pr = node_ptr as *const bindings_raw::ParamRef; - println!("[leaf] ParamRef number={}", (*pr).number); self.push_result(protobuf::node::Node::ParamRef(protobuf::ParamRef { number: (*pr).number, location: (*pr).location })); } @@ -1281,11 +1226,7 @@ impl Processor { } _ => { - panic!( - "[ERROR] Unhandled node tag={} ({}) in iterative processor. This type needs to be migrated.", - node_tag_name(node_tag), - node_tag, - ); + panic!("[ERROR] Unhandled node tag={} in iterative processor. This type needs to be migrated.", node_tag,); } } } @@ -1300,18 +1241,15 @@ impl Processor { } fn push_result(&mut self, node: protobuf::node::Node) { - println!("[push] result variant={:?} → result_stack will be {}", std::mem::discriminant(&node), self.result_stack.len() + 1); self.result_stack.push(protobuf::Node { node: Some(node) }); } fn single_result(&mut self, node: *const bindings_raw::Node) -> Option { if node.is_null() { - println!("[single] node is null — skipping pop"); return None; } let result = self.result_stack.pop().expect("result stack should not be empty while processing"); - println!("[single] popped result — result_stack now={}", self.result_stack.len()); Some(result) } @@ -1320,7 +1258,6 @@ impl Processor { } fn fetch_results(&mut self, count: usize) -> Vec { - println!("[fetch] count={} from result_stack.len={}", count, self.result_stack.len()); if count > self.result_stack.len() { panic!( "fetch_results: count ({}) > result_stack.len ({}) — stack contents: {:?}", @@ -1340,16 +1277,13 @@ impl Processor { let list = &*list; let length = list.length as usize; - println!("[qlist] queuing {} nodes from list", length); self.stack.reserve(length); for i in 0..length { let cell = list.elements.add(i); let node = (*cell).ptr_value as *const bindings_raw::Node; if !node.is_null() { - println!("[qlist] [{}] tag={} ({})", i, node_tag_name((*node).type_), (*node).type_); } else { - println!("[qlist] [{}] null", i); } self.stack.push(ProcessingNode::with_node(node)); } @@ -1362,7 +1296,6 @@ impl Processor { let list = &*list; let length = list.length as usize; - println!("[flist] fetching {} results for list", length); self.fetch_results(length) } @@ -1486,11 +1419,6 @@ impl Processor { unsafe fn queue_res_target(&mut self, rt: &bindings_raw::ResTarget) { // Queue children that need recursive processing: // indirection (list of nodes) and val (single node) - println!( - "[queue] ResTarget children: indirection={}, val={}", - if rt.indirection.is_null() { "null".to_string() } else { format!("list({})", (*rt.indirection).length) }, - if rt.val.is_null() { "null" } else { "present" }, - ); self.queue_list_nodes(rt.indirection); self.queue_node(rt.val); } @@ -1499,14 +1427,6 @@ impl Processor { let indirection = self.fetch_list_results(rt.indirection); let val = self.single_result_box(rt.val); - println!( - "[collect] ResTarget: name={:?}, indirection_len={}, val={:?}, location={}", - convert_c_string(rt.name), - indirection.len(), - val.as_ref().map(|v| format!("{:?}", v.node.as_ref().map(|n| std::mem::discriminant(n)))), - rt.location, - ); - let res = protobuf::ResTarget { name: convert_c_string(rt.name), indirection, val, location: rt.location }; protobuf::node::Node::ResTarget(Box::new(res)) } @@ -1516,16 +1436,11 @@ impl Processor { // ==================================================================== unsafe fn queue_column_ref(&mut self, cr: &bindings_raw::ColumnRef) { - println!( - "[queue] ColumnRef children: fields={}", - if cr.fields.is_null() { "null".to_string() } else { format!("list({})", (*cr.fields).length) }, - ); self.queue_list_nodes(cr.fields); } unsafe fn collect_column_ref(&mut self, cr: &bindings_raw::ColumnRef) -> protobuf::node::Node { let fields = self.fetch_list_results(cr.fields); - println!("[collect] ColumnRef: fields_len={}, location={}", fields.len(), cr.location); protobuf::node::Node::ColumnRef(protobuf::ColumnRef { fields, location: cr.location }) } @@ -3277,61 +3192,6 @@ impl Processor { } } -/// Returns a human-readable name for a NodeTag value (for debug logging). -fn node_tag_name(tag: u32) -> &'static str { - match tag { - bindings_raw::NodeTag_T_SelectStmt => "SelectStmt", - bindings_raw::NodeTag_T_InsertStmt => "InsertStmt", - bindings_raw::NodeTag_T_UpdateStmt => "UpdateStmt", - bindings_raw::NodeTag_T_DeleteStmt => "DeleteStmt", - bindings_raw::NodeTag_T_ResTarget => "ResTarget", - bindings_raw::NodeTag_T_A_Const => "A_Const", - bindings_raw::NodeTag_T_A_Expr => "A_Expr", - bindings_raw::NodeTag_T_ColumnRef => "ColumnRef", - bindings_raw::NodeTag_T_FuncCall => "FuncCall", - bindings_raw::NodeTag_T_TypeCast => "TypeCast", - bindings_raw::NodeTag_T_RangeVar => "RangeVar", - bindings_raw::NodeTag_T_JoinExpr => "JoinExpr", - bindings_raw::NodeTag_T_SortBy => "SortBy", - bindings_raw::NodeTag_T_BoolExpr => "BoolExpr", - bindings_raw::NodeTag_T_SubLink => "SubLink", - bindings_raw::NodeTag_T_NullTest => "NullTest", - bindings_raw::NodeTag_T_CaseExpr => "CaseExpr", - bindings_raw::NodeTag_T_CaseWhen => "CaseWhen", - bindings_raw::NodeTag_T_A_Star => "A_Star", - bindings_raw::NodeTag_T_Integer => "Integer", - bindings_raw::NodeTag_T_Float => "Float", - bindings_raw::NodeTag_T_Boolean => "Boolean", - bindings_raw::NodeTag_T_String => "String", - bindings_raw::NodeTag_T_BitString => "BitString", - bindings_raw::NodeTag_T_WithClause => "WithClause", - bindings_raw::NodeTag_T_TypeName => "TypeName", - bindings_raw::NodeTag_T_ParamRef => "ParamRef", - bindings_raw::NodeTag_T_List => "List", - bindings_raw::NodeTag_T_WindowDef => "WindowDef", - bindings_raw::NodeTag_T_CoalesceExpr => "CoalesceExpr", - bindings_raw::NodeTag_T_MinMaxExpr => "MinMaxExpr", - bindings_raw::NodeTag_T_SQLValueFunction => "SQLValueFunction", - bindings_raw::NodeTag_T_SetToDefault => "SetToDefault", - bindings_raw::NodeTag_T_BooleanTest => "BooleanTest", - bindings_raw::NodeTag_T_A_ArrayExpr => "A_ArrayExpr", - bindings_raw::NodeTag_T_A_Indirection => "A_Indirection", - bindings_raw::NodeTag_T_A_Indices => "A_Indices", - bindings_raw::NodeTag_T_CollateClause => "CollateClause", - bindings_raw::NodeTag_T_RangeSubselect => "RangeSubselect", - bindings_raw::NodeTag_T_CommonTableExpr => "CommonTableExpr", - bindings_raw::NodeTag_T_CTESearchClause => "CTESearchClause", - bindings_raw::NodeTag_T_CTECycleClause => "CTECycleClause", - bindings_raw::NodeTag_T_GroupingSet => "GroupingSet", - bindings_raw::NodeTag_T_LockingClause => "LockingClause", - bindings_raw::NodeTag_T_RowExpr => "RowExpr", - bindings_raw::NodeTag_T_MultiAssignRef => "MultiAssignRef", - bindings_raw::NodeTag_T_Alias => "Alias", - bindings_raw::NodeTag_T_GroupingFunc => "GroupingFunc", - _ => "Unknown", - } -} - unsafe fn convert_a_const(aconst: &bindings_raw::A_Const) -> protobuf::AConst { let val = if aconst.isnull { None