Bug #43972 Schema Information Bug (System.Byte[] and Invalid Cast)
Submitted: 31 Mar 2009 6:44 Modified: 17 Apr 2009 20:32
Reporter: Armando Bañuelos Email Updates:
Status: Can't repeat Impact on me:
None 
Category:Connector / NET Severity:S1 (Critical)
Version:5.2.5, 6.0.0 OS:Any (Error in Schema Information)
Assigned to: CPU Architecture:Any
Tags: .net, 5.2.5, 6.0.0, cast, configure, System.Byte[], TableAdapter

[31 Mar 2009 6:44] Armando Bañuelos
Description:
Good Day,
first of all, there are 2 bugs in the SchemaProvider.cs file. At least is broken compatibility with 4.1.11 servers.
The first, is that MetaData information of GetColumns(COLUMN_DEFAULT and CHARACTER_SET_NAME), and GetIndexes(INDEX_NAME, TABLE_NAME, PRIMARY) is returned incorrectly (Returned as System.Byte[], or compared incorrectly). I readed that is a bug of the Server, I also noted that the flag "Respect Binary Flag" fixes the behaviour, but I think the Driver should read correctly, cause its database metadata.

The second bug is in the GetIndexes, SEQ_IN_INDEX and NON_UNIQUE. 
Both are byte, and you cast to long, and Visual Studio 8 & 9 complains to generate Update and Delete statements and modify the TableAdapter.

The third bug is when you try to Alter Table with Foreign Keys you get a Incorrect Table Name 'System.Byte[]'. Also if table have not Foreign Keys you get some weird info.

How to repeat:
Create a table in MySQL 4.1.11, and show in Visual Studio Explorer.

CREATE TABLE  test (
  `id` varchar(5) NOT NULL default '',
  `id_ref` varchar(5) NOT NULL default '',
  `desc` varchar(45) NOT NULL default '',
  PRIMARY KEY  (`id`),
  CONSTRAINT `FK_TEST` FOREIGN KEY (`id_ref`) REFERENCES `test` (`id`)
) ENGINE=InnoDB;

Show the columns and the information is incorrect (System.Byte[]).

Try to configure a DataAdapter and you receive and 'Invalid Cast' and no Update, Delete Statements are Generated.

Try to 'Alter Table' and Gets incorrect or no data.

Suggested fix:
=> SchemaProvider.cs

LoadTableColumns(...)

Change:
row["COLUMN_DEFAULT"] = reader.GetValue(5);
...
row["CHARACTER_SET_NAME"] = reader.GetValue(2);

To:
row["COLUMN_DEFAULT"] = GetString(reader, 5);
...
row["CHARACTER_SET_NAME"] = GetString(reader, 2);

GetIndexes(...)
You can change to iterate a Reader instead of use DataTable.Fill, or you can change:

From:
long seq_index = (long)index["SEQ_IN_INDEX"];
...
row["INDEX_NAME"] = index["KEY_NAME"];
row["TABLE_NAME"] = index["TABLE"];
row["UNIQUE"] = (long)index["NON_UNIQUE"] == 0;
row["PRIMARY"] = index["KEY_NAME"].Equals("PRIMARY");

To:
long seq_index = Convert.ToInt64(index["SEQ_IN_INDEX"]);
...
row["INDEX_NAME"] = GetStringMetaData(index["KEY_NAME"]);
row["TABLE_NAME"] = GetStringMetaData(index["TABLE"]);
row["UNIQUE"] = Convert.ToInt64(index["NON_UNIQUE"]) == 0;
row["PRIMARY"] = row["INDEX_NAME"].Equals("PRIMARY");

//Add this method
private string GetStringMetaData(object value)
        {
            if (value != null)
            {
                if (value is byte[])
                {
                    //As of MySQL 4.1, the server now treats its metadata using the UTF-8 encoding
                    return Encoding.UTF8.GetString((byte[])value);
                }
                return value.ToString();
            }
            return null;
        }

=> MySqlConnectionSupport.cs
internal static DataTable ConvertAllBinaryColumns(DataTable dt)
...
//FIX:Could be DBNull
if (column.DataType == typeof(System.Byte[]) && row[column.Ordinal] != System.DBNull.Value)
	newRow[column.Ordinal] = e.GetString((byte[])row[column.Ordinal]);
...

=> IndexDescriptor.cs
ReadTable(...)
...
//BUG: Index Metadata in version 4.1.11 read as Byte[]
indexes = MySqlConnectionSupport.ConvertAllBinaryColumns(indexes);
// Fetch data
FetchData(restrictions, table, indexes, result);
...

Also I suggest the following Tests:
GetSchemaTests(...)
//FIX: It supported also in 4.1.11, not only 5.0.0
if (version < new Version(4, 1, 11)) return;
...
//FIX: Some Schema Strings as System.Byte[]
Assert.AreNotEqual("System.Byte[]", dt.Rows[0]["INDEX_NAME"]);
Assert.AreNotEqual("System.Byte[]", dt.Rows[0]["INDEX_CATALOG"]);
Assert.AreNotEqual("System.Byte[]", dt.Rows[0]["INDEX_SCHEMA"]);
Assert.AreNotEqual("System.Byte[]", dt.Rows[0]["INDEX_NAME"]);
Assert.AreNotEqual("System.Byte[]", dt.Rows[0]["TABLE_NAME"]);
[7 Apr 2009 9:33] Tonci Grgin
Hi Armando and thanks for your report.

Partially I have reported it in Bug#43991 (fixed). Can you please make complete test case for second part of your report? Are you using MySQL server 4.1 or higher?
[9 Apr 2009 23:44] Armando Bañuelos
Hi!
I'm using server 4.1.11 .
Ok, the second part of the report is an issue casting the variable. You asume is long, but it returns another type at runtime. So i think you must convert it, and not only cast the value.
[17 Apr 2009 9:56] Bogdan Degtyariov
VS 2005 Server explorer displayed the list of table columns correctly for me.
I used MySQL Server 4.1.11 and Connector/NET 6.0.
Did I miss anything?
[17 Apr 2009 20:32] Armando Bañuelos
I checked and is present in 5.2.5 and also in 6.0.0.

1) Do a normal connection, Don't modify anything.

2) The Server Explorer shows tables and columns, but carefully check the Columns properties "Character Set", "Collation", "Default Value" they apper to be "System.Byte[]"

3) Try to do an "Alter Table" in the Table in Server Explorer.

Hope you can repeat it.
Try to follow the screenshoots with the Problem.
Thanks.
[17 Apr 2009 20:38] Armando Bañuelos
Incorrect Column Information

Attachment: ScreenShoot-1.PNG (image/png, text), 157.16 KiB.

[17 Apr 2009 20:39] Armando Bañuelos
Error trying to "Alter Table"

Attachment: ScreenShoot-2.PNG (image/png, text), 280.70 KiB.