Skip to content

Commit 0146ba9

Browse files
chore(schema_cache): improve functions type and query
1 parent 864b374 commit 0146ba9

File tree

1 file changed

+103
-36
lines changed

1 file changed

+103
-36
lines changed

crates/pg_schema_cache/src/functions.rs

Lines changed: 103 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ use sqlx::PgPool;
44

55
use crate::schema_cache::SchemaCacheItem;
66

7+
/// `Behavior` describes the characteristics of the function. Is it deterministic? Does it changed due to side effects, and if so, when?
78
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
89
pub enum Behavior {
10+
/// The function is a pure function (same input leads to same output.)
911
Immutable,
12+
13+
/// The results of the function do not change within a scan.
1014
Stable,
15+
16+
/// The results of the function might change at any time.
1117
#[default]
1218
Volatile,
1319
}
@@ -28,9 +34,14 @@ impl From<Option<String>> for Behavior {
2834

2935
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
3036
pub struct FunctionArg {
37+
/// `in`, `out`, or `inout`.
3138
pub mode: String,
39+
3240
pub name: String,
41+
42+
/// Refers to the argument type's ID in the `pg_type` table.
3343
pub type_id: i64,
44+
3445
pub has_default: Option<bool>,
3546
}
3647

@@ -49,20 +60,49 @@ impl From<Option<JsonValue>> for FunctionArgs {
4960

5061
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
5162
pub struct Function {
52-
pub id: Option<i64>,
53-
pub schema: Option<String>,
54-
pub name: Option<String>,
55-
pub language: Option<String>,
63+
/// The Id (`oid`).
64+
pub id: i64,
65+
66+
/// The name of the schema the function belongs to.
67+
pub schema: String,
68+
69+
/// The name of the function.
70+
pub name: String,
71+
72+
/// e.g. `plpgsql/sql` or `internal`.
73+
pub language: String,
74+
75+
/// The body of the function – the `declare [..] begin [..] end [..]` block.` Not set for internal functions.
76+
pub body: Option<String>,
77+
78+
/// The full definition of the function. Includes the full `CREATE OR REPLACE...` shenanigans. Not set for internal functions.
5679
pub definition: Option<String>,
57-
pub complete_statement: Option<String>,
80+
81+
/// The Rust representation of the function's arguments.
5882
pub args: FunctionArgs,
83+
84+
/// Comma-separated list of argument types, in the form required for a CREATE FUNCTION statement. For example, `"text, smallint"`. `None` if the function doesn't take any arguments.
5985
pub argument_types: Option<String>,
86+
87+
/// Comma-separated list of argument types, in the form required to identify a function in an ALTER FUNCTION statement. For example, `"text, smallint"`. `None` if the function doesn't take any arguments.
6088
pub identity_argument_types: Option<String>,
61-
pub return_type_id: Option<i64>,
62-
pub return_type: Option<String>,
89+
90+
/// An ID identifying the return type. For example, `2275` refers to `cstring`. 2278 refers to `void`.
91+
pub return_type_id: i64,
92+
93+
/// The return type, for example "text", "trigger", or "void".
94+
pub return_type: String,
95+
96+
/// If the return type is a composite type, this will point the matching entry's `oid` column in the `pg_class` table. `None` if the function does not return a composite type.
6397
pub return_type_relation_id: Option<i64>,
98+
99+
/// Does the function returns multiple values of a data type?
64100
pub is_set_returning_function: bool,
101+
102+
/// See `Behavior`.
65103
pub behavior: Behavior,
104+
105+
/// Is the function's security set to `Definer` (true) or `Invoker` (false)?
66106
pub security_definer: bool,
67107
}
68108

@@ -73,48 +113,65 @@ impl SchemaCacheItem for Function {
73113
sqlx::query_as!(
74114
Function,
75115
r#"
76-
with functions as (
116+
with functions as (
77117
select
78-
*,
118+
oid,
119+
proname,
120+
prosrc,
121+
prorettype,
122+
proretset,
123+
provolatile,
124+
prosecdef,
125+
prolang,
126+
pronamespace,
127+
proconfig,
128+
79129
-- proargmodes is null when all arg modes are IN
80130
coalesce(
81131
p.proargmodes,
82-
array_fill('i'::text, array[cardinality(coalesce(p.proallargtypes, p.proargtypes))])
132+
array_fill(
133+
'i' :: text,
134+
array [cardinality(coalesce(p.proallargtypes, p.proargtypes))]
135+
)
83136
) as arg_modes,
84137
-- proargnames is null when all args are unnamed
85138
coalesce(
86139
p.proargnames,
87-
array_fill(''::text, array[cardinality(coalesce(p.proallargtypes, p.proargtypes))])
140+
array_fill(
141+
'' :: text,
142+
array [cardinality(coalesce(p.proallargtypes, p.proargtypes))]
143+
)
88144
) as arg_names,
89145
-- proallargtypes is null when all arg modes are IN
90146
coalesce(p.proallargtypes, p.proargtypes) as arg_types,
91147
array_cat(
92-
array_fill(false, array[pronargs - pronargdefaults]),
93-
array_fill(true, array[pronargdefaults])) as arg_has_defaults
148+
array_fill(false, array [pronargs - pronargdefaults]),
149+
array_fill(true, array [pronargdefaults])
150+
) as arg_has_defaults
94151
from
95152
pg_proc as p
96153
where
97154
p.prokind = 'f'
98155
)
99156
select
100-
f.oid::int8 as id,
101-
n.nspname as schema,
102-
f.proname as name,
103-
l.lanname as language,
157+
f.oid :: int8 as "id!",
158+
n.nspname as "schema!",
159+
f.proname as "name!",
160+
l.lanname as "language!",
104161
case
105162
when l.lanname = 'internal' then ''
106163
else f.prosrc
107-
end as definition,
164+
end as body,
108165
case
109-
when l.lanname = 'internal' then f.prosrc
166+
when l.lanname = 'internal' then ''
110167
else pg_get_functiondef(f.oid)
111-
end as complete_statement,
168+
end as definition,
112169
coalesce(f_args.args, '[]') as args,
113-
pg_get_function_arguments(f.oid) as argument_types,
114-
pg_get_function_identity_arguments(f.oid) as identity_argument_types,
115-
f.prorettype::int8 as return_type_id,
116-
pg_get_function_result(f.oid) as return_type,
117-
nullif(rt.typrelid::int8, 0) as return_type_relation_id,
170+
nullif(pg_get_function_arguments(f.oid), '') as argument_types,
171+
nullif(pg_get_function_identity_arguments(f.oid), '') as identity_argument_types,
172+
f.prorettype :: int8 as "return_type_id!",
173+
pg_get_function_result(f.oid) as "return_type!",
174+
nullif(rt.typrelid :: int8, 0) as return_type_relation_id,
118175
f.proretset as is_set_returning_function,
119176
case
120177
when f.provolatile = 'i' then 'IMMUTABLE'
@@ -130,13 +187,16 @@ from
130187
left join (
131188
select
132189
oid,
133-
jsonb_object_agg(param, value) filter (where param is not null) as config_params
190+
jsonb_object_agg(param, value) filter (
191+
where
192+
param is not null
193+
) as config_params
134194
from
135195
(
136196
select
137197
oid,
138-
(string_to_array(unnest(proconfig), '='))[1] as param,
139-
(string_to_array(unnest(proconfig), '='))[2] as value
198+
(string_to_array(unnest(proconfig), '=')) [1] as param,
199+
(string_to_array(unnest(proconfig), '=')) [2] as value
140200
from
141201
functions
142202
) as t
@@ -146,19 +206,25 @@ from
146206
left join (
147207
select
148208
oid,
149-
jsonb_agg(jsonb_build_object(
150-
'mode', t2.mode,
151-
'name', name,
152-
'type_id', type_id,
153-
'has_default', has_default
154-
)) as args
209+
jsonb_agg(
210+
jsonb_build_object(
211+
'mode',
212+
t2.mode,
213+
'name',
214+
name,
215+
'type_id',
216+
type_id,
217+
'has_default',
218+
has_default
219+
)
220+
) as args
155221
from
156222
(
157223
select
158224
oid,
159225
unnest(arg_modes) as mode,
160226
unnest(arg_names) as name,
161-
unnest(arg_types)::int8 as type_id,
227+
unnest(arg_types) :: int8 as type_id,
162228
unnest(arg_has_defaults) as has_default
163229
from
164230
functions
@@ -175,7 +241,8 @@ from
175241
) as t2
176242
group by
177243
t1.oid
178-
) f_args on f_args.oid = f.oid"#
244+
) f_args on f_args.oid = f.oid;
245+
"#
179246
)
180247
.fetch_all(pool)
181248
.await

0 commit comments

Comments
 (0)