migrations icon indicating copy to clipboard operation
migrations copied to clipboard

Version Table in Schema Named After the Connecting User Always Tries to be Re-Created

Open chrisguitarguy opened this issue 5 years ago • 3 comments

Bug Report

Q A
BC Break no
Version 2.1.1

Summary

I've got a postgres database with two schemas: public and {userName} (where {userName} is the name of my connecting user). My migration versions table is in {userName}.migration_versions.

When migrations attempts to figure out whether the table exists, it always determines that it does not exist and attempts to recreate. Which causes an error.

Current behavior

An initial run of a migraitons:* command will create the version table perfectly in the correct schema and such. But subsequent runs will always try to create the table again.

How to reproduce

Create a postgres database with two schemas and put the migration versions table in the non public schema.

I also suspect it's important that the other schema comes before the public in the query that generates the search paths (see below).

Expected behavior

Migrations shouldn't try to recreate the table each time.

DBAL has a bug open for this: https://github.com/doctrine/dbal/issues/1599 and https://github.com/doctrine/dbal/issues/2491, but it seems like this might be expected behavior in DBAL (the table does exist and the search path would make that the case were you to run queries on it).

Maybe a work around would be to use listTableDetails or something like that to determine if the table exists.

chrisguitarguy avatar Aug 01 '19 16:08 chrisguitarguy

I guess you can workaround this by specifying the table name as public.migration_versions. In this way if will not fallback on the postgres search_pathvariable

goetas avatar Oct 17 '19 16:10 goetas

Old issue, but I got the same one recently, so here is my analysis.

When you connect with username to a postgres db the search path is "$user",public.

The version table is created again because the method used to check if the table exists remove the first schema of the search path. When you're connected with username, the PostgreSqlSchemaManager::_getPortableTableDefinition() remove the username part of the table name because it is the first schema in the search path. Then when it try to check if username.migration_versions is in the list it fail.

You can try to solve defining in doctrine migration config migration_versions instead of username.migration_versions. As migration_versions is the first schema of the path, the table will be created in the correct schema, not in public.

But if you have a second migration table, with the same name, but in the schema public, a new error will appear because retrieving the list of tables, doctrine will call PostgreSqlPlatform::getListTableForeignKeysSQL() and the query will fail because the subquery will returns more than one row.

With the current process to determine if a given table exists, we do not have a correct solution. In my case I'll use something like username.username_migration_versions to get the table in the correct schema but with a unique name accross all schemas.

other possibilities are to update the postgres config to always have public un first on the search path instead of $user, or do not use a schema and a user with the same value.

geelweb avatar Feb 08 '22 11:02 geelweb

I was hit by the same bug today (Doctrine Migrations 3.6.0) and can confirm @geelweb's analysis. In case it can be useful, the behavior can be narrowed down to these four cases:

User / schema names table_name setting Finds the table?
Same Without schema Succeeds
Same With schema Fails
Different Without schema Fails
Different With schema Succeeds

marcverney avatar Sep 18 '23 23:09 marcverney