forked from opengaussexamples/examples
add pl/sql
This commit is contained in:
parent
ac03ad7130
commit
15ec96c822
|
|
@ -4,12 +4,13 @@
|
|||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add PL ast 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/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/Lexer/Token.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Lexer/Token.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/AST/PL/PLDeclareNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/PL/PLDeclareNode.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureRetDefNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureRetDefNode.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" />
|
||||
|
|
@ -108,13 +109,6 @@
|
|||
<option name="presentableId" value="Default" />
|
||||
<updated>1723106789329</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00043" summary="add select convert rules">
|
||||
<created>1726148093221</created>
|
||||
<option name="number" value="00043" />
|
||||
<option name="presentableId" value="LOCAL-00043" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1726148093221</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00044" summary="add update ast class">
|
||||
<created>1726149015586</created>
|
||||
<option name="number" value="00044" />
|
||||
|
|
@ -451,7 +445,14 @@
|
|||
<option name="project" value="LOCAL" />
|
||||
<updated>1726629819863</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="92" />
|
||||
<task id="LOCAL-00092" summary="revise">
|
||||
<created>1726631451338</created>
|
||||
<option name="number" value="00092" />
|
||||
<option name="presentableId" value="LOCAL-00092" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1726631451338</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="93" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
|
|
@ -477,7 +478,6 @@
|
|||
<MESSAGE value="add Loop" />
|
||||
<MESSAGE value="add Exception document" />
|
||||
<MESSAGE value="add exception classes" />
|
||||
<MESSAGE value="revise" />
|
||||
<MESSAGE value="add exception" />
|
||||
<MESSAGE value="add document of Procedure" />
|
||||
<MESSAGE value="add ast classes of procedure" />
|
||||
|
|
@ -491,7 +491,8 @@
|
|||
<MESSAGE value="add trigger" />
|
||||
<MESSAGE value="add PL document" />
|
||||
<MESSAGE value="add PL ast classes" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="add PL ast classes" />
|
||||
<MESSAGE value="revise" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="revise" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<watches-manager>
|
||||
|
|
|
|||
|
|
@ -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<Token> 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<Token> 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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue