|
3 | 3 | // See the License.txt file in the project root for more information. |
4 | 4 |
|
5 | 5 | using System; |
| 6 | +using System.Collections.Generic; |
6 | 7 | using System.Linq; |
7 | 8 | using Xtensive.Orm.Providers.PostgreSql; |
8 | 9 | using Xtensive.Sql.Compiler; |
@@ -125,24 +126,14 @@ public override void Visit(SqlFunctionCall node) |
125 | 126 | SqlHelper.IntervalAbs(node.Arguments[0]).AcceptVisitor(this); |
126 | 127 | return; |
127 | 128 | case SqlFunctionType.DateTimeConstruct: |
128 | | - var newNode = ReferenceDateTimeLiteral |
129 | | - + (OneYearInterval * (node.Arguments[0] - 2001)) |
130 | | - + (OneMonthInterval * (node.Arguments[1] - 1)) |
131 | | - + (OneDayInterval * (node.Arguments[2] - 1)); |
132 | | - newNode.AcceptVisitor(this); |
| 129 | + ConstructDateTime(node.Arguments).AcceptVisitor(this); |
133 | 130 | return; |
134 | 131 | #if NET6_0_OR_GREATER |
135 | 132 | case SqlFunctionType.DateConstruct: |
136 | | - (ReferenceDateLiteral |
137 | | - + (OneYearInterval * (node.Arguments[0] - 2001)) |
138 | | - + (OneMonthInterval * (node.Arguments[1] - 1)) |
139 | | - + (OneDayInterval * (node.Arguments[2] - 1))).AcceptVisitor(this); |
| 133 | + ConstructDate(node.Arguments).AcceptVisitor(this); |
140 | 134 | return; |
141 | 135 | case SqlFunctionType.TimeConstruct: |
142 | | - ((ZeroTimeLiteral |
143 | | - + (OneHourInterval * (node.Arguments[0])) |
144 | | - + (OneMinuteInterval * (node.Arguments[1])) |
145 | | - + (OneSecondInterval * (node.Arguments[2] + (SqlDml.Cast(node.Arguments[3], SqlType.Double) / 1000))))).AcceptVisitor(this); |
| 136 | + ConstructTime(node.Arguments).AcceptVisitor(this); |
146 | 137 | return; |
147 | 138 | #endif |
148 | 139 | case SqlFunctionType.DateTimeTruncate: |
@@ -397,6 +388,45 @@ public override void Visit(SqlExtract node) |
397 | 388 | base.Visit(node); |
398 | 389 | } |
399 | 390 |
|
| 391 | + protected virtual SqlExpression ConstructDateTime(IReadOnlyList<SqlExpression> arguments) |
| 392 | + { |
| 393 | + return ReferenceDateTimeLiteral |
| 394 | + + (OneYearInterval * (arguments[0] - 2001)) |
| 395 | + + (OneMonthInterval * (arguments[1] - 1)) |
| 396 | + + (OneDayInterval * (arguments[2] - 1)); |
| 397 | + } |
| 398 | +#if NET6_0_OR_GREATER |
| 399 | + |
| 400 | + protected virtual SqlExpression ConstructDate(IReadOnlyList<SqlExpression> arguments) |
| 401 | + { |
| 402 | + return ReferenceDateLiteral |
| 403 | + + (OneYearInterval * (arguments[0] - 2001)) |
| 404 | + + (OneMonthInterval * (arguments[1] - 1)) |
| 405 | + + (OneDayInterval * (arguments[2] - 1)); |
| 406 | + } |
| 407 | + |
| 408 | + protected virtual SqlExpression ConstructTime(IReadOnlyList<SqlExpression> arguments) |
| 409 | + { |
| 410 | + if (arguments.Count == 4) { |
| 411 | + return ZeroTimeLiteral |
| 412 | + + (OneHourInterval * (arguments[0])) |
| 413 | + + (OneMinuteInterval * (arguments[1])) |
| 414 | + + (OneSecondInterval * (arguments[2] + (SqlDml.Cast(arguments[3], SqlType.Double) / 1000))); |
| 415 | + } |
| 416 | + else if (arguments.Count == 1) { |
| 417 | + var ticks = arguments[0]; |
| 418 | + if (SqlHelper.IsTimeSpanTicks(ticks, out var intervalExpr)) { |
| 419 | + return ZeroTimeLiteral + intervalExpr; |
| 420 | + } |
| 421 | + return ZeroTimeLiteral + (ticks / SqlDml.Literal(10000000.0) * OneSecondInterval); |
| 422 | + } |
| 423 | + else { |
| 424 | + throw new InvalidOperationException("Unsupported count of parameters"); |
| 425 | + } |
| 426 | + |
| 427 | + } |
| 428 | +#endif |
| 429 | + |
400 | 430 | protected SqlExpression DateTimeOffsetExtractDate(SqlExpression timestamp) => |
401 | 431 | SqlDml.FunctionCall("DATE", timestamp); |
402 | 432 |
|
@@ -518,6 +548,23 @@ private bool TryDivideOffsetIntoParts(SqlExpression offsetInMinutes, ref int hou |
518 | 548 | return false; |
519 | 549 | } |
520 | 550 |
|
| 551 | + private bool IsTimeSpanTicks(SqlExpression expressionToCheck, out SqlExpression source) |
| 552 | + { |
| 553 | + source = null; |
| 554 | + |
| 555 | + if (expressionToCheck is SqlCast sqlCast && sqlCast.Type.Type==SqlType.Int64) { |
| 556 | + var operand = sqlCast.Operand; |
| 557 | + if (operand is SqlBinary sqlBinary && sqlBinary.NodeType == SqlNodeType.Divide) { |
| 558 | + var left = sqlBinary.Left; |
| 559 | + if (left is SqlFunctionCall functionCall && functionCall.FunctionType == SqlFunctionType.IntervalToNanoseconds) { |
| 560 | + source = functionCall.Arguments[0]; |
| 561 | + return true; |
| 562 | + } |
| 563 | + } |
| 564 | + } |
| 565 | + return false; |
| 566 | + } |
| 567 | + |
521 | 568 | // Constructors |
522 | 569 |
|
523 | 570 | protected internal Compiler(SqlDriver driver) |
|
0 commit comments