/*
Copyright 2018-2022 Stichting DuckDB Foundation

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#pragma once


#include "duckdb.hpp"

namespace duckdb {

class ParquetExtension : public Extension {
public:
	void Load(DuckDB &db) override;
	std::string Name() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// parquet_reader.hpp
//
//
//===----------------------------------------------------------------------===//



#include "duckdb.hpp"
#ifndef DUCKDB_AMALGAMATION
#include "duckdb/common/common.hpp"
#include "duckdb/common/exception.hpp"
#include "duckdb/common/string_util.hpp"
#include "duckdb/common/types/data_chunk.hpp"
#endif
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// column_reader.hpp
//
//
//===----------------------------------------------------------------------===//





// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #1
// See the end of this file for a list

/**
 * Autogenerated by Thrift Compiler (0.11.0)
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */
#ifndef parquet_TYPES_H
#define parquet_TYPES_H

#include <iosfwd>



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_THRIFT_H_
#define _DUCKDB_THRIFT_THRIFT_H_ 1



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

// clang-format off

#ifndef _DUCKDB_THRIFT_TRANSPORT_PLATFORM_SOCKET_H_
#  define _DUCKDB_THRIFT_TRANSPORT_PLATFORM_SOCKET_H_

#ifdef _WIN32
#ifdef _WINSOCKAPI_
#undef _WINSOCKAPI_
#endif
#  include <winsock2.h>
#  define THRIFT_GET_SOCKET_ERROR ::WSAGetLastError()
#  define THRIFT_ERRNO (*_errno())
#  define THRIFT_EINPROGRESS WSAEINPROGRESS
#  define THRIFT_EAGAIN WSAEWOULDBLOCK
#  define THRIFT_EINTR WSAEINTR
#  define THRIFT_ECONNRESET WSAECONNRESET
#  define THRIFT_ENOTCONN WSAENOTCONN
#  define THRIFT_ETIMEDOUT WSAETIMEDOUT
#  define THRIFT_EWOULDBLOCK WSAEWOULDBLOCK
#  define THRIFT_EPIPE WSAECONNRESET
#  define THRIFT_NO_SOCKET_CACHING SO_EXCLUSIVEADDRUSE
#  define THRIFT_SOCKET SOCKET
#  define THRIFT_INVALID_SOCKET INVALID_SOCKET
#  define THRIFT_SOCKETPAIR thrift_socketpair
#  define THRIFT_FCNTL thrift_fcntl
#  define THRIFT_O_NONBLOCK 1
#  define THRIFT_F_GETFL 0
#  define THRIFT_F_SETFL 1
#  define THRIFT_GETTIMEOFDAY thrift_gettimeofday
#  define THRIFT_CLOSESOCKET closesocket
#  define THRIFT_CLOSE _close
#  define THRIFT_OPEN _open
#  define THRIFT_FTRUNCATE _chsize_s
#  define THRIFT_FSYNC _commit
#  define THRIFT_LSEEK _lseek
#  define THRIFT_WRITE _write
#  define THRIFT_READ _read
#  define THRIFT_IOCTL_SOCKET ioctlsocket
#  define THRIFT_IOCTL_SOCKET_NUM_BYTES_TYPE u_long
#  define THRIFT_FSTAT _fstat
#  define THRIFT_STAT _stat
#  ifdef _WIN32_WCE
#    define THRIFT_GAI_STRERROR(...) thrift_wstr2str(gai_strerrorW(__VA_ARGS__))
#  else
#    define THRIFT_GAI_STRERROR gai_strerrorA
#  endif
#  define THRIFT_SSIZET ptrdiff_t
#  if (_MSC_VER < 1900)
#    define THRIFT_SNPRINTF _snprintf
#  else
#    define THRIFT_SNPRINTF snprintf
#  endif
#  define THRIFT_SLEEP_SEC thrift_sleep
#  define THRIFT_SLEEP_USEC thrift_usleep
#  define THRIFT_TIMESPEC thrift_timespec
#  define THRIFT_CTIME_R thrift_ctime_r
#  define THRIFT_POLL thrift_poll
#  if WINVER <= 0x0502 //XP, Server2003
#    define THRIFT_POLLFD  thrift_pollfd
#    define THRIFT_POLLIN  0x0300
#    define THRIFT_POLLOUT 0x0010
#  else //Vista, Win7...
#    define THRIFT_POLLFD  pollfd
#    define THRIFT_POLLIN  POLLIN
#    define THRIFT_POLLOUT POLLOUT
#  endif //WINVER
#  define THRIFT_SHUT_RDWR SD_BOTH
#  if !defined(AI_ADDRCONFIG)
#    define AI_ADDRCONFIG 0x00000400
#  endif
#else //not _WIN32
#  include <errno.h>
#  define THRIFT_GET_SOCKET_ERROR errno
#  define THRIFT_ERRNO errno
#  define THRIFT_EINTR       EINTR
#  define THRIFT_EINPROGRESS EINPROGRESS
#  define THRIFT_ECONNRESET  ECONNRESET
#  define THRIFT_ENOTCONN    ENOTCONN
#  define THRIFT_ETIMEDOUT   ETIMEDOUT
#  define THRIFT_EWOULDBLOCK EWOULDBLOCK
#  define THRIFT_EAGAIN      EAGAIN
#  define THRIFT_EPIPE       EPIPE
#  define THRIFT_NO_SOCKET_CACHING SO_REUSEADDR
#  define THRIFT_SOCKET int
#  define THRIFT_INVALID_SOCKET (-1)
#  define THRIFT_SOCKETPAIR socketpair
#  define THRIFT_FCNTL fcntl
#  define THRIFT_O_NONBLOCK O_NONBLOCK
#  define THRIFT_F_GETFL F_GETFL
#  define THRIFT_F_SETFL F_SETFL
#  define THRIFT_GETTIMEOFDAY gettimeofday
#  define THRIFT_CLOSESOCKET close
#  define THRIFT_CLOSE close
#  define THRIFT_OPEN open
#  define THRIFT_FTRUNCATE ftruncate
#  define THRIFT_FSYNC fsync
#  define THRIFT_LSEEK lseek
#  define THRIFT_WRITE write
#  define THRIFT_READ read
#  define THRIFT_IOCTL_SOCKET ioctl
#  define THRIFT_IOCTL_SOCKET_NUM_BYTES_TYPE int
#  define THRIFT_STAT stat
#  define THRIFT_FSTAT fstat
#  define THRIFT_GAI_STRERROR gai_strerror
#  define THRIFT_SSIZET ssize_t
#  define THRIFT_SNPRINTF snprintf
#  define THRIFT_SLEEP_SEC sleep
#  define THRIFT_SLEEP_USEC usleep
#  define THRIFT_TIMESPEC timespec
#  define THRIFT_CTIME_R ctime_r
#  define THRIFT_POLL poll
#  define THRIFT_POLLFD  pollfd
#  define THRIFT_POLLIN  POLLIN
#  define THRIFT_POLLOUT POLLOUT
#  define THRIFT_SHUT_RDWR SHUT_RDWR
#endif

#endif // _DUCKDB_THRIFT_TRANSPORT_PLATFORM_SOCKET_H_


// LICENSE_CHANGE_END




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef THRIFT_CONFIG_H
#define THRIFT_CONFIG_H


#ifdef _WIN32
#if defined(_M_IX86) || defined(_M_X64)
#define ARITHMETIC_RIGHT_SHIFT 1
#define SIGNED_RIGHT_SHIFT_IS 1
#endif
#else
#define SIGNED_RIGHT_SHIFT_IS  1
#define ARITHMETIC_RIGHT_SHIFT 1
#endif

#endif

// LICENSE_CHANGE_END


#include <stdio.h>
#include <assert.h>

#include <sys/types.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include <string>
#include <map>
#include <list>
#include <set>
#include <vector>
#include <exception>
#include <typeinfo>



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_TLOGGING_H_
#define _DUCKDB_THRIFT_TLOGGING_H_ 1



/**
 * Contains utility macros for debugging and logging.
 *
 */

#include <time.h>

#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif

//namespace duckdb_apache {
//namespace thrift {
/**
 * T_GLOBAL_DEBUGGING_LEVEL = 0: all debugging turned off, debug macros undefined
 * T_GLOBAL_DEBUGGING_LEVEL = 1: all debugging turned on
 */
#define T_GLOBAL_DEBUGGING_LEVEL 0

/**
 * T_GLOBAL_LOGGING_LEVEL = 0: all logging turned off, logging macros undefined
 * T_GLOBAL_LOGGING_LEVEL = 1: all logging turned on
 */
#define T_GLOBAL_LOGGING_LEVEL 0

/**
 * Standard wrapper around fprintf what will prefix the file name and line
 * number to the line. Uses T_GLOBAL_DEBUGGING_LEVEL to control whether it is
 * turned on or off.
 *
 * @param format_string
 */
#if T_GLOBAL_DEBUGGING_LEVEL > 0
#define T_DEBUG(format_string, ...)                                                                \
  if (T_GLOBAL_DEBUGGING_LEVEL > 0) {                                                              \
    fprintf(stderr, "[%s,%d] " format_string " \n", __FILE__, __LINE__, ##__VA_ARGS__);            \
  }
#else
#define T_DEBUG(format_string, ...)
#endif

/**
 * analogous to T_DEBUG but also prints the time
 *
 * @param string  format_string input: printf style format string
 */
#if T_GLOBAL_DEBUGGING_LEVEL > 0
#define T_DEBUG_T(format_string, ...)                                                              \
  {                                                                                                \
    if (T_GLOBAL_DEBUGGING_LEVEL > 0) {                                                            \
      time_t now;                                                                                  \
      char dbgtime[26];                                                                            \
      time(&now);                                                                                  \
      THRIFT_CTIME_R(&now, dbgtime);                                                               \
      dbgtime[24] = '\0';                                                                          \
      fprintf(stderr,                                                                              \
              "[%s,%d] [%s] " format_string " \n",                                                 \
              __FILE__,                                                                            \
              __LINE__,                                                                            \
              dbgtime,                                                                             \
              ##__VA_ARGS__);                                                                      \
    }                                                                                              \
  }
#else
#define T_DEBUG_T(format_string, ...)
#endif





/**
 * Log input message
 *
 * @param string  format_string input: printf style format string
 */
#if T_GLOBAL_LOGGING_LEVEL > 0
#define T_LOG_OPER(format_string, ...)                                                             \
  {                                                                                                \
    if (T_GLOBAL_LOGGING_LEVEL > 0) {                                                              \
      time_t now;                                                                                  \
      char dbgtime[26];                                                                            \
      time(&now);                                                                                  \
      THRIFT_CTIME_R(&now, dbgtime);                                                               \
      dbgtime[24] = '\0';                                                                          \
      fprintf(stderr, "[%s] " format_string " \n", dbgtime, ##__VA_ARGS__);                        \
    }                                                                                              \
  }
#else
#define T_LOG_OPER(format_string, ...)
#endif

/**
 * T_GLOBAL_DEBUG_VIRTUAL = 0 or unset: normal operation,
 *                                      virtual call debug messages disabled
 * T_GLOBAL_DEBUG_VIRTUAL = 1:          log a debug messages whenever an
 *                                      avoidable virtual call is made
 * T_GLOBAL_DEBUG_VIRTUAL = 2:          record detailed info that can be
 *                                      printed by calling
 *                                      duckdb_apache::thrift::profile_print_info()
 */
#if T_GLOBAL_DEBUG_VIRTUAL > 1
#define T_VIRTUAL_CALL() ::duckdb_apache::thrift::profile_virtual_call(typeid(*this))
#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot)                            \
  do {                                                                                             \
    if (!(specific_prot)) {                                                                        \
      ::duckdb_apache::thrift::profile_generic_protocol(typeid(*template_class), typeid(*generic_prot));  \
    }                                                                                              \
  } while (0)
#elif T_GLOBAL_DEBUG_VIRTUAL == 1
#define T_VIRTUAL_CALL() fprintf(stderr, "[%s,%d] virtual call\n", __FILE__, __LINE__)
#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot)                            \
  do {                                                                                             \
    if (!(specific_prot)) {                                                                        \
      fprintf(stderr, "[%s,%d] failed to cast to specific protocol type\n", __FILE__, __LINE__);   \
    }                                                                                              \
  } while (0)
#else
#define T_VIRTUAL_CALL()
#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot)
#endif

//}
//} // end of duckdb_apache::thrift

#endif // #ifndef _DUCKDB_THRIFT_TLOGGING_H_


// LICENSE_CHANGE_END

//#include <thrift/TOutput.h>

#define THRIFT_UNUSED_VARIABLE(x) ((void)(x))

namespace duckdb_apache {
namespace thrift {

class TEnumIterator
    : public std::iterator<std::forward_iterator_tag, std::pair<int, const char*> > {
public:
  TEnumIterator(int n, int* enums, const char** names)
    : ii_(0), n_(n), enums_(enums), names_(names) {}

  int operator++() { return ++ii_; }

  bool operator!=(const TEnumIterator& end) {
    THRIFT_UNUSED_VARIABLE(end);
    assert(end.n_ == -1);
    return (ii_ != n_);
  }

  std::pair<int, const char*> operator*() const { return std::make_pair(enums_[ii_], names_[ii_]); }

private:
  int ii_;
  const int n_;
  int* enums_;
  const char** names_;
};

class TException : public std::exception {
public:
  TException() : message_() {}

  TException(const std::string& message) : message_(message) {}

  ~TException() noexcept override = default;

  const char* what() const noexcept override {
    if (message_.empty()) {
      return "Default TException.";
    } else {
      return message_.c_str();
    }
  }

protected:
  std::string message_;
};

class TDelayedException {
public:
  template <class E>
  static TDelayedException* delayException(const E& e);
  virtual void throw_it() = 0;
  virtual ~TDelayedException() = default;
};

template <class E>
class TExceptionWrapper : public TDelayedException {
public:
  TExceptionWrapper(const E& e) : e_(e) {}
  void throw_it() override {
    E temp(e_);
    delete this;
    throw temp;
  }

private:
  E e_;
};

template <class E>
TDelayedException* TDelayedException::delayException(const E& e) {
  return new TExceptionWrapper<E>(e);
}

#if T_GLOBAL_DEBUG_VIRTUAL > 1
void profile_virtual_call(const std::type_info& info);
void profile_generic_protocol(const std::type_info& template_type, const std::type_info& prot_type);
void profile_print_info(FILE* f);
void profile_print_info();
void profile_write_pprof(FILE* gen_calls_f, FILE* virtual_calls_f);
#endif
}
} // duckdb_apache::thrift

#endif // #ifndef _DUCKDB_THRIFT_THRIFT_H_


// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_TAPPLICATIONEXCEPTION_H_
#define _DUCKDB_THRIFT_TAPPLICATIONEXCEPTION_H_ 1



namespace duckdb_apache {
namespace thrift {

namespace protocol {
class TProtocol;
}

class TApplicationException : public TException {
public:
  /**
   * Error codes for the various types of exceptions.
   */
  enum TApplicationExceptionType {
    UNKNOWN = 0,
    UNKNOWN_METHOD = 1,
    INVALID_MESSAGE_TYPE = 2,
    WRONG_METHOD_NAME = 3,
    BAD_SEQUENCE_ID = 4,
    MISSING_RESULT = 5,
    INTERNAL_ERROR = 6,
    PROTOCOL_ERROR = 7,
    INVALID_TRANSFORM = 8,
    INVALID_PROTOCOL = 9,
    UNSUPPORTED_CLIENT_TYPE = 10
  };

  TApplicationException() : TException(), type_(UNKNOWN) {}

  TApplicationException(TApplicationExceptionType type) : TException(), type_(type) {}

  TApplicationException(const std::string& message) : TException(message), type_(UNKNOWN) {}

  TApplicationException(TApplicationExceptionType type, const std::string& message)
    : TException(message), type_(type) {}

  ~TApplicationException() noexcept override = default;

  /**
   * Returns an error code that provides information about the type of error
   * that has occurred.
   *
   * @return Error code
   */
  TApplicationExceptionType getType() const { return type_; }

  const char* what() const noexcept override {
    if (message_.empty()) {
      switch (type_) {
      case UNKNOWN:
        return "TApplicationException: Unknown application exception";
      case UNKNOWN_METHOD:
        return "TApplicationException: Unknown method";
      case INVALID_MESSAGE_TYPE:
        return "TApplicationException: Invalid message type";
      case WRONG_METHOD_NAME:
        return "TApplicationException: Wrong method name";
      case BAD_SEQUENCE_ID:
        return "TApplicationException: Bad sequence identifier";
      case MISSING_RESULT:
        return "TApplicationException: Missing result";
      case INTERNAL_ERROR:
        return "TApplicationException: Internal error";
      case PROTOCOL_ERROR:
        return "TApplicationException: Protocol error";
      case INVALID_TRANSFORM:
        return "TApplicationException: Invalid transform";
      case INVALID_PROTOCOL:
        return "TApplicationException: Invalid protocol";
      case UNSUPPORTED_CLIENT_TYPE:
        return "TApplicationException: Unsupported client type";
      default:
        return "TApplicationException: (Invalid exception type)";
      };
    } else {
      return message_.c_str();
    }
  }

  uint32_t read(protocol::TProtocol* iprot);
  uint32_t write(protocol::TProtocol* oprot) const;

protected:
  /**
   * Error code
   */
  TApplicationExceptionType type_;
};
}
} // duckdb_apache::thrift

#endif // #ifndef _DUCKDB_THRIFT_TAPPLICATIONEXCEPTION_H_


// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_TBASE_H_
#define _DUCKDB_THRIFT_TBASE_H_ 1




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_PROTOCOL_TPROTOCOL_H_
#define _DUCKDB_THRIFT_PROTOCOL_TPROTOCOL_H_ 1

#ifdef _WIN32
// Need to come before any Windows.h includes
#include <winsock2.h>
#endif



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_TRANSPORT_TTRANSPORT_H_
#define _DUCKDB_THRIFT_TRANSPORT_TTRANSPORT_H_ 1




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_TRANSPORT_TTRANSPORTEXCEPTION_H_
#define _DUCKDB_THRIFT_TRANSPORT_TTRANSPORTEXCEPTION_H_ 1

// FUCK OFF #include <boost/numeric/conversion/cast.hpp>
#include <string>


namespace duckdb_apache {
namespace thrift {
namespace transport {

/**
 * Class to encapsulate all the possible types of transport errors that may
 * occur in various transport systems. This provides a sort of generic
 * wrapper around the vague UNIX E_ error codes that lets a common code
 * base of error handling to be used for various types of transports, i.e.
 * pipes etc.
 *
 */
class TTransportException : public duckdb_apache::thrift::TException {
public:
  /**
   * Error codes for the various types of exceptions.
   */
  enum TTransportExceptionType {
    UNKNOWN = 0,
    NOT_OPEN = 1,
    TIMED_OUT = 2,
    END_OF_FILE = 3,
    INTERRUPTED = 4,
    BAD_ARGS = 5,
    CORRUPTED_DATA = 6,
    INTERNAL_ERROR = 7
  };

  TTransportException() : duckdb_apache::thrift::TException(), type_(UNKNOWN) {}

  TTransportException(TTransportExceptionType type) : duckdb_apache::thrift::TException(), type_(type) {}

  TTransportException(const std::string& message)
    : duckdb_apache::thrift::TException(message), type_(UNKNOWN) {}

  TTransportException(TTransportExceptionType type, const std::string& message)
    : duckdb_apache::thrift::TException(message), type_(type) {}

  TTransportException(TTransportExceptionType type, const std::string& message, int errno_copy)
    : duckdb_apache::thrift::TException(message), type_(type) {}

  ~TTransportException() noexcept override = default;

  /**
   * Returns an error code that provides information about the type of error
   * that has occurred.
   *
   * @return Error code
   */
  TTransportExceptionType getType() const noexcept { return type_; }

  const char* what() const noexcept override;

protected:
  /** Just like strerror_r but returns a C++ string object. */
  std::string strerror_s(int errno_copy);

  /** Error code */
  TTransportExceptionType type_;
};

///**
// * Legacy code in transport implementations have overflow issues
// * that need to be enforced.
// */
//template <typename To, typename From> To safe_numeric_cast(From i) {
//  try {
//    return boost::numeric_cast<To>(i);
//  }
//  catch (const std::bad_cast& bc) {
//    throw TTransportException(TTransportException::CORRUPTED_DATA,
//                              bc.what());
//  }
//}

}
}
} // duckdb_apache::thrift::transport

#endif // #ifndef _DUCKDB_THRIFT_TRANSPORT_TTRANSPORTEXCEPTION_H_


// LICENSE_CHANGE_END

#include <memory>
#include <string>

namespace duckdb_apache {
namespace thrift {
namespace transport {

/**
 * Helper template to hoist readAll implementation out of TTransport
 */
template <class Transport_>
uint32_t readAll(Transport_& trans, uint8_t* buf, uint32_t len) {
  uint32_t have = 0;
  uint32_t get = 0;

  while (have < len) {
    get = trans.read(buf + have, len - have);
    if (get <= 0) {
      throw TTransportException(TTransportException::END_OF_FILE, "No more data to read.");
    }
    have += get;
  }

  return have;
}

/**
 * Generic interface for a method of transporting data. A TTransport may be
 * capable of either reading or writing, but not necessarily both.
 *
 */
class TTransport {
public:
  /**
   * Virtual deconstructor.
   */
  virtual ~TTransport() = default;

  /**
   * Whether this transport is open.
   */
  virtual bool isOpen() const { return false; }

  /**
   * Tests whether there is more data to read or if the remote side is
   * still open. By default this is true whenever the transport is open,
   * but implementations should add logic to test for this condition where
   * possible (i.e. on a socket).
   * This is used by a server to check if it should listen for another
   * request.
   */
  virtual bool peek() { return isOpen(); }

  /**
   * Opens the transport for communications.
   *
   * @return bool Whether the transport was successfully opened
   * @throws TTransportException if opening failed
   */
  virtual void open() {
    throw TTransportException(TTransportException::NOT_OPEN, "Cannot open base TTransport.");
  }

  /**
   * Closes the transport.
   */
  virtual void close() {
    throw TTransportException(TTransportException::NOT_OPEN, "Cannot close base TTransport.");
  }

  /**
   * Attempt to read up to the specified number of bytes into the string.
   *
   * @param buf  Reference to the location to write the data
   * @param len  How many bytes to read
   * @return How many bytes were actually read
   * @throws TTransportException If an error occurs
   */
  uint32_t read(uint8_t* buf, uint32_t len) {
    T_VIRTUAL_CALL();
    return read_virt(buf, len);
  }
  virtual uint32_t read_virt(uint8_t* /* buf */, uint32_t /* len */) {
    throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot read.");
  }

  /**
   * Reads the given amount of data in its entirety no matter what.
   *
   * @param s     Reference to location for read data
   * @param len   How many bytes to read
   * @return How many bytes read, which must be equal to size
   * @throws TTransportException If insufficient data was read
   */
  uint32_t readAll(uint8_t* buf, uint32_t len) {
    T_VIRTUAL_CALL();
    return readAll_virt(buf, len);
  }
  virtual uint32_t readAll_virt(uint8_t* buf, uint32_t len) {
    return duckdb_apache::thrift::transport::readAll(*this, buf, len);
  }

  /**
   * Called when read is completed.
   * This can be over-ridden to perform a transport-specific action
   * e.g. logging the request to a file
   *
   * @return number of bytes read if available, 0 otherwise.
   */
  virtual uint32_t readEnd() {
    // default behaviour is to do nothing
    return 0;
  }

  /**
   * Writes the string in its entirety to the buffer.
   *
   * Note: You must call flush() to ensure the data is actually written,
   * and available to be read back in the future.  Destroying a TTransport
   * object does not automatically flush pending data--if you destroy a
   * TTransport object with written but unflushed data, that data may be
   * discarded.
   *
   * @param buf  The data to write out
   * @throws TTransportException if an error occurs
   */
  void write(const uint8_t* buf, uint32_t len) {
    T_VIRTUAL_CALL();
    write_virt(buf, len);
  }
  virtual void write_virt(const uint8_t* /* buf */, uint32_t /* len */) {
    throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot write.");
  }

  /**
   * Called when write is completed.
   * This can be over-ridden to perform a transport-specific action
   * at the end of a request.
   *
   * @return number of bytes written if available, 0 otherwise
   */
  virtual uint32_t writeEnd() {
    // default behaviour is to do nothing
    return 0;
  }

  /**
   * Flushes any pending data to be written. Typically used with buffered
   * transport mechanisms.
   *
   * @throws TTransportException if an error occurs
   */
  virtual void flush() {
    // default behaviour is to do nothing
  }

  /**
   * Attempts to return a pointer to \c len bytes, possibly copied into \c buf.
   * Does not consume the bytes read (i.e.: a later read will return the same
   * data).  This method is meant to support protocols that need to read
   * variable-length fields.  They can attempt to borrow the maximum amount of
   * data that they will need, then consume (see next method) what they
   * actually use.  Some transports will not support this method and others
   * will fail occasionally, so protocols must be prepared to use read if
   * borrow fails.
   *
   * @oaram buf  A buffer where the data can be stored if needed.
   *             If borrow doesn't return buf, then the contents of
   *             buf after the call are undefined.  This parameter may be
   *             NULL to indicate that the caller is not supplying storage,
   *             but would like a pointer into an internal buffer, if
   *             available.
   * @param len  *len should initially contain the number of bytes to borrow.
   *             If borrow succeeds, *len will contain the number of bytes
   *             available in the returned pointer.  This will be at least
   *             what was requested, but may be more if borrow returns
   *             a pointer to an internal buffer, rather than buf.
   *             If borrow fails, the contents of *len are undefined.
   * @return If the borrow succeeds, return a pointer to the borrowed data.
   *         This might be equal to \c buf, or it might be a pointer into
   *         the transport's internal buffers.
   * @throws TTransportException if an error occurs
   */
  const uint8_t* borrow(uint8_t* buf, uint32_t* len) {
    T_VIRTUAL_CALL();
    return borrow_virt(buf, len);
  }
  virtual const uint8_t* borrow_virt(uint8_t* /* buf */, uint32_t* /* len */) { return nullptr; }

  /**
   * Remove len bytes from the transport.  This should always follow a borrow
   * of at least len bytes, and should always succeed.
   * TODO(dreiss): Is there any transport that could borrow but fail to
   * consume, or that would require a buffer to dump the consumed data?
   *
   * @param len  How many bytes to consume
   * @throws TTransportException If an error occurs
   */
  void consume(uint32_t len) {
    T_VIRTUAL_CALL();
    consume_virt(len);
  }
  virtual void consume_virt(uint32_t /* len */) {
    throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot consume.");
  }

  /**
   * Returns the origin of the transports call. The value depends on the
   * transport used. An IP based transport for example will return the
   * IP address of the client making the request.
   * If the transport doesn't know the origin Unknown is returned.
   *
   * The returned value can be used in a log message for example
   */
  virtual const std::string getOrigin() const { return "Unknown"; }

protected:
  /**
   * Simple constructor.
   */
  TTransport() = default;
};

/**
 * Generic factory class to make an input and output transport out of a
 * source transport. Commonly used inside servers to make input and output
 * streams out of raw clients.
 *
 */
class TTransportFactory {
public:
  TTransportFactory() = default;

  virtual ~TTransportFactory() = default;

  /**
   * Default implementation does nothing, just returns the transport given.
   */
  virtual std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> trans) {
    return trans;
  }
};
}
}
} // duckdb_apache::thrift::transport

#endif // #ifndef _DUCKDB_THRIFT_TRANSPORT_TTRANSPORT_H_


// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_
#define _DUCKDB_THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_ 1

#include <string>

namespace duckdb_apache {
namespace thrift {
namespace protocol {

/**
 * Class to encapsulate all the possible types of protocol errors that may
 * occur in various protocol systems. This provides a sort of generic
 * wrapper around the vague UNIX E_ error codes that lets a common code
 * base of error handling to be used for various types of protocols, i.e.
 * pipes etc.
 *
 */
class TProtocolException : public duckdb_apache::thrift::TException {
public:
  /**
   * Error codes for the various types of exceptions.
   */
  enum TProtocolExceptionType {
    UNKNOWN = 0,
    INVALID_DATA = 1,
    NEGATIVE_SIZE = 2,
    SIZE_LIMIT = 3,
    BAD_VERSION = 4,
    NOT_IMPLEMENTED = 5,
    DEPTH_LIMIT = 6
  };

  TProtocolException() : duckdb_apache::thrift::TException(), type_(UNKNOWN) {}

  TProtocolException(TProtocolExceptionType type) : duckdb_apache::thrift::TException(), type_(type) {}

  TProtocolException(const std::string& message)
    : duckdb_apache::thrift::TException(message), type_(UNKNOWN) {}

  TProtocolException(TProtocolExceptionType type, const std::string& message)
    : duckdb_apache::thrift::TException(message), type_(type) {}

  ~TProtocolException() noexcept override = default;

  /**
   * Returns an error code that provides information about the type of error
   * that has occurred.
   *
   * @return Error code
   */
  TProtocolExceptionType getType() const { return type_; }

  const char* what() const noexcept override {
    if (message_.empty()) {
      switch (type_) {
      case UNKNOWN:
        return "TProtocolException: Unknown protocol exception";
      case INVALID_DATA:
        return "TProtocolException: Invalid data";
      case NEGATIVE_SIZE:
        return "TProtocolException: Negative size";
      case SIZE_LIMIT:
        return "TProtocolException: Exceeded size limit";
      case BAD_VERSION:
        return "TProtocolException: Invalid version";
      case NOT_IMPLEMENTED:
        return "TProtocolException: Not implemented";
      default:
        return "TProtocolException: (Invalid exception type)";
      }
    } else {
      return message_.c_str();
    }
  }

protected:
  /**
   * Error code
   */
  TProtocolExceptionType type_;
};
}
}
} // duckdb_apache::thrift::protocol

#endif // #ifndef _DUCKDB_THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_


// LICENSE_CHANGE_END


#include <memory>

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include <sys/types.h>
#include <string>
#include <map>
#include <vector>
#include <climits>

// Use this to get around strict aliasing rules.
// For example, uint64_t i = bitwise_cast<uint64_t>(returns_double());
// The most obvious implementation is to just cast a pointer,
// but that doesn't work.
// For a pretty in-depth explanation of the problem, see
// http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
namespace duckdb_apache { namespace thrift {
template <typename To, typename From>
static inline To bitwise_cast(From from) {
	static_assert(sizeof(From) == sizeof(To), "sizeof(From) == sizeof(To)");

	// BAD!!!  These are all broken with -O2.
	// return *reinterpret_cast<To*>(&from);  // BAD!!!
	// return *static_cast<To*>(static_cast<void*>(&from));  // BAD!!!
	// return *(To*)(void*)&from;  // BAD!!!

	// Super clean and paritally blessed by section 3.9 of the standard.
	// unsigned char c[sizeof(from)];
	// memcpy(c, &from, sizeof(from));
	// To to;
	// memcpy(&to, c, sizeof(c));
	// return to;

	// Slightly more questionable.
	// Same code emitted by GCC.
	// To to;
	// memcpy(&to, &from, sizeof(from));
	// return to;

	// Technically undefined, but almost universally supported,
	// and the most efficient implementation.
	union {
		From f;
		To t;
	} u;
	u.f = from;
	return u.t;
}
}} // namespace duckdb_apache::thrift


#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif

#ifndef __THRIFT_BYTE_ORDER
# if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
#  define __THRIFT_BYTE_ORDER BYTE_ORDER
#  define __THRIFT_LITTLE_ENDIAN LITTLE_ENDIAN
#  define __THRIFT_BIG_ENDIAN BIG_ENDIAN
# else
//#  include <boost/predef/other/endian.h>
#  if BOOST_ENDIAN_BIG_BYTE
#    define __THRIFT_BYTE_ORDER 4321
#    define __THRIFT_LITTLE_ENDIAN 0
#    define __THRIFT_BIG_ENDIAN __THRIFT_BYTE_ORDER
#  elif BOOST_ENDIAN_LITTLE_BYTE
#    define __THRIFT_BYTE_ORDER 1234
#    define __THRIFT_LITTLE_ENDIAN __THRIFT_BYTE_ORDER
#    define __THRIFT_BIG_ENDIAN 0
#  endif
#  ifdef BOOST_LITTLE_ENDIAN
#  else
#  endif
# endif
#endif

#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
# if !defined(THRIFT_ntohll)
#  define THRIFT_ntohll(n) (n)
#  define THRIFT_htonll(n) (n)
# endif
# if defined(__GNUC__) && defined(__GLIBC__)
#  include <byteswap.h>
#  define THRIFT_htolell(n) bswap_64(n)
#  define THRIFT_letohll(n) bswap_64(n)
#  define THRIFT_htolel(n) bswap_32(n)
#  define THRIFT_letohl(n) bswap_32(n)
#  define THRIFT_htoles(n) bswap_16(n)
#  define THRIFT_letohs(n) bswap_16(n)
# else /* GNUC & GLIBC */
#  define bswap_64(n) \
      ( (((n) & 0xff00000000000000ull) >> 56) \
      | (((n) & 0x00ff000000000000ull) >> 40) \
      | (((n) & 0x0000ff0000000000ull) >> 24) \
      | (((n) & 0x000000ff00000000ull) >> 8)  \
      | (((n) & 0x00000000ff000000ull) << 8)  \
      | (((n) & 0x0000000000ff0000ull) << 24) \
      | (((n) & 0x000000000000ff00ull) << 40) \
      | (((n) & 0x00000000000000ffull) << 56) )
#  define bswap_32(n) \
      ( (((n) & 0xff000000ul) >> 24) \
      | (((n) & 0x00ff0000ul) >> 8)  \
      | (((n) & 0x0000ff00ul) << 8)  \
      | (((n) & 0x000000fful) << 24) )
#  define bswap_16(n) \
      ( (((n) & ((unsigned short)0xff00ul)) >> 8)  \
      | (((n) & ((unsigned short)0x00fful)) << 8)  )
#  define THRIFT_htolell(n) bswap_64(n)
#  define THRIFT_letohll(n) bswap_64(n)
#  define THRIFT_htolel(n) bswap_32(n)
#  define THRIFT_letohl(n) bswap_32(n)
#  define THRIFT_htoles(n) bswap_16(n)
#  define THRIFT_letohs(n) bswap_16(n)
# endif /* GNUC & GLIBC */
#elif __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
#  define THRIFT_htolell(n) (n)
#  define THRIFT_letohll(n) (n)
#  define THRIFT_htolel(n) (n)
#  define THRIFT_letohl(n) (n)
#  define THRIFT_htoles(n) (n)
#  define THRIFT_letohs(n) (n)
# if defined(__GNUC__) && defined(__GLIBC__)
#  include <byteswap.h>
#  define THRIFT_ntohll(n) bswap_64(n)
#  define THRIFT_htonll(n) bswap_64(n)
# elif defined(_MSC_VER) /* Microsoft Visual C++ */
#  define THRIFT_ntohll(n) ( _byteswap_uint64((uint64_t)n) )
#  define THRIFT_htonll(n) ( _byteswap_uint64((uint64_t)n) )
# elif !defined(THRIFT_ntohll) /* Not GNUC/GLIBC or MSVC */
#  define THRIFT_ntohll(n) ( (((uint64_t)ntohl((uint32_t)n)) << 32) + ntohl((uint32_t)(n >> 32)) )
#  define THRIFT_htonll(n) ( (((uint64_t)htonl((uint32_t)n)) << 32) + htonl((uint32_t)(n >> 32)) )
# endif /* GNUC/GLIBC or MSVC or something else */
#else /* __THRIFT_BYTE_ORDER */
# error "Can't define THRIFT_htonll or THRIFT_ntohll!"
#endif

namespace duckdb_apache {
namespace thrift {
namespace protocol {

using duckdb_apache::thrift::transport::TTransport;

/**
 * Enumerated definition of the types that the Thrift protocol supports.
 * Take special note of the T_END type which is used specifically to mark
 * the end of a sequence of fields.
 */
enum TType {
  T_STOP       = 0,
  T_VOID       = 1,
  T_BOOL       = 2,
  T_BYTE       = 3,
  T_I08        = 3,
  T_I16        = 6,
  T_I32        = 8,
  T_U64        = 9,
  T_I64        = 10,
  T_DOUBLE     = 4,
  T_STRING     = 11,
  T_UTF7       = 11,
  T_STRUCT     = 12,
  T_MAP        = 13,
  T_SET        = 14,
  T_LIST       = 15,
  T_UTF8       = 16,
  T_UTF16      = 17
};

/**
 * Enumerated definition of the message types that the Thrift protocol
 * supports.
 */
enum TMessageType {
  T_CALL       = 1,
  T_REPLY      = 2,
  T_EXCEPTION  = 3,
  T_ONEWAY     = 4
};

static const uint32_t DEFAULT_RECURSION_LIMIT = 64;

/**
 * Abstract class for a thrift protocol driver. These are all the methods that
 * a protocol must implement. Essentially, there must be some way of reading
 * and writing all the base types, plus a mechanism for writing out structs
 * with indexed fields.
 *
 * TProtocol objects should not be shared across multiple encoding contexts,
 * as they may need to maintain internal state in some protocols (i.e. XML).
 * Note that is is acceptable for the TProtocol module to do its own internal
 * buffered reads/writes to the underlying TTransport where appropriate (i.e.
 * when parsing an input XML stream, reading should be batched rather than
 * looking ahead character by character for a close tag).
 *
 */
class TProtocol {
public:
  virtual ~TProtocol();

  /**
   * Writing functions.
   */

  virtual uint32_t writeMessageBegin_virt(const std::string& name,
                                          const TMessageType messageType,
                                          const int32_t seqid) = 0;

  virtual uint32_t writeMessageEnd_virt() = 0;

  virtual uint32_t writeStructBegin_virt(const char* name) = 0;

  virtual uint32_t writeStructEnd_virt() = 0;

  virtual uint32_t writeFieldBegin_virt(const char* name,
                                        const TType fieldType,
                                        const int16_t fieldId) = 0;

  virtual uint32_t writeFieldEnd_virt() = 0;

  virtual uint32_t writeFieldStop_virt() = 0;

  virtual uint32_t writeMapBegin_virt(const TType keyType, const TType valType, const uint32_t size)
      = 0;

  virtual uint32_t writeMapEnd_virt() = 0;

  virtual uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) = 0;

  virtual uint32_t writeListEnd_virt() = 0;

  virtual uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) = 0;

  virtual uint32_t writeSetEnd_virt() = 0;

  virtual uint32_t writeBool_virt(const bool value) = 0;

  virtual uint32_t writeByte_virt(const int8_t byte) = 0;

  virtual uint32_t writeI16_virt(const int16_t i16) = 0;

  virtual uint32_t writeI32_virt(const int32_t i32) = 0;

  virtual uint32_t writeI64_virt(const int64_t i64) = 0;

  virtual uint32_t writeDouble_virt(const double dub) = 0;

  virtual uint32_t writeString_virt(const std::string& str) = 0;

  virtual uint32_t writeBinary_virt(const std::string& str) = 0;

  uint32_t writeMessageBegin(const std::string& name,
                             const TMessageType messageType,
                             const int32_t seqid) {
    T_VIRTUAL_CALL();
    return writeMessageBegin_virt(name, messageType, seqid);
  }

  uint32_t writeMessageEnd() {
    T_VIRTUAL_CALL();
    return writeMessageEnd_virt();
  }

  uint32_t writeStructBegin(const char* name) {
    T_VIRTUAL_CALL();
    return writeStructBegin_virt(name);
  }

  uint32_t writeStructEnd() {
    T_VIRTUAL_CALL();
    return writeStructEnd_virt();
  }

  uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId) {
    T_VIRTUAL_CALL();
    return writeFieldBegin_virt(name, fieldType, fieldId);
  }

  uint32_t writeFieldEnd() {
    T_VIRTUAL_CALL();
    return writeFieldEnd_virt();
  }

  uint32_t writeFieldStop() {
    T_VIRTUAL_CALL();
    return writeFieldStop_virt();
  }

  uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size) {
    T_VIRTUAL_CALL();
    return writeMapBegin_virt(keyType, valType, size);
  }

  uint32_t writeMapEnd() {
    T_VIRTUAL_CALL();
    return writeMapEnd_virt();
  }

  uint32_t writeListBegin(const TType elemType, const uint32_t size) {
    T_VIRTUAL_CALL();
    return writeListBegin_virt(elemType, size);
  }

  uint32_t writeListEnd() {
    T_VIRTUAL_CALL();
    return writeListEnd_virt();
  }

  uint32_t writeSetBegin(const TType elemType, const uint32_t size) {
    T_VIRTUAL_CALL();
    return writeSetBegin_virt(elemType, size);
  }

  uint32_t writeSetEnd() {
    T_VIRTUAL_CALL();
    return writeSetEnd_virt();
  }

  uint32_t writeBool(const bool value) {
    T_VIRTUAL_CALL();
    return writeBool_virt(value);
  }

  uint32_t writeByte(const int8_t byte) {
    T_VIRTUAL_CALL();
    return writeByte_virt(byte);
  }

  uint32_t writeI16(const int16_t i16) {
    T_VIRTUAL_CALL();
    return writeI16_virt(i16);
  }

  uint32_t writeI32(const int32_t i32) {
    T_VIRTUAL_CALL();
    return writeI32_virt(i32);
  }

  uint32_t writeI64(const int64_t i64) {
    T_VIRTUAL_CALL();
    return writeI64_virt(i64);
  }

  uint32_t writeDouble(const double dub) {
    T_VIRTUAL_CALL();
    return writeDouble_virt(dub);
  }

  uint32_t writeString(const std::string& str) {
    T_VIRTUAL_CALL();
    return writeString_virt(str);
  }

  uint32_t writeBinary(const std::string& str) {
    T_VIRTUAL_CALL();
    return writeBinary_virt(str);
  }

  /**
   * Reading functions
   */

  virtual uint32_t readMessageBegin_virt(std::string& name,
                                         TMessageType& messageType,
                                         int32_t& seqid) = 0;

  virtual uint32_t readMessageEnd_virt() = 0;

  virtual uint32_t readStructBegin_virt(std::string& name) = 0;

  virtual uint32_t readStructEnd_virt() = 0;

  virtual uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) = 0;

  virtual uint32_t readFieldEnd_virt() = 0;

  virtual uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) = 0;

  virtual uint32_t readMapEnd_virt() = 0;

  virtual uint32_t readListBegin_virt(TType& elemType, uint32_t& size) = 0;

  virtual uint32_t readListEnd_virt() = 0;

  virtual uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) = 0;

  virtual uint32_t readSetEnd_virt() = 0;

  virtual uint32_t readBool_virt(bool& value) = 0;

  virtual uint32_t readBool_virt(std::vector<bool>::reference value) = 0;

  virtual uint32_t readByte_virt(int8_t& byte) = 0;

  virtual uint32_t readI16_virt(int16_t& i16) = 0;

  virtual uint32_t readI32_virt(int32_t& i32) = 0;

  virtual uint32_t readI64_virt(int64_t& i64) = 0;

  virtual uint32_t readDouble_virt(double& dub) = 0;

  virtual uint32_t readString_virt(std::string& str) = 0;

  virtual uint32_t readBinary_virt(std::string& str) = 0;

  uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) {
    T_VIRTUAL_CALL();
    return readMessageBegin_virt(name, messageType, seqid);
  }

  uint32_t readMessageEnd() {
    T_VIRTUAL_CALL();
    return readMessageEnd_virt();
  }

  uint32_t readStructBegin(std::string& name) {
    T_VIRTUAL_CALL();
    return readStructBegin_virt(name);
  }

  uint32_t readStructEnd() {
    T_VIRTUAL_CALL();
    return readStructEnd_virt();
  }

  uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
    T_VIRTUAL_CALL();
    return readFieldBegin_virt(name, fieldType, fieldId);
  }

  uint32_t readFieldEnd() {
    T_VIRTUAL_CALL();
    return readFieldEnd_virt();
  }

  uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
    T_VIRTUAL_CALL();
    return readMapBegin_virt(keyType, valType, size);
  }

  uint32_t readMapEnd() {
    T_VIRTUAL_CALL();
    return readMapEnd_virt();
  }

  uint32_t readListBegin(TType& elemType, uint32_t& size) {
    T_VIRTUAL_CALL();
    return readListBegin_virt(elemType, size);
  }

  uint32_t readListEnd() {
    T_VIRTUAL_CALL();
    return readListEnd_virt();
  }

  uint32_t readSetBegin(TType& elemType, uint32_t& size) {
    T_VIRTUAL_CALL();
    return readSetBegin_virt(elemType, size);
  }

  uint32_t readSetEnd() {
    T_VIRTUAL_CALL();
    return readSetEnd_virt();
  }

  uint32_t readBool(bool& value) {
    T_VIRTUAL_CALL();
    return readBool_virt(value);
  }

  uint32_t readByte(int8_t& byte) {
    T_VIRTUAL_CALL();
    return readByte_virt(byte);
  }

  uint32_t readI16(int16_t& i16) {
    T_VIRTUAL_CALL();
    return readI16_virt(i16);
  }

  uint32_t readI32(int32_t& i32) {
    T_VIRTUAL_CALL();
    return readI32_virt(i32);
  }

  uint32_t readI64(int64_t& i64) {
    T_VIRTUAL_CALL();
    return readI64_virt(i64);
  }

  uint32_t readDouble(double& dub) {
    T_VIRTUAL_CALL();
    return readDouble_virt(dub);
  }

  uint32_t readString(std::string& str) {
    T_VIRTUAL_CALL();
    return readString_virt(str);
  }

  uint32_t readBinary(std::string& str) {
    T_VIRTUAL_CALL();
    return readBinary_virt(str);
  }

  /*
   * std::vector is specialized for bool, and its elements are individual bits
   * rather than bools.   We need to define a different version of readBool()
   * to work with std::vector<bool>.
   */
  uint32_t readBool(std::vector<bool>::reference value) {
    T_VIRTUAL_CALL();
    return readBool_virt(value);
  }

  /**
   * Method to arbitrarily skip over data.
   */
  uint32_t skip(TType type) {
    T_VIRTUAL_CALL();
    return skip_virt(type);
  }
  virtual uint32_t skip_virt(TType type);

  inline std::shared_ptr<TTransport> getTransport() { return ptrans_; }

  // TODO: remove these two calls, they are for backwards
  // compatibility
  inline std::shared_ptr<TTransport> getInputTransport() { return ptrans_; }
  inline std::shared_ptr<TTransport> getOutputTransport() { return ptrans_; }

  // input and output recursion depth are kept separate so that one protocol
  // can be used concurrently for both input and output.
  void incrementInputRecursionDepth() {
    if (recursion_limit_ < ++input_recursion_depth_) {
      throw TProtocolException(TProtocolException::DEPTH_LIMIT);
    }
  }
  void decrementInputRecursionDepth() { --input_recursion_depth_; }

  void incrementOutputRecursionDepth() {
    if (recursion_limit_ < ++output_recursion_depth_) {
      throw TProtocolException(TProtocolException::DEPTH_LIMIT);
    }
  }
  void decrementOutputRecursionDepth() { --output_recursion_depth_; }

  uint32_t getRecursionLimit() const {return recursion_limit_;}
  void setRecurisionLimit(uint32_t depth) {recursion_limit_ = depth;}

protected:
  TProtocol(std::shared_ptr<TTransport> ptrans)
    : ptrans_(ptrans), input_recursion_depth_(0), output_recursion_depth_(0), recursion_limit_(DEFAULT_RECURSION_LIMIT)
  {}

  std::shared_ptr<TTransport> ptrans_;

private:
  TProtocol() = default;
  uint32_t input_recursion_depth_;
  uint32_t output_recursion_depth_;
  uint32_t recursion_limit_;
};

/**
 * Constructs input and output protocol objects given transports.
 */
class TProtocolFactory {
public:
  TProtocolFactory() = default;

  virtual ~TProtocolFactory();

  virtual std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> trans) = 0;
  virtual std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> inTrans,
               std::shared_ptr<TTransport> outTrans) {
    (void)outTrans;
    return getProtocol(inTrans);
  }
};

/**
 * Dummy protocol class.
 *
 * This class does nothing, and should never be instantiated.
 * It is used only by the generator code.
 */
class TDummyProtocol : public TProtocol {};


// HM: this is sub-optimal since it creates a depencency even for memory-only struct
//// This is the default / legacy choice
//struct TNetworkBigEndian
//{
//  static uint16_t toWire16(uint16_t x)   {return htons(x);}
//  static uint32_t toWire32(uint32_t x)   {return htonl(x);}
//  static uint64_t toWire64(uint64_t x)   {return THRIFT_htonll(x);}
//  static uint16_t fromWire16(uint16_t x) {return ntohs(x);}
//  static uint32_t fromWire32(uint32_t x) {return ntohl(x);}
//  static uint64_t fromWire64(uint64_t x) {return THRIFT_ntohll(x);}
//};
//
//// On most systems, this will be a bit faster than TNetworkBigEndian
//struct TNetworkLittleEndian
//{
//  static uint16_t toWire16(uint16_t x)   {return THRIFT_htoles(x);}
//  static uint32_t toWire32(uint32_t x)   {return THRIFT_htolel(x);}
//  static uint64_t toWire64(uint64_t x)   {return THRIFT_htolell(x);}
//  static uint16_t fromWire16(uint16_t x) {return THRIFT_letohs(x);}
//  static uint32_t fromWire32(uint32_t x) {return THRIFT_letohl(x);}
//  static uint64_t fromWire64(uint64_t x) {return THRIFT_letohll(x);}
//};

struct TOutputRecursionTracker {
  TProtocol &prot_;
  TOutputRecursionTracker(TProtocol &prot) : prot_(prot) {
    prot_.incrementOutputRecursionDepth();
  }
  ~TOutputRecursionTracker() {
    prot_.decrementOutputRecursionDepth();
  }
};

struct TInputRecursionTracker {
  TProtocol &prot_;
  TInputRecursionTracker(TProtocol &prot) : prot_(prot) {
    prot_.incrementInputRecursionDepth();
  }
  ~TInputRecursionTracker() {
    prot_.decrementInputRecursionDepth();
  }
};

/**
 * Helper template for implementing TProtocol::skip().
 *
 * Templatized to avoid having to make virtual function calls.
 */
template <class Protocol_>
uint32_t skip(Protocol_& prot, TType type) {
  TInputRecursionTracker tracker(prot);

  switch (type) {
  case T_BOOL: {
    bool boolv;
    return prot.readBool(boolv);
  }
  case T_BYTE: {
    int8_t bytev = 0;
    return prot.readByte(bytev);
  }
  case T_I16: {
    int16_t i16;
    return prot.readI16(i16);
  }
  case T_I32: {
    int32_t i32;
    return prot.readI32(i32);
  }
  case T_I64: {
    int64_t i64;
    return prot.readI64(i64);
  }
  case T_DOUBLE: {
    double dub;
    return prot.readDouble(dub);
  }
  case T_STRING: {
    std::string str;
    return prot.readBinary(str);
  }
  case T_STRUCT: {
    uint32_t result = 0;
    std::string name;
    int16_t fid;
    TType ftype;
    result += prot.readStructBegin(name);
    while (true) {
      result += prot.readFieldBegin(name, ftype, fid);
      if (ftype == T_STOP) {
        break;
      }
      result += skip(prot, ftype);
      result += prot.readFieldEnd();
    }
    result += prot.readStructEnd();
    return result;
  }
  case T_MAP: {
    uint32_t result = 0;
    TType keyType;
    TType valType;
    uint32_t i, size;
    result += prot.readMapBegin(keyType, valType, size);
    for (i = 0; i < size; i++) {
      result += skip(prot, keyType);
      result += skip(prot, valType);
    }
    result += prot.readMapEnd();
    return result;
  }
  case T_SET: {
    uint32_t result = 0;
    TType elemType;
    uint32_t i, size;
    result += prot.readSetBegin(elemType, size);
    for (i = 0; i < size; i++) {
      result += skip(prot, elemType);
    }
    result += prot.readSetEnd();
    return result;
  }
  case T_LIST: {
    uint32_t result = 0;
    TType elemType;
    uint32_t i, size;
    result += prot.readListBegin(elemType, size);
    for (i = 0; i < size; i++) {
      result += skip(prot, elemType);
    }
    result += prot.readListEnd();
    return result;
  }
  default:
    break;
  }

  throw TProtocolException(TProtocolException::INVALID_DATA,
                           "invalid TType");
}

}}} // duckdb_apache::thrift::protocol

