4

I am trying to use a parameter passed into a PostgreSQL query inside a DO block within that query. It fails though, and seems to be parsing the statement as if the parameter was a column. Is it possible to reference a query parameter in this way?

Here is my C# code (using Npgsql and Dapper as well):

private static async Task ParameterInDoBlock(IDbConnection postgresConn)
{
    DynamicParameters queryParams = new DynamicParameters();
    queryParams.Add("some_variable", 123);
//example of successfully using a parameter    
string sql = @"SELECT @some_variable;";
var row = await postgresConn.QuerySingleOrDefaultAsync<dynamic>(sql, queryParams);
Console.WriteLine($"Simple select: {row}");

//this one unexpectedly fails
sql = @"
DO
$$
BEGIN
    IF @some_variable = 1 THEN
        RAISE EXCEPTION 'blah';
    END IF;
END
$$;";
await postgresConn.QuerySingleOrDefaultAsync<dynamic>(sql, queryParams);
/*
Exception data:
 Severity: ERROR
 SqlState: 42703
 MessageText: column "some_variable" does not exist
 InternalPosition: 2
 InternalQuery: @some_variable = 1
 Where: PL/pgSQL function inline_code_block line 3 at IF
 File: parse_relation.c
 Line: 3633
 Routine: errorMissingColumn
*/

}

Anssssss
  • 248
  • 1
  • 11

2 Answers2

3

Parameters can only be used in SELECT, INSERT, UPDATE and DELETE. I can think of two solutions:

  1. write a database function in PL/pgSQL, have the parameter be a function parameter and use a parameterized statement in a SELECT statement that calls the function

  2. compose a string that contains the actual value instead of a parameter and execute that (but take care that your code is not vulnerable to SQL injection)

Laurenz Albe
  • 61,070
  • 4
  • 55
  • 90
2

@Laurenz-Albe, thanks for the answer. I liked the first option better (prefer parameterized queries), so here is what I would end up with:

sql = @"
--create temp function to hold code
CREATE OR REPLACE FUNCTION pg_temp.some_function(x int) RETURNS VOID
LANGUAGE plpgsql
AS
$$
BEGIN
    --just the example code I was trying to do before
    IF x = 1 THEN
        RAISE EXCEPTION 'blah';
    END IF;
END
$$;

SELECT pg_temp.some_function(@some_variable); "; await postgresConn.QuerySingleOrDefaultAsync<dynamic>(sql, queryParams);

Anssssss
  • 248
  • 1
  • 11