Rosetta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
sql_utils.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file src/basic/database/sql_utils.cc
11 /// @brief Database utility functions
12 /// @author Sam DeLuca
13 /// @author Matthew O'Meara
14 
15 #ifdef USEMPI
16 #include <mpi.h>
17 #endif
18 
20 
21 #include <basic/Tracer.hh> // for Tracer
22 #include <basic/options/keys/inout.OptionKeys.gen.hh> // for databa...
23 #include <basic/options/keys/out.OptionKeys.gen.hh> // for all, db
24 #include <basic/options/option.hh> // for Option...
25 #include <basic/resource_manager/ResourceManager.hh> // for Resour...
26 #include <basic/resource_manager/util.hh> // for get_re...
27 
28 #include <cppdb/errors.h> // for cppdb_...
29 #include <cppdb/frontend.h> // for statement
30 
31 #include <boost/algorithm/string/predicate.hpp> // for istart...
32 #include <boost/foreach.hpp> // for auto_a...
33 #include <boost/iterator/iterator_facade.hpp> // for operat...
34 #include <boost/lexical_cast.hpp> // for bad_le...
35 #include <boost/mpl/bool.hpp> // for bool_
36 #include <boost/mpl/bool_fwd.hpp> // for false_
37 #include <boost/token_functions.hpp> // for char_s...
38 #include <boost/tokenizer.hpp> // for tokenizer
39 #include <numeric/random/random.hh> // for rg
40 #include <platform/types.hh> // for Size
41 #include <utility/excn/Exceptions.hh> // for EXCN_M...
42 #include <utility/exit.hh> // for utilit...
43 #include <utility/file/PathName.hh> // for PathName
44 #include <utility/options/BooleanOption.hh> // for Boolea...
45 #include <utility/options/IntegerOption.hh> // for Intege...
46 #include <utility/options/PathOption.hh> // for PathOp...
47 #include <utility/options/ScalarOption_T_.hh> // for Scalar...
48 #include <utility/options/StringOption.hh> // for String...
50 #include <utility/sql_database/DatabaseSessionManager.hh> // for session
51 #include <utility/string_util.hh> // for join
52 #include <utility/vector1.hh> // for vector1
53 #include <utility/tag/Tag.hh> // for Tag
54 
55 #include <cstddef> // for size_t
56 #include <iosfwd> // for string
57 #include <memory> // for shared...
58 #include <sstream> // for operat...
59 #include <string> // for basic_...
60 #include <vector> // for vector
61 
62 #ifndef WIN32
63 #include <unistd.h> // for usleep
64 #endif
65 
66 
67 #ifdef WIN32
68 #include <windows.h>
69 #endif
70 
71 using std::string;
72 using std::stringstream;
74 using platform::Size;
75 using cppdb::statement;
76 using cppdb::cppdb_error;
77 using cppdb::result;
78 using utility::vector1;
79 using namespace utility::sql_database;
80 
81 namespace basic {
82 namespace database {
83 
84 static THREAD_LOCAL basic::Tracer TR( "basic.database.sql_utils" );
85 
86 
89  using namespace basic::options;
90  using namespace basic::options::OptionKeys;
91 
92  return get_db_session(
93  option[inout::dbms::database_name],
95  0,
96  option[inout::dbms::pq_schema]);
97 }
98 
99 
100 sessionOP
102  string const & db_name,
103  string const & pq_schema
104 ){
105  using namespace basic::options;
106  using namespace basic::options::OptionKeys;
107 
108  return get_db_session(
111  0,
112  db_name,
113  pq_schema);
114 }
115 
116 sessionOP
118  string const & db_name,
119  TransactionMode::e transaction_mode,
120  Size chunk_size,
121  string const & pq_schema
122 ){
123  using namespace basic::options;
124  using namespace basic::options::OptionKeys;
125 
126  return get_db_session(
128  transaction_mode,
129  chunk_size,
130  db_name,
131  pq_schema);
132 }
133 
137  std::string const & db_name,
138  std::string const & pq_schema){
139 
140  return get_db_session(
141  db_mode,
143  0,
144  db_name,
145  pq_schema);
146 }
147 
148 sessionOP
150  DatabaseMode::e db_mode,
151  TransactionMode::e transaction_mode,
152  Size chunk_size,
153  string const & db_name,
154  string const & pq_schema
155 ) {
156  using namespace basic::options;
157  using namespace basic::options::OptionKeys;
158 
159 
160  switch(db_mode) {
161  case DatabaseMode::sqlite3 :
162 
163  if (
164  option[inout::dbms::host].user() ||
166  option[inout::dbms::password].user() ||
167  option[inout::dbms::port].user() ) {
169  "You have specified options for a client-server database "
170  "but the database mode is sqlite3. "
171  "Please specify -inout:dbms:mode <db_mode>.");
172  }
173 
174  if ( pq_schema.compare("") ) {
175  TR.Warning
176  << "You have specified a postgres schema but using a sqlite3 database. "
177  << "To use postgres, please specify -inout:dbms:mode postgres"
178  << std::endl;
179  }
180 
182  db_name,
183  transaction_mode,
184  chunk_size,
185  option[inout::dbms::readonly],
186  db_partition_from_options(db_mode));
187 
188  case DatabaseMode::mysql :
189 
190  if ( option[inout::dbms::readonly] ) {
192  "Restricting access to a mysql database is done at the user level "
193  "rather that the connection level. "
194  "So requesting a readonly connection cannot fullfilled.");
195  }
196 
197  if ( pq_schema.compare("") ) {
198  TR.Warning
199  << "You have specified a postgres schema but using a mysql database. "
200  << "To use postgres, please specify -inout:dbms:mode postgres"
201  << std::endl;
202  }
203 
204  if ( !(
205  option[inout::dbms::host].user() &&
207  option[inout::dbms::password].user() &&
208  option[inout::dbms::port].user()) ) {
210  "To connect to a mysql database you must specify "
211  "-inout:dbms:host -inout:dbms:user -inout:dbms:password and "
212  "-inout:dbms:port");
213  }
214 
215  // Call to get partition performs option validation.
216  db_partition_from_options(db_mode);
217 
219  db_name,
220  transaction_mode,
221  chunk_size,
222  option[inout::dbms::host],
224  option[inout::dbms::password],
225  option[inout::dbms::port]);
226 
227 
229 
230  if ( option[inout::dbms::readonly] ) {
232  "Restricting access to a postgres database is done at the user level "
233  "rather that the connection level. So requesting a readonly connection "
234  "cannot fullfilled.");
235  }
236 
237 
238  if ( !(
239  option[inout::dbms::host].user() &&
240  option[inout::dbms::user].user() &&
241  option[inout::dbms::password].user() &&
242  option[inout::dbms::port].user()) ) {
244  "To connect to a postgres database you must specify "
245  "-inout:dbms:host -inout:dbms:user -inout:dbms:password "
246  "and -inout:dbms:port");
247  }
248 
249  // Call to get partition performs option validation.
250  db_partition_from_options(db_mode);
251 
253  db_name,
254  transaction_mode,
255  chunk_size,
256  pq_schema,
257  option[inout::dbms::host],
258  option[inout::dbms::user],
259  option[inout::dbms::password],
260  option[inout::dbms::port]);
261  default :
263  "Unrecognized database mode: '" + name_from_database_mode(db_mode) + "'");
264  }
265  return 0;
266 }
267 
268 /// @
270 {
271  using namespace basic::options;
272  using namespace basic::options::OptionKeys;
273 
274  if ( option[inout::dbms::separate_db_per_mpi_process] && option[inout::dbms::database_partition].user() ) {
276  "The -inout:dbms:separate_db_per_mpi_process and -inout::dbms::database_partition options are mutually exclusive.");
277  } else if ( option[inout::dbms::database_partition].user() ) {
278  if ( option[inout::dbms::database_partition] < 0 ) {
279  stringstream error;
280  error << "Invalid -inout::dbms::database_partition specified, must be positive integer value: " << option[inout::dbms::database_partition] << std::endl;
281  utility_exit_with_message(error.str());
282  }
283  }
284 
285  switch(db_mode)
286  {
287  case DatabaseMode::sqlite3 :
288 
289  if ( !option[inout::dbms::database_partition].user() ) {
290  return resolve_db_partition(
291  option[inout::dbms::separate_db_per_mpi_process]);
292  } else {
293  return resolve_db_partition(
294  option[inout::dbms::separate_db_per_mpi_process],
295  option[inout::dbms::database_partition]);
296  }
297 
298  break;
299 
300  case DatabaseMode::mysql:
302  if ( option[inout::dbms::separate_db_per_mpi_process] || option[inout::dbms::database_partition].user() ) {
304  "The -inout:dbms:separate_db_per_mpi_process and -inout::dbms::database_partition flags only apply to "
305  "sqlite3 databases.");
306  }
307 
308  break;
309  }
310 
311  return -1;
312 }
313 
315  bool partition_by_mpi_process,
316  platform::SSize manual_partition)
317 {
318  if ( partition_by_mpi_process ) {
319 #ifdef USEMPI
320  int mpi_rank(0);
321  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
322  return mpi_rank;
323 #endif
324  }
325 
326  if ( manual_partition >= 0 ) {
327  return manual_partition;
328  }
329 
330  return -1;
331 }
332 
334  string const & statement_string,
335  sessionOP db_session)
336 {
337  statement stmt;
338  try
339 {
340  stmt = db_session->prepare(statement_string);
341  return stmt;
342  }catch(cppdb_error const & error)
343 {
344  TR.Error << " Failed to safely prepare the following statement: " << std::endl;
345  TR.Error << statement_string << std::endl;
346  TR.Error << error.what() << std::endl;
347 
348  utility_exit_with_message(error.what());
349  }
350  return stmt; //there's no way this should happen
351 }
352 
353 void
355  statement & statement
356 ) {
357 
358  platform::Size cycle = 0;
359  while ( true )
360  {
361  try
362 {
363  statement.exec();
364  return;
365  }catch(cppdb::bad_value_cast & except)
366 {
367 
368  utility_exit_with_message(except.what());
369  }catch(cppdb::empty_row_access & except)
370 {
371  utility_exit_with_message(except.what());
372  }catch(cppdb::invalid_column & except)
373 {
374  utility_exit_with_message(except.what());
375  }catch(cppdb::invalid_placeholder & except)
376 {
377  utility_exit_with_message(except.what());
378  }catch(cppdb::multiple_rows_query & except)
379 {
380  utility_exit_with_message(except.what());
381  }catch(cppdb::not_supported_by_backend & except)
382 {
383  utility_exit_with_message(except.what());
384  } catch(cppdb::null_value_fetch & except)
385 {
386  utility_exit_with_message(except.what());
387  } catch(cppdb::cppdb_error & except)
388 {
389 #ifdef USEMPI
390  if( std::string(except.what()) == "database is locked"){
391  stringstream err_msg;
392  err_msg
393  << "database is locked" << std::endl
394  << std::endl
395  << "PSA: If this is an sqlite3 session, running under MPI, and you are using the database primarily for writing output," << std::endl
396  << "consider using the 'separate_db_per_mpi_process' option if you're not already using it." << std::endl
397  << "To do this add separate_db_per_mpi_process=1 to a RosettaScripts/resource_definitions xml tag that takes database options" << std::endl
398  << "or add -inout:dbms:separate_db_per_mpi_process to the command line or flags file" << std::endl
399  << "This option will append '_<mpi_rank>' to the database filename for each mpi process. Once the run has finished," << std::endl
400  << "these databases can be merged together using " << std::endl
401  << std::endl
402  << " bash /path/to/rosetta_tests/features/sample_sources/merge.sh <output_db> <input_db_part_1> [<input_db_part_2> [ ... ] ]" << std::endl
403  << std::endl
404  << "For more information see the database connection options page in the Rosetta Wiki: RosettaScripts_database_connection_options" << std::endl
405  << except.what() << std::endl;
406  utility_exit_with_message(err_msg.str());
407  }
408 #endif
409 
410  utility_exit_with_message(except.what());
411  }
412 
413  cycle++;
414  }
415 }
416 
417 result
419  statement & statement
420 ) {
421  using namespace basic::options;
422  using namespace basic::options::OptionKeys;
423  platform::Size retry_limit = 10;
424  platform::Size cycle = 1;
425  while ( true )
426  {
427  try
428 {
429  return statement.query();
430  }catch(cppdb::bad_value_cast & except)
431 {
432 
433  utility_exit_with_message(except.what());
434  }catch(cppdb::empty_row_access & except)
435 {
436  utility_exit_with_message(except.what());
437  }catch(cppdb::invalid_column & except)
438 {
439  utility_exit_with_message(except.what());
440  }catch(cppdb::invalid_placeholder & except)
441 {
442  utility_exit_with_message(except.what());
443  }catch(cppdb::multiple_rows_query & except)
444 {
445  utility_exit_with_message(except.what());
446  }catch(cppdb::not_supported_by_backend & except)
447 {
448  utility_exit_with_message(except.what());
449  }catch(cppdb::null_value_fetch & except)
450 {
451  utility_exit_with_message(except.what());
452  }catch(cppdb::cppdb_error & except)
453 {
454  if ( option[inout::dbms::retry_failed_reads] && cycle <= retry_limit ) {
455  TR << "Caught an exception on db read: " << except.what() << "\n" <<
456  "pausing before another attempted read. This is attempt " << cycle << " of " << retry_limit <<std::endl;
457 #ifdef WIN32
458  Sleep(1000);
459 #else
460  //Sleep some amount between 100-2000 ms
461  usleep(100+1900*numeric::random::rg().uniform());
462 #endif
463  } else {
464  utility_exit_with_message(except.what());
465  }
466  }
467  cycle++;
468  }
469 }
470 
471 
472 bool
474  sessionOP db_session,
475  string const & table_name
476 ) {
477 
478  // TODO: handle when the current database is not the one from the
479  // option system, can someone with mysql try this and see if it
480  // works?
481  // "SHOW TABLES IN database();"
482  string statement_string;
483  statement stmt;
484  Size i(1);
485  switch(db_session->get_db_mode()){
486  case DatabaseMode::sqlite3 :
487  statement_string = "SELECT name FROM sqlite_master WHERE name=?;";
488  stmt = safely_prepare_statement(statement_string,db_session);
489  break;
490  case DatabaseMode::mysql :
491  statement_string = "SHOW TABLES WHERE Tables_in_"+db_session->get_db_name()+" = ?;";
492  stmt = safely_prepare_statement(statement_string,db_session);
493  break;
495  if ( db_session->get_pq_schema() == "" ) {
496  statement_string =
497  "SELECT tablename \n"
498  "FROM pg_catalog.pg_tables \n"
499  "WHERE tablename = ?;";
500  stmt = safely_prepare_statement(statement_string, db_session);
501  } else {
502  statement_string =
503  "SELECT tablename FROM pg_catalog.pg_tables \n"
504  "WHERE schemaname = ? AND tablename = ?;";
505  stmt = safely_prepare_statement(statement_string, db_session);
506  stmt.bind(i, db_session->get_pq_schema());
507  i++;
508  }
509  break;
510  default :
511  utility_exit_with_message("unknown database mode");
512  }
513 
514  stmt.bind(i, table_name);
515  result res(stmt.query());
516 
517  return res.next();
518 }
519 
520 //Simply (probably overly so) protection from SQL injection
521 void
523  string sql
524 ) {
525  if ( !boost::istarts_with(sql, "SELECT") ) {
526  utility_exit_with_message("ERROR: Database select statement is not safe! Only SELECT statements are allowed.");
527  }
528 
529  int semicolon_count=0;
530  for ( size_t i = 0; i < sql.size(); i++ ) {
531  if ( sql[i] == ';' ) {
532  semicolon_count++;
533  }
534  }
535  if ( semicolon_count > 1 ) {
536  utility_exit_with_message("Database select statement is not safe! Only 1 SQL statement is allowed");
537  }
538 }
539 
540 //This should ideally only be used for reference tables that have static data that needs to only be written once(ex: dssp_codes)
541 void
543  string table_name,
544  std::vector<string> column_names,
545  std::vector<string> values,
546  sessionOP db_session
547 ){
548 
549  string statement_string="";
550  switch(db_session->get_db_mode()){
552  statement_string = "INSERT IGNORE into " + table_name + " (";
553  for ( size_t i=0; i<column_names.size(); i++ ) {
554  statement_string += column_names[i];
555  if ( i != column_names.size()-1 ) {
556  statement_string += ",";
557  }
558  }
559 
560  statement_string+=") VALUES(";
561  for ( size_t i=0; i<values.size(); i++ ) {
562  statement_string += "?";
563  if ( i != column_names.size()-1 ) {
564  statement_string += ",";
565  }
566  }
567 
568  statement_string += ");";
569 
570  statement stmt( safely_prepare_statement(statement_string, db_session) );
571  for ( size_t i=0; i<values.size(); i++ ) {
572  stmt.bind(i+1, values[i]);
573  }
574 
576  break;
577  }
579  //This is a dirty postgres hack and seems to be the easiest workaround for lack of INSERT IGNORE support in postgres
580  string select_statement_string = "SELECT * FROM " + table_name + " WHERE ";
581  for ( size_t i=0; i<column_names.size(); i++ ) {
582  select_statement_string += column_names[i] + "=?";
583  if ( i != column_names.size()-1 ) {
584  select_statement_string += " AND ";
585  }
586  }
587  select_statement_string+=";";
588 
589  statement select_stmt ( safely_prepare_statement(
590  select_statement_string, db_session
591  ));
592 
593  for ( size_t i=0; i<values.size(); i++ ) {
594  select_stmt.bind(i+1, values[i]);
595  }
596 
597  result res = safely_read_from_database(select_stmt);
598 
599  if ( !res.next() ) {
600  statement_string += "INSERT into " + table_name + "(";
601  for ( size_t i=0; i<column_names.size(); i++ ) {
602  statement_string += column_names[i];
603  if ( i != column_names.size()-1 ) {
604  statement_string += ",";
605  }
606  }
607 
608  statement_string += ") VALUES(";
609  for ( size_t i=0; i<values.size(); i++ ) {
610  statement_string += "?";
611  if ( i != column_names.size()-1 ) {
612  statement_string += ",";
613  }
614  }
615 
616  statement_string += ");";
617 
618  statement stmt ( safely_prepare_statement(
619  statement_string, db_session
620  ));
621 
622  for ( size_t i=0; i<values.size(); i++ ) {
623  stmt.bind(i+1, values[i]);
624  }
625 
627  }
628  break;
629  }
631  statement_string = "INSERT OR IGNORE into "+table_name+"(";
632  for ( size_t i=0; i<column_names.size(); i++ ) {
633  statement_string+=column_names[i];
634  if ( i != column_names.size()-1 ) {
635  statement_string+=",";
636  }
637  }
638 
639  statement_string+=") VALUES(";
640  for ( size_t i=0; i<values.size(); i++ ) {
641  statement_string += "?";
642  if ( i != column_names.size()-1 ) {
643  statement_string+=",";
644  }
645  }
646  statement_string+=");";
647 
648  statement stmt ( safely_prepare_statement(statement_string, db_session) );
649  for ( size_t i=0; i<values.size(); i++ ) {
650  stmt.bind(i+1, values[i]);
651  }
652 
654  break;
655  }
656  default :
658  "Unrecognized database mode: '" +
659  name_from_database_mode(db_session->get_db_mode()) + "'");
660  }
661 }
662 
664  string schema_str,
665  sessionOP db_session)
666 {
667  boost::char_separator< char > sep(";");
668  boost::tokenizer< boost::char_separator< char > > tokens( schema_str, sep );
669  BOOST_FOREACH ( std::string const & stmt_str, tokens ) {
670  string trimmed_stmt_str(utility::trim(stmt_str, " \n\t"));
671  if ( trimmed_stmt_str.size() ) {
672  try{
673  statement stmt = (*db_session) << trimmed_stmt_str + ";";
675  } catch (cppdb_error const & e) {
676  TR.Error
677  << "ERROR reading schema \n"
678  << trimmed_stmt_str << std::endl;
679  TR.Error << e.what() << std::endl;
680  utility_exit();
681  }
682  }
683  }
684 }
685 
686 
687 void
689  sessionOP db_session,
690  Size cache_size
691 ) {
692 
693  if ( db_session->get_db_mode() == DatabaseMode::sqlite3 ) {
694  stringstream stmt_ss;
695  stmt_ss << "PRAGMA cache_size = " << cache_size << ";";
696  statement stmt(safely_prepare_statement(stmt_ss.str(), db_session));
698  } else {
699  TR
700  << "WARNING: Attempting to set database cache size "
701  << "for a database type for which this is currently not supported: "
702  << "'" << name_from_database_mode(db_session->get_db_mode()) << "'." << std::endl;
703  }
704 }
705 
707  std::string const & table_name,
708  std::vector<std::string> const & column_names,
709  platform::Size const & row_count)
710 {
711  std::string table_definition = table_name + " (" + utility::join(column_names,",") + ")";
712  std::string value_list;
713  platform::Size column_count = column_names.size();
714  for ( platform::Size i = 0; i < row_count; ++i ) {
715  std::string row_block= "(?";
716  for ( platform::Size j = 1; j < column_count; ++j ) {
717  row_block += ",?";
718  }
719  row_block += ")";
720 
721  value_list += row_block;
722  if ( i != row_count-1 ) {
723  value_list += ", ";
724  }
725  }
726 
727  return "INSERT INTO "+table_definition+ " VALUES " + value_list +";";
728 }
729 
730 /// @detail build database connection from options in a tag, this is useful make sure the fields for
731 ///constructing a database connection are consistent across different tags.
735 ){
736  using std::endl;
737  using namespace basic::options;
738  using namespace basic::options::OptionKeys::inout;
739  using namespace basic::options::OptionKeys;
741  using namespace basic::resource_manager;
742 
743  bool separate_database = option[ inout::dbms::separate_db_per_mpi_process ]();
744  int database_partition = option[ inout::dbms::database_partition]();
745 
746  if ( tag->hasOption("database_resource") ) {
747  std::string database_resource = tag->getOption<string>("database_resource");
748  if ( ! ResourceManager::get_instance()->has_resource_with_description( database_resource ) ) {
750  ( "You specified a database_resource of '" + database_resource +
751  "', but the ResourceManager doesn't have a resource with that description." );
752  }
753  return get_resource< utility::sql_database::session >( database_resource );
754  }
755 
756  if ( tag->hasOption("database_resource_tag") ) {
757  std::string database_resource_tag = tag->getOption<string>(
758  "database_resource_tag");
759  if ( ! ResourceManager::get_instance()->has_resource(
760  database_resource_tag ) ) {
762  ( "You specified a database_resource_tag of '" + database_resource_tag +
763  "', but the ResourceManager doesn't have a resource with that tag." );
764  }
765  utility::sql_database::sessionOP db_session(utility::pointer::dynamic_pointer_cast< utility::sql_database::session > (
766  ResourceManager::get_instance()->find_resource(database_resource_tag)));
767  if ( !db_session ) {
768  stringstream err_msg;
769  err_msg
770  << "You specified a database_resource_tag of '" + database_resource_tag + "', while the ResourceManager does have a resource with that tag, it couldn't cast into a database session.";
771  throw utility::excn::EXCN_Msg_Exception(err_msg.str());
772  }
773  return db_session;
774  }
775 
777  tag->getOption<string>("transaction_mode", "standard"));
778 
779  Size chunk_size;
780  switch(transaction_mode){
782  if ( tag->hasOption("chunk_size") ) {
783  TR << "WARNING: You must specify 'transaction_mode=chunk' ";
784  TR << "to use the 'chunk size' tag." << endl;
785  }
786  chunk_size=0;
787  break;
789  if ( tag->hasOption("chunk_size") ) {
790  TR << "WARNING: You must specify 'transaction_mode=chunk' ";
791  TR << "to use the 'chunk size' tag." << endl;
792  }
793  chunk_size=0;
794  break;
796  if ( !tag->hasOption("chunk_size") ) {
798  "Must specify chunk_size if using the chunk transaction mode");
799  }
800  chunk_size=
801  tag->getOption<Size>("chunk_size");
802  break;
803  default :
805  "Unrecognized transaction mode: '" +
806  name_from_transaction_mode(transaction_mode) + "'");
807  }
808 
810 
811  if ( tag->hasOption("database_mode") ) {
813  tag->getOption<string>("database_mode"));
814  } else {
816  option[dbms::mode]);
817  }
818 
819  std::string database_name;
820  if ( tag->hasOption("database_name") ) {
821  database_name = tag->getOption<string>("database_name");
822  } else {
823  database_name = option[dbms::database_name];
824  }
825 
826  std::string database_dir;
827  if ( option[ out::path::db ].user() ) {
828  database_dir = option[ out::path::db ]().path();
829  } else if ( option[ inout::dbms::path ].user() ) {
830  database_dir = option[ inout::dbms::path ]().path();
831  } else if ( option[ out::path::all ].user() ) {
832  database_dir = option[ out::path::all ]().path();
833  } else {
834  database_dir = "";
835  }
836  std::string database_path = database_dir + database_name;
837 
838  // Parse pq_schema
839  if ( tag->hasOption("database_pq_schema") && (database_mode != utility::sql_database::DatabaseMode::postgres) ) {
840  TR << "WARNING: You must specify 'database_mode=postgres' ";
841  TR << "to use the 'database_pq_schema' tag." << endl;
842  }
843 
844  std::string database_pq_schema;
845  if ( tag->hasOption("database_pq_schema") ) {
846  database_pq_schema = tag->getOption<string>("database_pq_schema");
847  } else {
848  database_pq_schema = option[dbms::pq_schema];
849  }
850 
851 
852  // Check for invalid tags
853  if ( database_mode != utility::sql_database::DatabaseMode::sqlite3 ) {
854  if ( tag->hasOption("database_separate_db_per_mpi_process") ) {
855  TR << "WARNING: You must specify 'database_mode=sqlite3' ";
856  TR << "to use the 'database_separate_db_per_mpi_process' tag." << endl;
857  }
858 
859  if ( tag->hasOption("database_partition") ) {
860  TR << "WARNING: You must specify 'database_mode=sqlite3' ";
861  TR << "to use the 'database_partition' tag." << endl;
862  }
863 
864  if ( tag->hasOption("database_read_only") ) {
865  TR << "WARNING: You must specify 'database_mode=sqlite3' ";
866  TR << "to use the 'database_read_only tag." << endl;
867  }
868  }
869 
870  if ( database_mode == utility::sql_database::DatabaseMode::sqlite3 ) {
871  if ( tag->hasOption("database_separate_db_per_mpi_process") && tag->hasOption("database_partition") ) {
872  TR << "WARNING: 'database_separate_db_per_mpi_process' and 'database_partition' tags are mutually exclusive, using 'database_separate_db_per_mpi_process'." << endl;
873  }
874 
875  if ( tag->hasOption("database_host") ) {
876  TR << "WARNING: You must specify either 'database_mode=mysql' ";
877  TR << "or database_mode=postgres' to use the 'database_host' tag." << endl;
878  }
879 
880  if ( tag->hasOption("database_user") ) {
881  TR << "WARNING: You must specify either 'database_mode=mysql' ";
882  TR << "or database_mode=postgres' to use the 'database_user' tag." << endl;
883  }
884 
885  if ( tag->hasOption("database_password") ) {
886  TR << "WARNING: You must specify either 'database_mode=mysql' ";
887  TR << "or database_mode=postgres' to use the 'database_password' tag." << endl;
888  }
889 
890  if ( tag->hasOption("database_port") ) {
891  TR << "WARNING: You must specify either 'database_mode=mysql' ";
892  TR << "or database_mode=postgres' to use the 'database_port' tag." << endl;
893  }
894  }
895 
896  switch(database_mode){
897 
900  database_mode, transaction_mode, chunk_size,
901  database_path, "", "", "", "", 0,
902  tag->getOption("database_read_only", false),
904  tag->getOption("database_separate_db_per_mpi_process", separate_database),
905  tag->getOption("database_partition", database_partition)));
906 
909 
910  std::string database_host;
911  if ( !tag->hasOption("database_host") ) {
912  if ( !option[dbms::host].user() ) {
914  "WARNING: To connect to a postgres or mysql database you must set"
915  " the database_host tag or specify -dbms:host on the command line.");
916  } else {
917  database_host=option[dbms::host];
918  }
919  } else {
920  database_host=tag->getOption<string>("database_host");
921  }
922 
923  std::string database_user;
924  if ( !tag->hasOption("database_user") ) {
925  if ( !option[dbms::user].user() ) {
927  "WARNING: To connect to a postgres or mysql database you must set"
928  "the database_user tag or specify -dbms:user on the command line.");
929  } else {
930  database_user=option[dbms::user];
931  }
932  } else {
933  database_user=tag->getOption<string>("database_user");
934  }
935 
936  std::string database_password;
937  if ( !tag->hasOption("database_password") ) {
938  if ( !option[dbms::password].user() ) {
940  "WARNING: To connect to a postgres or mysql database you must set"
941  "the database_password tag or specify -dbms:password on the command line.");
942  } else {
943  database_password=option[dbms::password];
944  }
945  } else {
946  database_password=tag->getOption<string>("database_password");
947  }
948 
949  Size database_port;
950  if ( !tag->hasOption("database_port") ) {
951  if ( !option[dbms::port].user() ) {
953  "WARNING: To connect to a postgres or mysql database you must set"
954  "the database_port tag or specify -dbms:port on the command line.");
955  } else {
956  database_port=option[dbms::port];
957  }
958  } else {
959  database_port=tag->getOption<Size>("database_port");
960  }
961 
962 
964  database_mode, transaction_mode, chunk_size,
965  database_path,
966  database_pq_schema,
967  database_host,
968  database_user,
969  database_password,
970  database_port);
971  }
972  default :
974  "Unrecognized database mode: '" +
975  name_from_database_mode(database_mode) + "'");
976  }
977  return 0;
978 }
979 
980 }
981 }
#define utility_exit_with_message(m)
Exit with file + line + message.
Definition: exit.hh:47
Program path option class.
#define THREAD_LOCAL
static THREAD_LOCAL basic::Tracer TR("basic.database.sql_utils")
std::string make_compound_statement(std::string const &table_name, std::vector< std::string > const &column_names, platform::Size const &row_count)
Definition: sql_utils.cc:706
RandomGenerator & rg()
Return the one-per-thread "singleton" random generator.
Definition: random.cc:46
std::string name_from_database_mode(DatabaseMode::e database_mode)
Definition: types.cc:83
sessionOP get_db_session(DatabaseMode::e db_mode, TransactionMode::e transaction_mode, Size chunk_size, string const &db_name, string const &pq_schema)
Definition: sql_utils.cc:149
BooleanOptionKey const user("options:user")
Definition: OptionKeys.hh:40
Program string option class.
std::ssize_t SSize
Definition: types.hh:38
void trim(std::string &s, const std::string &drop)
Definition: string_util.cc:296
statement safely_prepare_statement(string const &statement_string, sessionOP db_session)
Definition: sql_utils.cc:333
utility::sql_database::sessionOP parse_database_connection(utility::tag::TagCOP tag)
Definition: sql_utils.cc:733
DatabaseMode::e database_mode_from_name(std::string database_mode)
Definition: types.cc:26
Program boolean option class.
Program scalar-valued option abstract base class.
Random number generator system.
common derived classes for thrown exceptions
TracerProxy Warning
Definition: Tracer.hh:262
bool table_exists(sessionOP db_session, string const &table_name)
Definition: sql_utils.cc:473
void check_statement_sanity(string sql)
Definition: sql_utils.cc:522
result safely_read_from_database(statement &statement)
Definition: sql_utils.cc:418
sessionOP get_session_postgres(std::string const &database, TransactionMode::e transaction_mode, platform::Size chunk_size, std::string const &pq_schema, std::string const &host, std::string const &user, std::string const &password, platform::Size port)
Acquire a postgres database session.
platform::SSize db_partition_from_options(DatabaseMode::e db_mode)
@
Definition: sql_utils.cc:269
std::string join(utility::vector1< std::string > const &s, std::string const &connector)
combine strings with anything
Definition: string_util.cc:91
tuple database
void write_schema_to_database(string schema_str, sessionOP db_session)
Definition: sql_utils.cc:663
sessionOP get_db_session(DatabaseMode::e db_mode, TransactionMode::e transaction_mode, platform::Size chunk_size, std::string const &db_name, std::string const &pq_schema, std::string const &host, std::string const &user, std::string const &password, platform::Size port, bool readonly=false, platform::SSize db_partition=-1)
Acquire a database session.
Program exit functions and macros.
std::string name_from_transaction_mode(TransactionMode::e transaction_mode)
Definition: types.cc:60
Tracer IO system.
void set_cache_size(sessionOP db_session, Size cache_size)
Definition: sql_utils.cc:688
#define utility_exit()
Macro function wrappers for utility::exit.
Definition: exit.hh:41
std::vector with 1-based indexing
Definition: vector1.fwd.hh:44
TracerProxy Error
Definition: Tracer.hh:262
void insert_or_ignore(string table_name, std::vector< string > column_names, std::vector< string > values, sessionOP db_session)
Definition: sql_utils.cc:542
rule< Scanner, options_closure::context_t > options
Definition: Tag.cc:377
BooleanOptionKey const all("options:all")
Definition: OptionKeys.hh:41
void safely_write_to_database(statement &statement)
Definition: sql_utils.cc:354
static DatabaseSessionManager * get_instance()
return singleton instance of session manager
Program integer option class.
Path name class supporting Windows and UN*X/Linux format names.
vector1: std::vector with 1-based indexing
int mpi_rank()
Definition: mpi_util.cc:254
Class for handling user debug/warnings/errors. Use instance of this class instead of 'std::cout' for ...
Definition: Tracer.hh:134
sessionOP get_session_sqlite3(std::string const &database, TransactionMode::e transaction_mode=TransactionMode::standard, platform::Size chunk_size=0, bool const readonly=false, platform::SSize db_partition=-1)
Acquire a sqlite3 database session.
utility::pointer::shared_ptr< Tag const > TagCOP
Definition: Tag.fwd.hh:27
double uniform()
Generate a random number between 0 and 1. Threadsafe since each thread uses its own random generator...
Definition: random.cc:56
An object for reading/writing a simple xml-like language.
sessionOP get_session_mysql(std::string const &database, TransactionMode::e transaction_mode, platform::Size chunk_size, std::string const &host, std::string const &user, std::string const &password, platform::Size port)
Acquire a mysql database session.
string mode
Definition: contacts.py:32
Some std::string helper functions.
Program options global and initialization function.
rule< Scanner, tag_closure::context_t > tag
Definition: Tag.cc:373
std::size_t Size
Definition: types.hh:37
TransactionMode::e transaction_mode_from_name(std::string transaction_mode)
Definition: types.cc:43
platform::Size Size
Definition: random.fwd.hh:30
pointer::shared_ptr< session > sessionOP
platform::SSize resolve_db_partition(bool partition_by_mpi_process, platform::SSize manual_partition)
Returns partition identifer from mpi rank if in partitioned database mode, or valid manual partition...
Definition: sql_utils.cc:314
rule< Scanner, option_closure::context_t > option
Definition: Tag.cc:378