]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Fixes: #11724 - PGDialect `get_multi_indexes` PGVecto.rs Bug
authorNick Wilkinson <nicholas.w@solenya.ai>
Fri, 6 Dec 2024 06:59:22 +0000 (01:59 -0500)
committerFederico Caselli <cfederico87@gmail.com>
Sat, 7 Dec 2024 17:01:05 +0000 (18:01 +0100)
When attempting to generate an auto-revision using Alembic, the `get_multi_indexes` method fails with the error:
```python
    dialect_options["postgresql_with"] = dict(
ValueError: dictionary update sequence element #0 has length 4; 2 is required
```

### Description

The cause of this error is that when creating a vector index in PGVecto.rs, the index is:
```sql
CREATE INDEX vector_embedding_idx ON public.vector_embeddings USING vectors (embedding vector_cos_ops) WITH (options='
                    [indexing.hnsw]
                    m = 16
                    ef_construction = 64
                ')
```

However, in PostgreSQL the index seems to be generated as:
```sql
CREATE INDEX vector_embedding_idx ON public.vector_embeddings USING hnsw (embedding vector_cos_ops) WITH (m='16', ef_construction='64');
```

To fix this, we need to modify:
```diff
if row["reloptions"]:
-    dialect_options["postgresql_with"] = dict([option.split("=") for option in row["reloptions"]])
+    dialect_options["postgresql_with"] = dict([option.split("=", 1) for option in row["reloptions"]])
```

For more details on this error and a reproducible example, refer to #11724

### Testing

I couldn't really think of an easy way to add the potential test suggested in the issue thread [here](https://github.com/sqlalchemy/sqlalchemy/issues/11724#issuecomment-2518501318). However, this code is already tested in [`test_get_multi_view_indexes`](https://github.com/sqlalchemy/sqlalchemy/blob/5ded16fae8abfc31d43430cb25757fb434c37ba2/test/dialect/postgresql/test_reflection.py#L378), so assuming that test still passes and nothing breaks I believe we should be fine.

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [ ] A documentation / typographical / small typing error fix
- Good to go, no issue or tests are needed
- [x] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

Closes: #12162
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/12162
Pull-request-sha: 7d996fd92dd24a7d79bccab090d22bd76564dc76

Change-Id: Id6ad86133f3221eefcf0aa799c7f79a754e9c1bf
(cherry picked from commit 9eacf3408d1deeb42fc1ecc6002437b898ecc397)

doc/build/changelog/unreleased_20/11724.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/postgresql/base.py

diff --git a/doc/build/changelog/unreleased_20/11724.rst b/doc/build/changelog/unreleased_20/11724.rst
new file mode 100644 (file)
index 0000000..3e8c436
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: bug, postgresql
+    :ticket: 11724
+
+    Fixes issue in `get_multi_indexes` in postgresql dialect, where an error
+    would be thrown when attempting to use alembic with a vector index from
+    the pgvecto.rs extension.
index e3920857a8705c4700ed9d6a2105b9aa156194f9..cd3ebfd597265a7f26d043ef744d40c7cb7844ec 100644 (file)
@@ -4603,7 +4603,10 @@ class PGDialect(default.DefaultDialect):
                     dialect_options = {}
                     if row["reloptions"]:
                         dialect_options["postgresql_with"] = dict(
-                            [option.split("=") for option in row["reloptions"]]
+                            [
+                                option.split("=", 1)
+                                for option in row["reloptions"]
+                            ]
                         )
                     # it *might* be nice to include that this is 'btree' in the
                     # reflection info.  But we don't want an Index object