Skip to content

Commit b5d9a38

Browse files
committed
Remove CopyInStatement
The API's awful to use.
1 parent e094ce6 commit b5d9a38

File tree

3 files changed

+3
-270
lines changed

3 files changed

+3
-270
lines changed

src/lib.rs

Lines changed: 2 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -778,35 +778,6 @@ impl InnerConnection {
778778
})
779779
}
780780

781-
fn prepare_copy_in<'a>(&mut self, table: &str, rows: &[&str], conn: &'a Connection)
782-
-> Result<CopyInStatement<'a>> {
783-
let mut query = vec![];
784-
let _ = write!(&mut query, "SELECT ");
785-
let _ = util::comma_join_quoted_idents(&mut query, rows.iter().cloned());
786-
let _ = write!(&mut query, " FROM ");
787-
let _ = util::write_quoted_ident(&mut query, table);
788-
let query = String::from_utf8(query).unwrap();
789-
let (_, columns) = try!(self.raw_prepare("", &query));
790-
let column_types = columns.into_iter().map(|desc| desc.type_).collect();
791-
792-
let mut query = vec![];
793-
let _ = write!(&mut query, "COPY ");
794-
let _ = util::write_quoted_ident(&mut query, table);
795-
let _ = write!(&mut query, " (");
796-
let _ = util::comma_join_quoted_idents(&mut query, rows.iter().cloned());
797-
let _ = write!(&mut query, ") FROM STDIN WITH (FORMAT binary)");
798-
let query = String::from_utf8(query).unwrap();
799-
let stmt_name = self.make_stmt_name();
800-
try!(self.raw_prepare(&stmt_name, &query));
801-
802-
Ok(CopyInStatement {
803-
conn: conn,
804-
name: stmt_name,
805-
column_types: column_types,
806-
finished: false,
807-
})
808-
}
809-
810781
fn close_statement(&mut self, name: &str, type_: u8) -> Result<()> {
811782
try!(self.write_messages(&[
812783
Close {
@@ -1094,15 +1065,6 @@ impl Connection {
10941065
self.conn.borrow_mut().prepare_cached(query, self)
10951066
}
10961067

1097-
/// Creates a new COPY FROM STDIN prepared statement.
1098-
///
1099-
/// These statements provide a method to efficiently bulk-upload data to
1100-
/// the database.
1101-
pub fn prepare_copy_in<'a>(&'a self, table: &str, rows: &[&str])
1102-
-> Result<CopyInStatement<'a>> {
1103-
self.conn.borrow_mut().prepare_copy_in(table, rows, self)
1104-
}
1105-
11061068
/// Begins a new transaction.
11071069
///
11081070
/// Returns a `Transaction` object which should be used instead of
@@ -1322,11 +1284,6 @@ impl<'conn> Transaction<'conn> {
13221284
self.conn.prepare_cached(query)
13231285
}
13241286

1325-
/// Like `Connection::prepare_copy_in`.
1326-
pub fn prepare_copy_in(&self, table: &str, cols: &[&str]) -> Result<CopyInStatement<'conn>> {
1327-
self.conn.prepare_copy_in(table, cols)
1328-
}
1329-
13301287
/// Like `Connection::execute`.
13311288
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64> {
13321289
self.conn.execute(query, params)
@@ -2030,90 +1987,7 @@ impl<'trans, 'stmt> Iterator for LazyRows<'trans, 'stmt> {
20301987
}
20311988
}
20321989

2033-
/// A prepared `COPY FROM STDIN` statement.
2034-
pub struct CopyInStatement<'a> {
2035-
conn: &'a Connection,
2036-
name: String,
2037-
column_types: Vec<Type>,
2038-
finished: bool,
2039-
}
2040-
2041-
impl<'a> fmt::Debug for CopyInStatement<'a> {
2042-
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2043-
DebugStruct::new(fmt, "CopyInStatement")
2044-
.field("name", &self.name)
2045-
.field("column_types", &self.column_types)
2046-
.finish()
2047-
}
2048-
}
2049-
2050-
impl<'a> Drop for CopyInStatement<'a> {
2051-
fn drop(&mut self) {
2052-
if !self.finished {
2053-
let _ = self.finish_inner();
2054-
}
2055-
}
2056-
}
2057-
2058-
/// An `Iterator` variant which returns borrowed values.
2059-
pub trait StreamIterator {
2060-
/// Returns the next value, or `None` if there is none.
2061-
fn next<'a>(&'a mut self) -> Option<&'a (ToSql + 'a)>;
2062-
}
2063-
2064-
/// An adapter type implementing `StreamIterator` for a `Vec<Box<ToSql>>`.
2065-
pub struct VecStreamIterator<'a> {
2066-
v: Vec<Box<ToSql + 'a>>,
2067-
idx: usize,
2068-
}
2069-
2070-
impl<'a> VecStreamIterator<'a> {
2071-
/// Creates a new `VecStreamIterator`.
2072-
pub fn new(v: Vec<Box<ToSql + 'a>>) -> VecStreamIterator<'a> {
2073-
VecStreamIterator {
2074-
v: v,
2075-
idx: 0,
2076-
}
2077-
}
2078-
2079-
/// Returns the underlying `Vec`.
2080-
pub fn into_inner(self) -> Vec<Box<ToSql + 'a>> {
2081-
self.v
2082-
}
2083-
}
2084-
2085-
impl<'a> StreamIterator for VecStreamIterator<'a> {
2086-
fn next<'b>(&'b mut self) -> Option<&'b (ToSql + 'b)> {
2087-
match self.v.get_mut(self.idx) {
2088-
Some(mut e) => {
2089-
self.idx += 1;
2090-
Some(&mut **e)
2091-
},
2092-
None => None,
2093-
}
2094-
}
2095-
}
2096-
2097-
impl<'a> CopyInStatement<'a> {
2098-
fn finish_inner(&mut self) -> Result<()> {
2099-
let mut conn = self.conn.conn.borrow_mut();
2100-
check_desync!(conn);
2101-
conn.close_statement(&self.name, b'S')
2102-
}
2103-
2104-
/// Returns a slice containing the expected column types.
2105-
pub fn column_types(&self) -> &[Type] {
2106-
&self.column_types
2107-
}
2108-
2109-
/// Executes the prepared statement.
2110-
///
2111-
/// The `rows` argument is an `Iterator` returning `StreamIterator` values,
2112-
/// each one of which provides values for a row of input. This setup is
2113-
/// designed to allow callers to avoid having to maintain the entire row
2114-
/// set in memory.
2115-
///
2116-
/// Returns the number of rows copied.
1990+
/*
21171991
pub fn execute<I, J>(&self, rows: I) -> Result<u64>
21181992
where I: Iterator<Item=J>, J: StreamIterator {
21191993
let mut conn = self.conn.conn.borrow_mut();
@@ -2225,17 +2099,7 @@ impl<'a> CopyInStatement<'a> {
22252099
try!(conn.wait_for_ready());
22262100
Ok(num)
22272101
}
2228-
2229-
/// Consumes the statement, clearing it from the Postgres session.
2230-
///
2231-
/// Functionally identical to the `Drop` implementation of the
2232-
/// `CopyInStatement` except that it returns any error to the
2233-
/// caller.
2234-
pub fn finish(mut self) -> Result<()> {
2235-
self.finished = true;
2236-
self.finish_inner()
2237-
}
2238-
}
2102+
*/
22392103

22402104
/// A trait allowing abstraction over connections and transactions
22412105
pub trait GenericConnection {
@@ -2248,10 +2112,6 @@ pub trait GenericConnection {
22482112
/// Like `Connection::execute`.
22492113
fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64>;
22502114

2251-
/// Like `Connection::prepare_copy_in`.
2252-
fn prepare_copy_in<'a>(&'a self, table: &str, columns: &[&str])
2253-
-> Result<CopyInStatement<'a>>;
2254-
22552115
/// Like `Connection::transaction`.
22562116
fn transaction<'a>(&'a self) -> Result<Transaction<'a>>;
22572117

@@ -2279,11 +2139,6 @@ impl GenericConnection for Connection {
22792139
self.transaction()
22802140
}
22812141

2282-
fn prepare_copy_in<'a>(&'a self, table: &str, columns: &[&str])
2283-
-> Result<CopyInStatement<'a>> {
2284-
self.prepare_copy_in(table, columns)
2285-
}
2286-
22872142
fn batch_execute(&self, query: &str) -> Result<()> {
22882143
self.batch_execute(query)
22892144
}
@@ -2310,11 +2165,6 @@ impl<'a> GenericConnection for Transaction<'a> {
23102165
self.transaction()
23112166
}
23122167

2313-
fn prepare_copy_in<'b>(&'b self, table: &str, columns: &[&str])
2314-
-> Result<CopyInStatement<'b>> {
2315-
self.prepare_copy_in(table, columns)
2316-
}
2317-
23182168
fn batch_execute(&self, query: &str) -> Result<()> {
23192169
self.batch_execute(query)
23202170
}

src/util.rs

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,5 @@
11
use std::io;
22
use std::io::prelude::*;
3-
use std::ascii::AsciiExt;
4-
5-
pub fn comma_join_quoted_idents<'a, W, I>(writer: &mut W, strs: I) -> io::Result<()>
6-
where W: Write, I: Iterator<Item=&'a str> {
7-
let mut first = true;
8-
for str_ in strs {
9-
if !first {
10-
try!(write!(writer, ", "));
11-
}
12-
first = false;
13-
try!(write_quoted_ident(writer, str_));
14-
}
15-
Ok(())
16-
}
17-
18-
// See http://www.postgresql.org/docs/9.4/static/sql-syntax-lexical.html for ident grammar
19-
pub fn write_quoted_ident<W: Write>(w: &mut W, ident: &str) -> io::Result<()> {
20-
try!(write!(w, "U&\""));
21-
for ch in ident.chars() {
22-
match ch {
23-
'"' => try!(write!(w, "\"\"")),
24-
'\\' => try!(write!(w, "\\\\")),
25-
ch if ch.is_ascii() => try!(write!(w, "{}", ch)),
26-
ch => try!(write!(w, "\\+{:06X}", ch as u32)),
27-
}
28-
}
29-
write!(w, "\"")
30-
}
313

