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

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

Go to download

This is the full Active Objects library, if you don't know which one to use, you probably want this one.

There is a newer version: 6.1.1
Show newest version
/*
 * Copyright 2007 Daniel Spiewak
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at
 * 
 *	    http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
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.DDLIndex;
import net.java.ao.schema.ddl.DDLIndexField;
import net.java.ao.schema.ddl.DDLTable;
import net.java.ao.schema.ddl.SQLAction;
import net.java.ao.types.TypeManager;
import net.java.ao.types.TypeQualifiers;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

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

/**
 * @author Daniel Spiewak
 */
public class MySQLDatabaseProvider extends DatabaseProvider {

    public static final String TRUNCATE_TO_255_CHARACTERS_FUNCTION = "(255)";

    public MySQLDatabaseProvider(DisposableDataSource dataSource) {
        super(dataSource, null, TypeManager.mysql());
    }

    @Override
    protected String renderAutoIncrement() {
        return "AUTO_INCREMENT";
    }

    @Override
    protected String renderAppend() {
        return "ENGINE=InnoDB";
    }

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

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

        // use the "LIMIT [, ] " style, with (2^64-1) meaning "unlimited"
        int offset = query.getOffset();
        int limit = query.getLimit();

        if (offset > 0) {
            sql.append(" LIMIT ");
            sql.append(offset);
            sql.append(", ");
            if (limit >= 0) {
                sql.append(limit);
            } else {
                sql.append("18446744073709551615");
            }
        } else if (limit >= 0) {
            sql.append(" LIMIT ");
            sql.append(limit);
        }

