|
12 | 12 |
|
13 | 13 | /* Includes */ |
14 | 14 | #include "postgres.h" |
15 | | -/* Comments just indicate which includes are still in use. */ |
16 | | -#include "commands/explain.h" /* To explain statements. */ |
17 | | -#include "fmgr.h" /* PG_RETURN_VOID() */ |
18 | | -#include "funcapi.h" /* To return sets in SQL funcs. */ |
19 | | -#include "lib/stringinfo.h" /* StringInfo */ |
20 | | -#include "miscadmin.h" /* process_shared_preload_libraries_in_progress */ |
21 | | -#include "storage/ipc.h" /* shmem_startup_hook_type */ |
22 | | -#include "storage/lwlock.h" /* Locking mechanism, for shared data safety. */ |
23 | | -#include "storage/shmem.h" /* RequestAddinShmemSpace() */ |
24 | | -#include "utils/builtins.h" /* CStringGetTextDatum() */ |
25 | | -#include "utils/guc.h" /* For GUC variables. */ |
26 | 15 |
|
| 16 | +#include "catalog/pg_authid.h" |
| 17 | +#include "commands/explain.h" |
| 18 | +#include "fmgr.h" |
| 19 | +#include "funcapi.h" |
| 20 | +#include "lib/stringinfo.h" |
| 21 | +#include "miscadmin.h" |
| 22 | +#include "storage/ipc.h" |
| 23 | +#include "storage/lwlock.h" |
| 24 | +#include "storage/shmem.h" |
| 25 | +#include "utils/acl.h" |
| 26 | +#include "utils/builtins.h" |
| 27 | +#include "utils/guc.h" |
27 | 28 |
|
28 | 29 | /* Constants and Macros */ |
29 | 30 | PG_MODULE_MAGIC; |
@@ -83,6 +84,12 @@ static pgspEntry *create_hash_entry(const pgspHashKey *key); |
83 | 84 | static void append_query_plan(ExplainState *es); |
84 | 85 | /* on_shmem_exit() callback to delete hash entry on client disconnect. */ |
85 | 86 | static void cleanup(int code, Datum arg); |
| 87 | +/* Set extension state, either enable or disable. */ |
| 88 | +static void set_state(const bool state); |
| 89 | +/* Set query plan output format: text, json, ... */ |
| 90 | +static void set_format(const int format); |
| 91 | +/* Check whether the user has required privileges. */ |
| 92 | +static bool is_allowed_role(void); |
86 | 93 | /* Hook functions. */ |
87 | 94 | /* Ask for shared memory. */ |
88 | 95 | #if PG_VERSION_NUM >= 150000 |
@@ -314,6 +321,33 @@ void cleanup(int code, Datum arg) |
314 | 321 | LWLockRelease(pgsp->lock); |
315 | 322 | } |
316 | 323 |
|
| 324 | +void |
| 325 | +set_state(const bool state) |
| 326 | +{ |
| 327 | + if (is_allowed_role()) |
| 328 | + pgsp->is_enabled = state; |
| 329 | +} |
| 330 | + |
| 331 | +void |
| 332 | +set_format(const int format) |
| 333 | +{ |
| 334 | + if (is_allowed_role()) |
| 335 | + pgsp->plan_format = format; |
| 336 | +} |
| 337 | + |
| 338 | +bool |
| 339 | +is_allowed_role(void) |
| 340 | +{ |
| 341 | + bool is_allowed_role = false; |
| 342 | +#if PG_VERSION_NUM >= 140000 |
| 343 | + is_allowed_role = is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS); |
| 344 | +#else |
| 345 | + is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS); |
| 346 | +#endif |
| 347 | + return is_allowed_role; |
| 348 | + |
| 349 | +} |
| 350 | + |
317 | 351 | #if PG_VERSION_NUM >= 150000 |
318 | 352 | void |
319 | 353 | pgvp_shmem_request(void) |
@@ -431,42 +465,42 @@ pgsp_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, |
431 | 465 | Datum |
432 | 466 | pg_show_plans_enable(PG_FUNCTION_ARGS) |
433 | 467 | { |
434 | | - pgsp->is_enabled = true; |
| 468 | + set_state(true); |
435 | 469 | PG_RETURN_VOID(); |
436 | 470 | } |
437 | 471 |
|
438 | 472 | Datum |
439 | 473 | pg_show_plans_disable(PG_FUNCTION_ARGS) |
440 | 474 | { |
441 | | - pgsp->is_enabled = false; |
| 475 | + set_state(false); |
442 | 476 | PG_RETURN_VOID(); |
443 | 477 | } |
444 | 478 |
|
445 | 479 | Datum |
446 | 480 | pgsp_format_text(PG_FUNCTION_ARGS) |
447 | 481 | { |
448 | | - pgsp->plan_format = EXPLAIN_FORMAT_TEXT; |
| 482 | + set_format(EXPLAIN_FORMAT_TEXT); |
449 | 483 | PG_RETURN_VOID(); |
450 | 484 | } |
451 | 485 |
|
452 | 486 | Datum |
453 | 487 | pgsp_format_json(PG_FUNCTION_ARGS) |
454 | 488 | { |
455 | | - pgsp->plan_format = EXPLAIN_FORMAT_JSON; |
| 489 | + set_format(EXPLAIN_FORMAT_JSON); |
456 | 490 | PG_RETURN_VOID(); |
457 | 491 | } |
458 | 492 |
|
459 | 493 | Datum |
460 | 494 | pgsp_format_yaml(PG_FUNCTION_ARGS) |
461 | 495 | { |
462 | | - pgsp->plan_format = EXPLAIN_FORMAT_YAML; |
| 496 | + set_format(EXPLAIN_FORMAT_YAML); |
463 | 497 | PG_RETURN_VOID(); |
464 | 498 | } |
465 | 499 |
|
466 | 500 | Datum |
467 | 501 | pgsp_format_xml(PG_FUNCTION_ARGS) |
468 | 502 | { |
469 | | - pgsp->plan_format = EXPLAIN_FORMAT_XML; |
| 503 | + set_format(EXPLAIN_FORMAT_XML); |
470 | 504 | PG_RETURN_VOID(); |
471 | 505 | } |
472 | 506 |
|
@@ -530,8 +564,15 @@ pg_show_plans(PG_FUNCTION_ARGS) |
530 | 564 | if (is_done) /* Done processing a hash entry? */ |
531 | 565 | { /* Grab a new one. */ |
532 | 566 | pgvp_tmp_entry = hash_seq_search(hash_seq); |
533 | | - /* Skip empty entries. */ |
534 | | - while (pgvp_tmp_entry->n_plans < 1) { |
| 567 | + /* Skip empty entries and the ones the user is not |
| 568 | + * allowed to see. */ |
| 569 | + for (;;) { |
| 570 | + if (pgvp_tmp_entry->n_plans >= 1) { |
| 571 | + if (is_allowed_role()) |
| 572 | + break; |
| 573 | + else if (pgvp_tmp_entry->user_id == GetUserId()) |
| 574 | + break; |
| 575 | + } |
535 | 576 | if (call_cntr == max_calls-1) { /* No more entries. */ |
536 | 577 | hash_seq_term(hash_seq); |
537 | 578 | LWLockRelease(pgsp->lock); |
|
0 commit comments