Fix a few more test issues and handle group by summarization rendering strategies as well as group by literal rendering strategies

This commit is contained in:
Christian Beikov 2020-12-08 11:25:07 +01:00
parent a57f93b14a
commit c4673e5a5c
27 changed files with 386 additions and 77 deletions

View File

@ -1538,4 +1538,9 @@ public abstract class AbstractHANADialect extends Dialect {
protected abstract boolean supportsAsciiStringTypes();
protected abstract Boolean useUnicodeStringTypesDefault();
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.EMPTY_GROUPING;
}
}

View File

@ -20,6 +20,7 @@ import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import java.sql.CallableStatement;
@ -217,14 +218,24 @@ abstract class AbstractTransactSQLDialect extends Dialect {
return "select getdate()";
}
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.COLUMN_REFERENCE;
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType entityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableStrategy(
new IdTable( entityDescriptor, basename -> "#" + basename, this ),
() -> new TempIdTableExporter( true, this::getTypeName ) {
@Override
protected String getCreateCommand() {
return "create table";
}
},
// // sql-server, at least needed this dropped after use; strange!
this::getTypeName,
AfterUseAction.DROP,
TempTableDdlTransactionHandling.NONE,
runtimeModelCreationContext.getSessionFactory()

View File

@ -698,8 +698,13 @@ public class DB2Dialect extends Dialect {
}
@Override
public boolean supportsGroupByRollup() {
return true;
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
return GroupBySummarizationRenderingStrategy.FUNCTION;
}
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.EMPTY_GROUPING;
}
@Override

View File

@ -766,7 +766,7 @@ public class DerbyDialect extends Dialect {
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableStrategy(
new IdTable( rootEntityDescriptor, basename -> "HT_" + basename, this ),
new IdTable( rootEntityDescriptor, basename -> "session.HT_" + basename, this ),
() -> new TempIdTableExporter( true, this::getTypeName ) {
@Override
protected String getCreateCommand() {
@ -785,7 +785,7 @@ public class DerbyDialect extends Dialect {
}
@Override
public boolean supportsGroupByRollup() {
return true;
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
return GroupBySummarizationRenderingStrategy.FUNCTION;
}
}

View File

@ -360,10 +360,6 @@ public abstract class Dialect implements ConversionContext {
CommonFunctionFactory.aggregates(queryEngine);
//grouping functions cube() and rollup() supported on some databases
CommonFunctionFactory.groupings(queryEngine);
//the ANSI SQL-defined aggregate functions any() and every() are only
//supported on one database, but can be emulated using sum() and case,
//though there is a more natural mapping on some databases
@ -2625,14 +2621,21 @@ public abstract class Dialect implements ConversionContext {
}
/**
* Is this dialect known to support ROLLUP functions in the GROUP BY clause.
* The strategy to use for rendering summarizations in the GROUP BY clause.
*
* @return True if this SQL dialect supports ROLLUP functions; false otherwise.
* @since 6.0
*/
public boolean supportsGroupByRollup() {
// return false here, as most databases do not properly support this construct...
return false;
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
return GroupBySummarizationRenderingStrategy.NONE;
}
/**
* The strategy to use for rendering constants in the GROUP BY clause.
*
* @since 6.0
*/
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.CONSTANT_EXPRESSION;
}
/**

View File

@ -0,0 +1,35 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
/**
* Strategies for rendering a constant in a group by.
*
* @author Christian Beikov
*/
public enum GroupByConstantRenderingStrategy {
/**
* The strategy for ANSI SQL compliant DBs like e.g. PostgreSQL that renders `()` i.e. the empty grouping.
*/
EMPTY_GROUPING,
/**
* Renders a constant e.g. `'0'`
*/
CONSTANT,
/**
* Renders a constant expression e.g. `'0' || '0'`
*/
CONSTANT_EXPRESSION,
/**
* Renders a subquery e.g. `(select 1)`
*/
SUBQUERY,
/**
* Renders a column reference to a dummy table e.g. `, (select 1 x) dummy` and `dummy.x`
*/
COLUMN_REFERENCE;
}

View File

@ -0,0 +1,27 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
/**
* Strategies for rendering summarization function like rollup and cube in a group by.
*
* @author Christian Beikov
*/
public enum GroupBySummarizationRenderingStrategy {
/**
* No support for summarization.
*/
NONE,
/**
* Use the proprietary WITH ROLLUP or WITH CUBE clause.
*/
CLAUSE,
/**
* Use the rollup or cube functions like specified in the SQL standard.
*/
FUNCTION;
}

View File

@ -334,6 +334,11 @@ public class InformixDialect extends Dialect {
return "select distinct current timestamp from informix.systables";
}
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.COLUMN_REFERENCE;
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,

View File

@ -420,4 +420,9 @@ public class IngresDialect extends Dialect {
}
}
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.COLUMN_REFERENCE;
}
}

