Class DuckDBSqlExpressionConvertVisitor
- Namespace
- LinqToDB.Internal.DataProvider.DuckDB
- Assembly
- linq2db.dll
public class DuckDBSqlExpressionConvertVisitor : SqlExpressionConvertVisitor
- Inheritance
-
objectDuckDBSqlExpressionConvertVisitor
- Inherited Members
- Extension Methods
Constructors
DuckDBSqlExpressionConvertVisitor(bool)
public DuckDBSqlExpressionConvertVisitor(bool allowModify)
Parameters
allowModifybool
Properties
CanLowerIntervalDifference
Whether an elapsed date difference can be lowered to a value here.
public override bool CanLowerIntervalDifference { get; }
Property Value
Remarks
Declared beside the lowering it describes, and read by the member translator through
ITranslationContext.ProviderFlags. The translator has to ask before it builds anything, because
a difference it does not build stays an ordinary .NET subtraction and is computed on materialisation -
and by the time this visitor runs, the read expression is already bound to its columns, so there is no
going back.
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.
CanWrapWindowOrderByConstant
DuckDB takes a scalar subquery as a window sort key in general, but not inside a RANGE frame -
there it fails with Serialization Error: Cannot copy BoundSubqueryExpression. It runs
ORDER BY 1 RANGE BETWEEN 1 PRECEDING AND 2 FOLLOWING happily, so the caller's own key is kept.
protected override bool CanWrapWindowOrderByConstant { get; }
Property Value
Remarks
Keeping it is safe because DuckDB reads the integer as a constant expression rather than an output
column position, unlike MySQL 8: ORDER BY 99 is accepted with only four columns in play, and a
RANGE frame over ORDER BY 1 covers the whole partition instead of ordering by the first
column. So the key ties every row exactly as the dropped constant did.
ConcatRequiresExplicitStringCast
When true (default), ConvertConcat(SqlConcatExpression) wraps every non-string
operand in an explicit CAST(... AS VARCHAR(N)) before adding it to the concat chain.
Required for providers whose concat operator is + (SQL Server pre-2025, SqlCe,
Access) — SQL-standard data-type precedence would otherwise try to coerce
string operands to the non-string side's type. Most providers whose final concat operator
is || (PostgreSQL / Oracle / SQLite / SAP HANA / DuckDB / Firebird / DB2 / Informix /
SQL Server 2025+) or CONCAT(...) function (MySQL / ClickHouse) auto-coerce
non-string operands and override this to false for cleaner SQL.
Sybase ASE is the exception: it emits || but keeps this true,
since ASE requires an explicit convert() for non-character operands under both
+ and ||.
protected override bool ConcatRequiresExplicitStringCast { get; }
Property Value
SupportsNullInColumn
protected override bool SupportsNullInColumn { get; }
Property Value
Methods
ConvertConversion(SqlCastExpression)
Implements SqlCastExpression conversion.
protected override ISqlExpression ConvertConversion(SqlCastExpression cast)
Parameters
castSqlCastExpression
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
ElapsedTicks(SqlIntervalDifferenceExpression)
Elapsed ticks from date_diff at microsecond resolution.
protected override ISqlExpression? ElapsedTicks(SqlIntervalDifferenceExpression element)
Parameters
elementSqlIntervalDifferenceExpression
Returns
Remarks
A DuckDB timestamp holds microseconds, so the count is exact and scaling it to ticks - ten of them to
the microsecond - loses nothing. Taken through the count rather than DuckDB's own INTERVAL,
because an interval carries months and days alongside the microseconds and only the count is a single
number.
LowerTemporalArithmetic(SqlTemporalArithmeticExpression)
Shifts by an interval built from the microsecond count, which is what DuckDB stores.
protected override ISqlExpression? LowerTemporalArithmetic(SqlTemporalArithmeticExpression element)
Parameters
elementSqlTemporalArithmeticExpression
Returns
TruncateDivide(ISqlExpression, long)
//, DuckDB's integer division - its / produces a double even between two integers.
protected override ISqlExpression TruncateDivide(ISqlExpression value, long divisor)
Parameters
valueISqlExpressiondivisorlong