diff --git a/migration/i8.2/oracle/202108182002_IDEMPIERE-4911.sql b/migration/i8.2/oracle/202108182002_IDEMPIERE-4911.sql new file mode 100644 index 0000000000..388d3b25f1 --- /dev/null +++ b/migration/i8.2/oracle/202108182002_IDEMPIERE-4911.sql @@ -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 +; + diff --git a/migration/i8.2/postgresql/202108182002_IDEMPIERE-4911.sql b/migration/i8.2/postgresql/202108182002_IDEMPIERE-4911.sql new file mode 100644 index 0000000000..f0698e73f5 --- /dev/null +++ b/migration/i8.2/postgresql/202108182002_IDEMPIERE-4911.sql @@ -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 +; + diff --git a/org.adempiere.base.process/src/org/compiere/process/TranslationDocSync.java b/org.adempiere.base.process/src/org/compiere/process/TranslationDocSync.java index cbca88a631..156d04b440 100644 --- a/org.adempiere.base.process/src/org/compiere/process/TranslationDocSync.java +++ b/org.adempiere.base.process/src/org/compiere/process/TranslationDocSync.java @@ -20,6 +20,8 @@ import java.math.BigDecimal; import java.util.List; import java.util.logging.Level; +import org.adempiere.exceptions.AdempiereException; +import org.adempiere.exceptions.DBException; import org.compiere.model.MClient; import org.compiere.model.MColumn; import org.compiere.model.MTable; @@ -29,6 +31,7 @@ import org.compiere.util.AdempiereUserError; import org.compiere.util.DB; import org.compiere.util.DisplayType; 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); if (log.isLoggable(Level.CONFIG)) log.config(baseTable + ": " + columnNames); - + + try { if (client.isMultiLingualDocument()) { String baselang = Language.getBaseAD_Language(); 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(getAD_Client_ID()).append(" AND AD_Language=").append(DB.TO_STRING(client.getAD_Language())); - int no = DB.executeUpdate(sql.toString(), get_TrxName()); - addLog(0, null, new BigDecimal(no), baseTable); + int no = DB.executeUpdateEx(sql.toString(), get_TrxName()); + addBufferLog(0, null, new BigDecimal(no), baseTable, 0, 0); } } else { // 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(getAD_Client_ID()); - int no = DB.executeUpdate(sql.toString(), get_TrxName()); - addLog(0, null, new BigDecimal(no), baseTable); + int no = DB.executeUpdateEx(sql.toString(), get_TrxName()); + 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 diff --git a/org.adempiere.base/src/org/adempiere/exceptions/DBException.java b/org.adempiere.base/src/org/adempiere/exceptions/DBException.java index 93fc4794b5..14702b7f40 100644 --- a/org.adempiere.base/src/org/adempiere/exceptions/DBException.java +++ b/org.adempiere.base/src/org/adempiere/exceptions/DBException.java @@ -36,13 +36,14 @@ import org.compiere.util.DB; */ 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; /** @@ -212,7 +213,18 @@ public class DBException extends AdempiereException 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 */ @@ -227,4 +239,5 @@ public class DBException extends AdempiereException return null; } } + } // DBException diff --git a/org.adempiere.base/src/org/compiere/model/MColumn.java b/org.adempiere.base/src/org/compiere/model/MColumn.java index 9b1c5f559f..1ca9bd4a33 100644 --- a/org.adempiere.base/src/org/compiere/model/MColumn.java +++ b/org.adempiere.base/src/org/compiere/model/MColumn.java @@ -524,6 +524,21 @@ public class MColumn extends X_AD_Column implements ImmutablePOSupport 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; } // beforeSave @@ -543,7 +558,26 @@ public class MColumn extends X_AD_Column implements ImmutablePOSupport || "EntityType".equals(get_ValueOld(COLUMNNAME_ColumnName).toString()))) { 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; } // afterSave diff --git a/org.adempiere.base/src/org/compiere/model/PO.java b/org.adempiere.base/src/org/compiere/model/PO.java index 3e5334edf0..a41e9fb2d2 100644 --- a/org.adempiere.base/src/org/compiere/model/PO.java +++ b/org.adempiere.base/src/org/compiere/model/PO.java @@ -3806,7 +3806,18 @@ public abstract class PO .append(" AND NOT EXISTS (SELECT * FROM ").append(tableName) .append("_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.") .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) { 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)); int no = -1; + try { if (client.isMultiLingualDocument()) { if (client.getAD_Language().equals(baselang)) { // tenant language = base language @@ -3895,7 +3907,7 @@ public abstract class PO .append(sqlupdate) .append("IsTranslated='N'") .append(whereid); - no = DB.executeUpdate(sqlexec.toString(), m_trxName); + no = DB.executeUpdateEx(sqlexec.toString(), m_trxName); if (log.isLoggable(Level.FINE)) log.fine("#" + no); } else { // tenant language <> base language @@ -3907,7 +3919,7 @@ public abstract class PO .append("IsTranslated='Y'") .append(whereid) .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 (no >= 0) { // set other translations as untranslated @@ -3916,7 +3928,7 @@ public abstract class PO .append("IsTranslated='N'") .append(whereid) .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); } } @@ -3928,9 +3940,19 @@ public abstract class PO .append(sqlcols) .append("IsTranslated='Y'") .append(whereid); - no = DB.executeUpdate(sqlexec.toString(), m_trxName); + no = DB.executeUpdateEx(sqlexec.toString(), m_trxName); 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; } // updateTranslations