How do I reuse SQLiteCpp SQLite::Statement? - c++

SQLiteCpp is a open sourced library for operating sqlite database. Here's an example.
try
{
// Open a database file
SQLite::Database db("example.db3");
// Compile a SQL query, containing one parameter (index 1)
SQLite::Statement query(db, "SELECT * FROM test WHERE size > ?");
// Bind the integer value 6 to the first parameter of the SQL query
query.bind(1, 6);
// Loop to execute the query step by step, to get rows of result
while (query.executeStep())
{
// Demonstrate how to get some typed column value
int id = query.getColumn(0);
const char* value = query.getColumn(1);
int size = query.getColumn(2);
std::cout << "row: " << id << ", " << value << ", " << size << std::endl;
}
}
catch (std::exception& e)
{
std::cout << "exception: " << e.what() << std::endl;
}
Since the query is passed in the constructor of Statement SQLite::Statement query(db, "SELECT * FROM test WHERE size > ?");, how do I reuse it?
I didn't see a method accepts a string like query.setQuery("select * from table"). Do you know how do I reuse it?

If it bothers you that much you can just reassign it:
query = SQLite::Statement{db, "select * from table"};

Related

neo4j-client in C, raw type encoding in a statement (i.e. int)

How can I send a statement with an integer type in neo4j-client? Fore example, in CREATE (n:Node {id:1}) the value of the field id is 1. Also, how can I retrieve it?
I have tried, assuming:
std::stringstream ss;
neo4j_run(connection,
ss.str().c_str(), neo4j_null);
--
ss << "RETURN 'hello world'"; // server returns 'hello world'
ss << "RETURN 1"; // server returns 1
ss << "CREATE (n:Node {id:" << std::to_string(2) << "}); // Statement failed
ss << "CREATE (n:Node {id:" << neo4j_int(2) << "})"; // compile error
I am also printing those strings in the console, and CREATE (n:Node {id:" << std::to_string(2) << "}) copy-pasted fro the consolo to the web gui works.
You're probably best sending the integer ID as a parameter, e.g.:
neo4j_map_entry_t map_entry = neo4j_map_entry("id", 2);
neo4j_value_t params = neo4j_map(&map_entry, 1);
neo4j_run(session, "CREATE (n:Node {id:$id});", params);

Access to html table retrieved with QNetworkReply

I want to read the suffix column of the table that I see at http://finance.yahoo.com/exchanges.
I read the page with QNetworkManager. storing data in QNetworkReply *reply. If I read all the page with reply->readAll() I obtain the page, so it's retrieved correctly. I set it inside a QWebPage and then I want to retrieve all tables that are inside.
In order to obtain the table I want to use QWebElement but I'm not be able to read it. I read all tables at the same level of the one that I want but the QWebElementCollection that I obtain is empty.
What I'm doing wrong and that I must do in order to read the table?
void getMarketListFromReply(QNetworkReply *reply) {
std::cout << "Reading page" << std::endl;
const QString html(reply->readAll()); // html contain the code
QWebPage page;
std::cout << "Setting page." << std::endl;
page.mainFrame()->setHtml(html);
std::cout << "Retrieving tables" << std::endl;
QWebElementCollection tables = page.mainFrame()->documentElement().findAll("html body div.screen div.content table");
const int size = tables.count(); // size it's 0 :-(
std::cout << "size: " << size << std::endl;
for (int i = 0; i < size; i++) {
std::cout << i << ": " << tables.at(i).toPlainText().toStdString() << std::endl;
}
}
Dot in findAll() selector denotes tag class. However, in your case "screen" and "content" are element ids that can be selected by sharp (#). So, the following selectors should work
.findAll("html body div#screen div#content table");
.findAll("#content table");

const char * changing value during loop

I have a function that iterates through a const char * and uses the character to add objects to an instance of std::map if it is one of series of recognized characters.
#define CHARSEQ const char*
void compile(CHARSEQ s) throw (BFCompilationError)
{
std::cout << "#Receive call " << s << std::endl;
for(int i = 0; s[i] != '\0'; i++)
{
if (std::string("<>-+.,[]").find_first_of(s[i]) == std::string::npos)
{
throw BFCompilationError("Unknown operator",*s,i);
}
std::cout << "#Compiling: " << s[i] << std::endl;
std::cout << "#address s " << (void*)s << std::endl;
std::cout << "#var s " << s << std::endl;
controlstack.top().push_back(opmap[s[i]]);
}
}
The character sequence passed is "++++++++++."
For the first three iterations, the print statements display the expected values of '+', '+', and '+', and the value of s continues to be "+++++++++++.". However, on the fourth iteration, s becomes mangled, producing bizarre values such as 'Ð', 'öê', 'cR ', 'œk' and many other character sequences. If the line that throws the exception is removed and the loop is allowed to continue, the value of s does not change after again.
Other functions have access to s but since this is not a multithreaded program I don't see why that would matter. I am not so much confused about why s is changing but why it only changes on the fourth iteration.
I have searched SO and the only post that seems at all relevant is this one but it still doesn't answer my question. (Research has been difficult because searching "const char* changing value" or similar terms just comes up with hundreds of posts about what part of is is const).
Lastly, I know I should probably be using std::string, which I will if no answers come forth, but I would still like to understand this behavior.
EDIT:
Here is the code that calls this function.
CHARSEQ text = load(s);
std::cout << "#Receive load " << text << std::endl;
try
{
compile(text);
}
catch(BFCompilationError& err)
{
std::cerr << "\nError in bf code: caught BFCompilationError #" << err.getIndex() << " in file " << s << ":\n";
std::cerr << text << '\n';
for(int i = 0; i < err.getIndex(); i++)
{
std::cerr << " ";
}
std::cerr << "^\n";
std::cerr << err.what() << err.getProblemChar() << std::endl;
return 1;
}
Where load is:
CHARSEQ load(CHARSEQ fname)
{
std::ifstream infile (fname);
std::string data(""), line;
if (infile.is_open())
{
while(infile.good())
{
std::getline(infile,line);
std::cout << "#loading: "<< line << '\n';
data += line;
}
infile.close();
}
else
{
std::cerr << "Error: unable to open file: " << fname << std::endl;
}
return std::trim(data).c_str();
}
and the file fname is ++++++++++. spread such that there is one character per line.
EDIT 2:
Here is an example of console output:
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: .
#Receive load ++++++++++.
#Receive call ++++++++++.
#Compiling: +
#address s 0x7513e4
#var s ++++++++++.
#Compiling: +
#address s 0x7513e4
#var s ++++++++++.
#Compiling: +
#address s 0x7513e4
#var s ++++++++++.
#Compiling:
#address s 0x7513e4
#var s ßu
Error in bf code: caught BFCompilationError #4 in file bf_src/Hello.txt:
ßu
^
Unknown operatorß
Your load function is flawed. The const char* pointer returned by c_str() is valid only until the underlying std::string object exists. But data is a local variable in load and is cleared after return. Its buffer is not overwritten by zeroes but left as it were as free memory. Therefore printing out the value immediately after returning is likely to work but your program may put new values there and the value pointed by your pointer will change.
I suggest to use std::string as the return value of load as a workaround.

String to String build function using different index variables for each string

There are 2 programs below. In the first I have striped out everything but the problem loop and when I do that it works. In the second program (still striped down from the one I am working on) I use the same logic but the sub string called for_loop_buffer never loads.
Basically I am parsing 1 string which holds a record from a cdf file. The for loop buffer is where I build each field and save it to my class. I have been spinning my wheels on this for days any help would be appreciated.
EDIT:
Here are the contents from the file the program is reading:0,Nicole 0,Debbie –
Program 1
/*******************************************************\
* Debug Version 02-b-1 - string to string build *
* *
* Saving a Person Object to file *
* This program will have a class that can save and *
* retrieve itself to and from a flat file in cdf format *
* *
* The program will accept screen input for subsequent *
* Object store call and will allow a print command that *
* will create a file of mailing labels. *
\*******************************************************/
#include <cstdlib>
#include <iostream>
#include <string>
std::string current_person = "Why does this not work? "; // CDF String version of person record from file
std::string for_loop_buffer = " "; // the substring buffer
int counter2 = 0;
int main( )
{
for (int i = 0;i <= 23;++i){
/*****************************************************************************\
* This next line apears to be the problem *
\*****************************************************************************/
for_loop_buffer[counter2] = current_person[i];
std::cout << "DEBUG - Current person " << current_person << std::endl;
std::cout << "DEBUG - current Person element " << current_person[i] << std::endl;
std::cout << "DEBUG - for Loop Buffer " << for_loop_buffer << std::endl;
std::cout << "DEBUG - for Loop Buffer element " << for_loop_buffer[counter2] << std::endl;
std::cout << "DEBUG - for Loop Buffer counter " << counter2 << std::endl;
++counter2;
} // close for
return (0);
}
Program 2
/*******************************************************\
* Debug Version 02 - Read data from a cdf file *
* *
* Saving a Person Object to file *
* This program will have a class that can save and *
* retrieve itself to and from a flat file in cdf format *
* *
* The program will accept screen input for subsequent *
* Object store call and will allow a print command that *
* will create a file of mailing labels. *
\*******************************************************/
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
/***************************************************************\
* Class Definition - person *
* *
* Member functions *
* save_person -- Save the person object to a flat file in CDF *
* get_person -- Retrives a persons data from a CDF flat file *
\***************************************************************/
// Definition of the Class
class person_class {
public:
struct person_contact {
int person_number; // System assigned not on ui
std::string first_name;
};
// Declarations for the method Prototypes
public:
// A Function that retrieves 1 person from file and
// provides it to the user
void get_person();
} person;
/*********************************************************\
* person_class::get_person -- get a data record from file *
* *
\*********************************************************/
inline void person_class::get_person()
{
// Declaration of private variables for this method
std::string ui_first_name; // User Input from Keyboard
person_contact target_person; // Name of the opbect we are filling
std::string current_person; // CDF String version of person record from file
std::cout << "Enter the First Name of the person you are looking for: ";
std::cin >> ui_first_name;
std::cout << std::endl << "Matching Records: " << std::endl;
// Open file
std::ifstream input_file("ntc_db02test.ntc");
std::cout << "DEBUG - I opened the file " << std::endl;
current_person.clear();
while (input_file.good()){
std::cout << "DEBUG - I have entered the while loop " << std::endl;
// Grab the next record from a comma delimited file
getline(input_file,current_person);
std::cout << "DEBUG - I have performed a getline " << std::endl;
std::cout << current_person << std::endl;
// I need a mechanism to build substrings
// Substring Buffer stuff
int buffer_pointer = 0; // pointer to the next position in the substring buffer
std::string for_loop_buffer =" "; // the substring buffer
for_loop_buffer.clear();
int field_index = 0; // Which field is next to load
/*******************************************************************\
* If everything went as planned I have a single CDF person record *
* in the current_person string and now all I have to do is parse *
* it and place each field in the current instance. *
\*******************************************************************/
// load the instance with the record data from the file
for (int i = 0;i < current_person.length();++i){
std::cout << "DEBUG - I am in the for loop " << std::endl;
// look for the end of the CDF field
if(current_person[i] == ','){
// Write the buffer to the next field
std::cout << "DEBUG - I found a comma " << std::endl;
switch (field_index) {
case 0:
stringstream(for_loop_buffer) >> target_person.person_number;
std::cout << "DEBUG - Field Index " << field_index << std::endl;
std::cout << "DEBUG - For Loop Buffer " << for_loop_buffer << std::endl;
std::cout << "DEBUG - Person Number " << target_person.person_number << std::endl;
break;
case 1:
stringstream(for_loop_buffer) >> target_person.first_name;
std::cout << "DEBUG - First Name " << target_person.first_name << std::endl;
break;
default:
std::cout << "This should not happen, index not functioning " << '\n';
break;
} // Close Switch
// clear the buffer
for_loop_buffer.clear(); //SE
buffer_pointer = 0;
// set up the next field load - increment the field index
++field_index; //
}else{ // close if
std::cout << "DEBUG - not a comma " << std::endl;
// If the character is not a comma
// add the character to the buffer
/*****************************************************************************\
* !!!!!!!!!!!! This next line apears to be the problem !!!!!!!!!!!!!!! *
\*****************************************************************************/
for_loop_buffer[buffer_pointer] = current_person[i];
std::cout << "DEBUG - Primary Index i " << i << std::endl;
std::cout << "DEBUG - current Person element " << current_person[i] << std::endl;
std::cout << "DEBUG - Buffer Pointer " << buffer_pointer << std::endl;
std::cout << "DEBUG - for Loop Buffer element " << for_loop_buffer[buffer_pointer] << std::endl;
std::cout << "DEBUG - for Loop Buffer " << for_loop_buffer << std::endl;
// Increment the buffer pointer
++buffer_pointer;
} // close else
} // close for
if (target_person.first_name == ui_first_name){
// Code to print out full record
std::cout << target_person.first_name << " "
<< std::endl;
} // Close if
} // Close While
input_file.close();
} // Close Class
/******************************************************************************\
* The idea this time is to do as little in the main as possible and as much *
* in the class as is appropriate. So rather than read in data and pass it to *
* the method, I will call the method and let it do its own UI reading. *
\******************************************************************************/
int main( )
{
/**********************************************************\
* Ask the user if they want to Create a new person record *
* n or find a record in the database f *
\**********************************************************/
// Set up for user input
char command = 'f';
std::cout << " What do you want to do? New Person (n) or Find Person (f) ";
std::cin >> command;
while (command == 'n' || command == 'f'){
if (command == 'n'){
std::cout << "Do Nothing" << std::endl;
} else if (command == 'f'){
person_class current_person_object;
current_person_object.get_person();
}
command = 'x';
std::cout << "I am Back in Main" << std::endl;
}
std::cout << "You entered something other than a -n- or a -f-, program terminating now" << std::endl;
return (0);
}
You are looping through the string, splitting it up on commas, however there are standard library functions that can simplify this for you. This sounds like homework, so I wont post any code answers, but here are some hints:
std::string::find_first_of will search through a string for you, and tell you where the next comma is.
std::string::substr given a position in the string and a length, will return a part of the string.
Using the above two functions in a loop you could pick out your fields in less code, that's easier to follow.
Alternatively, it would be possible to read the values straight from the stream, as the std::getline function you are using has an extra parameter to specify what character terminates the line (i.e. the comma).
Hard to see through the code, but in your "real" code you say for_loop_buffer.clear();, which is synonymous to for_loop_buffer = "";, and later I think you are accessing a member of the (now empty) string:
for_loop_buffer[buffer_pointer] = current_person[i]; // Illegal access!

Function returning MYSQL_ROW

I'm working on a system using lots of MySQL queries and I'm running into some memory problems I'm pretty sure have to do with me not handling pointers right...
Basically, I've got something like this:
MYSQL_ROW function1() {
string query="SELECT * FROM table limit 1;";
MYSQL_ROW return_row;
mysql_init(&connection); // "connection" is a global variable
if (mysql_real_connect(&connection,HOST,USER,PASS,DB,0,NULL,0)){
if (mysql_query(&connection,query.c_str()))
cout << "Error: " << mysql_error(&connection);
else{
resp = mysql_store_result(&connection); //"resp" is also global
if (resp) return_row = mysql_fetch_row(resp);
mysql_free_result(resp);
}
mysql_close(&connection);
}else{
cout << "connection failed\n";
if (mysql_errno(&connection))
cout << "Error: " << mysql_errno(&connection) << " " << mysql_error(&connection);
}
return return_row;
}
And function2():
MYSQL_ROW function2(MYSQL_ROW row) {
string query = "select * from table2 where code = '" + string(row[2]) + "'";
MYSQL_ROW retorno;
mysql_init(&connection);
if (mysql_real_connect(&connection,HOST,USER,PASS,DB,0,NULL,0)){
if (mysql_query(&connection,query.c_str()))
cout << "Error: " << mysql_error(&conexao);
else{
// My "debugging" shows me at this point `row[2]` is already fubar
resp = mysql_store_result(&connection);
if (resp) return_row = mysql_fetch_row(resp);
mysql_free_result(resp);
}
mysql_close(&connection);
}else{
cout << "connection failed\n";
if (mysql_errno(&connection))
cout << "Error : " << mysql_errno(&connection) << " " << mysql_error(&connection);
}
return return_row;
}
And main() is an infinite loop basically like this:
int main( int argc, char* args[] ){
MYSQL_ROW row = NULL;
while (1) {
row = function1();
if(row != NULL) function2(row);
}
}
(variable and function names have been generalized to protect the innocent)
But after the 3rd or 4th call to function2, that only uses row for reading, row starts losing its value coming to a segfault error...
Anyone's got any ideas why? I'm not sure the amount of global variables in this code is any good, but I didn't design it and only got until tomorrow to fix and finish it, so workarounds are welcome!
Thanks!
Update: I misunderstood how mysql results are used. It looks like the row pointer array points to the results array which you free in function1() and then use it in function2() after it has been returned to the heap.
What you need to do is copy return_row[2] to a persistent string before freeing the results. Then pass that on to function2(). I see you doing something similar in function2() so you need to fix it there as well (though in your example you aren't doing anything with its return value).
Also, you are correct that free(row); is not the correct thing to do.
You should not be closing the connection or freeing the result set while you are processing a row returned by mysql_fetch_row.