in tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java [256:379]
public Column resolveColumn(QueryBlock block, ColumnReferenceExpr columnRef) throws PlanningException {
if (columnRef.hasQualifier()) { // if a column reference is qualified
RelationNode relationOp = block.getRelation(columnRef.getQualifier());
// if a column name is outside of this query block
if (relationOp == null) {
// TODO - nested query can only refer outer query block? or not?
for (QueryBlock eachBlock : queryBlocks.values()) {
if (eachBlock.existsRelation(columnRef.getQualifier())) {
relationOp = eachBlock.getRelation(columnRef.getQualifier());
}
}
}
// If we cannot find any relation against a qualified column name
if (relationOp == null) {
throw new NoSuchColumnException(columnRef.getCanonicalName());
}
Schema schema = relationOp.getTableSchema();
Column column = schema.getColumn(columnRef.getCanonicalName());
if (column == null) {
throw new NoSuchColumnException(columnRef.getCanonicalName());
}
// If code reach here, a column is found.
// But, it may be aliased from bottom logical node.
// If the column is aliased, the found name may not be used in upper node.
// Here, we try to check if column reference is already aliased.
// If so, it replaces the name with aliased name.
LogicalNode currentNode = block.getCurrentNode();
// The condition (currentNode.getInSchema().contains(column)) means
// the column can be used at the current node. So, we don't need to find aliase name.
if (currentNode != null && !currentNode.getInSchema().contains(column)) {
List<Column> candidates = TUtil.newList();
if (block.namedExprsMgr.isAliased(column.getQualifiedName())) {
String alias = block.namedExprsMgr.getAlias(columnRef.getCanonicalName());
Column found = resolveColumn(block, new ColumnReferenceExpr(alias));
if (found != null) {
candidates.add(found);
}
}
if (!candidates.isEmpty()) {
return ensureUniqueColumn(candidates);
}
}
return column;
} else { // if a column reference is not qualified
// Trying to find the column within the current block
if (block.currentNode != null && block.currentNode.getInSchema() != null) {
Column found = block.currentNode.getInSchema().getColumn(columnRef.getCanonicalName());
if (found != null) {
return found;
}
}
if (block.getLatestNode() != null) {
Column found = block.getLatestNode().getOutSchema().getColumn(columnRef.getName());
if (found != null) {
return found;
}
}
List<Column> candidates = TUtil.newList();
// Trying to find columns from aliased references.
if (block.namedExprsMgr.isAliased(columnRef.getCanonicalName())) {
String originalName = block.namedExprsMgr.getAlias(columnRef.getCanonicalName());
Column found = resolveColumn(block, new ColumnReferenceExpr(originalName));
if (found != null) {
candidates.add(found);
}
}
if (!candidates.isEmpty()) {
return ensureUniqueColumn(candidates);
}
// Trying to find columns from other relations in the current block
for (RelationNode rel : block.getRelations()) {
Column found = rel.getTableSchema().getColumn(columnRef.getName());
if (found != null) {
candidates.add(found);
}
}
if (!candidates.isEmpty()) {
return ensureUniqueColumn(candidates);
}
// Trying to find columns from other relations in other blocks
for (QueryBlock eachBlock : queryBlocks.values()) {
for (RelationNode rel : eachBlock.getRelations()) {
Column found = rel.getTableSchema().getColumn(columnRef.getName());
if (found != null) {
candidates.add(found);
}
}
}
if (!candidates.isEmpty()) {
return ensureUniqueColumn(candidates);
}
// Trying to find columns from schema in current block.
if (block.getSchema() != null) {
Column found = block.getSchema().getColumn(columnRef.getName());
if (found != null) {
candidates.add(found);
}
}
if (!candidates.isEmpty()) {
return ensureUniqueColumn(candidates);
}
throw new VerifyException("ERROR: no such a column name "+ columnRef.getCanonicalName());
}
}