I have a function:
int main()
{
MySQL::Connect("127.0.0.1", 3306, "root", "", "player");
MySQL::ExecuteQuery("select * from player");
while (row = mysql_fetch_row(res))
{
std::cout << row[2] << "\n";
MySQL::SetDatabase("account");
MySQL::ExecuteQuery("select * from account"); // This function causes a problem.
// while (row = mysql_fetch_row(res))
// break;
}
return 0;
}
Which should get everything of player names from player table what it does and what it display in console (I'm posting a screenshot of table in Navicat):
https://i.stack.imgur.com/n6HJQ.png
However, when MySQL::ExecuteQuery("select * from account"); function is used which selects everything in account table, the earlier std::cout display only one player name instead of two:
https://i.stack.imgur.com/q9ZkP.png
What can I do in this situation? Or is there another simple way to connect to MySQL in C++? Please help.
I attach files such as MySQL_Func.cpp and MySQL_Func.h which include problematic function:
.cpp:
#include "MySQL_Func.h"
#include "../Log.hpp"
MYSQL* conn;
MYSQL_ROW row;
MYSQL_RES* res;
std::string conf_ip;
unsigned int conf_port;
std::string conf_db;
std::string conf_login;
std::string conf_password;
std::string error = mysql_error(conn);
int err = 0;
namespace MySQL
{
void Connect(std::string ip, unsigned int port, std::string login, std::string password, std::string db)
{
conf_ip = ip;
conf_port = port;
conf_login = login;
conf_password = password;
conf_db = db;
if (conn != 0)
{
SendLog(0, "MySQL has been restared.");
mysql_close(conn);
}
conn = mysql_init(0);
if (!mysql_real_connect(conn, ip.c_str(), login.c_str(), password.c_str(), db.c_str(), port, NULL, 0))
{
error = mysql_error(conn);
SendLog(1, "Connection with database was failed: " + error + ".");
exit(1);
}
else
{
SendLog(0, "Successfully connected with database!");
}
}
void ExecuteQuery(std::string query)
{
err = mysql_query(conn, query.c_str());
res = mysql_store_result(conn);
if (res != 0) // Protection against NullPointer.
{
int total_rows = mysql_num_fields(res);
if (total_rows != 0) // If total rows isn't 0.
{
if (err)
{
error = mysql_error(conn);
SendLog(1, "Query execute failed:" + error + ".");
mysql_free_result(res);
exit(1);
}
else
{
SendLog(0, "Query has been sent (" + query + ")!");
}
}
else
{
SendLog(1, "Query has been sent: (" + query + ") but its value is 0.");
exit(0);
}
}
else
{
exit(1);
}
}
void SetDatabase(std::string current_db)
{
if (current_db != conf_db) // If current_db isn't conf_db.
MySQL::Connect(conf_ip, conf_port, conf_login, conf_password, current_db);
}
}
.h:
#pragma once
#include <iostream>
#include <mysql.h>
#include <string>
extern MYSQL* conn;
extern MYSQL_ROW row;
extern MYSQL_RES* res;
extern std::string conf_ip;
extern unsigned int conf_port;
extern std::string conf_db;
extern std::string conf_login;
extern std::string conf_password;
namespace MySQL
{
void Connect(std::string ip, unsigned int port, std::string login, std::string password, std::string db);
void ExecuteQuery(std::string query);
void SetDatabase(std::string database);
}
Your two calls to ExecuteQuery share state, namely the "currently active query" and the buffered resultset you downloaded with mysql_result_row.
This is called a non-reentrant function.
Some options:
have a dedicated connection for each query
Do a single query that somehow combines the results (ie JOIN the players and accounts table)
Fetch all the players first into a dedicated datastructure (eg std::vector or std::map), then do the query for accounts later.
Related
I've been making program that need to continuously insert data to a database. I'm new to C++.
I'm using xampp for my database. I want to make insert loop inside one of my function.
my code looks like this
#include "stdio.h"
#include "fstream"
#include "iostream"
#include "mysql.h"
#include "sstream"
void loop();
void print();
int i;
const char* hostname = "localhost";
const char* username = "root";
const char* password = "";
const char* database = "testinsertdb";
unsigned int port = 3306;
const char* unixsocket = NULL;
unsigned long clientflag = 0;
insertion(){
MYSQL* conn;
conn = mysql_init(0);
conn = mysql_real_connect(conn, hostname, username, password, database, port, unixsocket, clientflag);
int qstate=0;
using namespace std;
stringstream ss;
ss << " INSERT INTO test (number) values ('" <<i<<"')";
string query = ss.str ();
const char * q = query.c_str();
qstate = mysql_query(conn, q);
if (qstate == 0)
{
cout <<" Record inserted successfully ..."<<endl;
}
else
{
cout <<" Error, data not inserted..."<<endl;
}
}
int main()
{
print();
return 0;
}
void print()
{
for (int j = 0; j < 1000000; j++) {
loop();
}
}
void loop()
{
i=1;
insertion();
}
When I run the program, I managed to insert some data to the database, but after several seconds the program stopped with code -10737741819 (0xC0000005). On my build log Process the terminated with status -1073741510
How can i solve this?
Preferablly try this one.
Your code is trying to connect database as many times as the loop proceeds.
There is the description of that error from this link
#include "stdio.h"
#include "fstream"
#include "iostream"
#include "mysql.h"
#include "sstream"
void loop();
void print();
MYSQL* conn;
const char* hostname = "localhost";
const char* username = "root";
const char* password = "";
const char* database = "testinsertdb";
unsigned int port = 3306;
const char* unixsocket = NULL;
unsigned long clientflag = 0;
void insertion() {
int qstate=0, i;
using namespace std;
stringstream ss;
ss << " INSERT INTO test (number) values ('" <<i<<"')";
string query = ss.str ();
const char * q = query.c_str();
qstate = mysql_query(conn, q);
if (qstate == 0)
{
cout <<" Record inserted successfully ..."<<endl;
}
else
{
cout <<" Error, data not inserted..."<<endl;
}
}
int main()
{
print();
return 0;
}
void print()
{
conn = mysql_init(0);
conn = mysql_real_connect(conn, hostname, username, password, database, port, unixsocket, clientflag);
for (int j = 0; j < 1000000; j++) {
loop();
mysql_close(conn);
}
void loop()
{
i=1;
insertion();
}
I wrote a server using cpp to connect mysql with libmysqlclient.a, codes are like this:
#ifndef __IVC_MYSQLAPI_H__
#define __IVC_MYSQLAPI_H__
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <mysql.h>
#include <string.h>
#include <vector>
using namespace std;
class ConnMysql {
public:
ConnMysql();
~ConnMysql();
int connInit(const char* host,int port,const char* user,const char* password,const char* database);
int executeSql(const char* sql, std::vector<std::string> &v);
void close();
private:
MYSQL *sock;
MYSQL *my_sql;
};
ConnMysql::ConnMysql(){
}
ConnMysql::~ConnMysql(){
}
int ConnMysql::connInit(const char* host,int port,const char* user,const char* password,const char* database){
my_sql = mysql_init(NULL);
if (my_sql == NULL) {
fprintf(stderr, "Init failed\n");
return -1;
}
sock = mysql_real_connect(my_sql, host,
user, password, database, port, NULL, CLIENT_MULTI_STATEMENTS);
if (sock < 0) {
return -1;
}
}
int ConnMysql::executeSql(const char* sql, std::vector<std::string> &v) {
mysql_query(sock, sql);
MYSQL_RES *res_ptr;
res_ptr = mysql_store_result(sock);
if(res_ptr == nullptr) {
printf("Get data from mysql failed\n");
return -1;
}
MYSQL_ROW sqlrow;
int j = mysql_num_fields(res_ptr);
while((sqlrow = mysql_fetch_row(res_ptr))) {
v.push_back(std::string(sqlrow[0]));
}
return 0;
}
void ConnMysql::close() {
mysql_close(sock);
sock=NULL;
my_sql = NULL;
}
#endif //__IVC_MYSQLAPI_H__
The method called like this:
ConnMysql connsql = ConnMysql{};
fprintf(stderr, "begin to init\n");
if (connsql.connInit(ip, port, username, pwd, database) < 0) {
fprintf(stderr, "mysql init return failed\n");
return -1;
}
std::string sql = "select env_code from env_codes where env_type = 1";
connsql.executeSql(sql.c_str(), v);
for (int len=0; len < v.size(); len++) {
fprintf(stderr, "get: %s\n", v[len].c_str());
}
connsql.close();
I will get error suchInit failed occasionally, not always. My questions are
Is there any wrong with my codes? Forget to release something?
How can get the reason why mysql init failed?
I changed mysql_real_connect like this
if(mysql_real_connect(my_sql, host,
user, password, database, port, NULL, CLIENT_MULTI_STATEMENTS) == NULL)
{
return -1;
}
and delete MYSQL *sock parameter, and changed sock to my_sql, such as mysql_query(sock, sql) to mysql_query(my_sql, sql). It seems workable.
#include <iostream>
#include <windows.h>
#include <mysql.h> //header mysql
#include <sstream> //merubah semua tipe data yang diinputkan user ke string
#include <regex>
using namespace std;
int main()
{
string data, hadis, hadis1, hadis2;
const char *hadiss;
int itung = 0;
MYSQL* conn; //for connection handler
MYSQL_ROW row; //return data as array of strings
MYSQL_RES* res; //hold the result set
int num_fields; //to get the number of array
conn = mysql_init(0); //initialaize connection handler. dont change!
conn = mysql_real_connect(conn, "192.168.43.205", "ibrahim", "hadis", "dbdb", 0, NULL, 0);
if(conn)
{
int qstate = mysql_query(conn, "SELECT Isi_Indonesia FROM malik");
if(!qstate)
{
res = mysql_store_result(conn);
num_fields = mysql_num_fields(res);
while (row = mysql_fetch_row(res))
{
data = row[0];
regex reg("[^\\w]+");
data = regex_replace(data, reg, " ");
//cout << data <<"\n\n";
istringstream stm(data) ;
while( stm >> hadis ) // read white-space delimited tokens one by one
{
for(int i = 0; i < num_fields; i++)
{
hadiss = hadis.c_str();
cout << hadiss << endl;
if(hadiss != NULL)
{
hadis1 = hadiss;
string query1 = "SELECT kata FROM totalkata_malik2 WHERE kata='"+hadis1+"'";
mysql_query(conn, query1.c_str());
res = mysql_store_result(conn);
while ((row = mysql_fetch_row(res)))
{
if (row[0] == NULL)
{
string query2 = "INSERT INTO totalkata_malik2(kata,total) VALUES ('"+hadis1+"',1)";
mysql_query(conn, query2.c_str());
itung++;
}
else
{
string query3 = "UPDATE totalkata_malik2 SET total=total+1 where kata='"+hadis1+"'";
mysql_query(conn, query3.c_str());
}
}
}
else
{
//
}
}
}
}
cout<< "\n\nJumlah kata = "<<itung++<<"\n\n";
}
}
return 0;
}
this is my c++ code and i got no warning when i was running this program but the result is not like what i want, the result that i hope look like this:
but my result did not insert or update anything in mysql databse, therefore mysql database was empty.
but if i deleted "select kata query till row part " my insert into query code could insert the word to "kata field" at database but the code didnt update the "total field" properly
#include <iostream>
#include "libpq-fe.h"
using namespace std;
void CloseConn(PGconn *conn)
{
PQfinish(conn);
getchar();
}
PGconn *ConnectDB()
{
PGconn *conn = NULL;
// Make a connection to the database
conn = PQconnectdb("user=postgres password=password dbname=postgres hostaddr=192.168.xxx.xxx port=5432");
// Check to see that the backend connection was successfully made
if (PQstatus(conn) != CONNECTION_OK)
{
cout << "Connection to database failed.\n";
CloseConn(conn);
}
cout << "Connection to database - OK\n";
return conn;
}
void InsertEmployeeRec(PGconn *conn)
{
int nFields;
// Append the SQL statment
std::string sSQL;
// problem start-------------------------
for(int i=0;i<10;i++)
{
sSQL.append("INSERT INTO test(lat,lng) VALUES (i,20)");
}
//problem end----------------------------
// Execute with sql statement
PGresult *res = PQexec(conn, sSQL.c_str());
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
cout << "Insert test record failed\n";
PQclear(res);
CloseConn(conn);
}
cout << "Insert test record - OK";
// Clear result
PQclear(res);
}
int main(int argc, char *argv[ ])
{
PGconn *conn = NULL;
conn = ConnectDB();
if (conn != NULL)
{
InsertEmployeeRec(conn);
CloseConn(conn);
}
return 0;
}
and in terminal
alan#alan-virtual-machine:~/文件$ g++ ex6.cpp -I /usr/include/postgresql -l pq -o ex6
alan#alan-virtual-machine:~/文件$ ./ex6
Connection to database - OK
Insert test record failed
*** Error in `./ex6': corrupted double-linked list: 0x08eadad0 ***
But if I remove for loop and modify
INSERT INTO test(lat,lng) VALUES (i,20)
to
INSERT INTO test(lat,lng) VALUES (20,20)
it can work.
Linux Ubuntu 13.04 g++ compiler
I refer to http://www.askyb.com/cpp/c-postgresql-example/
The problem resides in the fact that 'i' is not been evaluated inside the string. To solve that, you can create the string with correct value and send it to the insert command.
for(int i=0;i<10;i++)
{
char buffer[256];
snprintf(buffer, 256, "INSERT INTO test(lat,lng) VALUES (%d,20)", i);
sSQL.append(buffer);
}
Of course, you need to adjust your buffer adequately
The problem is that you're not sending i. It looks like PQexecParams is the function you want:
PGresult *PQexecParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
I decided to use SQLite as it allows to store database into a single file. I think I have managed to do a database with SQLite Database Browser.
How can I read that data in a C/C++ program?
A example using sqlite read:
#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
int main(int argc, char** argv)
{
const char* username = "satyam";
char q[999];
sqlite3* db;
sqlite3_stmt* stmt;
int row = 0;
int bytes;
const unsigned char* text;
if (2 == argc) {
username = argv[1];
}
q[sizeof q - 1] = '\0';
snprintf(
q,
sizeof q - 1,
"SELECT ipaddr FROM items WHERE username = '%s'",
username
);
if (sqlite3_open ("test.db", &db) != SQLITE_OK) {
fprintf(stderr, "Error opening database.\n");
return 2;
}
printf("Query: %s\n", q);
sqlite3_prepare(db, q, sizeof q, &stmt, NULL);
bool done = false;
while (!done) {
printf("In select while\n");
switch (sqlite3_step (stmt)) {
case SQLITE_ROW:
bytes = sqlite3_column_bytes(stmt, 0);
text = sqlite3_column_text(stmt, 1);
printf ("count %d: %s (%d bytes)\n", row, text, bytes);
row++;
break;
case SQLITE_DONE:
done = true;
break;
default:
fprintf(stderr, "Failed.\n");
return 1;
}
}
sqlite3_finalize(stmt);
return 0;
}
How about the 'An Introduction to Sqlite C/C++ Interface', and there is a whole C++ example here on CodeProject.
This is bits of the more full sample,
#include "CppSQLite.h"
#include <ctime>
#include <iostream>
using namespace std;
const char* gszFile = "C:\\test.db";
int main(int argc, char** argv)
{
try
{
int i, fld;
time_t tmStart, tmEnd;
CppSQLiteDB db;
cout << "SQLite Version: " << db.SQLiteVersion() << endl;
db.open(gszFile);
cout << db.execScalar("select count(*) from emp;")
<< " rows in emp table in ";
db.Close();
}
catch (CppSQLiteException& e)
{
cerr << e.errorCode() << ":" << e.errorMessage() << endl;
}
}
One way to do it without additional wrappers
#include <stdio.h>
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
#include "sqlite3.h"
bool find_employee(int _id)
{
bool found = false;
sqlite3* db;
sqlite3_stmt* stmt;
stringstream ss;
// create sql statement string
// if _id is not 0, search for id, otherwise print all IDs
// this can also be achieved with the default sqlite3_bind* utilities
if(_id) { ss << "select * from employees where id = " << _id << ";"; }
else { ss << "select * from employees;"; }
string sql(ss.str());
//the resulting sql statement
printf("sql: %s\n", sql.c_str());
//get link to database object
if(sqlite3_open("data/test.db", &db) != SQLITE_OK) {
printf("ERROR: can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return found;
}
// compile sql statement to binary
if(sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL) != SQLITE_OK) {
printf("ERROR: while compiling sql: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
sqlite3_finalize(stmt);
return found;
}
// execute sql statement, and while there are rows returned, print ID
int ret_code = 0;
while((ret_code = sqlite3_step(stmt)) == SQLITE_ROW) {
printf("TEST: ID = %d\n", sqlite3_column_int(stmt, 0));
found = true;
}
if(ret_code != SQLITE_DONE) {
//this error handling could be done better, but it works
printf("ERROR: while performing sql: %s\n", sqlite3_errmsg(db));
printf("ret_code = %d\n", ret_code);
}
printf("entry %s\n", found ? "found" : "not found");
//release resources
sqlite3_finalize(stmt);
sqlite3_close(db);
return found;
}