source: trunk/FACT++/src/fits2sql.cc@ 19140

Last change on this file since 19140 was 19140, checked in by tbretz, 7 years ago
Fixed some compiler wanring with gcc.
File size: 25.5 KB
Line 
1#include <boost/algorithm/string/join.hpp>
2#include <boost/regex.hpp>
3
4#include "Database.h"
5
6#include "tools.h"
7#include "Time.h"
8#include "Configuration.h"
9
10#include "zfits.h"
11
12using namespace std;
13
14// ------------------------------------------------------------------------
15
16struct Map : pair<string, string>
17{
18 Map() { }
19};
20
21std::istream &operator>>(std::istream &in, Map &m)
22{
23 const istreambuf_iterator<char> eos;
24 string txt(istreambuf_iterator<char>(in), eos);
25
26 const boost::regex expr("((.*)[^\\\\])/(.*)");
27 boost::smatch match;
28 if (!boost::regex_match(txt, match, expr))
29 throw runtime_error("Could not evaluate map argument: "+txt);
30
31 m.first = match[1].str();
32 m.second = match[3].str();
33
34 return in;
35}
36
37
38void SetupConfiguration(Configuration &conf)
39{
40 po::options_description control("Root to SQL");
41 control.add_options()
42 ("uri,u", var<string>()
43#if BOOST_VERSION >= 104200
44 ->required()
45#endif
46 , "Database link as in\n\tuser:password@server[:port]/database[?compress=0|1].")
47 ("file", var<string>("")
48#if BOOST_VERSION >= 104200
49 ->required()
50#endif
51 , "The root file to read from")
52 ("force", po_switch(), "Force processing even if there is no database connection")
53 ("create", po_switch(), "Create the database if not existing")
54 ("drop", po_switch(), "Drop the table (implies create)")
55 ("extension,e", var<string>(""), "Name of the fits extension (table) to convert")
56 ("table", var<string>(""), "Name of the table to use (default is the tree name)")
57 ("map", vars<Map>(), "A regular expression which is applied to the leaf name befoee it is used as SQL column name)")
58 ("sql-type", vars<Map>(), "Allows to overwrite the calculated SQL type for a given column e.g. 'sql-column-name/UNSIGNED IN'")
59 ("ignore", vars<string>(), "Ignore the given leaf, if the given regular expression matches")
60 ("unsigned", vars<string>(), "In fits files per default columns are signed. This interpretss the column as unsigned value. Use the FITS column name.")
61 ("primary", vars<string>(), "List of columns to be used as primary keys during table creation (in connection with --create)")
62 ("first", var<size_t>(size_t(0)), "First event to start with (default: 0), mainly for test purpose")
63 ("max", var<size_t>(size_t(0)), "Maximum number of events to process (0: all), mainly for test purpose")
64 ("engine", var<string>(""), "Database engine to be used when a new table is created")
65 ("row-format", var<string>(""), "Defines the ROW_FORMAT keyword for table creation")
66 ("duplicate", vars<string>(), "Specifies an assignment_list for an 'ON DUPLICATE KEY UPDATE' expression")
67 ("ignore-errors", po_switch(), "Adds the IGNORE keyword to the INSERT query (turns errors into warnings, ignores rows with errors)")
68 ;
69
70 po::options_description debug("Debug options");
71 debug.add_options()
72 ("no-insert", po_switch(), "Does not insert any data into the table")
73 ("dry-run", po_switch(), "Skip any query which changes the databse (might result in consecutive failures)")
74 ("print-extensions", po_switch(), "Print extensions (tables) from fits file")
75 ("print-connection", po_switch(), "Print database connection information")
76 ("print-columns", po_switch(), "Print columns in fits table")
77 ("print-insert", po_switch(), "Print the INSERT query (note that it contains all data)")
78 ("print-create", po_switch(), "Print the CREATE query")
79 ("verbose,v", var<uint16_t>(1), "Verbosity (0: quiet, 1: default, 2: more, 3, ...)")
80 ;
81
82 po::positional_options_description p;
83 p.add("file", 1); // The 1st positional options (n=1)
84
85 conf.AddOptions(control);
86 conf.AddOptions(debug);
87 conf.SetArgumentPositions(p);
88}
89
90void PrintUsage()
91{
92 cout <<
93 "fits2sql - Fills the data from a fits file into a database\n"
94 "\n"
95 "For convenience, this documentation uses the extended version of the options, "
96 "refer to the output below to get the abbreviations.\n"
97 "\n"
98 "This is a general purpose tool to fill the contents of a fite file into a database.\n"
99 "\n"
100 "Each fits file contians several table, so called extenbsions. Each tables has "
101 "a number of columns compilsed from basic data types. The default extension to "
102 "read from is the first one on the file but the name can be overwritten using "
103 "--extension. The default table name to fill the data into is identical to "
104 "the extension name. It can be overwritten using --table.\n"
105 "\n"
106 "The name of each column to which data is filled is obtained from "
107 "the fits column names. The column names can be checked using --print-columns. "
108 "Sometimes these names might not be convenient. To allow to simplify or replace "
109 "column names, regular expressions (using boost's regex) can be defined to change "
110 "the names. Note that these regular expressions are applied one by one on each "
111 "columns's name. A valid expression could "
112 "be:\n"
113 " --map=MHillas\\.f/\n"
114 "which would remove all occurances of 'MHillas.f'. This option can be used more than "
115 "once. They are applied in sequence. A single match does not stop the sequence.\n"
116 "\n"
117 "Sometimes it might also be convenient to skip a column. This can be done with "
118 "the --ignore resource. If the given regular expresion yields a match, the "
119 "column will be ignored. Note that the regular expression works on the raw-name "
120 "of the column not the readily mapped SQL column names. Example:\n"
121 " --ignore=ThetaSq\\..*\n"
122 "will skip all leaved which start with 'ThetaSq.'. This option can be used"
123 "more than once.\n"
124 "\n"
125 "The data type of each column is kept as close as possible to the columns' data "
126 "types. If for some reason this is not wanted, the data type of the SQL column "
127 "can be overwritten with --sql-type sql-column/sql-ytpe, for example:\n"
128 " --sql-type=FileId/UNSIGNED INT\n"
129 "while the first argument of the name of the SQL column to which the data type "
130 "should be applied. The second column is the basic SQL data type. The option can "
131 "be given more than once.\n"
132 "\n"
133 "Database interaction:\n"
134 "\n"
135 "To drop an existing table, --drop can be used.\n"
136 "\n"
137 "To create a table according to theSQL column names and data types, --create "
138 "can be used. The query used can be printed with --print-create even --create "
139 "has not been specified.\n"
140 "\n"
141 "To choose the columns which should become primary keys, use --primary, "
142 "for exmaple:\n"
143 " --primary=col1\n"
144 "To define more than one column as primary key, the option can be given more than "
145 "once. Note that the combination of these columns must be unique.\n"
146 "\n"
147 "All columns are created as NOT NULL as default. To force a database engine "
148 "and/or a storage format, use --engine and --rot-format.\n"
149 "\n"
150 "Usually, the INSERT query would fail if the PRIMARY key exists already. "
151 "This can be avoided using the 'ON DUPLICATE KEY UPDATE' directive. With the "
152 "--duplicate, you can specify what should be updated in case of a duplicate key. "
153 "To keep the row untouched, you can just update the primary key "
154 "with the identical primary key, e.g. --duplicate='MyPrimary=VALUES(MyPrimary)'. "
155 "The --duplicate resource can be specified more than once to add more expressions "
156 "to the assignment_list. For more details, see the MySQL manual.\n"
157 "\n"
158 "Another possibility is to add the IGNORE keyword to the INSERT query by "
159 "--ignore-errors, which essentially ignores all errors and turns them into "
160 "warnings which are printed after the query succeeded.\n"
161 "\n"
162 "For debugging purpose, or to just create or drop a table, the final insert "
163 "query can be skipped using --no-insert. Note that for performance reason, "
164 "all data is collected in memory and a single INSERT query is issued at the "
165 "end.\n"
166 "\n"
167 "Using a higher verbosity level (-v), an overview of the written columns or all "
168 "processed leaves is printed depending on the verbosity level. The output looks "
169 "like the following\n"
170 " Leaf name [root data type] (SQL name)\n"
171 "for example\n"
172 " MTime.fTime.fMilliSec [Long64_t] (MilliSec)\n"
173 "which means that the leaf MTime.fTime.fMilliSec is detected to be a Long64_t "
174 "which is filled into a column called MilliSec. Leaves with non basic data types "
175 "are ignored automatically and are marked as (-n/a-). User ignored columnd "
176 "are marked as (-ignored-).\n"
177 "\n"
178 "If a query failed, the query is printed to stderr together with the error message. "
179 "For the main INSERT query, this is only true if the verbosity level is at least 2 "
180 "or the query has less than 80*25 bytes.\n"
181 "\n"
182 "In case of succes, 0 is returned, a value>0 otherwise.\n"
183 "\n"
184 "Usage: fits2sql [options] --uri URI fitsfile.fits[.gz]\n"
185 "\n"
186 ;
187 cout << endl;
188}
189
190enum BasicType_t
191{
192 kNone = 0,
193 kVarchar,
194 kBool,
195 kFloat,
196 kDouble,
197 kInt8,
198 kUInt8,
199 kInt16,
200 kUInt16,
201 kInt32,
202 kUInt32,
203 kInt64,
204 kUInt64,
205// kMJD,
206};
207
208static const map<char, pair<BasicType_t, string>> ConvFits =
209{
210 { 'A', { kVarchar, "VARCHAR" } },
211 { 'a', { kVarchar, "VARCHAR" } },
212 { 'L', { kBool, "BOOLEAN" } },
213 { 'l', { kBool, "BOOLEAN" } },
214 { 'B', { kInt8, "TINYINT" } },
215 { 'b', { kUInt8, "TINYINT UNSIGNED" } },
216 { 'I', { kInt16, "SMALLINT" } },
217 { 'i', { kUInt16, "SMALLINT UNSIGNED" } },
218 { 'J', { kInt32, "INT" } },
219 { 'j', { kUInt32, "INT UNSIGNED" } },
220 { 'K', { kInt64, "BIGINT" } },
221 { 'k', { kUInt64, "BIGINT UNSIGNED" } },
222 { 'E', { kFloat, "FLOAT" } },
223 { 'e', { kFloat, "FLOAT" } },
224 { 'D', { kDouble, "DOUBLE" } },
225 { 'd', { kDouble, "DOUBLE" } },
226};
227
228struct Container
229{
230 string branch; // fits column name
231 string column; // sql column name
232 BasicType_t type;
233 size_t num;
234// double offset;
235 void *ptr;
236
237 Container(const string &b, const string &c, const BasicType_t &t, const size_t &n/*, const double &offset=0*/) : branch(b), column(c), type(t), num(n), ptr(0)
238 {
239 }
240 ~Container()
241 {
242 }
243
244 string fmt(const size_t &index) const
245 {
246 ostringstream str;
247
248 switch (type)
249 {
250 //case kVarchar: str << string(reinterpret_cast<char*>(ptr), num); break;
251 case kVarchar: str << string(reinterpret_cast<char*>(ptr), num).c_str(); break;
252 case kFloat: str << setprecision(8) << reinterpret_cast<float*>(ptr)[index]; break;
253// case kMJD: str << setprecision(16) << reinterpret_cast<double*>(ptr)[0]+offset; break;
254 case kDouble: str << setprecision(16) << reinterpret_cast<double*>(ptr)[index]; break;
255 case kBool:
256 case kInt8: str << int32_t(reinterpret_cast<int8_t*>(ptr)[index]); break;
257 case kUInt8: str << uint32_t(reinterpret_cast<uint8_t*>(ptr)[index]); break;
258 case kInt16: str << reinterpret_cast<int16_t*>(ptr)[index]; break;
259 case kUInt16: str << reinterpret_cast<uint16_t*>(ptr)[index]; break;
260 case kInt32: str << reinterpret_cast<int32_t*>(ptr)[index]; break;
261 case kUInt32: str << reinterpret_cast<uint32_t*>(ptr)[index]; break;
262 case kInt64: str << reinterpret_cast<int64_t*>(ptr)[index]; break;
263 case kUInt64: str << reinterpret_cast<uint64_t*>(ptr)[index]; break;
264 case kNone:
265 break;
266 }
267
268 return str.str();
269 }
270};
271
272int main(int argc, const char* argv[])
273{
274 Time start;
275
276 Configuration conf(argv[0]);
277 conf.SetPrintUsage(PrintUsage);
278 SetupConfiguration(conf);
279
280 if (!conf.DoParse(argc, argv))
281 return 127;
282
283 // ----------------------------- Evaluate options --------------------------
284 const string uri = conf.Get<string>("uri");
285 const string file = conf.Get<string>("file");
286 const string extension = conf.Get<string>("extension");
287 string table = conf.Get<string>("table");
288
289 const uint16_t verbose = conf.Get<uint16_t>("verbose");
290 const size_t first = conf.Get<size_t>("first");
291 const size_t max = conf.Get<size_t>("max");
292
293 const bool force = conf.Get<bool>("force");
294 const bool drop = conf.Get<bool>("drop");
295 const bool create = conf.Get<bool>("create") || drop;
296 const bool noinsert = conf.Get<bool>("no-insert");
297 const bool dry_run = conf.Get<bool>("dry-run");
298
299 const string engine = conf.Get<string>("engine");
300 const string row_format = conf.Get<string>("row-format");
301
302 const bool ignore_errors = conf.Get<bool>("ignore-errors");
303
304 const bool print_connection = conf.Get<bool>("print-connection");
305 const bool print_extensions = conf.Get<bool>("print-extensions");
306 const bool print_columns = conf.Get<bool>("print-columns");
307 const bool print_create = conf.Get<bool>("print-create");
308 const bool print_insert = conf.Get<bool>("print-insert");
309
310 const vector<Map> mymap = conf.Vec<Map>("map");
311 const vector<Map> sqltypes = conf.Vec<Map>("sql-type");
312 const vector<string> _ignore = conf.Vec<string>("ignore");
313 const vector<string> primary = conf.Vec<string>("primary");
314
315 const vector<string> duplicate = conf.Vec<string>("duplicate");
316 const vector<string> notsigned = conf.Vec<string>("unsigned");
317
318 if (first>=max)
319 cerr << "WARNING: Resource `first` (" << first << ") exceeds `max` (" << max << ")" << endl;
320
321
322 // -------------------------------------------------------------------------
323
324 if (verbose>0)
325 cout << "\n-------------------------- Evaluating file -------------------------" << endl;
326
327 zfits f(file.c_str(), extension.c_str());
328 if (!f)
329 {
330 cerr << "Could not open file " << file << ": " << strerror(errno) << endl;
331 return 1;
332 }
333
334 if (verbose>0)
335 cout << "File: " << file << endl;
336
337 if (!extension.empty() && extension!=f.Get<string>("EXTNAME"))
338 {
339 cerr << "Extension " << extension << " not found in file." << endl;
340 return 2;
341 }
342
343 if (print_extensions)
344 {
345 cout << "\nTables:\n - " << boost::join(f.GetTables(), "\n - ") << '\n' << endl;
346 return 3;
347 }
348
349 if (verbose>0)
350 cout << "FITS extension [table]: " << f.Get<string>("EXTNAME") << endl;
351
352 if (table.empty())
353 table = f.Get<string>("EXTNAME");
354
355 if (verbose>0)
356 cout << "SQL table: " << table << endl;
357
358// const double mjdref = f.Get("MJDREF", double(0));
359
360 if (print_columns)
361 {
362 cout << '\n';
363 f.PrintColumns();
364 cout << '\n';
365 }
366
367 const auto cols = f.GetColumns();
368
369 if (verbose>0)
370 {
371 cout << f.GetNumRows() << " events found." << endl;
372 cout << cols.size() << " columns found." << endl;
373 }
374
375 string query =
376 "CREATE TABLE IF NOT EXISTS `"+table+"`\n"
377 "(\n";
378
379 vector<Container> vec;
380
381 for (const auto &ic : cols)
382 {
383 const auto &col = ic.second;
384
385 if (verbose>2)
386 cout << '\n' << col.type << " " << ic.first << "[" << col.num << "]";
387
388 string name = ic.first;
389
390 bool found = false;
391 for (auto b=_ignore.cbegin(); b!=_ignore.cend(); b++)
392 {
393 if (boost::regex_match(name, boost::regex(*b)))
394 {
395 found = true;
396 if (verbose>2)
397 cout << " (-ignored-)";
398 break;
399 }
400 }
401 if (found)
402 continue;
403
404 const char tn = find(notsigned.cbegin(), notsigned.cend(), ic.first)!=notsigned.cend() ?
405 tolower(col.type) : toupper(col.type);
406
407 auto it = ConvFits.find(tn);
408 if (it==ConvFits.end())
409 {
410 if (verbose>2)
411 cout << " (-n/a-)";
412 continue;
413 }
414
415 if (verbose==2)
416 cout << '\n' << name << " [" << tn << "]";
417
418 for (auto m=mymap.cbegin(); m!=mymap.cend(); m++)
419 name = boost::regex_replace(name, boost::regex(m->first), m->second);
420
421 if (verbose>1)
422 cout << " (" << name << ")";
423
424 string sqltype = it->second.second;
425
426 for (auto m=sqltypes.cbegin(); m!=sqltypes.cend(); m++)
427 if (m->first==name)
428 sqltype = m->second;
429
430 if (!vec.empty())
431 query += ",\n";
432
433 const size_t N = col.type=='A' ? 1 : col.num;
434 for (size_t i=0; i<N; i++)
435 {
436 query += " `"+name;
437 if (N>1)
438 query += "["+to_string(i)+"]";
439 query += "` "+sqltype;
440 if (col.type=='A')
441 query += '('+to_string(col.num)+')';
442 query += " NOT NULL COMMENT '"+ic.first;
443 if (!col.unit.empty())
444 query += "["+col.unit+"]";
445 if (!col.comment.empty())
446 query += ": "+col.comment;
447 query += +"'";
448 if (N>1 && i!=N-1)
449 query += ",\n";
450 }
451
452 const BasicType_t bt =
453 /*ic.first=="Time" && col.num==1 && col.unit=="MJD" && it->second.first==kDouble ?
454 kMJD :*/ it->second.first;
455
456 vec.emplace_back(ic.first, name, bt, col.num/*, mjdref*/);
457 vec.back().ptr = f.SetPtrAddress(ic.first);
458 }
459
460 if (verbose>1)
461 cout << "\n\n";
462 if (verbose>0)
463 cout << vec.size() << " columns setup for reading." << endl;
464
465 // -------------------------------------------------------------------------
466 // Checking for database connection
467
468 Database connection(uri);
469
470 if (verbose>0)
471 {
472 cout << "Client Version: " << connection.client_version() << '\n';
473 cout << "Server Version: " << connection.server_version() << endl;
474 }
475
476 if (print_connection)
477 {
478 try
479 {
480 const auto &res1 = connection.query("SHOW STATUS LIKE 'Compression'").store();
481 cout << "Compression of databse connection is " << string(res1[0][1]) << endl;
482
483 const auto &res2 = connection.query("SHOW STATUS LIKE 'Ssl_cipher'").store();
484 cout << "Connection to databases is " << (string(res2[0][1]).empty()?"UNENCRYPTED":"ENCRYPTED ("+string(res2[0][1])+")") << endl;
485 }
486 catch (const exception &e)
487 {
488 cerr << "\nSHOW STATUS LIKE COMPRESSION\n\n";
489 cerr << "SQL query failed:\n" << e.what() << endl;
490 return 6;
491 }
492 }
493
494 try
495 {
496 if (!force)
497 connection.connected();
498 }
499 catch (const exception &e)
500 {
501 cerr << "SQL connection failed: " << e.what() << '\n' << endl;
502 return 4;
503 }
504
505 // -------------------------------------------------------------------------
506
507 if (verbose>0)
508 cout << "\n--------------------------- Database Table -------------------------" << endl;
509
510 if (!primary.empty())
511 query += ",\n PRIMARY KEY USING BTREE (`"+boost::algorithm::join(primary, "`, `")+"`)\n";
512
513 query +=
514 ")\n"
515 "DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci\n";
516 if (!engine.empty())
517 query += "ENGINE="+engine+"\n";
518 if (!row_format.empty())
519 query += "ROW_FORMAT="+row_format+"\n";
520 query += "COMMENT='created by "+conf.GetName()+"'\n";
521
522
523 // FIXME: Can we omit the catching to be able to print the
524 // query 'autmatically'?
525 try
526 {
527 if (drop)
528 {
529 // => Simple result
530 if (!dry_run)
531 connection.query("DROP TABLE `"+table+"`").execute();
532 if (verbose>0)
533 cout << "Table `" << table << "` dropped." << endl;
534 }
535 }
536 catch (const exception &e)
537 {
538 cerr << "DROP TABLE `" << table << "`\n\n";
539 cerr << "SQL query failed:\n" << e.what() << '\n' << endl;
540 return 5;
541 }
542
543 try
544 {
545 if (create && !dry_run)
546 connection.query(query).execute();
547 }
548 catch (const exception &e)
549 {
550 cerr << query << "\n\n";
551 cerr << "SQL query failed:\n" << e.what() << '\n' << endl;
552 return 6;
553 }
554
555 if (print_create)
556 cout << query << endl;
557
558 if (create && verbose>0)
559 cout << "Table `" << table << "` created." << endl;
560
561 // -------------------------------------------------------------------------
562
563 if (verbose>0)
564 cout << "\n---------------------------- Reading file --------------------------" << endl;
565
566 //query = update ? "UPDATE" : "INSERT";
567 query = "INSERT ";
568 if (ignore_errors)
569 query += "IGNORE ";
570 query += "`"+table+"`\n"
571 "(\n";
572
573 for (auto c=vec.cbegin(); c!=vec.cend(); c++)
574 {
575 const size_t N = c->type==kVarchar ? 1 : c->num;
576 for (size_t i=0; i<N; i++)
577 {
578 if (c!=vec.cbegin())
579 query += ",\n";
580
581 if (N==1)
582 query += " `"+c->column+"`";
583 else
584 query += " `"+c->column+"["+to_string(i)+"]`";
585
586 if (N>1 && i!=N-1)
587 query += ",\n";
588 }
589 }
590
591 query +=
592 "\n)\n"
593 "VALUES\n";
594
595 size_t count = 0;
596
597 const size_t num = max>first && (max-first)<f.GetNumRows() ? (max-first) : f.GetNumRows();
598 for (size_t j=first; j<num; j++)
599 {
600 f.GetRow(j);
601
602 if (count>0)
603 query += ",\n";
604
605 query += "(\n";
606
607 for (auto c=vec.cbegin(); c!=vec.cend(); c++)
608 {
609 const size_t N = c->type==kVarchar ? 1 : c->num;
610 for (size_t i=0; i<N; i++)
611 {
612 if (c!=vec.cbegin())
613 query += ",\n";
614
615 if (c->type==kVarchar)
616 query += " '"+c->fmt(i)+"'";
617 else
618 query += " "+c->fmt(i);
619
620 if (print_insert && i==0)
621 query += " /* "+c->column+" -> "+c->branch+" */";
622
623 if (N>1 && i!=N-1)
624 query += ",\n";
625 }
626 }
627 query += "\n)";
628
629 count ++;
630 }
631
632 if (!duplicate.empty())
633 query += "\nON DUPLICATE KEY UPDATE\n " + boost::join(duplicate, ",\n ");
634
635 if (verbose>0)
636 cout << count << " out of " << num << " row(s) read from file [N=" << first << ".." << num-1 << "]." << endl;
637
638 if (count==0)
639 {
640 if (verbose>0)
641 cout << "Total execution time: " << Time().UnixTime()-start.UnixTime() << "s\n" << endl;
642 return 0;
643 }
644
645 // -------------------------------------------------------------------------
646
647 if (verbose>0)
648 {
649 cout << "\n--------------------------- Inserting data -------------------------" << endl;
650 cout << "Sending INSERT query (" << query.length() << " bytes)" << endl;
651 }
652
653 try
654 {
655 if (!noinsert && !dry_run)
656 {
657 auto q = connection.query(query);
658 q.execute();
659 cout << q.info() << '\n' << endl;
660 }
661 else
662 cout << "Insert query skipped!" << endl;
663
664 if (print_insert)
665 cout << query << endl;
666 }
667 catch (const exception &e)
668 {
669 if (verbose>1 || query.length()<80*25)
670 cerr << query << "\n\n";
671 cerr << "SQL query failed (" << query.length() << " bytes):\n" << e.what() << '\n' << endl;
672 return 7;
673 }
674
675 if (verbose>0)
676 {
677 const auto sec = Time().UnixTime()-start.UnixTime();
678 cout << "Total execution time: " << sec << "s ";
679 cout << "(" << Tools::Fractional(sec/count) << "s/row)\n";
680
681 try
682 {
683 const auto resw =
684 connection.query("SHOW WARNINGS").store();
685
686 for (size_t i=0; i<resw.num_rows(); i++)
687 {
688 const mysqlpp::Row &roww = resw[i];
689
690 cout << roww["Level"] << '[' << roww["Code"] << "]: ";
691 cout << roww["Message"] << '\n';
692 }
693 cout << endl;
694
695 }
696 catch (const exception &e)
697 {
698 cerr << "\nSHOW WARNINGS\n\n";
699 cerr << "SQL query failed:\n" << e.what() << '\n' <<endl;
700 return 8;
701 }
702 }
703
704 if (print_connection)
705 {
706 try
707 {
708 // Exchange _send and _received as it is the view of the server
709 const auto &res1 = connection.query("SHOW STATUS LIKE 'Bytes_%'").store();
710 cout << left << setw(16) << res1[1]["Variable_name"] << ' ' << Tools::Scientific(res1[0]["Value"]) << endl;
711 cout << left << setw(16) << res1[0]["Variable_name"] << ' ' << Tools::Scientific(res1[1]["Value"]) << endl;
712 cout << endl;
713 }
714 catch (const exception &e)
715 {
716 cerr << "\nSHOW STATUS LIKE 'Bytes_%'\n\n";
717 cerr << "SQL query failed:\n" << e.what() << endl;
718 return 6;
719 }
720 }
721
722 return 0;
723}
Note: See TracBrowser for help on using the repository browser.