diff --git a/Cargo.lock b/Cargo.lock index d1189940e..6dffb8999 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,7 +294,9 @@ dependencies = [ "object", "once_cell", "owo-colors", + "pgx-pg-config", "pgx-utils", + "prettyplease", "proc-macro2", "quote", "rayon", @@ -1447,6 +1449,21 @@ dependencies = [ "unescape", ] +[[package]] +name = "pgx-pg-config" +version = "0.5.0-beta.0" +dependencies = [ + "dirs", + "eyre", + "owo-colors", + "serde", + "serde_derive", + "serde_json", + "toml", + "tracing", + "url", +] + [[package]] name = "pgx-pg-sys" version = "0.5.0-beta.0" @@ -1460,6 +1477,7 @@ dependencies = [ "once_cell", "owo-colors", "pgx-macros", + "pgx-pg-config", "pgx-utils", "proc-macro2", "quote", @@ -1479,6 +1497,7 @@ dependencies = [ "owo-colors", "pgx", "pgx-macros", + "pgx-pg-config", "pgx-utils", "postgres", "regex", @@ -1495,12 +1514,9 @@ version = "0.5.0-beta.0" dependencies = [ "atty", "convert_case", - "dirs", - "env_proxy", "eyre", "owo-colors", "petgraph", - "prettyplease", "proc-macro2", "quote", "regex", @@ -1509,12 +1525,10 @@ dependencies = [ "serde_json", "syn", "syntect", - "toml", "tracing", "tracing-error", "tracing-subscriber", "unescape", - "url", ] [[package]] @@ -1618,9 +1632,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "prettyplease" -version = "0.1.11" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28f53e8b192565862cf99343194579a022eb9c7dd3a8d03134734803c7b3125" +checksum = "697ae720ee02011f439e0701db107ffe2916d83f718342d65d7f8bf7b8a5fee9" dependencies = [ "proc-macro2", "syn", diff --git a/Cargo.toml b/Cargo.toml index 50df078bb..9885e0da7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "cargo-pgx", "pgx", "pgx-macros", + "pgx-pg-config", "pgx-pg-sys", "pgx-tests", "pgx-utils", diff --git a/cargo-pgx/Cargo.toml b/cargo-pgx/Cargo.toml index 0cb2c8a53..fb8ba306d 100644 --- a/cargo-pgx/Cargo.toml +++ b/cargo-pgx/Cargo.toml @@ -24,7 +24,9 @@ semver = "1.0.9" owo-colors = { version = "3.4.0", features = [ "supports-colors" ] } env_proxy = "0.4.1" num_cpus = "1.13.1" +pgx-pg-config = { path = "../pgx-pg-config", version = "=0.5.0-beta.0" } pgx-utils = { path = "../pgx-utils", version = "=0.5.0-beta.0" } +prettyplease = "0.1.10" proc-macro2 = { version = "1.0.39", features = [ "span-locations" ] } quote = "1.0.18" rayon = "1.5.3" diff --git a/cargo-pgx/src/command/connect.rs b/cargo-pgx/src/command/connect.rs index 090f8dcdc..12fdd11e1 100644 --- a/cargo-pgx/src/command/connect.rs +++ b/cargo-pgx/src/command/connect.rs @@ -14,8 +14,7 @@ use crate::{ use cargo_toml::Manifest; use eyre::{eyre, WrapErr}; use owo_colors::OwoColorize; -use pgx_utils::createdb; -use pgx_utils::pg_config::{PgConfig, Pgx}; +use pgx_pg_config::{createdb, PgConfig, Pgx}; use std::path::PathBuf; /// Connect, via psql, to a Postgres instance diff --git a/cargo-pgx/src/command/init.rs b/cargo-pgx/src/command/init.rs index 4e91058ac..bb8dc289b 100644 --- a/cargo-pgx/src/command/init.rs +++ b/cargo-pgx/src/command/init.rs @@ -12,10 +12,7 @@ use crate::command::version::pgx_default; use crate::CommandExecute; use eyre::{eyre, WrapErr}; use owo_colors::OwoColorize; -use pgx_utils::{ - pg_config::{PgConfig, PgConfigSelector, Pgx}, - prefix_path, SUPPORTED_MAJOR_VERSIONS, -}; +use pgx_pg_config::{prefix_path, PgConfig, PgConfigSelector, Pgx, SUPPORTED_MAJOR_VERSIONS}; use rayon::prelude::*; use std::collections::HashMap; diff --git a/cargo-pgx/src/command/install.rs b/cargo-pgx/src/command/install.rs index 3a114e31c..5975ee8fe 100644 --- a/cargo-pgx/src/command/install.rs +++ b/cargo-pgx/src/command/install.rs @@ -14,8 +14,7 @@ use crate::{ use cargo_toml::Manifest; use eyre::{eyre, WrapErr}; use owo_colors::OwoColorize; -use pgx_utils::pg_config::PgConfig; -use pgx_utils::{get_target_dir, versioned_so_name}; +use pgx_pg_config::{get_target_dir, PgConfig}; use std::{ io::BufReader, path::{Path, PathBuf}, @@ -156,7 +155,8 @@ pub(crate) fn install_extension( dest.push(&pkgdir); let so_name = if versioned_so { let extver = get_version(&package_manifest_path)?; - versioned_so_name(&extname, &extver) + // note: versioned so-name format must agree with pgx-utils + format!("{}-{}", &extname, &extver) } else { extname.clone() }; diff --git a/cargo-pgx/src/command/package.rs b/cargo-pgx/src/command/package.rs index 63cb317c6..d34acaabb 100644 --- a/cargo-pgx/src/command/package.rs +++ b/cargo-pgx/src/command/package.rs @@ -13,7 +13,7 @@ use crate::{ }; use cargo_toml::Manifest; use eyre::{eyre, WrapErr}; -use pgx_utils::{get_target_dir, pg_config::PgConfig}; +use pgx_pg_config::{get_target_dir, PgConfig}; use std::path::{Path, PathBuf}; /// Create an installation package directory. diff --git a/cargo-pgx/src/command/run.rs b/cargo-pgx/src/command/run.rs index 8137c692c..87569eaf2 100644 --- a/cargo-pgx/src/command/run.rs +++ b/cargo-pgx/src/command/run.rs @@ -16,10 +16,7 @@ use crate::{ use cargo_toml::Manifest; use eyre::{eyre, WrapErr}; use owo_colors::OwoColorize; -use pgx_utils::{ - createdb, - pg_config::{PgConfig, Pgx}, -}; +use pgx_pg_config::{createdb, PgConfig, Pgx}; use std::{os::unix::process::CommandExt, path::Path, process::Command}; /// Compile/install extension to a pgx-managed Postgres instance and start psql #[derive(clap::Args, Debug)] diff --git a/cargo-pgx/src/command/schema.rs b/cargo-pgx/src/command/schema.rs index a41b57d62..77bbf0848 100644 --- a/cargo-pgx/src/command/schema.rs +++ b/cargo-pgx/src/command/schema.rs @@ -11,6 +11,7 @@ use crate::{ get::{find_control_file, get_property}, install::format_display_path, }, + pgx_pg_sys_stub::PgxPgSysStub, CommandExecute, }; use cargo_toml::Manifest; @@ -18,11 +19,8 @@ use eyre::{eyre, WrapErr}; use object::Object; use once_cell::sync::OnceCell; use owo_colors::OwoColorize; -use pgx_utils::{ - pg_config::{PgConfig, Pgx}, - sql_entity_graph::{PgxSql, SqlGraphEntity}, - PgxPgSysStub, -}; +use pgx_pg_config::{get_target_dir, PgConfig, Pgx}; +use pgx_utils::sql_entity_graph::{PgxSql, SqlGraphEntity}; use std::{ collections::HashSet, hash::{Hash, Hasher}, @@ -178,7 +176,7 @@ pub(crate) fn generate_schema( let flags = std::env::var("PGX_BUILD_FLAGS").unwrap_or_default(); - let mut target_dir_with_profile = pgx_utils::get_target_dir()?; + let mut target_dir_with_profile = get_target_dir()?; target_dir_with_profile.push(if is_release { "release" } else { "debug" }); // First, build the SQL generator so we can get a look at the symbol table diff --git a/cargo-pgx/src/command/start.rs b/cargo-pgx/src/command/start.rs index ab7469aee..5b9c63a26 100644 --- a/cargo-pgx/src/command/start.rs +++ b/cargo-pgx/src/command/start.rs @@ -13,7 +13,7 @@ use crate::CommandExecute; use cargo_toml::Manifest; use eyre::{eyre, WrapErr}; use owo_colors::OwoColorize; -use pgx_utils::pg_config::{PgConfig, PgConfigSelector, Pgx}; +use pgx_pg_config::{PgConfig, PgConfigSelector, Pgx}; use std::{os::unix::process::CommandExt, path::PathBuf, process::Stdio}; /// Start a pgx-managed Postgres instance diff --git a/cargo-pgx/src/command/status.rs b/cargo-pgx/src/command/status.rs index 0eddcdb42..3077328a1 100644 --- a/cargo-pgx/src/command/status.rs +++ b/cargo-pgx/src/command/status.rs @@ -9,7 +9,7 @@ Use of this source code is governed by the MIT license that can be found in the use eyre::eyre; use owo_colors::OwoColorize; -use pgx_utils::pg_config::{PgConfig, PgConfigSelector, Pgx}; +use pgx_pg_config::{PgConfig, PgConfigSelector, Pgx}; use std::{path::PathBuf, process::Stdio}; use crate::CommandExecute; diff --git a/cargo-pgx/src/command/stop.rs b/cargo-pgx/src/command/stop.rs index 7b8984b6b..fcef67c8d 100644 --- a/cargo-pgx/src/command/stop.rs +++ b/cargo-pgx/src/command/stop.rs @@ -11,7 +11,7 @@ use crate::{command::status::status_postgres, CommandExecute}; use cargo_toml::Manifest; use eyre::{eyre, WrapErr}; use owo_colors::OwoColorize; -use pgx_utils::pg_config::{PgConfig, PgConfigSelector, Pgx}; +use pgx_pg_config::{PgConfig, PgConfigSelector, Pgx}; use std::{path::PathBuf, process::Stdio}; /// Stop a pgx-managed Postgres instance diff --git a/cargo-pgx/src/command/test.rs b/cargo-pgx/src/command/test.rs index f35402bae..b0bdde374 100644 --- a/cargo-pgx/src/command/test.rs +++ b/cargo-pgx/src/command/test.rs @@ -9,10 +9,7 @@ Use of this source code is governed by the MIT license that can be found in the use cargo_toml::Manifest; use eyre::{eyre, WrapErr}; -use pgx_utils::{ - get_target_dir, - pg_config::{PgConfig, PgConfigSelector, Pgx}, -}; +use pgx_pg_config::{get_target_dir, PgConfig, PgConfigSelector, Pgx}; use std::{ path::{Path, PathBuf}, process::{Command, Stdio}, diff --git a/cargo-pgx/src/command/version.rs b/cargo-pgx/src/command/version.rs index bcc8415b7..326eadf22 100644 --- a/cargo-pgx/src/command/version.rs +++ b/cargo-pgx/src/command/version.rs @@ -1,4 +1,4 @@ -use pgx_utils::pg_config::{PgConfig, Pgx}; +use pgx_pg_config::{PgConfig, Pgx}; pub(crate) fn pgx_default(supported_major_versions: &[u16]) -> eyre::Result { let mut pgx = Pgx::new(); @@ -13,7 +13,7 @@ mod rss { use env_proxy::for_url_str; use eyre::WrapErr; use owo_colors::OwoColorize; - use pgx_utils::pg_config::PgVersion; + use pgx_pg_config::PgVersion; use serde_derive::Deserialize; use ureq::{Agent, AgentBuilder, Proxy}; use url::Url; diff --git a/cargo-pgx/src/main.rs b/cargo-pgx/src/main.rs index 0ae74adf5..a8c89f583 100644 --- a/cargo-pgx/src/main.rs +++ b/cargo-pgx/src/main.rs @@ -10,6 +10,7 @@ Use of this source code is governed by the MIT license that can be found in the mod command; mod manifest; mod metadata; +mod pgx_pg_sys_stub; use atty::Stream; use clap::Parser; diff --git a/cargo-pgx/src/manifest.rs b/cargo-pgx/src/manifest.rs index 201ec9309..0d8547228 100644 --- a/cargo-pgx/src/manifest.rs +++ b/cargo-pgx/src/manifest.rs @@ -9,7 +9,7 @@ Use of this source code is governed by the MIT license that can be found in the use cargo_metadata::Metadata; use cargo_toml::Manifest; use eyre::eyre; -use pgx_utils::SUPPORTED_MAJOR_VERSIONS; +use pgx_pg_config::SUPPORTED_MAJOR_VERSIONS; use std::path::PathBuf; #[tracing::instrument(skip_all)] diff --git a/pgx-utils/src/pgx_pg_sys_stub/mod.rs b/cargo-pgx/src/pgx_pg_sys_stub.rs similarity index 100% rename from pgx-utils/src/pgx_pg_sys_stub/mod.rs rename to cargo-pgx/src/pgx_pg_sys_stub.rs diff --git a/pgx-macros/src/operators.rs b/pgx-macros/src/operators.rs index 8c2594ea3..65e4c5ceb 100644 --- a/pgx-macros/src/operators.rs +++ b/pgx-macros/src/operators.rs @@ -6,11 +6,10 @@ All rights reserved. Use of this source code is governed by the MIT license that can be found in the LICENSE file. */ -use pgx_utils::{ - operator_common::*, - sql_entity_graph::{PostgresHash, PostgresOrd}, -}; +use pgx_utils::sql_entity_graph::{PostgresHash, PostgresOrd}; +use proc_macro2::Ident; +use quote::quote; use quote::ToTokens; use syn::DeriveInput; @@ -48,3 +47,146 @@ pub(crate) fn impl_postgres_hash(ast: DeriveInput) -> syn::Result proc_macro2::TokenStream { + let pg_name = Ident::new( + &format!("{}_eq", type_name).to_lowercase(), + type_name.span(), + ); + quote! { + #[allow(non_snake_case)] + #[pg_operator(immutable, parallel_safe)] + #[opname(=)] + #[negator(<>)] + #[restrict(eqsel)] + #[join(eqjoinsel)] + #[merges] + #[hashes] + fn #pg_name(left: #type_name, right: #type_name) -> bool { + left == right + } + } +} + +pub fn ne(type_name: &Ident) -> proc_macro2::TokenStream { + let pg_name = Ident::new( + &format!("{}_ne", type_name).to_lowercase(), + type_name.span(), + ); + quote! { + #[allow(non_snake_case)] + #[pg_operator(immutable, parallel_safe)] + #[opname(<>)] + #[negator(=)] + #[restrict(neqsel)] + #[join(neqjoinsel)] + fn #pg_name(left: #type_name, right: #type_name) -> bool { + left != right + } + } +} + +pub fn lt(type_name: &Ident) -> proc_macro2::TokenStream { + let pg_name = Ident::new( + &format!("{}_lt", type_name).to_lowercase(), + type_name.span(), + ); + quote! { + #[allow(non_snake_case)] + #[pg_operator(immutable, parallel_safe)] + #[opname(<)] + #[negator(>=)] + #[commutator(>)] + #[restrict(scalarltsel)] + #[join(scalarltjoinsel)] + fn #pg_name(left: #type_name, right: #type_name) -> bool { + left < right + } + + } +} + +pub fn gt(type_name: &Ident) -> proc_macro2::TokenStream { + let pg_name = Ident::new( + &format!("{}_gt", type_name).to_lowercase(), + type_name.span(), + ); + quote! { + #[allow(non_snake_case)] + #[pg_operator(immutable, parallel_safe)] + #[opname(>)] + #[negator(<=)] + #[commutator(<)] + #[restrict(scalargtsel)] + #[join(scalargtjoinsel)] + fn #pg_name(left: #type_name, right: #type_name) -> bool { + left > right + } + } +} + +pub fn le(type_name: &Ident) -> proc_macro2::TokenStream { + let pg_name = Ident::new( + &format!("{}_le", type_name).to_lowercase(), + type_name.span(), + ); + quote! { + #[allow(non_snake_case)] + #[pg_operator(immutable, parallel_safe)] + #[opname(<=)] + #[negator(>)] + #[commutator(>=)] + #[restrict(scalarlesel)] + #[join(scalarlejoinsel)] + fn #pg_name(left: #type_name, right: #type_name) -> bool { + left <= right + } + } +} + +pub fn ge(type_name: &Ident) -> proc_macro2::TokenStream { + let pg_name = Ident::new( + &format!("{}_ge", type_name).to_lowercase(), + type_name.span(), + ); + quote! { + #[allow(non_snake_case)] + #[pg_operator(immutable, parallel_safe)] + #[opname(>=)] + #[negator(<)] + #[commutator(<=)] + #[restrict(scalargesel)] + #[join(scalargejoinsel)] + fn #pg_name(left: #type_name, right: #type_name) -> bool { + left >= right + } + } +} + +pub fn cmp(type_name: &Ident) -> proc_macro2::TokenStream { + let pg_name = Ident::new( + &format!("{}_cmp", type_name).to_lowercase(), + type_name.span(), + ); + quote! { + #[allow(non_snake_case)] + #[pg_extern(immutable, parallel_safe)] + fn #pg_name(left: #type_name, right: #type_name) -> i32 { + left.cmp(&right) as i32 + } + } +} + +pub fn hash(type_name: &Ident) -> proc_macro2::TokenStream { + let pg_name = Ident::new( + &format!("{}_hash", type_name).to_lowercase(), + type_name.span(), + ); + quote! { + #[allow(non_snake_case)] + #[pg_extern(immutable, parallel_safe)] + fn #pg_name(value: #type_name) -> i32 { + pgx::misc::pgx_seahash(&value) as i32 + } + } +} diff --git a/pgx-pg-config/Cargo.toml b/pgx-pg-config/Cargo.toml new file mode 100644 index 000000000..6a2960a26 --- /dev/null +++ b/pgx-pg-config/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "pgx-pg-config" +version = "0.5.0-beta.0" +authors = ["ZomboDB, LLC "] +license = "MIT" +description = "A Postgres pg_config wrapper for 'pgx'" +homepage = "https://github.com/zombodb/pgx" +repository = "https://github.com/zombodb/pgx" +#documentation = "https://docs.rs/pgx-utils" +readme = "README.md" +edition = "2021" +rust-version = "1.58" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dirs = "4.0.0" +eyre = "0.6.8" +owo-colors = "3.4.0" +serde = { version = "1.0.137", features = [ "derive" ] } +serde_derive = "1.0.137" +serde_json = "1.0.81" +toml = "0.5.9" +tracing = "0.1.34" +url = "2.2.2" diff --git a/pgx-pg-config/README.md b/pgx-pg-config/README.md new file mode 100644 index 000000000..da89c7c5a --- /dev/null +++ b/pgx-pg-config/README.md @@ -0,0 +1,3 @@ +# pgx-pg-config + +A crate containing an abstraction/wrapper over Postgres' `pg_config` to be used with [`pgx`](https://crates.io/crates/pgx/) diff --git a/pgx-utils/src/pg_config.rs b/pgx-pg-config/src/lib.rs similarity index 80% rename from pgx-utils/src/pg_config.rs rename to pgx-pg-config/src/lib.rs index cd3c09594..4d207f4ad 100644 --- a/pgx-utils/src/pg_config.rs +++ b/pgx-pg-config/src/lib.rs @@ -7,11 +7,11 @@ All rights reserved. Use of this source code is governed by the MIT license that can be found in the LICENSE file. */ //! Wrapper around Postgres' `pg_config` command-line tool -use crate::{BASE_POSTGRES_PORT_NO, BASE_POSTGRES_TESTING_PORT_NO}; use eyre::{eyre, WrapErr}; use owo_colors::OwoColorize; use serde_derive::{Deserialize, Serialize}; use std::fmt::{self, Display, Formatter}; +use std::process::Stdio; use std::{ collections::HashMap, io::ErrorKind, @@ -21,6 +21,16 @@ use std::{ }; use url::Url; +pub static BASE_POSTGRES_PORT_NO: u16 = 28800; +pub static BASE_POSTGRES_TESTING_PORT_NO: u16 = 32200; + +// These methods were originally in `pgx-utils`, but in an effort to consolidate +// dependencies, the decision was made to package them into wherever made the +// most sense. In this case, it made the most sense to put them into this +// pgx-pg-config crate. That doesnt mean they can't be moved at a later date. +mod path_methods; +pub use path_methods::{get_target_dir, prefix_path}; + #[derive(Clone)] pub struct PgVersion { major: u16, @@ -410,3 +420,85 @@ impl Pgx { Ok(path) } } + +pub const SUPPORTED_MAJOR_VERSIONS: &[u16] = &[10, 11, 12, 13, 14]; + +pub fn createdb( + pg_config: &PgConfig, + dbname: &str, + is_test: bool, + if_not_exists: bool, +) -> eyre::Result { + if if_not_exists && does_db_exist(pg_config, dbname)? { + return Ok(false); + } + + println!("{} database {}", " Creating".bold().green(), dbname); + let mut command = Command::new(pg_config.createdb_path()?); + command + .env_remove("PGDATABASE") + .env_remove("PGHOST") + .env_remove("PGPORT") + .env_remove("PGUSER") + .arg("-h") + .arg(pg_config.host()) + .arg("-p") + .arg(if is_test { + pg_config.test_port()?.to_string() + } else { + pg_config.port()?.to_string() + }) + .arg(dbname) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + let command_str = format!("{:?}", command); + + let output = command.output()?; + + if !output.status.success() { + return Err(eyre!( + "problem running createdb: {}\n\n{}{}", + command_str, + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap() + )); + } + + Ok(true) +} + +fn does_db_exist(pg_config: &PgConfig, dbname: &str) -> eyre::Result { + let mut command = Command::new(pg_config.psql_path()?); + command + .arg("-XqAt") + .env_remove("PGUSER") + .arg("-h") + .arg(pg_config.host()) + .arg("-p") + .arg(pg_config.port()?.to_string()) + .arg("template1") + .arg("-c") + .arg(&format!( + "select count(*) from pg_database where datname = '{}';", + dbname.replace("'", "''") + )) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + + let command_str = format!("{:?}", command); + let output = command.output()?; + + if !output.status.success() { + return Err(eyre!( + "problem checking if database '{}' exists: {}\n\n{}{}", + dbname, + command_str, + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap() + )); + } else { + let count = i32::from_str(&String::from_utf8(output.stdout).unwrap().trim()) + .wrap_err("result is not a number")?; + Ok(count > 0) + } +} diff --git a/pgx-pg-config/src/path_methods.rs b/pgx-pg-config/src/path_methods.rs new file mode 100644 index 000000000..ba081896d --- /dev/null +++ b/pgx-pg-config/src/path_methods.rs @@ -0,0 +1,44 @@ +use eyre::{eyre, WrapErr}; +use serde_json::value::Value as JsonValue; +use std::{path::PathBuf, process::Command}; + +// Originally part of `pgx-utils` +pub fn prefix_path>(dir: P) -> String { + let mut path = std::env::split_paths(&std::env::var_os("PATH").expect("failed to get $PATH")) + .collect::>(); + + path.insert(0, dir.into()); + std::env::join_paths(path) + .expect("failed to join paths") + .into_string() + .expect("failed to construct path") +} + +// Originally part of `pgx-utils` +pub fn get_target_dir() -> eyre::Result { + let mut command = Command::new("cargo"); + command + .arg("metadata") + .arg("--format-version=1") + .arg("--no-deps"); + let output = command + .output() + .wrap_err("Unable to get target directory from `cargo metadata`")?; + if !output.status.success() { + return Err(eyre!( + "'cargo metadata' failed with exit code: {}", + output.status + )); + } + + let json: JsonValue = + serde_json::from_slice(&output.stdout).wrap_err("Invalid `cargo metada` response")?; + let target_dir = json.get("target_directory"); + match target_dir { + Some(JsonValue::String(target_dir)) => Ok(target_dir.into()), + v => Err(eyre!( + "could not read target dir from `cargo metadata` got: {:?}", + v, + )), + } +} diff --git a/pgx-pg-sys/Cargo.toml b/pgx-pg-sys/Cargo.toml index 3987c4324..49e8de37b 100644 --- a/pgx-pg-sys/Cargo.toml +++ b/pgx-pg-sys/Cargo.toml @@ -40,6 +40,7 @@ bindgen = { version = "0.59.2", default-features = false, features = ["runtime"] build-deps = "0.1.4" owo-colors = "3.4.0" num_cpus = "1.13.1" +pgx-pg-config= { path = "../pgx-pg-config/", version = "=0.5.0-beta.0" } pgx-utils = { path = "../pgx-utils/", version = "=0.5.0-beta.0" } proc-macro2 = "1.0.39" quote = "1.0.18" diff --git a/pgx-pg-sys/build.rs b/pgx-pg-sys/build.rs index 82532c211..0f1329685 100644 --- a/pgx-pg-sys/build.rs +++ b/pgx-pg-sys/build.rs @@ -11,8 +11,7 @@ extern crate build_deps; use bindgen::callbacks::MacroParsingBehavior; use eyre::{eyre, WrapErr}; -use pgx_utils::pg_config::{PgConfig, PgConfigSelector, Pgx}; -use pgx_utils::prefix_path; +use pgx_pg_config::{prefix_path, PgConfig, PgConfigSelector, Pgx, SUPPORTED_MAJOR_VERSIONS}; use pgx_utils::rewriter::PgGuardRewriter; use quote::{quote, ToTokens}; use rayon::prelude::*; @@ -110,7 +109,7 @@ fn main() -> color_eyre::Result<()> { .collect::>>()? } else { let mut found = None; - for version in pgx_utils::SUPPORTED_MAJOR_VERSIONS { + for version in SUPPORTED_MAJOR_VERSIONS { if let Err(_) = std::env::var(&format!("CARGO_FEATURE_PG{}", version)) { continue; } @@ -122,7 +121,7 @@ fn main() -> color_eyre::Result<()> { let found = found.ok_or_else(|| { eyre!( "Did not find `pg$VERSION` feature. `pgx-pg-sys` requires one of {} to be set", - pgx_utils::SUPPORTED_MAJOR_VERSIONS + SUPPORTED_MAJOR_VERSIONS .iter() .map(|x| format!("`pg{}`", x)) .collect::>() diff --git a/pgx-tests/Cargo.toml b/pgx-tests/Cargo.toml index c4844de7d..645d0390f 100644 --- a/pgx-tests/Cargo.toml +++ b/pgx-tests/Cargo.toml @@ -37,6 +37,7 @@ once_cell = "1.10.0" libc = "0.2.126" pgx = { path = "../pgx", default-features = false, version= "=0.5.0-beta.0" } pgx-macros = { path = "../pgx-macros", version= "=0.5.0-beta.0" } +pgx-pg-config = { path = "../pgx-pg-config", version= "=0.5.0-beta.0" } pgx-utils = { path = "../pgx-utils", version= "=0.5.0-beta.0" } postgres = "0.19.3" regex = "1.5.5" diff --git a/pgx-tests/src/framework.rs b/pgx-tests/src/framework.rs index 01953610e..443bd0fb9 100644 --- a/pgx-tests/src/framework.rs +++ b/pgx-tests/src/framework.rs @@ -9,20 +9,18 @@ Use of this source code is governed by the MIT license that can be found in the use std::process::{Command, Stdio}; -use once_cell::sync::Lazy; -use std::sync::{Arc, Mutex}; - use eyre::{eyre, WrapErr}; +use once_cell::sync::Lazy; use owo_colors::OwoColorize; use pgx::*; -use pgx_utils::pg_config::{PgConfig, Pgx}; -use pgx_utils::{createdb, get_named_capture, get_target_dir}; +use pgx_pg_config::{createdb, get_target_dir, PgConfig, Pgx}; use postgres::error::DbError; use postgres::Client; use std::collections::HashMap; use std::fmt::Write as _; use std::io::{BufRead, BufReader, Write}; use std::path::PathBuf; +use std::sync::{Arc, Mutex}; type LogLines = Arc>>>; @@ -542,3 +540,14 @@ fn get_pg_user() -> String { std::env::var("USER") .unwrap_or_else(|_| panic!("USER environment var is unset or invalid UTF-8")) } + +pub fn get_named_capture( + regex: ®ex::Regex, + name: &'static str, + against: &str, +) -> Option { + match regex.captures(against) { + Some(cap) => Some(cap[name].to_string()), + None => None, + } +} diff --git a/pgx-tests/src/tests/struct_type_tests.rs b/pgx-tests/src/tests/struct_type_tests.rs index ee8e4ffee..3722b77ac 100644 --- a/pgx-tests/src/tests/struct_type_tests.rs +++ b/pgx-tests/src/tests/struct_type_tests.rs @@ -9,7 +9,8 @@ Use of this source code is governed by the MIT license that can be found in the use pgx::stringinfo::StringInfo; use pgx::*; -use pgx_utils::get_named_capture; + +use crate::get_named_capture; #[derive(Debug)] #[repr(C)] diff --git a/pgx-utils/Cargo.toml b/pgx-utils/Cargo.toml index 5b1f3f2d2..62dc3f37a 100644 --- a/pgx-utils/Cargo.toml +++ b/pgx-utils/Cargo.toml @@ -13,10 +13,10 @@ rust-version = "1.58" [dependencies] atty = "0.2.14" -owo-colors = "3.4.0" convert_case = "0.5.0" -dirs = "4.0.0" -env_proxy = "0.4.1" +eyre = "0.6.8" +owo-colors = "3.4.0" +petgraph = "0.6.0" proc-macro2 = { version = "1.0.39", features = [ "span-locations" ] } quote = "1.0.18" regex = "1.5.5" @@ -25,12 +25,7 @@ serde_derive = "1.0.137" serde_json = "1.0.81" syn = { version = "1.0.95", features = [ "extra-traits", "full", "fold", "parsing" ] } syntect = { version = "5.0.0", default-features = false, features = ["default-fancy"] } -toml = "0.5.9" unescape = "0.1.0" -url = "2.2.2" -eyre = "0.6.8" tracing = "0.1.34" tracing-error = "0.2.0" tracing-subscriber = { version = "0.3.11", features = [ "env-filter" ] } -petgraph = "0.6.0" -prettyplease = "0.1.10" diff --git a/pgx-utils/src/lib.rs b/pgx-utils/src/lib.rs index 5733f2db6..24bfd4e4b 100644 --- a/pgx-utils/src/lib.rs +++ b/pgx-utils/src/lib.rs @@ -7,29 +7,15 @@ All rights reserved. Use of this source code is governed by the MIT license that can be found in the LICENSE file. */ -use crate::{pg_config::PgConfig, sql_entity_graph::PositioningRef}; -use eyre::{eyre, WrapErr}; -use owo_colors::OwoColorize; +use crate::sql_entity_graph::PositioningRef; use proc_macro2::{TokenStream, TokenTree}; use quote::{format_ident, quote, ToTokens, TokenStreamExt}; -use serde_json::value::Value as JsonValue; -use std::{ - collections::HashSet, - path::PathBuf, - process::{Command, Stdio}, - str::FromStr, -}; +use std::collections::HashSet; use syn::{GenericArgument, ItemFn, PathArguments, ReturnType, Type, TypeParamBound}; -mod pgx_pg_sys_stub; - -pub mod operator_common; -pub mod pg_config; pub mod rewriter; pub mod sql_entity_graph; -pub use pgx_pg_sys_stub::PgxPgSysStub; - #[doc(hidden)] pub mod __reexports { pub use eyre; @@ -41,140 +27,6 @@ pub mod __reexports { } } -pub const SUPPORTED_MAJOR_VERSIONS: &[u16] = &[10, 11, 12, 13, 14]; -pub static BASE_POSTGRES_PORT_NO: u16 = 28800; -pub static BASE_POSTGRES_TESTING_PORT_NO: u16 = 32200; - -pub fn get_target_dir() -> eyre::Result { - let mut command = Command::new("cargo"); - command - .arg("metadata") - .arg("--format-version=1") - .arg("--no-deps"); - let output = command - .output() - .wrap_err("Unable to get target directory from `cargo metadata`")?; - if !output.status.success() { - return Err(eyre!( - "'cargo metadata' failed with exit code: {}", - output.status - )); - } - - let json: JsonValue = - serde_json::from_slice(&output.stdout).wrap_err("Invalid `cargo metada` response")?; - let target_dir = json.get("target_directory"); - match target_dir { - Some(JsonValue::String(target_dir)) => Ok(target_dir.into()), - v => Err(eyre!( - "could not read target dir from `cargo metadata` got: {:?}", - v, - )), - } -} - -pub fn prefix_path>(dir: P) -> String { - let mut path = std::env::split_paths(&std::env::var_os("PATH").expect("failed to get $PATH")) - .collect::>(); - - path.insert(0, dir.into()); - std::env::join_paths(path) - .expect("failed to join paths") - .into_string() - .expect("failed to construct path") -} - -pub fn createdb( - pg_config: &PgConfig, - dbname: &str, - is_test: bool, - if_not_exists: bool, -) -> eyre::Result { - if if_not_exists && does_db_exist(pg_config, dbname)? { - return Ok(false); - } - - println!("{} database {}", " Creating".bold().green(), dbname); - let mut command = Command::new(pg_config.createdb_path()?); - command - .env_remove("PGDATABASE") - .env_remove("PGHOST") - .env_remove("PGPORT") - .env_remove("PGUSER") - .arg("-h") - .arg(pg_config.host()) - .arg("-p") - .arg(if is_test { - pg_config.test_port()?.to_string() - } else { - pg_config.port()?.to_string() - }) - .arg(dbname) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - let command_str = format!("{:?}", command); - - let output = command.output()?; - - if !output.status.success() { - return Err(eyre!( - "problem running createdb: {}\n\n{}{}", - command_str, - String::from_utf8(output.stdout).unwrap(), - String::from_utf8(output.stderr).unwrap() - )); - } - - Ok(true) -} - -fn does_db_exist(pg_config: &PgConfig, dbname: &str) -> eyre::Result { - let mut command = Command::new(pg_config.psql_path()?); - command - .arg("-XqAt") - .env_remove("PGUSER") - .arg("-h") - .arg(pg_config.host()) - .arg("-p") - .arg(pg_config.port()?.to_string()) - .arg("template1") - .arg("-c") - .arg(&format!( - "select count(*) from pg_database where datname = '{}';", - dbname.replace("'", "''") - )) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - - let command_str = format!("{:?}", command); - let output = command.output()?; - - if !output.status.success() { - return Err(eyre!( - "problem checking if database '{}' exists: {}\n\n{}{}", - dbname, - command_str, - String::from_utf8(output.stdout).unwrap(), - String::from_utf8(output.stderr).unwrap() - )); - } else { - let count = i32::from_str(&String::from_utf8(output.stdout).unwrap().trim()) - .wrap_err("result is not a number")?; - Ok(count > 0) - } -} - -pub fn get_named_capture( - regex: ®ex::Regex, - name: &'static str, - against: &str, -) -> Option { - match regex.captures(against) { - Some(cap) => Some(cap[name].to_string()), - None => None, - } -} - #[derive(Debug, Hash, Eq, PartialEq, Clone, PartialOrd, Ord)] pub enum ExternArgs { Immutable, @@ -564,10 +416,6 @@ pub fn staticize_lifetimes(value: &mut syn::Type) { } } -pub fn versioned_so_name(extension_name: &str, extension_version: &str) -> String { - format!("{}-{}", extension_name, extension_version) -} - /// Roughly `pgx::pg_sys::NAMEDATALEN` /// /// Technically it **should** be that exactly, however this is `pgx-utils` and a this data is used at macro time. diff --git a/pgx-utils/src/operator_common.rs b/pgx-utils/src/operator_common.rs deleted file mode 100644 index 49878e32c..000000000 --- a/pgx-utils/src/operator_common.rs +++ /dev/null @@ -1,153 +0,0 @@ -/* -Portions Copyright 2019-2021 ZomboDB, LLC. -Portions Copyright 2021-2022 Technology Concepts & Design, Inc. - -All rights reserved. - -Use of this source code is governed by the MIT license that can be found in the LICENSE file. -*/ -use proc_macro2::Ident; -use quote::quote; - -pub fn eq(type_name: &Ident) -> proc_macro2::TokenStream { - let pg_name = Ident::new( - &format!("{}_eq", type_name).to_lowercase(), - type_name.span(), - ); - quote! { - #[allow(non_snake_case)] - #[pg_operator(immutable, parallel_safe)] - #[opname(=)] - #[negator(<>)] - #[restrict(eqsel)] - #[join(eqjoinsel)] - #[merges] - #[hashes] - fn #pg_name(left: #type_name, right: #type_name) -> bool { - left == right - } - } -} - -pub fn ne(type_name: &Ident) -> proc_macro2::TokenStream { - let pg_name = Ident::new( - &format!("{}_ne", type_name).to_lowercase(), - type_name.span(), - ); - quote! { - #[allow(non_snake_case)] - #[pg_operator(immutable, parallel_safe)] - #[opname(<>)] - #[negator(=)] - #[restrict(neqsel)] - #[join(neqjoinsel)] - fn #pg_name(left: #type_name, right: #type_name) -> bool { - left != right - } - } -} - -pub fn lt(type_name: &Ident) -> proc_macro2::TokenStream { - let pg_name = Ident::new( - &format!("{}_lt", type_name).to_lowercase(), - type_name.span(), - ); - quote! { - #[allow(non_snake_case)] - #[pg_operator(immutable, parallel_safe)] - #[opname(<)] - #[negator(>=)] - #[commutator(>)] - #[restrict(scalarltsel)] - #[join(scalarltjoinsel)] - fn #pg_name(left: #type_name, right: #type_name) -> bool { - left < right - } - - } -} - -pub fn gt(type_name: &Ident) -> proc_macro2::TokenStream { - let pg_name = Ident::new( - &format!("{}_gt", type_name).to_lowercase(), - type_name.span(), - ); - quote! { - #[allow(non_snake_case)] - #[pg_operator(immutable, parallel_safe)] - #[opname(>)] - #[negator(<=)] - #[commutator(<)] - #[restrict(scalargtsel)] - #[join(scalargtjoinsel)] - fn #pg_name(left: #type_name, right: #type_name) -> bool { - left > right - } - } -} - -pub fn le(type_name: &Ident) -> proc_macro2::TokenStream { - let pg_name = Ident::new( - &format!("{}_le", type_name).to_lowercase(), - type_name.span(), - ); - quote! { - #[allow(non_snake_case)] - #[pg_operator(immutable, parallel_safe)] - #[opname(<=)] - #[negator(>)] - #[commutator(>=)] - #[restrict(scalarlesel)] - #[join(scalarlejoinsel)] - fn #pg_name(left: #type_name, right: #type_name) -> bool { - left <= right - } - } -} - -pub fn ge(type_name: &Ident) -> proc_macro2::TokenStream { - let pg_name = Ident::new( - &format!("{}_ge", type_name).to_lowercase(), - type_name.span(), - ); - quote! { - #[allow(non_snake_case)] - #[pg_operator(immutable, parallel_safe)] - #[opname(>=)] - #[negator(<)] - #[commutator(<=)] - #[restrict(scalargesel)] - #[join(scalargejoinsel)] - fn #pg_name(left: #type_name, right: #type_name) -> bool { - left >= right - } - } -} - -pub fn cmp(type_name: &Ident) -> proc_macro2::TokenStream { - let pg_name = Ident::new( - &format!("{}_cmp", type_name).to_lowercase(), - type_name.span(), - ); - quote! { - #[allow(non_snake_case)] - #[pg_extern(immutable, parallel_safe)] - fn #pg_name(left: #type_name, right: #type_name) -> i32 { - left.cmp(&right) as i32 - } - } -} - -pub fn hash(type_name: &Ident) -> proc_macro2::TokenStream { - let pg_name = Ident::new( - &format!("{}_hash", type_name).to_lowercase(), - type_name.span(), - ); - quote! { - #[allow(non_snake_case)] - #[pg_extern(immutable, parallel_safe)] - fn #pg_name(value: #type_name) -> i32 { - pgx::misc::pgx_seahash(&value) as i32 - } - } -} diff --git a/pgx-utils/src/sql_entity_graph/pgx_sql.rs b/pgx-utils/src/sql_entity_graph/pgx_sql.rs index 9adc1c106..298163891 100644 --- a/pgx-utils/src/sql_entity_graph/pgx_sql.rs +++ b/pgx-utils/src/sql_entity_graph/pgx_sql.rs @@ -32,7 +32,6 @@ use crate::sql_entity_graph::{ to_sql::ToSql, SqlGraphEntity, SqlGraphIdentifier, }; -use crate::versioned_so_name; use super::pg_extern::entity::PgExternReturnEntityIteratedItem; @@ -548,7 +547,8 @@ impl PgxSql { return if self.versioned_so { let extname = &self.extension_name; let extver = &self.control.default_version; - format!("$libdir/{}", versioned_so_name(extname, extver)) + // Note: versioned so-name format must agree with cargo pgx + format!("$libdir/{}-{}", extname, extver) } else { String::from("MODULE_PATHNAME") };