From: Tom Lane Date: Mon, 25 Jul 2022 19:45:24 +0000 (-0400) Subject: Add test for session_preload_libraries and parameter permissions checks. X-Git-Tag: REL_15_BETA3~51 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e1bd4990b2b599b2de7ae531516660c86fbb910b;p=thirdparty%2Fpostgresql.git Add test for session_preload_libraries and parameter permissions checks. We weren't exercising the session_preload_libraries option in any meaningful way. auto_explain is a good testbed for doing so, since it's one of the primary use-cases for session_preload_libraries. Hence, adjust its TAP test to load the library via session_preload_libraries not shared_preload_libraries. While at it, feed test-specific settings to the backend via PGOPTIONS rather than tediously rewriting postgresql.conf. Also, since auto_explain has some PGC_SUSET parameters, we can use it to provide a test case for the permissions-checking bug just fixed by commit b35617de3. Back-patch to v15 so that we have coverage for the permissions issue in that branch too. To do that, I back-patched the refactoring recently done by commit 550bc0a6c. Dagfinn Ilmari Mannsåker and Tom Lane Discussion: https://postgr.es/m/CABwTF4VEpwTHhRQ+q5MiC5ucngN-whN-PdcKeufX7eLSoAfbZA@mail.gmail.com --- diff --git a/contrib/auto_explain/t/001_auto_explain.pl b/contrib/auto_explain/t/001_auto_explain.pl index 82e4d9d15cd..b34de5f3a87 100644 --- a/contrib/auto_explain/t/001_auto_explain.pl +++ b/contrib/auto_explain/t/001_auto_explain.pl @@ -8,50 +8,141 @@ use PostgreSQL::Test::Cluster; use PostgreSQL::Test::Utils; use Test::More; +# Runs the specified query and returns the emitted server log. +# params is an optional hash mapping GUC names to values; +# any such settings are transmitted to the backend via PGOPTIONS. +sub query_log +{ + my ($node, $sql, $params) = @_; + $params ||= {}; + + local $ENV{PGOPTIONS} = join " ", + map { "-c $_=$params->{$_}" } keys %$params; + + my $log = $node->logfile(); + my $offset = -s $log; + + $node->safe_psql("postgres", $sql); + + return slurp_file($log, $offset); +} + my $node = PostgreSQL::Test::Cluster->new('main'); $node->init; $node->append_conf('postgresql.conf', - "shared_preload_libraries = 'auto_explain'"); + "session_preload_libraries = 'auto_explain'"); $node->append_conf('postgresql.conf', "auto_explain.log_min_duration = 0"); $node->append_conf('postgresql.conf', "auto_explain.log_analyze = on"); $node->start; -# run a couple of queries -$node->safe_psql("postgres", "SELECT * FROM pg_class;"); -$node->safe_psql("postgres", - "SELECT * FROM pg_proc WHERE proname = 'int4pl';"); +# Simple query. +my $log_contents = query_log($node, "SELECT * FROM pg_class;"); -# emit some json too -$node->append_conf('postgresql.conf', "auto_explain.log_format = json"); -$node->reload; -$node->safe_psql("postgres", "SELECT * FROM pg_proc;"); -$node->safe_psql("postgres", - "SELECT * FROM pg_class WHERE relname = 'pg_class';"); - -$node->stop('fast'); - -my $log = $node->logfile(); +like( + $log_contents, + qr/Query Text: SELECT \* FROM pg_class;/, + "query text logged, text mode"); -my $log_contents = slurp_file($log); +unlike( + $log_contents, + qr/Query Parameters:/, + "no query parameters logged when none, text mode"); like( $log_contents, qr/Seq Scan on pg_class/, "sequential scan logged, text mode"); +# Prepared query. +$log_contents = query_log($node, + q{PREPARE get_proc(name) AS SELECT * FROM pg_proc WHERE proname = $1; EXECUTE get_proc('int4pl');} +); + +like( + $log_contents, + qr/Query Text: PREPARE get_proc\(name\) AS SELECT \* FROM pg_proc WHERE proname = \$1;/, + "prepared query text logged, text mode"); + like( $log_contents, qr/Index Scan using pg_proc_proname_args_nsp_index on pg_proc/, "index scan logged, text mode"); + +# JSON format. +$log_contents = query_log( + $node, + "SELECT * FROM pg_class;", + { "auto_explain.log_format" => "json" }); + +like( + $log_contents, + qr/"Query Text": "SELECT \* FROM pg_class;"/, + "query text logged, json mode"); + +unlike( + $log_contents, + qr/"Query Parameters":/, + "query parameters not logged when none, json mode"); + like( $log_contents, - qr/"Node Type": "Seq Scan"[^}]*"Relation Name": "pg_proc"/s, + qr/"Node Type": "Seq Scan"[^}]*"Relation Name": "pg_class"/s, "sequential scan logged, json mode"); +# Prepared query in JSON format. +$log_contents = query_log( + $node, + q{PREPARE get_class(name) AS SELECT * FROM pg_class WHERE relname = $1; EXECUTE get_class('pg_class');}, + { "auto_explain.log_format" => "json" }); + +like( + $log_contents, + qr/"Query Text": "PREPARE get_class\(name\) AS SELECT \* FROM pg_class WHERE relname = \$1;"/, + "prepared query text logged, json mode"); + like( $log_contents, qr/"Node Type": "Index Scan"[^}]*"Index Name": "pg_class_relname_nsp_index"/s, "index scan logged, json mode"); +# Check that PGC_SUSET parameters can be set by non-superuser if granted, +# otherwise not + +$node->safe_psql( + "postgres", q{ +CREATE USER regress_user1; +GRANT SET ON PARAMETER auto_explain.log_format TO regress_user1; +}); + +$ENV{PGUSER} = "regress_user1"; + +$log_contents = query_log( + $node, + "SELECT * FROM pg_database;", + { "auto_explain.log_format" => "json" }); + +like( + $log_contents, + qr/"Query Text": "SELECT \* FROM pg_database;"/, + "query text logged, json mode selected by non-superuser"); + +$log_contents = query_log( + $node, + "SELECT * FROM pg_database;", + { "auto_explain.log_level" => "log" }); + +like( + $log_contents, + qr/WARNING: permission denied to set parameter "auto_explain\.log_level"/, + "permission failure logged"); + +$ENV{PGUSER} = undef; + +$node->safe_psql( + "postgres", q{ +REVOKE SET ON PARAMETER auto_explain.log_format FROM regress_user1; +DROP USER regress_user1; +}); + done_testing();