fireboltgosdk

package module
v1.20.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 31, 2026 License: Apache-2.0 Imports: 35 Imported by: 5

README

Firebolt Go SDK

Nightly code check Code quality checks Integration tests Coverage

Connect to Firebolt using Go. The Firebolt Go driver is an implementation of database/sql/driver.

Installation
go get github.com/firebolt-db/firebolt-go-sdk
DSN (Data source name)
Cloud instance

All information for the connection should be specified using the DSN string. The firebolt dsn string has the following format:

firebolt://[/database]?account_name=account_name&client_id=client_id&client_secret=client_secret[&engine=engine]
  • client_id - client id of the service account.
  • client_secret - client secret of the service account.
  • account_name - the name of Firebolt account to log in to.
  • database - (optional) the name of the database to connect to.
  • engine - (optional) the name of the engine to run SQL on.
Core instance

For the core instance, the DSN string has the following format:

firebolt://[/database]?url=core_instance_url[&client_side_lb=false]
  • url - the URL of the core instance to connect to. It should contain the full URL, including schema. E.g. http://localhost:3473.
  • database - (optional) the name of the database to connect to.
  • client_side_lb - (optional, default true) enables client-side round-robin load balancing. The SDK resolves the hostname in url to its underlying IP addresses and distributes requests across them. This prevents Go's default connection pooling from pinning all requests to a single pod when url points to a Kubernetes service. Set to false to disable.
  • client_side_lb_dns_ttl - (optional, default 30s) how often the round-robin resolver re-resolves the hostname to discover new or removed nodes. Accepts any Go duration string (e.g. 5s, 500ms, 2m). Lower values give faster failover; higher values reduce DNS traffic. Only takes effect when client_side_lb is enabled.
Custom HTTP transport

The SDK ships with sensible HTTP transport defaults (30s dial timeout, 10s TLS handshake timeout, 30s keep-alive, 90s idle connection timeout). If you need to tune these -- for example, to increase the dial timeout for high-latency networks or the idle connection timeout for long-lived batch pipelines -- use OpenConnectorWithDSN together with WithTransport:

package main

import (
	"database/sql"
	"log"
	"net"
	"time"

	firebolt "github.com/firebolt-db/firebolt-go-sdk"
	"github.com/firebolt-db/firebolt-go-sdk/client"
)

func main() {
	// Start from the SDK defaults and override what you need.
	transport := client.DefaultTransport()
	transport.DialContext = (&net.Dialer{
		Timeout:   60 * time.Second,
		KeepAlive: 60 * time.Second,
	}).DialContext
	transport.TLSHandshakeTimeout = 20 * time.Second
	transport.IdleConnTimeout = 2 * time.Minute

	dsn := "firebolt:///mydb?url=http://firebolt:3473&client_side_lb_dns_ttl=5s"

	// OpenConnectorWithDSN parses the DSN and applies driver options.
	connector, err := firebolt.OpenConnectorWithDSN(dsn, firebolt.WithTransport(transport))
	if err != nil {
		log.Fatal(err)
	}

	// sql.OpenDB returns the same *sql.DB you get from sql.Open,
	// but with your custom transport in effect.
	db := sql.OpenDB(connector)
	defer db.Close()

	// Use db as usual ...
}

client.DefaultTransport() returns a new *http.Transport each time, so you can safely create different transports for different use cases. WithTransport accepts any http.RoundTripper, so you can also wrap the transport with middleware (e.g. otelhttp.NewTransport for OpenTelemetry tracing). When no custom transport is provided (i.e. when using sql.Open), the SDK uses its built-in defaults.

Querying example

Here is an example of establishing a connection and executing a simple select query. For it to run successfully, you have to specify your credentials, and have a default engine up and running.

package main

import (
	"database/sql"
	"fmt"
	"log"

	// we need to import firebolt-go-sdk in order to register the driver
	_ "github.com/firebolt-db/firebolt-go-sdk"
)

