abstract-db.cpp 3.8 KB
Newer Older
Ronan's avatar
Ronan committed
1 2
/*
 * abstract-db.cpp
3
 * Copyright (C) 2010-2018 Belledonne Communications SARL
Ronan's avatar
Ronan committed
4
 *
Ghislain MARY's avatar
Ghislain MARY committed
5 6 7 8
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
Ronan's avatar
Ronan committed
9 10 11 12 13 14 15
 *
 * 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
Ghislain MARY's avatar
Ghislain MARY committed
16 17
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Ronan's avatar
Ronan committed
18 19
 */

20 21 22 23
#ifdef __APPLE__
	#include <TargetConditionals.h>
#endif // ifdef __APPLE__

24 25 26 27
#if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__))
	#include <sqlite3.h>
#endif // if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__))

Ronan's avatar
Ronan committed
28
#include "abstract-db-p.h"
29
#include "logger/logger.h"
Ronan's avatar
Ronan committed
30 31 32

// =============================================================================

33 34
using namespace std;

Ronan's avatar
Ronan committed
35 36
LINPHONE_BEGIN_NAMESPACE

37
#if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__))
38
	// Force static sqlite3 linking for IOS and Android.
39
	extern "C" void register_factory_sqlite3();
40 41 42 43

	static void sqlite3Log (void *, int iErrCode, const char *zMsg) {
		lInfo() << "[sqlite3][" << iErrCode << "]" << zMsg;
	}
44
#endif // if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__))
45

46 47
AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(p) {}

48
bool AbstractDb::connect (Backend backend, const string &parameters) {
49
	L_D();
50

51
	#if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__))
52 53 54 55 56 57 58 59
		if (backend == Sqlite3) {
			static bool registered = false;
			if (!registered) {
				registered = true;
				register_factory_sqlite3();
				sqlite3_config(SQLITE_CONFIG_LOG, sqlite3Log, nullptr);
			}
		}
60
	#endif // if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__))
61

62
	d->backend = backend;
63
	d->dbSession = DbSession(
64 65
		(backend == Mysql ? "mysql://" : "sqlite3://") + parameters
	);
66

67 68
	if (d->dbSession) {
		try {
69 70 71 72 73
			#ifdef SOCI_ENABLED
				d->dbSession.enableForeignKeys(false);
				init();
				d->dbSession.enableForeignKeys(true);
			#endif // ifdef SOCI_ENABLED
74 75 76 77 78 79 80 81
		} catch (const exception &e) {
			lWarning() << "Unable to init database: " << e.what();

			// Reset session.
			d->dbSession = DbSession();
		}
	}

82
	return d->dbSession;
Ronan's avatar
Ronan committed
83 84
}

85
void AbstractDb::disconnect () {
86
	L_D();
87
	d->dbSession = DbSession();
Ronan's avatar
Ronan committed
88 89
}

90
bool AbstractDb::forceReconnect () {
91
	L_D();
92 93 94
	if (!d->dbSession) {
		lWarning() << "Unable to reconnect. Not a valid database session.";
		return false;
95 96
	}

97 98 99
	#ifdef SOCI_ENABLED
		constexpr int retryCount = 2;
		lInfo() << "Trying sql backend reconnect...";
100

101 102 103 104 105 106 107 108
		try {
			soci::session *session = d->dbSession.getBackendSession();
			session->close();

			for (int i = 0; i < retryCount; ++i) {
				try {
					lInfo() << "Reconnect... Try: " << i;
					session->reconnect();
109
					init();
110 111 112 113 114 115 116 117 118 119 120
					lInfo() << "Database reconnection successful!";
					return true;
				} catch (const soci::soci_error &e) {
					if (e.get_error_category() != soci::soci_error::connection_error)
						throw e;
				}
			}
		} catch (const exception &e) {
			lError() << "Unable to reconnect: `" << e.what() << "`.";
			return false;
		}
121

122 123
		lError() << "Database reconnection failed!";
	#endif // ifdef SOCI_ENABLED
124

125
	return false;
126 127
}

128
AbstractDb::Backend AbstractDb::getBackend () const {
129
	L_D();
130
	return d->backend;
131 132
}

133 134
bool AbstractDb::import (Backend, const string &) {
	return false;
135 136
}

137
// -----------------------------------------------------------------------------
138

139 140
void AbstractDb::init () {
	// Nothing.
141 142
}

Ronan's avatar
Ronan committed
143
LINPHONE_END_NAMESPACE