Index: trunk/FACT++/src/rootifysql.cc
===================================================================
--- trunk/FACT++/src/rootifysql.cc	(revision 19965)
+++ trunk/FACT++/src/rootifysql.cc	(revision 19966)
@@ -9,4 +9,5 @@
 #include "Time.h"
 #include "Splitting.h"
+#include "FileEntry.h"
 
 #include <TROOT.h>
@@ -55,4 +56,5 @@
         ("compression,c", var<uint16_t>(1),            "zlib compression level for the root file")
         ("tree,t",        var<string>("Result"),       "Name of the root tree")
+        ("accurate",      po_switch(),                 "Accurate type conversion, otherwise all branches are creates as double which is often more convenient.")
         ("ignore",        vars<string>(),              "Ignore the given columns")
         ("null,n",        po_switch(),                 "Redirect the root output file to /dev/null (mainly for debugging purposes, e.g. performance studies)")
@@ -464,4 +466,11 @@
 }
 
+template<typename T>
+void Convert(FileEntry::Container &container, const mysqlpp::String &col)
+{
+    *reinterpret_cast<T*>(container.ptr) = static_cast<T>(col);
+}
+
+
 int main(int argc, const char* argv[])
 {
@@ -491,4 +500,5 @@
     const bool     explain     = conf.Get<bool>("explain");
     const bool     profiling   = conf.Get<bool>("profiling");
+    const bool     accurate    = conf.Get<bool>("accurate");
     const uint16_t verbose     = conf.Get<uint16_t>("verbose");
     const uint16_t compression = conf.Get<uint16_t>("compression");
@@ -810,6 +820,5 @@
     const mysqlpp::FieldNames &l = *row.field_list().list;
 
-    vector<double>  buf(l.size());
-    vector<uint8_t> typ(l.size(),'n'); // n=number [double], d is used for DateTime
+    vector<FileEntry::Container> container;
 
     UInt_t cols = 0;
@@ -834,58 +843,78 @@
             ttree.emplace_back(new TTree((tree+"["+to_string(i)+"]").c_str(), query.c_str()));
 
+    size_t skipno  = 0;
     size_t skipat  = 0;
     size_t skipreg = 0;
+    size_t skipch  = 0;
     for (size_t i=0; i<l.size(); i++)
     {
-        const string t = row[i].type().sql_name();
-
-        if (t.find("DATETIME")!=string::npos)
-            typ[i] = 'd';
+        string t = row[i].type().sql_name();
+
+        bool skip = false;
+
+        // Remove trailing " NULL"
+        if (t.find(" NOT NULL")==t.size()-9)
+            t = t.substr(0, t.size()-9);
+        if (t.find(" NULL")==t.size()-5)
+            t = t.substr(0, t.size()-5);
+
+        // Get FileEntry description corresponding to the sql type
+        const auto it = FileEntry::LUT.sql(t);
+
+        // Skip all columns that do not follow a convertible type
+        if (it==FileEntry::LUT.end())
+        {
+            skip = true;
+            skipno++;
+        }
+
+        // For valid colums, check if they are of a type that can not be written to a root file
+        if (!skip && (it->type==FileEntry::kVarchar || it->type==FileEntry::kChar))
+        {
+            skip = true;
+            skipch++;
+        }
+
+        // Check if there is any user request for skipping a column
+        if (!skip)
+        {
+            for (auto pattern=_ignore.cbegin(); pattern!=_ignore.cend(); pattern++)
+            {
+                if (boost::regex_match(l[i], boost::regex(*pattern)))
+                {
+                    skip = true;
+                    skipreg++;
+                    break;
+                }
+            }
+        }
+
+        // Skip all columns that start with an @ (variable names)
+        if (!skip && l[i][0]=='@')
+        {
+            skip = true;
+            skipat++;
+        }
+
+        // Create the 'leaflist'. If no accurate conversion is requested, create doubles for all leaves
+        const string leaflist = l[i] + "/" + (accurate ? it->branch : 'D');
+
+        if (verbose>1)
+            cout << (skip?" - ":" + ") << branch.c_str() << " [" << t << "] {" << (it==FileEntry::LUT.end()?'-':it->branch) << "}\n";
+
+        // Create the container entry (must be emplace_back due to the std::string)
+        if (accurate)
+            container.emplace_back(leaflist, it->type);
         else
-            if (t.find("DATE")!=string::npos)
-                typ[i] = 'D';
-            else
-                if (t.find("TIME")!=string::npos)
-                    typ[i] = 'T';
-                else
-                    if (t.find("VARCHAR")!=string::npos)
-                        typ[i] = 'V';
-                    else
-                        if (t.find("CHAR")!=string::npos)
-                            typ[i] = 'C';
-
-        bool found = false;
-        for (auto pattern=_ignore.cbegin(); pattern!=_ignore.cend(); pattern++)
-        {
-            if (boost::regex_match(l[i], boost::regex(*pattern)))
-            {
-                found = true;
-                typ[i] = '-';
-                skipreg++;
-                break;
-            }
-        }
-
-        if (l[i][0]=='@')
-        {
-            typ[i] = '@';
-            skipat++;
-        }
-
-        const bool use = l[i][0]!='@' && typ[i]!='V' && typ[i]!='C' && !found;
-
-        if (verbose>1)
-            cout << (use?" + ":" - ") << l[i].c_str() << " [" << t << "] {" << typ[i] << "}\n";
-
-        if (use)
-        {
-            // string name = l[i];
-            // for (const auto &m: mymap)
-            //     name = boost::regex_replace(l[i], boost::regex(m.first), m.second);
-
-            for (auto it=ttree.begin(); it!=ttree.end(); it++)
-                it[0]->Branch(l[i].c_str(), buf.data()+i);
-            cols++;
-        }
+            container.emplace_back(leaflist, "", it->type);
+
+        if (skip)
+            continue;
+
+        // Create corresponding branches in all trees
+        for (auto itree=ttree.begin(); itree!=ttree.end(); itree++)
+            itree[0]->Branch(l[i].c_str(), container[i].ptr, branch.c_str());
+
+        cols++;
     }
     // -------------------------------------------------------------------------
@@ -895,4 +924,8 @@
     if (verbose>0)
     {
+        if (skipno)
+            cout << skipno << " branches skipped because no suitable type available." << endl;
+        if (skipch)
+            cout << skipch << " branches skipped because type is a character string." << endl;
         if (skipreg)
             cout << skipreg << " branches skipped due to ignore list." << endl;
@@ -994,26 +1027,67 @@
             }
 
-            switch (typ[idx])
+            if (accurate)
             {
-            case 'd':
-                buf[idx] = time_t((mysqlpp::DateTime)(*col));
-                break;
-
-            case 'D':
-                buf[idx] = time_t((mysqlpp::Date)(*col));
-                break;
-
-            case 'T':
-                buf[idx] = time_t((mysqlpp::Time)(*col));
-                break;
-
-            case 'V':
-            case 'C':
-            case '-':
-            case '@':
-                break;
-
-            default:
-                buf[idx] = atof(col->c_str());
+                // Do an accurate type conversion and assign to the memory allocated as branch-address
+                switch (container[idx].type)
+                {
+                case FileEntry::kBool:   Convert<bool>    (container[idx], *col); break;
+                case FileEntry::kFloat:  Convert<float>   (container[idx], *col); break;
+                case FileEntry::kDecimal:
+                case FileEntry::kNumeric:
+                case FileEntry::kDouble: Convert<double>  (container[idx], *col); break;
+                case FileEntry::kUInt64: Convert<uint64_t>(container[idx], *col); break;
+                case FileEntry::kInt64:  Convert<int64_t> (container[idx], *col); break;
+                case FileEntry::kUInt32: Convert<uint32_t>(container[idx], *col); break;
+                case FileEntry::kInt32:  Convert<int32_t> (container[idx], *col); break;
+                case FileEntry::kUInt16: Convert<uint16_t>(container[idx], *col); break;
+                case FileEntry::kInt16:  Convert<int16_t> (container[idx], *col); break;
+                case FileEntry::kUInt8:  Convert<uint8_t> (container[idx], *col); break;
+                case FileEntry::kInt8:   
+                case FileEntry::kDate:
+                    *reinterpret_cast<uint64_t*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::Date(*col));
+                    break;
+                case FileEntry::kDateTime:
+                    *reinterpret_cast<uint64_t*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::DateTime(*col));
+                    break;
+                case FileEntry::kTime:
+                    *reinterpret_cast<uint32_t*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::Time(*col));
+                    break;
+                default:
+                    break;
+                }
+            }
+            else
+            {
+                // Convert everything to double, no matter what... and assign to the memory allocated as branch-address
+                switch (container[idx].type)
+                {
+                case FileEntry::kBool:
+                case FileEntry::kFloat:
+                case FileEntry::kDecimal:
+                case FileEntry::kNumeric:
+                case FileEntry::kDouble:
+                case FileEntry::kUInt64:
+                case FileEntry::kInt64:
+                case FileEntry::kUInt32:
+                case FileEntry::kInt32:
+                case FileEntry::kUInt16:
+                case FileEntry::kInt16:
+                case FileEntry::kUInt8:
+                case FileEntry::kInt8:
+                    Convert<double>(container[idx], *col);
+                    break;
+                case FileEntry::kDate:
+                    *reinterpret_cast<double*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::Date(*col));
+                    break;
+                case FileEntry::kDateTime:
+                    *reinterpret_cast<double*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::DateTime(*col));
+                    break;
+                case FileEntry::kTime:
+                    *reinterpret_cast<double*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::Time(*col));
+                    break;
+                default:
+                    break;
+                }
             }
         }
