forked from opengaussexamples/examples
add function
This commit is contained in:
parent
d61e9d8460
commit
6afc2b1085
|
|
@ -4,18 +4,20 @@
|
|||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add document of function">
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionBeginNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionBodyNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionColumnNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionEndNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionNameNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionRetDefNode.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionReturnNode.java" afterDir="false" />
|
||||
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add ast classes of function">
|
||||
<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/Function in Oracle" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Document/Function 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/Interface/ColumnType.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Interface/DataType.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/AlterTable/AlterAddColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/AlterTable/AlterAddColumnNode.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/AlterTable/AlterModifyColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/AlterTable/AlterModifyColumnNode.java" 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/Parser/AST/Function/FunctionColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionColumnNode.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionNameNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionNameNode.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionRetDefNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionRetDefNode.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/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" />
|
||||
|
|
@ -113,13 +115,6 @@
|
|||
<option name="presentableId" value="Default" />
|
||||
<updated>1723106789329</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00035" summary="revise">
|
||||
<created>1726065430463</created>
|
||||
<option name="number" value="00035" />
|
||||
<option name="presentableId" value="LOCAL-00035" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1726065430463</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00036" summary="revise">
|
||||
<created>1726066806993</created>
|
||||
<option name="number" value="00036" />
|
||||
|
|
@ -456,7 +451,14 @@
|
|||
<option name="project" value="LOCAL" />
|
||||
<updated>1726561299659</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="84" />
|
||||
<task id="LOCAL-00084" summary="add ast classes of function">
|
||||
<created>1726583392370</created>
|
||||
<option name="number" value="00084" />
|
||||
<option name="presentableId" value="LOCAL-00084" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1726583392370</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="85" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
|
|
@ -471,7 +473,6 @@
|
|||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="add alter table keywords" />
|
||||
<MESSAGE value="add alter table parser" />
|
||||
<MESSAGE value="add alter" />
|
||||
<MESSAGE value="fix some bugs" />
|
||||
|
|
@ -496,7 +497,8 @@
|
|||
<MESSAGE value="add procedure" />
|
||||
<MESSAGE value="add document of rollback, commot, execute" />
|
||||
<MESSAGE value="add document of function" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="add document of function" />
|
||||
<MESSAGE value="add ast classes of function" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="add ast classes of function" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<watches-manager>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package Generator;
|
||||
|
||||
import Interface.ColumnType;
|
||||
import Interface.DataType;
|
||||
import Lexer.OracleLexer;
|
||||
import Lexer.Token;
|
||||
import Parser.AST.ASTNode;
|
||||
|
|
@ -15,6 +15,10 @@ import Parser.AST.Drop.DropNode;
|
|||
import Parser.AST.Drop.DropOptionNode;
|
||||
import Parser.AST.Exception.ExceptionActionNode;
|
||||
import Parser.AST.Exception.ExceptionNode;
|
||||
import Parser.AST.Function.FunctionColumnNode;
|
||||
import Parser.AST.Function.FunctionEndNode;
|
||||
import Parser.AST.Function.FunctionNode;
|
||||
import Parser.AST.Function.FunctionRetDefNode;
|
||||
import Parser.AST.Insert.InsertNode;
|
||||
import Parser.AST.Join.JoinConditionNode;
|
||||
import Parser.AST.Join.JoinSourceTabNode;
|
||||
|
|
@ -82,6 +86,9 @@ public class OpenGaussGenerator {
|
|||
else if (node instanceof ProcedureNode) {
|
||||
return GenProcedureSQL(node);
|
||||
}
|
||||
else if (node instanceof FunctionNode) {
|
||||
return GenFunctionSQL(node);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
throw new GenerateFailedException("Root node:" + node.getClass() + "(Unsupported node type!)");
|
||||
|
|
@ -154,7 +161,12 @@ public class OpenGaussGenerator {
|
|||
|
||||
private String GenProcedureSQL(ASTNode node) {
|
||||
visitPL(node);
|
||||
System.out.println(node.getASTString());
|
||||
// System.out.println(node.getASTString());
|
||||
return node.toQueryString();
|
||||
}
|
||||
|
||||
private String GenFunctionSQL(ASTNode node) {
|
||||
visitFunc(node);
|
||||
return node.toQueryString();
|
||||
}
|
||||
|
||||
|
|
@ -271,6 +283,25 @@ public class OpenGaussGenerator {
|
|||
visitPL(child);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitFunc(ASTNode node) {
|
||||
if (node instanceof FunctionRetDefNode) {
|
||||
PLConvert(node);
|
||||
}
|
||||
else if (node instanceof ExceptionNode) {
|
||||
visitException(node);
|
||||
}
|
||||
else if (node instanceof FunctionColumnNode) {
|
||||
ColumnTypeConvert((FunctionColumnNode) node);
|
||||
}
|
||||
else if (node instanceof FunctionEndNode) {
|
||||
PLConvert(node);
|
||||
}
|
||||
for (ASTNode child : node.getChildren()) {
|
||||
visitFunc(child);
|
||||
}
|
||||
}
|
||||
|
||||
private void PLConvert(ASTNode node) {
|
||||
if (node.checkExistsByRegex("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
|
||||
String printObj = "";
|
||||
|
|
@ -359,10 +390,36 @@ public class OpenGaussGenerator {
|
|||
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
|
||||
node.setTokens(tokens);
|
||||
}
|
||||
if (node instanceof FunctionEndNode) {
|
||||
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);
|
||||
}
|
||||
if (node instanceof FunctionRetDefNode) {
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
for (Token token: node.getTokens()) {
|
||||
if (token.hasType(Token.TokenType.KEYWORD) && token.getValue().equalsIgnoreCase("RETURN")) {
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "RETURNS"));
|
||||
}
|
||||
else if (token.hasType(Token.TokenType.KEYWORD) && token.getValue().equalsIgnoreCase("IS")) {
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "AS"));
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "$$"));
|
||||
}
|
||||
else {
|
||||
tokens.add(token);
|
||||
}
|
||||
}
|
||||
node.setTokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ColumnTypeConvert(ColumnType node) {
|
||||
private void ColumnTypeConvert(DataType node) {
|
||||
// type convert
|
||||
if (node.getType().getValue().equalsIgnoreCase("NUMBER")) {
|
||||
node.setType(new Token(Token.TokenType.KEYWORD, "NUMERIC"));
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package Interface;
|
|||
|
||||
import Lexer.Token;
|
||||
|
||||
public interface ColumnType {
|
||||
public interface DataType {
|
||||
Token getType();
|
||||
void setType(Token type);
|
||||
void ResetTokensbyNameTypeConstraint();
|
||||
|
|
@ -37,6 +37,8 @@ public class OracleLexer {
|
|||
, "EXCEPTION", "SQLERRM", "ZERO_DIVIDE", "INVALID_NUMBER", "OTHERS"
|
||||
// Procedure
|
||||
, "PROCEDURE", "IS", "IN", "OUT", "$$", "COMMIT", "ROLLBACK", "EXEC", "EXECUTE"
|
||||
// function
|
||||
, "FUNCTION", "RETURN"
|
||||
};
|
||||
private static final Pattern TOKEN_PATTERN = Pattern.compile(
|
||||
"(NUMBER\\(.*?\\))|" + // NUMBER() function
|
||||
|
|
@ -55,6 +57,7 @@ public class OracleLexer {
|
|||
"(MIN\\(.*?\\))|" + // MIN() function
|
||||
"(\\|\\|\\s*'.*?'\\s*\\|\\|)|" + // || '*' ||
|
||||
"(DBMS_OUTPUT.PUT_LINE\\(.*?\\))|" + // DBMS_OUTPUT.PUT_LINE() function
|
||||
"(LENGTH\\(.*?\\))|" + // LENGTH() function
|
||||
|
||||
"(NOT NULL)|" +
|
||||
"(PRIMARY KEY)|" +
|
||||
|
|
@ -177,6 +180,9 @@ public class OracleLexer {
|
|||
} else if (tokenValue.matches("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
|
||||
// RAW() function, CASE_INSENSITIVE
|
||||
return new Token(Token.TokenType.KEYWORD, tokenValue);
|
||||
} else if (tokenValue.matches("(?i)LENGTH\\(.*?\\)")) {
|
||||
// RAW() function, CASE_INSENSITIVE
|
||||
return new Token(Token.TokenType.KEYWORD, tokenValue);
|
||||
}
|
||||
|
||||
else if (isKeyword(tokenValue)) {
|
||||
|
|
|
|||
|
|
@ -60,33 +60,40 @@ 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 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" +
|
||||
" /";
|
||||
// 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" +
|
||||
// " /";
|
||||
String sql = "CREATE OR REPLACE FUNCTION string_length (\n" +
|
||||
" input_string VARCHAR2\n" +
|
||||
") RETURN NUMBER IS\n" +
|
||||
"BEGIN\n" +
|
||||
" RETURN LENGTH(input_string);\n" +
|
||||
"END;\n" +
|
||||
"/";
|
||||
OracleLexer lexer = new OracleLexer(sql);
|
||||
lexer.printTokens();
|
||||
OracleParser parser = new OracleParser(lexer);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
package Parser.AST.AlterTable;
|
||||
|
||||
import Interface.ColumnType;
|
||||
import Interface.DataType;
|
||||
import Lexer.Token;
|
||||
import Parser.AST.ASTNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AlterAddColumnNode extends ASTNode implements ColumnType {
|
||||
public class AlterAddColumnNode extends ASTNode implements DataType {
|
||||
private Token name;
|
||||
private Token type;
|
||||
private List<Token> constraint;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
package Parser.AST.AlterTable;
|
||||
|
||||
import Interface.ColumnType;
|
||||
import Interface.DataType;
|
||||
import Lexer.Token;
|
||||
import Parser.AST.ASTNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AlterModifyColumnNode extends ASTNode implements ColumnType {
|
||||
public class AlterModifyColumnNode extends ASTNode implements DataType {
|
||||
private Token name;
|
||||
private Token type;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
package Parser.AST.CreateTable;
|
||||
|
||||
import Interface.ColumnType;
|
||||
import Interface.DataType;
|
||||
import Lexer.Token;
|
||||
import Parser.AST.ASTNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ColumnNode extends ASTNode implements ColumnType {
|
||||
public class ColumnNode extends ASTNode implements DataType {
|
||||
private Token name;
|
||||
private Token type;
|
||||
private List<Token> constraint;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
package Parser.AST.Function;
|
||||
|
||||
import Interface.ColumnType;
|
||||
import Interface.DataType;
|
||||
import Lexer.Token;
|
||||
import Parser.AST.ASTNode;
|
||||
import Parser.AST.Procedure.ProcedureColumnNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FunctionColumnNode extends ASTNode implements ColumnType {
|
||||
public class FunctionColumnNode extends ASTNode implements DataType {
|
||||
private Token name;
|
||||
private Token type;
|
||||
private List<Token> constraint;
|
||||
|
|
@ -16,6 +15,7 @@ public class FunctionColumnNode extends ASTNode implements ColumnType {
|
|||
public FunctionColumnNode() {
|
||||
super();
|
||||
setTokens(new ArrayList<>());
|
||||
setInOut(new ArrayList<>());
|
||||
}
|
||||
|
||||
public FunctionColumnNode(ASTNode node) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class FunctionNameNode extends ASTNode {
|
|||
|
||||
@Override
|
||||
public void visit(ASTNode node, StringBuilder queryString) {
|
||||
queryString.append(toString() + " ");
|
||||
queryString.append(toString() + " ( ");
|
||||
for (ASTNode child : node.getChildren()) {
|
||||
child.visit(child, queryString);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package Parser.AST.Function;
|
||||
|
||||
import Interface.DataType;
|
||||
import Lexer.Token;
|
||||
import Parser.AST.ASTNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FunctionRetDefNode extends ASTNode {
|
||||
public class FunctionRetDefNode extends ASTNode implements DataType {
|
||||
private Token type;
|
||||
public FunctionRetDefNode() {
|
||||
super();
|
||||
setTokens(new ArrayList<>());
|
||||
|
|
@ -22,9 +24,28 @@ public class FunctionRetDefNode extends ASTNode {
|
|||
|
||||
@Override
|
||||
public void visit(ASTNode node, StringBuilder queryString) {
|
||||
queryString.append(toString() + " ");
|
||||
queryString.append(") " + toString() + " ");
|
||||
for (ASTNode child : node.getChildren()) {
|
||||
child.visit(child, queryString);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(Token type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ResetTokensbyNameTypeConstraint() {
|
||||
List <Token> tokens = new ArrayList<>();
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "RETURN"));
|
||||
tokens.add(type);
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "IS"));
|
||||
setTokens(tokens);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
package Parser.AST.Procedure;
|
||||
|
||||
import Interface.ColumnType;
|
||||
import Interface.DataType;
|
||||
import Lexer.Token;
|
||||
import Parser.AST.ASTNode;
|
||||
import Parser.AST.CreateTable.CRTEndNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ProcedureColumnNode extends ASTNode implements ColumnType {
|
||||
public class ProcedureColumnNode extends ASTNode implements DataType {
|
||||
private Token name;
|
||||
private Token type;
|
||||
private List<Token> constraint;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import Parser.AST.Drop.DropObjNameNode;
|
|||
import Parser.AST.Drop.DropNode;
|
||||
import Parser.AST.Drop.DropOptionNode;
|
||||
import Parser.AST.Exception.*;
|
||||
import Parser.AST.Function.*;
|
||||
import Parser.AST.IFELSIF.*;
|
||||
import Parser.AST.Insert.InsertDataNode;
|
||||
import Parser.AST.Insert.InsertEndNode;
|
||||
|
|
@ -80,6 +81,12 @@ public class OracleParser {
|
|||
)
|
||||
{
|
||||
return parseProcedure(lexer.getTokens());
|
||||
} else if (
|
||||
(lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("FUNCTION"))
|
||||
|| (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("FUNCTION"))
|
||||
)
|
||||
{
|
||||
return parseFunction(lexer.getTokens());
|
||||
}
|
||||
else {
|
||||
try {
|
||||
|
|
@ -1859,7 +1866,8 @@ public class OracleParser {
|
|||
childNode = new ProcedureEndNode();
|
||||
for (int j = index; j < parseTokens.size(); j++) {
|
||||
childNode.addToken(parseTokens.get(j));
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.EOF)) {
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1872,7 +1880,8 @@ public class OracleParser {
|
|||
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)) {
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1897,4 +1906,240 @@ public class OracleParser {
|
|||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create FUNCTION
|
||||
* Grammar: CREATE OR REPLACE FUNCTION function_name (
|
||||
* parameter1 [IN | OUT] datatype1 ,
|
||||
* parameter2 [IN | OUT] datatype2 ,
|
||||
* ...
|
||||
* ) RETURN return_datatype IS
|
||||
* BEGIN
|
||||
* -- function body
|
||||
* RETURN result;
|
||||
* END;
|
||||
* /
|
||||
* Example: CREATE OR REPLACE FUNCTION string_length (
|
||||
* input_string VARCHAR2
|
||||
* ) RETURN NUMBER IS
|
||||
* BEGIN
|
||||
* RETURN LENGTH(input_string);
|
||||
* END;
|
||||
* /
|
||||
*/
|
||||
private ASTNode parseFunction(List<Token> parseTokens) {
|
||||
ASTNode root = new FunctionNode();
|
||||
ASTNode currentNode = root;
|
||||
for (int i = 0; i < parseTokens.size(); i++) {
|
||||
// CREATE [OR REPLACE] FUNCTION
|
||||
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("FUNCTION")) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// match function name
|
||||
else if (currentNode == root && parseTokens.get(i).hasType(Token.TokenType.IDENTIFIER)) {
|
||||
ASTNode childNode = new FunctionNameNode();
|
||||
childNode.addToken(parseTokens.get(i));
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
i++;
|
||||
}
|
||||
// match parameters
|
||||
else if (currentNode instanceof FunctionNameNode && parseTokens.get(i).hasType(Token.TokenType.IDENTIFIER)) {
|
||||
for (int ii = i; ii < parseTokens.size(); ii++) {
|
||||
if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("RETURN")) {
|
||||
i = ii - 1;
|
||||
break;
|
||||
}
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
FunctionColumnNode child = new FunctionColumnNode();
|
||||
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 return definition
|
||||
else if (currentNode instanceof FunctionColumnNode && parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("RETURN")) {
|
||||
FunctionRetDefNode childNode = new FunctionRetDefNode();
|
||||
for (int j = i; j < parseTokens.size(); j++) {
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("RETURN")) {
|
||||
childNode.addToken(parseTokens.get(j));
|
||||
}
|
||||
else if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equals("IS")) {
|
||||
childNode.addToken(parseTokens.get(j));
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
childNode.addToken(parseTokens.get(j));
|
||||
childNode.setType(parseTokens.get(j));
|
||||
}
|
||||
}
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
}
|
||||
// match function begin
|
||||
else if (currentNode instanceof FunctionRetDefNode && parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("BEGIN")) {
|
||||
ASTNode childNode = new FunctionBeginNode();
|
||||
childNode.addToken(parseTokens.get(i));
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
}
|
||||
// match function body
|
||||
else if (currentNode instanceof FunctionBeginNode) {
|
||||
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 if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("RETURN")) {
|
||||
ASTNode childNode = new FunctionReturnNode();
|
||||
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;
|
||||
}
|
||||
else {
|
||||
ASTNode childNode = new FunctionBodyNode();
|
||||
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 function end
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("END")) {
|
||||
ASTNode childNode = new FunctionEndNode();
|
||||
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;
|
||||
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