        return sql.toString();
    }

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

        for (DDLField field : table.getFields()) {
            if (field.isUnique()) {
                back.append(" CONSTRAINT ").append(uniqueNameConverter.getName(table.getName(), field.getName())).append(" UNIQUE(").append(processID(field.getName())).append("),\n");
            }
        }

        return back.toString();
    }

    @Override
    protected Iterable renderAlterTableAddColumn(NameConverters nameConverters, DDLTable table, DDLField field) {
        final Iterable back = super.renderAlterTableAddColumn(nameConverters, table, field);
        if (field.isUnique()) {
            return concat(back, ImmutableList.of(alterAddUniqueConstraint(nameConverters, table, field)));
        }
        return back;
    }

    private SQLAction alterAddUniqueConstraint(NameConverters nameConverters, DDLTable table, DDLField field) {
        return SQLAction.of(new StringBuilder().append("ALTER TABLE ").append(withSchema(table.getName())).append(" ADD CONSTRAINT ").append(nameConverters.getUniqueNameConverter().getName(table.getName(), field.getName())).append(" UNIQUE (").append(processID(field.getName())).append(")"));
    }

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

        back.addAll(renderDropAccessoriesForField(nameConverters, table, oldField));

        back.add(renderAlterTableChangeColumnStatement(nameConverters, table, oldField, field, renderFieldOptionsInAlterColumn()));

        if (oldField.isUnique() && !field.isUnique()) {
            back.add(SQLAction.of(new StringBuilder().append("ALTER TABLE ").append(withSchema(table.getName())).append(" DROP INDEX ").append(nameConverters.getUniqueNameConverter().getName(table.getName(), field.getName()))));
        }

        if (!oldField.isUnique() && field.isUnique()) {
            back.add(alterAddUniqueConstraint(nameConverters, table, field));
        }

        back.addAll(renderAccessoriesForField(nameConverters, table, field));

        return back.build();
    }

    @Override
    protected SQLAction renderCreateIndex(IndexNameConverter indexNameConverter, DDLIndex index) {

        String statement = "CREATE INDEX " + processID(index.getIndexName())
                + " ON " + processID(index.getTable()) +
                Stream.of(index.getFields())
                        .map(this::appendLength)
                        .collect(Collectors.joining(",", "(", ")"));
        return SQLAction.of(statement);
    }

    /**
     * MySQL has an internal limitation that prevents "long" indexes. Its default behaviour is to truncate them
     * silently, but some settings cause index creation to fail instead. When creating an index on columns that
     * have length data available, if the length is "too long", create a prefix index instead.
     *
     * When MySQL silently truncates a "long" index, the prefix index it creates is 255 characters. This
     * emulates that behaviour.
     *
     * @return index field name with length declaration if necessary
     */
    private String appendLength(DDLIndexField indexField) {

        TypeQualifiers qualifiers = indexField.getType().getQualifiers();
        if (qualifiers.hasStringLength() && qualifiers.getStringLength() > 255) {
            return processID(indexField.getFieldName()) + TRUNCATE_TO_255_CHARACTERS_FUNCTION;
        } else {
            return processID(indexField.getFieldName());
        }
    }

    @Override
    public SQLAction renderCreateCompositeIndex(String tableName, String indexName, List fields) {
        StringBuilder statement = new StringBuilder();
        statement.append("CREATE INDEX " + processID(indexName));
        statement.append(" ON " + processID(tableName));
        statement.append(" (");
        boolean needDelimiter = false;
        for (String field : fields) {
            if (needDelimiter) {
                statement.append(",");
            }
            statement.append(processID(field));
            needDelimiter = true;
        }
        statement.append(")");
        return SQLAction.of(statement);
    }

    public void putNull(PreparedStatement stmt, int index) throws SQLException {
        stmt.setString(index, null);
    }

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

    @Override
    public boolean isCaseSensitive() {
        return FileSystemUtils.isCaseSensitive();
    }

    private static final Set RESERVED_WORDS = ImmutableSet.of(
            "ADD", "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC",
            "ASENSITIVE", "BEFORE", "BETWEEN", "BIGINT", "BINARY", "BLOB",
            "BOTH", "BY", "CALL", "CASCADE", "CASE", "CHANGE", "CHAR",
            "CHARACTER", "CHECK", "COLLATE", "COLUMN", "COLUMNS", "CONDITION",
            "CONNECTION", "CONSTRAINT", "CONTINUE", "CONVERT", "CREATE", "CROSS",
            "CUME_DIST", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP",
            "CURRENT_USER", "CURSOR", "DATABASE", "DATABASES", "DAY_HOUR",
            "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "DEC", "DECIMAL",
            "DECLARE", "DEFAULT", "DELAYED", "DELETE", "DENSE_RANK", "DESC",
            "DESCRIBE", "DETERMINISTIC", "DISTINCT", "DISTINCTROW", "DIV", "DOUBLE",
            "DROP", "DUAL", "EACH", "ELSE", "ELSEIF", "EMPTY", "ENCLOSED", "ESCAPED",
            "EXCEPT", "EXISTS", "EXIT", "EXPLAIN", "FALSE", "FETCH", "FIELDS",
            "FIRST_VALUE", "FLOAT", "FLOAT4", "FLOAT8", "FOR", "FORCE", "FOREIGN",
            "FROM", "FULLTEXT", "GOTO", "GRANT", "GROUP", "GROUPING", "GROUPS", "HAVING",
            "HIGH_PRIORITY", "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND",
            "IF", "IGNORE", "IN", "INDEX", "INFILE", "INNER", "INOUT", "INSENSITIVE",
            "INSERT", "INT", "INT1", "INT2", "INT3", "INT4", "INT8", "INTEGER",
            "INTERVAL", "INTO", "IS", "ITERATE", "JOIN", "JSON_TABLE", "KEY", "KEYS",
            "KILL", "LABEL", "LAG", "LAST_VALUE", "LATERAL", "LEAD", "LEADING", "LEAVE",
            "LEFT", "LIKE", "LIMIT", "LINES", "LOAD", "LOCALTIME", "LOCALTIMESTAMP",
            "LOCK", "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", "MATCH",
            "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT", "MIDDLEINT", "MINUTE_MICROSECOND",
            "MINUTE_SECOND", "MOD", "MODIFIES", "NATURAL", "NOT", "NO_WRITE_TO_BINLOG",
            "NTH_VALUE", "NTILE", "NULL", "NUMERIC", "OF", "ON", "OPTIMIZE", "OPTION",
            "OPTIONALLY", "OR", "ORDER", "OUT", "OUTER", "OUTFILE", "OVER", "PERCENT_RANK",
            "PRECISION", "PRIMARY", "PRIVILEGES", "PROCEDURE", "PURGE", "RANK", "READ",
            "READS", "REAL", "RECURSIVE", "REFERENCES", "REGEXP", "RELEASE", "RENAME",
            "REPEAT", "REPLACE", "REQUIRE", "RESTRICT", "RETURN", "REVOKE", "RIGHT",
            "RLIKE", "ROW_NUMBER", "SCHEMA", "SCHEMAS", "SECOND_MICROSECOND", "SELECT",
            "SENSITIVE", "SEPARATOR", "SET", "SHOW", "SMALLINT", "SONAME", "SPATIAL",
            "SPECIFIC", "SQL", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "SQL_BIG_RESULT",
            "SQL_CALC_FOUND_ROWS", "SQL_SMALL_RESULT", "SSL", "STARTING",
            "STRAIGHT_JOIN", "SYSTEM", "TABLE", "TABLES", "TERMINATED", "THEN", "TINYBLOB",
            "TINYINT", "TINYTEXT", "TO", "TRAILING", "TRIGGER", "TRUE", "UNDO",
            "UNION", "UNIQUE", "UNLOCK", "UNSIGNED", "UPDATE", "UPGRADE", "USAGE",
            "USE", "USING", "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", "VALUES",
            "VARBINARY", "VARCHAR", "VARCHARACTER", "VARYING", "WHEN", "WHERE",
            "WHILE", "WINDOW", "WITH", "WRITE", "XOR", "YEAR_MONTH", "ZEROFILL");
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy