Kuonen SQL

Handbuch

Syntax, Datentypen, Funktionen und Fehlernummern je Abfragesprache — jeder Abschnitt mit einem Beispiel aus dem Beispielkatalog und, wo die Sprache einen eigenen Sprachmeilenstein der Roadmap hat, dem Stand jedes einzelnen Punktes daraus.

KSQL ist der Kern von KuonenSQL nach ISO/IEC 9075:2023. Über Port 1333 (voreingestellt aus, Umgebungsvariable KUONENSQL_KSQL_PORT) spricht der Server TDS wie am T-SQL-Port — jeder Treiber für SQL Server verbindet sich (Microsoft.Data.SqlClient, JDBC, go-mssqldb, der eigene Manager) —, nennt in @@VERSION und SERVERPROPERTY aber ehrlich KuonenSQL. Es ist derselbe Datenbestand wie über T-SQL, MariaDB und PostgreSQL: Sperren, Transaktionen und Blockaden gelten über alle Zugänge.

Treiber

Eigene KSQL-Treiber, je nach dem Vorbild des Microsoft-Treibers (D36.8: eine Handbuchseite je Treiber): .NET · Java (JDBC) · TypeScript/JavaScript · C/ODBC · PHP · C++ · Python · Go

Regeln bei Widerspruch zur T-SQL

Wo T-SQL und die Norm verschieden rechnen, gilt am KSQL-Zugang die Norm; wo die Norm die Wahl lässt, bleibt KSQL beim Kern, damit dieselbe Datenbank über jeden Zugang dieselben Werte zeigt. Es gibt keinen Schalter: die Wahl des Zugangs ist die Wahl des Verhaltens.

FallT-SQLKSQL
UNIQUE und NULLeine NULL, die zweite ist 2627beliebig viele NULL (NULL ist nie gleich NULL)
Primärschlüssel nachträglich auf Spalte mit NULLFehler 8111schliesst NOT NULL ein
ADD COLUMN … DEFAULTvorhandene Zeilen NULLvorhandene Zeilen bekommen die Vorgabe
CAST(x AS VARCHAR) ohne Länge30 Zeichenohne Grenze
0x1FBinärwertGanzzahl; ein Binärwert ist X'1F'
BOOLEANnur bitBOOLEAN mit TRUE, FALSE und UNKNOWN
COMMIT/ROLLBACK ohne offene TransaktionFehler 3902/3903erlaubt
TIMESTAMP als TyprowversionZeitpunkt (datetime2(6))
'ab' und 'cd' über einen Zeilenumbruch'cd' ist der Spaltennameein Literal 'abcd'
LOG(a, b)LOG(zahl, basis)LOG(basis, zahl)
OFFSET … FETCH … WITH TIESnicht erlaubtder Gleichstand zählt ab dem Versatz

Merkmale der Norm

Die Merkmalsliste von ISO SQL:2023 steht im Server (INFORMATION_SCHEMA.SQL_FEATURES); jedes unterstützte Merkmal hat eine Probe, die der Testlauf am KSQL-Zugang ausführt.

