среда, 20 октября 2010 г.

Изменился формат вывода bytea в PostgreSQL 9.0

После перехода на PostgreSQL 9, в одном из приложений, в разработке которого я учавствую, начала возникать ошибка при получении и десериализации данных, которые хранятся в базе данных в поле типа byte. В приложении используется библиотека Npgsql.

Причиной возникновения ошибки стало изменение формата вывода данных типа bytea. До версии PostgreSQL 9 форматом вывода по умолчанию был escape. Начиная с версии PostgreSQL 9 форматом вывода по умолчанию стал hex. Библиотека Npgsql этих изменений еще не учитывает.

Я нашел два способа решения этой проблемы. Первый, это изменение параметра bytea_output в конфигурационном файле postgresql.conf. Нужно убрать комментарий и установить значение escape. Второй способ, это в клиентском коде преобразовать массив из hex-формата в обычный массив байт. Что из себя представляет hex-формат можно прочитать здесь. Вот быстро набросанный код, который получает исходный массив байт:


  1. using (var reader = command.ExecuteReader())
  2. {
  3.   reader.Read();
  4.   data2 = (byte[])reader[0];
  5.  
  6.   byte[] data3 = new byte[(data2.Length - 1) / 2];
  7.   for (int i = 0; i < data3.Length; ++i)
  8.   {
  9.     var hi = byte.Parse(((char)data2[(i + 1) * 2 - 1]).ToString(), NumberStyles.AllowHexSpecifier);
  10.     var lo = byte.Parse(((char)data2[(i + 1) * 2]).ToString(), NumberStyles.AllowHexSpecifier);
  11.     data3[i] = (byte)((hi << 4) | (lo & 0x0F));
  12.   }
  13. }

Скорее всего есть более цивилизованные способы, но я их пока не нашел. :)

4 комментария:

  1. А помимо этой особенности, преимущества от перехода на новую версию заметны?
    З.Ы. Вы стационарный или авто перевели? или что-то свое?

    ОтветитьУдалить
  2. В PostgreSQL 9 много полезных доработок, которые хотелось бы использовать http://wiki.postgresql.org/wiki/Illustrated_9_0. И потоковая репликация и безымянные блоки кода и использование индекса для IS NOT NULL... Перевел уже и стационарный и автомобильный. На выставку повезли на PostgreSQL 9.

    ОтветитьУдалить
  3. Привет, коллега.

    Более цивилизованные способы:
    - если клиентская библиотека использует libpq - обновить libpq до версии >= 9.0 и, возможно, пересобрать/перелинковать клиентскую библиотеку (например, psycopg2 для питона).
    - установить опцию bytea_output в escape в конфиге базы.
    - установить эту опцию на время соединения с помощью запроса SET bytea_output TO escape;

    https://profiles.google.com/temotor/posts/USmApxGi1d9

    ОтветитьУдалить
  4. Привет. Про опцию bytea_output у меня написано. О возможности установления значения на время соединения, это хорошее замечание, спасибо. Что касается libpg, то было бы странным если бы последняя версия работала неправильно. :)

    ОтветитьУдалить