Skip to content

Commit

Permalink
GUID representation aligned with server (DNET-509).
Browse files Browse the repository at this point in the history
  • Loading branch information
cincuranet committed Dec 21, 2017
1 parent 61d6245 commit fdb00e0
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 33 deletions.
Expand Up @@ -826,7 +826,7 @@ protected void WriteRawParameter(XdrStream xdr, DbField field)
break;

case DbDataType.Guid:
xdr.WriteOpaque(field.DbValue.GetGuid().ToByteArray());
xdr.Write(field.DbValue.GetGuid());
break;

case DbDataType.Double:
Expand All @@ -847,7 +847,7 @@ protected void WriteRawParameter(XdrStream xdr, DbField field)
break;

case DbDataType.Boolean:
xdr.Write(Convert.ToBoolean(field.Value));
xdr.Write(field.DbValue.GetBoolean());
break;

default:
Expand Down Expand Up @@ -911,7 +911,7 @@ protected object ReadRawValue(DbField field)
return _database.XdrStream.ReadSingle();

case DbDataType.Guid:
return _database.XdrStream.ReadGuid(field.Length);
return _database.XdrStream.ReadGuid();

case DbDataType.Double:
return _database.XdrStream.ReadDouble();
Expand Down
Expand Up @@ -472,9 +472,9 @@ public long ReadInt64()
return IPAddress.HostToNetworkOrder(BitConverter.ToInt64(ReadBytes(8), 0));
}

public Guid ReadGuid(int length)
public Guid ReadGuid()
{
return new Guid(ReadOpaque(length));
return TypeDecoder.DecodeGuid(ReadOpaque(16));
}

public float ReadSingle()
Expand Down Expand Up @@ -717,6 +717,11 @@ public void Write(DateTime value)
WriteTime(TypeHelper.DateTimeToTimeSpan(value));
}

public void Write(Guid value)
{
WriteOpaque(TypeEncoder.EncodeGuid(value));
}

public void WriteDate(DateTime value)
{
Write(TypeEncoder.EncodeDate(Convert.ToDateTime(value)));
Expand Down
Expand Up @@ -326,7 +326,7 @@ public void SetValue(byte[] buffer)
case IscCodes.SQL_VARYING:
if (DbDataType == DbDataType.Guid)
{
Value = new Guid(buffer);
Value = TypeDecoder.DecodeGuid(buffer);
}
else
{
Expand Down
63 changes: 36 additions & 27 deletions Provider/src/FirebirdSql.Data.FirebirdClient/Common/DbValue.cs
Expand Up @@ -82,13 +82,13 @@ public bool IsDBNull()

public string GetString()
{
if (Field.DbDataType == DbDataType.Text && _value is long)
if (Field.DbDataType == DbDataType.Text && _value is long l)
{
_value = GetClobData((long)_value);
_value = GetClobData(l);
}
if (_value is byte[])
if (_value is byte[] bytes)
{
return Field.Charset.GetString((byte[])_value);
return Field.Charset.GetString(bytes);
}

return _value.ToString();
Expand Down Expand Up @@ -136,16 +136,15 @@ public float GetFloat()

public Guid GetGuid()
{
if (Value is Guid)
switch (_value)
{
return (Guid)Value;
}
else if (Value is byte[])
{
return new Guid((byte[])_value);
case Guid guid:
return guid;
case byte[] bytes:
return TypeDecoder.DecodeGuid(bytes);
default:
throw new InvalidOperationException($"Incorrect {nameof(Guid)} value.");
}

throw new InvalidOperationException("Incorrect Guid value");
}

public double GetDouble()
Expand All @@ -155,29 +154,36 @@ public double GetDouble()

public DateTime GetDateTime()
{
if (_value is TimeSpan)
return new DateTime(0 * 10000L + 621355968000000000 + ((TimeSpan)_value).Ticks);
else if (_value is DateTimeOffset)
return Convert.ToDateTime(((DateTimeOffset)_value).DateTime, CultureInfo.CurrentCulture.DateTimeFormat);
else
return Convert.ToDateTime(_value, CultureInfo.CurrentCulture.DateTimeFormat);
switch (_value)
{
case TimeSpan ts:
return new DateTime(0 * 10000L + 621355968000000000 + ts.Ticks);
case DateTimeOffset dto:
return Convert.ToDateTime(dto.DateTime, CultureInfo.CurrentCulture.DateTimeFormat);
default:
return Convert.ToDateTime(_value, CultureInfo.CurrentCulture.DateTimeFormat);
}
}

public Array GetArray()
{
if (_value is long)
if (_value is long l)
{
_value = GetArrayData((long)_value);
_value = GetArrayData(l);
}

return (Array)_value;
}

public byte[] GetBinary()
{
if (_value is long)
if (_value is long l)
{
_value = GetBlobData(l);
}
if (_value is Guid guid)
{
_value = GetBlobData((long)_value);
return TypeEncoder.EncodeGuid(guid);
}

return (byte[])_value;
Expand All @@ -190,10 +196,13 @@ public int GetDate()

public int GetTime()
{
if (_value is TimeSpan)
return TypeEncoder.EncodeTime((TimeSpan)_value);
else
return TypeEncoder.EncodeTime(TypeHelper.DateTimeToTimeSpan(GetDateTime()));
switch (_value)
{
case TimeSpan ts:
return TypeEncoder.EncodeTime(ts);
default:
return TypeEncoder.EncodeTime(TypeHelper.DateTimeToTimeSpan(GetDateTime()));
}
}

public byte[] GetBytes()
Expand Down Expand Up @@ -312,7 +321,7 @@ public byte[] GetBytes()
return result;

case DbDataType.Guid:
return GetGuid().ToByteArray();
return TypeEncoder.EncodeGuid(GetGuid());

case DbDataType.Boolean:
return BitConverter.GetBytes(GetBoolean());
Expand Down
11 changes: 11 additions & 0 deletions Provider/src/FirebirdSql.Data.FirebirdClient/Common/TypeDecoder.cs
Expand Up @@ -13,6 +13,7 @@
* language governing rights and limitations under the License.
*
* Copyright (c) 2002, 2007 Carlos Guzman Alvarez
* Copyright (c) 2016 - 2017 Jiri Cincura (jiri@cincura.net)
* All Rights Reserved.
*
* Contributors:
Expand All @@ -21,6 +22,7 @@

using System;
using System.Globalization;
using System.Net;

namespace FirebirdSql.Data.Common
{
Expand Down Expand Up @@ -92,5 +94,14 @@ public static bool DecodeBoolean(byte[] value)
{
return value[0] != 0;
}

public static Guid DecodeGuid(byte[] value)
{
var a = IPAddress.HostToNetworkOrder(BitConverter.ToInt32(value, 0));
var b = IPAddress.HostToNetworkOrder(BitConverter.ToInt16(value, 4));
var c = IPAddress.HostToNetworkOrder(BitConverter.ToInt16(value, 6));
var d = new[] { value[8], value[9], value[10], value[11], value[12], value[13], value[14], value[15] };
return new Guid(a, b, c, d);
}
}
}
17 changes: 17 additions & 0 deletions Provider/src/FirebirdSql.Data.FirebirdClient/Common/TypeEncoder.cs
Expand Up @@ -13,6 +13,7 @@
* language governing rights and limitations under the License.
*
* Copyright (c) 2002, 2007 Carlos Guzman Alvarez
* Copyright (c) 2016 - 2017 Jiri Cincura (jiri@cincura.net)
* All Rights Reserved.
*
* Contributors:
Expand All @@ -21,6 +22,7 @@

using System;
using System.Globalization;
using System.Net;

namespace FirebirdSql.Data.Common
{
Expand Down Expand Up @@ -89,5 +91,20 @@ public static byte[] EncodeBoolean(bool value)
{
return new[] { (byte)(value ? 1 : 0) };
}

public static byte[] EncodeGuid(Guid value)
{
var data = value.ToByteArray();
var a = BitConverter.GetBytes(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, 0)));
var b = BitConverter.GetBytes(IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 4)));
var c = BitConverter.GetBytes(IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 6)));
return new[]
{
a[0], a[1], a[2], a[3],
b[0], b[1],
c[0], c[1],
data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]
};
}
}
}
78 changes: 78 additions & 0 deletions Provider/src/FirebirdSql.Data.UnitTests/FbDataReaderTests.cs
Expand Up @@ -13,6 +13,7 @@
* language governing rights and limitations under the License.
*
* Copyright (c) 2002, 2007 Carlos Guzman Alvarez
* Copyright (c) 2017 Jiri Cincura (jiri@cincura.net)
* All Rights Reserved.
*/

Expand Down Expand Up @@ -395,6 +396,83 @@ public void ReadBinaryTest()
transaction.Rollback();
}

[Test]
public void ReadGuidRoundTripTest()
{
using (var cmd = Connection.CreateCommand())
{
var guid = Guid.NewGuid();
var commandText = $"select char_to_uuid('{guid}') from rdb$database";
cmd.CommandText = commandText;
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
Assert.AreEqual(guid, reader.GetGuid(0));
}
else
{
Assert.Fail();
}
}
}
}

[Test]
public void ReadGuidRoundTrip2Test()
{
using (var cmd = Connection.CreateCommand())
{
var commandText = @"
execute block
returns (a varchar(16) character set octets, b varchar(36) character set ascii)
as
declare guid varchar(16) character set octets;
begin
guid = gen_uuid();
for select :guid, uuid_to_char(:guid) from rdb$database into a, b do
begin
suspend;
end
end";
cmd.CommandText = commandText;
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
StringAssert.AreEqualIgnoringCase(reader.GetString(1), reader.GetGuid(0).ToString());
}
else
{
Assert.Fail();
}
}
}
}

[Test]
public void ReadGuidRoundTrip3Test()
{
using (var cmd = Connection.CreateCommand())
{
var guid = Guid.NewGuid();
var commandText = $"select cast(@guid as varchar(16) character set octets) from rdb$database";
cmd.CommandText = commandText;
cmd.Parameters.Add("guid", guid);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
Assert.AreEqual(guid, reader.GetGuid(0));
}
else
{
Assert.Fail();
}
}
}
}

[Test]
public void DNET60_EmptyFieldReadingError()
{
Expand Down

0 comments on commit fdb00e0

Please sign in to comment.