diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 814306a..403e54c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - postgres: [ 13, 14, 15, 16, 17 ] + postgres: [ 14, 15, 16, 17 ] env: PG_MAJOR: ${{ matrix.postgres }} @@ -91,7 +91,7 @@ jobs: - name: Install and configure pgrx run: | cargo install --locked cargo-pgrx@0.12.6 - cargo pgrx init --pg${{ env.PG_MAJOR }} /usr/lib/postgresql/${{ env.PG_MAJOR }}/bin/pg_config + cargo pgrx init --pg${{ env.PG_MAJOR }} $(which pg_config) - name: Install cargo-llvm-cov for coverage report run: cargo install --locked cargo-llvm-cov@0.6.12 @@ -104,9 +104,9 @@ jobs: - name: Run tests run: | # Set up permissions so that the current user below can create extensions - sudo chmod a+rwx $(/usr/lib/postgresql/${{ env.PG_MAJOR }}/bin/pg_config --pkglibdir) \ - $(/usr/lib/postgresql/${{ env.PG_MAJOR }}/bin/pg_config --sharedir)/extension \ - /var/run/postgresql/ + sudo chmod a+rwx $(pg_config --pkglibdir) \ + $(pg_config --sharedir)/extension \ + /var/run/postgresql/ # pgrx tests with runas argument ignores environment variables, so # we read env vars from .env file in tests (https://github.com/pgcentralfoundation/pgrx/pull/1674) diff --git a/Cargo.toml b/Cargo.toml index b8c3557..09b056f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ pg17 = ["pgrx/pg17", "pgrx-tests/pg17"] pg16 = ["pgrx/pg16", "pgrx-tests/pg16"] pg15 = ["pgrx/pg15", "pgrx-tests/pg15"] pg14 = ["pgrx/pg14", "pgrx-tests/pg14"] -pg13 = ["pgrx/pg13", "pgrx-tests/pg13"] pg_test = [] [dependencies] diff --git a/README.md b/README.md index b1ac7b8..7c679a1 100644 --- a/README.md +++ b/README.md @@ -238,7 +238,6 @@ There is currently only one GUC parameter to enable/disable the `pg_parquet`: `pg_parquet` supports the following PostgreSQL versions: | PostgreSQL Major Version | Supported | |--------------------------|-----------| -| 13 | ✅ | | 14 | ✅ | | 15 | ✅ | | 16 | ✅ | diff --git a/src/parquet_copy_hook/copy_from.rs b/src/parquet_copy_hook/copy_from.rs index 15a077f..bf3a878 100644 --- a/src/parquet_copy_hook/copy_from.rs +++ b/src/parquet_copy_hook/copy_from.rs @@ -5,8 +5,8 @@ use pgrx::{ pg_sys::{ addNSItemToQuery, assign_expr_collations, canonicalize_qual, check_enable_rls, coerce_to_boolean, eval_const_expressions, make_ands_implicit, transformExpr, AsPgCStr, - CheckEnableRlsResult, CopyFrom, CopyStmt, EndCopyFrom, InvalidOid, Node, Oid, - ParseExprKind, ParseNamespaceItem, ParseState, PlannedStmt, QueryEnvironment, + BeginCopyFrom, CheckEnableRlsResult, CopyFrom, CopyStmt, EndCopyFrom, InvalidOid, Node, + Oid, ParseExprKind, ParseNamespaceItem, ParseState, PlannedStmt, QueryEnvironment, }, void_mut_ptr, PgBox, PgLogLevel, PgRelation, PgSqlErrorCode, }; @@ -19,12 +19,9 @@ use crate::{ }, }; -use super::{ - copy_utils::{ - copy_stmt_attribute_list, copy_stmt_create_namespace_item, copy_stmt_create_parse_state, - create_filtered_tupledesc_for_relation, - }, - pg_compat::BeginCopyFrom, +use super::copy_utils::{ + copy_stmt_attribute_list, copy_stmt_create_namespace_item, copy_stmt_create_parse_state, + create_filtered_tupledesc_for_relation, }; // stack to store parquet reader contexts for COPY FROM. @@ -146,6 +143,8 @@ pub(crate) fn execute_copy_from( p_state.as_ptr(), relation.as_ptr(), where_clause, + std::ptr::null(), + false, Some(copy_parquet_data_to_buffer), attribute_list, copy_options.as_ptr(), diff --git a/src/parquet_copy_hook/hook.rs b/src/parquet_copy_hook/hook.rs index e5f6da9..f533a56 100644 --- a/src/parquet_copy_hook/hook.rs +++ b/src/parquet_copy_hook/hook.rs @@ -109,7 +109,6 @@ fn process_copy_from_parquet( .execute() } -#[cfg(any(feature = "pg14", feature = "pg15", feature = "pg16", feature = "pg17"))] #[pg_guard] #[allow(clippy::too_many_arguments)] extern "C" fn parquet_copy_hook( @@ -172,64 +171,3 @@ extern "C" fn parquet_copy_hook( } } } - -#[cfg(feature = "pg13")] -#[pg_guard] -#[allow(clippy::too_many_arguments)] -extern "C" fn parquet_copy_hook( - p_stmt: *mut PlannedStmt, - query_string: *const c_char, - context: u32, - params: *mut ParamListInfoData, - query_env: *mut QueryEnvironment, - dest: *mut DestReceiver, - completion_tag: *mut QueryCompletion, -) { - let p_stmt = unsafe { PgBox::from_pg(p_stmt) }; - let query_string = unsafe { CStr::from_ptr(query_string) }; - let params = unsafe { PgBox::from_pg(params) }; - let query_env = unsafe { PgBox::from_pg(query_env) }; - let mut completion_tag = unsafe { PgBox::from_pg(completion_tag) }; - - if ENABLE_PARQUET_COPY_HOOK.get() && is_copy_to_parquet_stmt(&p_stmt) { - let nprocessed = process_copy_to_parquet(&p_stmt, query_string, ¶ms, &query_env); - - if !completion_tag.is_null() { - completion_tag.nprocessed = nprocessed; - completion_tag.commandTag = CommandTag::CMDTAG_COPY; - } - return; - } else if ENABLE_PARQUET_COPY_HOOK.get() && is_copy_from_parquet_stmt(&p_stmt) { - let nprocessed = process_copy_from_parquet(&p_stmt, query_string, &query_env); - - if !completion_tag.is_null() { - completion_tag.nprocessed = nprocessed; - completion_tag.commandTag = CommandTag::CMDTAG_COPY; - } - return; - } - - unsafe { - if let Some(prev_hook) = PREV_PROCESS_UTILITY_HOOK { - prev_hook( - p_stmt.into_pg(), - query_string.as_ptr(), - context, - params.into_pg(), - query_env.into_pg(), - dest, - completion_tag.into_pg(), - ) - } else { - standard_ProcessUtility( - p_stmt.into_pg(), - query_string.as_ptr(), - context, - params.into_pg(), - query_env.into_pg(), - dest, - completion_tag.into_pg(), - ) - } - } -} diff --git a/src/parquet_copy_hook/pg_compat.rs b/src/parquet_copy_hook/pg_compat.rs index d9fc8dd..1ff95eb 100644 --- a/src/parquet_copy_hook/pg_compat.rs +++ b/src/parquet_copy_hook/pg_compat.rs @@ -1,23 +1,13 @@ use std::ffi::{c_char, CStr}; -use pgrx::{ - datum::TimeWithTimeZone, - direct_function_call, - pg_sys::{ - copy_data_source_cb, AsPgCStr, List, Node, ParseState, QueryEnvironment, RawStmt, Relation, - }, - IntoDatum, -}; - -#[cfg(any(feature = "pg14", feature = "pg15", feature = "pg16", feature = "pg17"))] -use pgrx::AnyNumeric; +use pgrx::pg_sys::{AsPgCStr, List, Node, QueryEnvironment, RawStmt}; pub(crate) fn pg_analyze_and_rewrite( raw_stmt: *mut RawStmt, query_string: *const c_char, query_env: *mut QueryEnvironment, ) -> *mut List { - #[cfg(any(feature = "pg13", feature = "pg14"))] + #[cfg(feature = "pg14")] unsafe { pgrx::pg_sys::pg_analyze_and_rewrite( raw_stmt, @@ -42,7 +32,7 @@ pub(crate) fn pg_analyze_and_rewrite( #[allow(non_snake_case)] pub(crate) fn strVal(val: *mut Node) -> String { - #[cfg(any(feature = "pg13", feature = "pg14"))] + #[cfg(feature = "pg14")] unsafe { let val = (*(val as *mut pgrx::pg_sys::Value)).val.str_; @@ -63,88 +53,9 @@ pub(crate) fn strVal(val: *mut Node) -> String { } } -#[cfg(feature = "pg13")] -#[allow(non_snake_case)] -pub(crate) fn BeginCopyFrom( - pstate: *mut ParseState, - relation: Relation, - _where_clause: *mut Node, - data_source_cb: copy_data_source_cb, - attribute_list: *mut List, - copy_options: *mut List, -) -> *mut pgrx::pg_sys::CopyStateData { - unsafe { - pgrx::pg_sys::BeginCopyFrom( - pstate, - relation, - std::ptr::null(), - false, - data_source_cb, - attribute_list, - copy_options, - ) - } -} - -#[cfg(any(feature = "pg14", feature = "pg15", feature = "pg16", feature = "pg17"))] -#[allow(non_snake_case)] -pub(crate) fn BeginCopyFrom( - pstate: *mut ParseState, - relation: Relation, - _where_clause: *mut Node, - data_source_cb: copy_data_source_cb, - attribute_list: *mut List, - copy_options: *mut List, -) -> *mut pgrx::pg_sys::CopyFromStateData { - unsafe { - pgrx::pg_sys::BeginCopyFrom( - pstate, - relation, - _where_clause, - std::ptr::null(), - false, - data_source_cb, - attribute_list, - copy_options, - ) - } -} - -pub(crate) fn extract_timezone_from_timetz(timetz: TimeWithTimeZone) -> f64 { - #[cfg(feature = "pg13")] - { - let timezone_as_secs: f64 = unsafe { - direct_function_call( - pgrx::pg_sys::timetz_part, - &["timezone".into_datum(), timetz.into_datum()], - ) - } - .expect("cannot extract timezone from timetz"); - - timezone_as_secs - } - - #[cfg(any(feature = "pg14", feature = "pg15", feature = "pg16", feature = "pg17"))] - { - let timezone_as_secs: AnyNumeric = unsafe { - direct_function_call( - pgrx::pg_sys::extract_timetz, - &["timezone".into_datum(), timetz.into_datum()], - ) - } - .expect("cannot extract timezone from timetz"); - - let timezone_as_secs: f64 = timezone_as_secs - .try_into() - .unwrap_or_else(|e| panic!("{}", e)); - - timezone_as_secs - } -} - #[allow(non_snake_case)] pub(crate) fn MarkGUCPrefixReserved(guc_prefix: &str) { - #[cfg(any(feature = "pg13", feature = "pg14"))] + #[cfg(feature = "pg14")] unsafe { pgrx::pg_sys::EmitWarningsOnPlaceholders(guc_prefix.as_pg_cstr()) } diff --git a/src/type_compat/pg_arrow_type_conversions.rs b/src/type_compat/pg_arrow_type_conversions.rs index 02752c1..9d9375f 100644 --- a/src/type_compat/pg_arrow_type_conversions.rs +++ b/src/type_compat/pg_arrow_type_conversions.rs @@ -5,8 +5,6 @@ use pgrx::{ direct_function_call, pg_sys, AnyNumeric, IntoDatum, }; -use crate::parquet_copy_hook::pg_compat::extract_timezone_from_timetz; - pub(crate) const MAX_DECIMAL_PRECISION: usize = 38; pub(crate) fn date_to_i32(date: Date) -> i32 { @@ -130,7 +128,17 @@ pub(crate) fn i64_to_time(i64_time: i64) -> Time { } pub(crate) fn timetz_to_i64(timetz: TimeWithTimeZone) -> i64 { - let timezone_as_secs = extract_timezone_from_timetz(timetz); + let timezone_as_secs: AnyNumeric = unsafe { + direct_function_call( + pg_sys::extract_timetz, + &["timezone".into_datum(), timetz.into_datum()], + ) + } + .expect("cannot extract timezone from timetz"); + + let timezone_as_secs: f64 = timezone_as_secs + .try_into() + .unwrap_or_else(|e| panic!("{}", e)); let timezone_as_interval = Interval::from_seconds(timezone_as_secs); let adjusted_timetz: TimeWithTimeZone = unsafe {