~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzledump.cc

  • Committer: Andrew Hutchings
  • Date: 2010-09-23 13:14:32 UTC
  • mto: (1792.1.1 build)
  • mto: This revision was merged to the branch mainline in revision 1793.
  • Revision ID: andrew@linuxjedi.co.uk-20100923131432-oyjj1nrtyfhtz7af
Add database connection class and the start of a database output ostream

Show diffs side-by-side

added added

removed removed

Lines of Context:
112
112
bool opt_drop= true; 
113
113
uint32_t show_progress_size= 0;
114
114
//static uint64_t total_rows= 0;
115
 
static drizzle_st drizzle;
116
 
 drizzle_con_st dcon;
117
115
static string insert_pat;
118
116
//static char *order_by= NULL;
119
117
static uint32_t opt_drizzle_port= 0;
122
120
FILE *md_result_file= 0;
123
121
FILE *stderror_file= 0;
124
122
std::vector<DrizzleDumpDatabase*> database_store;
125
 
 
126
 
enum server_type {
127
 
  SERVER_MYSQL_FOUND,
128
 
  SERVER_DRIZZLE_FOUND,
129
 
  SERVER_UNKNOWN_FOUND
130
 
};
131
 
 
132
 
int connected_server_type= SERVER_UNKNOWN_FOUND;
 
123
DrizzleDumpConnection* db_connection;
133
124
 
134
125
const string progname= "drizzledump";
135
126
 
152
143
 
153
144
static void maybe_exit(int error);
154
145
static void die(int error, const char* reason, ...);
155
 
static void maybe_die(int error, const char* reason, ...);
156
146
static void write_header(FILE *sql_file, char *db_name);
157
147
static int dump_selected_tables(const string &db, const vector<string> &table_names);
158
148
static int dump_databases(const vector<string> &db_names);
173
163
 
174
164
void generate_dump(void)
175
165
{
176
 
    std::vector<DrizzleDumpDatabase*>::iterator i;
 
166
  std::vector<DrizzleDumpDatabase*>::iterator i;
 
167
  DrizzleStringBuf sbuf(1024);
 
168
  std::ostream sout(&sbuf);
177
169
  for (i= database_store.begin(); i != database_store.end(); ++i)
178
170
  {
179
171
    DrizzleDumpDatabase *database= *i;
180
 
    cout << *database;
 
172
    
 
173
    sout << *database;
181
174
  }
182
175
}
183
176
 
184
177
/*
185
 
  Print the supplied message if in verbose mode
186
 
 
187
 
  SYNOPSIS
188
 
  verbose_msg()
189
 
  fmt   format specifier
190
 
  ...   variable number of parameters
191
 
*/
192
 
 
193
 
static void verbose_msg(const char *fmt, ...)
194
 
{
195
 
  va_list args;
196
 
 
197
 
 
198
 
  if (!verbose)
199
 
    return;
200
 
 
201
 
  va_start(args, fmt);
202
 
  vfprintf(stderr, fmt, args);
203
 
  va_end(args);
204
 
}
205
 
 
206
 
/*
207
178
  exit with message if ferror(file)
208
179
 
209
180
  SYNOPSIS
232
203
      fputs("-- ------------------------------------------------------\n",
233
204
            sql_file);
234
205
      fprintf(sql_file, "-- Server version\t%s",
235
 
              drizzle_con_server_version(&dcon));
236
 
      if (connected_server_type == SERVER_MYSQL_FOUND)
 
206
              db_connection->getServerVersion());
 
207
      if (db_connection->getServerType() == DrizzleDumpConnection::SERVER_MYSQL_FOUND)
237
208
        fprintf(sql_file, " (MySQL server)");
238
 
      else if (connected_server_type == SERVER_DRIZZLE_FOUND)
 
209
      else if (db_connection->getServerType() == DrizzleDumpConnection::SERVER_DRIZZLE_FOUND)
239
210
        fprintf(sql_file, " (Drizzle server)");
240
211
    }
241
212
    if (opt_set_charset)
313
284
 
314
285
 
315
286
/*
316
 
 ** DB_error -- prints DRIZZLE error message and exits the program.
317
 
*/
318
 
static void DB_error(drizzle_result_st *res, drizzle_return_t ret,
319
 
                     const char *when)
320
 
{
321
 
  if (ret == DRIZZLE_RETURN_ERROR_CODE)
322
 
  {
323
 
    maybe_die(EX_DRIZZLEERR, _("Got error: %s (%d) %s"),
324
 
              drizzle_result_error(res),
325
 
              drizzle_result_error_code(res),
326
 
              when);
327
 
    drizzle_result_free(res);
328
 
  }
329
 
  else
330
 
    maybe_die(EX_DRIZZLEERR, _("Got error: %d %s"), ret, when);
331
 
 
332
 
  return;
333
 
}
334
 
 
335
 
 
336
 
 
337
 
/*
338
287
  Prints out an error message and kills the process.
339
288
 
340
289
  SYNOPSIS
362
311
  maybe_exit(error_num);
363
312
}
364
313
 
365
 
 
366
 
/*
367
 
  Prints out an error message and maybe kills the process.
368
 
 
369
 
  SYNOPSIS
370
 
  maybe_die()
371
 
  error_num   - process return value
372
 
  fmt_reason  - a format string for use by vsnprintf.
373
 
  ...         - variable arguments for above fmt_reason string
374
 
 
375
 
  DESCRIPTION
376
 
  This call prints out the formatted error message to stderr and then
377
 
  terminates the process, unless the --force command line option is used.
378
 
 
379
 
  This call should be used for non-fatal errors (such as database
380
 
  errors) that the code may still be able to continue to the next unit
381
 
  of work.
382
 
 
383
 
*/
384
 
static void maybe_die(int error_num, const char* fmt_reason, ...)
385
 
{
386
 
  char buffer[1000];
387
 
  va_list args;
388
 
  va_start(args,fmt_reason);
389
 
  vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
390
 
  va_end(args);
391
 
 
392
 
  fprintf(stderr, "%s: %s\n", progname.c_str(), buffer);
393
 
  fflush(stderr);
394
 
 
395
 
  maybe_exit(error_num);
396
 
}
397
 
 
398
 
 
399
 
 
400
 
/*
401
 
  Sends a query to server, optionally reads result, prints error message if
402
 
  some.
403
 
 
404
 
  SYNOPSIS
405
 
  drizzleclient_query_with_error_report()
406
 
  drizzle_con       connection to use
407
 
  res             if non zero, result will be put there with
408
 
  drizzleclient_store_result()
409
 
  query           query to send to server
410
 
 
411
 
  RETURN VALUES
412
 
  0               query sending and (if res!=0) result reading went ok
413
 
  1               error
414
 
*/
415
 
 
416
 
static int drizzleclient_query_with_error_report(drizzle_con_st *con,
417
 
                                                 drizzle_result_st *result,
418
 
                                                 const char *query_str,
419
 
                                                 bool no_buffer)
420
 
{
421
 
  drizzle_return_t ret;
422
 
 
423
 
  if (drizzle_query_str(con, result, query_str, &ret) == NULL ||
424
 
      ret != DRIZZLE_RETURN_OK)
425
 
  {
426
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
427
 
    {
428
 
      maybe_die(EX_DRIZZLEERR, _("Couldn't execute '%s': %s (%d)"),
429
 
                query_str, drizzle_result_error(result),
430
 
                drizzle_result_error_code(result));
431
 
      drizzle_result_free(result);
432
 
    }
433
 
    else
434
 
    {
435
 
      maybe_die(EX_DRIZZLEERR, _("Couldn't execute '%s': %s (%d)"),
436
 
                query_str, drizzle_con_error(con), ret);
437
 
    }
438
 
    return 1;
439
 
  }
440
 
 
441
 
  if (no_buffer)
442
 
    ret= drizzle_column_buffer(result);
443
 
  else
444
 
    ret= drizzle_result_buffer(result);
445
 
  if (ret != DRIZZLE_RETURN_OK)
446
 
  {
447
 
    drizzle_result_free(result);
448
 
    maybe_die(EX_DRIZZLEERR, _("Couldn't execute '%s': %s (%d)"),
449
 
              query_str, drizzle_con_error(con), ret);
450
 
    return 1;
451
 
  }
452
 
 
453
 
  return 0;
454
 
}
455
 
 
456
314
static void free_resources(void)
457
315
{
458
316
  if (md_result_file && md_result_file != stdout)
467
325
    first_error= error;
468
326
  if (ignore_errors)
469
327
    return;
470
 
  drizzle_con_free(&dcon);
471
 
  drizzle_free(&drizzle);
 
328
  delete db_connection;
472
329
  free_resources();
473
330
  exit(error);
474
331
}
475
332
 
