forked from opengaussexamples/examples
add Loop
This commit is contained in:
parent
d15d4cf123
commit
f82a2acf79
|
|
@ -4,7 +4,12 @@
|
|||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add Loop keywords">
|
||||
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add Loop ast classes">
|
||||
<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/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Main.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/ASTNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/ASTNode.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" />
|
||||
|
|
@ -15,8 +20,8 @@
|
|||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Interface" />
|
||||
<option value="Class" />
|
||||
<option value="Interface" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
|
|
@ -103,13 +108,6 @@
|
|||
<option name="presentableId" value="Default" />
|
||||
<updated>1723106789329</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00022" summary="add insert sql">
|
||||
<created>1725885115923</created>
|
||||
<option name="number" value="00022" />
|
||||
<option name="presentableId" value="LOCAL-00022" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1725885115924</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00023" summary="add todolist">
|
||||
<created>1725890826442</created>
|
||||
<option name="number" value="00023" />
|
||||
|
|
@ -446,7 +444,14 @@
|
|||
<option name="project" value="LOCAL" />
|
||||
<updated>1726315219011</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="71" />
|
||||
<task id="LOCAL-00071" summary="add Loop ast classes">
|
||||
<created>1726316179151</created>
|
||||
<option name="number" value="00071" />
|
||||
<option name="presentableId" value="LOCAL-00071" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1726316179152</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="72" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
|
|
@ -461,7 +466,6 @@
|
|||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="add join" />
|
||||
<MESSAGE value="add join convert rule" />
|
||||
<MESSAGE value="refractor" />
|
||||
<MESSAGE value="add select convert rules" />
|
||||
|
|
@ -486,7 +490,8 @@
|
|||
<MESSAGE value="add IF ELSIF" />
|
||||
<MESSAGE value="add Loop document" />
|
||||
<MESSAGE value="add Loop keywords" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="add Loop keywords" />
|
||||
<MESSAGE value="add Loop ast classes" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="add Loop ast classes" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<watches-manager>
|
||||
|
|
|
|||
|
|
@ -15,15 +15,18 @@ import Parser.AST.Drop.DropOptionNode;
|
|||
import Parser.AST.Insert.InsertNode;
|
||||
import Parser.AST.Join.JoinConditionNode;
|
||||
import Parser.AST.Join.JoinSourceTabNode;
|
||||
import Parser.AST.Loop.ForNode;
|
||||
import Parser.AST.Loop.LoopBodyNode;
|
||||
import Parser.AST.Loop.LoopNode;
|
||||
import Parser.AST.Loop.WhileNode;
|
||||
import Parser.AST.Select.SelectNode;
|
||||
import Parser.AST.Select.SelectObjNode;
|
||||
import Parser.AST.Update.UpdateNode;
|
||||
import Parser.AST.Update.UpdateObjNode;
|
||||
import Parser.AST.View.ViewCreateNode;
|
||||
import Parser.OracleParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class OpenGaussGenerator {
|
||||
private ASTNode node;
|
||||
|
|
@ -63,6 +66,9 @@ public class OpenGaussGenerator {
|
|||
else if (node instanceof ViewCreateNode) {
|
||||
return GenCreateViewSQL(node);
|
||||
}
|
||||
else if (node instanceof LoopNode || node instanceof WhileNode || node instanceof ForNode) {
|
||||
return GenLoopSQL(node);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
throw new GenerateFailedException("Root node:" + node.getClass() + "(Unsupported node type!)");
|
||||
|
|
@ -123,6 +129,11 @@ public class OpenGaussGenerator {
|
|||
return node.toQueryString();
|
||||
}
|
||||
|
||||
private String GenLoopSQL(ASTNode node) {
|
||||
visitLoop(node);
|
||||
return node.toQueryString();
|
||||
}
|
||||
|
||||
private void visitCrt(ASTNode node) {
|
||||
if (node instanceof ColumnNode) {
|
||||
ColumnTypeConvert((ColumnNode) node);
|
||||
|
|
@ -162,6 +173,15 @@ public class OpenGaussGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
private void visitLoop(ASTNode node) {
|
||||
if (node instanceof LoopBodyNode) {
|
||||
PLConvert(node);
|
||||
}
|
||||
for (ASTNode child : node.getChildren()) {
|
||||
visitLoop(child);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitSelect(ASTNode node) {
|
||||
if (node instanceof JoinSourceTabNode) {
|
||||
visitJoin(node);
|
||||
|
|
@ -200,6 +220,30 @@ public class OpenGaussGenerator {
|
|||
visitCreateView(child);
|
||||
}
|
||||
}
|
||||
private void PLConvert(ASTNode node) {
|
||||
if (node.checkExistsByRegex("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
|
||||
String printObj = "";
|
||||
for (Token token: node.getTokens()) {
|
||||
if (token.getValue().matches("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
|
||||
Pattern pattern = Pattern.compile("\\(([^()]*)\\)");
|
||||
Matcher matcher = pattern.matcher(token.getValue());
|
||||
while (matcher.find()) {
|
||||
printObj = matcher.group(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "RAISE"));
|
||||
tokens.add(new Token(Token.TokenType.KEYWORD, "NOTICE"));
|
||||
tokens.add(new Token(Token.TokenType.STRING, "'%'"));
|
||||
tokens.add(new Token(Token.TokenType.SYMBOL, ","));
|
||||
tokens.add(new Token(Token.TokenType.IDENTIFIER, printObj));
|
||||
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
|
||||
node.setTokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ColumnTypeConvert(ColumnType node) {
|
||||
// type convert
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class OracleLexer {
|
|||
// keywords of view
|
||||
, "REPLACE", "VIEW"
|
||||
// PL/SQL
|
||||
, ":=", "IF", "ELSIF", "BEGIN"
|
||||
, ":=", "IF", "ELSIF", "BEGIN", ".."
|
||||
// Loop
|
||||
, "LOOP", "EXIT", "WHILE", "FOR", "IN"
|
||||
};
|
||||
|
|
@ -50,6 +50,7 @@ public class OracleLexer {
|
|||
"(MAX\\(.*?\\))|" + // MAX() function
|
||||
"(MIN\\(.*?\\))|" + // MIN() function
|
||||
"(\\|\\|\\s*'.*?'\\s*\\|\\|)|" + // || '*' ||
|
||||
"(DBMS_OUTPUT.PUT_LINE\\(.*?\\))|" + // DBMS_OUTPUT.PUT_LINE() function
|
||||
|
||||
"(NOT NULL)|" +
|
||||
"(PRIMARY KEY)|" +
|
||||
|
|
@ -73,7 +74,7 @@ public class OracleLexer {
|
|||
"(CROSS JOIN)|" +
|
||||
"(\\|\\|)|" +
|
||||
"(:=)|" +
|
||||
|
||||
"(\\.\\.)|" +
|
||||
|
||||
"(\\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
|
||||
|
|
@ -168,6 +169,9 @@ public class OracleLexer {
|
|||
} else if (tokenValue.matches("\\|\\|\\s*'.*?'\\s*\\|\\|")) {
|
||||
// RAW() function, CASE_INSENSITIVE
|
||||
return new Token(Token.TokenType.KEYWORD, tokenValue);
|
||||
} else if (tokenValue.matches("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
|
||||
// RAW() function, CASE_INSENSITIVE
|
||||
return new Token(Token.TokenType.KEYWORD, tokenValue);
|
||||
}
|
||||
|
||||
else if (isKeyword(tokenValue)) {
|
||||
|
|
@ -194,6 +198,7 @@ public class OracleLexer {
|
|||
input = input.replace(" ", " ");
|
||||
}
|
||||
input = input.replace(" (", "(");
|
||||
input = input.replace("..", " .. ");
|
||||
return input;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ import Lexer.OracleLexer;
|
|||
import Parser.AST.ASTNode;
|
||||
import Parser.OracleParser;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
|
|
@ -33,20 +36,26 @@ public class Main {
|
|||
// String sql = "ALTER TABLE employees ADD email VARCHAR2(100) Check (email != '12813@163.com');";
|
||||
// String sql = "CASE WHEN column2 > 0 THEN 'Positive' ELSE 'Non-positive' END";
|
||||
// String sql = "CREATE OR REPLACE VIEW emp_dept_info AS SELECT e.first_name, e.last_name, d.department_name FROM employees e JOIN departments d Using e.department_id = d.department_id;";
|
||||
String sql = "IF v_salary >= 100000 THEN\n" +
|
||||
" v_bonus := v_salary * 0.1;\n" +
|
||||
" ELSIF v_salary >= 50000 THEN\n" +
|
||||
" v_bonus := v_salary * 0.08;\n" +
|
||||
" ELSIF v_salary >= 30000 THEN\n" +
|
||||
" v_bonus := v_salary * 0.05;\n" +
|
||||
" ELSE\n" +
|
||||
" v_bonus := v_salary * 0.03;\n" +
|
||||
" END IF;";
|
||||
// String sql = "IF v_salary >= 100000 THEN\n" +
|
||||
// " v_bonus := v_salary * 0.1;\n" +
|
||||
// " ELSIF v_salary >= 50000 THEN\n" +
|
||||
// " v_bonus := v_salary * 0.08;\n" +
|
||||
// " ELSIF v_salary >= 30000 THEN\n" +
|
||||
// " v_bonus := v_salary * 0.05;\n" +
|
||||
// " ELSE\n" +
|
||||
// " v_bonus := v_salary * 0.03;\n" +
|
||||
// " END IF;";
|
||||
String sql = "LOOP\n" +
|
||||
" DBMS_OUTPUT.PUT_LINE(v_counter);\n" +
|
||||
" v_counter := v_counter + 1;\n" +
|
||||
" EXIT WHEN v_counter > 10;\n" +
|
||||
" END LOOP;";
|
||||
OracleLexer lexer = new OracleLexer(sql);
|
||||
lexer.printTokens();
|
||||
// OracleParser parser = new OracleParser(lexer);
|
||||
// ASTNode root = parser.parse();
|
||||
ASTNode root = OracleParser.parseIFELSE(lexer.getTokens());
|
||||
ASTNode root = OracleParser.parseLoop(lexer.getTokens());
|
||||
// ASTNode root = OracleParser.parseIFELSE(lexer.getTokens());
|
||||
// ASTNode root = OracleParser.parseCaseWhen(lexer.getTokens());
|
||||
// ASTNode root = OracleParser.parseJoin(lexer.getTokens());
|
||||
System.out.println(root.toQueryString());
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ public abstract class ASTNode {
|
|||
this.tokens = tokens;
|
||||
}
|
||||
|
||||
public boolean checkExistsByRegex (String regex) {
|
||||
return tokens.stream().anyMatch(token -> token.getValue().matches(regex));
|
||||
}
|
||||
|
||||
public void addToken(Token token) {
|
||||
tokens.add(token);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public class WhileNode extends ASTNode {
|
|||
|
||||
@Override
|
||||
public void visit(ASTNode node, StringBuilder queryString) {
|
||||
queryString.append(toString());
|
||||
queryString.append(toString() + " ");
|
||||
for (ASTNode child : getChildren())
|
||||
{
|
||||
child.visit(child, queryString);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import Parser.AST.Insert.InsertEndNode;
|
|||
import Parser.AST.Insert.InsertNode;
|
||||
import Parser.AST.Insert.InsertObjNode;
|
||||
import Parser.AST.Join.*;
|
||||
import Parser.AST.Loop.*;
|
||||
import Parser.AST.Select.*;
|
||||
import Parser.AST.Update.*;
|
||||
import Parser.AST.View.ViewCreateNode;
|
||||
|
|
@ -749,7 +750,103 @@ public class OracleParser {
|
|||
* @param parseTokens should start with LOOP | WHILE | FOR
|
||||
*/
|
||||
public static ASTNode parseLoop(List<Token> parseTokens) {
|
||||
return null;
|
||||
ASTNode root = null;
|
||||
ASTNode currentNode = null;
|
||||
for (int i = 0; i < parseTokens.size(); i++) {
|
||||
//match LOOP
|
||||
if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("LOOP")) {
|
||||
root = new LoopNode();
|
||||
root.addToken(parseTokens.get(i));
|
||||
currentNode = root;
|
||||
}
|
||||
// match WHILE condition LOOP
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("WHILE")) {
|
||||
root = new WhileNode();
|
||||
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().equals("LOOP")) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentNode = root;
|
||||
|
||||
}
|
||||
// match FOR counter IN start..stop LOOP
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("FOR")) {
|
||||
root = new ForNode();
|
||||
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().equals("LOOP")) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentNode = root;
|
||||
}
|
||||
// match END LOOP;
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("END")) {
|
||||
ASTNode childNode = new LoopEndNode();
|
||||
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;
|
||||
}
|
||||
// match EXIT WHEN condition;
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("EXIT")) {
|
||||
ASTNode childNode = new LoopExitNode();
|
||||
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;
|
||||
}
|
||||
//match LOOP BODY
|
||||
else if (
|
||||
(currentNode == root && root instanceof LoopNode)
|
||||
|| (currentNode == root && root instanceof WhileNode)
|
||||
|| (currentNode == root && root instanceof ForNode)
|
||||
) {
|
||||
ASTNode childNode = new LoopBodyNode();
|
||||
for (int j = i; j < parseTokens.size(); j++) {
|
||||
if (
|
||||
parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equals("EXIT")
|
||||
|| parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equals("END")
|
||||
) {
|
||||
i = j - 1;
|
||||
break;
|
||||
}
|
||||
childNode.addToken(parseTokens.get(j));
|
||||
if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
childNode = new LoopBodyNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parseTokens.get(i).hasType(Token.TokenType.EOF)) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
throw new ParseFailedException("Parse failed!--" + parseTokens.get(i));
|
||||
}
|
||||
catch (ParseFailedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue