[opt](plsql) Fix plsql exception and doris exception compatibility (#31647)
This commit is contained in:
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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());
|
||||
|
||||
Reference in New Issue
Block a user