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
- Kuonen.Data.Gemeinsam.2.8.1.nupkg · 29 KB
SHA-256
8970bbedd6260f0b1d29c5a9e58b458602c737e52fdc223fb20e6fbcd9c58f35 - Kuonen.Data.Ksql.2.8.1.nupkg · 61 KB
SHA-256
0f03e8312f6717ab0f782a3f843ac2ae823daea3fd4b1d6df7986e671bfd3ca7 - Kuonen.Data.Tds.2.8.1.nupkg · 230 KB
SHA-256
87a945aa6e9ae03dee96652c2b448639d3722e2cf57aef0585a8a1e9cd0e2616
# 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.1Kuonen.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
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=TrueOhne Port gilt 1333 (der KSQL-Port).
| Schlüssel | Bedeutung |
|---|---|
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 |
Encrypt | true/yes/mandatory (Vorgabe), false/no/optional, strict (TDS 8.0) |
TrustServerCertificate, Host Name In Certificate, Server Certificate | Prüfung des Zertifikats |
Connect Timeout, Command Timeout | Fristen in Sekunden (Vorgabe 15 bzw. 30) |
Pooling, Max Pool Size, Min Pool Size, Connection Lifetime | Pool des TDS-Treibers |
Multiple Active Result Sets | MARS des TDS-Treibers |
Application Name, Workstation ID, Packet Size, Application Intent, Current Language | wie bei SqlClient |
Beispiel: verbinden, abfragen, Parameter, Transaktion
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-Typ | im Treiber |
|---|---|
| Typen von SQL Server | wie 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 MULTISET | KsqlMultiset (GetKsqlMultiset) |
| JSON (Benutzertyp 244) | der Text des Dokuments (KsqlDbType.Json) |
| XML | der Text des Dokuments (KsqlDbType.Xml) |
| Zeitzonen | DateTimeOffset |
Fehler und SQLSTATE
| Fall | Angaben |
|---|---|
| KsqlException : TdsException | Number (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 |
| 22018 | ein Wert vom Server, der nicht die Textform seines Typs hat |
| an SQL Server | der 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.
| Restzeile | Beschreibung | Stand |
|---|---|---|
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.