feat(mysql): expose executable comment recognition - #398
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fee6348234
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9a5c1a85a6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| type ExecutableCommentOptions struct { | ||
| // NoBackslashEscapes must match the session's NO_BACKSLASH_ESCAPES SQL | ||
| // mode. When true, backslashes in string literals are ordinary bytes. | ||
| NoBackslashEscapes bool |
There was a problem hiding this comment.
Account for ANSI_QUOTES when scanning double quotes
When the session enables ANSI_QUOTES without NO_BACKSLASH_ESCAPES, double quotes delimit identifiers and a backslash does not escape the following quote. For example, in SELECT "x\" /*!50000 + 1 */, MySQL closes the identifier before the comment and recognizes the executable opener, while this helper treats \" as part of a string and returns false. Add the applicable ANSI_QUOTES mode to the options and scan double-quoted identifiers with identifier escaping, or otherwise conservatively detect this boundary.
Useful? React with 👍 / 👎.
| if l.pos+2 < len(l.input) && l.input[l.pos+2] == '!' { | ||
| l.hasExecutableComment = true |
There was a problem hiding this comment.
Stop regular comments at MySQL's first terminator
Because this flag is set only after the ordinary-comment skipper exposes an opener, the skip logic's generic nesting behavior can hide a server-visible executable comment. MySQL regular block comments do not generally nest, so in /* outer /* inner */ /*!50000 DROP TABLE t*/ the first */ ends the ordinary comment and MySQL processes the following executable comment; this lexer instead increments its nesting depth for the inner /*, consumes through the executable comment's closing delimiter, and returns false. The detection path should scan ordinary comments using MySQL's actual termination rules.
Useful? React with 👍 / 👎.
| // ExecutableCommentOptions configures SQL modes that affect lexical comment | ||
| // recognition. | ||
| type ExecutableCommentOptions struct { | ||
| // NoBackslashEscapes must match the session's NO_BACKSLASH_ESCAPES SQL | ||
| // mode. When true, backslashes in string literals are ordinary bytes. | ||
| NoBackslashEscapes bool |
There was a problem hiding this comment.
Make string scanning aware of the connection character set
With a multibyte connection character set whose trailing bytes may include 0x5c, the byte-oriented string scanner can mistake part of a character for a backslash escape and hide an active opener. For example, under sjis, the bytes in SELECT '\x95\x5c' /*!50000 DROP TABLE t*/ encode one character followed by the closing quote, so MySQL sees the executable comment; this lexer consumes that quote as escaped and returns false. Pass the connection character set into detection or conservatively handle backslashes that can be multibyte trailing bytes.
Useful? React with 👍 / 👎.
Summary
parser.ContainsExecutableComment(sql, options)as a one-shot public lexer APINO_BACKSLASH_ESCAPESmode throughExecutableCommentOptions/*! ... */at the lexer boundary without changing normal token or AST behaviorWhy
MySQL executable comments are spliced into the token stream today, so callers cannot distinguish their contents from ordinary SQL through the public API. Security-sensitive consumers need a stable lexer signal instead of regex or raw-text scanning.
The API is intentionally conservative: unknown version prefixes and unterminated executable comments return true, while string literals, quoted identifiers, ordinary block comments, optimizer hints, and line comments return false under the supplied SQL mode.
Closes #397.
Validation
go build ./mysql/...go test -short ./mysql/parser -count=1go test -short ./mysql/ast ./mysql/completion ./mysql/deparse ./mysql/parser ./mysql/validate -count=1go vet ./mysql/parserThe Docker-backed non-short Oracle/catalog tests cannot run in the local Windows environment; the relevant non-container packages pass.