Skip to content

Commit 6176339

Browse files
authored
Merge pull request #336 from liuxy0551/feat_mysql
mysql grammar correct
2 parents 24b392d + 5d6ff46 commit 6176339

File tree

14 files changed

+11625
-10547
lines changed

14 files changed

+11625
-10547
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ coverage
99
.idea
1010
gen/
1111
src/**/*.iml
12-
benchmark/reports/*
12+
benchmark/reports/*
13+
*.tgz

src/grammar/mysql/MySqlParser.g4

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ ddlStatement
7575
| createLogfileGroup
7676
| createProcedure
7777
| createFunction
78+
| createFunctionLoadable
7879
| createServer
7980
| createTable
8081
| createTablespaceInnodb
@@ -266,6 +267,22 @@ createProcedure
266267
)* ')' routineOption* routineBody
267268
;
268269

270+
createFunction
271+
: KW_CREATE ownerStatement? KW_AGGREGATE? KW_FUNCTION ifNotExists? functionNameCreate '(' functionParameter? (
272+
',' functionParameter
273+
)* ')' KW_RETURNS dataType routineOption* (routineBody | returnStatement)
274+
;
275+
276+
// https://dev.mysql.com/doc/refman/8.0/en/create-function-loadable.html
277+
createFunctionLoadable
278+
: KW_CREATE KW_AGGREGATE? KW_FUNCTION ifNotExists? functionNameCreate KW_RETURNS returnType=(
279+
KW_STRING
280+
| KW_INTEGER
281+
| KW_REAL
282+
| KW_DECIMAL
283+
) KW_SONAME STRING_LITERAL
284+
;
285+
269286
createRole
270287
: KW_CREATE KW_ROLE ifNotExists? userOrRoleNames
271288
;
@@ -310,7 +327,7 @@ createTablespaceNdb
310327
;
311328

312329
createTrigger
313-
: KW_CREATE ownerStatement? KW_TRIGGER ifNotExists? trigger_name=fullId triggerTime=(
330+
: KW_CREATE ownerStatement? ifNotExists? KW_TRIGGER ifNotExists? trigger_name=fullId triggerTime=(
314331
KW_BEFORE
315332
| KW_AFTER
316333
) triggerEvent=(KW_INSERT | KW_UPDATE | KW_DELETE) KW_ON tableName KW_FOR KW_EACH KW_ROW (
@@ -420,6 +437,10 @@ procedureParameter
420437
: direction=(KW_IN | KW_OUT | KW_INOUT)? paramName=uid dataType
421438
;
422439

440+
functionParameter
441+
: paramName=uid dataType
442+
;
443+
423444
routineOption
424445
: KW_COMMENT STRING_LITERAL # routineComment
425446
| KW_LANGUAGE KW_SQL # routineLanguage
@@ -907,19 +928,6 @@ replaceStatement
907928
)? (('(' columnNames ')')? replaceStatementValuesOrSelectOrTable | setAssignmentList)
908929
;
909930

910-
// selectStatement
911-
// : querySpecification lockClause? # simpleSelect
912-
// | querySpecificationNointo lockClause? intoClause? # simpleSelect
913-
// | queryExpression lockClause? # parenthesisSelect
914-
// | querySpecificationNointo unionStatement+ (
915-
// KW_UNION unionType=(KW_ALL | KW_DISTINCT)? (querySpecification | queryExpression)
916-
// )? orderByClause? limitClause? lockClause? # unionSelect
917-
// | queryExpressionNointo unionParenthesis+ (
918-
// KW_UNION unionType=(KW_ALL | KW_DISTINCT)? queryExpression
919-
// )? orderByClause? limitClause? lockClause? # unionParenthesisSelect
920-
// | querySpecificationNointo (',' lateralStatement)+ # withLateralStatement
921-
// ;
922-
923931
// TODO: Simplify the rules to fit SLL(*) Mode
924932
selectStatement
925933
: querySpecification unionStatement* (
@@ -1127,6 +1135,7 @@ queryExpression
11271135
*/
11281136
querySpecification
11291137
: KW_SELECT selectSpec* selectElements intoClause? fromClause groupByClause? havingClause? windowClause? orderByClause? limitClause? intoClause?
1138+
unionStatement?
11301139
;
11311140

