Repository: edgedb/edgedb

Issue:
ISE inserting empty id with allow_user_specified_id enabled
<!-- Please search existing issues to avoid creating duplicates. -->

<!--
For the EdgeDB Version: run `edgedb query 'select sys::get_version_as_str()'` from your project directory (or run `select sys::get_version_as_str();` in the EdgeDB interactive shell).
For the EdgeDB CLI Version: Run `edgedb --version` from anywhere
-->

- EdgeDB Version: 3.0-dev.7343+4d0b071
- EdgeDB CLI Version: 3.0.0-dev.941+730fc35
- OS Version: ubuntu 22.04

Steps to Reproduce:
![image](https://user-images.githubusercontent.com/8278635/229178480-e1dd32c1-bfbf-4191-bde0-faebd2ebb155.png)


<!-- If the issue is about a query error, please also provide your schema -->

Schema:
```
module default {
  type User {
    required property name -> str;
  }
}
```


Discussion:
An error processing bug in `errormech.py`. This one happens whether in a transaction or not

Resolving patch:
diff --git a/edb/server/compiler/errormech.py b/edb/server/compiler/errormech.py
--- a/edb/server/compiler/errormech.py
+++ b/edb/server/compiler/errormech.py
@@ -30,6 +30,8 @@
 from edb.schema import name as sn
 from edb.schema import objtypes as s_objtypes
 from edb.schema import pointers as s_pointers
+from edb.schema import schema as s_schema
+from edb.schema import constraints as s_constraints
 
 from edb.pgsql import common
 from edb.pgsql import types
@@ -423,7 +425,12 @@ def interpret_by_code(code, schema, err_details, hint):
 
 
 @interpret_by_code.register_for_all(constraint_errors)
-def _interpret_constraint_errors(code, schema, err_details, hint):
+def _interpret_constraint_errors(
+    code: str,
+    schema: s_schema.Schema,
+    err_details: ErrorDetails,
+    hint: Optional[str],
+):
     details = None
     if code == pgerrors.ERROR_NOT_NULL_VIOLATION:
         colname = err_details.column_name
@@ -432,8 +439,17 @@ def _interpret_constraint_errors(code, schema, err_details, hint):
                 ptr_id, *_ = colname[2:].partition('_')
             else:
                 ptr_id = colname
-            pointer = common.get_object_from_backend_name(
-                schema, s_pointers.Pointer, ptr_id)
+            if ptr_id == 'id':
+                assert err_details.table_name
+                obj_type: s_objtypes.ObjectType = schema.get_by_id(
+                    uuidgen.UUID(err_details.table_name),
+                    type=s_objtypes.ObjectType,
+                )
+                pointer = obj_type.getptr(schema, sn.UnqualName('id'))
+            else:
+                pointer = common.get_object_from_backend_name(
+                    schema, s_pointers.Pointer, ptr_id
+                )
             pname = pointer.get_verbosename(schema, with_parent=True)
         else:
             pname = None
@@ -465,17 +481,24 @@ def _interpret_constraint_errors(code, schema, err_details, hint):
     # the static version
 
     if error_type == 'constraint' or error_type == 'idconstraint':
+        assert err_details.constraint_name
+
         # similarly, if we're here it's because we have a constraint_id
         if error_type == 'constraint':
-            constraint_id, _, _ = err_details.constraint_name.rpartition(';')
-            constraint_id = uuidgen.UUID(constraint_id)
-            constraint = schema.get_by_id(constraint_id)
+            constraint_id_s, _, _ = err_details.constraint_name.rpartition(';')
+            assert err_details.constraint_name
+            constraint_id = uuidgen.UUID(constraint_id_s)
+            constraint = schema.get_by_id(
+                constraint_id, type=s_constraints.Constraint
+            )
         else:
             # Primary key violations give us the table name, so
             # look through that for the constraint
             obj_id, _, _ = err_details.constraint_name.rpartition('_')
-            obj_ptr = schema.get_by_id(uuidgen.UUID(obj_id)).getptr(
-                schema, sn.UnqualName('id'))
+            obj_type = schema.get_by_id(
+                uuidgen.UUID(obj_id), type=s_objtypes.ObjectType
+            )
+            obj_ptr = obj_type.getptr(schema, sn.UnqualName('id'))
             constraint = obj_ptr.get_exclusive_constraints(schema)[0]
 
         msg = constraint.format_error(schema)
@@ -499,6 +522,7 @@ def _interpret_constraint_errors(code, schema, err_details, hint):
             f'Existing {source_name}.{pointer_name} '
             f'values violate the new constraint')
     elif error_type == 'scalar':
+        assert match
         domain_name = match.group(1)
         stype_name = types.base_type_name_map_r.get(domain_name)
         if stype_name:


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
@@ -5655,6 +5655,22 @@ async def test_edgeql_insert_explicit_id_05(self):
             []
         )
 
+    async def test_edgeql_insert_explicit_id_06(self):
+        await self.con.execute('''
+            configure session set allow_user_specified_id := true
+        ''')
+
+        async with self.assertRaisesRegexTx(
+            edgedb.MissingRequiredError,
+            "missing value for required property"
+        ):
+            await self.con.execute(r'''
+                INSERT Person {
+                    id := <optional uuid>{},
+                    name := "test",
+                }
+            ''')
+
     async def test_edgeql_insert_except_constraint_01(self):
         # Test basic behavior of a constraint using except
         await self.con.execute('''