IDEMPIERE-4911 Silent fail when translated column is shorter than original column (FHCA-2888) (#844)

* IDEMPIERE-4911 Silent fail when translated column is shorter than original column (FHCA-2888)

Changes:
* Saving a value that doesn't fit in the translation now fails with a proper user understandable message
* Synchronize Doc Translation now fails with a user understandable message in case it fails because a value doesn't fit
* When updating a column on a translation table, check for the size of the original column and update the size accordingly
* When updating a translated column, show warnings to user about creating the table, or creating the column, or updating the column size

* IDEMPIERE-4911 Silent fail when translated column is shorter than original column (FHCA-2888)

Improve message for end user
This commit is contained in:
Carlos Ruiz 2021-08-20 13:59:35 +02:00 committed by GitHub
parent f912cf2c21
commit 0167c91424
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 149 additions and 16 deletions

View File

@ -0,0 +1,27 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-4911 Silent fail when translated column is shorter than original column (FHCA-2888)
-- Aug 18, 2021, 8:01:59 PM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','...',0,0,'Y',TO_DATE('2021-08-18 20:01:59','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-08-18 20:01:59','YYYY-MM-DD HH24:MI:SS'),100,200714,'MismatchTrlColumnSize','D','14ca00be-1dc1-4e27-b908-257704aae45d')
;
-- Aug 18, 2021, 8:13:56 PM CEST
UPDATE AD_Message SET MsgText='Error synchronizing translation, string too long', MsgTip='There is a mismatch in the size of a translated column. Please contact the system administrator to correct the problem.',Updated=TO_DATE('2021-08-18 20:13:56','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200714
;
-- Aug 18, 2021, 9:24:16 PM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','Do not forget to create the corresponding translation table {0} with column {1}',0,0,'Y',TO_DATE('2021-08-18 21:24:15','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-08-18 21:24:15','YYYY-MM-DD HH24:MI:SS'),100,200715,'WarnCreateTrlTable','D','df97a71a-bb65-4ed5-b7dc-000610f807f5')
;
-- Aug 18, 2021, 9:24:27 PM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','Do not forget to create the translation column {0}.{1}',0,0,'Y',TO_DATE('2021-08-18 21:24:26','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-08-18 21:24:26','YYYY-MM-DD HH24:MI:SS'),100,200716,'WarnCreateTrlColumn','D','7bd54fc7-40cc-408d-b88e-ec25f9ae28fa')
;
-- Aug 18, 2021, 9:24:38 PM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','Do not forget to increase the size on translation column {0}.{1} to {2}',0,0,'Y',TO_DATE('2021-08-18 21:24:38','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-08-18 21:24:38','YYYY-MM-DD HH24:MI:SS'),100,200717,'WarnUpdateSizeTrlTable','D','d5951ecd-3d4f-4438-bc48-8d3fbace8693')
;
SELECT register_migration_script('202108182002_IDEMPIERE-4911.sql') FROM dual
;

View File

@ -0,0 +1,24 @@
-- IDEMPIERE-4911 Silent fail when translated column is shorter than original column (FHCA-2888)
-- Aug 18, 2021, 8:01:59 PM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','...',0,0,'Y',TO_TIMESTAMP('2021-08-18 20:01:59','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-08-18 20:01:59','YYYY-MM-DD HH24:MI:SS'),100,200714,'MismatchTrlColumnSize','D','14ca00be-1dc1-4e27-b908-257704aae45d')
;
-- Aug 18, 2021, 8:13:56 PM CEST
UPDATE AD_Message SET MsgText='Error synchronizing translation, string too long', MsgTip='There is a mismatch in the size of a translated column. Please contact the system administrator to correct the problem.',Updated=TO_TIMESTAMP('2021-08-18 20:13:56','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200714
;
-- Aug 18, 2021, 9:24:16 PM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','Do not forget to create the corresponding translation table {0} with column {1}',0,0,'Y',TO_TIMESTAMP('2021-08-18 21:24:15','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-08-18 21:24:15','YYYY-MM-DD HH24:MI:SS'),100,200715,'WarnCreateTrlTable','D','df97a71a-bb65-4ed5-b7dc-000610f807f5')
;
-- Aug 18, 2021, 9:24:27 PM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','Do not forget to create the translation column {0}.{1}',0,0,'Y',TO_TIMESTAMP('2021-08-18 21:24:26','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-08-18 21:24:26','YYYY-MM-DD HH24:MI:SS'),100,200716,'WarnCreateTrlColumn','D','7bd54fc7-40cc-408d-b88e-ec25f9ae28fa')
;
-- Aug 18, 2021, 9:24:38 PM CEST
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','Do not forget to increase the size on translation column {0}.{1} to {2}',0,0,'Y',TO_TIMESTAMP('2021-08-18 21:24:38','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-08-18 21:24:38','YYYY-MM-DD HH24:MI:SS'),100,200717,'WarnUpdateSizeTrlTable','D','d5951ecd-3d4f-4438-bc48-8d3fbace8693')
;
SELECT register_migration_script('202108182002_IDEMPIERE-4911.sql') FROM dual
;

View File

@ -20,6 +20,8 @@ import java.math.BigDecimal;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.exceptions.DBException;
import org.compiere.model.MClient; import org.compiere.model.MClient;
import org.compiere.model.MColumn; import org.compiere.model.MColumn;
import org.compiere.model.MTable; import org.compiere.model.MTable;
@ -29,6 +31,7 @@ import org.compiere.util.AdempiereUserError;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.DisplayType; import org.compiere.util.DisplayType;
import org.compiere.util.Language; import org.compiere.util.Language;
import org.compiere.util.Msg;
/** /**
@ -103,7 +106,8 @@ public class TranslationDocSync extends SvrProcess
String baseTable = trlTable.substring(0, trlTable.length()-4); String baseTable = trlTable.substring(0, trlTable.length()-4);
if (log.isLoggable(Level.CONFIG)) log.config(baseTable + ": " + columnNames); if (log.isLoggable(Level.CONFIG)) log.config(baseTable + ": " + columnNames);
try {
if (client.isMultiLingualDocument()) { if (client.isMultiLingualDocument()) {
String baselang = Language.getBaseAD_Language(); String baselang = Language.getBaseAD_Language();
if (client.getAD_Language().equals(baselang)) { if (client.getAD_Language().equals(baselang)) {
@ -118,8 +122,8 @@ public class TranslationDocSync extends SvrProcess
.append(baseTable).append("_ID=b.").append(baseTable).append("_ID) WHERE AD_Client_ID=") .append(baseTable).append("_ID=b.").append(baseTable).append("_ID) WHERE AD_Client_ID=")
.append(getAD_Client_ID()).append(" AND AD_Language=").append(DB.TO_STRING(client.getAD_Language())); .append(getAD_Client_ID()).append(" AND AD_Language=").append(DB.TO_STRING(client.getAD_Language()));
int no = DB.executeUpdate(sql.toString(), get_TrxName()); int no = DB.executeUpdateEx(sql.toString(), get_TrxName());
addLog(0, null, new BigDecimal(no), baseTable); addBufferLog(0, null, new BigDecimal(no), baseTable, 0, 0);
} }
} else { } else {
// auto update all translations // auto update all translations
@ -129,9 +133,18 @@ public class TranslationDocSync extends SvrProcess
.append(baseTable).append("_ID=b.").append(baseTable).append("_ID) WHERE AD_Client_ID=") .append(baseTable).append("_ID=b.").append(baseTable).append("_ID) WHERE AD_Client_ID=")
.append(getAD_Client_ID()); .append(getAD_Client_ID());
int no = DB.executeUpdate(sql.toString(), get_TrxName()); int no = DB.executeUpdateEx(sql.toString(), get_TrxName());
addLog(0, null, new BigDecimal(no), baseTable); addBufferLog(0, null, new BigDecimal(no), baseTable, 0, 0);
} }
} catch (DBException e) {
String msg = trlTable + " -> ";
if (DBException.isValueTooLarge(e)) {
msg += Msg.getMsg(getCtx(), "MismatchTrlColumnSize");
} else {
msg += e.getLocalizedMessage();
}
throw new AdempiereException(msg, e);
}
} // processTable } // processTable

View File

@ -36,13 +36,14 @@ import org.compiere.util.DB;
*/ */
public class DBException extends AdempiereException public class DBException extends AdempiereException
{ {
public static final String DATABASE_OPERATION_TIMEOUT_MSG = "DatabaseOperationTimeout";
public static final String DELETE_ERROR_DEPENDENT_MSG = "DeleteErrorDependent";
public static final String SAVE_ERROR_NOT_UNIQUE_MSG = "SaveErrorNotUnique";
/** /**
* *
*/ */
private static final long serialVersionUID = 4264201718343118625L; private static final long serialVersionUID = -1961265420169932726L;
public static final String DATABASE_OPERATION_TIMEOUT_MSG = "DatabaseOperationTimeout";
public static final String DELETE_ERROR_DEPENDENT_MSG = "DeleteErrorDependent";
public static final String SAVE_ERROR_NOT_UNIQUE_MSG = "SaveErrorNotUnique";
private String m_sql = null; private String m_sql = null;
/** /**
@ -212,7 +213,18 @@ public class DBException extends AdempiereException
return false; return false;
} }
} }
/**
* Check if value too large for column exception (aka ORA-12899)
* @param e exception
*/
public static boolean isValueTooLarge(Exception e) {
if (DB.isPostgreSQL())
return isSQLState(e, "22001");
//
return isErrorCode(e, 12899);
}
/** /**
* @param e * @param e
*/ */
@ -227,4 +239,5 @@ public class DBException extends AdempiereException
return null; return null;
} }
} }
} // DBException } // DBException

View File

@ -524,6 +524,21 @@ public class MColumn extends X_AD_Column implements ImmutablePOSupport
LogicEvaluator.validate(getReadOnlyLogic()); LogicEvaluator.validate(getReadOnlyLogic());
} }
} }
// IDEMPIERE-4911
MTable table = MTable.get(getAD_Table_ID());
String tableName = table.getTableName();
if (tableName.toLowerCase().endsWith("_trl")) {
String parentTable = tableName.substring(0, tableName.length()-4);
MColumn column = MColumn.get(getCtx(), parentTable, colname);
if (column != null && column.isTranslated()) {
if (getFieldLength() < column.getFieldLength()) {
log.saveWarning("Warning", "Size increased to " + column.getFieldLength() + " in translated column " + tableName + "." + colname);
setFieldLength(column.getFieldLength());
}
}
}
return true; return true;
} // beforeSave } // beforeSave
@ -543,7 +558,26 @@ public class MColumn extends X_AD_Column implements ImmutablePOSupport
|| "EntityType".equals(get_ValueOld(COLUMNNAME_ColumnName).toString()))) { || "EntityType".equals(get_ValueOld(COLUMNNAME_ColumnName).toString()))) {
MChangeLog.resetLoggedList(); MChangeLog.resetLoggedList();
} }
// IDEMPIERE-4911
if (isTranslated()) {
MTable table = MTable.get(getAD_Table_ID());
String trlTableName = table.getTableName() + "_Trl";
MTable trlTable = MTable.get(getCtx(), trlTableName);
if (trlTable == null) {
log.saveWarning("Warning", Msg.getMsg(getCtx(), "WarnCreateTrlTable", new Object[] {trlTableName, getColumnName()}));
} else {
MColumn trlColumn = MColumn.get(getCtx(), trlTableName, getColumnName());
if (trlColumn == null) {
log.saveWarning("Warning", Msg.getMsg(getCtx(), "WarnCreateTrlColumn", new Object[] {trlTableName, getColumnName()}));
} else {
if (trlColumn.getFieldLength() < getFieldLength()) {
log.saveWarning("Warning", Msg.getMsg(getCtx(), "WarnUpdateSizeTrlTable", new Object[] {trlTableName, getColumnName(), getFieldLength()}));
}
}
}
}
return success; return success;
} // afterSave } // afterSave

