Search in sources :

Example 1 with PostgresDatabase

use of liquibase.database.core.PostgresDatabase in project opennms by OpenNMS.

the class SetSequenceGeneratorTest method testWithMultipleTables.

@Test
public void testWithMultipleTables() {
    for (final Database database : TestContext.getInstance().getAllDatabases()) {
        if (database instanceof PostgresDatabase) {
            final SetSequenceStatement statement = new SetSequenceStatement("SEQUENCE_NAME");
            statement.addTable("TABLE1_NAME", "COLUMN1_NAME");
            statement.addTable("TABLE2_NAME", "COLUMN2_NAME");
            if (shouldBeImplementation(database)) {
                final SqlGenerator<SetSequenceStatement> generator = this.generatorUnderTest;
                final String tempTableName = ((SetSequenceGenerator) generator).getTempTableName();
                final Sql[] sql = generator.generateSql(statement, database, null);
                assertEquals("SELECT pg_catalog.setval('SEQUENCE_NAME',(SELECT max(" + tempTableName + ".id)+1 AS id FROM ((SELECT max(COLUMN1_NAME) AS id FROM TABLE1_NAME LIMIT 1) UNION (SELECT max(COLUMN2_NAME) AS id FROM TABLE2_NAME LIMIT 1)) AS " + tempTableName + " LIMIT 1),true);", sql[0].toSql());
            }
        }
    }
}
Also used : SetSequenceStatement(liquibase.ext.opennms.setsequence.SetSequenceStatement) SetSequenceGenerator(liquibase.ext.opennms.setsequence.SetSequenceGenerator) PostgresDatabase(liquibase.database.core.PostgresDatabase) PostgresDatabase(liquibase.database.core.PostgresDatabase) Database(liquibase.database.Database) Sql(liquibase.sql.Sql) AbstractSqlGeneratorTest(liquibase.sqlgenerator.AbstractSqlGeneratorTest) Test(org.junit.Test)

Example 2 with PostgresDatabase

use of liquibase.database.core.PostgresDatabase in project opennms by OpenNMS.

the class SetSequenceGeneratorTest method testBasicOperation.

@Test
public void testBasicOperation() {
    for (final Database database : TestContext.getInstance().getAllDatabases()) {
        if (database instanceof PostgresDatabase) {
            final SetSequenceStatement statement = new SetSequenceStatement("SEQUENCE_NAME");
            statement.addTable("TABLE_NAME", "COLUMN1_NAME");
            if (shouldBeImplementation(database)) {
                final SqlGenerator<SetSequenceStatement> generator = this.generatorUnderTest;
                final String tempTableName = ((SetSequenceGenerator) generator).getTempTableName();
                final Sql[] sql = generator.generateSql(statement, database, null);
                assertEquals("SELECT pg_catalog.setval('SEQUENCE_NAME',(SELECT max(" + tempTableName + ".id)+1 AS id FROM ((SELECT max(COLUMN1_NAME) AS id FROM TABLE_NAME LIMIT 1)) AS " + tempTableName + " LIMIT 1),true);", sql[0].toSql());
            }
        }
    }
}
Also used : SetSequenceStatement(liquibase.ext.opennms.setsequence.SetSequenceStatement) SetSequenceGenerator(liquibase.ext.opennms.setsequence.SetSequenceGenerator) PostgresDatabase(liquibase.database.core.PostgresDatabase) PostgresDatabase(liquibase.database.core.PostgresDatabase) Database(liquibase.database.Database) Sql(liquibase.sql.Sql) AbstractSqlGeneratorTest(liquibase.sqlgenerator.AbstractSqlGeneratorTest) Test(org.junit.Test)

Example 3 with PostgresDatabase

use of liquibase.database.core.PostgresDatabase in project opennms by OpenNMS.

the class AddNamedAutoIncrementChange method generateStatements.

@Override
public SqlStatement[] generateStatements(final Database database) {
    final List<SqlStatement> statements = new ArrayList<>();
    if (database instanceof PostgresDatabase) {
        String sequenceName = m_sequenceName;
        if (m_sequenceName == null) {
            sequenceName = (getTableName() + "_" + getColumnName() + "_seq").toLowerCase();
            statements.add(new CreateSequenceStatement(getSchemaName(), sequenceName));
        }
        statements.add(new SetNullableStatement(getSchemaName(), getTableName(), getColumnName(), null, false));
        statements.add(new AddDefaultValueStatement(getSchemaName(), getTableName(), getColumnName(), getColumnDataType(), new DatabaseFunction("NEXTVAL('" + sequenceName + "')")));
        return statements.toArray(new SqlStatement[0]);
    } else {
        return super.generateStatements(database);
    }
}
Also used : SqlStatement(liquibase.statement.SqlStatement) PostgresDatabase(liquibase.database.core.PostgresDatabase) SetNullableStatement(liquibase.statement.core.SetNullableStatement) DatabaseFunction(liquibase.statement.DatabaseFunction) CreateSequenceStatement(liquibase.statement.core.CreateSequenceStatement) ArrayList(java.util.ArrayList) AddDefaultValueStatement(liquibase.statement.core.AddDefaultValueStatement)

Example 4 with PostgresDatabase

use of liquibase.database.core.PostgresDatabase in project liquibase by liquibase.

the class AddAutoIncrementChange method generateStatements.

@Override
public SqlStatement[] generateStatements(Database database) {
    if (database instanceof PostgresDatabase) {
        String sequenceName = (getTableName() + "_" + getColumnName() + "_seq");
        String escapedTableName = database.escapeObjectName(getTableName(), Table.class);
        String escapedColumnName = database.escapeObjectName(getColumnName(), Table.class);
        if ((escapedTableName != null) && (escapedColumnName != null) && !escapedTableName.startsWith("\"") && !escapedColumnName.startsWith("\"")) {
            sequenceName = sequenceName.toLowerCase(Locale.US);
        }
        String schemaPrefix;
        if (this.schemaName == null) {
            schemaPrefix = database.getDefaultSchemaName();
        } else {
            schemaPrefix = this.schemaName;
        }
        SequenceNextValueFunction nvf = new SequenceNextValueFunction(schemaPrefix, sequenceName);
        return new SqlStatement[] { new CreateSequenceStatement(catalogName, this.schemaName, sequenceName), new SetNullableStatement(catalogName, this.schemaName, getTableName(), getColumnName(), null, false), new AddDefaultValueStatement(catalogName, this.schemaName, getTableName(), getColumnName(), getColumnDataType(), nvf) };
    }
    return new SqlStatement[] { new AddAutoIncrementStatement(getCatalogName(), getSchemaName(), getTableName(), getColumnName(), getColumnDataType(), getStartWith(), getIncrementBy(), getDefaultOnNull(), getGenerationType()) };
}
Also used : PostgresDatabase(liquibase.database.core.PostgresDatabase) SqlStatement(liquibase.statement.SqlStatement) SetNullableStatement(liquibase.statement.core.SetNullableStatement) CreateSequenceStatement(liquibase.statement.core.CreateSequenceStatement) SequenceNextValueFunction(liquibase.statement.SequenceNextValueFunction) AddAutoIncrementStatement(liquibase.statement.core.AddAutoIncrementStatement) AddDefaultValueStatement(liquibase.statement.core.AddDefaultValueStatement)

Example 5 with PostgresDatabase

use of liquibase.database.core.PostgresDatabase in project liquibase by liquibase.

the class LoadDataChange method generateStatements.

