@roji As discussed yesterday in our call with @ajcvickers and the others, here the information about the AccessViolationException issue I was talking about.
The AccessViolationException issue has been previously discussed in detail in CirrusRedOrg/EntityFrameworkCore.Jet#43 (comment) (and I also referenced it before in #33899 (comment)).
It contains the specific conditions under which the issue appears and also contains the original reproduction code.
I updated the code (simplified it further) and also added projects for ODBC using ADO.NET and for directly using OLE DB via C++.
Both of those added projects work as expected, so this issue is either a System.Data.OleDb issue after all, or it is an OLE DB layer issue, but depends on specific operations that are being performed by ADO.NET, but not by my Working_Jet_OleDb_x64_Native C++ project.
The original post from CirrusRedOrg/EntityFrameworkCore.Jet#43 (comment):
I created the smallest possible sample to reproduce the AccessViolationException.
- The exception will only be thrown when run as an
x64 process. - The exception should be thrown at least once in every 5 app executions.
- I tested with
Microsoft.ACE.OLEDB.16.0 and Microsoft.ACE.OLEDB.12.0. Both will throw the exception (v16 usually very early, when still below 10 iterations; v12 usually after around 50 iterations). - The exception will only be thrown, when a
UNION query as been executed and later a SELECT query over the same table as the UNION query is executed. - This second
SELECT query must return only scalar values (no column reference). - It doesn't matter, what the scalar values are (e.g.
0, 1, NULL). - The count of scalar values of the second
SELECT query must be at least as high as the count of returned fields in the previous UNION query. - It does not matter, if another query is executed in between.
- In case there has been no
AccessViolationException within the first 100 interations, it is very unlikely that they will ever appear within the lifetime of the process. (Though sometimes one is thrown near the 50K mark.)
A couple of examples that will throw:
SELECT [c].[Address]
FROM [Customers] AS [c]
WHERE [c].[City] ='Berlin'UNIONSELECT [c0].[Address]
FROM [Customers] AS [c0]
WHERE [c0].[City] ='London';
SELECT1FROM [Customers] AS [c];
SELECT [c].[Address], [c].[Address]
FROM [Customers] AS [c]
WHERE [c].[City] ='Berlin'UNIONSELECT [c0].[Address], [c0].[Address]
FROM [Customers] AS [c0]
WHERE [c0].[City] ='London';
SELECT1, NULLFROM [Customers] AS [c];
SELECT [c].[Address], [c].[Address]
FROM [Customers] AS [c]
WHERE [c].[City] ='Berlin'UNIONSELECT [c0].[Address], [c0].[Address]
FROM [Customers] AS [c0]
WHERE [c0].[City] ='London';
SELECT1, NULLFROM [Customers] AS [c];
A couple of examples that will not throw:
SELECT [c].[Address]
FROM [Customers] AS [c]
WHERE [c].[City] ='Berlin'UNIONSELECT [c0].[Address]
FROM [Customers] AS [c0]
WHERE [c0].[City] ='London';
SELECT [c].[CustomerID] /* <-- not a scalar value */FROM [Customers] AS [c];
SELECT [c].[Address]
FROM [Customers] AS [c]
WHERE [c].[City] ='Berlin'; /* <-- not a UNION */SELECT1FROM [Customers] AS [c];
SELECT [c].[Address], [c].[Address]
FROM [Customers] AS [c]
WHERE [c].[City] ='Berlin'UNIONSELECT [c0].[Address], [c0].[Address]
FROM [Customers] AS [c0]
WHERE [c0].[City] ='London';
SELECT1/* <-- fewer scalar values than fields in UNION */FROM [Customers] AS [c];
SELECT [c].[Address], [c].[Address]
FROM [Customers] AS [c]
WHERE [c].[City] ='Berlin'UNIONSELECT [c0].[Address], [c0].[Address]
FROM [Customers] AS [c0]
WHERE [c0].[City] ='London';
SELECT1, [c].[CustomerID] /* <-- not just scalar values */FROM [Customers] AS [c];
SELECT [c].[Address]
FROM [Customers] AS [c]
WHERE [c].[City] ='Berlin'UNIONSELECT [c0].[Address]
FROM [Customers] AS [c0]
WHERE [c0].[City] ='London';
SELECT*FROM [Orders] AS [o]; /* <-- table differs from the one used in the UNION */
The following code can be used to reproduce the issue. The code should be run with the latest nightly-build of System.Data.OleDb:
usingSystem;usingSystem.Data.OleDb;namespaceJetProviderExceptionTests{internalstaticclassProgram{privatestaticvoidMain(){Console.WriteLine($"Running as {(Environment.Is64BitProcess?"x64":"x86")} process.");vartagDBPARAMBINDINFOName="tagDBPARAMBINDINFO"+(Environment.Is64BitProcess?string.Empty:"_x86");// Is 2 on x86 and 8 on x64.Console.WriteLine($"{tagDBPARAMBINDINFOName} field alignment is {Type.GetType($"System.Data.OleDb.{tagDBPARAMBINDINFOName}, System.Data.OleDb").StructLayoutAttribute.Pack}.");// Is 8 on both x86 and x64.Console.WriteLine($"tagDBPARAMS field alignment is {Type.GetType("System.Data.OleDb.tagDBPARAMS, System.Data.OleDb").StructLayoutAttribute.Pack}.");Console.WriteLine();Console.WriteLine("Press any key to start...");Console.ReadKey();RunNorthwindTest();}privatestaticvoidRunNorthwindTest(){try{usingvarconnection=newOleDbConnection("Provider=Microsoft.ACE.OLEDB.16.0;Data Source=Northwind.accdb");connection.Open();for(vari=0;i<1000;i++){Console.WriteLine($"{i:000}");//// Select_Union://using(varcommand1=connection.CreateCommand()){command1.CommandText=@"SELECT [c].[Address]FROM [Customers] AS [c]WHERE [c].[City] = 'Berlin'UNIONSELECT [c0].[Address]FROM [Customers] AS [c0]WHERE [c0].[City] = 'London'";using(vardataReader1=command1.ExecuteReader()){while(dataReader1.Read()){}}}/* using (var command15 = connection.CreateCommand()) { command15.CommandText = @"SELECT [c].[Address]FROM [Customers] AS [c]WHERE [c].[City] = 'Madrid'"; using (var dataReader15 = command15.ExecuteReader()) { while (dataReader15.Read()) { } } } *///// Select_bool_closure://using(varcommand2=connection.CreateCommand()){command2.CommandText=@"SELECT 1FROM [Customers] AS [c]";using(vardataReader2=command2.ExecuteReader()){while(dataReader2.Read()){}}}}}catch(AccessViolationExceptione){Console.WriteLine(e);}}}}The code uses the version of the Northwind database we are also now using in our functional tests:
Northwind.zip
There are no transactions and no multi-threading involved to trigger the exception.
[...]
@roji As discussed yesterday in our call with @ajcvickers and the others, here the information about the
AccessViolationExceptionissue I was talking about.The
AccessViolationExceptionissue has been previously discussed in detail in CirrusRedOrg/EntityFrameworkCore.Jet#43 (comment) (and I also referenced it before in #33899 (comment)).It contains the specific conditions under which the issue appears and also contains the original reproduction code.
I updated the code (simplified it further) and also added projects for ODBC using ADO.NET and for directly using OLE DB via C++.
Both of those added projects work as expected, so this issue is either a
System.Data.OleDbissue after all, or it is an OLE DB layer issue, but depends on specific operations that are being performed by ADO.NET, but not by myWorking_Jet_OleDb_x64_NativeC++ project.The original post from CirrusRedOrg/EntityFrameworkCore.Jet#43 (comment):