LCOV - code coverage report
Current view: top level - clients/mapiclient - dump.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1117 1752 63.8 %
Date: 2021-10-13 02:24:04 Functions: 21 22 95.5 %

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

Generated by: LCOV version 1.14