Repository: duckdb/duckdb
File: src/planner/binder/expression/bind_operator_expression.cpp (C++)

Code before:
			ExpressionBinder::PushCollation(context, child, max_type);
		}
	}
	return max_type;
}

LogicalType ExpressionBinder::ResolveOperatorType(OperatorExpression &op, vector<unique_ptr<Expression>> &children) {
	switch (op.GetExpressionType()) {
	case ExpressionType::OPERATOR_IS_NULL:
	case ExpressionType::OPERATOR_IS_NOT_NULL:
		// IS (NOT) NULL always returns a boolean, and does not cast its children
		if (!children[0]->return_type.IsValid()) {
			throw ParameterNotResolvedException();
		}
		return LogicalType::BOOLEAN;
	case ExpressionType::COMPARE_IN:
	case ExpressionType::COMPARE_NOT_IN:
		ResolveCoalesceType(op, children);
		// (NOT) IN always returns a boolean
		return LogicalType::BOOLEAN;
	case ExpressionType::OPERATOR_COALESCE: {
		return ResolveCoalesceType(op, children);
	}
	case ExpressionType::OPERATOR_TRY: {
		LogicalType return_type = LogicalType::SQLNULL;
		auto child_type = ExpressionBinder::GetExpressionReturnType(*children[0]);
		LogicalType::TryGetMaxLogicalType(context, return_type, child_type, return_type);
		return return_type;
	}
	case ExpressionType::OPERATOR_NOT:
		return ResolveNotType(op, children);
	default:
		throw InternalException("Unrecognized expression type for ResolveOperatorType");
	}
}

BindResult ExpressionBinder::BindGroupingFunction(OperatorExpression &op, idx_t depth) {
	return BindResult("GROUPING function is not supported here");
}

BindResult ExpressionBinder::BindExpression(OperatorExpression &op, idx_t depth) {
	if (op.GetExpressionType() == ExpressionType::GROUPING_FUNCTION) {
		return BindGroupingFunction(op, depth);
	}

	// Bind the children of the operator expression. We already create bound expressions.
	// Only those children that trigger an error are not yet bound.
	ErrorData error;
	for (idx_t i = 0; i < op.children.size(); i++) {
		BindChild(op.children[i], depth, error);
	}

Review comment (suggestion):
I think we should just use `children[0]->return_type` here.`ExpressionBinder::GetExpressionReturnType` is a function that is explicitly designed to return special literal types that are used during binding only:

```sql

LogicalType ExpressionBinder::GetExpressionReturnType(const Expression &expr) {
	if (expr.GetExpressionClass() == ExpressionClass::BOUND_CONSTANT) {
		if (expr.return_type == LogicalTypeId::VARCHAR && StringType::GetCollation(expr.return_type).empty()) {
			return LogicalTypeId::STRING_LITERAL;
		}
		if (expr.return_type.IsIntegral()) {
			auto &constant = expr.Cast<BoundConstantExpression>();
			if (!constant.value.IsNull()) {
				return LogicalType::INTEGER_LITERAL(constant.value);
			}
		}
	}
	return expr.return_type;
}
```

The current code uses this function to add these types, to then remove them again using `LogicalType::TryGetMaxLogicalType`

Code after:
			ExpressionBinder::PushCollation(context, child, max_type);
		}
	}
	return max_type;
}

LogicalType ExpressionBinder::ResolveOperatorType(OperatorExpression &op, vector<unique_ptr<Expression>> &children) {
	switch (op.GetExpressionType()) {
	case ExpressionType::OPERATOR_IS_NULL:
	case ExpressionType::OPERATOR_IS_NOT_NULL:
		// IS (NOT) NULL always returns a boolean, and does not cast its children
		if (!children[0]->return_type.IsValid()) {
			throw ParameterNotResolvedException();
		}
		return LogicalType::BOOLEAN;
	case ExpressionType::COMPARE_IN:
	case ExpressionType::COMPARE_NOT_IN:
		ResolveCoalesceType(op, children);
		// (NOT) IN always returns a boolean
		return LogicalType::BOOLEAN;
	case ExpressionType::OPERATOR_COALESCE: {
		return ResolveCoalesceType(op, children);
	}
	case ExpressionType::OPERATOR_TRY: {
		return children[0]->return_type;
	}
	case ExpressionType::OPERATOR_NOT:
		return ResolveNotType(op, children);
	default:
		throw InternalException("Unrecognized expression type for ResolveOperatorType");
	}
}

BindResult ExpressionBinder::BindGroupingFunction(OperatorExpression &op, idx_t depth) {
	return BindResult("GROUPING function is not supported here");
}

BindResult ExpressionBinder::BindExpression(OperatorExpression &op, idx_t depth) {
	if (op.GetExpressionType() == ExpressionType::GROUPING_FUNCTION) {
		return BindGroupingFunction(op, depth);
	}

	// Bind the children of the operator expression. We already create bound expressions.
	// Only those children that trigger an error are not yet bound.
	ErrorData error;
	for (idx_t i = 0; i < op.children.size(); i++) {
		BindChild(op.children[i], depth, error);
	}
	if (error.HasError()) {
		return BindResult(std::move(error));
	}