func main() {

	// set your Firebolt credentials to construct a dsn string
	clientId := ""
	clientSecret := ""
	accountName := ""
	databaseName := ""
	engineName := ""
	dsn := fmt.Sprintf("firebolt:///%s?account_name=%s&client_id=%s&client_secret=%s&engine=%s", databaseName, accountName, clientId, clientSecret, engineName)

	// open a Firebolt connection
	db, err := sql.Open("firebolt", dsn)
	if err != nil {
		log.Fatalf("error during opening a driver: %v", err)
	}

	// create a table
	_, err = db.Query("CREATE TABLE test_table(id INT, value TEXT)")
	if err != nil {
		log.Fatalf("error during select query: %v", err)
	}

	// execute a parametrized insert (only ? placeholders are supported)
	_, err = db.Query("INSERT INTO test_table VALUES (?, ?)", 1, "my value")
	if err != nil {
		log.Fatalf("error during select query: %v", err)
	}

	// execute a simple select query
	rows, err := db.Query("SELECT id FROM test_table")
	if err != nil {
		log.Fatalf("error during select query: %v", err)
	}

	// iterate over the result
	defer func() {
		if err := rows.Close(); err != nil {
			log.Printf("error during rows.Close(): %v\n", err)
		}
	}()

	for rows.Next() {
		var id int
		if err := rows.Scan(&id); err != nil {
			log.Fatalf("error during scan: %v", err)
		}
		log.Print(id)
	}

	if err := rows.Err(); err != nil {
		log.Fatalf("error during rows iteration: %v\n", err)
	}
}
Streaming example

In order to stream the query result (and not store it in memory fully), you need to pass a special context with streaming enabled.

Warning: If you enable streaming the result, the query execution might finish successfully, but the actual error might be returned during the iteration over the rows.

Here is an example of how to do it:

package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"

	// we need to import firebolt-go-sdk in order to register the driver
	_ "github.com/firebolt-db/firebolt-go-sdk"
	fireboltContext "github.com/firebolt-db/firebolt-go-sdk/context"
)

func main() {
	// set your Firebolt credentials to construct a dsn string
	clientId := ""
	clientSecret := ""
	accountName := ""
	databaseName := ""
	engineName := ""
	dsn := fmt.Sprintf("firebolt:///%s?account_name=%s&client_id=%s&client_secret=%s&engine=%s", databaseName, accountName, clientId, clientSecret, engineName)

	// open a Firebolt connection
	db, err := sql.Open("firebolt", dsn)
	if err != nil {
		log.Fatalf("error during opening a driver: %v", err)
	}

	// create a streaming context
	streamingCtx := fireboltContext.WithStreaming(context.Background())

	// execute a large select query
	rows, err := db.QueryContext(streamingCtx, "SELECT 'abc' FROM generate_series(1, 100000000)")
	if err != nil {
		log.Fatalf("error during select query: %v", err)
	}

	// iterating over the result is exactly the same as in the previous example
	defer func() {
		if err := rows.Close(); err != nil {
			log.Printf("error during rows.Close(): %v\n", err)
		}
	}()

	for rows.Next() {
		var data string
		if err := rows.Scan(&data); err != nil {
			log.Fatalf("error during scan: %v", err)
		}
		log.Print(data)
	}

	if err := rows.Err(); err != nil {
		log.Fatalf("error during rows iteration: %v\n", err)
	}
}
Errors in streaming

If you enable streaming the result, the query execution might finish successfully, but the actual error might be returned during the iteration over the rows.

Prepared statements

The SDK supports two types of prepared statements:

  1. Native - client-side prepared statements. Uses ? as a placeholder for parameters.
  2. FBNumeric - server-side prepared statements. Uses $i as a placeholder for parameters.

You can manually create a prepared statement using the Prepare method of the sql.DB object. You can also use the Exec method of the sql.DB object to execute a prepared statement directly without creating it first.

