Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.hibernate.dialect.Replacer;
import org.hibernate.dialect.SelectItemReferenceStrategy;
import org.hibernate.dialect.function.InsertSubstringOverlayEmulation;
import org.hibernate.dialect.function.TrimFunction;
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
Expand All @@ -38,6 +39,7 @@
import org.hibernate.query.sqm.CastType;
import org.hibernate.query.sqm.IntervalType;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.jdbc.VarcharUUIDJdbcType;
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
Expand Down Expand Up @@ -391,6 +393,18 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio

functionRegistry.register( "overlay",
new InsertSubstringOverlayEmulation( typeConfiguration, true ) );

// coalesce() has a bug where it does not accept parameters
// as arguments, even with a cast (on Informix 14)
functionRegistry.namedDescriptorBuilder( "coalesce" )
.setMinArgumentCount( 1 )
.setArgumentRenderingMode( SqlAstNodeRenderingMode.INLINE_PARAMETERS )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();

// parameter arguments to trim() require a cast
functionContributions.getFunctionRegistry().register( "trim",
new TrimFunction( this, typeConfiguration, SqlAstNodeRenderingMode.NO_UNTYPED ) );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.FunctionExpression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.from.NamedTableReference;
Expand Down Expand Up @@ -191,18 +190,6 @@ else if ( expression instanceof Summarization ) {
}
}

// @Override
// protected void renderNull(Literal literal) {
// if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.NO_UNTYPED ) {
// renderCasted( literal );
// }
// else {
// int sqlType = literal.getExpressionType().getSingleJdbcMapping().getJdbcType().getJdbcTypeCode();
// String nullString = getDialect().getSelectClauseNullString( sqlType, getSessionFactory().getTypeConfiguration() );
// appendSql( nullString );
// }
// }

@Override
protected void renderInsertIntoNoColumns(TableInsertStandard tableInsert) {
renderIntoIntoAndTable( tableInsert );
Expand Down Expand Up @@ -295,36 +282,22 @@ protected void visitArithmeticOperand(Expression expression) {
}
}

@Override
public void visitSelfRenderingExpression(SelfRenderingExpression expression) {
final boolean isStringFunctionWithParameterArg =
expression instanceof FunctionExpression fn
&& expression.getExpressionType() != null
&& expression.getExpressionType().getJdbcTypeCount() == 1
&& expression.getExpressionType().getSingleJdbcMapping().getJdbcType().isString()
&& fn.getArguments().stream().anyMatch( arg -> arg instanceof SqmParameterInterpretation );
if ( isStringFunctionWithParameterArg ) {
append( "cast(" );
}
super.visitSelfRenderingExpression( expression );
if ( isStringFunctionWithParameterArg ) {
append( " as lvarchar)" );
}
private static boolean isConcatFunction(Expression expression) {
return expression instanceof FunctionExpression fn
&& fn.getFunctionName().equals( "concat" );
}

private void caseArgument(Expression expression) {
// concatenation inside a case must be cast to varchar(255)
// or we get a bunch of trailing whitespace
final boolean concat =
expression instanceof FunctionExpression fn
&& fn.getFunctionName().equals( "concat" );
if ( concat ) {
if ( isConcatFunction( expression ) ) {
// concatenation inside a case must be cast to varchar(255)
// or we get a bunch of trailing whitespace
append( "cast(" );
}
expression.accept( this );
if ( concat ) {
expression.accept( this );
append( " as varchar(255))");
}
else {
expression.accept( this );
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,6 @@ public void render(
renderCastArrayToString( sqlAppender, arguments.get( 0 ), dialect, walker );
}
else {
if ( source instanceof QueryLiteral<?> literal && literal.getLiteralValue() == null ) {
literal.setInCast(true);
}
new PatternRenderer( dialect.castPattern( sourceType, targetType ) )
.render( sqlAppender, arguments, walker );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.SortSpecification;

import java.util.Collections;
import java.util.List;
import java.util.Locale;

import static java.util.Collections.emptyList;

/**
* Provides a standard implementation that supports the majority of the HQL
* functions that are translated to SQL. The Dialect and its sub-classes use
Expand Down Expand Up @@ -119,7 +120,7 @@ public void render(
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), null, null, translator );
render( sqlAppender, sqlAstArguments, null, emptyList(), null, null, translator );
}

@Override
Expand All @@ -129,7 +130,7 @@ public void render(
Predicate filter,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), null, null, translator );
render( sqlAppender, sqlAstArguments, filter, emptyList(), null, null, translator );
}

@Override
Expand All @@ -152,7 +153,7 @@ public void render(
Boolean fromFirst,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), respectNulls, fromFirst, walker );
render( sqlAppender, sqlAstArguments, filter, emptyList(), respectNulls, fromFirst, walker );
}

private void render(
Expand All @@ -164,7 +165,10 @@ private void render(
Boolean fromFirst,
SqlAstTranslator<?> translator) {
final boolean useParens = useParenthesesWhenNoArgs || !sqlAstArguments.isEmpty();
final boolean caseWrapper = filter != null && !translator.getSessionFactory().getJdbcServices().getDialect(). supportsFilterClause();
final boolean caseWrapper =
filter != null
&& !translator.getSessionFactory().getJdbcServices().getDialect()
.supportsFilterClause();

sqlAppender.appendSql( functionName );
if ( useParens ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7057,23 +7057,20 @@ public void visitOverflow(Overflow overflow) {
public void visitParameter(JdbcParameter jdbcParameter) {
switch ( getParameterRenderingMode() ) {
case NO_UNTYPED:
case NO_PLAIN_PARAMETER: {
case NO_PLAIN_PARAMETER:
renderCasted( jdbcParameter );
break;
}
case INLINE_PARAMETERS:
case INLINE_ALL_PARAMETERS: {
case INLINE_ALL_PARAMETERS:
renderExpressionAsLiteral( jdbcParameter, jdbcParameterBindings );
break;
}
case WRAP_ALL_PARAMETERS:
renderWrappedParameter( jdbcParameter );
break;
case DEFAULT:
default: {
default:
visitParameterAsParameter( jdbcParameter );
break;
}
}
}

Expand Down Expand Up @@ -7115,8 +7112,9 @@ protected void renderParameterAsParameter(int position, JdbcParameter jdbcParame

@Override
public void render(SqlAstNode sqlAstNode, SqlAstNodeRenderingMode renderingMode) {
SqlAstNodeRenderingMode original = this.parameterRenderingMode;
if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS && original != SqlAstNodeRenderingMode.WRAP_ALL_PARAMETERS ) {
final SqlAstNodeRenderingMode original = this.parameterRenderingMode;
if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS
&& original != SqlAstNodeRenderingMode.WRAP_ALL_PARAMETERS ) {
this.parameterRenderingMode = renderingMode;
}
try {
Expand All @@ -7128,8 +7126,9 @@ public void render(SqlAstNode sqlAstNode, SqlAstNodeRenderingMode renderingMode)
}

protected void withParameterRenderingMode(SqlAstNodeRenderingMode renderingMode, Runnable runnable) {
SqlAstNodeRenderingMode original = this.parameterRenderingMode;
if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS && original != SqlAstNodeRenderingMode.WRAP_ALL_PARAMETERS ) {
final SqlAstNodeRenderingMode original = this.parameterRenderingMode;
if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS
&& original != SqlAstNodeRenderingMode.WRAP_ALL_PARAMETERS ) {
this.parameterRenderingMode = renderingMode;
}
try {
Expand Down Expand Up @@ -7351,7 +7350,7 @@ protected void visitAnsiCaseSearchedExpression(
Consumer<Expression> resultRenderer) {
appendSql( "case" );
final SqlAstNodeRenderingMode original = this.parameterRenderingMode;
for ( CaseSearchedExpression.WhenFragment whenFragment : caseSearchedExpression.getWhenFragments() ) {
for ( var whenFragment : caseSearchedExpression.getWhenFragments() ) {
if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS
&& original != SqlAstNodeRenderingMode.WRAP_ALL_PARAMETERS ) {
this.parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
Expand All @@ -7375,12 +7374,12 @@ protected void visitAnsiCaseSearchedExpression(
protected void visitDecodeCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression) {
appendSql( "decode( " );
final SqlAstNodeRenderingMode original = this.parameterRenderingMode;
final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
final var whenFragments = caseSearchedExpression.getWhenFragments();
final int caseNumber = whenFragments.size();
CaseSearchedExpression.WhenFragment firstWhenFragment = null;
for ( int i = 0; i < caseNumber; i++ ) {
final CaseSearchedExpression.WhenFragment whenFragment = whenFragments.get( i );
Predicate predicate = whenFragment.getPredicate();
final var whenFragment = whenFragments.get( i );
final Predicate predicate = whenFragment.getPredicate();
if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS
&& original != SqlAstNodeRenderingMode.WRAP_ALL_PARAMETERS ) {
this.parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
Expand Down Expand Up @@ -7504,12 +7503,7 @@ public void visitJdbcLiteral(JdbcLiteral<?> jdbcLiteral) {

@Override
public void visitQueryLiteral(QueryLiteral<?> queryLiteral) {
if ( queryLiteral.getLiteralValue() == null && queryLiteral.isInCast() ) {
appendSql( SqlAppender.NULL_KEYWORD );
}
else {
visitLiteral( queryLiteral );
}
visitLiteral( queryLiteral );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
public class QueryLiteral<T> implements Literal, DomainResultProducer<T> {
private final T value;
private final SqlExpressible expressible;
private boolean inCast;

public QueryLiteral(T value, SqlExpressible expressible) {
assert value == null || expressible.getJdbcMapping().getJdbcJavaType().isInstance( value );
Expand Down Expand Up @@ -101,12 +100,4 @@ public void applySqlSelections(DomainResultCreationState creationState) {
creationState.getSqlAstCreationState().getCreationContext().getMappingMetamodel().getTypeConfiguration()
);
}

public void setInCast(boolean inCast) {
this.inCast = inCast;
}

public boolean isInCast() {
return inCast;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,14 @@
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.community.dialect.AltibaseDialect;
import org.hibernate.community.dialect.FirebirdDialect;
import org.hibernate.community.dialect.InformixDialect;
import org.hibernate.dialect.HANADialect;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.community.dialect.DerbyDialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.PostgresPlusDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.community.dialect.TiDBDialect;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.type.NumericBooleanConverter;
import org.hibernate.type.YesNoConverter;

Expand Down Expand Up @@ -92,21 +84,9 @@ public void testYesNo(BiConsumer<SessionFactoryScope, Consumer<? extends SharedS

@ParameterizedTest
@MethodSource("transactionKind")
@SkipForDialect(dialectClass = H2Dialect.class, reason = "H2 silently converts a boolean to string types")
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "HSQL silently converts a boolean to string types")
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby silently converts a boolean to string types")
@SkipForDialect(dialectClass = DB2Dialect.class, reason = "DB2 silently converts a boolean to string types")
@SkipForDialect(dialectClass = MySQLDialect.class, reason = "MySQL silently converts a boolean to string types")
@SkipForDialect(dialectClass = MariaDBDialect.class, reason = "MariaDB silently converts a boolean to string types")
@SkipForDialect(dialectClass = TiDBDialect.class, reason = "TiDB silently converts a boolean to string types")
@SkipForDialect(dialectClass = SybaseDialect.class, matchSubTypes = true, reason = "Sybase silently converts a boolean to string types")
@SkipForDialect(dialectClass = HANADialect.class, matchSubTypes = true, reason = "HANA silently converts a boolean to string types")
@SkipForDialect(dialectClass = CockroachDialect.class, matchSubTypes = true, reason = "Cockroach silently converts a boolean to string types")
@SkipForDialect(dialectClass = PostgresPlusDialect.class, reason = "PostgresPlus silently converts a boolean to string types")
@SkipForDialect(dialectClass = FirebirdDialect.class, reason = "Firebird silently converts a boolean to string")
@SkipForDialect(dialectClass = AltibaseDialect.class, reason = "Altibase silently converts a boolean to string")
@SkipForDialect(dialectClass = OracleDialect.class, majorVersion = 23, reason = "Oracle 23 interprets Y and T as true and N and F as false, so this works")
@SkipForDialect(dialectClass = InformixDialect.class)
// most dialects silently convert boolean to string types
@RequiresDialect(SQLServerDialect.class)
@RequiresDialect(value = PostgreSQLDialect.class, matchSubTypes = false)
public void testYesNoMismatch(BiConsumer<SessionFactoryScope, Consumer<? extends SharedSessionContract>> inTransaction) {
scope.inTransaction( (session) -> {
session.disableFilter( "subDepartmentFilter" );
Expand Down Expand Up @@ -147,20 +127,9 @@ public void testNumeric(BiConsumer<SessionFactoryScope, Consumer<? extends Share

@ParameterizedTest
@MethodSource("transactionKind")
@SkipForDialect(dialectClass = H2Dialect.class, reason = "H2 silently converts a boolean to integral types")
@SkipForDialect(dialectClass = OracleDialect.class, reason = "Oracle silently converts a boolean to integral types")
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "HSQL silently converts a boolean to integral types")
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby silently converts a boolean to integral types")
@SkipForDialect(dialectClass = DB2Dialect.class, reason = "DB2 silently converts a boolean to integral types")
@SkipForDialect(dialectClass = MySQLDialect.class, reason = "MySQL silently converts a boolean to integral types")
@SkipForDialect(dialectClass = MariaDBDialect.class, reason = "MariaDB silently converts a boolean to integral types")
@SkipForDialect(dialectClass = TiDBDialect.class, reason = "TiDB silently converts a boolean to integral types")
@SkipForDialect(dialectClass = SQLServerDialect.class, reason = "SQL Server silently converts a boolean to integral types")
@SkipForDialect(dialectClass = AltibaseDialect.class, reason = "Altibase silently converts a boolean to integral types")
@SkipForDialect(dialectClass = SybaseDialect.class, matchSubTypes = true, reason = "Sybase silently converts a boolean to integral types")
@SkipForDialect(dialectClass = HANADialect.class, matchSubTypes = true, reason = "HANA silently converts a boolean to integral types")
@SkipForDialect(dialectClass = FirebirdDialect.class, matchSubTypes = true, reason = "Firebird silently converts a boolean to integral types")
@SkipForDialect(dialectClass = InformixDialect.class)
// most dialects silently convert boolean to integral types
@RequiresDialect(PostgreSQLDialect.class)
@RequiresDialect(CockroachDialect.class)
public void testNumericMismatch(BiConsumer<SessionFactoryScope, Consumer<? extends SharedSessionContract>> inTransaction) {
scope.inTransaction( (session) -> {
session.disableFilter( "subDepartmentFilter" );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,9 @@ public void testPadFunction(SessionFactoryScope scope) {
is(".....hello"));
assertThat(session.createQuery("select pad('hello' with 10 trailing '.')", String.class).getSingleResult(),
is("hello....."));

assertThat(session.createQuery("select pad(:hello with 10 leading)", String.class).setParameter( "hello", "hello" ).getSingleResult(),
is(" hello"));
}
);

Expand Down Expand Up @@ -2020,6 +2023,10 @@ public void testIntervalDiffExpressions(SessionFactoryScope scope) {
session.createQuery("select (e.theDate - e.theDate) by day from EntityOfBasics e", Long.class)
.list();

//TODO
// session.createQuery("select (e.theDate - e.theDate) by week from EntityOfBasics e", Long.class)
// .list();

session.createQuery("select (e.theTimestamp - e.theTimestamp) by hour from EntityOfBasics e", Long.class)
.list();
session.createQuery("select (e.theTimestamp - e.theTimestamp) by minute from EntityOfBasics e", Long.class)
Expand Down