LCOV - code coverage report
Current view: top level - clients/mapiclient - dump.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1412 2328 60.7 %
Date: 2025-03-25 21:27:32 Functions: 24 27 88.9 %

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

Generated by: LCOV version 1.14