summaryrefslogtreecommitdiffstats
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c19
-rw-r--r--src/backend/parser/parse_merge.c7
-rw-r--r--src/backend/parser/parse_relation.c19
-rw-r--r--src/backend/parser/parse_target.c18
-rw-r--r--src/backend/parser/parse_utilcmd.c11
5 files changed, 61 insertions, 13 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index eaa0bce..f992646 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1063,17 +1063,28 @@ transformInsertRow(ParseState *pstate, List *exprlist,
if (strip_indirection)
{
+ /*
+ * We need to remove top-level FieldStores and SubscriptingRefs,
+ * as well as any CoerceToDomain appearing above one of those ---
+ * but not a CoerceToDomain that isn't above one of those.
+ */
while (expr)
{
- if (IsA(expr, FieldStore))
+ Expr *subexpr = expr;
+
+ while (IsA(subexpr, CoerceToDomain))
+ {
+ subexpr = ((CoerceToDomain *) subexpr)->arg;
+ }
+ if (IsA(subexpr, FieldStore))
{
- FieldStore *fstore = (FieldStore *) expr;
+ FieldStore *fstore = (FieldStore *) subexpr;
expr = (Expr *) linitial(fstore->newvals);
}
- else if (IsA(expr, SubscriptingRef))
+ else if (IsA(subexpr, SubscriptingRef))
{
- SubscriptingRef *sbsref = (SubscriptingRef *) expr;
+ SubscriptingRef *sbsref = (SubscriptingRef *) subexpr;
if (sbsref->refassgnexpr == NULL)
break;
diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c
index e8865bf..de4825b 100644
--- a/src/backend/parser/parse_merge.c
+++ b/src/backend/parser/parse_merge.c
@@ -133,7 +133,11 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
int when_type = (mergeWhenClause->matched ? 0 : 1);
/*
- * Collect action types so we can check target permissions
+ * Collect permissions to check, according to action types. We require
+ * SELECT privileges for DO NOTHING because it'd be irregular to have
+ * a target relation with zero privileges checked, in case DO NOTHING
+ * is the only action. There's no damage from that: any meaningful
+ * MERGE command requires at least some access to the table anyway.
*/
switch (mergeWhenClause->commandType)
{
@@ -147,6 +151,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
targetPerms |= ACL_DELETE;
break;
case CMD_NOTHING:
+ targetPerms |= ACL_SELECT;
break;
default:
elog(ERROR, "unknown action in MERGE WHEN clause");
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 863c25f..e006683 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -2722,12 +2722,17 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
{
RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
TypeFuncClass functypclass;
- Oid funcrettype;
- TupleDesc tupdesc;
+ Oid funcrettype = InvalidOid;
+ TupleDesc tupdesc = NULL;
+
+ /* If it has a coldeflist, it returns RECORD */
+ if (rtfunc->funccolnames != NIL)
+ functypclass = TYPEFUNC_RECORD;
+ else
+ functypclass = get_expr_result_type(rtfunc->funcexpr,
+ &funcrettype,
+ &tupdesc);
- functypclass = get_expr_result_type(rtfunc->funcexpr,
- &funcrettype,
- &tupdesc);
if (functypclass == TYPEFUNC_COMPOSITE ||
functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
{
@@ -3345,6 +3350,10 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
{
TupleDesc tupdesc;
+ /* If it has a coldeflist, it returns RECORD */
+ if (rtfunc->funccolnames != NIL)
+ return false; /* can't have any dropped columns */
+
tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr,
true);
if (tupdesc)
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index bff3003..4d6d88c 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -828,7 +828,16 @@ transformAssignmentIndirection(ParseState *pstate,
fstore->fieldnums = list_make1_int(attnum);
fstore->resulttype = baseTypeId;
- /* If target is a domain, apply constraints */
+ /*
+ * If target is a domain, apply constraints. Notice that this
+ * isn't totally right: the expression tree we build would check
+ * the domain's constraints on a composite value with only this
+ * one field populated or updated, possibly leading to an unwanted
+ * failure. The rewriter will merge together any subfield
+ * assignments to the same table column, resulting in the domain's
+ * constraints being checked only once after we've assigned to all
+ * the fields that the INSERT or UPDATE means to.
+ */
if (baseTypeId != targetTypeId)
return coerce_to_domain((Node *) fstore,
baseTypeId, baseTypeMod,
@@ -976,7 +985,12 @@ transformAssignmentSubscripts(ParseState *pstate,
result = (Node *) sbsref;
- /* If target was a domain over container, need to coerce up to the domain */
+ /*
+ * If target was a domain over container, need to coerce up to the domain.
+ * As in transformAssignmentIndirection, this coercion is premature if the
+ * query assigns to multiple elements of the container; but we'll fix that
+ * during query rewrite.
+ */
if (containerType != targetTypeId)
{
Oid resulttype = exprType(result);
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index b8dda03..5a06136 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -456,7 +456,16 @@ generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
seqstmt = makeNode(CreateSeqStmt);
seqstmt->for_identity = for_identity;
seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
- seqstmt->sequence->relpersistence = cxt->relation->relpersistence;
+
+ /*
+ * Copy the persistence of the table. For CREATE TABLE, we get the
+ * persistence from cxt->relation, which comes from the CreateStmt in
+ * progress. For ALTER TABLE, the parser won't set
+ * cxt->relation->relpersistence, but we have cxt->rel as the existing
+ * table, so we copy the persistence from there.
+ */
+ seqstmt->sequence->relpersistence = cxt->rel ? cxt->rel->rd_rel->relpersistence : cxt->relation->relpersistence;
+
seqstmt->options = seqoptions;
/*