View File

@ -107,6 +107,11 @@ public class MariaDBDialect extends MySQLDialect {
return getVersion() >= 1030;
}
@Override
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
return GroupBySummarizationRenderingStrategy.CLAUSE;
}
@Override
boolean supportsForShare() {
//only supported on MySQL

View File

@ -922,7 +922,7 @@ public class MySQLDialect extends Dialect {
}
@Override
public boolean supportsGroupByRollup() {
return true;
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
return GroupBySummarizationRenderingStrategy.CLAUSE;
}
}

View File

@ -30,6 +30,8 @@ import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
import org.hibernate.procedure.spi.CallableStatementSupport;
import org.hibernate.query.CastType;
@ -37,6 +39,11 @@ import org.hibernate.query.SemanticException;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.*;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl;
@ -807,8 +814,13 @@ public class OracleDialect extends Dialect {
}
@Override
public boolean supportsGroupByRollup() {
return true;
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
return GroupBySummarizationRenderingStrategy.FUNCTION;
}
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.EMPTY_GROUPING;
}
@Override
@ -826,6 +838,23 @@ public class OracleDialect extends Dialect {
return true;
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new GlobalTemporaryTableStrategy(
new IdTable( rootEntityDescriptor, name -> name.length() > 30 ? name.substring( 0, 30 ) : name, this ),
() -> new TempIdTableExporter( false, this::getTypeName ) {
@Override
protected String getCreateOptions() {
return "on commit delete rows";
}
},
AfterUseAction.CLEAN,
runtimeModelCreationContext.getSessionFactory()
);
}
/**
* For Oracle, the FOR UPDATE clause cannot be applied when using ORDER BY, DISTINCT or views.
*

View File

@ -781,8 +781,13 @@ public class PostgreSQLDialect extends Dialect {
}
@Override
public boolean supportsGroupByRollup() {
return getVersion() >= 950;
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
return getVersion() >= 950 ? GroupBySummarizationRenderingStrategy.FUNCTION : GroupBySummarizationRenderingStrategy.NONE;
}
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return getVersion() >= 950 ? GroupByConstantRenderingStrategy.EMPTY_GROUPING : GroupByConstantRenderingStrategy.SUBQUERY;
}
@Override

View File

@ -359,8 +359,8 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
}
@Override
public boolean supportsGroupByRollup() {
return true;
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
return GroupBySummarizationRenderingStrategy.CLAUSE;
}
@Override
@ -638,4 +638,9 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
}
}
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.EMPTY_GROUPING;
}
}

View File

@ -130,4 +130,9 @@ public class SybaseAnywhereDialect extends SybaseDialect {
// by default
return TopLimitHandler.INSTANCE;
}
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.EMPTY_GROUPING;
}
}

View File

@ -549,4 +549,9 @@ public class TeradataDialect extends Dialect {
//TODO: is this right?!
return TopLimitHandler.INSTANCE;
}
@Override
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.EMPTY_GROUPING;
}
}

View File

@ -1431,15 +1431,6 @@ public class CommonFunctionFactory {
.register();
}
public static void groupings(QueryEngine queryEngine) {
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("cube")
.setMinArgumentCount(1)
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("rollup")
.setMinArgumentCount(1)
.register();
}
public static void aggregates(QueryEngine queryEngine) {
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("max")
.setExactArgumentCount(1)

View File

@ -119,6 +119,7 @@ import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPathEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.tree.expression.SqmSummarization;
import org.hibernate.query.sqm.tree.expression.SqmToDuration;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
@ -3307,31 +3308,19 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
@Override
public SqmExpression<?> visitCube(HqlParser.CubeContext ctx) {
List<SqmTypedNode<?>> args = new ArrayList<>();
for ( HqlParser.ExpressionContext arg: ctx.expression() ) {
args.add( (SqmExpression<?>) arg.accept( this ) );
}
//ignore DISTINCT
return getFunctionDescriptor("cube").generateSqmExpression(
args,
resolveExpressableTypeBasic( Integer.class ),
creationContext.getQueryEngine(),
creationContext.getJpaMetamodel().getTypeConfiguration()
return new SqmSummarization<>(
SqmSummarization.Kind.CUBE,
visitExpressions( ctx.expression() ),
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression<?> visitRollup(HqlParser.RollupContext ctx) {
List<SqmTypedNode<?>> args = new ArrayList<>();
for ( HqlParser.ExpressionContext arg: ctx.expression() ) {
args.add( (SqmExpression<?>) arg.accept( this ) );
}
//ignore DISTINCT
return getFunctionDescriptor("rollup").generateSqmExpression(
args,
resolveExpressableTypeBasic( Integer.class ),
creationContext.getQueryEngine(),
creationContext.getJpaMetamodel().getTypeConfiguration()
return new SqmSummarization<>(
SqmSummarization.Kind.ROLLUP,
visitExpressions( ctx.expression() ),
creationContext.getNodeBuilder()
);
}

View File

@ -49,6 +49,7 @@ import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
import org.hibernate.query.sqm.tree.expression.SqmPathEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmSummarization;
import org.hibernate.query.sqm.tree.expression.SqmToDuration;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
@ -205,6 +206,8 @@ public interface SemanticQueryWalker<T> {
T visitEvery(SqmEvery<?> sqmEvery);
T visitSummarization(SqmSummarization<?> sqmSummarization);
T visitPositionalParameterExpression(SqmPositionalParameter<?> expression);
T visitNamedParameterExpression(SqmNamedParameter<?> expression);

View File

@ -56,6 +56,7 @@ import org.hibernate.query.sqm.tree.expression.SqmPathEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.tree.expression.SqmSummarization;
import org.hibernate.query.sqm.tree.expression.SqmToDuration;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
@ -935,6 +936,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
return null;
}
@Override
public Object visitSummarization(SqmSummarization<?> sqmSummarization) {
return null;
}
@Override
public Object visitDynamicInstantiation(SqmDynamicInstantiation sqmDynamicInstantiation) {
processStanza(

View File

@ -51,6 +51,7 @@ import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPathEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmSummarization;
import org.hibernate.query.sqm.tree.expression.SqmToDuration;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
@ -633,6 +634,11 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
return sqmEvery;
}
@Override
public Object visitSummarization(SqmSummarization<?> sqmSummarization) {
return sqmSummarization;
}
@Override
public Object visitSearchedCaseExpression(SqmCaseSearched<?> expression) {
return expression;

View File

@ -108,6 +108,7 @@ import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.tree.expression.SqmSummarization;
import org.hibernate.query.sqm.tree.expression.SqmToDuration;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
@ -179,6 +180,7 @@ import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Star;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
import org.hibernate.sql.ast.tree.from.TableGroup;
@ -2235,6 +2237,30 @@ public abstract class BaseSqmToSqlAstConverter
);
}
@Override
public Object visitSummarization(SqmSummarization<?> sqmSummarization) {
final List<SqmExpression<?>> groupingExpressions = sqmSummarization.getGroupings();
final int size = groupingExpressions.size();
final List<Expression> expressions = new ArrayList<>( size );
for ( int i = 0; i < size; i++ ) {
expressions.add( (Expression) groupingExpressions.get( i ).accept( this ) );
}
return new Summarization(
getSummarizationKind(sqmSummarization.getKind()),
expressions
);
}
private Summarization.Kind getSummarizationKind(SqmSummarization.Kind kind) {
switch ( kind ) {
case CUBE:
return Summarization.Kind.CUBE;
case ROLLUP:
return Summarization.Kind.ROLLUP;
}
throw new UnsupportedOperationException( "Unsupported summarization: " + kind );
}
@Override
public Object visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral) {
return new QueryLiteral<>(

View File

@ -0,0 +1,47 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.tree.expression;
import java.util.List;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
/**
* @author Christian Beikov
*/
public class SqmSummarization<T> extends AbstractSqmExpression<T> {
private final Kind kind;
private final List<SqmExpression<?>> groupings;
public SqmSummarization(Kind kind, List<SqmExpression<?>> groupings, NodeBuilder criteriaBuilder) {
super( null, criteriaBuilder );
this.kind = kind;
this.groupings = groupings;
}
public Kind getKind() {
return kind;
}
public List<SqmExpression<?>> getGroupings() {
return groupings;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitSummarization( this );
}
public enum Kind {
ROLLUP,
CUBE
}
}

View File

@ -30,6 +30,7 @@ import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Star;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
import org.hibernate.sql.ast.tree.from.FromClause;
@ -106,6 +107,8 @@ public interface SqlAstWalker {
void visitEvery(Every every);
void visitSummarization(Summarization every);
void visitSelfRenderingExpression(SelfRenderingExpression expression);
void visitSqlSelectionExpression(SqlSelectionExpression expression);

View File

@ -67,6 +67,7 @@ import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Star;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
import org.hibernate.sql.ast.tree.from.FromClause;
@ -369,7 +370,49 @@ public abstract class AbstractSqlAstWalker
// We render an empty group instead of literals as some DBs don't support grouping by literals
// Note that integer literals, which refer to select item positions, are handled in #visitGroupByClause
if ( expression instanceof Literal ) {
appendSql( "()" );
switch ( dialect.getGroupByConstantRenderingStrategy() ) {
case CONSTANT:
appendSql( "'0'" );
break;
case CONSTANT_EXPRESSION:
appendSql( "'0' || '0'" );
break;
case EMPTY_GROUPING:
appendSql( "()" );
break;
case SUBQUERY:
appendSql( "(select 1 " );
appendSql( dialect.getFromDual() );
appendSql( ')' );
break;
case COLUMN_REFERENCE:
// todo (6.0): We need to introduce a dummy from clause item
// String fromItem = ", (select 1 x " + dialect.getFromDual() + ") dummy";
// sqlBuffer.insert( fromEndIndex, fromItem );
// appendSql( "dummy.x" );
throw new UnsupportedOperationException( "Column reference strategy is not yet implemented!" );
}
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
switch ( dialect.getGroupBySummarizationRenderingStrategy() ) {
case FUNCTION:
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );
break;
case CLAUSE:
renderCommaSeparated( summarization.getGroupings() );
appendSql( " with " );
appendSql( summarization.getKind().name().toLowerCase() );
break;
default:
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
}
else {
expression.accept( this );
@ -497,12 +540,7 @@ public abstract class AbstractSqlAstWalker
try {
appendSql( "select " );
String separator = NO_SEPARATOR;
for ( Expression expression : expressions ) {
appendSql( separator );
expression.accept( this );
separator = COMA_SEPARATOR;
}
renderCommaSeparated( expressions );
String fromDual = dialect.getFromDual();
if ( !fromDual.isEmpty() ) {
appendSql( " " );
@ -985,17 +1023,22 @@ public abstract class AbstractSqlAstWalker
appendSql( OPEN_PARENTHESIS );
}
for ( Expression expression : tuple.getExpressions() ) {
appendSql( separator );
expression.accept( this );
separator = COMA_SEPARATOR;
}
renderCommaSeparated( tuple.getExpressions() );
if ( isCurrentWhereClause ) {
appendSql( CLOSE_PARENTHESIS );
}
}
private void renderCommaSeparated(Iterable<? extends Expression> expressions) {
String separator = NO_SEPARATOR;
for ( Expression expression : expressions ) {
appendSql( separator );
expression.accept( this );
separator = COMA_SEPARATOR;
}
}
@Override
public void visitCollate(Collate collate) {
collate.getExpression().accept( this );
@ -1366,6 +1409,11 @@ public abstract class AbstractSqlAstWalker
every.getSubquery().accept( this );
}
@Override
public void visitSummarization(Summarization every) {
// nothing to do... handled within #renderGroupByItem
}
@Override
public void visitJdbcLiteral(JdbcLiteral jdbcLiteral) {
visitLiteral( jdbcLiteral );
@ -1538,12 +1586,7 @@ public abstract class AbstractSqlAstWalker
appendSql( " not" );
}
appendSql( " in (" );
String separator = NO_SEPARATOR;
for ( Expression expression : inListPredicate.getListExpressions() ) {
appendSql( separator );
expression.accept( this );
separator = COMA_SEPARATOR;
}
renderCommaSeparated( inListPredicate.getListExpressions() );
appendSql( CLOSE_PARENTHESIS );
}
}
@ -1553,12 +1596,7 @@ public abstract class AbstractSqlAstWalker
appendSql( " not" );
}
appendSql( " in (" );
String separator = NO_SEPARATOR;
for ( Expression expression : inListPredicate.getListExpressions() ) {
appendSql( separator );
expression.accept( this );
separator = COMA_SEPARATOR;
}
renderCommaSeparated( inListPredicate.getListExpressions() );
appendSql( CLOSE_PARENTHESIS );
}
}

