C++: handle sql-String in UTF32 - c++

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.

Related

How does prepared statements in Sqlite C++ work

I do not know how to implement prepared statements in my Sqlite3 code
#include <iostream>
#include <sqlite3.h>
#include <stdio.h>
static int callback (void* NotUsed, int argc, char** argv, char** azColName) {
int i;
for (i = 0; i < argc; i++) {
std::cout << ("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
std::cout << ("\n");
return 0;
}
int main (int argc, char* argv[]) {
sqlite3* db;
char* zErrMsg = 0;
int rc;
char* sql;
/* Open database */
rc = sqlite3_open ("test.db", &db);
if (rc) {
std::cerr << "Can't open database: \n" << sqlite3_errmsg (db);
return (0);
}
else {
std::cout << "Opened database successfully\n";
}
std::string newName;
std::cin >> newName;
/* Create SQL statement */
sql = "UPDATE company SET name = newName WHERE id = 1";
/* Execute SQL statement */
rc = sqlite3_exec (db, sql, callback, 0, &zErrMsg);
if (rc != SQLITE_OK) {
std::cout << "SQL error: \n" << zErrMsg;
sqlite3_free (zErrMsg);
}
else {
std::cout << "Records created successfully\n";
}
sqlite3_close (db);
return 0;
}
The user has to input newName and this variable should be used to Update a field in the Database. This way it does not work, because the Sql script is searching for a column. In the internet I found, that I had to use a prepared statement, but I do not know how to implement it.
You start with an sql statement that has placeholders for the parameters that you wish to bind later. Here, I use a single question mark for the placeholder, but there are other options described in the documentation.
std::string sql = "UPDATE company SET name = ? WHERE id = 1";
Then you construct a prepared statement (or "compile", as they say it in sqlite documentation). You'll normally use sqlite_prepare_v2 function, but there are others (for when your statement is encoded in something else than utf-8, for example).
sqlite3_stmt* stmt; // will point to prepared stamement object
sqlite3_prepare_v2(
db, // the handle to your (opened and ready) database
sql.c_str(), // the sql statement, utf-8 encoded
sql.length(), // max length of sql statement
&stmt, // this is an "out" parameter, the compiled statement goes here
nullptr); // pointer to the tail end of sql statement (when there are
// multiple statements inside the string; can be null)
Then you bind the parameter(s). There's a whole bunch of avaliable functions. Which one exactly you use depends on the type
of data that you're binding to the parameter. Here, we bind text, so we use sqlite3_bind_text:
std::string newName = /* get name from user */;
sqlite3_bind_text(
stmt, // previously compiled prepared statement object
1, // parameter index, 1-based
newName.c_str(), // the data
newName.length(), // length of data
SQLITE_STATIC); // this parameter is a little tricky - it's a pointer to the callback
// function that frees the data after the call to this function.
// It can be null if the data doesn't need to be freed, or like in this case,
// special value SQLITE_STATIC (the data is managed by the std::string
// object and will be freed automatically).
So, the prepared statement is ready to go. Now you execute it by passing it to sqlite3_step:
sqlite3_step(stmt); // you'll want to check the return value, read on...
Now, when you step through a statement that's supposed to return rows of a result table, this function will keep returning SQLITE_ROW as long as there are result rows to process, and SQLITE_DONE when there are none left. You can use sqlite3_column_* family of functions to get the single columns from a result row. I'll let you figure this out on your own.
For a simple update statements that you have, sqlite3_step will return SQLITE_DONE on the first call. More info and possible error codes are here.
When it's all done, you finish by destructing the prepared statement.
sqlite3_finalize(stmt);
I hope this should get you started.

Getting segmentation fault when using pointers in C

I'm currently working on a project where I want to use SQLite to store some data. Everything is working well except when I want to insert new data into the table. When I run the application, I get segmentation fault, but I can't find the problem.
void sqlite(char *id, char *sensorname, char *sensorvalue){
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
const char* data = "Callback function called";
/* Open database */
rc = sqlite3_open("/home/macho/Documents/sensor_database.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stderr, "Opened database successfully\n");
}
sql = "INSERT INTO sensors (id,sensorname,sensorvalue) VALUES(";
char* split = ",";
strcat(sql, id);
strcat(sql, ",");
strcat(sql, sensorname);
strcat(sql, ",");
strcat(sql, sensorvalue);
strcat(sql, ");");
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}else{
fprintf(stdout, "Operation done successfully\n");
}
sqlite3_close(db);
}
And in the main, I'm calling the sqlite() function:
sqlite("1","sensor","sensor1");
Any idea what the problem can be?
Thanks!
You assign sql a static (read-only) string and then attempt to append to it. Instead, create a large writeable array either on the stack or use malloc and then assemble your query in that. So
char sql[4096];
strcpy(sql, "INSERT INTO sensors ...
...
Note that you should check for overflow of the buffer based on the lengths of the values.
BTW, the code as written is just asking for an SQL injection attack if accessible to users. Look up Bobby Tables.

ADO Recordset object returning 80004003 Error

I am simply trying to Open a Recordset, but it is returning me error..
Here is a part of my code:
void MyFunction(_ConnectionPtr ConnPtr) {
_RecordsetPtr RecPtr;
std::string command = "Select * from MYTABLE";
RecPtr.CreateInstance(__uuidof(_Recordset));
RecPtr->Open(command.c_str(), ConnPtr.GetInterfacePtr(), adOpenStatic, adLockOptimistic, adCmdText);
//ERROR!!!!!!!
}
int main(int argc, char** argv) {
CoInitializeEx(NULL, COINIT_MULTITHREADED)
_ConnectionPtr ConnPtr;
ConnPtr.CreateInstance("ADODB.Connection");
ConnPtr->Open(....my Connection String, UserID, and Password....);
MyFunction(ConnPtr);
::CoUninitialize();
ConnPtr->Close();
}
The Error Message:
Code = 80004003
Code Meaning = I
Source = <null>
Description = <null>
dd
(The description says nothing.. and also I have no idea what "I" means or why "dd" is printed out at the end,,)
There is nothing wrong with the connection string, userID, and Password, since opening the connection ptr returns no error. The error occurs when I try to open the Recordset.. Can anyone find a problem in my code?
Thanks

Simple C++ connection to mysql database

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).

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));