Rivendellaudio/lib/rddb.cpp
Fred Gleason cc3dc06b4a 2019-09-25 Fred Gleason <fredg@paravelsystems.com>
* Fixed a bug in rddbmgr(8) that caused a segfault when processing
	a SQL error.
2019-09-25 16:47:21 -04:00

208 lines
4.5 KiB
C++

// rddb.cpp
//
// Database driver with automatic reconnect
//
// (C) Copyright 2007 Dan Mills <dmills@exponent.myzen.co.uk>
// (C) Copyright 2018-2019 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// 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 along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <netdb.h>
#include <stdio.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <QObject>
#include <QString>
#include <QTextCodec>
#include <QTranslator>
#include <QSqlError>
#include <QStringList>
#include <QVariant>
#include "rdapplication.h"
#include "rddb.h"
#include "rddbheartbeat.h"
RDSqlQuery::RDSqlQuery (const QString &query,bool reconnect):
QSqlQuery(query)
{
QSqlDatabase db;
QString err;
sql_columns=0;
if (!isActive() && reconnect) {
db = QSqlDatabase::database();
if (db.open()) {
clear();
exec(query);
err=QObject::tr("DB connection re-established");
}
else {
err=QObject::tr("Could not re-establish DB connection")+
+"["+db.lastError().text()+"]";
}
fprintf(stderr,"%s\n",(const char *)err);
if(rda!=NULL) {
rda->syslog(LOG_ERR,(const char *)err);
}
}
if(isActive()) {
//printf("QUERY: %s\n",(const char *)query.toUtf8());
QStringList f0=query.split(" ");
if(f0[0].toLower()=="select") {
for(int i=1;i<f0.size();i++) {
if(f0[i].toLower()=="from") {
QString fields;
for(int j=1;j<i;j++) {
fields+=f0[j];
}
QStringList f1=fields.split(",");
sql_columns=f1.size();
continue;
}
}
}
}
else {
err=QObject::tr("invalid SQL or failed DB connection")+
+"["+lastError().text()+"]: "+query;
fprintf(stderr,"%s\n",(const char *)err);
if(rda!=NULL) {
rda->syslog(LOG_ERR,(const char *)err);
}
}
}
int RDSqlQuery::columns() const
{
return sql_columns;
}
QVariant RDSqlQuery::value(int index) const
{
QVariant ret=QSqlQuery::value(index);
if(!ret.isValid()) {
fprintf(stderr,"for query: %s\n\n",(const char *)executedQuery().toUtf8());
}
return ret;
}
QVariant RDSqlQuery::run(const QString &sql,bool *ok)
{
QVariant ret;
RDSqlQuery *q=new RDSqlQuery(sql);
if(ok!=NULL) {
*ok=q->isActive();
}
ret=q->lastInsertId();
delete q;
return ret;
}
bool RDSqlQuery::apply(const QString &sql,QString *err_msg)
{
bool ret=false;
RDSqlQuery *q=new RDSqlQuery(sql);
ret=q->isActive();
if((err_msg!=NULL)&&(!ret)) {
*err_msg="sql error: "+q->lastError().text()+" query: "+sql;
}
delete q;
return ret;
}
int RDSqlQuery::rows(const QString &sql)
{
int ret=0;
RDSqlQuery *q=new RDSqlQuery(sql);
ret=q->size();
delete q;
return ret;
}
bool RDOpenDb (int *schema,QString *err_str,RDConfig *config)
{
QSqlDatabase db;
QString sql;
QSqlQuery *q;
if (!db.isOpen()){
db=QSqlDatabase::addDatabase(config->mysqlDriver());
if(!db.isValid()) {
*err_str+= QString(QObject::tr("Couldn't initialize MySql driver!"));
return false;
}
db.setHostName(config->mysqlHostname());
db.setDatabaseName(config->mysqlDbname());
db.setUserName(config->mysqlUsername());
db.setPassword(config->mysqlPassword());
if(!db.open()) {
*err_str+=QString(QObject::tr("Couldn't open MySQL connection on"))+
" \""+config->mysqlHostname()+"\".";
db.removeDatabase(config->mysqlDbname());
db.close();
return false;
}
}
new RDDbHeartbeat(config->mysqlHeartbeatInterval());
sql=QString("set NAMES utf8mb4 collate utf8mb4_general_ci");
q=new QSqlQuery(sql);
delete q;
*schema=-1;
sql=QString("show tables where ")+
"Tables_in_"+config->mysqlDbname()+"=\"VERSION\"";
q=new QSqlQuery(sql);
if(q->first()) {
delete q;
q=new QSqlQuery("select DB from VERSION");
if(q->first()) {
*schema=q->value(0).toUInt();
}
}
else {
delete q;
sql=QString("show tables");
q=new QSqlQuery(sql);
if(!q->first()) {
*schema=0;
}
}
delete q;
return true;
}