Search in sources :

Example 16 with InvalidExampleException

use of liquibase.snapshot.InvalidExampleException in project liquibase by liquibase.

the class IndexSnapshotGenerator method snapshotObject.

@Override
protected DatabaseObject snapshotObject(DatabaseObject example, DatabaseSnapshot snapshot) throws DatabaseException, InvalidExampleException {
    Database database = snapshot.getDatabase();
    Relation exampleIndex = ((Index) example).getRelation();
    String tableName = null;
    Schema schema = null;
    if (exampleIndex != null) {
        tableName = exampleIndex.getName();
        schema = exampleIndex.getSchema();
    }
    if (schema == null) {
        schema = new Schema(database.getDefaultCatalogName(), database.getDefaultSchemaName());
    }
    for (int i = 0; i < ((Index) example).getColumns().size(); i++) {
        ((Index) example).getColumns().set(i, ((Index) example).getColumns().get(i));
    }
    String exampleName = example.getName();
    if (exampleName != null) {
        exampleName = database.correctObjectName(exampleName, Index.class);
    }
    Map<String, Index> foundIndexes = new HashMap<>();
    JdbcDatabaseSnapshot.CachingDatabaseMetaData databaseMetaData = null;
    List<CachedRow> rs = null;
    try {
        databaseMetaData = ((JdbcDatabaseSnapshot) snapshot).getMetaDataFromCache();
        rs = databaseMetaData.getIndexInfo(((AbstractJdbcDatabase) database).getJdbcCatalogName(schema), ((AbstractJdbcDatabase) database).getJdbcSchemaName(schema), tableName, exampleName);
        for (CachedRow row : rs) {
            String rawIndexName = row.getString("INDEX_NAME");
            String indexName = cleanNameFromDatabase(rawIndexName, database);
            String correctedIndexName = database.correctObjectName(indexName, Index.class);
            if (indexName == null) {
                continue;
            }
            if ((exampleName != null) && !exampleName.equals(correctedIndexName)) {
                continue;
            }
            /*
                 * TODO Informix generates indexnames with a leading blank if no name given.
                 * An identifier with a leading blank is not allowed.
                 * So here is it replaced.
                 */
            if ((database instanceof InformixDatabase) && indexName.startsWith(" ")) {
                // suppress creation of generated_index records
                continue;
            }
            short type = row.getShort("TYPE");
            Boolean nonUnique = row.getBoolean("NON_UNIQUE");
            if (nonUnique == null) {
                nonUnique = true;
            }
            String columnName = cleanNameFromDatabase(row.getString("COLUMN_NAME"), database);
            short position = row.getShort("ORDINAL_POSITION");
            String definition = StringUtil.trimToNull(row.getString("FILTER_CONDITION"));
            if (definition != null) {
                if (!(database instanceof OracleDatabase)) {
                    // TODO: this replaceAll code has been there for a long time but we don't know why. Investigate when it is ever needed and modify it to be smarter
                    definition = definition.replaceAll("\"", "");
                }
            }
            if ((columnName == null) && (definition == null)) {
                // nothing to index, not sure why these come through sometimes
                continue;
            }
            if (!(database instanceof H2Database) && type == DatabaseMetaData.tableIndexStatistic) {
                continue;
            }
            /*
                 * In Oracle database, ALL_IND_COLUMNS/ALL_IND_EXPRESSIONS (the views from which we bulk-fetch the
                 * column definitions for a given index) can show a strange behaviour if an index column consists of
                 * a regular table column, but its sort order is DESC(ending). In this case, we get something like
                 * this (example values):
                 * ALL_IND_COLUMNS.COLUMN_NAME=SYS_NC00006$
                 * ALL_IND_EXPRESSIONS.COLUMN_EXPRESSIONS="COLUMN1FORDESC"
                 * Note that the quote characters (") are part of the actual column value!
                 * Our strategy here is: If the expression would be a valid Oracle identifier, but not a valid Oracle
                 * function name, then we assume it is the name of a regular column.
                 */
            if ((database instanceof OracleDatabase) && (definition != null) && (columnName != null)) {
                String potentialColumnExpression = definition.replaceFirst("^\"?(.*?)\"?$", "$1");
                OracleDatabase oracle = (OracleDatabase) database;
                if (oracle.isValidOracleIdentifier(potentialColumnExpression, Index.class) && (!oracle.isFunction(potentialColumnExpression))) {
                    columnName = potentialColumnExpression;
                    definition = null;
                }
            }
            // Have we already seen/found this index? If not, let's read its properties!
            Index returnIndex = foundIndexes.get(correctedIndexName);
            if (returnIndex == null) {
                returnIndex = new Index();
                Relation relation = new Table();
                if ("V".equals(row.getString("INTERNAL_OBJECT_TYPE"))) {
                    relation = new View();
                }
                returnIndex.setRelation(relation.setName(row.getString("TABLE_NAME")).setSchema(schema));
                returnIndex.setName(indexName);
                returnIndex.setUnique(!nonUnique);
                String tablespaceName = row.getString("TABLESPACE_NAME");
                if ((tablespaceName != null) && database.supportsTablespaces()) {
                    returnIndex.setTablespace(tablespaceName);
                }
                if (type == DatabaseMetaData.tableIndexClustered) {
                    returnIndex.setClustered(true);
                } else if (database instanceof MSSQLDatabase) {
                    returnIndex.setClustered(false);
                }
                if (database instanceof MSSQLDatabase) {
                    Boolean recompute = (Boolean) row.get("NO_RECOMPUTE");
                    if (recompute != null) {
                        recompute = !recompute;
                    }
                    returnIndex.setAttribute("padIndex", row.get("IS_PADDED"));
                    returnIndex.setAttribute("fillFactor", row.get("FILL_FACTOR"));
                    returnIndex.setAttribute("ignoreDuplicateKeys", row.get("IGNORE_DUP_KEY"));
                    returnIndex.setAttribute("recomputeStatistics", recompute);
                    returnIndex.setAttribute("incrementalStatistics", row.get("IS_INCREMENTAL"));
                    returnIndex.setAttribute("allowRowLocks", row.get("ALLOW_ROW_LOCKS"));
                    returnIndex.setAttribute("allowPageLocks", row.get("ALLOW_PAGE_LOCKS"));
                }
                foundIndexes.put(correctedIndexName, returnIndex);
            }
            if ((database instanceof MSSQLDatabase) && (Boolean) row.get("IS_INCLUDED_COLUMN")) {
                List<String> includedColumns = returnIndex.getAttribute("includedColumns", List.class);
                if (includedColumns == null) {
                    includedColumns = new ArrayList<>();
                    returnIndex.setAttribute("includedColumns", includedColumns);
                }
                includedColumns.add(columnName);
            } else {
                if (position != 0) {
                    // if really a column, position is 1-based.
                    for (int i = returnIndex.getColumns().size(); i < position; i++) {
                        returnIndex.getColumns().add(null);
                    }
                    // or is it a computed expression (definition != null)
                    if (definition == null) {
                        String ascOrDesc;
                        if (database instanceof Db2zDatabase) {
                            ascOrDesc = row.getString("ORDER");
                        } else {
                            ascOrDesc = row.getString("ASC_OR_DESC");
                        }
                        Boolean descending = "D".equals(ascOrDesc) ? Boolean.TRUE : ("A".equals(ascOrDesc) ? Boolean.FALSE : null);
                        returnIndex.getColumns().set(position - 1, new Column(columnName).setDescending(descending).setRelation(returnIndex.getRelation()));
                    } else {
                        returnIndex.getColumns().set(position - 1, new Column().setRelation(returnIndex.getRelation()).setName(definition, true));
                    }
                }
            }
        }
    } catch (Exception e) {
        throw new DatabaseException(e);
    }
    if (exampleName != null) {
        Index index = foundIndexes.get(exampleName);
        return index;
    } else {
        // prefer clustered version of the index
        List<Index> nonClusteredIndexes = new ArrayList<>();
        for (Index index : foundIndexes.values()) {
            if (DatabaseObjectComparatorFactory.getInstance().isSameObject(index.getRelation(), exampleIndex, snapshot.getSchemaComparisons(), database)) {
                boolean actuallyMatches = false;
                if (database.isCaseSensitive()) {
                    if (index.getColumnNames().equals(((Index) example).getColumnNames())) {
                        actuallyMatches = true;
                    }
                } else {
                    if (index.getColumnNames().equalsIgnoreCase(((Index) example).getColumnNames())) {
                        actuallyMatches = true;
                    }
                }
                if (actuallyMatches) {
                    if ((index.getClustered() != null) && index.getClustered()) {
                        return finalizeIndex(schema, tableName, index, snapshot);
                    } else {
                        nonClusteredIndexes.add(index);
                    }
                }
            }
        }
        if (!nonClusteredIndexes.isEmpty()) {
            return finalizeIndex(schema, tableName, nonClusteredIndexes.get(0), snapshot);
        }
        return null;
    }
}
Also used : CachedRow(liquibase.snapshot.CachedRow) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Database(liquibase.database.Database) AbstractJdbcDatabase(liquibase.database.AbstractJdbcDatabase) AbstractJdbcDatabase(liquibase.database.AbstractJdbcDatabase) InvalidExampleException(liquibase.snapshot.InvalidExampleException) DatabaseException(liquibase.exception.DatabaseException) JdbcDatabaseSnapshot(liquibase.snapshot.JdbcDatabaseSnapshot) DatabaseException(liquibase.exception.DatabaseException)

Aggregations

InvalidExampleException (liquibase.snapshot.InvalidExampleException)16 DatabaseException (liquibase.exception.DatabaseException)9 UnexpectedLiquibaseException (liquibase.exception.UnexpectedLiquibaseException)8 CatalogAndSchema (liquibase.CatalogAndSchema)7 Database (liquibase.database.Database)7 AbstractJdbcDatabase (liquibase.database.AbstractJdbcDatabase)5 SnapshotControl (liquibase.snapshot.SnapshotControl)5 Table (liquibase.structure.core.Table)5 SQLException (java.sql.SQLException)4 CachedRow (liquibase.snapshot.CachedRow)4 JdbcDatabaseSnapshot (liquibase.snapshot.JdbcDatabaseSnapshot)4 DatabaseObject (liquibase.structure.DatabaseObject)4 DB2Database (liquibase.database.core.DB2Database)3 MSSQLDatabase (liquibase.database.core.MSSQLDatabase)3 DiffResult (liquibase.diff.DiffResult)3 SqlStatement (liquibase.statement.SqlStatement)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 Change (liquibase.change.Change)2 Db2zDatabase (liquibase.database.core.Db2zDatabase)2