Simple C++ connection to mysql database - c++

I just started with c++, after reading some tutorials I'm trying to create a simple myqsl connection with a database. Keep in mind that I'm mainly a web developer hence this is a new thing for me. My current code (taken from a tutorial) is this:
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
//#include <string>
using namespace std;
struct connection_details
{
char *server;
char *user;
char *password;
char *database;
};
MYSQL* mysql_connection_setup(struct connection_details mysql_details) {
MYSQL *connection = mysql_init(NULL);
if (!mysql_real_connect(connection,mysql_details.server, mysql_details.user, mysql_details.password, mysql_details.database, 0, NULL, 0)) {
printf("Conection error : %s\n", mysql_error(connection));
exit(1);
}
return connection;
}
MYSQL_RES* mysql_perform_query(MYSQL *connection, char *sql_query) {
if (mysql_query(connection, sql_query)) {
printf("MySQL query error : %s\n", mysql_error(connection));
exit(1);
}
return mysql_use_result(connection);
}
int main() {
MYSQL *conn; // the connection
MYSQL_RES *res; // the results
MYSQL_ROW row; // the results row (line by line)
struct connection_details mysqlD;
mysqlD.server = "localhost"; // line 46
mysqlD.user = "root"; // line 47
mysqlD.password = "root"; // line 48
mysqlD.database = "backseat"; // line 49
conn = mysql_connection_setup(mysqlD);
res = mysql_perform_query(conn, "show tables"); // line 53
printf("MySQL Tables in mysql database:\n");
while ((row = mysql_fetch_row(res)) !=NULL)
printf("%s\n", row[0]);
mysql_free_result(res);
mysql_close(conn);
return 0;
}
however g++ gives me the followign warning:
main.cpp:46:19: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
main.cpp:47:17: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
main.cpp:48:21: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
main.cpp:49:21: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
main.cpp:53:48: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Which is beyond my understanding at the time being, although the program works.
What I did in order to remove the warning was the following:
char s[] = "localhost";
char u[] = "root";
char p[] = "root";
char d[] = "backseat";
and then
mysqlD.server = s;
mysqlD.user = u;
mysqlD.password = p;
mysqlD.database = d;
That took care of the warning but I assume there must be a better way & explanation on how I should take care of this.
Moreover I tried to use:
struct connection_details
{
string *server;
string *user;
string *password;
string *database;
};
But that didn't take care the warning on line 53 plus all hell broke loose after doing this.
My question is how should I be approaching simple mysql connection, why did those warnings came up and was it a bad idea to use strings in the struct?
I'm sorry for the long post, but I'm on a learning curve here and there a lot of things to take in.
PS: Any good tutorials / guides will be appreciated. Thank you.

You're missing some basics. I don't know about good tutorials to link to, but I'll explain what you're doing wrong:
First of all, when you're writing C++, you should use string rather than char*. You should read up the details of char*; it's a pointer and handling it is therefore significantly different from handling a string.
What happens in your code is that you assign the address of a string literal like "localhost" to a char* (because it's a pointer). The problem is, gcc converts string literals to constants, which are read-only (as the warning tells you). The type char* however implies that the contents of the string can be changed. Change the type to const char* to get rid of the warning.
Here's some code to illustrate the issue:
char* a;
const char* b;
a = "foo";
b = "bar";
a[0] = 'a'; // you're changing the constant string!
b[0] = 'b'; // compiler error; b is const
a = "foz"; // both allowed because you're not changing
b = "baz"; // the string, but only the pointer
The easier option is to use string:
struct connection_details
{
string server;
string user;
string password;
string database;
}
You shouldn't use pointers here. string manages the low-level memory stuff internally. Now the problem is that you're using the C-level MySQL binding, which expects char* rather than string. To call it when you're using strings in your code, use c_str() for conversion:
connection.server.c_str()
and so on.
Alternatively, you might want to use a higher-level C++ API to connect to MySQL. If you're learning C++, you'll be better off avoiding C APIs if possible. There is, for example, MySQL++, but I don't know it and therefore cannot recommend it. A higher-level API is provided by SOCI, which works with multiple database backends (including MySQL).

Related

C++: handle sql-String in UTF32

I'm writing a program, that reads a UTF32 encoded string from a MySQL-Database and should write it to a file/cout. The Problem is, that as long as I just use letters and so on, it works, but as soon as I take a emojicon it just writes a "?". I tried:
1. Change the locale (with std::setlocale(LC_ALL, "en_EN.UTF-32");)
2. Use wstringsbut gives an eror like that: Can't convert sql::String to wstring...
Any suggestions how to do this?
I use the following (shortened) code:
int main(int argc, char **argv){
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
driver = get_driver_instance();
con = driver->connect(IP, USER, Password);
con->setSchema(DBNAME);
stmt = con->createStatement();
res= stmt->executeQuery("Select * from messages");
std::string tmp;
while (res->next()) {
tmp = res->getString(7);
std::cout << tmp;
}
}
The MySQL-Field is created with the following (shortened) command:
std::string msgs = "CREATE TABLE if not Exists `"+dbnam+e"`.`messages` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
`message` LONGTEXT CHARACTER SET utf32 COLLATE utf32_bin NOT NULL ,
UNIQUE (`id`)) ENGINE = InnoDB;;
stmt->execute(msgs);"
Thanks for your help in advance.

