plperl (pack unpack и кодировка)

inforse
Дата: 09.12.2014 10:41:50
Доброе утро!!

Столкнулся с проблемой написания функций на 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


Но на прошлой версии без танцев все чики пуки =(
SmeL_md
Дата: 09.12.2014 11:37:06
select current_setting('bytea_output')

попробуйте выполнить, не помню когда появилось bytea_output и hex по умолчанию
inforse
Дата: 09.12.2014 11:53:54
SmeL_md,

на 9е:
"escape"


На 8.4 : "не распознанный параметр конфигурации"
inforse
Дата: 09.12.2014 14:53:49
И все равно на 8.4 работает, на 9.1 не хочет((( Что ж такое.
После этой команды тож не изменилось ничего.
select current_setting('bytea_output')
Гость_0
Дата: 09.12.2014 23:37:37
inforse
Дата: 11.12.2014 16:37:18
Гость_0,

Большое спасибо!!! Получилось нормально записать в базу)
inforse
Дата: 16.12.2014 11:47:49
Гость_0
inforse,

http://www.postgresql.org/docs/9.1/static/plperl-builtins.html#PLPERL-UTILITY-FUNCTIONS

encode_bytea(string)


Аналог для 8.4 существует? В 9-ку записалось нормально. А вот в 8.4 отказывается.

ОШИБКА:  error from Perl function "sp_test_read_all": неверный входной синтаксис для типа bytea at line 107.