All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.java.ao.db.H2DatabaseProvider Maven / Gradle / Ivy

Go to download

This is the core library for Active Objects. It is generic and can be embedded in any environment. As such it is generic and won't contain all connection pooling, etc.

There is a newer version: 6.1.1
Show newest version
package net.java.ao.db;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import net.java.ao.DatabaseProvider;
import net.java.ao.DisposableDataSource;
import net.java.ao.Query;
import net.java.ao.schema.IndexNameConverter;
import net.java.ao.schema.NameConverters;
import net.java.ao.schema.UniqueNameConverter;
import net.java.ao.schema.ddl.DDLField;
import net.java.ao.schema.ddl.DDLForeignKey;
import net.java.ao.schema.ddl.DDLIndex;
import net.java.ao.schema.ddl.DDLTable;
import net.java.ao.schema.ddl.SQLAction;
import net.java.ao.types.TypeManager;

import java.sql.Types;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.google.common.collect.Iterables.concat;

public class H2DatabaseProvider extends DatabaseProvider {
    public H2DatabaseProvider(final DisposableDataSource dataSource) {
        this(dataSource, "PUBLIC");
    }

    public H2DatabaseProvider(final DisposableDataSource dataSource, final String schema) {
        super(dataSource, schema, TypeManager.h2());
    }

    @Override
    protected String renderQueryLimit(final Query query) {
        final StringBuilder sql = new StringBuilder();

        // H2 requires a LIMIT when OFFSET is specified; -1 indicates unlimited
        if (query.getLimit() < 0 && query.getOffset() > 0) {
            sql.append(" LIMIT -1");
        }

        sql.append(super.renderQueryLimit(query));

        return sql.toString();
    }

    @Override
    protected Iterable renderAlterTableAddColumn(final NameConverters nameConverters, final DDLTable table, final DDLField field) {
        final Iterable back = super.renderAlterTableAddColumn(nameConverters, table, field);

        if (field.isUnique()) {
            return concat(back, ImmutableList.of(renderAddUniqueConstraint(nameConverters.getUniqueNameConverter(), table, field)));
        }

        return back;
    }

    @Override
    protected Iterable renderAlterTableChangeColumn(final NameConverters nameConverters, final DDLTable table, final DDLField oldField, final DDLField field) {
        final ImmutableList.Builder back = ImmutableList.builder();

        back.addAll(super.renderAlterTableChangeColumn(nameConverters, table, oldField, field));

        if (!field.isPrimaryKey()) {
            if (oldField.isUnique() && !field.isUnique()) {
                back.add(renderDropUniqueConstraint(nameConverters.getUniqueNameConverter(), table, field));
            } else if (!oldField.isUnique() && field.isUnique()) {
                back.add(renderAddUniqueConstraint(nameConverters.getUniqueNameConverter(), table, field));
            }
        }

        return back.build();
    }

    @Override
    protected SQLAction renderAlterTableChangeColumnStatement(final NameConverters nameConverters, final DDLTable table, final DDLField oldField, final DDLField field, final RenderFieldOptions options) {
        final StringBuilder sql = new StringBuilder();

        sql.append("ALTER TABLE ");
        sql.append(withSchema(table.getName()));
        sql.append(" ALTER COLUMN ");
        sql.append(renderField(nameConverters, table, field, options));

        if (oldField.isNotNull() && !field.isNotNull()) {
            sql.append(" NULL ");
        }

        return SQLAction.of(sql);
    }

    @Override
    protected String renderFieldDefault(final DDLTable table, final DDLField field) {
        final StringBuilder sql = new StringBuilder();

        if (field.getDefaultValue() != null) {
            sql.append(" DEFAULT ").append(renderValue(field.getDefaultValue()));
        }

        return sql.toString();
    }

    @Override
    protected SQLAction renderAlterTableDropKey(final DDLForeignKey key) {
        final StringBuilder sql = new StringBuilder();

        sql.append("ALTER TABLE ");
        sql.append(withSchema(key.getDomesticTable()));
        sql.append(" DROP CONSTRAINT ");
        sql.append(processID(key.getFKName()));

        return SQLAction.of(sql);
    }

    @Override
    protected SQLAction renderDropIndex(final IndexNameConverter indexNameConverter, final DDLIndex index) {
        return SQLAction.of(new StringBuilder()
                        .append("DROP INDEX IF EXISTS ")
                        .append(withSchema(index.getIndexName()))
        );
    }

    @Override
    protected String renderConstraintsForTable(final UniqueNameConverter uniqueNameConverter, final DDLTable table) {
        final StringBuilder sql = new StringBuilder(super.renderConstraintsForTable(uniqueNameConverter, table));

        for (final DDLField field : table.getFields()) {
            if (field.isUnique()) {
                sql.append("   ");
                sql.append(renderUniqueConstraint(uniqueNameConverter, table, field));
                sql.append(",\n");
            }
        }

        return sql.toString();
    }

    @Override
    protected String renderUnique(final UniqueNameConverter uniqueNameConverter, final DDLTable table, final DDLField field) {
        return "";
    }

