migrate icon indicating copy to clipboard operation
migrate copied to clipboard

pq: relation "schema_migrations" does not exist in line 0: TRUNCATE "schema_migrations"

Open zemirco opened this issue 5 years ago • 12 comments

Hey,

I've recently upgraded from version 3 to the latest version v4.3.1. Since then I'm getting the error.

pq: relation "schema_migrations" does not exist in line 0: TRUNCATE "schema_migrations"

I looked around at StackOverflow and here in existing issues. I think it might have something to do with search_path but so far I couldn't find a solution that works for me.

I have set up a demo repo with Circle CI integration which shows my problem. Here is my code https://github.com/zemirco/golang-migrate-err and here is the failing test https://circleci.com/gh/zemirco/golang-migrate-err/2.

Migrate Version v4.3.1

Loaded Source Drivers file

Loaded Database Drivers postgres

Go Version go version go1.12 linux/amd64

Here is my demo code

func main() {
	source := "user=postgres host=localhost dbname=postgres sslmode=disable"
	db, err := sql.Open("postgres", source)
	if err != nil {
		panic(err)
	}
	if err := db.Ping(); err != nil {
		panic(err)
	}
	driver, err := postgres.WithInstance(db, &postgres.Config{})
	if err != nil {
		panic(err)
	}
	migration, err := migrate.NewWithDatabaseInstance("file://migrations", "postgres", driver)
	if err != nil {
		panic(err)
	}
	if err := migration.Drop(); err != nil {
		panic(err)
	}
	if err := migration.Up(); err != nil {
		panic(err)
	}
}

The Up migration fails. The funny thing is that when I only run Drop without Up OR only Up without Drop everything works. However during development it's nice to start with a clean db every time. So I'd like to use both.

zemirco avatar May 21 '19 09:05 zemirco

This sounds like an issue that was introduced in v4.3.0. Namely, after Migrate.Drop() is called, the schema version table is no longer recreated.

Maybe we should rethink how/when the schema version table is created...

In the meanwhile, you can create a new Migrate instance, to run your migrations after running Migrate.Drop()

dhui avatar May 21 '19 18:05 dhui

This sounds like an issue that was introduced in v4.3.0. Namely, after Migrate.Drop() is called, the schema version table is no longer recreated.

Maybe we should rethink how/when the schema version table is created...

In the meanwhile, you can create a new Migrate instance, to run your migrations after running Migrate.Drop()

This does indeed break the behaviour we depended on in our service and I think having Up recreate the migrations table if it does not exist, as we were using Drop() and Up() to reset the db state in our integration tests and it was working very well so far.

Are there any downsides to doing it this way? Could you maybe explain a little bit more on how the v4 behaviour results in better flows?

aignas avatar Sep 16 '19 15:09 aignas

Are there any downsides to doing it this way? Could you maybe explain a little bit more on how the v4 behaviour results in better flows?

There are issues with how the db locks are managed by migration which probably can't be addressed w/o a breaking change. e.g. the locks are managed by migrate except when the schema version table is created, then it's managed by the db driver

One idea is to make the db driver explicitly support schema version table creation (probably in the new driver interface) so the locks can be fully managed by the migrate again. Then we can explore the best places in the migration workflow to ensure the schema version table.

For efficiency reasons, we probably don't want to re-create or check schema version table on every run or invocation. Maybe every we only check it on every Up() run? We don't want to do it on Drop() since that's suppose to leave the db in a clean state.

dhui avatar Oct 15 '19 04:10 dhui

Hello so I am running into this issue and pq: relation "schema_migrations" does not exist in line 0: TRUNCATE "schema_migrations" too - but it does create my tables and schemas, at this point should I always see this error message when I up until the above mentioned is thought through and fixed?

also based on my pgadmin dashboard I see the following after up

image

mdere-unbound avatar Oct 25 '19 13:10 mdere-unbound

In the meanwhile, you can create a new Migrate instance, to run your migrations after running Migrate.Drop()

Two migrate instances also result in the same error.

ankur-anand avatar May 09 '20 05:05 ankur-anand

Does anyone know any solutions to this issue?

mathbalduino avatar Aug 25 '20 19:08 mathbalduino

I use two migrate instances (only for my test environment):

m1, _ := migrate.New(migrationURL, pgURL)
	
err = m1.Drop()
if err != nil && err.Error() != "no change" {
	log.Fatal(err)
}

m2, _ := migrate.New(migrationURL, pgURL)

err = m2.Up()
if err != nil && err.Error() != "no change" {
	log.Fatal(err)
}

carlows avatar Aug 25 '20 19:08 carlows

I use two migrate instances (only for my test environment):

m1, _ := migrate.New(migrationURL, pgURL)
	
err = m1.Drop()
if err != nil && err.Error() != "no change" {
	log.Fatal(err)
}

m2, _ := migrate.New(migrationURL, pgURL)

err = m2.Up()
if err != nil && err.Error() != "no change" {
	log.Fatal(err)
}

Thanks for trying to help me, but I was looking for a more concise way to do this. I don't think that creating a new connection is the solution, as it can lead to other issues.

(Instead of comparing Error() strings, you can just use the migrate.ErrNoChange)

mathbalduino avatar Aug 25 '20 20:08 mathbalduino

I was running into this and was sort of confused as to what was going on. It turns out that because I created my initial migrations with pg_dump it had prepended some information about setting the search_path. pg_dump nullifies the search path and then explicitly creates all the tables with their schema prefix after that. My understanding is that because of the way migrate is running all of this stuff it's just using the search path. In other words, if you have this one line from the dump in your migration it will result in this error.

SELECT pg_catalog.set_config('search_path', '', false);

Just grep for that in your migrations and get rid of it if that's the case. You most likely don't need that in there, and your migrations will still work properly.

trevoro avatar Aug 26 '20 00:08 trevoro

My understanding is that because of the way migrate is running all of this stuff it's just using the search path.

@trevoro Your understanding is correct. Thanks for sharing your solution!

dhui avatar Sep 14 '20 05:09 dhui

does anyone have solution for this? in my case i got this error when i only run Up() with db with schema_infomations table

hieplam avatar Jul 15 '21 08:07 hieplam

I had the same issue with MySQL and some of my tests

I thought this had to be something related with concurrency, while one test was migrating the Database the other was running a Drop.

By default Golang usually sets the -p parameter to a value higher than 1:

 -p n
        the number of programs, such as build commands or
        test binaries, that can be run in parallel.
        The default is the number of CPUs available.

Quick and dirty solution is to set -p 1 when running your tests, but the performance will decrease.

dvigueras avatar Feb 13 '23 10:02 dvigueras