/*
 * Copyright (c) 2008, 2024, Oracle and/or its affiliates.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2.0, as
 * published by the Free Software Foundation.
 *
 * This program is designed to work with certain software (including
 * but not limited to OpenSSL) that is licensed under separate terms, as
 * designated in a particular file or component or in included license
 * documentation. The authors of MySQL hereby grant you an additional
 * permission to link the program and your derivative works with the
 * separately licensed software that they have either included with
 * the program or referenced in the documentation.
 *
 * Without limiting anything contained in the foregoing, this file,
 * which is part of Connector/C++, is also subject to the
 * Universal FOSS Exception, version 1.0, a copy of which can be found at
 * https://oss.oracle.com/licenses/universal-foss-exception.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License, version 2.0, for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */



#ifndef _MYSQL_UTIL_H_
#define _MYSQL_UTIL_H_

#include "nativeapi/mysql_private_iface.h"
#include <cppconn/config.h>
#include <cppconn/sqlstring.h>
#include <cppconn/exception.h>
#include <memory>


#ifndef UL64
#ifdef _WIN32
#define UL64(x) x##ui64
#else
#define UL64(x) x##ULL
#endif
#endif

#ifndef L64
#ifdef _WIN32
#define L64(x) x##i64
#else
#define L64(x) x##LL
#endif
#endif

#define NULLCSTR static_cast<char *>(0)

#ifndef _WIN32
#  ifndef HAVE_FUNCTION_STRTOLL
#    define strtoll(__a, __b, __c)  static_cast<long long>(sql::mysql::util::strtold((__a), NULL))
#    define HAVE_FUNCTION_STRTOLL 1
#  endif
#  ifndef HAVE_FUNCTION_STRTOULL
#    define strtoull(__a, __b, __c)  static_cast<unsigned long long>(sql::mysql::util::strtold((__a), NULL))
#    define HAVE_FUNCTION_STRTOULL 1
#  endif
#else
# ifndef strtoll
#  define strtoll(x, e, b) _strtoi64((x), (e), (b))
# endif
# ifndef strtoull
#  define strtoull(x, e, b) _strtoui64((x), (e), (b))
# endif
#endif	//	_WIN32


#define bit_uint1korr(A)	(*(((uint8_t*)(A))))

#define bit_uint2korr(A) ((uint16_t) (((uint16_t) (((unsigned char*) (A))[1])) +\
                                   ((uint16_t) (((unsigned char*) (A))[0]) << 8)))
#define bit_uint3korr(A) ((uint32_t) (((uint32_t) (((unsigned char*) (A))[2])) +\
                                   (((uint32_t) (((unsigned char*) (A))[1])) << 8) +\
                                   (((uint32_t) (((unsigned char*) (A))[0])) << 16)))
#define bit_uint4korr(A) ((uint32_t) (((uint32_t) (((unsigned char*) (A))[3])) +\
                                   (((uint32_t) (((unsigned char*) (A))[2])) << 8) +\
                                   (((uint32_t) (((unsigned char*) (A))[1])) << 16) +\
                                   (((uint32_t) (((unsigned char*) (A))[0])) << 24)))
#define bit_uint5korr(A) ((uint64_t)(((uint32_t) (((unsigned char*) (A))[4])) +\
                                    (((uint32_t) (((unsigned char*) (A))[3])) << 8) +\
                                    (((uint32_t) (((unsigned char*) (A))[2])) << 16) +\
                                   (((uint32_t) (((unsigned char*) (A))[1])) << 24)) +\
                                    (((uint64_t) (((unsigned char*) (A))[0])) << 32))
#define bit_uint6korr(A) ((uint64_t)(((uint32_t) (((unsigned char*) (A))[5])) +\
                                    (((uint32_t) (((unsigned char*) (A))[4])) << 8) +\
                                    (((uint32_t) (((unsigned char*) (A))[3])) << 16) +\
                                    (((uint32_t) (((unsigned char*) (A))[2])) << 24)) +\
                        (((uint64_t) (((uint32_t) (((unsigned char*) (A))[1])) +\
                                    (((uint32_t) (((unsigned char*) (A))[0]) << 8)))) <<\
                                     32))
#define bit_uint7korr(A) ((uint64_t)(((uint32_t) (((unsigned char*) (A))[6])) +\
                                    (((uint32_t) (((unsigned char*) (A))[5])) << 8) +\
                                    (((uint32_t) (((unsigned char*) (A))[4])) << 16) +\
                                   (((uint32_t) (((unsigned char*) (A))[3])) << 24)) +\
                        (((uint64_t) (((uint32_t) (((unsigned char*) (A))[2])) +\
                                    (((uint32_t) (((unsigned char*) (A))[1])) << 8) +\
                                    (((uint32_t) (((unsigned char*) (A))[0])) << 16))) <<\
                                     32))
