First, I am new to C++; now,I am trying to write a project to listen to any database change from MySQL binlog and do something. I chose a library called mysql-binlog-repliation, following its example codes, now I can track event in MySQL binlog, retrieve old values and new values. However, I can not retrieve columns, I want to know how to retrieve columns together with values, appreciate for any useful answers!
Below is part of my codes:
while (true) {
int result = binlog.wait_for_next_event(&event);
if (result == ERR_EOF)
break;
std::cout << "Found event of type " << event->get_event_type();
int event_type = event->get_event_type();
if (event_type == mysql::TABLE_MAP_EVENT) {
tmev = (mysql::Table_map_event *)event;
std::string tablename=tmev->table_name;
}
if (event_type == mysql::WRITE_ROWS_EVENT || event_type==mysql::UPDATE_ROWS_EVENT || event_type==mysql::DELETE_ROWS_EVENT) {
mysql::Row_event *row_event = (mysql::Row_event *)event;
mysql::Row_event_set rows(row_event, tmev);
mysql::Row_event_set::iterator itor = rows.begin();
do {
mysql::Row_of_fields fields = *itor;
mysql::Row_of_fields::iterator it = fields.begin();
// Here,fields represent values,I have no way to get columns
do {
std::string out;
converter.to(out, *it);
std::cout << "\t" << out;
} while (++it != fields.end());
} while (++itor != rows.end());
}
std::cout << std::endl;
Related
I made this:
int querystate;
std::string pol;
std::string login;
std::cout << "login: ";
std::cin >> login;
pol = "select * from table where login = '" + login + "';";
querystate = mysql_query(conn, pol.c_str());
if (querystate != 0)
{
std::cout << mysql_error(conn);
}
res = mysql_store_result(conn);
while ((row = mysql_fetch_row(res)) != NULL)
{
std::cout << row[0] << " " << row[1] << " " << row[2];
}
It is possible to make something like this?
if (res == 0)
{
cout<<"there is 0 results";
}
I want to output text when query returns 0 results, for example:
there is no such login in the database.
First, your code is open to an SQL injection attack. You need to escape the login string using mysql_real_escape_string_quote(), eg:
std::string escapeStr(MYSQL *mysql, const std::string &str, char quoteChar)
{
std::string out((str.size()*2)+1, '\0');
unsigned long len = mysql_real_escape_string_quote(mysql, out.data(), str.c_str(), str.size(), quoteChar);
out.resize(len);
return out;
}
std::string pol = "select * from table where login = '" + escapeStr(conn, login, '\'') + "';";
Though, you really should be using a prepared statement instead, let MySQL handle the escaping for you.
Second, the mysql_query() documentation says:
To determine whether a statement returns a result set, call mysql_field_count(). See Section 5.4.23, “mysql_field_count()”.
Where the mysql_field_count() documentation says:
The normal use of this function is when mysql_store_result() returned NULL (and thus you have no result set pointer). In this case, you can call mysql_field_count() to determine whether mysql_store_result() should have produced a nonempty result. This enables the client program to take proper action without knowing whether the query was a SELECT (or SELECT-like) statement. The example shown here illustrates how this may be done.
See Section 3.6.8, “NULL mysql_store_result() Return After mysql_query() Success”.
And that last document says:
It is possible for mysql_store_result() to return NULL following a successful call to to the server using mysql_real_query() or mysql_query(). When this happens, it means one of the following conditions occurred:
There was a malloc() failure (for example, if the result set was too large).
The data could not be read (an error occurred on the connection).
The query returned no data (for example, it was an INSERT, UPDATE, or DELETE).
You can always check whether the statement should have produced a nonempty result by calling mysql_field_count(). If mysql_field_count() returns zero, the result is empty and the last query was a statement that does not return values (for example, an INSERT or a DELETE). If mysql_field_count() returns a nonzero value, the statement should have produced a nonempty result. See the description of the mysql_field_count() function for an example.
So, for example:
std::string login;
std::cout << "login: ";
std::cin >> login;
std::string pol = "select * from table where login = '" + escapeStr(conn, login, '\'') + "';";
if (mysql_query(conn, pol.c_str()) != 0)
{
std::cout << mysql_error(conn);
}
else if ((res = mysql_store_result(conn)) != NULL)
{
while ((row = mysql_fetch_row(res)) != NULL)
{
std::cout << row[0] << " " << row[1] << " " << row[2];
}
mysql_free_result(res);
}
else if (mysql_field_count(conn) == 0)
{
std::cout << "there are 0 results";
}
else
{
std::cout << mysql_error(conn);
}
Alternatively, the documentation also says:
An alternative is to replace the mysql_field_count(&mysql) call with mysql_errno(&mysql). In this case, you are checking directly for an error from mysql_store_result() rather than inferring from the value of mysql_field_count() whether the statement was a SELECT.
std::string login;
std::cout << "login: ";
std::cin >> login;
std::string pol = "select * from table where login = '" + escapeStr(conn, login, '\'') + "';";
if (mysql_query(conn, pol.c_str()) != 0)
{
std::cout << mysql_error(conn);
}
else if ((res = mysql_store_result(conn)) != NULL)
{
while ((row = mysql_fetch_row(res)) != NULL)
{
std::cout << row[0] << " " << row[1] << " " << row[2];
}
mysql_free_result(res);
}
else if (mysql_errno(conn) == 0)
{
std::cout << "there are 0 results";
}
else
{
std::cout << mysql_error(conn);
}
From the documentation available in this site https://dev.mysql.com/doc/c-api/5.7/en/mysql-fetch-row.html
When used after mysql_store_result(), mysql_fetch_row() returns NULL if there are no more rows to retrieve.
so use that to verify whether the data has rows or not. Since doing this once would have fetched a row already, you need to print them immediately before trying to get another row from the DB.
row = mysql_fetch_row(res)
if( row == NULL ) // This verifies whether data is NULL or not
cout << " There is no Results "<<endl
else {
do
{
std::cout << row[0] << " " << row[1] << " " << row[2];
}
while (row = mysql_fetch_row(res)) != NULL)
}
This might be a very small issue, but I'm really wondering why it is not working. I'm trying to output the facet ID associated to every halfedge.
void MeshModel::printFacetsOfHalfedges() {
for (Polyhedron::Halfedge_iterator j = P_.halfedges_begin(); j != P_.halfedges_end(); ++j) {
int id = j->facet()->id();
std::cout << "Facet is: " << id << std::endl;
}
}
It starts with Facet is: 0 and then crashes. If I remove the line std::cout << "Facet is: " << id << std::endl; the iteration runs just fine. I'm really wondering how this simple int output messes up the code.
I'm aware that I could also iterate over facets (and this works fine), but I need the halfedge<->facet association.
I'm using CGAL::Polyhedron_items_with_id_3 and initialize my facet IDs at the beginning:
void MeshModel::initializeFacetIndices() {
std::size_t i = 0;
for (Polyhedron::Facet_iterator facet = P_.facets_begin(); facet != P_.facets_end(); ++facet) {
facet->id() = i++;
}
}
You need to check if the halfedge is not a boundary halfedge. In such a case j->facet() == Polyhedron::Face_handle()
I want to use OpenSceneGraph Pickhandler in order to print the name of a node when clicked on with a mouse. I have made a PickHandler Header file and included what I think is the correct code to make this happen.
After no errors upon running the application does not display the node name when clicked. Have I missed something important?
bool PickHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
{
`if( ea.getEventType() != osgGA::GUIEventAdapter::RELEASE &&
ea.getButton() != osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON )
{
return false;
}
osgViewer::View* viewer = dynamic_cast<osgViewer::View*>( &aa );
if( viewer )
{
osgUtil::LineSegmentIntersector* intersector
= new osgUtil::LineSegmentIntersector( osgUtil::Intersector::WINDOW, ea.getX(), ea.getY() );`if( ea.getEventType() != osgGA::GUIEventAdapter::RELEASE &&
ea.getButton() != osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON )
{
return false;
}
osgViewer::View* viewer = dynamic_cast<osgViewer::View*>( &aa );
if( viewer )
{
osgUtil::LineSegmentIntersector* intersector
= new osgUtil::LineSegmentIntersector( osgUtil::Intersector::WINDOW, ea.getX(), ea.getY() );
osgUtil::IntersectionVisitor iv( intersector );
osg::Camera* camera = viewer->getCamera();
if( !camera )
return false;
camera->accept( iv );
if( !intersector->containsIntersections() )
return false;
auto intersections = intersector->getIntersections();
std::cout << "Got " << intersections.size() << " intersections:\n";
for( auto&& intersection : intersections )
std::cout << " - Local intersection point = " << intersection.localIntersectionPoint << "\n";
}
return true;
}
You need to extract your node name in order to print it. If you do not use any custom nodes, then use intersection.drawable->getName(). Make sure you set up a name for that particular's osg::Geometry, otherwire the name is empty by default.
The printing code for your case would be something like:
for( auto&& intersection : intersections ) {
std::cout << " - Local intersection point = " << intersection.localIntersectionPoint << "\n";
std::cout << "Intersection name = " << intersection.drawable->getName() << std::endl;
}
I'm currently trying to make a little recipe app. I have made a string array with 10 strings and 10 bools. For example, when I type Cinnemon I want to make the _Cinnemon true. How do I do that?
Also, is this written correctly, or could I make it better? I'm quite new to programming.
Lastly, how can I fix it so it doesn't have anything to say whether it's small letters or big?
Here's the code:
std::cout << "Welcome, type your ingredients " << std::endl;
std::string ingredients[10]{"Cinnemon", "Milk", "Eggs", "Butter", "Tomatoes", "Salt", "Backing Soda", "Suggar", "Chicken", "Honny"};
bool _cinnemon, _milk, _eggs, _butter, _tomatoes, _salt, _backingSoda, _Suggar, _chicken, _honny;
std::string ingredient;
int i = -1;
while (i = -1) {
std::cin >> ingredient;
i++;
while (i < 9)
{
if (ingredient == ingredients[i]){
std::cout << "Type another if you have any more igredients else type Exit" << std::endl;
i++;
} if (ingredient == "Exit" || "exit"){
return 0;
} else{
i++;
}
}
}
Try to map your hard-coded strings into booleans. So you can change them easily.
map<string, bool> m;
m["blah"] = false; // Initialize to false
// Later, you can change it by
m["blah"] = true;
// To look up a value, simply do
if(m.count("blah") && m["blah"]) {
// "blah" is true and do whatever you want to do here
}
As for string comparison ignoring the case, you can write your own function to do that, for example
#include <cctype> // This is where tolower() is defined
bool stringCmpIgnoreCase(string a, string b) {
if(a.length() != b.length())
return false;
for(int i = 0; i < a.length(); i++)
if(tolower(a[i]) != tolower(b[i]))
return false;
return true;
}
I understand that you are learning, so I'll avoid advanced datastructures such as maps and sets, which would be used for a real life application.
My proposed solution just uses an array of boolean. For every indegrients which string is found, I set the boolean flag at the same index. Here is how it works:
std::cout << "Welcome, type your ingredients " << std::endl;
const size_t maxind = 10; // avoid hard coded size !
std::string ingredients[maxind]{"Cinnemon", "Milk", "Eggs", "Butter", "Tomatoes", "Salt", "Backing Soda", "Suggar", "Chicken", "Honny"};
bool hasindegrient[maxind]{}; // make a table to know which one is present
std::string ingredient;
bool stopit = false; // exit requested ?
while (! stopit) {
std::cin >> ingredient;
int i;
for (i=0; i<maxind; i++)
if (ingredient == ingredients[i]){
hasindegrient[i] = true; // <================ set flag of indegrient
break;
}
if (i==maxind) { // here we didn't find it !
if (ingredient == "Exit" || ingredient == "exit")
stopit = true;
else
std::cout << "Indegrient not found !" << std::endl;
if (!stopit)
std::cout << "Type another if you have any more igredients else type Exit" << std::endl;
}
}
for (int i=0; i<10; i++) // display the indegrient list
if (hasindegrient[i])
cout << ingredients[i]<< " ";
cout << endl;
With this approach, each boolean is anonymous: each hasindegrient[i] is either true or false, but has no name. So on its own it doesn't mean anything. But in this programme, if hasindegrient[i] is true, it means that indegrients[i] is in the receipe.
If you want to add some logic where your code interprets the content of the receipe, you could add at the begin an enum that gives a logical name to each index:
enum {IDG_Cinnemon, IDG_Milk, IDG_Eggs, IDG_Butter, IDG_Tomatoes, IDG_Salt, IDG_Backing_Soda, IDG_Suggar, IDG_Chicken, IDG_Honny };
You can understand each element of this enumeration as a constant. As you see, I've followed the same order than in the table of strings. This allows then the writing of code such as:
if (hasindegrient[IDG_Butter]) {
std::cout << "Take care of your cholesterol" << std::endl;
}
Important remarks:
I think you should know some problems of your original code:
while (i = -1) will loop forever, whatever the value of i is. = is the assignement operator (i.e. -1 is copied to i and the value of i is evaluated in condition). This is the most common errors when starting with C/C++: you certainly meant while (i==-1) which is a comparison.
ingredient == "Exit" || "exit" is a valid syntax. But this condition is always true. It does in no way mean "indegrient is either Exit or exit" . For this you'd write ingredient == "Exit" || ingredient =="exit"
your loop structure will not succeed in the search. Especially if the entering of the indegrients doesn't follow the predefined list...
There are different approaches for this task. For example you could use a bool array and an enumeration with names of ingredients that would be used as indices of the array.
You could use std::bitset or std::vector<bool>
You could use an array of pairs std::pair<std::string, bool>.
Also you can use std::map.
Here is a demonstrative program
#include <iostream>
#include <map>
#include <string>
int main()
{
std::map<std::string, bool> ingredients =
{
{ "Cinnemon", false }, { "Milk", false }, { "Eggs",false },
{ "Butter", false }, { "Tomatoes", false }, { "Salt", false },
{ "Backing Soda", false }, { "Suggar", false }, { "Chicken", false },
{ "Honny", false }
};
std::cout << "Welcome, type your ingredients\n" << std::endl;
std::string ingredient;
bool selected = false;
while ( std::getline(std::cin, ingredient ) )
{
if ( ingredient == "Exit" | ingredient == "exit" ) break;
if ( selected = ( ingredients.count( ingredient ) != 0 ) )
{
ingredients[ingredient] = true;
}
else
{
std::cout << "Invalid ingredient." << std::endl;
}
std::cout << "Type another if you have any more igredients else type Exit" << std::endl;
}
if ( selected )
{
std::cout << "You selected ingredients:" << std::endl;
for ( const auto &p : ingredients )
{
if ( p.second ) std::cout << p.first << std::endl;
}
}
return 0;
}
Take into account that you have to use function std::getline instead of operator >> because some ingredient names consist from several words.
Also you should make case insensitive search.
I have started working with C++ libcql library for Cassandra.. I am trying to retrieve data from Cassandra using C++ with libcql library..
Whenever I go on the command line using cqlsh and do select like this -
select record_name, record_value from profile_user where user_id = '1';
I always get the below output on the cql command line and in which record_name and record_value are actually a column of TEXT datatype which is UTF-8 encoded string.
record_name | record_value
-------------+--------------
e1 | hello
e2 | hello
Now Coming to C++ world-
Now I am trying to retrieve the same thing from the C++ libcql library... I will be running the same above select query in C++ and I want to return a map which will have e1, e2 as the key and HELLO as there value inside that map... It is possible to do it in C++?
/**
* This method will retrieve the data from Cassandra..
* And then call print_rows method to print it out on the console
*/
void get_attributes(string id){
try{
// some code
//Connection open
connection_open();
execute_query("USE testks;");
//this will give me the result back of the select query
cql_result_t& result = execute_query("select * from profile_user where key ='"+id+"';");
// and this is printing it out on the console
print_rows(result);
// some code
} catch (int e){
// some code here
}
}
Below is the method which will print out the results on the console after running my C++ program -
/**
* This method prints out the result on the console.. *
*
*/
void print_rows(cql::cql_result_t& result) {
while (result.next()) {
for (size_t i = 0; i < result.column_count(); ++i) {
cql::cql_byte_t* data = NULL;
cql::cql_int_t size = 0;
result.get_data(i, &data, size);
std::cout.write(reinterpret_cast<char*>(data), size);
std::cout << " | ";
}
std::cout << std::endl;
}
}
The result that I see on the console after running my above C++ program is something like this -
e1 | hello |
e2 | hello |
But what I am looking for is - Store the result in a Map in C++, in such a way such that key should be e1 and e2 in the Map.. And the value for them should be HELLO in the same Map... And then iterate the Map and print out the result in C++? Is this possible to do with the current code I have?
If yes, can anyone provide a simple example on this? Thanks...
It is basically a C++ question I guess.. Just retrieve the data and put it into the Map... But the problem I am facing is my background is totally in Java so having little bit hard time to figure out how to do that...
I have slightly changed my table design in this question to my original question here instead of using collection, now I am using composite keys..
But If I can figure out the solution to my previous question then I will be going with that approach, otherwise I will be going with this approach..
Thanks for the help...
Update Code:-
With the below change, it always print out first result twice? Not sure why?
void print_rows(cql::cql_result_t& result){
while (result.next()) {
for (size_t i = 0; i < result.column_count(); ++i) {
cql::cql_byte_t* data = NULL;
cql::cql_int_t size = 0;
result.get_data(i, &data, size);
// std::cout.write(reinterpret_cast<char*>(data), size);
// std::cout << " | ";
if(!flag) {
key = reinterpret_cast<char*>(data);
flag = true;
} else if(flag) {
value = reinterpret_cast<char*>(data);
m[key] = value;
flag = false;
}
}
std:map<std::string, std::string>::const_iterator it = m.begin();
for (;it!=m.end(); ++it ) {
std::cout << it->first << " : " << it->second << std::endl;
}
std::cout << std::endl;
}
}
e1 : hello
e1 : hello
e2 : hello
Is there anything wrong I am doing here?
So looks like your keys and values are alternating on each pass,
You can have something like this :
bool flag=false;
std::map<std::string, std::string> m;
std::string key,value;
void print_rows(cql::cql_result_t& result) {
while (result.next()) {
//...
if(!flag)
{
key=reinterpret_cast<char*>(data);
flag= true;
}
else if(flag)
{
value=reinterpret_cast<char*>(data);
m[key] = value;
flag = false;
}
// ....
}
//...
}
Now to transverse the map:
std::map<std::string, std::string>::const_iterator it=m.begin();
for(;it!=m.end();++it)
std::cout << it->first << " : " << it->second << std::endl;
Or if you're using C++11 :
for(const auto &it:m)
std::cout << it.first << " : "<< it.second << std::endl;