doctrine / dbal

Doctrine Database Abstraction Layer
https://www.doctrine-project.org/projects/dbal.html
MIT License
9.48k stars 1.34k forks source link

DBAL-1168: Schema's getMigrateFromSql always adds CREATE SCHEMA #1110

Closed doctrinebot closed 2 years ago

doctrinebot commented 9 years ago

Jira issue originally created by user vbence:

I originally posted this to Migrations; noticing that all the generated down() methods start with a "CREATE SCHEMA public" line.

Inspecting the return from Schema#getMigrateFromSql it indeed contains the create statement.

doctrinebot commented 9 years ago

Comment created by asentner:

I am also having this issue. The down() method always adds: $this->addSql('CREATE SCHEMA public');

Same environment, also using Postgres.

Any chance this is on anyone's radar for a release in the near future?

doctrinebot commented 9 years ago

Comment created by acasademont:

Hit by this too. The problem seems to be that the "public" namespace is not added to the table names by default and hence the diff between what postgres says (a "public" schema is created by default in the DB) and what our schema says.

I tried to solve this with a workaround by prepending "public." to all table names. It works for the first migration but then in the next migration will try to delete all tables without the "public." and create them again. So that's not working!

The solution is assuming that there's always a default 'public' namespace in the Schema.php class.

cleentfaar commented 8 years ago

Any updates on this? Would be nice to get rid of this in our version files

josensanchez commented 8 years ago

As @doctrinebot commented, the problem seems to be here:

        $fromSchema = $conn->getSchemaManager()->createSchema();
        $toSchema = $this->getSchemaProvider()->createSchema();

the first line builds the schema querying the database

SELECT schema_name AS nspname
          FROM   information_schema.schemata
...

and the second one builds it from the ORM metadata in your application

@ORM\Table(name="table_1" ...

there is a "public" schema in $fromSchema but since there is no @ORM\Table(name="table_1", schema="public"...) also there is no "public" schema in $toSchema

trying the @doctrinebot workaround @ORM\Table(name="table_1", schema="public"...) it's also useless as he already commented because table_1 and public.table_1 are two different things to the dbal, witch is logic. but it will try to perform the next code every time.

create table public.table_1 ...  -- table already exists exception
drop table table_1

the drop command is without the "public." and I assume that it's to add support to tables without namespaces...

I don't see an easy solution for this issue. Either finding a way to define table_1 as an alias for public.table_1 (maybe in postgresql if a database object doesn't have a namespace defined, then the 'public' namespace is attached to it) or removing support in postgresql for no namespace objects, forcing always to define schema="public"

for the moment if anybody is working with postgresql and doctrine I suggest to use only the public schema or not use it at all.

idchlife commented 8 years ago

Yep, waiting issue to be resolved

garex commented 8 years ago

Can't use diff commands as schema always differs by those CREATE SCHEMA public.

Melkij commented 8 years ago

My workaround without modify library and waiting patch. Add class in any namespace in application:

<?php

namespace EngineBundle\Doctrine;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;

class MigrationEventSubscriber implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return array(
            'postGenerateSchema',
        );
    }

    public function postGenerateSchema(GenerateSchemaEventArgs $Args)
    {
        $Schema = $Args->getSchema();

        if (! $Schema->hasNamespace('public')) {
            $Schema->createNamespace('public');
        }
    }
}

Register event subscriber. For symfony this can be done in config:

# app/config/services.yml
services:
    doctrineMigrationDiffListener:
        class: EngineBundle\Doctrine\MigrationEventSubscriber
        tags:
            - { name: doctrine.event_subscriber, connection: default }

Works for me, no more useless CREATE SCHEMA public in down migration.

teohhanhui commented 8 years ago

@Melkij What about other schemas? For example when using PostGIS.

garex commented 8 years ago

@teohhanhui see my PR #2490

There is $platform->getDefaultSchemaName() -- then it will be unversal. Currently 'public' is hardcoded value in this solution.

Melkij commented 8 years ago

@teohhanhui I test only public schema. This is just workaround for my project, not complete solution. I think same hasNamespace + createNamespace needed for any schemas, which is not used in any Entity. And for schemas in search_path setting.

vudaltsov commented 7 years ago

Created a bundle addressing this issue

isaackearl commented 7 years ago

If you are using the Laravel doctrine package, here is a workaround: https://github.com/laravel-doctrine/migrations/issues/51

alemosk commented 7 years ago

If it very old and very hard bug, why not replace constant 'CREATE SCHEMA ' to 'CREATE SCHEMA IF NOT EXISTS ' ?

Not beauty, but will no exceptions.

Ocramius commented 7 years ago

Silent failures are the worst failures

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/

On Thu, Jul 13, 2017 at 4:17 PM, alemosk notifications@github.com wrote:

If it very old and very hard bug, why not replace constant 'CREATE SCHEMA ' to 'CREATE SCHEMA IF NOT EXISTS ' ?

Not beauty, but will no exceptions.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/doctrine/dbal/issues/1110#issuecomment-315091252, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJakEloMbcE7GNgVQTAZ-5UK9C8-EKjks5sNibwgaJpZM4HXQHQ .

vudaltsov commented 6 years ago

I think, I found a cleaner solution. At least for PostgreSQL. And it looks like it follows @deeky666's advice in https://github.com/doctrine/dbal/pull/2490#issuecomment-272990941 since it uses AbstractSchemaManager::getSchemaSearchPaths() through PostgreSqlSchemaManager::determineExistingSchemaSearchPaths().

<?php

declare(strict_types=1);

namespace App\EventListener;

