This is an implementation of .NET 6 Core driver for Firebolt in a form of a DbConnection class. Supports all latest .NET frameworks and all platforms.
This project is developed under Visual Studio 2022. Earlier versions of Visual Studio are not supported.
Here is a FireboltNetSDK NuGet page.
- Install using .NET CLI
dotnet add package FireboltNetSDK
- Install using Visual Studio UI
Tools
>NuGet Package Manager
>Manage NuGet Packages for Solution
and search forFirebolt
- Install using Package Manager Console:
PM> Install-Package FireboltNetSDK
Following examples demonstrate how to connect and interact with Firebolt database using this driver:
// Name of your Firebolt account
string account = "my_firebolt_account";
// Client credentials, that you want to use to connect
string clientId = "my_client_id";
string clientSecret = "my_client_secret";
// Name of database and engine to connect to (Optional)
string database = "my_database_name";
string engine = "my_engine_name";
// Construct a connection string using defined parameter
string conn_string = $"account={account};clientid={clientId};clientsecret={clientSecret};database={database};engine={engine}";
using FireboltDotNetSdk.Client;
// Create a new connection using generated connection string
using var conn = new FireboltConnection(conn_string);
// Open a connection
conn.Open();
// Execute SQL, fetch data, ...
// Close the connection after all operations are done
conn.Close();
// First you would need to create a command
var command = conn.CreateCommand();
// ... and set the SQL query
command.CommandText = "CREATE DATABASE IF NOT EXISTS MY_DB";
// Execute a SQL query and get a DB reader
command.ExecuteNonQuery();
// Close the connection after all operations are done
conn.Close();
// First you would need to create a command
var command = conn.CreateCommand();
// ... and set the SQL query
command.CommandText = "SELECT * FROM my_table";
// Execute a SQL query and get a DB reader
DbDataReader reader = command.ExecuteReader();
// Optionally you can check whether the result set has rows
Console.WriteLine($"Has rows: {reader.HasRows}");
// Discover the result metadata
int n = reader.FieldCount();
for (int i = 0; i < n; i++)
{
Type type = reader.GetFieldType();
string name = reader.GetName();
}
// Iterate over the rows and get values
while (reader.Read())
{
for (int i = 0; i < n; i++)
{
Console.WriteLine($"{reader.GetName(i)}:{reader.GetFieldType(i)}={reader.GetValue(i)}");
}
}
var tz = conn.CreateCommand();
tz.CommandText = "SET time_zone=America/New_York";
tz.ExecuteNonQuery();
tz.CommandText = "SELECT '2000-01-01 12:00:00.123456 Europe/Berlin'::timestamptz as t";
DbDataReader tzr = tz.ExecuteReader();
if (tzr.Read())
{
// 2000-01-01 06:00:00.123456-05
Console.WriteLine(tzr.GetDateTime(0));
}
Firebolt supports server-side asynchronous query execution, allowing queries to run in the background while you retrieve results later. This is particularly useful for long-running queries, as it eliminates the need to maintain a persistent connection to the server while waiting for execution to complete.
⚠ Note: This is different from .NET's asynchronous programming model. Firebolt's server-side async execution means that the query runs independently on the server, while .NET async/await handles non-blocking execution on the client side.
Executing a query asynchronously means the database will start processing it in the background. Instead of returning data immediately, the response contains a query token, which can be used later (even in a new connection) to check the query status or retrieve results.
FireboltCommand command = (FireboltCommand)conn.CreateCommand();
command.CommandText = "INSERT INTO large_table SELECT * FROM source_table";
// Execute the query asynchronously on the server
command.ExecuteServerSideAsyncNonQuery();
// Alternatively, use .NET's async/await to avoid blocking the client thread
await command.ExecuteServerSideAsyncNonQueryAsync();
// Store the async query token for later use
string token = command.AsyncToken;
You can check if the query is still running or if it has finished executing.
IsServerSideAsyncQueryRunning(token)
returnstrue
if the query is still in progress andfalse
if it has finished.IsServerSideAsyncQuerySuccessful(token)
returns:true
if the query completed successfullyfalse
if the query failednull
if the query is still running
using FireboltConnection conn = new FireboltConnection(conn_string);
conn.Open();
// Check if the query is still running
bool isRunning = conn.IsServerSideAsyncQueryRunning(token);
// Check if the query completed successfully (returns null if it's still running)
bool? isSuccessful = conn.IsServerSideAsyncQuerySuccessful(token);
or use .NET asynchronous eqivalents
// Check if the query is still running
bool isRunning = await conn.IsServerSideAsyncQueryRunningAsync(token);
// Check if the query completed successfully (returns null if it's still running)
bool? isSuccessful = await conn.IsServerSideAsyncQuerySuccessfulAsync(token);
If an asynchronous query is no longer needed, you can cancel it before execution completes.
using FireboltConnection conn = new FireboltConnection(conn_string);
conn.Open();
// Cancel the async query
bool cancelled = conn.CancelServerSideAsyncQuery(token);
or do so asynchronously
bool cancelled = await conn.CancelServerSideAsyncQueryAsync(token);
This approach ensures that long-running queries do not block your application while allowing you to monitor, manage, and cancel them as needed.
Firebolt supports server-side prepared statement execution, allowing better safety when using client provided inputs, not constructing the query client-side.
To make use of server-side prepared statements, you need to provide the following parameter in your connection string:
preparedStatementParamStyle=FbNumeric
This makes any prepared statement constructed from the connection to use the FbNumeric
parameter style, which is required for server-side prepared statements.
⚠ Note: Using this parameter, normal prepared statements will not work, so you need to use server-side prepared statements only.
Other than this parameter, the API is the same, except for the command text.
var command = (FireboltCommand)conn.CreateCommand();
command.CommandText = "SELECT * FROM my_table WHERE id = $1";
command.Parameters.AddWithValue("$1", 123);
command.Prepare();
// Execute the query as any other command
using var reader = command.ExecuteReader();
The preparedStatementParamStyle
parameter in the connection string can take the following values:
Native
(@paramName) - default: Uses the native parameter style, which is compatible with client-side prepared statements.FbNumeric
($number): Uses Firebolt's numeric parameter style, which is required for server-side prepared statements.
Firebolt supports query result streaming, allowing you to retrieve large datasets in a memory-efficient manner. This is particularly useful for queries that return a significant amount of data, as it avoids loading the entire result set into memory at once.
To execute a query that returns a large result set, you can use the ExecuteStreamedQuery
method or it's asynchronous equivalent ExecuteStreamedQueryAsync
. This method allows you to stream the results directly from the server without loading them all into memory at once.
FireboltCommand command = (FireboltCommand)conn.CreateCommand();
command.CommandText = "SELECT * FROM large_table";
// Execute the query asynchronously on the server
using var reader = command.ExecuteStreamedQuery();
// or use the asynchronous version
using var reader = await command.ExecuteStreamedQueryAsync();
// Iterate over the streamed results in the same way as with a regular DbDataReader
while (await reader.ReadAsync())
{
for (int i = 0; i < reader.FieldCount; i++)
{
Console.WriteLine($"{reader.GetName(i)}: {reader.GetValue(i)}");
}
}
The Firebolt .NET SDK provides full support for database transactions, allowing you to group multiple operations into atomic units of work.
using var connection = new FireboltConnection(connectionString);
await connection.OpenAsync();
// Begin a transaction
using var transaction = connection.BeginTransaction();
try
{
// Execute multiple commands within the transaction
using var command1 = connection.CreateCommand();
command1.CommandText = "INSERT INTO customers (name) VALUES ('John Doe')";
await command1.ExecuteNonQueryAsync();
using var command2 = connection.CreateCommand();
command2.CommandText = "UPDATE inventory SET quantity = quantity - 1 WHERE product_id = 123";
await command2.ExecuteNonQueryAsync();
// Commit the transaction if all operations succeed
transaction.Commit();
}
catch (Exception)
{
// Rollback the transaction if any operation fails
transaction.Rollback();
throw;
}
The SDK supports both synchronous and asynchronous transaction operations:
// Asynchronous commit
await transaction.CommitAsync();
// Asynchronous rollback
await transaction.RollbackAsync();
If a transaction is disposed without being explicitly committed or rolled back, it will automatically rollback:
using var connection = new FireboltConnection(connectionString);
await connection.OpenAsync();
using (var transaction = connection.BeginTransaction())
{
// Execute commands...
// If an exception occurs here, the transaction will automatically rollback when disposed
}
// Transaction is automatically rolled back if not committed
The FireboltTransaction class provides properties to check the current state:
var transaction = connection.BeginTransaction();
// Check if transaction has been completed
bool isCompleted = transaction.IsCompleted;
// Check if transaction has been committed
bool isCommitted = transaction.IsCommitted;
// Check if transaction has been rolled back
bool isRolledBack = transaction.IsRolledBack;
If you prefer manual transaction management, you can use the FireboltConnection
class to control transactions explicitly:
using var connection = new FireboltConnection(connectionString);
await connection.OpenAsync();
// Start a transaction manually
var command = connection.CreateCommand();
command.CommandText = "BEGIN TRANSACTION";
await command.ExecuteNonQueryAsync();
// Execute your SQL commands
// Commit the transaction
command.CommandText = "COMMIT";
await command.ExecuteNonQueryAsync();
// If you need to rollback, you can do so
command.CommandText = "ROLLBACK";
await command.ExecuteNonQueryAsync();
TransactionScope is not supported in the Firebolt .NET SDK. Instead, you should use the explicit transaction management provided by the SDK, as shown in the examples above.