/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2010, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.hibernate.dialect; import java.sql.CallableStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; //import org.hibernate.JDBCException; import org.hibernate.NullPrecedence; import org.hibernate.cfg.AvailableSettings; //import org.hibernate.exception.LockAcquisitionException; //import org.hibernate.exception.LockTimeoutException; //import org.hibernate.exception.spi.SQLExceptionConversionDelegate; //import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.StringHelper; //import org.hibernate.type.StandardBasicTypes; /** * An SQL dialect for MySQL (prior to 5.x). * * @author Gavin King */ @SuppressWarnings("deprecation") public class MySQLDialect extends Dialect { /** * Constructs a MySQLDialect */ public MySQLDialect() { super(); registerColumnType( Types.BIT, "bit" ); registerColumnType( Types.BIGINT, "bigint" ); registerColumnType( Types.SMALLINT, "smallint" ); registerColumnType( Types.TINYINT, "tinyint" ); registerColumnType( Types.INTEGER, "integer" ); registerColumnType( Types.CHAR, "char(1)" ); registerColumnType( Types.FLOAT, "float" ); registerColumnType( Types.DOUBLE, "double precision" ); registerColumnType( Types.BOOLEAN, "bit" ); // HHH-6935 registerColumnType( Types.DATE, "date" ); registerColumnType( Types.TIME, "time" ); registerColumnType( Types.TIMESTAMP, "datetime" ); registerColumnType( Types.VARBINARY, "longblob" ); registerColumnType( Types.VARBINARY, 16777215, "mediumblob" ); registerColumnType( Types.VARBINARY, 65535, "blob" ); registerColumnType( Types.VARBINARY, 255, "tinyblob" ); registerColumnType( Types.BINARY, "binary($l)" ); registerColumnType( Types.LONGVARBINARY, "longblob" ); registerColumnType( Types.LONGVARBINARY, 16777215, "mediumblob" ); registerColumnType( Types.NUMERIC, "decimal($p,$s)" ); registerColumnType( Types.BLOB, "longblob" ); // registerColumnType( Types.BLOB, 16777215, "mediumblob" ); // registerColumnType( Types.BLOB, 65535, "blob" ); registerColumnType( Types.CLOB, "longtext" ); // registerColumnType( Types.CLOB, 16777215, "mediumtext" ); // registerColumnType( Types.CLOB, 65535, "text" ); registerVarcharTypes(); getDefaultProperties().setProperty( AvailableSettings.MAX_FETCH_DEPTH, "2" ); getDefaultProperties().setProperty( AvailableSettings.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE ); } protected void registerVarcharTypes() { registerColumnType( Types.VARCHAR, "longtext" ); // registerColumnType( Types.VARCHAR, 16777215, "mediumtext" ); // registerColumnType( Types.VARCHAR, 65535, "text" ); registerColumnType( Types.VARCHAR, 255, "varchar($l)" ); registerColumnType( Types.LONGVARCHAR, "longtext" ); } @Override public String getAddColumnString() { return "add column"; } @Override public boolean qualifyIndexName() { return false; } @Override public boolean supportsIdentityColumns() { return true; } @Override public String getIdentitySelectString() { return "select last_insert_id()"; } @Override public String getIdentityColumnString() { //starts with 1, implicitly return "not null auto_increment"; } @Override public String getAddForeignKeyConstraintString( String constraintName, String[] foreignKey, String referencedTable, String[] primaryKey, boolean referencesPrimaryKey) { final String cols = StringHelper.join( ", ", foreignKey ); final String referencedCols = StringHelper.join( ", ", primaryKey ); return String.format( " add constraint %s foreign key (%s) references %s (%s)", constraintName, cols, referencedTable, referencedCols ); } @Override public boolean supportsLimit() { return true; } @Override public String getDropForeignKeyString() { return " drop foreign key "; } @Override public String getLimitString(String sql, boolean hasOffset) { return sql + (hasOffset ? " limit ?, ?" : " limit ?"); } @Override public char closeQuote() { return '`'; } @Override public char openQuote() { return '`'; } @Override public boolean supportsIfExistsBeforeTableName() { return true; } @Override public String getSelectGUIDString() { return "select uuid()"; } @Override public boolean supportsCascadeDelete() { return false; } @Override public String getTableComment(String comment) { return " comment='" + comment + "'"; } @Override public String getColumnComment(String comment) { return " comment '" + comment + "'"; } @Override public boolean supportsTemporaryTables() { return true; } @Override public String getCreateTemporaryTableString() { return "create temporary table if not exists"; } @Override public String getDropTemporaryTableString() { return "drop temporary table"; } @Override public Boolean performTemporaryTableDDLInIsolation() { // because we [drop *temporary* table...] we do not // have to doAfterTransactionCompletion these in isolation. return Boolean.FALSE; } // // @Override // public String getCastTypeName(int code) { // switch ( code ) { // case Types.INTEGER: // case Types.BIGINT: // case Types.SMALLINT: // return "signed"; // case Types.FLOAT: // case Types.NUMERIC: // case Types.REAL: // return "decimal"; // case Types.VARCHAR: // return "char"; // case Types.VARBINARY: // return "binary"; // default: // return super.getCastTypeName( code ); // } // } @Override public boolean supportsCurrentTimestampSelection() { return true; } @Override public boolean isCurrentTimestampSelectStringCallable() { return false; } @Override public String getCurrentTimestampSelectString() { return "select now()"; } @Override public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException { return col; } @Override public ResultSet getResultSet(CallableStatement ps) throws SQLException { boolean isResultSet = ps.execute(); while ( !isResultSet && ps.getUpdateCount() != -1 ) { isResultSet = ps.getMoreResults(); } return ps.getResultSet(); } @Override public boolean supportsRowValueConstructorSyntax() { return true; } @Override public String renderOrderByElement(String expression, String collation, String order, NullPrecedence nulls) { final StringBuilder orderByElement = new StringBuilder(); if ( nulls != NullPrecedence.NONE ) { // Workaround for NULLS FIRST / LAST support. orderByElement.append( "case when " ).append( expression ).append( " is null then " ); if ( nulls == NullPrecedence.FIRST ) { orderByElement.append( "0 else 1" ); } else { orderByElement.append( "1 else 0" ); } orderByElement.append( " end, " ); } // Nulls precedence has already been handled so passing NONE value. orderByElement.append( super.renderOrderByElement( expression, collation, order, NullPrecedence.NONE ) ); return orderByElement.toString(); } // locking support @Override public String getForUpdateString() { return " for update"; } @Override public String getWriteLockString(int timeout) { return " for update"; } @Override public String getReadLockString(int timeout) { return " lock in share mode"; } // Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public boolean supportsEmptyInList() { return false; } @Override public boolean areStringComparisonsCaseInsensitive() { return true; } @Override public boolean supportsLobValueChangePropogation() { // note: at least my local MySQL 5.1 install shows this not working... return false; } @Override public boolean supportsSubqueryOnMutatingTable() { return false; } @Override public boolean supportsLockTimeouts() { // yes, we do handle "lock timeout" conditions in the exception conversion delegate, // but that's a hardcoded lock timeout period across the whole entire MySQL database. // MySQL does not support specifying lock timeouts as part of the SQL statement, which is really // what this meta method is asking. return false; } // @Override // public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { // return new SQLExceptionConversionDelegate() { // @Override // public JDBCException convert(SQLException sqlException, String message, String sql) { // final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException ); // // if ( "41000".equals( sqlState ) ) { // return new LockTimeoutException( message, sqlException, sql ); // } // // if ( "40001".equals( sqlState ) ) { // return new LockAcquisitionException( message, sqlException, sql ); // } // // return null; // } // }; // } @Override public String getNotExpression(String expression) { return "not (" + expression + ")"; } }