mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-20 02:50:46 -06:00
Change the internal data type for cell contents to a binary type
Store the data of a DB cell in a QByteArray, i.e. a binary data type, instead of putting it in a QString, thus converting it to a UTF8 string. Rewrite the reading and writing of DB cells to correctly handle binary data containing 0x00 bytes. Change the edit dialog to actually do all the data checks etc. on a currently invisible QHexEdit widget instead of a QTextEdit. All these changes combined make it possible to actually store binary data without it being corrupted. You can for example import pictures now, export them and actually open the exported file. So this is an improvement.
This commit is contained in:
@@ -4,12 +4,17 @@
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include "sqlitedb.h"
|
||||
#include <src/qhexedit.h>
|
||||
|
||||
EditDialog::EditDialog(QWidget* parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::EditDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
hexEdit = new QHexEdit(this);
|
||||
hexEdit->setVisible(false);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -24,6 +29,7 @@ void EditDialog::reset()
|
||||
curCol = -1;
|
||||
ui->editData->setPlainText("");
|
||||
ui->editData->setFocus();
|
||||
hexEdit->setData(QByteArray());
|
||||
setDataType(kSQLiteMediaType_Void, 0);
|
||||
}
|
||||
|
||||
@@ -57,14 +63,15 @@ void EditDialog::closeEvent(QCloseEvent*)
|
||||
emit goingAway();
|
||||
}
|
||||
|
||||
void EditDialog::loadText(const QString& text, int row, int col)
|
||||
void EditDialog::loadText(const QByteArray& data, int row, int col)
|
||||
{
|
||||
ui->editData->setPlainText(text);
|
||||
ui->editData->setPlainText(data);
|
||||
ui->editData->setFocus();
|
||||
ui->editData->selectAll();
|
||||
hexEdit->setData(data);
|
||||
curRow = row;
|
||||
curCol = col;
|
||||
if(ui->editData->toPlainText().length() > 0)
|
||||
if(hexEdit->data().length() > 0)
|
||||
setDataType(kSQLiteMediaType_String, 0);
|
||||
else
|
||||
setDataType(kSQLiteMediaType_Void, 0);
|
||||
@@ -84,11 +91,12 @@ void EditDialog::importData()
|
||||
QFile file(fileName);
|
||||
if(file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QTextStream stream(&file);
|
||||
ui->editData->setPlainText(stream.readAll());
|
||||
QByteArray d = file.readAll();
|
||||
hexEdit->setData(d);
|
||||
ui->editData->setPlainText(d);
|
||||
file.close();
|
||||
}
|
||||
setDataType(type, ui->editData->toPlainText().length());
|
||||
setDataType(type, hexEdit->data().length());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,8 +127,7 @@ void EditDialog::exportData()
|
||||
QFile file(fileName);
|
||||
if(file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
QTextStream stream(&file);
|
||||
stream << ui->editData->toPlainText();
|
||||
file.write(hexEdit->data());
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
@@ -134,13 +141,14 @@ void EditDialog::exportData()
|
||||
void EditDialog::clearData()
|
||||
{
|
||||
ui->editData->setPlainText("");
|
||||
hexEdit->setData(QByteArray());
|
||||
setDataType(kSQLiteMediaType_Void, 0);
|
||||
}
|
||||
|
||||
void EditDialog::accept()
|
||||
{
|
||||
if(dataType == kSQLiteMediaType_String)
|
||||
emit updateRecordText(curRow, curCol, ui->editData->toPlainText());
|
||||
emit updateRecordText(curRow, curCol, hexEdit->data());
|
||||
|
||||
if (dataType == kSQLiteMediaType_Void)
|
||||
emit updateRecordText(curRow, curCol, "");
|
||||
@@ -150,8 +158,11 @@ void EditDialog::accept()
|
||||
|
||||
void EditDialog::editTextChanged()
|
||||
{
|
||||
if(ui->editData->hasFocus())
|
||||
hexEdit->setData(ui->editData->toPlainText().toUtf8());
|
||||
|
||||
int newtype = kSQLiteMediaType_String;
|
||||
if(ui->editData->toPlainText().length() == 0)
|
||||
if(hexEdit->data().length() == 0)
|
||||
newtype = kSQLiteMediaType_Void;
|
||||
setDataType(newtype, ui->editData->toPlainText().length());
|
||||
setDataType(newtype, hexEdit->data().length());
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __EDITDIALOG_H__
|
||||
|
||||
#include <QDialog>
|
||||
class QHexEdit;
|
||||
|
||||
namespace Ui {
|
||||
class EditDialog;
|
||||
@@ -23,7 +24,7 @@ public:
|
||||
|
||||
public slots:
|
||||
virtual void reset();
|
||||
virtual void loadText(const QString& text, int row, int col);
|
||||
virtual void loadText(const QByteArray& data, int row, int col);
|
||||
|
||||
private slots:
|
||||
virtual void enableExport(bool enabled);
|
||||
@@ -37,10 +38,11 @@ private slots:
|
||||
|
||||
signals:
|
||||
void goingAway();
|
||||
void updateRecordText(int, int, const QString&);
|
||||
void updateRecordText(int, int, const QByteArray&);
|
||||
|
||||
private:
|
||||
Ui::EditDialog* ui;
|
||||
QHexEdit* hexEdit;
|
||||
int dataType;
|
||||
int dataSize;
|
||||
int curCol;
|
||||
|
||||
@@ -73,7 +73,7 @@ void ExportCsvDialog::accept()
|
||||
rowList data = pdb->browseRecs;
|
||||
for(int i=0;i<data.size();i++)
|
||||
{
|
||||
QStringList& row = data[i];
|
||||
QList<QByteArray> row = data[i];
|
||||
for(int j=1;j<row.size();j++)
|
||||
{
|
||||
QString content = row[j];
|
||||
|
||||
@@ -105,7 +105,7 @@ void MainWindow::init()
|
||||
connect(ui->dataTable->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(browseTableHeaderClicked(int)));
|
||||
connect(ui->dataTable->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(setRecordsetLabel()));
|
||||
connect(editWin, SIGNAL(goingAway()), this, SLOT(editWinAway()));
|
||||
connect(editWin, SIGNAL(updateRecordText(int, int , QString)), this, SLOT(updateRecordText(int, int , QString)));
|
||||
connect(editWin, SIGNAL(updateRecordText(int, int, QByteArray)), this, SLOT(updateRecordText(int, int , QByteArray)));
|
||||
|
||||
// Load window settings
|
||||
QSettings settings(QApplication::organizationName(), QApplication::organizationName());
|
||||
@@ -449,10 +449,10 @@ void MainWindow::updateTableView(int lineToSelect, bool keepColumnWidths)
|
||||
rowLabel.setNum(rowNum+1);
|
||||
browseTableModel->setVerticalHeaderItem(rowNum, new QStandardItem(rowLabel));
|
||||
colNum = 0;
|
||||
QStringList& rt = tab[i];
|
||||
QList<QByteArray> rt = tab[i];
|
||||
for (int e = 1; e < rt.size(); ++e)
|
||||
{
|
||||
QString& content = rt[e];
|
||||
QString content = rt[e];
|
||||
|
||||
QStandardItem* item = new QStandardItem(content);
|
||||
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
@@ -704,20 +704,19 @@ void MainWindow::helpAbout()
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void MainWindow::updateRecordText(int row, int col, const QString& newtext)
|
||||
void MainWindow::updateRecordText(int row, int col, const QByteArray& newtext)
|
||||
{
|
||||
if (!db.updateRecord(row, col, newtext)){
|
||||
QMessageBox::information( this, QApplication::applicationName(), tr("Data could not be updated"));
|
||||
}
|
||||
|
||||
rowList tab = db.browseRecs;
|
||||
QStringList& rt = tab[row];
|
||||
QString& cv = rt[col+1];//must account for rowid
|
||||
QList<QByteArray>& rt = tab[row];
|
||||
QByteArray& cv = rt[col+1];//must account for rowid
|
||||
|
||||
QStandardItem* item = new QStandardItem(cv);
|
||||
QStandardItem* item = new QStandardItem(QString(cv));
|
||||
item->setToolTip( wrapText(cv) );
|
||||
browseTableModel->setItem(row, col, item);
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::editWinAway()
|
||||
@@ -730,8 +729,8 @@ void MainWindow::editWinAway()
|
||||
void MainWindow::editText(int row, int col)
|
||||
{
|
||||
rowList tab = db.browseRecs;
|
||||
QStringList& rt = tab[row];
|
||||
QString cv = rt[col+1];//must account for rowid
|
||||
QList<QByteArray> rt = tab[row];
|
||||
QByteArray cv = rt[col+1];//must account for rowid
|
||||
|
||||
editWin->loadText(cv , row, col);
|
||||
editWin->show();
|
||||
|
||||
@@ -127,7 +127,7 @@ private slots:
|
||||
virtual void editTable();
|
||||
virtual void helpWhatsThis();
|
||||
virtual void helpAbout();
|
||||
virtual void updateRecordText( int row, int col, const QString& newtext );
|
||||
virtual void updateRecordText(int row, int col, const QByteArray& newtext);
|
||||
virtual void editWinAway();
|
||||
virtual void editText( int row, int col );
|
||||
virtual void doubleClickTable(const QModelIndex& index);
|
||||
|
||||
124
src/sqlitedb.cpp
124
src/sqlitedb.cpp
@@ -386,8 +386,8 @@ bool DBBrowserDB::deleteRecord( int wrow)
|
||||
if (!isOpen()) return false;
|
||||
bool ok = false;
|
||||
rowList tab = browseRecs;
|
||||
QStringList& rt = tab[wrow];
|
||||
QString& rowid = rt[0];
|
||||
QList<QByteArray> rt = tab[wrow];
|
||||
QString rowid = rt[0];
|
||||
lastErrorMessage = QString("no error");
|
||||
|
||||
QString statement = QString("DELETE FROM `%1` WHERE rowid=%2;").arg(curBrowseTableName).arg(rowid);
|
||||
@@ -406,45 +406,52 @@ bool DBBrowserDB::deleteRecord( int wrow)
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool DBBrowserDB::updateRecord(int wrow, int wcol, const QString & wtext)
|
||||
bool DBBrowserDB::updateRecord(int wrow, int wcol, const QByteArray& wtext)
|
||||
{
|
||||
char * errmsg;
|
||||
if (!hasValidBrowseSet) return false;
|
||||
if (!isOpen()) return false;
|
||||
bool ok = false;
|
||||
|
||||
lastErrorMessage = QString("no error");
|
||||
|
||||
QStringList& rt = browseRecs[wrow];
|
||||
QString& rowid = rt[0];
|
||||
QString& cv = rt[wcol+1];//must account for rowid
|
||||
QList<QByteArray>& rt = browseRecs[wrow];
|
||||
QString rowid = rt[0];
|
||||
QByteArray& cv = rt[wcol+1];//must account for rowid
|
||||
QString ct = browseFields.at(wcol);
|
||||
|
||||
QString statement = QString("UPDATE `%1` SET `%2`=").arg(curBrowseTableName).arg(ct);
|
||||
QString sql = QString("UPDATE `%1` SET `%2`=? WHERE rowid=%4;").arg(curBrowseTableName).arg(ct).arg(rowid);
|
||||
|
||||
char * formSQL = sqlite3_mprintf("%Q", wtext.toUtf8().constData());
|
||||
statement.append(formSQL);
|
||||
if (formSQL) sqlite3_free(formSQL);
|
||||
|
||||
statement.append(" WHERE rowid=");
|
||||
statement.append(rowid);
|
||||
statement.append(";");
|
||||
logSQL(sql, kLogMsg_App);
|
||||
setRestorePoint();
|
||||
|
||||
if (_db){
|
||||
logSQL(statement, kLogMsg_App);
|
||||
setRestorePoint();
|
||||
if (SQLITE_OK==sqlite3_exec(_db,statement.toUtf8(),
|
||||
NULL,NULL,&errmsg)){
|
||||
ok=true;
|
||||
/*update local copy*/
|
||||
cv = wtext;
|
||||
} else {
|
||||
lastErrorMessage = QString::fromUtf8(errmsg);
|
||||
qCritical() << "update Record: " << lastErrorMessage;
|
||||
}
|
||||
sqlite3_stmt* stmt;
|
||||
if(sqlite3_prepare(_db, sql.toUtf8(), -1, &stmt, 0) != SQLITE_OK)
|
||||
{
|
||||
lastErrorMessage = sqlite3_errmsg(_db);
|
||||
qCritical() << "updateRecord: " << lastErrorMessage;
|
||||
return false;
|
||||
}
|
||||
if(sqlite3_bind_blob(stmt, 1, wtext.constData(), wtext.length(), SQLITE_STATIC) != SQLITE_OK)
|
||||
{
|
||||
lastErrorMessage = sqlite3_errmsg(_db);
|
||||
qCritical() << "updateRecord: " << lastErrorMessage;
|
||||
return false;
|
||||
}
|
||||
if(sqlite3_step(stmt) != SQLITE_DONE)
|
||||
{
|
||||
lastErrorMessage = sqlite3_errmsg(_db);
|
||||
qCritical() << "updateRecord: " << lastErrorMessage;
|
||||
return false;
|
||||
}
|
||||
if(sqlite3_finalize(stmt) != SQLITE_OK)
|
||||
{
|
||||
lastErrorMessage = sqlite3_errmsg(_db);
|
||||
qCritical() << "updateRecord: " << lastErrorMessage;
|
||||
return false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
cv = wtext;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBBrowserDB::browseTable( const QString & tablename, const QString& orderby )
|
||||
@@ -664,44 +671,43 @@ bool DBBrowserDB::renameTable(const QString& from_table, const QString& to_table
|
||||
|
||||
void DBBrowserDB::getTableRecords( const QString & tablename, const QString& orderby )
|
||||
{
|
||||
sqlite3_stmt *vm;
|
||||
const char *tail;
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
int ncol;
|
||||
QStringList r;
|
||||
// char *errmsg;
|
||||
int err=0;
|
||||
// int tabnum = 0;
|
||||
QList<QByteArray> r;
|
||||
browseRecs.clear();
|
||||
idmap.clear();
|
||||
lastErrorMessage = QObject::tr("no error");
|
||||
|
||||
QString statement = QString("SELECT rowid, * FROM `%1` ORDER BY %2;").arg(tablename).arg(orderby);
|
||||
logSQL(statement, kLogMsg_App);
|
||||
QByteArray utf8Statement = statement.toUtf8();
|
||||
err=sqlite3_prepare(_db,utf8Statement,utf8Statement.length(),
|
||||
&vm, &tail);
|
||||
if (err == SQLITE_OK){
|
||||
int rownum = 0;
|
||||
|
||||
while ( sqlite3_step(vm) == SQLITE_ROW ){
|
||||
r.clear();
|
||||
ncol = sqlite3_data_count(vm);
|
||||
for (int e=0; e<ncol; ++e){
|
||||
QString rv = QString::fromUtf8((const char*)sqlite3_column_text(vm,e));
|
||||
r << rv;
|
||||
if (e==0){
|
||||
idmap.insert(rv.toInt(),rownum);
|
||||
rownum++;
|
||||
}
|
||||
}
|
||||
browseRecs.append(r);
|
||||
}
|
||||
|
||||
sqlite3_finalize(vm);
|
||||
}else{
|
||||
QString sql = QString("SELECT rowid, * FROM `%1` ORDER BY %2;").arg(tablename).arg(orderby);
|
||||
logSQL(sql, kLogMsg_App);
|
||||
if(sqlite3_prepare(_db, sql.toUtf8(), -1, &stmt, 0) != SQLITE_OK)
|
||||
{
|
||||
lastErrorMessage = QObject::tr("could not get fields");
|
||||
return;
|
||||
}
|
||||
|
||||
int rownum = 0;
|
||||
|
||||
while(sqlite3_step(stmt) == SQLITE_ROW)
|
||||
{
|
||||
r.clear();
|
||||
ncol = sqlite3_data_count(stmt);
|
||||
for(int e=0;e<ncol;++e)
|
||||
{
|
||||
QByteArray rv = QByteArray(static_cast<const char*>(sqlite3_column_blob(stmt, e)), sqlite3_column_bytes(stmt, e));
|
||||
r.append(rv);
|
||||
|
||||
if(e == 0)
|
||||
{
|
||||
idmap.insert(rv.toInt(), rownum);
|
||||
rownum++;
|
||||
}
|
||||
}
|
||||
browseRecs.append(r);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
resultMap DBBrowserDB::getFindResults( const QString & wstatement)
|
||||
|
||||
@@ -26,7 +26,7 @@ typedef QMap<int, class DBBrowserField> fieldMap;
|
||||
typedef QMultiMap<QString, class DBBrowserObject> objectMap;
|
||||
typedef QMap<int, int> rowIdMap;
|
||||
|
||||
typedef QList<QStringList> rowList;
|
||||
typedef QList<QList<QByteArray> > rowList;
|
||||
typedef QMap<int, QString> resultMap;
|
||||
|
||||
class DBBrowserField
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
void updateSchema() ;
|
||||
bool addRecord();
|
||||
bool deleteRecord(int wrow);
|
||||
bool updateRecord(int wrow, int wcol, const QString & wtext);
|
||||
bool updateRecord(int wrow, int wcol, const QByteArray& wtext);
|
||||
bool browseTable( const QString & tablename, const QString& orderby = "rowid" );
|
||||
|
||||
bool createTable(const QString& name, const QList<DBBrowserField>& structure);
|
||||
|
||||
Reference in New Issue
Block a user