@@ -58,13 +58,11 @@ pub fn setvar(name: &str, value: &str) -> String {
5858 pgrx:: error!( "df.setvar() cannot be called inside a workflow - set variables before starting the workflow" ) ;
5959 }
6060
61- let sql = format ! (
62- "INSERT INTO df.vars (name, value) VALUES ('{}', '{}' )
61+ if let Err ( e ) = Spi :: run_with_args (
62+ "INSERT INTO df.vars (name, value) VALUES ($1, $2 )
6363 ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value" ,
64- name. replace( '\'' , "''" ) ,
65- value. replace( '\'' , "''" )
66- ) ;
67- if let Err ( e) = Spi :: run ( & sql) {
64+ & [ name. into ( ) , value. into ( ) ] ,
65+ ) {
6866 pgrx:: error!( "Failed to set variable: {:?}" , e) ;
6967 }
7068 "OK" . to_string ( )
@@ -73,11 +71,12 @@ pub fn setvar(name: &str, value: &str) -> String {
7371/// Gets a workflow variable value.
7472#[ pg_extern( schema = "df" ) ]
7573pub fn getvar ( name : & str ) -> Option < String > {
76- let sql = format ! (
77- "SELECT value FROM df.vars WHERE name = '{}'" ,
78- name. replace( '\'' , "''" )
79- ) ;
80- Spi :: get_one :: < String > ( & sql) . ok ( ) . flatten ( )
74+ Spi :: get_one_with_args :: < String > (
75+ "SELECT value FROM df.vars WHERE name = $1" ,
76+ & [ name. into ( ) ] ,
77+ )
78+ . ok ( )
79+ . flatten ( )
8180}
8281
8382/// Removes a workflow variable.
@@ -88,11 +87,10 @@ pub fn unsetvar(name: &str) -> String {
8887 pgrx:: error!( "df.unsetvar() cannot be called inside a workflow - manage variables before starting the workflow" ) ;
8988 }
9089
91- let sql = format ! (
92- "DELETE FROM df.vars WHERE name = '{}'" ,
93- name. replace( '\'' , "''" )
94- ) ;
95- if let Err ( e) = Spi :: run ( & sql) {
90+ if let Err ( e) = Spi :: run_with_args (
91+ "DELETE FROM df.vars WHERE name = $1" ,
92+ & [ name. into ( ) ] ,
93+ ) {
9694 pgrx:: error!( "Failed to unset variable: {:?}" , e) ;
9795 }
9896 "OK" . to_string ( )
@@ -464,10 +462,10 @@ pub fn signal(instance_id: &str, signal_name: &str, signal_data: default!(&str,
464462
465463 // Ownership check: SPI goes through RLS, so this returns false for
466464 // non-owned instances (the row is invisible to the calling user).
467- let exists: bool = Spi :: get_one ( & format ! (
468- "SELECT EXISTS(SELECT 1 FROM df.instances WHERE id = '{}' )" ,
469- instance_id. replace ( '\'' , "''" )
470- ) )
465+ let exists: bool = Spi :: get_one_with_args (
466+ "SELECT EXISTS(SELECT 1 FROM df.instances WHERE id = $1 )" ,
467+ & [ instance_id. into ( ) ] ,
468+ )
471469 . ok ( )
472470 . flatten ( )
473471 . unwrap_or ( false ) ;
@@ -508,10 +506,10 @@ pub fn start(
508506
509507 // Validate that the target database exists (if specified)
510508 if let Some ( db) = database {
511- let exists: bool = match Spi :: get_one ( & format ! (
512- "SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = '{}' )" ,
513- db. replace ( '\'' , "''" )
514- ) ) {
509+ let exists: bool = match Spi :: get_one_with_args (
510+ "SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = $1 )" ,
511+ & [ db. into ( ) ] ,
512+ ) {
515513 Ok ( Some ( v) ) => v,
516514 Ok ( None ) => false ,
517515 Err ( e) => pgrx:: error!( "failed to check database existence: {}" , e) ,
@@ -684,10 +682,10 @@ pub fn cancel(instance_id: &str, reason: default!(&str, "'Cancelled by user'"))
684682
685683 // Ownership check: SPI goes through RLS, so this returns false for
686684 // non-owned instances (the row is invisible to the calling user).
687- let exists: bool = Spi :: get_one ( & format ! (
688- "SELECT EXISTS(SELECT 1 FROM df.instances WHERE id = '{}' )" ,
689- instance_id. replace ( '\'' , "''" )
690- ) )
685+ let exists: bool = Spi :: get_one_with_args (
686+ "SELECT EXISTS(SELECT 1 FROM df.instances WHERE id = $1 )" ,
687+ & [ instance_id. into ( ) ] ,
688+ )
691689 . ok ( )
692690 . flatten ( )
693691 . unwrap_or ( false ) ;
@@ -701,10 +699,10 @@ pub fn cancel(instance_id: &str, reason: default!(&str, "'Cancelled by user'"))
701699
702700 // Update the instance status to 'cancelled' via SPI.
703701 // User has column-level UPDATE on (status, updated_at) with RLS restricting to own rows.
704- Spi :: run ( & format ! (
705- "UPDATE df.instances SET status = 'cancelled', updated_at = now() WHERE id = '{}' " ,
706- instance_id. replace ( '\'' , "''" )
707- ) )
702+ Spi :: run_with_args (
703+ "UPDATE df.instances SET status = 'cancelled', updated_at = now() WHERE id = $1 " ,
704+ & [ instance_id. into ( ) ] ,
705+ )
708706 . unwrap_or_else ( |e| warning ! ( "Failed to update instance status: {e}" ) ) ;
709707
710708 format ! ( "Instance {instance_id} cancelled: {reason}" )
@@ -713,11 +711,12 @@ pub fn cancel(instance_id: &str, reason: default!(&str, "'Cancelled by user'"))
713711/// Gets the status of a durable function instance.
714712#[ pg_extern( schema = "df" ) ]
715713pub fn status ( instance_id : & str ) -> Option < String > {
716- let sql = format ! (
717- "SELECT status FROM df.instances WHERE id = '{}'" ,
718- instance_id. replace( '\'' , "''" )
719- ) ;
720- Spi :: get_one :: < String > ( & sql) . ok ( ) . flatten ( )
714+ Spi :: get_one_with_args :: < String > (
715+ "SELECT status FROM df.instances WHERE id = $1" ,
716+ & [ instance_id. into ( ) ] ,
717+ )
718+ . ok ( )
719+ . flatten ( )
721720}
722721
723722/// Manually runs pending durable functions.
@@ -733,13 +732,14 @@ pub fn run(instance_id: default!(Option<&str>, "NULL")) -> String {
733732/// Gets the result of a completed durable function.
734733#[ pg_extern( schema = "df" ) ]
735734pub fn result ( instance_id : & str ) -> Option < String > {
736- let escaped_instance_id = instance_id. replace ( '\'' , "''" ) ;
737- let sql = format ! (
738- r#"SELECT result::text FROM df.nodes
739- WHERE id = (SELECT root_node FROM df.instances WHERE id = '{escaped_instance_id}')
740- AND status = 'completed'"#
741- ) ;
742- Spi :: get_one :: < String > ( & sql) . ok ( ) . flatten ( )
735+ Spi :: get_one_with_args :: < String > (
736+ r#"SELECT result::text FROM df.nodes
737+ WHERE id = (SELECT root_node FROM df.instances WHERE id = $1)
738+ AND status = 'completed'"# ,
739+ & [ instance_id. into ( ) ] ,
740+ )
741+ . ok ( )
742+ . flatten ( )
743743}
744744
745745/// Waits for a durable function to complete, returning its final status.
@@ -772,13 +772,11 @@ pub fn wait_for_completion(
772772
773773 loop {
774774 // Query instance status
775- let sql = format ! (
776- "SELECT status FROM df.instances WHERE id = '{}'" ,
777- instance_id. replace( '\'' , "''" )
778- ) ;
779-
780- let status: Option < String > =
781- Spi :: get_one ( & sql) . map_err ( |e| format ! ( "Failed to query status: {:?}" , e) ) ?;
775+ let status: Option < String > = Spi :: get_one_with_args (
776+ "SELECT status FROM df.instances WHERE id = $1" ,
777+ & [ instance_id. into ( ) ] ,
778+ )
779+ . map_err ( |e| format ! ( "Failed to query status: {:?}" , e) ) ?;
782780
783781 if let Some ( ref s) = status {
784782 let s_lower = s. to_lowercase ( ) ;
0 commit comments