#define bit_uint8korr(A) ((uint64_t)(((uint32_t) (((unsigned char*) (A))[7])) +\
                                    (((uint32_t) (((unsigned char*) (A))[6])) << 8) +\
                                    (((uint32_t) (((unsigned char*) (A))[5])) << 16) +\
                                    (((uint32_t) (((unsigned char*) (A))[4])) << 24)) +\
                        (((uint64_t) (((uint32_t) (((unsigned char*) (A))[3])) +\
                                    (((uint32_t) (((unsigned char*) (A))[2])) << 8) +\
                                    (((uint32_t) (((unsigned char*) (A))[1])) << 16) +\
                                    (((uint32_t) (((unsigned char*) (A))[0])) << 24))) <<\
                                    32))

#if (__GNUC__ >= 7) && (__cplusplus == 201103L)
  #define FALLTHROUGH [[gnu::fallthrough]];
#elif (__cplusplus > 201103L)
  #define FALLTHROUGH [[fallthrough]];
#else
  #define FALLTHROUGH
#endif

/*
  Macros used to disable warnings for fragments of code.
*/

#if defined __GNUC__ || defined __clang__

#define PRAGMA(X) _Pragma(#X)
#define DISABLE_WARNING(W) PRAGMA(GCC diagnostic ignored #W)

#if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#define DIAGNOSTIC_PUSH PRAGMA(GCC diagnostic push)
#define DIAGNOSTIC_POP  PRAGMA(GCC diagnostic pop)
#else
#define DIAGNOSTIC_PUSH
#define DIAGNOSTIC_POP
#endif

#elif defined _MSC_VER


#define PRAGMA(X) __pragma(X)
#define DISABLE_WARNING(W) PRAGMA(warning (disable:W))

#define DIAGNOSTIC_PUSH  PRAGMA(warning (push))
#define DIAGNOSTIC_POP   PRAGMA(warning (pop))

#else

#define PRAGMA(X)
#define DISABLE_WARNING(W)

#define DIAGNOSTIC_PUSH
#define DIAGNOSTIC_POP

#endif


/*
  NO_WARNINGS_PUSH/POP macros are intended to locally disable warnings
  for example when including 3-rd party headers (however, it should not be used
  for std library headers -- we should ensure they are used in a way that does
  not generate any warnings)
*/

#if defined _MSC_VER

#define NO_WARNINGS_PUSH  PRAGMA(warning (push,0))
#define NO_WARNINGS_POP   PRAGMA(warning (pop))

#else

#define NO_WARNINGS_PUSH  DIAGNOSTIC_PUSH \
  DISABLE_WARNING(-Wall) DISABLE_WARNING(-Wextra) DISABLE_WARNING(-Wcpp)
#define NO_WARNINGS_POP   DIAGNOSTIC_POP

#endif




namespace sql
{
namespace mysql
{

class MySQL_DebugLogger;

namespace NativeAPI
{
class NativeConnectionWrapper;
class NativeStatementWrapper;
} /* namespace NativeAPI */


namespace util {

extern const char *EMPTYSTR;
extern const char *LOCALHOST;

void throwSQLException(::sql::mysql::NativeAPI::NativeConnectionWrapper & proxy);
void throwSQLException(::sql::mysql::NativeAPI::NativeStatementWrapper & proxy);

int mysql_string_type_to_datatype(const sql::SQLString & name);
int mysql_type_to_datatype(const MYSQL_FIELD * const fieldm,
                           unsigned long server_version);
const char *mysql_type_to_string(
    const MYSQL_FIELD *const field,
    std::shared_ptr<sql::mysql::MySQL_DebugLogger> &l);

char * utf8_strup(const char * const src, size_t srclen);

long double strtold(const char *nptr, char **endptr);

/*
  Generic string to number conversion function template.

  Retrurns numeric value after converting given string in a given base,
  which should be either 10, 16 or 8. Throws error if the whole string
  could not be converted to a number.

  Unlike strtod() and friends, this function does not depend on the current
  locale setting but always uses the "C" locale (so that, e.g., decimal point
  character is always '.').
*/

long double strtonum(const std::string &str, int radix = 10);

typedef struct st_our_charset
{
  unsigned int	nr;
  const char		*name;
  const char		*collation;
  unsigned int	char_minlen;
  unsigned int	char_maxlen;
  const char		*comment;
  unsigned int 	(*mb_charlen)(unsigned int c);
  unsigned int 	(*mb_valid)(const char *start, const char *end);
} OUR_CHARSET;

const OUR_CHARSET * find_charset(unsigned int charsetnr);

class nocopy {
 public:
  nocopy(const nocopy &) = delete;
  nocopy &operator=(const nocopy &) = delete;

 protected:
  nocopy() {}
};

} /* namespace util */
} /* namespace mysql */
} /* namespace sql */

#endif /* _MYSQL_UTIL_H_ */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
