This commit is contained in:
XudongXie 2024-09-13 21:30:41 +08:00
parent c10d92fae6
commit c4cec7795c
6 changed files with 159 additions and 67 deletions

View File

@ -4,7 +4,14 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add view document" />
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add ast class of view">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" 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/View/ViewEndNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/View/ViewEndNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/View/ViewNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/View/ViewCreateNode.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" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@ -13,8 +20,8 @@
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Class" />
<option value="Interface" />
<option value="Class" />
</list>
</option>
</component>
@ -101,20 +108,6 @@
<option name="presentableId" value="Default" />
<updated>1723106789329</updated>
</task>
<task id="LOCAL-00010" summary="add parser function">
<created>1724166047929</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1724166047929</updated>
</task>
<task id="LOCAL-00011" summary="add function">
<created>1724338301831</created>
<option name="number" value="00011" />
<option name="presentableId" value="LOCAL-00011" />
<option name="project" value="LOCAL" />
<updated>1724338301831</updated>
</task>
<task id="LOCAL-00012" summary="add function">
<created>1724419179050</created>
<option name="number" value="00012" />
@ -444,7 +437,21 @@
<option name="project" value="LOCAL" />
<updated>1726214965146</updated>
</task>
<option name="localTasksCounter" value="59" />
<task id="LOCAL-00059" summary="add keywords of view">
<created>1726215246855</created>
<option name="number" value="00059" />
<option name="presentableId" value="LOCAL-00059" />
<option name="project" value="LOCAL" />
<updated>1726215246856</updated>
</task>
<task id="LOCAL-00060" summary="add ast class of view">
<created>1726215657277</created>
<option name="number" value="00060" />
<option name="presentableId" value="LOCAL-00060" />
<option name="project" value="LOCAL" />
<updated>1726215657277</updated>
</task>
<option name="localTasksCounter" value="61" />
<servers />
</component>
<component name="Vcs.Log.Tabs.Properties">
@ -459,8 +466,6 @@
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="add insert sql" />
<MESSAGE value="add todolist" />
<MESSAGE value="add select" />
<MESSAGE value="add case when" />
<MESSAGE value="add pattern of functions in select" />
@ -484,7 +489,9 @@
<MESSAGE value="add alter" />
<MESSAGE value="fix some bugs" />
<MESSAGE value="add view document" />
<option name="LAST_COMMIT_MESSAGE" value="add view document" />
<MESSAGE value="add keywords of view" />
<MESSAGE value="add ast class of view" />
<option name="LAST_COMMIT_MESSAGE" value="add ast class of view" />
</component>
<component name="XDebuggerManager">
<watches-manager>

View File

@ -18,7 +18,7 @@ public class OracleLexer {
// keywords of drop table
, "DROP", "CASCADE"
// keywords of select
, "DISTINCT", "JOIN", "GROUP BY", "ORDER BY", "HAVING", "UNION", "CASE", "WHEN", "END", "AS"
, "DISTINCT", "JOIN", "GROUP BY", "ORDER BY", "HAVING", "UNION", "CASE", "WHEN", "END", "AS", "||"
// keywords of join
, "INNER JOIN", "LEFT JOIN", "LEFT OUTER JOIN", "RIGHT JOIN", "RIGHT OUTER JOIN", "FULL JOIN", "FULL OUTER JOIN", "CROSS JOIN", "JOIN", "ON", "USING"
// keywords of case when
@ -45,6 +45,7 @@ public class OracleLexer {
"(AVG\\(.*?\\))|" + // AVG() function
"(MAX\\(.*?\\))|" + // MAX() function
"(MIN\\(.*?\\))|" + // MIN() function
"(\\|\\|\\s*'.*?'\\s*\\|\\|)|" + // || '*' ||
"(NOT NULL)|" +
"(PRIMARY KEY)|" +
@ -66,6 +67,7 @@ public class OracleLexer {
"(FULL JOIN)|" +
"(FULL OUTER JOIN)|" +
"(CROSS JOIN)|" +
"(\\|\\|)|" +
"(\\b[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*\\b)|" + // Keywords and identifiers
@ -122,40 +124,43 @@ public class OracleLexer {
else if (tokenValue.matches("(?i)NUMBER\\(.*?\\)")) {
// NUMBER() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)DECIMAL\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)DECIMAL\\(.*?\\)")) {
// DECIMAL() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)FLOAT\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)FLOAT\\(.*?\\)")) {
// FLOAT() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)CHAR\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)CHAR\\(.*?\\)")) {
// CHAR() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)VARCHAR2\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)VARCHAR2\\(.*?\\)")) {
// VARCHAR2() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)NCHAR\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)NCHAR\\(.*?\\)")) {
// NCHAR() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)NVARCHAR2\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)NVARCHAR2\\(.*?\\)")) {
// NVARCHAR2() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)RAW\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)RAW\\(.*?\\)")) {
// RAW() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)COUNT\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)COUNT\\(.*?\\)")) {
// RAW() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)SUM\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)SUM\\(.*?\\)")) {
// RAW() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)AVG\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)AVG\\(.*?\\)")) {
// RAW() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)MAX\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)MAX\\(.*?\\)")) {
// RAW() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}else if (tokenValue.matches("(?i)MIN\\(.*?\\)")) {
} else if (tokenValue.matches("(?i)MIN\\(.*?\\)")) {
// RAW() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("\\|\\|\\s*'.*?'\\s*\\|\\|")) {
// RAW() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
}

View File

@ -30,8 +30,9 @@ public class Main {
// " FROM departments d\n" +
// " WHERE d.department_name = 'Sales'\n" +
// ");";
String sql = "ALTER TABLE employees ADD email VARCHAR2(100) Check (email != '12813@163.com');";
// 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 ON e.department_id = d.department_id;";
OracleLexer lexer = new OracleLexer(sql);
lexer.printTokens();
OracleParser parser = new OracleParser(lexer);

View File

@ -5,12 +5,17 @@ import Parser.AST.ASTNode;
import java.util.List;
public class ViewNode extends ASTNode {
public ViewNode(ASTNode node) {
public class ViewCreateNode extends ASTNode {
public ViewCreateNode() {
super();
}
public ViewCreateNode(ASTNode node) {
super(node);
}
public ViewNode(List<Token> tokens) {
public ViewCreateNode(List<Token> tokens) {
super(tokens);
}

View File

@ -6,6 +6,10 @@ import Parser.AST.ASTNode;
import java.util.List;
public class ViewEndNode extends ASTNode {
public ViewEndNode() {
super();
}
public ViewEndNode(ASTNode node) {
super(node);
}

View File

@ -25,6 +25,10 @@ import Parser.AST.Insert.InsertObjNode;
import Parser.AST.Join.*;
import Parser.AST.Select.*;
import Parser.AST.Update.*;
import Parser.AST.View.ViewCreateNode;
import Parser.AST.View.ViewEndNode;
import Parser.AST.View.ViewNameNode;
import Parser.AST.View.ViewTargetNode;
import java.util.Stack;
@ -38,38 +42,41 @@ public class OracleParser {
}
public ASTNode parse()
{
// check if the input is a create table statement
if ((lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("TABLE")) ||
(lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(2).getValue().equalsIgnoreCase("TEMPORARY") && lexer.getTokens().get(3).getValue().equalsIgnoreCase("TABLE")) ) {
return parseCreateTab(lexer.getTokens());
}
else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("INSERT")) {
return parseInsert(lexer.getTokens());
}
else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("DROP")) {
return parseDrop(lexer.getTokens());
}
else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("SELECT")) {
return parseSelect(lexer.getTokens());
}
else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("UPDATE")) {
return parseUpdate(lexer.getTokens());
}
else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("DELETE")) {
return parseDelete(lexer.getTokens());
}
else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("ALTER")) {
return parseAlterTable(lexer.getTokens());
}
else {
try {
throw new ParseFailedException("Parse failed!--Unsupport SQL:" + lexer.getTokens().get(0).getValue());
try {
// check if the input is a create table statement
if ((lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("TABLE")) ||
(lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(2).getValue().equalsIgnoreCase("TEMPORARY") && lexer.getTokens().get(3).getValue().equalsIgnoreCase("TABLE"))) {
return parseCreateTab(lexer.getTokens());
} else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("INSERT")) {
return parseInsert(lexer.getTokens());
} else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("DROP")) {
return parseDrop(lexer.getTokens());
} else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("SELECT")) {
return parseSelect(lexer.getTokens());
} else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("UPDATE")) {
return parseUpdate(lexer.getTokens());
} else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("DELETE")) {
return parseDelete(lexer.getTokens());
} else if (lexer.getTokens().get(0).getValue().equalsIgnoreCase("ALTER")) {
return parseAlterTable(lexer.getTokens());
} else if (
(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("VIEW"))
|| (lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("VIEW"))
) {
return parseCreateView(lexer.getTokens());
} else {
try {
throw new ParseFailedException("Parse failed!--Unsupport SQL:" + lexer.getTokens().get(0).getValue());
} catch (ParseFailedException e) {
e.printStackTrace();
}
return null;
}
catch (ParseFailedException e) {
e.printStackTrace();
}
return null;
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
@ -1210,5 +1217,68 @@ public class OracleParser {
return root;
}
/**
* Create view
* Grammar: CREATE [OR REPLACE] VIEW view_name [(column_name [, column_name]...)] AS SELECT_statement;
* Example: CREATE OR REPLACE VIEW employee_details (full_name, pay)
* AS SELECT first_name, last_name, salary FROM employees;
*/
private ASTNode parseCreateView(List<Token> parseTokens) {
List<Token> tokens = new ArrayList<>();
ASTNode root = new ViewCreateNode();
ASTNode currentNode = root;
for (int i = 0; i < parseTokens.size(); i++) {
if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("CREATE")) {
tokens.add(parseTokens.get(i));
}
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("OR")) {
tokens.add(parseTokens.get(i));
}
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("REPLACE")) {
tokens.add(parseTokens.get(i));
}
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("VIEW")) {
tokens.add(parseTokens.get(i));
root.setTokens(tokens);
}
else if (parseTokens.get(i).hasType(Token.TokenType.IDENTIFIER) && currentNode instanceof ViewCreateNode) {
tokens = new ArrayList<>();
for (int j = i; j < parseTokens.size(); j++) {
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("AS")) {
i = j - 1;
break;
}
tokens.add(parseTokens.get(j));
}
ASTNode childNode = new ViewNameNode(tokens);
currentNode.addChild(childNode);
currentNode = childNode;
}
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("AS")) {
tokens = new ArrayList<>();
tokens.add(parseTokens.get(i));
ASTNode childNode = new ViewTargetNode(tokens);
currentNode.addChild(childNode);
currentNode = childNode;
tokens = parseTokens.subList(i + 1, parseTokens.size());
ASTNode selectRootNode = parseSelect(tokens);
currentNode.addChild(selectRootNode);
currentNode = selectRootNode.getDeepestChild();
ASTNode viewEndNode = new ViewEndNode();
currentNode.addChild(viewEndNode);
currentNode = viewEndNode;
break;
}
else {
try {
throw new ParseFailedException("Failed to parse:" + parseTokens.get(i));
}
catch (ParseFailedException e) {
e.printStackTrace();
}
}
}
return root;
}
}