All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.community.dialect.IngresDialect Maven / Gradle / Ivy

The newest version!
/*
 * SPDX-License-Identifier: LGPL-2.1-or-later
 * 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"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy