From 98ea0adc320d5d98cbb3146dd209e3e04b6d0ff8 Mon Sep 17 00:00:00 2001
From: Julian <juliandomke@outlook.de>
Date: Mon, 9 Jun 2025 09:16:22 +0200
Subject: [PATCH 1/8] allow procedures

---
 crates/pgt_schema_cache/src/functions.rs      | 147 +++++++++++++++++-
 .../src/queries/functions.sql                 |   8 +-
 2 files changed, 148 insertions(+), 7 deletions(-)

diff --git a/crates/pgt_schema_cache/src/functions.rs b/crates/pgt_schema_cache/src/functions.rs
index 5e40709f1..8d549268c 100644
--- a/crates/pgt_schema_cache/src/functions.rs
+++ b/crates/pgt_schema_cache/src/functions.rs
@@ -4,6 +4,33 @@ use sqlx::types::JsonValue;
 
 use crate::schema_cache::SchemaCacheItem;
 
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
+pub enum ProcKind {
+    #[default]
+    Function,
+    Aggregate,
+    Window,
+    Procedure,
+}
+
+impl From<char> for ProcKind {
+    fn from(value: char) -> Self {
+        match value {
+            'f' => Self::Function,
+            'p' => Self::Function,
+            'w' => Self::Window,
+            'a' => Self::Aggregate,
+            _ => unreachable!(),
+        }
+    }
+}
+
+impl From<i8> for ProcKind {
+    fn from(value: i8) -> Self {
+        char::from(u8::try_from(value).unwrap()).into()
+    }
+}
+
 /// `Behavior` describes the characteristics of the function. Is it deterministic? Does it changed due to side effects, and if so, when?
 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
 pub enum Behavior {
@@ -40,7 +67,7 @@ pub struct FunctionArg {
     pub name: String,
 
     /// Refers to the argument type's ID in the `pg_type` table.
-    pub type_id: i64,
+    pub type_id: Option<i64>,
 
     pub has_default: Option<bool>,
 }
@@ -72,6 +99,8 @@ pub struct Function {
     /// e.g. `plpgsql/sql` or `internal`.
     pub language: String,
 
+    pub kind: ProcKind,
+
     /// The body of the function – the `declare [..] begin [..] end [..]` block.` Not set for internal functions.
     pub body: Option<String>,
 
@@ -88,10 +117,10 @@ pub struct Function {
     pub identity_argument_types: Option<String>,
 
     /// An ID identifying the return type. For example, `2275` refers to `cstring`. 2278 refers to `void`.
-    pub return_type_id: i64,
+    pub return_type_id: Option<i64>,
 
     /// The return type, for example "text", "trigger", or "void".
-    pub return_type: String,
+    pub return_type: Option<String>,
 
     /// 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.
     pub return_type_relation_id: Option<i64>,
@@ -115,3 +144,115 @@ impl SchemaCacheItem for Function {
             .await
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use sqlx::{Executor, PgPool};
+
+    use crate::SchemaCache;
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn loads(pool: PgPool) {
+        let setup = r#"
+          create table coos (
+            id serial primary key,
+            name text
+          );
+
+          create or replace function my_cool_foo()
+          returns trigger
+          language plpgsql
+          security invoker
+          as $$
+          begin
+            raise exception 'dont matter';
+          end;
+          $$;
+
+          create or replace procedure my_cool_proc()
+          language plpgsql
+          security invoker
+          as $$
+          begin
+            raise exception 'dont matter';
+          end;
+          $$;
+
+          create or replace function string_concat_state(
+            state text, 
+            value text, 
+            separator text)
+          returns text
+          language plpgsql
+          as $$
+          begin
+              if state is null then
+                  return value;
+              else
+                  return state || separator || value;
+              end if;
+          end;
+          $$;
+
+          create aggregate string_concat(text, text) (
+            sfunc = string_concat_state,
+            stype = text,
+            initcond = ''
+          );
+        "#;
+
+        pool.execute(setup).await.unwrap();
+
+        let cache = SchemaCache::load(&pool).await.unwrap();
+
+        // // Check the number of functions, procedures, and aggregates
+        // assert_eq!(cache.functions.len(), 4);
+
+        // // Find and check the function
+        // let foo_fn = cache
+        //     .functions
+        //     .iter()
+        //     .find(|f| f.name == "my_cool_foo")
+        //     .unwrap();
+        // assert_eq!(foo_fn.schema, "public");
+        // assert_eq!(foo_fn.kind, ProcKind::Function);
+        // assert_eq!(foo_fn.language, "plpgsql");
+        // assert_eq!(foo_fn.return_type.as_deref(), Some("trigger"));
+        // assert_eq!(foo_fn.security_definer, false);
+        // assert_eq!(foo_fn.behavior, Behavior::Volatile);
+
+        // // Find and check the procedure
+        // let proc_fn = cache
+        //     .functions
+        //     .iter()
+        //     .find(|f| f.name == "my_cool_proc")
+        //     .unwrap();
+        // assert_eq!(proc_fn.kind, ProcKind::Procedure);
+        // assert_eq!(proc_fn.language, "plpgsql");
+        // assert_eq!(proc_fn.security_definer, false);
+
+        // // Find and check the aggregate
+        // let agg_fn = cache
+        //     .functions
+        //     .iter()
+        //     .find(|f| f.name == "string_concat")
+        //     .unwrap();
+        // assert_eq!(agg_fn.kind, ProcKind::Aggregate);
+        // assert_eq!(agg_fn.language, "internal"); // Aggregates are often "internal"
+        // // The return type should be text
+        // assert_eq!(agg_fn.return_type.as_deref(), Some("text"));
+
+        // // Find and check the state function for the aggregate
+        // let state_fn = cache
+        //     .functions
+        //     .iter()
+        //     .find(|f| f.name == "string_concat_state")
+        //     .unwrap();
+        // assert_eq!(state_fn.kind, ProcKind::Function);
+        // assert_eq!(state_fn.language, "plpgsql");
+        // assert_eq!(state_fn.return_type.as_deref(), Some("text"));
+        // assert_eq!(state_fn.args.args.len(), 3);
+        // let arg_names: Vec<_> = state_fn.args.args.iter().map(|a| a.name.as_str()).collect();
+        // assert_eq!(arg_names, &["state", "value", "separator"]);
+    }
+}
diff --git a/crates/pgt_schema_cache/src/queries/functions.sql b/crates/pgt_schema_cache/src/queries/functions.sql
index f78ba91e6..fa06fd250 100644
--- a/crates/pgt_schema_cache/src/queries/functions.sql
+++ b/crates/pgt_schema_cache/src/queries/functions.sql
@@ -10,6 +10,7 @@ with functions as (
     prolang,
     pronamespace,
     proconfig,
+    prokind,
     -- proargmodes is null when all arg modes are IN
     coalesce(
       p.proargmodes,
@@ -34,14 +35,13 @@ with functions as (
     ) 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!",
+  f.prokind as "kind!",
   case
     when l.lanname = 'internal' then null
     else f.prosrc
@@ -53,8 +53,8 @@ select
   coalesce(f_args.args, '[]') as args,
   nullif(pg_get_function_arguments(f.oid), '') as argument_types,
   nullif(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!",
+  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

From d80842978aa73c05785de32c560b49d178229c36 Mon Sep 17 00:00:00 2001
From: Julian <juliandomke@outlook.de>
Date: Mon, 9 Jun 2025 10:38:08 +0200
Subject: [PATCH 2/8] fix query?

---
 crates/pgt_schema_cache/src/functions.rs      | 107 ++++++++++--------
 .../src/queries/functions.sql                 |  13 ++-
 2 files changed, 64 insertions(+), 56 deletions(-)

diff --git a/crates/pgt_schema_cache/src/functions.rs b/crates/pgt_schema_cache/src/functions.rs
index 8d549268c..49b8b36d8 100644
--- a/crates/pgt_schema_cache/src/functions.rs
+++ b/crates/pgt_schema_cache/src/functions.rs
@@ -17,7 +17,7 @@ impl From<char> for ProcKind {
     fn from(value: char) -> Self {
         match value {
             'f' => Self::Function,
-            'p' => Self::Function,
+            'p' => Self::Procedure,
             'w' => Self::Window,
             'a' => Self::Aggregate,
             _ => unreachable!(),
@@ -203,56 +203,63 @@ mod tests {
 
         pool.execute(setup).await.unwrap();
 
+        let results = sqlx::query_file!("src/queries/functions.sql")
+            .fetch_all(&pool)
+            .await
+            .unwrap();
+
+        println!("{:#?}", results);
+
         let cache = SchemaCache::load(&pool).await.unwrap();
 
-        // // Check the number of functions, procedures, and aggregates
-        // assert_eq!(cache.functions.len(), 4);
-
-        // // Find and check the function
-        // let foo_fn = cache
-        //     .functions
-        //     .iter()
-        //     .find(|f| f.name == "my_cool_foo")
-        //     .unwrap();
-        // assert_eq!(foo_fn.schema, "public");
-        // assert_eq!(foo_fn.kind, ProcKind::Function);
-        // assert_eq!(foo_fn.language, "plpgsql");
-        // assert_eq!(foo_fn.return_type.as_deref(), Some("trigger"));
-        // assert_eq!(foo_fn.security_definer, false);
-        // assert_eq!(foo_fn.behavior, Behavior::Volatile);
-
-        // // Find and check the procedure
-        // let proc_fn = cache
-        //     .functions
-        //     .iter()
-        //     .find(|f| f.name == "my_cool_proc")
-        //     .unwrap();
-        // assert_eq!(proc_fn.kind, ProcKind::Procedure);
-        // assert_eq!(proc_fn.language, "plpgsql");
-        // assert_eq!(proc_fn.security_definer, false);
-
-        // // Find and check the aggregate
-        // let agg_fn = cache
-        //     .functions
-        //     .iter()
-        //     .find(|f| f.name == "string_concat")
-        //     .unwrap();
-        // assert_eq!(agg_fn.kind, ProcKind::Aggregate);
-        // assert_eq!(agg_fn.language, "internal"); // Aggregates are often "internal"
-        // // The return type should be text
-        // assert_eq!(agg_fn.return_type.as_deref(), Some("text"));
-
-        // // Find and check the state function for the aggregate
-        // let state_fn = cache
-        //     .functions
-        //     .iter()
-        //     .find(|f| f.name == "string_concat_state")
-        //     .unwrap();
-        // assert_eq!(state_fn.kind, ProcKind::Function);
-        // assert_eq!(state_fn.language, "plpgsql");
-        // assert_eq!(state_fn.return_type.as_deref(), Some("text"));
-        // assert_eq!(state_fn.args.args.len(), 3);
-        // let arg_names: Vec<_> = state_fn.args.args.iter().map(|a| a.name.as_str()).collect();
-        // assert_eq!(arg_names, &["state", "value", "separator"]);
+        // Find and check the function
+        let foo_fn = cache
+            .functions
+            .iter()
+            .find(|f| f.name == "my_cool_foo")
+            .unwrap();
+        assert_eq!(foo_fn.schema, "public");
+        assert_eq!(foo_fn.kind, ProcKind::Function);
+        assert_eq!(foo_fn.language, "plpgsql");
+        assert_eq!(foo_fn.return_type.as_deref(), Some("trigger"));
+        assert_eq!(foo_fn.security_definer, false);
+        assert_eq!(foo_fn.behavior, Behavior::Volatile);
+
+        // Find and check the procedure
+        let proc_fn = cache
+            .functions
+            .iter()
+            .find(|f| f.name == "my_cool_proc")
+            .unwrap();
+
+        println!("{:?}", proc_fn);
+        assert_eq!(proc_fn.kind, ProcKind::Procedure);
+        assert_eq!(proc_fn.language, "plpgsql");
+        assert_eq!(proc_fn.security_definer, false);
+
+        // Find and check the aggregate
+        let agg_fn = cache
+            .functions
+            .iter()
+            .find(|f| f.name == "string_concat")
+            .unwrap();
+        assert_eq!(agg_fn.kind, ProcKind::Aggregate);
+        assert_eq!(agg_fn.language, "internal"); // Aggregates are often "internal"
+        // The return type should be text
+        assert_eq!(agg_fn.return_type.as_deref(), Some("text"));
+
+        // Find and check the state function for the aggregate
+        let state_fn = cache
+            .functions
+            .iter()
+            .find(|f| f.name == "string_concat_state")
+            .unwrap();
+
+        assert_eq!(state_fn.kind, ProcKind::Function);
+        assert_eq!(state_fn.language, "plpgsql");
+        assert_eq!(state_fn.return_type.as_deref(), Some("text"));
+        assert_eq!(state_fn.args.args.len(), 3);
+        let arg_names: Vec<_> = state_fn.args.args.iter().map(|a| a.name.as_str()).collect();
+        assert_eq!(arg_names, &["state", "value", "separator"]);
     }
 }
diff --git a/crates/pgt_schema_cache/src/queries/functions.sql b/crates/pgt_schema_cache/src/queries/functions.sql
index fa06fd250..ee8352a43 100644
--- a/crates/pgt_schema_cache/src/queries/functions.sql
+++ b/crates/pgt_schema_cache/src/queries/functions.sql
@@ -28,7 +28,7 @@ with functions as (
       )
     ) as arg_names,
     -- proallargtypes is null when all arg modes are IN
-    coalesce(p.proallargtypes, p.proargtypes) as arg_types,
+    coalesce(p.proallargtypes, string_to_array(proargtypes::text, ' ')::int[]) as arg_types,
     array_cat(
       array_fill(false, array [pronargs - pronargdefaults]),
       array_fill(true, array [pronargdefaults])
@@ -106,12 +106,13 @@ 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
+          arg_modes[i] as mode,
+          arg_names[i] as name,
+          arg_types[i] :: int8 as type_id,
+          arg_has_defaults[i] as has_default
         from
-          functions
+          functions,
+          pg_catalog.generate_subscripts(arg_names, 1) as i
       ) as t1,
       lateral (
         select

From 85fc27d94ed8cd85a86c0a414f24fdeeba46e534 Mon Sep 17 00:00:00 2001
From: Julian <juliandomke@outlook.de>
Date: Mon, 9 Jun 2025 10:40:15 +0200
Subject: [PATCH 3/8] finito

---
 crates/pgt_schema_cache/src/functions.rs          | 9 +--------
 crates/pgt_schema_cache/src/queries/functions.sql | 4 ++--
 2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/crates/pgt_schema_cache/src/functions.rs b/crates/pgt_schema_cache/src/functions.rs
index 49b8b36d8..5d8ba6779 100644
--- a/crates/pgt_schema_cache/src/functions.rs
+++ b/crates/pgt_schema_cache/src/functions.rs
@@ -149,7 +149,7 @@ impl SchemaCacheItem for Function {
 mod tests {
     use sqlx::{Executor, PgPool};
 
-    use crate::SchemaCache;
+    use crate::{Behavior, SchemaCache, functions::ProcKind};
 
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn loads(pool: PgPool) {
@@ -203,13 +203,6 @@ mod tests {
 
         pool.execute(setup).await.unwrap();
 
-        let results = sqlx::query_file!("src/queries/functions.sql")
-            .fetch_all(&pool)
-            .await
-            .unwrap();
-
-        println!("{:#?}", results);
-
         let cache = SchemaCache::load(&pool).await.unwrap();
 
         // Find and check the function
diff --git a/crates/pgt_schema_cache/src/queries/functions.sql b/crates/pgt_schema_cache/src/queries/functions.sql
index ee8352a43..9be1992db 100644
--- a/crates/pgt_schema_cache/src/queries/functions.sql
+++ b/crates/pgt_schema_cache/src/queries/functions.sql
@@ -56,13 +56,13 @@ select
   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,
+  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
+  f.prosecdef as "security_definer!"
 from
   functions f
   left join pg_namespace n on f.pronamespace = n.oid

From be1575b776cc8cb653dc7b2cfcde2899a0de891d Mon Sep 17 00:00:00 2001
From: Julian <juliandomke@outlook.de>
Date: Mon, 9 Jun 2025 10:43:21 +0200
Subject: [PATCH 4/8] lint

---
 crates/pgt_schema_cache/src/functions.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crates/pgt_schema_cache/src/functions.rs b/crates/pgt_schema_cache/src/functions.rs
index 5d8ba6779..59d3501eb 100644
--- a/crates/pgt_schema_cache/src/functions.rs
+++ b/crates/pgt_schema_cache/src/functions.rs
@@ -67,7 +67,7 @@ pub struct FunctionArg {
     pub name: String,
 
     /// Refers to the argument type's ID in the `pg_type` table.
-    pub type_id: Option<i64>,
+    pub type_id: i64,
 
     pub has_default: Option<bool>,
 }

From c7161edb4be759c74da797a98d9e892dc07e23db Mon Sep 17 00:00:00 2001
From: Julian <juliandomke@outlook.de>
Date: Mon, 9 Jun 2025 10:45:59 +0200
Subject: [PATCH 5/8] ran just ready

---
 packages/@postgrestools/backend-jsonrpc/src/workspace.ts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts
index aaa5a42aa..a81a1ca9c 100644
--- a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts
+++ b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts
@@ -97,7 +97,7 @@ export type DiagnosticTags = DiagnosticTag[];
 /**
 	* Serializable representation of a [Diagnostic](super::Diagnostic) advice
 
-See the [Visitor] trait for additional documentation on all the supported advice types.
+See the [Visitor] trait for additional documentation on all the supported advice types. 
 	 */
 export type Advice =
 	| { log: [LogCategory, MarkupBuf] }
@@ -202,7 +202,7 @@ export interface CompletionItem {
 /**
 	* The text that the editor should fill in. If `None`, the `label` should be used. Tables, for example, might have different completion_texts:
 
-label: "users", description: "Schema: auth", completion_text: "auth.users".
+label: "users", description: "Schema: auth", completion_text: "auth.users". 
 	 */
 export interface CompletionText {
 	is_snippet: boolean;
@@ -355,7 +355,7 @@ export interface PartialVcsConfiguration {
 	/**
 	* The folder where we should check for VCS files. By default, we will use the same folder where `postgrestools.jsonc` was found.
 
-If we can't find the configuration, it will attempt to use the current working directory. If no current working directory can't be found, we won't use the VCS integration, and a diagnostic will be emitted
+If we can't find the configuration, it will attempt to use the current working directory. If no current working directory can't be found, we won't use the VCS integration, and a diagnostic will be emitted 
 	 */
 	root?: string;
 	/**

From 26dcaedb2cc36b3e89c41a4e611eaf2e4edad0fa Mon Sep 17 00:00:00 2001
From: Julian <juliandomke@outlook.de>
Date: Mon, 9 Jun 2025 10:47:26 +0200
Subject: [PATCH 6/8] ready

---
 crates/pgt_schema_cache/src/functions.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/crates/pgt_schema_cache/src/functions.rs b/crates/pgt_schema_cache/src/functions.rs
index 59d3501eb..8f5f7d869 100644
--- a/crates/pgt_schema_cache/src/functions.rs
+++ b/crates/pgt_schema_cache/src/functions.rs
@@ -215,7 +215,7 @@ mod tests {
         assert_eq!(foo_fn.kind, ProcKind::Function);
         assert_eq!(foo_fn.language, "plpgsql");
         assert_eq!(foo_fn.return_type.as_deref(), Some("trigger"));
-        assert_eq!(foo_fn.security_definer, false);
+        assert!(!foo_fn.security_definer);
         assert_eq!(foo_fn.behavior, Behavior::Volatile);
 
         // Find and check the procedure
@@ -228,7 +228,7 @@ mod tests {
         println!("{:?}", proc_fn);
         assert_eq!(proc_fn.kind, ProcKind::Procedure);
         assert_eq!(proc_fn.language, "plpgsql");
-        assert_eq!(proc_fn.security_definer, false);
+        assert!(!proc_fn.security_definer);
 
         // Find and check the aggregate
         let agg_fn = cache

From c0cd4e7704bf27b3192f4649319849666374edc6 Mon Sep 17 00:00:00 2001
From: Julian <juliandomke@outlook.de>
Date: Mon, 9 Jun 2025 10:48:17 +0200
Subject: [PATCH 7/8] sqlx prepare

---
 ...117910b19f540f19393b76aa6434e9d1d8502.json | 110 ++++++++++++++++++
 ...e496f5337cadbad7a3fb03ccd3e3c21b71389.json | 104 -----------------
 ...053db65ea6a7529e2cb97b2d3432a18aff6ba.json |  20 ----
 3 files changed, 110 insertions(+), 124 deletions(-)
 create mode 100644 .sqlx/query-4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502.json
 delete mode 100644 .sqlx/query-64d9718b07516f3d2720cb7aa79e496f5337cadbad7a3fb03ccd3e3c21b71389.json
 delete mode 100644 .sqlx/query-b0504a4340264403ad43d05c60d053db65ea6a7529e2cb97b2d3432a18aff6ba.json

diff --git a/.sqlx/query-4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502.json b/.sqlx/query-4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502.json
new file mode 100644
index 000000000..4980f4f37
--- /dev/null
+++ b/.sqlx/query-4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502.json
@@ -0,0 +1,110 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "with functions as (\n  select\n    oid,\n    proname,\n    prosrc,\n    prorettype,\n    proretset,\n    provolatile,\n    prosecdef,\n    prolang,\n    pronamespace,\n    proconfig,\n    prokind,\n    -- proargmodes is null when all arg modes are IN\n    coalesce(\n      p.proargmodes,\n      array_fill(\n        'i' :: text,\n        array [cardinality(coalesce(p.proallargtypes, p.proargtypes))]\n      )\n    ) as arg_modes,\n    -- proargnames is null when all args are unnamed\n    coalesce(\n      p.proargnames,\n      array_fill(\n        '' :: text,\n        array [cardinality(coalesce(p.proallargtypes, p.proargtypes))]\n      )\n    ) as arg_names,\n    -- proallargtypes is null when all arg modes are IN\n    coalesce(p.proallargtypes, string_to_array(proargtypes::text, ' ')::int[]) as arg_types,\n    array_cat(\n      array_fill(false, array [pronargs - pronargdefaults]),\n      array_fill(true, array [pronargdefaults])\n    ) as arg_has_defaults\n  from\n    pg_proc as p\n)\nselect\n  f.oid :: int8 as \"id!\",\n  n.nspname as \"schema!\",\n  f.proname as \"name!\",\n  l.lanname as \"language!\",\n  f.prokind as \"kind!\",\n  case\n    when l.lanname = 'internal' then null\n    else f.prosrc\n  end as body,\n  case\n    when l.lanname = 'internal' then null\n    else pg_get_functiondef(f.oid)\n  end as definition,\n  coalesce(f_args.args, '[]') as args,\n  nullif(pg_get_function_arguments(f.oid), '') as argument_types,\n  nullif(pg_get_function_identity_arguments(f.oid), '') as identity_argument_types,\n  f.prorettype :: int8 as return_type_id,\n  pg_get_function_result(f.oid) as return_type,\n  nullif(rt.typrelid :: int8, 0) as return_type_relation_id,\n  f.proretset as \"is_set_returning_function!\",\n  case\n    when f.provolatile = 'i' then 'IMMUTABLE'\n    when f.provolatile = 's' then 'STABLE'\n    when f.provolatile = 'v' then 'VOLATILE'\n  end as behavior,\n  f.prosecdef as \"security_definer!\"\nfrom\n  functions f\n  left join pg_namespace n on f.pronamespace = n.oid\n  left join pg_language l on f.prolang = l.oid\n  left join pg_type rt on rt.oid = f.prorettype\n  left join (\n    select\n      oid,\n      jsonb_object_agg(param, value) filter (\n        where\n          param is not null\n      ) as config_params\n    from\n      (\n        select\n          oid,\n          (string_to_array(unnest(proconfig), '=')) [1] as param,\n          (string_to_array(unnest(proconfig), '=')) [2] as value\n        from\n          functions\n      ) as t\n    group by\n      oid\n  ) f_config on f_config.oid = f.oid\n  left join (\n    select\n      oid,\n      jsonb_agg(\n        jsonb_build_object(\n          'mode',\n          t2.mode,\n          'name',\n          name,\n          'type_id',\n          type_id,\n          'has_default',\n          has_default\n        )\n      ) as args\n    from\n      (\n        select\n          oid,\n          arg_modes[i] as mode,\n          arg_names[i] as name,\n          arg_types[i] :: int8 as type_id,\n          arg_has_defaults[i] as has_default\n        from\n          functions,\n          pg_catalog.generate_subscripts(arg_names, 1) as i\n      ) as t1,\n      lateral (\n        select\n          case\n            when t1.mode = 'i' then 'in'\n            when t1.mode = 'o' then 'out'\n            when t1.mode = 'b' then 'inout'\n            when t1.mode = 'v' then 'variadic'\n            else 'table'\n          end as mode\n      ) as t2\n    group by\n      t1.oid\n  ) f_args on f_args.oid = f.oid;",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id!",
+        "type_info": "Int8"
+      },
+      {
+        "ordinal": 1,
+        "name": "schema!",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 2,
+        "name": "name!",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 3,
+        "name": "language!",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 4,
+        "name": "kind!",
+        "type_info": "Char"
+      },
+      {
+        "ordinal": 5,
+        "name": "body",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 6,
+        "name": "definition",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 7,
+        "name": "args",
+        "type_info": "Jsonb"
+      },
+      {
+        "ordinal": 8,
+        "name": "argument_types",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 9,
+        "name": "identity_argument_types",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 10,
+        "name": "return_type_id",
+        "type_info": "Int8"
+      },
+      {
+        "ordinal": 11,
+        "name": "return_type",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 12,
+        "name": "return_type_relation_id",
+        "type_info": "Int8"
+      },
+      {
+        "ordinal": 13,
+        "name": "is_set_returning_function!",
+        "type_info": "Bool"
+      },
+      {
+        "ordinal": 14,
+        "name": "behavior",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 15,
+        "name": "security_definer!",
+        "type_info": "Bool"
+      }
+    ],
+    "parameters": {
+      "Left": []
+    },
+    "nullable": [
+      null,
+      true,
+      true,
+      true,
+      true,
+      null,
+      null,
+      null,
+      null,
+      null,
+      null,
+      null,
+      null,
+      true,
+      null,
+      true
+    ]
+  },
+  "hash": "4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502"
+}
diff --git a/.sqlx/query-64d9718b07516f3d2720cb7aa79e496f5337cadbad7a3fb03ccd3e3c21b71389.json b/.sqlx/query-64d9718b07516f3d2720cb7aa79e496f5337cadbad7a3fb03ccd3e3c21b71389.json
deleted file mode 100644
index 43d634597..000000000
--- a/.sqlx/query-64d9718b07516f3d2720cb7aa79e496f5337cadbad7a3fb03ccd3e3c21b71389.json
+++ /dev/null
@@ -1,104 +0,0 @@
-{
-  "db_name": "PostgreSQL",
-  "query": "with functions as (\n  select\n    oid,\n    proname,\n    prosrc,\n    prorettype,\n    proretset,\n    provolatile,\n    prosecdef,\n    prolang,\n    pronamespace,\n    proconfig,\n    -- proargmodes is null when all arg modes are IN\n    coalesce(\n      p.proargmodes,\n      array_fill(\n        'i' :: text,\n        array [cardinality(coalesce(p.proallargtypes, p.proargtypes))]\n      )\n    ) as arg_modes,\n    -- proargnames is null when all args are unnamed\n    coalesce(\n      p.proargnames,\n      array_fill(\n        '' :: text,\n        array [cardinality(coalesce(p.proallargtypes, p.proargtypes))]\n      )\n    ) as arg_names,\n    -- proallargtypes is null when all arg modes are IN\n    coalesce(p.proallargtypes, p.proargtypes) as arg_types,\n    array_cat(\n      array_fill(false, array [pronargs - pronargdefaults]),\n      array_fill(true, array [pronargdefaults])\n    ) as arg_has_defaults\n  from\n    pg_proc as p\n  where\n    p.prokind = 'f'\n)\nselect\n  f.oid :: int8 as \"id!\",\n  n.nspname as \"schema!\",\n  f.proname as \"name!\",\n  l.lanname as \"language!\",\n  case\n    when l.lanname = 'internal' then null\n    else f.prosrc\n  end as body,\n  case\n    when l.lanname = 'internal' then null\n    else pg_get_functiondef(f.oid)\n  end as definition,\n  coalesce(f_args.args, '[]') as args,\n  nullif(pg_get_function_arguments(f.oid), '') as argument_types,\n  nullif(pg_get_function_identity_arguments(f.oid), '') as identity_argument_types,\n  f.prorettype :: int8 as \"return_type_id!\",\n  pg_get_function_result(f.oid) as \"return_type!\",\n  nullif(rt.typrelid :: int8, 0) as return_type_relation_id,\n  f.proretset as is_set_returning_function,\n  case\n    when f.provolatile = 'i' then 'IMMUTABLE'\n    when f.provolatile = 's' then 'STABLE'\n    when f.provolatile = 'v' then 'VOLATILE'\n  end as behavior,\n  f.prosecdef as security_definer\nfrom\n  functions f\n  left join pg_namespace n on f.pronamespace = n.oid\n  left join pg_language l on f.prolang = l.oid\n  left join pg_type rt on rt.oid = f.prorettype\n  left join (\n    select\n      oid,\n      jsonb_object_agg(param, value) filter (\n        where\n          param is not null\n      ) as config_params\n    from\n      (\n        select\n          oid,\n          (string_to_array(unnest(proconfig), '=')) [1] as param,\n          (string_to_array(unnest(proconfig), '=')) [2] as value\n        from\n          functions\n      ) as t\n    group by\n      oid\n  ) f_config on f_config.oid = f.oid\n  left join (\n    select\n      oid,\n      jsonb_agg(\n        jsonb_build_object(\n          'mode',\n          t2.mode,\n          'name',\n          name,\n          'type_id',\n          type_id,\n          'has_default',\n          has_default\n        )\n      ) as args\n    from\n      (\n        select\n          oid,\n          unnest(arg_modes) as mode,\n          unnest(arg_names) as name,\n          unnest(arg_types) :: int8 as type_id,\n          unnest(arg_has_defaults) as has_default\n        from\n          functions\n      ) as t1,\n      lateral (\n        select\n          case\n            when t1.mode = 'i' then 'in'\n            when t1.mode = 'o' then 'out'\n            when t1.mode = 'b' then 'inout'\n            when t1.mode = 'v' then 'variadic'\n            else 'table'\n          end as mode\n      ) as t2\n    group by\n      t1.oid\n  ) f_args on f_args.oid = f.oid;",
-  "describe": {
-    "columns": [
-      {
-        "ordinal": 0,
-        "name": "id!",
-        "type_info": "Int8"
-      },
-      {
-        "ordinal": 1,
-        "name": "schema!",
-        "type_info": "Name"
-      },
-      {
-        "ordinal": 2,
-        "name": "name!",
-        "type_info": "Name"
-      },
-      {
-        "ordinal": 3,
-        "name": "language!",
-        "type_info": "Name"
-      },
-      {
-        "ordinal": 4,
-        "name": "body",
-        "type_info": "Text"
-      },
-      {
-        "ordinal": 5,
-        "name": "definition",
-        "type_info": "Text"
-      },
-      {
-        "ordinal": 6,
-        "name": "args",
-        "type_info": "Jsonb"
-      },
-      {
-        "ordinal": 7,
-        "name": "argument_types",
-        "type_info": "Text"
-      },
-      {
-        "ordinal": 8,
-        "name": "identity_argument_types",
-        "type_info": "Text"
-      },
-      {
-        "ordinal": 9,
-        "name": "return_type_id!",
-        "type_info": "Int8"
-      },
-      {
-        "ordinal": 10,
-        "name": "return_type!",
-        "type_info": "Text"
-      },
-      {
-        "ordinal": 11,
-        "name": "return_type_relation_id",
-        "type_info": "Int8"
-      },
-      {
-        "ordinal": 12,
-        "name": "is_set_returning_function",
-        "type_info": "Bool"
-      },
-      {
-        "ordinal": 13,
-        "name": "behavior",
-        "type_info": "Text"
-      },
-      {
-        "ordinal": 14,
-        "name": "security_definer",
-        "type_info": "Bool"
-      }
-    ],
-    "parameters": {
-      "Left": []
-    },
-    "nullable": [
-      null,
-      true,
-      false,
-      true,
-      null,
-      null,
-      null,
-      null,
-      null,
-      null,
-      null,
-      null,
-      false,
-      null,
-      false
-    ]
-  },
-  "hash": "64d9718b07516f3d2720cb7aa79e496f5337cadbad7a3fb03ccd3e3c21b71389"
-}
diff --git a/.sqlx/query-b0504a4340264403ad43d05c60d053db65ea6a7529e2cb97b2d3432a18aff6ba.json b/.sqlx/query-b0504a4340264403ad43d05c60d053db65ea6a7529e2cb97b2d3432a18aff6ba.json
deleted file mode 100644
index dfc842b70..000000000
--- a/.sqlx/query-b0504a4340264403ad43d05c60d053db65ea6a7529e2cb97b2d3432a18aff6ba.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "db_name": "PostgreSQL",
-  "query": "select rolname from pg_catalog.pg_roles;",
-  "describe": {
-    "columns": [
-      {
-        "ordinal": 0,
-        "name": "rolname",
-        "type_info": "Name"
-      }
-    ],
-    "parameters": {
-      "Left": []
-    },
-    "nullable": [
-      true
-    ]
-  },
-  "hash": "b0504a4340264403ad43d05c60d053db65ea6a7529e2cb97b2d3432a18aff6ba"
-}

From 0e5f425b2af342dad9d71b4cbd2b31b9f7e32686 Mon Sep 17 00:00:00 2001
From: Julian Domke <68325451+juleswritescode@users.noreply.github.com>
Date: Tue, 10 Jun 2025 18:11:09 +0200
Subject: [PATCH 8/8] Update crates/pgt_schema_cache/src/functions.rs

---
 crates/pgt_schema_cache/src/functions.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/crates/pgt_schema_cache/src/functions.rs b/crates/pgt_schema_cache/src/functions.rs
index 8f5f7d869..4afaa76dd 100644
--- a/crates/pgt_schema_cache/src/functions.rs
+++ b/crates/pgt_schema_cache/src/functions.rs
@@ -225,7 +225,6 @@ mod tests {
             .find(|f| f.name == "my_cool_proc")
             .unwrap();
 
-        println!("{:?}", proc_fn);
         assert_eq!(proc_fn.kind, ProcKind::Procedure);
         assert_eq!(proc_fn.language, "plpgsql");
         assert!(!proc_fn.security_definer);
