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);
}
*/
}