Table of Contents

Class StringMemberTranslatorBase

Namespace
LinqToDB.Internal.DataProvider.Translation
Assembly
linq2db.dll
public class StringMemberTranslatorBase : MemberTranslatorBase, IMemberTranslator
Inheritance
object
StringMemberTranslatorBase
Implements
Derived
Inherited Members
Extension Methods

Constructors

StringMemberTranslatorBase()

public StringMemberTranslatorBase()

Fields

ASCII_WHITESPACES

protected const string ASCII_WHITESPACES = "\t\n\v\f\r \u0085 "

Field Value

string

WHITESPACES

protected const string WHITESPACES = "\t\n\v\f\r \u0085             \u2028\u2029   "

Field Value

string

WHITESPACES_REGEX

protected const string WHITESPACES_REGEX = "\t|\n|\v|\f|\r| |\u0085| | | | | | | | | | | | | |\u2028|\u2029| | | "

Field Value

string

Methods

BuildAggregateNullsOrderBy(ISqlExpressionFactory, IReadOnlyList<(ISqlExpression expr, bool desc, NullsPosition nulls)>, bool, NullsDefaultOrdering)

Builds the ORDER BY … suffix fragment for an aggregate (e.g. STRING_AGG) that renders native NULLS FIRST/NULLS LAST. The NULLS token is omitted when the aggregate is null-filtered, or when the requested position already equals the provider's natural null ordering (naturalOrdering) for the item's direction — the provider default then yields the same placement. An unspecified position (None) is pinned to FIRST for cross-provider / in-memory consistency. Returns null when there is no ordering. Shared by the PostgreSQL / SAP HANA / DuckDB translators.

protected static ISqlExpression? BuildAggregateNullsOrderBy(ISqlExpressionFactory factory, IReadOnlyList<(ISqlExpression expr, bool desc, Sql.NullsPosition nulls)> orderBy, bool isNullFiltered, NullsDefaultOrdering naturalOrdering)

Parameters

factory ISqlExpressionFactory
orderBy IReadOnlyList<(ISqlExpression expr, bool desc, Sql.NullsPosition nulls)>
isNullFiltered bool
naturalOrdering NullsDefaultOrdering

Returns

ISqlExpression

ConfigureConcat(AggregateFunctionBuilder, bool)

Configures the aggregate-function builder to emit a plain SqlConcatExpression with preserveNull: true. Bypasses the CONCAT_WS aggregate path; the chain lowers to plain SQL || / + on every provider.

protected void ConfigureConcat(AggregateFunctionBuilder builder, bool wrapByCoalesce = false)

Parameters

builder AggregateFunctionBuilder

Aggregate-function builder being configured.

wrapByCoalesce bool

When true, each value is wrapped in Coalesce(v, '') before the concat — matches string.Concat null-as-empty semantics with non-null result. Used by string.Concat(items) on emulation providers (except Oracle, where Coalesce(v, '') is a no-op due to the empty-string-is-NULL identity). When false (default), values pass through unchanged — the strict any-null-→-null semantic for Sql.Concat; nullability is conserved (any operand nullable → result nullable).

ConfigureConcatWs(AggregateFunctionBuilder, bool, bool, Func<ISqlExpressionFactory, DbDataType, ISqlExpression, ISqlExpression[], ISqlExpression>?, bool)

Configures the aggregate-function builder for providers with native CONCAT_WS (or an equivalent multi-argument string aggregate). Used by ClickHouse, MySQL, PostgreSQL, SqlServer 2017+, YDB; see ConfigureConcatWsEmulation(AggregateFunctionBuilder, bool, bool, Func<ISqlExpressionFactory, DbDataType, ISqlExpression, ISqlExpression, ISqlExpression>, bool, bool) for providers that emulate CONCAT_WS via SUBSTRING tricks. Used by string.Concat / string.Join / Sql.ConcatStrings / Sql.ConcatStringsNullable; Sql.Concat bypasses this path and goes through ConfigureConcat(AggregateFunctionBuilder, bool) instead (any-null-→-null semantic via plain SqlConcatExpression).

