Новый триал. Сборка 13084.

Привет всем.

На сайте провайдера выложен новый триал, в котором исправлена одна мелкая, но досадная ошибка.

При тестировании провайдера через OLEDB.NET обнаружилось, что провайдер некорректно обрабатывает нулевые ссылки (null), передаваемые через значения параметров запросов.

using System;
using System.Data;
using NUnit;
using NUnit.Framework;

using sys_oledb=System.Data.OleDb;

////////////////////////////////////////////////////////////////////////////////
//class Test_04__bug_with_null_value

public static class Test_04__bug_with_null_value
{
 [Test]
 public static void Test_01__Integer()
 {
  //Connection string from application settings
  string cn_str=TestServices.Conf__GetCnStr();

  using(var cn=new sys_oledb.OleDbConnection(cn_str))
  {
   cn.Open();

   using(var tr=cn.BeginTransaction(IsolationLevel.RepeatableRead))
   {
    var cmd=new sys_oledb.OleDbCommand("insert into TEST_MODIFY_ROW (COL_INTEGER) values(?) returning (COL_INTEGER)",cn,tr);

    cmd.Parameters.Add(null,sys_oledb.OleDbType.Integer).Value=null;
    cmd.Parameters[0].Direction=ParameterDirection.Input;

    cmd.Parameters.Add(null,sys_oledb.OleDbType.Integer).Value=111;
    cmd.Parameters[1].Direction=ParameterDirection.Output;

    var rows_affected=cmd.ExecuteNonQuery();

    Assert.That(rows_affected,Is.EqualTo(1));

    Assert.That(cmd.Parameters[1].Value,Is.SameAs(DBNull.Value));
   }//using tr
  }//using cn
 }//Test_01__Integer

 //-----------------------------------------------------------------------
 [Test]
 public static void Test_02__TimeStamp()
 {
  //Connection string from application settings
  string cn_str=TestServices.Conf__GetCnStr();

  using(var cn=new sys_oledb.OleDbConnection(cn_str))
  {
   cn.Open();

   using(var tr=cn.BeginTransaction(IsolationLevel.RepeatableRead))
   {
    var cmd=new sys_oledb.OleDbCommand("insert into TEST_MODIFY_ROW (COL_TIMESTAMP) values(?) returning (COL_TIMESTAMP)",cn,tr);

    cmd.Parameters.Add(null,sys_oledb.OleDbType.DBTimeStamp).Value=null;
    cmd.Parameters[0].Direction=ParameterDirection.Input;

    cmd.Parameters.Add(null,sys_oledb.OleDbType.DBTimeStamp).Value=DateTime.Now;
    cmd.Parameters[1].Direction=ParameterDirection.Output;

    var rows_affected=cmd.ExecuteNonQuery();

    Assert.That(rows_affected,Is.EqualTo(1));

    Assert.That(cmd.Parameters[1].Value,Is.SameAs(DBNull.Value));
   }//using tr
  }//using cn
 }//Test_02__TimeStamp
};//class Test_04__bug_with_null_value

////////////////////////////////////////////////////////////////////////////////

В первом тесте получалось, что провайдер записывал в базу нулевое значение. И, соответственно, получал его через OUT-параметр.

А во втором — провайдер возвращает ошибку вида:

System.Data.OleDb.OleDbException : Ошибка формирования ib-значения входящего параметра. Позиция 0.
Ошибка формирования ISC_DATE. Некорректный элемент [month]. Допустимый диапазон [1..12].
Год: 0. Месяц: 0. День: 0.
—-> System.InvalidOperationException : Поставщик не смог определить значение DateTime. Например, строка только что была создана, значение по умолчанию для столбца DateTime не было доступно, а потребитель еще не задал нового значения DateTime.

Начиная с новой сборки (13084) провайдер будет трансформировать такие значения параметров в NULL и вышеуказанные тесты будут отрабатывать без проблем.

Немного более подробное описание проблемы.
Вообще говоря, null это не тоже самое что и DBNull.Value. OLEDB.NET передает null-ссылки как данные с состоянием DBSTATUS_S_DEFAULT. А DBNull.Value — как данные с состоянием DBSTATUS_S_ISNULL.

Формально, DBSTATUS_S_DEFAULT означает, что провайдер должен использовать значение по-умолчанию, которое задано для связанной колонки. Однако ни FB, ни IB на текущий момент не поддерживают указание использования DEFAULT значения колонки для параметра запроса. Поэтому приходится передавать NULL. Если я ничего не упустил в этом вопросе.

В дальнейшем, когда такая функциональность будет добавлена в сервер, поведение DBSTATUS_S_DEFAULT будет изменено на правильное. Так что, чисто практический совет, который избавит от неприятных неожиданностей в будущем — используйте DBNull.Value вместо null.

Другое.
В новом триале все бинарники (и 32 и 64 бита) собраны с помощью VS2010.

2 комментария

Ксения  on 25 декабря, 2011

Ммм, заюзали 2010 студию. Поздравляю! IntelliSense там куда приятнее.

P.S. Неужели Вы так любите плюсы? Или у Вас богатое прошлое как кодера на Си? 🙂

Kovalenko  on 26 декабря, 2011

Смешной комментарий. Спасибо.

Leave a Comment