JSqlParser
JSqlParser copied to clipboard
JSQLParser 5.1: Incorrect Parent node
I have a query: select A from B where (A ~ 'fish') which when tree walking with an ExpressionVisitor, I end up in void visit(RegExpMatchOperator regExpMatchOperator) {...}, the parent of the regExpMatchOperator is the PlainSelect, and not the ParenthesedExpressionList
Test Case (which fails on the final assertion):
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.PlainSelect;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class RegexpMatchesTest {
@Test
void parentIsExpected() throws JSQLParserException {
var parsed = CCJSqlParserUtil.parse("select A from B where (A ~ 'fish')");
assertThat(parsed).isInstanceOf(PlainSelect.class);
var select = (PlainSelect) parsed;
assertThat(select.getWhere()).isInstanceOf(ParenthesedExpressionList.class);
var parenthesis = (ParenthesedExpressionList<?>) select.getWhere();
assertThat(parenthesis.getFirst()).isInstanceOf(RegExpMatchOperator.class);
var regExpMatchOperator = (RegExpMatchOperator) parenthesis.getFirst();
assertThat(regExpMatchOperator.getParent()).isSameAs(parenthesis);
}
}
My expectation is that the parent node of the regex operator should be the parenthesis object, not the plain select
Although I note now, that ParenthesedExpressionList does not contain a getParent() method, so you couldn't tree walk up to the PlainSelect from the ParenthesedExpressionList. I guess that because getParent() is a member of ASTNodeAccessImpl, and you can't have ExpressionList extend ArrayList and ASTNodeAccessImpl.
An extension of this problem, which I think is more problematic:
SELECT A FROM B WHERE (A ~ 'fish' AND A !~ 'banana')
The RegExpMatchOperator of A ~ 'fish' has a parent of the PlainSelect and not AndExpression (as does the A !~ 'banana'), even though the structure is
PlainSelect.where => ParenthesedExpressionList(AndExpression(RegExpMatchOperator, RegExpMatchOperator))
where AndExpression does extend ASTNodeAccessImpl
Although I still think this is an issue, we worked around this issue and so I'm happy for this to be closed.