Repository: edgedb/edgedb

Issue:
Insert objects via FOR LOOP error
- EdgeDB Version: 1.0.0-beta.2
- OS Version: MacOS 11.4

I'm trying to bulk insert objects via FOR loop and getting an error:
```
ERROR: edgedb.InternalServerError: there is no range var for [ns~1]@[ns~12]@@(__derived__::__derived__|t@w~1) source in <pg.SelectStmt at 0x7f9561685490>
  Hint: This is most likely a bug in EdgeDB. Please consider opening an issue ticket at https://github.com/edgedb/edgedb/issues/new?template=bug_report.md
```

So the schema is:
```
module default {
    type Translation {
		required property lang -> str;
		required property text -> str;
    }
};
```

I'm using the `edgedb-go` library, so the code is:

```go
   err := db.QueryOne(ctx, `INSERT City {
            name := <str>$0,
            country := (
                SELECT Country
                FILTER .id = <uuid>$1),
            i18nnames := (
                # Bulk insert all translated city names
                FOR t IN { array_unpack(<array<Translation>$2>) }
                UNION (
                    INSERT Translation {
                        lang := t.lang,
                        text := t.text,
                    }
                )
            ),
        }`, &id,
        city.Name,
        city.Country.ID,
        city.I18NNames,
    )
```

I'm trying to reproduce this in the edgedb-cli, and even without data it yields the same error:
```
edgedb> FOR t IN { array_unpack(<array<Translation>>{}) }
.......                 UNION (
.......                     INSERT Translation {
.......                         lang := t.lang,
.......                         text := t.text,
.......                     }
.......                 );
```
```
ERROR: InternalServerError: there is no range var for (__derived__::__derived__|t@w~1) source in <pg.SelectStmt at 0x7f9561a836d0>
  Hint: This is most likely a bug in EdgeDB. Please consider opening an issue ticket at https://github.com/edgedb/edgedb/issues/new?template=bug_report.md
```

<details>
<summary>Server traceback:</summary>
```      Traceback (most recent call last):
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/__init__.py", line 94, in compile_ir_to_sql_tree
          qtree = dispatch.compile(ir_expr, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/expr.py", line 60, in compile_Set
          _compile_set_impl(ir_set, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/expr.py", line 114, in _compile_set_impl
          _compile_set(ir_set, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/expr.py", line 589, in _compile_set
          relgen.get_set_rvar(ir_set, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 136, in get_set_rvar
          return _process_toplevel_query(ir_set, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 243, in _process_toplevel_query
          rvars = _get_set_rvar(ir_set, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 277, in _get_set_rvar
          rvars = process_set_as_subquery(ir_set, stmt, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 1213, in process_set_as_subquery
          dispatch.visit(ir_set.expr, ctx=newctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/dispatch.py", line 44, in visit
          compile(ir, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/stmt.py", line 95, in compile_SelectStmt
          outvar = clauses.compile_output(stmt.result, ctx=ictx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/clauses.py", line 173, in compile_output
          dispatch.visit(ir_set, ctx=newctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/expr.py", line 85, in visit_Set
          _compile_set_impl(ir_set, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/expr.py", line 110, in _compile_set_impl
          _compile_set(ir_set, ctx=scopectx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/expr.py", line 589, in _compile_set
          relgen.get_set_rvar(ir_set, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 189, in get_set_rvar
          rvars = _get_set_rvar(ir_set, ctx=subctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 277, in _get_set_rvar
          rvars = process_set_as_subquery(ir_set, stmt, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 1213, in process_set_as_subquery
          dispatch.visit(ir_set.expr, ctx=newctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/dispatch.py", line 44, in visit
          compile(ir, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/stmt.py", line 157, in compile_InsertStmt
          dml.process_insert_body(
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/dml.py", line 646, in process_insert_body
          rel = compile_insert_shape_element(
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/dml.py", line 913, in compile_insert_shape_element
          dispatch.visit(shape_el, ctx=insvalctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/expr.py", line 85, in visit_Set
          _compile_set_impl(ir_set, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/expr.py", line 110, in _compile_set_impl
          _compile_set(ir_set, ctx=scopectx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/expr.py", line 589, in _compile_set
          relgen.get_set_rvar(ir_set, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 189, in get_set_rvar
          rvars = _get_set_rvar(ir_set, ctx=subctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 277, in _get_set_rvar
          rvars = process_set_as_subquery(ir_set, stmt, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/relgen.py", line 1213, in process_set_as_subquery
          dispatch.visit(ir_set.expr, ctx=newctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/dispatch.py", line 44, in visit
          compile(ir, ctx=ctx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/stmt.py", line 95, in compile_SelectStmt
          outvar = clauses.compile_output(stmt.result, ctx=ictx)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/clauses.py", line 182, in compile_output
          val = pathctx.get_path_value_output(
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/pathctx.py", line 1004, in get_path_value_output
          return get_path_output(rel, path_id, aspect='value', env=env)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/pathctx.py", line 848, in get_path_output
          return _get_path_output(rel, path_id=path_id, aspect=aspect,
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/pathctx.py", line 892, in _get_path_output
          ref = get_path_var(rel, path_id, aspect=aspect, env=env)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/pathctx.py", line 323, in get_path_var
          outvar = get_path_output(
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/pathctx.py", line 848, in get_path_output
          return _get_path_output(rel, path_id=path_id, aspect=aspect,
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/pathctx.py", line 892, in _get_path_output
          ref = get_path_var(rel, path_id, aspect=aspect, env=env)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/pathctx.py", line 294, in get_path_var
          raise LookupError(
      LookupError: there is no range var for (__derived__::__derived__|t@w~1) source in <pg.SelectStmt at 0x7f9561a836d0>

      The above exception was the direct cause of the following exception:

      Traceback (most recent call last):
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/server/compiler_pool/worker.py", line 312, in worker
          res = meth(*args)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/server/compiler_pool/worker.py", line 173, in compile
          units, cstate = COMPILER.compile(
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/server/compiler/compiler.py", line 1986, in compile
          units = self._compile(ctx=ctx, source=source)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/server/compiler/compiler.py", line 1565, in _compile
          return self._try_compile(ctx=ctx, source=source)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/server/compiler/compiler.py", line 1618, in _try_compile
          comp, capabilities = self._compile_dispatch_ql(ctx, stmt)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/server/compiler/compiler.py", line 1539, in _compile_dispatch_ql
          query = self._compile_ql_query(ctx, ql)
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/server/compiler/compiler.py", line 597, in _compile_ql_query
          sql_text, argmap = pg_compiler.compile_ir_to_sql(
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/__init__.py", line 116, in compile_ir_to_sql
          qtree = compile_ir_to_sql_tree(
        File "/Library/Frameworks/EdgeDB.framework/Versions/1-beta2/lib/edgedb-server-1-beta2/lib/python3.9/site-packages/edb/pgsql/compiler/__init__.py", line 101, in compile_ir_to_sql_tree
          raise errors.InternalServerError(*args) from e
      edb.errors.InternalServerError: there is no range var for (__derived__::__derived__|t@w~1) source in <pg.SelectStmt at 0x7f9561a836d0>
edgedb>
```
</details>

I'm not sure I'm doing for loop insert correctly, though. If I can provide more details to make it easier to figure out the problem, let me know.


Discussion:
The `InternalServerError` is a bug, but there is also a problem in the original query:
```
<array<Translation>$2>
```
Here the cast should all be before the query parameter like this `<array<Translation>>$2`, however that still wouldn't work, since  EdgeDB only allows scalars or arrays of scalars in query parameters. (https://www.edgedb.com/docs/edgeql/expressions/parameters#parameter-types)

Instead you would have to pass the array of `Translation` objects as an array of `json` objects to the query parameter, then extract and cast the fields you need from those `json` objects:
```edgeql
INSERT City {
  name := <str>$0,
  country := (
    SELECT Country
    FILTER .id = <uuid>$1
  ),
  i18nnames := (
    # Bulk insert all translated city names
    FOR t IN { array_unpack(<array<json>>$2) }
    UNION (
      INSERT Translation {
        lang := <str>t['lang'],
        text := <str>t['text'],
      }
    )
  ),
}
```
> there is also a problem in the original query

Right, that was copy-paste bug (edited code a bit in the browsers).

> Instead you would have to pass the array of Translation objects as an array of json objects

Thank you. It looks a bit hackish. Is there another idiomatic and more elegant way to solve what I'm trying to do here? Use transactions I guess and insert in two queries maybe?

Trying the JSON approach and getting this error:

```go
    var id struct{ id edgedb.UUID }
    err := db.QueryOne(ctx, `INSERT City {
            name := <str>$0,
            country := (
                SELECT Country
                FILTER .id = <uuid>$1
                # TODO: check if we need LIMIT here, as cardinality should be ONE anyways
                LIMIT 1),
            i18nnames := (
                # Bulk insert all translated strings
                FOR t IN { array_unpack(<array<json>>$2) }
                UNION (
                    INSERT Translation {
                        lang := <str>t['lang'],
                        text := <str>t['text'],
                    }
                )
            ),
        }`, &id,
        city.Name,
        city.Country.ID,
        []byte(`[{"lang":"es","text":"Madrid"}]`),
    )
}
```

Error:
```
create city: edgedb.InvalidArgumentError: expected args[2][0] to be []byte, got uint8
```

What could be wrong here?
You appear to be passing a single JSON value that contains an array, instead of an array of JSON values as specified in the query parameter.
@jaclarke oh, right, thank you. Makes sense. Is there a way to specify query right for this use case? Or it's easier to reencode data into array of JSON values?
> Is there a way to specify query right for this use case?

Yes, there is a `json_array_unpack` function ([docs](https://www.edgedb.com/docs/edgeql/funcops/json#function::std::json_array_unpack)), so the `for` loop sub query would become:
```edgeql
FOR t IN { json_array_unpack(<json>$2) }
UNION (
    INSERT Translation {
        lang := <str>t['lang'],
        text := <str>t['text'],
    }
)
```
Also, this isn't related to your issue, but regarding this comment in your query: `# TODO: check if we need LIMIT here, as cardinality should be ONE anyways`

In this case of a filter checking equality against an objects `id`, EdgeDB should always be able to infer singleton cardinality, since `id` has a unique constraint. However in other cases where EdgeDB isn't able to infer singleton cardinality, but you know it should be, EdgeDB now has the [`assert_single` function](https://www.edgedb.com/docs/edgeql/funcops/set#function::std::assert_single) (added in beta 3), which will throw an error if there is ever more than a single item, instead of silently discarding the extra items as `LIMIT 1` would.
@jaclarke thank you so much!
Re-opening this since the ISE in the initial issue (https://github.com/edgedb/edgedb/issues/2813#issue-970276381) is still a bug.

Resolving patch:
diff --git a/edb/pgsql/compiler/dml.py b/edb/pgsql/compiler/dml.py
--- a/edb/pgsql/compiler/dml.py
+++ b/edb/pgsql/compiler/dml.py
@@ -534,6 +534,8 @@ def compile_iterator_cte(
                                           ctx=ictx)
 
         clauses.compile_iterator_expr(ictx.rel, iterator_set, ctx=ictx)
+        if iterator_set.path_id.is_objtype_path():
+            relgen.ensure_source_rvar(iterator_set, ictx.rel, ctx=ictx)
         ictx.rel.path_id = iterator_set.path_id
         pathctx.put_path_bond(ictx.rel, iterator_set.path_id)
         iterator_cte = pgast.CommonTableExpr(
diff --git a/edb/pgsql/compiler/pathctx.py b/edb/pgsql/compiler/pathctx.py
--- a/edb/pgsql/compiler/pathctx.py
+++ b/edb/pgsql/compiler/pathctx.py
@@ -292,7 +292,11 @@ def _find_rel_rvar(
             src_aspect = aspect
 
         if src_path_id.is_tuple_path():
-            if (var := _find_in_output_tuple(rel, path_id, aspect, env=env)):
+            if src_aspect == 'identity':
+                src_aspect = 'value'
+
+            if (var := _find_in_output_tuple(
+                    rel, path_id, src_aspect, env=env)):
                 return src_aspect, None, var
 
             rel_rvar = maybe_get_path_rvar(
diff --git a/edb/pgsql/compiler/relgen.py b/edb/pgsql/compiler/relgen.py
--- a/edb/pgsql/compiler/relgen.py
+++ b/edb/pgsql/compiler/relgen.py
@@ -413,7 +413,7 @@ def _get_set_rvar(
     return rvars
 
 
-def _ensure_source_rvar(
+def ensure_source_rvar(
     ir_set: irast.Set,
     stmt: pgast.Query,
     *,
@@ -947,7 +947,7 @@ def process_set_as_path(
             # (The returned one won't be a source rvar if it comes
             # from a function, for example)
             if not ir_source.path_id.is_type_intersection_path():
-                src_rvar = _ensure_source_rvar(ir_source, ctx.rel, ctx=srcctx)
+                src_rvar = ensure_source_rvar(ir_source, ctx.rel, ctx=srcctx)
             set_rvar = relctx.semi_join(stmt, ir_set, src_rvar, ctx=srcctx)
             rvars.append(SetRVar(set_rvar, ir_set.path_id,
                                  ['value', 'source']))
@@ -964,7 +964,7 @@ def process_set_as_path(
             if is_inline_primitive_ref:
                 # Semi-join variant for inline scalar links,
                 # which is, essentially, just filtering out NULLs.
-                _ensure_source_rvar(ir_source, srcctx.rel, ctx=srcctx)
+                ensure_source_rvar(ir_source, srcctx.rel, ctx=srcctx)
 
                 var = pathctx.get_path_value_var(
                     srcctx.rel, path_id=ir_set.path_id, env=ctx.env)
@@ -986,7 +986,7 @@ def process_set_as_path(
 
     elif is_id_ref_to_inline_source:
         main_rvar = SetRVar(
-            _ensure_source_rvar(ir_source, stmt, ctx=ctx),
+            ensure_source_rvar(ir_source, stmt, ctx=ctx),
             path_id=ir_set.path_id,
             aspects=['value']
         )
@@ -997,7 +997,7 @@ def process_set_as_path(
         # complex field indirections, so rely on tuple_getattr()
         # fallback for tuple properties for now.
         main_rvar = SetRVar(
-            _ensure_source_rvar(ir_source, stmt, ctx=ctx),
+            ensure_source_rvar(ir_source, stmt, ctx=ctx),
             path_id=ir_set.path_id,
             aspects=['value']
         )
@@ -1008,7 +1008,7 @@ def process_set_as_path(
             aspects = ['value']
             # If this is a link that is stored inline, make sure
             # the source aspect is actually accessible (not just value).
-            src_rvar = _ensure_source_rvar(ir_source, stmt, ctx=ctx)
+            src_rvar = ensure_source_rvar(ir_source, stmt, ctx=ctx)
         else:
             aspects = ['value', 'source']
             src_rvar = get_set_rvar(ir_source, ctx=ctx)


Test patch:
diff --git a/tests/test_edgeql_insert.py b/tests/test_edgeql_insert.py
--- a/tests/test_edgeql_insert.py
+++ b/tests/test_edgeql_insert.py
@@ -1370,6 +1370,80 @@ async def test_edgeql_insert_for_18(self):
               "note": {"name": "Madeline Hatch"}}],
         )
 
+    async def test_edgeql_insert_for_19(self):
+        await self.con.execute(r"""
+            FOR t IN { array_unpack(<array<InsertTest>>[]) }
+            UNION (
+                INSERT InsertTest {
+                    name := t.name, l2 := t.l2,
+                }
+            );
+        """)
+
+        await self.assert_query_result(
+            "SELECT InsertTest",
+            [],
+        )
+
+    async def test_edgeql_insert_for_20(self):
+        await self.con.execute(r"""
+            INSERT InsertTest { name := "a", l2 := 1 };
+        """)
+
+        await self.con.execute(r"""
+            FOR t IN { array_unpack([InsertTest]) }
+            UNION (
+                INSERT InsertTest {
+                    name := t.name ++ "!", l2 := t.l2 + 1,
+                }
+            );
+        """)
+
+        await self.assert_query_result(
+            "SELECT InsertTest { name, l2 } ORDER BY .l2",
+            [
+                {'name': "a", 'l2': 1},
+                {'name': "a!", 'l2': 2},
+            ],
+        )
+
+    async def test_edgeql_insert_for_21(self):
+        await self.con.execute(r"""
+            FOR t IN { array_unpack(<array<tuple<InsertTest>>>[]) }
+            UNION (
+                INSERT InsertTest {
+                    name := t.0.name, l2 := t.0.l2,
+                }
+            );
+        """)
+
+        await self.assert_query_result(
+            "SELECT InsertTest",
+            [],
+        )
+
+    async def test_edgeql_insert_for_22(self):
+        await self.con.execute(r"""
+            INSERT InsertTest { name := "a", l2 := 1 };
+        """)
+
+        await self.con.execute(r"""
+            FOR t IN { array_unpack([(InsertTest,)]) }
+            UNION (
+                INSERT InsertTest {
+                    name := t.0.name ++ "!", l2 := t.0.l2 + 1,
+                }
+            );
+        """)
+
+        await self.assert_query_result(
+            "SELECT InsertTest { name, l2 } ORDER BY .l2",
+            [
+                {'name': "a", 'l2': 1},
+                {'name': "a!", 'l2': 2},
+            ],
+        )
+
     async def test_edgeql_insert_for_bad_01(self):
         with self.assertRaisesRegex(
             edgedb.errors.QueryError,