HHH-8228 - support for SAP HANA

This commit is contained in:
Andrew Clemons 2013-10-10 16:05:18 +13:00 committed by Brett Meyer
parent 4d04f40fe0
commit c986fe9121
21 changed files with 950 additions and 87 deletions

View File

@ -0,0 +1,685 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.io.FilterReader;
import java.io.Reader;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.JDBCException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.ScrollMode;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.function.AnsiTrimFunction;
import org.hibernate.dialect.function.NoArgSQLFunction;
import org.hibernate.dialect.function.SQLFunctionTemplate;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.dialect.function.VarArgsSQLFunction;
import org.hibernate.engine.jdbc.CharacterStream;
import org.hibernate.engine.jdbc.ClobImplementer;
import org.hibernate.engine.jdbc.NClobImplementer;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.SQLGrammarException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.BasicBinder;
import org.hibernate.type.descriptor.sql.BitTypeDescriptor;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.NClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
/**
* An abstract base class for HANA dialects. <br/>
* <a href="http://help.sap.com/hana/html/sqlmain.html">SAP HANA Reference</a> <br/>
* This dialect is currently configured to <b>not</b> create foreign keys by
* returning the empty string from {@link #getAddForeignKeyConstraintString}
* since they currently have caveats compared to other databases. This does not
* affect using this dialect with your own DDL scripts which use foreign keys.
*
* @author Andrew Clemons <andrew.clemons@sap.com>
*/
public abstract class AbstractHANADialect extends Dialect {
private static class CloseSuppressingReader extends FilterReader {
protected CloseSuppressingReader( final Reader in ) {
super(in);
}
@Override
public void close() {
// do not close
}
}
// the ClobTypeDescriptor and NClobTypeDescriptor for HANA are slightly
// changed from the standard ones. The HANA JDBC driver currently closes any
// stream passed in via
// PreparedStatement.setCharacterStream(int,Reader,long)
// after the stream has been processed. this causes problems later if we are
// using non-contexual lob creation and HANA then closes our StringReader.
// see test case LobLocatorTest
private static final ClobTypeDescriptor HANA_CLOB_STREAM_BINDING =
new ClobTypeDescriptor() {
/** serial version uid. */
private static final long serialVersionUID = -379042275442752102L;
@Override
public <X> BasicBinder<X> getClobBinder( final JavaTypeDescriptor<X> javaTypeDescriptor ) {
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBind( final PreparedStatement st, final X value, final int index, final WrapperOptions options )
throws SQLException {
final CharacterStream characterStream = javaTypeDescriptor.unwrap( value, CharacterStream.class, options );
if (value instanceof ClobImplementer) {
st.setCharacterStream( index, new CloseSuppressingReader(characterStream.asReader()), characterStream.getLength() );
} else {
st.setCharacterStream( index, characterStream.asReader(), characterStream.getLength() );
}
}
};
}
};
private static final NClobTypeDescriptor HANA_NCLOB_STREAM_BINDING =
new NClobTypeDescriptor() {
/** serial version uid. */
private static final long serialVersionUID = 5651116091681647859L;
@Override
public <X> BasicBinder<X> getNClobBinder( final JavaTypeDescriptor<X> javaTypeDescriptor ) {
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBind( final PreparedStatement st, final X value, final int index, final WrapperOptions options )
throws SQLException {
final CharacterStream characterStream = javaTypeDescriptor.unwrap( value, CharacterStream.class, options );
if (value instanceof NClobImplementer) {
st.setCharacterStream( index, new CloseSuppressingReader(characterStream.asReader()), characterStream.getLength() );
} else {
st.setCharacterStream( index, characterStream.asReader(), characterStream.getLength() );
}
}
};
}
};
/**
*/
public AbstractHANADialect() {
super();
registerColumnType( Types.DECIMAL, "decimal($p, $s)" );
registerColumnType( Types.DOUBLE, "double" );
// varbinary max length 5000
registerColumnType( Types.BINARY, 5000, "varbinary($l)" );
registerColumnType( Types.VARBINARY, 5000, "varbinary($l)" );
registerColumnType( Types.LONGVARBINARY, 5000, "varbinary($l)" );
// for longer values, map to blob
registerColumnType( Types.BINARY, "blob" );
registerColumnType( Types.VARBINARY, "blob" );
registerColumnType( Types.LONGVARBINARY, "blob" );
registerColumnType( Types.CHAR, "varchar(1)" );
registerColumnType( Types.VARCHAR, 5000, "varchar($l)" );
registerColumnType( Types.LONGVARCHAR, 5000, "varchar($l)" );
registerColumnType( Types.NVARCHAR, 5000, "nvarchar($l)" );
// for longer values map to clob/nclob
registerColumnType( Types.LONGVARCHAR, "clob" );
registerColumnType( Types.VARCHAR, "clob" );
registerColumnType( Types.NVARCHAR, "nclob" );
registerColumnType( Types.CLOB, "clob" );
registerColumnType( Types.BOOLEAN, "tinyint" );
// map bit/tinyint to smallint since tinyint is unsigned on HANA
registerColumnType( Types.BIT, "smallint" );
registerColumnType( Types.TINYINT, "smallint" );
registerHibernateType( Types.NCLOB, StandardBasicTypes.NCLOB.getName() );
registerHibernateType( Types.NVARCHAR, StandardBasicTypes.STRING.getName() );
registerFunction( "to_date", new StandardSQLFunction( "to_date", StandardBasicTypes.DATE ) );
registerFunction( "to_seconddate", new StandardSQLFunction( "to_seconddate", StandardBasicTypes.TIMESTAMP ) );
registerFunction( "to_time", new StandardSQLFunction( "to_time", StandardBasicTypes.TIME ) );
registerFunction( "to_timestamp", new StandardSQLFunction( "to_timestamp", StandardBasicTypes.TIMESTAMP ) );
registerFunction( "current_date", new NoArgSQLFunction( "current_date", StandardBasicTypes.DATE, false ) );
registerFunction( "current_time", new NoArgSQLFunction( "current_time", StandardBasicTypes.TIME, false ) );
registerFunction( "current_timestamp", new NoArgSQLFunction( "current_timestamp", StandardBasicTypes.TIMESTAMP,
false ) );
registerFunction( "current_utcdate", new NoArgSQLFunction( "current_utcdate", StandardBasicTypes.DATE, false ) );
registerFunction( "current_utctime", new NoArgSQLFunction( "current_utctime", StandardBasicTypes.TIME, false ) );
registerFunction( "current_utctimestamp", new NoArgSQLFunction( "current_utctimestamp",
StandardBasicTypes.TIMESTAMP, false ) );
registerFunction( "add_days", new StandardSQLFunction( "add_days" ) );
registerFunction( "add_months", new StandardSQLFunction( "add_months" ) );
registerFunction( "add_seconds", new StandardSQLFunction( "add_seconds" ) );
registerFunction( "add_years", new StandardSQLFunction( "add_years" ) );
registerFunction( "dayname", new StandardSQLFunction( "dayname", StandardBasicTypes.STRING ) );
registerFunction( "dayofmonth", new StandardSQLFunction( "dayofmonth", StandardBasicTypes.INTEGER ) );
registerFunction( "dayofyear", new StandardSQLFunction( "dayofyear", StandardBasicTypes.INTEGER ) );
registerFunction( "days_between", new StandardSQLFunction( "days_between", StandardBasicTypes.INTEGER ) );
registerFunction( "hour", new StandardSQLFunction( "hour", StandardBasicTypes.INTEGER ) );
registerFunction( "isoweek", new StandardSQLFunction( "isoweek", StandardBasicTypes.STRING ) );
registerFunction( "last_day", new StandardSQLFunction( "last_day", StandardBasicTypes.DATE ) );
registerFunction( "localtoutc", new StandardSQLFunction( "localtoutc", StandardBasicTypes.TIMESTAMP ) );
registerFunction( "minute", new StandardSQLFunction( "minute", StandardBasicTypes.INTEGER ) );
registerFunction( "month", new StandardSQLFunction( "month", StandardBasicTypes.INTEGER ) );
registerFunction( "monthname", new StandardSQLFunction( "monthname", StandardBasicTypes.STRING ) );
registerFunction( "next_day", new StandardSQLFunction( "next_day", StandardBasicTypes.DATE ) );
registerFunction( "now", new NoArgSQLFunction( "now", StandardBasicTypes.TIMESTAMP, true ) );
registerFunction( "quarter", new StandardSQLFunction( "quarter", StandardBasicTypes.STRING ) );
registerFunction( "second", new StandardSQLFunction( "second", StandardBasicTypes.INTEGER ) );
registerFunction( "seconds_between", new StandardSQLFunction( "seconds_between", StandardBasicTypes.LONG ) );
registerFunction( "week", new StandardSQLFunction( "week", StandardBasicTypes.INTEGER ) );
registerFunction( "weekday", new StandardSQLFunction( "weekday", StandardBasicTypes.INTEGER ) );
registerFunction( "year", new StandardSQLFunction( "year", StandardBasicTypes.INTEGER ) );
registerFunction( "utctolocal", new StandardSQLFunction( "utctolocal", StandardBasicTypes.TIMESTAMP ) );
registerFunction( "to_bigint", new StandardSQLFunction( "to_bigint", StandardBasicTypes.LONG ) );
registerFunction( "to_binary", new StandardSQLFunction( "to_binary", StandardBasicTypes.BINARY ) );
registerFunction( "to_decimal", new StandardSQLFunction( "to_decimal", StandardBasicTypes.BIG_DECIMAL ) );
registerFunction( "to_double", new StandardSQLFunction( "to_double", StandardBasicTypes.DOUBLE ) );
registerFunction( "to_int", new StandardSQLFunction( "to_int", StandardBasicTypes.INTEGER ) );
registerFunction( "to_integer", new StandardSQLFunction( "to_integer", StandardBasicTypes.INTEGER ) );
registerFunction( "to_real", new StandardSQLFunction( "to_real", StandardBasicTypes.FLOAT ) );
registerFunction( "to_smalldecimal",
new StandardSQLFunction( "to_smalldecimal", StandardBasicTypes.BIG_DECIMAL ) );
registerFunction( "to_smallint", new StandardSQLFunction( "to_smallint", StandardBasicTypes.SHORT ) );
registerFunction( "to_tinyint", new StandardSQLFunction( "to_tinyint", StandardBasicTypes.BYTE ) );
registerFunction( "abs", new StandardSQLFunction( "abs" ) );
registerFunction( "acos", new StandardSQLFunction( "acos", StandardBasicTypes.DOUBLE ) );
registerFunction( "asin", new StandardSQLFunction( "asin", StandardBasicTypes.DOUBLE ) );
registerFunction( "atan2", new StandardSQLFunction( "atan", StandardBasicTypes.DOUBLE ) );
registerFunction( "bin2hex", new StandardSQLFunction( "bin2hex", StandardBasicTypes.STRING ) );
registerFunction( "bitand", new StandardSQLFunction( "bitand", StandardBasicTypes.LONG ) );
registerFunction( "ceil", new StandardSQLFunction( "ceil" ) );
registerFunction( "cos", new StandardSQLFunction( "cos", StandardBasicTypes.DOUBLE ) );
registerFunction( "cosh", new StandardSQLFunction( "cosh", StandardBasicTypes.DOUBLE ) );
registerFunction( "cot", new StandardSQLFunction( "cos", StandardBasicTypes.DOUBLE ) );
registerFunction( "exp", new StandardSQLFunction( "exp", StandardBasicTypes.DOUBLE ) );
registerFunction( "floor", new StandardSQLFunction( "floor" ) );
registerFunction( "greatest", new StandardSQLFunction( "greatest" ) );
registerFunction( "hex2bin", new StandardSQLFunction( "hex2bin", StandardBasicTypes.BINARY ) );
registerFunction( "least", new StandardSQLFunction( "least" ) );
registerFunction( "ln", new StandardSQLFunction( "ln", StandardBasicTypes.DOUBLE ) );
registerFunction( "log", new StandardSQLFunction( "ln", StandardBasicTypes.DOUBLE ) );
registerFunction( "power", new StandardSQLFunction( "power" ) );
registerFunction( "round", new StandardSQLFunction( "round" ) );
registerFunction( "mod", new StandardSQLFunction( "mod", StandardBasicTypes.INTEGER ) );
registerFunction( "sign", new StandardSQLFunction( "sign", StandardBasicTypes.INTEGER ) );
registerFunction( "sin", new StandardSQLFunction( "sin", StandardBasicTypes.DOUBLE ) );
registerFunction( "sinh", new StandardSQLFunction( "sinh", StandardBasicTypes.DOUBLE ) );
registerFunction( "sqrt", new StandardSQLFunction( "sqrt", StandardBasicTypes.DOUBLE ) );
registerFunction( "tan", new StandardSQLFunction( "tan", StandardBasicTypes.DOUBLE ) );
registerFunction( "tanh", new StandardSQLFunction( "tanh", StandardBasicTypes.DOUBLE ) );
registerFunction( "uminus", new StandardSQLFunction( "uminus" ) );
registerFunction( "to_alphanum", new StandardSQLFunction( "to_alphanum", StandardBasicTypes.STRING ) );
registerFunction( "to_nvarchar", new StandardSQLFunction( "to_nvarchar", StandardBasicTypes.STRING ) );
registerFunction( "to_varchar", new StandardSQLFunction( "to_varchar", StandardBasicTypes.STRING ) );
registerFunction( "ascii", new StandardSQLFunction( "ascii", StandardBasicTypes.INTEGER ) );
registerFunction( "char", new StandardSQLFunction( "char", StandardBasicTypes.CHARACTER ) );
registerFunction( "concat", new VarArgsSQLFunction( StandardBasicTypes.STRING, "(", "||", ")" ) );
registerFunction( "lcase", new StandardSQLFunction( "lcase", StandardBasicTypes.STRING ) );
registerFunction( "left", new StandardSQLFunction( "left", StandardBasicTypes.STRING ) );
registerFunction( "length", new StandardSQLFunction( "length", StandardBasicTypes.LONG ) );
registerFunction( "locate", new StandardSQLFunction( "locate", StandardBasicTypes.INTEGER ) );
registerFunction( "lpad", new StandardSQLFunction( "lpad", StandardBasicTypes.STRING ) );
registerFunction( "ltrim", new StandardSQLFunction( "ltrim", StandardBasicTypes.STRING ) );
registerFunction( "nchar", new StandardSQLFunction( "nchar", StandardBasicTypes.STRING ) );
registerFunction( "replace", new StandardSQLFunction( "replace", StandardBasicTypes.STRING ) );
registerFunction( "right", new StandardSQLFunction( "right", StandardBasicTypes.STRING ) );
registerFunction( "rpad", new StandardSQLFunction( "rpad", StandardBasicTypes.STRING ) );
registerFunction( "rtrim", new StandardSQLFunction( "rtrim", StandardBasicTypes.STRING ) );
registerFunction( "substr_after", new StandardSQLFunction( "substr_after", StandardBasicTypes.STRING ) );
registerFunction( "substr_before", new StandardSQLFunction( "substr_before", StandardBasicTypes.STRING ) );
registerFunction( "substring", new StandardSQLFunction( "substring", StandardBasicTypes.STRING ) );
registerFunction( "trim", new AnsiTrimFunction() );
registerFunction( "ucase", new StandardSQLFunction( "ucase", StandardBasicTypes.STRING ) );
registerFunction( "unicode", new StandardSQLFunction( "unicode", StandardBasicTypes.INTEGER ) );
registerFunction( "bit_length", new SQLFunctionTemplate( StandardBasicTypes.INTEGER, "length(to_binary(?1))*8" ) );
registerFunction( "to_blob", new StandardSQLFunction( "to_blob", StandardBasicTypes.BLOB ) );
registerFunction( "to_clob", new StandardSQLFunction( "to_clob", StandardBasicTypes.CLOB ) );
registerFunction( "to_nclob", new StandardSQLFunction( "to_nclob", StandardBasicTypes.NCLOB ) );
registerFunction( "coalesce", new StandardSQLFunction( "coalesce" ) );
registerFunction( "current_connection", new NoArgSQLFunction( "current_connection", StandardBasicTypes.INTEGER,
false ) );
registerFunction( "current_schema", new NoArgSQLFunction( "current_schema", StandardBasicTypes.STRING, false ) );
registerFunction( "current_user", new NoArgSQLFunction( "current_user", StandardBasicTypes.STRING, false ) );
registerFunction( "grouping_id", new VarArgsSQLFunction( StandardBasicTypes.INTEGER, "(", ",", ")" ) );
registerFunction( "ifnull", new StandardSQLFunction( "ifnull" ) );
registerFunction( "map", new StandardSQLFunction( "map" ) );
registerFunction( "nullif", new StandardSQLFunction( "nullif" ) );
registerFunction( "session_context", new StandardSQLFunction( "session_context" ) );
registerFunction( "session_user", new NoArgSQLFunction( "session_user", StandardBasicTypes.STRING, false ) );
registerFunction( "sysuuid", new NoArgSQLFunction( "sysuuid", StandardBasicTypes.STRING, false ) );
registerHanaKeywords();
// createBlob() and createClob() are not supported by the HANA JDBC driver
getDefaultProperties().setProperty( AvailableSettings.NON_CONTEXTUAL_LOB_CREATION, "true" );
}
@Deprecated
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(final SQLException sqlException, final String message, final String sql) {
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
if ( errorCode == 131 ) {
// 131 - Transaction rolled back by lock wait timeout
return new LockTimeoutException( message, sqlException, sql );
}
if ( errorCode == 146 ) {
// 146 - Resource busy and acquire with NOWAIT specified
return new LockTimeoutException( message, sqlException, sql );
}
if ( errorCode == 132 ) {
// 132 - Transaction rolled back due to unavailable resource
return new LockAcquisitionException( message, sqlException, sql );
}
if ( errorCode == 133 ) {
// 133 - Transaction rolled back by detected deadlock
return new LockAcquisitionException( message, sqlException, sql );
}
// 259 - Invalid table name
// 260 - Invalid column name
// 261 - Invalid index name
// 262 - Invalid query name
// 263 - Invalid alias name
if ( errorCode == 257 || ( errorCode >= 259 && errorCode <= 263 ) ) {
throw new SQLGrammarException( message, sqlException, sql );
}
// 257 - Cannot insert NULL or update to NULL
// 301 - Unique constraint violated
// 461 - foreign key constraint violation
// 462 - failed on update or delete by foreign key constraint violation
if ( errorCode == 287 || errorCode == 301 || errorCode == 461 || errorCode == 462 ) {
final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName(
sqlException );
return new ConstraintViolationException( message, sqlException, sql, constraintName );
}
return null;
}
};
}
@Override
public boolean forUpdateOfColumns() {
return true;
}
@Override
public String getAddColumnString() {
return "add (";
}
@Override
public String getAddColumnSuffixString() {
return ")";
}
@Override
public String getCascadeConstraintsString() {
return " cascade";
}
@Override
public String getCreateSequenceString( final String sequenceName ) {
return "create sequence " + sequenceName;
}
@Override
public String getCreateTemporaryTableString() {
return "create global temporary table";
}
@Override
public String getCurrentTimestampSelectString() {
return "select current_timestamp from dummy";
}
@Override
public String getDropSequenceString( final String sequenceName ) {
return "drop sequence " + sequenceName;
}
@Override
public String getForUpdateString( final String aliases ) {
return getForUpdateString() + " of " + aliases;
}
@Override
public String getForUpdateString( final String aliases, final LockOptions lockOptions ) {
LockMode lockMode = lockOptions.getLockMode();
final Iterator<Map.Entry<String, LockMode>> itr = lockOptions.getAliasLockIterator();
while ( itr.hasNext() ) {
// seek the highest lock mode
final Map.Entry<String, LockMode> entry = itr.next();
final LockMode lm = entry.getValue();
if ( lm.greaterThan( lockMode ) ) {
lockMode = lm;
}
}
// not sure why this is sometimes empty
if ( aliases == null || "".equals( aliases ) ) {
return getForUpdateString( lockMode );
}
return getForUpdateString( lockMode ) + " of " + aliases;
}
@Deprecated
@Override
public String getLimitString( final String sql, final boolean hasOffset ) {
return new StringBuilder( sql.length() + 20 ).append( sql )
.append( hasOffset ? " limit ? offset ?" : " limit ?" ).toString();
}
@Override
public String getNotExpression( final String expression ) {
return "not (" + expression + ")";
}
@Override
public String getQuerySequencesString() {
return "select sequence_name from sys.sequences";
}
@Override
public String getSelectSequenceNextValString( final String sequenceName ) {
return sequenceName + ".nextval";
}
@Override
public String getSequenceNextValString( final String sequenceName ) {
return "select " + getSelectSequenceNextValString( sequenceName ) + " from dummy";
}
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride( final int sqlCode ) {
switch ( sqlCode ) {
case Types.BOOLEAN:
return BitTypeDescriptor.INSTANCE;
case Types.CLOB:
return HANA_CLOB_STREAM_BINDING;
case Types.NCLOB:
return HANA_NCLOB_STREAM_BINDING;
case Types.TINYINT:
// tinyint is unsigned on HANA
return SmallIntTypeDescriptor.INSTANCE;
default:
return super.getSqlTypeDescriptorOverride( sqlCode );
}
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
protected void registerHanaKeywords() {
registerKeyword( "all" );
registerKeyword( "alter" );
registerKeyword( "as" );
registerKeyword( "before" );
registerKeyword( "begin" );
registerKeyword( "both" );
registerKeyword( "case" );
registerKeyword( "char" );
registerKeyword( "condition" );
registerKeyword( "connect" );
registerKeyword( "cross" );
registerKeyword( "cube" );
registerKeyword( "current_connection" );
registerKeyword( "current_date" );
registerKeyword( "current_schema" );
registerKeyword( "current_time" );
registerKeyword( "current_timestamp" );
registerKeyword( "current_user" );
registerKeyword( "current_utcdate" );
registerKeyword( "current_utctime" );
registerKeyword( "current_utctimestamp" );
registerKeyword( "currval" );
registerKeyword( "cursor" );
registerKeyword( "declare" );
registerKeyword( "distinct" );
registerKeyword( "else" );
registerKeyword( "elseif" );
registerKeyword( "elsif" );
registerKeyword( "end" );
registerKeyword( "except" );
registerKeyword( "exception" );
registerKeyword( "exec" );
registerKeyword( "for" );
registerKeyword( "from" );
registerKeyword( "full" );
registerKeyword( "group" );
registerKeyword( "having" );
registerKeyword( "if" );
registerKeyword( "in" );
registerKeyword( "inner" );
registerKeyword( "inout" );
registerKeyword( "intersect" );
registerKeyword( "into" );
registerKeyword( "is" );
registerKeyword( "join" );
registerKeyword( "leading" );
registerKeyword( "left" );
registerKeyword( "limit" );
registerKeyword( "loop" );
registerKeyword( "minus" );
registerKeyword( "natural" );
registerKeyword( "nextval" );
registerKeyword( "null" );
registerKeyword( "on" );
registerKeyword( "order" );
registerKeyword( "out" );
registerKeyword( "prior" );
registerKeyword( "return" );
registerKeyword( "returns" );
registerKeyword( "reverse" );
registerKeyword( "right" );
registerKeyword( "rollup" );
registerKeyword( "rowid" );
registerKeyword( "select" );
registerKeyword( "set" );
registerKeyword( "sql" );
registerKeyword( "start" );
registerKeyword( "sysdate" );
registerKeyword( "systime" );
registerKeyword( "systimestamp" );
registerKeyword( "sysuuid" );
registerKeyword( "top" );
registerKeyword( "trailing" );
registerKeyword( "union" );
registerKeyword( "using" );
registerKeyword( "utcdate" );
registerKeyword( "utctime" );
registerKeyword( "utctimestamp" );
registerKeyword( "values" );
registerKeyword( "when" );
registerKeyword( "where" );
registerKeyword( "while" );
registerKeyword( "with" );
}
@Override
public boolean supportsCircularCascadeDeleteConstraints() {
// HANA does not support circular constraints
return false;
}
/**
* HANA does support cascade deletes, but since we have overridden the
* foreign key support, this should also be false.
*/
@Override
public boolean supportsCascadeDelete() {
return false;
}
@Override
public ScrollMode defaultScrollMode() {
return ScrollMode.FORWARD_ONLY;
}
/**
* HANA currently does not support check constraints.
*/
@Override
public boolean supportsColumnCheck() {
return false;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public boolean supportsEmptyInList() {
return false;
}
@Override
public boolean supportsExistsInSelect() {
return false;
}
@Override
public boolean supportsExpectedLobUsagePattern() {
// http://scn.sap.com/thread/3221812
return false;
}
@Deprecated
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean supportsPooledSequences() {
return true;
}
@Override
public boolean supportsSequences() {
return true;
}
@Override
public boolean supportsTableCheck() {
return false;
}
@Override
public boolean supportsTemporaryTables() {
return true;
}
@Override
public boolean supportsTupleDistinctCounts() {
return false;
}
@Override
public boolean supportsUnionAll() {
return true;
}
@Override
public boolean dropConstraints() {
return false;
}
@Override
public boolean supportsRowValueConstructorSyntax() {
return true;
}
@Override
public boolean supportsRowValueConstructorSyntaxInInList() {
return true;
}
@Override
public int getMaxAliasLength() {
return 128;
}
/**
* Currently disabling foreign key creation when using Hibernate's auto-ddl
* feature. HANA does allow creating foreign keys, but they do not always
* behave as expected.
*/
@Override
public String getAddForeignKeyConstraintString( final String constraintName,
final String[] foreignKey, final String referencedTable,
final String[] primaryKey, final boolean referencesPrimaryKey ) {
return "";
}
}

View File

@ -2023,6 +2023,15 @@ public abstract class Dialect implements ConversionContext {
throw new UnsupportedOperationException( "No add column syntax supported by " + getClass().getName() );
}
/**
* The syntax for the suffix used to add a column to a table (optional).
*
* @return The suffix "add column" fragment.
*/
public String getAddColumnSuffixString() {
return "";
}
public String getDropForeignKeyString() {
return " drop constraint ";
}

View File

@ -0,0 +1,49 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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;
/**
* An SQL dialect for HANA. <br/>
* <a href="http://help.sap.com/hana/html/sqlmain.html">SAP HANA Reference</a> <br/>
* Column tables are created by this dialect when using the auto-ddl feature.
* This dialect was tested with HANA Rev 67 and HDB JDBC 1.00.67.383230.
*
* @author Andrew Clemons <andrew.clemons@sap.com>
*/
public class HANAColumnStoreDialect extends AbstractHANADialect {
/**
*/
public HANAColumnStoreDialect() {
super();
}
@Override
public String getCreateTableString() {
return "create column table";
}
}

View File

@ -0,0 +1,42 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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;
/**
* An SQL dialect for HANA. <br/>
* <a href="http://help.sap.com/hana/html/sqlmain.html">SAP HANA Reference</a> <br/>
* Row tables are created by this dialect when using the auto-ddl feature.
* This dialect was tested with HANA Rev 67 and HDB JDBC 1.00.67.383230.
*
* @author Andrew Clemons <andrew.clemons@sap.com>
*/
public class HANARowStoreDialect extends AbstractHANADialect {
/**
*/
public HANARowStoreDialect() {
super();
}
}

View File

@ -32,6 +32,7 @@ import org.hibernate.dialect.DerbyTenSevenDialect;
import org.hibernate.dialect.DerbyTenSixDialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HANAColumnStoreDialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.InformixDialect;
import org.hibernate.dialect.Ingres10Dialect;
@ -206,6 +207,10 @@ public class StandardDialectResolver implements DialectResolver {
}
}
if ( "HDB".equals( databaseName ) ) {
return new HANAColumnStoreDialect();
}
return null;
}
}

