Юникод. Чем буква Я хуже буквы Z?

Глупый Телевизор
Дата: 24.03.2011 10:01:25
Как написано в документации функция lpad:
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions140.htm
left-padded to length n characters
По-моему все несколько иначе.
Для двухбайтных строк она вычитает из желаемой длины текущею длину в байтах. И дополняет символом в количестве полученной разницы.
Это если дополняемый символ считается однобайтным. Если двухбайтным, то дополняет в количестве разница/2. Поячему-то "ё" считается однобайтным, "ы" - двухбайтным.
В результате и в символах и в байтах можно получить самые разнообразнейшие длины.
SQL> select t.s s,
  2         lengthb(t.s) b,
  3         lengthc(t.s) c,
  4         lpad(t.s, 10, '*') s1,
  5         lengthb(lpad(t.s, 10, '*')) b,
  6         lengthc(lpad(t.s, 10, '*')) c,
  7         lpad(t.s, 10, 'ё') s2,
  8         lengthb(lpad(t.s, 10, 'ё')) b,
  9         lengthc(lpad(t.s, 10, 'ё')) c,
 10         lpad(t.s, 10, 'ы') s3,
 11         lengthb(lpad(t.s, 10, 'ы')) b,
 12         lengthc(lpad(t.s, 10, 'ы')) c
 13  from
 14  (select cast('Я' as varchar2(3 char)) s from dual
 15  union all select 'МЫ' from dual
 16  union all select convert('Я','CL8MSWIN1251','AL32UTF8') from dual
 17  union all select convert('МЫ','CL8MSWIN1251','AL32UTF8') from dual
 18  union all select convert('Z','CL8MSWIN1251','AL32UTF8') from dual
 19  ) t;
 
S     B   C S1                     B   C S2                     B   C S3                     B   C
--- --- --- -------------------- --- --- -------------------- --- --- -------------------- --- ---
Я     2   1 ********Я             10   9 ёёёёёёёёЯ             18   9 ыыыыЯ                 10   5
МЫ    4   2 ******МЫ              10   8 ёёёёёёМЫ              16   8 ыыыМЫ                 10   5
Я     1   0 **********            10  10 ёёёёёёёёёё            20  10 ыыыыы                 10   5
МЫ    2   1 *********МЫ           11  10 ёёёёёёёёёМЫ  20  10  ыыыыМЫ           11   6
Z     1   1 *********Z            10  10 ёёёёёёёёёZ            19  10  ыыыыZ                10   6
Вопросы
1. Почему длина в байтах для Z = 1, для Я = 0? То есть почему-то после преобразования для русских букв длина считается как остаток от деления длины в байтах на 2, а для англ. - просто длина в байтах.
2. Почему ё считается однобайтным, ы - двухбайтным.
3. Можно ли как-то сделать, чтоб длина в символах всегда была фиксированная и равнялась 10, независимо от параметров функции (если они корректные)?

З.Ы. Вывод выложил из PL/SQL Developer command window т.к. SQL*Plus работать отказывается.
C:\Windows\system32>chcp 65001
Active code page: 65001

C:\Windows\system32>sqlplus -s / as sysdba
select convert('убей меня','CL8MSWIN1251','AL32UTF8') from dual;

C:\Windows\system32>

Или я что-то не учел или какой-то полный П с этим юникодом...
-2-
Дата: 24.03.2011 10:28:33
Глупый Телевизор,

У тебя основная кодировка какая? lengthc это не длина в символах, это - "uses Unicode complete characters"
orawish
Дата: 24.03.2011 10:44:55
Глупый Телевизор,
dump() используйте - он всё покажет

Глупый Телевизор
..
Или я что-то не учел или какой-то полный П с этим юникодом...

серьёзные основания для такого умозаключения вы не предъявили
(но, имхо, вывод сделали верный )
Глупый Телевизор
Дата: 24.03.2011 11:29:35
-2-
У тебя основная кодировка какая?
SQL> select *
  2  from nls_database_parameters
  3  where parameter like '%CHARACTERSET';
 
PARAMETER                      VALUE
------------------------------ --------------------------------------------------------------------------------
NLS_CHARACTERSET               AL32UTF8
NLS_NCHAR_CHARACTERSET         AL16UTF16
orawish
dump() используйте - он всё покажет
SQL> select t.s s,
  2         lengthb(t.s) b,
  3         lengthc(t.s) c,
  4         length(t.s) l,
  5         lpad(t.s, 10, x) s1,
  6         dump(lpad(t.s, 10, x)) d,
  7         lengthb(lpad(t.s, 10, x)) b,
  8         lengthc(lpad(t.s, 10, x)) c,
  9         length(lpad(t.s, 10, x)) l
 10  from
 11  (select cast('Я' as varchar2(3 char)) s from dual
 12  union all select 'МЫ' from dual
 13  union all select convert('Я','CL8MSWIN1251','AL32UTF8') from dual
 14  union all select convert('МЫ','CL8MSWIN1251','AL32UTF8') from dual
 15  union all select convert('Z','CL8MSWIN1251','AL32UTF8') from dual
 16  ) t,
 17  (
 18  select '*' x from dual union all select 'ё' x from dual union all select 'ы' x from dual
 19  ) p;
 
