From 64f23708167721aa561bd93c4f19cd515a1ea8bc Mon Sep 17 00:00:00 2001 From: huyinghao Date: Thu, 19 Dec 2024 11:22:56 +0800 Subject: [PATCH 1/6] =?UTF-8?q?GiST=20=E7=B4=A2=E5=BC=95=E6=89=AB=E6=8F=8F?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=20order=20by=20expr=20=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E6=97=B6=EF=BC=8C=20lossy=E5=9C=BA=E6=99=AF=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E7=BB=93=E6=9E=9C=E4=B8=8D=E7=AC=A6=E5=90=88=E9=A2=84?= =?UTF-8?q?=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gausskernel/optimizer/plan/createplan.cpp | 68 +++- .../runtime/executor/nodeIndexscan.cpp | 359 +++++++++++++++++- .../storage/access/gist/gistget.cpp | 76 +++- .../storage/access/gist/gistscan.cpp | 22 ++ src/include/access/gist_private.h | 5 + src/include/access/relscan.h | 10 + src/include/nodes/execnodes.h | 19 + src/include/nodes/plannodes.h | 10 +- 8 files changed, 541 insertions(+), 28 deletions(-) diff --git a/src/gausskernel/optimizer/plan/createplan.cpp b/src/gausskernel/optimizer/plan/createplan.cpp index ba6a1dc229..a8ee158047 100755 --- a/src/gausskernel/optimizer/plan/createplan.cpp +++ b/src/gausskernel/optimizer/plan/createplan.cpp @@ -31,6 +31,7 @@ #include "catalog/pg_opfamily.h" #include "catalog/pgxc_group.h" #include "catalog/pg_proc_ext.h" +#include "catalog/pg_operator.h" #include "foreign/fdwapi.h" #include "foreign/foreign.h" #include "miscadmin.h" @@ -157,7 +158,8 @@ static Plan* setBucketInfoParam(PlannerInfo* root, Plan* plan, RelOptInfo* rel); Plan* create_globalpartInterator_plan(PlannerInfo* root, PartIteratorPath* pIterpath); static IndexScan* make_indexscan(List* qptlist, List* qpqual, Index scanrelid, Oid indexid, List* indexqual, - List* indexqualorig, List* indexorderby, List* indexorderbyorig, ScanDirection indexscandir, double indexselectivity, bool is_partial); + List* indexqualorig, List* indexorderby, List* indexorderbyorig, Oid* indexorderbyops, + ScanDirection indexscandir, double indexselectivity, bool is_partial); static IndexOnlyScan* make_indexonlyscan(List* qptlist, List* qpqual, Index scanrelid, Oid indexid, List* indexqual, List* indexqualorig, List* indexorderby, List* indextlist, ScanDirection indexscandir, double indexselectivity, bool is_partial); static CStoreIndexScan* make_cstoreindexscan(PlannerInfo* root, Path* best_path, List* qptlist, List* qpqual, @@ -199,7 +201,7 @@ static MergeJoin* make_mergejoin(List* tlist, List* joinclauses, List* otherclau static Plan* prepare_sort_from_pathkeys(PlannerInfo* root, Plan* lefttree, List* pathkeys, Relids relids, const AttrNumber* reqColIdx, bool adjust_tlist_in_place, int* p_numsortkeys, AttrNumber** p_sortColIdx, Oid** p_sortOperators, Oid** p_collations, bool** p_nullsFirst); -static EquivalenceMember* find_ec_member_for_tle(EquivalenceClass* ec, TargetEntry* tle, Relids relids); +static EquivalenceMember* find_ec_member_for_expr(EquivalenceClass* ec, Expr* tlexpr, Relids relids); static List* fix_cstore_scan_qual(PlannerInfo* root, List* qpqual); static List* make_null_eq_clause(List* joinqual, List** otherqual, List* nullinfo); static Node* get_null_eq_restrictinfo(Node* restrictinfo, List* nullinfo); @@ -2620,6 +2622,7 @@ static Scan* create_indexscan_plan( double indexselectivity = best_path->indexselectivity; ListCell* l = NULL; Bitmapset *prefixkeys = NULL; + Oid* indexorderbyops = NULL; /* it should be a base rel... */ Assert(baserelid > 0); @@ -2730,6 +2733,44 @@ static Scan* create_indexscan_plan( indexorderbys = (List*)replace_nestloop_params(root, (Node*)indexorderbys); } + /* + * If there are ORDER BY expressions, look up the sort operators for + * their datatypes. + */ + if (best_path->path.pathkeys && indexorderbys) { + int numOrderBys = list_length(indexorderbys); + int i; + ListCell* pathkeyCell; + ListCell* exprCell; + PathKey* pathkey; + Expr* expr; + EquivalenceMember* em; + + indexorderbyops = (Oid *) palloc(numOrderBys * sizeof(Oid)); + + /* + * PathKey contains pointer to the equivalence class, but that's not + * enough because we need the expression's datatype to look up the + * sort operator in the operator family. We have to dig the + * equivalence member for the datatype. + */ + i = 0; + forboth (pathkeyCell, best_path->path.pathkeys, exprCell, indexorderbys) { + pathkey = (PathKey *) lfirst(pathkeyCell); + expr = (Expr *) lfirst(exprCell); + + /* Find equivalence member for the order by expression */ + em = find_ec_member_for_expr(pathkey->pk_eclass, expr, NULL); + + /* Get sort operator from opfamily */ + indexorderbyops[i] = get_opfamily_member(pathkey->pk_opfamily, + em->em_datatype, + em->em_datatype, + pathkey->pk_strategy); + i++; + } + } + /* Finally ready to build the plan node */ if (best_path->path.parent->orientation == REL_COL_ORIENTED) { scan_plan = (Scan*)make_cstoreindexscan(root, @@ -2788,6 +2829,7 @@ static Scan* create_indexscan_plan( stripped_indexquals, fixed_indexorderbys, indexorderbys, + indexorderbyops, best_path->indexscandir, indexselectivity, (best_path->indexinfo->indpred != NIL)); @@ -6124,7 +6166,8 @@ static TsStoreScan* make_tsstorescan(List* qptlist, List* qpqual, Index scanreli #endif /* ENABLE_MULTIPLE_NODES */ static IndexScan* make_indexscan(List* qptlist, List* qpqual, Index scanrelid, Oid indexid, List* indexqual, - List* indexqualorig, List* indexorderby, List* indexorderbyorig, ScanDirection indexscandir, double indexselectivity, bool is_partial) + List* indexqualorig, List* indexorderby, List* indexorderbyorig, Oid* indexorderbyops, + ScanDirection indexscandir, double indexselectivity, bool is_partial) { IndexScan* node = makeNode(IndexScan); Plan* plan = &node->scan.plan; @@ -6140,6 +6183,7 @@ static IndexScan* make_indexscan(List* qptlist, List* qpqual, Index scanrelid, O node->indexqualorig = indexqualorig; node->indexorderby = indexorderby; node->indexorderbyorig = indexorderbyorig; + node->indexorderbyops = indexorderbyops; node->indexorderdir = indexscandir; node->selectivity = indexselectivity; node->is_partial = is_partial; @@ -7718,7 +7762,7 @@ static Plan* prepare_sort_from_pathkeys(PlannerInfo* root, Plan* lefttree, List* */ tle = get_tle_by_resno(tlist, reqColIdx[numsortkeys]); if (tle != NULL) { - em = find_ec_member_for_tle(ec, tle, relids); + em = find_ec_member_for_expr(ec, tle->expr, relids); if (em != NULL) { /* found expr at right place in tlist */ pk_datatype = em->em_datatype; @@ -7744,7 +7788,7 @@ static Plan* prepare_sort_from_pathkeys(PlannerInfo* root, Plan* lefttree, List* */ foreach (j, tlist) { tle = (TargetEntry*)lfirst(j); - em = find_ec_member_for_tle(ec, tle, relids); + em = find_ec_member_for_expr(ec, tle->expr, relids); if (em != NULL) { /* found expr already in tlist */ pk_datatype = em->em_datatype; @@ -7875,20 +7919,18 @@ static Plan* prepare_sort_from_pathkeys(PlannerInfo* root, Plan* lefttree, List* } /* - * find_ec_member_for_tle - * Locate an EquivalenceClass member matching the given TLE, if any + * find_ec_member_for_expr + * Locate an EquivalenceClass member matching the given expression, if any * * Child EC members are ignored unless they match 'relids'. */ -static EquivalenceMember* find_ec_member_for_tle(EquivalenceClass* ec, TargetEntry* tle, Relids relids) +static EquivalenceMember* find_ec_member_for_expr(EquivalenceClass* ec, Expr* expr, Relids relids) { - Expr* tlexpr = NULL; ListCell* lc = NULL; /* We ignore binary-compatible relabeling on both ends */ - tlexpr = tle->expr; - while (tlexpr && IsA(tlexpr, RelabelType)) - tlexpr = ((RelabelType*)tlexpr)->arg; + while (expr && IsA(expr, RelabelType)) + expr = ((RelabelType *) expr)->arg; foreach (lc, ec->ec_members) { EquivalenceMember* em = (EquivalenceMember*)lfirst(lc); @@ -7913,7 +7955,7 @@ static EquivalenceMember* find_ec_member_for_tle(EquivalenceClass* ec, TargetEnt while (emexpr && IsA(emexpr, RelabelType)) emexpr = ((RelabelType*)emexpr)->arg; - if (equal(emexpr, tlexpr)) + if (equal(emexpr, expr)) return em; } diff --git a/src/gausskernel/runtime/executor/nodeIndexscan.cpp b/src/gausskernel/runtime/executor/nodeIndexscan.cpp index 9dab06d9e2..a24cd30461 100644 --- a/src/gausskernel/runtime/executor/nodeIndexscan.cpp +++ b/src/gausskernel/runtime/executor/nodeIndexscan.cpp @@ -16,6 +16,7 @@ * INTERFACE ROUTINES * ExecIndexScan scans a relation using an index * IndexNext retrieve next tuple using index + * IndexNextWithReorder same, but recheck ORDER BY expressions * ExecInitIndexScan creates and initializes state info. * ExecReScanIndexScan rescans the indexed relation. * ExecEndIndexScan releases all storage. @@ -32,6 +33,7 @@ #include "commands/cluster.h" #include "executor/exec/execdebug.h" #include "executor/node/nodeIndexscan.h" +#include "lib/pairingheap.h" #include "optimizer/clauses.h" #include "storage/tcap.h" #include "utils/array.h" @@ -39,14 +41,37 @@ #include "utils/memutils.h" #include "utils/rel.h" #include "utils/rel_gs.h" +#include "utils/datum.h" #include "gstrace/gstrace_infra.h" #include "gstrace/executer_gstrace.h" #include "nodes/makefuncs.h" #include "optimizer/pruning.h" +/* + * When an ordering operator is used, tuples fetched from the index that + * need to be reordered are queued in a pairing heap, as ReorderTuples. + */ +typedef struct +{ + pairingheap_node ph_node; + HeapTuple htup; + Datum* orderbyvals; + bool* orderbynulls; +} ReorderTuple; + static TupleTableSlot* ExecIndexScan(PlanState* state); static TupleTableSlot* IndexNext(IndexScanState* node); static void ExecInitNextPartitionForIndexScan(IndexScanState* node); +static TupleTableSlot* IndexNextWithReorder(IndexScanState* node); +static void EvalOrderByExpressions(IndexScanState* node, ExprContext* econtext); +static int cmp_orderbyvals(const Datum* adist, const bool* anulls, + const Datum* bdist, const bool* bnulls, + IndexScanState* node); +static int reorderqueue_cmp(const pairingheap_node* a, + const pairingheap_node* b, void* arg); +static void reorderqueue_push(IndexScanState* node, HeapTuple tuple, + Datum* orderbyvals, bool* orderbynulls); +static HeapTuple reorderqueue_pop(IndexScanState* node); /* ---------------------------------------------------------------- * IndexNext @@ -135,9 +160,188 @@ static TupleTableSlot* IndexNext(IndexScanState* node) * if we get here it means the index scan failed so we are at the end of * the scan.. */ + node->iss_ReachedEnd = true; return ExecClearTuple(slot); } +/* ---------------------------------------------------------------- + * IndexNextWithReorder + * + * Like IndexNext, but his version can also re-check any + * ORDER BY expressions, and reorder the tuples as necessary. + * ---------------------------------------------------------------- + */ +static TupleTableSlot * IndexNextWithReorder(IndexScanState* node) +{ + ExprContext* econtext; + IndexScanDesc scandesc; + HeapTuple tuple; + TupleTableSlot* slot; + ReorderTuple* topmost = NULL; + bool was_exact; + Datum* lastfetched_vals; + bool* lastfetched_nulls; + int cmp; + + /* only forward scan is supported with reordering. */ + Assert(!ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir)); + Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction)); + scandesc = node->iss_ScanDesc; + econtext = node->ss.ps.ps_ExprContext; + slot = node->ss.ss_ScanTupleSlot; + + for (;;) { + /* + * Check the reorder queue first. If the topmost tuple in the queue + * has an ORDER BY value smaller than (or equal to) the value last + * returned by the index, we can return it now. + */ + if (!pairingheap_is_empty(node->iss_ReorderQueue)) { + topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue); + + if (node->iss_ReachedEnd || + cmp_orderbyvals(topmost->orderbyvals, + topmost->orderbynulls, + scandesc->xs_orderbyvals, + scandesc->xs_orderbynulls, + node) <= 0) { + tuple = reorderqueue_pop(node); + + /* Pass 'true', as the tuple in the queue is a palloc'd copy */ + ExecStoreTuple(tuple, slot, InvalidBuffer, true); + return slot; + } + } else if (node->iss_ReachedEnd) { + /* Queue is empty, and no more tuples from index. We're done. */ + return ExecClearTuple(slot); + } + + /* + * Fetch next tuple from the index. + */ +next_indextuple: + tuple = (HeapTuple)index_getnext(scandesc, ForwardScanDirection); + if (!tuple) { + /* + * No more tuples from the index. But we still need to drain any + * remaining tuples from the queue before we're done. + */ + node->iss_ReachedEnd = true; + continue; + } + + /* + * Store the scanned tuple in the scan tuple slot of the scan state. + * Note: we pass 'false' because tuples returned by amgetnext are + * pointers onto disk pages and must not be pfree()'d. + */ + ExecStoreTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + scandesc->xs_cbuf, /* buffer containing tuple */ + false); /* don't pfree */ + + /* + * If the index was lossy, we have to recheck the index quals and + * ORDER BY expressions using the fetched tuple. + */ + if (scandesc->xs_recheck) { + econtext->ecxt_scantuple = slot; + ResetExprContext(econtext); + if (!ExecQual(node->indexqualorig, econtext, false)) { + /* Fails recheck, so drop it and loop back for another */ + InstrCountFiltered2(node, 1); + goto next_indextuple; + } + } + + if (scandesc->xs_recheckorderby) { + econtext->ecxt_scantuple = slot; + ResetExprContext(econtext); + + EvalOrderByExpressions(node, econtext); + + /* + * Was the ORDER BY value returned by the index accurate? The + * recheck flag means that the index can return inaccurate values, + * but then again, the value returned for any particular tuple + * could also be exactly correct. Compare the value returned by + * the index with the recalculated value. (If the value returned + * by the index happened to be exact right, we can often avoid + * pushing the tuple to the queue, just to pop it back out again.) + */ + cmp = cmp_orderbyvals(node->iss_OrderByValues, + node->iss_OrderByNulls, + scandesc->xs_orderbyvals, + scandesc->xs_orderbynulls, + node); + if (cmp < 0) + elog(ERROR, "index returned tuples in wrong order"); + else if (cmp == 0) + was_exact = true; + else + was_exact = false; + lastfetched_vals = node->iss_OrderByValues; + lastfetched_nulls = node->iss_OrderByNulls; + } else { + was_exact = true; + lastfetched_vals = scandesc->xs_orderbyvals; + lastfetched_nulls = scandesc->xs_orderbynulls; + } + + /* + * Can we return this tuple immediately, or does it need to be pushed + * to the reorder queue? If the ORDER BY expression values returned + * by the index were inaccurate, we can't return it yet, because the + * next tuple from the index might need to come before this one. + * Also, we can't return it yet if there are any smaller tuples in the + * queue already. + */ + if (!was_exact || (topmost && cmp_orderbyvals(lastfetched_vals, + lastfetched_nulls, + topmost->orderbyvals, + topmost->orderbynulls, + node) > 0)) { + /* Put this tuple to the queue */ + reorderqueue_push(node, tuple, lastfetched_vals, lastfetched_nulls); + continue; + } else { + /* Can return this tuple immediately. */ + return slot; + } + } + + /* + * if we get here it means the index scan failed so we are at the end of + * the scan.. + */ + return ExecClearTuple(slot); +} + +/* + * Calculate the expressions in the ORDER BY clause, based on the heap tuple. + */ +static void EvalOrderByExpressions(IndexScanState* node, ExprContext* econtext) +{ + int i; + ListCell* l; + MemoryContext oldContext; + + oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); + + i = 0; + foreach(l, node->indexorderbyorig) { + ExprState* orderby = (ExprState *) lfirst(l); + + node->iss_OrderByValues[i] = ExecEvalExpr(orderby, + econtext, + &node->iss_OrderByNulls[i], + NULL); + i++; + } + + MemoryContextSwitchTo(oldContext); +} + /* * IndexRecheck -- access method routine to recheck a tuple in EvalPlanQual */ @@ -158,6 +362,105 @@ static bool IndexRecheck(IndexScanState* node, TupleTableSlot* slot) return ExecQual(node->indexqualorig, econtext, false); } +/* + * Compare ORDER BY expression values. + */ +static int cmp_orderbyvals(const Datum* adist, const bool* anulls, + const Datum* bdist, const bool* bnulls, + IndexScanState* node) +{ + int i; + int result; + + for (i = 0; i < node->iss_NumOrderByKeys; i++) { + SortSupport ssup = &node->iss_SortSupport[i]; + + /* Handle nulls. We only support NULLS LAST. */ + if (anulls[i] && !bnulls[i]) + return 1; + else if (!anulls[i] && bnulls[i]) + return -1; + else if (anulls[i] && bnulls[i]) + return 0; + + result = ssup->comparator(adist[i], bdist[i], ssup); + if (result != 0) + return result; + } + + return 0; +} + +/* + * Pairing heap provides getting topmost (greatest) element while KNN provides + * ascending sort. That's why we inverse the sort order. + */ +static int reorderqueue_cmp(const pairingheap_node* a, const pairingheap_node* b, void* arg) +{ + ReorderTuple* rta = (ReorderTuple *) a; + ReorderTuple* rtb = (ReorderTuple *) b; + IndexScanState* node = (IndexScanState *) arg; + + /* exchange argument order to invert the sort order */ + return cmp_orderbyvals(rtb->orderbyvals, rtb->orderbynulls, + rta->orderbyvals, rta->orderbynulls, + node); +} + +/* + * Helper function to push a tuple to the reorder queue. + */ +static void reorderqueue_push(IndexScanState* node, HeapTuple tuple, Datum* orderbyvals, bool* orderbynulls) +{ + IndexScanDesc scandesc = node->iss_ScanDesc; + EState* estate = node->ss.ps.state; + MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt); + ReorderTuple* rt; + int i; + + rt = (ReorderTuple *) palloc(sizeof(ReorderTuple)); + rt->htup = heap_copytuple(tuple); + rt->orderbyvals = + (Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys); + rt->orderbynulls = + (bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys); + for (i = 0; i < node->iss_NumOrderByKeys; i++) { + if (!orderbynulls[i]) + rt->orderbyvals[i] = datumCopy(orderbyvals[i], + node->iss_OrderByTypByVals[i], + node->iss_OrderByTypLens[i]); + else + rt->orderbyvals[i] = (Datum) 0; + rt->orderbynulls[i] = orderbynulls[i]; + } + pairingheap_add(node->iss_ReorderQueue, &rt->ph_node); + + MemoryContextSwitchTo(oldContext); +} + +/* + * Helper function to pop the next tuple from the reorder queue. + */ +static HeapTuple reorderqueue_pop(IndexScanState* node) +{ + HeapTuple result; + ReorderTuple* topmost; + + topmost = (ReorderTuple *) pairingheap_remove_first(node->iss_ReorderQueue); + + result = topmost->htup; + for (int i = 0; i < node->iss_NumOrderByKeys; i++) { + if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i]) { + pfree(DatumGetPointer(topmost->orderbyvals[i])); + } + } + pfree(topmost->orderbyvals); + pfree(topmost->orderbynulls); + pfree(topmost); + + return result; +} + /* ---------------------------------------------------------------- * ExecIndexScan(node) * ---------------------------------------------------------------- @@ -187,7 +490,15 @@ static TupleTableSlot* ExecIndexScan(PlanState* state) ExecIndexEvalRuntimeKeys(econtext, node->iss_RuntimeKeys, node->iss_NumRuntimeKeys); } - return ExecScan(&node->ss, (ExecScanAccessMtd)IndexNext, (ExecScanRecheckMtd)IndexRecheck); + if (node->iss_NumOrderByKeys > 0) { + return ExecScan(&node->ss, + (ExecScanAccessMtd) IndexNextWithReorder, + (ExecScanRecheckMtd) IndexRecheck); + } else { + return ExecScan(&node->ss, + (ExecScanAccessMtd) IndexNext, + (ExecScanRecheckMtd) IndexRecheck); + } } /* ---------------------------------------------------------------- @@ -670,6 +981,7 @@ IndexScanState* ExecInitIndexScan(IndexScan* node, EState* estate, int eflags) IndexScanState* index_state = NULL; Relation current_relation; bool relis_target = false; + int i; gstrace_entry(GS_TRC_ID_ExecInitIndexScan); /* @@ -709,6 +1021,7 @@ IndexScanState* ExecInitIndexScan(IndexScan* node, EState* estate, int eflags) index_state->ss.ps.targetlist = (List*)ExecInitExprByRecursion((Expr*)node->scan.plan.targetlist, (PlanState*)index_state); index_state->ss.ps.qual = (List*)ExecInitExprByRecursion((Expr*)node->scan.plan.qual, (PlanState*)index_state); index_state->indexqualorig = (List*)ExecInitExprByRecursion((Expr*)node->indexqualorig, (PlanState*)index_state); + index_state->indexorderbyorig = (List *)ExecInitExprByRecursion((Expr *) node->indexorderbyorig, (PlanState *) index_state); } /* @@ -802,6 +1115,50 @@ IndexScanState* ExecInitIndexScan(IndexScan* node, EState* estate, int eflags) NULL, /* no ArrayKeys */ NULL); + /* Initialize sort support, if we need to re-check ORDER BY exprs */ + if (index_state->iss_NumOrderByKeys > 0) { + int numOrderByKeys = index_state->iss_NumOrderByKeys; + + /* + * Prepare sort support, and look up the distance type for each ORDER + * BY expression. + */ + index_state->iss_SortSupport = + (SortSupport)palloc0(numOrderByKeys * sizeof(SortSupportData)); + index_state->iss_OrderByTypByVals = + (bool*)palloc(numOrderByKeys * sizeof(bool)); + index_state->iss_OrderByTypLens = + (int16*)palloc(numOrderByKeys * sizeof(int16)); + for (i = 0; i < index_state->iss_NumOrderByKeys; i++) { + Oid orderbyType; + Oid opfamily; + int16 strategy; + + PrepareSortSupportFromOrderingOp(node->indexorderbyops[i], + &index_state->iss_SortSupport[i]); + + if (!get_ordering_op_properties(node->indexorderbyops[i], + &opfamily, &orderbyType, &strategy)) { + ereport(LOG, + (errmsg("operator %u is not a valid ordering operator", + node->indexorderbyops[i]))); + } + get_typlenbyval(orderbyType, + &index_state->iss_OrderByTypLens[i], + &index_state->iss_OrderByTypByVals[i]); + } + + /* allocate arrays to hold the re-calculated distances */ + index_state->iss_OrderByValues = + (Datum*)palloc(index_state->iss_NumOrderByKeys * sizeof(Datum)); + index_state->iss_OrderByNulls = + (bool*)palloc(index_state->iss_NumOrderByKeys * sizeof(bool)); + + /* and initialize the reorder queue */ + index_state->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp, + index_state); + } + /* * If we have runtime keys, we need an ExprContext to evaluate them. The * node's standard context won't do because we want to reset that context diff --git a/src/gausskernel/storage/access/gist/gistget.cpp b/src/gausskernel/storage/access/gist/gistget.cpp index 0dfb8950f8..ea41a4129c 100644 --- a/src/gausskernel/storage/access/gist/gistget.cpp +++ b/src/gausskernel/storage/access/gist/gistget.cpp @@ -20,6 +20,7 @@ #include "access/gist_private.h" #include "access/relscan.h" +#include "catalog/pg_type.h" #include "miscadmin.h" #include "pgstat.h" #include "utils/builtins.h" @@ -48,7 +49,7 @@ * so we don't need to worry about cleaning up allocated memory, either here * or in the implementation of any Consistent or Distance methods. */ -static bool gistindex_keytest(IndexScanDesc scan, IndexTuple tuple, Page page, OffsetNumber offset, bool *recheck_p) +static bool gistindex_keytest(IndexScanDesc scan, IndexTuple tuple, Page page, OffsetNumber offset, bool *recheck_p, bool *recheck_distances_p) { GISTScanOpaque so = (GISTScanOpaque)scan->opaque; GISTSTATE *giststate = so->giststate; @@ -58,6 +59,7 @@ static bool gistindex_keytest(IndexScanDesc scan, IndexTuple tuple, Page page, O Relation r = scan->indexRelation; *recheck_p = false; + *recheck_distances_p = false; /* * If it's a leftover invalid tuple from pre-9.1, treat it as a match with @@ -153,26 +155,31 @@ static bool gistindex_keytest(IndexScanDesc scan, IndexTuple tuple, Page page, O } else { Datum dist; GISTENTRY de; + bool recheck = false; gistdentryinit(giststate, key->sk_attno - 1, &de, datum, r, page, offset, FALSE, isNull); /* * Call the Distance function to evaluate the distance. The * arguments are the index datum (as a GISTENTRY*), the comparison - * datum, and the ordering operator's strategy number and subtype - * from pg_amop. + * datum, the ordering operator's strategy number and subtype from + * pg_amop, and the recheck flag. * * (Presently there's no need to pass the subtype since it'll * always be zero, but might as well pass it for possible future * use.) * - * Note that Distance functions don't get a recheck argument. We - * can't tolerate lossy distance calculations on leaf tuples; - * there is no opportunity to re-sort the tuples afterwards. + * If the function sets the recheck flag, the returned distance is + * a lower bound on the true distance and needs to be rechecked. + * We initialize the flag to 'false'. This flag was added in + * version 9.5; distance functions written before that won't know + * about the flag, but are expected to never be lossy. */ - dist = FunctionCall4Coll(&key->sk_func, key->sk_collation, PointerGetDatum(&de), key->sk_argument, - Int32GetDatum(key->sk_strategy), ObjectIdGetDatum(key->sk_subtype)); - + recheck = false; + dist = FunctionCall5Coll(&key->sk_func, key->sk_collation, PointerGetDatum(&de), key->sk_argument, + Int32GetDatum(key->sk_strategy), ObjectIdGetDatum(key->sk_subtype), + PointerGetDatum(&recheck)); + *recheck_distances_p |= recheck; *distance_p = DatumGetFloat8(dist); } @@ -245,7 +252,7 @@ static void gistScanPage(IndexScanDesc scan, const GISTSearchItem *pageItem, con oldcxt = MemoryContextSwitchTo(so->queueCxt); /* Create new GISTSearchItem for the right sibling index page */ - item = (GISTSearchItem *)palloc(sizeof(GISTSearchItem)); + item = (GISTSearchItem *)palloc(GSIHDRSZ + sizeof(double) * scan->numberOfOrderBys); item->next = NULL; item->blkno = opaque->rightlink; item->data.parentlsn = pageItem->data.parentlsn; @@ -257,6 +264,9 @@ static void gistScanPage(IndexScanDesc scan, const GISTSearchItem *pageItem, con ret = memcpy_s(tmpItem->distances, sizeof(double) * scan->numberOfOrderBys, myDistances, sizeof(double) * scan->numberOfOrderBys); securec_check(ret, "", ""); + ret = memcpy_s(item->distances, sizeof(double) * scan->numberOfOrderBys, myDistances, + sizeof(double) * scan->numberOfOrderBys); + securec_check(ret, "", ""); } (void)rb_insert(so->queue, (RBNode *)tmpItem, &isNew); @@ -273,6 +283,7 @@ static void gistScanPage(IndexScanDesc scan, const GISTSearchItem *pageItem, con IndexTuple it = (IndexTuple)PageGetItem(page, PageGetItemId(page, i)); bool match = false; bool recheck = false; + bool recheck_distances = false; /* * Must call gistindex_keytest in tempCxt, and clean up any leftover @@ -280,7 +291,7 @@ static void gistScanPage(IndexScanDesc scan, const GISTSearchItem *pageItem, con */ oldcxt = MemoryContextSwitchTo(so->giststate->tempCxt); - match = gistindex_keytest(scan, it, page, i, &recheck); + match = gistindex_keytest(scan, it, page, i, &recheck, &recheck_distances); (void)MemoryContextSwitchTo(oldcxt); MemoryContextReset(so->giststate->tempCxt); @@ -315,7 +326,7 @@ static void gistScanPage(IndexScanDesc scan, const GISTSearchItem *pageItem, con oldcxt = MemoryContextSwitchTo(so->queueCxt); /* Create new GISTSearchItem for this item */ - item = (GISTSearchItem *)palloc(sizeof(GISTSearchItem)); + item = (GISTSearchItem *)palloc(GSIHDRSZ + sizeof(double) * scan->numberOfOrderBys); item->next = NULL; if (GistPageIsLeaf(page)) { @@ -323,6 +334,7 @@ static void gistScanPage(IndexScanDesc scan, const GISTSearchItem *pageItem, con item->blkno = InvalidBlockNumber; item->data.heap.heapPtr = it->t_tid; item->data.heap.recheck = recheck; + item->data.heap.recheckDistances = recheck_distances; } else { /* Creating index-page GISTSearchItem */ item->blkno = ItemPointerGetBlockNumber(&it->t_tid); @@ -343,6 +355,9 @@ static void gistScanPage(IndexScanDesc scan, const GISTSearchItem *pageItem, con ret = memcpy_s(tmpItem->distances, sizeof(double) * scan->numberOfOrderBys, so->distances, sizeof(double) * scan->numberOfOrderBys); securec_check(ret, "", ""); + ret = memcpy_s(item->distances, sizeof(double) * scan->numberOfOrderBys, so->distances, + sizeof(double) * scan->numberOfOrderBys); + securec_check(ret, "", ""); } (void)rb_insert(so->queue, (RBNode *)tmpItem, &isNew); @@ -400,6 +415,7 @@ static bool getNextNearest(IndexScanDesc scan) { GISTScanOpaque so = (GISTScanOpaque)scan->opaque; bool res = false; + int i = 0; do { GISTSearchItem *item = getNextGISTSearchItem(so); @@ -412,6 +428,42 @@ static bool getNextNearest(IndexScanDesc scan) scan->xs_ctup.t_self = item->data.heap.heapPtr; scan->xs_recheck = item->data.heap.recheck; res = true; + scan->xs_recheckorderby = item->data.heap.recheckDistances; + for (i = 0; i < scan->numberOfOrderBys; i++) { + if (so->orderByTypes[i] == FLOAT8OID) { +#ifndef USE_FLOAT8_BYVAL + /* must free any old value to avoid memory leakage */ + if (!scan->xs_orderbynulls[i]) { + pfree(DatumGetPointer(scan->xs_orderbyvals[i])); + } +#endif + scan->xs_orderbyvals[i] = Float8GetDatum(item->distances[i]); + scan->xs_orderbynulls[i] = false; + } else if (so->orderByTypes[i] == FLOAT4OID) { + /* convert distance function's result to ORDER BY type */ +#ifndef USE_FLOAT4_BYVAL + /* must free any old value to avoid memory leakage */ + if (!scan->xs_orderbynulls[i]) { + pfree(DatumGetPointer(scan->xs_orderbyvals[i])); + } +#endif + scan->xs_orderbyvals[i] = Float4GetDatum((float4) item->distances[i]); + scan->xs_orderbynulls[i] = false; + } else { + /* + * If the ordering operator's return value is anything + * else, we don't know how to convert the float8 bound + * calculated by the distance function to that. The + * executor won't actually need the order by values we + * return here, if there are no lossy results, so only + * insist on converting if the *recheck flag is set. + */ + if (scan->xs_recheckorderby) + ereport(ERROR, + (errmsg("GiST operator family's FOR ORDER BY operator must return float8 or float4 if the distance function is lossy"))); + scan->xs_orderbynulls[i] = true; + } + } } else { /* visit an index page, extract its items into queue */ CHECK_FOR_INTERRUPTS(); diff --git a/src/gausskernel/storage/access/gist/gistscan.cpp b/src/gausskernel/storage/access/gist/gistscan.cpp index ccb885f01b..125b102984 100644 --- a/src/gausskernel/storage/access/gist/gistscan.cpp +++ b/src/gausskernel/storage/access/gist/gistscan.cpp @@ -19,6 +19,7 @@ #include "access/gist_private.h" #include "access/gistscan.h" #include "access/relscan.h" +#include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/rel.h" #include "utils/rel_gs.h" @@ -118,6 +119,13 @@ Datum gistbeginscan(PG_FUNCTION_ARGS) so->tmpTreeItem = (GISTSearchTreeItem *)palloc(GSTIHDRSZ + sizeof(double) * scan->numberOfOrderBys); so->distances = (double *)palloc(sizeof(double) * scan->numberOfOrderBys); so->qual_ok = true; /* in case there are zero keys */ + if (scan->numberOfOrderBys > 0) { + errno_t rc = EOK; + scan->xs_orderbyvals = (Datum*)palloc0(sizeof(Datum) * scan->numberOfOrderBys); + scan->xs_orderbynulls = (bool*)palloc(sizeof(bool) * scan->numberOfOrderBys); + rc = memset_s(scan->xs_orderbynulls, sizeof(bool) * scan->numberOfOrderBys, true, sizeof(bool) * scan->numberOfOrderBys); + securec_check(rc, "\0", "\0"); + } scan->opaque = so; @@ -235,6 +243,7 @@ Datum gistrescan(PG_FUNCTION_ARGS) ret = memmove_s(scan->orderByData, scan->numberOfOrderBys * sizeof(ScanKeyData), orderbys, scan->numberOfOrderBys * sizeof(ScanKeyData)); securec_check(ret, "", ""); + so->orderByTypes = (Oid *) palloc(scan->numberOfOrderBys * sizeof(Oid)); /* * Modify the order-by key so that the Distance method is called for @@ -256,6 +265,19 @@ Datum gistrescan(PG_FUNCTION_ARGS) (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("missing support function %d for attribute %d of index \"%s\"", GIST_DISTANCE_PROC, skey->sk_attno, RelationGetRelationName(scan->indexRelation)))); + /* + * Look up the datatype returned by the original ordering operator. + * GiST always uses a float8 for the distance function, but the + * ordering operator could be anything else. + * + * XXX: The distance function is only allowed to be lossy if the + * ordering operator's result type is float4 or float8. Otherwise + * we don't know how to return the distance to the executor. But + * we cannot check that here, as we won't know if the distance + * function is lossy until it returns *recheck = true for the + * first time. + */ + so->orderByTypes[i] = get_func_rettype(skey->sk_func.fn_oid); } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 61970bc0b5..0e25a372bf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -113,6 +113,7 @@ typedef struct GISTSTATE { typedef struct GISTSearchHeapItem { ItemPointerData heapPtr; bool recheck; /* T if quals must be rechecked */ + bool recheckDistances; /* T if distances must be rechecked */ } GISTSearchHeapItem; /* Unvisited item, either index page or heap tuple */ @@ -124,8 +125,11 @@ typedef struct GISTSearchItem { /* we must store parentlsn to detect whether a split occurred */ GISTSearchHeapItem heap; /* heap info, if heap tuple */ } data; + double distances[FLEXIBLE_ARRAY_MEMBER]; /* numberOfOrderBys entries */ } GISTSearchItem; +#define GSIHDRSZ offsetof(GISTSearchItem, distances) + #define GISTSearchItemIsHeap(item) ((item).blkno == InvalidBlockNumber) /* @@ -147,6 +151,7 @@ typedef struct GISTSearchTreeItem { */ typedef struct GISTScanOpaqueData { GISTSTATE *giststate; /* index information, see above */ + Oid *orderByTypes; /* datatypes of ORDER BY expressions */ RBTree *queue; /* queue of unvisited items */ MemoryContext queueCxt; /* context holding the queue */ bool qual_ok; /* false if qual can never be satisfied */ diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h index c05568ebd4..8ba4d19317 100644 --- a/src/include/access/relscan.h +++ b/src/include/access/relscan.h @@ -157,6 +157,16 @@ typedef struct IndexScanDescData { Buffer xs_cbuf; /* current heap buffer in scan, if any */ /* NB: if xs_cbuf is not InvalidBuffer, we hold a pin on that buffer */ bool xs_recheck; /* T means scan keys must be rechecked */ + /* + * When fetching with an ordering operator, the values of the ORDER BY + * expressions of the last returned tuple, according to the index. If + * xs_recheckorderby is true, these need to be rechecked just like the + * scan keys, and the values returned here are a lower-bound on the actual + * values. + */ + Datum* xs_orderbyvals; + bool* xs_orderbynulls; + bool xs_recheckorderby; /* used in ubtree only, indicate that we need to recheck the returned IndexTuple */ bool xs_recheck_itup; diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 38bd7e98eb..4ea1017bd4 100755 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -19,6 +19,7 @@ #include "access/relscan.h" #include "bulkload/dist_fdw.h" #include "executor/instrument.h" +#include "lib/pairingheap.h" #include "nodes/params.h" #include "nodes/plannodes.h" #include "storage/pagecompress.h" @@ -1974,6 +1975,7 @@ typedef struct { * IndexScanState information * * indexqualorig execution state for indexqualorig expressions + * indexorderbyorig execution state for indexorderbyorig expressions * ScanKeys Skey structures for index quals * NumScanKeys number of ScanKeys * OrderByKeys Skey structures for index ordering operators @@ -1984,11 +1986,20 @@ typedef struct { * RuntimeContext expr context for evaling runtime Skeys * RelationDesc index relation descriptor * ScanDesc index scan descriptor + * + * ReorderQueue tuples that need reordering due to re-check + * ReachedEnd have we fetched all tuples from index already? + * OrderByValues values of ORDER BY exprs of last fetched tuple + * OrderByNulls null flags for OrderByValues + * SortSupport for reordering ORDER BY exprs + * OrderByTypByVals is the datatype of order by expression pass-by-value? + * OrderByTypLens typlens of the datatypes of order by expressions * ---------------- */ typedef struct IndexScanState { ScanState ss; /* its first field is NodeTag */ List* indexqualorig; + List* indexorderbyorig; ScanKey iss_ScanKeys; int iss_NumScanKeys; ScanKey iss_OrderByKeys; @@ -2002,6 +2013,14 @@ typedef struct IndexScanState { List* iss_IndexPartitionList; LOCKMODE lockMode; Relation iss_CurrentIndexPartition; + /* These are needed for re-checking ORDER BY expr ordering */ + pairingheap* iss_ReorderQueue; + bool iss_ReachedEnd; + Datum* iss_OrderByValues; + bool* iss_OrderByNulls; + SortSupport iss_SortSupport; + bool* iss_OrderByTypByVals; + int16* iss_OrderByTypLens; } IndexScanState; /* ---------------- diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index c93dfc697e..894aade367 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -737,8 +737,13 @@ typedef struct TsStoreScan: public Scan { * index column order. Only the expressions are provided, not the auxiliary * sort-order information from the ORDER BY SortGroupClauses; it's assumed * that the sort ordering is fully determinable from the top-level operators. - * indexorderbyorig is unused at run time, but is needed for EXPLAIN. - * (Note these fields are used for amcanorderbyop cases, not amcanorder cases.) + * indexorderbyorig is used at runtime to recheck the ordering, if the index + * cannot calculate an accurate ordering. It is also needed for EXPLAIN. + * + * indexorderbyops is an array of operators used to sort the ORDER BY + * expressions, used together with indexorderbyorig to recheck ordering at run + * time. (Note these fields are used for amcanorderbyop cases, not amcanorder + * cases.) * * indexorderdir specifies the scan ordering, for indexscans on amcanorder * indexes (for other indexes it should be "don't care"). @@ -752,6 +757,7 @@ typedef struct IndexScan { List* indexqualorig; /* the same in original form */ List* indexorderby; /* list of index ORDER BY exprs */ List* indexorderbyorig; /* the same in original form */ + Oid* indexorderbyops; /* operators to sort ORDER BY exprs */ ScanDirection indexorderdir; /* forward or backward or don't care */ bool usecstoreindex; /* mark the column store index */ Index indexscan_relid; /* Hack for column store index, treat the index as normal relation */ -- Gitee From cafa2fe74cbb2b221c870b4577e32015f0ff921b Mon Sep 17 00:00:00 2001 From: huyinghao Date: Fri, 11 Apr 2025 18:00:16 +0800 Subject: [PATCH 2/6] =?UTF-8?q?circle=20=E7=B1=BB=E5=9E=8B=20GiST=20?= =?UTF-8?q?=E7=B4=A2=E5=BC=95=E5=9C=BA=E6=99=AF=E6=94=AF=E6=8C=81=20Order?= =?UTF-8?q?=20by=20expr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/catalog/builtin_funcs.ini | 8 ++++ src/common/backend/utils/adt/geo_ops.cpp | 15 +++++++ src/common/backend/utils/init/globals.cpp | 2 +- .../storage/access/gist/gistproc.cpp | 45 +++++++++++++++++++ src/include/catalog/pg_amop.data | 1 + src/include/catalog/pg_amproc.h | 1 + src/include/catalog/pg_operator.data | 2 + .../rollback-post_catalog_maindb_93_045.sql | 5 +++ .../rollback-post_catalog_otherdb_93_045.sql | 5 +++ .../upgrade-post_catalog_maindb_93_045.sql | 22 +++++++++ .../upgrade-post_catalog_otherdb_93_045.sql | 22 +++++++++ src/include/utils/geo_decls.h | 2 + .../regress/expected/create_index_gist.out | 31 +++++++++++++ src/test/regress/sql/create_index_gist.sql | 10 +++++ 14 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql create mode 100644 src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql create mode 100644 src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql create mode 100644 src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql diff --git a/src/common/backend/catalog/builtin_funcs.ini b/src/common/backend/catalog/builtin_funcs.ini index f119e3548f..8a89ac7864 100644 --- a/src/common/backend/catalog/builtin_funcs.ini +++ b/src/common/backend/catalog/builtin_funcs.ini @@ -2467,6 +2467,10 @@ "dispell_lexize", 1, AddBuiltinFunc(_0(3732), _1("dispell_lexize"), _2(4), _3(true), _4(false), _5(dispell_lexize), _6(2281), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(4, 2281, 2281, 2281, 2281), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("dispell_lexize"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("(internal)"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "dist_cpoint", 1, + AddBuiltinFunc(_0(3291), _1("dist_cpoint"), _2(2), _3(true), _4(false), _5(dist_cpoint), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 718, 600), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("dist_cpoint"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), AddFuncGroup( "dist_cpoly", 1, AddBuiltinFunc(_0(728), _1("dist_cpoly"), _2(2), _3(true), _4(false), _5(dist_cpoly), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 718, 604), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("dist_cpoly"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) @@ -3537,6 +3541,10 @@ "gist_circle_consistent", 1, AddBuiltinFunc(_0(2591), _1("gist_circle_consistent"), _2(5), _3(true), _4(false), _5(gist_circle_consistent), _6(16), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(5, 2281, 718, 23, 26, 2281), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("gist_circle_consistent"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("GiST support"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "gist_circle_distance", 1, + AddBuiltinFunc(_0(3280), _1("gist_circle_distance"), _2(4), _3(true), _4(false), _5(gist_circle_distance), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(5, 2281, 600, 23, 26, 2281), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("gist_circle_distance"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("GiST support"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), AddFuncGroup( "gist_point_compress", 1, AddBuiltinFunc(_0(1030), _1("gist_point_compress"), _2(1), _3(true), _4(false), _5(gist_point_compress), _6(2281), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 2281), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("gist_point_compress"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("GiST support"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) diff --git a/src/common/backend/utils/adt/geo_ops.cpp b/src/common/backend/utils/adt/geo_ops.cpp index 95067987d8..775707c61f 100644 --- a/src/common/backend/utils/adt/geo_ops.cpp +++ b/src/common/backend/utils/adt/geo_ops.cpp @@ -4587,6 +4587,21 @@ Datum dist_pc(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } +/* + * Distance from a circle to a point + */ +Datum +dist_cpoint(PG_FUNCTION_ARGS) +{ + CIRCLE* circle = PG_GETARG_CIRCLE_P(0); + Point* point = PG_GETARG_POINT_P(1); + float8 result; + + result = point_dt(point, &circle->center) - circle->radius; + result = result < 0 ? 0 : result; + PG_RETURN_FLOAT8(result); +} + /* circle_center - returns the center point of the circle. */ Datum circle_center(PG_FUNCTION_ARGS) diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp index 57daef9306..99d1a880d8 100644 --- a/src/common/backend/utils/init/globals.cpp +++ b/src/common/backend/utils/init/globals.cpp @@ -77,7 +77,7 @@ bool will_shutdown = false; * ********************************************/ -const uint32 GRAND_VERSION_NUM = 93044; +const uint32 GRAND_VERSION_NUM = 93045; /******************************************** * 2.VERSION NUM FOR EACH FEATURE diff --git a/src/gausskernel/storage/access/gist/gistproc.cpp b/src/gausskernel/storage/access/gist/gistproc.cpp index e2f5df877d..e2eb59492b 100644 --- a/src/gausskernel/storage/access/gist/gistproc.cpp +++ b/src/gausskernel/storage/access/gist/gistproc.cpp @@ -1265,3 +1265,48 @@ Datum gist_point_distance(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(distance); } + +static float8 gist_bbox_distance(GISTENTRY *entry, Datum query, StrategyNumber strategy) +{ + float8 distance; + StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset; + + switch (strategyGroup) { + case PointStrategyNumberGroup: + distance = computeDistance(false, + DatumGetBoxP(entry->key), + DatumGetPointP(query)); + break; + default: + elog(ERROR, "unrecognized strategy number: %d", strategy); + distance = 0.0; /* keep compiler quiet */ + } + + return distance; +} + +/* + * The inexact GiST distance methods for geometric types that store bounding + * boxes. + * + * Compute lossy distance from point to index entries. The result is inexact + * because index entries are bounding boxes, not the exact shapes of the + * indexed geometric types. We use distance from point to MBR of index entry. + * This is a lower bound estimate of distance from point to indexed geometric + * type. + */ +Datum gist_circle_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY* entry = (GISTENTRY *) PG_GETARG_POINTER(0); + Datum query = PG_GETARG_DATUM(1); + StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); + + /* Oid subtype = PG_GETARG_OID(3); */ + bool* recheck = (bool *) PG_GETARG_POINTER(4); + float8 distance; + + distance = gist_bbox_distance(entry, query, strategy); + *recheck = true; + + PG_RETURN_FLOAT8(distance); +} diff --git a/src/include/catalog/pg_amop.data b/src/include/catalog/pg_amop.data index 51bfc7637f..f52d01b458 100644 --- a/src/include/catalog/pg_amop.data +++ b/src/include/catalog/pg_amop.data @@ -644,6 +644,7 @@ DATA(insert ( 2595 718 718 11 s 1514 783 0 )); DATA(insert ( 2595 718 718 12 s 2590 783 0 )); DATA(insert ( 2595 718 718 13 s 2865 783 0 )); DATA(insert ( 2595 718 718 14 s 2864 783 0 )); +DATA(insert ( 2595 718 600 15 o 3291 783 1970 )); /* * gin array_ops (these anyarray operators are used with all the opclasses diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h index 7b54d6b4b2..a5b0a360b7 100644 --- a/src/include/catalog/pg_amproc.h +++ b/src/include/catalog/pg_amproc.h @@ -245,6 +245,7 @@ DATA(insert ( 2595 718 718 4 2580 )); DATA(insert ( 2595 718 718 5 2581 )); DATA(insert ( 2595 718 718 6 2582 )); DATA(insert ( 2595 718 718 7 2584 )); +DATA(insert ( 2595 718 718 8 3280 )); DATA(insert ( 3655 3614 3614 1 3654 )); DATA(insert ( 3655 3614 3614 2 3651 )); DATA(insert ( 3655 3614 3614 3 3648 )); diff --git a/src/include/catalog/pg_operator.data b/src/include/catalog/pg_operator.data index 71d9af566f..df4f22d152 100644 --- a/src/include/catalog/pg_operator.data +++ b/src/include/catalog/pg_operator.data @@ -972,6 +972,8 @@ DATA(insert OID = 1522 ("<->" PGNSP PGUID b f f 600 718 701 0 0 d DESCR("distance between"); DATA(insert OID = 1523 ("<->" PGNSP PGUID b f f 718 604 701 0 0 dist_cpoly - -)); DESCR("distance between"); +DATA(insert OID = 3291 ("<->" PGNSP PGUID b f f 718 600 701 1522 0 dist_cpoint - -)); +DESCR("distance between"); /* additional geometric operators - thomas 1997-07-09 */ DATA(insert OID = 1524 ("<->" PGNSP PGUID b f f 628 603 701 0 0 dist_lb - -)); diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql new file mode 100644 index 0000000000..b71020422b --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql @@ -0,0 +1,5 @@ +ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (internal, point, int4, oid, internal); +ALTER OPERATOR FAMILY circle_ops USING gist DROP OPERATOR 15 (circle, point); +DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; +DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); +DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); \ No newline at end of file diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql new file mode 100644 index 0000000000..b71020422b --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql @@ -0,0 +1,5 @@ +ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (internal, point, int4, oid, internal); +ALTER OPERATOR FAMILY circle_ops USING gist DROP OPERATOR 15 (circle, point); +DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; +DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); +DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); \ No newline at end of file diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql new file mode 100644 index 0000000000..91f842cdef --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql @@ -0,0 +1,22 @@ + +-- function dist_cpoint +DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3291; +CREATE FUNCTION pg_catalog.dist_cpoint(circle,point) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'dist_cpoint'; + +-- function gist_circle_distance +DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3280; +CREATE FUNCTION pg_catalog.gist_circle_distance((internal, point, int4, oid, internal) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_circle_distance'; + +-- operator circle <-> point +DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_GENERAL, 3291; +CREATE OPERATOR pg_catalog.<->( +leftarg = circle, rightarg = point, procedure = dist_cpoint +); +COMMENT ON OPERATOR pg_catalog.<->(circle, point) IS 'distance between'; + +-- update circle_ops +ALTER OPERATOR FAMILY circle_ops USING gist ADD OPERATOR 15 <->(circle, point) FOR ORDER BY pg_catalog.float_ops; +ALTER OPERATOR FAMILY circle_ops USING gist ADD FUNCTION 8 gist_circle_distance(internal, point, int4, oid, internal); diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql new file mode 100644 index 0000000000..91f842cdef --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql @@ -0,0 +1,22 @@ + +-- function dist_cpoint +DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3291; +CREATE FUNCTION pg_catalog.dist_cpoint(circle,point) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'dist_cpoint'; + +-- function gist_circle_distance +DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3280; +CREATE FUNCTION pg_catalog.gist_circle_distance((internal, point, int4, oid, internal) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_circle_distance'; + +-- operator circle <-> point +DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_GENERAL, 3291; +CREATE OPERATOR pg_catalog.<->( +leftarg = circle, rightarg = point, procedure = dist_cpoint +); +COMMENT ON OPERATOR pg_catalog.<->(circle, point) IS 'distance between'; + +-- update circle_ops +ALTER OPERATOR FAMILY circle_ops USING gist ADD OPERATOR 15 <->(circle, point) FOR ORDER BY pg_catalog.float_ops; +ALTER OPERATOR FAMILY circle_ops USING gist ADD FUNCTION 8 gist_circle_distance(internal, point, int4, oid, internal); diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h index 1cd1824f7f..e43cdb02e9 100644 --- a/src/include/utils/geo_decls.h +++ b/src/include/utils/geo_decls.h @@ -384,6 +384,7 @@ extern Datum circle_diameter(PG_FUNCTION_ARGS); extern Datum circle_radius(PG_FUNCTION_ARGS); extern Datum circle_distance(PG_FUNCTION_ARGS); extern Datum dist_pc(PG_FUNCTION_ARGS); +extern Datum dist_cpoint(PG_FUNCTION_ARGS); extern Datum dist_cpoly(PG_FUNCTION_ARGS); extern Datum circle_center(PG_FUNCTION_ARGS); extern Datum cr_circle(PG_FUNCTION_ARGS); @@ -407,6 +408,7 @@ extern Datum gist_circle_compress(PG_FUNCTION_ARGS); extern Datum gist_circle_consistent(PG_FUNCTION_ARGS); extern Datum gist_point_compress(PG_FUNCTION_ARGS); extern Datum gist_point_consistent(PG_FUNCTION_ARGS); +extern Datum gist_circle_distance(PG_FUNCTION_ARGS); extern Datum gist_point_distance(PG_FUNCTION_ARGS); /* geo_selfuncs.c */ diff --git a/src/test/regress/expected/create_index_gist.out b/src/test/regress/expected/create_index_gist.out index a7fd7d3ec1..63b9e91728 100644 --- a/src/test/regress/expected/create_index_gist.out +++ b/src/test/regress/expected/create_index_gist.out @@ -567,6 +567,36 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0 create table t(id int, c_point point); insert into t select id, point'(1, 2)' from (select * from generate_series(1, 200000) as id) as x; create index i on t using gist(c_point) with (buffering=on); +-- test 'Order by' using GiST indexscan with reorder on circle +CREATE TABLE circle_tbl2(f1 circle); +INSERT INTO circle_tbl2(f1) VALUES('<(7.1,5),1>'::circle),('<(2.5,8.5),2.5>'::circle),('<(1,2),1>'::circle),('<(2,2),1>'::circle); +CREATE INDEX circle_ind2 on circle_tbl2 USING gist(f1); +EXPLAIN (COSTS false) SELECT /*+ indexscan(circle_tbl2 circle_ind2) */ * FROM circle_tbl2 ORDER BY f1 <-> '(5,5)'::point ASC; + QUERY PLAN +--------------------------------------------- + Index Scan using circle_ind2 on circle_tbl2 + Order By: (f1 <-> '(5,5)'::point) +(2 rows) + +-- '<(7.1,5),1>' shoule be output before'<(2.5,8.5),2.5>', and it is reverse if there is no 'reorder' +SELECT /*+ indexscan(circle_tbl2 circle_ind2) */ f1, trunc(f1 <-> '(5,5)'::point, 2) AS d FROM circle_tbl2 ORDER BY f1 <-> '(5,5)'::point ASC; + f1 | d +-----------------+------ + <(7.1,5),1> | 1.10 + <(2.5,8.5),2.5> | 1.80 + <(2,2),1> | 3.24 + <(1,2),1> | 4.00 +(4 rows) + +SELECT /*+ tablescan(circle_tbl2) */ f1, trunc(f1 <-> '(5,5)'::point, 2) AS d FROM circle_tbl2 ORDER BY f1 <-> '(5,5)'::point ASC; + f1 | d +-----------------+------ + <(7.1,5),1> | 1.10 + <(2.5,8.5),2.5> | 1.80 + <(2,2),1> | 3.24 + <(1,2),1> | 4.00 +(4 rows) + RESET enable_seqscan; RESET enable_indexscan; RESET enable_bitmapscan; @@ -576,4 +606,5 @@ DROP TABLE polygon_tbl; DROP TABLE circle_tbl; DROP TABLE point_tbl; DROP TABLE t; +DROP TABLE circle_tbl2; DROP SCHEMA create_index_gist CASCADE; diff --git a/src/test/regress/sql/create_index_gist.sql b/src/test/regress/sql/create_index_gist.sql index a20655a11f..980e4e2762 100644 --- a/src/test/regress/sql/create_index_gist.sql +++ b/src/test/regress/sql/create_index_gist.sql @@ -236,6 +236,15 @@ create table t(id int, c_point point); insert into t select id, point'(1, 2)' from (select * from generate_series(1, 200000) as id) as x; create index i on t using gist(c_point) with (buffering=on); +-- test 'Order by' using GiST indexscan with reorder on circle +CREATE TABLE circle_tbl2(f1 circle); +INSERT INTO circle_tbl2(f1) VALUES('<(7.1,5),1>'::circle),('<(2.5,8.5),2.5>'::circle),('<(1,2),1>'::circle),('<(2,2),1>'::circle); +CREATE INDEX circle_ind2 on circle_tbl2 USING gist(f1); +EXPLAIN (COSTS false) SELECT /*+ indexscan(circle_tbl2 circle_ind2) */ * FROM circle_tbl2 ORDER BY f1 <-> '(5,5)'::point ASC; +-- '<(7.1,5),1>' shoule be output before'<(2.5,8.5),2.5>', and it is reverse if there is no 'reorder' +SELECT /*+ indexscan(circle_tbl2 circle_ind2) */ f1, trunc(f1 <-> '(5,5)'::point, 2) AS d FROM circle_tbl2 ORDER BY f1 <-> '(5,5)'::point ASC; +SELECT /*+ tablescan(circle_tbl2) */ f1, trunc(f1 <-> '(5,5)'::point, 2) AS d FROM circle_tbl2 ORDER BY f1 <-> '(5,5)'::point ASC; + RESET enable_seqscan; RESET enable_indexscan; RESET enable_bitmapscan; @@ -245,4 +254,5 @@ DROP TABLE polygon_tbl; DROP TABLE circle_tbl; DROP TABLE point_tbl; DROP TABLE t; +DROP TABLE circle_tbl2; DROP SCHEMA create_index_gist CASCADE; \ No newline at end of file -- Gitee From fbfcf6fd1592cc9235889ffd246b7da92daa9357 Mon Sep 17 00:00:00 2001 From: huyinghao Date: Mon, 14 Apr 2025 15:01:33 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rollback-post_catalog_maindb_93_045.sql | 2 +- .../rollback-post_catalog_otherdb_93_045.sql | 2 +- .../upgrade-post_catalog_maindb_93_045.sql | 4 ++-- .../upgrade-post_catalog_otherdb_93_045.sql | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql index b71020422b..ab6740dc6d 100644 --- a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql @@ -1,4 +1,4 @@ -ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (internal, point, int4, oid, internal); +ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (circle, circle); ALTER OPERATOR FAMILY circle_ops USING gist DROP OPERATOR 15 (circle, point); DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql index b71020422b..ab6740dc6d 100644 --- a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql @@ -1,4 +1,4 @@ -ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (internal, point, int4, oid, internal); +ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (circle, circle); ALTER OPERATOR FAMILY circle_ops USING gist DROP OPERATOR 15 (circle, point); DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql index 91f842cdef..8ca168c1e9 100644 --- a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql @@ -7,7 +7,7 @@ CREATE FUNCTION pg_catalog.dist_cpoint(circle,point) RETURNS pg_catalog.float8 L -- function gist_circle_distance DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3280; -CREATE FUNCTION pg_catalog.gist_circle_distance((internal, point, int4, oid, internal) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_circle_distance'; +CREATE FUNCTION pg_catalog.gist_circle_distance(internal, point, int4, oid, internal) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_circle_distance'; -- operator circle <-> point DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; @@ -19,4 +19,4 @@ COMMENT ON OPERATOR pg_catalog.<->(circle, point) IS 'distance between'; -- update circle_ops ALTER OPERATOR FAMILY circle_ops USING gist ADD OPERATOR 15 <->(circle, point) FOR ORDER BY pg_catalog.float_ops; -ALTER OPERATOR FAMILY circle_ops USING gist ADD FUNCTION 8 gist_circle_distance(internal, point, int4, oid, internal); +ALTER OPERATOR FAMILY circle_ops USING gist ADD FUNCTION 8 (circle, circle) gist_circle_distance(internal, point, int4, oid, internal); diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql index 91f842cdef..8ca168c1e9 100644 --- a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql @@ -7,7 +7,7 @@ CREATE FUNCTION pg_catalog.dist_cpoint(circle,point) RETURNS pg_catalog.float8 L -- function gist_circle_distance DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3280; -CREATE FUNCTION pg_catalog.gist_circle_distance((internal, point, int4, oid, internal) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_circle_distance'; +CREATE FUNCTION pg_catalog.gist_circle_distance(internal, point, int4, oid, internal) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_circle_distance'; -- operator circle <-> point DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; @@ -19,4 +19,4 @@ COMMENT ON OPERATOR pg_catalog.<->(circle, point) IS 'distance between'; -- update circle_ops ALTER OPERATOR FAMILY circle_ops USING gist ADD OPERATOR 15 <->(circle, point) FOR ORDER BY pg_catalog.float_ops; -ALTER OPERATOR FAMILY circle_ops USING gist ADD FUNCTION 8 gist_circle_distance(internal, point, int4, oid, internal); +ALTER OPERATOR FAMILY circle_ops USING gist ADD FUNCTION 8 (circle, circle) gist_circle_distance(internal, point, int4, oid, internal); -- Gitee From 5030435ebb2ea6f3b2cfe8bc2e9c29ddc3d5a1aa Mon Sep 17 00:00:00 2001 From: huyinghao Date: Mon, 14 Apr 2025 15:40:31 +0800 Subject: [PATCH 4/6] =?UTF-8?q?rollback=20=E8=84=9A=E6=9C=AC=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rollback-post_catalog_maindb_93_045.sql | 25 ++++++++++++++++--- .../rollback-post_catalog_otherdb_93_045.sql | 25 ++++++++++++++++--- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql index ab6740dc6d..10c8b96d20 100644 --- a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql @@ -1,5 +1,24 @@ -ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (circle, circle); -ALTER OPERATOR FAMILY circle_ops USING gist DROP OPERATOR 15 (circle, point); + +DO +$do$ +DECLARE + havefunc8 boolean; + haveoper15 boolean; +BEGIN + select count(*)>0 into havefunc8 from pg_amproc where amprocfamily = 2595 and amprocnum = 8; + select count(*)>0 into haveoper15 from pg_amop where amopfamily = 2595 and amopstrategy = 15; + + IF havefunc8 = true then + ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (circle, circle); + END IF; + + IF haveoper15 = true then + ALTER OPERATOR FAMILY circle_ops USING gist DROP OPERATOR 15 (circle, point); + END IF; +END +$do$; + + DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); -DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); \ No newline at end of file +DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql index ab6740dc6d..10c8b96d20 100644 --- a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql @@ -1,5 +1,24 @@ -ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (circle, circle); -ALTER OPERATOR FAMILY circle_ops USING gist DROP OPERATOR 15 (circle, point); + +DO +$do$ +DECLARE + havefunc8 boolean; + haveoper15 boolean; +BEGIN + select count(*)>0 into havefunc8 from pg_amproc where amprocfamily = 2595 and amprocnum = 8; + select count(*)>0 into haveoper15 from pg_amop where amopfamily = 2595 and amopstrategy = 15; + + IF havefunc8 = true then + ALTER OPERATOR FAMILY circle_ops USING gist DROP FUNCTION 8 (circle, circle); + END IF; + + IF haveoper15 = true then + ALTER OPERATOR FAMILY circle_ops USING gist DROP OPERATOR 15 (circle, point); + END IF; +END +$do$; + + DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); -DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); \ No newline at end of file +DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); -- Gitee From e3132d799eec37bfb24a83597596959bbb52df8b Mon Sep 17 00:00:00 2001 From: huyinghao Date: Mon, 14 Apr 2025 17:57:40 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20gist=5Fpoint=5Fdistanc?= =?UTF-8?q?e=20=E5=87=BD=E6=95=B0=E5=92=8C=E4=BB=A3=E7=A0=81=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/catalog/builtin_funcs.ini | 4 +- src/common/backend/utils/adt/geo_ops.cpp | 3 +- .../runtime/executor/nodeIndexscan.cpp | 76 ++++++++++--------- .../storage/access/gist/gistget.cpp | 3 +- .../storage/access/gist/gistproc.cpp | 1 - .../storage/access/gist/gistscan.cpp | 3 +- src/include/catalog/pg_proc.h_for_llt | 2 +- .../rollback-post_catalog_maindb_93_045.sql | 5 ++ .../rollback-post_catalog_otherdb_93_045.sql | 5 ++ .../upgrade-post_catalog_maindb_93_045.sql | 5 ++ .../upgrade-post_catalog_otherdb_93_045.sql | 5 ++ 11 files changed, 68 insertions(+), 44 deletions(-) diff --git a/src/common/backend/catalog/builtin_funcs.ini b/src/common/backend/catalog/builtin_funcs.ini index 8a89ac7864..86b0479955 100644 --- a/src/common/backend/catalog/builtin_funcs.ini +++ b/src/common/backend/catalog/builtin_funcs.ini @@ -3543,7 +3543,7 @@ ), AddFuncGroup( "gist_circle_distance", 1, - AddBuiltinFunc(_0(3280), _1("gist_circle_distance"), _2(4), _3(true), _4(false), _5(gist_circle_distance), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(5, 2281, 600, 23, 26, 2281), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("gist_circle_distance"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("GiST support"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + AddBuiltinFunc(_0(3280), _1("gist_circle_distance"), _2(5), _3(true), _4(false), _5(gist_circle_distance), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(5, 2281, 600, 23, 26, 2281), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("gist_circle_distance"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("GiST support"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( "gist_point_compress", 1, @@ -3555,7 +3555,7 @@ ), AddFuncGroup( "gist_point_distance", 1, - AddBuiltinFunc(_0(3064), _1("gist_point_distance"), _2(4), _3(true), _4(false), _5(gist_point_distance), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(4, 2281, 600, 23, 26), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("gist_point_distance"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("GiST support"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + AddBuiltinFunc(_0(3064), _1("gist_point_distance"), _2(5), _3(true), _4(false), _5(gist_point_distance), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(5, 2281, 600, 23, 26, 2281), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("gist_point_distance"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("GiST support"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( "gist_poly_compress", 1, diff --git a/src/common/backend/utils/adt/geo_ops.cpp b/src/common/backend/utils/adt/geo_ops.cpp index 775707c61f..464fafd563 100644 --- a/src/common/backend/utils/adt/geo_ops.cpp +++ b/src/common/backend/utils/adt/geo_ops.cpp @@ -4590,8 +4590,7 @@ Datum dist_pc(PG_FUNCTION_ARGS) /* * Distance from a circle to a point */ -Datum -dist_cpoint(PG_FUNCTION_ARGS) +Datum dist_cpoint(PG_FUNCTION_ARGS) { CIRCLE* circle = PG_GETARG_CIRCLE_P(0); Point* point = PG_GETARG_POINT_P(1); diff --git a/src/gausskernel/runtime/executor/nodeIndexscan.cpp b/src/gausskernel/runtime/executor/nodeIndexscan.cpp index a24cd30461..a8176cf48e 100644 --- a/src/gausskernel/runtime/executor/nodeIndexscan.cpp +++ b/src/gausskernel/runtime/executor/nodeIndexscan.cpp @@ -51,8 +51,7 @@ * When an ordering operator is used, tuples fetched from the index that * need to be reordered are queued in a pairing heap, as ReorderTuples. */ -typedef struct -{ +typedef struct ReorderTuple { pairingheap_node ph_node; HeapTuple htup; Datum* orderbyvals; @@ -171,7 +170,7 @@ static TupleTableSlot* IndexNext(IndexScanState* node) * ORDER BY expressions, and reorder the tuples as necessary. * ---------------------------------------------------------------- */ -static TupleTableSlot * IndexNextWithReorder(IndexScanState* node) +static TupleTableSlot* IndexNextWithReorder(IndexScanState* node) { ExprContext* econtext; IndexScanDesc scandesc; @@ -219,39 +218,41 @@ static TupleTableSlot * IndexNextWithReorder(IndexScanState* node) /* * Fetch next tuple from the index. */ -next_indextuple: - tuple = (HeapTuple)index_getnext(scandesc, ForwardScanDirection); - if (!tuple) { + for(;;) { + tuple = (HeapTuple)index_getnext(scandesc, ForwardScanDirection); + if (!tuple) { + /* + * No more tuples from the index. But we still need to drain any + * remaining tuples from the queue before we're done. + */ + node->iss_ReachedEnd = true; + continue; + } + /* - * No more tuples from the index. But we still need to drain any - * remaining tuples from the queue before we're done. + * Store the scanned tuple in the scan tuple slot of the scan state. + * Note: we pass 'false' because tuples returned by amgetnext are + * pointers onto disk pages and must not be pfree()'d. */ - node->iss_ReachedEnd = true; - continue; - } + ExecStoreTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + scandesc->xs_cbuf, /* buffer containing tuple */ + false); /* don't pfree */ - /* - * Store the scanned tuple in the scan tuple slot of the scan state. - * Note: we pass 'false' because tuples returned by amgetnext are - * pointers onto disk pages and must not be pfree()'d. - */ - ExecStoreTuple(tuple, /* tuple to store */ - slot, /* slot to store in */ - scandesc->xs_cbuf, /* buffer containing tuple */ - false); /* don't pfree */ - - /* - * If the index was lossy, we have to recheck the index quals and - * ORDER BY expressions using the fetched tuple. - */ - if (scandesc->xs_recheck) { - econtext->ecxt_scantuple = slot; - ResetExprContext(econtext); - if (!ExecQual(node->indexqualorig, econtext, false)) { - /* Fails recheck, so drop it and loop back for another */ - InstrCountFiltered2(node, 1); - goto next_indextuple; + /* + * If the index was lossy, we have to recheck the index quals and + * ORDER BY expressions using the fetched tuple. + */ + if (scandesc->xs_recheck) { + econtext->ecxt_scantuple = slot; + ResetExprContext(econtext); + if (!ExecQual(node->indexqualorig, econtext, false)) { + /* Fails recheck, so drop it and loop back for another */ + InstrCountFiltered2(node, 1); + continue; + } } + break; } if (scandesc->xs_recheckorderby) { @@ -274,12 +275,15 @@ next_indextuple: scandesc->xs_orderbyvals, scandesc->xs_orderbynulls, node); - if (cmp < 0) + if (cmp < 0) { elog(ERROR, "index returned tuples in wrong order"); - else if (cmp == 0) + } else if (cmp == 0) { was_exact = true; - else + } + else { was_exact = false; + } + lastfetched_vals = node->iss_OrderByValues; lastfetched_nulls = node->iss_OrderByNulls; } else { @@ -1156,7 +1160,7 @@ IndexScanState* ExecInitIndexScan(IndexScan* node, EState* estate, int eflags) /* and initialize the reorder queue */ index_state->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp, - index_state); + index_state); } /* diff --git a/src/gausskernel/storage/access/gist/gistget.cpp b/src/gausskernel/storage/access/gist/gistget.cpp index ea41a4129c..5d54f02598 100644 --- a/src/gausskernel/storage/access/gist/gistget.cpp +++ b/src/gausskernel/storage/access/gist/gistget.cpp @@ -458,9 +458,10 @@ static bool getNextNearest(IndexScanDesc scan) * return here, if there are no lossy results, so only * insist on converting if the *recheck flag is set. */ - if (scan->xs_recheckorderby) + if (scan->xs_recheckorderby) { ereport(ERROR, (errmsg("GiST operator family's FOR ORDER BY operator must return float8 or float4 if the distance function is lossy"))); + } scan->xs_orderbynulls[i] = true; } } diff --git a/src/gausskernel/storage/access/gist/gistproc.cpp b/src/gausskernel/storage/access/gist/gistproc.cpp index e2eb59492b..9e850d25e8 100644 --- a/src/gausskernel/storage/access/gist/gistproc.cpp +++ b/src/gausskernel/storage/access/gist/gistproc.cpp @@ -1301,7 +1301,6 @@ Datum gist_circle_distance(PG_FUNCTION_ARGS) Datum query = PG_GETARG_DATUM(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); - /* Oid subtype = PG_GETARG_OID(3); */ bool* recheck = (bool *) PG_GETARG_POINTER(4); float8 distance; diff --git a/src/gausskernel/storage/access/gist/gistscan.cpp b/src/gausskernel/storage/access/gist/gistscan.cpp index 125b102984..12776ab1e0 100644 --- a/src/gausskernel/storage/access/gist/gistscan.cpp +++ b/src/gausskernel/storage/access/gist/gistscan.cpp @@ -123,7 +123,8 @@ Datum gistbeginscan(PG_FUNCTION_ARGS) errno_t rc = EOK; scan->xs_orderbyvals = (Datum*)palloc0(sizeof(Datum) * scan->numberOfOrderBys); scan->xs_orderbynulls = (bool*)palloc(sizeof(bool) * scan->numberOfOrderBys); - rc = memset_s(scan->xs_orderbynulls, sizeof(bool) * scan->numberOfOrderBys, true, sizeof(bool) * scan->numberOfOrderBys); + rc = memset_s(scan->xs_orderbynulls, sizeof(bool) * scan->numberOfOrderBys, + true, sizeof(bool) * scan->numberOfOrderBys); securec_check(rc, "\0", "\0"); } diff --git a/src/include/catalog/pg_proc.h_for_llt b/src/include/catalog/pg_proc.h_for_llt index 55dca982bd..26d63ce29c 100755 --- a/src/include/catalog/pg_proc.h_for_llt +++ b/src/include/catalog/pg_proc.h_for_llt @@ -4533,7 +4533,7 @@ DATA(insert OID = 1030 ( gist_point_compress PGNSP PGUID 12 1 0 0 0 f f f f t f DESCR("GiST support"); DATA(insert OID = 2179 ( gist_point_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 5 0 16 "2281 600 23 26 2281" _null_ _null_ _null_ _null_ gist_point_consistent _null_ _null_ _null_ "" f)); DESCR("GiST support"); -DATA(insert OID = 3064 ( gist_point_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ gist_point_distance _null_ _null_ _null_ "" f)); +DATA(insert OID = 3064 ( gist_point_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i 5 0 701 "2281 600 23 26 2281" _null_ _null_ _null_ _null_ gist_point_distance _null_ _null_ _null_ "" f)); DESCR("GiST support"); /* GIN */ diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql index 10c8b96d20..eedc332aaa 100644 --- a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_045.sql @@ -22,3 +22,8 @@ $do$; DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); + +-- function gist_point_distance +DROP FUNCTION IF EXISTS pg_catalog.gist_point_distance; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3064; +CREATE FUNCTION pg_catalog.gist_point_distance(internal, point, int4, oid) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_point_distance'; diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql index 10c8b96d20..eedc332aaa 100644 --- a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_045.sql @@ -22,3 +22,8 @@ $do$; DROP OPERATOR IF EXISTS pg_catalog.<->(circle, point) cascade; DROP FUNCTION IF EXISTS pg_catalog.gist_circle_distance(internal, point, int4, oid, internal); DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); + +-- function gist_point_distance +DROP FUNCTION IF EXISTS pg_catalog.gist_point_distance; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3064; +CREATE FUNCTION pg_catalog.gist_point_distance(internal, point, int4, oid) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_point_distance'; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql index 8ca168c1e9..fb069520e6 100644 --- a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_045.sql @@ -1,4 +1,9 @@ +-- function gist_point_distance +DROP FUNCTION IF EXISTS pg_catalog.gist_point_distance; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3064; +CREATE FUNCTION pg_catalog.gist_point_distance(internal, point, int4, oid, internal) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_point_distance'; + -- function dist_cpoint DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3291; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql index 8ca168c1e9..fb069520e6 100644 --- a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_045.sql @@ -1,4 +1,9 @@ +-- function gist_point_distance +DROP FUNCTION IF EXISTS pg_catalog.gist_point_distance; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3064; +CREATE FUNCTION pg_catalog.gist_point_distance(internal, point, int4, oid, internal) RETURNS pg_catalog.float8 LANGUAGE INTERNAL STABLE as 'gist_point_distance'; + -- function dist_cpoint DROP FUNCTION IF EXISTS pg_catalog.dist_cpoint(circle, point); SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3291; -- Gitee From a428236ef5c9173dda31a043840fab3017a9456c Mon Sep 17 00:00:00 2001 From: huyinghao Date: Wed, 16 Apr 2025 09:48:34 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B6=88=E9=99=A4goto?= =?UTF-8?q?=E8=AF=AD=E5=8F=A5=E5=90=8E=E4=BA=A7=E7=94=9F=E7=9A=84=E6=97=A0?= =?UTF-8?q?=E9=99=90=E5=BE=AA=E7=8E=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gausskernel/runtime/executor/nodeIndexscan.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gausskernel/runtime/executor/nodeIndexscan.cpp b/src/gausskernel/runtime/executor/nodeIndexscan.cpp index a8176cf48e..aed539f5e2 100644 --- a/src/gausskernel/runtime/executor/nodeIndexscan.cpp +++ b/src/gausskernel/runtime/executor/nodeIndexscan.cpp @@ -226,7 +226,7 @@ static TupleTableSlot* IndexNextWithReorder(IndexScanState* node) * remaining tuples from the queue before we're done. */ node->iss_ReachedEnd = true; - continue; + break; } /* @@ -255,6 +255,10 @@ static TupleTableSlot* IndexNextWithReorder(IndexScanState* node) break; } + if (node->iss_ReachedEnd) { + continue; + } + if (scandesc->xs_recheckorderby) { econtext->ecxt_scantuple = slot; ResetExprContext(econtext); @@ -279,8 +283,7 @@ static TupleTableSlot* IndexNextWithReorder(IndexScanState* node) elog(ERROR, "index returned tuples in wrong order"); } else if (cmp == 0) { was_exact = true; - } - else { + } else { was_exact = false; } -- Gitee