Skip to content

Commit 60e16d3

Browse files
committed
Add a batch_execute method
1 parent 4a1bb4d commit 60e16d3

3 files changed

Lines changed: 88 additions & 0 deletions

File tree

src/lib.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,51 @@ impl PostgresConnection {
868868
self.prepare(query).and_then(|stmt| stmt.execute(params))
869869
}
870870

871+
/// Execute a sequence of SQL statements.
872+
///
873+
/// Statements should be separated by `;` characters. If an error occurs,
874+
/// execution of the sequence will stop at that point. This is intended for
875+
/// execution of batches of non-dynamic statements - for example, creation
876+
/// of a schema for a fresh database.
877+
///
878+
/// # Warning
879+
///
880+
/// Prepared statements should be used for any SQL statement which contains
881+
/// user-specified data, as it provides functionality to safely embed that
882+
/// data in the statment. Do not form statements via string concatenation
883+
/// and feed them into this method.
884+
///
885+
/// # Example
886+
///
887+
/// ```rust
888+
/// # use postgres::{PostgresConnection, PostgresResult};
889+
///
890+
/// fn init_db(conn: &PostgresConnection) -> PostgresResult<()> {
891+
/// static INIT_DB: &'static str = "
892+
/// CREATE TABLE person (
893+
/// id SERIAL PRIMARY KEY,
894+
/// name NOT NULL
895+
/// );
896+
///
897+
/// CREATE TABLE purchase (
898+
/// id SERIAL PRIMARY KEY,
899+
/// person INT NOT NULL REFERENCES person (id),
900+
/// time TIMESTAMPTZ NOT NULL,
901+
/// );
902+
///
903+
/// CREATE INDEX ON purchase (time);
904+
/// ";
905+
/// conn.batch_execute(INIT_DB)
906+
/// }
907+
/// ```
908+
pub fn batch_execute(&self, query: &str) -> PostgresResult<()> {
909+
let mut conn = self.conn.borrow_mut();
910+
if conn.trans_depth != 0 {
911+
return Err(PgWrongTransaction);
912+
}
913+
conn.quick_query(query).map(|_| ())
914+
}
915+
871916
/// Returns information used to cancel pending queries.
872917
///
873918
/// Used with the `cancel_query` function. The object returned can be used
@@ -976,6 +1021,14 @@ impl<'conn> PostgresTransaction<'conn> {
9761021
self.prepare(query).and_then(|s| s.execute(params))
9771022
}
9781023

1024+
/// Like `PostgresConnection::batch_execute`.
1025+
pub fn batch_execute(&self, query: &str) -> PostgresResult<()> {
1026+
if self.conn.conn.borrow().trans_depth != self.depth {
1027+
return Err(PgWrongTransaction);
1028+
}
1029+
self.conn.batch_execute(query)
1030+
}
1031+
9791032
/// Like `PostgresConnection::transaction`.
9801033
pub fn transaction<'a>(&'a self)
9811034
-> PostgresResult<PostgresTransaction<'a>> {

src/pool.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ impl PooledPostgresConnection {
124124
self.conn.get_ref().execute(query, params)
125125
}
126126

127+
/// Like `PostgresConnection::batch_execute`.
128+
pub fn batch_execute(&self, query: &str) -> PostgresResult<()> {
129+
self.conn.get_ref().batch_execute(query)
130+
}
131+
127132
/// Like `PostgresConnection::transaction`.
128133
pub fn transaction<'a>(&'a self)
129134
-> PostgresResult<PostgresTransaction<'a>> {

src/test.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use error::{PgConnectDbError,
3131
SyntaxError,
3232
InvalidPassword,
3333
QueryCanceled,
34+
UndefinedTable,
3435
InvalidCatalogName,
3536
PgWrongTransaction};
3637
use types::{ToSql, FromSql, PgInt4, PgVarchar};
@@ -339,6 +340,35 @@ fn test_stmt_finish() {
339340
assert!(stmt.finish().is_ok());
340341
}
341342

343+
#[test]
344+
fn test_batch_execute() {
345+
let conn = or_fail!(PostgresConnection::connect("postgres://postgres@localhost", &NoSsl));
346+
let query = "CREATE TEMPORARY TABLE foo (id BIGINT PRIMARY KEY);
347+
INSERT INTO foo (id) VALUES (10);";
348+
or_fail!(conn.batch_execute(query));
349+
350+
let stmt = or_fail!(conn.prepare("SELECT * from foo ORDER BY id"));
351+
let result = or_fail!(stmt.query([]));
352+
353+
assert_eq!(vec![10i64], result.map(|row| row[1]).collect());
354+
}
355+
356+
#[test]
357+
fn test_batch_execute_error() {
358+
let conn = or_fail!(PostgresConnection::connect("postgres://postgres@localhost", &NoSsl));
359+
let query = "CREATE TEMPORARY TABLE foo (id BIGINT PRIMARY KEY);
360+
INSERT INTO foo (id) VALUES (10);
361+
asdfa;
362+
INSERT INTO foo (id) VALUES (11)";
363+
conn.batch_execute(query).unwrap_err();
364+
365+
match conn.prepare("SELECT * from foo ORDER BY id") {
366+
Err(PgDbError(PostgresDbError { code: UndefinedTable, .. })) => {},
367+
Err(e) => fail!("unexpected error {}", e),
368+
_ => fail!("unexpected success"),
369+
}
370+
}
371+
342372
#[test]
343373
fn test_query() {
344374
let conn = or_fail!(PostgresConnection::connect("postgres://postgres@localhost", &NoSsl));

0 commit comments

Comments
 (0)