[info] == Running PixelMetrics.Repo.Migrations.AddIndexesToForeignKeysOnActionsTable.change/0 forward
[info] create index if not exists actions_store_id_index
** (Postgrex.Error) ERROR 25001 (active_sql_transaction): CREATE INDEX CONCURRENTLY cannot run inside a transaction block
(ecto) lib/ecto/adapters/sql.ex:200: Ecto.Adapters.SQL.query!/5
(ecto) lib/ecto/adapters/postgres.ex:85: anonymous fn/4 in Ecto.Adapters.Postgres.execute_ddl/3
(elixir) lib/enum.ex:1899: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto) lib/ecto/adapters/postgres.ex:85: Ecto.Adapters.Postgres.execute_ddl/3
(ecto) lib/ecto/migration/runner.ex:104: anonymous fn/2 in Ecto.Migration.Runner.flush/0
(elixir) lib/enum.ex:1899: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto) lib/ecto/migration/runner.ex:102: Ecto.Migration.Runner.flush/0
(stdlib) timer.erl:181: :timer.tc/2
(ecto) lib/ecto/migration/runner.ex:26: Ecto.Migration.Runner.run/6
(ecto) lib/ecto/migrator.ex:128: Ecto.Migrator.attempt/6
(ecto) lib/ecto/migrator.ex:73: anonymous fn/4 in Ecto.Migrator.do_up/4
(ecto) lib/ecto/migrator.ex:261: anonymous fn/4 in Ecto.Migrator.migrate/4
(elixir) lib/enum.ex:1294: Enum."-map/2-lists^map/1-0-"/2
(ecto) lib/mix/tasks/ecto.migrate.ex:83: anonymous fn/4 in Mix.Tasks.Ecto.Migrate.run/2
(elixir) lib/enum.ex:737: Enum."-each/2-lists^foreach/1-0-"/2
(elixir) lib/enum.ex:737: Enum.each/2
(mix) lib/mix/task.ex:314: Mix.Task.run_task/3
(mix) lib/mix/cli.ex:80: Mix.CLI.run_task/2
Expected behavior
The migration runs outside a transaction. ;)
@matthewlehner could you please investigate? According to the test we were supposed to detect it just fine: https://github.com/elixir-ecto/ecto/blob/v2.2.8/lib/ecto/migrator.ex#L114-L123
So we are missing something somewhere.
Here you go!
https://github.com/matthewlehner/concurrent_indexes
From my precursory trace through the logic, it looks like it does hit Ecto.Migrator.run_maybe_in_transaction/3
and runs fun.()
under the true
condition, not module.__migration__[:disable_ddl_transaction]
.
Beyond that, I got lost… Also, maybe don't rely on what I've said above, I'm not familiar enough with how macros result in this code to be super confident in my diagnosis and got to this point by adding IEx.pry()
in the function.
Migration doesn't disable transactions
create_if_not_exists with index doesn't work with concurrently
Feb 10, 2018
Good catch. This stack overflow post has more information about it: https://dba.stackexchange.com/questions/35616/create-index-if-it-does-not-exist
The proper statement that works with CONCURRENTLY is only available on Postgres 9.5 which is quite recent, so I don't feel like we should impose it onto users.
My suggestion is for you to run this particular command at the SQL level:
execute "CREATE INDEX CONCURRENTLY IF NOT EXISTS ...."
I am pretty sure this works now. The following (slightly doctored 😄) has shown to work locally using Postgres.
defmodule MyApp.Repo.Migrations.CreateFooNumbersGinIndexes do
use Ecto.Migration
@disable_ddl_transaction true
@disable_migration_lock true
def change do
execute "CREATE EXTENSION IF NOT EXISTS pg_trgm", "DROP EXTENSION pg_trgm"
create_if_not_exists index(:foos, ["foo_number gin_trgm_ops"],
name: "foos_foo_number_gin_trgm_idx",
concurrently: true,
using: :gin