Search in sources :

Example 1 with QueryPartTableReference

use of org.hibernate.sql.ast.tree.from.QueryPartTableReference in project hibernate-orm by hibernate.

the class AbstractSqlAstTranslator method renderPrimaryTableReference.

protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lockMode) {
    final TableReference tableReference = tableGroup.getPrimaryTableReference();
    if (tableReference instanceof NamedTableReference) {
        return renderNamedTableReference((NamedTableReference) tableReference, lockMode);
    }
    final DerivedTableReference derivedTableReference = (DerivedTableReference) tableReference;
    if (derivedTableReference.isLateral()) {
        if (getDialect().supportsLateral()) {
            appendSql("lateral");
        } else if (tableReference instanceof QueryPartTableReference) {
            final QueryPartTableReference queryPartTableReference = (QueryPartTableReference) tableReference;
            final QueryPart emulationQueryPart = stripToSelectClause(queryPartTableReference.getQueryPart());
            final QueryPartTableReference emulationTableReference = new QueryPartTableReference(emulationQueryPart, tableReference.getIdentificationVariable(), queryPartTableReference.getColumnNames(), false, sessionFactory);
            emulationTableReference.accept(this);
            return false;
        }
    }
    tableReference.accept(this);
    return false;
}
Also used : NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) DerivedTableReference(org.hibernate.sql.ast.tree.from.DerivedTableReference) ValuesTableReference(org.hibernate.sql.ast.tree.from.ValuesTableReference) FunctionTableReference(org.hibernate.sql.ast.tree.from.FunctionTableReference) TableReference(org.hibernate.sql.ast.tree.from.TableReference) QueryPartTableReference(org.hibernate.sql.ast.tree.from.QueryPartTableReference) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) DerivedTableReference(org.hibernate.sql.ast.tree.from.DerivedTableReference) QueryPartTableReference(org.hibernate.sql.ast.tree.from.QueryPartTableReference)

Example 2 with QueryPartTableReference

use of org.hibernate.sql.ast.tree.from.QueryPartTableReference in project hibernate-orm by hibernate.

the class BaseSqmToSqlAstConverter method createLateralJoinExpression.

