All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.rdf.sail.sparql.ValueExprBuilder Maven / Gradle / Ivy

/**

Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016.  All rights reserved.

Contact:
     SYSTAP, LLC DBA Blazegraph
     2501 Calvert ST NW #106
     Washington, DC 20008
     [email protected]

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/* Portions of this code are:
 *
 * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007.
 *
 * Licensed under the Aduna BSD-style license.
 */
/*
 * Created on Aug 21, 2011
 */

package com.bigdata.rdf.sail.sparql;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import org.openrdf.model.URI;
import org.openrdf.model.vocabulary.FN;

import com.bigdata.bop.aggregate.AggregateBase;
import com.bigdata.bop.rdf.aggregate.GROUP_CONCAT;
import com.bigdata.rdf.internal.constraints.IriBOp;
import com.bigdata.rdf.model.BigdataURI;
import com.bigdata.rdf.sail.sparql.ast.ASTAbs;
import com.bigdata.rdf.sail.sparql.ast.ASTAggregate;
import com.bigdata.rdf.sail.sparql.ast.ASTAnd;
import com.bigdata.rdf.sail.sparql.ast.ASTAvg;
import com.bigdata.rdf.sail.sparql.ast.ASTBNodeFunc;
import com.bigdata.rdf.sail.sparql.ast.ASTBound;
import com.bigdata.rdf.sail.sparql.ast.ASTCeil;
import com.bigdata.rdf.sail.sparql.ast.ASTCoalesce;
import com.bigdata.rdf.sail.sparql.ast.ASTCompare;
import com.bigdata.rdf.sail.sparql.ast.ASTConcat;
import com.bigdata.rdf.sail.sparql.ast.ASTContains;
import com.bigdata.rdf.sail.sparql.ast.ASTCount;
import com.bigdata.rdf.sail.sparql.ast.ASTDatatype;
import com.bigdata.rdf.sail.sparql.ast.ASTDay;
import com.bigdata.rdf.sail.sparql.ast.ASTEncodeForURI;
import com.bigdata.rdf.sail.sparql.ast.ASTExistsFunc;
import com.bigdata.rdf.sail.sparql.ast.ASTFloor;
import com.bigdata.rdf.sail.sparql.ast.ASTFunctionCall;
import com.bigdata.rdf.sail.sparql.ast.ASTGroupConcat;
import com.bigdata.rdf.sail.sparql.ast.ASTGroupCondition;
import com.bigdata.rdf.sail.sparql.ast.ASTHours;
import com.bigdata.rdf.sail.sparql.ast.ASTIRIFunc;
import com.bigdata.rdf.sail.sparql.ast.ASTIf;
import com.bigdata.rdf.sail.sparql.ast.ASTIn;
import com.bigdata.rdf.sail.sparql.ast.ASTInfix;
import com.bigdata.rdf.sail.sparql.ast.ASTIsBlank;
import com.bigdata.rdf.sail.sparql.ast.ASTIsIRI;
import com.bigdata.rdf.sail.sparql.ast.ASTIsLiteral;
import com.bigdata.rdf.sail.sparql.ast.ASTIsNumeric;
import com.bigdata.rdf.sail.sparql.ast.ASTLang;
import com.bigdata.rdf.sail.sparql.ast.ASTLangMatches;
import com.bigdata.rdf.sail.sparql.ast.ASTLowerCase;
import com.bigdata.rdf.sail.sparql.ast.ASTMD5;
import com.bigdata.rdf.sail.sparql.ast.ASTMath;
import com.bigdata.rdf.sail.sparql.ast.ASTMax;
import com.bigdata.rdf.sail.sparql.ast.ASTMin;
import com.bigdata.rdf.sail.sparql.ast.ASTMinutes;
import com.bigdata.rdf.sail.sparql.ast.ASTMonth;
import com.bigdata.rdf.sail.sparql.ast.ASTNot;
import com.bigdata.rdf.sail.sparql.ast.ASTNotExistsFunc;
import com.bigdata.rdf.sail.sparql.ast.ASTNotIn;
import com.bigdata.rdf.sail.sparql.ast.ASTNow;
import com.bigdata.rdf.sail.sparql.ast.ASTOr;
import com.bigdata.rdf.sail.sparql.ast.ASTRand;
import com.bigdata.rdf.sail.sparql.ast.ASTRegexExpression;
import com.bigdata.rdf.sail.sparql.ast.ASTReplace;
import com.bigdata.rdf.sail.sparql.ast.ASTRound;
import com.bigdata.rdf.sail.sparql.ast.ASTSHA1;
import com.bigdata.rdf.sail.sparql.ast.ASTSHA224;
import com.bigdata.rdf.sail.sparql.ast.ASTSHA256;
import com.bigdata.rdf.sail.sparql.ast.ASTSHA384;
import com.bigdata.rdf.sail.sparql.ast.ASTSHA512;
import com.bigdata.rdf.sail.sparql.ast.ASTSTRUUID;
import com.bigdata.rdf.sail.sparql.ast.ASTSameTerm;
import com.bigdata.rdf.sail.sparql.ast.ASTSample;
import com.bigdata.rdf.sail.sparql.ast.ASTSeconds;
import com.bigdata.rdf.sail.sparql.ast.ASTStr;
import com.bigdata.rdf.sail.sparql.ast.ASTStrAfter;
import com.bigdata.rdf.sail.sparql.ast.ASTStrBefore;
import com.bigdata.rdf.sail.sparql.ast.ASTStrDt;
import com.bigdata.rdf.sail.sparql.ast.ASTStrEnds;
import com.bigdata.rdf.sail.sparql.ast.ASTStrLang;
import com.bigdata.rdf.sail.sparql.ast.ASTStrLen;
import com.bigdata.rdf.sail.sparql.ast.ASTStrStarts;
import com.bigdata.rdf.sail.sparql.ast.ASTSubstr;
import com.bigdata.rdf.sail.sparql.ast.ASTSum;
import com.bigdata.rdf.sail.sparql.ast.ASTTimezone;
import com.bigdata.rdf.sail.sparql.ast.ASTTz;
import com.bigdata.rdf.sail.sparql.ast.ASTUUID;
import com.bigdata.rdf.sail.sparql.ast.ASTUpperCase;
import com.bigdata.rdf.sail.sparql.ast.ASTYear;
import com.bigdata.rdf.sail.sparql.ast.Node;
import com.bigdata.rdf.sail.sparql.ast.SimpleNode;
import com.bigdata.rdf.sail.sparql.ast.VisitorException;
import com.bigdata.rdf.sparql.ast.AssignmentNode;
import com.bigdata.rdf.sparql.ast.ConstantNode;
import com.bigdata.rdf.sparql.ast.ExistsNode;
import com.bigdata.rdf.sparql.ast.FunctionNode;
import com.bigdata.rdf.sparql.ast.FunctionRegistry;
import com.bigdata.rdf.sparql.ast.GraphPatternGroup;
import com.bigdata.rdf.sparql.ast.IGroupMemberNode;
import com.bigdata.rdf.sparql.ast.IValueExpressionNode;
import com.bigdata.rdf.sparql.ast.NotExistsNode;
import com.bigdata.rdf.sparql.ast.ValueExpressionNode;
import com.bigdata.rdf.sparql.ast.VarNode;

