Bad cast exception on poco-library when I tried to cast Int64 - c++

I wrote some code for parse JSON string.
I got "Bad Cast Exception" sometimes.
In My JSON string 1. 2. don't raise exception and 3. 4. raise exception.
A difference between two group is that 1. 2.'s BCodeW is in range long and 3. 4.'s BCodeW is in range Int64.
Why the casting raise the exception ?
I wrote some guard code for Bad Cast Exception but I wanna know the reason of exception.
Thanks for reading.
my environment is below.
g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11)
poco-1.6.0 (using Poco::JSON)
CentOS release 6.6 (Final)
My JSON string example below.
{"y":37.56376,"x":126.97287,"poiY":37.563686111111,"poiX":126.97302222222,"jibunY":37.563805555556,"jibunX":126.97285833333,"BCodeW":1114016700,"poi":"...","jibun":"..."}
{"y":37.59771,"x":127.041493,"poiY":37.597605555556,"poiX":127.041725,"jibunY":37.597547222222,"jibunX":127.04176666667,"BCodeW":1129013600,"poi":"...","jibun":"..."}
{"y":36.760035,"x":127.250362,"poiY":36.759905555556,"poiX":127.25036111111,"jibunY":36.760119444444,"jibunX":127.25040833333,"BCodeW":4413125029,"poi":"...","jibun":"..."}
{"y":36.129513,"x":128.34381,"poiY":36.128672222222,"poiX":128.34373888889,"jibunY":36.129738888889,"jibunX":128.34425833333,"BCodeW":4719010200,"poi":"...","jibun":"..."}
My Code is below.
bool CUBIUtils::ParseAddressResult( llong& _BCodeW, char* _szPOI, char* _szJibun, char* _szAPIResult )
{
JSON::Parser parser;
try
{
JSON::Object::Ptr _object = parser.parse(_szAPIResult).extract<JSON::Object::Ptr>();
if ( NULL == _object)
{
formatlog( LOG_ERROR, "JSON parsing failed");
return false;
}
formatlog( LOG_DEBUG, "CUBIUtils::%s(%d) AddrSrc: %s", __func__, __LINE__, _szAPIResult);
_BCodeW = 0;
try
{
_BCodeW = _object->get("BCodeW").extract<Int64>();
}
catch(exception &_e)
{
_BCodeW = _object->get("BCodeW").extract<int>();
}
strcpy( _szPOI, _object->get("poi").extract<std::string>().c_str());
strcpy( _szJibun, _object->get("jibun").extract<std::string>().c_str());
}
catch(exception &e)
{
formatlog( LOG_ERROR, "CUBIUtils::%s(%d) JSON parsing Exception. %s", __func__, __LINE__, e.what());
return false;
}
return true;
}
Var.h in Poco's source code says.
/// Invoke this method to perform a safe conversion.
///
/// Example usage:
/// Var any("42");
/// int i = any.convert<int>();
///
/// Throws a RangeException if the value does not fit
/// into the result variable.
/// Throws a NotImplementedException if conversion is
/// not available for the given type.
/// Throws InvalidAccessException if Var is empty.
Below Code works.
use convert<T>() instead of extract<T>()
Data type is different. "i", "l"
extract get data which are exactly match type.
_BCodeW = 0;
if ( _object->isNull("BCodeW"))
cout << "BCodeW is NULL" << endl;
else
{
Dynamic::Var _BCodeWVar = _object->get("BCodeW");
cout << "Data Type is " << _BCodeWVar.type().name() << endl;
_BCodeW = _BCodeWVar.convert<Int64>();
cout << "BCodeW is " << _BCodeW << endl;
}

The problem here is not in the JSON parsing and/or data extraction. It is in the comparison line:
if (NULL == _object)
that line will result in BadCastException being thrown.
The reason is because the operator== resolves to
inline bool operator == (const Poco::Int32& other, const Var& da)
and conversion of Poco::JSON::Object::Ptr to Poco::Int32 throws.
Replace the offending line with
if (_object.isNull())
and all will be well.

Related

Problems with JSON for Modern C++ Multidimentional Array

So I have a JSON string I get using cURL that I'm trying to parse for data using JSON for Modern C++ (nlohmann::json). Here is my code:
double retValue(string data) {
string str;
double value = 0;
try {
auto jsonData = json::parse(data.c_str());
str = jsonData["layer"][1]["Page"]["Number"];
value = stoi(str);
}
catch(json::parse_error& e) {
cout << "Error: " << e.what() << endl;
return 0;
}
return value;
}
So In PHP json_decode works fine to decode into an array and the values can be easily parsed in this way, but I am having trouble with C++ and this library. I get the following error at run time but compiles fine:
terminate called after throwing an instance of 'nlohmann::detail::type_error'
what(): [json.exception.type_error.305] cannot use operator[] with object
Aborted (core dumped)
The JSON data is similar to this I'm trying to parse and I figure being multidimensional is the problem and that I'm not handling the data properly.
{
"layer": {
"1": {
"Page": {
"Number": 3.14
}
}
}
}
Can anybody point me in the right direction?
C++ is a strong-typed language, you must use correct data type:
str = jsonData["layer"]["1"]["Page"]["Number"];
But in PHP, you access data[1], which is the same as data["1"]

Create a function to get a username using a try and catch method in C++

