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: keine eigene C++-Schnittstelle von Microsoft: Schlüssel von ODBC Driver 18 (für bestehende Programme bleibt der ODBC-Treiber der Weg) · Bibliothek ksqlcpp über ksqlkern, CMake-Ziel ksql::ksql (find_package(KuonenKsql)) · C++20, CMake · Quelle: Data/src/Kuonen.Data.Ksql.Cpp · Roadmap D36.6 ✅

Herunterladen und einbinden

Befehle
sudo mkdir -p /opt/ksql && sudo tar -xzf kuonen-ksql-cpp-2.8.0.1-linux-*.tar.gz -C /opt/ksql
# CMakeLists.txt des eigenen Programms:
#   find_package(KuonenKsql CONFIG REQUIRED)
#   target_link_libraries(meinprogramm PRIVATE ksql::ksql)
cmake -S . -B bau -DCMAKE_PREFIX_PATH=/opt/ksql && cmake --build bau

Köpfe und die beiden statischen Bibliotheken (ksqlcpp, ksqlkern) für Linux (x64 oder arm64), gebaut mit g++ und OpenSSL 3; dazu die Paketbeschreibung für find_package.

Aus dem Quellcode bauen

Befehle
cmake -S Data/src/Kuonen.Data.Ksql.Cpp -B bau [-DKSQL_TLS=openssl|apple|schannel] && cmake --build bau
cmake --install bau --prefix /opt/ksql          # Köpfe, Bibliotheken, find_package(KuonenKsql)
# vcpkg (Overlay-Port) und Conan 2 (Rezept) sind vorbereitet, nicht veröffentlicht:
vcpkg install kuonen-ksql --overlay-ports=Data/src/Kuonen.Data.Ksql.Cpp/verteilung/vcpkg
conan create Data/src/Kuonen.Data.Ksql.Cpp/verteilung/conan --build=missing

Ein Programm bindet ksql::ksql (find_package(KuonenKsql CONFIG REQUIRED)). Die Fassung folgt der des Servers.

Verbindungszeichenfolge

Server=127.0.0.1,1333;UID=sa;PWD={<Ihr-Kennwort>};Encrypt=yes;TrustServerCertificate=yes

Ohne Port gilt 1433 wie beim Vorbild; den KSQL-Port 1333 nennt man.

SchlüsselBedeutung
ServerRechner[,Port]; Vorgabeport 1433 wie bei ODBC Driver 18
UID, PWD, DatabaseSQL-Anmeldung; {…} um einen Wert erlaubt ; darin
Encryptyes, no, strict
TrustServerCertificate, HostNameInCertificate, ServerCertificatePrüfung des Zertifikats
APP, WSID, Language, PacketSize, LoginTimeout, ApplicationIntentwie bei ODBC Driver 18

Beispiel: verbinden, abfragen, Parameter, Transaktion

C++
#include <ksql/ksql.hpp>

auto v = ksql::verbindung::oeffne("Server=127.0.0.1,1333;UID=sa;PWD={…};Encrypt=yes;TrustServerCertificate=yes");
for (const ksql::zeile &z : v.ausfuehren("SELECT id, name FROM kunde WHERE ort = @p1", std::string("Sion")))
    std::cout << z.get<int>(0) << ' ' << z.get<std::optional<std::string>>("name").value_or("-") << '\n';

auto t = v.beginne();
long long n = v.ausfuehren("UPDATE konto SET saldo = saldo - @betrag WHERE id = @id",
                           ksql::param("@betrag", ksql::dezimal("12.50")), ksql::param("@id", 7)).betroffen();
t.bestaetige();                      // ohne bestaetige() nimmt der Zerstörer die Transaktion zurück

try {
    v.ausfuehren("SELECT 1 / 0").zu_ende();
} catch (const ksql::fehler &e) {    // e.nummer() 8134, e.klasse() 16, e.sqlstate() "22012" (am KSQL-Port)
}

Typen

SQL- bzw. KSQL-Typim Treiber
Parameter (Typ aus dem C++-Typ)bool → bit, short → smallint, int → int, long long → bigint, std::uint8_t → tinyint, std::uint64_t → decimal(20,0), float → real, double → float, Text → nvarchar(4000|max), bytes → varbinary(8000|max), dezimal → decimal(p,s), guid → uniqueidentifier, year_month_day → date, uhrzeit → time(7), local_time → datetime2(7), zeit_mit_versatz und sys_time → datetimeoffset(7), std::optional<T> → NULL mit dem Typ von T
Werte (zeile::get<T>)bool, Ganzzahlen, float/double, std::string, dezimal, guid, bytes, std::chrono::year_month_day, uhrzeit, ortszeit, zeit_mit_versatz, jeweils auch std::optional<T>; text(i) in der kanonischen Form des Prüfkatalogs
KSQL-Typen als Parameterksql::als{"int ARRAY", "{1,2}"} (in @params mit ihrem Namen deklariert); ksql::als nennt jeden anderen Typ ausdrücklich
ARRAY, ROW, MULTISET, INTERVAL als WertText, keine eigenen C++-Typen

