Repository: edgedb/edgedb

Issue:
Attempting to switch index type fails with `InternalServerError`
```
edgedb error: InternalServerError: AssertionError:
  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 "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/server/compiler_pool/worker.py", line 203, in compile_in_tx
          units, cstate = COMPILER.compile_in_tx(cstate, *args, **kwargs)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/server/compiler/compiler.py", line 939, in compile_in_tx
          return compile(ctx=ctx, source=source), ctx.state
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/server/compiler/compiler.py", line 2313, in compile
          return _try_compile(ctx=ctx, source=original)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/server/compiler/compiler.py", line 2377, in _try_compile
          comp, capabilities = _compile_dispatch_ql(
                               ^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/server/compiler/compiler.py", line 2222, in _compile_dispatch_ql
          query = ddl.compile_dispatch_ql_migration(
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/server/compiler/ddl.py", line 384, in compile_dispatch_ql_migration
          return _describe_current_migration(ctx, ql)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/server/compiler/ddl.py", line 638, in _describe_current_migration
          top_op2 = s_ddl.cmd_from_ddl(
                    ^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/ddl.py", line 443, in cmd_from_ddl
          res = sd.compile_ddl(schema, ddl, context=context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 4365, in compile_ddl
          cmd = cmdcls._cmd_tree_from_ast(schema, astnode, context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/inheriting.py", line 1040, in _cmd_tree_from_ast
          cmd = super()._cmd_tree_from_ast(schema, astnode, context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 3526, in _cmd_tree_from_ast
          cmd = super()._cmd_tree_from_ast(schema, astnode, context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 1087, in _cmd_tree_from_ast
          subcmd = compile_ddl(schema, subastnode, context=context)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 4365, in compile_ddl
          cmd = cmdcls._cmd_tree_from_ast(schema, astnode, context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/referencing.py", line 1230, in _cmd_tree_from_ast
          cmd = super()._cmd_tree_from_ast(schema, astnode, context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/inheriting.py", line 1040, in _cmd_tree_from_ast
          cmd = super()._cmd_tree_from_ast(schema, astnode, context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 3526, in _cmd_tree_from_ast
          cmd = super()._cmd_tree_from_ast(schema, astnode, context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 1087, in _cmd_tree_from_ast
          subcmd = compile_ddl(schema, subastnode, context=context)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 4367, in compile_ddl
          cmd = cmdcls._cmd_tree_from_ast(schema, astnode, context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 1078, in _cmd_tree_from_ast
          cmd = cls._cmd_from_ast(schema, astnode, context)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 3476, in _cmd_from_ast
          return rename_class._rename_cmd_from_ast(schema, astnode, context)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/delta.py", line 3494, in _rename_cmd_from_ast
          new_name = cls._classname_from_ast(schema, astnode, context)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/indexes.py", line 413, in _classname_from_ast
          quals = cls._classname_quals_from_ast(
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-4/lib/python3.11/site-packages/edb/schema/indexes.py", line 438, in _classname_quals_from_ast
          assert isinstance(astnode, qlast.ConcreteIndexCommand)
      AssertionError
```

- EdgeDB Version: 4.4+596d0e4 on Ubuntu 22.04.3 LTS
- EdgeDB CLI Version: EdgeDB CLI 4.0.2+500be79 on OSX 14.3, 16gb M1

Steps to reproduce immediate error:

1. Restore from dump provided via DM to Devon in discord
2. Attempt to `edgedb migration create`

I got into this state by creating and applying a migration for

`index ext::pg_trgm::gin on (.legal_name);`

After which the above error happens even with zero schema changes.

However, I've done this several times (currently playing with how to even hit the index) without issue. I've also been able to restore to a backup before this, add it again, and not hit the issue again. Reproducibility to create this state organically is probably tough. 


Discussion:
I think I figured out how to repro

Changing from `gin` to `gist` immediately and reproducibly causes this. 

However, it's not giving the total lockup, zero changes `InternalServerError` like I had before. I'd say it's possible I had messed up and didn't actually have zero changes but I specifically did a hard revert in git & a dump to test that dump/restore could hit the same error. 

I can get past the error by removing the gin index then separately adding the gist index. 
Also it seems to be any switch of index type on the same column
That's right, the problem is with migration from gin to gist:

Minimal reproducible example of migrating from:
```
using extension pg_trgm version '1.6';
module default {
    type Hello {
        required property world: std::str;

        index ext::pg_trgm::gin on (.world);
    };
};
```
... to:
```
using extension pg_trgm version '1.6';
module default {
    type Hello {
        required property world: std::str;

        index ext::pg_trgm::gist on (.world);
    };
};
```
The problem is that delta of this migration is computed to be:
```
ALTER INDEX ext::pg_trgm::gin ON (.world) {
    rename to ext::pg_trgm::gist;
    drop extending ext::pg_trgm::gin;
    extending ext::pg_trgm::gist LAST;
}
```
... but we don't support renaming of the index (hence the error) or rebasing it to some other abstract index.

Instead, index should be dropped and recreated.

Resolving patch:
diff --git a/edb/schema/indexes.py b/edb/schema/indexes.py
--- a/edb/schema/indexes.py
+++ b/edb/schema/indexes.py
@@ -163,6 +163,15 @@ class Index(
     qlkind=qltypes.SchemaObjectClass.INDEX,
     data_safe=True,
 ):
+    # redefine, so we can change compcoef
+    bases = so.SchemaField(
+        so.ObjectList['Index'],  # type: ignore
+        type_is_generic_self=True,
+        default=so.DEFAULT_CONSTRUCTOR,
+        coerce=True,
+        inheritable=False,
+        compcoef=0.0,  # can't rebase
+    )
 
     subject = so.SchemaField(
         so.Object,


Test patch:
diff --git a/tests/test_indexes.py b/tests/test_indexes.py
--- a/tests/test_indexes.py
+++ b/tests/test_indexes.py
@@ -402,3 +402,31 @@ async def test_index_10(self):
                 };
                 """
             )
+
+    async def test_index_11(self):
+        # indexes should not be rebased, but should be dropped and recreated
+
+        await self.con.execute(
+            '''
+            create type Hello {
+                create required property world: str;
+                create index pg::btree on (.world);
+            };
+            '''
+        )
+        await self.migrate(
+            r"""
+            type Hello {
+                property world: str;
+                index pg::hash on (.world);
+            };
+            """
+        )
+        await self.migrate(
+            r"""
+            type Hello {
+                property world: str;
+                index pg::btree on (.world);
+            };
+            """
+        )