I'm making a query using POCO::Data with ODBC Connector, and I need to check for NULL values from code. In the documentation, the Recordset object is supposed to have the function isNull, but the code I download here does not contains such a method (version 1.4.6p4 right now).
How can I check then if a value is NULL with POCO library? I'm trying to create a JSON string with the data retrieved from database.
My actual code looks like this:
Session session(bdName, conn);
Statement select(session);
select << sSQL;
select.execute();
RecordSet rs(select);
bool more = rs.moveFirst();
std::size_t cols = rs.columnCount();
sResult = "{\"rowsField\":[";
while (more) {
if (sResult.back() != '[') sResult += ','; // Not first time
sResult += "{\"columnsField\":[";
for (std::size_t col = 0; col < cols; ++col) {
std::string cName = rs.columnName (col);
std::string tName = getPocoTypeName(rs.columnType(col));
std::string val = "";
if (!rs[col] || rs.value(col).isEmpty())
val = "NULL"; // DOES NOT WORK
else
val = rs[col].convert<std::string>();
if (col != 0) sResult += ',';
sResult += "\n{\"nameField\":\"" + cName + '\"';
sResult += ",\"typeField\":\"" + tName + '\"';
sResult += ",\"valueField\":\"" + val + '\"';
sResult += "}"; // each JSON column/value
}
sResult += "]}\n"; // columnsField (one per row)
more = rs.moveNext();
}
Use Nullable<std::string> val = std::string("");
isNull is a member of Nullable, so you will be able to check if the return value is null..
I know this is an old question but I have had issues with it. I am also formatting as JSON strings. You can use Poco::Recordset::IsNull(ColumnName) to check if a given column name's value is NULL or not.
The below code will replace NULLS with the empty string to prevent throwing errors:
Poco::Data::Statement statement(session);
statement << query;
statement.execute();
Poco::Data::RecordSet record_set(statement);
bool more = record_set.moveFirst();
while (more)
{
std::map<std::string, std::string> row;
for (std::size_t i = 0; i < record_set.columnCount(); ++i)
{
std::string val = "";
if(!record_set.isNull(record_set.columnName(i)))
val = record_set[i].convert<std::string>();
// print results for testing
cout << "->" << record_set.columnName(i) << ":{" << val << "}";
}
ret.push_back(row);
more = record_set.moveNext();
}
Use record_set[col].isEmpty() for checking NULL.
Related
So i am trying to implement a cryptocurrency for a school project but i am stuck at the block validation part, the mining. I used this code i found online and i adapted it to my project:
void Block::MineBlock(int nDifficulty)
{
std::string cstr(nDifficulty + 1, '\0');
for (int i = 0; i < nDifficulty; i++)
{
cstr[i] = '0';
}
cstr[nDifficulty] = '\0';
std::string str(cstr);
do
{
nNonce++;
blockHash = generateHash();
} while (blockHash.substr(0, nDifficulty) != str);
this->checked = true;
}
My nDifficulty is set to 1. Is it normal that it is looping indefinetely?
Here is the generateHash function as well:
std::string Block::generateHash()
{
std::stringstream ss;
ss << index << timestamp << filename << nNonce << prevHash;
return sha256(ss.str());
}
Your str variable is of length nDifficulty + 1.
So it could never compare equal to a sub-string of length nDifficulty, and the loop condition will never be false.
I am trying to read the elements in an XML and store in a array of
struct and need to pass the pointer of this array to other functions.
However I have issue compiling in gnu, error message:
error: cannot
convert myRec to uint32_t {aka unsigned int}' in return
return *recs;
Tried to set myRec recs[count] without malloc, get an error of invalid pointer.
struct myRec
{
std::string one;
std::string two;
std::string three;
std::string four;
std::string five;
std::string six;
};
uint32_t count = 0;
XMLDocument doc;
doc.LoadFile(pFilename);
XMLElement* parent = doc.FirstChildElement("a");
XMLElement* child = parent->FirstChildElement("b");
XMLElement* e = child->FirstChildElement("c");
for (e = child->FirstChildElement("c"); e; e = e->NextSiblingElement("c"))
{
count++;
}
std::cout << "\n""Count = " << count << std::endl;
recs = (myRec *)malloc(6 *count * sizeof(myRec));
XMLElement *row = child->FirstChildElement();
if (count > 0)
{
--count;
count = (count < 0) ? 0 : count;
for (uint32_t i = 0; i <= count; i++)
{
while (row != NULL)
{
std::string six;
six = row->Attribute("ID");
recs[i].six = six;
XMLElement *col = row->FirstChildElement();
while (col != NULL)
{
std::string sKey;
std::string sVal;
char *sTemp1 = (char *)col->Value();
if (sTemp1 != NULL) {
sKey = static_cast<std::string>(sTemp1);
}
else {
sKey = "";
}
char *sTemp2 = (char *)col->GetText();
if (sTemp2 != NULL) {
sVal = static_cast<std::string>(sTemp2);
}
else {
sVal = "";
}
if (sKey == "one") {
recs[i].one = sVal;
}
if (sKey == "two") {
recs[i].two = sVal;
}
if (sKey == "three") {
recs[i].three = sVal;
}
if (sKey == "four") {
recs[i].four = sVal;
}
if (sKey == "five") {
recs[i].five = sVal;
}
col = col->NextSiblingElement();
}// end while col
std::cout << "\n""one = " << recs[i].one << "\n"" two= " << recs[i].two << "\n""three = " << recs[i].three << "\n""four = " << recs[i].four << "\n""five = " << recs[i].five << "\n""six = " << recs[i].six << std::endl;
row = row->NextSiblingElement();
}// end while row
}
}
else
{
std::cout << "Failed to find value, please check XML! \n" << std::endl;
}
return *recs;
expect to return a pointer to the array
I declared it as:
std::string getxmlcontent(const char* pFilename);
myRec*recs= NULL;
Function:
std::string readxml::getxmlcontent(const char* pFilename)
{
}
Not sure if it is the right way as I am quite new to c++
You're making a few errors, you probably should get a good C++ book and do some studying
In C++ use new
recs = new myRec[6*count];
instead of
recs = (myRec *)malloc(6 *count * sizeof(myRec));
The problem with malloc in a C++ program is that it won't call constructors, so all the strings you have in your struct are invalid, and (most likely) your program will crash when you run it.
It's not clear to me why you need 6*count, that seems to be because you have six strings in your struct. If so then that's confused thinking, really you just need
recs = new myRec[count];
and you'll get 6*count strings because that's how you declared your struct.
sKey = sTemp1;
instead of
sKey = static_cast<std::string>(sTemp1);
No need for the cast, it's perfectly legal to assign a char* to a std::string.
Finally if you want to return a pointer, then just return the pointer
return recs;
not
return *recs;
However you haven't included the function signature in the code you posted. I suspect there's another error, but I can't tell unless you post how you declare this function.
I'm creating a game that requires a lot of setup. I decided to add a configuration file (.ini) and a reader to get the information. My ini file is setup as follows:
-cmd arg0 arg1
I initially only had one command which worked fine until I added a second. For whatever reason, I receive an std::logic_error when my command is not the first one.
// this works
-load w "someName"
// this doesn't
-delete "someName"
Here is the code used to read the file:
InitFileReader::InitFileReader()
{
std::string ini_file_path = "";
ini_file_path += PROGRAM_FOLDER;
ini_file_path += "\\blockgame.ini";
std::ifstream ini_file(ini_file_path);
if (!ini_file.is_open()) std::cout << "Couldn't find configuration file at " << ini_file_path << std::endl;
std::string line;
while(std::getline(ini_file, line))
{
if (starts_with(line, "-load "))
{
std::string arg0 = "";
unsigned int index = 6;
for (; index < line.size(); index++)
{
char c = line[index];
if (c == ' ') break;
arg0 += c;
}
std::string arg1 = "";
bool reached_quote = false;
for (; index < line.size(); index++)
{
char c = line[index];
if (c == ' ' && !reached_quote) continue;
if (c == '\"' && !reached_quote)
{
reached_quote = true;
continue;
}
else if (c == '\"') break;
arg1 += c;
}
sfr = new SaveFolderReader(arg1);
if (arg0 == "new")
{
sfr->new_header(DEFAULT_HEADER);
}
else if (arg0 == "def")
{
sfr->restore_header(DEFAULT_HEADER);
}
}
else if (starts_with(line, "-delete "))
{
std::string arg0 = "";
unsigned int index = 8;
for (; index < line.size(); index++)
{
char c = line[index];
if (c == ' ') break;
arg0 += c;
}
std::string world_path = "";
world_path += PROGRAM_FOLDER;
world_path += "\\save\\";
world_path += arg0;
if (rmdir(world_path.c_str()) != 0)
{
std::cout << "Error deleting world \"" << arg0 << "\"" << std::endl;
}
}
}
}
inline bool starts_with(const std::string& target, const std::string& prefix)
{
if (target.size() < prefix.size())
return false;
for (unsigned int i = 0; i < prefix.size(); i++)
{
if (target[i] != prefix[i])
return false;
}
return true;
}
The PROGRAM_FOLDER constant is just the parent folder of the path returned by argv[0] in main. I can't run the debugger on this code because the path changes to something strange when I do that.
I know that this error shows up because of a nullptr initialization of std::string but I still have no idea why this is happening.
I've tried typing in random characters into the config file and get the same result. It baffles me that the first if-statement works fine but the second one doesn't (when I use the -delete command).
Any suggestions would be of great use, thanks in advance!
It turns out that the error wasn't coming from that block of code at all. What was happening was that my game tried to load data in afterwards but because I didn't write the load command there was nothing to read from. I fixed my Debugger issue (For whatever reason the char[] I allocated stored different data when the debugger ran) and just reverted to std::strings.
Disclaimer -- I'm coming from a pretty strictly C background.
How can the STL and std::string instead of char* be used to go about jumping around a string like this (admittedly nonsensical) example?
const char* s = "XXXXXXXXhello";
while (*s == 'X')
s++;
s += 2;
std::cout << --(--s); //prints `hello`
If what you want to do is modify the object, and get rid of "h":
std::string s = "hello";
s = s.substr(1); // position = 1, length = everything (npos)
std::cout << s; //"ello"
or
std::string s = "hello";
s.erase(0, 1); // position = 0, length = 1
std::cout << s; //"ello"
perfer #José 's second answer and no need to modify the original str
just std::cout<<s.substr(1)<<endl
to the edited question:
std::string s = "hello world!";
cout<<s.substr(s.find_first_of('e'))<<endl; // == "ello world!"
man std::string:
http://www.cplusplus.com/reference/string/string/?kw=string
If you want to jump around without modifying the string, you can either use indices or an iterator:
std::string const s("XXXXXXXXhello");
int idx = 0;
while ( s[idx] == 'X' )
++idx;
idx += 2;
std::cout << &s[idx -= 2] << '\n';
The iterator version:
auto it = s.begin();
while (*it == 'X')
++it;
it += 2;
std::cout << &*it << '\n';
Since C++11 it is guaranteed that std::string is stored with null terminator in place, so you can use & to output the tail of the string. In old code bases you will need to index from s.c_str() instead.
In my game I keep track of unlocked levels with a vector std::vector<bool> lvlUnlocked_;.
The simple function to save the progress is this:
void save() {
std::stringstream ss;
std::string stringToSave = "";
std::ofstream ofile("./progress.txt");
if (ofile.good()) {
ofile.clear();
for (std::size_t i = 0; i < levelUnlocked_.size(); ++i) {
ss << "lvl" << i << "=" << (lvlUnlocked_.at(i) ? "1" : "0") << std::endl;
}
stringToSave = ss.str();
ofile << stringToSave;
ofile.close();
}
}
This works and is nice since I can just use a loop to dump the info.
Now to the part where I am stuck, the lower part of my load function (see comment in code below):
void load() {
std::ifstream ifile("./progress.txt");
if (ifile.good()) {
int begin;
int end;
std::string line;
std::string stringKey = "";
std::string stringValue = "";
unsigned int result;
while (std::getline(ifile, line)) {
stringKey = "";
stringValue = "";
for (unsigned int i = 0; i < line.length(); i++) {
if (line.at(i) == '=') {
begin = i + 1;
end = line.length();
break;
}
}
for (int i = 0; i < begin - 1; i++) {
stringKey += line.at(i);
}
for (int i = begin; i < end; i++) {
stringValue += line.at(i);
}
result = static_cast<unsigned int>(std::stoi(stringValue));
// usually I now compare the value and act accordingly, like so:
if (std::strcmp(stringKey.c_str(), "lvl0") == 0) {
lvlUnlocked_.at(0) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl1") == 0) {
lvlUnlocked_.at(1) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl2") == 0) {
lvlUnlocked_.at(2) = true;
}
// etc....
}
}
}
This works fine, but...
the problem is that I have 100+ levels and I want it to be dynamic based on the size of my lvlUnlocked_ vector instead of having to type it all like in the code above.
Is there a way to somehow make use of a loop like in my save function to check all levels?
If you parse your key to extract a suitable integer value, you can just index into the bit-vector with that:
while (std::getline(ifile, line)) {
const size_t eq = line.find('=');
if (eq == std::string::npos)
// no equals sign
continue;
auto stringKey = line.substr(0, eq);
auto stringValue = line.substr(eq+1);
if (stringKey.substr(0,3) != "lvl")
// doesn't begin with lvl
continue;
// strip off "lvl"
stringKey = stringKey.substr(3);
size_t end;
std::vector<bool>::size_type index = std::stoi(stringKey, &end);
if (end == 0 || end != stringKey.length())
// not a valid level number
continue;
if (index >= lvlUnlocked_.size())
// out of range
continue;
// Set it :-)
lvlUnlocked_[index] = stringValue=="1";
}
(I've also updated your parsing for "key=value" strings to more idiomatic C++.)