17 po::options_description control(
"Rootify SQL");
19 (
"uri,u", var<string>()->required(),
"Database link as in\n\tuser:password@server[:port]/database.")
20 (
"query,q", var<string>(
""),
"MySQL query (overwrites --file)")
21 (
"file", var<string>(
"rootify.sql"),
"An ASCII file with the MySQL query (overwrites --query)")
22 (
"ignore-null,i",
po_switch(),
"Do not skip rows containing any NULL field")
23 (
"out,o", var<string>(
"rootify.root"),
"Output root file name")
24 (
"force,f",
po_switch(),
"Force overwriting an existing root file ('RECREATE')")
25 (
"update",
po_switch(),
"Update an existing root file with the new tree ('UPDATE')")
26 (
"compression,c", var<uint16_t>(1),
"zlib compression level for the root file")
27 (
"tree,t", var<string>(
"Result"),
"Name of the root tree")
28 (
"display,d",
po_switch(),
"Displays contents on the screen (most usefull in combination with mysql statements as SHOW or EXPLAIN)")
29 (
"null,n",
po_switch(),
"Redirect the output file to /dev/null")
30 (
"delimiter", var<string>(
""),
"The delimiter used if contents are displayed with --display (default=\\t)")
31 (
"verbose,v", var<uint16_t>(1),
"Verbosity (0: quiet, 1: default, 2: more, 3, ...)")
34 po::positional_options_description p;
45 "rootifysql - Converts the result of a mysql query into a root file\n" 47 "For convenience, this documentation uses the extended version of the options, " 48 "refer to the output below to get the abbreviations.\n" 50 "Writes the result of a mysql query into a root file. For each column, a branch is " 51 "created of type double with the field name as name. This is usually the column name " 52 "if not specified otherwise by the AS mysql directive.\n" 54 "Columns with CHAR or VARCHAR as field type are ignored. DATETIME, DATE and TIME " 55 "columns are converted to unix time (time_t). Rows containing any file which is " 56 "NULL are skipped if not suppressed by the --ignore-null option. Ideally, the query " 57 "is compiled in a way that no NULL field is returned. With the --display option the " 58 "result of the request is printed on the screen (NULL skipping still in action). " 59 "This can be useful to create an ascii file or to show results as 'SHOW DATABASES' " 60 "or 'EXPLAIN table'. To redirect the contents into an ascii file, the option -v0 " 61 "is useful. To suppredd writing to an output file --null can be used.\n" 63 "The default is to read the query from a file called rootify.sql. Except if a different " 64 "filename is specified by the --file option or a query is given with --query.\n" 66 "Comments in the query-file can be placed according to the SQL standard inline " 67 "/*comment*/ or on individual lines introduces with # or --.\n" 69 "In case of succes, 0 is returned, a value>0 otherwise.\n" 71 "Usage: rootifysql [rootify.sql [rootify.root]] [-u URI] [-q query|-f file] [-i] [-o out] [-f] [-cN] [-t tree] [-vN]\n" 77 int main(
int argc,
const char* 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.
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
po::typed_value< bool > * po_switch()
void SetArgumentPositions(const po::positional_options_description &desc)
void AddOptions(const po::options_description &opt, bool visible=true)
int main(int argc, const char *argv[])
Commandline parsing, resource file parsing and database access.
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())