Example of client-side prepared statements
package main
import (
    "database/sql"
    "fmt"
    "log"

    // we need to import firebolt-go-sdk in order to register the driver
    _ "github.com/firebolt-db/firebolt-go-sdk"
)
func main() {
    // set your Firebolt credentials to construct a dsn string
    clientId := ""
    clientSecret := ""
    accountName := ""
    databaseName := ""
    engineName := ""
    dsn := fmt.Sprintf("firebolt:///%s?account_name=%s&client_id=%s&client_secret=%s&engine=%s", databaseName, accountName, clientId, clientSecret, engineName)

	// open a Firebolt connection
	db, err := sql.Open("firebolt", dsn)
	if err != nil {
		log.Fatalf("error during opening a driver: %v", err)
	}
	defer db.Close()
	log.Printf("successfully opened a driver with dsn: %s", dsn)

	// Initially created client-side prepared statement
	nativeStmt, err := db.Prepare("INSERT INTO test_table VALUES (?, ?)")
	if err != nil {
		log.Fatalf("error preparing native statement: %v", err)
	}
	defer nativeStmt.Close()
	log.Printf("successfully prepared a native statement")

	_, err = nativeStmt.Exec(1, "value")
	if err != nil {
		log.Fatalf("error executing native prepared statement: %v", err)
	}
	log.Printf("successfully executed native prepared statement with args: 1, \"value\"")

	// Executing the same statement directly using Exec
	_, err = db.Exec("INSERT INTO test_table VALUES (?, ?)", 2, "another value")
	if err != nil {
		log.Fatalf("error executing native prepared statement directly: %v", err)
	}
	log.Printf("successfully executed native prepared statement directly with args: 2, \"another_value\"")
}
Example of server-side prepared statements
package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"

	// we need to import firebolt-go-sdk in order to register the driver
	_ "github.com/firebolt-db/firebolt-go-sdk"
	fireboltContext "github.com/firebolt-db/firebolt-go-sdk/context"
)

func main() {
	// set your Firebolt credentials to construct a dsn string
	clientId := ""
	clientSecret := ""
	accountName := ""
	databaseName := ""
	engineName := ""
	dsn := fmt.Sprintf("firebolt:///%s?account_name=%s&client_id=%s&client_secret=%s&engine=%s", databaseName, accountName, clientId, clientSecret, engineName)

	// open a Firebolt connection
	db, err := sql.Open("firebolt", dsn)
	if err != nil {
		log.Fatalf("error during opening a driver: %v", err)
	}
	defer db.Close()
	log.Printf("successfully opened a driver with dsn: %s", dsn)

	// We need to specify the prepared statement style in the context. Native is used by default.
	serverSideCtx := fireboltContext.WithPreparedStatementsStyle(context.Background(), fireboltContext.PreparedStatementsStyleFbNumeric)

	// Initially created server-side prepared statement
	fbnumericStmt, err := db.PrepareContext(serverSideCtx, "INSERT INTO test_table VALUES ($1, $2)")
	if err != nil {
		log.Fatalf("error preparing FBNumeric statement: %v", err)
	}
	defer fbnumericStmt.Close()
	log.Printf("successfully prepared a native statement")

	_, err = fbnumericStmt.Exec(1, "value")
	if err != nil {
		log.Fatalf("error executing FBNumeric prepared statement: %v", err)
	}
	log.Printf("successfully executed native prepared statement with args: 1, \"value\"")

	// Executing the same statement directly using Exec
	_, err = db.ExecContext(serverSideCtx, "INSERT INTO test_table VALUES ($1, $2)", 2, "another value")
	if err != nil {
		log.Fatalf("error executing FBNumeric prepared statement directly: %v", err)
	}
	log.Printf("successfully executed native prepared statement directly with args: 2, \"another_value\"")
}
Server-side asynchronous execution

The SDK supports server-side asynchronous execution of queries. This allows you to execute long-running queries on the background and retrieve the results later.

Note: the asynchronous execution does not support returning query results. It is useful for long-running queries that do not require immediate results, such as data loading or transformation tasks.

Here is an example of how to use server-side asynchronous execution:

package main

import (
    "context"
    "database/sql"
    "fmt"
    "log"

    firebolt "github.com/firebolt-db/firebolt-go-sdk"
)