@Override
public SqlStatement[] generateStatements(Database database) {
    boolean databaseSupportsBatchUpdates = false;
    try {
        if (!(database instanceof MySQLDatabase)) {
            // mysql supports batch updates, but the performance vs. the big insert is worse
            databaseSupportsBatchUpdates = database.supportsBatchUpdates();
        }
    } catch (DatabaseException e) {
        throw new UnexpectedLiquibaseException(e);
    }
    CSVReader reader = null;
    try {
        reader = getCSVReader();
        if (reader == null) {
            throw new UnexpectedLiquibaseException("Unable to read file " + this.getFile());
        }
        String[] headers = reader.readNext();
        if (headers == null) {
            throw new UnexpectedLiquibaseException("Data file " + getFile() + " was empty");
        }
        // Make sure all take the column list we interpolated from the CSV headers
        addColumnsFromHeaders(headers);
        // If we have an real JDBC connection to the database, ask the database for any missing column types.
        try {
            retrieveMissingColumnLoadTypes(columns, database);
        } catch (DatabaseException e) {
            throw new UnexpectedLiquibaseException(e);
        }
        List<ExecutablePreparedStatementBase> preparedStatements = new ArrayList<>();
        boolean anyPreparedStatements = false;
        String[] line;
        // Start at '1' to take into account the header (already processed):
        int lineNumber = 1;
        boolean isCommentingEnabled = StringUtil.isNotEmpty(commentLineStartsWith);
        List<SqlStatement> statements = new ArrayList<>();
        while ((line = reader.readNext()) != null) {
            lineNumber++;
            if ((line.length == 0) || ((line.length == 1) && (StringUtil.trimToNull(line[0]) == null)) || (isCommentingEnabled && isLineCommented(line))) {
                // nothing interesting on this line
                continue;
            }
            // (Failure could indicate unquoted strings with commas, for example).
            if (line.length != headers.length) {
                throw new UnexpectedLiquibaseException("CSV file " + getFile() + " Line " + lineNumber + " has " + line.length + " values defined, Header has " + headers.length + ". Numbers MUST be equal (check for unquoted string with embedded commas)");
            }
            boolean needsPreparedStatement = false;
            List<LoadDataColumnConfig> columnsFromCsv = new ArrayList<>();
            for (int i = 0; i < headers.length; i++) {
                String value = line[i];
                String columnName = headers[i].trim();
                LoadDataColumnConfig valueConfig = new LoadDataColumnConfig();
                LoadDataColumnConfig columnConfig = getColumnConfig(i, columnName);
                if (columnConfig != null) {
                    if ("skip".equalsIgnoreCase(columnConfig.getType())) {
                        continue;
                    }
                    // don't overwrite header name unless there is actually a value to override it with
                    if (columnConfig.getName() != null) {
                        columnName = columnConfig.getName();
                    }
                    // 
                    if ("NULL".equalsIgnoreCase(value)) {
                        valueConfig.setType(columnConfig.getType());
                    }
                    valueConfig.setName(columnName);
                    valueConfig.setAllowUpdate(columnConfig.getAllowUpdate());
                    if (value.isEmpty()) {
                        value = columnConfig.getDefaultValue();
                    }
                    if (StringUtil.equalsWordNull(value)) {
                        valueConfig.setValue(null);
                    } else if (columnConfig.getType() == null) {
                        // columnConfig did not specify a type
                        valueConfig.setValue(value);
                    } else if (columnConfig.getTypeEnum() == LOAD_DATA_TYPE.UNKNOWN) {
                        // columnConfig did not match a specific type
                        valueConfig.setValue(value);
                    } else if (columnConfig.getTypeEnum() == LOAD_DATA_TYPE.BOOLEAN) {
                        if (value == null) {
                            // TODO getDefaultValueBoolean should use BooleanUtil.parseBoolean also for consistent behaviour
                            valueConfig.setValueBoolean(columnConfig.getDefaultValueBoolean());
                        } else {
                            valueConfig.setValueBoolean(BooleanUtil.parseBoolean(value));
                        }
                    } else if (columnConfig.getTypeEnum() == LOAD_DATA_TYPE.NUMERIC) {
                        if (value != null) {
                            valueConfig.setValueNumeric(value);
                        } else {
                            valueConfig.setValueNumeric(columnConfig.getDefaultValueNumeric());
                        }
                    } else if (columnConfig.getType().toLowerCase().contains("date") || columnConfig.getType().toLowerCase().contains("time")) {
                        if ("NULL".equalsIgnoreCase(value) || "".equals(value)) {
                            valueConfig.setValue(null);
                        } else {
                            try {
                                // Need the column type for handling 'NOW' or 'TODAY' type column value
                                valueConfig.setType(columnConfig.getType());
                                if (value != null) {
                                    valueConfig.setValueDate(value);
                                } else {
                                    valueConfig.setValueDate(columnConfig.getDefaultValueDate());
                                }
                            } catch (DateParseException e) {
                                throw new UnexpectedLiquibaseException(e);
                            }
                        }
                    } else if (columnConfig.getTypeEnum() == LOAD_DATA_TYPE.STRING) {
                        valueConfig.setType(columnConfig.getType());
                        valueConfig.setValue(value == null ? "" : value);
                    } else if (columnConfig.getTypeEnum() == LOAD_DATA_TYPE.COMPUTED) {
                        if (null != value) {
                            liquibase.statement.DatabaseFunction function = new liquibase.statement.DatabaseFunction(value);
                            valueConfig.setValueComputed(function);
                        } else {
                            valueConfig.setValueComputed(columnConfig.getDefaultValueComputed());
                        }
                    } else if (columnConfig.getTypeEnum() == LOAD_DATA_TYPE.SEQUENCE) {
                        if (value == null) {
                            throw new UnexpectedLiquibaseException("Must set a sequence name in the loadData column defaultValue attribute");
                        }
                        liquibase.statement.SequenceNextValueFunction function = new liquibase.statement.SequenceNextValueFunction(getSchemaName(), value);
                        valueConfig.setValueComputed(function);
                    } else if (columnConfig.getType().equalsIgnoreCase(LOAD_DATA_TYPE.BLOB.toString())) {
                        if ("NULL".equalsIgnoreCase(value)) {
                            valueConfig.setValue(null);
                        } else if (BASE64_PATTERN.matcher(value).matches()) {
                            valueConfig.setType(columnConfig.getType());
                            valueConfig.setValue(value);
                            needsPreparedStatement = true;
                        } else {
                            valueConfig.setValueBlobFile(value);
                            needsPreparedStatement = true;
                        }
                    } else if (columnConfig.getTypeEnum() == LOAD_DATA_TYPE.CLOB) {
                        valueConfig.setValueClobFile(value);
                        needsPreparedStatement = true;
                    } else if (columnConfig.getTypeEnum() == LOAD_DATA_TYPE.UUID) {
                        valueConfig.setType(columnConfig.getType());
                        if ("NULL".equalsIgnoreCase(value)) {
                            valueConfig.setValue(null);
                        } else {
                            valueConfig.setValue(value);
                        }
                    } else if (columnConfig.getType().equalsIgnoreCase(LOAD_DATA_TYPE.OTHER.toString())) {
                        valueConfig.setType(columnConfig.getType());
                        if ("NULL".equalsIgnoreCase(value)) {
                            valueConfig.setValue(null);
                        } else {
                            valueConfig.setValue(value);
                        }
                    } else {
                        throw new UnexpectedLiquibaseException(String.format(coreBundle.getString("loaddata.type.is.not.supported"), columnConfig.getType()));
                    }
                } else {
                    // No columnConfig found. Assume header column name to be the table column name.
                    if (columnName.contains("(") || (columnName.contains(")") && (database instanceof AbstractJdbcDatabase))) {
                        columnName = ((AbstractJdbcDatabase) database).quoteObject(columnName, Column.class);
                    }
                    valueConfig.setName(columnName);
                    valueConfig.setValue(getValueToWrite(value));
                }
                columnsFromCsv.add(valueConfig);
            }
            // end of: iterate through all the columns of a CSV line
            // Try to use prepared statements if any of the following conditions apply:
            // 1. There is no other option than using a prepared statement (e.g. in cases of LOBs) regardless
            // of whether the 'usePreparedStatement' is set to false
            // 2. The database supports batched statements (for improved performance) AND we are not in an
            // "SQL" mode (i.e. we generate an SQL file instead of actually modifying the database).
            // BUT: if the user specifically requests usePreparedStatement=false, then respect that
            boolean actuallyUsePreparedStatements = false;
            if (hasPreparedStatementsImplemented()) {
                if (usePreparedStatements != null) {
                    if (!usePreparedStatements && needsPreparedStatement) {
                        throw new UnexpectedLiquibaseException("loadData is requesting usePreparedStatements=false but prepared statements are required");
                    }
                    actuallyUsePreparedStatements = usePreparedStatements;
                } else {
                    actuallyUsePreparedStatements = needsPreparedStatement || (databaseSupportsBatchUpdates && !isLoggingExecutor(database));
                }
            }
            if (actuallyUsePreparedStatements) {
                anyPreparedStatements = true;
                ExecutablePreparedStatementBase stmt = this.createPreparedStatement(database, getCatalogName(), getSchemaName(), getTableName(), columnsFromCsv, getChangeSet(), Scope.getCurrentScope().getResourceAccessor());
                preparedStatements.add(stmt);
            } else {
                InsertStatement insertStatement = this.createStatement(getCatalogName(), getSchemaName(), getTableName());
                for (LoadDataColumnConfig column : columnsFromCsv) {
                    String columnName = column.getName();
                    Object value = column.getValueObject();
                    if (value == null) {
                        value = "NULL";
                    }
                    insertStatement.addColumnValue(columnName, value);
                    if (insertStatement instanceof InsertOrUpdateStatement) {
                        ((InsertOrUpdateStatement) insertStatement).setAllowColumnUpdate(columnName, column.getAllowUpdate() == null || column.getAllowUpdate());
                    }
                }
                statements.add(insertStatement);
            }
        // end of: will we use a PreparedStatement?
        }
        if (anyPreparedStatements) {
            // If we have only prepared statements and the database supports batching, let's roll
            if (databaseSupportsBatchUpdates && statements.isEmpty() && (!preparedStatements.isEmpty())) {
                if (database instanceof PostgresDatabase) {
                    // we don't do batch updates for Postgres but we still send as a prepared statement, see LB-744
                    return preparedStatements.toArray(new SqlStatement[preparedStatements.size()]);
                } else {
                    return new SqlStatement[] { new BatchDmlExecutablePreparedStatement(database, getCatalogName(), getSchemaName(), getTableName(), columns, getChangeSet(), Scope.getCurrentScope().getResourceAccessor(), preparedStatements) };
                }
            } else {
                return statements.toArray(new SqlStatement[statements.size()]);
            }
        } else {
            if (statements.isEmpty()) {
                // avoid returning unnecessary dummy statement
                return new SqlStatement[0];
            }
            InsertSetStatement statementSet = this.createStatementSet(getCatalogName(), getSchemaName(), getTableName());
            for (SqlStatement stmt : statements) {
                statementSet.addInsertStatement((InsertStatement) stmt);
            }
            if ((database instanceof MSSQLDatabase) || (database instanceof MySQLDatabase) || (database instanceof PostgresDatabase)) {
                List<InsertStatement> innerStatements = statementSet.getStatements();
                if ((innerStatements != null) && (!innerStatements.isEmpty()) && (innerStatements.get(0) instanceof InsertOrUpdateStatement)) {
                    // cannot do insert or update in a single statement
                    return statementSet.getStatementsArray();
                }
                // should the need arise, on generation.
                return new SqlStatement[] { statementSet };
            } else {
                return statementSet.getStatementsArray();
            }
        }
    } catch (CsvMalformedLineException e) {
        throw new RuntimeException("Error parsing " + getRelativeTo() + " on line " + e.getLineNumber() + ": " + e.getMessage());
    } catch (IOException | LiquibaseException e) {
        throw new RuntimeException(e);
    } catch (UnexpectedLiquibaseException ule) {
        if ((getChangeSet() != null) && (getChangeSet().getFailOnError() != null) && !getChangeSet().getFailOnError()) {
            LOG.info("Change set " + getChangeSet().toString(false) + " failed, but failOnError was false.  Error: " + ule.getMessage());
            return new SqlStatement[0];
        } else {
            throw ule;
        }
    } finally {
        if (null != reader) {
            try {
                reader.close();
            } catch (Exception e) {
            // Do nothing
            }
        }
    }
}
Also used : InsertOrUpdateStatement(liquibase.statement.core.InsertOrUpdateStatement) CsvMalformedLineException(com.opencsv.exceptions.CsvMalformedLineException) InsertStatement(liquibase.statement.core.InsertStatement) SqlStatement(liquibase.statement.SqlStatement) BatchDmlExecutablePreparedStatement(liquibase.statement.BatchDmlExecutablePreparedStatement) Column(liquibase.structure.core.Column) MSSQLDatabase(liquibase.database.core.MSSQLDatabase) CSVReader(liquibase.util.csv.CSVReader) MySQLDatabase(liquibase.database.core.MySQLDatabase) IOException(java.io.IOException) AbstractJdbcDatabase(liquibase.database.AbstractJdbcDatabase) CsvMalformedLineException(com.opencsv.exceptions.CsvMalformedLineException) InvalidExampleException(liquibase.snapshot.InvalidExampleException) IOException(java.io.IOException) ExecutablePreparedStatementBase(liquibase.statement.ExecutablePreparedStatementBase) PostgresDatabase(liquibase.database.core.PostgresDatabase) InsertSetStatement(liquibase.statement.core.InsertSetStatement)

