forked from opengaussexamples/examples
add procedure
This commit is contained in:
parent
f0a909f288
commit
9a54d05f12
|
|
@ -4,17 +4,18 @@
|
|||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add document of Procedure">
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureBeginNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureEndNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureObjNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedurePLStatementNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureRetDefNode.java" afterDir="false" />
|
||||
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add ast classes of procedure">
|
||||
<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/Procedure in Oracle" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Document/Procedure in Oracle" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/CreateTable/ColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/CreateTable/ColumnNode.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Document/Todolist" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Document/Todolist" 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/AST/Exception/ExceptionEndNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Exception/ExceptionEndNode.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedurePLStatementNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedurePLStatementNode.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" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
|
|
@ -112,13 +113,6 @@
|
|||
<option name="presentableId" value="Default" />
|
||||
<updated>1723106789329</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00031" summary="add some comments">
|
||||
<created>1725981511612</created>
|
||||
<option name="number" value="00031" />
|
||||
<option name="presentableId" value="LOCAL-00031" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1725981511612</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00032" summary="add parseSelect">
|
||||
<created>1725981975960</created>
|
||||
<option name="number" value="00032" />
|
||||
|
|
@ -455,7 +449,14 @@
|
|||
<option name="project" value="LOCAL" />
|
||||
<updated>1726491998609</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="80" />
|
||||
<task id="LOCAL-00080" summary="add ast classes of procedure">
|
||||
<created>1726496640760</created>
|
||||
<option name="number" value="00080" />
|
||||
<option name="presentableId" value="LOCAL-00080" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1726496640760</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="81" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
|
|
@ -470,7 +471,6 @@
|
|||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="add Delete ast class" />
|
||||
<MESSAGE value="add Delete" />
|
||||
<MESSAGE value="add alter table grammar document" />
|
||||
<MESSAGE value="add alter table ast class" />
|
||||
|
|
@ -495,7 +495,8 @@
|
|||
<MESSAGE value="revise" />
|
||||
<MESSAGE value="add exception" />
|
||||
<MESSAGE value="add document of Procedure" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="add document of Procedure" />
|
||||
<MESSAGE value="add ast classes of procedure" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="add ast classes of procedure" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<watches-manager>
|
||||
|
|
|
|||
|
|
@ -6,15 +6,30 @@ BEGIN
|
|||
-- Exception handling
|
||||
END [procedure_name]; -- [procedure_name] should be removed in OpenGauss
|
||||
|
||||
Example: CREATE OR REPLACE PROCEDURE update_salary(
|
||||
Example: CREATE OR REPLACE PROCEDURE update_salary (
|
||||
employee_id IN NUMBER,
|
||||
new_salary IN OUT NUMBER
|
||||
) IS
|
||||
v_employee employees%ROWTYPE;
|
||||
BEGIN
|
||||
SELECT * INTO v_employee FROM employees WHERE employee_id = employee_id;
|
||||
|
||||
IF new_salary < 3000 THEN
|
||||
new_salary := new_salary * 1.1;
|
||||
ELSE
|
||||
new_salary := new_salary * 1.05;
|
||||
END IF;
|
||||
|
||||
UPDATE employees SET salary = new_salary WHERE employee_id = employee_id;
|
||||
COMMIT;
|
||||
|
||||
DBMS_OUTPUT.PUT_LINE('Updated Salary: ' || new_salary);
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
DBMS_OUTPUT.PUT_LINE('Employee not found.');
|
||||
WHEN TOO_MANY_ROWS THEN
|
||||
DBMS_OUTPUT.PUT_LINE('Multiple employees found.');
|
||||
WHEN OTHERS THEN
|
||||
DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLERRM);
|
||||
END update_salary;
|
||||
/
|
||||
|
|
@ -15,7 +15,7 @@ Operation
|
|||
continue、exit 1
|
||||
return ***
|
||||
exception 1
|
||||
commit、rollback、execute ****
|
||||
commit、rollback、execute ***
|
||||
alter table 1
|
||||
create table 1
|
||||
drop table 1
|
||||
|
|
@ -24,4 +24,4 @@ Object
|
|||
view 1
|
||||
function ***
|
||||
procedure ***
|
||||
trigger *****
|
||||
trigger ****
|
||||
|
|
@ -22,6 +22,10 @@ import Parser.AST.Loop.ForNode;
|
|||
import Parser.AST.Loop.LoopBodyNode;
|
||||
import Parser.AST.Loop.LoopNode;
|
||||
import Parser.AST.Loop.WhileNode;
|
||||
import Parser.AST.Procedure.ProcedureColumnNode;
|
||||
import Parser.AST.Procedure.ProcedureEndNode;
|
||||
import Parser.AST.Procedure.ProcedureNode;
|
||||
import Parser.AST.Procedure.ProcedureRetDefNode;
|
||||
import Parser.AST.Select.SelectNode;
|
||||
import Parser.AST.Update.UpdateNode;
|
||||
import Parser.AST.View.ViewCreateNode;
|
||||
|
|
@ -75,6 +79,9 @@ public class OpenGaussGenerator {
|
|||
else if (node instanceof ExceptionNode) {
|
||||
return GenExceptionSQL(node);
|
||||
}
|
||||
else if (node instanceof ProcedureNode) {
|
||||
return GenProcedureSQL(node);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
throw new GenerateFailedException("Root node:" + node.getClass() + "(Unsupported node type!)");
|
||||
|
|
@ -145,6 +152,12 @@ public class OpenGaussGenerator {
|
|||
return node.toQueryString();
|
||||
}
|
||||
|
||||
private String GenProcedureSQL(ASTNode node) {
|
||||
visitPL(node);
|
||||
System.out.println(node.getASTString());
|
||||
return node.toQueryString();
|
||||
}
|
||||
|
||||
private void visitCrt(ASTNode node) {
|
||||
if (node instanceof ColumnNode) {
|
||||
ColumnTypeConvert((ColumnNode) node);
|
||||
|
|
@ -240,6 +253,24 @@ public class OpenGaussGenerator {
|
|||
visitCreateView(child);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitPL(ASTNode node) {
|
||||
if (node instanceof ProcedureRetDefNode) {
|
||||
PLConvert(node);
|
||||
}
|
||||
else if (node instanceof ProcedureColumnNode) {
|
||||
ColumnTypeConvert((ProcedureColumnNode) node);
|
||||
}
|
||||
else if (node instanceof ProcedureEndNode) {
|
||||
PLConvert(node);
|
||||
}
|
||||
else if (node instanceof ExceptionNode) {
|
||||
visitException(node);
|
||||
}
|
||||
for (ASTNode child : node.getChildren()) {
|
||||
visitPL(child);
|
||||
}
|
||||
}
|
||||
private void PLConvert(ASTNode node) {
|
||||
if (node.checkExistsByRegex("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
|
||||
String printObj = "";
|
||||
|
|
@ -304,6 +335,30 @@ public class OpenGaussGenerator {
|
|||
|
||||
}
|
||||
}
|
||||
if (node instanceof ProcedureRetDefNode) {
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "AS"));
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "$$"));
|
||||
for (Token token: node.getTokens()) {
|
||||
if (token.hasType(Token.TokenType.KEYWORD) && token.getValue().equalsIgnoreCase("IS")) {
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "DECLARE"));
|
||||
}
|
||||
else {
|
||||
tokens.add(token);
|
||||
}
|
||||
}
|
||||
node.setTokens(tokens);
|
||||
}
|
||||
if (node instanceof ProcedureEndNode) {
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "END"));
|
||||
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "$$"));
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "LANGUAGE"));
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "plpgsql"));
|
||||
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
|
||||
node.setTokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ public class OracleLexer {
|
|||
, "LOOP", "EXIT", "WHILE", "FOR", "IN", "CONTINUE"
|
||||
// Exception
|
||||
, "EXCEPTION", "SQLERRM", "ZERO_DIVIDE", "INVALID_NUMBER", "OTHERS"
|
||||
// Procedure
|
||||
, "PROCEDURE", "IS", "IN", "OUT", "$$"
|
||||
};
|
||||
private static final Pattern TOKEN_PATTERN = Pattern.compile(
|
||||
"(NUMBER\\(.*?\\))|" + // NUMBER() function
|
||||
|
|
@ -78,6 +80,7 @@ public class OracleLexer {
|
|||
"(:=)|" +
|
||||
"(\\.\\.)|" +
|
||||
|
||||
"(\\b[A-Za-z_][A-Za-z0-9_]*(%[A-Za-z_][A-Za-z0-9_]*)*\\b)|" + // Keywords and identifiers
|
||||
"(\\b[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*\\b)|" + // Keywords and identifiers
|
||||
"(\\b[A-Za-z_][A-Za-z0-9_]*\\b)|" + // Keywords and identifiers
|
||||
"(\\d+\\.?\\d*)|" + // Numbers (integer or decimal)
|
||||
|
|
@ -178,6 +181,8 @@ public class OracleLexer {
|
|||
|
||||
else if (isKeyword(tokenValue)) {
|
||||
return new Token(Token.TokenType.KEYWORD, tokenValue);
|
||||
} else if (tokenValue.matches("[A-Za-z_][A-Za-z0-9_]*(%[A-Za-z_][A-Za-z0-9_]*)*")) {
|
||||
return new Token(Token.TokenType.IDENTIFIER, tokenValue);
|
||||
} else if (tokenValue.matches("[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*")) {
|
||||
return new Token(Token.TokenType.IDENTIFIER, tokenValue);
|
||||
} else if (tokenValue.matches("[a-zA-Z_][a-zA-Z0-9_]*")) {
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ public class Main {
|
|||
// String sql = "DROP TABLE employees CASCADE CONSTRAINTS;";
|
||||
// String sql = "SELECT e.first_name, d.department_name FROM employees e JOIN departments d Using e.department_id = d.department_id;";
|
||||
// String sql = "employees e JOIN departments d ON e.department_id = d.department_id;";
|
||||
// String sql = "UPDATE employees e\n" +
|
||||
// "JOIN departments d using e.department_id = d.department_id\n" +
|
||||
// "SET e.salary = e.salary * 1.10,\n" +
|
||||
// " d.budget = d.budget * 1.10\n" +
|
||||
// "WHERE d.department_name = 'Sales';";
|
||||
String sql = "UPDATE employees e\n" +
|
||||
"JOIN departments d using e.department_id = d.department_id\n" +
|
||||
"SET e.salary = e.salary * 1.10,\n" +
|
||||
" d.budget = d.budget * 1.10\n" +
|
||||
"WHERE d.department_name = 'Sales';";
|
||||
// String sql = "DELETE FROM employees e\n" +
|
||||
// "WHERE e.department_id IN (\n" +
|
||||
// " SELECT d.department_id\n" +
|
||||
|
|
@ -51,20 +51,47 @@ public class Main {
|
|||
// " 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);";
|
||||
// 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);";
|
||||
// String sql = "CREATE OR REPLACE PROCEDURE update_salary (\n" +
|
||||
// " employee_id IN NUMBER,\n" +
|
||||
// " new_salary IN OUT NUMBER\n" +
|
||||
// " ) IS\n" +
|
||||
// " v_employee employees%ROWTYPE;\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" +
|
||||
// " /";
|
||||
OracleLexer lexer = new OracleLexer(sql);
|
||||
lexer.printTokens();
|
||||
// OracleParser parser = new OracleParser(lexer);
|
||||
// ASTNode root = parser.parse();
|
||||
ASTNode root = OracleParser.parseException(lexer.getTokens());
|
||||
OracleParser parser = new OracleParser(lexer);
|
||||
ASTNode root = parser.parse();
|
||||
// ASTNode root = OracleParser.parseException(lexer.getTokens());
|
||||
// ASTNode root = OracleParser.parseLoop(lexer.getTokens());
|
||||
// ASTNode root = OracleParser.parseIFELSE(lexer.getTokens());
|
||||
// ASTNode root = OracleParser.parseCaseWhen(lexer.getTokens());
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ public class ExceptionEndNode extends ASTNode {
|
|||
|
||||
@Override
|
||||
public void visit(ASTNode node, StringBuilder queryString) {
|
||||
|
||||
queryString.append(toString());
|
||||
for (ASTNode child : node.getChildren()) {
|
||||
child.visit(child, queryString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ public class ProcedureColumnNode extends ASTNode implements ColumnType {
|
|||
public ProcedureColumnNode() {
|
||||
super();
|
||||
setTokens(new ArrayList<>());
|
||||
setInOut(new ArrayList<>());
|
||||
}
|
||||
|
||||
public ProcedureColumnNode(ASTNode node)
|
||||
|
|
@ -31,9 +32,9 @@ public class ProcedureColumnNode extends ASTNode implements ColumnType {
|
|||
@Override
|
||||
public void visit(ASTNode node, StringBuilder queryString)
|
||||
{
|
||||
if (node.hasChild() && !(node.getChildren().get(0) instanceof ProcedureColumnNode) )
|
||||
if (node.hasChild() && (node.getChildren().get(0) instanceof ProcedureColumnNode) )
|
||||
queryString.append(toString() + ", ");
|
||||
else if (node.hasChild() && (node.getChildren().get(0) instanceof ProcedureColumnNode))
|
||||
else if (node.hasChild() && !(node.getChildren().get(0) instanceof ProcedureColumnNode))
|
||||
queryString.append(toString() + " ");
|
||||
for (ASTNode child : getChildren())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import java.util.List;
|
|||
public class ProcedurePLStatementNode extends ASTNode {
|
||||
public ProcedurePLStatementNode() {
|
||||
super();
|
||||
setTokens(new ArrayList<>());
|
||||
}
|
||||
public ProcedurePLStatementNode(ASTNode node) {
|
||||
super(node);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import java.util.List;
|
|||
public class ProcedureRetDefNode extends ASTNode {
|
||||
public ProcedureRetDefNode() {
|
||||
super();
|
||||
setTokens(new ArrayList<>());
|
||||
}
|
||||
|
||||
public ProcedureRetDefNode(ASTNode node) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public class UpdateObjNode extends ASTNode {
|
|||
public void visit(ASTNode node, StringBuilder queryString) {
|
||||
queryString.append(toString() + " ");
|
||||
for (ASTNode child : getChildren()) {
|
||||
child.visit(this, queryString);
|
||||
child.visit(child, queryString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public class UpdateSetNode extends ASTNode {
|
|||
public void visit(ASTNode node, StringBuilder queryString) {
|
||||
queryString.append(toString() + " ");
|
||||
for (ASTNode child : getChildren()) {
|
||||
child.visit(this, queryString);
|
||||
child.visit(child, queryString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import Parser.AST.Insert.InsertNode;
|
|||
import Parser.AST.Insert.InsertObjNode;
|
||||
import Parser.AST.Join.*;
|
||||
import Parser.AST.Loop.*;
|
||||
import Parser.AST.Procedure.*;
|
||||
import Parser.AST.Select.*;
|
||||
import Parser.AST.Update.*;
|
||||
import Parser.AST.View.ViewCreateNode;
|
||||
|
|
@ -73,6 +74,12 @@ public class OracleParser {
|
|||
|| lexer.getTokens().get(0).getValue().equalsIgnoreCase("WHILE")
|
||||
) {
|
||||
return parseLoop(lexer.getTokens());
|
||||
} else if (
|
||||
(lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("PROCEDURE"))
|
||||
|| (lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("OR") && lexer.getTokens().get(2).getValue().equalsIgnoreCase("REPLACE") && lexer.getTokens().get(3).getValue().equalsIgnoreCase("PROCEDURE"))
|
||||
)
|
||||
{
|
||||
return parseProcedure(lexer.getTokens());
|
||||
}
|
||||
else {
|
||||
try {
|
||||
|
|
@ -1642,4 +1649,252 @@ public class OracleParser {
|
|||
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create PROCEDURE
|
||||
* Grammar: CREATE [OR REPLACE] PROCEDURE procedure_name ([parameter_list])
|
||||
* IS [LOCAL DECLARATIONS]
|
||||
* BEGIN
|
||||
* -- PL/SQL statements
|
||||
* [EXCEPTION]
|
||||
* -- Exception handling
|
||||
* END [procedure_name];
|
||||
* Example: CREATE OR REPLACE PROCEDURE update_salary(
|
||||
* employee_id IN NUMBER,
|
||||
* new_salary IN OUT NUMBER
|
||||
* ) IS
|
||||
* BEGIN
|
||||
* IF new_salary < 3000 THEN
|
||||
* new_salary := new_salary * 1.1;
|
||||
* ELSE
|
||||
* new_salary := new_salary * 1.05;
|
||||
* END IF;
|
||||
* END update_salary;
|
||||
* /
|
||||
*/
|
||||
private ASTNode parseProcedure(List<Token> parseTokens) {
|
||||
ASTNode root = new ProcedureNode(new ArrayList<>());
|
||||
ASTNode currentNode = root;
|
||||
for (int i = 0; i < parseTokens.size(); i++) {
|
||||
// match CREATE PROCEDURE
|
||||
if (root.getTokens().isEmpty()) {
|
||||
for (int j = i; j < parseTokens.size(); j++) {
|
||||
root.addToken(parseTokens.get(j));
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("PROCEDURE")) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// match procedure name
|
||||
else if (currentNode == root && parseTokens.get(i).hasType(Token.TokenType.IDENTIFIER)) {
|
||||
ASTNode childNode = new ProcedureObjNode();
|
||||
childNode.addToken(parseTokens.get(i));
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
}
|
||||
// match parameter list
|
||||
else if (currentNode instanceof ProcedureObjNode && parseTokens.get(i).hasType(Token.TokenType.SYMBOL) && parseTokens.get(i).getValue().equals("(")) {
|
||||
i++;
|
||||
for (int ii = i; ii < parseTokens.size(); ii++) {
|
||||
if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("IS")) {
|
||||
i = ii - 1;
|
||||
break;
|
||||
}
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
ProcedureColumnNode child = new ProcedureColumnNode();
|
||||
child.setName(parseTokens.get(ii));
|
||||
tokens.add(parseTokens.get(ii));
|
||||
List<Token> constraint = new ArrayList<>();
|
||||
boolean typeMatch = false;
|
||||
int typeIdx = -1;
|
||||
for (int j = ii + 1; j < parseTokens.size(); j++) {
|
||||
if (!typeMatch && !(parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))))
|
||||
{
|
||||
child.setType(parseTokens.get(j));
|
||||
typeMatch = true;
|
||||
typeIdx = j;
|
||||
}
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))) {
|
||||
child.addInOut(parseTokens.get(j));
|
||||
}
|
||||
// Check () or REFERENCES other_table(other_column)
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) &&
|
||||
(parseTokens.get(j).getValue().equalsIgnoreCase("REFERENCES")
|
||||
|| parseTokens.get(j).getValue().equalsIgnoreCase("CHECK"))) {
|
||||
tokens.add(parseTokens.get(j));
|
||||
if (!(parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))))
|
||||
constraint.add(parseTokens.get(j));
|
||||
Stack<String> stack = new Stack<>();
|
||||
for (int k = j + 1; k < parseTokens.size(); k++) {
|
||||
tokens.add(parseTokens.get(k));
|
||||
if (!(parseTokens.get(k).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(k).getValue().equalsIgnoreCase("IN") || parseTokens.get(k).getValue().equalsIgnoreCase("OUT"))))
|
||||
constraint.add(parseTokens.get(k));
|
||||
if (parseTokens.get(k).getValue().equals("(")) {
|
||||
stack.push("(");
|
||||
for (int t = k + 1; t < parseTokens.size(); t++) {
|
||||
tokens.add(parseTokens.get(t));
|
||||
if (!(parseTokens.get(t).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(t).getValue().equalsIgnoreCase("IN") || parseTokens.get(t).getValue().equalsIgnoreCase("OUT"))))
|
||||
constraint.add(parseTokens.get(t));
|
||||
if (parseTokens.get(t).getValue().equals("(")) {
|
||||
stack.push("(");
|
||||
} else if (parseTokens.get(t).getValue().equals(")")) {
|
||||
stack.pop();
|
||||
if (stack.empty()) {
|
||||
ii = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(",")) ||
|
||||
(parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(")"))) {
|
||||
ii = j;
|
||||
break;
|
||||
}
|
||||
tokens.add(parseTokens.get(j));
|
||||
if (typeMatch && j != typeIdx) {
|
||||
if (!(parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))))
|
||||
constraint.add(parseTokens.get(j));
|
||||
}
|
||||
}
|
||||
child.setTokens(tokens);
|
||||
child.setConstraint(constraint);
|
||||
currentNode.addChild(child);
|
||||
currentNode = child;
|
||||
}
|
||||
}
|
||||
// match procedure return definition
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("IS")) {
|
||||
ASTNode childNode = new ProcedureRetDefNode();
|
||||
for (int j = i; j < parseTokens.size(); j++) {
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("BEGIN")) {
|
||||
i = j - 1;
|
||||
break;
|
||||
}
|
||||
childNode.addToken(parseTokens.get(j));
|
||||
}
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
}
|
||||
// match procedure begin
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("BEGIN")) {
|
||||
ASTNode childNode = new ProcedureBeginNode();
|
||||
childNode.addToken(parseTokens.get(i));
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
}
|
||||
// match procedure body
|
||||
else if (currentNode instanceof ProcedureBeginNode) {
|
||||
for (int ii = i; ii < parseTokens.size(); ii++) {
|
||||
if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("END")) {
|
||||
i = ii - 1;
|
||||
break;
|
||||
}
|
||||
else if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("EXCEPTION")) {
|
||||
i = ii - 1;
|
||||
break;
|
||||
}
|
||||
else if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("IF")) {
|
||||
int index = -1;
|
||||
for (int j = ii; j < parseTokens.size(); j++) {
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("END")
|
||||
&& j + 1 < parseTokens.size() && parseTokens.get(j + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j + 1).getValue().equalsIgnoreCase("IF")
|
||||
&& j + 2 < parseTokens.size() && parseTokens.get(j + 2).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j + 2).getValue().equals(";") ) {
|
||||
index = j + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1) {
|
||||
try {
|
||||
throw new ParseFailedException("There exists syntax error and no END if block is found!");
|
||||
} catch (ParseFailedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ASTNode childNode = parseIFELSE(parseTokens.subList(ii, index + 1));
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode.getDeepestChild();
|
||||
ii = index;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ASTNode childNode = new ProcedurePLStatementNode();
|
||||
for (int j = ii; j < parseTokens.size(); j++) {
|
||||
childNode.addToken(parseTokens.get(j));
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
|
||||
ii = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
// match exception
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("EXCEPTION")) {
|
||||
int index = -1;
|
||||
for (int j = i; j < parseTokens.size(); j++) {
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("END")) {
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1) {
|
||||
try {
|
||||
throw new ParseFailedException("There exists syntax error and no END block is found!");
|
||||
} catch (ParseFailedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
ASTNode childNode = parseException(parseTokens.subList(i, index + 1));
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode.getDeepestChild();
|
||||
childNode = new ProcedureEndNode();
|
||||
for (int j = index; j < parseTokens.size(); j++) {
|
||||
childNode.addToken(parseTokens.get(j));
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.EOF)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
break;
|
||||
}
|
||||
// match procedure end
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("END")) {
|
||||
ASTNode childNode = new ProcedureEndNode();
|
||||
for (int j = i; j < parseTokens.size(); j++) {
|
||||
childNode.addToken(parseTokens.get(j));
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.EOF)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
break;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue