Attached is a patch that fixes this by storing typmod info in the RTE.
This turned out to be straightforward, and I think it's definitely
what we should do in HEAD.  I have mixed emotions about whether it's
worth doing anything about it in the back branches.

I chose to redefine the existing coltypes/coltypmods/colcollations
lists for CTE RTEs as also applying to VALUES RTEs.  That saves a
little space in the RangeTblEntry nodes and allows sharing code
in a couple of places.  It's tempting to consider making that apply
to all RTE types, which would permit collapsing expandRTE() and
get_rte_attribute_type() into a single case.  But AFAICS there would
be no benefit elsewhere, so I'm not sure the extra code churn is
justified.

BTW, I noticed that the CTE case of expandRTE() fails to assign the
specified location to the generated Vars, which is clearly a bug
though a very minor one; it would result in failing to display a
parse error location in some cases where we would do so for Vars from
other RTE types.  That part might be worth back-patching, not sure.

                        regards, tom lane

diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e30c57e..d973225 100644
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
*************** _copyRangeTblEntry(const RangeTblEntry *
*** 2149,2161 ****
  	COPY_NODE_FIELD(functions);
  	COPY_SCALAR_FIELD(funcordinality);
  	COPY_NODE_FIELD(values_lists);
- 	COPY_NODE_FIELD(values_collations);
  	COPY_STRING_FIELD(ctename);
  	COPY_SCALAR_FIELD(ctelevelsup);
  	COPY_SCALAR_FIELD(self_reference);
! 	COPY_NODE_FIELD(ctecoltypes);
! 	COPY_NODE_FIELD(ctecoltypmods);
! 	COPY_NODE_FIELD(ctecolcollations);
  	COPY_NODE_FIELD(alias);
  	COPY_NODE_FIELD(eref);
  	COPY_SCALAR_FIELD(lateral);
--- 2149,2160 ----
  	COPY_NODE_FIELD(functions);
  	COPY_SCALAR_FIELD(funcordinality);
  	COPY_NODE_FIELD(values_lists);
  	COPY_STRING_FIELD(ctename);
  	COPY_SCALAR_FIELD(ctelevelsup);
  	COPY_SCALAR_FIELD(self_reference);
! 	COPY_NODE_FIELD(coltypes);
! 	COPY_NODE_FIELD(coltypmods);
! 	COPY_NODE_FIELD(colcollations);
  	COPY_NODE_FIELD(alias);
  	COPY_NODE_FIELD(eref);
  	COPY_SCALAR_FIELD(lateral);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index b7a109c..edc1797 100644
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
*************** _equalRangeTblEntry(const RangeTblEntry 
*** 2460,2472 ****
  	COMPARE_NODE_FIELD(functions);
  	COMPARE_SCALAR_FIELD(funcordinality);
  	COMPARE_NODE_FIELD(values_lists);
- 	COMPARE_NODE_FIELD(values_collations);
  	COMPARE_STRING_FIELD(ctename);
  	COMPARE_SCALAR_FIELD(ctelevelsup);
  	COMPARE_SCALAR_FIELD(self_reference);
! 	COMPARE_NODE_FIELD(ctecoltypes);
! 	COMPARE_NODE_FIELD(ctecoltypmods);
! 	COMPARE_NODE_FIELD(ctecolcollations);
  	COMPARE_NODE_FIELD(alias);
  	COMPARE_NODE_FIELD(eref);
  	COMPARE_SCALAR_FIELD(lateral);
--- 2460,2471 ----
  	COMPARE_NODE_FIELD(functions);
  	COMPARE_SCALAR_FIELD(funcordinality);
  	COMPARE_NODE_FIELD(values_lists);
  	COMPARE_STRING_FIELD(ctename);
  	COMPARE_SCALAR_FIELD(ctelevelsup);
  	COMPARE_SCALAR_FIELD(self_reference);
! 	COMPARE_NODE_FIELD(coltypes);
! 	COMPARE_NODE_FIELD(coltypmods);
! 	COMPARE_NODE_FIELD(colcollations);
  	COMPARE_NODE_FIELD(alias);
  	COMPARE_NODE_FIELD(eref);
  	COMPARE_SCALAR_FIELD(lateral);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 0d858f5..7258c03 100644
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
*************** _outRangeTblEntry(StringInfo str, const 
*** 2841,2855 ****
  			break;
  		case RTE_VALUES:
  			WRITE_NODE_FIELD(values_lists);
! 			WRITE_NODE_FIELD(values_collations);
  			break;
  		case RTE_CTE:
  			WRITE_STRING_FIELD(ctename);
  			WRITE_UINT_FIELD(ctelevelsup);
  			WRITE_BOOL_FIELD(self_reference);
! 			WRITE_NODE_FIELD(ctecoltypes);
! 			WRITE_NODE_FIELD(ctecoltypmods);
! 			WRITE_NODE_FIELD(ctecolcollations);
  			break;
  		default:
  			elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
--- 2841,2857 ----
  			break;
  		case RTE_VALUES:
  			WRITE_NODE_FIELD(values_lists);
! 			WRITE_NODE_FIELD(coltypes);
! 			WRITE_NODE_FIELD(coltypmods);
! 			WRITE_NODE_FIELD(colcollations);
  			break;
  		case RTE_CTE:
  			WRITE_STRING_FIELD(ctename);
  			WRITE_UINT_FIELD(ctelevelsup);
  			WRITE_BOOL_FIELD(self_reference);
! 			WRITE_NODE_FIELD(coltypes);
! 			WRITE_NODE_FIELD(coltypmods);
! 			WRITE_NODE_FIELD(colcollations);
  			break;
  		default:
  			elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index c587d4e..d608530 100644
*** a/src/backend/nodes/readfuncs.c
--- b/src/backend/nodes/readfuncs.c
*************** _readRangeTblEntry(void)
*** 1314,1328 ****
  			break;
  		case RTE_VALUES:
  			READ_NODE_FIELD(values_lists);
! 			READ_NODE_FIELD(values_collations);
  			break;
  		case RTE_CTE:
  			READ_STRING_FIELD(ctename);
  			READ_UINT_FIELD(ctelevelsup);
  			READ_BOOL_FIELD(self_reference);
! 			READ_NODE_FIELD(ctecoltypes);
! 			READ_NODE_FIELD(ctecoltypmods);
! 			READ_NODE_FIELD(ctecolcollations);
  			break;
  		default:
  			elog(ERROR, "unrecognized RTE kind: %d",
--- 1314,1330 ----
  			break;
  		case RTE_VALUES:
  			READ_NODE_FIELD(values_lists);
! 			READ_NODE_FIELD(coltypes);
! 			READ_NODE_FIELD(coltypmods);
! 			READ_NODE_FIELD(colcollations);
  			break;
  		case RTE_CTE:
  			READ_STRING_FIELD(ctename);
  			READ_UINT_FIELD(ctelevelsup);
  			READ_BOOL_FIELD(self_reference);
! 			READ_NODE_FIELD(coltypes);
! 			READ_NODE_FIELD(coltypmods);
! 			READ_NODE_FIELD(colcollations);
  			break;
  		default:
  			elog(ERROR, "unrecognized RTE kind: %d",
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index d91bc3b..2fe1c8c 100644
*** a/src/backend/optimizer/plan/setrefs.c
--- b/src/backend/optimizer/plan/setrefs.c
*************** add_rte_to_flat_rtable(PlannerGlobal *gl
*** 396,405 ****
  	newrte->joinaliasvars = NIL;
  	newrte->functions = NIL;
  	newrte->values_lists = NIL;
! 	newrte->values_collations = NIL;
! 	newrte->ctecoltypes = NIL;
! 	newrte->ctecoltypmods = NIL;
! 	newrte->ctecolcollations = NIL;
  	newrte->securityQuals = NIL;
  
  	glob->finalrtable = lappend(glob->finalrtable, newrte);
--- 396,404 ----
  	newrte->joinaliasvars = NIL;
  	newrte->functions = NIL;
  	newrte->values_lists = NIL;
! 	newrte->coltypes = NIL;
! 	newrte->coltypmods = NIL;
! 	newrte->colcollations = NIL;
  	newrte->securityQuals = NIL;
  
  	glob->finalrtable = lappend(glob->finalrtable, newrte);
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 7364346..5e65fe7 100644
*** a/src/backend/parser/analyze.c
--- b/src/backend/parser/analyze.c
*************** transformInsertStmt(ParseState *pstate, 
*** 633,642 ****
  		 * RTE.
  		 */
  		List	   *exprsLists = NIL;
! 		List	   *collations = NIL;
  		int			sublist_length = -1;
  		bool		lateral = false;
- 		int			i;
  
  		Assert(selectStmt->intoClause == NULL);
  
--- 633,643 ----
  		 * RTE.
  		 */
  		List	   *exprsLists = NIL;
! 		List	   *coltypes = NIL;
! 		List	   *coltypmods = NIL;
! 		List	   *colcollations = NIL;
  		int			sublist_length = -1;
  		bool		lateral = false;
  
  		Assert(selectStmt->intoClause == NULL);
  
*************** transformInsertStmt(ParseState *pstate, 
*** 703,713 ****
  		}
  
  		/*
! 		 * Although we don't really need collation info, let's just make sure
! 		 * we provide a correctly-sized list in the VALUES RTE.
  		 */
! 		for (i = 0; i < sublist_length; i++)
! 			collations = lappend_oid(collations, InvalidOid);
  
  		/*
  		 * Ordinarily there can't be any current-level Vars in the expression
--- 704,723 ----
  		}
  
  		/*
! 		 * Construct column type/typmod/collation lists for the VALUES RTE.
! 		 * Every expression in each column has been coerced to the type/typmod
! 		 * of the corresponding target column or subfield, so it's sufficient
! 		 * to look at the exprType/exprTypmod of the first row.  We don't care
! 		 * about the collation labeling, so just fill in InvalidOid for that.
  		 */
! 		foreach(lc, (List *) linitial(exprsLists))
! 		{
! 			Node	   *val = (Node *) lfirst(lc);
! 
! 			coltypes = lappend_oid(coltypes, exprType(val));
! 			coltypmods = lappend_int(coltypmods, exprTypmod(val));
! 			colcollations = lappend_oid(colcollations, InvalidOid);
! 		}
  
  		/*
  		 * Ordinarily there can't be any current-level Vars in the expression
*************** transformInsertStmt(ParseState *pstate, 
*** 722,728 ****
  		/*
  		 * Generate the VALUES RTE
  		 */
! 		rte = addRangeTableEntryForValues(pstate, exprsLists, collations,
  										  NULL, lateral, true);
  		rtr = makeNode(RangeTblRef);
  		/* assume new rte is at end */
--- 732,739 ----
  		/*
  		 * Generate the VALUES RTE
  		 */
! 		rte = addRangeTableEntryForValues(pstate, exprsLists,
! 										  coltypes, coltypmods, colcollations,
  										  NULL, lateral, true);
  		rtr = makeNode(RangeTblRef);
  		/* assume new rte is at end */
*************** transformValuesClause(ParseState *pstate
*** 1274,1280 ****
  {
  	Query	   *qry = makeNode(Query);
  	List	   *exprsLists;
! 	List	   *collations;
  	List	  **colexprs = NULL;
  	int			sublist_length = -1;
  	bool		lateral = false;
--- 1285,1293 ----
  {
  	Query	   *qry = makeNode(Query);
  	List	   *exprsLists;
! 	List	   *coltypes = NIL;
! 	List	   *coltypmods = NIL;
! 	List	   *colcollations = NIL;
  	List	  **colexprs = NULL;
  	int			sublist_length = -1;
  	bool		lateral = false;
*************** transformValuesClause(ParseState *pstate
*** 1360,1367 ****
  
  	/*
  	 * Now resolve the common types of the columns, and coerce everything to
! 	 * those types.  Then identify the common collation, if any, of each
! 	 * column.
  	 *
  	 * We must do collation processing now because (1) assign_query_collations
  	 * doesn't process rangetable entries, and (2) we need to label the VALUES
--- 1373,1380 ----
  
  	/*
  	 * Now resolve the common types of the columns, and coerce everything to
! 	 * those types.  Then identify the common typmod and common collation, if
! 	 * any, of each column.
  	 *
  	 * We must do collation processing now because (1) assign_query_collations
  	 * doesn't process rangetable entries, and (2) we need to label the VALUES
*************** transformValuesClause(ParseState *pstate
*** 1372,1382 ****
  	 *
  	 * Note we modify the per-column expression lists in-place.
  	 */
- 	collations = NIL;
  	for (i = 0; i < sublist_length; i++)
  	{
  		Oid			coltype;
  		Oid			colcoll;
  
  		coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL);
  
--- 1385,1396 ----
  	 *
  	 * Note we modify the per-column expression lists in-place.
  	 */
  	for (i = 0; i < sublist_length; i++)
  	{
  		Oid			coltype;
+ 		int32		coltypmod = -1;
  		Oid			colcoll;
+ 		bool		first = true;
  
  		coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL);
  
*************** transformValuesClause(ParseState *pstate
*** 1386,1396 ****
  
  			col = coerce_to_common_type(pstate, col, coltype, "VALUES");
  			lfirst(lc) = (void *) col;
  		}
  
  		colcoll = select_common_collation(pstate, colexprs[i], true);
  
! 		collations = lappend_oid(collations, colcoll);
  	}
  
  	/*
--- 1400,1423 ----
  
  			col = coerce_to_common_type(pstate, col, coltype, "VALUES");
  			lfirst(lc) = (void *) col;
+ 			if (first)
+ 			{
+ 				coltypmod = exprTypmod(col);
+ 				first = false;
+ 			}
+ 			else
+ 			{
+ 				/* As soon as we see a non-matching typmod, fall back to -1 */
+ 				if (coltypmod >= 0 && coltypmod != exprTypmod(col))
+ 					coltypmod = -1;
+ 			}
  		}
  
  		colcoll = select_common_collation(pstate, colexprs[i], true);
  
! 		coltypes = lappend_oid(coltypes, coltype);
! 		coltypmods = lappend_int(coltypmods, coltypmod);
! 		colcollations = lappend_oid(colcollations, colcoll);
  	}
  
  	/*
*************** transformValuesClause(ParseState *pstate
*** 1432,1438 ****
  	/*
  	 * Generate the VALUES RTE
  	 */
! 	rte = addRangeTableEntryForValues(pstate, exprsLists, collations,
  									  NULL, lateral, true);
  	addRTEtoQuery(pstate, rte, true, true, true);
  
--- 1459,1466 ----
  	/*
  	 * Generate the VALUES RTE
  	 */
! 	rte = addRangeTableEntryForValues(pstate, exprsLists,
! 									  coltypes, coltypmods, colcollations,
  									  NULL, lateral, true);
  	addRTEtoQuery(pstate, rte, true, true, true);
  
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 1e3ecbc..58f7050 100644
*** a/src/backend/parser/parse_relation.c
--- b/src/backend/parser/parse_relation.c
*************** addRangeTableEntryForFunction(ParseState
*** 1635,1641 ****
  RangeTblEntry *
  addRangeTableEntryForValues(ParseState *pstate,
  							List *exprs,
! 							List *collations,
  							Alias *alias,
  							bool lateral,
  							bool inFromCl)
--- 1635,1643 ----
  RangeTblEntry *
  addRangeTableEntryForValues(ParseState *pstate,
  							List *exprs,
! 							List *coltypes,
! 							List *coltypmods,
! 							List *colcollations,
  							Alias *alias,
  							bool lateral,
  							bool inFromCl)
*************** addRangeTableEntryForValues(ParseState *
*** 1652,1658 ****
  	rte->relid = InvalidOid;
  	rte->subquery = NULL;
  	rte->values_lists = exprs;
! 	rte->values_collations = collations;
  	rte->alias = alias;
  
  	eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
--- 1654,1662 ----
  	rte->relid = InvalidOid;
  	rte->subquery = NULL;
  	rte->values_lists = exprs;
! 	rte->coltypes = coltypes;
! 	rte->coltypmods = coltypmods;
! 	rte->colcollations = colcollations;
  	rte->alias = alias;
  
  	eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
*************** addRangeTableEntryForCTE(ParseState *pst
*** 1822,1830 ****
  					 parser_errposition(pstate, rv->location)));
  	}
  
! 	rte->ctecoltypes = cte->ctecoltypes;
! 	rte->ctecoltypmods = cte->ctecoltypmods;
! 	rte->ctecolcollations = cte->ctecolcollations;
  
  	rte->alias = alias;
  	if (alias)
--- 1826,1834 ----
  					 parser_errposition(pstate, rv->location)));
  	}
  
! 	rte->coltypes = cte->ctecoltypes;
! 	rte->coltypmods = cte->ctecoltypmods;
! 	rte->colcollations = cte->ctecolcollations;
  
  	rte->alias = alias;
  	if (alias)
*************** expandRTE(RangeTblEntry *rte, int rtinde
*** 2153,2198 ****
  				}
  			}
  			break;
- 		case RTE_VALUES:
- 			{
- 				/* Values RTE */
- 				ListCell   *aliasp_item = list_head(rte->eref->colnames);
- 				ListCell   *lcv;
- 				ListCell   *lcc;
- 
- 				varattno = 0;
- 				forboth(lcv, (List *) linitial(rte->values_lists),
- 						lcc, rte->values_collations)
- 				{
- 					Node	   *col = (Node *) lfirst(lcv);
- 					Oid			colcollation = lfirst_oid(lcc);
- 
- 					varattno++;
- 					if (colnames)
- 					{
- 						/* Assume there is one alias per column */
- 						char	   *label = strVal(lfirst(aliasp_item));
- 
- 						*colnames = lappend(*colnames,
- 											makeString(pstrdup(label)));
- 						aliasp_item = lnext(aliasp_item);
- 					}
- 
- 					if (colvars)
- 					{
- 						Var		   *varnode;
- 
- 						varnode = makeVar(rtindex, varattno,
- 										  exprType(col),
- 										  exprTypmod(col),
- 										  colcollation,
- 										  sublevels_up);
- 						varnode->location = location;
- 						*colvars = lappend(*colvars, varnode);
- 					}
- 				}
- 			}
- 			break;
  		case RTE_JOIN:
  			{
  				/* Join RTE */
--- 2157,2162 ----
*************** expandRTE(RangeTblEntry *rte, int rtinde
*** 2262,2278 ****
  				}
  			}
  			break;
  		case RTE_CTE:
  			{
  				ListCell   *aliasp_item = list_head(rte->eref->colnames);
  				ListCell   *lct;
  				ListCell   *lcm;
  				ListCell   *lcc;
  
  				varattno = 0;
! 				forthree(lct, rte->ctecoltypes,
! 						 lcm, rte->ctecoltypmods,
! 						 lcc, rte->ctecolcollations)
  				{
  					Oid			coltype = lfirst_oid(lct);
  					int32		coltypmod = lfirst_int(lcm);
--- 2226,2244 ----
  				}
  			}
  			break;
+ 		case RTE_VALUES:
  		case RTE_CTE:
  			{
+ 				/* Values or CTE RTE */
  				ListCell   *aliasp_item = list_head(rte->eref->colnames);
  				ListCell   *lct;
  				ListCell   *lcm;
  				ListCell   *lcc;
  
  				varattno = 0;
! 				forthree(lct, rte->coltypes,
! 						 lcm, rte->coltypmods,
! 						 lcc, rte->colcollations)
  				{
  					Oid			coltype = lfirst_oid(lct);
  					int32		coltypmod = lfirst_int(lcm);
*************** expandRTE(RangeTblEntry *rte, int rtinde
*** 2285,2291 ****
  						/* Assume there is one alias per output column */
  						char	   *label = strVal(lfirst(aliasp_item));
  
! 						*colnames = lappend(*colnames, makeString(pstrdup(label)));
  						aliasp_item = lnext(aliasp_item);
  					}
  
--- 2251,2258 ----
  						/* Assume there is one alias per output column */
  						char	   *label = strVal(lfirst(aliasp_item));
  
! 						*colnames = lappend(*colnames,
! 											makeString(pstrdup(label)));
  						aliasp_item = lnext(aliasp_item);
  					}
  
*************** expandRTE(RangeTblEntry *rte, int rtinde
*** 2296,2301 ****
--- 2263,2270 ----
  						varnode = makeVar(rtindex, varattno,
  										  coltype, coltypmod, colcoll,
  										  sublevels_up);
+ 						varnode->location = location;
+ 
  						*colvars = lappend(*colvars, varnode);
  					}
  				}
*************** get_rte_attribute_type(RangeTblEntry *rt
*** 2654,2675 ****
  								rte->eref->aliasname)));
  			}
  			break;
- 		case RTE_VALUES:
- 			{
- 				/* Values RTE --- get type info from first sublist */
- 				/* collation is stored separately, though */
- 				List	   *collist = (List *) linitial(rte->values_lists);
- 				Node	   *col;
- 
- 				if (attnum < 1 || attnum > list_length(collist))
- 					elog(ERROR, "values list %s does not have attribute %d",
- 						 rte->eref->aliasname, attnum);
- 				col = (Node *) list_nth(collist, attnum - 1);
- 				*vartype = exprType(col);
- 				*vartypmod = exprTypmod(col);
- 				*varcollid = list_nth_oid(rte->values_collations, attnum - 1);
- 			}
- 			break;
  		case RTE_JOIN:
  			{
  				/*
--- 2623,2628 ----
*************** get_rte_attribute_type(RangeTblEntry *rt
*** 2685,2697 ****
  				*varcollid = exprCollation(aliasvar);
  			}
  			break;
  		case RTE_CTE:
  			{
! 				/* CTE RTE --- get type info from lists in the RTE */
! 				Assert(attnum > 0 && attnum <= list_length(rte->ctecoltypes));
! 				*vartype = list_nth_oid(rte->ctecoltypes, attnum - 1);
! 				*vartypmod = list_nth_int(rte->ctecoltypmods, attnum - 1);
! 				*varcollid = list_nth_oid(rte->ctecolcollations, attnum - 1);
  			}
  			break;
  		default:
