package org.aksw.sparqlify.core.sparql.algebra.transform;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.aksw.jena_sparql_api.utils.ExprUtils;
import org.aksw.sparqlify.algebra.sql.exprs2.S_ColumnRef;
import org.aksw.sparqlify.algebra.sql.exprs2.S_Constant;
import org.aksw.sparqlify.algebra.sql.exprs2.S_Equals;
import org.aksw.sparqlify.algebra.sql.exprs2.S_IsNotNull;
import org.aksw.sparqlify.algebra.sql.exprs2.S_LogicalAnd;
import org.aksw.sparqlify.algebra.sql.exprs2.S_LogicalOr;
import org.aksw.sparqlify.algebra.sql.exprs2.SqlExpr;
import org.aksw.sparqlify.algebra.sql.exprs2.SqlExprFunction;
import org.aksw.sparqlify.core.TypeToken;
import org.aksw.sparqlify.util.CnfTransformer;
import org.aksw.sparqlify.util.ExprAccessor;
import org.aksw.sparqlify.util.SqlExprAccessor;
import com.google.common.collect.Iterables;
public class SqlExprUtils
{
public static SqlExpr orifyBalanced(Iterable<SqlExpr> exprs) {
return ExprUtils.opifyBalanced(exprs, S_LogicalOr::new);
}
public static SqlExpr andifyBalanced(Iterable<SqlExpr> exprs) {
return ExprUtils.opifyBalanced(exprs, S_LogicalAnd::new);
}
public static List<TypeToken> getTypes(List<SqlExpr> args) {
List<TypeToken> argTypes = new ArrayList<TypeToken>(args.size());
for(SqlExpr newArg : args) {
argTypes.add(newArg.getDatatype());
}
return argTypes;
}
/**
* Returns a null list for empty argument.
*
* @param expr
* @return
*/
public static <T> List<T> exprToList(T expr) {
List<T> result;
if(expr == null) {
result = Collections.emptyList();
} else {
result = Collections.singletonList(expr);
}
return result;
}
//
// public static List<SqlExprColumn> getColumnsMentioned(SqlExpr expr) {
// List<SqlExprColumn> result = new ArrayList<SqlExprColumn>();
// getColumnsMentioned(expr, result);
// return result;
// }
//
// public static void getColumnsMentioned(SqlExpr expr, List<SqlExprColumn> list) {
// for(SqlExpr arg : expr.getArgs()) {
// if(arg instanceof SqlExprColumn) {
// if(!list.contains(arg)) {
// list.add((SqlExprColumn)arg);
// }
// } else {
// getColumnsMentioned(arg, list);
// }
// }
// }
public static boolean isConstantsOnly(Iterable<SqlExpr> exprs) {
for(SqlExpr expr : exprs) {
if(!expr.isConstant()) {
return false;
}
}
return true;
}
public static boolean isConstantArgsOnly(SqlExprFunction fn) {
boolean result = isConstantsOnly(fn.getArgs());
return result;
}
public static Set<S_ColumnRef> getColumnReferences(SqlExpr expr) {
Set<S_ColumnRef> result = new HashSet<S_ColumnRef>();
collectColumnReferences(expr, result);
return result;
}
public static void collectColumnReferences(SqlExpr expr, Collection<S_ColumnRef> result) {
if(expr.isFunction()) {
List<SqlExpr> args = expr.getArgs();
for(SqlExpr arg : args) {
collectColumnReferences(arg, result);
}
}
else if(expr.isConstant()) {
// Nothing to do
}
else if(expr.isVariable()) {
S_ColumnRef columnRef = (S_ColumnRef)expr;
result.add(columnRef);
}
else {
throw new RuntimeException("Should not happen");
}
}
public static List<SqlExpr> cnfAsList(Collection<? extends Iterable<SqlExpr>> nf) {
List<SqlExpr> result = new ArrayList<SqlExpr>();
for(Iterable<SqlExpr> clause : nf) {
SqlExpr expr = orifyBalanced(clause);
if(expr != null) {
result.add(expr);
}
}
return result;
}
public static List<SqlExpr> toDnf(Collection<? extends Iterable<SqlExpr>> clauses) {
List<SqlExpr> result = new ArrayList<SqlExpr>();
if(clauses.size() == 1) {
Iterable<SqlExpr> itr = clauses.iterator().next();
Iterables.addAll(result, itr);
}
else if(!clauses.isEmpty()) {
List<SqlExpr> ors = new ArrayList<SqlExpr>();
for(Iterable<SqlExpr> clause : clauses) {
SqlExpr and = andifyBalanced(clause);
ors.add(and);
}
SqlExpr or = orifyBalanced(ors);
result.add(or);
}
return result;
}
public static boolean containsFalse(Iterable<SqlExpr> exprs, boolean includeTypeErrors) {
for(SqlExpr expr : exprs) {
if(S_Constant.FALSE.equals(expr) || (includeTypeErrors && S_Constant.TYPE_ERROR.equals(expr))) {
return true;
}
}
return false;
}
//public static final CnfTransformer<SqlExpr> cnfTransformer = new CnfTransformer<SqlExpr>(new SqlExprAccessor());
public static final ExprAccessor<SqlExpr> accessor = new SqlExprAccessor();
public static SqlExpr toCnfExpr(SqlExpr expr) {
SqlExpr result = CnfTransformer.eval(expr, accessor);
return result;
}
public static List<Collection<SqlExpr>> toCnf(SqlExpr expr) {
SqlExpr tmp = toCnfExpr(expr);
List<Collection<SqlExpr>> result = CnfTransformer.toCnf(tmp, accessor);
return result;
}
public static List<Collection<SqlExpr>> toCnf(Iterable<SqlExpr> exprs) {
List<Collection<SqlExpr>> result = CnfTransformer.toCnf(exprs, accessor);
return result;
}
public static void optimizeEqualityInPlace(List<Collection<SqlExpr>> cnf) {
for(Collection<SqlExpr> clause : cnf) {
Iterator<SqlExpr> it = clause.iterator();
while(it.hasNext()) {
SqlExpr expr = it.next();
if(expr instanceof S_Equals) {
S_Equals tmp = (S_Equals)expr;
boolean isSame = tmp.getLeft().equals(tmp.getRight());
if(isSame) {
it.remove();
}
}
}
}
}
public static void optimizeNotNullInPlace(List<Collection<SqlExpr>> cnf) {
for(Collection<SqlExpr> clause : cnf) {
Iterator<SqlExpr> it = clause.iterator();
Set<S_ColumnRef> columnRefs = new HashSet<S_ColumnRef>();
for(SqlExpr expr : clause) {
if(!(expr instanceof S_IsNotNull)) {
SqlExprUtils.collectColumnReferences(expr, columnRefs);
}
}
while(it.hasNext()) {
SqlExpr expr = it.next();
if(expr instanceof S_IsNotNull) {
S_IsNotNull tmp = (S_IsNotNull)expr;
SqlExpr arg = tmp.getExpr();
boolean contained = columnRefs.contains(arg);
if(contained) {
it.remove();
}
}
}
}
}
}