I'm trying to check if a table exist in a schema for QMYSQL inside QT framework.
I have connected the MySQL server and it can create a table, but NOT check if a table exist.
This is the code for checking if a table exist
query.exec("CREATE TABLE " + table_name + "(ID BIGINT PRIMARY KEY)");
QStringList tables = this->qSqlDatabase.tables();
qDebug() << "Table name: " + table_name;
for(int i = 0; i < tables.length(); i++)
qDebug() << tables[i];
qDebug() << tables.length();
if(tables.contains(table_name))
The if-statement does not run and the output is:
"Table name: table0"
0
In this case table_name = "table0". But why does this happening?
try this line:
query.exec("CREATE TABLE " + table_name + " (ID BIGINT, PRIMARY KEY (ID));");
Related
I want to create a SQL table in QT C++. So I have made this code.
And it is going to create a database for me, where the first argument tableName is the name of the table I want to create. Then the next argument is quite tricky.
Here, columns, specify the column name and it's data type. I think this is a bad way to do. Example
QVector<QPair<QString, QString>> myColumns = new QVector<QPair<QString, QString>>{{"ID", "BIGINT"}, {"logging_id", "INT"}};
Because If i have for example like 50 columns. The myColumns is going to be very long.
My question if QT C++ have some kind of reflections, so I can:
Get the name if every field
Get the data type of every field
If the field is an array, then I'm going to know how many elements there are inside that array
I was planning to have an entity class where I create a class, and use that class to get the information to create each columns in the database.
void Database::createTable(QString tableName, const QVector<QPair<QString, QString>> columns){
QSqlQuery query;
for (int i = 0; i < columns.length(); i++){
/* Get the Qpair values */
QString columnName = columns.at(i).first;
QString dataType = columns.at(i).second;
/* If key is ID, then try to create a new table */
if(columnName == "ID"){
query.exec("CREATE TABLE " + tableName + "(" + columnName + " " + dataType + " NOT NULL AUTO_INCREMENT PRIMARY KEY)");
continue;
}
/* If not, then try append new columns */
query.exec("ALTER TABLE " + tableName + " ADD " + columnName + " " + dataType);
}
}
My task is to determine the primary key of a postgres table with libpqxx (dynamically), but I don't know how to bind the value correctly. I get syntax error.
std::string sql =
"SELECT c.column_name, c.data_type "\
"FROM information_schema.table_constraints tc"
"JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)"
"JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema "
"AND tc.table_name = c.table_name AND ccu.column_name = c.column_name "
"WHERE constraint_type = 'PRIMARY KEY' and tc.table_name = '$1';";
C->prepare("determine_primary_key", sql.c_str());
pqxx::prepare::invocation w_invocation = W->prepared("determine_primary_key");
std::vector<std::string > vect;
vect.push_back("postgres_table_name");
prep_dynamic(vect, w_invocation);
pqxx::result r = w_invocation.exec();
From the documentation for pqxx, the prepared() method is deprecated. So using your code snippet I would make the following changes to use the new exec_prepared() statement and pull in your parameter:
std::string sql =
"SELECT c.column_name, c.data_type "\
"FROM information_schema.table_constraints tc"
"JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)"
"JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema "
"AND tc.table_name = c.table_name AND ccu.column_name = c.column_name "
"WHERE constraint_type = 'PRIMARY KEY' and tc.table_name = '$1';";
C->prepare("determine_primary_key", sql.c_str());
pqxx::result r = W->exec_prepared("determine_primary_key", "<your_table_name_here>");
But, if you are still using the older version of pqxx and need to keep using prepared() you can do the following:
std::string sql =
"SELECT c.column_name, c.data_type "\
"FROM information_schema.table_constraints tc"
"JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)"
"JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema "
"AND tc.table_name = c.table_name AND ccu.column_name = c.column_name "
"WHERE constraint_type = 'PRIMARY KEY' and tc.table_name = '$1';";
C->prepare("determine_primary_key", sql.c_str());
pqxx::result r = W->prepared("determine_primary_key")("<your_table_name_here>").exec();
You can check the libpqxx documentation to get more info on prepared() and exec_prepared().
After I create a table, insert data into it, and then delete a non-existent row, the operation succeeds even though the row does not exist. When I delete a row that actually exists, it succeeds as well and the row is actually deleted. Why doesn't an error occur when I try to delete a row that does not exist?
I am using sqlite3 with c++ on eclipse.
I've been working with some code found on the web, as well as my own.
Other operations, like SELECT and INSERT work fine. DELETE works when rows exist and even when they don't exist.
// Creating a table
sql = "CREATE TABLE COMPANY(" \
"ID INT PRIMARY KEY NOT NULL," \
"NAME TEXT NOT NULL," \
"AGE INT NOT NULL," \
"ADDRESS CHAR(50)," \
"SALARY REAL );";
// Inserting data
sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " \
"VALUES (1, 'Paul', 32, 'California', 20000.00 ); " \
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " \
"VALUES (2, 'Allen', 25, 'Texas', 15000.00 ); " \
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \
"VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );" \
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \
"VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );";
// Deleting (this is where the deletion should fail because there is no
ID 30)
rc = sqlite3_open("test.db", &db);
if( rc ) {
cout << "ERROR ----> " << zErrMsg << endl;
return(0);
} else {
fprintf(stderr, "Opened database successfully\n");
}
/* Create SQL statement */
sql = "DELETE FROM COMPANY WHERE ID = 30";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
if( rc != SQLITE_OK ) {
cout << "ERROR DELETING" << endl;
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
fprintf(stdout, "Deletion operation done successfully\n");
}
sqlite3_close(db);
I expect the message "ERROR DELETING" to be displayed, but "Deletion operation done successfully" always displays, even when the ID deleted does not exist.
Why doesn't an error occur when I try to delete a row that does not exist?
Databases return number of rows affected (deleted in your case), they don't throw error, unless there is something wrong with the query.
The only guaranteed method to check if the row has been deleted is to execute a SELECT statement with the same conditions. Transaction control is an important factor here, i.e. what happens if something causes a rollback? Are you explicitly committing transactions, or allowing them to auto-commit? You shouldn't just rely on return codes for this. If you do a COUNT as well, then you will know for sure, at least within your session:
SELECT COUNT(*) FROM COMPANY WHERE ID = 30
If after the DELETE, the COUNT is 0, the row no longer exists.
Note: This approach will be helpful if you need concurrency, which will force you to use a different database engine (e.g. PostgreSQL).
I guess the answer is "this is by design".
If you need to know if zero (or more) rows were affected by the last DELETE statement (or INSERT or UPDATE for that matter) then you could look into using:
int sqlite3_changes(sqlite3*);
That will allow you to react accordingly if no rows were deleted.
See https://www.sqlite.org/c3ref/changes.html
I am using mysql C++ connector. I have a table:
CREATE TABLE some_table
(
id INT NOT NULL AUTO_INCREMENT,
col1 INT,
col2 INT,
PRIMARY KEY ( id )
);
To insert multiple records in a query, I use:
INSERT INTO some_table
(col1, col2)
VALUES
(0, 1),
(2, 3),
(4, 5);
My question is: After the insertion, I would like to retrieve all the auto-generated ids. Is it possible that I could use a function in the c++ connector without creating another query?
For example, in the JDBC, the AUTO_INCREMENT column values can be retrieved by using following method.
stmt.executeUpdate(
"INSERT INTO autoIncTutorial (dataField) "
+ "values ('Can I Get the Auto Increment Field?')",
Statement.RETURN_GENERATED_KEYS);
//
// Example of using Statement.getGeneratedKeys()
// to retrieve the value of an auto-increment
// value
//
int autoIncKeyFromApi = -1;
rs = stmt.getGeneratedKeys();
if (rs.next()) {
autoIncKeyFromApi = rs.getInt(1);
} else {
// throw an exception from here
}
https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-usagenotes-last-insert-id.html
Any c++ connector alternatives?
Thanks
Last year I faced the same problem. The solution was to use the builtin LAST_INSERT_ID(). Following I changed the getting start example 2 to show how to use it:
//previous variable declarations and initialisation similar to the original example
driver = get_driver_instance();
con = driver->connect("tcp://127.0.0.1:3306", "root", "root");
con->setSchema("test_schema");
con->setAutoCommit(false);
stmt = con->createStatement();
stmt->execute("DROP TABLE IF EXISTS tbl__test1");
stmt->execute("DROP TABLE IF EXISTS tbl_test2");
const string createTbl1Statement = "CREATE TABLE `tbl__test1` ("
"`id` int(11) NOT NULL AUTO_INCREMENT,"
"`col_value` varchar(45) DEFAULT NULL,"
"PRIMARY KEY (`id`)"
") ENGINE=InnoDB DEFAULT CHARSET=latin1;";
const string createTbl2Statement = "CREATE TABLE `tbl_test2` ("
"`id` int(11) NOT NULL AUTO_INCREMENT,"
"`tbl_test1_id` int(11) NOT NULL,"
"`col_value` varchar(45) DEFAULT NULL,"
"PRIMARY KEY (`id`)"
") ENGINE=InnoDB DEFAULT CHARSET=latin1;";
stmt->execute(createTbl1Statement);
stmt->execute(createTbl2Statement);
pstmt = con->prepareStatement(
"INSERT INTO tbl__test1(col_value) VALUES ('abcde')");
pstmt->executeUpdate();
delete pstmt;
stmt->execute("SET #lastInsertId = LAST_INSERT_ID()");
delete stmt;
const string insertTbl2 = "INSERT INTO tbl_test2(tbl_test1_id, col_value)"
" VALUES (#lastInsertId, '1234')";
pstmt = con->prepareStatement(insertTbl2);
pstmt->executeUpdate();
delete pstmt;
con->commit();
delete con;
//remain code is like the example 2 from mysql site
About how safe is call LAST_INSERT_ID(), as stated in the mysql docs:
The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own. This behavior ensures that each client can retrieve its own ID without concern for the activity of other clients, and without the need for locks or transactions.
EDIT:
As given here:
With no argument, LAST_INSERT_ID() returns a 64-bit value representing the first automatically generated value successfully inserted for an AUTO_INCREMENT column as a result of the most recently executed INSERT statement.
Thus, the LAST_INSERT_ID returns the last generated id regardless the table where the new row was insert. If you need to insert several rows just call LAST_INSERT_ID immediately after insert each row such you want to get the key.
In the following code it is inserted 1 row in the table 1, get the generated key (returns '1') than that key is used for insert news 2 rows in the associated table 2. Than again it is inserted 1 new row in the table 1, get generated key again (returns '2') and inserted 2 news rows again in the table 2:
#include <stdlib.h>
#include <iostream>
#include "mysql_connection.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
using namespace std;
int main(void) {
cout << endl;
cout << "Let's have MySQL count from 10 to 1..." << endl;
try {
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::PreparedStatement *pstmt1;
sql::PreparedStatement *pstmt2;
driver = get_driver_instance();
con = driver->connect("tcp://127.0.0.1:3306", "root", "root");
con->setSchema("test_schema");
con->setAutoCommit(false);
stmt = con->createStatement();
stmt->execute("DROP TABLE IF EXISTS tbl__test1");
stmt->execute("DROP TABLE IF EXISTS tbl_test2");
const string createTbl1Statement = "CREATE TABLE `tbl__test1` ("
"`id` int(11) NOT NULL AUTO_INCREMENT,"
"`col_value` varchar(45) DEFAULT NULL,"
"PRIMARY KEY (`id`)"
") ENGINE=InnoDB DEFAULT CHARSET=latin1;";
const string createTbl2Statement = "CREATE TABLE `tbl_test2` ("
"`id` int(11) NOT NULL AUTO_INCREMENT,"
"`tbl_test1_id` int(11) NOT NULL,"
"`col_value` varchar(45) DEFAULT NULL,"
"PRIMARY KEY (`id`)"
") ENGINE=InnoDB DEFAULT CHARSET=latin1;";
stmt->execute(createTbl1Statement);
stmt->execute(createTbl2Statement);
pstmt1 = con->prepareStatement(
"INSERT INTO tbl__test1(col_value) VALUES (?)");
pstmt1->setString(1, "abcde");
pstmt1->executeUpdate();
stmt->execute("SET #lastInsertId = LAST_INSERT_ID()");
const string insertTbl2 =
"INSERT INTO tbl_test2(tbl_test1_id, col_value)"
" VALUES (#lastInsertId, ?)";
pstmt2 = con->prepareStatement(insertTbl2);
pstmt2->setString(1, "child value 1");
pstmt2->executeUpdate();
pstmt2->setString(1, "child value 2");
pstmt2->executeUpdate();
pstmt1->setString(1, "xpto");
pstmt1->executeUpdate();
stmt->execute("SET #lastInsertId = LAST_INSERT_ID()");
pstmt2->setString(1, "child value 3");
pstmt2->executeUpdate();
pstmt2->setString(1, "child value 4");
pstmt2->executeUpdate();
con->commit();
delete stmt;
delete pstmt1;
delete pstmt2;
delete con;
} catch (sql::SQLException &e) {
cout << "# ERR: SQLException in " << __FILE__;
cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
cout << "# ERR: " << e.what();
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
}
cout << endl;
return EXIT_SUCCESS;
}
The result is the 2 rows in table 1:
And 4 rows in the table 2 each one properly associated with the key in table 1:
So, the key point is to call LAST_INSERT_ID() after insert the new row with the generated key you need.
I've been creating a dictionary file that contains 85000 records with Sqlite and QT. the file of sqlite is too huge, it's 134MB, and another dictionary like MDic DB have same data that created with sqlite and same records is 10 MB!
query.exec("PRAGMA journal_mode = MEMORY");
query.exec("PRAGMA synchronous = OFF");
Dic_entry DictionaryEntry = DictionaryInstance.readEntry();
QString definition, headword, displayedHeadWord;
query.exec("BEGIN Transaction");
int Count = 0;
while(!DictionaryEntry.headword.empty())
{
definition = QString::fromStdString(DictionaryEntry.definition);
definition.replace("'", "''");
headword = QString::fromStdString(DictionaryEntry.headword);
headword.replace("'", "''");
displayedHeadWord = QString::fromStdString(DictionaryEntry.displayedHeadword);
displayedHeadWord.replace("'", "''");
string strQuery = "INSERT INTO Dictionary_Words([Definition], [HeadWord], [DisplayedHeadWord]) "
"values('"
+ definition.toStdString() + "', '"
+ headword.toStdString() + "', '"
+ displayedHeadWord.toStdString()
+ "')";
query.exec(QString::fromStdString(strQuery));
if(Count == 200)
{
query.exec("COMMIT TRANSACTION");
Count = 0;
}
Count++;
DictionaryEntry = DictionaryInstance.readEntry();
}
query.exec("End Transaction");
query.exec("CREATE INDEX HW_idx ON [Dictionary_Words](HeadWord)");
query.exec("CREATE INDEX Def_idx ON [Dictionary_Words](Definition)");
query.exec("CREATE INDEX DHW_idx ON [Dictionary_Words](DisplayedHeadword)");
query.exec("PRAGMA auto_vacuum=FULL");
db.close();
Please help me that how can i reduce my SQlite DB file
I have no way of proving it, but I suspect the indexes are the cause of the trouble. Indexes can take up a huge amount of space, and you've got three of them. Try it without them and see if the access is still acceptably fast; the database size should be much smaller that way.