forked from phoedos/pmd
[plsql] ParseException when using hierarchical query clause
Fixes #1590 * Moves function calls down to primary expression so that functions can be used in a select expression * Restrict FunctionCall to built-in functions. User defined functions are parsed as primary expressions. * Parse function name of built-in function as general ID. * The Tokens _DEFAULT, ELSE and EXCEPTION are reserved words and not available for identifiers.
This commit is contained in:
Andreas Dangel
committed by
Andreas Dangel
parent
544238244b
commit
fcba29a3b7
File diff suppressed because it is too large
Load Diff
@ -986,4 +986,9 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor {
|
||||
public Object visit(ASTValuesClause node, Object data) {
|
||||
return visit((PLSQLNode) node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTHierarchicalQueryClause node, Object data) {
|
||||
return visit((PLSQLNode) node, data);
|
||||
}
|
||||
}
|
||||
|
@ -1080,6 +1080,11 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar
|
||||
return visit((PLSQLNode) node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTHierarchicalQueryClause node, Object data) {
|
||||
return visit((PLSQLNode) node, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Treat all Executable Code
|
||||
*/
|
||||
|
@ -125,10 +125,14 @@ public class CodeFormatRule extends AbstractPLSQLRule {
|
||||
int currentLine = firstLine;
|
||||
for (int i = 0; i < parent.jjtGetNumChildren(); i++) {
|
||||
Node child = parent.jjtGetChild(i);
|
||||
String image = child.getImage();
|
||||
if (image == null && child.jjtGetNumChildren() > 0) {
|
||||
image = child.jjtGetChild(0).getImage();
|
||||
}
|
||||
if (child.getBeginLine() != currentLine) {
|
||||
addViolationWithMessage(data, child, child.getImage() + " should be on line " + currentLine);
|
||||
addViolationWithMessage(data, child, image + " should be on line " + currentLine);
|
||||
} else if (i > 0 && child.getBeginColumn() != indentation) {
|
||||
addViolationWithMessage(data, child, child.getImage() + " should begin at column " + indentation);
|
||||
addViolationWithMessage(data, child, image + " should begin at column " + indentation);
|
||||
}
|
||||
// next entry needs to be on the next line
|
||||
currentLine++;
|
||||
|
@ -8,7 +8,6 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst;
|
||||
@ -16,7 +15,6 @@ import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst;
|
||||
public class SelectExpressionsTest extends AbstractPLSQLParserTst {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void parseSelectExpression() throws Exception {
|
||||
String code = IOUtils.toString(this.getClass().getResourceAsStream("SelectExpressions.pls"),
|
||||
StandardCharsets.UTF_8);
|
||||
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst;
|
||||
|
||||
public class SelectHierarchicalTest extends AbstractPLSQLParserTst {
|
||||
|
||||
@Test
|
||||
public void parseSelectHierarchicalQueries() throws Exception {
|
||||
String code = IOUtils.toString(this.getClass().getResourceAsStream("SelectHierarchical.pls"),
|
||||
StandardCharsets.UTF_8);
|
||||
ASTInput input = parsePLSQL(code);
|
||||
Assert.assertNotNull(input);
|
||||
}
|
||||
}
|
@ -23,8 +23,12 @@ public class WhereClauseTest extends AbstractPLSQLParserTst {
|
||||
List<ASTSelectIntoStatement> selectStatements = input.findDescendantsOfType(ASTSelectIntoStatement.class);
|
||||
Assert.assertEquals(3, selectStatements.size());
|
||||
|
||||
ASTFunctionCall functionCall = selectStatements.get(2).getFirstDescendantOfType(ASTFunctionCall.class);
|
||||
Assert.assertEquals("utils.get_colname", functionCall.getImage());
|
||||
ASTFunctionCall functionCall = selectStatements.get(0).getFirstDescendantOfType(ASTFunctionCall.class);
|
||||
Assert.assertEquals("UPPER", functionCall.getImage());
|
||||
|
||||
ASTPrimaryPrefix primaryPrefix = selectStatements.get(2).getFirstDescendantOfType(ASTWhereClause.class)
|
||||
.findDescendantsOfType(ASTPrimaryPrefix.class).get(1);
|
||||
Assert.assertEquals("utils.get_colname", primaryPrefix.getImage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -4,6 +4,9 @@
|
||||
|
||||
BEGIN
|
||||
|
||||
SELECT AVG(sal)*2 INTO foo FROM bar;
|
||||
|
||||
|
||||
SELECT
|
||||
AVG(salary) * 12 "Average Sal"
|
||||
INTO some_record
|
||||
@ -14,5 +17,6 @@ SELECT
|
||||
INTO some_record
|
||||
FROM some_table;
|
||||
|
||||
|
||||
END;
|
||||
/
|
@ -0,0 +1,90 @@
|
||||
--
|
||||
-- Select statement with hierarchical queries
|
||||
--
|
||||
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6
|
||||
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__I2130004
|
||||
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Hierarchical-Queries.html#GUID-0118DF1D-B9A9-41EB-8556-C6E7D6A5A84E
|
||||
--
|
||||
|
||||
BEGIN
|
||||
|
||||
SELECT id INTO v_id
|
||||
FROM (SELECT separator_in || string_in || separator_in AS token_list FROM DUAL)
|
||||
CONNECT BY col_length <= LENGTH(string_in) - LENGTH(separator_in);
|
||||
|
||||
SELECT last_name, employee_id, manager_id
|
||||
INTO test
|
||||
FROM employees
|
||||
CONNECT BY employee_id = manager_id
|
||||
ORDER BY last_name;
|
||||
|
||||
SELECT last_name, employee_id, manager_id
|
||||
INTO test
|
||||
FROM employees
|
||||
CONNECT BY PRIOR employee_id = manager_id
|
||||
AND salary > commission_pct
|
||||
ORDER BY last_name;
|
||||
|
||||
SELECT employee_id, last_name, manager_id
|
||||
INTO test
|
||||
FROM employees
|
||||
CONNECT BY PRIOR employee_id = manager_id;
|
||||
|
||||
SELECT employee_id, last_name, manager_id, LEVEL
|
||||
INTO test
|
||||
FROM employees
|
||||
CONNECT BY PRIOR employee_id = manager_id;
|
||||
|
||||
SELECT last_name, employee_id, manager_id, LEVEL
|
||||
INTO test
|
||||
FROM employees
|
||||
START WITH employee_id = 100
|
||||
CONNECT BY PRIOR employee_id = manager_id
|
||||
ORDER SIBLINGS BY last_name;
|
||||
|
||||
SELECT last_name "Employee",
|
||||
LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path"
|
||||
INTO test
|
||||
FROM employees
|
||||
WHERE level <= 3 AND department_id = 80
|
||||
START WITH last_name = 'King'
|
||||
CONNECT BY PRIOR employee_id = manager_id AND LEVEL <= 4;
|
||||
|
||||
SELECT last_name "Employee", CONNECT_BY_ISCYCLE "Cycle",
|
||||
LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path"
|
||||
INTO test
|
||||
FROM employees
|
||||
WHERE level <= 3 AND department_id = 80
|
||||
START WITH last_name = 'King'
|
||||
CONNECT BY NOCYCLE PRIOR employee_id = manager_id AND LEVEL <= 4
|
||||
ORDER BY "Employee", "Cycle", LEVEL, "Path";
|
||||
|
||||
SELECT LTRIM(SYS_CONNECT_BY_PATH (warehouse_id,','),',')
|
||||
INTO test
|
||||
FROM
|
||||
(SELECT ROWNUM r, warehouse_id FROM warehouses)
|
||||
WHERE CONNECT_BY_ISLEAF = 1
|
||||
START WITH r = 1
|
||||
CONNECT BY r = PRIOR r + 1
|
||||
ORDER BY warehouse_id;
|
||||
|
||||
SELECT last_name "Employee", CONNECT_BY_ROOT last_name "Manager",
|
||||
LEVEL-1 "Pathlen", SYS_CONNECT_BY_PATH(last_name, '/') "Path"
|
||||
INTO test
|
||||
FROM employees
|
||||
WHERE LEVEL > 1 and department_id = 110
|
||||
CONNECT BY PRIOR employee_id = manager_id
|
||||
ORDER BY "Employee", "Manager", "Pathlen", "Path";
|
||||
|
||||
SELECT name, SUM(salary) "Total_Salary"
|
||||
INTO test
|
||||
FROM (
|
||||
SELECT CONNECT_BY_ROOT last_name as name, Salary
|
||||
FROM employees
|
||||
WHERE department_id = 110
|
||||
CONNECT BY PRIOR employee_id = manager_id)
|
||||
GROUP BY name
|
||||
ORDER BY name, "Total_Salary";
|
||||
|
||||
END;
|
||||
/
|
Reference in New Issue
Block a user