Дали мне тут задачку простенькую: раз в N минут посмотреть в базу, и если там нашлись подходящие записи, вынуть из них пару полей и отослать по почте соответствующим людям. Ничего сложного. Казалось бы.
Набросал за пять минут скриптик, отослал себе письмо тестовое… Опс. Вместо символов валюты фигня какая-то. Вместо евро вопросики, вместо фунтов британских — решёточки. Ну, думаю, чего-то с кодировками в почте напутал. Включил в скрипте отладочную печать, ан нет, оказывается это оно прямо из базы такое приходит.
Иду к DBA, они запускают в своём TOAD’е тот же запрос, и.. у них всё нормально. Евро как евро, фунты как фунты. “А выставь у себя в скрипте явно NLS_CHARACTERSET”, — говорят они, и у тебя тоже будет всё нормально. “А какой?” — спрашиваю я. “А.. фиг его знает. Мы никогда не пробовали его менять, у нас и так всё работает.”
Ну ладно, пошёл, поставил UTF8. Там вроде ж все символы есть, должно работать.. Авотфиг. Евро появлись, а фунты почему-то показываются однобайтовым символом 0xA3. А должен быть U+C2A3.
Пошел гуглить. Нашёл, что в оракле кодировки называются не по-человечески, а чёрт знает как. Правильное название для UTF8 — AL32UTF8. Попробовал. Те же гениталии.
Ну ладно, не выходит с универсальной кодировкой, попробуем что-нибудь однобайтовое, где оба символа есть. ISO-8859-15. По-оракловому это WE8ISO8859P15. Э-э.. фиг: “connect failed: ERROR OCIEnvNlsCreate. Check ORACLE_HOME (Linux) env var or PATH (Windows) and or NLS settings, permissions, etc.” Не знает оно такой кодировки.
Пробую ISO-8859-1, в которой вообще-то евро нет, но вдруг.. С фунтом нормально, он 0xA3, а вместо евро выдают 0xBF, который ¿.
Испробовал ещё одну разновидность ISO-8859-1 под названием WE8ISOICLUK, UTF16 в лице AL16UTF16 и ещё какую-то UTFE. Нэту таких. “connect failed: ERROR OCIEnvNlsCreate …”
Чтоб этим индусам всю их поганую жизнь икалось.
После трёхчасовых проклятий в их адрес я таки подобрал одну кодировку, в которой видно и то, и другое. Поиск ответа оставляется интересующимся читателям в качестве домашнего задания.
Оригинал этой записи в личном блоге.
Любые материалы из этого блога запрещается использовать на сайте livejournal.ru в любой форме и любом объёме.
no subject
строка
NLS_CHARACTERSET
у меня она CL8MSWIN1251
так, что наши ДБА живут в прошлом во времена 1251.
no subject
no subject
AMERICAN_CIS.UTF8
no subject
(UN
---
€
SQL> select (unistr('\00A3')) from dual;
(UN
---
£
no subject
NLS_TERRITORY:AMERICA
NLS_CURRENCY:$
NLS_ISO_CURRENCY:AMERICA
NLS_CHARACTERSET:AL32UTF8
NLS_NCHAR_CHARACTERSET:AL16UTF16
и чё?
no subject
#
И пофиг ему на NLS_LANG, результат от него не зависит. Причем для таких запросов он даже от ora_charset в DBI->connect не зависит, всегда выводятся вопросик и решётка, и всё тут.
no subject
покажи что там лежит на самом деле
select dump(имя_поля)
no subject
Может DBI->connect совсем utf не умеет?
no subject
В целом умеет. Я же написал, в UTF8 евро нормально показываются, а вот фнуты как были однобайтовыми, так и остались.
no subject
226,130,172,50,49 (€21) и 194,163,46,54 (£.6).
0xE2 0x82 0xAC для евро, 0xC2 0xA3 для фунта. Вроде нормальный UTF8. Так какого ж хрена он от фунта отгрызает 0xC2 при перекодировании в тот же самый UTF8?
no subject
no subject
no subject
no subject
NLS_NCHAR_CHARACTERSET:AL16UTF16
Это кодировки внутри бд, NLS_NCHAR_CHARACTERSET это кодировка для nchar полей, NLS_CHARACTERSET для char полей и для sql/plsql.
Т.е. при однобайтной кодировке NLS_CHARACTERSET, например cp1251 нельзя использовать юникод в тексте sql запросов, и процедур, тем не менее юникод хранить можно, в nchar полях. Эти кодировки изменить нельзя, задаются при создании бд.
NLS_NCHAR UTF16 (ucs2) родилась очень давно, это типа deprecated
в NLS_LANG часть после точки, это кодировка клиента, куда перекодировать кодировку бд, utf16 для NLS_LANG не существует.
Проблема dil-а мне кажется в том что его клиент не умеет utf8, и он ищет однобайтную кодировку в которой есть и евро и фунт.
no subject
no subject
no subject
echo €|iconv -f utf8 -t cp1251|iconv -fcp1251 -t utf8
€
Oci без перекодировки выдает utf8
dbi перекодирует в однобайтную
перл перекодирует в utf8
$ echo $LANG
ru_RU.UTF-8
$ echo $NLS_LANG
AMERICAN_AMERICA.UTF8
$ sqlplus
UTF8
SQL> create table utest1(a varchar2(10));
SQL> insert into utest1
select (unistr('\00A3')) from dual
union all
select (unistr('\20AC')) from dual;
SQL> select dump(a),a from utest1;
Typ=1 Len=2: 194,163 £
Typ=1 Len=3: 226,130,172 €
UCS-2
SQL> select (unistr('\00A3')),dump (unistr('\00A3')) from dual
union all
select (unistr('\20AC')),dump(unistr('\20AC')) from dual;
£ Typ=1 Len=2: 0,163
€ Typ=1 Len=2: 32,172
select * from NLS_DATABASE_PARAMETERS;
....
NLS_LANGUAGE AMERICAN
NLS_TERRITORY AMERICA
NLS_CHARACTERSET AL32UTF8
NLS_NCHAR_CHARACTERSET AL16UTF16
....
no subject
no subject
no subject
iconv: illegal input sequence at position 0
no subject
no subject
no subject
export NLS_LANG=AMERICAN_AMERICA.US7ASCII
no subject
Почему при указании на клиенте ISO-8859-1 евро превращается в "¿"?
И главное - почему при указании на клиенте той же UTF8 евро приходит нормально, а фунт портится?
no subject
no subject
это однобайтная кодировка в которой есть и фунт и евро, только что попробвал в ней тоже нормально отображается в sqlplus
Typ=1 Len=2: 194,163
£
Typ=1 Len=3: 226,130,172
€
no subject
тоже все замечательно
Typ=1 Len=2: 194,163
£
Typ=1 Len=3: 226,130,172
€
no subject
no subject
no subject
no subject
den@denzh:~> cat test.pl #!/usr/bin/perl use strict; use warnings; use Getopt::Long; use DBI; $ENV{NLS_LANG} = 'AMERICAN_AMERICA.UTF8'; binmode(STDOUT, ':utf8'); my $dbh = DBI->connect( 'DBI:Oracle:tutf','system','sys' ) or die "can't connect to database"; my $query = 'select a from sys.utest1'; my $sth = $dbh->prepare($query); $sth->execute() or die "can't execute input query"; while (my ($string) = $sth->fetchrow_array()) { print uc $string, "\n"; } $sth->finish(); $dbh->disconnect(); den@denzh:~> perl test.pl £ €no subject
den@denzh:~> perl test.pl |iconv -f ISO8859-15
£
€
установлен у меня
# rpm -qa|grep oracl
oracle-instantclient11.2-jdbc-11.2.0.2.0-1.i386
oracle-instantclient11.2-basic-11.2.0.2.0-1.i386
oracle-instantclient11.2-devel-11.2.0.2.0-1.i386
oracle-instantclient11.2-sqlplus-11.2.0.2.0-1.i386
no subject
instantclient-basiclite а не instantclient-basic
no subject
no subject
И у меня оно ставилось не из пакетов, а из родного ораклового инсталлятора. Хотя сейчас за давностью лет установить, из какого именно, не удастся.
Кстати, в адрес этих индусских пидарасов, твёрдо убеждённых, что на сервере обязаны быть иксы, а без них инсталлятор даже запускаться не собирается, у меня тоже много добрых слов есть. Запускать его на машине, куда попасть можно только через два ssh, то ещё удовольствие. И от рута он, конечно, тоже не работает. Несекьюрно, типа. А после su x-forwarding, естественно, отваливается нафиг, даже если до того его удалось как-то пробросить.
Информиксовский клиент почему-то прекрасно ставится из консоли без всех этих выебонов.
no subject
>что на сервере обязаны быть иксы, а без них инсталлятор даже
>запускаться не собирается, у меня тоже много добрых слов >есть. Запускать его на машине, куда попасть можно только
Это да, за инсталлятор их надо жарить 5000 лет, особенно за картинки в бекграунде. Я раз в полгода ставлю оракл через ssh через спутник, это удовоьствие часа на 3-4. Но на самом деле у них сайлент инстляция, но там сложный файл ответов, и начиная с 10-го, в сайлент режиме уже не требуются X-ы. Ну и клиент вообще ставить не надо, есть instant для всех осей, это просто файлики.
> через два ssh, то ещё удовольствие. И от рута он,
>конечно, тоже не работает. Несекьюрно, типа.
Это кстати по просьбам трудящихся. В информиксовых форумах много лет просили сделать возможность работу инсталлятора не от рута.
>А после su x-forwarding, естественно, отваливается нафиг,
>даже если до того его удалось как-то пробросить.
после su недоступен меджик файл ~root/.Xauthority, наверно его можно копировать и выставить такой-же DISPLAY.