[plsql] Refactor ExtractExpression
* Separate helper productions for datetime/xml * Use StringLiteral for xpath and namespace
This commit is contained in:
@ -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) :
|
||||
|
@ -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" />
|
||||
|
@ -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 "";
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
Reference in New Issue
Block a user