Skip to content

Commit a1eaceb

Browse files
committed
Transactions aren't executed with "psql -c"
The transaction did not appear to execute when running a set of SQL commands using psql commands with the '-c' option, such as "SELECT * FROM t; BEGIN; UPDATE t SET k = id; END;". This issue was caused by the tokio-postgres crate adding column information to all EmptyQueryResponses for every SQL query. The resolution for this issue was to only add the column information to 'SELECT' queries.
1 parent 13206f6 commit a1eaceb

File tree

3 files changed

+87
-2
lines changed

3 files changed

+87
-2
lines changed

tokio-postgres/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ pub use crate::error::Error;
132132
pub use crate::generic_client::GenericClient;
133133
pub use crate::generic_result::GenericResult;
134134
pub use crate::portal::Portal;
135-
pub use crate::query::{RowStream, ResultStream};
135+
pub use crate::query::{ResultStream, RowStream};
136136
pub use crate::row::{Row, SimpleQueryRow};
137137
pub use crate::simple_query::SimpleQueryStream;
138138
#[cfg(feature = "runtime")]

tokio-postgres/src/simple_query.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,11 @@ impl Stream for SimpleQueryStream {
9898
.parse()
9999
.unwrap_or(0);
100100
let fields = if *this.include_fields_in_complete {
101-
this.fields.clone()
101+
if body.tag().expect("Failed to get tag").starts_with("SELECT") {
102+
this.fields.clone()
103+
} else {
104+
None
105+
}
102106
} else {
103107
// Reset bool for next grouping
104108
*this.include_fields_in_complete = true;

tokio-postgres/tests/test/main.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,88 @@ async fn custom_range() {
347347
assert_eq!("floatrange", ty.name());
348348
assert_eq!(&Kind::Range(Type::FLOAT8), ty.kind());
349349
}
350+
/// This test check to make sure that empty responses for select queries include the header but not
351+
/// for other query types.
352+
#[tokio::test]
353+
async fn simple_query_select_transaction() {
354+
let client = connect("user=postgres").await;
355+
356+
let _ = client.simple_query("DROP TABLE sbtest1").await.unwrap();
357+
let _ = client.simple_query("DROP TABLE sbtest2").await.unwrap();
358+
let _ = client
359+
.simple_query("CREATE TABLE sbtest1 (id INTEGER, k INTEGER);")
360+
.await
361+
.unwrap();
362+
let _ = client
363+
.simple_query("CREATE TABLE sbtest2 (id INTEGER, k INTEGER);")
364+
.await
365+
.unwrap();
366+
367+
let messages = client
368+
.simple_query(
369+
"INSERT INTO sbtest1 VALUES (1, 2);
370+
INSERT INTO sbtest2 VALUES (1, 2);
371+
SELECT * FROM sbtest1 ORDER BY id;
372+
SELECT k FROM sbtest1 WHERE id = 999;
373+
BEGIN;
374+
UPDATE sbtest1 SET k=id;
375+
UPDATE sbtest2 SET k=id;
376+
END;",
377+
)
378+
.await
379+
.unwrap();
380+
381+
match messages[0] {
382+
SimpleQueryMessage::CommandComplete(CommandCompleteContents { rows: 1, .. }) => {}
383+
_ => panic!("unexpected message or too many rows"),
384+
}
385+
match messages[1] {
386+
SimpleQueryMessage::CommandComplete(CommandCompleteContents { rows: 1, .. }) => {}
387+
_ => panic!("unexpected message or too many rows"),
388+
}
389+
match &messages[2] {
390+
SimpleQueryMessage::Row(row) => {
391+
assert_eq!(row.columns().get(0).map(|c| c.name()), Some("id"));
392+
assert_eq!(row.columns().get(1).map(|c| c.name()), Some("k"));
393+
assert_eq!(row.get(0), Some("1"));
394+
assert_eq!(row.get(1), Some("2"));
395+
}
396+
_ => panic!("unexpected message"),
397+
}
398+
match &messages[3] {
399+
SimpleQueryMessage::CommandComplete(CommandCompleteContents { fields: None, .. }) => {}
400+
_ => panic!("unexpected message or fields are not empty "),
401+
}
402+
match &messages[4] {
403+
SimpleQueryMessage::CommandComplete(CommandCompleteContents { fields, .. }) => {
404+
if let Some(field_vec) = &fields {
405+
assert_eq!((&**field_vec).len(), 1);
406+
assert_eq!("k", (&**field_vec)[0].name());
407+
} else {
408+
panic!("No data found");
409+
}
410+
}
411+
_ => panic!("unexpected message"),
412+
}
413+
match &messages[5] {
414+
SimpleQueryMessage::CommandComplete(CommandCompleteContents { fields: None, .. }) => {}
415+
_ => panic!("unexpected message or fields are not empty"),
416+
}
417+
match &messages[6] {
418+
SimpleQueryMessage::CommandComplete(CommandCompleteContents { fields: None, .. }) => {}
419+
_ => panic!("unexpected message or fields are not empty"),
420+
}
421+
match &messages[7] {
422+
SimpleQueryMessage::CommandComplete(CommandCompleteContents { fields: None, .. }) => {}
423+
_ => panic!("unexpected message or fields are not empty"),
424+
}
425+
match &messages[8] {
426+
SimpleQueryMessage::CommandComplete(CommandCompleteContents { fields: None, .. }) => {}
427+
_ => panic!("unexpected message or fields are not empty"),
428+
}
350429

430+
assert_eq!(messages.len(), 9);
431+
}
351432
#[tokio::test]
352433
async fn simple_query() {
353434
let client = connect("user=postgres").await;

0 commit comments

Comments
 (0)