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