Class AccessSqlExpressionConvertVisitor
- Namespace
- LinqToDB.Internal.DataProvider.Access
- Assembly
- linq2db.dll
public class AccessSqlExpressionConvertVisitor : SqlExpressionConvertVisitor
- Inheritance
-
objectAccessSqlExpressionConvertVisitor
- Inherited Members
- Extension Methods
Constructors
AccessSqlExpressionConvertVisitor(bool)
public AccessSqlExpressionConvertVisitor(bool allowModify)
Parameters
allowModifybool
Properties
CanLowerIntervalPart
Whether a member of an elapsed date difference can be lowered. Defaults to whatever the difference itself can do.
public override bool CanLowerIntervalPart { get; }
Property Value
Remarks
Separate because one provider has only this half: Access counts elapsed units well enough to answer
TotalHours, but its DateDiff is a 32-bit count that overflows once scaled to ticks, so
the interval never becomes a value there.
CanLowerIntervalShift
Whether LowerTemporalArithmetic(SqlTemporalArithmeticExpression) can express a date shifted by an interval at all.
public override bool CanLowerIntervalShift { get; }
Property Value
Remarks
Read by the member translator so a declared duration added to a date is declined while the expression is still being built, rather than reaching the builder as a node nothing can render - a refusal there has no client-side fallback left. The default follows what the base implementation needs: it spends the amount through ShiftDate(SqlIntervalUnit, ISqlExpression, ISqlExpression) at FinestDateUnit, so a provider that names no finest unit cannot lower one.
Only the declared half is declined early. A shift by a computed difference is left to be built,
because start + (end - start) cancels against the difference it came from and asks the provider
for nothing - refusing it here would sink a query that works everywhere.
CanMeasureDifferenceInTicks
And no tick count either, for the reason ElapsedTicks(SqlIntervalDifferenceExpression) gives, which is what leaves a total below the resolution with nowhere to come from rather than merely quantised.
public override bool CanMeasureDifferenceInTicks { get; }
Property Value
ElapsedTicksResolveMembers
Access counts seconds, and an OLE Automation date holds fractions of one, so a tick count derived from it is only good to the second - which is why the members are counted instead.
protected override bool ElapsedTicksResolveMembers { get; }
Property Value
FinestDateUnit
A second is as fine as Access counts - DateDiff has no millisecond part at all.
protected override SqlIntervalUnit? FinestDateUnit { get; }
Property Value
Remarks
The whole-unit members are still exact, because the anchor correction compares actual dates rather than
trusting the count. What this limits is the fraction of a Total and anything below a second,
which an OLE Automation date - a floating day number - could not carry reliably anyway.
IntervalResolution
A second is also as fine as the measurement resolves, so a component asked for below one is identically zero rather than merely imprecise.
public override SqlIntervalUnit IntervalResolution { get; }
Property Value
Remarks
Access refuses such a member either way - there is no millisecond date part to extract and no tick count to divide - but where it refuses decides what a caller can do about it. Declined here, while the expression is still being built, the message names the unit and the resolution, and a projection stays free to fall back to .NET, which holds both dates and answers exactly. Left to the builder, the refusal arrives as an exception with no such escape.
LikeCharactersToEscape
Characters with special meaning in LIKE predicate (defined by LikeCharactersToEscape) that should be escaped to be used as matched character.
Default: ["%", "_", "?", "*", "#", "[", "]"].
public override string[] LikeCharactersToEscape { get; }
Property Value
- string[]
LikeIsEscapeSupported
public override bool LikeIsEscapeSupported { get; }
Property Value
SupportsNullIf
protected override bool SupportsNullIf { get; }
Property Value
Methods
ConvertCoalesce(SqlCoalesceExpression)
public override ISqlExpression ConvertCoalesce(SqlCoalesceExpression element)
Parameters
elementSqlCoalesceExpression
Returns
ConvertConversion(SqlCastExpression)
Implements SqlCastExpression conversion.
protected override ISqlExpression ConvertConversion(SqlCastExpression cast)
Parameters
castSqlCastExpression
Returns
ConvertLikePredicate(Like)
public override ISqlPredicate ConvertLikePredicate(SqlPredicate.Like predicate)
Parameters
predicateSqlPredicate.Like
Returns
ConvertSearchStringPredicate(SearchString)
public override ISqlPredicate ConvertSearchStringPredicate(SqlPredicate.SearchString predicate)
Parameters
predicateSqlPredicate.SearchString
Returns
ConvertSqlBinaryExpression(SqlBinaryExpression)
public override IQueryElement ConvertSqlBinaryExpression(SqlBinaryExpression element)
Parameters
elementSqlBinaryExpression
Returns
ConvertSqlFunction(SqlFunction)
public override ISqlExpression ConvertSqlFunction(SqlFunction func)
Parameters
funcSqlFunction
Returns
ConvertSqlUnaryExpression(SqlUnaryExpression)
public override ISqlExpression ConvertSqlUnaryExpression(SqlUnaryExpression element)
Parameters
elementSqlUnaryExpression
Returns
CountDateBoundaries(SqlIntervalUnit, ISqlExpression, ISqlExpression)
Boundary counting through DateDiff, whose count is a 32-bit value - so a count in seconds is taken
across the sub-day remainder rather than across the whole span.
protected override ISqlExpression? CountDateBoundaries(SqlIntervalUnit unit, ISqlExpression start, ISqlExpression end)
Parameters
unitSqlIntervalUnitstartISqlExpressionendISqlExpression
Returns
Remarks
A second count reaches the 32-bit limit after about sixty-eight years, which is inside the range a person's
age can reach. Past it Access answers Numeric value out of range instead of a number, and it does so
before any cast here can widen the result - the overflow happens while Access computes the count. Counting
days first and seconds only from there keeps both counts small: days stay 32-bit for any date Access can
hold, and the remainder spans at most a day. Every coarser datepart is counted directly, being far from the
limit - minutes reach it only after four thousand years.
The two counts telescope, so the split is exact rather than an approximation. DateDiff truncates both
operands to the unit and subtracts, which makes it additive through any intermediate point, and shifting by
whole days leaves the time of day alone - so the day count contributes exactly its own seconds. That holds
even when the day count overshoots the end, as it does between an evening and the following morning: the
remainder comes back negative by the same amount.
CDbl is what keeps the product from overflowing in turn - Access multiplies in 32-bit integers and a
century of days is past that once scaled to seconds. A cast to a wider integer would not do: Access has none
to name, and a cast to a floating type renders as nothing here.
This provider is the only one that gets here - it is the only override of ElapsedTicksResolveMembers to false, and everywhere else a member is taken from the tick count instead.
ElapsedTicks(SqlIntervalDifferenceExpression)
No tick count from Access at all.
protected override ISqlExpression? ElapsedTicks(SqlIntervalDifferenceExpression element)
Parameters
elementSqlIntervalDifferenceExpression
Returns
Remarks
DateDiff hands back a 32-bit count, and scaling seconds to ticks overflows it after about three
and a half minutes - the driver answers Numeric value out of range. There is no wider integer to
reach for, so the interval never becomes a value here and its member translator says so.
EscapeLikeCharacters(ISqlExpression, ref ISqlExpression?)
public override ISqlExpression EscapeLikeCharacters(ISqlExpression expression, ref ISqlExpression? escape)
Parameters
expressionISqlExpressionescapeISqlExpression
Returns
EscapeLikePattern(string)
Implements LIKE pattern escaping logic for provider without ESCAPE clause support (LikeIsEscapeSupported is false). Default logic prefix characters from LikeCharactersToEscape with LikeEscapeCharacter.
protected override string EscapeLikePattern(string str)
Parameters
strstringRaw pattern value.
Returns
- string
Escaped pattern value.
LowerIntervalPart(SqlIntervalPartExpression)
Forms a component of an elapsed difference over the last day of it rather than over the whole span.
protected override ISqlExpression? LowerIntervalPart(SqlIntervalPartExpression element)
Parameters
elementSqlIntervalPartExpression
Returns
Remarks
Everything this provider counts with is 32-bit, and a component asks for all three of it: the count, the
amount the correction's anchor is shifted by, and MOD, which coerces both operands before dividing.
A second count crosses that range after about sixty-eight years - inside a human lifetime - and the last
of the three takes the elapsed count whole, so no split made inside the component can help.
Made outside it instead. A component wraps at a divisor of a day - twenty-four hours, sixty minutes, sixty seconds - so whole days contribute nothing to it, and the same answer comes from the part of the span that is left after them. That part is under a day, which every count and every shift here holds comfortably.
The day count has to be the elapsed one rather than the boundary one, which is the whole reason this is
not simply DateDiff. A boundary count overshoots between an evening and the following morning, and
an anchor past the end turns the remainder negative - a sign the modulo keeps, answering -20 where 40 was
meant.
LowerTemporalArithmetic(SqlTemporalArithmeticExpression)
No shift by an interval either, for the reason ElapsedTicks(SqlIntervalDifferenceExpression) gives.
protected override ISqlExpression? LowerTemporalArithmetic(SqlTemporalArithmeticExpression element)
Parameters
elementSqlTemporalArithmeticExpression
Returns
Remarks
The amount reaches a shift as a tick count whatever it was built from, and that is the one number Access
cannot hold - scaling to ticks overflows its arithmetic and the driver answers Numeric value out of
range. Refusing by name is the whole of the difference between this and a date that comes back wrong.
Access shifts dates perfectly well in seconds; what it cannot do is take delivery of the amount in ticks. Should a coarser hand-off ever exist, this is the override to drop.
ShiftDate(SqlIntervalUnit, ISqlExpression, ISqlExpression)
Shifts a date/time value by a whole number of units - the provider's DATEADD.
protected override ISqlExpression? ShiftDate(SqlIntervalUnit unit, ISqlExpression amount, ISqlExpression date)
Parameters
unitSqlIntervalUnitamountISqlExpressiondateISqlExpression
Returns
Remarks
Must be exact: the anchor correction in IntervalLowering shifts by a computed count and compares the result against the original, so an approximate shift would produce an off-by-one count.
TruncateDivide(ISqlExpression, long)
Access has no FLOOR or CEILING, but its Fix is exactly truncation toward zero -
the semantic the base composes those two functions to reach.
protected override ISqlExpression TruncateDivide(ISqlExpression value, long divisor)
Parameters
valueISqlExpressiondivisorlong
Returns
Remarks
Int would be wrong here: it rounds down, so Int(-2.5) is -3 where CLR integer division
gives -2. Access division is floating, so no cast is needed before Fix.