Improve escpaing support

When generating SQL statements properly escape all identifiers, even
those containing backticks which apparently are allowed inside
identifiers in SQLite.

See issue #387.
This commit is contained in:
Martin Kleusberg
2015-08-17 00:17:48 +02:00
parent 160bc87d3c
commit 631979c330
13 changed files with 95 additions and 62 deletions

View File

@@ -1,5 +1,6 @@
#include "ColumnDisplayFormatDialog.h"
#include "ui_ColumnDisplayFormatDialog.h"
#include "sqlitetypes.h"
ColumnDisplayFormatDialog::ColumnDisplayFormatDialog(const QString& colname, QString current_format, QWidget* parent)
: QDialog(parent),
@@ -56,21 +57,21 @@ void ColumnDisplayFormatDialog::updateSqlCode()
QString format = ui->comboDisplayFormat->itemData(ui->comboDisplayFormat->currentIndex()).toString();
#endif
if(format == "default")
ui->editDisplayFormat->setText("`" + column_name + "`");
ui->editDisplayFormat->setText(sqlb::escapeIdentifier(column_name));
else if(format == "lower")
ui->editDisplayFormat->setText("lower(`" + column_name + "`)");
ui->editDisplayFormat->setText("lower(" + sqlb::escapeIdentifier(column_name) + ")");
else if(format == "upper")
ui->editDisplayFormat->setText("upper(`" + column_name + "`)");
ui->editDisplayFormat->setText("upper(" + sqlb::escapeIdentifier(column_name) + ")");
else if(format == "epoch")
ui->editDisplayFormat->setText("datetime(`" + column_name + "`, 'unixepoch')");
ui->editDisplayFormat->setText("datetime(" + sqlb::escapeIdentifier(column_name) + ", 'unixepoch')");
else if(format == "julian")
ui->editDisplayFormat->setText("datetime(`" + column_name + "`)");
ui->editDisplayFormat->setText("datetime(" + sqlb::escapeIdentifier(column_name) + ")");
else if(format == "round")
ui->editDisplayFormat->setText("round(`" + column_name + "`)");
ui->editDisplayFormat->setText("round(" + sqlb::escapeIdentifier(column_name) + ")");
else if(format == "hex")
ui->editDisplayFormat->setText("printf('%x', `" + column_name + "`)");
ui->editDisplayFormat->setText("printf('%x', " + sqlb::escapeIdentifier(column_name) + ")");
else if(format == "octal")
ui->editDisplayFormat->setText("printf('%o', `" + column_name + "`)");
ui->editDisplayFormat->setText("printf('%o', " + sqlb::escapeIdentifier(column_name) + ")");
else if(format == "exponent")
ui->editDisplayFormat->setText("printf('%e', `" + column_name + "`)");
ui->editDisplayFormat->setText("printf('%e', " + sqlb::escapeIdentifier(column_name) + ")");
}

View File

@@ -57,7 +57,7 @@ void CreateIndexDialog::tableChanged(const QString& new_table)
void CreateIndexDialog::checkInput()
{
bool valid = true;
if(ui->editIndexName->text().isEmpty() || ui->editIndexName->text().contains("`"))
if(ui->editIndexName->text().isEmpty())
valid = false;
int num_columns = 0;
@@ -74,17 +74,17 @@ void CreateIndexDialog::checkInput()
void CreateIndexDialog::accept()
{
QString sql = QString("CREATE %1 INDEX `%2` ON `%3` (")
QString sql = QString("CREATE %1 INDEX %2 ON %3 (")
.arg(ui->checkIndexUnique->isChecked() ? "UNIQUE" : "")
.arg(ui->editIndexName->text())
.arg(ui->comboTableName->currentText());
.arg(sqlb::escapeIdentifier(ui->editIndexName->text()))
.arg(sqlb::escapeIdentifier(ui->comboTableName->currentText()));
for(int i=0; i < ui->tableIndexColumns->rowCount(); ++i)
{
if(ui->tableIndexColumns->item(i, 1)->data(Qt::CheckStateRole) == Qt::Checked)
{
sql.append(QString("`%1` %2,")
.arg(ui->tableIndexColumns->item(i, 0)->text())
sql.append(QString("%1 %2,")
.arg(sqlb::escapeIdentifier(ui->tableIndexColumns->item(i, 0)->text()))
.arg(qobject_cast<QComboBox*>(ui->tableIndexColumns->cellWidget(i, 2))->currentText()));
}
}

View File

@@ -218,7 +218,7 @@ QMimeData* DbStructureModel::mimeData(const QModelIndexList& indices) const
tableModel.setTable(data(index.sibling(index.row(), 0), Qt::DisplayRole).toString());
for(int i=0; i < tableModel.rowCount(); ++i)
{
QString insertStatement = "INSERT INTO `" + data(index.sibling(index.row(), 0), Qt::DisplayRole).toString() + "` VALUES(";
QString insertStatement = "INSERT INTO " + sqlb::escapeIdentifier(data(index.sibling(index.row(), 0), Qt::DisplayRole).toString()) + " VALUES(";
for(int j=1; j < tableModel.columnCount(); ++j)
insertStatement += QString("'%1',").arg(tableModel.data(tableModel.index(i, j)).toString());
insertStatement.chop(1);

View File

@@ -16,7 +16,7 @@ EditTableDialog::EditTableDialog(DBBrowserDB* db, const QString& tableName, bool
curTable(tableName),
m_table(tableName),
m_bNewTable(createTable),
m_sRestorePointName(QString("edittable_%1_save_%2").arg(curTable).arg(QDateTime::currentMSecsSinceEpoch()))
m_sRestorePointName(sqlb::escapeIdentifier(QString("edittable_%1_save_%2").arg(curTable).arg(QDateTime::currentMSecsSinceEpoch())))
{
// Create UI
ui->setupUi(this);
@@ -173,7 +173,7 @@ void EditTableDialog::checkInput()
{
QString normTableName = ui->editTableName->text().trimmed();
bool valid = true;
if(normTableName.isEmpty() || normTableName.contains("`"))
if(normTableName.isEmpty())
valid = false;
if(ui->treeWidget->topLevelItemCount() == 0)
valid = false;
@@ -272,7 +272,10 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
// we need to check for this case and cancel here. Maybe we can think of some way to modify the INSERT INTO ... SELECT statement
// to at least replace all troublesome NULL values by the default value
SqliteTableModel m(this, pdb);
m.setQuery(QString("SELECT COUNT(`%1`) FROM `%2` WHERE `%3` IS NULL;").arg(pdb->getObjectByName(curTable).table.rowidColumn()).arg(curTable).arg(field->name()));
m.setQuery(QString("SELECT COUNT(%1) FROM %2 WHERE %3 IS NULL;")
.arg(sqlb::escapeIdentifier(pdb->getObjectByName(curTable).table.rowidColumn()))
.arg(sqlb::escapeIdentifier(curTable))
.arg(sqlb::escapeIdentifier(field->name())));
if(m.data(m.index(0, 0)).toInt() > 0)
{
// There is a NULL value, so print an error message, uncheck the combobox, and return here
@@ -296,7 +299,10 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
if(!m_bNewTable)
{
SqliteTableModel m(this, pdb);
m.setQuery(QString("SELECT COUNT(*) FROM `%1` WHERE `%2` <> CAST(`%3` AS INTEGER);").arg(curTable).arg(field->name()).arg(field->name()));
m.setQuery(QString("SELECT COUNT(*) FROM %1 WHERE %2 <> CAST(%3 AS INTEGER);")
.arg(sqlb::escapeIdentifier(curTable))
.arg(sqlb::escapeIdentifier(field->name()))
.arg(sqlb::escapeIdentifier(field->name())));
if(m.data(m.index(0, 0)).toInt() > 0)
{
// There is a non-integer value, so print an error message, uncheck the combobox, and return here
@@ -337,14 +343,14 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
{
// Because our renameColumn() function fails when setting a column to unique when it already contains the same values
SqliteTableModel m(this, pdb);
m.setQuery(QString("SELECT COUNT(`%2`) FROM `%1`;").arg(curTable).arg(field->name()));
m.setQuery(QString("SELECT COUNT(%2) FROM %1;").arg(sqlb::escapeIdentifier(curTable)).arg(sqlb::escapeIdentifier(field->name())));
int rowcount = m.data(m.index(0, 0)).toInt();
m.setQuery(QString("SELECT COUNT(distinct `%2`) FROM `%1`;").arg(curTable).arg(field->name()));
m.setQuery(QString("SELECT COUNT(DISTINCT %2) FROM %1;").arg(sqlb::escapeIdentifier(curTable)).arg(sqlb::escapeIdentifier(field->name())));
int uniquecount = m.data(m.index(0, 0)).toInt();
if(rowcount != uniquecount)
{
// There is a NULL value, so print an error message, uncheck the combobox, and return here
QMessageBox::information(this, qApp->applicationName(), tr("Column `%1` has no unique data.\n").arg(field->name())
QMessageBox::information(this, qApp->applicationName(), tr("Column '%1'' has no unique data.\n").arg(field->name())
+ tr("This makes it impossible to set this flag. Please change the table data first."));
item->setCheckState(column, Qt::Unchecked);
return;

View File

@@ -210,7 +210,7 @@ void ExportCsvDialog::accept()
{
// if we are called from execute sql tab, query is already set
// and we only export 1 select
QString sQuery = QString("SELECT * from `%1`;").arg(selectedItems.at(i)->text());
QString sQuery = QString("SELECT * FROM %1;").arg(sqlb::escapeIdentifier(selectedItems.at(i)->text()));
exportQuery(sQuery, filenames.at(i));
}

View File

@@ -223,7 +223,7 @@ void ImportCsvDialog::accept()
it != csv.csv().end();
++it)
{
QString sql = QString("INSERT INTO `%1` VALUES(").arg(ui->editName->text());
QString sql = QString("INSERT INTO %1 VALUES(").arg(sqlb::escapeIdentifier(ui->editName->text()));
QStringList insertlist;
for(QStringList::const_iterator jt = it->begin(); jt != it->end(); ++jt)
@@ -321,7 +321,7 @@ void ImportCsvDialog::updatePreview()
void ImportCsvDialog::checkInput()
{
bool valid = true;
if(ui->editName->text().isEmpty() || ui->editName->text().contains("`"))
if(ui->editName->text().isEmpty())
valid = false;
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);

View File

@@ -348,7 +348,7 @@ void MainWindow::populateTable(const QString& tablename)
v.push_back(format);
only_defaults = false;
} else {
v.push_back("`" + db.getObjectByName(tablename).table.fields().at(i)->name() + "`");
v.push_back(sqlb::escapeIdentifier(db.getObjectByName(tablename).table.fields().at(i)->name()));
}
}
if(only_defaults)
@@ -652,7 +652,7 @@ void MainWindow::deleteObject()
QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Yes)
{
// Delete the table
QString statement = QString("DROP %1 `%2`;").arg(type.toUpper()).arg(table);
QString statement = QString("DROP %1 %2;").arg(type.toUpper()).arg(sqlb::escapeIdentifier(table));
if(!db.executeSQL( statement))
{
QString error = tr("Error: could not delete the %1. Message from database engine:\n%2").arg(type).arg(db.lastErrorMessage);

View File

@@ -100,7 +100,7 @@ void SqlExecutionArea::saveAsView()
return;
// Create the view
if(db->executeSQL(QString("CREATE VIEW `%1` AS %2;").arg(name).arg(model->query())))
if(db->executeSQL(QString("CREATE VIEW %1 AS %2;").arg(sqlb::escapeIdentifier(name)).arg(model->query())))
QMessageBox::information(this, qApp->applicationName(), tr("View successfully created."));
else
QMessageBox::warning(this, qApp->applicationName(), tr("Error creating view: %1").arg(db->lastErrorMessage));

View File

@@ -55,7 +55,7 @@ void VacuumDialog::accept()
// No, so execute a vacuum command for each selected object individually
QList<QTreeWidgetItem*> selection = ui->treeSelectedObjects->selectedItems();
foreach(QTreeWidgetItem* item, selection)
db->executeSQL(QString("VACUUM `%1`;").arg(item->text(0)), false);
db->executeSQL(QString("VACUUM %1;").arg(sqlb::escapeIdentifier(item->text(0))), false);
}
QApplication::restoreOverrideCursor();

View File

@@ -164,14 +164,14 @@ bool DBBrowserDB::attach(const QString& filename, QString attach_as)
// Attach database
QString key;
if(cipher) key = cipher->password();
if(!executeSQL(QString("ATTACH '%1' AS `%2` KEY '%3'").arg(filename).arg(attach_as).arg(key), false))
if(!executeSQL(QString("ATTACH '%1' AS %2 KEY '%3'").arg(filename).arg(sqlb::escapeIdentifier(attach_as)).arg(key), false))
{
QMessageBox::warning(0, qApp->applicationName(), lastErrorMessage);
return false;
}
if(cipher && cipher->pageSize() != 1024)
{
if(!executeSQL(QString("PRAGMA `%1`.cipher_page_size = %2").arg(attach_as).arg(cipher->pageSize()), false))
if(!executeSQL(QString("PRAGMA %1.cipher_page_size = %2").arg(sqlb::escapeIdentifier(attach_as)).arg(cipher->pageSize()), false))
{
QMessageBox::warning(0, qApp->applicationName(), lastErrorMessage);
return false;
@@ -179,7 +179,7 @@ bool DBBrowserDB::attach(const QString& filename, QString attach_as)
}
#else
// Attach database
if(!executeSQL(QString("ATTACH '%1' AS `%2`").arg(filename).arg(attach_as), false))
if(!executeSQL(QString("ATTACH '%1' AS %2").arg(filename).arg(sqlb::escapeIdentifier(attach_as)), false))
{
QMessageBox::warning(0, qApp->applicationName(), lastErrorMessage);
return false;
@@ -453,7 +453,7 @@ bool DBBrowserDB::dump(const QString& filename,
// get columns
QStringList cols(it->table.fieldNames());
QString sQuery = QString("SELECT * FROM `%1`;").arg(it->getTableName());
QString sQuery = QString("SELECT * FROM %1;").arg(sqlb::escapeIdentifier(it->getTableName()));
QByteArray utf8Query = sQuery.toUtf8();
sqlite3_stmt *stmt;
QString lineSep(QString(")%1\n").arg(insertNewSyntx?',':';'));
@@ -470,7 +470,7 @@ bool DBBrowserDB::dump(const QString& filename,
if (!insertNewSyntx || !counter)
{
stream << "INSERT INTO `" << it->getTableName() << '`';
stream << "INSERT INTO " << sqlb::escapeIdentifier(it->getTableName());
if (insertColNames)
stream << " (" << cols.join(",") << ")";
stream << " VALUES (";
@@ -650,7 +650,11 @@ bool DBBrowserDB::executeMultiSQL(const QString& statement, bool dirty, bool log
bool DBBrowserDB::getRow(const QString& sTableName, const QString& rowid, QList<QByteArray>& rowdata)
{
QString sQuery = QString("SELECT * FROM `%1` WHERE `%2`='%3';").arg(sTableName).arg(getObjectByName(sTableName).table.rowidColumn()).arg(rowid);
QString sQuery = QString("SELECT * FROM %1 WHERE %2='%3';")
.arg(sqlb::escapeIdentifier(sTableName))
.arg(sqlb::escapeIdentifier(getObjectByName(sTableName).table.rowidColumn()))
.arg(rowid);
QByteArray utf8Query = sQuery.toUtf8();
sqlite3_stmt *stmt;
bool ret = false;
@@ -684,7 +688,7 @@ bool DBBrowserDB::getRow(const QString& sTableName, const QString& rowid, QList<
QString DBBrowserDB::max(const sqlb::Table& t, sqlb::FieldPtr field) const
{
QString sQuery = QString("SELECT MAX(CAST(`%2` AS INTEGER)) FROM `%1`;").arg(t.name()).arg(field->name());
QString sQuery = QString("SELECT MAX(CAST(%2 AS INTEGER)) FROM %1;").arg(sqlb::escapeIdentifier(t.name())).arg(sqlb::escapeIdentifier(field->name()));
QByteArray utf8Query = sQuery.toUtf8();
sqlite3_stmt *stmt;
QString ret = "0";
@@ -708,7 +712,7 @@ QString DBBrowserDB::max(const sqlb::Table& t, sqlb::FieldPtr field) const
QString DBBrowserDB::emptyInsertStmt(const sqlb::Table& t, const QString& pk_value) const
{
QString stmt = QString("INSERT INTO `%1`").arg(t.name());
QString stmt = QString("INSERT INTO %1").arg(sqlb::escapeIdentifier(t.name()));
QStringList vals;
QStringList fields;
@@ -749,12 +753,14 @@ QString DBBrowserDB::emptyInsertStmt(const sqlb::Table& t, const QString& pk_val
}
if(fields.empty())
stmt.append(" DEFAULT VALUES;");
else
{
stmt.append("(`");
stmt.append(fields.join("`,`"));
stmt.append("`) VALUES (");
stmt.append(" DEFAULT VALUES;");
} else {
stmt.append("(");
foreach(const QString& f, fields)
stmt.append(sqlb::escapeIdentifier(f) + ",");
stmt.chop(1);
stmt.append(") VALUES (");
stmt.append(vals.join(","));
stmt.append(");");
}
@@ -797,7 +803,10 @@ bool DBBrowserDB::deleteRecord(const QString& table, const QString& rowid)
if (!isOpen()) return false;
bool ok = false;
QString statement = QString("DELETE FROM `%1` WHERE `%2`='%3';").arg(table).arg(getObjectByName(table).table.rowidColumn()).arg(rowid);
QString statement = QString("DELETE FROM %1 WHERE %2='%3';")
.arg(sqlb::escapeIdentifier(table))
.arg(sqlb::escapeIdentifier(getObjectByName(table).table.rowidColumn()))
.arg(rowid);
if(executeSQL(statement))
ok = true;
else
@@ -810,7 +819,11 @@ bool DBBrowserDB::updateRecord(const QString& table, const QString& column, cons
{
if (!isOpen()) return false;
QString sql = QString("UPDATE `%1` SET `%2`=? WHERE `%3`='%4';").arg(table).arg(column).arg(getObjectByName(table).table.rowidColumn()).arg(rowid);
QString sql = QString("UPDATE %1 SET %2=? WHERE %3='%4';")
.arg(sqlb::escapeIdentifier(table))
.arg(sqlb::escapeIdentifier(column))
.arg(sqlb::escapeIdentifier(getObjectByName(table).table.rowidColumn()))
.arg(rowid);
logSQL(sql, kLogMsg_App);
setRestorePoint();
@@ -865,7 +878,7 @@ bool DBBrowserDB::createTable(const QString& name, const sqlb::FieldVector& stru
bool DBBrowserDB::addColumn(const QString& tablename, const sqlb::FieldPtr& field)
{
QString sql = QString("ALTER TABLE `%1` ADD COLUMN %2").arg(tablename).arg(field->toString());
QString sql = QString("ALTER TABLE %1 ADD COLUMN %2").arg(sqlb::escapeIdentifier(tablename)).arg(field->toString());
// Execute it and update the schema
bool result = executeSQL(sql);
@@ -880,9 +893,9 @@ bool DBBrowserDB::renameColumn(const QString& tablename, const QString& name, sq
// function can be changed to executing something like this:
//QString sql;
//if(to.isNull())
// sql = QString("ALTER TABLE `%1` DROP COLUMN `%2`;").arg(table).arg(column);
// sql = QString("ALTER TABLE %1 DROP COLUMN %2;").arg(sqlb::escapeIdentifier(table)).arg(sqlb::escapeIdentifier(column));
//else
// sql = QString("ALTER TABLE `%1` MODIFY `%2` %3").arg(tablename).arg(to).arg(type); // This is wrong...
// sql = QString("ALTER TABLE %1 MODIFY %2 %3").arg(sqlb::escapeIdentifier(tablename)).arg(sqlb::escapeIdentifier(to)).arg(type); // This is wrong...
//return executeSQL(sql);
// Collect information on the current DB layout
@@ -925,7 +938,7 @@ bool DBBrowserDB::renameColumn(const QString& tablename, const QString& name, sq
newSchema.removeField(name);
for(int i=0;i<newSchema.fields().count();++i)
select_cols.append(QString("`%1`,").arg(newSchema.fields().at(i)->name()));
select_cols.append(sqlb::escapeIdentifier(newSchema.fields().at(i)->name()) + ',');
select_cols.chop(1); // remove last comma
} else {
// We want to modify it
@@ -938,7 +951,7 @@ bool DBBrowserDB::renameColumn(const QString& tablename, const QString& name, sq
// Get names of fields to select from old table now - after the field has been moved and before it might be renamed
for(int i=0;i<newSchema.fields().count();++i)
select_cols.append(QString("`%1`,").arg(newSchema.fields().at(i)->name()));
select_cols.append(sqlb::escapeIdentifier(newSchema.fields().at(i)->name()) + ',');
select_cols.chop(1); // remove last comma
// Modify field
@@ -956,7 +969,7 @@ bool DBBrowserDB::renameColumn(const QString& tablename, const QString& name, sq
}
// Copy the data from the old table to the new one
if(!executeSQL(QString("INSERT INTO sqlitebrowser_rename_column_new_table SELECT %1 FROM `%2`;").arg(select_cols).arg(tablename)))
if(!executeSQL(QString("INSERT INTO sqlitebrowser_rename_column_new_table SELECT %1 FROM %2;").arg(select_cols).arg(sqlb::escapeIdentifier(tablename))))
{
QString error(tr("renameColumn: copying data to new table failed. DB says:\n%1").arg(lastErrorMessage));
qWarning() << error;
@@ -979,7 +992,7 @@ bool DBBrowserDB::renameColumn(const QString& tablename, const QString& name, sq
setPragma("foreign_keys", "0");
// Delete the old table
if(!executeSQL(QString("DROP TABLE `%1`;").arg(tablename)))
if(!executeSQL(QString("DROP TABLE %1;").arg(sqlb::escapeIdentifier(tablename))))
{
QString error(tr("renameColumn: deleting old table failed. DB says: %1").arg(lastErrorMessage));
qWarning() << error;
@@ -1022,7 +1035,7 @@ bool DBBrowserDB::renameColumn(const QString& tablename, const QString& name, sq
bool DBBrowserDB::renameTable(const QString& from_table, const QString& to_table)
{
QString sql = QString("ALTER TABLE `%1` RENAME TO `%2`").arg(from_table, to_table);
QString sql = QString("ALTER TABLE %1 RENAME TO %2").arg(sqlb::escapeIdentifier(from_table)).arg(sqlb::escapeIdentifier(to_table));
if(!executeSQL(sql))
{
QString error = tr("Error renaming table '%1' to '%2'."
@@ -1129,7 +1142,7 @@ void DBBrowserDB::updateSchema( )
{
(*it).table = sqlb::Table::parseSQL((*it).getsql()).first;
} else if((*it).gettype() == "view") {
statement = QString("PRAGMA TABLE_INFO(`%1`);").arg((*it).getname());
statement = QString("PRAGMA TABLE_INFO(%1);").arg(sqlb::escapeIdentifier((*it).getname()));
logSQL(statement, kLogMsg_App);
err=sqlite3_prepare_v2(_db,statement.toUtf8(),statement.length(),
&vm, &tail);

View File

@@ -69,7 +69,7 @@ void SqliteTableModel::setTable(const QString& table, const QVector<QString>& di
if(!allOk)
{
QString sColumnQuery = QString::fromUtf8("SELECT * FROM `%1`;").arg(table);
QString sColumnQuery = QString::fromUtf8("SELECT * FROM %1;").arg(sqlb::escapeIdentifier(table));
m_headers.push_back("rowid");
m_headers.append(getColumns(sColumnQuery, m_vDataTypes));
}
@@ -484,7 +484,7 @@ void SqliteTableModel::buildQuery()
column = QString("col%1").arg(i.key());
else
column = m_headers.at(i.key());
where.append(QString(" AND `%1` %2").arg(column).arg(i.value()));
where.append(QString(" AND %1 %2").arg(sqlb::escapeIdentifier(column)).arg(i.value()));
}
}
@@ -498,7 +498,13 @@ void SqliteTableModel::buildQuery()
selector.chop(1);
}
QString sql = QString("SELECT `%1`,%2 FROM `%3` %4 ORDER BY `%5` %6").arg(m_headers.at(0)).arg(selector).arg(m_sTable).arg(where).arg(m_headers.at(m_iSortColumn)).arg(m_sSortOrder);
QString sql = QString("SELECT %1,%2 FROM %3 %4 ORDER BY %5 %6")
.arg(sqlb::escapeIdentifier(m_headers.at(0)))
.arg(selector)
.arg(sqlb::escapeIdentifier(m_sTable))
.arg(where)
.arg(sqlb::escapeIdentifier(m_headers.at(m_iSortColumn)))
.arg(m_sSortOrder);
setQuery(sql, true);
}

View File

@@ -9,6 +9,11 @@ namespace sqlb {
QStringList Field::Datatypes = QStringList() << "INTEGER" << "TEXT" << "BLOB" << "REAL" << "NUMERIC";
QString escapeIdentifier(QString id)
{
return '`' + id.replace('`', "``") + '`';
}
bool ForeignKeyClause::isSet() const
{
return m_override.size() || m_table.size();
@@ -22,13 +27,13 @@ QString ForeignKeyClause::toString() const
if(m_override.size())
return m_override;
QString result = "`" + m_table + "`";
QString result = escapeIdentifier(m_table);
if(m_columns.size())
{
result += "(";
foreach(const QString& column, m_columns)
result += "`" + column + "`,";
result += escapeIdentifier(column) + ',';
result.chop(1); // Remove last comma
result += ")";
}
@@ -46,7 +51,7 @@ void ForeignKeyClause::setFromString(const QString& fk)
QString Field::toString(const QString& indent, const QString& sep) const
{
QString str = indent + '`' + m_name + '`' + sep + m_type;
QString str = indent + escapeIdentifier(m_name) + sep + m_type;
if(m_notnull)
str += " NOT NULL";
if(!m_defaultvalue.isEmpty())
@@ -204,7 +209,7 @@ QPair<Table, bool> Table::parseSQL(const QString &sSQL)
QString Table::sql() const
{
QString sql = QString("CREATE TABLE `%1` (\n").arg(m_name);
QString sql = QString("CREATE TABLE %1 (\n").arg(escapeIdentifier(m_name));
sql += fieldList().join(",\n");
@@ -230,7 +235,7 @@ QString Table::sql() const
foreach(FieldPtr f, m_fields)
{
if(f->foreignKey().isSet())
sql += QString(",\n\tFOREIGN KEY(`%1`) REFERENCES %2").arg(f->name()).arg(f->foreignKey().toString());
sql += QString(",\n\tFOREIGN KEY(%1) REFERENCES %2").arg(escapeIdentifier(f->name())).arg(f->foreignKey().toString());
}
sql += "\n)";

View File

@@ -12,6 +12,8 @@
namespace sqlb {
QString escapeIdentifier(QString id);
class ForeignKeyClause
{
public: