org.hibernate.community.dialect.IngresDialect Maven / Gradle / Ivy
                 Go to download
                
        
                    Show more of this group  Show more artifacts with this name
Show all versions of hibernate-community-dialects Show documentation
                Show all versions of hibernate-community-dialects Show documentation
Hibernate's community supported dialects
                
             The newest version!
        
        /*
 * SPDX-License-Identifier: Apache-2.0
 * Copyright Red Hat Inc. and Hibernate Authors
 */
package org.hibernate.community.dialect;
import java.sql.Types;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.community.dialect.identity.Ingres10IdentityColumnSupport;
import org.hibernate.community.dialect.identity.Ingres9IdentityColumnSupport;
import org.hibernate.community.dialect.pagination.FirstLimitHandler;
import org.hibernate.community.dialect.pagination.IngresLimitHandler;
import org.hibernate.community.dialect.sequence.IngresLegacySequenceSupport;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.sequence.ANSISequenceSupport;
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.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.common.FetchClauseType;
import org.hibernate.query.sqm.IntervalType;
import org.hibernate.query.common.TemporalUnit;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.sql.SqmTranslator;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.query.sqm.sql.StandardSqmTranslatorFactory;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.internal.SequenceNameExtractorImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import jakarta.persistence.TemporalType;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
import static org.hibernate.type.SqlTypes.BINARY;
import static org.hibernate.type.SqlTypes.BLOB;
import static org.hibernate.type.SqlTypes.BOOLEAN;
import static org.hibernate.type.SqlTypes.CLOB;
import static org.hibernate.type.SqlTypes.DATE;
import static org.hibernate.type.SqlTypes.DECIMAL;
import static org.hibernate.type.SqlTypes.NCLOB;
import static org.hibernate.type.SqlTypes.NUMERIC;
import static org.hibernate.type.SqlTypes.VARBINARY;
/**
 * An SQL dialect for Ingres 9.2.
 * 
 * Known limitations: 
 *     - 
 *         Only supports simple constants or columns on the left side of an IN,
 *         making {@code (1,2,3) in (...)} or {@code (subselect) in (...)} non-supported.
 *     
 
 *     - 
 *         Supports only 39 digits in decimal.
 *     
 
 *     - 
 *         Explicitly set USE_GET_GENERATED_KEYS property to false.
 *     
 
 *     - 
 *         Perform string casts to varchar; removes space padding.
 *     
 
 * 
 *
 * @author Ian Booth
 * @author Bruce Lunsford
 * @author Max Rydahl Andersen
 * @author Raymond Fan
 */
public class IngresDialect extends Dialect {
	private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 9, 2 );
	private final LimitHandler limitHandler;
	private final SequenceSupport sequenceSupport;
	public IngresDialect() {
		this( DEFAULT_VERSION );
	}
	public IngresDialect(DialectResolutionInfo info) {
		this( info.makeCopyOrDefault( DEFAULT_VERSION ) );
		registerKeywords( info );
	}
	/**
	 * Constructs a IngresDialect
	 */
	public IngresDialect(DatabaseVersion version) {
		super( version );
		if ( getVersion().isSameOrAfter( 9, 3 ) ) {
			limitHandler = IngresLimitHandler.INSTANCE;
			sequenceSupport = ANSISequenceSupport.INSTANCE;
		}
		else {
			limitHandler = FirstLimitHandler.INSTANCE;
			sequenceSupport = IngresLegacySequenceSupport.INSTANCE;
		}
	}
	@Override
	protected String columnType(int sqlTypeCode) {
		//TODO: should we be using nchar/nvarchar/long nvarchar
		//      here? I think Ingres char/varchar types don't
		//      support Unicode. Copy what HANADialect
		//      does with a Hibernate property to config this.
		switch ( sqlTypeCode ) {
			case BOOLEAN:
				return getVersion().isBefore( 10 ) ? "tinyint" : super.columnType( sqlTypeCode );
			// Not completely necessary, given that Ingres
			// can be configured to set DATE = ANSIDATE
			case DATE:
				return getVersion().isBefore( 10 ) && getVersion().isSameOrAfter( 9, 3 )
						? "ansidate"
						: super.columnType( sqlTypeCode );
			//Ingres has no 'numeric' type
			case NUMERIC:
				return castType( DECIMAL );
			case BINARY:
				return "byte($l)";
			case VARBINARY:
				return "varbyte($l)";
			//note: 'long byte' is a  synonym for 'blob'
			case BLOB:
				return "long byte($l)";
			//note: 'long varchar' is a synonym for 'clob'
			case CLOB:
				return "long varchar($l)";
			//note: 'long varchar' is a synonym for 'nclob'
			case NCLOB:
				return "long nvarchar($l)";
			default:
				return super.columnType( sqlTypeCode );
		}
	}
	@Override
	public boolean getDefaultUseGetGeneratedKeys() {
		// Ingres driver supports getGeneratedKeys but only in the following
		// form:
		// The Ingres DBMS returns only a single table key or a single object
		// key per insert statement. Ingres does not return table and object
		// keys for INSERT AS SELECT statements. Depending on the keys that are
		// produced by the statement executed, auto-generated key parameters in
		// execute(), executeUpdate(), and prepareStatement() methods are
		// ignored and getGeneratedKeys() returns a result-set containing no
		// rows, a single row with one column, or a single row with two columns.
		// Ingres JDBC Driver returns table and object keys as BINARY values.
		return false;
	}
	@Override
	public int getMaxVarcharLength() {
		// the maximum possible (configurable) value for
		// both varchar and varbyte
		return 32_000;
	}
	@Override
	public int getMaxNVarcharLength() {
		// the maximum possible (configurable) value for
		// nvarchar
		return 16_000;
	}
	@Override
	public JdbcType resolveSqlTypeDescriptor(
			String columnTypeName,
			int jdbcTypeCode,
			int precision,
			int scale,
			JdbcTypeRegistry jdbcTypeRegistry) {
		if ( jdbcTypeCode == Types.BIT ) {
			return jdbcTypeRegistry.getDescriptor( Types.BOOLEAN );
		}
		return super.resolveSqlTypeDescriptor(
				columnTypeName,
				jdbcTypeCode,
				precision,
				scale,
				jdbcTypeRegistry
		);
	}
	@Override
	public int getPreferredSqlTypeCodeForBoolean() {
		return getVersion().isBefore( 10 ) ? Types.BIT : Types.BOOLEAN;
	}
	@Override
	public void appendBooleanValueString(SqlAppender appender, boolean bool) {
		if ( getVersion().isBefore( 10 ) ) {
			appender.appendSql( bool ? '1' : '0' );
		}
		else {
			appender.appendSql( bool );
		}
	}
	@Override
	public int getDefaultDecimalPrecision() {
		//the maximum
		return 39;
	}
	@Override
	public void initializeFunctionRegistry(FunctionContributions functionContributions) {
		super.initializeFunctionRegistry(functionContributions);
		final BasicTypeRegistry basicTypeRegistry = functionContributions.getTypeConfiguration().getBasicTypeRegistry();
		final BasicType stringType = basicTypeRegistry.resolve( StandardBasicTypes.STRING );
		// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Common functions
		CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions);
		functionFactory.log();
		functionFactory.rand();
		functionFactory.soundex();
		functionFactory.octetLength();
		functionFactory.repeat();
		functionFactory.trim2();
		functionFactory.dateTrunc();
		functionFactory.trunc_dateTrunc();
		functionFactory.initcap();
		functionFactory.yearMonthDay();
		functionFactory.hourMinuteSecond();
		functionFactory.dayofweekmonthyear();
		functionFactory.weekQuarter();
		functionFactory.lastDay();
		functionFactory.concat_pipeOperator();
		functionFactory.substr();
		functionFactory.monthsBetween();
		functionFactory.substring_substr();
		//also natively supports ANSI-style substring()
		functionFactory.ascii();
		functionFactory.char_chr();
		functionFactory.sysdate();
		functionFactory.position();
		functionFactory.format_dateFormat();
		functionFactory.bitLength_pattern( "octet_length(hex(?1))*4" );
		final BasicType integerType = functionContributions.getTypeConfiguration().getBasicTypeRegistry()
				.resolve( StandardBasicTypes.INTEGER );
		functionContributions.getFunctionRegistry().registerBinaryTernaryPattern(
				"locate",
				integerType,
				"position(?1 in ?2)",
				"(position(?1 in substring(?2 from ?3))+(?3)-1)",
				STRING, STRING, INTEGER,
				functionContributions.getTypeConfiguration()
		).setArgumentListSignature("(pattern, string[, start])");
		functionContributions.getFunctionRegistry().registerPattern( "extract", "date_part('?1',?2)", integerType );
		functionFactory.bitandorxornot_bitAndOrXorNot();
		functionContributions.getFunctionRegistry().namedDescriptorBuilder( "squeeze" )
				.setExactArgumentCount( 1 )
				.setInvariantType( stringType )
				.register();
		// No idea since when this is supported
		functionFactory.windowFunctions();
		functionFactory.listagg( null );
		functionFactory.inverseDistributionOrderedSetAggregates();
		functionFactory.hypotheticalOrderedSetAggregates();
	}
	@Override
	public SqmTranslatorFactory getSqmTranslatorFactory() {
		return new StandardSqmTranslatorFactory() {
			@Override
			public SqmTranslator createSelectTranslator(
					SqmSelectStatement> sqmSelectStatement,
					QueryOptions queryOptions,
					DomainParameterXref domainParameterXref,
					QueryParameterBindings domainParameterBindings,
					LoadQueryInfluencers loadQueryInfluencers,
					SqlAstCreationContext creationContext,
					boolean deduplicateSelectionItems) {
				return new IngresSqmToSqlAstConverter<>(
						sqmSelectStatement,
						queryOptions,
						domainParameterXref,
						domainParameterBindings,
						loadQueryInfluencers,
						creationContext,
						deduplicateSelectionItems
				);
			}
		};
	}
	@Override
	public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
		return new StandardSqlAstTranslatorFactory() {
			@Override
			protected  SqlAstTranslator buildTranslator(
					SessionFactoryImplementor sessionFactory, Statement statement) {
				return new IngresSqlAstTranslator<>( sessionFactory, statement );
			}
		};
	}
	@Override
	public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
		return "timestampadd(?1,?2,?3)";
	}
	@Override
	public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
		return "timestampdiff(?1,?2,?3)";
	}
	@Override
	public TimeZoneSupport getTimeZoneSupport() {
		return TimeZoneSupport.NATIVE;
	}
	@Override
	public String getSelectGUIDString() {
		return "select uuid_to_char(uuid_create())";
	}
	@Override
	public boolean dropConstraints() {
		return false;
	}
	@Override
	public String getNullColumnString() {
		return " with null";
	}
	// SEQUENCE support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	@Override
	public SequenceSupport getSequenceSupport() {
		return sequenceSupport;
	}
	@Override
	public String getQuerySequencesString() {
		return getVersion().isBefore( 9, 3 )
				? "select seq_name from iisequence"
				: "select seq_name from iisequences";
	}
	@Override
	public SequenceInformationExtractor getSequenceInformationExtractor() {
		return SequenceNameExtractorImpl.INSTANCE;
	}
	@Override
	public String getLowercaseFunction() {
		return "lowercase";
	}
	@Override
	public LimitHandler getLimitHandler() {
		return limitHandler;
	}
	@Override
	public IdentityColumnSupport getIdentityColumnSupport() {
		if ( getVersion().isSameOrAfter( 10 ) ) {
			return Ingres10IdentityColumnSupport.INSTANCE;
		}
		else if ( getVersion().isSameOrAfter( 9, 3 ) ) {
			return Ingres9IdentityColumnSupport.INSTANCE;
		}
		else {
			return super.getIdentityColumnSupport();
		}
	}
	// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	/**
	 * {@code FOR UPDATE} only supported for cursors
	 *
	 * @return the empty string
	 */
	@Override
	public String getForUpdateString() {
		return "";
	}
	// current timestamp support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	@Override
	public boolean isCurrentTimestampSelectStringCallable() {
		return false;
	}
	@Override
	public boolean supportsCurrentTimestampSelection() {
		return getVersion().isSameOrAfter( 9, 3 );
	}
	@Override
	public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
			EntityMappingType rootEntityDescriptor,
			RuntimeModelCreationContext runtimeModelCreationContext) {
		return new GlobalTemporaryTableMutationStrategy(
				TemporaryTable.createIdTable(
						rootEntityDescriptor,
						name -> "session." + TemporaryTable.ID_TABLE_PREFIX + name,
						this,
						runtimeModelCreationContext
				),
				runtimeModelCreationContext.getSessionFactory()
		);
	}
	@Override
	public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
			EntityMappingType rootEntityDescriptor,
			RuntimeModelCreationContext runtimeModelCreationContext) {
		return new GlobalTemporaryTableInsertStrategy(
				TemporaryTable.createEntityTable(
						rootEntityDescriptor,
						name -> "session." + TemporaryTable.ENTITY_TABLE_PREFIX + name,
						this,
						runtimeModelCreationContext
				),
				runtimeModelCreationContext.getSessionFactory()
		);
	}
	@Override
	public TemporaryTableKind getSupportedTemporaryTableKind() {
		return TemporaryTableKind.GLOBAL;
	}
	@Override
	public String getTemporaryTableCreateOptions() {
		return "on commit preserve rows with norecovery";
	}
	@Override
	public String getTemporaryTableCreateCommand() {
		return "declare global temporary table";
	}
	// union subclass support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	@Override
	public boolean supportsUnionAll() {
		return getVersion().isSameOrAfter( 9, 3 );
	}
	@Override
	public boolean supportsUnionInSubquery() {
		// At least not according to HHH-3637
		return false;
	}
	@Override
	public boolean supportsSubqueryInSelect() {
		// At least according to HHH-4961
		return getVersion().isSameOrAfter( 10 );
	}
	@Override
	public boolean supportsOrderByInSubquery() {
		// This is just a guess
		return false;
	}
	@Override
	public boolean supportsWindowFunctions() {
		return getVersion().isSameOrAfter( 10, 2 );
	}
// Informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	@Override
	public boolean doesReadCommittedCauseWritersToBlockReaders() {
		return getVersion().isSameOrAfter( 9, 3 );
	}
	@Override
	public boolean doesRepeatableReadCauseReadersToBlockWriters() {
		return getVersion().isSameOrAfter( 9, 3 );
	}
	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	@Override
	public boolean supportsSubselectAsInPredicateLHS() {
		return false;
	}
	@Override
	public boolean supportsExpectedLobUsagePattern() {
		return false;
	}
	@Override
	public boolean supportsTupleDistinctCounts() {
		return false;
	}
	@Override
	public void appendDatetimeFormat(SqlAppender appender, String format) {
		appender.appendSql( MySQLDialect.datetimeFormat( format ).result() );
	}
	@Override
	public String translateExtractField(TemporalUnit unit) {
		switch ( unit ) {
			case DAY_OF_MONTH: return "day";
			case DAY_OF_YEAR: return "doy";
			case DAY_OF_WEEK: return "dow";
			case WEEK: return "iso_week";
			default: return super.translateExtractField( unit );
		}
	}
	@Override
	public boolean supportsFetchClause(FetchClauseType type) {
		return getVersion().isSameOrAfter( 9, 3 );
	}
	@Override
	public String getDual() {
		return "(select 0)";
	}
	@Override
	public String getFromDualForSelectOnly() {
		//this is only necessary if the query has a where clause
		return " from " + getDual() + " dual";
	}
	@Override
	public boolean supportsRowValueConstructorSyntax() {
		return false;
	}
	@Override
	public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
		return false;
	}
	@Override
	public boolean supportsRowValueConstructorSyntaxInInList() {
		return false;
	}
}
         © 2015 - 2025 Weber Informatics LLC | Privacy Policy