Changeset 19966


Ignore:
Timestamp:
May 26, 2020, 8:20:25 PM (3 months ago)
Author:
tbretz
Message:
Added an accurate mode in which all SQL column types are converted as accurately as possible.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/FACT++/src/rootifysql.cc

    r19802 r19966  
    99#include "Time.h"
    1010#include "Splitting.h"
     11#include "FileEntry.h"
    1112
    1213#include <TROOT.h>
     
    5556        ("compression,c", var<uint16_t>(1),            "zlib compression level for the root file")
    5657        ("tree,t",        var<string>("Result"),       "Name of the root tree")
     58        ("accurate",      po_switch(),                 "Accurate type conversion, otherwise all branches are creates as double which is often more convenient.")
    5759        ("ignore",        vars<string>(),              "Ignore the given columns")
    5860        ("null,n",        po_switch(),                 "Redirect the root output file to /dev/null (mainly for debugging purposes, e.g. performance studies)")
     
    464466}
    465467
     468template<typename T>
     469void Convert(FileEntry::Container &container, const mysqlpp::String &col)
     470{
     471    *reinterpret_cast<T*>(container.ptr) = static_cast<T>(col);
     472}
     473
     474
    466475int main(int argc, const char* argv[])
    467476{
     
    491500    const bool     explain     = conf.Get<bool>("explain");
    492501    const bool     profiling   = conf.Get<bool>("profiling");
     502    const bool     accurate    = conf.Get<bool>("accurate");
    493503    const uint16_t verbose     = conf.Get<uint16_t>("verbose");
    494504    const uint16_t compression = conf.Get<uint16_t>("compression");
     
    810820    const mysqlpp::FieldNames &l = *row.field_list().list;
    811821
    812     vector<double>  buf(l.size());
    813     vector<uint8_t> typ(l.size(),'n'); // n=number [double], d is used for DateTime
     822    vector<FileEntry::Container> container;
    814823
    815824    UInt_t cols = 0;
     
    834843            ttree.emplace_back(new TTree((tree+"["+to_string(i)+"]").c_str(), query.c_str()));
    835844
     845    size_t skipno  = 0;
    836846    size_t skipat  = 0;
    837847    size_t skipreg = 0;
     848    size_t skipch  = 0;
    838849    for (size_t i=0; i<l.size(); i++)
    839850    {
    840         const string t = row[i].type().sql_name();
    841 
    842         if (t.find("DATETIME")!=string::npos)
    843             typ[i] = 'd';
     851        string t = row[i].type().sql_name();
     852
     853        bool skip = false;
     854
     855        // Remove trailing " NULL"
     856        if (t.find(" NOT NULL")==t.size()-9)
     857            t = t.substr(0, t.size()-9);
     858        if (t.find(" NULL")==t.size()-5)
     859            t = t.substr(0, t.size()-5);
     860
     861        // Get FileEntry description corresponding to the sql type
     862        const auto it = FileEntry::LUT.sql(t);
     863
     864        // Skip all columns that do not follow a convertible type
     865        if (it==FileEntry::LUT.end())
     866        {
     867            skip = true;
     868            skipno++;
     869        }
     870
     871        // For valid colums, check if they are of a type that can not be written to a root file
     872        if (!skip && (it->type==FileEntry::kVarchar || it->type==FileEntry::kChar))
     873        {
     874            skip = true;
     875            skipch++;
     876        }
     877
     878        // Check if there is any user request for skipping a column
     879        if (!skip)
     880        {
     881            for (auto pattern=_ignore.cbegin(); pattern!=_ignore.cend(); pattern++)
     882            {
     883                if (boost::regex_match(l[i], boost::regex(*pattern)))
     884                {
     885                    skip = true;
     886                    skipreg++;
     887                    break;
     888                }
     889            }
     890        }
     891
     892        // Skip all columns that start with an @ (variable names)
     893        if (!skip && l[i][0]=='@')
     894        {
     895            skip = true;
     896            skipat++;
     897        }
     898
     899        // Create the 'leaflist'. If no accurate conversion is requested, create doubles for all leaves
     900        const string leaflist = l[i] + "/" + (accurate ? it->branch : 'D');
     901
     902        if (verbose>1)
     903            cout << (skip?" - ":" + ") << branch.c_str() << " [" << t << "] {" << (it==FileEntry::LUT.end()?'-':it->branch) << "}\n";
     904
     905        // Create the container entry (must be emplace_back due to the std::string)
     906        if (accurate)
     907            container.emplace_back(leaflist, it->type);
    844908        else
    845             if (t.find("DATE")!=string::npos)
    846                 typ[i] = 'D';
    847             else
    848                 if (t.find("TIME")!=string::npos)
    849                     typ[i] = 'T';
    850                 else
    851                     if (t.find("VARCHAR")!=string::npos)
    852                         typ[i] = 'V';
    853                     else
    854                         if (t.find("CHAR")!=string::npos)
    855                             typ[i] = 'C';
    856 
    857         bool found = false;
    858         for (auto pattern=_ignore.cbegin(); pattern!=_ignore.cend(); pattern++)
    859         {
    860             if (boost::regex_match(l[i], boost::regex(*pattern)))
    861             {
    862                 found = true;
    863                 typ[i] = '-';
    864                 skipreg++;
    865                 break;
    866             }
    867         }
    868 
    869         if (l[i][0]=='@')
    870         {
    871             typ[i] = '@';
    872             skipat++;
    873         }
    874 
    875         const bool use = l[i][0]!='@' && typ[i]!='V' && typ[i]!='C' && !found;
    876 
    877         if (verbose>1)
    878             cout << (use?" + ":" - ") << l[i].c_str() << " [" << t << "] {" << typ[i] << "}\n";
    879 
    880         if (use)
    881         {
    882             // string name = l[i];
    883             // for (const auto &m: mymap)
    884             //     name = boost::regex_replace(l[i], boost::regex(m.first), m.second);
    885 
    886             for (auto it=ttree.begin(); it!=ttree.end(); it++)
    887                 it[0]->Branch(l[i].c_str(), buf.data()+i);
    888             cols++;
    889         }
     909            container.emplace_back(leaflist, "", it->type);
     910
     911        if (skip)
     912            continue;
     913
     914        // Create corresponding branches in all trees
     915        for (auto itree=ttree.begin(); itree!=ttree.end(); itree++)
     916            itree[0]->Branch(l[i].c_str(), container[i].ptr, branch.c_str());
     917
     918        cols++;
    890919    }
    891920    // -------------------------------------------------------------------------
     
    895924    if (verbose>0)
    896925    {
     926        if (skipno)
     927            cout << skipno << " branches skipped because no suitable type available." << endl;
     928        if (skipch)
     929            cout << skipch << " branches skipped because type is a character string." << endl;
    897930        if (skipreg)
    898931            cout << skipreg << " branches skipped due to ignore list." << endl;
     
    9941027            }
    9951028
    996             switch (typ[idx])
     1029            if (accurate)
    9971030            {
    998             case 'd':
    999                 buf[idx] = time_t((mysqlpp::DateTime)(*col));
    1000                 break;
    1001 
    1002             case 'D':
    1003                 buf[idx] = time_t((mysqlpp::Date)(*col));
    1004                 break;
    1005 
    1006             case 'T':
    1007                 buf[idx] = time_t((mysqlpp::Time)(*col));
    1008                 break;
    1009 
    1010             case 'V':
    1011             case 'C':
    1012             case '-':
    1013             case '@':
    1014                 break;
    1015 
    1016             default:
    1017                 buf[idx] = atof(col->c_str());
     1031                // Do an accurate type conversion and assign to the memory allocated as branch-address
     1032                switch (container[idx].type)
     1033                {
     1034                case FileEntry::kBool:   Convert<bool>    (container[idx], *col); break;
     1035                case FileEntry::kFloat:  Convert<float>   (container[idx], *col); break;
     1036                case FileEntry::kDecimal:
     1037                case FileEntry::kNumeric:
     1038                case FileEntry::kDouble: Convert<double>  (container[idx], *col); break;
     1039                case FileEntry::kUInt64: Convert<uint64_t>(container[idx], *col); break;
     1040                case FileEntry::kInt64:  Convert<int64_t> (container[idx], *col); break;
     1041                case FileEntry::kUInt32: Convert<uint32_t>(container[idx], *col); break;
     1042                case FileEntry::kInt32:  Convert<int32_t> (container[idx], *col); break;
     1043                case FileEntry::kUInt16: Convert<uint16_t>(container[idx], *col); break;
     1044                case FileEntry::kInt16:  Convert<int16_t> (container[idx], *col); break;
     1045                case FileEntry::kUInt8:  Convert<uint8_t> (container[idx], *col); break;
     1046                case FileEntry::kInt8:   
     1047                case FileEntry::kDate:
     1048                    *reinterpret_cast<uint64_t*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::Date(*col));
     1049                    break;
     1050                case FileEntry::kDateTime:
     1051                    *reinterpret_cast<uint64_t*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::DateTime(*col));
     1052                    break;
     1053                case FileEntry::kTime:
     1054                    *reinterpret_cast<uint32_t*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::Time(*col));
     1055                    break;
     1056                default:
     1057                    break;
     1058                }
     1059            }
     1060            else
     1061            {
     1062                // Convert everything to double, no matter what... and assign to the memory allocated as branch-address
     1063                switch (container[idx].type)
     1064                {
     1065                case FileEntry::kBool:
     1066                case FileEntry::kFloat:
     1067                case FileEntry::kDecimal:
     1068                case FileEntry::kNumeric:
     1069                case FileEntry::kDouble:
     1070                case FileEntry::kUInt64:
     1071                case FileEntry::kInt64:
     1072                case FileEntry::kUInt32:
     1073                case FileEntry::kInt32:
     1074                case FileEntry::kUInt16:
     1075                case FileEntry::kInt16:
     1076                case FileEntry::kUInt8:
     1077                case FileEntry::kInt8:
     1078                    Convert<double>(container[idx], *col);
     1079                    break;
     1080                case FileEntry::kDate:
     1081                    *reinterpret_cast<double*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::Date(*col));
     1082                    break;
     1083                case FileEntry::kDateTime:
     1084                    *reinterpret_cast<double*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::DateTime(*col));
     1085                    break;
     1086                case FileEntry::kTime:
     1087                    *reinterpret_cast<double*>(container[idx].ptr) = static_cast<time_t>(mysqlpp::Time(*col));
     1088                    break;
     1089                default:
     1090                    break;
     1091                }
    10181092            }
    10191093        }
Note: See TracChangeset for help on using the changeset viewer.