Mysql client library implemented in rust.

Overview

Gitter

Crates.io Build Status

mysql

This crate offers:

  • MySql database driver in pure rust;
  • connection pool.

Features:

  • macOS, Windows and Linux support;
  • TLS support via nativetls create;
  • MySql text protocol support, i.e. support of simple text queries and text result sets;
  • MySql binary protocol support, i.e. support of prepared statements and binary result sets;
  • support of multi-result sets;
  • support of named parameters for prepared statements;
  • optional per-connection cache of prepared statements;
  • support of MySql packets larger than 2^24;
  • support of Unix sockets and Windows named pipes;
  • support of custom LOCAL INFILE handlers;
  • support of MySql protocol compression;
  • support of auth plugins:
    • mysql_native_password - for MySql prior to v8;
    • caching_sha2_password - for MySql v8 and higher.

Installation

Put the desired version of the crate into the dependencies section of your Cargo.toml:

[dependencies]
mysql = "*"

Example

use mysql::*;
use mysql::prelude::*;

#[derive(Debug, PartialEq, Eq)]
struct Payment {
    customer_id: i32,
    amount: i32,
    account_name: Option<String>,
}

let url = "mysql://root:password@localhost:3307/db_name";

let pool = Pool::new(url)?;

let mut conn = pool.get_conn()?;

// Let's create a table for payments.
conn.query_drop(
    r"CREATE TEMPORARY TABLE payment (
        customer_id int not null,
        amount int not null,
        account_name text
    )")?;

let payments = vec![
    Payment { customer_id: 1, amount: 2, account_name: None },
    Payment { customer_id: 3, amount: 4, account_name: Some("foo".into()) },
    Payment { customer_id: 5, amount: 6, account_name: None },
    Payment { customer_id: 7, amount: 8, account_name: None },
    Payment { customer_id: 9, amount: 10, account_name: Some("bar".into()) },
];

// Now let's insert payments to the database
conn.exec_batch(
    r"INSERT INTO payment (customer_id, amount, account_name)
      VALUES (:customer_id, :amount, :account_name)",
    payments.iter().map(|p| params! {
        "customer_id" => p.customer_id,
        "amount" => p.amount,
        "account_name" => &p.account_name,
    })
)?;

// Let's select payments from database. Type inference should do the trick here.
let selected_payments = conn
    .query_map(
        "SELECT customer_id, amount, account_name from payment",
        |(customer_id, amount, account_name)| {
            Payment { customer_id, amount, account_name }
        },
    )?;

// Let's make sure, that `payments` equals to `selected_payments`.
// Mysql gives no guaranties on order of returned rows
// without `ORDER BY`, so assume we are lucky.
assert_eq!(payments, selected_payments);
println!("Yay!");

API Documentation

Please refer to the crate docs.

Basic structures

Opts

This structure holds server host name, client username/password and other settings, that controls client behavior.

URL-based connection string

Note, that you can use URL-based connection string as a source of an Opts instance. URL schema must be mysql. Host, port and credentials, as well as query parameters, should be given in accordance with the RFC 3986.

Examples:

let _ = Opts::from_url("mysql://localhost/some_db")?;
let _ = Opts::from_url("mysql://[::1]/some_db")?;
let _ = Opts::from_url("mysql://user:pass%[email protected]:3307/some_db?")?;

Supported URL parameters (for the meaning of each field please refer to the docs on Opts structure in the create API docs):

  • prefer_socket: true | false - defines the value of the same field in the Opts structure;
  • tcp_keepalive_time_ms: u32 - defines the value (in milliseconds) of the tcp_keepalive_time field in the Opts structure;
  • tcp_connect_timeout_ms: u64 - defines the value (in milliseconds) of the tcp_connect_timeout field in the Opts structure;
  • stmt_cache_size: u32 - defines the value of the same field in the Opts structure;
  • compress - defines the value of the same field in the Opts structure. Supported value are:
    • true - enables compression with the default compression level;
    • fast - enables compression with "fast" compression level;
    • best - enables compression with "best" compression level;
    • 1..9 - enables compression with the given compression level.
  • socket - socket path on UNIX, or pipe name on Windows.

OptsBuilder

It's a convenient builder for the Opts structure. It defines setters for fields of the Opts structure.

let opts = OptsBuilder::new()
    .user(Some("foo"))
    .db_name(Some("bar"));
let _ = Conn::new(opts)?;

Conn

This structure represents an active MySql connection. It also holds statement cache and metadata for the last result set.

Transaction

It's a simple wrapper on top of a routine, that starts with START TRANSACTION and ends with COMMIT or ROLLBACK.

use mysql::*;
use mysql::prelude::*;

let pool = Pool::new(get_opts())?;
let mut conn = pool.get_conn()?;

let mut tx = conn.start_transaction(TxOpts::default())?;
tx.query_drop("CREATE TEMPORARY TABLE tmp (TEXT a)")?;
tx.exec_drop("INSERT INTO tmp (a) VALUES (?)", ("foo",))?;
let val: Option<String> = tx.query_first("SELECT a from tmp")?;
assert_eq!(val.unwrap(), "foo");
// Note, that transaction will be rolled back implicitly on Drop, if not committed.
tx.rollback();

let val: Option<String> = conn.query_first("SELECT a from tmp")?;
assert_eq!(val, None);

Pool

It's a reference to a connection pool, that can be cloned and shared between threads.

use mysql::*;
use mysql::prelude::*;

use std::thread::spawn;

let pool = Pool::new(get_opts())?;

let handles = (0..4).map(|i| {
    spawn({
        let pool = pool.clone();
        move || {
            let mut conn = pool.get_conn()?;
            conn.exec_first::<u32, _, _>("SELECT ? * 10", (i,))
                .map(Option::unwrap)
        }
    })
});

let result: Result<Vec<u32>> = handles.map(|handle| handle.join().unwrap()).collect();

assert_eq!(result.unwrap(), vec![0, 10, 20, 30]);

Statement

Statement, actually, is just an identifier coupled with statement metadata, i.e an information about its parameters and columns. Internally the Statement structure also holds additional data required to support named parameters (see bellow).

use mysql::*;
use mysql::prelude::*;

let pool = Pool::new(get_opts())?;
let mut conn = pool.get_conn()?;

let stmt = conn.prep("DO ?")?;

// The prepared statement will return no columns.
assert!(stmt.columns().is_empty());

// The prepared statement have one parameter.
let param = stmt.params().get(0).unwrap();
assert_eq!(param.schema_str(), "");
assert_eq!(param.table_str(), "");
assert_eq!(param.name_str(), "?");

Value

This enumeration represents the raw value of a MySql cell. Library offers conversion between Value and different rust types via FromValue trait described below.

FromValue trait

This trait is reexported from mysql_common create. Please refer to its crate docs for the list of supported conversions.

Trait offers conversion in two flavours:

  • from_value(Value) -> T - convenient, but panicking conversion.

    Note, that for any variant of Value there exist a type, that fully covers its domain, i.e. for any variant of Value there exist T: FromValue such that from_value will never panic. This means, that if your database schema is known, than it's possible to write your application using only from_value with no fear of runtime panic.

  • from_value_opt(Value) -> Option<T> - non-panicking, but less convenient conversion.

    This function is useful to probe conversion in cases, where source database schema is unknown.

use mysql::*;
use mysql::prelude::*;

let via_test_protocol: u32 = from_value(Value::Bytes(b"65536".to_vec()));
let via_bin_protocol: u32 = from_value(Value::UInt(65536));
assert_eq!(via_test_protocol, via_bin_protocol);

let unknown_val = // ...

// Maybe it is a float?
let unknown_val = match from_value_opt::<f64>(unknown_val) {
    Ok(float) => {
        println!("A float value: {}", float);
        return Ok(());
    }
    Err(FromValueError(unknown_val)) => unknown_val,
};

// Or a string?
let unknown_val = match from_value_opt::<String>(unknown_val) {
    Ok(string) => {
        println!("A string value: {}", string);
        return Ok(());
    }
    Err(FromValueError(unknown_val)) => unknown_val,
};

// Screw this, I'll simply match on it
match unknown_val {
    val @ Value::NULL => {
        println!("An empty value: {:?}", from_value::<Option<u8>>(val))
    },
    val @ Value::Bytes(..) => {
        // It's non-utf8 bytes, since we already tried to convert it to String
        println!("Bytes: {:?}", from_value::<Vec<u8>>(val))
    }
    val @ Value::Int(..) => {
        println!("A signed integer: {}", from_value::<i64>(val))
    }
    val @ Value::UInt(..) => {
        println!("An unsigned integer: {}", from_value::<u64>(val))
    }
    Value::Float(..) => unreachable!("already tried"),
    val @ Value::Double(..) => {
        println!("A double precision float value: {}", from_value::<f64>(val))
    }
    val @ Value::Date(..) => {
        use mysql::chrono::NaiveDateTime;
        println!("A date value: {}", from_value::<NaiveDateTime>(val))
    }
    val @ Value::Time(..) => {
        use std::time::Duration;
        println!("A time value: {:?}", from_value::<Duration>(val))
    }
}

Row

Internally Row is a vector of Values, that also allows indexing by a column name/offset, and stores row metadata. Library offers conversion between Row and sequences of Rust types via FromRow trait described below.

FromRow trait

This trait is reexported from mysql_common create. Please refer to its crate docs for the list of supported conversions.

This conversion is based on the FromValue and so comes in two similar flavours:

  • from_row(Row) -> T - same as from_value, but for rows;
  • from_row_opt(Row) -> Option<T> - same as from_value_opt, but for rows.

Queryable trait offers implicit conversion for rows of a query result, that is based on this trait.

use mysql::*;
use mysql::prelude::*;

let mut conn = Conn::new(get_opts())?;

// Single-column row can be converted to a singular value:
let val: Option<String> = conn.query_first("SELECT 'foo'")?;
assert_eq!(val.unwrap(), "foo");

// Example of a mutli-column row conversion to an inferred type:
let row = conn.query_first("SELECT 255, 256")?;
assert_eq!(row, Some((255u8, 256u16)));

// The FromRow trait does not support to-tuple conversion for rows with more than 12 columns,
// but you can do this by hand using row indexing or `Row::take` method:
let row: Row = conn.exec_first("select 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12", ())?.unwrap();
for i in 0..row.len() {
    assert_eq!(row[i], Value::Int(i as i64));
}

// Some unknown row
let row: Row = conn.query_first(
    // ...
    # "SELECT 255, Null",
)?.unwrap();

for column in row.columns_ref() {
    // Cells in a row can be indexed by numeric index or by column name
    let column_value = &row[column.name_str().as_ref()];

    println!(
        "Column {} of type {:?} with value {:?}",
        column.name_str(),
        column.column_type(),
        column_value,
    );
}

Params

Represents parameters of a prepared statement, but this type won't appear directly in your code because binary protocol API will ask for T: Into<Params>, where Into<Params> is implemented:

  • for tuples of Into<Value> types up to arity 12;

    Note: singular tuple requires extra comma, e.g. ("foo",);

  • for IntoIterator<Item: Into<Value>> for cases, when your statement takes more than 12 parameters;

  • for named parameters representation (the value of the params! macro, described below).

use mysql::*;
use mysql::prelude::*;

let mut conn = Conn::new(get_opts())?;

// Singular tuple requires extra comma:
let row: Option<u8> = conn.exec_first("SELECT ?", (0,))?;
assert_eq!(row.unwrap(), 0);

// More than 12 parameters:
let row: Option<u8> = conn.exec_first(
    "SELECT CONVERT(? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ?, UNSIGNED)",
    (0..16).collect::<Vec<_>>(),
)?;
assert_eq!(row.unwrap(), 120);

Note: Please refer to the mysql_common crate docs for the list of types, that implements Into<Value>.

Serialized, Deserialized

Wrapper structures for cases, when you need to provide a value for a JSON cell, or when you need to parse JSON cell as a struct.

use mysql::*;
use mysql::prelude::*;

/// Serializable structure.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Example {
    foo: u32,
}

