class ResultSetExtractor {

        private final Database database;

        public ResultSetExtractor(Database database) {
            this.database = database;
        }

        public abstract boolean bulkContainsSchema(String schemaKey);

        public String getSchemaKey(CachedRow row) {
            throw new UnexpectedLiquibaseException("Not Implemented");
        }

        protected boolean shouldBulkSelect(String schemaKey, ResultSetCache resultSetCache) {
            return resultSetCache.getTimesSingleQueried(schemaKey) >= 3;
        }

        protected List<CachedRow> executeAndExtract(String sql, Database database) throws DatabaseException, SQLException {
            return executeAndExtract(database, false, sql);
        }

        protected List<CachedRow> executeAndExtract(Database database, String sql, Object...parameters) throws DatabaseException, SQLException {
            return executeAndExtract(database, false, sql, parameters);
        }

        protected List<CachedRow> executeAndExtract(Database database, boolean informixTrimHint, String sql, Object...parameters)
                throws DatabaseException, SQLException {
            if (sql == null) {
                return new ArrayList<>();
            }
            PreparedStatement statement = null;
            ResultSet resultSet = null;
            try {
                JdbcConnection connection = (JdbcConnection) database.getConnection();
                statement = connection.prepareStatement(sql);
                for (int i = 0; i < parameters.length; ++i) {
                    statement.setObject(i + 1, parameters[i]);
                }
                resultSet = statement.executeQuery();
                resultSet.setFetchSize(database.getFetchSize());
                return extract(resultSet, informixTrimHint);
            } finally {
                JdbcUtil.close(resultSet, statement);
            }
        }

        public boolean equals(Object expectedValue, Object foundValue) {
            return equals(expectedValue, foundValue, true);
        }

        public boolean equals(Object expectedValue, Object foundValue, boolean equalIfEitherNull) {
            if ((expectedValue == null) && (foundValue == null)) {
                return true;
            }
            if ((expectedValue == null) || (foundValue == null)) {
                return equalIfEitherNull;
            }

            return expectedValue.equals(foundValue);
        }

        public abstract RowData rowKeyParameters(CachedRow row);

        public abstract RowData wantedKeyParameters();

        public abstract List<CachedRow> fastFetch() throws SQLException, DatabaseException;

        public abstract List<CachedRow> bulkFetch() throws SQLException, DatabaseException;

        protected List<CachedRow> extract(ResultSet resultSet) throws SQLException {
            return extract(resultSet, false);
        }

        protected List<CachedRow> extract(ResultSet resultSet, final boolean informixIndexTrimHint)
                throws SQLException {
            resultSet.setFetchSize(database.getFetchSize());
            List<CachedRow> returnList = new ArrayList<>();
            try {
                List<Map> result = (List<Map>) new RowMapperResultSetExtractor(new ColumnMapRowMapper(database.isCaseSensitive()) {
                    @Override
                    protected Object getColumnValue(ResultSet rs, int index) throws SQLException {<FILL_FUNCTION_BODY>}
                }).extractData(resultSet);

                for (Map row : result) {
                    returnList.add(new CachedRow(row));
                }
            } finally {
                JdbcUtil.closeResultSet(resultSet);
            }
            return returnList;
        }
    }

                        Object value = super.getColumnValue(rs, index);
                        if ((value instanceof String)) {

                            // Don't trim for informix database,
                            // We need to discern the space in front of an index name,
                            // to know if it was auto-generated or not

                            if (informixIndexTrimHint == false) {
                                value = ((String) value).trim(); // Trim the value normally
                            } else {
                                boolean startsWithSpace = (database instanceof InformixDatabase) && ((String) value).matches("^ .*$");
                                // Set the flag if the value started with a space
                                value = ((String) value).trim(); // Trim the value normally
                                if (startsWithSpace == true) {
                                    value = " " + value; // Put the space back at the beginning if the flag was set
                                }
                            }
                        }
                        return value;
                    
<no_super_class>