sqlite3 won't work second time - c++

My Sqlite connector works just fine the first time I try to insert rows, but after it is closed and I run the program again it won't work at all.
Here is my constructor
Sqldatabase::Sqldatabase() {
open_connection("Database.db");
sqlite3_stmt *statement;
std::string sql = "SELECT id FROM articles ORDER BY id DESC LIMIT 1";
char *query = &sql[0];
if(sqlite3_prepare_v2(db, query, -1, &statement, 0) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) {
article_counter = sqlite3_column_int(statement, 0) + 1;
} else {
article_counter = 1;
}
}
Here is my preparedStatement method.
bool Sqldatabase::prepareStatement(std::string sql) {
char *query = &sql[0];
sqlite3_stmt *statement;
int result;
if (sqlite3_prepare_v2(db, query, sql.size(), &statement, 0) == SQLITE_OK) {
result = sqlite3_step(statement);
std::cout << sql << '\n';
sqlite3_finalize(statement);
if(result == SQLITE_DONE) {
return true;
}
}
std::cout << "SQL failed: " << sql << '\n';
return false;
}
And finally here is where I call the method.
bool Sqldatabase::create_ART(int ng_id, std::string title, std::string author, std::string text) {
//Creating article
std::ostringstream s;
s << "INSERT INTO articles (id, title, author, content, created) " <<
"VALUES (" << article_counter << ", '" << title << "', '" << author << "', '" << text << "' , CURRENT_DATE)";
std::string sql(s.str());
prepareStatement(sql);
//Adding article to newsgroup
std::ostringstream t;
t << "INSERT INTO contains VALUES ( " << article_counter << " , " << ng_id << ")";
std::string sql2(t.str());
article_counter++;
return prepareStatement(sql2);
}
My test script looks like this. And I already have a Newsgroup with id 1 in the database.
Sqldatabase db;
int main(int argc, char* argv[]){
std::cout << "-----Test of Memdatabase, Newsgroup and Article classes-----" << std::endl;
db = Sqldatabase();
db.create_ART(1, "Happy day", "John", "Sunday afternoon is pretty chill");
db.create_ART(1, "Chill day", "Peter", "Sunday afternoon is pretty chill");
}

Ah, you're trying to create a new record with the same id. ids are typically unique. try:
db.create_ART(2, "Chill day", "Peter", "Sunday afternoon is pretty chill");

Related

sqlite3: Table schema not copying from main database to second database

