diff --git a/.github/workflows/deb-packager.yaml b/.github/workflows/deb-packager.yaml index 434961cc..d49ac9ed 100644 --- a/.github/workflows/deb-packager.yaml +++ b/.github/workflows/deb-packager.yaml @@ -29,6 +29,8 @@ jobs: minor: 3 - major: 17 minor: 0 + - major: 18 + minor: 0 platform: - type: amd64 runs_on: ubuntu-latest @@ -81,7 +83,7 @@ jobs: uses: ./.github/actions/install-pgrx with: pg-install-dir: ~/${{ env.PG_INSTALL_DIR }} - pgrx-version: 0.12.9 + pgrx-version: 0.16.1 - name: Build Deb id: debbuild diff --git a/.github/workflows/pgrx_test.yaml b/.github/workflows/pgrx_test.yaml index 287ebc41..dec9249d 100644 --- a/.github/workflows/pgrx_test.yaml +++ b/.github/workflows/pgrx_test.yaml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: pgvector: - - version: 0.8.0 + - version: 0.8.1 pg: - major: 13 minor: 16 @@ -23,6 +23,8 @@ jobs: minor: 3 - major: 17 minor: 0 + - major: 18 + minor: 0 platform: - type: amd64 runs_on: ubuntu-22.04 @@ -62,7 +64,7 @@ jobs: uses: ./.github/actions/install-pgrx with: pg-install-dir: ~/${{ env.PG_INSTALL_DIR }} - pgrx-version: 0.12.9 + pgrx-version: 0.16.1 - name: Run Clippy id: clippy diff --git a/.github/workflows/python_tests.yml b/.github/workflows/python_tests.yml index 253fab59..1ba71a31 100644 --- a/.github/workflows/python_tests.yml +++ b/.github/workflows/python_tests.yml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: pgvector: - - version: 0.8.0 + - version: 0.8.1 pg: - major: 13 minor: 16 @@ -23,7 +23,8 @@ jobs: minor: 3 - major: 17 minor: 0 - + - major: 18 + minor: 0 env: PG_SRC_DIR: pgbuild PG_INSTALL_DIR: postgresql @@ -69,7 +70,7 @@ jobs: uses: ./.github/actions/install-pgrx with: pg-install-dir: ~/${{ env.PG_INSTALL_DIR }} - pgrx-version: 0.12.9 + pgrx-version: 0.16.1 - name: Build and install pgvectorscale run: | diff --git a/README.md b/README.md index 2826a98a..f95cef65 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ You can install pgvectorscale from source and install it in an existing PostgreS cd pgvectorscale/pgvectorscale # install cargo-pgrx with the same version as pgrx cargo install --locked cargo-pgrx --version $(cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "pgrx") | .version') - cargo pgrx init --pg17 pg_config + cargo pgrx init --pg18 pg_config # build and install pgvectorscale cargo pgrx install --release ``` diff --git a/pgvectorscale/Cargo.toml b/pgvectorscale/Cargo.toml index 4476fb55..11837d2d 100644 --- a/pgvectorscale/Cargo.toml +++ b/pgvectorscale/Cargo.toml @@ -11,12 +11,13 @@ name = "pgrx_embed_vectorscale" path = "./src/bin/pgrx_embed.rs" [features] -default = ["pg17"] +default = ["pg18"] pg13 = ["pgrx/pg13", "pgrx-tests/pg13"] pg14 = ["pgrx/pg14", "pgrx-tests/pg14"] pg15 = ["pgrx/pg15", "pgrx-tests/pg15"] pg16 = ["pgrx/pg16", "pgrx-tests/pg16"] pg17 = ["pgrx/pg17", "pgrx-tests/pg17"] +pg18 = ["pgrx/pg18", "pgrx-tests/pg18"] pg_test = [] [lints.rust] @@ -27,7 +28,7 @@ unexpected_cfgs = { level = "allow", check-cfg = [ [dependencies] memoffset = "0.9.0" -pgrx = "=0.12.9" +pgrx = "=0.16.1" rkyv = { version = "0.7.43", features = ["validation"] } simdeez = { version = "1.0.8" } rand = { version = "0.8", features = ["small_rng"] } @@ -38,8 +39,8 @@ once_cell = "1.20.1" lru = "0.14.0" [dev-dependencies] -pgrx-tests = "=0.12.9" -pgrx-pg-config = "=0.12.9" +pgrx-tests = "=0.16.1" +pgrx-pg-config = "=0.16.1" criterion = "0.5.1" tempfile = "3.15.0" diff --git a/pgvectorscale/src/access_method/build.rs b/pgvectorscale/src/access_method/build.rs index 37ca6635..dd25714e 100644 --- a/pgvectorscale/src/access_method/build.rs +++ b/pgvectorscale/src/access_method/build.rs @@ -73,7 +73,7 @@ pub const MAX_DIMENSION: u32 = 16000; pub const MAX_DIMENSION_NO_SBQ: u32 = 2000; #[pg_guard] -pub extern "C" fn ambuild( +pub extern "C-unwind" fn ambuild( heaprel: pg_sys::Relation, indexrel: pg_sys::Relation, index_info: *mut pg_sys::IndexInfo, @@ -146,10 +146,16 @@ pub extern "C" fn ambuild( result.into_pg() } -#[cfg(any(feature = "pg14", feature = "pg15", feature = "pg16", feature = "pg17"))] +#[cfg(any( + feature = "pg14", + feature = "pg15", + feature = "pg16", + feature = "pg17", + feature = "pg18" +))] #[pg_guard] #[allow(clippy::too_many_arguments)] -pub unsafe extern "C" fn aminsert( +pub unsafe extern "C-unwind" fn aminsert( indexrel: pg_sys::Relation, values: *mut pg_sys::Datum, isnull: *mut bool, @@ -164,7 +170,7 @@ pub unsafe extern "C" fn aminsert( #[cfg(feature = "pg13")] #[pg_guard] -pub unsafe extern "C" fn aminsert( +pub unsafe extern "C-unwind" fn aminsert( indexrel: pg_sys::Relation, values: *mut pg_sys::Datum, isnull: *mut bool, @@ -260,7 +266,7 @@ unsafe fn insert_storage( } #[pg_guard] -pub extern "C" fn ambuildempty(_index_relation: pg_sys::Relation) { +pub extern "C-unwind" fn ambuildempty(_index_relation: pg_sys::Relation) { panic!("ambuildempty: not yet implemented") } @@ -450,7 +456,7 @@ fn finalize_index_build( } #[pg_guard] -unsafe extern "C" fn build_callback_bq_train( +unsafe extern "C-unwind" fn build_callback_bq_train( _index: pg_sys::Relation, _ctid: pg_sys::ItemPointer, values: *mut pg_sys::Datum, @@ -466,7 +472,7 @@ unsafe extern "C" fn build_callback_bq_train( } #[pg_guard] -unsafe extern "C" fn build_callback( +unsafe extern "C-unwind" fn build_callback( index: pg_sys::Relation, ctid: pg_sys::ItemPointer, values: *mut pg_sys::Datum, @@ -552,7 +558,7 @@ const BUILD_PHASE_BUILDING_GRAPH: i64 = 1; const BUILD_PHASE_FINALIZING_GRAPH: i64 = 2; #[pg_guard] -pub unsafe extern "C" fn ambuildphasename(phasenum: i64) -> *mut ffi::c_char { +pub unsafe extern "C-unwind" fn ambuildphasename(phasenum: i64) -> *mut ffi::c_char { match phasenum { BUILD_PHASE_TRAINING => "training quantizer".as_pg_cstr(), BUILD_PHASE_BUILDING_GRAPH => "building graph".as_pg_cstr(), @@ -656,10 +662,7 @@ pub mod tests { WITH cte as (select * from {table_name} order by embedding {operator} $1::vector) SELECT count(*) from cte; ", ), - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - test_vec.clone().into_datum(), - )], + &[unsafe { pgrx::datum::DatumWithOid::new(test_vec.clone().into_datum(), pgrx::pg_sys::FLOAT4ARRAYOID) }], )?; //FIXME: should work in all cases @@ -724,10 +727,12 @@ pub mod tests { ) SELECT array_agg(ctid) from cte;" ), - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - test_vec.clone().into_datum(), - )], + &[unsafe { + pgrx::datum::DatumWithOid::new( + test_vec.clone().into_datum(), + pgrx::pg_sys::FLOAT4ARRAYOID, + ) + }], )?; /* Test that the explain plan is generated ok */ @@ -747,10 +752,12 @@ pub mod tests { ) SELECT array_agg(ctid) from cte;" ), - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - test_vec.clone().into_datum(), - )], + &[unsafe { + pgrx::datum::DatumWithOid::new( + test_vec.clone().into_datum(), + pgrx::pg_sys::FLOAT4ARRAYOID, + ) + }], )?; assert!(explain.is_some()); //warning!("explain: {}", explain.unwrap().0); @@ -771,10 +778,12 @@ pub mod tests { ) SELECT array_agg(ctid) from cte;" ), - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - test_vec.clone().into_datum(), - )], + &[unsafe { + pgrx::datum::DatumWithOid::new( + test_vec.clone().into_datum(), + pgrx::pg_sys::FLOAT4ARRAYOID, + ) + }], )? .unwrap(); @@ -800,10 +809,7 @@ pub mod tests { WITH cte as (select * from {table_name} order by embedding {operator} $1::vector) SELECT count(*) from cte; ", ), - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - test_vec.into_datum(), - )], + &[unsafe { pgrx::datum::DatumWithOid::new(test_vec.into_datum(), pgrx::pg_sys::FLOAT4ARRAYOID) }], )?; assert_eq!(cnt.unwrap(), 312); @@ -1066,10 +1072,7 @@ pub mod tests { WITH cte as (select * from {table_name} order by embedding {operator} $1::vector) SELECT count(*) from cte; ", ), - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - test_vec.clone().into_datum(), - )], + &[unsafe { pgrx::datum::DatumWithOid::new(test_vec.clone().into_datum(), pgrx::pg_sys::FLOAT4ARRAYOID) }], )?; assert!(cnt.unwrap() == expected_cnt, "initial count"); @@ -1105,10 +1108,7 @@ pub mod tests { WITH cte as (select * from {table_name} order by embedding {operator} $1::vector) SELECT count(*) from cte; ", ), - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - test_vec.clone().into_datum(), - )], + &[unsafe { pgrx::datum::DatumWithOid::new(test_vec.clone().into_datum(), pgrx::pg_sys::FLOAT4ARRAYOID) }], )?; assert!(cnt.unwrap() == expected_cnt, "after update count"); @@ -1133,10 +1133,7 @@ pub mod tests { SET diskann.query_search_list_size = 2; WITH cte as (select * from {table_name} order by embedding <=> $1::vector) SELECT count(*) from cte; "), - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - test_vec.clone().into_datum(), - )], + &[unsafe { pgrx::datum::DatumWithOid::new(test_vec.clone().into_datum(), pgrx::pg_sys::FLOAT4ARRAYOID) }], )?; if cnt.unwrap() != expected_cnt { @@ -1148,10 +1145,7 @@ pub mod tests { SET diskann.query_search_list_size = 2; WITH cte as (select id from {table_name} EXCEPT (select id from {table_name} order by embedding <=> $1::vector)) SELECT ctid::text || ' ' || id from {table_name} where id in (select id from cte limit 1); "), - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - test_vec.clone().into_datum(), - )], + &[unsafe { pgrx::datum::DatumWithOid::new(test_vec.clone().into_datum(), pgrx::pg_sys::FLOAT4ARRAYOID) }], )?; assert_eq!(cnt.unwrap(), expected_cnt, "id is {}", id.unwrap()); diff --git a/pgvectorscale/src/access_method/cost_estimate.rs b/pgvectorscale/src/access_method/cost_estimate.rs index 7ae8f65c..edc35f76 100644 --- a/pgvectorscale/src/access_method/cost_estimate.rs +++ b/pgvectorscale/src/access_method/cost_estimate.rs @@ -3,7 +3,7 @@ use pgrx::*; /// cost estimate function loosely based on how ivfflat does things #[pg_guard(immutable, parallel_safe)] #[allow(clippy::too_many_arguments)] -pub unsafe extern "C" fn amcostestimate( +pub unsafe extern "C-unwind" fn amcostestimate( root: *mut pg_sys::PlannerInfo, path: *mut pg_sys::IndexPath, loop_count: f64, @@ -14,28 +14,21 @@ pub unsafe extern "C" fn amcostestimate( index_pages: *mut f64, ) { if (*path).indexorderbys.is_null() { - //can't use index without order bys + // Can't use index without order-bys *index_startup_cost = f64::MAX; *index_total_cost = f64::MAX; *index_selectivity = 0.; *index_correlation = 0.; *index_pages = 0.; + #[cfg(any(feature = "pg18"))] + { + // Following in the footsteps of pgvector's PG18+ cost estimate change + // https://github.com/pgvector/pgvector/commit/1291b12090bbb03bd92b92e42a1567ae5b1c96ad + (*path).path.disabled_nodes = 2; + } return; } let path_ref = path.as_ref().expect("path argument is NULL"); - /*let indexinfo = path_ref - .indexinfo - .as_ref() - .expect("indexinfo in path is NULL"); - let index_relation = unsafe { - PgRelation::with_lock( - indexinfo.indexoid, - pg_sys::AccessShareLock as pg_sys::LOCKMODE, - ) - }; - let heap_relation = index_relation - .heap_relation() - .expect("failed to get heap relation for index");*/ let total_index_tuples = (*path_ref.indexinfo).tuples; diff --git a/pgvectorscale/src/access_method/guc.rs b/pgvectorscale/src/access_method/guc.rs index 09f4daec..f5a9440a 100644 --- a/pgvectorscale/src/access_method/guc.rs +++ b/pgvectorscale/src/access_method/guc.rs @@ -1,13 +1,19 @@ -use pgrx::*; +use pgrx::{pg_sys::AsPgCStr, *}; pub static TSV_QUERY_SEARCH_LIST_SIZE: GucSetting = GucSetting::::new(100); pub static TSV_RESORT_SIZE: GucSetting = GucSetting::::new(50); pub fn init() { GucRegistry::define_int_guc( - "diskann.query_search_list_size", - "The size of the search list used in queries", - "Higher value increases recall at the cost of speed.", + unsafe { std::ffi::CStr::from_ptr("diskann.query_search_list_size".as_pg_cstr()) }, + unsafe { + std::ffi::CStr::from_ptr("The size of the search list used in queries".as_pg_cstr()) + }, + unsafe { + std::ffi::CStr::from_ptr( + "Higher value increases recall at the cost of speed.".as_pg_cstr(), + ) + }, &TSV_QUERY_SEARCH_LIST_SIZE, 1, 10000, @@ -16,9 +22,15 @@ pub fn init() { ); GucRegistry::define_int_guc( - "diskann.query_rescore", - "The number of elements rescored (0 to disable rescoring)", - "Rescoring takes the query_rescore number of elements that have the smallest approximate distance, rescores them with the exact distance, returning the closest ones with the exact distance.", + unsafe { std::ffi::CStr::from_ptr("diskann.query_rescore".as_pg_cstr()) }, + unsafe { + std::ffi::CStr::from_ptr( + "The number of elements rescored (0 to disable rescoring)".as_pg_cstr(), + ) + }, + unsafe { + std::ffi::CStr::from_ptr("Rescoring takes the query_rescore number of elements that have the smallest approximate distance, rescores them with the exact distance, returning the closest ones with the exact distance.".as_pg_cstr()) + }, &TSV_RESORT_SIZE, 0, 1000, diff --git a/pgvectorscale/src/access_method/labels/filtering_tests.rs b/pgvectorscale/src/access_method/labels/filtering_tests.rs index e19daa7a..380a248b 100644 --- a/pgvectorscale/src/access_method/labels/filtering_tests.rs +++ b/pgvectorscale/src/access_method/labels/filtering_tests.rs @@ -410,7 +410,7 @@ pub mod tests { assert_eq!(2, res.unwrap(), "Should find 2 documents with label 1"); // Ensure that the index is used. Test seems to be unreliable pre-pg17. - #[cfg(feature = "pg17")] + #[cfg(any(feature = "pg17", feature = "pg18"))] { let res = Spi::explain( "SELECT * FROM test_complex_order_by WHERE labels && '{1}' ORDER BY embedding <=> '[0,0,0]', labels;" @@ -456,15 +456,17 @@ pub mod tests { ORDER BY embedding <=> $1::vector, labels ) SELECT COUNT(*) FROM cte;", - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - vector.clone().into_datum(), - )], + &[unsafe { + pgrx::datum::DatumWithOid::new( + vector.clone().into_datum(), + pgrx::pg_sys::FLOAT4ARRAYOID, + ) + }], )?; assert_eq!(2, res.unwrap(), "Should find 2 documents with label 1"); // Ensure that the index is used. Test seems to be unreliable pre-pg17. - #[cfg(feature = "pg17")] + #[cfg(any(feature = "pg17", feature = "pg18"))] { let res = Spi::explain( "SELECT * FROM test_complex_order_by WHERE labels && '{1}' ORDER BY embedding <=> '[0,0,0]', labels;" @@ -486,10 +488,9 @@ pub mod tests { ORDER BY labels, embedding <=> $1::vector ) SELECT COUNT(*) FROM cte;", - vec![( - pgrx::PgOid::Custom(pgrx::pg_sys::FLOAT4ARRAYOID), - vector.into_datum(), - )], + &[unsafe { + pgrx::datum::DatumWithOid::new(vector.into_datum(), pgrx::pg_sys::FLOAT4ARRAYOID) + }], )?; assert_eq!(2, res.unwrap(), "Should find 2 documents with label 1"); @@ -876,7 +877,7 @@ pub mod tests { // For simplicity, only run this test on pg version 16 and above. Otherwise, we have // to choose different seeds for different pg versions to get the test to pass. - #[cfg(any(feature = "pg16", feature = "pg17"))] + #[cfg(any(feature = "pg16", feature = "pg17", feature = "pg18"))] #[pg_test] pub unsafe fn test_labeled_recall() -> spi::Result<()> { // Ensure clean environment diff --git a/pgvectorscale/src/access_method/mod.rs b/pgvectorscale/src/access_method/mod.rs index 87a2e043..f0740944 100644 --- a/pgvectorscale/src/access_method/mod.rs +++ b/pgvectorscale/src/access_method/mod.rs @@ -270,7 +270,7 @@ $$; ); #[pg_guard] -pub extern "C" fn amvalidate(_opclassoid: pg_sys::Oid) -> bool { +pub extern "C-unwind" fn amvalidate(_opclassoid: pg_sys::Oid) -> bool { true } diff --git a/pgvectorscale/src/access_method/options.rs b/pgvectorscale/src/access_method/options.rs index c427688c..2855fd0f 100644 --- a/pgvectorscale/src/access_method/options.rs +++ b/pgvectorscale/src/access_method/options.rs @@ -99,42 +99,66 @@ static mut RELOPT_KIND_TSV: pg_sys::relopt_kind::Type = 0; // so when displaying the info, they'll show the old options and their values as set when the index was created. #[allow(clippy::unneeded_field_pattern)] // b/c of offset_of!() #[pg_guard] -pub unsafe extern "C" fn amoptions( +pub unsafe extern "C-unwind" fn amoptions( reloptions: pg_sys::Datum, validate: bool, ) -> *mut pg_sys::bytea { // TODO: how to make this const? we can't use offset_of!() macro in const definitions, apparently + + fn make_relopt_parse_elt( + optname: &str, + opttype: pg_sys::relopt_type::Type, + offset: i32, + ) -> pg_sys::relopt_parse_elt { + #[cfg(not(feature = "pg18"))] + { + pg_sys::relopt_parse_elt { + optname: optname.as_pg_cstr(), + opttype: opttype, + offset, + } + } + #[cfg(feature = "pg18")] + { + pg_sys::relopt_parse_elt { + optname: optname.as_pg_cstr(), + opttype: opttype, + offset, + isset_offset: 0, + } + } + } let tab: [pg_sys::relopt_parse_elt; 6] = [ - pg_sys::relopt_parse_elt { - optname: "storage_layout".as_pg_cstr(), - opttype: pg_sys::relopt_type::RELOPT_TYPE_STRING, - offset: offset_of!(TSVIndexOptions, storage_layout_offset) as i32, - }, - pg_sys::relopt_parse_elt { - optname: "num_neighbors".as_pg_cstr(), - opttype: pg_sys::relopt_type::RELOPT_TYPE_INT, - offset: offset_of!(TSVIndexOptions, num_neighbors) as i32, - }, - pg_sys::relopt_parse_elt { - optname: "search_list_size".as_pg_cstr(), - opttype: pg_sys::relopt_type::RELOPT_TYPE_INT, - offset: offset_of!(TSVIndexOptions, search_list_size) as i32, - }, - pg_sys::relopt_parse_elt { - optname: "num_dimensions".as_pg_cstr(), - opttype: pg_sys::relopt_type::RELOPT_TYPE_INT, - offset: offset_of!(TSVIndexOptions, num_dimensions) as i32, - }, - pg_sys::relopt_parse_elt { - optname: "num_bits_per_dimension".as_pg_cstr(), - opttype: pg_sys::relopt_type::RELOPT_TYPE_INT, - offset: offset_of!(TSVIndexOptions, bq_num_bits_per_dimension) as i32, - }, - pg_sys::relopt_parse_elt { - optname: "max_alpha".as_pg_cstr(), - opttype: pg_sys::relopt_type::RELOPT_TYPE_REAL, - offset: offset_of!(TSVIndexOptions, max_alpha) as i32, - }, + make_relopt_parse_elt( + "storage_layout", + pg_sys::relopt_type::RELOPT_TYPE_STRING, + offset_of!(TSVIndexOptions, storage_layout_offset) as i32, + ), + make_relopt_parse_elt( + "num_neighbors", + pg_sys::relopt_type::RELOPT_TYPE_INT, + offset_of!(TSVIndexOptions, num_neighbors) as i32, + ), + make_relopt_parse_elt( + "search_list_size", + pg_sys::relopt_type::RELOPT_TYPE_INT, + offset_of!(TSVIndexOptions, search_list_size) as i32, + ), + make_relopt_parse_elt( + "num_dimensions", + pg_sys::relopt_type::RELOPT_TYPE_INT, + offset_of!(TSVIndexOptions, num_dimensions) as i32, + ), + make_relopt_parse_elt( + "num_bits_per_dimension", + pg_sys::relopt_type::RELOPT_TYPE_INT, + offset_of!(TSVIndexOptions, bq_num_bits_per_dimension) as i32, + ), + make_relopt_parse_elt( + "max_alpha", + pg_sys::relopt_type::RELOPT_TYPE_REAL, + offset_of!(TSVIndexOptions, max_alpha) as i32, + ), ]; build_relopts(reloptions, validate, &tab) @@ -159,7 +183,7 @@ unsafe fn build_relopts( } #[pg_guard] -extern "C" fn validate_storage_layout(value: *const std::os::raw::c_char) { +extern "C-unwind" fn validate_storage_layout(value: *const std::os::raw::c_char) { if value.is_null() { // use a default value return; diff --git a/pgvectorscale/src/access_method/scan.rs b/pgvectorscale/src/access_method/scan.rs index 1fb1267b..a5262e8c 100644 --- a/pgvectorscale/src/access_method/scan.rs +++ b/pgvectorscale/src/access_method/scan.rs @@ -306,7 +306,7 @@ impl TSVResponseIterator { } #[pg_guard] -pub extern "C" fn ambeginscan( +pub extern "C-unwind" fn ambeginscan( index_relation: pg_sys::Relation, nkeys: ::std::os::raw::c_int, norderbys: ::std::os::raw::c_int, @@ -333,7 +333,7 @@ pub extern "C" fn ambeginscan( } #[pg_guard] -pub extern "C" fn amrescan( +pub extern "C-unwind" fn amrescan( scan: pg_sys::IndexScanDesc, keys: pg_sys::ScanKey, nkeys: ::std::os::raw::c_int, @@ -367,7 +367,7 @@ pub extern "C" fn amrescan( } #[pg_guard] -pub extern "C" fn amgettuple( +pub extern "C-unwind" fn amgettuple( scan: pg_sys::IndexScanDesc, _direction: pg_sys::ScanDirection::Type, ) -> bool { @@ -436,7 +436,7 @@ fn get_tuple( } #[pg_guard] -pub extern "C" fn amendscan(scan: pg_sys::IndexScanDesc) { +pub extern "C-unwind" fn amendscan(scan: pg_sys::IndexScanDesc) { let min_level = unsafe { let l = pg_sys::log_min_messages; let c = pg_sys::client_min_messages; diff --git a/pgvectorscale/src/access_method/upgrade_test.rs b/pgvectorscale/src/access_method/upgrade_test.rs index d2854e5e..057008b0 100644 --- a/pgvectorscale/src/access_method/upgrade_test.rs +++ b/pgvectorscale/src/access_method/upgrade_test.rs @@ -30,11 +30,17 @@ pub mod tests { amname: &str, ) { if cfg!(feature = "pg17") - && semver::Version::parse(version).unwrap() < semver::Version::parse("0.4.0").unwrap() + || cfg!(feature = "pg18") + && semver::Version::parse(version).unwrap() + < semver::Version::parse("0.4.0").unwrap() { // PG17 was not supported before 0.4.0 return; } + if cfg!(feature = "pg18") { + // No release for PG18 yet + return; + } pgrx_tests::run_test( "test_delete_mock_fn", None, diff --git a/pgvectorscale/src/access_method/vacuum.rs b/pgvectorscale/src/access_method/vacuum.rs index 283eece3..1acf9f60 100644 --- a/pgvectorscale/src/access_method/vacuum.rs +++ b/pgvectorscale/src/access_method/vacuum.rs @@ -21,7 +21,7 @@ use crate::{ use super::storage::{NodeVacuum, Storage, StorageType}; #[pg_guard] -pub extern "C" fn ambulkdelete( +pub extern "C-unwind" fn ambulkdelete( info: *mut pg_sys::IndexVacuumInfo, stats: *mut pg_sys::IndexBulkDeleteResult, callback: pg_sys::IndexBulkDeleteCallback, @@ -91,7 +91,14 @@ fn bulk_delete_for_storage( } let mut modified = false; - unsafe { pg_sys::vacuum_delay_point() }; + #[cfg(feature = "pg18")] + unsafe { + pg_sys::vacuum_delay_point(false) + }; + #[cfg(not(feature = "pg18"))] + unsafe { + pg_sys::vacuum_delay_point() + }; let max_offset = unsafe { PageGetMaxOffsetNumber(*page) }; for offset_number in FirstOffsetNumber..(max_offset + 1) as _ { @@ -129,7 +136,7 @@ fn bulk_delete_for_storage( } #[pg_guard] -pub extern "C" fn amvacuumcleanup( +pub extern "C-unwind" fn amvacuumcleanup( vinfo: *mut pg_sys::IndexVacuumInfo, stats: *mut pg_sys::IndexBulkDeleteResult, ) -> *mut pg_sys::IndexBulkDeleteResult { diff --git a/pgvectorscale/src/lib.rs b/pgvectorscale/src/lib.rs index 27af131b..a8e96f55 100644 --- a/pgvectorscale/src/lib.rs +++ b/pgvectorscale/src/lib.rs @@ -8,7 +8,7 @@ mod util; #[allow(non_snake_case)] #[pg_guard] -pub unsafe extern "C" fn _PG_init() { +pub unsafe extern "C-unwind" fn _PG_init() { access_method::distance::init(); access_method::options::init(); access_method::guc::init(); @@ -16,7 +16,7 @@ pub unsafe extern "C" fn _PG_init() { #[allow(non_snake_case)] #[pg_guard] -pub extern "C" fn _PG_fini() { +pub extern "C-unwind" fn _PG_fini() { // noop } diff --git a/pgvectorscale/src/util/ports.rs b/pgvectorscale/src/util/ports.rs index bcbf1b07..d685b00c 100644 --- a/pgvectorscale/src/util/ports.rs +++ b/pgvectorscale/src/util/ports.rs @@ -6,7 +6,7 @@ use std::os::raw::c_int; use memoffset::*; -#[cfg(any(feature = "pg15", feature = "pg16", feature = "pg17"))] +#[cfg(any(feature = "pg15", feature = "pg16", feature = "pg17", feature = "pg18"))] use pg_sys::pgstat_assoc_relation; use pgrx::pg_sys::{Datum, ItemId, OffsetNumber, Pointer, TupleTableSlot}; @@ -132,13 +132,13 @@ pub unsafe fn pgstat_count_index_scan(index_relation: pg_sys::Relation, indexrel { (*tmp).t_counts.t_numscans += 1; } - #[cfg(any(feature = "pg16", feature = "pg17"))] + #[cfg(any(feature = "pg16", feature = "pg17", feature = "pg18"))] { (*tmp).counts.numscans += 1; } } - #[cfg(any(feature = "pg15", feature = "pg16", feature = "pg17"))] + #[cfg(any(feature = "pg15", feature = "pg16", feature = "pg17", feature = "pg18"))] if indexrel.pgstat_info.is_null() && indexrel.pgstat_enabled { pgstat_assoc_relation(index_relation); assert!(!indexrel.pgstat_info.is_null()); @@ -147,7 +147,7 @@ pub unsafe fn pgstat_count_index_scan(index_relation: pg_sys::Relation, indexrel { (*tmp).t_counts.t_numscans += 1; } - #[cfg(any(feature = "pg16", feature = "pg17"))] + #[cfg(any(feature = "pg16", feature = "pg17", feature = "pg18"))] { (*tmp).counts.numscans += 1; } @@ -158,7 +158,7 @@ pub unsafe fn pgstat_count_index_scan(index_relation: pg_sys::Relation, indexrel /// operations. The lock is managed by Postgres, so no RAII/Drop implementation is needed. #[allow(non_snake_case)] pub fn acquire_index_lock(index: &PgRelation) { - let oid = index.oid().as_u32(); + let oid = u32::from(index.oid()); unsafe { // Use PostgreSQL's transaction-level advisory lock with relation OID as key