* Portions Copyright (c) 2012-2023, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   src/backend/lib/binaryheap.c
+ *   src/common/binaryheap.c
  *
  *-------------------------------------------------------------------------
  */
 
+#ifdef FRONTEND
+#include "postgres_fe.h"
+#else
 #include "postgres.h"
+#endif
 
 #include <math.h>
 
+#ifdef FRONTEND
+#include "common/logging.h"
+#endif
 #include "lib/binaryheap.h"
 
 static void sift_down(binaryheap *heap, int node_off);
    int         sz;
    binaryheap *heap;
 
-   sz = offsetof(binaryheap, bh_nodes) + sizeof(Datum) * capacity;
+   sz = offsetof(binaryheap, bh_nodes) + sizeof(bh_node_type) * capacity;
    heap = (binaryheap *) palloc(sz);
    heap->bh_space = capacity;
    heap->bh_compare = compare;
  * afterwards.
  */
 void
-binaryheap_add_unordered(binaryheap *heap, Datum d)
+binaryheap_add_unordered(binaryheap *heap, bh_node_type d)
 {
    if (heap->bh_size >= heap->bh_space)
+   {
+#ifdef FRONTEND
+       pg_fatal("out of binary heap slots");
+#else
        elog(ERROR, "out of binary heap slots");
+#endif
+   }
    heap->bh_has_heap_property = false;
    heap->bh_nodes[heap->bh_size] = d;
    heap->bh_size++;
  * the heap property.
  */
 void
-binaryheap_add(binaryheap *heap, Datum d)
+binaryheap_add(binaryheap *heap, bh_node_type d)
 {
    if (heap->bh_size >= heap->bh_space)
+   {
+#ifdef FRONTEND
+       pg_fatal("out of binary heap slots");
+#else
        elog(ERROR, "out of binary heap slots");
+#endif
+   }
    heap->bh_nodes[heap->bh_size] = d;
    heap->bh_size++;
    sift_up(heap, heap->bh_size - 1);
  * without modifying the heap. The caller must ensure that this
  * routine is not used on an empty heap. Always O(1).
  */
-Datum
+bh_node_type
 binaryheap_first(binaryheap *heap)
 {
    Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
  * that this routine is not used on an empty heap. O(log n) worst
  * case.
  */
-Datum
+bh_node_type
 binaryheap_remove_first(binaryheap *heap)
 {
-   Datum       result;
+   bh_node_type result;
 
    Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
 
  * sifting the new node down.
  */
 void
-binaryheap_replace_first(binaryheap *heap, Datum d)
+binaryheap_replace_first(binaryheap *heap, bh_node_type d)
 {
    Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
 
 static void
 sift_up(binaryheap *heap, int node_off)
 {
-   Datum       node_val = heap->bh_nodes[node_off];
+   bh_node_type node_val = heap->bh_nodes[node_off];
 
    /*
     * Within the loop, the node_off'th array entry is a "hole" that
    {
        int         cmp;
        int         parent_off;
-       Datum       parent_val;
+       bh_node_type parent_val;
 
        /*
         * If this node is smaller than its parent, the heap condition is
 static void
 sift_down(binaryheap *heap, int node_off)
 {
-   Datum       node_val = heap->bh_nodes[node_off];
+   bh_node_type node_val = heap->bh_nodes[node_off];
 
    /*
     * Within the loop, the node_off'th array entry is a "hole" that
 
 #ifndef BINARYHEAP_H
 #define BINARYHEAP_H
 
+/*
+ * We provide a Datum-based API for backend code and a void *-based API for
+ * frontend code (since the Datum definitions are not available to frontend
+ * code).  You should typically avoid using bh_node_type directly and instead
+ * use Datum or void * as appropriate.
+ */
+#ifdef FRONTEND
+typedef void *bh_node_type;
+#else
+typedef Datum bh_node_type;
+#endif
+
 /*
  * For a max-heap, the comparator must return <0 iff a < b, 0 iff a == b,
  * and >0 iff a > b.  For a min-heap, the conditions are reversed.
  */
-typedef int (*binaryheap_comparator) (Datum a, Datum b, void *arg);
+typedef int (*binaryheap_comparator) (bh_node_type a, bh_node_type b, void *arg);
 
 /*
  * binaryheap
    bool        bh_has_heap_property;   /* debugging cross-check */
    binaryheap_comparator bh_compare;
    void       *bh_arg;
-   Datum       bh_nodes[FLEXIBLE_ARRAY_MEMBER];
+   bh_node_type bh_nodes[FLEXIBLE_ARRAY_MEMBER];
 } binaryheap;
 
 extern binaryheap *binaryheap_allocate(int capacity,
                                       void *arg);
 extern void binaryheap_reset(binaryheap *heap);
 extern void binaryheap_free(binaryheap *heap);
-extern void binaryheap_add_unordered(binaryheap *heap, Datum d);
+extern void binaryheap_add_unordered(binaryheap *heap, bh_node_type d);
 extern void binaryheap_build(binaryheap *heap);
-extern void binaryheap_add(binaryheap *heap, Datum d);
-extern Datum binaryheap_first(binaryheap *heap);
-extern Datum binaryheap_remove_first(binaryheap *heap);
-extern void binaryheap_replace_first(binaryheap *heap, Datum d);
+extern void binaryheap_add(binaryheap *heap, bh_node_type d);
+extern bh_node_type binaryheap_first(binaryheap *heap);
+extern bh_node_type binaryheap_remove_first(binaryheap *heap);
+extern void binaryheap_replace_first(binaryheap *heap, bh_node_type d);
 
 #define binaryheap_empty(h)            ((h)->bh_size == 0)