HHH-17639 Make recursive CTE cycle detection emulation independent of collation
This commit is contained in:
parent
dfa9cd5b29
commit
ea7c8c6836
|
@ -395,4 +395,13 @@ public class MariaDBLegacySqlAstTranslator<T extends JdbcOperation> extends Abst
|
|||
super.visitCastTarget( castTarget );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderStringContainsExactlyPredicate(Expression haystack, Expression needle) {
|
||||
// MariaDB can't cope with NUL characters in the position function, so we use a like predicate instead
|
||||
haystack.accept( this );
|
||||
appendSql( " like concat('%',replace(replace(replace(" );
|
||||
needle.accept( this );
|
||||
appendSql( ",'~','~~'),'?','~?'),'%','~%'),'%') escape '~'" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ import org.hibernate.dialect.MySQLSqlAstTranslator;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.Stack;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.tree.MutationStatement;
|
||||
|
@ -414,4 +416,13 @@ public class MySQLLegacySqlAstTranslator<T extends JdbcOperation> extends Abstra
|
|||
super.visitCastTarget( castTarget );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderStringContainsExactlyPredicate(Expression haystack, Expression needle) {
|
||||
// MySQL can't cope with NUL characters in the position function, so we use a like predicate instead
|
||||
haystack.accept( this );
|
||||
appendSql( " like concat('%',replace(replace(replace(" );
|
||||
needle.accept( this );
|
||||
appendSql( ",'~','~~'),'?','~?'),'%','~%'),'%') escape '~'" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -549,4 +549,15 @@ public class SQLServerLegacySqlAstTranslator<T extends JdbcOperation> extends Ab
|
|||
TOP_ONLY,
|
||||
EMULATED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderStringContainsExactlyPredicate(Expression haystack, Expression needle) {
|
||||
// SQL Server ignores NUL characters in string on case-insensitive collations, so we force a binary collation.
|
||||
// This is needed for the emulation of cycle detection in recursive queries
|
||||
appendSql( "charindex(" );
|
||||
needle.accept( this );
|
||||
appendSql( " collate Latin1_General_100_BIN2," );
|
||||
haystack.accept( this );
|
||||
append( ")>0" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -384,4 +384,13 @@ public class MariaDBSqlAstTranslator<T extends JdbcOperation> extends AbstractSq
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderStringContainsExactlyPredicate(Expression haystack, Expression needle) {
|
||||
// MariaDB can't cope with NUL characters in the position function, so we use a like predicate instead
|
||||
haystack.accept( this );
|
||||
appendSql( " like concat('%',replace(replace(replace(" );
|
||||
needle.accept( this );
|
||||
appendSql( ",'~','~~'),'?','~?'),'%','~%'),'%') escape '~'" );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -448,4 +448,13 @@ public class MySQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
|
|||
super.visitCastTarget( castTarget );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderStringContainsExactlyPredicate(Expression haystack, Expression needle) {
|
||||
// MySQL can't cope with NUL characters in the position function, so we use a like predicate instead
|
||||
haystack.accept( this );
|
||||
appendSql( " like concat('%',replace(replace(replace(" );
|
||||
needle.accept( this );
|
||||
appendSql( ",'~','~~'),'?','~?'),'%','~%'),'%') escape '~'" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
|||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
|
@ -531,4 +533,15 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends SqlAstTr
|
|||
super.renderMergeStatement( optionalTableUpdate );
|
||||
appendSql( ";" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderStringContainsExactlyPredicate(Expression haystack, Expression needle) {
|
||||
// SQL Server ignores NUL characters in string on case-insensitive collations, so we force a binary collation.
|
||||
// This is needed for the emulation of cycle detection in recursive queries
|
||||
appendSql( "charindex(" );
|
||||
needle.accept( this );
|
||||
appendSql( " collate Latin1_General_100_BIN2," );
|
||||
haystack.accept( this );
|
||||
append( ")>0" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,4 +345,13 @@ public class TiDBSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAs
|
|||
super.visitCastTarget( castTarget );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderStringContainsExactlyPredicate(Expression haystack, Expression needle) {
|
||||
// TiDB can't cope with NUL characters in the position function, so we use a like predicate instead
|
||||
haystack.accept( this );
|
||||
appendSql( " like concat('%',replace(replace(replace(" );
|
||||
needle.accept( this );
|
||||
appendSql( ",'~','~~'),'?','~?'),'%','~%'),'%') escape '~'" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3167,7 +3167,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
null,
|
||||
stringType
|
||||
);
|
||||
arguments.add( new QueryLiteral<>( "%", stringType ) );
|
||||
for ( CteColumn cycleColumn : currentCteStatement.getCycleColumns() ) {
|
||||
final int selectionIndex = currentCteStatement.getCteTable()
|
||||
.getCteColumns()
|
||||
|
@ -3190,14 +3189,20 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
arguments.add( nullSeparator );
|
||||
}
|
||||
arguments.add( nullSeparator );
|
||||
arguments.add( new QueryLiteral<>( "%", stringType ) );
|
||||
|
||||
if ( !supportsRecursiveCycleClause() ) {
|
||||
// Cycle mark
|
||||
appendSql( "case when " );
|
||||
visitColumnReference( cyclePathColumnReference );
|
||||
appendSql( " like " );
|
||||
concat.render( this, arguments, stringType, this );
|
||||
renderStringContainsExactlyPredicate(
|
||||
cyclePathColumnReference,
|
||||
new SelfRenderingFunctionSqlAstExpression(
|
||||
"concat",
|
||||
concat,
|
||||
arguments,
|
||||
stringType,
|
||||
stringType
|
||||
)
|
||||
);
|
||||
appendSql( " then " );
|
||||
currentCteStatement.getCycleValue().accept( this );
|
||||
appendSql( " else " );
|
||||
|
@ -3206,9 +3211,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
appendSql( COMMA_SEPARATOR );
|
||||
}
|
||||
|
||||
// Remove the wildcard literals
|
||||
arguments.remove( arguments.size() - 1 );
|
||||
arguments.set( 0, cyclePathColumnReference );
|
||||
// Add the previous path
|
||||
arguments.add( 0, cyclePathColumnReference );
|
||||
// Cycle path
|
||||
concat.render( this, arguments, stringType, this );
|
||||
}
|
||||
|
@ -3257,6 +3261,18 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
}
|
||||
|
||||
protected void renderStringContainsExactlyPredicate(Expression haystack, Expression needle) {
|
||||
final AbstractSqmSelfRenderingFunctionDescriptor position = findSelfRenderingFunction( "position", 2 );
|
||||
new SelfRenderingFunctionSqlAstExpression(
|
||||
"position",
|
||||
position,
|
||||
List.of( needle, haystack ),
|
||||
getStringType(),
|
||||
getStringType()
|
||||
).accept( this );
|
||||
append( ">0" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the given expression so that it produces a string, which should have the same ordering as the original value.
|
||||
* Here are the mappings for various data types:
|
||||
|
|
Loading…
Reference in New Issue