--- 2638,2651 ----
  				*varcollid = exprCollation(aliasvar);
  			}
  			break;
+ 		case RTE_VALUES:
  		case RTE_CTE:
  			{
! 				/* VALUES or CTE RTE --- get type info from lists in the RTE */
! 				Assert(attnum > 0 && attnum <= list_length(rte->coltypes));
! 				*vartype = list_nth_oid(rte->coltypes, attnum - 1);
! 				*vartypmod = list_nth_int(rte->coltypmods, attnum - 1);
! 				*varcollid = list_nth_oid(rte->colcollations, attnum - 1);
  			}
  			break;
  		default:
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 6b95c48..fc532fb 100644
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef struct RangeTblEntry
*** 927,933 ****
  	 * Fields valid for a values RTE (else NIL):
  	 */
  	List	   *values_lists;	/* list of expression lists */
- 	List	   *values_collations;		/* OID list of column collation OIDs */
  
  	/*
  	 * Fields valid for a CTE RTE (else NULL/zero):
--- 927,932 ----
*************** typedef struct RangeTblEntry
*** 935,943 ****
  	char	   *ctename;		/* name of the WITH list item */
  	Index		ctelevelsup;	/* number of query levels up */
  	bool		self_reference; /* is this a recursive self-reference? */
! 	List	   *ctecoltypes;	/* OID list of column type OIDs */
! 	List	   *ctecoltypmods;	/* integer list of column typmods */
! 	List	   *ctecolcollations;		/* OID list of column collation OIDs */
  
  	/*
  	 * Fields valid in all RTEs:
--- 934,950 ----
  	char	   *ctename;		/* name of the WITH list item */
  	Index		ctelevelsup;	/* number of query levels up */
  	bool		self_reference; /* is this a recursive self-reference? */
