Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support unless conflict on on multi pointers #4907

Closed
msullivan opened this issue Jan 20, 2023 · 1 comment · Fixed by #4955
Closed

Support unless conflict on on multi pointers #4907

msullivan opened this issue Jan 20, 2023 · 1 comment · Fixed by #4955

Comments

@msullivan
Copy link
Member

I think it wasn't originally implemented because it couldn't just be done using ON CONFLICT.
But it turned out that a ton of stuff couldn't be implemented with just ON CONFLICT,
and so we now have the "conflict CTE" mechanism that allows us to do unless conflict
style behavior in very flexible ways.

I think to make this work all we need to do is:

  • Remove the error
  • Make sure that we always use conflict CTEs if any of the pointers are multi

Looking at this I found an existing bug when there is an exclusive multi pointer and UNLESS CONFLICT with no ON is specified: the query is allowed, but can spuriously raise a constraint violation, because it does not properly choose to use conflict CTEs. But if some modification to the query is made that forces the use of conflict CTEs (such as another insert to the same type), then it works properly!

@msullivan
Copy link
Member Author

This one will probably get fixed very soon (especially since it has a clear bug attached), but in the mean time, here is my general workaround for cases where you wish to use unless conflict but cannot:

with
    old := (select Foo filter <whatever>),
    new := (for _ in (select () filter not exists old) union (
        insert Foo { <whatever> }
    )),
select {old, new}

The select for old can also be an update.

The idea here is that you aren't allowed to do DML (insert/update/delete) inside of a conditional (an if/else), but you can do them inside of a for loop, so we write a for loop that executes exactly once if the object does not exist and zero times otherwise.

(DML is not allowed in conditionals because there were concerns about both what the semantics should be and whether it was implementable, but the observation that if/else can be translated into for loops provides a resolution to both of those questions, so we probably will start allowing it: #4437)

@msullivan msullivan self-assigned this Jan 30, 2023
msullivan added a commit that referenced this issue Jan 31, 2023
And fix a bug where we could spuriously still raise an exception
when using a bare UNLESS CONFLICT on a multi property conflict.

Fixes #4907.
msullivan added a commit that referenced this issue Jan 31, 2023
And fix a bug where we could spuriously still raise an exception
when using a bare UNLESS CONFLICT on a multi property conflict.

Fixes #4907.
msullivan added a commit that referenced this issue Feb 9, 2023
And fix a bug where we could spuriously still raise an exception
when using a bare UNLESS CONFLICT on a multi property conflict.

Fixes #4907.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant