1 /****************************************************************************************
2 * Copyright (c) 2008 Edward Toroshchin <edward.hades@gmail.com> *
3 * Copyright (c) 2009 Jeff Mitchell <mitchell@kde.org> *
4 * *
5 * This program is free software; you can redistribute it and/or modify it under *
6 * the terms of the GNU General Public License as published by the Free Software *
7 * Foundation; either version 2 of the License, or (at your option) any later *
8 * version. *
9 * *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY *
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
12 * PARTICULAR PURPOSE. See the GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License along with *
15 * this program. If not, see <http://www.gnu.org/licenses/>. *
16 ****************************************************************************************/
17
18 #define DEBUG_PREFIX "MySqlEmbeddedStorage"
19
20 #include "MySqlEmbeddedStorage.h"
21
22 #include <amarokconfig.h>
23 #include <core/support/Amarok.h>
24 #include <core/support/Debug.h>
25
26 #include <QDir>
27 #include <QVarLengthArray>
28 #include <QVector>
29 #include <QAtomicInt>
30
31 #include <mysql.h>
32
33 /** number of times the library is used.
34 */
35 static QAtomicInt libraryInitRef;
36
MySqlEmbeddedStorage()37 MySqlEmbeddedStorage::MySqlEmbeddedStorage()
38 : MySqlStorage()
39 {
40 m_debugIdent = "MySQLe";
41 }
42
43 bool
init(const QString & storageLocation)44 MySqlEmbeddedStorage::init( const QString &storageLocation )
45 {
46 // -- figuring out and setting the database path.
47 QString storagePath = storageLocation;
48 QString databaseDir;
49 // TODO: the following logic is not explained in the comments.
50 // tests use a different directory then the real run
51 if( storagePath.isEmpty() )
52 {
53 storagePath = Amarok::saveLocation();
54 databaseDir = Amarok::config( "MySQLe" ).readEntry( "data", QString(storagePath + "mysqle") );
55 }
56 else
57 {
58 QDir dir( storagePath );
59 dir.mkpath( "." ); //ensure directory exists
60 databaseDir = dir.absolutePath() + QDir::separator() + "mysqle";
61 }
62
63 QVector<const char*> mysql_args;
64 QByteArray dataDir = QStringLiteral( "--datadir=%1" ).arg( databaseDir ).toLocal8Bit();
65 mysql_args << "amarok"
66 << dataDir.constData()
67 // CAUTION: if we ever change the table type we will need to fix a number of MYISAM specific
68 // functions, such as FULLTEXT indexing.
69 << "--default-storage-engine=MyISAM"
70 << "--innodb=OFF"
71 << "--skip-grant-tables"
72 #if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID >= 50700)
73 << "--myisam-recover-options=FORCE"
74 #else
75 << "--myisam-recover=FORCE"
76 #endif
77 << "--key-buffer-size=16777216" // (16Mb)
78 << "--character-set-server=utf8"
79 << "--collation-server=utf8_bin";
80
81
82 if( !QFile::exists( databaseDir ) )
83 {
84 QDir dir( databaseDir );
85 dir.mkpath( "." );
86 }
87
88 // -- initializing the library
89 // we only need to do this once
90 if( !libraryInitRef.fetchAndAddOrdered( 1 ) )
91 {
92 int ret = mysql_library_init( mysql_args.size(), const_cast<char**>(mysql_args.data()), 0 );
93 if( ret != 0 )
94 {
95 // mysql sources show that there is only 0 and 1 as return code
96 // and it can only fail because of memory or thread issues.
97 reportError( "library initialization "
98 "failed, return code " + QString::number( ret ) );
99 libraryInitRef.deref();
100 return false;
101 }
102 }
103
104 m_db = mysql_init( NULL );
105 if( !m_db )
106 {
107 reportError( "call to mysql_init" );
108 return false;
109 }
110
111 if( mysql_options( m_db, MYSQL_READ_DEFAULT_GROUP, "amarokclient" ) )
112 reportError( "Error setting options for READ_DEFAULT_GROUP" );
113 if( mysql_options( m_db, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL ) )
114 reportError( "Error setting option to use embedded connection" );
115
116 if( !mysql_real_connect( m_db, NULL,NULL,NULL, 0, 0,NULL, 0 ) )
117 {
118 error() << "Could not connect to mysql embedded!";
119 reportError( "call to mysql_real_connect" );
120 mysql_close( m_db );
121 m_db = 0;
122 return false;
123 }
124
125 if( !sharedInit( QLatin1String("amarok") ) )
126 {
127 // if sharedInit fails then we can usually not switch to the correct database
128 // sharedInit already reports errors.
129 mysql_close( m_db );
130 m_db = 0;
131 return false;
132 }
133
134 MySqlStorage::initThreadInitializer();
135
136 return true;
137 }
138
~MySqlEmbeddedStorage()139 MySqlEmbeddedStorage::~MySqlEmbeddedStorage()
140 {
141 if( m_db )
142 {
143 mysql_close( m_db );
144 libraryInitRef.deref();
145 }
146 }
147
148