Teil der NormUnterstütztMerkmale
Teil 2435585
Teil 488
Teil 9025
Teil 1178
Teil 1490137
Teil 162930
Punkt Beschreibung Stand
K33.1 KSQL als Kern, T-SQL als Dialektmodul, eigener Port Nach dem Grundsatzentscheid vom 15.10.2026: der heutige Ausführer (Parser, Ausführer, Ablage, Katalog) ist der Kern = KSQL; **T-SQL wird Dialektmodul wie MariaDB** über die gemeinsamen Nahtstellen, zunächst mit genau dem heutigen Verhalten und der SQL-Server-Kennung (aus dem Kern dorthin verschoben); eigener TDS-Hörer für KSQL (`KUONENSQL_KSQL_PORT`, Vorgabe **1333**), Zugang `Zugang.Ksql` für Sitzungen, Verbindungsgrenzen und Protokoll; Unterschiede nur als Eigenschaften der Dialektbeschreibung. Dienstvorlagen (Docker, Linux, macOS, Windows) und die Installationsseite der gemeinsamen Webseite um den Port ergänzt. **Erledigt 15.10.2026:** `Dialekt.Ksql` (Kennung 4) ist der Kern, `TSql/TSqlDialekt.cs` (Kennung 0, Vorgabe jeder Sitzung ohne eigenen Anschluss) das Modul samt `TSql/Serverkennung.cs`; die sechs Namensabfragen auf T-SQL sind die Eigenschaft `Kernregeln`, die Fremddialekte setzen sie aus; Hörer `ksql` über `KUONENSQL_KSQL_PORT` (im Programm aus, in den Dienstvorlagen und im Compose 1333), `Zugang.Ksql`; `KsqlZugangTests`. ✅
K33.2 Ehrliche Kennung Am KSQL-Port melden `@@VERSION`, `SERVERPROPERTY('ProductVersion'/'ProductMajorVersion'/'ProductLevel'/'Edition'/'EngineEdition'/'ProductBuild')`, `@@MICROSOFTVERSION`, die TDS-Vorabmeldung (Fassung) und LOGINACK (Programmname `KuonenSQL`) die echte KuonenSQL-Fassung; `sys.dm_os_host_info`, `host_platform`, Pfade und Trennzeichen das echte Wirtssystem (Linux/macOS/Windows, Architektur, .NET-Fassung); `xp_msver`, `sys.dm_os_sys_info` mit echten Werten. Eigene `EngineEdition` und Edition „KuonenSQL“. Am T-SQL-Port bleibt alles wie SQL Server 2025 (`@@KVERSION` bleibt dort). **Erledigt 15.10.2026** mit K33.1 (die Kennung ist eine Eigenschaft des Dialekts, `Dialekte/Ansage.cs`): `@@VERSION`, `@@MICROSOFTVERSION`, `SERVERPROPERTY` (Fassung, Stufe, Edition „KuonenSQL“, EngineEdition 100, EditionID „KSQL“, Pfade, Trennzeichen), `sys.dm_os_host_info`, Vorabmeldung und LOGINACK (`KuonenSQL`, SqlClient: `ServerVersion` 01.12.…) melden am KSQL-Port die Wahrheit. Rest in K33.2a. ✅
K33.2a Rest aus K33.2: `xp_msver` und `sys.dm_os_sys_info` Am KSQL-Port nennt `xp_msver` noch Produktname, Hersteller, Dateibeschreibung und Windows-Fassung von SQL Server (Fassung und Bau sind schon echt), `sys.dm_os_sys_info` die Werte des Nachbaus; beide aus der `Ansage` des Dialekts speisen. **Erledigt 15.10.2026:** `xp_msver` liest Produktname, Hersteller, Dateibeschreibung und -version, Programmdatei, Urheberrecht, Marke, Plattform und Windows-Fassung aus der `Ansage` (T-SQL wortgleich wie bisher); `sys.dm_os_sys_info` nennt an jedem Zugang den echten Speicher, belegten Speicher und die Startzeit des Prozesses (vorher feste 16 GB und „vor einer Stunde“). ✅
K33.3 Merkmalsliste ISO SQL:2023 `tools/ksql/iso-merkmale.tsv` mit allen Merkmalen von Teil 2 (Foundation), 4 (PSM), 9 (MED, nur Kennung), 11 (Schemata), 14 (XML), 15 (MDA) und 16 (PGQ): Kennung, Name, Pflicht/optional, Status, Testname; Prüfung im Test, dass jedes ✅-Merkmal einen grünen Test hat. Daraus `INFORMATION_SCHEMA.SQL_FEATURES`, `SQL_IMPLEMENTATION_INFO`, `SQL_SIZING` und die Übersicht im Handbuch. **Erledigt 15.10.2026:** die Liste liegt als `src/Server/Kuonen.Data.KuonenSql/Ksql/Referenzdaten/iso-merkmale.tsv` (eingebettet; 788 Merkmale: Teil 2, 9, 11, 14 aus `information_schema.sql_features` von PostgreSQL 17 am Referenzcontainer gemessen, Teil 16 aus der öffentlichen Konformitätsliste SQL/PGQ von Oracle, Teil 4 nur P001–P003 mit unbestätigtem Namen). Jede Probe läuft am KSQL-Zugang, `KsqlMerkmalTests` verlangt Status „+“ genau dann, wenn sie läuft; Proben für alle 35 Merkmale von Core SQL, davon heute 108 Zeilen „+“. `INFORMATION_SCHEMA.SQL_FEATURES`, `SQL_PARTS`, `SQL_IMPLEMENTATION_INFO`, `SQL_SIZING` am KSQL-Zugang (Modul `Ksql/`). Die Übersicht im Handbuch gehört zu K33.15. ✅
K33.4 Regeln bei Widerspruch T-SQL ↔ Norm Wo T-SQL und Norm verschieden rechnen, gilt am KSQL-Port die Norm, T-SQL bleibt per `SET`-Schalter erreichbar - Liste mit Entscheid des Nutzers je Fall: Verkettung `||` und `+`, `"` als Bezeichner, Ganzzahldivision, NULL in Verkettungen, Vergleich mit Leerzeichen am Ende (PAD SPACE/NO PAD je Sortierung), `''` gegen NULL, Grösse von `CHAR` ohne Länge, `BOOLEAN` gegen `bit`, Ergebnistypen von Ausdrücken, Gross-/Kleinschreibung nicht zitierter Namen (Norm: Grossschreibung). **Erledigt 15.10.2026:** Liste mit Entscheid je Fall in nach der Leitlinie des Grundsatzentscheids (Norm bei Widerspruch, sonst Kern; kein SET-Schalter, die Wahl des Zugangs ist die Wahl des Verhaltens). Am KSQL-Zugang gelten jetzt `UNIQUE` mit mehreren NULL, NOT NULL durch nachträglichen Primärschlüssel, Vorgabe für vorhandene Zeilen bei `ADD COLUMN`, `CAST` ohne Länge ohne Grenze (`KsqlNormregelnTests`, je Regel beide Zugänge); dazu die Grammatik `NATURAL JOIN`/`USING`, `WITH RECURSIVE`, Zeilenwerte, `GROUPS`/`EXCLUDE`. Die Fälle `0x`-Literal und `BOOLEAN` setzt K33.5 um, `COMMIT` ohne Transaktion K33.9. ✅
K33.5 Core SQL: Typen und Literale `BOOLEAN` als echter Typ (TRUE/FALSE/UNKNOWN, `IS TRUE/FALSE/UNKNOWN`), `CHARACTER VARYING`, `CHARACTER LARGE OBJECT`, `BINARY LARGE OBJECT`, `DOUBLE PRECISION`, `DECFLOAT`, `TIME/TIMESTAMP WITH TIME ZONE`, `INTERVAL YEAR TO MONTH`/`DAY TO SECOND` samt Rechnung mit Zeitpunkten; Literale `DATE '…'`, `TIME '…'`, `TIMESTAMP '…'`, `INTERVAL '…' DAY`, `U&'…'` mit `UESCAPE`, `X'…'`, SQL:2023 `0x`/`0o`/`0b` und Unterstriche in Zahlen; Typen `ROW`, `ARRAY` (S091) und `MULTISET` (S271) mit Konstruktoren, `UNNEST`, `CARDINALITY`. **Erledigt 15.10.2026 bis auf K33.5a:** Literale `X'…'` (mit Leerzeichen, fortgesetzt), `U&'…'`/`U&"…"` mit `UESCAPE`, Fortsetzung über Zeilenumbrüche, `0x`/`0o`/`0b`, Unterstriche; `DATE/TIME/TIMESTAMP '…'`; `BOOLEAN` mit `TRUE`/`FALSE`/`UNKNOWN` und `IS …`; `CHARACTER VARYING`, `CHARACTER/BINARY LARGE OBJECT`, `CLOB`/`BLOB`, `DOUBLE PRECISION`, `TIME/TIMESTAMP [WITH TIME ZONE]`. ✅
K33.5a Rest aus K33.5: `INTERVAL`, `DECFLOAT`, `ROW`/`ARRAY`/`MULTISET` `INTERVAL YEAR TO MONTH`/`DAY TO SECOND` als Typen samt Literalen (`INTERVAL '3' DAY`) und Rechnung mit Zeitpunkten (F052), `DECFLOAT(16|34)` (T076; der Kern nahm `DECFLOAT` bisher still an und rechnete falsch, K33.16), Zeilentypen `ROW(…)` mit Feldzugriff (T051, T053), `ARRAY` (S091) und `MULTISET` (S271) mit Konstruktoren, `UNNEST`, `CARDINALITY`. **Erledigt 20.10.2026** (Arrays, Zeilen, `UNNEST` und Intervall-Literale an PostgreSQL 17 gemessen, T-SQL am Orakel 2025; DECFLOAT, `(a - b) <Felder>`, DATE + INTERVAL und Monatsende nach Normtext, keine Referenz kennt sie): Intervalle mit Feldangabe, Literale in Normform (Vorzeichen für alle Felder, 22006/22015), `(a - b) DAY TO SECOND`, Zeitpunkt ± Intervall mit dem Typ des Zeitpunkts, Monatsende 22008, `EXTRACT` (Werte an PostgreSQL 17 gemessen, wo es der Norm folgt); `DECFLOAT(p)` als eigener Typ nur am KSQL-Zugang (halb-gerade auf p Stellen, Exponentenbereich decimal64/128); `ROW(…)` als Typ und Wert, `(r).feld`, `(r).* AS (x, y)`, `typ ARRAY[n]`, `ARRAY[…]`, `a[i]` (2202E), `||`, `typ MULTISET`, `MULTISET[…]`, `ELEMENT`, `CARDINALITY`, `UNNEST … WITH ORDINALITY` auch seitlich; Fehlernummern 23301–23305; T-SQL unverändert (Orakel 19./20.10.2026). F052, T076, T051, T053, S090, S091, S271 „+“. Rest K33.5c. ✅
K33.5c Reste aus K33.5a Konstruktoren durch Abfrage `ARRAY(SELECT …)`/`MULTISET(SELECT …)` (S095), `ARRAY_AGG` (S098), `TRIM_ARRAY`/`ARRAY_MAX_CARDINALITY` (S403, S404), Multimengen-Operatoren (S275), `(r).*` ohne Namensliste, Prüfungen 2202F und 22015, Jahr-Monat gegen Tag-Zeit, geschachtelte Sammlungen und Arrays von Zeilen (S281), `datetimeoffset`-Elemente, Funktionen über `DECFLOAT`, `INFORMATION_SCHEMA` für die neuen Typen, T-SQL-Punkte. **Erledigt 20.10.2026** (an PostgreSQL 17 und SQL Server 2025 gemessen, sonst Normtext): Arrays mit beliebigem Elementtyp (`kt:array(T)[n]`, Höchstzahl geprüft 2202F), `ARRAY(…)`/`MULTISET(…)` und `ARRAY_AGG`/`COLLECT`/`FUSION`/`INTERSECTION` über das Aggregat `__KSQL_SAMMELN`, `TRIM_ARRAY`, `ARRAY_MAX_CARDINALITY`, `MULTISET UNION/EXCEPT/INTERSECT`, `SET`, `MEMBER OF`, `SUBMULTISET OF`, `IS A SET`, `(r).*`, führende Intervall-Genauigkeit (22015), Jahr-Monat gegen Tag-Zeit 402, `ABS`/`SIGN`/`FLOOR`/`CEILING`/`ROUND`/`MOD`/`POWER`/`SQRT`/`EXP`/`LN`/`LOG`/`LOG10` über `DECFLOAT`, `COLUMNS` und `ELEMENT_TYPES`; T-SQL: `CAST` auf Nicht-Systemtyp und Aliastyp 243, Wörter hinter dem Spaltentyp und Namen in der Typklammer 102. S095, S096, S098, S275, S281, S403, S404 „+“. Rest K33.5d. ✅
K33.5d Reste aus K33.5c Die Länge eines Textelements einer Multimenge (`VARCHAR(3) MULTISET`) bei der Zuweisung prüfen (22001) statt zu kürzen; Jahr-Monat gegen Tag-Zeit auch prüfen, wenn eine Seite ein Intervall ohne Feldangabe aus einer Rechnung ist; T-SQL: `int(5)` als Spaltentyp 2716 (am Orakel 2025), heute angenommen; `tools/ksql/normsichten-erzeugen.py` wieder deckungsgleich mit `Normsichten.Definitionen.cs` machen. **Erledigt 20.10.2026:** Länge der Elemente von Multimengen, Arrays und Zeilenfeldern bei einer Zuweisung 2628 (22001), `CAST` kürzt; eine Intervallrechnung trägt die Felder ihrer Operanden, so bleibt die Klasse im Zwischenergebnis (402); `int(5)` u. a. am T-SQL-Zugang 2716, in `CAST` 291 (Orakel 2025); das Erzeugerskript erzeugt die Normsichten wieder byte-genau. **Bewusst nicht:** ein Intervall ganz ohne Feldangabe (PostgreSQL-Form, `sum` über Intervalle) hat keine Klasse der Norm und wird nicht als Jahr-Monat oder Tag-Zeit geraten - es vergleicht wie bei PostgreSQL. ✅
K33.5e Befund aus K33.5c: verschachtelte Zahlenfunktionen exponentiell Die Typableitung von ABS, SIGN, FLOOR, CEILING, ROUND und POWER fragt seit K33.5c den Typ des ersten Arguments zweimal ab (Zweig für eigene Zahlentypen und allgemeiner Zweig) - 2^n Schritte je Verschachtelungstiefe. Der Langläufer SchachtelgrenzenTests (ABS 1013 Ebenen) lief nie zu Ende und hielt den grossen Testlauf vor der Veröffentlichung über vier Stunden auf. **Erledigt 22.10.2026:** ArgType merkt sich den Typ des ersten Arguments, der Zweig von K33.5c nutzt ihn; 200 Ebenen ABS in Millisekunden statt nie. ✅
K33.6 Core SQL: Abfragen **Teil 1 erledigt (15.10.2026): `FETCH FIRST|NEXT [n] [PERCENT] ROW|ROWS ONLY|WITH TIES` ohne `OFFSET`, auch in Unterabfragen, Sichten und Mengenoperationen (F433, F850–F868, T619), **Teil 2 erledigt:** `EXCEPT`/`INTERSECT` `ALL`/`DISTINCT` (E071-03, F303–F305), `CORRESPONDING [BY (…)]` (F301), erweitertes einfaches `CASE` (`WHEN < 3`, `WHEN 1, 2`, F262/F263), Spaltenliste hinter dem Tabellenalias (E051-09), `WITH` in Unterabfragen (T122, T132). **Teil 3 erledigt:** `NATURAL JOIN` über Tabellen aus demselben Stapel (F401, F405; der Ausführer liest den Rest des Stapels nach), `JOIN … USING (…) AS j` (F404), `NTH_VALUE … [FROM FIRST|LAST] [IGNORE NULLS]` (T618), `ANY_VALUE` (T626), `LISTAGG` (T625). **Teil 4 erledigt:** `FILTER (WHERE …)` an Aggregaten, auch vor `OVER` (T612); **Teil 5 erledigt:** `BETWEEN SYMMETRIC` (T461), `NULLS FIRST|LAST`, `EVERY`/`SOME`/`ANY`/`BOOL_AND`/`BOOL_OR`, `UNIQUE (…)` (F291), `GROUPING(a, b)` (T433), Gruppierungsglieder als Kreuzprodukt samt verschachteltem `ROLLUP` in `GROUPING SETS` (T432, auch T-SQL wie SQL Server) und `GROUP BY DISTINCT|ALL` (T434), funktionale Abhängigkeit vom Primärschlüssel (T301), `SET (a, b) = (…)` (T641), `LISTAGG … ON OVERFLOW`; **Teil 6 erledigt:** `LATERAL` hinter Komma, `JOIN` und `LEFT JOIN` (T491), `VALUES` und `TABLE t` als Abfrage samt `ORDER BY`/`FETCH` und als Glied einer Mengenoperation, `VALUES ROW(…)`, `WITH … AS (VALUES …)` (Spalten `column1` … wie PostgreSQL); **Teil 7 erledigt:** `TABLESAMPLE [SYSTEM] (n PERCENT|ROWS) [REPEATABLE (s)]` im Kern wie SQL Server (fehlte, auch am T-SQL-Zugang; 476 ausserhalb 0..100), am KSQL-Zugang `BERNOULLI` (T613); `LISTAGG … OVER (…)` (T625; T-SQL 4113 wie das Orakel); **Teil 8 erledigt:** `SEARCH DEPTH|BREADTH FIRST BY … SET` und `CYCLE … SET … [TO … DEFAULT …] USING` hinter `WITH RECURSIVE` (T131–T133; Pfad als geordnete Bytefolge, Reihenfolge wie PostgreSQL 17), `[KEY] k VALUE v` in `JSON_OBJECT`/`JSON_OBJECTAGG` (T811–T814); siehe .** Rest: `MATCH_RECOGNIZE` als K33.6a. ✅
K33.6a `MATCH_RECOGNIZE` (R010, R020) **Erledigt (19.10.2026).** Am KSQL-Zugang Zeilenmuster nach SQL:2016 als Tabellenoperator (R010): `PARTITION BY`, `ORDER BY`, `MEASURES` mit `RUNNING`/`FINAL`, `ONE ROW|ALL ROWS PER MATCH` (`SHOW|OMIT EMPTY MATCHES`, `WITH UNMATCHED ROWS`), `AFTER MATCH SKIP PAST LAST ROW|TO NEXT ROW|TO FIRST|LAST v`, `PATTERN` mit `*`, `+`, `?`, `{n,m}` (auch zurückhaltend), Alternativen, Gruppen, `^`/`$`, `{- … -}`, `PERMUTE`, `SUBSET` und `DEFINE` mit `PREV`/`NEXT`/`FIRST`/`LAST` (verschachtelt), `CLASSIFIER`, `MATCH_NUMBER` und laufenden Aggregaten; dazu die Fensterform (R020: `MEASURES` und Muster im `WINDOW`, `INITIAL`/`SEEK`, `mass OVER w`). Orakel: Referenzcontainer `kq-ref-trino` (Trino 476, nur von aussen gemessen). Auswertung als Rückverfolgung mit eigenem Stapel, gedeckelt (Schrittgrenze, Programmgrösse) gegen bösartige Muster. Am T-SQL-Zugang bleibt es ein Syntaxfehler wie bei SQL Server 2025 (102, ohne Alias 156). Rest: K33.6b. ✅
K33.6b Rest aus K33.6a: R030 und Fensterform einmal je Fenster **Erledigt (20.10.2026), nach Normtext, Abgleich als K33.6c offen.** Teil 1: die Fensterform (R020) sucht die Treffer einmal je Fenster und Partition statt je Fensterfunktion (3000 Zeilen, 5 Funktionen: 48,5 → 23,0 ms). Teil 2 (R030): jedes Aggregat des Kerns in `MEASURES` und `DEFINE` der Mustererkennung, auch mit `DISTINCT`, `FILTER (WHERE …)`, `WITHIN GROUP (ORDER BY …)` und `CLASSIFIER()`/`MATCH_NUMBER()` im Argument. ✅
K33.6c Rest aus K33.6b: R030 am Orakel abgleichen **Erledigt (20.10.2026).** An `kq-ref-trino` gemessen: alle Aggregate, die Trino in der Mustererkennung rechnet, stimmen (`MIN(CLASSIFIER())`, `SUM(MATCH_NUMBER())`, `SUM(B.p * 2)`, `var_pop`, `stddev_samp`, `every`, `bool_or`, `COUNT(B.p + 1)`, `MAX(p) - MIN(p)`), ebenso die Fensterprobe aus K33.6b und die Fensterform mit Statistik. Abweichung behoben: `ANY_VALUE` ist im Treffer der erste Wert (Trino 8 und 5, vorher der kleinste 6 und 4). `SUM(PREV(p))` ist an beiden ein Fehler. `DISTINCT`, `FILTER` und `WITHIN GROUP` lehnt Trino in der Mustererkennung ab; KSQL rechnet sie nach der Norm (R030). ✅
K33.7 Core SQL: Funktionen **Erledigt (15.10.2026).** Am KSQL-Zugang nach der Norm: `POSITION`, `SUBSTRING … FROM … FOR` und `SUBSTRING … SIMILAR … ESCAPE` (T581), `OVERLAY`, `EXTRACT`, `TRIM(BOTH/LEADING/TRAILING …)`, `CHARACTER_LENGTH … USING`, `OCTET_LENGTH`, `LOCALTIME`/`LOCALTIMESTAMP`, `CURRENT_CATALOG`/`CURRENT_SCHEMA`, `LIKE_REGEX` und die `…_REGEX`-Funktionen, `[NOT] SIMILAR TO` (NonBacktracking, 2 s Frist), `LN`, `LOG(basis, zahl)` (Regel K33.4), `SINH`/`COSH`/`TANH`, `CEIL`, `WIDTH_BUCKET`, `BTRIM`, `STDDEV_POP/SAMP`, `VAR_POP/SAMP`. Kernfehler: `SUBSTRING` mit Länge 2147483647 lief über (Orakel `cdef`). 262 Merkmale „+“. Siehe . ✅
K33.7a Rest aus K33.7: Statistik, `NORMALIZE`, `CAST … FORMAT` **Erledigt (15.10.2026).** Am KSQL-Zugang: `COVAR_POP`, `COVAR_SAMP`, `CORR` und `REGR_SLOPE|INTERCEPT|COUNT|R2|AVGX|AVGY|SXX|SYY|SXY` als Aggregate und im Fenster (T621, über die Paare ohne NULL, zwei Durchgänge; Werte an PostgreSQL 17 gemessen), hypothetische Aggregate `RANK|DENSE_RANK|PERCENT_RANK|CUME_DIST(w) WITHIN GROUP (ORDER BY …)`, `NORMALIZE(x [, NFC|NFD|NFKC|NFKD])` und `x IS [NOT] [NFC|…] NORMALIZED` (T061-Teil), `CAST(… AS … FORMAT 'vorlage')` für Zeitwerte in beide Richtungen (T839; kein Orakel kennt es, Regeln nach der öffentlichen Beschreibung der Vorlagen). `PERCENTILE_CONT/DISC` als Aggregat und `UPPER`/`LOWER` liefen schon wie PostgreSQL. `KsqlStatistikTests` (28), `KsqlZeitvorlageTests` (23); siehe . ✅
K33.8 Datenänderung und DDL nach Norm `MERGE` nach Norm, `UPDATE … SET (a, b) = (…)`, Änderungstabellen (`SELECT … FROM NEW/OLD/FINAL TABLE (…)`), `GENERATED ALWAYS/BY DEFAULT AS IDENTITY`, `GENERATED ALWAYS AS (ausdruck)`, `CREATE DOMAIN`, `CREATE ASSERTION`, `CHECK`/`UNIQUE [NULLS NOT DISTINCT]`/Fremdschlüssel mit `MATCH SIMPLE/FULL/PARTIAL` und `RESTRICT`, `DEFERRABLE INITIALLY DEFERRED` samt `SET CONSTRAINTS`, `CREATE SCHEMA` mit eingeschlossenen Elementen, `GLOBAL/LOCAL TEMPORARY` mit `ON COMMIT`, Anwendungszeit (`PERIOD FOR`, `WITHOUT OVERLAPS`, `UPDATE/DELETE … FOR PORTION OF`), Systemzeit nach Norm, Sequenzen nach Norm, `CREATE TYPE` (Distinct- und strukturierte Typen), `DROP … CASCADE/RESTRICT`. **Teil 1 erledigt 16.10.2026** (F031 ganz, F032): `ALTER TABLE … ADD COLUMN`; `DROP TABLE|VIEW … RESTRICT` verweigert bei abhängiger Sicht (3729) oder Fremdschlüssel (3726), beide SQLSTATE 2BP01; `CASCADE` löscht abhängige Sichten (auch über mehrere Stufen) und die Fremdschlüssel, die Tabelle mit dem Fremdschlüssel bleibt samt Zeilen (an PostgreSQL 17 gemessen); `REVOKE … RESTRICT`. Am T-SQL-Zugang bleiben die Wörter ein Syntaxfehler (am Orakel 156). `KsqlLoeschverhaltenTests` (7). **Teil 2 erledigt 16.10.2026** (T174, T175, T178, F202, F384–F386): `GENERATED ALWAYS|BY DEFAULT AS IDENTITY [(START WITH … INCREMENT BY …)]`, ohne Spaltenliste zählt die Spalte mit; ein eigener Wert in ALWAYS ist 544 (428C9), ausser mit `OVERRIDING SYSTEM VALUE`, und rückt den Zähler nicht vor; `OVERRIDING USER VALUE`; `UPDATE` einer Identitätsspalte ist 8102 (am Orakel, nun auch am T-SQL-Zugang); `GENERATED ALWAYS AS (ausdruck)` nimmt nur `DEFAULT`; `ALTER COLUMN … RESTART [WITH n] | SET GENERATED … | SET INCREMENT BY | SET START WITH | DROP IDENTITY | DROP EXPRESSION [IF EXISTS]`; `TRUNCATE` setzt den Zähler nach Norm nur mit `RESTART IDENTITY` zurück (an PostgreSQL 17 gemessen). `KsqlIdentitaetTests` (9). **Teil 3 erledigt 16.10.2026** (F292, F492, F741): `UNIQUE NULLS NOT DISTINCT` (Spalte, Tabelle, `ADD CONSTRAINT`; ohne Angabe bleiben mehrere NULL erlaubt), `CHECK`/`REFERENCES … [NOT] ENFORCED` und `ALTER CONSTRAINT c [NOT] ENFORCED` (abgeschaltet wie NOCHECK), `MATCH FULL|SIMPLE` (gemischte NULL sind bei FULL 547); `MATCH PARTIAL` wie bei PostgreSQL abgewiesen (1235, 0A000); `INFORMATION_SCHEMA` meldet `NULLS_DISTINCT`, `ENFORCED` und `MATCH_OPTION` (FULL/NONE) nach dem Stand. Am T-SQL-Zugang ein Syntaxfehler (102, am Orakel; die Spaltenschleife verschluckte die Wörter vorher still). `KsqlEinschraenkungsartenTests` (6). **Teil 4 erledigt 16.10.2026** (F721): Fremdschlüssel `[NOT] DEFERRABLE [INITIALLY DEFERRED|IMMEDIATE]`; in einer Transaktion prüft ein aufgeschobener erst beim äussersten COMMIT (Kind- und Elternseite mit NO ACTION), ein Verstoss ist 547 und rollt zurück; `SET CONSTRAINTS {ALL|name} {DEFERRED|IMMEDIATE}` (IMMEDIATE prüft das Ausstehende; nicht aufschiebbar 7997, unbekannt 4917); `ALTER CONSTRAINT … DEFERRABLE …`; `INFORMATION_SCHEMA.TABLE_CONSTRAINTS` meldet IS_DEFERRABLE/INITIALLY_DEFERRED; `CHECK … DEFERRABLE` und `NOT DEFERRABLE INITIALLY DEFERRED` sind Fehler (an PostgreSQL 17 gemessen). `KsqlAufschiebbarTests` (4). **Teil 5 erledigt 16.10.2026** (F251, F711, E081-09): `CREATE DOMAIN d [AS] typ [DEFAULT e] [CONSTRAINT n] CHECK (… VALUE …) | NOT NULL`; die Domäne prüft jeden geschriebenen Wert (INSERT, UPDATE, MERGE) und `CAST(x AS d)` - NOT NULL 515, Bedingung 547; ihre Vorgabe gilt ohne eigene der Spalte; `ALTER DOMAIN … SET|DROP DEFAULT | SET|DROP NOT NULL | ADD [CONSTRAINT] CHECK … [NOT VALID] | DROP CONSTRAINT [IF EXISTS] | RENAME CONSTRAINT` wirkt auf die vorhandenen Spalten (SET NOT NULL und ADD CHECK prüfen die Zeilen); `DROP DOMAIN [IF EXISTS] … [CASCADE]`; `GRANT … ON DOMAIN d`. Dabei behoben: ein Typ aus `CREATE TYPE … FROM` liess sich im selben Stapel nicht als Spaltentyp nutzen (2715), und ein Recht an einem Typ (`ON TYPE::t`) stand als OBJECT_OR_COLUMN mit 0 statt als Klasse 6 TYPE in `sys.database_permissions` (am Orakel gemessen). Am T-SQL-Zugang ist `DOMAIN` 343 wie am Orakel. `KsqlDomaenenTests` (6). **Teil 6 erledigt 16.10.2026** (T171, T172, T173, F531): `CREATE TABLE q (LIKE p [INCLUDING|EXCLUDING DEFAULTS|IDENTITY|GENERATED|CONSTRAINTS|INDEXES|ALL] …, weitere Spalten)` (ohne Angabe Spalten, Typ und NOT NULL); `CREATE TABLE t [(x, …)] AS abfrage [WITH [NO] DATA]`; `CREATE [GLOBAL|LOCAL] TEMPORARY TABLE … [ON COMMIT PRESERVE ROWS|DELETE ROWS|DROP]` (DELETE ROWS leert bei jedem Festschreiben, ohne Transaktion nach jeder Anweisung); `CREATE SCHEMA s CREATE TABLE … CREATE VIEW … GRANT …` legt die Elemente im neuen Schema an - auch am T-SQL-Zugang (am Orakel gemessen, vorher landeten sie in dbo). Dabei behoben: ein temporärer Name verdeckte eine dauerhafte Tabelle auch, nachdem die temporäre fehlte (nun nur, solange es sie gibt; so auch PostgreSQL). `KsqlTabellenanlageTests` (5). **Teil 7 erledigt 20.10.2026** (F521; nach Normtext, Abgleich als K33.8b offen): `CREATE ASSERTION n CHECK (…) [[NOT] DEFERRABLE] [INITIALLY DEFERRED|IMMEDIATE]` prüft beim Anlegen und nach jeder äussersten Datenänderung einer genannten Tabelle (INSERT, UPDATE, DELETE, MERGE); falsch ist 547 (23000) und nimmt die ganze Anweisung zurück, UNKNOWN besteht; aufgeschoben prüft sie in einer Transaktion beim COMMIT bzw. bei `SET CONSTRAINTS n IMMEDIATE`; `DROP ASSERTION [IF EXISTS] n`; `DROP TABLE` einer genannten Tabelle ist 3729 (2BP01), mit `CASCADE` fällt die Assertion mit. Am T-SQL-Zugang 343 wie DOMAIN. `KsqlZusicherungenTests` (5). **Teil 8 erledigt 20.10.2026** (T495, F313, T641; nach Normtext, Abgleich als K33.8b offen): `SELECT … FROM NEW|OLD|FINAL TABLE (INSERT|UPDATE|DELETE|MERGE …) [AS] t [(spalten)]` führt die Änderung einmal ganz oder gar nicht aus und liest NEW/FINAL die geschriebenen, OLD die ersetzten Zeilen (bei MERGE nach Aktion getrennt); OLD zu INSERT und NEW zu DELETE sind 102. MERGE: `UPDATE SET (a, b) = (…)`, `SET a = DEFAULT`, `INSERT … VALUES (…, DEFAULT)`, `INSERT … OVERRIDING SYSTEM|USER VALUE`; eine mehrfach getroffene Zielzeile (8672) trägt SQLSTATE 21000. `UPDATE … SET (a) = ROW (x)` (Grad 1). DELETE in MATCHED und mehrere Bedingungen gab es schon. `KsqlAenderungstabellenTests` (4). **Teil 9 erledigt 20.10.2026** (T180, T181, T502; nach Normtext, Abgleich als K33.8b offen): `PERIOD FOR p (a, b)` (DATE/TIMESTAMP, beide NOT NULL, `a < b` als Prüfung, 547), `PRIMARY KEY|UNIQUE (…, p WITHOUT OVERLAPS)` (am Ende jeder Änderung geprüft, 2627), `UPDATE|DELETE t FOR PORTION OF p FROM x TO y …` teilt die Zeilen (die Reste vor x und nach y bleiben mit den alten Werten; SET auf eine Zeitraumspalte ist 8102), die Prädikate `OVERLAPS`, `EQUALS`, `CONTAINS` (Zeitraum oder Zeitpunkt), `PRECEDES`, `SUCCEEDS`, `IMMEDIATELY PRECEDES|SUCCEEDS` über einen Zeitraum beim Namen oder `PERIOD (x, y)`. Systemzeit auf den temporalen Tabellen von T-SQL: `WITH SYSTEM VERSIONING`, `ALTER TABLE … ADD|DROP SYSTEM VERSIONING` (DROP nimmt den Verlauf mit), `FOR SYSTEM_TIME BETWEEN SYMMETRIC|ASYMMETRIC`, kein Primärschlüssel nötig. Dabei behoben (auch am T-SQL-Zugang): das offene Ende einer Spalte `datetime2(0…6)` lief beim Runden über, INSERT scheiterte (jetzt 9999-12-31 23:59:59…). `KsqlZeitraeumeTests` (18). **Teil 10 erledigt 20.10.2026** (S011, S011-01; nach Normtext, Abgleich als K33.8b offen): `CREATE TYPE geld AS DECIMAL(10,2) [FINAL]` ist ein Distinct-Typ, streng getrennt von seinem Quelltyp: Vergleiche (auch BETWEEN, IN, in Unterabfragen) nur mit demselben Typ oder NULL, keine Rechnung, keine Zuweisung eines anderen Distinct-Typs - sonst 206 (42000); `CAST` führt hinein und zurück, eine Zuweisung aus dem Quelltyp nimmt er an; NOT FINAL ist 102. `CREATE TYPE punkt [UNDER obertyp] AS (attribut typ, …) [[NOT] INSTANTIABLE] [[NOT] FINAL]` legt strukturierte Typen an (Attribute erben, Obertyp muss NOT FINAL sein, doppeltes Attribut 2705, `DROP TYPE` eines Obertyps 3732); als Spaltentyp oder in `CAST` ist ein strukturierter Typ 1235, bis es Zeilenwerte gibt (K33.8c). Aliastypen (`FROM`) und Domänen bleiben nachsichtig. `KsqlBenutzertypenTests` (4). **Abschluss 20.10.2026: alle Teile nach Normtext, der Abgleich am Orakel ist K33.8b, die Reste K33.8c.** ✅
K33.8a Rest aus K33.8 Teil 4: aufschiebbares `UNIQUE`/`PRIMARY KEY` `UNIQUE … DEFERRABLE INITIALLY DEFERRED` (an PostgreSQL gemessen: `UPDATE u SET a = 3 - a` über 1, 2 geht, ein Duplikat ist beim COMMIT 23505); heute mit 1235 (0A000) abgewiesen statt still verschluckt. **Erledigt (20.10.2026), abgeglichen in K33.8b:** `UNIQUE`/`PRIMARY KEY … [NOT] DEFERRABLE [INITIALLY …]` auf Spalten-, Tabellenebene und in `ADD CONSTRAINT`; nicht aufgeschoben je Anweisung (Norm; UPDATE prüft UNIQUE jetzt vorab wie den Primärschlüssel, auch am T-SQL-Zugang wie SQL Server), aufgeschoben beim COMMIT über die ganze Tabelle (2627, rollt zurück); `SET CONSTRAINTS` und `TABLE_CONSTRAINTS` für die Schlüssel. Ohne neue Messung (Docker aus), Grundlage die Messung aus K33.8 Teil 4 und das Handbuch von PostgreSQL. `KsqlAufschiebbarSchluesselTests` (21). ✅
K33.8b Abgleich am Orakel für K33.8 Teile 7–10 Gemessen am 20.10.2026 (SQL Server 2025, PostgreSQL 17): Ablehnung von ASSERTION (343), `FROM NEW TABLE` am T-SQL-Zugang jetzt 156, MERGE mit DEFAULT, Zeilenzuweisung, OVERRIDING und Kardinalität 21000, `PERIOD FOR` 102, offenes Ende `datetime2(0)`, `CREATE TYPE … AS` 102 - alles wie hier. Offen bleibt nur, was allein der Normtext festlegt (Nummern und Regeln für Assertions, Änderungstabellen, Anwendungszeit, Distinct-Typen); Liste in . **Abgeschlossen 20.10.2026: der Rest ist nach Normtext, kein Orakel** (keine Referenz kennt Assertions, Änderungstabellen, Anwendungszeit oder Distinct-Typen nach Norm). ✅
K33.8c Reste aus K33.8 Teile 7–10 **Teil A erledigt 20.10.2026:** `TRUNCATE` prüft die Assertions (ganz oder gar nicht, auch ausserhalb einer Transaktion), `INFORMATION_SCHEMA.ASSERTIONS` und `PERIODS` (Anwendungs- und Systemzeit) nach ISO/IEC 9075-11, `USER_DEFINED_TYPES` (DISTINCT/STRUCTURED, IS_FINAL, Quelltyp) und `ATTRIBUTES` (geerbte zuerst) aus dem Katalog, `ALTER TABLE … ADD PERIOD FOR p (a, b)` und `DROP PERIOD FOR p` (Prüfung `t_p_check`, 3729 bei WITHOUT OVERLAPS); dabei behoben: `ALTER COLUMN … SET NOT NULL` am KSQL-Zugang prüfte vorhandene NULL nicht (jetzt 515, PostgreSQL 23502). **Teil B erledigt 20.10.2026:** F053 `(S1, T1) OVERLAPS (S2, T2)` (an PostgreSQL 17 gemessen), `FOREIGN KEY (k, PERIOD p) REFERENCES t (k, PERIOD q)` (lückenlose Deckung, 547), `FINAL TABLE` gegen einen Trigger (23321, SQLSTATE 27000); dabei behoben: eine Änderung mit Trigger liess sich vom Rahmen ihrer Anweisung (Assertion, FINAL TABLE) nicht mehr zurücknehmen. **Teil C erledigt 20.10.2026:** die strenge Prüfung der Distinct-Typen auch in MERGE, `UPDATE|DELETE … FROM`, `WITH` und in Funktionsargumenten (`SUM(geld)` 206; COUNT, MIN, MAX, COALESCE, NULLIF gehen). **Teil D erledigt 20.10.2026** (S023, S025): Werte strukturierter Typen über die Zeilentypen aus K33.5a - Spalten, `NEW typ (…)`, `NEW typ ()`, `(wert).attribut`, `CAST(… AS typ)`, streng getrennt (206). **Abgeschlossen 20.10.2026; was davon offen bleibt, steht in K33.8e.** ✅
K33.8e Rest aus K33.8c: strukturierte Typen über die Grundform hinaus **Erledigt 20.10.2026** (nach Normtext, kein Orakel - keine Referenz kennt es; S026, S041, S051, S081, S111, S151, S161, S251 auf „+“): Attributzugriff ohne Klammern (`p.x`, `t.p.x`), Mutatoren (`SET p.x = …`), Methoden (`METHOD …` in CREATE TYPE, `CREATE METHOD … FOR typ` mit SELF, Aufruf `p.m(…)`, geerbt und überschrieben), `CREATE|DROP ORDERING` (EQUALS ONLY, FULL BY STATE|MAP|RELATIVE), `IS [NOT] OF`, `TREAT`, getypte Tabellen (`CREATE TABLE t OF typ`, `REF IS … SYSTEM|USER GENERATED`, `WITH OPTIONS`), Untertabellen (`UNDER`, `ONLY (t)` in FROM/UPDATE/DELETE), Referenzen (`REF(typ) SCOPE t`, `r->a`, `DEREF`, selbstbezügliche Typen mit `REF USING`). **Bewusst nicht gebaut, weil nicht sinnvoll:** die *Ersetzbarkeit* (ein Wert eines Untertyps in einer Spalte des Obertyps samt dynamischer Bindung der Methoden) - sie verlangt, dass jeder Wert seinen speziellsten Typ mitträgt; die Werte sind aber die Zeilentypen aus K33.5a mit fester Feldliste, und eine zweite, selbstbeschreibende Wertform für Speicher, Vergleich, Ausgabe und die Treiber wöge den Nutzen nicht auf (kein anderes System am Prüfstand kennt sie; unter den verbreiteten Systemen nur Oracle und Db2 mit eigener Objektschicht); ohne sie ist der speziellste Typ der statische, IS OF und TREAT sind darauf genau. Ebenso nicht: `REF … DERIVED`/`REF FROM` und REF in weiteren Zusammenhängen (S043, S162), `SPECIFIC METHOD` (S027, S261), Konstruktor- und statische Methodenaufrufe (`typ::m()`), Locators (S231) - selten genutzte Teile ohne Gegenstück in den Referenzen. Die Vereinigung über Untertabellen gilt für die Hauptquelle von FROM, nicht in Verbunden. ✅
K33.8d Rest aus K33.8a (unter dem Ticket K33.8b committet, die Kennung war parallel vergeben): Abgleich an PostgreSQL 17 und am Orakel An `kq-ref-postgres` (127.0.0.1:15433, eigenes Schema): `UPDATE u SET a = 3 - a` über 1 und 2 mit `UNIQUE`, `UNIQUE DEFERRABLE INITIALLY IMMEDIATE` und `… INITIALLY DEFERRED` (PostgreSQL prüft das nicht aufschiebbare je Zeile, KSQL nach Norm je Anweisung - Abweichung bestätigen), Duplikat beim COMMIT (23505, Transaktion zurückgerollt), dasselbe für `PRIMARY KEY` auf Spalten-/Tabellenebene und über `ALTER TABLE … ADD CONSTRAINT`, `SET CONSTRAINTS k DEFERRED/IMMEDIATE`, `SET CONSTRAINTS ALL …` neben einem nicht aufschiebbaren Schlüssel (Fehler 55000), `ROLLBACK TO SAVEPOINT`, `information_schema.table_constraints.is_deferrable/initially_deferred`, `UNIQUE NOT DEFERRABLE INITIALLY DEFERRED` und `NOT NULL DEFERRABLE` (Syntaxfehler). Am Orakel SQL Server 2025: `UPDATE u SET a = 3 - a` über ein `UNIQUE` und einen eindeutigen Index (je Anweisung erwartet, so jetzt am T-SQL-Zugang), `DEFERRABLE` hinter `UNIQUE`/`PRIMARY KEY` (102). **Erledigt (20.10.2026):** an PostgreSQL 17 alle Fälle wie KSQL, einzige Abweichung mit Absicht (PostgreSQL prüft ein nicht aufschiebbares UNIQUE je Zeile, KSQL nach Norm je Anweisung); am Orakel 2025 `3 - a` über UNIQUE und eindeutigen Index wie der T-SQL-Zugang, 2627/2601, `DEFERRABLE` 102. ✅
K33.9 Transaktionen und Sitzung nach Norm **Erledigt (16.10.2026).** Am KSQL-Zugang (Erwartungen an PostgreSQL 17): `START TRANSACTION [ISOLATION LEVEL …][, READ ONLY|READ WRITE]`, `COMMIT|ROLLBACK [WORK] [AND [NO] CHAIN]` (ohne Transaktion ein stilles OK, `AND CHAIN` dann ein Fehler), `SAVEPOINT`, `ROLLBACK [WORK] TO [SAVEPOINT]`, `RELEASE SAVEPOINT` (danach gibt es den Punkt nicht mehr), `SET TRANSACTION READ ONLY|WRITE` (laufende oder nächste Transaktion; die Isolation gilt wie in T-SQL für die Sitzung); in einer Transaktion READ ONLY ist jede Änderung 3906. `GRANT rolle TO x [WITH ADMIN OPTION]` und `REVOKE [ADMIN OPTION FOR] rolle FROM x` sind die Mitgliedschaft bzw. das Recht `ALTER` auf die Rolle (vorher legte der Kern still ein Recht namens „rolle“ an; am T-SQL-Zugang jetzt 102 wie SQL Server 2025); ein Recht `ON ROLE::r` steht in `sys.database_permissions` als `DATABASE_PRINCIPAL` (vorher Klasse 1 mit 0, KS1). `SET ROLE r|NONE` setzt `CURRENT_ROLE`. `CURRENT_USER`/`SESSION_USER`/`SYSTEM_USER`/`CURRENT_SCHEMA`/`CURRENT_CATALOG`, `SET CATALOG`, `SET TIME ZONE`, `SET SESSION AUTHORIZATION` liefen schon. `KsqlTransaktionTests` (21); T241, T261, T271, T272, T332, E152 auf „+“ (315). Rest als K33.9a. ✅
K33.9a Rest aus K33.9: `SET SCHEMA` (Vorgabeschema der Sitzung) `SET SCHEMA 's'` setzt das Vorgabeschema der Sitzung für unqualifizierte Namen (F761; heute ohne Wirkung, ein unbekanntes Schema wird still angenommen). Versuch 16.10.2026 zurückgenommen: der Kern normalisiert Namen mehrfach (`NormalizeTableName` aus `dbo.p` → `p`, beim zweiten Mal wäre es `s.p`), und `ParseTableName` liest auch Logins, Datenbanken, Schemas und Rollen - ein Vorgabeschema braucht eine Namensauflösung, die es kennt (unqualifiziert → Vorgabeschema, dann dbo; ausgenommen CTEs, `#`/`@`, `inserted`/`deleted`). Dieselbe Auflösung trägt das Vorgabeschema des Benutzers (`ALTER USER … WITH DEFAULT_SCHEMA`, KS1). Tests dafür lagen bereit (Anlegen, Lesen, `CURRENT_SCHEMA`, 2760, Trigger/CTE/Tabellenvariable). **Entschieden (16.10.2026, Auftraggeber):** KSQL-Sitzungen bleiben im Autocommit wie T-SQL, E151-02 (implizite Transaktionen nach der Norm) bleibt darum begründet „-“; ein Skript mit ausdrücklich begonnener Transaktion ohne COMMIT/ROLLBACK wird beim Schliessen der Verbindung zurückgerollt - an beiden Zugängen über die Leitung belegt (`TrennenRolltZurueckTests`, 6). **Erledigt 16.10.2026 (Entscheid des Auftraggebers: Vorgabeschema zuerst, dann dbo):** `SET SCHEMA 's'` (auch ohne Anführungszeichen) setzt das Vorgabeschema der Sitzung, ein unbekanntes ist 2760, `dbo` stellt zurück; `CURRENT_SCHEMA`/`SCHEMA_NAME()` nennen es. Der Parser kennzeichnet in einer Sitzung mit Vorgabeschema (auch nach `SET SCHEMA` weiter vorn im selben Stapel) unqualifizierte Namen an den Objektstellen (FROM, JOIN, INSERT/UPDATE/DELETE/MERGE, CREATE/ALTER/DROP/TRUNCATE TABLE, VIEW, INDEX ON, TRIGGER ON, REFERENCES, Sequenzen, `NEXT VALUE FOR`, Prozeduren, `EXEC`, Funktionen; nicht CTEs, `#`/`@`, `inserted`/`deleted`); erst die Normalisierung beim Ausführen löst das Kennzeichen auf - zuerst `s.name`, dann `dbo.name`, sonst `s.name` (dort legt CREATE an) -, so bleibt ein ausdrückliches `dbo.` auch nach mehrfacher Normalisierung dbo. Ohne `SET SCHEMA` liest jede Sitzung wie bisher. Abweichung von der strengen Norm und PostgreSQL 17 (gemessen: kein Rückfall auf `public`): der Rückfall auf dbo wie bei SQL Server. Dabei behoben: `sys.sequences` nannte jede Sequenz in dbo mit vollem Namen. F761 auf „+“ (316). `KsqlVorgabeschemaTests` (7). Rest als K33.9b. ✅
K33.9b Rest aus K33.9a: Vorgabeschema des Benutzers `CREATE USER … WITH DEFAULT_SCHEMA = s` und `ALTER USER … WITH DEFAULT_SCHEMA` (heute beim Anlegen gelesen, beim Ändern übergangen) wirken wie bei SQL Server über dieselbe Auflösung wie K33.9a: bei der Anmeldung, nach `USE` und unter `EXECUTE AS` gilt das Vorgabeschema des Benutzers der Datenbank, an allen Zugängen; `sys.database_principals.default_schema_name` zeigt es (am Orakel messen, KS1). **Erledigt 16.10.2026:** `ALTER USER … WITH DEFAULT_SCHEMA` übernimmt den Wert (ohne Prüfung, wie am Orakel); das wirksame Vorgabeschema ist `SET SCHEMA`, sonst das des Benutzers der Datenbank (auch unter `EXECUTE AS`, auch im selben Stapel), wenn es das Schema gibt; ein neues Objekt entsteht immer im Vorgabeschema, auch wenn der Name in dbo schon steht (am Orakel: `CREATE TABLE q` neben `dbo.q` legt `s.q` an) - das gilt nun auch für `SET SCHEMA`. Dabei behoben: ein Recht auf ein Schema (`GRANT SELECT ON SCHEMA::s`) kam bei keinem Objekt darin an; jetzt gilt es, und ein DENY sticht, ob am Objekt oder am Schema (am Orakel gemessen). `BenutzerVorgabeschemaTests` (3), `SchemarechteTests` (5). ✅
K33.10 SQL/PSM (Teil 4) Routinen nach Norm: `CREATE PROCEDURE/FUNCTION … LANGUAGE SQL`, `BEGIN [ATOMIC] … END`, `DECLARE` von Variablen, Bedingungen und Handlern (`CONTINUE/EXIT/UNDO`), `SIGNAL`/`RESIGNAL`, `GET DIAGNOSTICS`, `IF`/`CASE`/`LOOP`/`WHILE`/`REPEAT`/`FOR`/`LEAVE`/`ITERATE`, `CALL`, Trigger nach Norm (`REFERENCING OLD/NEW ROW/TABLE AS`, `FOR EACH ROW/STATEMENT`, `WHEN`) - auf die vorhandenen Ablaufbausteine von MariaDB und Db2. **Erledigt 20.10.2026 (nach Normtext, Abgleich als K33.10a offen):** KSQL liest Routinen mit dem Leser der MariaDB-Routinen (ein Weg), die Regeln der Norm schaltet `Dialekt.NormRoutinen` (`Parser/PrattParser.Psm.cs`, `Ksql/KsqlRoutinen.cs`): Rumpf = eine Anweisung, danach geht der Stapel weiter; ein Fehler ohne Handler beendet die Prozedur; Handler und `GET DIAGNOSTICS` nach dem SQLSTATE von `Normzustand` (K33.11), `SIGNAL` meldet seinen Zustand am KSQL-Zugang; `DECLARE … CONDITION`, `UNDO` in `BEGIN ATOMIC` (Sicherungspunkt), `CASE`-Anweisung (20000), `FOR … AS … DO`, `SET (a, b) = …`, `marke.x`, `f.x`, Merkmale der Norm samt `RETURNS NULL ON NULL INPUT`; Trigger mit `REFERENCING`, `FOR EACH ROW|STATEMENT`, `WHEN`, `UPDATE OF` auf den Zeilentriggern des Kerns. Schleifen bricht der Client per ATTENTION ab (Test). Kernfehler behoben: `RETURN` mit scheiterndem Ausdruck übersprang das `CATCH` (am Orakel gemessen). P001–P008 mit Namen (Mimer, postgres.cz), neu „+“: P002–P008, B128, E081, T200, T211, T212, T214–T216, T218, T321, T325, T651. Am T-SQL-Zugang unverändert. `KsqlPsmTests` (62), `KsqlPsmLeitungTests` (3). Funktionsreste in K33.10b. ✅
K33.10a Abgleich am Orakel (Rest aus K33.10) Entscheid des Auftraggebers 20.10.2026: Docker blieb aus, K33.10 lief nach dem Normtext; die Fälle von aussen nachmessen. **Erledigt 20.10.2026:** PostgreSQL 17 (SQL-Rumpf, `BEGIN ATOMIC`, `RETURNS NULL ON NULL INPUT`, Übergangstabellen, `WHEN`, `UPDATE OF`, `PARAMETERS`) und MariaDB 11 (`ROW_COUNT`, 23000, `CONTINUE`-Handler, `SIGNAL` im BEFORE-Trigger) wie KSQL; nach Norm abweichend und belassen: Reihenfolge der Trigger (PostgreSQL nach Namen), `CONSTRAINT_NAME` (MariaDB leer). SQL Server 2025: zwei Abweichungen am T-SQL-Zugang behoben - `(IN x …)` ist 156 beim Schlüsselwort (vorher 102), `CALL p()` bzw. ein Aufruf als Argument von `EXEC` ist 102 (vorher 195). ✅
K33.10b Rest aus K33.10: was SQL/PSM noch fehlt `INSTEAD OF`-Trigger nach Norm (T213), Übergangstabellen im Zeilentrigger, Tabellenfunktionen `RETURNS TABLE … RETURN TABLE (…)` (T326), `%TYPE` (T322), Überladen (T341), `EXECUTE IMMEDIATE` in Routinen (T652), Module `CREATE MODULE` (P001); Namensauflösung nach Norm, Handler fangen 208/207 derselben Ebene, `COMMIT`/`ROLLBACK` in `BEGIN ATOMIC` abweisen, `UNDO` im Trigger als echter Sicherungspunkt, gleichnamige Variablen in inneren Blöcken. **Erledigt 20.10.2026:** alles davon (eine Spalte geht der gleichnamigen Variablen vor, Bereich ist die Anweisung; Überladungen heissen im Katalog `name__ovN`). Befund: `INFORMATION_SCHEMA.MODULES` fehlte, die P003-Probe lief nur, weil eine unbekannte Normsicht leer antwortet; `MODULES` ist jetzt da, P003 wieder „-“ (K33.10c). Neu „+“: P001, T213, T322, T326, T341, T652. `KsqlPsmRestTests` (24). ✅
K33.10c Rest aus K33.10b: übrige Sichten zu Modulen (P003) `INFORMATION_SCHEMA.MODULE_TABLE_USAGE`, `MODULE_COLUMN_USAGE`, `MODULE_PRIVILEGES` aus den Verweisen der Routinen eines Moduls; dazu `ROUTINES.MODULE_*`. **Erledigt 20.10.2026:** die Zugehörigkeit steht als erweiterte Eigenschaft `KSQL_MODUL` an jeder Routine des Moduls; `ROUTINES.MODULE_*` liest sie, die drei Sichten berechnet `Ksql/Normsichten.Module.cs` aus dem Katalog (Verweise wie bei Sichten und Funktionen, dazu die Ziele von Änderungen; `EXECUTE` des Besitzers). P003 „+“. Der rote Test zur letzten Stelle der Winkelfunktionen ist auf `main` genauso rot (Plattform, nicht K33.10). ✅
K33.10d Nachtrag zu K33.10: endlose PSM-Schleifen und der Fuzzer `KsqlSyntaxFuzzingTests` hing an einer verfälschten Routine, deren `CONTINUE`-Handler den Fehler im Schleifenrumpf schluckt (legitime Endlosschleife). Prüfen, dass ATTENTION, `CommandTimeout` und das Schliessen der Verbindung eine laufende PSM-Schleife beenden; der Fuzzer führt jeden Fall mit Frist aus und zählt eine abbrechbare Schleife nicht als Befund, ein Hängen trotz Abbruch schon. **Erledigt 20.10.2026:** alle drei Wege über TDS belegt (Funktion und Prozedur mit schluckendem Handler); der Fuzzer bricht nach 5 s ab wie ein Attention (`ExecutionEngine.AbbruchToken` öffentlich) und unterscheidet abgebrochen/hängt (`MitFrist`, eigener Test). ✅
K33.11 Fehler nach Norm Jede Meldung am KSQL-Port trägt den SQLSTATE nach Norm (Klassen 01, 02, 21, 22, 23, 25, 40, 42 …); `GET DIAGNOSTICS … RETURNED_SQLSTATE`, `MESSAGE_TEXT`, `CONSTRAINT_NAME` u. a.; Übersetzung aus den gemeinsamen Fehlern an einer Stelle. **Erledigt 15.10.2026:** Zuordnung an einer Stelle (`Execution/Normzustand.cs`, sonst `HY000`); am KSQL-Zugang trägt jede Fehlermeldung den SQLSTATE am Ende (`… (SQLSTATE 22012)`), weil das ERROR-Token von TDS kein Feld dafür hat. `GET DIAGNOSTICS` liest dieselbe Tabelle und kommt mit K33.10. ✅
K33.12 Information Schema (Teil 11) vollständig Alle Sichten des Information Schema nach Norm, mit den Spalten der Norm: `TABLES`, `COLUMNS`, `VIEWS`, `DOMAINS`, `DOMAIN_CONSTRAINTS`, `CHECK_CONSTRAINTS`, `TABLE_CONSTRAINTS`, `KEY_COLUMN_USAGE`, `REFERENTIAL_CONSTRAINTS`, `ROUTINES`, `PARAMETERS`, `TRIGGERS`, `TRIGGERED_UPDATE_COLUMNS`, `SEQUENCES`, `ELEMENT_TYPES`, `ATTRIBUTES`, `USER_DEFINED_TYPES`, `APPLICABLE_ROLES`, `ENABLED_ROLES`, `*_PRIVILEGES`, `SQL_FEATURES`, `SQL_IMPLEMENTATION_INFO`, `SQL_SIZING` u. a. **Erledigt 15.10.2026:** alle 64 Sichten mit den Spalten der Norm in ihrer Reihenfolge (an PostgreSQL 17 gemessen, `tools/ksql/is-spalten.tsv`); Werte aus den Sichten des Kerns samt berechneter Normspalten, neu aus dem Katalog `TRIGGERS`, `USER_DEFINED_TYPES`, `ENABLED_ROLES`, `APPLICABLE_ROLES`, `COLLATIONS`, `CHARACTER_SETS` u. a. (erzeugt von `tools/ksql/normsichten-erzeugen.py`). Sichten ohne Gegenstück im Kern (Fremddaten, Element- und Attributtypen, Rechte je Rolle) haben die Spalten und füllen sich mit den Fähigkeiten von K33.5–K33.10. ✅
K33.13 SQL/XML, SQL/JSON, SQL/PGQ nach Norm Teil 14: `XMLELEMENT`, `XMLATTRIBUTES`, `XMLFOREST`, `XMLCONCAT`, `XMLAGG`, `XMLPARSE`, `XMLSERIALIZE`, `XMLQUERY`, `XMLEXISTS`, `XMLTABLE`, Typ `XML` nach Norm. SQL/JSON: `JSON_TABLE`, `JSON_EXISTS`/`JSON_VALUE`/`JSON_QUERY` mit `ON EMPTY`/`ON ERROR`, `JSON_SCALAR`, `JSON_SERIALIZE`, `IS JSON`, vereinfachte Pfade (SQL:2023). Teil 16: `CREATE PROPERTY GRAPH`, `GRAPH_TABLE (… MATCH …)` auf die vorhandenen Graphtabellen (C11.3). Teil 15 (MDA, mehrdimensionale Felder) nur nach Bedarf. **Teil 14 erledigt 19.10.2026:** `XMLELEMENT`/`XMLATTRIBUTES`, `XMLFOREST`, `XMLCONCAT`, `XMLAGG … ORDER BY`, `XMLPARSE`, `XMLSERIALIZE` (INDENT, Deklaration), `XMLQUERY`, `XMLEXISTS`, `XMLTABLE`, `XMLCAST`, `XMLCOMMENT`/`XMLPI`/`XMLTEXT`, `IS DOCUMENT` auf dem `xml`-Typ und Kuonen.Global.Xml (an PostgreSQL 17 gemessen), 40 Merkmale „+“, `KsqlSqlXmlTests`. **SQL/JSON erledigt 20.10.2026:** `JSON_VALUE`/`JSON_QUERY`/`JSON_EXISTS` mit `PASSING`, `RETURNING`, Hülle, `OMIT QUOTES`, `ON EMPTY`/`ON ERROR`, `JSON_TABLE` mit `NESTED` (Plan OUTER/UNION), `JSON_SCALAR`, `JSON_SERIALIZE`, `JSON(…)`, `IS JSON … WITH UNIQUE KEYS`, `FORMAT JSON`/`WITH UNIQUE KEYS`/`RETURNING` an den Konstruktoren, vereinfachter Zugriff `t.j.a.b` (T860/T861) auf der Pfadsprache von PR27.17s, 37 Merkmale „+“, `KsqlSqlJsonTests`. **Teil 16 erledigt 20.10.2026 (nach Normtext, Abgleich als K33.13a offen):** `CREATE PROPERTY GRAPH` (Knoten- und Kantentabellen, KEY, LABEL, PROPERTIES samt Ausdrücken und EXCEPT, auch über den Graphtabellen von C11.3 mit `$node_id`/`$from_id`/`$to_id`), `DROP PROPERTY GRAPH`, `GRAPH_TABLE (g MATCH … WHERE … COLUMNS (…))` mit Richtungen, Beschriftungsausdrücken und Quantoren an Kanten (Deckel 16 Schritte, 256 Zweige), 22 Merkmale „+“, `KsqlSqlPgqTests`. Teil 15 (MDA) nicht gebaut: braucht den Feldtyp aus K33.5a, siehe K33.13b. Ungemessene Annahmen: . ✅
K33.13a Abgleich am Orakel für K33.13 Entscheid des Auftraggebers 20.10.2026 (Docker aus): nachmessen, was K33.13 nach dem Normtext gebaut hat - an PostgreSQL 17 (`kq-ref-postgres`): Textform von `time_tz()`/`timestamp_tz()` in `JSON_VALUE`, `JSON_SERIALIZE` einer `json`-Spalte, `RETURNING` an `JSON_OBJECT`/`JSON_ARRAYAGG`, `XMLSERIALIZE … INCLUDING XMLDECLARATION`, `XMLEXISTS` über `false()`; an SQL Server 2025 (Orakel 14335): dass `CREATE PROPERTY GRAPH`, `GRAPH_TABLE`, `XMLTABLE`, `JSON_TABLE`, `IS JSON`, `JSON_VALUE … ON EMPTY` am T-SQL-Zugang dieselben Fehler wie dort geben, und `MATCH` gegen `GRAPH_TABLE` über denselben Graphtabellen (gleiche Treffer); SQL/PGQ insgesamt gegen ein System mit SQL/PGQ (Oracle 23ai oder PostgreSQL 18, wenn freigegeben): Vorgaben für Schlüssel und Kanten, ungerichtete Kanten, WALK-Zählung bei Quantoren, Fehlerklassen; `XMLQUERY`/`XMLCAST` gegen ein System mit SQL/XML-XQuery. Liste in . **Erledigt 20.10.2026:** an PostgreSQL 17 und SQL Server 2025 gemessen und behoben: `JSON_VALUE` schreibt Zeitwerte als Text ihres SQL-Typs (`2026-10-19 08:11:12+00`), `RETURNING` mit zu kurzer Länge ist 22001 statt still gekürzt (in den Abfragefunktionen an ON ERROR), am T-SQL-Zugang `CREATE|DROP PROPERTY GRAPH` 343 und `DEFAULT` in der Argumentliste 156 wie am Orakel, dazu neu `JSON_QUERY … WITH ARRAY WRAPPER` mit `[*]` (SQL Server 2025); `MATCH` und `GRAPH_TABLE` finden über denselben Graphtabellen dasselbe. SQL/PGQ als Ganzes und `XMLQUERY`/`XMLCAST` haben kein erreichbares Vergleichssystem und bleiben nach Normtext. ✅
K33.13b Reste aus K33.13 **Erledigt 20.10.2026.** SQL/XML: Typen `XML(DOCUMENT|CONTENT(UNTYPED|ANY|XMLSCHEMA ID s))`/`XML(SEQUENCE)` mit Prüfung, `XMLVALIDATE` und `IS VALID` gegen die Schemasammlungen des Kerns als registrierte Schemata, `XMLNAMESPACES` beim Erzeugen, `OPTION … ON NULL`, Binärserialisierung mit `ENCODING`/BOM, Spaltenliste hinter dem Alias, Tabellenabbildung `TABLE_TO_XML`/`QUERY_TO_XML`/`SCHEMA_TO_XML`/`DATABASE_TO_XML` (an PostgreSQL 17 gemessen). SQL/JSON: `PLAN`/`PLAN DEFAULT`, vereinfachter Zugriff an jedem Ausdruck mit `.*`, `.'a'`, `[n]`, `[*]`, `JSON_ARRAY(abfrage)`. SQL/PGQ: `TRAIL`/`SIMPLE`/`ACYCLIC`, `ANY`/`ALL SHORTEST`, `SHORTEST k`, geklammerte Pfade mit Quantor (G035, G037), Aggregate über Gruppenvariablen (G120), `ELEMENT_ID`, `IS SOURCE|DESTINATION OF`, `SAME`/`ALL_DIFFERENT`, `v.*`, Information Schema nach Teil 16, Schutz vor `DROP TABLE … RESTRICT`. 62 Merkmale „+“. **Begründet nicht gebaut** (je Grund in ): Namensraumerklärungen ausserhalb des Erzeugens (X081–X084, X086: Kuonen.Global.Xml bindet keine Präfixe), Prüfung nach dem Dokument selbst und Schemaorte (X141–X157, X260–X286 ohne die gebauten), X047/X057, X049/X059/X131–X135, X160/X161, X211, X100–X114, X121, JSON-Vergleiche (T879–T882: der json-Typ von SQL Server 2025 ist nicht vergleichbar), T802, G940, **Teil 15 (MDA)**: nicht in der Merkmalsliste, ohne Fall, und er verlangte einen zweiten Feldtyp neben dem aus K33.5a. Nach K33.5a/K33.8 Teil 10/K33.10 je eine Probe: X011, X012, X013, X014, X015, X120. ✅
K33.13c Fundstellen des Syntaxfuzzers in K33.13 **Erledigt 20.10.2026.** `XMLTABLE`, `JSON_TABLE`, `GRAPH_TABLE` ohne Argumentliste sind eine unbekannte Tabelle (208 wie am Orakel 2025, PostgreSQL 42P01) statt einer Ausnahme; `SUM()` und die übrigen Aggregate ohne Argument 174; XQuery-Funktionen mit zu wenigen Argumenten (`count()` u. a., XPST0017) 2236 an beiden Zugängen. Feste Fälle in `FuzzingFundeTests`, vollständige Prüfung der 38 Proben 0 Befunde in 152 408 Fällen, Fuzzer je 60 s (20261004, 4711) ohne Absturz. Offen und nicht aus K33.13: Hänger der verfälschten SQL/PSM-Probe von K33.10 (Endlosschleife unter `CONTINUE HANDLER`). ✅
K33.13d Normlogik von K33.13 aus dem KSQL-Modul in den Kern **Erledigt 20.10.2026.** `DialektArchitekturTests.Der_Kern_greift_nur_mit_begruendeter_Ausnahme_in_ein_Dialekt_Modul` war nach dem Zusammenführen rot: acht Kerndateien griffen ins Modul `Ksql/` (SqlConvert, Rowsetfunktionen, PrattParser, PrattParser.SqlXml/SqlJson/Eigenschaftsgraph, ExpressionEvaluator, ExecutionEngine.Eigenschaftsgraph). `SqlXml`, `SqlJson`, `Graphmuster`, `Graphsichten` und `Normtabelle` sind Normlogik ohne Bezug zum KSQL-Modul, die Kernparser, Kernausführung und der T-SQL- bzw. MySQL-Zugang mitbenutzen - sie liegen jetzt im Kernordner `Norm/` (Namensraum `Kuonen.Data.KuonenSql.Norm`); die Schalter des Dialekts (`NormFunktionen` usw.) bleiben die Weiche. Keine neue Ausnahme in der Liste. Die letzte Stelle (`Parser/PrattParser.Psm.cs`, K33.10c) behebt K33.13e. ✅
K33.13e Architekturwächter grün: Moduleigenschaft im Kern **Erledigt 20.10.2026.** Nach K33.13d meldete `DialektArchitekturTests` nur noch `Parser/PrattParser.Psm.cs`: der Kernparser schrieb bei `CREATE MODULE` die erweiterte Eigenschaft unter dem Namen `Ksql.Normsichten.Moduleigenschaft` (K33.10c). Der Name `KSQL_MODUL` liegt jetzt als `PrattParser.Moduleigenschaft` im Kern, der ihn schreibt; `Normsichten` im Modul liest ihn von dort. Der Wächter ist grün (15/15), ohne neue Ausnahme; Sabotage (alter Verweis) → rot. ✅
K33.13f GRAPH_TABLE: Tiefengrenze statt Stapelüberlauf Befund 22.10.2026 (voller Lauf): Verfaelschte_Muster_werden_Fehler_und_kein_Absturz liess den Testhost mit Stack Overflow in Norm.Graphmuster+Leser enden (3000 öffnende Klammern; ebenso IS (((… und !!!… im Labelausdruck). **Erledigt 22.10.2026:** der Leser zählt die Tiefe geklammerter Pfade und Labelausdrücke (auch !); über 128 Ebenen Fehler 191 statt Absturz. Test um die beiden Label-Fälle erweitert, Sabotage (Grenze aufgehoben) stürzt wieder ab. ✅
K33.14 Der eigene SQL-Manager als Client Abnahme mit dem eigenen SQL-Manager (Objektbaum, Abfragefenster, Pläne über den KSQL-Port), Microsoft.Data.SqlClient, JDBC-Treiber für SQL Server und `go-mssqldb`; kein SSMS-Zwang. Merkmale, die der Manager braucht (Katalog, Kennung, Fehler mit SQLSTATE), werden mit ihm abgestimmt. **Erledigt 16.10.2026:** die Plugin- und Treibertests des Managers laufen auch am KSQL-Port (Orakel `KuonenSqlKsql`, 88 Fälle: Erkennung, Baum, Abfragelauf, Befehle, Pläne, Live-Statistik, Treiber); JDBC (mssql-jdbc 12.8) und go-mssqldb 1.8 aus Docker (`KsqlTreiberAbnahmeTests`), SqlClient in `KsqlZugangTests`. Dabei behoben: Binärparameter wurden als `0x…` geparst, unter KSQL eine Ganzzahl (jetzt `X'…'`); die Parameter eines RPC hinterliessen gezählte DONEINPROC (go-mssqldb meldete 4 statt 1 Zeile, auch am T-SQL-Port); PRELOGIN und LOGINACK nennen am KSQL-Port die Sprachstufe 17.0.5005 (Entscheid 16.10.2026: mssql-jdbc lehnt Fassung 1 ab), ehrlich bleiben Programmname, `@@VERSION`, `ProductVersion`. Im Manager: SQLSTATE getrennt vom Text (Treiber `TdsError.SqlState`, Meldung im Studio), Sprachstufe 17 für die Schranken des Plugins, GetSchema mit den Typen von SQL Server. ✅
K33.15 Handbuch, Prüfstand und Abnahme Handbuchkapitel KSQL mit der Merkmalsliste und den Regeln aus K33.4, Playground-Beispiele, Fuzzing der neuen Syntax (PR27.7), Gleichwertigkeit (M26; der Lastlauf über den KSQL-Port steht als LT35.1 in M35): dieselbe Datenbank gleichzeitig über T-SQL, KSQL, MariaDB und PostgreSQL. **Erledigt 16.10.2026:** Handbuchkapitel KSQL auf der Webseite (Zugang, Leitlinie, die Regeln aus K33.4 als Tabelle, die Merkmalsliste je Teil direkt aus `IsoMerkmale`, die Punkte von M33), acht Beispiele im Prüfstand (`Beispielkatalog`, KSQL als Sprache auf Port 1333; je Beispiel ein Test über einen KSQL-Hörer); Syntaxfuzzer `KsqlSyntaxFuzzingTests` über die Proben der unterstützten Merkmale (3000 Fälle im Testlauf, lang über `dist\fuzzing.ps1 -Protokoll Ksql`) mit 21 Funden als feste Tests (`FuzzingFundeTests`, je mit der Nummer des Orakels: VALUES ohne Zeile, ORDER BY-Nummer über int 408, Fremdschlüssel mit ungleicher Spaltenzahl 8139, LAG/LEAD 10755, FIRST_VALUE/LAST_VALUE 174, Datum/Zeit als Bedingung 4145, Rahmengrenze über int 102, Minus vor Zeitwert 8117, SUBSTRING-Länge über int 8115, Sortierfehler in WITHIN GROUP); Gleichwertigkeit: `GleichzeitigKreuzTests` mit KSQL als viertem Zugang (Sperren, Sichtbarkeit, Deadlock über die Ports). Dabei auch: `TRUE`/`FALSE` am KSQL-Zugang BOOLEAN statt 1/0, `OFFSET … FETCH … WITH TIES|PERCENT` (F867 mit Versatz, an PostgreSQL 17 gemessen). ✅
K33.16 Nachsichtigkeiten des Kerns: im T-SQL-Dialekt verboten, in KSQL erlaubt **Erledigt (16.10.2026).** Schalter `StrengWieSqlServer` (nur im T-SQL-Dialekt; KSQL erlaubt es weiter, die Fremddialekte haben eigene Regeln), je Fall am Orakel 2025 gemessen: `CHECK` mit Unterabfrage 1046 (beim Anlegen der Tabelle und bei `ADD CHECK`), eine unbekannte `INFORMATION_SCHEMA`-Sicht 208 (vorher leeres Ergebnis), `CREATE VIEW|PROCEDURE|FUNCTION|TRIGGER` hinter einer anderen Anweisung desselben Stapels 111 (in `EXEC ('…')` und am Stapelanfang erlaubt), `CONCAT` mit `sql_variant` 257 (`SERVERPROPERTY(…)`, `CAST(… AS sql_variant)`). `DECFLOAT` ist an beiden Zugängen schon 2715 wie am Orakel (nicht 243; am KSQL-Zugang kommt der Typ mit K33.5a). Fünf bestehende Tests legten Module mitten im Stapel an und nutzen jetzt `EXEC` oder einen eigenen Aufruf. `TsqlStrengTests` (17); siehe . Rest als K33.16a. ✅
K33.16a `+` mit `sql_variant` am T-SQL-Zugang **Erledigt (16.10.2026).** Rechnen mit `sql_variant` am T-SQL-Zugang wie SQL Server 2025 (am Orakel): mit Text oder zwei Varianten 402 („Die Datentypen sql_variant und varchar sind im add-Operator inkompatibel“, in der geschriebenen Reihenfolge), mit jedem anderen Typ 257; vorher lieferte `'x' + CAST(1 AS sql_variant)` „1“. KSQL rechnet mit dem Grundtyp (`CAST(1 AS sql_variant) + 1` ist 2). Prüfung vorn in `SqlArithmetic.Binary` über das Merkmal `InVariante` (zwei Bittests, kein Mehraufwand je Zeile). `TsqlStrengTests` (9 neu). ✅
K33.17 Eigener KSQL-Treiber, unabhängig von Microsoft.Data.SqlClient **Nutzerwunsch 15.10.2026:** ein vollwertiger ADO.NET-Treiber für KSQL mit dem vollen Umfang, den der Server kann - SQLSTATE der Fehler (K33.11), `BOOLEAN`, Intervalle, Zeilen- und Feldtypen, Zeitzonen, `GET DIAGNOSTICS`, Routinen nach Norm, ehrliche Kennung, Information Schema -, aufgesetzt auf den eigenen TDS-Treiber `Kuonen.Data.Tds` (Manager), nicht neben ihm. Nach K33.5–K33.13, damit er deren Umfang abdeckt; Abnahme mit dem SQL-Manager (K33.14). **Erledigt 20.10.2026:** `Data/src/Kuonen.Data.Ksql` erbt von `Kuonen.Data.Tds` (`KsqlConnection`, `KsqlCommand`, `KsqlParameter`, `KsqlConnectionStringBuilder` mit den Schlüsseln von SqlClient, `KsqlException : TdsException`; `KsqlDataReader` umhüllt den TDS-Leser, `KsqlTransaction`, `KsqlProviderFactory`); das KSQL-Profil steht in `Profil/`: am KSQL-Zugang nennt ein eigener Typ im Typnamen seines UDT die Schreibweise der Norm (`int ARRAY[5]`, `ROW(a int, b varchar(5))`, `INTERVAL DAY(3) TO SECOND(2)`, `DECFLOAT(16)`; Server `Erweiterungstyp.Normname`, `Dialekt.NormtypenAufDerLeitung`), JSON trägt den Benutzertyp 244; Werte als `KsqlArray`, `KsqlMultiset`, `KsqlRow`, `KsqlInterval`, `KsqlDecfloat` (Elemente in ihrem Typ), `BOOLEAN` als `bool`, Zeitzonen als `DateTimeOffset`, XML; dieselben Typen als Parameter (Textform über `nvarchar`, Typ der Norm in der Deklaration, nur neu geschrieben aus dem Typleser) und als OUTPUT; `SqlState` neben `Number`; `ServerVersion` die Fassung von KuonenSQL, `ServerProgramName` „KuonenSQL“, ohne Port 1333; `CALL` mit OUT/INOUT, `GET DIAGNOSTICS` in Routinen; `SAVEPOINT`/`ROLLBACK TO SAVEPOINT`/`RELEASE SAVEPOINT`, `READ ONLY` (3906/25006); `GetSchema("INFORMATION_SCHEMA.<SICHT>")` mit den Spalten der Norm. Server dabei behoben: `sp_executesql` las Typen der Deklaration nur mit T-SQL-Namen (`INTEGER ARRAY`, `ROW(…)`, `INTERVAL DAY TO SECOND` wurden `nvarchar`). Manager: `SqlServerPlugin` verbindet über `KsqlConnection` (T6). Robust gegen verfälschte Antworten (Relais, 60 Zufallsfälle), Lesepfad ohne Belegen je Wert (gegen den TDS-Treiber gemessen, gegen SqlClient in `docs/leistung.md`). `Kuonen.Data.Ksql.Tests` (93), `KsqlLeitungsprofilTests` (16). Reste in K33.17a. ✅
K33.17a Reste aus K33.17 Abgleich am Orakel (SQL Server 2025 auf 14335: `KsqlConnection` dort wie `TdsConnection`, Fehler ohne SQLSTATE; das Kennwort lag dem Worktree nicht vor), JDBC und go-mssqldb am KSQL-Port mit den neuen Typnamen des UDT nachprüfen (`KsqlTreiberAbnahmeTests`, Docker), `DbBatch` mit den Typen der Norm (`KsqlBatch`; heute liefert der `TdsBatch` Text), `GetColumnSchema` mit den Typnamen der Norm, `GET DIAGNOSTICS` ausserhalb einer Routine (heute 102), `BOOLEAN` mit eigenem Typnamen auf der Leitung (heute `bit`). Im Server gefunden: `ARRAY[ROW(…)]` hat den Elementtyp `nvarchar(max)` statt der Zeile, `JSON_OBJECT(…)` liefert `nvarchar` statt `JSON`. **Erledigt 21.10.2026:** Der Teil des Servers und der Abgleich am Orakel. (1) Orakel: `KsqlConnection` an SQL Server 2025 ist ein TDS-Treiber (`IsKsql` falsch, Fassung `17.00.5005`, Werte wie SqlClient, `1 / 0` ist 8134 ohne SQLSTATE) - `Kuonen.Data.Ksql.Tests/OrakelTests` (übersprungen ohne `KSQL_KONFORMITAET_ORAKEL_KENNWORT`). (2) `ARRAY[ROW(…), ROW(…)]`/`MULTISET[…]` mit ungleichen Feldtypen ist ein Array von Zeilen (Feld für Feld vereinigt, `Sammlungen.Vereinige`; vorher `nvarchar(max) ARRAY`), ebenso Arrays von Arrays. (3) `JSON_OBJECT`, `JSON_ARRAY`, `JSON_OBJECTAGG`, `JSON_ARRAYAGG` liefern am KSQL-Zugang ohne `RETURNING` den Typ JSON (T801; auf der Leitung Benutzertyp 244), mit `RETURNING` den genannten; T-SQL bleibt `nvarchar(max)`; der interne Schlüssel von `GRAPH_TABLE` bleibt Text. Tests in `KsqlLeitungsprofilTests`. Rest in K33.17b. ✅
K33.17b K33.17 und D36.1 zusammen **Erledigt 21.10.2026:** nach dem Zusammenführen waren im Referenzlauf von D36.1 `typen.interval`, `typen.decfloat` und `typen.sammlungen` rot - der Katalog erwartete die kurzen UDT-Namen, seit K33.17 nennt der KSQL-Port die Schreibweise der Norm (`INTERVAL YEAR(2) TO MONTH`, `DECFLOAT(34)`, `ROW(f1 int, f2 varchar(1))`, `int ARRAY`). Katalog, README und Profil (§8.2: Typname, JSON-UserType 244, Typen der Norm in `@params`) nachgezogen; Referenzlauf 84 grün, 2 übersprungen. ✅
K33.17c Reste aus K33.17a (vom Zweig der Serverbefunde, dort als K33.17b angelegt) (1) JDBC und go-mssqldb am KSQL-Port mit den neuen Typnamen des UDT nachprüfen (`KsqlTreiberAbnahmeTests`, braucht Docker; `docker run` startete am 21.10. keine Container). (2) Treiber: `DbBatch` mit den Typen der Norm (`KsqlBatch`; heute liefert der `TdsBatch` Text), `GetColumnSchema` mit den Typnamen der Norm. (3) `GET DIAGNOSTICS` ausserhalb einer Routine (heute 102; die Übersetzung hängt am Rumpf einer Routine, `PrattParser.MariaHandler.LiesMariaDiagnostics`). (4) `BOOLEAN` mit eigenem Typnamen auf der Leitung (heute `bit`) - Entscheid über das Profil nötig. (5) Gefunden: `ROW(1)` mit einem Feld ist `int` statt einer Zeile; ein NULL-Feld (`ROW(2, NULL)`) bekommt `nvarchar(4000)` statt des Typs der übrigen Zeilen eines Arrays. **Erledigt 21.10.2026** (ohne (4)): (5) `ROW(1)` ist am KSQL-Zugang eine Zeile mit einem Feld (`ROW(f1 int)`, PostgreSQL 17: `record`); ein Feld aus einem NULL ohne Typ bleibt im Zeilentyp unbestimmt (Marke `null`) und nimmt in `ARRAY[…]`/`MULTISET[…]` den Typ der übrigen Zeilen an, allein heisst es `nvarchar(max)` wie das Element von `ARRAY[NULL]` (PostgreSQL: `text`). (3) `GET [CURRENT] DIAGNOSTICS` geht im Stapel (Variablen `@v`, `CONDITION 1` im `CATCH`) - derselbe Leser wie im Rumpf, ohne dessen Namensfilter. (2) `KsqlBatch : TdsBatch`/`KsqlBatchCommand` (Leser `KsqlDataReader`, `ExecuteScalar` mit den Typen der Norm, `KsqlException` mit SQLSTATE und Befehl), `KsqlConnection.CreateBatch` und Fabrik; `KsqlDataReader` ist `IDbColumnSchemaGenerator` mit Typname und .NET-Typ der Norm. (1) `KsqlTreiberAbnahmeTests` mit den Typen der Norm, als Bauschritt (`KUONENSQL_DOCKER_BAU=1`) gelaufen: JDBC nennt `int ARRAY`, `ROW(f1 int, f2 varchar(1))`, `INTERVAL DAY(2)` und liest die Textform; go-mssqldb liest die Werte, `ColumnTypes` bricht bei jedem UDT ausser denen von SQL Server ab (auch mit den kurzen Namen; am Orakel gemessen). Tests: `KsqlLeitungsprofilTests`, `KsqlPsmRestTests`, `Kuonen.Data.Ksql.Tests/StapelTests`. Reste in K33.17d. ✅
K33.17d Reste aus K33.17c (1) **Entscheid von Marc:** `BOOLEAN` mit eigenem Typnamen auf der Leitung (heute `bit`, `GetDataTypeName` „bit“). Möglichkeiten: (a) so lassen - jeder SQL-Server-Treiber liest `bool`, der Name der Norm fehlt; (b) ein UDT `BOOLEAN` wie `int ARRAY` - der Name stimmt, aber JDBC, go-mssqldb und SqlClient lesen dann Bytes statt `bool` (`getBoolean`/`Scan(&bool)` gehen nicht mehr), go-mssqldb bricht in `ColumnTypes` ab; (c) `bit` mit eigenem Benutzertyp wie JSON (244) - fremde Treiber merken nichts, `Kuonen.Data.Ksql` nennt `BOOLEAN`; braucht eine Nummer und einen Eintrag im Profil (§8.2). Vorschlag: (c). (2) go-mssqldb 1.8.0: `ColumnTypes` bricht bei jedem UDT ausser `hierarchyid`/`geometry`/`geography` mit einer Panik ab (am KSQL-Port für alle Typen der Norm, schon vor K33.17); Werte lesen geht. Am Server nicht lösbar, ohne den Namen aufzugeben - beim Treiber melden oder im eigenen Go-Treiber (M36) abdecken. (3) Beobachtet: `json` heisst am Orakel bei JDBC `varchar`, bei go `NVARCHAR`; am KSQL-Port bei beiden `nvarchar` (Benutzertyp 244) - abgleichen, ob SQL Server 2025 einem Client ohne JSON-Merkmal `varchar(max)` schickt. (4) Gefunden: `(ARRAY[ROW(…)])[2].f2` ist am KSQL-Zugang „vereinfachter Zugriff braucht JSON“; `((…)[2]).f2` geht. (5) `docker run` startet auf dem Mac keinen Container: die Abnahme lief mit `KUONENSQL_DOCKER_BAU=1`; mit `docker run` (PC) nachholen: `KUONENSQL_DOCKER_ABNAHME=1 dotnet test Kuonen.KuonenSQL.slnx --filter FullyQualifiedName~KsqlTreiberAbnahmeTests`. (6) Auf dem Mac rot, nicht verursacht und nicht auf `main` gegengeprüft: `MySqlSysSichtenTests` (zwei Perzentilfälle) und `MariaDbFunktionenOrakelTests` (Rundung in der letzten Stelle von `COT`/`ACOS`). **Erledigt 21.10.2026:** (1) Entscheid (c): am KSQL-Port trägt ein `BOOLEAN` in COLMETADATA den Benutzertyp **16**, auf der Leitung bleibt es `bit` (fremde Treiber lesen `bool`/`bit`; SQL Server 2025 schickt 0, 80, 244, 255, 256 und ab 257 die Nummer eines Aliastyps - am Orakel gemessen; 16 ist die OID von `boolean` in PostgreSQL; Profil §8.2). Im Kern ist `BOOLEAN` `bit`, darum trägt am KSQL-Port jede `bit`-Spalte die 16; der T-SQL-Port bleibt bei 0. Die eigenen Treiber nennen `BOOLEAN`: .NET `GetDataTypeName`/`GetColumnSchema`, JDBC `getColumnTypeName` mit `Types.BOOLEAN`, TypeScript `typeName`/`sql.Boolean`, Python `column_types`, Go `ColumnTypes`, ODBC `SQL_DESC_TYPE_NAME` bei `SQL_BIT`, PHP `KsqlTypeName`/`decl_type`, C++ `spalte::typ`; kanonisch (Katalog) bleibt `bit`, die Abspieler bilden `BOOLEAN` darauf ab (Katalog am KSQL-Port mit .NET, Java, TypeScript, Python, Go, ODBC, C++ und PHP: je 82 ok). C, ODBC, PHP und C++ als Bauschritte in `debian:bookworm-slim` bzw. `php:8.3-cli` gebaut und getestet (Sanitizer; `kern`, `odbc`, `cpp_tests`, PHP-Robustheit grün). Tests: `KsqlLeitungsprofilTests`, `Kuonen.Data.Ksql.Tests/TypenTests`, JDBC `PruefungenTest`, TypeScript `einheit`/`mssql`, Python `test_robustheit`, Go `treiber_test`, C `kern_tests`/`odbc_tests`, C++ `cpp_tests` . (4) `.feld` nach `a[n]` ist ein Feldzugriff wie `(r).feld` (`__KSQL_FELD`, auch mehrfach und mit folgendem `[n]`); die Laufzeit entscheidet zwischen Zeile und JSON: `(ARRAY[ROW(1, 'a'), ROW(2, 'b')])[2].f2` ist `b` (die Feldnamen `f1`, `f2` vergibt KSQL seit K33.5a; PostgreSQL 17 liefert die Zeile `(2,b)`, kennt bei einer namenlosen Zeile aber kein Feld `f2` - kein Orakel, Regel des Kerns), `r[2].t` an einer Spalte geht ohne Klammer, `JSON_QUERY(…)[0].x[1]` bleibt ein JSON-Glied. Tests: `KsqlSammeltypenResteTests`. (3) Am Orakel gemessen (21.10.2026, `Kuonen.Data.Tds` ohne FeatureExt JSONSUPPORT, Leitung mitgeschnitten): SQL Server 2025 schickt einem Client ohne JSON-Merkmal `json` als `nvarchar(max)` (Benutzertyp 0, Merkmale 0x0021, Sortierung der Datenbank 0904D00034), nicht `varchar(max)`; wer das Merkmal verlangt (SqlClient 6.1.6 nachweislich, JDBC), bekommt den Typ 0xF4 - daher `varchar` bei JDBC und `NVARCHAR` bei go-mssqldb. KuonenSQL bestätigt das Merkmal nicht; der T-SQL-Port antwortet jedem Client schon genau so (nichts anzugleichen), der KSQL-Port bleibt nach Profil §8.2 bei Benutzertyp 244. Test `KsqlLeitungsprofilTests.Json_geht_wie_bei_SQL_Server_an_einen_Client_ohne_JSON_Merkmal` (beide Zugänge, Sollfolge des Orakels; war schon grün, darum kein roter Lauf); Sabotage: Benutzertyp 244 auch am T-SQL-Port, 2 rot. Offen bleiben (2), (5), (6); den Typ 0xF4 für Clients mit Merkmal anzubieten wäre ein eigenes Ticket. **Erledigt 21.10.2026** (2), (5), (6): (5) `KUONENSQL_DOCKER_ABNAHME=1 … KsqlTreiberAbnahmeTests` mit `docker run` auf dem PC (Windows, Docker Desktop 29.5): JDBC und go-mssqldb am KSQL-Port grün (2 von 2). (6) `MySqlSysSichtenTests` und `MariaDbFunktionenOrakelTests` auf dem PC (x64) grün (4 von 4) - die Abweichungen waren nur auf dem Mac (arm64). (2) Im eigenen Go-Treiber abgedeckt: sein Abspieler ruft `rows.ColumnTypes()` für jeden Fall des Katalogs, auch für ARRAY, ROW, MULTISET, INTERVAL und BOOLEAN, ohne Panik (`TreiberPruefstandTests` go am KSQL-Port grün); die Panik von go-mssqldb 1.8.0 bei fremden UDTs bleibt dort - eine Meldung an go-mssqldb wäre Marcs Entscheid. Offen bleibt aus dieser Zeile nichts; den Typ 0xF4 für Clients mit JSON-Merkmal anzubieten wäre ein eigenes Ticket. ✅
K33.18 Sperrstufen: Tabelle, Seite, Hinweise **Erledigt (20.10.2026).** Absichtssperren IS/IX/SIX als echte Sperren bis zum Transaktionsende; `TABLOCK`/`TABLOCKX`, `UPDLOCK` (U, verträgt S), `XLOCK`, `HOLDLOCK`/`REPEATABLEREAD`/`READCOMMITTED` je Tabelle, `PAGLOCK`/`ROWLOCK` mit Seitensperren, Hinweise am Ziel von INSERT/UPDATE/DELETE/MERGE, Fehler 1047/650/1065/651; `ALLOW_ROW_LOCKS`/`ALLOW_PAGE_LOCKS` am gruppierten Index; Eskalation je Anweisung bei 6250 Sperren, nicht gegen fremde unverträgliche Sperren, `ALTER TABLE … SET (LOCK_ESCALATION = TABLE/AUTO/DISABLE)` samt `sys.tables`; `sys.dm_tran_locks` aus den echten Sperren; am KSQL-Zugang `LOCK [TABLE] … [IN … MODE] [NOWAIT]` mit der Matrix von PostgreSQL (55P03, 25P01). Am Orakel SQL Server 2025 und an `postgres:17` mit zwei Sitzungen gemessen, solange Docker lief; der Rest nach Doku, Abgleich als K33.18a offen. Leistung einer Sitzung unverändert ( §21). Siehe . ✅
K33.18a Sperrstufen: Abgleich am Orakel **Erledigt (20.10.2026).** Am Orakel SQL Server 2025 mit zwei/drei Sitzungen nachgemessen: die Annahmen aus K33.18 (Fehler 1047/1065, SNAPSHOT und READ_COMMITTED_SNAPSHOT mit `TABLOCK`/`READCOMMITTEDLOCK`, Eskalation von `UPDLOCK`/`XLOCK`-Lesen, Seitensperren über mehrere Seiten) stimmen. Behoben: `READPAST, NOLOCK` ist 650; Haufen unter SERIALIZABLE sperrt die Tabelle (S); REPEATABLE READ hält nur die Zeilen, die die Bedingung trifft; UPDATE/DELETE per Durchlauf wartet auf jede fremde X/U-Sperre (READPAST lässt sie aus); Haufen zeigt eine RID je geänderter Zeile; wartende Anfragen stehen mit `WAIT` in `sys.dm_tran_locks`; `UPDLOCK, HOLDLOCK` auf fehlende Schlüssel sperrt nur die Lücke bis zum nächsten Schlüssel. Siehe . ✅
K33.18b Sperrstufen: Nebenindex-Seiten, Partitionen **Erledigt (20.10.2026).** Am Orakel gemessen: `CREATE INDEX … WITH (ALLOW_ROW_LOCKS = OFF)` wirkt; eine Änderung, die einen solchen Nebenindex berührt, sperrt seine Seite X (`PAGE X`), Lesen über ihn (`INDEX(…)`, `COUNT(*)`) und jede andere Änderung daran warten; `HOLDLOCK`/`UPDLOCK` über ihn hält die Seite S/U statt der Zeilen. `LOCK_ESCALATION = AUTO` an einer Tabelle auf einem Partitionsschema (K33.18c): `HOBT IX` je Partition, Eskalation zu `HOBT X` bzw. `HOBT S` nur der Partition. Abweichung: der ganze Nebenindex gilt als eine Seite. Siehe . ✅
K33.18c Partitionsfunktionen und -schemata von T-SQL **Erledigt (20.10.2026).** `CREATE/DROP PARTITION FUNCTION` (RANGE LEFT/RIGHT, Grenzen sortiert, `function_id` ab 65536) und `CREATE/DROP PARTITION SCHEME` (`ALL TO`, Liste, `data_space_id` ab 65601), `CREATE TABLE … ON schema(spalte)`, `$PARTITION.funktion(wert)`, `sys.partition_functions`, `partition_range_values`, `partition_parameters`, `partition_schemes`, `destination_data_spaces`, `sys.data_spaces`, `sys.partitions` je Partition, `sys.indexes.data_space_id`; Fehler wie am Orakel (208, 7707, 7708, 2714, 1921, 7726, 1911, 1750, 7706, 7717, 15151); dauerhaft über Kontrollpunkt und Neustart. Nicht gebaut: SPLIT/MERGE, NEXT USED, SWITCH, Partitionsauslassung, `partition_ordinal`. Siehe . ✅
K33.18d Teilressourcen erst bei Bedarf (Speicher je Abfrage) Befund 22.10.2026 (voller Lauf rot): BaumdurchlaufTests über der Grenze von 78 000 Bytes je Abfrage; git bisect: K33.18b (d50d21969) hob sie von 76 760 auf 78 400 (MemoryTable legte je Instanz ein leeres ConcurrentDictionary für Teilressourcen an). **Erledigt 22.10.2026:** das Wörterbuch der Teilressourcen entsteht erst beim ersten Bedarf (LazyInitializer); 77 485 bis 77 625 Bytes je Abfrage statt 78 260 bis 79 220. Sabotage (wieder sofort angelegt) 79 203, rot. ✅
K33.19 Befunde aus modern-sql.com (SQL:2023 und Unterseiten) **Erledigt (15.10.2026).** Die 88 Merkmale der Seite stehen alle in der Merkmalsliste (B032-01 heisst in SQL:2023 B036). Die Beispiele der Unterseiten am KSQL-Zugang ausgeführt; drei **Kernfehler** behoben (alle Zugänge, am Orakel 2025 gemessen): verschachtelte Kommentare `/* a /* b */ c */` (SQL Server gültig, offener Kommentar 113; MariaDB/MySQL flach), `STRING_AGG(DISTINCT …)` ist 102 statt still übergangen (am KSQL-Zugang entdoppelt `LISTAGG(DISTINCT …)`, bei MariaDB `GROUP_CONCAT(DISTINCT …)` - beide übergingen es still), `VARCHAR(10 CHARACTERS)` ist 102 statt still eine Länge 1 (am KSQL-Zugang Längeneinheiten `CHARACTERS`/`OCTETS`, T062). Die Proben von T612 (jetzt mit `FILTER`, steht auf „-“) und T062 (Einheit in der Deklaration) geschärft. Siehe . ✅
K33.19a Rest aus K33.19: `GREATEST`/`LEAST` und Umwandlungen nach Norm **Erledigt (15.10.2026).** Am KSQL-Zugang: `GREATEST`/`LEAST` mit einem NULL-Argument ergeben NULL (T054; PostgreSQL und SQL Server übergehen es), Text in Ganzzahl und `numeric` nimmt `0x`/`0o`/`0b` und Unterstriche zwischen Ziffern (T661/T662 in der Umwandlung; Regeln an PostgreSQL 17 gemessen: `'0x_2a'` 42, `'-0x2a'` −42, `'1_000.5'` als numeric; Fehler bei `'_1'`, `'1__0'`, `'1_'`, `'0x'` und in `float`). Am T-SQL-Zugang: `SELEC 1 FROM t` am Stapelanfang ist 156 wie SQL Server 2025 (weiter hinten 102, ohne Klausel 2812 - am Orakel gemessen). `KsqlUmwandlungTests` (27); siehe . ✅
K33.20 Live-Abfragestatistik am Server **Nutzerwunsch 15.10.2026** (Studio T3g): `sys.dm_exec_query_statistics_xml(sitzung)` liefert den Plan der laufenden Anweisung einer Sitzung mit den bisher gezählten Zeilen je Operator (wie SQL Server mit eingeschalteter leichter Profilerstellung), `sys.dm_exec_query_profiles` (heute nur eine leere Vorlage) je Operator `row_count`/`estimate_row_count`; die Zähler kommen aus dem Ausführer, ohne den heissen Weg zu belasten (je Operator ein Zähler, kein Belegen je Zeile). Danach zeigt das Studio die Live-Abfragestatistik auch für KuonenSQL (Grund im Plugin entfällt). **Erledigt 16.10.2026:** gezählt wird je Tabellenzugriff (ein Zähler je Tabelle) und je gesendeter Zeile, nur in Sitzungen mit `SET STATISTICS XML ON` (so schaltet SSMS die Live-Statistik ein; sonst kostete die Zählung rund 5 %, docs/leistung.md §20); der Plan eines SELECT entsteht unter dem Schalter nach der Ausführung, damit die Vorzählung nicht an einer Sperre wartet. `LiveStatistikTests` (über TDS, an einer gesperrten Zeile wartend). ✅
K33.20a Sperren an ##-Tabellen und DROP gegen wartende Leser Befund 16.10.2026 (Manager-Test zu K33.20, gemessen am eigenen Testserver gegen SQL Server 2025): ein Leser einer globalen Temp-Tabelle (`##t`) wartet nicht an der Zeilensperre einer anderen Sitzung (`BEGIN TRAN; UPDATE ##t …`), bei gewöhnlichen Tabellen schon - SQL Server wartet in beiden Fällen; `DROP TABLE` einer Tabelle, an der ein Leser wartet, geht in KuonenSQL sofort durch (der Leser meldet danach 208), SQL Server lässt den DROP auf die Schemasperre warten. **Erledigt 16.10.2026:** `##`-Tabellen sperren wie gewöhnliche (Aufbausperre unter `tempdb`); DROP/ALTER/CREATE INDEX/TRUNCATE warten auf jede fremde Sperre der Tabelle (wie bisher nur TRUNCATE) und auf Anweisungen, die an ihr warten (geteilte Aufbausperre, Sch-S); dabei auch gefunden und behoben: DROP ging gegen eine offene fremde Schreibtransaktion durch. `AufbauGegenLeserSperrTests`. ✅
K33.21 `CHECKSUM` und `BINARY_CHECKSUM` **Erledigt (16.10.2026).** `CHECKSUM(…|*)` und `BINARY_CHECKSUM(…|*)` an allen Zugängen, Rechenweg aus Messreihen am Orakel 2025 (SQL_Latin1_General_CP1_CI_AS): je Wert ein 32-Bit-Wort, verknüpft durch „um 4 Bit nach links drehen, dann XOR“, innerhalb eines Texts oder Binärwerts je Zeichen bzw. Byte; NULL 0x7FFFFFFF; bigint, float und money (Zehntausendstel) hoch XOR tief; real seine Bits; date Tage seit 1900; Text ohne Leerzeichen am Ende; `CHECKSUM` über varchar mit den 256 gemessenen Sortiergewichten, `BINARY_CHECKSUM` mit dem Code. Exakt wie SQL Server für diese Typen (u. a. (1, 2) → 18, 'ab' → 2159, 9 Argumente → 591751048, 18 Bytes → 930299899). `CHECKSUM_AGG` gab es schon. `PruefsummeTests` (40). Rest als K33.21a. ✅
K33.21a Rest aus K33.21: Prüfsummen weiterer Typen und Sortierungen Genau wie SQL Server fehlen: `CHECKSUM` über nvarchar (rechnet über den Unicode-Sortierschlüssel: N'ab' → 0x090E020E, N'a' → 114), `datetime` ('2026-01-02 03:04:05' → 3292314, nicht Tage XOR Ticks), `datetime2`/`time`/`datetimeoffset`, `decimal`/`numeric` (1.50 → 1768927692), `uniqueidentifier`, ein NULL-Text hinter einem Text (BINARY_CHECKSUM('a', NULL) → 2147482095) und die Gewichte anderer Sortierungen als SQL_Latin1_General_CP1_CI_AS. Bis dahin rechnet der Kern dort deterministisch (gleiche Werte, gleiche Summe). Nur aus weiteren Messreihen herleiten. **Erledigt 16.10.2026:** datetime (Tage XOR Dreihundertstel), smalldatetime (Tage·65536 plus Minuten), time (gefaltete 100-ns-Ticks), datetime2 und datetimeoffset (Tage XOR gefaltete Ticks, datetimeoffset in UTC), uniqueidentifier (Bytes) genau wie SQL Server; ein untypisiertes NULL als Argument ist 8116 wie am Orakel. Der NULL-Text hinter einem Text folgte schon der Regel (die Zahl oben war falsch umgerechnet). Rest als K33.21b. `PruefsummeTests` (64). ✅
K33.21b Rest aus K33.21a: Prüfsummen von decimal, nvarchar und weiteren Sortierungen **Erledigt für decimal/numeric (20.10.2026), am Orakel abgeglichen in K33.21c:** aus den Messreihen von K33.21a hergeleitet - die Ziffern ohne Vorzeichen, Komma und nachgestellte Nullen, auf 38 Stellen aufgefüllt (1 → 10^37), als vier 32-Bit-Wörter vom niedrigsten an verknüpft; trifft alle 17 Messwerte (1 → -1374215283, 15 = 1.50 → 1768927692, 65536 → -495039993). nvarchar und andere Sortierungen liessen sich aus den drei vorhandenen Messwerten nicht herleiten (Docker lief nicht, keine neuen Messreihen) - Rest als K33.21c. `PruefsummeTests` (88). ✅
K33.21c Rest aus K33.21b: Prüfsummen von nvarchar und weiteren Sortierungen `CHECKSUM` über nvarchar genau wie SQL Server: gemessen N'a' 114, N'aa' 0x020E020E, N'ab' 0x090E020E; die Primärgewichte des Sortierschlüssels als Wörter in Little Endian treffen die beiden längeren, nicht N'a' (526 statt 114) - Rest von unter 4 Byte, Akzent-/Gross-Klein-Gewichte und andere Schriften offen. Dazu die Gewichte anderer Sortierungen als SQL_Latin1_General_CP1_CI_AS (keine Messung) und der Abgleich von K33.21b am Orakel: die decimal-Werte aus `PruefsummeTests` (u. a. 1, 15, 125, 65536 als decimal(38,0), 1.50 als decimal(5,2), 0.1, 10, -1, 1e19), Werte mit 38 Stellen und grosser Skala (`CAST(0.12345678901234567890123456789012345678 AS decimal(38,38))`, `CAST(99999999999999999999999999999999999999 AS decimal(38,0))`), decimal neben einem weiteren Argument (`CHECKSUM(CAST(1.5 AS decimal(5,2)), 1)`) und `BINARY_CHECKSUM` über decimal. Die nötige Messreihe steht in docs/umsetzung.md#k3321b. Bis dahin deterministisch über den Text. **Erledigt (20.10.2026):** aus Messreihen am Orakel 2025 hergeleitet - nvarchar und varchar unter Windows-Sortierungen über die Bytes des primären Sortierschlüssels (je volles Wort Little Endian, je Restbyte, um 3 gedreht), 133 Familien samt Kontraktionen, Wiederholungsmarken und Leerzeichen am Ende; varchar unter den 77 SQL_-Sortierungen über deren Gewichte je Byte mit Erweiterungen und Kontraktionen; binär und `BINARY_CHECKSUM` über die Bytes mit Vorzeichen (bisher vorzeichenlos) bzw. UTF-16; decimal neben weiteren Argumenten wie K33.21b. Daten `pruefsummen.tsv.gz` (82 KB), Herkunft `KuonenSQL/tools/pruefsumme`. Rest als K33.21d. `PruefsummeTextTests` (93), `PruefsummeFamilienTests` (131). ✅
K33.21d Rest aus K33.21c: Han-Ideogramme der CJK-Sortierungen Die Reihenfolge der Han-Ideogramme (U+3400–4DBF, U+4E00–9FFF, U+F900–FAFF) in den chinesischen, japanischen und koreanischen Familien (über 500 000 Einträge, rund 0,8 MB gz) und die Zeichen ausserhalb der BMP in Chinese_*_100/160 (rund 290 000) und Japanese_Bushu_Kakusu (303) - gemessen und mit demselben Verfahren herleitbar, offen ist nur die Datenmenge (Entscheid des Auftraggebers); bis dahin nimmt der Kern dort die Grundtabelle. Dazu kennt der Kern die Sortierungen der Fassung 160 (SQL Server 2025, `Chinese_Simplified_*_160_*`) noch nicht (448); ihre übrigen Gewichte liegen schon in den Daten. **Erledigt (20.10.2026, Entscheid des Auftraggebers):** Han-Reihenfolgen der 27 CJK-Familien und eigene Schlüssel ausserhalb der BMP (Chinese_*_100/160, Japanese_Bushu_Kakusu) in `pruefsummen-cjk.tsv.gz` (1,22 MB), nachgeladen beim ersten Gebrauch (Start unverändert 428/418 ms, erstes CJK-CHECKSUM 65 ms); die 32 Sortierungen der Fassung 160 im Kern (`fn_helpcollations` 5540 wie 2025). 324 frische Stichproben wie das Orakel. `PruefsummeCjkTests` (323). ✅
K33.22 Umbenennen und Typwechsel per Skript **Erledigt (15.10.2026, Frage Marc).** Am Orakel 2025 gemessen und an beiden Zugängen gleich: `sp_rename` für Spalte und Tabelle, `ALTER COLUMN` auf einen grösseren Typ (int → bigint, varchar(5) → varchar(50), decimal(5,2) → decimal(10,3)), von Zahl auf Text und von Text auf Zahl, wenn alle Werte passen; sonst 245, 220 oder 2628 (beim Umbau mit leerem Wert, wie SQL Server) und die Zeilen bleiben. Kernfehler: ein Typwechsel, den SQL Server schon nach den Typen abweist (int → date), ist jetzt 206 (vorher 529), auch bei leerer Tabelle. Am KSQL-Zugang dazu `ALTER TABLE … RENAME [COLUMN] a TO b` und `RENAME TO` (wie PostgreSQL) neben `ALTER COLUMN … SET DATA TYPE`. `SpaltenumbauTests`. Im Studio: siehe Manager-Roadmap T3i. ✅
K33.23 Neuaufbau einer Tabelle (Befunde KS1 aus dem Studio) **Erledigt (15.10.2026).** Der Neuaufbau im Designer des Studios scheiterte an KuonenSQL (KS1-Zwillinge): ein nachträglicher Primärschlüssel oder eine UNIQUE-Einschränkung über doppelte Werte wurde still angenommen (über TDS hing der Stapel) - jetzt 1505 mit dem doppelten Wert und `'dbo.t'`, gefolgt von 1750 und 3621, `ERROR_NUMBER()` 1750 (Orakel 2025; nur T-SQL und KSQL); `SET IDENTITY_INSERT dbo.t ON` mit Schema galt nicht (der Parser reihte "dbo . t" auf); `DROP TABLE` liess die Trigger stehen (ein ROLLBACK stellt sie mit der Tabelle wieder her). Ab dieser Fassung (1.21.5.0) baut das Studio die Tabelle auch bei KuonenSQL neu auf (Manager T3i). `NeuaufbauBefundeTests`. ✅
K33.24 Umbenennen: Befunde aus dem Studio (T3i) **Erledigt (15.10.2026).** Am MariaDB- und MySQL-Zugang gab `ALTER TABLE db.t RENAME COLUMN|INDEX … TO …` und `ALTER TABLE db.t RENAME TO …` den Namen `db.t` an `sp_rename` weiter, das `db` als Schema las („kein Element mit dem Namen 'db.t' in der aktuellen Datenbank“) - auch aus derselben Datenbank. Jetzt fällt `db.` in der gewählten Datenbank weg, eine andere übernimmt `TabelleUmbenennenStatement` (Spalte und Index neu) in deren Kontext. `sp_rename 'tabelle.spalte', 'neu'` ohne Objekttyp benennt die Spalte um wie SQL Server 2025 (der Kern meldete 15225; am Orakel gemessen, auch `[dbo].[t].[s]`). `MariaUmbenennenTests`, `SpaltenumbauTests`. Offen als KS1 (Manager): am PostgreSQL-Zugang folgt eine Sicht dem neuen Namen ihrer Tabelle nicht (PostgreSQL bindet sie an die OID). ✅
K33.25 Nebenbefund aus K33.8 Teil 6: Katalogfunktionen im Aggregat über Systemsichten `SELECT MAX(SCHEMA_NAME(schema_id)) FROM sys.objects …` und `MAX(OBJECT_NAME(object_id))` liefern im Kern leer (am T-SQL- und am KSQL-Zugang); ohne Aggregat, mit einem festen Argument oder über einer eigenen Tabelle stimmt es. Nicht der Plan des Stromaggregats (dort mit Katalog geprüft, ohne Wirkung) - Ursache im Weg der Systemsichten suchen, am Orakel gegenprüfen. **Erledigt (20.10.2026), am Orakel abgeglichen in K33.25a:** über einer Systemsicht hat das Aggregat keinen übersetzten Plan, und der Rückfall wertete das Argument ohne Katalog aus (`OBJECT_NAME` NULL, `SCHEMA_NAME` nur feste Schemas); jetzt mit Katalog, gleich wie ohne Aggregat. `KatalogfunktionImAggregatTests` (8). ✅
K33.25a Rest aus K33.25: Abgleich am Orakel Am Orakel SQL Server 2025 (eigene Objekte mit Präfix) gegen den Kern halten: `MAX(SCHEMA_NAME(schema_id))` und `MAX(OBJECT_NAME(object_id))` über `sys.objects`/`sys.tables` mit einem eigenen Schema, `MIN(OBJECT_SCHEMA_NAME(object_id))`, `COUNT(OBJECT_NAME(object_id))`, `STRING_AGG(OBJECT_NAME(object_id), ',') WITHIN GROUP (ORDER BY name)`, dasselbe mit `GROUP BY type` - Erwartung wie in `KatalogfunktionImAggregatTests`. **Erledigt (20.10.2026):** am Orakel 2025 alle Fälle wie der Kern (kr_s, kr_t, 2, kr_t,kr_u, kr_s|kr_u). ✅

Beispiele

Typen

BOOLEAN mit TRUE, FALSE und UNKNOWN

BOOLEAN ist ein echter Typ (T031): ein Vergleich ist ein Wert, IS TRUE/IS UNKNOWN prüft ihn, auch wenn er NULL ist.

SELECT TRUE AS wahr, (1 > 2) AS vergleich, (NULL = 1) IS UNKNOWN AS unbekannt;
Erwartetes Ergebnis
wahr | vergleich | unbekannt
True | False | True

Literale

0x als Zahl, X'…' als Binärwert

Nach SQL:2023 (T661) ist 0x1F eine Ganzzahl; ein Binärwert schreibt sich X'1F'. Zahlen dürfen Unterstriche als Trenner tragen (1_000).

SELECT 0x1F AS zahl, X'1F' AS binaer, 1_000 + 1 AS mit_trenner;
Erwartetes Ergebnis
zahl | binaer | mit_trenner
31 | 0x1F | 1001

Abfragen

OFFSET und FETCH FIRST

Die Norm blättert mit OFFSET … ROWS und FETCH FIRST … ROWS ONLY; WITH TIES nimmt Gleichstand mit.

SELECT n FROM (VALUES (3), (1), (2), (2)) AS t (n)
ORDER BY n OFFSET 1 ROW FETCH FIRST 1 ROW WITH TIES;
Erwartetes Ergebnis
n
2
2

WITH RECURSIVE

Eine rekursive gemeinsame Tabelle trägt in der Norm das Wort RECURSIVE.

WITH RECURSIVE zahlen (n) AS (SELECT 1 UNION ALL SELECT n + 1 FROM zahlen WHERE n < 4)
SELECT SUM(n) AS summe FROM zahlen;
Erwartetes Ergebnis
summe
10

Vergleiche

IS DISTINCT FROM

IS [NOT] DISTINCT FROM vergleicht so, dass NULL gleich NULL ist - ohne ISNULL-Umweg.

SELECT CASE WHEN NULL IS NOT DISTINCT FROM NULL THEN 'gleich' ELSE 'verschieden' END AS nullen,
       CASE WHEN 1 IS DISTINCT FROM NULL THEN 'verschieden' ELSE 'gleich' END AS eins_null;
Erwartetes Ergebnis
nullen | eins_null
gleich | verschieden

Regeln

UNIQUE lässt mehrere NULL zu

Wo T-SQL und Norm verschieden rechnen, gilt am KSQL-Zugang die Norm: NULL ist nie gleich NULL, ein UNIQUE-Schlüssel nimmt beliebig viele NULL (T-SQL: eine).

CREATE TABLE Pruefstand_Eindeutig (Id int PRIMARY KEY, Kennung varchar(10) UNIQUE);
INSERT INTO Pruefstand_Eindeutig VALUES (1, NULL), (2, NULL), (3, 'A');
SELECT COUNT(*) AS zeilen, COUNT(Kennung) AS mit_kennung FROM Pruefstand_Eindeutig;
DROP TABLE Pruefstand_Eindeutig;
Erwartetes Ergebnis
zeilen | mit_kennung
3 | 1

Transaktionen

START TRANSACTION und Sicherungspunkte

Transaktionen nach der Norm: START TRANSACTION, SAVEPOINT, ROLLBACK TO SAVEPOINT, COMMIT. Ohne offene Transaktion ist COMMIT erlaubt.

CREATE TABLE Pruefstand_Buchung (Id int PRIMARY KEY, Betrag int);
START TRANSACTION;
INSERT INTO Pruefstand_Buchung VALUES (1, 100);
SAVEPOINT vor_fehler;
INSERT INTO Pruefstand_Buchung VALUES (2, 999);
ROLLBACK TO SAVEPOINT vor_fehler;
COMMIT;
COMMIT;
SELECT Id, Betrag FROM Pruefstand_Buchung;
DROP TABLE Pruefstand_Buchung;
Erwartetes Ergebnis
Id | Betrag
1 | 100

Kennung

Wer antwortet

Der KSQL-Zugang sagt ehrlich, wer er ist: @@VERSION und SERVERPROPERTY nennen KuonenSQL und seine Fassung, nicht SQL Server.

SELECT LEFT(@@VERSION, 9) AS produkt, CAST(SERVERPROPERTY('Edition') AS nvarchar(20)) AS ausgabe;
Erwartetes Ergebnis
produkt | ausgabe
KuonenSQL | KuonenSQL