func main() {
    // set your Firebolt credentials to construct a dsn string
    clientId := ""
    clientSecret := ""
    accountName := ""
    databaseName := ""
    engineName := ""
    dsn := fmt.Sprintf("firebolt:///%s?account_name=%s&client_id=%s&client_secret=%s&engine=%s", databaseName, accountName, clientId, clientSecret, engineName)

    // open a Firebolt connection
    db, err := sql.Open("firebolt", dsn)
    if err != nil {
        log.Fatalf("error during opening a driver: %v", err)
    }
    defer db.Close()
    log.Printf("successfully opened a driver with dsn: %s", dsn)


    token, err := firebolt.ExecAsync(db, "INSERT INTO test_table VALUES (?, ?)", 1, "async value")
    if err != nil {
        log.Fatalf("error executing asynchronous query: %v", err)
    }

	log.Print("started asynchronous query execution")

	for {
		running, err := firebolt.IsAsyncQueryRunning(db, token)
		if err != nil {
			log.Fatalf("Failed to check async query status: %v", err)
		}
		if !running {
			break
		}
    }

	success, err := firebolt.IsAsyncQuerySuccessful(db, token)
	if err != nil {
		log.Fatalf("Failed to check async query success: %v", err)
	}
	if success {
		log.Println("asynchronous query executed successfully")
	} else {
        log.Println("asynchronous query failed")
    }
}
Transaction support

The SDK supports transactions using the sql.Tx interface. Firebolt uses snapshot isolation for DML (INSERT, UPDATE, DELETE) statements and strict serializability for DDL (CREATE, ALTER, DROP) statements. Here is an example of how to use transactions:

package main

import (
    "context"
    "database/sql"
    "fmt"
    "log"

    firebolt "github.com/firebolt-db/firebolt-go-sdk"
)

func main() {
	// set your Firebolt credentials to construct a dsn string
	clientId := ""
	clientSecret := ""
	accountName := ""
	databaseName := ""
	engineName := ""
	dsn := fmt.Sprintf("firebolt:///%s?account_name=%s&client_id=%s&client_secret=%s&engine=%s", databaseName, accountName, clientId, clientSecret, engineName)

	// open a Firebolt connection
	db, err := sql.Open("firebolt", dsn)
	if err != nil {
		log.Fatalf("error during opening a driver: %v", err)
	}
	defer db.Close()
	log.Printf("successfully opened a driver with dsn: %s", dsn)

	// Start a transaction
	tx, err := db.Begin()
	if err != nil {
        log.Fatalf("error starting transaction: %v", err)
    }

	// Execute a sql query within the transaction
	_, err = tx.ExecContext(context.Background(), "INSERT INTO test_table VALUES (?, ?)", 1, "value")

	// Rollback the transaction if there was an error
	if err != nil {
        log.Printf("error executing query within transaction: %v", err)
        if rollbackErr := tx.Rollback(); rollbackErr != nil {
            log.Fatalf("error rolling back transaction: %v", rollbackErr)
        }
        return
    }

	// Commit the transaction if everything was successful
	if err = tx.Commit(); err != nil {
        log.Fatalf("error committing transaction: %v", err)
    } else {
        log.Println("transaction committed successfully")
    }
}
Batch insert

The SDK supports high-performance batch insertion. Data is buffered client-side, serialised to Parquet, and uploaded via multipart form POST when Send() is called. Two modes are available and can be mixed freely.

Access the batch API by unwrapping the raw driver connection via (*sql.Conn).Raw:

Row-wise insertion

Append one row at a time — convenient when iterating over records:

package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"

	firebolt "github.com/firebolt-db/firebolt-go-sdk"
)

