03.07.2009, 06:19 | #4 |
Участник
|
Цитата:
Сообщение от Dron AKA andy
... После непродолжительных размышлений над оригинальным кодом я заметил некую странность: мы сначала наполняем контейнер названиями полей в SQL-интерпретации через
X++: dictTable.fieldName(this.field(i), DbBackend::SQL) X++: dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy) В случае, наличия в индексе строкового поля, при вызове dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy) ядро AX преобразует поля к одному регистру, добавляя вызов substr и nls_lower. Т.е. в AX 3.0 для СУБД Oracle вызов dictTable.fieldName(this.field(i), DbBackend::SQL) для строкового поля вернет field, а вызов dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy) - вернет substr(nls_lower(field), 1, strlen(field)). В конфигурации АОСа AX4.0 есть параметр - Database Tuning\AutoGeneration Options\Include SUBSTR and LOWER in all SELECT statements to support Oracle mixed-case systems, который видимо и отвечает за генерацию данного substr и nls_lower. В итоге, если в таблице есть значения строкового поля 'SSS' и 'sss', данное поле включено в индекс и используемая СУБД Oracle, то замена X++: dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy) X++: dictTable.fieldName(this.field(i), DbBackend::SQL) В связи с этим, привожу немного измененный код(для AX 3.0, аналогичные изменения можно внести и для AX 4.0), который одинаково работает как на SQL, так и на Oracle. X++: void showDuplicates() { tableId tableId = this.tableid(); DictTable dictTable = new DictTable(tableId); boolean dataPrCompany = dictTable.dataPrCompany(); container fields; Counter numberOfFields = this.numberOfFields(); Counter i; str stmtStr; str resultLineStr; str resultField; str resultField1; UserConnection con = new UserConnection(); Statement stmt = con.createStatement(); ResultSet resultSet; boolean anyDuplicates = false; ; if (dataPrCompany) fields += dictTable.fieldname(fieldnum(common,DataAreaId),DbBackend::SQL); for (i = 1; i <= numberOfFields; i++) { fields += dictTable.fieldName(this.field(i), DbBackend::SQL); } //srf --> //if (dataPrCompany) // numberOfFields++; //srf <-- stmtStr = 'select count(*)'; //srf --> if (dataPrCompany) { stmtStr += ', ' + dictTable.fieldName(fieldnum(Common,DataAreaId),DbBackend::Sql,0,FieldNameGenerationMode::FieldListGroupBy); } //srf <-- for (i = 1; i <= numberOfFields; i++) { stmtStr += ', ' + dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy); } stmtStr += ' from ' + dictTable.name(DbBackend::SQL); stmtStr += ' group by '; //srf --> if (dataPrCompany) { stmtStr += dictTable.fieldName(fieldnum(Common,DataAreaId),DbBackend::Sql,0,FieldNameGenerationMode::FieldListGroupBy); if (numberOfFields >= 1) { stmtStr+= ', '; } } //srf <-- for (i = 1; i <= numberOfFields; i++) { if (i > 1) stmtStr += ', '; stmtStr += dicttable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::GroupByFieldList); } //srf --> if (dataPrCompany) numberOfFields++; //srf <-- stmtStr += ' having count(*) > 1'; if (numberOfFields > 0) { stmtStr += ' order by '; for (i = 1; i <= numberOfFields; i++) { if (i > 1) stmtStr += ', '; stmtStr += int2str(i+1); } stmtStr += ' desc'; } resultSet = stmt.executeQuery(stmtStr); while (resultSet.next()) { resultLineStr = "@SYS283" + strFmt(': %1', resultSet.getString(1)); for (i = 1; i <= numberOfFields; i++) { resultField = strLtrim(resultSet.getString(i+1)); if (i == 1 && dataPrCompany) resultField1 = resultField; else resultLineStr += strFmt(', %1: \'%2\'', conPeek(fields, i), resultField); } if (dataPrCompany) setPrefix(strFmt('%1: %2', conPeek(fields, 1), resultField1)); info(resultLineStr); anyDuplicates = true; } if (!anyDuplicates) info("@SYS68671"); } |
|
|
За это сообщение автора поблагодарили: tricky (1). |
Теги |
aot, ax2009, ax3.0, ax4.0, code access security, security, баг, безопасность, индекс, инструменты, ошибка, полезное |
|
|