Table of Contents

Class SqlServerSqlExpressionConvertVisitor

Namespace
LinqToDB.Internal.DataProvider.SqlServer
Assembly
linq2db.dll
public class SqlServerSqlExpressionConvertVisitor : SqlExpressionConvertVisitor
Inheritance
object
SqlServerSqlExpressionConvertVisitor
Derived
Inherited Members
Extension Methods

Constructors

SqlServerSqlExpressionConvertVisitor(bool, SqlServerVersion)

public SqlServerSqlExpressionConvertVisitor(bool allowModify, SqlServerVersion sqlServerVersion)

Parameters

allowModify bool
sqlServerVersion SqlServerVersion

Properties

CanLowerIntervalDifference

Every version counts elapsed time: 2016 and later through DATEDIFF_BIG, earlier ones through the 32-bit DATEDIFF over windows kept short enough for it.

public override bool CanLowerIntervalDifference { get; }

Property Value

bool

FinestDateUnit

DATEDIFF_BIG counts nanoseconds, and datetime2 stores 100ns, so the leftover of a total is exact. It is only ever applied to a sub-unit window, well inside the roughly 292 years at which the nanosecond form would overflow.

protected override SqlIntervalUnit? FinestDateUnit { get; }

Property Value

SqlIntervalUnit?

Remarks

The nanosecond datepart arrived with datetime2 in 2008 - DATEADD on 2005 answers is not a recognized dateadd option - so that version counts in milliseconds instead, which is as fine as its own datetime resolves anyway. Version-checked here rather than overridden on the 2005 visitor, because the 2008 one derives from it and would inherit the wrong answer.

IntervalResolution

On 2005 the measurement stops at the millisecond, so a component asked for below one is identically zero rather than merely imprecise - declined for the reason SQL CE and Sybase decline it.

public override SqlIntervalUnit IntervalResolution { get; }

Property Value

SqlIntervalUnit

SupportsDistinctAsExistsIntersect

protected override bool SupportsDistinctAsExistsIntersect { get; }

Property Value

bool

Methods

ConvertConcat(SqlConcatExpression)

public override ISqlExpression ConvertConcat(SqlConcatExpression element)

Parameters

element SqlConcatExpression

Returns

ISqlExpression

ConvertConversion(SqlCastExpression)

Implements SqlCastExpression conversion.

protected override ISqlExpression ConvertConversion(SqlCastExpression cast)

Parameters

cast SqlCastExpression

Returns

ISqlExpression

ConvertDefaultValue(SqlDefaultValueExpression)

Writes the default a reader substitutes for a NULL: as its value here, and as the least value of the column's type where a provider's type cannot hold it.

public override ISqlExpression ConvertDefaultValue(SqlDefaultValueExpression expression)

Parameters

expression SqlDefaultValueExpression

The default to write.

Returns

ISqlExpression

The expression the default is written as.

ConvertSearchStringPredicate(SearchString)

public override ISqlPredicate ConvertSearchStringPredicate(SqlPredicate.SearchString predicate)

Parameters

predicate SqlPredicate.SearchString

Returns

ISqlPredicate

ConvertSqlBinaryExpression(SqlBinaryExpression)

public override IQueryElement ConvertSqlBinaryExpression(SqlBinaryExpression element)

Parameters

element SqlBinaryExpression

Returns

IQueryElement

ConvertSqlFunction(SqlFunction)

public override ISqlExpression ConvertSqlFunction(SqlFunction func)

Parameters

func SqlFunction

Returns

ISqlExpression

CountDateBoundaries(SqlIntervalUnit, ISqlExpression, ISqlExpression)

Counts unit boundaries crossed between two date/time values - the provider's DATEDIFF.

protected override ISqlExpression? CountDateBoundaries(SqlIntervalUnit unit, ISqlExpression start, ISqlExpression end)

Parameters

unit SqlIntervalUnit
start ISqlExpression
end ISqlExpression

Returns

ISqlExpression

Remarks

Boundary counting, not elapsed time. It is deliberately the wrong answer on its own: it is the cheap starting estimate that the anchor correction turns into the elapsed count, and being a count of whole units it cannot overflow the way a fine-grained difference over the same range would.

ElapsedTicks(SqlIntervalDifferenceExpression)

Before 2016 the base decomposition cannot be used as it is once the finest unit is the nanosecond: it counts the remainder after whole days in that unit, and a day is 8.64e13 nanoseconds against the roughly 2.1e9 a 32-bit DATEDIFF holds. The remainder is split once more instead - whole seconds within it, then the nanoseconds within the last second, at most 1e9 - so every count stays in range and the result stays exact at the 100ns datetime2 stores.

protected override ISqlExpression? ElapsedTicks(SqlIntervalDifferenceExpression element)

Parameters

element SqlIntervalDifferenceExpression

Returns

ISqlExpression

Remarks

Each count is the raw boundary count, measured from exactly where the previous shift landed, so an overshoot at one step returns as a negative remainder at the next and the parts telescope, as in the base. That needs the second shift to be exact, which two storage types do not give: DATEADD refuses a second on a date, and rounds a smalldatetime to the minute. So the anchor is widened to datetime2 first, which holds either of them exactly - whatever the mapping declares, since that is not what the column stores: a date column mapped as a plain DateTime is typed datetime2 here.

IsWindowOrderByRequired(SqlExtendedFunction)

Every ranking function and every one that reads a neighbouring row - The function 'ROW_NUMBER' must have an OVER clause with ORDER BY - and any frame at all, which is Incorrect syntax near 'ROWS' without one. An unframed aggregate is exempt: SUM(x) OVER () is valid.

protected override bool IsWindowOrderByRequired(SqlExtendedFunction func)

Parameters

func SqlExtendedFunction

Returns

bool

LowerTemporalArithmetic(SqlTemporalArithmeticExpression)

Shifts as the base does - days, then seconds, then the rest in the finest unit - over the value widened to datetime2 first, or to datetime on 2005.

protected override ISqlExpression? LowerTemporalArithmetic(SqlTemporalArithmeticExpression element)

Parameters

element SqlTemporalArithmeticExpression

Returns

ISqlExpression

Remarks

DATEADD refuses the nanosecond the last step adds on a date, a smalldatetime and a datetime - the common type before 2008, and what GETDATE() returns - and the first two would not hold the time of day it adds anyway. The widening is applied whatever the mapping declares, for the reason ElapsedTicks(SqlIntervalDifferenceExpression) gives. 2005 has no datetime2 and counts in milliseconds, which DATEADD takes on a datetime; a smalldatetime is still widened there, since it keeps no seconds and would round the result to the minute.

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

unit SqlIntervalUnit
amount ISqlExpression
date ISqlExpression

Returns

ISqlExpression

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.

WrapColumnExpression(ISqlExpression)

protected override ISqlExpression WrapColumnExpression(ISqlExpression expr)

Parameters

expr ISqlExpression

Returns

ISqlExpression