#define IsBooleanOpfamily(opfamily) \
    ((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID)
 
+#define IndexCollMatchesExprColl(idxcollation, exprcollation) \
+   ((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))
+
 /* Whether to use ScalarArrayOpExpr to build index qualifications */
 typedef enum
 {
  *   We do not actually do the commuting here, but we check whether a
  *   suitable commutator operator is available.
  *
+ *   If the index has a collation, the clause must have the same collation.
+ *   For collation-less indexes, we assume it doesn't matter; this is
+ *   necessary for cases like "hstore ? text", wherein hstore's operators
+ *   don't care about collation but the clause will get marked with a
+ *   collation anyway because of the text argument.  (This logic is
+ *   embodied in the macro IndexCollMatchesExprColl.)
+ *
  *   It is also possible to match RowCompareExpr clauses to indexes (but
  *   currently, only btree indexes handle this).  In this routine we will
  *   report a match if the first column of the row comparison matches the
        bms_is_subset(right_relids, outer_relids) &&
        !contain_volatile_functions(rightop))
    {
-       if (idxcollation == expr_coll &&
+       if (IndexCollMatchesExprColl(idxcollation, expr_coll) &&
            is_indexable_operator(expr_op, opfamily, true))
            return true;
 
        bms_is_subset(left_relids, outer_relids) &&
        !contain_volatile_functions(leftop))
    {
-       if (idxcollation == expr_coll &&
+       if (IndexCollMatchesExprColl(idxcollation, expr_coll) &&
            is_indexable_operator(expr_op, opfamily, false))
            return true;
 
    expr_op = linitial_oid(clause->opnos);
    expr_coll = linitial_oid(clause->inputcollids);
 
-   /* Collations must match */
-   if (expr_coll != idxcollation)
+   /* Collations must match, if relevant */
+   if (!IndexCollMatchesExprColl(idxcollation, expr_coll))
        return false;
 
    /*
    /*
     * We can forget the whole thing right away if wrong collation.
     */
-   if (expr_coll != idxcollation)
+   if (!IndexCollMatchesExprColl(idxcollation, expr_coll))
        return NULL;
 
    /*
             */
            if ((index->relam != BTREE_AM_OID ||
                 list_member_oid(ec->ec_opfamilies, curFamily)) &&
-               ec->ec_collation == curCollation &&
+               IndexCollMatchesExprColl(curCollation, ec->ec_collation) &&
                match_index_to_operand((Node *) em->em_expr, indexcol, index))
                return true;
        }
            break;
 
        /* Does collation match? */
-       if (lfirst_oid(collids_cell) != index->indexcollations[i])
+       if (!IndexCollMatchesExprColl(index->indexcollations[i],
+                                     lfirst_oid(collids_cell)))
            break;
 
        /* Add opfamily and datatypes to lists */