Nearly done with PreparedStatement

It’s been a really busy week – starting out with me going locking down on Monday and working from home to get a whole bunch of stuff blasted out without having to go cowboy.

Somehow, inbetween everything else, I’ve managed to get a little ‘recreational coding’ out of the genuine need to get prepared statements integrated into the codebase for what we’re doing with the auth process.

So far, I only need data modifying statements, but the natural progression is a general encapsulation that will also support call/select etc. (Right now I never even both fetching the result set because none of my queries needs to).

Yes, there are PreparedStatement encapsulations out there – but most of them are scripting language oriented and don’t really give a hoot about performance. Here my goal is high-end performance – getting my data as close to the wire as possible.

I’ve made some nice little improvements this week that have made it thread-usable (its inherently not thread-safe because of its MySQL connection binding but it can be used in a thread-safe way now) and extened the encapsulation to allow you to bind it to your own data storage without allocating any which gives me maximal performance. Woot!

But the part I’m struggling with is … how to handle the result set binding. MySQLs MYSQL_BIND stuff is just a pain to work with for this, and I want to avoid lots of allocations – infact ideally I want to avoid any allocations.

I’ve already worked out what I want to do:

struct RankResults
{
    UINT32 rankID ;
    char rankName[64] ;
} ;
struct ResultBind : MYSQL_BIND
{
public:
    ResultBind(UINT32& integer)
    {
        this->buffer = &integer ;
        this->buffer_type = MYSQL_TYPE_LONG ;
        this->is_unsigned = true ;
    }

}  ;


void
someFunc(MYSQL* mysql, UINT32 forCountry) 
{
    static RankResults res ;
    static PreparedStatement myStmt(mysql
        , “SELECT rank, name FROM ranks”
              ” WHERE country = %u”
        , ResultBind(res.rankID)
        , ResultBind(res.rankName)) ;

    myStmt.Execute(mysql, forCountry) ;
    while ( myStmt.FetchRow() )
    {
printf(“%u: %s\n”, res.rankID, res.rankName) ;
    }

If I know what I want to do and can write the code, what’s the problem?

C++ can’t do what I just wrote. The variable list of parameters I’m passing to my PreparedStatement constructor are variable. My current working version uses stdarg. Trouble is, that means I have to tell it how many parameters there are going to be or assume you will provide the right number of arguments for the metadata. In the case of something like CALL there’s no way to be sure though.

While I want efficiency, I also want a smidgem of type safety: I use overloading to in the ResultBind constructors to let me prep the MYSQL_BINDs with “what do we have here” data that I later validate quickly against the metadata before allowing you to proceed.

But the ResultBind’s in the sample constructor above are temporary objects, which means they won’t work with stdarg – either trying to take references or addresses of.

C and C++ inherit a couple of concepts for describing items of data: lvalues and rvalues. These stem from the early days of assignment statements where the left value was storage to a known, named location while the right hand side was potentially transitory:

  int i = 2 + 3 ;

The expression “2 + 3” is evaluated “somewhere” and then committed to i – but before it is stored in “i” it is stored somewhere temporary (probably a register).

So – for at least some sense of the term “scope” – the lvalue is persistent while the rvalue evaporates by the end of the expression.

The new C++ standard, C++0x, is solving this with rvalue references. The motivation behind this is something they call “move operations”, which I’ve finally understood as “handoff operations” — in simple terms you can tear up a temporary instance of an object and then hand off everything that was involved in that setup process to a permanent object.

Lots of C++ programmers will write statements like:

someobject Foo = somevalue ;

because they’re used to using things like

std::string Foo = “Hello” ;

Luckily, std::string implements operator=(const char*);. If it didn’t, then the compiler would want the right side of the expression to be a std::string for the assignment, and it would notice that std::string has a constructor for const char* so it would expand the code to:

std::string _temporary_ ;
_temporary_.m_size = strlen(“Hello”) + 1 ;
_temporary_.m_data = new char[_temporary_.m_size];
std::string Foo() ;
Foo.m_size = _temporary_.m_size ;
Foo.m_data = new char[Foo.m_size]; // a second alloc
memcpy(Foo.m_data, _temporary_.m_data, Foo.m_size]; // Copy
// _temporary_.~string() gets called as it goes out of scope
delete [] _temporary_.m_data ; // Another memory allocation operation

The last assignment involves another memory allocation because Foo must resize itself to accomodate the contents of  _temporary_.

A “move operation” is aware that the stuff on the right hand side is temporary, that after the current scope it will be destroyed. A move-operation based operator= for std::string expands to:

std::string _temporary_ ;
_temporary_.m_size = strlen(“Hello”) + 1 ;
_temporary_.m_data = new char[_temporary_.m_size];
std::string Foo ;
Foo.m_size = _temporary_.m_size ;
Foo.m_data = _temporary_.m_data ;
_temporary_.m_data = NULL ; // _temporary_ is no-longer the owner of any string data, we have taken it.
// now _temporary_ goes out of scope calling ~string()
// m_data is NULL so no delete operation

It’s a comparable number of high-level instructions but it boils down to eliminating a whole bunch of memory operations – instead of both the temporary and the Foo strings allocating storage and both of them copying the text into their storage, only the temporary has to do leg work, and the permanent just takes the stuff for itself.

C++0x also has variadic templates which would provide me another means of solving this problem gracefully. And since we’re flogging this future horse, I should point out it also has initializer lists.

The good news is that GCC 4.4 will support all of these features and having a new language feature set come out while I have a practical application for them makes me feel nearly as giddy as experimenting with C++/CLI did. But the even better news is that GCC 4.4 is almost ready – I think it’s probably going to be out (and hopefully patched a couple of times and stable) by the time I get around to actually needing to implement this :)

