20.01.2009, 22:49 | #1 |
Участник
|
Осторожно. RecordSortedList учитывает регистр символов
Обнаружил неприятную особенность RecordSortedList. При сравнении строковых значений при поиске по ключу, сравнение учитывает регистр символов, что может приводить к ошибкам, так как везде в X++ сравнение строк регистронезависимое.
X++: // pkoz, 20.01.2009 static void testRegistSensitive(Args _args) { RecordSortedList cacheInventSum; InventSum InventSum; boolean testSameRegistr; boolean testLowerRegistr; boolean testSameRegistrMap; boolean testLowerRegistrMap; boolean testSameRegistrMapCon; boolean testLowerRegistrMapCon; map map; str key; container conKey; str getKey(str _param1, str _param2) { return strFMT("%1;%2;", _param1, _param2); } container getConKey(str _param1, str _param2) { return [_param1, _param2]; } void initInventSum() { ; InventSum = null; InventSum.ItemId = "1234"; InventSum.InventDimId = "DIM1234"; InventSum.PostedQty = 10; } ; initInventSum(); cacheInventSum = new RecordSortedList(TableNum(InventSum)); cacheInventSum.sortOrder(FieldNum(InventSum,itemId),FieldNum(InventSum,inventDimId)); cacheInventSum.ins(InventSum); testSameRegistr = cacheInventSum.find(InventSum); InventSum.InventDimId = strLwr(InventSum.InventDimId); testLowerRegistr = cacheInventSum.find(InventSum); info(strFMT("RSL %1; %2", testSameRegistr, testLowerRegistr)); if (!testLowerRegistr) error("CaseSensitive RSL !!!"); ////////////////// map = New Map (types::String, types::Record); initInventSum(); key = getKey(InventSum.ItemId, InventSum.InventDimId); map.insert(key, InventSum); testSameRegistrMap = map.exists(key); key = getKey(InventSum.ItemId, strLwr(InventSum.InventDimId)); testLowerRegistrMap = map.exists(key); info(strFMT("Map StrinKey %1; %2", testSameRegistrMap, testLowerRegistrMap)); if (!testLowerRegistrMap) error("CaseSensitive Map StrinKey !!!"); ////////////////// map = New Map (types::Container, types::Record); initInventSum(); conKey = getConKey(InventSum.ItemId, InventSum.InventDimId); map.insert(conkey, InventSum); testSameRegistrMapCon = map.exists(Conkey); Conkey = getConKey(InventSum.ItemId, strLwr(InventSum.InventDimId)); testLowerRegistrMapcon = map.exists(conkey); info(strFMT("Map ContainerKey %1; %2", testSameRegistrMapCon, testLowerRegistrMapCon)); if (!testLowerRegistrMapCon) error("CaseSensitive Map ContainerKey !!!"); } P.S. Ax 3.0 KR3 SP5 Oracle |
|
|
За это сообщение автора поблагодарили: dn (2), ZVV (1), lev (1), coolibin (1), aidsua (1), gl00mie (8). |
21.01.2009, 00:08 | #2 |
Участник
|
Проверил щас на ядре 3.0.1951.7669 (afaik последнем доступном для 3-ки) - косяк с RecordSortedList воспроизводится А в той же 4-ке (4.0.2501.116) уже не воспроизводится, видимо, втихоря поправили.
|
|
21.01.2009, 00:42 | #3 |
MCITP
|
да, действительно, и ведь об этом нигде не написано...
Ещё интересный момент с регистром - это когда делаешь запрос с группировкой в Аксапте на Оракле - запрос строится с использованием nls_lower() и соответсвенно в результате поля группировки в резултСете все в lower-case. Не всегда приятно, но особо ничего с этим не поделаешь. На Сиквеле такого, естественно, нет...
__________________
Zhirenkov Vitaly |
|
21.01.2009, 03:24 | #4 |
Участник
|
Оказалось, что "исправление втихоря" в 4-ке было связано с переходом на Unicode. В общем, метод find() ищет строки, используя итератор и передавая ему ссылку на функцию сравнения записей; та же, в свою очередь, перво-наперво сравнивает коды компаний двух записей, а потом пробегается по полям, используемым для сортировки, и сравнивает их значения с помощью некой функции _DBICompare().
Данная функция предназначена для сравнения уникальных ключей, составленных из значений различных примитивных типов (строковые, BCD, целочисленные, даты, etc). В основном это используется, я так понял, на DataSource'ах, при переиндексации таблиц через DictTable.reindex() и xCompany.reindex(), а также в RecordSortedList, в UtilElements, возможно, и во временных таблицах. Так вот, при условии, что в текущей локали не используется какая-нить многобайтовая кодировка и база не инициализирована для использования Unicode'а, для строковых значений эта функция в 3-ке тупо использует функцию strncmp() со всеми вытекающими... В 4-ке же используется CompareStringW() из kernel32.dll с флагами NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH, поэтому и работает все, как положено. Последний раз редактировалось gl00mie; 21.01.2009 в 03:28. |
|
|
За это сообщение автора поблагодарили: Logger (5), aidsua (1). |
21.01.2009, 09:33 | #5 |
Moderator
|
Цитата:
Пусть скажут свое слово "троешники"-SQL-серверщики! У них воспроизводится? |
|
21.01.2009, 09:43 | #6 |
Axapta
|
|
|
21.01.2009, 10:17 | #7 |
MCITP
|
Цитата:
Это проблема самого СортЛиста.
__________________
Zhirenkov Vitaly |
|
23.01.2009, 15:09 | #8 |
Участник
|
gl00ime, а откуда такая подробная информация о том, как именно работает find()?
|
|
23.01.2009, 15:38 | #9 |
Участник
|
|
|
23.01.2009, 15:39 | #10 |
Участник
|
Цитата:
Получается это может вылезти не только в RecordSortedList. |
|
Теги |
баг, ax3.0 |
|
Похожие темы | ||||
Тема | Ответов | |||
RecordSortedList как проверить??? | 29 | |||
Как узнать по объекту RecordSortedList, из какой таблицы в нем записи? | 4 | |||
axStart: RecordSortedList | 0 |
|