SET LOCAL working as expected with multi-statement batch query but raising warning in Postgres
See original GitHub issueSteps to reproduce
From the C# side, this code is working exactly as expected:
using var connection = new NpgsqlConnection(connectionString);
await connection.OpenAsync();
Console.WriteLine("*** SET LOCAL ***");
// with SET LOCAL, the SET persists to the end of the batch but does not leak into subsequent commands
Console.WriteLine(await ExecuteAsync("SET LOCAL lock_timeout = 12345; CREATE TEMPORARY TABLE temp_table (id INT); SHOW lock_timeout;")); // 12345ms
Console.WriteLine(await ExecuteAsync("SHOW lock_timeout;")); // 0
Console.WriteLine(await ExecuteAsync("SET LOCAL lock_timeout = 456; SELECT 'x'")); // 'x'
Console.WriteLine(await ExecuteAsync("SHOW lock_timeout")); // 0
Console.WriteLine("*** SET ***");
// with SET, the SET persists for the lifetime of the connection
Console.WriteLine(await ExecuteAsync("SET lock_timeout = 987; CREATE TEMPORARY TABLE temp_table2 (id INT); SHOW lock_timeout;")); // 987ms
Console.WriteLine(await ExecuteAsync("SHOW lock_timeout;")); // 987ms (leak!)
Console.WriteLine(await ExecuteAsync("SET lock_timeout = 654; SELECT 'x'")); // 'x'
Console.WriteLine(await ExecuteAsync("SHOW lock_timeout")); // 654ms (leak!)
async Task<string> ExecuteAsync(string sql)
{
using var command = connection.CreateCommand();
command.CommandText = sql;
return (string)await command.ExecuteScalarAsync();
}
The issue
However, this same code logs a warning on the Postgres side that is visible in the postgres logs:
WARNING: SET LOCAL can only be used in transaction blocks
Apologies in advance if this is just revealing my lack of understanding when it comes to Postgres functionality. It feels weird to me that working code would produce a warning and that the seeming alternative does not work as desired. This could also be an issue to report to Postgres, but I wanted to check here first because I know that Npgsql does some explicit handling of multi-statement queries (e. g. https://github.com/npgsql/npgsql/blob/main/src/Npgsql/SqlQueryParser.cs#L17) that I thought could be impacting this behavior.
Further technical details
Npgsql version: 5.0.4 PostgreSQL version: 12 Operating system: Windows 10
Issue Analytics
- State:
- Created 2 years ago
- Comments:11 (9 by maintainers)
Done
Here’s the thread if you want to follow along: https://www.postgresql.org/message-id/flat/16988-58edba102adb5128%40postgresql.org
The issue is probably with extended query protocol.
What Tom Lane was simulating via psql is essentially sending the whole query string as simple query via
PQexec
. As he expected, this does not match what Npgsql is doing at the wire protocol level.Npqsql uses the extended query protocol and sends the two queries separately without syncing in-between them in a way that resembles the new pipeline mode in libpq.
I’m not entirely sure if it is a Npgsql issue or a PostgreSQL issue but at least the problem can be reproduced via libpq (currently unreleased PG 14 version) with the following small program (for brevity I’ve omitted any error checking):