diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index a85f962801..207c4362af 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -295,6 +295,7 @@ static bool pgss_save; /* whether to save stats across shutdown */ void _PG_init(void); void _PG_fini(void); +JumbleState *_PG_calculate_query_id(Query *query, const char *querytext); PG_FUNCTION_INFO_V1(pg_stat_statements_reset); PG_FUNCTION_INFO_V1(pg_stat_statements_reset_1_7); @@ -478,6 +479,13 @@ _PG_fini(void) ProcessUtility_hook = prev_ProcessUtility; } +/* Test queryid provider function */ +JumbleState *_PG_calculate_query_id(Query *query, const char *querytext) +{ + elog(LOG, "Called query id generatr of pg_stat_statements"); + return DefaultJumbleQuery(query, querytext); +} + /* * shmem_startup hook: allocate or attach to shared memory, * then load any pre-existing statistics from file. @@ -544,6 +552,11 @@ pgss_shmem_startup(void) if (!IsUnderPostmaster) on_shmem_exit(pgss_shmem_shutdown, (Datum) 0); + /* request my defalt provider, but allow exisint one */ + if (!queryIdWanted("pg_stat_statements", true)) + ereport(ERROR, + (errmsg ("query_id provider is not available"))); + /* * Done if some other process already completed our initialization. */ diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 1202bf85a3..be00564221 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -245,8 +245,7 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, es->summary = (summary_set) ? es->summary : es->analyze; query = castNode(Query, stmt->query); - if (compute_query_id) - jstate = JumbleQuery(query, pstate->p_sourcetext); + jstate = JumbleQuery(query, pstate->p_sourcetext); if (post_parse_analyze_hook) (*post_parse_analyze_hook) (pstate, query, jstate); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 168198acd1..bdf3a5a6d1 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -124,8 +124,7 @@ parse_analyze(RawStmt *parseTree, const char *sourceText, query = transformTopLevelStmt(pstate, parseTree); - if (compute_query_id) - jstate = JumbleQuery(query, sourceText); + jstate = JumbleQuery(query, sourceText); if (post_parse_analyze_hook) (*post_parse_analyze_hook) (pstate, query, jstate); @@ -163,8 +162,7 @@ parse_analyze_varparams(RawStmt *parseTree, const char *sourceText, /* make sure all is well with parameter types */ check_variable_parameters(pstate, query); - if (compute_query_id) - jstate = JumbleQuery(query, sourceText); + jstate = JumbleQuery(query, sourceText); if (post_parse_analyze_hook) (*post_parse_analyze_hook) (pstate, query, jstate); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6200699ddd..1034dfea28 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -704,8 +704,7 @@ pg_analyze_and_rewrite_params(RawStmt *parsetree, query = transformTopLevelStmt(pstate, parsetree); - if (compute_query_id) - jstate = JumbleQuery(query, query_string); + jstate = JumbleQuery(query, query_string); if (post_parse_analyze_hook) (*post_parse_analyze_hook) (pstate, query, jstate); diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index eb7f7181e4..70d06b825e 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -101,6 +101,7 @@ #include "utils/plancache.h" #include "utils/portal.h" #include "utils/ps_status.h" +#include "utils/queryjumble.h" #include "utils/rls.h" #include "utils/snapmgr.h" #include "utils/tzparser.h" @@ -534,7 +535,6 @@ extern const struct config_enum_entry dynamic_shared_memory_options[]; /* * GUC option variables that are exported from this module */ -bool compute_query_id = false; bool log_duration = false; bool Debug_print_plan = false; bool Debug_print_parse = false; @@ -1441,15 +1441,6 @@ static struct config_bool ConfigureNamesBool[] = true, NULL, NULL, NULL }, - { - {"compute_query_id", PGC_SUSET, STATS_MONITORING, - gettext_noop("Compute query identifiers."), - NULL - }, - &compute_query_id, - false, - NULL, NULL, NULL - }, { {"log_parser_stats", PGC_SUSET, STATS_MONITORING, gettext_noop("Writes parser performance statistics to the server log."), @@ -4579,6 +4570,16 @@ static struct config_string ConfigureNamesString[] = check_backtrace_functions, assign_backtrace_functions, NULL }, + + { + {"query_id_provider", PGC_SUSET, CLIENT_CONN_PRELOAD, + gettext_noop("Sets the query-id provider."), + }, + &query_id_provider, + "auto", + check_query_id_provider, assign_query_id_provider, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index efde01ee56..fc31ce15c4 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -604,7 +604,7 @@ # - Monitoring - -#compute_query_id = off +#query_id_provider = 'auto' #log_statement_stats = off #log_parser_stats = off #log_planner_stats = off diff --git a/src/backend/utils/misc/queryjumble.c b/src/backend/utils/misc/queryjumble.c index f004a9ce8c..709d654ea0 100644 --- a/src/backend/utils/misc/queryjumble.c +++ b/src/backend/utils/misc/queryjumble.c @@ -47,6 +47,96 @@ static void JumbleRangeTable(JumbleState *jstate, List *rtable); static void JumbleRowMarks(JumbleState *jstate, List *rowMarks); static void JumbleExpr(JumbleState *jstate, Node *node); static void RecordConstLocation(JumbleState *jstate, int location); +static JumbleState *DummyJumbleQuery(Query *query, const char *querytext); + +char *query_id_provider = NULL; +static bool lock_provider = false; + +typedef JumbleState *(*JumbleQueryType) (Query *query, const char *querytext); +JumbleQueryType JumbleQuery = NULL; + +typedef struct QueryIdProviderExtra +{ + JumbleQueryType pfunc; +} QueryIdProviderExtra; + +bool +check_query_id_provider(char **newval, void **extra, GucSource source) +{ + QueryIdProviderExtra *param = NULL; + + if (lock_provider) + return false; + + param = (QueryIdProviderExtra *)malloc(sizeof(QueryIdProviderExtra)); + if (param == NULL) + return false; + + if (strcmp(*newval, "none") == 0 || + strcmp(*newval, "auto") == 0) + param->pfunc = DummyJumbleQuery; + else if (strcmp(*newval, "default") == 0) + param->pfunc = DefaultJumbleQuery; + else + param->pfunc = + load_external_function(*newval, "_PG_calculate_query_id", + false, NULL); + + if (param->pfunc == NULL) + { + free(param); + param = NULL; + GUC_check_errdetail("failed to load query id provider"); + return false; + } + + *extra = (void *) param; + return true; +} + +void +assign_query_id_provider(const char *newval, void *extra) +{ + QueryIdProviderExtra *param = (QueryIdProviderExtra *)extra; + + JumbleQuery = param->pfunc; +} + +bool +queryIdWanted(char *provider_name, bool use_existing) +{ + JumbleQueryType func; + + Assert(query_id_provider != NULL); + Assert(JumbleQuery != NULL); + + if (lock_provider || strcmp(query_id_provider, "none") == 0) + return false; + + /* use existing provider when use_existing */ + if (strcmp(query_id_provider, "auto") != 0 && use_existing) + return true; + + if (strcmp(provider_name, "default") == 0) + func = DefaultJumbleQuery; + else + func = load_external_function(provider_name, "_PG_calculate_query_id", + false, NULL); + + if (func == NULL) + return false; + + elog(LOG, "query-id provider \"%s\" loaded", provider_name); + JumbleQuery = func; + + /* expose real provider name */ + SetConfigOption("query_id_provider", provider_name, + PGC_POSTMASTER, PGC_S_OVERRIDE); + + lock_provider = true; + + return true; +} /* * Given a possibly multi-statement source string, confine our attention to the @@ -92,7 +182,7 @@ CleanQuerytext(const char *query, int *location, int *len) } JumbleState * -JumbleQuery(Query *query, const char *querytext) +DefaultJumbleQuery(Query *query, const char *querytext) { JumbleState *jstate = NULL; @@ -132,6 +222,12 @@ JumbleQuery(Query *query, const char *querytext) return jstate; } +static JumbleState * +DummyJumbleQuery(Query *query, const char *querytext) +{ + return NULL; +} + /* * Compute a query identifier for the given utility query string. */ diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 24a5d9d3fb..a7c3a4958e 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -247,7 +247,6 @@ extern bool log_btree_build_stats; extern PGDLLIMPORT bool check_function_bodies; extern bool session_auth_is_superuser; -extern bool compute_query_id; extern bool log_duration; extern int log_parameter_max_length; extern int log_parameter_max_length_on_error; diff --git a/src/include/utils/queryjumble.h b/src/include/utils/queryjumble.h index 83ba7339fa..682d687b79 100644 --- a/src/include/utils/queryjumble.h +++ b/src/include/utils/queryjumble.h @@ -15,6 +15,7 @@ #define QUERYJUBLE_H #include "nodes/parsenodes.h" +#include "utils/guc.h" #define JUMBLE_SIZE 1024 /* query serialization buffer size */ @@ -52,7 +53,12 @@ typedef struct JumbleState int highest_extern_param_id; } JumbleState; +extern char *query_id_provider; +extern JumbleState *(*JumbleQuery)(Query *query, const char *querytext); + +JumbleState *DefaultJumbleQuery(Query *query, const char *querytext); +bool queryIdWanted(char *provider_name, bool use_existing); +bool check_query_id_provider(char **newval, void **extra, GucSource source); +void assign_query_id_provider(const char *newval, void *extra); const char *CleanQuerytext(const char *query, int *location, int *len); -JumbleState *JumbleQuery(Query *query, const char *querytext); - #endif /* QUERYJUMBLE_H */ diff --git a/src/test/regress/expected/explain.out b/src/test/regress/expected/explain.out index cda28098ba..16375d5596 100644 --- a/src/test/regress/expected/explain.out +++ b/src/test/regress/expected/explain.out @@ -477,7 +477,7 @@ select jsonb_pretty( (1 row) rollback; -set compute_query_id = on; +set compute_query_id = 'default'; select explain_filter('explain (verbose) select * from int8_tbl i8'); explain_filter ----------------------------------------------------------------