Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does flyway migrations support PostgreSQL's COPY?

Having performed a pg_dump of an existing posgresql schema, I have an sql file containing a number of table population statements using the copy.

COPY test_table (id, itm, factor, created_timestamp, updated_timestamp, updated_by_user, version) FROM stdin;
1   600 0.000   2012-07-17 18:12:42.360828  2012-07-17 18:12:42.360828  system  0
2   700 0.000   2012-07-17 18:12:42.360828  2012-07-17 18:12:42.360828  system  0
\.

Though not standard this is part of PostgreSQL's PLSQL implementation.

Performing a flyway migration (via the maven plugin) I get:

[ERROR] Caused by org.postgresql.util.PSQLException: ERROR: unexpected message type 0x50 during COPY from stein

Am I doing something wrong, or is this just not supported?

Thanks.

like image 416
englishteeth Avatar asked Jul 17 '12 17:07

englishteeth


People also ask

Does Flyway support rollback?

For rollbacks to work, an undo script needs to be maintained for each forward versioned migration between the currently deployed version and the version to roll back to. Undo scripts need to reverse the change made by the corresponding versioned migration and ensure that any data manipulation is reversed.

What are some of the supported databases that Flyway is compatible with?

Supported databases are Oracle, SQL Server (including Amazon RDS and Azure SQL Database), Azure Synapse (Formerly Data Warehouse), DB2, MySQL (including Amazon RDS, Azure Database & Google Cloud SQL), Aurora MySQL, MariaDB, Percona XtraDB Cluster, TestContainers, PostgreSQL (including Amazon RDS, Azure Database, Google ...

What is repeatable migration in Flyway?

Repeatable migrations have a description and a checksum, but no version. Instead of being run just once, they are (re-)applied every time their checksum changes. This is very useful for managing database objects whose definition can then simply be maintained in a single file in version control.

Which is better Liquibase or Flyway?

While both tools are based on Martin Fowler's Evolutionary Database, there are many differences in what these tools offer. Here's where Liquibase and Flyway differ. The bottom line is that Liquibase is more powerful and flexible — covering more database change and deployment use cases than Flyway.


2 Answers

The short answer is no.

The one definite problem is that the parser is currently not able to deal with this special construct.

The other question is jdbc driver support. Could you try and see if this syntax generally supported by the jdbc driver with a single createStatement call?

If it is, please file an issue in the issue tracker and I'll extend the parser.

Update: This is now supported

like image 166
Axel Fontaine Avatar answered Oct 04 '22 03:10

Axel Fontaine


I have accomplished this for Postgres using

public abstract class SeedData implements JdbcMigration {

    protected static final String CSV_COPY_STRING = "COPY %s(%s) FROM STDIN HEADER DELIMITER ',' CSV ENCODING 'UTF-8'";

    protected CopyManager copyManager;

    @Override
    public void migrate(Connection connection) throws Exception {
        log.info(String.format("[%s] Populating database with seed data", getClass().getName()));
        copyManager = new CopyManager((BaseConnection) connection);

        Resource[] resources = scanForResources();

        List<Resource> res = Arrays.asList(resources);
        for (Resource resource : res) {
            load(resource);
        }
    }

    private void load(Resource resource) throws SQLException, IOException {
        String location = resource.getLocation();

        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(location);
        if (inputStream == null) {
            throw new FlywayException("Failure to load seed data. Unable to load from location: " + location);
        }
        if (!inputStream.markSupported()) {
            // Sanity check. We have to be able to mark the stream.
            throw new FlywayException(
                    "Failure to load seed data as mark is not supported. Unable to load from location: " + location);
        }
        // set our mark to something big
        inputStream.mark(1 << 32);

        String filename = resource.getFilename();
        // Strip the prefix (e.g. 01_) and the file extension (e.g. .csv)
        String table = filename.substring(3, filename.length() - 4);
        String columns = loadCsvHeader(location, inputStream);

        // reset to the mark
        inputStream.reset();

        // Use Postgres COPY command to bring it in
        long result = copyManager.copyIn(String.format(CSV_COPY_STRING, table, columns), inputStream);
        log.info(format("   %s - Inserted %d rows", location, result));
    }

    private String loadCsvHeader(String location, InputStream inputStream) {
        try {
            return new BufferedReader(new InputStreamReader(inputStream)).readLine();
        } catch (IOException e) {
            throw new FlywayException("Failure to load seed data. Unable to load from location: " + location, e);
        }
    }

    private Resource[] scanForResources() throws IOException {
        return new ClassPathScanner(getClass().getClassLoader()).scanForResources(getSeedDataLocation(), "", ".csv");
    }

    protected String getSeedDataLocation() {
        return getClass().getPackage().getName().replace('.', '/');
    }

}

To use implement the class with the appropriate classpath

package db.devSeedData.dev;

public class v0_90__seed extends db.devSeedData.v0_90__seed {
}

All that is needed then is to have CSV files in your classpath under db/devSeedData that follow the format 01_tablename.csv. Columns are extracted from the header line of the CSV.

like image 29
Collin Peters Avatar answered Oct 04 '22 01:10

Collin Peters