Коллеги, выношу на суд общественности.
Либо я глючу, либо в процедуре обновления базы для СП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)