use of org.hibernate.sql.ast.tree.expression.SqlTuple in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method resolveGroupOrOrderByExpression.
protected Expression resolveGroupOrOrderByExpression(SqmExpression<?> groupByClauseExpression) {
final int sqmPosition;
if (groupByClauseExpression instanceof SqmAliasedNodeRef) {
final int aliasedNodeOrdinal = ((SqmAliasedNodeRef) groupByClauseExpression).getPosition();
sqmPosition = aliasedNodeOrdinal - 1;
} else if (statement.getQuerySource() == SqmQuerySource.CRITERIA) {
// In JPA Criteria we could be using the same expression object for the group/order by and select item
// We try to find the select item position for this expression here which is not necessarily just an optimization.
// This is vital to enable the support for parameters in these expressions.
// Databases usually don't know if a parameter marker will have the same value as another parameter marker
// and due to that, a database usually complains when seeing something like
// `select ?, count(*) from dual group by ?` saying that there is a missing group by for the first `?`
// To avoid this issue, we determine the position and let the SqlAstTranslator handle the rest.
// Usually it will render `select ?, count(*) from dual group by 1` if supported
// or force rendering the parameter as literal instead so that the database can see the grouping is fine
final SqmQuerySpec<?> querySpec = currentSqmQueryPart.getFirstQuerySpec();
sqmPosition = indexOfExpression(querySpec.getSelectClause().getSelections(), groupByClauseExpression);
} else {
sqmPosition = -1;
}
if (sqmPosition != -1) {
final List<SqlSelection> selections = currentSqlSelectionCollector().getSelections(sqmPosition);
assert selections != null : String.format(Locale.ROOT, "No SqlSelections for SQM position `%s`", sqmPosition);
final List<Expression> expressions = new ArrayList<>(selections.size());
OUTER: for (int i = 0; i < selections.size(); i++) {
final SqlSelection selection = selections.get(i);
// which is, just like the identifier itself, also registered as selection
for (int j = 0; j < i; j++) {
if (selections.get(j) == selection) {
continue OUTER;
}
}
if (currentSqmQueryPart instanceof SqmQueryGroup<?>) {
// Reusing the SqlSelection for query groups would be wrong because the aliases do no exist
// So we have to use a literal expression in a new SqlSelection instance to refer to the position
expressions.add(new SqlSelectionExpression(new SqlSelectionImpl(selection.getJdbcResultSetIndex(), selection.getValuesArrayPosition(), new QueryLiteral<>(selection.getValuesArrayPosition(), basicType(Integer.class)))));
} else {
expressions.add(new SqlSelectionExpression(selection));
}
}
if (expressions.size() == 1) {
return expressions.get(0);
}
return new SqlTuple(expressions, null);
}
return (Expression) groupByClauseExpression.accept(this);
}
use of org.hibernate.sql.ast.tree.expression.SqlTuple in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method createCorrelatedAggregateSubQuery.
protected Expression createCorrelatedAggregateSubQuery(AbstractSqmSpecificPluralPartPath<?> pluralPartPath, boolean index, String function) {
prepareReusablePath(pluralPartPath.getLhs(), () -> null);
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) determineValueMapping(pluralPartPath.getPluralDomainPath());
final FromClauseAccess parentFromClauseAccess = getFromClauseAccess();
final QuerySpec subQuerySpec = new QuerySpec(false);
pushProcessingState(new SqlAstQueryPartProcessingStateImpl(subQuerySpec, getCurrentProcessingState(), this, currentClauseStack::getCurrent, false));
try {
final TableGroup tableGroup = pluralAttributeMapping.createRootTableGroup(true, pluralPartPath.getNavigablePath(), null, () -> subQuerySpec::applyPredicate, this, creationContext);
pluralAttributeMapping.applyBaseRestrictions(subQuerySpec::applyPredicate, tableGroup, true, getLoadQueryInfluencers().getEnabledFilters(), null, this);
getFromClauseAccess().registerTableGroup(pluralPartPath.getNavigablePath(), tableGroup);
registerPluralTableGroupParts(tableGroup);
subQuerySpec.getFromClause().addRoot(tableGroup);
final AbstractSqmSelfRenderingFunctionDescriptor functionDescriptor = (AbstractSqmSelfRenderingFunctionDescriptor) creationContext.getSessionFactory().getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor(function);
final CollectionPart collectionPart = index ? pluralAttributeMapping.getIndexDescriptor() : pluralAttributeMapping.getElementDescriptor();
final ModelPart modelPart;
if (collectionPart instanceof EntityAssociationMapping) {
modelPart = ((EntityAssociationMapping) collectionPart).getKeyTargetMatchPart();
} else {
modelPart = collectionPart;
}
final List<Expression> arguments = new ArrayList<>(1);
final NavigablePath navigablePath = pluralPartPath.getNavigablePath();
final int jdbcTypeCount = modelPart.getJdbcTypeCount();
final List<Expression> tupleElements;
if (jdbcTypeCount == 1) {
tupleElements = arguments;
} else {
tupleElements = new ArrayList<>(jdbcTypeCount);
}
modelPart.forEachSelectable((selectionIndex, selectionMapping) -> tupleElements.add(new ColumnReference(tableGroup.resolveTableReference(navigablePath, selectionMapping.getContainingTableExpression()), selectionMapping, creationContext.getSessionFactory())));
if (jdbcTypeCount != 1) {
arguments.add(new SqlTuple(tupleElements, modelPart));
}
final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression(functionDescriptor.getName(), functionDescriptor, arguments, null, (ReturnableType<?>) functionDescriptor.getReturnTypeResolver().resolveFunctionReturnType(() -> null, arguments).getJdbcMapping(), modelPart);
subQuerySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, expression));
NavigablePath parent = pluralPartPath.getPluralDomainPath().getNavigablePath().getParent();
subQuerySpec.applyPredicate(pluralAttributeMapping.getKeyDescriptor().generateJoinPredicate(parentFromClauseAccess.findTableGroup(parent), tableGroup, getSqlExpressionResolver(), creationContext));
} finally {
popProcessingStateStack();
}
return subQuerySpec;
}
use of org.hibernate.sql.ast.tree.expression.SqlTuple in project hibernate-orm by hibernate.
the class RestrictedDeleteExecutionDelegate method deleteFromNonRootTableWithoutIdTable.
private int deleteFromNonRootTableWithoutIdTable(NamedTableReference targetTableReference, Supplier<Consumer<SelectableConsumer>> tableKeyColumnVisitationSupplier, SqlExpressionResolver sqlExpressionResolver, TableGroup rootTableGroup, QuerySpec matchingIdSubQuerySpec, JdbcParameterBindings jdbcParameterBindings, ExecutionContext executionContext) {
assert targetTableReference != null;
log.tracef("deleteFromNonRootTable - %s", targetTableReference.getTableExpression());
final NamedTableReference deleteTableReference = new NamedTableReference(targetTableReference.getTableExpression(), DeleteStatement.DEFAULT_ALIAS, true, sessionFactory);
final Predicate tableDeletePredicate;
if (matchingIdSubQuerySpec == null) {
tableDeletePredicate = null;
} else {
/*
* delete from sub_table
* where sub_id in (
* select root_id from root_table
* where {predicate}
* )
*/
/*
* Create the `sub_id` reference as the LHS of the in-subquery predicate
*/
final List<ColumnReference> deletingTableColumnRefs = new ArrayList<>();
tableKeyColumnVisitationSupplier.get().accept((columnIndex, selection) -> {
assert deleteTableReference.getTableReference(selection.getContainingTableExpression()) != null;
final Expression expression = sqlExpressionResolver.resolveSqlExpression(SqlExpressionResolver.createColumnReferenceKey(deleteTableReference, selection.getSelectionExpression()), sqlAstProcessingState -> new ColumnReference(deleteTableReference, selection, sessionFactory));
deletingTableColumnRefs.add((ColumnReference) expression);
});
final Expression deletingTableColumnRefsExpression;
if (deletingTableColumnRefs.size() == 1) {
deletingTableColumnRefsExpression = deletingTableColumnRefs.get(0);
} else {
deletingTableColumnRefsExpression = new SqlTuple(deletingTableColumnRefs, entityDescriptor.getIdentifierMapping());
}
tableDeletePredicate = new InSubQueryPredicate(deletingTableColumnRefsExpression, matchingIdSubQuerySpec, false);
}
final DeleteStatement sqlAstDelete = new DeleteStatement(deleteTableReference, tableDeletePredicate);
final int rows = executeSqlDelete(sqlAstDelete, jdbcParameterBindings, executionContext);
log.debugf("deleteFromNonRootTable - `%s` : %s rows", targetTableReference, rows);
return rows;
}
use of org.hibernate.sql.ast.tree.expression.SqlTuple in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method determineLateralEmulationPredicate.
protected Predicate determineLateralEmulationPredicate(TableGroup tableGroup) {
if (tableGroup.getPrimaryTableReference() instanceof QueryPartTableReference) {
final QueryPartTableReference tableReference = (QueryPartTableReference) tableGroup.getPrimaryTableReference();
final List<String> columnNames = tableReference.getColumnNames();
final List<ColumnReference> columnReferences = new ArrayList<>(columnNames.size());
final List<ColumnReference> subColumnReferences = new ArrayList<>(columnNames.size());
final QueryPart queryPart = tableReference.getQueryPart();
for (String columnName : columnNames) {
columnReferences.add(new ColumnReference(tableReference, columnName, false, null, null, null, sessionFactory));
}
// The following optimization only makes sense if the necessary features are supported natively
if ((columnReferences.size() == 1 || supportsRowValueConstructorSyntax()) && supportsDistinctFromPredicate()) {
// ... x(c) on x.c is not distinct from (... fetch first 1 rows only)
if (queryPart.getFetchClauseType() == FetchClauseType.ROWS_ONLY && queryPart.getFetchClauseExpression() instanceof QueryLiteral<?> && Integer.valueOf(1).equals(((QueryLiteral<?>) queryPart.getFetchClauseExpression()).getLiteralValue())) {
return new ComparisonPredicate(new SqlTuple(columnReferences, tableGroup.getModelPart()), ComparisonOperator.NOT_DISTINCT_FROM, queryPart);
}
}
// ... x(c) on exists(select x.c intersect ...)
if (supportsIntersect()) {
final QuerySpec lhsReferencesQuery = new QuerySpec(false);
for (ColumnReference columnReference : columnReferences) {
lhsReferencesQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, columnReference));
}
final List<QueryPart> queryParts = new ArrayList<>(2);
queryParts.add(lhsReferencesQuery);
queryParts.add(queryPart);
return new ExistsPredicate(new QueryGroup(false, SetOperator.INTERSECT, queryParts), false, getBooleanType());
}
// Double nested sub-query rendering if nothing else works
// We try to avoid this as much as possible as it is not very efficient and some DBs don't like it
// when a correlation happens in a sub-query that is not a direct child
// ... x(c) on exists(select 1 from (...) synth_(c) where x.c = synth_.c)
final QueryPartTableGroup subTableGroup = new QueryPartTableGroup(tableGroup.getNavigablePath(), (TableGroupProducer) tableGroup.getModelPart(), queryPart, "synth_", columnNames, false, true, sessionFactory);
for (String columnName : columnNames) {
subColumnReferences.add(new ColumnReference(subTableGroup.getPrimaryTableReference(), columnName, false, null, null, null, sessionFactory));
}
final QuerySpec existsQuery = new QuerySpec(false, 1);
existsQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new QueryLiteral<>(1, getIntegerType())));
existsQuery.getFromClause().addRoot(subTableGroup);
existsQuery.applyPredicate(new ComparisonPredicate(new SqlTuple(columnReferences, tableGroup.getModelPart()), ComparisonOperator.NOT_DISTINCT_FROM, new SqlTuple(subColumnReferences, tableGroup.getModelPart())));
return new ExistsPredicate(existsQuery, false, getBooleanType());
}
return null;
}
use of org.hibernate.sql.ast.tree.expression.SqlTuple in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method renderCommaSeparatedSelectExpression.
protected final void renderCommaSeparatedSelectExpression(Iterable<? extends SqlAstNode> expressions) {
String separator = NO_SEPARATOR;
for (SqlAstNode expression : expressions) {
final SqlTuple sqlTuple = SqlTupleContainer.getSqlTuple(expression);
if (sqlTuple != null) {
for (Expression e : sqlTuple.getExpressions()) {
appendSql(separator);
renderSelectExpression(e);
separator = COMA_SEPARATOR;
}
} else if (expression instanceof Expression) {
appendSql(separator);
renderSelectExpression((Expression) expression);
} else {
appendSql(separator);
expression.accept(this);
}
separator = COMA_SEPARATOR;
}
}
Aggregations