Class StringMemberTranslatorBase
- Namespace
- LinqToDB.Internal.DataProvider.Translation
- Assembly
- linq2db.dll
public class StringMemberTranslatorBase : MemberTranslatorBase, IMemberTranslator
- Inheritance
-
objectStringMemberTranslatorBase
- 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
WHITESPACES
protected const string WHITESPACES = "\t\n\v\f\r \u0085 \u2028\u2029 "
Field Value
WHITESPACES_REGEX
protected const string WHITESPACES_REGEX = "\t|\n|\v|\f|\r| |\u0085| | | | | | | | | | | | | |\u2028|\u2029| | | "
Field Value
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
factoryISqlExpressionFactoryorderByIReadOnlyList<(ISqlExpression expr, bool desc, Sql.NullsPosition nulls)>isNullFilteredboolnaturalOrderingNullsDefaultOrdering
Returns
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
builderAggregateFunctionBuilderAggregate-function builder being configured.
wrapByCoalesceboolWhen true, each value is wrapped in
Coalesce(v, '')before the concat — matchesstring.Concatnull-as-empty semantics with non-null result. Used bystring.Concat(items)on emulation providers (except Oracle, whereCoalesce(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 forSql.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
builderAggregateFunctionBuilderAggregate-function builder being configured.
nullValuesAsEmptyStringboolWhen true, individual NULL values are wrapped in
COALESCE(v, '')before the join — used bystring.Concat/string.Join/Sql.ConcatStringsto give C# null-as-empty semantics. When false, NULLs are preserved perisNullableResult.isNullableResultboolWhen true, the result can be
NULLonly when ALL inputs areNULL(Sql.ConcatStringsNullablesemantic — emitted asCASE 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 bynullValuesAsEmptyStringor by an outer wrap).functionFactoryFunc<ISqlExpressionFactory, DbDataType, ISqlExpression, ISqlExpression[], ISqlExpression>Optional override of the SQL function emission (e.g. ClickHouse uses
arrayStringConcatinstead ofCONCAT_WS). Receives(factory, valueType, separator, items); when null, plainCONCAT_WS(separator, ...items)is emitted.withoutSeparatorboolWhen 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
builderAggregateFunctionBuilderAggregate-function builder being configured.
nullValuesAsEmptyStringboolWhen true, individual NULL values are wrapped in
COALESCE(v, '')before the chain — used bystring.Concat/string.Join/Sql.ConcatStrings. When false, NULLs flow through SQL||/+directly; on standards-compliant providers this propagates NULL.isNullResultboolWhen true, the result can be
NULL; no outerCOALESCE(..., '')is added. When false, the chain is wrapped in a finalCOALESCE(..., '').substringFuncFunc<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.).withoutSeparatorboolWhen true, no separator argument is consumed and no
SUBSTRINGstrip is needed (string.Concat). When false, the first argument is the separator (string.Join / Sql.ConcatStrings).wrapByCoalesceboolControls the per-operand NULL-skip strategy for the
WITH separatorpath. When true (default), each per-value contribution is wrapped inCoalesce(sep || v, '')— relies onNULL || x = NULLto 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 inCASE WHEN v IS NULL THEN '' ELSE sep || v ENDinstead — the explicit-IS-NULL form is required on Oracle, whereNULL || x = xmeans the Coalesce form would emit a stray separator for each NULL operand (and the empty-string-is-NULL identity makesCoalesceagainst''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 theIsNullFiltered / isNullResult / !nullValuesAsEmptybranch; the other branches keepCoalescewhen 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
operandExpression
Returns
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
composerAggregateFunctionBuilder.AggregateComposeraggregateSqlISqlExpressionisNullableResultboolemptyValueTypeDbDataType
TranslateIsNullOrWhiteSpace(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression)
public virtual ISqlExpression? TranslateIsNullOrWhiteSpace(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value)
Parameters
translationContextITranslationContextmethodCallMethodCallExpressiontranslationFlagsTranslationFlagsvalueISqlExpression
Returns
TranslateLPad(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression, ISqlExpression)
public virtual ISqlExpression? TranslateLPad(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression padding, ISqlExpression paddingChar)
Parameters
translationContextITranslationContextmethodCallMethodCallExpressiontranslationFlagsTranslationFlagsvalueISqlExpressionpaddingISqlExpressionpaddingCharISqlExpression
Returns
TranslateLength(ITranslationContext, TranslationFlags, ISqlExpression)
public virtual ISqlExpression? TranslateLength(ITranslationContext translationContext, TranslationFlags translationFlags, ISqlExpression value)
Parameters
translationContextITranslationContexttranslationFlagsTranslationFlagsvalueISqlExpression
Returns
TranslateLike(ITranslationContext, MethodCallExpression, TranslationFlags)
protected virtual Expression? TranslateLike(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags)
Parameters
translationContextITranslationContextmethodCallMethodCallExpressiontranslationFlagsTranslationFlags
Returns
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
translationContextITranslationContextmemberExpressionExpressiontranslationFlagsTranslationFlags
Returns
TranslatePadLeft(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression, ISqlExpression?)
public virtual ISqlExpression? TranslatePadLeft(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression padding, ISqlExpression? paddingChar)
Parameters
translationContextITranslationContextmethodCallMethodCallExpressiontranslationFlagsTranslationFlagsvalueISqlExpressionpaddingISqlExpressionpaddingCharISqlExpression
Returns
TranslateReplace(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression, ISqlExpression)
public virtual ISqlExpression? TranslateReplace(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression oldValue, ISqlExpression newValue)
Parameters
translationContextITranslationContextmethodCallMethodCallExpressiontranslationFlagsTranslationFlagsvalueISqlExpressionoldValueISqlExpressionnewValueISqlExpression
Returns
TranslateStringFormat(ITranslationContext, MethodCallExpression, string, IReadOnlyList<ISqlExpression>, TranslationFlags)
public virtual ISqlExpression? TranslateStringFormat(ITranslationContext translationContext, MethodCallExpression methodCall, string format, IReadOnlyList<ISqlExpression> arguments, TranslationFlags translationFlags)
Parameters
translationContextITranslationContextmethodCallMethodCallExpressionformatstringargumentsIReadOnlyList<ISqlExpression>translationFlagsTranslationFlags
Returns
TranslateStringJoin(ITranslationContext, MethodCallExpression, TranslationFlags, bool, bool, bool)
protected virtual Expression? TranslateStringJoin(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, bool nullValuesAsEmptyString, bool isNullableResult, bool withoutSeparator)
Parameters
translationContextITranslationContextmethodCallMethodCallExpressiontranslationFlagsTranslationFlagsnullValuesAsEmptyStringboolisNullableResultboolwithoutSeparatorbool
Returns
TranslateTrimEnd(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression?)
public virtual ISqlExpression? TranslateTrimEnd(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression? trimChars)
Parameters
translationContextITranslationContextmethodCallMethodCallExpressiontranslationFlagsTranslationFlagsvalueISqlExpressiontrimCharsISqlExpression
Returns
TranslateTrimStart(ITranslationContext, MethodCallExpression, TranslationFlags, ISqlExpression, ISqlExpression?)
public virtual ISqlExpression? TranslateTrimStart(ITranslationContext translationContext, MethodCallExpression methodCall, TranslationFlags translationFlags, ISqlExpression value, ISqlExpression? trimChars)
Parameters
translationContextITranslationContextmethodCallMethodCallExpressiontranslationFlagsTranslationFlagsvalueISqlExpressiontrimCharsISqlExpression
Returns
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
translationContextITranslationContextvalueISqlExpressionpredicateISqlPredicate