Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ coverage
.idea
gen/
src/**/*.iml
benchmark/reports/*
benchmark/reports/*
*.tgz
47 changes: 24 additions & 23 deletions src/grammar/mysql/MySqlParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ ddlStatement
| createLogfileGroup
| createProcedure
| createFunction
| createFunctionLoadable
| createServer
| createTable
| createTablespaceInnodb
Expand Down Expand Up @@ -266,6 +267,22 @@ createProcedure
)* ')' routineOption* routineBody
;

createFunction
: KW_CREATE ownerStatement? KW_AGGREGATE? KW_FUNCTION ifNotExists? functionNameCreate '(' functionParameter? (
',' functionParameter
)* ')' KW_RETURNS dataType routineOption* (routineBody | returnStatement)
;

// https://dev.mysql.com/doc/refman/8.0/en/create-function-loadable.html
createFunctionLoadable
: KW_CREATE KW_AGGREGATE? KW_FUNCTION ifNotExists? functionNameCreate KW_RETURNS returnType=(
KW_STRING
| KW_INTEGER
| KW_REAL
| KW_DECIMAL
) KW_SONAME STRING_LITERAL
;

createRole
: KW_CREATE KW_ROLE ifNotExists? userOrRoleNames
;
Expand Down Expand Up @@ -310,7 +327,7 @@ createTablespaceNdb
;

createTrigger
: KW_CREATE ownerStatement? KW_TRIGGER ifNotExists? trigger_name=fullId triggerTime=(
: KW_CREATE ownerStatement? ifNotExists? KW_TRIGGER ifNotExists? trigger_name=fullId triggerTime=(
KW_BEFORE
| KW_AFTER
) triggerEvent=(KW_INSERT | KW_UPDATE | KW_DELETE) KW_ON tableName KW_FOR KW_EACH KW_ROW (
Expand Down Expand Up @@ -420,6 +437,10 @@ procedureParameter
: direction=(KW_IN | KW_OUT | KW_INOUT)? paramName=uid dataType
;

functionParameter
: paramName=uid dataType
;

routineOption
: KW_COMMENT STRING_LITERAL # routineComment
| KW_LANGUAGE KW_SQL # routineLanguage
Expand Down Expand Up @@ -907,19 +928,6 @@ replaceStatement
)? (('(' columnNames ')')? replaceStatementValuesOrSelectOrTable | setAssignmentList)
;

// selectStatement
// : querySpecification lockClause? # simpleSelect
// | querySpecificationNointo lockClause? intoClause? # simpleSelect
// | queryExpression lockClause? # parenthesisSelect
// | querySpecificationNointo unionStatement+ (
// KW_UNION unionType=(KW_ALL | KW_DISTINCT)? (querySpecification | queryExpression)
// )? orderByClause? limitClause? lockClause? # unionSelect
// | queryExpressionNointo unionParenthesis+ (
// KW_UNION unionType=(KW_ALL | KW_DISTINCT)? queryExpression
// )? orderByClause? limitClause? lockClause? # unionParenthesisSelect
// | querySpecificationNointo (',' lateralStatement)+ # withLateralStatement
// ;

// TODO: Simplify the rules to fit SLL(*) Mode
selectStatement
: querySpecification unionStatement* (
Expand Down Expand Up @@ -1127,6 +1135,7 @@ queryExpression
*/
querySpecification
: KW_SELECT selectSpec* selectElements intoClause? fromClause groupByClause? havingClause? windowClause? orderByClause? limitClause? intoClause?
unionStatement?
;

unionStatement
Expand Down Expand Up @@ -1996,15 +2005,6 @@ checkTableOption
| KW_CHANGED
;

createFunction
: KW_CREATE KW_AGGREGATE? KW_FUNCTION ifNotExists? functionNameCreate KW_RETURNS returnType=(
KW_STRING
| KW_INTEGER
| KW_REAL
| KW_DECIMAL
) KW_SONAME STRING_LITERAL
;

installComponent
: KW_INSTALL KW_COMPONENT component_name=uid (',' component_name=uid)* (
KW_SET variableExpr (',' variableExpr)*
Expand Down Expand Up @@ -3421,6 +3421,7 @@ keywordsCanBeId
| KW_RESOURCE_GROUP_USER
| KW_RESUME
| KW_RETURNED_SQLSTATE
| KW_RETURNING
| KW_RETURNS
| KW_REUSE
| KW_ROLE
Expand Down
6 changes: 4 additions & 2 deletions src/lib/mysql/MySqlParser.interp

Large diffs are not rendered by default.

21,948 changes: 11,453 additions & 10,495 deletions src/lib/mysql/MySqlParser.ts

Large diffs are not rendered by default.

44 changes: 33 additions & 11 deletions src/lib/mysql/MySqlParserListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { CreateEventContext } from "./MySqlParser.js";
import { CreateIndexContext } from "./MySqlParser.js";
import { CreateLogfileGroupContext } from "./MySqlParser.js";
import { CreateProcedureContext } from "./MySqlParser.js";
import { CreateFunctionContext } from "./MySqlParser.js";
import { CreateFunctionLoadableContext } from "./MySqlParser.js";
import { CreateRoleContext } from "./MySqlParser.js";
import { CreateServerContext } from "./MySqlParser.js";
import { QueryCreateTableContext } from "./MySqlParser.js";
Expand All @@ -49,6 +51,7 @@ import { EnableTypeContext } from "./MySqlParser.js";
import { IndexTypeContext } from "./MySqlParser.js";
import { IndexOptionContext } from "./MySqlParser.js";
import { ProcedureParameterContext } from "./MySqlParser.js";
import { FunctionParameterContext } from "./MySqlParser.js";
import { RoutineCommentContext } from "./MySqlParser.js";
import { RoutineLanguageContext } from "./MySqlParser.js";
import { RoutineBehaviorContext } from "./MySqlParser.js";
Expand Down Expand Up @@ -444,7 +447,6 @@ import { OptimizeTableContext } from "./MySqlParser.js";
import { RepairTableContext } from "./MySqlParser.js";
import { TableActionOptionContext } from "./MySqlParser.js";
import { CheckTableOptionContext } from "./MySqlParser.js";
import { CreateFunctionContext } from "./MySqlParser.js";
import { InstallComponentContext } from "./MySqlParser.js";
import { VariableExprContext } from "./MySqlParser.js";
import { UninstallComponentContext } from "./MySqlParser.js";
Expand Down Expand Up @@ -854,6 +856,26 @@ export class MySqlParserListener implements ParseTreeListener {
* @param ctx the parse tree
*/
exitCreateProcedure?: (ctx: CreateProcedureContext) => void;
/**
* Enter a parse tree produced by `MySqlParser.createFunction`.
* @param ctx the parse tree
*/
enterCreateFunction?: (ctx: CreateFunctionContext) => void;
/**
* Exit a parse tree produced by `MySqlParser.createFunction`.
* @param ctx the parse tree
*/
exitCreateFunction?: (ctx: CreateFunctionContext) => void;
/**
* Enter a parse tree produced by `MySqlParser.createFunctionLoadable`.
* @param ctx the parse tree
*/
enterCreateFunctionLoadable?: (ctx: CreateFunctionLoadableContext) => void;
/**
* Exit a parse tree produced by `MySqlParser.createFunctionLoadable`.
* @param ctx the parse tree
*/
exitCreateFunctionLoadable?: (ctx: CreateFunctionLoadableContext) => void;
/**
* Enter a parse tree produced by `MySqlParser.createRole`.
* @param ctx the parse tree
Expand Down Expand Up @@ -1104,6 +1126,16 @@ export class MySqlParserListener implements ParseTreeListener {
* @param ctx the parse tree
*/
exitProcedureParameter?: (ctx: ProcedureParameterContext) => void;
/**
* Enter a parse tree produced by `MySqlParser.functionParameter`.
* @param ctx the parse tree
*/
enterFunctionParameter?: (ctx: FunctionParameterContext) => void;
/**
* Exit a parse tree produced by `MySqlParser.functionParameter`.
* @param ctx the parse tree
*/
exitFunctionParameter?: (ctx: FunctionParameterContext) => void;
/**
* Enter a parse tree produced by the `routineComment`
* labeled alternative in `MySqlParser.routineOption`.
Expand Down Expand Up @@ -5440,16 +5472,6 @@ export class MySqlParserListener implements ParseTreeListener {
* @param ctx the parse tree
*/
exitCheckTableOption?: (ctx: CheckTableOptionContext) => void;
/**
* Enter a parse tree produced by `MySqlParser.createFunction`.
* @param ctx the parse tree
*/
enterCreateFunction?: (ctx: CreateFunctionContext) => void;
/**
* Exit a parse tree produced by `MySqlParser.createFunction`.
* @param ctx the parse tree
*/
exitCreateFunction?: (ctx: CreateFunctionContext) => void;
/**
* Enter a parse tree produced by `MySqlParser.installComponent`.
* @param ctx the parse tree
Expand Down
28 changes: 21 additions & 7 deletions src/lib/mysql/MySqlParserVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { CreateEventContext } from "./MySqlParser.js";
import { CreateIndexContext } from "./MySqlParser.js";
import { CreateLogfileGroupContext } from "./MySqlParser.js";
import { CreateProcedureContext } from "./MySqlParser.js";
import { CreateFunctionContext } from "./MySqlParser.js";
import { CreateFunctionLoadableContext } from "./MySqlParser.js";
import { CreateRoleContext } from "./MySqlParser.js";
import { CreateServerContext } from "./MySqlParser.js";
import { QueryCreateTableContext } from "./MySqlParser.js";
Expand All @@ -49,6 +51,7 @@ import { EnableTypeContext } from "./MySqlParser.js";
import { IndexTypeContext } from "./MySqlParser.js";
import { IndexOptionContext } from "./MySqlParser.js";
import { ProcedureParameterContext } from "./MySqlParser.js";
import { FunctionParameterContext } from "./MySqlParser.js";
import { RoutineCommentContext } from "./MySqlParser.js";
import { RoutineLanguageContext } from "./MySqlParser.js";
import { RoutineBehaviorContext } from "./MySqlParser.js";
Expand Down Expand Up @@ -444,7 +447,6 @@ import { OptimizeTableContext } from "./MySqlParser.js";
import { RepairTableContext } from "./MySqlParser.js";
import { TableActionOptionContext } from "./MySqlParser.js";
import { CheckTableOptionContext } from "./MySqlParser.js";
import { CreateFunctionContext } from "./MySqlParser.js";
import { InstallComponentContext } from "./MySqlParser.js";
import { VariableExprContext } from "./MySqlParser.js";
import { UninstallComponentContext } from "./MySqlParser.js";
Expand Down Expand Up @@ -789,6 +791,18 @@ export class MySqlParserVisitor<Result> extends AbstractParseTreeVisitor<Result>
* @return the visitor result
*/
visitCreateProcedure?: (ctx: CreateProcedureContext) => Result;
/**
* Visit a parse tree produced by `MySqlParser.createFunction`.
* @param ctx the parse tree
* @return the visitor result
*/
visitCreateFunction?: (ctx: CreateFunctionContext) => Result;
/**
* Visit a parse tree produced by `MySqlParser.createFunctionLoadable`.
* @param ctx the parse tree
* @return the visitor result
*/
visitCreateFunctionLoadable?: (ctx: CreateFunctionLoadableContext) => Result;
/**
* Visit a parse tree produced by `MySqlParser.createRole`.
* @param ctx the parse tree
Expand Down Expand Up @@ -938,6 +952,12 @@ export class MySqlParserVisitor<Result> extends AbstractParseTreeVisitor<Result>
* @return the visitor result
*/
visitProcedureParameter?: (ctx: ProcedureParameterContext) => Result;
/**
* Visit a parse tree produced by `MySqlParser.functionParameter`.
* @param ctx the parse tree
* @return the visitor result
*/
visitFunctionParameter?: (ctx: FunctionParameterContext) => Result;
/**
* Visit a parse tree produced by the `routineComment`
* labeled alternative in `MySqlParser.routineOption`.
Expand Down Expand Up @@ -3501,12 +3521,6 @@ export class MySqlParserVisitor<Result> extends AbstractParseTreeVisitor<Result>
* @return the visitor result
*/
visitCheckTableOption?: (ctx: CheckTableOptionContext) => Result;
/**
* Visit a parse tree produced by `MySqlParser.createFunction`.
* @param ctx the parse tree
* @return the visitor result
*/
visitCreateFunction?: (ctx: CreateFunctionContext) => Result;
/**
* Visit a parse tree produced by `MySqlParser.installComponent`.
* @param ctx the parse tree
Expand Down
9 changes: 9 additions & 0 deletions src/parser/mysql/mysqlEntityCollector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
CopyCreateTableContext,
CreateDatabaseContext,
CreateFunctionContext,
CreateFunctionLoadableContext,
CreateViewContext,
DatabaseNameContext,
DatabaseNameCreateContext,
Expand Down Expand Up @@ -143,4 +144,12 @@ export class MySqlEntityCollector extends EntityCollector implements MySqlParser
exitCreateFunction(ctx: CreateFunctionContext) {
this.popStmt();
}

enterCreateFunctionLoadable(ctx: CreateFunctionLoadableContext) {
this.pushStmt(ctx, StmtContextType.CREATE_FUNCTION_STMT);
}

exitCreateFunctionLoadable(ctx: CreateFunctionLoadableContext) {
this.popStmt();
}
}
54 changes: 46 additions & 8 deletions test/parser/mysql/contextCollect/entityCollector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('MySQL entity collector tests', () => {
});

test('split results', () => {
expect(splitListener.statementsContext.length).toBe(15);
expect(splitListener.statementsContext.length).toBe(16);
});

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

expect(functionEntity.entityContextType).toBe(EntityContextType.FUNCTION_CREATE);
expect(functionEntity.text).toBe('my_concat_ws');
expect(functionEntity.text).toBe('hello');
expect(functionEntity.position).toEqual({
endColumn: 43,
endIndex: 982,
endColumn: 39,
endIndex: 978,
line: 39,
startColumn: 31,
startIndex: 971,
startColumn: 34,
startIndex: 974,
});

expect(functionEntity.belongStmt.stmtContextType).toBe(
StmtContextType.CREATE_FUNCTION_STMT
);
expect(functionEntity.belongStmt.position).toEqual({
endColumn: 87,
endIndex: 1026,
endColumn: 114,
endIndex: 1053,
endLine: 39,
startColumn: 1,
startIndex: 941,
Expand All @@ -492,4 +492,42 @@ describe('MySQL entity collector tests', () => {
expect(functionEntity.columns).toBeNull();
expect(functionEntity.relatedEntities).toBeNull();
});

test('create function loadable', () => {
const functionCreateContext = splitListener.statementsContext[15];

const collectListener = new MySqlEntityCollector(commonSql);
mysql.listen(collectListener as ParseTreeListener, functionCreateContext);

const allEntities = collectListener.getEntities();

expect(allEntities.length).toBe(1);

const functionEntity = allEntities[0];

expect(functionEntity.entityContextType).toBe(EntityContextType.FUNCTION_CREATE);
expect(functionEntity.text).toBe('my_concat_ws');
expect(functionEntity.position).toEqual({
endColumn: 43,
endIndex: 1098,
line: 41,
startColumn: 31,
startIndex: 1087,
});

expect(functionEntity.belongStmt.stmtContextType).toBe(
StmtContextType.CREATE_FUNCTION_STMT
);
expect(functionEntity.belongStmt.position).toEqual({
endColumn: 87,
endIndex: 1142,
endLine: 41,
startColumn: 1,
startIndex: 1057,
startLine: 41,
});

expect(functionEntity.columns).toBeNull();
expect(functionEntity.relatedEntities).toBeNull();
});
});
2 changes: 2 additions & 0 deletions test/parser/mysql/contextCollect/fixtures/common.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ SHOW CREATE SCHEMA IF NOT EXISTS db_name;

DROP SCHEMA IF EXISTS db_name;

CREATE DEFINER = 'user' FUNCTION hello (s CHAR(20)) RETURNS CHAR(50) DETERMINISTIC RETURN CONCAT('Hello, ',s,'!');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里是否应该将SONAME string和RETURN的两种sql都保留作为测试?


CREATE FUNCTION IF NOT EXISTS my_concat_ws RETURNS STRING SONAME 'udf_my_concat_ws.so';
1 change: 1 addition & 0 deletions test/parser/mysql/suggestion/tokenSuggestion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ describe('MySQL Token Suggestion', () => {
'ALGORITHM',
'OR',
'TRIGGER',
'IF',
'TABLESPACE',
'UNDO',
'TABLE',
Expand Down
3 changes: 3 additions & 0 deletions test/parser/mysql/syntax/fixtures/alterTable.sql
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ ALTER TABLE t1 ALTER COLUMN c1 DROP DEFAULT, DROP CONSTRAINT c2_positive, ALTER
ALTER TABLE t1 ALTER COLUMN c1 DROP DEFAULT, DROP CONSTRAINT c2_positive, ALTER CHECK c2_positive NOT ENFORCED REBUILD PARTITION p0 REBUILD PARTITION ALL;
ALTER TABLE t1 ALTER COLUMN c1 DROP DEFAULT, DROP CONSTRAINT c2_positive, ALTER CHECK c2_positive NOT ENFORCED REPAIR PARTITION p0 REPAIR PARTITION ALL;
ALTER TABLE t1 ALTER COLUMN c1 SET VISIBLE, DROP CONSTRAINT c2_positive, ALTER CHECK c2_positive NOT ENFORCED REMOVE PARTITIONING UPGRADE PARTITIONING;


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;
Loading
Loading