diff --git a/context_chat_backend/repair/repair5004_date20260716145303.py b/context_chat_backend/repair/repair5004_date20260716145303.py new file mode 100644 index 00000000..8d74e4f5 --- /dev/null +++ b/context_chat_backend/repair/repair5004_date20260716145303.py @@ -0,0 +1,40 @@ +# +# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later +# +import os + +import sqlalchemy as sa + +''' +Drop the "id" column from the access_list table since its auto-increment sequence +(32-bit integer) gets exhausted after many ownership modifications, causing: + psycopg.errors.SequenceGeneratorLimitExceeded: nextval: reached maximum value of + sequence "access_list_id_seq" (2147483647) +Also, "id" isn't used anywhere except as a primary key. + +The composite (uid, source_id) key is promoted to primary key instead. +''' + + +def run(_previous_version: int): + db_url = os.environ.get('CCB_DB_URL') + if not db_url: + print('CCB_DB_URL not set, skipping "id" column drop from "access_list" table', flush=True) + return + + engine = sa.create_engine(db_url) + with engine.connect() as conn: + # Drop the unique index that we'll convert to primary key + conn.execute(sa.text( + 'DROP INDEX IF EXISTS uid_chunk_id_idx' + )) + # Drop the id column (also removes the old PK constraint and sequence) + conn.execute(sa.text( + 'ALTER TABLE access_list DROP COLUMN IF EXISTS id' + )) + # Add the primary key constraint using the existing unique columns + conn.execute(sa.text( + 'ALTER TABLE access_list ADD CONSTRAINT access_list_pkey PRIMARY KEY (uid, source_id)' + )) + conn.commit() diff --git a/context_chat_backend/vectordb/pgvector.py b/context_chat_backend/vectordb/pgvector.py index e562f94a..382baff0 100644 --- a/context_chat_backend/vectordb/pgvector.py +++ b/context_chat_backend/vectordb/pgvector.py @@ -79,8 +79,6 @@ class AccessListStore(Base): __tablename__ = ACCESS_LIST_TABLE_NAME - id: orm.Mapped[int] = orm.mapped_column(primary_key=True, autoincrement=True) - uid: orm.Mapped[str] = orm.mapped_column(nullable=False) source_id: orm.Mapped[str] = orm.mapped_column( sa.ForeignKey( @@ -91,16 +89,15 @@ class AccessListStore(Base): ) __table_args__ = ( - sa.Index( - 'uid_chunk_id_idx', + sa.PrimaryKeyConstraint( 'uid', 'source_id', - unique=True, + name='access_list_pkey', ), sa.Index( 'idx_access_list_source_id', 'source_id', - ) + ), ) @classmethod @@ -348,7 +345,7 @@ def decl_update_access(self, user_ids: list[str], source_id: str, session_: orm. } for user_id in batched_uids ]) - .on_conflict_do_nothing(index_elements=['uid', 'source_id']) + .on_conflict_do_nothing(constraint='access_list_pkey') ) session.execute(stmt) @@ -402,7 +399,7 @@ def update_access( } for user_id in batched_uids ]) - .on_conflict_do_nothing(index_elements=['uid', 'source_id']) + .on_conflict_do_nothing(constraint='access_list_pkey') ) session.execute(stmt) session.commit()