Skip to content

opt: support INSERT ON CONFLICT DO UPDATE and unique partial indexes#53171

Merged
craig[bot] merged 1 commit into
cockroachdb:masterfrom
mgartner:do-update-partial-index
Aug 25, 2020
Merged

opt: support INSERT ON CONFLICT DO UPDATE and unique partial indexes#53171
craig[bot] merged 1 commit into
cockroachdb:masterfrom
mgartner:do-update-partial-index

Conversation

@mgartner

Copy link
Copy Markdown
Contributor

This commit adds support for INSERT ON CONFLICT DO UPDATE statements
on tables with unique partial indexes. In order to use a unique partial
index as an arbiter, a WHERE clause must be provided that implies the
partial index's predicate expression. For example:

CREATE TABLE t (a INT, b INT, UNIQUE INDEX (a) WHERE b > 0)

INSERT INTO t VALUES (1, 1)
  ON CONFLICT (a) WHERE b > 0
  DO UPDATE SET b = 10

In the event that multiple arbiter indexes are found, an error is
returned to the user. Postgres supports multiple arbiters, but this is
left as a TODO for now, until there a strong enough motivation to
justify the added complexity.

Similar to the previous commit that added support for INSERT ON CONFLICT DO NOTHING for unique partial indexes, there are three primary
changes to the expression tree build by optbuilder:

  1. Fetched rows are filtered by the partial index predicate.

  2. Only insert rows that satisfy the partial index predicate are
    joined with fetched rows in the left outer join.

  3. A new column is projected so that the EnsureUpsertDistinctOn
    expression only errors when rows that satisfy the partial index
    predicate conflict with each other.

Fixes #52603

Release note: None

@mgartner mgartner requested a review from a team as a code owner August 20, 2020 23:55
@cockroach-teamcity

Copy link
Copy Markdown
Member

This change is Reviewable

@mgartner

Copy link
Copy Markdown
Contributor Author

The first commit is from #53067.

Comment thread pkg/sql/opt/optbuilder/testdata/upsert Outdated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The canary column is changing because of this change in optbuilder/insert.go:

- canaryScopeCol := &fetchScope.cols[findNotNullIndexCol(mb.tab.Index(cat.PrimaryIndex))]
+ canaryScopeCol := &fetchScope.cols[findNotNullIndexCol(index)]

The changes in these tests looks fine — a different not-null column is found. In this case, instead of the primary key, its the indexed non-null column a. I don't think this should not affect the results or performance of the UPSERT in any way.

@rytaft rytaft left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 14 of 14 files at r1, 2 of 3 files at r2, 3 of 3 files at r3.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained

This commit adds support for `INSERT ON CONFLICT DO UPDATE` statements
on tables with unique partial indexes. In order to use a unique partial
index as an arbiter, a `WHERE` clause must be provided that implies the
partial index's predicate expression. For example:

    CREATE TABLE t (a INT, b INT, UNIQUE INDEX (a) WHERE b > 0)

    INSERT INTO t VALUES (1, 1)
      ON CONFLICT (a) WHERE b > 0
      DO UPDATE SET b = 10

In the event that multiple arbiter indexes are found, an error is
returned to the user. Postgres supports multiple arbiters, but this is
left as a TODO for now, until there a strong enough motivation to
justify the added complexity.

Similar to the previous commit that added support for `INSERT ON
CONFLICT DO NOTHING` for unique partial indexes, there are three primary
changes to the expression tree build by `optbuilder`:

  1. Fetched rows are filtered by the partial index predicate.

  2. Only insert rows that satisfy the partial index predicate are
  joined with fetched rows in the left outer join.

  3. A new column is projected so that the `EnsureUpsertDistinctOn`
  expression only errors when rows that satisfy the partial index
  predicate conflict with each other.

Release note: None
@mgartner mgartner force-pushed the do-update-partial-index branch from d1be69f to 6364f27 Compare August 25, 2020 10:35
@mgartner

Copy link
Copy Markdown
Contributor Author

bors r=rytaft

@mgartner

Copy link
Copy Markdown
Contributor Author

TFTR @rytaft!

@craig

craig Bot commented Aug 25, 2020

Copy link
Copy Markdown
Contributor

Build succeeded:

@craig craig Bot merged commit 84f1959 into cockroachdb:master Aug 25, 2020
@mgartner mgartner deleted the do-update-partial-index branch August 25, 2020 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sql: unique partial indexes do not work correctly with INSERT ON CONFLICT

3 participants