func main() {
	dsn := "firebolt:///mydb?account_name=acct&client_id=id&client_secret=secret&engine=eng"
	db, err := sql.Open("firebolt", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	ctx := context.Background()
	conn, err := db.Conn(ctx)
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	err = conn.Raw(func(driverConn interface{}) error {
		batch, err := driverConn.(firebolt.BatchConnection).PrepareBatch(
			ctx, "INSERT INTO events (id, name, active)")
		if err != nil {
			return err
		}

		// Append one row at a time
		for i := int32(0); i < 1000; i++ {
			if err := batch.Append(i, fmt.Sprintf("event_%d", i), true); err != nil {
				return err
			}
		}

		return batch.Send(ctx)
	})
	if err != nil {
		log.Fatalf("batch insert failed: %v", err)
	}
}
Columnar insertion

Append entire typed slices per column — ideal when data is already in columnar layout:

err = conn.Raw(func(driverConn interface{}) error {
    batch, err := driverConn.(firebolt.BatchConnection).PrepareBatch(
        ctx, "INSERT INTO events (id, name, active)")
    if err != nil {
        return err
    }

    // Append whole columns at once
    if err := batch.Column(0).Append([]int32{1, 2, 3}); err != nil {
        return err
    }
    if err := batch.Column(1).Append([]string{"a", "b", "c"}); err != nil {
        return err
    }
    if err := batch.Column(2).Append([]bool{true, false, true}); err != nil {
        return err
    }

    return batch.Send(ctx)
})
Notes
  • PrepareBatch requires an explicit column list in the INSERT statement (e.g. INSERT INTO t (col1, col2)). Column types are discovered automatically.
  • Both modes can be mixed in the same batch; all columns must have the same number of rows when Send() is called.
  • After a successful Send() the batch is reset and can be reused for another round of appends.
  • Call Abort() to discard buffered data without sending.
  • Supported column types: int/integer, long/bigint, float/real, double, text, boolean, date, timestamp, timestampntz, timestamptz, bytea, array(T), and nullable variants.
Error handling

The SDK provides specific error types that can be checked using Go's errors.Is() function. Here's how to handle different types of errors:

package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"

	_ "github.com/firebolt-db/firebolt-go-sdk"
	fireboltErrors "github.com/firebolt-db/firebolt-go-sdk/errors"
)

func main() {
	// set your Firebolt credentials to construct a dsn string
	clientId := ""
	clientSecret := ""
	accountName := ""
	databaseName := ""
	engineName := ""

	// Example 1: Invalid DSN format (using account-name instead of account_name)
	invalidDSN := fmt.Sprintf("firebolt:///%s?account-name=%s&client_id=%s&client_secret=%s&engine=%s",
		databaseName, accountName, clientId, clientSecret, engineName)
	db, err := sql.Open("firebolt", invalidDSN)
	if err != nil {
		if errors.Is(err, fireboltErrors.DSNParseError) {
			log.Println("Invalid DSN format, please update your DSN and try again")
		} else {
			log.Fatalf("Unexpected error type: %v", err)
		}
	}

	// Example 2: Invalid credentials
	invalidCredentialsDSN := fmt.Sprintf("firebolt:///%s?account_name=%s&client_id=%s&client_secret=%s&engine=%s",
		databaseName, accountName, "invalid", "invalid", engineName)
	db, err = sql.Open("firebolt", invalidCredentialsDSN)
	if err != nil {
		if errors.Is(err, fireboltErrors.AuthenticationError) {
			log.Println("Authentication error. Please check your credentials and try again")
		} else {
			log.Fatalf("Unexpected error type: %v", err)
		}
	}

	// Example 3: Invalid account name
    invalidAccountDSN := fmt.Sprintf("firebolt:///%s?account_name=%s&client_id=%s&client_secret=%s&engine=%s",
        databaseName, "invalid", clientId, clientSecret, engineName)
    db, err = sql.Open("firebolt", invalidAccountDSN)
	if err != nil {
        if errors.Is(err, fireboltErrors.InvalidAccountError) {
            log.Println("Invalid account name. Please check your account name and try again")
        } else {
            log.Fatalf("Unexpected error type: %v", err)
        }
    }

	// Example 4: Invalid SQL query
	dsn := fmt.Sprintf("firebolt:///%s?account_name=%s&client_id=%s&client_secret=%s&engine=%s",
		databaseName, accountName, clientId, clientSecret, engineName)
	db, err = sql.Open("firebolt", dsn)
	if err != nil {
		log.Fatalf("Failed to open connection: %v", err)
	}
	defer db.Close()

	// Try to execute an invalid SQL query
	_, err = db.Query("SELECT * FROM non_existent_table")
	if err != nil {
		if errors.Is(err, fireboltErrors.QueryExecutionError) {
			log.Printf("Error during query execution. Please fix your SQL query and try again")
		} else {
			log.Fatalf("Unexpected error type: %v", err)
		}
	}
}

The SDK provides the following error types:

  • DSNParseError: Provided DSN string format is invalid
  • AuthenticationError: Authentication failure
  • QueryExecutionError: SQL query execution error
  • AuthorizationError:A user doesn't have permission to perform an action
  • InvalidAccountError: Provided account name is invalid or no permissions to access the account

Each error type can be checked using errors.Is(err, errorType). This allows for specific error handling based on the type of error encountered.

Limitations

Although, all interfaces are available, not all of them are implemented or could be implemented:

  • driver.Result is a dummy implementation and doesn't return the real result values.
  • Named query parameters are not supported.
  • Batch insert requires an explicit column list; omitting it (as INSERT INTO t) is not supported.
  • AppendStruct (struct-based batch insertion) is not supported.
  • Decimal and nested struct column types are not supported in batch inserts.

Documentation

Index

Constants

View Source
const DefaultBufferSize int64 = 16384

DefaultBufferSize is the default number of rows buffered before the serialiser flushes to the underlying writer, enabling true streaming: compressed data flows to the HTTP transport incrementally instead of buffering the entire file in memory. Override via WithBufferSize.

Variables

This section is empty.

Functions

func CancelAsyncQuery added in v1.11.0

func CancelAsyncQuery(db *sql.DB, token rows.AsyncResult) error

func ExecAsync added in v1.11.0

func ExecAsync(db *sql.DB, query string, args ...any) (rows.AsyncResult, error)

func ExecAsyncContext added in v1.11.0

func ExecAsyncContext(ctx context.Context, db *sql.DB, query string, args ...any) (rows.AsyncResult, error)

func IsAsyncQueryRunning added in v1.11.0

func IsAsyncQueryRunning(db *sql.DB, token rows.AsyncResult) (bool, error)

func IsAsyncQuerySuccessful added in v1.11.0

func IsAsyncQuerySuccessful(db *sql.DB, token rows.AsyncResult) (bool, error)

func NoError added in v1.8.0

func NoError(option driverOption) driverOptionWithError

func ParseDSNString

func ParseDSNString(dsn string) (*types.FireboltSettings, error)

ParseDSNString parses a dsn in a format: firebolt://username:password@db_name[/engine_name][?account_name=organization] returns a settings object where all parsed values are populated returns an error if required fields couldn't be parsed or if after parsing some characters were left unparsed

func WithAccountID added in v1.6.1

func WithAccountID(accountID string) driverOption

WithAccountID defines account ID for the driver

func WithAccountName added in v1.8.0

func WithAccountName(accountName string) driverOptionWithError

WithAccountName defines account name for the driver

func WithClientParams added in v1.1.0

func WithClientParams(accountID string, token string, userAgent string) driverOption

WithClientParams defines client parameters for the driver

func WithDatabaseAndEngineName added in v1.8.0

func WithDatabaseAndEngineName(databaseName, engineName string) driverOptionWithError

WithDatabaseAndEngineName defines database name and engine name for the driver

func WithDatabaseName added in v1.1.0

func WithDatabaseName(databaseName string) driverOption

WithDatabaseName defines database name for the driver

func WithDefaultQueryParams added in v1.14.0

func WithDefaultQueryParams(params map[string]string) driverOption

WithDefaultQueryParams defines default query parameters that will be seeded into the connection These parameters will be included in all HTTP requests and can be overridden by SET statements

func WithEngineUrl added in v1.1.0

func WithEngineUrl(engineUrl string) driverOption

WithEngineUrl defines engine url for the driver

func WithToken added in v1.6.1

func WithToken(token string) driverOption

WithToken defines token for the driver

func WithTransport added in v1.18.0

func WithTransport(transport http.RoundTripper) driverOption

WithTransport sets a custom http.RoundTripper for all HTTP requests made by the SDK (queries, batch uploads, authentication). Use client.DefaultTransport() as a starting point and override specific fields, or wrap it with middleware (e.g. otelhttp for tracing):

transport := client.DefaultTransport()
transport.DialContext = (&net.Dialer{Timeout: 60*time.Second}).DialContext
connector, _ := firebolt.OpenConnectorWithDSN(dsn, firebolt.WithTransport(transport))
db := sql.OpenDB(connector)

func WithUserAgent added in v1.6.1

func WithUserAgent(userAgent string) driverOption

WithUserAgent defines user agent for the driver

