Asyncronous Rust Mysql driver based on Tokio.

Related tags

Database mysql_async
Overview

mysql-async

Tokio based asynchronous MySql client library for rust programming language.

Gitter

Build Status API Documentation on docs.rs

Installation

Library hosted on crates.io.

[dependencies]
mysql_async = "<desired version>"

Example

See crate documentation on docs.rs.

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Comments
  • Add support for std::future and async/await

    Add support for std::future and async/await

    Still a work in progress.

    This is a very direct port of the existing codebase. I'm avoiding rearchitecting as much as I can, and instead doing a mostly mechanical transformation. Seems to be going okay so far, but I'm not quite done yet (need https://github.com/tokio-rs/tokio/pull/1537 for example). There are definitely a bunch of places the codebase could be improved (in particular, a bunch of Boxes that could be removed), but at least this will get us off the ground.

    Fixes #63.

    opened by jonhoo 32
  • Register for binlog events

    Register for binlog events

    In my project, I need a listener for MySQL's binlog events. There are 2 crates available that can parse the Binlog event data, but there is no network-based listener. I think this could be a nice addition to this crate.

    Over the weekend, I built a prototype that adds commands for registering to the binlog events. I am happy to work on this further in a PR, but first wanted to get your feedback on this. See: https://github.com/blackbeam/mysql_async/compare/master...normanrz:expose-binlog

    The API is as follows: The client code creates a Conn, registers that conn as a slave and then requests binlog events. After that, the client can repeatedly call read_packet to receive the next binlog event, which needs to be parsed and used. The conn can't be used for regular queries anymore.

    Here is a runnable test: https://github.com/normanrz/mysql_async/blob/expose-binlog/src/binlog/mod.rs Please note that mysqld needs to be configured for binlogs: https://github.com/normanrz/mysql_async/blob/expose-binlog/.circleci/config.yml#L17 In my example code, I use the mysql_binlog crate for parsing. There is a PR for my changes in that crate.

    Would you rather implement the command code for COM_REGISTER_SLAVE and COM_BINLOG_DUMP in mysql_common? Also, I couldn't figure out how to expose read_packet for Conn as a public function.

    My implementation is built upon @dannysu's fork: https://github.com/blackbeam/rust-mysql-simple/compare/master...dannysu:binlogsync

    opened by normanrz 21
  • Conn::new sometimes fails to make progress under load

    Conn::new sometimes fails to make progress under load

    Try running the following test:

    #[tokio::test(threaded_scheduler)]
    async fn can_handle_the_pressure() {
        use futures_util::stream::StreamExt;
        {
            let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<()>();
            for _ in 0..500 {
                let tx = tx.clone();
                tokio::spawn(async move {
                    let c = Conn::new(get_opts()).await.unwrap();
                    let c = c.drop_query("SELECT 1").await.unwrap();
                    c.disconnect().await.unwrap();
                    drop(tx);
                });
            }
            drop(tx);
            // see that all the tx's eventually complete
            assert_eq!(rx.next().await, None);
        }
        eprintln!("MID");
        {
            let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<()>();
            for _ in 0..500 {
                let tx = tx.clone();
                tokio::spawn(async move {
                    eprintln!("GETCONN");
                    let c = Conn::new(get_opts()).await.unwrap();
                    eprintln!("GOTCONN");
                    let c = c.drop_query("SELECT 1").await.unwrap();
                    c.disconnect().await.unwrap();
                    drop(tx);
                });
            }
            drop(tx);
            // see that all the tx's eventually complete
            assert_eq!(rx.next().await, None);
        }
        eprintln!("DONE");
    }
    

    Against a local MySQL with max_connections = 1000. It passes just fine. Now, run some CPU-heavy program that takes up most of the cores on the machine, and run the test again. It will frequently hang between printing MID and printing DONE. Digging a big deeper, you will see that GETCONN gets printed 500 times, but GOTCONN only N < 500 times (the exact value of N varies). Some further digging reveals that the issue lies in handle_handshake. Specifically, if you put a print statement above and below the call to read_packet().await, you'll see that the print before gets printed 2*500-N times, and the print after 2*500-2*N times. The explanation for this is that every connection goes through Conn::new twice: once as a "plain" connection, and once as an "upgraded" socket connection. But some (500-N) plain connections get "stuck" on that .await. They therefore do not get upgraded, so they fail to hit the second print twice, and the first print once (as a socket).

    In any case, the issue for the stuck connections is that read_packet().await never returns for plain connections. Reading through the code, it appears that there are only three ways this can happen: tokio::net::TcpStream is broken (unlikely), tokio_util::codec::Framed is broken (possible), or mysql_common::proto::codec::PacketCodec either blocks (unlikely) or returns None when it should return Some (a likely culprit). How any of these are related to load, I have no idea. Why it is necessary to first spin up and drop 500 connections, I also have no idea. But that's what I'm seeing. Which sort of points at a tokio bug, but that seems weird too?

    Well, I figured I should write up my findings no matter what, so that hopefully we can get to the bottom of it. I ran into this when running code on EC2 which is infamous for having a lot of scheduling noise, similar to that of a loaded machine, so it's probably worth trying to fix.

    opened by jonhoo 21
  • packet order incorrect

    packet order incorrect

    While connecting to the same server referenced for this mysql simple issue https://github.com/blackbeam/rust-mysql-simple/issues/160 I get an error about unexpected packet order using mysql_async. My first thought is perhaps the feature that was added in mysql simple just hasn't been implement in mysql_async. I can get any extra details you need. This is using SSL without a server public certificate and with domain verification off.

    opened by glademiller 15
  • "Can't parse" error

    Did a cargo update, now my pool get_conn throws these errors:

    Io(Custom { kind: UnexpectedEof, error: "can't parse: buf doesn't have enough data" })
    

    Reverted to the previous Cargo.toml, works fine. Not sure if it's mysql_async or a dependent package, but I can't debug it more fine-grained at the moment.

    opened by magnusmanske 14
  • Pool::disconnect blocks indefinitely

    Pool::disconnect blocks indefinitely

    I have a wrapper around a Pool object (using the new async update) which has a disconnect method:

    pub async fn disconnect(&self) -> Result<()> {
        self.pool.clone().disconnect().await?;
        Ok(())
    }
    

    When I want to exit my program, I run this on my tokio runtime with ::block_on. However, it never returns.

    cc @jonhoo

    opened by PvdBerg1998 14
  • PacketOutOfOrder error on connect with too many connections

    PacketOutOfOrder error on connect with too many connections

    Conn::new returns a PacketOutOfOrder error if too many connections are established at the same time to a MySQL database. This doesn't seem like the right error to return? You can try this with something like:

    #[tokio::test(threaded_scheduler)]
    async fn ooo_error() {
        use futures_util::stream::StreamExt;
    
        let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<()>();
        for _ in 0..1000 {
            let tx = tx.clone();
            tokio::spawn(async move {
                let c = Conn::new(get_opts()).await.unwrap();
                let c = c.drop_query("SELECT 1").await.unwrap();
                c.disconnect().await.unwrap();
                drop(tx);
            });
        }
    
        // wait until all connections have been dropped
        drop(tx);
        assert_eq!(rx.next().await, None);
    }
    

    Which will panic at Conn::new(get_opts()).await.unwrap() (expected) with a PacketOutOfOrder error (unexpected).

    opened by jonhoo 13
  • Clean up broken and dropped connections

    Clean up broken and dropped connections

    This should be a first step towards fixing #68.

    We currently don't maintain pool invariants if a connection errors or is dropped (exist to be specific). This patch should fix that.

    Also renames should_hold_bounds to should_hold_bounds1 to make it easier to run that test by itself.

    opened by udoprog 13
  • Err(Driver(ConnectionClosed))

    Err(Driver(ConnectionClosed))

    Hi, I am trying mysql_async with warp something like this:

    The pool:

    let mut opts = mysql_async::OptsBuilder::new();
        opts.user(dsn.username);
        opts.pass(dsn.password.clone());
        opts.ip_or_hostname(dsn.host.unwrap());
        opts.socket(dsn.socket);
        opts.db_name(dsn.database);
        if let Some(port) = dsn.port {
            opts.tcp_port(port);
        }
        opts.pool_options(mysql_async::PoolOptions::with_constraints(
            mysql_async::PoolConstraints::new(10, 100).unwrap(),
        ));
    
        // mysql ssl options
        let mut ssl_opts = mysql_async::SslOpts::default();
        if let Some(tls) = dsn.params.get("tls") {
            if *tls == "skip-verify" {
                ssl_opts.set_danger_accept_invalid_certs(true);
            }
        }
        opts.ssl_opts(ssl_opts);
    
        mysql_async::Pool::new(opts)
    

    Then with warp:

    let pool = options::new();
        pool.get_conn().await.unwrap_or_else(|e| {
            eprintln!("Could not connect to MySQL: {}", e);
            process::exit(1);
        });
        println!("{:#?}", pool);
    
     let db = warp::any().map(move || pool.clone());
    
        let register = warp::post()
            .and(warp::path("register"))
            .and(warp::body::json())
            .and(db.clone())
            .and_then(register);
    
        warp::serve(register).run(([0, 0, 0, 0], 8000)).await;
    
    
    async fn register(
        user: User,
        pool: mysql_async::Pool,
    ) -> Result<impl warp::Reply, warp::Rejection> {
     match queries::find_user(pool.clone(), &user.username, &user.email).await {
            Ok(rs) => {
                 println!("{:?}", rs);
                 Ok(StatusCode::CREATED)
           }
            err => {
                eprintln!("{:?}", err);
               Ok(StatusCode::INTERNAL_SERVER_ERROR)
            }
        }
    }
    

    and queries is something like:

    pub async fn find_user(
        pool: mysql_async::Pool,
        username: &str,
        email: &str,
    ) -> Result<usize, Box<dyn Error>> {
        let conn = pool.get_conn().await?;
        let (_, row) = conn
            .first_exec::<_,_,usize>(
                "SELECT IF((SELECT count(*) FROM users WHERE email=?), 2, (IF((SELECT count(*) FROM users WHERE name=?), 1, 0)))",
                (&email, &username),
            ).await?;
        Ok(row.ok_or("expecting a row")?)
    }
    

    It works but in some cases, I am getting an Err(Driver(ConnectionClosed)), also the pool is always one connection instead of 10 as defined, therefore wondering what could be wrong or if I should close the connection after every use.

    Any ideas?

    opened by nbari 12
  • failed to fill whole buffer

    failed to fill whole buffer

    Hi! I meet a problem while executing transaction exec_drop,some times I got error result like: Io(Io(Custom { kind: UnexpectedEof, error: "failed to fill whole buffer" })) But when i tried again,it's just ok.

    On version 0.25.0 my code like this: trans.exec_drop( "INSERT INTO stock_order_sku (order_id,sku_id,amount) VALUES(?,?,?)", (order_id, sku, amount), ).await.map_err(|e| error!("fail to insert sku info {:?}",e)) .is_ok();

    opened by DrYaling 11
  • impl Stream for QueryResult

    impl Stream for QueryResult

    In light of stable async/await, a lot of these collect/try_collect/map/etc. methods seem redundant if we could instead stream the async results.

    e.g. this pattern is replicated with minor changes in several places:

        pub async fn for_each<F>(self, mut fun: F) -> Result<Self>
        where
            F: FnMut(Row),
        {
            if self.is_empty() {
                Ok(self)
            } else {
                let mut qr = self;
                loop {
                    let (qr_, row) = qr.get_row().await?;
                    qr = qr_;
                    if let Some(row) = row {
                        fun(row);
                    } else {
                        break Ok(qr);
                    }
                }
            }
        }
    

    Why not simply swap out the fun(row); and instead make that the poll on a Stream? The big thing this would open up for me, is I could impl From<my::Row> (which would call the FromRow), and then let the From and standard collect() calls build my result sets.

    As it's written, I'm stuck forced to build full Vecs of my entire QueryResult, when a stream would let me map, filter, zip, etc., and let type inference handle my result from collecting (could even make a HashMap or whatever). Would also make it a lot easier to return an Err on the very first TryFrom<my::Row> that fails, instead of building the full result with all errors like try_collect does now.

    opened by jkoudys 10
Releases(v0.31.2)
  • v0.31.2(Dec 10, 2022)

  • v0.31.1(Dec 5, 2022)

  • v0.31.0(Nov 12, 2022)

    What's Changed

    • Implemented rustls support, fixes #195 by @TobiasDeBruijn in #209
    • Turn get_conn waiting queue into FIFO queue. by @cloneable in #213 (fixes #212)

    New Contributors

    • @TobiasDeBruijn made their first contribution in https://github.com/blackbeam/mysql_async/pull/209
    • @cloneable made their first contribution in https://github.com/blackbeam/mysql_async/pull/213

    Full Changelog: https://github.com/blackbeam/mysql_async/compare/v0.30.0...v0.31.0

    Source code(tar.gz)
    Source code(zip)
  • v0.30.0(Jun 2, 2022)

    What's New

    • #190 simplifies LOCAL INFILE API as suggested by @cc-morning (see #188)
    • thanks to @glittershark the driver is now able to use raw bytes as a query (suggested in #194 and implemented in #203, #204)

    Fixes

    • @oussama reported and @galeaspablo fixed an issue with the Pool ability to properly handle BinlogStream's Conn (see #200, #201)
    • #205 fixes a subtle issue in DisconnectPool, that was reported by @heavycharged in #199

    Other changes

    • ci: Add TiDB tests by @blackbeam in https://github.com/blackbeam/mysql_async/pull/179
    • Narrow the scope of unsafe blocks by @peamaeq in https://github.com/blackbeam/mysql_async/pull/193
    • fix some typos by @cuishuang in https://github.com/blackbeam/mysql_async/pull/191
    Source code(tar.gz)
    Source code(zip)
  • v0.29.0(Dec 17, 2021)

    Breaking

    • mysql_common version bumped to 0.28.0, this means that now there is another set of enabled mysql_common features:

      • mysql_common/chrono – disabled due to RUSTSEC-2020-0159
      • mysql_common/time replaced with mysql_common/time03
      • mysql_common/bigdecimal replaced with mysql_common/bigdecimal03

      You should be able to redefine this features in your Cargo.toml.

      Also note, that mysql_async::time and mysql_async::uuid reexports are now removed. Please use direct dependencies in your Cargo.toml

    Improvements

    • BufferPool is now lock free (implemented by @vkrasnov in #170)

    Fixes

    • #175 fixes Conn::perform_auth_switch that was broken in e18f47d (reported by @bfjnaude in #173)
    • #172 fixes resource leak in Conn::drop (reported by @WGH- in #171)\

    Other

    • mio bumped to 0.8
    • lru bumped to 0.7
    • pem bumped to 1.0
    Source code(tar.gz)
    Source code(zip)
  • v0.28.1(Sep 18, 2021)

    This release adds streaming support to the QueryResult (thanks to @nappa85, @dodomorandi). Namely it adds two new methods:

    • QueryResult::stream – to stream the current result set,
    • QueryResult::stream_and_drop – to stream the current result set and ignore subsequent sets.

    Also this release adds a few convenience methods into Query and Queryable traits (they are based on QueryResult::stream_and_drop):

    • Query::stream – executes a query/statement and streams the first result set ignoring subsequent sets,
    • Queryable::query_stream – performs a query and streams the first result set ignoring subsequent sets,
    • Queryable::exec_stream – executes a statement and streams the first result set ignoring subsequent sets.

    (See #166, #90)

    Source code(tar.gz)
    Source code(zip)
  • v0.28.0(Jul 5, 2021)

    New features:

    Improvements:

    • binary serialization/deserialization was improved (up to 5% speedup)

    Other:

    • add Conn::last_ok_packet
    • migrate from crate::BoxFuture to futures_core::future::BoxFuture
    • documentation fixes (by @yerke)
    • fix #155
    Source code(tar.gz)
    Source code(zip)
  • v0.27.1(Feb 20, 2021)

  • v0.26.1(Feb 20, 2021)

  • v0.27.0(Feb 6, 2021)

  • v0.25.1(Jan 11, 2021)

  • v0.26.0(Jan 10, 2021)

    Breaking changes

    • mysql_common bumped to v0.26
    • tokio bumped to v1
    • named pipes are temporary disabled (see tokio-rs/tokio#3388)

    Improvements

    • lru updated to v0.6.0
    • multiple pem certs are now allowed in SslOpts::with_root_cert_path

    Fixes

    • #96
    • #134

    Thanks

    • @amilkov3
    • @gperinazzo
    • @darksonn
    • @dryaling
    Source code(tar.gz)
    Source code(zip)
  • v0.25.0(Oct 1, 2020)

  • v0.24.2(Aug 28, 2020)

    • #124 was reported and fixed in #125 (thanks to @glyphpoch);
    • #126 was reported and fixed (thanks to @nemosupremo);
    • blackbeam/rust-mysql-simple#248 was ported to mysql_async
    Source code(tar.gz)
    Source code(zip)
  • v0.24.1(Aug 24, 2020)

    • QueryResult::new is now public (by @IvanChepurnyi in #119)
    • #121 was found and fixed in #123 (thanks to @IvanChepurnyi)
    • #96 and related issues were fixed in 4602469 (hopefully)
    Source code(tar.gz)
    Source code(zip)
  • v0.24.0(Jul 23, 2020)

    API changes

    • library switched to non-consuming API:

      // pre 0.24.0:
      let conn = conn.query_drop("DO 1").await?;
      
      // 0.24.0:
      conn.query_drop("DO 1").await?;
      
    • Queryable trait was updated and now it is more convenient to work with usual single-result sets. Use Queryable::query_iter and Queryable::exec_iter if you need more flexibility.

    • Query trait was introduced. It allows you to run queries directly on a Pool and to create 'static QueryResults

    • Thick Stmt structure was removed in favor of the Statement structure, which is a thin wrapper over raw statement identifier and metadata.

    Fixes

    • #110
    Source code(tar.gz)
    Source code(zip)
  • v0.23.1(Jun 19, 2020)

  • v0.23.0(Mar 29, 2020)

  • v0.22.2(Mar 23, 2020)

  • v0.22.1(Mar 10, 2020)

  • v0.22.0(Mar 2, 2020)

    • pool was simplified by @jonhoo (see #92, #97);
    • the info field of mysql ok packet was exposed (see #93, #98);
    • ipv6 parsing for URLs was fixed by @HarveyHunt (see #95);
    Source code(tar.gz)
    Source code(zip)
  • v0.21.1(Dec 15, 2019)

  • v0.21.0(Nov 28, 2019)

  • v0.21.0-alpha.4(Nov 4, 2019)

    Changes:

    • mysql_common was updated:
      • codec replaced by mysql_common codec;
      • compression support was introduced (see docs on OptsBuilder::compression);
    • falure was replaced by thiserror (by @udoprog in #78);
    • #79 was fixed;
    • #82 was fixed by @tomhoule;
    • #57 fixed:
      • PoolOptions structure was introduced;
      • inactive_connection_ttl and ttl_check_interval options were introduced.
    Source code(tar.gz)
    Source code(zip)
  • v0.21.0-alpha.2(Oct 1, 2019)

  • v0.21.0-alpha.1(Sep 20, 2019)

  • v0.20.0(Aug 19, 2019)

    • WhiteListFsLocalInfileHandler was switched from mio to tokio::fs::File, mio dependency was removed (#61, #62 by @travismiller)
    • Pool was reimplemented to be fully async (#66 by @jonhoo, #70 by @udoprog)
    Source code(tar.gz)
    Source code(zip)
  • v0.19.1(Jun 11, 2019)

  • v0.19.0(Apr 20, 2019)

    • Protocoland ConnectionLike traits are now in prelude (see #48)
    • mysql_common bumped to the latest version
    • unix domain sockets and windows named pipes now supported
    • now pool won't wait for queue cleanup when new_conn is called (see #45)
    • pool ongoing count fixed by @Healthire (see #44)
    Source code(tar.gz)
    Source code(zip)
  • v0.17.2(Jan 28, 2019)

Owner
Anatoly I
Writing Rust since 2014.
Anatoly I
Cassandra (CQL) driver for Rust, using the DataStax C/C++ driver under the covers.

cassandra-cpp This is a maintained Rust project that exposes the DataStax cpp driver at https://github.com/datastax/cpp-driver/ in a somewhat-sane cra

null 93 Jan 7, 2023
This is a maintained rust project that exposes the cpp driver at cpp-driver in a somewhat-sane crate.

cassandra-rs This is a maintained rust project that exposes the cpp driver at https://github.com/datastax/cpp-driver/ in a somewhat-sane crate. For th

Tupshin Harper 51 Aug 20, 2020
Simple crate that wraps a tokio::process into a tokio::stream

tokio-process-stream tokio-process-stream is a simple crate that wraps a tokio::process into a tokio::stream Having a stream interface to processes is

Leandro Lisboa Penz 8 Sep 13, 2022
This project provides a Rust-based solution for migrating MSSQL databases to MySQL.

MSSQL to MySQL Database Migration A Rust project to migrate MSSQL databases to MySQL, including table structures, column data types, and table data ro

Bitalizer 2 Jul 10, 2023
🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, SQLite, and MSSQL.

SQLx ?? The Rust SQL Toolkit Install | Usage | Docs Built with ❤️ by The LaunchBadge team SQLx is an async, pure Rust† SQL crate featuring compile-tim

launchbadge 7.6k Dec 31, 2022
A highly scalable MySQL Proxy framework written in Rust

mysql-proxy-rs An implementation of a MySQL proxy server built on top of tokio-core. Overview This crate provides a MySQL proxy server that you can ex

AgilData 175 Dec 19, 2022
Mysql client library implemented in rust.

mysql This crate offers: MySql database driver in pure rust; connection pool. Features: macOS, Windows and Linux support; TLS support via nativetls cr

Anatoly I 548 Dec 31, 2022
A user crud written in Rust, designed to connect to a MySQL database with full integration test coverage.

SQLX User CRUD Purpose This application demonstrates the how to implement a common design for CRUDs in, potentially, a system of microservices. The de

null 78 Nov 27, 2022
rust-mysql-simple support library for the r2d2 connection pool

r2d2-mysql rust-mysql-simple support library for the r2d2 connection pool.

outersky 44 Nov 1, 2022
A tool for automated migrations for PostgreSQL, SQLite and MySQL.

Models Models is an implementation for a SQL migration management tool. It supports PostgreSQL, MySQL, and SQLite. Quick Start install the CLI by runn

null 45 Nov 16, 2022
CRUD example with Rocket, Toql and MySQL

Todo (Rocket, Toql, MySQL) This is a little REST server built with Rocket, Toql and MySQL. The server allows to call CRUD functions on a Todo item. It

Artos 7 Jan 5, 2022
Gibbs MySQL Spyglass

Gibbs MySQL Spyglass Ahoy Matey! The Gibbs MySQL Spyglass is a application used to capture application traffic into a MySQL database. It is designed t

AgilData 82 Nov 14, 2021
fast & easy CLI and vscode extension specialized to format MySQL INSERT queries.

insertfmt fast & easy CLI specialized to format MySQL INSERT queries. format queries so that they look like a table. NOTE: If you wanna use the VSCode

canalun 7 May 2, 2023
This is an Oracle database driver for Rust based on ODPI-C

Rust-oracle This is an Oracle database driver for Rust based on ODPI-C. Change Log See ChangeLog.md. Build-time Requirements C compiler. See Compile-t

Kubo Takehiro 138 Dec 23, 2022
An unofficial Logitech HID++>2.0 driver based on the original logiops by PixlOne

ruhroh An unofficial Logitech HID++>2.0 driver based on the original logiops by PixlOne Configuration Refer to the docs for details. The default locat

Matthew Wilks 3 Dec 11, 2022
An ArangoDB driver for Rust

Rincon Rincon is an ArangoDB driver for Rust. It enables low level access to ArangoDB in a typesafe and Rust idiomatic manner. The name Rincon is deri

Innoave 35 Mar 21, 2021
The official MongoDB Rust Driver

MongoDB Rust Driver This repository contains the officially supported MongoDB Rust driver, a client side library that can be used to interact with Mon

mongodb 1.1k Dec 30, 2022
TDS 7.2+ (mssql / Microsoft SQL Server) async driver for rust

Tiberius A native Microsoft SQL Server (TDS) client for Rust. Supported SQL Server versions Version Support level Notes 2019 Tested on CI 2017 Tested

Prisma 189 Dec 25, 2022
Native PostgreSQL driver for the Rust programming language

Rust-Postgres PostgreSQL support for Rust. postgres Documentation A native, synchronous PostgreSQL client. tokio-postgres Documentation A native, asyn

Steven Fackler 2.8k Jan 8, 2023