1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//! User-defined aggregate catalog query.
//!
//! One row per ordinary aggregate (`pg_aggregate` joined to its wrapper
//! `pg_proc` entry via `aggfnoid`). The assembler (`catalog::assemble`)
//! skips ordered-set / hypothetical-set aggregates (`aggkind <> 'n'`) and any
//! aggregate whose state or final function is written in a language pgevolve
//! does not manage (anything other than `sql` / `plpgsql`), recording those in
//! [`crate::catalog::DriftReport::unmanaged_aggregates`].
//!
//! Argument types are resolved by re-parsing the
//! `pg_get_function_identity_arguments` signature through `pg_query` (the same
//! AST → [`crate::ir::column_type::ColumnType`] path the source-side
//! `CREATE AGGREGATE` parser uses), so the catalog-side and source-side
//! `arg_types` compare equal. The state type arrives as a `format_type` string
//! and is parsed via `ColumnType::parse_from_pg_type_string`.
/// SQL query that fetches all user-defined aggregates in the managed schemas.
///
/// Schema-filtered via `$1::text[]` (the same param group as
/// [`super::functions::SELECT_FUNCTIONS`]). Extension-owned aggregates
/// (`pg_depend.deptype = 'e'`) are excluded at the SQL layer.
pub const SELECT_AGGREGATES: &str = "\
SELECT \
pn.nspname AS schema_name, \
p.proname AS name, \
pg_get_function_identity_arguments(p.oid) AS arg_signature, \
a.aggkind::text AS aggkind, \
sfn.nspname AS sfunc_schema, \
sf.proname AS sfunc_name, \
sl.lanname AS sfunc_lang, \
pg_catalog.format_type(a.aggtranstype, NULL) AS state_type, \
ffn.nspname AS finalfunc_schema, \
ff.proname AS finalfunc_name, \
fl.lanname AS finalfunc_lang, \
a.agginitval AS initcond, \
owner_role.rolname AS owner, \
obj_description(p.oid, 'pg_proc') AS comment \
FROM pg_catalog.pg_aggregate a \
JOIN pg_catalog.pg_proc p ON p.oid = a.aggfnoid \
JOIN pg_catalog.pg_namespace pn ON pn.oid = p.pronamespace \
JOIN pg_catalog.pg_proc sf ON sf.oid = a.aggtransfn \
JOIN pg_catalog.pg_namespace sfn ON sfn.oid = sf.pronamespace \
JOIN pg_catalog.pg_language sl ON sl.oid = sf.prolang \
JOIN pg_catalog.pg_authid owner_role ON owner_role.oid = p.proowner \
LEFT JOIN pg_catalog.pg_proc ff ON ff.oid = NULLIF(a.aggfinalfn, 0) \
LEFT JOIN pg_catalog.pg_namespace ffn ON ffn.oid = ff.pronamespace \
LEFT JOIN pg_catalog.pg_language fl ON fl.oid = ff.prolang \
WHERE pn.nspname = ANY($1::text[]) \
AND NOT EXISTS ( \
SELECT 1 \
FROM pg_catalog.pg_depend dep \
WHERE dep.classid = 'pg_catalog.pg_proc'::regclass \
AND dep.objid = p.oid \
AND dep.deptype = 'e' \
) \
ORDER BY pn.nspname, p.proname, pg_get_function_identity_arguments(p.oid)";