major
#29384
TL-Script resetSequence/generateSequenceId build a different sequence id than SequenceDefaultProvider (suffix/context order), so they cannot reset a provider-managed sequence with a dynamic context
The TL-Script functions resetSequence and generateSequenceId and the model default provider SequenceDefaultProvider compose the physical sequence identifier (the name passed to RowLevelLockingSequenceManager) in a different order when a context is involved. As a result, resetSequence/`generateSequenceId` address 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 plus TLObject.tId().asString() (or the MetaLabelProvider label) for the context, i.e. a non-empty token. So for a non-null context the two constructions yield different strings:
- provider: <base>_SequenceId<sep><ctxId>
- functions: <base><sep><ctxId>_SequenceId
They only coincide 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 real 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/`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 (duplicate ids). A straightforward alignment therefore requires a data migration renaming the existing sequence rows, or an opt-in mechanism (e.g. a new function/parameter that targets a provider-style sequence id) that leaves the current script-sequence naming untouched.
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 build the name through 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 behind the context (the fixed _NumberHandler token marks the base/context boundary, so the rewrite is unambiguous). On a name collision with a row that a script function already created, the higher counter value is kept, so no number is ever handed out twice. Sequences created by the script functions (suffix _SequenceId) are already in the target layout and are left unchanged.
No manual steps are required.