question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Nested INSERT bug

See original GitHub issue
db> CREATE TYPE Foo {CREATE LINK bar -> Object};
CREATE
db> INSERT Foo {bar := (INSERT Foo)};
QueryError: invalid reference to default::Foo: self-referencing INSERTs are not allowed
Hint: Use DETACHED if you meant to refer to an uncorrelated default::Foo set
### INSERT Foo {bar := (INSERT Foo)};
###

This looks like a bug to me. I was under the impression that the thing right after INSERT is supposed to be a type name, not an arbitrary expression, as such there cannot be a problem of self-reference. If memory serves me, we couldn’t actually guarantee that self-references in an INSERT would work (say for use in a subquery selecting some link based on other yet-to-be-inserted data that appears syntactically in the INSERT statement).

As far as I recall this is illegal:

INSERT Bar {
    a := 'data',
    b := .a
};

Am I misunderstanding INSERT?

Just to clarify, the intent is to simple create 2 Foo objects where one is linked to the other. This is not intended or expected to be some sort of self-link.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:12 (12 by maintainers)

github_iconTop GitHub Comments

1reaction
elpranscommented, Aug 25, 2021

After some discussion and poking around the realization about nested INSERT is that it does, in fact, obey the general binding rules through its UNLESS CONFLICT clause, which would get very complicated and inconsistent in nested scenarios:

INSERT Tree {
    val := 'i2',
    parent := (
        INSERT Tree {
            val := 'i1',
        } UNLESS CONFLICT ELSE Tree
    ),
} UNLESS CONFLICT ELSE Tree;

Intuitively, the nested ELSE Tree should bind to the nearest INSERT and not to the outer INSERT, but this is inconsistent with the general binding rules of EdgeQL. Thus, I’m reaffirming our position that INSERT isn’t different from other statements in terms of the binding rules.

A possible long-term solution to this problem would be type aliases as in #1578:

WITH ParentTree AS TYPE Tree
INSERT Tree {
    val := 'i2',
    parent := (
        INSERT ParentTree {
            val := 'i1',
        } UNLESS CONFLICT ELSE SELECT ParentTree
    ),
} UNLESS CONFLICT ELSE SELECT Tree;

However, that hinges on a new syntax that isn’t yet implemented, so for now the official recommendation on how to handle simultaneous insertion into a recursive type is to move the nested INSERT statements into a WITH block, as is the general recommendation where recursive types are concerned:

WITH
  parent := (
    INSERT Tree {
      val := 'i1',
    } UNLESS CONFLICT ON .val ELSE (SELECT Tree)
  )
INSERT Tree {
  val := 'i2',
  parent := parent
}
UNLESS CONFLICT ON .val ELSE (SELECT Tree);
0reactions
elpranscommented, Aug 24, 2021

I’m reopening this for reconsideration, since there is currently no clean way of INSERT-ing self-referencing objects. To improve the situation we have two options:

  1. Allow INSERT Foo {bar := (INSERT Foo)}; without qualifiers, since, as @vpetrovykh rightly pointed out in the comment above, there is no ambiguity as to how to interpret the expression, it must always insert two distinct objects.

  2. Allow and require INSERT DETACHED Foo in the nested INSERT. The only benefit of this approach is visual consistency with other statements that already require DETACHED to refer to Foo in the body of its INSERT, most importantly the UPDATE statement.

I now lean toward option 1), as it’s the least verbose option, and visual inconsistency with UPDATE can be explained in the error message and the documentation, whereas forcing the DISTINCT noise word is a price you’ll need to pay every time.

@1st1, thoughts?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Errors: "INSERT EXEC statement cannot be nested." and ...
I tried to change the place of execute Sp2 and it display me another error: Cannot use the ROLLBACK statement within an INSERT-EXEC...
Read more >
An INSERT EXEC statement cannot be nested after upgrade ...
I am receiving "An INSERT EXEC statement cannot be nested". ... there h*as never been issue with Insert Exec* nested error till now....
Read more >
HOW TO - Resolve 'An INSERT EXEC statement cannot be ...
I get the error message. An INSERT EXEC statement cannot be nested. But the query DOES insert the records into my table. I...
Read more >
INSERT EXEC statement cannot be nested
EXEC then if you try to call that stored procedure in the context of another INSERT...EXEC you will get the error you are...
Read more >
Msg 8164 - An INSERT EXEC statement cannot be nested.
Server: Msg 8164, Level 16, State 1, Line 1 An INSERT EXEC statement cannot be nested. ... This error occurs when calling a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found