0
# SQL Parsing
1
2
SQL parsing classes provide MySQL and MariaDB-specific SQL parsing capabilities, handling database-specific syntax, delimiters, comments, and statement types. They ensure proper parsing of MySQL/MariaDB SQL scripts during migrations.
3
4
## Capabilities
5
6
### MySQL Parser
7
8
MySQL-specific SQL parser that handles MySQL syntax, delimiters, comments, and stored procedures.
9
10
```java { .api }
11
/**
12
* MySQL-specific SQL parser
13
* Handles MySQL SQL syntax, delimiters, comments, and statement parsing
14
*/
15
public class MySQLParser extends Parser {
16
17
/**
18
* Creates a new MySQL parser instance
19
* @param configuration Flyway configuration
20
* @param parsingContext Context for parsing operations
21
*/
22
public MySQLParser(Configuration configuration, ParsingContext parsingContext);
23
24
/**
25
* Handles DELIMITER command processing
26
* MySQL allows changing statement delimiters with DELIMITER command
27
* @param reader Source reader for SQL content
28
* @param context Parser context and state
29
* @param pos Current position in source
30
* @param line Current line number
31
* @param col Current column number
32
* @param keyword The "DELIMITER" keyword
33
* @return Token representing the new delimiter
34
* @throws IOException if reading fails
35
*/
36
@Override
37
protected Token handleKeyword(PeekingReader reader, ParserContext context, int pos, int line, int col, String keyword) throws IOException;
38
39
/**
40
* Returns the identifier quote character for MySQL
41
* @return '`' (backtick) for MySQL identifiers
42
*/
43
@Override
44
protected char getIdentifierQuote();
45
46
/**
47
* Returns the alternative string literal quote character
48
* @return '"' (double quote) for alternative string literals
49
*/
50
@Override
51
protected char getAlternativeStringLiteralQuote();
52
53
/**
54
* Determines if a character sequence is a single-line comment
55
* Supports both -- and # comment styles
56
* @param peek Character sequence to check
57
* @param context Parser context
58
* @param col Current column position
59
* @return true if sequence is a single-line comment
60
*/
61
@Override
62
protected boolean isSingleLineComment(String peek, ParserContext context, int col);
63
64
/**
65
* Handles string literal parsing with MySQL-specific escaping
66
* @param reader Source reader
67
* @param context Parser context
68
* @param pos Current position
69
* @param line Current line number
70
* @param col Current column number
71
* @return String literal token
72
* @throws IOException if reading fails
73
*/
74
@Override
75
protected Token handleStringLiteral(PeekingReader reader, ParserContext context, int pos, int line, int col) throws IOException;
76
77
/**
78
* Handles alternative string literal parsing (double quotes)
79
* @param reader Source reader
80
* @param context Parser context
81
* @param pos Current position
82
* @param line Current line number
83
* @param col Current column number
84
* @return String literal token
85
* @throws IOException if reading fails
86
*/
87
@Override
88
protected Token handleAlternativeStringLiteral(PeekingReader reader, ParserContext context, int pos, int line, int col) throws IOException;
89
90
/**
91
* Handles MySQL comment directives (/*! ... */)
92
* @param reader Source reader
93
* @param context Parser context
94
* @param pos Current position
95
* @param line Current line number
96
* @param col Current column number
97
* @return Comment directive token
98
* @throws IOException if reading fails
99
*/
100
@Override
101
protected Token handleCommentDirective(PeekingReader reader, ParserContext context, int pos, int line, int col) throws IOException;
102
103
/**
104
* Determines if text is a MySQL comment directive
105
* MySQL comment directives start with /*! and contain version-specific SQL
106
* @param text Text to check
107
* @return true if text is a comment directive
108
*/
109
@Override
110
protected boolean isCommentDirective(String text);
111
112
/**
113
* Detects MySQL statement types including stored procedures
114
* @param simplifiedStatement Simplified statement text
115
* @param context Parser context
116
* @param reader Source reader for additional parsing
117
* @return Statement type classification
118
*/
119
@Override
120
protected StatementType detectStatementType(String simplifiedStatement, ParserContext context, PeekingReader reader);
121
122
/**
123
* Determines if block depth should be adjusted for MySQL syntax
124
* @param context Parser context
125
* @param tokens Current token list
126
* @param token Current token being processed
127
* @return true if block depth adjustment needed
128
*/
129
@Override
130
protected boolean shouldAdjustBlockDepth(ParserContext context, List<Token> tokens, Token token);
131
132
/**
133
* Adjusts block depth for MySQL control structures
134
* @param context Parser context
135
* @param tokens Current token list
136
* @param keyword Current keyword token
137
* @param reader Source reader for lookahead
138
*/
139
@Override
140
protected void adjustBlockDepth(ParserContext context, List<Token> tokens, Token keyword, PeekingReader reader);
141
142
/**
143
* Resets delimiter state (MySQL preserves delimiters across statements)
144
* @param context Parser context
145
*/
146
@Override
147
protected void resetDelimiter(ParserContext context);
148
}
149
```
150
151
**Constants:**
152
153
```java { .api }
154
// Comment and parsing constants
155
private static final char ALTERNATIVE_SINGLE_LINE_COMMENT = '#';
156
private static final Pattern STORED_PROGRAM_REGEX = Pattern.compile(
157
"^CREATE\\s(((DEFINER\\s(\\w+\\s)?@\\s(\\w+\\s)?)?(PROCEDURE|FUNCTION|EVENT))|TRIGGER)",
158
Pattern.CASE_INSENSITIVE);
159
private static final StatementType STORED_PROGRAM_STATEMENT = new StatementType();
160
}
161
```
162
163
**Usage Examples:**
164
165
```java
166
// Parser creation via DatabaseType
167
MySQLDatabaseType dbType = new MySQLDatabaseType();
168
MySQLParser parser = (MySQLParser) dbType.createParser(configuration, resourceProvider, parsingContext);
169
170
// Parse MySQL script with DELIMITER changes
171
String sql = """
172
DELIMITER $$
173
CREATE PROCEDURE test_proc()
174
BEGIN
175
SELECT 'Hello World';
176
END$$
177
DELIMITER ;
178
""";
179
180
List<SqlStatement> statements = parser.parse(sql);
181
```
182
183
### MariaDB Parser
184
185
MariaDB-specific SQL parser extending MySQL parser with MariaDB-specific syntax support.
186
187
```java { .api }
188
/**
189
* MariaDB-specific SQL parser
190
* Extends MySQLParser with MariaDB-specific syntax and features
191
*/
192
public class MariaDBParser extends MySQLParser {
193
194
/**
195
* Creates a new MariaDB parser instance
196
* @param configuration Flyway configuration
197
* @param parsingContext Context for parsing operations
198
*/
199
public MariaDBParser(Configuration configuration, ParsingContext parsingContext);
200
201
/**
202
* Detects MariaDB-specific statement types
203
* Includes support for BEGIN NOT ATOMIC and other MariaDB extensions
204
* @param simplifiedStatement Simplified statement text
205
* @param context Parser context
206
* @param reader Source reader for additional parsing
207
* @return Statement type classification
208
*/
209
@Override
210
protected StatementType detectStatementType(String simplifiedStatement, ParserContext context, PeekingReader reader);
211
212
/**
213
* Adjusts block depth for MariaDB-specific control structures
214
* Handles BEGIN NOT ATOMIC and other MariaDB syntax
215
* @param context Parser context
216
* @param tokens Current token list
217
* @param keyword Current keyword token
218
* @param reader Source reader for lookahead
219
*/
220
@Override
221
protected void adjustBlockDepth(ParserContext context, List<Token> tokens, Token keyword, PeekingReader reader);
222
}
223
```
224
225
**Usage Example:**
226
227
```java
228
// MariaDB parser creation
229
MariaDBDatabaseType dbType = new MariaDBDatabaseType();
230
MariaDBParser parser = (MariaDBParser) dbType.createParser(configuration, resourceProvider, parsingContext);
231
232
// Parse MariaDB-specific syntax
233
String mariadbSql = """
234
BEGIN NOT ATOMIC
235
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
236
SELECT 'MariaDB specific syntax';
237
END;
238
""";
239
240
List<SqlStatement> statements = parser.parse(mariadbSql);
241
```
242
243
## MySQL Syntax Features
244
245
### Delimiter Handling
246
247
MySQL supports changing statement delimiters:
248
249
```sql
250
-- Default delimiter is semicolon
251
SELECT * FROM users;
252
253
-- Change delimiter for stored procedures
254
DELIMITER $$
255
256
CREATE PROCEDURE get_users()
257
BEGIN
258
SELECT * FROM users;
259
END$$
260
261
-- Reset delimiter
262
DELIMITER ;
263
```
264
265
**Parser Behavior:**
266
- Recognizes `DELIMITER` command
267
- Updates delimiter context dynamically
268
- Preserves delimiter changes across statements
269
- Handles nested delimiter scenarios
270
271
### Comment Support
272
273
#### Single-Line Comments
274
275
Two formats supported:
276
```sql
277
-- Standard SQL comment
278
SELECT * FROM users; -- End of line comment
279
280
# MySQL hash comment
281
SELECT * FROM users; # Alternative comment style
282
```
283
284
**Note:** Hash comments (`#`) are disabled when `#` is set as delimiter.
285
286
#### Multi-Line Comments
287
288
```sql
289
/* Standard multi-line comment */
290
SELECT * FROM users;
291
292
/*! MySQL-specific comment directive */
293
/*!50717 SELECT * FROM users */; -- Only execute on MySQL 5.7.17+
294
```
295
296
### String Literals
297
298
#### Single Quotes (Standard)
299
```sql
300
SELECT 'Hello World';
301
SELECT 'Don\'t worry'; -- Escaped quote
302
```
303
304
#### Double Quotes (Alternative)
305
```sql
306
SELECT "Hello World";
307
SELECT "Don\"t worry"; -- Escaped quote
308
```
309
310
**Parser Features:**
311
- Handles backslash escaping (`\'`, `\"`, `\\`)
312
- Supports both quote styles
313
- Proper escape sequence processing
314
315
### Identifier Quoting
316
317
MySQL uses backticks for identifiers:
318
```sql
319
SELECT `column name with spaces` FROM `table name`;
320
CREATE TABLE `order` (`index` INT); -- Reserved word quoting
321
```
322
323
## Statement Type Detection
324
325
### Stored Programs
326
327
Detects MySQL stored procedures, functions, events, and triggers:
328
329
```java
330
// Pattern for stored program detection
331
"^CREATE\\s(((DEFINER\\s(\\w+\\s)?@\\s(\\w+\\s)?)?(PROCEDURE|FUNCTION|EVENT))|TRIGGER)"
332
```
333
334
**Supported Patterns:**
335
```sql
336
CREATE PROCEDURE proc_name() ...
337
CREATE FUNCTION func_name() RETURNS INT ...
338
CREATE EVENT event_name ...
339
CREATE TRIGGER trigger_name ...
340
CREATE DEFINER=`user`@`host` PROCEDURE ...
341
```
342
343
### Control Structures
344
345
Block depth tracking for MySQL control structures:
346
- `BEGIN...END` blocks
347
- `IF...END IF` statements
348
- `WHILE...END WHILE` loops
349
- `REPEAT...UNTIL` loops
350
- `CASE...END CASE` statements
351
352
## MariaDB-Specific Features
353
354
### BEGIN NOT ATOMIC
355
356
MariaDB supports `BEGIN NOT ATOMIC` for compound statements:
357
358
```sql
359
BEGIN NOT ATOMIC
360
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
361
INSERT INTO logs VALUES ('Starting operation');
362
-- More statements
363
END;
364
```
365
366
**Parser Behavior:**
367
- Recognizes `BEGIN NOT ATOMIC` pattern
368
- Handles block depth correctly
369
- Supports MariaDB-specific error handling
370
371
### Statement Detection
372
373
MariaDB parser extends MySQL detection with:
374
- `BEGIN NOT ATOMIC` compound statements
375
- MariaDB-specific syntax variations
376
- Enhanced error handling constructs
377
378
## Comment Directives
379
380
MySQL comment directives provide version-specific SQL:
381
382
### Version-Specific Comments
383
```sql
384
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
385
/*!50717 SELECT JSON_EXTRACT(data, '$.key') FROM table1 */;
386
```
387
388
### Parser Processing
389
- Extracts version number from directive
390
- Preserves directive content
391
- Enables conditional SQL execution based on version
392
393
## Parser Configuration
394
395
### Block Depth Tracking
396
397
Parsers maintain block depth for:
398
- Stored procedure parsing
399
- Control structure nesting
400
- Transaction block handling
401
- Error handling blocks
402
403
### Context Management
404
405
Parser context tracks:
406
- Current delimiter setting
407
- Block nesting level
408
- Statement boundaries
409
- Token stream position
410
411
## Error Handling
412
413
### Parsing Errors
414
415
Common parsing scenarios:
416
- Malformed DELIMITER commands
417
- Unmatched quotes in string literals
418
- Invalid comment directive syntax
419
- Unterminated block structures
420
421
### Recovery Strategies
422
423
Parsers implement recovery for:
424
- Missing delimiter reset
425
- Incomplete string literals
426
- Nested comment issues
427
- Block structure mismatches
428
429
## Performance Considerations
430
431
### Lookahead Optimization
432
433
Parsers use efficient lookahead for:
434
- Keyword detection
435
- Statement type classification
436
- Block structure analysis
437
- Comment boundary detection
438
439
### Token Stream Processing
440
441
Optimized processing for:
442
- Large SQL script files
443
- Complex stored procedures
444
- Deeply nested structures
445
- Multiple delimiter changes