HHH-17639 Make recursive CTE cycle detection emulation independent of collation
This commit is contained in:
parent
899bf7b4fb
commit
8250f13d77
|
@ -250,4 +250,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 '~'" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -258,4 +258,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 '~'" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -470,4 +470,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" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,4 +240,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 '~'" );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -294,4 +294,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 '~'" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
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;
|
||||
|
@ -451,4 +453,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" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -201,4 +201,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 '~'" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2660,7 +2660,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()
|
||||
|
@ -2683,14 +2682,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 " );
|
||||
|
@ -2699,9 +2704,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 );
|
||||
}
|
||||
|
@ -2750,6 +2754,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