View File

@ -0,0 +1,49 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.ast.tree.expression;
import java.util.List;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.sql.ast.SqlAstWalker;
/**
* @author Christian Beikov
*/
public class Summarization implements Expression {
private final Kind kind;
private final List<Expression> groupings;
public Summarization(Kind kind, List<Expression> groupings) {
this.kind = kind;
this.groupings = groupings;
}
public Kind getKind() {
return kind;
}
public List<Expression> getGroupings() {
return groupings;
}
@Override
public MappingModelExpressable getExpressionType() {
return null;
}
@Override
public void accept(SqlAstWalker walker) {
walker.visitSummarization( this );
}
public enum Kind {
ROLLUP,
CUBE
}
}

View File

@ -8,6 +8,7 @@ package org.hibernate.testing.orm.junit;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.GroupBySummarizationRenderingStrategy;
/**
* Container class for different implementation of the {@link DialectFeatureCheck} interface.
@ -223,7 +224,7 @@ abstract public class DialectFeatureChecks {
public static class SupportsGroupByRollup implements DialectFeatureCheck {
public boolean apply(Dialect dialect) {
return dialect.supportsGroupByRollup();
return dialect.getGroupBySummarizationRenderingStrategy() != GroupBySummarizationRenderingStrategy.NONE;
}
}