aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/catalog/dependency.c9
-rw-r--r--src/backend/optimizer/plan/planner.c17
-rw-r--r--src/backend/optimizer/plan/subselect.c1
-rw-r--r--src/backend/optimizer/prep/prepjointree.c26
-rw-r--r--src/backend/optimizer/util/plancat.c9
-rw-r--r--src/backend/utils/adt/ruleutils.c7
-rw-r--r--src/test/regress/expected/insert_conflict.out15
-rw-r--r--src/test/regress/sql/insert_conflict.sql22
8 files changed, 94 insertions, 12 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index efca34c66d7..4539c1828ee 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1777,6 +1777,15 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_TYPE, cd->resulttype, 0,
context->addrs);
}
+ else if (IsA(node, OnConflictExpr))
+ {
+ OnConflictExpr *onconflict = (OnConflictExpr *) node;
+
+ if (OidIsValid(onconflict->constraint))
+ add_object_address(OCLASS_CONSTRAINT, onconflict->constraint, 0,
+ context->addrs);
+ /* fall through to examine arguments */
+ }
else if (IsA(node, SortGroupClause))
{
SortGroupClause *sgc = (SortGroupClause *) node;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 1fb74ccc15f..fcb57bf411b 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -65,6 +65,7 @@ planner_hook_type planner_hook = NULL;
#define EXPRKIND_APPINFO 7
#define EXPRKIND_PHV 8
#define EXPRKIND_TABLESAMPLE 9
+#define EXPRKIND_ARBITER_ELEM 10
/* Passthrough data for standard_qp_callback */
typedef struct
@@ -483,13 +484,23 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
if (parse->onConflict)
{
+ parse->onConflict->arbiterElems = (List *)
+ preprocess_expression(root,
+ (Node *) parse->onConflict->arbiterElems,
+ EXPRKIND_ARBITER_ELEM);
+ parse->onConflict->arbiterWhere =
+ preprocess_expression(root,
+ parse->onConflict->arbiterWhere,
+ EXPRKIND_QUAL);
parse->onConflict->onConflictSet = (List *)
- preprocess_expression(root, (Node *) parse->onConflict->onConflictSet,
+ preprocess_expression(root,
+ (Node *) parse->onConflict->onConflictSet,
EXPRKIND_TARGET);
-
parse->onConflict->onConflictWhere =
- preprocess_expression(root, (Node *) parse->onConflict->onConflictWhere,
+ preprocess_expression(root,
+ parse->onConflict->onConflictWhere,
EXPRKIND_QUAL);
+ /* exclRelTlist contains only Vars, so no preprocessing needed */
}
root->append_rel_list = (List *)
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 00fb6376d97..979802f70d5 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -2426,6 +2426,7 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
&context);
finalize_primnode((Node *) mtplan->onConflictWhere,
&context);
+ /* exclRelTlist contains only Vars, doesn't need examination */
foreach(l, mtplan->plans)
{
context.paramids =
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 39cce846024..55fc04d2864 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -1031,8 +1031,19 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
parse->returningList = (List *)
pullup_replace_vars((Node *) parse->returningList, &rvcontext);
if (parse->onConflict)
+ {
parse->onConflict->onConflictSet = (List *)
- pullup_replace_vars((Node *) parse->onConflict->onConflictSet, &rvcontext);
+ pullup_replace_vars((Node *) parse->onConflict->onConflictSet,
+ &rvcontext);
+ parse->onConflict->onConflictWhere =
+ pullup_replace_vars(parse->onConflict->onConflictWhere,
+ &rvcontext);
+
+ /*
+ * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
+ * can't contain any references to a subquery
+ */
+ }
replace_vars_in_jointree((Node *) parse->jointree, &rvcontext,
lowest_nulling_outer_join);
Assert(parse->setOperations == NULL);
@@ -1625,8 +1636,19 @@ pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
parse->returningList = (List *)
pullup_replace_vars((Node *) parse->returningList, &rvcontext);
if (parse->onConflict)
+ {
parse->onConflict->onConflictSet = (List *)
- pullup_replace_vars((Node *) parse->onConflict->onConflictSet, &rvcontext);
+ pullup_replace_vars((Node *) parse->onConflict->onConflictSet,
+ &rvcontext);
+ parse->onConflict->onConflictWhere =
+ pullup_replace_vars(parse->onConflict->onConflictWhere,
+ &rvcontext);
+
+ /*
+ * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
+ * can't contain any references to a subquery
+ */
+ }
replace_vars_in_jointree((Node *) parse->jointree, &rvcontext, NULL);
Assert(parse->setOperations == NULL);
parse->havingQual = pullup_replace_vars(parse->havingQual, &rvcontext);
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 9442e5fa32b..0d6a1313a08 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -530,7 +530,6 @@ infer_arbiter_indexes(PlannerInfo *root)
Bitmapset *indexedAttrs = NULL;
List *idxExprs;
List *predExprs;
- List *whereExplicit;
AttrNumber natt;
ListCell *el;
@@ -592,6 +591,7 @@ infer_arbiter_indexes(PlannerInfo *root)
{
int attno = idxRel->rd_index->indkey.values[natt];
+ /* XXX broken */
if (attno < 0)
elog(ERROR, "system column in index");
@@ -652,13 +652,12 @@ infer_arbiter_indexes(PlannerInfo *root)
goto next;
/*
- * Any user-supplied ON CONFLICT unique index inference WHERE clause
- * need only be implied by the cataloged index definitions predicate.
+ * If it's a partial index, its predicate must be implied by the ON
+ * CONFLICT's WHERE clause.
*/
predExprs = RelationGetIndexPredicate(idxRel);
- whereExplicit = make_ands_implicit((Expr *) onconflict->arbiterWhere);
- if (!predicate_implied_by(predExprs, whereExplicit))
+ if (!predicate_implied_by(predExprs, (List *) onconflict->arbiterWhere))
goto next;
results = lappend_oid(results, idxForm->indexrelid);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 09053d1041d..922e1733b94 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -5543,12 +5543,15 @@ get_insert_query_def(Query *query, deparse_context *context)
context->varprefix = save_varprefix;
}
}
- else if (confl->constraint != InvalidOid)
+ else if (OidIsValid(confl->constraint))
{
char *constraint = get_constraint_name(confl->constraint);
+ if (!constraint)
+ elog(ERROR, "cache lookup failed for constraint %u",
+ confl->constraint);
appendStringInfo(buf, " ON CONSTRAINT %s",
- quote_qualified_identifier(NULL, constraint));
+ quote_identifier(constraint));
}
if (confl->action == ONCONFLICT_NOTHING)
diff --git a/src/test/regress/expected/insert_conflict.out b/src/test/regress/expected/insert_conflict.out
index f56cbd642de..e5c8b4aaacb 100644
--- a/src/test/regress/expected/insert_conflict.out
+++ b/src/test/regress/expected/insert_conflict.out
@@ -454,6 +454,21 @@ ERROR: column excluded.oid does not exist
LINE 1: ...values (1) on conflict (key) do update set data = excluded.o...
^
drop table syscolconflicttest;
+--
+-- Previous tests all managed to not test any expressions requiring
+-- planner preprocessing ...
+--
+create table insertconflict (a bigint, b bigint);
+create unique index insertconflicti1 on insertconflict(coalesce(a, 0));
+create unique index insertconflicti2 on insertconflict(b)
+ where coalesce(a, 1) > 0;
+insert into insertconflict values (1, 2)
+on conflict (coalesce(a, 0)) do nothing;
+insert into insertconflict values (1, 2)
+on conflict (b) where coalesce(a, 1) > 0 do nothing;
+insert into insertconflict values (1, 2)
+on conflict (b) where coalesce(a, 1) > 1 do nothing;
+drop table insertconflict;
-- ******************************************************************
-- * *
-- * Test inheritance (example taken from tutorial) *
diff --git a/src/test/regress/sql/insert_conflict.sql b/src/test/regress/sql/insert_conflict.sql
index 8d846f51df4..94b1b0aadee 100644
--- a/src/test/regress/sql/insert_conflict.sql
+++ b/src/test/regress/sql/insert_conflict.sql
@@ -261,6 +261,28 @@ insert into syscolconflicttest values (1) on conflict (key) do update set data =
insert into syscolconflicttest values (1) on conflict (key) do update set data = excluded.oid::text;
drop table syscolconflicttest;
+--
+-- Previous tests all managed to not test any expressions requiring
+-- planner preprocessing ...
+--
+create table insertconflict (a bigint, b bigint);
+
+create unique index insertconflicti1 on insertconflict(coalesce(a, 0));
+
+create unique index insertconflicti2 on insertconflict(b)
+ where coalesce(a, 1) > 0;
+
+insert into insertconflict values (1, 2)
+on conflict (coalesce(a, 0)) do nothing;
+
+insert into insertconflict values (1, 2)
+on conflict (b) where coalesce(a, 1) > 0 do nothing;
+
+insert into insertconflict values (1, 2)
+on conflict (b) where coalesce(a, 1) > 1 do nothing;
+
+drop table insertconflict;
+
-- ******************************************************************
-- * *