use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class TableBasedInsertHandler method resolveDelegate.
private ExecutionDelegate resolveDelegate(DomainQueryExecutionContext executionContext) {
final EntityPersister entityDescriptor = sessionFactory.getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(getSqmInsertStatement().getTarget().getEntityName());
final MultiTableSqmMutationConverter converterDelegate = new MultiTableSqmMutationConverter(entityDescriptor, getSqmInsertStatement(), getSqmInsertStatement().getTarget(), domainParameterXref, executionContext.getQueryOptions(), executionContext.getSession().getLoadQueryInfluencers(), executionContext.getQueryParameterBindings(), sessionFactory);
final TableGroup insertingTableGroup = converterDelegate.getMutatingTableGroup();
final Map<SqmParameter<?>, List<List<JdbcParameter>>> parameterResolutions;
if (domainParameterXref.getSqmParameterCount() == 0) {
parameterResolutions = Collections.emptyMap();
} else {
parameterResolutions = new IdentityHashMap<>();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// visit the insertion target using our special converter, collecting
// information about the target paths
final List<Assignment> targetPathColumns = new ArrayList<>();
final Map<SqmParameter<?>, MappingModelExpressible<?>> paramTypeResolutions = new LinkedHashMap<>();
final NamedTableReference entityTableReference = new NamedTableReference(entityTable.getTableExpression(), TemporaryTable.DEFAULT_ALIAS, true, sessionFactory);
final InsertStatement insertStatement = new InsertStatement(entityTableReference);
final BaseSqmToSqlAstConverter.AdditionalInsertValues additionalInsertValues = converterDelegate.visitInsertionTargetPaths((assigable, columnReferences) -> {
insertStatement.addTargetColumnReferences(columnReferences);
targetPathColumns.add(new Assignment(assigable, (Expression) assigable));
}, sqmInsertStatement, entityDescriptor, insertingTableGroup, (sqmParameter, mappingType, jdbcParameters) -> {
parameterResolutions.computeIfAbsent(sqmParameter, k -> new ArrayList<>(1)).add(jdbcParameters);
paramTypeResolutions.put(sqmParameter, mappingType);
});
if (sqmInsertStatement instanceof SqmInsertSelectStatement) {
final QueryPart queryPart = converterDelegate.visitQueryPart(((SqmInsertSelectStatement<?>) sqmInsertStatement).getSelectQueryPart());
queryPart.visitQuerySpecs(querySpec -> {
if (additionalInsertValues.applySelections(querySpec, sessionFactory)) {
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(entityTable.getColumns().size() - 1);
final ColumnReference columnReference = new ColumnReference((String) null, rowNumberColumn.getColumnName(), false, null, null, rowNumberColumn.getJdbcMapping(), sessionFactory);
insertStatement.getTargetColumnReferences().set(insertStatement.getTargetColumnReferences().size() - 1, columnReference);
targetPathColumns.set(targetPathColumns.size() - 1, new Assignment(columnReference, columnReference));
} else if (entityDescriptor.getIdentifierGenerator() instanceof OptimizableGenerator) {
final Optimizer optimizer = ((OptimizableGenerator) entityDescriptor.getIdentifierGenerator()).getOptimizer();
if (optimizer != null && optimizer.getIncrementSize() > 1) {
if (!sessionFactory.getJdbcServices().getDialect().supportsWindowFunctions()) {
return;
}
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(entityTable.getColumns().size() - 1);
final ColumnReference columnReference = new ColumnReference((String) null, rowNumberColumn.getColumnName(), false, null, null, rowNumberColumn.getJdbcMapping(), sessionFactory);
insertStatement.getTargetColumnReferences().add(columnReference);
targetPathColumns.add(new Assignment(columnReference, columnReference));
final BasicType<Integer> rowNumberType = sessionFactory.getTypeConfiguration().getBasicTypeForJavaType(Integer.class);
querySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new Over<>(new SelfRenderingFunctionSqlAstExpression("row_number", (appender, args, walker) -> appender.appendSql("row_number()"), Collections.emptyList(), rowNumberType, rowNumberType), Collections.emptyList(), Collections.emptyList())));
}
}
});
insertStatement.setSourceSelectStatement(queryPart);
} else {
// Add the row number column if there is one
final IdentifierGenerator generator = entityDescriptor.getIdentifierGenerator();
final BasicType<?> rowNumberType;
if (generator instanceof OptimizableGenerator) {
final Optimizer optimizer = ((OptimizableGenerator) generator).getOptimizer();
if (optimizer != null && optimizer.getIncrementSize() > 1) {
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(entityTable.getColumns().size() - 1);
rowNumberType = (BasicType<?>) rowNumberColumn.getJdbcMapping();
final ColumnReference columnReference = new ColumnReference((String) null, rowNumberColumn.getColumnName(), false, null, null, rowNumberColumn.getJdbcMapping(), sessionFactory);
insertStatement.getTargetColumnReferences().add(columnReference);
targetPathColumns.add(new Assignment(columnReference, columnReference));
} else {
rowNumberType = null;
}
} else {
rowNumberType = null;
}
final List<SqmValues> sqmValuesList = ((SqmInsertValuesStatement<?>) sqmInsertStatement).getValuesList();
final List<Values> valuesList = new ArrayList<>(sqmValuesList.size());
for (int i = 0; i < sqmValuesList.size(); i++) {
final Values values = converterDelegate.visitValues(sqmValuesList.get(i));
additionalInsertValues.applyValues(values);
if (rowNumberType != null) {
values.getExpressions().add(new QueryLiteral<>(i + 1, rowNumberType));
}
valuesList.add(values);
}
insertStatement.setValuesList(valuesList);
}
converterDelegate.pruneTableGroupJoins();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// cross-reference the TableReference by alias. The TableGroup already
// cross-references it by name, but the ColumnReference only has the alias
final Map<String, TableReference> tableReferenceByAlias = CollectionHelper.mapOfSize(insertingTableGroup.getTableReferenceJoins().size() + 1);
collectTableReference(insertingTableGroup.getPrimaryTableReference(), tableReferenceByAlias::put);
for (int i = 0; i < insertingTableGroup.getTableReferenceJoins().size(); i++) {
collectTableReference(insertingTableGroup.getTableReferenceJoins().get(i), tableReferenceByAlias::put);
}
return new InsertExecutionDelegate(sqmInsertStatement, converterDelegate, entityTable, afterUseAction, sessionUidAccess, domainParameterXref, insertingTableGroup, tableReferenceByAlias, targetPathColumns, insertStatement, parameterResolutions, paramTypeResolutions, executionContext);
}
use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class ArgumentTypesValidator method validateSqlTypes.
/**
* This is the final validation phase with the fully-typed SQL nodes. Note that these
* checks are much less useful, occurring "too late", right before we execute the
* query and get an error from the database. However, they help in the sense of (a)
* resulting in more consistent/understandable error messages, and (b) protecting the
* user from writing queries that depend on generally-unportable implicit type
* conversions happening at the database level. (Implicit type conversions between
* numeric types are portable, and are not prohibited here.)
*/
@Override
public void validateSqlTypes(List<? extends SqlAstNode> arguments, String functionName) {
int count = 0;
for (SqlAstNode argument : arguments) {
if (argument instanceof Expression) {
JdbcMappingContainer expressionType = ((Expression) argument).getExpressionType();
if (expressionType != null) {
ParameterDetector detector = new ParameterDetector();
argument.accept(detector);
if (detector.detected) {
count += expressionType.getJdbcTypeCount();
} else {
count = validateArgument(count, expressionType, functionName);
}
}
}
}
}
use of org.hibernate.sql.ast.tree.expression.Expression 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.Expression in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method visitValuesList.
protected void visitValuesList(List<Values> valuesList) {
appendSql("values");
boolean firstTuple = true;
final Stack<Clause> clauseStack = getClauseStack();
try {
clauseStack.push(Clause.VALUES);
for (Values values : valuesList) {
if (firstTuple) {
firstTuple = false;
} else {
appendSql(COMA_SEPARATOR_CHAR);
}
appendSql(" (");
boolean firstExpr = true;
for (Expression expression : values.getExpressions()) {
if (firstExpr) {
firstExpr = false;
} else {
appendSql(COMA_SEPARATOR_CHAR);
}
expression.accept(this);
}
appendSql(')');
}
} finally {
clauseStack.pop();
}
}
use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method areAllResultsParameters.
protected boolean areAllResultsParameters(CaseSearchedExpression caseSearchedExpression) {
final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get(0).getResult();
if (isParameter(firstResult)) {
for (int i = 1; i < whenFragments.size(); i++) {
if (!isParameter(whenFragments.get(i).getResult())) {
return false;
}
}
return true;
}
return false;
}
Aggregations