Merge branch 'pr-2184'
[plsql] Fix DDLCommands parsing
This commit is contained in:
@ -227,6 +227,9 @@ public class PLSQLParser {
|
||||
/**
|
||||
* Semantic lookahead to check if the next identifier is a
|
||||
* specific keyword.
|
||||
*
|
||||
* <p>
|
||||
* Usage: <code>LOOKAHEAD({isKeyword("WAIT")}) KEYWORD("WAIT")</code>
|
||||
*/
|
||||
private boolean isKeyword(String keyword) {
|
||||
return getToken(1).kind == IDENTIFIER && getToken(1).image.equalsIgnoreCase(keyword);
|
||||
@ -259,13 +262,13 @@ ASTInput Input(String sourcecode) : {}
|
||||
| LOOKAHEAD(6) Directory()
|
||||
| LOOKAHEAD(6) DatabaseLink()
|
||||
| LOOKAHEAD(6) Global()
|
||||
| LOOKAHEAD(6) DDLCommand() //Ignore any other DDL Event
|
||||
| (LOOKAHEAD(6) DDLCommand())+
|
||||
| LOOKAHEAD(2) SqlPlusCommand()
|
||||
| UpdateStatement()
|
||||
| DeleteStatement()
|
||||
| InsertStatement()
|
||||
| SelectStatement() (";")?
|
||||
|(<COMMIT>|<ROLLBACK>|<SAVEPOINT>|<LOCK><TABLE>|<MERGE>|<WITH>) SkipPastNextTokenOccurrence(SQLPLUS_TERMINATOR) //Ignore SQL statements in scripts
|
||||
| SelectStatement() [";"]
|
||||
|(<COMMIT>|<ROLLBACK>|<SAVEPOINT>|<LOCK><TABLE>|<MERGE>|<WITH>) ReadPastNextOccurrence(";") //Ignore SQL statements in scripts
|
||||
)
|
||||
("/")*
|
||||
)*
|
||||
@ -279,8 +282,15 @@ ASTDDLCommand DDLCommand() :
|
||||
}
|
||||
{
|
||||
(
|
||||
simpleNode = DDLEvent()
|
||||
SkipPastNextTokenOccurrence(SQLPLUS_TERMINATOR)
|
||||
(
|
||||
LOOKAHEAD({isKeyword("COMMENT")})
|
||||
simpleNode = Comment()
|
||||
)
|
||||
|
|
||||
(
|
||||
simpleNode = DDLEvent()
|
||||
ReadPastNextOccurrence(";")
|
||||
)
|
||||
)
|
||||
{ jjtThis.setImage(simpleNode.getImage()) ; return jjtThis ; }
|
||||
}
|
||||
@ -315,7 +325,7 @@ ASTSqlPlusCommand SqlPlusCommand() :
|
||||
| <VARIABLE>
|
||||
| <WHENEVER>
|
||||
// DDL that might be encountered
|
||||
| <COMMENT>
|
||||
| LOOKAHEAD({isKeyword("COMMENT")}) KEYWORD("COMMENT")
|
||||
| <GRANT>
|
||||
| <REVOKE>
|
||||
| <DROP>
|
||||
@ -1121,6 +1131,7 @@ ASTRead2NextOccurrence Read2NextOccurrence(String target) :
|
||||
{
|
||||
nextToken = getNextToken();
|
||||
sb.append(nextToken.image);
|
||||
sb.append(' ');
|
||||
nextToken = getToken(1);
|
||||
}
|
||||
}
|
||||
@ -1133,10 +1144,11 @@ ASTRead2NextOccurrence Read2NextOccurrence(String target) :
|
||||
*/
|
||||
ASTReadPastNextOccurrence ReadPastNextOccurrence(String target) :
|
||||
{
|
||||
ASTRead2NextOccurrence skipped = Read2NextOccurrence(target);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Token t = null;
|
||||
sb.append(Read2NextOccurrence(target)) ;
|
||||
t = getNextToken(); // Chomp this one
|
||||
sb.append(skipped.getImage()) ;
|
||||
Token t = getNextToken(); // Chomp this one
|
||||
sb.append(t.image);
|
||||
}
|
||||
{
|
||||
@ -3860,19 +3872,22 @@ ASTViewColumn ViewColumn() :
|
||||
{ return jjtThis ; }
|
||||
}
|
||||
|
||||
/**
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/COMMENT.html#GUID-65F447C4-6914-4823-9691-F15D52DB74D7
|
||||
*/
|
||||
ASTComment Comment() :
|
||||
{
|
||||
}
|
||||
{
|
||||
<COMMENT> <ON> (
|
||||
LOOKAHEAD({isKeyword("COMMENT")}) KEYWORD("COMMENT") { jjtThis.setImage(token.image); }
|
||||
<ON> (
|
||||
((<TABLE> | <OPERATOR> | <INDEXTYPE>) [LOOKAHEAD(2) ID()"."] ID()) |
|
||||
(<COLUMN> [LOOKAHEAD(ID()"."ID()"."ID()) ID()"."] ID() "." ID())
|
||||
)
|
||||
<IS> <STRING_LITERAL>
|
||||
[";"]
|
||||
{ return jjtThis ; }
|
||||
<IS> StringLiteral()
|
||||
";"
|
||||
{ return jjtThis ; }
|
||||
}
|
||||
// SRT * /
|
||||
|
||||
|
||||
|
||||
@ -4445,23 +4460,26 @@ ASTNonDMLTrigger NonDMLTrigger() :
|
||||
{ return jjtThis ; }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Types-of-SQL-Statements.html#GUID-FD9A8CB4-6B9A-44E5-B114-EFB8DA76FC88
|
||||
*/
|
||||
ASTDDLEvent DDLEvent(): {}
|
||||
{
|
||||
( <ALTER>
|
||||
| <ANALYZE>
|
||||
| <ASSOCIATE> <STATISTICS>
|
||||
| <AUDIT>
|
||||
| <COMMENT>
|
||||
| LOOKAHEAD({isKeyword("COMMENT")}) KEYWORD("COMMENT")
|
||||
| <CREATE>
|
||||
| <DISASSOCIATE> <STATISTICS>
|
||||
| <DROP>
|
||||
// | <FLASHBACK>
|
||||
| <GRANT>
|
||||
| <NOAUDIT>
|
||||
// | <PURGE>
|
||||
| <RENAME>
|
||||
| <REVOKE>
|
||||
| <TRUNCATE>
|
||||
| <DDL>
|
||||
)
|
||||
{ jjtThis.setImage(token.toString()) ; jjtThis.value = token ; return jjtThis ; }
|
||||
}
|
||||
@ -4697,7 +4715,6 @@ TOKEN [IGNORE_CASE]:
|
||||
<COALESCE: "COALESCE"> |
|
||||
<COLLECT: "COLLECT"> |
|
||||
<COLUMN: "COLUMN"> |
|
||||
<COMMENT: "COMMENT"> |
|
||||
<COMMIT: "COMMIT"> |
|
||||
<CONSTANT: "CONSTANT"> |
|
||||
<CONSTRAINT: "CONSTRAINT"> |
|
||||
@ -4953,7 +4970,6 @@ TOKEN [IGNORE_CASE]:
|
||||
| <COMPOUND: "COMPOUND"> //11G Trigger Syntax
|
||||
| <DATABASE: "DATABASE"> //11G Trigger Syntax
|
||||
| <CALL: "CALL"> //11G Trigger Syntax
|
||||
| <DDL: "DDL"> //11G Trigger Syntax
|
||||
| <DISASSOCIATE: "DISASSOCIATE"> //11G Trigger Syntax
|
||||
| <EACH: "EACH"> //11G Trigger Syntax
|
||||
| <FOLLOWS: "FOLLOWS"> //11G Trigger Syntax
|
||||
@ -5082,8 +5098,6 @@ TOKEN :
|
||||
< JAVA_INTERFACE_CLASS: ( "SQLData" | "CustomDatum" | "OraData" ) >
|
||||
//|
|
||||
//< #BOOLEAN_LITERAL: "TRUE" | "FALSE" >
|
||||
|
|
||||
<SQLPLUS_TERMINATOR: ( ";" | "/" ) >
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5360,7 +5374,6 @@ ASTKEYWORD_UNRESERVED KEYWORD_UNRESERVED (): {}
|
||||
//| <COLUMN_STATS>
|
||||
//| <COLUMN_VALUE>
|
||||
//| <COLUMNS>
|
||||
| <COMMENT>
|
||||
| <COMMIT>
|
||||
//| <COMMITTED>
|
||||
//| <COMPACT>
|
||||
@ -5421,7 +5434,6 @@ ASTKEYWORD_UNRESERVED KEYWORD_UNRESERVED (): {}
|
||||
//| <DBA_RECYCLEBIN>
|
||||
//| <DBMS_STATS>
|
||||
| <DBTIMEZONE>
|
||||
| <DDL>
|
||||
//| <DEALLOCATE>
|
||||
//| <DEBUG>
|
||||
| <DEC>
|
||||
@ -6326,7 +6338,7 @@ ASTID ID(): {}
|
||||
| KEYWORD_UNRESERVED() //SRT 2011-04-17
|
||||
/*KEYWORDS_UNRESERVED
|
||||
|<EXTRACT> | <FALSE> | <TRUE> | <SECOND> | <MINUTE> | <HOUR> | <DAY> | <MONTH> | <YEAR>
|
||||
| <NO> |<ROW> | <COMMENT> | <CURSOR>
|
||||
| <NO> |<ROW> | <CURSOR>
|
||||
*/
|
||||
//20120501 | <DEFINER>
|
||||
| <SERIALLY_REUSABLE> | <RESTRICT_REFERENCES>
|
||||
@ -6589,7 +6601,6 @@ ASTQualifiedID QualifiedID(): {}
|
||||
//<CLUSTER>
|
||||
//| <COALESCE>
|
||||
//20120501 | <COLLECT>
|
||||
//| <COMMENT>
|
||||
//| <COMMIT>
|
||||
//<COMPRESS>
|
||||
//<CONNECT>
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.plsql.ast;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst;
|
||||
|
||||
public class MultipleDDLStatementsTest extends AbstractPLSQLParserTst {
|
||||
|
||||
@Test
|
||||
public void parseDDLCommands() throws Exception {
|
||||
String code = IOUtils.toString(this.getClass().getResourceAsStream("DDLCommands.sql"),
|
||||
StandardCharsets.UTF_8);
|
||||
ASTInput input = parsePLSQL(code);
|
||||
List<ASTDDLCommand> ddlcommands = input.findDescendantsOfType(ASTDDLCommand.class);
|
||||
Assert.assertEquals(4, ddlcommands.size());
|
||||
List<ASTComment> comments = input.findDescendantsOfType(ASTComment.class);
|
||||
Assert.assertEquals(3, comments.size());
|
||||
Assert.assertEquals("'abbreviated job title'", comments.get(0).getFirstChildOfType(ASTStringLiteral.class).getImage());
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
COMMENT ON COLUMN employees.job_id IS 'abbreviated job title';
|
||||
|
||||
COMMENT ON COLUMN employees.job_id IS 'abbreviated job title';
|
||||
|
||||
DROP TABLE employees;
|
||||
|
||||
COMMENT ON COLUMN employees.job_id IS 'abbreviated job title';
|
Reference in New Issue
Block a user