Ref<AssignedSymbol> outSym, Ref<Type> outType) throws TypeCheckException {
// Check that this field is defined by one of the input sources.
// Since the source pushed a symbol table on the stack, just check
// that we have a symbol table, and that this is a primitive value.
Symbol fieldSym = fieldsSymTab.resolve(fieldName);
if (null == fieldSym) {
// This isn't just a simple field. Check if it's an attribute.
if (fieldName.startsWith("#") && fieldName.length() > 1) {
// This is an attribute name.
String attrName = fieldName.substring(1);
fieldSym = new AssignedSymbol(attrName,
Type.getNullable(Type.TypeName.BINARY),
attrName, IdentifierExpr.AccessType.ATTRIBUTE);
} else if (isAmbiguousAlias(fieldName, fieldsSymTab)) {
// The identifier doesn't exist, or else it's an ambiguous alias.
// Return the appropriate error message.
// This identifier is probably an alias for another identifier
// but the alias is removed due to ambiguity in a JOIN.
throw new TypeCheckException("Ambiguous identifier: \"" + fieldName + "\". "
+ "You must prefix this with a stream name qualifier.");
} else {
// This identifier straight-up doesn't exist.
throw new TypeCheckException("No such identifier: \"" + fieldName + "\"");
}
}
Type fieldType = fieldSym.getType();
if (!fieldType.isConcrete()) {
// This name refers to a stream or other ephemeral type. We can't
// select that.
throw new TypeCheckException("Cannot select non-concrete entity \""
+ fieldName + "\"");
}
outType.item = fieldType;
// The field symbol should also be an AssignedSymbol that has a unique
// reference name throughout the query. Bind to the reference name here;
// the actual query uses this name instead of the user-friendly
// identifier.
fieldSym = fieldSym.resolveAliases();
assert fieldSym instanceof AssignedSymbol;
outSym.item = (AssignedSymbol) fieldSym;
}