8 Comments

I hope you’re aware of, that the following source isn’t calling the operator = but the constructor of std::string.

std::string foo = "hello";

There won’t be any temporary object of std::string in this sourcecode.

And to your problem with variable amounts of parameters:
What about a proxy with an overloaded operator? Something like boost::format does.
http://www.boost.org/doc/libs/1_38_0/libs/format/doc/format.html

Drave

Drave, you appear to have missed the bit right below that example:

Luckily, std::string implements operator=(const char*);. If it didn’t, then the compiler would want the right side of the expression to be a std::string for the assignment, and it would notice that std::string has a constructor for const char* so it would expand the code to:

You do realize that if std::string did not implement operator=(const char*) then the code would expand as I’d said?

If it didn’t, then the compiler would take advantage of the std::string(const char*) to create an rvalue (temporary std::string) to comply with the std::string::operator=(const std::string& rhs) assignment.

The point of my example is that it’s not automatic, and types that forget or neglect to provide a matching assignment constructor will try for a copy constructor and silently insert an additional object creation overhead.

Operator overloading would rank there with my list of inelegant solutions — it’d get the job done, but that’s not what ‘%’ would actually mean. I tried it with ‘<<‘ but I just don’t like it:

static PreparedStatement stmt(conn, SQL) << ResultBind(&int1) << ResultBind(charArray, 64) ; [/sourcecode]

No it wouldn’t!

std::string foo = "Hello";
// is the same as:
std::string foo("Hello");

Try it yourself. I bet the following won’t compile:

class Foo
{
public:
  Foo()
  { }

  Foo& operator =(char const*)
  { return *this; }
};


int main()
{
  Foo foo = "Hello";
  return 0;
}

It will complain about, that there is no available constructor which takes a char const*.

What you’re saying does only apply for:

std::string foo;
foo = "Hello";

But this is something completly different!

And about operator overloading:
Well then you probably only can wait and hope :)

Drave

I stand corrected about the = constructor, but it certainly used to be true (I even checked my old, yellowed C++ book from 10 years ago :)

As for wait and hope – hoping is not required – see the links in the article :)

10 years – perhaps on a non-Standard 98 compiler? I only learned the C++ Standard 98, so no idea how it was before. :)

I read the articles, but you should be aware of the timetables from computer scientists. Look at BGE, they announced a month ago that there would be an open beta. Soon ™. :D

Drave

Heh, I already have GCC 4.4 – it’s just not production ready yet :)

And you also already have BGE 1.30! That’s not fair…

Drave

Kfs1, A little off topic but related to C++, is there a msi installer for c++ as i cant seem to find one?

Leave a Reply

Name and email address are required. Your email address will not be published.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

You may use these HTML tags and attributes:

<a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <pre> <q cite=""> <s> <strike> <strong> 

%d bloggers like this: