1//! Writes an extension's install script from the schema entities pgrx 2//! 0.19 embeds in the `.pgrxsc` section of the built shared object: the 3//! part of `cargo pgrx schema` a buck build needs (contract §4). 4//! 5//! Usage: pgrx-schema <lib-name> <lib.so> <control-file> <out.sql> 6 7use std::error::Error; 8 9use object::{Object, ObjectSection}; 10use pgrx_sql_entity_graph::section::{decode_entities, is_schema_section_name}; 11use pgrx_sql_entity_graph::{ControlFile, PgrxSql, SqlGraphEntity}; 12 13fn main() { 14 if let Err(e) = run() { 15 eprintln!("pgrx-schema: {e}"); 16 std::process::exit(1); 17 } 18} 19 20fn run() -> Result<(), Box<dyn Error>> { 21 let args: Vec<String> = std::env::args().skip(1).collect(); 22 let [lib_name, so_path, control_path, out_path] = args.as_slice() else { 23 return Err("usage: pgrx-schema <lib-name> <lib.so> <control-file> <out.sql>".into()); 24 }; 25 26 let so = std::fs::read(so_path)?; 27 let file = object::File::parse(so.as_slice())?; 28 let section = file 29 .sections() 30 .find(|s| s.name().is_ok_and(is_schema_section_name)) 31 .ok_or_else(|| format!("{so_path}: no pgrx schema section"))?; 32 let bytes = section.data()?; 33 34 let control = ControlFile::from_str(&std::fs::read_to_string(control_path)?)?; 35 // A control file naming module_pathname gets MODULE_PATHNAME in the 36 // script; one without gets a versioned library path (cargo-pgrx's rule). 37 let versioned_so = control.module_pathname.is_none(); 38 39 let entities = std::iter::once(SqlGraphEntity::ExtensionRoot(control)) 40 .chain(decode_entities(bytes)?); 41 PgrxSql::build(entities, lib_name.clone(), versioned_so)?.to_file(out_path)?; 42 Ok(()) 43}