autoquote column names with initial _ on those dbs that require it

This commit is contained in:
Gavin King 2022-01-07 17:08:06 +01:00
parent 54b5a85af4
commit 32f4122470
6 changed files with 59 additions and 7 deletions

View File

@ -21,6 +21,8 @@ import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.dialect.unique.DB2UniqueDelegate;
import org.hibernate.dialect.unique.UniqueDelegate;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
@ -53,6 +55,7 @@ import org.hibernate.type.descriptor.jdbc.*;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import java.sql.CallableStatement;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
@ -727,4 +730,11 @@ public class DB2Dialect extends Dialect {
public String generatedAs(String generatedAs) {
return " generated always as (" + generatedAs + ")";
}
@Override
public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData)
throws SQLException {
builder.setAutoQuoteInitialUnderscore(true);
return super.buildIdentifierHelper(builder, dbMetaData);
}
}

View File

@ -24,6 +24,8 @@ import org.hibernate.dialect.sequence.DerbySequenceSupport;
import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
@ -64,6 +66,8 @@ import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
import org.hibernate.type.descriptor.jdbc.TimestampJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import jakarta.persistence.TemporalType;
@ -876,4 +880,11 @@ public class DerbyDialect extends Dialect {
// It seems at least the row_number function is supported as of 10.4
return getVersion().isSameOrAfter( 10, 4 );
}
@Override
public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData)
throws SQLException {
builder.setAutoQuoteInitialUnderscore(true);
return super.buildIdentifierHelper(builder, dbMetaData);
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.dialect;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.JDBCException;
@ -31,6 +32,8 @@ import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.dialect.temptable.TemporaryTable;
import org.hibernate.dialect.temptable.TemporaryTableKind;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -785,4 +788,10 @@ public class HSQLDialect extends Dialect {
}
}
@Override
public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData)
throws SQLException {
builder.setAutoQuoteInitialUnderscore(true);
return super.buildIdentifierHelper(builder, dbMetaData);
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.dialect;
import java.sql.CallableStatement;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
@ -32,6 +33,8 @@ import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.LockAcquisitionException;
@ -1262,4 +1265,11 @@ public class OracleDialect extends Dialect {
public String generatedAs(String generatedAs) {
return " generated always as (" + generatedAs + ")";
}
@Override
public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData)
throws SQLException {
builder.setAutoQuoteInitialUnderscore(true);
return super.buildIdentifierHelper(builder, dbMetaData);
}
}

View File

@ -31,6 +31,7 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
private final boolean globallyQuoteIdentifiers;
private final boolean globallyQuoteIdentifiersSkipColumnDefinitions;
private final boolean autoQuoteKeywords;
private final boolean autoQuoteInitialUnderscore;
private final TreeSet<String> reservedWords;
private final IdentifierCaseStrategy unquotedCaseStrategy;
private final IdentifierCaseStrategy quotedCaseStrategy;
@ -41,6 +42,7 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
boolean globallyQuoteIdentifiers,
boolean globallyQuoteIdentifiersSkipColumnDefinitions,
boolean autoQuoteKeywords,
boolean autoQuoteInitialUnderscore,
TreeSet<String> reservedWords, //careful, we intentionally omit making a defensive copy to not waste memory
IdentifierCaseStrategy unquotedCaseStrategy,
IdentifierCaseStrategy quotedCaseStrategy) {
@ -49,6 +51,7 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
this.globallyQuoteIdentifiers = globallyQuoteIdentifiers;
this.globallyQuoteIdentifiersSkipColumnDefinitions = globallyQuoteIdentifiersSkipColumnDefinitions;
this.autoQuoteKeywords = autoQuoteKeywords;
this.autoQuoteInitialUnderscore = autoQuoteInitialUnderscore;
this.reservedWords = reservedWords;
this.unquotedCaseStrategy = unquotedCaseStrategy == null ? IdentifierCaseStrategy.UPPER : unquotedCaseStrategy;
this.quotedCaseStrategy = quotedCaseStrategy == null ? IdentifierCaseStrategy.MIXED : quotedCaseStrategy;
@ -76,6 +79,11 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
return Identifier.toIdentifier( identifier.getText(), true );
}
if ( autoQuoteInitialUnderscore && identifier.getText().startsWith("_") ) {
log.tracef( "Forcing identifier [%s] to quoted due to initial underscore", identifier );
return Identifier.toIdentifier( identifier.getText(), true );
}
return identifier;
}
@ -96,7 +104,7 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
@Override
public boolean isReservedWord(String word) {
if ( autoQuoteKeywords == false ) {
if ( !autoQuoteKeywords ) {
throw new AssertionFailure( "The reserved keywords map is only initialized if autoQuoteKeywords is true" );
}
return reservedWords.contains( word );

View File

@ -40,6 +40,7 @@ public class IdentifierHelperBuilder {
private boolean globallyQuoteIdentifiers = false;
private boolean skipGlobalQuotingForColumnDefinitions = false;
private boolean autoQuoteKeywords = true;
private boolean autoQuoteInitialUnderscore = false;
private IdentifierCaseStrategy unquotedCaseStrategy = IdentifierCaseStrategy.UPPER;
private IdentifierCaseStrategy quotedCaseStrategy = IdentifierCaseStrategy.MIXED;
@ -64,11 +65,10 @@ public class IdentifierHelperBuilder {
}
//Important optimisation: skip loading all keywords from the DB when autoQuoteKeywords is disabled
if ( autoQuoteKeywords == false ) {
return;
}
if ( autoQuoteKeywords ) {
this.reservedWords.addAll( parseKeywords( metaData.getSQLKeywords() ) );
}
}
private static List<String> parseKeywords(String extraKeywordsString) {
return StringHelper.parseCommaSeparatedString( extraKeywordsString );
@ -153,6 +153,10 @@ public class IdentifierHelperBuilder {
this.autoQuoteKeywords = autoQuoteKeywords;
}
public void setAutoQuoteInitialUnderscore(boolean autoQuoteInitialUnderscore) {
this.autoQuoteInitialUnderscore = autoQuoteInitialUnderscore;
}
public NameQualifierSupport getNameQualifierSupport() {
return nameQualifierSupport;
}
@ -187,11 +191,10 @@ public class IdentifierHelperBuilder {
public void applyReservedWords(Collection<String> words) {
//No use when autoQuoteKeywords is disabled
if ( autoQuoteKeywords == false ) {
return;
}
if ( autoQuoteKeywords ) {
this.reservedWords.addAll( words );
}
}
public void applyReservedWords(Set<String> words) {
applyReservedWords( (Collection<String>) words );
@ -218,6 +221,7 @@ public class IdentifierHelperBuilder {
globallyQuoteIdentifiers,
skipGlobalQuotingForColumnDefinitions,
autoQuoteKeywords,
autoQuoteInitialUnderscore,
reservedWords,
unquotedCaseStrategy,
quotedCaseStrategy