use Doctrine\Common\EventSubscriber;
use Doctrine\DBAL\Schema\PostgreSqlSchemaManager;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use Doctrine\ORM\Tools\ToolEvents;

class FixDefaultSchemaListener implements EventSubscriber
{
    /**
     * {@inheritdoc}
     */
    public function getSubscribedEvents(): array
    {
        return [
            ToolEvents::postGenerateSchema,
        ];
    }

    public function postGenerateSchema(GenerateSchemaEventArgs $args): void
    {
        $schemaManager = $args->getEntityManager()
            ->getConnection()
            ->getSchemaManager();

        if (!$schemaManager instanceof PostgreSqlSchemaManager) {
            return;
        }

        foreach ($schemaManager->getExistingSchemaSearchPaths() as $namespace) {
            if (!$args->getSchema()->hasNamespace($namespace)) {
                $args->getSchema()->createNamespace($namespace);
            }
        }
    }
}
yurtesen commented 6 years ago

I have also faced with this problem.

greg0ire commented 6 years ago

@vudaltsov I don't think this bug happens on anything but Postgres, does it? Maybe create a PR?

antonmedv commented 6 years ago

Any updates?

Ocramius commented 6 years ago

@antonmedv can you provide a failing test case for the DBAL test suite?

antonmedv commented 6 years ago

I think @garex already did: https://github.com/doctrine/dbal/pull/2490/files#diff-27e8892e001d5c205813663f22e02b32R18

igorjacauna commented 6 years ago

Any updates? I stopped a migration of project to doctrine because of this. :disappointed:

morozov commented 6 years ago

@igorjacauna I do not recall any work on this issue during the last year, so most likely no updates. Please feel free to submit a failing test.

garex commented 6 years ago

@igorjacauna I suggest you to switch to hibernate ))

PedroDiSanti commented 6 years ago

Is this bug still occurring while using Symfony 4 + Postgres? Thanks for any help!

mneute commented 6 years ago

@PedroDiSanti : Yes, this is still occuring

PedroDiSanti commented 6 years ago

@PedroDiSanti : Yes, this is still occuring

Thanks, mate.

melyouz commented 5 years ago

This is still occuring. Even when there are no migrations to generate, the following line is added:

$this->addSql('CREATE SCHEMA public');

Full generated migration content could be found here.

vasilvestre commented 5 years ago

Still occurring, got some fresh news?

Ocramius commented 5 years ago

@vasilvestre pick up https://github.com/doctrine/dbal/pull/2490 if you can work on it.

ghost commented 5 years ago

Anyone know how to implement https://github.com/doctrine/dbal/issues/1110#issuecomment-352177498 into a symfony4 project? What yaml file does it go into, and where?

Any help would be awesome.

vudaltsov commented 5 years ago

@pc-trent , https://gist.github.com/vudaltsov/ec01012d3fe27c9eed59aa7fd9089cf7

ghost commented 5 years ago

@vudaltsov - legend thanks!

Autsider666 commented 3 years ago

@vudaltsov 2 years later and you're still a legend!

aleksandrphilippov commented 2 years ago

@vudaltsov Any updates?

TheFox commented 2 years ago

@vudaltsov 3 years later and you're still a legend.

greg0ire commented 2 years ago

Notes to self:

Doesn't this mean this is actually a bug in doctrine/migrations (since it's building the desired schema)? If yes, should @Melkij / @vudaltsov 's fix be implemented in doctrine/migrations + DoctrineMigrationsBundle?

myselfhimself commented 2 years ago

Thanks! Very good to fix the following error on PostgreSQL + symfony + doctrine:

 Creating database schema...

In ToolsException.php line 19:

  Schema-Tool failed with Error 'An exception occurred while executing a query: SQLSTATE[42P06]: Duplicate schema: 7 ERROR:  schema "public" already exists' while executing DDL: CREATE SCHEMA public  

In ExceptionConverter.php line 87:

  An exception occurred while executing a query: SQLSTATE[42P06]: Duplicate schema: 7 ERROR:  schema "public" already exists  

In Exception.php line 28:

  SQLSTATE[42P06]: Duplicate schema: 7 ERROR:  schema "public" already exists  

In Connection.php line 69:

  SQLSTATE[42P06]: Duplicate schema: 7 ERROR:  schema "public" already exists  

doctrine:schema:create [--em EM] [--dump-sql]
myselfhimself commented 2 years ago

Hmm actually it is problematic for doctrine:schema:create, here is a variant fix:

<?php

namespace EngineBundle\Doctrine;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;

/**
 * @see https://github.com/doctrine/dbal/issues/1110#issuecomment-255765189
 */
class MigrationEventSubscriber implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return array(
            'postGenerateSchema',
        );
    }

    public function postGenerateSchema(GenerateSchemaEventArgs $Args)
    {
        // This listener helps to prevent generating 'down' migrations trying to remove a 'public' schema for ever
        // however it confuses the doctrine:schema:create command which tries to recreate a 'public' table.
        // The workaround is to run doctrine:schema:create command with the following environment variable
        // set to a non-empty value, then unsetting that variable forever.
        if(empty(getenv('NO_PUBLIC_SCHEMA_CREATE_PLEASE'))) {
            $Schema = $Args->getSchema();

            if (! $Schema->hasNamespace('public')) {
                $Schema->createNamespace('public');
            }
        }
    }
}

And running thedoctrine:schema:create command: NO_PUBLIC_SCHEMA_CREATE_PLEASE=yes php bin/console doctrine:schema:create But that environment variable is removed for all cases: php bin/console make:migration

github-actions[bot] commented 2 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.