Tuesday, September 17, 2013

Compact C++11 code for Oracle – Part I

The less we understand something, the more variables we require to explain it.

-- Ackoff, The Art Of Problem Solving

Not long ago I was told that with the arcane C++ language it was not possible to write compact easy to read code accessing a relational database. The comment was from a PERL programmer. Because I don't particular like PERL as a language – mostly because of its lack of type safety together with the obscure way variables are interpreted as scalars, arrays or hashes (and other obscure types) by pre-fixing a variable, again, by an obscure symbol - I saw the comment as a good opportunity to show what C++ is capable off.

The topic of this entry and a few more to come is to show how the features of C++ together with Oracle OCCI can be used to access Orcale in a very simple way making PERL hacks obsolete in this area. I will describe an implementation (yet to be coded) which allows me to write type safe code which is comparable to the amount of code a PERL programmer would have to write to execute .

Because the code will be written while writing blog entries, I'll give no guarantees on the quality of the code. I will do my best to try to write quality bug free code, but ultimately, it's up to the reader if he/she views it as useable code and point out glaring and maybe not so glaring mistakes. With almost 100% certainty, the code will need modifications as my colleagues' comment on it.

Let's get started! Say I want to select data from a database. I want to treat the set of data covered by a select statement as a collection. Specifically, I would like to be able write something like this:

OcciAuth const auth{"hans","ewetz","MyOracleDatabase"};
std::shared_ptr<Environment>env(Environment::createEnvironment(Environment::DEFAULT),occi_env_deleter());
…
typedef tuple<int,string,string,string>row_t;
typedef tuple<string>bind_t;
string select{"select rownum,dbid,tab,cutoff_dt from MT_DBSYNC_CUTOFF_DT where dbid=:1"};
bind_t bind{"Policy"};
OcciSelectCollection<row_t,bind_t>rows{env.get(),auth,select,bind};
for(auto r:rows)cout<<r<<endl;

The code should be simple enough to read. I typedef two types; one for the row and one for bind variables. Ones the select statement and bind variables are defined I declare a collection representing the data defined by the select. Now I'm on solid C++ ground and can iterate through the collection and print one element (row) at a time to standard out.

If I can implement a collection in such a way as shown above, I should be pretty close to the amount of PERL code that would do the same thing. I know a PERL programmer would say something to the extent that I can do the same thing in fewer lines. So can I, I simply wrote the code to be readable but could have squeezed the whole thing to a line or two.

I chose to use the C++11 tuple templates to represent rows and bind variables. After all, tuples, at a low level, maps straight forward to rows and bind variable. They are also part of the C++11 standard so it makes sense to put them to good use.

Before getting started I will need some support to deal with the fact that a row or a bind type can have any number of elements. Specifically I know that both for rows and bind tuples I need to apply a function on each individual element of the tuples. For example, I know that when dealing with the Oracle API (in this case OCCI) I have to assign values to elements in a row. Therefore I'll first write a function that applies a function object to each one of the elements in a tuple.

My initial idea was to write the function as a variadic template along the lines of:

template<typename...Args> 
void applyWithIndex(Func f,tuple<Args...>&&t){}
  ...
}

The problem with this, as pointed out in comp.lang.c++.moderated is that it is not possible to do perfect forwarding of the tuple inside the function due to the fact that tuple<Args...> does not correspond to a cv-unqualified template parameter as required by the standard.

After trying a few different designs I decided on the following:

template<typename Func,typename Tuple> 
typename std::enable_if<is_tuple<typename std::remove_cv<typename std::remove_reference<Tuple>::type>::type>::value>::type 
applyWithIndex(Func f,Tuple&&t){
  typedef typename std::remove_cv<typename std::remove_reference<Tuple>::type>::type TupleNonRef;
  static const int N=std::tuple_size<TupleNonRef>::value;
  ApplyWithIndex<N,Func,Tuple>::apply(f,std::forward<Tuple>(t));
}
  1. The template takes two parameters: Func representing the function object and Tuple representing the tuple
  2. Enable the function (SFINAE) only if Tuple actually is a std::tuple
  3. I call the function applyWithIndex since it calls Func with a tuple index and a tuple element
  4. Before calling std::tuple_size remove cv-qualifiers and references from Tuple template parameter
  5. Get number of elements in tuple (could be zero)
  6. Call a static member function in a struct (yet to be written) which does the actual work. Notice that the tuple is forwarded

A meta function used for checking that a type is a tuple is implemented as:

template<class> 
struct is_tuple:std::false_type{};
template<class... T>
struct is_tuple<std::tuple<T...>>:std::true_type {};

The ApplyWithIndex struct is fairly straight forward to code. The static apply function recurse until having no more elements to process:

template<int N,typename Func,typename Tuple>
struct ApplyWithIndex{
  static void apply(Func f,Tuple&&t){
    ApplyWithIndex<N-1,Func,Tuple>::apply(f,std::forward<Tuple>(t));
    f(N-1,std::forward<decltype(std::get<N-1>(t))>(std::get<N-1>(t)));  }
};
template<typename Func,typename Tuple>
struct ApplyWithIndex<0,Func,Tuple>{
  static void apply(Func f,Tuple&&t){}
};
  1. Struct takes the number of elements to print, the function to apply and the tuple as template parameters
  2. Name of struct
  3. A static apply function takes the tuple as r-value reference and function by value
  4. Recurses until number of elements to print are 0
  5. Calls function passing tuple index together with tuple element (notice that tuple element os forwarded)
  6. Struct terminating recursion
  7. When number of tuple elements to process is 0, this template specialization is used
  8. Since number of elements to process are 0 the function does not do anything

It's worth noticing the forwarding both of the tuple as well as of individual tuple elements.

To test the code I'll print out the index of each element of a tuple together with the value:

struct PrintTupleInfo{
  template<typename T>
  void operator()(int ind,T&&t){
    cout<<"index: "<<ind<<", value: "<<t<<endl;
  }
};
// ...
applyWithIndex(PrintTupleInfo{},make_tuple(17,"Hello world"));
The output is:
index: 0, value: 17
index: 1, value: Hello world

As always with C++ meta programming the golden rule is to make sure the code using the template code is compact and simple even though the underlying template code is … let's say, not always pleasing to the eye.

I'll finish this first blog post with a simple utility for printing both type and value information from a tuple. The code is mostly self-explanatory. Demangling works for code compiled using gcc running under Linux. For other compilers and operating systems some other demangling facility will most likely have to be used.

Here is the code:

#include <ostream>
#include <tuple>
#include <cxxabi.h>
#include <type_traits>

// print a variable together with its type 
template<typename T>
void printTypeValue(std::ostream&os,T const&t){
  int status;
  os<<"("<<abi::__cxa_demangle(typeid(T).name(),0,0,&status)<<": "<<t<<")";
} 
// print a tuplet (type and value)
template<int N,typename Tuple>
struct PrintTuple{
  static void print(std::ostream&os,Tuple const&t){
    PrintTuple<N-1,decltype(t)>::print(os,t);
    printTypeValue(os,std::get<N-1>(t));
  } 
};  
template<typename Tuple>
struct PrintTuple<0,Tuple>{
  static void print(std::ostream&os,Tuple const&t){}
};  
// tuplet print operator (no need to have perfect forwarding since tuple can always be const)
template<typename ... Args>
std::ostream&operator<<(std::ostream&os,std::tuple<Args ...>const&t){
  os<<"[";
  PrintTuple<sizeof ... (Args),decltype(t)>::print(os,t);
  return os<<"]";
}

Executing the following code:

cout<<make_tuple(17,"Hello")<<endl;

generates this output:

 [(int: 17)(char const*: Hello)]

In the next blog entry I'll make use of the code developed here to write a few classes that will help me write very compact code for accessing an Oracle database.