major
#29384
The TL-Script functions `resetSequence` and `generateSequenceId` generate a different sequence ID than `SequenceDefaultProvider` (in terms of suffix and context order), so they cannot reset a provider-managed sequence with a dynamic context
The TL-Script functions `resetSequence ` and `generateSequenceId `, along with the default model provider ` SequenceDefaultProvider `, construct the physical sequence identifier (the name passed to ` RowLevelLockingSequenceManager`) in a different order when a context is involved. As a result, `resetSequence` and `generateSequenceId` refer to a different DB sequence row than the auto-numbering managed by ` SequenceDefaultProvider ` whenever the provider uses a ` DynamicSequenceName ` (e.g., ` ContextAwareSequenceName`).
Divergent identifier construction
com.top_logic.model.search.expr.config.operations.string.ResetSequence#eval (module tl-model-search):
StringBuilder b = new StringBuilder(sequenceId); if (contextArg != null) SequenceIdGenerator.addNames(b, contextArg); b.append(SEQUENCE_SUFFIX); // "_SequenceId" // => <base> <context> _SequenceId
GenerateSequenceId#eval (same module) uses the identical order (context, then suffix).
com.top_logic.element.structured.util.SequenceDefaultProvider#createDefault (module tl-element):
StringBuilder b = new StringBuilder(_sequenceName).append(SequenceIdGenerator.SEQUENCE_SUFFIX);
if (dynamicSequenceName != null) {
Object contextName = dynamicSequenceName.getSequenceName(context);
SequenceIdGenerator.addNames(b, contextName);
}
// => <base> _SequenceId <context>
SequenceIdGenerator.addNames appends a separator followed by TLObject.tId().asString() (or the MetaLabelProvider label) for the context, i.e., a non-empty token. Thus, for a non-null context, the two constructions yield different strings:
- provider: <base>_SequenceId<sep><ctxId>
- functions: <base><sep><ctxId>_SequenceId
They only match when there is no context (no ` DynamicSequenceName`, or the dynamic name resolves to `null`).
Note also that ResetSequence and GenerateSequenceId each declare their own SEQUENCE_SUFFIX = "_SequenceId" constant instead of referencing SequenceIdGenerator.SEQUENCE_SUFFIX.
Impact
There is no way from TL-Script to reset (or continue) a SequenceDefaultProvider sequence that uses a dynamic context, because the functions always append _SequenceId last and cannot reproduce the provider's ...suffix...context layout. A ` resetSequence(base, context, value) ` call against such a provider sequence silently resets an unrelated, unused row and leaves the actual counter untouched.
Concrete case: a per-object number attribute configured with
<provider class="...SequenceDefaultProvider" sequence-name="X">
<dynamic-sequence-name class="...ContextAwareSequenceName"/>
</provider>
cannot be re-seeded via ` resetSequence("X", $context, n) ` after a bulk import that assigns explicit numbers, so subsequently created objects restart at 1 and collide with the imported numbers.
Backward-compatibility constraint for the fix
Simply reordering the functions to <base>_SequenceId<context> (to match the provider) is not backward compatible: existing `generateSequenceId` and `resetSequence` callers that pass a context already have persisted rows named <base><context>_SequenceId. After such a change, the functions would look up <base>_SequenceId<context>, find no row, and restart the counter at 1 (resulting in duplicate IDs). A straightforward alignment therefore requires a data migration to rename the existing sequence rows, or an opt-in mechanism (e.g., a new function or parameter that targets a provider-style sequence ID) that leaves the current script-sequence naming unchanged.
Migration
The physical sequence naming is unified to <base><context>_SequenceId (the technical suffix always comes last now), shared by SequenceDefaultProvider, SequenceIdGenerator/`NumberHandlerDefaultProvider`, and the generateSequenceId/`resetSequence` TL-Script functions. All of them construct the name using ` SequenceIdGenerator.sequenceName(base, context)`.
A data migration (Ticket_29384_unify_sequence_names, module tl-element) runs automatically on the first startup after the upgrade. It rewrites the existing object-annotated sequence rows (technical suffix _NumberHandler) in the Sequence table to the unified name, relocating the suffix after the context (the fixed _NumberHandler token marks the base/context boundary, so the rewrite is unambiguous). In the event of a name collision with a row already created by a script function, the higher counter value is retained, ensuring that no number is ever assigned twice. Sequences created by script functions (suffix _SequenceId) are already in the target layout and remain unchanged.
No manual steps are required.