package org.aksw.sparqlify.core.algorithms; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.aksw.commons.collections.CartesianProduct; import org.aksw.jena_sparql_api.views.E_RdfTerm; import org.aksw.jena_sparql_api.views.RestrictedExpr; import org.aksw.jena_sparql_api.views.VarDefinition; import org.aksw.sparqlify.algebra.sql.exprs2.S_Coalesce; import org.aksw.sparqlify.algebra.sql.exprs2.SqlAggFunction; import org.aksw.sparqlify.algebra.sql.exprs2.SqlExpr; import org.aksw.sparqlify.algebra.sql.nodes.Projection; import org.aksw.sparqlify.algebra.sql.nodes.SqlOp; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpExtend; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpGroupBy; import org.aksw.sparqlify.core.TypeToken; import org.aksw.sparqlify.core.cast.TypeSystem; import org.aksw.sparqlify.core.domain.input.Mapping; import org.aksw.sparqlify.core.domain.input.MappingUnion; import org.aksw.sparqlify.core.interfaces.SqlTranslator; import org.aksw.sparqlify.trash.ExprCommonFactor; import org.apache.jena.sdb.core.Generator; import org.apache.jena.sdb.core.Gensym; import org.apache.jena.sparql.core.Var; import org.apache.jena.sparql.core.VarExprList; import org.apache.jena.sparql.expr.Expr; import org.apache.jena.sparql.expr.ExprAggregator; import org.apache.jena.sparql.expr.ExprVar; import org.apache.jena.sparql.expr.aggregate.Aggregator; import com.google.common.base.Joiner; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.HashMultimap; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimap; /** * Groups RDF Terms by their signature. * * @author raven * */ //class RdfTermGrouper { // public add(E_RdfTerm rdfTerm) { // rdfTerm.getSignature // // } //} public class MappingRefactor { /* public static List<Mapping> refactorToUnion(List<Mapping> ms, Var var) { List<Mapping> result = new ArrayList<Mapping>(); for(Mapping m : ms) { refactorToUnion(m, var, result); } return result; } group by ?s ?p public static List<Mapping> refactorToUnion(Mapping m, Var var, List<Mapping> result) { if(result == null) { result = new ArrayList<Mapping>(); } VarDefinition varDef = m.getVarDefinition(); Collection<RestrictedExpr> defs = varDef.getDefinitions(var); if(defs.size() > 1) { for(RestrictedExpr restExpr : defs) { Multimap<Var, RestrictedExpr> map = HashMultimap.create(varDef.getMap()); map.removeAll(var); map.put(var, restExpr); VarDefinition newVd = new VarDefinition(map); Mapping newM = new Mapping(newVd, m.getSqlOp()); result.add(newM); } } else { result.add(m); } return result; } */ /** * * * * * * @param ms * @param groupExprs * @return */ public static ListMultimap<String, Mapping> groupBy(List<Mapping> ms, List<Expr> groupExprs) { return null; } /** * * * @param ms * @param groupExpr * @return A list of MappingUnion that can be further grouped. */ public static ListMultimap<String, Mapping> groupBy(List<Mapping> ms, Expr groupExpr) { return null; } /* public static Mapping groupBy(Mapping m, VarExprList groupVars, List<ExprAggregator> aggregators, SqlTranslator sqlTranslator, TypeSystem typeSystem, ExprDatatypeNorm exprNormalizer) { Mapping a = m; for(Var var : groupVars.getVars()) { Expr expr = groupVars.getExpr(var); if(expr == null) { expr = new ExprVar(var); } groupBy(a, var, expr, sqlTranslator, exprNormalizer, typeSystem); } return null; } */ // For each rdfTerm signature cluster, cluster the contexts by their datatype // If there are multiple rewrites of the group expression, the question is whether we have to // duplicate the relation or whether these rewrites have compatible types so that we can // coalesce them // type groups are characterized by a set of super types // Any sub type of Int will be placed in the group for 'Int' public static String createClusterKey(List<SqlExprContext> contexts, ExprDatatypeNorm exprNormalizer) { String result = ""; for(SqlExprContext context : contexts) { E_RdfTerm e = context.getRewrite().asConstRdfTerm(); //context.getRewrite().getProjection(). //Map<String, TypeToken> typeMap = context.getRewrite().getProjection().getTypeMap(); // TODO We should group types such as int, byte, short, etc together //TypeToken groupType = getTypeGroup(context.getSqlExpr().getDatatype(),); //Expr valueType = exprNormalizer.normalize(e.getLexicalValue(), typeMap); //result += "" + e.getType() + valueType + e.getDatatype(); result += "| " + e.getType() + e.getDatatype(); } return result; } public static TypeToken getTypeGroup(TypeToken type, TypeSystem typeSystem) { Set<TypeToken> typeGroupTypes = new HashSet<TypeToken>(Arrays.asList(TypeToken.Int)); TypeToken result = null; // Check if the type is compatible with any of the groups for(TypeToken superType : typeGroupTypes) { boolean belongsToGroup = typeSystem.isSuperClassOf(type, superType); if(belongsToGroup) { if(result != null) { throw new RuntimeException("Type " + type + " already reassigned to group " + superType + " although already a member of " + result); } result = superType; } } if(result == null) { result = type; } return result; } public static <T, U extends Collection<T>> List<List<T>> transpose(Collection<U> items) { List<List<T>> result = new ArrayList<List<T>>(); // Compute maximum length of a row for(U c : items) { //n = Math.max(n, c.size()); List<T> tmp = new ArrayList<T>(c.size()); result.add(tmp); } // for(int i = 0; i < n; ++i) { // List<T> tmp = new ArrayList<T>(); // result.add(null); // } int y = 0; for(U c : items) { int x = 0; List<T> col = result.get(x); for(T t : c) { col.set(y, t); ++x; } ++y; } return result; } // ExprBindingSubstitutor subst = new ExprBindingSubstitutorImpl(); // e1 = subst.substitute(sparqlExpr, binding); //Map<List<SqlExprContext>> varContexts = new ArrayList<List<>> class RdfTermTypeGroup { private String groupKey; // Map Cluster private Map<TypeToken, SqlTypeGroup> groupTypeToMembers; } class SqlTypeGroup { RdfTermTypeGroup parent; TypeToken groupType; private List<SqlExprContext> contexts; } /** * * * @param ms * @param expr * @return */ public static MappingUnion groupBy(Mapping m, VarExprList groupVars, List<ExprAggregator> aggregators, SqlTranslator sqlTranslator, TypeSystem typeSystem, ExprDatatypeNorm exprNormalizer) { MappingUnion result; if(groupVars.isEmpty()) { Generator generator = Gensym.create("X"); Mapping mapping = applyAggregators(m, aggregators, generator, typeSystem, sqlTranslator); result = new MappingUnion(); result.add(mapping); } else { //public static MappingUnion groupBy(Mapping m, VarExprList groupVars, List<ExprAggregator> aggregators, SqlTranslator sqlTranslator, TypeSystem typeSystem, ExprDatatypeNorm exprNormalizer) { result = groupByWithExprs(m, groupVars, aggregators, sqlTranslator, typeSystem, exprNormalizer); } return result; } public static MappingUnion groupByWithExprs(Mapping m, VarExprList groupVars, List<ExprAggregator> aggregators, SqlTranslator sqlTranslator, TypeSystem typeSystem, ExprDatatypeNorm exprNormalizer) { MappingUnion result = new MappingUnion(); List<Var> vars = groupVars.getVars(); /* * Rewrite all involved group by expressions to SQL */ List<List<SqlExprContext>> contextsLists = new ArrayList<List<SqlExprContext>>();//ArrayListMultimap.create(); for(Var var : vars) { Expr expr = groupVars.getExpr(var); if(expr == null) { expr = new ExprVar(var); } List<SqlExprContext> contexts = MappingOpsImpl.createExprSqlRewrites(expr, m, sqlTranslator); contextsLists.add(contexts); } /* * Group the SQL rewritten expressions by their RDF term signature * i.e. uri(...), plainLiteral(...), typedLiteral(..., some:type) */ Multimap<String, List<SqlExprContext>> sigClusters = ArrayListMultimap.create(); CartesianProduct<SqlExprContext> cart = CartesianProduct.create(contextsLists); for(List<SqlExprContext> c : cart) { // The cartesion product is just a view - but we want copies! // TODO This is dangerous, make the view behaviour require a specific flag c = new ArrayList<SqlExprContext>(c); String clusterKey = createClusterKey(c, exprNormalizer); sigClusters.put(clusterKey, c); } Set<String> columnNameBlacklist = new HashSet<String>(m.getSqlOp().getSchema().getColumnNames()); //MappingOpsImpl.getReferencedColumnNames(mappings); Generator aliasGenUnion = GeneratorBlacklist.create("X", columnNameBlacklist); ExprCommonFactor factorizer = new ExprCommonFactor(aliasGenUnion); /* * Within each of the groups, we group again by the * involved SQL types * * Types within a group can be coalesced * e.g. int, byte, short belong to the group int */ Map<String, Multimap<String, List<SqlExprContext>>> groups = new HashMap<String, Multimap<String, List<SqlExprContext>>>(); for(Entry<String, Collection<List<SqlExprContext>>> sigEntry : sigClusters.asMap().entrySet()) { String sigKey = sigEntry.getKey(); Collection<List<SqlExprContext>> sigCluster = sigEntry.getValue(); Multimap<String, List<SqlExprContext>> typeGroup = ArrayListMultimap.create(); groups.put(sigKey, typeGroup); for(List<SqlExprContext> rewriteEntry : sigCluster) { String typeKey = ""; for(SqlExprContext context : rewriteEntry) { TypeToken type = context.getSqlExpr().getDatatype(); TypeToken groupType = getTypeGroup(type, typeSystem); typeKey += "| " + groupType; } typeGroup.put(typeKey, rewriteEntry); } } /* * Process the groups. * */ for(Multimap<String, List<SqlExprContext>> sigEntry : groups.values()) { Collection<List<SqlExprContext>> typeGroup = sigEntry.values(); // Within a type group, vertically group the expressions List<E_RdfTerm> grouped = new ArrayList<E_RdfTerm>(); for(int i = 0; i < vars.size(); ++i) { grouped.add(null); } // Coalesce all the sql exprs // List<List<Projection>> sqlExprss = new ArrayList<List<Projection>>(); // for(int i = 0; i < vars.size(); ++i) { // sqlExprss.add(new ArrayList<Projection>()); // } // Vertically iterate each expression // First pass: create the E_RdfTerm object for(List<SqlExprContext> rewriteEntry : typeGroup) { for(int i = 0; i < vars.size(); ++i) { SqlExprContext rewrite = rewriteEntry.get(i); E_RdfTerm gTerm = grouped.get(i); E_RdfTerm rdfTerm = rewrite.getRewrite().asConstRdfTerm(); E_RdfTerm tmp; if(gTerm == null) { tmp = rdfTerm; } else { tmp = (E_RdfTerm)factorizer.transformMM(gTerm, rdfTerm); } grouped.set(i, tmp); } } // Table<Integer, Integer, Integer> x; // x.r // Second pass: Map the Sql expressions //rowToColsToProj // colToRowsToProjs List<List<Projection>> sqlExprss = new ArrayList<List<Projection>>(vars.size()); for(int i = 0; i < vars.size(); ++i) { E_RdfTerm gTerm = grouped.get(i); List<Projection> sqlExprs = new ArrayList<Projection>(typeGroup.size()); for(List<SqlExprContext> rewriteEntry : typeGroup) { SqlExprContext rewrite = rewriteEntry.get(i); //List<Projection> sqlExprs = sqlExprss.get(i); sqlExprss.add(sqlExprs); Projection proj = new Projection(); List<Expr> args = gTerm.getArgs(); for(int j = 0; j < args.size(); ++j) { Expr arg = args.get(j); if(arg.isVariable()) { Var var = arg.asVar(); ExprSqlRewrite r = rewrite.getRewrite(); E_RdfTerm t = r.getRdfTermExpr(); Expr e = t.getArg(j + 1); Var v = e.asVar(); SqlExpr sqlExpr = r.getProjection().getNameToExpr().get(v.getVarName()); proj.put(var.getName(), sqlExpr); } else if(arg.isConstant()) { // Nothing to do } else { throw new RuntimeException("Should not happen"); } } sqlExprs.add(proj); // List<Expr> args = tmp.getArgs(); // for(int j = 0; j gTerm.getArgs()) // sqlExprss.get(i).add(rewrite.getSqlExpr()); // // // // E_RdfTerm rdfTerm = rewrite.getRewrite().asConstRdfTerm(); } } // TODO We must preserve order in the coalesce expressions: // E.g. if we are grouping (?label, ?lang) (?x, ?y), then we // need coalesce(?label, ?lang) (?x, ?y) and not e.g. (?y, ?x) // so that ?label matches again with ?x Projection proj = new Projection(); List<String> groupColumnNames = new ArrayList<String>(); //SqlOpExtend //List<SqlExpr> sqlGroup = new ArrayList<SqlExpr>(vars.size()); Multimap<Var, RestrictedExpr> varDef = HashMultimap.create(); for(int i = 0; i < vars.size(); ++i) { Var var = vars.get(i); E_RdfTerm group = grouped.get(i); List<Projection> sqlExprs = sqlExprss.get(i); List<Expr> args = group.getArgs(); List<Expr> newArgs = new ArrayList<Expr>(args.size()); for(Expr arg : args) { Expr newArg; if(arg.isConstant()) { newArg = arg; } else if(arg.isVariable()) { String varName = arg.getVarName(); List<SqlExpr> ss = new ArrayList<SqlExpr>(); for(Projection p : sqlExprs) { SqlExpr s = p.getNameToExpr().get(varName); ss.add(s); } SqlExpr sqlCoalesce = S_Coalesce.create(ss); //sqlGroup.add(sqlCoalesce); String columnName = aliasGenUnion.next(); groupColumnNames.add(columnName); proj.put(columnName, sqlCoalesce); newArg = new ExprVar(columnName); } else { throw new RuntimeException("Should not happen"); } newArgs.add(newArg); } E_RdfTerm groupTerm = new E_RdfTerm(newArgs); varDef.put(var, new RestrictedExpr(groupTerm)); //System.out.println("" + group + " --- " + sqlExprs); } // Get the variables referenced by the aggregators Set<Var> varRefs = new HashSet<Var>(); for(ExprAggregator exprAgg : aggregators) { Aggregator agg = exprAgg.getAggregator(); // Expr expr = agg.getExpr(); // if(expr == null) { // continue; // } // // Set<Var> tmp = expr.getVarsMentioned(); // varRefs.addAll(tmp); for(Expr expr : agg.getExprList()) { Set<Var> tmp = expr.getVarsMentioned(); varRefs.addAll(tmp); } } // Remove the group variables varRefs.removeAll(varDef.keySet()); // Add the new variables to the def for(Var varRef : varRefs) { Collection<RestrictedExpr> tmp = m.getVarDefinition().getDefinitions(varRef); varDef.putAll(varRef, tmp); } // Deal with the aggregators //for() SqlOp subOp = m.getSqlOp(); List<SqlExpr> groupByExprs = new ArrayList<SqlExpr>(groupColumnNames.size()); for(String columnName : groupColumnNames) { SqlExpr sqlExpr = proj.getNameToExpr().get(columnName); groupByExprs.add(sqlExpr); } SqlOpGroupBy sqlOp = SqlOpGroupBy.create(subOp, groupByExprs, new ArrayList<SqlAggFunction>()); VarDefinition vd = new VarDefinition(varDef); SqlOpExtend sqlOpExtend = SqlOpExtend.create(sqlOp, proj); // TODO: Project to only the referenced columns Mapping mapping = new Mapping(vd, sqlOpExtend); Mapping done = applyAggregators(mapping, aggregators, aliasGenUnion, typeSystem, sqlTranslator); // // Multimap<Var, RestrictedExpr> varDef2 = HashMultimap.create(); // Projection proj2 = new Projection(); // for(ExprAggregator exprAgg : aggregators) { // Var var = exprAgg.getVar(); // Aggregator agg = exprAgg.getAggregator(); // // ExprSqlRewrite rewrite = MappingOpsImpl.rewrite(mapping, agg, aliasGenUnion, typeSystem, sqlTranslator); // // E_RdfTerm rdfTerm = rewrite.getRdfTermExpr(); // // varDef2.put(var, new RestrictedExpr(rdfTerm)); // proj2.add(rewrite.getProjection()); // } // // SqlOpExtend sqlOpExtend2 = SqlOpExtend.create(sqlOpExtend, proj2); // VarDefinition vd2 = new VarDefinition(varDef2); // Mapping done = new Mapping(vd2, sqlOpExtend2); // Map<String, TypeToken> typeMap = u.getSqlOp().getSchema().getTypeMap(); // List<SqlExpr> columnRefs = new ArrayList<SqlExpr>(); // for(String columnName : columnNames) { // TypeToken type = typeMap.get(columnName); // // SqlExpr expr = new S_ColumnRef(type, columnName); // columnRefs.add(expr); // } // // List<SqlExprAggregator> sqlAggregators = new ArrayList<SqlExprAggregator>(); // // SqlOpGroupBy sqlOpGroupBy = SqlOpGroupBy.create(u.getSqlOp(), columnRefs, sqlAggregators); // //public ExprSqlRewrite rewrite(Mapping mapping, Aggregator agg, Generator generator) { // TODO Clone the mapping // TODO Project only to the referenced columns // TODO Apply aggregators to the mapping result.add(done); //System.out.println("Added group"); } return result; } public static Mapping applyAggregators(Mapping mapping, List<ExprAggregator> aggregators, Generator generator, TypeSystem typeSystem, SqlTranslator sqlTranslator) { Multimap<Var, RestrictedExpr> varDef2 = HashMultimap.create(); varDef2.putAll(mapping.getVarDefinition().getMap()); Projection proj2 = new Projection(); for(ExprAggregator exprAgg : aggregators) { Var var = exprAgg.getVar(); Aggregator agg = exprAgg.getAggregator(); ExprSqlRewrite rewrite = MappingOpsImpl.rewrite(mapping, agg, generator, typeSystem, sqlTranslator); E_RdfTerm rdfTerm = rewrite.getRdfTermExpr(); varDef2.put(var, new RestrictedExpr(rdfTerm)); proj2.add(rewrite.getProjection()); } //SqlOpExtend sqlOpExtend2 = SqlOpExtend.create(sqlOpExtend, proj2); SqlOpExtend sqlOpExtend2 = SqlOpExtend.create(mapping.getSqlOp(), proj2); VarDefinition vd2 = new VarDefinition(varDef2); Mapping result = new Mapping(vd2, sqlOpExtend2); return result; } // for(List<SqlExprContext> rewriteEntry : typeGroup) { // // System.out.println("::: " + rewriteEntry); // } // System.out.println("---"); /* * * */ // for(Collection<List<SqlExprContext>> cluster : sigClusters.asMap().values()) { // // List<E_RdfTerm> grouped = new ArrayList<E_RdfTerm>(); // for(int i = 0; i < vars.size(); ++i) { // grouped.add(null); // } // // // Coalesce all the sql exprs // List<List<SqlExpr>> sqlExprss = new ArrayList<List<SqlExpr>>(); // for(int i = 0; i < vars.size(); ++i) { // sqlExprss.add(new ArrayList<SqlExpr>()); // } // // // // Vertically group each expression // for(List<SqlExprContext> member : cluster) { // for(int i = 0; i < vars.size(); ++i) { // SqlExprContext rewrite = member.get(i); // // E_RdfTerm gTerm = grouped.get(i); // E_RdfTerm rdfTerm = rewrite.getRewrite().asConstRdfTerm(); // // E_RdfTerm tmp; // if(gTerm == null) { // tmp = rdfTerm; // } else { // tmp = (E_RdfTerm)factorizer.transformMM(gTerm, rdfTerm); // } // grouped.set(i, tmp); // // sqlExprss.get(i).add(rewrite.getSqlExpr()); // } // } // // //// for(int i = 0; i < vars.size(); ++i) { //// for(List<SqlExprContext> member : cluster) { //// } //// //// // // Now we only have 1 grouped expression for each variable // for(int i = 0; i < vars.size(); ++i) { // Var var = vars.get(i); // E_RdfTerm group = grouped.get(i); // // List<SqlExpr> sqlExprs = sqlExprss.get(i); // // SqlExpr sqlCoalesce = S_Coalesce.create(sqlExprs); // // System.out.println(group + " --- " + sqlCoalesce); // } // // } // // // //List<SqlExprContext> // // // For each signature there is now a list of context rewrites // // Cluster the contexts first by the rdfTerm signature // // // // For each exprCluster, coalesce the expressions // // //contextexprCluster.values(); // // List<SqlExpr> sqlExprs = new ArrayList<SqlExpr>(cs.size()); // for(SqlExprContext context : exprCluster.values()) { // sqlExprs.add(context.getSqlExpr()); // //// sqlCoalesce = S_Coalesce.create(coalesceArgs); //// System.out.println(context); // } // // SqlExpr sqlCoalesce = S_Coalesce.create(sqlExprs); // System.out.println("COALESCE: " + sqlCoalesce); // // // // Clone the mapping // Multimap<Var, RestrictedExpr> newVarDef = HashMultimap.create(m.getVarDefinition().getMap()); // // // Replace the mapping for the grouping variable // newVarDef.removeAll(var); // // newVarDef.put(var, new RestrictedExpr(E_RdfTerm.createUri(NodeValue.makeString("test")))); // // // // TODO I think we need to filter the sqlOp to those rows for which the expression applies? // Mapping newMapping = new Mapping(new VarDefinition(newVarDef), m.getSqlOp()); // // result.add(newMapping); // } // // // System.out.println(result); // // // Each of the cluster's entries can be coalesced // Important: If we clone the mapping by an expression, we need to make sure we do not duplicate/lose any // of the NULL values /** * Given a list of mappings, create groups of them with the following properties: * All members of a group must have the same datatypes for their term constructor args * e.g. rdfTerm(int, string, string, string), rdfTerm(int, float, string, string) * * */ public static ListMultimap<String, Mapping> groupByOld(ExprDatatypeNorm exprNormalizer, List<Mapping> ms, List<Var> vars) { //Multimap<String, ArgExpr> cluster = HashMultimap.create(); ListMultimap<String, Mapping> cluster = LinkedListMultimap.create(); for(Mapping m : ms) { Map<String, TypeToken> tmpTypeMap = m.getSqlOp().getSchema().getTypeMap(); List<String> hashes = new ArrayList<String>(vars.size()); for(Var var : vars) { Collection<RestrictedExpr> defs = m.getVarDefinition().getDefinitions(var); Expr expr; if(defs.size() > 1) { throw new RuntimeException("Encountered multiple variable definitions during group by. Var: " + var + " vardef: " + m.getVarDefinition()); // + ", Mapping: " ); } else if(defs.isEmpty()) { // Example If only name is defined, but we request "GROUP BY name, age" // then this is the same as grouping by name only, since age is implicitely NULL // TODO Do we have to bind name to NULL? //expr = //throw new RuntimeException("Cannot group by " + var + " because mapping does not define it. Mapping: " + m); expr = null; } else { RestrictedExpr restExpr = defs.iterator().next(); expr = restExpr.getExpr(); } String hash; if(expr == null) { hash = "null"; } else { Expr datatypeNorm = exprNormalizer.normalize(expr, tmpTypeMap); hash = datatypeNorm.toString(); } hashes.add(hash); } String key = Joiner.on(",").join(hashes); cluster.put(key, m); } return cluster; } /** * If there are multiple definitions for any of the specified variables, * each definition results in a new mapping. * The result is then a union of these mappings. * * Note that this should only be used for corner cases where for some reason * the union of mappings got lost, and we have a single mapping with multiple * var definitions. * * @param m */ public static List<Mapping> refactorToUnion(Mapping m, List<Var> tmpVars) { //if(true) throw new RuntimeException("test"); List<Mapping> result = new ArrayList<Mapping>(); VarDefinition varDef = m.getVarDefinition(); List<Var> vars = new ArrayList<Var>(tmpVars.size()); List<Collection<RestrictedExpr>> c = new ArrayList<Collection<RestrictedExpr>>(tmpVars.size()); if(tmpVars.isEmpty()) { result.add(m); return result; } for(Var var : tmpVars) { Collection<RestrictedExpr> defs = varDef.getDefinitions(var); if(defs.isEmpty()) { continue; } vars.add(var); c.add(defs); } Multimap<Var, RestrictedExpr> baseMap = HashMultimap.create(varDef.getMap()); baseMap.keySet().removeAll(vars); CartesianProduct<RestrictedExpr> cart = CartesianProduct.create(c); for(List<RestrictedExpr> item : cart) { Multimap<Var, RestrictedExpr> map = HashMultimap.create(varDef.getMap()); for(int i = 0; i < vars.size(); ++i) { Var var = vars.get(i); RestrictedExpr restExpr = item.get(i); map.put(var, restExpr); } VarDefinition newVd = new VarDefinition(map); Mapping newM = new Mapping(newVd, m.getSqlOp()); result.add(newM); } /* OpDisjunction result = null; return result; */ return result; } // public static void trySplitUnion(SqlOp sqlOp, Set<String> columnNames) { // if(sqlOp instanceof SqlOpUnionN) { // splitUnion((SqlOpUnionN)sqlOp, columnNames); // } // } // // public static Map<String, SqlExpr> filterNotNull(Map<String, SqlExpr> map) { // Map<String, SqlExpr> result = new HashMap<String, SqlExpr>(); // // for(Entry<String, SqlExpr> entry : map.entrySet()) { // String name = entry.getKey(); // SqlExpr sqlExpr = entry.getValue(); // // if(sqlExpr.isConstant()) { // Object obj = sqlExpr.asConstant().getValue().getValue(); // if(obj == null) { // continue; // } // } // // //sqlExpr instanceof S_Constant. // // result.put(name, sqlExpr); // } // // return result; // } // // public static void splitUnion(SqlOpUnionN union, Set<String> columnNames) { // // SqlOpSelectBlockCollector collector = new SqlOpSelectBlockCollectorImpl(); // // for(SqlOp member : union.getSubOps()) { // // SqlOpSelectBlock block = (SqlOpSelectBlock)collector.transform(member); // // Projection proj = block.getProjection(); // // Map<String, SqlExpr> tmp = proj.getNameToExpr(); // Map<String, SqlExpr> nameToExpr = filterNotNull(tmp); // // System.out.println(nameToExpr); //// SqlOpProject project = (SqlOpProject)member; //// //// project.get // // // } // } }