use of org.hibernate.sql.ast.tree.expression.Literal in project hibernate-orm by hibernate.
the class AggregateWindowEmulationQueryTransformer method transform.
@Override
public QuerySpec transform(CteContainer cteContainer, QuerySpec querySpec, SqmToSqlAstConverter converter) {
final SessionFactoryImplementor factory = converter.getCreationContext().getSessionFactory();
final QuerySpec outerQuerySpec = new QuerySpec(querySpec.isRoot());
final String identifierVariable = "hhh_";
final NavigablePath navigablePath = new NavigablePath(identifierVariable, identifierVariable);
final SelectClause selectClause = outerQuerySpec.getSelectClause();
final QuerySpec subQuerySpec = querySpec.asSubQuery();
final SelectClause subSelectClause = subQuerySpec.getSelectClause();
final List<SqlSelection> subSelections = subSelectClause.getSqlSelections();
final List<String> columnNames = new ArrayList<>(subSelections.size());
// A map to find the select item position for an expression
// which is needed to decide if we need to introduce synthetic select items
// for group by items, since these group by items are migrated to the outer query
final Map<Expression, Integer> selectionMapping = new HashMap<>(subSelections.size());
// for the QueryPartTableGroup within which the sub query spec is embedded
for (int i = 0; i < subSelections.size(); i++) {
final BasicValuedMapping mapping = (BasicValuedMapping) subSelections.get(i).getExpressionType();
final String columnName = "col" + i;
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, mapping.getJdbcMapping(), factory);
final Expression expression = subSelections.get(i).getExpression();
final Expression finalExpression;
if (expression == windowFunction) {
finalExpression = new SelfRenderingAggregateFunctionSqlAstExpression("min", (sqlAppender, sqlAstArguments, walker1) -> {
sqlAppender.appendSql("min(");
sqlAstArguments.get(0).accept(walker1);
sqlAppender.append(')');
}, Collections.singletonList(columnReference), null, (ReturnableType<?>) mapping.getMappedType(), expression.getExpressionType());
} else {
finalExpression = columnReference;
selectionMapping.put(expression, i);
}
columnNames.add(columnName);
selectClause.addSqlSelection(new ResolvedSqlSelection(i + 1, i, finalExpression, (BasicType<Object>) mapping.getJdbcMapping()));
}
// Migrate the group by clause to the outer query
// and push group by expressions into the partition by clause of the window function
final List<Expression> groupByExpressions = new ArrayList<>(subQuerySpec.getGroupByClauseExpressions().size());
for (Expression groupByClauseExpression : subQuerySpec.getGroupByClauseExpressions()) {
final Expression realExpression;
final Expression outerGroupByExpression;
if (groupByClauseExpression instanceof SqlSelectionExpression) {
final SqlSelection selection = ((SqlSelectionExpression) groupByClauseExpression).getSelection();
outerGroupByExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(selection.getValuesArrayPosition()));
realExpression = selection.getExpression();
} else {
if (groupByClauseExpression instanceof SqmPathInterpretation<?>) {
realExpression = ((SqmPathInterpretation<?>) groupByClauseExpression).getSqlExpression();
} else {
realExpression = groupByClauseExpression;
}
final Integer position = selectionMapping.get(realExpression);
if (position == null) {
// Group by something that has no corresponding selection item,
// so we need to introduce an intermediate selection item
final int valuesPosition = selectClause.getSqlSelections().size();
final String columnName = "col" + valuesPosition;
final JdbcMapping jdbcMapping = realExpression.getExpressionType().getJdbcMappings().get(0);
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, jdbcMapping, factory);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(subValuesPosition + 1, subValuesPosition, realExpression, (BasicType<Object>) jdbcMapping);
columnNames.add(columnName);
subSelectClause.addSqlSelection(subSelection);
outerGroupByExpression = columnReference;
selectionMapping.put(realExpression, subValuesPosition);
} else {
outerGroupByExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(position));
}
}
windowFunction.getPartitions().add(realExpression);
groupByExpressions.add(outerGroupByExpression);
}
outerQuerySpec.setGroupByClauseExpressions(groupByExpressions);
subQuerySpec.setGroupByClauseExpressions(null);
// Migrate the having clause to the outer query
if (subQuerySpec.getHavingClauseRestrictions() != null) {
final Predicate predicate = new ExpressionReplacementWalker() {
@Override
protected <X extends SqlAstNode> X replaceExpression(X expression) {
if (expression instanceof Literal || expression instanceof JdbcParameter) {
return expression;
}
final Expression outerExpression;
if (expression instanceof SqlSelectionExpression) {
final SqlSelection selection = ((SqlSelectionExpression) expression).getSelection();
outerExpression = selectClause.getSqlSelections().get(selection.getValuesArrayPosition()).getExpression();
} else {
final Expression realExpression;
if (expression instanceof SqmPathInterpretation<?>) {
realExpression = ((SqmPathInterpretation<?>) expression).getSqlExpression();
} else {
realExpression = (Expression) expression;
}
final Integer position = selectionMapping.get(realExpression);
if (position == null) {
// An expression that has no corresponding selection item,
// so we need to introduce an intermediate selection item
final int valuesPosition = selectClause.getSqlSelections().size();
final String columnName = "col" + valuesPosition;
final JdbcMapping jdbcMapping = realExpression.getExpressionType().getJdbcMappings().get(0);
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, jdbcMapping, factory);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(subValuesPosition + 1, subValuesPosition, realExpression, (BasicType<Object>) jdbcMapping);
columnNames.add(columnName);
subSelectClause.addSqlSelection(subSelection);
outerExpression = columnReference;
selectionMapping.put(realExpression, subValuesPosition);
} else {
outerExpression = selectClause.getSqlSelections().get(position).getExpression();
}
}
return (X) outerExpression;
}
}.replaceExpressions(subQuerySpec.getHavingClauseRestrictions());
outerQuerySpec.setHavingClauseRestrictions(predicate);
subQuerySpec.setHavingClauseRestrictions(null);
}
// Migrate the order by clause to the outer query
if (subQuerySpec.hasSortSpecifications()) {
for (SortSpecification sortSpecification : subQuerySpec.getSortSpecifications()) {
final Expression sortExpression = sortSpecification.getSortExpression();
final Expression outerSortExpression;
if (sortExpression instanceof SqlSelectionExpression) {
final SqlSelection selection = ((SqlSelectionExpression) sortExpression).getSelection();
outerSortExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(selection.getValuesArrayPosition()));
} else {
final Expression realExpression;
if (sortExpression instanceof SqmPathInterpretation<?>) {
realExpression = ((SqmPathInterpretation<?>) sortExpression).getSqlExpression();
} else {
realExpression = sortExpression;
}
final Integer position = selectionMapping.get(realExpression);
if (position == null) {
// Group by something that has no corresponding selection item,
// so we need to introduce an intermediate selection item
final int valuesPosition = selectClause.getSqlSelections().size();
final String columnName = "col" + valuesPosition;
final JdbcMapping jdbcMapping = realExpression.getExpressionType().getJdbcMappings().get(0);
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, jdbcMapping, factory);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(subValuesPosition + 1, subValuesPosition, realExpression, (BasicType<Object>) jdbcMapping);
columnNames.add(columnName);
subSelectClause.addSqlSelection(subSelection);
outerSortExpression = columnReference;
selectionMapping.put(realExpression, subValuesPosition);
} else {
outerSortExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(position));
}
}
outerQuerySpec.addSortSpecification(new SortSpecification(outerSortExpression, sortSpecification.getSortOrder(), sortSpecification.getNullPrecedence()));
}
subQuerySpec.getSortSpecifications().clear();
}
// We need to add selection items for the expressions we order by to the sub query spec.
final int selectionOffset = columnNames.size();
// Collect the sorting column references so we can apply the filter later
final List<ColumnReference> sortingColumns = new ArrayList<>(withinGroup.size());
for (int i = 0; i < withinGroup.size(); i++) {
final int valueIndex = selectionOffset + i;
final Expression sortExpression = withinGroup.get(i).getSortExpression();
final BasicValuedMapping mapping = (BasicValuedMapping) sortExpression.getExpressionType();
final String columnName = "col" + valueIndex;
final int oldValueIndex = subSelectClause.getSqlSelections().size();
columnNames.add(columnName);
subSelectClause.addSqlSelection(new ResolvedSqlSelection(oldValueIndex + 1, oldValueIndex, sortExpression, (BasicType<Object>) mapping.getJdbcMapping()));
sortingColumns.add(new ColumnReference(identifierVariable, columnName, false, null, null, mapping.getJdbcMapping(), factory));
}
if (arguments != null) {
// So we add a filter to the outer query so we can extract the rank
switch(arguments.size()) {
case 0:
break;
case 1:
outerQuerySpec.applyPredicate(new ComparisonPredicate(sortingColumns.get(0), ComparisonOperator.EQUAL, (Expression) arguments.get(0)));
break;
default:
outerQuerySpec.applyPredicate(new ComparisonPredicate(new SqlTuple(sortingColumns, null), ComparisonOperator.EQUAL, new SqlTuple((List<? extends Expression>) (List<?>) arguments, null)));
}
}
final QueryPartTableGroup queryPartTableGroup = new QueryPartTableGroup(navigablePath, null, subQuerySpec, identifierVariable, columnNames, false, true, factory);
outerQuerySpec.getFromClause().addRoot(queryPartTableGroup);
// Migrate the offset/fetch clause
outerQuerySpec.setOffsetClauseExpression(subQuerySpec.getOffsetClauseExpression());
outerQuerySpec.setFetchClauseExpression(subQuerySpec.getFetchClauseExpression(), subQuerySpec.getFetchClauseType());
subQuerySpec.setOffsetClauseExpression(null);
subQuerySpec.setFetchClauseExpression(null, null);
return outerQuerySpec;
}
use of org.hibernate.sql.ast.tree.expression.Literal in project hibernate-orm by hibernate.
the class TrimFunction method render.
@Override
public void render(SqlAppender sqlAppender, List<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
final TrimSpec specification = ((TrimSpecification) sqlAstArguments.get(0)).getSpecification();
final Object trimCharacter = ((Literal) sqlAstArguments.get(1)).getLiteralValue();
final Expression sourceExpr = (Expression) sqlAstArguments.get(2);
String trim = dialect.trimPattern(specification, (char) trimCharacter);
new PatternRenderer(trim).render(sqlAppender, Collections.singletonList(sourceExpr), walker);
}
use of org.hibernate.sql.ast.tree.expression.Literal in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method renderFetchPlusOffsetExpressionAsSingleParameter.
protected void renderFetchPlusOffsetExpressionAsSingleParameter(Expression fetchClauseExpression, Expression offsetClauseExpression, int offset) {
if (fetchClauseExpression instanceof Literal) {
final Number fetchCount = (Number) ((Literal) fetchClauseExpression).getLiteralValue();
if (offsetClauseExpression instanceof Literal) {
final Number offsetCount = (Number) ((Literal) offsetClauseExpression).getLiteralValue();
appendSql(fetchCount.intValue() + offsetCount.intValue() + offset);
} else {
appendSql(PARAM_MARKER);
final JdbcParameter offsetParameter = (JdbcParameter) offsetClauseExpression;
final int offsetValue = offset + fetchCount.intValue();
jdbcParameters.addParameter(offsetParameter);
parameterBinders.add((statement, startPosition, jdbcParameterBindings, executionContext) -> {
final JdbcParameterBinding binding = jdbcParameterBindings.getBinding(offsetParameter);
if (binding == null) {
throw new ExecutionException("JDBC parameter value not bound - " + offsetParameter);
}
final Number bindValue = (Number) binding.getBindValue();
offsetParameter.getExpressionType().getJdbcMappings().get(0).getJdbcValueBinder().bind(statement, bindValue.intValue() + offsetValue, startPosition, executionContext.getSession());
});
}
} else {
appendSql(PARAM_MARKER);
final JdbcParameter offsetParameter = (JdbcParameter) offsetClauseExpression;
final JdbcParameter fetchParameter = (JdbcParameter) fetchClauseExpression;
final OffsetReceivingParameterBinder fetchBinder = new OffsetReceivingParameterBinder(offsetParameter, fetchParameter, offset);
// And in this case, we only want to bind a single JDBC parameter
if (!(offsetParameter instanceof OffsetJdbcParameter)) {
jdbcParameters.addParameter(offsetParameter);
parameterBinders.add((statement, startPosition, jdbcParameterBindings, executionContext) -> {
final JdbcParameterBinding binding = jdbcParameterBindings.getBinding(offsetParameter);
if (binding == null) {
throw new ExecutionException("JDBC parameter value not bound - " + offsetParameter);
}
fetchBinder.dynamicOffset = (Number) binding.getBindValue();
});
}
jdbcParameters.addParameter(fetchParameter);
parameterBinders.add(fetchBinder);
}
}
use of org.hibernate.sql.ast.tree.expression.Literal in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method renderExpressionAsLiteral.
protected void renderExpressionAsLiteral(Expression expression, JdbcParameterBindings jdbcParameterBindings) {
if (expression instanceof Literal) {
expression.accept(this);
return;
} else if (expression instanceof JdbcParameter) {
if (jdbcParameterBindings == null) {
throw new IllegalArgumentException("Can't interpret expression because no parameter bindings are available!");
}
final JdbcParameter parameter = (JdbcParameter) expression;
renderAsLiteral(parameter, getParameterBindValue(parameter));
return;
} else if (expression instanceof SqmParameterInterpretation) {
if (jdbcParameterBindings == null) {
throw new IllegalArgumentException("Can't interpret expression because no parameter bindings are available!");
}
final JdbcParameter parameter = (JdbcParameter) ((SqmParameterInterpretation) expression).getResolvedExpression();
renderAsLiteral(parameter, getParameterBindValue(parameter));
return;
}
throw new UnsupportedOperationException("Can't render expression as literal: " + expression);
}
Aggregations