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 : }
|