On 03/05/2015 03:18 AM, Peter Geoghegan wrote:
Attached patch series forms what I'm calling V3.0 of the INSERT ... ON
CONFLICT IGNORE/UPDATE feature. (Sorry about all the threads. I feel
this development justifies a new thread, though.)

I'm still not sure the way the speculative locking works is the best approach. Instead of clearing xmin on super-deletion, a new flag on the heap tuple seems more straightforward. And we could put the speculative insertion token in t_ctid, instead of stashing it in the PGPROC array. That would again seem more straightforward.

A couple of quick random comments:

/*
 * plan_speculative_use_index
 *              Use the planner to decide speculative insertion arbiter index
 *
 * Among indexes on target of INSERT ... ON CONFLICT, decide which index to
 * use to arbitrate taking alternative path.  This should be called
 * infrequently in practice, because it's unusual for more than one index to
 * be available that can satisfy a user-specified unique index inference
 * specification.
 *
 * Note: caller had better already hold some type of lock on the table.
 */
Oid
plan_speculative_use_index(PlannerInfo *root, List *indexList)
{
        ...
        /* Locate cheapest IndexOptInfo for the target index */

If I'm reading this correctly, if there are multiple indexes that match the unique index inference specification, we pick the cheapest one. Isn't that unstable? Two backends running the same INSERT ON CONFLICT statement might pick different indexes, and the decision might change over time as the table is analyzed. I think we should have a more robust rule. Could we easily just use all matching indexes?


... Deferred unique constraints are not supported as
+   arbiters of whether an alternative <literal>ON CONFLICT</> path
+   should be taken.

We really need to find a shorter term for "arbiter of whether an alternative path should be taken". Different variations of that term are used a lot, and it's tedious to read.

* There is still an unresolved semantics issue with unique index
inference and non-default opclasses. I think it's sufficient that the
available/defined unique indexes dictate our idea of a unique
violation (that necessitates taking the alternative path). Even in a
world where there exists a non-default opclass with an "equals"
operator that does not match that of the default opclass (that is not
really the world we live in, because the only counter-example known is
made that way specifically to *discourage* its use by users), this
seems okay to me. It seems okay to me because surely the relevant
definition of equality is the one actually chosen for the available
unique index. If there exists an ambiguity for some strange reason
(i.e. there are two unique indexes, on the same attribute(s), but with
different "equals" operators), then its a costing issue, so the
behavior given is essentially non-predictable (it could end up being
either...but hey, those are the semantics). I have a very hard time
imagining how that could ever be the case, even when we have (say)
case insensitive opclasses for the text type. A case insensitive
opclass is stricter than a case sensitive opclass.  Why would a user
ever want both on the same attribute(s) of the same table? Is the user
really more or less expecting to never get a unique violation on the
non-arbitrating unique index, despite all this?

If reviewers are absolutely insistent that this theoretical ambiguity
is a problem, we can add an optional CREATE INDEX style opclass
specification (I'm already using the IndexElems representation from
CREATE INDEX for the inference specification, actually, so that would
be easy enough). I really have a hard time believing that the ugliness
is a problem for those hypothetical users that eventually consider
"equals" operator ambiguity among opclasses among available unique
indexes to be a problem. I haven't just gone and implemented this
already because I didn't want to document that an opclass
specification will be accepted. Since there is literally no reason why
anyone would care today, I see no reason to add what IMV would really
just be cruft.

I've been thinking that it would be nice to be able to specify a constraint name. Naming an index directly feels wrong, as in relational and SQL philosophy, indexes are just an implementation detail, but naming a constraint is a fair game. It would also be nice to be able to specify "use the primary key".

Attached patch contains a few more things I saw at a quick read.

- Heikki

diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml
index 46b8db8..d6fa98c 100644
--- a/doc/src/sgml/fdwhandler.sgml
+++ b/doc/src/sgml/fdwhandler.sgml
@@ -1014,6 +1014,10 @@ GetForeignServerByName(const char *name, bool missing_ok);
      source provides.
     </para>
 
+    <!-- FIXME: If this is a hard limitation with the backend, the backend
+         should check and reject these cases. Otherwise, if it's possible
+         that a FDW would actually support this, this needs to be reworded
+      -->
     <para>
      <command>INSERT</> with an <literal>ON CONFLICT</> clause is not
      supported with a unique index inference specification.  When
diff --git a/doc/src/sgml/ref/create_view.sgml b/doc/src/sgml/ref/create_view.sgml
index 2b68121..24fb4b7 100644
--- a/doc/src/sgml/ref/create_view.sgml
+++ b/doc/src/sgml/ref/create_view.sgml
@@ -385,6 +385,7 @@ CREATE VIEW vista AS SELECT text 'Hello World' AS hello;
     <xref linkend="rules-privileges">).
    </para>
    <para>
+    <!-- FIXME: This paragraph needs to reworded, to make it more readable. -->
     <command>INSERT</command> with an <literal>ON CONFLICT IGNORE</>
     clause is only supported on updatable views under specific
     circumstances.  If a set of columns/expressions has been provided
diff --git a/doc/src/sgml/ref/insert.sgml b/doc/src/sgml/ref/insert.sgml
index 1395c48..4f3878b 100644
--- a/doc/src/sgml/ref/insert.sgml
+++ b/doc/src/sgml/ref/insert.sgml
@@ -33,9 +33,12 @@ INSERT INTO <replaceable class="PARAMETER">table_name</replaceable> [ ( <replace
   <title>Description</title>
 
   <para>
-   <command>INSERT</command> inserts new rows into a table.  One can
-   insert one or more rows specified by value expressions, or zero or
-   more rows resulting from a query.  An alternative
+   <command>INSERT</command> inserts new rows into a table.
+   One can insert one or more rows specified by value expressions,
+   or zero or more rows resulting from a query.
+   <!-- FIXME: This needs to go somewhere later, not in the very first
+        introductory paragraph on INSERT in general -->
+   An alternative
    <literal>IGNORE</literal> path can optionally be specified, to be
    taken in the event of detecting that proceeding with insertion
    would result in a conflict (i.e. a conflicting tuple already
diff --git a/doc/src/sgml/ref/set_constraints.sgml b/doc/src/sgml/ref/set_constraints.sgml
index 5030f3c..b1e8f9b 100644
--- a/doc/src/sgml/ref/set_constraints.sgml
+++ b/doc/src/sgml/ref/set_constraints.sgml
@@ -69,7 +69,11 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ...
   <para>
    Currently, only <literal>UNIQUE</>, <literal>PRIMARY KEY</>,
    <literal>REFERENCES</> (foreign key), and <literal>EXCLUDE</>
-   constraints are affected by this setting.  Note that constraints
+   constraints are affected by this setting.
+   <!-- FIXME: I take that this is meant to say that DEFERRED constraints
+        cannot be used as arbiters. e.g.  SET CONSTRAINTS ALL IMMEDIATE is
+        OK. -->
+   Note that constraints
    that were created with this clause cannot be used as arbiters of
    whether or not to take the alternative path with an
    <command>INSERT</command> statement that includes an <literal>ON
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index ffe1d62..0dabd16 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -1548,6 +1548,7 @@ retry:
 			if (DirtySnapshot.speculativeToken)
 				SpeculativeInsertionWait(DirtySnapshot.xmin,
 										 DirtySnapshot.speculativeToken);
+			/* FIXME: both arms of this if do the same thing. Huh? */
 			else if (violationOK)
 				XactLockTableWait(xwait, heap, &ctid_wait,
 								  XLTW_RecheckExclusionConstr);
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 99c8d6a..d31db33 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -4118,10 +4118,10 @@ string_to_const(const char *str, Oid datatype)
  * plan_speculative_use_index
  *		Use the planner to decide speculative insertion arbiter index
  *
- * Among indexes on target of INSERT ... ON CONFLICT,  decide which index to
+ * Among indexes on target of INSERT ... ON CONFLICT, decide which index to
  * use to arbitrate taking alternative path.  This should be called
- * infrequently in practice, because its unusual for more than one index to be
- * available that can satisfy a user-specified unique index inference
+ * infrequently in practice, because it's unusual for more than one index to
+ * be available that can satisfy a user-specified unique index inference
  * specification.
  *
  * Note: caller had better already hold some type of lock on the table.
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to