Доброе утро!!
Столкнулся с проблемой написания функций на plperl. Точнее даже с не написанием, а возможно с кодировкой.
Суть проблемы. Есть функция, которая запоковывает в двоичный вид по маске определенную последовательность переменных (float float int shortint). И соответственно записывает в базу. Ну и в обратную сторону unpack, зеркально.
Вот функция на сервере версии
"PostgreSQL 8.4.0 on x86_64-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 4.3.2-1.1astra4.se1) 4.3.2, 64-bit"
CREATE OR REPLACE FUNCTION nku.sp_testsss3()
RETURNS bytea AS
$BODY$
my $val = 14.1234567;
my $timer = 54.489748656;
my $nka = 725564;
my $nip = 14;
$record = pack 'd1 d1 i1 s1', $val, $timer, $nka, $nip;
#$query1 = "insert into nku.table(val, timer, nka, nip) values($val, $timer, $nka, $nip);";
#$rv = spi_exec_query($query1);
#$_SHARED{my_plan} = spi_prepare('update nku.table set bytealen = $1;','BYTEA');
#$rv = spi_exec_prepared($_SHARED{my_plan},$record);
($val, $timer, $nka, $nip) = unpack('d d i s',$record);
return $record;
$BODY$
LANGUAGE plperlu VOLATILE
COST 100;
ALTER FUNCTION nku.sp_testsss3()
OWNER TO postgres;
Она работает, добавляет в базу, возвращает bytea. Все как говориться без проблем. unpack так же нормально распаковывает, и возвращает в первозданном виде.
Проверил, работает, обрадовался, перенес на другой сервер функцию. И..
Таже самая функция начала сыпаться с ошибками:
неверная последовательность байт для кодировки "UTF8": 0xb5
Версия сервера:
"PostgreSQL 9.1.4 on x86_64-unknown-linux-gnu, compiled by gcc (Debian 4.7.1-2) 4.7.1, 64-bit"
Дальше начал копать в сторону кодировок. Кодировки серверов одинаковые:
LC_COLLATE = 'ru_RU.CP1251'
LC_CTYPE = 'ru_RU.CP1251'
Ну думаю может из-за новой версии надо явно указывать что то. Докапался до этого:
CREATE OR REPLACE FUNCTION nku.sp_test_9992()
RETURNS bytea AS
$BODY$
use Encode qw(encode decode is_utf8);
my $val = 14.1234567;
my $timer = 54.489748656;
my $nka = 725564;
my $nip = 14;
#my $record = pack 'd1 d1 s1 s1', $val, $timer, $nka, $nip;
#my $record = pack 'd1d1',$val,$timer; # работает!!!!
my $record = pack 'd1 d1 i1 s1 @19', $val, $timer, $nka ,$nip;
my $str = decode('cp1251', $record);
($val, $timer, $nka, $nip) = unpack('d d i s',$str);
#$query1 = "insert into nku.table(val,timer,nka,nip) values($val, $timer, $nka, $nip);";
#$rv = spi_exec_query($query1);
$_SHARED{my_plan} = spi_prepare('update nku.table set bytealen = $1;','BYTEA');
$rv = spi_exec_prepared($_SHARED{my_plan},$str);
return $str;
$BODY$
LANGUAGE plperlu VOLATILE
COST 100;
ALTER FUNCTION nku.sp_test_9992()
OWNER TO postgres;
Но то что я подогнал, всеравно работает через пень колоду. Во первых в базу не вставляется, хотя выводит такой же результат как и на другом сервере ошибка идентичная при вставке:
ОШИБКА: неверная последовательность байт для кодировки "UTF8": 0xeef8e8
опытным путем выяснил, что она конкретно из-за inserta выскакивает.
Во вторых pack как мне кажется не совсем правильный получился. Без танцев с бубном он не совсем хорошо работает.
В третьих unpack возвращает float вроде бы нормально но с потерей точности, всепоследющие цифры заполняет 9ми. Инты вообще не те, послейдний инт просто пустой.
Уважаемые знатоки. Не подскажете в чем может быть дело? Что изменилось в perl при переходе на 9ую версию постгрес? Что еще можно предпринять? Может кто подскажет синтаксис pack правильный. Вроде почитал, вроде все так сделал.
Как мне кажется дело в пустых символах, их как то надо заполнять, что бы точность не тирялась, и обратно возращались инты нормально. Или я не прав? Если увеличить цифру до 20 после собаки, то сразу выкидывает ошибка:
ОШИБКА: неверная последовательность байт для кодировки "UTF8": 0x00
а при update:
ОШИБКА: неверная последовательность байт для кодировки "UTF8": 0xede5e2
Но на прошлой версии без танцев все чики пуки =(