[opt](plsql) Fix plsql exception and doris exception compatibility (#31647)

This commit is contained in:
Xinyi Zou
2024-03-01 18:44:23 +08:00
committed by yiguolei
parent 248ea20901
commit 38cb17567a
6 changed files with 84 additions and 59 deletions

View File

@ -20,6 +20,8 @@
package org.apache.doris.plsql;
import org.apache.doris.common.ErrorCode;
public interface Console {
void print(String msg);
@ -27,7 +29,7 @@ public interface Console {
void printError(String msg);
void flushConsole();
void printError(ErrorCode errorCode, String msg);
Console STANDARD = new Console() {
@Override
@ -46,6 +48,8 @@ public interface Console {
}
@Override
public void flushConsole() {}
public void printError(ErrorCode errorCode, String msg) {
System.err.println(errorCode.toString() + ", " + msg);
}
};
}

View File

@ -20,6 +20,7 @@
package org.apache.doris.plsql;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.nereids.PLLexer;
import org.apache.doris.nereids.PLParser;
import org.apache.doris.nereids.PLParser.Allocate_cursor_stmtContext;
@ -150,6 +151,8 @@ import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
@ -176,6 +179,7 @@ import java.util.stream.Collectors;
* PL/SQL script executor
*/
public class Exec extends org.apache.doris.nereids.PLParserBaseVisitor<Integer> implements Closeable {
private static final Logger LOG = LogManager.getLogger(Exec.class);
public static final String VERSION = "PL/SQL 0.1";
public static final String ERRORCODE = "ERRORCODE";
@ -839,6 +843,8 @@ public class Exec extends org.apache.doris.nereids.PLParserBaseVisitor<Integer>
init();
try {
parseAndEval(arguments);
} catch (Exception e) {
exec.signal(e);
} finally {
close();
}
@ -901,8 +907,6 @@ public class Exec extends org.apache.doris.nereids.PLParserBaseVisitor<Integer>
*/
public void init() {
enterGlobalScope();
// specify the default log4j2 properties file.
System.setProperty("log4j.configurationFile", "hive-log4j2.properties");
if (conf == null) {
conf = new Conf();
}
@ -944,7 +948,7 @@ public class Exec extends org.apache.doris.nereids.PLParserBaseVisitor<Integer>
PLParser parser = newParser(tokens);
ParseTree tree = parser.program();
if (trace) {
console.printError("Parser tree: " + tree.toStringTree(parser));
console.printLine("Parser tree: " + tree.toStringTree(parser));
}
return tree;
}
@ -978,7 +982,7 @@ public class Exec extends org.apache.doris.nereids.PLParserBaseVisitor<Integer>
boolean parseArguments(String[] args) {
boolean parsed = arguments.parse(args);
if (parsed && arguments.hasVersionOption()) {
console.printError(VERSION);
console.printLine(VERSION);
return false;
}
if (!parsed || arguments.hasHelpOption()
@ -1092,13 +1096,24 @@ public class Exec extends org.apache.doris.nereids.PLParserBaseVisitor<Integer>
if (sig.type == Signal.Type.VALIDATION) {
error(((PlValidationException) sig.exception).getCtx(), sig.exception.getMessage());
} else if (sig.type == Signal.Type.SQLEXCEPTION) {
console.printError("Unhandled exception in PL/SQL. " + ExceptionUtils.getStackTrace(sig.exception));
LOG.warn(ExceptionUtils.getStackTrace(sig.exception));
console.printError(ErrorCode.ERR_SP_BAD_SQLSTATE,
"Unhandled exception in PL/SQL. " + sig.exception.toString());
} else if (sig.type == Signal.Type.UNSUPPORTED_OPERATION) {
console.printError(sig.value == null ? "Unsupported operation" : sig.value);
console.printError(ErrorCode.ERR_SP_BAD_SQLSTATE,
sig.value == null ? "Unsupported operation" : sig.value);
} else if (sig.type == Signal.Type.TOO_MANY_ROWS) {
console.printError(ErrorCode.ERR_SP_BAD_SQLSTATE,
sig.value == null ? "Too many rows exception" : sig.value);
} else if (sig.type == Signal.Type.NOTFOUND) {
console.printError(ErrorCode.ERR_SP_FETCH_NO_DATA,
sig.value == null ? "Not found data exception" : sig.value);
} else if (sig.exception != null) {
console.printError("HPL/SQL error: " + ExceptionUtils.getStackTrace(sig.exception));
LOG.warn(ExceptionUtils.getStackTrace(sig.exception));
console.printError(ErrorCode.ERR_SP_BAD_SQLSTATE,
"PL/SQL error: " + sig.exception.toString());
} else if (sig.value != null) {
console.printError(sig.value);
console.printError(ErrorCode.ERR_SP_BAD_SQLSTATE, sig.value);
} else {
trace(null, "Signal: " + sig.type);
}
@ -1156,14 +1171,9 @@ public class Exec extends org.apache.doris.nereids.PLParserBaseVisitor<Integer>
@Override
public Integer visitDoris_statement(Doris_statementContext ctx) {
Integer rc = exec.stmt.statement(ctx);
if (rc != 0) {
printExceptions();
throw new RuntimeException(exec.signalPeek().getValue());
}
// Sometimes the query results are not returned to the mysql client,
// such as declare result; select … into result;
// such as `declare result; select … into result;`, not need finalize.
resultListener.onFinalize();
console.flushConsole(); // if running from plsql.sh
return rc;
}
@ -1793,6 +1803,8 @@ public class Exec extends org.apache.doris.nereids.PLParserBaseVisitor<Integer>
} else if (ctx.multipartIdentifier() != null) {
functionCall(ctx, ctx.multipartIdentifier(), null);
}
} catch (Exception e) {
exec.signal(e);
} finally {
exec.inCallStmt = false;
}
@ -2379,9 +2391,9 @@ public class Exec extends org.apache.doris.nereids.PLParserBaseVisitor<Integer>
return;
}
if (ctx != null) {
console.printError("Ln:" + ctx.getStart().getLine() + " " + message);
console.printLine("Ln:" + ctx.getStart().getLine() + " " + message);
} else {
console.printError(message);
console.printLine(message);
}
}

View File

@ -134,11 +134,11 @@ public class Stmt {
exec.setSqlSuccess();
if (query.next()) {
exec.setSqlCode(SqlCodes.TOO_MANY_ROWS);
exec.signal(Signal.Type.TOO_MANY_ROWS);
exec.signal(Signal.Type.TOO_MANY_ROWS, "too many rows into variables");
}
} else {
exec.setSqlCode(SqlCodes.NO_DATA_FOUND);
exec.signal(Signal.Type.NOTFOUND);
exec.signal(Signal.Type.NOTFOUND, "no rows into variables");
}
} else if (ctx instanceof Doris_statementContext) { // only from visitStatement
// Print all results for standalone Statement.
@ -406,7 +406,7 @@ public class Stmt {
return 1;
} else if (exec.getOffline()) {
exec.setSqlCode(SqlCodes.NO_DATA_FOUND);
exec.signal(Signal.Type.NOTFOUND);
exec.signal(Signal.Type.NOTFOUND, "fetch not found data");
return 0;
}
// Assign values from the row to local variables
@ -590,7 +590,7 @@ public class Stmt {
exec.setSqlSuccess();
} else {
exec.setSqlCode(SqlCodes.NO_DATA_FOUND);
exec.signal(Signal.Type.NOTFOUND);
exec.signal(Signal.Type.NOTFOUND, "assign from select not found data");
}
} catch (QueryException | AnalysisException e) {
exec.signal(query);

View File

@ -44,30 +44,34 @@ public class PlSqlOperation {
}
public void execute(ConnectContext ctx, String statement) {
ctx.setRunProcedure(true);
ctx.setProcedureExec(exec);
result.reset();
try {
Arguments args = new Arguments();
args.parse(new String[] { "-e", statement });
exec.parseAndEval(args);
// Exception is not thrown after catch.
// For example, select a not exist table will return empty results, exception
// will put into signals.
exec.printExceptions();
String error = result.getError();
String msg = result.getMsg();
if (!error.isEmpty()) {
ctx.getState().setError("plsql exec error, " + error);
} else if (!msg.isEmpty()) {
ctx.getState().setOk(0, 0, msg);
ctx.setRunProcedure(true);
ctx.setProcedureExec(exec);
result.reset();
try {
Arguments args = new Arguments();
args.parse(new String[] {"-e", statement});
exec.parseAndEval(args);
} catch (Exception e) {
exec.signal(e);
} finally {
// Exception is not thrown after catch.
// For example, select a not exist table will return empty results, exception
// will put into signals.
exec.printExceptions();
String error = result.getError();
String msg = result.getMsg();
if (!error.isEmpty()) {
ctx.getState().setError(result.getLastErrorCode(), error);
} else if (!msg.isEmpty()) {
ctx.getState().setOk(0, 0, msg);
}
ctx.getMysqlChannel().reset();
ctx.setRunProcedure(false);
ctx.setProcedureExec(null);
}
ctx.getMysqlChannel().reset();
ctx.setRunProcedure(false);
ctx.setProcedureExec(null);
} catch (Exception e) {
exec.printExceptions();
ctx.getState().setError(ErrorCode.ERR_UNKNOWN_ERROR, result.getError() + " " + e.getMessage());
ctx.getState().setError(ErrorCode.ERR_UNKNOWN_ERROR, e.getMessage());
LOG.warn(e);
}
}

View File

@ -17,6 +17,7 @@
package org.apache.doris.plsql.executor;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.mysql.MysqlEofPacket;
import org.apache.doris.mysql.MysqlSerializer;
import org.apache.doris.mysql.MysqlServerStatusFlag;
@ -27,11 +28,13 @@ import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ConnectProcessor;
import org.apache.doris.qe.QueryState;
import com.google.common.collect.Lists;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
// If running from mysql client, first send schema column,
// and then send the ByteBuffer through the mysql channel.
@ -44,12 +47,14 @@ public class PlsqlResult implements ResultListener, Console {
private Metadata metadata = null;
private StringBuilder msg;
private StringBuilder error;
private List<ErrorCode> errorCodes;
private boolean isSendFields;
public PlsqlResult() {
this.msg = new StringBuilder();
this.error = new StringBuilder();
this.isSendFields = false;
this.errorCodes = Lists.newArrayList();
}
public void reset() {
@ -58,6 +63,7 @@ public class PlsqlResult implements ResultListener, Console {
isSendFields = false;
error.delete(0, error.length());
msg.delete(0, msg.length());
errorCodes.clear();
}
public void setProcessor(ConnectProcessor processor) {
@ -72,6 +78,14 @@ public class PlsqlResult implements ResultListener, Console {
return error.toString();
}
public List<ErrorCode> getErrorCodes() {
return errorCodes;
}
public ErrorCode getLastErrorCode() {
return errorCodes.isEmpty() ? ErrorCode.ERR_UNKNOWN_ERROR : errorCodes.get(errorCodes.size() - 1);
}
@Override
public void onMysqlRow(ByteBuffer rows) {
ConnectContext ctx = processor != null ? processor.getConnectContext() : ConnectContext.get();
@ -106,6 +120,7 @@ public class PlsqlResult implements ResultListener, Console {
@Override
public void onFinalize() {
// If metadata not null, it means that mysql channel sent query results.
if (metadata == null) {
return;
}
@ -166,24 +181,14 @@ public class PlsqlResult implements ResultListener, Console {
@Override
public void printError(String msg) {
this.error.append(msg);
errorCodes.add(ErrorCode.ERR_UNKNOWN_ERROR);
this.error.append("\n" + errorCodes.size() + ". " + getLastErrorCode().toString() + ", " + msg);
}
@Override
public void flushConsole() {
ConnectContext ctx = processor != null ? processor.getConnectContext() : ConnectContext.get();
boolean needSend = false;
if (error.length() > 0) {
ctx.getState().setError("hplsql exec error, " + error.toString());
needSend = true;
} else if (msg.length() > 0) {
ctx.getState().setOk(0, 0, msg.toString());
needSend = true;
}
if (needSend) {
finalizeCommand();
reset();
}
public void printError(ErrorCode errorCode, String msg) {
errorCodes.add(errorCode != null ? errorCode : ErrorCode.ERR_UNKNOWN_ERROR);
this.error.append("\n" + errorCodes.size() + ". " + getLastErrorCode().toString() + ", " + msg);
}
private void finalizeCommand() {

View File

@ -153,7 +153,7 @@ public class MysqlConnectProcessor extends ConnectProcessor {
}
} catch (Throwable e) {
// Catch all throwable.
// If reach here, maybe palo bug.
// If reach here, maybe doris bug.
LOG.warn("Process one query failed because unknown reason: ", e);
ctx.getState().setError(ErrorCode.ERR_UNKNOWN_ERROR,
e.getClass().getSimpleName() + ", msg: " + e.getMessage());