Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions base/src/main/java/org/compiere/model/MSequence.java
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,29 @@ public MSequence(Properties ctx, int AD_Client_ID, String sequenceName, int Star
setCurrentNextSys(StartNo/10);
} // MSequence;

/**
* Before Save
* @param newRecord new record
* @return true if it can be saved
*/
@Override
protected boolean beforeSave(boolean newRecord)
{
// A Table ID sequence (IsTableID='Y') name must be a valid SQL identifier, because the
// native sequence is created as <Name>_SEQ. A name with spaces or special chars
// (typically a document sequence mis-flagged as IsTableID='Y') breaks "CREATE SEQUENCE"
// and would never be consumed. Reject it to keep the data correct.
if (isTableID()) {
String name = getName();
if (name == null || !name.matches("[A-Za-z_][A-Za-z0-9_]*")) {
throw new AdempiereException(
Msg.parseTranslation(getCtx(), "@Name@ (@IsTableID@='Y'): '" + name + "'")
);
}
}
return true;
} // beforeSave


/**************************************************************************
* Get Next No and increase current next
Expand Down
62 changes: 61 additions & 1 deletion base/src/main/java/org/compiere/process/SequenceCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,16 @@ private static void checkTableID (Properties ctx, SvrProcess sp,
s_log.warning("AD_Sequence_ID=" + sequenceId + " could not be loaded, skipping");
return;
}
// If the name is invalid (e.g. spaces) but its canonical form (spaces -> '_')
// matches a real table, it was a typo: fix the stored name so it becomes a
// valid table-ID sequence and gets validated/created below.
String fixedName = fixTableSequenceName(seq);
if (fixedName != null) {
seq.saveEx();
if (sp != null) {
sp.addLog(0, null, null, "Sequence name fixed => " + fixedName);
}
}
int old = seq.getCurrentNext();
int oldSys = seq.getCurrentNextSys();
// Created may be null for some sequences; guard against NPE so the
Expand Down Expand Up @@ -266,16 +276,66 @@ private static void checkTableID (Properties ctx, SvrProcess sp,
s_log.fine("#" + counterValue);
} // checkTableID

/**
* Fix the name of a table-ID sequence stored with an invalid identifier (e.g. spaces).
* If the canonical form (whitespace collapsed to '_') matches a real table that has a
* &lt;canonical&gt;_ID column, the name was a typo: it is corrected on the PO (not saved
* here) and the new name is returned. Otherwise (name already valid, or no matching
* table) returns null and the caller leaves it for the skip+warning path.
* @param sequence sequence to inspect/fix
* @return the corrected name, or null if no correction applies
*/
private static String fixTableSequenceName(MSequence sequence) {
if (!sequence.isTableID()) {
return null;
}
String name = sequence.getName();
if (name == null || name.matches("[A-Za-z_][A-Za-z0-9_]*")) {
return null; // null or already a valid identifier
}
String canonical = name.trim().replaceAll("\\s+", "_");
if (!canonical.matches("[A-Za-z_][A-Za-z0-9_]*")) {
return null; // still invalid after normalization (other special chars)
}
// Match the table case-insensitively but fetch the REAL TableName so the stored name
// matches AD_Table exactly: validateTableIDValue() and the native sequence rely on the
// exact (case-sensitive) name.
String realTableName = DB.getSQLValueString(
sequence.get_TrxName(),
"SELECT t.TableName FROM AD_Table t"
+ " INNER JOIN AD_Column c ON (t.AD_Table_ID=c.AD_Table_ID)"
+ " WHERE UPPER(t.TableName)=UPPER(?) AND UPPER(c.ColumnName)=UPPER(?)",
canonical, canonical + "_ID"
);
if (realTableName == null || realTableName.isEmpty()) {
return null; // not a real table -> leave for skip+warn
}
sequence.setName(realTableName);
return realTableName;
}

/**
* Create Native sequence if not exists
*/
private static boolean createMissingNativeSequence(MSequence sequence, String transactionName) {
if(!sequence.isTableID()) {
return false;
}
String name = sequence.getName();
// A table-ID sequence name must be a valid SQL identifier (a real table name), because
// the native sequence is created as <name>_SEQ. Names with spaces or special chars
// (typically a document sequence mis-flagged as IsTableID='Y') break "CREATE SEQUENCE"
// and would never be consumed, so skip them and surface the misconfiguration.
if(name == null || !name.matches("[A-Za-z_][A-Za-z0-9_]*")) {
s_log.warning(
"Native sequence skipped, invalid name for IsTableID='Y': '"
+ name + "' (AD_Sequence_ID=" + sequence.getAD_Sequence_ID() + ")"
);
return false;
}
boolean SYSTEM_NATIVE_SEQUENCE = MSysConfig.getBooleanValue("SYSTEM_NATIVE_SEQUENCE",false);
if(SYSTEM_NATIVE_SEQUENCE) {
CConnection.get().getDatabase().createSequence(sequence.getName()+"_SEQ", 1, 0 , 99999999, sequence.getNextID(), transactionName);
CConnection.get().getDatabase().createSequence(name+"_SEQ", 1, 0 , 99999999, sequence.getNextID(), transactionName);
}
return true;
}
Expand Down
Loading