Aggregations

PostgresDatabase (liquibase.database.core.PostgresDatabase)33 Test (org.junit.Test)19 Sql (liquibase.sql.Sql)16 Database (liquibase.database.Database)11 MSSQLDatabase (liquibase.database.core.MSSQLDatabase)11 AbstractSqlGeneratorTest (liquibase.sqlgenerator.AbstractSqlGeneratorTest)11 MySQLDatabase (liquibase.database.core.MySQLDatabase)10 OracleDatabase (liquibase.database.core.OracleDatabase)10 SQLiteDatabase (liquibase.database.core.SQLiteDatabase)9 AbstractDb2Database (liquibase.database.core.AbstractDb2Database)8 H2Database (liquibase.database.core.H2Database)7 SybaseASADatabase (liquibase.database.core.SybaseASADatabase)7 SybaseDatabase (liquibase.database.core.SybaseDatabase)7 BigInteger (java.math.BigInteger)6 ColumnConfig (liquibase.change.ColumnConfig)6 DerbyDatabase (liquibase.database.core.DerbyDatabase)6 HsqlDatabase (liquibase.database.core.HsqlDatabase)6 CreateTableStatement (liquibase.statement.core.CreateTableStatement)6 MockDatabaseConnection (liquibase.database.MockDatabaseConnection)5 ArrayList (java.util.ArrayList)4