4.7. Arrow Flight SQL#

The QuasarDB REST server, qdb_rest, contains an Arrow Flight SQL server. Flight SQL is a protocol that sends query results as Arrow data over gRPC. Flight SQL is an open standard, and many drivers, applications and tools support it. Thus they connect to QuasarDB without a QuasarDB client library.

Use Flight SQL in these conditions:

  • You want to integrate QuasarDB with an application or tool without custom code.

  • You read large results and want them as Arrow data.

For access over HTTP, see the REST API. To install and configure the server, see qdb_rest.

4.7.1. Requirements#

Before you start, make sure that:

  • You have access to a running QuasarDB cluster.

  • A qdb_rest server runs and connects to that cluster.

  • You have a client that supports Flight SQL. As examples, this page shows the ADBC driver for Python and the Arrow JDBC driver.

4.7.2. Connection#

The Flight SQL listener of the server uses port 40493 by default. The listener uses TLS always, and it has no plain text mode.

Driver

Address

ADBC

grpc+tls://<host>:40493

JDBC

jdbc:arrow-flight-sql://<host>:40493

A server without a configured certificate generates a self-signed certificate at each start. A driver refuses that certificate by default. The examples on this page disable the certificate verification for this reason. Keep the verification enabled when the server has a certificate that your computer trusts.

4.7.3. Authentication#

The Flight SQL listener accepts the same users as the REST API.

Cluster

Credentials

Secure

The username and the secret key from your user security file. The secret key is the password of the driver.

Insecure

None. The connection operates as the anonymous user.

The driver sends the credentials when it connects, and the server answers with an access token. The driver then sends that token with each call.

By default, an access token is valid for 15 minutes. Flight SQL has no refresh operation. When the token expires, the server refuses the call with the code UNAUTHENTICATED. Connect again to get a new token. For connections that stay open longer, ask your system administrator to increase the validity of the access token.

A driver can also send an access token from the login route of the REST API. Set the authorization header of the driver to Bearer <access_token>.

4.7.4. Queries#

A query that starts with #sql and a space runs in the embedded SQL engine, DuckDB with the Quasar extension. Each other query runs in the QuasarDB query engine. This rule is the same as for the REST API.

Query

Engine

SELECT * FROM trades

QuasarDB query language

#sql SELECT * FROM qdb.trades

SQL

In SQL, the cluster is the catalog qdb and its tables are in the schema main. A driver shows the tables of the cluster with these names.

4.7.5. Python#

Install the ADBC driver:

python3 -m pip install adbc-driver-flightsql pyarrow

This example connects to a secure cluster and runs one query in each engine:

import json

import adbc_driver_flightsql.dbapi as flightsql
from adbc_driver_flightsql import DatabaseOptions

with open("user_private.key") as f:
    user = json.load(f)

conn = flightsql.connect(
    "grpc+tls://127.0.0.1:40493",
    db_kwargs={
        "username": user["username"],
        "password": user["secret_key"],
        # Only for a server with a self-signed certificate.
        DatabaseOptions.TLS_SKIP_VERIFY.value: "true",
    },
)

with conn.cursor() as cur:
    cur.execute("SELECT * FROM trades")
    print(cur.fetch_arrow_table())

    cur.execute(
        "#sql SELECT exchange, sum(volume) AS volume "
        "FROM qdb.trades GROUP BY exchange ORDER BY exchange"
    )
    print(cur.fetchall())

conn.close()

The first query prints an Arrow table:

pyarrow.Table
$timestamp: timestamp[ns]
$table: string
price: double
volume: int64
exchange: string
note: string
----
$timestamp: [[2026-01-05 09:30:00.000000000,2026-01-05 09:30:01.500000000,2026-01-05 09:30:02.000000000]]
$table: [["trades","trades","trades"]]
price: [[101.25,101.5,101.4]]
volume: [[300,120,75]]
exchange: [["XNAS","XNYS","XNAS"]]
note: [["open",null,null]]

The second query prints rows:

[('XNAS', Decimal('375')), ('XNYS', Decimal('120'))]

For an insecure cluster, omit username and password.

To use an access token from the REST API, replace username and password with this option:

DatabaseOptions.AUTHORIZATION_HEADER.value: "Bearer " + access_token,

4.7.6. Java#

Add the Arrow Flight SQL JDBC driver to your project:

<dependency>
  <groupId>org.apache.arrow</groupId>
  <artifactId>flight-sql-jdbc-driver</artifactId>
  <version>19.0.0</version>
</dependency>

This example connects to a secure cluster and runs one SQL query:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

public class Example {
    public static void main(String[] args) throws Exception {
        Properties p = new Properties();
        p.setProperty("useEncryption", "true");
        // Only for a server with a self-signed certificate.
        p.setProperty("disableCertificateVerification", "true");
        p.setProperty("user", "tintin");
        p.setProperty("password", "SIMC1BQCOgjU7rkMoMP3gVQACA6JcxRwLhok/5bgS0J8=");

        String url = "jdbc:arrow-flight-sql://127.0.0.1:40493";
        try (Connection c = DriverManager.getConnection(url, p);
             Statement s = c.createStatement();
             ResultSet r = s.executeQuery("#sql SELECT count(*) FROM qdb.trades")) {
            while (r.next()) {
                System.out.println(r.getLong(1));
            }
        }
    }
}

For an insecure cluster, omit the user and password properties.

4.7.7. Supported operations#

The server supports the operations that a driver needs to connect, to browse the tables and to run a query.

Operation

Support

Statements

Yes, in the two engines.

Prepared statements

Yes, without parameters.

Query parameters

No. A query with a parameter marker fails with the code INVALID_ARGUMENT.

Catalogs, schemas, tables and table types

Yes. The cluster is one catalog, qdb, with one schema, main.

Server information (GetSqlInfo)

Yes.

Transactions and savepoints

No.

Bulk ingestion and updates through DoPut

No. To write rows, use the REST API.

Substrait plans

No.

An operation that the server does not support fails with the code UNIMPLEMENTED.

These rules apply to prepared statements:

  • The server keeps no state for a prepared statement, so each server instance behind a load balancer can run it.

  • A prepared #sql statement must contain one statement only.

4.7.8. Errors#

The server reports an error as a gRPC status code with a message.

Code

Cause

UNAUTHENTICATED

The token is absent, incorrect or expired, or the cluster refused the credentials. Connect again.

INVALID_ARGUMENT

The cluster or the SQL engine refused the query. The message is the message of the cluster or the engine.

UNAVAILABLE

The server cannot connect to the cluster, or it is at a limit. Try again later.

UNIMPLEMENTED

The server does not support the operation.

INTERNAL

The REST server failed.