Skip to content

Commit 9d866ce

Browse files
committed
Support for DateOnly/TimeOnly parts extraction
Ticks part is not supported yet. MySQL: - time for mysql 5.5 and below does not support fractions of second, precision declaration works from 5.6. - changes extraction of milliseconds (seems to be working, on tests but some issues might appear)
1 parent 005e62d commit 9d866ce

16 files changed

Lines changed: 346 additions & 107 deletions

File tree

Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,31 @@ public override void Visit(SqlExtract node)
101101
Visit(CastToLong(node.Operand));
102102
return;
103103
}
104+
#if NET6_0_OR_GREATER
105+
if (((node.IsDatePart && node.DatePart == SqlDatePart.DayOfYear)
106+
|| (node.IsDateTimePart && node.DateTimePart == SqlDateTimePart.DayOfYear))) {
107+
if (!case_SqlDateTimePart_DayOfYear) {
108+
case_SqlDateTimePart_DayOfYear = true;
109+
Visit(SqlDml.Add(node, SqlDml.Literal(1)));
110+
case_SqlDateTimePart_DayOfYear = false;
111+
}
112+
else {
113+
base.Visit(node);
114+
}
115+
return;
116+
}
117+
else if (node.IsSecondExtraction) {
118+
if (!case_SqlDateTimePart_Second) {
119+
case_SqlDateTimePart_Second = true;
120+
Visit(SqlDml.Truncate(node));
121+
case_SqlDateTimePart_Second = false;
122+
}
123+
else {
124+
base.Visit(node);
125+
}
126+
return;
127+
}
128+
#else
104129
switch (node.DateTimePart) {
105130
case SqlDateTimePart.DayOfYear:
106131
if (!case_SqlDateTimePart_DayOfYear) {
@@ -123,6 +148,8 @@ public override void Visit(SqlExtract node)
123148
}
124149
return;
125150
}
151+
#endif
152+
126153
base.Visit(node);
127154
}
128155

@@ -235,7 +262,7 @@ public override void Visit(SqlAlterSequence node)
235262
translator.Translate(context, node, NodeSection.Exit);
236263
}
237264

238-
#region Static helpers
265+
#region Static helpers
239266

240267
protected static SqlExpression DateTimeSubtractDateTime(SqlExpression date1, SqlExpression date2)
241268
{
@@ -301,7 +328,7 @@ protected static SqlConcat DateTimeToStringIso(SqlExpression dateTime)
301328
return SqlDml.Concat(date, SqlDml.Literal("T"), time);
302329
}
303330

304-
#endregion
331+
#endregion
305332

306333
protected internal Compiler(SqlDriver driver)
307334
: base(driver)

Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Translator.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,18 @@ public override void Translate(IOutput output, SqlDateTimePart dateTimePart)
221221
}
222222
}
223223

224+
#if NET6_0_OR_GREATER //DO_DATEONLY
225+
/// <inheritdoc/>
226+
public override void Translate(IOutput output, SqlDatePart datePart)
227+
{
228+
switch (datePart) {
229+
case SqlDatePart.DayOfYear: _ = output.Append("YEARDAY"); break;
230+
case SqlDatePart.DayOfWeek: _ = output.Append("WEEKDAY"); break;
231+
default: base.Translate(output, datePart); break;
232+
}
233+
}
234+
#endif
235+
224236
/// <inheritdoc/>
225237
public override void Translate(SqlCompilerContext context, SqlSelect node, SelectSection section)
226238
{

Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,13 @@ public override void Visit(SqlExtract node)
239239
Visit(SqlDml.FunctionCall(node.DateTimePart.ToString(), node.Operand));
240240
return;
241241
}
242+
#if NET6_0_OR_GREATER //DO_DATEONLY
243+
if (node.DatePart == SqlDatePart.DayOfWeek || node.DatePart == SqlDatePart.DayOfYear) {
244+
Visit(SqlDml.FunctionCall(node.DatePart.ToString(), node.Operand));
245+
return;
246+
}
247+
#endif
248+
242249
base.Visit(node);
243250
}
244251

Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Extractor.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ private SqlValueType CreateValueType(IDataRecord row,
602602
int typeNameIndex, int precisionIndex, int scaleIndex, int charLengthIndex)
603603
{
604604
var typeName = row.GetString(typeNameIndex).ToUpperInvariant();
605-
var columnName = row.GetString(6).ToUpperInvariant();
605+
var dataTypeName = row.GetString(6).ToUpperInvariant();
606606

607607
var precision = row.IsDBNull(precisionIndex) ? DefaultPrecision : ReadInt(row, precisionIndex);
608608
var scale = row.IsDBNull(scaleIndex) ? DefaultScale : ReadInt(row, scaleIndex);
@@ -618,7 +618,7 @@ private SqlValueType CreateValueType(IDataRecord row,
618618
return new SqlValueType(SqlType.Double);
619619
}
620620

621-
if (columnName.Equals("TINYINT(1)", StringComparison.Ordinal)) {
621+
if (dataTypeName.Equals("TINYINT(1)", StringComparison.Ordinal)) {
622622
return new SqlValueType(SqlType.Boolean);
623623
}
624624

@@ -654,8 +654,8 @@ private SqlValueType CreateValueType(IDataRecord row,
654654
}
655655
#if NET6_0_OR_GREATER //DO_DATEONLY
656656
if (typeName.Equals("TIME", StringComparison.Ordinal)) {
657-
658-
return new SqlValueType(SqlType.Time);
657+
var time_precision = (dataTypeName.Length > 4) ? int.Parse(dataTypeName[5].ToString()) : 0;
658+
return new SqlValueType(SqlType.Time, precision);
659659
}
660660
else if (typeName.StartsWith("TIME", StringComparison.Ordinal)) {
661661
// "timestamp precision" is saved as "scale", ignoring too

Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Translator.cs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,9 +411,8 @@ public override void Translate(SqlCompilerContext context, object literalValue)
411411
/// <inheritdoc/>
412412
public override void Translate(SqlCompilerContext context, SqlExtract node, ExtractSection section)
413413
{
414-
var isSecond = node.DateTimePart == SqlDateTimePart.Second || node.IntervalPart == SqlIntervalPart.Second;
415-
var isMillisecond = node.DateTimePart == SqlDateTimePart.Millisecond
416-
|| node.IntervalPart == SqlIntervalPart.Millisecond;
414+
var isSecond = node.IsSecondExtraction;
415+
var isMillisecond = node.IsMillisecondExtraction;
417416
if (!(isSecond || isMillisecond)) {
418417
base.Translate(context, node, section);
419418
return;
@@ -423,7 +422,7 @@ public override void Translate(SqlCompilerContext context, SqlExtract node, Extr
423422
_ = context.Output.AppendOpeningPunctuation("(extract(");
424423
break;
425424
case ExtractSection.Exit:
426-
_ = context.Output.Append(isMillisecond ? ") % 1000)" : "))");
425+
_ = context.Output.Append(isMillisecond ? ") / 1000)" : "))");
427426
break;
428427
default:
429428
base.Translate(context, node, section);
@@ -519,6 +518,31 @@ public override void Translate(IOutput output, SqlDateTimePart dateTimePart)
519518
}
520519
}
521520

521+
#if NET6_0_OR_GREATER //DO_DATEONLY
522+
/// <inheritdoc/>
523+
public override void Translate(IOutput output, SqlDatePart datePart)
524+
{
525+
switch (datePart) {
526+
case SqlDatePart.Day: _ = output.Append("DAY"); break;
527+
case SqlDatePart.Year: _ = output.Append("YEAR"); break;
528+
case SqlDatePart.Month: _ = output.Append("MONTH"); break;
529+
default: base.Translate(output, datePart); break;
530+
}
531+
}
532+
533+
/// <inheritdoc/>
534+
public override void Translate(IOutput output, SqlTimePart dateTimePart)
535+
{
536+
switch (dateTimePart) {
537+
case SqlTimePart.Millisecond: _ = output.Append("MICROSECOND"); break;
538+
case SqlTimePart.Hour: _ = output.Append("HOUR"); break;
539+
case SqlTimePart.Minute: _ = output.Append("MINUTE"); break;
540+
default: base.Translate(output, dateTimePart); break;
541+
}
542+
}
543+
#endif
544+
545+
522546
/// <inheritdoc/>
523547
public override void Translate(IOutput output, SqlLockType lockType)
524548
{

Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_6/ServerInfoProvider.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,32 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
1+
// Copyright (C) 2003-2010 Xtensive LLC.
22
// All rights reserved.
33
// For conditions of distribution and use, see license.
44
// Created by: Alena Mikshina
55
// Created: 2013.12.30
66

7+
using Xtensive.Sql.Info;
8+
79
namespace Xtensive.Sql.Drivers.MySql.v5_6
810
{
911
internal class ServerInfoProvider : v5_5.ServerInfoProvider
1012
{
13+
#if NET6_0_OR_GREATER
14+
/// <inheritdoc/>
15+
public override DataTypeCollection GetDataTypesInfo()
16+
{
17+
var types = base.GetDataTypesInfo();
18+
19+
var common = DataTypeFeatures.Default | DataTypeFeatures.Nullable | DataTypeFeatures.NonKeyIndexing |
20+
DataTypeFeatures.Grouping | DataTypeFeatures.Ordering | DataTypeFeatures.Multiple;
21+
22+
var index = DataTypeFeatures.Indexing | DataTypeFeatures.KeyConstraint;
23+
24+
types.TimeOnly = DataTypeInfo.Range(SqlType.Time, common | index, ValueRange.TimeOnly, "time(6)");
25+
26+
return types;
27+
}
28+
#endif
29+
1130
// Constructors
1231

1332
public ServerInfoProvider(SqlDriver driver)

Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/v09/Compiler.cs

Lines changed: 68 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -108,69 +108,77 @@ public override void Visit(SqlTrim node)
108108
public override void Visit(SqlExtract node)
109109
{
110110
switch (node.DateTimeOffsetPart) {
111-
case SqlDateTimeOffsetPart.Day:
112-
DateTimeOffsetExtractPart(node.Operand, "DD").AcceptVisitor(this);
113-
return;
114-
case SqlDateTimeOffsetPart.Hour:
115-
DateTimeOffsetExtractPart(node.Operand, "HH24").AcceptVisitor(this);
116-
return;
117-
case SqlDateTimeOffsetPart.Millisecond:
118-
DateTimeOffsetExtractPart(node.Operand, "FF3").AcceptVisitor(this);
119-
return;
120-
case SqlDateTimeOffsetPart.Nanosecond:
121-
DateTimeOffsetExtractPart(node.Operand, "FF9").AcceptVisitor(this);
122-
return;
123-
case SqlDateTimeOffsetPart.Minute:
124-
DateTimeOffsetExtractPart(node.Operand, "MI").AcceptVisitor(this);
125-
return;
126-
case SqlDateTimeOffsetPart.Month:
127-
DateTimeOffsetExtractPart(node.Operand, "MM").AcceptVisitor(this);
128-
return;
129-
case SqlDateTimeOffsetPart.Second:
130-
DateTimeOffsetExtractPart(node.Operand, "SS").AcceptVisitor(this);
131-
return;
132-
case SqlDateTimeOffsetPart.Year:
133-
DateTimeOffsetExtractPart(node.Operand, "YYYY").AcceptVisitor(this);
134-
return;
135-
case SqlDateTimeOffsetPart.TimeZoneHour:
136-
DateTimeOffsetExtractPart(node.Operand, "TZH").AcceptVisitor(this);
137-
return;
138-
case SqlDateTimeOffsetPart.TimeZoneMinute:
139-
DateTimeOffsetExtractPart(node.Operand, "TZM").AcceptVisitor(this);
140-
return;
141-
case SqlDateTimeOffsetPart.DayOfWeek:
142-
DateTimeExtractDayOfWeek(node.Operand).AcceptVisitor(this);
143-
return;
144-
case SqlDateTimeOffsetPart.DayOfYear:
145-
DateTimeOffsetExtractPart(node.Operand, "DDD").AcceptVisitor(this);
146-
return;
147-
case SqlDateTimeOffsetPart.Date:
148-
DateTimeOffsetTruncate(node.Operand).AcceptVisitor(this);
149-
return;
150-
case SqlDateTimeOffsetPart.DateTime:
151-
DateTimeOffsetTruncateOffset(node.Operand).AcceptVisitor(this);
152-
return;
153-
case SqlDateTimeOffsetPart.LocalDateTime:
154-
DateTimeOffsetToLocalDateTime(node.Operand).AcceptVisitor(this);
155-
return;
156-
case SqlDateTimeOffsetPart.UtcDateTime:
157-
DateTimeOffsetToUtcDateTime(node.Operand).AcceptVisitor(this);
158-
return;
159-
case SqlDateTimeOffsetPart.Offset:
160-
DateTimeOffsetPartOffset(node.Operand).AcceptVisitor(this);
161-
return;
111+
case SqlDateTimeOffsetPart.Day:
112+
DateTimeOffsetExtractPart(node.Operand, "DD").AcceptVisitor(this);
113+
return;
114+
case SqlDateTimeOffsetPart.Hour:
115+
DateTimeOffsetExtractPart(node.Operand, "HH24").AcceptVisitor(this);
116+
return;
117+
case SqlDateTimeOffsetPart.Millisecond:
118+
DateTimeOffsetExtractPart(node.Operand, "FF3").AcceptVisitor(this);
119+
return;
120+
case SqlDateTimeOffsetPart.Nanosecond:
121+
DateTimeOffsetExtractPart(node.Operand, "FF9").AcceptVisitor(this);
122+
return;
123+
case SqlDateTimeOffsetPart.Minute:
124+
DateTimeOffsetExtractPart(node.Operand, "MI").AcceptVisitor(this);
125+
return;
126+
case SqlDateTimeOffsetPart.Month:
127+
DateTimeOffsetExtractPart(node.Operand, "MM").AcceptVisitor(this);
128+
return;
129+
case SqlDateTimeOffsetPart.Second:
130+
DateTimeOffsetExtractPart(node.Operand, "SS").AcceptVisitor(this);
131+
return;
132+
case SqlDateTimeOffsetPart.Year:
133+
DateTimeOffsetExtractPart(node.Operand, "YYYY").AcceptVisitor(this);
134+
return;
135+
case SqlDateTimeOffsetPart.TimeZoneHour:
136+
DateTimeOffsetExtractPart(node.Operand, "TZH").AcceptVisitor(this);
137+
return;
138+
case SqlDateTimeOffsetPart.TimeZoneMinute:
139+
DateTimeOffsetExtractPart(node.Operand, "TZM").AcceptVisitor(this);
140+
return;
141+
case SqlDateTimeOffsetPart.DayOfWeek:
142+
DateTimeExtractDayOfWeek(node.Operand).AcceptVisitor(this);
143+
return;
144+
case SqlDateTimeOffsetPart.DayOfYear:
145+
DateTimeOffsetExtractPart(node.Operand, "DDD").AcceptVisitor(this);
146+
return;
147+
case SqlDateTimeOffsetPart.Date:
148+
DateTimeOffsetTruncate(node.Operand).AcceptVisitor(this);
149+
return;
150+
case SqlDateTimeOffsetPart.DateTime:
151+
DateTimeOffsetTruncateOffset(node.Operand).AcceptVisitor(this);
152+
return;
153+
case SqlDateTimeOffsetPart.LocalDateTime:
154+
DateTimeOffsetToLocalDateTime(node.Operand).AcceptVisitor(this);
155+
return;
156+
case SqlDateTimeOffsetPart.UtcDateTime:
157+
DateTimeOffsetToUtcDateTime(node.Operand).AcceptVisitor(this);
158+
return;
159+
case SqlDateTimeOffsetPart.Offset:
160+
DateTimeOffsetPartOffset(node.Operand).AcceptVisitor(this);
161+
return;
162162
}
163163
switch (node.DateTimePart) {
164-
case SqlDateTimePart.DayOfYear:
165-
DateTimeExtractDayOfYear(node.Operand).AcceptVisitor(this);
166-
return;
167-
case SqlDateTimePart.DayOfWeek:
168-
DateTimeExtractDayOfWeek(node.Operand).AcceptVisitor(this);
169-
return;
170-
default:
171-
base.Visit(node);
172-
return;
164+
case SqlDateTimePart.DayOfYear:
165+
DateTimeExtractDayOfYear(node.Operand).AcceptVisitor(this);
166+
return;
167+
case SqlDateTimePart.DayOfWeek:
168+
DateTimeExtractDayOfWeek(node.Operand).AcceptVisitor(this);
169+
return;
170+
}
171+
#if NET6_0_OR_GREATER //DO_DATEONLY
172+
switch (node.DatePart) {
173+
case SqlDatePart.DayOfYear:
174+
DateTimeExtractDayOfYear(node.Operand).AcceptVisitor(this);
175+
return;
176+
case SqlDatePart.DayOfWeek:
177+
DateTimeExtractDayOfWeek(node.Operand).AcceptVisitor(this);
178+
return;
173179
}
180+
#endif
181+
base.Visit(node);
174182
}
175183

176184
protected override void VisitSelectFrom(SqlSelect node)

0 commit comments

Comments
 (0)