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