C - Extern struct

I'm using structure to process NMEA messages, but I don't know what, something goes wrong when processing it. So, I have NMEA_parse.h:
/* GPRMC */
#define TIME 2U
#define LAT 4U
#define LON 6U
#define SPD 8U
#define ANG 9U
#define DATE 10U
extern struct gprmc{
char time[10];
char latitude[10];
char longitude[10];
char speed[10];
char angle[10];
char date[10];
}gprmc_datas;
NMEA_parse.c:
#include "NMEA_parse.h"
struct gprmc gprmc_datas;
static void fill_data (char* param_in)
{
uint8_t i = 0U;
char* trunk;
char trunk_datas[20U][10U];
trunk = strtok(param_in, ",");
while(trunk != NULL)
{
i++;
if(i > 20) { i = 0; }
strcpy(trunk_datas[i],trunk);
trunk = strtok (NULL, ",");
}
if(memcmp(trunk_datas[1U],"GPRMC",6U) == 0U)
{
strcpy(gprmc_datas.time,trunk_datas[TIME]);
strcpy(gprmc_datas.latitude,trunk_datas[LAT]);
strcpy(gprmc_datas.longitude,trunk_datas[LON]);
strcpy(gprmc_datas.date,trunk_datas[DATE]);
strcpy(gprmc_datas.time,trunk_datas[TIME]);
}
}
main.c:
#include <stdio.h>
#include "NMEA_parse.h"
int main(void)
{
char *message = "$GPRMC,182127.00,A,4753.47678,N,02022.20259,E,0.837,,161019,,,A*7C\r\n";
char *mes = "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A";
proc_sentence(message);
printf("\ntime: %s\n", gprmc_datas.time);
printf("latitude: %s\n", gprmc_datas.latitude);
printf("longitude: %s\n", gprmc_datas.longitude);
}
proc_sentence function pass the data to fill_data(), if the message valid (checksum, etc)
When I'm using the mes as input, everything is correct, but when I switch to message, some abnormality is shown, because the result is the following:
time: 182127.00
latitude: 4753.4767802022.2025E
longitude: 02022.2025E
Do you have any idea what goes wrong?
If you change latitude[10] in the struct into latitude [12], the string "message" can also be used.
Unlike almost every other SO question about the use of scanf, yours is actually a problem that cries out for it. After all, if a machine wrote it, a machine can read it, right?
Using C's concatenation of string literals, I got pretty close to filling the struct with a single function:
int n = sscanf( message,
"%[^,],"
"%[^,],"
"%*[^,],%[^,],"
"%*[^,],%[^,],"
"%*[^,],%[^,],"
"%[^,],"
"%[^,],",
label,
gprmc.time,
gprmc.latitude,
gprmc.longitude,
gprmc.speed,
gprmc.angle,
gprmc.date );
This makes use of the little-used regex specifier, where we look for non-commas %[^] separated by commas. The %*[^] specifies to skip the field.

smtp auth via boost and c++