protected Expression createLateralJoinExpression(AbstractSqmSpecificPluralPartPath<?> pluralPartPath, boolean index, String functionName) {
    prepareReusablePath(pluralPartPath.getLhs(), () -> null);
    final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) determineValueMapping(pluralPartPath.getPluralDomainPath());
    final FromClauseAccess parentFromClauseAccess = getFromClauseAccess();
    final TableGroup parentTableGroup = parentFromClauseAccess.findTableGroup(pluralPartPath.getNavigablePath().getParent());
    final CollectionPart collectionPart = index ? pluralAttributeMapping.getIndexDescriptor() : pluralAttributeMapping.getElementDescriptor();
    final ModelPart modelPart;
    if (collectionPart instanceof EntityAssociationMapping) {
        modelPart = ((EntityAssociationMapping) collectionPart).getKeyTargetMatchPart();
    } else {
        modelPart = collectionPart;
    }
    final int jdbcTypeCount = modelPart.getJdbcTypeCount();
    final String pathName = functionName + (index ? "_index" : "_element");
    final String identifierVariable = parentTableGroup.getPrimaryTableReference().getIdentificationVariable() + "_" + pathName;
    final NavigablePath queryPath = new NavigablePath(parentTableGroup.getNavigablePath(), pathName, identifierVariable);
    TableGroup lateralTableGroup = parentFromClauseAccess.findTableGroup(queryPath);
    if (lateralTableGroup == null) {
        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 List<String> columnNames = new ArrayList<>(jdbcTypeCount);
            final List<ColumnReference> resultColumnReferences = new ArrayList<>(jdbcTypeCount);
            final NavigablePath navigablePath = pluralPartPath.getNavigablePath();
            final Boolean max = functionName.equalsIgnoreCase("max") ? Boolean.TRUE : (functionName.equalsIgnoreCase("min") ? Boolean.FALSE : null);
            final AbstractSqmSelfRenderingFunctionDescriptor functionDescriptor = (AbstractSqmSelfRenderingFunctionDescriptor) creationContext.getSessionFactory().getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor(functionName);
            final List<ColumnReference> subQueryColumns = new ArrayList<>(jdbcTypeCount);
            modelPart.forEachSelectable((selectionIndex, selectionMapping) -> {
                final ColumnReference columnReference = new ColumnReference(tableGroup.resolveTableReference(navigablePath, selectionMapping.getContainingTableExpression()), selectionMapping, creationContext.getSessionFactory());
                final String columnName;
                if (selectionMapping.isFormula()) {
                    columnName = "col" + columnNames.size();
                } else {
                    columnName = selectionMapping.getSelectionExpression();
                }
                columnNames.add(columnName);
                subQueryColumns.add(columnReference);
                if (max != null) {
                    subQuerySpec.addSortSpecification(new SortSpecification(columnReference, max ? SortOrder.DESCENDING : SortOrder.ASCENDING));
                }
            });
            if (max != null) {
                for (int i = 0; i < subQueryColumns.size(); i++) {
                    subQuerySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(i + 1, i, subQueryColumns.get(i)));
                    resultColumnReferences.add(new ColumnReference(identifierVariable, columnNames.get(i), false, null, null, subQueryColumns.get(i).getJdbcMapping(), creationContext.getSessionFactory()));
                }
                subQuerySpec.setFetchClauseExpression(new QueryLiteral<>(1, basicType(Integer.class)), FetchClauseType.ROWS_ONLY);
            } else {
                final List<? extends SqlAstNode> arguments;
                if (jdbcTypeCount == 1) {
                    arguments = subQueryColumns;
                } else {
                    arguments = Collections.singletonList(new SqlTuple(subQueryColumns, 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));
                resultColumnReferences.add(new ColumnReference(identifierVariable, columnNames.get(0), false, null, null, expression.getExpressionType().getJdbcMappings().get(0), creationContext.getSessionFactory()));
            }
            subQuerySpec.applyPredicate(pluralAttributeMapping.getKeyDescriptor().generateJoinPredicate(parentFromClauseAccess.findTableGroup(pluralPartPath.getPluralDomainPath().getNavigablePath().getParent()), tableGroup, getSqlExpressionResolver(), creationContext));
            final String compatibleTableExpression;
            if (modelPart instanceof BasicValuedModelPart) {
                compatibleTableExpression = ((BasicValuedModelPart) modelPart).getContainingTableExpression();
            } else if (modelPart instanceof EmbeddableValuedModelPart) {
                compatibleTableExpression = ((EmbeddableValuedModelPart) modelPart).getContainingTableExpression();
            } else {
                compatibleTableExpression = null;
            }
            lateralTableGroup = new QueryPartTableGroup(queryPath, null, subQuerySpec, identifierVariable, columnNames, compatibleTableExpression, true, false, creationContext.getSessionFactory());
            if (currentlyProcessingJoin == null) {
                parentTableGroup.addTableGroupJoin(new TableGroupJoin(lateralTableGroup.getNavigablePath(), SqlAstJoinType.LEFT, lateralTableGroup));
            } else {
                // In case this is used in the ON condition, we must prepend this lateral join
                final TableGroup targetTableGroup;
                if (currentlyProcessingJoin.getLhs() == null) {
                    targetTableGroup = parentFromClauseAccess.getTableGroup(currentlyProcessingJoin.findRoot().getNavigablePath());
                } else {
                    targetTableGroup = parentFromClauseAccess.getTableGroup(currentlyProcessingJoin.getLhs().getNavigablePath());
                }
                // Many databases would support modelling this as nested table group join,
                // but at least SQL Server doesn't like that, saying that the correlated columns can't be "bound"
                // Since there is no dependency on the currentlyProcessingJoin, we can safely prepend this join
                targetTableGroup.prependTableGroupJoin(currentlyProcessingJoin.getNavigablePath(), new TableGroupJoin(lateralTableGroup.getNavigablePath(), SqlAstJoinType.LEFT, lateralTableGroup));
            }
            parentFromClauseAccess.registerTableGroup(lateralTableGroup.getNavigablePath(), lateralTableGroup);
            if (jdbcTypeCount == 1) {
                return new SelfRenderingFunctionSqlAstExpression(pathName, (sqlAppender, sqlAstArguments, walker) -> {
                    sqlAstArguments.get(0).accept(walker);
                }, resultColumnReferences, (ReturnableType<?>) resultColumnReferences.get(0).getJdbcMapping(), resultColumnReferences.get(0).getJdbcMapping());
            } else {
                return new SqlTuple(resultColumnReferences, modelPart);
            }
        } finally {
            popProcessingStateStack();
        }
    }
    final QueryPartTableReference tableReference = (QueryPartTableReference) lateralTableGroup.getPrimaryTableReference();
    if (jdbcTypeCount == 1) {
        final List<SqlSelection> sqlSelections = tableReference.getQueryPart().getFirstQuerySpec().getSelectClause().getSqlSelections();
        return new SelfRenderingFunctionSqlAstExpression(pathName, (sqlAppender, sqlAstArguments, walker) -> {
            sqlAstArguments.get(0).accept(walker);
        }, Collections.singletonList(new ColumnReference(identifierVariable, tableReference.getColumnNames().get(0), false, null, null, sqlSelections.get(0).getExpressionType().getJdbcMappings().get(0), creationContext.getSessionFactory())), (ReturnableType<?>) sqlSelections.get(0).getExpressionType().getJdbcMappings().get(0), sqlSelections.get(0).getExpressionType());
    } else {
        final List<ColumnReference> resultColumnReferences = new ArrayList<>(jdbcTypeCount);
        modelPart.forEachSelectable((selectionIndex, selectionMapping) -> resultColumnReferences.add(new ColumnReference(identifierVariable, tableReference.getColumnNames().get(selectionIndex), false, null, null, selectionMapping.getJdbcMapping(), creationContext.getSessionFactory())));
        return new SqlTuple(resultColumnReferences, modelPart);
    }
}
Also used : SelfRenderingAggregateFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression) NavigablePath(org.hibernate.query.spi.NavigablePath) ConvertibleModelPart(org.hibernate.metamodel.mapping.ConvertibleModelPart) ModelPart(org.hibernate.metamodel.mapping.ModelPart) EntityValuedModelPart(org.hibernate.metamodel.mapping.EntityValuedModelPart) BasicValuedModelPart(org.hibernate.metamodel.mapping.BasicValuedModelPart) EmbeddableValuedModelPart(org.hibernate.metamodel.mapping.EmbeddableValuedModelPart) PluralAttributeMapping(org.hibernate.metamodel.mapping.PluralAttributeMapping) ArrayList(java.util.ArrayList) SqlSelection(org.hibernate.sql.ast.spi.SqlSelection) AbstractSqmSelfRenderingFunctionDescriptor(org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor) TableGroupJoin(org.hibernate.sql.ast.tree.from.TableGroupJoin) SqlAstQueryPartProcessingStateImpl(org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl) EntityCollectionPart(org.hibernate.metamodel.mapping.internal.EntityCollectionPart) CollectionPart(org.hibernate.metamodel.mapping.CollectionPart) EmbeddedCollectionPart(org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart) VirtualTableGroup(org.hibernate.sql.ast.tree.from.VirtualTableGroup) LazyTableGroup(org.hibernate.sql.ast.tree.from.LazyTableGroup) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) CorrelatedTableGroup(org.hibernate.sql.ast.tree.from.CorrelatedTableGroup) CorrelatedPluralTableGroup(org.hibernate.sql.ast.tree.from.CorrelatedPluralTableGroup) PluralTableGroup(org.hibernate.sql.ast.tree.from.PluralTableGroup) QueryPartTableGroup(org.hibernate.sql.ast.tree.from.QueryPartTableGroup) BasicValuedModelPart(org.hibernate.metamodel.mapping.BasicValuedModelPart) EntityAssociationMapping(org.hibernate.metamodel.mapping.EntityAssociationMapping) QueryPartTableGroup(org.hibernate.sql.ast.tree.from.QueryPartTableGroup) FromClauseAccess(org.hibernate.sql.ast.spi.FromClauseAccess) SqmSortSpecification(org.hibernate.query.sqm.tree.select.SqmSortSpecification) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) BinaryArithmeticExpression(org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression) SqmModifiedSubQueryExpression(org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) SelfRenderingAggregateFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression) CaseSearchedExpression(org.hibernate.sql.ast.tree.expression.CaseSearchedExpression) SelfRenderingSqlFragmentExpression(org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression) Expression(org.hibernate.sql.ast.tree.expression.Expression) SelfRenderingExpression(org.hibernate.sql.ast.tree.expression.SelfRenderingExpression) SqmExpression(org.hibernate.query.sqm.tree.expression.SqmExpression) CaseSimpleExpression(org.hibernate.sql.ast.tree.expression.CaseSimpleExpression) SqlSelectionExpression(org.hibernate.sql.ast.tree.expression.SqlSelectionExpression) ModifiedSubQueryExpression(org.hibernate.sql.ast.tree.expression.ModifiedSubQueryExpression) EmbeddableValuedModelPart(org.hibernate.metamodel.mapping.EmbeddableValuedModelPart) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) SqlTuple(org.hibernate.sql.ast.tree.expression.SqlTuple) SqlSelectionImpl(org.hibernate.sql.results.internal.SqlSelectionImpl) SqmQuerySpec(org.hibernate.query.sqm.tree.select.SqmQuerySpec) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) QueryPartTableReference(org.hibernate.sql.ast.tree.from.QueryPartTableReference) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference)

