database.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #ifndef KOPANO_DATABASE_HPP
  2. #define KOPANO_DATABASE_HPP 1
  3. #include <mutex>
  4. #include <string>
  5. #include <utility>
  6. #include <mysql.h>
  7. #include <kopano/zcdefs.h>
  8. #include <kopano/kcodes.h>
  9. namespace KC {
  10. typedef char **DB_ROW;
  11. typedef unsigned long *DB_LENGTHS;
  12. typedef unsigned int DB_ERROR;
  13. enum {
  14. DB_E_UNKNOWN = -1,
  15. DB_E_LOCK_WAIT_TIMEOUT = 1,
  16. DB_E_LOCK_DEADLOCK = 2,
  17. };
  18. enum {
  19. /*
  20. * The maximum packet size. This is automatically also the maximum size
  21. * of a single entry in the database. This means that PR_BODY,
  22. * PR_COMPRESSED_RTF etc. cannot grow larger than 16M. This shouldn't
  23. * be such a problem in practice.
  24. *
  25. * In Debian Lenny, setting your max_allowed_packet to 16M actually
  26. * gives this value.... Unknown why.
  27. */
  28. KC_DFL_MAX_PACKET_SIZE = 16776192,
  29. };
  30. struct sSQLDatabase_t {
  31. const char *lpComment;
  32. const char *lpSQL;
  33. };
  34. class KDatabase;
  35. class _kc_export DB_RESULT _kc_final {
  36. public:
  37. DB_RESULT(void) = default;
  38. DB_RESULT(KDatabase *d, void *r) : m_res(r), m_db(d) {}
  39. DB_RESULT(DB_RESULT &&o) = default;
  40. ~DB_RESULT(void);
  41. void operator=(DB_RESULT &&o)
  42. {
  43. std::swap(m_res, o.m_res);
  44. std::swap(m_db, o.m_db);
  45. }
  46. operator bool(void) const { return m_res != nullptr; }
  47. bool operator==(std::nullptr_t) const { return m_res == nullptr; }
  48. bool operator!=(std::nullptr_t) const { return m_res != nullptr; }
  49. void *get(void) const { return m_res; }
  50. void *release(void)
  51. {
  52. void *p = m_res;
  53. m_res = nullptr;
  54. return p;
  55. }
  56. private:
  57. void *m_res = nullptr;
  58. KDatabase *m_db = nullptr;
  59. };
  60. class _kc_export KDatabase {
  61. public:
  62. KDatabase(void);
  63. virtual ~KDatabase(void) _kc_impdtor;
  64. ECRESULT Close(void);
  65. virtual ECRESULT Connect(ECConfig *, bool, unsigned int, unsigned int);
  66. virtual ECRESULT CreateDatabase(ECConfig *, bool);
  67. virtual ECRESULT DoDelete(const std::string &query, unsigned int *affect = nullptr);
  68. virtual ECRESULT DoInsert(const std::string &query, unsigned int *insert_id = nullptr, unsigned int *affect = nullptr);
  69. virtual ECRESULT DoSelect(const std::string &query, DB_RESULT *, bool stream = false);
  70. /* Sequence generator - Do not call this from within a transaction. */
  71. virtual ECRESULT DoSequence(const std::string &seq, unsigned int count, unsigned long long *first_id);
  72. virtual ECRESULT DoUpdate(const std::string &query, unsigned int *affect = nullptr);
  73. std::string Escape(const std::string &);
  74. std::string EscapeBinary(const unsigned char *, size_t);
  75. std::string EscapeBinary(const std::string &);
  76. DB_ROW FetchRow(DB_RESULT &);
  77. DB_LENGTHS FetchRowLengths(DB_RESULT &);
  78. const char *GetError(void);
  79. DB_ERROR GetLastError(void);
  80. unsigned int GetMaxAllowedPacket(void) const { return m_ulMaxAllowedPacket; }
  81. unsigned int GetNumRows(const DB_RESULT &) const;
  82. /*
  83. * Transactions.
  84. * These functions should be used to wrap blocks of queries into
  85. * transactions. This will speed up writes a lot, so try to use them as
  86. * much as possible. If you don't start a transaction then each INSERT
  87. * or UPDATE will automatically be a single transaction, causing an
  88. * fsync after each write-query, which is not fast to say the least.
  89. */
  90. virtual ECRESULT Begin(void) { return Query("BEGIN") == 0 ? erSuccess : KCERR_DATABASE_ERROR; }
  91. virtual ECRESULT Commit(void) { return Query("COMMIT") == 0 ? erSuccess : KCERR_DATABASE_ERROR; }
  92. virtual ECRESULT Rollback(void) { return Query("ROLLBACK") == 0 ? erSuccess : KCERR_DATABASE_ERROR; }
  93. protected:
  94. class autolock : private std::unique_lock<std::recursive_mutex> {
  95. public:
  96. autolock(KDatabase &p) :
  97. std::unique_lock<std::recursive_mutex>(p.m_hMutexMySql, std::defer_lock_t())
  98. {
  99. if (p.m_bAutoLock)
  100. lock();
  101. }
  102. };
  103. unsigned int GetAffectedRows(void);
  104. virtual const struct sSQLDatabase_t *GetDatabaseDefs(void) = 0;
  105. unsigned int GetInsertId(void);
  106. ECRESULT InitEngine(bool reconnect);
  107. bool isConnected(void) const { return m_bConnected; }
  108. ECRESULT IsInnoDBSupported(void);
  109. virtual ECRESULT Query(const std::string &q);
  110. ECRESULT _Update(const std::string &q, unsigned int *affected);
  111. MYSQL m_lpMySQL;
  112. unsigned int m_ulMaxAllowedPacket = KC_DFL_MAX_PACKET_SIZE;
  113. bool m_bMysqlInitialize = false, m_bConnected = false;
  114. bool m_bSuppressLockErrorLogging = false;
  115. private:
  116. void FreeResult_internal(void *);
  117. std::recursive_mutex m_hMutexMySql;
  118. bool m_bAutoLock = true;
  119. friend class DB_RESULT;
  120. };
  121. } /* namespace */
  122. #endif /* KOPANO_DATABASE_HPP */