protected void ConfigureConcatWs(AggregateFunctionBuilder builder, bool nullValuesAsEmptyString, bool isNullableResult, Func<ISqlExpressionFactory, DbDataType, ISqlExpression, ISqlExpression[], ISqlExpression>? functionFactory = null, bool withoutSeparator = false)

Parameters

builder AggregateFunctionBuilder

Aggregate-function builder being configured.

nullValuesAsEmptyString bool

When true, individual NULL values are wrapped in COALESCE(v, '') before the join — used by string.Concat / string.Join / Sql.ConcatStrings to give C# null-as-empty semantics. When false, NULLs are preserved per isNullableResult.

isNullableResult bool

When true, the result can be NULL only when ALL inputs are NULL (Sql.ConcatStringsNullable semantic — emitted as CASE WHEN (v1 IS NULL AND v2 IS NULL …) THEN NULL ELSE CONCAT_WS(...) END). When false, the result is always non-null (NULL inputs are coalesced to empty by nullValuesAsEmptyString or by an outer wrap).

functionFactory Func<ISqlExpressionFactory, DbDataType, ISqlExpression, ISqlExpression[], ISqlExpression>

Optional override of the SQL function emission (e.g. ClickHouse uses arrayStringConcat instead of CONCAT_WS). Receives (factory, valueType, separator, items); when null, plain CONCAT_WS(separator, ...items) is emitted.

withoutSeparator bool

When true, no separator argument is consumed (string.Concat). When false, the first argument is the separator (string.Join / Sql.ConcatStrings).

ConfigureConcatWsEmulation(AggregateFunctionBuilder, bool, bool, Func<ISqlExpressionFactory, DbDataType, ISqlExpression, ISqlExpression, ISqlExpression>, bool, bool)

Configures the aggregate-function builder for providers without native CONCAT_WS; the emulation chains values via SQL || / + and strips the leading separator with a SUBSTRING call. Used by Access, DB2, Firebird, Informix, Oracle, SapHana, SQLite, SqlCe, Sybase, SqlServer (older). Used by string.Concat / string.Join / Sql.ConcatStrings / Sql.ConcatStringsNullable; Sql.Concat bypasses this path and goes through ConfigureConcat(AggregateFunctionBuilder, bool) instead. See ConfigureConcatWs(AggregateFunctionBuilder, bool, bool, Func<ISqlExpressionFactory, DbDataType, ISqlExpression, ISqlExpression[], ISqlExpression>?, bool) for the native path.

protected void ConfigureConcatWsEmulation(AggregateFunctionBuilder builder, bool nullValuesAsEmptyString, bool isNullResult, Func<ISqlExpressionFactory, DbDataType, ISqlExpression, ISqlExpression, ISqlExpression> substringFunc, bool withoutSeparator = false, bool wrapByCoalesce = true)

Parameters

builder AggregateFunctionBuilder

Aggregate-function builder being configured.

nullValuesAsEmptyString bool

When true, individual NULL values are wrapped in COALESCE(v, '') before the chain — used by string.Concat / string.Join / Sql.ConcatStrings. When false, NULLs flow through SQL || / + directly; on standards-compliant providers this propagates NULL.

isNullResult bool

When true, the result can be NULL; no outer COALESCE(..., '') is added. When false, the chain is wrapped in a final COALESCE(..., '').

substringFunc Func<ISqlExpressionFactory, DbDataType, ISqlExpression, ISqlExpression, ISqlExpression>

Builds the SUBSTRING(chain, len(separator) + 1) call to strip the leading separator. Provider-specific because the substring function name and offset arity vary (SUBSTR, SUBSTRING, STUFF, etc.).

withoutSeparator bool

