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

org.apache.phoenix.parse.SelectStatementRewriter Maven / Gradle / Ivy

There is a newer version: 5.1.0-HBase-2.0.0.2
Show newest version
/*
 * 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 org.apache.phoenix.parse;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;



/**
 * 
 * Class that creates a new select statement by filtering out nodes.
 * Currently only supports filtering out boolean nodes (i.e. nodes
 * that may be ANDed and ORed together.
 *
 * TODO: generize this
 * 
 * @since 0.1
 */
public class SelectStatementRewriter extends ParseNodeRewriter {
    
    /**
     * Rewrite the select statement by filtering out expression nodes from the WHERE clause
     * @param statement the select statement from which to filter.
     * @param removeNodes expression nodes to filter out of WHERE clause.
     * @return new select statement
     * @throws SQLException 
     */
    public static SelectStatement removeFromWhereClause(SelectStatement statement, Set removeNodes) throws SQLException {
        if (removeNodes.isEmpty()) {
            return statement;
        }
        ParseNode where = statement.getWhere();
        SelectStatementRewriter rewriter = new SelectStatementRewriter(removeNodes);
        where = where.accept(rewriter);
        // Return new SELECT statement with updated WHERE clause
        return NODE_FACTORY.select(statement, where);
    }
    
    /**
     * Rewrite the select statement by filtering out expression nodes from the HAVING clause
     * and anding them with the WHERE clause.
     * @param statement the select statement from which to move the nodes.
     * @param moveNodes expression nodes to filter out of HAVING clause and add to WHERE clause.
     * @return new select statement
     * @throws SQLException 
     */
    public static SelectStatement moveFromHavingToWhereClause(SelectStatement statement, Set moveNodes) throws SQLException {
        if (moveNodes.isEmpty()) {
            return statement;
        }
        ParseNode andNode = NODE_FACTORY.and(new ArrayList(moveNodes));
        ParseNode having = statement.getHaving();
        SelectStatementRewriter rewriter = new SelectStatementRewriter(moveNodes);
        having = having.accept(rewriter);
        ParseNode where = statement.getWhere();
        if (where == null) {
            where = andNode;
        } else {
            where = NODE_FACTORY.and(Arrays.asList(where,andNode));
        }
        // Return new SELECT statement with updated WHERE and HAVING clauses
        return NODE_FACTORY.select(statement, where, having);
    }
    
    private static final ParseNodeFactory NODE_FACTORY = new ParseNodeFactory();

    private final Set removeNodes;
    
    private SelectStatementRewriter(Set removeNodes) {
        this.removeNodes = removeNodes;
    }
    
    private static interface CompoundNodeFactory {
        ParseNode createNode(List children);
    }
    
    private boolean enterCompoundNode(ParseNode node) {
        if (removeNodes.contains(node)) {
            return false;
        }
        return true;
    }
    
    private ParseNode leaveCompoundNode(CompoundParseNode node, List children, CompoundNodeFactory factory) {
        int newSize = children.size();
        int oldSize = node.getChildren().size();
        if (newSize == oldSize) {
            return node;
        } else if (newSize > 1) {
            return factory.createNode(children);
        } else if (newSize == 1) {
            // TODO: keep or collapse? Maybe be helpful as context of where a problem occurs if a node could not be consumed
            return(children.get(0));
        } else {
            return null;
        }
    }
    
    @Override
    public boolean visitEnter(AndParseNode node) throws SQLException {
        return enterCompoundNode(node);
    }

    @Override
    public ParseNode visitLeave(AndParseNode node, List nodes) throws SQLException {
        return leaveCompoundNode(node, nodes, new CompoundNodeFactory() {
            @Override
            public ParseNode createNode(List children) {
                return NODE_FACTORY.and(children);
            }
        });
    }

    @Override
    public boolean visitEnter(OrParseNode node) throws SQLException {
        return enterCompoundNode(node);
    }

    @Override
    public ParseNode visitLeave(OrParseNode node, List nodes) throws SQLException {
        return leaveCompoundNode(node, nodes, new CompoundNodeFactory() {
            @Override
            public ParseNode createNode(List children) {
                return NODE_FACTORY.or(children);
            }
        });
    }
    
    @Override
    public boolean visitEnter(ComparisonParseNode node) throws SQLException {
        if (removeNodes.contains(node)) {
            return false;
        }
        return true;
    }

    @Override
    public ParseNode visitLeave(ComparisonParseNode node, List c) throws SQLException {
        return c.isEmpty() ? null : node;
    }
    
    @Override
    public boolean visitEnter(LikeParseNode node) throws SQLException {
        if (removeNodes.contains(node)) {
            return false;
        }
        return true;
    }
    
    @Override
    public ParseNode visitLeave(LikeParseNode node, List c) throws SQLException {
        return c.isEmpty() ? null : node;
    }
    
    @Override
    public boolean visitEnter(InListParseNode node) throws SQLException {
        if (removeNodes.contains(node)) {
            return false;
        }
        return true;
    }
    
    @Override
    public ParseNode visitLeave(InListParseNode node, List c) throws SQLException {
        return c.isEmpty() ? null : node;
    }
    
    @Override
    public boolean visitEnter(InParseNode node) throws SQLException {
        if (removeNodes.contains(node)) {
            return false;
        }
        return true;
    }
    
    @Override
    public ParseNode visitLeave(InParseNode node, List c) throws SQLException {
        return c.isEmpty() ? null : node;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy