mojolicious / mojo-pg

Mojolicious :heart: PostgreSQL
https://metacpan.org/release/Mojo-Pg
Artistic License 2.0
101 stars 46 forks source link

prepare statements break migration #78

Open abraxxa opened 3 years ago

abraxxa commented 3 years ago

Steps to reproduce the behavior

Create a migration SQL file which contains PREPARE statements for inserting data:

PREPARE v1_role (text) AS
INSERT INTO role (name)
VALUES ($1);

EXECUTE v1_role('Role A');

EXECUTE v1_role('Role B');

EXECUTE v1_role('Role C');

PREPARE v1_rel_ramuser_role (integer, integer) AS
INSERT INTO rel_ramuser_role (ramuser_id, role_id)
VALUES ($1, $2);

EXECUTE v1_rel_ramuser_role(1, 1);

EXECUTE v1_rel_ramuser_role(1, 2);

EXECUTE v1_rel_ramuser_role(1, 3);

Enable auto migration on startup:

sub startup ($self) {
    # Load configuration from config file
    $self->plugin('NotYAMLConfig');

    $self->helper(
        pg => sub { state $pg = Mojo::Pg->new( shift->config('pg') ) } );

    # Migrate to latest version if necessary
    my $path = $self->home->child( 'migrations', 'ram.sql' );
    $self->pg->auto_migrate(1)->migrations->name('ram')->from_file($path);
    $self->log->info(
        "current database version: " . $self->pg->migrations->active );
}

Expected behavior

Migration SQL run without errors.

Actual behavior

DBD::Pg::st execute failed: ERROR:  invalid input syntax for type integer: "ram"
LINE 63: VALUES ('1', 'ram');
                      ^ at /home/alex/.plenv/versions/5.32.1/lib/perl5/site_perl/5.32.1/Mojo/Pg/Migrations.pm line 77.

export DBI_TRACE=SQL shows the following SQL getting executed:

EXECUTE SELECT version FROM mojo_migrations WHERE name = $1 (
$1: ram
);

CREATE TABLE IF NOT EXISTS mojo_migrations (
       name    TEXT PRIMARY KEY,
       version BIGINT NOT NULL CHECK (version >= 0)
     );

EXECUTE INSERT INTO mojo_migrations VALUES ($1, $2) (
$1: ram
$2: 0
);

begin;

LOCK TABLE mojo_migrations IN EXCLUSIVE MODE;

PREPARE dbdpg_p204881_1 AS SELECT version FROM mojo_migrations WHERE name = $1;

EXECUTE dbdpg_p204881_1 (
$1: ram
);

-- 1 up
-- various create table statements etc.
PREPARE v1_role (text) AS
INSERT INTO role (name)
VALUES ('1');

EXECUTE v1_role('Role A');

EXECUTE v1_role('Role B');

EXECUTE v1_role('Role C');

PREPARE v1_rel_ramuser_role (integer, integer) AS
INSERT INTO rel_ramuser_role (ramuser_id, role_id)
VALUES ('1', 'ram');

EXECUTE v1_rel_ramuser_role(1, 1);

EXECUTE v1_rel_ramuser_role(1, 2);

EXECUTE v1_rel_ramuser_role(1, 3);
;UPDATE mojo_migrations SET version = '1' WHERE name = 'ram';;

DBD::Pg::st execute failed: ERROR:  invalid input syntax for type integer: "ram"
LINE 63: VALUES ('1', 'ram');
                      ^ at /home/alex/.plenv/versions/5.32.1/lib/perl5/site_perl/5.32.1/Mojo/Pg/Migrations.pm line 77.
rollback;

DEALLOCATE dbdpg_p204881_1;

When the second prepare statement is removed from the SQL file, it works also as expected so the different data types seem to cause the issue. This shouldn't be an issue as all prepare statements are named.