Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник |
Коллекция курьезных вопросов из форумов
KOL и MCK |
KOL и MCK - Компактные программы на Delphi
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

TWideStringField.Size - некорректный размер [D2010]


Чемпаркароке ©   (02.08.17 14:15

если использовать кодировку UTF8 и dbExpress, то Size дает ровно в 4 раза больше, чем есть на самом деле, хотя в справке сказано
Size is the maximum number of characters in the string.
т.е. именно символов, а не байтов
если ж взять кодировку win1251, то размер правильный

вопрос - это глюк драйвера или ошибка в документации?
склоняюсь к первому, т.к. поля CHAR(1) вдруг на клиенте вырастают до 4 символов и дополняются пробелами

у кого есть возможность, пожалуйста, проверьте в других версиях Delphi новее 2010


Чемпаркароке ©   (15.08.17 14:38[1]

судя по вопросам, которые я накопал в интернете по этому поводу, болячка старая и запущенная, появилась вместе с юникодом в BDS-2006
за столько лет вполне могла стать фичей, хоть и недокументированной

это проявляется не только в dbExpress, но и в ADO
не имеет значения и кодировка в БД, важно, что указано в настройках коннекта к БД

из всего этого можно сделать вывод, что драйвер тут вряд ли имеет значение, скорее, где-то во внутренностях компонентов доступа к данным недоработка


sniknik ©   (15.08.17 20:55[2]

> но и в ADO
в ADO нет "внутренностей компонентов доступа к данным", это по сути внешний COM объект, в компонентах просто доступ через интерфейсы к ним.

старая и запущенная болячка, она не компонентах, она в головах.


Чемпаркароке ©   (15.08.17 21:10[3]


> sniknik ©   (15.08.17 20:55) [2]

значит, делаешь вывод, что описанное в сабже поведение - нормативное?
или просто к словам цепляешься?


sniknik ©   (15.08.17 23:12[4]

я не делаю вывод, только факты.
в сабже о dbExpress, ничего не знаю про dbExpress... практически не пользовался им. а написал про ADO про которое ты сделал вывод, явно не понимая принципов его работы.


Чемпаркароке ©   (20.08.17 13:54[5]

аналогичная ситуация и при работе через IBX


sniknik ©   (20.08.17 18:49[6]

ну, если это везде так, то видимо одинаково делают... (а чего бы отличатся?)
хотя все одно, говорю только за ADO
он не держит в рекордсете типов utf-8 и другое, только юникод и ansi (локализацию) типы описаны в разделе справки по обьектам ado в разделе DataTypeEnum ( https://docs.microsoft.com/en-us/sql/ado/reference/ado-api/datatypeenum ), ну мелкософт же, чего ему внутри себя с чужими кодировками работать? но это не значит, что не понимает их, в базе может быть в любой, главное правильно указать он/драйвер преобразует из любого имеющегося на машине/в разделе
HKEY_CLASSES_ROOT\MIME\Database\Charset
а вот данные "наружу" (при сохранении в файл/передачи в стриме) используется именно utf-8 ибо спецификация... т.е. нельзя сказать что они не умеют с ним работать, не хотят, ну я бы тоже не хотел учитывая все проблемы при работе в живую на транспортной кодировке.

ты видать пытаешся работать с utf в ansi строках, он позволяет, ибо это его суть - универсальность на стандартных ansi кодах.
а вот это
> и дополняются пробелами
указывает, что тип в базе char(), а не varchar(), это тоже его стандартное поведение дополнять пробелами до указанной в типе длинны, еще с dbase 3 повелось (ну может не 3 но смысл что "стандарт" со времен "царя гороха").


Чемпаркароке ©   (20.08.17 23:00[7]


> указывает, что тип в базе char(), а не varchar(), это тоже
> его стандартное поведение дополнять пробелами до указанной в типе длинны,

поведение верное, но не в данном случае
как я уже сказал поля CHAR(1) вдруг на клиенте вырастают до 4 символов и дополняются пробелами
т.е. в БД - 1 символ длина поля (а не содержимого), в на клиенте уже 4 символа


Чемпаркароке ©   (20.08.17 23:03[8]

т.е. по сути где-то ошибочно подменяется понятие длины поля в символах на длину поля в байтах (т.е. длину места в памяти), необходимых для хранения этих символов


Чемпаркароке ©   (20.08.17 23:04[9]

а для длины в байтах есть отдельное свойство DataSize


rrrrrrr ©   (21.08.17 10:03[10]

открываешь исходники.

смотришь, что сайз объявлен у TField и ссылается на гетсайз который возвращает fSize

У стрингфилд он перенесен в паблишед и никаких доп телодвижений не наблюдается

вайдстрингфилд наследован от тстрингфилд

и тоже никакой особой обработки вокруг размера не имеет.

а размерность полей tfield узнает у  клиентских библиотек сервера.

итого на весь этот захватывающий детектив ушло полторы минуты рассматривания db.pas


sniknik ©   (21.08.17 10:16[11]

> т.е. по сути где-то ошибочно подменяется понятие длины поля в символах на длину поля в байтах
да, у тебя в голове. суть utf-8:
> ибо это его суть - универсальность на стандартных ansi кодах.
т.е. впихивая utf-8 в поле с типом ansi ты просто говоришь ему - это строка символов, обычных. т.к. нет разницы между обычными символами и utf-8, кроме как в интерпретации (договоренности, вот это вот считать utf-8, а это ansi, ну может исключая файлы, там еще определяется BOM, если он есть).


sniknik ©   (21.08.17 10:39[12]

> т.е. в БД - 1 символ длина поля (а не содержимого), в на клиенте уже 4 символа
вообще это неправда... опять ты что то не так интерпретировал. если в базе длинна поля 1 символ для типа utf-8, то она должна быть равна 7 простых символов/байт, а не 4ре. т.к. длинна символов utf-8 переменная от 1го до 7ми (вроде, не охота вникать, как помню, может 8, но точно не 4). в четыре некоторые не влезут в общем, что приведет к ошибкам в базе... что в общем вряд ли, т.к. базы делают обычно грамотные разработчики.


Игорь Шевченко ©   (21.08.17 12:14[13]

sniknik ©   (21.08.17 10:39) [12]

Я тебе открою страшный секрет - при использовании юникодной базы данных Oracle (UTF-8) размер символьного поля в неюникодной версии Delphi получается в 4 раза больше, чем объявленная длина поля в базе данных.
И никому это не мешает.

Базы делают грамотные разработчики, Delphi пишут тоже грамотные разработчики.


sniknik ©   (21.08.17 13:53[14]

может тогда все таки внутреннее представление он держит в UTF-32?
или UTF-16, тоже возможно тут либо одно либо 2 слова на символ. а уже наружу отдает так как программист поле указал...

> И никому это не мешает.
сохрани туда и прочитай обратно какой нибудь семибайтный символ UTF-8. не мешает? тогда как?


rrrrrrr ©   (21.08.17 14:01[15]

как он внутренне складирует это отдельный вопрос. как сказали при установке.
а отдает так как попросишь.


sniknik ©   (21.08.17 14:01[16]

а, понял, посмотрел
https://ru.wikipedia.org/wiki/UTF-8
5 и 6 байтные уже не имеют представления в юникоде
00200000 — 03FFFFFF  5 байт  не используется в Unicode
04000000 — 7FFFFFFF  6 байт  не используется в Unicode

т.е. нет смысла больше размерность делать. просто UTF-8 позволяет до 7ми, а символов под это нет...


sniknik ©   (21.08.17 14:04[17]

> а отдает так как попросишь.
не только в этом вопрос, это как раз очевидно, еще и в том что компонент делфи для такого поля выделяет 4 байта, хотя казалось бы должен 7. но тут может и есть не тоже самое, я ошибся когда подумал, что должно выделять под полный символ.


Чемпаркароке ©   (22.08.17 14:30[18]


> а размерность полей tfield узнает у  клиентских библиотек сервера.

верно, но вопрос, как он интерпретирует то, что получил
особенно, если по пути есть еще драйвер-посредник


rrrrrrr ©   (22.08.17 14:43[19]

заняться ему больше нечем как интерпретацией прямого ответа какого размера поле ему сейчас прилетит.


rrrrrrr ©   (22.08.17 14:49[20]

прототип завода по утилизации как-то уж слишком замороченных погромистов

http://i.makeagif.com/media/6-10-2014/FAQmDj.gif

возрастные ограничения на гиф : 35+


Чемпаркароке ©   (22.08.17 15:19[21]

Firebird 2.5 Language Reference Update

Table 5.1. Character sets new in Firebird
Name   UTF8
Max bytes/ch.   4
Languages   All
Added in   2.0


rrrrrrr ©   (22.08.17 15:26[22]

и што?
тем более что это про типы данных сервера


Чемпаркароке ©   (28.08.17 15:12[23]

докладываю результаты экспериментов

я оказался прав - все дело в интерпретации драйвером

теперь подробно
--------------------------------------
исследуя исходники IBX, наткнулся на
function TIBXSQLVAR.GetCharsetSize: Integer;
begin
 case SQLVar.SQLSubtype and $FF of
   0, 1, 2, 10, 11, 12, 13, 14, 19, 21, 22, 39,
   45, 46, 47, 50, 51, 52, 53, 54, 55, 58 :  Result := 1;
   5, 6, 8, 44, 56, 57, 64 : Result := 2;
   3 :
   begin
     // System Tables incorrectly state they are in Unicode_Fss character set but they are not
     if POS('RDB$', SQLVar.RelName) = 1 then
       Result := 1
     else
       Result := 3;
   end;
   59 : Result := 4;
   else
     Result := 1;
 end;
end;

как видно, в код жестко зашиты идентификаторы чарсетов, причем для UTF8=59
это очень нехорошо, но для IBX, предназначенных для работы с InterBase, это простительно
однако простой анализ таблицы RDB$CHARACTER_SETS в БД на FireBird показывает, что там для UTF8 идентификатор=4, а код 59 соответствует чарсету WIN1256
для эксперимента подсоединяемся к БД с этим чарсетом (хоть через IBX, хоть через dbExpress) и - вуаля! - размер поля на клиенте становится корректным

из всего этого можно сделать несколько выводов:
1. в момент разветвления IB6 и FB1 идентификаторы чарсетов совпадали, но дальше каждый разработчик добавлял новые чарсеты со своими ID по своему усмотрению и в свой момент
2. драйвер dbxfb.dll явно делался по исходникам для dbxint.dll, возможно, условной компиляцией отдельных кусочков (в бинарнике четко прослеживаются имена модулей с "IB", а также присутствует SQL-тип данных BOOLEAN, которого в 2010 г в FB еще не было)
3. программисты драйвера наверняка тоже зашили в код ID чарсетов вместо того, чтобы считать и интерпретировать корректно данные из RDB$CHARACTER_SETS


sniknik ©   (28.08.17 17:20[24]

> вместо того, чтобы считать и интерпретировать корректно данные из RDB$CHARACTER_SETS
// System Tables incorrectly state they are in Unicode_Fss character set but they are not
переведи. все они интерпретировали корректно... на тот момент когда писали.


sniknik ©   (28.08.17 17:31[25]

+ писал же про путаницу
> ты видать пытаешся работать с utf в ansi(вернее ascii) строках
и тут похоже так и есть, пытаются интерпретировать длину по ascii представлению utf-ного символа. чего в ado бы быть не должно т.к. utf должен был однозначно преобразован к юникоду (в понимании мелкософта) и имел бы всегда длину символа в 2 байта.


sniknik ©   (28.08.17 17:54[26]

> а код 59 соответствует чарсету WIN1256
вообще не соответствует, а показывает, что конкретно этот код из utf-8 состоит из 4-ех байт/ascii символов.


Чемпаркароке ©   (28.08.17 18:07[27]


> sniknik ©   (28.08.17 17:20) [24]
ты невнимателен:
1. UNICODE_FSS - это другая кодировка
2. речь идет о системных таблицах, что в них данные не в заявленной кодировке, а не некорректных кодировках каких-то других таблиц

> ты видать пытаешся работать с utf в ansi(вернее ascii) строках
снова догадки
я работаю БЕЗ ansi-строк, да и все методы компонентов доступа тоже

> sniknik ©   (28.08.17 17:54) [26]
а тут вообще пальцем в небо
код 59 - это не код символа, а внутренний ID чарсета, только это разные чарсеты в IB и FB, несмотря на одинаковость кода
вот цитата из http://www.ibase.ru/unicode_faq/
В rdb$character_sets кодировка UTF8 имеет в Firebird идентификатор 4 (это был свободный номер рядом с давно имеющейся в IB и FB кодировкой UNICODE_FSS с ID = 3), а в InterBase – 59. Код 59 в Firebird имеет кодировка WIN1256. То есть, разработчики InterBase не ставили перед собой вопрос обеспечения совместимости с Firebird в этом плане.


sniknik ©   (28.08.17 21:36[28]

> ты невнимателен:
а ты английский не знаешь...
> 1. UNICODE_FSS - это другая кодировка
> 2. речь идет о системных таблицах ...
вот именно это в комментарии к "костылю" и написано, что в системных указана Unicode_Fss хотя там другая. притом это было тогда, когда писался код, сейчас, если в системных исправили, то ситуация поменялась на обратную.

> я работаю БЕЗ ansi-строк, да и все методы компонентов доступа тоже
как скажешь.

> Код 59 в Firebird имеет кодировка WIN1256.
код 59 это точка с запятой (;). и он не может иметь кодировку WIN1256. символы с одинаковыми кодами могут входить в разные кодировки и выглядеть по разному в разных кодировках, но вот конкретно 59 и в WIN1256 тоже точка с запятой. т.е. как ты определил, что один из символов ; ; в 1251, а другой в 1256 не понятно...  может ты про кодировку в параметрах поля говоришь?


Чемпаркароке ©   (28.08.17 22:05[29]


> sniknik ©   (28.08.17 21:36) [28]

английский - мой почти родной
в том комменте system tables и they взаимозаменяемы, поэтому в методе и проверяется наличие 'RDB$' в названии таблицы, чтобы ее не перекодировать при чтении
а RDB$ - это префикс системной таблицы, и никакой другой
к остальным таблицам этот коммент просто не относится

> код 59 это точка с запятой (;)

59 - это ИДЕНТИФИКАТОР для чарсета, указанный в системной таблице, а не какой-то там символ непонятно где
прочитай еще раз цитату с ibase.ru


sniknik ©   (29.08.17 16:30[30]

> 59 - это ИДЕНТИФИКАТОР для чарсета
вот теперь вообще ничего не понимаю... 1 идентификатор на всю строку? для кодировки с переменным числом байт на символ? бред.


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо