2 columns sample

```sql
CREATE TABLE userid_set(userid UInt64, name String) ENGINE = Set;
INSERT INTO userid_set VALUES (1, 'Mary'),(2, 'Jane'),(3, 'Mary'),(4, 'Jack');

CREATE TABLE userid_test (userid UInt64, name String) ENGINE = MergeTree() PARTITION BY (intDiv(userid, 500)) ORDER BY (userid) SETTINGS index_granularity = 8192;
INSERT INTO userid_test VALUES (1, 'Jack'),(2, 'Mary'),(3, 'Mary'),(4, 'John'),(5, 'Mary');

SELECT * FROM userid_test WHERE (userid, name) IN (userid_set); -- fails

SELECT * FROM userid_test WHERE (name, userid) IN (userid_set); -- works, but order of columns is reversed.

```

3 columns sample
```sql
CREATE TABLE userid_set2(userid UInt64, name String, birthdate Date) ENGINE = Set;
 insert into userid_set2 values (1,'John', '1990-01-01');

WITH  'John' AS name,  toDate('1990-01-01') AS birthdate
SELECT * FROM numbers(10)
WHERE (number, name, birthdate) IN (userid_set2); -- fails

WITH  'John' AS name,  toDate('1990-01-01') AS birthdate
SELECT * FROM numbers(10)
WHERE (birthdate, name, number) IN (userid_set2); -- works, but order of column is reversed
```

const NamesAndTypesList & sourceColumns() const { return syntax->required_source_columns; }
    const std::vector<const ASTFunction *> & aggregates() const { return syntax->aggregates; }
    
    void initGlobalSubqueriesAndExternalTables(bool do_global, bool is_explain);
    ArrayJoinActionPtr addMultipleArrayJoinAction(ActionsDAGPtr & actions, bool is_left) const;
    void getRootActions(const ASTPtr & ast, bool no_makeset_for_subqueries, ActionsDAGPtr & actions, bool only_consts = false);
    /** Similar to getRootActions but do not make sets when analyzing IN functions. It's used in
      * analyzeAggregation which happens earlier than analyzing PREWHERE and WHERE. If we did, the
      * prepared sets would not be applicable for MergeTree index optimization.
      */
    void getRootActionsNoMakeSet(const ASTPtr & ast, ActionsDAGPtr & actions, bool only_consts = false);
    void getRootActionsForHaving(const ASTPtr & ast, bool no_makeset_for_subqueries, ActionsDAGPtr & actions, bool only_consts = false);
    void getRootActionsForWindowFunctions(const ASTPtr & ast, bool no_makeset_for_subqueries, ActionsDAGPtr & actions);
    /** Add aggregation keys to aggregation_keys, aggregate functions to aggregate_descriptions,
      * Create a set of columns aggregated_columns resulting after the aggregation, if any,
      *  or after all the actions that are normally performed before aggregation.
      * Set has_aggregation = true if there is GROUP BY or at least one aggregate function.
      */
    void analyzeAggregation(ActionsDAGPtr & temp_actions);
    void makeAggregateDescriptions(ActionsDAGPtr & actions, AggregateDescriptions & descriptions);
    const ASTSelectQuery * getSelectQuery() const;
    bool isRemoteStorage() const { return syntax->is_remote_storage; }
    NamesAndTypesList getColumnsAfterArrayJoin(ActionsDAGPtr & actions, const NamesAndTypesList & src_columns);
    NamesAndTypesList analyzeJoin(ActionsDAGPtr & actions, const NamesAndTypesList & src_columns);
    AggregationKeysInfo getAggregationKeysInfo() const noexcept
    {
      return { aggregation_keys, aggregation_keys_indexes_list, group_by_kind };
    }
};
class SelectQueryExpressionAnalyzer;