> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kinetica.com/llms.txt
> Use this file to discover all available pages before exploring further.

# sqlx_support

> sqlx_support — Kinetica Rust API

[gpudb\_api](https://docs.kinetica.com/content/api/rust/index.md)
[Source](https://github.com/kineticadb/kinetica-api-rust/blob/master/crates/gpudb-api/src/sqlx_support.rs#L1-L1519)&#x20;

SQLx Support for Kinetica via PostgreSQL Wire ProtocolThis module provides helpers for using [SQLx](https://github.com/launchbadge/sqlx) with Kinetica’s PostgreSQL wire protocol support.

## Overview

Kinetica supports the PostgreSQL wire protocol on port 5432, which means you can use SQLx’s PostgreSQL driver directly. This module provides:

<ul>
  <li>[`KineticaPool`](https://docs.kinetica.com/content/api/rust/sqlx_support/type.KineticaPool) - A type alias for `PgPool` with Kinetica-specific configuration</li>
  <li>[`KineticaPoolOptions`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaPoolOptions) - Builder for creating connection pools with sensible defaults</li>
  <li>[`connect`](https://docs.kinetica.com/content/api/rust/sqlx_support/fn.connect), [`connect_with_url`](https://docs.kinetica.com/content/api/rust/sqlx_support/fn.connect_with_url) and [`connect_with_options`](https://docs.kinetica.com/content/api/rust/sqlx_support/fn.connect_with_options) - Convenience functions for establishing connections</li>
  <li>[`KineticaText`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaText), [`KineticaTimestamp`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaTimestamp), [`KineticaBytes`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaBytes), [`KineticaJson`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaJson), [`KineticaVector`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaVector) and [`KineticaArray`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaArray) - for the Kinetica types the protocol does not carry as PostgreSQL does</li>
</ul>

## Quick Start

```rust theme={null}
use gpudb_api::sqlx_support::{KineticaPoolOptions, connect};
use sqlx::Row;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    // Simple connection
    let pool = connect("localhost", "admin", "password").await?;

    // Or with full options
    let pool = KineticaPoolOptions::new()
        .host("localhost")
        .port(5432)
        .username("admin")
        .password("password")
        .max_connections(10)
        .connect()
        .await?;

    // Execute queries using standard SQLx
    let rows = sqlx::query("SELECT id, name FROM users")
        .fetch_all(&pool)
        .await?;

    for row in rows {
        let id: i64 = row.get("id");
        let name: String = row.get("name");
        println!("User: id={}, name={}", id, name);
    }

    Ok(())
}
```

## Type Mappings

Kinetica’s PostgreSQL protocol carries its types as below, as measured against Kinetica 7.2. Where the PostgreSQL type does not carry the value whole, read and write it through the wrappers this module provides (see [`KineticaText`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaText) and its siblings).

<table>
  <thead>
    <tr>
      <th>Kinetica type</th>
      <th>Sent as</th>
      <th>Read as</th>
      <th>Bind as</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`BOOLEAN`</td>
      <td>`BOOL`</td>
      <td>`bool`</td>
      <td>`KineticaText(bool)`</td>
    </tr>

    <tr>
      <td>`TINYINT`, `SMALLINT`, `INTEGER`</td>
      <td>`INT4`</td>
      <td>`i32`</td>
      <td>`KineticaText(i32)`</td>
    </tr>

    <tr>
      <td>`BIGINT`</td>
      <td>`INT8`</td>
      <td>`i64`</td>
      <td>`KineticaText(i64)`</td>
    </tr>

    <tr>
      <td>`UNSIGNED BIGINT`</td>
      <td>`TEXT`</td>
      <td>`KineticaText<u64>`</td>
      <td>`KineticaText(u64)`</td>
    </tr>

    <tr>
      <td>`REAL`</td>
      <td>`FLOAT4`</td>
      <td>`f32`</td>
      <td>`KineticaText(f32)`</td>
    </tr>

    <tr>
      <td>`DOUBLE`</td>
      <td>`FLOAT8`</td>
      <td>`f64`</td>
      <td>`KineticaText(f64)`</td>
    </tr>

    <tr>
      <td>`DECIMAL(p,s)`</td>
      <td>`NUMERIC`</td>
      <td>a decimal type, with SQLx’s `bigdecimal` or `rust_decimal` feature; or `CAST(col AS VARCHAR)` as `KineticaText<String>`</td>
      <td>`KineticaText` of its text</td>
    </tr>

    <tr>
      <td>`VARCHAR`, `VARCHAR(n)`</td>
      <td>`TEXT`</td>
      <td>`String`</td>
      <td>`KineticaText(&str)`</td>
    </tr>

    <tr>
      <td>`IPV4`</td>
      <td>`TEXT`</td>
      <td>`KineticaText<Ipv4Addr>`</td>
      <td>`KineticaText(Ipv4Addr)`</td>
    </tr>

    <tr>
      <td>`UUID`</td>
      <td>`TEXT`</td>
      <td>`KineticaText<uuid::Uuid>`</td>
      <td>`KineticaText(uuid::Uuid)`</td>
    </tr>

    <tr>
      <td>`DATE`</td>
      <td>`DATE`</td>
      <td>`chrono::NaiveDate`</td>
      <td>`KineticaText(NaiveDate)`</td>
    </tr>

    <tr>
      <td>`TIME`</td>
      <td>`TEXT`</td>
      <td>`KineticaText<NaiveTime>`</td>
      <td>`KineticaText(NaiveTime)`</td>
    </tr>

    <tr>
      <td>`DATETIME`</td>
      <td>`TIMESTAMP`, **without its milliseconds**</td>
      <td>`CAST(col AS VARCHAR)` as `KineticaText<NaiveDateTime>`</td>
      <td>`KineticaText(NaiveDateTime)`</td>
    </tr>

    <tr>
      <td>`TIMESTAMP`</td>
      <td>`INT8`: milliseconds since the epoch</td>
      <td>`KineticaTimestamp`</td>
      <td>`KineticaTimestamp`</td>
    </tr>

    <tr>
      <td>`BLOB`</td>
      <td>`BYTEA`</td>
      <td>`Vec<u8>` or `KineticaBytes`</td>
      <td>`KineticaBytes`</td>
    </tr>

    <tr>
      <td>`GEOMETRY`, `BLOB(WKT)`</td>
      <td>none: **the query fails**</td>
      <td>`ST_ASTEXT(col)` as `String`</td>
      <td>`KineticaText` of its WKT</td>
    </tr>

    <tr>
      <td>`JSON`</td>
      <td>`JSON`</td>
      <td>`serde_json::Value` or `KineticaJson<T>`</td>
      <td>`KineticaJson(value)`</td>
    </tr>

    <tr>
      <td>`VECTOR(n)`</td>
      <td>`TEXT`, e.g. `[1,2.5,3]`</td>
      <td>`KineticaVector`</td>
      <td>`KineticaVector` in a plain `INSERT`; `KineticaText(vector.as_slice())` elsewhere</td>
    </tr>

    <tr>
      <td>arrays, e.g. `INTEGER[3]`</td>
      <td>PostgreSQL arrays numbered from 0</td>
      <td>`KineticaArray<T>`</td>
      <td>`KineticaArray<T>`</td>
    </tr>
  </tbody>
</table>

This crate enables SQLx’s `chrono` and `json` features, so `NaiveDate` and `serde_json::Value` read as they are. Nulls read as `Option<_>` of any of these, and bind as `None`.What goes wrong without the wrappers:

<ul>
  <li>SQLx’s `Vec<T>` refuses Kinetica’s arrays, which are numbered from 0.</li>
  <li>A `DATETIME` read as a `NaiveDateTime`, or bound as one, loses its milliseconds.</li>
  <li>Kinetica refuses `uuid::Uuid`, `NaiveTime`, decimal and `Vec<u8>` (`BYTEA`) parameters.</li>
  <li>SQLx binds `serde_json::Value` and `sqlx::types::Json` as `JSONB`, which Kinetica refuses as invalid JSON.</li>
  <li>A plain `INSERT` refuses a vector as text, and everything else refuses one as raw floats.</li>
</ul>

## Parameters

Kinetica reads every parameter after a statement’s first as text, whatever type SQLx sends it as. A second integer, float or date parameter therefore fails to convert in an `INSERT`. In a `WHERE` clause it matches nothing, so an `UPDATE` or `DELETE` reports success and changes no rows. A literal beside such a parameter can be stored as NULL. Text parameters work in every position, and Kinetica converts each to its column’s type, so bind every parameter through a wrapper, which sends text:

```rust theme={null}
use gpudb_api::sqlx_support::{KineticaPool, KineticaText, KineticaTimestamp};

async fn record_login(pool: &KineticaPool, user_id: i64, active: bool) -> Result<u64, sqlx::Error> {
    let result = sqlx::query("UPDATE users SET active = $1, last_login = $2 WHERE id = $3")
        .bind(KineticaText(active))
        .bind(KineticaTimestamp(chrono::Utc::now()))
        .bind(KineticaText(user_id))
        .execute(pool)
        .await?;
    Ok(result.rows_affected())
}
```

## JSON, Arrays and Vectors

Each is inserted, updated, filtered on and deleted by with ordinary SQL, binding the wrappers above. Measured against Kinetica 7.2:

<ul>
  <li>**JSON.** Bind documents with [`KineticaJson`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaJson), which takes any `Serialize` value; read them as `KineticaJson<T>` for any `DeserializeOwned` `T`. `JSON_VALUE(col, 1)` (`bool`) and ranked with `text_match_bm25` or `text_match_bm25_global` (`f64`), the query bound as `KineticaText("customer.tier:Enterprise")`. Do not UPDATE such a column: on Kinetica 7.2.3.21 that crashes a worker rank. Delete the row and insert it again.</li>
  <li>**Arrays.** Bind with [`KineticaArray`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaArray), and use `KineticaArray<Option<T>>` for arrays holding nulls. `ARRAY_CONTAINS`, `ARRAY_CONTAINS_ANY`, `ARRAY_CONTAINS_ALL`, `ARRAY_LENGTH`, `col[i]` (numbered from 1), `ARRAY_APPEND`, `ARRAY_CONCAT`, `ARRAY_SLICE` and `ARRAY_TO_STRING` work; arrays they compute arrive as JSON text, which `KineticaArray` reads too. A numeric `ARRAY_CONTAINS(col, 1)` with a one-element `KineticaArray`. A fixed size, as in `INTEGER[3]`, is not enforced, and an infinite float is refused.</li>
  <li>**Vectors.** A plain `INSERT ... VALUES (n`, `VECTOR(1 AS VECTOR(n))`; a bare `v <-> $1` is refused.</li>
</ul>

```rust theme={null}
use gpudb_api::sqlx_support::{
    KineticaArray, KineticaJson, KineticaPool, KineticaText, KineticaVector,
};
use serde::{Deserialize, Serialize};
use sqlx::Row;

#[derive(Serialize, Deserialize)]
struct Profile {
    name: String,
    score: f64,
}

async fn nearest_tagged(pool: &KineticaPool, tag: &str, probe: &[f32]) -> Result<Vec<(i64, Profile)>, sqlx::Error> {
    sqlx::query("INSERT INTO docs (id, profile, tags, embedding) VALUES ($1, $2, $3, $4)")
        .bind(KineticaText(1_i64))
        .bind(KineticaJson(Profile { name: "first".into(), score: 0.5 }))
        .bind(KineticaArray(vec![tag.to_string()]))
        .bind(KineticaVector(probe.to_vec()))
        .execute(pool)
        .await?;

    let rows = sqlx::query(
        "SELECT id, profile FROM docs WHERE ARRAY_CONTAINS(tags, $1)
         ORDER BY COSINE_DISTANCE(embedding, $2) LIMIT 5",
    )
    .bind(KineticaText(tag))
    .bind(KineticaText(probe))
    .fetch_all(pool)
    .await?;
    Ok(rows
        .iter()
        .map(|row| (row.get("id"), row.get::<KineticaJson<Profile>, _>("profile").0))
        .collect())
}
```

Read arrays through `sqlx::query`: in the text form `sqlx::raw_sql` returns, Kinetica writes `null` in capitals wherever it occurs in a string element.

## Compile-Time Checked Queries

SQLx supports compile-time checked queries with the `query!` macro. However, this requires a live database connection during compilation. For Kinetica, you can:

<ol>
  <li>Use the offline mode with `sqlx prepare`</li>
  <li>Use runtime queries with `sqlx::query()`</li>
</ol>

```rust theme={null}
use gpudb_api::sqlx_support::KineticaPool;

// Runtime query (always works)
async fn get_users(pool: &KineticaPool) -> Result<Vec<(i64, String)>, sqlx::Error> {
    let rows = sqlx::query_as::<_, (i64, String)>("SELECT id, name FROM users")
        .fetch_all(pool)
        .await?;
    Ok(rows)
}

// With a custom struct
#[derive(sqlx::FromRow)]
struct User {
    id: i64,
    name: String,
    email: Option<String>,
}

async fn get_users_typed(pool: &KineticaPool) -> Result<Vec<User>, sqlx::Error> {
    sqlx::query_as::<_, User>("SELECT id, name, email FROM users")
        .fetch_all(pool)
        .await
}
```

## Transactions

Kinetica’s PostgreSQL protocol does not support transactions: `pool.begin()` fails (“got unexpected connection status after attempting to begin transaction”), and each statement applies when it runs.

## Connection Pooling Best Practices

For optimal performance with Kinetica:

<ul>
  <li>Set `max_connections` based on your workload (default: 10)</li>
  <li>Use `min_connections` for warm connection pools</li>
  <li>Set appropriate timeouts for your network latency</li>
</ul>

The server serves one session per thread, up to its `postgres_proxy.max_threads` (64 by default), shared by every client. It ends a session when its client sends PostgreSQL’s Terminate message, which `pool.close()` sends. A connection closed without it, as when a process exits or a task panics with the connection open, keeps its session until the server’s `postgres_proxy.idle_connection_timeout` (300 seconds by default). Pools that outgrow the server’s sessions wait, then fail with `sqlx::Error::PoolTimedOut`. SQLx 0.8’s `pool.close()` can return while a connection on its way back to the pool is still open: before a program ends, close again once `pool.size()` shows it is back (see SQLX\_API.md).

```rust theme={null}
use gpudb_api::sqlx_support::KineticaPoolOptions;
use std::time::Duration;

let pool = KineticaPoolOptions::new()
    .host("kinetica-cluster.example.com")
    .username("admin")
    .password("secure_password")
    .max_connections(20)
    .min_connections(5)
    .acquire_timeout(Duration::from_secs(30))
    .idle_timeout(Some(Duration::from_secs(600)))
    .connect()
    .await?;
```

## Limitations

Besides the types and parameters above:

<ul>
  <li>Transactions are not supported.</li>
  <li>Sessions are limited by the server, and outlive connections that are not closed (see above).</li>
  <li>PostgreSQL-specific features, such as `LISTEN`/`NOTIFY`, are not available.</li>
  <li>Kinetica-specific SQL extensions should be written as raw SQL strings.</li>
</ul>

For full fidelity on every Kinetica type, and for Kinetica-specific operations (bulk insert, type management, KiFS), use the native API of the [`Kinetica`](https://docs.kinetica.com/content/api/rust/gpudb/struct.Kinetica) client. It carries each value with its column’s properties.

## Structs

[Batching<wbr />Sqlx<wbr />Client](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.BatchingSqlxClient.md)A SQLx client that automatically batches INSERT statements and routes them through `BulkInserter<GenericRecord>` for high-performance shard-aware ingestion.[Batching<wbr />Sqlx<wbr />Stats](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.BatchingSqlxStats.md)Statistics from batching operations.[Kinetica<wbr />Array](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaArray.md)Values for the Kinetica types SQLx’s own PostgreSQL types cannot read or write over Kinetica’s protocol, or cannot reliably: see their module. An array column’s value. Kinetica sends arrays numbered from 0, which SQLx’s own `Vec<T>` refuses; this reads them, in the binary form a query’s results come in and in the text form `sqlx::raw_sql` gives, and writes them as the JSON text Kinetica takes. It also reads the JSON text Kinetica sends for an array a function computes, such as `ARRAY_APPEND(col, 4)`.[Kinetica<wbr />Bytes](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaBytes.md)Values for the Kinetica types SQLx’s own PostgreSQL types cannot read or write over Kinetica’s protocol, or cannot reliably: see their module. A `BLOB` column’s value. Kinetica refuses a `BYTEA` parameter, but takes the bytes of a text parameter as they are, so this sends them under the text type; it reads the `BYTEA` Kinetica sends.[Kinetica<wbr />Json](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaJson.md)Values for the Kinetica types SQLx’s own PostgreSQL types cannot read or write over Kinetica’s protocol, or cannot reliably: see their module. A `JSON` column’s value: anything serde serializes, bound directly as JSON, and read back from the JSON Kinetica sends.[Kinetica<wbr />Pool<wbr />Options](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaPoolOptions.md)Builder for creating Kinetica connection pools with sensible defaults.[Kinetica<wbr />Text](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaText.md)Values for the Kinetica types SQLx’s own PostgreSQL types cannot read or write over Kinetica’s protocol, or cannot reliably: see their module. A value carried as text, both ways, which Kinetica converts to and from its column’s type.[Kinetica<wbr />Timestamp](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaTimestamp.md)Values for the Kinetica types SQLx’s own PostgreSQL types cannot read or write over Kinetica’s protocol, or cannot reliably: see their module. A `TIMESTAMP` column’s value: milliseconds since the Unix epoch, which Kinetica sends as `BIGINT` and takes as text.[Kinetica<wbr />Vector](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaVector.md)Values for the Kinetica types SQLx’s own PostgreSQL types cannot read or write over Kinetica’s protocol, or cannot reliably: see their module. A `VECTOR(n)` column’s value. Kinetica sends it as text, `[1,2.5,3]`, and reads it from a parameter in two ways, depending on where it is:[Sqlx<wbr />Bulk<wbr />Inserter](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.SqlxBulkInserter.md)Bulk inserter for SQLx that uses Kinetica’s HTTP API for efficient data loading.[Sqlx<wbr />Pagination<wbr />Stats](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.SqlxPaginationStats.md)Statistics from a paginated SQLx query execution.

## Enums

[Batching<wbr />Sqlx<wbr />Error](https://docs.kinetica.com/content/api/rust/sqlx_support/enum.BatchingSqlxError.md)Error type for BatchingSqlxClient operations[SslMode](https://docs.kinetica.com/content/api/rust/sqlx_support/enum.SslMode.md)SSL mode for connections.

## Constants

`pub const DEFAULT_DATABASE: &str = "postgres";`

Default database name (PostgreSQL compatibility).

`pub const DEFAULT_PORT: u16 = 5432;`

Default PostgreSQL wire protocol port for Kinetica.

## Traits

[From<wbr />Kinetica<wbr />Text](https://docs.kinetica.com/content/api/rust/sqlx_support/trait.FromKineticaText.md)Values for the Kinetica types SQLx’s own PostgreSQL types cannot read or write over Kinetica’s protocol, or cannot reliably: see their module. A value read from the text Kinetica sends: see [`KineticaText`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaText).[Kinetica<wbr />Array<wbr />Element](https://docs.kinetica.com/content/api/rust/sqlx_support/trait.KineticaArrayElement.md)Values for the Kinetica types SQLx’s own PostgreSQL types cannot read or write over Kinetica’s protocol, or cannot reliably: see their module. An element of a Kinetica array: see [`KineticaArray`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaArray).[Kinetica<wbr />Pool<wbr />Ext](https://docs.kinetica.com/content/api/rust/sqlx_support/trait.KineticaPoolExt.md)Extension trait for `PgPool` with Kinetica-specific helpers.[ToKinetica<wbr />Text](https://docs.kinetica.com/content/api/rust/sqlx_support/trait.ToKineticaText.md)Values for the Kinetica types SQLx’s own PostgreSQL types cannot read or write over Kinetica’s protocol, or cannot reliably: see their module. A value Kinetica takes as text: see [`KineticaText`](https://docs.kinetica.com/content/api/rust/sqlx_support/struct.KineticaText).

## Functions

[build\_<wbr />connection\_<wbr />url](https://docs.kinetica.com/content/api/rust/sqlx_support/fn.build_connection_url.md)Create a connection URL from components.[connect](https://docs.kinetica.com/content/api/rust/sqlx_support/fn.connect.md)Connect to Kinetica with minimal configuration.[connect\_<wbr />from\_<wbr />env](https://docs.kinetica.com/content/api/rust/sqlx_support/fn.connect_from_env.md)Connect to Kinetica using environment variables.[connect\_<wbr />with\_<wbr />options](https://docs.kinetica.com/content/api/rust/sqlx_support/fn.connect_with_options.md)Connect to Kinetica using `PgConnectOptions`.[connect\_<wbr />with\_<wbr />url](https://docs.kinetica.com/content/api/rust/sqlx_support/fn.connect_with_url.md)Connect to Kinetica using a connection URL.[connection\_<wbr />url\_<wbr />from\_<wbr />env](https://docs.kinetica.com/content/api/rust/sqlx_support/fn.connection_url_from_env.md)Parse a Kinetica connection URL from environment variables.

## Type Aliases

[Kinetica<wbr />Connection](https://docs.kinetica.com/content/api/rust/sqlx_support/type.KineticaConnection.md)Type alias for SQLx PostgreSQL connection.[Kinetica<wbr />Pool](https://docs.kinetica.com/content/api/rust/sqlx_support/type.KineticaPool.md)Type alias for SQLx PostgreSQL connection pool configured for Kinetica.[Kinetica<wbr />Transaction](https://docs.kinetica.com/content/api/rust/sqlx_support/type.KineticaTransaction.md)Type alias for SQLx PostgreSQL transaction.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.