Discussion:
[soci-users] bad_cast error (oracle backend)
Lalit Bhasin
2013-06-11 07:57:08 UTC
Permalink
Hi Guys,

Here is my test code to simulate the problem:

*****************
#include <soci/oracle/soci-oracle.h>
#include<soci/soci.h>
#include<iostream>

main()

{
    soci::session sql( soci::oracle, "service=XE user=scott password=tiger" );
    soci::rowset<soci::row> rs = (
        sql.prepare << "select data_length+0, data_length from "
        << " user_tab_cols  where table_name = 'TABLE2' ");

    soci::rowset<soci::row>::const_iterator it = rs.begin();
    soci::row const & row = *it;
    std::cout << "DATA_LENGTH + 0 = " << row.get<int>(0) <<std::endl;      // no error here as expected
    std::cout << "DATA_LENGTH = " << row.get<int>(1) <<std::endl;           // this gives bad_cast error. Why ??

}
*************************

Now when  running this executable:

sqlplus> create table table2 ( a number);
sqlplus> exit

[ubuntu_host]$ ./a.out
DATA_LENGTH + 0 = 22
terminate called after throwing an instance of 'std::bad_cast'
  what():  St8bad_cast
Aborted
[ubuntu_host]$



Any idea why I am getting bad_cast error on accessing data_length column from user_tab_cols view, even though the column is of type number ? The only way to access this column is using data_length+0 in select query.

Thanks,
Lalit
Neil Morgenstern
2013-06-11 08:06:13 UTC
Permalink
If there was one thing I really disliked about SOCI and had to change,
it was getting silly meaningless context-less errors like bad_cast.

I had to fix that to get it to try to work, e.g. convert different
integer types, and then provide context if it still failed.

Please consider making your exceptions meaningful, so if there is an
error there, you know how to fix it.
Post by Lalit Bhasin
Hi Guys,
*****************
#include <soci/oracle/soci-oracle.h>
#include<soci/soci.h>
#include<iostream>
main()
{
soci::session sql( soci::oracle, "service=XE user=scott password=tiger"
);
soci::rowset<soci::row> rs = (
sql.prepare << "select data_length+0, data_length from "
<< " user_tab_cols where table_name = 'TABLE2' ");
soci::rowset<soci::row>::const_iterator it = rs.begin();
soci::row const & row = *it;
std::cout << "DATA_LENGTH + 0 = " << row.get<int>(0) <<std::endl;
// no error here as expected
std::cout << "DATA_LENGTH = " << row.get<int>(1) <<std::endl;
// this gives bad_cast error. Why ??
}
*************************
sqlplus> create table table2 ( a number);
sqlplus> exit
[ubuntu_host]$ ./a.out
DATA_LENGTH + 0 = 22
terminate called after throwing an instance of 'std::bad_cast'
what(): St8bad_cast
Aborted
[ubuntu_host]$
Any idea why I am getting bad_cast error on accessing data_length column
from user_tab_cols view, even though the column is of type number ? The only
way to access this column is using data_length+0 in select query.
Thanks,
Lalit
------------------------------------------------------------------------------
Build for Windows Store.
http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
soci-users mailing list
https://lists.sourceforge.net/lists/listinfo/soci-users
Mateusz Loskot
2013-06-11 13:11:44 UTC
Permalink
Post by Neil Morgenstern
If there was one thing I really disliked about SOCI and had to change,
it was getting silly meaningless context-less errors like bad_cast.
I had to fix that to get it to try to work, e.g. convert different
integer types, and then provide context if it still failed.
Neil,

I agree.
Post by Neil Morgenstern
Please consider making your exceptions meaningful, so if there is an
error there, you know how to fix it.
The bad_cast is thrown by

template<typename T>
T get()
{
type_holder<T>* p = dynamic_cast<type_holder<T> *>(this);
if (p)
{
return p->template value<T>();
}
else
{
throw std::bad_cast();
}
}

where little information on logical correspondance
between the source/target types, fields.

A simple solution, perhaps, would be to catch this exception in row::get(),
try to add some meaningful info from the row, and rethrow.

Suggestions on how you'd like to see it solved are welcome.

Best regards,
--
Mateusz Loskot, http://mateusz.loskot.net
Mateusz Loskot
2013-06-11 13:05:05 UTC
Permalink
This post might be inappropriate. Click to display it.
Lalit Bhasin
2013-06-12 01:06:10 UTC
Permalink
This post might be inappropriate. Click to display it.
Neil Morgenstern
2013-06-12 09:31:54 UTC
Permalink
Another change I made when I worked on the source (which I don't have
available for me now) was to create a specific "deadlock" exception,
which was thrown when a call failed due to database deadlock. This is
handled differently from other exceptions (you resubmit the request)
therefore should throw a different exception type rather than the
general one.

In addition we had to change the ODBC exception to put the error
message returned by ODBC into the "what" of the message otherwise it
got lost. The catcher is only dealing with SOCI errors or std
exceptions and not with specific implementation details. Thus an
exception should reflect what went wrong and why, and not be specific
on the implementation detail.

Error handling is one of those areas where programmers are often lazy
because we expect them not to occur and it is a big effort ensuring
you handle them properly when they do. But hours are spent error
tracking and debugging, and thus handling them properly can save a lot
of users time.

In the case of a user using the wrong integral type, it is better that
they fix the code to use the type that matches what the database uses.
So if you are going to enforce it rather than try to convert, then ok.
Of course you could make it some "option" to do that. (Perhaps they
have a lot of old code that now wants to convert to SOCI, and
internally uses integers of the wrong type). If you do report an
error, ensure there is some context. (One of the weaknesses of C++
actually is that exceptions do not carry call-stack information).
Post by Lalit Bhasin
Thanks. Good that this is known issue, and would be worked upon in future.
I think I can live with fixing it with some trial and errors .
/ Lalit
________________________________
Sent: Tuesday, June 11, 2013 10:05 PM
Subject: Re: [soci-users] bad_cast error (oracle backend)
Post by Lalit Bhasin
*****************
#include <soci/oracle/soci-oracle.h>
#include<soci/soci.h>
#include<iostream>
main()
{
soci::session sql( soci::oracle, "service=XE user=scott password=tiger"
);
soci::rowset<soci::row> rs = (
sql.prepare << "select data_length+0, data_length from "
<< " user_tab_cols where table_name = 'TABLE2' ");
soci::rowset<soci::row>::const_iterator it = rs.begin();
soci::row const & row = *it;
std::cout << "DATA_LENGTH + 0 = " << row.get<int>(0) <<std::endl;
// no error here as expected
std::cout << "DATA_LENGTH = " << row.get<int>(1) <<std::endl;
// this gives bad_cast error. Why ??
}
*************************
https://github.com/SOCI/soci/issues/90
Post by Lalit Bhasin
sqlplus> create table table2 ( a number);
sqlplus> exit
[ubuntu_host]$ ./a.out
DATA_LENGTH + 0 = 22
terminate called after throwing an instance of 'std::bad_cast'
what(): St8bad_cast
Aborted
[ubuntu_host]$
Any idea why I am getting bad_cast error on accessing data_length column
from user_tab_cols view, even though the column is of type number ? The only
way to access this column is using data_length+0 in select query.
I presume, one type is signed the other unsigned, and that hits the wall
of quite unfortunately simplified integral conversions in SOCI, currently.
I'm slowly working (investigating) on getting it right
(https://github.com/SOCI/soci/wiki/RFC1), but I'm too much
multitasking and dealing with unexpected bugfix releases in
meantime.
The only solution I can suggest is to match the right type by some
trial and error.
I know, I'm sorry :(
Best regards,
--
Mateusz Loskot, http://mateusz.loskot.net
------------------------------------------------------------------------------
Build for Windows Store.
http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
soci-users mailing list
https://lists.sourceforge.net/lists/listinfo/soci-users
Mateusz Loskot
2013-06-14 16:27:59 UTC
Permalink
Post by Neil Morgenstern
Another change I made when I worked on the source (which I don't have
available for me now) was to create a specific "deadlock" exception,
which was thrown when a call failed due to database deadlock. This is
handled differently from other exceptions (you resubmit the request)
therefore should throw a different exception type rather than the
general one.
Interesting. I don't think such feature has been considered for SOCI.
Post by Neil Morgenstern
In addition we had to change the ODBC exception to put the error
message returned by ODBC into the "what" of the message otherwise it
got lost. The catcher is only dealing with SOCI errors or std
exceptions and not with specific implementation details. Thus an
exception should reflect what went wrong and why, and not be specific
on the implementation detail.
Error handling is one of those areas where programmers are often lazy
because we expect them not to occur and it is a big effort ensuring
you handle them properly when they do. But hours are spent error
tracking and debugging, and thus handling them properly can save a lot
of users time.
The exceptions are minimal sort of by design, with
"Don't worry too much about the what() message" [1]
principle in mind. I have been thinking on improving it

[1] http://www.boost.org/community/error_handling.html

There is room for improvement, especially with experience based on
std::system_error-like approach, or even exception hierarchies.
A while ago we have brainstormed how to improve it and provide
information context of error
http://thread.gmane.org/gmane.comp.db.soci.devel/7/focus=1075
Post by Neil Morgenstern
In the case of a user using the wrong integral type, it is better that
they fix the code to use the type that matches what the database uses.
So if you are going to enforce it rather than try to convert, then ok.
Of course you could make it some "option" to do that. (Perhaps they
have a lot of old code that now wants to convert to SOCI, and
internally uses integers of the wrong type). If you do report an
error, ensure there is some context. (One of the weaknesses of C++
actually is that exceptions do not carry call-stack information).
I'll keep that in mind, I've recorded your ideas for future reference
https://github.com/SOCI/soci/issues/160

Best regards,
--
Mateusz Loskot, http://mateusz.loskot.net
Loading...