History | Log In     View a printable version of the current page. Get help!  
Issue Details [XML]

Key: SES-818
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Jeen Broekstra
Reporter: Bryan Thompson
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
Sesame

Incorrect TupleExpression created for "SELECT (?s IN (?p,?o) AS ?x) ... ".

Created: 23/Aug/11 12:58 AM   Updated: 28/Aug/11 11:41 PM
Component/s: SPARQL
Affects Version/s: 2.4.2
Fix Version/s: 2.5.1

Environment: any


 Description   
The incorrect TupleExpression is created for "SELECT (?s IN (?p,?o) AS ?x) ... ". It produces the following AST tree. You can see that Var(s), In, and Var(x) are all children of the ProjectionElem. However, getAlias() assumes that the child at index 1 will be the alias when there are at least two children of the ProjectionElem. That is In() rather than Var(x). It seems likely that it would be easier if IN were treated as an infix operator such that the parse tree would be ProjectionElem(IN(s,p,o),x) and thus always have either one or two children which would make identifying the alias much easier. This might be done by a rewrite step. Other solutions are of course possible, but if the expression in the "left" hand side of the AS has more than one node then getAlias() should return the last element rather than the 2nd element.

> QueryContainer
> SelectQuery
> Select
> ProjectionElem
> Var (s)
> In
> Var (p)
> Var (o)
> Var (x)

public String getAlias() {
                if (children.size()>= 2) {
                        Node aliasNode = children.get(1);

                        if (aliasNode instanceof ASTString) {
                                return ((ASTString)aliasNode).getValue();
                        }
                        else if (aliasNode instanceof ASTVar) {
                                return ((ASTVar)aliasNode).getName();
                        }
                }

                return null;
        }

 All   Comments   Change History      Sort Order:
Comment by Bryan Thompson [23/Aug/11 12:49 PM]
Something related which I noticed is that the "AS" appears to disappear within a GROUP BY (?x AS ?y). The ?x and ?y show as the children of a GroupBywithout the AS being represented by a dominating AS node. You can see this would be the case by looking at the grammar. I think that it might be more convenient to represent the { Expr AS Var } as an "AS" grammar production so it was always just a single AST node. This would also solve the problem in the SELECT expressions since an AS would always be represented as a binary relation regardless of the number of nodes involved in the left hand side.

void GroupCondition() :
{}
{
FunctionCall()
| BuiltInCall()
| <LPAREN> Expression() [ <AS> Var() ] <RPAREN> <==
| Var()
}

Change by Jeen Broekstra [23/Aug/11 10:08 PM]
Field Original Value New Value
Assignee Arjohn Kampman [ arjohn ] Jeen Broekstra [ jeen ]

Change by Jeen Broekstra [23/Aug/11 10:08 PM]
Field Original Value New Value
Component/s SPARQL [ 10105 ]
Fix Version/s 2.5.1 [ 10600 ]

Comment by Bryan Thompson [26/Aug/11 08:59 PM]
Jeen,

This problem with IN and NOT IN was driving me nuts. I modified the sparql.jjt grammar as follows:

void RelationalExpression() #void :
{}
{
NumericExpression()
[
<EQ> NumericExpression() {jjtThis.setOperator(CompareOp.EQ);} #Compare(2)
| <NE> NumericExpression() {jjtThis.setOperator(CompareOp.NE);} #Compare(2)
| <LT> NumericExpression() {jjtThis.setOperator(CompareOp.LT);} #Compare(2)
| <LE> NumericExpression() {jjtThis.setOperator(CompareOp.LE);} #Compare(2)
| <GE> NumericExpression() {jjtThis.setOperator(CompareOp.GE);} #Compare(2)
| <GT> NumericExpression() {jjtThis.setOperator(CompareOp.GT);} #Compare(2)
// | In()
// | NotIn()
| In() #Infix(2)
| NotIn() #Infix(2)
]
}

This ensures that the IN() construction does not cause there to be more than one AST node in the value expression for the parent.

I then added a production to handle the Infix operator:

    /**
     * Unwrap an {@link ASTInfix} node, returning the inner {@link FunctionNode}
     * constructed for it.
     */
    @Override
    public FunctionNode visit(ASTInfix node, Object data) throws VisitorException {

        final Node left = node.jjtGetChild(0);

        final Node op = node.jjtGetChild(1);
        
        op.jjtInsertChild(left, 0);

        return (FunctionNode) op.jjtAccept(this, data);

    }

This fixes the problem for me.

Change by Jeen Broekstra [28/Aug/11 11:09 PM]
Field Original Value New Value
Status Open [ 1 ] In Progress [ 3 ]

Comment by Jeen Broekstra [28/Aug/11 11:39 PM]
Thanks for the suggestions. I have added the Infix approach for the productions of In and Not In, which fixes the issues with this kind of operation appearing in the projection. The TupleExprBuilder now reads an Infix object by first visiting the leftArg and then injecting that arg immediately into the production for the rightArg, so the operator has both operands available, resulting in a ValueExpr (in this case, a OR-ed set of Compare objects).

Have to run a few more quick tests before I commit, to see if I don't break any existing queries.

Change by Jeen Broekstra [28/Aug/11 11:41 PM]
Field Original Value New Value
Status In Progress [ 3 ] Resolved [ 5 ]
Resolution Fixed [ 1 ]