! 
! 	/*
! 	 * Fields valid for values and CTE RTEs (else NIL):
! 	 *
! 	 * We need these for CTE RTEs so that the types of self-referential
! 	 * columns are well-defined.  For VALUES RTEs, storing these explicitly
! 	 * saves having to re-determine the info by scanning the values_lists.
! 	 */
! 	List	   *coltypes;		/* OID list of column type OIDs */
! 	List	   *coltypmods;		/* integer list of column typmods */
! 	List	   *colcollations;	/* OID list of column collation OIDs */
  
  	/*
  	 * Fields valid in all RTEs:
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index 3ef3d7b..9463f9d 100644
*** a/src/include/parser/parse_relation.h
--- b/src/include/parser/parse_relation.h
*************** extern RangeTblEntry *addRangeTableEntry
*** 85,91 ****
  							  bool inFromCl);
  extern RangeTblEntry *addRangeTableEntryForValues(ParseState *pstate,
  							List *exprs,
! 							List *collations,
  							Alias *alias,
  							bool lateral,
  							bool inFromCl);
--- 85,93 ----
  							  bool inFromCl);
  extern RangeTblEntry *addRangeTableEntryForValues(ParseState *pstate,
  							List *exprs,
! 							List *coltypes,
! 							List *coltypmods,
! 							List *colcollations,
  							Alias *alias,
  							bool lateral,
  							bool inFromCl);
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index 66ed2c8..15ceefe 100644
*** a/src/test/regress/expected/create_view.out
--- b/src/test/regress/expected/create_view.out
*************** SELECT relname, relkind, reloptions FROM
*** 288,293 ****
--- 288,317 ----
   mysecview4 | v       | {security_barrier=false}
  (4 rows)
  
+ -- This test checks that proper typmods are assigned in a multi-row VALUES
+ CREATE TABLE tt1 AS
+   SELECT * FROM (
+     VALUES
+        ('abc'::varchar(3), '0123456789', 42, 'abcd'::varchar(4)),
+        ('0123456789', 'abc'::varchar(3), 42.12, 'abc'::varchar(4))
+   ) vv(a,b,c,d);
+ \d tt1
+                    Table "testviewschm2.tt1"
+  Column |         Type         | Collation | Nullable | Default 
+ --------+----------------------+-----------+----------+---------
+  a      | character varying    |           |          | 
+  b      | character varying    |           |          | 
+  c      | numeric              |           |          | 
+  d      | character varying(4) |           |          | 
+ 
+ SELECT * FROM tt1;
+      a      |     b      |   c   |  d   
+ ------------+------------+-------+------
+  abc        | 0123456789 |    42 | abcd
+  0123456789 | abc        | 42.12 | abc
+ (2 rows)
+ 
+ DROP TABLE tt1;
  -- Test view decompilation in the face of relation renaming conflicts
  CREATE TABLE tt1 (f1 int, f2 int, f3 text);
  CREATE TABLE tx1 (x1 int, x2 int, x3 text);
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 8bed5a5..c3391f9 100644
*** a/src/test/regress/sql/create_view.sql
--- b/src/test/regress/sql/create_view.sql
*************** SELECT relname, relkind, reloptions FROM
*** 224,229 ****
--- 224,241 ----
                       'mysecview3'::regclass, 'mysecview4'::regclass)
         ORDER BY relname;
  
+ -- This test checks that proper typmods are assigned in a multi-row VALUES
+ 
+ CREATE TABLE tt1 AS
+   SELECT * FROM (
+     VALUES
+        ('abc'::varchar(3), '0123456789', 42, 'abcd'::varchar(4)),
+        ('0123456789', 'abc'::varchar(3), 42.12, 'abc'::varchar(4))
+   ) vv(a,b,c,d);
+ \d tt1
+ SELECT * FROM tt1;
+ DROP TABLE tt1;
+ 
  -- Test view decompilation in the face of relation renaming conflicts
  
  CREATE TABLE tt1 (f1 int, f2 int, f3 text);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to