From 5a5eaabeef1d7651cf07419d7616a7ce41583ded Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Sun, 1 Mar 2015 18:21:59 +0000 Subject: [PATCH] * Fix microseconds in MSSQL date/time data types, hidden in data and query grids. * Add support for microsecond precision of MSSQL date/time types in table editor, show these in "Length/Set" column * See http://www.heidisql.com/forum.php?t=17728 --- source/dbconnection.pas | 50 ++++++++++++++----------------------- source/grideditlinks.pas | 22 +++++++++++++--- source/mysql_structures.pas | 22 +++++++++++++--- 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/source/dbconnection.pas b/source/dbconnection.pas index 23ea92a4..ab7d56e0 100644 --- a/source/dbconnection.pas +++ b/source/dbconnection.pas @@ -2111,7 +2111,7 @@ begin if ((ServerVersionInt >= 50300) and Parameters.IsMariaDB) or ((ServerVersionInt >= 50604) and (not Parameters.IsMariaDB)) then begin for i:=Low(FDatatypes) to High(FDatatypes) do begin - if FDatatypes[i].Index in [dtDatetime, dtTime, dtTimestamp] then + if FDatatypes[i].Index in [dtDatetime, dtDatetime2, dtTime, dtTimestamp] then FDatatypes[i].HasLength := True; end; end; @@ -2644,13 +2644,20 @@ begin DataType := Cols.Col('DATA_TYPE'); DataType := DataType.ToUpper.DeQuotedString('"'); Result := Result + CRLF + #9 + QuoteIdent(Cols.Col('COLUMN_NAME')) + ' ' + DataType; + MaxLen := ''; if not Cols.IsNull('CHARACTER_MAXIMUM_LENGTH') then begin MaxLen := Cols.Col('CHARACTER_MAXIMUM_LENGTH'); if MaxLen = '-1' then - Result := Result + '(max)' - else - Result := Result + '(' + MaxLen + ')'; + MaxLen := 'max'; + end else if not Cols.IsNull('NUMERIC_PRECISION') then begin + MaxLen := Cols.Col('NUMERIC_PRECISION'); + if not Cols.IsNull('NUMERIC_SCALE') then + MaxLen := MaxLen + ',' + Cols.Col('NUMERIC_SCALE'); + end else if not Cols.IsNull('DATETIME_PRECISION') then begin + MaxLen := Cols.Col('DATETIME_PRECISION'); end; + if not MaxLen.IsEmpty then + Result := Result + '(' + MaxLen + ')'; if Cols.Col('IS_NULLABLE') = 'NO' then Result := Result + ' NOT'; Result := Result + ' NULL'; @@ -3827,32 +3834,10 @@ end; function TDBConnection.GetDateTimeValue(Input: String; Datatype: TDBDatatypeIndex): String; -var - dt: TDateTime; begin // Return date/time string value as expected by server - case Parameters.NetTypeGroup of - ngMSSQL: begin - try - dt := StrToDateTime(Input); - case Datatype of - dtDate: - Result := SysUtils.FormatDateTime('yyyy"-"mm"-"dd', dt); - dtTime: - Result := SysUtils.FormatDateTime('hh":"nn":"ss', dt); - dtYear: - Result := SysUtils.FormatDateTime('yyyy', dt); - dtDatetime: - Result := SysUtils.FormatDateTime('yyyy"-"mm"-"dd hh":"nn":"ss', dt); - end; - except - on E:EConvertError do - Result := Input; - end; - end; - else - Result := Input; - end; + // Not sure why there was a conversion required in earlier versions. + Result := Input; end; @@ -5554,6 +5539,8 @@ begin case Datatype(Column).Category of dtcReal: Result := FloatToStr(FCurrentResults.Fields[Column].AsExtended, FFormatSettings); + dtcTemporal: + Result := FormatDateTime(Datatype(Column).Format, FCurrentResults.Fields[Column].AsFloat); else Result := FCurrentResults.Fields[Column].AsString; end; @@ -5792,9 +5779,10 @@ begin break; end; end; - if idx = -1 then - raise EDatabaseError.CreateFmt(_('Column "%s" not available.'), [Column]); - Result := IsNull(idx); + if idx > -1 then + Result := IsNull(idx) + else + Result := True; end; diff --git a/source/grideditlinks.pas b/source/grideditlinks.pas index 366a6aa2..47d652b7 100644 --- a/source/grideditlinks.pas +++ b/source/grideditlinks.pas @@ -8,7 +8,7 @@ uses Windows, Forms, Graphics, Messages, VirtualTrees, ComCtrls, SysUtils, Classes, StdCtrls, ExtCtrls, CheckLst, Controls, Types, Dialogs, Menus, Mask, DateUtils, Math, dbconnection, mysql_structures, helpers, texteditor, bineditor, gnugettext, - StrUtils, System.UITypes; + StrUtils, System.UITypes, SynRegExpr; type // Radio buttons and checkboxes which do not pass key to their parent control @@ -562,7 +562,7 @@ begin case FTableColumn.DataType.Index of dtDate: FMaskEdit.EditMask := '0000-00-00;1; '; - dtDatetime, dtTimestamp, dtInt, dtBigint: begin + dtDatetime, dtDatetime2, dtTimestamp, dtInt, dtBigint: begin if MicroSecondsPrecision > 0 then FMaskEdit.EditMask := '0000-00-00 00\:00\:00.'+StringOfChar('0', MicroSecondsPrecision)+';1; ' else @@ -738,7 +738,7 @@ begin text := DateToStr(d); end; - dtDateTime, dtTimestamp, dtInt, dtBigint: begin + dtDateTime, dtDateTime2, dtTimestamp, dtInt, dtBigint: begin dt := StrToDateTime(FMaskEdit.Text); case FMaskEdit.SelStart of 0..3: dt := IncYear(dt, Offset); @@ -803,8 +803,22 @@ end; function TDateTimeEditorLink.MicroSecondsPrecision: Integer; +var + rx: TRegExpr; begin - Result := MakeInt(FTableColumn.LengthSet); + if not FTableColumn.LengthSet.IsEmpty then + Result := MakeInt(FTableColumn.LengthSet) + else begin + // Find default length of supported microseconds in datatype definition + // See mysql_structures + rx := TRegExpr.Create; + rx.Expression := '\.([^\.]+)$'; + if rx.Exec(FTableColumn.DataType.Format) then + Result := rx.MatchLen[1] + else + Result := 0; + rx.Free; + end; // No microseconds for UNIX timestamp columns if FTableColumn.DataType.Index in [dtInt, dtBigint] then Result := 0; diff --git a/source/mysql_structures.pas b/source/mysql_structures.pas index 7bbe1df0..a52390c1 100644 --- a/source/mysql_structures.pas +++ b/source/mysql_structures.pas @@ -183,7 +183,7 @@ type // MySQL data types TDBDatatypeIndex = (dtTinyint, dtSmallint, dtMediumint, dtInt, dtBigint, dtSerial, dtBigSerial, dtFloat, dtDouble, dtDecimal, dtNumeric, dtReal, dtDoublePrecision, dtMoney, dtSmallmoney, - dtDate, dtTime, dtYear, dtDatetime, dtSmalldatetime, dtTimestamp, dtInterval, + dtDate, dtTime, dtYear, dtDatetime, dtDatetime2, dtSmalldatetime, dtTimestamp, dtInterval, dtChar, dtNchar, dtVarchar, dtNvarchar, dtTinytext, dtText, dtNtext, dtMediumtext, dtLongtext, dtBinary, dtVarbinary, dtTinyblob, dtBlob, dtMediumblob, dtLongblob, dtImage, dtEnum, dtSet, dtBit, dtVarBit, dtBool, dtJson, dtUnknown, @@ -207,6 +207,7 @@ type HasBinary: Boolean; // Can be binary? HasDefault: Boolean; // Can have a default value? DefLengthSet: String; // Should be set for types which require a length/set + Format: String; // Used for date/time values when displaying and generating queries Category: TDBDatatypeCategoryIndex; end; @@ -403,6 +404,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'yyyy-mm-dd'; Category: dtcTemporal; ), ( @@ -417,6 +419,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'hh:nn:ss'; Category: dtcTemporal; ), ( @@ -434,6 +437,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'yyyy'; Category: dtcTemporal; ), ( @@ -449,6 +453,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'yyyy-mm-dd hh:nn:ss'; Category: dtcTemporal; ), ( @@ -466,6 +471,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'yyyy-mm-dd hh:nn:ss'; Category: dtcTemporal; ), ( @@ -941,6 +947,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'hh:nn:ss'; Category: dtcTemporal; ), ( @@ -953,6 +960,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'yyyy-mm-dd'; Category: dtcTemporal; ), ( @@ -963,16 +971,18 @@ var RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'yyyy-mm-dd hh:nn:ss.zzz'; Category: dtcTemporal; ), ( - Index: dtDatetime; + Index: dtDatetime2; Name: 'DATETIME2'; Description: 'Date and time data from January 1,1 AD through December 31, 9999 AD, with an accuracy of three-hundredths of a second, or 3.33 milliseconds.'; - HasLength: False; + HasLength: True; RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'yyyy-mm-dd hh:nn:ss.zzzzzzz'; Category: dtcTemporal; ), ( @@ -983,6 +993,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: True; + Format: 'yyyy-mm-dd hh:nn:ss'; Category: dtcTemporal; ), ( @@ -1329,6 +1340,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: False; + Format: 'yyyy-mm-dd'; Category: dtcTemporal; ), ( @@ -1340,6 +1352,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: False; + Format: 'hh:nn:ss'; Category: dtcTemporal; ), ( @@ -1352,6 +1365,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: False; + Format: 'yyyy-mm-dd hh:nn:ss'; Category: dtcTemporal; ), ( @@ -1363,6 +1377,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: False; + Format: 'yyyy-mm-dd'; Category: dtcTemporal; ), ( @@ -1374,6 +1389,7 @@ var RequiresLength: False; HasBinary: False; HasDefault: False; + Format: 'yyyy-mm-dd hh:nn:ss'; Category: dtcTemporal; ), (