commit ac07fbf306004b5ebc648d0ba0f298369911aa62 Author: JDierkse Date: Sun Feb 9 16:32:42 2020 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a201fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.o.* +*.d.* +*.a.* +.*.swp +.AppleDouble +lib +Libraries diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7da2786 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Makefiles"] + path = Makefiles + url = https://gogs.dierkse.nl/JDierkse/Makefiles.git diff --git a/Makefile b/Makefile new file mode 120000 index 0000000..6aa5187 --- /dev/null +++ b/Makefile @@ -0,0 +1 @@ +Makefiles/Makefile \ No newline at end of file diff --git a/Makefile.conf b/Makefile.conf new file mode 100644 index 0000000..ded1ce8 --- /dev/null +++ b/Makefile.conf @@ -0,0 +1,6 @@ +# +# Makefile.conf +# + +CFLAGS += -I$(ROOTPATH) -I$(ROOTPATH)/include -I$(ROOTPATH)/Libraries/Logging/include +DEBUGDIR := .debug diff --git a/Makefile.target b/Makefile.target new file mode 100644 index 0000000..af751b1 --- /dev/null +++ b/Makefile.target @@ -0,0 +1,12 @@ +# +# Makefile.target +# + +MySQL.a.$(ARCH) : $(OBJECTS) + $(call build_target_library_arch,$@,$^) +MySQL.a: + $(call build_target,$@) + +.DEFAULT_GOAL := MySQL.a + +TARGETS += MySQL.a diff --git a/Makefiles b/Makefiles new file mode 160000 index 0000000..61894c4 --- /dev/null +++ b/Makefiles @@ -0,0 +1 @@ +Subproject commit 61894c4588eb2b85e342a6f923eeb7ac97c3fe64 diff --git a/MySQL/Makefile b/MySQL/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/MySQL/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/MySQL/MySQLClient.cpp b/MySQL/MySQLClient.cpp new file mode 100644 index 0000000..a3678b5 --- /dev/null +++ b/MySQL/MySQLClient.cpp @@ -0,0 +1,46 @@ +#include "MySQLClient.h" +#include "MySQLClientImpl.h" + + +namespace MySQL { + +MySQLClient::MySQLClient() : + m_pMySQLClientImpl(new MySQLClientImpl()) +{ +} + +MySQLClient::~MySQLClient() +{ +} + +void MySQLClient::Connect(const std::string& hostname, const std::string& username, const std::string& password) +{ + m_pMySQLClientImpl->Connect(hostname, username, password); +} + +void MySQLClient::Connect(const std::string& hostname, const std::string& username, const std::string& password, const std::string& database) +{ + m_pMySQLClientImpl->Connect(hostname, username, password, database); +} + +void MySQLClient::Disconnect() +{ + m_pMySQLClientImpl->Disconnect(); +} + +std::string MySQLClient::Database() const +{ + return m_pMySQLClientImpl->Database(); +} + +void MySQLClient::Execute(const std::string& query) const +{ + m_pMySQLClientImpl->Execute(query); +} + +MySQLResultSet MySQLClient::ExecuteQuery(const std::string& query) const +{ + return MySQLResultSet(m_pMySQLClientImpl->ExecuteQuery(query)); +} + +} // namespace MySQL diff --git a/MySQL/MySQLClientImpl.cpp b/MySQL/MySQLClientImpl.cpp new file mode 100644 index 0000000..362b237 --- /dev/null +++ b/MySQL/MySQLClientImpl.cpp @@ -0,0 +1,123 @@ +#include "MySQLClientImpl.h" +#include "MySQLResultSetImpl.h" +#include "Logging.h" +#include + + +namespace MySQL { + +MySQLClientImpl::MySQLClientImpl() : + m_connected(false), + m_pDriver(sql::mysql::get_mysql_driver_instance()) +{ +} + +MySQLClientImpl::~MySQLClientImpl() +{ +} + +void MySQLClientImpl::Connect(const std::string& hostname, const std::string& username, const std::string& password) +{ + std::unique_lock lock(m_mutex); + try + { + if (m_pConnection) + Disconnect(); + + std::stringstream ss; + ss << "tcp://" << hostname << ":3306"; + + m_pConnection = std::shared_ptr(m_pDriver->connect(ss.str(), username, password)); + m_database = ""; + m_connected = true; + } + catch (sql::SQLException &e) + { + std::stringstream ss; + ss << "MySQLClientImpl::Connect() - Error: " << e.what() << std::endl; + Logging::Log(Logging::Severity::Error, ss.str()); + } +} + +void MySQLClientImpl::Connect(const std::string& hostname, const std::string& username, const std::string& password, const std::string& database) +{ + std::unique_lock lock(m_mutex); + try + { + if (m_pConnection) + Disconnect(); + + std::stringstream ss; + ss << "tcp://" << hostname << ":3306/" << database; + + m_pConnection = std::shared_ptr(m_pDriver->connect(ss.str(), username, password)); + m_database = database; + m_connected = true; + } + catch (sql::SQLException &e) + { + std::stringstream ss; + ss << "MySQLClientImpl::Connect() - Error: " << e.what() << std::endl; + Logging::Log(Logging::Severity::Error, ss.str()); + } +} + +void MySQLClientImpl::Disconnect() +{ + std::unique_lock lock(m_mutex); + m_pConnection.reset(); + m_database = ""; + m_connected = false; +} + +std::string MySQLClientImpl::Database() const +{ + if (!m_connected) + return std::string(); + return m_database; +} + +void MySQLClientImpl::Execute(const std::string& query) const +{ + std::unique_lock lock(m_mutex); + if (!m_connected) + throw std::runtime_error("MySQLClientImpl::ExecuteQuery() - Not connected to a Database Server"); + + try + { + std::unique_ptr statement(m_pConnection->createStatement()); + statement->execute(query); + } + catch (sql::SQLException &e) + { + std::stringstream ss; + ss << "MySQLClientImpl::Execute() - Error: " << e.what() << std::endl; + ss << "Query: " << query << std::endl; + Logging::Log(Logging::Severity::Error, ss.str()); + } +} + +std::shared_ptr MySQLClientImpl::ExecuteQuery(const std::string& query) const +{ + std::unique_lock lock(m_mutex); + if (!m_connected) + throw std::runtime_error("MySQLClientImpl::ExecuteQuery() - Not connected to a Database Server"); + + try + { + std::unique_ptr statement(m_pConnection->createStatement()); + std::shared_ptr pResult(statement->executeQuery(query)); + return std::make_shared(pResult); + } + catch (sql::SQLException &e) + { + std::stringstream ss; + ss << "MySQLClientImpl::ExecuteQuery() - Error: " << e.what() << std::endl; + ss << "Query: " << query << std::endl; + Logging::Log(Logging::Severity::Error, ss.str()); + } + + return std::make_shared(nullptr); +} + +} // namespace MySQL diff --git a/MySQL/MySQLClientImpl.h b/MySQL/MySQLClientImpl.h new file mode 100644 index 0000000..a6909b2 --- /dev/null +++ b/MySQL/MySQLClientImpl.h @@ -0,0 +1,42 @@ +#ifndef MYSQL_MYSQLCLIENTIMPL_H +#define MYSQL_MYSQLCLIENTIMPL_H + +#include "MySQLResultSetImpl.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace MySQL { + +class MySQLClientImpl +{ +public: + MySQLClientImpl(); + ~MySQLClientImpl(); + + void Connect(const std::string& hostname, const std::string& username, const std::string& password); + void Connect(const std::string& hostname, const std::string& username, const std::string& password, const std::string& database); + void Disconnect(); + + std::string Database() const; + + void Execute(const std::string& query) const; + std::shared_ptr ExecuteQuery(const std::string& query) const; + +private: + mutable std::mutex m_mutex; + bool m_connected; + std::string m_database; + sql::mysql::MySQL_Driver* m_pDriver; + std::shared_ptr m_pConnection; +}; + +} // namespace MySQL + +#endif // MYSQL_MYSQLCLIENTIMPL_H diff --git a/MySQL/MySQLResultSet.cpp b/MySQL/MySQLResultSet.cpp new file mode 100644 index 0000000..45840b8 --- /dev/null +++ b/MySQL/MySQLResultSet.cpp @@ -0,0 +1,306 @@ +#include "MySQLResultSet.h" +#include "MySQLResultSetImpl.h" + + +namespace MySQL { + +MySQLResultSet::MySQLResultSet() : + m_pMySQLResultSetImpl(new MySQLResultSetImpl()) +{ +} + +MySQLResultSet::MySQLResultSet(std::shared_ptr pMySQLResultSetImpl) : + m_pMySQLResultSetImpl(pMySQLResultSetImpl) +{ +} + +MySQLResultSet::~MySQLResultSet() +{ +} + +bool MySQLResultSet::Absolute(int row) +{ + return m_pMySQLResultSetImpl->Absolute(row); +} + +void MySQLResultSet::AfterLast() +{ + m_pMySQLResultSetImpl->AfterLast(); +} + +void MySQLResultSet::BeforeFirst() +{ + m_pMySQLResultSetImpl->BeforeFirst(); +} + +void MySQLResultSet::CancelRowUpdates() +{ + m_pMySQLResultSetImpl->CancelRowUpdates(); +} + +void MySQLResultSet::ClearWarnings() +{ + m_pMySQLResultSetImpl->ClearWarnings(); +} + +void MySQLResultSet::Close() +{ + m_pMySQLResultSetImpl->Close(); +} + +uint32_t MySQLResultSet::FindColumn(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->FindColumn(columnLabel); +} + +bool MySQLResultSet::First() +{ + return m_pMySQLResultSetImpl->First(); +} + +std::istream* MySQLResultSet::Blob(uint32_t columnIndex) const +{ + return m_pMySQLResultSetImpl->Blob(columnIndex); +} + +std::istream* MySQLResultSet::Blob(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->Blob(columnLabel); +} + +bool MySQLResultSet::Boolean(uint32_t columnIndex) const +{ + return m_pMySQLResultSetImpl->Boolean(columnIndex); +} + +bool MySQLResultSet::Boolean(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->Boolean(columnLabel); +} + +int MySQLResultSet::Concurrency() +{ + return m_pMySQLResultSetImpl->Concurrency(); +} + +std::string MySQLResultSet::CursorName() +{ + return m_pMySQLResultSetImpl->CursorName(); +} + +long double MySQLResultSet::Double(uint32_t columnIndex) const +{ + return m_pMySQLResultSetImpl->Double(columnIndex); +} + +long double MySQLResultSet::Double(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->Double(columnLabel); +} + +int MySQLResultSet::FetchDirection() +{ + return m_pMySQLResultSetImpl->FetchDirection(); +} + +size_t MySQLResultSet::FetchSize() +{ + return m_pMySQLResultSetImpl->FetchSize(); +} + +int MySQLResultSet::Holdability() +{ + return m_pMySQLResultSetImpl->Holdability(); +} + +int32_t MySQLResultSet::Int(uint32_t columnIndex) const +{ + return m_pMySQLResultSetImpl->Int(columnIndex); +} + +int32_t MySQLResultSet::Int(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->Int(columnLabel); +} + +uint32_t MySQLResultSet::UInt(uint32_t columnIndex) const +{ + return m_pMySQLResultSetImpl->UInt(columnIndex); +} + +uint32_t MySQLResultSet::UInt(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->UInt(columnLabel); +} + +int64_t MySQLResultSet::Int64(uint32_t columnIndex) const +{ + return m_pMySQLResultSetImpl->Int64(columnIndex); +} + +int64_t MySQLResultSet::Int64(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->Int64(columnLabel); +} + +uint64_t MySQLResultSet::UInt64(uint32_t columnIndex) const +{ + return m_pMySQLResultSetImpl->UInt64(columnIndex); +} + +uint64_t MySQLResultSet::UInt64(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->UInt64(columnLabel); +} + +MySQLResultSetMetaData MySQLResultSet::MetaData() const +{ + return MySQLResultSetMetaData(m_pMySQLResultSetImpl->MetaData()); +} + +size_t MySQLResultSet::Row() const +{ + return m_pMySQLResultSetImpl->Row(); +} +/* +RowID* MySQLResultSet::RowId(uint32_t columnIndex) +{ + return m_pMySQLResultSetImpl->RowId(columnIndex); +} + +RowID* MySQLResultSet::RowId(const std::string & columnLabel) +{ + return m_pMySQLResultSetImpl->RowId(columnLabel); +} + +const Statement* MySQLResultSet::Statement() const +{ + return m_pMySQLResultSetImpl->Statement(); +} +*/ +std::string MySQLResultSet::String(uint32_t columnIndex) const +{ + return m_pMySQLResultSetImpl->String(columnIndex); +} + +std::string MySQLResultSet::String(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->String(columnLabel); +} +/* +enum_type MySQLResultSet::Type() const +{ + return m_pMySQLResultSetImpl->Type(); +} +*/ +void MySQLResultSet::Warnings() +{ + m_pMySQLResultSetImpl->Warnings(); +} + +void MySQLResultSet::InsertRow() +{ + m_pMySQLResultSetImpl->InsertRow(); +} + +bool MySQLResultSet::IsAfterLast() const +{ + return m_pMySQLResultSetImpl->IsAfterLast(); +} + +bool MySQLResultSet::IsBeforeFirst() const +{ + return m_pMySQLResultSetImpl->IsBeforeFirst(); +} + +bool MySQLResultSet::IsClosed() const +{ + return m_pMySQLResultSetImpl->IsClosed(); +} + +bool MySQLResultSet::IsFirst() const +{ + return m_pMySQLResultSetImpl->IsFirst(); +} + +bool MySQLResultSet::IsLast() const +{ + return m_pMySQLResultSetImpl->IsLast(); +} + +bool MySQLResultSet::IsNull(uint32_t columnIndex) const +{ + return m_pMySQLResultSetImpl->IsNull(columnIndex); +} + +bool MySQLResultSet::IsNull(const std::string& columnLabel) const +{ + return m_pMySQLResultSetImpl->IsNull(columnLabel); +} + +bool MySQLResultSet::Last() +{ + return m_pMySQLResultSetImpl->Last(); +} + +bool MySQLResultSet::Next() +{ + return m_pMySQLResultSetImpl->Next(); +} + +void MySQLResultSet::MoveToCurrentRow() +{ + m_pMySQLResultSetImpl->MoveToCurrentRow(); +} + +void MySQLResultSet::MoveToInsertRow() +{ + m_pMySQLResultSetImpl->MoveToInsertRow(); +} + +bool MySQLResultSet::Previous() +{ + return m_pMySQLResultSetImpl->Previous(); +} + +void MySQLResultSet::RefreshRow() +{ + m_pMySQLResultSetImpl->RefreshRow(); +} + +bool MySQLResultSet::Relative(int rows) +{ + return m_pMySQLResultSetImpl->Relative(rows); +} + +bool MySQLResultSet::RowDeleted() +{ + return m_pMySQLResultSetImpl->RowDeleted(); +} + +bool MySQLResultSet::RowInserted() +{ + return m_pMySQLResultSetImpl->RowInserted(); +} + +bool MySQLResultSet::RowUpdated() +{ + return m_pMySQLResultSetImpl->RowUpdated(); +} + +void MySQLResultSet::FetchSize(size_t rows) +{ + return m_pMySQLResultSetImpl->FetchSize(rows); +} + +size_t MySQLResultSet::RowsCount() const +{ + return m_pMySQLResultSetImpl->RowsCount(); +} + +bool MySQLResultSet::WasNull() const +{ + return m_pMySQLResultSetImpl->WasNull(); +} + +} // namespace MySQL diff --git a/MySQL/MySQLResultSetImpl.cpp b/MySQL/MySQLResultSetImpl.cpp new file mode 100644 index 0000000..88c39d9 --- /dev/null +++ b/MySQL/MySQLResultSetImpl.cpp @@ -0,0 +1,478 @@ +#include "MySQLResultSetImpl.h" +#include "MySQLResultSetMetaDataImpl.h" +#include +#include + + +namespace MySQL { + +MySQLResultSetImpl::MySQLResultSetImpl() +{ +} + +MySQLResultSetImpl::MySQLResultSetImpl(const std::shared_ptr& pResultSet) : + m_pResultSet(pResultSet) +{ +} + +MySQLResultSetImpl::~MySQLResultSetImpl() +{ +} + +bool MySQLResultSetImpl::Absolute(int row) +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->absolute(row); +} + +void MySQLResultSetImpl::AfterLast() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->afterLast(); +} + +void MySQLResultSetImpl::BeforeFirst() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->beforeFirst(); +} + +void MySQLResultSetImpl::CancelRowUpdates() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->cancelRowUpdates(); +} + +void MySQLResultSetImpl::ClearWarnings() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->clearWarnings(); +} + +void MySQLResultSetImpl::Close() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->close(); +} + +uint32_t MySQLResultSetImpl::FindColumn(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->findColumn(columnLabel); +} + +bool MySQLResultSetImpl::First() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->first(); +} + +std::istream* MySQLResultSetImpl::Blob(uint32_t columnIndex) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getBlob(columnIndex); +} + +std::istream* MySQLResultSetImpl::Blob(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getBlob(columnLabel); +} + +bool MySQLResultSetImpl::Boolean(uint32_t columnIndex) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getBoolean(columnIndex); +} + +bool MySQLResultSetImpl::Boolean(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getBoolean(columnLabel); +} + +int MySQLResultSetImpl::Concurrency() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getConcurrency(); +} + +std::string MySQLResultSetImpl::CursorName() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getCursorName(); +} + +long double MySQLResultSetImpl::Double(uint32_t columnIndex) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getDouble(columnIndex); +} + +long double MySQLResultSetImpl::Double(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getDouble(columnLabel); +} + +int MySQLResultSetImpl::FetchDirection() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getFetchDirection(); +} + +size_t MySQLResultSetImpl::FetchSize() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getFetchSize(); +} + +int MySQLResultSetImpl::Holdability() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getHoldability(); +} + +int32_t MySQLResultSetImpl::Int(uint32_t columnIndex) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getInt(columnIndex); +} + +int32_t MySQLResultSetImpl::Int(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getInt(columnLabel); +} + +uint32_t MySQLResultSetImpl::UInt(uint32_t columnIndex) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getUInt(columnIndex); +} + +uint32_t MySQLResultSetImpl::UInt(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getUInt(columnLabel); +} + +int64_t MySQLResultSetImpl::Int64(uint32_t columnIndex) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getInt64(columnIndex); +} + +int64_t MySQLResultSetImpl::Int64(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getInt64(columnLabel); +} + +uint64_t MySQLResultSetImpl::UInt64(uint32_t columnIndex) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getUInt64(columnIndex); +} + +uint64_t MySQLResultSetImpl::UInt64(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getUInt64(columnLabel); +} + +std::shared_ptr MySQLResultSetImpl::MetaData() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return std::make_shared(m_pResultSet->getMetaData()); +} + +size_t MySQLResultSetImpl::Row() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getRow(); +} +/* +RowID* MySQLResultSetImpl::RowId(uint32_t columnIndex) +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getRowId(columnIndex); +} + +RowID* MySQLResultSetImpl::RowId(const std::string & columnLabel) +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getRowId(columnLabel); +} + +const Statement* Statement() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getStatement(); +} +*/ +std::string MySQLResultSetImpl::String(uint32_t columnIndex) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getString(columnIndex); +} + +std::string MySQLResultSetImpl::String(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getString(columnLabel); +} +/* +enum_type MySQLResultSetImpl::Type() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->getType(); +} +*/ +void MySQLResultSetImpl::Warnings() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->getWarnings(); +} + +void MySQLResultSetImpl::InsertRow() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->insertRow(); +} + +bool MySQLResultSetImpl::IsAfterLast() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->isAfterLast(); +} + +bool MySQLResultSetImpl::IsBeforeFirst() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->isBeforeFirst(); +} + +bool MySQLResultSetImpl::IsClosed() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->isClosed(); +} + +bool MySQLResultSetImpl::IsFirst() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->isFirst(); +} + +bool MySQLResultSetImpl::IsLast() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->isLast(); +} + +bool MySQLResultSetImpl::IsNull(uint32_t columnIndex) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->isNull(columnIndex); +} + +bool MySQLResultSetImpl::IsNull(const std::string& columnLabel) const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->isNull(columnLabel); +} + +bool MySQLResultSetImpl::Last() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->last(); +} + +bool MySQLResultSetImpl::Next() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->next(); +} + +void MySQLResultSetImpl::MoveToCurrentRow() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->moveToCurrentRow(); +} + +void MySQLResultSetImpl::MoveToInsertRow() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->moveToInsertRow(); +} + +bool MySQLResultSetImpl::Previous() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->previous(); +} + +void MySQLResultSetImpl::RefreshRow() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->refreshRow(); +} + +bool MySQLResultSetImpl::Relative(int rows) +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->relative(rows); +} + +bool MySQLResultSetImpl::RowDeleted() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->rowDeleted(); +} + +bool MySQLResultSetImpl::RowInserted() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->rowInserted(); +} + +bool MySQLResultSetImpl::RowUpdated() +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->rowUpdated(); +} + +void MySQLResultSetImpl::FetchSize(size_t rows) +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + m_pResultSet->setFetchSize(rows); +} + +size_t MySQLResultSetImpl::RowsCount() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->rowsCount(); +} + +bool MySQLResultSetImpl::WasNull() const +{ + if (!m_pResultSet) + throw std::runtime_error("Empty Result"); + + return m_pResultSet->wasNull(); +} + +} // namespace MySQL diff --git a/MySQL/MySQLResultSetImpl.h b/MySQL/MySQLResultSetImpl.h new file mode 100644 index 0000000..ce98515 --- /dev/null +++ b/MySQL/MySQLResultSetImpl.h @@ -0,0 +1,85 @@ +#ifndef MYSQL_MYSQLRESULTSETIMPL_H +#define MYSQL_MYSQLRESULTSETIMPL_H + +#include "MySQLResultSetMetaDataImpl.h" +#include +#include +#include +#include + + +namespace MySQL { + +class MySQLResultSetImpl +{ +public: + MySQLResultSetImpl(); + explicit MySQLResultSetImpl(const std::shared_ptr& pResultSet); + ~MySQLResultSetImpl(); + +public: + bool Absolute(int row); + void AfterLast(); + void BeforeFirst(); + void CancelRowUpdates(); + void ClearWarnings(); + void Close(); + uint32_t FindColumn(const std::string& columnLabel) const; + bool First(); + std::istream* Blob(uint32_t columnIndex) const; + std::istream* Blob(const std::string& columnLabel) const; + bool Boolean(uint32_t columnIndex) const; + bool Boolean(const std::string& columnLabel) const; + int Concurrency(); + std::string CursorName(); + long double Double(uint32_t columnIndex) const; + long double Double(const std::string& columnLabel) const; + int FetchDirection(); + size_t FetchSize(); + int Holdability(); + int32_t Int(uint32_t columnIndex) const; + int32_t Int(const std::string& columnLabel) const; + uint32_t UInt(uint32_t columnIndex) const; + uint32_t UInt(const std::string& columnLabel) const; + int64_t Int64(uint32_t columnIndex) const; + int64_t Int64(const std::string& columnLabel) const; + uint64_t UInt64(uint32_t columnIndex) const; + uint64_t UInt64(const std::string& columnLabel) const; + std::shared_ptr MetaData() const; + size_t Row() const; + //RowID* RowId(uint32_t columnIndex); + //RowID* RowId(const std::string & columnLabel); + //const Statement* Statement() const; + std::string String(uint32_t columnIndex) const; + std::string String(const std::string& columnLabel) const; + //enum_type Type() const; + void Warnings(); + void InsertRow(); + bool IsAfterLast() const; + bool IsBeforeFirst() const; + bool IsClosed() const; + bool IsFirst() const; + bool IsLast() const; + bool IsNull(uint32_t columnIndex) const; + bool IsNull(const std::string& columnLabel) const; + bool Last(); + bool Next(); + void MoveToCurrentRow(); + void MoveToInsertRow(); + bool Previous(); + void RefreshRow(); + bool Relative(int rows); + bool RowDeleted(); + bool RowInserted(); + bool RowUpdated(); + void FetchSize(size_t rows); + size_t RowsCount() const; + bool WasNull() const; + +private: + std::shared_ptr m_pResultSet; +}; + +} // namespace MySQL + +#endif // MYSQL_MYSQLRESULTSETIMPL_H diff --git a/MySQL/MySQLResultSetMetaData.cpp b/MySQL/MySQLResultSetMetaData.cpp new file mode 100644 index 0000000..85fb319 --- /dev/null +++ b/MySQL/MySQLResultSetMetaData.cpp @@ -0,0 +1,131 @@ +#include "MySQLResultSetMetaData.h" +#include "MySQLResultSetMetaDataImpl.h" + + +namespace MySQL { + +MySQLResultSetMetaData::MySQLResultSetMetaData() : + m_pMySQLResultSetMetaDataImpl(new MySQLResultSetMetaDataImpl()) +{ +} + +MySQLResultSetMetaData::MySQLResultSetMetaData(std::shared_ptr pMySQLResultSetMetaDataImpl) : + m_pMySQLResultSetMetaDataImpl(pMySQLResultSetMetaDataImpl) +{ +} + +MySQLResultSetMetaData::~MySQLResultSetMetaData() +{ +} + +std::string MySQLResultSetMetaData::CatalogName(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->CatalogName(column); +} + +uint32_t MySQLResultSetMetaData::ColumnCount() +{ + return m_pMySQLResultSetMetaDataImpl->ColumnCount(); +} + +uint32_t MySQLResultSetMetaData::ColumnDisplaySize(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->ColumnDisplaySize(column); +} + +std::string MySQLResultSetMetaData::ColumnLabel(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->ColumnLabel(column); +} + +std::string MySQLResultSetMetaData::ColumnName(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->ColumnName(column); +} + +int MySQLResultSetMetaData::ColumnType(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->ColumnType(column); +} + +std::string MySQLResultSetMetaData::ColumnTypeName(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->ColumnTypeName(column); +} + +uint32_t MySQLResultSetMetaData::Precision(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->Precision(column); +} + +uint32_t MySQLResultSetMetaData::Scale(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->Scale(column); +} + +std::string MySQLResultSetMetaData::SchemaName(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->SchemaName(column); +} + +std::string MySQLResultSetMetaData::TableName(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->TableName(column); +} + +bool MySQLResultSetMetaData::AutoIncrement(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->AutoIncrement(column); +} + +bool MySQLResultSetMetaData::CaseSensitive(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->CaseSensitive(column); +} + +bool MySQLResultSetMetaData::Currency(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->Currency(column); +} + +bool MySQLResultSetMetaData::DefinitelyWritable(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->DefinitelyWritable(column); +} + +int MySQLResultSetMetaData::Nullable(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->Nullable(column); +} + +bool MySQLResultSetMetaData::Numeric(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->Numeric(column); +} + +bool MySQLResultSetMetaData::ReadOnly(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->ReadOnly(column); +} + +bool MySQLResultSetMetaData::Searchable(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->Searchable(column); +} + +bool MySQLResultSetMetaData::Signed(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->Signed(column); +} + +bool MySQLResultSetMetaData::Writable(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->Writable(column); +} + +bool MySQLResultSetMetaData::Zerofill(uint32_t column) +{ + return m_pMySQLResultSetMetaDataImpl->Zerofill(column); +} + +} // namespace MySQL diff --git a/MySQL/MySQLResultSetMetaDataImpl.cpp b/MySQL/MySQLResultSetMetaDataImpl.cpp new file mode 100644 index 0000000..7160d1b --- /dev/null +++ b/MySQL/MySQLResultSetMetaDataImpl.cpp @@ -0,0 +1,196 @@ +#include "MySQLResultSetMetaDataImpl.h" +#include + + +namespace MySQL { + +MySQLResultSetMetaDataImpl::MySQLResultSetMetaDataImpl() +{ +} + +MySQLResultSetMetaDataImpl::MySQLResultSetMetaDataImpl(sql::ResultSetMetaData* pResultSetMetaData) : + m_pResultSetMetaData(pResultSetMetaData) +{ +} + +MySQLResultSetMetaDataImpl::~MySQLResultSetMetaDataImpl() +{ +} + +std::string MySQLResultSetMetaDataImpl::CatalogName(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getCatalogName(column); +} + +uint32_t MySQLResultSetMetaDataImpl::ColumnCount() +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getColumnCount(); +} + +uint32_t MySQLResultSetMetaDataImpl::ColumnDisplaySize(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getColumnDisplaySize(column); +} + +std::string MySQLResultSetMetaDataImpl::ColumnLabel(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getColumnLabel(column); +} + +std::string MySQLResultSetMetaDataImpl::ColumnName(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getColumnName(column); +} + +int MySQLResultSetMetaDataImpl::ColumnType(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getColumnType(column); +} + +std::string MySQLResultSetMetaDataImpl::ColumnTypeName(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getColumnTypeName(column); +} + +uint32_t MySQLResultSetMetaDataImpl::Precision(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getPrecision(column); +} + +uint32_t MySQLResultSetMetaDataImpl::Scale(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getScale(column); +} + +std::string MySQLResultSetMetaDataImpl::SchemaName(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getSchemaName(column); +} + +std::string MySQLResultSetMetaDataImpl::TableName(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->getTableName(column); +} + +bool MySQLResultSetMetaDataImpl::AutoIncrement(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isAutoIncrement(column); +} + +bool MySQLResultSetMetaDataImpl::CaseSensitive(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isCaseSensitive(column); +} + +bool MySQLResultSetMetaDataImpl::Currency(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isCurrency(column); +} + +bool MySQLResultSetMetaDataImpl::DefinitelyWritable(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isDefinitelyWritable(column); +} + +int MySQLResultSetMetaDataImpl::Nullable(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isNullable(column); +} + +bool MySQLResultSetMetaDataImpl::Numeric(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isNumeric(column); +} + +bool MySQLResultSetMetaDataImpl::ReadOnly(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isReadOnly(column); +} + +bool MySQLResultSetMetaDataImpl::Searchable(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isSearchable(column); +} + +bool MySQLResultSetMetaDataImpl::Signed(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isSigned(column); +} + +bool MySQLResultSetMetaDataImpl::Writable(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isWritable(column); +} + +bool MySQLResultSetMetaDataImpl::Zerofill(uint32_t column) +{ + if (!m_pResultSetMetaData) + throw std::runtime_error("No Metadata for Result"); + + return m_pResultSetMetaData->isZerofill(column); +} + +} // namespace MySQL diff --git a/MySQL/MySQLResultSetMetaDataImpl.h b/MySQL/MySQLResultSetMetaDataImpl.h new file mode 100644 index 0000000..9e18012 --- /dev/null +++ b/MySQL/MySQLResultSetMetaDataImpl.h @@ -0,0 +1,48 @@ +#ifndef MYSQL_MYSQLRESULTSETMETADATAIMPL_H +#define MYSQL_MYSQLRESULTSETMETADATAIMPL_H + +#include +#include +#include + + +namespace MySQL { + +class MySQLResultSetMetaDataImpl +{ +public: + MySQLResultSetMetaDataImpl(); + explicit MySQLResultSetMetaDataImpl(sql::ResultSetMetaData* pResultSetMetaData); + ~MySQLResultSetMetaDataImpl(); + +public: + std::string CatalogName(uint32_t column); + uint32_t ColumnCount(); + uint32_t ColumnDisplaySize(uint32_t column); + std::string ColumnLabel(uint32_t column); + std::string ColumnName(uint32_t column); + int ColumnType(uint32_t column); + std::string ColumnTypeName(uint32_t column); + uint32_t Precision(uint32_t column); + uint32_t Scale(uint32_t column); + std::string SchemaName(uint32_t column); + std::string TableName(uint32_t column); + bool AutoIncrement(uint32_t column); + bool CaseSensitive(uint32_t column); + bool Currency(uint32_t column); + bool DefinitelyWritable(uint32_t column); + int Nullable(uint32_t column); + bool Numeric(uint32_t column); + bool ReadOnly(uint32_t column); + bool Searchable(uint32_t column); + bool Signed(uint32_t column); + bool Writable(uint32_t column); + bool Zerofill(uint32_t column); + +private: + sql::ResultSetMetaData* m_pResultSetMetaData; +}; + +} // namespace MySQL + +#endif // MYSQL_MYSQLRESULTSETMETADATAIMPL_H diff --git a/include/MySQLClient.h b/include/MySQLClient.h new file mode 100644 index 0000000..262286f --- /dev/null +++ b/include/MySQLClient.h @@ -0,0 +1,34 @@ +#ifndef MYSQLCLIENT_H +#define MYSQLCLIENT_H + +#include "MySQLResultSet.h" +#include +#include + + +namespace MySQL { + +class MySQLClientImpl; + +class MySQLClient +{ +public: + MySQLClient(); + ~MySQLClient(); + + void Connect(const std::string& hostname, const std::string& username, const std::string& password); + void Connect(const std::string& hostname, const std::string& username, const std::string& password, const std::string& database); + void Disconnect(); + + std::string Database() const; + + void Execute(const std::string& query) const; + MySQLResultSet ExecuteQuery(const std::string& query) const; + +private: + std::unique_ptr m_pMySQLClientImpl; +}; + +} // namespace MySQL + +#endif // MYSQLCLIENT_H diff --git a/include/MySQLResultSet.h b/include/MySQLResultSet.h new file mode 100644 index 0000000..aefd693 --- /dev/null +++ b/include/MySQLResultSet.h @@ -0,0 +1,91 @@ +#ifndef MYSQLRESULTSET_H +#define MYSQLRESULTSET_H + +#include "MySQLResultSetMetaData.h" +#include +#include + + +namespace MySQL { + +class MySQLResultSetImpl; + +class MySQLResultSet +{ +public: + MySQLResultSet(); + ~MySQLResultSet(); + +public: + bool Absolute(int row); + void AfterLast(); + void BeforeFirst(); + void CancelRowUpdates(); + void ClearWarnings(); + void Close(); + uint32_t FindColumn(const std::string& columnLabel) const; + bool First(); + std::istream* Blob(uint32_t columnIndex) const; + std::istream* Blob(const std::string& columnLabel) const; + bool Boolean(uint32_t columnIndex) const; + bool Boolean(const std::string& columnLabel) const; + int Concurrency(); + std::string CursorName(); + long double Double(uint32_t columnIndex) const; + long double Double(const std::string& columnLabel) const; + int FetchDirection(); + size_t FetchSize(); + int Holdability(); + int32_t Int(uint32_t columnIndex) const; + int32_t Int(const std::string& columnLabel) const; + uint32_t UInt(uint32_t columnIndex) const; + uint32_t UInt(const std::string& columnLabel) const; + int64_t Int64(uint32_t columnIndex) const; + int64_t Int64(const std::string& columnLabel) const; + uint64_t UInt64(uint32_t columnIndex) const; + uint64_t UInt64(const std::string& columnLabel) const; + MySQLResultSetMetaData MetaData() const; + size_t Row() const; + //RowID* RowId(uint32_t columnIndex); + //RowID* RowId(const std::string & columnLabel); + //const Statement* Statement() const; + std::string String(uint32_t columnIndex) const; + std::string String(const std::string& columnLabel) const; + //enum_type Type() const; + void Warnings(); + void InsertRow(); + bool IsAfterLast() const; + bool IsBeforeFirst() const; + bool IsClosed() const; + bool IsFirst() const; + bool IsLast() const; + bool IsNull(uint32_t columnIndex) const; + bool IsNull(const std::string& columnLabel) const; + bool Last(); + bool Next(); + void MoveToCurrentRow(); + void MoveToInsertRow(); + bool Previous(); + void RefreshRow(); + bool Relative(int rows); + bool RowDeleted(); + bool RowInserted(); + bool RowUpdated(); + void FetchSize(size_t rows); + size_t RowsCount() const; + bool WasNull() const; + +private: + MySQLResultSet(std::shared_ptr pMySQLResultSetImpl); + +private: + friend class MySQLClient; + friend class MySQLClientImpl; + +private: + std::shared_ptr m_pMySQLResultSetImpl; +}; + +} // namespace MySQL + +#endif // MYSQLRESULTSET_H diff --git a/include/MySQLResultSetMetaData.h b/include/MySQLResultSetMetaData.h new file mode 100644 index 0000000..99762ed --- /dev/null +++ b/include/MySQLResultSetMetaData.h @@ -0,0 +1,56 @@ +#ifndef MYSQLRESULTSETMETADATA_H +#define MYSQLRESULTSETMETADATA_H + +#include +#include + + +namespace MySQL { + +class MySQLResultSet; +class MySQLResultSetMetaDataImpl; + +class MySQLResultSetMetaData +{ +public: + MySQLResultSetMetaData(); + ~MySQLResultSetMetaData(); + +public: + std::string CatalogName(uint32_t column); + uint32_t ColumnCount(); + uint32_t ColumnDisplaySize(uint32_t column); + std::string ColumnLabel(uint32_t column); + std::string ColumnName(uint32_t column); + int ColumnType(uint32_t column); + std::string ColumnTypeName(uint32_t column); + uint32_t Precision(uint32_t column); + uint32_t Scale(uint32_t column); + std::string SchemaName(uint32_t column); + std::string TableName(uint32_t column); + bool AutoIncrement(uint32_t column); + bool CaseSensitive(uint32_t column); + bool Currency(uint32_t column); + bool DefinitelyWritable(uint32_t column); + int Nullable(uint32_t column); + bool Numeric(uint32_t column); + bool ReadOnly(uint32_t column); + bool Searchable(uint32_t column); + bool Signed(uint32_t column); + bool Writable(uint32_t column); + bool Zerofill(uint32_t column); + +private: + MySQLResultSetMetaData(std::shared_ptr pMySQLResultSetMetaDataImpl); + +private: + friend class MySQLResultSet; + friend class MySQLResultSetMetaDataImpl; + +private: + std::shared_ptr m_pMySQLResultSetMetaDataImpl; +}; + +} // namespace MySQL + +#endif // MYSQLRESULTSETMETADATA_H