use of org.hibernate.query.sqm.TemporalUnit in project hibernate-orm by hibernate.
the class IntegralTimestampaddFunction method render.
@Override
public void render(SqlAppender sqlAppender, List<? extends SqlAstNode> arguments, SqlAstTranslator<?> walker) {
final DurationUnit field = (DurationUnit) arguments.get(0);
final Expression magnitude = (Expression) arguments.get(1);
final Expression to = (Expression) arguments.get(2);
final TemporalUnit unit = bestTemporalUnit(magnitude, field);
if (unit != field.getUnit()) {
renderWithUnitConversion(sqlAppender, magnitude, to, walker, field, unit);
} else {
super.render(sqlAppender, arguments, walker);
}
}
use of org.hibernate.query.sqm.TemporalUnit in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitBasicValuedPath.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SqmPath
@Override
public Expression visitBasicValuedPath(SqmBasicValuedSimplePath<?> sqmPath) {
final BasicValuedPathInterpretation<?> path = prepareReusablePath(sqmPath, () -> BasicValuedPathInterpretation.from(sqmPath, this, this, jpaQueryComplianceEnabled));
Expression result = path;
if (isDuration(sqmPath.getNodeType())) {
// Durations are stored (at least by default)
// in a NUMERIC column in seconds with fractional
// seconds in the decimal places
// which we need to convert to the given unit
//
// This does not work at all for a Duration
// mapped to a VARCHAR column, in which case
// we would need to parse the weird format
// defined by java.time.Duration (a bit hard
// to do without some custom function).
// Nor does it work for databases which have
// a well-defined INTERVAL type, but that is
// something we could implement.
// first let's apply the propagated scale
Expression scaledExpression = applyScale(toSqlExpression(path));
if (adjustedTimestamp != null) {
if (appliedByUnit != null) {
throw new IllegalStateException();
}
// we're adding this variable duration to the
// given date or timestamp, producing an
// adjusted date or timestamp
result = timestampadd().expression((ReturnableType<?>) adjustedTimestampType, new DurationUnit(SECOND, basicType(Long.class)), scaledExpression, adjustedTimestamp);
} else if (appliedByUnit != null) {
// we're applying the 'by unit' operator,
// producing a literal scalar value, so
// we must convert this duration from
// nanoseconds to the given unit
JdbcMappingContainer durationType = scaledExpression.getExpressionType();
Duration duration;
if (durationType.getJdbcMappings().get(0).getJdbcType().isInterval()) {
// For interval types, we need to extract the epoch for integer arithmetic for the 'by unit' operator
duration = new Duration(extractEpoch(scaledExpression), SECOND, (BasicValuedMapping) durationType);
} else {
// The absolute value of the expression is in seconds
// as the fractional seconds are in the fraction part as can be seen in DurationJavaType
duration = new Duration(scaledExpression, SECOND, (BasicValuedMapping) durationType);
}
TemporalUnit appliedUnit = appliedByUnit.getUnit().getUnit();
BasicValuedMapping scalarType = (BasicValuedMapping) appliedByUnit.getNodeType();
result = new Conversion(duration, appliedUnit, scalarType);
} else {
// a "bare" Duration value in nanoseconds
result = scaledExpression;
}
}
return withTreatRestriction(result, sqmPath);
}
use of org.hibernate.query.sqm.TemporalUnit in project hibernate-orm by hibernate.
the class ExtractFunction method generateSqmFunctionExpression.
@Override
protected <T> SelfRenderingSqmFunction generateSqmFunctionExpression(List<? extends SqmTypedNode<?>> arguments, ReturnableType<T> impliedResultType, QueryEngine queryEngine, TypeConfiguration typeConfiguration) {
SqmExtractUnit<?> field = (SqmExtractUnit<?>) arguments.get(0);
SqmExpression<?> expression = (SqmExpression<?>) arguments.get(1);
TemporalUnit unit = field.getUnit();
switch(unit) {
case NANOSECOND:
return extractNanoseconds(expression, queryEngine, typeConfiguration);
case NATIVE:
throw new SemanticException("can't extract() the field TemporalUnit.NATIVE");
case OFFSET:
// use format(arg, 'xxx') to get the offset
return extractOffsetUsingFormat(expression, queryEngine, typeConfiguration);
case DATE:
case TIME:
// on the type of the expression we're extracting from
return extractDateOrTimeUsingCast(expression, field.getType(), queryEngine, typeConfiguration);
case WEEK_OF_MONTH:
// use ceiling(extract(day of month, arg)/7.0)
return extractWeek(expression, field, DAY_OF_MONTH, queryEngine, typeConfiguration);
case WEEK_OF_YEAR:
// use ceiling(extract(day of year, arg)/7.0)
return extractWeek(expression, field, DAY_OF_YEAR, queryEngine, typeConfiguration);
default:
// otherwise it's something we expect the SQL dialect
// itself to understand, either natively, or via the
// method Dialect.extract()
String pattern = dialect.extractPattern(unit);
return queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder("extract", pattern).setExactArgumentCount(2).setReturnTypeResolver(useArgType(1)).descriptor().generateSqmExpression(arguments, impliedResultType, queryEngine, typeConfiguration);
}
}
use of org.hibernate.query.sqm.TemporalUnit in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitToDuration.
@Override
public Object visitToDuration(SqmToDuration<?> toDuration) {
// TODO: do we need to temporarily set appliedByUnit
// to null before we recurse down the tree?
// and what about scale?
Expression magnitude = toSqlExpression(toDuration.getMagnitude().accept(this));
DurationUnit unit = (DurationUnit) toDuration.getUnit().accept(this);
// let's start by applying the propagated scale
// so we don't forget to do it in what follows
Expression scaledMagnitude = applyScale(magnitude);
if (adjustedTimestamp != null) {
// adjusted date or timestamp
if (appliedByUnit != null) {
throw new IllegalStateException();
}
return timestampadd().expression(// TODO should be adjustedTimestamp.getType()
(ReturnableType<?>) adjustedTimestampType, unit, scaledMagnitude, adjustedTimestamp);
} else {
BasicValuedMapping durationType = (BasicValuedMapping) toDuration.getNodeType();
Duration duration;
if (scaledMagnitude.getExpressionType().getJdbcMappings().get(0).getJdbcType().isInterval()) {
duration = new Duration(extractEpoch(scaledMagnitude), SECOND, durationType);
} else {
duration = new Duration(scaledMagnitude, unit.getUnit(), durationType);
}
if (appliedByUnit != null) {
// we're applying the 'by unit' operator,
// producing a literal scalar value in
// the given unit
TemporalUnit appliedUnit = appliedByUnit.getUnit().getUnit();
BasicValuedMapping scalarType = (BasicValuedMapping) appliedByUnit.getNodeType();
return new Conversion(duration, appliedUnit, scalarType);
} else {
// a "bare" Duration value (gets rendered as nanoseconds)
return duration;
}
}
}
use of org.hibernate.query.sqm.TemporalUnit in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method transformDatetimeArithmetic.
private Object transformDatetimeArithmetic(SqmBinaryArithmetic<?> expression) {
BinaryArithmeticOperator operator = expression.getOperator();
// timestamps are ill-formed
if (operator != SUBTRACT) {
throw new SemanticException("illegal operator for temporal type: " + operator);
}
// a difference between two dates or two
// timestamps is a leaf duration, so we
// must apply the scale, and the 'by unit'
// ts1 - ts2
Expression left = cleanly(() -> toSqlExpression(expression.getLeftHandOperand().accept(this)));
Expression right = cleanly(() -> toSqlExpression(expression.getRightHandOperand().accept(this)));
TypeConfiguration typeConfiguration = getCreationContext().getMappingMetamodel().getTypeConfiguration();
TemporalType leftTimestamp = typeConfiguration.getSqlTemporalType(expression.getLeftHandOperand().getNodeType());
TemporalType rightTimestamp = typeConfiguration.getSqlTemporalType(expression.getRightHandOperand().getNodeType());
// when we're dealing with Dates, we use
// DAY as the smallest unit, otherwise we
// use a platform-specific granularity
TemporalUnit baseUnit = (rightTimestamp == TemporalType.TIMESTAMP || leftTimestamp == TemporalType.TIMESTAMP) ? NATIVE : DAY;
if (adjustedTimestamp != null) {
if (appliedByUnit != null) {
throw new IllegalStateException();
}
// we're using the resulting duration to
// adjust a date or timestamp on the left
// baseUnit is the finest resolution for the
// temporal type, so we must use it for both
// the diff, and then the subsequent add
DurationUnit unit = new DurationUnit(baseUnit, basicType(Integer.class));
Expression magnitude = applyScale(timestampdiff().expression(null, unit, right, left));
return timestampadd().expression(// TODO should be adjustedTimestamp.getType()
(ReturnableType<?>) adjustedTimestampType, unit, magnitude, adjustedTimestamp);
} else if (appliedByUnit != null) {
// we're immediately converting the resulting
// duration to a scalar in the given unit
DurationUnit unit = (DurationUnit) appliedByUnit.getUnit().accept(this);
return applyScale(timestampdiff().expression(null, unit, right, left));
} else {
// a plain "bare" Duration
DurationUnit unit = new DurationUnit(baseUnit, basicType(Integer.class));
BasicValuedMapping durationType = (BasicValuedMapping) expression.getNodeType();
Expression scaledMagnitude = applyScale(timestampdiff().expression((ReturnableType<?>) expression.getNodeType(), unit, right, left));
return new Duration(scaledMagnitude, baseUnit, durationType);
}
}
Aggregations