@Override
  protected Boolean visitInPredicate(InPredicate actual, Expression expectedExpression) {
    if (!(expectedExpression instanceof InPredicate)) {
      return false;
    }
    InPredicate expected = (InPredicate) expectedExpression;

    if (actual.getValueList() instanceof InListExpression
        || !(expected.getValueList() instanceof InListExpression)) {
      return process(actual.getValue(), expected.getValue())
          && process(actual.getValueList(), expected.getValueList());
    }

    /*
     * In some cases, actual.getValueList() and expected.getValueList() might be of different types,
     * although they originated from identical single-element InListExpression.
     *
     * This happens because actual passes through the analyzer, planner, and possibly optimizers,
     * one of which sometimes takes the liberty of unpacking the InListExpression.
     *
     * Since the expected value doesn't go through all of that, we have to deal with the case
     * of the actual value being unpacked, but the expected value being an InListExpression.
     *
     * If the expected value is a value list, but the actual is e.g. a SymbolReference,
     * we need to unpack the value from the list to enable comparison: so that when we hit
     * visitSymbolReference, the expected.toString() call returns something that the symbolAliases
     * actually contains.
     * For example, InListExpression.toString returns "(onlyitem)" rather than "onlyitem".
     */
    List<Expression> values = ((InListExpression) expected.getValueList()).getValues();
    checkState(
        values.size() == 1,
        "Multiple expressions in expected value list %s, but actual value is not a list: %s",
        values,
        actual.getValue());
    Expression onlyExpectedExpression = values.get(0);
    return process(actual.getValue(), expected.getValue())
        && process(actual.getValueList(), onlyExpectedExpression);
  }
Expression visitor which verifies if given expression (actual) is matching other expression given
as context (expected). Visitor returns true if plans match to each other.

<p>Note that actual expression is using real name references (table columns etc) while expected
expression is using symbol aliases. Given symbol alias can point only to one real name reference.

<p>Example:

<pre>
NOT (orderkey = 3 AND custkey = 3 AND orderkey < 10)
</pre>

will match to:

<pre>
NOT (X = 3 AND Y = 3 AND X < 10)
</pre>

, but will not match to:

<pre>
NOT (X = 3 AND Y = 3 AND Z < 10)
</pre>

nor to

<pre>
NOT (X = 3 AND X = 3 AND X < 10)
</pre>
iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/ExpressionVerifier.java