    @Override
    public Object parseValue(final int type, String value) {
        if (value == null || value.equals("") || value.equals("NULL")) {
            return null;
        }

        switch (type) {
            case Types.TIMESTAMP:
            case Types.DATE:
            case Types.TIME:
            case Types.VARCHAR:
                Matcher matcher = Pattern.compile("'(.*)'.*").matcher(value);
                if (matcher.find()) {
                    value = matcher.group(1);
                }
                break;
        }

        return super.parseValue(type, value);
    }

    @Override
    protected Set getReservedWords() {
        return RESERVED_WORDS;
    }

    private static final Set RESERVED_WORDS = ImmutableSet.of(
            "ALL", // since 1.4.198
            //"AND", // since 1.4.199. See also additionalKeywords flag
            "ARRAY", // since 1.4.198
            //"BETWEEN", // since 1.4.199. See also additionalKeywords flag
            //"BOTH", // since 1.4.199. See also additionalKeywords flag
            "CASE", // since 1.4.198
            "CHECK", // since 1.4.196
            "CONSTRAINT", // since 1.4.198
            "CROSS",
            "CURRENT_DATE",
            "CURRENT_TIME",
            "CURRENT_TIMESTAMP",
            "CURRENT_USER", // since 1.4.198
            "DISTINCT",
            "EXCEPT",
            "EXISTS",
            "FALSE",
            "FETCH", // since 1.3.176 at least. See also supportsOffsetFetch flag (<1.4.198)
            //"FILTER", // since 1.4.199. See also additionalKeywords flag
            "FOR",
            "FOREIGN", // since 1.4.198
            "FROM",
            "FULL",
            "GROUP",
            //"GROUPS", // since 1.4.199. See also additionalKeywords flag
            "HAVING",
            "IF", // since 1.4.198
            //"ILIKE", // since 1.4.199. See also additionalKeywords flag
            //"IN", // since 1.4.199. See also additionalKeywords flag
            "INNER",
            "INTERSECT",
            "INTERSECTS", // since 1.4.198
            "INTERVAL", // since 1.4.198
            "IS",
            "JOIN",
            //"LEADING", // since 1.4.199. See also additionalKeywords flag
            //"LEFT", // since 1.4.199. See also additionalKeywords flag
            "LIKE",
            "LIMIT",
            "LOCALTIME", // since 1.4.198
            "LOCALTIMESTAMP", // since 1.4.198
            "MINUS",
            "NATURAL",
            "NOT",
            "NULL",
            "OFFSET", // since 1.3.176 at least. See also supportsOffsetFetch flag (<1.4.198)
            "ON",
            //"OR", // since 1.4.199. See also additionalKeywords flag
            "ORDER",
            //"OVER", // since 1.4.199. See also additionalKeywords flag
            //"PARTITION", // since 1.4.199. See also additionalKeywords flag
            "PRIMARY",
            "QUALIFY", // since 1.4.198
            //"RANGE", // since 1.4.199. See also additionalKeywords flag
            //"REGEXP", // since 1.4.199. See also additionalKeywords flag
            //"RIGHT", // since 1.4.199. See also additionalKeywords flag
            "ROW", // since 1.4.198
            //"ROWS", // since 1.4.199. See also additionalKeywords flag
            "ROWNUM",
            "SELECT",
            "SYSDATE", // See also additionalKeywords flag (14.198+)
            "SYSTIME", // See also additionalKeywords flag (14.198+)
            "SYSTIMESTAMP", // See also additionalKeywords flag (14.198+)
            "TABLE", // since 1.4.198
            "TODAY", // See also additionalKeywords flag (14.198+)
            //"TOP", // since 1.4.198. See also additionalKeywords flag
            //"TRAILING", // since 1.4.199. See also additionalKeywords flag
            "TRUE",
            "UNION",
            "UNIQUE",
            "VALUES", // since 1.4.198
            "WHERE",
            "WINDOW", // since 1.4.198
            "WITH" // since 1.3.176 at least
    );

    private SQLAction renderAddUniqueConstraint(UniqueNameConverter uniqueNameConverter, DDLTable table, DDLField field) {
        final StringBuilder sql = new StringBuilder();

        sql.append("ALTER TABLE ");
        sql.append(withSchema(table.getName()));
        sql.append(" ADD ");
        sql.append(renderUniqueConstraint(uniqueNameConverter, table, field));

        return SQLAction.of(sql);
    }

    private SQLAction renderDropUniqueConstraint(UniqueNameConverter uniqueNameConverter, DDLTable table, DDLField field) {
        final StringBuilder sql = new StringBuilder();

        sql.append("ALTER TABLE ");
        sql.append(withSchema(table.getName()));
        sql.append(" DROP CONSTRAINT ");
        sql.append(uniqueNameConverter.getName(table.getName(), field.getName()));

        return SQLAction.of(sql);
    }

    private String renderUniqueConstraint(UniqueNameConverter uniqueNameConverter, DDLTable table, DDLField field) {
        final StringBuilder sql = new StringBuilder();

        sql.append(" CONSTRAINT ");
        sql.append(uniqueNameConverter.getName(table.getName(), field.getName()));
        sql.append(" UNIQUE(");
        sql.append(processID(field.getName()));
        sql.append(")");

        return sql.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy