[plsql] Refactor ExtractExpression

* Separate helper productions for datetime/xml
* Use StringLiteral for xpath and namespace
This commit is contained in:
Andreas Dangel
2020-03-05 12:02:56 +01:00
parent 69025d7522
commit 3329374214
5 changed files with 116 additions and 6 deletions

View File

@ -27,6 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* Add support for XMLROOT, improve ExtractExpression to support xml
*
* Piotr Szymanski 03/2020
*====================================================================
* Add basic support for with clause in select statements
*
* Andreas Dangel 09/2019
@ -3241,7 +3245,16 @@ ASTUnaryExpression UnaryExpression(boolean isUnarySign) #UnaryExpression(>1) :
ASTExtractExpression ExtractExpression() :
{}
{
LOOKAHEAD(4)
LOOKAHEAD(4) ExtractDatetime() { return jjtThis ; }
|
LOOKAHEAD(3) ExtractXml(jjtThis) { return jjtThis ; }
}
/**
* See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/EXTRACT-datetime.html#GUID-36E52BF8-945D-437D-9A3C-6860CABD210E
*/
void ExtractDatetime() #void : {}
{
<EXTRACT> "("
( <MONTH> | <YEAR> | <DAY> |<HOUR> | <MINUTE> | <SECOND>
| <TIMEZONE_HOUR> | <TIMEZONE_MINUTE>
@ -3254,10 +3267,17 @@ ASTExtractExpression ExtractExpression() :
|
LOOKAHEAD(Name()) Name()
) ")"
{ return jjtThis ; }
|
LOOKAHEAD(3) <EXTRACT> "(" Argument() "," Expression() ["," SchemaName() ] ")"
{ return jjtThis ; }
}
/**
* See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/EXTRACT-XML.html#GUID-593295AA-4F46-4D75-B8DC-E7BCEDB1D4D7
*/
void ExtractXml(ASTExtractExpression extractExpr) #void :
{
extractExpr.setXml();
}
{
<EXTRACT> "(" Argument() "," StringLiteral() ["," StringLiteral() ] ")"
}
ASTUnaryExpressionNotPlusMinus UnaryExpressionNotPlusMinus() #UnaryExpressionNotPlusMinus(>1) :

View File

@ -47,6 +47,7 @@
<delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTComparisonCondition.java" />
<delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTCompoundCondition.java" />
<delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTDatatype.java" />
<delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java" />
<delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTFormalParameter.java" />
<delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTIfStatement.java" />
<delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTInnerCrossJoinClause.java" />

View File

@ -0,0 +1,57 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.plsql.ast;
import java.util.List;
import net.sourceforge.pmd.annotation.InternalApi;
public final class ASTExtractExpression extends AbstractPLSQLNode {
private boolean xml;
@InternalApi
@Deprecated
public ASTExtractExpression(int id) {
super(id);
}
@InternalApi
@Deprecated
public ASTExtractExpression(PLSQLParser p, int id) {
super(p, id);
}
public Object jjtAccept(PLSQLParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
void setXml() {
xml = true;
}
public boolean isXml() {
return xml;
}
public String getXPath() {
if (xml) {
return getFirstChildOfType(ASTStringLiteral.class).getString();
}
return "";
}
public String getNamespace() {
if (xml) {
List<ASTStringLiteral> literals = findChildrenOfType(ASTStringLiteral.class);
if (literals.size() == 2) {
return literals.get(1).getString();
}
}
return "";
}
}

View File

@ -0,0 +1,26 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.plsql.ast;
import org.junit.Assert;
import org.junit.Test;
import net.sourceforge.pmd.lang.plsql.PlsqlParsingHelper;
public class ASTExtractExpressionTest {
@Test
public void testXml() {
PlsqlParsingHelper parser = PlsqlParsingHelper.JUST_PARSE;
ASTInput unit = parser.parse("SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks', "
+ "'xmlns:a=\"http://warehouse/1\" xmlns:b=\"http://warehouse/2\"') \"Number of Docks\" "
+ " FROM warehouses WHERE warehouse_spec IS NOT NULL;");
ASTExtractExpression extract = unit.getFirstDescendantOfType(ASTExtractExpression.class);
Assert.assertTrue(extract.isXml());
Assert.assertEquals("/Warehouse/Docks", extract.getXPath());
Assert.assertEquals("xmlns:a=\"http://warehouse/1\" xmlns:b=\"http://warehouse/2\"", extract.getNamespace());
}
}

View File

@ -8,7 +8,13 @@ SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks')
"Number of Docks"
FROM warehouses
WHERE warehouse_spec IS NOT NULL;
SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks', 'xmlns:a="http://warehouse/1" xmlns:b="http://warehouse/2"')
"Number of Docks"
FROM warehouses
WHERE warehouse_spec IS NOT NULL;
SELECT XMLELEMENT("Emp",
XMLFOREST(e.employee_id, e.last_name, e.salary))
"Emp Element"