FACT++  1.0
int main ( int  argc,
const char *  argv[] 
)

Definition at line 77 of file rootifysql.cc.

References display, Configuration::DoParse(), Configuration::Get(), i, PrintUsage(), Configuration::SetPrintUsage(), SetupConfiguration(), start(), t, Time::UnixTime(), and verbose.

78 {
79  Time start;
80 
81  gROOT->SetBatch();
82 
83  Configuration conf(argv[0]);
84  conf.SetPrintUsage(PrintUsage);
85  SetupConfiguration(conf);
86 
87  if (!conf.DoParse(argc, argv))
88  return 127;
89 
90  // ----------------------------- Evaluate options --------------------------
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");
103  // -------------------------------------------------------------------------
104 
105  if (verbose>0)
106  cout << "\n--------------------- Rootify SQL ----------------------" << endl;
107 
108  string query = conf.Get<string>("query");
109  if (query.empty())
110  {
111  if (verbose>0)
112  cout << "Reading query from file '" << file << "'." << endl;
113 
114  ifstream fin(file);
115  if (!fin)
116  {
117  cerr << "Could not open '" << file << "': " << strerror(errno) << endl;
118  return 1;
119  }
120  getline(fin, query, (char)fin.eof());
121  }
122 
123  if (query.empty())
124  {
125  cerr << "No query specified." << endl;
126  return 2;
127  }
128 
129  // -------------------------- Check for file permssion ---------------------
130  // Strictly speaking, checking for write permission and existance is not necessary,
131  // but it is convenient that the user does not find out that it failed after
132  // waiting long for the query result
133  //
134  // I am using root here instead of boost to be
135  // consistent with the access pattern by TFile
136  TString path(noout?"/dev/null":out.c_str());
137  gSystem->ExpandPathName(path);
138 
139  if (!noout)
140  {
141  FileStat_t stat;
142  const Int_t exist = !gSystem->GetPathInfo(path, stat);
143  const Bool_t write = !gSystem->AccessPathName(path, kWritePermission) && R_ISREG(stat.fMode);
144 
145  if ((update && !exist) || (update && exist && !write) || (force && exist && !write))
146  {
147  cerr << "File '" << path << "' is not writable." << endl;
148  return 3;
149  }
150 
151  if (!update && !force && exist)
152  {
153  cerr << "File '" << path << "' already exists." << endl;
154  return 4;
155  }
156  }
157  // -------------------------------------------------------------------------
158 
159  if (query.back()!='\n')
160  query += '\n';
161 
162  if (verbose>2)
163  cout << '\n' << query << endl;
164 
165  if (verbose>0)
166  cout << "Requesting data..." << endl;
167 
168  Time start2;
169 
170  // -------------------------- Request data from database -------------------
171  const mysqlpp::StoreQueryResult res =
172  Database(uri).query(query).store();
173  // -------------------------------------------------------------------------
174 
175  if (verbose>0)
176  {
177  cout << res.size() << " rows received." << endl;
178  cout << "Query time: " << Time().UnixTime()-start2.UnixTime() << "s" << endl;
179  }
180 
181  if (res.empty())
182  {
183  cerr << "Nothing to write." << endl;
184  return 5;
185  }
186 
187  if (verbose>0)
188  cout << "Opening file '" << path << "' [compression=" << compression << "]..." << endl;
189 
190  // ----------------------------- Open output file --------------------------
191  TFile tfile(path, update?"UPDATE":(force?"RECREATE":"CREATE"), "Rootify SQL", compression);
192  if (tfile.IsZombie())
193  return 6;
194  // -------------------------------------------------------------------------
195 
196  const mysqlpp::Row &r = res.front();
197 
198  if (verbose>0)
199  cout << "Trying to setup " << r.size() << " branches..." << endl;
200 
201  if (verbose>1)
202  cout << endl;
203 
204  const mysqlpp::FieldNames &l = *r.field_list().list;
205 
206  vector<double> buf(l.size());
207  vector<uint8_t> typ(l.size(),'n');
208 
209  UInt_t cols = 0;
210 
211  // -------------------- Configure branches of TTree ------------------------
212  TTree *ttree = new TTree(tree.c_str(), query.c_str());
213  for (size_t i=0; i<l.size(); i++)
214  {
215  const string t = r[i].type().sql_name();
216 
217  if (t.find("DATETIME")!=string::npos)
218  typ[i] = 'd';
219  else
220  if (t.find("DATE")!=string::npos)
221  typ[i] = 'D';
222  else
223  if (t.find("TIME")!=string::npos)
224  typ[i] = 'T';
225  else
226  if (t.find("VARCHAR")!=string::npos)
227  typ[i] = 'V';
228  else
229  if (t.find("CHAR")!=string::npos)
230  typ[i] = 'C';
231 
232  const bool use = typ[i]!='V' && typ[i]!='C';
233 
234  if (verbose>1)
235  cout << (use?" + ":" - ") << l[i].c_str() << " [" << t << "] {" << typ[i] << "}\n";
236 
237  if (use)
238  {
239  ttree->Branch(l[i].c_str(), buf.data()+i);
240  cols++;
241  }
242  }
243  // -------------------------------------------------------------------------
244 
245  if (verbose>1)
246  cout << endl;
247  if (verbose>0)
248  cout << "Configured " << cols << " branches.\nFilling branches..." << endl;
249 
250  if (display)
251  {
252  cout << endl;
253  cout << "#";
254  for (size_t i=0; i<l.size(); i++)
255  cout << ' ' << l[i].c_str();
256  cout << endl;
257  }
258 
259  // ---------------------- Fill TTree with DB data --------------------------
260  size_t skip = 0;
261  for (auto row=res.begin(); row<res.end(); row++)
262  {
263  ostringstream sout;
264 
265  size_t idx=0;
266  for (auto col=row->begin(); col!=row->end(); col++, idx++)
267  {
268  if (display)
269  {
270  if (idx>0)
271  sout << (delimiter.empty()?"\t":delimiter);
272  sout << col->c_str();
273  }
274 
275  if (!ignore && col->is_null())
276  {
277  skip++;
278  break;
279  }
280 
281  switch (typ[idx])
282  {
283  case 'd':
284  buf[idx] = time_t((mysqlpp::DateTime)(*col));
285  break;
286 
287  case 'D':
288  buf[idx] = time_t((mysqlpp::Date)(*col));
289  break;
290 
291  case 'T':
292  buf[idx] = time_t((mysqlpp::Time)(*col));
293  break;
294 
295  case 'V':
296  case 'C':
297  break;
298 
299  default:
300  buf[idx] = atof(col->c_str());
301  }
302  }
303 
304  if (idx==row->size())
305  {
306  ttree->Fill();
307  if (display)
308  cout << sout.str() << endl;
309  }
310  }
311  // -------------------------------------------------------------------------
312 
313  if (display)
314  cout << '\n' << endl;
315 
316  if (verbose>0)
317  {
318  if (skip>0)
319  cout << skip << " rows skipped due to NULL field." << endl;
320 
321  cout << ttree->GetEntries() << " rows filled into tree." << endl;
322  }
323 
324  ttree->Write();
325  tfile.Close();
326 
327  if (verbose>0)
328  {
329  cout << "File closed.\n";
330  cout << "Execution time: " << Time().UnixTime()-start.UnixTime() << "s\n";
331  cout << "--------------------------------------------------------" << endl;
332  }
333 
334  return 0;
335 }
int start(int initState)
Definition: feeserver.c:1740
void SetupConfiguration(Configuration &conf)
Definition: rootifysql.cc:15
int i
Definition: db_dim_client.c:21
Adds some functionality to boost::posix_time::ptime for our needs.
Definition: Time.h:30
void PrintUsage()
Definition: rootifysql.cc:42
Display * display
Definition: did.h:37
double UnixTime() const
Definition: Time.cc:195
Commandline parsing, resource file parsing and database access.
Definition: Configuration.h:9
TT t
Definition: test_client.c:26
static int verbose
Definition: t_erfa_c.c:4

+ Here is the call graph for this function: