[yet more rambling]
A ResultSetNode has a set of ResultColumns and each ResultColumn has an expression under it.
A NormalizeResultSetNode is added above a ResultSetNode (wraps it) when the type of at least one of its
ResultColumn does not match the type of its expression,
ResultColumn indicates this can be the case & I added some more comments to that.
Once the decision is made to add a NormalizeResultSetNode there is some processing of ResultColumns and ResultColumnLists
that I haven't understood yet, this includes the call copyLengthsAndTypesToSource() that Kathey modified.
Setting up a NormalizeResultSetNode is spread over three locations, the class itself (very little, it's almost acting like a C struct),
the genNormalizeResultSetNode method and then copyLengthsAndTypesToSource. A good O-O implementation would have
the logic to create a NormalizeResultSetNode self-contained in NormalizeResultSetNode.
Since the ResultColumnList of the original ResultSetNode correctly describes the desired outcome, it's not clear to
me why NormalizeResultSetNode can't just refer to the same list and use it for its processing. They may be some chance
that this would cause recursion at some point, where a NormalizeResultSetNode would think it needed to be wrapped
in a NormalizeResultSetNode since the types of its columns and expression don't match (i.e. when it is handled as a regular ResultSetNode).
I think moving the setup of a NormalizeResultSetNode into the class itself, so that its inputs are just the ResultSetNode to wrap
would help clear up the code, especially if comments were added indicating why certain actions were being taken.