Current section
27 Versions
Jump to
Current section
27 Versions
Compare versions
7
files changed
+139
additions
-48
deletions
| @@ -1,3 +1,11 @@ | |
| 1 | + ## [0.13.0] - 2024-06-27 |
| 2 | + |
| 3 | + **New migration patches:** 9 |
| 4 | + |
| 5 | + ### Fixed |
| 6 | + |
| 7 | + - Fix `set_transaction_id` trigger not using the PK index on `transactions` due to being dependent on `CURRVAL` for every row. Replaced with a CTE the `EXIST` query is now an index-only scan as it was intended to be. As a consequence, scalability of inserts into the `transactions` table has been greatly improved. |
| 8 | + |
| 1 9 | ## [0.12.1] - 2024-05-21 |
| 2 10 | |
| 3 11 | ### Fixed |
| @@ -93,7 +93,7 @@ Due to its use of [`pg_current_xact_id`](https://www.postgresql.org/docs/13/func | |
| 93 93 | # mix.exs |
| 94 94 | def deps do |
| 95 95 | [ |
| 96 | - {:carbonite, "~> 0.12.1"} |
| 96 | + {:carbonite, "~> 0.13.0"} |
| 97 97 | ] |
| 98 98 | end |
| 99 99 | ``` |
| @@ -120,7 +120,7 @@ defmodule MyApp.Repo.Migrations.InstallCarbonite do | |
| 120 120 | use Ecto.Migration |
| 121 121 | |
| 122 122 | def up do |
| 123 | - Carbonite.Migrations.up(1..8) |
| 123 | + Carbonite.Migrations.up(1..9) |
| 124 124 | |
| 125 125 | # For each table that you want to capture changes of, you need to install the trigger. |
| 126 126 | Carbonite.Migrations.create_trigger(:rabbits) |
| @@ -140,7 +140,7 @@ defmodule MyApp.Repo.Migrations.InstallCarbonite do | |
| 140 140 | Carbonite.Migrations.drop_trigger(:rabbits) |
| 141 141 | |
| 142 142 | # Drop the Carbonite tables. |
| 143 | - Carbonite.Migrations.down(8..1) |
| 143 | + Carbonite.Migrations.down(9..1) |
| 144 144 | end |
| 145 145 | end |
| 146 146 | ``` |
| @@ -1,6 +1,6 @@ | |
| 1 1 | {<<"links">>,[{<<"github">>,<<"https://github.com/bitcrowd/carbonite">>}]}. |
| 2 2 | {<<"name">>,<<"carbonite">>}. |
| 3 | - {<<"version">>,<<"0.12.1">>}. |
| 3 | + {<<"version">>,<<"0.13.0">>}. |
| 4 4 | {<<"description">>,<<"Audit trails for Elixir/PostgreSQL based on triggers">>}. |
| 5 5 | {<<"elixir">>,<<"~> 1.11">>}. |
| 6 6 | {<<"app">>,<<"carbonite">>}. |
| @@ -22,19 +22,20 @@ | |
| 22 22 | {<<"requirement">>,<<"~> 0.15 and >= 0.15.11">>}, |
| 23 23 | {<<"repository">>,<<"hexpm">>}]]}. |
| 24 24 | {<<"files">>, |
| 25 | - [<<"lib">>,<<"lib/carbonite">>,<<"lib/carbonite/trigger.ex">>, |
| 26 | - <<"lib/carbonite/schema.ex">>,<<"lib/carbonite/prefix.ex">>, |
| 27 | - <<"lib/carbonite/change.ex">>,<<"lib/carbonite/migrations">>, |
| 28 | - <<"lib/carbonite/migrations/helper.ex">>, |
| 29 | - <<"lib/carbonite/migrations/v3.ex">>,<<"lib/carbonite/migrations/v1.ex">>, |
| 30 | - <<"lib/carbonite/migrations/v7.ex">>,<<"lib/carbonite/migrations/v2.ex">>, |
| 31 | - <<"lib/carbonite/migrations/v6.ex">>, |
| 25 | + [<<"lib">>,<<"lib/carbonite">>,<<"lib/carbonite/migrations">>, |
| 32 26 | <<"lib/carbonite/migrations/version.ex">>, |
| 33 | - <<"lib/carbonite/migrations/v8.ex">>,<<"lib/carbonite/migrations/v5.ex">>, |
| 34 | - <<"lib/carbonite/migrations/v4.ex">>,<<"lib/carbonite/query.ex">>, |
| 35 | - <<"lib/carbonite/outbox.ex">>,<<"lib/carbonite/migrations.ex">>, |
| 36 | - <<"lib/carbonite/transaction.ex">>,<<"lib/carbonite/multi.ex">>, |
| 37 | - <<"lib/carbonite.ex">>,<<"lib/mix">>,<<"lib/mix/tasks">>, |
| 38 | - <<"lib/mix/tasks/carbonite.gen.initial_migration.ex">>,<<".formatter.exs">>, |
| 39 | - <<"mix.exs">>,<<"README.md">>,<<"LICENSE">>,<<"CHANGELOG.md">>]}. |
| 27 | + <<"lib/carbonite/migrations/v5.ex">>,<<"lib/carbonite/migrations/v2.ex">>, |
| 28 | + <<"lib/carbonite/migrations/v3.ex">>,<<"lib/carbonite/migrations/v6.ex">>, |
| 29 | + <<"lib/carbonite/migrations/helper.ex">>, |
| 30 | + <<"lib/carbonite/migrations/v7.ex">>,<<"lib/carbonite/migrations/v4.ex">>, |
| 31 | + <<"lib/carbonite/migrations/v9.ex">>,<<"lib/carbonite/migrations/v1.ex">>, |
| 32 | + <<"lib/carbonite/migrations/v8.ex">>,<<"lib/carbonite/change.ex">>, |
| 33 | + <<"lib/carbonite/schema.ex">>,<<"lib/carbonite/outbox.ex">>, |
| 34 | + <<"lib/carbonite/multi.ex">>,<<"lib/carbonite/transaction.ex">>, |
| 35 | + <<"lib/carbonite/prefix.ex">>,<<"lib/carbonite/query.ex">>, |
| 36 | + <<"lib/carbonite/trigger.ex">>,<<"lib/carbonite/migrations.ex">>, |
| 37 | + <<"lib/mix">>,<<"lib/mix/tasks">>, |
| 38 | + <<"lib/mix/tasks/carbonite.gen.initial_migration.ex">>, |
| 39 | + <<"lib/carbonite.ex">>,<<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>, |
| 40 | + <<"LICENSE">>,<<"CHANGELOG.md">>]}. |
| 40 41 | {<<"build_tools">>,[<<"mix">>]}. |
| @@ -18,7 +18,7 @@ defmodule Carbonite.Migrations do | |
| 18 18 | # --------------------------------- patch levels --------------------------------- |
| 19 19 | |
| 20 20 | @initial_patch 1 |
| 21 | - @current_patch 8 |
| 21 | + @current_patch 9 |
| 22 22 | |
| 23 23 | @doc false |
| 24 24 | @spec initial_patch :: non_neg_integer() |
| @@ -125,6 +125,40 @@ defmodule Carbonite.Migrations.V4 do | |
| 125 125 | :ok |
| 126 126 | end |
| 127 127 | |
| 128 | + @spec create_set_transaction_id_procedure(prefix()) :: :ok |
| 129 | + def create_set_transaction_id_procedure(prefix) do |
| 130 | + """ |
| 131 | + CREATE OR REPLACE FUNCTION #{prefix}.set_transaction_id() RETURNS TRIGGER AS |
| 132 | + $body$ |
| 133 | + BEGIN |
| 134 | + BEGIN |
| 135 | + /* verify that no previous INSERT within current transaction (with same id) */ |
| 136 | + IF |
| 137 | + EXISTS( |
| 138 | + SELECT 1 FROM #{prefix}.transactions |
| 139 | + WHERE id = COALESCE(NEW.id, CURRVAL('#{prefix}.transactions_id_seq')) |
| 140 | + AND xact_id = COALESCE(NEW.xact_id, pg_current_xact_id()) |
| 141 | + ) |
| 142 | + THEN |
| 143 | + NEW.id = COALESCE(NEW.id, CURRVAL('#{prefix}.transactions_id_seq')); |
| 144 | + END IF; |
| 145 | + EXCEPTION WHEN object_not_in_prerequisite_state THEN |
| 146 | + /* when NEXTVAL has never been called within session, we're good */ |
| 147 | + END; |
| 148 | + |
| 149 | + NEW.id = COALESCE(NEW.id, NEXTVAL('#{prefix}.transactions_id_seq')); |
| 150 | + NEW.xact_id = COALESCE(NEW.xact_id, pg_current_xact_id()); |
| 151 | + |
| 152 | + RETURN NEW; |
| 153 | + END |
| 154 | + $body$ |
| 155 | + LANGUAGE plpgsql; |
| 156 | + """ |
| 157 | + |> squish_and_execute() |
| 158 | + |
| 159 | + :ok |
| 160 | + end |
| 161 | + |
| 128 162 | @impl true |
| 129 163 | @spec up([up_option()]) :: :ok |
| 130 164 | def up(opts) do |
| @@ -161,34 +195,7 @@ defmodule Carbonite.Migrations.V4 do | |
| 161 195 | """ |
| 162 196 | |> squish_and_execute() |
| 163 197 | |
| 164 | - """ |
| 165 | - CREATE OR REPLACE FUNCTION #{prefix}.set_transaction_id() RETURNS TRIGGER AS |
| 166 | - $body$ |
| 167 | - BEGIN |
| 168 | - BEGIN |
| 169 | - /* verify that no previous INSERT within current transaction (with same id) */ |
| 170 | - IF |
| 171 | - EXISTS( |
| 172 | - SELECT 1 FROM #{prefix}.transactions |
| 173 | - WHERE id = COALESCE(NEW.id, CURRVAL('#{prefix}.transactions_id_seq')) |
| 174 | - AND xact_id = COALESCE(NEW.xact_id, pg_current_xact_id()) |
| 175 | - ) |
| 176 | - THEN |
| 177 | - NEW.id = COALESCE(NEW.id, CURRVAL('#{prefix}.transactions_id_seq')); |
| 178 | - END IF; |
| 179 | - EXCEPTION WHEN object_not_in_prerequisite_state THEN |
| 180 | - /* when NEXTVAL has never been called within session, we're good */ |
| 181 | - END; |
| 182 | - |
| 183 | - NEW.id = COALESCE(NEW.id, NEXTVAL('#{prefix}.transactions_id_seq')); |
| 184 | - NEW.xact_id = COALESCE(NEW.xact_id, pg_current_xact_id()); |
| 185 | - |
| 186 | - RETURN NEW; |
| 187 | - END |
| 188 | - $body$ |
| 189 | - LANGUAGE plpgsql; |
| 190 | - """ |
| 191 | - |> squish_and_execute() |
| 198 | + create_set_transaction_id_procedure(prefix) |
| 192 199 | |
| 193 200 | # ------------- override_xact_id ------------- |
Loading more files…