#endif // #define _DUCKDB_THRIFT_PROTOCOL_TPROTOCOL_H_ 1


// LICENSE_CHANGE_END


namespace duckdb_apache {
namespace thrift {

class TBase {
public:
  virtual ~TBase() = default;
  virtual uint32_t read(protocol::TProtocol* iprot) = 0;
  virtual uint32_t write(protocol::TProtocol* oprot) const = 0;
};
}
} // duckdb_apache::thrift

#endif // #ifndef _DUCKDB_THRIFT_TBASE_H_


// LICENSE_CHANGE_END






// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list



// LICENSE_CHANGE_END




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #1
// See the end of this file for a list



#ifdef _WIN32
#undef CREATE_NEW
#undef OPTIONAL
#undef Realloc
#undef min
#undef max
#endif

// LICENSE_CHANGE_END


namespace duckdb_parquet { namespace format {

struct Type {
  enum type {
    BOOLEAN = 0,
    INT32 = 1,
    INT64 = 2,
    INT96 = 3,
    FLOAT = 4,
    DOUBLE = 5,
    BYTE_ARRAY = 6,
    FIXED_LEN_BYTE_ARRAY = 7
  };
};

extern const std::map<int, const char*> _Type_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const Type::type& val);

struct ConvertedType {
  enum type {
    UTF8 = 0,
    MAP = 1,
    MAP_KEY_VALUE = 2,
    LIST = 3,
    ENUM = 4,
    DECIMAL = 5,
    DATE = 6,
    TIME_MILLIS = 7,
    TIME_MICROS = 8,
    TIMESTAMP_MILLIS = 9,
    TIMESTAMP_MICROS = 10,
    UINT_8 = 11,
    UINT_16 = 12,
    UINT_32 = 13,
    UINT_64 = 14,
    INT_8 = 15,
    INT_16 = 16,
    INT_32 = 17,
    INT_64 = 18,
    JSON = 19,
    BSON = 20,
    INTERVAL = 21
  };
};

extern const std::map<int, const char*> _ConvertedType_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const ConvertedType::type& val);

struct FieldRepetitionType {
  enum type {
    REQUIRED = 0,
    OPTIONAL = 1,
    REPEATED = 2
  };
};

extern const std::map<int, const char*> _FieldRepetitionType_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const FieldRepetitionType::type& val);

struct Encoding {
  enum type {
    PLAIN = 0,
    PLAIN_DICTIONARY = 2,
    RLE = 3,
    BIT_PACKED = 4,
    DELTA_BINARY_PACKED = 5,
    DELTA_LENGTH_BYTE_ARRAY = 6,
    DELTA_BYTE_ARRAY = 7,
    RLE_DICTIONARY = 8
  };
};

extern const std::map<int, const char*> _Encoding_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const Encoding::type& val);

struct CompressionCodec {
  enum type {
    UNCOMPRESSED = 0,
    SNAPPY = 1,
    GZIP = 2,
    LZO = 3,
    BROTLI = 4,
    LZ4 = 5,
    ZSTD = 6
  };
};

extern const std::map<int, const char*> _CompressionCodec_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const CompressionCodec::type& val);

struct PageType {
  enum type {
    DATA_PAGE = 0,
    INDEX_PAGE = 1,
    DICTIONARY_PAGE = 2,
    DATA_PAGE_V2 = 3
  };
};

extern const std::map<int, const char*> _PageType_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const PageType::type& val);

struct BoundaryOrder {
  enum type {
    UNORDERED = 0,
    ASCENDING = 1,
    DESCENDING = 2
  };
};

extern const std::map<int, const char*> _BoundaryOrder_VALUES_TO_NAMES;

std::ostream& operator<<(std::ostream& out, const BoundaryOrder::type& val);

class Statistics;

class StringType;

class UUIDType;

class MapType;

class ListType;

class EnumType;

class DateType;

class NullType;

class DecimalType;

class MilliSeconds;

class MicroSeconds;

class NanoSeconds;

class TimeUnit;

class TimestampType;

class TimeType;

class IntType;

class JsonType;

class BsonType;

class LogicalType;

class SchemaElement;

class DataPageHeader;

class IndexPageHeader;

class DictionaryPageHeader;

class DataPageHeaderV2;

class PageHeader;

class KeyValue;

class SortingColumn;

class PageEncodingStats;

class ColumnMetaData;

class EncryptionWithFooterKey;

class EncryptionWithColumnKey;

class ColumnCryptoMetaData;

class ColumnChunk;

class RowGroup;

class TypeDefinedOrder;

class ColumnOrder;

class PageLocation;

class OffsetIndex;

class ColumnIndex;

class AesGcmV1;

class AesGcmCtrV1;

class EncryptionAlgorithm;

class FileMetaData;

class FileCryptoMetaData;

typedef struct _Statistics__isset {
  _Statistics__isset() : max(false), min(false), null_count(false), distinct_count(false), max_value(false), min_value(false) {}
  bool max :1;
  bool min :1;
  bool null_count :1;
  bool distinct_count :1;
  bool max_value :1;
  bool min_value :1;
} _Statistics__isset;

class Statistics : public virtual ::duckdb_apache::thrift::TBase {
 public:

  Statistics(const Statistics&);
  Statistics& operator=(const Statistics&);
  Statistics() : max(), min(), null_count(0), distinct_count(0), max_value(), min_value() {
  }

  virtual ~Statistics() throw();
  std::string max;
  std::string min;
  int64_t null_count;
  int64_t distinct_count;
  std::string max_value;
  std::string min_value;

  _Statistics__isset __isset;

  void __set_max(const std::string& val);

  void __set_min(const std::string& val);

  void __set_null_count(const int64_t val);

  void __set_distinct_count(const int64_t val);

  void __set_max_value(const std::string& val);

  void __set_min_value(const std::string& val);

  bool operator == (const Statistics & rhs) const
  {
    if (__isset.max != rhs.__isset.max)
      return false;
    else if (__isset.max && !(max == rhs.max))
      return false;
    if (__isset.min != rhs.__isset.min)
      return false;
    else if (__isset.min && !(min == rhs.min))
      return false;
    if (__isset.null_count != rhs.__isset.null_count)
      return false;
    else if (__isset.null_count && !(null_count == rhs.null_count))
      return false;
    if (__isset.distinct_count != rhs.__isset.distinct_count)
      return false;
    else if (__isset.distinct_count && !(distinct_count == rhs.distinct_count))
      return false;
    if (__isset.max_value != rhs.__isset.max_value)
      return false;
    else if (__isset.max_value && !(max_value == rhs.max_value))
      return false;
    if (__isset.min_value != rhs.__isset.min_value)
      return false;
    else if (__isset.min_value && !(min_value == rhs.min_value))
      return false;
    return true;
  }
  bool operator != (const Statistics &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const Statistics & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(Statistics &a, Statistics &b);

std::ostream& operator<<(std::ostream& out, const Statistics& obj);


class StringType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  StringType(const StringType&);
  StringType& operator=(const StringType&);
  StringType() {
  }

  virtual ~StringType() throw();

  bool operator == (const StringType & /* rhs */) const
  {
    return true;
  }
  bool operator != (const StringType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const StringType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(StringType &a, StringType &b);

std::ostream& operator<<(std::ostream& out, const StringType& obj);


class UUIDType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  UUIDType(const UUIDType&);
  UUIDType& operator=(const UUIDType&);
  UUIDType() {
  }

  virtual ~UUIDType() throw();

  bool operator == (const UUIDType & /* rhs */) const
  {
    return true;
  }
  bool operator != (const UUIDType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const UUIDType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(UUIDType &a, UUIDType &b);

std::ostream& operator<<(std::ostream& out, const UUIDType& obj);


class MapType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  MapType(const MapType&);
  MapType& operator=(const MapType&);
  MapType() {
  }

  virtual ~MapType() throw();

  bool operator == (const MapType & /* rhs */) const
  {
    return true;
  }
  bool operator != (const MapType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const MapType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(MapType &a, MapType &b);

std::ostream& operator<<(std::ostream& out, const MapType& obj);


class ListType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  ListType(const ListType&);
  ListType& operator=(const ListType&);
  ListType() {
  }

  virtual ~ListType() throw();

  bool operator == (const ListType & /* rhs */) const
  {
    return true;
  }
  bool operator != (const ListType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const ListType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ListType &a, ListType &b);

std::ostream& operator<<(std::ostream& out, const ListType& obj);


class EnumType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  EnumType(const EnumType&);
  EnumType& operator=(const EnumType&);
  EnumType() {
  }

  virtual ~EnumType() throw();

  bool operator == (const EnumType & /* rhs */) const
  {
    return true;
  }
  bool operator != (const EnumType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const EnumType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(EnumType &a, EnumType &b);

std::ostream& operator<<(std::ostream& out, const EnumType& obj);


class DateType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  DateType(const DateType&);
  DateType& operator=(const DateType&);
  DateType() {
  }

  virtual ~DateType() throw();

  bool operator == (const DateType & /* rhs */) const
  {
    return true;
  }
  bool operator != (const DateType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const DateType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DateType &a, DateType &b);

std::ostream& operator<<(std::ostream& out, const DateType& obj);


class NullType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  NullType(const NullType&);
  NullType& operator=(const NullType&);
  NullType() {
  }

  virtual ~NullType() throw();

  bool operator == (const NullType & /* rhs */) const
  {
    return true;
  }
  bool operator != (const NullType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const NullType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(NullType &a, NullType &b);

std::ostream& operator<<(std::ostream& out, const NullType& obj);


class DecimalType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  DecimalType(const DecimalType&);
  DecimalType& operator=(const DecimalType&);
  DecimalType() : scale(0), precision(0) {
  }

  virtual ~DecimalType() throw();
  int32_t scale;
  int32_t precision;

  void __set_scale(const int32_t val);

  void __set_precision(const int32_t val);

  bool operator == (const DecimalType & rhs) const
  {
    if (!(scale == rhs.scale))
      return false;
    if (!(precision == rhs.precision))
      return false;
    return true;
  }
  bool operator != (const DecimalType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const DecimalType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DecimalType &a, DecimalType &b);

std::ostream& operator<<(std::ostream& out, const DecimalType& obj);


class MilliSeconds : public virtual ::duckdb_apache::thrift::TBase {
 public:

  MilliSeconds(const MilliSeconds&);
  MilliSeconds& operator=(const MilliSeconds&);
  MilliSeconds() {
  }

  virtual ~MilliSeconds() throw();

  bool operator == (const MilliSeconds & /* rhs */) const
  {
    return true;
  }
  bool operator != (const MilliSeconds &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const MilliSeconds & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(MilliSeconds &a, MilliSeconds &b);

std::ostream& operator<<(std::ostream& out, const MilliSeconds& obj);


class MicroSeconds : public virtual ::duckdb_apache::thrift::TBase {
 public:

  MicroSeconds(const MicroSeconds&);
  MicroSeconds& operator=(const MicroSeconds&);
  MicroSeconds() {
  }

  virtual ~MicroSeconds() throw();

  bool operator == (const MicroSeconds & /* rhs */) const
  {
    return true;
  }
  bool operator != (const MicroSeconds &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const MicroSeconds & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(MicroSeconds &a, MicroSeconds &b);

std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj);


class NanoSeconds : public virtual ::duckdb_apache::thrift::TBase {
 public:

  NanoSeconds(const NanoSeconds&);
  NanoSeconds& operator=(const NanoSeconds&);
  NanoSeconds() {
  }

  virtual ~NanoSeconds() throw();

  bool operator == (const NanoSeconds & /* rhs */) const
  {
    return true;
  }
  bool operator != (const NanoSeconds &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const NanoSeconds & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(NanoSeconds &a, NanoSeconds &b);

std::ostream& operator<<(std::ostream& out, const NanoSeconds& obj);

typedef struct _TimeUnit__isset {
  _TimeUnit__isset() : MILLIS(false), MICROS(false), NANOS(false) {}
  bool MILLIS :1;
  bool MICROS :1;
  bool NANOS :1;
} _TimeUnit__isset;

class TimeUnit : public virtual ::duckdb_apache::thrift::TBase {
 public:

  TimeUnit(const TimeUnit&);
  TimeUnit& operator=(const TimeUnit&);
  TimeUnit() {
  }

  virtual ~TimeUnit() throw();
  MilliSeconds MILLIS;
  MicroSeconds MICROS;
  NanoSeconds NANOS;

  _TimeUnit__isset __isset;

  void __set_MILLIS(const MilliSeconds& val);

  void __set_MICROS(const MicroSeconds& val);

  void __set_NANOS(const NanoSeconds& val);

  bool operator == (const TimeUnit & rhs) const
  {
    if (__isset.MILLIS != rhs.__isset.MILLIS)
      return false;
    else if (__isset.MILLIS && !(MILLIS == rhs.MILLIS))
      return false;
    if (__isset.MICROS != rhs.__isset.MICROS)
      return false;
    else if (__isset.MICROS && !(MICROS == rhs.MICROS))
      return false;
    if (__isset.NANOS != rhs.__isset.NANOS)
      return false;
    else if (__isset.NANOS && !(NANOS == rhs.NANOS))
      return false;
    return true;
  }
  bool operator != (const TimeUnit &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const TimeUnit & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(TimeUnit &a, TimeUnit &b);

std::ostream& operator<<(std::ostream& out, const TimeUnit& obj);


class TimestampType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  TimestampType(const TimestampType&);
  TimestampType& operator=(const TimestampType&);
  TimestampType() : isAdjustedToUTC(0) {
  }

  virtual ~TimestampType() throw();
  bool isAdjustedToUTC;
  TimeUnit unit;

  void __set_isAdjustedToUTC(const bool val);

  void __set_unit(const TimeUnit& val);

  bool operator == (const TimestampType & rhs) const
  {
    if (!(isAdjustedToUTC == rhs.isAdjustedToUTC))
      return false;
    if (!(unit == rhs.unit))
      return false;
    return true;
  }
  bool operator != (const TimestampType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const TimestampType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(TimestampType &a, TimestampType &b);

std::ostream& operator<<(std::ostream& out, const TimestampType& obj);


class TimeType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  TimeType(const TimeType&);
  TimeType& operator=(const TimeType&);
  TimeType() : isAdjustedToUTC(0) {
  }

  virtual ~TimeType() throw();
  bool isAdjustedToUTC;
  TimeUnit unit;

  void __set_isAdjustedToUTC(const bool val);

  void __set_unit(const TimeUnit& val);

  bool operator == (const TimeType & rhs) const
  {
    if (!(isAdjustedToUTC == rhs.isAdjustedToUTC))
      return false;
    if (!(unit == rhs.unit))
      return false;
    return true;
  }
  bool operator != (const TimeType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const TimeType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(TimeType &a, TimeType &b);

std::ostream& operator<<(std::ostream& out, const TimeType& obj);


class IntType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  IntType(const IntType&);
  IntType& operator=(const IntType&);
  IntType() : bitWidth(0), isSigned(0) {
  }

  virtual ~IntType() throw();
  int8_t bitWidth;
  bool isSigned;

  void __set_bitWidth(const int8_t val);

  void __set_isSigned(const bool val);

  bool operator == (const IntType & rhs) const
  {
    if (!(bitWidth == rhs.bitWidth))
      return false;
    if (!(isSigned == rhs.isSigned))
      return false;
    return true;
  }
  bool operator != (const IntType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const IntType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(IntType &a, IntType &b);

std::ostream& operator<<(std::ostream& out, const IntType& obj);


class JsonType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  JsonType(const JsonType&);
  JsonType& operator=(const JsonType&);
  JsonType() {
  }

  virtual ~JsonType() throw();

  bool operator == (const JsonType & /* rhs */) const
  {
    return true;
  }
  bool operator != (const JsonType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const JsonType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(JsonType &a, JsonType &b);

std::ostream& operator<<(std::ostream& out, const JsonType& obj);


class BsonType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  BsonType(const BsonType&);
  BsonType& operator=(const BsonType&);
  BsonType() {
  }

  virtual ~BsonType() throw();

  bool operator == (const BsonType & /* rhs */) const
  {
    return true;
  }
  bool operator != (const BsonType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const BsonType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(BsonType &a, BsonType &b);

std::ostream& operator<<(std::ostream& out, const BsonType& obj);

typedef struct _LogicalType__isset {
  _LogicalType__isset() : STRING(false), MAP(false), LIST(false), ENUM(false), DECIMAL(false), DATE(false), TIME(false), TIMESTAMP(false), INTEGER(false), UNKNOWN(false), JSON(false), BSON(false), UUID(false) {}
  bool STRING :1;
  bool MAP :1;
  bool LIST :1;
  bool ENUM :1;
  bool DECIMAL :1;
  bool DATE :1;
  bool TIME :1;
  bool TIMESTAMP :1;
  bool INTEGER :1;
  bool UNKNOWN :1;
  bool JSON :1;
  bool BSON :1;
  bool UUID :1;
} _LogicalType__isset;

class LogicalType : public virtual ::duckdb_apache::thrift::TBase {
 public:

  LogicalType(const LogicalType&);
  LogicalType& operator=(const LogicalType&);
  LogicalType() {
  }

  virtual ~LogicalType() throw();
  StringType STRING;
  MapType MAP;
  ListType LIST;
  EnumType ENUM;
  DecimalType DECIMAL;
  DateType DATE;
  TimeType TIME;
  TimestampType TIMESTAMP;
  IntType INTEGER;
  NullType UNKNOWN;
  JsonType JSON;
  BsonType BSON;
  UUIDType UUID;

  _LogicalType__isset __isset;

  void __set_STRING(const StringType& val);

  void __set_MAP(const MapType& val);

  void __set_LIST(const ListType& val);

  void __set_ENUM(const EnumType& val);

  void __set_DECIMAL(const DecimalType& val);

  void __set_DATE(const DateType& val);

  void __set_TIME(const TimeType& val);

  void __set_TIMESTAMP(const TimestampType& val);

  void __set_INTEGER(const IntType& val);

  void __set_UNKNOWN(const NullType& val);

  void __set_JSON(const JsonType& val);

  void __set_BSON(const BsonType& val);

  void __set_UUID(const UUIDType& val);

  bool operator == (const LogicalType & rhs) const
  {
    if (__isset.STRING != rhs.__isset.STRING)
      return false;
    else if (__isset.STRING && !(STRING == rhs.STRING))
      return false;
    if (__isset.MAP != rhs.__isset.MAP)
      return false;
    else if (__isset.MAP && !(MAP == rhs.MAP))
      return false;
    if (__isset.LIST != rhs.__isset.LIST)
      return false;
    else if (__isset.LIST && !(LIST == rhs.LIST))
      return false;
    if (__isset.ENUM != rhs.__isset.ENUM)
      return false;
    else if (__isset.ENUM && !(ENUM == rhs.ENUM))
      return false;
    if (__isset.DECIMAL != rhs.__isset.DECIMAL)
      return false;
    else if (__isset.DECIMAL && !(DECIMAL == rhs.DECIMAL))
      return false;
    if (__isset.DATE != rhs.__isset.DATE)
      return false;
    else if (__isset.DATE && !(DATE == rhs.DATE))
      return false;
    if (__isset.TIME != rhs.__isset.TIME)
      return false;
    else if (__isset.TIME && !(TIME == rhs.TIME))
      return false;
    if (__isset.TIMESTAMP != rhs.__isset.TIMESTAMP)
      return false;
    else if (__isset.TIMESTAMP && !(TIMESTAMP == rhs.TIMESTAMP))
      return false;
    if (__isset.INTEGER != rhs.__isset.INTEGER)
      return false;
    else if (__isset.INTEGER && !(INTEGER == rhs.INTEGER))
      return false;
    if (__isset.UNKNOWN != rhs.__isset.UNKNOWN)
      return false;
    else if (__isset.UNKNOWN && !(UNKNOWN == rhs.UNKNOWN))
      return false;
    if (__isset.JSON != rhs.__isset.JSON)
      return false;
    else if (__isset.JSON && !(JSON == rhs.JSON))
      return false;
    if (__isset.BSON != rhs.__isset.BSON)
      return false;
    else if (__isset.BSON && !(BSON == rhs.BSON))
      return false;
    if (__isset.UUID != rhs.__isset.UUID)
      return false;
    else if (__isset.UUID && !(UUID == rhs.UUID))
      return false;
    return true;
  }
  bool operator != (const LogicalType &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const LogicalType & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(LogicalType &a, LogicalType &b);

std::ostream& operator<<(std::ostream& out, const LogicalType& obj);

typedef struct _SchemaElement__isset {
  _SchemaElement__isset() : type(false), type_length(false), repetition_type(false), num_children(false), converted_type(false), scale(false), precision(false), field_id(false), logicalType(false) {}
  bool type :1;
  bool type_length :1;
  bool repetition_type :1;
  bool num_children :1;
  bool converted_type :1;
  bool scale :1;
  bool precision :1;
  bool field_id :1;
  bool logicalType :1;
} _SchemaElement__isset;

class SchemaElement : public virtual ::duckdb_apache::thrift::TBase {
 public:

  SchemaElement(const SchemaElement&);
  SchemaElement& operator=(const SchemaElement&);
  SchemaElement() : type((Type::type)0), type_length(0), repetition_type((FieldRepetitionType::type)0), name(), num_children(0), converted_type((ConvertedType::type)0), scale(0), precision(0), field_id(0) {
  }

  virtual ~SchemaElement() throw();
  Type::type type;
  int32_t type_length;
  FieldRepetitionType::type repetition_type;
  std::string name;
  int32_t num_children;
  ConvertedType::type converted_type;
  int32_t scale;
  int32_t precision;
  int32_t field_id;
  LogicalType logicalType;

  _SchemaElement__isset __isset;

  void __set_type(const Type::type val);

  void __set_type_length(const int32_t val);

  void __set_repetition_type(const FieldRepetitionType::type val);

  void __set_name(const std::string& val);

  void __set_num_children(const int32_t val);

  void __set_converted_type(const ConvertedType::type val);

  void __set_scale(const int32_t val);

  void __set_precision(const int32_t val);

  void __set_field_id(const int32_t val);

  void __set_logicalType(const LogicalType& val);

  bool operator == (const SchemaElement & rhs) const
  {
    if (__isset.type != rhs.__isset.type)
      return false;
    else if (__isset.type && !(type == rhs.type))
      return false;
    if (__isset.type_length != rhs.__isset.type_length)
      return false;
    else if (__isset.type_length && !(type_length == rhs.type_length))
      return false;
    if (__isset.repetition_type != rhs.__isset.repetition_type)
      return false;
    else if (__isset.repetition_type && !(repetition_type == rhs.repetition_type))
      return false;
    if (!(name == rhs.name))
      return false;
    if (__isset.num_children != rhs.__isset.num_children)
      return false;
    else if (__isset.num_children && !(num_children == rhs.num_children))
      return false;
    if (__isset.converted_type != rhs.__isset.converted_type)
      return false;
    else if (__isset.converted_type && !(converted_type == rhs.converted_type))
      return false;
    if (__isset.scale != rhs.__isset.scale)
      return false;
    else if (__isset.scale && !(scale == rhs.scale))
      return false;
    if (__isset.precision != rhs.__isset.precision)
      return false;
    else if (__isset.precision && !(precision == rhs.precision))
      return false;
    if (__isset.field_id != rhs.__isset.field_id)
      return false;
    else if (__isset.field_id && !(field_id == rhs.field_id))
      return false;
    if (__isset.logicalType != rhs.__isset.logicalType)
      return false;
    else if (__isset.logicalType && !(logicalType == rhs.logicalType))
      return false;
    return true;
  }
  bool operator != (const SchemaElement &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const SchemaElement & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(SchemaElement &a, SchemaElement &b);

std::ostream& operator<<(std::ostream& out, const SchemaElement& obj);

typedef struct _DataPageHeader__isset {
  _DataPageHeader__isset() : statistics(false) {}
  bool statistics :1;
} _DataPageHeader__isset;

class DataPageHeader : public virtual ::duckdb_apache::thrift::TBase {
 public:

  DataPageHeader(const DataPageHeader&);
  DataPageHeader& operator=(const DataPageHeader&);
  DataPageHeader() : num_values(0), encoding((Encoding::type)0), definition_level_encoding((Encoding::type)0), repetition_level_encoding((Encoding::type)0) {
  }

  virtual ~DataPageHeader() throw();
  int32_t num_values;
  Encoding::type encoding;
  Encoding::type definition_level_encoding;
  Encoding::type repetition_level_encoding;
  Statistics statistics;

  _DataPageHeader__isset __isset;

  void __set_num_values(const int32_t val);

  void __set_encoding(const Encoding::type val);

  void __set_definition_level_encoding(const Encoding::type val);

  void __set_repetition_level_encoding(const Encoding::type val);

  void __set_statistics(const Statistics& val);

  bool operator == (const DataPageHeader & rhs) const
  {
    if (!(num_values == rhs.num_values))
      return false;
    if (!(encoding == rhs.encoding))
      return false;
    if (!(definition_level_encoding == rhs.definition_level_encoding))
      return false;
    if (!(repetition_level_encoding == rhs.repetition_level_encoding))
      return false;
    if (__isset.statistics != rhs.__isset.statistics)
      return false;
    else if (__isset.statistics && !(statistics == rhs.statistics))
      return false;
    return true;
  }
  bool operator != (const DataPageHeader &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const DataPageHeader & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DataPageHeader &a, DataPageHeader &b);

std::ostream& operator<<(std::ostream& out, const DataPageHeader& obj);


class IndexPageHeader : public virtual ::duckdb_apache::thrift::TBase {
 public:

  IndexPageHeader(const IndexPageHeader&);
  IndexPageHeader& operator=(const IndexPageHeader&);
  IndexPageHeader() {
  }

  virtual ~IndexPageHeader() throw();

  bool operator == (const IndexPageHeader & /* rhs */) const
  {
    return true;
  }
  bool operator != (const IndexPageHeader &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const IndexPageHeader & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(IndexPageHeader &a, IndexPageHeader &b);

std::ostream& operator<<(std::ostream& out, const IndexPageHeader& obj);

typedef struct _DictionaryPageHeader__isset {
  _DictionaryPageHeader__isset() : is_sorted(false) {}
  bool is_sorted :1;
} _DictionaryPageHeader__isset;

class DictionaryPageHeader : public virtual ::duckdb_apache::thrift::TBase {
 public:

  DictionaryPageHeader(const DictionaryPageHeader&);
  DictionaryPageHeader& operator=(const DictionaryPageHeader&);
  DictionaryPageHeader() : num_values(0), encoding((Encoding::type)0), is_sorted(0) {
  }

  virtual ~DictionaryPageHeader() throw();
  int32_t num_values;
  Encoding::type encoding;
  bool is_sorted;

  _DictionaryPageHeader__isset __isset;

  void __set_num_values(const int32_t val);

  void __set_encoding(const Encoding::type val);

  void __set_is_sorted(const bool val);

  bool operator == (const DictionaryPageHeader & rhs) const
  {
    if (!(num_values == rhs.num_values))
      return false;
    if (!(encoding == rhs.encoding))
      return false;
    if (__isset.is_sorted != rhs.__isset.is_sorted)
      return false;
    else if (__isset.is_sorted && !(is_sorted == rhs.is_sorted))
      return false;
    return true;
  }
  bool operator != (const DictionaryPageHeader &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const DictionaryPageHeader & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DictionaryPageHeader &a, DictionaryPageHeader &b);

std::ostream& operator<<(std::ostream& out, const DictionaryPageHeader& obj);

typedef struct _DataPageHeaderV2__isset {
  _DataPageHeaderV2__isset() : is_compressed(true), statistics(false) {}
  bool is_compressed :1;
  bool statistics :1;
} _DataPageHeaderV2__isset;

class DataPageHeaderV2 : public virtual ::duckdb_apache::thrift::TBase {
 public:

  DataPageHeaderV2(const DataPageHeaderV2&);
  DataPageHeaderV2& operator=(const DataPageHeaderV2&);
  DataPageHeaderV2() : num_values(0), num_nulls(0), num_rows(0), encoding((Encoding::type)0), definition_levels_byte_length(0), repetition_levels_byte_length(0), is_compressed(true) {
  }

  virtual ~DataPageHeaderV2() throw();
  int32_t num_values;
  int32_t num_nulls;
  int32_t num_rows;
  Encoding::type encoding;
  int32_t definition_levels_byte_length;
  int32_t repetition_levels_byte_length;
  bool is_compressed;
  Statistics statistics;

  _DataPageHeaderV2__isset __isset;

  void __set_num_values(const int32_t val);

  void __set_num_nulls(const int32_t val);

  void __set_num_rows(const int32_t val);

  void __set_encoding(const Encoding::type val);

  void __set_definition_levels_byte_length(const int32_t val);

  void __set_repetition_levels_byte_length(const int32_t val);

  void __set_is_compressed(const bool val);

  void __set_statistics(const Statistics& val);

  bool operator == (const DataPageHeaderV2 & rhs) const
  {
    if (!(num_values == rhs.num_values))
      return false;
    if (!(num_nulls == rhs.num_nulls))
      return false;
    if (!(num_rows == rhs.num_rows))
      return false;
    if (!(encoding == rhs.encoding))
      return false;
    if (!(definition_levels_byte_length == rhs.definition_levels_byte_length))
      return false;
    if (!(repetition_levels_byte_length == rhs.repetition_levels_byte_length))
      return false;
    if (__isset.is_compressed != rhs.__isset.is_compressed)
      return false;
    else if (__isset.is_compressed && !(is_compressed == rhs.is_compressed))
      return false;
    if (__isset.statistics != rhs.__isset.statistics)
      return false;
    else if (__isset.statistics && !(statistics == rhs.statistics))
      return false;
    return true;
  }
  bool operator != (const DataPageHeaderV2 &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const DataPageHeaderV2 & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(DataPageHeaderV2 &a, DataPageHeaderV2 &b);

std::ostream& operator<<(std::ostream& out, const DataPageHeaderV2& obj);

typedef struct _PageHeader__isset {
  _PageHeader__isset() : crc(false), data_page_header(false), index_page_header(false), dictionary_page_header(false), data_page_header_v2(false) {}
  bool crc :1;
  bool data_page_header :1;
  bool index_page_header :1;
  bool dictionary_page_header :1;
  bool data_page_header_v2 :1;
} _PageHeader__isset;

class PageHeader : public virtual ::duckdb_apache::thrift::TBase {
 public:

  PageHeader(const PageHeader&);
  PageHeader& operator=(const PageHeader&);
  PageHeader() : type((PageType::type)0), uncompressed_page_size(0), compressed_page_size(0), crc(0) {
  }

  virtual ~PageHeader() throw();
  PageType::type type;
  int32_t uncompressed_page_size;
  int32_t compressed_page_size;
  int32_t crc;
  DataPageHeader data_page_header;
  IndexPageHeader index_page_header;
  DictionaryPageHeader dictionary_page_header;
  DataPageHeaderV2 data_page_header_v2;

  _PageHeader__isset __isset;

  void __set_type(const PageType::type val);

  void __set_uncompressed_page_size(const int32_t val);

  void __set_compressed_page_size(const int32_t val);

  void __set_crc(const int32_t val);

  void __set_data_page_header(const DataPageHeader& val);

  void __set_index_page_header(const IndexPageHeader& val);

  void __set_dictionary_page_header(const DictionaryPageHeader& val);

  void __set_data_page_header_v2(const DataPageHeaderV2& val);

  bool operator == (const PageHeader & rhs) const
  {
    if (!(type == rhs.type))
      return false;
    if (!(uncompressed_page_size == rhs.uncompressed_page_size))
      return false;
    if (!(compressed_page_size == rhs.compressed_page_size))
      return false;
    if (__isset.crc != rhs.__isset.crc)
      return false;
    else if (__isset.crc && !(crc == rhs.crc))
      return false;
    if (__isset.data_page_header != rhs.__isset.data_page_header)
      return false;
    else if (__isset.data_page_header && !(data_page_header == rhs.data_page_header))
      return false;
    if (__isset.index_page_header != rhs.__isset.index_page_header)
      return false;
    else if (__isset.index_page_header && !(index_page_header == rhs.index_page_header))
      return false;
    if (__isset.dictionary_page_header != rhs.__isset.dictionary_page_header)
      return false;
    else if (__isset.dictionary_page_header && !(dictionary_page_header == rhs.dictionary_page_header))
      return false;
    if (__isset.data_page_header_v2 != rhs.__isset.data_page_header_v2)
      return false;
    else if (__isset.data_page_header_v2 && !(data_page_header_v2 == rhs.data_page_header_v2))
      return false;
    return true;
  }
  bool operator != (const PageHeader &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const PageHeader & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(PageHeader &a, PageHeader &b);

std::ostream& operator<<(std::ostream& out, const PageHeader& obj);

typedef struct _KeyValue__isset {
  _KeyValue__isset() : value(false) {}
  bool value :1;
} _KeyValue__isset;

class KeyValue : public virtual ::duckdb_apache::thrift::TBase {
 public:

  KeyValue(const KeyValue&);
  KeyValue& operator=(const KeyValue&);
  KeyValue() : key(), value() {
  }

  virtual ~KeyValue() throw();
  std::string key;
  std::string value;

  _KeyValue__isset __isset;

  void __set_key(const std::string& val);

  void __set_value(const std::string& val);

  bool operator == (const KeyValue & rhs) const
  {
    if (!(key == rhs.key))
      return false;
    if (__isset.value != rhs.__isset.value)
      return false;
    else if (__isset.value && !(value == rhs.value))
      return false;
    return true;
  }
  bool operator != (const KeyValue &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const KeyValue & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(KeyValue &a, KeyValue &b);

std::ostream& operator<<(std::ostream& out, const KeyValue& obj);


class SortingColumn : public virtual ::duckdb_apache::thrift::TBase {
 public:

  SortingColumn(const SortingColumn&);
  SortingColumn& operator=(const SortingColumn&);
  SortingColumn() : column_idx(0), descending(0), nulls_first(0) {
  }

  virtual ~SortingColumn() throw();
  int32_t column_idx;
  bool descending;
  bool nulls_first;

  void __set_column_idx(const int32_t val);

  void __set_descending(const bool val);

  void __set_nulls_first(const bool val);

  bool operator == (const SortingColumn & rhs) const
  {
    if (!(column_idx == rhs.column_idx))
      return false;
    if (!(descending == rhs.descending))
      return false;
    if (!(nulls_first == rhs.nulls_first))
      return false;
    return true;
  }
  bool operator != (const SortingColumn &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const SortingColumn & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(SortingColumn &a, SortingColumn &b);

std::ostream& operator<<(std::ostream& out, const SortingColumn& obj);


class PageEncodingStats : public virtual ::duckdb_apache::thrift::TBase {
 public:

  PageEncodingStats(const PageEncodingStats&);
  PageEncodingStats& operator=(const PageEncodingStats&);
  PageEncodingStats() : page_type((PageType::type)0), encoding((Encoding::type)0), count(0) {
  }

  virtual ~PageEncodingStats() throw();
  PageType::type page_type;
  Encoding::type encoding;
  int32_t count;

  void __set_page_type(const PageType::type val);

  void __set_encoding(const Encoding::type val);

  void __set_count(const int32_t val);

  bool operator == (const PageEncodingStats & rhs) const
  {
    if (!(page_type == rhs.page_type))
      return false;
    if (!(encoding == rhs.encoding))
      return false;
    if (!(count == rhs.count))
      return false;
    return true;
  }
  bool operator != (const PageEncodingStats &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const PageEncodingStats & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(PageEncodingStats &a, PageEncodingStats &b);

std::ostream& operator<<(std::ostream& out, const PageEncodingStats& obj);

typedef struct _ColumnMetaData__isset {
  _ColumnMetaData__isset() : key_value_metadata(false), index_page_offset(false), dictionary_page_offset(false), statistics(false), encoding_stats(false) {}
  bool key_value_metadata :1;
  bool index_page_offset :1;
  bool dictionary_page_offset :1;
  bool statistics :1;
  bool encoding_stats :1;
} _ColumnMetaData__isset;

class ColumnMetaData : public virtual ::duckdb_apache::thrift::TBase {
 public:

  ColumnMetaData(const ColumnMetaData&);
  ColumnMetaData& operator=(const ColumnMetaData&);
  ColumnMetaData() : type((Type::type)0), codec((CompressionCodec::type)0), num_values(0), total_uncompressed_size(0), total_compressed_size(0), data_page_offset(0), index_page_offset(0), dictionary_page_offset(0) {
  }

  virtual ~ColumnMetaData() throw();
  Type::type type;
  std::vector<Encoding::type>  encodings;
  std::vector<std::string>  path_in_schema;
  CompressionCodec::type codec;
  int64_t num_values;
  int64_t total_uncompressed_size;
  int64_t total_compressed_size;
  std::vector<KeyValue>  key_value_metadata;
  int64_t data_page_offset;
  int64_t index_page_offset;
  int64_t dictionary_page_offset;
  Statistics statistics;
  std::vector<PageEncodingStats>  encoding_stats;

  _ColumnMetaData__isset __isset;

  void __set_type(const Type::type val);

  void __set_encodings(const std::vector<Encoding::type> & val);

  void __set_path_in_schema(const std::vector<std::string> & val);

  void __set_codec(const CompressionCodec::type val);

  void __set_num_values(const int64_t val);

  void __set_total_uncompressed_size(const int64_t val);

  void __set_total_compressed_size(const int64_t val);

  void __set_key_value_metadata(const std::vector<KeyValue> & val);

  void __set_data_page_offset(const int64_t val);

  void __set_index_page_offset(const int64_t val);

  void __set_dictionary_page_offset(const int64_t val);

  void __set_statistics(const Statistics& val);

  void __set_encoding_stats(const std::vector<PageEncodingStats> & val);

  bool operator == (const ColumnMetaData & rhs) const
  {
    if (!(type == rhs.type))
      return false;
    if (!(encodings == rhs.encodings))
      return false;
    if (!(path_in_schema == rhs.path_in_schema))
      return false;
    if (!(codec == rhs.codec))
      return false;
    if (!(num_values == rhs.num_values))
      return false;
    if (!(total_uncompressed_size == rhs.total_uncompressed_size))
      return false;
    if (!(total_compressed_size == rhs.total_compressed_size))
      return false;
    if (__isset.key_value_metadata != rhs.__isset.key_value_metadata)
      return false;
    else if (__isset.key_value_metadata && !(key_value_metadata == rhs.key_value_metadata))
      return false;
    if (!(data_page_offset == rhs.data_page_offset))
      return false;
    if (__isset.index_page_offset != rhs.__isset.index_page_offset)
      return false;
    else if (__isset.index_page_offset && !(index_page_offset == rhs.index_page_offset))
      return false;
    if (__isset.dictionary_page_offset != rhs.__isset.dictionary_page_offset)
      return false;
    else if (__isset.dictionary_page_offset && !(dictionary_page_offset == rhs.dictionary_page_offset))
      return false;
    if (__isset.statistics != rhs.__isset.statistics)
      return false;
    else if (__isset.statistics && !(statistics == rhs.statistics))
      return false;
    if (__isset.encoding_stats != rhs.__isset.encoding_stats)
      return false;
    else if (__isset.encoding_stats && !(encoding_stats == rhs.encoding_stats))
      return false;
    return true;
  }
  bool operator != (const ColumnMetaData &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const ColumnMetaData & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnMetaData &a, ColumnMetaData &b);

std::ostream& operator<<(std::ostream& out, const ColumnMetaData& obj);


class EncryptionWithFooterKey : public virtual ::duckdb_apache::thrift::TBase {
 public:

  EncryptionWithFooterKey(const EncryptionWithFooterKey&);
  EncryptionWithFooterKey& operator=(const EncryptionWithFooterKey&);
  EncryptionWithFooterKey() {
  }

  virtual ~EncryptionWithFooterKey() throw();

  bool operator == (const EncryptionWithFooterKey & /* rhs */) const
  {
    return true;
  }
  bool operator != (const EncryptionWithFooterKey &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const EncryptionWithFooterKey & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(EncryptionWithFooterKey &a, EncryptionWithFooterKey &b);

std::ostream& operator<<(std::ostream& out, const EncryptionWithFooterKey& obj);

typedef struct _EncryptionWithColumnKey__isset {
  _EncryptionWithColumnKey__isset() : key_metadata(false) {}
  bool key_metadata :1;
} _EncryptionWithColumnKey__isset;

class EncryptionWithColumnKey : public virtual ::duckdb_apache::thrift::TBase {
 public:

  EncryptionWithColumnKey(const EncryptionWithColumnKey&);
  EncryptionWithColumnKey& operator=(const EncryptionWithColumnKey&);
  EncryptionWithColumnKey() : key_metadata() {
  }

  virtual ~EncryptionWithColumnKey() throw();
  std::vector<std::string>  path_in_schema;
  std::string key_metadata;

  _EncryptionWithColumnKey__isset __isset;

  void __set_path_in_schema(const std::vector<std::string> & val);

  void __set_key_metadata(const std::string& val);

  bool operator == (const EncryptionWithColumnKey & rhs) const
  {
    if (!(path_in_schema == rhs.path_in_schema))
      return false;
    if (__isset.key_metadata != rhs.__isset.key_metadata)
      return false;
    else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata))
      return false;
    return true;
  }
  bool operator != (const EncryptionWithColumnKey &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const EncryptionWithColumnKey & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(EncryptionWithColumnKey &a, EncryptionWithColumnKey &b);

std::ostream& operator<<(std::ostream& out, const EncryptionWithColumnKey& obj);

typedef struct _ColumnCryptoMetaData__isset {
  _ColumnCryptoMetaData__isset() : ENCRYPTION_WITH_FOOTER_KEY(false), ENCRYPTION_WITH_COLUMN_KEY(false) {}
  bool ENCRYPTION_WITH_FOOTER_KEY :1;
  bool ENCRYPTION_WITH_COLUMN_KEY :1;
} _ColumnCryptoMetaData__isset;

class ColumnCryptoMetaData : public virtual ::duckdb_apache::thrift::TBase {
 public:

  ColumnCryptoMetaData(const ColumnCryptoMetaData&);
  ColumnCryptoMetaData& operator=(const ColumnCryptoMetaData&);
  ColumnCryptoMetaData() {
  }

  virtual ~ColumnCryptoMetaData() throw();
  EncryptionWithFooterKey ENCRYPTION_WITH_FOOTER_KEY;
  EncryptionWithColumnKey ENCRYPTION_WITH_COLUMN_KEY;

  _ColumnCryptoMetaData__isset __isset;

  void __set_ENCRYPTION_WITH_FOOTER_KEY(const EncryptionWithFooterKey& val);

  void __set_ENCRYPTION_WITH_COLUMN_KEY(const EncryptionWithColumnKey& val);

  bool operator == (const ColumnCryptoMetaData & rhs) const
  {
    if (__isset.ENCRYPTION_WITH_FOOTER_KEY != rhs.__isset.ENCRYPTION_WITH_FOOTER_KEY)
      return false;
    else if (__isset.ENCRYPTION_WITH_FOOTER_KEY && !(ENCRYPTION_WITH_FOOTER_KEY == rhs.ENCRYPTION_WITH_FOOTER_KEY))
      return false;
    if (__isset.ENCRYPTION_WITH_COLUMN_KEY != rhs.__isset.ENCRYPTION_WITH_COLUMN_KEY)
      return false;
    else if (__isset.ENCRYPTION_WITH_COLUMN_KEY && !(ENCRYPTION_WITH_COLUMN_KEY == rhs.ENCRYPTION_WITH_COLUMN_KEY))
      return false;
    return true;
  }
  bool operator != (const ColumnCryptoMetaData &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const ColumnCryptoMetaData & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnCryptoMetaData &a, ColumnCryptoMetaData &b);

std::ostream& operator<<(std::ostream& out, const ColumnCryptoMetaData& obj);

typedef struct _ColumnChunk__isset {
  _ColumnChunk__isset() : file_path(false), meta_data(false), offset_index_offset(false), offset_index_length(false), column_index_offset(false), column_index_length(false), crypto_metadata(false), encrypted_column_metadata(false) {}
  bool file_path :1;
  bool meta_data :1;
  bool offset_index_offset :1;
  bool offset_index_length :1;
  bool column_index_offset :1;
  bool column_index_length :1;
  bool crypto_metadata :1;
  bool encrypted_column_metadata :1;
} _ColumnChunk__isset;

class ColumnChunk : public virtual ::duckdb_apache::thrift::TBase {
 public:

  ColumnChunk(const ColumnChunk&);
  ColumnChunk& operator=(const ColumnChunk&);
  ColumnChunk() : file_path(), file_offset(0), offset_index_offset(0), offset_index_length(0), column_index_offset(0), column_index_length(0), encrypted_column_metadata() {
  }

  virtual ~ColumnChunk() throw();
  std::string file_path;
  int64_t file_offset;
  ColumnMetaData meta_data;
  int64_t offset_index_offset;
  int32_t offset_index_length;
  int64_t column_index_offset;
  int32_t column_index_length;
  ColumnCryptoMetaData crypto_metadata;
  std::string encrypted_column_metadata;

  _ColumnChunk__isset __isset;

  void __set_file_path(const std::string& val);

  void __set_file_offset(const int64_t val);

  void __set_meta_data(const ColumnMetaData& val);

  void __set_offset_index_offset(const int64_t val);

  void __set_offset_index_length(const int32_t val);

  void __set_column_index_offset(const int64_t val);

  void __set_column_index_length(const int32_t val);

  void __set_crypto_metadata(const ColumnCryptoMetaData& val);

  void __set_encrypted_column_metadata(const std::string& val);

  bool operator == (const ColumnChunk & rhs) const
  {
    if (__isset.file_path != rhs.__isset.file_path)
      return false;
    else if (__isset.file_path && !(file_path == rhs.file_path))
      return false;
    if (!(file_offset == rhs.file_offset))
      return false;
    if (__isset.meta_data != rhs.__isset.meta_data)
      return false;
    else if (__isset.meta_data && !(meta_data == rhs.meta_data))
      return false;
    if (__isset.offset_index_offset != rhs.__isset.offset_index_offset)
      return false;
    else if (__isset.offset_index_offset && !(offset_index_offset == rhs.offset_index_offset))
      return false;
    if (__isset.offset_index_length != rhs.__isset.offset_index_length)
      return false;
    else if (__isset.offset_index_length && !(offset_index_length == rhs.offset_index_length))
      return false;
    if (__isset.column_index_offset != rhs.__isset.column_index_offset)
      return false;
    else if (__isset.column_index_offset && !(column_index_offset == rhs.column_index_offset))
      return false;
    if (__isset.column_index_length != rhs.__isset.column_index_length)
      return false;
    else if (__isset.column_index_length && !(column_index_length == rhs.column_index_length))
      return false;
    if (__isset.crypto_metadata != rhs.__isset.crypto_metadata)
      return false;
    else if (__isset.crypto_metadata && !(crypto_metadata == rhs.crypto_metadata))
      return false;
    if (__isset.encrypted_column_metadata != rhs.__isset.encrypted_column_metadata)
      return false;
    else if (__isset.encrypted_column_metadata && !(encrypted_column_metadata == rhs.encrypted_column_metadata))
      return false;
    return true;
  }
  bool operator != (const ColumnChunk &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const ColumnChunk & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnChunk &a, ColumnChunk &b);

std::ostream& operator<<(std::ostream& out, const ColumnChunk& obj);

typedef struct _RowGroup__isset {
  _RowGroup__isset() : sorting_columns(false), file_offset(false), total_compressed_size(false), ordinal(false) {}
  bool sorting_columns :1;
  bool file_offset :1;
  bool total_compressed_size :1;
  bool ordinal :1;
} _RowGroup__isset;

class RowGroup : public virtual ::duckdb_apache::thrift::TBase {
 public:

  RowGroup(const RowGroup&);
  RowGroup& operator=(const RowGroup&);
  RowGroup() : total_byte_size(0), num_rows(0), file_offset(0), total_compressed_size(0), ordinal(0) {
  }

  virtual ~RowGroup() throw();
  std::vector<ColumnChunk>  columns;
  int64_t total_byte_size;
  int64_t num_rows;
  std::vector<SortingColumn>  sorting_columns;
  int64_t file_offset;
  int64_t total_compressed_size;
  int16_t ordinal;

  _RowGroup__isset __isset;

  void __set_columns(const std::vector<ColumnChunk> & val);

  void __set_total_byte_size(const int64_t val);

  void __set_num_rows(const int64_t val);

  void __set_sorting_columns(const std::vector<SortingColumn> & val);

  void __set_file_offset(const int64_t val);

  void __set_total_compressed_size(const int64_t val);

  void __set_ordinal(const int16_t val);

  bool operator == (const RowGroup & rhs) const
  {
    if (!(columns == rhs.columns))
      return false;
    if (!(total_byte_size == rhs.total_byte_size))
      return false;
    if (!(num_rows == rhs.num_rows))
      return false;
    if (__isset.sorting_columns != rhs.__isset.sorting_columns)
      return false;
    else if (__isset.sorting_columns && !(sorting_columns == rhs.sorting_columns))
      return false;
    if (__isset.file_offset != rhs.__isset.file_offset)
      return false;
    else if (__isset.file_offset && !(file_offset == rhs.file_offset))
      return false;
    if (__isset.total_compressed_size != rhs.__isset.total_compressed_size)
      return false;
    else if (__isset.total_compressed_size && !(total_compressed_size == rhs.total_compressed_size))
      return false;
    if (__isset.ordinal != rhs.__isset.ordinal)
      return false;
    else if (__isset.ordinal && !(ordinal == rhs.ordinal))
      return false;
    return true;
  }
  bool operator != (const RowGroup &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const RowGroup & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(RowGroup &a, RowGroup &b);

std::ostream& operator<<(std::ostream& out, const RowGroup& obj);


class TypeDefinedOrder : public virtual ::duckdb_apache::thrift::TBase {
 public:

  TypeDefinedOrder(const TypeDefinedOrder&);
  TypeDefinedOrder& operator=(const TypeDefinedOrder&);
  TypeDefinedOrder() {
  }

  virtual ~TypeDefinedOrder() throw();

  bool operator == (const TypeDefinedOrder & /* rhs */) const
  {
    return true;
  }
  bool operator != (const TypeDefinedOrder &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const TypeDefinedOrder & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(TypeDefinedOrder &a, TypeDefinedOrder &b);

std::ostream& operator<<(std::ostream& out, const TypeDefinedOrder& obj);

typedef struct _ColumnOrder__isset {
  _ColumnOrder__isset() : TYPE_ORDER(false) {}
  bool TYPE_ORDER :1;
} _ColumnOrder__isset;

class ColumnOrder : public virtual ::duckdb_apache::thrift::TBase {
 public:

  ColumnOrder(const ColumnOrder&);
  ColumnOrder& operator=(const ColumnOrder&);
  ColumnOrder() {
  }

  virtual ~ColumnOrder() throw();
  TypeDefinedOrder TYPE_ORDER;

  _ColumnOrder__isset __isset;

  void __set_TYPE_ORDER(const TypeDefinedOrder& val);

  bool operator == (const ColumnOrder & rhs) const
  {
    if (__isset.TYPE_ORDER != rhs.__isset.TYPE_ORDER)
      return false;
    else if (__isset.TYPE_ORDER && !(TYPE_ORDER == rhs.TYPE_ORDER))
      return false;
    return true;
  }
  bool operator != (const ColumnOrder &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const ColumnOrder & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnOrder &a, ColumnOrder &b);

std::ostream& operator<<(std::ostream& out, const ColumnOrder& obj);


class PageLocation : public virtual ::duckdb_apache::thrift::TBase {
 public:

  PageLocation(const PageLocation&);
  PageLocation& operator=(const PageLocation&);
  PageLocation() : offset(0), compressed_page_size(0), first_row_index(0) {
  }

  virtual ~PageLocation() throw();
  int64_t offset;
  int32_t compressed_page_size;
  int64_t first_row_index;

  void __set_offset(const int64_t val);

  void __set_compressed_page_size(const int32_t val);

  void __set_first_row_index(const int64_t val);

  bool operator == (const PageLocation & rhs) const
  {
    if (!(offset == rhs.offset))
      return false;
    if (!(compressed_page_size == rhs.compressed_page_size))
      return false;
    if (!(first_row_index == rhs.first_row_index))
      return false;
    return true;
  }
  bool operator != (const PageLocation &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const PageLocation & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(PageLocation &a, PageLocation &b);

std::ostream& operator<<(std::ostream& out, const PageLocation& obj);


class OffsetIndex : public virtual ::duckdb_apache::thrift::TBase {
 public:

  OffsetIndex(const OffsetIndex&);
  OffsetIndex& operator=(const OffsetIndex&);
  OffsetIndex() {
  }

  virtual ~OffsetIndex() throw();
  std::vector<PageLocation>  page_locations;

  void __set_page_locations(const std::vector<PageLocation> & val);

  bool operator == (const OffsetIndex & rhs) const
  {
    if (!(page_locations == rhs.page_locations))
      return false;
    return true;
  }
  bool operator != (const OffsetIndex &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const OffsetIndex & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(OffsetIndex &a, OffsetIndex &b);

std::ostream& operator<<(std::ostream& out, const OffsetIndex& obj);

typedef struct _ColumnIndex__isset {
  _ColumnIndex__isset() : null_counts(false) {}
  bool null_counts :1;
} _ColumnIndex__isset;

class ColumnIndex : public virtual ::duckdb_apache::thrift::TBase {
 public:

  ColumnIndex(const ColumnIndex&);
  ColumnIndex& operator=(const ColumnIndex&);
  ColumnIndex() : boundary_order((BoundaryOrder::type)0) {
  }

  virtual ~ColumnIndex() throw();
  std::vector<bool>  null_pages;
  std::vector<std::string>  min_values;
  std::vector<std::string>  max_values;
  BoundaryOrder::type boundary_order;
  std::vector<int64_t>  null_counts;

  _ColumnIndex__isset __isset;

  void __set_null_pages(const std::vector<bool> & val);

  void __set_min_values(const std::vector<std::string> & val);

  void __set_max_values(const std::vector<std::string> & val);

  void __set_boundary_order(const BoundaryOrder::type val);

  void __set_null_counts(const std::vector<int64_t> & val);

  bool operator == (const ColumnIndex & rhs) const
  {
    if (!(null_pages == rhs.null_pages))
      return false;
    if (!(min_values == rhs.min_values))
      return false;
    if (!(max_values == rhs.max_values))
      return false;
    if (!(boundary_order == rhs.boundary_order))
      return false;
    if (__isset.null_counts != rhs.__isset.null_counts)
      return false;
    else if (__isset.null_counts && !(null_counts == rhs.null_counts))
      return false;
    return true;
  }
  bool operator != (const ColumnIndex &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const ColumnIndex & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(ColumnIndex &a, ColumnIndex &b);

std::ostream& operator<<(std::ostream& out, const ColumnIndex& obj);

typedef struct _AesGcmV1__isset {
  _AesGcmV1__isset() : aad_prefix(false), aad_file_unique(false), supply_aad_prefix(false) {}
  bool aad_prefix :1;
  bool aad_file_unique :1;
  bool supply_aad_prefix :1;
} _AesGcmV1__isset;

class AesGcmV1 : public virtual ::duckdb_apache::thrift::TBase {
 public:

  AesGcmV1(const AesGcmV1&);
  AesGcmV1& operator=(const AesGcmV1&);
  AesGcmV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) {
  }

  virtual ~AesGcmV1() throw();
  std::string aad_prefix;
  std::string aad_file_unique;
  bool supply_aad_prefix;

  _AesGcmV1__isset __isset;

  void __set_aad_prefix(const std::string& val);

  void __set_aad_file_unique(const std::string& val);

  void __set_supply_aad_prefix(const bool val);

  bool operator == (const AesGcmV1 & rhs) const
  {
    if (__isset.aad_prefix != rhs.__isset.aad_prefix)
      return false;
    else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix))
      return false;
    if (__isset.aad_file_unique != rhs.__isset.aad_file_unique)
      return false;
    else if (__isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique))
      return false;
    if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix)
      return false;
    else if (__isset.supply_aad_prefix && !(supply_aad_prefix == rhs.supply_aad_prefix))
      return false;
    return true;
  }
  bool operator != (const AesGcmV1 &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const AesGcmV1 & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(AesGcmV1 &a, AesGcmV1 &b);

std::ostream& operator<<(std::ostream& out, const AesGcmV1& obj);

typedef struct _AesGcmCtrV1__isset {
  _AesGcmCtrV1__isset() : aad_prefix(false), aad_file_unique(false), supply_aad_prefix(false) {}
  bool aad_prefix :1;
  bool aad_file_unique :1;
  bool supply_aad_prefix :1;
} _AesGcmCtrV1__isset;

class AesGcmCtrV1 : public virtual ::duckdb_apache::thrift::TBase {
 public:

  AesGcmCtrV1(const AesGcmCtrV1&);
  AesGcmCtrV1& operator=(const AesGcmCtrV1&);
  AesGcmCtrV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) {
  }

  virtual ~AesGcmCtrV1() throw();
  std::string aad_prefix;
  std::string aad_file_unique;
  bool supply_aad_prefix;

  _AesGcmCtrV1__isset __isset;

  void __set_aad_prefix(const std::string& val);

  void __set_aad_file_unique(const std::string& val);

  void __set_supply_aad_prefix(const bool val);

  bool operator == (const AesGcmCtrV1 & rhs) const
  {
    if (__isset.aad_prefix != rhs.__isset.aad_prefix)
      return false;
    else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix))
      return false;
    if (__isset.aad_file_unique != rhs.__isset.aad_file_unique)
      return false;
    else if (__isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique))
      return false;
    if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix)
      return false;
    else if (__isset.supply_aad_prefix && !(supply_aad_prefix == rhs.supply_aad_prefix))
      return false;
    return true;
  }
  bool operator != (const AesGcmCtrV1 &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const AesGcmCtrV1 & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(AesGcmCtrV1 &a, AesGcmCtrV1 &b);

std::ostream& operator<<(std::ostream& out, const AesGcmCtrV1& obj);

typedef struct _EncryptionAlgorithm__isset {
  _EncryptionAlgorithm__isset() : AES_GCM_V1(false), AES_GCM_CTR_V1(false) {}
  bool AES_GCM_V1 :1;
  bool AES_GCM_CTR_V1 :1;
} _EncryptionAlgorithm__isset;

class EncryptionAlgorithm : public virtual ::duckdb_apache::thrift::TBase {
 public:

  EncryptionAlgorithm(const EncryptionAlgorithm&);
  EncryptionAlgorithm& operator=(const EncryptionAlgorithm&);
  EncryptionAlgorithm() {
  }

  virtual ~EncryptionAlgorithm() throw();
  AesGcmV1 AES_GCM_V1;
  AesGcmCtrV1 AES_GCM_CTR_V1;

  _EncryptionAlgorithm__isset __isset;

  void __set_AES_GCM_V1(const AesGcmV1& val);

  void __set_AES_GCM_CTR_V1(const AesGcmCtrV1& val);

  bool operator == (const EncryptionAlgorithm & rhs) const
  {
    if (__isset.AES_GCM_V1 != rhs.__isset.AES_GCM_V1)
      return false;
    else if (__isset.AES_GCM_V1 && !(AES_GCM_V1 == rhs.AES_GCM_V1))
      return false;
    if (__isset.AES_GCM_CTR_V1 != rhs.__isset.AES_GCM_CTR_V1)
      return false;
    else if (__isset.AES_GCM_CTR_V1 && !(AES_GCM_CTR_V1 == rhs.AES_GCM_CTR_V1))
      return false;
    return true;
  }
  bool operator != (const EncryptionAlgorithm &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const EncryptionAlgorithm & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(EncryptionAlgorithm &a, EncryptionAlgorithm &b);

std::ostream& operator<<(std::ostream& out, const EncryptionAlgorithm& obj);

typedef struct _FileMetaData__isset {
  _FileMetaData__isset() : key_value_metadata(false), created_by(false), column_orders(false), encryption_algorithm(false), footer_signing_key_metadata(false) {}
  bool key_value_metadata :1;
  bool created_by :1;
  bool column_orders :1;
  bool encryption_algorithm :1;
  bool footer_signing_key_metadata :1;
} _FileMetaData__isset;

class FileMetaData : public virtual ::duckdb_apache::thrift::TBase {
 public:

  FileMetaData(const FileMetaData&);
  FileMetaData& operator=(const FileMetaData&);
  FileMetaData() : version(0), num_rows(0), created_by(), footer_signing_key_metadata() {
  }

  virtual ~FileMetaData() throw();
  int32_t version;
  std::vector<SchemaElement>  schema;
  int64_t num_rows;
  std::vector<RowGroup>  row_groups;
  std::vector<KeyValue>  key_value_metadata;
  std::string created_by;
  std::vector<ColumnOrder>  column_orders;
  EncryptionAlgorithm encryption_algorithm;
  std::string footer_signing_key_metadata;

  _FileMetaData__isset __isset;

  void __set_version(const int32_t val);

  void __set_schema(const std::vector<SchemaElement> & val);

  void __set_num_rows(const int64_t val);

  void __set_row_groups(const std::vector<RowGroup> & val);

  void __set_key_value_metadata(const std::vector<KeyValue> & val);

  void __set_created_by(const std::string& val);

  void __set_column_orders(const std::vector<ColumnOrder> & val);

  void __set_encryption_algorithm(const EncryptionAlgorithm& val);

  void __set_footer_signing_key_metadata(const std::string& val);

  bool operator == (const FileMetaData & rhs) const
  {
    if (!(version == rhs.version))
      return false;
    if (!(schema == rhs.schema))
      return false;
    if (!(num_rows == rhs.num_rows))
      return false;
    if (!(row_groups == rhs.row_groups))
      return false;
    if (__isset.key_value_metadata != rhs.__isset.key_value_metadata)
      return false;
    else if (__isset.key_value_metadata && !(key_value_metadata == rhs.key_value_metadata))
      return false;
    if (__isset.created_by != rhs.__isset.created_by)
      return false;
    else if (__isset.created_by && !(created_by == rhs.created_by))
      return false;
    if (__isset.column_orders != rhs.__isset.column_orders)
      return false;
    else if (__isset.column_orders && !(column_orders == rhs.column_orders))
      return false;
    if (__isset.encryption_algorithm != rhs.__isset.encryption_algorithm)
      return false;
    else if (__isset.encryption_algorithm && !(encryption_algorithm == rhs.encryption_algorithm))
      return false;
    if (__isset.footer_signing_key_metadata != rhs.__isset.footer_signing_key_metadata)
      return false;
    else if (__isset.footer_signing_key_metadata && !(footer_signing_key_metadata == rhs.footer_signing_key_metadata))
      return false;
    return true;
  }
  bool operator != (const FileMetaData &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const FileMetaData & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(FileMetaData &a, FileMetaData &b);

std::ostream& operator<<(std::ostream& out, const FileMetaData& obj);

typedef struct _FileCryptoMetaData__isset {
  _FileCryptoMetaData__isset() : key_metadata(false) {}
  bool key_metadata :1;
} _FileCryptoMetaData__isset;

class FileCryptoMetaData : public virtual ::duckdb_apache::thrift::TBase {
 public:

  FileCryptoMetaData(const FileCryptoMetaData&);
  FileCryptoMetaData& operator=(const FileCryptoMetaData&);
  FileCryptoMetaData() : key_metadata() {
  }

  virtual ~FileCryptoMetaData() throw();
  EncryptionAlgorithm encryption_algorithm;
  std::string key_metadata;

  _FileCryptoMetaData__isset __isset;

  void __set_encryption_algorithm(const EncryptionAlgorithm& val);

  void __set_key_metadata(const std::string& val);

  bool operator == (const FileCryptoMetaData & rhs) const
  {
    if (!(encryption_algorithm == rhs.encryption_algorithm))
      return false;
    if (__isset.key_metadata != rhs.__isset.key_metadata)
      return false;
    else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata))
      return false;
    return true;
  }
  bool operator != (const FileCryptoMetaData &rhs) const {
    return !(*this == rhs);
  }

  bool operator < (const FileCryptoMetaData & ) const;

  uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot);
  uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const;

  virtual void printTo(std::ostream& out) const;
};

void swap(FileCryptoMetaData &a, FileCryptoMetaData &b);

std::ostream& operator<<(std::ostream& out, const FileCryptoMetaData& obj);

}} // namespace

#endif


// LICENSE_CHANGE_END


#include <list>


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_PROTOCOL_TCOMPACTPROTOCOL_H_
#define _DUCKDB_THRIFT_PROTOCOL_TCOMPACTPROTOCOL_H_ 1



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_
#define _DUCKDB_THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ 1



namespace duckdb_apache {
namespace thrift {
namespace protocol {

using duckdb_apache::thrift::transport::TTransport;

/**
 * Helper class that provides default implementations of TProtocol methods.
 *
 * This class provides default implementations of the non-virtual TProtocol
 * methods.  It exists primarily so TVirtualProtocol can derive from it.  It
 * prevents TVirtualProtocol methods from causing infinite recursion if the
 * non-virtual methods are not overridden by the TVirtualProtocol subclass.
 *
 * You probably don't want to use this class directly.  Use TVirtualProtocol
 * instead.
 */
class TProtocolDefaults : public TProtocol {
public:
  uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) {
    (void)name;
    (void)messageType;
    (void)seqid;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readMessageEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readStructBegin(std::string& name) {
    (void)name;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readStructEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
    (void)name;
    (void)fieldType;
    (void)fieldId;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readFieldEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
    (void)keyType;
    (void)valType;
    (void)size;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readMapEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readListBegin(TType& elemType, uint32_t& size) {
    (void)elemType;
    (void)size;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readListEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readSetBegin(TType& elemType, uint32_t& size) {
    (void)elemType;
    (void)size;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readSetEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readBool(bool& value) {
    (void)value;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readBool(std::vector<bool>::reference value) {
    (void)value;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readByte(int8_t& byte) {
    (void)byte;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readI16(int16_t& i16) {
    (void)i16;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readI32(int32_t& i32) {
    (void)i32;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readI64(int64_t& i64) {
    (void)i64;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readDouble(double& dub) {
    (void)dub;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readString(std::string& str) {
    (void)str;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t readBinary(std::string& str) {
    (void)str;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support reading (yet).");
  }

  uint32_t writeMessageBegin(const std::string& name,
                             const TMessageType messageType,
                             const int32_t seqid) {
    (void)name;
    (void)messageType;
    (void)seqid;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeMessageEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeStructBegin(const char* name) {
    (void)name;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeStructEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId) {
    (void)name;
    (void)fieldType;
    (void)fieldId;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeFieldEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeFieldStop() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size) {
    (void)keyType;
    (void)valType;
    (void)size;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeMapEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeListBegin(const TType elemType, const uint32_t size) {
    (void)elemType;
    (void)size;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeListEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeSetBegin(const TType elemType, const uint32_t size) {
    (void)elemType;
    (void)size;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeSetEnd() {
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeBool(const bool value) {
    (void)value;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeByte(const int8_t byte) {
    (void)byte;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeI16(const int16_t i16) {
    (void)i16;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeI32(const int32_t i32) {
    (void)i32;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeI64(const int64_t i64) {
    (void)i64;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeDouble(const double dub) {
    (void)dub;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeString(const std::string& str) {
    (void)str;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t writeBinary(const std::string& str) {
    (void)str;
    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                             "this protocol does not support writing (yet).");
  }

  uint32_t skip(TType type) { return ::duckdb_apache::thrift::protocol::skip(*this, type); }

protected:
  TProtocolDefaults(std::shared_ptr<TTransport> ptrans) : TProtocol(ptrans) {}
};

/**
 * Concrete TProtocol classes should inherit from TVirtualProtocol
 * so they don't have to manually override virtual methods.
 */
template <class Protocol_, class Super_ = TProtocolDefaults>
class TVirtualProtocol : public Super_ {
public:
  /**
   * Writing functions.
   */

  uint32_t writeMessageBegin_virt(const std::string& name,
                                          const TMessageType messageType,
                                          const int32_t seqid) override {
    return static_cast<Protocol_*>(this)->writeMessageBegin(name, messageType, seqid);
  }

  uint32_t writeMessageEnd_virt() override {
    return static_cast<Protocol_*>(this)->writeMessageEnd();
  }

  uint32_t writeStructBegin_virt(const char* name) override {
    return static_cast<Protocol_*>(this)->writeStructBegin(name);
  }

  uint32_t writeStructEnd_virt() override { return static_cast<Protocol_*>(this)->writeStructEnd(); }

  uint32_t writeFieldBegin_virt(const char* name,
                                        const TType fieldType,
                                        const int16_t fieldId) override {
    return static_cast<Protocol_*>(this)->writeFieldBegin(name, fieldType, fieldId);
  }

  uint32_t writeFieldEnd_virt() override { return static_cast<Protocol_*>(this)->writeFieldEnd(); }

  uint32_t writeFieldStop_virt() override { return static_cast<Protocol_*>(this)->writeFieldStop(); }

  uint32_t writeMapBegin_virt(const TType keyType,
                                      const TType valType,
                                      const uint32_t size) override {
    return static_cast<Protocol_*>(this)->writeMapBegin(keyType, valType, size);
  }

  uint32_t writeMapEnd_virt() override { return static_cast<Protocol_*>(this)->writeMapEnd(); }

  uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) override {
    return static_cast<Protocol_*>(this)->writeListBegin(elemType, size);
  }

  uint32_t writeListEnd_virt() override { return static_cast<Protocol_*>(this)->writeListEnd(); }

  uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) override {
    return static_cast<Protocol_*>(this)->writeSetBegin(elemType, size);
  }

  uint32_t writeSetEnd_virt() override { return static_cast<Protocol_*>(this)->writeSetEnd(); }

  uint32_t writeBool_virt(const bool value) override {
    return static_cast<Protocol_*>(this)->writeBool(value);
  }

  uint32_t writeByte_virt(const int8_t byte) override {
    return static_cast<Protocol_*>(this)->writeByte(byte);
  }

  uint32_t writeI16_virt(const int16_t i16) override {
    return static_cast<Protocol_*>(this)->writeI16(i16);
  }

  uint32_t writeI32_virt(const int32_t i32) override {
    return static_cast<Protocol_*>(this)->writeI32(i32);
  }

  uint32_t writeI64_virt(const int64_t i64) override {
    return static_cast<Protocol_*>(this)->writeI64(i64);
  }

  uint32_t writeDouble_virt(const double dub) override {
    return static_cast<Protocol_*>(this)->writeDouble(dub);
  }

  uint32_t writeString_virt(const std::string& str) override {
    return static_cast<Protocol_*>(this)->writeString(str);
  }

  uint32_t writeBinary_virt(const std::string& str) override {
    return static_cast<Protocol_*>(this)->writeBinary(str);
  }

  /**
   * Reading functions
   */

  uint32_t readMessageBegin_virt(std::string& name,
                                         TMessageType& messageType,
                                         int32_t& seqid) override {
    return static_cast<Protocol_*>(this)->readMessageBegin(name, messageType, seqid);
  }

  uint32_t readMessageEnd_virt() override { return static_cast<Protocol_*>(this)->readMessageEnd(); }

  uint32_t readStructBegin_virt(std::string& name) override {
    return static_cast<Protocol_*>(this)->readStructBegin(name);
  }

  uint32_t readStructEnd_virt() override { return static_cast<Protocol_*>(this)->readStructEnd(); }

  uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) override {
    return static_cast<Protocol_*>(this)->readFieldBegin(name, fieldType, fieldId);
  }

  uint32_t readFieldEnd_virt() override { return static_cast<Protocol_*>(this)->readFieldEnd(); }

  uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) override {
    return static_cast<Protocol_*>(this)->readMapBegin(keyType, valType, size);
  }

  uint32_t readMapEnd_virt() override { return static_cast<Protocol_*>(this)->readMapEnd(); }

  uint32_t readListBegin_virt(TType& elemType, uint32_t& size) override {
    return static_cast<Protocol_*>(this)->readListBegin(elemType, size);
  }

  uint32_t readListEnd_virt() override { return static_cast<Protocol_*>(this)->readListEnd(); }

  uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) override {
    return static_cast<Protocol_*>(this)->readSetBegin(elemType, size);
  }

  uint32_t readSetEnd_virt() override { return static_cast<Protocol_*>(this)->readSetEnd(); }

  uint32_t readBool_virt(bool& value) override {
    return static_cast<Protocol_*>(this)->readBool(value);
  }

  uint32_t readBool_virt(std::vector<bool>::reference value) override {
    return static_cast<Protocol_*>(this)->readBool(value);
  }

  uint32_t readByte_virt(int8_t& byte) override {
    return static_cast<Protocol_*>(this)->readByte(byte);
  }

  uint32_t readI16_virt(int16_t& i16) override {
    return static_cast<Protocol_*>(this)->readI16(i16);
  }

  uint32_t readI32_virt(int32_t& i32) override {
    return static_cast<Protocol_*>(this)->readI32(i32);
  }

  uint32_t readI64_virt(int64_t& i64) override {
    return static_cast<Protocol_*>(this)->readI64(i64);
  }

  uint32_t readDouble_virt(double& dub) override {
    return static_cast<Protocol_*>(this)->readDouble(dub);
  }

  uint32_t readString_virt(std::string& str) override {
    return static_cast<Protocol_*>(this)->readString(str);
  }

  uint32_t readBinary_virt(std::string& str) override {
    return static_cast<Protocol_*>(this)->readBinary(str);
  }

  uint32_t skip_virt(TType type) override { return static_cast<Protocol_*>(this)->skip(type); }

  /*
   * Provide a default skip() implementation that uses non-virtual read
   * methods.
   *
   * Note: subclasses that use TVirtualProtocol to derive from another protocol
   * implementation (i.e., not TProtocolDefaults) should beware that this may
   * override any non-default skip() implementation provided by the parent
   * transport class.  They may need to explicitly redefine skip() to call the
   * correct parent implementation, if desired.
   */
  uint32_t skip(TType type) {
    auto* const prot = static_cast<Protocol_*>(this);
    return ::duckdb_apache::thrift::protocol::skip(*prot, type);
  }

  /*
   * Provide a default readBool() implementation for use with
   * std::vector<bool>, that behaves the same as reading into a normal bool.
   *
   * Subclasses can override this if desired, but there normally shouldn't
   * be a need to.
   */
  uint32_t readBool(std::vector<bool>::reference value) {
    bool b = false;
    uint32_t ret = static_cast<Protocol_*>(this)->readBool(b);
    value = b;
    return ret;
  }
  using Super_::readBool; // so we don't hide readBool(bool&)

protected:
  TVirtualProtocol(std::shared_ptr<TTransport> ptrans) : Super_(ptrans) {}
};
}
}
} // duckdb_apache::thrift::protocol

#endif // #define _DUCKDB_THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ 1


// LICENSE_CHANGE_END


#include <stack>
#include <memory>

namespace duckdb_apache {
namespace thrift {
namespace protocol {

/**
 * C++ Implementation of the Compact Protocol as described in THRIFT-110
 */
template <class Transport_>
class TCompactProtocolT : public TVirtualProtocol<TCompactProtocolT<Transport_> > {
public:
  static const int8_t PROTOCOL_ID = (int8_t)0x82u;
  static const int8_t VERSION_N = 1;
  static const int8_t VERSION_MASK = 0x1f;       // 0001 1111

protected:
  static const int8_t TYPE_MASK = (int8_t)0xE0u; // 1110 0000
  static const int8_t TYPE_BITS = 0x07;          // 0000 0111
  static const int32_t TYPE_SHIFT_AMOUNT = 5;

  Transport_* trans_;

  /**
   * (Writing) If we encounter a boolean field begin, save the TField here
   * so it can have the value incorporated.
   */
  struct {
    const char* name;
    TType fieldType;
    int16_t fieldId;
  } booleanField_;

  /**
   * (Reading) If we read a field header, and it's a boolean field, save
   * the boolean value here so that readBool can use it.
   */
  struct {
    bool hasBoolValue;
    bool boolValue;
  } boolValue_;

  /**
   * Used to keep track of the last field for the current and previous structs,
   * so we can do the delta stuff.
   */

  std::stack<int16_t> lastField_;
  int16_t lastFieldId_;

public:
  TCompactProtocolT(std::shared_ptr<Transport_> trans)
    : TVirtualProtocol<TCompactProtocolT<Transport_> >(trans),
      trans_(trans.get()),
      lastFieldId_(0),
      string_limit_(0),
      string_buf_(nullptr),
      string_buf_size_(0),
      container_limit_(0) {
    booleanField_.name = nullptr;
    boolValue_.hasBoolValue = false;
  }

  TCompactProtocolT(std::shared_ptr<Transport_> trans,
                    int32_t string_limit,
                    int32_t container_limit)
    : TVirtualProtocol<TCompactProtocolT<Transport_> >(trans),
      trans_(trans.get()),
      lastFieldId_(0),
      string_limit_(string_limit),
      string_buf_(nullptr),
      string_buf_size_(0),
      container_limit_(container_limit) {
    booleanField_.name = nullptr;
    boolValue_.hasBoolValue = false;
  }

  ~TCompactProtocolT() override { free(string_buf_); }

  /**
   * Writing functions
   */

  virtual uint32_t writeMessageBegin(const std::string& name,
                                     const TMessageType messageType,
                                     const int32_t seqid);

  uint32_t writeStructBegin(const char* name);

  uint32_t writeStructEnd();

  uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);

  uint32_t writeFieldStop();

  uint32_t writeListBegin(const TType elemType, const uint32_t size);

  uint32_t writeSetBegin(const TType elemType, const uint32_t size);

  virtual uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);

  uint32_t writeBool(const bool value);

  uint32_t writeByte(const int8_t byte);

  uint32_t writeI16(const int16_t i16);

  uint32_t writeI32(const int32_t i32);

  uint32_t writeI64(const int64_t i64);

  uint32_t writeDouble(const double dub);

  uint32_t writeString(const std::string& str);

  uint32_t writeBinary(const std::string& str);

  /**
  * These methods are called by structs, but don't actually have any wired
  * output or purpose
  */
  virtual uint32_t writeMessageEnd() { return 0; }
  uint32_t writeMapEnd() { return 0; }
  uint32_t writeListEnd() { return 0; }
  uint32_t writeSetEnd() { return 0; }
  uint32_t writeFieldEnd() { return 0; }

protected:
  int32_t writeFieldBeginInternal(const char* name,
                                  const TType fieldType,
                                  const int16_t fieldId,
                                  int8_t typeOverride);
  uint32_t writeCollectionBegin(const TType elemType, int32_t size);
  uint32_t writeVarint32(uint32_t n);
  uint32_t writeVarint64(uint64_t n);
  uint64_t i64ToZigzag(const int64_t l);
  uint32_t i32ToZigzag(const int32_t n);
  inline int8_t getCompactType(const TType ttype);

public:
  uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid);

  uint32_t readStructBegin(std::string& name);

  uint32_t readStructEnd();

  uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId);

  uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size);

  uint32_t readListBegin(TType& elemType, uint32_t& size);

  uint32_t readSetBegin(TType& elemType, uint32_t& size);

  uint32_t readBool(bool& value);
  // Provide the default readBool() implementation for std::vector<bool>
  using TVirtualProtocol<TCompactProtocolT<Transport_> >::readBool;

  uint32_t readByte(int8_t& byte);

  uint32_t readI16(int16_t& i16);

  uint32_t readI32(int32_t& i32);

  uint32_t readI64(int64_t& i64);

  uint32_t readDouble(double& dub);

  uint32_t readString(std::string& str);

  uint32_t readBinary(std::string& str);

  /*
   *These methods are here for the struct to call, but don't have any wire
   * encoding.
   */
  uint32_t readMessageEnd() { return 0; }
  uint32_t readFieldEnd() { return 0; }
  uint32_t readMapEnd() { return 0; }
  uint32_t readListEnd() { return 0; }
  uint32_t readSetEnd() { return 0; }

protected:
  uint32_t readVarint32(int32_t& i32);
  uint32_t readVarint64(int64_t& i64);
  int32_t zigzagToI32(uint32_t n);
  int64_t zigzagToI64(uint64_t n);
  TType getTType(int8_t type);

  // Buffer for reading strings, save for the lifetime of the protocol to
  // avoid memory churn allocating memory on every string read
  int32_t string_limit_;
  uint8_t* string_buf_;
  int32_t string_buf_size_;
  int32_t container_limit_;
};

typedef TCompactProtocolT<TTransport> TCompactProtocol;

/**
 * Constructs compact protocol handlers
 */
template <class Transport_>
class TCompactProtocolFactoryT : public TProtocolFactory {
public:
  TCompactProtocolFactoryT() : string_limit_(0), container_limit_(0) {}

  TCompactProtocolFactoryT(int32_t string_limit, int32_t container_limit)
    : string_limit_(string_limit), container_limit_(container_limit) {}

  ~TCompactProtocolFactoryT() override = default;

  void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }

  void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; }

  std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> trans) override {
    std::shared_ptr<Transport_> specific_trans = std::static_pointer_cast<Transport_>(trans);
    TProtocol* prot;
    if (specific_trans) {
      prot = new TCompactProtocolT<Transport_>(specific_trans, string_limit_, container_limit_);
    } else {
      prot = new TCompactProtocol(trans, string_limit_, container_limit_);
    }

    return std::shared_ptr<TProtocol>(prot);
  }

private:
  int32_t string_limit_;
  int32_t container_limit_;
};

typedef TCompactProtocolFactoryT<TTransport> TCompactProtocolFactory;
}
}
} // duckdb_apache::thrift::protocol



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
#ifndef _DUCKDB_THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_
#define _DUCKDB_THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_ 1

#include <limits>

/*
 * TCompactProtocol::i*ToZigzag depend on the fact that the right shift
 * operator on a signed integer is an arithmetic (sign-extending) shift.
 * If this is not the case, the current implementation will not work.
 * If anyone encounters this error, we can try to figure out the best
 * way to implement an arithmetic right shift on their platform.
 */
#if !defined(SIGNED_RIGHT_SHIFT_IS) || !defined(ARITHMETIC_RIGHT_SHIFT)
# error "Unable to determine the behavior of a signed right shift"
#endif
#if SIGNED_RIGHT_SHIFT_IS != ARITHMETIC_RIGHT_SHIFT
# error "TCompactProtocol currently only works if a signed right shift is arithmetic"
#endif

#ifndef UNLIKELY
#ifdef __GNUC__
#define UNLIKELY(val) (__builtin_expect((val), 0))
#else
#define UNLIKELY(val) (val)
#endif
#endif

namespace duckdb_apache { namespace thrift { namespace protocol {

namespace detail { namespace compact {

enum Types {
  CT_STOP           = 0x00,
  CT_BOOLEAN_TRUE   = 0x01,
  CT_BOOLEAN_FALSE  = 0x02,
  CT_BYTE           = 0x03,
  CT_I16            = 0x04,
  CT_I32            = 0x05,
  CT_I64            = 0x06,
  CT_DOUBLE         = 0x07,
  CT_BINARY         = 0x08,
  CT_LIST           = 0x09,
  CT_SET            = 0x0A,
  CT_MAP            = 0x0B,
  CT_STRUCT         = 0x0C
};

const int8_t TTypeToCType[16] = {
  CT_STOP, // T_STOP
  0, // unused
  CT_BOOLEAN_TRUE, // T_BOOL
  CT_BYTE, // T_BYTE
  CT_DOUBLE, // T_DOUBLE
  0, // unused
  CT_I16, // T_I16
  0, // unused
  CT_I32, // T_I32
  0, // unused
  CT_I64, // T_I64
  CT_BINARY, // T_STRING
  CT_STRUCT, // T_STRUCT
  CT_MAP, // T_MAP
  CT_SET, // T_SET
  CT_LIST, // T_LIST
};

}} // end detail::compact namespace


template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeMessageBegin(
    const std::string& name,
    const TMessageType messageType,
    const int32_t seqid) {
  uint32_t wsize = 0;
  wsize += writeByte(PROTOCOL_ID);
  wsize += writeByte((VERSION_N & VERSION_MASK) | (((int32_t)messageType << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
  wsize += writeVarint32(seqid);
  wsize += writeString(name);
  return wsize;
}

/**
 * Write a field header containing the field id and field type. If the
 * difference between the current field id and the last one is small (< 15),
 * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
 * field id will follow the type header as a zigzag varint.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeFieldBegin(const char* name,
                                                        const TType fieldType,
                                                        const int16_t fieldId) {
  if (fieldType == T_BOOL) {
    booleanField_.name = name;
    booleanField_.fieldType = fieldType;
    booleanField_.fieldId = fieldId;
  } else {
    return writeFieldBeginInternal(name, fieldType, fieldId, -1);
  }
  return 0;
}

/**
 * Write the STOP symbol so we know there are no more fields in this struct.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeFieldStop() {
  return writeByte(T_STOP);
}

/**
 * Write a struct begin. This doesn't actually put anything on the wire. We
 * use it as an opportunity to put special placeholder markers on the field
 * stack so we can get the field id deltas correct.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeStructBegin(const char* name) {
  (void) name;
  lastField_.push(lastFieldId_);
  lastFieldId_ = 0;
  return 0;
}

/**
 * Write a struct end. This doesn't actually put anything on the wire. We use
 * this as an opportunity to pop the last field from the current struct off
 * of the field stack.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeStructEnd() {
  lastFieldId_ = lastField_.top();
  lastField_.pop();
  return 0;
}

/**
 * Write a List header.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeListBegin(const TType elemType,
                                                       const uint32_t size) {
  return writeCollectionBegin(elemType, size);
}

/**
 * Write a set header.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeSetBegin(const TType elemType,
                                                      const uint32_t size) {
  return writeCollectionBegin(elemType, size);
}

/**
 * Write a map header. If the map is empty, omit the key and value type
 * headers, as we don't need any additional information to skip it.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeMapBegin(const TType keyType,
                                                      const TType valType,
                                                      const uint32_t size) {
  uint32_t wsize = 0;

  if (size == 0) {
    wsize += writeByte(0);
  } else {
    wsize += writeVarint32(size);
    wsize += writeByte(getCompactType(keyType) << 4 | getCompactType(valType));
  }
  return wsize;
}

/**
 * Write a boolean value. Potentially, this could be a boolean field, in
 * which case the field header info isn't written yet. If so, decide what the
 * right type header is for the value and then write the field header.
 * Otherwise, write a single byte.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeBool(const bool value) {
  uint32_t wsize = 0;

  if (booleanField_.name != NULL) {
    // we haven't written the field header yet
    wsize
      += writeFieldBeginInternal(booleanField_.name,
                                 booleanField_.fieldType,
                                 booleanField_.fieldId,
                                 static_cast<int8_t>(value
                                                     ? detail::compact::CT_BOOLEAN_TRUE
                                                     : detail::compact::CT_BOOLEAN_FALSE));
    booleanField_.name = NULL;
  } else {
    // we're not part of a field, so just write the value
    wsize
      += writeByte(static_cast<int8_t>(value
                                       ? detail::compact::CT_BOOLEAN_TRUE
                                       : detail::compact::CT_BOOLEAN_FALSE));
  }
  return wsize;
}

template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeByte(const int8_t byte) {
  trans_->write((uint8_t*)&byte, 1);
  return 1;
}

/**
 * Write an i16 as a zigzag varint.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeI16(const int16_t i16) {
  return writeVarint32(i32ToZigzag(i16));
}

/**
 * Write an i32 as a zigzag varint.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeI32(const int32_t i32) {
  return writeVarint32(i32ToZigzag(i32));
}

/**
 * Write an i64 as a zigzag varint.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeI64(const int64_t i64) {
  return writeVarint64(i64ToZigzag(i64));
}

/**
 * Write a double to the wire as 8 bytes.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeDouble(const double dub) {
  //BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
  //BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);

  uint64_t bits = bitwise_cast<uint64_t>(dub);
  bits = THRIFT_htolell(bits);
  trans_->write((uint8_t*)&bits, 8);
  return 8;
}

/**
 * Write a string to the wire with a varint size preceding.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeString(const std::string& str) {
  return writeBinary(str);
}

template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeBinary(const std::string& str) {
  if(str.size() > (std::numeric_limits<uint32_t>::max)())
    throw TProtocolException(TProtocolException::SIZE_LIMIT);
  uint32_t ssize = static_cast<uint32_t>(str.size());
  uint32_t wsize = writeVarint32(ssize) ;
  // checking ssize + wsize > uint_max, but we don't want to overflow while checking for overflows.
  // transforming the check to ssize > uint_max - wsize
  if(ssize > (std::numeric_limits<uint32_t>::max)() - wsize)
    throw TProtocolException(TProtocolException::SIZE_LIMIT);
  wsize += ssize;
  trans_->write((uint8_t*)str.data(), ssize);
  return wsize;
}

//
// Internal Writing methods
//

/**
 * The workhorse of writeFieldBegin. It has the option of doing a
 * 'type override' of the type header. This is used specifically in the
 * boolean field case.
 */
template <class Transport_>
int32_t TCompactProtocolT<Transport_>::writeFieldBeginInternal(
    const char* name,
    const TType fieldType,
    const int16_t fieldId,
    int8_t typeOverride) {
  (void) name;
  uint32_t wsize = 0;

  // if there's a type override, use that.
  int8_t typeToWrite = (typeOverride == -1 ? getCompactType(fieldType) : typeOverride);

  // check if we can use delta encoding for the field id
  if (fieldId > lastFieldId_ && fieldId - lastFieldId_ <= 15) {
    // write them together
    wsize += writeByte(static_cast<int8_t>((fieldId - lastFieldId_)
                                           << 4 | typeToWrite));
  } else {
    // write them separate
    wsize += writeByte(typeToWrite);
    wsize += writeI16(fieldId);
  }

  lastFieldId_ = fieldId;
  return wsize;
}

/**
 * Abstract method for writing the start of lists and sets. List and sets on
 * the wire differ only by the type indicator.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeCollectionBegin(const TType elemType,
                                                             int32_t size) {
  uint32_t wsize = 0;
  if (size <= 14) {
    wsize += writeByte(static_cast<int8_t>(size
                                           << 4 | getCompactType(elemType)));
  } else {
    wsize += writeByte(0xf0 | getCompactType(elemType));
    wsize += writeVarint32(size);
  }
  return wsize;
}

/**
 * Write an i32 as a varint. Results in 1-5 bytes on the wire.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeVarint32(uint32_t n) {
  uint8_t buf[5];
  uint32_t wsize = 0;

  while (true) {
    if ((n & ~0x7F) == 0) {
      buf[wsize++] = (int8_t)n;
      break;
    } else {
      buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
      n >>= 7;
    }
  }
  trans_->write(buf, wsize);
  return wsize;
}

/**
 * Write an i64 as a varint. Results in 1-10 bytes on the wire.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeVarint64(uint64_t n) {
  uint8_t buf[10];
  uint32_t wsize = 0;

  while (true) {
    if ((n & ~0x7FL) == 0) {
      buf[wsize++] = (int8_t)n;
      break;
    } else {
      buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
      n >>= 7;
    }
  }
  trans_->write(buf, wsize);
  return wsize;
}

/**
 * Convert l into a zigzag long. This allows negative numbers to be
 * represented compactly as a varint.
 */
template <class Transport_>
uint64_t TCompactProtocolT<Transport_>::i64ToZigzag(const int64_t l) {
  return (static_cast<uint64_t>(l) << 1) ^ (l >> 63);
}

/**
 * Convert n into a zigzag int. This allows negative numbers to be
 * represented compactly as a varint.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::i32ToZigzag(const int32_t n) {
  return (static_cast<uint32_t>(n) << 1) ^ (n >> 31);
}

/**
 * Given a TType value, find the appropriate detail::compact::Types value
 */
template <class Transport_>
int8_t TCompactProtocolT<Transport_>::getCompactType(const TType ttype) {
  return detail::compact::TTypeToCType[ttype];
}

//
// Reading Methods
//

/**
 * Read a message header.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readMessageBegin(
    std::string& name,
    TMessageType& messageType,
    int32_t& seqid) {
  uint32_t rsize = 0;
  int8_t protocolId;
  int8_t versionAndType;
  int8_t version;

  rsize += readByte(protocolId);
  if (protocolId != PROTOCOL_ID) {
    throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol identifier");
  }

  rsize += readByte(versionAndType);
  version = (int8_t)(versionAndType & VERSION_MASK);
  if (version != VERSION_N) {
    throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol version");
  }

  messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
  rsize += readVarint32(seqid);
  rsize += readString(name);

  return rsize;
}

/**
 * Read a struct begin. There's nothing on the wire for this, but it is our
 * opportunity to push a new struct begin marker on the field stack.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readStructBegin(std::string& name) {
  name = "";
  lastField_.push(lastFieldId_);
  lastFieldId_ = 0;
  return 0;
}

/**
 * Doesn't actually consume any wire data, just removes the last field for
 * this struct from the field stack.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readStructEnd() {
  lastFieldId_ = lastField_.top();
  lastField_.pop();
  return 0;
}

/**
 * Read a field header off the wire.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readFieldBegin(std::string& name,
                                                       TType& fieldType,
                                                       int16_t& fieldId) {
  (void) name;
  uint32_t rsize = 0;
  int8_t byte;
  int8_t type;

  rsize += readByte(byte);
  type = (byte & 0x0f);

  // if it's a stop, then we can return immediately, as the struct is over.
  if (type == T_STOP) {
    fieldType = T_STOP;
    fieldId = 0;
    return rsize;
  }

  // mask off the 4 MSB of the type header. it could contain a field id delta.
  int16_t modifier = (int16_t)(((uint8_t)byte & 0xf0) >> 4);
  if (modifier == 0) {
    // not a delta, look ahead for the zigzag varint field id.
    rsize += readI16(fieldId);
  } else {
    fieldId = (int16_t)(lastFieldId_ + modifier);
  }
  fieldType = getTType(type);

  // if this happens to be a boolean field, the value is encoded in the type
  if (type == detail::compact::CT_BOOLEAN_TRUE ||
      type == detail::compact::CT_BOOLEAN_FALSE) {
    // save the boolean value in a special instance variable.
    boolValue_.hasBoolValue = true;
    boolValue_.boolValue =
      (type == detail::compact::CT_BOOLEAN_TRUE ? true : false);
  }

  // push the new field onto the field stack so we can keep the deltas going.
  lastFieldId_ = fieldId;
  return rsize;
}

/**
 * Read a map header off the wire. If the size is zero, skip reading the key
 * and value type. This means that 0-length maps will yield TMaps without the
 * "correct" types.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readMapBegin(TType& keyType,
                                                     TType& valType,
                                                     uint32_t& size) {
  uint32_t rsize = 0;
  int8_t kvType = 0;
  int32_t msize = 0;

  rsize += readVarint32(msize);
  if (msize != 0)
    rsize += readByte(kvType);

  if (msize < 0) {
    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
  } else if (container_limit_ && msize > container_limit_) {
    throw TProtocolException(TProtocolException::SIZE_LIMIT);
  }

  keyType = getTType((int8_t)((uint8_t)kvType >> 4));
  valType = getTType((int8_t)((uint8_t)kvType & 0xf));
  size = (uint32_t)msize;

  return rsize;
}

/**
 * Read a list header off the wire. If the list size is 0-14, the size will
 * be packed into the element type header. If it's a longer list, the 4 MSB
 * of the element type header will be 0xF, and a varint will follow with the
 * true size.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readListBegin(TType& elemType,
                                                      uint32_t& size) {
  int8_t size_and_type;
  uint32_t rsize = 0;
  int32_t lsize;

  rsize += readByte(size_and_type);

  lsize = ((uint8_t)size_and_type >> 4) & 0x0f;
  if (lsize == 15) {
    rsize += readVarint32(lsize);
  }

  if (lsize < 0) {
    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
  } else if (container_limit_ && lsize > container_limit_) {
    throw TProtocolException(TProtocolException::SIZE_LIMIT);
  }

  elemType = getTType((int8_t)(size_and_type & 0x0f));
  size = (uint32_t)lsize;

  return rsize;
}

/**
 * Read a set header off the wire. If the set size is 0-14, the size will
 * be packed into the element type header. If it's a longer set, the 4 MSB
 * of the element type header will be 0xF, and a varint will follow with the
 * true size.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readSetBegin(TType& elemType,
                                                     uint32_t& size) {
  return readListBegin(elemType, size);
}

/**
 * Read a boolean off the wire. If this is a boolean field, the value should
 * already have been read during readFieldBegin, so we'll just consume the
 * pre-stored value. Otherwise, read a byte.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readBool(bool& value) {
  if (boolValue_.hasBoolValue == true) {
    value = boolValue_.boolValue;
    boolValue_.hasBoolValue = false;
    return 0;
  } else {
    int8_t val;
    readByte(val);
    value = (val == detail::compact::CT_BOOLEAN_TRUE);
    return 1;
  }
}

/**
 * Read a single byte off the wire. Nothing interesting here.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readByte(int8_t& byte) {
  uint8_t b[1];
  trans_->readAll(b, 1);
  byte = *(int8_t*)b;
  return 1;
}

/**
 * Read an i16 from the wire as a zigzag varint.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readI16(int16_t& i16) {
  int32_t value;
  uint32_t rsize = readVarint32(value);
  i16 = (int16_t)zigzagToI32(value);
  return rsize;
}

/**
 * Read an i32 from the wire as a zigzag varint.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readI32(int32_t& i32) {
  int32_t value;
  uint32_t rsize = readVarint32(value);
  i32 = zigzagToI32(value);
  return rsize;
}

/**
 * Read an i64 from the wire as a zigzag varint.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readI64(int64_t& i64) {
  int64_t value;
  uint32_t rsize = readVarint64(value);
  i64 = zigzagToI64(value);
  return rsize;
}

/**
 * No magic here - just read a double off the wire.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readDouble(double& dub) {
  //BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
  //BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);

  union {
    uint64_t bits;
    uint8_t b[8];
  } u;
  trans_->readAll(u.b, 8);
  u.bits = THRIFT_letohll(u.bits);
  dub = bitwise_cast<double>(u.bits);
  return 8;
}

template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readString(std::string& str) {
  return readBinary(str);
}

/**
 * Read a byte[] from the wire.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readBinary(std::string& str) {
  int32_t rsize = 0;
  int32_t size;

  rsize += readVarint32(size);
  // Catch empty string case
  if (size == 0) {
    str = "";
    return rsize;
  }

  // Catch error cases
  if (size < 0) {
    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
  }
  if (string_limit_ > 0 && size > string_limit_) {
    throw TProtocolException(TProtocolException::SIZE_LIMIT);
  }

  // Use the heap here to prevent stack overflow for v. large strings
  if (size > string_buf_size_ || string_buf_ == NULL) {
    void* new_string_buf = std::realloc(string_buf_, (uint32_t)size);
    if (new_string_buf == NULL) {
      throw std::bad_alloc();
    }
    string_buf_ = (uint8_t*)new_string_buf;
    string_buf_size_ = size;
  }
  trans_->readAll(string_buf_, size);
  str.assign((char*)string_buf_, size);

  return rsize + (uint32_t)size;
}

/**
 * Read an i32 from the wire as a varint. The MSB of each byte is set
 * if there is another byte to follow. This can read up to 5 bytes.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readVarint32(int32_t& i32) {
  int64_t val;
  uint32_t rsize = readVarint64(val);
  i32 = (int32_t)val;
  return rsize;
}

/**
 * Read an i64 from the wire as a proper varint. The MSB of each byte is set
 * if there is another byte to follow. This can read up to 10 bytes.
 */
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readVarint64(int64_t& i64) {
  uint32_t rsize = 0;
  uint64_t val = 0;
  int shift = 0;
  uint8_t buf[10];  // 64 bits / (7 bits/byte) = 10 bytes.
  uint32_t buf_size = sizeof(buf);
  const uint8_t* borrowed = trans_->borrow(buf, &buf_size);

  // Fast path.
  if (borrowed != NULL) {
    while (true) {
      uint8_t byte = borrowed[rsize];
      rsize++;
      val |= (uint64_t)(byte & 0x7f) << shift;
      shift += 7;
      if (!(byte & 0x80)) {
        i64 = val;
        trans_->consume(rsize);
        return rsize;
      }
      // Have to check for invalid data so we don't crash.
      if (UNLIKELY(rsize == sizeof(buf))) {
        throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
      }
    }
  }

  // Slow path.
  else {
    while (true) {
      uint8_t byte;
      rsize += trans_->readAll(&byte, 1);
      val |= (uint64_t)(byte & 0x7f) << shift;
      shift += 7;
      if (!(byte & 0x80)) {
        i64 = val;
        return rsize;
      }
      // Might as well check for invalid data on the slow path too.
      if (UNLIKELY(rsize >= sizeof(buf))) {
        throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
      }
    }
  }
}

/**
 * Convert from zigzag int to int.
 */
template <class Transport_>
int32_t TCompactProtocolT<Transport_>::zigzagToI32(uint32_t n) {
  return (n >> 1) ^ static_cast<uint32_t>(-static_cast<int32_t>(n & 1));
}

/**
 * Convert from zigzag long to long.
 */
template <class Transport_>
int64_t TCompactProtocolT<Transport_>::zigzagToI64(uint64_t n) {
  return (n >> 1) ^ static_cast<uint64_t>(-static_cast<int64_t>(n & 1));
}

template <class Transport_>
TType TCompactProtocolT<Transport_>::getTType(int8_t type) {
  switch (type) {
    case T_STOP:
      return T_STOP;
    case detail::compact::CT_BOOLEAN_FALSE:
    case detail::compact::CT_BOOLEAN_TRUE:
      return T_BOOL;
    case detail::compact::CT_BYTE:
      return T_BYTE;
    case detail::compact::CT_I16:
      return T_I16;
    case detail::compact::CT_I32:
      return T_I32;
    case detail::compact::CT_I64:
      return T_I64;
    case detail::compact::CT_DOUBLE:
      return T_DOUBLE;
    case detail::compact::CT_BINARY:
      return T_STRING;
    case detail::compact::CT_LIST:
      return T_LIST;
    case detail::compact::CT_SET:
      return T_SET;
    case detail::compact::CT_MAP:
      return T_MAP;
    case detail::compact::CT_STRUCT:
      return T_STRUCT;
    default:
      throw TException(std::string("don't know what type: ") + (char)type);
  }
}

}}} // duckdb_apache::thrift::protocol

#endif // _DUCKDB_THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_


// LICENSE_CHANGE_END


#endif


// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_
#define _DUCKDB_THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_ 1

#include <cstdlib>
#include <cstddef>
#include <cstring>
#include <limits>
//#include <boost/scoped_array.hpp> // FUCK OFF




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _DUCKDB_THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_
#define _DUCKDB_THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_ 1



namespace duckdb_apache {
namespace thrift {
namespace transport {

/**
 * Helper class that provides default implementations of TTransport methods.
 *
 * This class provides default implementations of read(), readAll(), write(),
 * borrow() and consume().
 *
 * In the TTransport base class, each of these methods simply invokes its
 * virtual counterpart.  This class overrides them to always perform the
 * default behavior, without a virtual function call.
 *
 * The primary purpose of this class is to serve as a base class for
 * TVirtualTransport, and prevent infinite recursion if one of its subclasses
 * does not override the TTransport implementation of these methods.  (Since
 * TVirtualTransport::read_virt() calls read(), and TTransport::read() calls
 * read_virt().)
 */
class TTransportDefaults : public TTransport {
public:
  /*
   * TTransport *_virt() methods provide reasonable default implementations.
   * Invoke them non-virtually.
   */
  uint32_t read(uint8_t* buf, uint32_t len) { return this->TTransport::read_virt(buf, len); }
  uint32_t readAll(uint8_t* buf, uint32_t len) { return this->TTransport::readAll_virt(buf, len); }
  void write(const uint8_t* buf, uint32_t len) { this->TTransport::write_virt(buf, len); }
  const uint8_t* borrow(uint8_t* buf, uint32_t* len) {
    return this->TTransport::borrow_virt(buf, len);
  }
  void consume(uint32_t len) { this->TTransport::consume_virt(len); }

protected:
  TTransportDefaults() = default;
};

/**
 * Helper class to provide polymorphism for subclasses of TTransport.
 *
 * This class implements *_virt() methods of TTransport, to call the
 * non-virtual versions of these functions in the proper subclass.
 *
 * To define your own transport class using TVirtualTransport:
 * 1) Derive your subclass from TVirtualTransport<your class>
 *    e.g:  class MyTransport : public TVirtualTransport<MyTransport> {
 * 2) Provide your own implementations of read(), readAll(), etc.
 *    These methods should be non-virtual.
 *
 * Transport implementations that need to use virtual inheritance when
 * inheriting from TTransport cannot use TVirtualTransport.
 *
 * @author Chad Walters <chad@powerset.com>
 */
template <class Transport_, class Super_ = TTransportDefaults>
class TVirtualTransport : public Super_ {
public:
  /*
   * Implementations of the *_virt() functions, to call the subclass's
   * non-virtual implementation function.
   */
  uint32_t read_virt(uint8_t* buf, uint32_t len) override {
    return static_cast<Transport_*>(this)->read(buf, len);
  }

  uint32_t readAll_virt(uint8_t* buf, uint32_t len) override {
    return static_cast<Transport_*>(this)->readAll(buf, len);
  }

  void write_virt(const uint8_t* buf, uint32_t len) override {
    static_cast<Transport_*>(this)->write(buf, len);
  }

  const uint8_t* borrow_virt(uint8_t* buf, uint32_t* len) override {
    return static_cast<Transport_*>(this)->borrow(buf, len);
  }

  void consume_virt(uint32_t len) override { static_cast<Transport_*>(this)->consume(len); }

  /*
   * Provide a default readAll() implementation that invokes
   * read() non-virtually.
   *
   * Note: subclasses that use TVirtualTransport to derive from another
   * transport implementation (i.e., not TTransportDefaults) should beware that
   * this may override any non-default readAll() implementation provided by
   * the parent transport class.  They may need to redefine readAll() to call
   * the correct parent implementation, if desired.
   */
  uint32_t readAll(uint8_t* buf, uint32_t len) {
    auto* trans = static_cast<Transport_*>(this);
    return ::duckdb_apache::thrift::transport::readAll(*trans, buf, len);
  }

protected:
  TVirtualTransport() = default;

  /*
   * Templatized constructors, to allow arguments to be passed to the Super_
   * constructor.  Currently we only support 0, 1, or 2 arguments, but
   * additional versions can be added as needed.
   */
  template <typename Arg_>
  TVirtualTransport(Arg_ const& arg)
    : Super_(arg) {}

  template <typename Arg1_, typename Arg2_>
  TVirtualTransport(Arg1_ const& a1, Arg2_ const& a2)
    : Super_(a1, a2) {}
};
}
}
} // duckdb_apache::thrift::transport

#endif // #ifndef _DUCKDB_THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_


// LICENSE_CHANGE_END


#ifdef __GNUC__
#define TDB_LIKELY(val) (__builtin_expect((val), 1))
#define TDB_UNLIKELY(val) (__builtin_expect((val), 0))
#else
#define TDB_LIKELY(val) (val)
#define TDB_UNLIKELY(val) (val)
#endif

namespace duckdb_apache {
namespace thrift {
namespace transport {

/**
 * Base class for all transports that use read/write buffers for performance.
 *
 * TBufferBase is designed to implement the fast-path "memcpy" style
 * operations that work in the common case.  It does so with small and
 * (eventually) nonvirtual, inlinable methods.  TBufferBase is an abstract
 * class.  Subclasses are expected to define the "slow path" operations
 * that have to be done when the buffers are full or empty.
 *
 */
class TBufferBase : public TVirtualTransport<TBufferBase> {

public:
  /**
   * Fast-path read.
   *
   * When we have enough data buffered to fulfill the read, we can satisfy it
   * with a single memcpy, then adjust our internal pointers.  If the buffer
   * is empty, we call out to our slow path, implemented by a subclass.
   * This method is meant to eventually be nonvirtual and inlinable.
   */
  uint32_t read(uint8_t* buf, uint32_t len) {
    uint8_t* new_rBase = rBase_ + len;
    if (TDB_LIKELY(new_rBase <= rBound_)) {
      std::memcpy(buf, rBase_, len);
      rBase_ = new_rBase;
      return len;
    }
    return readSlow(buf, len);
  }

  /**
   * Shortcutted version of readAll.
   */
  uint32_t readAll(uint8_t* buf, uint32_t len) {
    uint8_t* new_rBase = rBase_ + len;
    if (TDB_LIKELY(new_rBase <= rBound_)) {
      std::memcpy(buf, rBase_, len);
      rBase_ = new_rBase;
      return len;
    }
    return duckdb_apache::thrift::transport::readAll(*this, buf, len);
  }

  /**
   * Fast-path write.
   *
   * When we have enough empty space in our buffer to accommodate the write, we
   * can satisfy it with a single memcpy, then adjust our internal pointers.
   * If the buffer is full, we call out to our slow path, implemented by a
   * subclass.  This method is meant to eventually be nonvirtual and
   * inlinable.
   */
  void write(const uint8_t* buf, uint32_t len) {
    uint8_t* new_wBase = wBase_ + len;
    if (TDB_LIKELY(new_wBase <= wBound_)) {
      std::memcpy(wBase_, buf, len);
      wBase_ = new_wBase;
      return;
    }
    writeSlow(buf, len);
  }

  /**
   * Fast-path borrow.  A lot like the fast-path read.
   */
  const uint8_t* borrow(uint8_t* buf, uint32_t* len) {
    if (TDB_LIKELY(static_cast<ptrdiff_t>(*len) <= rBound_ - rBase_)) {
      // With strict aliasing, writing to len shouldn't force us to
      // refetch rBase_ from memory.  TODO(dreiss): Verify this.
      *len = static_cast<uint32_t>(rBound_ - rBase_);
      return rBase_;
    }
    return borrowSlow(buf, len);
  }

  /**
   * Consume doesn't require a slow path.
   */
  void consume(uint32_t len) {
    if (TDB_LIKELY(static_cast<ptrdiff_t>(len) <= rBound_ - rBase_)) {
      rBase_ += len;
    } else {
      throw TTransportException(TTransportException::BAD_ARGS, "consume did not follow a borrow.");
    }
  }

protected:
  /// Slow path read.
  virtual uint32_t readSlow(uint8_t* buf, uint32_t len) = 0;

  /// Slow path write.
  virtual void writeSlow(const uint8_t* buf, uint32_t len) = 0;

  /**
   * Slow path borrow.
   *
   * POSTCONDITION: return == NULL || rBound_ - rBase_ >= *len
   */
  virtual const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len) = 0;

  /**
   * Trivial constructor.
   *
   * Initialize pointers safely.  Constructing is not a very
   * performance-sensitive operation, so it is okay to just leave it to
   * the concrete class to set up pointers correctly.
   */
  TBufferBase() : rBase_(nullptr), rBound_(nullptr), wBase_(nullptr), wBound_(nullptr) {}

  /// Convenience mutator for setting the read buffer.
  void setReadBuffer(uint8_t* buf, uint32_t len) {
    rBase_ = buf;
    rBound_ = buf + len;
  }

  /// Convenience mutator for setting the write buffer.
  void setWriteBuffer(uint8_t* buf, uint32_t len) {
    wBase_ = buf;
    wBound_ = buf + len;
  }

  ~TBufferBase() override = default;

  /// Reads begin here.
  uint8_t* rBase_;
  /// Reads may extend to just before here.
  uint8_t* rBound_;

  /// Writes begin here.
  uint8_t* wBase_;
  /// Writes may extend to just before here.
  uint8_t* wBound_;
};


/**
 * A memory buffer is a transport that simply reads from and writes to an
 * in memory buffer. Anytime you call write on it, the data is simply placed
 * into a buffer, and anytime you call read, data is read from that buffer.
 *
 * The buffers are allocated using C constructs malloc,realloc, and the size
 * doubles as necessary.  We've considered using scoped
 *
 */
class TMemoryBuffer : public TVirtualTransport<TMemoryBuffer, TBufferBase> {
private:
  // Common initialization done by all constructors.
  void initCommon(uint8_t* buf, uint32_t size, bool owner, uint32_t wPos) {

    maxBufferSize_ = (std::numeric_limits<uint32_t>::max)();

    if (buf == nullptr && size != 0) {
      assert(owner);
      buf = (uint8_t*)std::malloc(size);
      if (buf == nullptr) {
	throw std::bad_alloc();
      }
    }

    buffer_ = buf;
    bufferSize_ = size;

    rBase_ = buffer_;
    rBound_ = buffer_ + wPos;
    // TODO(dreiss): Investigate NULL-ing this if !owner.
    wBase_ = buffer_ + wPos;
    wBound_ = buffer_ + bufferSize_;

    owner_ = owner;

    // rBound_ is really an artifact.  In principle, it should always be
    // equal to wBase_.  We update it in a few places (computeRead, etc.).
  }

public:
  static const uint32_t defaultSize = 1024;

  /**
   * This enum specifies how a TMemoryBuffer should treat
   * memory passed to it via constructors or resetBuffer.
   *
   * OBSERVE:
   *   TMemoryBuffer will simply store a pointer to the memory.
   *   It is the callers responsibility to ensure that the pointer
   *   remains valid for the lifetime of the TMemoryBuffer,
   *   and that it is properly cleaned up.
   *   Note that no data can be written to observed buffers.
   *
   * COPY:
   *   TMemoryBuffer will make an internal copy of the buffer.
   *   The caller has no responsibilities.
   *
   * TAKE_OWNERSHIP:
   *   TMemoryBuffer will become the "owner" of the buffer,
   *   and will be responsible for freeing it.
   *   The membory must have been allocated with malloc.
   */
  enum MemoryPolicy { OBSERVE = 1, COPY = 2, TAKE_OWNERSHIP = 3 };

  /**
   * Construct a TMemoryBuffer with a default-sized buffer,
   * owned by the TMemoryBuffer object.
   */
  TMemoryBuffer() { initCommon(nullptr, defaultSize, true, 0); }

  /**
   * Construct a TMemoryBuffer with a buffer of a specified size,
   * owned by the TMemoryBuffer object.
   *
   * @param sz  The initial size of the buffer.
   */
  TMemoryBuffer(uint32_t sz) { initCommon(nullptr, sz, true, 0); }

  /**
   * Construct a TMemoryBuffer with buf as its initial contents.
   *
   * @param buf    The initial contents of the buffer.
   *               Note that, while buf is a non-const pointer,
   *               TMemoryBuffer will not write to it if policy == OBSERVE,
   *               so it is safe to const_cast<uint8_t*>(whatever).
   * @param sz     The size of @c buf.
   * @param policy See @link MemoryPolicy @endlink .
   */
  TMemoryBuffer(uint8_t* buf, uint32_t sz, MemoryPolicy policy = OBSERVE) {
    if (buf == nullptr && sz != 0) {
      throw TTransportException(TTransportException::BAD_ARGS,
                                "TMemoryBuffer given null buffer with non-zero size.");
    }

    switch (policy) {
    case OBSERVE:
    case TAKE_OWNERSHIP:
      initCommon(buf, sz, policy == TAKE_OWNERSHIP, sz);
      break;
    case COPY:
      initCommon(nullptr, sz, true, 0);
      this->write(buf, sz);
      break;
    default:
      throw TTransportException(TTransportException::BAD_ARGS,
                                "Invalid MemoryPolicy for TMemoryBuffer");
    }
  }

  ~TMemoryBuffer() override {
    if (owner_) {
      std::free(buffer_);
    }
  }

  bool isOpen() const override { return true; }

  bool peek() override { return (rBase_ < wBase_); }

  void open() override {}

  void close() override {}

  // TODO(dreiss): Make bufPtr const.
  void getBuffer(uint8_t** bufPtr, uint32_t* sz) {
    *bufPtr = rBase_;
    *sz = static_cast<uint32_t>(wBase_ - rBase_);
  }

  std::string getBufferAsString() {
    if (buffer_ == nullptr) {
      return "";
    }
    uint8_t* buf;
    uint32_t sz;
    getBuffer(&buf, &sz);
    return std::string((char*)buf, (std::string::size_type)sz);
  }

  void appendBufferToString(std::string& str) {
    if (buffer_ == nullptr) {
      return;
    }
    uint8_t* buf;
    uint32_t sz;
    getBuffer(&buf, &sz);
    str.append((char*)buf, sz);
  }

  void resetBuffer() {
    rBase_ = buffer_;
    rBound_ = buffer_;
    wBase_ = buffer_;
    // It isn't safe to write into a buffer we don't own.
    if (!owner_) {
      wBound_ = wBase_;
      bufferSize_ = 0;
    }
  }

  /// See constructor documentation.
  void resetBuffer(uint8_t* buf, uint32_t sz, MemoryPolicy policy = OBSERVE) {
    // Use a variant of the copy-and-swap trick for assignment operators.
    // This is sub-optimal in terms of performance for two reasons:
    //   1/ The constructing and swapping of the (small) values
    //      in the temporary object takes some time, and is not necessary.
    //   2/ If policy == COPY, we allocate the new buffer before
    //      freeing the old one, precluding the possibility of
    //      reusing that memory.
    // I doubt that either of these problems could be optimized away,
    // but the second is probably no a common case, and the first is minor.
    // I don't expect resetBuffer to be a common operation, so I'm willing to
    // bite the performance bullet to make the method this simple.

    // Construct the new buffer.
    TMemoryBuffer new_buffer(buf, sz, policy);
    // Move it into ourself.
    this->swap(new_buffer);
    // Our old self gets destroyed.
  }

  /// See constructor documentation.
  void resetBuffer(uint32_t sz) {
    // Construct the new buffer.
    TMemoryBuffer new_buffer(sz);
    // Move it into ourself.
    this->swap(new_buffer);
    // Our old self gets destroyed.
  }

  std::string readAsString(uint32_t len) {
    std::string str;
    (void)readAppendToString(str, len);
    return str;
  }

  uint32_t readAppendToString(std::string& str, uint32_t len);

  // return number of bytes read
  uint32_t readEnd() override {
    // This cast should be safe, because buffer_'s size is a uint32_t
    auto bytes = static_cast<uint32_t>(rBase_ - buffer_);
    if (rBase_ == wBase_) {
      resetBuffer();
    }
    return bytes;
  }

  // Return number of bytes written
  uint32_t writeEnd() override {
    // This cast should be safe, because buffer_'s size is a uint32_t
    return static_cast<uint32_t>(wBase_ - buffer_);
  }

  uint32_t available_read() const {
    // Remember, wBase_ is the real rBound_.
    return static_cast<uint32_t>(wBase_ - rBase_);
  }

  uint32_t available_write() const { return static_cast<uint32_t>(wBound_ - wBase_); }

  // Returns a pointer to where the client can write data to append to
  // the TMemoryBuffer, and ensures the buffer is big enough to accommodate a
  // write of the provided length.  The returned pointer is very convenient for
  // passing to read(), recv(), or similar. You must call wroteBytes() as soon
  // as data is written or the buffer will not be aware that data has changed.
  uint8_t* getWritePtr(uint32_t len) {
    ensureCanWrite(len);
    return wBase_;
  }

  // Informs the buffer that the client has written 'len' bytes into storage
  // that had been provided by getWritePtr().
  void wroteBytes(uint32_t len);

  /*
   * TVirtualTransport provides a default implementation of readAll().
   * We want to use the TBufferBase version instead.
   */
  uint32_t readAll(uint8_t* buf, uint32_t len) { return TBufferBase::readAll(buf, len); }

  //! \brief Get the current buffer size
  //! \returns the current buffer size
  uint32_t getBufferSize() const {
    return bufferSize_;
  }

  //! \brief Get the current maximum buffer size
  //! \returns the current maximum buffer size
  uint32_t getMaxBufferSize() const {
    return maxBufferSize_;
  }

  //! \brief Change the maximum buffer size
  //! \param[in]  maxSize  the new maximum buffer size allowed to grow to
  //! \throws  TTransportException(BAD_ARGS) if maxSize is less than the current buffer size
  void setMaxBufferSize(uint32_t maxSize) {
    if (maxSize < bufferSize_) {
      throw TTransportException(TTransportException::BAD_ARGS,
                                "Maximum buffer size would be less than current buffer size");
    }
    maxBufferSize_ = maxSize;
  }

protected:
  void swap(TMemoryBuffer& that) {
    using std::swap;
    swap(buffer_, that.buffer_);
    swap(bufferSize_, that.bufferSize_);

    swap(rBase_, that.rBase_);
    swap(rBound_, that.rBound_);
    swap(wBase_, that.wBase_);
    swap(wBound_, that.wBound_);

    swap(owner_, that.owner_);
  }

  // Make sure there's at least 'len' bytes available for writing.
  void ensureCanWrite(uint32_t len);

  // Compute the position and available data for reading.
  void computeRead(uint32_t len, uint8_t** out_start, uint32_t* out_give);

  uint32_t readSlow(uint8_t* buf, uint32_t len) override;

  void writeSlow(const uint8_t* buf, uint32_t len) override;

  const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len) override;

  // Data buffer
  uint8_t* buffer_;

  // Allocated buffer size
  uint32_t bufferSize_;

  // Maximum allowed size
  uint32_t maxBufferSize_;

  // Is this object the owner of the buffer?
  bool owner_;

  // Don't forget to update constrctors, initCommon, and swap if
  // you add new members.
};
}
}
} // duckdb_apache::thrift::transport

#endif // #ifndef _DUCKDB_THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_


// LICENSE_CHANGE_END


#include "duckdb.hpp"
#ifndef DUCKDB_AMALGAMATION
#include "duckdb/common/file_system.hpp"
#include "duckdb/common/allocator.hpp"
#endif

namespace duckdb {

// A ReadHead for prefetching data in a specific range
struct ReadHead {
	ReadHead(idx_t location, uint64_t size) : location(location), size(size) {};
	// Hint info
	idx_t location;
	uint64_t size;

	// Current info
	unique_ptr<AllocatedData> data;
	bool data_isset = false;

	idx_t GetEnd() const {
		return size + location;
	}

	void Allocate(Allocator &allocator) {
		data = allocator.Allocate(size);
	}
};

// Comparator for ReadHeads that are either overlapping, adjacent, or within ALLOW_GAP bytes from each other
struct ReadHeadComparator {
	static constexpr uint64_t ALLOW_GAP = 1 << 14; // 16 KiB
	bool operator()(const ReadHead *a, const ReadHead *b) const {
		auto a_start = a->location;
		auto a_end = a->location + a->size;
		auto b_start = b->location;

		if (a_end <= NumericLimits<idx_t>::Maximum() - ALLOW_GAP) {
			a_end += ALLOW_GAP;
		}

		return a_start < b_start && a_end < b_start;
	}
};

// Two-step read ahead buffer
// 1: register all ranges that will be read, merging ranges that are consecutive
// 2: prefetch all registered ranges
struct ReadAheadBuffer {
	ReadAheadBuffer(Allocator &allocator, FileHandle &handle, FileOpener &opener)
	    : allocator(allocator), handle(handle), file_opener(opener) {
	}

	// The list of read heads
	std::list<ReadHead> read_heads;
	// Set for merging consecutive ranges
	std::set<ReadHead *, ReadHeadComparator> merge_set;

	Allocator &allocator;
	FileHandle &handle;
	FileOpener &file_opener;

	idx_t total_size = 0;

	// Add a read head to the prefetching list
	void AddReadHead(idx_t pos, uint64_t len, bool merge_buffers = true) {
		// Attempt to merge with existing
		if (merge_buffers) {
			ReadHead new_read_head {pos, len};
			auto lookup_set = merge_set.find(&new_read_head);
			if (lookup_set != merge_set.end()) {
				auto existing_head = *lookup_set;
				auto new_start = MinValue<idx_t>(existing_head->location, new_read_head.location);
				auto new_length = MaxValue<idx_t>(existing_head->GetEnd(), new_read_head.GetEnd()) - new_start;
				existing_head->location = new_start;
				existing_head->size = new_length;
				return;
			}
		}

		read_heads.emplace_front(ReadHead(pos, len));
		total_size += len;
		auto &read_head = read_heads.front();

		if (merge_buffers) {
			merge_set.insert(&read_head);
		}

		if (read_head.GetEnd() > handle.GetFileSize()) {
			throw std::runtime_error("Prefetch registered for bytes outside file");
		}
	}

	// Returns the relevant read head
	ReadHead *GetReadHead(idx_t pos) {
		for (auto &read_head : read_heads) {
			if (pos >= read_head.location && pos < read_head.GetEnd()) {
				return &read_head;
			}
		}
		return nullptr;
	}

	// Prefetch all read heads
	void Prefetch() {
		for (auto &read_head : read_heads) {
			read_head.Allocate(allocator);

			if (read_head.GetEnd() > handle.GetFileSize()) {
				throw std::runtime_error("Prefetch registered requested for bytes outside file");
			}

			handle.Read(read_head.data->get(), read_head.size, read_head.location);
			read_head.data_isset = true;
		}
	}
};

class ThriftFileTransport : public duckdb_apache::thrift::transport::TVirtualTransport<ThriftFileTransport> {
public:
	static constexpr uint64_t PREFETCH_FALLBACK_BUFFERSIZE = 1000000;

	ThriftFileTransport(Allocator &allocator, FileHandle &handle_p, FileOpener &opener, bool prefetch_mode_p)
	    : handle(handle_p), location(0), allocator(allocator), ra_buffer(ReadAheadBuffer(allocator, handle_p, opener)),
	      prefetch_mode(prefetch_mode_p) {
	}

	uint32_t read(uint8_t *buf, uint32_t len) {
		auto prefetch_buffer = ra_buffer.GetReadHead(location);
		if (prefetch_buffer != nullptr && location - prefetch_buffer->location + len <= prefetch_buffer->size) {
			D_ASSERT(location - prefetch_buffer->location + len <= prefetch_buffer->size);

			if (!prefetch_buffer->data_isset) {
				prefetch_buffer->Allocate(allocator);
				handle.Read(prefetch_buffer->data->get(), prefetch_buffer->size, prefetch_buffer->location);
				prefetch_buffer->data_isset = true;
			}
			memcpy(buf, prefetch_buffer->data->get() + location - prefetch_buffer->location, len);
		} else {
			if (prefetch_mode && len < PREFETCH_FALLBACK_BUFFERSIZE && len > 0) {
				Prefetch(location, MinValue<uint64_t>(PREFETCH_FALLBACK_BUFFERSIZE, handle.GetFileSize() - location));
				auto prefetch_buffer_fallback = ra_buffer.GetReadHead(location);
				D_ASSERT(location - prefetch_buffer_fallback->location + len <= prefetch_buffer_fallback->size);
				memcpy(buf, prefetch_buffer_fallback->data->get() + location - prefetch_buffer_fallback->location, len);
			} else {
				handle.Read(buf, len, location);
			}
		}
		location += len;
		return len;
	}

	// Prefetch a single buffer
	void Prefetch(idx_t pos, uint64_t len) {
		RegisterPrefetch(pos, len, false);
		FinalizeRegistration();
		PrefetchRegistered();
	}

	// Register a buffer for prefixing
	void RegisterPrefetch(idx_t pos, uint64_t len, bool can_merge = true) {
		ra_buffer.AddReadHead(pos, len, can_merge);
	}

	// Prevents any further merges, should be called before PrefetchRegistered
	void FinalizeRegistration() {
		ra_buffer.merge_set.clear();
	}

	// Prefetch all previously registered ranges
	void PrefetchRegistered() {
		ra_buffer.Prefetch();
	}

	void ClearPrefetch() {
		ra_buffer.read_heads.clear();
		ra_buffer.merge_set.clear();
	}

	void SetLocation(idx_t location_p) {
		location = location_p;
	}

	idx_t GetLocation() {
		return location;
	}
	idx_t GetSize() {
		return handle.file_system.GetFileSize(handle);
	}

private:
	FileHandle &handle;
	idx_t location;

	Allocator &allocator;

	// Multi-buffer prefetch
	ReadAheadBuffer ra_buffer;

	// Whether the prefetch mode is enabled. In this mode the DirectIO flag of the handle will be set and the parquet
	// reader will manage the read buffering.
	bool prefetch_mode;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// resizable_buffer.hpp
//
//
//===----------------------------------------------------------------------===//


#include "duckdb.hpp"
#ifndef DUCKDB_AMALGAMATION
#include "duckdb/common/allocator.hpp"
#endif

#include <exception>

namespace duckdb {

class ByteBuffer { // on to the 10 thousandth impl
public:
	ByteBuffer() {};
	ByteBuffer(char *ptr, uint64_t len) : ptr(ptr), len(len) {};

	char *ptr = nullptr;
	uint64_t len = 0;

public:
	void inc(uint64_t increment) {
		available(increment);
		len -= increment;
		ptr += increment;
	}

	template <class T>
	T read() {
		T val = get<T>();
		inc(sizeof(T));
		return val;
	}

	template <class T>
	T get() {
		available(sizeof(T));
		T val = Load<T>((data_ptr_t)ptr);
		return val;
	}

	void copy_to(char *dest, uint64_t len) {
		available(len);
		std::memcpy(dest, ptr, len);
	}

	void zero() {
		std::memset(ptr, 0, len);
	}

	void available(uint64_t req_len) {
		if (req_len > len) {
			throw std::runtime_error("Out of buffer");
		}
	}
};

class ResizeableBuffer : public ByteBuffer {
public:
	ResizeableBuffer() {
	}
	ResizeableBuffer(Allocator &allocator, uint64_t new_size) {
		resize(allocator, new_size);
	}
	void resize(Allocator &allocator, uint64_t new_size) {
		len = new_size;
		if (new_size == 0) {
			return;
		}
		if (new_size > alloc_len) {
			alloc_len = new_size;
			allocated_data = allocator.Allocate(alloc_len);
			ptr = (char *)allocated_data->get();
		}
	}

private:
	unique_ptr<AllocatedData> allocated_data;
	idx_t alloc_len = 0;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// parquet_rle_bp_decoder.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {
class ParquetDecodeUtils {

public:
	template <class T>
	static T ZigzagToInt(const T n) {
		return (n >> 1) ^ -(n & 1);
	}

	static const uint32_t BITPACK_MASKS[];
	static const uint8_t BITPACK_DLEN;

	template <typename T>
	static uint32_t BitUnpack(ByteBuffer &buffer, uint8_t &bitpack_pos, T *dest, uint32_t count, uint8_t width) {
		auto mask = BITPACK_MASKS[width];

		for (uint32_t i = 0; i < count; i++) {
			T val = (buffer.get<uint8_t>() >> bitpack_pos) & mask;
			bitpack_pos += width;
			while (bitpack_pos > BITPACK_DLEN) {
				buffer.inc(1);
				val |= (buffer.get<uint8_t>() << (BITPACK_DLEN - (bitpack_pos - width))) & mask;
				bitpack_pos -= BITPACK_DLEN;
			}
			dest[i] = val;
		}
		return count;
	}

	template <class T>
	static T VarintDecode(ByteBuffer &buf) {
		T result = 0;
		uint8_t shift = 0;
		while (true) {
			auto byte = buf.read<uint8_t>();
			result |= (byte & 127) << shift;
			if ((byte & 128) == 0)
				break;
			shift += 7;
			if (shift > sizeof(T) * 8) {
				throw std::runtime_error("Varint-decoding found too large number");
			}
		}
		return result;
	}
};
} // namespace duckdb


namespace duckdb {

class RleBpDecoder {
public:
	/// Create a decoder object. buffer/buffer_len is the decoded data.
	/// bit_width is the width of each value (before encoding).
	RleBpDecoder(const uint8_t *buffer, uint32_t buffer_len, uint32_t bit_width)
	    : buffer_((char *)buffer, buffer_len), bit_width_(bit_width), current_value_(0), repeat_count_(0),
	      literal_count_(0) {
		if (bit_width >= 64) {
			throw std::runtime_error("Decode bit width too large");
		}
		byte_encoded_len = ((bit_width_ + 7) / 8);
		max_val = (uint64_t(1) << bit_width_) - 1;
	}

	template <typename T>
	void GetBatch(char *values_target_ptr, uint32_t batch_size) {
		auto values = (T *)values_target_ptr;
		uint32_t values_read = 0;

		while (values_read < batch_size) {
			if (repeat_count_ > 0) {
				int repeat_batch = MinValue(batch_size - values_read, static_cast<uint32_t>(repeat_count_));
				std::fill(values + values_read, values + values_read + repeat_batch, static_cast<T>(current_value_));
				repeat_count_ -= repeat_batch;
				values_read += repeat_batch;
			} else if (literal_count_ > 0) {
				uint32_t literal_batch = MinValue(batch_size - values_read, static_cast<uint32_t>(literal_count_));
				uint32_t actual_read = ParquetDecodeUtils::BitUnpack<T>(buffer_, bitpack_pos, values + values_read,
				                                                        literal_batch, bit_width_);
				if (literal_batch != actual_read) {
					throw std::runtime_error("Did not find enough values");
				}
				literal_count_ -= literal_batch;
				values_read += literal_batch;
			} else {
				if (!NextCounts<T>()) {
					if (values_read != batch_size) {
						throw std::runtime_error("RLE decode did not find enough values");
					}
					return;
				}
			}
		}
		if (values_read != batch_size) {
			throw std::runtime_error("RLE decode did not find enough values");
		}
	}

	static uint8_t ComputeBitWidth(idx_t val) {
		if (val == 0) {
			return 0;
		}
		uint8_t ret = 1;
		while (((idx_t)(1 << ret) - 1) < val) {
			ret++;
		}
		return ret;
	}

private:
	ByteBuffer buffer_;

	/// Number of bits needed to encode the value. Must be between 0 and 64.
	uint32_t bit_width_;
	uint64_t current_value_;
	uint32_t repeat_count_;
	uint32_t literal_count_;
	uint8_t byte_encoded_len;
	uint64_t max_val;

	uint8_t bitpack_pos = 0;

	/// Fills literal_count_ and repeat_count_ with next values. Returns false if there
	/// are no more.
	template <typename T>
	bool NextCounts() {
		// Read the next run's indicator int, it could be a literal or repeated run.
		// The int is encoded as a vlq-encoded value.
		if (bitpack_pos != 0) {
			buffer_.inc(1);
			bitpack_pos = 0;
		}
		auto indicator_value = ParquetDecodeUtils::VarintDecode<uint32_t>(buffer_);

		// lsb indicates if it is a literal run or repeated run
		bool is_literal = indicator_value & 1;
		if (is_literal) {
			literal_count_ = (indicator_value >> 1) * 8;
		} else {
			repeat_count_ = indicator_value >> 1;
			// (ARROW-4018) this is not big-endian compatible, lol
			current_value_ = 0;
			for (auto i = 0; i < byte_encoded_len; i++) {
				current_value_ |= (buffer_.read<uint8_t>() << (i * 8));
			}
			// sanity check
			if (repeat_count_ > 0 && current_value_ > max_val) {
				throw std::runtime_error("Payload value bigger than allowed. Corrupted file?");
			}
		}
		// TODO complain if we run out of buffer
		return true;
	}
};
} // namespace duckdb




namespace duckdb {
class DbpDecoder {
public:
	DbpDecoder(const uint8_t *buffer, uint32_t buffer_len) : buffer_((char *)buffer, buffer_len) {

		//<block size in values> <number of miniblocks in a block> <total value count> <first value>
		// overall header
		block_value_count = ParquetDecodeUtils::VarintDecode<uint64_t>(buffer_);
		miniblocks_per_block = ParquetDecodeUtils::VarintDecode<uint64_t>(buffer_);
		total_value_count = ParquetDecodeUtils::VarintDecode<uint64_t>(buffer_);
		start_value = ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode<int64_t>(buffer_));

		// some derivatives
		values_per_miniblock = block_value_count / miniblocks_per_block;
		miniblock_bit_widths = std::unique_ptr<uint8_t[]>(new data_t[miniblocks_per_block]);

		// init state to something sane
		values_left_in_block = 0;
		values_left_in_miniblock = 0;
		miniblock_offset = 0;
		min_delta = 0;
		bitpack_pos = 0;
		is_first_value = true;
	};

	ByteBuffer BufferPtr() {
		if (bitpack_pos != 0) {
			buffer_.inc(1);
			bitpack_pos = 0;
		}
		return buffer_;
	}

	template <typename T>
	void GetBatch(char *values_target_ptr, uint32_t batch_size) {
		auto values = (T *)values_target_ptr;

		if (batch_size == 0) {
			return;
		}
		idx_t value_offset = 0;

		if (is_first_value) {
			values[0] = start_value;
			value_offset++;
			is_first_value = false;
		}

		if (total_value_count == 1) { // I guess it's a special case
			if (batch_size > 1) {
				throw std::runtime_error("DBP decode did not find enough values (have 1)");
			}
			return;
		}

		while (value_offset < batch_size) {
			if (values_left_in_block == 0) { // need to open new block
				if (bitpack_pos > 0) {       // have to eat the leftovers if any
					buffer_.inc(1);
				}
				min_delta = ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode<uint64_t>(buffer_));
				for (idx_t miniblock_idx = 0; miniblock_idx < miniblocks_per_block; miniblock_idx++) {
					miniblock_bit_widths[miniblock_idx] = buffer_.read<uint8_t>();
					// TODO what happens if width is 0?
				}
				values_left_in_block = block_value_count;
				miniblock_offset = 0;
				bitpack_pos = 0;
				values_left_in_miniblock = values_per_miniblock;
			}
			if (values_left_in_miniblock == 0) {
				miniblock_offset++;
				values_left_in_miniblock = values_per_miniblock;
			}

			auto read_now = MinValue(values_left_in_miniblock, (idx_t)batch_size - value_offset);
			ParquetDecodeUtils::BitUnpack<T>(buffer_, bitpack_pos, &values[value_offset], read_now,
			                                 miniblock_bit_widths[miniblock_offset]);
			for (idx_t i = value_offset; i < value_offset + read_now; i++) {
				values[i] = ((i == 0) ? start_value : values[i - 1]) + min_delta + values[i];
			}
			value_offset += read_now;
			values_left_in_miniblock -= read_now;
			values_left_in_block -= read_now;
		}

		if (value_offset != batch_size) {
			throw std::runtime_error("DBP decode did not find enough values");
		}
		start_value = values[batch_size - 1];
	}

private:
	ByteBuffer buffer_;
	idx_t block_value_count;
	idx_t miniblocks_per_block;
	idx_t total_value_count;
	int64_t start_value;
	idx_t values_per_miniblock;

	std::unique_ptr<uint8_t[]> miniblock_bit_widths;
	idx_t values_left_in_block;
	idx_t values_left_in_miniblock;
	idx_t miniblock_offset;
	int64_t min_delta;

	bool is_first_value;

	uint8_t bitpack_pos;
};
} // namespace duckdb



#include "duckdb.hpp"
#ifndef DUCKDB_AMALGAMATION
#include "duckdb/storage/statistics/base_statistics.hpp"
#endif


namespace duckdb {

using duckdb_parquet::format::ColumnChunk;
using duckdb_parquet::format::SchemaElement;

struct LogicalType;

struct ParquetStatisticsUtils {

	static unique_ptr<BaseStatistics> TransformColumnStatistics(const SchemaElement &s_ele, const LogicalType &type,
	                                                            const ColumnChunk &column_chunk);

	static Value ConvertValue(const LogicalType &type, const duckdb_parquet::format::SchemaElement &schema_ele,
	                          const std::string &stats);
};

} // namespace duckdb


#include "duckdb.hpp"
#ifndef DUCKDB_AMALGAMATION
#include "duckdb/storage/statistics/string_statistics.hpp"
#include "duckdb/storage/statistics/numeric_statistics.hpp"
#include "duckdb/common/types/vector.hpp"
#include "duckdb/common/types/string_type.hpp"
#include "duckdb/common/types/chunk_collection.hpp"
#include "duckdb/common/operator/cast_operators.hpp"
#include "duckdb/common/types/vector_cache.hpp"
#endif

namespace duckdb {
class ParquetReader;

using duckdb_apache::thrift::protocol::TProtocol;

using duckdb_parquet::format::ColumnChunk;
using duckdb_parquet::format::FieldRepetitionType;
using duckdb_parquet::format::PageHeader;
using duckdb_parquet::format::SchemaElement;
using duckdb_parquet::format::Type;

typedef std::bitset<STANDARD_VECTOR_SIZE> parquet_filter_t;

class ColumnReader {
public:
	ColumnReader(ParquetReader &reader, LogicalType type_p, const SchemaElement &schema_p, idx_t file_idx_p,
	             idx_t max_define_p, idx_t max_repeat_p);
	virtual ~ColumnReader();

public:
	static unique_ptr<ColumnReader> CreateReader(ParquetReader &reader, const LogicalType &type_p,
	                                             const SchemaElement &schema_p, idx_t schema_idx_p, idx_t max_define,
	                                             idx_t max_repeat);
	virtual void InitializeRead(const std::vector<ColumnChunk> &columns, TProtocol &protocol_p);
	virtual idx_t Read(uint64_t num_values, parquet_filter_t &filter, uint8_t *define_out, uint8_t *repeat_out,
	                   Vector &result_out);

	virtual void Skip(idx_t num_values);

	ParquetReader &Reader();
	const LogicalType &Type() const;
	const SchemaElement &Schema() const;
	idx_t FileIdx() const;
	idx_t MaxDefine() const;
	idx_t MaxRepeat() const;

	virtual idx_t FileOffset() const;
	virtual uint64_t TotalCompressedSize();
	virtual idx_t GroupRowsAvailable();

	// register the range this reader will touch for prefetching
	virtual void RegisterPrefetch(ThriftFileTransport &transport, bool allow_merge);

	virtual unique_ptr<BaseStatistics> Stats(const std::vector<ColumnChunk> &columns);

protected:
	// readers that use the default Read() need to implement those
	virtual void Plain(shared_ptr<ByteBuffer> plain_data, uint8_t *defines, idx_t num_values, parquet_filter_t &filter,
	                   idx_t result_offset, Vector &result);
	virtual void Dictionary(shared_ptr<ByteBuffer> dictionary_data, idx_t num_entries);
	virtual void Offsets(uint32_t *offsets, uint8_t *defines, idx_t num_values, parquet_filter_t &filter,
	                     idx_t result_offset, Vector &result);

	// these are nops for most types, but not for strings
	virtual void DictReference(Vector &result);
	virtual void PlainReference(shared_ptr<ByteBuffer>, Vector &result);

	// applies any skips that were registered using Skip()
	virtual void ApplyPendingSkips(idx_t num_values);

	bool HasDefines() {
		return max_define > 0;
	}

	bool HasRepeats() {
		return max_repeat > 0;
	}

protected:
	const SchemaElement &schema;

	idx_t file_idx;
	idx_t max_define;
	idx_t max_repeat;

	ParquetReader &reader;
	LogicalType type;

	idx_t pending_skips = 0;

private:
	void PrepareRead(parquet_filter_t &filter);
	void PreparePage(idx_t compressed_page_size, idx_t uncompressed_page_size);
	void PrepareDataPage(PageHeader &page_hdr);
	void PreparePageV2(PageHeader &page_hdr);

	const duckdb_parquet::format::ColumnChunk *chunk = nullptr;

	duckdb_apache::thrift::protocol::TProtocol *protocol;
	idx_t page_rows_available;
	idx_t group_rows_available;
	idx_t chunk_read_offset;

	shared_ptr<ResizeableBuffer> block;

	ResizeableBuffer offset_buffer;

	unique_ptr<RleBpDecoder> dict_decoder;
	unique_ptr<RleBpDecoder> defined_decoder;
	unique_ptr<RleBpDecoder> repeated_decoder;
	unique_ptr<DbpDecoder> dbp_decoder;

	// dummies for Skip()
	parquet_filter_t none_filter;
	ResizeableBuffer dummy_define;
	ResizeableBuffer dummy_repeat;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// parquet_file_metadata_cache.hpp
//
//
//===----------------------------------------------------------------------===//


#include "duckdb.hpp"
#ifndef DUCKDB_AMALGAMATION
#include "duckdb/storage/object_cache.hpp"
#endif


namespace duckdb {

//! ParquetFileMetadataCache
class ParquetFileMetadataCache : public ObjectCacheEntry {
public:
	ParquetFileMetadataCache() : metadata(nullptr) {
	}
	ParquetFileMetadataCache(std::unique_ptr<duckdb_parquet::format::FileMetaData> file_metadata, time_t r_time)
	    : metadata(std::move(file_metadata)), read_time(r_time) {
	}

	~ParquetFileMetadataCache() override = default;

	//! Parquet file metadata
	std::unique_ptr<const duckdb_parquet::format::FileMetaData> metadata;

	//! read time
	time_t read_time;

public:
	static string ObjectType() {
		return "parquet_metadata";
	}

	string GetObjectType() override {
		return ObjectType();
	}
};
} // namespace duckdb





#include <exception>

namespace duckdb_parquet {
namespace format {
class FileMetaData;
}
} // namespace duckdb_parquet

namespace duckdb {
class Allocator;
class ClientContext;
class ChunkCollection;
class BaseStatistics;
class TableFilterSet;

struct ParquetReaderPrefetchConfig {
	// Percentage of data in a row group span that should be scanned for enabling whole group prefetch
	static constexpr double WHOLE_GROUP_PREFETCH_MINIMUM_SCAN = 0.95;
};

struct ParquetReaderScanState {
	vector<idx_t> group_idx_list;
	int64_t current_group;
	vector<column_t> column_ids;
	idx_t group_offset;
	unique_ptr<FileHandle> file_handle;
	unique_ptr<ColumnReader> root_reader;
	unique_ptr<duckdb_apache::thrift::protocol::TProtocol> thrift_file_proto;

	bool finished;
	TableFilterSet *filters;
	SelectionVector sel;

	ResizeableBuffer define_buf;
	ResizeableBuffer repeat_buf;

	bool prefetch_mode = false;
	bool current_group_prefetched = false;
};

struct ParquetOptions {
	explicit ParquetOptions() {
	}
	explicit ParquetOptions(ClientContext &context);

	bool binary_as_string = false;
};

class ParquetReader {
public:
	ParquetReader(Allocator &allocator, unique_ptr<FileHandle> file_handle_p,
	              const vector<LogicalType> &expected_types_p, const string &initial_filename_p = string());
	ParquetReader(Allocator &allocator, unique_ptr<FileHandle> file_handle_p)
	    : ParquetReader(allocator, std::move(file_handle_p), vector<LogicalType>(), string()) {
	}

	ParquetReader(ClientContext &context, string file_name, const vector<string> &names,
	              const vector<LogicalType> &expected_types_p, const vector<column_t> &column_ids,
	              ParquetOptions parquet_options, const string &initial_filename = string());
	ParquetReader(ClientContext &context, string file_name, ParquetOptions parquet_options)
	    : ParquetReader(context, std::move(file_name), vector<string>(), vector<LogicalType>(), vector<column_t>(),
	                    parquet_options, string()) {
	}
	ParquetReader(ClientContext &context, string file_name, const vector<LogicalType> &expected_types_p,
	              ParquetOptions parquet_options)
	    : ParquetReader(context, std::move(file_name), vector<string>(), expected_types_p, vector<column_t>(),
	                    parquet_options, string()) {
	}
	~ParquetReader();

	Allocator &allocator;
	string file_name;
	FileOpener *file_opener;
	vector<LogicalType> return_types;
	vector<string> names;
	shared_ptr<ParquetFileMetadataCache> metadata;
	ParquetOptions parquet_options;

public:
	void InitializeScan(ParquetReaderScanState &state, vector<column_t> column_ids, vector<idx_t> groups_to_read,
	                    TableFilterSet *table_filters);
	void Scan(ParquetReaderScanState &state, DataChunk &output);

	idx_t NumRows();
	idx_t NumRowGroups();

	const duckdb_parquet::format::FileMetaData *GetFileMetadata();

	static unique_ptr<BaseStatistics> ReadStatistics(ParquetReader &reader, LogicalType &type, column_t column_index,
	                                                 const duckdb_parquet::format::FileMetaData *file_meta_data);
	static LogicalType DeriveLogicalType(const SchemaElement &s_ele, bool binary_as_string);

private:
	void InitializeSchema(const vector<string> &names, const vector<LogicalType> &expected_types_p,
	                      const vector<column_t> &column_ids, const string &initial_filename_p);
	bool ScanInternal(ParquetReaderScanState &state, DataChunk &output);
	unique_ptr<ColumnReader> CreateReader(const duckdb_parquet::format::FileMetaData *file_meta_data);

	unique_ptr<ColumnReader> CreateReaderRecursive(const duckdb_parquet::format::FileMetaData *file_meta_data,
	                                               idx_t depth, idx_t max_define, idx_t max_repeat,
	                                               idx_t &next_schema_idx, idx_t &next_file_idx);
	const duckdb_parquet::format::RowGroup &GetGroup(ParquetReaderScanState &state);
	uint64_t GetGroupCompressedSize(ParquetReaderScanState &state);
	idx_t GetGroupOffset(ParquetReaderScanState &state);
	// Group span is the distance between the min page offset and the max page offset plus the max page compressed size
	uint64_t GetGroupSpan(ParquetReaderScanState &state);
	void PrepareRowGroupBuffer(ParquetReaderScanState &state, idx_t out_col_idx);
	LogicalType DeriveLogicalType(const SchemaElement &s_ele);

	template <typename... Args>
	std::runtime_error FormatException(const string fmt_str, Args... params) {
		return std::runtime_error("Failed to read Parquet file \"" + file_name +
		                          "\": " + StringUtil::Format(fmt_str, params...));
	}

private:
	unique_ptr<FileHandle> file_handle;
	//! column-id map, used when reading multiple parquet files since separate parquet files might have columns at
	//! different positions e.g. the first file might have column "a" at position 0, the second at position 1, etc
	vector<column_t> column_id_map;
	//! Map of column_id -> cast, used when reading multiple parquet files when parquet files have diverging types
	//! for the same column
	unordered_map<column_t, LogicalType> cast_map;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// parquet_writer.hpp
//
//
//===----------------------------------------------------------------------===//



#include "duckdb.hpp"
#ifndef DUCKDB_AMALGAMATION
#include "duckdb/common/common.hpp"
#include "duckdb/common/exception.hpp"
#include "duckdb/common/mutex.hpp"
#include "duckdb/common/serializer/buffered_file_writer.hpp"
#include "duckdb/common/types/chunk_collection.hpp"
#endif


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// column_writer.hpp
//
//
//===----------------------------------------------------------------------===//



#include "duckdb.hpp"


namespace duckdb {
class BufferedSerializer;
class ParquetWriter;
class ColumnWriterPageState;
class StandardColumnWriterState;

class ColumnWriterState {
public:
	virtual ~ColumnWriterState();

	vector<uint16_t> definition_levels;
	vector<uint16_t> repetition_levels;
	vector<bool> is_empty;
};

class ColumnWriterStatistics {
public:
	virtual ~ColumnWriterStatistics();

	virtual string GetMin();
	virtual string GetMax();
	virtual string GetMinValue();
	virtual string GetMaxValue();
};

class ColumnWriter {
	//! We limit the uncompressed page size to 100MB
	// The max size in Parquet is 2GB, but we choose a more conservative limit
	static constexpr const idx_t MAX_UNCOMPRESSED_PAGE_SIZE = 100000000;

public:
	ColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector<string> schema_path, idx_t max_repeat,
	             idx_t max_define, bool can_have_nulls);
	virtual ~ColumnWriter();

	ParquetWriter &writer;
	idx_t schema_idx;
	vector<string> schema_path;
	idx_t max_repeat;
	idx_t max_define;
	bool can_have_nulls;
	// collected stats
	idx_t null_count;

public:
	//! Create the column writer for a specific type recursively
	static unique_ptr<ColumnWriter> CreateWriterRecursive(vector<duckdb_parquet::format::SchemaElement> &schemas,
	                                                      ParquetWriter &writer, const LogicalType &type,
	                                                      const string &name, vector<string> schema_path,
	                                                      idx_t max_repeat = 0, idx_t max_define = 1,
	                                                      bool can_have_nulls = true);

	virtual unique_ptr<ColumnWriterState> InitializeWriteState(duckdb_parquet::format::RowGroup &row_group);
	virtual void Prepare(ColumnWriterState &state, ColumnWriterState *parent, Vector &vector, idx_t count);

	virtual void BeginWrite(ColumnWriterState &state);
	virtual void Write(ColumnWriterState &state, Vector &vector, idx_t count);
	virtual void FinalizeWrite(ColumnWriterState &state);

protected:
	void HandleDefineLevels(ColumnWriterState &state, ColumnWriterState *parent, ValidityMask &validity, idx_t count,
	                        uint16_t define_value, uint16_t null_value);
	void HandleRepeatLevels(ColumnWriterState &state_p, ColumnWriterState *parent, idx_t count, idx_t max_repeat);

	void WriteLevels(Serializer &temp_writer, const vector<uint16_t> &levels, idx_t max_value, idx_t start_offset,
	                 idx_t count);

	virtual duckdb_parquet::format::Encoding::type GetEncoding();

	void NextPage(ColumnWriterState &state_p);
	void FlushPage(ColumnWriterState &state_p);
	void WriteDictionary(ColumnWriterState &state_p, unique_ptr<BufferedSerializer> temp_writer, idx_t row_count);

	virtual void FlushDictionary(ColumnWriterState &state, ColumnWriterStatistics *stats);

	//! Initializes the state used to track statistics during writing. Only used for scalar types.
	virtual unique_ptr<ColumnWriterStatistics> InitializeStatsState();
	//! Retrieves the row size of a vector at the specified location. Only used for scalar types.
	virtual idx_t GetRowSize(Vector &vector, idx_t index);
	//! Writes a (subset of a) vector to the specified serializer. Only used for scalar types.
	virtual void WriteVector(Serializer &temp_writer, ColumnWriterStatistics *stats, ColumnWriterPageState *page_state,
	                         Vector &vector, idx_t chunk_start, idx_t chunk_end);

	//! Initialize the writer for a specific page. Only used for scalar types.
	virtual unique_ptr<ColumnWriterPageState> InitializePageState();
	//! Flushes the writer for a specific page. Only used for scalar types.
	virtual void FlushPageState(Serializer &temp_writer, ColumnWriterPageState *state);

	void CompressPage(BufferedSerializer &temp_writer, size_t &compressed_size, data_ptr_t &compressed_data,
	                  unique_ptr<data_t[]> &compressed_buf);

	void SetParquetStatistics(StandardColumnWriterState &state, duckdb_parquet::format::ColumnChunk &column);
};

} // namespace duckdb



namespace duckdb {
class FileSystem;
class FileOpener;

class ParquetWriter {
	friend class ColumnWriter;
	friend class ListColumnWriter;
	friend class StructColumnWriter;

public:
	ParquetWriter(FileSystem &fs, string file_name, FileOpener *file_opener, vector<LogicalType> types,
	              vector<string> names, duckdb_parquet::format::CompressionCodec::type codec);

public:
	void Flush(ChunkCollection &buffer);
	void Finalize();

	static duckdb_parquet::format::Type::type DuckDBTypeToParquetType(const LogicalType &duckdb_type);
	static void SetSchemaProperties(const LogicalType &duckdb_type, duckdb_parquet::format::SchemaElement &schema_ele);

private:
	string file_name;
	vector<LogicalType> sql_types;
	vector<string> column_names;
	duckdb_parquet::format::CompressionCodec::type codec;

	unique_ptr<BufferedFileWriter> writer;
	shared_ptr<duckdb_apache::thrift::protocol::TProtocol> protocol;
	duckdb_parquet::format::FileMetaData file_meta_data;
	std::mutex lock;

	vector<unique_ptr<ColumnWriter>> column_writers;
};

} // namespace duckdb