i am writing an cpp smtp client using boost 1.67.
When i try to send log in data, the server returns auth error, but when i try it by hand via telnet it works.
Here is my code:
sktSocket.write_some(boost::asio::buffer("AUTH LOGIN\r\n"));
size_t lenTemp = sktSocket.read_some(boost::asio::buffer(chTemp),error);
showResponse(chTemp.data(), lenTemp);
std::string strUse = boost::beast::detail::base64_encode(srvTest.strUser);
sktSocket.write_some(boost::asio::buffer(strUse));
sktSocket.write_some(boost::asio::buffer("\r\n"));
showText(strUse);
lenTemp = sktSocket.read_some(boost::asio::buffer(chTemp), error);
showResponse(chTemp.data(), lenTemp);
std::string strPass = boost::beast::detail::base64_encode(srvTest.strPasswd);
sktSocket.write_some(boost::asio::buffer(strPass));
sktSocket.write_some(boost::asio::buffer("\r\n"));
showText(strPass);
size_t lenLogin = sktSocket.read_some(boost::asio::buffer(chLogin), error);
showResponse(chLogin.data(), lenLogin);
When i run this code i got the response:
535 Inncorrect authentication data
I dont really know what i am doing wrong...
Thanks in advance
edit------------
now i am using an own implementation for encoding to base64 and it also returns the correct encoded string as beast, but the server respoonse with 535 as before
unsigned int paddedCharacters = 0;
while (data.size() % 3 != 0)
{
paddedCharacters++;
data.push_back(0x00);
}
// Crazy typedef black magic
typedef insert_linebreaks<base64_from_binary<transform_width<const unsigned char *, 6, 8>>, 76> base64Iterator;
std::string encodedString(
base64Iterator(data.c_str()),
base64Iterator(data.c_str() + (data.size() - paddedCharacters)));
// Add '=' for each padded character used
for (unsigned int i = 0; i < paddedCharacters; i++)
{
encodedString.push_back('=');
}
return encodedString;
You shouldn't be using boost::beast::detail::base64_encode, because that is not a public interface. Anything in a detail namespace is an implementation detail which should not be used directly. And in fact I believe there is a bug in it. Try using a different base64 encoding function.

Cannot add TCHAR* to const char

Hello I'm trying to make my application to run on startup, and to do this to work on my clients PC firstly I needed to get their PC username, but when I'm trying to make this working I'm getting this error :
E2140 expression must have integral or unscoped enum type
Here's the code:
HKEY hKey;
const char* czStartName = "MY application";
TCHAR pcusername[UNLEN + 1];
DWORD pcusername_len = UNLEN + 1;
GetUserName((TCHAR*)pcusername, &pcusername_len);
const char* czExePath = "\"C:\\Users\\" + pcusername + "\\Desktop\\Myapplication.exe\" /background";
How Can I convert TCHAR* to Const Char?
As others have said in the comments, you cannot concatenate strings in C using the addition operator. You can do something like in this example:
#include <string.h>
char buf[4096];
snprintf(buf, sizeof(buf), "\"C:\\Users\\%s\\Desktop\\Myapplication.exe\" /background", username);
const char* czExePath = buf;

Process utf-8 data from MySQL in C++ and give result back

I just simply want to know - how to get MySQL results to C++ in string (or another similar "string" datatype) in a way that would not deform data saved in utf8_unicode_ci.
After C++ process, app should write results back (to another table) into the database where argument is encoded in utf8_unicode_ci as well.
I read somewhere that using wide char is not recommended by Unicode consortium, but my problem is still that a second argument for mysql_query() is string which is not wide enough.
I've already tried some "utf8 string" solutions, but unsuccessfully. I also tried to save data in common string and than write it into the database in the same way (byte after byte), but it doesn't work properly at all... (see my code below)
DATABASE:
save_text: text = ěščřžýáíé
AFTER PROCESS: save_newtext: text = ?š??žýáíé
#include <iostream>
#include <mysql.h>
#include <string>
#define ... // server conection
using namespace std;
MYSQL *connection, mysql;
MYSQL_RES *result;
MYSQL_ROW row;
int query_state;
int main(int argc, char** argv)
{
mysql_init(&mysql);
mysql_real_connect(&mysql,CTH_SERVER,CTH_USER,CTH_PASSWORD,CTH_DB_IN,0,0,0));
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "utf8");
mysql_options(&mysql, MYSQL_INIT_COMMAND, "SET NAMES utf8");
mysql_query(connection, "SELECT text FROM save_text WHERE id = 23");
result = mysql_store_result(connection);
if ((row = mysql_fetch_row(result)) != NULL) {
string sql;
sql = "INSERT INTO save_newtext (text) VALUES ('";
sql += row[0];
sql += "')";
mysql_query(connection, sql.c_str());
}
return 0;
}
Thanks in advance!!
From MySQL Reference
mysql_options() should be called after mysql_init() and before
mysql_connect() or mysql_real_connect().
So your code should be
mysql_init(&mysql);
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "utf8");
mysql_options(&mysql, MYSQL_INIT_COMMAND, "SET NAMES utf8");
mysql_real_connect(&mysql,CTH_SERVER,CTH_USER,CTH_PASSWORD,CTH_DB_IN,0,0,0));