// Copyright (c) 2023-2025 ParadeDB, Inc. // // This file is part of ParadeDB - Postgres for Search and Analytics // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #![recursion_limit = "512"] #![allow(unexpected_cfgs)] mod api; mod bootstrap; mod index; mod postgres; mod query; mod schema; pub mod gucs; use self::postgres::customscan; use pgrx::*; /// A hardcoded value when we can't figure out a good selectivity value const UNKNOWN_SELECTIVITY: f64 = 0.00001; /// A hardcoded value for parameterized plan queries const PARAMETERIZED_SELECTIVITY: f64 = 0.10; /// An arbitrary value for what it costs for a plan with one of our operators (@@@) to do whatever /// initial work it needs to do (open tantivy index, start the query, etc). The value is largely /// meaningless but we should be honest that do _something_. const DEFAULT_STARTUP_COST: f64 = 10.0; pgrx::pg_module_magic!(); extension_sql!( "GRANT ALL ON SCHEMA paradedb TO PUBLIC;", name = "paradedb_grant_all", finalize ); use once_cell::sync::Lazy; use rand::Rng; use std::sync::Mutex; /// For debugging #[allow(dead_code)] pub static LOG_MUTEX: Lazy> = Lazy::new(|| Mutex::new(())); pub fn log_message(message: &str) { let _lock = LOG_MUTEX.lock().unwrap(); eprintln!("{}", message); } /// Convenience method for [`pgrx::pg_sys::MyDatabaseId`] #[allow(non_snake_case)] #[inline(always)] pub fn MyDatabaseId() -> u32 { unsafe { // SAFETY: this static is set by Postgres when the backend first connects and is // never changed afterwards. As such, it'll always be set whenever this code runs pg_sys::MyDatabaseId.as_u32() } } /// Initializes option parsing #[allow(clippy::missing_safety_doc)] #[allow(non_snake_case)] #[pg_guard] pub unsafe extern "C" fn _PG_init() { // initialize environment logging (to stderr) for dependencies that do logging // we can't implement our own logger that sends messages to Postgres `ereport()` because // of threading concerns std::env::set_var("RUST_LOG", "warn"); std::env::set_var("RUST_LOG_STYLE", "never"); env_logger::init(); if cfg!(not(feature = "pg17")) && !pg_sys::process_shared_preload_libraries_in_progress { error!("pg_search must be loaded via shared_preload_libraries. Add 'pg_search' to shared_preload_libraries in postgresql.conf and restart Postgres."); } postgres::options::init(); gucs::init(); #[cfg(not(feature = "pg17"))] postgres::fake_aminsertcleanup::register(); #[allow(static_mut_refs)] #[allow(deprecated)] customscan::register_rel_pathlist(customscan::pdbscan::PdbScan); } #[pg_extern] fn random_words(num_words: i32) -> String { let mut rng = rand::thread_rng(); let letters = "abcdefghijklmnopqrstuvwxyz"; let mut result = String::new(); for _ in 0..num_words { // Choose a random word length between 3 and 7. let word_length = rng.gen_range(3..=7); let mut word = String::new(); for _ in 0..word_length { // Pick a random letter from the letters string. let random_index = rng.gen_range(0..letters.len()); // Safe to use .unwrap() because the index is guaranteed to be valid. let letter = letters.chars().nth(random_index).unwrap(); word.push(letter); } result.push_str(&word); result.push(' '); } result.trim_end().to_string() } /// This module is required by `cargo pgrx test` invocations. /// It must be visible at the root of your extension crate. #[cfg(test)] pub mod pg_test { pub fn setup(_options: Vec<&str>) { // perform one-off initialization when the pg_test framework starts } pub fn postgresql_conf_options() -> Vec<&'static str> { // return any postgresql.conf settings that are required for your tests let mut options: Vec<&'static str> = Vec::new(); if cfg!(not(feature = "pg17")) { options.push("shared_preload_libraries='pg_search'"); } options } }