package org.aksw.sparqlify.core.sql.algebra.transform; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.aksw.commons.util.reflect.MultiMethod; import org.aksw.sparqlify.algebra.sql.exprs2.S_ColumnRef; 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.SqlOpDistinct; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpEmpty; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpExtend; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpFilter; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpGroupBy; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpJoin; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpOrder; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpProject; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpQuery; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpRename; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpSelectBlock; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpSlice; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpTable; import org.aksw.sparqlify.algebra.sql.nodes.SqlOpUnionN; import org.aksw.sparqlify.algebra.sql.nodes.SqlSortCondition; import org.aksw.sparqlify.core.TypeToken; import org.aksw.sparqlify.core.algorithms.SqlExprSubstitutor; import org.aksw.sparqlify.core.algorithms.SqlOps; import org.aksw.sparqlify.core.sparql.algebra.transform.SqlExprUtils; import org.aksw.sparqlify.core.sql.schema.Schema; import org.apache.jena.sdb.core.Generator; import org.apache.jena.sdb.core.Gensym; import org.apache.jena.sdb.core.JoinType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; interface JoinContext { SqlOp getOp(); //List<Projection> getProjections(); //SqlOp getOp(); List<SqlExpr> getConditions(); Projection getProjection(); } /* class JoinContextBlock implements JoinContext { private SqlOpSelectBlock block; //private List<SqlExpr> conditions; public JoinContextBlock(SqlOpSelectBlock block) { this.block = block; } @Override public SqlOpSelectBlock getOp() { return block; } @Override public List<SqlExpr> getConditions() { return block.getConditions(); } @Override public Projection getProjection() { return block.getProjection(); } } */ class JoinContextJoin implements JoinContext { // The effective op, i.e. table, query, join or union. private SqlOp op; private Projection projection = new Projection(); private List<SqlExpr> conditions = new ArrayList<SqlExpr>(); // public JoinContextJoin() { // super(); // } public JoinContextJoin(SqlOp op) { this.op = op; } public SqlOp getOp() { return op; } public List<SqlExpr> getConditions() { return conditions; } public Projection getProjection() { return projection; } } class SqlOpJoinBlock { private List<JoinContext> members = new ArrayList<JoinContext>(); public SqlOpJoinBlock() { super(); } public List<JoinContext> getMembers() { return members; } } class SqlOpJoinBlockOld { // The effective op, i.e. table, query, join or union. private List<SqlOp> ops; private List<Projection> projections = new ArrayList<Projection>(); private List<SqlExpr> conditions = new ArrayList<SqlExpr>(); public SqlOpJoinBlockOld() { super(); } //public JoinContextJoin(SqlOp op) { // this.ops = new ArrayList<SqlOp>(Arrays.asList(op)); //} public List<SqlOp> getOps() { return ops; } public List<SqlExpr> getConditions() { return conditions; } public List<Projection> getProjections() { return projections; } public void addOther(SqlOpJoinBlockOld other) { this.ops.addAll(other.getOps()); this.projections.addAll(other.getProjections()); } public void add(SqlOp op, Projection projection) { this.ops.add(op); this.projections.add(projection); } } /** * Pitfalls: * (distinct (project ...)) -> First project then make distinct * -> Select Distinct [project] * But * (project (distinct ...)) -> First make distinct (with potentially some different projection), * then project: * Select [projection] FROM (Select Distinct * From ...) * * * @author Claus Stadler <cstadler@informatik.uni-leipzig.de> * */ public class SqlOpSelectBlockCollectorImpl implements SqlOpSelectBlockCollector { private static final Logger logger = LoggerFactory.getLogger(SqlOpSelectBlockCollectorImpl.class); private static Generator aliasGenerator = Gensym.create("a"); // Used for sort conditions private static Generator projectionGenerator = Gensym.create("o"); /** * Turn an SqlOp into an OpSqlSelectBlock. * Exception is SqlOpUnion, which does not need to be wrapped as such block. * * * @param sqlOp * @return */ public static SqlOp makeSelect(SqlOp sqlOp) { SqlOp result = _makeSelect(sqlOp, null); return result; } public static SqlOp _makeSelect(SqlOp sqlOp, Set<String> refs) { SqlOp result; SqlOps type = SqlOps.valueOf(sqlOp.getClass().getSimpleName()); switch(type) { case SqlOpOrder: result = makeSelect((SqlOpOrder)sqlOp, refs); break; case SqlOpGroupBy: result = makeSelect((SqlOpGroupBy)sqlOp, refs); break; case SqlOpEmpty: result = makeSelect((SqlOpEmpty)sqlOp, refs); break; case SqlOpTable: result = makeSelect((SqlOpTable)sqlOp, refs); break; case SqlOpQuery: result = makeSelect((SqlOpQuery)sqlOp, refs); break; case SqlOpFilter: result = makeSelect((SqlOpFilter)sqlOp, refs); break; case SqlOpProject: result = makeSelect((SqlOpProject)sqlOp, refs); break; case SqlOpExtend: result = makeSelect((SqlOpExtend)sqlOp, refs); break; // case SqlOpRename: // result = makeSelect((SqlOpRename)sqlOp); // break; case SqlOpJoin: result = makeSelect((SqlOpJoin)sqlOp, refs); break; case SqlOpUnionN: result = makeSelect((SqlOpUnionN)sqlOp, refs); break; case SqlOpDistinct: result = makeSelect((SqlOpDistinct)sqlOp, refs); break; case SqlOpSlice: result = makeSelect((SqlOpSlice)sqlOp, refs); break; default: logger.warn("Should not come here"); result = MultiMethod.invokeStatic(SqlOpSelectBlockCollectorImpl.class, "makeSelect", sqlOp, refs); break; } return result; } /** * Create a dummy select query: * * SELECT NULL WHERE FALSE; * * If above is not cross db safe, we could change to: * SELECT NULL c FROM (SELECT NULL) t WHERE FALSE; * * @param op * @return */ public static SqlOp makeSelect(SqlOpEmpty op, Set<String> refs) { SqlOp result = makeSelectOrTable(op, refs); // SqlOpSelectBlock result = requireSelectBlock(op); // String aliasName = aliasGenerator.next(); // result.setAliasName(aliasName); return result; } public static SqlOp makeSelect(SqlOpOrder op, Set<String> refs) { SqlOp newOp = _makeSelect(op.getSubOp(), refs); SqlOpSelectBlock result = requireSelectBlock(newOp); List<SqlSortCondition> newExprs = adjustSortConditions(op.getSortConditions(), result.getProjection()); result.getSortConditions().addAll(newExprs); return result; } public static SqlOp makeSelect(SqlOpGroupBy op, Set<String> refs) { SqlOp newOp = _makeSelect(op.getSubOp(), refs); SqlOpSelectBlock result = requireSelectBlock(newOp); List<SqlExpr> newExprs = adjustConditions(op.getGroupByExprs(), result.getProjection()); result.getGroupByExprs().addAll(newExprs); return result; } public static SqlOpSelectBlock makeSelect(SqlOpSlice op, Set<String> refs) { SqlOp newOp = _makeSelect(op.getSubOp(), refs); SqlOpSelectBlock result = requireSelectBlock(newOp); SqlOpSelectBlock.slice(result, op.getOffset(), op.getLimit()); return result; } public static SqlOpSelectBlock makeSelect(SqlOpDistinct op, Set<String> refs) { SqlOp newOp = _makeSelect(op.getSubOp(), refs); SqlOpSelectBlock result = requireSelectBlock(newOp); result.setDistinct(true); // Sort conditions must now become part of the projection for(SqlSortCondition cond : result.getSortConditions()) { String colName = projectionGenerator.next(); SqlExpr expr = cond.getExpression(); result.getProjection().put(colName, expr); } return result; } public static SqlOpUnionN makeSelect(SqlOpUnionN op, Set<String> refs) { List<SqlOp> newMembers = new ArrayList<SqlOp>(); for(SqlOp member : op.getSubOps()) { SqlOp subOp = _makeSelect(member, refs); newMembers.add(subOp); } String aliasName = aliasGenerator.next(); SqlOpUnionN result = new SqlOpUnionN(op.getSchema(), newMembers, aliasName); // makeSelectOrTable(op); //SqlOpUnionN result = SqlOpUnionN.create(newMembers, aliasName); //SqlOpSelectBlock result = SqlOpSelectBlock.create(opTable); /* for(String columnName : op.getSchema().getColumnNames()) { //XClass datatype = result.getSchema().getColumnType(columnName); //result.getProjection().put(columnName, new SqlExprColumn(opTable.getAliasName(), columnName, datatype)); //ExprVar(aliasName + "." + columnName)); result.getProjection().put(columnName, new ExprVar(opTable.getAliasName() + "." + columnName)); } */ return result; } public static SqlOp makeSelect(SqlOpTable node, Set<String> refs) { SqlOpTable opTable = makeSelectOrTable(node); SqlOpSelectBlock result = SqlOpSelectBlock.create(opTable); for(String columnName : opTable.getSchema().getColumnNames()) { TypeToken datatype = result.getSchema().getColumnType(columnName); result.getProjection().put(columnName, new S_ColumnRef(datatype, columnName, opTable.getAliasName())); //ExprVar(aliasName + "." + columnName)); //result.getProjection().put(columnName, new ExprVar(opTable.getAliasName() + "." + columnName)); } return result; } public static SqlOp makeSelect(SqlOpQuery node, Set<String> refs) { SqlOpQuery result = makeSelectOrTable(node); return result; } // public static SqlOpSelectBlock forceSelectBlock(SqlOp op) { // SqlOpSelectBlock result; // result = SqlOpSelectBlock.create(op); // initProjection(result.getProjection(), op.getSchema(), result.getAliasName()); // // return result; // } public static SqlOpSelectBlock requireSelectBlock(SqlOp op) { SqlOpSelectBlock result; if(op instanceof SqlOpSelectBlock) { result = (SqlOpSelectBlock) op; } else { result = SqlOpSelectBlock.create(op); initProjection(result.getProjection(), op.getSchema(), result.getAliasName()); } return result; } /* public static SqlOpSelectBlock requireSelectBlock(SqlOp op, String aliasName) { SqlOpSelectBlock result = (op instanceof SqlOpSelectBlock) ? (SqlOpSelectBlock) op : SqlOpSelectBlock.create(op, aliasName); return result; }*/ public static SqlExpr transformToAliasedReferences(SqlExpr expr, Projection projection) { Map<String, SqlExpr> map = projection.getNameToExpr(); SqlExprSubstitutor substitutor = SqlExprSubstitutor.create(map); SqlExpr result = substitutor.substitute(expr); return result; } public static List<SqlSortCondition> adjustSortConditions(List<SqlSortCondition> sqlConds, Projection projection) { int n = sqlConds.size(); List<SqlExpr> exprs = new ArrayList<SqlExpr>(n); for(SqlSortCondition sqlCond : sqlConds) { SqlExpr expr = sqlCond.getExpression(); exprs.add(expr); } List<SqlExpr> adjusteds = adjustConditions(exprs, projection); List<SqlSortCondition> result = new ArrayList<SqlSortCondition>(n); for(int i = 0; i < n; ++i) { SqlSortCondition sqlCond = sqlConds.get(i); SqlExpr adjusted = adjusteds.get(i); int direction = sqlCond.getDirection(); SqlSortCondition newSqlCond = new SqlSortCondition(adjusted, direction); result.add(newSqlCond); } return result; } public static List<SqlExpr> adjustConditions(List<SqlExpr> exprs, Projection projection) { Map<String, SqlExpr> map = projection.getNameToExpr(); //SqlExprSubstitute x = new SqlEx SqlExprSubstitutor substitutor = SqlExprSubstitutor.create(map); List<SqlExpr> result = substitutor.substitute(exprs); return result; } public static SqlOp makeSelect(SqlOpFilter op, Set<String> refs) { SqlOp subOp = _makeSelect(op.getSubOp(), refs); SqlOpSelectBlock result = requireSelectBlock(subOp); result.setSchema(op.getSchema()); List<SqlExpr> transformed = adjustConditions(op.getExprs(), result.getProjection()); result.getConditions().addAll(transformed); return result; } public static SqlOpSelectBlock makeSelect(SqlOpExtend op, Set<String> refs) { SqlOp subOp = op.getSubOp(); if(subOp instanceof SqlOpSlice) { // Create a wrapping SqlOpSelectBlock SqlOpSelectBlock wrapper = makeSelect((SqlOpSlice)subOp, refs); String aliasName = SqlOpSelectBlock.getAliasName(wrapper.getSubOp()); initProjection(wrapper.getProjection(), wrapper.getSchema(), aliasName); String aliasName2 = aliasGenerator.next(); wrapper.setAliasName(aliasName2); subOp = SqlOpSelectBlock.create(wrapper); } else { subOp = _makeSelect(subOp, refs); } //SqlOp subOp = _makeSelect(op.getSubOp(), refs); SqlOpSelectBlock result = requireSelectBlock(subOp); //SqlOpSelectBlock result = forceSelectBlock(subOp); result.setSchema(op.getSchema()); Projection subProj = result.getProjection(); Projection extendedProj = new Projection(); for(Entry<String, SqlExpr> entry : op.getProjection().getNameToExpr().entrySet()) { String columnName = entry.getKey(); SqlExpr originalExpr = entry.getValue(); boolean enableRefSubstitution = false; // TODO Expand the originalExpr as to not refer to any other columns that have been added through expansion // If the projection removes them, we get dangling references: // Project(C2, Expand(C2=C1, Expand(C1=c, tbl))) -> SELECT C2 FROM tbl -> FAIL, because C2 does not exist in the table // Project(C2, Expand(C2=c, table)) -> SUCCESS // UPDATE Seems as if this is not the problem if(enableRefSubstitution) { Set<S_ColumnRef> colRefs = SqlExprUtils.getColumnReferences(originalExpr); //Map<S_ColumnRef, SqlExpr> subst = new HashMap<S_ColumnRef, SqlExpr>(); Map<String, SqlExpr> subst = new HashMap<String, SqlExpr>(); for(S_ColumnRef colRef : colRefs) { String colAlias = colRef.getRelationAlias(); if(colAlias != null) { continue; } String refName = colRef.getColumnName(); SqlExpr subExpr = subProj.getNameToExpr().get(refName); if(subExpr != null) { subst.put(refName, subExpr); } } if(!subst.isEmpty()) { originalExpr = SqlExprSubstitutor.create(subst).substitute(originalExpr); } } SqlExpr aliasedExpr = transformToAliasedReferences(originalExpr, result.getProjection()); extendedProj.getNames().add(columnName); extendedProj.getNameToExpr().put(columnName, aliasedExpr); } result.getProjection().extend(extendedProj); return result; } public static SqlOpSelectBlock makeSelect(SqlOpProject op, Set<String> refs) { SqlOp subOp = _makeSelect(op.getSubOp(), refs); SqlOpSelectBlock result = requireSelectBlock(subOp); SqlOp effectiveOp = result.getSubOp(); if(effectiveOp instanceof SqlOpUnionN) { initProjection(result.getProjection(), effectiveOp.getSchema(), SqlOpSelectBlock.getAliasName(effectiveOp)); } result.setSchema(op.getSchema()); result.getProjection().project(op.getColumnNames()); //result.getProjection().project(op.get$) //List<SqlExpr> transformed = adjustConditions(op.getExprs(), result.getProjection()); //result.getConditions().addAll(transformed); return result; } public static SqlOpSelectBlock contextToBlock(Schema schema, JoinContext context) { SqlOpSelectBlock block = SqlOpSelectBlock.create(); /* JoinContext left = _$s(op.getLeft()); JoinContext right = _collectJoins(op.getRight()); SqlOpJoin join = SqlOpJoin.create(op.getJoinType(), left.getOp(), right.getOp()); join.getConditions().addAll(op.getConditions()); context.getProjection().add(left.getProjection()); context.getProjection().add(right.getProjection()); //join.getConditions().addAll(left.getConditions()); context.getConditions().addAll(left.getConditions()); context.getConditions().addAll(right.getConditions()); //copyProjection(join, node); */ // Create joins for all elements // TODO We could actually make the JoinContext into // an SqlOp directly // SqlOp op = null; // for(SqlOp member : context.getOps()) { // if(op == null) { // op = member; // } else { // op = SqlOpJoin.create(JoinType.INNER, op, member); // } // } SqlOp op = context.getOp(); block.setSubOp(op); //block.setSchema(op.getSchema()); block.setSchema(schema); block.getProjection().add(context.getProjection()); block.getConditions().addAll(context.getConditions()); return block; } public static SqlOp makeSelect(SqlOpJoin op, Set<String> refs) { JoinContext context = collectJoins(op, refs); SqlOpSelectBlock block = contextToBlock(op.getSchema(), context); return block; } public static JoinContext _collectJoins(SqlOp sqlOp, Set<String> refs) { JoinContext result; SqlOps type = SqlOps.valueOf(sqlOp.getClass().getSimpleName()); switch(type) { case SqlOpEmpty: result = collectJoins((SqlOpEmpty)sqlOp, refs); break; case SqlOpTable: result = collectJoins((SqlOpTable)sqlOp, refs); break; case SqlOpQuery: result = collectJoins((SqlOpQuery)sqlOp, refs); break; case SqlOpFilter: result = collectJoins((SqlOpFilter)sqlOp, refs); break; /* case SqlOpProject: result = collectJoins((SqlOpProject)sqlOp); break; */ case SqlOpExtend: result = collectJoins((SqlOpExtend)sqlOp, refs); break; case SqlOpRename: result = collectJoins((SqlOpRename)sqlOp, refs); break; case SqlOpJoin: result = collectJoins((SqlOpJoin)sqlOp, refs); break; case SqlOpUnionN: result = collectJoins((SqlOpUnionN)sqlOp, refs); break; case SqlOpDistinct: { SqlOpSelectBlock tmp = makeSelect((SqlOpDistinct)sqlOp, refs); result = collectJoins(tmp, refs); break; } case SqlOpSlice: { SqlOpSelectBlock tmp = makeSelect((SqlOpSlice)sqlOp, refs); result = collectJoins(tmp, refs); break; } case SqlOpProject: { SqlOpSelectBlock tmp = makeSelect((SqlOpProject)sqlOp, refs); result = collectJoins(tmp, refs); break; } default: throw new RuntimeException("Should not come here; don't know how to handle " + sqlOp); // logger.warn("Not sure if we should come here"); // result = MultiMethod.invokeStatic(SqlOpSelectBlockCollectorImpl.class, "collectJoins", sqlOp); // break; } return result; } // TODO SqlOpEmpty needs an alias public static JoinContext collectJoins(SqlOpEmpty op, Set<String> refs) { SqlOpEmpty table = makeSelectOrTable(op, refs); JoinContextJoin result = new JoinContextJoin(table); initProjection(result.getProjection(), op.getSchema(), table.getAliasName()); return result; } // public static SqlOpJoinBlock _collectJoinBlock(SqlOp op) { // return null; // } // // public static SqlOpJoinBlock collectJoinBlock(SqlOpJoin op, SqlOpJoinBlock joinBlock) { // // _collectJoinBlock(op.getLeft(), ); // SqlOpJoinBlock right = _collectJoinBlock(op.getRight()); // // //// if(op.getJoinType().equals(JoinType.LEFT)) { //// if(left.getOp() instanceof SqlOpJoin) { //// //requireSelectBlock(op.getLeft()); //// //// SqlOpSelectBlock subSelect = contextToBlock(op.getSchema(), left); //// String aliasName = aliasGenerator.next(); //// subSelect.setAliasName(aliasName); //// //// left = new JoinContextJoin(subSelect); //// left.getProjection().add(subSelect.getProjection()); //// initProjection(left.getProjection(), op.getSchema(), aliasName); //// } //// } // // // NOTE We use a null schema because column names may be common to left and right operand // // which is invalid for the schema object. // // However, at this stage, we assume that the schema is already validated, and we can // // allow duplicate column names in order to avoid creating sub-queries // SqlOpJoin join = //SqlOpJoin.create(op.getJoinType(), left.getOp(), right.getOp()); // new SqlOpJoin(null, op.getJoinType(), left.getOp(), right.getOp()); // op.getConditions()); // // // JoinContextJoin context = new JoinContextJoin(join); // // context.getProjection().add(left.getProjection()); // context.getProjection().add(right.getProjection()); // // //join.getConditions().addAll(left.getConditions()); // context.getConditions().addAll(left.getConditions()); // context.getConditions().addAll(right.getConditions()); // //copyProjection(join, node); // // List<SqlExpr> transformed = adjustConditions(op.getConditions(), context.getProjection()); // //result.getConditions().addAll(transformed); // // //join.getConditions().addAll(op.getConditions()); // join.getConditions().addAll(transformed); // // // return context; // } public static JoinContext collectJoins(SqlOpJoin op, Set<String> refs) { JoinContext left = _collectJoins(op.getLeft(), refs); JoinContext right = _collectJoins(op.getRight(), refs); if(op.getJoinType().equals(JoinType.LEFT)) { // SqlOp leftOp = left.getOp(); // List<SqlOp> joins = SqlOptimizer.collectJoins(left.getOp()); // // // if there is multiple joins, create a subselect if(left.getOp() instanceof SqlOpJoin) { //requireSelectBlock(op.getLeft()); SqlOpSelectBlock subSelect = contextToBlock(left.getOp().getSchema(), left); /* * TODO Treat the case: * * context.projection.nameToExpr={h_4=a_4.label, ..., label=a_3.label}] * * */ String aliasName = aliasGenerator.next(); subSelect.setAliasName(aliasName); left = new JoinContextJoin(subSelect); Projection p = subSelect.getProjection(); Projection p2 = createProjectionWithReplacedAliasReferences(p, aliasName); left.getProjection().add(p2); //initProjection(left.getProjection(), left.getOp().getSchema(), aliasName); //initProjection(left.getProjection(), op.getSchema(), aliasName); } } // NOTE We use a null schema because column names may be common to left and right operand // which is invalid for the schema object. // However, at this stage, we assume that the schema is already validated, and we can // allow duplicate column names in order to avoid creating sub-queries SqlOpJoin join; if(useCodeThatCausesConflictsOnDuplicateNames) { join = new SqlOpJoin(null, op.getJoinType(), left.getOp(), right.getOp()); // op.getConditions()); } else { join = SqlOpJoin.create(op.getJoinType(), left.getOp(), right.getOp()); } JoinContextJoin context = new JoinContextJoin(join); context.getProjection().add(left.getProjection()); context.getProjection().add(right.getProjection()); //join.getConditions().addAll(left.getConditions()); context.getConditions().addAll(left.getConditions()); context.getConditions().addAll(right.getConditions()); //copyProjection(join, node); List<SqlExpr> transformed = adjustConditions(op.getConditions(), context.getProjection()); //result.getConditions().addAll(transformed); //join.getConditions().addAll(op.getConditions()); join.getConditions().addAll(transformed); return context; } public static JoinContext collectJoins(SqlOpUnionN op, Set<String> refs) { SqlOpUnionN newOp = makeSelect(op, refs); //SqlOpSelectBlock resultOp = SqlOpSelectBlock.create(newOp, newOp.getAliasName()); //initProjection(resultOp.getProjection(), op.getSchema(), resultOp.getAliasName()); SqlOpUnionN resultOp = newOp; ////SqlOp resultOp = requireSelectBlock(newOp); //JoinContext result = new JoinContextJoin(resultOp); JoinContext result = new JoinContextJoin(newOp); initProjection(result.getProjection(), op.getSchema(), resultOp.getAliasName()); return result; } public static JoinContext collectJoins(SqlOpFilter op, Set<String> refs) { JoinContext result = _collectJoins(op.getSubOp(), refs); List<SqlExpr> transformed = adjustConditions(op.getExprs(), result.getProjection()); result.getConditions().addAll(transformed); return result; } // If false, will wrap each join in a sub-select for renaming -- not working anymore static boolean useCodeThatCausesConflictsOnDuplicateNames = true; /** * * We need to map new-name to old name, such as: * a1.id -> id * becomes SELECT a1.id AS id * * otherwise we could create clashes such as: * id -> a1.id * id -> a2.id * * Even if we temporarily have * a1.id -> id * a2.id -> id * * there can be a rename * a2.id -> h_1 * * * @param op * @param context * @return */ public static JoinContext collectJoins(SqlOpRename op, Set<String> refs) { JoinContext result; if (useCodeThatCausesConflictsOnDuplicateNames) { // FIXME: Can be removed it seems; the other part seems to be working now result = _collectJoins(op.getSubOp(), refs); result.getProjection().renameAll(op.getRename()); } else { // Create a sub select JoinContext context = _collectJoins(op.getSubOp(), refs); context.getProjection().renameAll(op.getRename()); SqlOpSelectBlock selectBlock = contextToBlock(op.getSchema(), context); String aliasName = aliasGenerator.next(); selectBlock.setAliasName(aliasName); result = new JoinContextJoin(selectBlock); } return result; } public static Projection initNewProjection(Schema schema, String aliasName) { Projection result = new Projection(); initProjection(result, schema, aliasName); return result; } public static Projection createProjectionWithReplacedAliasReferences(Projection projection, String aliasName) { Projection result = new Projection(); for(Entry<String, SqlExpr> entry : projection.getNameToExpr().entrySet()) { String oldName = entry.getKey(); SqlExpr sqlExpr = entry.getValue(); SqlExpr newSqlExpr; // TODO In general, we would have to do this recursively!!! if(sqlExpr instanceof S_ColumnRef) { S_ColumnRef oldRef = (S_ColumnRef)sqlExpr; //newSqlExpr = new S_ColumnRef(oldRef.getDatatype(), oldRef.getColumnName(), aliasName); newSqlExpr = new S_ColumnRef(oldRef.getDatatype(), oldName, aliasName); } else { newSqlExpr = sqlExpr; } result.put(oldName, newSqlExpr); // TypeToken datatype = schema.getColumnType(oldName); // assert datatype != null : "Datatype must not be null at this point"; // // // // //projection.put(newName, new E_SqlColumnRef(oldName, aliasName, datatype)); // projection.put(newName, new S_ColumnRef(datatype, oldName, aliasName)); // } return result; } public static void initProjection(Projection projection, Schema schema, String aliasName) { for(String oldName : schema.getColumnNames()) { String newName = oldName; /* if(renames != null) { String renamed = renames.get(oldName); if(renamed != null) { newName = renamed; } }*/ //XClass datatype = schema.getColumnType(columnName); //context.getProjection().put(columnName, new SqlExprColumn(aliasName, columnName, datatype)); //ExprVar(aliasName + "." + columnName)); TypeToken datatype = schema.getColumnType(newName); assert datatype != null : "Datatype must not be null at this point"; //projection.put(newName, new E_SqlColumnRef(oldName, aliasName, datatype)); projection.put(newName, new S_ColumnRef(datatype, oldName, aliasName)); } } public static JoinContextJoin collectJoins(SqlOpExtend sqlOp, Set<String> refs) { //SqlOpQuery query = makeSelectOrTable(op); SqlOpSelectBlock op = makeSelect((SqlOpExtend)sqlOp, refs); String alias = aliasGenerator.next(); op.setAliasName(alias); JoinContextJoin result = new JoinContextJoin(op); initProjection(result.getProjection(), op.getSchema(), op.getAliasName()); return result; } public static JoinContextJoin collectJoins(SqlOpSelectBlock sqlOp, Set<String> refs) { //SqlOpSelectBlock op = makeSelect(sqlOp, refs); String alias = aliasGenerator.next(); sqlOp.setAliasName(alias); JoinContextJoin result = new JoinContextJoin(sqlOp); initProjection(result.getProjection(), sqlOp.getSchema(), sqlOp.getAliasName()); return result; } public static JoinContextJoin collectJoins(SqlOpTable op, Set<String> refs) { SqlOpTable table = makeSelectOrTable(op); JoinContextJoin result = new JoinContextJoin(table); initProjection(result.getProjection(), op.getSchema(), table.getAliasName()); return result; } public static JoinContextJoin collectJoins(SqlOpQuery op, Set<String> refs) { SqlOpQuery query = makeSelectOrTable(op); JoinContextJoin result = new JoinContextJoin(query); initProjection(result.getProjection(), op.getSchema(), query.getAliasName()); return result; } /* public static SqlOpUnionN makeSelectOrTable(SqlOpUnionN op) { String alias = aliasGenerator.next(); SqlOpUnionN result = new SqlOpUnionN(op.getSchema(), op.getSubOps(), alias); return result; } */ public static SqlOpEmpty makeSelectOrTable(SqlOpEmpty node, Set<String> refs) { String alias = aliasGenerator.next(); SqlOpEmpty result = new SqlOpEmpty(node.getSchema(), alias); return result; } // public static SqlOpSelectBlock makeSelectOrTable(SqlOpSelectBlock result) { // // // TODO Maybe we should copy rather than doing in-place transformations // String alias = aliasGenerator.next(); // result.setAliasName(alias); // //SqlOpSelectBlock result = SqlOpSelectBlock.create(sqlOp, aliasName) // //SqlOpTable result = new SqlOpSelect(node.getSchema(), node.getTableName(), alias); // // return result; // } public static SqlOpTable makeSelectOrTable(SqlOpTable node) { String alias = aliasGenerator.next(); SqlOpTable result = new SqlOpTable(node.getSchema(), node.getTableName(), alias); return result; } public static SqlOpQuery makeSelectOrTable(SqlOpQuery node) { String alias = aliasGenerator.next(); SqlOpQuery result = new SqlOpQuery(node.getSchema(), node.getQueryString(), alias); return result; } @Override public SqlOp transform(SqlOp op) { return SqlOpSelectBlockCollectorImpl._makeSelect(op, null); } /* public static SqlOpSelectBlock makeSelect(SqlGroup node) { SqlOpSelectBlock result; if(node.getSubOp() instanceof SqlOpSlice) { SqlOpSelectBlock tmp = _makeSelect(node.getSubOp()); result = new SqlOpSelectBlock(tmp.getAliasName(), tmp); copyProjection(result, result); } else { result = _makeSelect(node.getSubOp()); } System.err.println("TODO Handle group by vars if present"); return result; } */ /* SqlOpSelectBlock result = SqlOpSelectBlock.create(opQuery); for(String columnName : opQuery.getSchema().getColumnNames()) { result.getProjection().put(columnName, new ExprVar(opQuery.getAliasName() + "." + columnName)); } return result; * / } */ /* public static SqlOpSelectBlock makeSelect(SqlOpFilter node) { SqlOpSelectBlock result = _makeSelect(node.getSubOp()); result.getConditions().addAll(node.getExprs()); return result; } public static SqlOpSelectBlock makeSelect(SqlOpSlice node) { SqlOpSelectBlock result = _makeSelect(node.getSubOp()); SqlOpSelectBlock.slice(null, result, node.getOffset(), node.getLimit()); return result; } public static SqlOpSelectBlock makeSelect(SqlOpDistinct node) { SqlOpSelectBlock result = _makeSelect(node.getSubOp()); result.setDistinct(true); return result; } /* public static SqlOpSelectBlock makeSelect(SqlAlias node) { if(true) { SqlOpSelectBlock result = _makeSelect(node.getSubOp()); //result.setAliasName(node.getAliasName()); SqlOpSelectBlock wrap = new SqlOpSelectBlock(node.getAliasName(), result); copyProjection(wrap, result); return wrap; /* copyProjection(result, node); result.setAliasName(node.getAliasName()); return result; * / } //throw new RuntimeException("Should not come here"); SqlOp result = _makeSelectOrTable(node.getSubOp()); SqlOpSelectBlock wrap = new SqlOpSelectBlock(node.getAliasName(), result); copyProjection(wrap, result); return wrap; /* wrap.getSparqlVarToExprs().putAll(node.getSparqlVarToExprs()); wrap.getAliasToColumn().putAll(node.getAliasToColumn()); result.setAliasName(node.getAliasName()); return result; * / } */ /* public static SqlOpSelectBlock makeSelect(SqlOpOrder node) { SqlOpSelectBlock result = _makeSelect(node.getSubOp()); result.getSortConditions().addAll(node.getConditions()); copyProjection(result, node); return result; } */ /* public static SqlOpSelectBlock makeSelect(SqlOpProject node) { SqlOpSelectBlock result = _makeSelect(node.getSubOp()); // If the node is distinct, or if it already has a projection set, // we must create a subselect if(result.isDistinct()) { // || result.isResultStar() //SqlOpSelectBlock wrapped = new } return result; } public static SqlOpSelectBlock makeSelect(SqlOpRename op) { SqlOpSelectBlock result = _makeSelect(op.getSubOp()); result.getProjection().renameAll(op.getRename()); return result; } public static SqlOpSelectBlock makeSelect(SqlOpJoin op) { SqlOpSelectBlock result = SqlOpSelectBlock.create(op); SqlOp subOp = makeSelect(op, result); result.setSubOp(subOp); return result; } public static SqlOpSelectBlock makeSelect(SqlOpUnionN node) { // Wrap all elements of the union List<SqlOp> wrapped = new ArrayList<SqlOp>(); for(SqlOp arg : node.getSubOps()) { SqlOpSelectBlock argSelect = _makeSelect(arg); /* argSelect.getSparqlVarToExprs().clear(); argSelect.getAliasToColumn().clear(); argSelect.getSparqlVarToExprs().putAll(arg.getSparqlVarToExprs()); argSelect.getAliasToColumn().putAll(arg.getAliasToColumn()); * / wrapped.add(argSelect); } SqlOpUnionN union = SqlOpUnionN.create(wrapped); //, SqlOpSelectBlock.getAliasName(node)); SqlOpSelectBlock result = SqlOpSelectBlock.create(union); return result; } /* public static SqlOp _makeSelectOrTable(SqlOp node) { return MultiMethod.invokeStatic(SqlOpSelectBlockCollectorOld.class, "makeSelectOrTable", node); } public static SqlOp makeSelectOrTable(SqlOpEmpty node) { // Should never come here return node; } public static SqlOp makeSelectOrTable(SqlOpProject node) { return _makeSelect(node); } /* public static SqlOp makeSelectOrTable(SqlAlias node) { SqlOp tmp = _makeSelectOrTable(node.getSubOp()); SqlAlias result = new SqlAlias(node.getAliasName(), tmp); copyProjection(result, node); return result; } * / public static SqlOp makeSelectOrTable(SqlOpFilter node) { return _makeSelect(node); } public static SqlOp makeSelectOrTable(SqlOpSlice node) { return _makeSelect(node); } public static SqlOp makeSelectOrTable(SqlOpDistinct node) { return _makeSelect(node); } public static SqlOp makeSelectOrTable(SqlOpRename op) { return _makeSelect(op); } /* public static SqlOp makeSelectOrTable(SqlOpJoin node) { SqlOp left = _makeSelectOrTable(node.getLeft()); SqlOp right = _makeSelectOrTable(node.getRight()); SqlOpJoin join = SqlOpJoin.create(node.getJoinType(), left, right); join.getConditions().addAll(node.getConditions()); //copyProjection(join, node); return join; } * / public static SqlOp makeSelectOrTable(SqlOpUnionN node) { return makeSelect(node); } */ }