Bug #46453 | MySql .NET connector strange behaviour | ||
---|---|---|---|
Submitted: | 29 Jul 2009 15:54 | Modified: | 23 Jun 2010 23:33 |
Reporter: | Bogdan Patru | Email Updates: | |
Status: | Can't repeat | Impact on me: | |
Category: | Connector / NET | Severity: | S2 (Serious) |
Version: | 6.0.4.0 | OS: | Windows (XP 64bit) |
Assigned to: | Vladislav Vaintroub | CPU Architecture: | Any |
Tags: | DataTable.Load, primary key |
[29 Jul 2009 15:54]
Bogdan Patru
[30 Jul 2009 9:05]
Tonci Grgin
Hi Bogdan and thanks for your report. I fail to see anything strange here. With strict condition on one column of course it's declared as PK for your particular query. Please do the same test in mysql command line client and do also DESCRIBE SELECT and see what happens.
[3 Aug 2009 8:52]
Bogdan Patru
I've uploaded two photos of what MySql says when I do The describe. (bug46453_pic1 and 2) I've also uploaded two photos with query results. (bug46453_queryres1 and 2) As you can see from the result photos the primary key is set to PartNoId. For the first query .Net driver does not set any primary key. But the .Net driver sets for the second query the 'CompanyId' field as a primary key which is not correct. What is wrong then? Should there be for the first query at least PartNoId as the primary key? Why the driver says 'CompanyId' is the first query when: - the property IsKey is set to true - the property IsUnique is set to false
[3 Aug 2009 8:52]
Bogdan Patru
DESCRIBE on first query
Attachment: bug46453_pict1.png (image/png, text), 139.77 KiB.
[3 Aug 2009 8:53]
Bogdan Patru
DESCRIBE on second query
Attachment: bug46453_pict2.png (image/png, text), 136.34 KiB.
[3 Aug 2009 8:53]
Bogdan Patru
Query results first query
Attachment: bug46453_queryres1.png (image/png, text), 167.18 KiB.
[3 Aug 2009 8:53]
Bogdan Patru
Query results second query
Attachment: bug46453_queryres2.png (image/png, text), 167.17 KiB.
[3 Aug 2009 8:55]
Bogdan Patru
One mistake, The last 3 lines of previous comment are: Why the driver says 'CompanyId' is the primary key for the second query when: - the property IsKey is set to true - the property IsUnique is set to false
[3 Aug 2009 11:12]
Tonci Grgin
Bogdan, my guess is c/NET tries to do it's best... Let's look at first query: mysql> explain SELECT SP.PartNo, SPC.Description, C.Name AS CompanyName, SP.P KID AS PartNoId, C.PKID AS CompanyId FROM aeropartslocator.StockParts SP INNER JOIN aeropartslocator.StockPartsCompany SPC ON SP.PKID=SPC.PartId INNER JOIN aeropartslocator.Companies C ON SPC.CompanyId=C.PKID WHERE (SP.PartNo LIKE '%an3%' OR SP.PartNoStripped LIKE '%an3%' OR PC.Description LIKE '%an3%') AND (SPC.Spareable=1 OR CompanyId IN (2)) ORDER BY SP.PartNo LIMIT 0,10; +----+-------------+-------+--------+---------------------+---------+---------+- -------------------------------+------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------------+---------+---------+- -------------------------------+------+---------------------------------+ | 1 | SIMPLE | SP | ALL | PRIMARY | NULL | NULL | NULL | 1 | Using temporary; Using filesort | | 1 | SIMPLE | SPC | ALL | UQ_CompanyId_PartId | NULL | NULL | NULL | 1 | Using where; Using join buffer | | 1 | SIMPLE | C | eq_ref | PRIMARY | PRIMARY | 4 | aeropartslocator.SPC.CompanyId | 1 | | +----+-------------+-------+--------+---------------------+---------+---------+- -------------------------------+------+---------------------------------+ So, no keys are used at all, thus c/NET can't use them too. Second query: mysql> explain SELECT SP.PartNo, SPC.Description, C.Name AS CompanyName, SP.PKID AS PartNoId, C.PKID AS CompanyId FROM aeropartslocator.StockParts SP INNER JOIN aeropartslocator.StockPartsCompany SPC ON SP.PKID=SPC.PartId INNER JOIN aeropartslocator.Companies C ON SPC.CompanyId=C.PKID WHERE (SP.PartNo LIKE '%an3%' OR SP.PartNoStripped LIKE '%an3%' OR PC.Description LIKE '%an3%') AND CompanyId IN (2) ORDER BY `PartNo` LIMIT 0,10; +----+-------------+-------+------+---------------+------+---------+------+----- -+-----------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+----- -+-----------------------------------------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables | +----+-------------+-------+------+---------------+------+---------+------+----- -+-----------------------------------------------------+ So this query is screwed up as I have no data in tables. I guess the only constant c/NET can pick on is "AND CompanyId IN (2)". So I'd expect for CompanyId to be a PK here but that breaks your schema. So I guess, the real question would be how is c/NET determining PK for such queries, right? To check on that I'll need some data too. Can you attach a dump with relevant portion of data please?
[12 Aug 2009 10:28]
Bogdan Patru
Hello, Please find in the upload some data. All the best, Bogdan
[14 Aug 2009 7:08]
Tonci Grgin
Bogdan, using test case similar to yours, I get proper result for both queries (PK is dt.Column[0]): MySqlConnection conn = new MySqlConnection(); conn.ConnectionString = "DataSource=**;Database=**;UserID=**;Password=**;PORT=**;Allow Zero Datetime=True;allow user variables = true; respect binary flags=false"; conn.Open(); //MySqlCommand cmdCreateTable = new MySqlCommand("SELECT SP.PartNo, SPC.Description, C.Name AS CompanyName, SP.PKID AS PartNoId, C.PKID AS CompanyId " + // "FROM aeropartslocator.StockParts SP "+ // "INNER JOIN aeropartslocator.StockPartsCompany SPC ON SP.PKID=SPC.PartId "+ // "INNER JOIN aeropartslocator.Companies C ON SPC.CompanyId=C.PKID "+ // "WHERE (SP.PartNo LIKE '%an3%' OR SP.PartNoStripped LIKE '%an3%' OR SPC.Description LIKE '%an3%') AND (SPC.Spareable=1 OR CompanyId IN (2)) "+ // "ORDER BY SP.PartNo LIMIT 0,10", conn); MySqlCommand cmdCreateTable = new MySqlCommand("SELECT SP.PartNo, SPC.Description, C.Name AS CompanyName, SP.PKID AS PartNoId, C.PKID AS CompanyId " + "FROM aeropartslocator.StockParts SP " + "INNER JOIN aeropartslocator.StockPartsCompany SPC ON SP.PKID=SPC.PartId " + "INNER JOIN aeropartslocator.Companies C ON SPC.CompanyId=C.PKID " + "WHERE (SP.PartNo LIKE '%an3%' OR SP.PartNoStripped LIKE '%an3%' OR SPC.Description LIKE '%an3%') AND CompanyId IN (2) " + "ORDER BY SP.PartNo LIMIT 0,10", conn); cmdCreateTable.CommandTimeout = 0; DataTable dt = new DataTable(); MySqlDataAdapter da = new MySqlDataAdapter(cmdCreateTable); da.Fill(dt); DisplayData(dt); dt.Clear(); dt.Dispose(); da.Dispose(); cmdCreateTable.Dispose(); conn.Close(); Console.WriteLine("Done."); Now I will check with test case closer to yours.
[14 Aug 2009 7:26]
Tonci Grgin
Test case
Attachment: Bug46453.txt (text/plain), 2.28 KiB.
[14 Aug 2009 7:37]
Tonci Grgin
Hi Bogdan. Truly, second test case (attached) produces different result than first one I made: 1st query - no keys 2nd query - ColumnName = CompanyId ColumnOrdinal = 5 ColumnSize = 11 NumericPrecision = 0 NumericScale = 0 IsUnique = False IsKey = True BaseCatalogName = BaseColumnName = PKID BaseSchemaName = aeropartslocator BaseTableName = Companies DataType = System.Int32 AllowDBNull = False ProviderType = 3 IsAliased = IsExpression = IsIdentity = IsAutoIncrement = True IsRowVersion = False IsHidden = IsLong = False IsReadOnly = False ============================ Now I see two problems here: o Different behavior of first and second test case: DataTable dt = new DataTable(); MySqlDataAdapter da = new MySqlDataAdapter(cmdQry); da.Fill(dt); vs. MySqlDataReader dr = cmdQry.ExecuteReader(); DataTable SchemaTable = dr.GetSchemaTable(); o PK based on CONST which is contradiction in itself since all of the rows in data table have CompanyId of 2... However, updatability of this type of query is highly doubtful thus I do not see the problem reported here as serious. Can you give me a use case proving this is a major culprit?
[14 Aug 2009 9:39]
Bogdan Patru
Hello Tonci, You probably need to put in app.config or web.config the following lines <system.data> <DbProviderFactories> <clear/> <!-- To get PublicKeyToken run "sn -T my.dll" --> <add name="MySql 5 Provider" invariant="MySql.Data" description=".Net Framework Data Provider for Mysql" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.0.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"/> </DbProviderFactories> </system.data> This is my code: =============================== string _Provider = "MySql.Data"; string _ConnectionString = "Server=**;Port=3306;Uid=**;Pwd=**;Connect Timeout=30;"; DbProviderFactory _factory = DbProviderFactories.GetFactory(_Provider); DBConnection _conn = _factory.CreateConnection(); _conn.ConnectionString = _ConnectionString; _conn.Open(); System.Data.IDataReader _dr = null; DbCommand _comm = _factory.CreateCommand(); _comm.Connection = _conn; // please replace here sSql with each query. _comm.CommandText = sSql; _dr = _comm.ExecuteReader(); // schema table is used to see why I was getting the errors DataTable SchemaTable = _dr.GetSchemaTable(); DataTable _dt = new DataTable(); _dt.Load(_dr); // with query 1 I get 10 rows in _dt // query 2 returns 10 rows but because of the PK set _dt has 1 row (last of the 10) ================================= As you can see I have a wrapper on top of database dll which allows me to use it with any database without changing a line of code. So I do not use directly mysql classes. All the best, Bogdan
[23 Jun 2010 23:30]
Vladislav Vaintroub
test case
Attachment: test.cs (text/plain), 3.89 KiB.
[23 Jun 2010 23:31]
Vladislav Vaintroub
Could not reproduce using 5.5.5 server and the attached test case.
[23 Jun 2010 23:33]
Vladislav Vaintroub
Closing, based on non-reproducibility. Will reopen if there is any need for clarification or if there is a working test case.