class RelOptUtil {

    public static RexNode isDistinctFrom(
        RexBuilder rexBuilder,
        RexNode x,
        RexNode y,
        boolean neg) {
        RexNode ret = null;
        if (x.getType().isStruct()) {
            assert y.getType().isStruct();
            List<RelDataTypeField> xFields = x.getType().getFieldList();
            List<RelDataTypeField> yFields = y.getType().getFieldList();
            assert xFields.size() == yFields.size();
            for (Pair<RelDataTypeField, RelDataTypeField> pair
                : Pair.zip(xFields, yFields)) {
                RelDataTypeField xField = pair.left;
                RelDataTypeField yField = pair.right;
                RexNode newX =
                    rexBuilder.makeFieldAccess(
                        x,
                        xField.getIndex());
                RexNode newY =
                    rexBuilder.makeFieldAccess(
                        y,
                        yField.getIndex());
                RexNode newCall =
                    isDistinctFromInternal(rexBuilder, newX, newY, neg);
                if (ret == null) {
                    ret = newCall;
                } else {
                    ret =
                        rexBuilder.makeCall(
                            SqlStdOperatorTable.AND,
                            ret,
                            newCall);
                }
            }
        } else {
            ret = isDistinctFromInternal(rexBuilder, x, y, neg);
        }

        // The result of IS DISTINCT FROM is NOT NULL because it can
        // only return TRUE or FALSE.
        assert ret != null;
        assert !ret.getType().isNullable();

        return ret;
    }

}