1 | #include <boost/regex.hpp>
|
---|
2 | #include <boost/algorithm/string/replace.hpp>
|
---|
3 |
|
---|
4 | #include "Database.h"
|
---|
5 |
|
---|
6 | #include "pal.h"
|
---|
7 | #include "nova.h"
|
---|
8 | #include "tools.h"
|
---|
9 | #include "Time.h"
|
---|
10 | #include "Configuration.h"
|
---|
11 |
|
---|
12 | using namespace std;
|
---|
13 |
|
---|
14 | // ------------------------------------------------------------------------
|
---|
15 |
|
---|
16 | void SetupConfiguration(Configuration &conf)
|
---|
17 | {
|
---|
18 | po::options_description control("Calcsource options");
|
---|
19 | control.add_options()
|
---|
20 | ("uri,u", var<string>()
|
---|
21 | #if BOOST_VERSION >= 104200
|
---|
22 | ->required()
|
---|
23 | #endif
|
---|
24 | , "Database link as in\n\tuser:password@server[:port]/database[?compress=0|1].")
|
---|
25 | ("file", var<string>()->required(), "Corsika Input Card")
|
---|
26 | ("force", po_switch(), "Force processing even if there is no database connection")
|
---|
27 | ;
|
---|
28 |
|
---|
29 | po::options_description debug("Debug options");
|
---|
30 | debug.add_options()
|
---|
31 | ("no-insert", po_switch(), "Does not insert or update any data to any table")
|
---|
32 | ("print-insert", po_switch(), "Print the INSERT/REPLACE queries")
|
---|
33 | ("verbose,v", var<uint16_t>(1), "Verbosity (0: quiet, 1: default, 2: more, 3, ...)")
|
---|
34 | ;
|
---|
35 |
|
---|
36 | po::positional_options_description p;
|
---|
37 | p.add("file", 1); // The 1st positional options (n=1)
|
---|
38 |
|
---|
39 | conf.AddOptions(control);
|
---|
40 | conf.AddOptions(debug);
|
---|
41 | conf.SetArgumentPositions(p);
|
---|
42 | }
|
---|
43 |
|
---|
44 | void PrintUsage()
|
---|
45 | {
|
---|
46 | cout <<
|
---|
47 | "corsika2sql - Fill a Corsika Input Card into a SQL table\n"
|
---|
48 | "\n\n"
|
---|
49 | "Usage: corsika2sql input-card [-u URI] [options]\n"
|
---|
50 | "\n"
|
---|
51 | ;
|
---|
52 | cout << endl;
|
---|
53 | }
|
---|
54 |
|
---|
55 | bool ShowWarnings(Database &connection)
|
---|
56 | {
|
---|
57 | try
|
---|
58 | {
|
---|
59 | const auto resw =
|
---|
60 | connection.query("SHOW WARNINGS").store();
|
---|
61 |
|
---|
62 | for (size_t i=0; i<resw.num_rows(); i++)
|
---|
63 | {
|
---|
64 | const mysqlpp::Row &roww = resw[i];
|
---|
65 |
|
---|
66 | cout << roww["Level"] << '[' << roww["Code"] << "]: ";
|
---|
67 | cout << roww["Message"] << '\n';
|
---|
68 | }
|
---|
69 | if (resw.num_rows())
|
---|
70 | cout << endl;
|
---|
71 | return true;
|
---|
72 | }
|
---|
73 | catch (const exception &e)
|
---|
74 | {
|
---|
75 | cerr << "\nSHOW WARNINGS\n\n";
|
---|
76 | cerr << "SQL query failed:\n" << e.what() << '\n' <<endl;
|
---|
77 | return false;
|
---|
78 | }
|
---|
79 | }
|
---|
80 |
|
---|
81 |
|
---|
82 | int main(int argc, const char* argv[])
|
---|
83 | {
|
---|
84 | Time start;
|
---|
85 |
|
---|
86 | Configuration conf(argv[0]);
|
---|
87 | conf.SetPrintUsage(PrintUsage);
|
---|
88 | SetupConfiguration(conf);
|
---|
89 |
|
---|
90 | if (!conf.DoParse(argc, argv))
|
---|
91 | return 127;
|
---|
92 |
|
---|
93 | // ----------------------------- Evaluate options --------------------------
|
---|
94 | const string uri = conf.Get<string>("uri");
|
---|
95 | const string file = conf.Get<string>("file");
|
---|
96 |
|
---|
97 | const bool print_insert = conf.Get<bool>("print-insert");
|
---|
98 |
|
---|
99 | const bool force = conf.Get<bool>("force");
|
---|
100 | const bool noinsert = conf.Get<bool>("no-insert");
|
---|
101 | const uint16_t verbose = conf.Get<uint16_t>("verbose");
|
---|
102 |
|
---|
103 | // -------------------------------------------------------------------------
|
---|
104 | // Checking for database connection
|
---|
105 |
|
---|
106 | Database connection(uri); // Keep alive while fetching rows
|
---|
107 |
|
---|
108 | try
|
---|
109 | {
|
---|
110 | if (!force)
|
---|
111 | connection.connected();
|
---|
112 | }
|
---|
113 | catch (const exception &e)
|
---|
114 | {
|
---|
115 | cerr << "SQL connection failed: " << e.what() << endl;
|
---|
116 | return 1;
|
---|
117 | }
|
---|
118 |
|
---|
119 |
|
---|
120 | // -------------------------------------------------------------------------
|
---|
121 | // create INSERT/UPDATE query (calculate positions)
|
---|
122 |
|
---|
123 | const mysqlpp::StoreQueryResult res =
|
---|
124 | connection.query("EXPLAIN `CorsikaSetup`").store();
|
---|
125 |
|
---|
126 | map<string, uint16_t> fields;
|
---|
127 |
|
---|
128 | for (size_t i=0; i<res.num_rows(); i++)
|
---|
129 | {
|
---|
130 | auto field = string(res[i]["Field"]);
|
---|
131 |
|
---|
132 | int cnt = 0;
|
---|
133 |
|
---|
134 | boost::smatch match;
|
---|
135 | if (boost::regex_match(field, match, boost::regex("([^\\[]+)(\\[([0-9]+)\\])$")))
|
---|
136 | {
|
---|
137 | cnt = stoi(match[3])+1;
|
---|
138 | field = match[1];
|
---|
139 | }
|
---|
140 |
|
---|
141 | if (fields[field]<cnt)
|
---|
142 | fields[field] = cnt;
|
---|
143 | }
|
---|
144 |
|
---|
145 | fields["SEED"] = 3;
|
---|
146 | fields["TELESCOPE"] = 5;
|
---|
147 |
|
---|
148 | // -------------------------------------------------------------------------
|
---|
149 | // evaluate input card
|
---|
150 |
|
---|
151 | vector<string> insert;
|
---|
152 | vector<string> seeds;
|
---|
153 | vector<string> telescopes;
|
---|
154 |
|
---|
155 | string runnr;;
|
---|
156 | string buf;
|
---|
157 |
|
---|
158 | ifstream fin(file);
|
---|
159 |
|
---|
160 | while (getline(fin, buf))
|
---|
161 | {
|
---|
162 | string line = buf;
|
---|
163 | while (1)
|
---|
164 | {
|
---|
165 | boost::replace_all(buf, " ", " ");
|
---|
166 | if (line==buf)
|
---|
167 | break;
|
---|
168 | line = buf;
|
---|
169 | }
|
---|
170 |
|
---|
171 | vector<string> vec = Tools::Split(Tools::Trim(line), " ");
|
---|
172 |
|
---|
173 | const auto it = fields.find(vec[0]);
|
---|
174 | if (it==fields.end())
|
---|
175 | {
|
---|
176 | //if (verbose>1)
|
---|
177 | //cout << "Not found: " << vec[0] << " " << vec.size()-1 << endl;
|
---|
178 | continue;
|
---|
179 | }
|
---|
180 |
|
---|
181 | const uint16_t N = ::max<uint16_t>(1, it->second);
|
---|
182 |
|
---|
183 | if (N<vec.size()-1)
|
---|
184 | {
|
---|
185 | //if (verbose>1)
|
---|
186 | cerr << "Size mismatch: " << vec[0] << " " << N << "<" << vec.size()-1 << endl;
|
---|
187 | return 2;
|
---|
188 | }
|
---|
189 |
|
---|
190 | if (vec[0]=="SEED")
|
---|
191 | {
|
---|
192 | seeds.emplace_back("'"+vec[1]+"','"+vec[2]+"','"+vec[3]+"'");
|
---|
193 | continue;
|
---|
194 | }
|
---|
195 | if (vec[0]=="TELESCOPE")
|
---|
196 | {
|
---|
197 | const auto tel = atoi((vec.size()>5?vec[5]:"0").c_str());
|
---|
198 | telescopes.emplace_back("'"+vec[1]+"','"+vec[2]+"','"+vec[3]+"'"+"'"+vec[4]+"',"+to_string(tel));
|
---|
199 | continue;
|
---|
200 | }
|
---|
201 | if (vec[0]=="RUNNR")
|
---|
202 | runnr = vec[1];
|
---|
203 |
|
---|
204 | for (int i=1; i<N+1; i++)
|
---|
205 | {
|
---|
206 | if (vec[i]=="T")
|
---|
207 | vec[i]="1";
|
---|
208 | if (vec[i]=="F")
|
---|
209 | vec[i]="0";
|
---|
210 | }
|
---|
211 |
|
---|
212 | if (it->second==0)
|
---|
213 | insert.emplace_back("`"+vec[0]+"`='"+vec[1]+"'");
|
---|
214 | else
|
---|
215 | {
|
---|
216 | for (int i=1; i<N+1; i++)
|
---|
217 | insert.emplace_back("`"+vec[0]+"["+to_string(i-1)+"]`='"+vec[i]+"'");
|
---|
218 | }
|
---|
219 | }
|
---|
220 |
|
---|
221 | cout << "RUNNR=" << runnr << " => " << file << endl;
|
---|
222 |
|
---|
223 | // -------------------------------------------------------------------------
|
---|
224 | // insert card data into table
|
---|
225 |
|
---|
226 | const string query1 =
|
---|
227 | "REPLACE CorsikaSetup SET "+boost::join(insert, ",");
|
---|
228 |
|
---|
229 | try
|
---|
230 | {
|
---|
231 | if (!noinsert)
|
---|
232 | {
|
---|
233 | const mysqlpp::SimpleResult res1 =
|
---|
234 | connection.query(query1).execute();
|
---|
235 |
|
---|
236 | if (verbose>0 && res1.info())
|
---|
237 | cout << res1.info() << '\n' << endl;
|
---|
238 | }
|
---|
239 | }
|
---|
240 | catch (const exception &e)
|
---|
241 | {
|
---|
242 | cerr << query1 << "\n\n";
|
---|
243 | cerr << "SQL query (" << query1.length() << " bytes) failed:\n" << e.what() << endl;
|
---|
244 | return 3;
|
---|
245 | }
|
---|
246 |
|
---|
247 | if (print_insert)
|
---|
248 | cout << query1 << endl;
|
---|
249 |
|
---|
250 | if (!ShowWarnings(connection))
|
---|
251 | return 4;
|
---|
252 |
|
---|
253 | // -------------------------------------------------------------------------
|
---|
254 | // insert seed data into table
|
---|
255 |
|
---|
256 | if (!seeds.empty())
|
---|
257 | {
|
---|
258 | int i=0;
|
---|
259 | for (auto it=seeds.begin(); it!=seeds.end(); it++)
|
---|
260 | it->insert(0, runnr+","+to_string(i++)+",");
|
---|
261 |
|
---|
262 | const string query2 =
|
---|
263 | "INSERT CorsikaSeed (RUNNR,idx,`SEED[0]`,`SEED[1]`,`SEED[2]`) VALUES ("+boost::join(seeds, "),(")+")";
|
---|
264 |
|
---|
265 | try
|
---|
266 | {
|
---|
267 |
|
---|
268 | const mysqlpp::SimpleResult res2a =
|
---|
269 | connection.query("DELETE FROM CorsikaSeed WHERE RUNNR="+runnr).execute();
|
---|
270 |
|
---|
271 | if (verbose>0)
|
---|
272 | cout << res2a.info() << '\n' << endl;
|
---|
273 |
|
---|
274 | if (!noinsert)
|
---|
275 | {
|
---|
276 | const mysqlpp::SimpleResult res2b =
|
---|
277 | connection.query(query2).execute();
|
---|
278 |
|
---|
279 | if (verbose>0)
|
---|
280 | cout << res2b.info() << '\n' << endl;
|
---|
281 | }
|
---|
282 | }
|
---|
283 | catch (const exception &e)
|
---|
284 | {
|
---|
285 | cerr << query2 << "\n\n";
|
---|
286 | cerr << "SQL query (" << query2.length() << " bytes) failed:\n" << e.what() << endl;
|
---|
287 | return 5;
|
---|
288 | }
|
---|
289 |
|
---|
290 | if (print_insert)
|
---|
291 | cout << query2 << endl;
|
---|
292 |
|
---|
293 | if (!ShowWarnings(connection))
|
---|
294 | return 6;
|
---|
295 | }
|
---|
296 |
|
---|
297 | // -------------------------------------------------------------------------
|
---|
298 | // insert telescope data into table
|
---|
299 |
|
---|
300 | if (!telescopes.empty())
|
---|
301 | {
|
---|
302 | for (auto it=telescopes.begin(); it!=telescopes.end(); it++)
|
---|
303 | it->insert(0, runnr+",");
|
---|
304 |
|
---|
305 | const string query2 =
|
---|
306 | "INSERT CorsikaTelescope (RUNNR,X,Y,Z,R,ID) VALUES ("+boost::join(telescopes, "),(")+")";
|
---|
307 |
|
---|
308 | try
|
---|
309 | {
|
---|
310 |
|
---|
311 | const mysqlpp::SimpleResult res2a =
|
---|
312 | connection.query("DELETE FROM CorsikaTelescope WHERE RUNNR="+runnr).execute();
|
---|
313 |
|
---|
314 | if (verbose>0)
|
---|
315 | cout << res2a.info() << '\n' << endl;
|
---|
316 |
|
---|
317 | if (!noinsert)
|
---|
318 | {
|
---|
319 | const mysqlpp::SimpleResult res2b =
|
---|
320 | connection.query(query2).execute();
|
---|
321 |
|
---|
322 | if (verbose>0)
|
---|
323 | cout << res2b.info() << '\n' << endl;
|
---|
324 | }
|
---|
325 | }
|
---|
326 | catch (const exception &e)
|
---|
327 | {
|
---|
328 | cerr << query2 << "\n\n";
|
---|
329 | cerr << "SQL query (" << query2.length() << " bytes) failed:\n" << e.what() << endl;
|
---|
330 | return 5;
|
---|
331 | }
|
---|
332 |
|
---|
333 | if (print_insert)
|
---|
334 | cout << query2 << endl;
|
---|
335 |
|
---|
336 | if (!ShowWarnings(connection))
|
---|
337 | return 6;
|
---|
338 | }
|
---|
339 |
|
---|
340 | // -------------------------------------------------------------------------
|
---|
341 |
|
---|
342 | if (verbose>0)
|
---|
343 | {
|
---|
344 | const auto sec = Time().UnixTime()-start.UnixTime();
|
---|
345 | cout << "Total execution time: " << sec << "s\n";
|
---|
346 | }
|
---|
347 |
|
---|
348 | return 0;
|
---|
349 | }
|
---|