aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/copyfuncs.c7
-rw-r--r--src/backend/nodes/equalfuncs.c7
-rw-r--r--src/backend/nodes/outfuncs.c10
-rw-r--r--src/backend/nodes/readfuncs.c10
-rw-r--r--src/backend/optimizer/plan/setrefs.c7
-rw-r--r--src/backend/parser/analyze.c54
-rw-r--r--src/backend/parser/parse_relation.c94
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/nodes/parsenodes.h15
-rw-r--r--src/include/parser/parse_relation.h4
-rw-r--r--src/test/regress/expected/create_view.out37
-rw-r--r--src/test/regress/sql/create_view.sql13
12 files changed, 151 insertions, 109 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e30c57e86be..d9732259ae8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2149,13 +2149,12 @@ _copyRangeTblEntry(const RangeTblEntry *from)
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(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 b7a109cfb04..edc1797c424 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2460,13 +2460,12 @@ _equalRangeTblEntry(const RangeTblEntry *a, const RangeTblEntry *b)
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(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 0d858f59206..7258c0357db 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2841,15 +2841,17 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
break;
case RTE_VALUES:
WRITE_NODE_FIELD(values_lists);
- WRITE_NODE_FIELD(values_collations);
+ 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(ctecoltypes);
- WRITE_NODE_FIELD(ctecoltypmods);
- WRITE_NODE_FIELD(ctecolcollations);
+ 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 c587d4e1d72..d608530c6e2 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1314,15 +1314,17 @@ _readRangeTblEntry(void)
break;
case RTE_VALUES:
READ_NODE_FIELD(values_lists);
- READ_NODE_FIELD(values_collations);
+ 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(ctecoltypes);
- READ_NODE_FIELD(ctecoltypmods);
- READ_NODE_FIELD(ctecolcollations);
+ 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 d91bc3b30de..2fe1c8cb9d0 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -396,10 +396,9 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
newrte->joinaliasvars = NIL;
newrte->functions = NIL;
newrte->values_lists = NIL;
- newrte->values_collations = NIL;
- newrte->ctecoltypes = NIL;
- newrte->ctecoltypmods = NIL;
- newrte->ctecolcollations = 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 73643461672..5e65fe75bd5 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -633,10 +633,11 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
* RTE.
*/
List *exprsLists = NIL;
- List *collations = NIL;
+ List *coltypes = NIL;
+ List *coltypmods = NIL;
+ List *colcollations = NIL;
int sublist_length = -1;
bool lateral = false;
- int i;
Assert(selectStmt->intoClause == NULL);
@@ -703,11 +704,20 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
}
/*
- * Although we don't really need collation info, let's just make sure
- * we provide a correctly-sized list in the VALUES RTE.
+ * 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.
*/
- for (i = 0; i < sublist_length; i++)
- collations = lappend_oid(collations, InvalidOid);
+ 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
@@ -722,7 +732,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
/*
* Generate the VALUES RTE
*/
- rte = addRangeTableEntryForValues(pstate, exprsLists, collations,
+ rte = addRangeTableEntryForValues(pstate, exprsLists,
+ coltypes, coltypmods, colcollations,
NULL, lateral, true);
rtr = makeNode(RangeTblRef);
/* assume new rte is at end */
@@ -1274,7 +1285,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
{
Query *qry = makeNode(Query);
List *exprsLists;
- List *collations;
+ List *coltypes = NIL;
+ List *coltypmods = NIL;
+ List *colcollations = NIL;
List **colexprs = NULL;
int sublist_length = -1;
bool lateral = false;
@@ -1360,8 +1373,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
/*
* Now resolve the common types of the columns, and coerce everything to
- * those types. Then identify the common collation, if any, of each
- * column.
+ * 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
@@ -1372,11 +1385,12 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
*
* Note we modify the per-column expression lists in-place.
*/
- collations = NIL;
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);
@@ -1386,11 +1400,24 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
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);
- collations = lappend_oid(collations, colcoll);
+ coltypes = lappend_oid(coltypes, coltype);
+ coltypmods = lappend_int(coltypmods, coltypmod);
+ colcollations = lappend_oid(colcollations, colcoll);
}
/*
@@ -1432,7 +1459,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
/*
* Generate the VALUES RTE
*/
- rte = addRangeTableEntryForValues(pstate, exprsLists, collations,
+ 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 1e3ecbc51ef..58f70508fea 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1635,7 +1635,9 @@ addRangeTableEntryForFunction(ParseState *pstate,
RangeTblEntry *
addRangeTableEntryForValues(ParseState *pstate,
List *exprs,
- List *collations,
+ List *coltypes,
+ List *coltypmods,
+ List *colcollations,
Alias *alias,
bool lateral,
bool inFromCl)
@@ -1652,7 +1654,9 @@ addRangeTableEntryForValues(ParseState *pstate,
rte->relid = InvalidOid;
rte->subquery = NULL;
rte->values_lists = exprs;
- rte->values_collations = collations;
+ rte->coltypes = coltypes;
+ rte->coltypmods = coltypmods;
+ rte->colcollations = colcollations;
rte->alias = alias;
eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
@@ -1822,9 +1826,9 @@ addRangeTableEntryForCTE(ParseState *pstate,
parser_errposition(pstate, rv->location)));
}
- rte->ctecoltypes = cte->ctecoltypes;
- rte->ctecoltypmods = cte->ctecoltypmods;
- rte->ctecolcollations = cte->ctecolcollations;
+ rte->coltypes = cte->ctecoltypes;
+ rte->coltypmods = cte->ctecoltypmods;
+ rte->colcollations = cte->ctecolcollations;
rte->alias = alias;
if (alias)
@@ -2153,46 +2157,6 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
}
}
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 */
@@ -2262,17 +2226,19 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
}
}
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->ctecoltypes,
- lcm, rte->ctecoltypmods,
- lcc, rte->ctecolcollations)
+ forthree(lct, rte->coltypes,
+ lcm, rte->coltypmods,
+ lcc, rte->colcollations)
{
Oid coltype = lfirst_oid(lct);
int32 coltypmod = lfirst_int(lcm);
@@ -2285,7 +2251,8 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
/* Assume there is one alias per output column */
char *label = strVal(lfirst(aliasp_item));
- *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ *colnames = lappend(*colnames,
+ makeString(pstrdup(label)));
aliasp_item = lnext(aliasp_item);
}
@@ -2296,6 +2263,8 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
varnode = makeVar(rtindex, varattno,
coltype, coltypmod, colcoll,
sublevels_up);
+ varnode->location = location;
+
*colvars = lappend(*colvars, varnode);
}
}
@@ -2654,22 +2623,6 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
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:
{
/*
@@ -2685,13 +2638,14 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
*varcollid = exprCollation(aliasvar);
}
break;
+ case RTE_VALUES:
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);
+ /* 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/catalog/catversion.h b/src/include/catalog/catversion.h
index a602ba38616..cfe01f19ac1 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201612071
+#define CATALOG_VERSION_NO 201612081
#endif
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 6b95c484476..fc532fbd432 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -927,7 +927,6 @@ typedef struct RangeTblEntry
* 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):
@@ -935,9 +934,17 @@ typedef struct RangeTblEntry
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 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 3ef3d7bae5b..9463f9d7757 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -85,7 +85,9 @@ extern RangeTblEntry *addRangeTableEntryForFunction(ParseState *pstate,
bool inFromCl);
extern RangeTblEntry *addRangeTableEntryForValues(ParseState *pstate,
List *exprs,
- List *collations,
+ 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 66ed2c8a3e8..096bfc30c9e 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -288,6 +288,43 @@ SELECT relname, relkind, reloptions FROM pg_class
mysecview4 | v | {security_barrier=false}
(4 rows)
+-- This test checks that proper typmods are assigned in a multi-row VALUES
+CREATE VIEW 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
+ View "testviewschm2.tt1"
+ Column | Type | Collation | Nullable | Default | Storage | Description
+--------+----------------------+-----------+----------+---------+----------+-------------
+ a | character varying | | | | extended |
+ b | character varying | | | | extended |
+ c | numeric | | | | main |
+ d | character varying(4) | | | | extended |
+View definition:
+ SELECT vv.a,
+ vv.b,
+ vv.c,
+ vv.d
+ FROM ( VALUES ('abc'::character varying(3),'0123456789'::character varying,42,'abcd'::character varying(4)), ('0123456789'::character varying,'abc'::character varying(3),42.12,'abc'::character varying(4))) vv(a, b, c, d);
+
+SELECT * FROM tt1;
+ a | b | c | d
+------------+------------+-------+------
+ abc | 0123456789 | 42 | abcd
+ 0123456789 | abc | 42.12 | abc
+(2 rows)
+
+SELECT a::varchar(3) FROM tt1;
+ a
+-----
+ abc
+ 012
+(2 rows)
+
+DROP VIEW 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 8bed5a53b3a..5fe8b94aae0 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -224,6 +224,19 @@ SELECT relname, relkind, reloptions FROM pg_class
'mysecview3'::regclass, 'mysecview4'::regclass)
ORDER BY relname;
+-- This test checks that proper typmods are assigned in a multi-row VALUES
+
+CREATE VIEW 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;
+SELECT a::varchar(3) FROM tt1;
+DROP VIEW tt1;
+
-- Test view decompilation in the face of relation renaming conflicts
CREATE TABLE tt1 (f1 int, f2 int, f3 text);