476
 
 
477
 
/*
478
 
  db_connect -- connects to the host and selects DB.
479
 
*/
480
 
 
481
 
static int connect_to_db(string host, string user,string passwd)
482
 
{
483
 
  drizzle_return_t ret;
484
 
 
485
 
  verbose_msg(_("-- Connecting to %s, using protocol %s...\n"), ! host.empty() ? (char *)host.c_str() : "localhost", opt_protocol.c_str());
486
 
  drizzle_create(&drizzle);
487
 
  drizzle_con_create(&drizzle, &dcon);
488
 
  drizzle_con_set_tcp(&dcon, (char *)host.c_str(), opt_drizzle_port);
489
 
  drizzle_con_set_auth(&dcon, (char *)user.c_str(), (char *)passwd.c_str());
490
 
  drizzle_con_add_options(&dcon, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
491
 
  ret= drizzle_con_connect(&dcon);
492
 
  if (ret != DRIZZLE_RETURN_OK)
493
 
  {
494
 
    DB_error(NULL, ret, "when trying to connect");
495
 
    return(1);
496
 
  }
497
 
 
498
 
  int found= get_server_type();
499
 
 
500
 
  switch (found)
501
 
  {
502
 
    case SERVER_MYSQL_FOUND:
503
 
     verbose_msg(_("-- Connected to a MySQL server\n"));
504
 
     connected_server_type= SERVER_MYSQL_FOUND;
505
 
     break;
506
 
    case SERVER_DRIZZLE_FOUND:
507
 
     verbose_msg(_("-- Connected to a Drizzle server\n"));
508
 
     connected_server_type= SERVER_DRIZZLE_FOUND;
509
 
     break;
510
 
    default:
511
 
     verbose_msg(_("-- Connected to an unknown server type\n"));
512
 
     connected_server_type= SERVER_DRIZZLE_FOUND;
513
 
     break;
514
 
  }
515
 
 
516
 
  return(0);
517
 
} /* connect_to_db */
518
 
 
519
 
 
520
 
/*
521
 
 ** dbDisconnect -- disconnects from the host.
522
 
*/
523
 
static void dbDisconnect(string &host)
524
 
{
525
 
  verbose_msg(_("-- Disconnecting from %s...\n"), ! host.empty() ? host.c_str() : "localhost");
526
 
  drizzle_con_free(&dcon);
527
 
  drizzle_free(&drizzle);
528
 
} /* dbDisconnect */
529
 
 
530
333
static int dump_all_databases()
531
334
{
532
335
  drizzle_row_t row;
533
 
  drizzle_result_st tableres;
 
336
  drizzle_result_st *tableres;
534
337
  int result=0;
535
338
  std::string query;
536
339
  DrizzleDumpDatabase *database;
537
340
 
538
 
  if (connected_server_type == SERVER_MYSQL_FOUND)
 
341
  if (db_connection->getServerType() == DrizzleDumpConnection::SERVER_MYSQL_FOUND)
539
342
    query= "SELECT SCHEMA_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('information_schema', 'performance_schema')";
540
343
  else
541
344
    query= "SELECT SCHEMA_NAME, DEFAULT_COLLATION_NAME FROM DATA_DICTIONARY.SCHEMAS WHERE SCHEMA_NAME NOT IN ('information_schema','data_dictionary')";
542
345
 
543
 
  if (drizzleclient_query_with_error_report(&dcon, &tableres, query.c_str(), false))
544
 
    return 1;
545
 
  while ((row= drizzle_row_next(&tableres)))
 
346
  tableres= db_connection->query(query);
 
347
  while ((row= drizzle_row_next(tableres)))
546
348
  {
547
349
    std::string database_name(row[0]);
548
 
    if (connected_server_type == SERVER_MYSQL_FOUND)
549
 
      database= new DrizzleDumpDatabaseMySQL(database_name);
 
350
    if (db_connection->getServerType() == DrizzleDumpConnection::SERVER_MYSQL_FOUND)
 
351
      database= new DrizzleDumpDatabaseMySQL(database_name, db_connection);
550
352
    else
551
 
      database= new DrizzleDumpDatabaseDrizzle(database_name);
 
353
      database= new DrizzleDumpDatabaseDrizzle(database_name, db_connection);
552
354
 
553
355
    database->setCollate(row[1]);
554
356
    database_store.push_back(database);
555
357
  }
556
 
  drizzle_result_free(&tableres);
 
358
  db_connection->freeResult(tableres);
557
359
  return result;
558
360
}
559
361
/* dump_all_databases */
568
370
  for (vector<string>::const_iterator it= db_names.begin(); it != db_names.end(); ++it)
569
371
  {
570
372
    temp= *it;
571
 
    if (connected_server_type == SERVER_MYSQL_FOUND)
572
 
      database= new DrizzleDumpDatabaseMySQL(temp);
 
373
    if (db_connection->getServerType() == DrizzleDumpConnection::SERVER_MYSQL_FOUND)
 
374
      database= new DrizzleDumpDatabaseMySQL(temp, db_connection);
573
375
    else
574
 
      database= new DrizzleDumpDatabaseDrizzle(temp);
 
376
      database= new DrizzleDumpDatabaseDrizzle(temp, db_connection);
575
377
    database_store.push_back(database);
576
378
  }
577
379
  return(result);
582
384
  DrizzleDumpDatabase *database;
583
385
  DrizzleDumpTable *table;
584
386
 
585
 
  if (connected_server_type == SERVER_MYSQL_FOUND)
586
 
    database= new DrizzleDumpDatabaseMySQL(db);
 
387
  if (db_connection->getServerType() == DrizzleDumpConnection::SERVER_MYSQL_FOUND)
 
388
    database= new DrizzleDumpDatabaseMySQL(db, db_connection);
587
389
  else
588
 
    database= new DrizzleDumpDatabaseDrizzle(db);
 
390
    database= new DrizzleDumpDatabaseDrizzle(db, db_connection);
589
391
 
590
392
  database_store.push_back(database); 
591
393
 
592
394
  for (vector<string>::const_iterator it= table_names.begin(); it != table_names.end(); ++it)
593
395
  {
594
396
    string temp= *it;
595
 
    if (connected_server_type == SERVER_MYSQL_FOUND)
596
 
      table= new DrizzleDumpTableMySQL(temp);
 
397
    if (db_connection->getServerType() == DrizzleDumpConnection::SERVER_MYSQL_FOUND)
 
398
      table= new DrizzleDumpTableMySQL(temp, db_connection);
597
399
    else
598
 
      table= new DrizzleDumpTableDrizzle(temp);
 
400
      table= new DrizzleDumpTableDrizzle(temp, db_connection);
599
401
    database->tables.push_back(table);
600
402
  }
601
403
  database_store.push_back(database);
603
405
  return 0;
604
406
} /* dump_selected_tables */
605
407
 
606
 
static int do_flush_tables_read_lock(drizzle_con_st *drizzle_con)
 
408
static int do_flush_tables_read_lock()
607
409
{
608
410
  /*
609
411
    We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES
613
415
    and most client connections are stalled. Of course, if a second long
614
416
    update starts between the two FLUSHes, we have that bad stall.
615
417
  */
616
 
  return
617
 
    ( drizzleclient_query_with_error_report(drizzle_con, 0, "FLUSH TABLES", false) ||
618
 
      drizzleclient_query_with_error_report(drizzle_con, 0,
619
 
                                            "FLUSH TABLES WITH READ LOCK", false) );
620
 
}
621
 
 
622
 
static int do_unlock_tables(drizzle_con_st *drizzle_con)
623
 
{
624
 
  return drizzleclient_query_with_error_report(drizzle_con, 0, "UNLOCK TABLES", false);
625
 
}
626
 
 
627
 
static int start_transaction(drizzle_con_st *drizzle_con)
628
 
{
629
 
  return (drizzleclient_query_with_error_report(drizzle_con, 0,
630
 
                                                "SET SESSION TRANSACTION ISOLATION "
631
 
                                                "LEVEL REPEATABLE READ", false) ||
632
 
          drizzleclient_query_with_error_report(drizzle_con, 0,
633
 
                                                "START TRANSACTION "
634
 
                                                "WITH CONSISTENT SNAPSHOT", false));
635
 
}
636
 
 
637
 
 
638
 
int get_server_type()
639
 
{
640
 
  boost::match_flag_type flags = boost::match_default; 
641
 
 
642
 
  boost::regex mysql_regex("(5\\.[0-9]+\\.[0-9]+)");
643
 
  boost::regex drizzle_regex("(20[0-9]{2}\\.(0[1-9]|1[012])\\.[0-9]+)");
644
 
 
645
 
  std::string version(drizzle_con_server_version(&dcon));
646
 
 
647
 
  if (regex_search(version, mysql_regex, flags))
648
 
    return SERVER_MYSQL_FOUND;
649
 
  
650
 
  if (regex_search(version, drizzle_regex, flags))
651
 
    return SERVER_DRIZZLE_FOUND;
652
 
 
653
 
  return SERVER_UNKNOWN_FOUND;
 
418
 
 
419
   db_connection->queryNoResult("FLUSH TABLES");
 
420
   db_connection->queryNoResult("FLUSH TABLES WITH READ LOCK");
 
421
 
 
422
  return 0;
 
423
}
 
424
 
 
425
static int do_unlock_tables()
 
426
{
 
427
  db_connection->queryNoResult("UNLOCK TABLES");
 
428
  return 0;
 
429
}
 
430
 
 
431
static int start_transaction()
 
432
{
 
433
  db_connection->queryNoResult("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ");
 
434
  db_connection->queryNoResult("START TRANSACTION WITH CONSISTENT SNAPSHOT");
 
435
  return 0;
654
436
}
655
437
 
656
438
int main(int argc, char **argv)
658
440
try
659
441
{
660
442
  int exit_code;
661
 
  drizzle_result_st result;
662
443
 
663
444
  po::options_description commandline_options(N_("Options used only in command line"));
664
445
  commandline_options.add_options()
950
731
    exit(exit_code);
951
732
  }
952
733
 
953
 
  if (connect_to_db(current_host, current_user, opt_password))
954
 
  {
955
 
    free_resources();
956
 
    exit(EX_DRIZZLEERR);
957
 
  }
 
734
  db_connection = new DrizzleDumpConnection(current_host, opt_drizzle_port,
 
735
    current_user, opt_password, use_drizzle_protocol);
958
736
 
959
 
  if (connected_server_type == SERVER_MYSQL_FOUND)
960
 
  {
961
 
    if (drizzleclient_query_with_error_report(&dcon, &result, "SET NAMES 'utf8'", false))
962
 
      goto err;
963
 
    drizzle_result_free(&result);
964
 
  }
 
737
  if (db_connection->getServerType() == DrizzleDumpConnection::SERVER_MYSQL_FOUND)
 
738
    db_connection->queryNoResult("SET NAMES 'utf8'");
965
739
 
966
740
  if (path.empty() && vm.count("database-used"))
967
741
  {
969
743
    write_header(md_result_file, (char *)database_used.c_str());
970
744
  }
971
745
 
972
 
  if ((opt_lock_all_tables) && do_flush_tables_read_lock(&dcon))
 
746
  if ((opt_lock_all_tables) && do_flush_tables_read_lock())
973
747
    goto err;
974
 
  if (opt_single_transaction && start_transaction(&dcon))
 
748
  if (opt_single_transaction && start_transaction())
975
749
    goto err;
976
750
  if (opt_lock_all_tables)
977
 
  {
978
 
    if (drizzleclient_query_with_error_report(&dcon, &result, "FLUSH LOGS", false))
979
 
      goto err;
980
 
    drizzle_result_free(&result);
981
 
    flush_logs= 0; /* not anymore; that would not be sensible */
982
 
  }
983
 
  if (opt_single_transaction && do_unlock_tables(&dcon)) /* unlock but no commit! */
 
751
    db_connection->queryNoResult("FLUSH LOGS");
 
752
  if (opt_single_transaction && do_unlock_tables()) /* unlock but no commit! */
984
753
    goto err;
985
754
 
986
755
  if (opt_alldbs)
1036
805
    server.
1037
806
  */
1038
807
err:
1039
 
  dbDisconnect(current_host);
 
808
  delete db_connection;
1040
809
  if (path.empty())
1041
810
    write_footer(md_result_file);
1042
811
  free_resources();