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 a6180a64f21..04d78402903 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1789,6 +1789,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 6770836dc89..75d93c08db2 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -77,6 +77,7 @@ create_upper_paths_hook_type create_upper_paths_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
@@ -620,13 +621,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 1ff430229dd..0849b1d5634 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -2507,6 +2507,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 75577bce2ca..a334f15773a 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -1039,8 +1039,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);
@@ -1633,8 +1644,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 9c11b09cbcc..4f399a5b854 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -623,7 +623,6 @@ infer_arbiter_indexes(PlannerInfo *root)
Bitmapset *indexedAttrs = NULL;
List *idxExprs;
List *predExprs;
- List *whereExplicit;
AttrNumber natt;
ListCell *el;
@@ -685,6 +684,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");
@@ -745,13 +745,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 6dfa6b9a319..8cb3075e785 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -5570,12 +5570,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;
+
-- ******************************************************************
-- * *