use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method transformDurationArithmetic.
private Object transformDurationArithmetic(SqmBinaryArithmetic<?> expression) {
BinaryArithmeticOperator operator = expression.getOperator();
// the expression tree
switch(operator) {
case ADD:
case SUBTRACT:
// the only legal binary operations involving
// a duration with a date or timestamp are
// addition and subtraction with the duration
// on the right and the date or timestamp on
// the left, producing a date or timestamp
//
// ts + d or ts - d
//
// the only legal binary operations involving
// two durations are addition and subtraction,
// producing a duration
//
// d1 + d2
// re-express addition of non-leaf duration
// expressions to a date or timestamp as
// addition of leaf durations to a date or
// timestamp
// ts + x * (d1 + d2) => (ts + x * d1) + x * d2
// ts - x * (d1 + d2) => (ts - x * d1) - x * d2
// ts + x * (d1 - d2) => (ts + x * d1) - x * d2
// ts - x * (d1 - d2) => (ts - x * d1) + x * d2
Expression timestamp = adjustedTimestamp;
SqmExpressible<?> timestampType = adjustedTimestampType;
adjustedTimestamp = toSqlExpression(expression.getLeftHandOperand().accept(this));
JdbcMappingContainer type = adjustedTimestamp.getExpressionType();
if (type instanceof SqmExpressible) {
adjustedTimestampType = (SqmExpressible<?>) type;
} else if (type instanceof AttributeMapping) {
adjustedTimestampType = (SqmExpressible<?>) ((AttributeMapping) type).getMappedType();
} else {
// else we know it has not been transformed
adjustedTimestampType = expression.getLeftHandOperand().getNodeType();
}
if (operator == SUBTRACT) {
negativeAdjustment = !negativeAdjustment;
}
try {
return expression.getRightHandOperand().accept(this);
} finally {
if (operator == SUBTRACT) {
negativeAdjustment = !negativeAdjustment;
}
adjustedTimestamp = timestamp;
adjustedTimestampType = timestampType;
}
case MULTIPLY:
// finally, we can multiply a duration on the
// right by a scalar value on the left
// scalar multiplication produces a duration
// x * d
// distribute scalar multiplication over the
// terms, not forgetting the propagated scale
// x * (d1 + d2) => x * d1 + x * d2
// x * (d1 - d2) => x * d1 - x * d2
// -x * (d1 + d2) => - x * d1 - x * d2
// -x * (d1 - d2) => - x * d1 + x * d2
Expression duration = toSqlExpression(expression.getLeftHandOperand().accept(this));
Expression scale = adjustmentScale;
boolean negate = negativeAdjustment;
adjustmentScale = applyScale(duration);
// was sucked into the scale
negativeAdjustment = false;
try {
return expression.getRightHandOperand().accept(this);
} finally {
adjustmentScale = scale;
negativeAdjustment = negate;
}
default:
throw new SemanticException("illegal operator for a duration " + operator);
}
}
use of org.hibernate.sql.ast.tree.expression.Expression 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.Expression in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitMemberOfPredicate.
@Override
public Predicate visitMemberOfPredicate(SqmMemberOfPredicate predicate) {
final SqmPath<?> pluralPath = predicate.getPluralPath();
prepareReusablePath(pluralPath, () -> null);
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) determineValueMapping(pluralPath);
if (pluralAttributeMapping.getElementDescriptor() instanceof EntityCollectionPart) {
inferrableTypeAccessStack.push(() -> ((EntityCollectionPart) pluralAttributeMapping.getElementDescriptor()).getKeyTargetMatchPart());
} else if (pluralAttributeMapping.getElementDescriptor() instanceof EmbeddedCollectionPart) {
inferrableTypeAccessStack.push(pluralAttributeMapping::getElementDescriptor);
} else {
inferrableTypeAccessStack.push(() -> pluralAttributeMapping);
}
final Expression lhs;
try {
lhs = (Expression) predicate.getLeftHandExpression().accept(this);
} finally {
inferrableTypeAccessStack.pop();
}
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, pluralPath.getNavigablePath(), null, () -> subQuerySpec::applyPredicate, this, creationContext);
pluralAttributeMapping.applyBaseRestrictions(subQuerySpec::applyPredicate, tableGroup, true, getLoadQueryInfluencers().getEnabledFilters(), null, this);
getFromClauseAccess().registerTableGroup(pluralPath.getNavigablePath(), tableGroup);
registerPluralTableGroupParts(tableGroup);
subQuerySpec.getFromClause().addRoot(tableGroup);
final CollectionPart elementDescriptor = pluralAttributeMapping.getElementDescriptor();
if (elementDescriptor instanceof EntityCollectionPart) {
((EntityCollectionPart) elementDescriptor).getKeyTargetMatchPart().createDomainResult(pluralPath.getNavigablePath(), tableGroup, null, this);
} else {
elementDescriptor.createDomainResult(pluralPath.getNavigablePath(), tableGroup, null, this);
}
subQuerySpec.applyPredicate(pluralAttributeMapping.getKeyDescriptor().generateJoinPredicate(parentFromClauseAccess.findTableGroup(pluralPath.getNavigablePath().getParent()), tableGroup, getSqlExpressionResolver(), creationContext));
} finally {
popProcessingStateStack();
}
return new InSubQueryPredicate(lhs, subQuerySpec, predicate.isNegated(), getBooleanType());
}
use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method addVersionedAssignment.
public void addVersionedAssignment(Consumer<Assignment> assignmentConsumer, SqmUpdateStatement<?> sqmStatement) {
if (!sqmStatement.isVersioned()) {
return;
}
final EntityPersister persister = creationContext.getSessionFactory().getRuntimeMetamodels().getMappingMetamodel().findEntityDescriptor(sqmStatement.getTarget().getEntityName());
if (!persister.isVersioned()) {
throw new SemanticException("increment option specified for update of non-versioned entity");
}
final BasicType<?> versionType = persister.getVersionType();
if (versionType instanceof UserVersionType) {
throw new SemanticException("user-defined version types not supported for increment option");
}
final EntityVersionMapping versionMapping = persister.getVersionMapping();
final List<ColumnReference> targetColumnReferences = BasicValuedPathInterpretation.from((SqmBasicValuedSimplePath<?>) sqmStatement.getRoot().get(versionMapping.getPartName()), this, this, jpaQueryComplianceEnabled).getColumnReferences();
assert targetColumnReferences.size() == 1;
final ColumnReference versionColumn = targetColumnReferences.get(0);
final Expression value;
if (versionMapping.getJdbcMapping().getJdbcType().isTemporal()) {
value = new VersionTypeSeedParameterSpecification(versionType, persister.getVersionJavaType());
} else {
value = new BinaryArithmeticExpression(versionColumn, ADD, new QueryLiteral<>(1, versionType), versionType);
}
assignmentConsumer.accept(new Assignment(versionColumn, value));
}
use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitSetClause.
@Override
public List<Assignment> visitSetClause(SqmSetClause setClause) {
final List<Assignment> assignments = new ArrayList<>(setClause.getAssignments().size());
for (SqmAssignment sqmAssignment : setClause.getAssignments()) {
final List<ColumnReference> targetColumnReferences = new ArrayList<>();
pushProcessingState(new SqlAstProcessingStateImpl(getCurrentProcessingState(), this, getCurrentClauseStack()::getCurrent) {
@Override
public Expression resolveSqlExpression(String key, Function<SqlAstProcessingState, Expression> creator) {
final Expression expression = getParentState().getSqlExpressionResolver().resolveSqlExpression(key, creator);
assert expression instanceof ColumnReference;
targetColumnReferences.add((ColumnReference) expression);
return expression;
}
}, getFromClauseIndex());
final SqmPathInterpretation<?> assignedPathInterpretation;
try {
assignedPathInterpretation = (SqmPathInterpretation<?>) sqmAssignment.getTargetPath().accept(this);
} finally {
popProcessingStateStack();
}
inferrableTypeAccessStack.push(assignedPathInterpretation::getExpressionType);
// final List<ColumnReference> valueColumnReferences = new ArrayList<>();
pushProcessingState(new SqlAstProcessingStateImpl(getCurrentProcessingState(), this, getCurrentClauseStack()::getCurrent) {
@Override
public Expression resolveSqlExpression(String key, Function<SqlAstProcessingState, Expression> creator) {
final Expression expression = getParentState().getSqlExpressionResolver().resolveSqlExpression(key, creator);
assert expression instanceof ColumnReference;
// valueColumnReferences.add( (ColumnReference) expression );
return expression;
}
}, getFromClauseIndex());
try {
final SqmExpression<?> assignmentValue = sqmAssignment.getValue();
final SqmParameter<?> assignmentValueParameter = getSqmParameter(assignmentValue);
if (assignmentValueParameter != null) {
consumeSqmParameter(assignmentValueParameter, assignedPathInterpretation.getExpressionType(), (index, jdbcParameter) -> assignments.add(new Assignment(targetColumnReferences.get(index), jdbcParameter)));
} else {
final Expression valueExpression = (Expression) assignmentValue.accept(this);
final int valueExprJdbcCount = getKeyExpressible(valueExpression.getExpressionType()).getJdbcTypeCount();
final int assignedPathJdbcCount = getKeyExpressible(assignedPathInterpretation.getExpressionType()).getJdbcTypeCount();
if (valueExprJdbcCount != assignedPathJdbcCount) {
SqlTreeCreationLogger.LOGGER.debugf("JDBC type count does not match in UPDATE assignment between the assigned-path and the assigned-value; " + "this will likely lead to problems executing the query");
}
assert assignedPathJdbcCount == valueExprJdbcCount;
for (ColumnReference columnReference : targetColumnReferences) {
assignments.add(new Assignment(columnReference, valueExpression));
}
}
} finally {
popProcessingStateStack();
inferrableTypeAccessStack.pop();
}
}
return assignments;
}
Aggregations