text: #include <Common/typeid_cast.h>
  #include <Parsers/ASTFunction.h>
  #include <Parsers/ASTIdentifier.h>
  #include <Parsers/ASTIndexDeclaration.h>
  #include <Parsers/ASTExpressionList.h>
  #include <Parsers/ASTCreateQuery.h>
  #include <Parsers/ASTSetQuery.h>
  #include <Parsers/ASTSelectWithUnionQuery.h>
  #include <Parsers/ExpressionListParsers.h>
  #include <Parsers/ParserCreateQuery.h>
  #include <Parsers/ParserSelectWithUnionQuery.h>
  #include <Parsers/ParserSetQuery.h>
  
  
  namespace DB
  {
  
  bool ParserNestedTable::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      ParserToken open(TokenType::OpeningRoundBracket);
      ParserToken close(TokenType::ClosingRoundBracket);
      ParserIdentifier name_p;
      ParserNameTypePairList columns_p;
  
      ASTPtr name;
      ASTPtr columns;
  
      /// For now `name == 'Nested'`, probably alternative nested data structures will appear
      if (!name_p.parse(pos, name, expected))
          return false;
  
      if (!open.ignore(pos))
          return false;
  
      if (!columns_p.parse(pos, columns, expected))
          return false;
  
      if (!close.ignore(pos))
          return false;
  
      auto func = std::make_shared<ASTFunction>();
      getIdentifierName(name, func->name);
      func->arguments = columns;
      func->children.push_back(columns);
      node = func;
  
      return true;
  }
  
  
  bool ParserIdentifierWithParameters::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      ParserFunction function_or_array;
      if (function_or_array.parse(pos, node, expected))
          return true;
  
      ParserNestedTable nested;
      if (nested.parse(pos, node, expected))
          return true;
  
      return false;
  }
  
  
  bool ParserIdentifierWithOptionalParameters::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      ParserIdentifier non_parametric;
      ParserIdentifierWithParameters parametric;
  
      if (parametric.parse(pos, node, expected))
          return true;
  
      ASTPtr ident;
      if (non_parametric.parse(pos, ident, expected))
      {
          auto func = std::make_shared<ASTFunction>();
          getIdentifierName(ident, func->name);
          node = func;
          return true;
      }
  
      return false;
  }
  
  bool ParserNameTypePairList::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      return ParserList(std::make_unique<ParserNameTypePair>(), std::make_unique<ParserToken>(TokenType::Comma), false)
          .parse(pos, node, expected);
  }
  
  bool ParserColumnDeclarationList::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      return ParserList(std::make_unique<ParserColumnDeclaration>(), std::make_unique<ParserToken>(TokenType::Comma), false)
          .parse(pos, node, expected);
  }
  
  bool ParserIndexDeclaration::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      ParserKeyword s_type("TYPE");
      ParserKeyword s_granularity("GRANULARITY");
  
      ParserIdentifier name_p;
      ParserIdentifierWithOptionalParameters ident_with_optional_params_p;
      ParserExpression expression_p;
      ParserUnsignedInteger granularity_p;
  
      ASTPtr name;
      ASTPtr expr;
      ASTPtr type;
      ASTPtr granularity;
  
      if (!name_p.parse(pos, name, expected))
          return false;
  
      if (!expression_p.parse(pos, expr, expected))
          return false;
  
      if (!s_type.ignore(pos, expected))
          return false;
  
      if (!ident_with_optional_params_p.parse(pos, type, expected))
          return false;
  
      if (!s_granularity.ignore(pos, expected))
          return false;
  
      if (!granularity_p.parse(pos, granularity, expected))
          return false;
  
      auto index = std::make_shared<ASTIndexDeclaration>();
      index->name = name->as<ASTIdentifier &>().name;
      index->granularity = granularity->as<ASTLiteral &>().value.get<UInt64>();
      index->set(index->expr, expr);
      index->set(index->type, type);
      node = index;
  
      return true;
  }
  
  
  bool ParserColumnAndIndexDeclaraion::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      ParserKeyword s_index("INDEX");
  
      ParserIndexDeclaration index_p;
      ParserColumnDeclaration column_p;
  
      ASTPtr new_node = nullptr;
  
      if (s_index.ignore(pos, expected))
      {
          if (!index_p.parse(pos, new_node, expected))
              return false;
      }
      else
      {
          if (!column_p.parse(pos, new_node, expected))
              return false;
      }
  
      node = new_node;
      return true;
  }
  
  bool ParserIndexDeclarationList::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      return ParserList(std::make_unique<ParserIndexDeclaration>(), std::make_unique<ParserToken>(TokenType::Comma), false)
              .parse(pos, node, expected);
  }
  
  
  bool ParserColumnsOrIndicesDeclarationList::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      ASTPtr list;
      if (!ParserList(std::make_unique<ParserColumnAndIndexDeclaraion>(), std::make_unique<ParserToken>(TokenType::Comma), false)
              .parse(pos, list, expected))
          return false;
  
      ASTPtr columns = std::make_shared<ASTExpressionList>();
      ASTPtr indices = std::make_shared<ASTExpressionList>();
  
      for (const auto & elem : list->children)
      {
          if (elem->as<ASTColumnDeclaration>())
              columns->children.push_back(elem);
          else if (elem->as<ASTIndexDeclaration>())
              indices->children.push_back(elem);
          else
              return false;
      }
  
      auto res = std::make_shared<ASTColumns>();
  
      if (!columns->children.empty())
          res->set(res->columns, columns);
      if (!indices->children.empty())
          res->set(res->indices, indices);
  
      node = res;
  
      return true;
  }
  
  
  bool ParserStorage::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      ParserKeyword s_engine("ENGINE");
      ParserToken s_eq(TokenType::Equals);
      ParserKeyword s_partition_by("PARTITION BY");
      ParserKeyword s_primary_key("PRIMARY KEY");
      ParserKeyword s_order_by("ORDER BY");
      ParserKeyword s_sample_by("SAMPLE BY");
      ParserKeyword s_ttl("TTL");
      ParserKeyword s_settings("SETTINGS");
  
      ParserIdentifierWithOptionalParameters ident_with_optional_params_p;
      ParserExpression expression_p;
      ParserSetQuery settings_p(/* parse_only_internals_ = */ true);
  
      ASTPtr engine;
      ASTPtr partition_by;
      ASTPtr primary_key;
      ASTPtr order_by;
      ASTPtr sample_by;
      ASTPtr ttl_table;
      ASTPtr settings;
  
      if (!s_engine.ignore(pos, expected))
          return false;
  
      s_eq.ignore(pos, expected);
  
      if (!ident_with_optional_params_p.parse(pos, engine, expected))
          return false;
  
      while (true)
      {
          if (!partition_by && s_partition_by.ignore(pos, expected))
          {
              if (expression_p.parse(pos, partition_by, expected))
                  continue;
              else
                  return false;
          }
  
          if (!primary_key && s_primary_key.ignore(pos, expected))
          {
              if (expression_p.parse(pos, primary_key, expected))
                  continue;
              else
                  return false;
          }
  
          if (!order_by && s_order_by.ignore(pos, expected))
          {
              if (expression_p.parse(pos, order_by, expected))
                  continue;
              else
                  return false;
          }
  
          if (!sample_by && s_sample_by.ignore(pos, expected))
          {
              if (expression_p.parse(pos, sample_by, expected))
                  continue;
              else
                  return false;
          }
  
          if (!ttl_table && s_ttl.ignore(pos, expected))
          {
              if (expression_p.parse(pos, ttl_table, expected))
                  continue;
              else
                  return false;
          }
  
          if (s_settings.ignore(pos, expected))
          {
              if (!settings_p.parse(pos, settings, expected))
                  return false;
          }
  
          break;
      }
  
      auto storage = std::make_shared<ASTStorage>();
      storage->set(storage->engine, engine);
      storage->set(storage->partition_by, partition_by);
      storage->set(storage->primary_key, primary_key);
      storage->set(storage->order_by, order_by);
      storage->set(storage->sample_by, sample_by);
      storage->set(storage->ttl_table, ttl_table);
  
      storage->set(storage->settings, settings);
  
      node = storage;
      return true;
  }
  
  
  bool ParserCreateQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
  {
      ParserKeyword s_create("CREATE");
      ParserKeyword s_temporary("TEMPORARY");
      ParserKeyword s_attach("ATTACH");
      ParserKeyword s_table("TABLE");
      ParserKeyword s_database("DATABASE");
      ParserKeyword s_if_not_exists("IF NOT EXISTS");
      ParserKeyword s_as("AS");
      ParserKeyword s_view("VIEW");
      ParserKeyword s_materialized("MATERIALIZED");
      ParserKeyword s_populate("POPULATE");
      ParserKeyword s_or_replace("OR REPLACE");
      ParserToken s_dot(TokenType::Dot);
      ParserToken s_lparen(TokenType::OpeningRoundBracket);
      ParserToken s_rparen(TokenType::ClosingRoundBracket);
      ParserStorage storage_p;
      ParserIdentifier name_p;
      ParserColumnsOrIndicesDeclarationList columns_or_indices_p;
      ParserSelectWithUnionQuery select_p;
      ParserFunction table_function_p;
  
      ASTPtr database;
      ASTPtr table;
      ASTPtr columns_list;
      ASTPtr to_database;
      ASTPtr to_table;
      ASTPtr storage;
      ASTPtr as_database;
      ASTPtr as_table;
      ASTPtr as_table_function;
      ASTPtr select;
      String cluster_str;
      bool attach = false;
      bool if_not_exists = false;
      bool is_view = false;
      bool is_materialized_view = false;
      bool is_populate = false;
      bool is_temporary = false;
      bool replace_view = false;
  
      if (!s_create.ignore(pos, expected))
      {
          if (s_attach.ignore(pos, expected))
              attach = true;
          else
              return false;
      }
  
      if (s_temporary.ignore(pos, expected))
      {
          is_temporary = true;
      }
  
      if (s_table.ignore(pos, expected))
      {
          if (s_if_not_exists.ignore(pos, expected))
              if_not_exists = true;
  
          if (!name_p.parse(pos, table, expected))
              return false;
  
          if (s_dot.ignore(pos, expected))
          {
              database = table;
              if (!name_p.parse(pos, table, expected))
                  return false;
          }
  
          if (ParserKeyword{"ON"}.ignore(pos, expected))
          {
              if (!ASTQueryWithOnCluster::parse(pos, cluster_str, expected))
                  return false;
          }
  
          // Shortcut for ATTACH a previously detached table
          if (attach && (!pos.isValid() || pos.get().type == TokenType::Semicolon))
          {
              auto query = std::make_shared<ASTCreateQuery>();
              node = query;
  
              query->attach = attach;
              query->if_not_exists = if_not_exists;
              query->cluster = cluster_str;
  
              getIdentifierName(database, query->database);
              getIdentifierName(table, query->table);
  
              return true;
          }
  
          /// List of columns.
          if (s_lparen.ignore(pos, expected))
          {
              if (!columns_or_indices_p.parse(pos, columns_list, expected))
                  return false;
  
              if (!s_rparen.ignore(pos, expected))
                  return false;
  
              if (!storage_p.parse(pos, storage, expected) && !is_temporary)
                  return false;
          }
          else
          {
              storage_p.parse(pos, storage, expected);
  
              if (!s_as.ignore(pos, expected))
                  return false;
  
              if (!table_function_p.parse(pos, as_table_function, expected))
              {
                  if (!select_p.parse(pos, select, expected)) /// AS SELECT ...
                  {
                      /// AS [db.]table
                      if (!name_p.parse(pos, as_table, expected))
                          return false;
  
                      if (s_dot.ignore(pos, expected))
                      {
                          as_database = as_table;
                          if (!name_p.parse(pos, as_table, expected))
                              return false;
                      }
  
                      /// Optional - ENGINE can be specified.
                      if (!storage)
                          storage_p.parse(pos, storage, expected);
                  }
              }
          }
      }
      else if (is_temporary)
          return false;
      else if (s_database.ignore(pos, expected))
      {
          if (s_if_not_exists.ignore(pos, expected))
              if_not_exists = true;
  
          if (!name_p.parse(pos, database, expected))
              return false;
  
          if (ParserKeyword{"ON"}.ignore(pos, expected))
          {
              if (!ASTQueryWithOnCluster::parse(pos, cluster_str, expected))
                  return false;
          }
  
          storage_p.parse(pos, storage, expected);
      }
      else
      {
          /// VIEW or MATERIALIZED VIEW
          if (s_or_replace.ignore(pos, expected))
          {
              replace_view = true;
          }
  
          if (!replace_view && s_materialized.ignore(pos, expected))
          {
              is_materialized_view = true;
          }
          else
              is_view = true;
  
          if (!s_view.ignore(pos, expected))
              return false;
  
          if (!replace_view && s_if_not_exists.ignore(pos, expected))
              if_not_exists = true;
  
          if (!name_p.parse(pos, table, expected))
              return false;
  
          if (s_dot.ignore(pos, expected))
          {
              database = table;
              if (!name_p.parse(pos, table, expected))
                  return false;
          }
  
          if (ParserKeyword{"ON"}.ignore(pos, expected))
          {
              if (!ASTQueryWithOnCluster::parse(pos, cluster_str, expected))
                  return false;
          }
  
          // TO [db.]table
          if (ParserKeyword{"TO"}.ignore(pos, expected))
          {
              if (!name_p.parse(pos, to_table, expected))
                  return false;
  
              if (s_dot.ignore(pos, expected))
              {
                  to_database = to_table;
                  if (!name_p.parse(pos, to_table, expected))
                      return false;
              }
          }
  
          /// Optional - a list of columns can be specified. It must fully comply with SELECT.
          if (s_lparen.ignore(pos, expected))
          {
              if (!columns_or_indices_p.parse(pos, columns_list, expected))
                  return false;
  
              if (!s_rparen.ignore(pos, expected))
                  return false;
          }
  
          if (is_materialized_view && !to_table)
          {
              /// Internal ENGINE for MATERIALIZED VIEW must be specified.
              if (!storage_p.parse(pos, storage, expected))
                  return false;
  
              if (s_populate.ignore(pos, expected))
                  is_populate = true;
          }
  
          /// AS SELECT ...
          if (!s_as.ignore(pos, expected))
              return false;
  
          if (!select_p.parse(pos, select, expected))
              return false;
      }
  
      auto query = std::make_shared<ASTCreateQuery>();
      node = query;
  
      if (as_table_function)
          query->as_table_function = as_table_function;
  
      query->attach = attach;
      query->if_not_exists = if_not_exists;
      query->is_view = is_view;
      query->is_materialized_view = is_materialized_view;
      query->is_populate = is_populate;
      query->temporary = is_temporary;
      query->replace_view = replace_view;
  
      getIdentifierName(database, query->database);
      getIdentifierName(table, query->table);
      query->cluster = cluster_str;
  
      getIdentifierName(to_database, query->to_database);
      getIdentifierName(to_table, query->to_table);
  
      query->set(query->columns_list, columns_list);
      query->set(query->storage, storage);
  
      getIdentifierName(as_database, query->as_database);
      getIdentifierName(as_table, query->as_table);
      query->set(query->select, select);
  
      return true;
  }
  
  
  }
  