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