morningman commented on issue #67369: URL: https://github.com/apache/doris/issues/67369#issuecomment-5535127022
### Scope: this only affects `branch-4.0`, `branch-4.1` and `branch-3.1`. Not reproducible on master. PL/SQL was removed from master by #58700 (`ec4014ec268`, 2025-12-08), which deleted the whole `org.apache.doris.plsql` package, the `PLLexer.g4` / `PLParser.g4` grammars, `CallProcedure`, and the `CREATE|DROP|SHOW CREATE PROCEDURE` grammar rules. `branch-4.0`, `branch-4.1` and `branch-3.1` still carry that code, so the bug lives only there. **Verified on a master build (both protocols, MySQL on 9033 and Arrow Flight SQL on 8077):** | statement | MySQL | Arrow Flight SQL | |---|---|---| | `CREATE [OR REPLACE] PROCEDURE ...` | `errCode = 2, no viable alternative at input 'CREATE OR REPLACE PROCEDURE'(line 1, pos 18)` | same syntax error, wrapped in `get flight info statement failed` | | `DROP PROCEDURE ...` | `no viable alternative at input 'DROP PROCEDURE'` | same | | `SHOW CREATE PROCEDURE ...` | `no viable alternative at input 'SHOW CREATE PROCEDURE'` | same | | `CALL p(444,'x')` | `do not support call function P` | same, **no side effect** | | `SHOW PROCEDURE STATUS` / `SHOW FUNCTION STATUS` | empty result set | empty result set | | `SELECT * FROM information_schema.routines` | 0 rows | 0 rows | The last two rows are the deliberate compatibility shims restored by #66659 — the SQL entry points parse and return empty, the stored-procedure functionality itself stays removed. On master `CALL` only accepts the built-ins `EXECUTE_STMT` and `FLUSH_AUDIT_LOG`; anything else is rejected in `CallFunc.getFunc()` **before** anything is executed, so no DML can be duplicated. ### Root cause on 4.x `PlSqlOperation.execute()` ends with an unconditional ```java ctx.getMysqlChannel().reset(); ``` in its `finally` block, and `FlightSqlConnectContext.getMysqlChannel()` throws `getMysqlChannel not in mysql connection`. The `INSERT` has already run by then, the throw is swallowed into an ERR state, `executeQueryStatement` turns that into `after executeQueryStatement handleQuery`, and the client sees `INTERNAL` — which matches the report exactly: **the error is raised after the side effect**. The deeper reason is that PL/SQL assumes a MySQL channel throughout: `PlsqlQueryExecutor.executeQuery()` runs every inner statement through `ConnectContext.get().cloneContext()`, and `cloneContext()` builds a plain `ConnectContext` (`connectType = MYSQL`) while copying `mysqlChannel` — which is `null` on a Flight SQL connection. ### About "four times" I could not find a server-side loop that would execute the body four times: `getFlightInfoStatement` executes the statement once per `GetFlightInfo`; `StmtExecutor.queryRetry()` only retries the three `SystemInfoService.NEED_REPLAN_ERRORS` messages; `handleQueryWithRetry()` additionally requires `RpcException` **and** `ConnectType.MYSQL`; and the `retryTimes` loop in `InsertIntoTableCommand.initPlan()` only re-plans before the transaction begins. If anyone reproduces this on 4.x, `fe.audit.log` settles it: four `CALL` entries means the client retried `GetFlightInfo`, while one `CALL` plus four `INSERT`s would mean a server-side loop. ### Next step A guard for `branch-4.1` is on the way: reject `CALL <procedure>` on a non-MySQL connection in `CallProcedure.create()`, i.e. **before** `exec.parseAndEval()` runs, so the statement fails cleanly with no side effect. `branch-4.0` / `branch-3.1` can take the same cherry-pick. /cc — please set the affected-version labels (4.0 / 4.1 / 3.1) and drop any `master` label. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
