[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [amarok] /: Improve sql database configuration handling.
From: Ralf Engels <ralf-engels () gmx ! de>
Date: 2015-01-17 18:12:21
Message-ID: E1YCXrB-000431-Q4 () scm ! kde ! org
[Download RAW message or body]
Git commit ca2a2f854ef84ec2d4e4c5ee8615e9caace8e618 by Ralf Engels.
Committed on 14/12/2014 at 21:43.
Pushed by rengels into branch 'master'.
Improve sql database configuration handling.
Add check database button for configuration.
Add test database slot to storage factory.
Refactor storage factory to support
- creating multiple storages
- cleanup only after last storage uses sql server (at least for
the server/client storage)
- reporting of configuration errors
Unify general reporting of storage errors.
M +1 -0 ChangeLog
M +3 -2 src/PluginManager.cpp
M +2 -2 src/configdialog/ConfigDialog.cpp
M +72 -6 src/configdialog/dialogs/DatabaseConfig.cpp
M +13 -2 src/configdialog/dialogs/DatabaseConfig.h
M +8 -1 src/configdialog/dialogs/DatabaseConfig.ui
M +14 -6 src/core-impl/collections/support/CollectionManager.cpp
M +10 -2 src/core-impl/storage/sql/mysql-shared/MySqlStorage.cpp
M +7 -7 src/core-impl/storage/sql/mysql-shared/MySqlStorage.h
M +35 -24 src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.cpp
M +6 -6 src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.h
M +39 -57 src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.cpp
M +10 -4 src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.h
M +23 -1 src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.cpp
M +6 -0 src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.h
M +2 -1 src/dynamic/TrackSet.cpp
M +2 -2 tests/core-impl/collections/db/sql/TestDatabaseUpdater.cpp
M +2 -2 tests/core-impl/collections/db/sql/TestDatabaseUpdater.h
M +2 -2 tests/core-impl/collections/db/sql/TestSqlAlbum.cpp
M +2 -2 tests/core-impl/collections/db/sql/TestSqlAlbum.h
M +2 -2 tests/core-impl/collections/db/sql/TestSqlArtist.cpp
M +2 -2 tests/core-impl/collections/db/sql/TestSqlArtist.h
M +2 -2 tests/core-impl/collections/db/sql/TestSqlCollection.cpp
M +2 -2 tests/core-impl/collections/db/sql/TestSqlCollection.h
M +2 -2 tests/core-impl/collections/db/sql/TestSqlCollectionLocation.cpp
M +2 -2 tests/core-impl/collections/db/sql/TestSqlCollectionLocation.h
M +2 -2 tests/core-impl/collections/db/sql/TestSqlQueryMaker.cpp
M +2 -2 tests/core-impl/collections/db/sql/TestSqlQueryMaker.h
M +2 -2 tests/core-impl/collections/db/sql/TestSqlScanManager.cpp
M +2 -2 tests/core-impl/collections/db/sql/TestSqlScanManager.h
M +2 -2 tests/core-impl/collections/db/sql/TestSqlTrack.cpp
M +2 -2 tests/core-impl/collections/db/sql/TestSqlTrack.h
http://commits.kde.org/amarok/ca2a2f854ef84ec2d4e4c5ee8615e9caace8e618
diff --git a/ChangeLog b/ChangeLog
index eeff0d4..f1ff7ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,7 @@ Amarok ChangeLog
VERSION 2.8.1
FEATURES:
+ * Database configuration dialog now has a "test connection" button.
* Add Service entries for directories. (BR 229708)
* Collection Browser scrolls back to its original position when the filter is \
cleared. (BR 188074)
diff --git a/src/PluginManager.cpp b/src/PluginManager.cpp
index abdc707..2c1a86d 100644
--- a/src/PluginManager.cpp
+++ b/src/PluginManager.cpp
@@ -81,6 +81,7 @@ Plugins::PluginManager::~PluginManager()
if( controller )
controller->setFactories( emptyFactories );
ServicePluginManager::instance()->setFactories( emptyFactories );
+ CollectionManager::instance()->setFactories( emptyFactories );
StorageManager::instance()->setFactories( emptyFactories );
}
@@ -143,8 +144,8 @@ Plugins::PluginManager::checkPluginEnabledStates()
}
}
- // the setFactories functions should to:
- // - filter out factories not usefull
+ // the setFactories functions should:
+ // - filter out factories not usefull (e.g. services when setting collections)
// - handle the new list of factories, disabling old ones and enabling new ones.
PERF_LOG( "Loading storage plugins" )
diff --git a/src/configdialog/ConfigDialog.cpp b/src/configdialog/ConfigDialog.cpp
index 234815e..89d2215 100644
--- a/src/configdialog/ConfigDialog.cpp
+++ b/src/configdialog/ConfigDialog.cpp
@@ -49,7 +49,7 @@ Amarok2ConfigDialog::Amarok2ConfigDialog( QWidget *parent, const \
char* name, KCo ConfigDialogBase *metadata = new MetadataConfig( this );
ConfigDialogBase *playback = new PlaybackConfig( this );
ConfigDialogBase *notify = new NotificationsConfig( this );
- ConfigDialogBase *database = new DatabaseConfig( this );
+ ConfigDialogBase *database = new DatabaseConfig( this, config );
ConfigDialogBase *plugins = new PluginsConfig( this );
ConfigDialogBase *scripts = new ScriptsConfig( this );
@@ -198,7 +198,7 @@ bool Amarok2ConfigDialog::isDefault()
bool def = false;
foreach( ConfigDialogBase* page, m_pageList )
- if( page->hasChanged() )
+ if( page->isDefault() )
def = true;
return def;
diff --git a/src/configdialog/dialogs/DatabaseConfig.cpp \
b/src/configdialog/dialogs/DatabaseConfig.cpp index f8d966f..8280a48 100644
--- a/src/configdialog/dialogs/DatabaseConfig.cpp
+++ b/src/configdialog/dialogs/DatabaseConfig.cpp
@@ -16,15 +16,18 @@
#include "DatabaseConfig.h"
-#include "core/support/Amarok.h"
-#include "core/support/Debug.h"
-#include "core-impl/collections/support/CollectionManager.h"
+#include <PluginManager.h>
+#include <core/support/Amarok.h>
+#include <core/support/Debug.h>
+#include <KConfigDialogManager>
+#include <KMessageBox>
#include <KCMultiDialog>
-DatabaseConfig::DatabaseConfig( QWidget* parent )
+DatabaseConfig::DatabaseConfig( QWidget* parent, KConfigSkeleton *config )
: ConfigDialogBase( parent )
+ , m_configManager( new KConfigDialogManager( this, config ) )
{
setupUi( this );
@@ -34,15 +37,32 @@ DatabaseConfig::DatabaseConfig( QWidget* parent )
setTabOrder( kcfg_User, kcfg_Password ); // username to password
setTabOrder( kcfg_Password, kcfg_Database ); // password to database
+ // enable the test button if one of the plugin factories has a correct \
testSettings slot + // get all storage factories
+ QList<Plugins::PluginFactory*> factories;
+ factories = Plugins::PluginManager::instance()->factories( \
Plugins::PluginManager::Storage ); + bool testFunctionAvailable = false;
+ foreach( Plugins::PluginFactory* factory, factories )
+ {
+ // check the meta object if there is a testSettings slot available
+ if( factory->metaObject()->
+ indexOfMethod( QMetaObject::normalizedSignature("testSettings(QString, \
QString, QString, int, QString)" ) ) >= 0 ) + testFunctionAvailable = \
true; + }
+ button_Test->setEnabled( testFunctionAvailable );
+
+ // connect slots
connect( kcfg_UseServer, SIGNAL(stateChanged(int)), \
SLOT(toggleExternalConfigAvailable(int)) );
connect( kcfg_Database, SIGNAL(textChanged(QString)), SLOT(updateSQLQuery()) );
connect( kcfg_User, SIGNAL(textChanged(QString)), SLOT(updateSQLQuery()) );
- connect( kcfg_Host, SIGNAL(textChanged(QString)), SLOT(updateSQLQuery()) );
+ connect( button_Test, SIGNAL(clicked(bool)), SLOT(testDatabaseConnection()));
toggleExternalConfigAvailable( kcfg_UseServer->checkState() );
updateSQLQuery();
+
+ m_configManager->addWidget( this );
}
DatabaseConfig::~DatabaseConfig()
@@ -54,6 +74,47 @@ DatabaseConfig::toggleExternalConfigAvailable( const int \
checkBoxState ) //SLOT group_Connection->setEnabled( checkBoxState == Qt::Checked );
}
+void
+DatabaseConfig::testDatabaseConnection() //SLOT
+{
+ // get all storage factories
+ QList<Plugins::PluginFactory*> factories;
+ factories = Plugins::PluginManager::instance()->factories( \
Plugins::PluginManager::Storage ); +
+ // try if they have a testSettings slot that we can call
+ bool tested = false;
+ foreach( Plugins::PluginFactory* factory, factories )
+ {
+ bool callSucceeded = false;
+ QStringList connectionErrors;
+
+ callSucceeded = QMetaObject::invokeMethod( factory,
+ "testSettings",
+ Q_RETURN_ARG( QStringList, connectionErrors ),
+ Q_ARG( QString, kcfg_Host->text() ),
+ Q_ARG( QString, kcfg_User->text() ),
+ Q_ARG( QString, kcfg_Password->text() ),
+ Q_ARG( int, kcfg_Port->text().toInt() ),
+ Q_ARG( QString, kcfg_Database->text() )
+ );
+
+ if( callSucceeded )
+ {
+ tested = true;
+ if( connectionErrors.isEmpty() )
+ KMessageBox::messageBox( this, KMessageBox::Information,
+ i18n( "Amarok was able to connect \
succesfull to the database." ), + i18n( \
"Success" ) ); + else
+ KMessageBox::error( this, i18n( "The amarok database reported "
+ "the following errors:\n%1\nIn most \
cases you will need to resolve " + \
"these errors before Amarok will run properly." ). + \
arg( connectionErrors.join( "\n" ) ), + i18n( \
"Database Error" )); + }
+ }
+}
+
///////////////////////////////////////////////////////////////
// REIMPLEMENTED METHODS from ConfigDialogBase
///////////////////////////////////////////////////////////////
@@ -72,7 +133,12 @@ DatabaseConfig::isDefault()
void
DatabaseConfig::updateSettings()
-{}
+{
+ if( m_configManager->hasChanged() )
+ KMessageBox::messageBox( 0, KMessageBox::Information,
+ i18n( "Changes to database settings only take\neffect after Amarok \
is restarted." ), + i18n( "Database settings changed" ) );
+}
///////////////////////////////////////////////////////////////
diff --git a/src/configdialog/dialogs/DatabaseConfig.h \
b/src/configdialog/dialogs/DatabaseConfig.h index c78847f..baff2df 100644
--- a/src/configdialog/dialogs/DatabaseConfig.h
+++ b/src/configdialog/dialogs/DatabaseConfig.h
@@ -21,12 +21,15 @@
#include "ui_DatabaseConfig.h"
#include "configdialog/ConfigDialogBase.h"
+class KConfigDialogManager;
+class KConfigSkeleton;
+
class DatabaseConfig : public ConfigDialogBase, public Ui_DatabaseConfig
{
Q_OBJECT
public:
- DatabaseConfig( QWidget* parent );
+ DatabaseConfig( QWidget* parent, KConfigSkeleton *config );
virtual ~DatabaseConfig();
virtual bool hasChanged();
@@ -35,12 +38,20 @@ class DatabaseConfig : public ConfigDialogBase, public \
Ui_DatabaseConfig
public slots:
void toggleExternalConfigAvailable( int checkBoxState );
+ void testDatabaseConnection();
private Q_SLOTS:
void updateSQLQuery();
private:
- inline bool isSQLInfoPresent() const;
+ /** Returns true if the configuration is complete.
+ *
+ * Complete menas that the database, user and host are filled out.
+ */
+ bool isSQLInfoPresent() const;
+
+ KConfigDialogManager* m_configManager;
+
};
diff --git a/src/configdialog/dialogs/DatabaseConfig.ui \
b/src/configdialog/dialogs/DatabaseConfig.ui index 4c6904b..0d198e3 100644
--- a/src/configdialog/dialogs/DatabaseConfig.ui
+++ b/src/configdialog/dialogs/DatabaseConfig.ui
@@ -182,6 +182,13 @@
</property>
</widget>
</item>
+ <item row="4" column="1" colspan="5">
+ <widget class="QPushButton" name="button_Test">
+ <property name="text">
+ <string>Test database connection</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
@@ -196,7 +203,7 @@
<item>
<widget class="QLabel" name="label_Info">
<property name="text">
- <string>Amarok expects the above database and user account to already \
exist. This user also requires full access to the database. You MUST restart Amarok \
after changing these settings.</string> + <string>Amarok expects the above \
database and user account to already exist. This user also requires full access to \
the database. Changes only take effect after Amarok is restarted.</string> \
</property> <property name="wordWrap">
<bool>true</bool>
diff --git a/src/core-impl/collections/support/CollectionManager.cpp \
b/src/core-impl/collections/support/CollectionManager.cpp index 16e9cbc..1cb46c7 \
100644
--- a/src/core-impl/collections/support/CollectionManager.cpp
+++ b/src/core-impl/collections/support/CollectionManager.cpp
@@ -241,7 +241,7 @@ CollectionManager::slotNewCollection( Collections::Collection* \
newCollection )
if( !newCollection )
{
- debug() << "Warning, newCollection in slotNewCollection is 0";
+ error() << "newCollection in slotNewCollection is 0";
return;
}
{
@@ -250,7 +250,7 @@ CollectionManager::slotNewCollection( Collections::Collection* \
newCollection ) {
if( p.first == newCollection )
{
- debug() << "Warning, newCollection is already being managed";
+ error() << "newCollection " << newCollection->collectionId() << " is \
already being managed"; return;
}
}
@@ -266,13 +266,21 @@ CollectionManager::slotNewCollection( Collections::Collection* \
newCollection )
{
QWriteLocker locker( &d->lock );
- d->collections.append( pair );
- d->trackProviders.append( newCollection );
+ if( newCollection->collectionId() == QLatin1String("localCollection") )
+ {
+ d->primaryCollection = newCollection;
+ d->collections.insert( 0, pair ); // the primary collection should be \
the first collection to be searched + d->trackProviders.insert( 2, \
newCollection ); // the primary collection should be between the timecode track \
provider and the local file track provider + }
+ else
+ {
+ d->collections.append( pair );
+ d->trackProviders.append( newCollection );
+ }
connect( newCollection, SIGNAL(remove()), SLOT(slotRemoveCollection()), \
Qt::QueuedConnection );
connect( newCollection, SIGNAL(updated()), SLOT(slotCollectionChanged()), \
Qt::QueuedConnection );
- if( newCollection->collectionId() == "localCollection" )
- d->primaryCollection = newCollection;
+ debug() << "new Collection " << newCollection->collectionId();
}
if( status & CollectionViewable )
diff --git a/src/core-impl/storage/sql/mysql-shared/MySqlStorage.cpp \
b/src/core-impl/storage/sql/mysql-shared/MySqlStorage.cpp index 3f2f98c..4a7ccbc \
100644
--- a/src/core-impl/storage/sql/mysql-shared/MySqlStorage.cpp
+++ b/src/core-impl/storage/sql/mysql-shared/MySqlStorage.cpp
@@ -273,7 +273,11 @@ void
MySqlStorage::reportError( const QString& message )
{
QMutexLocker locker( &m_mutex );
- QString errorMessage( "GREPME " + m_debugIdent + " query failed! (" + \
QString::number( mysql_errno( m_db ) ) + ") " + mysql_error( m_db ) + " on " + \
message ); + QString errorMessage;
+ if( m_db )
+ errorMessage = m_debugIdent + " query failed! (" + QString::number( \
mysql_errno( m_db ) ) + ") " + mysql_error( m_db ) + " on " + message; + else
+ errorMessage = m_debugIdent + " something failed! on " + message;
error() << errorMessage;
if( m_lastErrors.count() < 20 )
@@ -287,7 +291,7 @@ MySqlStorage::initThreadInitializer()
ThreadInitializer::init();
}
-void
+bool
MySqlStorage::sharedInit( const QString &databaseName )
{
QMutexLocker locker( &m_mutex );
@@ -298,7 +302,11 @@ MySqlStorage::sharedInit( const QString &databaseName )
if( mysql_query( m_db, QString( "ALTER DATABASE %1 DEFAULT CHARACTER SET utf8 \
DEFAULT COLLATE utf8_bin" ).arg( databaseName ).toUtf8() ) ) reportError( "Could not \
alter database charset/collation" );
if( mysql_query( m_db, QString( "USE %1" ).arg( databaseName ).toUtf8() ) )
+ {
reportError( "Could not select database" );
+ return false; // this error is fatal
+ }
debug() << "Connected to MySQL server" << mysql_get_server_info( m_db );
+ return true;
}
diff --git a/src/core-impl/storage/sql/mysql-shared/MySqlStorage.h \
b/src/core-impl/storage/sql/mysql-shared/MySqlStorage.h index f09ee30..213ea7b 100644
--- a/src/core-impl/storage/sql/mysql-shared/MySqlStorage.h
+++ b/src/core-impl/storage/sql/mysql-shared/MySqlStorage.h
@@ -40,12 +40,6 @@ class MySqlStorage: public SqlStorage
MySqlStorage();
virtual ~MySqlStorage();
- /** Initializes the sql storage.
- *
- * @returns true if the initialization was successfull.
- */
- virtual bool init() = 0;
-
virtual QStringList query( const QString &query );
virtual int insert( const QString &statement, const QString &table = \
QString() );
@@ -80,7 +74,13 @@ class MySqlStorage: public SqlStorage
void reportError( const QString &message );
void initThreadInitializer();
- void sharedInit( const QString &databaseName );
+
+ /** Sends the first sql commands to setup the connection.
+ *
+ * Sets things like the used database and charset.
+ * @returns false if something fatal was wrong.
+ */
+ bool sharedInit( const QString &databaseName );
MYSQL* m_db;
diff --git a/src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.cpp \
b/src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.cpp index \
3db04e2..4a9568f 100644
--- a/src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.cpp
+++ b/src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.cpp
@@ -24,28 +24,31 @@
#include <core/support/Debug.h>
#include <QDir>
-#include <QString>
-#include <QMutexLocker>
-#include <QThreadStorage>
#include <QVarLengthArray>
#include <QVector>
+#include <QAtomicInt>
#include <mysql.h>
-MySqlEmbeddedStorage::MySqlEmbeddedStorage( const QString &storageLocation )
+/** number of times the library is used.
+ */
+static QAtomicInt libraryInitRef;
+
+MySqlEmbeddedStorage::MySqlEmbeddedStorage()
: MySqlStorage()
- , m_storageLocation( storageLocation )
{
m_debugIdent = "MySQLe";
}
bool
-MySqlEmbeddedStorage::init()
+MySqlEmbeddedStorage::init( const QString &storageLocation )
{
// -- figuring out and setting the database path.
- QString storagePath = m_storageLocation;
+ QString storagePath = storageLocation;
QString databaseDir;
+ // TODO: the following logic is not explained in the comments.
+ // tests use a different directory then the real run
if( storagePath.isEmpty() )
{
storagePath = Amarok::saveLocation();
@@ -80,25 +83,25 @@ MySqlEmbeddedStorage::init()
}
// -- initializing the library
- int ret = mysql_library_init( mysql_args.size(), \
const_cast<char**>(mysql_args.data()), 0 );
- if( ret != 0 )
+ // we only need to do this once
+ if( !libraryInitRef.fetchAndAddOrdered( 1 ) )
{
- // it has no sense to call reportError here because m_db is not yet \
initialized
- QMutexLocker locker( &m_mutex );
- QString errorMessage( "GREPME " + m_debugIdent + " library initialization "
- "failed, return code " + QString::number( ret ) );
- m_lastErrors.append( errorMessage );
- error() << errorMessage.toLocal8Bit().constData();
- error() << "mysqle arguments were:" << mysql_args;
- return false;
+ int ret = mysql_library_init( mysql_args.size(), \
const_cast<char**>(mysql_args.data()), 0 ); + if( ret != 0 )
+ {
+ // mysql sources show that there is only 0 and 1 as return code
+ // and it can only fail because of memory or thread issues.
+ reportError( "library initialization "
+ "failed, return code " + QString::number( ret ) );
+ libraryInitRef.deref();
+ return false;
+ }
}
m_db = mysql_init( NULL );
-
if( !m_db )
{
- error() << "MySQLe initialization failed";
- mysql_library_end();
+ reportError( "call to mysql_init" );
return false;
}
@@ -112,13 +115,18 @@ MySqlEmbeddedStorage::init()
error() << "Could not connect to mysql embedded!";
reportError( "call to mysql_real_connect" );
mysql_close( m_db );
- mysql_library_end();
m_db = 0;
return false;
}
- sharedInit( "amarok" );
- debug() << "Connected to MySQL server" << mysql_get_server_info( m_db );
+ if( !sharedInit( QLatin1String("amarok") ) )
+ {
+ // if sharedInit fails then we can usually not switch to the correct \
database + // sharedInit already reports errors.
+ mysql_close( m_db );
+ m_db = 0;
+ return false;
+ }
MySqlStorage::initThreadInitializer();
@@ -130,7 +138,10 @@ MySqlEmbeddedStorage::~MySqlEmbeddedStorage()
if( m_db )
{
mysql_close( m_db );
- mysql_library_end();
+ if( !libraryInitRef.deref() )
+ {
+ mysql_library_end();
+ }
}
}
diff --git a/src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.h \
b/src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.h index \
308121f..29963d9 100644
--- a/src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.h
+++ b/src/core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.h
@@ -28,18 +28,18 @@ class AMAROK_SQLSTORAGE_MYSQLE_EXPORT MySqlEmbeddedStorage : \
public MySqlStorage {
public:
/** Creates a new SqlStorage.
- * @param storageLocation The directory for storing the mysql database, \
will use the default defined by Amarok/KDE if not set. + *
* Note: Currently it is not possible to open two storages to different \
locations
* in one process.
* The first caller wins.
*/
- MySqlEmbeddedStorage( const QString &storageLocation = QString() );
+ MySqlEmbeddedStorage();
virtual ~MySqlEmbeddedStorage();
- virtual bool init();
-
- private:
- QString m_storageLocation;
+ /** Initializes the storage.
+ * @param storageLocation The directory for storing the mysql database, \
will use the default defined by Amarok/KDE if not set. + */
+ bool init( const QString &storageLocation = QString() );
};
#endif // MYSQLEMBEDDEDSTORAGE_H
diff --git a/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.cpp \
b/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.cpp index \
f427b2e..83ca486 100644
--- a/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.cpp
+++ b/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.cpp
@@ -2,6 +2,7 @@
* Copyright (c) 2008 Edward Toroshchin <edward.hades@gmail.com> \
*
* Copyright (c) 2009 Jeff Mitchell <mitchell@kde.org> \
*
* Copyright (c) 2012 Lachlan Dufton <dufton@gmail.com> \
* + * Copyright (c) 2014 Ralf Engels <ralf-engels@gmx.de> \
*
* \
*
* 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 \
* @@ -20,14 +21,16 @@
#include "MySqlServerStorage.h"
-#include <amarokconfig.h>
-#include <core/support/Amarok.h>
#include <core/support/Debug.h>
-#include <QMutexLocker>
+#include <QAtomicInt>
#include <mysql.h>
+/** number of times the library is used.
+ */
+static QAtomicInt libraryInitRef;
+
MySqlServerStorage::MySqlServerStorage()
: MySqlStorage()
{
@@ -35,26 +38,30 @@ MySqlServerStorage::MySqlServerStorage()
}
bool
-MySqlServerStorage::init()
+MySqlServerStorage::init( const QString &host, const QString &user, const QString \
&password, int port, const QString &databaseName ) {
DEBUG_BLOCK
-
// -- initializing the library
- int ret = mysql_library_init( 0, NULL, NULL );
- if( ret != 0 )
+ // we only need to do this once
+ if( !libraryInitRef.fetchAndAddOrdered( 1 ) )
{
- // it has no sense to call reportError here because m_db is not yet \
initialized
- error() << "MySQL library initialization failed!";
- return false;
+ int ret = mysql_library_init( 0, NULL, NULL );
+ if( ret != 0 )
+ {
+ // mysql sources show that there is only 0 and 1 as return code
+ // and it can only fail because of memory or thread issues.
+ reportError( "library initialization "
+ "failed, return code " + QString::number( ret ) );
+ libraryInitRef.deref();
+ return false;
+ }
}
m_db = mysql_init( NULL );
-
if( !m_db )
{
- error() << "MySQL initialization failed";
- mysql_library_end();
+ reportError( "call to mysql_init" );
return false;
}
@@ -65,20 +72,19 @@ MySqlServerStorage::init()
else
debug() << "Automatic reconnect successfully activated";
+ debug() << "Connecting to mysql server " << user << "@" << host << ":" << port;
if( !mysql_real_connect( m_db,
- Amarok::config( "MySQL" ).readEntry( "Host", "localhost" ).toUtf8(),
- Amarok::config( "MySQL" ).readEntry( "User", "amarokuser" \
).toUtf8(),
- Amarok::config( "MySQL" ).readEntry( "Password", "password" \
).toUtf8(), + host.toUtf8(),
+ user.toUtf8(),
+ password.toUtf8(),
NULL,
- Amarok::config( "MySQL" ).readEntry( "Port", "3306" ).toInt(),
+ port,
NULL,
CLIENT_COMPRESS )
)
{
- error() << "Could not connect to mysql server!";
reportError( "call to mysql_real_connect" );
mysql_close( m_db );
- mysql_library_end();
m_db = 0;
return false;
}
@@ -90,9 +96,15 @@ MySqlServerStorage::init()
else
debug() << "Automatic reconnect successfully activated";
- QString databaseName = Amarok::config( "MySQL" ).readEntry( "Database", \
"amarokdb" );
- sharedInit( databaseName );
- debug() << "Connected to MySQL server" << mysql_get_server_info( m_db );
+ m_databaseName = databaseName; // store it when we need it later for reconnect
+ if( !sharedInit( databaseName ) )
+ {
+ // if sharedInit fails then we can usually not switch to the correct \
database + // sharedInit already reports errors.
+ mysql_close( m_db );
+ m_db = 0;
+ return false;
+ }
MySqlServerStorage::initThreadInitializer();
return true;
@@ -105,7 +117,10 @@ MySqlServerStorage::~MySqlServerStorage()
if( m_db )
{
mysql_close( m_db );
- mysql_library_end();
+ if( !libraryInitRef.deref() )
+ {
+ mysql_library_end();
+ }
}
}
@@ -132,10 +147,9 @@ MySqlServerStorage::query( const QString &query )
if( tid != mysql_thread_id( m_db ) )
{
debug() << "NOTE: MySQL server had gone away, ping reconnected it";
- QString databaseName = Amarok::config( "MySQL" ).readEntry( "Database", \
"amarokdb" ); if( mysql_query( m_db, QString( "SET NAMES 'utf8'" ).toUtf8() ) )
reportError( "SET NAMES 'utf8' died" );
- if( mysql_query( m_db, QString( "USE %1" ).arg( databaseName ).toUtf8() ) )
+ if( mysql_query( m_db, QString( "USE %1" ).arg( m_databaseName ).toUtf8() ) \
) reportError( "Could not select database" );
}
@@ -144,35 +158,3 @@ MySqlServerStorage::query( const QString &query )
}
-bool
-MySqlServerStorage::testSettings( const QString &host, const QString &user, const \
QString &password, int port )
-{
- DEBUG_BLOCK
- if( mysql_library_init( 0, NULL, NULL ) )
- {
- error() << "MySQL library initialization failed!";
- return false;
- }
-
- MYSQL* db = mysql_init( NULL );
-
- if( !db )
- {
- error() << "MySQL initialization failed";
- return false;
- }
-
- if( !mysql_real_connect( db, host.toUtf8(), user.toUtf8(), password.toUtf8(), \
NULL, port, NULL, CLIENT_COMPRESS ) )
- {
- mysql_close( db );
- db = 0;
- return false;
- }
-
- mysql_close( db );
- db = 0;
- return true;
-}
-
-
-
diff --git a/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.h \
b/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.h index \
f63cee7..b91aa81 100644
--- a/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.h
+++ b/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorage.h
@@ -27,16 +27,22 @@
class AMAROK_SQLSTORAGE_MYSQLE_EXPORT MySqlServerStorage: public MySqlStorage
{
public:
- /** Connect to the server defined by the configuration options. */
+ /** Constructor for the server based mysql storage. */
MySqlServerStorage();
virtual ~MySqlServerStorage();
- virtual bool init();
+ /** Try to connect to the server indicated by the options.
+ *
+ * Error messages are in the store error log.
+ *
+ * @return true if connection works.
+ */
+ virtual bool init( const QString &host, const QString &user, const QString \
&password, int port, const QString &databaseName );
virtual QStringList query( const QString &query );
- /** Returns true if the given settings allow to connect to a sql server. */
- static bool testSettings( const QString &host, const QString &user, const \
QString &password, int port ); + private:
+ QString m_databaseName; ///< remember the name given at init for reconnects
};
#endif
diff --git a/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.cpp \
b/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.cpp index \
676821a..5cdb693 100644
--- a/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.cpp
+++ b/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.cpp
@@ -17,6 +17,7 @@
#include "MySqlServerStorageFactory.h"
#include "MySqlServerStorage.h"
+#include <amarokconfig.h>
#include <core/support/Amarok.h>
AMAROK_EXPORT_STORAGE( MySqlServerStorageFactory, mysqlserverstorage )
@@ -42,7 +43,12 @@ MySqlServerStorageFactory::init()
if( Amarok::config( "MySQL" ).readEntry( "UseServer", false ) )
{
MySqlServerStorage* storage = new MySqlServerStorage();
- bool initResult = storage->init();
+ bool initResult = storage->init(
+ Amarok::config( "MySQL" ).readEntry( "Host", "localhost" ),
+ Amarok::config( "MySQL" ).readEntry( "User", "amarokuser" ),
+ Amarok::config( "MySQL" ).readEntry( "Password", "password" ),
+ Amarok::config( "MySQL" ).readEntry( "Port", "3306" ).toInt(),
+ Amarok::config( "MySQL" ).readEntry( "Database", "amarokdb" ) );
// handle errors during creation
if( !storage->getLastErrors().isEmpty() )
@@ -56,5 +62,21 @@ MySqlServerStorageFactory::init()
}
}
+QStringList
+MySqlServerStorageFactory::testSettings( const QString &host, const QString &user, \
const QString &password, int port, const QString &databaseName ) +{
+ QStringList errors;
+
+ MySqlServerStorage* storage = new MySqlServerStorage();
+ bool initResult = storage->init( host, user, password, port, databaseName );
+
+ // we are just interested in the errors.
+ errors = storage->getLastErrors();
+
+ delete storage;
+
+ return errors;
+}
+
#include "MySqlServerStorageFactory.moc"
diff --git a/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.h \
b/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.h index \
94015ae..f0e4645 100644
--- a/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.h
+++ b/src/core-impl/storage/sql/mysqlserverstorage/MySqlServerStorageFactory.h
@@ -28,6 +28,12 @@ class MySqlServerStorageFactory : public StorageFactory
virtual ~MySqlServerStorageFactory();
virtual void init();
+
+ public slots:
+
+ /** Returns the error messages created during establishing the connection.
+ */
+ QStringList testSettings( const QString &host, const QString &user, const \
QString &password, int port, const QString &databaseName ); };
diff --git a/src/dynamic/TrackSet.cpp b/src/dynamic/TrackSet.cpp
index 165e264..4877d40 100644
--- a/src/dynamic/TrackSet.cpp
+++ b/src/dynamic/TrackSet.cpp
@@ -223,7 +223,8 @@ Dynamic::TrackSet::subtract( const Meta::TrackPtr& B )
{
// that seems to happen. e.g. for tracks from the file collection
warning() << "TrackSet::subtract called for a track not even known to the \
collection. "<<
- "Track uid is"<<str<<"example from \
collection"<<m_collection->m_ids.keys().first()<< + "Track uid is"<<str<<
+ "example from collection"<<(m_collection->m_ids.isEmpty()?QString("no \
example"):QString(m_collection->m_ids.keys().first()))<<
"track is from \
collection"<<(B->collection()?B->collection()->collectionId():QString("no \
collection")); return;
}
diff --git a/tests/core-impl/collections/db/sql/TestDatabaseUpdater.cpp \
b/tests/core-impl/collections/db/sql/TestDatabaseUpdater.cpp index 7c2d904..fa9cec9 \
100644
--- a/tests/core-impl/collections/db/sql/TestDatabaseUpdater.cpp
+++ b/tests/core-impl/collections/db/sql/TestDatabaseUpdater.cpp
@@ -39,8 +39,8 @@ void
DatabaseUpdaterTest::initTestCase()
{
m_tmpDir = new KTempDir();
- m_storage = new MySqlEmbeddedStorage( m_tmpDir->name() );
- QVERIFY( m_storage->init() );
+ m_storage = new MySqlEmbeddedStorage();
+ QVERIFY( m_storage->init( m_tmpDir->name() ) );
m_collection = new Collections::SqlCollection( m_storage );
}
diff --git a/tests/core-impl/collections/db/sql/TestDatabaseUpdater.h \
b/tests/core-impl/collections/db/sql/TestDatabaseUpdater.h index b29d818..bbeeaaf \
100644
--- a/tests/core-impl/collections/db/sql/TestDatabaseUpdater.h
+++ b/tests/core-impl/collections/db/sql/TestDatabaseUpdater.h
@@ -21,7 +21,7 @@
#include <KTempDir>
-class MySqlStorage;
+class MySqlEmbeddedStorage;
namespace Collections {
class SqlCollection;
@@ -47,7 +47,7 @@ private slots:
private:
Collections::SqlCollection *m_collection;
- MySqlStorage *m_storage;
+ MySqlEmbeddedStorage *m_storage;
KTempDir *m_tmpDir;
};
diff --git a/tests/core-impl/collections/db/sql/TestSqlAlbum.cpp \
b/tests/core-impl/collections/db/sql/TestSqlAlbum.cpp index 6386b7c..b562625 100644
--- a/tests/core-impl/collections/db/sql/TestSqlAlbum.cpp
+++ b/tests/core-impl/collections/db/sql/TestSqlAlbum.cpp
@@ -47,8 +47,8 @@ void
TestSqlAlbum::initTestCase()
{
m_tmpDir = new KTempDir();
- m_storage = new MySqlEmbeddedStorage( m_tmpDir->name() );
- QVERIFY( m_storage->init() );
+ m_storage = new MySqlEmbeddedStorage();
+ QVERIFY( m_storage->init( m_tmpDir->name() ) );
m_collection = new Collections::SqlCollection( m_storage );
m_collection->setMountPointManager( new SqlMountPointManagerMock( this, \
m_storage ) ); }
diff --git a/tests/core-impl/collections/db/sql/TestSqlAlbum.h \
b/tests/core-impl/collections/db/sql/TestSqlAlbum.h index e105e4a..93480e1 100644
--- a/tests/core-impl/collections/db/sql/TestSqlAlbum.h
+++ b/tests/core-impl/collections/db/sql/TestSqlAlbum.h
@@ -21,7 +21,7 @@
#include <KTempDir>
-class MySqlStorage;
+class MySqlEmbeddedStorage;
class SqlRegistry;
namespace Collections {
@@ -60,7 +60,7 @@ private slots:
private:
Collections::SqlCollection *m_collection;
- MySqlStorage *m_storage;
+ MySqlEmbeddedStorage *m_storage;
KTempDir *m_tmpDir;
};
diff --git a/tests/core-impl/collections/db/sql/TestSqlArtist.cpp \
b/tests/core-impl/collections/db/sql/TestSqlArtist.cpp index 074cefc..c51cd6b 100644
--- a/tests/core-impl/collections/db/sql/TestSqlArtist.cpp
+++ b/tests/core-impl/collections/db/sql/TestSqlArtist.cpp
@@ -38,8 +38,8 @@ void
TestSqlArtist::initTestCase()
{
m_tmpDir = new KTempDir();
- m_storage = new MySqlEmbeddedStorage( m_tmpDir->name() );
- QVERIFY( m_storage->init() );
+ m_storage = new MySqlEmbeddedStorage();
+ QVERIFY( m_storage->init( m_tmpDir->name() ) );
m_collection = new Collections::SqlCollection( m_storage );
m_collection->setMountPointManager( new SqlMountPointManagerMock( this, \
m_storage ) ); }
diff --git a/tests/core-impl/collections/db/sql/TestSqlArtist.h \
b/tests/core-impl/collections/db/sql/TestSqlArtist.h index f8aed9d..83ef7a6 100644
--- a/tests/core-impl/collections/db/sql/TestSqlArtist.h
+++ b/tests/core-impl/collections/db/sql/TestSqlArtist.h
@@ -20,7 +20,7 @@
#include <QtTest/QtTest>
#include <KTempDir>
-class MySqlStorage;
+class MySqlEmbeddedStorage;
namespace Collections {
class SqlCollection;
@@ -43,7 +43,7 @@ private slots:
private:
Collections::SqlCollection *m_collection;
- MySqlStorage *m_storage;
+ MySqlEmbeddedStorage *m_storage;
KTempDir *m_tmpDir;
public:
diff --git a/tests/core-impl/collections/db/sql/TestSqlCollection.cpp \
b/tests/core-impl/collections/db/sql/TestSqlCollection.cpp index aca0973..5c47586 \
100644
--- a/tests/core-impl/collections/db/sql/TestSqlCollection.cpp
+++ b/tests/core-impl/collections/db/sql/TestSqlCollection.cpp
@@ -37,8 +37,8 @@ void
TestSqlCollection::initTestCase()
{
m_tmpDir = new KTempDir();
- m_storage = new MySqlEmbeddedStorage( m_tmpDir->name() );
- QVERIFY( m_storage->init() );
+ m_storage = new MySqlEmbeddedStorage();
+ QVERIFY( m_storage->init( m_tmpDir->name() ) );
m_collection = new Collections::SqlCollection( m_storage );
m_mpmMock = new SqlMountPointManagerMock( this, m_storage );
m_collection->setMountPointManager( m_mpmMock );
diff --git a/tests/core-impl/collections/db/sql/TestSqlCollection.h \
b/tests/core-impl/collections/db/sql/TestSqlCollection.h index 6a30fde..3da0f9b \
100644
--- a/tests/core-impl/collections/db/sql/TestSqlCollection.h
+++ b/tests/core-impl/collections/db/sql/TestSqlCollection.h
@@ -22,7 +22,7 @@
#include <KTempDir>
class SqlMountPointManagerMock;
-class MySqlStorage;
+class MySqlEmbeddedStorage;
namespace Collections {
class SqlCollection;
@@ -47,7 +47,7 @@ private slots:
private:
Collections::SqlCollection *m_collection;
SqlMountPointManagerMock *m_mpmMock;
- MySqlStorage *m_storage;
+ MySqlEmbeddedStorage *m_storage;
KTempDir *m_tmpDir;
};
diff --git a/tests/core-impl/collections/db/sql/TestSqlCollectionLocation.cpp \
b/tests/core-impl/collections/db/sql/TestSqlCollectionLocation.cpp index \
e83724f..0274498 100644
--- a/tests/core-impl/collections/db/sql/TestSqlCollectionLocation.cpp
+++ b/tests/core-impl/collections/db/sql/TestSqlCollectionLocation.cpp
@@ -115,8 +115,8 @@ TestSqlCollectionLocation::initTestCase()
{
Amarok::Components::setLogger( new ProxyLogger() );
m_tmpDir = new KTempDir();
- m_storage = new MySqlEmbeddedStorage( m_tmpDir->name() );
- QVERIFY( m_storage->init() );
+ m_storage = new MySqlEmbeddedStorage();
+ QVERIFY( m_storage->init( m_tmpDir->name() ) );
m_collection = new Collections::SqlCollection( m_storage );
SqlMountPointManagerMock *mock = new SqlMountPointManagerMock( this, m_storage \
);
mock->setCollectionFolders( QStringList() << m_tmpDir->name() ); // the target \
folder needs to have enough space and be writable
diff --git a/tests/core-impl/collections/db/sql/TestSqlCollectionLocation.h \
b/tests/core-impl/collections/db/sql/TestSqlCollectionLocation.h index \
3331b6a..10f3074 100644
--- a/tests/core-impl/collections/db/sql/TestSqlCollectionLocation.h
+++ b/tests/core-impl/collections/db/sql/TestSqlCollectionLocation.h
@@ -21,7 +21,7 @@
#include <KTempDir>
-class MySqlStorage;
+class MySqlEmbeddedStorage;
namespace Collections
{
class SqlCollection;
@@ -50,7 +50,7 @@ private:
private:
Collections::SqlCollection *m_collection;
- MySqlStorage *m_storage;
+ MySqlEmbeddedStorage *m_storage;
KTempDir *m_tmpDir;
};
diff --git a/tests/core-impl/collections/db/sql/TestSqlQueryMaker.cpp \
b/tests/core-impl/collections/db/sql/TestSqlQueryMaker.cpp index 5c83fc5..8811290 \
100644
--- a/tests/core-impl/collections/db/sql/TestSqlQueryMaker.cpp
+++ b/tests/core-impl/collections/db/sql/TestSqlQueryMaker.cpp
@@ -68,8 +68,8 @@ void
TestSqlQueryMaker::initTestCase()
{
m_tmpDir = new KTempDir();
- m_storage = new MySqlEmbeddedStorage( m_tmpDir->name() );
- QVERIFY( m_storage->init() );
+ m_storage = new MySqlEmbeddedStorage();
+ QVERIFY( m_storage->init( m_tmpDir->name() ) );
m_collection = new Collections::SqlCollection( m_storage );
QMap<int,QString> mountPoints;
diff --git a/tests/core-impl/collections/db/sql/TestSqlQueryMaker.h \
b/tests/core-impl/collections/db/sql/TestSqlQueryMaker.h index 5c6e10b..b9703b2 \
100644
--- a/tests/core-impl/collections/db/sql/TestSqlQueryMaker.h
+++ b/tests/core-impl/collections/db/sql/TestSqlQueryMaker.h
@@ -22,7 +22,7 @@
#include <KTempDir>
-class MySqlStorage;
+class MySqlEmbeddedStorage;
class SqlMountPointManagerMock;
namespace Collections {
@@ -95,7 +95,7 @@ private:
Collections::SqlCollection *m_collection;
SqlMountPointManagerMock *m_mpm;
- MySqlStorage *m_storage;
+ MySqlEmbeddedStorage *m_storage;
KTempDir *m_tmpDir;
};
diff --git a/tests/core-impl/collections/db/sql/TestSqlScanManager.cpp \
b/tests/core-impl/collections/db/sql/TestSqlScanManager.cpp index 2c942dd..217d4e4 \
100644
--- a/tests/core-impl/collections/db/sql/TestSqlScanManager.cpp
+++ b/tests/core-impl/collections/db/sql/TestSqlScanManager.cpp
@@ -59,8 +59,8 @@ TestSqlScanManager::initTestCase()
m_tmpDatabaseDir = new KTempDir();
QVERIFY( m_tmpDatabaseDir->exists() );
- m_storage = new MySqlEmbeddedStorage( m_tmpDatabaseDir->name() );
- QVERIFY( m_storage->init() );
+ m_storage = new MySqlEmbeddedStorage();
+ QVERIFY( m_storage->init( m_tmpDatabaseDir->name() ) );
m_collection = new Collections::SqlCollection( m_storage );
connect( m_collection, SIGNAL(updated()), this, SLOT(slotCollectionUpdated()) );
diff --git a/tests/core-impl/collections/db/sql/TestSqlScanManager.h \
b/tests/core-impl/collections/db/sql/TestSqlScanManager.h index e408f78..7cb2470 \
100644
--- a/tests/core-impl/collections/db/sql/TestSqlScanManager.h
+++ b/tests/core-impl/collections/db/sql/TestSqlScanManager.h
@@ -24,7 +24,7 @@
#include <KTempDir>
-class MySqlStorage;
+class MySqlEmbeddedStorage;
class GenericScanManager;
class QIODevice;
@@ -169,7 +169,7 @@ private:
int m_collectionUpdatedCount;
- MySqlStorage *m_storage;
+ MySqlEmbeddedStorage *m_storage;
KTempDir *m_tmpDatabaseDir;
KTempDir *m_tmpCollectionDir;
QString m_sourcePath; // the path to the template .mp3 file
diff --git a/tests/core-impl/collections/db/sql/TestSqlTrack.cpp \
b/tests/core-impl/collections/db/sql/TestSqlTrack.cpp index d3bdf81..489de85 100644
--- a/tests/core-impl/collections/db/sql/TestSqlTrack.cpp
+++ b/tests/core-impl/collections/db/sql/TestSqlTrack.cpp
@@ -46,8 +46,8 @@ void
TestSqlTrack::initTestCase()
{
m_tmpDir = new KTempDir();
- m_storage = new MySqlEmbeddedStorage( m_tmpDir->name() );
- QVERIFY( m_storage->init() );
+ m_storage = new MySqlEmbeddedStorage();
+ QVERIFY( m_storage->init( m_tmpDir->name() ) );
m_collection = new Collections::SqlCollection( m_storage );
m_collection->setMountPointManager( new SqlMountPointManagerMock( this, \
m_storage ) );
diff --git a/tests/core-impl/collections/db/sql/TestSqlTrack.h \
b/tests/core-impl/collections/db/sql/TestSqlTrack.h index 2ba4929..2832fcb 100644
--- a/tests/core-impl/collections/db/sql/TestSqlTrack.h
+++ b/tests/core-impl/collections/db/sql/TestSqlTrack.h
@@ -21,7 +21,7 @@
#include <KTempDir>
-class MySqlStorage;
+class MySqlEmbeddedStorage;
class SqlRegistry;
namespace Collections {
@@ -65,7 +65,7 @@ private:
void getAllValues( Meta::SqlTrack *track );
Collections::SqlCollection *m_collection;
- MySqlStorage *m_storage;
+ MySqlEmbeddedStorage *m_storage;
KTempDir *m_tmpDir;
};
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic