jena-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a...@apache.org
Subject svn commit: r1554915 [2/2] - in /jena/Scratch/AFS/Dev/src: ./ dev/ dev/g2/ dsg/ element/ opexec/ opt/
Date Thu, 02 Jan 2014 21:00:48 GMT
Added: jena/Scratch/AFS/Dev/src/element/ElementTransformer.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/element/ElementTransformer.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/element/ElementTransformer.java (added)
+++ jena/Scratch/AFS/Dev/src/element/ElementTransformer.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package element ;
+
+import java.util.ArrayDeque ;
+import java.util.Deque ;
+import java.util.List ;
+
+import org.apache.jena.atlas.logging.Log ;
+
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.sparql.expr.Expr ;
+import com.hp.hpl.jena.sparql.expr.ExprList ;
+import com.hp.hpl.jena.sparql.expr.ExprTransform ;
+import com.hp.hpl.jena.sparql.expr.ExprTransformer ;
+import com.hp.hpl.jena.sparql.syntax.* ;
+
+/** A bottom-up application of a transformation of SPARQL syntax Elements. 
+ * {@linkplain QueryTransformOps#transform} provides the mechanism
+ * to apply to a {@linkplain Query}.
+ * @see UpdateTransformOps#transform
+ */
+public class ElementTransformer {
+    private static ElementTransformer singleton = new ElementTransformer() ;
+
+    /** Get the current transformer */
+    public static ElementTransformer get() {
+        return singleton ;
+    }
+
+    /** Set the current transformer - use with care */
+    public static void set(ElementTransformer value) {
+        ElementTransformer.singleton = value ;
+    }
+
+    /** Transform an algebra expression */
+    public static Element transform(Element element, ElementTransform transform) {
+        return transform(element, transform, null, null, null) ;
+    }
+
+    /** Transformation with specific ElementTransform and ExprTransform */
+    public static Element transform(Element element, ElementTransform transform, ExprTransform exprTransform) {
+        return get().transformation(element, transform, exprTransform, null, null) ;
+    }
+
+    public static Element transform(Element element, ElementTransform transform, ExprTransform exprTransform,
+                                    ElementVisitor beforeVisitor, ElementVisitor afterVisitor) {
+        return get().transformation(element, transform, exprTransform, beforeVisitor, afterVisitor) ;
+    }
+
+    // To allow subclassing this class, we use a singleton pattern
+    // and these protected methods.
+    protected Element transformation(Element element, ElementTransform transform, ExprTransform exprTransform,
+                                     ElementVisitor beforeVisitor, ElementVisitor afterVisitor) {
+        ApplyTransformVisitor v = new ApplyTransformVisitor(transform, exprTransform) ;
+        return transformation(v, element, beforeVisitor, afterVisitor) ;
+    }
+
+    protected Element transformation(ApplyTransformVisitor transformApply, Element element,
+                                     ElementVisitor beforeVisitor, ElementVisitor afterVisitor) {
+        if ( element == null ) {
+            Log.warn(this, "Attempt to transform a null element - ignored") ;
+            return element ;
+        }
+        return applyTransformation(transformApply, element, beforeVisitor, afterVisitor) ;
+    }
+
+    /** The primitive operation to apply a transformation to an Op */
+    protected Element applyTransformation(ApplyTransformVisitor transformApply, Element element,
+                                          ElementVisitor beforeVisitor, ElementVisitor afterVisitor) {
+        ElementWalker.walk(element, transformApply) ; // , beforeVisitor,
+                                                      // afterVisitor) ;
+        Element r = transformApply.result() ;
+        return r ;
+    }
+
+    protected ElementTransformer() {}
+
+    static class ApplyTransformVisitor implements ElementVisitor {
+        protected final ElementTransform transform ;
+        private final ExprTransform      exprTransform ;
+
+        private final Deque<Element>     stack = new ArrayDeque<Element>() ;
+
+        protected final Element pop() {
+            return stack.pop() ;
+        }
+
+        protected final void push(Element elt) {
+            stack.push(elt) ;
+        }
+
+        protected final void pushChanged(Element elt, Element elt2) {
+            if ( elt == elt2 )
+                stack.push(elt) ;
+            else
+                stack.push(elt2) ;
+        }
+
+        public ApplyTransformVisitor(ElementTransform transform, ExprTransform exprTransform) {
+            this.transform = transform ;
+            this.exprTransform = exprTransform ;
+        }
+
+        final Element result() {
+            if ( stack.size() != 1 )
+                Log.warn(this, "Stack is not aligned") ;
+            return pop() ;
+        }
+
+        @Override
+        public void visit(ElementTriplesBlock el) {
+            Element el2 = transform.transform(el) ;
+            pushChanged(el, el2) ;
+        }
+
+        @Override
+        public void visit(ElementPathBlock el) {
+            Element el2 = transform.transform(el) ;
+            pushChanged(el, el2) ;
+        }
+
+        @Override
+        public void visit(ElementFilter el) {
+            Expr expr = el.getExpr() ;
+            Expr expr2 = transform(expr, exprTransform) ;
+            Element el2 = transform.transform(el, expr2) ;
+            pushChanged(el, el2) ;
+        }
+
+        @Override
+        public void visit(ElementAssign el) {
+            Var v = el.getVar() ;
+            Var v1 = TransEltLib.applyVar(v, exprTransform) ;
+            Expr expr = el.getExpr() ;
+            Expr expr1 = ExprTransformer.transform(exprTransform, expr) ;
+            if ( v == v1 && expr == expr1 ) {
+                push(el) ;
+                return ;
+            }
+            push(new ElementAssign(v1, expr1)) ;
+        }
+
+        @Override
+        public void visit(ElementBind el) {
+            Var v = el.getVar() ;
+            Var v1 = TransEltLib.applyVar(v, exprTransform) ;
+            Expr expr = el.getExpr() ;
+            Expr expr1 = ExprTransformer.transform(exprTransform, expr) ;
+            if ( v == v1 && expr == expr1 ) {
+                push(el) ;
+                return ;
+            }
+            push(new ElementBind(v1, expr1)) ;
+        }
+
+        @Override
+        public void visit(ElementData el) {
+            push(el) ;
+        }
+
+        @Override
+        public void visit(ElementOptional el) {
+            Element elSub = el.getOptionalElement() ;
+            Element elSub2 = pop() ;
+            Element el2 = (elSub == elSub2) ? el : new ElementOptional(elSub2) ;
+            pushChanged(el, el2) ;
+        }
+
+        @Override
+        public void visit(ElementGroup el) {
+            ElementGroup newElt = new ElementGroup() ;
+            boolean b = transformFromTo(el.getElements(), newElt.getElements()) ;
+            if ( b )
+                push(newElt) ;
+            else
+                push(el) ;
+        }
+
+        @Override
+        public void visit(ElementUnion el) {
+            ElementUnion newElt = new ElementUnion() ;
+            boolean b = transformFromTo(el.getElements(), newElt.getElements()) ;
+            if ( b )
+                push(newElt) ;
+            else
+                push(el) ;
+        }
+
+        private boolean transformFromTo(List<Element> elts, List<Element> elts2) {
+            boolean changed = false ;
+            for (Element elt : elts) {
+                Element elt2 = pop() ;
+                changed = (changed || (elt != elt2)) ;
+                // Add reversed.
+                elts2.add(0, elt2) ;
+            }
+            return changed ;
+        }
+
+        @Override
+        public void visit(ElementDataset el) {
+            push(el) ;
+            // TODO
+            // el.getPatternElement() ;
+        }
+
+        @Override
+        public void visit(ElementNamedGraph el) {
+            Node n = el.getGraphNameNode() ;
+            Node n1 = TransEltLib.apply(n, exprTransform) ;
+            Element elt = el.getElement() ;
+            Element elt1 = pop() ;
+            if ( n == n1 && elt == elt1 )
+                push(el) ;
+            else
+                push(new ElementNamedGraph(n1, elt1)) ;
+        }
+
+        @Override
+        public void visit(ElementExists el) {
+            Element elt = el.getElement() ;
+            Element elt1 = subElement(elt) ;
+            if ( elt == elt1 )
+                push(el) ;
+            else
+                push(new ElementExists(elt1)) ;
+        }
+
+        @Override
+        public void visit(ElementNotExists el) {
+            Element elt = el.getElement() ;
+            Element elt1 = subElement(elt) ;
+            if ( elt == elt1 )
+                push(el) ;
+            else
+                push(new ElementNotExists(elt1)) ;
+        }
+
+        // When you need to force the walking of the tree ... EXISTS / NOT
+        // EXISTS
+        private Element subElement(Element elt) {
+            ElementWalker.walk(elt, this) ;
+            Element elt1 = pop() ;
+            return elt1 ;
+        }
+
+        @Override
+        public void visit(ElementMinus el) {
+            Element elt = el.getMinusElement() ;
+            Element elt1 = pop() ;
+            if ( elt == elt1 )
+                push(el) ;
+            else
+                push(new ElementMinus(elt1)) ;
+        }
+
+        @Override
+        public void visit(ElementService el) {
+            boolean b = el.getSilent() ;
+            Node n = el.getServiceNode() ;
+            Node n1 = TransEltLib.apply(n, exprTransform) ;
+            Element elt = el.getElement() ;
+            Element elt1 = pop() ;
+            if ( n == n1 && elt == elt1 )
+                push(el) ;
+            else
+                push(new ElementService(n1, elt1, b)) ;
+        }
+
+        @Override
+        public void visit(ElementSubQuery el) {
+            Query newQuery = QueryTransformOps.transform(el.getQuery(), transform, exprTransform) ;
+            push(new ElementSubQuery(newQuery)) ;
+        }
+
+        // private Element transform(Element el)
+        // {
+        // el.visit(this) ;
+        // return pop() ;
+        // }
+
+        private ExprList transform(ExprList exprList, ExprTransform exprTransform) {
+            if ( exprList == null || exprTransform == null )
+                return exprList ;
+            return ExprTransformer.transform(exprTransform, exprList) ;
+        }
+
+        private Expr transform(Expr expr, ExprTransform exprTransform) {
+            if ( expr == null || exprTransform == null )
+                return expr ;
+            return ExprTransformer.transform(exprTransform, expr) ;
+        }
+    }
+}

Added: jena/Scratch/AFS/Dev/src/element/ExprTransformNodeElement.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/element/ExprTransformNodeElement.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/element/ExprTransformNodeElement.java (added)
+++ jena/Scratch/AFS/Dev/src/element/ExprTransformNodeElement.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package element ;
+
+import org.apache.jena.atlas.lib.InternalErrorException ;
+
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.sparql.algebra.Op ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.sparql.expr.* ;
+import com.hp.hpl.jena.sparql.graph.NodeTransform ;
+import com.hp.hpl.jena.sparql.syntax.Element ;
+
+/**
+ * Special version of ExprTransform for applying a node transform on syntax
+ * (Elements) only
+ */
+public class ExprTransformNodeElement extends ExprTransformCopy {
+    private final NodeTransform    nodeTransform ;
+    private final ElementTransform elementTransform ;
+
+    public ExprTransformNodeElement(NodeTransform nodeTransform, ElementTransform eltrans) {
+        this.nodeTransform = nodeTransform ;
+        this.elementTransform = eltrans ;
+    }
+
+    @Override
+    public Expr transform(ExprVar nv) {
+        Node n = nodeTransform.convert(nv.getAsNode()) ;
+        if ( n == nv.getAsNode() )
+            return nv ;
+        if ( n instanceof Var ) {
+            Var v = Var.alloc(n) ;
+            return new ExprVar(v) ;
+        }
+        return NodeValue.makeNode(n) ;
+    }
+
+    @Override
+    public Expr transform(NodeValue nv) {
+        Node n = nodeTransform.convert(nv.asNode()) ;
+        if ( n == nv.asNode() )
+            return nv ;
+        return NodeValue.makeNode(n) ;
+    }
+
+    @Override
+    public Expr transform(ExprFunctionOp funcOp, ExprList args, Op opArg) {
+        // Syntax phased only - ignore args and opArg
+        Element elt = funcOp.getElement() ;
+        Element elt1 = ElementTransformer.transform(elt, elementTransform) ;
+        if ( elt == elt1 )
+            return funcOp ;
+        else {
+            if ( funcOp instanceof E_Exists )
+                return new E_Exists(elt1) ;
+            if ( funcOp instanceof E_NotExists )
+                return new E_NotExists(elt1) ;
+            throw new InternalErrorException("Unknown ExprFunctionOp: " + funcOp.getFunctionSymbol()) ;
+        }
+    }
+}

Added: jena/Scratch/AFS/Dev/src/element/MainElt.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/element/MainElt.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/element/MainElt.java (added)
+++ jena/Scratch/AFS/Dev/src/element/MainElt.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package element;
+
+
+import java.util.HashMap ;
+import java.util.Map ;
+
+import org.apache.jena.atlas.lib.StrUtils ;
+
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.graph.NodeFactory ;
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.query.QueryFactory ;
+import com.hp.hpl.jena.query.Syntax ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.update.UpdateFactory ;
+import com.hp.hpl.jena.update.UpdateRequest ;
+
+public class MainElt
+{
+    public static void main(String[] args)
+    {
+        String x = StrUtils.strjoinNL
+            ( "PREFIX : <http://example/>"
+              //, "SELECT * { ?s :p ?x . NOT EXISTS { ?x :r ?x }  FILTER NOT EXISTS { ?x :r ?x } FILTER ( ?x > ?y ) OPTIONAL { ?x :q ?y } }"
+            //, "SELECT ?x { ?s :p ?x . FILTER NOT EXISTS { ?x :r ?x }} GROUP BY ?x ORDER BY ?x"
+            , "ASK { FILTER (?x = <http://example/X>) }"
+            );
+        
+        Query q = QueryFactory.create(x, Syntax.syntaxARQ) ;
+
+        Map<Var, Node> map = new HashMap<Var, Node>() ;
+        map.put(Var.alloc("x"), NodeFactory.createURI("http://example/X")) ; 
+        
+        Query q2 = QueryTransformOps.transform(q, map) ;
+        System.out.print(q) ;
+        System.out.println("-------------");
+        System.out.print(q2) ;
+        System.out.println("-------------");
+        
+        String z = StrUtils.strjoinNL
+            ( "PREFIX : <http://example/>"
+            , "DELETE { ?s :p ?x } WHERE {}" 
+            );
+        UpdateRequest req = UpdateFactory.create(z) ;
+        UpdateRequest req2 = UpdateTransformOps.transform(req, map) ;
+        System.out.print(req) ;
+        System.out.println("-------------");
+        System.out.print(req2) ;
+        System.out.println("-------------");
+        
+        
+    }
+    
+}
+

Added: jena/Scratch/AFS/Dev/src/element/NodeTransformSubst.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/element/NodeTransformSubst.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/element/NodeTransformSubst.java (added)
+++ jena/Scratch/AFS/Dev/src/element/NodeTransformSubst.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package element ;
+
+import java.util.Map ;
+
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.sparql.graph.NodeTransform ;
+
+/** Substituting variables for a Node */
+public class NodeTransformSubst implements NodeTransform {
+    private final Map<Var, Node> map ;
+
+    NodeTransformSubst(Map<Var, Node> map) {
+        this.map = map ;
+    }
+
+    @Override
+    public Node convert(Node node) {
+        Node n = map.get(node) ;
+        if ( n == null )
+            return node ;
+        return n ;
+    }
+}

Added: jena/Scratch/AFS/Dev/src/element/QueryTransformOps.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/element/QueryTransformOps.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/element/QueryTransformOps.java (added)
+++ jena/Scratch/AFS/Dev/src/element/QueryTransformOps.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,229 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package element ;
+
+import java.util.Map ;
+
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.query.QueryVisitor ;
+import com.hp.hpl.jena.query.SortCondition ;
+import com.hp.hpl.jena.shared.PrefixMapping ;
+import com.hp.hpl.jena.shared.impl.PrefixMappingImpl ;
+import com.hp.hpl.jena.sparql.ARQException ;
+import com.hp.hpl.jena.sparql.core.* ;
+import com.hp.hpl.jena.sparql.expr.* ;
+import com.hp.hpl.jena.sparql.graph.NodeTransform ;
+import com.hp.hpl.jena.sparql.syntax.Element ;
+
+/** Support for transformation of query abstract syntax. */ 
+
+public class QueryTransformOps {
+    public static Query transform(Query query, Map<Var, Node> substitutions) {
+        ElementTransform eltrans = new ElementTransformSubst(substitutions) ;
+        NodeTransform nodeTransform = new NodeTransformSubst(substitutions) ;
+        ExprTransform exprTrans = new ExprTransformNodeElement(nodeTransform, eltrans) ;
+        return transform(query, eltrans, exprTrans) ;
+    }
+
+    public static Query transform(Query query, ElementTransform transform, ExprTransform exprTransform) {
+        Query q2 = QueryTransformOps.shallowCopy(query) ;
+
+        transformVarExprList(q2.getProject(), exprTransform) ;
+        transformVarExprList(q2.getGroupBy(), exprTransform) ;
+        // Nothing to do about ORDER BY - leave to sort by that variable.
+
+        Element el = q2.getQueryPattern() ;
+        Element el2 = ElementTransformer.transform(el, transform, exprTransform) ;
+        q2.setQueryPattern(el2) ;
+        return q2 ;
+    }
+
+    // Mutates the VarExprList
+    private static void transformVarExprList(VarExprList varExprList, ExprTransform exprTransform)
+    // , final Map<Var, Node> substitutions)
+    {
+        Map<Var, Expr> map = varExprList.getExprs() ;
+
+        for (Var v : varExprList.getVars()) {
+            Expr e = varExprList.getExpr(v) ;
+            ExprVar ev = new ExprVar(v) ;
+            Expr ev2 = exprTransform.transform(ev) ;
+            if ( ev != ev2 ) {
+                if ( e != null )
+                    throw new ARQException("Can't substitute " + v + " because it's used as an AS variable") ;
+                if ( ev2 instanceof NodeValue ) {
+                    // Convert to (substit value AS ?var)
+                    map.put(v, ev2) ;
+                    continue ;
+                } else
+                    throw new ARQException("Can't substitute " + v + " because it's not a simple value: " + ev2) ;
+            }
+            if ( e == null )
+                continue ;
+
+            // Didn't change the variable.
+            Expr e2 = ExprTransformer.transform(exprTransform, e) ;
+            if ( e != e2 )
+                // replace
+                map.put(v, e2) ;
+        }
+    }
+
+    static class QueryShallowCopy implements QueryVisitor {
+        final Query newQuery = new Query() ;
+
+        QueryShallowCopy() {}
+
+        @Override
+        public void startVisit(Query query) {
+            newQuery.setSyntax(query.getSyntax()) ;
+
+            if ( query.explicitlySetBaseURI() )
+                newQuery.setBaseURI(query.getPrologue().getResolver()) ;
+
+            newQuery.setQueryResultStar(query.isQueryResultStar()) ;
+
+            if ( query.hasDatasetDescription() ) {
+                DatasetDescription desc = query.getDatasetDescription() ;
+                for (String x : desc.getDefaultGraphURIs())
+                    newQuery.addGraphURI(x) ;
+                for (String x : desc.getDefaultGraphURIs())
+                    newQuery.addNamedGraphURI(x) ;
+            }
+            // Not needed in a shallow copy?
+            // for ( ExprAggregator agg : query.getAggregators() )
+            // {
+            // // Hooks for
+            // //aggregatorsAllocated.put(key, v) ;
+            // //aggregatorsMap.put(v, aggExpr) ;
+            // //aggregators.add(aggExpr) ;
+            // }
+
+        }
+
+        @Override
+        public void visitPrologue(Prologue prologue) {
+            // newQuery.setBaseURI(prologue.getResolver()) ;
+            PrefixMapping pmap = new PrefixMappingImpl().setNsPrefixes(prologue.getPrefixMapping()) ;
+            newQuery.setPrefixMapping(pmap) ;
+        }
+
+        @Override
+        public void visitResultForm(Query q) {}
+
+        @Override
+        public void visitSelectResultForm(Query query) {
+            newQuery.setQuerySelectType() ;
+            newQuery.setDistinct(query.isDistinct()) ;
+            VarExprList x = query.getProject() ;
+            for (Var v : x.getVars()) {
+                Expr expr = x.getExpr(v) ;
+                if ( expr == null )
+                    newQuery.addResultVar(v) ;
+                else
+                    newQuery.addResultVar(v, expr) ;
+            }
+        }
+
+        @Override
+        public void visitConstructResultForm(Query query) {
+            newQuery.setQueryConstructType() ;
+            newQuery.setConstructTemplate(query.getConstructTemplate()) ;
+        }
+
+        @Override
+        public void visitDescribeResultForm(Query query) {
+            newQuery.setQueryDescribeType() ;
+            for (Node x : query.getResultURIs())
+                newQuery.addDescribeNode(x) ;
+        }
+
+        @Override
+        public void visitAskResultForm(Query query) {
+            newQuery.setQueryAskType() ;
+        }
+
+        @Override
+        public void visitDatasetDecl(Query query) {}
+
+        @Override
+        public void visitQueryPattern(Query query) {
+            newQuery.setQueryPattern(query.getQueryPattern()) ;
+        }
+
+        @Override
+        public void visitGroupBy(Query query) {
+            if ( query.hasGroupBy() ) {
+                VarExprList x = query.getGroupBy() ;
+
+                for (Var v : x.getVars()) {
+                    Expr expr = x.getExpr(v) ;
+                    if ( expr == null )
+                        newQuery.addGroupBy(v) ;
+                    else
+                        newQuery.addGroupBy(v, expr) ;
+                }
+            }
+        }
+
+        @Override
+        public void visitHaving(Query query) {
+            if ( query.hasHaving() ) {
+                for (Expr expr : query.getHavingExprs())
+                    newQuery.addHavingCondition(expr) ;
+            }
+        }
+
+        @Override
+        public void visitOrderBy(Query query) {
+            if ( query.hasOrderBy() ) {
+                for (SortCondition sc : query.getOrderBy())
+                    newQuery.addOrderBy(sc) ;
+            }
+        }
+
+        @Override
+        public void visitLimit(Query query) {
+            newQuery.setLimit(query.getLimit()) ;
+        }
+
+        @Override
+        public void visitOffset(Query query) {
+            newQuery.setOffset(query.getOffset()) ;
+        }
+
+        @Override
+        public void visitValues(Query query) {
+            if ( query.hasValues() )
+                newQuery.setValuesDataBlock(query.getValuesVariables(), query.getValuesData()) ;
+        }
+
+        @Override
+        public void finishVisit(Query query) {}
+    }
+
+    public static Query shallowCopy(Query query) {
+        QueryShallowCopy copy = new QueryShallowCopy() ;
+        query.visit(copy) ;
+        Query q2 = copy.newQuery ;
+        return q2 ;
+    }
+
+}

Added: jena/Scratch/AFS/Dev/src/element/TestQueryOps.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/element/TestQueryOps.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/element/TestQueryOps.java (added)
+++ jena/Scratch/AFS/Dev/src/element/TestQueryOps.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package element;
+
+import org.apache.jena.atlas.junit.BaseTest ;
+import org.junit.Test ;
+
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.query.QueryFactory ;
+
+public class TestQueryOps  extends BaseTest
+{
+    @Test public void queryOp_01() { testShallowCopy("SELECT * { }") ; }
+    
+    @Test public void queryOp_02() { testShallowCopy("SELECT ?x { }") ; }
+    
+    @Test public void queryOp_03() { testShallowCopy("SELECT * { ?s ?p ?o }") ; }
+
+    @Test public void queryOp_04() { testShallowCopy("SELECT ?x { ?s ?p ?o }") ; }
+
+    @Test public void queryOp_05() { testShallowCopy("SELECT (?x+1 AS ?z) ?y { }") ; }
+    
+    @Test public void queryOp_06() { testShallowCopy("SELECT DISTINCT (?x+1 AS ?z) ?y { }") ; }
+
+    @Test public void queryOp_07() { testShallowCopy("SELECT REDUCED (?x+1 AS ?z) ?y { }") ; }
+
+    @Test public void queryOp_10() { testShallowCopy("SELECT ?s { ?s ?p ?o } GROUP BY ?s") ; }
+
+    @Test public void queryOp_11() { testShallowCopy("SELECT ?s { ?s ?p ?o } ORDER BY ?o") ; }
+
+    @Test public void queryOp_12() { testShallowCopy("SELECT ?s { ?s ?p ?o } LIMIT 10") ; }
+
+    @Test public void queryOp_13() { testShallowCopy("SELECT ?s { ?s ?p ?o } OFFSET 5 LIMIT 10") ; }
+
+    private static void testShallowCopy(String queryString)
+    {
+        Query q1 = QueryFactory.create(queryString) ;
+        Query q2 = QueryTransformOps.shallowCopy(q1) ;
+        assertEquals(q1, q2) ;
+    }
+
+}
+

Added: jena/Scratch/AFS/Dev/src/element/TestSubstitution.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/element/TestSubstitution.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/element/TestSubstitution.java (added)
+++ jena/Scratch/AFS/Dev/src/element/TestSubstitution.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package element;
+
+import java.util.HashMap ;
+import java.util.Map ;
+
+import org.apache.jena.atlas.junit.BaseTest ;
+import org.junit.Test ;
+
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.query.QueryFactory ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.sparql.sse.SSE ;
+import com.hp.hpl.jena.update.UpdateFactory ;
+import com.hp.hpl.jena.update.UpdateRequest ;
+
+public class TestSubstitution extends BaseTest
+{
+    @Test public void subst_01() { testQuery("SELECT * { }", "SELECT * {}", "o", "1") ; }
+    
+    @Test public void subst_02() { testQuery("SELECT ?x { }", "SELECT ?x {}", "o", "1") ; }
+
+    @Test public void subst_03() { testQuery("SELECT ?o { }", "SELECT (1 as ?o) {}", "o", "1") ; }
+
+    @Test public void subst_04() { testQuery("SELECT (?o AS ?z) { }", "SELECT (1 AS ?z) {}", "o", "1") ; }
+
+    @Test public void subst_05() { testQuery("SELECT (?o+2 AS ?z) { }", "SELECT (1+2 AS ?z) {}", "o", "1") ; }
+
+    @Test public void subst_09() { testQuery("SELECT * {?s ?p ?o}", "SELECT * {?s ?p 1}", "o", "1") ; }  
+    
+    @Test public void subst_10() { testQuery("SELECT * { SELECT ?o {} }", "SELECT * {SELECT (1 as ?o) {}}", "o", "1") ; }
+
+    @Test public void subst_50() { testUpdate("DELETE { ?s <urn:p> ?x } WHERE {}",
+                                              "DELETE { ?s <urn:p> <urn:x> } WHERE {}", "x", "<urn:x>") ; }
+
+    //static final String PREFIX = "PREFIX : <http://example/>\n" ;
+    static final String PREFIX = "" ;
+
+    private void testQuery(String input, String output, String varStr, String valStr)
+    {
+        Query q1 = QueryFactory.create(PREFIX+input) ;
+        Query qExpected = QueryFactory.create(PREFIX+output) ;
+        
+        Map<Var, Node> map = new HashMap<Var, Node>() ;
+        map.put(Var.alloc(varStr), SSE.parseNode(valStr)) ;
+        
+        Query qTrans = QueryTransformOps.transform(q1, map) ;
+        assertEquals(qExpected, qTrans) ;
+    }
+
+    private void testUpdate(String input, String output, String varStr, String valStr)
+    {
+        UpdateRequest req1 = UpdateFactory.create(PREFIX+input) ;
+        UpdateRequest reqExpected = UpdateFactory.create(PREFIX+output) ;
+        
+        Map<Var, Node> map = new HashMap<Var, Node>() ;
+        map.put(Var.alloc(varStr), SSE.parseNode(valStr)) ;
+        
+        UpdateRequest reqTrans = UpdateTransformOps.transform(req1, map) ;
+        
+        // Crude.
+        String x1 = reqExpected.toString().replaceAll("[ \n\t]", "") ;
+        String x2 = reqTrans.toString().replaceAll("[ \n\t]", "") ;
+        //assertEquals(reqExpected, reqTrans) ;
+        assertEquals(x1, x2) ;
+    }
+    
+}
+

Added: jena/Scratch/AFS/Dev/src/element/TransEltLib.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/element/TransEltLib.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/element/TransEltLib.java (added)
+++ jena/Scratch/AFS/Dev/src/element/TransEltLib.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package element ;
+
+import org.apache.jena.atlas.lib.InternalErrorException ;
+
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.sparql.expr.Expr ;
+import com.hp.hpl.jena.sparql.expr.ExprTransform ;
+import com.hp.hpl.jena.sparql.expr.ExprVar ;
+import com.hp.hpl.jena.sparql.expr.NodeValue ;
+
+public class TransEltLib {
+    public static Var applyVar(Var v, ExprTransform exprTransform) {
+        ExprVar expr = new ExprVar(v) ;
+        Expr e = exprTransform.transform(expr) ;
+        if ( e instanceof ExprVar )
+            return ((ExprVar)e).asVar() ;
+        throw new InternalErrorException("Managed to turn a variable " + v + " into " + e) ;
+    }
+
+    public static Node apply(Node n, ExprTransform exprTransform) {
+        Expr e = null ;
+        if ( Var.isVar(n) ) {
+            Var v = Var.alloc(n) ;
+            ExprVar expr = new ExprVar(v) ;
+            e = exprTransform.transform(expr) ;
+        } else {
+            NodeValue nv = NodeValue.makeNode(n) ;
+            e = exprTransform.transform(nv) ;
+        }
+
+        if ( e instanceof ExprVar )
+            return ((ExprVar)e).asVar() ;
+        if ( e instanceof NodeValue )
+            return ((NodeValue)e).asNode() ;
+        throw new InternalErrorException("Managed to turn a node " + n + " into " + e) ;
+    }
+
+}

