#6705·druid

MySQL: simple-form CREATE FUNCTION (RETURN expr without BEGIN...END) breaks subsequent statements in multi-statement script

Author: leungjunCreated Aug 10, 2026Updated Aug 10, 2026

Describe the bug When a MySQL script contains a simple-form CREATE FUNCTION (body is a single RETURN expr; without BEGIN...END) followed by other statements, SQLUtils.parseStatements(sql, "mysql") throws ParserException: syntax error ... token SELECT. BEGIN...END bodies work fine. Affects all tested versions 1.2.14 ~ 1.2.28 (latest).

To Reproduce

java
List<SQLStatement> stmts = SQLUtils.parseStatements(
        "CREATE FUNCTION f() RETURNS INT RETURN 1;\nSELECT 1;", "mysql");
// ParserException: syntax error. pos 36, line 2, column 2, token SELECT

CREATE FUNCTION ... RETURN 1; followed by another CREATE FUNCTION passes on 1.2.14 but also fails on 1.2.27/1.2.28 (not supported ... token CREATE), because only case SELECT (and now case CREATE) guards on the semi flag.

Expected behavior The script parses into 2 statements: SQLCreateFunctionStatement + SQLSelectStatement.

Root cause SQLStatementParser.parseReturn() consumes the terminating SEMI itself (accept(Token.SEMI) + setAfterSemi). Back in parseStatementList, the local semi flag therefore stays false, and the case SELECT branch's guard i > 0 && dbType != odps && !semi wrongly throws for the next statement. case CREATE has no such guard on 1.2.14, which is why function + function accidentally passes there.

Suggested fix Let parseReturn() not consume the SEMI; leave statement-terminating semicolons to the SEMI branch of parseStatementList, which sets semi = true and afterSemi uniformly:

java
public SQLStatement parseReturn() {
    if (lexer.token == Token.RETURN || lexer.identifierEquals("RETURN")) {
        lexer.nextToken();
    }
    SQLReturnStatement stmt = new SQLReturnStatement();
    if (lexer.token != Token.SEMI) {
        stmt.setExpr(this.exprParser.expr());
    }
    return stmt; // do NOT accept(SEMI) here
}

We verified this change locally (via a MySqlStatementParser subclass): function+SELECT, function+function, BEGIN...END+SELECT, and mixed scripts all parse correctly.