We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AttributeError "attname" or "nspname" from various endpoints
I have been getting this API error intermittently when making a GET request to the records and columns endpoints. It always happens after making some DDL request, like importing a table, or renaming a columns, or extracting columns -- though I can't reproduce it 100% of the time.

<details>
<summary>(A) Sometimes I get this "nspname" error</summary>

```
Environment:


Request Method: GET
Request URL: http://localhost:8000/api/db/v0/tables/1894/records/?limit=500&offset=0

Django Version: 3.1.14
Python Version: 3.9.16
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework',
 'django_filters',
 'django_property_filter',
 'mathesar']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'mathesar.middleware.CursorClosedHandlerMiddleware',
 'mathesar.middleware.PasswordChangeNeededMiddleware',
 'django_userforeignkey.middleware.UserForeignKeyMiddleware',
 'django_request_cache.middleware.RequestCacheMiddleware']



Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/sqlalchemy/sql/base.py", line 1167, in __getattr__
    return self._index[key]

The above exception ('nspname') was the direct cause of the following exception:
  File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 466, in handle_exception
    response = exception_handler(exc, context)
  File "/code/mathesar/exception_handlers.py", line 59, in mathesar_exception_handler
    raise exc
  File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/code/mathesar/api/db/viewsets/records.py", line 72, in list
    records = paginator.paginate_queryset(
  File "/code/mathesar/api/pagination.py", line 81, in paginate_queryset
    self.count = table.sa_num_records(filter=filters, search=search)
  File "/code/mathesar/models/base.py", line 471, in sa_num_records
    table=self._sa_table,
  File "/code/mathesar/state/cached_property.py", line 62, in __get__
    new_value = self.original_get_fn(instance)
  File "/code/mathesar/models/base.py", line 337, in _sa_table
    sa_table = reflect_table_from_oid(
  File "/code/db/tables/operations/select.py", line 31, in reflect_table_from_oid
    tables = reflect_tables_from_oids(
  File "/code/db/tables/operations/select.py", line 43, in reflect_tables_from_oids
    get_map_of_table_oid_to_schema_name_and_table_name(
  File "/code/db/tables/operations/select.py", line 74, in get_map_of_table_oid_to_schema_name_and_table_name
    select(pg_namespace.c.nspname, pg_class.c.relname, pg_class.c.oid)
  File "/usr/local/lib/python3.9/site-packages/sqlalchemy/sql/base.py", line 1169, in __getattr__
    util.raise_(AttributeError(key), replace_context=err)
  File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception

Exception Type: AttributeError at /api/db/v0/tables/1894/records/
Exception Value: nspname
```

</details>

<details>
<summary>(B) Other times I get this "attname" error</summary>

```
Environment:


Request Method: GET
Request URL: http://localhost:8000/api/db/v0/tables/1824/records/?limit=500&offset=0

Django Version: 3.1.14
Python Version: 3.9.16
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework',
 'django_filters',
 'django_property_filter',
 'mathesar']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'mathesar.middleware.CursorClosedHandlerMiddleware',
 'mathesar.middleware.PasswordChangeNeededMiddleware',
 'django_userforeignkey.middleware.UserForeignKeyMiddleware',
 'django_request_cache.middleware.RequestCacheMiddleware']



Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/sqlalchemy/sql/base.py", line 1167, in __getattr__
    return self._index[key]

The above exception ('attname') was the direct cause of the following exception:
  File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 466, in handle_exception
    response = exception_handler(exc, context)
  File "/code/mathesar/exception_handlers.py", line 59, in mathesar_exception_handler
    raise exc
  File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/code/mathesar/api/db/viewsets/records.py", line 55, in list
    column_names_to_ids = table.get_column_name_id_bidirectional_map()
  File "/code/mathesar/models/base.py", line 554, in get_column_name_id_bidirectional_map
    columns_map = bidict({column.name: column.id for column in columns})
  File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 287, in __iter__
    self._fetch_all()
  File "/code/mathesar/utils/prefetch.py", line 158, in _fetch_all
    prefetcher.fetch(obj_list, name, self.model, forwarders)
  File "/code/mathesar/utils/prefetch.py", line 270, in fetch
    related_data = self.filter(data_mapping.keys(), data_mapping.values())
  File "/code/mathesar/models/base.py", line 225, in filter
    return get_map_of_attnum_to_column_name(
  File "/code/db/columns/operations/select.py", line 91, in get_map_of_attnum_to_column_name
    triples_of_col_info = _get_triples_of_column_name_and_attnum_and_table_oid(
  File "/code/db/columns/operations/select.py", line 104, in _get_triples_of_column_name_and_attnum_and_table_oid
    statement = _statement_for_triples_of_column_name_and_attnum_and_table_oid(
  File "/code/db/columns/operations/select.py", line 180, in _statement_for_triples_of_column_name_and_attnum_and_table_oid
    sel = select(pg_attribute.c.attname, pg_attribute.c.attnum, pg_attribute.c.attrelid)
  File "/usr/local/lib/python3.9/site-packages/sqlalchemy/sql/base.py", line 1169, in __getattr__
    util.raise_(AttributeError(key), replace_context=err)
  File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception

Exception Type: AttributeError at /api/db/v0/tables/1824/records/
Exception Value: attname
```

</details>

The exact same steps will sometimes produce (A), other times produce (B), and other times no error at all. I hit these errors a lot while working on #2140. I was doing a workflow where I'd import `books_sim.ts`, then extract the author's first and last names into a new table. I did it over and over again. I probably hit the error about 75% of the time during import and 60% of the time during column extraction.

https://user-images.githubusercontent.com/42411/208746906-86d06e41-18d0-45da-8d39-32aa8fddecba.mp4



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `db/utils.py`
Content:
```
1 import inspect
2 import warnings
3 
4 from psycopg2.errors import UndefinedFunction
5 
6 import sqlalchemy
7 from sqlalchemy.exc import ProgrammingError
8 
9 from db.records import exceptions
10 
11 
12 def execute_statement(engine, statement, connection_to_use=None):
13     try:
14         if connection_to_use:
15             return connection_to_use.execute(statement)
16         else:
17             with engine.begin() as conn:
18                 return conn.execute(statement)
19     except ProgrammingError as e:
20         if isinstance(e.orig, UndefinedFunction):
21             message = e.orig.args[0].split('\n')[0]
22             raise exceptions.UndefinedFunction(message)
23         else:
24             raise e
25 
26 
27 def execute_pg_query(engine, query, connection_to_use=None):
28     if isinstance(query, sqlalchemy.sql.expression.Executable):
29         executable = query
30     else:
31         executable = sqlalchemy.select(query)
32     return execute_statement(engine, executable, connection_to_use=connection_to_use).fetchall()
33 
34 
35 # TODO refactor to use @functools.total_ordering
36 class OrderByIds:
37     """
38     A mixin for ordering based on ids; useful at least for type enums in testing.
39     """
40 
41     id: str  # noqa: NT001
42 
43     def __ge__(self, other):
44         if self._ordering_supported(other):
45             return self.id >= other.id
46         return NotImplemented
47 
48     def __gt__(self, other):
49         if self._ordering_supported(other):
50             return self.id > other.id
51         return NotImplemented
52 
53     def __le__(self, other):
54         if self._ordering_supported(other):
55             return self.id <= other.id
56         return NotImplemented
57 
58     def __lt__(self, other):
59         if self._ordering_supported(other):
60             return self.id < other.id
61         return NotImplemented
62 
63     def _ordering_supported(self, other):
64         return hasattr(other, 'id')
65 
66 
67 def get_module_members_that_satisfy(module, predicate):
68     """
69     Looks at the members of the provided module and filters them using the provided predicate.
70 
71     Currently used to automatically collect all concrete subclasses of some abstract superclass
72     found as top-level members of a module.
73     """
74     all_members_in_defining_module = inspect.getmembers(module)
75     return set(
76         member
77         for _, member in all_members_in_defining_module
78         if predicate(member)
79     )
80 
81 
82 def ignore_type_warning(f):
83     """
84     When loading PostgreSQL system tables, an SAWarning is often generated
85     since they use some exotic, postgres-specific types.
86 
87     This decorator allows one to ignore those warnings.
88     """
89     def warning_ignored_func(*args, **kwargs):
90         with warnings.catch_warnings():
91             warnings.filterwarnings("ignore", message="Did not recognize type")
92             return f(*args, **kwargs)
93 
94     return warning_ignored_func
95 
96 
97 @ignore_type_warning
98 def get_pg_catalog_table(table_name, engine, metadata):
99     return sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog')
100 
101 
102 def ignore_duplicate_wrapper(stmt):
103     return f"""
104     DO $$ BEGIN
105     {stmt}
106     EXCEPTION
107     WHEN duplicate_object THEN null;
108     END $$;
109     """
110
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/db/utils.py b/db/utils.py
--- a/db/utils.py
+++ b/db/utils.py
@@ -96,7 +96,11 @@
 
 @ignore_type_warning
 def get_pg_catalog_table(table_name, engine, metadata):
-    return sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog')
+    table = sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog')
+    # Refresh metadata if it hasn't reflected correctly. Refer https://github.com/centerofci/mathesar/issues/2138
+    if len(table.c) < 1:
+        table = sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog', extend_existing=True)
+    return table
 
 
 def ignore_duplicate_wrapper(stmt):

{"golden_diff": "diff --git a/db/utils.py b/db/utils.py\n--- a/db/utils.py\n+++ b/db/utils.py\n@@ -96,7 +96,11 @@\n \n @ignore_type_warning\n def get_pg_catalog_table(table_name, engine, metadata):\n-    return sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog')\n+    table = sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog')\n+    # Refresh metadata if it hasn't reflected correctly. Refer https://github.com/centerofci/mathesar/issues/2138\n+    if len(table.c) < 1:\n+        table = sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog', extend_existing=True)\n+    return table\n \n \n def ignore_duplicate_wrapper(stmt):\n", "issue": "AttributeError \"attname\" or \"nspname\" from various endpoints\nI have been getting this API error intermittently when making a GET request to the records and columns endpoints. It always happens after making some DDL request, like importing a table, or renaming a columns, or extracting columns -- though I can't reproduce it 100% of the time.\r\n\r\n<details>\r\n<summary>(A) Sometimes I get this \"nspname\" error</summary>\r\n\r\n```\r\nEnvironment:\r\n\r\n\r\nRequest Method: GET\r\nRequest URL: http://localhost:8000/api/db/v0/tables/1894/records/?limit=500&offset=0\r\n\r\nDjango Version: 3.1.14\r\nPython Version: 3.9.16\r\nInstalled Applications:\r\n['django.contrib.admin',\r\n 'django.contrib.auth',\r\n 'django.contrib.contenttypes',\r\n 'django.contrib.sessions',\r\n 'django.contrib.messages',\r\n 'django.contrib.staticfiles',\r\n 'rest_framework',\r\n 'django_filters',\r\n 'django_property_filter',\r\n 'mathesar']\r\nInstalled Middleware:\r\n['django.middleware.security.SecurityMiddleware',\r\n 'django.contrib.sessions.middleware.SessionMiddleware',\r\n 'django.middleware.common.CommonMiddleware',\r\n 'django.middleware.csrf.CsrfViewMiddleware',\r\n 'django.contrib.auth.middleware.AuthenticationMiddleware',\r\n 'django.contrib.messages.middleware.MessageMiddleware',\r\n 'django.middleware.clickjacking.XFrameOptionsMiddleware',\r\n 'mathesar.middleware.CursorClosedHandlerMiddleware',\r\n 'mathesar.middleware.PasswordChangeNeededMiddleware',\r\n 'django_userforeignkey.middleware.UserForeignKeyMiddleware',\r\n 'django_request_cache.middleware.RequestCacheMiddleware']\r\n\r\n\r\n\r\nTraceback (most recent call last):\r\n  File \"/usr/local/lib/python3.9/site-packages/sqlalchemy/sql/base.py\", line 1167, in __getattr__\r\n    return self._index[key]\r\n\r\nThe above exception ('nspname') was the direct cause of the following exception:\r\n  File \"/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py\", line 47, in inner\r\n    response = get_response(request)\r\n  File \"/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py\", line 181, in _get_response\r\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)\r\n  File \"/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py\", line 54, in wrapped_view\r\n    return view_func(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.9/site-packages/rest_framework/viewsets.py\", line 125, in view\r\n    return self.dispatch(request, *args, **kwargs)\r\n  File \"/usr/local/lib/python3.9/site-packages/rest_framework/views.py\", line 509, in dispatch\r\n    response = self.handle_exception(exc)\r\n  File \"/usr/local/lib/python3.9/site-packages/rest_framework/views.py\", line 466, in handle_exception\r\n    response = exception_handler(exc, context)\r\n  File \"/code/mathesar/exception_handlers.py\", line 59, in mathesar_exception_handler\r\n    raise exc\r\n  File \"/usr/local/lib/python3.9/site-packages/rest_framework/views.py\", line 506, in dispatch\r\n    response = handler(request, *args, **kwargs)\r\n  File \"/code/mathesar/api/db/viewsets/records.py\", line 72, in list\r\n    records = paginator.paginate_queryset(\r\n  File \"/code/mathesar/api/pagination.py\", line 81, in paginate_queryset\r\n    self.count = table.sa_num_records(filter=filters, search=search)\r\n  File \"/code/mathesar/models/base.py\", line 471, in sa_num_records\r\n    table=self._sa_table,\r\n  File \"/code/mathesar/state/cached_property.py\", line 62, in __get__\r\n    new_value = self.original_get_fn(instance)\r\n  File \"/code/mathesar/models/base.py\", line 337, in _sa_table\r\n    sa_table = reflect_table_from_oid(\r\n  File \"/code/db/tables/operations/select.py\", line 31, in reflect_table_from_oid\r\n    tables = reflect_tables_from_oids(\r\n  File \"/code/db/tables/operations/select.py\", line 43, in reflect_tables_from_oids\r\n    get_map_of_table_oid_to_schema_name_and_table_name(\r\n  File \"/code/db/tables/operations/select.py\", line 74, in get_map_of_table_oid_to_schema_name_and_table_name\r\n    select(pg_namespace.c.nspname, pg_class.c.relname, pg_class.c.oid)\r\n  File \"/usr/local/lib/python3.9/site-packages/sqlalchemy/sql/base.py\", line 1169, in __getattr__\r\n    util.raise_(AttributeError(key), replace_context=err)\r\n  File \"/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py\", line 207, in raise_\r\n    raise exception\r\n\r\nException Type: AttributeError at /api/db/v0/tables/1894/records/\r\nException Value: nspname\r\n```\r\n\r\n</details>\r\n\r\n<details>\r\n<summary>(B) Other times I get this \"attname\" error</summary>\r\n\r\n```\r\nEnvironment:\r\n\r\n\r\nRequest Method: GET\r\nRequest URL: http://localhost:8000/api/db/v0/tables/1824/records/?limit=500&offset=0\r\n\r\nDjango Version: 3.1.14\r\nPython Version: 3.9.16\r\nInstalled Applications:\r\n['django.contrib.admin',\r\n 'django.contrib.auth',\r\n 'django.contrib.contenttypes',\r\n 'django.contrib.sessions',\r\n 'django.contrib.messages',\r\n 'django.contrib.staticfiles',\r\n 'rest_framework',\r\n 'django_filters',\r\n 'django_property_filter',\r\n 'mathesar']\r\nInstalled Middleware:\r\n['django.middleware.security.SecurityMiddleware',\r\n 'django.contrib.sessions.middleware.SessionMiddleware',\r\n 'django.middleware.common.CommonMiddleware',\r\n 'django.middleware.csrf.CsrfViewMiddleware',\r\n 'django.contrib.auth.middleware.AuthenticationMiddleware',\r\n 'django.contrib.messages.middleware.MessageMiddleware',\r\n 'django.middleware.clickjacking.XFrameOptionsMiddleware',\r\n 'mathesar.middleware.CursorClosedHandlerMiddleware',\r\n 'mathesar.middleware.PasswordChangeNeededMiddleware',\r\n 'django_userforeignkey.middleware.UserForeignKeyMiddleware',\r\n 'django_request_cache.middleware.RequestCacheMiddleware']\r\n\r\n\r\n\r\nTraceback (most recent call last):\r\n  File \"/usr/local/lib/python3.9/site-packages/sqlalchemy/sql/base.py\", line 1167, in __getattr__\r\n    return self._index[key]\r\n\r\nThe above exception ('attname') was the direct cause of the following exception:\r\n  File \"/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py\", line 47, in inner\r\n    response = get_response(request)\r\n  File \"/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py\", line 181, in _get_response\r\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)\r\n  File \"/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py\", line 54, in wrapped_view\r\n    return view_func(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.9/site-packages/rest_framework/viewsets.py\", line 125, in view\r\n    return self.dispatch(request, *args, **kwargs)\r\n  File \"/usr/local/lib/python3.9/site-packages/rest_framework/views.py\", line 509, in dispatch\r\n    response = self.handle_exception(exc)\r\n  File \"/usr/local/lib/python3.9/site-packages/rest_framework/views.py\", line 466, in handle_exception\r\n    response = exception_handler(exc, context)\r\n  File \"/code/mathesar/exception_handlers.py\", line 59, in mathesar_exception_handler\r\n    raise exc\r\n  File \"/usr/local/lib/python3.9/site-packages/rest_framework/views.py\", line 506, in dispatch\r\n    response = handler(request, *args, **kwargs)\r\n  File \"/code/mathesar/api/db/viewsets/records.py\", line 55, in list\r\n    column_names_to_ids = table.get_column_name_id_bidirectional_map()\r\n  File \"/code/mathesar/models/base.py\", line 554, in get_column_name_id_bidirectional_map\r\n    columns_map = bidict({column.name: column.id for column in columns})\r\n  File \"/usr/local/lib/python3.9/site-packages/django/db/models/query.py\", line 287, in __iter__\r\n    self._fetch_all()\r\n  File \"/code/mathesar/utils/prefetch.py\", line 158, in _fetch_all\r\n    prefetcher.fetch(obj_list, name, self.model, forwarders)\r\n  File \"/code/mathesar/utils/prefetch.py\", line 270, in fetch\r\n    related_data = self.filter(data_mapping.keys(), data_mapping.values())\r\n  File \"/code/mathesar/models/base.py\", line 225, in filter\r\n    return get_map_of_attnum_to_column_name(\r\n  File \"/code/db/columns/operations/select.py\", line 91, in get_map_of_attnum_to_column_name\r\n    triples_of_col_info = _get_triples_of_column_name_and_attnum_and_table_oid(\r\n  File \"/code/db/columns/operations/select.py\", line 104, in _get_triples_of_column_name_and_attnum_and_table_oid\r\n    statement = _statement_for_triples_of_column_name_and_attnum_and_table_oid(\r\n  File \"/code/db/columns/operations/select.py\", line 180, in _statement_for_triples_of_column_name_and_attnum_and_table_oid\r\n    sel = select(pg_attribute.c.attname, pg_attribute.c.attnum, pg_attribute.c.attrelid)\r\n  File \"/usr/local/lib/python3.9/site-packages/sqlalchemy/sql/base.py\", line 1169, in __getattr__\r\n    util.raise_(AttributeError(key), replace_context=err)\r\n  File \"/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py\", line 207, in raise_\r\n    raise exception\r\n\r\nException Type: AttributeError at /api/db/v0/tables/1824/records/\r\nException Value: attname\r\n```\r\n\r\n</details>\r\n\r\nThe exact same steps will sometimes produce (A), other times produce (B), and other times no error at all. I hit these errors a lot while working on #2140. I was doing a workflow where I'd import `books_sim.ts`, then extract the author's first and last names into a new table. I did it over and over again. I probably hit the error about 75% of the time during import and 60% of the time during column extraction.\r\n\r\nhttps://user-images.githubusercontent.com/42411/208746906-86d06e41-18d0-45da-8d39-32aa8fddecba.mp4\r\n\r\n\n", "before_files": [{"content": "import inspect\nimport warnings\n\nfrom psycopg2.errors import UndefinedFunction\n\nimport sqlalchemy\nfrom sqlalchemy.exc import ProgrammingError\n\nfrom db.records import exceptions\n\n\ndef execute_statement(engine, statement, connection_to_use=None):\n    try:\n        if connection_to_use:\n            return connection_to_use.execute(statement)\n        else:\n            with engine.begin() as conn:\n                return conn.execute(statement)\n    except ProgrammingError as e:\n        if isinstance(e.orig, UndefinedFunction):\n            message = e.orig.args[0].split('\\n')[0]\n            raise exceptions.UndefinedFunction(message)\n        else:\n            raise e\n\n\ndef execute_pg_query(engine, query, connection_to_use=None):\n    if isinstance(query, sqlalchemy.sql.expression.Executable):\n        executable = query\n    else:\n        executable = sqlalchemy.select(query)\n    return execute_statement(engine, executable, connection_to_use=connection_to_use).fetchall()\n\n\n# TODO refactor to use @functools.total_ordering\nclass OrderByIds:\n    \"\"\"\n    A mixin for ordering based on ids; useful at least for type enums in testing.\n    \"\"\"\n\n    id: str  # noqa: NT001\n\n    def __ge__(self, other):\n        if self._ordering_supported(other):\n            return self.id >= other.id\n        return NotImplemented\n\n    def __gt__(self, other):\n        if self._ordering_supported(other):\n            return self.id > other.id\n        return NotImplemented\n\n    def __le__(self, other):\n        if self._ordering_supported(other):\n            return self.id <= other.id\n        return NotImplemented\n\n    def __lt__(self, other):\n        if self._ordering_supported(other):\n            return self.id < other.id\n        return NotImplemented\n\n    def _ordering_supported(self, other):\n        return hasattr(other, 'id')\n\n\ndef get_module_members_that_satisfy(module, predicate):\n    \"\"\"\n    Looks at the members of the provided module and filters them using the provided predicate.\n\n    Currently used to automatically collect all concrete subclasses of some abstract superclass\n    found as top-level members of a module.\n    \"\"\"\n    all_members_in_defining_module = inspect.getmembers(module)\n    return set(\n        member\n        for _, member in all_members_in_defining_module\n        if predicate(member)\n    )\n\n\ndef ignore_type_warning(f):\n    \"\"\"\n    When loading PostgreSQL system tables, an SAWarning is often generated\n    since they use some exotic, postgres-specific types.\n\n    This decorator allows one to ignore those warnings.\n    \"\"\"\n    def warning_ignored_func(*args, **kwargs):\n        with warnings.catch_warnings():\n            warnings.filterwarnings(\"ignore\", message=\"Did not recognize type\")\n            return f(*args, **kwargs)\n\n    return warning_ignored_func\n\n\n@ignore_type_warning\ndef get_pg_catalog_table(table_name, engine, metadata):\n    return sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog')\n\n\ndef ignore_duplicate_wrapper(stmt):\n    return f\"\"\"\n    DO $$ BEGIN\n    {stmt}\n    EXCEPTION\n    WHEN duplicate_object THEN null;\n    END $$;\n    \"\"\"\n", "path": "db/utils.py"}], "after_files": [{"content": "import inspect\nimport warnings\n\nfrom psycopg2.errors import UndefinedFunction\n\nimport sqlalchemy\nfrom sqlalchemy.exc import ProgrammingError\n\nfrom db.records import exceptions\n\n\ndef execute_statement(engine, statement, connection_to_use=None):\n    try:\n        if connection_to_use:\n            return connection_to_use.execute(statement)\n        else:\n            with engine.begin() as conn:\n                return conn.execute(statement)\n    except ProgrammingError as e:\n        if isinstance(e.orig, UndefinedFunction):\n            message = e.orig.args[0].split('\\n')[0]\n            raise exceptions.UndefinedFunction(message)\n        else:\n            raise e\n\n\ndef execute_pg_query(engine, query, connection_to_use=None):\n    if isinstance(query, sqlalchemy.sql.expression.Executable):\n        executable = query\n    else:\n        executable = sqlalchemy.select(query)\n    return execute_statement(engine, executable, connection_to_use=connection_to_use).fetchall()\n\n\n# TODO refactor to use @functools.total_ordering\nclass OrderByIds:\n    \"\"\"\n    A mixin for ordering based on ids; useful at least for type enums in testing.\n    \"\"\"\n\n    id: str  # noqa: NT001\n\n    def __ge__(self, other):\n        if self._ordering_supported(other):\n            return self.id >= other.id\n        return NotImplemented\n\n    def __gt__(self, other):\n        if self._ordering_supported(other):\n            return self.id > other.id\n        return NotImplemented\n\n    def __le__(self, other):\n        if self._ordering_supported(other):\n            return self.id <= other.id\n        return NotImplemented\n\n    def __lt__(self, other):\n        if self._ordering_supported(other):\n            return self.id < other.id\n        return NotImplemented\n\n    def _ordering_supported(self, other):\n        return hasattr(other, 'id')\n\n\ndef get_module_members_that_satisfy(module, predicate):\n    \"\"\"\n    Looks at the members of the provided module and filters them using the provided predicate.\n\n    Currently used to automatically collect all concrete subclasses of some abstract superclass\n    found as top-level members of a module.\n    \"\"\"\n    all_members_in_defining_module = inspect.getmembers(module)\n    return set(\n        member\n        for _, member in all_members_in_defining_module\n        if predicate(member)\n    )\n\n\ndef ignore_type_warning(f):\n    \"\"\"\n    When loading PostgreSQL system tables, an SAWarning is often generated\n    since they use some exotic, postgres-specific types.\n\n    This decorator allows one to ignore those warnings.\n    \"\"\"\n    def warning_ignored_func(*args, **kwargs):\n        with warnings.catch_warnings():\n            warnings.filterwarnings(\"ignore\", message=\"Did not recognize type\")\n            return f(*args, **kwargs)\n\n    return warning_ignored_func\n\n\n@ignore_type_warning\ndef get_pg_catalog_table(table_name, engine, metadata):\n    table = sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog')\n    # Refresh metadata if it hasn't reflected correctly. Refer https://github.com/centerofci/mathesar/issues/2138\n    if len(table.c) < 1:\n        table = sqlalchemy.Table(table_name, metadata, autoload_with=engine, schema='pg_catalog', extend_existing=True)\n    return table\n\n\ndef ignore_duplicate_wrapper(stmt):\n    return f\"\"\"\n    DO $$ BEGIN\n    {stmt}\n    EXCEPTION\n    WHEN duplicate_object THEN null;\n    END $$;\n    \"\"\"\n", "path": "db/utils.py"}]}