Merge branch 'pr-2184'

[plsql] Fix DDLCommands parsing
This commit is contained in:
Andreas Dangel
2020-01-05 19:20:29 +01:00
4 changed files with 73 additions and 25 deletions

View File

@ -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>

View File

@ -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());
}
}

View File

@ -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';