When true, no separator argument is consumed and no SUBSTRING strip is needed (string.Concat). When false, the first argument is the separator (string.Join / Sql.ConcatStrings).

wrapByCoalesce bool

Controls the per-operand NULL-skip strategy for the WITH separator path. When true (default), each per-value contribution is wrapped in Coalesce(sep || v, '') — relies on NULL || x = NULL to convert a NULL operand to an empty contribution. Correct on standards-compliant providers (SQLite, SqlServer, Sybase, SqlCe, Informix, Firebird, DB2, SapHana). When false, each per-value contribution is wrapped in CASE WHEN v IS NULL THEN '' ELSE sep || v END instead — the explicit-IS-NULL form is required on Oracle, where NULL || x = x means the Coalesce form would emit a stray separator for each NULL operand (and the empty-string-is-NULL identity makes Coalesce against '' a no-op anyway). The CASE form also sidesteps ORA-12704 character-set mismatches on mixed VARCHAR/NVARCHAR operands. Affects only the per-operand wraps in the IsNullFiltered / isNullResult / !nullValuesAsEmpty branch; the other branches keep Coalesce when true and skip it entirely when false (their NULL-skip semantics don't depend on the wrap shape).

ConvertOperandToString(Expression)

Rewrites a non-string operand to a .ToString() call so it reaches its type-specific translator (e.g. GuidMemberTranslator) instead of falling through to the default CAST AS VarChar path. No-op for string operands. Used by every concat path (binary +, fixed-arity string.Concat, Sql.Concat array, and aggregate-over-grouping string.Concat via TransformItems(Func<Expression, Expression>) / TransformValue(Func<Expression, Expression>)).

protected static Expression ConvertOperandToString(Expression operand)

Parameters

operand Expression

Returns

Expression

SetStringJoinResult(AggregateComposer, ISqlExpression, bool, DbDataType)

Sets the StringJoin aggregate result on composer. When the result is non-nullable, also registers a lift-time SQL rewriter that wraps the lifted column reference with COALESCE(<ref>, '') — so a subquery-projected non-nullable StringJoin returns the empty string rather than NULL when the OUTER APPLY produces no matching row. The bare aggregate stays in the inner SQL tree during provider validation and downstream optimization; the rewriter only fires at OUTER APPLY lift time.

protected static void SetStringJoinResult(AggregateFunctionBuilder.AggregateComposer composer, ISqlExpression aggregateSql, bool isNullableResult, DbDataType emptyValueType)

Parameters

composer AggregateFunctionBuilder.AggregateComposer
aggregateSql ISqlExpression
isNullableResult bool
emptyValueType DbDataType

TranslateIsNullOrWhiteSpace(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression)

public virtual ISqlExpression? TranslateIsNullOrWhiteSpace(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value)

Parameters

translationContext ITranslationContext
methodCall MethodCallExpression
translationFlags TranslationFlags
value ISqlExpression

Returns

ISqlExpression

TranslateLPad(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression, ISqlExpression)

public virtual ISqlExpression? TranslateLPad(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression padding, ISqlExpression paddingChar)

Parameters

translationContext ITranslationContext
methodCall MethodCallExpression
translationFlags TranslationFlags
value ISqlExpression
padding ISqlExpression
paddingChar ISqlExpression

Returns

ISqlExpression

TranslateLength(ITranslationContext, TranslationFlags, ISqlExpression)

public virtual ISqlExpression? TranslateLength(ITranslationContext translationContext, TranslationFlags translationFlags, ISqlExpression value)

Parameters

translationContext ITranslationContext
translationFlags TranslationFlags
value ISqlExpression

Returns

ISqlExpression

TranslateLike(ITranslationContext, MethodCallExpression, TranslationFlags)

protected virtual Expression? TranslateLike(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags)

Parameters

translationContext ITranslationContext
methodCall MethodCallExpression
translationFlags TranslationFlags

Returns

Expression

TranslateOverrideHandler(ITranslationContext, Expression, TranslationFlags)

Catches all string-typed binary Add / AddChecked expressions (a + b where the result type is string), regardless of operand types. C# string + obj treats null as empty string while SQL || propagates NULL — for each operand we rewrite non-string operands to .ToString() calls (so ordinary translation produces a string-typed SQL expression / CAST), translate to SQL, and wrap each side with COALESCE(..., '').

protected override Expression? TranslateOverrideHandler(ITranslationContext translationContext, Expression memberExpression, TranslationFlags translationFlags)

Parameters

translationContext ITranslationContext
memberExpression Expression
translationFlags TranslationFlags

Returns

Expression

TranslatePadLeft(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression, ISqlExpression?)

public virtual ISqlExpression? TranslatePadLeft(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression padding, ISqlExpression? paddingChar)

Parameters

translationContext ITranslationContext
methodCall MethodCallExpression
translationFlags TranslationFlags
value ISqlExpression
padding ISqlExpression
paddingChar ISqlExpression

Returns

ISqlExpression

TranslateReplace(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression, ISqlExpression)

public virtual ISqlExpression? TranslateReplace(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression oldValue, ISqlExpression newValue)

Parameters

translationContext ITranslationContext
methodCall MethodCallExpression
translationFlags TranslationFlags
value ISqlExpression
oldValue ISqlExpression
newValue ISqlExpression

Returns

ISqlExpression

TranslateStringFormat(ITranslationContext, MethodCallExpression, string, IReadOnlyList<ISqlExpression>, TranslationFlags)

public virtual ISqlExpression? TranslateStringFormat(ITranslationContext translationContext, MethodCallExpression methodCall, string format, IReadOnlyList<ISqlExpression> arguments, TranslationFlags translationFlags)

Parameters

translationContext ITranslationContext
methodCall MethodCallExpression
format string
arguments IReadOnlyList<ISqlExpression>
translationFlags TranslationFlags

Returns

ISqlExpression

TranslateStringJoin(ITranslationContext, MethodCallExpression, TranslationFlags, bool, bool, bool)

protected virtual Expression? TranslateStringJoin(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, bool nullValuesAsEmptyString, bool isNullableResult, bool withoutSeparator)

Parameters

translationContext ITranslationContext
methodCall MethodCallExpression
translationFlags TranslationFlags
nullValuesAsEmptyString bool
isNullableResult bool
withoutSeparator bool

Returns

Expression

TranslateTrimEnd(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression?)

public virtual ISqlExpression? TranslateTrimEnd(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression? trimChars)

Parameters

translationContext ITranslationContext
methodCall MethodCallExpression
translationFlags TranslationFlags
value ISqlExpression
trimChars ISqlExpression

Returns

ISqlExpression

TranslateTrimStart(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression?)

public virtual ISqlExpression? TranslateTrimStart(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression? trimChars)

Parameters

translationContext ITranslationContext
methodCall MethodCallExpression
translationFlags TranslationFlags
value ISqlExpression
trimChars ISqlExpression

Returns

ISqlExpression

WrapIsNullOrWhiteSpaceResult(ITranslationContext, ISqlExpression, ISqlPredicate)

Wraps an IsNullOrWhiteSpace-shape predicate with an IS NULL OR … branch. Per-provider TranslateIsNullOrWhiteSpace(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression) overrides build the empty-after-trim predicate in provider-specific syntax and call this helper to attach the null check. The IS NULL branch is emitted unconditionally — SQL optimizers fold it away when the value is provably non-nullable.

protected ISqlExpression WrapIsNullOrWhiteSpaceResult(ITranslationContext translationContext, ISqlExpression value, ISqlPredicate predicate)

Parameters

translationContext ITranslationContext
value ISqlExpression
predicate ISqlPredicate

Returns

ISqlExpression