Skip to content

Commit 8b84e0c

Browse files
authored
Merge pull request #133 from allenap/escape-identifier
Escape database name in `createdb` and `dropdb`
2 parents b35cfd5 + ff137cd commit 8b84e0c

File tree

2 files changed

+46
-7
lines changed

2 files changed

+46
-7
lines changed

Cargo.toml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
[package]
22
authors = ["Gavin Panella <gavinpanella@gmail.com>"]
3-
categories = ["command-line-utilities", "database", "development-tools", "development-tools::testing"]
3+
categories = [
4+
"command-line-utilities",
5+
"database",
6+
"development-tools",
7+
"development-tools::testing",
8+
]
49
description = "Easily create and manage PostgreSQL clusters on demand for testing and development."
510
edition = "2021"
611
keywords = ["database", "postgres", "postgresql"]
@@ -11,7 +16,7 @@ repository = "https://github.com/allenap/rust-postgresfixture"
1116
version = "0.3.2"
1217

1318
[badges]
14-
travis-ci = {repository = "allenap/rust-postgresfixture", branch = "master"}
19+
travis-ci = { repository = "allenap/rust-postgresfixture", branch = "master" }
1520

1621
[lib]
1722
name = "postgresfixture"
@@ -23,16 +28,17 @@ name = "postgresfixture"
2328
path = "src/main.rs"
2429

2530
[dependencies]
26-
clap = {version = "^3.1.0", features = ["derive", "env"]}
31+
clap = { version = "^3.1.0", features = ["derive", "env"] }
2732
color-eyre = "^0.6.1"
28-
ctrlc = {version = "^3.2.1", features = ["termination"]}
33+
ctrlc = { version = "^3.2.1", features = ["termination"] }
2934
either = "^1.6.1"
3035
nix = "^0.23.0"
3136
postgres = "^0.19.2"
37+
postgres-protocol = "^0.6.4"
3238
rand = "^0.8.5"
3339
regex = "^1.5.4"
3440
shell-quote = "^0.3.0"
35-
uuid = {version = "^0.8.2", features = ["v5"]}
41+
uuid = { version = "^0.8.2", features = ["v5"] }
3642

3743
[dev-dependencies]
3844
tempdir = "^0.3.7"

src/cluster.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,15 +345,21 @@ impl Cluster {
345345

346346
/// Create the named database.
347347
pub fn createdb(&self, database: &str) -> Result<bool, ClusterError> {
348-
let statement = format!("CREATE DATABASE {}", &database);
348+
let statement = format!(
349+
"CREATE DATABASE {}",
350+
postgres_protocol::escape::escape_identifier(database)
351+
);
349352
self.connect("template1")?
350353
.execute(statement.as_str(), &[])?;
351354
Ok(true)
352355
}
353356

354357
/// Drop the named database.
355358
pub fn dropdb(&self, database: &str) -> Result<bool, ClusterError> {
356-
let statement = format!("DROP DATABASE {}", &database);
359+
let statement = format!(
360+
"DROP DATABASE {}",
361+
postgres_protocol::escape::escape_identifier(database)
362+
);
357363
self.connect("template1")?
358364
.execute(statement.as_str(), &[])?;
359365
Ok(true)
@@ -594,4 +600,31 @@ mod tests {
594600
cluster.destroy().unwrap();
595601
}
596602
}
603+
604+
#[test]
605+
fn cluster_databases_with_non_plain_names_can_be_created_and_dropped() {
606+
// PostgreSQL identifiers containing hyphens, for example, or where we
607+
// want to preserve capitalisation, are possible.
608+
for runtime in Runtime::find_on_path() {
609+
println!("{:?}", runtime);
610+
let data_dir = tempdir::TempDir::new("data").unwrap();
611+
let cluster = Cluster::new(&data_dir, runtime);
612+
cluster.start().unwrap();
613+
cluster.createdb("foo-bar").unwrap();
614+
cluster.createdb("Foo-BAR").unwrap();
615+
616+
let expected: HashSet<String> =
617+
["foo-bar", "Foo-BAR", "postgres", "template0", "template1"]
618+
.iter()
619+
.cloned()
620+
.map(|s| s.to_string())
621+
.collect();
622+
let observed: HashSet<String> = cluster.databases().unwrap().iter().cloned().collect();
623+
assert_eq!(expected, observed);
624+
625+
cluster.dropdb("foo-bar").unwrap();
626+
cluster.dropdb("Foo-BAR").unwrap();
627+
cluster.destroy().unwrap();
628+
}
629+
}
597630
}

0 commit comments

Comments
 (0)