sqlx icon indicating copy to clipboard operation
sqlx copied to clipboard

Usage with Postgres uint extension

Open ohmree opened this issue 5 years ago • 5 comments

Currently sqlx 0.4.0-beta.1 doesn't support the Postgres uint extension.
What can I do to have my app support the unsigned types from the extension apart from switching to signed types in my database?
If I need to contribute code directly to sqlx, where do I start?

Here's an example of code that returns an error:

-- Assuming the uint extension is installed:
CREATE EXTENSION uint;

CREATE TABLE streamers (
    username_id text CONSTRAINT username PRIMARY KEY,
    video_id text REFERENCES video_ids (id)
);

CREATE TABLE video_ids (
    id text PRIMARY KEY,
    people_playing uint8
);

INSERT INTO video_ids (id)
VALUES ('8iEukLpRyDU');
use sqlx::postgres::PgPoolOptions;
use anyhow::Result;

#[async_std::main]
async fn main() -> Result<()> {
    let pool = PgPoolOptions::new()
        .max_connections(5)
        .connect(&"postgres://username@localhost/db_name").await?;

    let row: (u64,) = sqlx::query_as("SELECT people_playing FROM video_ids")
        .fetch_one(&pool).await?;

    println!("{}", row.0);

    Ok(())
}

And the error:

Error: error returned from database: no binary output function available for type uint8

ohmree avatar Nov 06 '20 15:11 ohmree

no binary output function available for type uint8

that's not an error from SQLx, does that query work in psql?

mehcode avatar Nov 06 '20 19:11 mehcode

It actually does work, both in Emacs' sql-mode (which I assume wraps psql) and in Rust after working on my app some more.

It must've been an error on my side so I'm closing this.

ohmree avatar Nov 07 '20 08:11 ohmree

Sorry for the spam, but I think I was wrong about there being no problem.

Running this through the Emacs pgsql interface while connected to my database:

CREATE EXTENSION uint;

CREATE TABLE video_ids (
    id varchar(11) CONSTRAINT id PRIMARY KEY,
    people_playing uint8 DEFAULT 0 NOT NULL
);

CREATE TABLE users (
    username text CONSTRAINT username PRIMARY KEY,
    video_id varchar(11) REFERENCES video_ids (id) NOT NULL,
    progress_seconds uint8 DEFAULT 0 NOT NULL
);

And then trying to compile this code:

use anyhow::Result;
use sqlx::postgres::PgPoolOptions;
use std::env;

#[async_std::main]
async fn main() -> Result<()> {
    dotenv::dotenv()?;

    let pool = PgPoolOptions::new()
        .max_connections(5)
        .connect(&env::var("DATABASE_URL")?)
        .await?;

    sqlx::query!(
        r#"
            UPDATE users
            SET progress_seconds = $1
            WHERE username = $2
            "#,
        32,
        "ohmree"
    )
    .execute(&pool)
    .await?;

    Ok(())
}

Results in the error error: unsupported type uint8 for param #1.
If I change 32 to 32_u64 compilation fails with the same error.

If it matters I installed pguint from the AUR, the non-git version.

ohmree avatar Nov 07 '20 12:11 ohmree

I wonder what the best way for implementing support for this extension is? https://github.com/rksm/sqlx/commit/0d140dd00a01b11d1dba8f87320706d300b38147 is an approach but it hard codes the type ids for the extension types as returned by select oid, typarray from pg_type where typname = 'uint8'. Those change, however, with each CREATE EXTENSION. Is there a better approach?

rksm avatar Jan 05 '21 20:01 rksm

I've taken a crack at this, and it seems to work in my limited use case. JohnPeel/sqlx:pguint

It did however require some changes to pguint. I pulled in one of (the three) PRs for send & recv implementations on the uint types. JohnPeel/pguint:binary

JohnPeel avatar Sep 16 '22 03:09 JohnPeel