Repository: edgedb/edgedb

Issue:
Create Index in abstract Link crashes Migration
<!-- Please search existing issues to avoid creating duplicates. -->
- EdgeDB Version: 2.1
- OS Version: macOS 12.5 (M1 Pro, Also Checked in Docker Image with `amd64` architecture)

Steps to Reproduce:

1. Create Previous Schema (Works well!)
2. Add Index in Abstract Link
3. Create Migration and Apply, It Crashes.

```
edgedb error: InternalServerError: relation "edgedbpub.f6cc2eae-17e5-11ed-8e92-83df59ae4c33" does not exist
  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:
      edb.errors.InternalServerError: relation "edgedbpub.f6cc2eae-17e5-11ed-8e92-83df59ae4c33" does not exist
```

p.s. I'm new with EdgeDB, so It can be schema error. If my schema is wrong, Just Tell me please. :) I think this error message can be contain more information. 

<!-- If the issue is about a query error, please also provide your schema -->
Schema:

```
module default {
  # Base Model for Define Essential Values
  abstract type BaseModel {
    overloaded required property id -> uuid {
      constraint exclusive;
      readonly := true;
      default := uuid_generate_v1mc();
    };

    required property created_at -> datetime;
    required property updated_at -> datetime;
    property deleted_at -> datetime;
    required property deleted -> bool {
      default := false;
    };

    index on (.created_at) {
      annotation title := "CreatedAt Index";
    };
  }

  # Define User Model
  type User extending BaseModel {
    # Email is unique.
    required property email -> str {
      constraint exclusive;
    };

    required property password -> str;

    required property name -> str {
      constraint min_len_value(3);
    };

    index on (.email) {
      annotation title := "Email Index";
    };
  }

  abstract link IdIndex {
    property id -> uuid;
    # ----------------------------------
    # here is the problem!!
    index on (__subject__@id);
    # ----------------------------------
  }

  # Define Memo and Comment Model
  type Memo extending BaseModel {
    required link created_by extending IdIndex -> User;
    multi link accessable_users extending IdIndex -> User;

    required property title -> str;
    required property content -> str;
    required property tags -> array<str> {
      default := <array<str>>[];
    };
  }

  type Comment extending BaseModel {
    required link created_by extending IdIndex -> User;
    required link memo extending IdIndex -> Memo;
    required property content -> str;
  }
}
```


Discussion:
This one is actually darkly hilarious. The crux of the issue seems to be the use of the name `id` for the link property.

```
create abstract link foo { create property id -> uuid; create index on (__subject__@id); };
create type T;
create type S { create link x extending foo -> T; }
```
fails but
```
create abstract link foo { create property xid -> uuid; create index on (__subject__@xid); };
create type T;
create type S { create link x extending foo -> T; }
```
works

Resolving patch:
diff --git a/edb/edgeql/compiler/viewgen.py b/edb/edgeql/compiler/viewgen.py
--- a/edb/edgeql/compiler/viewgen.py
+++ b/edb/edgeql/compiler/viewgen.py
@@ -1097,9 +1097,8 @@ def _normalize_view_ptr_expr(
         )
 
     # Prohibit invalid operations on id and __type__
-    ptrcls_sn = ptrcls.get_shortname(ctx.env.schema)
     id_access = (
-        ptrcls_sn.name == 'id'
+        ptrcls.is_id_pointer(ctx.env.schema)
         and (
             not ctx.env.options.allow_user_specified_id
             or not exprtype.is_mutation()
@@ -1110,6 +1109,7 @@ def _normalize_view_ptr_expr(
         and (id_access or ptrcls.is_protected_pointer(ctx.env.schema))
         and not from_default
     ):
+        ptrcls_sn = ptrcls.get_shortname(ctx.env.schema)
         if is_polymorphic:
             msg = (f'cannot access {ptrcls_sn.name} on a polymorphic '
                    f'shape element')
diff --git a/edb/ir/typeutils.py b/edb/ir/typeutils.py
--- a/edb/ir/typeutils.py
+++ b/edb/ir/typeutils.py
@@ -784,7 +784,7 @@ def is_id_ptrref(ptrref: irast.BasePointerRef) -> bool:
     """Return True if *ptrref* describes the id property."""
     return (
         str(ptrref.std_parent_name) == 'std::id'
-    )
+    ) and not ptrref.source_ptr
 
 
 def is_computable_ptrref(ptrref: irast.BasePointerRef) -> bool:
diff --git a/edb/schema/pointers.py b/edb/schema/pointers.py
--- a/edb/schema/pointers.py
+++ b/edb/schema/pointers.py
@@ -685,7 +685,7 @@ def is_endpoint_pointer(self, schema: s_schema.Schema) -> bool:
     def is_special_pointer(self, schema: s_schema.Schema) -> bool:
         return self.get_shortname(schema).name in {
             'source', 'target', 'id'
-        }
+        } and (self.is_id_pointer(schema) or self.is_endpoint_pointer(schema))
 
     def is_property(self, schema: s_schema.Schema) -> bool:
         raise NotImplementedError


Test patch:
diff --git a/tests/test_edgeql_ddl.py b/tests/test_edgeql_ddl.py
--- a/tests/test_edgeql_ddl.py
+++ b/tests/test_edgeql_ddl.py
@@ -3241,6 +3241,29 @@ async def test_edgeql_ddl_link_property_08(self):
             };
         """)
 
+    async def test_edgeql_ddl_link_property_09(self):
+        await self.con.execute("""
+            create type T;
+            create type S {
+                create multi link x -> T {
+                    create property id -> str;
+                    create index on (__subject__@id);
+                }
+            };
+            insert T;
+            insert S { x := (select T { @id := "lol" }) };
+        """)
+
+        await self.assert_query_result(
+            r"""
+                select S { x: {id, @id} }
+            """,
+            [{'x': [{'id': str, '@id': "lol"}]}],
+            # The python bindings seem to misbehave when there is
+            # linkprop and a regular prop with the same name
+            json_only=True,
+        )
+
     async def test_edgeql_ddl_bad_01(self):
         with self.assertRaisesRegex(
                 edgedb.InvalidReferenceError,