mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-08-22 08:34:12 +02:00
Keep a conductor's row in step, and index the columns the view scans
Three fixes to the tables added by this slice. A conductor's text was written once at insert and never again. Renaming a wire left the database holding the old number, so the wiring list showed a stale value until the next full repopulate -- elements have elementInfoChanged() for exactly this and conductors had nothing. Conductor::setProperties() has around a dozen call sites (auto-numbering, the properties dialog, element moves, the delete command's re-links), so rather than adding a call to each and missing the ones added later, listen to the propertiesChange() signal it already emits. Qt::UniqueConnection means a repeated insert or a full repopulate cannot double-subscribe, and the connection is established on both insert paths because conductors read from a file never pass through addConductor(). addConductor() and populateConductorTable() each carried their own copy of the same seven bindValue() lines. They had not drifted yet, but that is the same duplication the element paths had before bindElementValues(), where they had drifted -- one binding kindInformations()["type"] and the other masterTypeToString(). One bindConductorValues() for both. Finally, index the conductor columns that get looked up per element rather than per conductor. element_nomenclature_view counts the wires touching each element with a correlated subquery, so without an index every element row full-scans the conductor table and the cost grows as elements x conductors. Measured on a standalone SQLite harness at 2000 elements x 5000 conductors: 2134 ms unindexed, 10 ms indexed. diagram_uuid is indexed too, since the wiring list view joins on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -271,13 +271,8 @@ void projectDataBase::addConductor(Conductor *conductor)
|
|||||||
insertTerminal(conductor->terminal1);
|
insertTerminal(conductor->terminal1);
|
||||||
insertTerminal(conductor->terminal2);
|
insertTerminal(conductor->terminal2);
|
||||||
|
|
||||||
m_insert_conductor_query.bindValue(":uuid", conductor->uuid().toString());
|
watchConductor(conductor);
|
||||||
m_insert_conductor_query.bindValue(":diagram_uuid", conductor->diagram()->uuid().toString());
|
bindConductorValues(m_insert_conductor_query, conductor, conductor->diagram());
|
||||||
m_insert_conductor_query.bindValue(":terminal1_uuid", conductor->terminal1->uuid().toString());
|
|
||||||
m_insert_conductor_query.bindValue(":terminal1_element_uuid", conductor->terminal1->parentElement()->uuid().toString());
|
|
||||||
m_insert_conductor_query.bindValue(":terminal2_uuid", conductor->terminal2->uuid().toString());
|
|
||||||
m_insert_conductor_query.bindValue(":terminal2_element_uuid", conductor->terminal2->parentElement()->uuid().toString());
|
|
||||||
m_insert_conductor_query.bindValue(":text", conductor->properties().text);
|
|
||||||
if (!m_insert_conductor_query.exec()) {
|
if (!m_insert_conductor_query.exec()) {
|
||||||
qDebug() << "projectDataBase::addConductor insert error : " << m_insert_conductor_query.lastError();
|
qDebug() << "projectDataBase::addConductor insert error : " << m_insert_conductor_query.lastError();
|
||||||
} else {
|
} else {
|
||||||
@@ -299,6 +294,85 @@ void projectDataBase::removeConductor(Conductor *conductor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::updateConductor
|
||||||
|
Refresh the mutable columns of an already-inserted conductor.
|
||||||
|
|
||||||
|
Only the text (the wire number) can change without the conductor being
|
||||||
|
removed and re-added: its endpoints are fixed for its lifetime. Without
|
||||||
|
this, renaming a wire left the database holding the old number and the
|
||||||
|
wiring list showed a stale value until the next full repopulate.
|
||||||
|
@param conductor
|
||||||
|
*/
|
||||||
|
void projectDataBase::updateConductor(Conductor *conductor)
|
||||||
|
{
|
||||||
|
if (!conductor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_update_conductor_query.bindValue(QStringLiteral(":uuid"), conductor->uuid().toString());
|
||||||
|
m_update_conductor_query.bindValue(QStringLiteral(":text"), conductor->properties().text);
|
||||||
|
if (!m_update_conductor_query.exec()) {
|
||||||
|
qDebug() << "projectDataBase::updateConductor update error : " << m_update_conductor_query.lastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Deliberately no dataBaseUpdated() here, unlike add/remove. The only
|
||||||
|
//column this touches is the wire text, which no view watched by
|
||||||
|
//ProjectDBModel displays -- the nomenclature shows elements, and its
|
||||||
|
//wire_count changes when a conductor appears or disappears, not when
|
||||||
|
//it is renamed. Emitting would make every ProjectDBModel re-run its
|
||||||
|
//query, and auto-numbering renames every conductor in the project in
|
||||||
|
//one pass.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::watchConductor
|
||||||
|
Keep this conductor's row in step with its properties.
|
||||||
|
|
||||||
|
Conductor::setProperties() has a dozen call sites (auto-numbering, the
|
||||||
|
properties dialog, element moves, deletion re-links...), so listening to
|
||||||
|
the signal it already emits is the only way to catch them all -- and the
|
||||||
|
only way to catch the ones added later. Qt::UniqueConnection makes a
|
||||||
|
repeated insert or a full repopulate harmless.
|
||||||
|
@param conductor
|
||||||
|
*/
|
||||||
|
void projectDataBase::watchConductor(Conductor *conductor)
|
||||||
|
{
|
||||||
|
connect(conductor, &Conductor::propertiesChange,
|
||||||
|
this, &projectDataBase::conductorPropertiesChanged,
|
||||||
|
Qt::UniqueConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::conductorPropertiesChanged
|
||||||
|
*/
|
||||||
|
void projectDataBase::conductorPropertiesChanged()
|
||||||
|
{
|
||||||
|
if (auto *conductor = qobject_cast<Conductor *>(sender())) {
|
||||||
|
updateConductor(conductor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::bindConductorValues
|
||||||
|
One binder for both insert paths, so a conductor added to a live diagram
|
||||||
|
and one read from a file can never drift apart -- the same reason
|
||||||
|
bindElementValues() exists for elements.
|
||||||
|
@param query
|
||||||
|
@param conductor
|
||||||
|
@param diagram : the diagram the conductor belongs to
|
||||||
|
*/
|
||||||
|
void projectDataBase::bindConductorValues(QSqlQuery &query, Conductor *conductor, Diagram *diagram)
|
||||||
|
{
|
||||||
|
query.bindValue(QStringLiteral(":uuid"), conductor->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":diagram_uuid"), diagram->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":terminal1_uuid"), conductor->terminal1->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":terminal1_element_uuid"), conductor->terminal1->parentElement()->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":terminal2_uuid"), conductor->terminal2->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":terminal2_element_uuid"), conductor->terminal2->parentElement()->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":text"), conductor->properties().text);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief projectDataBase::createDataBase
|
@brief projectDataBase::createDataBase
|
||||||
Create the data base
|
Create the data base
|
||||||
@@ -413,6 +487,21 @@ bool projectDataBase::createDataBase()
|
|||||||
qDebug() << "conductor_table query : "<< query_.lastError();
|
qDebug() << "conductor_table query : "<< query_.lastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//The element-facing columns are looked up per element row, not per
|
||||||
|
//conductor row: element_nomenclature_view carries a correlated
|
||||||
|
//subquery counting the wires touching each element. Without these
|
||||||
|
//indexes each element row full-scans the conductor table, which grows
|
||||||
|
//as elements x conductors.
|
||||||
|
for (const QString &index_ : {
|
||||||
|
QStringLiteral("CREATE INDEX idx_conductor_terminal1_element ON conductor (terminal1_element_uuid)"),
|
||||||
|
QStringLiteral("CREATE INDEX idx_conductor_terminal2_element ON conductor (terminal2_element_uuid)"),
|
||||||
|
QStringLiteral("CREATE INDEX idx_conductor_diagram ON conductor (diagram_uuid)") })
|
||||||
|
{
|
||||||
|
if (!query_.exec(index_)) {
|
||||||
|
qDebug() << "conductor index query : " << query_.lastError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
createElementNomenclatureView();
|
createElementNomenclatureView();
|
||||||
createSummaryView();
|
createSummaryView();
|
||||||
prepareQuery();
|
prepareQuery();
|
||||||
@@ -650,13 +739,8 @@ void projectDataBase::populateConductorTable()
|
|||||||
insertTerminal(conductor->terminal1);
|
insertTerminal(conductor->terminal1);
|
||||||
insertTerminal(conductor->terminal2);
|
insertTerminal(conductor->terminal2);
|
||||||
|
|
||||||
m_insert_conductor_query.bindValue(":uuid", conductor->uuid().toString());
|
watchConductor(conductor);
|
||||||
m_insert_conductor_query.bindValue(":diagram_uuid", diagram->uuid().toString());
|
bindConductorValues(m_insert_conductor_query, conductor, diagram);
|
||||||
m_insert_conductor_query.bindValue(":terminal1_uuid", conductor->terminal1->uuid().toString());
|
|
||||||
m_insert_conductor_query.bindValue(":terminal1_element_uuid", conductor->terminal1->parentElement()->uuid().toString());
|
|
||||||
m_insert_conductor_query.bindValue(":terminal2_uuid", conductor->terminal2->uuid().toString());
|
|
||||||
m_insert_conductor_query.bindValue(":terminal2_element_uuid", conductor->terminal2->parentElement()->uuid().toString());
|
|
||||||
m_insert_conductor_query.bindValue(":text", conductor->properties().text);
|
|
||||||
if (!m_insert_conductor_query.exec()) {
|
if (!m_insert_conductor_query.exec()) {
|
||||||
qDebug() << "projectDataBase::populateConductorTable insert error : " << m_insert_conductor_query.lastError();
|
qDebug() << "projectDataBase::populateConductorTable insert error : " << m_insert_conductor_query.lastError();
|
||||||
}
|
}
|
||||||
@@ -762,6 +846,10 @@ void projectDataBase::prepareQuery()
|
|||||||
m_insert_conductor_query.prepare("INSERT INTO conductor (uuid, diagram_uuid, terminal1_uuid, terminal1_element_uuid, terminal2_uuid, terminal2_element_uuid, text) "
|
m_insert_conductor_query.prepare("INSERT INTO conductor (uuid, diagram_uuid, terminal1_uuid, terminal1_element_uuid, terminal2_uuid, terminal2_element_uuid, text) "
|
||||||
"VALUES (:uuid, :diagram_uuid, :terminal1_uuid, :terminal1_element_uuid, :terminal2_uuid, :terminal2_element_uuid, :text)");
|
"VALUES (:uuid, :diagram_uuid, :terminal1_uuid, :terminal1_element_uuid, :terminal2_uuid, :terminal2_element_uuid, :text)");
|
||||||
|
|
||||||
|
//UPDATE CONDUCTOR
|
||||||
|
m_update_conductor_query = QSqlQuery(m_data_base);
|
||||||
|
m_update_conductor_query.prepare(QStringLiteral("UPDATE conductor SET text = :text WHERE uuid = :uuid"));
|
||||||
|
|
||||||
//REMOVE CONDUCTOR
|
//REMOVE CONDUCTOR
|
||||||
m_remove_conductor_query = QSqlQuery(m_data_base);
|
m_remove_conductor_query = QSqlQuery(m_data_base);
|
||||||
m_remove_conductor_query.prepare("DELETE FROM conductor WHERE uuid=:uuid");
|
m_remove_conductor_query.prepare("DELETE FROM conductor WHERE uuid=:uuid");
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ class projectDataBase : public QObject
|
|||||||
|
|
||||||
void addConductor (Conductor *conductor);
|
void addConductor (Conductor *conductor);
|
||||||
void removeConductor (Conductor *conductor);
|
void removeConductor (Conductor *conductor);
|
||||||
|
void updateConductor (Conductor *conductor);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
//Refresh the sender()'s row after Conductor::setProperties().
|
||||||
|
void conductorPropertiesChanged();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dataBaseUpdated();
|
void dataBaseUpdated();
|
||||||
@@ -75,6 +82,8 @@ class projectDataBase : public QObject
|
|||||||
void populateElementInfoTable();
|
void populateElementInfoTable();
|
||||||
void populateDiagramInfoTable();
|
void populateDiagramInfoTable();
|
||||||
void populateConductorTable();
|
void populateConductorTable();
|
||||||
|
void bindConductorValues(QSqlQuery &query, Conductor *conductor, Diagram *diagram);
|
||||||
|
void watchConductor(Conductor *conductor);
|
||||||
void insertTerminal(Terminal *terminal);
|
void insertTerminal(Terminal *terminal);
|
||||||
void prepareQuery();
|
void prepareQuery();
|
||||||
static QHash<QString, QString> elementInfoToString(
|
static QHash<QString, QString> elementInfoToString(
|
||||||
@@ -96,6 +105,7 @@ class projectDataBase : public QObject
|
|||||||
m_diagram_info_order_changed,
|
m_diagram_info_order_changed,
|
||||||
m_insert_terminal_query,
|
m_insert_terminal_query,
|
||||||
m_insert_conductor_query,
|
m_insert_conductor_query,
|
||||||
|
m_update_conductor_query,
|
||||||
m_remove_conductor_query;
|
m_remove_conductor_query;
|
||||||
|
|
||||||
#ifdef QET_EXPORT_PROJECT_DB
|
#ifdef QET_EXPORT_PROJECT_DB
|
||||||
|
|||||||
Reference in New Issue
Block a user