LCOV - code coverage report
Current view: top level - clients/mapiclient - dump.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1408 2313 60.9 %
Date: 2024-11-15 19:37:45 Functions: 25 28 89.3 %

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

Generated by: LCOV version 1.14