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

Generated by: LCOV version 1.14