I am attempting to copy the same table schema and a select number of entries from my main database to a new secondary database. I am able to create the second database START.sql and inside it, a table called copied, however the schema between that and the main masterDatabaseTest differ and as a result I receive the error:
table START.copied has 1 columns but 5 values were supplied
The code:
void newLog(std::string tableName, std::string timeStart, std::string timeEnd)
{
char *err_msg = NULL;
int rc= -1;
std::string dbLogName = timeStart;
std::string dbLogName2 = dbLogName + ".sql";
std::string attachQuery = "ATTACH DATABASE 'START.sql' AS 'START';";
std::string copyTable = "CREATE TABLE START.copied AS SELECT sql FROM sqlite_master WHERE type='table' and name='masterDatabaseTest';";
std::string insertCopied = "INSERT INTO START.copied SELECT * from sqlite_master where type='table' and name='masterDatabaseTest';";
std::string detach = "DETACH DATABASE START;";
std::cout << dbLogName << "\n"
<< attachQuery << "\n"
<< copyTable << "\n"
<< insertCopied << "\n"
<< detach << std::endl;
sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, 0);
rc = sqlite3_open(databaseName.c_str(), &db); // CREATES DATABASE
std::cout << "OPEN: " << rc << std::endl;
rc = sqlite3_exec(db, attachQuery.c_str(), NULL, 0, &err_msg);
std::cout << "ATTACH: " << rc << std::endl;
if(rc != 0){
std::cout << err_msg << std::endl;
}
rc = sqlite3_exec(db, copyTable.c_str(), NULL, 0, &err_msg);
std::cout << "copyTable: " << rc << std::endl;
if(rc != 0){
std::cout << err_msg << std::endl;
}
rc = sqlite3_exec(db, insertCopied.c_str(), NULL, 0, &err_msg);
std::cout << "insertCopied: " << rc << std::endl;
if(rc != 0){
std::cout << err_msg << std::endl;
}
rc = sqlite3_exec(db, detach.c_str(), NULL, 0, &err_msg);
std::cout << "detach: " << rc << std::endl;
if(rc != 0){
std::cout << err_msg << std::endl;
}
sqlite3_exec(db, "END TRANSACTION;", NULL, NULL, 0);
}
inside commandline sqlite3 database.sql:
sqlite> .schema
CREATE TABLE masterDatabaseTest (ID INTEGER,RECORDTIME BIGINT,TYPE INTEGER,TIMESTAMP BIGINT,ENCODER1 INTEGER,ENCODER2 INTEGER,ENCODER3 INTEGER,ENCODER4 INTEGER,ENCODER5 INTEGER);
inside commandline sqlite3 START.sql
sqlite> .schema
CREATE TABLE copied(sql TEXT);
If you want "an exact copy of the schema of masterDatabaseTest", you do not need to use sqlite_master. The DDL query
CREATE TABLE START.copied AS SELECT * from masterDatabaseTest
will accomplish that. If you want a select number of entries, add a WHERE clause. If you do not want any rows from the source table, add a WHERE 0; it will create the schema and will not select any rows.
I have figured out my problem :)
the db instance was not pointing to the correct database, so although I was able to execute it correctly in commandline, the actual program has no initialised the database connection so the sqlite3_exec command was pointing to nothing.
Fixing that I was able to execute the commands with no problem.

unable to use insert statement in mysql

