Re: Typmod associated with multi-row VALUES constructs - Mailing list pgsql-hackers
From | Tom Lane |
---|---|
Subject | Re: Typmod associated with multi-row VALUES constructs |
Date | |
Msg-id | 15128.1481172259@sss.pgh.pa.us Whole thread Raw |
In response to | Re: Typmod associated with multi-row VALUES constructs ("David G. Johnston" <david.g.johnston@gmail.com>) |
Responses |
Re: Typmod associated with multi-row VALUES constructs
|
List | pgsql-hackers |
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);
pgsql-hackers by date: