Skip to content

Commit 4559d04

Browse files
committed
Limit name of generated extended statistic
1 parent e4ecf2b commit 4559d04

File tree

1 file changed

+68
-76
lines changed

1 file changed

+68
-76
lines changed

contrib/auto_explain/auto_explain.c

Lines changed: 68 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
#include <limits.h>
1616
#include <math.h>
1717

18+
#include "access/hash.h"
1819
#include "access/parallel.h"
20+
#include "access/relscan.h"
21+
#include "access/skey.h"
1922
#include "access/table.h"
20-
#include "catalog/pg_statistic_ext_data_d.h"
23+
#include "access/tableam.h"
24+
#include "catalog/pg_statistic_ext.h"
2125
#include "commands/explain.h"
2226
#include "commands/defrem.h"
2327
#include "executor/instrument.h"
@@ -30,6 +34,7 @@
3034
#include "parser/parsetree.h"
3135
#include "storage/ipc.h"
3236
#include "statistics/statistics.h"
37+
#include "utils/fmgroids.h"
3338
#include "utils/guc.h"
3439
#include "utils/syscache.h"
3540
#include "utils/lsyscache.h"
@@ -428,31 +433,12 @@ vars_list_comparator(const ListCell *a, const ListCell *b)
428433
return strcmp(va, vb);
429434
}
430435

431-
typedef struct
432-
{
433-
Oid rel_oid;
434-
int n_attrs;
435-
uint64 attrs_mask;
436-
} StatHashKey;
437-
438-
static HTAB* ext_stat_hash;
439-
440436
static void
441437
AddMultiColumnStatisticsForQual(void* qual, ExplainState *es)
442438
{
443439
List *vars = NULL;
444440
ListCell* lc;
445-
StatHashKey key;
446-
key.attrs_mask = 0;
447-
key.n_attrs = 0;
448441

449-
if (ext_stat_hash == NULL)
450-
{
451-
HASHCTL ctl;
452-
MemSet(&ctl, 0, sizeof(ctl));
453-
ctl.keysize = ctl.entrysize = sizeof(StatHashKey);
454-
ext_stat_hash = hash_create("ext_stat_hash", 113, &ctl, HASH_ELEM|HASH_BLOBS);
455-
}
456442
foreach (lc, qual)
457443
{
458444
Node* node = (Node*)lfirst(lc);
@@ -490,8 +476,6 @@ AddMultiColumnStatisticsForQual(void* qual, ExplainState *es)
490476
col->fields = list_make1(makeString(colname));
491477
cols = lappend(cols, col);
492478
colmap = bms_add_member(colmap, var->varoattno);
493-
key.attrs_mask |= 1LL << (var->varoattno & 63);
494-
key.n_attrs += 1;
495479
}
496480
}
497481
}
@@ -505,65 +489,73 @@ AddMultiColumnStatisticsForQual(void* qual, ExplainState *es)
505489
if (list_length(cols) >= 2)
506490
{
507491
RangeTblEntry *rte = rt_fetch(varno, es->rtable);
508-
bool found;
509-
key.rel_oid = rte->relid;
510-
hash_search(ext_stat_hash, &key, HASH_ENTER, &found);
511-
if (!found)
512-
{
513-
CreateStatsStmt* stats = makeNode(CreateStatsStmt);
514-
char *rel_namespace = get_namespace_name(get_rel_namespace(rte->relid));
515-
char *rel_name = get_rel_name(rte->relid);
516-
RangeVar* rel = makeRangeVar(rel_namespace, rel_name, 0);
517-
char* stat_name = rel_name;
518-
char* create_stat_stmt = (char*)"";
519-
char const* sep = "ON";
520-
521-
list_sort(cols, vars_list_comparator);
522-
/* Construct name for statistic by concatenating relation name with all columns */
523-
foreach (cell, cols)
492+
CreateStatsStmt* stats = makeNode(CreateStatsStmt);
493+
char *rel_namespace = get_namespace_name(get_rel_namespace(rte->relid));
494+
char *rel_name = get_rel_name(rte->relid);
495+
RangeVar* rel = makeRangeVar(rel_namespace, rel_name, 0);
496+
char* stat_name = rel_name;
497+
char* create_stat_stmt = (char*)"";
498+
char const* sep = "ON";
499+
ScanKeyData entry[2];
500+
TableScanDesc scan;
501+
Relation stat_rel;
502+
size_t name_len;
503+
TupleTableSlot *slot;
504+
505+
list_sort(cols, vars_list_comparator);
506+
/* Construct name for statistic by concatenating relation name with all columns */
507+
foreach (cell, cols)
508+
{
509+
char* col_name = strVal((Value *) linitial(((ColumnRef *)lfirst(cell))->fields));
510+
stat_name = psprintf("%s_%s", stat_name, col_name);
511+
create_stat_stmt = psprintf("%s%s %s", create_stat_stmt, sep, col_name);
512+
sep = ",";
513+
}
514+
515+
name_len = strlen(stat_name);
516+
if (name_len >= NAMEDATALEN)
517+
stat_name = psprintf("%.*s_%08x", NAMEDATALEN - 10, stat_name, (unsigned)hash_any((uint8*)stat_name, name_len));
518+
519+
ScanKeyInit(&entry[0],
520+
Anum_pg_statistic_ext_stxname,
521+
BTEqualStrategyNumber, F_NAMEEQ,
522+
CStringGetDatum(stat_name));
523+
ScanKeyInit(&entry[1],
524+
Anum_pg_statistic_ext_stxnamespace,
525+
BTEqualStrategyNumber, F_OIDEQ,
526+
ObjectIdGetDatum(get_rel_namespace(rte->relid)));
527+
528+
/*
529+
* Prevent concurrent access to extended statistic table
530+
*/
531+
stat_rel = table_open(StatisticExtRelationId, AccessExclusiveLock);
532+
slot = table_slot_create(stat_rel, NULL);
533+
scan = table_beginscan_catalog(stat_rel, 2, entry);
534+
535+
/*
536+
* Check if multicolumn statistic object with such name already exists.
537+
* Most likely if was already created by auto_explain, but either ANALYZE was not performed since
538+
* this time, either presence of this multicolumn statistic doesn't help to provide more precise estimation.
539+
* Despite to the fact that we create statistics with "if_not_exist" option, presence of such check
540+
* allows to eliminate notice message that statistics object already exists.
541+
*/
542+
if (!table_scan_getnextslot(scan, ForwardScanDirection, slot))
543+
{
544+
if (auto_explain_suggest_only)
524545
{
525-
char* col_name = strVal((Value *) linitial(((ColumnRef *)lfirst(cell))->fields));
526-
stat_name = psprintf("%s_%s", stat_name, col_name);
527-
create_stat_stmt = psprintf("%s%s %s", create_stat_stmt, sep, col_name);
528-
sep = ",";
546+
elog(NOTICE, "Auto_explain suggestion: CREATE STATISTICS %s %s FROM %s", stat_name, create_stat_stmt, rel_name);
529547
}
530-
/*
531-
* Check if multicolumn statistic object with such name already exists.
532-
* Most likely if was already created by auto_explain, but either ANALYZE was not performed since
533-
* this time, either presence of this multicolumn statistic doesn't help to provide more precise estimation.
534-
* Despite to the fact that we create statistics with "if_not_exist" option, presence of such check
535-
* allows to eliminate notice message that statistics object already exists.
536-
*/
537-
if (!SearchSysCacheExists2(STATEXTNAMENSP,
538-
CStringGetDatum(stat_name),
539-
ObjectIdGetDatum(get_rel_namespace(rte->relid))))
548+
else
540549
{
541-
if (auto_explain_suggest_only)
542-
{
543-
elog(NOTICE, "Auto_explain suggestion: CREATE STATISTICS %s %s FROM %s", stat_name, create_stat_stmt, rel_name);
544-
}
545-
else
546-
{
547-
Relation stat = table_open(StatisticExtDataRelationId, AccessExclusiveLock);
548-
if (stat == NULL)
549-
elog(ERROR, "Failed to lock statistic table");
550-
551-
/* Recheck under lock */
552-
if (!SearchSysCacheExists2(STATEXTNAMENSP,
553-
CStringGetDatum(stat_name),
554-
ObjectIdGetDatum(get_rel_namespace(rte->relid))))
555-
{
556-
elog(LOG, "Add statistics %s", stat_name);
557-
stats->defnames = list_make2(makeString(rel_namespace), makeString(stat_name));
558-
stats->if_not_exists = true;
559-
stats->relations = list_make1(rel);
560-
stats->exprs = cols;
561-
CreateStatistics(stats);
562-
}
563-
table_close(stat, AccessExclusiveLock);
564-
}
550+
elog(LOG, "Add statistics %s", stat_name);
551+
stats->defnames = list_make2(makeString(rel_namespace), makeString(stat_name));
552+
stats->if_not_exists = true;
553+
stats->relations = list_make1(rel);
554+
stats->exprs = cols;
555+
CreateStatistics(stats);
565556
}
566557
}
558+
table_close(stat_rel, AccessExclusiveLock);
567559
}
568560
}
569561
}

0 commit comments

Comments
 (0)