// Value::from for Serialized will emit json string.
let value = Value::from(Serialized(Example { foo: 42 }));
assert_eq!(value, Value::Bytes(br#"{"foo":42}"#.to_vec()));

// from_value for Deserialized will parse json string.
let structure: Deserialized<Example> = from_value(value);
assert_eq!(structure, Deserialized(Example { foo: 42 }));

QueryResult

It's an iterator over rows of a query result with support of multi-result sets. It's intended for cases when you need full control during result set iteration. For other cases Queryable provides a set of methods that will immediately consume the first result set and drop everything else.

This iterator is lazy so it won't read the result from server until you iterate over it. MySql protocol is strictly sequential, so Conn will be mutably borrowed until the result is fully consumed.

use mysql::*;
use mysql::prelude::*;

let mut conn = Conn::new(get_opts())?;

// This query will emit two result sets.
let mut result = conn.query_iter("SELECT 1, 2; SELECT 3, 3.14;")?;

let mut sets = 0;
while let Some(result_set) = result.next_set() {
    let result_set = result_set?;
    sets += 1;

    println!("Result set columns: {:?}", result_set.columns());
    println!(
        "Result set meta: {}, {:?}, {} {}",
        result_set.affected_rows(),
        result_set.last_insert_id(),
        result_set.warnings(),
        result_set.info_str(),
    );

    for row in result_set {
        match sets {
            1 => {
                // First result set will contain two numbers.
                assert_eq!((1_u8, 2_u8), from_row(row?));
            }
            2 => {
                // Second result set will contain a number and a float.
                assert_eq!((3_u8, 3.14), from_row(row?));
            }
            _ => unreachable!(),
        }
    }
}

assert_eq!(sets, 2);

Text protocol

MySql text protocol is implemented in the set of Queryable::query* methods. It's useful when your query doesn't have parameters.

Note: All values of a text protocol result set will be encoded as strings by the server, so from_value conversion may lead to additional parsing costs.

Examples:

let pool = Pool::new(get_opts())?;
let val = pool.get_conn()?.query_first("SELECT POW(2, 16)")?;

// Text protocol returns bytes even though the result of POW
// is actually a floating point number.
assert_eq!(val, Some(Value::Bytes("65536".as_bytes().to_vec())));

The TextQuery trait.

The TextQuery trait covers the set of Queryable::query* methods from the perspective of a query, i.e. TextQuery is something, that can be performed if suitable connection is given. Suitable connections are:

  • &Pool
  • Conn
  • PooledConn
  • &mut Conn
  • &mut PooledConn
  • &mut Transaction

The unique characteristic of this trait, is that you can give away the connection and thus produce QueryResult that satisfies 'static:

use mysql::*;
use mysql::prelude::*;

fn iter(pool: &Pool) -> Result<impl Iterator<Item=Result<u32>>> {
    let result = "SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3".run(pool)?;
    Ok(result.map(|row| row.map(from_row)))
}

let pool = Pool::new(get_opts())?;

let it = iter(&pool)?;

assert_eq!(it.collect::<Result<Vec<u32>>>()?, vec![1, 2, 3]);

Binary protocol and prepared statements.

MySql binary protocol is implemented in prep, close and the set of exec* methods, defined on the Queryable trait. Prepared statements is the only way to pass rust value to the MySql server. MySql uses ? symbol as a parameter placeholder and it's only possible to use parameters where a single MySql value is expected. For example:

let pool = Pool::new(get_opts())?;
let val = pool.get_conn()?.exec_first("SELECT POW(?, ?)", (2, 16))?;

assert_eq!(val, Some(Value::Double(65536.0)));

Statements

In MySql each prepared statement belongs to a particular connection and can't be executed on another connection. Trying to do so will lead to an error. The driver won't tie statement to its connection in any way, but one can look on to the connection id, contained in the Statement structure.

let pool = Pool::new(get_opts())?;

let mut conn_1 = pool.get_conn()?;
let mut conn_2 = pool.get_conn()?;

let stmt_1 = conn_1.prep("SELECT ?")?;

// stmt_1 is for the conn_1, ..
assert!(stmt_1.connection_id() == conn_1.connection_id());
assert!(stmt_1.connection_id() != conn_2.connection_id());

// .. so stmt_1 will execute only on conn_1
assert!(conn_1.exec_drop(&stmt_1, ("foo",)).is_ok());
assert!(conn_2.exec_drop(&stmt_1, ("foo",)).is_err());

Statement cache

Conn will manage the cache of prepared statements on the client side, so subsequent calls to prepare with the same statement won't lead to a client-server roundtrip. Cache size for each connection is determined by the stmt_cache_size field of the Opts structure. Statements, that are out of this boundary will be closed in LRU order.

Statement cache is completely disabled if stmt_cache_size is zero.

Caveats:

  • disabled statement cache means, that you have to close statements yourself using Conn::close, or they'll exhaust server limits/resources;

  • you should be aware of the max_prepared_stmt_count option of the MySql server. If the number of active connections times the value of stmt_cache_size is greater, than you could receive an error while prepareing another statement.

Named parameters

MySql itself doesn't have named parameters support, so it's implemented on the client side. One should use :name as a placeholder syntax for a named parameter.

Named parameters may be repeated within the statement, e.g SELECT :foo, :foo will require a single named parameter foo that will be repeated on the corresponding positions during statement execution.

One should use the params! macro to build a parameters for execution.

Note: Positional and named parameters can't be mixed within the single statement.

Examples:

let pool = Pool::new(get_opts())?;

let mut conn = pool.get_conn()?;
let stmt = conn.prep("SELECT :foo, :bar, :foo")?;

let foo = 42;

let val_13 = conn.exec_first(&stmt, params! { "foo" => 13, "bar" => foo })?.unwrap();
// Short syntax is available when param name is the same as variable name:
let val_42 = conn.exec_first(&stmt, params! { foo, "bar" => 13 })?.unwrap();

assert_eq!((foo, 13, foo), val_42);
assert_eq!((13, foo, 13), val_13);

BinQuery and BatchQuery traits.

BinQuery and BatchQuery traits covers the set of Queryable::exec* methods from the perspective of a query, i.e. BinQuery is something, that can be performed if suitable connection is given (see TextQuery section for the list of suitable connections).

As with the TextQuery you can give away the connection and acquire QueryResult that satisfies 'static.

BinQuery is for prepared statements, and prepared statements requires a set of parameters, so BinQuery is implemented for QueryWithParams structure, that can be acquired, using WithParams trait.

Example:

use mysql::*;
use mysql::prelude::*;

let pool = Pool::new(get_opts())?;

let result: Option<(u8, u8, u8)> = "SELECT ?, ?, ?"
    .with((1, 2, 3)) // <- WithParams::with will construct an instance of QueryWithParams
    .first(&pool)?;  // <- QueryWithParams is executed on the given pool

assert_eq!(result.unwrap(), (1, 2, 3));

The BatchQuery trait is a helper for batch statement execution. It's implemented for QueryWithParams where parameters is an iterator over parameters:

use mysql::*;
use mysql::prelude::*;

let pool = Pool::new(get_opts())?;
let mut conn = pool.get_conn()?;

"CREATE TEMPORARY TABLE batch (x INT)".run(&mut conn)?;
"INSERT INTO batch (x) VALUES (?)"
    .with((0..3).map(|x| (x,))) // <- QueryWithParams constructed with an iterator
    .batch(&mut conn)?;         // <- batch execution is preformed here

let result: Vec<u8> = "SELECT x FROM batch".fetch(conn)?;

assert_eq!(result, vec![0, 1, 2]);

Queryable

The Queryable trait defines common methods for Conn, PooledConn and Transaction. The set of basic methods consts of:

  • query_iter - basic methods to execute text query and get QueryResult;
  • prep - basic method to prepare a statement;
  • exec_iter - basic method to execute statement and get QueryResult;
  • close - basic method to close the statement;

The trait also defines the set of helper methods, that is based on basic methods. These methods will consume only the first result set, other result sets will be dropped:

  • {query|exec} - to collect the result into a Vec<T: FromRow>;
  • {query|exec}_first - to get the first T: FromRow, if any;
  • {query|exec}_map - to map each T: FromRow to some U;
  • {query|exec}_fold - to fold the set of T: FromRow to a single value;
  • {query|exec}_drop - to immediately drop the result.

The trait also defines the exec_batch function, which is a helper for batch statement execution.

Changelog

Available here

License

Licensed under either of

at your option.

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
  • Large conditional compilation refactoring

    Large conditional compilation refactoring

    I've created this PR as a first step to cross-platform compilation without features patching. This implementation of IO is flexible and don't need a lot of duplications.

    opened by DenisKolodin 18
  • Pooled connections are dying after timeout

    Pooled connections are dying after timeout

    I use AWS RDS, where default timeout connection is 8 hours. After 8 hours one of pooled connections is dying because of this limit and ping() can't detect it (or reset() doesn't work as expected with really dead connections).

    opened by e-oz 15
  • URL ParseError { invalid port number } if password contains

    URL ParseError { invalid port number } if password contains "?"

    let pool = mysql::Pool::new("mysql://user:password?@localhost:3306/test").unwrap();

    throws the following error:

    thread 'main' panicked at 'URL ParseError { invalid port number }', 
    ...\mysql-7.1.2\src\conn\opts.rs:580
    

    It doesn't matter at which position the "?" is, it will always throw the error. My specs:

    D:\Rust_Training>rustc --version
    rustc 1.12.1 (d4f39402a 2016-10-19)
    
    D:\Rust_Training>cargo --version
    cargo 0.13.0-nightly (109cb7c 2016-08-19)
    
     Fresh mysql v7.1.2
    
    opened by RayFinney 13
  • Unexpected Packet

    Unexpected Packet

    Azure MySQL running 5.7.21 connecting over SSH tunnel error Crate version 14.1.1 DriverError { Unexpected packet }

    SSL is enabled with a CA Cert Key. Verify Peer is set to false.

    I'm not sure if it is relevant but in my Go project I have to set tls=skip-verify&allowNativePasswords=true

    opened by glademiller 12
  • Problem with parallel tests & muliple statements

    Problem with parallel tests & muliple statements

    Hello, I'm having trouble testing a multi-statement struct. I have a stream of elements and for each I have to execute two Statements. All of my existing functions are written to work with a &mut PooledConn because my tests will create a virtual table, so each of them can (as per cargo) run parallel without sharing data. As you specified yourself you expect people to use a pool for multiple statements, but because of the threading of my tests I can't use a pool. Is there a better approach or am I missing something ? This approach here is un-testable as the pool will give each one another connection ( and block the test indefinitely when I force a 1min, 1max pool)

    pub struct ImportAccountInserter<'a> {
        stm_member_names: Stmt<'a>,
        stm_member_addition: Stmt<'a>,
        comment_addition: &'a str,
        date_name_insert: &'a NaiveDateTime
    }
    
    impl<'a> ImportAccountInserter<'a> {
        /// New Import Account Inserter
        /// comment_addition: appended to comment on insertion (`imported account`)
        /// date_name_insert: date to use for name insertion & update field
        pub fn new(pool: &'a Pool, comment_addition: &'a str, date_name_insert: &'a NaiveDateTime) -> Result<ImportAccountInserter<'a>,Error> {
            Ok(ImportAccountInserter {
                stm_member_names: pool.prepare("INSERT IGNORE INTO `member_names` (`id`,`name`,`date`,`updated`) VALUES (?,?,?,?)")?,
                stm_member_addition: pool.prepare("INSERT IGNORE INTO `member_addition` (`id`,`name`,`vip`,`comment`) VALUES (?,?,?,?)`")?,
                comment_addition,
                date_name_insert
            })
        }
        
        pub fn insert_account(&mut self, acc: &import::ImportAccount) -> Result<(),Error> {
            self.stm_member_names.execute((acc.id,&acc.name,self.date_name_insert,self.date_name_insert
            ))?;
            self.stm_member_addition.execute((acc.id,&acc.vname,acc.vip,
                format!("{}{}",self.comment_addition,acc.comment)
            ))?;
            Ok(())
        }
    }
    

    Regards, 0xpr03

    Edit: sorry, currently on the train

    opened by 0xpr03 10
  • Default queries after connecting

    Default queries after connecting

    Hi! Some of the libraries emulates mysql protocol for easy api implementation. Such of them is sphinxsearch. Their daemon runs like mysql but it supports limited set of queries and operations.

    I found that the only "default" query after connection is getting "max_allowed_packet" value right after handshake (mod.rs:1553). It brokes all the logic and connection fails because sphinxsearch does not know such query.

    Is it possible to add something like no_default_queries : bool into options. When it set to true no autogenerated queries will be performed from library side. If it's okay for you I can make pull request with changes.

    opened by max-frai 10
  • Please remove unsafe code

    Please remove unsafe code

    In source code I found just 1 kind of unsafe usage - FromRow implementation. I tried to remove it (along with mem::forget) and code compiles successfully. Please consider to remove this part - Rust will clean up memory itself, I believe.

    opened by e-oz 10
  • Get Column Value by name?

    Get Column Value by name?

    Hello, i was wondering if i could actually get the value from a column. I know that row["column_name"] exists, but that returns a Value, which then when i use from_value on it, i keep getting a Value does not implement Copy. Any fixes?

    opened by Syn9673 9
  • Add support for supplying root cert in .pem format

    Add support for supplying root cert in .pem format

    Add support for supplying root cert in .pem format Right now, there is only support for .der format. .pem is another popular format, and it would be great if mysql crate could support it directly for root certificate without a need to converting it to .der, as is currently recommended.

    opened by yerke 8
  • Iterating result is slow

    Iterating result is slow

    I have a query with 2000 rows, iterating result takes ~10ms when compiled with --release and ~30ms when not optimized

    let result = conn.query(sql)?;
    let db_start_time = Instant::now();
    for mut row_res in result {
      // nothing
    }
    println!("DB aggregate complete: {} ms", db_start_time.elapsed().as_millis());
    

    Row look like this:

    Ok(
        Row {
            id: Bytes(
                "15671236..",
            ),
            txn_ref: Bytes(
                "a32c8457..",
            ),
            status: Bytes(
                "VERIFIED",
            ),
            amount: Bytes(
                "24000.00",
            ),
            already_verified: Null,
        },
    )
    

    Is it expected?

    opened by Paxa 8
  • Allow to pass &str or String

    Allow to pass &str or String

    This PR implements From for Into<String> on Opts, i.e. one can use either &str or String (or anything else that implements Into<String>) as argument type for Pool::new.

    opened by klingtnet 8
  • Support on `MYSQL_TYPE_TEXT`

    Support on `MYSQL_TYPE_TEXT`

    Currently if the column is specified as TEXT type, the column_type() result we get is MYSQL_TYPE_BLOB, which is the same with BLOB type, and thus cannot differentiate binary and non-binary strings.

    Should we add new types like MYSQL_TYPE_TEXT, or is there a way workaround?

    opened by wangxiaoying 0
  • disable-auto-rehash?

    disable-auto-rehash?

    Is there a way to add this connection attribute on connection intialization? it would make initial connections a bit faster.. doesn't look like it's currently supported..

    opened by cmollissony 2
  • Add WASI suuport.

    Add WASI suuport.

    Overview

    This PR will add WASI suuport to this crate. Users can use this crate in WebAssembly via WasmEdge.

    Missing parts

    Thead suuport

    There's no thread suuport in WASI. So I disable related tests for now.

    TLS suuport

    TLS support is still under development which is tracked in this issue. I commented out the native-tls in the feature list as a workaround.

    Signed-off-by: Tricster [email protected]

    opened by MediosZ 0
  • Initializate Pool without connect

    Initializate Pool without connect

    let pool = Pool::new(opts)?; This, tries to connect to database.., is it possible initialize an empty Pool?? Like let pool = Pool::default();

    Then later, for example with a connection button event the Pool finally stay connected.

    opened by realtica 1
  • Mysql 21.0.2 incompatible with poem-openapi 1.0.31

    Mysql 21.0.2 incompatible with poem-openapi 1.0.31

    Hey there, I would like to use Poem with Mysql, but they seem to be using incompatible bitvec / funty versions. On build I get a error[E0034]: multiple applicable items in scope --> C:\Users\local\.cargo\registry\src\github.com-1ecc6299db9ec823\bitvec-0.19.4\src\field.rs:307:25.

    This problem seems to be known in funty and can apparently be solved by updating all dependencies to funty 2.0.0 (or at least the same version.) Unfortunately it is nested quite deeply in the dependencies.

    Example Toml, full build output, and cargo tree output uploaded here: https://gist.github.com/Christoph-AK/366e6c39c24976d5bf48064e658b6670

    Can this be solved from this crate?

    opened by Christoph-AK 2
Releases(v23.0.1)
  • v23.0.1(Dec 10, 2022)

  • v23.0.0(Nov 18, 2022)

    What's Changed

    • breaking bump mysql_common to 0.29 by @blackbeam in #338 (see mysql_common release notes)
    • new default-rustls and minimal features (see Crate Features section of the README)

    Full Changelog: https://github.com/blackbeam/rust-mysql-simple/compare/v22.2.0...v23.0.0

    Source code(tar.gz)
    Source code(zip)
  • v22.2.0(Jun 28, 2022)

    What's new

    • @fulara added two new options into the Opts structure & connection URL (see #310):
      • tcp_keepalive_probe_interval_secs – TCP keep alive interval between subsequent probes
      • tcp_keepalive_probe_count – TCP keep alive probe count
    • {Conn, Pool}::new now supports literal URLs. Please note, that I accidentally violated the semver here 🙇.

    Fixes

    • #318 fixes a bug in Conn::reset found and reported by @fulara in #317

    Other changes

    • fix some typos by @cuishuang in https://github.com/blackbeam/rust-mysql-simple/pull/321
    • nix dependency is removed by @rtzoeller in https://github.com/blackbeam/rust-mysql-simple/pull/322
    • Fix docs for creating a connection from URL by @Zomtir in https://github.com/blackbeam/rust-mysql-simple/pull/327

    New Contributors

    • @cuishuang made their first contribution in https://github.com/blackbeam/rust-mysql-simple/pull/321
    • @rtzoeller made their first contribution in https://github.com/blackbeam/rust-mysql-simple/pull/322
    Source code(tar.gz)
    Source code(zip)
  • v22.1.0(Feb 16, 2022)

    What's new

    • @fulara added a way to control TCP_USER_TIMEOUT for a connection using the new tcp_user_timeout option (see #307). Please note that this is only for target_os = "linux".
    • @fulara implemented AsRawFd for Conn (see #307)

    Fixes

    • 3c4d4ee fixes the infinite loop in QueryResult, that may be triggered by a connectivity error (reported by @fulara in #306)

    Other

    • Conn::drop behavior is now mentioned in the docs (see #308)
    • There is now a test that asserts that TiDB connections are properly reused (see #309)
    Source code(tar.gz)
    Source code(zip)
  • v22.0.0(Dec 29, 2021)

    What's new

    • native-tls is now optional (thanks to @TheDutchMC) and the new rustls-based TLS backend added to the library. Please see the "SSL Support" section in the crate docs.
    • now the buffer pool is lock-free and optional (controlled by the buffer-pool feature). Please see the "Buffer Pool" section in the crate docs.

    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
    • chrono, time and uuid reexports are removed

    API changes

    • QueryResult::next_set renamed to QueryResult::iter (QueryResult::next_set is still available but deprecated). Docstring is updated to clarify the behavior.

    Fixes

    • turns out previous versions wasn't able to properly bind to the specified bind address in some circumstances. This is now fixed.

    Internal improvements

    • @amv-dev added some optimizations for the Pool (see #269)

    Bumped dependenices

    • pem to 1.0.1
    • lru to 0.7 (by @Roguelazer)
    Source code(tar.gz)
    Source code(zip)
  • v21.0.2(Oct 11, 2021)

  • v21.0.1(Jul 19, 2021)

  • v21.0.0(Jul 5, 2021)

    New features:

    Internal improvements:

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

    Other:

    • io-enum bumped to v1 (by @taiki-e)
    • socket2 library bumped to v0.4 (by @Thomasdezeeuw)
    • various documentation improvements (by @Zomtir, @prewriter, @2efPer)
    Source code(tar.gz)
    Source code(zip)
  • v20.1.0(Nov 20, 2020)

    Changes:

    • multiple pem certs are now allowed in root_cert_path (see #252, #255)
    • new OptsBuilder::from_hash_map was introduced by @hpca01 (see #232 ,#256)
    • typos fixes (by @toothbrush7777777)
    Source code(tar.gz)
    Source code(zip)
  • v20.0.1(Oct 4, 2020)

  • v20.0.0(Sep 28, 2020)

  • v19.0.1(Aug 28, 2020)

    • it is now possible to use pem certificates in SslOpts::with_root_cert_path (by @yerke, see #248);
    • it is now possible to override program_name connection attribute (by @yumm007, see #242);
    • various fixes for docs (by @yerke, see #246, #247).
    Source code(tar.gz)
    Source code(zip)
  • v19.0.0(Aug 24, 2020)

    • mysql_common was updated to v0.22.2,
    • tests for blackbeam/mysql_async#107 was added,
    • pool exhaustion was fixed by @SpaceManiac (#226),
    • the net2 crate was removed in favor of the socket2 crate (#233),
    • the Protocol trait was exported by @mguillemot-elt (#235),
    • various fixes in documentation (thanks to @dbanty, @nbrady-techempower, @Elykz, @eldad)
    • #244 and related issues were fixed (hopefully)
    Source code(tar.gz)
    Source code(zip)
  • v18.2.0(Apr 7, 2020)

  • v18.1.0(Mar 25, 2020)

    Additions:

    • new methods Transaction::{last_insert_id, affected_rows, warnings, info_ref, info_str}, Conn::{warnings, info_ref, info_str} (see #211)

    Internal improvements:

    • Conn size reduced to 8 bytes.
    Source code(tar.gz)
    Source code(zip)
  • v18.0.0(Mar 1, 2020)

    Breaking changes:

    • Conn::{query, first, *_exec, ...} were removed in favor of Queryable trait (see crate docs);
    • Pool::{prepare, *_exec, ...} were removed in favor of TextQuery and BinQuery traits (see crate docs);
    • helpers for batch statement execution were added in forms of Queryable::batch_exec method and BatchQuery trait (see crate docs);
    • Stmt was removed in favor of the new Statement structure, which is a thin wrapper around statement identifier. There are few caveats, please consult the corresponding section in the crate docs;
    • OptsBuilder and SslOpts methods now takes self by value;
    • QueryResult interface was altered;
    • start_transaction now takes new TxOpts structure;

    Fixes #189, #198, #199, #203, #204.

    Source code(tar.gz)
    Source code(zip)
  • v17.0.0(Nov 4, 2019)

    Changes:

    • mysql_common crate was updated;
    • ssl feature was removed, TLS support now implemented using native-tls (breaking);
    • compres option was changed (see docs on OptsBuilder::compress);
    • #190 was reported and fixed by @evenyag.
    Source code(tar.gz)
    Source code(zip)
  • v16.1.0(Aug 18, 2019)

    • mysql_common updated to v0.18.0
    • @killme2008 found and fixed #176
    • rustc-serialize support was removed (#184)
    • #182 was fixed
    • socket parameter was added to connection URL (#181)
    Source code(tar.gz)
    Source code(zip)
  • v16.0.2(Apr 30, 2019)

  • v15.1.2(Apr 30, 2019)

  • v16.0.1(Apr 23, 2019)

  • v15.1.1(Apr 23, 2019)

  • v0.16.0(Apr 21, 2019)

  • v15.1.0(Feb 16, 2019)

  • v14.2.0(Dec 9, 2018)

  • v14.1.0(Sep 5, 2018)

  • v14.0.0(Jun 30, 2018)

  • v13.0.0(May 17, 2018)

    • compression support was added. Use the compress function on OptsBuilder or the compress parameter of a connection URL (fixes #130).
    • added a way to set additional capabilities for connection. See docs on OptsBuilder::additional_capabilities (fixes #142)
    Source code(tar.gz)
    Source code(zip)
  • v12.3.0(Mar 16, 2018)

  • v.12.2.0(Feb 25, 2018)

Owner
Anatoly I
Writing Rust since 2014.
Anatoly I
🧰 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
Asyncronous Rust Mysql driver based on Tokio.

mysql-async Tokio based asynchronous MySql client library for rust programming language. Installation Library hosted on crates.io. [dependencies] mysq

Anatoly I 292 Dec 30, 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
cogo rust coroutine database driver (Mysql,Postgres,Sqlite)

cdbc Coroutine Database driver Connectivity.based on cogo High concurrency,based on coroutine No Future<'q,Output=*>,No async fn, No .await , no Poll*

co-rs 10 Nov 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
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
A minecraft-like multi version client implemented in Rust.

Leafish Multi-version Minecraft-compatible client written in Rust, forked from Stevenarella. Chat Chat takes place on Matrix and Discord. The channels

null 617 Dec 27, 2022
Affine-client is a client for AFFINE based on Tauri

Affine Client affine-client is a client for AFFINE based on Tauri Supported Platforms Windows Linux MacOS Download https://github.com/m1911star/affine

Horus 216 Dec 25, 2022
Redis re-implemented in Rust.

rsedis Redis re-implemented in Rust. Why? To learn Rust. Use Cases rsedis does not rely on UNIX-specific features. Windows users can run it as a repla

Sebastian Waisbrot 1.6k Jan 6, 2023
Raft distributed consensus algorithm implemented in Rust.

Raft Problem and Importance When building a distributed system one principal goal is often to build in fault-tolerance. That is, if one particular nod

TiKV Project 2.3k Dec 28, 2022
Sharded, concurrent mini redis that support http interface implemented in rust

Rudis A mini version of redis server that provides http interface implemented in Rust. The in-memorry kv-storage is sharded and concurrent safe. Inspi

Lorenzo Cao 43 May 30, 2023
CouchDB client-side library for the Rust programming language

Chill Chill is a client-side CouchDB library for the Rust programming language, available on crates.io. It targets Rust Stable. Chill's three chief de

null 35 Jun 26, 2022
An etcd client library for Rust.

etcd An etcd client library for Rust. etcd on crates.io Documentation for the latest crates.io release Running the tests Install Docker and Docker Com

Jimmy Cuadra 138 Dec 27, 2022
Skytable rust client support library for the bb8 connection pool

bb8-skytable Skytable rust client support library for the bb8 connection pool. Heavily based on bb8-redis Basic usage example use bb8_skytable::{

null 3 Sep 18, 2021
CouchDB client library for the Rust programming language

CouchDB This project is reborn! As of its v0.6.0 release, the couchdb crate has new life as a toolkit instead of providing a full-blown client. In a n

null 20 Jul 17, 2021