HHH-8228 cleanup, formatting, check for empty constraint alter table

statements before executing
This commit is contained in:
Brett Meyer 2013-10-10 11:27:28 -04:00
parent c986fe9121
commit f675b67c27
6 changed files with 91 additions and 91 deletions

View File

@ -63,18 +63,19 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
/** /**
* An abstract base class for HANA dialects. <br/> * An abstract base class for HANA dialects. <br/>
* <a href="http://help.sap.com/hana/html/sqlmain.html">SAP HANA Reference</a> <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} * NOTE: This dialect is currently configured to <b>not</b> create foreign keys by
* since they currently have caveats compared to other databases. This does not * 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. * affect using this dialect with your own DDL scripts which use foreign keys.
* *
* @author Andrew Clemons <andrew.clemons@sap.com> * @author Andrew Clemons <andrew.clemons@sap.com>
*/ */
public abstract class AbstractHANADialect extends Dialect { public abstract class AbstractHANADialect extends Dialect {
private static class CloseSuppressingReader extends FilterReader { private static class CloseSuppressingReader extends FilterReader {
protected CloseSuppressingReader( final Reader in ) { protected CloseSuppressingReader(final Reader in) {
super(in); super( in );
} }
@Override @Override
@ -91,56 +92,58 @@ public abstract class AbstractHANADialect extends Dialect {
// using non-contexual lob creation and HANA then closes our StringReader. // using non-contexual lob creation and HANA then closes our StringReader.
// see test case LobLocatorTest // see test case LobLocatorTest
private static final ClobTypeDescriptor HANA_CLOB_STREAM_BINDING = private static final ClobTypeDescriptor HANA_CLOB_STREAM_BINDING = new ClobTypeDescriptor() {
new ClobTypeDescriptor() { /** serial version uid. */
/** serial version uid. */ private static final long serialVersionUID = -379042275442752102L;
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> getClobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override @Override
public <X> BasicBinder<X> getNClobBinder( final JavaTypeDescriptor<X> javaTypeDescriptor ) { protected void doBind(final PreparedStatement st, final X value, final int index,
return new BasicBinder<X>( javaTypeDescriptor, this ) { final WrapperOptions options) throws SQLException {
@Override final CharacterStream characterStream = javaTypeDescriptor.unwrap( value, CharacterStream.class,
protected void doBind( final PreparedStatement st, final X value, final int index, final WrapperOptions options ) options );
throws SQLException {
final CharacterStream characterStream = javaTypeDescriptor.unwrap( value, CharacterStream.class, options );
if (value instanceof NClobImplementer) { if ( value instanceof ClobImplementer ) {
st.setCharacterStream( index, new CloseSuppressingReader(characterStream.asReader()), characterStream.getLength() ); st.setCharacterStream( index, new CloseSuppressingReader( characterStream.asReader() ),
} else { characterStream.getLength() );
st.setCharacterStream( index, 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() { public AbstractHANADialect() {
super(); super();
@ -359,7 +362,6 @@ public abstract class AbstractHANADialect extends Dialect {
return new ConstraintViolationException( message, sqlException, sql, constraintName ); return new ConstraintViolationException( message, sqlException, sql, constraintName );
} }
return null; return null;
} }
}; };
@ -372,7 +374,7 @@ public abstract class AbstractHANADialect extends Dialect {
@Override @Override
public String getAddColumnString() { public String getAddColumnString() {
return "add ("; return "add (";
} }
@Override @Override
@ -386,7 +388,7 @@ public abstract class AbstractHANADialect extends Dialect {
} }
@Override @Override
public String getCreateSequenceString( final String sequenceName ) { public String getCreateSequenceString(final String sequenceName) {
return "create sequence " + sequenceName; return "create sequence " + sequenceName;
} }
@ -401,17 +403,17 @@ public abstract class AbstractHANADialect extends Dialect {
} }
@Override @Override
public String getDropSequenceString( final String sequenceName ) { public String getDropSequenceString(final String sequenceName) {
return "drop sequence " + sequenceName; return "drop sequence " + sequenceName;
} }
@Override @Override
public String getForUpdateString( final String aliases ) { public String getForUpdateString(final String aliases) {
return getForUpdateString() + " of " + aliases; return getForUpdateString() + " of " + aliases;
} }
@Override @Override
public String getForUpdateString( final String aliases, final LockOptions lockOptions ) { public String getForUpdateString(final String aliases, final LockOptions lockOptions) {
LockMode lockMode = lockOptions.getLockMode(); LockMode lockMode = lockOptions.getLockMode();
final Iterator<Map.Entry<String, LockMode>> itr = lockOptions.getAliasLockIterator(); final Iterator<Map.Entry<String, LockMode>> itr = lockOptions.getAliasLockIterator();
while ( itr.hasNext() ) { while ( itr.hasNext() ) {
@ -433,13 +435,13 @@ public abstract class AbstractHANADialect extends Dialect {
@Deprecated @Deprecated
@Override @Override
public String getLimitString( final String sql, final boolean hasOffset ) { public String getLimitString(final String sql, final boolean hasOffset) {
return new StringBuilder( sql.length() + 20 ).append( sql ) return new StringBuilder( sql.length() + 20 ).append( sql )
.append( hasOffset ? " limit ? offset ?" : " limit ?" ).toString(); .append( hasOffset ? " limit ? offset ?" : " limit ?" ).toString();
} }
@Override @Override
public String getNotExpression( final String expression ) { public String getNotExpression(final String expression) {
return "not (" + expression + ")"; return "not (" + expression + ")";
} }
@ -449,17 +451,17 @@ public abstract class AbstractHANADialect extends Dialect {
} }
@Override @Override
public String getSelectSequenceNextValString( final String sequenceName ) { public String getSelectSequenceNextValString(final String sequenceName) {
return sequenceName + ".nextval"; return sequenceName + ".nextval";
} }
@Override @Override
public String getSequenceNextValString( final String sequenceName ) { public String getSequenceNextValString(final String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName ) + " from dummy"; return "select " + getSelectSequenceNextValString( sequenceName ) + " from dummy";
} }
@Override @Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride( final int sqlCode ) { protected SqlTypeDescriptor getSqlTypeDescriptorOverride(final int sqlCode) {
switch ( sqlCode ) { switch ( sqlCode ) {
case Types.BOOLEAN: case Types.BOOLEAN:
return BitTypeDescriptor.INSTANCE; return BitTypeDescriptor.INSTANCE;
@ -572,12 +574,11 @@ public abstract class AbstractHANADialect extends Dialect {
return false; return false;
} }
/**
* HANA does support cascade deletes, but since we have overridden the
* foreign key support, this should also be false.
*/
@Override @Override
public boolean supportsCascadeDelete() { public boolean supportsCascadeDelete() {
// HANA does support cascade deletes, but since we have (temporarily) overridden the foreign key support,
// this should also be false.
// TODO: Enable once FK support is solidified and getAddForeignKeyConstraintString is corrected.
return false; return false;
} }
@ -673,13 +674,13 @@ public abstract class AbstractHANADialect extends Dialect {
/** /**
* Currently disabling foreign key creation when using Hibernate's auto-ddl * Currently disabling foreign key creation when using Hibernate's auto-ddl
* feature. HANA does allow creating foreign keys, but they do not always * feature. HANA does allow creating foreign keys, but currently they do not always
* behave as expected. * behave as expected.
*/ */
@Override @Override
public String getAddForeignKeyConstraintString( final String constraintName, public String getAddForeignKeyConstraintString(final String constraintName, final String[] foreignKey,
final String[] foreignKey, final String referencedTable, final String referencedTable, final String[] primaryKey, final boolean referencesPrimaryKey) {
final String[] primaryKey, final boolean referencesPrimaryKey ) { // TODO: Re-evaluate in a later HANA release where, hopefully, this has been solidified.
return ""; return "";
} }
} }

View File

@ -27,14 +27,11 @@ package org.hibernate.dialect;
* An SQL dialect for HANA. <br/> * An SQL dialect for HANA. <br/>
* <a href="http://help.sap.com/hana/html/sqlmain.html">SAP HANA Reference</a> <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. * 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> * @author Andrew Clemons <andrew.clemons@sap.com>
*/ */
public class HANAColumnStoreDialect extends AbstractHANADialect { public class HANAColumnStoreDialect extends AbstractHANADialect {
/**
*/
public HANAColumnStoreDialect() { public HANAColumnStoreDialect() {
super(); super();
} }
@ -43,7 +40,4 @@ public class HANAColumnStoreDialect extends AbstractHANADialect {
public String getCreateTableString() { public String getCreateTableString() {
return "create column table"; return "create column table";
} }
} }

View File

@ -27,16 +27,15 @@ package org.hibernate.dialect;
* An SQL dialect for HANA. <br/> * An SQL dialect for HANA. <br/>
* <a href="http://help.sap.com/hana/html/sqlmain.html">SAP HANA Reference</a> <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. * 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> * @author Andrew Clemons <andrew.clemons@sap.com>
*/ */
public class HANARowStoreDialect extends AbstractHANADialect { public class HANARowStoreDialect extends AbstractHANADialect {
// Even though it's currently pointless, provide this structure in case HANA row store merits additional
// differences in the future.
/**
*/
public HANARowStoreDialect() { public HANARowStoreDialect() {
super(); super();
} }
} }

View File

@ -208,6 +208,7 @@ public class StandardDialectResolver implements DialectResolver {
} }
if ( "HDB".equals( databaseName ) ) { if ( "HDB".equals( databaseName ) ) {
// SAP recommends defaulting to column store.
return new HANAColumnStoreDialect(); return new HANAColumnStoreDialect();
} }

View File

@ -33,6 +33,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.annotations.common.util.StringHelper;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.Mapping;
@ -198,15 +199,18 @@ public abstract class Constraint implements RelationalModel, Serializable {
public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) { public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) {
if ( isGenerated( dialect ) ) { if ( isGenerated( dialect ) ) {
// Certain dialects (ex: HANA) don't support FKs as expected, but other constraints can still be created.
// If that's the case, hasAlterTable() will be true, but getAddForeignKeyConstraintString will return
// empty string. Prevent blank "alter table" statements.
String constraintString = sqlConstraintString( dialect, getName(), defaultCatalog, defaultSchema ); String constraintString = sqlConstraintString( dialect, getName(), defaultCatalog, defaultSchema );
StringBuilder buf = new StringBuilder( "alter table " ) if ( !StringHelper.isEmpty( constraintString ) ) {
.append( getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ) ) StringBuilder buf = new StringBuilder( "alter table " )
.append( constraintString ); .append( getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ) )
return buf.toString(); .append( constraintString );
} return buf.toString();
else { }
return null;
} }
return null;
} }
public List getColumns() { public List getColumns() {

View File

@ -756,13 +756,14 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
else { else {
s.createQuery( "from Animal where lower(upper('foo') || upper(:bar)) like 'f%'" ).setString( "bar", "xyz" ).list(); 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 || getDialect() instanceof AbstractHANADialect ) ) { if ( getDialect() instanceof AbstractHANADialect ) {
s.createQuery( "from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0" ) s.createQuery( "from Animal where abs(cast(1 as double) - cast(:param as double)) = 1.0" )
.setLong( "param", 1 ).list(); .setLong( "param", 1 ).list();
} }
else if ( getDialect() instanceof AbstractHANADialect ) { else if ( !( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof PostgreSQL81Dialect
s.createQuery( "from Animal where abs(cast(1 as double) - cast(:param as double)) = 1.0" ) || getDialect() instanceof MySQLDialect ) ) {
s.createQuery( "from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0" )
.setLong( "param", 1 ).list(); .setLong( "param", 1 ).list();
} }