blob: 8ca4ccfa3d26263af5015cfd098e410991284221 [file] [log] [blame]
/*
* Copyright 2009-2010 by The Regents of the University of California
* Licensed 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 from
*
* 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 edu.uci.ics.hyracks.algebricks.core.algebra.properties;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import edu.uci.ics.hyracks.algebricks.common.utils.ListSet;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.EquivalenceClass;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
import edu.uci.ics.hyracks.algebricks.core.algebra.properties.ILocalStructuralProperty.PropertyType;
public class PropertiesUtil {
public Set<LogicalVariable> closureUnderFDs(Collection<LogicalVariable> vars, List<FunctionalDependency> fdList) {
Set<LogicalVariable> k = new ListSet<LogicalVariable>(vars);
boolean change;
do {
change = false;
for (FunctionalDependency fd : fdList) {
List<LogicalVariable> h = fd.getHead();
if (k.containsAll(h)) {
List<LogicalVariable> t = fd.getTail();
for (LogicalVariable v : t) {
if (!(k.contains(v))) {
k.add(v);
change = true;
}
}
}
}
} while (change);
return k;
}
public static boolean matchLocalProperties(List<ILocalStructuralProperty> reqd,
List<ILocalStructuralProperty> dlvd, Map<LogicalVariable, EquivalenceClass> equivalenceClasses,
List<FunctionalDependency> fds) {
if (reqd == null) {
return true;
}
if (dlvd == null) {
return false;
}
normalizeLocals(reqd, equivalenceClasses, fds);
normalizeLocals(dlvd, equivalenceClasses, fds);
ListIterator<ILocalStructuralProperty> dlvdIter = dlvd.listIterator();
Set<LogicalVariable> rqdCols = new ListSet<LogicalVariable>();
Set<LogicalVariable> dlvdCols = new ListSet<LogicalVariable>();
for (ILocalStructuralProperty r : reqd) {
if (r.getPropertyType() == PropertyType.LOCAL_GROUPING_PROPERTY) {
rqdCols.clear();
r.getVariables(rqdCols);
}
boolean implied = false;
while (!implied && dlvdIter.hasNext()) {
ILocalStructuralProperty d = dlvdIter.next();
switch (r.getPropertyType()) {
case LOCAL_ORDER_PROPERTY: {
if (d.getPropertyType() != PropertyType.LOCAL_ORDER_PROPERTY) {
return false;
}
LocalOrderProperty lop = (LocalOrderProperty) d;
if (lop.getColumn() == ((LocalOrderProperty) r).getColumn()
&& lop.getOrder() == ((LocalOrderProperty) r).getOrder()) {
implied = true;
} else {
return false;
}
break;
}
case LOCAL_GROUPING_PROPERTY: {
dlvdCols.clear();
d.getColumns(dlvdCols);
for (LogicalVariable v : dlvdCols) {
if (rqdCols.contains(v)) {
rqdCols.remove(v);
} else {
return false;
}
}
if (rqdCols.isEmpty()) {
implied = true;
}
break;
}
default: {
throw new IllegalStateException();
}
}
}
if (!implied) {
return false;
}
}
return true;
}
public static boolean matchPartitioningProps(IPartitioningProperty reqd, IPartitioningProperty dlvd,
boolean mayExpandProperties) {
INodeDomain dom1 = reqd.getNodeDomain();
INodeDomain dom2 = dlvd.getNodeDomain();
if (dom1 != null && dom2 != null && !dom1.sameAs(dom2)) {
return false;
}
switch (reqd.getPartitioningType()) {
case RANDOM: {
// anything matches RANDOM
return true;
}
case UNORDERED_PARTITIONED: {
switch (dlvd.getPartitioningType()) {
case UNORDERED_PARTITIONED: {
UnorderedPartitionedProperty ur = (UnorderedPartitionedProperty) reqd;
UnorderedPartitionedProperty ud = (UnorderedPartitionedProperty) dlvd;
if (mayExpandProperties) {
return ur.getColumnSet().containsAll(ud.getColumnSet());
} else {
return ur.getColumnSet().equals(ud.getColumnSet());
}
}
case ORDERED_PARTITIONED: {
UnorderedPartitionedProperty ur = (UnorderedPartitionedProperty) reqd;
OrderedPartitionedProperty od = (OrderedPartitionedProperty) dlvd;
if (mayExpandProperties) {
return ur.getColumnSet().containsAll(od.getOrderColumns());
} else {
return ur.getColumnSet().containsAll(od.getOrderColumns())
&& od.getOrderColumns().containsAll(ur.getColumnSet());
}
}
default: {
return false;
}
}
}
case ORDERED_PARTITIONED: {
switch (dlvd.getPartitioningType()) {
case ORDERED_PARTITIONED: {
OrderedPartitionedProperty or = (OrderedPartitionedProperty) reqd;
OrderedPartitionedProperty od = (OrderedPartitionedProperty) dlvd;
if (mayExpandProperties) {
return isPrefixOf(od.getOrderColumns(), or.getOrderColumns());
} else {
return od.getOrderColumns().equals(or.getOrderColumns());
}
}
default: {
return false;
}
}
}
default: {
return (dlvd.getPartitioningType() == reqd.getPartitioningType());
}
}
}
/**
* @param pref
* @param target
* @return true iff pref is a prefix of target
*/
private static boolean isPrefixOf(List<OrderColumn> pref, List<OrderColumn> target) {
Iterator<OrderColumn> iter = target.iterator();
for (OrderColumn v : pref) {
if (!iter.hasNext()) {
return false;
}
if (!v.equals(iter.next())) {
return false;
}
}
return true;
}
public static ArrayList<OrderColumn> applyFDsToOrderColumns(ArrayList<OrderColumn> orderColumns,
List<FunctionalDependency> fds) {
// the set of vars. is ordered
// so we try the variables in order from last to first
if (fds == null || fds.isEmpty()) {
return orderColumns;
}
int deleted = 0;
for (int i = orderColumns.size() - 1; i >= 0; i--) {
for (FunctionalDependency fdep : fds) {
if (impliedByPrefix(orderColumns, i, fdep)) {
orderColumns.set(i, null);
deleted++;
break;
}
}
}
ArrayList<OrderColumn> norm = new ArrayList<OrderColumn>(orderColumns.size() - deleted);
for (OrderColumn oc : orderColumns) {
if (oc != null) {
norm.add(oc);
}
}
return norm;
}
public static ArrayList<OrderColumn> replaceOrderColumnsByEqClasses(ArrayList<OrderColumn> orderColumns,
Map<LogicalVariable, EquivalenceClass> equivalenceClasses) {
if (equivalenceClasses == null || equivalenceClasses.isEmpty()) {
return orderColumns;
}
ArrayList<OrderColumn> norm = new ArrayList<OrderColumn>();
for (OrderColumn v : orderColumns) {
EquivalenceClass ec = equivalenceClasses.get(v.getColumn());
if (ec == null) {
norm.add(v);
} else {
if (ec.representativeIsConst()) {
// trivially satisfied, so the var. can be removed
} else {
norm.add(new OrderColumn(ec.getVariableRepresentative(), v.getOrder()));
}
}
}
return norm;
}
private static boolean impliedByPrefix(ArrayList<OrderColumn> vars, int i, FunctionalDependency fdep) {
if (!fdep.getTail().contains(vars.get(i).getColumn())) {
return false;
}
boolean fdSat = true;
for (LogicalVariable pv : fdep.getHead()) {
boolean isInPrefix = false;
for (int j = 0; j < i; j++) {
if (vars.get(j).getColumn().equals(pv)) {
isInPrefix = true;
break;
}
}
if (!isInPrefix) {
fdSat = false;
break;
}
}
return fdSat;
}
private static void normalizeLocals(List<ILocalStructuralProperty> props,
Map<LogicalVariable, EquivalenceClass> equivalenceClasses, List<FunctionalDependency> fds) {
ListIterator<ILocalStructuralProperty> propIter = props.listIterator();
int pos = -1;
while (propIter.hasNext()) {
ILocalStructuralProperty p = propIter.next();
if (p.getPropertyType() == PropertyType.LOCAL_GROUPING_PROPERTY) {
((LocalGroupingProperty) p).normalizeGroupingColumns(equivalenceClasses, fds);
pos++;
} else {
LocalOrderProperty ord = (LocalOrderProperty) p;
EquivalenceClass ec = equivalenceClasses.get(ord.getColumn());
if (ec != null) {
if (ec.representativeIsConst()) {
propIter.remove();
} else {
ord.getOrderColumn().setColumn(ec.getVariableRepresentative());
pos++;
}
} else {
pos++;
}
}
}
if (pos < 1) {
return;
}
while (propIter.hasPrevious()) {
ILocalStructuralProperty p = propIter.previous();
ListIterator<ILocalStructuralProperty> secondIter = props.listIterator(pos);
pos--;
Set<LogicalVariable> cols = new ListSet<LogicalVariable>();
while (secondIter.hasPrevious()) {
secondIter.previous().getColumns(cols);
}
secondIter = null;
for (FunctionalDependency fdep : fds) {
LinkedList<LogicalVariable> columnsOfP = new LinkedList<LogicalVariable>();
p.getColumns(columnsOfP);
if (impliedByPrefix(columnsOfP, cols, fdep)) {
propIter.remove();
break;
}
}
}
}
private static boolean impliedByPrefix(List<LogicalVariable> colsOfProp, Set<LogicalVariable> colsOfPrefix,
FunctionalDependency fdep) {
return fdep.getTail().containsAll(colsOfProp) && colsOfPrefix.containsAll(fdep.getHead());
}
}