Repository: edgedb/edgedb

Issue:
Query fails at EdgeDB clients (golang, py, js) but not the REPL
- EdgeDB Version: EdgeDB 1.0-beta.3+g8ab4a7be0.cv202108020000 (repl 1.0.0-beta.3)
- OS Version: Ubuntu

## Issue
1. Query fails when using EdgeDB client, but works when the REPL is used.

The error:
> edgedb.InternalServerError: column User~2.target does not exist

## Steps to Reproduce:

1. Clone the repo - [Link](https://github.com/clmno/edgedb_client_error_report)
    ```
    get clone https://github.com/clmno/edgedb_client_error_report.git
    ```
2. Update `go`. `python` and `javascript` dependencies using their corresponding tools
    ```
    go mod download
    poetry install
    yarn install
    ```
3. Migrate EdeDB and populate the DB with the queires in `init_queries.edgeql`
    ```sql
    INSERT Company {name := "ABC"};
    INSERT Company {name := "XYZ"};
    INSERT User {
        name := "Alice", company := {
            (SELECT Company FILTER .name = "ABC"),
            (SELECT Company FILTER .name = "XYZ")
        }
    };
    INSERT User {name := "Bob"};
    
    # This one will fail with the error: edgedb.InternalServerError: column User~2.target does not exist
    SELECT User {id, name, c := .company.id};
    ```
4. Run each of the client implementation to find the same exception
    > edgedb.InternalServerError: column User~2.target does not exist
5. The query
    ```sql
    SELECT User {id, name, company_id := .company.id}
    ```


Here a quick look at the python client

```python

import edgedb

conn = edgedb.connect('edgedb_error')
query = '''SELECT User {
            id,
            name,
            company_id := .company.id
        }'''
print(f"result :{conn.query(query)}")

conn.close()
```


Discussion:
@msullivan @elprans any ideas?
The error can be reproduced in the CLI with implicit limit disabled (`\set limit 0`). It specifically seems to be this part of the query that causes the error: `select User {company_ids := .company.id}` (this query works: `select User {company_names := .company.name}`).

As a workaround, this query seems to work: `select User {company_ids := (select .company).id}`.

Edit: This query also fails with implicit limit disabled: 
```
select schema::ObjectType {p := .properties.id};
edgedb error: InternalServerError: None
  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
  Server traceback:
      Traceback (most recent call last):
        File "/home/james/dev/edgedb/edb/pgsql/compiler/__init__.py", line 101, in compile_ir_to_sql_tree
          qtree = dispatch.compile(ir_expr, ctx=ctx)
        File "/usr/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 60, in compile_Set
          _compile_set_impl(ir_set, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 114, in _compile_set_impl
          _compile_set(ir_set, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 592, in _compile_set
          relgen.get_set_rvar(ir_set, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/relgen.py", line 160, in get_set_rvar
          return _process_toplevel_query(ir_set, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/relgen.py", line 270, in _process_toplevel_query
          rvars = _get_set_rvar(ir_set, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/relgen.py", line 304, in _get_set_rvar
          rvars = process_set_as_subquery(ir_set, stmt, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/relgen.py", line 1193, in process_set_as_subquery
          dispatch.visit(ir_set.expr, ctx=newctx)
        File "/usr/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/dispatch.py", line 44, in visit
          compile(ir, ctx=ctx)
        File "/usr/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/stmt.py", line 98, in compile_SelectStmt
          outvar = clauses.compile_output(stmt.result, ctx=ictx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/clauses.py", line 237, in compile_output
          dispatch.visit(ir_set, ctx=newctx)
        File "/usr/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 85, in visit_Set
          _compile_set_impl(ir_set, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 114, in _compile_set_impl
          _compile_set(ir_set, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 596, in _compile_set
          _compile_shape(ir_set, ir_set.shape, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 615, in _compile_shape
          result = shapecomp.compile_shape(ir_set, shape, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/shapecomp.py", line 90, in compile_shape
          wrapper = relgen.set_as_subquery(
        File "/home/james/dev/edgedb/edb/pgsql/compiler/relgen.py", line 459, in set_as_subquery
          dispatch.visit(ir_set, ctx=subctx)
        File "/usr/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 85, in visit_Set
          _compile_set_impl(ir_set, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 110, in _compile_set_impl
          _compile_set(ir_set, ctx=scopectx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/expr.py", line 592, in _compile_set
          relgen.get_set_rvar(ir_set, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/relgen.py", line 214, in get_set_rvar
          rvars = _get_set_rvar(ir_set, ctx=subctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/relgen.py", line 304, in _get_set_rvar
          rvars = process_set_as_subquery(ir_set, stmt, ctx=ctx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/relgen.py", line 1193, in process_set_as_subquery
          dispatch.visit(ir_set.expr, ctx=newctx)
        File "/usr/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/dispatch.py", line 44, in visit
          compile(ir, ctx=ctx)
        File "/usr/lib/python3.9/functools.py", line 877, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/stmt.py", line 98, in compile_SelectStmt
          outvar = clauses.compile_output(stmt.result, ctx=ictx)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/clauses.py", line 246, in compile_output
          val = pathctx.get_path_value_output(
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1207, in get_path_value_output
          return get_path_output(rel, path_id, aspect='value', env=env)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1051, in get_path_output
          return _get_path_output(rel, path_id=path_id, aspect=aspect,
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1076, in _get_path_output
          id_output = maybe_get_path_output(rel, src_path_id,
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1190, in maybe_get_path_output
          return get_path_output(rel, path_id=path_id, aspect=aspect,
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1051, in get_path_output
          return _get_path_output(rel, path_id=path_id, aspect=aspect,
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1095, in _get_path_output
          ref = get_path_var(rel, path_id, aspect=aspect, env=env)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 252, in get_path_var
          outvar = get_path_output(
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1051, in get_path_output
          return _get_path_output(rel, path_id=path_id, aspect=aspect,
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1095, in _get_path_output
          ref = get_path_var(rel, path_id, aspect=aspect, env=env)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 252, in get_path_var
          outvar = get_path_output(
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1051, in get_path_output
          return _get_path_output(rel, path_id=path_id, aspect=aspect,
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1095, in _get_path_output
          ref = get_path_var(rel, path_id, aspect=aspect, env=env)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 252, in get_path_var
          outvar = get_path_output(
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1051, in get_path_output
          return _get_path_output(rel, path_id=path_id, aspect=aspect,
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1095, in _get_path_output
          ref = get_path_var(rel, path_id, aspect=aspect, env=env)
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 252, in get_path_var
          outvar = get_path_output(
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1051, in get_path_output
          return _get_path_output(rel, path_id=path_id, aspect=aspect,
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1085, in _get_path_output
          return _get_rel_path_output(rel, path_id, aspect=aspect,
        File "/home/james/dev/edgedb/edb/pgsql/compiler/pathctx.py", line 1015, in _get_rel_path_output
          assert not ptrref.is_computable
      AssertionError

      The above exception was the direct cause of the following exception:

      Traceback (most recent call last):
        File "/home/james/dev/edgedb/edb/server/compiler_pool/worker.py", line 308, in worker
          res = meth(*args)
        File "/home/james/dev/edgedb/edb/server/compiler_pool/worker.py", line 176, in compile
          units, cstate = COMPILER.compile(
        File "/home/james/dev/edgedb/edb/server/compiler/compiler.py", line 2059, in compile
          units = self._compile(ctx=ctx, source=source)
        File "/home/james/dev/edgedb/edb/server/compiler/compiler.py", line 1621, in _compile
          return self._try_compile(ctx=ctx, source=source)
        File "/home/james/dev/edgedb/edb/server/compiler/compiler.py", line 1674, in _try_compile
          comp, capabilities = self._compile_dispatch_ql(ctx, stmt)
        File "/home/james/dev/edgedb/edb/server/compiler/compiler.py", line 1595, in _compile_dispatch_ql
          query = self._compile_ql_query(ctx, ql)
        File "/home/james/dev/edgedb/edb/server/compiler/compiler.py", line 601, in _compile_ql_query
          sql_text, argmap = pg_compiler.compile_ir_to_sql(
        File "/home/james/dev/edgedb/edb/pgsql/compiler/__init__.py", line 123, in compile_ir_to_sql
          qtree = compile_ir_to_sql_tree(
        File "/home/james/dev/edgedb/edb/pgsql/compiler/__init__.py", line 108, in compile_ir_to_sql_tree
          raise errors.InternalServerError(*args) from e
      edb.errors.InternalServerError: None
```
`SELECT User {id, name, card_ids := .deck.id}` repros this in our `cards` test database

Resolving patch:
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
@@ -1068,9 +1068,18 @@ def _get_path_output(
     ref: pgast.BaseExpr
     alias = None
     rptr = path_id.rptr()
-    if rptr is not None and irtyputils.is_id_ptrref(rptr):
+    if rptr is not None and irtyputils.is_id_ptrref(rptr) and not (
+        (src_path_id := path_id.src_path())
+        and (src_rptr := src_path_id.rptr())
+        and (
+            src_rptr.is_computable
+            or src_rptr.out_cardinality.is_multi()
+        )
+    ):
         # A value reference to Object.id is the same as a value
-        # reference to the Object itself.
+        # reference to the Object itself. (Though we want to only
+        # apply this in the cases that process_set_as_path does this
+        # optimization, which means not for multi props.)
         src_path_id = path_id.src_path()
         assert src_path_id is not None
         id_output = maybe_get_path_output(rel, src_path_id,


Test patch:
diff --git a/tests/test_edgeql_select.py b/tests/test_edgeql_select.py
--- a/tests/test_edgeql_select.py
+++ b/tests/test_edgeql_select.py
@@ -735,6 +735,27 @@ async def test_edgeql_select_computable_32(self):
             ]
         )
 
+    async def test_edgeql_select_computable_33(self):
+        await self.assert_query_result(
+            r"""
+            SELECT User {name, todo_ids := .todo.id} FILTER .name = 'Elvis';
+            """,
+            [
+                {'name': 'Elvis', 'todo_ids': [{}, {}]},
+            ]
+        )
+
+        await self.assert_query_result(
+            r"""
+            WITH Z := (SELECT User {
+                asdf := (SELECT .todo ORDER BY .number LIMIT 1)})
+            SELECT Z {name, asdf_id := .asdf.id} FILTER .name = 'Elvis';
+            """,
+            [
+                {'name': 'Elvis', 'asdf_id': {}},
+            ]
+        )
+
     async def test_edgeql_select_match_01(self):
         await self.assert_query_result(
             r"""