I'm trying to create a function to get a username using a try and catch method in C++. Unfortunately this code doesn't work, and my application closes when it tries to run.
QString UserInfo::getFullUserName()
{
DBG_ENTERFUNC(getFullUserName);
QString result;
qDebug("trying to get the username");
try
{
struct passwd fullUserData=*getpwnam(getUserName().toLatin1());
result = fullUserData.pw_gecos;
// it is the first of the comma seperated records that contain the user name
result = result.split(",").first();
if (result.isEmpty())
{
result = getUserName();
}
}
catch (...)
{
qDebug("exception caught");
}
qDebug() << result;
#endif
DBG_EXITFUNC;
return result;
}
The problem occurs in this line of code as I have placed prints after it that are never reached.
struct passwd fullUserData=*getpwnam(getUserName().toLatin1());
Does anyone know what is the issue here?
*Edit--------
Here is my function getUserName()
QString UserInfo::GetUserName()
{
DBG_ENTERFUNC(GetUserName);
QString result;
foreach (QString environmentEntry, QProcess::systemEnvironment())
{
QString varName = environmentEntry.section('=',0,0);
QString varValue = environmentEntry.section('=',1,1);
if (varName == "USER" || varName == "USERNAME")
{
result = varValue;
}
}
DBG_EXITFUNC;
return result;
}
getpwnam() returns NULL when the username was not found. You are potentially dereferencing a NULL pointer.
*getpwnam(getUserName().toLatin1());
// ^ potential NULL pointer deref
Always check before deferencing a potentially invalid pointer:
struct passwd *fullUserData = getpwnam(getUserName().toLatin1());
// ^ note pointer
if (fullUserData != NULL) {
result = fullUserData->pw_gecos;
// ^^ fullUserData is a struct pointer
} else {
// throw Exception
}
If this is confusing to you, you might want to read up on C++ and pointers.

How to declare an empty rowset properly with SOCI?

Imagine that I have the following function. In case of invalid parameters or exception, the function has to exit with an empty rowset.
rowset<row> SelectAllFromTable(string tableName)
{
session sql(odbc, "...");
// if parameters are not valid -> return empty rowset<row>
if (tableName == "")
{
// query that returns 0 result
rowset<row> res = (sql.prepare << "SELECT ID FROM T1 WHERE ID = -9999");
return res;
}
string query = "SELECT * FROM " + tableName;
try
{
rowset<row> rs = sql.prepare << query;
return rs;
}
catch (exception const &e)
{
cerr << "Error: " << e.what() << endl;
// query that returns 0 result
rowset<row> res = (sql.prepare << "SELECT ID FROM T1 WHERE ID = -9999");
return res;
}
// query that returns 0 result
rowset<row> res = (sql.prepare << "SELECT ID FROM T1 WHERE ID = -9999");
return res;
}
The solution I wrote above works but my question is : Is there a better way to return an empty rowset with SOCI ?
Since the documentation hasn't much to offer to this I looked into the rowset Header: There is no default constructor for it and no public method to set the iterators, ergo you can't get an empty rowset by yourself.
Despite why don't you use exceptions which are just perfect for that case. Just don't catch the soci_error exception, then the caller SelectAllFromTable could catch it. This would have many advantages:
The caller would know if there is really no data in the table or there is no table
The caller could know why he can't use the table (misspelled or security reasons)
The caller could know if there are other troubles and take action or if not, rethrow it, so his caller might can.

Invalid null pointer when using _bstr_t

I have a COM DLL that I am developing and I am running into a few issues. I have a try catch around a block of code and in the catch I get a _bstr_t from the exception. What I wanted to do was catch that exception and print it out to a string, however, it is throwing an Invalid null pointer error at me when that exception gets thrown. I tried looking at the MSDN on how to check for a null pointer, but it doesn't seem like it is working. I can't really debug the error because this is on a client machine and when trying to output the information I get this error.
catch(const _com_error& ex)
{
::OutputDebugStringW(ex.Description());
_variant_t ret;
std::string str = "#N/A ExcelException: ";
_bstr_t desc = ex.Description();
if(!desc || desc.GetBSTR() == L"")
{
str += ConvertBSTRToMBS(desc);
}
ret.SetString(str.c_str());
*Result = ret.Detach();
}
std::string ConvertBSTRToMBS(_bstr_t bstr)
{
std::string converted((char *)bstr);
return converted;
}
Due to a mistake in if condition, ConvertBSTRToMBS is called only when bstr is null.
Correct it as follows
if(!!desc && desc.length() != 0)
{
str += ConvertBSTRToMBS(desc);
}
The strange !!desc expression means !(desc.operator!()).
_bstr_t::operator! returns true if BSTR is null, therefore you have to negate it to check for non-null.

Inserting multiple rows in an Oracle database with OCCI

This is my first experience so OCCI so I beg your pardon if the answer is obvious.
I have a Statement object, created the usual way:
string sqlStatement = "INSERT INTO data_tab VALUES(:id, :name, :number, :when)";
m_stmt = m_conn->createStatement(sqlStatement);
m_stmt->setMaxIterations(100);
Then I need to loop over a few objects that I should insert into the database:
for(size_t i = 0; i < data.size(); ++i)
{
m_stmt->setInt(1, i);
try {
m_stmt->setString(2, data[i].client());
}
catch(SQLException& e)
{
cerr << "setString(): " << e.what();
exit(1);
}
m_stmt->setDouble(3, data[i].number());
m_stmt->setDate(4, data[i].when());
// ...
// Checks if maxIterations is lesser than data size,
// oteherwise calls executeUpdate and other kind of
// boilerplate code.
// ...
m_stmt->addIteration();
}
But the code borks in the setString method with the following output:
setString(): ORA-32132: maximum iterations cannot be changed
I believe I should get this error is I call setMaxIterations after a setXXX method but I don't do this. What I am doing wrong?
You should invoke setMaxParamSize() prior to setting a variable length parameter:
m_stmt->setMaxParamSize(2, 1000) // or whatever is the max length of your string.