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 : #include "mapi.h"
15 : #include "stream.h"
16 : #include "mstring.h"
17 : #include <unistd.h>
18 : #include <string.h>
19 : #include <ctype.h>
20 :
21 : // TODO get rid of this ugly work around: Properly factor out mapi cals from dump.c
22 : #ifdef COMPILING_MONETDBE
23 :
24 : #define Mapi monetdbe_Mapi
25 : #define MapiHdl monetdbe_MapiHdl
26 : #define MapiHdl monetdbe_MapiHdl
27 : #define MapiMsg monetdbe_MapiMsg
28 :
29 : #define mapi_error monetdbe_mapi_error
30 : #define mapi_query monetdbe_mapi_query
31 : #define mapi_error monetdbe_mapi_error
32 : #define mapi_close_handle monetdbe_mapi_close_handle
33 : #define mapi_fetch_row monetdbe_mapi_fetch_row
34 : #define mapi_fetch_field monetdbe_mapi_fetch_field
35 : #define mapi_get_type monetdbe_mapi_get_type
36 : #define mapi_seek_row monetdbe_mapi_seek_row
37 : #define mapi_get_row_count monetdbe_mapi_get_row_count
38 : #define mapi_rows_affected monetdbe_mapi_rows_affected
39 : #define mapi_get_field_count monetdbe_mapi_get_field_count
40 : #define mapi_result_error monetdbe_mapi_result_error
41 : #define mapi_get_len monetdbe_mapi_get_len
42 : #define mapi_explain monetdbe_mapi_explain
43 : #define mapi_explain_query monetdbe_mapi_explain_query
44 : #define mapi_explain_result monetdbe_mapi_explain_result
45 :
46 : #include "monetdbe_mapi.h"
47 : #else
48 : #include "mapi.h"
49 : #endif
50 :
51 : #include "msqldump.h"
52 :
53 : static int
54 6411 : dquoted_print(stream *f, const char *s, const char *suff)
55 : {
56 6411 : int space = 0;
57 :
58 6411 : if (mnstr_write(f, "\"", 1, 1) < 0)
59 : return -1;
60 : space++;
61 12822 : while (*s) {
62 6411 : size_t n;
63 6411 : if ((n = strcspn(s, "\"")) > 0) {
64 6393 : if (mnstr_write(f, s, 1, n) < 0)
65 : return -1;
66 6393 : space += (int) n;
67 6393 : s += n;
68 : }
69 6411 : if (*s) {
70 18 : assert(*s == '"');
71 18 : if (mnstr_write(f, "\"\"", 1, 2) < 0)
72 : return -1;
73 18 : space += 2;
74 18 : s++;
75 : }
76 : }
77 6411 : if (mnstr_write(f, "\"", 1, 1) < 0)
78 : return -1;
79 6411 : space++;
80 6411 : if (suff != NULL) {
81 5165 : int n;
82 5165 : if ((n = mnstr_printf(f, "%s", suff)) < 0)
83 : return -1;
84 5165 : space += n;
85 : }
86 : return space;
87 : }
88 :
89 : static int
90 3942330 : squoted_print(stream *f, const char *s, char quote, bool noescape)
91 : {
92 3942330 : assert(quote == '\'' || quote == '"');
93 3942330 : if (mnstr_printf(f, "%c", quote) < 0)
94 : return -1;
95 7884722 : while (*s) {
96 3942392 : size_t n = noescape ? strcspn(s, "'\"") :
97 3942392 : strcspn(s, "\\'\"\177"
98 : "\001\002\003\004\005\006\007"
99 : "\010\011\012\013\014\015\016\017"
100 : "\020\021\022\023\024\025\026\027"
101 : "\030\031\032\033\034\035\036\037");
102 3942392 : if (n > 0 && mnstr_write(f, s, 1, n) < 0)
103 : return -1;
104 3942392 : s += n;
105 3942392 : switch (*s) {
106 3942330 : case '\0':
107 3942330 : continue;
108 0 : case '\\':
109 0 : if (mnstr_write(f, "\\\\", 1, 2) < 0)
110 : return -1;
111 : break;
112 62 : case '\'':
113 : case '"':
114 62 : if (mnstr_write(f, s, 1, 1) < 0 ||
115 62 : (*s == quote && mnstr_write(f, s, 1, 1) < 0))
116 0 : return -1;
117 : break;
118 0 : case '\n':
119 0 : if (mnstr_write(f, "\\n", 1, 2) < 0)
120 : return -1;
121 : break;
122 0 : case '\t':
123 0 : if (mnstr_write(f, "\\t", 1, 2) < 0)
124 : return -1;
125 : break;
126 0 : default:
127 0 : if (mnstr_printf(f, "\\%03o", (uint8_t) *s) < 0)
128 : return -1;
129 : break;
130 : }
131 62 : s++;
132 : }
133 3942330 : if (mnstr_printf(f, "%c", quote) < 0)
134 : return -1;
135 : return 0;
136 : }
137 :
138 : static char *
139 644 : descape(const char *s)
140 : {
141 644 : const char *p;
142 644 : size_t n = 1;
143 :
144 6131 : for (p = s; *p; p++) {
145 5487 : n += *p == '"';
146 : }
147 644 : n += p - s;
148 644 : char *d = malloc(n);
149 644 : if (d == NULL)
150 : return NULL;
151 6131 : for (p = s, n = 0; *p; p++) {
152 5487 : d[n++] = *p;
153 5487 : if (*p == '"')
154 9 : d[n++] = '"';
155 : }
156 644 : d[n] = 0;
157 644 : return d;
158 : }
159 :
160 : static char *
161 4042 : sescape(const char *s)
162 : {
163 4042 : const char *p;
164 4042 : size_t n = 1;
165 :
166 38965 : for (p = s; *p; p++) {
167 34923 : n += *p == '\'' || *p == '\\';
168 : }
169 4042 : n += p - s;
170 4042 : char *d = malloc(n);
171 4042 : if (d == NULL)
172 : return NULL;
173 38965 : for (p = s, n = 0; *p; p++) {
174 34923 : d[n++] = *p;
175 34923 : if (*p == '\'')
176 0 : d[n++] = '\'';
177 34923 : else if (*p == '\\')
178 0 : d[n++] = '\\';
179 : }
180 4042 : d[n] = 0;
181 4042 : return d;
182 : }
183 :
184 : static int
185 545 : comment_on(stream *sqlf, const char *object,
186 : const char *ident1, const char *ident2, const char *ident3,
187 : const char *remark)
188 : {
189 545 : if (remark) {
190 198 : if (mnstr_printf(sqlf, "COMMENT ON %s ", object) < 0 ||
191 99 : dquoted_print(sqlf, ident1, NULL) < 0)
192 0 : return -1;
193 99 : if (ident2) {
194 180 : if (mnstr_printf(sqlf, ".") < 0 ||
195 90 : dquoted_print(sqlf, ident2, NULL) < 0)
196 0 : return -1;
197 90 : if (ident3) {
198 54 : if (mnstr_printf(sqlf, ".") < 0 ||
199 27 : dquoted_print(sqlf, ident3, NULL) < 0)
200 0 : return -1;
201 : }
202 : }
203 198 : if (mnstr_write(sqlf, " IS ", 1, 4) < 0 ||
204 198 : squoted_print(sqlf, remark, '\'', false) < 0 ||
205 99 : mnstr_write(sqlf, ";\n", 1, 2) < 0)
206 0 : return -1;
207 : }
208 : return 0;
209 : }
210 :
211 : static const char *actions[] = {
212 : 0,
213 : "CASCADE",
214 : "RESTRICT",
215 : "SET NULL",
216 : "SET DEFAULT",
217 : };
218 : #define NR_ACTIONS ((int) (sizeof(actions) / sizeof(actions[0])))
219 :
220 : static char *
221 31 : get_schema(Mapi mid)
222 : {
223 31 : char *nsname = NULL, *sname = NULL;
224 31 : MapiHdl hdl;
225 :
226 62 : if ((hdl = mapi_query(mid, "SELECT current_schema")) == NULL ||
227 31 : mapi_error(mid))
228 0 : goto bailout;
229 62 : while ((mapi_fetch_row(hdl)) != 0) {
230 31 : nsname = mapi_fetch_field(hdl, 0);
231 :
232 31 : if (mapi_error(mid))
233 0 : goto bailout;
234 : }
235 31 : if (mapi_error(mid))
236 0 : goto bailout;
237 : /* copy before closing the handle */
238 31 : if (nsname)
239 31 : sname = strdup(nsname);
240 31 : if (nsname && !sname)
241 0 : goto bailout;
242 31 : mapi_close_handle(hdl);
243 31 : return sname;
244 :
245 0 : bailout:
246 0 : if (hdl) {
247 0 : if (mapi_result_error(hdl))
248 0 : mapi_explain_result(hdl, stderr);
249 0 : else if (mapi_error(mid))
250 0 : mapi_explain_query(hdl, stderr);
251 : else
252 0 : fprintf(stderr, "malloc failure\n");
253 0 : mapi_close_handle(hdl);
254 0 : } else if (mapi_error(mid))
255 0 : mapi_explain(mid, stderr);
256 : else
257 0 : fprintf(stderr, "malloc failure\n");
258 : return NULL;
259 : }
260 :
261 : /* return TRUE if the HUGEINT type exists */
262 : static bool
263 525 : has_hugeint(Mapi mid)
264 : {
265 525 : MapiHdl hdl;
266 525 : bool ret;
267 525 : static int answer = -1;
268 :
269 525 : if (answer >= 0)
270 494 : return (bool) answer;
271 :
272 31 : if ((hdl = mapi_query(mid,
273 : "SELECT id "
274 : "FROM sys.types "
275 31 : "WHERE sqlname = 'hugeint'")) == NULL ||
276 31 : mapi_error(mid))
277 0 : goto bailout;
278 31 : ret = mapi_get_row_count(hdl) == 1;
279 64 : while ((mapi_fetch_row(hdl)) != 0) {
280 33 : if (mapi_error(mid))
281 0 : goto bailout;
282 : }
283 31 : if (mapi_error(mid))
284 0 : goto bailout;
285 31 : mapi_close_handle(hdl);
286 31 : answer = (int) ret;
287 31 : return answer;
288 :
289 0 : bailout:
290 0 : if (hdl) {
291 0 : if (mapi_result_error(hdl))
292 0 : mapi_explain_result(hdl, stderr);
293 : else
294 0 : mapi_explain_query(hdl, stderr);
295 0 : mapi_close_handle(hdl);
296 : } else
297 0 : mapi_explain(mid, stderr);
298 : return 0;
299 : }
300 :
301 : /* columns sys.db_user_info.max_memory and sys.db_user_info.max_workers
302 : * introduced Sep2022 */
303 : static bool
304 31 : has_schema_max_memory(Mapi mid)
305 : {
306 31 : MapiHdl hdl;
307 31 : bool ret;
308 31 : static int answer = -1;
309 :
310 31 : if (answer >= 0)
311 0 : return answer;
312 :
313 62 : if ((hdl = mapi_query(mid, "select id from sys._columns where table_id = (select id from sys._tables where name = 'db_user_info' and schema_id = 2000) and name = 'max_memory'")) == NULL ||
314 31 : mapi_error(mid))
315 0 : goto bailout;
316 31 : ret = mapi_get_row_count(hdl) == 1;
317 62 : while ((mapi_fetch_row(hdl)) != 0) {
318 31 : if (mapi_error(mid))
319 0 : goto bailout;
320 : }
321 31 : if (mapi_error(mid))
322 0 : goto bailout;
323 31 : mapi_close_handle(hdl);
324 31 : answer = ret;
325 31 : return ret;
326 :
327 0 : bailout:
328 0 : if (hdl) {
329 0 : if (mapi_result_error(hdl))
330 0 : mapi_explain_result(hdl, stderr);
331 : else
332 0 : mapi_explain_query(hdl, stderr);
333 0 : mapi_close_handle(hdl);
334 : } else
335 0 : mapi_explain(mid, stderr);
336 : return false;
337 : }
338 :
339 : /* table sys.remote_user_info introduced Jun2023 */
340 : static bool
341 9 : has_remote_user_info_table(Mapi mid)
342 : {
343 9 : MapiHdl hdl;
344 9 : bool ret;
345 9 : static int answer = -1;
346 :
347 9 : if (answer >= 0)
348 0 : return answer;
349 :
350 9 : if ((hdl = mapi_query(mid,
351 : "select id from sys._tables"
352 : " where name = 'remote_user_info'"
353 9 : " and schema_id = 2000")) == NULL ||
354 9 : mapi_error(mid))
355 0 : goto bailout;
356 9 : ret = mapi_get_row_count(hdl) == 1;
357 18 : while ((mapi_fetch_row(hdl)) != 0) {
358 9 : if (mapi_error(mid))
359 0 : goto bailout;
360 : }
361 9 : if (mapi_error(mid))
362 0 : goto bailout;
363 9 : mapi_close_handle(hdl);
364 9 : answer = ret;
365 9 : return ret;
366 :
367 0 : bailout:
368 0 : if (hdl) {
369 0 : if (mapi_result_error(hdl))
370 0 : mapi_explain_result(hdl, stderr);
371 : else
372 0 : mapi_explain_query(hdl, stderr);
373 0 : mapi_close_handle(hdl);
374 : } else
375 0 : mapi_explain(mid, stderr);
376 : return false;
377 : }
378 :
379 : static bool
380 401 : has_check_constraint(Mapi mid)
381 : {
382 401 : MapiHdl hdl;
383 401 : bool ret;
384 401 : static int answer = -1;
385 :
386 401 : if (answer >= 0)
387 379 : return answer;
388 :
389 22 : if ((hdl = mapi_query(mid,
390 : "select id from sys.functions"
391 : " where schema_id = 2000"
392 22 : " and name = 'check_constraint'")) == NULL ||
393 22 : mapi_error(mid))
394 0 : goto bailout;
395 22 : ret = mapi_get_row_count(hdl) == 1;
396 44 : while ((mapi_fetch_row(hdl)) != 0) {
397 22 : if (mapi_error(mid))
398 0 : goto bailout;
399 : }
400 22 : if (mapi_error(mid))
401 0 : goto bailout;
402 22 : mapi_close_handle(hdl);
403 22 : answer = ret;
404 22 : return ret;
405 :
406 0 : bailout:
407 0 : if (hdl) {
408 0 : if (mapi_result_error(hdl))
409 0 : mapi_explain_result(hdl, stderr);
410 : else
411 0 : mapi_explain_query(hdl, stderr);
412 0 : mapi_close_handle(hdl);
413 : } else
414 0 : mapi_explain(mid, stderr);
415 : return false;
416 : }
417 :
418 : static int
419 31 : dump_foreign_keys(Mapi mid, const char *schema, const char *tname, const char *tid, stream *sqlf)
420 : {
421 31 : MapiHdl hdl = NULL;
422 31 : int cnt, i;
423 31 : char *query;
424 31 : size_t maxquerylen = 0;
425 :
426 31 : if (tname != NULL) {
427 0 : char *s = sescape(schema);
428 0 : char *t = sescape(tname);
429 0 : if (s == NULL || t == NULL) {
430 0 : free(s);
431 0 : free(t);
432 0 : goto bailout;
433 : }
434 0 : maxquerylen = 1024 + strlen(t) + strlen(s);
435 0 : query = malloc(maxquerylen);
436 0 : if (query == NULL) {
437 0 : free(s);
438 0 : free(t);
439 0 : goto bailout;
440 : }
441 0 : snprintf(query, maxquerylen,
442 : "SELECT ps.name, " /* 0 */
443 : "pkt.name, " /* 1 */
444 : "pkkc.name, " /* 2 */
445 : "fkkc.name, " /* 3 */
446 : "fkkc.nr, " /* 4 */
447 : "fkk.name, " /* 5 */
448 : "fkk.\"action\", " /* 6 */
449 : "fs.name, " /* 7 */
450 : "fkt.name " /* 8 */
451 : "FROM sys._tables fkt, "
452 : "sys.objects fkkc, "
453 : "sys.keys fkk, "
454 : "sys._tables pkt, "
455 : "sys.objects pkkc, "
456 : "sys.keys pkk, "
457 : "sys.schemas ps, "
458 : "sys.schemas fs "
459 : "WHERE fkt.id = fkk.table_id "
460 : "AND pkt.id = pkk.table_id "
461 : "AND fkk.id = fkkc.id "
462 : "AND pkk.id = pkkc.id "
463 : "AND fkk.rkey = pkk.id "
464 : "AND fkkc.nr = pkkc.nr "
465 : "AND pkt.schema_id = ps.id "
466 : "AND fkt.schema_id = fs.id "
467 : "AND fs.name = '%s' "
468 : "AND fkt.name = '%s' "
469 : "ORDER BY fkk.name, fkkc.nr", s, t);
470 0 : free(s);
471 0 : free(t);
472 31 : } else if (tid != NULL) {
473 0 : maxquerylen = 1024 + strlen(tid);
474 0 : query = malloc(maxquerylen);
475 0 : if (query == NULL)
476 0 : goto bailout;
477 0 : snprintf(query, maxquerylen,
478 : "SELECT ps.name, " /* 0 */
479 : "pkt.name, " /* 1 */
480 : "pkkc.name, " /* 2 */
481 : "fkkc.name, " /* 3 */
482 : "fkkc.nr, " /* 4 */
483 : "fkk.name, " /* 5 */
484 : "fkk.\"action\", " /* 6 */
485 : "0, " /* 7 */
486 : "fkt.name " /* 8 */
487 : "FROM sys._tables fkt, "
488 : "sys.objects fkkc, "
489 : "sys.keys fkk, "
490 : "sys._tables pkt, "
491 : "sys.objects pkkc, "
492 : "sys.keys pkk, "
493 : "sys.schemas ps "
494 : "WHERE fkt.id = fkk.table_id "
495 : "AND pkt.id = pkk.table_id "
496 : "AND fkk.id = fkkc.id "
497 : "AND pkk.id = pkkc.id "
498 : "AND fkk.rkey = pkk.id "
499 : "AND fkkc.nr = pkkc.nr "
500 : "AND pkt.schema_id = ps.id "
501 : "AND fkt.id = %s "
502 : "ORDER BY fkk.name, fkkc.nr", tid);
503 : } else {
504 : query = "SELECT ps.name, " /* 0 */
505 : "pkt.name, " /* 1 */
506 : "pkkc.name, " /* 2 */
507 : "fkkc.name, " /* 3 */
508 : "fkkc.nr, " /* 4 */
509 : "fkk.name, " /* 5 */
510 : "fkk.\"action\", " /* 6 */
511 : "fs.name, " /* 7 */
512 : "fkt.name " /* 8 */
513 : "FROM sys._tables fkt, "
514 : "sys.objects fkkc, "
515 : "sys.keys fkk, "
516 : "sys._tables pkt, "
517 : "sys.objects pkkc, "
518 : "sys.keys pkk, "
519 : "sys.schemas ps, "
520 : "sys.schemas fs "
521 : "WHERE fkt.id = fkk.table_id "
522 : "AND pkt.id = pkk.table_id "
523 : "AND fkk.id = fkkc.id "
524 : "AND pkk.id = pkkc.id "
525 : "AND fkk.rkey = pkk.id "
526 : "AND fkkc.nr = pkkc.nr "
527 : "AND pkt.schema_id = ps.id "
528 : "AND fkt.schema_id = fs.id "
529 : "AND fkt.system = FALSE "
530 : "ORDER BY fs.name, fkt.name, "
531 : "fkk.name, fkkc.nr";
532 : }
533 31 : hdl = mapi_query(mid, query);
534 31 : if (query != NULL && maxquerylen != 0)
535 0 : free(query);
536 31 : maxquerylen = 0;
537 31 : if (hdl == NULL || mapi_error(mid))
538 0 : goto bailout;
539 :
540 31 : cnt = mapi_fetch_row(hdl);
541 167 : while (cnt != 0) {
542 136 : char *c_psname = mapi_fetch_field(hdl, 0);
543 136 : char *c_ptname = mapi_fetch_field(hdl, 1);
544 136 : char *c_pcolumn = mapi_fetch_field(hdl, 2);
545 136 : char *c_fcolumn = mapi_fetch_field(hdl, 3);
546 136 : char *c_nr = mapi_fetch_field(hdl, 4);
547 136 : char *c_fkname = mapi_fetch_field(hdl, 5);
548 136 : char *c_faction = mapi_fetch_field(hdl, 6);
549 136 : char *c_fsname = mapi_fetch_field(hdl, 7);
550 136 : char *c_ftname = mapi_fetch_field(hdl, 8);
551 136 : char **fkeys, **pkeys;
552 136 : int nkeys = 1;
553 :
554 136 : if (mapi_error(mid) || c_psname == NULL || c_ptname == NULL ||
555 136 : c_pcolumn == NULL || c_fcolumn == NULL || c_nr == NULL ||
556 136 : c_fkname == NULL || c_faction == NULL || c_fsname == NULL ||
557 : c_ftname == NULL) {
558 : /* none of the columns should be NULL */
559 0 : goto bailout;
560 : }
561 136 : assert(strcmp(c_nr, "0") == 0);
562 136 : (void) c_nr; /* pacify compilers in case assertions are disabled */
563 136 : fkeys = malloc(nkeys * sizeof(*fkeys));
564 136 : pkeys = malloc(nkeys * sizeof(*pkeys));
565 136 : if (fkeys == NULL || pkeys == NULL) {
566 0 : free(fkeys);
567 0 : free(pkeys);
568 0 : goto bailout;
569 : }
570 136 : pkeys[0] = strdup(c_pcolumn);
571 136 : fkeys[0] = strdup(c_fcolumn);
572 136 : c_psname = strdup(c_psname);
573 136 : c_ptname = strdup(c_ptname);
574 136 : c_pcolumn = strdup(c_pcolumn);
575 136 : c_fcolumn = strdup(c_fcolumn);
576 136 : c_fkname = strdup(c_fkname);
577 136 : c_faction = strdup(c_faction);
578 136 : c_fsname = strdup(c_fsname);
579 136 : c_ftname = strdup(c_ftname);
580 136 : if (c_psname == NULL || c_ptname == NULL || c_pcolumn == NULL ||
581 136 : c_fcolumn == NULL || c_nr == NULL || c_fkname == NULL ||
582 136 : c_faction == NULL || c_fsname == NULL || c_ftname == NULL ||
583 136 : fkeys[0] == NULL || pkeys[0] == NULL) {
584 0 : freeall_bailout:
585 : /* free all temporarily allocated data, then bailout */
586 0 : while (nkeys-- > 0) {
587 0 : if (pkeys)
588 0 : free(pkeys[nkeys]);
589 0 : if (fkeys)
590 0 : free(fkeys[nkeys]);
591 : }
592 0 : free(fkeys);
593 0 : free(pkeys);
594 0 : free(c_psname);
595 0 : free(c_ptname);
596 0 : free(c_pcolumn);
597 0 : free(c_fcolumn);
598 0 : free(c_fkname);
599 0 : free(c_faction);
600 0 : free(c_fsname);
601 0 : free(c_ftname);
602 0 : goto bailout;
603 : }
604 153 : while ((cnt = mapi_fetch_row(hdl)) != 0 && strcmp(mapi_fetch_field(hdl, 4), "0") != 0) {
605 17 : char *pkey = mapi_fetch_field(hdl, 2);
606 17 : char *fkey = mapi_fetch_field(hdl, 3);
607 17 : char **tkeys;
608 :
609 17 : if (pkey == NULL || fkey == NULL) {
610 : /* we're not expecting NULL values */
611 0 : goto freeall_bailout;
612 : }
613 17 : tkeys = realloc(pkeys, (nkeys + 1) * sizeof(*pkeys));
614 17 : if (tkeys == NULL)
615 0 : goto freeall_bailout;
616 17 : pkeys = tkeys;
617 17 : tkeys = realloc(fkeys, (nkeys + 1) * sizeof(*fkeys));
618 17 : if (tkeys == NULL)
619 0 : goto freeall_bailout;
620 17 : fkeys = tkeys;
621 17 : nkeys++;
622 17 : pkeys[nkeys - 1] = strdup(pkey);
623 17 : fkeys[nkeys - 1] = strdup(fkey);
624 17 : if (pkeys[nkeys - 1] == NULL || fkeys[nkeys - 1] == NULL) {
625 0 : goto freeall_bailout;
626 : }
627 : }
628 136 : if (tname == NULL && tid == NULL) {
629 136 : mnstr_printf(sqlf, "ALTER TABLE ");
630 136 : dquoted_print(sqlf, c_fsname, ".");
631 136 : dquoted_print(sqlf, c_ftname, " ADD ");
632 : } else {
633 0 : mnstr_printf(sqlf, ",\n\t");
634 : }
635 136 : if (c_fkname) {
636 136 : mnstr_printf(sqlf, "CONSTRAINT ");
637 136 : dquoted_print(sqlf, c_fkname, " ");
638 : }
639 136 : mnstr_printf(sqlf, "FOREIGN KEY (");
640 425 : for (i = 0; i < nkeys; i++) {
641 153 : if (i > 0)
642 17 : mnstr_printf(sqlf, ", ");
643 153 : dquoted_print(sqlf, fkeys[i], NULL);
644 : }
645 136 : mnstr_printf(sqlf, ") REFERENCES ");
646 136 : dquoted_print(sqlf, c_psname, ".");
647 136 : dquoted_print(sqlf, c_ptname, " (");
648 425 : for (i = 0; i < nkeys; i++) {
649 153 : if (i > 0)
650 17 : mnstr_printf(sqlf, ", ");
651 153 : dquoted_print(sqlf, pkeys[i], NULL);
652 : }
653 136 : mnstr_printf(sqlf, ")");
654 136 : if (c_faction) {
655 136 : int action = atoi(c_faction);
656 136 : int on_update;
657 136 : int on_delete;
658 :
659 136 : if ((on_delete = action & 255) != 0 &&
660 136 : on_delete < NR_ACTIONS &&
661 136 : on_delete != 2 /* RESTRICT -- default */)
662 9 : mnstr_printf(sqlf, " ON DELETE %s",
663 : actions[on_delete]);
664 136 : if ((on_update = (action >> 8) & 255) != 0 &&
665 127 : on_update < NR_ACTIONS &&
666 127 : on_update != 2 /* RESTRICT -- default */)
667 0 : mnstr_printf(sqlf, " ON UPDATE %s",
668 : actions[on_update]);
669 : }
670 136 : free(c_psname);
671 136 : free(c_ptname);
672 136 : free(c_pcolumn);
673 136 : free(c_fcolumn);
674 136 : free(c_fkname);
675 136 : free(c_faction);
676 136 : free(c_fsname);
677 136 : free(c_ftname);
678 289 : while (nkeys-- > 0) {
679 153 : free(pkeys[nkeys]);
680 153 : free(fkeys[nkeys]);
681 : }
682 136 : free(fkeys);
683 136 : free(pkeys);
684 :
685 136 : if (tname == NULL && tid == NULL)
686 136 : mnstr_printf(sqlf, ";\n");
687 :
688 136 : if (mnstr_errnr(sqlf) != MNSTR_NO__ERROR)
689 0 : goto bailout;
690 : }
691 31 : if (mapi_error(mid))
692 0 : goto bailout;
693 31 : if (hdl)
694 31 : mapi_close_handle(hdl);
695 31 : return 0;
696 :
697 0 : bailout:
698 0 : if (hdl) {
699 0 : if (mapi_result_error(hdl))
700 0 : mapi_explain_result(hdl, stderr);
701 0 : else if (mapi_error(mid))
702 0 : mapi_explain_query(hdl, stderr);
703 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
704 0 : fprintf(stderr, "malloc failure\n");
705 0 : mapi_close_handle(hdl);
706 0 : } else if (mapi_error(mid))
707 0 : mapi_explain(mid, stderr);
708 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
709 0 : fprintf(stderr, "malloc failure\n");
710 :
711 : return 1;
712 : }
713 :
714 : static const char *
715 597 : toUpper(const char *s)
716 : {
717 597 : static char toupperbuf[64];
718 597 : size_t i;
719 597 : size_t len = strlen(s);
720 :
721 597 : if (len >= sizeof(toupperbuf))
722 : return s; /* too long: it's not *that* important */
723 4124 : for (i = 0; i < len; i++)
724 3527 : toupperbuf[i] = toupper((int)s[i]);
725 597 : toupperbuf[i] = '\0';
726 597 : return toupperbuf;
727 : }
728 :
729 : static int dump_column_definition(
730 : Mapi mid,
731 : stream *sqlf,
732 : const char *schema,
733 : const char *tname,
734 : const char *tid,
735 : bool foreign,
736 : bool hashge);
737 :
738 : static const char *geomsubtypes[] = {
739 : NULL, /* 0 */
740 : "POINT", /* 1 */
741 : "LINESTRING", /* 2 */
742 : NULL, /* 3 */
743 : "POLYGON", /* 4 */
744 : "MULTIPOINT", /* 5 */
745 : "MULTILINESTRING", /* 6 */
746 : "MULTIPOLYGON", /* 7 */
747 : "GEOMETRYCOLLECTION", /* 8 */
748 : };
749 :
750 : static int
751 2156 : dump_type(Mapi mid, stream *sqlf, const char *c_type, const char *c_type_digits, const char *c_type_scale, bool hashge)
752 : {
753 2156 : int space = 0;
754 :
755 2156 : if (strcmp(c_type, "boolean") == 0) {
756 17 : space = mnstr_printf(sqlf, "BOOLEAN");
757 2139 : } else if (strcmp(c_type, "int") == 0) {
758 835 : space = mnstr_printf(sqlf, "INTEGER");
759 1304 : } else if (strcmp(c_type, "smallint") == 0) {
760 30 : space = mnstr_printf(sqlf, "SMALLINT");
761 1274 : } else if (strcmp(c_type, "tinyint") == 0) {
762 15 : space = mnstr_printf(sqlf, "TINYINT");
763 1259 : } else if (strcmp(c_type, "bigint") == 0) {
764 19 : space = mnstr_printf(sqlf, "BIGINT");
765 1240 : } else if (strcmp(c_type, "hugeint") == 0) {
766 0 : space = mnstr_printf(sqlf, "HUGEINT");
767 1240 : } else if (strcmp(c_type, "date") == 0) {
768 27 : space = mnstr_printf(sqlf, "DATE");
769 1213 : } else if (strcmp(c_type, "month_interval") == 0) {
770 45 : if (strcmp(c_type_digits, "1") == 0)
771 15 : space = mnstr_printf(sqlf, "INTERVAL YEAR");
772 30 : else if (strcmp(c_type_digits, "2") == 0)
773 15 : space = mnstr_printf(sqlf, "INTERVAL YEAR TO MONTH");
774 15 : else if (strcmp(c_type_digits, "3") == 0)
775 15 : space = mnstr_printf(sqlf, "INTERVAL MONTH");
776 : else
777 0 : fprintf(stderr, "Internal error: unrecognized month interval %s\n", c_type_digits);
778 1168 : } else if (strcmp(c_type, "day_interval") == 0 || strcmp(c_type, "sec_interval") == 0) {
779 150 : if (strcmp(c_type_digits, "4") == 0)
780 15 : space = mnstr_printf(sqlf, "INTERVAL DAY");
781 135 : else if (strcmp(c_type_digits, "5") == 0)
782 15 : space = mnstr_printf(sqlf, "INTERVAL DAY TO HOUR");
783 120 : else if (strcmp(c_type_digits, "6") == 0)
784 15 : space = mnstr_printf(sqlf, "INTERVAL DAY TO MINUTE");
785 105 : else if (strcmp(c_type_digits, "7") == 0)
786 15 : space = mnstr_printf(sqlf, "INTERVAL DAY TO SECOND");
787 90 : else if (strcmp(c_type_digits, "8") == 0)
788 15 : space = mnstr_printf(sqlf, "INTERVAL HOUR");
789 75 : else if (strcmp(c_type_digits, "9") == 0)
790 15 : space = mnstr_printf(sqlf, "INTERVAL HOUR TO MINUTE");
791 60 : else if (strcmp(c_type_digits, "10") == 0)
792 15 : space = mnstr_printf(sqlf, "INTERVAL HOUR TO SECOND");
793 45 : else if (strcmp(c_type_digits, "11") == 0)
794 15 : space = mnstr_printf(sqlf, "INTERVAL MINUTE");
795 30 : else if (strcmp(c_type_digits, "12") == 0)
796 15 : space = mnstr_printf(sqlf, "INTERVAL MINUTE TO SECOND");
797 15 : else if (strcmp(c_type_digits, "13") == 0)
798 15 : space = mnstr_printf(sqlf, "INTERVAL SECOND");
799 : else
800 0 : fprintf(stderr, "Internal error: unrecognized second interval %s\n", c_type_digits);
801 1018 : } else if (strcmp(c_type, "clob") == 0 ||
802 988 : (strcmp(c_type, "varchar") == 0 &&
803 281 : strcmp(c_type_digits, "0") == 0)) {
804 60 : space = mnstr_printf(sqlf, "CHARACTER LARGE OBJECT");
805 60 : if (strcmp(c_type_digits, "0") != 0)
806 6 : space += mnstr_printf(sqlf, "(%s)", c_type_digits);
807 958 : } else if (strcmp(c_type, "blob") == 0) {
808 44 : space = mnstr_printf(sqlf, "BINARY LARGE OBJECT");
809 44 : if (strcmp(c_type_digits, "0") != 0)
810 15 : space += mnstr_printf(sqlf, "(%s)", c_type_digits);
811 914 : } else if (strcmp(c_type, "timestamp") == 0 ||
812 884 : strcmp(c_type, "timestamptz") == 0) {
813 60 : space = mnstr_printf(sqlf, "TIMESTAMP");
814 60 : if (strcmp(c_type_digits, "7") != 0)
815 30 : space += mnstr_printf(sqlf, "(%d)", atoi(c_type_digits) - 1);
816 60 : if (strcmp(c_type, "timestamptz") == 0)
817 30 : space += mnstr_printf(sqlf, " WITH TIME ZONE");
818 854 : } else if (strcmp(c_type, "time") == 0 ||
819 823 : strcmp(c_type, "timetz") == 0) {
820 61 : space = mnstr_printf(sqlf, "TIME");
821 61 : if (strcmp(c_type_digits, "1") != 0)
822 30 : space += mnstr_printf(sqlf, "(%d)", atoi(c_type_digits) - 1);
823 61 : if (strcmp(c_type, "timetz") == 0)
824 30 : space += mnstr_printf(sqlf, " WITH TIME ZONE");
825 793 : } else if (strcmp(c_type, "real") == 0) {
826 45 : if (strcmp(c_type_digits, "24") == 0 &&
827 15 : strcmp(c_type_scale, "0") == 0)
828 15 : space = mnstr_printf(sqlf, "REAL");
829 30 : else if (strcmp(c_type_scale, "0") == 0)
830 15 : space = mnstr_printf(sqlf, "FLOAT(%s)", c_type_digits);
831 : else
832 15 : space = mnstr_printf(sqlf, "FLOAT(%s,%s)",
833 : c_type_digits, c_type_scale);
834 748 : } else if (strcmp(c_type, "double") == 0) {
835 48 : if (strcmp(c_type_digits, "53") == 0 &&
836 48 : strcmp(c_type_scale, "0") == 0)
837 48 : space = mnstr_printf(sqlf, "DOUBLE");
838 0 : else if (strcmp(c_type_scale, "0") == 0)
839 0 : space = mnstr_printf(sqlf, "FLOAT(%s)", c_type_digits);
840 : else
841 0 : space = mnstr_printf(sqlf, "FLOAT(%s,%s)",
842 : c_type_digits, c_type_scale);
843 700 : } else if (strcmp(c_type, "decimal") == 0 &&
844 125 : strcmp(c_type_digits, "1") == 0 &&
845 4 : strcmp(c_type_scale, "0") == 0) {
846 4 : space = mnstr_printf(sqlf, "DECIMAL");
847 696 : } else if (strcmp(c_type, "table") == 0) {
848 0 : mnstr_printf(sqlf, "TABLE ");
849 0 : dump_column_definition(mid, sqlf, NULL, NULL, c_type_digits, 1, hashge);
850 696 : } else if (strcmp(c_type, "geometry") == 0 &&
851 108 : strcmp(c_type_digits, "0") != 0) {
852 99 : const char *geom = NULL;
853 99 : int sub = atoi(c_type_digits);
854 :
855 99 : if (sub > 0 && (sub & 3) == 0 &&
856 99 : (sub >> 2) < (int) (sizeof(geomsubtypes) / sizeof(geomsubtypes[0])))
857 99 : geom = geomsubtypes[sub >> 2];
858 99 : if (geom) {
859 99 : mnstr_printf(sqlf, "GEOMETRY(%s", geom);
860 99 : if (strcmp(c_type_scale, "0") != 0)
861 0 : mnstr_printf(sqlf, ",%s", c_type_scale);
862 99 : mnstr_printf(sqlf, ")");
863 : } else {
864 0 : mnstr_printf(sqlf, "GEOMETRY");
865 : }
866 597 : } else if (strcmp(c_type_digits, "0") == 0) {
867 53 : space = mnstr_printf(sqlf, "%s", toUpper(c_type));
868 544 : } else if (strcmp(c_type_scale, "0") == 0) {
869 438 : space = mnstr_printf(sqlf, "%s(%s)",
870 : toUpper(c_type), c_type_digits);
871 : } else {
872 106 : if (strcmp(c_type, "decimal") == 0) {
873 106 : if (strcmp(c_type_digits, "39") == 0)
874 : c_type_digits = "38";
875 106 : else if (!hashge && strcmp(c_type_digits, "19") == 0)
876 106 : c_type_digits = "18";
877 : }
878 106 : space = mnstr_printf(sqlf, "%s(%s,%s)",
879 : toUpper(c_type), c_type_digits, c_type_scale);
880 : }
881 2156 : return space;
882 : }
883 :
884 : static int
885 401 : dump_column_definition(Mapi mid, stream *sqlf, const char *schema,
886 : const char *tname, const char *tid, bool foreign,
887 : bool hashge)
888 : {
889 401 : MapiHdl hdl = NULL;
890 401 : char *query = NULL;
891 401 : char *s, *t;
892 401 : size_t maxquerylen = 1024;
893 401 : int cnt;
894 401 : int slen;
895 401 : int cap;
896 : #define CAP(X) ((cap = (int) (X)) < 0 ? 0 : cap)
897 :
898 401 : t = tname ? sescape(tname) : NULL;
899 401 : s = schema ? sescape(schema) : NULL;
900 401 : if (tid == NULL) {
901 401 : if (tname == NULL || schema == NULL) {
902 0 : if (t != NULL)
903 0 : free(t);
904 0 : if (s != NULL)
905 0 : free(s);
906 0 : return 1;
907 : }
908 401 : maxquerylen += 2 * strlen(tname) + 2 * strlen(schema);
909 : }
910 : else
911 0 : maxquerylen += strlen(tid);
912 401 : if ((query = malloc(maxquerylen)) == NULL)
913 0 : goto bailout;
914 :
915 401 : mnstr_printf(sqlf, "(\n");
916 :
917 401 : if (tid)
918 0 : snprintf(query, maxquerylen,
919 : "SELECT c.name, " /* 0 */
920 : "c.type, " /* 1 */
921 : "c.type_digits, " /* 2 */
922 : "c.type_scale, " /* 3 */
923 : "c.\"null\", " /* 4 */
924 : "c.number " /* 5 */
925 : "FROM sys._columns c "
926 : "WHERE c.table_id = %s "
927 : "ORDER BY c.number", tid);
928 : else
929 401 : snprintf(query, maxquerylen,
930 : "SELECT c.name, " /* 0 */
931 : "c.type, " /* 1 */
932 : "c.type_digits, " /* 2 */
933 : "c.type_scale, " /* 3 */
934 : "c.\"null\", " /* 4 */
935 : "c.number " /* 5 */
936 : "FROM sys._columns c, "
937 : "sys._tables t, "
938 : "sys.schemas s "
939 : "WHERE c.table_id = t.id "
940 : "AND t.name = '%s' "
941 : "AND t.schema_id = s.id "
942 : "AND s.name = '%s' "
943 : "ORDER BY c.number", t, s);
944 401 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
945 0 : goto bailout;
946 :
947 401 : slen = mapi_get_len(hdl, 0) + 3; /* add quotes and space */
948 401 : cnt = 0;
949 2368 : while ((mapi_fetch_row(hdl)) != 0) {
950 1967 : const char *c_name = mapi_fetch_field(hdl, 0);
951 1967 : char *c_type = strdup(mapi_fetch_field(hdl, 1)); /* copy variables used outside this scope (look for possible mapi cache incoherency) */
952 1967 : char *c_type_digits = strdup(mapi_fetch_field(hdl, 2));
953 1967 : char *c_type_scale = strdup(mapi_fetch_field(hdl, 3));
954 1967 : const char *c_null = mapi_fetch_field(hdl, 4);
955 1967 : int space;
956 :
957 1967 : if (mapi_error(mid) || !c_type || !c_type_digits || !c_type_scale) {
958 0 : free(c_type);
959 0 : free(c_type_digits);
960 0 : free(c_type_scale);
961 0 : goto bailout;
962 : }
963 :
964 1967 : if (cnt)
965 1566 : mnstr_printf(sqlf, ",\n");
966 :
967 1967 : mnstr_printf(sqlf, "\t");
968 1967 : space = dquoted_print(sqlf, c_name, " ");
969 1967 : mnstr_printf(sqlf, "%*s", CAP(slen - space), "");
970 1967 : if (s != NULL && t != NULL &&
971 1967 : strcmp(c_type, "char") == 0 && strcmp(c_type_digits, "0") == 0) {
972 : /* if the number of characters is not specified (due to a bug),
973 : * calculate a size */
974 0 : char *c = descape(c_name);
975 0 : if (c != NULL) {
976 0 : size_t qlen = strlen(c) + strlen(s) + strlen(t) + 64;
977 0 : char *q = malloc(qlen);
978 0 : if (q != NULL) {
979 0 : snprintf(q, qlen, "SELECT max(length(\"%s\")) FROM \"%s\".\"%s\"", c, s, t);
980 0 : MapiHdl h = mapi_query(mid, q);
981 0 : if (h != NULL) {
982 0 : if (mapi_fetch_row(h) != 0) {
983 0 : const char *d = mapi_fetch_field(h, 0);
984 0 : free(c_type_digits);
985 : /* if NULL, i.e. no non-NULL values, fill in 1 */
986 0 : c_type_digits = strdup(d ? d : "1");
987 0 : fprintf(stderr, "Warning: fixing size of CHAR column for %s of table %s.%s\n", c_name, schema, tname);
988 : }
989 0 : mapi_close_handle(h);
990 : }
991 0 : free(q);
992 : }
993 0 : free(c);
994 : }
995 0 : if (c_type_digits == NULL)
996 0 : goto bailout;
997 : }
998 1967 : space = dump_type(mid, sqlf, c_type, c_type_digits, c_type_scale, hashge);
999 1967 : if (strcmp(c_null, "false") == 0) {
1000 188 : mnstr_printf(sqlf, "%*s NOT NULL",
1001 188 : CAP(13 - space), "");
1002 188 : space = 13;
1003 : }
1004 :
1005 1967 : cnt++;
1006 1967 : free(c_type);
1007 1967 : free(c_type_digits);
1008 1967 : free(c_type_scale);
1009 1967 : if (mnstr_errnr(sqlf) != MNSTR_NO__ERROR)
1010 0 : goto bailout;
1011 : }
1012 401 : if (mapi_error(mid))
1013 0 : goto bailout;
1014 401 : mapi_close_handle(hdl);
1015 401 : hdl = NULL;
1016 :
1017 : /* presumably we don't need to order on id, since there should
1018 : only be a single primary key, but it doesn't hurt, and the
1019 : code is then close to the code for the uniqueness
1020 : constraint */
1021 401 : if (tid)
1022 0 : snprintf(query, maxquerylen,
1023 : "SELECT kc.name, " /* 0 */
1024 : "kc.nr, " /* 1 */
1025 : "k.name, " /* 2 */
1026 : "kc.id " /* 3 */
1027 : "FROM sys.objects kc, "
1028 : "sys.keys k "
1029 : "WHERE kc.id = k.id "
1030 : "AND k.table_id = %s "
1031 : "AND k.type = 0 "
1032 : "ORDER BY kc.id, kc.nr", tid);
1033 : else
1034 401 : snprintf(query, maxquerylen,
1035 : "SELECT kc.name, " /* 0 */
1036 : "kc.nr, " /* 1 */
1037 : "k.name, " /* 2 */
1038 : "kc.id " /* 3 */
1039 : "FROM sys.objects kc, "
1040 : "sys.keys k, "
1041 : "sys.schemas s, "
1042 : "sys._tables t "
1043 : "WHERE kc.id = k.id "
1044 : "AND k.table_id = t.id "
1045 : "AND k.type = 0 "
1046 : "AND t.schema_id = s.id "
1047 : "AND s.name = '%s' "
1048 : "AND t.name = '%s' "
1049 : "ORDER BY kc.id, kc.nr", s, t);
1050 401 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1051 0 : goto bailout;
1052 : cnt = 0;
1053 555 : while ((mapi_fetch_row(hdl)) != 0) {
1054 154 : const char *c_column = mapi_fetch_field(hdl, 0);
1055 154 : const char *k_name = mapi_fetch_field(hdl, 2);
1056 :
1057 154 : if (mapi_error(mid))
1058 0 : goto bailout;
1059 154 : if (cnt == 0) {
1060 131 : mnstr_printf(sqlf, ",\n\t");
1061 131 : if (k_name) {
1062 131 : mnstr_printf(sqlf, "CONSTRAINT ");
1063 131 : dquoted_print(sqlf, k_name, " ");
1064 : }
1065 131 : mnstr_printf(sqlf, "PRIMARY KEY (");
1066 : } else
1067 23 : mnstr_printf(sqlf, ", ");
1068 154 : dquoted_print(sqlf, c_column, NULL);
1069 154 : cnt++;
1070 154 : if (mnstr_errnr(sqlf) != MNSTR_NO__ERROR)
1071 0 : goto bailout;
1072 : }
1073 401 : if (cnt)
1074 131 : mnstr_printf(sqlf, ")");
1075 401 : if (mapi_error(mid))
1076 0 : goto bailout;
1077 401 : mapi_close_handle(hdl);
1078 401 : hdl = NULL;
1079 :
1080 401 : const char *cc = has_check_constraint(mid) ? "case when k.type = 4 then sys.check_constraint(s.name, k.name) else null end" : "cast(null as varchar(10))";
1081 401 : if (tid)
1082 0 : snprintf(query, maxquerylen,
1083 : "SELECT kc.name, " /* 0 */
1084 : "kc.nr, " /* 1 */
1085 : "k.name, " /* 2 */
1086 : "kc.id, " /* 3 */
1087 : "k.type, " /* 4 */
1088 : "%s " /* 5 */
1089 : "FROM sys.objects kc, "
1090 : "sys.keys k "
1091 : "WHERE kc.id = k.id "
1092 : "AND k.table_id = %s "
1093 : "AND k.type = 1 "
1094 : "ORDER BY kc.id, kc.nr", cc, tid);
1095 : else
1096 401 : snprintf(query, maxquerylen,
1097 : "SELECT kc.name, " /* 0 */
1098 : "kc.nr, " /* 1 */
1099 : "k.name, " /* 2 */
1100 : "kc.id, " /* 3 */
1101 : "k.type, " /* 4 */
1102 : "%s " /* 5 */
1103 : "FROM sys.objects kc, "
1104 : "sys.keys k, "
1105 : "sys.schemas s, "
1106 : "sys._tables t "
1107 : "WHERE kc.id = k.id "
1108 : "AND k.table_id = t.id "
1109 : "AND k.type in (1, 3, 4) "
1110 : "AND t.schema_id = s.id "
1111 : "AND s.name = '%s' "
1112 : "AND t.name = '%s' "
1113 : "ORDER BY kc.id, kc.nr", cc, s, t);
1114 401 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1115 0 : goto bailout;
1116 : cnt = 0;
1117 451 : while ((mapi_fetch_row(hdl)) != 0) {
1118 50 : const char *c_column = mapi_fetch_field(hdl, 0);
1119 50 : const char *kc_nr = mapi_fetch_field(hdl, 1);
1120 50 : const char *k_name = mapi_fetch_field(hdl, 2);
1121 50 : const char *k_type = mapi_fetch_field(hdl, 4);
1122 :
1123 50 : if (mapi_error(mid))
1124 0 : goto bailout;
1125 50 : if (strcmp(kc_nr, "0") == 0) {
1126 41 : if (cnt)
1127 19 : mnstr_write(sqlf, ")", 1, 1);
1128 41 : cnt = 0;
1129 41 : mnstr_printf(sqlf, ",\n\t");
1130 41 : if (k_name) {
1131 41 : mnstr_printf(sqlf, "CONSTRAINT ");
1132 41 : dquoted_print(sqlf, k_name, " ");
1133 : }
1134 41 : if (strcmp(k_type, "4") == 0) {
1135 7 : const char *k_check = mapi_fetch_field(hdl, 5);
1136 7 : mnstr_printf(sqlf, "CHECK (%s)", k_check);
1137 : } else {
1138 34 : if (strcmp(k_type, "1") == 0) {
1139 22 : mnstr_printf(sqlf, "UNIQUE");
1140 : } else {
1141 12 : mnstr_printf(sqlf, "UNIQUE NULLS NOT DISTINCT");
1142 : }
1143 34 : mnstr_printf(sqlf, " (");
1144 34 : cnt = 1;
1145 : }
1146 : } else
1147 9 : mnstr_printf(sqlf, ", ");
1148 50 : if (cnt)
1149 43 : dquoted_print(sqlf, c_column, NULL);
1150 50 : if (mnstr_errnr(sqlf) != MNSTR_NO__ERROR)
1151 0 : goto bailout;
1152 : }
1153 401 : if (cnt)
1154 15 : mnstr_write(sqlf, ")", 1, 1);
1155 401 : if (mapi_error(mid))
1156 0 : goto bailout;
1157 401 : mapi_close_handle(hdl);
1158 401 : hdl = NULL;
1159 :
1160 401 : if (foreign &&
1161 0 : dump_foreign_keys(mid, schema, tname, tid, sqlf))
1162 0 : goto bailout;
1163 :
1164 401 : mnstr_printf(sqlf, "\n");
1165 :
1166 401 : mnstr_printf(sqlf, ")");
1167 :
1168 401 : if (t != NULL)
1169 401 : free(t);
1170 401 : if (s != NULL)
1171 401 : free(s);
1172 401 : free(query);
1173 401 : return 0;
1174 :
1175 0 : bailout:
1176 0 : if (hdl) {
1177 0 : if (mapi_result_error(hdl))
1178 0 : mapi_explain_result(hdl, stderr);
1179 0 : else if (mapi_error(mid))
1180 0 : mapi_explain_query(hdl, stderr);
1181 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
1182 0 : fprintf(stderr, "malloc failure\n");
1183 0 : mapi_close_handle(hdl);
1184 0 : } else if (mapi_error(mid))
1185 0 : mapi_explain(mid, stderr);
1186 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
1187 0 : fprintf(stderr, "malloc failure\n");
1188 0 : if (query != NULL)
1189 0 : free(query);
1190 0 : if (t != NULL)
1191 0 : free(t);
1192 0 : if (s != NULL)
1193 0 : free(s);
1194 : return 1;
1195 : }
1196 :
1197 : static int
1198 401 : describe_table(Mapi mid, const char *schema, const char *tname,
1199 : stream *sqlf, bool foreign, bool databaseDump)
1200 : {
1201 401 : int cnt, table_id = 0;
1202 401 : MapiHdl hdl = NULL;
1203 401 : char *query = NULL, *view = NULL, *remark = NULL, *s = NULL, *t = NULL;
1204 401 : int type = 0;
1205 401 : int ca = 0;
1206 401 : size_t maxquerylen;
1207 401 : bool hashge;
1208 :
1209 401 : hashge = has_hugeint(mid);
1210 :
1211 401 : s = sescape(schema);
1212 401 : t = sescape(tname);
1213 401 : if (s == NULL || t == NULL)
1214 0 : goto bailout;
1215 401 : maxquerylen = 5120 + strlen(t) + strlen(s);
1216 401 : query = malloc(maxquerylen);
1217 401 : if (query == NULL)
1218 0 : goto bailout;
1219 :
1220 401 : snprintf(query, maxquerylen,
1221 : "SELECT t.name, t.query, t.type, t.id, c.remark, t.commit_action "
1222 : "FROM sys.schemas s, sys._tables t "
1223 : "LEFT OUTER JOIN sys.comments c ON t.id = c.id "
1224 : "WHERE s.name = '%s' "
1225 : "AND t.schema_id = s.id "
1226 : "AND t.name = '%s'",
1227 : s, t);
1228 :
1229 401 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1230 0 : goto bailout;
1231 : cnt = 0;
1232 802 : while ((mapi_fetch_row(hdl)) != 0) {
1233 401 : cnt++;
1234 401 : view = mapi_fetch_field(hdl, 2);
1235 401 : if (view)
1236 401 : type = atoi(view);
1237 401 : view = mapi_fetch_field(hdl, 1);
1238 401 : table_id = atoi(mapi_fetch_field(hdl, 3));
1239 401 : remark = mapi_fetch_field(hdl, 4);
1240 401 : ca = atoi(mapi_fetch_field(hdl, 5));
1241 : }
1242 401 : if (mapi_error(mid)) {
1243 0 : view = NULL;
1244 0 : remark = NULL;
1245 0 : goto bailout;
1246 : }
1247 401 : if (view) {
1248 : /* skip initial comments and empty lines */
1249 9 : while ((view[0] == '-' && view[1] == '-') || view[0] == '\n') {
1250 0 : view = strchr(view, '\n');
1251 0 : if (view == NULL)
1252 : view = "";
1253 : else
1254 0 : view++;
1255 : }
1256 9 : if (!(view = strdup(view)))
1257 0 : goto bailout;
1258 : }
1259 401 : if (remark) {
1260 9 : if (!(remark = strdup(remark)))
1261 0 : goto bailout;
1262 : }
1263 401 : mapi_close_handle(hdl);
1264 401 : hdl = NULL;
1265 :
1266 401 : if (cnt != 1) {
1267 0 : if (cnt == 0)
1268 0 : fprintf(stderr, "table %s.%s does not exist\n", schema, tname);
1269 : else
1270 0 : fprintf(stderr, "table %s.%s is not unique, corrupt catalog?\n",
1271 : schema, tname);
1272 0 : goto bailout2;
1273 : }
1274 :
1275 401 : if (type == 1) {
1276 : /* the table is actually a view */
1277 0 : mnstr_printf(sqlf, "%s\n", view);
1278 0 : comment_on(sqlf, "VIEW", schema, tname, NULL, remark);
1279 : } else {
1280 401 : if (!databaseDump) { //if it is not a database dump the table might depend on UDFs that must be dumped first
1281 0 : assert(table_id);
1282 0 : snprintf(query, maxquerylen,
1283 : "SELECT f.id, s.name, f.name "
1284 : "FROM sys.schemas s, "
1285 : "sys.functions f "
1286 : "WHERE s.id = f.schema_id "
1287 : "AND f.id IN (SELECT id FROM sys.dependencies WHERE depend_id = '%d')",
1288 : table_id);
1289 0 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1290 0 : goto bailout;
1291 0 : while (mapi_fetch_row(hdl) != 0) {
1292 0 : bool failure = false;
1293 0 : char *function_id = strdup(mapi_fetch_field(hdl, 0));
1294 0 : char *schema_name = strdup(mapi_fetch_field(hdl, 1));
1295 0 : char *function_name = strdup(mapi_fetch_field(hdl, 2));
1296 :
1297 0 : if (function_id && schema_name && function_name)
1298 0 : dump_functions(mid, sqlf, 0, schema_name, function_name, function_id);
1299 : else
1300 : failure = true;
1301 :
1302 0 : free(function_id);
1303 0 : free(schema_name);
1304 0 : free(function_name);
1305 :
1306 0 : if (failure)
1307 0 : goto bailout;
1308 : }
1309 0 : mapi_close_handle(hdl);
1310 0 : hdl = NULL;
1311 : }
1312 : /* the table is a real table */
1313 802 : mnstr_printf(sqlf, "CREATE %sTABLE ",
1314 : ca > 0 ? "GLOBAL TEMPORARY " :
1315 : type == 3 ? "MERGE " :
1316 : type == 4 ? "STREAM " :
1317 : type == 5 ? "REMOTE " :
1318 : type == 6 ? "REPLICA " :
1319 : type == 7 ? "UNLOGGED " :
1320 : "");
1321 401 : dquoted_print(sqlf, schema, ".");
1322 401 : dquoted_print(sqlf, tname, " ");
1323 :
1324 401 : if (dump_column_definition(mid, sqlf, schema, tname, NULL, foreign, hashge))
1325 0 : goto bailout;
1326 401 : if (ca > 0) { /* temporary table */
1327 0 : mnstr_printf(sqlf, " ON COMMIT %s",
1328 : ca == 1 /* the default */ ? "DELETE ROWS" :
1329 0 : ca == 2 ? "PRESERVE ROWS" :
1330 : /* ca == 3 */ "DROP");
1331 401 : } else if (type == 5) { /* remote table */
1332 9 : char *rt_user = NULL;
1333 9 : char *rt_hash = NULL;
1334 9 : if (has_remote_user_info_table(mid)) {
1335 9 : snprintf(query, maxquerylen,
1336 : "SELECT username, sys.decypher(password) "
1337 : "FROM sys.remote_user_info where table_id = (select t.id from sys._tables t, sys.schemas s where "
1338 : "t.schema_id = s.id and s.name = '%s' and t.name = '%s')", schema, tname);
1339 : } else {
1340 0 : snprintf(query, maxquerylen,
1341 : "SELECT username, hash "
1342 : "FROM sys.remote_table_credentials('%s.%s')",
1343 : schema, tname);
1344 : }
1345 9 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1346 0 : goto bailout;
1347 18 : cnt = 0;
1348 18 : while (mapi_fetch_row(hdl) != 0) {
1349 9 : rt_user = mapi_fetch_field(hdl, 0);
1350 9 : rt_hash = mapi_fetch_field(hdl, 1);
1351 : }
1352 9 : mnstr_printf(sqlf, " ON ");
1353 9 : squoted_print(sqlf, view, '\'', false);
1354 9 : mnstr_printf(sqlf, " WITH USER ");
1355 9 : squoted_print(sqlf, rt_user, '\'', false);
1356 9 : mnstr_printf(sqlf, " ENCRYPTED PASSWORD ");
1357 9 : squoted_print(sqlf, rt_hash, '\'', false);
1358 9 : mapi_close_handle(hdl);
1359 9 : hdl = NULL;
1360 392 : } else if (type == 3) { /* A merge table might be partitioned */
1361 70 : int properties = 0;
1362 :
1363 70 : snprintf(query, maxquerylen, "SELECT tp.type FROM sys.table_partitions tp WHERE tp.table_id = '%d'", table_id);
1364 70 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1365 0 : goto bailout;
1366 113 : while (mapi_fetch_row(hdl) != 0)
1367 43 : properties = atoi(mapi_fetch_field(hdl, 0));
1368 70 : mapi_close_handle(hdl);
1369 :
1370 70 : if (properties) {
1371 43 : bool list = (properties & 2) == 2, column = (properties & 4) == 4;
1372 43 : const char *phow = list ? "VALUES" : "RANGE";
1373 43 : const char *pusing = column ? "ON" : "USING";
1374 43 : const char *expr = NULL;
1375 :
1376 43 : if (column) { /* by column */
1377 36 : snprintf(query, maxquerylen,
1378 : "SELECT c.name FROM sys.schemas s, sys._tables t, sys._columns c, sys.table_partitions tp "
1379 : "WHERE s.name = '%s' AND t.name = '%s' AND s.id = t.schema_id AND t.id = c.table_id "
1380 : "AND c.id = tp.column_id", s, t);
1381 : } else { /* by expression */
1382 7 : snprintf(query, maxquerylen,
1383 : "SELECT tp.expression FROM sys.schemas s, sys._tables t, sys.table_partitions tp "
1384 : "WHERE s.name = '%s' AND t.name = '%s' AND s.id = t.schema_id AND t.id = tp.table_id",
1385 : s, t);
1386 : }
1387 43 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1388 0 : goto bailout;
1389 86 : while (mapi_fetch_row(hdl) != 0)
1390 43 : expr = mapi_fetch_field(hdl, 0);
1391 43 : mnstr_printf(sqlf, " PARTITION BY %s %s (", phow, pusing);
1392 43 : if (column)
1393 36 : dquoted_print(sqlf, expr, ")");
1394 : else
1395 7 : mnstr_printf(sqlf, "%s)", expr);
1396 43 : mapi_close_handle(hdl);
1397 : }
1398 : }
1399 401 : mnstr_printf(sqlf, ";\n");
1400 401 : comment_on(sqlf, "TABLE", schema, tname, NULL, remark);
1401 :
1402 401 : snprintf(query, maxquerylen,
1403 : "SELECT i.name, " /* 0 */
1404 : "k.name, " /* 1 */
1405 : "kc.nr, " /* 2 */
1406 : "c.name, " /* 3 */
1407 : "it.idx " /* 4 */
1408 : "FROM sys.idxs AS i "
1409 : "LEFT JOIN sys.keys AS k ON i.name = k.name, "
1410 : "sys.objects AS kc, "
1411 : "sys._columns AS c, "
1412 : "sys.schemas s, "
1413 : "sys._tables AS t, "
1414 : "(VALUES (0, 'INDEX'), "
1415 : "(4, 'IMPRINTS INDEX'), "
1416 : "(5, 'ORDERED INDEX')) AS it (id, idx) "
1417 : "WHERE i.table_id = t.id "
1418 : "AND i.id = kc.id "
1419 : "AND t.id = c.table_id "
1420 : "AND kc.name = c.name "
1421 : "AND (k.type IS NULL OR k.type = 1) "
1422 : "AND t.schema_id = s.id "
1423 : "AND s.name = '%s' "
1424 : "AND t.name = '%s' "
1425 : "AND i.type in (0, 4, 5) "
1426 : "AND i.type = it.id "
1427 : "ORDER BY i.name, kc.nr", s, t);
1428 401 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1429 0 : goto bailout;
1430 : cnt = 0;
1431 475 : while (mapi_fetch_row(hdl) != 0) {
1432 74 : const char *i_name = mapi_fetch_field(hdl, 0);
1433 74 : const char *k_name = mapi_fetch_field(hdl, 1);
1434 74 : const char *kc_nr = mapi_fetch_field(hdl, 2);
1435 74 : const char *c_name = mapi_fetch_field(hdl, 3);
1436 74 : const char *i_type = mapi_fetch_field(hdl, 4);
1437 :
1438 74 : if (mapi_error(mid))
1439 0 : goto bailout;
1440 74 : if (k_name != NULL) {
1441 : /* unique key, already handled */
1442 26 : continue;
1443 : }
1444 :
1445 48 : if (strcmp(kc_nr, "0") == 0) {
1446 36 : if (cnt)
1447 25 : mnstr_printf(sqlf, ");\n");
1448 36 : mnstr_printf(sqlf, "CREATE %s ", i_type);
1449 36 : dquoted_print(sqlf, i_name, " ON ");
1450 36 : dquoted_print(sqlf, schema, ".");
1451 36 : dquoted_print(sqlf, tname, " (");
1452 36 : cnt = 1;
1453 : } else
1454 12 : mnstr_printf(sqlf, ", ");
1455 48 : dquoted_print(sqlf, c_name, NULL);
1456 48 : if (mnstr_errnr(sqlf) != MNSTR_NO__ERROR)
1457 0 : goto bailout;
1458 : }
1459 401 : mapi_close_handle(hdl);
1460 401 : hdl = NULL;
1461 401 : if (cnt)
1462 11 : mnstr_printf(sqlf, ");\n");
1463 401 : snprintf(query, maxquerylen,
1464 : "SELECT i.name, c.remark "
1465 : "FROM sys.idxs i, sys.comments c "
1466 : "WHERE i.id = c.id "
1467 : "AND i.table_id = (SELECT id FROM sys._tables WHERE schema_id = (select id FROM sys.schemas WHERE name = '%s') AND name = '%s') "
1468 : "ORDER BY i.name",
1469 : s, t);
1470 401 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1471 0 : goto bailout;
1472 428 : while (mapi_fetch_row(hdl) != 0) {
1473 27 : comment_on(sqlf, "INDEX", schema,
1474 27 : mapi_fetch_field(hdl, 0), NULL,
1475 27 : mapi_fetch_field(hdl, 1));
1476 : }
1477 401 : mapi_close_handle(hdl);
1478 401 : hdl = NULL;
1479 : }
1480 :
1481 401 : snprintf(query, maxquerylen,
1482 : "SELECT col.name, com.remark "
1483 : "FROM sys._columns col, sys.comments com "
1484 : "WHERE col.id = com.id "
1485 : "AND col.table_id = (SELECT id FROM sys._tables WHERE schema_id = (SELECT id FROM sys.schemas WHERE name = '%s') AND name = '%s') "
1486 : "ORDER BY col.number",
1487 : s, t);
1488 401 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1489 0 : goto bailout;
1490 428 : while (mapi_fetch_row(hdl) != 0) {
1491 27 : comment_on(sqlf, "COLUMN", schema, tname,
1492 27 : mapi_fetch_field(hdl, 0),
1493 27 : mapi_fetch_field(hdl, 1));
1494 : }
1495 401 : mapi_close_handle(hdl);
1496 401 : hdl = NULL;
1497 401 : if (mapi_error(mid))
1498 0 : goto bailout;
1499 :
1500 401 : free(s);
1501 401 : free(t);
1502 401 : if (view)
1503 9 : free(view);
1504 401 : if (remark)
1505 9 : free(remark);
1506 401 : if (query != NULL)
1507 401 : free(query);
1508 401 : return 0;
1509 :
1510 0 : bailout:
1511 0 : if (hdl) {
1512 0 : if (mapi_result_error(hdl))
1513 0 : mapi_explain_result(hdl, stderr);
1514 0 : else if (mapi_error(mid))
1515 0 : mapi_explain_query(hdl, stderr);
1516 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
1517 0 : fprintf(stderr, "malloc failure\n");
1518 0 : mapi_close_handle(hdl);
1519 0 : } else if (mapi_error(mid))
1520 0 : mapi_explain(mid, stderr);
1521 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
1522 0 : fprintf(stderr, "malloc failure\n");
1523 0 : bailout2:
1524 0 : if (view)
1525 0 : free(view);
1526 0 : if (remark)
1527 0 : free(remark);
1528 0 : if (query != NULL)
1529 0 : free(query);
1530 0 : if (s != NULL)
1531 0 : free(s);
1532 0 : if (t != NULL)
1533 0 : free(t);
1534 : return 1;
1535 : }
1536 :
1537 : int
1538 0 : describe_sequence(Mapi mid, const char *schema, const char *tname, stream *sqlf)
1539 : {
1540 0 : MapiHdl hdl = NULL;
1541 0 : char *query = NULL;
1542 0 : size_t maxquerylen;
1543 0 : char *sname = NULL;
1544 :
1545 0 : if (schema == NULL) {
1546 0 : if ((sname = strchr(tname, '.')) != NULL) {
1547 0 : size_t len = sname - tname + 1;
1548 :
1549 0 : sname = malloc(len);
1550 0 : if (sname == NULL)
1551 0 : goto bailout;
1552 0 : strcpy_len(sname, tname, len);
1553 0 : tname += len;
1554 0 : } else if ((sname = get_schema(mid)) == NULL) {
1555 : return 1;
1556 : }
1557 : schema = sname;
1558 : }
1559 :
1560 0 : maxquerylen = 5120 + strlen(tname) + strlen(schema);
1561 :
1562 0 : query = malloc(maxquerylen);
1563 0 : if (query == NULL)
1564 0 : goto bailout;
1565 :
1566 0 : snprintf(query, maxquerylen,
1567 : "SELECT c.remark, q.* "
1568 : "FROM sys.sequences seq LEFT OUTER JOIN sys.comments c ON seq.id = c.id, "
1569 : "sys.schemas s, "
1570 : "sys.describe_sequences q "
1571 : "WHERE s.id = seq.schema_id "
1572 : "AND s.name = '%s' " /* schema name */
1573 : "AND seq.name = '%s' " /* sequence name */
1574 : "AND q.sch = '%s' " /* schema name */
1575 : "AND q.seq = '%s' " /* sequence name */
1576 : "ORDER BY q.sch, q.seq",
1577 : schema, tname,
1578 : schema, tname);
1579 :
1580 0 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1581 0 : goto bailout;
1582 :
1583 0 : while (mapi_fetch_row(hdl) != 0) {
1584 0 : const char *remark = mapi_fetch_field(hdl, 0);
1585 0 : const char *schema = mapi_fetch_field(hdl, 1); /* sch */
1586 0 : const char *name = mapi_fetch_field(hdl, 2); /* seq */
1587 0 : const char *restart = mapi_fetch_field(hdl, 4); /* rs */
1588 0 : const char *minvalue;
1589 0 : const char *maxvalue;
1590 0 : const char *increment = mapi_fetch_field(hdl, 7); /* inc */
1591 0 : const char *cacheinc = mapi_fetch_field(hdl, 8); /* cache */
1592 0 : const char *cycle = mapi_fetch_field(hdl, 9); /* cycle */
1593 :
1594 0 : if (mapi_get_field_count(hdl) > 10) {
1595 : /* new version (Jan2022) of sys.describe_sequences */
1596 0 : minvalue = mapi_fetch_field(hdl, 12); /* rmi */
1597 0 : maxvalue = mapi_fetch_field(hdl, 13); /* rma */
1598 : } else {
1599 : /* old version (pre Jan2022) of sys.describe_sequences */
1600 0 : minvalue = mapi_fetch_field(hdl, 5); /* minvalue */
1601 0 : maxvalue = mapi_fetch_field(hdl, 6); /* maxvalue */
1602 0 : if (strcmp(minvalue, "0") == 0)
1603 0 : minvalue = NULL;
1604 0 : if (strcmp(maxvalue, "0") == 0)
1605 0 : maxvalue = NULL;
1606 : }
1607 0 : mnstr_printf(sqlf, "CREATE SEQUENCE ");
1608 0 : dquoted_print(sqlf, schema, ".");
1609 0 : dquoted_print(sqlf, name, NULL);
1610 0 : mnstr_printf(sqlf, " START WITH %s", restart);
1611 0 : if (strcmp(increment, "1") != 0)
1612 0 : mnstr_printf(sqlf, " INCREMENT BY %s", increment);
1613 0 : if (minvalue)
1614 0 : mnstr_printf(sqlf, " MINVALUE %s", minvalue);
1615 0 : if (maxvalue)
1616 0 : mnstr_printf(sqlf, " MAXVALUE %s", maxvalue);
1617 0 : if (strcmp(cacheinc, "1") != 0)
1618 0 : mnstr_printf(sqlf, " CACHE %s", cacheinc);
1619 0 : mnstr_printf(sqlf, " %sCYCLE;\n", strcmp(cycle, "true") == 0 ? "" : "NO ");
1620 0 : comment_on(sqlf, "SEQUENCE", schema, name, NULL, remark);
1621 0 : if (mnstr_errnr(sqlf) != MNSTR_NO__ERROR) {
1622 0 : mapi_close_handle(hdl);
1623 0 : hdl = NULL;
1624 0 : goto bailout;
1625 : }
1626 : }
1627 0 : if (mapi_error(mid))
1628 0 : goto bailout;
1629 0 : if (sname != NULL)
1630 0 : free(sname);
1631 0 : if (query != NULL)
1632 0 : free(query);
1633 0 : mapi_close_handle(hdl);
1634 0 : hdl = NULL;
1635 0 : return 0;
1636 :
1637 0 : bailout:
1638 0 : if (hdl) {
1639 0 : if (mapi_result_error(hdl))
1640 0 : mapi_explain_result(hdl, stderr);
1641 0 : else if (mapi_error(mid))
1642 0 : mapi_explain_query(hdl, stderr);
1643 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
1644 0 : fprintf(stderr, "malloc failure\n");
1645 0 : mapi_close_handle(hdl);
1646 0 : } else if (mapi_error(mid))
1647 0 : mapi_explain(mid, stderr);
1648 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
1649 0 : fprintf(stderr, "malloc failure\n");
1650 0 : if (sname != NULL)
1651 0 : free(sname);
1652 0 : if (query != NULL)
1653 0 : free(query);
1654 : return 1;
1655 : }
1656 :
1657 : int
1658 0 : describe_schema(Mapi mid, const char *sname, stream *sqlf)
1659 : {
1660 0 : MapiHdl hdl = NULL;
1661 0 : char schemas[5120];
1662 :
1663 0 : snprintf(schemas, sizeof(schemas),
1664 : "SELECT s.name, a.name, c.remark "
1665 : "FROM sys.auths a, "
1666 : "sys.schemas s LEFT OUTER JOIN sys.comments c ON s.id = c.id "
1667 : "WHERE s.\"authorization\" = a.id "
1668 : "AND s.name = '%s' "
1669 : "ORDER BY s.name",
1670 : sname);
1671 :
1672 0 : if ((hdl = mapi_query(mid, schemas)) == NULL || mapi_error(mid)) {
1673 0 : if (hdl) {
1674 0 : if (mapi_result_error(hdl))
1675 0 : mapi_explain_result(hdl, stderr);
1676 : else
1677 0 : mapi_explain_query(hdl, stderr);
1678 0 : mapi_close_handle(hdl);
1679 : } else
1680 0 : mapi_explain(mid, stderr);
1681 :
1682 0 : return 1;
1683 : }
1684 :
1685 0 : while (mapi_fetch_row(hdl) != 0) {
1686 0 : const char *sname = mapi_fetch_field(hdl, 0);
1687 0 : const char *aname = mapi_fetch_field(hdl, 1);
1688 0 : const char *remark = mapi_fetch_field(hdl, 2);
1689 :
1690 0 : mnstr_printf(sqlf, "CREATE SCHEMA ");
1691 0 : dquoted_print(sqlf, sname, NULL);
1692 0 : if (strcmp(aname, "sysadmin") != 0) {
1693 0 : mnstr_printf(sqlf, " AUTHORIZATION ");
1694 0 : dquoted_print(sqlf, aname, NULL);
1695 : }
1696 0 : mnstr_printf(sqlf, ";\n");
1697 0 : comment_on(sqlf, "SCHEMA", sname, NULL, NULL, remark);
1698 : }
1699 :
1700 0 : mapi_close_handle(hdl);
1701 0 : return 0;
1702 : }
1703 :
1704 : static int
1705 322 : dump_table_data(Mapi mid, const char *schema, const char *tname,
1706 : stream *sqlf, const char *ddir, const char *ext,
1707 : bool useInserts, bool noescape)
1708 : {
1709 322 : int cnt, i;
1710 322 : int64_t rows;
1711 322 : MapiHdl hdl = NULL;
1712 322 : char *query = NULL;
1713 322 : size_t maxquerylen;
1714 322 : unsigned char *string = NULL;
1715 322 : char *s, *t;
1716 322 : stream *datf = sqlf;
1717 :
1718 322 : maxquerylen = 5120 + 2*strlen(tname) + 2*strlen(schema);
1719 322 : query = malloc(maxquerylen);
1720 322 : if (query == NULL)
1721 0 : goto bailout;
1722 :
1723 322 : s = sescape(schema);
1724 322 : t = sescape(tname);
1725 322 : snprintf(query, maxquerylen,
1726 : "SELECT t.name, t.query, t.type "
1727 : "FROM sys._tables t, sys.schemas s "
1728 : "WHERE s.name = '%s' "
1729 : "AND t.schema_id = s.id "
1730 : "AND t.name = '%s'",
1731 : s, t);
1732 322 : free(s);
1733 322 : free(t);
1734 :
1735 322 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1736 0 : goto bailout;
1737 322 : if (mapi_rows_affected(hdl) != 1) {
1738 0 : if (mapi_rows_affected(hdl) == 0)
1739 0 : fprintf(stderr, "table %s.%s does not exist\n", schema, tname);
1740 : else
1741 0 : fprintf(stderr, "table %s.%s is not unique\n", schema, tname);
1742 0 : goto bailout;
1743 : }
1744 644 : while ((mapi_fetch_row(hdl)) != 0) {
1745 322 : const char *ttype = mapi_fetch_field(hdl, 2);
1746 322 : if (strcmp(ttype, "1") == 0) {
1747 : /* the table is actually a view */
1748 0 : goto doreturn;
1749 : }
1750 322 : if (strcmp(ttype, "3") == 0) {
1751 : /* merge table */
1752 0 : goto doreturn;
1753 : }
1754 322 : if (strcmp(ttype, "4") == 0) {
1755 : /* stream table */
1756 0 : goto doreturn;
1757 : }
1758 322 : if (strcmp(ttype, "5") == 0) {
1759 : /* remote table */
1760 0 : goto doreturn;
1761 : }
1762 322 : if (strcmp(ttype, "6") == 0) {
1763 : /* replica table */
1764 0 : goto doreturn;
1765 : }
1766 322 : if (strcmp(ttype, "7") == 0) {
1767 : /* unlogged table */
1768 0 : goto doreturn;
1769 : }
1770 : }
1771 322 : if (mapi_error(mid))
1772 0 : goto bailout;
1773 322 : mapi_close_handle(hdl);
1774 322 : hdl = NULL;
1775 :
1776 322 : s = descape(schema);
1777 322 : t = descape(tname);
1778 322 : snprintf(query, maxquerylen, "SELECT * FROM \"%s\".\"%s\"", s, t);
1779 322 : free(s);
1780 322 : free(t);
1781 322 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1782 0 : goto bailout;
1783 :
1784 322 : rows = mapi_get_row_count(hdl);
1785 322 : if (rows == 0) {
1786 : /* nothing more to do */
1787 97 : goto doreturn;
1788 : }
1789 :
1790 225 : cnt = mapi_get_field_count(hdl);
1791 225 : if (cnt < 1 || cnt >= 1 << 29)
1792 0 : goto bailout; /* ridiculous number of columns */
1793 225 : if (!useInserts) {
1794 221 : mnstr_printf(sqlf, "COPY %" PRId64 " RECORDS INTO ", rows);
1795 221 : dquoted_print(sqlf, schema, ".");
1796 221 : dquoted_print(sqlf, tname, NULL);
1797 221 : if (ddir) {
1798 19 : size_t fnl = strlen(ddir) + strlen(schema) + strlen(tname) + (ext ? strlen(ext) + 1 : 0) + 7;
1799 19 : char *fn = malloc(fnl);
1800 19 : if (fn == NULL)
1801 0 : goto bailout;
1802 19 : int off;
1803 19 : off = snprintf(fn, fnl, "%s%c", ddir, DIR_SEP);
1804 19 : if (ext)
1805 0 : snprintf(fn + off, fnl - off, "%s.%s.csv.%s", schema, tname, ext);
1806 : else
1807 19 : snprintf(fn + off, fnl - off, "%s.%s.csv", schema, tname);
1808 19 : mnstr_printf(sqlf, " FROM E");
1809 19 : squoted_print(sqlf, fn + off, '\'', false);
1810 19 : mnstr_printf(sqlf, " ON CLIENT");
1811 19 : datf = open_wastream(fn);
1812 19 : free(fn);
1813 19 : if (datf == NULL) {
1814 0 : goto bailout;
1815 : }
1816 : } else {
1817 202 : mnstr_printf(sqlf, " FROM stdin");
1818 : }
1819 442 : mnstr_printf(sqlf, " USING DELIMITERS E'\\t',E'\\n','\"'%s;\n",
1820 : noescape ? " NO ESCAPE" : "");
1821 : }
1822 225 : string = malloc(sizeof(unsigned char) * cnt);
1823 225 : if (string == NULL)
1824 0 : goto bailout;
1825 1477 : for (i = 0; i < cnt; i++) {
1826 1252 : const char *tp = mapi_get_type(hdl, i);
1827 1252 : string[i] = (strcmp(tp, "char") == 0 ||
1828 1183 : strcmp(tp, "varchar") == 0 ||
1829 1015 : strcmp(tp, "clob") == 0 ||
1830 1015 : strcmp(tp, "timestamp") == 0 ||
1831 985 : strcmp(tp, "timestamptz") == 0 ||
1832 955 : strcmp(tp, "json") == 0 ||
1833 2194 : strcmp(tp, "url") == 0 ||
1834 938 : strcmp(tp, "xml") == 0);
1835 : }
1836 1314730 : while (mapi_fetch_row(hdl)) {
1837 1314505 : const char *s;
1838 :
1839 1314505 : if (useInserts) {
1840 10 : mnstr_printf(datf, "INSERT INTO ");
1841 10 : dquoted_print(datf, schema, ".");
1842 10 : dquoted_print(datf, tname, " VALUES (");
1843 : }
1844 :
1845 5258855 : for (i = 0; i < cnt; i++) {
1846 3944350 : const char *tp = mapi_get_type(hdl, i);
1847 3944350 : s = mapi_fetch_field(hdl, i);
1848 3944350 : if (s == NULL)
1849 796 : mnstr_printf(datf, "NULL");
1850 3943554 : else if (useInserts) {
1851 77 : if (strcmp(tp, "day_interval") == 0 || strcmp(tp, "sec_interval") == 0) {
1852 10 : const char *p = strchr(s, '.');
1853 10 : if (p == NULL)
1854 0 : p = s + strlen(s);
1855 10 : mnstr_printf(datf, "INTERVAL '%.*s' SECOND", (int) (p - s), s);
1856 57 : } else if (strcmp(tp, "month_interval") == 0)
1857 3 : mnstr_printf(datf, "INTERVAL '%s' MONTH", s);
1858 54 : else if (strcmp(tp, "timestamptz") == 0)
1859 2 : mnstr_printf(datf, "TIMESTAMP WITH TIME ZONE '%s'", s);
1860 52 : else if (strcmp(tp, "timestamp") == 0)
1861 2 : mnstr_printf(datf, "TIMESTAMP '%s'", s);
1862 50 : else if (strcmp(tp, "timetz") == 0)
1863 2 : mnstr_printf(datf, "TIME WITH TIME ZONE '%s'", s);
1864 48 : else if (strcmp(tp, "time") == 0)
1865 2 : mnstr_printf(datf, "TIME '%s'", s);
1866 46 : else if (strcmp(tp, "date") == 0)
1867 1 : mnstr_printf(datf, "DATE '%s'", s);
1868 45 : else if (strcmp(tp, "blob") == 0)
1869 2 : mnstr_printf(datf, "BINARY LARGE OBJECT '%s'", s);
1870 43 : else if (strcmp(tp, "inet") == 0 ||
1871 41 : strcmp(tp, "json") == 0 ||
1872 39 : strcmp(tp, "url") == 0 ||
1873 37 : strcmp(tp, "uuid") == 0 ||
1874 36 : string[i])
1875 12 : squoted_print(datf, s, '\'', false);
1876 : else
1877 31 : mnstr_printf(datf, "%s", s);
1878 3943487 : } else if (string[i]) {
1879 : /* write double-quoted string with
1880 : certain characters escaped */
1881 3941962 : squoted_print(datf, s, '"', noescape);
1882 1525 : } else if (strcmp(tp, "blob") == 0) {
1883 : /* inside blobs, special characters
1884 : don't occur */
1885 72 : mnstr_printf(datf, "\"%s\"", s);
1886 : } else
1887 1453 : mnstr_printf(datf, "%s", s);
1888 :
1889 3944350 : if (useInserts) {
1890 67 : if (i < cnt - 1)
1891 57 : mnstr_printf(datf, ", ");
1892 : else
1893 10 : mnstr_printf(datf, ");\n");
1894 : } else {
1895 3944283 : if (i < cnt - 1)
1896 2629788 : mnstr_write(datf, "\t", 1, 1);
1897 : else
1898 1314495 : mnstr_write(datf, "\n", 1, 1);
1899 : }
1900 : }
1901 1314505 : if (mnstr_errnr(datf) != MNSTR_NO__ERROR)
1902 0 : goto bailout;
1903 : }
1904 225 : if (mapi_error(mid))
1905 0 : goto bailout;
1906 225 : free(string);
1907 :
1908 322 : doreturn:
1909 322 : if (datf != sqlf)
1910 19 : close_stream(datf);
1911 322 : if (hdl)
1912 322 : mapi_close_handle(hdl);
1913 322 : if (query != NULL)
1914 322 : free(query);
1915 322 : return 0;
1916 :
1917 0 : bailout:
1918 0 : if (datf != NULL && datf != sqlf)
1919 0 : close_stream(datf);
1920 0 : if (hdl) {
1921 0 : if (mapi_result_error(hdl))
1922 0 : mapi_explain_result(hdl, stderr);
1923 0 : else if (mapi_error(mid))
1924 0 : mapi_explain_query(hdl, stderr);
1925 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
1926 0 : fprintf(stderr, "malloc failure\n");
1927 0 : mapi_close_handle(hdl);
1928 0 : } else if (mapi_error(mid))
1929 0 : mapi_explain(mid, stderr);
1930 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
1931 0 : fprintf(stderr, "malloc failure\n");
1932 0 : if (query != NULL)
1933 0 : free(query);
1934 0 : if (string != NULL)
1935 0 : free(string);
1936 : return 1;
1937 : }
1938 :
1939 : static int
1940 401 : dump_table_storage(Mapi mid, const char *schema, const char *tname, stream *sqlf)
1941 : {
1942 401 : char *query = NULL;
1943 401 : size_t maxquerylen;
1944 401 : MapiHdl hdl = NULL;
1945 401 : char *s = NULL;
1946 401 : char *t = NULL;
1947 401 : int rc = 1;
1948 :
1949 401 : maxquerylen = 5120 + 2*strlen(tname) + 2*strlen(schema);
1950 401 : query = malloc(maxquerylen);
1951 401 : s = sescape(schema);
1952 401 : t = sescape(tname);
1953 401 : if (query == NULL || s == NULL || t == NULL)
1954 0 : goto bailout;
1955 :
1956 401 : snprintf(query, maxquerylen,
1957 : "SELECT name, storage FROM sys._columns "
1958 : "WHERE storage IS NOT NULL "
1959 : "AND table_id = (SELECT id FROM sys._tables WHERE name = '%s' "
1960 : "AND schema_id = (SELECT id FROM sys.schemas WHERE name = '%s'))",
1961 : t, s);
1962 401 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
1963 0 : goto bailout;
1964 401 : while ((mapi_fetch_row(hdl)) != 0) {
1965 0 : const char *cname = mapi_fetch_field(hdl, 0);
1966 0 : const char *storage = mapi_fetch_field(hdl, 1);
1967 0 : char *stg = sescape(storage);
1968 0 : if (stg == NULL)
1969 0 : goto bailout;
1970 0 : mnstr_printf(sqlf, "ALTER TABLE ");
1971 0 : dquoted_print(sqlf, schema, ".");
1972 0 : dquoted_print(sqlf, tname, " ");
1973 0 : mnstr_printf(sqlf, "ALTER COLUMN ");
1974 0 : dquoted_print(sqlf, cname, " ");
1975 0 : mnstr_printf(sqlf, "SET STORAGE '%s';\n", stg);
1976 0 : free(stg);
1977 : }
1978 : rc = 0; /* success */
1979 401 : bailout:
1980 401 : free(query);
1981 401 : free(s);
1982 401 : free(t);
1983 401 : mapi_close_handle(hdl); /* may be NULL */
1984 401 : return rc;
1985 : }
1986 :
1987 : static int
1988 401 : dump_table_access(Mapi mid, const char *schema, const char *tname, stream *sqlf)
1989 : {
1990 401 : char *query = NULL;
1991 401 : size_t maxquerylen;
1992 401 : MapiHdl hdl = NULL;
1993 401 : char *s = NULL;
1994 401 : char *t = NULL;
1995 401 : int rc = 1;
1996 :
1997 401 : maxquerylen = 5120 + 2*strlen(tname) + 2*strlen(schema);
1998 401 : query = malloc(maxquerylen);
1999 401 : s = sescape(schema);
2000 401 : t = sescape(tname);
2001 401 : if (query == NULL || s == NULL || t == NULL)
2002 0 : goto bailout;
2003 :
2004 401 : snprintf(query, maxquerylen,
2005 : "SELECT t.access FROM sys._tables t, sys.schemas s "
2006 : "WHERE s.name = '%s' AND t.schema_id = s.id AND t.name = '%s'",
2007 : s, t);
2008 401 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
2009 0 : goto bailout;
2010 401 : if (mapi_rows_affected(hdl) != 1) {
2011 0 : if (mapi_rows_affected(hdl) == 0)
2012 0 : fprintf(stderr, "table %s.%s does not exist\n", schema, tname);
2013 : else
2014 0 : fprintf(stderr, "table %s.%s is not unique\n", schema, tname);
2015 0 : goto bailout;
2016 : }
2017 802 : while ((mapi_fetch_row(hdl)) != 0) {
2018 401 : const char *access = mapi_fetch_field(hdl, 0);
2019 401 : if (access && (*access == '1' || *access == '2')) {
2020 0 : mnstr_printf(sqlf, "ALTER TABLE ");
2021 0 : dquoted_print(sqlf, schema, ".");
2022 0 : dquoted_print(sqlf, tname, " ");
2023 0 : mnstr_printf(sqlf, "SET %s ONLY;\n", *access == '1' ? "READ" : "INSERT");
2024 : }
2025 : }
2026 : rc = 0; /* success */
2027 401 : bailout:
2028 401 : free(query);
2029 401 : free(s);
2030 401 : free(t);
2031 401 : mapi_close_handle(hdl); /* may be NULL */
2032 401 : return rc;
2033 : }
2034 :
2035 : static int
2036 31 : dump_table_defaults(Mapi mid, const char *schema, const char *tname, stream *sqlf)
2037 : {
2038 31 : char *query = NULL;
2039 31 : size_t maxquerylen;
2040 31 : MapiHdl hdl = NULL;
2041 31 : char *s = NULL;
2042 31 : char *t = NULL;
2043 31 : int rc = 1;
2044 :
2045 31 : maxquerylen = 512;
2046 31 : if (schema != NULL && tname != NULL) {
2047 0 : maxquerylen += 2*strlen(tname) + 2*strlen(schema);
2048 0 : s = sescape(schema);
2049 0 : t = sescape(tname);
2050 0 : if (s == NULL || t == NULL)
2051 0 : goto bailout;
2052 : }
2053 31 : query = malloc(maxquerylen);
2054 31 : if (query == NULL)
2055 0 : goto bailout;
2056 :
2057 31 : if (schema == NULL && tname == NULL)
2058 31 : snprintf(query, maxquerylen,
2059 : "SELECT s.name, t.name, c.name, c.\"default\" "
2060 : "FROM sys._columns c, sys._tables t, sys.schemas s "
2061 : "WHERE c.\"default\" IS NOT NULL "
2062 : "AND c.table_id = t.id "
2063 : "AND t.schema_id = s.id "
2064 : "AND NOT t.system");
2065 : else
2066 0 : snprintf(query, maxquerylen,
2067 : "SELECT s.name, t.name, c.name, c.\"default\" "
2068 : "FROM sys._columns c, sys._tables t, sys.schemas s "
2069 : "WHERE c.\"default\" IS NOT NULL "
2070 : "AND c.table_id = t.id "
2071 : "AND t.schema_id = s.id "
2072 : "AND t.name = '%s' AND s.name = '%s'",
2073 : t, s);
2074 31 : if ((hdl = mapi_query(mid, query)) == NULL || mapi_error(mid))
2075 0 : goto bailout;
2076 68 : while ((mapi_fetch_row(hdl)) != 0) {
2077 37 : const char *sch = mapi_fetch_field(hdl, 0);
2078 37 : const char *tab = mapi_fetch_field(hdl, 1);
2079 37 : const char *col = mapi_fetch_field(hdl, 2);
2080 37 : const char *def = mapi_fetch_field(hdl, 3);
2081 37 : mnstr_printf(sqlf, "ALTER TABLE ");
2082 37 : dquoted_print(sqlf, sch, ".");
2083 37 : dquoted_print(sqlf, tab, " ");
2084 37 : mnstr_printf(sqlf, "ALTER COLUMN ");
2085 37 : dquoted_print(sqlf, col, " ");
2086 37 : mnstr_printf(sqlf, "SET DEFAULT %s;\n", def);
2087 : }
2088 : rc = 0; /* success */
2089 31 : bailout:
2090 31 : free(query);
2091 31 : free(s);
2092 31 : free(t);
2093 31 : mapi_close_handle(hdl); /* may be NULL */
2094 31 : return rc;
2095 : }
2096 :
2097 : int
2098 401 : dump_table(Mapi mid, const char *schema, const char *tname, stream *sqlf,
2099 : const char *ddir, const char *ext,
2100 : bool describe, bool foreign, bool useInserts, bool databaseDump,
2101 : bool noescape, bool percent)
2102 : {
2103 401 : char *sname = NULL;
2104 401 : int rc = 1;
2105 :
2106 401 : if (schema == NULL) {
2107 0 : if ((sname = strchr(tname, '.')) != NULL) {
2108 0 : size_t len = sname - tname + 1;
2109 :
2110 0 : sname = malloc(len);
2111 0 : if (sname == NULL) {
2112 0 : fprintf(stderr, "malloc failure\n");
2113 0 : return 1;
2114 : }
2115 0 : strcpy_len(sname, tname, len);
2116 0 : tname += len;
2117 0 : } else if ((sname = get_schema(mid)) == NULL) {
2118 : return 1;
2119 : }
2120 0 : schema = sname;
2121 :
2122 0 : if (percent && (strchr(schema, '%') != NULL || strchr(tname, '%') != NULL)) {
2123 0 : char *s = sescape(schema);
2124 0 : char *t = sescape(tname);
2125 0 : if (s == NULL || t == NULL) {
2126 0 : free(s);
2127 0 : free(t);
2128 0 : fprintf(stderr, "malloc failure\n");
2129 0 : goto doreturn;
2130 : }
2131 0 : size_t qlen = strlen(s) + strlen(t) + 256;
2132 0 : char *query = malloc(qlen);
2133 0 : if (query == NULL) {
2134 0 : free(s);
2135 0 : free(t);
2136 0 : fprintf(stderr, "malloc failure\n");
2137 0 : goto doreturn;
2138 : }
2139 0 : snprintf(query, qlen, "SELECT s.name, t.name FROM sys._tables t, sys.schemas s WHERE t.schema_id = s.id AND s.name LIKE '%s' AND t.name LIKE '%s' ORDER BY t.id", s, t);
2140 0 : free(s);
2141 0 : free(t);
2142 0 : MapiHdl hdl = mapi_query(mid, query);
2143 0 : free(query);
2144 0 : if (hdl == NULL) {
2145 0 : if (mapi_error(mid))
2146 0 : mapi_explain(mid, stderr);
2147 : else
2148 0 : fprintf(stderr, "malloc failure\n");
2149 0 : goto doreturn;
2150 : }
2151 0 : if (mapi_error(mid)) {
2152 0 : if (mapi_result_error(hdl))
2153 0 : mapi_explain_result(hdl, stderr);
2154 0 : else if (mapi_error(mid))
2155 0 : mapi_explain_query(hdl, stderr);
2156 : else
2157 0 : fprintf(stderr, "malloc failure\n");
2158 0 : mapi_close_handle(hdl);
2159 0 : goto doreturn;
2160 : }
2161 0 : struct tables {
2162 : char *schema;
2163 : char *table;
2164 : } *tables;
2165 0 : int64_t rows = mapi_get_row_count(hdl);
2166 0 : if (rows == 0) {
2167 0 : mapi_close_handle(hdl);
2168 0 : fprintf(stderr, "no tables matching %s.%s\n", schema, tname);
2169 0 : goto doreturn;
2170 : }
2171 0 : tables = malloc((size_t) rows * sizeof(struct tables));
2172 0 : if (tables == NULL) {
2173 0 : mapi_close_handle(hdl);
2174 0 : fprintf(stderr, "malloc failure\n");
2175 0 : goto doreturn;
2176 : }
2177 0 : for (int64_t i = 0; i < rows; i++) {
2178 0 : tables[i].schema = tables[i].table = NULL;
2179 0 : if (mapi_fetch_row(hdl) == 0 ||
2180 0 : (tables[i].schema = strdup(mapi_fetch_field(hdl, 0))) == NULL ||
2181 0 : (tables[i].table = strdup(mapi_fetch_field(hdl, 1))) == NULL) {
2182 0 : do {
2183 0 : free(tables[i].schema);
2184 0 : free(tables[i].table);
2185 0 : } while (i-- > 0);
2186 0 : free(tables);
2187 0 : mapi_close_handle(hdl);
2188 0 : fprintf(stderr, "malloc failure\n");
2189 0 : goto doreturn;
2190 : }
2191 : }
2192 0 : mapi_close_handle(hdl);
2193 0 : for (int64_t i = 0; i < rows; i++) {
2194 0 : rc = dump_table(mid, tables[i].schema, tables[i].table, sqlf,
2195 : ddir, ext,
2196 : describe, foreign, useInserts, databaseDump,
2197 : noescape, false);
2198 0 : if (rc != 0)
2199 : break;
2200 : }
2201 0 : for (int64_t i = 0; i < rows; i++) {
2202 0 : free(tables[i].schema);
2203 0 : free(tables[i].table);
2204 : }
2205 0 : free(tables);
2206 0 : goto doreturn;
2207 : }
2208 : }
2209 :
2210 401 : rc = describe_table(mid, schema, tname, sqlf, foreign, databaseDump);
2211 401 : if (rc == 0)
2212 401 : rc = dump_table_storage(mid, schema, tname, sqlf);
2213 401 : if (rc == 0 && !describe)
2214 322 : rc = dump_table_data(mid, schema, tname, sqlf, ddir, ext, useInserts, noescape);
2215 401 : if (rc == 0)
2216 401 : rc = dump_table_access(mid, schema, tname, sqlf);
2217 401 : if (rc == 0 && !databaseDump)
2218 0 : rc = dump_table_defaults(mid, schema, tname, sqlf);
2219 401 : doreturn:
2220 401 : free(sname); /* may be NULL, but that's OK */
2221 401 : return rc;
2222 : }
2223 :
2224 : static int
2225 93 : dump_function(Mapi mid, stream *sqlf, const char *fid, bool hashge)
2226 : {
2227 93 : MapiHdl hdl = NULL;
2228 93 : size_t query_size = 5120 + strlen(fid);
2229 93 : int query_len;
2230 93 : char *query;
2231 93 : const char *sep;
2232 93 : char *ffunc = NULL, *flkey = NULL, *remark = NULL;
2233 93 : char *sname, *fname, *ftkey;
2234 93 : int flang, ftype;
2235 :
2236 93 : query = malloc(query_size);
2237 93 : if (query == NULL)
2238 0 : goto bailout;
2239 :
2240 93 : query_len = snprintf(query, query_size,
2241 : "SELECT f.id, "
2242 : "f.func, "
2243 : "f.language, "
2244 : "f.type, "
2245 : "s.name, "
2246 : "f.name, "
2247 : "ft.function_type_keyword, "
2248 : "fl.language_keyword, "
2249 : "c.remark "
2250 : "FROM sys.functions f "
2251 : "JOIN sys.schemas s ON f.schema_id = s.id "
2252 : "JOIN sys.function_types ft ON f.type = ft.function_type_id "
2253 : "LEFT OUTER JOIN sys.function_languages fl ON f.language = fl.language_id "
2254 : "LEFT OUTER JOIN sys.comments c ON f.id = c.id "
2255 : "WHERE f.id = %s",
2256 : fid);
2257 93 : assert(query_len < (int) query_size);
2258 93 : if (query_len < 0 || query_len >= (int) query_size ||
2259 93 : (hdl = mapi_query(mid, query)) == NULL || mapi_error(mid)) {
2260 0 : free(query);
2261 0 : goto bailout;
2262 : }
2263 :
2264 93 : if (mapi_fetch_row(hdl) == 0) {
2265 0 : free(query);
2266 0 : mapi_close_handle(hdl);
2267 0 : return 0; /* no such function, apparently */
2268 : }
2269 93 : ffunc = mapi_fetch_field(hdl, 1);
2270 93 : flang = atoi(mapi_fetch_field(hdl, 2));
2271 93 : ftype = atoi(mapi_fetch_field(hdl, 3));
2272 93 : sname = mapi_fetch_field(hdl, 4);
2273 93 : fname = mapi_fetch_field(hdl, 5);
2274 93 : ftkey = mapi_fetch_field(hdl, 6);
2275 93 : flkey = mapi_fetch_field(hdl, 7);
2276 93 : remark = mapi_fetch_field(hdl, 8);
2277 93 : if (remark) {
2278 9 : remark = strdup(remark);
2279 9 : sname = strdup(sname);
2280 9 : fname = strdup(fname);
2281 9 : ftkey = strdup(ftkey);
2282 :
2283 9 : if (remark == NULL || sname == NULL || fname == NULL || ftkey == NULL) {
2284 0 : if (remark)
2285 0 : free(remark);
2286 0 : if (sname)
2287 0 : free(sname);
2288 0 : if (fname)
2289 0 : free(fname);
2290 0 : if (ftkey)
2291 0 : free(ftkey);
2292 0 : if (query)
2293 0 : free(query);
2294 0 : goto bailout;
2295 : }
2296 : }
2297 93 : if (flang == 1 || flang == 2) {
2298 : /* all information is stored in the func column
2299 : * first skip initial comments and empty lines */
2300 30 : while ((ffunc[0] == '-' && ffunc[1] == '-') || ffunc[0] == '\n') {
2301 0 : ffunc = strchr(ffunc, '\n');
2302 0 : if (ffunc == NULL)
2303 : ffunc = "";
2304 : else
2305 0 : ffunc++;
2306 : }
2307 30 : mnstr_printf(sqlf, "%s\n", ffunc);
2308 30 : if (remark == NULL) {
2309 21 : mapi_close_handle(hdl);
2310 21 : free(query);
2311 21 : return 0;
2312 : }
2313 : } else {
2314 63 : mnstr_printf(sqlf, "CREATE %s ", ftkey);
2315 63 : dquoted_print(sqlf, sname, ".");
2316 63 : dquoted_print(sqlf, fname, "(");
2317 : }
2318 : /* strdup these two because they are needed after another query */
2319 72 : if (flkey) {
2320 63 : if ((flkey = strdup(flkey)) == NULL) {
2321 0 : if (remark) {
2322 0 : free(remark);
2323 0 : free(sname);
2324 0 : free(fname);
2325 0 : free(ftkey);
2326 : }
2327 0 : goto bailout;
2328 : }
2329 : }
2330 72 : ffunc = strdup(ffunc);
2331 72 : query_len = snprintf(query, query_size,
2332 : "SELECT a.name, a.type, a.type_digits, "
2333 : "a.type_scale, a.inout "
2334 : "FROM sys.args a, sys.functions f "
2335 : "WHERE a.func_id = f.id AND f.id = %s "
2336 : "ORDER BY a.inout DESC, a.number", fid);
2337 72 : assert(query_len < (int) query_size);
2338 72 : if (!ffunc || query_len < 0 || query_len >= (int) query_size) {
2339 0 : free(ffunc);
2340 0 : free(flkey);
2341 0 : if (remark) {
2342 0 : free(remark);
2343 0 : free(sname);
2344 0 : free(fname);
2345 0 : free(ftkey);
2346 : }
2347 0 : free(query);
2348 0 : goto bailout;
2349 : }
2350 72 : mapi_close_handle(hdl);
2351 72 : hdl = mapi_query(mid, query);
2352 72 : free(query);
2353 72 : if (hdl == NULL || mapi_error(mid)) {
2354 0 : free(ffunc);
2355 0 : free(flkey);
2356 0 : if (remark) {
2357 0 : free(remark);
2358 0 : free(sname);
2359 0 : free(fname);
2360 0 : free(ftkey);
2361 : }
2362 0 : goto bailout;
2363 : }
2364 72 : if (flang != 1 && flang != 2) {
2365 : sep = "";
2366 171 : while (mapi_fetch_row(hdl) != 0) {
2367 171 : const char *aname = mapi_fetch_field(hdl, 0);
2368 171 : char *atype = mapi_fetch_field(hdl, 1);
2369 171 : char *adigs = mapi_fetch_field(hdl, 2);
2370 171 : char *ascal = mapi_fetch_field(hdl, 3);
2371 171 : const char *ainou = mapi_fetch_field(hdl, 4);
2372 :
2373 171 : if (strcmp(ainou, "0") == 0) {
2374 : /* end of arguments */
2375 : break;
2376 : }
2377 :
2378 108 : atype = strdup(atype);
2379 108 : adigs = strdup(adigs);
2380 108 : ascal = strdup(ascal);
2381 108 : if (atype == NULL || adigs == NULL || ascal == NULL) {
2382 0 : free(atype);
2383 0 : free(adigs);
2384 0 : free(ascal);
2385 0 : free(ffunc);
2386 0 : free(flkey);
2387 0 : if (remark) {
2388 0 : free(remark);
2389 0 : free(sname);
2390 0 : free(fname);
2391 0 : free(ftkey);
2392 : }
2393 0 : goto bailout;
2394 : }
2395 :
2396 108 : mnstr_printf(sqlf, "%s", sep);
2397 108 : dquoted_print(sqlf, aname, " ");
2398 108 : dump_type(mid, sqlf, atype, adigs, ascal, hashge);
2399 108 : sep = ", ";
2400 :
2401 108 : free(atype);
2402 108 : free(adigs);
2403 108 : free(ascal);
2404 : }
2405 63 : mnstr_printf(sqlf, ")");
2406 63 : if (ftype == 1 || ftype == 3 || ftype == 5) {
2407 63 : sep = "TABLE (";
2408 63 : mnstr_printf(sqlf, " RETURNS ");
2409 81 : do {
2410 81 : const char *aname = mapi_fetch_field(hdl, 0);
2411 81 : char *atype = strdup(mapi_fetch_field(hdl, 1));
2412 81 : char *adigs = strdup(mapi_fetch_field(hdl, 2));
2413 81 : char *ascal = strdup(mapi_fetch_field(hdl, 3));
2414 :
2415 81 : if (atype == NULL || adigs == NULL || ascal == NULL) {
2416 0 : free(atype);
2417 0 : free(adigs);
2418 0 : free(ascal);
2419 0 : free(ffunc);
2420 0 : free(flkey);
2421 0 : if (remark) {
2422 0 : free(remark);
2423 0 : free(sname);
2424 0 : free(fname);
2425 0 : free(ftkey);
2426 : }
2427 0 : goto bailout;
2428 : }
2429 :
2430 81 : assert(strcmp(mapi_fetch_field(hdl, 4), "0") == 0);
2431 81 : if (ftype == 5) {
2432 36 : mnstr_printf(sqlf, "%s", sep);
2433 36 : dquoted_print(sqlf, aname, " ");
2434 36 : sep = ", ";
2435 : }
2436 81 : dump_type(mid, sqlf, atype, adigs, ascal, hashge);
2437 :
2438 81 : free(atype);
2439 81 : free(adigs);
2440 81 : free(ascal);
2441 81 : } while (mapi_fetch_row(hdl) != 0);
2442 63 : if (ftype == 5)
2443 18 : mnstr_printf(sqlf, ")");
2444 : }
2445 63 : if (flkey) {
2446 63 : mnstr_printf(sqlf, " LANGUAGE %s", flkey);
2447 63 : free(flkey);
2448 : }
2449 63 : mnstr_printf(sqlf, "\n%s\n", ffunc);
2450 : }
2451 72 : free(ffunc);
2452 72 : if (remark) {
2453 18 : if (mapi_seek_row(hdl, 0, MAPI_SEEK_SET) != MOK ||
2454 18 : mnstr_printf(sqlf, "COMMENT ON %s ", ftkey) < 0 ||
2455 18 : dquoted_print(sqlf, sname, ".") < 0 ||
2456 9 : dquoted_print(sqlf, fname, "(") < 0) {
2457 0 : free(sname);
2458 0 : free(fname);
2459 0 : free(ftkey);
2460 0 : free(remark);
2461 0 : goto bailout;
2462 : }
2463 9 : free(sname);
2464 9 : free(fname);
2465 9 : free(ftkey);
2466 9 : sep = "";
2467 9 : while (mapi_fetch_row(hdl) != 0) {
2468 9 : char *atype = strdup(mapi_fetch_field(hdl, 1));
2469 9 : char *adigs = strdup(mapi_fetch_field(hdl, 2));
2470 9 : char *ascal = strdup(mapi_fetch_field(hdl, 3));
2471 9 : const char *ainou = mapi_fetch_field(hdl, 4);
2472 :
2473 9 : if (!atype || !adigs || !ascal) {
2474 0 : free(atype);
2475 0 : free(adigs);
2476 0 : free(ascal);
2477 0 : free(remark);
2478 0 : goto bailout;
2479 : }
2480 :
2481 9 : if (strcmp(ainou, "0") == 0) {
2482 : /* end of arguments */
2483 9 : free(atype);
2484 9 : free(adigs);
2485 9 : free(ascal);
2486 9 : break;
2487 : }
2488 0 : mnstr_printf(sqlf, "%s", sep);
2489 0 : dump_type(mid, sqlf, atype, adigs, ascal, hashge);
2490 0 : sep = ", ";
2491 :
2492 0 : free(atype);
2493 0 : free(adigs);
2494 0 : free(ascal);
2495 : }
2496 9 : mnstr_printf(sqlf, ") IS ");
2497 9 : squoted_print(sqlf, remark, '\'', false);
2498 9 : mnstr_printf(sqlf, ";\n");
2499 9 : free(remark);
2500 : }
2501 72 : mapi_close_handle(hdl);
2502 72 : return 0;
2503 0 : bailout:
2504 0 : if (hdl) {
2505 0 : if (mapi_result_error(hdl))
2506 0 : mapi_explain_result(hdl, stderr);
2507 0 : else if (mapi_error(mid))
2508 0 : mapi_explain_query(hdl, stderr);
2509 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
2510 0 : fprintf(stderr, "malloc failure\n");
2511 0 : mapi_close_handle(hdl);
2512 0 : } else if (mapi_error(mid))
2513 0 : mapi_explain(mid, stderr);
2514 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
2515 0 : fprintf(stderr, "malloc failure\n");
2516 : return 1;
2517 : }
2518 :
2519 : int
2520 93 : dump_functions(Mapi mid, stream *sqlf, char set_schema, const char *sname, const char *fname, const char *id)
2521 : {
2522 93 : MapiHdl hdl = NULL;
2523 93 : char *query = NULL;
2524 93 : size_t query_size;
2525 93 : int query_len;
2526 93 : bool hashge;
2527 93 : char *to_free = NULL;
2528 93 : bool wantSystem;
2529 93 : long prev_sid;
2530 :
2531 93 : if (fname != NULL) {
2532 : /* dump a single function */
2533 93 : wantSystem = true;
2534 :
2535 93 : if (sname == NULL) {
2536 : /* no schema given, so figure it out */
2537 0 : const char *dot = strchr(fname, '.');
2538 0 : if (dot != NULL) {
2539 0 : size_t len = dot - fname + 1;
2540 :
2541 0 : to_free = malloc(len);
2542 0 : if (to_free == NULL)
2543 0 : goto bailout;
2544 0 : strcpy_len(to_free, fname, len);
2545 0 : fname += len;
2546 0 : } else if ((to_free = get_schema(mid)) == NULL) {
2547 : return 1;
2548 : }
2549 : sname = to_free;
2550 : }
2551 : } else {
2552 : wantSystem = false;
2553 : }
2554 :
2555 93 : hashge = has_hugeint(mid);
2556 :
2557 93 : query_size = 5120 + (sname ? strlen(sname) : 0) + (fname ? strlen(fname) : 0);
2558 93 : query = malloc(query_size);
2559 93 : if (query == NULL)
2560 0 : goto bailout;
2561 :
2562 93 : query_len = snprintf(query, query_size,
2563 : "SELECT s.id, s.name, f.id "
2564 : "FROM sys.schemas s "
2565 : "JOIN sys.functions f ON s.id = f.schema_id "
2566 : "WHERE f.language > 0 ");
2567 93 : if (id) {
2568 93 : query_len += snprintf(query + query_len,
2569 : query_size - query_len,
2570 : "AND f.id = %s ", id);
2571 : } else {
2572 0 : if (sname)
2573 0 : query_len += snprintf(query + query_len,
2574 : query_size - query_len,
2575 : "AND s.name = '%s' ", sname);
2576 0 : if (fname)
2577 0 : query_len += snprintf(query + query_len, query_size - query_len, "AND f.name = '%s' ", fname);
2578 0 : if (!wantSystem) {
2579 0 : query_len += snprintf(query + query_len, query_size - query_len, "AND NOT f.system ");
2580 : }
2581 : }
2582 93 : query_len += snprintf(query + query_len, query_size - query_len, "ORDER BY f.func, f.id");
2583 93 : assert(query_len < (int) query_size);
2584 93 : if (query_len >= (int) query_size) {
2585 : free(query);
2586 : goto bailout;
2587 : }
2588 :
2589 93 : hdl = mapi_query(mid, query);
2590 93 : free(query);
2591 93 : if (hdl == NULL || mapi_error(mid))
2592 0 : goto bailout;
2593 : prev_sid = 0;
2594 186 : while (mnstr_errnr(sqlf) == MNSTR_NO__ERROR && mapi_fetch_row(hdl) != 0) {
2595 93 : long sid = strtol(mapi_fetch_field(hdl, 0), NULL, 10);
2596 93 : const char *schema = mapi_fetch_field(hdl, 1);
2597 93 : char *fid = strdup(mapi_fetch_field(hdl, 2));
2598 :
2599 93 : if (fid) {
2600 93 : if (set_schema && sid != prev_sid) {
2601 0 : mnstr_printf(sqlf, "SET SCHEMA ");
2602 0 : dquoted_print(sqlf, schema, ";\n");
2603 0 : prev_sid = sid;
2604 : }
2605 93 : dump_function(mid, sqlf, fid, hashge);
2606 93 : free(fid);
2607 : } else {
2608 0 : goto bailout;
2609 : }
2610 : }
2611 93 : if (mapi_error(mid))
2612 0 : goto bailout;
2613 93 : mapi_close_handle(hdl);
2614 :
2615 93 : if (to_free)
2616 0 : free(to_free);
2617 93 : return mnstr_errnr(sqlf) != MNSTR_NO__ERROR;
2618 :
2619 0 : bailout:
2620 0 : if (hdl) {
2621 0 : if (mapi_result_error(hdl))
2622 0 : mapi_explain_result(hdl, stderr);
2623 0 : else if (mapi_error(mid))
2624 0 : mapi_explain_query(hdl, stderr);
2625 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
2626 0 : fprintf(stderr, "malloc failure\n");
2627 0 : mapi_close_handle(hdl);
2628 0 : } else if (mapi_error(mid))
2629 0 : mapi_explain(mid, stderr);
2630 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
2631 0 : fprintf(stderr, "malloc failure\n");
2632 0 : if (to_free)
2633 0 : free(to_free);
2634 : return 1;
2635 : }
2636 :
2637 : int
2638 31 : dump_database(Mapi mid, stream *sqlf, const char *ddir, const char *ext, bool describe, bool useInserts, bool noescape)
2639 : {
2640 31 : const char start_trx[] = "START TRANSACTION";
2641 31 : const char end[] = "ROLLBACK";
2642 31 : const char types[] =
2643 : "SELECT s.name, "
2644 : "t.systemname, "
2645 : "t.sqlname "
2646 : "FROM sys.types t LEFT JOIN sys.schemas s ON s.id = t.schema_id "
2647 : "WHERE t.eclass = 18 "
2648 : "AND (t.schema_id <> 2000 "
2649 : "OR (t.schema_id = 2000 "
2650 : "AND t.sqlname NOT IN ('geometrya','mbr','url','inet','json','uuid')))"
2651 : "ORDER BY s.name, t.sqlname";
2652 62 : const char *users =
2653 31 : has_schema_max_memory(mid) ?
2654 : "SELECT ui.name, "
2655 : "ui.fullname, "
2656 : "sys.password_hash(ui.name), "
2657 : "s.name, "
2658 : "ui.schema_path, "
2659 : "ui.max_memory, "
2660 : "ui.max_workers, "
2661 : "ui.optimizer, "
2662 : "au.name "
2663 : "FROM sys.db_user_info ui LEFT OUTER JOIN sys.auths au on ui.default_role = au.id, "
2664 : "sys.schemas s "
2665 : "WHERE ui.default_schema = s.id "
2666 : "AND ui.name <> 'monetdb' "
2667 : "AND ui.name <> '.snapshot' "
2668 31 : "ORDER BY ui.name" :
2669 : "SELECT ui.name, "
2670 : "ui.fullname, "
2671 : "sys.password_hash(ui.name), "
2672 : "s.name, "
2673 : "ui.schema_path, "
2674 : "0, 0, 'default_pipe', cast(null as clob) "
2675 : "FROM sys.db_user_info ui, "
2676 : "sys.schemas s "
2677 : "WHERE ui.default_schema = s.id "
2678 : "AND ui.name <> 'monetdb' "
2679 : "AND ui.name <> '.snapshot' "
2680 : "ORDER BY ui.name";
2681 31 : const char roles[] =
2682 : "SELECT name "
2683 : "FROM sys.auths "
2684 : "WHERE name NOT IN (SELECT name FROM sys.db_user_info) "
2685 : "AND grantor <> 0 "
2686 : "ORDER BY name";
2687 31 : const char grants[] =
2688 : /* all grants granting roles to users excepting the default role */
2689 : "SELECT a1.name, "
2690 : "a2.name "
2691 : "FROM sys.auths a1, "
2692 : "sys.auths a2, "
2693 : "sys.user_role ur, "
2694 : "sys.db_user_info ui "
2695 : "WHERE a1.id = ur.login_id "
2696 : "AND a2.id = ur.role_id "
2697 : "AND a1.name = ui.name "
2698 : "AND a2.id <> ui.default_role "
2699 : "ORDER BY a1.name, a2.name";
2700 31 : const char table_grants[] =
2701 : "SELECT s.name, t.name, "
2702 : "a.name, "
2703 : "sum(p.privileges), "
2704 : "g.name, go.opt "
2705 : "FROM sys.schemas s, sys.tables t, "
2706 : "sys.auths a, sys.privileges p, "
2707 : "sys.auths g, "
2708 : "(VALUES (0, ''), (1, ' WITH GRANT OPTION')) AS go (id, opt) "
2709 : "WHERE p.obj_id = t.id "
2710 : "AND p.auth_id = a.id "
2711 : "AND t.schema_id = s.id "
2712 : "AND t.system = FALSE "
2713 : "AND p.grantor = g.id "
2714 : "AND p.grantable = go.id "
2715 : "GROUP BY s.name, t.name, a.name, g.name, go.opt "
2716 : "ORDER BY s.name, t.name, a.name, g.name, go.opt";
2717 31 : const char column_grants[] =
2718 : "SELECT s.name, t.name, "
2719 : "c.name, a.name, "
2720 : "pc.privilege_code_name, "
2721 : "g.name, go.opt "
2722 : "FROM sys.schemas s, "
2723 : "sys.tables t, "
2724 : "sys.columns c, "
2725 : "sys.auths a, "
2726 : "sys.privileges p, "
2727 : "sys.auths g, "
2728 : "sys.privilege_codes pc, "
2729 : "(VALUES (0, ''), (1, ' WITH GRANT OPTION')) AS go (id, opt) "
2730 : "WHERE p.obj_id = c.id "
2731 : "AND c.table_id = t.id "
2732 : "AND p.auth_id = a.id "
2733 : "AND t.schema_id = s.id "
2734 : "AND t.system = FALSE "
2735 : "AND p.grantor = g.id "
2736 : "AND p.privileges = pc.privilege_code_id "
2737 : "AND p.grantable = go.id "
2738 : "ORDER BY s.name, t.name, c.name, a.name, g.name, p.grantable";
2739 31 : const char function_grants[] =
2740 : "SELECT f.id, "
2741 : "s.name, "
2742 : "f.name, "
2743 : "a.type, "
2744 : "a.type_digits, "
2745 : "a.type_scale, "
2746 : "a.inout, "
2747 : "a.number, "
2748 : "au.name, "
2749 : "pc.privilege_code_name, "
2750 : "go.opt, "
2751 : "ft.function_type_keyword "
2752 : "FROM sys.schemas s, "
2753 : "sys.functions f LEFT OUTER JOIN sys.args a ON f.id = a.func_id, "
2754 : "sys.auths au, "
2755 : "sys.privileges p, "
2756 : "sys.auths g, "
2757 : "sys.function_types ft, "
2758 : "sys.privilege_codes pc, "
2759 : "(VALUES (0, ''), (1, ' WITH GRANT OPTION')) AS go (id, opt) "
2760 : "WHERE NOT f.system "
2761 : "AND s.id = f.schema_id "
2762 : "AND f.id = p.obj_id "
2763 : "AND p.auth_id = au.id "
2764 : "AND p.grantor = g.id "
2765 : "AND p.privileges = pc.privilege_code_id "
2766 : "AND f.type = ft.function_type_id "
2767 : "AND p.grantable = go.id "
2768 : "ORDER BY s.name, "
2769 : "f.name, "
2770 : "au.name, "
2771 : "g.name, "
2772 : "p.grantable, "
2773 : "f.id, "
2774 : "a.inout DESC, "
2775 : "a.number";
2776 31 : const char global_grants[] =
2777 : "SELECT a.name, pc.grnt, g.name, go.opt "
2778 : "FROM sys.privileges p, "
2779 : "sys.auths a, "
2780 : "sys.auths g, "
2781 : "(VALUES (0, 'COPY INTO'), (1, 'COPY FROM')) AS pc (id, grnt), "
2782 : "(VALUES (0, ''), (1, ' WITH GRANT OPTION')) AS go (id, opt) "
2783 : "WHERE p.obj_id = 0 "
2784 : "AND p.auth_id = a.id "
2785 : "AND p.grantor = g.id "
2786 : "AND p.privileges = pc.id "
2787 : "AND p.grantable = go.id "
2788 : "ORDER BY a.name, g.name, go.opt";
2789 31 : const char schemas[] =
2790 : "SELECT s.name, a.name, rem.remark "
2791 : "FROM sys.schemas s LEFT OUTER JOIN sys.comments rem ON s.id = rem.id, "
2792 : "sys.auths a "
2793 : "WHERE s.\"authorization\" = a.id "
2794 : "AND s.system = FALSE "
2795 : "ORDER BY s.name";
2796 31 : const char sequences1[] =
2797 : "SELECT sch.name, seq.name, rem.remark "
2798 : "FROM sys.schemas sch, "
2799 : "sys.sequences seq LEFT OUTER JOIN sys.comments rem ON seq.id = rem.id "
2800 : "WHERE sch.id = seq.schema_id "
2801 : "ORDER BY sch.name, seq.name";
2802 31 : const char sequences2[] =
2803 : "SELECT * FROM sys.describe_sequences ORDER BY sch, seq";
2804 31 : const char tables[] =
2805 : "SELECT t.id AS id, "
2806 : "s.name AS sname, "
2807 : "t.name AS name, "
2808 : "t.type AS type "
2809 : "FROM sys.schemas s, "
2810 : "sys._tables t "
2811 : "WHERE t.type IN (0, 3, 4, 5, 6) "
2812 : "AND t.system = FALSE "
2813 : "AND s.id = t.schema_id "
2814 : "ORDER BY id";
2815 31 : const char mergetables[] =
2816 : "SELECT subq.s1name, "
2817 : "subq.t1name, "
2818 : "subq.s2name, "
2819 : "subq.t2name, "
2820 : "table_partitions.type "
2821 : "FROM (SELECT t1.id, "
2822 : "t1.type, "
2823 : "s1.name AS s1name, "
2824 : "t1.name AS t1name, "
2825 : "s2.name AS s2name, "
2826 : "t2.name AS t2name "
2827 : "FROM sys.schemas s1, "
2828 : "sys._tables t1, "
2829 : "sys.dependencies d, "
2830 : "sys.schemas s2, "
2831 : "sys._tables t2 "
2832 : "WHERE t1.type IN (3, 6) "
2833 : "AND t1.schema_id = s1.id "
2834 : "AND s1.name <> 'tmp' "
2835 : "AND t1.system = FALSE "
2836 : "AND t1.id = d.depend_id "
2837 : "AND d.id = t2.id "
2838 : "AND t2.schema_id = s2.id "
2839 : "ORDER BY t1.id, t2.id) subq "
2840 : "LEFT OUTER JOIN sys.table_partitions "
2841 : "ON subq.id = table_partitions.table_id";
2842 : /* we must dump views, functions/procedures and triggers in order
2843 : * of creation since they can refer to each other */
2844 31 : const char views_functions_triggers[] =
2845 : "with vft (sname, name, id, query, remark) AS ("
2846 : "SELECT s.name AS sname, " /* views */
2847 : "t.name AS name, "
2848 : "t.id AS id, "
2849 : "t.query AS query, "
2850 : "rem.remark AS remark "
2851 : "FROM sys.schemas s, "
2852 : "sys._tables t LEFT OUTER JOIN sys.comments rem ON t.id = rem.id "
2853 : "WHERE t.type = 1 "
2854 : "AND t.system = FALSE "
2855 : "AND s.id = t.schema_id "
2856 : "AND s.name <> 'tmp' "
2857 : "UNION ALL "
2858 : "SELECT s.name AS sname, " /* functions and procedures */
2859 : "f.name AS name, "
2860 : "f.id AS id, "
2861 : "NULL AS query, "
2862 : "NULL AS remark " /* emitted separately */
2863 : "FROM sys.schemas s, "
2864 : "sys.functions f "
2865 : "WHERE s.id = f.schema_id "
2866 : "AND NOT f.system "
2867 : "UNION ALL "
2868 : "SELECT s.name AS sname, " /* triggers */
2869 : "tr.name AS name, "
2870 : "tr.id AS id, "
2871 : "tr.\"statement\" AS query, "
2872 : "NULL AS remark " /* not available yet */
2873 : "FROM sys.triggers tr, "
2874 : "sys.schemas s, "
2875 : "sys._tables t "
2876 : "WHERE s.id = t.schema_id "
2877 : "AND t.id = tr.table_id "
2878 : "AND t.system = FALSE"
2879 : ") "
2880 : "SELECT id, sname, name, query, remark FROM vft ORDER BY id";
2881 31 : char *sname = NULL;
2882 31 : char *curschema = NULL;
2883 31 : MapiHdl hdl = NULL;
2884 31 : int rc = 0;
2885 31 : int lastfid = 0;
2886 31 : const char *sep;
2887 31 : bool hashge = has_hugeint(mid);
2888 :
2889 : /* start a transaction for the dump */
2890 31 : mnstr_printf(sqlf, "%s;\n", start_trx);
2891 :
2892 31 : if ((hdl = mapi_query(mid, start_trx)) == NULL || mapi_error(mid))
2893 0 : goto bailout;
2894 31 : mapi_close_handle(hdl);
2895 31 : hdl = NULL;
2896 :
2897 31 : sname = get_schema(mid);
2898 31 : if (sname == NULL)
2899 0 : goto bailout2;
2900 31 : mnstr_printf(sqlf, "SET SCHEMA ");
2901 31 : dquoted_print(sqlf, sname, ";\n");
2902 31 : curschema = strdup(sname);
2903 31 : if (curschema == NULL)
2904 0 : goto bailout;
2905 31 : if (strcmp(sname, "sys") == 0 || strcmp(sname, "tmp") == 0) {
2906 29 : free(sname);
2907 29 : sname = NULL;
2908 :
2909 : /* dump roles */
2910 29 : if ((hdl = mapi_query(mid, roles)) == NULL || mapi_error(mid))
2911 0 : goto bailout;
2912 :
2913 29 : while (mapi_fetch_row(hdl) != 0) {
2914 0 : const char *name = mapi_fetch_field(hdl, 0);
2915 :
2916 0 : mnstr_printf(sqlf, "CREATE ROLE ");
2917 0 : dquoted_print(sqlf, name, ";\n");
2918 : }
2919 29 : if (mapi_error(mid))
2920 0 : goto bailout;
2921 29 : mapi_close_handle(hdl);
2922 :
2923 : /* dump users, part 1 */
2924 29 : if ((hdl = mapi_query(mid, users)) == NULL || mapi_error(mid))
2925 0 : goto bailout;
2926 :
2927 53 : while (mapi_fetch_row(hdl) != 0) {
2928 24 : const char *uname = mapi_fetch_field(hdl, 0);
2929 24 : const char *fullname = mapi_fetch_field(hdl, 1);
2930 24 : const char *pwhash = mapi_fetch_field(hdl, 2);
2931 24 : const char *sname = mapi_fetch_field(hdl, 3);
2932 24 : const char *spath = mapi_fetch_field(hdl, 4);
2933 24 : const char *mmemory = mapi_fetch_field(hdl, 5);
2934 24 : const char *mworkers = mapi_fetch_field(hdl, 6);
2935 24 : const char *optimizer = mapi_fetch_field(hdl, 7);
2936 24 : const char *defrole = mapi_fetch_field(hdl, 8);
2937 :
2938 24 : mnstr_printf(sqlf, "CREATE USER ");
2939 24 : dquoted_print(sqlf, uname, " ");
2940 24 : mnstr_printf(sqlf, "WITH ENCRYPTED PASSWORD ");
2941 24 : squoted_print(sqlf, pwhash, '\'', false);
2942 24 : mnstr_printf(sqlf, " NAME ");
2943 24 : squoted_print(sqlf, fullname, '\'', false);
2944 24 : mnstr_printf(sqlf, " SCHEMA ");
2945 48 : dquoted_print(sqlf, describe ? sname : "sys", NULL);
2946 24 : if (spath && strcmp(spath, "\"sys\"") != 0) {
2947 0 : mnstr_printf(sqlf, " SCHEMA PATH ");
2948 0 : squoted_print(sqlf, spath, '\'', false);
2949 : }
2950 24 : if (mmemory && strcmp(mmemory, "0") != 0) {
2951 9 : mnstr_printf(sqlf, " MAX_MEMORY %s", mmemory);
2952 : }
2953 24 : if (mworkers && strcmp(mworkers, "0") != 0) {
2954 9 : mnstr_printf(sqlf, " MAX_WORKERS %s", mworkers);
2955 : }
2956 24 : if (optimizer && strcmp(optimizer, "default_pipe") != 0) {
2957 9 : mnstr_printf(sqlf, " OPTIMIZER ");
2958 9 : squoted_print(sqlf, optimizer, '\'', false);
2959 : }
2960 24 : if (defrole && strcmp(defrole, uname) != 0) {
2961 9 : mnstr_printf(sqlf, " DEFAULT ROLE ");
2962 9 : dquoted_print(sqlf, defrole, NULL);
2963 : }
2964 24 : mnstr_printf(sqlf, ";\n");
2965 : }
2966 29 : if (mapi_error(mid))
2967 0 : goto bailout;
2968 29 : mapi_close_handle(hdl);
2969 :
2970 : /* dump schemas */
2971 58 : if ((hdl = mapi_query(mid, schemas)) == NULL ||
2972 29 : mapi_error(mid))
2973 0 : goto bailout;
2974 :
2975 53 : while (mapi_fetch_row(hdl) != 0) {
2976 24 : const char *sname = mapi_fetch_field(hdl, 0);
2977 24 : const char *aname = mapi_fetch_field(hdl, 1);
2978 24 : const char *remark = mapi_fetch_field(hdl, 2);
2979 :
2980 24 : mnstr_printf(sqlf, "CREATE SCHEMA ");
2981 24 : dquoted_print(sqlf, sname, NULL);
2982 24 : if (strcmp(aname, "sysadmin") != 0) {
2983 24 : mnstr_printf(sqlf,
2984 : " AUTHORIZATION ");
2985 24 : dquoted_print(sqlf, aname, NULL);
2986 : }
2987 24 : mnstr_printf(sqlf, ";\n");
2988 24 : comment_on(sqlf, "SCHEMA", sname, NULL, NULL, remark);
2989 : }
2990 29 : if (mapi_error(mid))
2991 0 : goto bailout;
2992 29 : mapi_close_handle(hdl);
2993 :
2994 29 : if (!describe) {
2995 : /* dump users, part 2 */
2996 58 : if ((hdl = mapi_query(mid, users)) == NULL ||
2997 29 : mapi_error(mid))
2998 0 : goto bailout;
2999 :
3000 53 : while (mapi_fetch_row(hdl) != 0) {
3001 24 : char *uname = mapi_fetch_field(hdl, 0);
3002 24 : char *sname = mapi_fetch_field(hdl, 3);
3003 :
3004 24 : if (strcmp(sname, "sys") == 0)
3005 0 : continue;
3006 24 : mnstr_printf(sqlf, "ALTER USER ");
3007 24 : dquoted_print(sqlf, uname, " SET SCHEMA ");
3008 24 : dquoted_print(sqlf, sname, ";\n");
3009 : }
3010 29 : if (mapi_error(mid))
3011 0 : goto bailout;
3012 29 : mapi_close_handle(hdl);
3013 : }
3014 :
3015 : /* grant user privileges */
3016 29 : if ((hdl = mapi_query(mid, grants)) == NULL || mapi_error(mid))
3017 0 : goto bailout;
3018 :
3019 29 : while (mapi_fetch_row(hdl) != 0) {
3020 0 : const char *uname = mapi_fetch_field(hdl, 0);
3021 0 : const char *rname = mapi_fetch_field(hdl, 1);
3022 :
3023 0 : mnstr_printf(sqlf, "GRANT ");
3024 0 : dquoted_print(sqlf, rname, " TO ");
3025 0 : if (strcmp(uname, "public") == 0)
3026 0 : mnstr_printf(sqlf, "PUBLIC");
3027 : else
3028 0 : dquoted_print(sqlf, uname, NULL);
3029 : /* optional WITH ADMIN OPTION and FROM
3030 : (CURRENT_USER|CURRENT_ROLE) are ignored by
3031 : server, so we can't dump them */
3032 0 : mnstr_printf(sqlf, ";\n");
3033 : }
3034 29 : if (mapi_error(mid))
3035 0 : goto bailout;
3036 29 : mapi_close_handle(hdl);
3037 :
3038 : /* grant global privileges */
3039 29 : if ((hdl = mapi_query(mid, global_grants)) == NULL || mapi_error(mid))
3040 0 : goto bailout;
3041 :
3042 34 : while (mapi_fetch_row(hdl) != 0) {
3043 5 : const char *uname = mapi_fetch_field(hdl, 0);
3044 5 : const char *grant = mapi_fetch_field(hdl, 1);
3045 : //const char *gname = mapi_fetch_field(hdl, 2);
3046 5 : const char *grantable = mapi_fetch_field(hdl, 3);
3047 5 : mnstr_printf(sqlf, "GRANT %s TO ", grant);
3048 5 : dquoted_print(sqlf, uname, grantable);
3049 5 : mnstr_printf(sqlf, ";\n");
3050 : }
3051 29 : if (mapi_error(mid))
3052 0 : goto bailout;
3053 29 : mapi_close_handle(hdl);
3054 : }
3055 :
3056 : /* dump types */
3057 31 : if ((hdl = mapi_query(mid, types)) == NULL || mapi_error(mid))
3058 0 : goto bailout;
3059 :
3060 31 : while (mapi_fetch_row(hdl) != 0) {
3061 0 : const char *sname = mapi_fetch_field(hdl, 0);
3062 0 : const char *sysname = mapi_fetch_field(hdl, 1);
3063 0 : const char *sqlname = mapi_fetch_field(hdl, 2);
3064 0 : mnstr_printf(sqlf, "CREATE TYPE ");
3065 0 : dquoted_print(sqlf, sname, ".");
3066 0 : dquoted_print(sqlf, sqlname, " EXTERNAL NAME ");
3067 0 : dquoted_print(sqlf, sysname, ";\n");
3068 : }
3069 31 : if (mapi_error(mid))
3070 0 : goto bailout;
3071 31 : mapi_close_handle(hdl);
3072 31 : hdl = NULL;
3073 :
3074 : /* dump sequences, part 1 */
3075 31 : if ((hdl = mapi_query(mid, sequences1)) == NULL || mapi_error(mid))
3076 0 : goto bailout;
3077 :
3078 59 : while (mapi_fetch_row(hdl) != 0) {
3079 28 : const char *schema = mapi_fetch_field(hdl, 0);
3080 28 : const char *name = mapi_fetch_field(hdl, 1);
3081 28 : const char *remark = mapi_fetch_field(hdl, 2);
3082 :
3083 28 : if (sname != NULL && strcmp(schema, sname) != 0)
3084 0 : continue;
3085 28 : mnstr_printf(sqlf, "CREATE SEQUENCE ");
3086 28 : dquoted_print(sqlf, schema, ".");
3087 28 : dquoted_print(sqlf, name, " AS INTEGER;\n");
3088 28 : comment_on(sqlf, "SEQUENCE", schema, name, NULL, remark);
3089 : }
3090 31 : if (mapi_error(mid))
3091 0 : goto bailout;
3092 31 : mapi_close_handle(hdl);
3093 31 : hdl = NULL;
3094 :
3095 : /* Tables, views, triggers, and functions can all reference each
3096 : * other, so we need to be very careful in how we dump them. We
3097 : * first dump the tables (all types), including data, but without
3098 : * the DEFAULT clause which is the one that can reference functions,
3099 : * views, and other tables. Then we add tables to the MERGE tables
3100 : * they belong to. After this, we dump the views, triggers, and
3101 : * functions in order of original creation (they can't be altered
3102 : * afterwards, so they can only reference objects that were created
3103 : * earlier). Finally, we set the DEFAULT clauses on the tables. */
3104 :
3105 : /* dump tables */
3106 31 : if ((hdl = mapi_query(mid, tables)) == NULL || mapi_error(mid))
3107 0 : goto bailout;
3108 :
3109 436 : while (rc == 0 &&
3110 872 : mnstr_errnr(sqlf) == MNSTR_NO__ERROR &&
3111 436 : mapi_fetch_row(hdl) != 0) {
3112 405 : char *id = strdup(mapi_fetch_field(hdl, 0));
3113 405 : char *schema = strdup(mapi_fetch_field(hdl, 1));
3114 405 : char *name = strdup(mapi_fetch_field(hdl, 2));
3115 405 : const char *type = mapi_fetch_field(hdl, 3);
3116 :
3117 405 : if (mapi_error(mid) || id == NULL || schema == NULL || name == NULL) {
3118 0 : free(id);
3119 0 : free(schema);
3120 0 : free(name);
3121 0 : goto bailout;
3122 : }
3123 405 : if (sname != NULL && strcmp(schema, sname) != 0) {
3124 4 : free(id);
3125 4 : free(schema);
3126 4 : free(name);
3127 4 : continue;
3128 : }
3129 401 : if (strcmp(schema, "tmp") != 0) {
3130 401 : if (curschema == NULL || strcmp(schema, curschema) != 0) {
3131 15 : if (curschema)
3132 15 : free(curschema);
3133 15 : curschema = strdup(schema);
3134 15 : if (curschema == NULL) {
3135 0 : free(id);
3136 0 : free(schema);
3137 0 : free(name);
3138 0 : goto bailout;
3139 : }
3140 15 : mnstr_printf(sqlf, "SET SCHEMA ");
3141 15 : dquoted_print(sqlf, curschema, ";\n");
3142 : }
3143 : }
3144 401 : int ptype = atoi(type), dont_describe = (ptype == 3 || ptype == 5);
3145 401 : rc = dump_table(mid, schema, name, sqlf, ddir, ext, dont_describe || describe, describe, useInserts, true, noescape, false);
3146 401 : free(id);
3147 401 : free(schema);
3148 401 : free(name);
3149 : }
3150 31 : mapi_close_handle(hdl);
3151 31 : hdl = NULL;
3152 :
3153 : /* dump views, functions and triggers */
3154 62 : if ((hdl = mapi_query(mid, views_functions_triggers)) == NULL ||
3155 31 : mapi_error(mid))
3156 0 : goto bailout;
3157 :
3158 170 : while (rc == 0 &&
3159 340 : mnstr_errnr(sqlf) == MNSTR_NO__ERROR &&
3160 170 : mapi_fetch_row(hdl) != 0) {
3161 139 : char *id = strdup(mapi_fetch_field(hdl, 0));
3162 139 : char *schema = strdup(mapi_fetch_field(hdl, 1));
3163 139 : char *name = strdup(mapi_fetch_field(hdl, 2));
3164 139 : const char *query = mapi_fetch_field(hdl, 3);
3165 139 : const char *remark = mapi_fetch_field(hdl, 4);
3166 :
3167 139 : if (mapi_error(mid) || id == NULL || schema == NULL || name == NULL) {
3168 0 : free(id);
3169 0 : free(schema);
3170 0 : free(name);
3171 0 : goto bailout;
3172 : }
3173 139 : if (sname != NULL && strcmp(schema, sname) != 0) {
3174 8 : free(id);
3175 8 : free(schema);
3176 8 : free(name);
3177 8 : continue;
3178 : }
3179 131 : if (curschema == NULL || strcmp(schema, curschema) != 0) {
3180 2 : if (curschema)
3181 2 : free(curschema);
3182 2 : curschema = strdup(schema);
3183 2 : if (curschema == NULL) {
3184 0 : free(id);
3185 0 : free(schema);
3186 0 : free(name);
3187 0 : goto bailout;
3188 : }
3189 2 : mnstr_printf(sqlf, "SET SCHEMA ");
3190 2 : dquoted_print(sqlf, curschema, ";\n");
3191 : }
3192 131 : if (query) {
3193 : /* view or trigger */
3194 38 : mnstr_printf(sqlf, "%s\n", query);
3195 : /* only views have comments due to query */
3196 38 : comment_on(sqlf, "VIEW", schema, name, NULL, remark);
3197 : } else {
3198 : /* procedure */
3199 93 : dump_functions(mid, sqlf, 0, schema, name, id);
3200 : }
3201 131 : free(id);
3202 131 : free(schema);
3203 131 : free(name);
3204 : }
3205 31 : mapi_close_handle(hdl);
3206 31 : hdl = NULL;
3207 :
3208 : /* dump DEFAULT clauses for tables */
3209 31 : if (dump_table_defaults(mid, NULL, NULL, sqlf))
3210 0 : goto bailout2;
3211 :
3212 31 : if (!describe) {
3213 31 : if (dump_foreign_keys(mid, NULL, NULL, NULL, sqlf))
3214 0 : goto bailout2;
3215 :
3216 : /* dump sequences, part 2 */
3217 62 : if ((hdl = mapi_query(mid, sequences2)) == NULL ||
3218 31 : mapi_error(mid))
3219 0 : goto bailout;
3220 :
3221 59 : while (mapi_fetch_row(hdl) != 0) {
3222 28 : const char *schema = mapi_fetch_field(hdl, 0); /* sch */
3223 28 : const char *name = mapi_fetch_field(hdl, 1); /* seq */
3224 28 : const char *restart = mapi_fetch_field(hdl, 3); /* rs */
3225 28 : const char *minvalue;
3226 28 : const char *maxvalue;
3227 28 : const char *increment = mapi_fetch_field(hdl, 6); /* inc */
3228 28 : const char *cycle = mapi_fetch_field(hdl, 8); /* cycle */
3229 :
3230 28 : if (mapi_get_field_count(hdl) > 9) {
3231 : /* new version (Jan2022) of sys.describe_sequences */
3232 28 : minvalue = mapi_fetch_field(hdl, 11); /* rmi */
3233 28 : maxvalue = mapi_fetch_field(hdl, 12); /* rma */
3234 : } else {
3235 : /* old version (pre Jan2022) of sys.describe_sequences */
3236 0 : minvalue = mapi_fetch_field(hdl, 4); /* minvalue */
3237 0 : maxvalue = mapi_fetch_field(hdl, 5); /* maxvalue */
3238 0 : if (strcmp(minvalue, "0") == 0)
3239 0 : minvalue = NULL;
3240 0 : if (strcmp(maxvalue, "0") == 0)
3241 0 : maxvalue = NULL;
3242 : }
3243 :
3244 28 : if (sname != NULL && strcmp(schema, sname) != 0)
3245 0 : continue;
3246 :
3247 28 : mnstr_printf(sqlf,
3248 : "ALTER SEQUENCE ");
3249 28 : dquoted_print(sqlf, schema, ".");
3250 28 : dquoted_print(sqlf, name, NULL);
3251 28 : mnstr_printf(sqlf, " RESTART WITH %s", restart);
3252 28 : if (strcmp(increment, "1") != 0)
3253 15 : mnstr_printf(sqlf, " INCREMENT BY %s", increment);
3254 28 : if (minvalue)
3255 15 : mnstr_printf(sqlf, " MINVALUE %s", minvalue);
3256 28 : if (maxvalue)
3257 15 : mnstr_printf(sqlf, " MAXVALUE %s", maxvalue);
3258 41 : mnstr_printf(sqlf, " %sCYCLE;\n", strcmp(cycle, "true") == 0 ? "" : "NO ");
3259 28 : if (mnstr_errnr(sqlf) != MNSTR_NO__ERROR) {
3260 0 : mapi_close_handle(hdl);
3261 0 : goto bailout2;
3262 : }
3263 : }
3264 31 : if (mapi_error(mid))
3265 0 : goto bailout;
3266 31 : mapi_close_handle(hdl);
3267 : }
3268 :
3269 : /* add tables to MERGE tables */
3270 31 : if ((hdl = mapi_query(mid, mergetables)) == NULL || mapi_error(mid))
3271 0 : goto bailout;
3272 :
3273 180 : while (rc == 0 &&
3274 360 : mnstr_errnr(sqlf) == MNSTR_NO__ERROR &&
3275 180 : mapi_fetch_row(hdl) != 0) {
3276 149 : const char *schema1 = mapi_fetch_field(hdl, 0);
3277 149 : const char *tname1 = mapi_fetch_field(hdl, 1);
3278 149 : const char *schema2 = mapi_fetch_field(hdl, 2);
3279 149 : const char *tname2 = mapi_fetch_field(hdl, 3);
3280 149 : const char *prop = mapi_fetch_field(hdl, 4);
3281 244 : int properties = prop ? atoi(prop) : 0;
3282 :
3283 149 : if (mapi_error(mid))
3284 0 : goto bailout;
3285 149 : if (schema1 == NULL || schema2 == NULL) {
3286 : /* cannot happen, but make analysis tools happy */
3287 0 : continue;
3288 : }
3289 149 : if (sname != NULL && strcmp(schema1, sname) != 0)
3290 0 : continue;
3291 149 : mnstr_printf(sqlf, "ALTER TABLE ");
3292 149 : dquoted_print(sqlf, schema1, ".");
3293 149 : dquoted_print(sqlf, tname1, " ADD TABLE ");
3294 149 : dquoted_print(sqlf, schema2, ".");
3295 149 : dquoted_print(sqlf, tname2, NULL);
3296 149 : if (properties) {
3297 95 : MapiHdl shdl = NULL;
3298 95 : char *s2 = sescape(schema2);
3299 95 : char *t2 = sescape(tname2);
3300 95 : const size_t query_size = 5120;
3301 95 : char *query = malloc(query_size);
3302 95 : if (query == NULL)
3303 0 : goto bailout;
3304 :
3305 95 : mnstr_printf(sqlf, " AS PARTITION");
3306 95 : if ((properties & 2) == 2) { /* by values */
3307 27 : int i = 0;
3308 27 : bool first = true, found_nil = false;
3309 27 : snprintf(query, query_size,
3310 : "SELECT vp.value "
3311 : "FROM sys.schemas s, "
3312 : "sys._tables t, "
3313 : "sys.value_partitions vp "
3314 : "WHERE s.name = '%s' "
3315 : "AND t.name = '%s' "
3316 : "AND s.id = t.schema_id "
3317 : "AND t.id = vp.table_id",
3318 : s2, t2);
3319 27 : shdl = mapi_query(mid, query);
3320 27 : free(query);
3321 27 : if (shdl == NULL || mapi_error(mid)) {
3322 0 : mapi_close_handle(shdl);
3323 0 : goto bailout;
3324 : }
3325 117 : while (mapi_fetch_row(shdl) != 0) {
3326 90 : char *nextv = mapi_fetch_field(shdl, 0);
3327 90 : if (first && nextv == NULL) {
3328 9 : found_nil = true;
3329 9 : first = false; // if the partition can hold null values, is explicit in the first entry
3330 9 : continue;
3331 : }
3332 81 : if (nextv) {
3333 81 : if (i == 0) {
3334 : // start by writing the IN clause
3335 27 : mnstr_printf(sqlf, " IN (");
3336 : } else {
3337 54 : mnstr_printf(sqlf, ", ");
3338 : }
3339 81 : squoted_print(sqlf, nextv, '\'', false);
3340 81 : i++;
3341 : }
3342 : first = false;
3343 : }
3344 27 : mapi_close_handle(shdl);
3345 27 : if (i > 0) {
3346 27 : mnstr_printf(sqlf, ")");
3347 : }
3348 27 : if (found_nil) {
3349 18 : mnstr_printf(sqlf, " %s NULL VALUES", (i == 0) ? "FOR" : "WITH");
3350 : }
3351 : } else { /* by range */
3352 68 : char *minv = NULL, *maxv = NULL, *wnulls = NULL;
3353 68 : snprintf(query, query_size,
3354 : "SELECT rp.minimum, "
3355 : "rp.maximum, "
3356 : "rp.with_nulls "
3357 : "FROM sys.schemas s, "
3358 : "sys._tables t, "
3359 : "sys.range_partitions rp "
3360 : "WHERE s.name = '%s' "
3361 : "AND t.name = '%s' "
3362 : "AND s.id = t.schema_id "
3363 : "AND t.id = rp.table_id",
3364 : s2, t2);
3365 68 : shdl = mapi_query(mid, query);
3366 68 : free(query);
3367 68 : if (shdl == NULL || mapi_error(mid)) {
3368 0 : mapi_close_handle(shdl);
3369 0 : goto bailout;
3370 : }
3371 136 : while (mapi_fetch_row(shdl) != 0) {
3372 68 : minv = mapi_fetch_field(shdl, 0);
3373 68 : maxv = mapi_fetch_field(shdl, 1);
3374 68 : wnulls = mapi_fetch_field(shdl, 2);
3375 : }
3376 68 : if (minv || maxv || !wnulls || (!minv && !maxv && wnulls && strcmp(wnulls, "false") == 0)) {
3377 59 : mnstr_printf(sqlf, " FROM ");
3378 59 : if (minv)
3379 32 : squoted_print(sqlf, minv, '\'', false);
3380 : else
3381 27 : mnstr_printf(sqlf, "RANGE MINVALUE");
3382 59 : mnstr_printf(sqlf, " TO ");
3383 59 : if (maxv)
3384 32 : squoted_print(sqlf, maxv, '\'', false);
3385 : else
3386 27 : mnstr_printf(sqlf, "RANGE MAXVALUE");
3387 : }
3388 68 : if (!wnulls || strcmp(wnulls, "true") == 0)
3389 45 : mnstr_printf(sqlf, " %s NULL VALUES", (minv || maxv || !wnulls) ? "WITH" : "FOR");
3390 68 : mapi_close_handle(shdl);
3391 : }
3392 95 : free(s2);
3393 95 : free(t2);
3394 : }
3395 149 : mnstr_printf(sqlf, ";\n");
3396 : }
3397 31 : mapi_close_handle(hdl);
3398 31 : hdl = NULL;
3399 :
3400 31 : if ((hdl = mapi_query(mid, table_grants)) == NULL || mapi_error(mid))
3401 0 : goto bailout;
3402 :
3403 31 : while (mapi_fetch_row(hdl) != 0) {
3404 0 : const char *schema = mapi_fetch_field(hdl, 0);
3405 0 : const char *tname = mapi_fetch_field(hdl, 1);
3406 0 : const char *aname = mapi_fetch_field(hdl, 2);
3407 0 : int priv = atoi(mapi_fetch_field(hdl, 3));
3408 0 : const char *grantable = mapi_fetch_field(hdl, 5);
3409 :
3410 0 : if (sname != NULL && strcmp(schema, sname) != 0)
3411 0 : continue;
3412 0 : mnstr_printf(sqlf, "GRANT");
3413 0 : if (priv == 79) {
3414 0 : mnstr_printf(sqlf, " ALL PRIVILEGES");
3415 : } else {
3416 0 : sep = "";
3417 :
3418 0 : if (priv & 1) {
3419 0 : mnstr_printf(sqlf, "%s SELECT", sep);
3420 0 : sep = ",";
3421 : }
3422 0 : if (priv & 2) {
3423 0 : mnstr_printf(sqlf, "%s UPDATE", sep);
3424 0 : sep = ",";
3425 : }
3426 0 : if (priv & 4) {
3427 0 : mnstr_printf(sqlf, "%s INSERT", sep);
3428 0 : sep = ",";
3429 : }
3430 0 : if (priv & 8) {
3431 0 : mnstr_printf(sqlf, "%s DELETE", sep);
3432 0 : sep = ",";
3433 : }
3434 0 : if (priv & 16) {
3435 0 : mnstr_printf(sqlf, "%s EXECUTE", sep);
3436 0 : sep = ",";
3437 : }
3438 0 : if (priv & 32) {
3439 0 : mnstr_printf(sqlf, "%s GRANT", sep);
3440 0 : sep = ",";
3441 : }
3442 0 : if (priv & 64) {
3443 0 : mnstr_printf(sqlf, "%s TRUNCATE", sep);
3444 : // sep = ","; /* sep will be overwritten after this */
3445 : }
3446 : }
3447 0 : mnstr_printf(sqlf, " ON TABLE ");
3448 0 : dquoted_print(sqlf, schema, ".");
3449 0 : dquoted_print(sqlf, tname, " TO ");
3450 0 : dquoted_print(sqlf, aname, grantable);
3451 0 : mnstr_printf(sqlf, ";\n");
3452 : }
3453 31 : if (mapi_error(mid))
3454 0 : goto bailout;
3455 31 : mapi_close_handle(hdl);
3456 :
3457 31 : if ((hdl = mapi_query(mid, column_grants)) == NULL || mapi_error(mid))
3458 0 : goto bailout;
3459 :
3460 49 : while (mapi_fetch_row(hdl) != 0) {
3461 18 : const char *schema = mapi_fetch_field(hdl, 0);
3462 18 : const char *tname = mapi_fetch_field(hdl, 1);
3463 18 : const char *cname = mapi_fetch_field(hdl, 2);
3464 18 : const char *aname = mapi_fetch_field(hdl, 3);
3465 18 : const char *priv = mapi_fetch_field(hdl, 4);
3466 18 : const char *grantable = mapi_fetch_field(hdl, 6);
3467 :
3468 18 : if (sname != NULL && strcmp(schema, sname) != 0)
3469 0 : continue;
3470 18 : mnstr_printf(sqlf, "GRANT %s(", priv);
3471 18 : dquoted_print(sqlf, cname, ") ON ");
3472 18 : dquoted_print(sqlf, schema, ".");
3473 18 : dquoted_print(sqlf, tname, " TO ");
3474 18 : if (strcmp(aname, "public") == 0) {
3475 0 : mnstr_printf(sqlf, "PUBLIC%s", grantable);
3476 : } else {
3477 18 : dquoted_print(sqlf, aname, grantable);
3478 : }
3479 18 : mnstr_printf(sqlf, ";\n");
3480 : }
3481 31 : if (mapi_error(mid))
3482 0 : goto bailout;
3483 31 : mapi_close_handle(hdl);
3484 :
3485 62 : if ((hdl = mapi_query(mid, function_grants)) == NULL ||
3486 31 : mapi_error(mid))
3487 0 : goto bailout;
3488 :
3489 : sep = "";
3490 58 : while (mapi_fetch_row(hdl) != 0) {
3491 27 : const char *fid = mapi_fetch_field(hdl, 0);
3492 27 : const char *schema = mapi_fetch_field(hdl, 1);
3493 27 : const char *fname = mapi_fetch_field(hdl, 2);
3494 27 : const char *argtype = mapi_fetch_field(hdl, 3);
3495 27 : const char *argdigits = mapi_fetch_field(hdl, 4);
3496 27 : const char *argscale = mapi_fetch_field(hdl, 5);
3497 27 : const char *arginout = mapi_fetch_field(hdl, 6);
3498 27 : const char *argnumber = mapi_fetch_field(hdl, 7);
3499 27 : const char *aname = mapi_fetch_field(hdl, 8);
3500 27 : const char *priv = mapi_fetch_field(hdl, 9);
3501 27 : const char *grantable = mapi_fetch_field(hdl, 10);
3502 27 : const char *ftype = mapi_fetch_field(hdl, 11);
3503 :
3504 27 : if (sname != NULL && strcmp(schema, sname) != 0)
3505 0 : continue;
3506 27 : int thisfid = atoi(fid);
3507 27 : if (lastfid != thisfid) {
3508 9 : lastfid = thisfid;
3509 9 : sep = "";
3510 9 : mnstr_printf(sqlf, "GRANT %s ON %s ", priv, ftype);
3511 9 : dquoted_print(sqlf, schema, ".");
3512 9 : dquoted_print(sqlf, fname, "(");
3513 : }
3514 27 : if (arginout != NULL && strcmp(arginout, "1") == 0) {
3515 0 : mnstr_printf(sqlf, "%s", sep);
3516 0 : dump_type(mid, sqlf, argtype, argdigits, argscale, hashge);
3517 0 : sep = ", ";
3518 27 : } else if (argnumber == NULL || strcmp(argnumber, "0") == 0) {
3519 9 : mnstr_printf(sqlf, ") TO ");
3520 9 : if (strcmp(aname, "public") == 0) {
3521 9 : mnstr_printf(sqlf, "PUBLIC%s", grantable);
3522 : } else {
3523 0 : dquoted_print(sqlf, aname, grantable);
3524 : }
3525 9 : mnstr_printf(sqlf, ";\n");
3526 : }
3527 : }
3528 31 : if (mapi_error(mid))
3529 0 : goto bailout;
3530 31 : mapi_close_handle(hdl);
3531 :
3532 31 : if (curschema) {
3533 60 : if (strcmp(sname ? sname : "sys", curschema) != 0) {
3534 14 : mnstr_printf(sqlf, "SET SCHEMA ");
3535 14 : dquoted_print(sqlf, sname ? sname : "sys", ";\n");
3536 : }
3537 31 : free(curschema);
3538 31 : curschema = NULL;
3539 : }
3540 :
3541 31 : if ((hdl = mapi_query(mid, end)) == NULL || mapi_error(mid))
3542 0 : goto bailout;
3543 31 : mapi_close_handle(hdl);
3544 :
3545 : /* finally commit the whole transaction */
3546 31 : mnstr_printf(sqlf, "COMMIT;\n");
3547 31 : if (sname)
3548 2 : free(sname);
3549 : return rc;
3550 :
3551 0 : bailout:
3552 0 : if (hdl) {
3553 0 : if (mapi_result_error(hdl))
3554 0 : mapi_explain_result(hdl, stderr);
3555 0 : else if (mapi_error(mid))
3556 0 : mapi_explain_query(hdl, stderr);
3557 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
3558 0 : fprintf(stderr, "malloc failure\n");
3559 0 : mapi_close_handle(hdl);
3560 0 : } else if (mapi_error(mid))
3561 0 : mapi_explain(mid, stderr);
3562 0 : else if (mnstr_errnr(sqlf) == MNSTR_NO__ERROR)
3563 0 : fprintf(stderr, "malloc failure\n");
3564 :
3565 0 : bailout2:
3566 0 : if (sname)
3567 0 : free(sname);
3568 0 : if (curschema)
3569 0 : free(curschema);
3570 0 : hdl = mapi_query(mid, end);
3571 0 : if (hdl)
3572 0 : mapi_close_handle(hdl);
3573 : return 1;
3574 : }
3575 :
3576 : void
3577 0 : dump_version(Mapi mid, stream *sqlf, const char *prefix)
3578 : {
3579 0 : MapiHdl hdl;
3580 0 : char *dbname = NULL, *uri = NULL, *dbver = NULL, *dbrel = NULL, *dbrev = NULL;
3581 0 : const char *name, *val;
3582 :
3583 0 : if ((hdl = mapi_query(mid,
3584 : "SELECT name, value "
3585 : "FROM sys.env() AS env "
3586 : "WHERE name IN ('gdk_dbname', "
3587 : "'monet_version', "
3588 : "'monet_release', "
3589 : "'merovingian_uri', "
3590 0 : "'revision')")) == NULL ||
3591 0 : mapi_error(mid))
3592 0 : goto cleanup;
3593 :
3594 0 : while ((mapi_fetch_row(hdl)) != 0) {
3595 0 : name = mapi_fetch_field(hdl, 0);
3596 0 : val = mapi_fetch_field(hdl, 1);
3597 :
3598 0 : if (mapi_error(mid))
3599 0 : goto cleanup;
3600 :
3601 0 : if (name != NULL && val != NULL) {
3602 0 : if (strcmp(name, "gdk_dbname") == 0) {
3603 0 : assert(dbname == NULL);
3604 0 : dbname = *val == '\0' ? NULL : strdup(val);
3605 0 : } else if (strcmp(name, "monet_version") == 0) {
3606 0 : assert(dbver == NULL);
3607 0 : dbver = *val == '\0' ? NULL : strdup(val);
3608 0 : } else if (strcmp(name, "monet_release") == 0) {
3609 0 : assert(dbrel == NULL);
3610 0 : dbrel = *val == '\0' ? NULL : strdup(val);
3611 0 : } else if (strcmp(name, "merovingian_uri") == 0) {
3612 0 : assert(uri == NULL);
3613 0 : uri = strdup(val);
3614 0 : } else if (strcmp(name, "revision") == 0) {
3615 0 : assert(dbrev == NULL);
3616 0 : dbrev = strdup(val);
3617 : }
3618 : }
3619 : }
3620 0 : if (uri != NULL) {
3621 0 : if (dbname != NULL)
3622 0 : free(dbname);
3623 : dbname = uri;
3624 : uri = NULL;
3625 : }
3626 0 : mnstr_printf(sqlf, "%s MonetDB", prefix);
3627 0 : if (dbver)
3628 0 : mnstr_printf(sqlf, " v%s", dbver);
3629 0 : if (dbrel && strcmp(dbrel, "unreleased") != 0)
3630 0 : mnstr_printf(sqlf, " (%s)", dbrel);
3631 0 : else if (dbrev && strcmp(dbrev, "Unknown") != 0)
3632 0 : mnstr_printf(sqlf, " (hg id: %s)", dbrev);
3633 0 : if (dbname)
3634 0 : mnstr_printf(sqlf, ", '%s'", dbname);
3635 0 : mnstr_printf(sqlf, "\n");
3636 :
3637 0 : cleanup:
3638 0 : if (dbname != NULL)
3639 0 : free(dbname);
3640 0 : if (dbver != NULL)
3641 0 : free(dbver);
3642 0 : if (dbrel != NULL)
3643 0 : free(dbrel);
3644 0 : if (uri != NULL)
3645 0 : free(uri);
3646 0 : if (dbrev != NULL)
3647 0 : free(dbrev);
3648 0 : if (hdl)
3649 0 : mapi_close_handle(hdl);
3650 0 : }
|