11321141
unionStatement
@@ -1996,15 +2005,6 @@ checkTableOption
19962005
| KW_CHANGED
19972006
;
19982007

1999-
createFunction
2000-
: KW_CREATE KW_AGGREGATE? KW_FUNCTION ifNotExists? functionNameCreate KW_RETURNS returnType=(
2001-
KW_STRING
2002-
| KW_INTEGER
2003-
| KW_REAL
2004-
| KW_DECIMAL
2005-
) KW_SONAME STRING_LITERAL
2006-
;
2007-
20082008
installComponent
20092009
: KW_INSTALL KW_COMPONENT component_name=uid (',' component_name=uid)* (
20102010
KW_SET variableExpr (',' variableExpr)*
@@ -3421,6 +3421,7 @@ keywordsCanBeId
34213421
| KW_RESOURCE_GROUP_USER
34223422
| KW_RESUME
34233423
| KW_RETURNED_SQLSTATE
3424+
| KW_RETURNING
34243425
| KW_RETURNS
34253426
| KW_REUSE
34263427
| KW_ROLE

src/lib/mysql/MySqlParser.interp

Lines changed: 4 additions & 2 deletions
Large diffs are not rendered by default.

src/lib/mysql/MySqlParser.ts

Lines changed: 11453 additions & 10495 deletions
Large diffs are not rendered by default.

src/lib/mysql/MySqlParserListener.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { CreateEventContext } from "./MySqlParser.js";
2525
import { CreateIndexContext } from "./MySqlParser.js";
2626
import { CreateLogfileGroupContext } from "./MySqlParser.js";
2727
import { CreateProcedureContext } from "./MySqlParser.js";
28+
import { CreateFunctionContext } from "./MySqlParser.js";
29+
import { CreateFunctionLoadableContext } from "./MySqlParser.js";
2830
import { CreateRoleContext } from "./MySqlParser.js";
2931
import { CreateServerContext } from "./MySqlParser.js";
3032
import { QueryCreateTableContext } from "./MySqlParser.js";
@@ -49,6 +51,7 @@ import { EnableTypeContext } from "./MySqlParser.js";
4951
import { IndexTypeContext } from "./MySqlParser.js";
5052
import { IndexOptionContext } from "./MySqlParser.js";
5153
import { ProcedureParameterContext } from "./MySqlParser.js";
54+
import { FunctionParameterContext } from "./MySqlParser.js";
5255
import { RoutineCommentContext } from "./MySqlParser.js";
5356
import { RoutineLanguageContext } from "./MySqlParser.js";
5457
import { RoutineBehaviorContext } from "./MySqlParser.js";
@@ -444,7 +447,6 @@ import { OptimizeTableContext } from "./MySqlParser.js";
444447
import { RepairTableContext } from "./MySqlParser.js";
445448
import { TableActionOptionContext } from "./MySqlParser.js";
446449
import { CheckTableOptionContext } from "./MySqlParser.js";
447-
import { CreateFunctionContext } from "./MySqlParser.js";
448450
import { InstallComponentContext } from "./MySqlParser.js";
449451
import { VariableExprContext } from "./MySqlParser.js";
450452
import { UninstallComponentContext } from "./MySqlParser.js";
@@ -854,6 +856,26 @@ export class MySqlParserListener implements ParseTreeListener {
854856
* @param ctx the parse tree
855857
*/
856858
exitCreateProcedure?: (ctx: CreateProcedureContext) => void;
859+
/**
860+
* Enter a parse tree produced by `MySqlParser.createFunction`.
861+
* @param ctx the parse tree
862+
*/
863+
enterCreateFunction?: (ctx: CreateFunctionContext) => void;
864+
/**
865+
* Exit a parse tree produced by `MySqlParser.createFunction`.
866+
* @param ctx the parse tree
867+
*/
868+
exitCreateFunction?: (ctx: CreateFunctionContext) => void;
869+
/**
870+
* Enter a parse tree produced by `MySqlParser.createFunctionLoadable`.
871+
* @param ctx the parse tree
872+
*/
873+
enterCreateFunctionLoadable?: (ctx: CreateFunctionLoadableContext) => void;
874+
/**
875+
* Exit a parse tree produced by `MySqlParser.createFunctionLoadable`.
876+
* @param ctx the parse tree
877+
*/
878+
exitCreateFunctionLoadable?: (ctx: CreateFunctionLoadableContext) => void;
857879
/**
858880
* Enter a parse tree produced by `MySqlParser.createRole`.
859881
* @param ctx the parse tree
@@ -1104,6 +1126,16 @@ export class MySqlParserListener implements ParseTreeListener {
11041126
* @param ctx the parse tree
11051127
*/
11061128
exitProcedureParameter?: (ctx: ProcedureParameterContext) => void;
1129+
/**
1130+
* Enter a parse tree produced by `MySqlParser.functionParameter`.
1131+
* @param ctx the parse tree
1132+
*/
1133+
enterFunctionParameter?: (ctx: FunctionParameterContext) => void;
1134+
/**
1135+
* Exit a parse tree produced by `MySqlParser.functionParameter`.
1136+
* @param ctx the parse tree
1137+
*/
1138+
exitFunctionParameter?: (ctx: FunctionParameterContext) => void;
11071139
/**
11081140
* Enter a parse tree produced by the `routineComment`
11091141
* labeled alternative in `MySqlParser.routineOption`.
@@ -5440,16 +5472,6 @@ export class MySqlParserListener implements ParseTreeListener {
54405472
* @param ctx the parse tree
54415473
*/
54425474
exitCheckTableOption?: (ctx: CheckTableOptionContext) => void;
5443-
/**
5444-
* Enter a parse tree produced by `MySqlParser.createFunction`.
5445-
* @param ctx the parse tree
5446-
*/
5447-
enterCreateFunction?: (ctx: CreateFunctionContext) => void;
5448-
/**
5449-
* Exit a parse tree produced by `MySqlParser.createFunction`.
5450-
* @param ctx the parse tree
5451-
*/
5452-
exitCreateFunction?: (ctx: CreateFunctionContext) => void;
54535475
/**
54545476
* Enter a parse tree produced by `MySqlParser.installComponent`.
54555477
* @param ctx the parse tree

src/lib/mysql/MySqlParserVisitor.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { CreateEventContext } from "./MySqlParser.js";
2525
import { CreateIndexContext } from "./MySqlParser.js";
2626
import { CreateLogfileGroupContext } from "./MySqlParser.js";
2727
import { CreateProcedureContext } from "./MySqlParser.js";
28+
import { CreateFunctionContext } from "./MySqlParser.js";
29+
import { CreateFunctionLoadableContext } from "./MySqlParser.js";
2830
import { CreateRoleContext } from "./MySqlParser.js";
2931
import { CreateServerContext } from "./MySqlParser.js";
3032
import { QueryCreateTableContext } from "./MySqlParser.js";
@@ -49,6 +51,7 @@ import { EnableTypeContext } from "./MySqlParser.js";
4951
import { IndexTypeContext } from "./MySqlParser.js";
5052
import { IndexOptionContext } from "./MySqlParser.js";
5153
import { ProcedureParameterContext } from "./MySqlParser.js";
54+
import { FunctionParameterContext } from "./MySqlParser.js";
5255
import { RoutineCommentContext } from "./MySqlParser.js";
5356
import { RoutineLanguageContext } from "./MySqlParser.js";
5457
import { RoutineBehaviorContext } from "./MySqlParser.js";
@@ -444,7 +447,6 @@ import { OptimizeTableContext } from "./MySqlParser.js";
444447
import { RepairTableContext } from "./MySqlParser.js";
445448
import { TableActionOptionContext } from "./MySqlParser.js";
446449
import { CheckTableOptionContext } from "./MySqlParser.js";
447-
import { CreateFunctionContext } from "./MySqlParser.js";
448450
import { InstallComponentContext } from "./MySqlParser.js";
449451
import { VariableExprContext } from "./MySqlParser.js";
450452
import { UninstallComponentContext } from "./MySqlParser.js";
@@ -789,6 +791,18 @@ export class MySqlParserVisitor<Result> extends AbstractParseTreeVisitor<Result>
789791
* @return the visitor result
790792
*/
791793
visitCreateProcedure?: (ctx: CreateProcedureContext) => Result;
794+
/**
795+
* Visit a parse tree produced by `MySqlParser.createFunction`.
796+
* @param ctx the parse tree
797+
* @return the visitor result
798+
*/
799+
visitCreateFunction?: (ctx: CreateFunctionContext) => Result;
800+
/**
801+
* Visit a parse tree produced by `MySqlParser.createFunctionLoadable`.
802+
* @param ctx the parse tree
803+
* @return the visitor result
804+
*/
805+
visitCreateFunctionLoadable?: (ctx: CreateFunctionLoadableContext) => Result;
792806
/**
793807
* Visit a parse tree produced by `MySqlParser.createRole`.
794808
* @param ctx the parse tree
@@ -938,6 +952,12 @@ export class MySqlParserVisitor<Result> extends AbstractParseTreeVisitor<Result>
938952
* @return the visitor result
939953
*/
940954
visitProcedureParameter?: (ctx: ProcedureParameterContext) => Result;
955+
/**
956+
* Visit a parse tree produced by `MySqlParser.functionParameter`.
957+
* @param ctx the parse tree
958+
* @return the visitor result
959+
*/
960+
visitFunctionParameter?: (ctx: FunctionParameterContext) => Result;
941961
/**
942962
* Visit a parse tree produced by the `routineComment`
943963
* labeled alternative in `MySqlParser.routineOption`.
@@ -3501,12 +3521,6 @@ export class MySqlParserVisitor<Result> extends AbstractParseTreeVisitor<Result>
35013521
* @return the visitor result
35023522
*/
35033523
visitCheckTableOption?: (ctx: CheckTableOptionContext) => Result;
3504-
/**
3505-
* Visit a parse tree produced by `MySqlParser.createFunction`.
3506-
* @param ctx the parse tree
3507-
* @return the visitor result
3508-
*/
3509-
visitCreateFunction?: (ctx: CreateFunctionContext) => Result;
35103524
/**
35113525
* Visit a parse tree produced by `MySqlParser.installComponent`.
35123526
* @param ctx the parse tree

src/parser/mysql/mysqlEntityCollector.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
CopyCreateTableContext,
55
CreateDatabaseContext,
66
CreateFunctionContext,
7+
CreateFunctionLoadableContext,
78
CreateViewContext,
89
DatabaseNameContext,
910
DatabaseNameCreateContext,
@@ -143,4 +144,12 @@ export class MySqlEntityCollector extends EntityCollector implements MySqlParser
143144
exitCreateFunction(ctx: CreateFunctionContext) {
144145
this.popStmt();
145146
}
147+
148+
enterCreateFunctionLoadable(ctx: CreateFunctionLoadableContext) {
149+
this.pushStmt(ctx, StmtContextType.CREATE_FUNCTION_STMT);
150+
}
151+
152+
exitCreateFunctionLoadable(ctx: CreateFunctionLoadableContext) {
153+
this.popStmt();
154+
}
146155
}

test/parser/mysql/contextCollect/entityCollector.test.ts

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('MySQL entity collector tests', () => {
2020
});
2121

2222
test('split results', () => {
23-
expect(splitListener.statementsContext.length).toBe(15);
23+
expect(splitListener.statementsContext.length).toBe(16);
2424
});
2525

2626
test('create table by columns', () => {
@@ -468,21 +468,21 @@ describe('MySQL entity collector tests', () => {
468468
const functionEntity = allEntities[0];
469469

470470
expect(functionEntity.entityContextType).toBe(EntityContextType.FUNCTION_CREATE);
471-
expect(functionEntity.text).toBe('my_concat_ws');
471+
expect(functionEntity.text).toBe('hello');
472472
expect(functionEntity.position).toEqual({
473-
endColumn: 43,
474-
endIndex: 982,
473+
endColumn: 39,
474+
endIndex: 978,
475475
line: 39,
476-
startColumn: 31,
477-
startIndex: 971,
476+
startColumn: 34,
477+
startIndex: 974,
478478
});
479479

480480
expect(functionEntity.belongStmt.stmtContextType).toBe(
481481
StmtContextType.CREATE_FUNCTION_STMT
482482
);
483483
expect(functionEntity.belongStmt.position).toEqual({
484-
endColumn: 87,
485-
endIndex: 1026,
484+
endColumn: 114,
485+
endIndex: 1053,
486486
endLine: 39,
487487
startColumn: 1,
488488
startIndex: 941,
@@ -492,4 +492,42 @@ describe('MySQL entity collector tests', () => {
492492
expect(functionEntity.columns).toBeNull();
493493
expect(functionEntity.relatedEntities).toBeNull();
494494
});
495+
496+
test('create function loadable', () => {
497+
const functionCreateContext = splitListener.statementsContext[15];
498+
499+
const collectListener = new MySqlEntityCollector(commonSql);
500+
mysql.listen(collectListener as ParseTreeListener, functionCreateContext);
501+
502+
const allEntities = collectListener.getEntities();
503+
504+
expect(allEntities.length).toBe(1);
505+
506+
const functionEntity = allEntities[0];
507+
508+
expect(functionEntity.entityContextType).toBe(EntityContextType.FUNCTION_CREATE);
509+
expect(functionEntity.text).toBe('my_concat_ws');
510+
expect(functionEntity.position).toEqual({
511+
endColumn: 43,
512+
endIndex: 1098,
513+
line: 41,
514+
startColumn: 31,
515+
startIndex: 1087,
516+
});
517+
518+
expect(functionEntity.belongStmt.stmtContextType).toBe(
519+
StmtContextType.CREATE_FUNCTION_STMT
520+
);
521+
expect(functionEntity.belongStmt.position).toEqual({
522+
endColumn: 87,
523+
endIndex: 1142,
524+
endLine: 41,
525+
startColumn: 1,
526+
startIndex: 1057,
527+
startLine: 41,
528+
});
529+
530+
expect(functionEntity.columns).toBeNull();
531+
expect(functionEntity.relatedEntities).toBeNull();
532+
});
495533
});

test/parser/mysql/contextCollect/fixtures/common.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,6 @@ SHOW CREATE SCHEMA IF NOT EXISTS db_name;
3636

3737
DROP SCHEMA IF EXISTS db_name;
3838

39+
CREATE DEFINER = 'user' FUNCTION hello (s CHAR(20)) RETURNS CHAR(50) DETERMINISTIC RETURN CONCAT('Hello, ',s,'!');
40+
3941
CREATE FUNCTION IF NOT EXISTS my_concat_ws RETURNS STRING SONAME 'udf_my_concat_ws.so';

test/parser/mysql/suggestion/tokenSuggestion.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ describe('MySQL Token Suggestion', () => {
6060
'ALGORITHM',
6161
'OR',
6262
'TRIGGER',
63+
'IF',
6364
'TABLESPACE',
6465
'UNDO',
6566
'TABLE',

test/parser/mysql/syntax/fixtures/alterTable.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,6 @@ ALTER TABLE t1 ALTER COLUMN c1 DROP DEFAULT, DROP CONSTRAINT c2_positive, ALTER
102102
ALTER TABLE t1 ALTER COLUMN c1 DROP DEFAULT, DROP CONSTRAINT c2_positive, ALTER CHECK c2_positive NOT ENFORCED REBUILD PARTITION p0 REBUILD PARTITION ALL;
103103
ALTER TABLE t1 ALTER COLUMN c1 DROP DEFAULT, DROP CONSTRAINT c2_positive, ALTER CHECK c2_positive NOT ENFORCED REPAIR PARTITION p0 REPAIR PARTITION ALL;
104104
ALTER TABLE t1 ALTER COLUMN c1 SET VISIBLE, DROP CONSTRAINT c2_positive, ALTER CHECK c2_positive NOT ENFORCED REMOVE PARTITIONING UPGRADE PARTITIONING;
105+
106+
107+
ALTER TABLE `order` ADD cancelled TINYINT(1) DEFAULT 0 NOT NULL, ADD delivered TINYINT(1) DEFAULT 0 NOT NULL, ADD returning TINYINT(1) DEFAULT 0 NOT NULL;

0 commit comments

Comments
 (0)