未验证 提交 bc23399a 编写于 作者: S Shay Rojansky 提交者: GitHub

Make all function translations lower-case (#1526)

上级 3d6c6385
......@@ -47,7 +47,7 @@ public NpgsqlByteArrayMethodTranslator([NotNull] ISqlExpressionFactory sqlExpres
? (SqlExpression)_sqlExpressionFactory.Constant(new[] { (byte)constantValue.Value }, typeMapping)
// Create bytea from non-constant byte: SELECT set_byte('\x00', 0, 8::smallint);
: _sqlExpressionFactory.Function(
"SET_BYTE",
"set_byte",
new[]
{
_sqlExpressionFactory.Constant(new[] { (byte)0 }, typeMapping),
......@@ -61,7 +61,7 @@ public NpgsqlByteArrayMethodTranslator([NotNull] ISqlExpressionFactory sqlExpres
return _sqlExpressionFactory.GreaterThan(
PostgresFunctionExpression.CreateWithArgumentSeparators(
"POSITION",
"position",
new[] { value, source },
new[] { "IN" }, // POSITION(x IN y)
nullable: true,
......
......@@ -40,7 +40,7 @@ public NpgsqlDateTimeMemberTranslator([NotNull] NpgsqlSqlExpressionFactory sqlEx
_sqlExpressionFactory.AtTimeZone(Now(), _sqlExpressionFactory.Constant("UTC"), returnType),
nameof(DateTime.Today) => _sqlExpressionFactory.Function(
"DATE_TRUNC",
"date_trunc",
new SqlExpression[] { _sqlExpressionFactory.Constant("day"), Now() },
nullable: true,
argumentsPropagateNullability: TrueArrays[2],
......@@ -60,7 +60,7 @@ public NpgsqlDateTimeMemberTranslator([NotNull] NpgsqlSqlExpressionFactory sqlEx
nameof(DateTime.DayOfWeek) => GetDatePartExpression(instance, "dow", floor: true),
nameof(DateTime.Date) => _sqlExpressionFactory.Function(
"DATE_TRUNC",
"date_trunc",
new[] { _sqlExpressionFactory.Constant("day"), instance },
nullable: true,
argumentsPropagateNullability: TrueArrays[2],
......@@ -80,7 +80,7 @@ public NpgsqlDateTimeMemberTranslator([NotNull] NpgsqlSqlExpressionFactory sqlEx
SqlFunctionExpression Now()
=> _sqlExpressionFactory.Function(
"NOW",
"now",
Array.Empty<SqlExpression>(),
nullable: false,
argumentsPropagateNullability: TrueArrays[0],
......@@ -107,7 +107,7 @@ SqlFunctionExpression Now()
bool floor = false)
{
var result = _sqlExpressionFactory.Function(
"DATE_PART",
"date_part",
new[]
{
_sqlExpressionFactory.Constant(partName),
......@@ -119,7 +119,7 @@ SqlFunctionExpression Now()
if (floor)
result = _sqlExpressionFactory.Function(
"FLOOR",
"floor",
new[] { result },
nullable: true,
argumentsPropagateNullability: TrueArrays[1],
......
......@@ -24,50 +24,50 @@ public class NpgsqlMathTranslator : IMethodCallTranslator
{
static readonly Dictionary<MethodInfo, string> SupportedMethodTranslations = new Dictionary<MethodInfo, string>
{
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(decimal) }), "ABS" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(double) }), "ABS" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(float) }), "ABS" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(int) }), "ABS" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(long) }), "ABS" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(short) }), "ABS" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Ceiling), new[] { typeof(decimal) }), "CEILING" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Ceiling), new[] { typeof(double) }), "CEILING" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Floor), new[] { typeof(decimal) }), "FLOOR" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Floor), new[] { typeof(double) }), "FLOOR" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Pow), new[] { typeof(double), typeof(double) }), "POWER" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Exp), new[] { typeof(double) }), "EXP" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Log10), new[] { typeof(double) }), "LOG" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Log), new[] { typeof(double) }), "LN" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(decimal) }), "abs" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(double) }), "abs" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(float) }), "abs" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(int) }), "abs" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(long) }), "abs" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Abs), new[] { typeof(short) }), "abs" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Ceiling), new[] { typeof(decimal) }), "ceiling" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Ceiling), new[] { typeof(double) }), "ceiling" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Floor), new[] { typeof(decimal) }), "floor" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Floor), new[] { typeof(double) }), "floor" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Pow), new[] { typeof(double), typeof(double) }), "power" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Exp), new[] { typeof(double) }), "exp" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Log10), new[] { typeof(double) }), "log" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Log), new[] { typeof(double) }), "ln" },
// Note: PostgreSQL has log(x,y) but only for decimal, whereas .NET has it only for double
{ typeof(Math).GetRuntimeMethod(nameof(Math.Sqrt), new[] { typeof(double) }), "SQRT" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Acos), new[] { typeof(double) }), "ACOS" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Asin), new[] { typeof(double) }), "ASIN" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Atan), new[] { typeof(double) }), "ATAN" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Atan2), new[] { typeof(double), typeof(double) }), "ATAN2" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Cos), new[] { typeof(double) }), "COS" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Sin), new[] { typeof(double) }), "SIN" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Tan), new[] { typeof(double) }), "TAN" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Round), new[] { typeof(double) }), "ROUND" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Round), new[] { typeof(decimal) }), "ROUND" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Truncate), new[] { typeof(double) }), "TRUNC" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Truncate), new[] { typeof(decimal) }), "TRUNC" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Sqrt), new[] { typeof(double) }), "sqrt" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Acos), new[] { typeof(double) }), "acos" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Asin), new[] { typeof(double) }), "asin" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Atan), new[] { typeof(double) }), "atan" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Atan2), new[] { typeof(double), typeof(double) }), "atan2" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Cos), new[] { typeof(double) }), "cos" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Sin), new[] { typeof(double) }), "sin" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Tan), new[] { typeof(double) }), "tan" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Round), new[] { typeof(double) }), "round" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Round), new[] { typeof(decimal) }), "round" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Truncate), new[] { typeof(double) }), "trunc" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Truncate), new[] { typeof(decimal) }), "trunc" },
// https://www.postgresql.org/docs/current/functions-conditional.html#FUNCTIONS-GREATEST-LEAST
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(decimal), typeof(decimal) }), "GREATEST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(double), typeof(double) }), "GREATEST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(float), typeof(float) }), "GREATEST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(int), typeof(int) }), "GREATEST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(long), typeof(long) }), "GREATEST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(short), typeof(short) }), "GREATEST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(decimal), typeof(decimal) }), "greatest" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(double), typeof(double) }), "greatest" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(float), typeof(float) }), "greatest" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(int), typeof(int) }), "greatest" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(long), typeof(long) }), "greatest" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Max), new[] { typeof(short), typeof(short) }), "greatest" },
// https://www.postgresql.org/docs/current/functions-conditional.html#FUNCTIONS-GREATEST-LEAST
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(decimal), typeof(decimal) }), "LEAST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(double), typeof(double) }), "LEAST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(float), typeof(float) }), "LEAST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(int), typeof(int) }), "LEAST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(long), typeof(long) }), "LEAST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(short), typeof(short) }), "LEAST" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(decimal), typeof(decimal) }), "least" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(double), typeof(double) }), "least" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(float), typeof(float) }), "least" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(int), typeof(int) }), "least" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(long), typeof(long) }), "least" },
{ typeof(Math).GetRuntimeMethod(nameof(Math.Min), new[] { typeof(short), typeof(short) }), "least" },
};
static readonly IEnumerable<MethodInfo> SignMethodInfos = new[]
......@@ -149,7 +149,7 @@ public class NpgsqlMathTranslator : IMethodCallTranslator
return
_sqlExpressionFactory.Convert(
_sqlExpressionFactory.Function(
"SIGN",
"sign",
arguments,
nullable: true,
argumentsPropagateNullability: TrueArrays[1],
......@@ -160,7 +160,7 @@ public class NpgsqlMathTranslator : IMethodCallTranslator
if (method == RoundDecimalTwoParams)
{
return _sqlExpressionFactory.Function("ROUND", new[]
return _sqlExpressionFactory.Function("round", new[]
{
_sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[0]),
_sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[1])
......
......@@ -10,7 +10,7 @@
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Internal
{
/// <summary>
/// Translates <see cref="M:string.Length"/> to 'LENGTH(text)'.
/// Translates <see cref="M:string.Length"/> to 'length(text)'.
/// </summary>
public class NpgsqlStringMemberTranslator : IMemberTranslator
{
......@@ -26,7 +26,7 @@ public NpgsqlStringMemberTranslator([NotNull] ISqlExpressionFactory sqlExpressio
=> member.Name == nameof(string.Length) && instance?.Type == typeof(string)
? _sqlExpressionFactory.Convert(
_sqlExpressionFactory.Function(
"LENGTH",
"length",
new[] { instance },
nullable: true,
argumentsPropagateNullability: TrueArrays[1],
......
......@@ -93,7 +93,7 @@ public class NpgsqlStringMethodTranslator : IMethodCallTranslator
return _sqlExpressionFactory.Subtract(
_sqlExpressionFactory.Function(
"STRPOS",
"strpos",
new[]
{
_sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
......@@ -112,7 +112,7 @@ public class NpgsqlStringMethodTranslator : IMethodCallTranslator
var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, oldValue, newValue);
return _sqlExpressionFactory.Function(
"REPLACE",
"replace",
new[]
{
_sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
......@@ -128,7 +128,7 @@ public class NpgsqlStringMethodTranslator : IMethodCallTranslator
if (method == ToLower || method == ToUpper)
{
return _sqlExpressionFactory.Function(
method == ToLower ? "LOWER" : "UPPER",
method == ToLower ? "lower" : "upper",
new[] { instance },
nullable: true,
argumentsPropagateNullability: TrueArrays[1],
......@@ -143,7 +143,7 @@ public class NpgsqlStringMethodTranslator : IMethodCallTranslator
? new[] { instance, GenerateOneBasedIndexExpression(arguments[0]) }
: new[] { instance, GenerateOneBasedIndexExpression(arguments[0]), arguments[1] };
return _sqlExpressionFactory.Function(
"SUBSTRING",
"substring",
args,
nullable: true,
argumentsPropagateNullability: TrueArrays[args.Length],
......@@ -159,7 +159,7 @@ public class NpgsqlStringMethodTranslator : IMethodCallTranslator
_sqlExpressionFactory.IsNull(argument),
_sqlExpressionFactory.Equal(
_sqlExpressionFactory.Function(
"BTRIM",
"btrim",
new[]
{
argument,
......@@ -193,7 +193,7 @@ public class NpgsqlStringMethodTranslator : IMethodCallTranslator
}
return _sqlExpressionFactory.Function(
isTrimStart ? "LTRIM" : isTrimEnd ? "RTRIM" : "BTRIM",
isTrimStart ? "ltrim" : isTrimEnd ? "rtrim" : "btrim",
new[]
{
instance,
......@@ -216,7 +216,7 @@ public class NpgsqlStringMethodTranslator : IMethodCallTranslator
var strposCheck = _sqlExpressionFactory.GreaterThan(
_sqlExpressionFactory.Function(
"STRPOS",
"strpos",
new[]
{
_sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping),
......@@ -334,12 +334,12 @@ SqlExpression TranslateStartsEndsWith(SqlExpression instance, SqlExpression patt
// For StartsWith we also first run a LIKE to quickly filter out most non-matching results (sargable, but imprecise
// because of wildchars).
SqlExpression leftRight = _sqlExpressionFactory.Function(
startsWith ? "LEFT" : "RIGHT",
startsWith ? "left" : "right",
new[]
{
instance,
_sqlExpressionFactory.Function(
"LENGTH",
"length",
new[] { pattern },
nullable: true,
argumentsPropagateNullability: TrueArrays[1],
......
......@@ -133,7 +133,7 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression)
(sqlOperand.TypeMapping == null || sqlOperand.TypeMapping is NpgsqlByteArrayTypeMapping))
{
return _sqlExpressionFactory.Function(
"LENGTH",
"length",
new[] { sqlOperand },
nullable: true,
argumentsPropagateNullability: TrueArrays[1],
......@@ -318,7 +318,7 @@ protected override Expression VisitNew(NewExpression newExpression)
{
return TryTranslateArguments(newExpression.Arguments, out var sqlArguments)
? _sqlExpressionFactory.Function(
"MAKE_DATE", sqlArguments, nullable: true, TrueArrays[3], typeof(DateTime))
"make_date", sqlArguments, nullable: true, TrueArrays[3], typeof(DateTime))
: null;
}
......@@ -331,7 +331,7 @@ protected override Expression VisitNew(NewExpression newExpression)
sqlArguments[5] = _sqlExpressionFactory.Convert(sqlArguments[5], typeof(double));
return _sqlExpressionFactory.Function(
"MAKE_TIMESTAMP", sqlArguments, nullable: true, TrueArrays[6], typeof(DateTime));
"make_timestamp", sqlArguments, nullable: true, TrueArrays[6], typeof(DateTime));
}
return null;
......
......@@ -49,7 +49,7 @@ public void StartsWith_param_pattern()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE (@__param_0 = '') OR ((s.""CaseInsensitiveText"" IS NOT NULL) AND ((s.""CaseInsensitiveText"" LIKE @__param_0 || '%') AND (LEFT(s.""CaseInsensitiveText"", LENGTH(@__param_0))::citext = @__param_0::citext)))
WHERE (@__param_0 = '') OR ((s.""CaseInsensitiveText"" IS NOT NULL) AND ((s.""CaseInsensitiveText"" LIKE @__param_0 || '%') AND (left(s.""CaseInsensitiveText"", length(@__param_0))::citext = @__param_0::citext)))
LIMIT 2");
}
......@@ -66,7 +66,7 @@ public void StartsWith_param_instance()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE (s.""CaseInsensitiveText"" = '') OR ((s.""CaseInsensitiveText"" IS NOT NULL) AND ((@__param_0 LIKE s.""CaseInsensitiveText"" || '%') AND (LEFT(@__param_0, LENGTH(s.""CaseInsensitiveText""))::citext = CAST(s.""CaseInsensitiveText"" AS citext))))
WHERE (s.""CaseInsensitiveText"" = '') OR ((s.""CaseInsensitiveText"" IS NOT NULL) AND ((@__param_0 LIKE s.""CaseInsensitiveText"" || '%') AND (left(@__param_0, length(s.""CaseInsensitiveText""))::citext = CAST(s.""CaseInsensitiveText"" AS citext))))
LIMIT 2");
}
......@@ -97,7 +97,7 @@ public void EndsWith_param_pattern()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE (@__param_0 = '') OR ((s.""CaseInsensitiveText"" IS NOT NULL) AND (RIGHT(s.""CaseInsensitiveText"", LENGTH(@__param_0))::citext = @__param_0::citext))
WHERE (@__param_0 = '') OR ((s.""CaseInsensitiveText"" IS NOT NULL) AND (right(s.""CaseInsensitiveText"", length(@__param_0))::citext = @__param_0::citext))
LIMIT 2");
}
......@@ -114,7 +114,7 @@ public void EndsWith_param_instance()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE (s.""CaseInsensitiveText"" = '') OR ((s.""CaseInsensitiveText"" IS NOT NULL) AND (RIGHT(@__param_0, LENGTH(s.""CaseInsensitiveText""))::citext = CAST(s.""CaseInsensitiveText"" AS citext)))
WHERE (s.""CaseInsensitiveText"" = '') OR ((s.""CaseInsensitiveText"" IS NOT NULL) AND (right(@__param_0, length(s.""CaseInsensitiveText""))::citext = CAST(s.""CaseInsensitiveText"" AS citext)))
LIMIT 2");
}
......@@ -128,7 +128,7 @@ public void Contains_literal()
AssertSql(
@"SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE STRPOS(s.""CaseInsensitiveText"", 'ometex') > 0
WHERE strpos(s.""CaseInsensitiveText"", 'ometex') > 0
LIMIT 2");
}
......@@ -145,7 +145,7 @@ public void Contains_param_pattern()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE (@__param_0 = '') OR (STRPOS(s.""CaseInsensitiveText"", @__param_0) > 0)
WHERE (@__param_0 = '') OR (strpos(s.""CaseInsensitiveText"", @__param_0) > 0)
LIMIT 2");
}
......@@ -162,7 +162,7 @@ public void Contains_param_instance()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE (s.""CaseInsensitiveText"" = '') OR (STRPOS(@__param_0, s.""CaseInsensitiveText"") > 0)
WHERE (s.""CaseInsensitiveText"" = '') OR (strpos(@__param_0, s.""CaseInsensitiveText"") > 0)
LIMIT 2");
}
......@@ -176,7 +176,7 @@ public void IndexOf_literal()
AssertSql(
@"SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE (STRPOS(s.""CaseInsensitiveText"", 'ometex') - 1) = 1
WHERE (strpos(s.""CaseInsensitiveText"", 'ometex') - 1) = 1
LIMIT 2");
}
......@@ -193,7 +193,7 @@ public void IndexOf_param_pattern()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE (STRPOS(s.""CaseInsensitiveText"", @__param_0) - 1) = 1
WHERE (strpos(s.""CaseInsensitiveText"", @__param_0) - 1) = 1
LIMIT 2");
}
......@@ -210,7 +210,7 @@ public void IndexOf_param_instance()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE (STRPOS(@__param_0, s.""CaseInsensitiveText"") - 1) = 5
WHERE (strpos(@__param_0, s.""CaseInsensitiveText"") - 1) = 5
LIMIT 2");
}
......@@ -224,7 +224,7 @@ public void Replace_literal()
AssertSql(
@"SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE REPLACE(s.""CaseInsensitiveText"", 'Te', 'Ne') = 'SomeNext'
WHERE replace(s.""CaseInsensitiveText"", 'Te', 'Ne') = 'SomeNext'
LIMIT 2");
}
......@@ -241,7 +241,7 @@ public void Replace_param_pattern()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE REPLACE(s.""CaseInsensitiveText"", @__param_0, 'Ne') = 'SomeNext'
WHERE replace(s.""CaseInsensitiveText"", @__param_0, 'Ne') = 'SomeNext'
LIMIT 2");
}
......@@ -258,7 +258,7 @@ public void Replace_param_instance()
SELECT s.""Id"", s.""CaseInsensitiveText""
FROM ""SomeEntities"" AS s
WHERE REPLACE(@__param_0, s.""CaseInsensitiveText"", 'NewStuff') = 'ExtraNewStuffExtra'
WHERE replace(@__param_0, s.""CaseInsensitiveText"", 'NewStuff') = 'ExtraNewStuffExtra'
LIMIT 2");
}
......
......@@ -132,7 +132,7 @@ public void Enum_ToString()
AssertSql(
@"SELECT s.""Id"", s.""ByteEnum"", s.""EnumValue"", s.""InferredEnum"", s.""MappedEnum"", s.""SchemaQualifiedEnum"", s.""UnmappedByteEnum"", s.""UnmappedEnum""
FROM test.""SomeEntities"" AS s
WHERE STRPOS(CAST(s.""MappedEnum"" AS text), 'sa') > 0
WHERE strpos(CAST(s.""MappedEnum"" AS text), 'sa') > 0
LIMIT 2");
}
......
......@@ -26,7 +26,7 @@ public override async Task Byte_array_contains_literal(bool async)
AssertSql(
@"SELECT s.""Id"", s.""Banner"", s.""Banner5"", s.""InternalNumber"", s.""Name""
FROM ""Squads"" AS s
WHERE POSITION(BYTEA E'\\x01' IN s.""Banner"") > 0");
WHERE position(BYTEA E'\\x01' IN s.""Banner"") > 0");
}
public override async Task Byte_array_contains_parameter(bool async)
......@@ -38,7 +38,7 @@ public override async Task Byte_array_contains_parameter(bool async)
SELECT s.""Id"", s.""Banner"", s.""Banner5"", s.""InternalNumber"", s.""Name""
FROM ""Squads"" AS s
WHERE POSITION(SET_BYTE(BYTEA E'\\x00', 0, @__someByte_0) IN s.""Banner"") > 0");
WHERE position(set_byte(BYTEA E'\\x00', 0, @__someByte_0) IN s.""Banner"") > 0");
}
public override async Task Byte_array_filter_by_length_literal(bool async)
......@@ -48,7 +48,7 @@ public override async Task Byte_array_filter_by_length_literal(bool async)
AssertSql(
@"SELECT s.""Id"", s.""Banner"", s.""Banner5"", s.""InternalNumber"", s.""Name""
FROM ""Squads"" AS s
WHERE LENGTH(s.""Banner"") = 1");
WHERE length(s.""Banner"") = 1");
}
public override async Task Byte_array_filter_by_length_literal_does_not_cast_on_varbinary_n(bool async)
......@@ -58,7 +58,7 @@ public override async Task Byte_array_filter_by_length_literal_does_not_cast_on_
AssertSql(
@"SELECT s.""Id"", s.""Banner"", s.""Banner5"", s.""InternalNumber"", s.""Name""
FROM ""Squads"" AS s
WHERE LENGTH(s.""Banner5"") = 5");
WHERE length(s.""Banner5"") = 5");
}
public override async Task Byte_array_filter_by_length_parameter(bool async)
......@@ -70,7 +70,7 @@ public override async Task Byte_array_filter_by_length_parameter(bool async)
SELECT s.""Id"", s.""Banner"", s.""Banner5"", s.""InternalNumber"", s.""Name""
FROM ""Squads"" AS s
WHERE LENGTH(s.""Banner"") = @__p_0");
WHERE length(s.""Banner"") = @__p_0");
}
public override void Byte_array_filter_by_length_parameter_compiled()
......@@ -82,7 +82,7 @@ public override void Byte_array_filter_by_length_parameter_compiled()
SELECT COUNT(*)::INT
FROM ""Squads"" AS s
WHERE LENGTH(s.""Banner"") = LENGTH(@__byteArrayParam)");
WHERE length(s.""Banner"") = length(@__byteArrayParam)");
}
[Theory(Skip = "https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/874")]
......
......@@ -38,7 +38,7 @@ public void Max_ushort_ushort()
.Select(x => Math.Max(x.UShort, x.UShort))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"UShort\", x.\"UShort\")");
AssertContainsSql("SELECT greatest(x.\"UShort\", x.\"UShort\")");
}
//[Fact]
......@@ -50,7 +50,7 @@ public void Max_uint_uint()
.Select(x => Math.Max(x.UInt, x.UInt))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"UInt\", x.\"UInt\")");
AssertContainsSql("SELECT greatest(x.\"UInt\", x.\"UInt\")");
}
//[Fact]
......@@ -62,7 +62,7 @@ public void Max_ulong_ulong()
.Select(x => Math.Max(x.ULong, x.ULong))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"ULong\", x.\"ULong\")");
AssertContainsSql("SELECT greatest(x.\"ULong\", x.\"ULong\")");
}
[Fact]
......@@ -74,7 +74,7 @@ public void Max_short_short()
.Select(x => Math.Max(x.Short, x.Short))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"Short\", x.\"Short\")");
AssertContainsSql("SELECT greatest(x.\"Short\", x.\"Short\")");
}
[Fact]
......@@ -86,7 +86,7 @@ public void Max_int_int()
.Select(x => Math.Max(x.Int, x.Int))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"Int\", x.\"Int\")");
AssertContainsSql("SELECT greatest(x.\"Int\", x.\"Int\")");
}
[Fact]
......@@ -98,7 +98,7 @@ public void Max_long_long()
.Select(x => Math.Max(x.Long, x.Long))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"Long\", x.\"Long\")");
AssertContainsSql("SELECT greatest(x.\"Long\", x.\"Long\")");
}
[Fact]
......@@ -110,7 +110,7 @@ public void Max_float_float()
.Select(x => Math.Max(x.Float, x.Float))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"Float\", x.\"Float\")");
AssertContainsSql("SELECT greatest(x.\"Float\", x.\"Float\")");
}
[Fact]
......@@ -122,7 +122,7 @@ public void Max_double_double()
.Select(x => Math.Max(x.Double, x.Double))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"Double\", x.\"Double\")");
AssertContainsSql("SELECT greatest(x.\"Double\", x.\"Double\")");
}
[Fact]
......@@ -134,7 +134,7 @@ public void Max_decimal_decimal()
.Select(x => Math.Max(x.Decimal, x.Decimal))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"Decimal\", x.\"Decimal\")");
AssertContainsSql("SELECT greatest(x.\"Decimal\", x.\"Decimal\")");
}
//[Fact]
......@@ -146,7 +146,7 @@ public void Max_sbyte_sbyte()
.Select(x => Math.Max(x.SByte, x.SByte))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"SByte\", x.\"SByte\")");
AssertContainsSql("SELECT greatest(x.\"SByte\", x.\"SByte\")");
}
//[Fact]
......@@ -158,7 +158,7 @@ public void Max_byte_byte()
.Select(x => Math.Max(x.Byte, x.Byte))
.ToArray();
AssertContainsSql("SELECT GREATEST(x.\"Byte\", x.\"Byte\")");
AssertContainsSql("SELECT greatest(x.\"Byte\", x.\"Byte\")");
}
#endregion
......@@ -174,7 +174,7 @@ public void Min_ushort_ushort()
.Select(x => Math.Min(x.UShort, x.UShort))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"UShort\", x.\"UShort\")");
AssertContainsSql("SELECT least(x.\"UShort\", x.\"UShort\")");
}
//[Fact]
......@@ -186,7 +186,7 @@ public void Min_uint_uint()
.Select(x => Math.Min(x.UInt, x.UInt))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"UInt\", x.\"UInt\")");
AssertContainsSql("SELECT least(x.\"UInt\", x.\"UInt\")");
}
//[Fact]
......@@ -198,7 +198,7 @@ public void Min_ulong_ulong()
.Select(x => Math.Min(x.ULong, x.ULong))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"ULong\", x.\"ULong\")");
AssertContainsSql("SELECT least(x.\"ULong\", x.\"ULong\")");
}
[Fact]
......@@ -210,7 +210,7 @@ public void Min_short_short()
.Select(x => Math.Min(x.Short, x.Short))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"Short\", x.\"Short\")");
AssertContainsSql("SELECT least(x.\"Short\", x.\"Short\")");
}
[Fact]
......@@ -222,7 +222,7 @@ public void Min_int_int()
.Select(x => Math.Min(x.Int, x.Int))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"Int\", x.\"Int\")");
AssertContainsSql("SELECT least(x.\"Int\", x.\"Int\")");
}
[Fact]
......@@ -234,7 +234,7 @@ public void Min_long_long()
.Select(x => Math.Min(x.Long, x.Long))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"Long\", x.\"Long\")");
AssertContainsSql("SELECT least(x.\"Long\", x.\"Long\")");
}
[Fact]
......@@ -246,7 +246,7 @@ public void Min_float_float()
.Select(x => Math.Min(x.Float, x.Float))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"Float\", x.\"Float\")");
AssertContainsSql("SELECT least(x.\"Float\", x.\"Float\")");
}
[Fact]
......@@ -258,7 +258,7 @@ public void Min_double_double()
.Select(x => Math.Min(x.Double, x.Double))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"Double\", x.\"Double\")");
AssertContainsSql("SELECT least(x.\"Double\", x.\"Double\")");
}
[Fact]
......@@ -270,7 +270,7 @@ public void Min_decimal_decimal()
.Select(x => Math.Min(x.Decimal, x.Decimal))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"Decimal\", x.\"Decimal\")");
AssertContainsSql("SELECT least(x.\"Decimal\", x.\"Decimal\")");
}
//[Fact]
......@@ -282,7 +282,7 @@ public void Min_sbyte_sbyte()
.Select(x => Math.Min(x.SByte, x.SByte))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"SByte\", x.\"SByte\")");
AssertContainsSql("SELECT least(x.\"SByte\", x.\"SByte\")");
}
//[Fact]
......@@ -294,7 +294,7 @@ public void Min_byte_byte()
.Select(x => Math.Min(x.Byte, x.Byte))
.ToArray();
AssertContainsSql("SELECT LEAST(x.\"Byte\", x.\"Byte\")");
AssertContainsSql("SELECT least(x.\"Byte\", x.\"Byte\")");
}
#endregion
......
......@@ -27,7 +27,7 @@ public override async Task IsNullOrWhiteSpace_in_predicate(bool async)
AssertSql(
@"SELECT c.""CustomerID"", c.""Address"", c.""City"", c.""CompanyName"", c.""ContactName"", c.""ContactTitle"", c.""Country"", c.""Fax"", c.""Phone"", c.""PostalCode"", c.""Region""
FROM ""Customers"" AS c
WHERE (c.""Region"" IS NULL) OR (BTRIM(c.""Region"", E' \t\n\r') = '')");
WHERE (c.""Region"" IS NULL) OR (btrim(c.""Region"", E' \t\n\r') = '')");
}
[ConditionalTheory(Skip = "Fixed for PostgreSQL 12.1, https://www.postgresql.org/message-id/CADT4RqAz7oN4vkPir86Kg1_mQBmBxCp-L_%3D9vRpgSNPJf0KRkw%40mail.gmail.com")]
......
......@@ -21,7 +21,7 @@ public NorthwindMiscellaneousQueryNpgsqlTest(NorthwindQueryNpgsqlFixture<NoopMod
public override async Task Query_expression_with_to_string_and_contains(bool async)
{
await base.Query_expression_with_to_string_and_contains(async);
AssertContainsSqlFragment(@"STRPOS(CAST(o.""EmployeeID"" AS text), '10') > 0");
AssertContainsSqlFragment(@"strpos(CAST(o.""EmployeeID"" AS text), '10') > 0");
}
public override async Task Select_expression_date_add_year(bool async)
......
......@@ -14,7 +14,16 @@ public NorthwindSelectQueryNpgsqlTest(NorthwindQueryNpgsqlFixture<NoopModelCusto
: base(fixture)
{
ClearLog();
//Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
// Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
public override async Task Select_datetime_DayOfWeek_component(bool async)
{
await base.Select_datetime_DayOfWeek_component(async);
AssertSql(
@"SELECT floor(date_part('dow', o.""OrderDate""))::INT
FROM ""Orders"" AS o");
}
[ConditionalTheory(Skip = "To be fixed in PG 12.0, https://www.postgresql.org/message-id/CADT4RqAz7oN4vkPir86Kg1_mQBmBxCp-L_%3D9vRpgSNPJf0KRkw%40mail.gmail.com")]
......
......@@ -15,9 +15,151 @@ public NorthwindWhereQueryNpgsqlTest(NorthwindQueryNpgsqlFixture<NoopModelCustom
: base(fixture)
{
ClearLog();
//Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
// Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
#region Date and time
public override async Task Where_datetime_now(bool async)
{
await base.Where_datetime_now(async);
AssertSql(
@"@__myDatetime_0='2015-04-10T00:00:00.0000000' (DbType = DateTime)
SELECT c.""CustomerID"", c.""Address"", c.""City"", c.""CompanyName"", c.""ContactName"", c.""ContactTitle"", c.""Country"", c.""Fax"", c.""Phone"", c.""PostalCode"", c.""Region""
FROM ""Customers"" AS c
WHERE now() <> @__myDatetime_0");
}
public override async Task Where_datetime_utcnow(bool async)
{
await base.Where_datetime_utcnow(async);
AssertSql(
@"@__myDatetime_0='2015-04-10T00:00:00.0000000' (DbType = DateTimeOffset)
SELECT c.""CustomerID"", c.""Address"", c.""City"", c.""CompanyName"", c.""ContactName"", c.""ContactTitle"", c.""Country"", c.""Fax"", c.""Phone"", c.""PostalCode"", c.""Region""
FROM ""Customers"" AS c
WHERE now() AT TIME ZONE 'UTC' <> @__myDatetime_0");
}
public override async Task Where_datetime_today(bool async)
{
await base.Where_datetime_today(async);
AssertSql(
@"SELECT e.""EmployeeID"", e.""City"", e.""Country"", e.""FirstName"", e.""ReportsTo"", e.""Title""
FROM ""Employees"" AS e
WHERE date_trunc('day', now()) = date_trunc('day', now())");
}
public override async Task Where_datetime_date_component(bool async)
{
await base.Where_datetime_date_component(async);
AssertSql(
@"@__myDatetime_0='1998-05-04T00:00:00.0000000' (DbType = DateTime)
SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE date_trunc('day', o.""OrderDate"") = @__myDatetime_0");
}
public override async Task Where_date_add_year_constant_component(bool async)
{
await base.Where_date_add_year_constant_component(async);
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE date_part('year', o.""OrderDate"" + INTERVAL '-1 years')::INT = 1997");
}
public override async Task Where_datetime_year_component(bool async)
{
await base.Where_datetime_year_component(async);
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE date_part('year', o.""OrderDate"")::INT = 1998");
}
public override async Task Where_datetime_month_component(bool async)
{
await base.Where_datetime_month_component(async);
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE date_part('month', o.""OrderDate"")::INT = 4");
}
public override async Task Where_datetime_dayOfYear_component(bool async)
{
await base.Where_datetime_dayOfYear_component(async);
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE date_part('doy', o.""OrderDate"")::INT = 68");
}
public override async Task Where_datetime_day_component(bool async)
{
await base.Where_datetime_day_component(async);
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE date_part('day', o.""OrderDate"")::INT = 4");
}
public override async Task Where_datetime_hour_component(bool async)
{
await base.Where_datetime_hour_component(async);
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE date_part('hour', o.""OrderDate"")::INT = 14");
}
public override async Task Where_datetime_minute_component(bool async)
{
await base.Where_datetime_minute_component(async);
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE date_part('minute', o.""OrderDate"")::INT = 23");
}
public override async Task Where_datetime_second_component(bool async)
{
await base.Where_datetime_second_component(async);
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE date_part('second', o.""OrderDate"")::INT = 44");
}
[Theory(Skip = "SQL translation not implemented, too annoying")]
public override Task Where_datetime_millisecond_component(bool async)
=> base.Where_datetime_millisecond_component(async);
[Theory(Skip = "Translation not implemented yet, #873")]
public override Task Where_datetimeoffset_now_component(bool async)
=> base.Where_datetimeoffset_now_component(async);
[Theory(Skip = "Translation not implemented yet, #873")]
public override Task Where_datetimeoffset_utcnow_component(bool async)
=> base.Where_datetimeoffset_utcnow_component(async);
#endregion Date and time
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Where_datetime_ctor1(bool async)
......@@ -30,7 +172,7 @@ public virtual async Task Where_datetime_ctor1(bool async)
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE MAKE_DATE(DATE_PART('year', o.""OrderDate"")::INT, DATE_PART('month', o.""OrderDate"")::INT, 1) = TIMESTAMP '1996-09-11 00:00:00'");
WHERE make_date(date_part('year', o.""OrderDate"")::INT, date_part('month', o.""OrderDate"")::INT, 1) = TIMESTAMP '1996-09-11 00:00:00'");
}
[ConditionalTheory]
......@@ -45,21 +187,9 @@ public virtual async Task Where_datetime_ctor2(bool async)
AssertSql(
@"SELECT o.""OrderID"", o.""CustomerID"", o.""EmployeeID"", o.""OrderDate""
FROM ""Orders"" AS o
WHERE MAKE_TIMESTAMP(DATE_PART('year', o.""OrderDate"")::INT, DATE_PART('month', o.""OrderDate"")::INT, 1, 0, 0, 0::double precision) = TIMESTAMP '1996-09-11 00:00:00'");
WHERE make_timestamp(date_part('year', o.""OrderDate"")::INT, date_part('month', o.""OrderDate"")::INT, 1, 0, 0, 0::double precision) = TIMESTAMP '1996-09-11 00:00:00'");
}
[Theory(Skip = "SQL translation not implemented, too annoying")]
public override Task Where_datetime_millisecond_component(bool async)
=> base.Where_datetime_millisecond_component(async);
[Theory(Skip = "Translation not implemented yet, #873")]
public override Task Where_datetimeoffset_now_component(bool async)
=> base.Where_datetimeoffset_now_component(async);
[Theory(Skip = "Translation not implemented yet, #873")]
public override Task Where_datetimeoffset_utcnow_component(bool async)
=> base.Where_datetimeoffset_utcnow_component(async);
void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
......
......@@ -122,7 +122,7 @@ public override void Scalar_Function_Where_Correlated_Static()
base.Scalar_Function_Where_Correlated_Static();
AssertSql(
@"SELECT LOWER(CAST(c.""Id"" AS text))
@"SELECT lower(CAST(c.""Id"" AS text))
FROM ""Customers"" AS c
WHERE ""IsTopCustomer""(c.""Id"")");
}
......@@ -349,7 +349,7 @@ public override void Scalar_Nested_Function_BCL_UDF_Static()
AssertSql(
@"SELECT c.""Id""
FROM ""Customers"" AS c
WHERE 3 = ABS(""CustomerOrderCount""(c.""Id""))
WHERE 3 = abs(""CustomerOrderCount""(c.""Id""))
LIMIT 2");
}
......@@ -371,7 +371,7 @@ public override void Scalar_Nested_Function_UDF_BCL_Static()
AssertSql(
@"SELECT c.""Id""
FROM ""Customers"" AS c
WHERE 3 = ""CustomerOrderCount""(ABS(c.""Id""))
WHERE 3 = ""CustomerOrderCount""(abs(c.""Id""))
LIMIT 2");
}
......@@ -500,7 +500,7 @@ public override void Scalar_Function_Where_Correlated_Instance()
base.Scalar_Function_Where_Correlated_Instance();
AssertSql(
@"SELECT LOWER(CAST(c.""Id"" AS text))
@"SELECT lower(CAST(c.""Id"" AS text))
FROM ""Customers"" AS c
WHERE ""IsTopCustomer""(c.""Id"")");
}
......@@ -727,7 +727,7 @@ public override void Scalar_Nested_Function_BCL_UDF_Instance()
AssertSql(
@"SELECT c.""Id""
FROM ""Customers"" AS c
WHERE 3 = ABS(""CustomerOrderCount""(c.""Id""))
WHERE 3 = abs(""CustomerOrderCount""(c.""Id""))
LIMIT 2");
}
......@@ -749,7 +749,7 @@ public override void Scalar_Nested_Function_UDF_BCL_Instance()
AssertSql(
@"SELECT c.""Id""
FROM ""Customers"" AS c
WHERE 3 = ""CustomerOrderCount""(ABS(c.""Id""))
WHERE 3 = ""CustomerOrderCount""(abs(c.""Id""))
LIMIT 2");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册