diff --git a/crates/pg_schema_cache/src/functions.rs b/crates/pg_schema_cache/src/functions.rs index 097c8f84..5ce4805e 100644 --- a/crates/pg_schema_cache/src/functions.rs +++ b/crates/pg_schema_cache/src/functions.rs @@ -70,114 +70,8 @@ impl SchemaCacheItem for Function { type Item = Function; async fn load(pool: &PgPool) -> Result, sqlx::Error> { - sqlx::query_as!( - Function, - r#" -with functions as ( - select - *, - -- proargmodes is null when all arg modes are IN - coalesce( - p.proargmodes, - array_fill('i'::text, array[cardinality(coalesce(p.proallargtypes, p.proargtypes))]) - ) as arg_modes, - -- proargnames is null when all args are unnamed - coalesce( - p.proargnames, - array_fill(''::text, array[cardinality(coalesce(p.proallargtypes, p.proargtypes))]) - ) as arg_names, - -- proallargtypes is null when all arg modes are IN - coalesce(p.proallargtypes, p.proargtypes) as arg_types, - array_cat( - array_fill(false, array[pronargs - pronargdefaults]), - array_fill(true, array[pronargdefaults])) as arg_has_defaults - from - pg_proc as p - where - p.prokind = 'f' -) -select - f.oid::int8 as id, - n.nspname as schema, - f.proname as name, - l.lanname as language, - case - when l.lanname = 'internal' then '' - else f.prosrc - end as definition, - case - when l.lanname = 'internal' then f.prosrc - else pg_get_functiondef(f.oid) - end as complete_statement, - coalesce(f_args.args, '[]') as args, - pg_get_function_arguments(f.oid) as argument_types, - pg_get_function_identity_arguments(f.oid) as identity_argument_types, - f.prorettype::int8 as return_type_id, - pg_get_function_result(f.oid) as return_type, - nullif(rt.typrelid::int8, 0) as return_type_relation_id, - f.proretset as is_set_returning_function, - case - when f.provolatile = 'i' then 'IMMUTABLE' - when f.provolatile = 's' then 'STABLE' - when f.provolatile = 'v' then 'VOLATILE' - end as behavior, - f.prosecdef as security_definer -from - functions f - left join pg_namespace n on f.pronamespace = n.oid - left join pg_language l on f.prolang = l.oid - left join pg_type rt on rt.oid = f.prorettype - left join ( - select - oid, - jsonb_object_agg(param, value) filter (where param is not null) as config_params - from - ( - select - oid, - (string_to_array(unnest(proconfig), '='))[1] as param, - (string_to_array(unnest(proconfig), '='))[2] as value - from - functions - ) as t - group by - oid - ) f_config on f_config.oid = f.oid - left join ( - select - oid, - jsonb_agg(jsonb_build_object( - 'mode', t2.mode, - 'name', name, - 'type_id', type_id, - 'has_default', has_default - )) as args - from - ( - select - oid, - unnest(arg_modes) as mode, - unnest(arg_names) as name, - unnest(arg_types)::int8 as type_id, - unnest(arg_has_defaults) as has_default - from - functions - ) as t1, - lateral ( - select - case - when t1.mode = 'i' then 'in' - when t1.mode = 'o' then 'out' - when t1.mode = 'b' then 'inout' - when t1.mode = 'v' then 'variadic' - else 'table' - end as mode - ) as t2 - group by - t1.oid - ) f_args on f_args.oid = f.oid"# - ) - .fetch_all(pool) - .await + sqlx::query_file_as!(Function, "src/queries/functions.sql") + .fetch_all(pool) + .await } } diff --git a/crates/pg_schema_cache/src/queries/functions.sql b/crates/pg_schema_cache/src/queries/functions.sql new file mode 100644 index 00000000..57b8aa6c --- /dev/null +++ b/crates/pg_schema_cache/src/queries/functions.sql @@ -0,0 +1,119 @@ +with functions as ( + select + *, + -- proargmodes is null when all arg modes are IN + coalesce( + p.proargmodes, + array_fill( + 'i' :: text, + array [cardinality(coalesce(p.proallargtypes, p.proargtypes))] + ) + ) as arg_modes, + -- proargnames is null when all args are unnamed + coalesce( + p.proargnames, + array_fill( + '' :: text, + array [cardinality(coalesce(p.proallargtypes, p.proargtypes))] + ) + ) as arg_names, + -- proallargtypes is null when all arg modes are IN + coalesce(p.proallargtypes, p.proargtypes) as arg_types, + array_cat( + array_fill(false, array [pronargs - pronargdefaults]), + array_fill(true, array [pronargdefaults]) + ) as arg_has_defaults + from + pg_proc as p + where + p.prokind = 'f' +) +select + f.oid :: int8 as id, + n.nspname as schema, + f.proname as name, + l.lanname as language, + case + when l.lanname = 'internal' then '' + else f.prosrc + end as definition, + case + when l.lanname = 'internal' then f.prosrc + else pg_get_functiondef(f.oid) + end as complete_statement, + coalesce(f_args.args, '[]') as args, + pg_get_function_arguments(f.oid) as argument_types, + pg_get_function_identity_arguments(f.oid) as identity_argument_types, + f.prorettype :: int8 as return_type_id, + pg_get_function_result(f.oid) as return_type, + nullif(rt.typrelid :: int8, 0) as return_type_relation_id, + f.proretset as is_set_returning_function, + case + when f.provolatile = 'i' then 'IMMUTABLE' + when f.provolatile = 's' then 'STABLE' + when f.provolatile = 'v' then 'VOLATILE' + end as behavior, + f.prosecdef as security_definer +from + functions f + left join pg_namespace n on f.pronamespace = n.oid + left join pg_language l on f.prolang = l.oid + left join pg_type rt on rt.oid = f.prorettype + left join ( + select + oid, + jsonb_object_agg(param, value) filter ( + where + param is not null + ) as config_params + from + ( + select + oid, + (string_to_array(unnest(proconfig), '=')) [1] as param, + (string_to_array(unnest(proconfig), '=')) [2] as value + from + functions + ) as t + group by + oid + ) f_config on f_config.oid = f.oid + left join ( + select + oid, + jsonb_agg( + jsonb_build_object( + 'mode', + t2.mode, + 'name', + name, + 'type_id', + type_id, + 'has_default', + has_default + ) + ) as args + from + ( + select + oid, + unnest(arg_modes) as mode, + unnest(arg_names) as name, + unnest(arg_types) :: int8 as type_id, + unnest(arg_has_defaults) as has_default + from + functions + ) as t1, + lateral ( + select + case + when t1.mode = 'i' then 'in' + when t1.mode = 'o' then 'out' + when t1.mode = 'b' then 'inout' + when t1.mode = 'v' then 'variadic' + else 'table' + end as mode + ) as t2 + group by + t1.oid + ) f_args on f_args.oid = f.oid; \ No newline at end of file diff --git a/crates/pg_schema_cache/src/queries/schemas.sql b/crates/pg_schema_cache/src/queries/schemas.sql new file mode 100644 index 00000000..55e1824b --- /dev/null +++ b/crates/pg_schema_cache/src/queries/schemas.sql @@ -0,0 +1,15 @@ +select + n.oid :: int8 as "id!", + n.nspname as name, + u.rolname as "owner!" +from + pg_namespace n, + pg_roles u +where + n.nspowner = u.oid + and ( + pg_has_role(n.nspowner, 'USAGE') + or has_schema_privilege(n.oid, 'CREATE, USAGE') + ) + and not pg_catalog.starts_with(n.nspname, 'pg_temp_') + and not pg_catalog.starts_with(n.nspname, 'pg_toast_temp_'); \ No newline at end of file diff --git a/crates/pg_schema_cache/src/queries/tables.sql b/crates/pg_schema_cache/src/queries/tables.sql new file mode 100644 index 00000000..bcce4fcc --- /dev/null +++ b/crates/pg_schema_cache/src/queries/tables.sql @@ -0,0 +1,40 @@ +select + c.oid :: int8 as "id!", + nc.nspname as schema, + c.relname as name, + c.relrowsecurity as rls_enabled, + c.relforcerowsecurity as rls_forced, + case + when c.relreplident = 'd' then 'DEFAULT' + when c.relreplident = 'i' then 'INDEX' + when c.relreplident = 'f' then 'FULL' + else 'NOTHING' + end as "replica_identity!", + pg_total_relation_size(format('%I.%I', nc.nspname, c.relname)) :: int8 as "bytes!", + pg_size_pretty( + pg_total_relation_size(format('%I.%I', nc.nspname, c.relname)) + ) as "size!", + pg_stat_get_live_tuples(c.oid) as "live_rows_estimate!", + pg_stat_get_dead_tuples(c.oid) as "dead_rows_estimate!", + obj_description(c.oid) as comment +from + pg_namespace nc + join pg_class c on nc.oid = c.relnamespace +where + c.relkind in ('r', 'p') + and not pg_is_other_temp_schema(nc.oid) + and ( + pg_has_role(c.relowner, 'USAGE') + or has_table_privilege( + c.oid, + 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER' + ) + or has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') + ) +group by + c.oid, + c.relname, + c.relrowsecurity, + c.relforcerowsecurity, + c.relreplident, + nc.nspname; \ No newline at end of file diff --git a/crates/pg_schema_cache/src/queries/types.sql b/crates/pg_schema_cache/src/queries/types.sql new file mode 100644 index 00000000..39f6b71c --- /dev/null +++ b/crates/pg_schema_cache/src/queries/types.sql @@ -0,0 +1,53 @@ +select + t.oid :: int8 as "id!", + t.typname as name, + n.nspname as "schema!", + format_type (t.oid, null) as "format!", + coalesce(t_enums.enums, '[]') as enums, + coalesce(t_attributes.attributes, '[]') as attributes, + obj_description (t.oid, 'pg_type') as comment +from + pg_type t + left join pg_namespace n on n.oid = t.typnamespace + left join ( + select + enumtypid, + jsonb_agg( + enumlabel + order by + enumsortorder + ) as enums + from + pg_enum + group by + enumtypid + ) as t_enums on t_enums.enumtypid = t.oid + left join ( + select + oid, + jsonb_agg( + jsonb_build_object('name', a.attname, 'type_id', a.atttypid :: int8) + order by + a.attnum asc + ) as attributes + from + pg_class c + join pg_attribute a on a.attrelid = c.oid + where + c.relkind = 'c' + and not a.attisdropped + group by + c.oid + ) as t_attributes on t_attributes.oid = t.typrelid +where + ( + t.typrelid = 0 + or ( + select + c.relkind = 'c' + from + pg_class c + where + c.oid = t.typrelid + ) + ); \ No newline at end of file diff --git a/crates/pg_schema_cache/src/queries/versions.sql b/crates/pg_schema_cache/src/queries/versions.sql new file mode 100644 index 00000000..c756e9c5 --- /dev/null +++ b/crates/pg_schema_cache/src/queries/versions.sql @@ -0,0 +1,10 @@ +select + version(), + current_setting('server_version_num') :: int8 AS version_num, + ( + select + count(*) :: int8 AS active_connections + FROM + pg_stat_activity + ) AS active_connections, + current_setting('max_connections') :: int8 AS max_connections; \ No newline at end of file diff --git a/crates/pg_schema_cache/src/schemas.rs b/crates/pg_schema_cache/src/schemas.rs index a5d71ef6..51eb8ea3 100644 --- a/crates/pg_schema_cache/src/schemas.rs +++ b/crates/pg_schema_cache/src/schemas.rs @@ -13,25 +13,8 @@ impl SchemaCacheItem for Schema { type Item = Schema; async fn load(pool: &PgPool) -> Result, sqlx::Error> { - sqlx::query_as!( - Schema, - r#"select - n.oid::int8 as "id!", - n.nspname as name, - u.rolname as "owner!" -from - pg_namespace n, - pg_roles u -where - n.nspowner = u.oid - and ( - pg_has_role(n.nspowner, 'USAGE') - or has_schema_privilege(n.oid, 'CREATE, USAGE') - ) - and not pg_catalog.starts_with(n.nspname, 'pg_temp_') - and not pg_catalog.starts_with(n.nspname, 'pg_toast_temp_')"# - ) - .fetch_all(pool) - .await + sqlx::query_file_as!(Schema, "src/queries/schemas.sql") + .fetch_all(pool) + .await } } diff --git a/crates/pg_schema_cache/src/tables.rs b/crates/pg_schema_cache/src/tables.rs index 1154f106..ea889ca9 100644 --- a/crates/pg_schema_cache/src/tables.rs +++ b/crates/pg_schema_cache/src/tables.rs @@ -42,50 +42,8 @@ impl SchemaCacheItem for Table { type Item = Table; async fn load(pool: &PgPool) -> Result, sqlx::Error> { - sqlx::query_as!( - Table, - r#"SELECT - c.oid :: int8 AS "id!", - nc.nspname AS schema, - c.relname AS name, - c.relrowsecurity AS rls_enabled, - c.relforcerowsecurity AS rls_forced, - CASE - WHEN c.relreplident = 'd' THEN 'DEFAULT' - WHEN c.relreplident = 'i' THEN 'INDEX' - WHEN c.relreplident = 'f' THEN 'FULL' - ELSE 'NOTHING' - END AS "replica_identity!", - pg_total_relation_size(format('%I.%I', nc.nspname, c.relname)) :: int8 AS "bytes!", - pg_size_pretty( - pg_total_relation_size(format('%I.%I', nc.nspname, c.relname)) - ) AS "size!", - pg_stat_get_live_tuples(c.oid) AS "live_rows_estimate!", - pg_stat_get_dead_tuples(c.oid) AS "dead_rows_estimate!", - obj_description(c.oid) AS comment -FROM - pg_namespace nc - JOIN pg_class c ON nc.oid = c.relnamespace -WHERE - c.relkind IN ('r', 'p') - AND NOT pg_is_other_temp_schema(nc.oid) - AND ( - pg_has_role(c.relowner, 'USAGE') - OR has_table_privilege( - c.oid, - 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER' - ) - OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') - ) -group by - c.oid, - c.relname, - c.relrowsecurity, - c.relforcerowsecurity, - c.relreplident, - nc.nspname"# - ) - .fetch_all(pool) - .await + sqlx::query_file_as!(Table, "src/queries/tables.sql") + .fetch_all(pool) + .await } } diff --git a/crates/pg_schema_cache/src/types.rs b/crates/pg_schema_cache/src/types.rs index dab04308..9d88f579 100644 --- a/crates/pg_schema_cache/src/types.rs +++ b/crates/pg_schema_cache/src/types.rs @@ -51,57 +51,8 @@ impl SchemaCacheItem for PostgresType { type Item = PostgresType; async fn load(pool: &PgPool) -> Result, sqlx::Error> { - sqlx::query_as!( - PostgresType, - r#"select - t.oid::int8 as "id!", - t.typname as name, - n.nspname as "schema!", - format_type (t.oid, null) as "format!", - coalesce(t_enums.enums, '[]') as enums, - coalesce(t_attributes.attributes, '[]') as attributes, - obj_description (t.oid, 'pg_type') as comment -from - pg_type t - left join pg_namespace n on n.oid = t.typnamespace - left join ( - select - enumtypid, - jsonb_agg(enumlabel order by enumsortorder) as enums - from - pg_enum - group by - enumtypid - ) as t_enums on t_enums.enumtypid = t.oid - left join ( - select - oid, - jsonb_agg( - jsonb_build_object('name', a.attname, 'type_id', a.atttypid::int8) - order by a.attnum asc - ) as attributes - from - pg_class c - join pg_attribute a on a.attrelid = c.oid - where - c.relkind = 'c' and not a.attisdropped - group by - c.oid - ) as t_attributes on t_attributes.oid = t.typrelid -where - ( - t.typrelid = 0 - or ( - select - c.relkind = 'c' - from - pg_class c - where - c.oid = t.typrelid - ) - )"# - ) - .fetch_all(pool) - .await + sqlx::query_file_as!(PostgresType, "src/queries/types.sql") + .fetch_all(pool) + .await } } diff --git a/crates/pg_schema_cache/src/versions.rs b/crates/pg_schema_cache/src/versions.rs index 40b0eb66..cf2a140f 100644 --- a/crates/pg_schema_cache/src/versions.rs +++ b/crates/pg_schema_cache/src/versions.rs @@ -14,21 +14,9 @@ impl SchemaCacheItem for Version { type Item = Version; async fn load(pool: &PgPool) -> Result, sqlx::Error> { - sqlx::query_as!( - Version, - r#"select - version(), - current_setting('server_version_num') :: int8 AS version_num, - ( - select - count(*) :: int8 AS active_connections - FROM - pg_stat_activity - ) AS active_connections, - current_setting('max_connections') :: int8 AS max_connections;"# - ) - .fetch_all(pool) - .await + sqlx::query_file_as!(Version, "src/queries/versions.sql") + .fetch_all(pool) + .await } /*