View File

@ -3806,7 +3806,18 @@ public abstract class PO
.append(" AND NOT EXISTS (SELECT * FROM ").append(tableName) .append(" AND NOT EXISTS (SELECT * FROM ").append(tableName)
.append("_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.") .append("_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.")
.append(keyColumn).append("=t.").append(keyColumn).append(")"); .append(keyColumn).append("=t.").append(keyColumn).append(")");
int no = DB.executeUpdate(sql.toString(), m_trxName); int no = -1;
try {
no = DB.executeUpdateEx(sql.toString(), m_trxName);
} catch (DBException e) {
String msg;
if (DBException.isValueTooLarge(e)) {
msg = Msg.getMsg(getCtx(), "MismatchTrlColumnSize");
} else {
msg = "insertTranslations -> " + e.getLocalizedMessage();
}
throw new AdempiereException(msg, e);
}
if (uuidColumn != null && !uuidFunction) { if (uuidColumn != null && !uuidFunction) {
UUIDGenerator.updateUUID(uuidColumn, get_TrxName()); UUIDGenerator.updateUUID(uuidColumn, get_TrxName());
} }
@ -3887,6 +3898,7 @@ public abstract class PO
StringBuilder andNotBaseLang = new StringBuilder(" AND AD_Language!=").append(DB.TO_STRING(baselang)); StringBuilder andNotBaseLang = new StringBuilder(" AND AD_Language!=").append(DB.TO_STRING(baselang));
int no = -1; int no = -1;
try {
if (client.isMultiLingualDocument()) { if (client.isMultiLingualDocument()) {
if (client.getAD_Language().equals(baselang)) { if (client.getAD_Language().equals(baselang)) {
// tenant language = base language // tenant language = base language
@ -3895,7 +3907,7 @@ public abstract class PO
.append(sqlupdate) .append(sqlupdate)
.append("IsTranslated='N'") .append("IsTranslated='N'")
.append(whereid); .append(whereid);
no = DB.executeUpdate(sqlexec.toString(), m_trxName); no = DB.executeUpdateEx(sqlexec.toString(), m_trxName);
if (log.isLoggable(Level.FINE)) log.fine("#" + no); if (log.isLoggable(Level.FINE)) log.fine("#" + no);
} else { } else {
// tenant language <> base language // tenant language <> base language
@ -3907,7 +3919,7 @@ public abstract class PO
.append("IsTranslated='Y'") .append("IsTranslated='Y'")
.append(whereid) .append(whereid)
.append(getAD_Client_ID() == 0 ? andBaseLang : andClientLang); .append(getAD_Client_ID() == 0 ? andBaseLang : andClientLang);
no = DB.executeUpdate(sqlexec.toString(), m_trxName); no = DB.executeUpdateEx(sqlexec.toString(), m_trxName);
if (log.isLoggable(Level.FINE)) log.fine("#" + no); if (log.isLoggable(Level.FINE)) log.fine("#" + no);
if (no >= 0) { if (no >= 0) {
// set other translations as untranslated // set other translations as untranslated
@ -3916,7 +3928,7 @@ public abstract class PO
.append("IsTranslated='N'") .append("IsTranslated='N'")
.append(whereid) .append(whereid)
.append(getAD_Client_ID() == 0 ? andNotBaseLang : andNotClientLang); .append(getAD_Client_ID() == 0 ? andNotBaseLang : andNotClientLang);
no = DB.executeUpdate(sqlexec.toString(), m_trxName); no = DB.executeUpdateEx(sqlexec.toString(), m_trxName);
if (log.isLoggable(Level.FINE)) log.fine("#" + no); if (log.isLoggable(Level.FINE)) log.fine("#" + no);
} }
} }
@ -3928,9 +3940,19 @@ public abstract class PO
.append(sqlcols) .append(sqlcols)
.append("IsTranslated='Y'") .append("IsTranslated='Y'")
.append(whereid); .append(whereid);
no = DB.executeUpdate(sqlexec.toString(), m_trxName); no = DB.executeUpdateEx(sqlexec.toString(), m_trxName);
if (log.isLoggable(Level.FINE)) log.fine("#" + no); if (log.isLoggable(Level.FINE)) log.fine("#" + no);
} }
} catch (DBException e) {
String msg;
if (DBException.isValueTooLarge(e)) {
msg = Msg.getMsg(getCtx(), "MismatchTrlColumnSize");
} else {
msg = "updateTranslations -> " + e.getLocalizedMessage();
}
throw new AdempiereException(msg, e);
}
return no >= 0; return no >= 0;
} // updateTranslations } // updateTranslations