Make it possible to add rows to a WITHOUT rowid table

This commit allows you to add new rows to a table without rowid column.
The main problem here is that SQLite won't create the next value for the
primary key column itself, so we have to do that instead.

See issue #51.
This commit is contained in:
Martin Kleusberg
2014-08-26 18:38:04 +02:00
parent e37df8658c
commit c7de94cb77
3 changed files with 38 additions and 21 deletions

View File

@@ -462,11 +462,22 @@ int DBBrowserDB::addRecord(const QString& sTableName)
char *errmsg;
if (!isOpen()) return false;
// add record is seldom called, for now this is ok
// but if we ever going to add a lot of records
// we should cache the parsed tables somewhere
sqlb::Table table = sqlb::Table::parseSQL(getObjectByName(sTableName).getsql()).first;
QString sInsertstmt = table.emptyInsertStmt();
sqlb::Table table = getObjectByName(sTableName).table;
// For tables without rowid we have to set the primary key by ourselves. We do so by querying for the largest value in the PK column
// and adding one to it.
QString sInsertstmt;
int pk_value;
if(table.isWithoutRowidTable())
{
SqliteTableModel m(this, this);
m.setQuery(QString("SELECT MAX(`%1`) FROM `%2`;").arg(getObjectByName(sTableName).table.rowidColumn()).arg(sTableName));
pk_value = m.data(m.index(0, 0)).toInt() + 1;
sInsertstmt = table.emptyInsertStmt(pk_value);
} else {
sInsertstmt = table.emptyInsertStmt();
}
lastErrorMessage = "";
logSQL(sInsertstmt, kLogMsg_App);
setRestorePoint();
@@ -477,7 +488,10 @@ int DBBrowserDB::addRecord(const QString& sTableName)
qWarning() << "addRecord: " << lastErrorMessage;
return -1;
} else {
return sqlite3_last_insert_rowid(_db);
if(table.isWithoutRowidTable())
return pk_value;
else
return sqlite3_last_insert_rowid(_db);
}
}

View File

@@ -156,28 +156,29 @@ QPair<Table, bool> Table::parseSQL(const QString &sSQL)
return qMakePair(Table(""), false);
}
QString Table::emptyInsertStmt() const
QString Table::emptyInsertStmt(int pk_value) const
{
QString stmt = QString("INSERT INTO `%1`").arg(m_name);
QStringList vals;
QStringList fields;
foreach(FieldPtr f, m_fields) {
if(f->notnull())
if( f->primaryKey() && f->isInteger() )
{
fields << f->name();
if( f->primaryKey() && f->isInteger() )
{
if(pk_value != -1)
vals << QString::number(pk_value);
else
vals << "NULL";
} else {
if(f->isInteger())
vals << "0";
else
vals << "''";
}
}
else
{
} else if(f->notnull()) {
fields << f->name();
if(f->isInteger())
vals << "0";
else
vals << "''";
} else {
// don't insert into fields with a default value
// or we will never see it.
if(f->defaultValue().length() == 0)
@@ -228,7 +229,7 @@ QString Table::sql() const
sql += "\n)";
// without rowid
if(m_rowidColumn != "_rowid_")
if(isWithoutRowidTable())
sql += " WITHOUT ROWID";
return sql + ";";

View File

@@ -82,9 +82,10 @@ public:
/**
* @brief Creates an empty insert statement.
* @param pk_value This optional parameter can be used to manually set a specific value for the primary key column
* @return An sqlite conform INSERT INTO statement with empty values. (NULL,'',0)
*/
QString emptyInsertStmt() const;
QString emptyInsertStmt(int pk_value = -1) const;
/**
* @brief Returns the CREATE TABLE statement for this table object
@@ -98,6 +99,7 @@ public:
void setField(int index, FieldPtr f) { m_fields[index] = f; }
void setRowidColumn(const QString& rowid) { m_rowidColumn = rowid; }
const QString& rowidColumn() const { return m_rowidColumn; }
bool isWithoutRowidTable() const { return m_rowidColumn != "_rowid_"; }
void clear();
/**