Skip to content

Catch IndexAlreadyExists#4710

Merged
dartcafe merged 2 commits into
mainfrom
fix/pgsql-index-creation
May 11, 2026
Merged

Catch IndexAlreadyExists#4710
dartcafe merged 2 commits into
mainfrom
fix/pgsql-index-creation

Conversation

@dartcafe
Copy link
Copy Markdown
Collaborator

  • Catch exception on index creation with pgsql, because the detections does not seem to be reliable in any cases

Further research is going on, but this should fix #4694 for the moment.

Signed-off-by: dartcafe <github@dartcafe.de>
@dartcafe dartcafe added this to the 9.1.2 milestone May 11, 2026
@dartcafe
Copy link
Copy Markdown
Collaborator Author

The problem seems to be the column comparison:

/**
* Check if two column lists match, ignoring order.
* @param string[] $existing list of columns in existing index
* @param string[] $expected list of columns in expected index definition
* @return bool true if the lists match, false otherwise
*/
private function columnsMatch(array $existing, array $expected): bool {
sort($existing);
sort($expected);
return $existing === $expected;
}

PostgreSQL seems to put indexed columns into quotes, if the column name matches reserved keywords.

By logging the comparison in case of the catch, the problem becomes visible:

IndexAlreadyExists caught for oc_polls_options: expected columns ["poll_id","poll_option_hash","timestamp"], existing indexes: idx_9aa5663c947c0f[poll_id] | oc_polls_options_pkey[id] UNIQUE | uniq_9aa5663c947c0fbd4bf59a5d6e63e[poll_id,poll_option_hash,"timestamp"] UNIQUE

Expected is We expect ['poll_id', 'poll_option_hash', 'timestamp'] but instead we get ['poll_id', 'poll_option_hash', '"timestamp"']

This also explains, why we get this error only with the options and the watch tables. table is a reserved keyword, too.

@dartcafe
Copy link
Copy Markdown
Collaborator Author

dartcafe commented May 11, 2026

So let's use Doctrine\DBAL\Schema::getUnquotedColumns() instead of Doctrine\DBAL\Schema::getColumns()

Keep the catch with the logging, although it should never be necessary to catch this situation.

@dartcafe
Copy link
Copy Markdown
Collaborator Author

Test results:

A) Catch with getColumns()
Catch Exception and skip creation ... (detected via exception) ...

 - Polls - Create all unique indices
     - Unique index for ["poll_id","poll_option_hash","timestamp"] already exists in polls_options (detected via exception). Skip creation.
     - Unique index for ["processed","poll_id","user_id","message_id"] already exists as uniq_3710b4a427fb1b8b3c947c0fa76ed395537a1329 in polls_log
     - Unique index for ["poll_id","user_id"] already exists as uniq_33f0715d3c947c0fa76ed395 in polls_notif
     - Unique index for ["poll_id","group_id","user_id"] already exists as uniq_1c85e16c3c947c0ffe54d947a76ed395 in polls_share
     - Unique index for ["token"] already exists as uniq_1c85e16c5f37a13b in polls_share
     - Unique index for ["poll_id","user_id","vote_option_hash"] already exists as uniq_a20806f93c947c0fa76ed3958a3bfe0f in polls_votes
     - Unique index for ["user_id"] already exists as uniq_4f5e9bd7a76ed395 in polls_preferences
     - Unique index for ["poll_id","table","session_id"] already exists in polls_watch (detected via exception). Skip creation.
     - Unique index for ["poll_id","group_id"] already exists as uniq_99598f933c947c0ffe54d947 in polls_groups_polls
     - Polls - Indices created.

B) Catch with getUnqotedColumns()
Recognize index existence before createIndex(): ... already exists as ...

 - Polls - Create all unique indices
     - Unique index for ["poll_id","poll_option_hash","timestamp"] already exists as uniq_9aa5663c947c0fbd4bf59a5d6e63e in polls_options
     - Unique index for ["processed","poll_id","user_id","message_id"] already exists as uniq_3710b4a427fb1b8b3c947c0fa76ed395537a1329 in polls_log
     - Unique index for ["poll_id","user_id"] already exists as uniq_33f0715d3c947c0fa76ed395 in polls_notif
     - Unique index for ["poll_id","group_id","user_id"] already exists as uniq_1c85e16c3c947c0ffe54d947a76ed395 in polls_share
     - Unique index for ["token"] already exists as uniq_1c85e16c5f37a13b in polls_share
     - Unique index for ["poll_id","user_id","vote_option_hash"] already exists as uniq_a20806f93c947c0fa76ed3958a3bfe0f in polls_votes
     - Unique index for ["user_id"] already exists as uniq_4f5e9bd7a76ed395 in polls_preferences
     - Unique index for ["poll_id","table","session_id"] already exists as uniq_a38836103c947c0ff6298f46613fecdf in polls_watch
     - Unique index for ["poll_id","group_id"] already exists as uniq_99598f933c947c0ffe54d947 in polls_groups_polls
     - Polls - Indices created.

Signed-off-by: dartcafe <github@dartcafe.de>
@dartcafe dartcafe merged commit b3e926f into main May 11, 2026
50 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

An index with name "uniq_9aa5663c947c0fbd4bf59a5d6e63e" was already defined on table "oc_polls_options

1 participant