View File

@ -438,6 +438,8 @@ public class Table implements RelationalModel, Serializable {
alter.append( dialect.getColumnComment( columnComment ) );
}
alter.append( dialect.getAddColumnSuffixString() );
results.add( alter.toString() );
}

View File

@ -12,6 +12,7 @@ import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Restrictions;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.mapping.PersistentClass;
@ -349,8 +350,8 @@ public class EnumeratedTypeTest extends BaseCoreFunctionalTestCase {
@Test
@TestForIssue(jiraKey = "HHH-4699")
@SkipForDialect(value = Oracle8iDialect.class, jiraKey = "HHH-8516",
comment = "HHH-4699 was specifically for using a CHAR, but Oracle does not handle the 2nd query correctly without VARCHAR. ")
@SkipForDialect(value = { Oracle8iDialect.class, AbstractHANADialect.class }, jiraKey = "HHH-8516",
comment = "HHH-4699 was specifically for using a CHAR, but Oracle/HANA do not handle the 2nd query correctly without VARCHAR. ")
public void testTrimmedEnumChar() throws SQLException {
// use native SQL to insert, forcing whitespace to occur
final Session s = openSession();

View File

@ -29,12 +29,16 @@ import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Emmanuel Bernard
*/
public class GenericsTest extends BaseCoreFunctionalTestCase {
@SkipForDialect(value = AbstractHANADialect.class, comment = "known bug in HANA: rs.next() returns false for org.hibernate.id.enhanced.SequenceStructure$1.getNextValue() for this test")
@Test
public void testManyToOneGenerics() throws Exception {
Paper white = new Paper();

View File

@ -31,6 +31,7 @@ import java.sql.Types;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.MySQLMyISAMDialect;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.ResultSetReturn;
@ -57,8 +58,8 @@ public class SQLExceptionConversionTest extends BaseCoreFunctionalTestCase {
@Test
@SkipForDialect(
value = MySQLMyISAMDialect.class,
comment = "MySQL (MyISAM) does not support FK violation checking"
value = { MySQLMyISAMDialect.class, AbstractHANADialect.class },
comment = "MySQL (MyISAM) / Hana do not support FK violation checking"
)
public void testIntegrityViolation() throws Exception {
final Session session = openSession();

View File

@ -42,6 +42,7 @@ import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.QueryException;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
@ -51,6 +52,7 @@ import org.hibernate.cfg.Environment;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.IngresDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.Oracle8iDialect;
@ -754,9 +756,16 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
else {
s.createQuery( "from Animal where lower(upper('foo') || upper(:bar)) like 'f%'" ).setString( "bar", "xyz" ).list();
}
if ( ! ( getDialect() instanceof PostgreSQLDialect|| getDialect() instanceof PostgreSQL81Dialect || getDialect() instanceof MySQLDialect ) ) {
s.createQuery( "from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0" ).setLong( "param", 1 ).list();
if ( !( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof PostgreSQL81Dialect
|| getDialect() instanceof MySQLDialect || getDialect() instanceof AbstractHANADialect ) ) {
s.createQuery( "from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0" )
.setLong( "param", 1 ).list();
}
else if ( getDialect() instanceof AbstractHANADialect ) {
s.createQuery( "from Animal where abs(cast(1 as double) - cast(:param as double)) = 1.0" )
.setLong( "param", 1 ).list();
}
s.getTransaction().commit();
s.close();
}
@ -1116,7 +1125,11 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
s.createQuery( "from Human h where h.name = ('John', 'X', 'Doe')" ).list();
s.createQuery( "from Human h where ('John', 'X', 'Doe') = h.name" ).list();
s.createQuery( "from Human h where ('John', 'X', 'Doe') <> h.name" ).list();
s.createQuery( "from Human h where ('John', 'X', 'Doe') >= h.name" ).list();
// HANA only allows '=' and '<>'/'!='
if ( ! ( getDialect() instanceof AbstractHANADialect ) ) {
s.createQuery( "from Human h where ('John', 'X', 'Doe') >= h.name" ).list();
}
s.createQuery( "from Human h order by h.name" ).list();
@ -1479,7 +1492,13 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
// note: simply performing syntax and column/table resolution checking in the db
Session s = openSession();
s.beginTransaction();
s.createQuery( "from Animal where mother = :mother" ).setParameter( "mother", null ).list();
if ( getDialect() instanceof AbstractHANADialect ) {
s.createQuery( "from Animal where mother is null" ).list();
}
else {
s.createQuery( "from Animal where mother = :mother" ).setParameter( "mother", null ).list();
}
s.getTransaction().commit();
s.close();
}
@ -2925,7 +2944,8 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
session = openSession();
ScrollableResults sr = session.createQuery( query )
.setResultTransformer(Transformers.aliasToBean(Animal.class)).scroll();
.setResultTransformer(Transformers.aliasToBean(Animal.class)).scroll();
assertTrue( "Incorrect result size", sr.next() );
assertTrue( "Incorrect return type", sr.get(0) instanceof Animal );
assertFalse( session.contains( sr.get( 0 ) ) );
@ -2988,7 +3008,8 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
session = openSession();
ScrollableResults sr = session.createQuery( query )
.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).scroll();
.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).scroll();
assertTrue( "Incorrect result size", sr.next() );
assertTrue( "Incorrect return type", sr.get(0) instanceof Map );
assertFalse( session.contains( sr.get( 0 ) ) );
@ -3068,17 +3089,20 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
* PostgreSQL >= 8.3.7 typecasts are no longer automatically allowed
* <link>http://www.postgresql.org/docs/current/static/release-8-3.html</link>
*/
if(getDialect() instanceof PostgreSQLDialect || getDialect() instanceof PostgreSQL81Dialect || getDialect() instanceof HSQLDialect){
if ( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof PostgreSQL81Dialect
|| getDialect() instanceof HSQLDialect ) {
hql = "from Animal a where bit_length(str(a.bodyWeight)) = 24";
}
else{
else {
hql = "from Animal a where bit_length(a.bodyWeight) = 24";
}
session.createQuery(hql).list();
if(getDialect() instanceof PostgreSQLDialect || getDialect() instanceof PostgreSQL81Dialect || getDialect() instanceof HSQLDialect){
if ( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof PostgreSQL81Dialect
|| getDialect() instanceof HSQLDialect ) {
hql = "select bit_length(str(a.bodyWeight)) from Animal a";
}else{
}
else {
hql = "select bit_length(a.bodyWeight) from Animal a";
}

View File

@ -37,6 +37,7 @@ import org.junit.Test;
import org.hibernate.QueryException;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.IngresDialect;
import org.hibernate.dialect.MySQLDialect;
@ -140,7 +141,7 @@ public class HQLTest extends QueryTranslatorTestCase {
}
@Test
@SkipForDialect( Oracle8iDialect.class )
@SkipForDialect( value = { Oracle8iDialect.class, AbstractHANADialect.class } )
public void testRowValueConstructorSyntaxInInListBeingTranslated() {
QueryTranslatorImpl translator = createNewQueryTranslator("from LineItem l where l.id in (?)");
assertInExist("'in' should be translated to 'and'", false, translator);
@ -358,6 +359,11 @@ public class HQLTest extends QueryTranslatorTestCase {
if ( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof PostgreSQL81Dialect ) {
return;
}
if ( getDialect() instanceof AbstractHANADialect ) {
// HANA returns
// ...al0_7_.mammal where [abs(cast(1 as float(19))-cast(? as float(19)))=1.0]
return;
}
assertTranslation("from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0");
}

View File

@ -23,25 +23,27 @@
*/
package org.hibernate.test.hql;
import org.hibernate.dialect.CUBRIDDialect;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.hibernate.HibernateException;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.dialect.CUBRIDDialect;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.SybaseASE15Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.SkipForDialects;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Test;
/**
* Tests the new functionality of allowing scrolling of results which
@ -72,7 +74,9 @@ public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase
}
@Test
@SkipForDialect( value = SybaseASE15Dialect.class, jiraKey = "HHH-5229")
@SkipForDialects(value = {
@SkipForDialect(value = SybaseASE15Dialect.class , jiraKey = "HHH-5229"),
@SkipForDialect(value = { AbstractHANADialect.class }, comment = "HANA only supports forward-only cursors.") })
public void testScrollingJoinFetchesEmptyResultSet() {
Session s = openSession();
Transaction txn = s.beginTransaction();
@ -140,11 +144,10 @@ public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase
}
@Test
@SkipForDialect(
value = CUBRIDDialect.class,
comment = "As of verion 8.4.1 CUBRID doesn't support temporary tables. This test fails with" +
"HibernateException: cannot doAfterTransactionCompletion multi-table deletes using dialect not supporting temp tables"
)
@SkipForDialects(value = {
@SkipForDialect(value = CUBRIDDialect.class, comment = "As of verion 8.4.1 CUBRID doesn't support temporary tables. This test fails with"
+ "HibernateException: cannot doAfterTransactionCompletion multi-table deletes using dialect not supporting temp tables"),
@SkipForDialect(value = AbstractHANADialect.class, comment = "HANA only supports forward-only cursors") })
public void testScrollingJoinFetchesSingleRowResultSet() {
Session s = openSession();
Transaction txn = s.beginTransaction();
@ -173,13 +176,12 @@ public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase
.uniqueResult() );
ScrollableResults results = s
.createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" )
.setString( "desc", "root%" )
.scroll();
.createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" )
.setString( "desc", "root%" ).scroll();
assertFalse( results.isFirst() );
assertFalse( results.isLast() );
assertFalse( results.previous() );
assertFalse( results.previous() );
assertTrue( results.next() );
assertTrue( results.isFirst() );
@ -223,7 +225,7 @@ public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase
assertTrue( results.first() );
assertTrue( results.isFirst() );
assertTrue( results.isLast() );
assertTrue( results.isLast() );
for ( int i=1; i<3; i++ ) {
assertTrue( results.setRowNumber( 1 ) );
@ -298,11 +300,10 @@ public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase
}
@Test
@SkipForDialect(
value = CUBRIDDialect.class,
comment = "As of verion 8.4.1 CUBRID doesn't support temporary tables. This test fails with" +
"HibernateException: cannot doAfterTransactionCompletion multi-table deletes using dialect not supporting temp tables"
)
@SkipForDialects(value = {
@SkipForDialect(value = CUBRIDDialect.class, comment = "As of verion 8.4.1 CUBRID doesn't support temporary tables. This test fails with"
+ "HibernateException: cannot doAfterTransactionCompletion multi-table deletes using dialect not supporting temp tables"),
@SkipForDialect(value = AbstractHANADialect.class, comment = "HANA only supports forward-only cursors.") })
public void testScrollingJoinFetchesReverse() {
TestData data = new TestData();
data.prepare();
@ -310,10 +311,10 @@ public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase
Session s = openSession();
Transaction txn = s.beginTransaction();
ScrollableResults results = s
.createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" )
.setString( "desc", "root%" )
.scroll();
ScrollableResults results = s
.createQuery(
"from Animal a left join fetch a.offspring where a.description like :desc order by a.id" )
.setString( "desc", "root%" ).scroll();
results.afterLast();
@ -332,11 +333,10 @@ public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase
}
@Test
@SkipForDialect(
value = CUBRIDDialect.class,
comment = "As of verion 8.4.1 CUBRID doesn't support temporary tables. This test fails with" +
"HibernateException: cannot doAfterTransactionCompletion multi-table deletes using dialect not supporting temp tables"
)
@SkipForDialects(value = {
@SkipForDialect(value = CUBRIDDialect.class, comment = "As of verion 8.4.1 CUBRID doesn't support temporary tables. This test fails with"
+ "HibernateException: cannot doAfterTransactionCompletion multi-table deletes using dialect not supporting temp tables"),
@SkipForDialect(value = AbstractHANADialect.class, comment = "HANA only supports forward-only cursors.") })
public void testScrollingJoinFetchesPositioning() {
TestData data = new TestData();
data.prepare();
@ -344,7 +344,7 @@ public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase
Session s = openSession();
Transaction txn = s.beginTransaction();
ScrollableResults results = s
ScrollableResults results = s
.createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" )
.setString( "desc", "root%" )
.scroll();
@ -440,7 +440,7 @@ public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase
private void cleanup() {
Session s = openSession();
Transaction txn = s.beginTransaction();
s.createQuery( "delete Animal where description like 'grand%'" ).executeUpdate();
s.createQuery( "delete Animal where not description like 'root%'" ).executeUpdate();
s.createQuery( "delete Animal" ).executeUpdate();

View File

@ -19,6 +19,7 @@ import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.engine.spi.SessionImplementor;
@ -28,8 +29,8 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.junit.Test;
@SkipForDialect( value = { Oracle8iDialect.class },
comment = "Oracle does not support the identity column used in the mapping. Extended by NoIdentityHQLScrollFetchTest" )
@SkipForDialect( value = { Oracle8iDialect.class, AbstractHANADialect.class },
comment = "Oracle/HANA do not support the identity column used in the mapping. Extended by NoIdentityHQLScrollFetchTest" )
public class HQLScrollFetchTest extends BaseCoreFunctionalTestCase {
private static final String QUERY = "select p from Parent p join fetch p.children c";
@ -42,7 +43,7 @@ public class HQLScrollFetchTest extends BaseCoreFunctionalTestCase {
}
@Test
@SkipForDialect( { SQLServerDialect.class, Oracle8iDialect.class, H2Dialect.class, DB2Dialect.class } )
@SkipForDialect( { SQLServerDialect.class, Oracle8iDialect.class, H2Dialect.class, DB2Dialect.class, AbstractHANADialect.class } )
public void testScroll() {
Session s = openSession();
ScrollableResults results = s.createQuery( QUERY ).scroll();

View File

@ -1,10 +1,11 @@
package org.hibernate.test.hqlfetchscroll;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.testing.RequiresDialect;
@RequiresDialect( value = { Oracle8iDialect.class },
comment = "Oracle does not support the identity column used in the HQLScrollFetchTest mapping." )
@RequiresDialect( value = { Oracle8iDialect.class, AbstractHANADialect.class },
comment = "Oracle/HANA do not support the identity column used in the HQLScrollFetchTest mapping." )
public class NoIdentityHQLScrollFetchTest extends HQLScrollFetchTest {
@Override

View File

@ -25,18 +25,18 @@ package org.hibernate.test.instrument.runtime;
import java.lang.reflect.InvocationTargetException;
import org.junit.Rule;
import org.junit.Test;
import org.hibernate.HibernateException;
import org.hibernate.bytecode.buildtime.spi.BasicClassFilter;
import org.hibernate.bytecode.buildtime.spi.FieldFilter;
import org.hibernate.bytecode.spi.BytecodeProvider;
import org.hibernate.bytecode.spi.InstrumentedClassLoader;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.hibernate.testing.junit4.ClassLoadingIsolater;
import org.junit.Rule;
import org.junit.Test;
/**
* @author Steve Ebersole
@ -90,25 +90,25 @@ public abstract class AbstractTransformingClassLoaderInstrumentTestCase extends
}
@Test
@SkipForDialect( value = MySQLDialect.class, comment = "wrong sql in mapping, mysql needs double type, but it is float type in mapping")
@SkipForDialect( value = { MySQLDialect.class, AbstractHANADialect.class }, comment = "wrong sql in mapping, mysql/hana need double type, but it is float type in mapping")
public void testFetchAll() throws Exception {
executeExecutable( "org.hibernate.test.instrument.cases.TestFetchAllExecutable" );
}
@Test
@SkipForDialect( value = MySQLDialect.class, comment = "wrong sql in mapping, mysql needs double type, but it is float type in mapping")
@SkipForDialect( value = { MySQLDialect.class, AbstractHANADialect.class }, comment = "wrong sql in mapping, mysql/hana need double type, but it is float type in mapping")
public void testLazy() {
executeExecutable( "org.hibernate.test.instrument.cases.TestLazyExecutable" );
}
@Test
@SkipForDialect( value = MySQLDialect.class, comment = "wrong sql in mapping, mysql needs double type, but it is float type in mapping")
@SkipForDialect( value = { MySQLDialect.class, AbstractHANADialect.class }, comment = "wrong sql in mapping, mysql/hana need double type, but it is float type in mapping")
public void testLazyManyToOne() {
executeExecutable( "org.hibernate.test.instrument.cases.TestLazyManyToOneExecutable" );
}
@Test
@SkipForDialect( value = MySQLDialect.class, comment = "wrong sql in mapping, mysql needs double type, but it is float type in mapping")
@SkipForDialect( value = { MySQLDialect.class, AbstractHANADialect.class }, comment = "wrong sql in mapping, mysql/hana need double type, but it is float type in mapping")
public void testPropertyInitialized() {
executeExecutable( "org.hibernate.test.instrument.cases.TestIsPropertyInitializedExecutable" );
}
@ -129,10 +129,10 @@ public abstract class AbstractTransformingClassLoaderInstrumentTestCase extends
}
@Test
@SkipForDialect( value = MySQLDialect.class, comment = "wrong sql in mapping, mysql needs double type, but it is float type in mapping")
@SkipForDialect( value = { MySQLDialect.class, AbstractHANADialect.class }, comment = "wrong sql in mapping, mysql/hana need double type, but it is float type in mapping")
public void testCustomColumnReadAndWrite() {
executeExecutable( "org.hibernate.test.instrument.cases.TestCustomColumnReadAndWrite" );
}
}
// reflection code to ensure isolation into the created classloader ~~~~~~~

View File

@ -27,6 +27,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.hibernate.Session;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.test.jpa.AbstractJPATest;
import org.hibernate.testing.SkipForDialect;
@ -36,8 +37,8 @@ import org.junit.Test;
/**
* @author Steve Ebersole
*/
@SkipForDialect(value = Oracle8iDialect.class,
comment = "Oracle does not support identity key generation")
@SkipForDialect(value = { Oracle8iDialect.class, AbstractHANADialect.class },
comment = "Oracle/Hana do not support identity key generation")
public class MutableNaturalIdTest extends AbstractJPATest {
@Override
protected Class<?>[] getAnnotatedClasses() {

View File

@ -64,6 +64,7 @@ import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
@ -71,6 +72,7 @@ import org.hibernate.criterion.Restrictions;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.InterbaseDialect;
import org.hibernate.dialect.MckoiDialect;
@ -84,7 +86,7 @@ import org.hibernate.dialect.Sybase11Dialect;
import org.hibernate.dialect.SybaseASE15Dialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.dialect.TimesTenDialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.util.SerializationHelper;
@ -92,10 +94,10 @@ import org.hibernate.internal.util.collections.JoinedIterator;
import org.hibernate.jdbc.AbstractReturningWork;
import org.hibernate.jdbc.AbstractWork;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.env.ConnectionProviderBuilder;
import org.hibernate.type.StandardBasicTypes;
@ -2298,7 +2300,7 @@ public class FooBarTest extends LegacyTestCase {
s.createQuery( "select count(*) from Baz as baz where 1 in indices(baz.fooArray)" ).list();
s.createQuery( "select count(*) from Bar as bar where 'abc' in elements(bar.baz.fooArray)" ).list();
s.createQuery( "select count(*) from Bar as bar where 1 in indices(bar.baz.fooArray)" ).list();
if ( !(getDialect() instanceof DB2Dialect) && !(getDialect() instanceof Oracle8iDialect ) && !( getDialect() instanceof SybaseDialect ) && !( getDialect() instanceof Sybase11Dialect ) && !( getDialect() instanceof SybaseASE15Dialect ) && !( getDialect() instanceof PostgreSQLDialect ) && !(getDialect() instanceof PostgreSQL81Dialect)) {
if ( !(getDialect() instanceof DB2Dialect) && !(getDialect() instanceof Oracle8iDialect ) && !( getDialect() instanceof SybaseDialect ) && !( getDialect() instanceof Sybase11Dialect ) && !( getDialect() instanceof SybaseASE15Dialect ) && !( getDialect() instanceof PostgreSQLDialect ) && !(getDialect() instanceof PostgreSQL81Dialect) && !(getDialect() instanceof AbstractHANADialect)) {
// SybaseAnywhereDialect supports implicit conversions from strings to ints
s.createQuery(
"select count(*) from Bar as bar, bar.component.glarch.proxyArray as g where g.id in indices(bar.baz.fooArray)"
@ -4015,7 +4017,8 @@ public class FooBarTest extends LegacyTestCase {
s.getTransaction().commit();
s.close();
}
@SkipForDialect(value = AbstractHANADialect.class, comment = "HANA currently requires specifying table name by 'FOR UPDATE of t1.c1' if there are more than one tables/views/subqueries in the FROM clause")
@Test
public void testNewSessionLifecycle() throws Exception {
Session s = openSession();
@ -4053,6 +4056,7 @@ public class FooBarTest extends LegacyTestCase {
s.beginTransaction();
try {
Foo f = (Foo) s.load(Foo.class, fid, LockMode.UPGRADE);
s.delete(f);
s.flush();
s.getTransaction().commit();
@ -4293,6 +4297,7 @@ public class FooBarTest extends LegacyTestCase {
s.close();
}
@SkipForDialect(value = AbstractHANADialect.class, comment = "HANA currently requires specifying table name by 'FOR UPDATE of t1.c1' if there are more than one tables/views/subqueries in the FROM clause")
@Test
public void testRefresh() throws Exception {
final Session s = openSession();

View File

@ -20,7 +20,6 @@ import java.util.Properties;
import java.util.Set;
import org.junit.Test;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.FlushMode;
@ -32,6 +31,7 @@ import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.MckoiDialect;
import org.hibernate.dialect.MySQLDialect;
@ -347,7 +347,13 @@ public class FumTest extends LegacyTestCase {
s = openSession();
txn = s.beginTransaction();
fum = (Fum) s.load( Fum.class, fumKey("fum"), LockMode.UPGRADE );
if ( getDialect() instanceof AbstractHANADialect ){
// HANA currently requires specifying table name by 'FOR UPDATE of t1.c1' if there are more than one tables/views/subqueries in the FROM clause
fum = (Fum) s.load( Fum.class, fumKey("fum") );
} else {
fum = (Fum) s.load( Fum.class, fumKey("fum"), LockMode.UPGRADE );
}
assertTrue( "load by composite key", fum!=null );
Fum fum2 = new Fum( fumKey("fi") );

View File

@ -22,6 +22,7 @@ import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.jdbc.Work;
@ -358,13 +359,17 @@ public class MultiTableTest extends LegacyTestCase {
t.commit();
s.close();
s = openSession();
t = s.beginTransaction();
multi = (Multi) s.load(Top.class, mid, LockMode.UPGRADE);
simp = (Top) s.load(Top.class, sid);
s.lock(simp, LockMode.UPGRADE_NOWAIT);
t.commit();
s.close();
// HANA currently requires specifying table name by 'FOR UPDATE of t1.c1'
// if there are more than one tables/views/subqueries in the FROM clause
if ( !( getDialect() instanceof AbstractHANADialect ) ) {
s = openSession();
t = s.beginTransaction();
multi = (Multi) s.load( Top.class, mid, LockMode.UPGRADE );
simp = (Top) s.load( Top.class, sid );
s.lock( simp, LockMode.UPGRADE_NOWAIT );
t.commit();
s.close();
}
s = openSession();
t = s.beginTransaction();
@ -476,13 +481,17 @@ public class MultiTableTest extends LegacyTestCase {
t.commit();
s.close();
s = openSession();
t = s.beginTransaction();
multi = (Multi) s.load( Top.class, multiId, LockMode.UPGRADE );
simp = (Top) s.load( Top.class, simpId );
s.lock(simp, LockMode.UPGRADE_NOWAIT);
t.commit();
s.close();
// HANA currently requires specifying table name by 'FOR UPDATE of t1.c1'
// if there are more than one tables/views/subqueries in the FROM clause
if ( !( getDialect() instanceof AbstractHANADialect ) ) {
s = openSession();
t = s.beginTransaction();
multi = (Multi) s.load( Top.class, multiId, LockMode.UPGRADE );
simp = (Top) s.load( Top.class, simpId );
s.lock( simp, LockMode.UPGRADE_NOWAIT );
t.commit();
s.close();
}
s = openSession();
t = s.beginTransaction();

View File

@ -26,6 +26,7 @@
*/
package org.hibernate.test.resulttransformer;
import java.sql.ResultSet;
import java.util.List;
import org.junit.Test;
@ -34,6 +35,7 @@ import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.transform.ResultTransformer;
@ -93,7 +95,14 @@ public class ResultTransformerTest extends BaseCoreFunctionalTestCase {
}
});
ScrollableResults sr = q.scroll();
sr.first();
// HANA supports only ResultSet.TYPE_FORWARD_ONLY and
// does not support java.sql.ResultSet.first()
if (getDialect() instanceof AbstractHANADialect) {
sr.next();
} else {
sr.first();
}
Object[] row = sr.get();
assertEquals(1, row.length);
Object obj = row[0];

View File

@ -20,6 +20,7 @@ import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.test.sql.hand.Dimension;
@ -796,6 +797,7 @@ public class NativeSQLQueriesTest extends BaseCoreFunctionalTestCase {
s.close();
}
@SkipForDialect(value = AbstractHANADialect.class, comment = "On HANA, this returns an clob for the text column which doesn't get mapped to a String")
@Test
public void testTextTypeInSQLQuery() {
Session s = openSession();
@ -816,6 +818,7 @@ public class NativeSQLQueriesTest extends BaseCoreFunctionalTestCase {
s.close();
}
@SkipForDialect(value = AbstractHANADialect.class, comment = "On HANA, this returns a blob for the image column which doesn't get mapped to a byte[]")
@Test
public void testImageTypeInSQLQuery() {
Session s = openSession();