From 512ba0bdc53aa140027a18449426bf1327ba3efe Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 27 Aug 2021 10:50:49 +0200 Subject: [PATCH] Fix record hash support, variant 2 --- src/backend/optimizer/path/joinpath.c | 2 +- src/backend/optimizer/plan/initsplan.c | 2 +- src/backend/parser/analyze.c | 18 +++++++++++++----- src/backend/parser/parse_clause.c | 6 ++++++ src/backend/rewrite/rewriteSearchCycle.c | 6 +++--- src/backend/utils/cache/lsyscache.c | 2 +- src/include/parser/analyze.h | 2 +- 7 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 6407ede12a..385a41606e 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -437,7 +437,7 @@ paraminfo_get_equal_hashops(PlannerInfo *root, ParamPathInfo *param_info, TYPECACHE_HASH_PROC | TYPECACHE_EQ_OPR); /* can't use a memoize node without a valid hash equals operator */ - if (!OidIsValid(typentry->hash_proc) || !OidIsValid(typentry->eq_opr)) + if (!OidIsValid(typentry->hash_proc) || !OidIsValid(typentry->eq_opr) || typentry->type_id == RECORDOID) { list_free(*operators); list_free(*param_exprs); diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index e25dc9a7ca..5fc411dcce 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -2733,7 +2733,7 @@ check_memoizable(RestrictInfo *restrictinfo) typentry = lookup_type_cache(exprType(leftarg), TYPECACHE_HASH_PROC | TYPECACHE_EQ_OPR); - if (!OidIsValid(typentry->hash_proc) || !OidIsValid(typentry->eq_opr)) + if (!OidIsValid(typentry->hash_proc) || !OidIsValid(typentry->eq_opr) || typentry->type_id == RECORDOID) return; restrictinfo->hasheqoperator = typentry->eq_opr; diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 15669c8238..07623f1daa 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -1852,9 +1852,12 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) /* * Make a SortGroupClause node for a SetOperationStmt's groupClauses + * + * If need_hash is true, the caller is indicating that they need hash support + * or they will fail. So look extra hard for hash support. */ SortGroupClause * -makeSortGroupClauseForSetOp(Oid rescoltype) +makeSortGroupClauseForSetOp(Oid rescoltype, bool need_hash) { SortGroupClause *grpcl = makeNode(SortGroupClause); Oid sortop; @@ -1867,6 +1870,9 @@ makeSortGroupClauseForSetOp(Oid rescoltype) &sortop, &eqop, NULL, &hashable); + if (rescoltype == RECORDOID) + hashable = need_hash; + /* we don't have a tlist yet, so can't assign sortgrouprefs */ grpcl->tleSortGroupRef = 0; grpcl->eqop = eqop; @@ -2027,6 +2033,9 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, ListCell *ltl; ListCell *rtl; const char *context; + bool recursive = (pstate->p_parent_cte && + pstate->p_parent_cte->cterecursive); + context = (stmt->op == SETOP_UNION ? "UNION" : (stmt->op == SETOP_INTERSECT ? "INTERSECT" : @@ -2048,9 +2057,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, * containing CTE as having those result columns. We should do this * only at the topmost setop of the CTE, of course. */ - if (isTopLevel && - pstate->p_parent_cte && - pstate->p_parent_cte->cterecursive) + if (isTopLevel && recursive) determineRecursiveColTypes(pstate, op->larg, ltargetlist); /* @@ -2182,8 +2189,9 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, setup_parser_errposition_callback(&pcbstate, pstate, bestlocation); + /* If it's a recursive union, we need to require hashing support. */ op->groupClauses = lappend(op->groupClauses, - makeSortGroupClauseForSetOp(rescoltype)); + makeSortGroupClauseForSetOp(rescoltype, recursive)); cancel_parser_errposition_callback(&pcbstate); } diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index b3f151d33b..3518d359aa 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -3318,6 +3318,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle, true, true, false, &sortop, &eqop, NULL, &hashable); + if (restype == RECORDOID) + hashable = false; reverse = false; break; case SORTBY_DESC: @@ -3325,6 +3327,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle, false, true, true, NULL, &eqop, &sortop, &hashable); + if (restype == RECORDOID) + hashable = false; reverse = true; break; case SORTBY_USING: @@ -3449,6 +3453,8 @@ addTargetToGroupList(ParseState *pstate, TargetEntry *tle, false, true, false, &sortop, &eqop, NULL, &hashable); + if (restype == RECORDOID) + hashable = false; cancel_parser_errposition_callback(&pcbstate); diff --git a/src/backend/rewrite/rewriteSearchCycle.c b/src/backend/rewrite/rewriteSearchCycle.c index c50ebdba24..ef38f4025a 100644 --- a/src/backend/rewrite/rewriteSearchCycle.c +++ b/src/backend/rewrite/rewriteSearchCycle.c @@ -594,7 +594,7 @@ rewriteSearchAndCycle(CommonTableExpr *cte) sos->colCollations = lappend_oid(sos->colCollations, InvalidOid); if (!sos->all) sos->groupClauses = lappend(sos->groupClauses, - makeSortGroupClauseForSetOp(search_seq_type)); + makeSortGroupClauseForSetOp(search_seq_type, true)); } if (cte->cycle_clause) { @@ -603,14 +603,14 @@ rewriteSearchAndCycle(CommonTableExpr *cte) sos->colCollations = lappend_oid(sos->colCollations, cte->cycle_clause->cycle_mark_collation); if (!sos->all) sos->groupClauses = lappend(sos->groupClauses, - makeSortGroupClauseForSetOp(cte->cycle_clause->cycle_mark_type)); + makeSortGroupClauseForSetOp(cte->cycle_clause->cycle_mark_type, true)); sos->colTypes = lappend_oid(sos->colTypes, RECORDARRAYOID); sos->colTypmods = lappend_int(sos->colTypmods, -1); sos->colCollations = lappend_oid(sos->colCollations, InvalidOid); if (!sos->all) sos->groupClauses = lappend(sos->groupClauses, - makeSortGroupClauseForSetOp(RECORDARRAYOID)); + makeSortGroupClauseForSetOp(RECORDARRAYOID, true)); } /* diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 4ebaa552a2..f66b09d940 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -1421,7 +1421,7 @@ op_hashjoinable(Oid opno, Oid inputtype) else if (opno == RECORD_EQ_OP) { typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC); - if (typentry->hash_proc == F_HASH_RECORD) + if (typentry->hash_proc == F_HASH_RECORD && inputtype != RECORDOID) result = true; } else diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h index 6716db6c13..89d61238e9 100644 --- a/src/include/parser/analyze.h +++ b/src/include/parser/analyze.h @@ -48,6 +48,6 @@ extern void applyLockingClause(Query *qry, Index rtindex, extern List *BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex); -extern SortGroupClause *makeSortGroupClauseForSetOp(Oid rescoltype); +extern SortGroupClause *makeSortGroupClauseForSetOp(Oid rescoltype, bool need_hash); #endif /* ANALYZE_H */ -- 2.33.0