Qt SQLite no query or parameter count mismatch - c++

Juggling between receiving 2 different errors.
void summary::on_pushButton_saveSummary_clicked()
{
if(db.open())
{
query.exec("insert or replace into [PN:"+partNum+" CN:"+chargeNum+"](total, defects, rust) values(1, 2, 3)");
if (!query.exec())
{
qDebug() << query.lastError();
qDebug() << query.exec()<<endl;
}
}
else
{
qDebug() << db.lastError();
}
}
The above gives error: QSqlError("", "Unable to fetch row", "No query")
While:
void summary::on_pushButton_saveSummary_clicked()
{
if(db.open())
{
qDebug() << "db open";
int a = 3;
int b = 1;
int c = 3;
query.prepare("insert into [PN:"+partNum+" CN:"+chargeNum+"](total, defects, rust) values(:total, :defects, :rust)");
query.bindValue(":total", a);
query.bindValue(":defects", b);
query.bindValue(":rust", c);
if (!query.exec())
{
qDebug() << query.lastError();
qDebug() << query.exec()<<endl;
}
}
else
{
qDebug() << db.lastError();
}
}
Yields: QSqlError("", "Parameter count mismatch", "")
The Constructor has:
db.setDatabaseName("/home/igraves/Databases/testdb");
db.open();
QString partNum = "134345";
QString chargeNum = "3452";
query.prepare("create table if not exists [PN:"+partNum+" CN:"+chargeNum+"](total int, defects int, rust int)");
query.exec();
The table is being create, I can see it. So I am guessing syntax? Although it is as the Qt wiki writes it...
Edit:
Adding some .h stuff
QString partNum;
QString chargeNum;
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
QSqlQuery query;
Answer: It was my QString variables being temporary, after the constructor was done, they went out of scope. Changed my .h
QString partNum = "124124";
QString chargeNum = "234234";

I see at least the following errors:
You do not set the database path.
Do not open the database when creating the table.
"134345" and "3452" are being assigned to temporary variables instead of class members
Considering the above, the following must be in the constructor:
partNum = "134345";
chargeNum = "3452";
db.setDatabaseName("/path/of/database.db");
if(db.open())
query.exec(QString("create table if not exists [PN:%1 CN:%2](total int, defects int, rust int)")
.arg(partNum)
.arg(chargeNum));

Related

QSqlTableModel: unable to find table when calling submitAll method

I want to insert data into an SQLite database using QSqlDatabase and QSqlTableModel.
The database is being created in an SqlDatabaseController class:
SqlDatabaseController.h
// ...
class SqlDatabaseController : public QObject
{
Q_OBJECT
// ...
private:
QSqlDatabase _database;
SqlContactModel* _contactModel { nullptr };
// ...
SqlDatabaseController.cpp
SqlDatabaseController::SqlDatabaseController(QObject *parent) : QObject(parent)
{
// create database driver
_database = QSqlDatabase::database();
_contactModel = new SqlContactModel(this, _database);
}
// ...
void SqlDatabaseController::connectToDatabase(const QString &name, const QString &pwd)
if (!_database.isValid()) {
_database = QSqlDatabase::addDatabase("QSQLITE");
if (!_database.isValid()) {
qFatal("[SQL] SqlDatabaseController: Cannot add database: %s", qPrintable(_database.lastError().text()));
}
}
const QDir writeDir { QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).append("/").append(name) };
if (!writeDir.exists() && !writeDir.mkpath(".")) {
qFatal("[SQL] SqlDatabaseController: Failed to create writable directory at %s", qPrintable(writeDir.absolutePath()));
}
// Ensure that we have a writable location on all devices.
const QString fileName { writeDir.absolutePath() + "/db.sqlite3" };
// When using the SQLite driver, open() will create the SQLite database if it doesn't exist.
_database.setDatabaseName(fileName);
if (!_database.open()) {
qFatal("[SQL] SqlDatabaseController: Cannot open database: %s", qPrintable(_database.lastError().text()));
QFile::remove(fileName);
return;
}
emit databaseConnected();
}
For model data storing, I'm subclassing QSqlTableModel:
SqlContactModel.cpp
SqlContactModel::SqlContactModel(QObject* parent, QSqlDatabase db) :
QSqlTableModel(parent, db),
_tableName("Contacts")
{
}
As you can see, I'm passing the database to the TableModel so it's able to use this database for all queries.
Afterwards, I'm creating the tables:
SqlContactModel.cpp
void SqlContactModel::create()
{
createTable();
setTable(_tableName);
setSort(2, Qt::DescendingOrder);
// Ensures that the model is sorted correctly after submitting a new row.
setEditStrategy(QSqlTableModel::OnManualSubmit);
}
// ...
void SqlContactModel::createTable()
{
qDebug() << "[SQL] Creating table" << _tableName << "for database" << QSqlDatabase::database().databaseName() << ".";
if (QSqlDatabase::database().tables().contains(_tableName)) {
qDebug() << "[SQL] Database table" << _tableName << "already exists. Exiting createTable().";
emit contactTableCreated();
return;
}
QSqlQuery query { "SOME_QUERY" };
if (!query.exec()) {
qFatal("[SQL] SqlContactModel: Failed to create table: %s", qPrintable(query.lastError().text()));
return;
}
if (!submitAll()) {
qFatal("[SQL] SqlContactModel: Failed to submit createTable query: %s", qPrintable(lastError().text()));
}
emit contactTableCreated();
qDebug() << "Done creating table" << _tableName << ".";
}
Now, I want to insert something into my table like this:
SqlContactModel.cpp
// ...
void SqlContactModel::addContact(const QString& contactName, const QString& id, const QByteArray& avatar)
{
QSqlQuery query;
query.prepare("INSERT OR REPLACE INTO '" +
_tableName +
"'(id, name" +
(avatar.isEmpty() ? "" : ", avatar") +
") VALUES (:Id, :Name" + (avatar.isEmpty() ? "" : ", :Avatar") +
")");
query.bindValue(":Id", id);
query.bindValue(":Name", contactName);
if (!avatar.isEmpty()) {
query.bindValue(":Avatar", avatar);
}
if (!query.exec()) {
qFatal("[SQL] SqlContactModel: Unable to execute query in addContact: %s", qPrintable(query.lastError().text()));
return;
}
for (auto const& table : QSqlDatabase::database().tables()) {
qDebug() << "Table: " << table;
}
if (!submitAll()) { // <-- here's where it breaks
qFatal("[SQL] SqlContactModel: Failed to submit addContact query: %s", qPrintable(lastError().text()));
return;
}
qDebug() << "[SQL] Added contact " << contactName << "(" << id << ") to table " << _tableName << ".";
// emit contactListChanged();
}
The query executes just fine and the data is being stored in the database, however since I'm using setEditStrategy(QSqlTableModel::OnManualSubmit); on my model, I would need to call submitAll() on my model to be updated properly. When calling submitAll(), however, I keep getting an error:
[SQL] SqlContactModel: Failed to submit addContact query: Unable to find table Contacts.
As you can see in the code above, I iterated through all tables of the database and I get the following output:
Table: "Contacts"
Table: "Conversations"
which is why I'm quite sure the table does exist.
Is this some kind of encoding error or why is submitAll() not able to find my table Contacts in the database? What am I missing here?
Thanks in advance.

QSqlTablelModel cannot find SQL view, but QSqlQuery can

I want to use QSqlTableModel since it seems easier to use. It does however not find my tables.
qDebug() << "connecting";
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName(dbHostName);
db.setPort(dbPort);
db.setUserName(dbUserName);
db.setPassword(dbPassword);
// Connect to database sys to get some info to test (basic communication)
db.setDatabaseName("sys");
// Check if opened and if so get some data
if(db.open()){
qDebug() << "DB succesfully opened";
} else {
qDebug() << "DB failed to open";
return;
}
QSqlTableModel* runsSimulationViewModel = new QSqlTableModel();
runsSimulationViewModel->setTable("results.runs_simulation_view");
qDebug() << runsSimulationViewModel->lastError();
//ERROR: QSqlError("", "Unable to find table results.runs_simulation_view", "")
QSqlQuery anotherQuery;
anotherQuery.prepare("SELECT * FROM results.runs_simulation_view");
if(!anotherQuery.exec()) {
qDebug() << anotherQuery.lastError();
} else {
anotherQuery.next();
qDebug() << anotherQuery.value("simulation_id").toInt();
//Prints "3", which is the first value for this field in the table
}
QSqlQuery works, but QSqlTableView cannot find this (SQL) view (and also no tables).
What am I missing?

Parameter count mismatch in Qtsql

I'm trying to insert data into a QtSql database, but I keep getting the error:
"Parameter count mismatch"
What could be what I'm doing wrong?
#include <QtSql>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << QSqlDatabase::drivers();
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setHostName("LOCALHOST");
db.setDatabaseName("people");
db.setUserName("root");
db.setPassword("");
if(db.open()) {
qDebug() << "Opened!";
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();
if( !query.exec() )
qDebug() << query.lastError().text();
else
qDebug( "Inserted!" );
db.close();
} else {
qDebug() << "Not opened";
}
}
You don't have a table named person in the database. You are trying to insert values into a table that does not exist.
I think that the error message is wrong. But anyway, I added a CREATE statement to your code, so that the table is created before the INSERT statement is executed:
#include <QtSql>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
if(!db.open()){
qDebug() << "Not opened";
return 1;
}
qDebug() << "Opened!";
QSqlQuery query;
//CREATE the table before executing the INSERT statement
query.exec("CREATE TABLE person (id INTEGER, forename TEXT, surname TEXT);");
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (:id, :forename, :surname)");
query.bindValue(":id", 1001);
query.bindValue(":forename", "Bart");
query.bindValue(":surname", "Simpson");
if( !query.exec() )
qDebug() << query.lastError().text();
else
qDebug( "Inserted!" );
return 0;
}
This prints Inserted! now. But if I comment out the CREATE statement line I get the same error in your question:
" Parameter count mismatch"

evaluating mysql NULL with = operator

I have following Qt/C++ class method:
bool UeOrdersModel::ueSlotRefreshOrdersData(const QString& userId,
const QString& placeId,
const QString& customerId)
{
bool result=false;
bool connected=false;
bool customerIdEmpty=customerId.isEmpty()||customerId.isNull();
this->ueSetUserId(userId);
this->ueSetPlaceId(placeId);
if(this->ueDatabase().isOpen())
{
connected=true;
}
else
{
if(this->ueConnectToDatabase())
{
connected=this->ueDatabase().open();
} // if
} // if
if(connected)
{
this->setQuery(UePosDatabase::UeSqlQueries::UeViewOrders::SQL_QUERY_GET_ORDERS_FILTERED_BY_USERID_PLACEID_CUSTOMER_ID.arg(userId)
.arg(placeId)
.arg(customerIdEmpty?QString(QString::null):customerId),
this->ueDatabase());
if(this->query().lastError().isValid())
{
qDebug() << Q_FUNC_INFO
<< this->query().lastError().text();
}
else
{
this->ueUpdateTotalAmounts(userId,
placeId,
customerId);
result=true;
} // if
}
else
{
qDebug() << Q_FUNC_INFO
<< this->lastError().text();
} // if
return result;
} // ueSlotRefreshOrdersData
which basically executes following mysql query:
static const QString SQL_QUERY_GET_ORDERS_FILTERED_BY_USERID_PLACEID_CUSTOMER_ID=
"SELECT ORDERS.USER_ID, PEOPLE.NAME, PLACE_ID, PLACES.NAME, PRODUCT_ID, "
"PRODUCTS.IMAGE, PRODUCTS.NAME, PRODUCTS.PRICESELL, TAXES.RATE, ORDERS.PRODUCT_QUANTITY, ORDERS.CUSTOMER_ID "
"FROM ORDERS "
"JOIN PEOPLE ON ORDERS.USER_ID=PEOPLE.ID "
"JOIN PRODUCTS ON ORDERS.PRODUCT_ID=PRODUCTS.ID "
"JOIN PLACES ON ORDERS.PLACE_ID=PLACES.ID "
"JOIN TAXCATEGORIES ON PRODUCTS.TAXCAT=TAXCATEGORIES.ID "
"JOIN TAXES ON TAXCATEGORIES.ID=TAXES.ID "
"WHERE ORDERS.USER_ID=\"%1\" AND ORDERS.PLACE_ID=\"%2\" AND CUSTOMER_ID=\"%3\"";
Now, if method's third parameter, customerId, is empty, I must evaluate upper mysql statement with CUSTOMER IS NULL, I am aware of that. But, is it possible to evaluate mysql NULL value using = operator, like in my case?

Qt Qvariantlist conversion into javascript array unsuccessful

I'm currently create an apps in Meego using QML and JS on most of the part. and now I stumbled upon a problem.
From javascript I want to call a C++ function to read text file, parse it, and then return an array of the parsing result.
so I create a Q_INVOKABLE function called parse() and call it through javascript
function parse() {
var myArray = new Array();
myArray = parser.parse("/home/user/MyDocs/angklungtext.txt")
if(myArray === undefined){
console.log("null found");
}
for(var i = 0; i < myArray.length; i++){
console.log(myArray[i][0] + "," + myArray[i][1])
}
}
and here is the parse function in C++
QVariantList* QMLParser::parse(QString filename)
{
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug()<< dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists())
{
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
QVariantList* myList = new QList<QVariant>;
while(!stream.atEnd())
{
QString line = stream.readLine();
qDebug() << line.trimmed();
QStringList lineList = line.split(":");
myList->append(lineList);
}
file.close();
return myList;
}
sadly.
when I try to run it it giving a result like this
start debugging
"/home/user/MyDocs/angklungtext.txt"
"/home/developer"
"/home/user/MyDocs/angklungtext.txt"
"1:1000"
"4:2000"
"5:3000"
"2:4000"
null found
file:///opt/memoryreader/qml/memoryreader/myjs.js:8: TypeError: Result of expression 'myArray' [undefined] is not an object.
looks like the C++ parse function successfully parsing the file. it can read it and it can save it into the QVariantList.
but after it return the result into javascript myArray still [undefined].
is there something wrong with the conversion?
Just simplify the C++ side like this :
QVariant QMLParser::parse(QString filename)
{
QStringList myList;
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug() << dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists()) {
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
while(!stream.atEnd()) {
QString line = stream.readLine();
qDebug() << line.trimmed();
myList << line.trimmed().split(":");
}
file.close();
return QVariant::fromValue(myList);
}
And it should work !
Just remember, QML must see a QVariant, even if a QList is wrapped inside it, and Qt is able to convert most of its base types to QVariant using QVariant::fromValue(T) so use it extensively.
Oh and BTW a QVariant is reference not pointer.
Haven't done this myself, so I'm just thinking out loud. But I note that you're returning a pointer to a QVariantList...which looks suspect. (Also: if you new, then who would do the delete?)
Have you tried returning it by value?