summaryrefslogtreecommitdiff
path: root/libmysqlpp/my-connection.cpp
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-12-23 23:15:18 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2015-12-23 23:15:18 +0000
commitf268aec98176049136bceb2741f3615841e5c516 (patch)
tree79b980073c32aa1bb08988d06151d194b4ac104c /libmysqlpp/my-connection.cpp
parentUse a b2 lib for mysql (diff)
downloadlibdbpp-mysql-f268aec98176049136bceb2741f3615841e5c516.tar.bz2
libdbpp-mysql-f268aec98176049136bceb2741f3615841e5c516.tar.xz
libdbpp-mysql-f268aec98176049136bceb2741f3615841e5c516.zip
MySQL files prefixed with my-
Diffstat (limited to 'libmysqlpp/my-connection.cpp')
-rw-r--r--libmysqlpp/my-connection.cpp269
1 files changed, 269 insertions, 0 deletions
diff --git a/libmysqlpp/my-connection.cpp b/libmysqlpp/my-connection.cpp
new file mode 100644
index 0000000..3e1aed3
--- /dev/null
+++ b/libmysqlpp/my-connection.cpp
@@ -0,0 +1,269 @@
+#include "my-connection.h"
+#include "my-error.h"
+#include "my-selectcommand.h"
+#include "my-modifycommand.h"
+#include <nvpParse.h>
+#include <runtimeContext.h>
+#include <ucontext.h>
+#include <boost/optional.hpp>
+
+NAMEDFACTORY("mysql", MySQL::Connection, DB::ConnectionFactory);
+
+class Opts {
+ public:
+ Opts() { port = 3306; }
+ typedef boost::optional<std::string> OptString;
+ OptString server;
+ OptString user;
+ OptString password;
+ OptString database;
+ unsigned int port;
+ OptString unix_socket;
+ OptString options;
+};
+
+const char *
+operator~(const Opts::OptString & os)
+{
+ if (os) {
+ return os->c_str();
+ }
+ return NULL;
+}
+
+namespace std {
+ template <typename T>
+ std::istream &
+ operator>>(std::istream & s, boost::optional<T> & o)
+ {
+ o = T();
+ return (s >> *o);
+ }
+}
+
+using namespace AdHoc;
+NvpTarget(Opts) OptsTargetMap {
+ NvpValue(Opts, server),
+ NvpValue(Opts, user),
+ NvpValue(Opts, password),
+ NvpValue(Opts, database),
+ NvpValue(Opts, unix_socket),
+ NvpValue(Opts, port),
+ NvpValue(Opts, options),
+};
+
+
+MySQL::Connection::Connection(const std::string & str) :
+ txDepth(0),
+ rolledback(false)
+{
+ std::stringstream i(str);
+ Opts o;
+ NvpParse::parse(i, OptsTargetMap, o);
+ mysql_init(&conn);
+ if (o.options) {
+ mysql_options(&conn, MYSQL_READ_DEFAULT_GROUP, ~o.options);
+ }
+ if (mysql_real_connect(&conn, ~o.server, ~o.user, ~o.password, ~o.database,
+ o.port, ~o.unix_socket, CLIENT_LOCAL_FILES | CLIENT_MULTI_STATEMENTS) == NULL) {
+ throw ConnectionError();
+ }
+ if (mysql_set_character_set(&conn, "utf8")) {
+ throw ConnectionError();
+ }
+}
+
+MySQL::Connection::~Connection()
+{
+ mysql_close(&conn);
+}
+
+void
+MySQL::Connection::finish() const
+{
+ if (txDepth != 0) {
+ rollbackTx();
+ throw Error("Transaction still open");
+ }
+}
+
+int
+MySQL::Connection::beginTx() const
+{
+ if (txDepth == 0) {
+ if (mysql_autocommit(&conn, 0)) {
+ throw Error(mysql_error(&conn));
+ }
+ rolledback = false;
+ }
+ return ++txDepth;
+}
+
+int
+MySQL::Connection::commitTx() const
+{
+ if (rolledback) {
+ return rollbackTx();
+ }
+ if (--txDepth == 0) {
+ if (mysql_commit(&conn)) {
+ throw Error(mysql_error(&conn));
+ }
+ }
+ return txDepth;
+}
+
+int
+MySQL::Connection::rollbackTx() const
+{
+ if (--txDepth == 0) {
+ if (mysql_rollback(&conn)) {
+ throw Error(mysql_error(&conn));
+ }
+ }
+ else {
+ rolledback = true;
+ }
+ return txDepth;
+}
+
+bool
+MySQL::Connection::inTx() const
+{
+ return txDepth;
+}
+
+DB::BulkDeleteStyle
+MySQL::Connection::bulkDeleteStyle() const
+{
+ return DB::BulkDeleteUsingUsingAlias;
+}
+
+DB::BulkUpdateStyle
+MySQL::Connection::bulkUpdateStyle() const
+{
+ return DB::BulkUpdateUsingJoin;
+}
+
+void
+MySQL::Connection::ping() const
+{
+ if (mysql_ping(&conn)) {
+ throw Error(mysql_error(&conn));
+ }
+}
+
+
+DB::SelectCommand *
+MySQL::Connection::newSelectCommand(const std::string & sql) const
+{
+ return new SelectCommand(this, sql);
+}
+
+DB::ModifyCommand *
+MySQL::Connection::newModifyCommand(const std::string & sql) const
+{
+ return new ModifyCommand(this, sql);
+}
+
+namespace MySQL {
+ class LoadContext : public AdHoc::System::RuntimeContext {
+ public:
+ LoadContext(MYSQL * c) :
+ loadBuf(NULL),
+ loadBufLen(0),
+ bufOff(0),
+ conn(c)
+ {
+ }
+
+ static int local_infile_init(void ** ptr, const char *, void * ctx) {
+ *ptr = ctx;
+ return 0;
+ }
+
+ static int local_infile_read(void * obj, char * buf, unsigned int bufSize) {
+ LoadContext * ctx = static_cast<LoadContext *>(obj);
+ if (ctx->loadBufLen - ctx->bufOff == 0) {
+ ctx->swapContext();
+ if (ctx->loadBufLen - ctx->bufOff <= 0) {
+ // Nothing to do or error
+ return ctx->bufOff;
+ }
+ }
+ unsigned int copy = std::min(ctx->loadBufLen - ctx->bufOff, bufSize);
+ memcpy(buf, ctx->loadBuf + ctx->bufOff, copy);
+ ctx->bufOff += copy;
+ return copy;
+ }
+
+ static void local_infile_end(void *) {
+ }
+
+ static int local_infile_error(void *, char*, unsigned int) {
+ return 0;
+ }
+
+ void callback() override
+ {
+ loadReturn = mysql_read_query_result(conn);
+ }
+
+ const char * loadBuf;
+ unsigned int loadBufLen;
+ int bufOff;
+ MYSQL * conn;
+ int loadReturn;
+ };
+}
+
+void
+MySQL::Connection::beginBulkUpload(const char * table, const char * extra) const
+{
+ static char buf[BUFSIZ];
+ int len = snprintf(buf, BUFSIZ, "LOAD DATA LOCAL INFILE 'any' INTO TABLE %s %s", table, extra);
+ mysql_send_query(&conn, buf, len);
+
+ ctx = boost::shared_ptr<LoadContext>(new MySQL::LoadContext(&conn));
+
+ mysql_set_local_infile_handler(&conn, LoadContext::local_infile_init, LoadContext::local_infile_read,
+ LoadContext::local_infile_end, LoadContext::local_infile_error, ctx.get());
+
+ ctx->swapContext();
+}
+
+void
+MySQL::Connection::endBulkUpload(const char * msg) const
+{
+ ctx->loadBuf = NULL;
+ ctx->loadBufLen = 0;
+ ctx->bufOff = msg ? -1 : 0;
+ // switch context with empty buffer fires finished
+ ctx->swapContext();
+ // Check result
+ if (!msg) {
+ if (ctx->loadReturn) {
+ ctx.reset();
+ throw Error(mysql_error(&conn));
+ }
+ }
+ ctx.reset();
+}
+
+size_t
+MySQL::Connection::bulkUploadData(const char * data, size_t len) const
+{
+ ctx->loadBuf = data;
+ ctx->loadBufLen = len;
+ ctx->bufOff = 0;
+ // switch context to load the buffered data
+ ctx->swapContext();
+ return len;
+}
+
+int64_t
+MySQL::Connection::insertId() const
+{
+ return mysql_insert_id(&conn);
+}
+