diff --git a/sqlTranslate/.idea/workspace.xml b/sqlTranslate/.idea/workspace.xml
index b3bd99f03..9514e9b44 100644
--- a/sqlTranslate/.idea/workspace.xml
+++ b/sqlTranslate/.idea/workspace.xml
@@ -4,12 +4,13 @@
-
+
+
+
-
@@ -108,13 +109,6 @@
1723106789329
-
- 1726148093221
-
-
-
- 1726148093221
-
1726149015586
@@ -451,7 +445,14 @@
1726629819863
-
+
+ 1726631451338
+
+
+
+ 1726631451338
+
+
@@ -477,7 +478,6 @@
-
@@ -491,7 +491,8 @@
-
+
+
diff --git a/sqlTranslate/src/main/java/Generator/OpenGaussGenerator.java b/sqlTranslate/src/main/java/Generator/OpenGaussGenerator.java
index bc8b32cc5..6faf376e1 100644
--- a/sqlTranslate/src/main/java/Generator/OpenGaussGenerator.java
+++ b/sqlTranslate/src/main/java/Generator/OpenGaussGenerator.java
@@ -26,6 +26,10 @@ import Parser.AST.Loop.ForNode;
import Parser.AST.Loop.LoopBodyNode;
import Parser.AST.Loop.LoopNode;
import Parser.AST.Loop.WhileNode;
+import Parser.AST.PL.PLBodyNode;
+import Parser.AST.PL.PLDeclareNode;
+import Parser.AST.PL.PLEndNode;
+import Parser.AST.PL.PLNode;
import Parser.AST.Procedure.ProcedureColumnNode;
import Parser.AST.Procedure.ProcedureEndNode;
import Parser.AST.Procedure.ProcedureNode;
@@ -93,6 +97,9 @@ public class OpenGaussGenerator {
else if (node instanceof TriggerNode) {
return GenTriggerSQL(node);
}
+ else if (node instanceof PLNode) {
+ return GenPLSQL(node);
+ }
else {
try {
throw new GenerateFailedException("Root node:" + node.getClass() + "(Unsupported node type!)");
@@ -179,9 +186,14 @@ public class OpenGaussGenerator {
return node.toQueryString();
}
+ private String GenPLSQL(ASTNode node) {
+ visitPLSQL(node);
+ return node.toQueryString();
+ }
+
private void visitCrt(ASTNode node) {
if (node instanceof ColumnNode) {
- ColumnTypeConvert((ColumnNode) node);
+ DataTypeConvert((ColumnNode) node);
}
for (ASTNode child : node.getChildren()) {
visitCrt(child);
@@ -256,10 +268,10 @@ public class OpenGaussGenerator {
private void visitAlter(ASTNode node) {
if (node instanceof AlterAddColumnNode) {
- ColumnTypeConvert((AlterAddColumnNode) node);
+ DataTypeConvert((AlterAddColumnNode) node);
}
else if (node instanceof AlterModifyColumnNode) {
- ColumnTypeConvert((AlterModifyColumnNode) node);
+ DataTypeConvert((AlterModifyColumnNode) node);
}
for (ASTNode child : node.getChildren()) {
visitAlter(child);
@@ -277,11 +289,11 @@ public class OpenGaussGenerator {
private void visitPL(ASTNode node) {
if (node instanceof ProcedureRetDefNode) {
- ColumnTypeConvert((ProcedureRetDefNode) node);
+ DataTypeConvert((ProcedureRetDefNode) node);
PLConvert(node);
}
else if (node instanceof ProcedureColumnNode) {
- ColumnTypeConvert((ProcedureColumnNode) node);
+ DataTypeConvert((ProcedureColumnNode) node);
}
else if (node instanceof ProcedureEndNode) {
PLConvert(node);
@@ -302,7 +314,7 @@ public class OpenGaussGenerator {
visitException(node);
}
else if (node instanceof FunctionColumnNode) {
- ColumnTypeConvert((FunctionColumnNode) node);
+ DataTypeConvert((FunctionColumnNode) node);
}
else if (node instanceof FunctionEndNode) {
PLConvert(node);
@@ -327,6 +339,24 @@ public class OpenGaussGenerator {
}
}
+ private void visitPLSQL(ASTNode node) {
+ if (node instanceof PLNode) {
+ PLConvert(node);
+ }
+ else if (node instanceof PLDeclareNode) {
+ DataTypeConvert((PLDeclareNode) node);
+ }
+ else if (node instanceof PLEndNode) {
+ PLConvert(node);
+ }
+ else if (node instanceof PLBodyNode) {
+ PLConvert(node);
+ }
+ for (ASTNode child : node.getChildren()) {
+ visitPLSQL(child);
+ }
+ }
+
private void PLConvert(ASTNode node) {
if (node.checkExistsByRegex("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
String printObj = "";
@@ -460,17 +490,31 @@ public class OpenGaussGenerator {
}
}
}
+ if (node instanceof PLNode) {
+ List tokens = new ArrayList<>();
+ tokens.add(new Token(Token.TokenType.KEYWORD, "DO"));
+ tokens.add(new Token(Token.TokenType.KEYWORD, "$$"));
+ tokens.add(new Token(Token.TokenType.KEYWORD, "DECLARE"));
+ node.setTokens(tokens);
+ }
+ if (node instanceof PLEndNode) {
+ List tokens = new ArrayList<>();
+ tokens.add(new Token(Token.TokenType.KEYWORD, "END"));
+ tokens.add(new Token(Token.TokenType.KEYWORD, "$$"));
+ tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
+ node.setTokens(tokens);
+ }
}
- private void ColumnTypeConvert(DataType node) {
+ private void DataTypeConvert(DataType node) {
// type convert
if (node.getType().getValue().equalsIgnoreCase("NUMBER")) {
node.setType(new Token(Token.TokenType.KEYWORD, "NUMERIC"));
node.ResetTokensbyNameTypeConstraint();
}
if (node.getType().getValue().matches("(?i)NUMBER\\(.*?\\)")) {
- node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().replace("NUMBER", "DECIMAL")));
+ node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().toUpperCase().replace("NUMBER", "DECIMAL")));
node.ResetTokensbyNameTypeConstraint();
}
@@ -479,7 +523,7 @@ public class OpenGaussGenerator {
node.ResetTokensbyNameTypeConstraint();
}
if (node.getType().getValue().matches("(?i)VARCHAR2\\(.*?\\)")) {
- node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().replace("VARCHAR2", "VARCHAR")));
+ node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().toUpperCase().replace("VARCHAR2", "VARCHAR")));
node.ResetTokensbyNameTypeConstraint();
}
@@ -488,7 +532,7 @@ public class OpenGaussGenerator {
node.ResetTokensbyNameTypeConstraint();
}
if (node.getType().getValue().matches("(?i)RAW\\(.*?\\)")) {
- node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().replace("RAW", "BYTEA")));
+ node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().toUpperCase().replace("RAW", "BYTEA")));
node.ResetTokensbyNameTypeConstraint();
}
@@ -502,7 +546,7 @@ public class OpenGaussGenerator {
node.ResetTokensbyNameTypeConstraint();
}
if (node.getType().getValue().matches("(?i)NCHAR\\(.*?\\)")) {
- node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().replace("NCHAR", "VARCHAR")));
+ node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().toUpperCase().replace("NCHAR", "VARCHAR")));
node.ResetTokensbyNameTypeConstraint();
}
@@ -511,7 +555,7 @@ public class OpenGaussGenerator {
node.ResetTokensbyNameTypeConstraint();
}
if (node.getType().getValue().matches("(?i)NVARCHAR2\\(.*?\\)")) {
- node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().replace("NVARCHAR2", "VARCHAR")));
+ node.setType(new Token(Token.TokenType.KEYWORD, node.getType().getValue().toUpperCase().replace("NVARCHAR2", "VARCHAR")));
node.ResetTokensbyNameTypeConstraint();
}
diff --git a/sqlTranslate/src/main/java/Lexer/OracleLexer.java b/sqlTranslate/src/main/java/Lexer/OracleLexer.java
index cbd5d1a00..bca459343 100644
--- a/sqlTranslate/src/main/java/Lexer/OracleLexer.java
+++ b/sqlTranslate/src/main/java/Lexer/OracleLexer.java
@@ -30,7 +30,7 @@ public class OracleLexer {
// keywords of view
, "REPLACE", "VIEW"
// PL/SQL
- , ":=", "IF", "ELSIF", "BEGIN", ".."
+ , ":=", "IF", "ELSIF", "BEGIN", "..", "DECLARE"
// Loop
, "LOOP", "EXIT", "WHILE", "FOR", "IN", "CONTINUE"
// Exception
diff --git a/sqlTranslate/src/main/java/Lexer/Token.java b/sqlTranslate/src/main/java/Lexer/Token.java
index 58d1634f7..178616101 100644
--- a/sqlTranslate/src/main/java/Lexer/Token.java
+++ b/sqlTranslate/src/main/java/Lexer/Token.java
@@ -4,7 +4,7 @@ import java.util.Objects;
public class Token {
public enum TokenType {
- KEYWORD, IDENTIFIER, NUMBER, OPERATOR, STRING, SYMBOL, EOF
+ KEYWORD, IDENTIFIER, NUMBER, OPERATOR, STRING, SYMBOL, NULL, EOF
}
private TokenType type;
diff --git a/sqlTranslate/src/main/java/Main.java b/sqlTranslate/src/main/java/Main.java
index 61d1bb54b..7adb77db2 100644
--- a/sqlTranslate/src/main/java/Main.java
+++ b/sqlTranslate/src/main/java/Main.java
@@ -60,33 +60,33 @@ public class Main {
// " DBMS_OUTPUT.PUT_LINE('Caught an exception: Invalid number');\n" +
// " WHEN OTHERS THEN\n" +
// " DBMS_OUTPUT.PUT_LINE('Caught an exception: ' || SQLERRM);";
- String sql = "CREATE OR REPLACE PROCEDURE update_salary (\n" +
- " employee_id IN NUMBER,\n" +
- " new_salary IN OUT NUMBER\n" +
- " ) IS\n" +
- " v_employee NUMBER;\n" +
- " BEGIN\n" +
- " SELECT * INTO v_employee FROM employees WHERE employee_id = employee_id;\n" +
- "\n" +
- " IF new_salary < 3000 THEN\n" +
- " new_salary := new_salary * 1.1;\n" +
- " ELSE\n" +
- " new_salary := new_salary * 1.05;\n" +
- " END IF;\n" +
- "\n" +
- " UPDATE employees SET salary = new_salary WHERE employee_id = employee_id;\n" +
- " COMMIT;\n" +
- "\n" +
- " DBMS_OUTPUT.PUT_LINE('Updated Salary: ' || new_salary);\n" +
- " EXCEPTION\n" +
- " WHEN NO_DATA_FOUND THEN\n" +
- " DBMS_OUTPUT.PUT_LINE('Employee not found.');\n" +
- " WHEN TOO_MANY_ROWS THEN\n" +
- " DBMS_OUTPUT.PUT_LINE('Multiple employees found.');\n" +
- " WHEN OTHERS THEN\n" +
- " DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLERRM);\n" +
- " END update_salary;\n" +
- " /";
+// String sql = "CREATE OR REPLACE PROCEDURE update_salary (\n" +
+// " employee_id IN NUMBER,\n" +
+// " new_salary IN OUT NUMBER\n" +
+// " ) IS\n" +
+// " v_employee NUMBER;\n" +
+// " BEGIN\n" +
+// " SELECT * INTO v_employee FROM employees WHERE employee_id = employee_id;\n" +
+// "\n" +
+// " IF new_salary < 3000 THEN\n" +
+// " new_salary := new_salary * 1.1;\n" +
+// " ELSE\n" +
+// " new_salary := new_salary * 1.05;\n" +
+// " END IF;\n" +
+// "\n" +
+// " UPDATE employees SET salary = new_salary WHERE employee_id = employee_id;\n" +
+// " COMMIT;\n" +
+// "\n" +
+// " DBMS_OUTPUT.PUT_LINE('Updated Salary: ' || new_salary);\n" +
+// " EXCEPTION\n" +
+// " WHEN NO_DATA_FOUND THEN\n" +
+// " DBMS_OUTPUT.PUT_LINE('Employee not found.');\n" +
+// " WHEN TOO_MANY_ROWS THEN\n" +
+// " DBMS_OUTPUT.PUT_LINE('Multiple employees found.');\n" +
+// " WHEN OTHERS THEN\n" +
+// " DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLERRM);\n" +
+// " END update_salary;\n" +
+// " /";
// String sql = "CREATE OR REPLACE FUNCTION string_length (\n" +
// " input_string VARCHAR2\n" +
// ") RETURN NUMBER IS\n" +
@@ -100,6 +100,13 @@ public class Main {
// " BEGIN\n" +
// " INSERT INTO audit_log (action, employee_id) VALUES ('INSERT', :NEW.id);\n" +
// " END;";
+ String sql = "DECLARE\n" +
+ " v_name Varchar2(20);\n" +
+ " v_salary employees.salary%TYPE;\n" +
+ " BEGIN\n" +
+ " SELECT name, salary INTO v_name, v_salary FROM employees WHERE employee_id = 100;\n" +
+ " DBMS_OUTPUT.PUT_LINE('Name: ' || v_name || ', Salary: ' || v_salary);\n" +
+ " END;";
OracleLexer lexer = new OracleLexer(sql);
lexer.printTokens();
OracleParser parser = new OracleParser(lexer);
diff --git a/sqlTranslate/src/main/java/Parser/AST/PL/PLDeclareNode.java b/sqlTranslate/src/main/java/Parser/AST/PL/PLDeclareNode.java
index ce2999b89..bd137b0f9 100644
--- a/sqlTranslate/src/main/java/Parser/AST/PL/PLDeclareNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/PL/PLDeclareNode.java
@@ -12,6 +12,7 @@ public class PLDeclareNode extends ASTNode implements DataType {
public PLDeclareNode() {
super();
setTokens(new ArrayList<>());
+ setType(new Token(Token.TokenType.NULL, ""));
}
public PLDeclareNode(ASTNode node) {
diff --git a/sqlTranslate/src/main/java/Parser/OracleParser.java b/sqlTranslate/src/main/java/Parser/OracleParser.java
index d35c4e7f2..fefbfce70 100644
--- a/sqlTranslate/src/main/java/Parser/OracleParser.java
+++ b/sqlTranslate/src/main/java/Parser/OracleParser.java
@@ -27,8 +27,7 @@ import Parser.AST.Insert.InsertNode;
import Parser.AST.Insert.InsertObjNode;
import Parser.AST.Join.*;
import Parser.AST.Loop.*;
-import Parser.AST.PL.PLDeclareNode;
-import Parser.AST.PL.PLNode;
+import Parser.AST.PL.*;
import Parser.AST.Procedure.*;
import Parser.AST.Select.*;
import Parser.AST.Trigger.*;
@@ -2369,13 +2368,71 @@ public class OracleParser {
i = j - 1;
break;
}
- ASTNode childNode = new PLDeclareNode();
+ PLDeclareNode childNode = new PLDeclareNode();
for (int k = j; k < parseTokens.size(); k++) {
+ childNode.addToken(parseTokens.get(k));
+ if (parseTokens.get(k).hasType(Token.TokenType.KEYWORD)) {
+ childNode.setType(parseTokens.get(k));
+ }
if (parseTokens.get(k).hasType(Token.TokenType.SYMBOL) && parseTokens.get(k).getValue().equals(";")) {
j = k;
break;
}
}
+ currentNode.addChild(childNode);
+ currentNode = childNode;
+ }
+ }
+ // match begin
+ else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("BEGIN")) {
+ ASTNode childNode = new PLBeginNode();
+ childNode.addToken(parseTokens.get(i));
+ currentNode.addChild(childNode);
+ currentNode = childNode;
+ }
+ // match body
+ else if (
+ (currentNode instanceof PLBeginNode || currentNode instanceof PLBodyNode) &&
+ !(parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("END"))
+ ) {
+ ASTNode childNode = new PLBodyNode();
+ for (int j = i; j < parseTokens.size(); j++) {
+ if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("END")) {
+ i = j - 1;
+ break;
+ }
+ else if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
+ i = j;
+ childNode.addToken(parseTokens.get(j));
+ break;
+ }
+ childNode.addToken(parseTokens.get(j));
+ }
+ currentNode.addChild(childNode);
+ currentNode = childNode;
+ }
+ // match end
+ else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("END")) {
+ ASTNode childNode = new PLEndNode();
+ 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;
+ }
+ else if (parseTokens.get(i).hasType(Token.TokenType.EOF)) {
+ break;
+ }
+ else {
+ try {
+ throw new ParseFailedException("Failed to parse:" + parseTokens.get(i));
+ }
+ catch (ParseFailedException e) {
+ e.printStackTrace();
}
}
}