blob: 567e92e0ca21cf8d8295cd33a826213420416ac1 [file] [log] [blame]
/*
* 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.optimize;
import org.apache.phoenix.compile.ExpressionCompiler;
import org.apache.phoenix.compile.StatementContext;
import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.parse.AndParseNode;
import org.apache.phoenix.parse.ArrayAllComparisonNode;
import org.apache.phoenix.parse.ArrayAnyComparisonNode;
import org.apache.phoenix.parse.ComparisonParseNode;
import org.apache.phoenix.parse.ExistsParseNode;
import org.apache.phoenix.parse.InParseNode;
import org.apache.phoenix.parse.OrParseNode;
import org.apache.phoenix.parse.ParseNode;
import org.apache.phoenix.parse.ParseNodeFactory;
import org.apache.phoenix.parse.ParseNodeRewriter;
import org.apache.phoenix.parse.SubqueryParseNode;
import org.apache.phoenix.schema.types.PDataType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Creates a new WHERE clause by replaces non-correlated sub-queries with dummy values.
*
* Note that this class does not check the presence of correlation, thus it should only
* be used after de-correlation has been performed.
*/
public class GenSubqueryParamValuesRewriter extends ParseNodeRewriter {
private static final ParseNodeFactory NODE_FACTORY = new ParseNodeFactory();
private final ExpressionCompiler expressionCompiler;
public static ParseNode replaceWithDummyValues(
ParseNode where, StatementContext context) throws SQLException {
return rewrite(where, new GenSubqueryParamValuesRewriter(context));
}
private GenSubqueryParamValuesRewriter(StatementContext context) {
this.expressionCompiler = new ExpressionCompiler(context);
}
protected List<ParseNode> generateDummyValues(
ParseNode lhs, boolean multipleValues) throws SQLException {
Expression expr = lhs.accept(expressionCompiler);
PDataType type = expr.getDataType();
if (!multipleValues) {
return Arrays.<ParseNode> asList(NODE_FACTORY.literal(type.getSampleValue(), type));
}
return Arrays.<ParseNode> asList(
NODE_FACTORY.literal(type.getSampleValue(), type),
NODE_FACTORY.literal(type.getSampleValue(), type),
NODE_FACTORY.literal(type.getSampleValue(), type));
}
@Override
public ParseNode visitLeave(AndParseNode node, List<ParseNode> l) throws SQLException {
return leaveCompoundNode(node, l, new CompoundNodeFactory() {
@Override
public ParseNode createNode(List<ParseNode> children) {
if (children.isEmpty()) {
return null;
}
if (children.size() == 1) {
return children.get(0);
}
return NODE_FACTORY.and(children);
}
});
}
@Override
public ParseNode visitLeave(OrParseNode node, List<ParseNode> l) throws SQLException {
return leaveCompoundNode(node, l, new CompoundNodeFactory() {
@Override
public ParseNode createNode(List<ParseNode> children) {
if (children.isEmpty()) {
return null;
}
if (children.size() == 1) {
return children.get(0);
}
return NODE_FACTORY.or(children);
}
});
}
@Override
public ParseNode visitLeave(InParseNode node, List<ParseNode> l) throws SQLException {
ParseNode lhs = l.get(0);
List<ParseNode> inList = generateDummyValues(lhs, true);
List<ParseNode> children = new ArrayList<ParseNode>();
children.add(lhs);
children.addAll(inList);
return NODE_FACTORY.inList(children, node.isNegate());
}
@Override
public ParseNode visitLeave(ExistsParseNode node, List<ParseNode> l) throws SQLException {
return null;
}
@Override
public ParseNode visitLeave(ComparisonParseNode node, List<ParseNode> l) throws SQLException {
if (!(l.get(1) instanceof SubqueryParseNode)) {
super.visitLeave(node, l);
}
ParseNode lhs = l.get(0);
List<ParseNode> rhs = generateDummyValues(lhs, false);
List<ParseNode> children = new ArrayList<ParseNode>();
children.add(lhs);
children.add(rhs.get(0));
return super.visitLeave(node, children);
}
@Override
public ParseNode visitLeave(ArrayAnyComparisonNode node, List<ParseNode> l) throws SQLException {
ComparisonParseNode compare = (ComparisonParseNode) l.get(1);
ParseNode lhs = compare.getLHS();
List<ParseNode> rhs = generateDummyValues(lhs, false);
return NODE_FACTORY.comparison(compare.getFilterOp(), lhs, rhs.get(0));
}
@Override
public ParseNode visitLeave(ArrayAllComparisonNode node, List<ParseNode> l) throws SQLException {
ComparisonParseNode compare = (ComparisonParseNode) l.get(1);
ParseNode lhs = compare.getLHS();
List<ParseNode> rhs = generateDummyValues(lhs, false);
return NODE_FACTORY.comparison(compare.getFilterOp(), lhs, rhs.get(0));
}
}