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