diff --git a/sqlTranslate/.idea/workspace.xml b/sqlTranslate/.idea/workspace.xml
index e8d02f402..be45680e5 100644
--- a/sqlTranslate/.idea/workspace.xml
+++ b/sqlTranslate/.idea/workspace.xml
@@ -4,7 +4,14 @@
-
+
+
+
+
+
+
+
+
@@ -13,8 +20,8 @@
@@ -101,20 +108,6 @@
1723106789329
-
- 1724166047929
-
-
-
- 1724166047929
-
-
- 1724338301831
-
-
-
- 1724338301831
-
1724419179050
@@ -444,7 +437,21 @@
1726214965146
-
+
+ 1726215246855
+
+
+
+ 1726215246856
+
+
+ 1726215657277
+
+
+
+ 1726215657277
+
+
@@ -459,8 +466,6 @@
-
-
@@ -484,7 +489,9 @@
-
+
+
+
diff --git a/sqlTranslate/src/main/java/Lexer/OracleLexer.java b/sqlTranslate/src/main/java/Lexer/OracleLexer.java
index c96034ca2..04e721e23 100644
--- a/sqlTranslate/src/main/java/Lexer/OracleLexer.java
+++ b/sqlTranslate/src/main/java/Lexer/OracleLexer.java
@@ -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);
}
diff --git a/sqlTranslate/src/main/java/Main.java b/sqlTranslate/src/main/java/Main.java
index ba193d911..b2bb58bed 100644
--- a/sqlTranslate/src/main/java/Main.java
+++ b/sqlTranslate/src/main/java/Main.java
@@ -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);
diff --git a/sqlTranslate/src/main/java/Parser/AST/View/ViewNode.java b/sqlTranslate/src/main/java/Parser/AST/View/ViewCreateNode.java
similarity index 67%
rename from sqlTranslate/src/main/java/Parser/AST/View/ViewNode.java
rename to sqlTranslate/src/main/java/Parser/AST/View/ViewCreateNode.java
index 397a53c66..a76923eec 100644
--- a/sqlTranslate/src/main/java/Parser/AST/View/ViewNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/View/ViewCreateNode.java
@@ -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 tokens) {
+ public ViewCreateNode(List tokens) {
super(tokens);
}
diff --git a/sqlTranslate/src/main/java/Parser/AST/View/ViewEndNode.java b/sqlTranslate/src/main/java/Parser/AST/View/ViewEndNode.java
index e4137b346..c384900c2 100644
--- a/sqlTranslate/src/main/java/Parser/AST/View/ViewEndNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/View/ViewEndNode.java
@@ -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);
}
diff --git a/sqlTranslate/src/main/java/Parser/OracleParser.java b/sqlTranslate/src/main/java/Parser/OracleParser.java
index 32d08391e..b9dd3a6a6 100644
--- a/sqlTranslate/src/main/java/Parser/OracleParser.java
+++ b/sqlTranslate/src/main/java/Parser/OracleParser.java
@@ -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 parseTokens) {
+ List 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;
+ }
}