When trying to make some queries and deletes in the database, the program closes and does not inform the reason of the crash
-
I created a customer registration form, with some lines edits, to make queries by NAME, CODE (ID) and ANY FIELD.
There is also a DELETE button and a TABLE WIDGET that lists all clients OR clients that are found in queries, above.
All the code works perfectly: I can do the queries by name, code and also by any field. I can delete the selected records and the table widget keeps track of all these activities, showing the chosen customers, and updating when customers are deleted.
However, without explanation, and WORST: WITHOUT INFORMING THE ERROR REASON, the system crashes for about 5 seconds and the form execution is terminated.
I noticed that the problem occurs more often when I try to delete a record right after selecting clients by ID.
In the debug area, the following texts appear:
08:56:27: The program has unexpectedly finished.
08:56:27: The process was ended forcefully.
08:56:27: C:/Camelo/C++ Programas Alexandre/1 - QT - PROGRAMAS/build-Totalis-Desktop_Qt_5_12_5_MinGW_32_bit-Debug/debug/Totalis.exe crashed.
What makes the situation worse is the fact that the problem appears intermittently, ie time appears, time does not appear.
Even worse: there is no fixed slot where it always appears. Sometimes the program closes when I try to delete a record, sometimes when I try to query by any field, sometimes when I try to query by code, etc.
I've reviewed the code 03 times, LINE BY LINE. I can not see the problem.
I am using the 32 bit mingW compiler, but my windows 10 is 64 bit.
I tried changing the compiler to mingW 64 bit, but there were even more errors.
I will attach all header and CPP files in addition to the problematic form.
The name of the form where the problem appears is cadacli.ui.
Debugging provides no clue about the problem, Robert löhning. And that is the reason for my near despair.
The only two messages debugging provide are the ones I wrote above.
I just attached a copy of the screen so you can see what I said.
You will notice that before the two error messages, the following two messages appear:
I also tried to run "Qmake", "Rebuild all" and "Start debuging of startup project". But it had no effect.
Can you help me?
-
@Alexandre-Camelo said in When trying to make some queries and deletes in the database, the program closes and does not inform the reason of the crash:
WORST: WITHOUT INFORMING THE ERROR REASON
First understand that C++ is a harsh mistress. She rarely gives up her secrets unless forced to with a debugger. Other languages like Python are like: "Yeah, I messed up right here and this why." With C++ its like: "Talk to the hand!"
So fire up the debugger (make sure to compile in debug mode). Learn to step to the problem or backtrack to find the actual failure in your code. This is a skill to learn.
Then if you cannot resolve the problem, post some minimal code that reproduces the issue that we can compile/run to try and see the issue.
-
I used the debugger. It was what was missing. It showed some errors at the time of program execution. The errors follow below:
19:55:19: Debugging starts
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
onecore\com\combase\dcomrem\channelb.cxx(6385)\combase.dll!76B4D51E: (caller: 74EE5BB9) ReturnHr(1) tid(3eb8) 8001010D An external call cannot be made because the application is routing on a synchronous incoming call.
onecore\com\combase\dcomrem\giptbl.cxx(1720)\combase.dll!76B39A60: (caller: 76AED0B0) ReturnHr(2) tid(3eb8) 8000FFFF Catastrophic failure
19:57:42: Debugging has finished
.
.
.
Just as you requested, follow the codes that matter:LOGIN WINDOW CODE:
//############################################
//########## FORMULÁRIO DE LOGIN #############
//#############################################include "login.h"
#include "ui_login.h"
#include "cadacli.h"
#include <QPixmap>
#include <QMessageBox>
#include "padroes.h"Login::Login(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::Login)
{
ui->setupUi(this);//Configura a logo da empresa, na tela de login QPixmap LogoEmpresa (":/Imagens/GERAR2002.jpg"); ui->lblLogomarca->setPixmap(LogoEmpresa.scaled(500,350,Qt::KeepAspectRatio)); ui->statusbar->showMessage("Não dá pra entrar!"); //Abre o BD, testando se ele foi aberto com sucesso BDLogin=QSqlDatabase::addDatabase("QSQLITE"); BDLogin.setDatabaseName (glbCAMINHOBDCADASTROS); //Seleciona o banco de dados if(!BDLogin.open()) //Abre o BD, testando se ele foi aberto com sucesso { QMessageBox::warning(this,"ERRO", "Não foi possível abrir Banco de dados"); }
}
Login::~Login()
{
delete ui;
}//Botão de login: faz as verificações necessárias para validar
//USUÁRIO E SENHA
void Login::on_btnEntrar_clicked()
{
//Joga dados de usuário e senha nas variáveis
QString strUsuario = ui->txtUsuario->text();
QString strSenha = ui->txtSenha->text();//Cria um objeto de consulta QSqlQuery ConsultaLogin; //Com objeto criado, elabora-se a consulta, colocando-se dentro de um 'if', para testar se ele //encontrou os dados da consulta //*** O método 'exec' retorna TRUE se encontrar os dados e FALSE se não encontrar if(ConsultaLogin.exec("select * from Login where NomeUsuario='"+strUsuario+"' and Senha='"+strSenha+"'")) { int Contador = 0; //O método 'next' retorna TRUE se existir um próximo registro para ir while (ConsultaLogin.next()) { Contador++; //Se existir um próximo registro, incrementa o contador } if (Contador > 0) //Se o contador for maior que zero... { //ConexaoCad.Fechar(); //Fecha banco de dados atual this->close(); //Fecha janela de login AbreJanelaPrincipal = new Principal(this); AbreJanelaPrincipal->showMaximized(); //Abre janela principal, maximizada } else //Caso a consulta não selecione nenhum registro, significa que os dados de login estão errados: envia mensagem de erro { QMessageBox::warning(this, "DADOS INVÁLIDOS", "Nome de usuário e/ou senha errado(s)"); } }
}
void Login::on_btnSair_clicked()
{
close();
}void Login::on_btnTeste_clicked()
{BDLogin.close();
close();
AbreCadacli = new cadacli(this);
AbreCadacli->show();}
void Login::on_btnTeste_2_clicked()
{
AbreJanelaTestes = new JanelaTestes(this);
AbreJanelaTestes->show();}
.
.
.
.
CODES WHERE ERRORS OCCUR (THIS IS ANOTHER WINDOW OPEN FROM THE LOGIN WINDOW):void cadacli::on_btnExcluir_clicked()
{QMessageBox::StandardButton Resposta = QMessageBox::question (this, "CUIDADO!", "TODOS OS DADOS DO CLIENTE SERÃO APAGADOS!" "\n\n CONFIRMA?", QMessageBox::Yes | QMessageBox::No); if(Resposta == QMessageBox::Yes) { QMessageBox::StandardButton Resposta2 = QMessageBox::question(this, "CUIDADO!", "ESTÁ CERTO(A) DISSO?\n\n VOCÊ NÃO CONSEGUIRÁ RECUPERAR ESTES DADOS!" "\n\nCONFIRMA?",QMessageBox::Yes | QMessageBox::No); if(Resposta2 == QMessageBox::No) { return; } } //Se o usuário clicar em YES, para todas as mensagens, acima... //Exclui o registro
int intCodAtual = ui->txtCod->text().toInt();
QSqlQuery ApagaClientes; ApagaClientes.prepare("delete from CadCliForn where COD = '"+QString::number(intCodAtual)+"'");
if(ApagaClientes.exec())
{
if(!ConsultaClientes.exec("select * from CadCliForn order by NOME"))
{
QMessageBox::warning(this, "OPS!", "Algo deu errado.\n\nNão foi possível selecionar dados de clientes/fornecedores.");
}
//SelecionaTodoBD();
ConsultaClientes.first(); //Vai para o primeiro registro da consulta
JogaDadosCampos(ConsultaClientes);
ConsultaClientes.previous(); //Vai para o registro anterior, para que a função PREENCHETABLEWIDGET consiga preencher desde o primeiro registro
LimpaTableWidget();
PreencheTableWidget(ConsultaClientes);
QMessageBox::information(this, "OK!", "Registro excluído!");
}
else
{
QMessageBox::warning(this, "OPS!", "Algo deu errado.\n\nO registro não foi excluído");
}}
.
.
.
.
//Faz pesquisa pelo código
void cadacli::on_txtConsuCod_returnPressed()
{//Limpa o outros dois campos de consulta ui->txtConsuNome->clear(); ui->txtConsuQualquer->clear(); int intConsultaCod = ui->txtConsuCod->text().toInt(); //Joga o conteúdo do campo de consulta, na variável, convertendo de string para int int intRegistrosEncontradosCod = 0; //Declara e inicia a variável para contar registros encontrados na consulta (o método size() não funcionou) QString strExisteCodigo = ui->txtConsuCod->text(); //Variável para identificar se algo foi escrito no campo de consulta por código //Caso o usuário dê ENTER, com o campo de consulta em branco... if(strExisteCodigo.isEmpty()) { LimpaTableWidget(); //Limpa a lista PreencheTableWidgetTUDO(); //Preenche a lista, novamente, com TODOS os clientes return; //Sai do procedimento } //Prepara a consulta por código ConsultaPorCod.prepare("select * from CadCliForn where COD = " + QString::number(intConsultaCod)); //Executa a consulta, dentro de um IF, para testar se ela funcionou if(!ConsultaPorCod.exec()) { QMessageBox::warning(this, "OPS! ALGO DEU ERRADO!", "Não foi possível efetuar a pesquisa no banco de dados!\n\n ('ConsultaPorCod')"); //Se a consulta não funcionar, manda mensagem de erro return; } else { //Verifica quantos registros foram retornados while (ConsultaPorCod.next()) { intRegistrosEncontradosCod++; } //Se a consulta não retornar nenhum resultado, manda mensagem e sai do procedimento //####### (isso pode evitar erros)####### if (intRegistrosEncontradosCod <= 0) { QMessageBox::about(this, "OPS!", "Código não encontrado."); return; } } ConsultaPorCod.first(); //Vai para o primeiro registro da consulta JogaDadosCampos(ConsultaPorCod); //Joga os dados do primeiro registro, nos campos do formulário ConsultaPorCod.previous(); //Volta para o início da consulta (index zero), //para que a função PREENCHETABLEWIDGET consiga preencher //a lista desde o primeiro registro encontrado. //Para que a função consiga fazer isso, o ponteiro precisa estar //no index zero (antes do index 1), para que, quando PREENCHETABLEWIDGET //Dê next, ela vá para o PRIMEIRO REGISTRO LimpaTableWidget(); //Apaga todas as linhas da lista PreencheTableWidget(ConsultaPorCod);//Preenche, NOVAMENTE, a lista
}
Can you help me?
-
@Alexandre-Camelo said in When trying to make some queries and deletes in the database, the program closes and does not inform the reason of the crash:
Can you help me?
Fix the errors from Qt - make sure to not have an open QSqlQuery when you close your database. Since I don't see where you close it, you have to search by your own.
Also please post the backtrace of the crash./edit: and please update your post and use the '<code>' - tags.
-
Hi
Do you use/open any other database at the same time besides
BDLogin ? -
Hi,
BDLogin is a member variable, isn't it ?
There's a warning in the QSqlDatabase documentation that explicitly say that you shall not keep QSqlDatabase object as member variables. -
Well, Christian ...
I'm VERY new to QT and C ++. I come from Visual Basic for Applications (VBA).
I didn't know it was possible to close a QSqlquery. After your tip, I tried to do that, but didn't find this option. Do you mean ‘QSqlquery.clear’?
So can an error occur if I close a database before closing QSqlquery?
I don't know what backtrace is. Can you explain this please?
Did you ask me to use the <code> tag on each line of code posted OR once before each block of code?
Thank you for your help.
-
Hi, mrjj!
I open the same database in two different instances. The name of the database is 'REGISTERS'. I need to open it in the login window, instance ‘BDLogin’ and when the username and password are validated, the main window opens. Then I close the instance 'BDLogin', close the login window and open the main window. In the builder area, I create a new instance (BDCadasters) and open the database again.
Although I close one instance to open another, in the debug area there are always two messages stating that there was an open database and that it is being unusable for another to open. Really do not understand.
Detail: The database has 3 tables. I use different tables in each of the windows.
-
Hi, SGainst!
I will give almost the same answer I gave to mrjj, with some additions:
I open the same database in two different instances. The name of the database is 'REGISTERS'. I need to open it in the login window, instance ‘BDLogin’ and when the username and password are validated, the main window opens. Then I close the instance 'BDLogin', close the login window and open the main window. In the builder area, I create a new instance (BDCadasters) and open the database again.
Although I close one instance to open another, in the debug area there are always two messages stating that there was an open database and that it is being unusable for another to open. Really do not understand.
Detail: The database has 3 tables. I use different tables in each of the windows.
Despite all my explanation, I was left with a little doubt: what is member variable? Where in the code should I NOT keep it?
I'm new to QT and C ++, so I will answer your question as I know: BDLogin is an instance of QSqldatabase, created to open the database. Would that be a member variable?
-
@Alexandre-Camelo @mrjj @fcarney @Christian-Ehrlicher @SGaist
One question for all of you trying to help me: I have declared all QSqlquery in the .h file so that they are available all the time, in any scope of the cpp file. I did wrong? Can I have multiple QSqlquery open at the same time? I realize that the error occurs when I am using these queries at the same time. Example: I search by ID, then do a search by name, and then delete the record. AT THAT EXACT TIME, the error occurs.
-
BUDIEEEEESSSSSSSSS !!!!!!!
I got to decipher the riddle !!!!!
Thanks to partner @fcarney! Your tip for running the program in debug mode was very valuable!
I noticed that the problem was NOT in any database or query.
There is a tablewidget on the form, which lists all customers. Whenever there is an update on the form, it is reflected in the tablewidget (additions, deletions, selections ...).
Similarly, when I select a record in tablewidget, this action is reflected in the form.
But I was using the "itemSelectonChanged" slot in the table widget. THAT WAS THE MISTAKE !!!!! Whenever some code updated tablewidget, the "itemSelectonChanged" slot was activated, generating an infinite loop that broke the code.
I changed the tablewidget slot to "itemDoubleClicked" and it's all settled!
Thank you very much to all of you. Each of your opinions helped me learn a little more about QT and C ++.
-
You should still fix the database warning as it may lead to crashes.
-
Exactly.
I haven't figured out how to do it yet.
I created a "Connection" class that contains two functions: 1) Open database; 2) Close database. It is through the functions of this class that I am opening the database. This class is in an .h file, which I refer to when I need to open the DB.
Example: I compile the program and the login window opens. In your .h file, I create a new instance for the "Connection" class. In the cpp file builder is the "open database" command. When user data is validated, the login window is closed and I use the .close () command to close the database.
Shortly after this, the main window opens and the whole process above (new instance creation, database opening) is repeated. Even so, the database open error messages appear.
I thought the error would occur in the class when entering the DB connection type: BDCadastros = QSqlDatabase :: addDatabase ("QSQLITE"). However, when I remove this command from the class and place it as a global variable, the database is not opened. I do not know what to do.
Here's the code of the class I created (remembering that I put it in an .h file that I give <include> to other files):
<code>
class ConexaoCadastros
{
public:
QSqlDatabase BDCadastros; //Cria um objeto da classe QSqlDatabaseConexaoCadastros() //Coloca o tipo de banco de dados no CONSTRUTOR da classe { BDCadastros=QSqlDatabase::addDatabase("QSQLITE"); } //Função para abrir o BD bool Abrir() { BDCadastros.setDatabaseName (glbCAMINHOBDCADASTROS); //Seleciona o banco de dados if(!BDCadastros.open()) //Abre o BD, testando se ele foi aberto com sucesso { return false; } else { return true; } } //Função para fechar o BD void Fechar() { BDCadastros.close(); }
};
<code/>Do you have any suggestions?
-
@Alexandre-Camelo said in When trying to make some queries and deletes in the database, the program closes and does not inform the reason of the crash:
I use the .close () command to close the database.
Why? Why don't you just follow the documentation, let the db open and get the connection with QSqlDatabase::database(QString)?
-
@Christian-Ehrlicher said in When trying to make some queries and deletes in the database, the program closes and does not inform the reason of the crash:
@Alexandre-Camelo said in When trying to make some queries and deletes in the database, the program closes and does not inform the reason of the crash:
I use the .close () command to close the database.
Why? Why don't you just follow the documentation, let the db open and get the connection with QSqlDatabase::database(QString)?
As I said, I'm new to QT and C ++.
I tried in many ways to leave the database open and make all queries throughout the code.
But I can't.
Whenever I close one window and open another, the previous window's database closes (even if I don't use the close () command.) This way, I am forced to reopen the DB when I open the new window. It's worse: The open database message appears.
How do I leave the database open during all code execution?
-
@Alexandre-Camelo said in When trying to make some queries and deletes in the database, the program closes and does not inform the reason of the crash:
How do I leave the database open during all code execution?
As stated in the documentation - open the database once with QSqlDatabase db = QSqlDatabase::addDatabase("..."); and get the db connection with QSqlDatabase db = QSqlDatabase::database(); ...
-
@Alexandre-Camelo said in When trying to make some queries and deletes in the database, the program closes and does not inform the reason of the crash:
the previous window's database closes
Do you have a member variable in your window which holds the database connection?
@SGaist already pointed out that you should NOT do this.
QSqlDatabase manages all your connections for you and you can get any open connection using QSqlDatabase::database();
There is absolutely no need to have member variables holding the connection. -
Literally I Googled "qt docs":
https://doc.qt.io/
Also, when searching for something specific search:
"qt json" or "qobject" or "qstring" etc -
@fcarney said in When trying to make some queries and deletes in the database, the program closes and does not inform the reason of the crash:
Literally I Googled "qt docs":
https://doc.qt.io/
Also, when searching for something specific search:
"qt json" or "qobject" or "qstring" etcThanks guys.
You guys helped me A LOT!
In a little while I'll be back to "bother" you again.
:-D