diff --git a/src/backend/optimizer/util/relnode.c src/backend/optimizer/util/relnode.c index 284215a7173..b80ef8e55b8 100644 --- a/src/backend/optimizer/util/relnode.c +++ src/backend/optimizer/util/relnode.c @@ -1030,12 +1030,60 @@ joinrel->joininfo = result; } +typedef struct UniquePtrList { + List *unique_list; + HTAB *h; +} UniquePtrList; + +static void +addUniquePtrList(UniquePtrList *upl, void *v) +{ + if (upl->h != NULL || list_length(upl->unique_list) > 32) + { + bool found; + + if (upl->h == NULL) + { + HASHCTL hash_ctl; + ListCell *l; + + MemSet(&hash_ctl, 0, sizeof(hash_ctl)); + + hash_ctl.keysize = sizeof(void*); + hash_ctl.entrysize = sizeof(void*); + + upl->h = hash_create("UniquePtrList storage", 64, &hash_ctl, + HASH_BLOBS | HASH_ELEM); + + foreach(l, upl->unique_list) + { + void *k = lfirst(l); + + hash_search(upl->h, &k, HASH_ENTER, &found); + Assert(found == false); + } + } + + hash_search(upl->h, &v, HASH_ENTER, &found); + if (found == false) + upl->unique_list = lappend(upl->unique_list, v); + } + else + { + upl->unique_list = list_append_unique_ptr(upl->unique_list, v); + } +} + static List * subbuild_joinrel_restrictlist(Relids joinrelids, List *joininfo_list, List *new_restrictlist) { ListCell *l; + UniquePtrList upl; + + memset(&upl, 0, sizeof(upl)); + upl.unique_list = new_restrictlist; foreach(l, joininfo_list) { @@ -1050,7 +1098,7 @@ * different joinlists will have been multiply-linked rather than * copied, pointer equality should be a sufficient test.) */ - new_restrictlist = list_append_unique_ptr(new_restrictlist, rinfo); + addUniquePtrList(&upl, rinfo); } else { @@ -1061,7 +1109,8 @@ } } - return new_restrictlist; + hash_destroy(upl.h); + return upl.unique_list; } static List * @@ -1070,6 +1119,10 @@ List *new_joininfo) { ListCell *l; + UniquePtrList upl; + + memset(&upl, 0, sizeof(upl)); + upl.unique_list = new_joininfo; /* Expected to be called only for join between parent relations. */ Assert(joinrel->reloptkind == RELOPT_JOINREL); @@ -1095,11 +1148,12 @@ * multiply-linked rather than copied, pointer equality should be * a sufficient test.) */ - new_joininfo = list_append_unique_ptr(new_joininfo, rinfo); + addUniquePtrList(&upl, rinfo); } } - return new_joininfo; + hash_destroy(upl.h); + return upl.unique_list; } diff --git a/src/backend/utils/adt/ruleutils.c src/backend/utils/adt/ruleutils.c index 74a18a146d0..954ee103d85 100644 --- a/src/backend/utils/adt/ruleutils.c +++ src/backend/utils/adt/ruleutils.c @@ -272,6 +272,8 @@ typedef struct int *leftattnos; /* left-child varattnos of join cols, or 0 */ int *rightattnos; /* right-child varattnos of join cols, or 0 */ List *usingNames; /* names assigned to merged columns */ + + HTAB *all_names; /* hash to store all names colname_is_unique() */ } deparse_columns; /* This macro is analogous to rt_fetch(), but for deparse_columns structs */ @@ -347,6 +349,7 @@ static void set_relation_column_names(deparse_namespace *dpns, deparse_columns *colinfo); static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo); +static void add_colname(deparse_columns *colinfo, char *colname); static bool colname_is_unique(const char *colname, deparse_namespace *dpns, deparse_columns *colinfo); static char *make_colname_unique(char *colname, deparse_namespace *dpns, @@ -4174,7 +4177,10 @@ set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, changed_any = true; } else + { colinfo->new_colnames[j] = child_colname; + add_colname(colinfo, child_colname); + } } colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc]; @@ -4223,7 +4229,10 @@ set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, changed_any = true; } else + { colinfo->new_colnames[j] = child_colname; + add_colname(colinfo, child_colname); + } } colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc]; @@ -4248,6 +4257,29 @@ set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, colinfo->printaliases = false; } +static uint32 +pstring_hash(const void *key, Size keysize) +{ + return string_hash(*(const void **)key, NAMEDATALEN); +} + +static int +pstring_compare(const void *key1, const void *key2, Size keysize) +{ + return strncmp(*(const void **)key1, *(const void **)key2, keysize - 1); +} + +static void +add_colname(deparse_columns *colinfo, char *colname) +{ + if (colinfo->all_names) + { + bool found; + + hash_search(colinfo->all_names, &colname, HASH_ENTER, &found); + } +} + /* * colname_is_unique: is colname distinct from already-chosen column names? * @@ -4260,6 +4292,75 @@ colname_is_unique(const char *colname, deparse_namespace *dpns, int i; ListCell *lc; + if (colinfo->all_names != NULL || + (colinfo->num_cols + colinfo->num_new_cols + + list_length(dpns->using_names) + + list_length(colinfo->parentUsing)) > 64) + { + bool found; + + if (colinfo->all_names == NULL) + { + HASHCTL hash_ctl; + + MemSet(&hash_ctl, 0, sizeof(hash_ctl)); + + hash_ctl.keysize = sizeof(char*); + hash_ctl.entrysize = sizeof(char*); + hash_ctl.hash = pstring_hash; + hash_ctl.match = pstring_compare; + + colinfo->all_names = hash_create("colname_is_unique storage", + 512, &hash_ctl, + HASH_ELEM | HASH_FUNCTION | HASH_COMPARE); + + + for (i = 0; i < colinfo->num_cols; i++) + { + if (colinfo->colnames[i] == NULL) + continue; + + hash_search(colinfo->all_names, &colinfo->colnames[i], + HASH_ENTER, &found); + } + + for (i = 0; i < colinfo->num_new_cols; i++) + { + if (colinfo->new_colnames[i] == NULL) + continue; + + hash_search(colinfo->all_names, &colinfo->new_colnames[i], + HASH_ENTER, &found); + } + + foreach(lc, dpns->using_names) + { + char *oldname = (char *) lfirst(lc); + + hash_search(colinfo->all_names, &oldname, + HASH_ENTER, &found); + } + + foreach(lc, colinfo->parentUsing) + { + char *oldname = (char *) lfirst(lc); + + hash_search(colinfo->all_names, &oldname, + HASH_ENTER, &found); + } + } + + hash_search(colinfo->all_names, &colname, HASH_FIND, &found); + + if (found) + return false; + + hash_search(colinfo->all_names, &colname, HASH_ENTER, &found); + Assert(found == false); + + return true; + } + /* Check against already-assigned column aliases within RTE */ for (i = 0; i < colinfo->num_cols; i++) { @@ -4311,6 +4412,8 @@ static char * make_colname_unique(char *colname, deparse_namespace *dpns, deparse_columns *colinfo) { + CHECK_FOR_INTERRUPTS(); + /* * If the selected name isn't unique, append digits to make it so. For a * very long input name, we might have to truncate to stay within