void database::adduser(std::string username, std::string password, std::string land){
connect();
mysql_query(con, "USE users");
std::stringstream ss;
ss << "INSERT INTO users (username, paswd, land, landx, landy) VALUES (" << "'" << username << "'" << "," << "'" << password <<"'" << "," << "'" << land << "'"<< "50, 50)";
std::string insert;
insert = ss.str();
const char * c = insert.c_str();
mysql_query(con, c);
mysql_close(con);
}
int database::init(){
connect();
mysql_query(con, "USE users");
mysql_query(con, "CREATE TABLE IF NOT EXISTS users(username TEXT, passwd TEXT, land TEXT, landx INT, landy INT)");
mysql_close(con);
return 0;
}
char* database::getpaswd(std::string username){
connect();
mysql_query(con, "USE users");
std::stringstream ss;
ss << "SELECT paswd FROM users WHERE username=" << "'" << username << "'";
std::string insert;
insert = ss.str();
const char * c = insert.c_str();
mysql_query(con, c);
MYSQL_RES *result;
result = mysql_store_result(con);
MYSQL_ROW row;
row = mysql_fetch_row(result);
if(row == NULL){
std::cout << "NO USER OF THAT USERNAME" << std::endl;
return "NOT VALID USERNAME";
}
mysql_free_result(result);
mysql_close(con);
return row[0];
}
bool database::does_exist_user(std::string user){
connect();
mysql_query(con, "USE users");
std::stringstream ss;
ss << "SELECT username FROM users WHERE username=" << "'" << user << "'";
std::string insert;
insert = ss.str();
const char *c = insert.c_str();
mysql_query(con, c);
MYSQL_RES *result;
result = mysql_store_result(con);
MYSQL_ROW row;
row = mysql_fetch_row(result);
if(row == NULL){
mysql_free_result(result);
return false;
}
else{
mysql_free_result(result);
return true;
}
std::cout << "username taken" << std::endl;
return true;
}
void database::edit_land(std::string username, std::string land){
connect();
mysql_query(con, "USE users");
std::stringstream ss;
ss << "UPDATE users SET land=" << "'" << land << "' " << "WHERE username=" << "'" << username << "'";
std::string insert;
insert = ss.str();
const char *c = insert.c_str();
mysql_query(con, c);
mysql_close(con);
}
void database::edit_landX(std::string username, int land){
connect();
mysql_query(con, "USE users");
std::stringstream ss;
ss << "UPDATE users SET landx=" << land << " WHERE username=" << "'" << username << "'";
std::string insert;
insert = ss.str();
const char *c = insert.c_str();
mysql_query(con, c);
mysql_close(con);
}
void database::edit_landY(std::string username, int land){
connect();
mysql_query(con, "USE users");
std::stringstream ss;
ss << "UPDATE users SET landy=" << land << " WHERE username=" << "'" << username << "'";
std::string insert;
insert = ss.str();
const char *c = insert.c_str();
mysql_query(con, c);
mysql_close(con);
}
char* database::getland(std::string username){
connect();
mysql_query(con, "USE users");
std::stringstream ss;
ss << "SELECT land FROM users WHERE username=" << "'" << username << "'";
std::string insert;
insert = ss.str();
const char *c = insert.c_str();
mysql_query(con, c);
MYSQL_RES *result;
result = mysql_store_result(con);
MYSQL_ROW row;
row = mysql_fetch_row(result);
if(row == NULL){
return "ERROR";
}
mysql_close(con);
mysql_free_result(result);
return row[0];
}
char* database::getlandY(std::string username){
connect();
mysql_query(con, "USE users");
std::stringstream ss;
ss << "SELECT landy FROM users WHERE username=" << "'" << username << "'";
std::string insert;
insert = ss.str();
const char *c = insert.c_str();
mysql_query(con, c);
MYSQL_RES *result;
result = mysql_store_result(con);
MYSQL_ROW row;
row = mysql_fetch_row(result);
if(row == NULL){
std::cout << "ERROE ME BOI" << std::endl;
return "ERROR";
}
mysql_close(con);
mysql_free_result(result);
return row[0];
}
char* database::getlandX(std::string username){
connect();
mysql_query(con, "USE users");
std::stringstream ss;
ss << "SELECT landx FROM users WHERE username=" << "'" << username << "'";
std::string insert;
insert = ss.str();
const char *c = insert.c_str();
mysql_query(con, c);
MYSQL_RES *result;
result = mysql_store_result(con);
MYSQL_ROW row;
row = mysql_fetch_row(result);
if(row == NULL){
std::cout << "ERROE ME BOI" << std::endl;
return "ERROR";
}
mysql_close(con);
mysql_free_result(result);
return row[0];
}
void database::connect(){
con = mysql_init(NULL);
if(con == NULL){
std::cout << mysql_error(con) << std::endl;
exit(1);
}
if(mysql_real_connect(con, "127.0.0.1", "root", "password", "users", 3306, NULL, 0) == NULL){
std::cout << "NO BEUNO";
std::cout << mysql_error(con) << std::endl;
exit(1);
}
}
the issue is that I am unable to to use the create user function, but all of the other functions reading from the database work perfectly fine, so my question is why am i unable to use an insert statment in the program but am able to read from the database. It works on teh terminal whan i use mysql -u root -p to enter mysql on the terminal but when run it teh c++ code it does not work.

Creating temporary table while still accessing other tables

I've got 2 or more databases ATTACHed to one SQLite database connection. Each database consists of 3 tables. To have better access for searching/filtering, I create a huge temporary table over all tables and databases like this:
"CREATE TEMPORARY TABLE temp_table AS "
"SELECT * FROM pb.name_table "
"LEFT JOIN pb.phone_table ON (pb.name_table.id=pb.phone_table.id) " \
"LEFT JOIN pb.email_table ON (pb.name_table.id=pb.email_table.id) " \
"UNION SELECT * FROM name_table " \<br>
"LEFT JOIN phone_table ON (name_table.id=phone_table.id) " \
"LEFT JOIN email_table ON (name_table.id=email_table.id);";
If something changes in a table, I have to recreate the temporary table. With an increasing amount of data, creating a temporary table takes some time, but since I'm having continuous read access to the table, my idea was as follows:
Create a thread, which creates a second temp table in background
Block access for the reading clients
DROP first temp table
Rename the second temp table
The problem is now: Creating a temporary table is a write access to the database, which blocks automatically all reading threads also.
Has anyone a good idea how I can handle this? I need read access while recreating the temporary table.
As long as all threads are part of the same program, you have control over all database connections.
So you can write the data in a completely separate database, and ATTACH is quickly later.
Thanks a lot for your answer. I changed my code and found out that I need a new database connection (sqlite3_open) in the working thread not to block the other thread. Also creating a TEMPORARY TABLE in the attached "temporary database" was not possible, because creating a temporary table doesn't allow a qualifier (like: x.temp_table), so I had to create a real table which consumes a lot of memory in our flash file system (which is not allowed).
But wait! I've got an idea
(2 hours later)
I did it! I open an empty database and attach alll relevant databases to the connection. I create a temporary table "in" the empty database which consumes no memory in flash, because it's temporary.
When I have to create a new table, I open another empty database and attach the relevant databases to the connection. When the operation is finished, I switch the old and the new connection. Code as follows:
#include <iostream>
#include "dbAccess.h"
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
bool inProgress = true;
DWORD WINAPI createTempTableThread(void *param);
int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
cout << "*";
return 0;
}
int main(void)
{
sqlite3* db = NULL;
HANDLE hThreadHandle = NULL;
CdbAccess *dba = new CdbAccess();
int i = 0;
db = dba->dbaConnect();
dba->dbaSetDatabase(db);
cout << "INFO: Creating initial temporary table. " << endl;
sqlite3_exec(dba->dbaGetDatabase(), "CREATE TEMPORARY TABLE temp_table AS " \
"SELECT * FROM pb.name_table " \
"LEFT JOIN pb.phone_table ON (pb.name_table.id=pb.phone_table.id) " \
"LEFT JOIN pb.email_table ON (pb.name_table.id=pb.email_table.id) " \
"UNION SELECT * FROM intern.name_table " \
"LEFT JOIN intern.phone_table ON (intern.name_table.id=intern.phone_table.id) " \
"LEFT JOIN intern.email_table ON (intern.name_table.id=email_intern.table.id);", NULL, NULL, NULL);
cout << "INFO: Creating initial temporary table finished. " << endl;
while(1)
{
hThreadHandle = CreateThread(0, 0, createTempTableThread, dba, 0, 0);
while(inProgress)
{
sqlite3_exec(dba->dbaGetDatabase(), "SELECT * FROM name_table WHERE id LIKE 1;", callback, NULL, NULL);
}
for(i = 0; i < 5; i++)
{
sqlite3_exec(dba->dbaGetDatabase(), "SELECT * FROM name_table WHERE id LIKE 2;", callback, NULL, NULL);
}
inProgress = true;
CloseHandle(hThreadHandle);
}
dba->dbaDisconnect();
return 0;
}
CdbAccess::CdbAccess()
{
hSemaphore = CreateSemaphore(NULL, 1, 1, 0);
}
CdbAccess::~CdbAccess()
{
}
sqlite3 *CdbAccess::dbaConnect()
{
sqlite3 *db;
static int num = 1;
int err = SQLITE_OK;
string attach = "ATTACH DATABASE \"";
string internal = "cbInternal.db";
if(num == 1)
{
cout << endl << "INFO: cbTemp1.db";
err = sqlite3_open("cbTemp1.db", &db);
num = 2;
}
else
{
cout << endl << "INFO: cbTemp2.db";
err = sqlite3_open("cbTemp2.db", &db);
num = 1;
}
if(err == SQLITE_OK)
{
cout << endl << "INFO: Temp database opened.";
err = sqlite3_exec(db, "ATTACH DATABASE \"cbInternal.db\" AS intern;", NULL, NULL, NULL);
if(err == SQLITE_OK)
{
cout << endl << "INFO: Internal database attached.";
err = sqlite3_exec(db, "ATTACH DATABASE \"0123456789.db\" AS pb;", NULL, NULL, NULL);
if(err == SQLITE_OK)
{
cout << endl << "INFO: Phone book attached.";
}
else
{
cout << endl << "ERROR: Attaching phone book: " << sqlite3_errmsg(db);
}
}
else
{
cout << endl << "ERROR: Attaching internal database: " << sqlite3_errmsg(db);
}
}
else
{
cout << endl << "ERROR: Opening database: " << sqlite3_errmsg(db);
}
return db;
}
int CdbAccess::dbaDisconnect(void)
{
int err = SQLITE_OK;
err = sqlite3_exec(db, "DETACH DATABASE pb;", NULL, NULL, NULL);
if(err == SQLITE_OK)
{
cout << endl << "INFO: Phone book detached.";
err = sqlite3_exec(db, "DETACH DATABASE intern;", NULL, NULL, NULL);
if(err == SQLITE_OK)
{
cout << endl << "INFO: Internal database detached.";
err = sqlite3_close(db);
if(err == SQLITE_OK)
{
cout << endl << "INFO: Database connection closed.";
}
else
{
cout << endl << "ERROR: Could not close database: " << sqlite3_errmsg(db);
}
}
else
{
cout << endl << "ERROR: Could not detach internal database: " << sqlite3_errmsg(db);
}
}
else
{
cout << endl << "ERROR: Could not detach phone book: " << sqlite3_errmsg(db);
}
return err;
}
sqlite3* CdbAccess::dbaGetDatabase(void)
{
return db;
}
void CdbAccess::dbaSetDatabase(sqlite3 * sqldb)
{
db = sqldb;
}
int CdbAccess::dbaGetTempTableAccess(void)
{
cout << endl << "INFO: Access requested.";
WaitForSingleObject(hSemaphore, INFINITE);
return 0;
}
int CdbAccess::dbaReleaseTempTableAccess(void)
{
cout << endl << "INFO: Access released.";
ReleaseSemaphore(hSemaphore, 1, NULL);
return 0;
}
DWORD WINAPI createTempTableThread(void *param)
{
int err = SQLITE_OK;
CdbAccess *d = (CdbAccess *)param;
sqlite3 *db;
cout << endl << "INFO: createTempTable: IN";
inProgress = true; // global variable for test porpose only
db = d->dbaConnect();
if(db != NULL)
{
cout << endl << "Thread: INFO: Creating temporary table. ";
err = sqlite3_exec(db, "CREATE TEMPORARY TABLE temp_table AS " \
"SELECT * FROM pb.name_table " \
"LEFT JOIN pb.phone_table ON (pb.name_table.id=pb.phone_table.id) " \
"LEFT JOIN pb.email_table ON (pb.name_table.id=pb.email_table.id) " \
"UNION SELECT * FROM intern.name_table " \
"LEFT JOIN intern.phone_table ON (intern.name_table.id=intern.phone_table.id) " \
"LEFT JOIN intern.email_table ON (intern.name_table.id=intern.email_table.id);", NULL, NULL, NULL);
}
if(err != SQLITE_OK)
{
cout << endl << "Thread: ERROR: Creating temporary table: " << sqlite3_errmsg(db);
}
else
{
cout << endl << "Thread: INFO: Creating temporary table finished. ";
}
d->dbaSetDatabase(db);
inProgress = false; // global variable for test porpose only
cout << endl << "Thread: INFO: createTempTable: OUT";
return 0;
}

SQLite, SELECT and max function

Why does the following code gives me the different result when using max function? I thought that it should return SQLITE_DONE in this case too.
#include <boost/scope_exit.hpp>
#include <sqlite3.h>
#include <cstdlib>
#include <iostream>
int main()
{
sqlite3* db;
int rc = sqlite3_open(":memory:", &db);
BOOST_SCOPE_EXIT_ALL(&db)
{
sqlite3_close(db);
};
if (rc != SQLITE_OK)
{
std::cerr << "Can't open database."
<< " Error code: " << rc
<< " Error description: " << sqlite3_errmsg(db);
return EXIT_FAILURE;
}
char* errMsg;
rc = sqlite3_exec(db, "CREATE TABLE foo (bar INTEGER)", NULL, NULL, &errMsg);
if (rc != SQLITE_OK)
{
std::cerr << "Can't create \"foo\" table."
<< " Error code: " << rc
<< " Error description: " << errMsg;
sqlite3_free(errMsg);
return EXIT_FAILURE;
}
{
sqlite3_stmt* stmt;
rc = sqlite3_prepare_v2(db, "SELECT bar FROM foo WHERE bar = 1", -1, &stmt, NULL);
if (rc != SQLITE_OK)
{
std::cerr << "Can't prepare SELECT statement."
<< " Error code: " << rc
<< " Error description: " << sqlite3_errmsg(db);
return EXIT_FAILURE;
}
BOOST_SCOPE_EXIT_ALL(&stmt)
{
sqlite3_finalize(stmt);
};
rc = sqlite3_step(stmt);
std::cout << rc << std::endl; // 101 -- SQLITE_DONE
}
{
sqlite3_stmt* stmt;
rc = sqlite3_prepare_v2(db, "SELECT max(bar) FROM foo WHERE bar = 1", -1, &stmt, NULL);
if (rc != SQLITE_OK)
{
std::cerr << "Can't prepare SELECT statement."
<< " Error code: " << rc
<< " Error description: " << sqlite3_errmsg(db);
return EXIT_FAILURE;
}
BOOST_SCOPE_EXIT_ALL(&stmt)
{
sqlite3_finalize(stmt);
};
rc = sqlite3_step(stmt);
std::cout << rc << std::endl; // 100 -- SQLITE_ROW
}
}
Thanks in advance.
When you are using GROUP BY, you get one group for each unique value of the grouped column(s).
If there does not exist any row to be grouped, there are no groups, and the query does not return any rows.
When you are using an aggregate function like max() without GROUP BY, the entire table becomes a single group.
This happens even if the table is empty, i.e., you then get a single group that aggregates over the empty set.
If you don't want to get a result when there are not bar = 1 rows, add GROUP BY bar.

why mysql_commit is so slow?

I'm a new one used MYSQL.
The codes is:
void gdns_mysql::commit_task()
{
if (mysql_commit(conn) != 0)
{
throw_trackerr_str(boost::format("MysqlCommitError %d %s") % mysql_errno(conn) % mysql_error(conn));
}
}
This function commit_task is always spending 6~7 seconds.
I want to know why this happen ?
please list some reasons. Thank you
By the way:
The queries is like:
void gdns_mysql::update_server_status(std::string const& server_, std::string const& status_)
{
stringstream sql;
sql << "update server";
if (!status_.empty()) sql << " set status = '" << get_escape_string(status_) << "'";
else sql <<" set status = status_predict";
sql << " where serverip = '" << get_escape_string(server_) << "'"
<< endl;
execute(sql.str());
}
And
zone_ptrs_t gdns_mysql::query_zone_bykey(std::string const& zonename_)
{
string statement = "select * from zone";
bool where_flag = false;
if (!zonename_.empty())
{
statement += " where zonename = '" + get_escape_string(zonename_) + "'";
where_flag = true;
}
select(statement);
return fetch_datas<zone_t>();
}