ADBC-Client
Installation Um den DuckDB-ADBC-Client zu verwenden, laden Sie das
libduckdb-Archiv für Ihre Plattform herunter und folgen Sie den Anweisungen unten.Die aktuelle stabile Version des DuckDB-ADBC-Clients ist 1.5.5.
Arrow Database Connectivity (ADBC) ist ähnlich wie ODBC und JDBC eine C-ähnliche API, die Code-Portabilität zwischen verschiedenen Datenbanksystemen ermöglicht. So können Entwickler Anwendungen bauen, die mit Datenbanksystemen kommunizieren, ohne systemspezifischen Code zu verwenden. Der wesentliche Unterschied zwischen ADBC und ODBC/JDBC ist, dass ADBC Arrow verwendet, um Daten zwischen dem Datenbanksystem und der Anwendung zu übertragen. DuckDB hat einen ADBC-Treiber, der die Zero-Copy-Integration zwischen DuckDB und Arrow nutzt, um Daten effizient zu übertragen.
Bitte lesen Sie die ADBC-Dokumentationsseite für eine ausführlichere Diskussion zu ADBC und eine detaillierte API-Erklärung.
Implementierte Funktionalität
Der DuckDB-ADBC-Treiber implementiert die vollständige ADBC-Spezifikation, mit Ausnahme der Funktionen ConnectionReadPartition und StatementExecutePartitions. Beide Funktionen existieren zur Unterstützung von Systemen, die intern die Abfrageergebnisse partitionieren, was auf DuckDB nicht zutrifft.
In diesem Abschnitt beschreiben wir die wichtigsten Funktionen, die in ADBC existieren, zusammen mit den Argumenten, die sie entgegennehmen, und geben Beispiele für jede Funktion.
Database
Satz von Funktionen, die auf einer Datenbank operieren.
| Funktionsname | Beschreibung | Argumente | Beispiel |
|---|---|---|---|
DatabaseNew |
Allokiert eine neue (aber nicht initialisierte) Datenbank. | (AdbcDatabase *database, AdbcError *error) |
AdbcDatabaseNew(&adbc_database, &adbc_error) |
DatabaseSetOption |
Setzt eine char*-Option. | (AdbcDatabase *database, const char *key, const char *value, AdbcError *error) |
AdbcDatabaseSetOption(&adbc_database, "path", "test.db", &adbc_error) |
DatabaseInit |
Schließt das Setzen von Optionen ab und initialisiert die Datenbank. | (AdbcDatabase *database, AdbcError *error) |
AdbcDatabaseInit(&adbc_database, &adbc_error) |
DatabaseRelease |
Zerstört die Datenbank. | (AdbcDatabase *database, AdbcError *error) |
AdbcDatabaseRelease(&adbc_database, &adbc_error) |
Database-Optionen
| Option | Beschreibung |
|---|---|
driver |
Pfad zur DuckDB-Shared-Library (libduckdb.so, libduckdb.dylib oder duckdb.dll). |
entrypoint |
Name der Einstiegsfunktion. Muss duckdb_adbc_init sein. |
path |
Pfad zu einer DuckDB-Datenbankdatei. Wenn nicht gesetzt, wird eine In-Memory-Datenbank erzeugt. |
uri |
Alternative zu path. Akzeptiert einfache Pfade oder file:-URIs (z. B. file:test.db, file:///absolute/path.db). Hat Vorrang vor path, wenn beide gesetzt sind. |
Connection
Ein Satz von Funktionen, die eine Verbindung zum Interagieren mit einer Datenbank erzeugen und zerstören.
| Funktionsname | Beschreibung | Argumente | Beispiel |
|---|---|---|---|
ConnectionNew |
Allokiert eine neue (aber nicht initialisierte) Verbindung. | (AdbcConnection*, AdbcError*) |
AdbcConnectionNew(&adbc_connection, &adbc_error) |
ConnectionSetOption |
Optionen können vor ConnectionInit gesetzt werden. | (AdbcConnection*, const char*, const char*, AdbcError*) |
AdbcConnectionSetOption(&adbc_connection, ADBC_CONNECTION_OPTION_AUTOCOMMIT, ADBC_OPTION_VALUE_DISABLED, &adbc_error) |
ConnectionInit |
Schließt das Setzen von Optionen ab und initialisiert die Verbindung. | (AdbcConnection*, AdbcDatabase*, AdbcError*) |
AdbcConnectionInit(&adbc_connection, &adbc_database, &adbc_error) |
ConnectionRelease |
Zerstört diese Verbindung. | (AdbcConnection*, AdbcError*) |
AdbcConnectionRelease(&adbc_connection, &adbc_error) |
Ein Satz von Funktionen, die Metadaten über die Datenbank abrufen. Im Allgemeinen geben diese Funktionen Arrow-Objekte zurück, insbesondere einen ArrowArrayStream.
| Funktionsname | Beschreibung | Argumente | Beispiel |
|---|---|---|---|
ConnectionGetInfo |
Holt Metadaten über Treiber und Datenbank. | (AdbcConnection*, const uint32_t*, size_t, ArrowArrayStream*, AdbcError*) |
AdbcConnectionGetInfo(&adbc_connection, NULL, 0, &arrow_stream, &adbc_error) |
ConnectionGetObjects |
Holt eine hierarchische Ansicht aller Kataloge, Datenbankschemas, Tabellen und Spalten. | (AdbcConnection*, int, const char*, const char*, const char*, const char**, const char*, ArrowArrayStream*, AdbcError*) |
AdbcDatabaseInit(&adbc_database, &adbc_error) |
ConnectionGetTableSchema |
Holt das Arrow-Schema einer Tabelle. | (AdbcConnection*, const char*, const char*, const char*, ArrowSchema*, AdbcError*) |
AdbcDatabaseRelease(&adbc_database, &adbc_error) |
ConnectionGetTableTypes |
Holt eine Liste der Tabellentypen in der Datenbank. | (AdbcConnection*, ArrowArrayStream*, AdbcError*) |
AdbcDatabaseNew(&adbc_database, &adbc_error) |
Die Funktion ConnectionGetInfo unterstützt die folgenden Info-Codes:
| Info-Code | Konstante | Beschreibung |
|---|---|---|
| 0 | ADBC_INFO_VENDOR_NAME |
Name des Datenbankanbieters (duckdb). |
| 1 | ADBC_INFO_VENDOR_VERSION |
Datenbankversion. |
| 100 | ADBC_INFO_DRIVER_NAME |
Treibername. |
| 101 | ADBC_INFO_DRIVER_VERSION |
Treiberversion. |
| 102 | ADBC_INFO_DRIVER_ARROW_VERSION |
Version der Arrow-Bibliothek. |
| 103 | ADBC_INFO_DRIVER_ADBC_VERSION |
Von dem Treiber unterstützte ADBC-Spezifikationsversion (als Ganzzahl, z. B. 1001000 für 1.1.0). |
Ein Satz von Funktionen mit Transaktionssemantik für die Verbindung. Standardmäßig starten alle Verbindungen mit aktiviertem Auto-Commit-Modus, dies kann jedoch über die Funktion ConnectionSetOption deaktiviert werden.
| Funktionsname | Beschreibung | Argumente | Beispiel |
|---|---|---|---|
ConnectionCommit |
Commitet ausstehende Transaktionen. | (AdbcConnection*, AdbcError*) |
AdbcConnectionCommit(&adbc_connection, &adbc_error) |
ConnectionRollback |
Führt einen Rollback ausstehender Transaktionen durch. | (AdbcConnection*, AdbcError*) |
AdbcConnectionRollback(&adbc_connection, &adbc_error) |
Statement
Statements halten den Zustand zur Abfrageausführung. Sie repräsentieren sowohl einmalige Abfragen als auch Prepared Statements. Sie können wiederverwendet werden; dabei werden jedoch vorherige Resultsets dieses Statements ungültig.
Die Funktionen zum Erzeugen, Zerstören und Setzen von Optionen für ein Statement:
| Funktionsname | Beschreibung | Argumente | Beispiel |
|---|---|---|---|
StatementNew |
Erzeugt ein neues Statement für eine gegebene Verbindung. | (AdbcConnection*, AdbcStatement*, AdbcError*) |
AdbcStatementNew(&adbc_connection, &adbc_statement, &adbc_error) |
StatementRelease |
Zerstört ein Statement. | (AdbcStatement*, AdbcError*) |
AdbcStatementRelease(&adbc_statement, &adbc_error) |
StatementSetOption |
Setzt eine String-Option an einem Statement. | (AdbcStatement*, const char*, const char*, AdbcError*) |
StatementSetOption(&adbc_statement, ADBC_INGEST_OPTION_TARGET_TABLE, "TABLE_NAME", &adbc_error) |
Funktionen zur Abfrageausführung:
| Funktionsname | Beschreibung | Argumente | Beispiel |
|---|---|---|---|
StatementSetSqlQuery |
Setzt die auszuführende SQL-Abfrage. Die Abfrage kann dann mit StatementExecuteQuery ausgeführt werden. | (AdbcStatement*, const char*, AdbcError*) |
AdbcStatementSetSqlQuery(&adbc_statement, "SELECT * FROM TABLE", &adbc_error) |
StatementSetSubstraitPlan |
Setzt einen Substrait-Plan zur Ausführung. Die Abfrage kann dann mit StatementExecuteQuery ausgeführt werden. | (AdbcStatement*, const uint8_t*, size_t, AdbcError*) |
AdbcStatementSetSubstraitPlan(&adbc_statement, substrait_plan, length, &adbc_error) |
StatementExecuteQuery |
Führt ein Statement aus und holt die Ergebnisse. | (AdbcStatement*, ArrowArrayStream*, int64_t*, AdbcError*) |
AdbcStatementExecuteQuery(&adbc_statement, &arrow_stream, &rows_affected, &adbc_error) |
StatementPrepare |
Wandelt dieses Statement in ein Prepared Statement um, das mehrfach ausgeführt werden kann. | (AdbcStatement*, AdbcError*) |
AdbcStatementPrepare(&adbc_statement, &adbc_error) |
Funktionen zum Binden, verwendet für Bulk-Einfügungen oder in Prepared Statements.
| Funktionsname | Beschreibung | Argumente | Beispiel |
|---|---|---|---|
StatementBindStream |
Bindet einen Arrow Stream. Dies kann für Bulk-Inserts oder Prepared Statements verwendet werden. | (AdbcStatement*, ArrowArrayStream*, AdbcError*) |
StatementBindStream(&adbc_statement, &input_data, &adbc_error) |
Ingestionsmodi
Beim Ingestieren von Daten über StatementBindStream kann der Ingestionsmodus mit ADBC_INGEST_OPTION_MODE gesetzt werden:
| Modus | Konstante | Beschreibung |
|---|---|---|
| Create | ADBC_INGEST_OPTION_MODE_CREATE |
Erzeugt eine neue Tabelle (Fehler, wenn die Tabelle bereits existiert). Dies ist der Standard. |
| Append | ADBC_INGEST_OPTION_MODE_APPEND |
Hängt an eine vorhandene Tabelle an (Fehler, wenn die Tabelle nicht existiert). |
| Replace | ADBC_INGEST_OPTION_MODE_REPLACE |
Löscht die vorhandene Tabelle und erzeugt eine neue. |
| Create or Append | ADBC_INGEST_OPTION_MODE_CREATE_APPEND |
Erzeugt eine neue Tabelle, wenn sie nicht existiert, andernfalls hängt an sie an. |
StatementExecuteQuery gibt die Anzahl der betroffenen Zeilen über den Ausgabeparameter rows_affected zurück.
Ingestionsoptionen
| Option | Beschreibung |
|---|---|
adbc.ingest.target_table |
Der Zieltabellenname für die Ingestion. |
adbc.ingest.target_catalog |
Der Zielkatalog (angehängte Datenbank) für die Ingestion. Wenn ohne adbc.ingest.target_db_schema gesetzt, ist das Schema standardmäßig main. |
adbc.ingest.target_db_schema |
Das Zielschema für die Ingestion. |
adbc.ingest.temporary |
Auf enabled setzen, um eine temporäre Tabelle zu erzeugen. Inkompatibel mit target_catalog und target_db_schema. |
Einrichten des DuckDB-ADBC-Treibers
Bevor Sie DuckDB als ADBC-Treiber verwenden, müssen Sie die Shared Library libduckdb auf Ihrem System installieren und Ihrer Anwendung zur Verfügung stellen. Diese Bibliothek enthält die DuckDB-Kern-Engine, mit der der ADBC-Treiber kommuniziert.
libduckdb herunterladen
Laden Sie die passende libduckdb-Bibliothek für Ihre Plattform von der DuckDB-Releases-Seite herunter:
- Linux:
libduckdb-linux-amd64.zip(enthältlibduckdb.so) - macOS:
libduckdb-osx-universal.zip(enthältlibduckdb.dylib) - Windows:
libduckdb-windows-amd64.zip(enthältduckdb.dll)
Entpacken Sie das Archiv, um die Shared-Library-Datei zu erhalten.
Installieren der Bibliothek
Linux
-
Extrahieren Sie die Datei
libduckdb.soaus dem heruntergeladenen Archiv -
Stellen Sie sicher, dass Ihr Code die Bibliothek verwenden kann. Sie können:
-
Entweder in ein System-Bibliotheksverzeichnis kopieren (erfordert Root-Zugriff):
Terminal window sudo cp libduckdb.so /usr/local/lib/sudo ldconfig -
Oder in ein eigenes Verzeichnis legen und dieses Verzeichnis zu Ihrem
LD_LIBRARY_PATHhinzufügen:Terminal window mkdir -p ~/libcp libduckdb.so ~/lib/export LD_LIBRARY_PATH=~/lib:$LD_LIBRARY_PATH
-
macOS
-
Extrahieren Sie die Datei
libduckdb.dylibaus dem heruntergeladenen Archiv -
Stellen Sie sicher, dass Ihr Code die Bibliothek verwenden kann. Sie können:
-
Entweder in ein System-Bibliotheksverzeichnis kopieren:
Terminal window sudo cp libduckdb.dylib /usr/local/lib/ -
Oder in ein eigenes Verzeichnis legen und dieses Verzeichnis zu Ihrem
DYLD_LIBRARY_PATHhinzufügen:Terminal window mkdir -p ~/libcp libduckdb.dylib ~/lib/export DYLD_LIBRARY_PATH=~/lib:$DYLD_LIBRARY_PATH
-
Windows
- Extrahieren Sie die Datei
duckdb.dllaus dem heruntergeladenen Archiv - Legen Sie sie an einem der folgenden Orte ab:
- Im selben Verzeichnis wie Ihre Anwendungs-Executable
- In einem Verzeichnis, das in Ihrer Umgebungsvariable
PATHaufgeführt ist - Im Windows-Systemverzeichnis (z. B.
C:\Windows\System32)
Bibliothekspfade verstehen
LD_LIBRARY_PATH (Linux) und DYLD_LIBRARY_PATH (macOS) sind Umgebungsvariablen, die dem System mitteilen, wo zur Laufzeit nach Shared Libraries gesucht werden soll. Wenn Ihre Anwendung versucht, libduckdb zu laden, durchsucht das System diese Pfade, um die Bibliotheksdatei zu finden.
Installation überprüfen
Sie können überprüfen, dass die Bibliothek korrekt installiert und zugänglich ist:
Linux/macOS:
ldd path/to/your/application # Linuxotool -L path/to/your/application # macOSBeispiele
Unabhängig von der verwendeten Programmiersprache gibt es zwei Datenbankoptionen, die erforderlich sind, um ADBC mit DuckDB zu nutzen. Die erste ist driver, die einen Pfad zur DuckDB-Bibliothek entgegennimmt (siehe Einrichten des DuckDB-ADBC-Treibers oben für Installationsanweisungen). Die zweite Option ist entrypoint, eine exportierte Funktion des DuckDB-ADBC-Treibers, die alle ADBC-Funktionen initialisiert. Sobald wir diese beiden Optionen konfiguriert haben, können wir optional die Option path setzen und einen Pfad auf der Festplatte angeben, um unsere DuckDB-Datenbank zu speichern. Wenn nicht gesetzt, wird eine In-Memory-Datenbank erzeugt. Nach dem Konfigurieren aller notwendigen Optionen können wir mit der Initialisierung unserer Datenbank fortfahren. Unten sehen Sie, wie Sie das in verschiedenen Sprachumgebungen tun.
C++
Wir beginnen unser C++-Beispiel mit der Deklaration der wesentlichen Variablen zum Abfragen von Daten über ADBC. Diese Variablen umfassen Error, Database, Connection, Statement-Handling und einen Arrow Stream, um Daten zwischen DuckDB und der Anwendung zu übertragen.
AdbcError adbc_error;AdbcDatabase adbc_database;AdbcConnection adbc_connection;AdbcStatement adbc_statement;ArrowArrayStream arrow_stream;Anschließend können wir unsere Datenbankvariable initialisieren. Vor der Initialisierung der Datenbank müssen wir die Optionen driver und entrypoint wie oben erwähnt setzen. Dann setzen wir die Option path und initialisieren die Datenbank. Die Option driver sollte auf Ihre installierte libduckdb-Bibliothek zeigen – siehe Einrichten des DuckDB-ADBC-Treibers für Installationsanweisungen.
AdbcDatabaseNew(&adbc_database, &adbc_error);AdbcDatabaseSetOption(&adbc_database, "driver", "path/to/libduckdb.dylib", &adbc_error);AdbcDatabaseSetOption(&adbc_database, "entrypoint", "duckdb_adbc_init", &adbc_error);// By default, we start an in-memory database, but you can optionally define a path to store it on disk.AdbcDatabaseSetOption(&adbc_database, "path", "test.db", &adbc_error);AdbcDatabaseInit(&adbc_database, &adbc_error);Nach der Initialisierung der Datenbank müssen wir eine Verbindung dazu erzeugen und initialisieren.
AdbcConnectionNew(&adbc_connection, &adbc_error);AdbcConnectionInit(&adbc_connection, &adbc_database, &adbc_error);Nun können wir unser Statement initialisieren und Abfragen über unsere Verbindung ausführen. Nach AdbcStatementExecuteQuery ist arrow_stream mit dem Ergebnis gefüllt.
AdbcStatementNew(&adbc_connection, &adbc_statement, &adbc_error);AdbcStatementSetSqlQuery(&adbc_statement, "SELECT 42", &adbc_error);int64_t rows_affected;AdbcStatementExecuteQuery(&adbc_statement, &arrow_stream, &rows_affected, &adbc_error);arrow_stream.release(arrow_stream)Neben dem Ausführen von Abfragen können wir auch Daten über arrow_streams ingestieren. Dazu müssen wir eine Option mit dem Tabellennamen setzen, in den wir einfügen möchten, den Stream binden und dann die Abfrage ausführen.
StatementSetOption(&adbc_statement, ADBC_INGEST_OPTION_TARGET_TABLE, "AnswerToEverything", &adbc_error);StatementBindStream(&adbc_statement, &arrow_stream, &adbc_error);StatementExecuteQuery(&adbc_statement, nullptr, nullptr, &adbc_error);Python
Als Erstes sollten Sie mit pip den ADBC Driver Manager installieren. Sie müssen außerdem pyarrow installieren, um direkt auf im Apache-Arrow-Format vorliegende Resultsets zuzugreifen (z. B. mit fetch_arrow_table).
pip install adbc_driver_manager pyarrowDetails zum Paket
adbc_driver_managerfinden Sie in der Paketdokumentation zuadbc_driver_manager.
Wie bei C++ müssen wir Initialisierungsoptionen bereitstellen, bestehend aus dem Speicherort des libduckdb-Shared-Objects und der Einstiegsfunktion. Beachten Sie, dass das Argument path für DuckDB über das Dictionary db_kwargs übergeben wird.
import adbc_driver_duckdb.dbapi
with adbc_driver_duckdb.dbapi.connect("test.db") as conn, conn.cursor() as cur: cur.execute("SELECT 42") # fetch a pyarrow table tbl = cur.fetch_arrow_table() print(tbl)Neben fetch_arrow_table sind weitere Methoden aus DBApi am Cursor implementiert, etwa fetchone und fetchall. Daten können auch über arrow_streams ingestiert werden. Wir müssen nur Optionen am Statement setzen, um den Datenstream zu binden, und die Abfrage ausführen.
import adbc_driver_duckdb.dbapiimport pyarrow
data = pyarrow.record_batch( [[1, 2, 3, 4], ["a", "b", "c", "d"]], names = ["ints", "strs"],)
with adbc_driver_duckdb.dbapi.connect("test.db") as conn, conn.cursor() as cur: cur.adbc_ingest("AnswerToEverything", data)Go
Stellen Sie zuerst sicher, dass Sie die Bibliothek libduckdb installiert haben – siehe Einrichten des DuckDB-ADBC-Treibers für detaillierte Installationsanweisungen.
Das folgende Beispiel verwendet eine In-Memory-DuckDB-Datenbank, um In-Memory-Arrow-RecordBatches über SQL-Abfragen zu verändern:
package main
import ( "bytes" "context" "fmt" "io"
"github.com/apache/arrow-adbc/go/adbc" "github.com/apache/arrow-adbc/go/adbc/drivermgr" "github.com/apache/arrow-go/v18/arrow" "github.com/apache/arrow-go/v18/arrow/array" "github.com/apache/arrow-go/v18/arrow/ipc" "github.com/apache/arrow-go/v18/arrow/memory")
func _makeSampleArrowRecord() arrow.Record { b := array.NewFloat64Builder(memory.DefaultAllocator) b.AppendValues([]float64{1, 2, 3}, nil) col := b.NewArray()
defer col.Release() defer b.Release()
schema := arrow.NewSchema([]arrow.Field{{Name: "column1", Type: arrow.PrimitiveTypes.Float64}}, nil) return array.NewRecord(schema, []arrow.Array{col}, int64(col.Len()))}
type DuckDBSQLRunner struct { ctx context.Context conn adbc.Connection db adbc.Database}
func NewDuckDBSQLRunner(ctx context.Context) (*DuckDBSQLRunner, error) { var drv drivermgr.Driver db, err := drv.NewDatabase(map[string]string{ "driver": "duckdb", "entrypoint": "duckdb_adbc_init", "path": ":memory:", }) if err != nil { return nil, fmt.Errorf("failed to create new in-memory DuckDB database: %w", err) } conn, err := db.Open(ctx) if err != nil { return nil, fmt.Errorf("failed to open connection to new in-memory DuckDB database: %w", err) } return &DuckDBSQLRunner{ctx: ctx, conn: conn, db: db}, nil}
func serializeRecord(record arrow.Record) (io.Reader, error) { buf := new(bytes.Buffer) wr := ipc.NewWriter(buf, ipc.WithSchema(record.Schema())) if err := wr.Write(record); err != nil { return nil, fmt.Errorf("failed to write record: %w", err) } if err := wr.Close(); err != nil { return nil, fmt.Errorf("failed to close writer: %w", err) } return buf, nil}
func (r *DuckDBSQLRunner) importRecord(sr io.Reader) error { rdr, err := ipc.NewReader(sr) if err != nil { return fmt.Errorf("failed to create IPC reader: %w", err) } defer rdr.Release()
_, err = adbc.IngestStream(r.ctx, r.conn, rdr, "temp_table", adbc.OptionValueIngestModeCreate, adbc.IngestStreamOptions{})
return err}
func (r *DuckDBSQLRunner) runSQL(sql string) ([]arrow.Record, error) { stmt, err := r.conn.NewStatement() if err != nil { return nil, fmt.Errorf("failed to create new statement: %w", err) } defer stmt.Close()
if err := stmt.SetSqlQuery(sql); err != nil { return nil, fmt.Errorf("failed to set SQL query: %w", err) } out, n, err := stmt.ExecuteQuery(r.ctx) if err != nil { return nil, fmt.Errorf("failed to execute query: %w", err) } defer out.Release()
result := make([]arrow.Record, 0, n) for out.Next() { rec := out.Record() rec.Retain() // .Next() will release the record, so we need to retain it result = append(result, rec) } if out.Err() != nil { return nil, out.Err() } return result, nil}
func (r *DuckDBSQLRunner) RunSQLOnRecord(record arrow.Record, sql string) ([]arrow.Record, error) { serializedRecord, err := serializeRecord(record) if err != nil { return nil, fmt.Errorf("failed to serialize record: %w", err) } if err := r.importRecord(serializedRecord); err != nil { return nil, fmt.Errorf("failed to import record: %w", err) } result, err := r.runSQL(sql) if err != nil { return nil, fmt.Errorf("failed to run SQL: %w", err) }
if _, err := r.runSQL("DROP TABLE temp_table"); err != nil { return nil, fmt.Errorf("failed to drop temp table after running query: %w", err) } return result, nil}
func (r *DuckDBSQLRunner) Close() { r.conn.Close() r.db.Close()}
func main() { rec := _makeSampleArrowRecord() fmt.Println(rec)
runner, err := NewDuckDBSQLRunner(context.Background()) if err != nil { panic(err) } defer runner.Close()
resultRecords, err := runner.RunSQLOnRecord(rec, "SELECT column1+1 FROM temp_table") if err != nil { panic(err) }
for _, resultRecord := range resultRecords { fmt.Println(resultRecord) resultRecord.Release() }}Die Ausführung erzeugt die folgende Ausgabe:
record: schema: fields: 1 - column1: type=float64 rows: 3 col[0][column1]: [1 2 3]
record: schema: fields: 1 - (column1 + 1): type=float64, nullable rows: 3 col[0][(column1 + 1)]: [2 3 4]