// also happen if an ExpressionNode is a constant NULL.
for (int rownum = 0, expressionsSize = rows.size(); rownum < expressionsSize; rownum++) {
List<ExpressionNode> row = rows.get(rownum);
assert row.size() == nfields : "jagged rows: " + node;
for (int field = 0; field < nfields; ++field) {
TInstance botInstance = type(row.get(field));
special:
if (botInstance == null) {
// type is unknown (parameter or literal NULL), so it doesn't participate in determining a
// type, but a cast is needed.
needCasts.set(field);
// If it is a parameter, it needs to be allowed to be wider than
// any of the existing values, while still consistent with them.
if (row.get(field) instanceof ParameterExpression) {
// Force use of commonTClass(existing,null) below to widen.
if (!widened.get(field)) {
widened.set(field);
break special;
}
}
continue;
}
else if (instances[field] == null) {
// Take type from first non-NULL, unless we have to widen,
// which commonTClass(null,expr) will take care of.
if (widened.get(field)) {
break special;
}
instances[field] = botInstance;
continue;
}
// If the two are the same, we know we don't need to cast them.
// This logic also handles the case where both are null, which is not a valid argument
// to resolver.commonTClass.
if (Objects.equal(instances[field], botInstance))
continue;
TClass topClass = tclass(instances[field]);
TClass botClass = tclass(botInstance);
TClass commonTClass = registry.getCastsResolver().commonTClass(topClass, botClass);
if (commonTClass == null) {
throw new AkibanInternalException("no common type found found between row " + (rownum-1)
+ " and " + rownum + " at field " + field);
}
// The two rows have different TClasses at this index, so we'll need at least one of them to
// be casted. Also the common class will be the widest comparable.
needCasts.set(field);
widened.set(field);
boolean eitherIsNullable;
if (botInstance == null)
eitherIsNullable = true;
else
eitherIsNullable = botInstance.nullability();
if ( (!eitherIsNullable) && (instances[field] != null)) {
// bottom is not nullable, and there is a top. See if it's nullable
eitherIsNullable = instances[field].nullability();
}
// need to set a new instances[field]. Rules:
// - if topClass and botClass are the same as common, use picking algorithm
// - else, if one of them == commonTClass, use topInstance or botInstance (whichever is == common)
// - else, use commonTClass.instance()
boolean topIsCommon = (topClass == commonTClass);
boolean botIsCommon = (botClass == commonTClass);
if (topIsCommon && botIsCommon) {
// TODO: The special case here for TClass VARCHAR with mismatched charsets
// is a limitation of the TClass#pickInstance, as there is no current way
// to create a common TInstance for TString with difference charsets.
if (commonTClass instanceof TString &&
botInstance.attribute(StringAttribute.CHARSET) != instances[field].attribute(StringAttribute.CHARSET)) {
;
}
else {
instances[field] = topClass.pickInstance(instances[field], botInstance);
}