Repository: edgedb/edgedb

Issue:
Dump fails with `error receiving dump header: unexpected constant type: <class 'edb.ir.statypes.Duration'>`
<!-- 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: `2.14` and `2.15`
- EdgeDB CLI Version: `2.3.1+5d93f42` and `3.0.0+80bc8b4`
- OS Version: macos 13

Steps to Reproduce:

Unsure as to the exact circumstances that led to this so apologies in advance for lack of detail. This does work as expected on an instance with identical version/schema, so this may be data dependent.

1. Run `edgedb dump -I instancename instance.dump`

```
edgedb error: InternalServerError: error receiving dump header: unexpected constant type: <class 'edb.ir.statypes.Duration'>
  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-2/lib/python3.10/site-packages/edb/server/compiler_pool/worker_proc.py", line 55, in worker
          res = meth(*args)
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-2/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 2595, in describe_database_dump
          config_ddl = config.to_edgeql(config.get_settings(), database_config)
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-2/lib/python3.10/site-packages/edb/server/config/ops.py", line 394, in to_edgeql
          val = value_to_edgeql_const(setting, value.value)
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-2/lib/python3.10/site-packages/edb/server/config/ops.py", line 333, in value_to_edgeql_const
          ql = s_utils.const_ast_from_python(value)
        File "/usr/lib/x86_64-linux-gnu/edgedb-server-2/lib/python3.10/site-packages/edb/schema/utils.py", line 1128, in const_ast_from_python
          raise ValueError(f'unexpected constant type: {type(val)!r}')
      ValueError: unexpected constant type: <class 'edb.ir.statypes.Duration'>
```

<!-- If the issue is about a query error, please also provide your schema -->

Schema:

Can send schema by discord DM Jack Fischer#5469. Happy to pull any other info that would be helpful. No `duration`s in schema. 

Database config state sync issues after restore
As I discovered when preparing #5528, it seems that if we restore a database that had a `query_execution_timeout` specified (and possibly other things with actual backend settings), and then our new connection to it immediately enters a transaction, the setting is not visible. If the connection executes a query first, and then enters a transaction, it works.

See the comment and workaround in #5528 for potentially more detail


Discussion:
It looks like the bug is that we can't properly handle dumping databases that have had any *configuration values* of type `duration` set.

As a workaround, try unsetting the three configuration values with `duration` type on the database: `session_idle_timeout`, `session_idle_transaction_timeout`, `query_execution_timeout`.


Resolving patch:
diff --git a/edb/schema/utils.py b/edb/schema/utils.py
--- a/edb/schema/utils.py
+++ b/edb/schema/utils.py
@@ -29,6 +29,8 @@
 from edb.common import levenshtein
 from edb.edgeql import ast as qlast
 
+from edb.ir import statypes
+
 from . import name as sn
 from . import objects as so
 
@@ -1147,7 +1149,7 @@ def _intersection_error(schema: s_schema.Schema,
 MIN_INT64 = -2 ** 63
 
 
-def const_ast_from_python(val: Any) -> qlast.BaseConstant:
+def const_ast_from_python(val: Any) -> qlast.Expr:
     if isinstance(val, str):
         return qlast.StringConstant.from_python(val)
     elif isinstance(val, bool):
@@ -1163,6 +1165,13 @@ def const_ast_from_python(val: Any) -> qlast.BaseConstant:
         return qlast.FloatConstant(value=str(val))
     elif isinstance(val, bytes):
         return qlast.BytesConstant.from_python(val)
+    elif isinstance(val, statypes.Duration):
+        return qlast.TypeCast(
+            type=qlast.TypeName(
+                maintype=qlast.ObjectRef(module='__std__', name='duration'),
+            ),
+            expr=qlast.StringConstant(value=val.to_iso8601()),
+        )
     else:
         raise ValueError(f'unexpected constant type: {type(val)!r}')
 
diff --git a/edb/testbase/server.py b/edb/testbase/server.py
--- a/edb/testbase/server.py
+++ b/edb/testbase/server.py
@@ -1406,6 +1406,7 @@ class StableDumpTestCase(QueryTestCase, CLITestCaseMixin):
     ISOLATED_METHODS = False
     STABLE_DUMP = True
     TRANSACTION_ISOLATION = False
+    PARALLELISM_GRANULARITY = 'suite'
 
     async def check_dump_restore_single_db(self, check_method):
         with tempfile.NamedTemporaryFile() as f:


Test patch:
diff --git a/tests/schemas/dump_v3_setup.edgeql b/tests/schemas/dump_v3_setup.edgeql
--- a/tests/schemas/dump_v3_setup.edgeql
+++ b/tests/schemas/dump_v3_setup.edgeql
@@ -44,3 +44,7 @@ create type Foo {
         }
     );
 };
+
+configure current database set allow_user_specified_id := true;
+configure current database set query_execution_timeout :=
+  <std::duration>'1 hour 20 minutes 13 seconds';
diff --git a/tests/test_dump_v3.py b/tests/test_dump_v3.py
--- a/tests/test_dump_v3.py
+++ b/tests/test_dump_v3.py
@@ -103,6 +103,19 @@ async def _ensure_schema_data_integrity(self):
             [{"name": "whatever_no", "errmessage": "aaaaaa"}],
         )
 
+        await self.assert_query_result(
+            r'''
+            select cfg::Config.allow_user_specified_id;
+            ''',
+            [True],
+        )
+        await self.assert_query_result(
+            r'''
+            select <str>cfg::Config.query_execution_timeout;
+            ''',
+            ['PT1H20M13S'],
+        )
+
 
 class TestDumpV3(tb.StableDumpTestCase, DumpTestCaseMixin):
     DEFAULT_MODULE = 'test'