Types

type Batch added in v1.16.0

type Batch interface {
	// Append buffers a single row. The number of arguments must match the
	// column count, and each value must be convertible to the column's type.
	Append(v ...interface{}) error

	// Column returns a handle for columnar appends to the column at the
	// given index. The returned BatchColumn is valid for the lifetime of
	// the batch.
	Column(index int) BatchColumn

	// Send serialises all buffered rows and uploads them to the engine.
	// The batch is reset after a successful send and can be reused.
	Send(ctx context.Context) error

	// Abort discards all buffered rows without sending.
	Abort() error

	// GetMetrics returns timing metrics for each Send() call made on this
	// batch (one entry per call, in chronological order). Returns an error
	// if metrics collection was not enabled via WithBatchMetrics.
	GetMetrics() ([]BatchMetric, error)
}

Batch represents an in-progress batch insert operation. Rows are buffered client-side and serialised when Send is called. The serialised payload is uploaded to the engine via a multipart form POST.

Two insertion modes are supported:

Row-wise — call Append once per row:

batch.Append(col1Val, col2Val, col3Val)

Columnar — obtain a column handle and append an entire typed slice at once:

batch.Column(0).Append([]int32{1, 2, 3})
batch.Column(1).Append([]string{"a", "b", "c"})

Both modes can be mixed freely; the only requirement is that all columns have the same number of rows by the time Send is called.

type BatchColumn added in v1.16.0

type BatchColumn interface {
	// Append appends all values in the given slice to this column.
	// The slice element type must be compatible with the column's Firebolt
	// type (e.g. []int32 for an "int" column, []string for "text").
	Append(v interface{}) error
}

BatchColumn is returned by Batch.Column and supports appending an entire typed slice of values to a single column (columnar insertion).

type BatchConnection added in v1.16.0

type BatchConnection interface {
	PrepareBatch(ctx context.Context, query string, opts ...BatchOption) (Batch, error)
}

BatchConnection provides access to batch insert functionality. Obtain it via database/sql (*sql.Conn).Raw:

conn.Raw(func(driverConn interface{}) error {
    batch, err := driverConn.(fireboltgosdk.BatchConnection).PrepareBatch(
        ctx, "INSERT INTO my_table (col1, col2, col3)")
    if err != nil { return err }
    for _, row := range rows {
        if err := batch.Append(row.Col1, row.Col2, row.Col3); err != nil {
            return err
        }
    }
    return batch.Send(ctx)
})

type BatchMetric added in v1.20.0

type BatchMetric struct {
	SerializeStart   time.Time
	SerializeSeconds float64
	UploadStart      time.Time
	UploadSeconds    float64
}

BatchMetric records timing for one Send() call, split into the serialisation phase and the network upload phase.

type BatchOption added in v1.20.0

type BatchOption func(*batchConfig)

BatchOption configures batch behaviour. Pass to PrepareBatch.

func WithBatchMetrics added in v1.20.1

func WithBatchMetrics() BatchOption

WithBatchMetrics enables per-Send() timing metrics collection. When enabled, GetMetrics returns the recorded metrics. When disabled (the default), GetMetrics returns an error.

func WithBufferSize added in v1.20.0

func WithBufferSize(n int64) BatchOption

WithBufferSize sets the maximum number of rows buffered before the serialiser flushes to the underlying writer. Smaller values produce more incremental streaming (less peak memory) at a small metadata cost. n must be positive; passing n <= 0 causes PrepareBatch to return an error.

The default is DefaultBufferSize (16 384).

func WithCompression added in v1.20.1

func WithCompression(c CompressionCodec) BatchOption

WithCompression selects the compression codec used inside the serialised file. For Parquet this controls page-level compression. The default is CompressSnappy.

func WithCompressionLevel added in v1.20.1

func WithCompressionLevel(level int) BatchOption

WithCompressionLevel sets the compression level passed to the underlying codec. The meaning is codec-specific:

  • Gzip / Deflate: 0 (no compression) – 9 (best), as defined by compress/flate.
  • Zstd: encoder level (e.g. 1 = fastest, 3 = default, 11 = best).
  • LZ4: 1–9 (Parquet only).
  • Brotli: quality 0–11 (Parquet only).
  • Snappy / Uncompressed: ignored (no tuneable level).

