Firebird .NET Data Provider reads Guids incorrectly on little-endian systems ----------------------------------------------------------------------------
Key: DNET-509 URL: http://tracker.firebirdsql.org/browse/DNET-509 Project: .NET Data provider Issue Type: Bug Components: ADO.NET Provider Affects Versions: 3.0.2.0 Reporter: Herman Schoenfeld Assignee: Jiri Cincura On a little-endian systems Guids values are not being correctly hydrated by the Firebird ADO.NET provider. For example, a user may insert a Guid via a query of the form ..." INSERT INTO MyTable VALUES (UUID_TO_CHAR(" + guid.ToString() + " ))" But when that user loads the Guid back via the provider (on a little endian system), the value is different than the correct value stored on the database value. The problem is that Uuid & Guid vary in storage format but not it presentation format.The The CHAR(16) octets contain the Uuid bytes in big endian layout. When hydrating these bytes into a Guid, the provider does not compensate for the Guid's storage of certain parts as the native endian. The correct way to parse the uuid into a guid is: var rfc4122bytes = ... uuid byte array returned from firebird .. if (BitConverter.IsLittleEndian) { Array.Reverse(rfc4122bytes, 0, 4); Array.Reverse(rfc4122bytes, 4, 2); Array.Reverse(rfc4122bytes, 6, 2); } var guid = new Guid(rfc4122bytes); Suspected location of bug is in class 'DbValue' method 'GetGuid'. As a work-around, I've written a wrapper for the FbDataReader which will correct the invalid guid value. public class FirebirdCorrectingReader : IDataReader { private readonly IDataReader _decoratedReader; public FirebirdCorrectingReader(IDataReader decoratedReader) { _decoratedReader = decoratedReader; } #region IDataReader Impl public void Dispose() { _decoratedReader.Dispose(); } public string GetName(int i) { return _decoratedReader.GetName(i); } public string GetDataTypeName(int i) { return _decoratedReader.GetDataTypeName(i); } public Type GetFieldType(int i) { return _decoratedReader.GetFieldType(i); } public object GetValue(int i) { var result = _decoratedReader.GetValue(i); if (result is Guid) { result = CorrectGuid((Guid)result); } return result; } public int GetValues(object[] values) { return _decoratedReader.GetValues(values); } public int GetOrdinal(string name) { return _decoratedReader.GetOrdinal(name); } public bool GetBoolean(int i) { return _decoratedReader.GetBoolean(i); } public byte GetByte(int i) { return _decoratedReader.GetByte(i); } public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) { return _decoratedReader.GetBytes(i, fieldOffset, buffer, bufferoffset, length); } public char GetChar(int i) { return _decoratedReader.GetChar(i); } public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) { return _decoratedReader.GetChars(i, fieldoffset, buffer, bufferoffset, length); } public Guid GetGuid(int i) { return CorrectGuid(_decoratedReader.GetGuid(i)); } public short GetInt16(int i) { return _decoratedReader.GetInt16(i); } public int GetInt32(int i) { return _decoratedReader.GetInt32(i); } public long GetInt64(int i) { return _decoratedReader.GetInt64(i); } public float GetFloat(int i) { return _decoratedReader.GetFloat(i); } public double GetDouble(int i) { return _decoratedReader.GetDouble(i); } public string GetString(int i) { return _decoratedReader.GetString(i); } public decimal GetDecimal(int i) { return _decoratedReader.GetDecimal(i); } public DateTime GetDateTime(int i) { return _decoratedReader.GetDateTime(i); } public IDataReader GetData(int i) { return _decoratedReader.GetData(i); } public bool IsDBNull(int i) { return _decoratedReader.IsDBNull(i); } public int FieldCount { get { return _decoratedReader.FieldCount; } } object IDataRecord.this[int i] { get { return _decoratedReader[i]; } } object IDataRecord.this[string name] { get {return _decoratedReader[name]; } } public void Close() { _decoratedReader.Close(); } public DataTable GetSchemaTable() { return _decoratedReader.GetSchemaTable(); } public bool NextResult() { return _decoratedReader.NextResult(); } public bool Read() { return _decoratedReader.Read(); } public int Depth { get { return _decoratedReader.Depth; } } public bool IsClosed { get { return _decoratedReader.IsClosed; } } public int RecordsAffected { get { return _decoratedReader.RecordsAffected; } } #endregion public static Guid CorrectGuid(Guid badlyParsedGuid) { var rfc4122bytes = badlyParsedGuid.ToByteArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(rfc4122bytes, 0, 4); Array.Reverse(rfc4122bytes, 4, 2); Array.Reverse(rfc4122bytes, 6, 2); } return new Guid(rfc4122bytes); } } -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://tracker.firebirdsql.org/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira ------------------------------------------------------------------------------ This SF.net email is sponsored by Windows: Build for Windows Store. http://p.sf.net/sfu/windows-dev2dev _______________________________________________ Firebird-net-provider mailing list Firebird-net-provider@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/firebird-net-provider