Example 3 with QueryPartTableReference

use of org.hibernate.sql.ast.tree.from.QueryPartTableReference 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;
}
Also used : QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) ExistsPredicate(org.hibernate.sql.ast.tree.predicate.ExistsPredicate) ArrayList(java.util.ArrayList) QueryPartTableGroup(org.hibernate.sql.ast.tree.from.QueryPartTableGroup) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) QueryGroup(org.hibernate.sql.ast.tree.select.QueryGroup) ConvertedQueryLiteral(org.hibernate.sql.ast.tree.expression.ConvertedQueryLiteral) QueryLiteral(org.hibernate.sql.ast.tree.expression.QueryLiteral) SqlTuple(org.hibernate.sql.ast.tree.expression.SqlTuple) SqlSelectionImpl(org.hibernate.sql.results.internal.SqlSelectionImpl) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) QueryPartTableReference(org.hibernate.sql.ast.tree.from.QueryPartTableReference) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference)

Aggregations

QueryPartTableReference (org.hibernate.sql.ast.tree.from.QueryPartTableReference)3 ArrayList (java.util.ArrayList)2 ColumnReference (org.hibernate.sql.ast.tree.expression.ColumnReference)2 SqlTuple (org.hibernate.sql.ast.tree.expression.SqlTuple)2 BasicValuedModelPart (org.hibernate.metamodel.mapping.BasicValuedModelPart)1 CollectionPart (org.hibernate.metamodel.mapping.CollectionPart)1 ConvertibleModelPart (org.hibernate.metamodel.mapping.ConvertibleModelPart)1 EmbeddableValuedModelPart (org.hibernate.metamodel.mapping.EmbeddableValuedModelPart)1 EntityAssociationMapping (org.hibernate.metamodel.mapping.EntityAssociationMapping)1 EntityValuedModelPart (org.hibernate.metamodel.mapping.EntityValuedModelPart)1 ModelPart (org.hibernate.metamodel.mapping.ModelPart)1 PluralAttributeMapping (org.hibernate.metamodel.mapping.PluralAttributeMapping)1 EmbeddedCollectionPart (org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart)1 EntityCollectionPart (org.hibernate.metamodel.mapping.internal.EntityCollectionPart)1 NavigablePath (org.hibernate.query.spi.NavigablePath)1 AbstractSqmSelfRenderingFunctionDescriptor (org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor)1 SelfRenderingAggregateFunctionSqlAstExpression (org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression)1 SelfRenderingFunctionSqlAstExpression (org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression)1 SqlAstQueryPartProcessingStateImpl (org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl)1 SqmExpression (org.hibernate.query.sqm.tree.expression.SqmExpression)1