Merge branch 'release-v0.10.1' into release
This commit is contained in:
commit
321cc4df3d
@ -3,11 +3,11 @@ sudo: required
|
|||||||
rust:
|
rust:
|
||||||
- nightly
|
- nightly
|
||||||
- beta
|
- beta
|
||||||
- stable
|
- 1.3.0
|
||||||
addons:
|
addons:
|
||||||
postgresql: 9.4
|
postgresql: 9.4
|
||||||
before_script:
|
before_script:
|
||||||
- "./.travis/setup.sh"
|
- "./.travis/setup.sh"
|
||||||
script:
|
script:
|
||||||
- cargo test
|
- cargo test
|
||||||
- cargo test --features "uuid rustc-serialize time unix_socket serde chrono openssl"
|
- cargo test --features "uuid rustc-serialize time unix_socket serde_json chrono openssl"
|
||||||
|
12
Cargo.toml
12
Cargo.toml
@ -1,11 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "postgres"
|
name = "postgres"
|
||||||
version = "0.10.0"
|
version = "0.10.1"
|
||||||
authors = ["Steven Fackler <sfackler@gmail.com>"]
|
authors = ["Steven Fackler <sfackler@gmail.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
description = "A native PostgreSQL driver"
|
description = "A native PostgreSQL driver"
|
||||||
repository = "https://github.com/sfackler/rust-postgres"
|
repository = "https://github.com/sfackler/rust-postgres"
|
||||||
documentation = "https://sfackler.github.io/rust-postgres/doc/v0.10.0/postgres"
|
documentation = "https://sfackler.github.io/rust-postgres/doc/v0.10.1/postgres"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["database", "sql"]
|
keywords = ["database", "sql"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
@ -25,15 +25,17 @@ phf_codegen = "0.7"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bufstream = "0.1"
|
bufstream = "0.1"
|
||||||
byteorder = "0.3"
|
byteorder = ">= 0.3, < 0.5"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
phf = "0.7"
|
phf = "0.7"
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
|
net2 = { version = "0.2", features = ["nightly"] }
|
||||||
chrono = { version = "0.2.14", optional = true }
|
chrono = { version = "0.2.14", optional = true }
|
||||||
openssl = { version = "0.6.4", optional = true }
|
openssl = { version = "0.6.4", optional = true }
|
||||||
serde = { version = "0.3", optional = true }
|
serde = { version = "0.3", optional = true } # Delete for 0.11
|
||||||
|
serde_json = { version = "0.6", optional = true }
|
||||||
time = { version = "0.1.14", optional = true }
|
time = { version = "0.1.14", optional = true }
|
||||||
unix_socket = { version = ">= 0.3, < 0.5", optional = true }
|
unix_socket = { version = ">= 0.3, < 0.5", optional = true, features = ["socket_timeout"] }
|
||||||
uuid = { version = "0.1", optional = true }
|
uuid = { version = "0.1", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Rust-Postgres
|
# Rust-Postgres
|
||||||
A native PostgreSQL driver for Rust.
|
A native PostgreSQL driver for Rust.
|
||||||
|
|
||||||
[Documentation](https://sfackler.github.io/rust-postgres/doc/v0.10.0/postgres)
|
[Documentation](https://sfackler.github.io/rust-postgres/doc/v0.10.1/postgres)
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/sfackler/rust-postgres.png?branch=master)](https://travis-ci.org/sfackler/rust-postgres) [![Latest Version](https://img.shields.io/crates/v/postgres.svg)](https://crates.io/crates/postgres)
|
[![Build Status](https://travis-ci.org/sfackler/rust-postgres.png?branch=master)](https://travis-ci.org/sfackler/rust-postgres) [![Latest Version](https://img.shields.io/crates/v/postgres.svg)](https://crates.io/crates/postgres)
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ fn main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
* **Rust** - Rust-Postgres is developed against the 1.2 release of Rust
|
* **Rust** - Rust-Postgres is developed against the 1.3 release of Rust
|
||||||
available on http://www.rust-lang.org. It should also compile against more
|
available on http://www.rust-lang.org. It should also compile against more
|
||||||
recent releases.
|
recent releases.
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ types. The driver currently supports the following conversions:
|
|||||||
<td>
|
<td>
|
||||||
<a href="https://github.com/rust-lang/rustc-serialize">serialize::json::Json</a>
|
<a href="https://github.com/rust-lang/rustc-serialize">serialize::json::Json</a>
|
||||||
and
|
and
|
||||||
<a href="https://github.com/erickt/serde">serde::json::Value</a>
|
<a href="https://github.com/erickt/serde_json">serde_json::Value</a>
|
||||||
(<a href="#optional-features">optional</a>)
|
(<a href="#optional-features">optional</a>)
|
||||||
</td>
|
</td>
|
||||||
<td>JSON, JSONB</td>
|
<td>JSON, JSONB</td>
|
||||||
@ -284,7 +284,7 @@ implementations for `uuid`'s `Uuid` type.
|
|||||||
[JSON and JSONB](http://www.postgresql.org/docs/9.4/static/datatype-json.html)
|
[JSON and JSONB](http://www.postgresql.org/docs/9.4/static/datatype-json.html)
|
||||||
support is provided optionally by the `rustc-serialize` feature, which adds
|
support is provided optionally by the `rustc-serialize` feature, which adds
|
||||||
`ToSql` and `FromSql` implementations for `rustc-serialize`'s `Json` type, and
|
`ToSql` and `FromSql` implementations for `rustc-serialize`'s `Json` type, and
|
||||||
the `serde` feature, which adds implementations for `serde`'s `json::Value`
|
the `serde` feature, which adds implementations for `serde_json`'s `Value`
|
||||||
type.
|
type.
|
||||||
|
|
||||||
### TIMESTAMP/TIMESTAMPTZ/DATE/TIME types
|
### TIMESTAMP/TIMESTAMPTZ/DATE/TIME types
|
||||||
|
55
src/lib.rs
55
src/lib.rs
@ -24,7 +24,7 @@
|
|||||||
//! )", &[]).unwrap();
|
//! )", &[]).unwrap();
|
||||||
//! let me = Person {
|
//! let me = Person {
|
||||||
//! id: 0,
|
//! id: 0,
|
||||||
//! name: "Steven".to_string(),
|
//! name: "Steven".to_owned(),
|
||||||
//! data: None
|
//! data: None
|
||||||
//! };
|
//! };
|
||||||
//! conn.execute("INSERT INTO person (name, data) VALUES ($1, $2)",
|
//! conn.execute("INSERT INTO person (name, data) VALUES ($1, $2)",
|
||||||
@ -41,7 +41,7 @@
|
|||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
#![doc(html_root_url="https://sfackler.github.io/rust-postgres/doc/v0.10.0")]
|
#![doc(html_root_url="https://sfackler.github.io/rust-postgres/doc/v0.10.1")]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate bufstream;
|
extern crate bufstream;
|
||||||
@ -52,6 +52,7 @@ extern crate phf;
|
|||||||
extern crate rustc_serialize as serialize;
|
extern crate rustc_serialize as serialize;
|
||||||
#[cfg(feature = "unix_socket")]
|
#[cfg(feature = "unix_socket")]
|
||||||
extern crate unix_socket;
|
extern crate unix_socket;
|
||||||
|
extern crate net2;
|
||||||
|
|
||||||
use bufstream::BufStream;
|
use bufstream::BufStream;
|
||||||
use md5::Md5;
|
use md5::Md5;
|
||||||
@ -67,6 +68,7 @@ use std::io::prelude::*;
|
|||||||
use std::marker::Sync as StdSync;
|
use std::marker::Sync as StdSync;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::result;
|
use std::result;
|
||||||
|
use std::time::Duration;
|
||||||
#[cfg(feature = "unix_socket")]
|
#[cfg(feature = "unix_socket")]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -455,10 +457,12 @@ impl InnerConnection {
|
|||||||
|
|
||||||
fn setup_typeinfo_query(&mut self) -> result::Result<(), ConnectError> {
|
fn setup_typeinfo_query(&mut self) -> result::Result<(), ConnectError> {
|
||||||
match self.raw_prepare(TYPEINFO_QUERY,
|
match self.raw_prepare(TYPEINFO_QUERY,
|
||||||
"SELECT t.typname, t.typelem, r.rngsubtype \
|
"SELECT t.typname, t.typelem, r.rngsubtype, n.nspname \
|
||||||
FROM pg_catalog.pg_type t \
|
FROM pg_catalog.pg_type t \
|
||||||
LEFT OUTER JOIN pg_catalog.pg_range r \
|
LEFT OUTER JOIN pg_catalog.pg_range r \
|
||||||
ON r.rngtypid = t.oid \
|
ON r.rngtypid = t.oid \
|
||||||
|
INNER JOIN pg_catalog.pg_namespace n \
|
||||||
|
ON t.typnamespace = n.oid \
|
||||||
WHERE t.oid = $1") {
|
WHERE t.oid = $1") {
|
||||||
Ok(..) => return Ok(()),
|
Ok(..) => return Ok(()),
|
||||||
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
|
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
|
||||||
@ -469,9 +473,11 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match self.raw_prepare(TYPEINFO_QUERY,
|
match self.raw_prepare(TYPEINFO_QUERY,
|
||||||
"SELECT typname, typelem, NULL::OID \
|
"SELECT t.typname, t.typelem, NULL::OID, n.nspname \
|
||||||
FROM pg_catalog.pg_type \
|
FROM pg_catalog.pg_type t \
|
||||||
WHERE oid = $1") {
|
INNER JOIN pg_catalog.pg_namespace n \
|
||||||
|
ON t.typnamespace = n.oid \
|
||||||
|
WHERE t.oid = $1") {
|
||||||
Ok(..) => Ok(()),
|
Ok(..) => Ok(()),
|
||||||
Err(Error::IoError(e)) => Err(ConnectError::IoError(e)),
|
Err(Error::IoError(e)) => Err(ConnectError::IoError(e)),
|
||||||
Err(Error::DbError(e)) => Err(ConnectError::DbError(e)),
|
Err(Error::DbError(e)) => Err(ConnectError::DbError(e)),
|
||||||
@ -504,6 +510,24 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_message_with_notification_timeout(&mut self, timeout: Duration)
|
||||||
|
-> std::io::Result<Option<BackendMessage>> {
|
||||||
|
debug_assert!(!self.desynchronized);
|
||||||
|
loop {
|
||||||
|
match try_desync!(self, self.stream.read_message_timeout(timeout)) {
|
||||||
|
Some(NoticeResponse { fields }) => {
|
||||||
|
if let Ok(err) = DbError::new_raw(fields) {
|
||||||
|
self.notice_handler.handle_notice(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(ParameterStatus { parameter, value }) => {
|
||||||
|
self.parameters.insert(parameter, value);
|
||||||
|
}
|
||||||
|
val => return Ok(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn read_message(&mut self) -> std_io::Result<BackendMessage> {
|
fn read_message(&mut self) -> std_io::Result<BackendMessage> {
|
||||||
loop {
|
loop {
|
||||||
match try!(self.read_message_with_notification()) {
|
match try!(self.read_message_with_notification()) {
|
||||||
@ -661,7 +685,7 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_type(&mut self, oid: Oid) -> Result<Type> {
|
fn get_type(&mut self, oid: Oid) -> Result<Type> {
|
||||||
if let Some(ty) = Type::new(oid) {
|
if let Some(ty) = Type::from_oid(oid) {
|
||||||
return Ok(ty);
|
return Ok(ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,7 +720,7 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
_ => bad_response!(self)
|
_ => bad_response!(self)
|
||||||
}
|
}
|
||||||
let (name, elem_oid, rngsubtype): (String, Oid, Option<Oid>) =
|
let (name, elem_oid, rngsubtype, schema): (String, Oid, Option<Oid>, String) =
|
||||||
match try!(self.read_message()) {
|
match try!(self.read_message()) {
|
||||||
DataRow { row } => {
|
DataRow { row } => {
|
||||||
let ctx = SessionInfo::new(self);
|
let ctx = SessionInfo::new(self);
|
||||||
@ -708,6 +732,9 @@ impl InnerConnection {
|
|||||||
&ctx)),
|
&ctx)),
|
||||||
try!(FromSql::from_sql_nullable(&Type::Oid,
|
try!(FromSql::from_sql_nullable(&Type::Oid,
|
||||||
row[2].as_ref().map(|r| &**r).as_mut(),
|
row[2].as_ref().map(|r| &**r).as_mut(),
|
||||||
|
&ctx)),
|
||||||
|
try!(FromSql::from_sql_nullable(&Type::Name,
|
||||||
|
row[3].as_ref().map(|r| &**r).as_mut(),
|
||||||
&ctx)))
|
&ctx)))
|
||||||
}
|
}
|
||||||
ErrorResponse { fields } => {
|
ErrorResponse { fields } => {
|
||||||
@ -735,7 +762,7 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let type_ = Type::Other(Box::new(Other::new(name, oid, kind)));
|
let type_ = Type::Other(Box::new(Other::new(name, oid, kind, schema)));
|
||||||
self.unknown_types.insert(oid, type_.clone());
|
self.unknown_types.insert(oid, type_.clone());
|
||||||
Ok(type_)
|
Ok(type_)
|
||||||
}
|
}
|
||||||
@ -860,7 +887,7 @@ impl Connection {
|
|||||||
/// target: ConnectTarget::Unix(some_crazy_path),
|
/// target: ConnectTarget::Unix(some_crazy_path),
|
||||||
/// port: None,
|
/// port: None,
|
||||||
/// user: Some(UserInfo {
|
/// user: Some(UserInfo {
|
||||||
/// user: "postgres".to_string(),
|
/// user: "postgres".to_owned(),
|
||||||
/// password: None
|
/// password: None
|
||||||
/// }),
|
/// }),
|
||||||
/// database: None,
|
/// database: None,
|
||||||
@ -911,7 +938,7 @@ impl Connection {
|
|||||||
self.conn.borrow_mut().prepare(query, self)
|
self.conn.borrow_mut().prepare(query, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates cached prepared statement.
|
/// Creates a cached prepared statement.
|
||||||
///
|
///
|
||||||
/// Like `prepare`, except that the statement is only prepared once over
|
/// Like `prepare`, except that the statement is only prepared once over
|
||||||
/// the lifetime of the connection and then cached. If the same statement
|
/// the lifetime of the connection and then cached. If the same statement
|
||||||
@ -1337,7 +1364,7 @@ impl<'a> GenericConnection for Transaction<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trait OtherNew {
|
trait OtherNew {
|
||||||
fn new(name: String, oid: Oid, kind: Kind) -> Other;
|
fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait DbErrorNew {
|
trait DbErrorNew {
|
||||||
@ -1346,10 +1373,6 @@ trait DbErrorNew {
|
|||||||
fn new<T>(fields: Vec<(u8, String)>) -> Result<T>;
|
fn new<T>(fields: Vec<(u8, String)>) -> Result<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait TypeNew {
|
|
||||||
fn new(oid: Oid) -> Option<Type>;
|
|
||||||
}
|
|
||||||
|
|
||||||
trait RowsNew<'a> {
|
trait RowsNew<'a> {
|
||||||
fn new(stmt: &'a Statement<'a>, data: Vec<Vec<Option<Vec<u8>>>>) -> Rows<'a>;
|
fn new(stmt: &'a Statement<'a>, data: Vec<Vec<Option<Vec<u8>>>>) -> Rows<'a>;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::time::Duration;
|
||||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
use types::Oid;
|
use types::Oid;
|
||||||
use util;
|
use util;
|
||||||
|
use priv_io::ReadTimeout;
|
||||||
|
|
||||||
use self::BackendMessage::*;
|
use self::BackendMessage::*;
|
||||||
use self::FrontendMessage::*;
|
use self::FrontendMessage::*;
|
||||||
@ -282,12 +284,39 @@ impl<R: BufRead> ReadCStr for R {
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait ReadMessage {
|
pub trait ReadMessage {
|
||||||
fn read_message(&mut self) -> io::Result<BackendMessage>;
|
fn read_message(&mut self) -> io::Result<BackendMessage>;
|
||||||
|
|
||||||
|
fn read_message_timeout(&mut self, timeout: Duration)
|
||||||
|
-> io::Result<Option<BackendMessage>>;
|
||||||
|
|
||||||
|
fn finish_read_message(&mut self, ident: u8) -> io::Result<BackendMessage>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: BufRead> ReadMessage for R {
|
impl<R: BufRead + ReadTimeout> ReadMessage for R {
|
||||||
fn read_message(&mut self) -> io::Result<BackendMessage> {
|
fn read_message(&mut self) -> io::Result<BackendMessage> {
|
||||||
let ident = try!(self.read_u8());
|
let ident = try!(self.read_u8());
|
||||||
|
self.finish_read_message(ident)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_message_timeout(&mut self, timeout: Duration)
|
||||||
|
-> io::Result<Option<BackendMessage>> {
|
||||||
|
try!(self.set_read_timeout(Some(timeout)));
|
||||||
|
let ident = self.read_u8();
|
||||||
|
try!(self.set_read_timeout(None));
|
||||||
|
|
||||||
|
match ident {
|
||||||
|
Ok(ident) => self.finish_read_message(ident).map(Some),
|
||||||
|
Err(e) => {
|
||||||
|
let e: io::Error = e.into();
|
||||||
|
if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_read_message(&mut self, ident: u8) -> io::Result<BackendMessage> {
|
||||||
// subtract size of length value
|
// subtract size of length value
|
||||||
let len = try!(self.read_u32::<BigEndian>()) - mem::size_of::<u32>() as u32;
|
let len = try!(self.read_u32::<BigEndian>()) - mem::size_of::<u32>() as u32;
|
||||||
let mut rdr = self.by_ref().take(len as u64);
|
let mut rdr = self.by_ref().take(len as u64);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Asynchronous notifications.
|
//! Asynchronous notifications.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use {desynchronized, Result, Connection, NotificationsNew};
|
use {desynchronized, Result, Connection, NotificationsNew};
|
||||||
use message::BackendMessage::NotificationResponse;
|
use message::BackendMessage::NotificationResponse;
|
||||||
@ -41,15 +42,16 @@ impl<'conn> Notifications<'conn> {
|
|||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// This iterator may start returning `Some` after previously returning
|
/// This iterator may start returning `Some` after previously returning
|
||||||
/// `None` if more notifications are received.
|
/// `None` if more notifications are received. However, those notifications
|
||||||
|
/// will not be registered until the connection is used in some way.
|
||||||
pub fn iter<'a>(&'a self) -> Iter<'a> {
|
pub fn iter<'a>(&'a self) -> Iter<'a> {
|
||||||
Iter {
|
Iter {
|
||||||
conn: self.conn,
|
conn: self.conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over notifications, blocking until one is received
|
/// Returns an iterator over notifications that blocks until one is
|
||||||
/// if none are pending.
|
/// received if none are pending.
|
||||||
///
|
///
|
||||||
/// The iterator will never return `None`.
|
/// The iterator will never return `None`.
|
||||||
pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
|
pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
|
||||||
@ -57,6 +59,20 @@ impl<'conn> Notifications<'conn> {
|
|||||||
conn: self.conn,
|
conn: self.conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over notifications that blocks for a limited time
|
||||||
|
/// waiting to receive one if none are pending.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// This iterator may start returning `Some` after previously returning
|
||||||
|
/// `None` if more notifications are received.
|
||||||
|
pub fn timeout_iter<'a>(&'a self, timeout: Duration) -> TimeoutIter<'a> {
|
||||||
|
TimeoutIter {
|
||||||
|
conn: self.conn,
|
||||||
|
timeout: timeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'conn> IntoIterator for &'a Notifications<'conn> {
|
impl<'a, 'conn> IntoIterator for &'a Notifications<'conn> {
|
||||||
@ -121,3 +137,39 @@ impl<'a> Iterator for BlockingIter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator over notifications which will block for a period of time if
|
||||||
|
/// none are pending.
|
||||||
|
pub struct TimeoutIter<'a> {
|
||||||
|
conn: &'a Connection,
|
||||||
|
timeout: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for TimeoutIter<'a> {
|
||||||
|
type Item = Result<Notification>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Result<Notification>> {
|
||||||
|
let mut conn = self.conn.conn.borrow_mut();
|
||||||
|
|
||||||
|
if let Some(notification) = conn.notifications.pop_front() {
|
||||||
|
return Some(Ok(notification));
|
||||||
|
}
|
||||||
|
|
||||||
|
if conn.is_desynchronized() {
|
||||||
|
return Some(Err(Error::IoError(desynchronized())));
|
||||||
|
}
|
||||||
|
|
||||||
|
match conn.read_message_with_notification_timeout(self.timeout) {
|
||||||
|
Ok(Some(NotificationResponse { pid, channel, payload })) => {
|
||||||
|
Some(Ok(Notification {
|
||||||
|
pid: pid,
|
||||||
|
channel: channel,
|
||||||
|
payload: payload
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Ok(None) => None,
|
||||||
|
Err(err) => Some(Err(Error::IoError(err))),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use byteorder::ReadBytesExt;
|
use byteorder::ReadBytesExt;
|
||||||
|
use net2::TcpStreamExt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
|
use std::time::Duration;
|
||||||
|
use bufstream::BufStream;
|
||||||
#[cfg(feature = "unix_socket")]
|
#[cfg(feature = "unix_socket")]
|
||||||
use unix_socket::UnixStream;
|
use unix_socket::UnixStream;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@ -17,6 +20,21 @@ use message::FrontendMessage::SslRequest;
|
|||||||
|
|
||||||
const DEFAULT_PORT: u16 = 5432;
|
const DEFAULT_PORT: u16 = 5432;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait ReadTimeout {
|
||||||
|
fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadTimeout for BufStream<Box<StreamWrapper>> {
|
||||||
|
fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
||||||
|
match self.get_ref().get_ref().0 {
|
||||||
|
InternalStream::Tcp(ref s) => <TcpStream as TcpStreamExt>::set_read_timeout(s, timeout),
|
||||||
|
#[cfg(feature = "unix_socket")]
|
||||||
|
InternalStream::Unix(ref s) => s.set_read_timeout(timeout),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A connection to the Postgres server.
|
/// A connection to the Postgres server.
|
||||||
///
|
///
|
||||||
/// It implements `Read`, `Write` and `StreamWrapper`, as well as `AsRawFd` on
|
/// It implements `Read`, `Write` and `StreamWrapper`, as well as `AsRawFd` on
|
||||||
|
@ -310,6 +310,10 @@ impl<'conn> Statement<'conn> {
|
|||||||
|
|
||||||
let (format, column_formats) = match try!(conn.read_message()) {
|
let (format, column_formats) = match try!(conn.read_message()) {
|
||||||
CopyInResponse { format, column_formats } => (format, column_formats),
|
CopyInResponse { format, column_formats } => (format, column_formats),
|
||||||
|
ErrorResponse { fields } => {
|
||||||
|
try!(conn.wait_for_ready());
|
||||||
|
return DbError::new(fields);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
loop {
|
loop {
|
||||||
match try!(conn.read_message()) {
|
match try!(conn.read_message()) {
|
||||||
@ -425,6 +429,10 @@ impl<'conn> Statement<'conn> {
|
|||||||
io::ErrorKind::InvalidInput,
|
io::ErrorKind::InvalidInput,
|
||||||
"called `copy_out` on a non-`COPY TO STDOUT` statement")));
|
"called `copy_out` on a non-`COPY TO STDOUT` statement")));
|
||||||
}
|
}
|
||||||
|
ErrorResponse { fields } => {
|
||||||
|
try!(conn.wait_for_ready());
|
||||||
|
return DbError::new(fields);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
loop {
|
loop {
|
||||||
match try!(conn.read_message()) {
|
match try!(conn.read_message()) {
|
||||||
|
406
src/types/mod.rs
406
src/types/mod.rs
@ -7,7 +7,7 @@ use std::io::prelude::*;
|
|||||||
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
||||||
|
|
||||||
pub use self::slice::Slice;
|
pub use self::slice::Slice;
|
||||||
use {Result, SessionInfoNew, InnerConnection, OtherNew, TypeNew};
|
use {Result, SessionInfoNew, InnerConnection, OtherNew};
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use util;
|
use util;
|
||||||
|
|
||||||
@ -49,6 +49,8 @@ mod time;
|
|||||||
mod slice;
|
mod slice;
|
||||||
#[cfg(feature = "rustc-serialize")]
|
#[cfg(feature = "rustc-serialize")]
|
||||||
mod rustc_serialize;
|
mod rustc_serialize;
|
||||||
|
#[cfg(feature = "serde_json")]
|
||||||
|
mod serde_json;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
mod serde;
|
mod serde;
|
||||||
#[cfg(feature = "chrono")]
|
#[cfg(feature = "chrono")]
|
||||||
@ -98,7 +100,7 @@ macro_rules! as_expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! make_postgres_type {
|
macro_rules! make_postgres_type {
|
||||||
($(#[$doc:meta] $oid:tt => $variant:ident: $kind:expr),+) => (
|
($(#[$doc:meta] $oid:tt: $name:expr => $variant:ident: $kind:expr),+) => (
|
||||||
/// A Postgres type.
|
/// A Postgres type.
|
||||||
#[derive(PartialEq, Eq, Clone)]
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
@ -120,16 +122,16 @@ macro_rules! make_postgres_type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeNew for Type {
|
impl Type {
|
||||||
fn new(oid: Oid) -> Option<Type> {
|
/// Returns the `Type` corresponding to the provided `Oid` if it
|
||||||
|
/// corresponds to a built-in type.
|
||||||
|
pub fn from_oid(oid: Oid) -> Option<Type> {
|
||||||
match oid {
|
match oid {
|
||||||
$(as_pat!($oid) => Some(Type::$variant),)+
|
$(as_pat!($oid) => Some(Type::$variant),)+
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Type {
|
|
||||||
/// Returns the OID of the `Type`.
|
/// Returns the OID of the `Type`.
|
||||||
pub fn oid(&self) -> Oid {
|
pub fn oid(&self) -> Oid {
|
||||||
match *self {
|
match *self {
|
||||||
@ -138,7 +140,7 @@ macro_rules! make_postgres_type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kind of this type.
|
/// Returns the kind of this type.
|
||||||
pub fn kind(&self) -> &Kind {
|
pub fn kind(&self) -> &Kind {
|
||||||
match *self {
|
match *self {
|
||||||
$(
|
$(
|
||||||
@ -150,6 +152,24 @@ macro_rules! make_postgres_type {
|
|||||||
Type::Other(ref u) => u.kind(),
|
Type::Other(ref u) => u.kind(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the schema of this type.
|
||||||
|
pub fn schema(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
Type::Other(ref u) => u.schema(),
|
||||||
|
_ => "pg_catalog",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the name of this type.
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
$(
|
||||||
|
Type::$variant => $name,
|
||||||
|
)+
|
||||||
|
Type::Other(ref u) => u.name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -157,317 +177,317 @@ macro_rules! make_postgres_type {
|
|||||||
// Values from pg_type.h
|
// Values from pg_type.h
|
||||||
make_postgres_type! {
|
make_postgres_type! {
|
||||||
#[doc="BOOL - boolean, 'true'/'false'"]
|
#[doc="BOOL - boolean, 'true'/'false'"]
|
||||||
16 => Bool: Kind::Simple,
|
16: "bool" => Bool: Kind::Simple,
|
||||||
#[doc="BYTEA - variable-length string, binary values escaped"]
|
#[doc="BYTEA - variable-length string, binary values escaped"]
|
||||||
17 => Bytea: Kind::Simple,
|
17: "bytea" => Bytea: Kind::Simple,
|
||||||
#[doc="\"char\" - single character"]
|
#[doc="\"char\" - single character"]
|
||||||
18 => Char: Kind::Simple,
|
18: "char" => Char: Kind::Simple,
|
||||||
#[doc="NAME - 63-byte type for storing system identifiers"]
|
#[doc="NAME - 63-byte type for storing system identifiers"]
|
||||||
19 => Name: Kind::Simple,
|
19: "name" => Name: Kind::Simple,
|
||||||
#[doc="INT8/BIGINT - ~18 digit integer, 8-byte storage"]
|
#[doc="INT8/BIGINT - ~18 digit integer, 8-byte storage"]
|
||||||
20 => Int8: Kind::Simple,
|
20: "int8" => Int8: Kind::Simple,
|
||||||
#[doc="INT2/SMALLINT - -32 thousand to 32 thousand, 2-byte storage"]
|
#[doc="INT2/SMALLINT - -32 thousand to 32 thousand, 2-byte storage"]
|
||||||
21 => Int2: Kind::Simple,
|
21: "int2" => Int2: Kind::Simple,
|
||||||
#[doc="INT2VECTOR - array of int2, used in system tables"]
|
#[doc="INT2VECTOR - array of int2, used in system tables"]
|
||||||
22 => Int2Vector: Kind::Array(Type::Int2),
|
22: "int2vector" => Int2Vector: Kind::Array(Type::Int2),
|
||||||
#[doc="INT4/INT - -2 billion to 2 billion integer, 4-byte storage"]
|
#[doc="INT4/INT - -2 billion to 2 billion integer, 4-byte storage"]
|
||||||
23 => Int4: Kind::Simple,
|
23: "int4" => Int4: Kind::Simple,
|
||||||
#[doc="REGPROC - registered procedure"]
|
#[doc="REGPROC - registered procedure"]
|
||||||
24 => Regproc: Kind::Simple,
|
24: "regproc" => Regproc: Kind::Simple,
|
||||||
#[doc="TEXT - variable-length string, no limit specified"]
|
#[doc="TEXT - variable-length string, no limit specified"]
|
||||||
25 => Text: Kind::Simple,
|
25: "text" => Text: Kind::Simple,
|
||||||
#[doc="OID - object identifier(oid), maximum 4 billion"]
|
#[doc="OID - object identifier(oid), maximum 4 billion"]
|
||||||
26 => Oid: Kind::Simple,
|
26: "oid" => Oid: Kind::Simple,
|
||||||
#[doc="TID - (block, offset), physical location of tuple"]
|
#[doc="TID - (block, offset), physical location of tuple"]
|
||||||
27 => Tid: Kind::Simple,
|
27: "tid" => Tid: Kind::Simple,
|
||||||
#[doc="XID - transaction id"]
|
#[doc="XID - transaction id"]
|
||||||
28 => Xid: Kind::Simple,
|
28: "xid" => Xid: Kind::Simple,
|
||||||
#[doc="CID - command identifier type, sequence in transaction id"]
|
#[doc="CID - command identifier type, sequence in transaction id"]
|
||||||
29 => Cid: Kind::Simple,
|
29: "cid" => Cid: Kind::Simple,
|
||||||
#[doc="OIDVECTOR - array of oids, used in system tables"]
|
#[doc="OIDVECTOR - array of oids, used in system tables"]
|
||||||
30 => OidVector: Kind::Array(Type::Oid),
|
30: "oidvector" => OidVector: Kind::Array(Type::Oid),
|
||||||
#[doc="PG_TYPE"]
|
#[doc="PG_TYPE"]
|
||||||
71 => PgType: Kind::Simple,
|
71: "pg_type" => PgType: Kind::Simple,
|
||||||
#[doc="PG_ATTRIBUTE"]
|
#[doc="PG_ATTRIBUTE"]
|
||||||
75 => PgAttribute: Kind::Simple,
|
75: "pg_attribute" => PgAttribute: Kind::Simple,
|
||||||
#[doc="PG_PROC"]
|
#[doc="PG_PROC"]
|
||||||
81 => PgProc: Kind::Simple,
|
81: "pg_proc" => PgProc: Kind::Simple,
|
||||||
#[doc="PG_CLASS"]
|
#[doc="PG_CLASS"]
|
||||||
83 => PgClass: Kind::Simple,
|
83: "pg_class" => PgClass: Kind::Simple,
|
||||||
#[doc="JSON"]
|
#[doc="JSON"]
|
||||||
114 => Json: Kind::Simple,
|
114: "json" => Json: Kind::Simple,
|
||||||
#[doc="XML - XML content"]
|
#[doc="XML - XML content"]
|
||||||
142 => Xml: Kind::Simple,
|
142: "xml" => Xml: Kind::Simple,
|
||||||
#[doc="XML[]"]
|
#[doc="XML[]"]
|
||||||
143 => XmlArray: Kind::Array(Type::Xml),
|
143: "_xml" => XmlArray: Kind::Array(Type::Xml),
|
||||||
#[doc="PG_NODE_TREE - string representing an internal node tree"]
|
#[doc="PG_NODE_TREE - string representing an internal node tree"]
|
||||||
194 => PgNodeTree: Kind::Simple,
|
194: "pg_node_tree" => PgNodeTree: Kind::Simple,
|
||||||
#[doc="JSON[]"]
|
#[doc="JSON[]"]
|
||||||
199 => JsonArray: Kind::Array(Type::Json),
|
199: "_json" => JsonArray: Kind::Array(Type::Json),
|
||||||
#[doc="SMGR - storage manager"]
|
#[doc="SMGR - storage manager"]
|
||||||
210 => Smgr: Kind::Simple,
|
210: "smgr" => Smgr: Kind::Simple,
|
||||||
#[doc="POINT - geometric point '(x, y)'"]
|
#[doc="POINT - geometric point '(x, y)'"]
|
||||||
600 => Point: Kind::Simple,
|
600: "point" => Point: Kind::Simple,
|
||||||
#[doc="LSEG - geometric line segment '(pt1,pt2)'"]
|
#[doc="LSEG - geometric line segment '(pt1,pt2)'"]
|
||||||
601 => Lseg: Kind::Simple,
|
601: "lseg" => Lseg: Kind::Simple,
|
||||||
#[doc="PATH - geometric path '(pt1,...)'"]
|
#[doc="PATH - geometric path '(pt1,...)'"]
|
||||||
602 => Path: Kind::Simple,
|
602: "path" => Path: Kind::Simple,
|
||||||
#[doc="BOX - geometric box '(lower left,upper right)'"]
|
#[doc="BOX - geometric box '(lower left,upper right)'"]
|
||||||
603 => Box: Kind::Simple,
|
603: "box" => Box: Kind::Simple,
|
||||||
#[doc="POLYGON - geometric polygon '(pt1,...)'"]
|
#[doc="POLYGON - geometric polygon '(pt1,...)'"]
|
||||||
604 => Polygon: Kind::Simple,
|
604: "polygon" => Polygon: Kind::Simple,
|
||||||
#[doc="LINE - geometric line"]
|
#[doc="LINE - geometric line"]
|
||||||
628 => Line: Kind::Simple,
|
628: "line" => Line: Kind::Simple,
|
||||||
#[doc="LINE[]"]
|
#[doc="LINE[]"]
|
||||||
629 => LineArray: Kind::Array(Type::Line),
|
629: "_line" => LineArray: Kind::Array(Type::Line),
|
||||||
#[doc="CIDR - network IP address/netmask, network address"]
|
#[doc="CIDR - network IP address/netmask, network address"]
|
||||||
650 => Cidr: Kind::Simple,
|
650: "cidr" => Cidr: Kind::Simple,
|
||||||
#[doc="CIDR[]"]
|
#[doc="CIDR[]"]
|
||||||
651 => CidrArray: Kind::Array(Type::Cidr),
|
651: "_cidr" => CidrArray: Kind::Array(Type::Cidr),
|
||||||
#[doc="FLOAT4/REAL - single-precision floating point number, 4-byte storage"]
|
#[doc="FLOAT4/REAL - single-precision floating point number, 4-byte storage"]
|
||||||
700 => Float4: Kind::Simple,
|
700: "float4" => Float4: Kind::Simple,
|
||||||
#[doc="FLOAT8/DOUBLE PRECISION - double-precision floating point number, 8-byte storage"]
|
#[doc="FLOAT8/DOUBLE PRECISION - double-precision floating point number, 8-byte storage"]
|
||||||
701 => Float8: Kind::Simple,
|
701: "float8" => Float8: Kind::Simple,
|
||||||
#[doc="ABSTIME - absolute, limited-range date and time (Unix system time)"]
|
#[doc="ABSTIME - absolute, limited-range date and time (Unix system time)"]
|
||||||
702 => Abstime: Kind::Simple,
|
702: "abstime" => Abstime: Kind::Simple,
|
||||||
#[doc="RELTIME - relative, limited-range date and time (Unix delta time)"]
|
#[doc="RELTIME - relative, limited-range date and time (Unix delta time)"]
|
||||||
703 => Reltime: Kind::Simple,
|
703: "reltime" => Reltime: Kind::Simple,
|
||||||
#[doc="TINTERVAL - (abstime,abstime), time interval"]
|
#[doc="TINTERVAL - (abstime,abstime), time interval"]
|
||||||
704 => Tinterval: Kind::Simple,
|
704: "tinterval" => Tinterval: Kind::Simple,
|
||||||
#[doc="UNKNOWN"]
|
#[doc="UNKNOWN"]
|
||||||
705 => Unknown: Kind::Simple,
|
705: "unknown" => Unknown: Kind::Simple,
|
||||||
#[doc="CIRCLE - geometric circle '(center,radius)'"]
|
#[doc="CIRCLE - geometric circle '(center,radius)'"]
|
||||||
718 => Circle: Kind::Simple,
|
718: "circle" => Circle: Kind::Simple,
|
||||||
#[doc="CIRCLE[]"]
|
#[doc="CIRCLE[]"]
|
||||||
719 => CircleArray: Kind::Array(Type::Circle),
|
719: "_circle" => CircleArray: Kind::Array(Type::Circle),
|
||||||
#[doc="MONEY - monetary amounts, $d,ddd.cc"]
|
#[doc="MONEY - monetary amounts, $d,ddd.cc"]
|
||||||
790 => Money: Kind::Simple,
|
790: "money" => Money: Kind::Simple,
|
||||||
#[doc="MONEY[]"]
|
#[doc="MONEY[]"]
|
||||||
791 => MoneyArray: Kind::Array(Type::Money),
|
791: "_money" => MoneyArray: Kind::Array(Type::Money),
|
||||||
#[doc="MACADDR - XX:XX:XX:XX:XX:XX, MAC address"]
|
#[doc="MACADDR - XX:XX:XX:XX:XX:XX, MAC address"]
|
||||||
829 => Macaddr: Kind::Simple,
|
829: "macaddr" => Macaddr: Kind::Simple,
|
||||||
#[doc="INET - IP address/netmask, host address, netmask optional"]
|
#[doc="INET - IP address/netmask, host address, netmask optional"]
|
||||||
869 => Inet: Kind::Simple,
|
869: "inet" => Inet: Kind::Simple,
|
||||||
#[doc="BOOL[]"]
|
#[doc="BOOL[]"]
|
||||||
1000 => BoolArray: Kind::Array(Type::Bool),
|
1000: "_bool" => BoolArray: Kind::Array(Type::Bool),
|
||||||
#[doc="BYTEA[]"]
|
#[doc="BYTEA[]"]
|
||||||
1001 => ByteaArray: Kind::Array(Type::Bytea),
|
1001: "_bytea" => ByteaArray: Kind::Array(Type::Bytea),
|
||||||
#[doc="\"char\"[]"]
|
#[doc="\"char\"[]"]
|
||||||
1002 => CharArray: Kind::Array(Type::Char),
|
1002: "_char" => CharArray: Kind::Array(Type::Char),
|
||||||
#[doc="NAME[]"]
|
#[doc="NAME[]"]
|
||||||
1003 => NameArray: Kind::Array(Type::Name),
|
1003: "_name" => NameArray: Kind::Array(Type::Name),
|
||||||
#[doc="INT2[]"]
|
#[doc="INT2[]"]
|
||||||
1005 => Int2Array: Kind::Array(Type::Int2),
|
1005: "_int2" => Int2Array: Kind::Array(Type::Int2),
|
||||||
#[doc="INT2VECTOR[]"]
|
#[doc="INT2VECTOR[]"]
|
||||||
1006 => Int2VectorArray: Kind::Array(Type::Int2Vector),
|
1006: "_int2vector" => Int2VectorArray: Kind::Array(Type::Int2Vector),
|
||||||
#[doc="INT4[]"]
|
#[doc="INT4[]"]
|
||||||
1007 => Int4Array: Kind::Array(Type::Int4),
|
1007: "_int4" => Int4Array: Kind::Array(Type::Int4),
|
||||||
#[doc="REGPROC[]"]
|
#[doc="REGPROC[]"]
|
||||||
1008 => RegprocArray: Kind::Array(Type::Regproc),
|
1008: "_regproc" => RegprocArray: Kind::Array(Type::Regproc),
|
||||||
#[doc="TEXT[]"]
|
#[doc="TEXT[]"]
|
||||||
1009 => TextArray: Kind::Array(Type::Text),
|
1009: "_text" => TextArray: Kind::Array(Type::Text),
|
||||||
#[doc="TID[]"]
|
#[doc="TID[]"]
|
||||||
1010 => TidArray: Kind::Array(Type::Tid),
|
1010: "_tid" => TidArray: Kind::Array(Type::Tid),
|
||||||
#[doc="XID[]"]
|
#[doc="XID[]"]
|
||||||
1011 => XidArray: Kind::Array(Type::Xid),
|
1011: "_xid" => XidArray: Kind::Array(Type::Xid),
|
||||||
#[doc="CID[]"]
|
#[doc="CID[]"]
|
||||||
1012 => CidArray: Kind::Array(Type::Cid),
|
1012: "_cid" => CidArray: Kind::Array(Type::Cid),
|
||||||
#[doc="OIDVECTOR[]"]
|
#[doc="OIDVECTOR[]"]
|
||||||
1013 => OidVectorArray: Kind::Array(Type::OidVector),
|
1013: "_oidvector" => OidVectorArray: Kind::Array(Type::OidVector),
|
||||||
#[doc="BPCHAR[]"]
|
#[doc="BPCHAR[]"]
|
||||||
1014 => BpcharArray: Kind::Array(Type::Bpchar),
|
1014: "_bpchar" => BpcharArray: Kind::Array(Type::Bpchar),
|
||||||
#[doc="VARCHAR[]"]
|
#[doc="VARCHAR[]"]
|
||||||
1015 => VarcharArray: Kind::Array(Type::Varchar),
|
1015: "_varchar" => VarcharArray: Kind::Array(Type::Varchar),
|
||||||
#[doc="INT8[]"]
|
#[doc="INT8[]"]
|
||||||
1016 => Int8Array: Kind::Array(Type::Int8),
|
1016: "_int8" => Int8Array: Kind::Array(Type::Int8),
|
||||||
#[doc="POINT[]"]
|
#[doc="POINT[]"]
|
||||||
1017 => PointArray: Kind::Array(Type::Point),
|
1017: "_point" => PointArray: Kind::Array(Type::Point),
|
||||||
#[doc="LSEG[]"]
|
#[doc="LSEG[]"]
|
||||||
1018 => LsegArray: Kind::Array(Type::Lseg),
|
1018: "_lseg" => LsegArray: Kind::Array(Type::Lseg),
|
||||||
#[doc="PATH[]"]
|
#[doc="PATH[]"]
|
||||||
1019 => PathArray: Kind::Array(Type::Path),
|
1019: "_path" => PathArray: Kind::Array(Type::Path),
|
||||||
#[doc="BOX[]"]
|
#[doc="BOX[]"]
|
||||||
1020 => BoxArray: Kind::Array(Type::Box),
|
1020: "_box" => BoxArray: Kind::Array(Type::Box),
|
||||||
#[doc="FLOAT4[]"]
|
#[doc="FLOAT4[]"]
|
||||||
1021 => Float4Array: Kind::Array(Type::Float4),
|
1021: "_float4" => Float4Array: Kind::Array(Type::Float4),
|
||||||
#[doc="FLOAT8[]"]
|
#[doc="FLOAT8[]"]
|
||||||
1022 => Float8Array: Kind::Array(Type::Float8),
|
1022: "_float8" => Float8Array: Kind::Array(Type::Float8),
|
||||||
#[doc="ABSTIME[]"]
|
#[doc="ABSTIME[]"]
|
||||||
1023 => AbstimeArray: Kind::Array(Type::Abstime),
|
1023: "_abstime" => AbstimeArray: Kind::Array(Type::Abstime),
|
||||||
#[doc="RELTIME[]"]
|
#[doc="RELTIME[]"]
|
||||||
1024 => ReltimeArray: Kind::Array(Type::Reltime),
|
1024: "_reltime" => ReltimeArray: Kind::Array(Type::Reltime),
|
||||||
#[doc="TINTERVAL[]"]
|
#[doc="TINTERVAL[]"]
|
||||||
1025 => TintervalArray: Kind::Array(Type::Tinterval),
|
1025: "_tinterval" => TintervalArray: Kind::Array(Type::Tinterval),
|
||||||
#[doc="POLYGON[]"]
|
#[doc="POLYGON[]"]
|
||||||
1027 => PolygonArray: Kind::Array(Type::Polygon),
|
1027: "_polygon" => PolygonArray: Kind::Array(Type::Polygon),
|
||||||
#[doc="OID[]"]
|
#[doc="OID[]"]
|
||||||
1028 => OidArray: Kind::Array(Type::Oid),
|
1028: "_oid" => OidArray: Kind::Array(Type::Oid),
|
||||||
#[doc="ACLITEM - access control list"]
|
#[doc="ACLITEM - access control list"]
|
||||||
1033 => Aclitem: Kind::Simple,
|
1033: "aclitem" => Aclitem: Kind::Simple,
|
||||||
#[doc="ACLITEM[]"]
|
#[doc="ACLITEM[]"]
|
||||||
1034 => AclitemArray: Kind::Array(Type::Aclitem),
|
1034: "_aclitem" => AclitemArray: Kind::Array(Type::Aclitem),
|
||||||
#[doc="MACADDR[]"]
|
#[doc="MACADDR[]"]
|
||||||
1040 => MacaddrArray: Kind::Array(Type::Macaddr),
|
1040: "_macaddr" => MacaddrArray: Kind::Array(Type::Macaddr),
|
||||||
#[doc="INET[]"]
|
#[doc="INET[]"]
|
||||||
1041 => InetArray: Kind::Array(Type::Inet),
|
1041: "_inet" => InetArray: Kind::Array(Type::Inet),
|
||||||
#[doc="BPCHAR - char(length), blank-padded string, fixed storage length"]
|
#[doc="BPCHAR - char(length), blank-padded string, fixed storage length"]
|
||||||
1042 => Bpchar: Kind::Simple,
|
1042: "bpchar" => Bpchar: Kind::Simple,
|
||||||
#[doc="VARCHAR - varchar(length), non-blank-padded string, variable storage length"]
|
#[doc="VARCHAR - varchar(length), non-blank-padded string, variable storage length"]
|
||||||
1043 => Varchar: Kind::Simple,
|
1043: "varchar" => Varchar: Kind::Simple,
|
||||||
#[doc="DATE - date"]
|
#[doc="DATE - date"]
|
||||||
1082 => Date: Kind::Simple,
|
1082: "date" => Date: Kind::Simple,
|
||||||
#[doc="TIME - time of day"]
|
#[doc="TIME - time of day"]
|
||||||
1083 => Time: Kind::Simple,
|
1083: "time" => Time: Kind::Simple,
|
||||||
#[doc="TIMESTAMP - date and time"]
|
#[doc="TIMESTAMP - date and time"]
|
||||||
1114 => Timestamp: Kind::Simple,
|
1114: "timestamp" => Timestamp: Kind::Simple,
|
||||||
#[doc="TIMESTAMP[]"]
|
#[doc="TIMESTAMP[]"]
|
||||||
1115 => TimestampArray: Kind::Array(Type::Timestamp),
|
1115: "_timestamp" => TimestampArray: Kind::Array(Type::Timestamp),
|
||||||
#[doc="DATE[]"]
|
#[doc="DATE[]"]
|
||||||
1182 => DateArray: Kind::Array(Type::Date),
|
1182: "_date" => DateArray: Kind::Array(Type::Date),
|
||||||
#[doc="TIME[]"]
|
#[doc="TIME[]"]
|
||||||
1183 => TimeArray: Kind::Array(Type::Time),
|
1183: "_time" => TimeArray: Kind::Array(Type::Time),
|
||||||
#[doc="TIMESTAMPTZ - date and time with time zone"]
|
#[doc="TIMESTAMPTZ - date and time with time zone"]
|
||||||
1184 => TimestampTZ: Kind::Simple,
|
1184: "timestamptz" => TimestampTZ: Kind::Simple,
|
||||||
#[doc="TIMESTAMPTZ[]"]
|
#[doc="TIMESTAMPTZ[]"]
|
||||||
1185 => TimestampTZArray: Kind::Array(Type::TimestampTZ),
|
1185: "_timestamptz" => TimestampTZArray: Kind::Array(Type::TimestampTZ),
|
||||||
#[doc="INTERVAL - @ <number> <units>, time interval"]
|
#[doc="INTERVAL - @ <number> <units>, time interval"]
|
||||||
1186 => Interval: Kind::Simple,
|
1186: "interval" => Interval: Kind::Simple,
|
||||||
#[doc="INTERVAL[]"]
|
#[doc="INTERVAL[]"]
|
||||||
1187 => IntervalArray: Kind::Array(Type::Interval),
|
1187: "_interval" => IntervalArray: Kind::Array(Type::Interval),
|
||||||
#[doc="NUMERIC[]"]
|
#[doc="NUMERIC[]"]
|
||||||
1231 => NumericArray: Kind::Array(Type::Numeric),
|
1231: "_numeric" => NumericArray: Kind::Array(Type::Numeric),
|
||||||
#[doc="CSTRING[]"]
|
#[doc="CSTRING[]"]
|
||||||
1263 => CstringArray: Kind::Array(Type::Cstring),
|
1263: "_cstring" => CstringArray: Kind::Array(Type::Cstring),
|
||||||
#[doc="TIMETZ - time of day with time zone"]
|
#[doc="TIMETZ - time of day with time zone"]
|
||||||
1266 => Timetz: Kind::Simple,
|
1266: "timetz" => Timetz: Kind::Simple,
|
||||||
#[doc="TIMETZ[]"]
|
#[doc="TIMETZ[]"]
|
||||||
1270 => TimetzArray: Kind::Array(Type::Timetz),
|
1270: "_timetz" => TimetzArray: Kind::Array(Type::Timetz),
|
||||||
#[doc="BIT - fixed-length bit string"]
|
#[doc="BIT - fixed-length bit string"]
|
||||||
1560 => Bit: Kind::Simple,
|
1560: "bit" => Bit: Kind::Simple,
|
||||||
#[doc="BIT[]"]
|
#[doc="BIT[]"]
|
||||||
1561 => BitArray: Kind::Array(Type::Bit),
|
1561: "_bit" => BitArray: Kind::Array(Type::Bit),
|
||||||
#[doc="VARBIT - variable-length bit string"]
|
#[doc="VARBIT - variable-length bit string"]
|
||||||
1562 => Varbit: Kind::Simple,
|
1562: "varbit" => Varbit: Kind::Simple,
|
||||||
#[doc="VARBIT[]"]
|
#[doc="VARBIT[]"]
|
||||||
1563 => VarbitArray: Kind::Array(Type::Varbit),
|
1563: "_varbit" => VarbitArray: Kind::Array(Type::Varbit),
|
||||||
#[doc="NUMERIC - numeric(precision, decimal), arbitrary precision number"]
|
#[doc="NUMERIC - numeric(precision, decimal), arbitrary precision number"]
|
||||||
1700 => Numeric: Kind::Simple,
|
1700: "numeric" => Numeric: Kind::Simple,
|
||||||
#[doc="REFCURSOR - reference to cursor (portal name)"]
|
#[doc="REFCURSOR - reference to cursor (portal name)"]
|
||||||
1790 => Refcursor: Kind::Simple,
|
1790: "refcursor" => Refcursor: Kind::Simple,
|
||||||
#[doc="REFCURSOR[]"]
|
#[doc="REFCURSOR[]"]
|
||||||
2201 => RefcursorArray: Kind::Array(Type::Refcursor),
|
2201: "_refcursor" => RefcursorArray: Kind::Array(Type::Refcursor),
|
||||||
#[doc="REGPROCEDURE - registered procedure (with args)"]
|
#[doc="REGPROCEDURE - registered procedure (with args)"]
|
||||||
2202 => Regprocedure: Kind::Simple,
|
2202: "regprocedure" => Regprocedure: Kind::Simple,
|
||||||
#[doc="REGOPER - registered operator"]
|
#[doc="REGOPER - registered operator"]
|
||||||
2203 => Regoper: Kind::Simple,
|
2203: "regoper" => Regoper: Kind::Simple,
|
||||||
#[doc="REGOPERATOR - registered operator (with args)"]
|
#[doc="REGOPERATOR - registered operator (with args)"]
|
||||||
2204 => Regoperator: Kind::Simple,
|
2204: "regoperator" => Regoperator: Kind::Simple,
|
||||||
#[doc="REGCLASS - registered class"]
|
#[doc="REGCLASS - registered class"]
|
||||||
2205 => Regclass: Kind::Simple,
|
2205: "regclass" => Regclass: Kind::Simple,
|
||||||
#[doc="REGTYPE - registered type"]
|
#[doc="REGTYPE - registered type"]
|
||||||
2206 => Regtype: Kind::Simple,
|
2206: "regtype" => Regtype: Kind::Simple,
|
||||||
#[doc="REGPROCEDURE[]"]
|
#[doc="REGPROCEDURE[]"]
|
||||||
2207 => RegprocedureArray: Kind::Array(Type::Regprocedure),
|
2207: "_regprocedure" => RegprocedureArray: Kind::Array(Type::Regprocedure),
|
||||||
#[doc="REGOPER[]"]
|
#[doc="REGOPER[]"]
|
||||||
2208 => RegoperArray: Kind::Array(Type::Regoper),
|
2208: "_regoper" => RegoperArray: Kind::Array(Type::Regoper),
|
||||||
#[doc="REGOPERATOR[]"]
|
#[doc="REGOPERATOR[]"]
|
||||||
2209 => RegoperatorArray: Kind::Array(Type::Regoperator),
|
2209: "_regoperator" => RegoperatorArray: Kind::Array(Type::Regoperator),
|
||||||
#[doc="REGCLASS[]"]
|
#[doc="REGCLASS[]"]
|
||||||
2210 => RegclassArray: Kind::Array(Type::Regclass),
|
2210: "_regclass" => RegclassArray: Kind::Array(Type::Regclass),
|
||||||
#[doc="REGTYPE[]"]
|
#[doc="REGTYPE[]"]
|
||||||
2211 => RegtypeArray: Kind::Array(Type::Regtype),
|
2211: "_regtype" => RegtypeArray: Kind::Array(Type::Regtype),
|
||||||
#[doc="RECORD"]
|
#[doc="RECORD"]
|
||||||
2249 => Record: Kind::Simple,
|
2249: "record" => Record: Kind::Simple,
|
||||||
#[doc="CSTRING"]
|
#[doc="CSTRING"]
|
||||||
2275 => Cstring: Kind::Simple,
|
2275: "cstring" => Cstring: Kind::Simple,
|
||||||
#[doc="ANY"]
|
#[doc="ANY"]
|
||||||
2276 => Any: Kind::Simple,
|
2276: "any" => Any: Kind::Simple,
|
||||||
#[doc="ANY[]"]
|
#[doc="ANYARRAY"]
|
||||||
2277 => AnyArray: Kind::Array(Type::Any),
|
2277: "anyarray" => AnyArray: Kind::Array(Type::Any),
|
||||||
#[doc="VOID"]
|
#[doc="VOID"]
|
||||||
2278 => Void: Kind::Simple,
|
2278: "void" => Void: Kind::Simple,
|
||||||
#[doc="TRIGGER"]
|
#[doc="TRIGGER"]
|
||||||
2279 => Trigger: Kind::Simple,
|
2279: "trigger" => Trigger: Kind::Simple,
|
||||||
#[doc="LANGUAGE_HANDLER"]
|
#[doc="LANGUAGE_HANDLER"]
|
||||||
2280 => LanguageHandler: Kind::Simple,
|
2280: "language_handler" => LanguageHandler: Kind::Simple,
|
||||||
#[doc="INTERNAL"]
|
#[doc="INTERNAL"]
|
||||||
2281 => Internal: Kind::Simple,
|
2281: "internal" => Internal: Kind::Simple,
|
||||||
#[doc="OPAQUE"]
|
#[doc="OPAQUE"]
|
||||||
2282 => Opaque: Kind::Simple,
|
2282: "opaque" => Opaque: Kind::Simple,
|
||||||
#[doc="ANYELEMENT"]
|
#[doc="ANYELEMENT"]
|
||||||
2283 => Anyelement: Kind::Simple,
|
2283: "anyelement" => Anyelement: Kind::Simple,
|
||||||
#[doc="RECORD[]"]
|
#[doc="RECORD[]"]
|
||||||
2287 => RecordArray: Kind::Array(Type::Record),
|
2287: "_record" => RecordArray: Kind::Array(Type::Record),
|
||||||
#[doc="ANYNONARRAY"]
|
#[doc="ANYNONARRAY"]
|
||||||
2776 => Anynonarray: Kind::Simple,
|
2776: "anynonarray" => Anynonarray: Kind::Simple,
|
||||||
#[doc="TXID_SNAPSHOT[]"]
|
#[doc="TXID_SNAPSHOT[]"]
|
||||||
2949 => TxidSnapshotArray: Kind::Array(Type::TxidSnapshot),
|
2949: "_txid_snapshot" => TxidSnapshotArray: Kind::Array(Type::TxidSnapshot),
|
||||||
#[doc="UUID - UUID datatype"]
|
#[doc="UUID - UUID datatype"]
|
||||||
2950 => Uuid: Kind::Simple,
|
2950: "uuid" => Uuid: Kind::Simple,
|
||||||
#[doc="TXID_SNAPSHOT - txid snapshot"]
|
#[doc="TXID_SNAPSHOT - txid snapshot"]
|
||||||
2970 => TxidSnapshot: Kind::Simple,
|
2970: "txid_snapshot" => TxidSnapshot: Kind::Simple,
|
||||||
#[doc="UUID[]"]
|
#[doc="UUID[]"]
|
||||||
2951 => UuidArray: Kind::Array(Type::Uuid),
|
2951: "_uuid" => UuidArray: Kind::Array(Type::Uuid),
|
||||||
#[doc="FDW_HANDLER"]
|
#[doc="FDW_HANDLER"]
|
||||||
3115 => FdwHandler: Kind::Simple,
|
3115: "fdw_handler" => FdwHandler: Kind::Simple,
|
||||||
#[doc="PG_LSN - PostgreSQL LSN datatype"]
|
#[doc="PG_LSN - PostgreSQL LSN datatype"]
|
||||||
3320 => PgLsn: Kind::Simple,
|
3220: "pg_lsn" => PgLsn: Kind::Simple,
|
||||||
#[doc="PG_LSN[]"]
|
#[doc="PG_LSN[]"]
|
||||||
3321 => PgLsnArray: Kind::Array(Type::PgLsn),
|
3221: "_pg_lsn" => PgLsnArray: Kind::Array(Type::PgLsn),
|
||||||
#[doc="ANYENUM"]
|
#[doc="ANYENUM"]
|
||||||
3500 => Anyenum: Kind::Simple,
|
3500: "anyenum" => Anyenum: Kind::Simple,
|
||||||
#[doc="TSVECTOR - text representation for text search"]
|
#[doc="TSVECTOR - text representation for text search"]
|
||||||
3614 => Tsvector: Kind::Simple,
|
3614: "tsvector" => Tsvector: Kind::Simple,
|
||||||
#[doc="TSQUERY - query representation for text search"]
|
#[doc="TSQUERY - query representation for text search"]
|
||||||
3615 => Tsquery: Kind::Simple,
|
3615: "tsquery" => Tsquery: Kind::Simple,
|
||||||
#[doc="GTSVECTOR - GiST index internal text representation for text search"]
|
#[doc="GTSVECTOR - GiST index internal text representation for text search"]
|
||||||
3642 => Gtsvector: Kind::Simple,
|
3642: "gtsvector" => Gtsvector: Kind::Simple,
|
||||||
#[doc="TSVECTOR[]"]
|
#[doc="TSVECTOR[]"]
|
||||||
3643 => TsvectorArray: Kind::Array(Type::Tsvector),
|
3643: "_tsvector" => TsvectorArray: Kind::Array(Type::Tsvector),
|
||||||
#[doc="GTSVECTOR[]"]
|
#[doc="GTSVECTOR[]"]
|
||||||
3644 => GtsvectorArray: Kind::Array(Type::Gtsvector),
|
3644: "_gtsvector" => GtsvectorArray: Kind::Array(Type::Gtsvector),
|
||||||
#[doc="TSQUERY[]"]
|
#[doc="TSQUERY[]"]
|
||||||
3645 => TsqueryArray: Kind::Array(Type::Tsquery),
|
3645: "_tsquery" => TsqueryArray: Kind::Array(Type::Tsquery),
|
||||||
#[doc="REGCONFIG - registered text search configuration"]
|
#[doc="REGCONFIG - registered text search configuration"]
|
||||||
3734 => Regconfig: Kind::Simple,
|
3734: "regconfig" => Regconfig: Kind::Simple,
|
||||||
#[doc="REGCONFIG[]"]
|
#[doc="REGCONFIG[]"]
|
||||||
3735 => RegconfigArray: Kind::Array(Type::Regconfig),
|
3735: "_regconfig" => RegconfigArray: Kind::Array(Type::Regconfig),
|
||||||
#[doc="REGDICTIONARY - registered text search dictionary"]
|
#[doc="REGDICTIONARY - registered text search dictionary"]
|
||||||
3769 => Regdictionary: Kind::Simple,
|
3769: "regdictionary" => Regdictionary: Kind::Simple,
|
||||||
#[doc="REGDICTIONARY[]"]
|
#[doc="REGDICTIONARY[]"]
|
||||||
3770 => RegdictionaryArray: Kind::Array(Type::Regdictionary),
|
3770: "_regdictionary" => RegdictionaryArray: Kind::Array(Type::Regdictionary),
|
||||||
#[doc="JSONB"]
|
#[doc="JSONB"]
|
||||||
3802 => Jsonb: Kind::Simple,
|
3802: "jsonb" => Jsonb: Kind::Simple,
|
||||||
#[doc="ANYRANGE"]
|
#[doc="ANYRANGE"]
|
||||||
3831 => Anyrange: Kind::Simple,
|
3831: "anyrange" => Anyrange: Kind::Simple,
|
||||||
#[doc="JSONB[]"]
|
#[doc="JSONB[]"]
|
||||||
3807 => JsonbArray: Kind::Array(Type::Jsonb),
|
3807: "_jsonb" => JsonbArray: Kind::Array(Type::Jsonb),
|
||||||
#[doc="INT4RANGE - range of integers"]
|
#[doc="INT4RANGE - range of integers"]
|
||||||
3904 => Int4Range: Kind::Range(Type::Int4),
|
3904: "int4range" => Int4Range: Kind::Range(Type::Int4),
|
||||||
#[doc="INT4RANGE[]"]
|
#[doc="INT4RANGE[]"]
|
||||||
3905 => Int4RangeArray: Kind::Array(Type::Int4Range),
|
3905: "_int4range" => Int4RangeArray: Kind::Array(Type::Int4Range),
|
||||||
#[doc="NUMRANGE - range of numerics"]
|
#[doc="NUMRANGE - range of numerics"]
|
||||||
3906 => NumRange: Kind::Range(Type::Numeric),
|
3906: "numrange" => NumRange: Kind::Range(Type::Numeric),
|
||||||
#[doc="NUMRANGE[]"]
|
#[doc="NUMRANGE[]"]
|
||||||
3907 => NumRangeArray: Kind::Array(Type::NumRange),
|
3907: "_numrange" => NumRangeArray: Kind::Array(Type::NumRange),
|
||||||
#[doc="TSRANGE - range of timestamps without time zone"]
|
#[doc="TSRANGE - range of timestamps without time zone"]
|
||||||
3908 => TsRange: Kind::Range(Type::Timestamp),
|
3908: "tsrange" => TsRange: Kind::Range(Type::Timestamp),
|
||||||
#[doc="TSRANGE[]"]
|
#[doc="TSRANGE[]"]
|
||||||
3909 => TsRangeArray: Kind::Array(Type::TsRange),
|
3909: "_tsrange" => TsRangeArray: Kind::Array(Type::TsRange),
|
||||||
#[doc="TSTZRANGE - range of timestamps with time zone"]
|
#[doc="TSTZRANGE - range of timestamps with time zone"]
|
||||||
3910 => TstzRange: Kind::Range(Type::TimestampTZ),
|
3910: "tstzrange" => TstzRange: Kind::Range(Type::TimestampTZ),
|
||||||
#[doc="TSTZRANGE[]"]
|
#[doc="TSTZRANGE[]"]
|
||||||
3911 => TstzRangeArray: Kind::Array(Type::TstzRange),
|
3911: "_tstzrange" => TstzRangeArray: Kind::Array(Type::TstzRange),
|
||||||
#[doc="DATERANGE - range of dates"]
|
#[doc="DATERANGE - range of dates"]
|
||||||
3912 => DateRange: Kind::Range(Type::Date),
|
3912: "daterange" => DateRange: Kind::Range(Type::Date),
|
||||||
#[doc="DATERANGE[]"]
|
#[doc="DATERANGE[]"]
|
||||||
3913 => DateRangeArray: Kind::Array(Type::DateRange),
|
3913: "_daterange" => DateRangeArray: Kind::Array(Type::DateRange),
|
||||||
#[doc="INT8RANGE - range of bigints"]
|
#[doc="INT8RANGE - range of bigints"]
|
||||||
3926 => Int8Range: Kind::Range(Type::Int8),
|
3926: "int8range" => Int8Range: Kind::Range(Type::Int8),
|
||||||
#[doc="INT8RANGE[]"]
|
#[doc="INT8RANGE[]"]
|
||||||
3927 => Int8RangeArray: Kind::Array(Type::Int8Range),
|
3927: "_int8range" => Int8RangeArray: Kind::Array(Type::Int8Range),
|
||||||
#[doc="EVENT_TRIGGER"]
|
#[doc="EVENT_TRIGGER"]
|
||||||
3838 => EventTrigger: Kind::Simple
|
3838: "event_trigger" => EventTrigger: Kind::Simple
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about an unknown type.
|
/// Information about an unknown type.
|
||||||
@ -476,14 +496,16 @@ pub struct Other {
|
|||||||
name: String,
|
name: String,
|
||||||
oid: Oid,
|
oid: Oid,
|
||||||
kind: Kind,
|
kind: Kind,
|
||||||
|
schema: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OtherNew for Other {
|
impl OtherNew for Other {
|
||||||
fn new(name: String, oid: Oid, kind: Kind) -> Other {
|
fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other {
|
||||||
Other {
|
Other {
|
||||||
name: name,
|
name: name,
|
||||||
oid: oid,
|
oid: oid,
|
||||||
kind: kind,
|
kind: kind,
|
||||||
|
schema: schema,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,6 +525,11 @@ impl Other {
|
|||||||
pub fn kind(&self) -> &Kind {
|
pub fn kind(&self) -> &Kind {
|
||||||
&self.kind
|
&self.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The schema of this type.
|
||||||
|
pub fn schema(&self) -> &str {
|
||||||
|
&self.schema
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
|
/// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
|
||||||
@ -546,13 +573,13 @@ impl error::Error for WasNull {
|
|||||||
/// In addition, some implementations are provided for types in third party
|
/// In addition, some implementations are provided for types in third party
|
||||||
/// crates. These are disabled by default; to opt into one of these
|
/// crates. These are disabled by default; to opt into one of these
|
||||||
/// implementations, activate the Cargo feature corresponding to the crate's
|
/// implementations, activate the Cargo feature corresponding to the crate's
|
||||||
/// name. For example, the `serde` feature enables the implementation for the
|
/// name. For example, the `serde_json` feature enables the implementation for
|
||||||
/// `serde::json::Value` type.
|
/// the `serde_json::Value` type.
|
||||||
///
|
///
|
||||||
/// | Rust type | Postgres type(s) |
|
/// | Rust type | Postgres type(s) |
|
||||||
/// |-------------------------------------|-------------------------------------|
|
/// |-------------------------------------|-------------------------------------|
|
||||||
/// | serialize::json::Json | JSON, JSONB |
|
/// | serialize::json::Json | JSON, JSONB |
|
||||||
/// | serde::json::Value | JSON, JSONB |
|
/// | serde_json::Value | JSON, JSONB |
|
||||||
/// | time::Timespec | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
|
/// | time::Timespec | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
|
||||||
/// | chrono::NaiveDateTime | TIMESTAMP |
|
/// | chrono::NaiveDateTime | TIMESTAMP |
|
||||||
/// | chrono::DateTime<UTC> | TIMESTAMP WITH TIME ZONE |
|
/// | chrono::DateTime<UTC> | TIMESTAMP WITH TIME ZONE |
|
||||||
@ -568,21 +595,12 @@ impl error::Error for WasNull {
|
|||||||
/// `Option<T>` where `T` implements `FromSql`. An `Option<T>` represents a
|
/// `Option<T>` where `T` implements `FromSql`. An `Option<T>` represents a
|
||||||
/// nullable Postgres value.
|
/// nullable Postgres value.
|
||||||
pub trait FromSql: Sized {
|
pub trait FromSql: Sized {
|
||||||
/// Creates a new value of this type from a `Read`er of Postgres data.
|
/// ### Deprecated
|
||||||
///
|
|
||||||
/// If the value was `NULL`, the `Read`er will be `None`.
|
|
||||||
///
|
|
||||||
/// The caller of this method is responsible for ensuring that this type
|
|
||||||
/// is compatible with the Postgres `Type`.
|
|
||||||
///
|
|
||||||
/// The default implementation calls `FromSql::from_sql` when `raw` is
|
|
||||||
/// `Some` and returns `Err(Error::Conversion(Box::new(WasNull))` when
|
|
||||||
/// `raw` is `None`. It does not typically need to be overridden.
|
|
||||||
fn from_sql_nullable<R: Read>(ty: &Type, raw: Option<&mut R>, ctx: &SessionInfo)
|
fn from_sql_nullable<R: Read>(ty: &Type, raw: Option<&mut R>, ctx: &SessionInfo)
|
||||||
-> Result<Self> {
|
-> Result<Self> {
|
||||||
match raw {
|
match raw {
|
||||||
Some(raw) => FromSql::from_sql(ty, raw, ctx),
|
Some(raw) => FromSql::from_sql(ty, raw, ctx),
|
||||||
None => Err(Error::Conversion(Box::new(WasNull))),
|
None => FromSql::from_sql_null(ty, ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,24 +611,32 @@ pub trait FromSql: Sized {
|
|||||||
/// is compatible with the Postgres `Type`.
|
/// is compatible with the Postgres `Type`.
|
||||||
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self>;
|
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self>;
|
||||||
|
|
||||||
|
/// Creates a new value of this type from a `NULL` SQL value.
|
||||||
|
///
|
||||||
|
/// The caller of this method is responsible for ensuring that this type
|
||||||
|
/// is compatible with the Postgres `Type`.
|
||||||
|
///
|
||||||
|
/// The default implementation returns
|
||||||
|
/// `Err(Error::Conversion(Box::new(WasNull))`.
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn from_sql_null(ty: &Type, ctx: &SessionInfo) -> Result<Self> {
|
||||||
|
Err(Error::Conversion(Box::new(WasNull)))
|
||||||
|
}
|
||||||
|
|
||||||
/// Determines if a value of this type can be created from the specified
|
/// Determines if a value of this type can be created from the specified
|
||||||
/// Postgres `Type`.
|
/// Postgres `Type`.
|
||||||
fn accepts(ty: &Type) -> bool;
|
fn accepts(ty: &Type) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromSql> FromSql for Option<T> {
|
impl<T: FromSql> FromSql for Option<T> {
|
||||||
fn from_sql_nullable<R: Read>(ty: &Type, raw: Option<&mut R>, ctx: &SessionInfo)
|
|
||||||
-> Result<Option<T>> {
|
|
||||||
match raw {
|
|
||||||
Some(raw) => <T as FromSql>::from_sql(ty, raw, ctx).map(Some),
|
|
||||||
None => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Option<T>> {
|
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Option<T>> {
|
||||||
<T as FromSql>::from_sql(ty, raw, ctx).map(Some)
|
<T as FromSql>::from_sql(ty, raw, ctx).map(Some)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_sql_null(_: &Type, _: &SessionInfo) -> Result<Option<T>> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
<T as FromSql>::accepts(ty)
|
<T as FromSql>::accepts(ty)
|
||||||
}
|
}
|
||||||
@ -753,13 +779,13 @@ pub enum IsNull {
|
|||||||
/// In addition, some implementations are provided for types in third party
|
/// In addition, some implementations are provided for types in third party
|
||||||
/// crates. These are disabled by default; to opt into one of these
|
/// crates. These are disabled by default; to opt into one of these
|
||||||
/// implementations, activate the Cargo feature corresponding to the crate's
|
/// implementations, activate the Cargo feature corresponding to the crate's
|
||||||
/// name. For example, the `serde` feature enables the implementation for the
|
/// name. For example, the `serde_json` feature enables the implementation for
|
||||||
/// `serde::json::Value` type.
|
/// the `serde_json::Value` type.
|
||||||
///
|
///
|
||||||
/// | Rust type | Postgres type(s) |
|
/// | Rust type | Postgres type(s) |
|
||||||
/// |-------------------------------------|-------------------------------------|
|
/// |-------------------------------------|-------------------------------------|
|
||||||
/// | serialize::json::Json | JSON, JSONB |
|
/// | serialize::json::Json | JSON, JSONB |
|
||||||
/// | serde::json::Value | JSON, JSONB |
|
/// | serde_json::Value | JSON, JSONB |
|
||||||
/// | time::Timespec | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
|
/// | time::Timespec | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
|
||||||
/// | chrono::NaiveDateTime | TIMESTAMP |
|
/// | chrono::NaiveDateTime | TIMESTAMP |
|
||||||
/// | chrono::DateTime<UTC> | TIMESTAMP WITH TIME ZONE |
|
/// | chrono::DateTime<UTC> | TIMESTAMP WITH TIME ZONE |
|
||||||
|
41
src/types/serde_json.rs
Normal file
41
src/types/serde_json.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
use std::error;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||||
|
use self::serde_json::Value;
|
||||||
|
|
||||||
|
use Result;
|
||||||
|
use error::Error;
|
||||||
|
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
|
||||||
|
|
||||||
|
impl FromSql for Value {
|
||||||
|
fn from_sql<R: Read>(ty: &Type, raw: &mut R, _: &SessionInfo) -> Result<Value> {
|
||||||
|
if let Type::Jsonb = *ty {
|
||||||
|
// We only support version 1 of the jsonb binary format
|
||||||
|
if try!(raw.read_u8()) != 1 {
|
||||||
|
let err: Box<error::Error+Sync+Send> = "unsupported JSONB encoding version".into();
|
||||||
|
return Err(Error::Conversion(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serde_json::de::from_reader(raw).map_err(|err| Error::Conversion(Box::new(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
accepts!(Type::Json, Type::Jsonb);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSql for Value {
|
||||||
|
fn to_sql<W: Write+?Sized>(&self, ty: &Type, mut out: &mut W, _: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
|
if let Type::Jsonb = *ty {
|
||||||
|
try!(out.write_u8(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(write!(out, "{:?}", self));
|
||||||
|
|
||||||
|
Ok(IsNull::No)
|
||||||
|
}
|
||||||
|
|
||||||
|
accepts!(Type::Json, Type::Jsonb);
|
||||||
|
to_sql_checked!();
|
||||||
|
}
|
30
src/url.rs
30
src/url.rs
@ -65,9 +65,9 @@ impl Url {
|
|||||||
// query and fragment
|
// query and fragment
|
||||||
let (query, fragment) = try!(get_query_fragment(rest));
|
let (query, fragment) = try!(get_query_fragment(rest));
|
||||||
|
|
||||||
let url = Url::new(scheme.to_string(),
|
let url = Url::new(scheme.to_owned(),
|
||||||
userinfo,
|
userinfo,
|
||||||
host.to_string(),
|
host.to_owned(),
|
||||||
port,
|
port,
|
||||||
path,
|
path,
|
||||||
query,
|
query,
|
||||||
@ -180,22 +180,22 @@ pub fn get_scheme(rawurl: &str) -> DecodeResult<(&str, &str)> {
|
|||||||
'0' ... '9' | '+' | '-' | '.' => {
|
'0' ... '9' | '+' | '-' | '.' => {
|
||||||
if i != 0 { continue }
|
if i != 0 { continue }
|
||||||
|
|
||||||
Err("url: Scheme must begin with a letter.".to_string())
|
Err("url: Scheme must begin with a letter.".to_owned())
|
||||||
}
|
}
|
||||||
':' => {
|
':' => {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
Err("url: Scheme cannot be empty.".to_string())
|
Err("url: Scheme cannot be empty.".to_owned())
|
||||||
} else {
|
} else {
|
||||||
Ok((&rawurl[0..i], &rawurl[i+1..rawurl.len()]))
|
Ok((&rawurl[0..i], &rawurl[i+1..rawurl.len()]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err("url: Invalid character in scheme.".to_string()),
|
_ => Err("url: Invalid character in scheme.".to_owned()),
|
||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Err("url: Scheme must be terminated with a colon.".to_string())
|
Err("url: Scheme must be terminated with a colon.".to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns userinfo, host, port, and unparsed part, or an error
|
// returns userinfo, host, port, and unparsed part, or an error
|
||||||
@ -255,7 +255,7 @@ fn get_authority(rawurl: &str) ->
|
|||||||
':' | '@' | '?' | '#' | '/' => {
|
':' | '@' | '?' | '#' | '/' => {
|
||||||
// separators, don't change anything
|
// separators, don't change anything
|
||||||
}
|
}
|
||||||
_ => return Err("Illegal character in authority".to_string()),
|
_ => return Err("Illegal character in authority".to_owned()),
|
||||||
}
|
}
|
||||||
|
|
||||||
// now process states
|
// now process states
|
||||||
@ -271,7 +271,7 @@ fn get_authority(rawurl: &str) ->
|
|||||||
// multiple colons means ipv6 address.
|
// multiple colons means ipv6 address.
|
||||||
if input == Input::Unreserved {
|
if input == Input::Unreserved {
|
||||||
return Err(
|
return Err(
|
||||||
"Illegal characters in IPv6 address.".to_string());
|
"Illegal characters in IPv6 address.".to_owned());
|
||||||
}
|
}
|
||||||
st = State::Ip6Host;
|
st = State::Ip6Host;
|
||||||
}
|
}
|
||||||
@ -288,7 +288,7 @@ fn get_authority(rawurl: &str) ->
|
|||||||
}
|
}
|
||||||
State::Ip6Port => {
|
State::Ip6Port => {
|
||||||
if input == Input::Unreserved {
|
if input == Input::Unreserved {
|
||||||
return Err("Illegal characters in authority.".to_string());
|
return Err("Illegal characters in authority.".to_owned());
|
||||||
}
|
}
|
||||||
st = State::Ip6Host;
|
st = State::Ip6Host;
|
||||||
}
|
}
|
||||||
@ -299,7 +299,7 @@ fn get_authority(rawurl: &str) ->
|
|||||||
st = State::InPort;
|
st = State::InPort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err("Invalid ':' in authority.".to_string()),
|
_ => return Err("Invalid ':' in authority.".to_owned()),
|
||||||
}
|
}
|
||||||
input = Input::Digit; // reset input class
|
input = Input::Digit; // reset input class
|
||||||
}
|
}
|
||||||
@ -319,7 +319,7 @@ fn get_authority(rawurl: &str) ->
|
|||||||
userinfo = Some(UserInfo::new(user, Some(pass)));
|
userinfo = Some(UserInfo::new(user, Some(pass)));
|
||||||
st = State::InHost;
|
st = State::InHost;
|
||||||
}
|
}
|
||||||
_ => return Err("Invalid '@' in authority.".to_string()),
|
_ => return Err("Invalid '@' in authority.".to_owned()),
|
||||||
}
|
}
|
||||||
begin = i+1;
|
begin = i+1;
|
||||||
}
|
}
|
||||||
@ -338,7 +338,7 @@ fn get_authority(rawurl: &str) ->
|
|||||||
State::PassHostPort
|
State::PassHostPort
|
||||||
| State::Ip6Port => {
|
| State::Ip6Port => {
|
||||||
if input != Input::Digit {
|
if input != Input::Digit {
|
||||||
return Err("Non-digit characters in port.".to_string());
|
return Err("Non-digit characters in port.".to_owned());
|
||||||
}
|
}
|
||||||
host = &rawurl[begin..pos];
|
host = &rawurl[begin..pos];
|
||||||
port = Some(&rawurl[pos+1..end]);
|
port = Some(&rawurl[pos+1..end]);
|
||||||
@ -347,7 +347,7 @@ fn get_authority(rawurl: &str) ->
|
|||||||
| State::InHost => host = &rawurl[begin..end],
|
| State::InHost => host = &rawurl[begin..end],
|
||||||
State::InPort => {
|
State::InPort => {
|
||||||
if input != Input::Digit {
|
if input != Input::Digit {
|
||||||
return Err("Non-digit characters in port.".to_string());
|
return Err("Non-digit characters in port.".to_owned());
|
||||||
}
|
}
|
||||||
port = Some(&rawurl[pos+1..end]);
|
port = Some(&rawurl[pos+1..end]);
|
||||||
}
|
}
|
||||||
@ -384,13 +384,13 @@ fn get_path(rawurl: &str, is_authority: bool) -> DecodeResult<(String, &str)> {
|
|||||||
end = i;
|
end = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => return Err("Invalid character in path.".to_string())
|
_ => return Err("Invalid character in path.".to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_authority && end != 0 && !rawurl.starts_with("/") {
|
if is_authority && end != 0 && !rawurl.starts_with("/") {
|
||||||
Err("Non-empty path must begin with \
|
Err("Non-empty path must begin with \
|
||||||
'/' in presence of authority.".to_string())
|
'/' in presence of authority.".to_owned())
|
||||||
} else {
|
} else {
|
||||||
Ok((try!(decode_component(&rawurl[0..end])), &rawurl[end..len]))
|
Ok((try!(decode_component(&rawurl[0..end])), &rawurl[end..len]))
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ use openssl::ssl::{SslContext, SslMethod};
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use postgres::{HandleNotice,
|
use postgres::{HandleNotice,
|
||||||
Connection,
|
Connection,
|
||||||
@ -17,7 +18,7 @@ use postgres::{HandleNotice,
|
|||||||
IntoConnectParams,
|
IntoConnectParams,
|
||||||
IsolationLevel};
|
IsolationLevel};
|
||||||
use postgres::error::{Error, ConnectError, DbError};
|
use postgres::error::{Error, ConnectError, DbError};
|
||||||
use postgres::types::{Type, Kind};
|
use postgres::types::{Oid, Type, Kind};
|
||||||
use postgres::error::SqlState::{SyntaxError,
|
use postgres::error::SqlState::{SyntaxError,
|
||||||
QueryCanceled,
|
QueryCanceled,
|
||||||
UndefinedTable,
|
UndefinedTable,
|
||||||
@ -609,6 +610,30 @@ fn test_notifications_next_block() {
|
|||||||
}, or_panic!(notifications.blocking_iter().next().unwrap()));
|
}, or_panic!(notifications.blocking_iter().next().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_notification_next_timeout() {
|
||||||
|
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
|
||||||
|
or_panic!(conn.execute("LISTEN test_notifications_next_timeout", &[]));
|
||||||
|
|
||||||
|
let _t = thread::spawn(|| {
|
||||||
|
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
|
||||||
|
thread::sleep_ms(500);
|
||||||
|
or_panic!(conn.execute("NOTIFY test_notifications_next_timeout, 'foo'", &[]));
|
||||||
|
thread::sleep_ms(1500);
|
||||||
|
or_panic!(conn.execute("NOTIFY test_notifications_next_timeout, 'foo'", &[]));
|
||||||
|
});
|
||||||
|
|
||||||
|
let notifications = conn.notifications();
|
||||||
|
let mut it = notifications.timeout_iter(Duration::from_secs(1));
|
||||||
|
check_notification(Notification {
|
||||||
|
pid: 0,
|
||||||
|
channel: "test_notifications_next_timeout".to_string(),
|
||||||
|
payload: "foo".to_string()
|
||||||
|
}, or_panic!(it.next().unwrap()));
|
||||||
|
|
||||||
|
assert!(it.next().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// This test is pretty sad, but I don't think there's a better way :(
|
// This test is pretty sad, but I don't think there's a better way :(
|
||||||
fn test_cancel_query() {
|
fn test_cancel_query() {
|
||||||
@ -786,6 +811,21 @@ fn test_copy_out() {
|
|||||||
or_panic!(conn.batch_execute("SELECT 1"));
|
or_panic!(conn.batch_execute("SELECT 1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_copy_out_error() {
|
||||||
|
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
|
||||||
|
or_panic!(conn.batch_execute("
|
||||||
|
CREATE TEMPORARY TABLE foo (id INT);
|
||||||
|
INSERT INTO foo (id) VALUES (0), (1), (2), (3)"));
|
||||||
|
let stmt = or_panic!(conn.prepare("COPY (SELECT id FROM foo ORDER BY id) TO STDOUT (OIDS)"));
|
||||||
|
let mut buf = vec![];
|
||||||
|
match stmt.copy_out(&[], &mut buf) {
|
||||||
|
Ok(_) => panic!("unexpected success"),
|
||||||
|
Err(Error::DbError(..)) => {}
|
||||||
|
Err(e) => panic!("unexpected error {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// Just make sure the impls don't infinite loop
|
// Just make sure the impls don't infinite loop
|
||||||
fn test_generic_connection() {
|
fn test_generic_connection() {
|
||||||
@ -812,6 +852,7 @@ fn test_custom_range_element_type() {
|
|||||||
&Type::Other(ref u) => {
|
&Type::Other(ref u) => {
|
||||||
assert_eq!("floatrange", u.name());
|
assert_eq!("floatrange", u.name());
|
||||||
assert_eq!(&Kind::Range(Type::Float8), u.kind());
|
assert_eq!(&Kind::Range(Type::Float8), u.kind());
|
||||||
|
assert_eq!("public", u.schema());
|
||||||
}
|
}
|
||||||
t => panic!("Unexpected type {:?}", t)
|
t => panic!("Unexpected type {:?}", t)
|
||||||
}
|
}
|
||||||
@ -928,3 +969,19 @@ fn test_row_case_insensitive() {
|
|||||||
assert_eq!(Some(1), "bAr".idx(&stmt));
|
assert_eq!(Some(1), "bAr".idx(&stmt));
|
||||||
assert_eq!(Some(2), "Bar".idx(&stmt));
|
assert_eq!(Some(2), "Bar".idx(&stmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_type_names() {
|
||||||
|
let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
|
||||||
|
let stmt = conn.prepare("SELECT t.oid, t.typname
|
||||||
|
FROM pg_catalog.pg_type t, pg_namespace n
|
||||||
|
WHERE n.oid = t.typnamespace
|
||||||
|
AND n.nspname = 'pg_catalog'
|
||||||
|
AND t.oid < 10000
|
||||||
|
AND t.typtype != 'c'").unwrap();
|
||||||
|
for row in stmt.query(&[]).unwrap() {
|
||||||
|
let id: Oid = row.get(0);
|
||||||
|
let name: String = row.get(1);
|
||||||
|
assert_eq!(Type::from_oid(id).unwrap().name(), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,8 +13,8 @@ mod uuid;
|
|||||||
mod time;
|
mod time;
|
||||||
#[cfg(feature = "rustc-serialize")]
|
#[cfg(feature = "rustc-serialize")]
|
||||||
mod rustc_serialize;
|
mod rustc_serialize;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde_json")]
|
||||||
mod serde;
|
mod serde_json;
|
||||||
#[cfg(feature = "chrono")]
|
#[cfg(feature = "chrono")]
|
||||||
mod chrono;
|
mod chrono;
|
||||||
|
|
||||||
@ -52,8 +52,8 @@ fn test_i8_params() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_name_params() {
|
fn test_name_params() {
|
||||||
test_type("NAME", &[(Some("hello world".to_string()), "'hello world'"),
|
test_type("NAME", &[(Some("hello world".to_owned()), "'hello world'"),
|
||||||
(Some("イロハニホヘト チリヌルヲ".to_string()), "'イロハニホヘト チリヌルヲ'"),
|
(Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
|
||||||
(None, "NULL")]);
|
(None, "NULL")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,15 +99,15 @@ fn test_f64_params() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_varchar_params() {
|
fn test_varchar_params() {
|
||||||
test_type("VARCHAR", &[(Some("hello world".to_string()), "'hello world'"),
|
test_type("VARCHAR", &[(Some("hello world".to_owned()), "'hello world'"),
|
||||||
(Some("イロハニホヘト チリヌルヲ".to_string()), "'イロハニホヘト チリヌルヲ'"),
|
(Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
|
||||||
(None, "NULL")]);
|
(None, "NULL")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_text_params() {
|
fn test_text_params() {
|
||||||
test_type("TEXT", &[(Some("hello world".to_string()), "'hello world'"),
|
test_type("TEXT", &[(Some("hello world".to_owned()), "'hello world'"),
|
||||||
(Some("イロハニホヘト チリヌルヲ".to_string()), "'イロハニホヘト チリヌルヲ'"),
|
(Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
|
||||||
(None, "NULL")]);
|
(None, "NULL")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ fn test_bpchar_params() {
|
|||||||
let stmt = or_panic!(conn.prepare("SELECT b FROM foo ORDER BY id"));
|
let stmt = or_panic!(conn.prepare("SELECT b FROM foo ORDER BY id"));
|
||||||
let res = or_panic!(stmt.query(&[]));
|
let res = or_panic!(stmt.query(&[]));
|
||||||
|
|
||||||
assert_eq!(vec!(Some("12345".to_string()), Some("123 ".to_string()), None),
|
assert_eq!(vec!(Some("12345".to_owned()), Some("123 ".to_owned()), None),
|
||||||
res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
|
res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,10 +158,10 @@ fn test_hstore_params() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
test_type("hstore",
|
test_type("hstore",
|
||||||
&[(Some(make_map!("a".to_string() => Some("1".to_string()))), "'a=>1'"),
|
&[(Some(make_map!("a".to_owned() => Some("1".to_owned()))), "'a=>1'"),
|
||||||
(Some(make_map!("hello".to_string() => Some("world!".to_string()),
|
(Some(make_map!("hello".to_owned() => Some("world!".to_owned()),
|
||||||
"hola".to_string() => Some("mundo!".to_string()),
|
"hola".to_owned() => Some("mundo!".to_owned()),
|
||||||
"what".to_string() => None)),
|
"what".to_owned() => None)),
|
||||||
"'hello=>world!,hola=>mundo!,what=>NULL'"),
|
"'hello=>world!,hola=>mundo!,what=>NULL'"),
|
||||||
(None, "NULL")]);
|
(None, "NULL")]);
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ fn test_slice() {
|
|||||||
|
|
||||||
let stmt = conn.prepare("SELECT f FROM foo WHERE id = ANY($1)").unwrap();
|
let stmt = conn.prepare("SELECT f FROM foo WHERE id = ANY($1)").unwrap();
|
||||||
let result = stmt.query(&[&Slice(&[1i32, 3, 4])]).unwrap();
|
let result = stmt.query(&[&Slice(&[1i32, 3, 4])]).unwrap();
|
||||||
assert_eq!(vec!["a".to_string(), "c".to_string(), "d".to_string()],
|
assert_eq!(vec!["a".to_owned(), "c".to_owned(), "d".to_owned()],
|
||||||
result.iter().map(|r| r.get::<_, String>(0)).collect::<Vec<_>>());
|
result.iter().map(|r| r.get::<_, String>(0)).collect::<Vec<_>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
extern crate serde;
|
|
||||||
|
|
||||||
use self::serde::json::{self, Value};
|
|
||||||
use types::test_type;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_json_params() {
|
|
||||||
test_type("JSON", &[(Some(json::from_str::<Value>("[10, 11, 12]").unwrap()),
|
|
||||||
"'[10, 11, 12]'"),
|
|
||||||
(Some(json::from_str::<Value>("{\"f\": \"asd\"}").unwrap()),
|
|
||||||
"'{\"f\": \"asd\"}'"),
|
|
||||||
(None, "NULL")])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_jsonb_params() {
|
|
||||||
test_type("JSONB", &[(Some(json::from_str::<Value>("[10, 11, 12]").unwrap()),
|
|
||||||
"'[10, 11, 12]'"),
|
|
||||||
(Some(json::from_str::<Value>("{\"f\": \"asd\"}").unwrap()),
|
|
||||||
"'{\"f\": \"asd\"}'"),
|
|
||||||
(None, "NULL")])
|
|
||||||
}
|
|
22
tests/types/serde_json.rs
Normal file
22
tests/types/serde_json.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
use self::serde_json::Value;
|
||||||
|
use types::test_type;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_json_params() {
|
||||||
|
test_type("JSON", &[(Some(serde_json::from_str::<Value>("[10, 11, 12]").unwrap()),
|
||||||
|
"'[10, 11, 12]'"),
|
||||||
|
(Some(serde_json::from_str::<Value>("{\"f\": \"asd\"}").unwrap()),
|
||||||
|
"'{\"f\": \"asd\"}'"),
|
||||||
|
(None, "NULL")])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_jsonb_params() {
|
||||||
|
test_type("JSONB", &[(Some(serde_json::from_str::<Value>("[10, 11, 12]").unwrap()),
|
||||||
|
"'[10, 11, 12]'"),
|
||||||
|
(Some(serde_json::from_str::<Value>("{\"f\": \"asd\"}").unwrap()),
|
||||||
|
"'{\"f\": \"asd\"}'"),
|
||||||
|
(None, "NULL")])
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user