rust-postgres/README.md

329 lines
10 KiB
Markdown
Raw Normal View History

2013-09-03 06:19:03 +00:00
Rust-Postgres
2013-08-18 21:16:39 +00:00
=============
2013-09-03 06:19:03 +00:00
A native PostgreSQL driver for Rust.
2014-04-28 06:17:30 +00:00
Documentation is available at http://sfackler.github.io/rust-postgres/doc/postgres/index.html.
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)
2013-09-03 06:19:03 +00:00
Overview
========
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
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
use postgres::{PostgresConnection, NoSsl};
2013-09-03 06:19:03 +00:00
use postgres::types::ToSql;
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() {
2013-11-11 01:59:25 +00:00
let conn = PostgresConnection::connect("postgres://postgres@localhost",
&NoSsl).unwrap();
2013-09-03 06:19:03 +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
)", []).unwrap();
2013-09-03 06:19:03 +00:00
let me = Person {
id: 0,
2014-05-25 03:42:07 +00:00
name: "Steven".to_owned(),
2013-10-01 07:01:54 +00:00
time_created: time::get_time(),
2013-09-03 06:19:03 +00:00
data: None
};
conn.execute("INSERT INTO person (name, time_created, data)
2013-09-03 06:19:03 +00:00
VALUES ($1, $2, $3)",
2014-05-12 04:52:59 +00:00
[&me.name.as_slice() as &ToSql, &me.time_created as &ToSql,
&me.data as &ToSql]).unwrap();
2013-09-03 06:19:03 +00:00
let stmt = conn.prepare("SELECT id, name, time_created, data FROM person")
.unwrap();
for row in stmt.query([]).unwrap() {
2013-09-03 06:19:03 +00:00
let person = Person {
2013-12-03 03:53:40 +00:00
id: row[1],
name: row[2],
time_created: row[3],
data: row[4]
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
}
}
```
Requirements
============
* **Rust** - Rust-Postgres is developed against the *master* branch of the Rust
repository. It will most likely not build against the releases on
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.
Usage
=====
Connecting
----------
Connect to a Postgres server using the standard URI format:
```rust
2014-03-28 04:20:04 +00:00
let conn = try!(PostgresConnection::connect("postgres://user:pass@host:port/database?arg1=val1&arg2=val2",
&NoSsl));
2013-09-03 06:19:03 +00:00
```
`pass` may be omitted if not needed. `port` defaults to `5432` and `database`
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
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
let conn = try!(PosgresConnection::connect("postgres://postgres@%2Frun%2Fpostgres", &NoSsl));
```
Paths which contain non-UTF8 characters can be handled in a different manner;
see the documentation for details.
2013-09-03 06:19:03 +00:00
Statement Preparation
---------------------
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
```
Querying
--------
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
`&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"));
let updates = try!(stmt.execute([&1i32 as &ToSql, & &"biz" as &ToSql]));
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,
though access by index is more efficient. Like statement parameters, result
columns are one-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"));
for row in try!(stmt.query([])) {
2013-12-03 03:53:40 +00:00
let bar: i32 = row[1];
2014-05-19 04:23:53 +00:00
let baz: StrBuf = row["baz"];
2013-09-03 06:19:03 +00:00
println!("bar: {}, baz: {}", bar, baz);
}
```
In addition, `PostgresConnection` has a utility `execute` method which is useful
2013-09-03 06:19:03 +00:00
if a statement is only going to be executed once:
```rust
2014-03-28 04:20:04 +00:00
let updates = try!(conn.execute("UPDATE foo SET bar = $1 WHERE baz = $2",
2014-05-19 04:23:53 +00:00
[&1i32 as &ToSql, &(&"biz") as &ToSql]));
2013-09-03 06:19:03 +00:00
println!("{} rows were updated", updates);
```
Transactions
------------
2013-10-14 01:58:31 +00:00
The `transaction` method will start a new transaction. It returns a
`PostgresTransaction` object which has the functionality of a
`PostgresConnection` as well as methods to control the result of the
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 a_bad_thing_happened {
trans.set_rollback();
}
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
drop(trans);
2013-09-03 06:19:03 +00:00
```
2013-10-14 01:58:31 +00:00
The transaction will be active until the `PostgresTransaction` object falls out
of scope. A transaction will commit by default. Nested transactions are
supported via savepoints.
2013-09-03 06:19:03 +00:00
Connection Pooling
------------------
A very basic fixed-size connection pool is provided in the `pool` module. A
single pool can be shared across tasks and `get_connection` will block until a
connection is available.
```rust
2014-03-28 04:20:04 +00:00
let pool = try!(PostgresConnectionPool::new("postgres://postgres@localhost",
NoSsl, 5));
for _ in range(0, 10) {
2013-12-05 05:57:49 +00:00
let pool = pool.clone();
2014-02-02 20:02:59 +00:00
spawn(proc() {
let conn = pool.get_connection();
2014-03-28 04:20:04 +00:00
conn.query(...).unwrap();
2014-02-02 20:02:59 +00:00
})
}
```
2013-09-03 06:19:03 +00:00
Type Correspondence
-------------------
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>
<td>Rust Type</td>
<td>Postgres Type</td>
</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>
<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-16 02:59:01 +00:00
<td>str/StrBuf</td>
2013-09-03 06:19:03 +00:00
<td>VARCHAR, CHAR(n), TEXT</td>
</tr>
<tr>
2014-04-08 16:59:45 +00:00
<td>[u8]/Vec&lt;u8&gt;</td>
2013-09-03 06:19:03 +00:00
<td>BYTEA</td>
</tr>
<tr>
<td>extra::json::Json</td>
<td>JSON</td>
</tr>
<tr>
<td>extra::uuid::Uuid</td>
<td>UUID</td>
</tr>
2013-09-08 20:27:15 +00:00
<tr>
<td>extra::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>
2013-10-31 05:51:18 +00:00
<tr>
<td>types::range::Range&lt;i32&gt;</td>
<td>INT4RANGE</td>
</tr>
<tr>
<td>types::range::Range&lt;i64&gt;</td>
<td>INT8RANGE</td>
</tr>
<tr>
<td>types::range::Range&lt;Timespec&gt;</td>
<td>TSRANGE, TSTZRANGE</td>
</tr>
2013-12-07 23:39:44 +00:00
<tr>
<td>types::array::ArrayBase&lt;Option&lt;bool&gt;&gt;</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&lt;Option&lt;Vec&lt;u8&gt;&gt;&gt;</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&lt;Option&lt;i8&gt;&gt;</td>
<td>"char"[], "char"[][], ...</td>
</tr>
2013-12-08 02:58:40 +00:00
<tr>
<td>types::array::ArrayBase&lt;Option&lt;i16&gt;&gt;</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&lt;Option&lt;i32&gt;&gt;</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-19 04:24:53 +00:00
<td>types::array::ArrayBase&lt;Option&lt;StrBuf&gt;&gt;</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&lt;Option&lt;Json&gt;&gt;</td>
<td>JSON[], JSON[][], ...</td>
</tr>
2013-12-04 06:32:54 +00:00
<tr>
<td>types::array::ArrayBase&lt;Option&lt;i64&gt;&gt;</td>
<td>INT8[], INT8[][], ...</td>
</tr>
2013-12-08 22:04:26 +00:00
<tr>
<td>types::array::ArrayBase&lt;Option&lt;Timespec&gt;&gt;</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&lt;Option&lt;f32&gt;&gt;</td>
<td>FLOAT4[], FLOAT4[][], ...</td>
</tr>
2013-12-06 05:58:22 +00:00
<tr>
<td>types::array::ArrayBase&lt;Option&lt;f64&gt;&gt;</td>
<td>FLOAT8[], FLOAT8[][], ...</td>
</tr>
2013-12-08 22:16:37 +00:00
<tr>
2013-12-08 23:03:27 +00:00
<td>types::array::ArrayBase&lt;Option&lt;Uuid&gt;&gt;</td>
2013-12-08 22:16:37 +00:00
<td>UUID[], UUID[][], ...</td>
</tr>
2013-12-08 22:37:31 +00:00
<tr>
2013-12-08 23:03:27 +00:00
<td>types::array::ArrayBase&lt;Option&lt;Range&lt;i32&gt;&gt;&gt;</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&lt;Option&lt;Range&lt;Timespec&gt;&gt;&gt;</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&lt;Option&lt;Range&lt;i64&gt;&gt;&gt;</td>
<td>INT8RANGE[], INT8RANGE[][], ...</td>
</tr>
2013-12-05 05:20:48 +00:00
<tr>
2014-05-19 04:24:53 +00:00
<td>std::hashmap::HashMap&lt;StrBuf, Option&lt;StrBuf&gt;&gt;</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.
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!