AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 28.04.2008, 13:49   #1  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Обновление данных при переходе на Ax3 SP5 - ошибка. Караул !
Коллеги, выношу на суд общественности.
Либо я глючу, либо в процедуре обновления базы для СП5 содержится ошибка.

В 5-м сервис-паке поменяли значения енумов - под это дело процедура обновления перебивает значения во всех таблицах.
SQL запрос для обновления генерится тут :

X++:
\Classes\ChangeEnumValueInTable_W\sqlQuery
X++:
protected str sqlQuery(DictTable _dictTable, FieldID  _fieldID, int _oldValue, int _newValue)
{
    str     szSql;
    str     dataAreaId, dataAreaIdName;

    ;

    dataAreaIdName  = _dictTable.fieldName(fieldnum(Common, DataAreaId), DbBackend::SQL);

    szSql           = strFmt("update %1 set %2 = %3 where %2 = %4",
                             _dictTable.name(DbBackend::Sql),
                             _dictTable.fieldname(_fieldID, DbBackend::Sql),
                             _newValue,
                             _oldValue);


    if (_dictTable.dataPrCompany())
    {
        dataAreaId = '\'' + curext() + '\'';

        if (SqlSystem::databaseBackendId() == DatabaseId::Oracle)
        {
            dataAreaId = strFmt(new SqlSystem().monocaseFmt(), dataAreaId);
        }

        szSql += " and " + dataAreaIdName + ' = ' + dataAreaId;
    }

    return szSql;
}
Что напрягает :

1. Строка 19
X++:
dataAreaId = '\'' + curext() + '\'';
всегда подставляется текущая компания что неверно для виртуальных компаний. Т.е. если таблица включена в виртуальную компанию, то данные для неё не будут обновляться.

Для лечения можно попробовать поставить так
X++:
dataAreaId = '\'' + curExt2dataareaid(_dictTable.id()) + '\'';
Но есть это верно только в том случае если значения енумов поменялись таким образом, что повторное применение процедуры обновления их не портит, т.е. код Idempotency - как сказано в документации. Дело в том что указанная процедура запускается в каждой компании, таким образом если у нас несколько компаний, то данная процедура стартует несколько раз - по числу компаний. Для надежности нужно еще обеспечить чтобы процедура стартовала по виртуальной компании только один раз !

2. Формирование фильтра по DataAreaId для оракла
Строка 23
X++:
dataAreaId = strFmt(new SqlSystem().monocaseFmt(), dataAreaId);
Строка 26
X++:
szSql += " and " + dataAreaIdName + ' = ' + dataAreaId;
функции new SqlSystem().monocaseFmt() не передаются параметры, поэтому она не генерит обрамления вида
SUBSTR(NLS_LOWER(...))
Похоже под ораклом переход вообще не тестировался.

Что это влечет :
1. Некоторые записив БД, для которых значение dataAreaId отличается от возвращаемого curExt() (например не тот регистр оказался) - могут остаться необновленными. Похоже на наше счастье значения DataAreaId сгенерированные ядром при создании записей как раз совпадают по регистру с тем что возвращает curExt() так что все нормально и все записи должны попасть. Но гарантий нет.

2. Поскольку индексы в оракле строятся тоже от функций SUBSTR(NLS_LOWER(DATAAREAID)) - то при выполнении указанных запросов любой индекс будет бесполезен - получится неэффективное сканирование таблицы даже для маленькой компании.

В итоге получился вот такой исправленный код

X++:
protected str sqlQuery(DictTable _dictTable, FieldID  _fieldID, int _oldValue, int _newValue)
{
    str     szSql;
    str     dataAreaId, dataAreaIdName;

    ;

    dataAreaIdName  = _dictTable.fieldName(fieldnum(Common, DataAreaId), DbBackend::SQL);

    szSql           = strFmt("update %1 set %2 = %3 where %2 = %4",
                             _dictTable.name(DbBackend::Sql),
                             _dictTable.fieldname(_fieldID, DbBackend::Sql),
                             _newValue,
                             _oldValue);


    if (_dictTable.dataPrCompany())
    {
        // pkoz 28.04.2008 -->
        //dataAreaId = '\'' + curext() + '\'';
        dataAreaId = '\'' + curExt2dataareaid(_dictTable.id()) + '\''; // перепроверить на корректность для повторных запусков !
        // pkoz 28.04.2008 <--

        if (SqlSystem::databaseBackendId() == DatabaseId::Oracle)
        {
          // pkoz 28.04.2008 -->
            //dataAreaId = strFmt(new SqlSystem().monocaseFmt(), dataAreaId);
            dataAreaId = strFmt(new SqlSystem().monocaseFmt(_dictTable.id(), _fieldID), dataAreaId);
          // pkoz 28.04.2008 <--
        }

        // pkoz 28.04.2008 -->
        if (SqlSystem::databaseBackendId() == DatabaseId::Oracle)
        {
            szSql += " and " + 
                strFmt(new SqlSystem().monocaseFmt(_dictTable.id(), FieldNum(common, DataAreaID)), dataAreaIdName)
                + ' = ' + dataAreaId;
        }
        else
        // pkoz 28.04.2008 <--
        szSql += " and " + dataAreaIdName + ' = ' + dataAreaId;
    }

    return szSql;
}
P.S.
Ax3.0
SP5

В качестве примера для табилцы InventTrans стандартный код сгенерил вот такой запрос
X++:
update INVENTTRANS set TRANSTYPE = 100 where TRANSTYPE = 21 and DATAAREAID = 'dat'
Исправленный код :
X++:
update INVENTTRANS set TRANSTYPE = 100 where TRANSTYPE = 21 and SUBSTR(NLS_LOWER(DATAAREAID),1,3) = SUBSTR(NLS_LOWER('dat'),1,3)

Последний раз редактировалось Logger; 28.04.2008 в 14:00.
Старый 28.04.2008, 15:34   #2  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Создается ощущение что это ядро с какого то момента изменило свою логику работы.
Например для SQL сервера всегда выдает выражение
X++:
{fn LCASE(%1)}
даже с дефолтными параметрами.

Посмотрел по перекрестным ссылкам - вызов sqlSystem.monocaseFmt() - идет во многих местах и нигде не заданы параметры. Т.е. баг должен проявиться в куче мест.

Плюс кое-где некорректно обрабатываются виртуальные компании
Например тут
X++:
\Classes\InventUpdateTTSCleanup\updateStr
Теги
ax3.0

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Ошибка при присоединении к базе данных serg_ DAX: Администрирование 1 18.11.2008 11:36
Стандартный импорт данных. Обновление sparur DAX: Функционал 0 24.03.2008 19:07
Ax3.0 SP3 CIS: Журнал накладных и российские договора (ошибка) mpa DAX: Функционал 2 11.10.2004 15:14
Русская локализация Axapta 3 ? SlavaK DAX: Администрирование 59 01.07.2003 22:38
Обновление существующего приложения до SP5 SSA DAX: Администрирование 16 19.02.2003 18:14

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 21:02.