Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation for specializing type_conversion<> doesn't fully explain indicators #102

Closed
creste opened this issue Mar 12, 2013 · 1 comment
Assignees
Labels
Milestone

Comments

@creste
Copy link

creste commented Mar 12, 2013

I am not sure if this is a bug or just unclear documentation on http://soci.sourceforge.net/doc/exchange.html, so I'll start with some questions:

  1. When specializing type_conversion<>, is the to_base method required to set the indicator equal to some value? The example in the documentation sets ind = i_ok, but I want to know if setting the indicator is required or not.
  2. Is the indicator in to_base an input and output variable, or only an output variable?
  3. If the indicator is only an output variable, then when client code calls soci::use(myType, i_null) won't the i_null be ignored if the user-defined type doesn't represent a null value?

I will try to illustrate the problem implied in question 3 using the following code:

namespace soci
{
    template <>
    struct type_conversion<MyInt>
    {
        typedef int base_type;

        static void from_base(int i, indicator ind, MyInt & mi)
        {
            // ... not important
        }

        static void to_base(const MyInt & mi, int & i, indicator & ind)
        {
            i = mi.get();
            ind = i_ok;
        }
    };
}

Code that wants to store MyInt in the database:

MyInt myInt(1);
soci::indicator ind = soci::i_null;
soci::session db;
db << "INSERT INTO foo (i) VALUES (:myInt)", soci::use(myInt, ind);

In the above code, what is the expected behavior? Should "NULL" be inserted, or should "1"? Currently, the above code results in "1" being inserted, even though the indicator was set to i_null. This is caused by the fact that to_base always sets the indicator to i_ok, even when it was explicitly set to i_null by the calling code.

One way to fix this issue would be to check ind in to_base to make sure the client code didn't set it to i_null:

        static void to_base(const MyInt & mi, int & i, indicator & ind)
        {
            if (ind != i_null) {
                i = mi.get();
                ind = i_ok;
            }
        }

This works fine, until the client code doesn't use an indicator:

MyInt myInt(1);
soci::session db;
db << "INSERT INTO foo (i) VALUES (:myInt)", soci::use(myInt);

Now, you will get undefined behavior because the indicator passed to to_base can come from soci::conversion_use_type::ind_, which is referencing soci::conversion_use_type::ownInd_, which was doesn't appear to be explicitly set when the client code used soci::use(T) instead of soci::use(T, indicator). This means that ownInd_ might be uninitialized. I see in my program that sometimes it is i_null and other times it is i_ok, which causes the exact same piece of client code to behave in different ways depending on which garbage value ownInd_ gets initialized to.

@mloskot
Copy link
Contributor

mloskot commented Mar 17, 2013

@creste sorry for delay, but haven't had time to compile a comprehensive answer to your question, a very interesting issue, by the way.

I have been trying to reach Maciej about original design background, if he replies it may clarify a lot.
Meanwhile, a brief answer to the three questions based on my own understanding. So, AFAIU:

  1. Yes, I'd expect indicator must be set or we decide explicitly on some default value and related behaviour.
  2. It is output variable.
  3. I'd expect, in soci::use(myType, i_null) that the value is ignored and, presumably, SOCI assigns SQL NULL to corresponding placeholder in query. I understand that the indicator correspondence with semantic of SQL NULL, thus wherever user sets soci::i_null, s/he means SQL NULL.

But, all these needs to be verified, either by Maciej's response or by inspection of current implementation and corrections applied if needed, so the semantics and behaviours are intuitive and consistent. I think this is important topic, but I have to complete the SOCI 3.2.0 release first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants