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.
Related
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?
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));
I have this c++ code that works fine, i can read from the tables and write to the tables:
int main()
{
// Try to get a driver to use to connect to our DBMS
try
{
driver = get_driver_instance();
}
catch (sql::SQLException e)
{
cout << "Could not get a database driver. Error message: " << e.what() << endl;
system("pause");
exit(1);
}
// Try to connect to the DBMS server
try
{
dbConn = driver->connect(server, username, password);
}
catch (sql::SQLException e)
{
cout << "Could not connect to database. Error message: " << e.what() << endl;
system("pause");
exit(1);
}
stmt = dbConn->createStatement(); // Specify which connection our SQL statement should be executed on
// Try to query the database
try
{
stmt->execute("USE test"); // Select which database to use. Notice that we use "execute" to perform a command.
res = stmt->executeQuery("INSERT INTO users (fName, lName, age) VALUES ('fname', 'lname', 25)"); // Perform a query and get the results. Notice that we use "executeQuery" to get results back
//res = stmt->executeQuery("SELECT * FROM users");
//return 0;
}
catch (sql::SQLException e)
{
cout << "SQL error. Error message: " << e.what() << endl;
system("pause");
exit(1);
}
sql::ResultSetMetaData *res_meta = res -> getMetaData();
int columns = res_meta -> getColumnCount();
// While there are still results (i.e. rows/records) in our result set...
while (res->next())
{
for (int i = 1; i <= columns; i++) {
cout << res->getString(i) << " | " ;
}
cout << endl;
}
delete res;
delete stmt;
delete dbConn;
//system("pause");
return 0;
}
So, this inserts to the table but then i get this error message
SQL error. Error message: sh: 1: pause: not found
This doesn't happen if i use the "select".
Also i know that this question was already asked here but unfortunately it has no answer so i'm asking again.
Your question looks related to MySQL Query executes but throws exception.
executeQuery() assumes that sql query should return sql::ResultSet but your INSERT INTO query does not. You can use execute() instead, which returns true or false:
try
{
stmt->execute("USE test");
stmt->execute("INSERT INTO users (fName, lName, age) VALUES ('fname', 'lname', 25)");
}
catch (sql::SQLException e)
{
cout << "SQL error. Error message: " << e.what() << endl;
exit(1);
}
An INSERT is not a query. Try using executeUpdate() instead of executeQuery(). Look at the official MySQL example here.
Replace this line
res = stmt->executeQuery("INSERT INTO users (fName, lName, age) VALUES ('fname', 'lname', 25)"); // Perform a query and get the results. Notice that we use "executeQuery" to get results back
with the following lines (you may need a new .h file):
sql::PreparedStatement *pstmt;
pstmt = con->prepareStatement("INSERT INTO users (fName, lName, age)
VALUES ('fname', 'lname', 25)");
res = pstmt->executeUpdate();
delete pstmt;
You may also try using execute(), as shown in this Stackoverflow question. The function execute() is used for generic SQL commands, but may not be as verbose in its return value as more specified functions (it returns a boolean).
I am taking ID from my user and then i want to delete that ID from the database. I am using postgresql. but the query is not running. When i give hard code value like id=5 then it runs but when i give it user's value like id = DeleteId then it doesn't run. Here is the function:
void DeleteValue(PGconn *conn, int DeleteId)
{
PGresult *res = PQexec(conn, "DELETE FROM testData where ID = DeleteId" );
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
cout << "Delete testData record failed." << endl;
PQclear(res);
CloseConn(conn);
}
cout << "\nDelete testData record - OK\n";
PQclear(res);
}
Just solved my own problem.first concatenate it with the help of sprintf and then execute the query. Here is the solution of the problem
sprintf(sql,"DELETE FROM testData WHERE id = %d",DeleteId);
PGresult *res = PQexec(conn, sql );
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?