Skip to content

Commit 4c2a655

Browse files
authored
Allow relocatable extensions (#1653)
Previously, relocatable extensions were disallowed by a check in the code for the install command. This pull request removes the check, and, more importantly, changes the behavior in `PgrxSql::schema_alias_of()` so that it simply never schema-qualifies based on the control file. This prevents relocatable extensions from trying to schema-qualify with `@extname@`, which did not get substituted out by Postgres. This resolves #1626
1 parent 0c823db commit 4c2a655

File tree

8 files changed

+24
-38
lines changed

8 files changed

+24
-38
lines changed

cargo-pgrx/src/command/install.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,6 @@ pub(crate) fn install_extension(
136136
let manifest = Manifest::from_path(&package_manifest_path)?;
137137
let (control_file, extname) = find_control_file(&package_manifest_path)?;
138138

139-
if get_property(&package_manifest_path, "relocatable")? != Some("false".into()) {
140-
return Err(eyre!(
141-
"{}: The `relocatable` property MUST be `false`. Please update your .control file.",
142-
control_file.display()
143-
));
144-
}
145-
146139
let versioned_so = get_property(&package_manifest_path, "module_pathname")?.is_none();
147140

148141
let build_command_output =

cargo-pgrx/src/command/schema.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::manifest::{get_package_manifest, pg_config_and_version};
1212
use crate::profile::CargoProfile;
1313
use crate::CommandExecute;
1414
use cargo_toml::Manifest;
15-
use eyre::{eyre, WrapErr};
15+
use eyre::WrapErr;
1616
use owo_colors::OwoColorize;
1717
use pgrx_pg_config::cargo::PgrxManifestExt;
1818
use pgrx_pg_config::{get_target_dir, PgConfig, Pgrx};
@@ -134,13 +134,6 @@ pub(crate) fn generate_schema(
134134
let manifest = Manifest::from_path(&package_manifest_path)?;
135135
let (control_file, _extname) = find_control_file(&package_manifest_path)?;
136136

137-
if get_property(&package_manifest_path, "relocatable")? != Some("false".into()) {
138-
return Err(eyre!(
139-
"{}: The `relocatable` property MUST be `false`. Please update your .control file.",
140-
control_file.display()
141-
));
142-
}
143-
144137
let flags = std::env::var("PGRX_BUILD_FLAGS").unwrap_or_default();
145138

146139
let features_arg = features.features.join(" ");

docs/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- [Testing Extensions with PGRX](./extension/test.md)
1010
- [Memory Checking](./extension/test/memory-checking.md)
1111
- [Installing a PGRX Extension](./extension/install.md)
12+
- [Schema Configuration](./extension/schema.md)
1213
- [Basics of Postgres Internals](./pg-internal.md)
1314
- [Pass-By-Datum](./pg-internal/datum.md)
1415
- [Memory Contexts](./pg-internal/memory-context.md)

docs/src/extension.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
- [Testing Extensions with PGRX](./extension/test.md)
88
- [Memory Checking](./extension/test/memory-checking.md)
99
- [Installing a PGRX Extension](./extension/install.md)
10+
- [Schema configuration](./extension/schema.md)

docs/src/extension/schema.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Schema Configuration
2+
3+
{{#include ./../../../pgrx-examples/schemas/README.md}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
comment = 'arrays: Created by pgrx'
22
default_version = '0.1.0'
33
module_pathname = '$libdir/datetime'
4-
relocatable = false
4+
relocatable = true
55
superuser = false

pgrx-examples/schemas/README.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,23 @@ If unspecified, that schema is whatever the first schema in the user's `search_p
55
it is the schema argument to `CREATE EXTENSION`.
66

77
In general, any `pgrx` object (a function, operator, type, etc), regardless of the Rust source
8-
file it is defined in, is created in that schema unless that object appears in a
8+
file it is defined in, is created in that schema unless that object appears in a
99
`#[pg_schema] mod modname { ... }` block. In this case, `pgrx` generates a top-level schema named the
10-
same as the module, and creates the contained objects within that schema.
10+
same as the module, and creates the contained objects within that schema.
1111

1212
Unlike Rust, which supports nested modules, Postgres only supports one-level of schemas,
1313
although a Postgres session can have many schemas in its `search_path`. As such, any
1414
`#[pg_schema] mod modname { ... }` block containing `pgrx` objects is hoisted to a top-level schema.
1515

1616
### `#[pg_extern]/#[pg_operator]` Functions and their Postgres `search_path`
1717

18-
When `pgrx` generates the DDL for a function (`CREATE FUNCTION ...`), it uses uses the schema
19-
it understands the function to belong in two different ways.
20-
21-
First off, if there's a `schema = foo` attribute in your extension `.control` file, the
22-
function is created in that schema. If there is no `schema = foo` attribute, then the
23-
function is *not* schema-qualified, which indicates it'll be created in the schema
24-
determined by the `CREATE EXTENSION` function.
25-
26-
Secondly, `pgrx` can apply `search_path` to that function that limits that function's
27-
search_path to whatever you specify. This is done via the `#[search_path(...)]` attribute macro
28-
applied to the function with `#[pg_extern]` or `#[pg_operator]` or `#[pg_test]`.
18+
When `pgrx` generates the DDL for a function (`CREATE FUNCTION ...`), it can apply `search_path` to
19+
that function that limits that function's search_path to whatever you specify.
20+
This is done via the `#[search_path(...)]` attribute macro applied to the function
21+
with `#[pg_extern]` or `#[pg_operator]` or `#[pg_test]`.
2922

3023
For example:
31-
24+
3225
```rust
3326
#[derive(PostgresType, Serialize, Deserialize, Debug, Eq, PartialEq)]
3427
pub struct SomeStruct {}
@@ -57,6 +50,14 @@ fn return_vec_of_customtype() -> Vec<SomeStruct> {
5750
```
5851

5952
In general this is only necessary when returning a `Vec<T: PostgresType>`. In this situation, pgrx needs to know that type's
60-
`oid` (from the `pg_catalog.pg_type` system catalog) and as such, the schema in which that type lives must be on that
53+
`oid` (from the `pg_catalog.pg_type` system catalog) and as such, the schema in which that type lives must be on that
6154
function's `search_path`.
6255

56+
### Relocatable extensions
57+
58+
Previously, PGRX would schema-qualify all of the output of `cargo pgrx schema` if there was a `schema = foo` attribute in your
59+
extension `.control` file, including items outside of a `#[pg_schema]` macro. However, this meant that pgrx could not support [relocatable extensions](https://www.postgresql.org/docs/current/extend-extensions.html#EXTEND-EXTENSIONS-RELOCATION).
60+
This is because relocatable extensions' defining characteristic is that they can be moved from one schema to another, and that
61+
means you absolutely cannot statically determine the schema the extension lives in by reading the control file alone.
62+
Since this change was implemented, you can now set `relocatable = true` in your control file without issue, and relocatable
63+
extensions can be moved with a `ALTER EXTENSION your_extension SET SCHEMA new_schema;` query.

pgrx-sql-entity-graph/src/pgrx_sql.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -390,13 +390,7 @@ impl PgrxSql {
390390
.neighbors_undirected(*item_index)
391391
.flat_map(|neighbor_index| match &self.graph[neighbor_index] {
392392
SqlGraphEntity::Schema(s) => Some(String::from(s.name)),
393-
SqlGraphEntity::ExtensionRoot(control) => {
394-
if !control.relocatable {
395-
control.schema.clone()
396-
} else {
397-
Some(String::from("@extname@"))
398-
}
399-
}
393+
SqlGraphEntity::ExtensionRoot(_control) => None,
400394
_ => None,
401395
})
402396
.next()

0 commit comments

Comments
 (0)