87 if (!conf.DoParse(argc, argv))
91 const string uri = conf.Get<
string>(
"uri");
92 const string out = conf.Get<
string>(
"out");
93 const string file = conf.Get<
string>(
"file");
94 const string tree = conf.Get<
string>(
"tree");
95 const bool force = conf.Get<
bool>(
"force");
96 const bool ignore = conf.Get<
bool>(
"ignore-null");
97 const bool update = conf.Get<
bool>(
"update");
98 const bool display = conf.Get<
bool>(
"display");
99 const bool noout = conf.Get<
bool>(
"null");
100 const uint16_t
verbose = conf.Get<uint16_t>(
"verbose");
101 const uint16_t compression = conf.Get<uint16_t>(
"compression");
102 const string delimiter = conf.Get<
string>(
"delimiter");
106 cout <<
"\n--------------------- Rootify SQL ----------------------" << endl;
108 string query = conf.Get<
string>(
"query");
112 cout <<
"Reading query from file '" << file <<
"'." << endl;
117 cerr <<
"Could not open '" << file <<
"': " << strerror(errno) << endl;
120 getline(fin, query, (
char)fin.eof());
125 cerr <<
"No query specified." << endl;
136 TString path(noout?
"/dev/null":out.c_str());
137 gSystem->ExpandPathName(path);
142 const Int_t exist = !gSystem->GetPathInfo(path, stat);
143 const Bool_t write = !gSystem->AccessPathName(path, kWritePermission) && R_ISREG(stat.fMode);
145 if ((update && !exist) || (update && exist && !write) || (force && exist && !write))
147 cerr <<
"File '" << path <<
"' is not writable." << endl;
151 if (!update && !force && exist)
153 cerr <<
"File '" << path <<
"' already exists." << endl;
159 if (query.back()!=
'\n')
163 cout <<
'\n' << query << endl;
166 cout <<
"Requesting data..." << endl;
171 const mysqlpp::StoreQueryResult res =
177 cout << res.size() <<
" rows received." << endl;
183 cerr <<
"Nothing to write." << endl;
188 cout <<
"Opening file '" << path <<
"' [compression=" << compression <<
"]..." << endl;
191 TFile tfile(path, update?
"UPDATE":(force?
"RECREATE":
"CREATE"),
"Rootify SQL", compression);
192 if (tfile.IsZombie())
196 const mysqlpp::Row &r = res.front();
199 cout <<
"Trying to setup " << r.size() <<
" branches..." << endl;
204 const mysqlpp::FieldNames &l = *r.field_list().list;
206 vector<double> buf(l.size());
207 vector<uint8_t> typ(l.size(),
'n');
212 TTree *ttree =
new TTree(tree.c_str(), query.c_str());
213 for (
size_t i=0;
i<l.size();
i++)
215 const string t = r[
i].type().sql_name();
217 if (t.find(
"DATETIME")!=string::npos)
220 if (t.find(
"DATE")!=string::npos)
223 if (t.find(
"TIME")!=string::npos)
226 if (t.find(
"VARCHAR")!=string::npos)
229 if (t.find(
"CHAR")!=string::npos)
232 const bool use = typ[
i]!=
'V' && typ[
i]!=
'C';
235 cout << (use?
" + ":
" - ") << l[
i].c_str() <<
" [" << t <<
"] {" << typ[
i] <<
"}\n";
239 ttree->Branch(l[
i].c_str(), buf.data()+
i);
248 cout <<
"Configured " << cols <<
" branches.\nFilling branches..." << endl;
254 for (
size_t i=0;
i<l.size();
i++)
255 cout <<
' ' << l[
i].c_str();
261 for (
auto row=res.begin(); row<res.end(); row++)
266 for (
auto col=row->begin(); col!=row->end(); col++, idx++)
271 sout << (delimiter.empty()?
"\t":delimiter);
272 sout << col->c_str();
275 if (!ignore && col->is_null())
284 buf[idx] = time_t((mysqlpp::DateTime)(*col));
288 buf[idx] = time_t((mysqlpp::Date)(*col));
292 buf[idx] = time_t((mysqlpp::Time)(*col));
300 buf[idx] = atof(col->c_str());
304 if (idx==row->size())
308 cout << sout.str() << endl;
314 cout <<
'\n' << endl;
319 cout << skip <<
" rows skipped due to NULL field." << endl;
321 cout << ttree->GetEntries() <<
" rows filled into tree." << endl;
329 cout <<
"File closed.\n";
331 cout <<
"--------------------------------------------------------" << endl;
void SetupConfiguration(Configuration &conf)
Adds some functionality to boost::posix_time::ptime for our needs.
Commandline parsing, resource file parsing and database access.