When this option is not used, each codec applies its own built-in default.

func WithQueryLabel added in v1.20.1

func WithQueryLabel(label string) BatchOption

WithQueryLabel sets the query label sent with the batch upload request. This is safe to use when multiple batches share the same connection, as it is stored per-batch rather than mutating shared connection state.

func WithSerialization added in v1.20.1

func WithSerialization(f SerializationFormat) BatchOption

WithSerialization selects the wire format for batch uploads. The default is FormatParquet.

type CompressionCodec added in v1.20.1

type CompressionCodec int

CompressionCodec selects the compression algorithm applied within the serialised file (e.g. Parquet page compression).

const (
	// CompressSnappy uses Snappy compression. This is the default.
	CompressSnappy CompressionCodec = iota
	// CompressZstd uses Zstandard compression.
	CompressZstd
	// CompressGzip uses gzip compression.
	CompressGzip
	// CompressUncompressed disables compression entirely.
	CompressUncompressed
	// CompressLZ4 uses LZ4 compression.
	CompressLZ4
	// CompressBrotli uses Brotli compression.
	CompressBrotli
)

type DescribeConnection added in v1.13.0

type DescribeConnection interface {
	Describe(ctx context.Context, query string, args ...interface{}) (*types.DescribeResult, error)
}

DescribeConnection interface provides access to query description functionality

type FireboltConnector added in v1.1.0

type FireboltConnector struct {
	// contains filtered or unexported fields
}

FireboltConnector is an intermediate type between a Connection and a Driver which stores session data

func FireboltConnectorWithOptions added in v1.1.0

func FireboltConnectorWithOptions(opts ...driverOption) *FireboltConnector

FireboltConnectorWithOptions builds a custom connector

func FireboltConnectorWithOptionsWithErrors added in v1.8.0

func FireboltConnectorWithOptionsWithErrors(opts ...driverOptionWithError) (*FireboltConnector, error)

FireboltConnectorWithOptionsWithErrors builds a custom connector with error handling

func OpenConnectorWithDSN added in v1.18.0

func OpenConnectorWithDSN(dsn string, opts ...driverOption) (*FireboltConnector, error)

OpenConnectorWithDSN parses a DSN string and applies the given driver options (e.g. WithTransport), returning a connector suitable for sql.OpenDB. This is the recommended way to customize transport settings that cannot be expressed in a DSN string:

transport := client.DefaultTransport()
transport.IdleConnTimeout = 2 * time.Minute
connector, err := firebolt.OpenConnectorWithDSN(dsn, firebolt.WithTransport(transport))
db := sql.OpenDB(connector)

func (*FireboltConnector) Connect added in v1.1.0

func (c *FireboltConnector) Connect(ctx context.Context) (driver.Conn, error)

Connect returns a connection to the database

func (*FireboltConnector) Driver added in v1.1.0

func (c *FireboltConnector) Driver() driver.Driver

Driver returns the underlying driver of the Connector

type FireboltDriver

type FireboltDriver struct {
	// contains filtered or unexported fields
}

func (*FireboltDriver) Open

func (d *FireboltDriver) Open(dsn string) (driver.Conn, error)

Open parses the dsn string, and if correct tries to establish a connection

func (*FireboltDriver) OpenConnector added in v1.1.0

func (d *FireboltDriver) OpenConnector(dsn string) (driver.Connector, error)

type QueryStatus added in v1.11.0

type QueryStatus string
const (
	QueryStatusRunning    QueryStatus = "RUNNING"
	QueryStatusSuccessful QueryStatus = "ENDED_SUCCESSFULLY"
	QueryStatusCanceled   QueryStatus = "CANCELED_EXECUTION"
)

type QueryStatusResponse added in v1.11.0

type QueryStatusResponse struct {
	// contains filtered or unexported fields
}

type SerializationFormat added in v1.20.1

type SerializationFormat int

SerializationFormat selects the wire format used to encode batch data.

const (
	// FormatParquet uses Parquet (columnar).
	// This is the default when no format is specified.
	FormatParquet SerializationFormat = iota
)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL