Eine nicht-binäre String-Spalte soll sich auf allen unterstützten Datenbanken case-insensitive verhalten (Vergleich, Eindeutigkeit, Sortierung). Aktuell ist das nur auf H2 (VARCHAR_IGNORECASE), MySQL (Default-*_ci-Collation) und MSSQL (Latin1_General_CI_AS) der Fall. Auf PostgreSQL (kein COLLATE → Cluster-/DB-Default), Oracle (NVARCHAR2 ohne CI-Collation) und DB2 wird case-sensitiv verglichen. Folge: ein UNIQUE-Index über einer nicht-binären Spalte lehnt case-insensitiv gleiche Werte dort nicht ab.
Umsetzung
- PostgreSQL: nicht-binäre String-/CLOB-Spalten erhalten eine nondeterministische ICU-Collation (locale und-u-ks-level2, case-insensitiv/akzentsensitiv), die beim Schema-Setup einmalig angelegt wird. LIKE bekommt auf Postgres ein deterministisches COLLATE "C" am Operanden (sonst Fehler bei nondeterministischer Collation). PG 12+.
- Oracle: keine Spalten-Collation supportsColumnCollation() == false). Eine Spalten-Collation setzt Oracle 12.2+ mit MAX_STRING_SIZE=EXTENDED} voraus; die Case-Insensitivität hängt daher an der Datenbank-/Session-Konfiguration (NLS_COMP=LINGUISTIC und ein NLS_SORT, das auf _CI oder _AI endet). Startup-Prüfung, die andernfalls einen Fehler protokolliert.
- DB2: keine Spalten-Collation möglich (nur DB-weit) → Startup-Prüfung, dass die Datenbank eine CI-Collation nutzt.
- ORDER BY: NATURAL-Hint auf den betroffenen Dialekten an die CI-Collation angleichen.
- H2/MySQL/MSSQL: unverändert.
- Bestand: DDL-Änderung greift für neue Spalten; zusätzlich ein Migrations-Werkzeug, das bestehende nicht-binäre Spalten gezielt oder auf Wunsch über alle Tabellen auf CI-Collation umstellt.
Migration
Betroffen sind Applikationen auf PostgreSQL und Oracle.
1. PostgreSQL: Voraussetzungen
- PostgreSQL 12 oder neuer, gebaut mit ICU-Unterstützung. Beides wird beim Start geprüft und andernfalls als Fehler protokolliert.
- Der DB-Benutzer der Applikation muss eine Collation anlegen dürfen (Recht CREATE auf dem Schema, in dem die Collation entsteht). Die Collation tl_ci wird bei jeder Initialisierung eines Connection-Pools über CREATE COLLATION IF NOT EXISTS "tl_ci" (provider = icu, locale = 'und-u-ks-level2', deterministic = false) auf einer Schreibverbindung angelegt. Fehlt das Recht, startet die Applikation nicht.
- Existiert die Collation nicht (z.B. weil sie in einem anderen Schema liegt, das nicht im search_path steht), schlagen zusätzlich alle Abfragen mit ORDER BY fehl: Der NATURAL-Sortier-Hint verweist jetzt auf COLLATE "tl_ci".
2. PostgreSQL: Bestehende Spalten umstellen (erforderlich)
Die DDL-Änderung greift nur für neu erzeugte Spalten. In einer bestehenden Datenbank entstehen dadurch gemischte Collations, und PostgreSQL bricht den Vergleich zweier Spalten mit unterschiedlichen impliziten Collations mit einem Fehler ab (could not determine which collation to use for string comparison, SQLSTATE 42P22). Ein Join oder Vergleich zwischen einer neu erzeugten (tl_ci) und einer alten Spalte (Default-Collation) läuft damit auf einen Laufzeitfehler. Die Umstellung bestehender Spalten ist auf PostgreSQL deshalb kein optionaler Komfortschritt, sondern Teil der Migration.
Die Engine liefert kein Migrationsskript dafür mit -- der Prozessor RecollateStringColumnsProcessor ist in ein Migrationsskript der Applikation einzutragen:
#!xml
<?xml version="1.0" encoding="utf-8" ?>
<migration config:interface="com.top_logic.knowledge.service.migration.MigrationConfig"
xmlns:config="http://www.top-logic.com/ns/config/6.0"
>
<version name="Ticket_XXXXX_recollate_string_columns"
module="my-app"
/>
<dependencies>
<dependency name="<letzte-eigene-version>"
module="my-app"
/>
</dependencies>
<processors>
<processor class="com.top_logic.knowledge.service.migration.processors.RecollateStringColumnsProcessor" />
</processors>
<post-processors/>
</migration>
Ohne table und column werden alle nicht-binären String-Spalten aller Tabellen umgestellt. Für eine gezielte Umstellung können die logischen Namen aus dem TopLogic-Metaschema angegeben werden:
#!xml
<processor class="com.top_logic.knowledge.service.migration.processors.RecollateStringColumnsProcessor"
table="Person"
column="name"
/>
Auf Dialekten ohne Spalten-Collation (Oracle, DB2) ist der Prozessor ein No-op und protokolliert das.
3. PostgreSQL: Vor der Umstellung auf Duplikate prüfen
Die Umstellung führt pro Spalte ein ALTER TABLE ... ALTER COLUMN ... TYPE ... aus; die Tabelle und ihre Indizes werden dabei neu aufgebaut. Enthält eine Spalte mit einem UNIQUE-Index Werte, die sich nur in der Groß-/Kleinschreibung unterscheiden, scheitert die Migration beim Neuaufbau des Index. Solche Werte sind vorher zu bereinigen, z.B.:
#!sql SELECT lower(NAME), count(*) FROM PERSON GROUP BY lower(NAME) HAVING count(*) > 1;
4. PostgreSQL: Laufzeit und Wartungsfenster
Über alle Tabellen ist die Umstellung ein langlaufender, sperrender ALTER-Sweep, der die betroffenen Tabellen neu schreibt (Sperren, temporärer Plattenplatz in Größe der Tabelle). Sie ist in einem Wartungsfenster durchzuführen; bei großen Datenbanken kann sie tabellenweise auf mehrere Migrationsschritte verteilt werden.
5. Oracle: Datenbank-Konfiguration
Oracle setzt keine Collation pro Spalte. Die Case-Insensitivität nicht-binärer Spalten hängt an der NLS-Konfiguration:
| Parameter | Erforderlicher Wert |
| NLS_COMP | LINGUISTIC |
| NLS_SORT | eine Collation, die auf _CI oder _AI endet (z.B. GENERIC_M_CI) |
Beim Start wird das geprüft; passt die Konfiguration nicht, wird ein Fehler protokolliert und nicht-binäre Spalten werden weiterhin case-sensitiv verglichen -- ein UNIQUE-Index lehnt case-insensitiv gleiche Werte dann nicht ab. TopLogic bietet keinen Hook für Init-SQL pro Verbindung, die Werte sind daher an der Datenbank bzw. Instanz zu setzen (Instanz-Parameter / ALTER SYSTEM, nicht pro Session).
6. Spalten, die case-sensitiv bleiben sollen
Auf PostgreSQL und Oracle werden praktisch alle String-Spalten case-insensitiv -- für Vergleich, Eindeutigkeit und Sortierung. Wo Groß-/Kleinschreibung unterschieden werden muss (z.B. technische Schlüssel, Passwort-Hashes, Base64-Werte), ist die Spalte im Schema als binary="true" zu deklarieren; solche Spalten dürfen nicht umgestellt werden (der Prozessor überspringt sie).