324
pub fn parse_update_count(tag: String) -> u64 {
335
tag.split(' ').last().unwrap().parse().unwrap_or(0)

tests/test.rs

Lines changed: 1 addition & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ use postgres::{HandleNotice,
1919
ConnectError,
2020
DbError,
2121
IntoConnectParams,
22-
IsolationLevel,
23-
VecStreamIterator};
22+
IsolationLevel};
2423
use postgres::SqlState::{SyntaxError,
2524
QueryCanceled,
2625
UndefinedTable,
@@ -755,94 +754,6 @@ fn test_execute_copy_from_err() {
755754
}
756755
}
757756

758-
#[test]
759-
fn test_copy_in() {
760-
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
761-
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT, name VARCHAR)", &[]));
762-
763-
let stmt = or_panic!(conn.prepare_copy_in("foo", &["id", "name"]));
764-
765-
let data = (0i32..2).map(|i| {
766-
VecStreamIterator::new(vec![Box::new(i),
767-
Box::new(format!("{}", i))])
768-
});
769-
770-
assert_eq!(2, stmt.execute(data).unwrap());
771-
772-
let stmt = or_panic!(conn.prepare("SELECT id, name FROM foo ORDER BY id"));
773-
assert_eq!(vec![(0i32, Some("0".to_string())), (1, Some("1".to_string()))],
774-
or_panic!(stmt.query(&[])).iter().map(|r| (r.get(0), r.get(1))).collect::<Vec<_>>());
775-
}
776-
777-
#[test]
778-
fn test_copy_in_bad_column_count() {
779-
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
780-
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT, name VARCHAR)", &[]));
781-
782-
let stmt = or_panic!(conn.prepare_copy_in("foo", &["id", "name"]));
783-
let data = vec![
784-
VecStreamIterator::new(vec![Box::new(1i32),
785-
Box::new("Steven".to_string())]),
786-
VecStreamIterator::new(vec![Box::new(2i32)]),
787-
].into_iter();
788-
789-
let res = stmt.execute(data);
790-
match res {
791-
Err(Error::DbError(ref err)) if err.message().contains("Invalid column count") => {}
792-
Err(err) => panic!("unexpected error {:?}", err),
793-
_ => panic!("Expected error"),
794-
}
795-
796-
let data = vec![
797-
VecStreamIterator::new(vec![Box::new(1i32),
798-
Box::new("Steven".to_string())]),
799-
VecStreamIterator::new(vec![Box::new(2i32),
800-
Box::new("Steven".to_string()),
801-
Box::new(3i64)]),
802-
].into_iter();
803-
804-
let res = stmt.execute(data);
805-
match res {
806-
Err(Error::DbError(ref err)) if err.message().contains("Invalid column count") => {}
807-
Err(err) => panic!("unexpected error {:?}", err),
808-
_ => panic!("Expected error"),
809-
}
810-
811-
or_panic!(conn.execute("SELECT 1", &[]));
812-
}
813-
814-
#[test]
815-
fn test_copy_in_bad_type() {
816-
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
817-
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT, name VARCHAR)", &[]));
818-
819-
let stmt = or_panic!(conn.prepare_copy_in("foo", &["id", "name"]));
820-
821-
let data = vec![
822-
VecStreamIterator::new(vec![Box::new(1i32),
823-
Box::new("Steven".to_string())]),
824-
VecStreamIterator::new(vec![Box::new(2i32),
825-
Box::new(1i32)]),
826-
].into_iter();
827-
828-
let res = stmt.execute(data);
829-
match res {
830-
Err(Error::DbError(ref err)) if err.message().contains("saw type Varchar") => {}
831-
Err(err) => panic!("unexpected error {:?}", err),
832-
_ => panic!("Expected error"),
833-
}
834-
835-
or_panic!(conn.execute("SELECT 1", &[]));
836-
}
837-
838-
#[test]
839-
fn test_copy_in_weird_names() {
840-
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
841-
or_panic!(conn.execute(r#"CREATE TEMPORARY TABLE "na""me" (U&" \\\+01F4A9" VARCHAR)"#, &[]));
842-
let stmt = or_panic!(conn.prepare_copy_in("na\"me", &[" \\💩"]));
843-
assert_eq!(&Type::Varchar, &stmt.column_types()[0]);
844-
}
845-
846757
#[test]
847758
fn test_batch_execute_copy_from_err() {
848759
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));

0 commit comments

Comments
 (0)