Fehler und SQLSTATE

FallAngaben
ksql::fehlerHauptmeldung mit nummer(), klasse(), Zustand, sqlstate() und Text ohne den Zusatz; alle Meldungen in meldungen()
leitungsfehlerdie Verbindung ist danach unbrauchbar
abbruch, fristablaufHY008 bzw. HYT00
wertfehler22002 NULL ohne optional, 22003 Bereich, 07006 Typ, 22018 Text, 07009 Spalte
HY010, 08003offene Antwort oder Massenkopie sperrt die Verbindung; Antwort, Transaktion und Massenkopie nach ihrer Verbindung

Unterschiede zu keine eigene C++-Schnittstelle von Microsoft: Schlüssel von ODBC Driver 18 (für bestehende Programme bleibt der ODBC-Treiber der Weg)

  • Microsoft liefert keine C++-Schnittstelle; Vorbild sind die Schlüssel von ODBC Driver 18, die Schnittstelle selbst ist eigen (RAII, Ausnahmen, typsichere Parameter, deutsche Namen).
  • Ein Fehler des Servers wird an der nächsten Grenze geworfen (Ende der Zeilen, naechste_menge(), zu_ende()); danach lässt sich die Antwort weiterlesen.
  • Der Zerstörer liest zu Ende, nimmt die Transaktion zurück und schliesst.

Was fehlt

  • Vorbereitete Anweisungen (sp_prepare-Kennung behalten), MARS, Tabellenwertparameter, Always Encrypted.
  • Integrierte Anmeldung und Entra ID, eine asynchrone Schnittstelle (Koroutinen), ein Pool.
  • Eigene C++-Typen für ARRAY, ROW, MULTISET und INTERVAL.
  • Windows (MSVC, SChannel) nicht gebaut; Verteilung nur vorbereitet (kein Register, kein Conan-Remote).
RestzeileBeschreibungStand
D36.6a Rest aus D36.6**Teilweise erledigt 21.10.2026:** `ksql::anweisung` (vorbereitet: erster Lauf `sp_prepexec`, dann `sp_execute` mit der behaltenen Kennung, `sp_unprepare` im Zerstörer oder mit der nächsten Anfrage; nach Namen aufgerufen, denn über die Kennung nimmt SQL Server bei `sp_execute` keine benannten Parameter an, 4002), die KSQL-Typen als eigene C++-Typen `intervall`, `sammlung` (ARRAY, MULTISET) und `zeilenwert` (ROW) zum Lesen und als Parameter (Textformen wie der Java-Treiber, Tiefe und Länge gedeckelt), `ksql::pool` für mehrere Fäden. Tests ohne Server 115, mit Server am KSQL-Port 136 und am Orakel 128 Prüfungen, je ohne Fehlschlag, auf dem Mac und im Container (dort als Bauschritt); Katalog im Container am KSQL-Port 82 ok, 0 abweichend, 0 Befunde, am Orakel 72 ok, 10 übersprungen. Gegenprobe: ohne das Abfangen der Kennung vier Fehlschläge. **Offen:** (1) Windows (MSVC, SChannel); macOS nur von Hand übersetzt (lokal fehlt CMake). (2) Kein .NET-Test wie `JavaTreiberTests`. (3) MARS, Tabellenwertparameter, Always Encrypted, integrierte Anmeldung und Entra ID, eine asynchrone Schnittstelle (Koroutinen); der Pool setzt den Sitzungszustand nicht zurück (kein RESETCONNECTION). (4) Verteilung nur vorbereitet; die Fassung in `vcpkg.json` ist von Hand nachzuführen. **Erledigt 21.10.2026:** (2) `TreiberPruefstandTests` (Bauschritt, `KUONENSQL_DOCKER_ABNAHME=1`) baut den Prüfstand `cpp/` (g++ 12 in `debian:bookworm-slim`, Tests mit Sanitizern, `find_package`-Probe, Abspieler) und spielt den Katalog am KSQL-Port und am Orakel ab - 2 von 2 grün. Der erste Lauf auf x64 fand einen Fehler, den clang auf dem Mac verdeckte: `sammlung::von` rief `elementtyp_aus(…, texte)` und `std::move(texte)` in derselben Argumentliste; g++ wertet von rechts aus, die Texte waren schon weg und eine Sammlung aus `dezimal` wurde `decimal(1,0)` statt `decimal(4,2)` (Prüfung „von dezimal“ rot). Jetzt wird der Typ vorher berechnet. Rest in D36.6g.✅
D36.6e Rest aus D36.6d(1) `sp_executesql` prüft die Werte nicht: SQL Server meldet 8178 (RETURNSTATUS 1) bzw. 8144 auch dort, KuonenSQL setzt NULL bzw. meldet 137; ebenso fehlen dort 352 und 102 für die Parameterliste. (2) Am Orakel hängt das Ergebnis eines fehlenden Werts am Plan-Cache: ist die Anweisung noch nicht übersetzt, kommt 8178 mit 8180 und RETURNSTATUS 8180 statt RETURNSTATUS 1 (einmal beobachtet) - KuonenSQL antwortet immer wie mit Plan. (3) Der RETURNSTATUS von `EXEC sp_prepare` im Stapel ist am Orakel der Status des vorigen Aufrufs auf der Verbindung (z. B. 8178 nach einem gescheiterten sp_prepexec); KuonenSQL schickt 0. (4) Ein Übersetzungsfehler einer Datenänderung (`INSERT` in eine fehlende Tabelle) bei `sp_prepare` ist nicht gemessen; KuonenSQL beschreibt sie ohne Prüfung. **Erledigt 21.10.2026** (am Orakel gemessen, SqlClient 6.1.6 mit Mitschnitt): (1) `sp_executesql` prüft über RPC und im Stapel die Parameterliste (352, 102) und die Werte (8178, 8144), dazu Werte ohne Liste (214 Zustand 3) und mit leerer Liste (8146, RETURNSTATUS 1); der Aufruf endet, der Stapel läuft weiter, `EXEC @r = …` trägt den Status. (2) Gemessen ist die Regel: der Status hängt daran, ob dieselbe Anweisung mit derselben Parameterliste schon übersetzt ist (aus `sp_executesql`, `sp_prepexec` oder `sp_prepare`, über Verbindungen hinweg) - dann 8178 mit RETURNSTATUS 1 und 8144 als Fehler der EXEC-Anweisung (curCmd 0x00FD, ohne Status, bricht den Stapel ab), sonst bei `sp_executesql` RETURNSTATUS gleich Fehlernummer, bei `sp_prepexec` 8180 samt Meldung 8180. KuonenSQL führt dafür je Datenbank einen gedeckelten `Planbestand`. (3) Der RETURNSTATUS von `sp_prepare` (RPC und Stapel) ist `@@ERROR` vor dem Aufruf, und `@@ERROR` gilt über das Ende eines Stapels hinaus (auch das war bei KuonenSQL anders); ein DECLARE ohne Wert und `sp_prepare` lassen es stehen, `sp_unprepare` und SET setzen es auf 0. (4) INSERT, UPDATE und DELETE an einer fehlenden Tabelle: 208, 8180, RETURNSTATUS 8180, Griff NULL. Tests `AusfuehrungsWerteTests` (37, vorher 35 rot), angepasst `VorbereiteteAnweisungenResteTests` (frische Anweisungen jetzt mit 8180). Rest in D36.6f.✅
D36.6f Rest aus D36.6e(1) Am Orakel meldet `sp_prepare` für `INSERT sys.objects …` 259 („Ad hoc updates to system catalogs are not allowed.“) mit 8180; KuonenSQL kennt 259 nicht. (2) Nicht gemessen: ob `sp_reset_connection` `@@ERROR` zurücksetzt (KuonenSQL behält es), ob der Plan-Cache des Orakels auch nach den SET-Optionen unterscheidet (der `Planbestand` nur nach Datenbank, Liste und Text) und was `sp_prepare` bei MERGE, `UPDATE … FROM` und Zielen in einer anderen Datenbank prüft (KuonenSQL prüft dort nichts vor). (3) Ob ein DECLARE mit Wert oder ein DECLARE einer Tabellenvariablen `@@ERROR` stehen lässt, ist nicht gemessen (KuonenSQL setzt es auf 0).⬜
D36.6g Rest aus D36.6a(1) Windows (MSVC, SChannel); macOS nur von Hand übersetzt (lokal fehlt CMake). (2) MARS, Tabellenwertparameter, Always Encrypted, integrierte Anmeldung und Entra ID, eine asynchrone Schnittstelle (Koroutinen); der Pool setzt den Sitzungszustand nicht zurück (kein RESETCONNECTION). (3) Verteilung nur vorbereitet; die Fassung in `vcpkg.json` ist von Hand nachzuführen.⬜

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.

Eigener Code ohne fremde Quellen; TLS kommt wie im Kern aus der Bibliothek des Systems. vcpkg und Conan vorbereitet, nicht veröffentlicht.