File: statisticsdb.cpp

package info (click to toggle)
kopete 4%3A4.14.1-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 38,368 kB
  • ctags: 49,852
  • sloc: cpp: 345,847; ansic: 13,954; xml: 1,775; lex: 1,735; python: 421; sh: 271; perl: 126; ruby: 28; makefile: 17
file content (173 lines) | stat: -rw-r--r-- 5,261 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
    statisticsdb.cpp

    Copyright (c) 2003-2004 by Marc Cramdal        <marc.cramdal@gmail.com>

    Copyright (c) 2007      by the Kopete Developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "statisticsdb.h"

#include <QByteArray>
#include <QSqlDriver>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlRecord>
#include <QVariant>

#include <kdebug.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kdeversion.h>

#include <time.h>

StatisticsDB::StatisticsDB()
{
	QString path = KStandardDirs::locateLocal ( "appdata", "kopete_statistics-0.1.db" );
	kDebug ( 14315 ) << "DB path:" << path;
	m_db = QSqlDatabase::addDatabase ( "QSQLITE", "kopete-statistics" );
	m_db.setDatabaseName(path);
	if (! m_db.open()){
		kError ( 14315 ) << "Unable to open database" << path;
		return;
	}

	// With synchronous mode turned off, SQLite does not call fsync (for every query).
	// System call fsync only ask kernel to flush buffers to disk and wait until complete.
	// It is expensive and not all filesystems implement it. Also it does not guarantee data lose.
	// If Kopete crash database will not be corrupted even if fsync will not called (but kernel must not crash).
	// Synchronous mode is turned on by default and degrades performance about 50 times.
	// On bigger database it cause big slowdown and changing status from online to offline can take ages...
	// When synchronous mode is off it dramatically speed up writes to database.
	// Synchronous mode has more disadvantages, so turn it off.
	query ( "PRAGMA synchronous = OFF" );

	has_transaction = m_db.driver()->hasFeature(QSqlDriver::Transactions);

	// Creates the tables if they do not exist.
	QStringList result = query ( "SELECT name FROM sqlite_master WHERE type='table'" );

	if ( !result.contains ( "contactstatus" ) )
	{
		kDebug ( 14315 ) << "Database empty";
		query ( QString ( "CREATE TABLE contactstatus "
		                  "(id INTEGER PRIMARY KEY,"
		                  "metacontactid TEXT,"
		                  "status TEXT,"
		                  "datetimebegin INTEGER,"
		                  "datetimeend INTEGER"
		                  ");" ) );
	}

	if ( !result.contains ( "commonstats" ) )
	{
		// To store things like the contact answer time etc.
		query ( QString ( "CREATE TABLE commonstats"
		                  " (id INTEGER PRIMARY KEY,"
		                  "metacontactid TEXT,"
		                  "statname TEXT," // for instance, answertime, lastmessage, messagelength ...
		                  "statvalue1 TEXT,"
		                  "statvalue2 TEXT"
		                  ");" ) );
	}

	if ( !result.contains ( "statsgroup" ) )
	{
		query ( QString ( "CREATE TABLE statsgroup"
		                  "(id INTEGER PRIMARY KEY,"
		                  "datetimebegin INTEGER,"
		                  "datetimeend INTEGER,"
		                  "caption TEXT);" ) );
	}

}

StatisticsDB::~StatisticsDB()
{
	m_db.close();
}

/**
 * Executes a SQL query on the already opened database
 * @param statement SQL program to execute. Only one SQL statement is allowed.
 * @param debug     Set to true for verbose debug output.
 * @retval names    Will contain all column names, set to NULL if not used.
 * @return          The queried data, or QStringList() on error.
 */
QStringList StatisticsDB::query ( const QString& statement, QStringList* const names, bool debug )
{

	if ( debug )
		kDebug ( 14315 ) << "query-start: " << statement;

	clock_t start = clock();

	QStringList values;
	QSqlQuery query ( m_db );

	// prepare query
	if ( !query.prepare ( statement ) )
	{
		kError ( 14315 ) << "error" << query.lastError().text() << "on query:" << statement;
		return QStringList();
	}

	// do query
	if ( !query.exec() )
	{
		kError ( 14315 ) << "error" << query.lastError().text() << "on query:" << statement;
		return QStringList();
	}
	
	int columns = query.record().count();
	while (query.next()) {
		for ( int i = 0; i < columns; i++ ){
			values << query.value(i).toString();
			if ( names )
				*names << query.record().fieldName(i);
		}
	}

	if ( debug )
	{
		clock_t finish = clock();
		const double duration = ( double ) ( finish - start ) / CLOCKS_PER_SEC;
		kDebug ( 14315 ) << "SQL-query (" << duration << "s): " << statement;
	}

	return values;
}

bool StatisticsDB::transaction()
{
	if (!has_transaction)
		return true;

	bool ret = m_db.transaction();
	if (!ret)
		kError ( 14315 ) << "failed to open transaction";

	return ret;
}

bool StatisticsDB::commit()
{
	if (!has_transaction)
		return true;

	bool ret = m_db.commit();
	if (!ret)
		kError ( 14315 ) << "failed to commit transaction:" << m_db.lastError().text();

	return ret;
}