1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9#include "monetdb_config.h"
10#ifndef HAVE_GETOPT_LONG
11# include "monet_getopt.h"
12#else
13# ifdef HAVE_GETOPT_H
14# include "getopt.h"
15# endif
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#define LIBMUTILS 1
26#include "mprompt.h"
27#include "mutils.h" /* mercurial_revision */
28#include "dotmonetdb.h"
29
30static _Noreturn void usage(const char *prog, int xit);
31
32static void
33usage(const char *prog, int xit)
34{
35 fprintf(stderr, "Usage: %s [ options ] [ dbname ]\n", prog);
36 fprintf(stderr, "\nOptions are:\n");
37 fprintf(stderr, " -h hostname | --host=hostname host to connect to\n");
38 fprintf(stderr, " -p portnr | --port=portnr port to connect to\n");
39 fprintf(stderr, " -u user | --user=user user id\n");
40 fprintf(stderr, " -d database | --database=database database to connect to\n");
41 fprintf(stderr, " -f | --functions dump functions\n");
42 fprintf(stderr, " -t table | --table=table dump a database table\n");
43 fprintf(stderr, " -D | --describe describe database\n");
44 fprintf(stderr, " -N | --inserts use INSERT INTO statements\n");
45 fprintf(stderr, " -q | --quiet don't print welcome message\n");
46 fprintf(stderr, " -X | --Xdebug trace mapi network interaction\n");
47 fprintf(stderr, " -? | --help show this usage message\n");
48 fprintf(stderr, "--functions and --table are mutually exclusive\n");
49 exit(xit);
50}
51
52int
53main(int argc, char **argv)
54{
55 int port = 0;
56 char *user = NULL;
57 char *passwd = NULL;
58 char *host = NULL;
59 char *dbname = NULL;
60 bool trace = false;
61 bool describe = false;
62 bool functions = false;
63 bool useinserts = false;
64 int c;
65 Mapi mid;
66 bool quiet = false;
67 stream *out;
68 bool user_set_as_flag = false;
69 char *table = NULL;
70 static struct option long_options[] = {
71 {"host", 1, 0, 'h'},
72 {"port", 1, 0, 'p'},
73 {"database", 1, 0, 'd'},
74 {"describe", 0, 0, 'D'},
75 {"functions", 0, 0, 'f'},
76 {"table", 1, 0, 't'},
77 {"inserts", 0, 0, 'N'},
78 {"Xdebug", 0, 0, 'X'},
79 {"user", 1, 0, 'u'},
80 {"quiet", 0, 0, 'q'},
81 {"version", 0, 0, 'v'},
82 {"help", 0, 0, '?'},
83 {0, 0, 0, 0}
84 };
85
86 parse_dotmonetdb(&user, &passwd, &dbname, NULL, NULL, NULL, NULL);
87
88 while ((c = getopt_long(argc, argv, "h:p:d:Dft:NXu:qv?", long_options, NULL)) != -1) {
89 switch (c) {
90 case 'u':
91 if (user)
92 free(user);
93 user = strdup(optarg);
94 user_set_as_flag = true;
95 break;
96 case 'h':
97 host = optarg;
98 break;
99 case 'p':
100 assert(optarg != NULL);
101 port = atoi(optarg);
102 break;
103 case 'd':
104 if (dbname)
105 free(dbname);
106 dbname = strdup(optarg);
107 break;
108 case 'D':
109 describe = true;
110 break;
111 case 'N':
112 useinserts = true;
113 break;
114 case 'f':
115 if (table)
116 usage(argv[0], -1);
117 functions = true;
118 break;
119 case 't':
120 if (table || functions)
121 usage(argv[0], -1);
122 table = optarg;
123 break;
124 case 'q':
125 quiet = true;
126 break;
127 case 'X':
128 trace = true;
129 break;
130 case 'v': {
131 printf("msqldump, the MonetDB interactive database "
132 "dump tool, version %s", VERSION);
133#ifdef MONETDB_RELEASE
134 printf(" (%s)", MONETDB_RELEASE);
135#else
136 const char *rev = mercurial_revision();
137 if (strcmp(rev, "Unknown") != 0)
138 printf(" (hg id: %s)", rev);
139#endif
140 printf("\n");
141 return 0;
142 }
143 case '?':
144 /* a bit of a hack: look at the option that the
145 current `c' is based on and see if we recognize
146 it: if -? or --help, exit with 0, else with -1 */
147 usage(argv[0], strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0 ? 0 : -1);
148 default:
149 usage(argv[0], -1);
150 }
151 }
152
153 if (optind == argc - 1)
154 dbname = strdup(argv[optind]);
155 else if (optind != argc)
156 usage(argv[0], -1);
157
158 /* when config file would provide defaults */
159 if (user_set_as_flag)
160 passwd = NULL;
161
162 if (user == NULL)
163 user = simple_prompt("user", BUFSIZ, 1, prompt_getlogin());
164 if (passwd == NULL)
165 passwd = simple_prompt("password", BUFSIZ, 0, NULL);
166
167 mid = mapi_connect(host, port, user, passwd, "sql", dbname);
168 if (user)
169 free(user);
170 if (passwd)
171 free(passwd);
172 if (dbname)
173 free(dbname);
174 if (mid == NULL) {
175 fprintf(stderr, "failed to allocate Mapi structure\n");
176 exit(2);
177 }
178 if (mapi_error(mid)) {
179 mapi_explain(mid, stderr);
180 exit(2);
181 }
182 if (!quiet) {
183 const char *motd = mapi_get_motd(mid);
184
185 if (motd)
186 fprintf(stderr, "%s", motd);
187 }
188 mapi_trace(mid, trace);
189 mapi_cache_limit(mid, 10000);
190
191 out = file_wastream(stdout, "stdout");
192 if (out == NULL) {
193 fprintf(stderr, "failed to allocate stream\n");
194 exit(2);
195 }
196 if (!quiet) {
197 char buf[27];
198 time_t t = time(0);
199 char *p;
200
201#ifdef HAVE_CTIME_R3
202 ctime_r(&t, buf, sizeof(buf));
203#else
204#ifdef HAVE_CTIME_R
205 ctime_r(&t, buf);
206#else
207 strcpy_len(buf, ctime(&t), sizeof(buf));
208#endif
209#endif
210 if ((p = strrchr(buf, '\n')) != NULL)
211 *p = 0;
212
213 mnstr_printf(out,
214 "-- msqldump version %s", VERSION);
215#ifdef MONETDB_RELEASE
216 mnstr_printf(out, " (%s)", MONETDB_RELEASE);
217#else
218 const char *rev = mercurial_revision();
219 if (strcmp(rev, "Unknown") != 0)
220 mnstr_printf(out, " (hg id: %s)", rev);
221#endif
222 mnstr_printf(out, " %s %s%s\n",
223 describe ? "describe" : "dump",
224 functions ? "functions" : table ? "table " : "database",
225 table ? table : "");
226 dump_version(mid, out, "-- server:");
227 mnstr_printf(out, "-- %s\n", buf);
228 }
229 if (functions) {
230 mnstr_printf(out, "START TRANSACTION;\n");
231 c = dump_functions(mid, out, true, NULL, NULL, NULL);
232 mnstr_printf(out, "COMMIT;\n");
233 } else if (table) {
234 mnstr_printf(out, "START TRANSACTION;\n");
235 c = dump_table(mid, NULL, table, out, describe, true, useinserts, false);
236 mnstr_printf(out, "COMMIT;\n");
237 } else
238 c = dump_database(mid, out, describe, useinserts);
239 mnstr_flush(out);
240
241 mapi_destroy(mid);
242 if (mnstr_errnr(out)) {
243 fprintf(stderr, "%s: %s", argv[0], mnstr_error(out));
244 return 1;
245 }
246
247 mnstr_destroy(out);
248 return c;
249}
250