add exception

This commit is contained in:
XudongXie 2024-09-16 16:19:26 +08:00
parent 565851cb6c
commit a4c7aa2acf
5 changed files with 192 additions and 30 deletions

View File

@ -4,9 +4,12 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add exception classes">
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="revise">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Document/Exception in Oracle" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Document/Exception in Oracle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Generator/OpenGaussGenerator.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Generator/OpenGaussGenerator.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Lexer/OracleLexer.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Lexer/OracleLexer.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Main.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/OracleParser.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/OracleParser.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -104,13 +107,6 @@
<option name="presentableId" value="Default" />
<updated>1723106789329</updated>
</task>
<task id="LOCAL-00028" summary="revise">
<created>1725958136981</created>
<option name="number" value="00028" />
<option name="presentableId" value="LOCAL-00028" />
<option name="project" value="LOCAL" />
<updated>1725958136981</updated>
</task>
<task id="LOCAL-00029" summary="revise">
<created>1725978582486</created>
<option name="number" value="00029" />
@ -447,7 +443,14 @@
<option name="project" value="LOCAL" />
<updated>1726471382852</updated>
</task>
<option name="localTasksCounter" value="77" />
<task id="LOCAL-00077" summary="revise">
<created>1726472321577</created>
<option name="number" value="00077" />
<option name="presentableId" value="LOCAL-00077" />
<option name="project" value="LOCAL" />
<updated>1726472321577</updated>
</task>
<option name="localTasksCounter" value="78" />
<servers />
</component>
<component name="Vcs.Log.Tabs.Properties">
@ -485,9 +488,9 @@
<MESSAGE value="add Loop ast classes" />
<MESSAGE value="add Loop" />
<MESSAGE value="add Exception document" />
<MESSAGE value="revise" />
<MESSAGE value="add exception classes" />
<option name="LAST_COMMIT_MESSAGE" value="add exception classes" />
<MESSAGE value="revise" />
<option name="LAST_COMMIT_MESSAGE" value="revise" />
</component>
<component name="XDebuggerManager">
<watches-manager>

View File

@ -13,6 +13,8 @@ import Exception.GenerateFailedException;
import Parser.AST.Delete.DeleteNode;
import Parser.AST.Drop.DropNode;
import Parser.AST.Drop.DropOptionNode;
import Parser.AST.Exception.ExceptionActionNode;
import Parser.AST.Exception.ExceptionNode;
import Parser.AST.Insert.InsertNode;
import Parser.AST.Join.JoinConditionNode;
import Parser.AST.Join.JoinSourceTabNode;
@ -70,6 +72,9 @@ public class OpenGaussGenerator {
else if (node instanceof LoopNode || node instanceof WhileNode || node instanceof ForNode) {
return GenLoopSQL(node);
}
else if (node instanceof ExceptionNode) {
return GenExceptionSQL(node);
}
else {
try {
throw new GenerateFailedException("Root node:" + node.getClass() + "(Unsupported node type!)");
@ -135,6 +140,11 @@ public class OpenGaussGenerator {
return node.toQueryString();
}
private String GenExceptionSQL(ASTNode node) {
visitException(node);
return node.toQueryString();
}
private void visitCrt(ASTNode node) {
if (node instanceof ColumnNode) {
ColumnTypeConvert((ColumnNode) node);
@ -183,6 +193,15 @@ public class OpenGaussGenerator {
}
}
private void visitException(ASTNode node) {
if (node instanceof ExceptionActionNode) {
PLConvert(node);
}
for (ASTNode child : node.getChildren()) {
visitException(child);
}
}
private void visitSelect(ASTNode node) {
if (node instanceof JoinSourceTabNode) {
visitJoin(node);
@ -252,7 +271,7 @@ public class OpenGaussGenerator {
if (token.hasType(Token.TokenType.STRING)) {
output += token.getValue().replace("'", "");
}
else if (token.hasType(Token.TokenType.IDENTIFIER)) {
else if (token.hasType(Token.TokenType.IDENTIFIER) || token.hasType(Token.TokenType.KEYWORD)) {
output += "%";
outputObj.add(token);
}
@ -260,16 +279,29 @@ public class OpenGaussGenerator {
continue;
}
}
List<Token> tokens = new ArrayList<>();
tokens.add(new Token(Token.TokenType.KEYWORD, "RAISE"));
tokens.add(new Token(Token.TokenType.KEYWORD, "NOTICE"));
tokens.add(new Token(Token.TokenType.STRING, "'" + output + "'"));
for (Token token: outputObj) {
tokens.add(new Token(Token.TokenType.SYMBOL, ","));
tokens.add(token);
if (!outputObj.isEmpty()) {
List<Token> tokens = new ArrayList<>();
tokens.add(new Token(Token.TokenType.KEYWORD, "RAISE"));
tokens.add(new Token(Token.TokenType.KEYWORD, "NOTICE"));
tokens.add(new Token(Token.TokenType.STRING, "'" + output + "'"));
for (Token token: outputObj) {
tokens.add(new Token(Token.TokenType.SYMBOL, ","));
tokens.add(token);
}
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
node.setTokens(tokens);
}
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
node.setTokens(tokens);
else {
List<Token> tokens = new ArrayList<>();
tokens.add(new Token(Token.TokenType.KEYWORD, "RAISE"));
tokens.add(new Token(Token.TokenType.KEYWORD, "NOTICE"));
tokens.add(new Token(Token.TokenType.STRING, "'%'"));
tokens.add(new Token(Token.TokenType.SYMBOL, ","));
tokens.add(new Token(Token.TokenType.STRING, "'" + output + "'"));
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
node.setTokens(tokens);
}
}
}
}

View File

@ -34,7 +34,7 @@ public class OracleLexer {
// Loop
, "LOOP", "EXIT", "WHILE", "FOR", "IN", "CONTINUE"
// Exception
, "EXCEPTION", "SQLERRM", "ZERO_DIVIDE", "INVALID_NUMBER"
, "EXCEPTION", "SQLERRM", "ZERO_DIVIDE", "INVALID_NUMBER", "OTHERS"
};
private static final Pattern TOKEN_PATTERN = Pattern.compile(
"(NUMBER\\(.*?\\))|" + // NUMBER() function

View File

@ -45,17 +45,27 @@ public class Main {
// " ELSE\n" +
// " v_bonus := v_salary * 0.03;\n" +
// " END IF;";
String sql = "LOOP\n" +
" DBMS_OUTPUT.PUT_LINE(v_counter);\n" +
" Continue;\n" +
" v_counter := v_counter + 1;\n" +
" EXIT WHEN v_counter > 10;\n" +
" END LOOP;";
// String sql = "LOOP\n" +
// " DBMS_OUTPUT.PUT_LINE(v_counter);\n" +
// " Continue;\n" +
// " v_counter := v_counter + 1;\n" +
// " EXIT WHEN v_counter > 10;\n" +
// " END LOOP;";
String sql = "EXCEPTION\n" +
" WHEN e_custom_exception THEN\n" +
" DBMS_OUTPUT.PUT_LINE('Caught an exception: Custom exception raised');\n" +
" WHEN ZERO_DIVIDE THEN\n" +
" DBMS_OUTPUT.PUT_LINE('Caught an exception: Division by zero');\n" +
" WHEN INVALID_NUMBER THEN\n" +
" DBMS_OUTPUT.PUT_LINE('Caught an exception: Invalid number');\n" +
" WHEN OTHERS THEN\n" +
" DBMS_OUTPUT.PUT_LINE('Caught an exception: ' || SQLERRM);";
OracleLexer lexer = new OracleLexer(sql);
lexer.printTokens();
// OracleParser parser = new OracleParser(lexer);
// ASTNode root = parser.parse();
ASTNode root = OracleParser.parseLoop(lexer.getTokens());
ASTNode root = OracleParser.parseException(lexer.getTokens());
// ASTNode root = OracleParser.parseLoop(lexer.getTokens());
// ASTNode root = OracleParser.parseIFELSE(lexer.getTokens());
// ASTNode root = OracleParser.parseCaseWhen(lexer.getTokens());
// ASTNode root = OracleParser.parseJoin(lexer.getTokens());

View File

@ -18,6 +18,7 @@ import Parser.AST.Drop.DropEndNode;
import Parser.AST.Drop.DropObjNameNode;
import Parser.AST.Drop.DropNode;
import Parser.AST.Drop.DropOptionNode;
import Parser.AST.Exception.*;
import Parser.AST.IFELSIF.*;
import Parser.AST.Insert.InsertDataNode;
import Parser.AST.Insert.InsertEndNode;
@ -849,6 +850,122 @@ public class OracleParser {
return root;
}
/**
* Exception
* For example: EXCEPTION
* -- custom exception
* WHEN e_custom_exception THEN
* DBMS_OUTPUT.PUT_LINE('Caught an exception: Custom exception raised');
* -- divide by zero
* WHEN ZERO_DIVIDE THEN
* DBMS_OUTPUT.PUT_LINE('Caught an exception: Division by zero');
* -- invalid number
* WHEN INVALID_NUMBER THEN
* DBMS_OUTPUT.PUT_LINE('Caught an exception: Invalid number');
* -- other exceptions
* WHEN OTHERS THEN
* DBMS_OUTPUT.PUT_LINE('Caught an exception: ' || SQLERRM);
* @param parseTokens should start with Exception keyword
* @return ASTNode will not contain 'END'
*/
public static ASTNode parseException(List<Token> parseTokens) {
ASTNode root = new ExceptionNode();
root.addToken(parseTokens.get(0));
ASTNode currentNode = root;
for (int i = 1; i < parseTokens.size(); i++) {
// match exception type
if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("WHEN")) {
if (i + 1 < parseTokens.size() && parseTokens.get(i + 1).hasType(Token.TokenType.IDENTIFIER)) {
ASTNode childNode = new CustomExceptionNode();
for (int j = i; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("THEN")) {
i = j;
break;
}
}
currentNode.addChild(childNode);
currentNode = childNode;
}
else if (i + 1 < parseTokens.size() && parseTokens.get(i + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i + 1).getValue().equalsIgnoreCase("ZERO_DIVIDE")) {
ASTNode childNode = new Zero_divideNode();
for (int j = i; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("THEN")) {
i = j;
break;
}
}
currentNode.addChild(childNode);
currentNode = childNode;
}
else if (i + 1 < parseTokens.size() && parseTokens.get(i + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i + 1).getValue().equalsIgnoreCase("INVALID_NUMBER")) {
ASTNode childNode = new Invalid_numberNode();
for (int j = i; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("THEN")) {
i = j;
break;
}
}
currentNode.addChild(childNode);
currentNode = childNode;
}
else if (i + 1 < parseTokens.size() && parseTokens.get(i + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i + 1).getValue().equalsIgnoreCase("OTHERS")) {
ASTNode childNode = new OtherExceptionNode();
for (int j = i; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("THEN")) {
i = j;
break;
}
}
currentNode.addChild(childNode);
currentNode = childNode;
}
else {
try {
throw new ParseFailedException("Parse failed:There exists syntex error in the input sql!");
}
catch (ParseFailedException e) {
e.printStackTrace();
}
}
}
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("END")) {
ASTNode childNode = new ExceptionEndNode();
currentNode.addChild(childNode);
currentNode = childNode;
break;
}
else if (parseTokens.get(i).hasType(Token.TokenType.EOF)) {
if (!(currentNode instanceof ExceptionEndNode)) {
ASTNode childNode = new ExceptionEndNode();
currentNode.addChild(childNode);
currentNode = childNode;
}
else {
break;
}
}
// match exception action
else {
ASTNode childNode = new ExceptionActionNode();
for (int j = i; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
i = j;
break;
}
}
currentNode.addChild(childNode);
currentNode = childNode;
}
}
return root;
}
/**
* JOIN clause
* For example: table1 t1 JOIN table2 t2 ON|USING t1.id = t2.id