set bytea_output = hex;
\pset tuples_only on
\pset format unaligned

create or replace function check_conv(
  src_encoding name,
  dest_encoding name,
  mule_id int
) returns setof text strict language plpgsql as $$
declare
  printerrs bool := false;
  -- "true" prints error message text too, which is not too helpful when
  -- comparing 9.5 against HEAD, because of bogus "MULE_INTERNAL" references
  c int;
  cbytea bytea;
  trbytea bytea;
  trback bytea;
  errtext text;
begin
  for c in 0..255 loop
    if c >= 128 and src_encoding = 'MULE_INTERNAL' then
      cbytea := set_byte('  ', 0, mule_id);
      cbytea := set_byte(cbytea, 1, c);
    else
      cbytea := set_byte(' ', 0, c);
    end if;
    begin
      trbytea = convert(cbytea, src_encoding, dest_encoding);
      errtext := '';      
    exception when sqlstate '22P05' or sqlstate '22021' then
      GET STACKED DIAGNOSTICS errtext = MESSAGE_TEXT;
      trbytea := '\x00';
    end;
    if trbytea <> '\x00' then
      return next 'convert '::text || cbytea || ' from ' || src_encoding || ' to ' || dest_encoding || ' produced ' || trbytea;
    else
      if printerrs then
        return next 'convert '::text || cbytea || ' from ' || src_encoding || ' to ' || dest_encoding || ' failed: ' || errtext;
      else
        return next 'convert '::text || cbytea || ' from ' || src_encoding || ' to ' || dest_encoding || ' failed';
      end if;
    end if;
    if trbytea <> '\x00' then
      trback = convert(trbytea, dest_encoding, src_encoding);
      if trback <> cbytea then
        return next 'convert '::text || cbytea || ' from ' || src_encoding || ' to ' || dest_encoding || ' reverse conversion produced ' || trback;
      end if;
    end if;
  end loop;
end
$$;

select check_conv('KOI8-R', 'MULE_INTERNAL', 139);
select check_conv('MULE_INTERNAL', 'KOI8-R', 139);
select check_conv('ISO-8859-5', 'MULE_INTERNAL', 139);
select check_conv('MULE_INTERNAL', 'ISO-8859-5', 139);
select check_conv('WIN1251', 'MULE_INTERNAL', 139);
select check_conv('MULE_INTERNAL', 'WIN1251', 139);
select check_conv('WIN866', 'MULE_INTERNAL', 139);
select check_conv('MULE_INTERNAL', 'WIN866', 139);

select check_conv('ISO-8859-5', 'KOI8-R', 139);
select check_conv('KOI8-R', 'ISO-8859-5', 139);
select check_conv('WIN1251', 'KOI8-R', 139);
select check_conv('KOI8-R', 'WIN1251', 139);
select check_conv('WIN866', 'KOI8-R', 139);
select check_conv('KOI8-R', 'WIN866', 139);
select check_conv('WIN866', 'WIN1251', 139);
select check_conv('WIN1251', 'WIN866', 139);
select check_conv('ISO-8859-5', 'WIN1251', 139);
select check_conv('WIN1251', 'ISO-8859-5', 139);
select check_conv('ISO-8859-5', 'WIN866', 139);
select check_conv('WIN866', 'ISO-8859-5', 139);

select check_conv('WIN1250', 'ISO-8859-2', 130);
select check_conv('ISO-8859-2', 'WIN1250', 130);
