Class IntervalLowering
- Namespace
- LinqToDB.Internal.SqlProvider
- Assembly
- linq2db.dll
Default lowering of interval nodes onto integral storage: the strategy used when a provider has no native interval type, or has one but the column is not mapped to it.
public static class IntervalLowering
- Inheritance
-
objectIntervalLowering
Remarks
This is one strategy among several - native INTERVAL, TIME, OLE Automation dates - so it lives
apart from the visitor that selects it. Every method returns null when the result cannot be
produced exactly, which leaves the node untranslated rather than approximated.
Truncating division is taken as a parameter rather than emitted here, because the SQL for it varies by
provider - see SqlExpressionConvertVisitor.TruncateDivide.
Methods
ElapsedTotal(ISqlExpressionFactory, SqlIntervalDifferenceExpression, SqlIntervalUnit, SqlIntervalUnit?, Func<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression?>, Func<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression?>)
The whole interval expressed in unit, fraction included - TotalHours and
friends.
public static ISqlExpression? ElapsedTotal(ISqlExpressionFactory factory, SqlIntervalDifferenceExpression difference, SqlIntervalUnit unit, SqlIntervalUnit? finestUnit, Func<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression?> countBoundaries, Func<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression?> shiftDate)
Parameters
factoryISqlExpressionFactorydifferenceSqlIntervalDifferenceExpressionunitSqlIntervalUnitfinestUnitSqlIntervalUnit?countBoundariesFunc<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression>shiftDateFunc<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression>
Returns
Remarks
Built as whole units plus the leftover, never as one division of a tick count: a century in ticks exceeds long, so the undivided form is not representable at all. The leftover is measured between the anchor and the end, a window shorter than one unit, so the fine count is always small.
The raw boundary count, uncorrected, for the reason the elapsed tick count gives: the leftover is measured from wherever the anchor landed, so a count that overshot by one unit comes back as a leftover of the same size pointing the other way, and the two telescope. Correcting it first would change nothing about the answer and would put the correction - three comparisons and two arithmetic terms - into the expression twice over, once as the whole part and once inside the anchor.
A component is the other case and does need the correction, because there the whole number is the answer and nothing follows it to make up the difference.
ElapsedUnits(ISqlExpressionFactory, SqlIntervalDifferenceExpression, SqlIntervalUnit, Func<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression?>, Func<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression?>)
Elapsed whole units between two date/time values, reproducing _ticks / TicksPerUnit without ever
materialising the tick count.
public static ISqlExpression? ElapsedUnits(ISqlExpressionFactory factory, SqlIntervalDifferenceExpression difference, SqlIntervalUnit unit, Func<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression?> countBoundaries, Func<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression?> shiftDate)
Parameters
factoryISqlExpressionFactoryExpression factory.
differenceSqlIntervalDifferenceExpressionThe difference whose elapsed units are wanted.
unitSqlIntervalUnitUnit to count in.
countBoundariesFunc<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression>Provider's
DATEDIFF- boundary counting.shiftDateFunc<SqlIntervalUnit, ISqlExpression, ISqlExpression, ISqlExpression>Provider's
DATEADD- must be exact.
Returns
Remarks
The provider's own difference counts crossed boundaries, so 10:59:30 to 11:01:00 reports two minutes where only one and a half elapsed. Shifting the start by that count and comparing against the end says whether it overshot, and the correction is at most one unit either way.
Counting whole units cannot overflow the way a fine-grained difference over the same range does - that
limit is what caps DATEDIFF(millisecond, ...) at about 24 days.
FromTicks(ISqlExpressionFactory, ISqlExpression, SqlIntervalPartExpression, Func<ISqlExpression, long, ISqlExpression>, Func<ISqlExpression, long, ISqlExpression>)
The same member arithmetic as LowerPart(ISqlExpressionFactory, SqlIntervalPartExpression, Func<ISqlExpression, long, ISqlExpression>, Func<ISqlExpression, long, ISqlExpression>), over a tick count the caller already has.
public static ISqlExpression? FromTicks(ISqlExpressionFactory factory, ISqlExpression ticks, SqlIntervalPartExpression element, Func<ISqlExpression, long, ISqlExpression> truncateDivide, Func<ISqlExpression, long, ISqlExpression> truncateRemainder)
Parameters
factoryISqlExpressionFactoryticksISqlExpressionelementSqlIntervalPartExpressiontruncateDivideFunc<ISqlExpression, long, ISqlExpression>truncateRemainderFunc<ISqlExpression, long, ISqlExpression>
Returns
Remarks
Where a provider can produce elapsed ticks directly, this answers every member from that one value, which is both shorter and closer to what .NET does than counting each unit separately. It is the second choice all the same: counting cannot overflow, and a fine-grained difference over a long range can.
LowerPart(ISqlExpressionFactory, SqlIntervalPartExpression, Func<ISqlExpression, long, ISqlExpression>, Func<ISqlExpression, long, ISqlExpression>)
Lowers a component or total of an interval into ordinary arithmetic.
public static ISqlExpression? LowerPart(ISqlExpressionFactory factory, SqlIntervalPartExpression element, Func<ISqlExpression, long, ISqlExpression> truncateDivide, Func<ISqlExpression, long, ISqlExpression> truncateRemainder)
Parameters
factoryISqlExpressionFactoryExpression factory.
elementSqlIntervalPartExpressionPart to lower.
truncateDivideFunc<ISqlExpression, long, ISqlExpression>Integer division truncating toward zero, as the provider spells it.
truncateRemainderFunc<ISqlExpression, long, ISqlExpression>Remainder of that same division.
Returns
ToTicks(ISqlExpressionFactory, SqlIntervalExpression)
Converts an interval's stored amount to ticks, exactly.
public static ISqlExpression? ToTicks(ISqlExpressionFactory factory, SqlIntervalExpression interval)
Parameters
factoryISqlExpressionFactoryintervalSqlIntervalExpression
Returns
WrapComponent(ISqlExpressionFactory, ISqlExpression, SqlIntervalUnit, SqlIntervalUnit?, Func<ISqlExpression, long, ISqlExpression>)
Wraps a whole-unit count into its CLR component, mirroring TimeSpan term for term:
Hours is (_ticks / TicksPerHour) % 24, and this is the % 24.
public static ISqlExpression WrapComponent(ISqlExpressionFactory factory, ISqlExpression wholeUnits, SqlIntervalUnit unit, SqlIntervalUnit? within, Func<ISqlExpression, long, ISqlExpression> truncateRemainder)
Parameters
factoryISqlExpressionFactorywholeUnitsISqlExpressionunitSqlIntervalUnitwithinSqlIntervalUnit?truncateRemainderFunc<ISqlExpression, long, ISqlExpression>
Returns
Remarks
Days does not wrap - a duration may legitimately exceed a year, and .NET applies no modulo to it.