Test, don't just Assert, that mergejoin's inputs are in order.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Feb 2022 16:59:29 +0000 (11:59 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Feb 2022 16:59:29 +0000 (11:59 -0500)
There are two Asserts in nodeMergejoin.c that are reachable if
the input data is not in the expected order.  This seems way too
fragile.  Alexander Lakhin reported a case where the assertions
could be triggered with misconfigured foreign-table partitions,
and bitter experience with unstable operating system collation
definitions suggests another easy route to hitting them.  Neither
Assert is in a place where we can't afford one more test-and-branch,
so replace 'em with plain test-and-elog logic.

Per bug #17395.  While the reported symptom is relatively recent,
collation changes could happen anytime, so back-patch to all
supported branches.

Discussion: https://postgr.es/m/17395-8c326292078d1a57@postgresql.org

src/backend/executor/nodeMergejoin.c

index 6988a6c64291dc13c5c8673d22a8f61bf4e76aaa..a049bc4ae05cd4951f0d62ae7026575523ee7dd4 100644 (file)
@@ -893,11 +893,10 @@ ExecMergeJoin(PlanState *pstate)
 
                                                if (compareResult == 0)
                                                        node->mj_JoinState = EXEC_MJ_JOINTUPLES;
-                                               else
-                                               {
-                                                       Assert(compareResult < 0);
+                                               else if (compareResult < 0)
                                                        node->mj_JoinState = EXEC_MJ_NEXTOUTER;
-                                               }
+                                               else    /* compareResult > 0 should not happen */
+                                                       elog(ERROR, "mergejoin input data is out of order");
                                                break;
                                        case MJEVAL_NONMATCHABLE:
 
@@ -1087,7 +1086,7 @@ ExecMergeJoin(PlanState *pstate)
 
                                        node->mj_JoinState = EXEC_MJ_JOINTUPLES;
                                }
-                               else
+                               else if (compareResult > 0)
                                {
                                        /* ----------------
                                         *      if the new outer tuple didn't match the marked inner
@@ -1106,7 +1105,6 @@ ExecMergeJoin(PlanState *pstate)
                                         *      no more inners, no more matches are possible.
                                         * ----------------
                                         */
-                                       Assert(compareResult > 0);
                                        innerTupleSlot = node->mj_InnerTupleSlot;
 
                                        /* reload comparison data for current inner */
@@ -1140,6 +1138,8 @@ ExecMergeJoin(PlanState *pstate)
                                                        return NULL;
                                        }
                                }
+                               else                    /* compareResult < 0 should not happen */
+                                       elog(ERROR, "mergejoin input data is out of order");
                                break;
 
                                /*----------------------------------------------------------