LCOV - code coverage report
Current view: top level - clients/mapiclient - msqldump.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 106 213 49.8 %
Date: 2024-12-19 23:10:26 Functions: 1 2 50.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #ifndef HAVE_GETOPT_LONG
      15             : #  include "monet_getopt.h"
      16             : #else
      17             : # ifdef HAVE_GETOPT_H
      18             : #  include "getopt.h"
      19             : # endif
      20             : #endif
      21             : #include "mapi.h"
      22             : #include <unistd.h>
      23             : #include <sys/stat.h>
      24             : #include <string.h>
      25             : #include <time.h>
      26             : 
      27             : #include "stream.h"
      28             : #include "msqldump.h"
      29             : #define LIBMUTILS 1
      30             : #include "mprompt.h"
      31             : #include "mutils.h"           /* mercurial_revision */
      32             : #include "dotmonetdb.h"
      33             : 
      34             : static _Noreturn void usage(const char *prog, int xit);
      35             : 
      36             : static void
      37           0 : usage(const char *prog, int xit)
      38             : {
      39           0 :         fprintf(stderr, "Usage: %s [ options ] [ dbname ]\n", prog);
      40           0 :         fprintf(stderr, "\nOptions are:\n");
      41           0 :         fprintf(stderr, " -h hostname | --host=hostname    host to connect to\n");
      42           0 :         fprintf(stderr, " -p portnr   | --port=portnr      port to connect to\n");
      43           0 :         fprintf(stderr, " -u user     | --user=user        user id\n");
      44           0 :         fprintf(stderr, " -d database | --database=database  database to connect to\n");
      45           0 :         fprintf(stderr, " -o filename | --output=filename  write dump to filename\n");
      46           0 :         fprintf(stderr, " -O dir      | --outputdir=dir    write multi-file dump to dir\n");
      47           0 :         fprintf(stderr, " -x ext      | --compression=ext  compression method ext for multi-file dump\n");
      48           0 :         fprintf(stderr, " -f          | --functions        dump functions\n");
      49           0 :         fprintf(stderr, " -t table    | --table=table      dump a database table\n");
      50           0 :         fprintf(stderr, " -D          | --describe         describe database\n");
      51           0 :         fprintf(stderr, " -N          | --inserts          use INSERT INTO statements\n");
      52           0 :         fprintf(stderr, " -e          | --noescape         use NO ESCAPE\n");
      53           0 :         fprintf(stderr, " -q          | --quiet            don't print welcome message\n");
      54           0 :         fprintf(stderr, " -X          | --Xdebug           trace mapi network interaction\n");
      55           0 :         fprintf(stderr, " -?          | --help             show this usage message\n");
      56           0 :         fprintf(stderr, "--functions and --table are mutually exclusive\n");
      57           0 :         fprintf(stderr, "--output and --outputdir are mutually exclusive\n");
      58           0 :         fprintf(stderr, "--inserts and --outputdir are mutually exclusive\n");
      59           0 :         fprintf(stderr, "--compression only has effect with --outputdir\n");
      60           0 :         exit(xit);
      61             : }
      62             : 
      63             : int
      64             : #ifdef _MSC_VER
      65             : wmain(int argc, wchar_t **wargv)
      66             : #else
      67          25 : main(int argc, char **argv)
      68             : #endif
      69             : {
      70          25 :         int port = 0;
      71          25 :         const char *user = NULL;
      72          25 :         const char *passwd = NULL;
      73          25 :         const char *host = NULL;
      74          25 :         const char *dbname = NULL;
      75          25 :         const char *output = NULL;
      76          25 :         const char *outputdir = NULL;
      77          25 :         const char *ext = NULL;
      78          25 :         DotMonetdb dotfile = {0};
      79          25 :         bool trace = false;
      80          25 :         bool describe = false;
      81          25 :         bool functions = false;
      82          25 :         bool useinserts = false;
      83          25 :         bool noescape = false;
      84          25 :         int c;
      85          25 :         Mapi mid;
      86          25 :         bool quiet = false;
      87          25 :         stream *out;
      88          25 :         bool user_set_as_flag = false;
      89          25 :         char *table = NULL;
      90          25 :         static struct option long_options[] = {
      91             :                 {"host", 1, 0, 'h'},
      92             :                 {"port", 1, 0, 'p'},
      93             :                 {"database", 1, 0, 'd'},
      94             :                 {"output", 1, 0, 'o'},
      95             :                 {"outputdir", 1, 0, 'O'},
      96             :                 {"compression", 1, 0, 'x'},
      97             :                 {"describe", 0, 0, 'D'},
      98             :                 {"functions", 0, 0, 'f'},
      99             :                 {"table", 1, 0, 't'},
     100             :                 {"inserts", 0, 0, 'N'},
     101             :                 {"noescape", 0, 0, 'e'},
     102             :                 {"Xdebug", 0, 0, 'X'},
     103             :                 {"user", 1, 0, 'u'},
     104             :                 {"quiet", 0, 0, 'q'},
     105             :                 {"version", 0, 0, 'v'},
     106             :                 {"help", 0, 0, '?'},
     107             :                 {0, 0, 0, 0}
     108             :         };
     109             : #ifdef _MSC_VER
     110             :         char **argv = malloc((argc + 1) * sizeof(char *));
     111             :         if (argv == NULL) {
     112             :                 fprintf(stderr, "cannot allocate memory for argument conversion\n");
     113             :                 exit(1);
     114             :         }
     115             :         for (int i = 0; i < argc; i++) {
     116             :                 if ((argv[i] = wchartoutf8(wargv[i])) == NULL) {
     117             :                         fprintf(stderr, "cannot convert argument to UTF-8\n");
     118             :                         exit(1);
     119             :                 }
     120             :         }
     121             :         argv[argc] = NULL;
     122             : #endif
     123             : 
     124          25 :         parse_dotmonetdb(&dotfile);
     125          25 :         user = dotfile.user;
     126          25 :         passwd = dotfile.passwd;
     127          25 :         dbname = dotfile.dbname;
     128          25 :         host = dotfile.host;
     129          25 :         port = dotfile.port;
     130             : 
     131         123 :         while ((c = getopt_long(argc, argv, "h:p:d:o:O:x:Dft:NeXu:qv?", long_options, NULL)) != -1) {
     132          99 :                 switch (c) {
     133           0 :                 case 'u':
     134           0 :                         user = optarg;
     135           0 :                         user_set_as_flag = true;
     136           0 :                         break;
     137          24 :                 case 'h':
     138          24 :                         host = optarg;
     139          24 :                         break;
     140          24 :                 case 'p':
     141          24 :                         assert(optarg != NULL);
     142          24 :                         port = atoi(optarg);
     143          24 :                         break;
     144          24 :                 case 'd':
     145          24 :                         dbname = optarg;
     146          24 :                         break;
     147           0 :                 case 'o':
     148           0 :                         output = optarg;
     149           0 :                         outputdir = NULL;
     150           0 :                         break;
     151           1 :                 case 'O':
     152           1 :                         outputdir = optarg;
     153           1 :                         output = NULL;
     154           1 :                         break;
     155           0 :                 case 'x':
     156           0 :                         ext = optarg;
     157           0 :                         break;
     158             :                 case 'D':
     159             :                         describe = true;
     160             :                         break;
     161           1 :                 case 'N':
     162           1 :                         useinserts = true;
     163           1 :                         break;
     164           0 :                 case 'e':
     165           0 :                         noescape = true;
     166           0 :                         break;
     167           0 :                 case 'f':
     168           0 :                         if (table)
     169           0 :                                 usage(argv[0], -1);
     170             :                         functions = true;
     171             :                         break;
     172           0 :                 case 't':
     173           0 :                         if (table || functions)
     174           0 :                                 usage(argv[0], -1);
     175           0 :                         table = optarg;
     176           0 :                         break;
     177          24 :                 case 'q':
     178          24 :                         quiet = true;
     179          24 :                         break;
     180           0 :                 case 'X':
     181           0 :                         trace = true;
     182           0 :                         break;
     183           1 :                 case 'v': {
     184           1 :                         printf("msqldump, the MonetDB interactive database "
     185             :                                "dump tool, version %s", MONETDB_VERSION);
     186             : #ifdef MONETDB_RELEASE
     187             :                         printf(" (%s)", MONETDB_RELEASE);
     188             : #else
     189           1 :                         const char *rev = mercurial_revision();
     190           1 :                         if (strcmp(rev, "Unknown") != 0)
     191           0 :                                 printf(" (hg id: %s)", rev);
     192             : #endif
     193           1 :                         printf("\n");
     194           1 :                         destroy_dotmonetdb(&dotfile);
     195           1 :                         return 0;
     196             :                 }
     197           0 :                 case '?':
     198             :                         /* a bit of a hack: look at the option that the
     199             :                            current `c' is based on and see if we recognize
     200             :                            it: if -? or --help, exit with 0, else with -1 */
     201           0 :                         usage(argv[0], strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0 ? 0 : -1);
     202           0 :                 default:
     203           0 :                         usage(argv[0], -1);
     204             :                 }
     205             :         }
     206             : 
     207          24 :         if ((output != NULL || useinserts) && outputdir) {
     208           0 :                 usage(argv[0], -1);
     209             :         }
     210             : 
     211          24 :         if (optind == argc - 1)
     212           0 :                 dbname = argv[optind];
     213          24 :         else if (optind != argc)
     214           0 :                 usage(argv[0], -1);
     215             : 
     216             :         /* when config file would provide defaults */
     217          24 :         if (user_set_as_flag)
     218           0 :                 passwd = NULL;
     219             : 
     220          24 :         if(dbname == NULL){
     221           0 :                 printf("msqldump, please specify a database\n");
     222           0 :                 usage(argv[0], -1);
     223             :         }
     224          24 :         char *user_allocated = NULL;
     225          24 :         if (user == NULL) {
     226           0 :                 user_allocated = simple_prompt("user", BUFSIZ, 1, prompt_getlogin());
     227           0 :                 user = user_allocated;
     228             :         }
     229          24 :         char *passwd_allocated = NULL;
     230          24 :         if (passwd == NULL) {
     231           0 :                 passwd_allocated = simple_prompt("password", BUFSIZ, 0, NULL);
     232           0 :                 passwd = passwd_allocated;
     233             :         }
     234             : 
     235          24 :         if (dbname != NULL && strchr(dbname, ':') != NULL) {
     236           0 :                 mid = mapi_mapiuri(dbname, user, passwd, "sql");
     237             :         } else {
     238          24 :                 mid = mapi_mapi(host, port, user, passwd, "sql", dbname);
     239             :         }
     240          24 :         free(user_allocated);
     241          24 :         user_allocated = NULL;
     242          24 :         free(passwd_allocated);
     243          24 :         passwd_allocated = NULL;
     244          24 :         user = NULL;
     245          24 :         passwd = NULL;
     246          24 :         dbname = NULL;
     247          24 :         if (mid == NULL) {
     248           0 :                 fprintf(stderr, "failed to allocate Mapi structure\n");
     249           0 :                 exit(2);
     250             :         }
     251          24 :         if (mapi_error(mid)) {
     252           0 :                 mapi_explain(mid, stderr);
     253           0 :                 exit(2);
     254             :         }
     255          24 :         mapi_set_time_zone(mid, 0);
     256          24 :         mapi_reconnect(mid);
     257          24 :         if (mapi_error(mid)) {
     258           0 :                 mapi_explain(mid, stderr);
     259           0 :                 exit(2);
     260             :         }
     261          24 :         if (!quiet) {
     262           0 :                 const char *motd = mapi_get_motd(mid);
     263             : 
     264           0 :                 if (motd)
     265           0 :                         fprintf(stderr, "%s", motd);
     266             :         }
     267          24 :         mapi_trace(mid, trace);
     268          24 :         mapi_cache_limit(mid, -1);
     269             : 
     270          24 :         if (output) {
     271           0 :                 out = open_wastream(output);
     272          24 :         } else if (outputdir) {
     273           1 :                 size_t fnl = strlen(outputdir) + 10;
     274           1 :                 if (ext)
     275           0 :                         fnl += strlen(ext) + 1;
     276           1 :                 char *fn = malloc(fnl);
     277           1 :                 if (fn == NULL) {
     278           0 :                         fprintf(stderr, "malloc failure\n");
     279           0 :                         exit(2);
     280             :                 }
     281           1 :                 if (MT_mkdir(outputdir) == -1 && errno != EEXIST) {
     282           0 :                         perror("cannot create output directory");
     283           0 :                         exit(2);
     284             :                 }
     285           1 :                 snprintf(fn, fnl, "%s%cdump.sql", outputdir, DIR_SEP);
     286           1 :                 out = open_wastream(fn);
     287           1 :                 free(fn);
     288           1 :                 (void) ext;
     289             :         } else {
     290          23 :                 out = stdout_wastream();
     291             :         }
     292          24 :         if (out == NULL) {
     293           0 :                 if (output)
     294           0 :                         fprintf(stderr, "cannot open file: %s: %s\n",
     295             :                                         output, mnstr_peek_error(NULL));
     296           0 :                 else if (outputdir)
     297           0 :                         fprintf(stderr, "cannot open file: %s%cdump.sql: %s\n",
     298             :                                         outputdir, DIR_SEP, mnstr_peek_error(NULL));
     299             :                 else
     300           0 :                         fprintf(stderr, "failed to allocate stream: %s\n",
     301             :                                         mnstr_peek_error(NULL));
     302           0 :                 exit(2);
     303             :         }
     304          24 :         if (!quiet) {
     305           0 :                 char buf[27];
     306           0 :                 time_t t = time(0);
     307           0 :                 char *p;
     308             : 
     309             : #ifdef HAVE_CTIME_R3
     310             :                 ctime_r(&t, buf, sizeof(buf));
     311             : #else
     312             : #ifdef HAVE_CTIME_R
     313           0 :                 ctime_r(&t, buf);
     314             : #else
     315             :                 strcpy_len(buf, ctime(&t), sizeof(buf));
     316             : #endif
     317             : #endif
     318           0 :                 if ((p = strrchr(buf, '\n')) != NULL)
     319           0 :                         *p = 0;
     320             : 
     321           0 :                 mnstr_printf(out,
     322             :                              "-- msqldump version %s", MONETDB_VERSION);
     323             : #ifdef MONETDB_RELEASE
     324             :                 mnstr_printf(out, " (%s)", MONETDB_RELEASE);
     325             : #else
     326           0 :                 const char *rev = mercurial_revision();
     327           0 :                 if (strcmp(rev, "Unknown") != 0)
     328           0 :                         mnstr_printf(out, " (hg id: %s)", rev);
     329             : #endif
     330           0 :                 mnstr_printf(out, " %s %s%s\n",
     331             :                              describe ? "describe" : "dump",
     332           0 :                              functions ? "functions" : table ? "table " : "database",
     333             :                              table ? table : "");
     334           0 :                 dump_version(mid, out, "-- server:");
     335           0 :                 mnstr_printf(out, "-- %s\n", buf);
     336             :         }
     337          24 :         if (functions) {
     338           0 :                 mnstr_printf(out, "START TRANSACTION;\n");
     339           0 :                 c = dump_functions(mid, out, true, NULL, NULL, NULL);
     340           0 :                 mnstr_printf(out, "COMMIT;\n");
     341          24 :         } else if (table) {
     342           0 :                 mnstr_printf(out, "START TRANSACTION;\n");
     343           0 :                 c = dump_table(mid, NULL, table, out, outputdir, ext, describe, true, useinserts, false, noescape, true);
     344           0 :                 mnstr_printf(out, "COMMIT;\n");
     345             :         } else
     346          24 :                 c = dump_database(mid, out, outputdir, ext, describe, useinserts, noescape);
     347          24 :         mnstr_flush(out, MNSTR_FLUSH_DATA);
     348             : 
     349          24 :         mapi_destroy(mid);
     350          24 :         if (mnstr_errnr(out) != MNSTR_NO__ERROR) {
     351           0 :                 fprintf(stderr, "%s: %s\n", argv[0], mnstr_peek_error(out));
     352           0 :                 c = 1;
     353             :         }
     354             : 
     355          24 :         close_stream(out);
     356             : 
     357          24 :         destroy_dotmonetdb(&dotfile);
     358             : 
     359          24 :         return c;
     360             : }

Generated by: LCOV version 1.14