/*
Portions Copyright 2019-2021 ZomboDB, LLC.
Portions Copyright 2021-2022 Technology Concepts & Design, Inc. <support@tcdi.com>
All rights reserved.
Use of this source code is governed by the MIT license that can be found in the LICENSE file.
*/
/*!
[Aggregate](https://www.postgresql.org/docs/current/xaggr.html) support.
Most items of this trait map directly to a [`CREATE AGGREGATE`](https://www.postgresql.org/docs/current/sql-createaggregate.html)
functionality.
Aggregates are created by implementing [`Aggregate`] for a type and decorating the implementation with
[`#[pg_aggregate]`](pgx_macros::pg_aggregate).
Definition of the aggregate is done via settings in the type's [`Aggregate`] implementation. While
the trait itself has several items, only a few are required, the macro will fill in the others with unused stubs.
# Minimal Example
```rust
use pgx::prelude::*;
use serde::{Serialize, Deserialize};
// pgx::pg_module_magic!(); // Uncomment this outside of docs!
#[derive(Copy, Clone, Default, PostgresType, Serialize, Deserialize)]
pub struct DemoSum {
count: i32,
}
#[pg_aggregate]
impl Aggregate for DemoSum {
const INITIAL_CONDITION: Option<&'static str> = Some(r#"{ "count": 0 }"#);
type Args = i32;
fn state(
mut current: Self::State,
arg: Self::Args,
_fcinfo: pg_sys::FunctionCallInfo
) -> Self::State {
current.count += arg;
current
}
}
```
This creates SQL like so:
```sql
-- src/lib.rs:11
-- aggregate::DemoSum
CREATE AGGREGATE DemoSum (
integer /* i32 */
)
(
SFUNC = "demo_sum_state", /* aggregate::DemoSum::state */
STYPE = DemoSum, /* aggregate::DemoSum */
INITCOND = '{ "count": 0 }' /* aggregate::DemoSum::INITIAL_CONDITION */
);
```
Example of usage:
```sql
aggregate=# CREATE TABLE demo_table (value INTEGER);
CREATE TABLE
aggregate=# INSERT INTO demo_table (value) VALUES (1), (2), (3);
INSERT 0 3
aggregate=# SELECT DemoSum(value) FROM demo_table;
demosum
-------------
{"count":6}
(1 row)
```
## Multiple Arguments
Sometimes aggregates need to handle multiple arguments. The
[`Aggregate::Args`](Aggregate::Args) associated type can be a tuple:
```rust
# use pgx::prelude::*;
# use serde::{Serialize, Deserialize};
#
# #[derive(Copy, Clone, Default, PostgresType, Serialize, Deserialize)]
# pub struct DemoSum {
# count: i32,
# }
#
#[pg_aggregate]
impl Aggregate for DemoSum {
const INITIAL_CONDITION: Option<&'static str> = Some(r#"{ "count": 0 }"#);
type Args = (i32, i32);
fn state(
mut current: Self::State,
(arg1, arg2): Self::Args,
_fcinfo: pg_sys::FunctionCallInfo
) -> Self::State {
current.count += arg1;
current.count += arg2;
current
}
}
```
Creates:
```sql
-- src/lib.rs:11
-- aggregate::DemoSum
CREATE AGGREGATE DemoSum (
integer, /* i32 */
integer /* i32 */
)
(
SFUNC = "demo_sum_state", /* aggregate::DemoSum::state */
STYPE = DemoSum, /* aggregate::DemoSum */
INITCOND = '{ "count": 0 }' /* aggregate::DemoSum::INITIAL_CONDITION */
);
```
## Named Arguments
The [`name!(ident, Type)`][macro@crate::name] macro can be used to set the name of an argument:
```rust
# use pgx::prelude::*;
# use serde::{Serialize, Deserialize};
#
# #[derive(Copy, Clone, Default, PostgresType, Serialize, Deserialize)]
# pub struct DemoSum {
# count: i32,
# }
#
# #[pg_aggregate]
impl Aggregate for DemoSum {
const INITIAL_CONDITION: Option<&'static str> = Some(r#"{ "count": 0 }"#);
type Args = (
i32,
name!(extra, i32),
);
fn state(
mut current: Self::State,
(arg1, extra): Self::Args,
_fcinfo: pg_sys::FunctionCallInfo
) -> Self::State {
todo!()
}
}
```
Creates:
```sql
-- src/lib.rs:11
-- aggregate::DemoSum
CREATE AGGREGATE DemoSum (
integer, /* i32 */
"extra" integer /* i32 */
)
(
SFUNC = "demo_sum_state", /* aggregate::DemoSum::state */
STYPE = DemoSum, /* aggregate::DemoSum */
INITCOND = '{ "count": 0 }' /* aggregate::DemoSum::INITIAL_CONDITION */
);
```
## Function attributes
Functions inside the `impl` may use the [`#[pgx]`](macro@crate::pgx) attribute. It
accepts the same parameters as [`#[pg_extern]`][macro@pgx-macros::pg_extern].
```rust
# use pgx::prelude::*;
# use serde::{Serialize, Deserialize};
#
# #[derive(Copy, Clone, Default, PostgresType, Serialize, Deserialize)]
# pub struct DemoSum {
# count: i32,
# }
#
#[pg_aggregate]
impl Aggregate for DemoSum {
const INITIAL_CONDITION: Option<&'static str> = Some(r#"{ "count": 0 }"#);
type Args = i32;
#[pgx(parallel_safe, immutable)]
fn state(
mut current: Self::State,
arg: Self::Args,
_fcinfo: pg_sys::FunctionCallInfo
) -> Self::State {
todo!()
}
}
```
Generates:
```sql
-- src/lib.rs:11
-- aggregate::demo_sum_state
CREATE FUNCTION "demo_sum_state"(
"this" DemoSum, /* aggregate::DemoSum */
"arg_one" integer /* i32 */
) RETURNS DemoSum /* aggregate::DemoSum */
PARALLEL SAFE IMMUTABLE STRICT
LANGUAGE c /* Rust */
AS 'MODULE_PATHNAME', 'demo_sum_state_wrapper';
```
## Non-`Self` State
Sometimes it's useful to have aggregates share state, or use some other type for state.
```rust
# use pgx::prelude::*;
# use serde::{Serialize, Deserialize};
#
#[derive(Copy, Clone, Default, PostgresType, Serialize, Deserialize)]
pub struct DemoSumState {
count: i32,
}
pub struct DemoSum;
#[pg_aggregate]
impl Aggregate for DemoSum {
const INITIAL_CONDITION: Option<&'static str> = Some(r#"{ "count": 0 }"#);
type Args = i32;
type State = DemoSumState;
fn state(
mut current: Self::State,
arg: Self::Args,
_fcinfo: pg_sys::FunctionCallInfo
) -> Self::State {
todo!()
}
}
```
Creates:
```sql
-- src/lib.rs:13
-- aggregate::demo_sum_state
CREATE FUNCTION "demo_sum_state"(
"this" DemoSumState, /* aggregate::DemoSumState */
"arg_one" integer /* i32 */
) RETURNS DemoSumState /* aggregate::DemoSumState */
STRICT
LANGUAGE c /* Rust */
AS 'MODULE_PATHNAME', 'demo_sum_state_wrapper';
-- src/lib.rs:13
-- aggregate::DemoSum
CREATE AGGREGATE DemoSum (
integer /* i32 */
)
(
SFUNC = "demo_sum_state", /* aggregate::DemoSum::state */
STYPE = DemoSumState, /* aggregate::DemoSumState */
INITCOND = '{ "count": 0 }' /* aggregate::DemoSum::INITIAL_CONDITION */
);
```
*/
use crate error;
use crate PgMemoryContexts;
use crate;
use crate PgBox;
pub use ;
/// Aggregate implementation trait.
///
/// When decorated with [`#[pgx_macros::pg_aggregate]`](pgx_macros::pg_aggregate), enables the
/// generation of [`CREATE AGGREGATE`](https://www.postgresql.org/docs/current/sql-createaggregate.html)
/// SQL.
///
/// The [`#[pgx_macros::pg_aggregate]`](pgx_macros::pg_aggregate) will automatically fill fields
/// marked optional with stubs.