Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ODP.NET : Parameter Types "cached" on identical CommandText

I'm currently evaluating Oracle's ODP.NET DataProvider and I ran into a problem that popped up in one of our testcases: When the same command text is executed with different parameter types, the parameter type of the first executed command is used in all following commands.

Take for example the following code:

const int sampleInt32 = 1234567890;
const string sampleNvarchar = "someTestString";

const string sqlCommandtext = "SELECT :PARAM PARAM FROM DUAL";
using (OracleConnection connection = new OracleConnection(builder.ConnectionString))
{
    connection.Open();

    //Test 1 - Int 32
    using (OracleCommand commandInt32 = connection.CreateCommand())
    {
        commandInt32.CommandText = sqlCommandtext;
        commandInt32.Parameters.Add("PARAM", OracleDbType.Int32, sampleInt32, ParameterDirection.Input);
        using (IDataReader reader = commandInt32.ExecuteReader())
        {
            while (reader.Read())
            {
                int resultInt32 = (int)reader.GetDecimal(0);
                Assert.AreEqual(sampleInt32, resultInt32);
            }
        }
    }
    //Test 2 - NVarchar
    using (OracleCommand commandNVarchar = connection.CreateCommand())
    {
        commandNVarchar.CommandText = sqlCommandtext;
        commandNVarchar.Parameters.Add("PARAM", OracleDbType.NVarchar2, sampleNvarchar, ParameterDirection.Input);
        using (IDataReader reader = commandNVarchar.ExecuteReader())
        {
            while (reader.Read())
            {
                string resultNVarchar = reader.GetString(0);
                Assert.AreEqual(sampleNvarchar, resultNVarchar);
            }
        }
    }
}

If commandInt32 is executed before commandNVarchar, execution of commandNVarchar fails with ORA-01722 - Invalid number. If the order is switched so commandNVarchar is executed first, it fails with "Specified cast is not valid" on reader.GetDecimal.

So far I've tried setting StatementCacheSize=0; Pooling=false; StatementCachePurge=true as ConnectionString parameters but I can't get this to work.

Is there anything I'm missing or are there any other options worth trying?

EDIT: Maybe some background on why this is needed/required: We don't use ODP or any other Dataprovider directly in our application (or at least: we're on our way to reach this goal), there's an DataLayer in between that performs database/provider specific optimiziations and monitoring of connection health,...

In this Layer for example StoredProcedures can be called, having the option of parameter type tuning. Some of our procedures have Clobs as Parameter types, as sometimes the value can be longer than x characters, but most likely it will be shorter. So before executing via ExecuteNonQuery with ArrayBindCount set to y, parameter values are checked if Clob can be passed as varchar (Nclob as Nvarchar). "Rebinding" reduces the time to execute 2500 records from about 500ms to 200ms at the cost of losing a few ms checking string lengths. And this rebinding can only be done if the parameter type can be changed. Without this option we would need to execute it as Clob everytime, taking the performance hit.

like image 693
Linky Avatar asked Feb 15 '23 17:02

Linky


2 Answers

To my understanding, parameter binding is unsupported in a SELECT list. I was so surprised that this worked at all that I had to run your code to see it with my own eyes. I believe that for the client to allow that SQL statement to execute at all is a bug.

Regardless, I inserted the following line between the test cases to get them both to work:

connection.PurgeStatementCache();

However, this only seems to work with the Managed Client (I've tried it with version 4.112.3.60). The regular client still fails as you describe.

like image 158
Vadim K. Avatar answered Feb 18 '23 05:02

Vadim K.


Two things. When used as connection string parameters, the configuration variables need to have spaces, ie

Statement Cache Size=0;

The format you are using can be used directly in the config though: http://docs.oracle.com/html/E10927_01/featConfig.htm#CJABCACG

http://docs.oracle.com/html/E10927_01/featOraCommand.htm#CIHCAFIG

You could use that same configuration section to enable tracing - comparing the traces might give you an idea of what is happening.

I believe PurgeStatementCache (not sure StatementCachePurge exists) is a runtime command, ie

connection.PurgeStatementCache
like image 35
b_levitt Avatar answered Feb 18 '23 06:02

b_levitt