S     B   C   L S1                   D                                                                                                      B   C   L
--- --- --- --- -------------------- ---------------------------------------------------------------------------------------------------- --- --- ---
Я     2   1   1 ********Я            Typ=1 Len=10: 42,42,42,42,42,42,42,42,208,175                                                         10   9   9
МЫ    4   2   2 ******МЫ             Typ=1 Len=10: 42,42,42,42,42,42,208,156,208,171                                                       10   8   8
Я     1   0   0 **********           Typ=1 Len=10: 42,42,42,42,42,42,42,42,42,42                                                           10  10  10
МЫ    2   1   1 *********МЫ          Typ=1 Len=11: 42,42,42,42,42,42,42,42,42,204,219                                                      11  10  10
Z     1   1   1 *********Z           Typ=1 Len=10: 42,42,42,42,42,42,42,42,42,90                                                           10  10  10
Я     2   1   1 ёёёёёёёёЯ            Typ=1 Len=18: 209,145,209,145,209,145,209,145,209,145,209,145,209,145,209,145,208,175                 18   9   9
МЫ    4   2   2 ёёёёёёМЫ             Typ=1 Len=16: 209,145,209,145,209,145,209,145,209,145,209,145,208,156,208,171                         16   8   8
Я     1   0   0 ёёёёёёёёёё           Typ=1 Len=20: 209,145,209,145,209,145,209,145,209,145,209,145,209,145,209,145,209,145,209,145         20  10  10
МЫ    2   1   1 ёёёёёёёёёМЫ Typ=1 Len=20: 209,145,209,145,209,145,209,145,209,145,209,145,209,145,209,145,209,145,204,219         20  10  10
Z     1   1   1 ёёёёёёёёёZ           Typ=1 Len=19: 209,145,209,145,209,145,209,145,209,145,209,145,209,145,209,145,209,145,90              19  10  10
Я     2   1   1 ыыыыЯ                Typ=1 Len=10: 209,139,209,139,209,139,209,139,208,175                                                 10   5   5
МЫ    4   2   2 ыыыМЫ                Typ=1 Len=10: 209,139,209,139,209,139,208,156,208,171                                                 10   5   5
Я     1   0   0 ыыыыы                Typ=1 Len=10: 209,139,209,139,209,139,209,139,209,139                                                 10   5   5
МЫ    2   1   1  ыыыыМЫ          Typ=1 Len=11: 32,209,139,209,139,209,139,209,139,204,219                                              11   6   6
Z     1   1   1  ыыыыZ               Typ=1 Len=10: 32,209,139,209,139,209,139,209,139,90                                                   10   6   6
 
15 rows selected
Глупый Телевизор
Дата: 24.03.2011 13:33:08
А в продакшене кто-нибудь использует базы с юникодными кодировками?
Потому как если на таких элементарных вещах весьма странное поведение, страшно подумать как обстоит дело с тонкостями.

Вот как написано в статье "Вышла СУБД Oracle Database 11g R2"
http://www.securitylab.ru/news/384542.php
Марк Таунсенд вице-президент подразделения Oracle Database, говорит, что 11g R2 является продуктом примерно 1500 разработчиков и 15 млн часов тестирования.

Что они там тестировали 15 000 000 часов млин???
comphead
Дата: 24.03.2011 15:04:25
Глупый Телевизор
А в продакшене кто-нибудь использует базы с юникодными кодировками?


конечно, всякие буржуйские сапы, зибеля и т.п
softwarer
Дата: 24.03.2011 15:54:09
Что они там тестировали 15 000 000 часов млин???

Ну поделим одно на другое, получим 10'000 часов на разработчика, то есть 1'250 рабочих дней тестирования на каждого разработчика, то есть 5 лет без перерывов при условии 1 тестер на 1 разработчика.

Что-то мне так кажется, что он имеет в виду не версию 11, а затраты на оракл с начала времён. Или тестирование на пользователях :)
comphead
Дата: 24.03.2011 15:59:27
softwarer
Что они там тестировали 15 000 000 часов млин???

Ну поделим одно на другое, получим 10'000 часов на разработчика, то есть 1'250 рабочих дней тестирования на каждого разработчика, то есть 5 лет без перерывов при условии 1 тестер на 1 разработчика.

Что-то мне так кажется, что он имеет в виду не версию 11, а затраты на оракл с начала времён. Или тестирование на пользователях :)


при такой математике картина тогда получится совсем уж печальной :)