Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUID Type coversion error [DNET376] #381

Closed
firebird-automations opened this issue Apr 3, 2011 · 7 comments
Closed

GUID Type coversion error [DNET376] #381

firebird-automations opened this issue Apr 3, 2011 · 7 comments

Comments

@firebird-automations
Copy link

Submitted by: vinogradniy (vinogradniy)

Attachments:
GuidTests.cs

My first post - http://216.121.112.228/browse/NH-2618 .

Firebird 2.5 store Uuid into left to right convetion as "CHAR(16) CHARACTER SET OCTETS" (see http://www.firebirdfaq.org/faq98/ ). But http://ADO.NET Provider constructs System.Guid with System.Guid(byte[]) constructor, but System.GuidType shoul be constructed with Guid(int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k) for correct representation. Also see Firebird 2.5 builtin fuctions UUID_TO_CHAR() and CHAR_TO_UUID().

System.Guid reflection:
{{{
// Creates a new guid from an array of bytes.
//
public Guid(byte[] b)
{
if (b==null)
throw new ArgumentNullException("b");
if (b.Length != 16)
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Arg_GuidArrayCtor"), "16"));

        \_a = \(\(int\)b\[3\] << 24\) \| \(\(int\)b\[2\] << 16\) \| \(\(int\)b\[1\] << 8\) \| b\[0\];
        \_b = \(short\)\(\(\(int\)b\[5\] << 8\) \| b\[4\]\);
        \_c = \(short\)\(\(\(int\)b\[7\] << 8\) \| b\[6\]\);
        \_d = b\[8\];
        \_e = b\[9\];
        \_f = b\[10\];
        \_g = b\[11\];
        \_h = b\[12\];
        \_i = b\[13\];
        \_j = b\[14\];
        \_k = b\[15\];
    \}


    // Creates a new GUID initialized to the value represented by the
    // arguments\. The bytes are specified like this to avoid endianness issues\.
    //
    public Guid\(int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k\)
    \{
        \_a = a;
        \_b = b;
        \_c = c;
        \_d = d;
        \_e = e;
        \_f = f;
        \_g = g;
        \_h = h;
        \_i = i;
        \_j = j;
        \_k = k;
    \}

}}}

NUnit test:

{{{
[Test]
public void GuidMappingTest()
{
FbCommand createTable = new FbCommand("CREATE TABLE GUID_TEST (INT_FIELD INTEGER, GUID_FIELD CHAR(16) CHARACTER SET OCTETS)", Connection);
createTable.ExecuteNonQuery();
createTable.Dispose();

	  var patternGuid = Guid\.NewGuid\(\);

		// Insert the Guid
		FbCommand insert = new FbCommand\("INSERT INTO GUID\_TEST \(INT\_FIELD, GUID\_FIELD\) VALUES \(@IntField, @GuidValue\)", Connection\);
		insert\.Parameters\.Add\("@IntField", FbDbType\.Integer\)\.Value = this\.GetId\(\);
  insert\.Parameters\.Add\("@GuidValue", FbDbType\.Guid\)\.Value = patternGuid;
		insert\.ExecuteNonQuery\(\);
		insert\.Dispose\(\);

		// Select the value
  FbCommand select = new FbCommand\("SELECT INT\_FIELD, GUID\_FIELD, UUID\_TO\_CHAR\(GUID\_FIELD\) AS FBGUID FROM GUID\_TEST", Connection\);
		using \(FbDataReader r = select\.ExecuteReader\(\)\)
		\{
			if \(r\.Read\(\)\)
			\{
			  var providerGuid = r\.GetGuid\(1\);
      Console\.WriteLine\("patternGuid  = \{0\}", patternGuid\);
      Console\.WriteLine\("providerGuid = \{0\}", providerGuid\);
      Assert\.AreEqual\(patternGuid, providerGuid\);
			  var fbGuidStr = r\.GetString\(2\);
			  var fbGuid = new Guid\(fbGuidStr\);
      Console\.WriteLine\("rfc4122Guid  = \{0\}", fbGuid\);
      Assert\.AreEqual\(patternGuid, fbGuid\);
			\}
		\}
	\}	

}}}

Execution Result:
{{{
GuidMappingTest: Failed

Command:
CREATE TABLE GUID_TEST (INT_FIELD INTEGER, GUID_FIELD CHAR(16) CHARACTER SET OCTETS)
Command:
INSERT INTO GUID_TEST (INT_FIELD, GUID_FIELD) VALUES (@intfield, @GuidValue)
Name:@intfield Type:Integer Value:-169522060
Name:@GuidValue Type:Guid Value:f470fb5b-fbbd-412e-83f9-eb14aa132ad9
Command:
SELECT INT_FIELD, GUID_FIELD, UUID_TO_CHAR(GUID_FIELD) AS FBGUID FROM GUID_TEST
patternGuid = f470fb5b-fbbd-412e-83f9-eb14aa132ad9
providerGuid = f470fb5b-fbbd-412e-83f9-eb14aa132ad9
rfc4122Guid = 5bfb70f4-bdfb-2e41-83f9-eb14aa132ad9

Expected: f470fb5b-fbbd-412e-83f9-eb14aa132ad9
But was: 5bfb70f4-bdfb-2e41-83f9-eb14aa132ad9
}}}

Best regards,
Eugenyi Vinogradnyi (aka ssdi).

@firebird-automations
Copy link
Author

Commented by: vinogradniy (vinogradniy)

Test

@firebird-automations
Copy link
Author

Modified by: vinogradniy (vinogradniy)

Attachment: GuidTests.cs [ 11936 ]

@firebird-automations
Copy link
Author

Commented by: @cincuranet

The second assert is failing. But you're creating Guid from *string* returned by Firebird. This string has different ordering compared to what Guid ctor expects. But the first assert, that really matters as it works with real Guid values, is OK and provider handles it correctly.

@firebird-automations
Copy link
Author

Modified by: @cincuranet

status: Open [ 1 ] => Closed [ 6 ]

resolution: Cannot Reproduce [ 5 ]

@firebird-automations
Copy link
Author

Commented by: vinogradniy (vinogradniy)

Guids obtained through Firebird DSQL and Net Guid (string) have a different view. This is at least misleading and at worst leads to errors.

String from UUID_TO_CHAR() : 5bfb70f4-bdfb-2e41-83f9-eb14aa132ad9
String from Provider : f470fb5b-fbbd-412e-83f9-eb14aa132ad9

@firebird-automations
Copy link
Author

Commented by: @cincuranet

Yes, that's expected. UUID_TO_CHAR returns different byte ordering than Guid.ToString.

@firebird-automations
Copy link
Author

Commented by: vinogradniy (vinogradniy)

See #⁠DNET509.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants