Sorry in advance for any apparent overlap of questions, but I have searched what feels like every possible question on this site for an answer to my problem and none of them have worked. The main issue is that I cannot seem to open my SQLITE3 database in order to search it and display to a QTableView. My code is below:
void MainWindow::on_searchBButton_clicked() {
qDebug() << QSqlDatabase::drivers();
//Setup the search query and open database
//toolboxData = QSqlDatabase::addDatabase("QSQLITE");
//toolboxData.setDatabaseName(":/Resources/Resources/ToolSearch.db");
QString searchStr;
searchStr = ui->basicSearchInput->text();
//Filter out any hyphens
for (int i = 0; i < searchStr.length(); ++i) {
if (searchStr[i] == QLatin1Char('-')) searchStr[i] = QLatin1Char(' ');
}
//Do the actual searching now
QString sQry;
QSqlQueryModel *model = new QSqlQueryModel();
QSqlDatabase toolboxDb = QSqlDatabase::addDatabase("QSQLITE");
//toolboxDb.setDatabaseName(":/Resources/Resources/ToolSearch.db");
toolboxDb.setDatabaseName("C:\\New folder\\ToolSearch.db");
bool db_ok = toolboxDb.open();
if (!QFile::exists("C:\\New folder\\ToolSearch.db"))
qDebug() << "This file does not exist";
if (!db_ok)
qDebug() << "Connection Failed\n";
QSqlQuery *qry = new QSqlQuery(toolboxDb);
sQry += "SELECT * FROM ToolSearch WHERE keywords MATCH :searchTerm UNION SELECT * FROM ToolSearch WHERE name MATCH :searchTerm UNION ";
sQry += "SELECT * FROM ToolSearch WHERE category MATCH :searchTerm UNION SELECT * FROM ToolSearch WHERE subcategory MATCH :searchTerm ";
sQry += "UNION SELECT * FROM ToolSearch WHERE sources MATCH :searchTerm UNION SELECT * FROM ToolSearch WHERE usagetype :searchTerm UNION ";
sQry += "SELECT * FROM ToolSearch WHERE cost MATCH :searchTerm";
qry->prepare(sQry);
//Add the necessary single quotes to the given string
searchStr = '\'' + searchStr + '\'';
qry->bindValue(":searchTerm", searchStr);
qry->exec();
model->setQuery(*qry);
ui->searchResults->setModel(model);
ui->searchResults->show(); }
Most of the answers that I saw on here said that to open the database you have to write something along the lines of the following:
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("C:\\SomeFolder\\SomeFile.db");
bool db_ok = db.open();
However, I have almost the exact same code in mine for opening the database and even tested it with an absolute address as opposed to the relative address I had with the ":/Resources/Resources/ToolSearch.db" line. Also, the output of qDebug() << QSqlDatabase::drivers() gives:
("QSQLITE", "QMYSQL", "QMYSQL3", "QODBC", "QODBC3", "QPSQL", "QPSQL7")
Lastly, I have also used verified that the file does exist at the location I am trying to open it at using the if (!QFile::exists()) statement. So, I am at a loss for why this is not working. The specific error message that I get when I attempt to run this code is "QSqlQuery::prepare: database not open".
Any help is greatly appreciated!
Related
I'm trying to retrieve the users from the database their names are 'DOMAIN\name'.
I've checked the query in sql console, simple select like :
select * from users where name='DOMAIN\\name'
it returns correct row if the name in the database looks like 'DOMAIN\user' (single back slash).
however QSqlQuery returns empty :
The code something like:
const QString command = QStringLiteral("select * "
"from %1 where name = '%2'")
.arg(Constants::kUsersTableName).arg(userId);
qCDebug() << "Query:" << command;
QSqlDatabase db = QSqlDatabase::database(m_connection, false);
QSqlQuery query(db);
if (!query.prepare(command) || !query.exec()) {
...
log :
Query: "select * from users where name = 'DOMAIN\\name'"
any idea why QSqlQuery returns empty at the same time when database console return valid record for the user.
dbms: MySQL
MySQL uses \ as its escape character therefore the correct query string you have to escape the slash twice, once for c++ and once for mysql:
"select * from users where name='DOMAIN\\\\name'"
The simpler solution is to use prepared statements and placeholders correctly which as a very important bonus will protect your code from SQLI.
Note that field and table names aren't allowed to be placeholders by most if not all database engines so you will still need to build that part of your string by hand:
const QString usernamePlaceholder = ":username"
const QString command = QStringLiteral("select * "
"from %1 where name = %2")
.arg(Constants::kUsersTableName).arg(usernamePlaceholder);
QSqlDatabase db = QSqlDatabase::database(m_connection, false);
QSqlQuery query(db);
if (!query.prepare(command)) {
qCDebug() << query.lastError();
return;
}
query.bindValue(usernamePlaceholder, userId);
if (!query.exec()) {
qCDebug() << query.lastError();
return;
}
bindValue will take care of whatever quoting and escaping is required for your values.
I am trying to get an input(username) from user and search for that in my sqlite to find it's password for recovery.
QString username = QInputDialog::getText(this, "Password Recovery", "please enter ur Username here:", QLineEdit::Normal,"myUsername", Q_NULLPTR, Qt::WindowFlags(), Qt::ImhNone);
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("/home/arian_press/Qt5.7.0/Projects/APQt_chat/apt.db");
if (db.open())
{
QSqlQuery query;
QString qstr="SELECT username,password,support_email FROM users WHERE username=\""+username+"\";" ;
}
if (query.exec(qstr))
{
QString password=query.value(1).toString();
QString pass = "ur password is:" + password;
Smtp *newMail = new Smtp("arian.press2015#gmail.com",query.value(2).toString()," Your Password",pass);
delete newMail;
QMessageBox messageBox;
messageBox.critical(0,"Error","ur credentials are wrong!");
messageBox.setFixedSize(500,200);
}
else
{
qDebug() << query.lastError().text();
}
db.close();
}
else
{
qDebug() << "Failed to connect to database.";
}
but when i run the program, It doesn't return anything while when I open SQLite file in terminal I can get results.
**update:
U didn't mean what I said. the problem is that I can't use \" in the above code because for the query i need: SELECT username,password,support_email FROM users WHERE username="myusername"
but when I use above code it queries for SELECT username,password,support_email FROM users WHERE username=\"myusername\"
so I can't have any results.so now how can I bring quotation marks in QString?
Never concatenate user input with your queries: that makes you vulnerable to SQL injection. Use prepared statements!
Furthermore, you must use single quotation marks '.
QSqlQuery query;
query.prepare("SELECT username,password,support_email "
"FROM users "
"WHERE username=':username';");
query.bindValue(":username", username);
The } following your QString qstr = ... should be removed.
SQL uses single quotes for strings. Try:
QString qstr="SELECT username,password,support_email FROM users WHERE username='"+username+"';";
There is also a more elegant way:
query.prepare("SELECT username,password,support_email FROM users WHERE username = :username;");
query.bindValue(":username", username);
query.exec();
I have been working on a small code which is supposed to fill up columns on a QTableWidget with values fetched from a SQL table.
Here's a small snippet:
QString path = "C:\\ENTRIES.db";
QString itemToSearch = "ABC"; //This comes as a parameter to a slot actually, assigning it here for simplicity
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(path);
db.open();
QSqlQuery query(db);
query.prepare("SELECT * FROM METADATA WHERE ITEM LIKE ':item %'");
query.bindValue(":item", itemToSearch);
if(query.exec())
{
ui->tableWidgetSearchResults->setVisible(true);
ui->tableWidgetSearchResults->clearContents();
int rCount = ui->tableWidgetSearchResults->rowCount();
while(query.next())
{
ui->tableWidgetSearchResults->setRowCount(rCount + 1);
QTableWidgetItem *qtwParamName = new QTableWidgetItem;
qtwParamName->setFlags(qtwParamName->flags() & ~Qt::ItemIsSelectable & ~Qt::ItemIsEditable);
qtwParamName->setText(query.value(0).toString());
ui->tableWidgetSearchResults->setItem(rCount, 0, qtwParamName);
QTableWidgetItem *qtwParamValue = new QTableWidgetItem;
qtwParamValue->setFlags(qtwParamValue->flags() & ~Qt::ItemIsSelectable & ~Qt::ItemIsEditable);
qtwParamValue->setText(query.value(1).toString());
ui->tableWidgetSearchResults->setItem(rCount, 1, qtwParamValue);
rCount++;
}
}
else
{
qDebug() << "Error message: " << query.lastError().text() ;
ui->tableWidgetSearchResults->setHidden(true);
}
db.close();
When executing query.value(<index here>).toString()); lines, the Application Output prints:
QSqlQuery::value: not positioned on a valid record
QSqlQuery::value: not positioned on a valid record
I'm not sure of what I am missing here.
Note: I am using Qt 5.6, MSVC 2013 compiler and SQLite 3.8.
#CL. Thanks for the hint. I tried this line and it worked:
query.prepare("SELECT * FROM METADATA WHERE ITEM LIKE '" + itemToSearch + "%'");
Apparently bindValue was inappropriate in this case.
Following QSqlQuery Class documentation one can implemented an insert operation in a MySQL database, i.e. like this:
QSqlQuery query;
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (:id, :forename, :surname)");
query.bindValue(":id", 1001);
query.bindValue(":forename", "Bart");
query.bindValue(":surname", "Simpson");
query.exec();
It works. But it's fragile, isn't? It will stop working (because names are hard coded) when a column name mismatch occurs, if the database programmer changes a column name in the MySQL script, i.e. surname to lastname.
What came to my mind was to change the whole mechanism so that instead of inserting individual fields one big object (perhaps a struct composed by the individual fields) should be inserted. And then, in the db side, the fields should be split back into a set of fields, i.e. using a view or a trigger.
Am I going in the right direction?
I'll appreciate general comments on the issue.
Well, there is a way, but you must be sure that structure of the table and column meaning wouldn't change and your query has data of each column to insert.
Firstly, you must select all information about your table:
SELECT c.column_name FROM information_schema.columns c
WHERE c.table_name = 'some_table_name'
ORDER BY c.ordinal_position ASC
Secondly, your code can be change like this. I am using universal method that meaning you have already known data:
QList<QVariant> valuesList { QVariant(1), QVariant("Bart"), QVariant("Simpson") };
QList<QPair<QString, QVariant>> varList;
QSqlQuery query;
query.exec("SELECT #rownum := #rownum + 1 AS row_num, c.column_name
FROM information_schema.columns c, (SELECT #rownum := -1) r
WHERE c.table_name = 'some_table_name'
ORDER BY c.ordinal_position ASC");
while(query.next())
colList << QPair<QString, QString>(query.value(1).toString(),
valuesList.at(query.value(0).toInt()));
QString queryString = "INSERT INTO person (%1) "
"VALUES (%2)";
QString insertColsString;
QString bindColsString;
for(int i = 0; i < colList.size(); i++) {
insertColsString += colList.at(i).first + ", ";
bindColsString += ":" colList.at(i).first + ", ";
}
if(!insertColsString.isEmpty()) {
insertColsString.chop(2);
bindColsString.chop(2);
}
query.prepare(queryString.arg(insertColsString, bindColsString));
for(int i = 0; i < colList.size(); i++)
query.bindValue(":" + colList.at(i).first, colList.at(i).second);
query.exec();
I'm editing the database in this manner:
QSqlQuery query;
query.prepare("UPDATE student "
"SET name = ? "
"WHERE id = ?");
QString name = "t";
int id = 3;
query.addBindValue(name);
query.addBindValue(id);
query.exec(); // query exec returns true
QSqlRecord record = query.record(); // but the record is empty!
mTableModel->beforeInsert(record);
The retrieved record is always empty, but the QSqlTableModel still changes! I need the record to be valid because I'm trying to synchronize an sql db with a std::vector.
I'm connecting to the database like this:
mDatabase = QSqlDatabase::addDatabase("QSQLITE");
mDatabase.setDatabaseName("database.db");
mDatabase.open();
I tried calling QSqlQuery::clear(), QSqlQuery::finish() but it didn't help. I also tried to open and close the DB, but it also didn't help. What can I do? :\
Qt is not a pain indeed.
All your code is good. The only wrong assumption is that an update request will automatically give you back the updated record. You have to make a new select request on this id to get the updates data in a QSqlRecord.
//[untested]
QSqlQuery select;
select.prepare("SELECT * from student where id = ?");
select.addBindValue(id);
if (select.exec() && select.next()) {
QSqlRecord record = select.record();
}