Kuonen SQL

KSQL-Treiber

Eigene Treiber für den KSQL-Port (TDS 7.4 mit dem KSQL-Profil) in acht Sprachen, je nach dem Vorbild des Microsoft-Treibers: dieselbe Schnittstelle, dieselben Schlüssel der Verbindungszeichenfolge, dieselbe Abbildung der Typen und Fehler — und dazu, was KSQL über SQL Server hinaus kann. Jeder arbeitet auch an SQL Server. Jeder Treiber spielt denselben sprachneutralen Prüfkatalog ab (KuonenSQL/tools/ksql-konformitaet/faelle.json, D36.1), einmal gegen den KSQL-Port und einmal gegen SQL Server 2025.

Vorbild: Microsoft.Data.SqlClient · Kuonen.Data.Ksql (Namensraum Kuonen.Data.Ksql), auf dem eigenen TDS-Treiber Kuonen.Data.Tds · .NET 10, AOT-tauglich · Quelle: Data/src/Kuonen.Data.Ksql · Roadmap K33.17 ✅

Herunterladen und einbinden

Befehle
# die drei .nupkg in einen Ordner legen, etwa ./ksql-pakete
dotnet nuget add source ./ksql-pakete --name kuonen-ksql
dotnet add package Kuonen.Data.Ksql --version 2.8.1

Kuonen.Data.Ksql braucht Kuonen.Data.Tds und dieses Kuonen.Data.Gemeinsam – alle drei Pakete gehören in denselben Ordner. Danach wie im Beispiel unten: using Kuonen.Data.Ksql;

Aus dem Quellcode bauen

Befehle
dotnet build Data/src/Kuonen.Data.Ksql
# im eigenen Projekt:
# <ProjectReference Include="…/Data/src/Kuonen.Data.Ksql/Kuonen.Data.Ksql.csproj" />

Aus dem Quellcode wird der Treiber als Projektverweis eingebunden (Kuonen.Data.Ksql.csproj) und zieht Kuonen.Data.Tds mit; gebaut gibt es ihn oben als NuGet-Paket. Ein README hat der Treiber nicht; die Angaben stammen aus dem Code und der Roadmap-Zeile K33.17.

Verbindungszeichenfolge

Server=localhost;Database=master;User ID=sa;Password=<Ihr-Kennwort>;TrustServerCertificate=True

Ohne Port gilt 1333 (der KSQL-Port).

SchlüsselBedeutung
Server (Data Source, Address, Addr)Rechner, Rechner,Port oder Rechner\Instanz; ohne Port und ohne Instanz hängt KsqlConnection ,1333 an
Database (Initial Catalog)Anfangsdatenbank
User ID (UID, User), Password (PWD)SQL-Anmeldung
Encrypttrue/yes/mandatory (Vorgabe), false/no/optional, strict (TDS 8.0)
TrustServerCertificate, Host Name In Certificate, Server CertificatePrüfung des Zertifikats
Connect Timeout, Command TimeoutFristen in Sekunden (Vorgabe 15 bzw. 30)
Pooling, Max Pool Size, Min Pool Size, Connection LifetimePool des TDS-Treibers
Multiple Active Result SetsMARS des TDS-Treibers
Application Name, Workstation ID, Packet Size, Application Intent, Current Languagewie bei SqlClient

Beispiel: verbinden, abfragen, Parameter, Transaktion

C#
using Kuonen.Data.Ksql;

await using var verbindung = new KsqlConnection("Server=localhost;User ID=sa;Password=…;TrustServerCertificate=True");
await verbindung.OpenAsync();                      // ohne Port gilt 1333

await using var transaktion = await verbindung.BeginTransactionAsync();
await using var befehl = new KsqlCommand("SELECT name FROM sys.tables WHERE name LIKE @muster", verbindung, transaktion);
befehl.Parameters.Add(new KsqlParameter("@muster", "kk_%"));
await using (var leser = await befehl.ExecuteReaderAsync())
{
    while (await leser.ReadAsync())
        Console.WriteLine(leser.GetString(0));
}
transaktion.Save("vorher");                        // SAVEPOINT vorher
await transaktion.CommitAsync();

try
{
    await new KsqlCommand("SELECT 1 / 0", verbindung).ExecuteScalarAsync();
}
catch (KsqlException fehler)                       // fehler.Number 8134, fehler.SqlState "22012"
{
    Console.WriteLine($"{fehler.Number} {fehler.SqlState}");
}

Typen

SQL- bzw. KSQL-Typim Treiber
Typen von SQL Serverwie beim TDS-Treiber bzw. SqlClient (int, decimal, string, DateTime, Guid, byte[] …)
BOOLEAN (auf der Leitung bit)bool; Parameter mit KsqlDbType.Boolean, NULL ist UNKNOWN
INTERVAL …KsqlInterval (GetKsqlInterval)
DECFLOAT(16|34)KsqlDecfloat (GetKsqlDecfloat)
ROW(…)KsqlRow (GetKsqlRow), Felder in ihrem Typ
typ ARRAY[n]KsqlArray (GetKsqlArray), Elemente in ihrem Typ
typ MULTISETKsqlMultiset (GetKsqlMultiset)
JSON (Benutzertyp 244)der Text des Dokuments (KsqlDbType.Json)
XMLder Text des Dokuments (KsqlDbType.Xml)
ZeitzonenDateTimeOffset

Fehler und SQLSTATE

FallAngaben
KsqlException : TdsExceptionNumber (Nummer des Servers) und SqlState: am KSQL-Port der SQLSTATE der Norm, den der Server als „(SQLSTATE xxxxx)“ an den Text hängt und der Treiber abtrennt
22018ein Wert vom Server, der nicht die Textform seines Typs hat
an SQL Serverder Treiber arbeitet wie ein TDS-Treiber: Fehler ohne SQLSTATE (K33.17a, am Orakel gemessen)

Unterschiede zu Microsoft.Data.SqlClient

  • Klassen KsqlConnection, KsqlCommand, KsqlParameter, KsqlDataReader, KsqlTransaction, KsqlProviderFactory statt Sql…; KsqlException erbt von TdsException, nicht von SqlException.
  • Vorgabeport 1333 statt 1433 (KsqlConnectionStringBuilder.WithDefaultPort).
  • Ehrliche Kennung: ServerVersion ist die Fassung von KuonenSQL, ServerProgramName „KuonenSQL“, IsKsql sagt, ob die Verbindung am KSQL-Port hängt.
  • Transaktionen nach der Norm: Sicherungspunkte über SAVEPOINT, ROLLBACK TO SAVEPOINT und RELEASE SAVEPOINT, BeginTransaction(isolationLevel, readOnly: true) für READ ONLY (eine Änderung darin ist 3906, SQLSTATE 25006).
  • GetSchema("INFORMATION_SCHEMA.<SICHT>") mit den Spalten der Norm.
  • CALL mit OUT/INOUT und GET DIAGNOSTICS in Routinen.

Was fehlt

  • DbBatch mit den Typen der Norm (KsqlBatch; heute liefert der TdsBatch Text).
  • GetColumnSchema mit den Typnamen der Norm.
  • BOOLEAN mit eigenem Typnamen auf der Leitung (heute bit) – Entscheid über das Profil nötig.
RestzeileBeschreibungStand
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.✅

Herkunft und Lizenz

Eigenbau: übernommen sind nur die Schnittstelle des Microsoft-Treibers und das am Orakel (SQL Server 2025) gemessene Verhalten, kein Code – auch nicht aus MIT- oder BSD-lizenzierten Quellen –, damit der Treiber uneingeschränkt KuonenSQL gehört. Der Code bleibt geschlossen; eine Veröffentlichung gibt es nur als eigenständigen Fork, den Marc Kuonen selbst anlegt.

Aufgesetzt auf den eigenen TDS-Treiber Kuonen.Data.Tds des Managers, unabhängig von Microsoft.Data.SqlClient; kein NuGet-Paket.