| 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 | }
|
|---|