Как показали полевые испытания, скрипт учитывал не все. Ниже - исправленная версия
X++:
public static server void sqlDictionaryFill4Table(tableId _tableId)
{
#macrolib.DictField
#define.RecIdBaseType (49) // для полей с типом RecId/RefRecId/createdTransactionId/modifiedTransactionId используется не Types::Int64, а этот тип
#define.TZIDsuffix ('_TZID') // для несистемных полей типа UtcDateTime в БД создается дополнительное поле с кодом временной зоны, в которой было записано значение
SqlDictionary sqlDict;
SysdictType dictType;
DictTable dictTable;
DictField dictField;
ArrayIdx arrIdx;
Counter numOfSqlFields; // сколько записей для полей таблицы должно быть в SqlDictionary
fieldName fieldName;
fieldId fieldId;
boolean processTableField(DictField _dictField, ArrayIdx _arrIdx, boolean _isTzIdField = false)
{
ArrayIdx dictArrIdx;
str infoName; // это имя поля сугубо для сообщений
FieldName sqlName;
boolean ret;
;
if (_isTzIdField)
{
if ( _dictField.baseType() != Types::UtcDateTime
|| _dictField.id() == fieldnum(Common, createdDateTime)
|| _dictField.id() == fieldnum(Common, modifiedDateTime)
)
{
throw error(Error::wrongUseOfFunction(funcname()));
}
dictArrIdx = _dictField.arraySize() + _arrIdx;
sqlName = _dictField.dateTimeTimeZoneRuleFieldName(_arrIdx - 1);
infoName = _dictField.name() + #TZIDsuffix;
}
else
{
dictArrIdx = _arrIdx;
sqlName = _dictField.name(DbBackend::Sql, _arrIdx);
infoName = _dictField.name();
}
select firstonly sqlDict
where sqlDict.tabId == _dictField.tableid()
&& sqlDict.fieldId == _dictField.id()
&& sqlDict.array == dictArrIdx
;
if (!sqlDict)
{
sqlDict.clear();
sqlDict.initValue();
sqlDict.tabId = _dictField.tableid();
sqlDict.fieldId = _dictField.id();
sqlDict.array = dictArrIdx;
sqlDict.name = strupr(_dictField.name(DbBackend::Native, _arrIdx));
sqlDict.sqlName = sqlName;
dictType = new SysDictType( _dictField.typeId() );
if (_isTzIdField)
{
sqlDict.fieldType = Types::Integer;
}
else
if ( _dictField.id() == fieldnum(Common, RecId)
|| _dictField.id() == fieldnum(Common, createdTransactionId)
|| _dictField.id() == fieldnum(Common, modifiedTransactionId)
|| _dictField.typeId() == extendedtypenum(RecId)
|| _dictField.typeId() == extendedtypenum(RefRecId)
|| _dictField.typeId() == extendedtypenum(createdTransactionId)
|| _dictField.typeId() == extendedtypenum(modifiedTransactionId)
|| ( dictType
&& ( dictType.isExtending(extendedtypenum(RecId))
|| dictType.isExtending(extendedtypenum(createdTransactionId))
|| dictType.isExtending(extendedtypenum(modifiedTransactionId))
)
)
)
{
// для RecId в поле fieldType прописывается не Types::Int64, а число 49
sqlDict.fieldType = #RecIdBaseType;
}
else
{
sqlDict.fieldType = _dictField.baseType();
}
sqlDict.strSize = _dictField.stringLen();
sqlDict.shadow = bitTest( _dictField.flags(), #DBF_SHADOW );
sqlDict.rightJustify = bitTest( _dictField.flags(), #DBF_RIGHT );
sqlDict.flags = sqlDict.shadow; // а вот ни фига не _dictField.flags();
sqlDict.nullable = _dictField.baseType() == Types::Container
|| _dictField.baseType() == Types::VarString
;
if (sqlDict.validateWrite())
{
sqlDict.insert();
ret = true;
info(strfmt(@"Создана запись для поля %1.%2%3",
dictTable.name(), infoName, _dictField.arraySize() > 1 ? strfmt(@"[%1]", _arrIdx) : ''
));
// для всех несистемных полей UtcDateTime создаем также связанное поле TZID
if ( !_isTzIdField
&& _dictField.baseType() == Types::UtcDateTime
&& _dictField.id() != fieldnum(Common, createdDateTime)
&& _dictField.id() != fieldnum(Common, modifiedDateTime)
)
{
processTableField(_dictField, _arrIdx, true);
}
}
else
{
ret = checkFailed(strfmt(@"Запись в %1 для поля %2.%3 не была создана", tablestr(SqlDictionary), dictTable.name(), infoName));
}
}
return ret;
}
;
dictTable = new DictTable( _tableId );
if (!dictTable)
{
throw error(strfmt(@"Не удалось создать объект %1 для таблицы '%2' (%3)", classstr(DictTable), tableid2name( _tableId ), _tableId));
}
if (dictTable.isSystemTable())
{
throw error(strfmt(@"Таблица '%1' - системная, на это я пойтить не могу", dictTable.name()));
}
if (!dictTable.isSql())
{
throw error(strfmt(@"Таблицы '%1' вообще не должно быть в базе", dictTable.name()));
}
for (fieldId = dictTable.fieldNext( 0 ); fieldId; fieldId = dictTable.fieldNext( fieldId ))
{
dictField = dictTable.fieldObject( fieldId );
if (dictField && dictField.isSql())
{
fieldName = dictField.name();
for (arrIdx = 1; arrIdx <= dictField.arraySize(); arrIdx++)
{
numOfSqlFields++;
processTableField( dictField, arrIdx );
}
}
}
select firstonly sqlDict
where sqlDict.tabId == _tableId
&& sqlDict.fieldId == 0
;
if (!sqlDict)
{
sqlDict.clear();
sqlDict.initValue();
sqlDict.tabId = _tableId;
sqlDict.name = strupr(dictTable.name());
sqlDict.sqlName = dictTable.name(DbBackend::Sql);
sqlDict.strSize = numOfSqlFields; // для "заголовка" таблицы тут указывается, сколько у нее полей в БД
sqlDict.flags = dictTable.isView(); // "мой дедуктивный метод..."
sqlDict.insert();
info(strfmt(@"Создана запись для таблицы %1", dictTable.name()));
}
}