diff --git a/src/api/duckdb.rs b/src/api/duckdb.rs index 6f220816..1ae90cae 100644 --- a/src/api/duckdb.rs +++ b/src/api/duckdb.rs @@ -11,6 +11,18 @@ type DuckdbSettingsRow = ( Option, ); +type DuckdbExtensionsRow = ( + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, +); + #[pg_extern] pub fn duckdb_execute(query: &str) { connection::execute(query, []).unwrap_or_else(|err| panic!("error executing query: {err:?}")); @@ -52,3 +64,61 @@ fn duckdb_settings_impl() -> Result> { .map(|row| row.unwrap()) .collect::>()) } + +#[allow(clippy::type_complexity)] +#[pg_extern] +pub fn duckdb_extensions() -> iter::TableIterator< + 'static, + ( + name!(extension_name, Option), + name!(loaded, Option), + name!(installed, Option), + name!(install_path, Option), + name!(description, Option), + name!(aliases, Option), + name!(extension_version, Option), + name!(install_mode, Option), + name!(installed_from, Option), + ), +> { + let rows = duckdb_extensions_impl().unwrap_or_else(|e| { + panic!("{}", e); + }); + iter::TableIterator::new(rows) +} + +#[inline] +fn duckdb_extensions_impl() -> Result> { + let conn = unsafe { &*connection::get_global_connection().get() }; + let mut stmt = conn.prepare( + "SELECT + extension_name, + loaded, + installed, + install_path, + description, + aliases::varchar, + extension_version, + install_mode, + installed_from + FROM + duckdb_extensions();", + )?; + + Ok(stmt + .query_map([], |row| { + Ok(( + row.get::<_, Option>(0)?, + row.get::<_, Option>(1)?, + row.get::<_, Option>(2)?, + row.get::<_, Option>(3)?, + row.get::<_, Option>(4)?, + row.get::<_, Option>(5)?, + row.get::<_, Option>(6)?, + row.get::<_, Option>(7)?, + row.get::<_, Option>(8)?, + )) + })? + .map(|row| row.unwrap()) + .collect::>()) +} diff --git a/tests/tests/settings.rs b/tests/tests/settings.rs index 6bb8c197..d87d121a 100644 --- a/tests/tests/settings.rs +++ b/tests/tests/settings.rs @@ -15,3 +15,13 @@ async fn test_duckdb_settings(mut conn: PgConnection) -> Result<()> { Ok(()) } + +#[rstest] +async fn test_duckdb_extensions(mut conn: PgConnection) -> Result<()> { + let azure_extension: (Option,) = + "SELECT extension_name FROM duckdb_extensions() WHERE extension_name = 'azure'" + .fetch_one(&mut conn); + assert!(azure_extension.0.is_some()); + + Ok(()) +}