You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Mode values are stored under their **canonical spelling**, not as a span of the input, so a consumer can compare a child against `"READ ONLY"` without first normalizing case or internal whitespace. `select_parser.h` already does this for `NOWAIT` and `SKIP LOCKED`. Spanning the source instead would make `READ ONLY` a different string from `READ ONLY`, which every consumer would then have to work around.
@@ -171,13 +163,13 @@ Mode values are stored under their **canonical spelling**, not as a span of the
171
163
172
164
### Recording the introducing keywords
173
165
174
-
`stmt_type` distinguishes `BEGIN` from `START TRANSACTION`, but not `BEGIN` from `BEGIN TRANSACTION`. The emitter needs that to round-trip, so it is recorded in the node flags rather than the node value — keywords are then emitted canonically like every other keyword in the emitter, instead of copying the input's casing. This matters for digests: `begin read only` and `BEGIN READ ONLY` must normalize to the same digest text, as they did when the statement had no AST and fell through to the token-level digest path, which uppercases keyword tokens.
166
+
`stmt_type` distinguishes `BEGIN` from `START TRANSACTION`, but not `BEGIN` from `BEGIN TRANSACTION`. The emitter needs that to round-trip, so the introducing keywords are stored as the node's **value**, under their canonical spelling — following `NODE_SET_OPERATION`, which likewise holds its mutually exclusive operator (`UNION` / `INTERSECT` / `EXCEPT`) in the value and reserves `flags` for the independent `ALL` modifier. A canonical literal rather than a source span keeps casing out of the digest: `begin read only` and `BEGIN READ ONLY` must normalize to the same digest text, as they did when the statement had no AST and fell through to the token-level digest path, which uppercases keyword tokens.
175
167
176
168
---
177
169
178
170
## Emitter Extensions
179
171
180
-
One new method, `emit_transaction_stmt()`, plus its dispatch case. It writes the introducing keywords from `flags`, then each mode. A single mode is emitted without a comma so the common forms round-trip exactly; multiple modes are comma-separated, which PostgreSQL accepts and MySQL requires. No case folding happens here as the parser already stored each mode canonically.
172
+
One new method, `emit_transaction_stmt()`, plus its dispatch case. It writes the node's value — the introducing keywords — then each mode. A single mode is emitted without a comma so the common forms round-trip exactly; multiple modes are comma-separated, which PostgreSQL accepts and MySQL requires. No case folding happens here as the parser already stored each mode canonically.
181
173
182
174
| input | emitted | dialect |
183
175
|---|---|---|
@@ -201,9 +193,9 @@ An input that starts a mode without completing it — `BEGIN READ`, `BEGIN ISOLA
201
193
202
194
## Implementation
203
195
204
-
1.`NODE_TRANSACTION_STMT` and the `FLAG_TXN_*` constants in `common.h`.
196
+
1.`NODE_TRANSACTION_STMT` and `FLAG_TXN_MODE_ISOLATION` in `common.h`.
205
197
2.`parse_transaction()` in `parser.cpp`, declared in the Tier-1 block of `parser.h`; `TK_BEGIN` / `TK_START` routed to it from `classify_and_dispatch()` and removed from `extract_transaction()`.
206
-
3.`parse_transaction_modes(ParseResult&, uint16_t)` as the mode loop, following the Tier-1 conventions: `ERROR` if the node cannot be allocated, `PARTIAL` on an incomplete mode. Each mode is stored under its canonical spelling, as `select_parser.h` already does for `NOWAIT` and `SKIP LOCKED`, so a consumer never has to normalize before comparing.
198
+
3.`parse_transaction_modes(ParseResult&, StringRef)` as the mode loop, following the Tier-1 conventions: `ERROR` if the node cannot be allocated, `PARTIAL` on an incomplete mode. Each mode is stored under its canonical spelling, as `select_parser.h` already does for `NOWAIT` and `SKIP LOCKED`, so a consumer never has to normalize before comparing.
207
199
4.`emit_transaction_stmt()` and its dispatch case in `emitter.h`.
208
200
5. Tests in `tests/test_misc_stmts.cpp`, beside the other Tier-1 statements that live in `parser.cpp`, plus digest coverage in `tests/test_digest.cpp`.
0 commit comments