Added: jena/Scratch/AFS/Dev/src/element/UpdateTransformOps.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/element/UpdateTransformOps.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/element/UpdateTransformOps.java (added)
+++ jena/Scratch/AFS/Dev/src/element/UpdateTransformOps.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,209 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package element ;
+
+import java.util.ArrayList ;
+import java.util.List ;
+import java.util.Map ;
+
+import org.apache.jena.atlas.lib.Sink ;
+
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.sparql.core.Quad ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.sparql.expr.ExprTransform ;
+import com.hp.hpl.jena.sparql.graph.NodeTransform ;
+import com.hp.hpl.jena.sparql.modify.request.* ;
+import com.hp.hpl.jena.sparql.syntax.Element ;
+import com.hp.hpl.jena.update.Update ;
+import com.hp.hpl.jena.update.UpdateRequest ;
+
+/** Support for transformation of update abstract syntax. */ 
+public class UpdateTransformOps {
+    
+    public static Update transform(Update update, Map<Var, Node> substitutions) {
+        ElementTransform eltrans = new ElementTransformSubst(substitutions) ;
+        NodeTransform nodeTransform = new NodeTransformSubst(substitutions) ;
+        ExprTransform exprTrans = new ExprTransformNodeElement(nodeTransform, eltrans) ;
+        return transform(update, eltrans, exprTrans) ;
+    }
+
+    public static UpdateRequest transform(UpdateRequest update, Map<Var, Node> substitutions) {
+        ElementTransform eltrans = new ElementTransformSubst(substitutions) ;
+        NodeTransform nodeTransform = new NodeTransformSubst(substitutions) ;
+        ExprTransform exprTrans = new ExprTransformNodeElement(nodeTransform, eltrans) ;
+        return transform(update, eltrans, exprTrans) ;
+    }
+
+    public static Update transform(Update update, ElementTransform transform, ExprTransform exprTransform) {
+        UpdateTransform upParam = new UpdateTransform(transform, exprTransform) ;
+        update.visit(upParam) ;
+        Update update1 = upParam.result ;
+        return update1 ;
+    }
+
+    public static UpdateRequest transform(UpdateRequest update, ElementTransform transform, ExprTransform exprTransform) {
+        UpdateRequest req = new UpdateRequest() ;
+        req.getPrefixMapping().setNsPrefixes(update.getPrefixMapping()) ;
+        
+        for (Update up : update.getOperations()) {
+            up = transform(up, transform, exprTransform) ;
+            req.add(up) ;
+        }
+
+        return req ;
+    }
+
+    static class UpdateTransform implements UpdateVisitor {
+        ElementTransform elTransform ;
+        ExprTransform    exprTransform ;
+        Update           result = null ;
+
+        public UpdateTransform(ElementTransform transform, ExprTransform exprTransform) {
+            this.elTransform = transform ;
+            this.exprTransform = exprTransform ;
+        }
+
+        @Override
+        public void visit(UpdateDrop update) {
+            result = update ;
+        }
+
+        @Override
+        public void visit(UpdateClear update) {
+            result = update ;
+        }
+
+        @Override
+        public void visit(UpdateCreate update) {
+            result = update ;
+        }
+
+        @Override
+        public void visit(UpdateLoad update) {
+            result = update ;
+        }
+
+        @Override
+        public void visit(UpdateAdd update) {
+            result = update ;
+        }
+
+        @Override
+        public void visit(UpdateCopy update) {
+            result = update ;
+        }
+
+        @Override
+        public void visit(UpdateMove update) {
+            result = update ;
+        }
+
+        @Override
+        public void visit(UpdateDataInsert update) {
+            result = update ;
+        }
+
+        @Override
+        public void visit(UpdateDataDelete update) {
+            result = update ;
+        }
+
+        @Override
+        public void visit(UpdateDeleteWhere update) {
+            List<Quad> quads = update.getQuads() ;
+            List<Quad> quads2 = transform(quads) ;
+            if ( quads == quads2 )
+                result = update ;
+            else {
+                QuadAcc acc = new QuadAcc() ;
+                addAll(acc, quads2) ;
+                result = new UpdateDeleteWhere(acc) ;
+            }
+        }
+
+        @Override
+        public void visit(UpdateModify update) {
+            Element el = update.getWherePattern() ;
+            Element el2 = ElementTransformer.transform(el, elTransform, exprTransform) ;
+
+            List<Quad> del = update.getDeleteQuads() ;
+            List<Quad> del1 = transform(del) ;
+            List<Quad> ins = update.getInsertQuads() ;
+            List<Quad> ins1 = transform(ins) ;
+
+            UpdateModify mod = new UpdateModify() ;
+
+            addAll(mod.getDeleteAcc(), del1) ;
+            addAll(mod.getInsertAcc(), ins1) ;
+            result = mod ;
+        }
+
+        private void addAll(QuadAcc acc, List<Quad> quads) {
+            for (Quad q : quads)
+                acc.addQuad(q) ;
+        }
+
+        public List<Quad> transform(List<Quad> quads) {
+            List<Quad> x = new ArrayList<Quad>() ;
+            boolean changed = false ;
+            for (Quad q : quads) {
+                Quad q1 = transform(q) ;
+                changed = changed || q1 != q ;
+                x.add(q1) ;
+            }
+            if ( changed )
+                return x ;
+            return quads ;
+        }
+
+        private Quad transform(Quad q) {
+            Node g = q.getGraph() ;
+            Node g1 = transform(g) ;
+            Node s = q.getSubject() ;
+            Node s1 = transform(s) ;
+            Node p = q.getPredicate() ;
+            Node p1 = transform(p) ;
+            Node o = q.getObject() ;
+            Node o1 = transform(o) ;
+            if ( g == g1 && s == s1 && p == p1 && o == o1 )
+                return q ;
+            return Quad.create(g1, s1, p1, o1) ;
+        }
+
+        private Node transform(Node n) {
+            if ( Var.isVar(n) )
+                return TransEltLib.apply(Var.alloc(n), exprTransform) ;
+            else
+                return TransEltLib.apply(n, exprTransform) ;
+        }
+
+        @Override
+        public Sink<Quad> createInsertDataSink() {
+            return null ;
+        }
+
+        @Override
+        public Sink<Quad> createDeleteDataSink() {
+            return null ;
+        }
+
+    }
+
+}

Added: jena/Scratch/AFS/Dev/src/opexec/OpExecutorExample.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/opexec/OpExecutorExample.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/opexec/OpExecutorExample.java (added)
+++ jena/Scratch/AFS/Dev/src/opexec/OpExecutorExample.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package opexec ;
+
+import java.io.StringReader ;
+
+import org.apache.jena.atlas.lib.StrUtils ;
+import org.apache.jena.atlas.logging.LogCtl ;
+
+import com.hp.hpl.jena.query.* ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.rdf.model.ModelFactory ;
+import com.hp.hpl.jena.sparql.algebra.op.OpBGP ;
+import com.hp.hpl.jena.sparql.algebra.op.OpFilter ;
+import com.hp.hpl.jena.sparql.core.BasicPattern ;
+import com.hp.hpl.jena.sparql.engine.ExecutionContext ;
+import com.hp.hpl.jena.sparql.engine.QueryIterator ;
+import com.hp.hpl.jena.sparql.engine.main.OpExecutor ;
+import com.hp.hpl.jena.sparql.engine.main.OpExecutorFactory ;
+import com.hp.hpl.jena.sparql.engine.main.QC ;
+
+/**
+ * Example skeleton for a query engine. To just extend ARQ by custom basic graph
+ * pattern matching (a very common case) see the arq.examples.bgpmatching
+ * package
+ */
+
+public class OpExecutorExample // extends QueryEngineMain
+{
+    // UNFINISHED
+    // Check where OpExecutorFactory.create happens.
+
+    /*
+     * To install a custom OpExecutor, the application needs
+     * 
+     * 
+     * The example MyQueryEngine shows how to take over the execution of a
+     * SPARQL algebra expression. This allows customization of optimizations
+     * running before query execution starts.
+     * 
+     * An OpExecutor controls the running of an algebra expression. An executor
+     * needs to cope with the fact a dataset might be composed of a mixture of
+     * graphs, and that it might be be being called for any kind of storage
+     * unit, not just one it is designed for.
+     * 
+     * Thsi is done by having a chain (via subclassing) of OpExecutors, with the
+     * base class being hthe general purpose one for ARQ that can operate on any
+     * data storage layer.
+     */
+
+    static void init() {
+        // Wire the new factory into the system.
+        ARQ.init() ;
+        // *** Where is the factory choosen?
+        OpExecutorFactory current = QC.getFactory(ARQ.getContext()) ;
+        // maybe null
+        QC.setFactory(ARQ.getContext(), new MyOpExecutorFactory(current)) ;
+    }
+
+    public static void main(String... argv) {
+        LogCtl.setLog4j() ;
+        init() ;
+        Model m = data() ;
+
+        String s = "SELECT DISTINCT ?s { ?s ?p ?o FILTER (?o=12) } " ;
+        Query query = QueryFactory.create(s) ;
+        QueryExecution qExec = QueryExecutionFactory.create(query, m) ;
+        ResultSetFormatter.out(qExec.execSelect()) ;
+        qExec.close() ;
+    }
+
+    private static Model data() {
+        String s = StrUtils.strjoinNL("<s> <p> 12 .", "<s> <p> 15 .") ;
+        Model m = ModelFactory.createDefaultModel() ;
+        m.read(new StringReader(s), null, "TTL") ;
+        return m ;
+    }
+
+    // This is a simple example.
+    // For execution logging, see:
+    // http://openjena.org/wiki/ARQ/Explain
+    // which printout more information.
+    static class MyOpExecutor extends OpExecutor
+    {
+        protected MyOpExecutor(ExecutionContext execCxt)
+        {
+            super(execCxt) ;
+        }
+
+        @Override
+        protected QueryIterator execute(OpBGP opBGP, QueryIterator input) {
+            System.out.print("Execute: " + opBGP) ;
+            // This is an illustration - it's a copy of the default
+            // implementation
+            BasicPattern pattern = opBGP.getPattern() ;
+            return stageGenerator.execute(pattern, input, execCxt) ;
+        }
+
+        @Override
+        protected QueryIterator execute(OpFilter opFilter, QueryIterator input) {
+            System.out.print("Execute: " + opFilter) ;
+            return super.execute(opFilter, input) ;
+        }
+    }
+
+    /** A factory to make OpExecutors */
+    static class MyOpExecutorFactory implements OpExecutorFactory
+    {
+        private final OpExecutorFactory other ;
+
+        public MyOpExecutorFactory(OpExecutorFactory other)
+        {
+            this.other = other ;
+        }
+
+        @Override
+        public OpExecutor create(ExecutionContext execCxt) {
+            return new MyOpExecutor(execCxt) ;
+        }
+    }
+}

Added: jena/Scratch/AFS/Dev/src/opt/Jena384_SubstitueFilterOptimize.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/opt/Jena384_SubstitueFilterOptimize.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/opt/Jena384_SubstitueFilterOptimize.java (added)
+++ jena/Scratch/AFS/Dev/src/opt/Jena384_SubstitueFilterOptimize.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package opt;
+
+import com.hp.hpl.jena.query.* ;
+import com.hp.hpl.jena.rdf.model.ModelFactory ;
+import com.hp.hpl.jena.rdf.model.ResourceFactory ;
+import com.hp.hpl.jena.sparql.algebra.Algebra ;
+import com.hp.hpl.jena.sparql.algebra.Op ;
+import com.hp.hpl.jena.sparql.algebra.Transformer ;
+import com.hp.hpl.jena.sparql.algebra.optimize.TransformFilterEquality ;
+import com.hp.hpl.jena.sparql.core.Substitute ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.sparql.engine.binding.Binding ;
+import com.hp.hpl.jena.sparql.engine.binding.BindingFactory ;
+import com.hp.hpl.jena.sparql.sse.SSE ;
+import com.hp.hpl.jena.sparql.util.QueryExecUtils ;
+
+public class Jena384_SubstitueFilterOptimize {
+
+    public static void main(String ... args)
+    {
+        new Jena384_SubstitueFilterOptimize() .testAskPrebound() ;
+    }
+    
+    //@Test
+    public void testAskPrebound() {
+        String term = "<http://example/>" ;
+        //String term = "'A55'@en" ;
+        
+        Query query = QueryFactory.create("ASK WHERE { FILTER (?arg = "+term+")}");
+        
+        System.out.println(query) ;
+
+        if ( false )
+        {
+            String str = "http://example/" ;
+            QuerySolutionMap binding = new QuerySolutionMap();
+            binding.add("arg", ResourceFactory.createResource(str)) ;
+            QueryExecution qexec = QueryExecutionFactory.create(query, ModelFactory.createDefaultModel());
+            qexec.setInitialBinding(binding);
+            QueryExecUtils.executeQuery(query, qexec) ;
+            System.exit(0) ;
+        }
+        final Op op = Algebra.compile(query) ;
+//        System.out.println("algebra") ;
+//        System.out.println(op) ;
+
+        Binding initialBinding = BindingFactory.binding(Var.alloc("arg"), SSE.parseNode(term)) ;
+        
+        {
+            // Order - substitute then optimize.
+            // Wrong answer, right reasons.
+            Op op1 = Transformer.transform(new TransformFilterEquality(), op);
+            op1 = Substitute.substitute(op1, initialBinding) ;
+            System.out.println("optimized-substitute") ;
+            System.out.println(op1) ;
+        }
+        {
+            // Order - substitue then optimize.
+            // Right answer -- wrong reasons.
+            Op op2 = Substitute.substitute(op,initialBinding) ;
+            op2 = Transformer.transform(new TransformFilterEquality(), op2);
+            System.out.println("substitute-optimize") ;
+            System.out.println(op2) ;
+        }
+        
+//        boolean result = qexec.execAsk();
+//        Assert.assertTrue(result);
+    } 
+}
\ No newline at end of file

Added: jena/Scratch/AFS/Dev/src/opt/OptMain.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/opt/OptMain.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/opt/OptMain.java (added)
+++ jena/Scratch/AFS/Dev/src/opt/OptMain.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,131 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package opt;
+
+import org.apache.jena.atlas.lib.StrUtils ;
+
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.query.QueryFactory ;
+import com.hp.hpl.jena.sparql.algebra.Algebra ;
+import com.hp.hpl.jena.sparql.algebra.Op ;
+import com.hp.hpl.jena.sparql.algebra.Transform ;
+import com.hp.hpl.jena.sparql.algebra.Transformer ;
+import com.hp.hpl.jena.sparql.algebra.optimize.TransformFilterPlacement ;
+import com.hp.hpl.jena.sparql.sse.SSE ;
+
+public class OptMain {
+    
+    
+    // Also TransformDistinctToReduced (JENA-585) and TransformOrderByDistincApplication 
+    
+    // JENA-383 : The query optimizer generates a suboptimal query plan in case of nested optionals followed by a filter
+
+    // JENA-293 : Allow the filter placement optimziation to push FILTER though BIND.
+    //    Filter push throughs.
+    // JENA-384 : SubstituteFilterOptimize :: Interaction of optimization (TransformFilterEquality) and initial binding
+
+    // Was Op.equals a good idea?
+    // Calculate vars for an expr once and cache : op.getVars.
+    
+    public static void main(String... argv) {
+        placement() ;
+    }
+            
+    static void placement() {
+        if ( false ) {
+            //String input = "(filter (?x 123) (sequence (conditional (table unit) 
+            String input = StrUtils.strjoinNL
+                ("(filter (= ?x <http://example/x>)",
+                 "  (sequence",
+                 "    (bgp (triple ?x <http://example/p> ?o2))",
+                 "    (bgp (triple ?x <http://example/p> ?o2))))"
+                    ) ;
+                      
+            Transform t_placement = new TransformFilterPlacement() ;
+            Op op1 = SSE.parseOp(input) ;
+            Op op2 = op1 ;
+            op2 = Algebra.optimize(op1) ;
+            op2 = Transformer.transform(t_placement, op1) ;
+            
+            System.out.print(op2) ;
+            System.out.println("------------------------");
+            System.exit(0) ;
+        }
+
+        if ( true ) {
+            String qs1 = StrUtils.strjoinNL
+                ("PREFIX ex: <http://example.org/test#>", 
+                 "SELECT * WHERE {", 
+                 "    ?var ex:p1 ?x. ",
+                 "    OPTIONAL {", 
+                 "        ?x ex:p2 ?y.",
+                 "        OPTIONAL {",
+                 "            ?y ex:p3 ?z",
+                 "        }",
+                 "    }",
+                 "    FILTER (?var = ex:i)",
+                 "}") ;
+            
+            // Order dependency.
+            // Push LHS and RHS on a JOIN then sequence => Filter twice in sequence.  No harm but ... 
+            
+            /*
+             * PREFIX : <http://example.org/>
+
+SELECT *
+{
+   OPTIONAL { ?x :qq ?o2 }
+   FILTER(?x = :x1)
+   ?x :p ?o1 .
+}
+
+             */
+            
+            String qs3 = StrUtils.strjoinNL
+                ( "PREFIX : <http://example/> SELECT * {"
+                  , "    OPTIONAL { ?x :q ?o }"
+                  , "    FILTER(?x = :x)"
+                  , "    ?x :p ?o2"
+                  , "}"
+                    ) ;
+            String qs4 = StrUtils.strjoinNL
+            ("SELECT *"
+            , "WHERE {"
+            , "    ?test ?p1 ?X." 
+            , "    FILTER ( ?test = <http://localhost/t1> )"
+            , "    { SELECT ?s1 ?test { ?test ?p2 ?o2 } }"
+            , "}") ; 
+
+            Query query = QueryFactory.create(qs4) ;
+            Op op1 = Algebra.compile(query) ;
+            System.out.println("** Input") ;
+            System.out.println(op1) ;
+            System.out.println("** OPTIMIZE") ;
+            Op op2 = Algebra.optimize(op1) ;
+            System.out.println(op2) ;
+            System.exit(0) ;
+        }
+        
+    }
+    
+    static Op placement(Op op) {
+        return Transformer.transform(new TransformFilterPlacement(), op) ;
+    }
+    
+}

Added: jena/Scratch/AFS/Dev/src/opt/TransformFilterEquality2.java
URL: http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src/opt/TransformFilterEquality2.java?rev=1554915&view=auto
==============================================================================
--- jena/Scratch/AFS/Dev/src/opt/TransformFilterEquality2.java (added)
+++ jena/Scratch/AFS/Dev/src/opt/TransformFilterEquality2.java Thu Jan  2 21:00:47 2014
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package opt;
+
+import static org.apache.jena.atlas.lib.CollectionUtils.disjoint ;
+
+import java.util.ArrayList ;
+import java.util.Collection ;
+import java.util.List ;
+import java.util.Set ;
+
+import org.apache.jena.atlas.lib.Pair ;
+
+import com.hp.hpl.jena.query.ARQ ;
+import com.hp.hpl.jena.sparql.algebra.Op ;
+import com.hp.hpl.jena.sparql.algebra.OpVars ;
+import com.hp.hpl.jena.sparql.algebra.TransformCopy ;
+import com.hp.hpl.jena.sparql.algebra.op.* ;
+import com.hp.hpl.jena.sparql.core.Substitute ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.sparql.core.VarExprList ;
+import com.hp.hpl.jena.sparql.engine.main.VarFinder ;
+import com.hp.hpl.jena.sparql.expr.* ;
+
+public class TransformFilterEquality2 extends TransformCopy
+{
+    // The approach taken for { OPTIONAL{} OPTIONAL{} } is more general ... and better?
+    // Still need to be careful of double-nested OPTIONALS as intermediates of a different
+    // value can block overall results so don't mask immediately.
+    public TransformFilterEquality2()
+    { }
+    
+    @Override
+    public Op transform(OpFilter opFilter, Op subOp)
+    {
+        Op op = apply(opFilter.getExprs(), subOp) ;
+        if ( op == null )
+            return super.transform(opFilter, subOp) ;
+        return op ;
+    }
+    
+    private static Op apply(ExprList exprs, Op subOp)
+    {
+        // ---- Find and extract any equality filters.
+        Pair<List<Pair<Var, NodeValue>>, ExprList> p = preprocessFilterEquality(exprs) ;
+        if ( p == null || p.getLeft().size() == 0 )
+            return null ;
+        
+        List<Pair<Var, NodeValue>> equalities = p.getLeft() ;
+        Collection<Var> varsMentioned = varsMentionedInEqualityFilters(equalities) ;
+        ExprList remaining = p.getRight() ;
+        
+        // ---- Check if the subOp is the right shape to transform.
+        Op op = subOp ;
+        
+        // Special case : deduce that the filter will always "eval unbound"
+        // hence elimate all rows.  Return the empty table. 
+        
+        if ( testSpecialCaseUnused(subOp, equalities, remaining))
+            return OpTable.empty() ;
+        
+        // Special case: the deep left op of a OpConditional/OpLeftJoin is unit table.
+        // This is 
+        // { OPTIONAL{P1} OPTIONAL{P2} ... FILTER(?x = :x) } 
+        if ( testSpecialCase1(subOp, equalities, remaining))
+        {
+            // Find backbone of ops
+            List<Op> ops = extractOptionals(subOp) ;
+            ops = processSpecialCase1(ops, equalities) ;
+            // Put back together
+            op = rebuild((Op2)subOp, ops) ;
+            // Put all filters - either we optimized, or we left alone.
+            // Either way, the complete set of filter expressions.
+            op = OpFilter.filter(exprs, op) ;
+            return op ;
+        }
+        
+        // ---- Transform
+
+        if ( ! safeToTransform(varsMentioned, op) )
+            return null ;
+        for ( Pair<Var, NodeValue> equalityTest : equalities )
+            op = processFilterWorker(op, equalityTest.getLeft(), equalityTest.getRight()) ;
+
+        // ---- Place any filter expressions around the processed sub op. 
+        if ( remaining.size() > 0 )
+            op = OpFilter.filter(remaining, op) ;
+        return op ;
+    }
+
+    // --- find and extract 
+    private static Pair<List<Pair<Var, NodeValue>>, ExprList> preprocessFilterEquality(ExprList exprs)
+    {
+        List<Pair<Var, NodeValue>> exprsFilterEquality = new ArrayList<Pair<Var, NodeValue>>() ;
+        ExprList exprsOther = new ExprList() ;
+        for ( Expr e : exprs.getList() )
+        {
+            Pair<Var, NodeValue> p = preprocess(e) ;
+            if ( p != null )
+                exprsFilterEquality.add(p) ;
+            else
+                exprsOther.add(e) ;
+        }
+        if ( exprsFilterEquality.size() == 0 )
+            return null ;
+        return Pair.create(exprsFilterEquality, exprsOther) ;
+    }
+    
+    private static Pair<Var, NodeValue> preprocess(Expr e)
+    {
+        if ( !(e instanceof E_Equals) && !(e instanceof E_SameTerm) )
+            return null ;
+
+        ExprFunction2 eq = (ExprFunction2)e ;
+        Expr left = eq.getArg1() ;
+        Expr right = eq.getArg2() ;
+
+        Var var = null ;
+        NodeValue constant = null ;
+
+        if ( left.isVariable() && right.isConstant() )
+        {
+            var = left.asVar() ;
+            constant = right.getConstant() ;
+        }
+        else if ( right.isVariable() && left.isConstant() )
+        {
+            var = right.asVar() ;
+            constant = left.getConstant() ;
+        }
+
+        if ( var == null || constant == null )
+            return null ;
+
+        // Corner case: sameTerm is false for string/plain literal, 
+        // but true in the graph for graph matching. 
+        if (e instanceof E_SameTerm)
+        {
+            if ( ! ARQ.isStrictMode() && constant.isString() )
+                return null ;
+        }
+        
+        // Final check for "=" where a FILTER = can do value matching when the graph does not.
+        if ( e instanceof E_Equals )
+        {
+            // Value based?
+            if ( ! ARQ.isStrictMode() && constant.isLiteral() )
+                return null ;
+        }
+        
+        return Pair.create(var, constant) ;
+    }
+
+    private static Collection<Var> varsMentionedInEqualityFilters(List<Pair<Var, NodeValue>> equalities)
+    {
+        List<Var> vars = new ArrayList<Var>() ;
+        for ( Pair<Var, NodeValue> p : equalities )
+            vars.add(p.getLeft()) ;
+        return vars ;
+    }
+
+    private static boolean safeToTransform(Collection<Var> varsEquality, Op op)
+    {
+        // Structure as a visitor?
+        if ( op instanceof OpBGP || op instanceof OpQuadPattern )
+            return true ;
+        
+        if ( op instanceof OpFilter )
+        {
+            OpFilter opf = (OpFilter)op ;
+            // Expressions are always safe transform by substitution.
+//            Collection<Var> fvars = opf.getExprs().getVarsMentioned() ;
+//            if ( ! disjoint(fvars, varsEquality) )
+//                return false ;
+            return safeToTransform(varsEquality, opf.getSubOp()) ;
+        }
+        
+        // This will be applied also in sub-calls of the Transform but queries 
+        // are very rarely so deep that it matters. 
+        if ( op instanceof OpSequence )
+        {
+            OpN opN = (OpN)op ;
+            for ( Op subOp : opN.getElements() )
+            {
+                if ( ! safeToTransform(varsEquality, subOp) )
+                    return false ;
+            }
+            return true ; 
+        }
+        
+        if ( op instanceof OpJoin || op instanceof OpUnion)
+        {
+            Op2 op2 = (Op2)op ;
+            
+            VarFinder vf = new VarFinder(op) ;
+            System.out.println("**** Join") ;
+            System.out.println("fixed:  "+vf.getFixed()) ;
+            System.out.println("opt:    "+vf.getOpt()) ;
+            System.out.println("filter: "+vf.getFilter()) ;
+            
+            return safeToTransform(varsEquality, op2.getLeft()) && safeToTransform(varsEquality, op2.getRight()) ; 
+        }
+
+        // Not safe unless filter variables are mentioned on the LHS. 
+        if ( op instanceof OpConditional || op instanceof OpLeftJoin )
+        {
+            Op2 opleftjoin = (Op2)op ;
+
+            VarFinder vf = new VarFinder(op) ;
+            System.out.println("**** LeftJoin") ;
+            System.out.println("fixed:  "+vf.getFixed()) ;
+            System.out.println("opt:    "+vf.getOpt()) ;
+            System.out.println("filter: "+vf.getFilter()) ;
+            
+            if ( ! safeToTransform(varsEquality, opleftjoin.getLeft()) || 
+                 ! safeToTransform(varsEquality, opleftjoin.getRight()) )
+                return false ;
+            
+            // Not only must the left and right be safe to transform,
+            // but the equality variable must be known to be always set. 
+
+            // If the varsLeft are disjoint from assigned vars,
+            // we may be able to push assign down right
+            // (this generalises the unit table case specialcase1)
+            // Needs more investigation.
+            
+            Op opLeft = opleftjoin.getLeft() ;
+            Set<Var> varsLeft = OpVars.visibleVars(opLeft) ;
+            if ( varsLeft.containsAll(varsEquality) )
+                return true ;
+            return false ;
+        }        
+        
+        if ( op instanceof OpGraph )
+        {
+            OpGraph opg = (OpGraph)op ;
+            return safeToTransform(varsEquality, opg.getSubOp()) ;
+        }
+        
+        // Subquery - assume scope rewriting has already been applied.  
+        if ( op instanceof OpModifier )
+        {
+            // ORDER BY?
+            OpModifier opMod = (OpModifier)op ;
+            if ( opMod instanceof OpProject )
+            {
+                OpProject opProject = (OpProject)op ;
+                // Writing "SELECT ?var" for "?var" -> a value would need AS-ification.
+                for ( Var v : opProject.getVars() )
+                {
+                    if ( varsEquality.contains(v) )
+                        return false ;
+                }
+            }
+            return safeToTransform(varsEquality, opMod.getSubOp()) ;
+        }
+                
+        if ( op instanceof OpGroup )
+        {
+            OpGroup opGroup = (OpGroup)op ;
+            VarExprList varExprList = opGroup.getGroupVars() ;
+            return safeToTransform(varsEquality, varExprList) && 
+                   safeToTransform(varsEquality, opGroup.getSubOp()) ;
+        }
+        
+        if ( op instanceof OpTable )
+        {
+            OpTable opTable = (OpTable)op ;
+            if ( opTable.isJoinIdentity() )
+                return true ;
+        }
+
+        // Op1 - OpGroup
+        // Op1 - OpOrder
+        // Op1 - OpAssign, OpExtend
+        // Op1 - OpFilter - done.
+        // Op1 - OpLabel - easy
+        // Op1 - OpService - no.
+        
+        return false ;
+    }
+    
+    private static boolean safeToTransform(Collection<Var> varsEquality, VarExprList varsExprList)
+    {
+        // If the named variable is used, unsafe to rewrite.
+        return disjoint(varsExprList.getVars(), varsEquality) ;
+    }
+    
+    // -- A special case
+
+    private static boolean testSpecialCaseUnused(Op op, List<Pair<Var, NodeValue>> equalities, ExprList remaining)
+    {
+        // If the op does not contain the var at all, for some equality
+        // then the filter expression will be "eval unbound" i.e. false.
+        // We can return empty table.
+        Set<Var> patternVars = OpVars.visibleVars(op) ;
+        for ( Pair<Var, NodeValue> p : equalities )
+        {
+            if ( ! patternVars.contains(p.getLeft()))
+                return true ;
+        }
+        return false ;
+    }
+    
+    // If a sequence of OPTIONALS, and nothing prior to the first, we end up with
+    // a unit table on the left sid of a next of LeftJoin/conditionals.
+
+    private static boolean testSpecialCase1(Op op, List<Pair<Var, NodeValue>> equalities , ExprList remaining )
+    {
+        while ( op instanceof OpConditional || op instanceof OpLeftJoin )
+        {
+            Op2 opleftjoin2 = (Op2)op ;
+            op = opleftjoin2.getLeft() ;
+        }
+        return isUnitTable(op) ;
+    }
+    
+    private static List<Op> extractOptionals(Op op)
+    {
+        List<Op> chain = new ArrayList<Op>() ;
+        while ( op instanceof OpConditional || op instanceof OpLeftJoin )
+        {
+            Op2 opleftjoin2 = (Op2)op ;
+            chain.add(opleftjoin2.getRight()) ;
+            op = opleftjoin2.getLeft() ;
+        }
+        return chain ;
+    }
+
+    private static List<Op> processSpecialCase1(List<Op> ops, List<Pair<Var, NodeValue>> equalities)
+    {
+        List<Op> ops2 = new ArrayList<Op>() ;
+        Collection<Var> vars = varsMentionedInEqualityFilters(equalities) ;
+        
+        for ( Op op : ops )
+        {
+            Op op2 = op ;
+            if ( safeToTransform(vars, op) )
+            {
+                for ( Pair<Var, NodeValue> p : equalities )
+                        op2 = processFilterWorker(op, p.getLeft(), p.getRight()) ;
+            }
+            ops2.add(op2) ;
+        }
+        return ops2 ;
+    }
+
+    private static Op rebuild(Op2 subOp, List<Op> ops)
+    {
+        Op chain = OpTable.unit() ; 
+        for ( Op op : ops )
+        {
+            chain = subOp.copy(chain, op) ;
+        }
+        return chain ;
+    }
+  
+    private static boolean isUnitTable(Op op)
+    {
+        if (op instanceof OpTable )
+        {
+            if ( ((OpTable)op).isJoinIdentity() )
+                return true;  
+        }
+        return false ;
+    }
+    
+    // ---- Transformation
+        
+    private static Op processFilterWorker(Op op, Var var, NodeValue constant)
+    {
+        return subst(op, var, constant) ;
+    }
+    
+    private static Op subst(Op subOp , Var var, NodeValue nv)
+    {
+        Op op = Substitute.substitute(subOp, var, nv.asNode()) ;
+        return OpAssign.assign(op, var, nv) ;
+    }
+    
+    // Helper for TransformFilterDisjunction.
+    
+    /** Apply the FilterEquality transform or return null if no change */
+
+    static Op processFilter(Expr e, Op subOp)
+    {
+        return apply(new ExprList(e), subOp) ;
+    }
+}



Mime
View raw message