add trigger

This commit is contained in:
XudongXie 2024-09-18 00:53:17 +08:00
parent fe805b9721
commit 8a8b13c793
3 changed files with 176 additions and 16 deletions

View File

@ -4,12 +4,10 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add trigger document">
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Trigger/TriggerConditionNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Trigger/TriggerNameNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Trigger/TriggerNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Trigger/TriggerObjNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Trigger/TriggerOptionNode.java" afterDir="false" />
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add trigger 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/Lexer/OracleLexer.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Lexer/OracleLexer.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" />
@ -107,13 +105,6 @@
<option name="presentableId" value="Default" />
<updated>1723106789329</updated>
</task>
<task id="LOCAL-00038" summary="add join class">
<created>1726112198383</created>
<option name="number" value="00038" />
<option name="presentableId" value="LOCAL-00038" />
<option name="project" value="LOCAL" />
<updated>1726112198384</updated>
</task>
<task id="LOCAL-00039" summary="add join">
<created>1726127728384</created>
<option name="number" value="00039" />
@ -450,7 +441,14 @@
<option name="project" value="LOCAL" />
<updated>1726588739459</updated>
</task>
<option name="localTasksCounter" value="87" />
<task id="LOCAL-00087" summary="add trigger ast classes">
<created>1726590115566</created>
<option name="number" value="00087" />
<option name="presentableId" value="LOCAL-00087" />
<option name="project" value="LOCAL" />
<updated>1726590115566</updated>
</task>
<option name="localTasksCounter" value="88" />
<servers />
</component>
<component name="Vcs.Log.Tabs.Properties">
@ -465,7 +463,6 @@
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="fix some bugs" />
<MESSAGE value="add view document" />
<MESSAGE value="add keywords of view" />
<MESSAGE value="add ast class of view" />
@ -490,7 +487,8 @@
<MESSAGE value="add ast classes of function" />
<MESSAGE value="add function" />
<MESSAGE value="add trigger document" />
<option name="LAST_COMMIT_MESSAGE" value="add trigger document" />
<MESSAGE value="add trigger ast classes" />
<option name="LAST_COMMIT_MESSAGE" value="add trigger ast classes" />
</component>
<component name="XDebuggerManager">
<watches-manager>

View File

@ -39,6 +39,8 @@ public class OracleLexer {
, "PROCEDURE", "IS", "IN", "OUT", "$$", "COMMIT", "ROLLBACK", "EXEC", "EXECUTE"
// function
, "FUNCTION", "RETURN"
// trigger
, "TRIGGER", "BEFORE", "AFTER", "INSTEAD OF", "REFERENCING", "NEW", "OLD", "EACH", "ROW"
};
private static final Pattern TOKEN_PATTERN = Pattern.compile(
"(NUMBER\\(.*?\\))|" + // NUMBER() function
@ -79,6 +81,7 @@ public class OracleLexer {
"(FULL JOIN)|" +
"(FULL OUTER JOIN)|" +
"(CROSS JOIN)|" +
"(INSTEAD OF)|" +
"(\\|\\|)|" +
"(:=)|" +
"(\\.\\.)|" +

View File

@ -29,6 +29,7 @@ import Parser.AST.Join.*;
import Parser.AST.Loop.*;
import Parser.AST.Procedure.*;
import Parser.AST.Select.*;
import Parser.AST.Trigger.*;
import Parser.AST.Update.*;
import Parser.AST.View.ViewCreateNode;
import Parser.AST.View.ViewEndNode;
@ -87,6 +88,12 @@ public class OracleParser {
)
{
return parseFunction(lexer.getTokens());
} else if (
(lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("TRIGGER"))
|| (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("TRIGGER"))
)
{
return parseTrigger(lexer.getTokens());
}
else {
try {
@ -2141,5 +2148,157 @@ public class OracleParser {
return root;
}
/**
* Create TRIGGER
* Grammar: CREATE OR REPLACE TRIGGER trigger_name
* BEFORE | AFTER | INSTEAD OF -- OpenGauss does not support INSTEAD OF
* { INSERT | UPDATE | DELETE }
* ON table_name
* [REFERENCING NEW AS new OLD AS old] -- OpenGauss does not support this
* FOR EACH ROW
* [WHEN (condition)]
* BEGIN
* -- trigger body
* END;
* Example: CREATE OR REPLACE TRIGGER log_insert
* BEFORE INSERT ON employees
* FOR EACH ROW
* BEGIN
* INSERT INTO audit_log (action, employee_id) VALUES ('INSERT', :NEW.id);
* END;
*/
private ASTNode parseTrigger(List<Token> parseTokens) {
ASTNode root = new TriggerNode();
ASTNode currentNode = root;
for (int i = 0; i < parseTokens.size(); i++) {
// match create trigger
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("TRIGGER")) {
i = j;
break;
}
}
}
// match trigger name
else if (currentNode == root && parseTokens.get(i).hasType(Token.TokenType.IDENTIFIER)) {
ASTNode childNode = new TriggerNameNode();
childNode.addToken(parseTokens.get(i));
currentNode.addChild(childNode);
currentNode = childNode;
}
// match trigger condition
else if (currentNode instanceof TriggerNameNode && (
parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("BEFORE") ||
parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("AFTER") ||
parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("INSTEAD OF")
)) {
if (i + 1 < parseTokens.size() && (
parseTokens.get(i + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i + 1).getValue().equalsIgnoreCase("INSERT") ||
parseTokens.get(i + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i + 1).getValue().equalsIgnoreCase("UPDATE") ||
parseTokens.get(i + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i + 1).getValue().equalsIgnoreCase("DELETE")
)) {
TriggerConditionNode childNode = new TriggerConditionNode();
childNode.setCondition(parseTokens.get(i));
childNode.setAction(parseTokens.get(i + 1));
}
else {
try {
throw new ParseFailedException("There exists syntax error!");
} catch (ParseFailedException e) {
e.printStackTrace();
}
}
}
// match trigger on table
else if (currentNode instanceof TriggerConditionNode && parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("ON")) {
if (i + 1 < parseTokens.size() && parseTokens.get(i + 1).hasType(Token.TokenType.IDENTIFIER)) {
ASTNode childNode = new TriggerObjNode();
childNode.addToken(parseTokens.get(i));
childNode.addToken(parseTokens.get(i + 1));
currentNode.addChild(childNode);
currentNode = childNode;
i++;
}
else {
try {
throw new ParseFailedException("There exists syntax error!");
} catch (ParseFailedException e) {
e.printStackTrace();
}
}
}
// match [REFERENCING NEW AS new OLD AS old]
else if (currentNode instanceof TriggerObjNode && parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("REFERENCING")) {
ASTNode childNode = new TriggerOptionNode();
for (int j = i; j < parseTokens.size(); j++) {
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("FOR")) {
i = j - 1;
break;
}
childNode.addToken(parseTokens.get(j));
}
currentNode.addChild(childNode);
currentNode = childNode;
}
// match FOR EACH ROW
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("FOR")) {
if ((i + 1 < parseTokens.size() && parseTokens.get(i + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i + 1).getValue().equalsIgnoreCase("EACH"))
&& (i + 2 < parseTokens.size() && parseTokens.get(i + 2).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i + 2).getValue().equalsIgnoreCase("ROW"))) {
ASTNode childNode = new TriggerForEachRowNode();
childNode.addToken(parseTokens.get(i));
childNode.addToken(parseTokens.get(i + 1));
childNode.addToken(parseTokens.get(i + 2));
currentNode.addChild(childNode);
currentNode = childNode;
}
else {
try {
throw new ParseFailedException("There exists syntax error!");
} catch (ParseFailedException e) {
e.printStackTrace();
}
}
}
// match when
else if (currentNode instanceof TriggerForEachRowNode && parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("WHEN")) {
ASTNode childNode = new TriggerWhenNode();
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 begin
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("BEGIN")) {
ASTNode childNode = new TriggerBeginNode();
childNode.addToken(parseTokens.get(i));
currentNode.addChild(childNode);
currentNode = childNode;
}
// match trigger body
else if (currentNode instanceof TriggerBeginNode) {
//TODO: parse trigger body
}
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;
}
}