2014-08-15 06:05:11 +00:00
|
|
|
# Rust-Postgres
|
2013-09-03 06:19:03 +00:00
|
|
|
A native PostgreSQL driver for Rust.
|
|
|
|
|
2014-10-26 20:11:14 +00:00
|
|
|
Documentation is available at https://sfackler.github.io/doc/postgres
|
2013-09-30 04:21:00 +00:00
|
|
|
|
2013-10-08 06:03:05 +00:00
|
|
|
[![Build Status](https://travis-ci.org/sfackler/rust-postgres.png?branch=master)](https://travis-ci.org/sfackler/rust-postgres)
|
|
|
|
|
2014-12-14 20:43:53 +00:00
|
|
|
You can integrate Rust-Postgres into your project through the [releases on crates.io](https://crates.io/crates/postgres):
|
2014-11-07 06:54:57 +00:00
|
|
|
```toml
|
|
|
|
# Cargo.toml
|
2014-12-07 20:56:41 +00:00
|
|
|
[dependencies]
|
2014-12-14 20:43:53 +00:00
|
|
|
postgres = "0.2"
|
2014-11-07 06:54:57 +00:00
|
|
|
```
|
|
|
|
|
2014-08-15 06:05:11 +00:00
|
|
|
## Overview
|
2013-09-03 06:19:03 +00:00
|
|
|
Rust-Postgres is a pure-Rust frontend for the popular PostgreSQL database. It
|
|
|
|
exposes a high level interface in the vein of JDBC or Go's `database/sql`
|
|
|
|
package.
|
|
|
|
```rust
|
2014-02-16 02:11:23 +00:00
|
|
|
extern crate postgres;
|
2014-03-09 07:37:31 +00:00
|
|
|
extern crate time;
|
2013-09-03 06:19:03 +00:00
|
|
|
|
2014-03-09 07:37:31 +00:00
|
|
|
use time::Timespec;
|
2013-10-01 07:01:54 +00:00
|
|
|
|
2014-11-17 21:46:33 +00:00
|
|
|
use postgres::{Connection, SslMode};
|
2013-09-03 06:19:03 +00:00
|
|
|
|
|
|
|
struct Person {
|
|
|
|
id: i32,
|
2014-05-26 03:39:06 +00:00
|
|
|
name: String,
|
2013-10-01 07:01:54 +00:00
|
|
|
time_created: Timespec,
|
2014-04-08 16:59:45 +00:00
|
|
|
data: Option<Vec<u8>>
|
2013-09-03 06:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2014-11-17 21:46:33 +00:00
|
|
|
let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None)
|
2014-11-01 23:38:52 +00:00
|
|
|
.unwrap();
|
2013-09-03 06:19:03 +00:00
|
|
|
|
2013-12-29 03:27:20 +00:00
|
|
|
conn.execute("CREATE TABLE person (
|
2013-10-01 07:01:54 +00:00
|
|
|
id SERIAL PRIMARY KEY,
|
|
|
|
name VARCHAR NOT NULL,
|
|
|
|
time_created TIMESTAMP NOT NULL,
|
|
|
|
data BYTEA
|
2014-11-25 20:44:42 +00:00
|
|
|
)", &[]).unwrap();
|
2013-09-03 06:19:03 +00:00
|
|
|
let me = Person {
|
|
|
|
id: 0,
|
2014-10-18 18:17:12 +00:00
|
|
|
name: "Steven".into_string(),
|
2013-10-01 07:01:54 +00:00
|
|
|
time_created: time::get_time(),
|
2013-09-03 06:19:03 +00:00
|
|
|
data: None
|
|
|
|
};
|
2013-12-29 03:27:20 +00:00
|
|
|
conn.execute("INSERT INTO person (name, time_created, data)
|
2013-09-03 06:19:03 +00:00
|
|
|
VALUES ($1, $2, $3)",
|
2014-08-30 09:57:46 +00:00
|
|
|
&[&me.name, &me.time_created, &me.data]).unwrap();
|
2013-09-03 06:19:03 +00:00
|
|
|
|
2014-03-28 04:08:22 +00:00
|
|
|
let stmt = conn.prepare("SELECT id, name, time_created, data FROM person")
|
|
|
|
.unwrap();
|
2014-11-25 20:44:42 +00:00
|
|
|
for row in stmt.query(&[]).unwrap() {
|
2013-09-03 06:19:03 +00:00
|
|
|
let person = Person {
|
2014-10-26 06:43:59 +00:00
|
|
|
id: row.get(0),
|
|
|
|
name: row.get(1),
|
|
|
|
time_created: row.get(2),
|
|
|
|
data: row.get(3)
|
2013-09-03 06:19:03 +00:00
|
|
|
};
|
2013-10-01 07:01:54 +00:00
|
|
|
println!("Found person {}", person.name);
|
2013-09-03 06:19:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2014-08-15 06:05:11 +00:00
|
|
|
## Requirements
|
2014-12-14 20:57:52 +00:00
|
|
|
* **Rust** - Rust-Postgres is developed against the nightly releases on
|
2013-09-03 06:19:03 +00:00
|
|
|
http://www.rust-lang.org.
|
|
|
|
|
|
|
|
* **PostgreSQL 7.4 or later** - Rust-Postgres speaks version 3 of the
|
|
|
|
PostgreSQL protocol, which corresponds to versions 7.4 and later. If your
|
|
|
|
version of Postgres was compiled in the last decade, you should be okay.
|
|
|
|
|
2014-08-15 06:05:11 +00:00
|
|
|
## Usage
|
2013-09-03 06:19:03 +00:00
|
|
|
|
2014-08-15 06:05:11 +00:00
|
|
|
### Connecting
|
2013-09-03 06:19:03 +00:00
|
|
|
Connect to a Postgres server using the standard URI format:
|
|
|
|
```rust
|
2014-11-01 23:31:06 +00:00
|
|
|
let conn = try!(Connection::connect("postgres://user:pass@host:port/database?arg1=val1&arg2=val2",
|
2014-11-17 21:52:59 +00:00
|
|
|
&SslMode::None));
|
2013-09-03 06:19:03 +00:00
|
|
|
```
|
|
|
|
`pass` may be omitted if not needed. `port` defaults to `5432` and `database`
|
2013-11-06 06:04:12 +00:00
|
|
|
defaults to the value of `user` if not specified. The driver supports `trust`,
|
|
|
|
`password`, and `md5` authentication.
|
2013-09-03 06:19:03 +00:00
|
|
|
|
2014-05-15 05:23:57 +00:00
|
|
|
Unix domain sockets can be used as well. The `host` portion of the URI should be
|
|
|
|
set to the absolute path to the directory containing the socket file. Since `/`
|
|
|
|
is a reserved character in URLs, the path should be URL encoded.
|
|
|
|
```rust
|
2014-11-17 21:52:59 +00:00
|
|
|
let conn = try!(Connection::connect("postgres://postgres@%2Frun%2Fpostgres", &SslMode::None));
|
2014-05-15 05:23:57 +00:00
|
|
|
```
|
|
|
|
Paths which contain non-UTF8 characters can be handled in a different manner;
|
|
|
|
see the documentation for details.
|
|
|
|
|
2014-08-15 06:05:11 +00:00
|
|
|
### Statement Preparation
|
2013-09-03 06:19:03 +00:00
|
|
|
Prepared statements can have parameters, represented as `$n` where `n` is an
|
|
|
|
index into the parameter array starting from 1:
|
|
|
|
```rust
|
2014-03-28 04:20:04 +00:00
|
|
|
let stmt = try!(conn.prepare("SELECT * FROM foo WHERE bar = $1 AND baz = $2"));
|
2013-09-03 06:19:03 +00:00
|
|
|
```
|
|
|
|
|
2014-08-15 06:05:11 +00:00
|
|
|
### Querying
|
2013-12-29 03:27:20 +00:00
|
|
|
A prepared statement can be executed with the `query` and `execute` methods.
|
2013-09-03 06:19:03 +00:00
|
|
|
Both methods take an array of parameters to bind to the query represented as
|
2013-12-29 03:27:20 +00:00
|
|
|
`&ToSql` trait objects. `execute` returns the number of rows affected by the
|
2013-09-03 06:19:03 +00:00
|
|
|
query (or 0 if not applicable):
|
2013-09-03 06:23:58 +00:00
|
|
|
```rust
|
2014-05-19 04:23:53 +00:00
|
|
|
let stmt = try!(conn.prepare("UPDATE foo SET bar = $1 WHERE baz = $2"));
|
2014-08-30 09:57:46 +00:00
|
|
|
let updates = try!(stmt.execute(&[&1i32, &"biz"]));
|
2013-09-03 06:19:03 +00:00
|
|
|
println!("{} rows were updated", updates);
|
|
|
|
```
|
2013-11-06 05:31:24 +00:00
|
|
|
`query` returns an iterator over the rows returned from the database. The
|
2013-12-03 03:53:40 +00:00
|
|
|
fields in a row can be accessed either by their indices or their column names,
|
2014-06-30 05:53:03 +00:00
|
|
|
though access by index is more efficient. Unlike statement parameters, result
|
|
|
|
columns are zero-indexed.
|
2013-09-03 06:19:03 +00:00
|
|
|
```rust
|
2014-03-28 04:20:04 +00:00
|
|
|
let stmt = try!(conn.prepare("SELECT bar, baz FROM foo"));
|
2014-11-25 20:44:42 +00:00
|
|
|
for row in try!(stmt.query(&[])) {
|
2014-10-26 06:49:13 +00:00
|
|
|
let bar: i32 = row.get(0);
|
2014-07-24 16:11:53 +00:00
|
|
|
let baz: String = row.get("baz");
|
2013-09-03 06:19:03 +00:00
|
|
|
println!("bar: {}, baz: {}", bar, baz);
|
|
|
|
}
|
|
|
|
```
|
2014-11-01 23:38:52 +00:00
|
|
|
In addition, `Connection` has a utility `execute` method which is useful if a
|
|
|
|
statement is only going to be executed once:
|
2013-09-03 06:19:03 +00:00
|
|
|
```rust
|
2014-03-28 04:20:04 +00:00
|
|
|
let updates = try!(conn.execute("UPDATE foo SET bar = $1 WHERE baz = $2",
|
2014-08-30 09:57:46 +00:00
|
|
|
&[&1i32, &"biz"]));
|
2013-09-03 06:19:03 +00:00
|
|
|
println!("{} rows were updated", updates);
|
|
|
|
```
|
|
|
|
|
2014-08-15 06:05:11 +00:00
|
|
|
### Transactions
|
2013-10-14 01:58:31 +00:00
|
|
|
The `transaction` method will start a new transaction. It returns a
|
2014-11-01 23:31:06 +00:00
|
|
|
`Transaction` object which has the functionality of a
|
|
|
|
`Connection` as well as methods to control the result of the
|
2013-10-14 01:58:31 +00:00
|
|
|
transaction:
|
2013-09-03 06:19:03 +00:00
|
|
|
```rust
|
2014-03-28 04:20:04 +00:00
|
|
|
let trans = try!(conn.transaction());
|
|
|
|
try!(trans.execute(...));
|
|
|
|
let stmt = try!(trans.prepare(...));
|
2013-09-03 06:19:03 +00:00
|
|
|
|
2013-12-05 05:32:13 +00:00
|
|
|
if the_coast_is_clear {
|
|
|
|
trans.set_commit();
|
2013-09-03 06:19:03 +00:00
|
|
|
}
|
2013-12-05 05:32:13 +00:00
|
|
|
|
2014-07-26 05:42:24 +00:00
|
|
|
try!(trans.finish());
|
2013-09-03 06:19:03 +00:00
|
|
|
```
|
2014-11-01 23:38:52 +00:00
|
|
|
The transaction will be active until the `Transaction` object falls out of
|
|
|
|
scope. A transaction will roll back by default. Nested transactions are
|
2013-10-14 01:58:31 +00:00
|
|
|
supported via savepoints.
|
2013-09-03 06:19:03 +00:00
|
|
|
|
2014-08-15 06:05:11 +00:00
|
|
|
### Type Correspondence
|
2013-09-03 06:19:03 +00:00
|
|
|
Rust-Postgres enforces a strict correspondence between Rust types and Postgres
|
2013-09-16 03:05:32 +00:00
|
|
|
types. The driver currently supports the following conversions:
|
2013-09-03 06:19:03 +00:00
|
|
|
|
|
|
|
<table>
|
|
|
|
<thead>
|
|
|
|
<tr>
|
2014-11-10 11:51:33 +00:00
|
|
|
<th>Rust Type</th>
|
|
|
|
<th>Postgres Type</th>
|
2013-09-03 06:19:03 +00:00
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
<tr>
|
|
|
|
<td>bool</td>
|
|
|
|
<td>BOOL</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>i8</td>
|
|
|
|
<td>"char"</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>i16</td>
|
2013-11-06 05:35:07 +00:00
|
|
|
<td>SMALLINT, SMALLSERIAL</td>
|
2013-09-03 06:19:03 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>i32</td>
|
2013-11-06 05:35:07 +00:00
|
|
|
<td>INT, SERIAL</td>
|
2013-09-03 06:19:03 +00:00
|
|
|
</tr>
|
2014-12-15 00:43:17 +00:00
|
|
|
<tr>
|
|
|
|
<td>u32</td>
|
|
|
|
<td>OID</td>
|
|
|
|
</tr>
|
2013-09-03 06:19:03 +00:00
|
|
|
<tr>
|
|
|
|
<td>i64</td>
|
2013-11-06 05:35:07 +00:00
|
|
|
<td>BIGINT, BIGSERIAL</td>
|
2013-09-03 06:19:03 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>f32</td>
|
2013-11-06 05:35:07 +00:00
|
|
|
<td>REAL</td>
|
2013-09-03 06:19:03 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>f64</td>
|
2013-11-06 05:35:07 +00:00
|
|
|
<td>DOUBLE PRECISION</td>
|
2013-09-03 06:19:03 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
2014-05-26 22:21:15 +00:00
|
|
|
<td>str/String</td>
|
2014-12-15 00:43:17 +00:00
|
|
|
<td>VARCHAR, CHAR(n), TEXT, CITEXT</td>
|
2013-09-03 06:19:03 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
2014-04-08 16:59:45 +00:00
|
|
|
<td>[u8]/Vec<u8></td>
|
2013-09-03 06:19:03 +00:00
|
|
|
<td>BYTEA</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
2014-06-28 03:36:12 +00:00
|
|
|
<td>serialize::json::Json</td>
|
2013-09-03 06:19:03 +00:00
|
|
|
<td>JSON</td>
|
|
|
|
</tr>
|
2014-12-14 19:39:26 +00:00
|
|
|
<tr>
|
|
|
|
<td>IpAddr</td>
|
2014-12-14 20:27:02 +00:00
|
|
|
<td>INET/CIDR</td>
|
2014-12-14 19:39:26 +00:00
|
|
|
</tr>
|
2013-09-08 20:27:15 +00:00
|
|
|
<tr>
|
2014-12-03 04:34:46 +00:00
|
|
|
<td>time::Timespec</td>
|
2013-09-09 04:42:03 +00:00
|
|
|
<td>TIMESTAMP, TIMESTAMP WITH TIME ZONE</td>
|
2013-09-08 20:27:15 +00:00
|
|
|
</tr>
|
2014-11-07 06:54:57 +00:00
|
|
|
<tr>
|
|
|
|
<td>
|
|
|
|
<a href="https://github.com/rust-lang/uuid">uuid::Uuid</a>
|
|
|
|
(<a href="#optional-features">optional</a>)
|
|
|
|
</td>
|
|
|
|
<td>UUID</td>
|
|
|
|
</tr>
|
2013-10-31 05:51:18 +00:00
|
|
|
<tr>
|
|
|
|
<td>types::range::Range<i32></td>
|
|
|
|
<td>INT4RANGE</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>types::range::Range<i64></td>
|
|
|
|
<td>INT8RANGE</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
2014-12-03 04:34:46 +00:00
|
|
|
<td>types::range::Range<Timespec></td>
|
2013-10-31 05:51:18 +00:00
|
|
|
<td>TSRANGE, TSTZRANGE</td>
|
|
|
|
</tr>
|
2013-12-07 23:39:44 +00:00
|
|
|
<tr>
|
|
|
|
<td>types::array::ArrayBase<Option<bool>></td>
|
|
|
|
<td>BOOL[], BOOL[][], ...</td>
|
|
|
|
</tr>
|
2013-12-08 02:38:53 +00:00
|
|
|
<tr>
|
2014-04-08 16:59:45 +00:00
|
|
|
<td>types::array::ArrayBase<Option<Vec<u8>>></td>
|
2013-12-08 02:38:53 +00:00
|
|
|
<td>BYTEA[], BYTEA[][], ...</td>
|
|
|
|
</tr>
|
2013-12-08 02:49:55 +00:00
|
|
|
<tr>
|
|
|
|
<td>types::array::ArrayBase<Option<i8>></td>
|
|
|
|
<td>"char"[], "char"[][], ...</td>
|
|
|
|
</tr>
|
2013-12-08 02:58:40 +00:00
|
|
|
<tr>
|
|
|
|
<td>types::array::ArrayBase<Option<i16>></td>
|
|
|
|
<td>INT2[], INT2[][], ...</td>
|
|
|
|
</tr>
|
2013-12-02 05:09:31 +00:00
|
|
|
<tr>
|
2013-12-02 05:41:42 +00:00
|
|
|
<td>types::array::ArrayBase<Option<i32>></td>
|
2013-12-02 05:09:31 +00:00
|
|
|
<td>INT4[], INT4[][], ...</td>
|
|
|
|
</tr>
|
2013-12-08 03:13:21 +00:00
|
|
|
<tr>
|
2014-05-26 22:21:15 +00:00
|
|
|
<td>types::array::ArrayBase<Option<String>></td>
|
2013-12-08 21:58:41 +00:00
|
|
|
<td>TEXT[], CHAR(n)[], VARCHAR[], TEXT[][], ...</td>
|
2013-12-08 03:13:21 +00:00
|
|
|
</tr>
|
2013-12-09 00:00:33 +00:00
|
|
|
<tr>
|
|
|
|
<td>types::array::ArrayBase<Option<Json>></td>
|
|
|
|
<td>JSON[], JSON[][], ...</td>
|
|
|
|
</tr>
|
2013-12-04 06:32:54 +00:00
|
|
|
<tr>
|
|
|
|
<td>types::array::ArrayBase<Option<i64>></td>
|
|
|
|
<td>INT8[], INT8[][], ...</td>
|
|
|
|
</tr>
|
2013-12-08 22:04:26 +00:00
|
|
|
<tr>
|
2014-12-03 04:34:46 +00:00
|
|
|
<td>types::array::ArrayBase<Option<Timespec>></td>
|
2013-12-08 22:08:35 +00:00
|
|
|
<td>TIMESTAMP[], TIMESTAMPTZ[], TIMESTAMP[][], ...</td>
|
2013-12-08 22:04:26 +00:00
|
|
|
</tr>
|
2013-12-06 05:51:09 +00:00
|
|
|
<tr>
|
|
|
|
<td>types::array::ArrayBase<Option<f32>></td>
|
|
|
|
<td>FLOAT4[], FLOAT4[][], ...</td>
|
|
|
|
</tr>
|
2013-12-06 05:58:22 +00:00
|
|
|
<tr>
|
|
|
|
<td>types::array::ArrayBase<Option<f64>></td>
|
|
|
|
<td>FLOAT8[], FLOAT8[][], ...</td>
|
|
|
|
</tr>
|
2013-12-08 22:37:31 +00:00
|
|
|
<tr>
|
2013-12-08 23:03:27 +00:00
|
|
|
<td>types::array::ArrayBase<Option<Range<i32>>></td>
|
2013-12-08 22:37:31 +00:00
|
|
|
<td>INT4RANGE[], INT4RANGE[][], ...</td>
|
|
|
|
</tr>
|
2013-12-08 23:02:38 +00:00
|
|
|
<tr>
|
2013-12-08 23:03:27 +00:00
|
|
|
<td>types::array::ArrayBase<Option<Range<Timespec>>></td>
|
2013-12-08 23:02:38 +00:00
|
|
|
<td>TSRANGE[], TSTZRANGE[], TSRANGE[][], ...</td>
|
|
|
|
</tr>
|
2013-12-08 23:07:11 +00:00
|
|
|
<tr>
|
|
|
|
<td>types::array::ArrayBase<Option<Range<i64>>></td>
|
|
|
|
<td>INT8RANGE[], INT8RANGE[][], ...</td>
|
|
|
|
</tr>
|
2013-12-05 05:20:48 +00:00
|
|
|
<tr>
|
2014-06-28 03:36:12 +00:00
|
|
|
<td>std::collections::HashMap<String, Option<String>></td>
|
2013-12-05 05:20:48 +00:00
|
|
|
<td>HSTORE</td>
|
|
|
|
</tr>
|
2013-09-03 06:19:03 +00:00
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
More conversions can be defined by implementing the `ToSql` and `FromSql`
|
|
|
|
traits.
|
|
|
|
|
2014-11-07 06:54:57 +00:00
|
|
|
## Optional features
|
|
|
|
|
|
|
|
### UUID type
|
|
|
|
|
2014-11-17 19:10:26 +00:00
|
|
|
[UUID](http://www.postgresql.org/docs/9.4/static/datatype-uuid.html) support is
|
2014-11-18 03:11:32 +00:00
|
|
|
provided optionally by the `uuid` feature. It is enabled by default.
|
|
|
|
|
|
|
|
To disable support for optional features, add `default-features = false` to
|
|
|
|
your Cargo manifest:
|
2014-11-07 06:54:57 +00:00
|
|
|
|
|
|
|
```toml
|
|
|
|
[dependencies.postgres]
|
2014-12-07 20:56:41 +00:00
|
|
|
version = ...
|
2014-11-17 19:08:28 +00:00
|
|
|
default-features = false
|
|
|
|
features = [...]
|
2014-11-07 06:54:57 +00:00
|
|
|
```
|
|
|
|
|
2014-08-15 06:05:11 +00:00
|
|
|
## Development
|
2013-11-06 05:29:41 +00:00
|
|
|
Like Rust itself, Rust-Postgres is still in the early stages of development, so
|
|
|
|
don't be surprised if APIs change and things break. If something's not working
|
|
|
|
properly, file an issue or submit a pull request!
|