/**
 * Visitor pattern builds {@link IValueExpressionNode}s.
 * 
 * @author Bryan Thompson
 * @version $Id$
 * 
 * @see FunctionRegistry
 * @openrdf
 */
public class ValueExprBuilder extends BigdataASTVisitorBase {

//    private static final Logger log = Logger.getLogger(ValueExprBuilder.class);

    /**
     * Used to manage collection and nesting of graph patterns. This is mostly
     * handled by {@link GroupGraphPatternBuilder}.
     * 

* Note: Both {@link ASTExistsFunc} and {@link ASTNotExistsFunc} have an * inner graph pattern by they appear within value expressions. */ protected GroupGraphPattern graphPattern; public ValueExprBuilder(final BigdataASTContext context) { super(context); } protected ValueExpressionNode left(final SimpleNode node) throws VisitorException { return (ValueExpressionNode) node.jjtGetChild(0).jjtAccept(this, null); } protected ValueExpressionNode right(final SimpleNode node) throws VisitorException { return (ValueExpressionNode) node.jjtGetChild(1).jjtAccept(this, null); } /** * Handle a simple function without any arguments. */ protected FunctionNode noneary(final SimpleNode node, final URI functionURI) throws VisitorException { return new FunctionNode(functionURI, null/* scalarValues */, new ValueExpressionNode[] {}); } /** * Handle a simple unary function (the child of the node is the argument to * the function). */ protected FunctionNode unary(final SimpleNode node, final URI functionURI) throws VisitorException { return new FunctionNode(functionURI, null/* scalarValues */, new ValueExpressionNode[] { left(node) }); } /** * Handle a simple binary function (both children of the node are arguments * to the function). */ protected FunctionNode binary(final SimpleNode node, final URI functionURI) throws VisitorException { return new FunctionNode(functionURI, null/* scalarValues */, new ValueExpressionNode[] { left(node), right(node) }); } /** * Handle a simple ternary function (there are three children of the node * which are the arguments to the function). */ protected FunctionNode ternary(final SimpleNode node, final URI functionURI) throws VisitorException { return new FunctionNode(functionURI, null/* scalarValues */, new ValueExpressionNode[] { left(node), right(node), (ValueExpressionNode) node.jjtGetChild(2).jjtAccept( this, null) }); } /** * Handle a function with four arguments (there are four children of the * node which are the arguments to the function). */ protected FunctionNode quadary(final SimpleNode node, final URI functionURI) throws VisitorException { return new FunctionNode(functionURI, null/* scalarValues */, new ValueExpressionNode[] { left(node), right(node), (ValueExpressionNode) node.jjtGetChild(2).jjtAccept( this, null), (ValueExpressionNode) node.jjtGetChild(3).jjtAccept( this, null)}); } /** * Handle a simple nary function (all children of the node are arguments to * the function). */ protected FunctionNode nary(final SimpleNode node, final URI functionURI) throws VisitorException { final int nargs = node.jjtGetNumChildren(); final ValueExpressionNode[] args = new ValueExpressionNode[nargs]; for (int i = 0; i < nargs; i++) { final Node argNode = node.jjtGetChild(i); args[i] = (ValueExpressionNode) argNode.jjtAccept(this, null); } if (functionURI.equals(FunctionRegistry.COALESCE)) { return new FunctionNode(FunctionRegistry.COALESCE, null/* scalarValues */, args); } else if (functionURI.equals(FN.SUBSTRING)) { return new FunctionNode(FunctionRegistry.SUBSTR, null/* scalarValues */, args); } else if (functionURI.equals(FN.CONCAT)) { return new FunctionNode(FunctionRegistry.CONCAT, null/* scalarValues */, args); } else { throw new IllegalArgumentException(); } } protected FunctionNode aggregate(final ASTAggregate node, final URI functionURI) throws VisitorException { Map scalarValues = null; if (node.isDistinct()) { scalarValues = Collections.singletonMap( AggregateBase.Annotations.DISTINCT, (Object) Boolean.TRUE); } if (node instanceof ASTCount && ((ASTCount) node).isWildcard()) { /* * Note: The wildcard is dropped by openrdf. */ return new FunctionNode(functionURI, scalarValues, new ValueExpressionNode[] { new VarNode("*") }); } return new FunctionNode(functionURI, scalarValues, new ValueExpressionNode[] { left(node) }); } // // // // @Override // final public FunctionNode visit(ASTBind node, Object data) throws VisitorException { // return new AssignmentNode((VarNode) right(node), left(node)); // } @Override final public FunctionNode visit(ASTOr node, Object data) throws VisitorException { return binary(node, FunctionRegistry.OR); } @Override final public FunctionNode visit(ASTAnd node, Object data) throws VisitorException { return binary(node, FunctionRegistry.AND); } @Override final public FunctionNode visit(ASTNot node, Object data) throws VisitorException { return unary(node, FunctionRegistry.NOT); } @Override final public FunctionNode visit(ASTCoalesce node, Object data) throws VisitorException { return nary(node, FunctionRegistry.COALESCE); } @Override final public FunctionNode visit(ASTCompare node, Object data) throws VisitorException { final URI functionURI; switch (node.getOperator()) { case LT: functionURI = FunctionRegistry.LT; break; case GT: functionURI = FunctionRegistry.GT; break; case EQ: functionURI = FunctionRegistry.EQ; break; case LE: functionURI = FunctionRegistry.LE; break; case GE: functionURI = FunctionRegistry.GE; break; case NE: functionURI = FunctionRegistry.NE; break; default: throw new UnsupportedOperationException(node.getOperator() .getSymbol()); } return binary(node, functionURI); } @Override final public FunctionNode visit(ASTSubstr node, Object data) throws VisitorException { return nary(node, FN.SUBSTRING); } @Override final public FunctionNode visit(ASTConcat node, Object data) throws VisitorException { return nary(node, FN.CONCAT); } @Override final public FunctionNode visit(ASTAbs node, Object data) throws VisitorException { return unary(node, FN.NUMERIC_ABS); } @Override final public FunctionNode visit(ASTCeil node, Object data) throws VisitorException { return unary(node, FN.NUMERIC_CEIL); } @Override final public FunctionNode visit(ASTContains node, Object data) throws VisitorException { return binary(node, FN.CONTAINS); } @Override final public FunctionNode visit(ASTFloor node, Object data) throws VisitorException { return unary(node, FN.NUMERIC_FLOOR); } @Override final public FunctionNode visit(ASTRound node, Object data) throws VisitorException { return unary(node, FN.NUMERIC_ROUND); } @Override final public FunctionNode visit(ASTRand node, Object data) throws VisitorException { return noneary(node, FunctionRegistry.RAND); } @Override final public FunctionNode visit(ASTSameTerm node, Object data) throws VisitorException { return binary(node, FunctionRegistry.SAME_TERM); } @Override final public FunctionNode visit(ASTMath node, Object data) throws VisitorException { final URI functionURI; switch (node.getOperator()) { case PLUS: functionURI = FunctionRegistry.ADD; break; case MINUS: functionURI = FunctionRegistry.SUBTRACT; break; case MULTIPLY: functionURI = FunctionRegistry.MULTIPLY; break; case DIVIDE: functionURI = FunctionRegistry.DIVIDE; break; default: throw new UnsupportedOperationException(node.getOperator() .getSymbol()); } return binary(node, functionURI); } /** ASTFunctionCall (IRIRef, ArgList). */ @Override final public FunctionNode visit(ASTFunctionCall node, Object data) throws VisitorException { final ConstantNode uriNode = (ConstantNode) node.jjtGetChild(0) .jjtAccept(this, null); final BigdataURI functionURI = (BigdataURI) uriNode.getValue(); final int nargs = node.jjtGetNumChildren() - 1; final ValueExpressionNode[] args = new ValueExpressionNode[nargs]; for (int i = 0; i < nargs; i++) { final Node argNode = node.jjtGetChild(i + 1); args[i] = (ValueExpressionNode) argNode.jjtAccept(this, null); } return new FunctionNode(functionURI, null/* scalarValues */, args); } @Override final public FunctionNode visit(ASTEncodeForURI node, Object data) throws VisitorException { return unary(node, FN.ENCODE_FOR_URI); } @Override final public FunctionNode visit(ASTStr node, Object data) throws VisitorException { return unary(node, FunctionRegistry.STR); } @Override final public FunctionNode visit(ASTStrDt node, Object data) throws VisitorException { return binary(node, FunctionRegistry.STR_DT); } @Override final public FunctionNode visit(ASTStrStarts node, Object data) throws VisitorException { return binary(node, FN.STARTS_WITH); } @Override final public FunctionNode visit(ASTStrEnds node, Object data) throws VisitorException { return binary(node, FN.ENDS_WITH); } @Override final public FunctionNode visit(ASTStrLen node, Object data) throws VisitorException { return unary(node, FN.STRING_LENGTH); } @Override final public FunctionNode visit(ASTStrAfter node, Object data) throws VisitorException { return binary(node, FunctionRegistry.STR_AFTER); // return createFunctionCall(FN.SUBSTRING_AFTER.toString(), node, 2, 2); } @Override final public FunctionNode visit(ASTStrBefore node, Object data) throws VisitorException { return binary(node, FunctionRegistry.STR_BEFORE); // return createFunctionCall(FN.SUBSTRING_BEFORE.toString(), node, 2, 2); } @Override final public FunctionNode visit(ASTUpperCase node, Object data) throws VisitorException { return unary(node, FN.UPPER_CASE); } @Override final public FunctionNode visit(ASTLowerCase node, Object data) throws VisitorException { return unary(node, FN.LOWER_CASE); } @Override final public FunctionNode visit(ASTStrLang node, Object data) throws VisitorException { return binary(node, FunctionRegistry.STR_LANG); } @Override final public FunctionNode visit(ASTNow node, Object data) throws VisitorException { return noneary(node, FunctionRegistry.NOW); } @Override final public FunctionNode visit(ASTYear node, Object data) throws VisitorException { return unary(node, FN.YEAR_FROM_DATETIME); } @Override final public FunctionNode visit(ASTMonth node, Object data) throws VisitorException { return unary(node, FN.MONTH_FROM_DATETIME); } @Override final public FunctionNode visit(ASTDay node, Object data) throws VisitorException { return unary(node, FN.DAY_FROM_DATETIME); } @Override final public FunctionNode visit(ASTHours node, Object data) throws VisitorException { return unary(node, FN.HOURS_FROM_DATETIME); } @Override final public FunctionNode visit(ASTMinutes node, Object data) throws VisitorException { return unary(node, FN.MINUTES_FROM_DATETIME); } @Override final public FunctionNode visit(ASTSeconds node, Object data) throws VisitorException { return unary(node, FN.SECONDS_FROM_DATETIME); } @Override final public FunctionNode visit(ASTTimezone node, Object data) throws VisitorException { return unary(node, FunctionRegistry.TIMEZONE); } @Override final public FunctionNode visit(ASTTz node, Object data) throws VisitorException { return unary(node, FunctionRegistry.TZ); } @Override final public FunctionNode visit(ASTMD5 node, Object data) throws VisitorException { return unary(node, FunctionRegistry.MD5); } @Override final public FunctionNode visit(ASTSHA1 node, Object data) throws VisitorException { return unary(node, FunctionRegistry.SHA1); } @Override final public FunctionNode visit(ASTSHA224 node, Object data) throws VisitorException { return unary(node, FunctionRegistry.SHA224); } @Override final public FunctionNode visit(ASTSHA256 node, Object data) throws VisitorException { return unary(node, FunctionRegistry.SHA256); } @Override final public FunctionNode visit(ASTSHA384 node, Object data) throws VisitorException { return unary(node, FunctionRegistry.SHA384); } @Override final public FunctionNode visit(ASTSHA512 node, Object data) throws VisitorException { return unary(node, FunctionRegistry.SHA512); } @Override public FunctionNode visit(ASTUUID node, Object data) throws VisitorException { return noneary(node, FunctionRegistry.UUID); } @Override public FunctionNode visit(ASTSTRUUID node, Object data) throws VisitorException { return noneary(node, FunctionRegistry.STRUUID); } @Override final public FunctionNode visit(ASTIRIFunc node, Object data) throws VisitorException { return new FunctionNode(FunctionRegistry.IRI, // null/* scalarValues */, Collections.singletonMap(IriBOp.Annotations.BASE_URI, (Object) node.getBaseURI()), new ValueExpressionNode[] { left(node) }); // return unary(node, FunctionRegistry.IRI); /* * FIXME baseURI resolution needs to be handled for IRI functions, most * likely in unary(), binary(), nary(), and aggregate(). Write AST * layer unit tests for this. */ // ValueExpr expr = (ValueExpr)node.jjtGetChild(0).jjtAccept(this, null); // IRIFunction fn = new IRIFunction(expr); // fn.setBaseURI(node.getBaseURI()); // return fn; } @Override final public FunctionNode visit(ASTLang node, Object data) throws VisitorException { return unary(node, FunctionRegistry.LANG); } @Override final public FunctionNode visit(ASTDatatype node, Object data) throws VisitorException { return unary(node, FunctionRegistry.DATATYPE); } @Override final public FunctionNode visit(ASTLangMatches node, Object data) throws VisitorException { return binary(node, FunctionRegistry.LANG_MATCHES); } @Override final public FunctionNode visit(ASTBound node, Object data) throws VisitorException { return unary(node, FunctionRegistry.BOUND); } @Override final public FunctionNode visit(ASTIsIRI node, Object data) throws VisitorException { return unary(node, FunctionRegistry.IS_IRI); } @Override final public FunctionNode visit(ASTIsBlank node, Object data) throws VisitorException { return unary(node, FunctionRegistry.IS_BLANK); } @Override final public FunctionNode visit(ASTIsLiteral node, Object data) throws VisitorException { return unary(node, FunctionRegistry.IS_LITERAL); } @Override final public FunctionNode visit(ASTIsNumeric node, Object data) throws VisitorException { return unary(node, FunctionRegistry.IS_NUMERIC); } /** TODO Same functionURI for BNode() and BNode(Literal)? */ @Override final public FunctionNode visit(ASTBNodeFunc node, Object data) throws VisitorException { if (node.jjtGetNumChildren() == 0) { return noneary(node, FunctionRegistry.BNODE); } return unary(node, FunctionRegistry.BNODE); } @Override final public FunctionNode visit(ASTRegexExpression node, Object data) throws VisitorException { if (node.jjtGetNumChildren() == 2) { return binary(node, FunctionRegistry.REGEX); } return ternary(node, FunctionRegistry.REGEX); } @Override public FunctionNode visit(ASTReplace node, Object data) throws VisitorException { if (node.jjtGetNumChildren() == 3) { return ternary(node, FunctionRegistry.REPLACE); } return quadary(node, FunctionRegistry.REPLACE); // return createFunctionCall(FN.REPLACE.toString(), node, 3, 4); } /** * Note: EXISTS is basically an ASK subquery. * * @see ExistsNode */ @Override final public ExistsNode visit(final ASTExistsFunc node, Object data) throws VisitorException { final VarNode anonvar = context.createAnonVar("-exists-"); /* * Use a new (empty) graph pattern to prevent the accept of the child * from being attached into the parent's graph pattern context. */ final GroupGraphPattern parentGP = graphPattern; graphPattern = scopedGroupGraphPattern(node); @SuppressWarnings("unchecked") final GraphPatternGroup innerGraphPattern = (GraphPatternGroup) node .jjtGetChild(0).jjtAccept(this/* visitor */, null); final ExistsNode fn = new ExistsNode(anonvar, innerGraphPattern); // Restore the parent's context. graphPattern = parentGP; return fn; } /** * See EXISTS above. * * @see NotExistsNode */ @Override final public NotExistsNode visit(final ASTNotExistsFunc node, Object data) throws VisitorException { final VarNode anonvar = context.createAnonVar("-exists-"); /* * Use a new (empty) graph pattern to prevent the accept of the child * from being attached into the parent's graph pattern context. */ final GroupGraphPattern parentGP = graphPattern; graphPattern = scopedGroupGraphPattern(node); @SuppressWarnings("unchecked") final GraphPatternGroup innerGraphPattern = (GraphPatternGroup) node .jjtGetChild(0).jjtAccept(this/* visitor */, null); final NotExistsNode fn = new NotExistsNode(anonvar, innerGraphPattern); // Restore the parent's context. graphPattern = parentGP; return fn; } @Override final public FunctionNode visit(ASTIf node, Object data) throws VisitorException { return ternary(node, FunctionRegistry.IF); } /** * Unwrap an {@link ASTInfix} node, returning the inner {@link FunctionNode} * constructed for it. *

* Note: Sesame has picked up the notion of an ASTInfix node, but they are * handling it slightly differently. * * @see http://www.openrdf.org/issues/browse/SES-818 */ @Override final 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); } /** * "IN" and "NOT IN" are infix notation operators. The syntax for "IN" is * [NumericExpression IN ArgList]. However, the IN operators declared by the * {@link FunctionRegistry} require that the outer NumericExpression is * their first argument. The function registry optimizes several different * cases, including where the set is empty, where it has one member, and * where the members of the set are constants and the outer expression is a * variable. * * @see FunctionRegistry#IN * @see FunctionRegistry#NOT_IN * * @see http://www.openrdf.org/issues/browse/SES-818 */ @Override final public FunctionNode visit(ASTIn node, Object data) throws VisitorException { // final int nargs = node.jjtGetNumChildren(); // // final ValueExpressionNode[] args = new ValueExpressionNode[nargs + 1]; // // /* // * Reach up to the parent's 1st child for the left argument to the infix // * IN operator. // */ // final ValueExpressionNode leftArg = (ValueExpressionNode) node // .jjtGetParent().jjtGetChild(0).jjtAccept(this, null); // // args[0] = leftArg; // // /* // * Handle the ArgList for IN. // */ // // for (int i = 0; i < nargs; i++) { // // final Node argNode = node.jjtGetChild(i); // // args[i + 1] = (ValueExpressionNode) argNode.jjtAccept(this, null); // // } /* * Handle the ArgList for IN. * * Note: This assumes that the left argument of IN has been rotated into * place as its first child. * * @see InfixProcessor */ final int nargs = node.jjtGetNumChildren(); final ValueExpressionNode[] args = new ValueExpressionNode[nargs]; for (int i = 0; i < nargs; i++) { final Node argNode = node.jjtGetChild(i); args[i] = (ValueExpressionNode) argNode.jjtAccept(this, null); } return new FunctionNode(FunctionRegistry.IN, null/* scalarValues */, args); } /** * See IN above. */ @Override final public FunctionNode visit(ASTNotIn node, Object data) throws VisitorException { // // final int nargs = node.jjtGetNumChildren(); // // final ValueExpressionNode[] args = new ValueExpressionNode[nargs + 1]; // // /* // * Reach up to the parent's 1st child for the left argument to the infix // * NOT IN operator. // */ // final ValueExpressionNode leftArg = (ValueExpressionNode) node // .jjtGetParent().jjtGetChild(0).jjtAccept(this, null); // // args[0] = leftArg; // // /* // * Handle the ArgList for NOT IN. // */ // // for (int i = 0; i < nargs; i++) { // // final Node argNode = node.jjtGetChild(i); // // args[i + 1] = (ValueExpressionNode) argNode.jjtAccept(this, null); // // } /* * Handle the ArgList for NOT_IN. * * Note: This assumes that the left argument of the NOT_IN has been * rotated into place as its first child. */ final int nargs = node.jjtGetNumChildren(); final ValueExpressionNode[] args = new ValueExpressionNode[nargs]; for (int i = 0; i < nargs; i++) { final Node argNode = node.jjtGetChild(i); args[i] = (ValueExpressionNode) argNode.jjtAccept(this, null); } return new FunctionNode(FunctionRegistry.NOT_IN, null/* scalarValues */, args); } /** * Aggregate value expressions in GROUP BY clause. The content of this * production can be a {@link VarNode}, {@link AssignmentNode}, or * {@link FunctionNode} (which handles both built-in functions and extension * functions). However, we always wrap it as an {@link AssignmentNode} and * return that. A {@link VarNode} will just bind itself. A bare * {@link FunctionNode} will bind an anonymous variable. */ @Override final public AssignmentNode visit(final ASTGroupCondition node, Object data) throws VisitorException { // The first value-expression. final IValueExpressionNode ve = (IValueExpressionNode) node.jjtGetChild(0) .jjtAccept(this, data); if (node.jjtGetNumChildren() == 2) { /* * If there are two value expressions, then BIND(ve,ve2). */ final IValueExpressionNode asVar = (IValueExpressionNode) node .jjtGetChild(1).jjtAccept(this, data); return new AssignmentNode((VarNode) asVar, ve); } if (ve instanceof VarNode) { // Assign to self. return new AssignmentNode((VarNode) ve, (VarNode) ve); } // Wrap with assignment to an anonymous variable. return new AssignmentNode(context.createAnonVar("-groupBy-"), ve); } /* * Aggregate functions. Each accepts a scalar boolean "distinct" argument. * In addition, COUNT may be used with "*" as the inner expression. */ @Override final public FunctionNode visit(ASTCount node, Object data) throws VisitorException { return aggregate(node, FunctionRegistry.COUNT); } @Override final public FunctionNode visit(ASTMax node, Object data) throws VisitorException { return aggregate(node, FunctionRegistry.MAX); } @Override final public FunctionNode visit(ASTMin node, Object data) throws VisitorException { return aggregate(node, FunctionRegistry.MIN); } @Override final public FunctionNode visit(ASTSum node, Object data) throws VisitorException { return aggregate(node, FunctionRegistry.SUM); } @Override final public FunctionNode visit(ASTAvg node, Object data) throws VisitorException { return aggregate(node, FunctionRegistry.AVERAGE); } @Override final public FunctionNode visit(ASTSample node, Object data) throws VisitorException { return aggregate(node, FunctionRegistry.SAMPLE); } /** * TODO additional scalar values (sparql.jjt specifies "separator EQ" as a * constant in the grammar, but we support additional scalar values for * {@link GROUP_CONCAT}. Also, the grammar is permissive and allows * Expression for separator rather than a quoted string (per the W3C draft). */ @Override final public FunctionNode visit(ASTGroupConcat node, Object data) throws VisitorException { Map scalarValues = new LinkedHashMap(); if (node.isDistinct()) { scalarValues.put(AggregateBase.Annotations.DISTINCT, Boolean.TRUE); } if (node.jjtGetNumChildren() > 1) { final ConstantNode separator = (ConstantNode) node.jjtGetChild(1) .jjtAccept(this, data); scalarValues.put(GROUP_CONCAT.Annotations.SEPARATOR, separator .getValue().stringValue()); } return new FunctionNode(FunctionRegistry.GROUP_CONCAT, scalarValues, new ValueExpressionNode[] { left(node) }); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy