Skip to content

Commit bc47b06

Browse files
committed
connection: add allow_attach to config
Default is false, which means connections are blocked from attaching databases. If allowed, colocated databases can be attached in readonly mode. Example: → attach another as another; select * from another.sqlite_master; TYPE NAME TBL NAME ROOTPAGE SQL table t3 t3 2 CREATE TABLE t3(id)
1 parent 8dbc294 commit bc47b06

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

libsql-server/src/connection/config.rs

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ pub struct DatabaseConfig {
1818
pub heartbeat_url: Option<Url>,
1919
#[serde(default)]
2020
pub bottomless_db_id: Option<String>,
21+
#[serde(default)]
22+
pub allow_attach: bool,
2123
}
2224

2325
const fn default_max_size() -> u64 {
@@ -33,6 +35,7 @@ impl Default for DatabaseConfig {
3335
max_db_pages: default_max_size(),
3436
heartbeat_url: None,
3537
bottomless_db_id: None,
38+
allow_attach: Default::default(),
3639
}
3740
}
3841
}

libsql-server/src/connection/libsql.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ impl<W: Wal> Connection<W> {
693693
StmtKind::Read | StmtKind::TxnBegin | StmtKind::Other => config.block_reads,
694694
StmtKind::Write => config.block_reads || config.block_writes,
695695
StmtKind::TxnEnd | StmtKind::Release | StmtKind::Savepoint => false,
696-
StmtKind::Attach | StmtKind::Detach => false,
696+
StmtKind::Attach | StmtKind::Detach => !config.allow_attach,
697697
};
698698
if blocked {
699699
return Err(Error::Blocked(config.block_reason.clone()));

libsql-server/src/http/admin/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ async fn handle_get_config<M: MakeNamespace, C: Connector>(
177177
block_reason: config.block_reason.clone(),
178178
max_db_size: Some(max_db_size),
179179
heartbeat_url: config.heartbeat_url.clone().map(|u| u.into()),
180+
allow_attach: config.allow_attach,
180181
};
181182

182183
Ok(Json(resp))
@@ -219,6 +220,8 @@ struct HttpDatabaseConfig {
219220
max_db_size: Option<bytesize::ByteSize>,
220221
#[serde(default)]
221222
heartbeat_url: Option<String>,
223+
#[serde(default)]
224+
allow_attach: bool,
222225
}
223226

224227
async fn handle_post_config<M: MakeNamespace, C>(
@@ -234,6 +237,7 @@ async fn handle_post_config<M: MakeNamespace, C>(
234237
config.block_reads = req.block_reads;
235238
config.block_writes = req.block_writes;
236239
config.block_reason = req.block_reason;
240+
config.allow_attach = req.allow_attach;
237241
if let Some(size) = req.max_db_size {
238242
config.max_db_pages = size.as_u64() / LIBSQL_PAGE_SIZE;
239243
}

libsql-server/tests/namespaces/meta.rs

+39
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,45 @@ fn meta_store() {
8181
foo_conn.execute("select 1", ()).await.unwrap();
8282
}
8383

84+
// STEP 4: try attaching a database
85+
{
86+
let foo = Database::open_remote_with_connector(
87+
"http://foo.primary:8080",
88+
"",
89+
TurmoilConnector,
90+
)?;
91+
let foo_conn = foo.connect()?;
92+
93+
foo_conn.execute("attach foo as foo", ()).await.unwrap_err();
94+
}
95+
96+
// STEP 5: update config to allow attaching databases
97+
client
98+
.post(
99+
"http://primary:9090/v1/namespaces/foo/config",
100+
json!({
101+
"block_reads": false,
102+
"block_writes": false,
103+
"allow_attach": true,
104+
}),
105+
)
106+
.await?;
107+
108+
{
109+
let foo = Database::open_remote_with_connector(
110+
"http://foo.primary:8080",
111+
"",
112+
TurmoilConnector,
113+
)?;
114+
let foo_conn = foo.connect()?;
115+
116+
foo_conn.execute("attach foo as foo", ()).await.unwrap();
117+
foo_conn
118+
.execute("select * from foo.sqlite_master", ())
119+
.await
120+
.unwrap();
121+
}
122+
84123
Ok(())
85124
});
86125

0 commit comments

Comments
 (0)