diff --git a/src/bundle/Core/Resources/config/doctrine_migrations.yml b/src/bundle/Core/Resources/config/doctrine_migrations.yml index 3ef2ca6eb5..62bf1c9cb4 100644 --- a/src/bundle/Core/Resources/config/doctrine_migrations.yml +++ b/src/bundle/Core/Resources/config/doctrine_migrations.yml @@ -78,3 +78,11 @@ services: $connection: '@ibexa.persistence.connection' tags: - { name: !php/const Ibexa\Contracts\DoctrineMigrations\Migrations\IbexaMigrationTag::TAG } + + Ibexa\Bundle\RepositoryInstaller\Migration\ConvertPostgreSqlSerialColumnsToIdentityMigration: + autowire: true + public: false + arguments: + $connection: '@ibexa.persistence.connection' + tags: + - { name: !php/const Ibexa\Contracts\DoctrineMigrations\Migrations\IbexaMigrationTag::TAG } diff --git a/src/bundle/RepositoryInstaller/Migration/ConvertPostgreSqlSerialColumnsToIdentityMigration.php b/src/bundle/RepositoryInstaller/Migration/ConvertPostgreSqlSerialColumnsToIdentityMigration.php new file mode 100644 index 0000000000..a78b22f86c --- /dev/null +++ b/src/bundle/RepositoryInstaller/Migration/ConvertPostgreSqlSerialColumnsToIdentityMigration.php @@ -0,0 +1,57 @@ +abortIfUnsupportedPlatform(SqlPlatform::MYSQL, SqlPlatform::MARIADB, SqlPlatform::POSTGRESQL, SqlPlatform::SQLITE); + + if ($this->isPostgreSQL()) { + $this->addSqlFile(__DIR__ . '/sql/convert-serial-columns-to-identity-postgresql.sql'); + } + } +} diff --git a/src/bundle/RepositoryInstaller/Migration/sql/convert-serial-columns-to-identity-postgresql.sql b/src/bundle/RepositoryInstaller/Migration/sql/convert-serial-columns-to-identity-postgresql.sql new file mode 100644 index 0000000000..f417fee97e --- /dev/null +++ b/src/bundle/RepositoryInstaller/Migration/sql/convert-serial-columns-to-identity-postgresql.sql @@ -0,0 +1,60 @@ +DO $$ +DECLARE + serial_column record; + sequence_name text; + old_last_value bigint; + old_is_called boolean; +BEGIN + FOR serial_column IN SELECT * FROM (VALUES + ('ibexa_content', 'id'), + ('ibexa_content_bookmark', 'id'), + ('ibexa_content_field', 'id'), + ('ibexa_content_relation', 'id'), + ('ibexa_content_tree', 'node_id'), + ('ibexa_content_type', 'id'), + ('ibexa_content_type_field_definition', 'id'), + ('ibexa_content_type_group', 'id'), + ('ibexa_content_version', 'id'), + ('ibexa_image_file', 'id'), + ('ibexa_keyword', 'id'), + ('ibexa_keyword_field_link', 'id'), + ('ibexa_node_assignment', 'id'), + ('ibexa_notification', 'id'), + ('ibexa_object_state', 'id'), + ('ibexa_object_state_group', 'id'), + ('ibexa_package', 'id'), + ('ibexa_policy', 'id'), + ('ibexa_policy_limitation', 'id'), + ('ibexa_policy_limitation_value', 'id'), + ('ibexa_role', 'id'), + ('ibexa_search_object_word_link', 'id'), + ('ibexa_search_word', 'id'), + ('ibexa_section', 'id'), + ('ibexa_setting', 'id'), + ('ibexa_token', 'id'), + ('ibexa_token_type', 'id'), + ('ibexa_url', 'id'), + ('ibexa_url_alias', 'id'), + ('ibexa_url_alias_ml_incr', 'id'), + ('ibexa_url_wildcard', 'id'), + ('ibexa_user_accountkey', 'id'), + ('ibexa_user_preference', 'id'), + ('ibexa_user_role', 'id') + ) AS c (table_name, column_name) + LOOP + -- A SERIAL column defaults to nextval(''::regclass); an identity column has no default. + SELECT substring(column_default FROM 'nextval\(''([^'']+)''::regclass\)') INTO sequence_name + FROM information_schema.columns + WHERE table_schema = current_schema() + AND table_name = serial_column.table_name + AND column_name = serial_column.column_name; + CONTINUE WHEN sequence_name IS NULL; + + EXECUTE format('SELECT last_value, is_called FROM %s', sequence_name) INTO old_last_value, old_is_called; + EXECUTE format('ALTER TABLE %I ALTER %I DROP DEFAULT', serial_column.table_name, serial_column.column_name); + EXECUTE format('DROP SEQUENCE %s', sequence_name); + EXECUTE format('ALTER TABLE %I ALTER %I ADD GENERATED BY DEFAULT AS IDENTITY', serial_column.table_name, serial_column.column_name); + PERFORM setval(pg_get_serial_sequence(serial_column.table_name, serial_column.column_name), old_last_value, old_is_called); + END LOOP; +END +$$;