LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_result.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 768 1020 75.3 %
Date: 2021-10-13 02:24:04 Functions: 37 44 84.1 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * author N.J. Nes
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "sql_result.h"
      15             : #include "str.h"
      16             : #include "tablet.h"
      17             : #include "gdk_time.h"
      18             : #include "bat/res_table.h"
      19             : #include "bat/bat_storage.h"
      20             : #include "rel_exp.h"
      21             : 
      22             : #ifndef HAVE_LLABS
      23             : #define llabs(x)        ((x) < 0 ? -(x) : (x))
      24             : #endif
      25             : 
      26             : #ifdef _MSC_VER
      27             : /* use intrinsic functions on Windows */
      28             : #define short_int_SWAP(s)       ((short) _byteswap_ushort((unsigned short) (s)))
      29             : /* on Windows, long is the same size as int */
      30             : #define normal_int_SWAP(s)      ((int) _byteswap_ulong((unsigned long) (s)))
      31             : #define long_long_SWAP(s)       ((lng) _byteswap_uint64((unsigned __int64) (s)))
      32             : #else
      33             : #define short_int_SWAP(s) ((short)(((0x00ff&(s))<<8) | ((0xff00&(s))>>8)))
      34             : 
      35             : #define normal_int_SWAP(i) (((0x000000ff&(i))<<24) | ((0x0000ff00&(i))<<8) | \
      36             :                             ((0x00ff0000&(i))>>8)  | ((0xff000000&(i))>>24))
      37             : #define long_long_SWAP(l)                                               \
      38             :                 ((((lng)normal_int_SWAP(l))<<32) |                \
      39             :                  (0xffffffff&normal_int_SWAP(l>>32)))
      40             : #endif
      41             : 
      42             : #ifdef HAVE_HGE
      43             : #define huge_int_SWAP(h)                                                                \
      44             :                 ((((hge)long_long_SWAP(h))<<64) |                         \
      45             :                  (0xffffffffffffffff&long_long_SWAP(h>>64)))
      46             : #endif
      47             : #define DEC_TOSTR(TYPE)                                                         \
      48             :         do {                                                                                    \
      49             :                 char buf[64];                                                           \
      50             :                 TYPE v = *(const TYPE *) a;                                     \
      51             :                 int scale = (int) (ptrdiff_t) extra;            \
      52             :                 int cur = 63, i, done = 0;                                      \
      53             :                 int neg = v < 0;                                                     \
      54             :                 ssize_t l;                                                                      \
      55             :                 if (is_##TYPE##_nil(v)) {                                       \
      56             :                         if (*Buf == NULL || *len < 5){                       \
      57             :                                 GDKfree(*Buf);                                          \
      58             :                                 *len = 5;                                                       \
      59             :                                 *Buf = GDKzalloc(*len);                         \
      60             :                                 if (*Buf == NULL) {                                     \
      61             :                                         return -1;                                              \
      62             :                                 }                                                                       \
      63             :                         }                                                                               \
      64             :                         strcpy(*Buf, "NULL");                                 \
      65             :                         return 4;                                                               \
      66             :                 }                                                                                       \
      67             :                 if (v<0)                                                                     \
      68             :                         v = -v;                                                                 \
      69             :                 buf[cur--] = 0;                                                         \
      70             :                 if (scale){                                                                     \
      71             :                         for (i=0; i<scale; i++) {                            \
      72             :                                 buf[cur--] = (char) (v%10 + '0');       \
      73             :                                 v /= 10;                                                        \
      74             :                         }                                                                               \
      75             :                         buf[cur--] = '.';                                               \
      76             :                 }                                                                                       \
      77             :                 while (v) {                                                                     \
      78             :                         buf[cur--] = (char ) (v%10 + '0');              \
      79             :                         v /= 10;                                                                \
      80             :                         done = 1;                                                               \
      81             :                 }                                                                                       \
      82             :                 if (!done)                                                                      \
      83             :                         buf[cur--] = '0';                                               \
      84             :                 if (neg)                                                                        \
      85             :                         buf[cur--] = '-';                                               \
      86             :                 l = (64-cur-1);                                                         \
      87             :                 if (*Buf == NULL || (ssize_t) *len < l) {    \
      88             :                         GDKfree(*Buf);                                                  \
      89             :                         *len = (size_t) l+1;                                    \
      90             :                         *Buf = GDKzalloc(*len);                                 \
      91             :                         if (*Buf == NULL) {                                             \
      92             :                                 return -1;                                                      \
      93             :                         }                                                                               \
      94             :                 }                                                                                       \
      95             :                 strcpy(*Buf, buf+cur+1);                                        \
      96             :                 return l-1;                                                                     \
      97             :         } while (0)
      98             : 
      99             : static ssize_t
     100       65699 : dec_tostr(void *extra, char **Buf, size_t *len, int type, const void *a)
     101             : {
     102             :         /* support dec map to bte, sht, int and lng */
     103       65699 :         if (type == TYPE_bte) {
     104         382 :                 DEC_TOSTR(bte);
     105       65585 :         } else if (type == TYPE_sht) {
     106        3101 :                 DEC_TOSTR(sht);
     107       64946 :         } else if (type == TYPE_int) {
     108       33899 :                 DEC_TOSTR(int);
     109       58925 :         } else if (type == TYPE_lng) {
     110      151961 :                 DEC_TOSTR(lng);
     111             : #ifdef HAVE_HGE
     112       33531 :         } else if (type == TYPE_hge) {
     113      236048 :                 DEC_TOSTR(hge);
     114             : #endif
     115             :         } else {
     116           0 :                 GDKerror("Decimal cannot be mapped to %s\n", ATOMname(type));
     117             :         }
     118           0 :         return -1;
     119             : }
     120             : 
     121             : struct time_res {
     122             :         int fraction;
     123             :         int has_tz;
     124             :         lng timezone;
     125             : };
     126             : 
     127             : static ssize_t
     128        2540 : sql_time_tostr(void *TS_RES, char **buf, size_t *len, int type, const void *A)
     129             : {
     130             :         struct time_res *ts_res = TS_RES;
     131             :         ssize_t len1;
     132        2540 :         size_t big = 128;
     133        2540 :         char buf1[128], *s1 = buf1, *s;
     134             :         daytime tmp;
     135             : 
     136             :         (void) type;
     137        2540 :         tmp = *(const daytime *) A;
     138        2540 :         if (ts_res->has_tz)
     139         181 :                 tmp = daytime_add_usec_modulo(tmp, ts_res->timezone * 1000);
     140             : 
     141        2540 :         len1 = daytime_precision_tostr(&s1, &big, tmp, ts_res->fraction, true);
     142        2540 :         if (len1 < 0)
     143             :                 return -1;
     144        2540 :         if (len1 == 3 && strcmp(s1, "nil") == 0) {
     145           0 :                 if (*len < 4 || *buf == NULL) {
     146           0 :                         GDKfree(*buf);
     147           0 :                         *buf = GDKzalloc(*len = 4);
     148           0 :                         if (*buf == NULL)
     149             :                                 return -1;
     150             :                 }
     151           0 :                 strcpy(*buf, "nil");
     152           0 :                 return len1;
     153             :         }
     154             : 
     155        2540 :         if (*buf == NULL || *len < (size_t) len1 + 8) {
     156           0 :                 GDKfree(*buf);
     157           0 :                 *buf = (str) GDKzalloc(*len = len1 + 8);
     158           0 :                 if (*buf == NULL) {
     159             :                         return -1;
     160             :                 }
     161             :         }
     162        2540 :         s = *buf;
     163        2540 :         strcpy(s, buf1);
     164        2540 :         s += len1;
     165             : 
     166        2540 :         if (ts_res->has_tz) {
     167         181 :                 lng timezone = llabs(ts_res->timezone / 60000);
     168         181 :                 s += sprintf(s, "%c%02d:%02d",
     169             :                              (ts_res->timezone >= 0) ? '+' : '-',
     170         181 :                              (int) (timezone / 60), (int) (timezone % 60));
     171             :         }
     172        2540 :         return (ssize_t) (s - *buf);
     173             : }
     174             : 
     175             : static ssize_t
     176        1424 : sql_timestamp_tostr(void *TS_RES, char **buf, size_t *len, int type, const void *A)
     177             : {
     178             :         struct time_res *ts_res = TS_RES;
     179             :         ssize_t len1, len2;
     180        1424 :         size_t big = 128;
     181        1424 :         char buf1[128], buf2[128], *s, *s1 = buf1, *s2 = buf2;
     182             :         timestamp tmp;
     183        1424 :         lng timezone = ts_res->timezone;
     184             :         date days;
     185             :         daytime usecs;
     186             : 
     187             :         (void) type;
     188        1424 :         tmp = *(const timestamp *)A;
     189        1424 :         if (ts_res->has_tz) {
     190         490 :                 tmp = timestamp_add_usec(tmp, timezone * 1000);
     191             :         }
     192        1424 :         days = timestamp_date(tmp);
     193        1424 :         usecs = timestamp_daytime(tmp);
     194        1424 :         len1 = date_tostr(&s1, &big, &days, true);
     195        1424 :         len2 = daytime_precision_tostr(&s2, &big, usecs, ts_res->fraction, true);
     196        1424 :         if (len1 < 0 || len2 < 0) {
     197           0 :                 GDKfree(s1);
     198           0 :                 GDKfree(s2);
     199           0 :                 return -1;
     200             :         }
     201             : 
     202        1424 :         if ((len1 == 3 && strcmp(s1, "nil") == 0) ||
     203           0 :             (len2 == 3 && strcmp(s2, "nil") == 0)) {
     204           0 :                 if (*len < 4 || *buf == NULL) {
     205           0 :                         GDKfree(*buf);
     206           0 :                         *buf = GDKzalloc(*len = 4);
     207           0 :                         if (*buf == NULL)
     208             :                                 return -1;
     209             :                 }
     210           0 :                 strcpy(*buf, "nil");
     211           0 :                 return len1;
     212             :         }
     213             : 
     214        1424 :         if (*buf == NULL || *len < (size_t) len1 + (size_t) len2 + 8) {
     215           0 :                 GDKfree(*buf);
     216           0 :                 *buf = (str) GDKzalloc(*len = (size_t) (len1 + len2 + 8));
     217           0 :                 if (*buf == NULL) {
     218             :                         return -1;
     219             :                 }
     220             :         }
     221        1424 :         s = *buf;
     222        1424 :         strcpy(s, buf1);
     223        1424 :         s += len1;
     224        1424 :         *s++ = ' ';
     225        1424 :         strcpy(s, buf2);
     226        1424 :         s += len2;
     227        1424 :         s[0] = 0;
     228             : 
     229        1424 :         if (ts_res->has_tz) {
     230         490 :                 timezone = ts_res->timezone / 60000;
     231         490 :                 *s++ = (ts_res->timezone >= 0) ? '+' : '-';
     232         490 :                 sprintf(s, "%02d:%02d", (int) (llabs(timezone) / 60), (int) (llabs(timezone) % 60));
     233         490 :                 s += 5;
     234             :         }
     235        1424 :         return (ssize_t) (s - *buf);
     236             : }
     237             : 
     238             : static inline int
     239     3953863 : STRwidth(const char *restrict s)
     240             : {
     241             :         int len = 0;
     242             :         int c;
     243             :         int n;
     244             : 
     245     3953863 :         if (strNil(s))
     246      410370 :                 return int_nil;
     247             :         c = 0;
     248             :         n = 0;
     249   123629867 :         while (*s != 0) {
     250   120086374 :                 if ((*s & 0x80) == 0) {
     251   120073852 :                         assert(n == 0);
     252   120073852 :                         len++;
     253             :                         n = 0;
     254       12522 :                 } else if ((*s & 0xC0) == 0x80) {
     255        8331 :                         c = (c << 6) | (*s & 0x3F);
     256        8331 :                         if (--n == 0) {
     257             :                                 /* last byte of a multi-byte character */
     258        4191 :                                 len++;
     259             :                                 /* this list was created by combining
     260             :                                  * the code points marked as
     261             :                                  * Emoji_Presentation in
     262             :                                  * /usr/share/unicode/emoji/emoji-data.txt
     263             :                                  * and code points marked either F or
     264             :                                  * W in EastAsianWidth.txt; this list
     265             :                                  * is up-to-date with Unicode 9.0 */
     266        4191 :                                 if ((0x1100 <= c && c <= 0x115F) ||
     267        4191 :                                     (0x231A <= c && c <= 0x231B) ||
     268        4191 :                                     (0x2329 <= c && c <= 0x232A) ||
     269        4191 :                                     (0x23E9 <= c && c <= 0x23EC) ||
     270        4191 :                                     c == 0x23F0 ||
     271        4191 :                                     c == 0x23F3 ||
     272        4191 :                                     (0x25FD <= c && c <= 0x25FE) ||
     273        4191 :                                     (0x2614 <= c && c <= 0x2615) ||
     274        4191 :                                     (0x2648 <= c && c <= 0x2653) ||
     275        4191 :                                     c == 0x267F ||
     276        4191 :                                     c == 0x2693 ||
     277        4191 :                                     c == 0x26A1 ||
     278        4191 :                                     (0x26AA <= c && c <= 0x26AB) ||
     279        4191 :                                     (0x26BD <= c && c <= 0x26BE) ||
     280        4191 :                                     (0x26C4 <= c && c <= 0x26C5) ||
     281        4191 :                                     c == 0x26CE ||
     282        4191 :                                     c == 0x26D4 ||
     283        4191 :                                     c == 0x26EA ||
     284        4191 :                                     (0x26F2 <= c && c <= 0x26F3) ||
     285        4191 :                                     c == 0x26F5 ||
     286        4191 :                                     c == 0x26FA ||
     287        4191 :                                     c == 0x26FD ||
     288        4191 :                                     c == 0x2705 ||
     289        4191 :                                     (0x270A <= c && c <= 0x270B) ||
     290        4191 :                                     c == 0x2728 ||
     291        4191 :                                     c == 0x274C ||
     292        4191 :                                     c == 0x274E ||
     293        4191 :                                     (0x2753 <= c && c <= 0x2755) ||
     294        4191 :                                     c == 0x2757 ||
     295        4191 :                                     (0x2795 <= c && c <= 0x2797) ||
     296        4191 :                                     c == 0x27B0 ||
     297        4191 :                                     c == 0x27BF ||
     298        4191 :                                     (0x2B1B <= c && c <= 0x2B1C) ||
     299        4191 :                                     c == 0x2B50 ||
     300        4191 :                                     c == 0x2B55 ||
     301        4191 :                                     (0x2E80 <= c && c <= 0x2E99) ||
     302        4191 :                                     (0x2E9B <= c && c <= 0x2EF3) ||
     303        4191 :                                     (0x2F00 <= c && c <= 0x2FD5) ||
     304        4191 :                                     (0x2FF0 <= c && c <= 0x2FFB) ||
     305        4191 :                                     (0x3000 <= c && c <= 0x303E) ||
     306        4191 :                                     (0x3041 <= c && c <= 0x3096) ||
     307        4191 :                                     (0x3099 <= c && c <= 0x30FF) ||
     308        4191 :                                     (0x3105 <= c && c <= 0x312D) ||
     309        4191 :                                     (0x3131 <= c && c <= 0x318E) ||
     310        4191 :                                     (0x3190 <= c && c <= 0x31BA) ||
     311        4191 :                                     (0x31C0 <= c && c <= 0x31E3) ||
     312        4191 :                                     (0x31F0 <= c && c <= 0x321E) ||
     313        4191 :                                     (0x3220 <= c && c <= 0x3247) ||
     314        4191 :                                     (0x3250 <= c && c <= 0x32FE) ||
     315        4191 :                                     (0x3300 <= c && c <= 0x4DBF) ||
     316        4191 :                                     (0x4E00 <= c && c <= 0xA48C) ||
     317        4168 :                                     (0xA490 <= c && c <= 0xA4C6) ||
     318        4168 :                                     (0xA960 <= c && c <= 0xA97C) ||
     319        4168 :                                     (0xAC00 <= c && c <= 0xD7A3) ||
     320        4166 :                                     (0xF900 <= c && c <= 0xFAFF) ||
     321        4166 :                                     (0xFE10 <= c && c <= 0xFE19) ||
     322        4166 :                                     (0xFE30 <= c && c <= 0xFE52) ||
     323        4166 :                                     (0xFE54 <= c && c <= 0xFE66) ||
     324        4166 :                                     (0xFE68 <= c && c <= 0xFE6B) ||
     325        4166 :                                     (0xFF01 <= c && c <= 0xFF60) ||
     326        4166 :                                     (0xFFE0 <= c && c <= 0xFFE6) ||
     327        4166 :                                     c == 0x16FE0 ||
     328        4166 :                                     (0x17000 <= c && c <= 0x187EC) ||
     329        4166 :                                     (0x18800 <= c && c <= 0x18AF2) ||
     330        4166 :                                     (0x1B000 <= c && c <= 0x1B001) ||
     331        4166 :                                     c == 0x1F004 ||
     332        4166 :                                     c == 0x1F0CF ||
     333        4166 :                                     c == 0x1F18E ||
     334        4166 :                                     (0x1F191 <= c && c <= 0x1F19A) ||
     335             :                                     /* removed 0x1F1E6..0x1F1FF */
     336        4166 :                                     (0x1F200 <= c && c <= 0x1F202) ||
     337        4166 :                                     (0x1F210 <= c && c <= 0x1F23B) ||
     338        4166 :                                     (0x1F240 <= c && c <= 0x1F248) ||
     339        4166 :                                     (0x1F250 <= c && c <= 0x1F251) ||
     340        4166 :                                     (0x1F300 <= c && c <= 0x1F320) ||
     341        4166 :                                     (0x1F32D <= c && c <= 0x1F335) ||
     342        4166 :                                     (0x1F337 <= c && c <= 0x1F37C) ||
     343        4166 :                                     (0x1F37E <= c && c <= 0x1F393) ||
     344        4166 :                                     (0x1F3A0 <= c && c <= 0x1F3CA) ||
     345        4166 :                                     (0x1F3CF <= c && c <= 0x1F3D3) ||
     346        4166 :                                     (0x1F3E0 <= c && c <= 0x1F3F0) ||
     347        4166 :                                     c == 0x1F3F4 ||
     348        4166 :                                     (0x1F3F8 <= c && c <= 0x1F43E) ||
     349        4166 :                                     c == 0x1F440 ||
     350        4166 :                                     (0x1F442 <= c && c <= 0x1F4FC) ||
     351        4166 :                                     (0x1F4FF <= c && c <= 0x1F53D) ||
     352        4163 :                                     (0x1F54B <= c && c <= 0x1F54E) ||
     353        4163 :                                     (0x1F550 <= c && c <= 0x1F567) ||
     354        4163 :                                     c == 0x1F57A ||
     355        4163 :                                     (0x1F595 <= c && c <= 0x1F596) ||
     356        4163 :                                     c == 0x1F5A4 ||
     357        4163 :                                     (0x1F5FB <= c && c <= 0x1F64F) ||
     358        4128 :                                     (0x1F680 <= c && c <= 0x1F6C5) ||
     359        4125 :                                     c == 0x1F6CC ||
     360        4125 :                                     (0x1F6D0 <= c && c <= 0x1F6D2) ||
     361        4125 :                                     (0x1F6EB <= c && c <= 0x1F6EC) ||
     362        4125 :                                     (0x1F6F4 <= c && c <= 0x1F6F6) ||
     363        4125 :                                     (0x1F910 <= c && c <= 0x1F91E) ||
     364        4125 :                                     (0x1F920 <= c && c <= 0x1F927) ||
     365        4125 :                                     c == 0x1F930 ||
     366        4125 :                                     (0x1F933 <= c && c <= 0x1F93E) ||
     367        4125 :                                     (0x1F940 <= c && c <= 0x1F94B) ||
     368        4125 :                                     (0x1F950 <= c && c <= 0x1F95E) ||
     369        4125 :                                     (0x1F980 <= c && c <= 0x1F991) ||
     370        4125 :                                     c == 0x1F9C0 ||
     371        4125 :                                     (0x20000 <= c && c <= 0x2FFFD) ||
     372        4125 :                                     (0x30000 <= c && c <= 0x3FFFD))
     373          66 :                                         len++;
     374             :                         }
     375        4191 :                 } else if ((*s & 0xE0) == 0xC0) {
     376          98 :                         assert(n == 0);
     377             :                         n = 1;
     378          98 :                         c = *s & 0x1F;
     379        4093 :                 } else if ((*s & 0xF0) == 0xE0) {
     380        4046 :                         assert(n == 0);
     381             :                         n = 2;
     382        4046 :                         c = *s & 0x0F;
     383          47 :                 } else if ((*s & 0xF8) == 0xF0) {
     384          47 :                         assert(n == 0);
     385             :                         n = 3;
     386          47 :                         c = *s & 0x07;
     387           0 :                 } else if ((*s & 0xFC) == 0xF8) {
     388           0 :                         assert(n == 0);
     389             :                         n = 4;
     390           0 :                         c = *s & 0x03;
     391             :                 } else {
     392           0 :                         assert(0);
     393             :                         n = 0;
     394             :                 }
     395   120086374 :                 s++;
     396             :         }
     397             :         return len;
     398             : }
     399             : 
     400             : static int
     401      114382 : bat_max_strlength(BAT *b)
     402             : {
     403             :         BUN p, q;
     404             :         int l = 0;
     405             :         int max = 0;
     406      114382 :         BATiter bi = bat_iterator(b);
     407             : 
     408     4068240 :         BATloop(b, p, q) {
     409     3953858 :                 l = STRwidth((const char *) BUNtvar(bi, p));
     410             : 
     411     3953858 :                 if (is_int_nil(l))
     412             :                         l = 0;
     413             :                 if (l > max)
     414             :                         max = l;
     415             :         }
     416      114382 :         bat_iterator_end(&bi);
     417      114382 :         return max;
     418             : }
     419             : 
     420             : #define bat_max_length(TPE, HIGH) \
     421             : static size_t \
     422             : bat_max_##TPE##length(BAT *b) \
     423             : { \
     424             :         BUN p, q; \
     425             :         HIGH max = 0, min = 0; \
     426             :         size_t ret = 0; \
     427             :         BATiter bi = bat_iterator(b); \
     428             :         const TPE *restrict vals = (const TPE *) bi.base; \
     429             :  \
     430             :         BATloop(b, p, q) { \
     431             :                 HIGH m = 0; \
     432             :                 TPE l = vals[p]; \
     433             :  \
     434             :                 if (!is_##TPE##_nil(l)) \
     435             :                         m = l; \
     436             :                 if (m > max) \
     437             :                         max = m; \
     438             :                 if (m < min) \
     439             :                         min = m; \
     440             :         } \
     441             :         bat_iterator_end(&bi); \
     442             :         if (-min > max / 10) { \
     443             :                 max = -min; \
     444             :                 ret++;          /* '-' */ \
     445             :         } \
     446             :         while (max /= 10) \
     447             :                 ret++; \
     448             :         ret++; \
     449             :         return ret; \
     450             : }
     451             : 
     452       19603 : bat_max_length(bte, lng)
     453      196269 : bat_max_length(sht, lng)
     454     2702447 : bat_max_length(int, lng)
     455     2150644 : bat_max_length(lng, lng)
     456             : #ifdef HAVE_HGE
     457      289448 : bat_max_length(hge, hge)
     458             : #endif
     459             : 
     460             : #define DEC_FRSTR(X)                                                                                                    \
     461             :         do {                                                                                                                            \
     462             :                 sql_column *col = c->extra;                                                                          \
     463             :                 sql_subtype *t = &col->type;                                                                     \
     464             :                 unsigned int scale = t->scale;                                                                       \
     465             :                 unsigned int i;                                                                                                 \
     466             :                 bool neg = false;                                                                                               \
     467             :                 X *r;                                                                                                                   \
     468             :                 X res = 0;                                                                                                              \
     469             :                 while(isspace((unsigned char) *s))                                                              \
     470             :                         s++;                                                                                                            \
     471             :                 if (*s == '-'){                                                                                                 \
     472             :                         neg = true;                                                                                                     \
     473             :                         s++;                                                                                                            \
     474             :                 } else if (*s == '+'){                                                                                  \
     475             :                         s++;                                                                                                            \
     476             :                 }                                                                                                                               \
     477             :                 for (i = 0; *s && *s != '.' && ((res == 0 && *s == '0') || i < t->digits - t->scale); s++) { \
     478             :                         if (!isdigit((unsigned char) *s))                                                       \
     479             :                                 break;                                                                                                  \
     480             :                         res *= 10;                                                                                                      \
     481             :                         res += (*s-'0');                                                                                        \
     482             :                         if (res)                                                                                                        \
     483             :                                 i++;                                                                                                    \
     484             :                 }                                                                                                                               \
     485             :                 if (*s == '.') {                                                                                                \
     486             :                         s++;                                                                                                            \
     487             :                         while (*s && isdigit((unsigned char) *s) && scale > 0) {     \
     488             :                                 res *= 10;                                                                                              \
     489             :                                 res += *s++ - '0';                                                                              \
     490             :                                 scale--;                                                                                                \
     491             :                         }                                                                                                                       \
     492             :                 }                                                                                                                               \
     493             :                 while(*s && isspace((unsigned char) *s))                                                \
     494             :                         s++;                                                                                                            \
     495             :                 while (scale > 0) {                                                                                          \
     496             :                         res *= 10;                                                                                                      \
     497             :                         scale--;                                                                                                        \
     498             :                 }                                                                                                                               \
     499             :                 if (*s)                                                                                                                 \
     500             :                         return NULL;                                                                                            \
     501             :                 r = c->data;                                                                                                 \
     502             :                 if (r == NULL &&                                                                                                \
     503             :                     (r = GDKzalloc(sizeof(X))) == NULL)                                                 \
     504             :                         return NULL;                                                                                            \
     505             :                 c->data = r;                                                                                                 \
     506             :                 if (neg)                                                                                                                \
     507             :                         *r = -res;                                                                                                      \
     508             :                 else                                                                                                                    \
     509             :                         *r = res;                                                                                                       \
     510             :                 return (void *) r;                                                                                              \
     511             :         } while (0)
     512             : 
     513             : static void *
     514    69444071 : dec_frstr(Column *c, int type, const char *s)
     515             : {
     516             :         /* support dec map to bte, sht, int and lng */
     517    69444071 :         if( strcmp(s,"nil")== 0)
     518             :                 return NULL;
     519    69444071 :         if (type == TYPE_bte) {
     520        8369 :                 DEC_FRSTR(bte);
     521    69441984 :         } else if (type == TYPE_sht) {
     522       21228 :                 DEC_FRSTR(sht);
     523    69438570 :         } else if (type == TYPE_int) {
     524   536614694 :                 DEC_FRSTR(int);
     525      322987 :         } else if (type == TYPE_lng) {
     526     2413966 :                 DEC_FRSTR(lng);
     527             : #ifdef HAVE_HGE
     528           0 :         } else if (type == TYPE_hge) {
     529           0 :                 DEC_FRSTR(hge);
     530             : #endif
     531             :         }
     532             :         return NULL;
     533             : }
     534             : 
     535             : static void *
     536         155 : sec_frstr(Column *c, int type, const char *s)
     537             : {
     538             :         /* read a sec_interval value
     539             :          * this knows that the stored scale is always 3 */
     540             :         unsigned int i, neg = 0;
     541             :         lng *r;
     542             :         lng res = 0;
     543             : 
     544             :         (void) c;
     545             :         (void) type;
     546         155 :         assert(type == TYPE_lng);
     547             : 
     548         155 :         if (*s == '-') {
     549             :                 neg = 1;
     550          10 :                 s++;
     551         145 :         } else if (*s == '+') {
     552             :                 neg = 0;
     553           0 :                 s++;
     554             :         }
     555        1201 :         for (i = 0; i < (19 - 3) && *s && *s != '.'; i++, s++) {
     556        1046 :                 if (!isdigit((unsigned char) *s))
     557             :                         return NULL;
     558        1046 :                 res *= 10;
     559        1046 :                 res += (*s - '0');
     560             :         }
     561             :         i = 0;
     562         155 :         if (*s) {
     563         135 :                 if (*s != '.')
     564             :                         return NULL;
     565         135 :                 s++;
     566         540 :                 for (; *s && i < 3; i++, s++) {
     567         405 :                         if (!isdigit((unsigned char) *s))
     568             :                                 return NULL;
     569         405 :                         res *= 10;
     570         405 :                         res += (*s - '0');
     571             :                 }
     572             :         }
     573         155 :         if (*s)
     574             :                 return NULL;
     575         215 :         for (; i < 3; i++) {
     576          60 :                 res *= 10;
     577             :         }
     578         155 :         r = c->data;
     579         155 :         if (r == NULL && (r = (lng *) GDKzalloc(sizeof(lng))) == NULL)
     580             :                 return NULL;
     581         155 :         c->data = r;
     582         155 :         if (neg)
     583          10 :                 *r = -res;
     584             :         else
     585         145 :                 *r = res;
     586             :         return (void *) r;
     587             : }
     588             : 
     589             : /* Literal parsing for SQL all pass through this routine */
     590             : static void *
     591   283265541 : _ASCIIadt_frStr(Column *c, int type, const char *s)
     592             : {
     593             :         ssize_t len;
     594             : 
     595   283265541 :         len = (*BATatoms[type].atomFromStr) (s, &c->len, &c->data, false);
     596   281537346 :         if (len < 0)
     597             :                 return NULL;
     598   281537333 :         switch (type) {
     599   255555476 :         case TYPE_bte:
     600             :         case TYPE_int:
     601             :         case TYPE_lng:
     602             :         case TYPE_sht:
     603             : #ifdef HAVE_HGE
     604             :         case TYPE_hge:
     605             : #endif
     606   255555476 :                 if (len == 0 || s[len]) {
     607             :                         /* decimals can be converted to integers when *.000 */
     608           8 :                         if (s[len++] == '.') {
     609          22 :                                 while (s[len] == '0')
     610          14 :                                         len++;
     611           8 :                                 if (s[len] == 0)
     612           4 :                                         return c->data;
     613             :                         }
     614             :                         return NULL;
     615             :                 }
     616             :                 break;
     617    23432162 :         case TYPE_str: {
     618    23432162 :                 sql_column *col = (sql_column *) c->extra;
     619             :                 int slen;
     620             : 
     621    23432162 :                 s = c->data;
     622    23432162 :                 slen = strNil(s) ? int_nil : UTF8_strlen(s);
     623    23416036 :                 if (col->type.digits > 0 && len > 0 && slen > (int) col->type.digits) {
     624           5 :                         len = STRwidth(c->data);
     625           5 :                         if (len > (ssize_t) col->type.digits)
     626             :                                 return NULL;
     627             :                 }
     628             :                 break;
     629             :         }
     630             :         default:
     631             :                 break;
     632             :         }
     633   281521194 :         return c->data;
     634             : }
     635             : 
     636             : 
     637             : static ssize_t
     638     9447031 : _ASCIIadt_toStr(void *extra, char **buf, size_t *len, int type, const void *a)
     639             : {
     640     9447031 :         if (type == TYPE_str) {
     641             :                 Column *c = extra;
     642             :                 char *dst;
     643             :                 const char *src = a;
     644     4806044 :                 size_t l = escapedStrlen(src, c->sep, c->rsep, c->quote), l2 = 0;
     645             : 
     646     4806044 :                 if (c->quote)
     647     4806044 :                         l = escapedStrlen(src, NULL, NULL, c->quote);
     648             :                 else
     649           0 :                         l = escapedStrlen(src, c->sep, c->rsep, 0);
     650     4806044 :                 if (l + 3 > *len) {
     651          52 :                         GDKfree(*buf);
     652          52 :                         *len = 2 * l + 3;
     653          52 :                         *buf = GDKzalloc(*len);
     654          52 :                         if (*buf == NULL) {
     655             :                                 return -1;
     656             :                         }
     657             :                 }
     658     4806044 :                 dst = *buf;
     659     4806044 :                 if (c->quote) {
     660     4806044 :                         dst[0] = c->quote;
     661             :                         l2 = 1;
     662     4806044 :                         l = escapedStr(dst + l2, src, *len - l2, NULL, NULL, c->quote);
     663             :                 } else {
     664           0 :                         l = escapedStr(dst + l2, src, *len - l2, c->sep, c->rsep, 0);
     665             :                 }
     666             :                 if (l2) {
     667     4806044 :                         dst[l + l2] = c->quote;
     668             :                         l2++;
     669             :                 }
     670     4806044 :                 dst[l + l2] = 0;
     671     4806044 :                 return l + l2;
     672             :         } else {
     673     4640987 :                 return (*BATatoms[type].atomToStr) (buf, len, a, true);
     674             :         }
     675             : }
     676             : 
     677             : 
     678             : static int
     679        9641 : has_whitespace(const char *s)
     680             : {
     681        9641 :         if (*s == ' ' || *s == '\t')
     682             :                 return 1;
     683        6656 :         while (*s)
     684        3339 :                 s++;
     685             :         s--;
     686        3317 :         if (*s == ' ' || *s == '\t')
     687           0 :                 return 1;
     688             :         return 0;
     689             : }
     690             : 
     691             : str
     692         975 : mvc_import_table(Client cntxt, BAT ***bats, mvc *m, bstream *bs, sql_table *t, const char *sep, const char *rsep, const char *ssep, const char *ns, lng sz, lng offset, int best, bool from_stdin, bool escape)
     693             : {
     694             :         int i = 0, j;
     695             :         node *n;
     696             :         Tablet as;
     697             :         Column *fmt;
     698             :         str msg = MAL_SUCCEED;
     699             : 
     700         975 :         *bats =0;       // initialize the receiver
     701             : 
     702         975 :         if (!bs)
     703           0 :                 throw(IO, "sql.copy_from", SQLSTATE(42000) "No stream (pointer) provided");
     704         975 :         if (mnstr_errnr(bs->s)) {
     705           0 :                 mnstr_error_kind errnr = mnstr_errnr(bs->s);
     706           0 :                 char *stream_msg = mnstr_error(bs->s);
     707           0 :                 msg = createException(IO, "sql.copy_from", SQLSTATE(42000) "Stream not open %s: %s", mnstr_error_kind_name(errnr), stream_msg ? stream_msg : "unknown error");
     708           0 :                 free(stream_msg);
     709           0 :                 return msg;
     710             :         }
     711         975 :         if (offset < 0 || offset > (lng) BUN_MAX)
     712           0 :                 throw(IO, "sql.copy_from", SQLSTATE(42000) "Offset out of range");
     713             : 
     714         975 :         if (offset > 0)
     715           7 :                 offset--;
     716         975 :         if (ol_first_node(t->columns)) {
     717         975 :                 stream *out = m->scanner.ws;
     718             : 
     719         975 :                 as = (Tablet) {
     720         975 :                         .nr_attrs = ol_length(t->columns),
     721         975 :                         .nr = (sz < 1) ? BUN_NONE : (BUN) sz,
     722         975 :                         .offset = (BUN) offset,
     723             :                         .error = NULL,
     724             :                         .tryall = 0,
     725             :                         .complaints = NULL,
     726         975 :                         .filename = m->scanner.rs == bs ? NULL : "",
     727             :                 };
     728         975 :                 fmt = GDKzalloc(sizeof(Column) * (as.nr_attrs + 1));
     729         975 :                 if (fmt == NULL)
     730           0 :                         throw(IO, "sql.copy_from", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     731         975 :                 as.format = fmt;
     732         975 :                 if (!isa_block_stream(bs->s))
     733             :                         out = NULL;
     734             : 
     735       10616 :                 for (n = ol_first_node(t->columns), i = 0; n; n = n->next, i++) {
     736        9641 :                         sql_column *col = n->data;
     737             : 
     738        9641 :                         fmt[i].name = col->base.name;
     739        9641 :                         fmt[i].sep = (n->next) ? sep : rsep;
     740        9641 :                         fmt[i].rsep = rsep;
     741        9641 :                         fmt[i].seplen = _strlen(fmt[i].sep);
     742        9641 :                         fmt[i].type = sql_subtype_string(m->ta, &col->type);
     743        9641 :                         fmt[i].adt = ATOMindex(col->type.type->impl);
     744        9641 :                         fmt[i].tostr = &_ASCIIadt_toStr;
     745        9641 :                         fmt[i].frstr = &_ASCIIadt_frStr;
     746        9641 :                         fmt[i].extra = col;
     747        9641 :                         fmt[i].len = ATOMlen(fmt[i].adt, ATOMnilptr(fmt[i].adt));
     748        9641 :                         fmt[i].data = GDKzalloc(fmt[i].len);
     749        9641 :                         if(fmt[i].data == NULL || fmt[i].type == NULL) {
     750           0 :                                 for (j = 0; j < i; j++) {
     751           0 :                                         GDKfree(fmt[j].data);
     752           0 :                                         BBPunfix(fmt[j].c->batCacheid);
     753             :                                 }
     754           0 :                                 GDKfree(fmt[i].data);
     755           0 :                                 throw(IO, "sql.copy_from", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     756             :                         }
     757        9641 :                         fmt[i].c = NULL;
     758        9641 :                         fmt[i].ws = !has_whitespace(fmt[i].sep);
     759        9641 :                         fmt[i].quote = ssep ? ssep[0] : 0;
     760        9641 :                         fmt[i].nullstr = ns;
     761        9641 :                         fmt[i].null_length = strlen(ns);
     762        9641 :                         fmt[i].nildata = ATOMnilptr(fmt[i].adt);
     763        9641 :                         fmt[i].skip = (col->base.name[0] == '%');
     764        9641 :                         if (col->type.type->eclass == EC_DEC) {
     765         332 :                                 fmt[i].tostr = &dec_tostr;
     766         332 :                                 fmt[i].frstr = &dec_frstr;
     767        9309 :                         } else if (col->type.type->eclass == EC_SEC) {
     768          63 :                                 fmt[i].tostr = &dec_tostr;
     769          63 :                                 fmt[i].frstr = &sec_frstr;
     770             :                         }
     771        9641 :                         fmt[i].size = ATOMsize(fmt[i].adt);
     772             :                 }
     773        1909 :                 if ((msg = TABLETcreate_bats(&as, (BUN) (sz < 0 ? 1000 : sz))) == MAL_SUCCEED){
     774         975 :                         if (!sz || (SQLload_file(cntxt, &as, bs, out, sep, rsep, ssep ? ssep[0] : 0, offset, sz, best, from_stdin, t->base.name, escape) != BUN_NONE &&
     775         939 :                                 (best || !as.error))) {
     776         950 :                                 *bats = (BAT**) GDKzalloc(sizeof(BAT *) * as.nr_attrs);
     777         950 :                                 if ( *bats == NULL){
     778           0 :                                         TABLETdestroy_format(&as);
     779           0 :                                         throw(IO, "sql.copy_from", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     780             :                                 }
     781         950 :                                 msg = TABLETcollect(*bats,&as);
     782             :                         }
     783             :                 }
     784         975 :                 if (as.error) {
     785          30 :                         if( !best) msg = createException(SQL, "sql.copy_from", SQLSTATE(42000) "Failed to import table '%s', %s", t->base.name, getExceptionMessage(as.error));
     786          30 :                         freeException(as.error);
     787          30 :                         as.error = NULL;
     788             :                 }
     789       10616 :                 for (n = ol_first_node(t->columns), i = 0; n; n = n->next, i++) {
     790        9641 :                         fmt[i].sep = NULL;
     791        9641 :                         fmt[i].rsep = NULL;
     792        9641 :                         fmt[i].nullstr = NULL;
     793             :                 }
     794         975 :                 TABLETdestroy_format(&as);
     795             :         }
     796             :         return msg;
     797             : }
     798             : 
     799             : /*
     800             :  * mvc_export_result dumps the sql header information and the
     801             :  * first part (reply_size) of the result set. It should be produced in Monet format to
     802             :  * enable mapi to work with it.
     803             :  */
     804             : 
     805             : static int
     806      115201 : mvc_export_warning(stream *s, str w)
     807             : {
     808             :         str tmp = NULL;
     809      115201 :         while (w != NULL && *w != '\0') {
     810           0 :                 if ((tmp = strchr(w, (int) '\n')) != NULL)
     811           0 :                         *tmp++ = '\0';
     812           0 :                 if (mnstr_printf(s, "#%s", w) < 0)
     813             :                         return -4;
     814             :                 w = tmp;
     815             :         }
     816             :         return 1;
     817             : }
     818             : 
     819             : static int
     820           2 : mvc_export_binary_bat(stream *s, BAT* bn)
     821             : {
     822           2 :         bool sendtheap = bn->ttype != TYPE_void, sendtvheap = sendtheap && bn->tvarsized;
     823             : 
     824           5 :         if (mnstr_printf(s, /*JSON*/"{"
     825             :                 "\"version\":1,"
     826             :                 "\"ttype\":%d,"
     827             :                 "\"hseqbase\":" OIDFMT ","
     828             :                 "\"tseqbase\":" OIDFMT ","
     829             :                 "\"tsorted\":%d,"
     830             :                 "\"trevsorted\":%d,"
     831             :                 "\"tkey\":%d,"
     832             :                 "\"tnonil\":%d,"
     833             :                 "\"tdense\":%d,"
     834             :                 "\"size\":" BUNFMT ","
     835             :                 "\"tailsize\":%zu,"
     836             :                 "\"theapsize\":%zu"
     837             :                 "}\n",
     838             :                 bn->ttype,
     839             :                 bn->hseqbase, bn->tseqbase,
     840           2 :                 bn->tsorted, bn->trevsorted,
     841           2 :                 bn->tkey,
     842           2 :                 bn->tnonil,
     843           2 :                 BATtdense(bn),
     844             :                 bn->batCount,
     845           2 :                 sendtheap ? (size_t)bn->batCount << bn->tshift : 0,
     846           1 :                 sendtvheap && bn->batCount > 0 ? bn->tvheap->free : 0) < 0)
     847             :                 return -4;
     848             : 
     849           2 :         if (sendtheap && bn->batCount > 0) {
     850           2 :                 BATiter bni = bat_iterator(bn);
     851           2 :                 if (mnstr_write(s, /* tail */ bni.base, bni.count * bni.width, 1) < 1) {
     852           0 :                         bat_iterator_end(&bni);
     853           0 :                         return -4;
     854             :                 }
     855           2 :                 if (sendtvheap && mnstr_write(s, /* tvheap */ bni.vh->base, bni.vh->free, 1) < 1) {
     856           0 :                         bat_iterator_end(&bni);
     857           0 :                         return -4;
     858             :                 }
     859           2 :                 bat_iterator_end(&bni);
     860             :         }
     861             :         return 0;
     862             : }
     863             : 
     864             : static int
     865         302 : create_prepare_result(backend *b, cq *q, int nrows)
     866             : {
     867             :         int error = 0;
     868             : 
     869         302 :         BAT* btype              = COLnew(0, TYPE_str, nrows, TRANSIENT);
     870         302 :         BAT* bimpl              = COLnew(0, TYPE_str, nrows, TRANSIENT);
     871         302 :         BAT* bdigits    = COLnew(0, TYPE_int, nrows, TRANSIENT);
     872         302 :         BAT* bscale             = COLnew(0, TYPE_int, nrows, TRANSIENT);
     873         302 :         BAT* bschema    = COLnew(0, TYPE_str, nrows, TRANSIENT);
     874         302 :         BAT* btable             = COLnew(0, TYPE_str, nrows, TRANSIENT);
     875         302 :         BAT* bcolumn    = COLnew(0, TYPE_str, nrows, TRANSIENT);
     876             :         BAT* order              = NULL;
     877             :         node *n;
     878             : 
     879         302 :         const int nr_columns = (b->client->protocol == PROTOCOL_COLUMNAR || GDKembedded()) ? 7 : 6;
     880             : 
     881             :         int len1 = 0, len4 = 0, len5 = 0, len6 = 0, len7 =0;    /* column widths */
     882             :         int len2 = 1, len3 = 1;
     883             :         sql_arg *a;
     884             :         sql_subtype *t;
     885         302 :         sql_rel *r = q->rel;
     886             : 
     887         302 :         if (!btype || !bdigits || !bscale || !bschema || !btable || !bcolumn) {
     888             :                 error = -1;
     889           0 :                 goto wrapup;
     890             :         }
     891             : 
     892         302 :         if (r && (is_topn(r->op) || is_sample(r->op)))
     893           0 :                 r = r->l;
     894         302 :         if (r && is_project(r->op) && r->exps) {
     895             :                 unsigned int max2 = 10, max3 = 10;      /* to help calculate widths */
     896         273 :                 nrows += list_length(r->exps);
     897             : 
     898         782 :                 for (n = r->exps->h; n; n = n->next) {
     899             :                         const char *name = NULL, *rname = NULL, *schema = NULL;
     900         509 :                         sql_exp *e = n->data;
     901             :                         int slen;
     902             : 
     903         509 :                         t = exp_subtype(e);
     904         509 :                         slen = (int) strlen(t->type->base.name);
     905             :                         if (slen > len1)
     906             :                                 len1 = slen;
     907         591 :                         while (t->digits >= max2) {
     908          82 :                                 len2++;
     909          82 :                                 max2 *= 10;
     910             :                         }
     911         510 :                         while (t->scale >= max3) {
     912           1 :                                 len3++;
     913           1 :                                 max3 *= 10;
     914             :                         }
     915         509 :                         rname = exp_relname(e);
     916         509 :                         if (!rname && e->type == e_column && e->l)
     917             :                                 rname = e->l;
     918             :                         slen = name ? (int) strlen(name) : 0;
     919             :                         if (slen > len5)
     920             :                                 len5 = slen;
     921         509 :                         name = exp_name(e);
     922         509 :                         if (!name && e->type == e_column && e->r)
     923             :                                 name = e->r;
     924         509 :                         slen = name ? (int) strlen(name) : 0;
     925             :                         if (slen > len6)
     926             :                                 len6 = slen;
     927         509 :                         slen = (int) strlen(t->type->impl);
     928             :                         if (slen > len7)
     929             :                                 len7 = slen;
     930             : 
     931             :                         if (!schema)
     932             :                                 schema = "";
     933             : 
     934         509 :                         if (!rname)
     935             :                                 rname = "";
     936             : 
     937         509 :                         if (!name)
     938             :                                 name = "";
     939             : 
     940        1018 :                         if (    BUNappend(btype,        t->type->base.name        , false) != GDK_SUCCEED ||
     941        1018 :                                         BUNappend(bimpl,        t->type->impl             , false) != GDK_SUCCEED ||
     942        1018 :                                         BUNappend(bdigits,      &t->digits                       , false) != GDK_SUCCEED ||
     943        1018 :                                         BUNappend(bscale,       &t->scale                        , false) != GDK_SUCCEED ||
     944        1018 :                                         BUNappend(bschema,      schema                          , false) != GDK_SUCCEED ||
     945        1018 :                                         BUNappend(btable,       rname                           , false) != GDK_SUCCEED ||
     946         509 :                                         BUNappend(bcolumn,      name                            , false) != GDK_SUCCEED) {
     947             :                                 error = -3;
     948           0 :                                 goto wrapup;
     949             :                         }
     950             :                 }
     951             :         }
     952             : 
     953         302 :         if (q->f->ops) {
     954             :                 int i;
     955             : 
     956         739 :                 for (n = q->f->ops->h, i = 0; n; n = n->next, i++) {
     957         522 :                         a = n->data;
     958             :                         t = &a->type;
     959             : 
     960        1044 :                         if (    BUNappend(btype,        t->type->base.name        , false) != GDK_SUCCEED ||
     961        1044 :                                         BUNappend(bimpl,        t->type->impl             , false) != GDK_SUCCEED ||
     962        1044 :                                         BUNappend(bdigits,      &t->digits                       , false) != GDK_SUCCEED ||
     963        1044 :                                         BUNappend(bscale,       &t->scale                        , false) != GDK_SUCCEED ||
     964        1044 :                                         BUNappend(bschema,      str_nil                         , false) != GDK_SUCCEED ||
     965        1044 :                                         BUNappend(btable,       str_nil                         , false) != GDK_SUCCEED ||
     966         522 :                                         BUNappend(bcolumn,      str_nil                         , false) != GDK_SUCCEED) {
     967             :                                 error = -3;
     968           0 :                                 goto wrapup;
     969             :                         }
     970             :                 }
     971             :         }
     972             : 
     973             :         // A little hack to inform the result receiver of the name of the compiled mal program.
     974         302 :         if (b->client->protocol == PROTOCOL_COLUMNAR) {
     975           0 :                 if (    BUNappend(btype,        str_nil         , false) != GDK_SUCCEED ||
     976           0 :                                 BUNappend(bimpl,        str_nil         , false) != GDK_SUCCEED ||
     977           0 :                                 BUNappend(bdigits,      &int_nil    , false) != GDK_SUCCEED ||
     978           0 :                                 BUNappend(bscale,       &int_nil    , false) != GDK_SUCCEED ||
     979           0 :                                 BUNappend(bschema,      str_nil         , false) != GDK_SUCCEED ||
     980           0 :                                 BUNappend(btable,       q->f->imp , false) != GDK_SUCCEED ||
     981           0 :                                 BUNappend(bcolumn,      str_nil         , false) != GDK_SUCCEED) {
     982             :                         error = -3;
     983           0 :                         goto wrapup;
     984             :                 }
     985             :         }
     986             : 
     987         302 :         if (!(order = BATdense(0, 0, BATcount(btype)))) {
     988             :                 error = -1;
     989           0 :                 goto wrapup;
     990             :         }
     991           0 :         b->results = res_table_create(
     992         302 :                                                         b->mvc->session->tr,
     993         302 :                                                         b->result_id++,
     994         302 :                                                         b->mb? b->mb->tag: 0 /*TODO check if this is sensible*/,
     995             :                                                         nr_columns,
     996             :                                                         Q_PREPARE,
     997             :                                                         b->results,
     998             :                                                         order);
     999         302 :         if (!b->results) {
    1000             :                 error = -1;
    1001           0 :                 goto wrapup;
    1002             :         }
    1003             : 
    1004         604 :         if (    mvc_result_column(b, ".prepare", "type"             , "varchar",  len1, 0, btype  ) ||
    1005         604 :                         mvc_result_column(b, ".prepare", "digits"   , "int",              len2, 0, bdigits) ||
    1006         604 :                         mvc_result_column(b, ".prepare", "scale"    , "int",              len3, 0, bscale ) ||
    1007         604 :                         mvc_result_column(b, ".prepare", "schema"   , "varchar",  len4, 0, bschema) ||
    1008         604 :                         mvc_result_column(b, ".prepare", "table"    , "varchar",  len5, 0, btable ) ||
    1009         302 :                         mvc_result_column(b, ".prepare", "column"   , "varchar",  len6, 0, bcolumn)) {
    1010             :                 error = -1;
    1011           0 :                 goto wrapup;
    1012             :         }
    1013             : 
    1014         302 :         if ((b->client->protocol == PROTOCOL_COLUMNAR || GDKembedded()) && mvc_result_column(b, "prepare", "impl" , "varchar", len7, 0, bimpl))
    1015             :                 error = -1;
    1016             : 
    1017         302 :         wrapup:
    1018         302 :                 if (btype)
    1019         302 :                         BBPunfix(btype->batCacheid);
    1020         302 :                 if (bdigits)
    1021         302 :                         BBPunfix(bdigits->batCacheid);
    1022         302 :                 if (bimpl)
    1023         302 :                         BBPunfix(bimpl->batCacheid);
    1024         302 :                 if (bscale)
    1025         302 :                         BBPunfix(bscale->batCacheid);
    1026         302 :                 if (bschema)
    1027         302 :                         BBPunfix(bschema->batCacheid);
    1028         302 :                 if (btable)
    1029         302 :                         BBPunfix(btable->batCacheid);
    1030         302 :                 if (bcolumn)
    1031         302 :                         BBPunfix(bcolumn->batCacheid);
    1032         302 :                 if (error < 0 && b->results) {
    1033           0 :                         res_table_destroy(b->results);
    1034           0 :                         b->results = NULL;
    1035         302 :                 } else if (order)
    1036         302 :                         BBPunfix(order->batCacheid);
    1037         302 :                 return error;
    1038             : }
    1039             : 
    1040             : int
    1041         302 : mvc_export_prepare(backend *b, stream *out)
    1042             : {
    1043         302 :         cq *q = b->q;
    1044         302 :         int nparam = q->f->ops ? list_length(q->f->ops) : 0;
    1045             :         int nrows = nparam, res;
    1046             : 
    1047         302 :         if ((res = create_prepare_result(b, q, nrows)) < 0)
    1048             :                 return res;
    1049             : 
    1050         302 :         return mvc_export_result(b, out, b->results->id /*TODO is this right?*/, true, 0 /*TODO*/, 0 /*TODO*/);
    1051             : }
    1052             : 
    1053             : /*
    1054             :  * improved formatting of positive integers
    1055             :  */
    1056             : 
    1057             : static ssize_t
    1058           0 : mvc_send_bte(stream *s, bte cnt)
    1059             : {
    1060             :         char buf[50], *b;
    1061             :         int neg = cnt < 0;
    1062           0 :         if (neg)
    1063           0 :                 cnt = -cnt;
    1064             :         b = buf + 49;
    1065             :         do {
    1066           0 :                 *b-- = (char) ('0' + (cnt % 10));
    1067           0 :                 cnt /= 10;
    1068           0 :         } while (cnt > 0);
    1069           0 :         if (neg)
    1070           0 :                 *b = '-';
    1071             :         else
    1072             :                 b++;
    1073           0 :         return mnstr_write(s, b, 50 - (b - buf), 1);
    1074             : }
    1075             : 
    1076             : static ssize_t
    1077           0 : mvc_send_sht(stream *s, sht cnt)
    1078             : {
    1079             :         char buf[50], *b;
    1080             :         int neg = cnt < 0;
    1081           0 :         if (neg)
    1082           0 :                 cnt = -cnt;
    1083             :         b = buf + 49;
    1084             :         do {
    1085           0 :                 *b-- = (char) ('0' + (cnt % 10));
    1086           0 :                 cnt /= 10;
    1087           0 :         } while (cnt > 0);
    1088           0 :         if (neg)
    1089           0 :                 *b = '-';
    1090             :         else
    1091             :                 b++;
    1092           0 :         return mnstr_write(s, b, 50 - (b - buf), 1);
    1093             : }
    1094             : 
    1095             : static ssize_t
    1096      325118 : mvc_send_int(stream *s, int cnt)
    1097             : {
    1098             :         char buf[50], *b;
    1099             :         int neg = cnt < 0;
    1100             :         if (neg)
    1101             :                 cnt = -cnt;
    1102             :         b = buf + 49;
    1103             :         do {
    1104      504775 :                 *b-- = (char) ('0' + (cnt % 10));
    1105      504775 :                 cnt /= 10;
    1106      504775 :         } while (cnt > 0);
    1107      325118 :         if (neg)
    1108           0 :                 *b = '-';
    1109             :         else
    1110             :                 b++;
    1111      325118 :         return mnstr_write(s, b, 50 - (b - buf), 1);
    1112             : }
    1113             : 
    1114             : static ssize_t
    1115      779954 : mvc_send_lng(stream *s, lng cnt)
    1116             : {
    1117             :         char buf[50], *b;
    1118             :         int neg = cnt < 0;
    1119             :         if (neg)
    1120             :                 cnt = -cnt;
    1121             :         b = buf + 49;
    1122             :         do {
    1123     1682297 :                 *b-- = (char) ('0' + (cnt % 10));
    1124     1682297 :                 cnt /= 10;
    1125     1682297 :         } while (cnt > 0);
    1126      779954 :         if (neg)
    1127       13269 :                 *b = '-';
    1128             :         else
    1129             :                 b++;
    1130      779954 :         return mnstr_write(s, b, 50 - (b - buf), 1);
    1131             : }
    1132             : 
    1133             : #ifdef HAVE_HGE
    1134             : static ssize_t
    1135           0 : mvc_send_hge(stream *s, hge cnt)
    1136             : {
    1137             :         char buf[50], *b;
    1138             :         int neg = cnt <0;
    1139             :         if(neg) cnt = -cnt;
    1140             :         b= buf+49;
    1141             :         do{
    1142           0 :                 *b--= (char) ('0'+ (cnt % 10));
    1143           0 :                 cnt /=10;
    1144           0 :         } while(cnt>0);
    1145           0 :         if( neg)
    1146           0 :                 *b = '-';
    1147             :         else b++;
    1148           0 :         return mnstr_write(s, b, 50 - (b - buf), 1);
    1149             : }
    1150             : #endif
    1151             : 
    1152             : ssize_t
    1153     1903066 : convert2str(mvc *m, sql_class eclass, int d, int sc, int has_tz, ptr p, int mtype, char **buf, size_t *len)
    1154             : {
    1155             :         ssize_t l = 0;
    1156             : 
    1157     1903066 :         if (!p || ATOMcmp(mtype, ATOMnilptr(mtype), p) == 0) {
    1158       20198 :                 (*buf)[0] = '\200';
    1159       20198 :                 (*buf)[1] = 0;
    1160     1869453 :         } else if (eclass == EC_DEC) {
    1161         185 :                 l = dec_tostr((void *) (ptrdiff_t) sc, buf, len, mtype, p);
    1162     1869268 :         } else if (eclass == EC_TIME || eclass == EC_TIME_TZ) {
    1163             :                 struct time_res ts_res;
    1164          74 :                 ts_res.has_tz = has_tz;
    1165          74 :                 ts_res.fraction = d ? d - 1 : 0;
    1166          74 :                 ts_res.timezone = m->timezone;
    1167          74 :                 l = sql_time_tostr((void *) &ts_res, buf, len, mtype, p);
    1168     1869194 :         } else if (eclass == EC_TIMESTAMP || eclass == EC_TIMESTAMP_TZ) {
    1169             :                 struct time_res ts_res;
    1170          79 :                 ts_res.has_tz = has_tz;
    1171          79 :                 ts_res.fraction = d ? d - 1 : 0;
    1172          79 :                 ts_res.timezone = m->timezone;
    1173          79 :                 l = sql_timestamp_tostr((void *) &ts_res, buf, len, mtype, p);
    1174     1869115 :         } else if (eclass == EC_SEC) {
    1175          26 :                 l = dec_tostr((void *) (ptrdiff_t) 3, buf, len, mtype, p);
    1176     1869089 :         } else if (eclass == EC_BIT) {
    1177         947 :                 bit b = *(bit *) p;
    1178         947 :                 if (*len == 0 || *len > 5) {
    1179         919 :                         if (b) {
    1180         864 :                                 strcpy(*buf, "true");
    1181             :                                 l = 4;
    1182             :                         } else {
    1183          55 :                                 strcpy(*buf, "false");
    1184             :                                 l = 5;
    1185             :                         }
    1186             :                 } else {
    1187          28 :                         (*buf)[0] = b?'t':'f';
    1188          28 :                         (*buf)[1] = 0;
    1189             :                         l = 1;
    1190             :                 }
    1191             :         } else {
    1192     1868142 :                 l = (*BATatoms[mtype].atomToStr) (buf, len, p, false);
    1193             :         }
    1194     1988596 :         return l;
    1195             : }
    1196             : 
    1197             : static int
    1198           0 : export_value(mvc *m, stream *s, sql_class eclass, const char *sqlname, int d, int sc, ptr p, int mtype, char **buf, size_t *len, const char *ns)
    1199             : {
    1200             :         int ok = 0;
    1201             :         ssize_t l = 0;
    1202             : 
    1203           0 :         if (!p || ATOMcmp(mtype, ATOMnilptr(mtype), p) == 0) {
    1204           0 :                 if (mnstr_write(s, ns, strlen(ns), 1) < 1)
    1205             :                         ok = -4;
    1206           0 :         } else if (eclass == EC_DEC) {
    1207           0 :                 l = dec_tostr((void *) (ptrdiff_t) sc, buf, len, mtype, p);
    1208           0 :                 if (l > 0 && mnstr_write(s, *buf, l, 1) < 1)
    1209             :                         ok = -4;
    1210           0 :         } else if (eclass == EC_TIME || eclass == EC_TIME_TZ) {
    1211             :                 struct time_res ts_res;
    1212           0 :                 ts_res.has_tz = (strcmp(sqlname, "timetz") == 0);
    1213           0 :                 ts_res.fraction = d ? d - 1 : 0;
    1214           0 :                 ts_res.timezone = m->timezone;
    1215           0 :                 l = sql_time_tostr((void *) &ts_res, buf, len, mtype, p);
    1216           0 :                 if (l >= 0 && mnstr_write(s, *buf, l, 1) < 1)
    1217             :                         ok = -4;
    1218           0 :         } else if (eclass == EC_TIMESTAMP || eclass == EC_TIMESTAMP_TZ) {
    1219             :                 struct time_res ts_res;
    1220           0 :                 ts_res.has_tz = (strcmp(sqlname, "timestamptz") == 0);
    1221           0 :                 ts_res.fraction = d ? d - 1 : 0;
    1222           0 :                 ts_res.timezone = m->timezone;
    1223           0 :                 l = sql_timestamp_tostr((void *) &ts_res, buf, len, mtype, p);
    1224           0 :                 if (l >= 0 && mnstr_write(s, *buf, l, 1) < 1)
    1225             :                         ok = -4;
    1226           0 :         } else if (eclass == EC_SEC) {
    1227           0 :                 l = dec_tostr((void *) (ptrdiff_t) 3, buf, len, mtype, p);
    1228           0 :                 if (l >= 0 && mnstr_write(s, *buf, l, 1) < 1)
    1229             :                         ok = -4;
    1230             :         } else {
    1231           0 :                 switch (mtype) {
    1232           0 :                 case TYPE_bte:
    1233           0 :                         if (mvc_send_bte(s, *(bte *) p) < 1)
    1234             :                                 ok = -4;
    1235             :                         break;
    1236           0 :                 case TYPE_sht:
    1237           0 :                         if (mvc_send_sht(s, *(sht *) p) < 1)
    1238             :                                 ok = -4;
    1239             :                         break;
    1240           0 :                 case TYPE_int:
    1241           0 :                         if (mvc_send_int(s, *(int *) p) < 1)
    1242             :                                 ok = -4;
    1243             :                         break;
    1244           0 :                 case TYPE_lng:
    1245           0 :                         if (mvc_send_lng(s, *(lng *) p) < 1)
    1246             :                                 ok = -4;
    1247             :                         break;
    1248             : #ifdef HAVE_HGE
    1249           0 :                 case TYPE_hge:
    1250           0 :                         if (mvc_send_hge(s, *(hge *) p) < 1)
    1251             :                                 ok = -4;
    1252             :                         break;
    1253             : #endif
    1254           0 :                 default:
    1255           0 :                         l = (*BATatoms[mtype].atomToStr) (buf, len, p, true);
    1256           0 :                         if (l >= 0 && mnstr_write(s, *buf, l, 1) < 1)
    1257             :                                 ok = -4;
    1258             :                 }
    1259             :         }
    1260           0 :         return ok;
    1261             : }
    1262             : 
    1263             : static int
    1264           0 : mvc_export_row(backend *b, stream *s, res_table *t, const char *btag, const char *sep, const char *rsep, const char *ssep, const char *ns)
    1265             : {
    1266           0 :         mvc *m = b->mvc;
    1267           0 :         size_t seplen = strlen(sep);
    1268           0 :         size_t rseplen = strlen(rsep);
    1269           0 :         char *buf = NULL;
    1270           0 :         size_t len = 0;
    1271             :         int i, ok = 1;
    1272           0 :         int csv = (b->output_format == OFMT_CSV);
    1273             :         int json = (b->output_format == OFMT_JSON);
    1274             : 
    1275           0 :         if (!s || !t)
    1276             :                 return 0;
    1277             : 
    1278             :         (void) ssep;
    1279           0 :         if (csv && btag[0] && mnstr_write(s, btag, strlen(btag), 1) < 1)
    1280             :                 ok = -4;
    1281           0 :         if (json) {
    1282             :                 sep = ", ";
    1283             :                 seplen = strlen(sep);
    1284             :         }
    1285           0 :         for (i = 0; i < t->nr_cols && ok > -1; i++) {
    1286           0 :                 res_col *c = t->cols + i;
    1287             : 
    1288           0 :                 if (i != 0 && mnstr_write(s, sep, seplen, 1) < 1) {
    1289             :                         ok = -4;
    1290             :                         break;
    1291             :                 }
    1292           0 :                 if (json && (mnstr_write(s, c->name, strlen(c->name), 1) < 1 || mnstr_write(s, ": ", 2, 1) < 1)) {
    1293             :                         ok = -4;
    1294             :                         break;
    1295             :                 }
    1296           0 :                 ok = export_value(m, s, c->type.type->eclass, c->type.type->base.name, c->type.digits, c->type.scale, c->p, c->mtype, &buf, &len, ns);
    1297             :         }
    1298           0 :         _DELETE(buf);
    1299           0 :         if (ok > -1 && mnstr_write(s, rsep, rseplen, 1) < 1)
    1300             :                 ok = -4;
    1301           0 :         b->results = res_tables_remove(b->results, t);
    1302           0 :         return ok;
    1303             : }
    1304             : 
    1305             : static int
    1306           1 : mvc_export_table_columnar(stream *s, res_table *t)
    1307             : {
    1308             :         int i, res = 0;
    1309             : 
    1310           1 :         if (!s || !t)
    1311             :                 return 0;
    1312             : 
    1313           3 :         for (i = 1; i <= t->nr_cols; i++) {
    1314           2 :                 res_col *c = t->cols + (i - 1);
    1315             : 
    1316           2 :                 if (!c->b)
    1317             :                         break;
    1318             : 
    1319           2 :                 BAT *b = BATdescriptor(c->b);
    1320           2 :                 if (b == NULL)
    1321             :                         return -2;
    1322             : 
    1323           2 :                 res = mvc_export_binary_bat(s, b);
    1324           2 :                 BBPunfix(b->batCacheid);
    1325           2 :                 if (res < 0)
    1326           0 :                         return res;
    1327             :         }
    1328             : 
    1329             :         return res;
    1330             : }
    1331             : 
    1332             : static int
    1333       85024 : mvc_export_table_(mvc *m, int output_format, stream *s, res_table *t, BAT *order, BUN offset, BUN nr, const char *btag, const char *sep, const char *rsep, const char *ssep, const char *ns)
    1334             : {
    1335             :         Tablet as;
    1336             :         Column *fmt;
    1337             :         int i, ok = 0;
    1338             :         struct time_res *tres;
    1339             :         int csv = (output_format == OFMT_CSV);
    1340             :         int json = (output_format == OFMT_JSON);
    1341             :         char *bj;
    1342             : 
    1343       85024 :         if (!s || !t)
    1344             :                 return 0;
    1345             : 
    1346       85024 :         as.nr_attrs = t->nr_cols + 1;        /* for the leader */
    1347       85024 :         as.nr = nr;
    1348       85024 :         as.offset = offset;
    1349       85024 :         fmt = as.format = (Column *) GDKzalloc(sizeof(Column) * (as.nr_attrs + 1));
    1350       85024 :         tres = GDKzalloc(sizeof(struct time_res) * (as.nr_attrs));
    1351       85024 :         if (fmt == NULL || tres == NULL) {
    1352           0 :                 GDKfree(fmt);
    1353           0 :                 GDKfree(tres);
    1354           0 :                 return -4;
    1355             :         }
    1356             : 
    1357       85024 :         fmt[0].c = NULL;
    1358       85024 :         fmt[0].sep = (csv) ? btag : "";
    1359       85024 :         fmt[0].rsep = rsep;
    1360       85024 :         fmt[0].seplen = _strlen(fmt[0].sep);
    1361       85024 :         fmt[0].ws = 0;
    1362       85024 :         fmt[0].nullstr = NULL;
    1363             : 
    1364      382027 :         for (i = 1; i <= t->nr_cols; i++) {
    1365      297003 :                 res_col *c = t->cols + (i - 1);
    1366             : 
    1367      297003 :                 if (!c->b)
    1368             :                         break;
    1369             : 
    1370      297003 :                 fmt[i].c = BATdescriptor(c->b);
    1371      297003 :                 if (fmt[i].c == NULL) {
    1372           0 :                         while (--i >= 1)
    1373           0 :                                 BBPunfix(fmt[i].c->batCacheid);
    1374           0 :                         GDKfree(fmt);
    1375           0 :                         GDKfree(tres);
    1376           0 :                         return -2;
    1377             :                 }
    1378      297003 :                 fmt[i].ci = bat_iterator(fmt[i].c);
    1379      297003 :                 fmt[i].name = NULL;
    1380      297003 :                 if (csv) {
    1381      297003 :                         fmt[i].sep = ((i - 1) < (t->nr_cols - 1)) ? sep : rsep;
    1382      297003 :                         fmt[i].seplen = _strlen(fmt[i].sep);
    1383      297003 :                         fmt[i].rsep = rsep;
    1384             :                 }
    1385      297003 :                 if (json) {
    1386           0 :                         res_col *p = t->cols + (i - 1);
    1387             : 
    1388             :                         /*
    1389             :                          * We define the "proper" way of returning
    1390             :                          * a relational table in json format as a
    1391             :                          * json array of objects, where each row is
    1392             :                          * represented as a json object.
    1393             :                          */
    1394           0 :                         if (i == 1) {
    1395           0 :                                 bj = SA_NEW_ARRAY(m->sa, char, strlen(p->name) + strlen(btag));
    1396           0 :                                 snprintf(bj, strlen(p->name) + strlen(btag), btag, p->name);
    1397           0 :                                 fmt[i - 1].sep = bj;
    1398           0 :                                 fmt[i - 1].seplen = _strlen(fmt[i - 1].sep);
    1399           0 :                                 fmt[i - 1].rsep = NULL;
    1400           0 :                         } else if (i <= t->nr_cols) {
    1401           0 :                                 bj = SA_NEW_ARRAY(m->sa, char, strlen(p->name) + strlen(sep));
    1402           0 :                                 snprintf(bj, strlen(p->name) + 10, sep, p->name);
    1403           0 :                                 fmt[i - 1].sep = bj;
    1404           0 :                                 fmt[i - 1].seplen = _strlen(fmt[i - 1].sep);
    1405           0 :                                 fmt[i - 1].rsep = NULL;
    1406             :                         }
    1407           0 :                         if (i == t->nr_cols) {
    1408           0 :                                 fmt[i].sep = rsep;
    1409           0 :                                 fmt[i].seplen = _strlen(fmt[i].sep);
    1410           0 :                                 fmt[i].rsep = NULL;
    1411             :                         }
    1412             :                 }
    1413      297003 :                 fmt[i].type = ATOMname(fmt[i].c->ttype);
    1414      297003 :                 fmt[i].adt = fmt[i].c->ttype;
    1415      297003 :                 fmt[i].tostr = &_ASCIIadt_toStr;
    1416      297003 :                 fmt[i].frstr = &_ASCIIadt_frStr;
    1417      297003 :                 fmt[i].extra = fmt + i;
    1418      297003 :                 fmt[i].data = NULL;
    1419      297003 :                 fmt[i].len = 0;
    1420      297003 :                 fmt[i].ws = 0;
    1421      297003 :                 fmt[i].quote = ssep ? ssep[0] : 0;
    1422      297003 :                 fmt[i].nullstr = ns;
    1423      297003 :                 if (c->type.type->eclass == EC_DEC) {
    1424        1685 :                         fmt[i].tostr = &dec_tostr;
    1425        1685 :                         fmt[i].frstr = &dec_frstr;
    1426        1685 :                         fmt[i].extra = (void *) (ptrdiff_t) c->type.scale;
    1427      295318 :                 } else if (c->type.type->eclass == EC_TIMESTAMP || c->type.type->eclass == EC_TIMESTAMP_TZ) {
    1428         899 :                         struct time_res *ts_res = tres + (i - 1);
    1429         899 :                         ts_res->has_tz = EC_TEMP_TZ(c->type.type->eclass);
    1430         899 :                         ts_res->fraction = c->type.digits ? c->type.digits - 1 : 0;
    1431         899 :                         ts_res->timezone = m->timezone;
    1432             : 
    1433         899 :                         fmt[i].tostr = &sql_timestamp_tostr;
    1434         899 :                         fmt[i].frstr = NULL;
    1435         899 :                         fmt[i].extra = ts_res;
    1436      294419 :                 } else if (c->type.type->eclass == EC_TIME || c->type.type->eclass == EC_TIME_TZ) {
    1437         241 :                         struct time_res *ts_res = tres + (i - 1);
    1438         241 :                         ts_res->has_tz = (strcmp(c->type.type->base.name, "timetz") == 0);
    1439         241 :                         ts_res->fraction = c->type.digits ? c->type.digits - 1 : 0;
    1440         241 :                         ts_res->timezone = m->timezone;
    1441             : 
    1442         241 :                         fmt[i].tostr = &sql_time_tostr;
    1443         241 :                         fmt[i].frstr = NULL;
    1444         241 :                         fmt[i].extra = ts_res;
    1445      294178 :                 } else if (c->type.type->eclass == EC_SEC) {
    1446         376 :                         fmt[i].tostr = &dec_tostr;
    1447         376 :                         fmt[i].frstr = &sec_frstr;
    1448         376 :                         fmt[i].extra = (void *) (ptrdiff_t) 3;
    1449             :                 } else {
    1450             :                         fmt[i].extra = fmt + i;
    1451             :                 }
    1452             :         }
    1453       85024 :         if (i == t->nr_cols + 1)
    1454       85024 :                 ok = TABLEToutput_file(&as, order, s);
    1455      467051 :         for (i = 0; i <= t->nr_cols; i++) {
    1456      382027 :                 fmt[i].sep = NULL;
    1457      382027 :                 fmt[i].rsep = NULL;
    1458      382027 :                 fmt[i].type = NULL;
    1459      382027 :                 fmt[i].nullstr = NULL;
    1460             :         }
    1461      382027 :         for (i = 1; i <= t->nr_cols; i++)
    1462      297003 :                 bat_iterator_end(&fmt[i].ci);
    1463       85024 :         TABLETdestroy_format(&as);
    1464       85024 :         GDKfree(tres);
    1465       85024 :         if (mnstr_errnr(s))
    1466             :                 return -4;
    1467             :         if (ok < 0)
    1468             :                 return ok;
    1469             :         return 0;
    1470             : }
    1471             : 
    1472             : static int
    1473             : mvc_export_table(backend *b, stream *s, res_table *t, BAT *order, BUN offset, BUN nr, const char *btag, const char *sep, const char *rsep, const char *ssep, const char *ns)
    1474             : {
    1475       85012 :         return mvc_export_table_(b->mvc, b->output_format, s, t, order, offset, nr, btag, sep, rsep, ssep, ns);
    1476             : }
    1477             : 
    1478             : int
    1479           0 : mvc_export(mvc *m, stream *s, res_table *t, BUN nr)
    1480             : {
    1481             :         backend b;
    1482           0 :         b.mvc = m;
    1483           0 :         b.results = t;
    1484           0 :         b.reloptimizer = 0;
    1485           0 :         t->order = t->cols[0].b;
    1486           0 :         t->nr_rows = nr;
    1487           0 :         BBPretain(t->order);
    1488           0 :         if (mvc_export_head(&b, s, t->id, TRUE, TRUE, 0/*starttime*/, 0/*maloptimizer*/) < 0)
    1489             :                 return -1;
    1490           0 :         return mvc_export_table_(m, OFMT_CSV, s, t, BBPquickdesc(t->cols[0].b), 0, nr, "[ ", ",\t", "\t]\n", "\"", "NULL");
    1491             : }
    1492             : 
    1493             : 
    1494             : static lng
    1495      250471 : get_print_width(int mtype, sql_class eclass, int digits, int scale, int tz, bat bid, ptr p)
    1496             : {
    1497             :         size_t count = 0, incr = 0;
    1498             : 
    1499      250471 :         if (eclass == EC_SEC)
    1500             :                 incr = 1;
    1501      250095 :         else if (mtype == TYPE_oid)
    1502             :                 incr = 2;
    1503      250471 :         mtype = ATOMbasetype(mtype);
    1504      250471 :         if (mtype == TYPE_str) {
    1505      122011 :                 if (eclass == EC_CHAR && digits) {
    1506        7583 :                         return digits;
    1507             :                 } else {
    1508             :                         int l = 0;
    1509      114428 :                         if (bid) {
    1510      114428 :                                 BAT *b = BATdescriptor(bid);
    1511             : 
    1512      114428 :                                 if (b) {
    1513             :                                         /* in practice, b can be a
    1514             :                                          * void(nil) bat, an oid bat
    1515             :                                          * with all nil values, or an
    1516             :                                          * empty void/oid bat */
    1517      114428 :                                         if (ATOMstorage(b->ttype) == TYPE_str)
    1518      114382 :                                                 l = bat_max_strlength(b);
    1519             :                                         else
    1520             :                                                 l = 0;
    1521      114428 :                                         BBPunfix(b->batCacheid);
    1522             :                                 } else {
    1523             :                                         return -2;
    1524             :                                 }
    1525           0 :                         } else if (p) {
    1526           0 :                                 l = STRwidth((const char *) p);
    1527           0 :                                 if (is_int_nil(l))
    1528             :                                         l = 0;
    1529             :                         }
    1530      114428 :                         return l;
    1531             :                 }
    1532      128460 :         } else if (eclass == EC_NUM || eclass == EC_POS || eclass == EC_MONTH || eclass == EC_SEC) {
    1533             :                 count = 0;
    1534      115936 :                 if (bid) {
    1535      115936 :                         BAT *b = BATdescriptor(bid);
    1536             : 
    1537      115936 :                         if (b) {
    1538      115936 :                                 if (mtype == TYPE_bte) {
    1539        4737 :                                         count = bat_max_btelength(b);
    1540      111199 :                                 } else if (mtype == TYPE_sht) {
    1541       29145 :                                         count = bat_max_shtlength(b);
    1542       82054 :                                 } else if (mtype == TYPE_int) {
    1543       56029 :                                         count = bat_max_intlength(b);
    1544       26025 :                                 } else if (mtype == TYPE_lng) {
    1545       21335 :                                         count = bat_max_lnglength(b);
    1546             : #ifdef HAVE_HGE
    1547        4690 :                                 } else if (mtype == TYPE_hge) {
    1548        4690 :                                         count = bat_max_hgelength(b);
    1549             : #endif
    1550           0 :                                 } else if (mtype == TYPE_void) {
    1551             :                                         count = 4;
    1552             :                                 } else {
    1553           0 :                                         assert(0);
    1554             :                                 }
    1555      115936 :                                 count += incr;
    1556      115936 :                                 BBPunfix(b->batCacheid);
    1557             :                         } else {
    1558             :                                 return -2;
    1559             :                         }
    1560             :                 } else {
    1561           0 :                         if (p) {
    1562             : #ifdef HAVE_HGE
    1563             :                                 hge val = 0;
    1564             : #else
    1565             :                                 lng val = 0;
    1566             : #endif
    1567           0 :                                 if (mtype == TYPE_bte) {
    1568           0 :                                         val = *((bte *) p);
    1569           0 :                                 } else if (mtype == TYPE_sht) {
    1570           0 :                                         val = *((sht *) p);
    1571           0 :                                 } else if (mtype == TYPE_int) {
    1572           0 :                                         val = *((int *) p);
    1573           0 :                                 } else if (mtype == TYPE_lng) {
    1574           0 :                                         val = *((lng *) p);
    1575             : #ifdef HAVE_HGE
    1576           0 :                                 } else if (mtype == TYPE_hge) {
    1577           0 :                                         val = *((hge *) p);
    1578             : #endif
    1579             :                                 } else {
    1580           0 :                                         assert(0);
    1581             :                                 }
    1582             : 
    1583           0 :                                 if (val < 0)
    1584             :                                         count++;
    1585           0 :                                 while (val /= 10)
    1586           0 :                                         count++;
    1587           0 :                                 count++;
    1588           0 :                                 count += incr;
    1589             :                         } else {
    1590             :                                 count = 0;
    1591             :                         }
    1592             :                 }
    1593      115936 :                 if (eclass == EC_SEC && count < 5)
    1594             :                         count = 5;
    1595      115936 :                 return count;
    1596             :                 /* the following two could be done once by taking the
    1597             :                    max value and calculating the number of digits from that
    1598             :                    value, instead of the maximum values taken now, which
    1599             :                    include the optional sign */
    1600       12524 :         } else if (eclass == EC_FLT) {
    1601             :                 /* floats are printed using "%.9g":
    1602             :                  * [sign]+digit+period+[max 8 digits]+E+[sign]+[max 2 digits] */
    1603        2161 :                 if (mtype == TYPE_flt) {
    1604             :                         return 15;
    1605             :                         /* doubles are printed using "%.17g":
    1606             :                          * [sign]+digit+period+[max 16 digits]+E+[sign]+[max 3 digits] */
    1607             :                 } else {        /* TYPE_dbl */
    1608        1896 :                         return 24;
    1609             :                 }
    1610       10363 :         } else if (eclass == EC_DEC) {
    1611        1222 :                 count = 1 + digits;
    1612        1222 :                 if (scale > 0)
    1613        1004 :                         count += 1;
    1614        1222 :                 if (scale == digits) // for preceding 0, e.g. 0.
    1615          13 :                         count += 1;
    1616        1222 :                 return count;
    1617        9141 :         } else if (eclass == EC_DATE) {
    1618             :                 return 10;
    1619        8775 :         } else if (eclass == EC_TIME || eclass == EC_TIME_TZ) {
    1620             :                 count = 8;
    1621         232 :                 if (tz)         /* time zone */
    1622             :                         count += 6;     /* +03:30 */
    1623         232 :                 if (digits > 1)      /* fractional seconds precision (including dot) */
    1624          77 :                         count += digits;
    1625         232 :                 return count;
    1626        8543 :         } else if (eclass == EC_TIMESTAMP || eclass == EC_TIMESTAMP_TZ) {
    1627             :                 count = 10 + 1 + 8;
    1628         899 :                 if (tz)         /* time zone */
    1629             :                         count += 6;     /* +03:30 */
    1630         899 :                 if (digits)     /* fractional seconds precision */
    1631         899 :                         count += digits;
    1632         899 :                 return count;
    1633        7644 :         } else if (eclass == EC_BIT) {
    1634             :                 return 5;       /* max(strlen("true"), strlen("false")) */
    1635         543 :         } else if (strcmp(ATOMname(mtype), "uuid") == 0) {
    1636             :                 return 36;      /* xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */
    1637             :         } else {
    1638         467 :                 return 0;
    1639             :         }
    1640             : }
    1641             : 
    1642             : static int
    1643      250471 : export_length(stream *s, int mtype, sql_class eclass, int digits, int scale, int tz, bat bid, ptr p)
    1644             : {
    1645      250471 :         lng length = get_print_width(mtype, eclass, digits, scale, tz, bid, p);
    1646      250471 :         if (length < 0)
    1647             :                 return -2;
    1648      250471 :         if (mvc_send_lng(s, length) != 1)
    1649           0 :                 return -4;
    1650             :         return 0;
    1651             : }
    1652             : 
    1653             : int
    1654       16536 : mvc_export_operation(backend *b, stream *s, str w, lng starttime, lng mal_optimizer)
    1655             : {
    1656       16536 :         mvc *m = b->mvc;
    1657             : 
    1658       16536 :         assert(m->type == Q_SCHEMA || m->type == Q_TRANS);
    1659       16536 :         if (m->type == Q_SCHEMA) {
    1660       13922 :                 if (!s)
    1661             :                         return 0;
    1662       13922 :                 if (mnstr_printf(s, "&3 " LLFMT " " LLFMT "\n", starttime > 0 ? GDKusec() - starttime : 0, mal_optimizer) < 0)
    1663             :                         return -4;
    1664             :         } else {
    1665        2614 :                 if (m->session->auto_commit) {
    1666        1218 :                         if (mnstr_write(s, "&4 t\n", 5, 1) != 1)
    1667             :                                 return -4;
    1668             :                 } else {
    1669        1396 :                         if (mnstr_write(s, "&4 f\n", 5, 1) != 1)
    1670             :                                 return -4;
    1671             :                 }
    1672             :         }
    1673             : 
    1674       16536 :         if (mvc_export_warning(s, w) != 1)
    1675           0 :                 return -4;
    1676             :         return 0;
    1677             : }
    1678             : 
    1679             : 
    1680             : int
    1681       73811 : mvc_affrows(mvc *m, stream *s, lng val, str w, oid query_id, lng last_id, lng starttime, lng maloptimizer, lng reloptimizer)
    1682             : {
    1683       73811 :         sqlvar_set_number(find_global_var(m, mvc_bind_schema(m, "sys"), "rowcnt"), val);
    1684             : 
    1685             :         /* if we don't have a stream, nothing can go wrong, so we return
    1686             :          * success.  This is especially vital for execution of internal SQL
    1687             :          * commands, since they don't get a stream to suppress their output.
    1688             :          * If we would fail on having no stream here, those internal commands
    1689             :          * fail too.
    1690             :          */
    1691       73811 :         if (!s || GDKembedded())
    1692       52673 :                 return 0;
    1693       42276 :         if (mnstr_write(s, "&2 ", 3, 1) != 1 ||
    1694       42276 :             mvc_send_lng(s, val) != 1 ||
    1695       42276 :             mnstr_write(s, " ", 1, 1) != 1 ||
    1696       42276 :             mvc_send_lng(s, last_id) != 1 ||
    1697       42276 :             mnstr_write(s, " ", 1, 1) != 1 ||
    1698       42276 :             mvc_send_lng(s, (lng) query_id) != 1 ||
    1699       42276 :             mnstr_write(s, " ", 1, 1) != 1 ||
    1700       42276 :             mvc_send_lng(s, starttime > 0 ? GDKusec() - starttime : 0) != 1 ||
    1701       42276 :             mnstr_write(s, " ", 1, 1) != 1 ||
    1702       42276 :             mvc_send_lng(s, maloptimizer) != 1 ||
    1703       42276 :             mnstr_write(s, " ", 1, 1) != 1 ||
    1704       42276 :             mvc_send_lng(s, reloptimizer) != 1 ||
    1705       21138 :             mnstr_write(s, "\n", 1, 1) != 1)
    1706           0 :                 return -4;
    1707       21138 :         if (mvc_export_warning(s, w) != 1)
    1708           0 :                 return -4;
    1709             : 
    1710             :         return 0;
    1711             : }
    1712             : 
    1713             : int
    1714       73811 : mvc_export_affrows(backend *b, stream *s, lng val, str w, oid query_id, lng starttime, lng maloptimizer)
    1715             : {
    1716       73811 :         b->rowcnt = val;
    1717       73811 :         return mvc_affrows(b->mvc, s, val, w, query_id, b->last_id, starttime, maloptimizer, b->reloptimizer);
    1718             : }
    1719             : 
    1720             : static int
    1721             : export_error(BAT *order)
    1722             : {
    1723             :         if (order)
    1724           0 :                 BBPunfix(order->batCacheid);
    1725             :         return -4;
    1726             : }
    1727             : 
    1728             : int
    1729       77537 : mvc_export_head(backend *b, stream *s, int res_id, int only_header, int compute_lengths, lng starttime, lng maloptimizer)
    1730             : {
    1731       77537 :         mvc *m = b->mvc;
    1732             :         int i, res = 0;
    1733             :         BUN count = 0;
    1734       77537 :         res_table *t = res_tables_find(b->results, res_id);
    1735             : 
    1736       77537 :         if (!s || !t)
    1737             :                 return 0;
    1738             : 
    1739             :         /* query type: Q_TABLE || Q_PREPARE */
    1740       77537 :         assert(t->query_type == Q_TABLE || t->query_type == Q_PREPARE);
    1741       77537 :         if (mnstr_write(s, "&", 1, 1) != 1 || mvc_send_int(s, (int) t->query_type) != 1 || mnstr_write(s, " ", 1, 1) != 1)
    1742           0 :                 return -4;
    1743             : 
    1744             :         /* id */
    1745       77537 :         int result_id = t->query_type == Q_PREPARE?b->q->id:t->id;
    1746       77537 :         if (mvc_send_int(s, result_id) != 1 || mnstr_write(s, " ", 1, 1) != 1)
    1747           0 :                 return -4;
    1748             : 
    1749             :         /* tuple count */
    1750       77537 :         if (only_header) {
    1751       77537 :                 if (t->order) {
    1752       77537 :                         count = t->nr_rows;
    1753             :                 } else {
    1754             :                         count = 1;
    1755             :                 }
    1756             :         }
    1757       77537 :         b->rowcnt = count;
    1758       77537 :         sqlvar_set_number(find_global_var(m, mvc_bind_schema(m, "sys"), "rowcnt"), b->rowcnt);
    1759       77537 :         if (mvc_send_lng(s, (lng) count) != 1 || mnstr_write(s, " ", 1, 1) != 1)
    1760           0 :                 return -4;
    1761             : 
    1762             :         /* column count */
    1763       77537 :         if (mvc_send_int(s, t->nr_cols) != 1 || mnstr_write(s, " ", 1, 1) != 1)
    1764           0 :                 return -4;
    1765             : 
    1766             :         /* row count, min(count, reply_size) */
    1767             :         /* the columnar protocol ignores the reply size by fetching the entire resultset at once, so don't set it */
    1768       77537 :         if (mvc_send_int(s, (b->client->protocol != PROTOCOL_COLUMNAR && m->reply_size >= 0 && (BUN) m->reply_size < count) ? m->reply_size : (int) count) != 1)
    1769             :                 return -4;
    1770             : 
    1771             :         // export query id
    1772       77537 :         if (mnstr_write(s, " ", 1, 1) != 1 || mvc_send_lng(s, (lng) t->query_id) != 1)
    1773           0 :                 return -4;
    1774             : 
    1775             :         // export query time
    1776       77537 :         if (mnstr_write(s, " ", 1, 1) != 1 || mvc_send_lng(s, starttime > 0 ? GDKusec() - starttime : 0) != 1)
    1777           0 :                 return -4;
    1778             : 
    1779             :         // export MAL optimizer time
    1780       77537 :         if (mnstr_write(s, " ", 1, 1) != 1 || mvc_send_lng(s, maloptimizer) != 1)
    1781           0 :                 return -4;
    1782             : 
    1783       77537 :         if (mnstr_write(s, " ", 1, 1) != 1 || mvc_send_lng(s, b->reloptimizer) != 1)
    1784           0 :                 return -4;
    1785             : 
    1786       77537 :         if (mnstr_write(s, "\n% ", 3, 1) != 1)
    1787             :                 return -4;
    1788      328008 :         for (i = 0; i < t->nr_cols; i++) {
    1789      250471 :                 res_col *c = t->cols + i;
    1790      250471 :                 size_t len = strlen(c->tn);
    1791             : 
    1792      250471 :                 if (len && mnstr_write(s, c->tn, len, 1) != 1)
    1793             :                         return -4;
    1794      250471 :                 if (i + 1 < t->nr_cols && mnstr_write(s, ",\t", 2, 1) != 1)
    1795             :                         return -4;
    1796             :         }
    1797       77537 :         if (mnstr_write(s, " # table_name\n% ", 16, 1) != 1)
    1798             :                 return -4;
    1799             : 
    1800      328008 :         for (i = 0; i < t->nr_cols; i++) {
    1801      250471 :                 res_col *c = t->cols + i;
    1802             : 
    1803      250471 :                 if (strpbrk(c->name, ", \t#\"\\")) {
    1804             :                         char *p;
    1805         163 :                         if (mnstr_write(s, "\"", 1, 1) != 1)
    1806             :                                 return -4;
    1807        2178 :                         for (p = c->name; *p; p++) {
    1808        2015 :                                 if (*p == '"' || *p == '\\') {
    1809          24 :                                         if (mnstr_write(s, "\\", 1, 1) != 1)
    1810             :                                                 return -4;
    1811             :                                 }
    1812        2015 :                                 if (mnstr_write(s, p, 1, 1) != 1)
    1813             :                                         return -4;
    1814             :                         }
    1815         163 :                         if (mnstr_write(s, "\"", 1, 1) != 1)
    1816             :                                 return -4;
    1817             :                 } else {
    1818      250308 :                         if (mnstr_write(s, c->name, strlen(c->name), 1) != 1)
    1819             :                                 return -4;
    1820             :                 }
    1821             : 
    1822      250471 :                 if (i + 1 < t->nr_cols && mnstr_write(s, ",\t", 2, 1) != 1)
    1823             :                         return -4;
    1824             :         }
    1825       77537 :         if (mnstr_write(s, " # name\n% ", 10, 1) != 1)
    1826             :                 return -4;
    1827             : 
    1828      328008 :         for (i = 0; i < t->nr_cols; i++) {
    1829      250471 :                 res_col *c = t->cols + i;
    1830             : 
    1831      250471 :                 if (mnstr_write(s, c->type.type->base.name, strlen(c->type.type->base.name), 1) != 1)
    1832             :                         return -4;
    1833      250471 :                 if (i + 1 < t->nr_cols && mnstr_write(s, ",\t", 2, 1) != 1)
    1834             :                         return -4;
    1835             :         }
    1836       77537 :         if (mnstr_write(s, " # type\n% ", 10, 1) != 1)
    1837             :                 return -4;
    1838       77537 :         if (compute_lengths) {
    1839      328008 :                 for (i = 0; i < t->nr_cols; i++) {
    1840      250471 :                         res_col *c = t->cols + i;
    1841      250471 :                         int mtype = c->type.type->localtype;
    1842      250471 :                         sql_class eclass = c->type.type->eclass;
    1843             : 
    1844      250471 :                         if ((res = export_length(s, mtype, eclass, c->type.digits, c->type.scale, type_has_tz(&c->type), c->b, c->p)) < 0)
    1845           0 :                                 return res;
    1846      250471 :                         if (i + 1 < t->nr_cols && mnstr_write(s, ",\t", 2, 1) != 1)
    1847             :                                 return -4;
    1848             :                 }
    1849       77537 :                 if (mnstr_write(s, " # length\n", 10, 1) != 1)
    1850             :                         return -4;
    1851             :         }
    1852       77537 :         if (b->sizeheader) {
    1853       31455 :                 if (mnstr_write(s, "% ", 2, 1) != 1)
    1854             :                         return -4;
    1855      133203 :                 for (i = 0; i < t->nr_cols; i++) {
    1856      101748 :                         res_col *c = t->cols + i;
    1857             : 
    1858      101748 :                         if (mnstr_printf(s, "%u %u", c->type.digits, c->type.scale) < 0)
    1859             :                                 return -4;
    1860      101748 :                         if (i + 1 < t->nr_cols && mnstr_write(s, ",\t", 2, 1) != 1)
    1861             :                                 return -4;
    1862             :                 }
    1863       31455 :                 if (mnstr_write(s, " # typesizes\n", 13, 1) != 1)
    1864           0 :                         return -4;
    1865             :         }
    1866             :         return res;
    1867             : }
    1868             : 
    1869             : static int
    1870          12 : mvc_export_file(backend *b, stream *s, res_table *t)
    1871             : {
    1872             :         int res = 0;
    1873             :         BUN count;
    1874             :         BAT *order = NULL;
    1875             : 
    1876          12 :         if (!t->order) {
    1877           0 :                 res = mvc_export_row(b, s, t, "", t->tsep, t->rsep, t->ssep, t->ns);
    1878             :         } else {
    1879          12 :                 order = BATdescriptor(t->order);
    1880          12 :                 if (!order)
    1881             :                         return -2;
    1882          12 :                 count = t->nr_rows;
    1883             : 
    1884          12 :                 res = mvc_export_table(b, s, t, order, 0, count, "", t->tsep, t->rsep, t->ssep, t->ns);
    1885          12 :                 BBPunfix(order->batCacheid);
    1886          12 :                 b->results = res_tables_remove(b->results, t);
    1887             :         }
    1888             :         return res;
    1889             : }
    1890             : 
    1891             : int
    1892       77973 : mvc_export_result(backend *b, stream *s, int res_id, bool header, lng starttime, lng maloptimizer)
    1893             : {
    1894       77973 :         mvc *m = b->mvc;
    1895             :         int clean = 0, res = 0;
    1896             :         BUN count;
    1897       77973 :         res_table *t = res_tables_find(b->results, res_id);
    1898             :         BAT *order = NULL;
    1899       77973 :         int json = (b->output_format == OFMT_JSON);
    1900             : 
    1901       77973 :         if (!s || !t)
    1902             :                 return 0;
    1903             : 
    1904             :         /* Proudly supporting SQLstatementIntern's output flag */
    1905       77973 :         if (b->output_format == OFMT_NONE)
    1906             :                 return 0;
    1907             : 
    1908       77540 :         assert(t->query_type == Q_TABLE || t->query_type == Q_PREPARE);
    1909       77540 :         if (t->tsep) {
    1910             :                 /* need header */
    1911          12 :                 if (header && (res = mvc_export_head(b, s, res_id, TRUE, TRUE, starttime, maloptimizer)) < 0)
    1912             :                         return res;
    1913          12 :                 return mvc_export_file(b, s, t);
    1914             :         }
    1915             : 
    1916       77528 :         if (!json && (res = mvc_export_head(b, s, res_id, TRUE, TRUE, starttime, maloptimizer)) < 0)
    1917             :                 return res;
    1918             : 
    1919       77528 :         assert(t->order);
    1920             : 
    1921       77528 :         if (b->client->protocol == PROTOCOL_COLUMNAR) {
    1922           1 :                 if (mnstr_flush(s, MNSTR_FLUSH_DATA) < 0)
    1923             :                         return -4;
    1924           1 :                 return mvc_export_table_columnar(s, t);
    1925             :         }
    1926             : 
    1927       77527 :         if (!(order = BATdescriptor(t->order)))
    1928             :                 return -2;
    1929             : 
    1930       77527 :         count = m->reply_size;
    1931       77527 :         if (m->reply_size != -2 && (count <= 0 || count >= t->nr_rows)) {
    1932       76930 :                 count = t->nr_rows;
    1933             :                 clean = 1;
    1934             :         }
    1935       77527 :         if (json) {
    1936           0 :                 switch(count) {
    1937             :                 case 0:
    1938             :                         res = mvc_export_table(b, s, t, order, 0, count, "{\t", "", "}\n", "\"", "null");
    1939           0 :                         break;
    1940             :                 case 1:
    1941             :                         res = mvc_export_table(b, s, t, order, 0, count, "{\n\t\"%s\" : ", ",\n\t\"%s\" : ", "\n}\n", "\"", "null");
    1942           0 :                         break;
    1943             :                 case 2:
    1944             :                         res = mvc_export_table(b, s, t, order, 0, 1, "[\n\t{\n\t\t\"%s\" : ", ",\n\t\t\"%s\" : ", "\n\t},\n", "\"", "null");
    1945           0 :                         res = mvc_export_table(b, s, t, order, 1, count - 1, "\t{\n\t\t\"%s\" : ", ",\n\t\t\"%s\" : ", "\n\t}\n]\n", "\"", "null");
    1946           0 :                         break;
    1947             :                 default:
    1948             :                         res = mvc_export_table(b, s, t, order, 0, 1, "[\n\t{\n\t\t\"%s\" : ", ",\n\t\t\"%s\" : ", "\n\t},\n", "\"", "null");
    1949           0 :                         res = mvc_export_table(b, s, t, order, 1, count - 2, "\t{\n\t\t\"%s\" : ", ",\n\t\t\"%s\" : ", "\n\t},\n", "\"", "null");
    1950           0 :                         res = mvc_export_table(b, s, t, order, count - 1, 1, "\t{\n\t\t\"%s\" : ", ",\n\t\t\"%s\" : ", "\n\t}\n]\n", "\"", "null");
    1951             :                 }
    1952             :         } else {
    1953             :                 res = mvc_export_table(b, s, t, order, 0, count, "[ ", ",\t", "\t]\n", "\"", "NULL");
    1954             :         }
    1955       77527 :         BBPunfix(order->batCacheid);
    1956       77527 :         if (clean)
    1957       76930 :                 b->results = res_tables_remove(b->results, t);
    1958             : 
    1959       77527 :         if (res > -1)
    1960       77527 :                 res = mvc_export_warning(s, "");
    1961             :         return res;
    1962             : }
    1963             : 
    1964             : int
    1965        7497 : mvc_export_chunk(backend *b, stream *s, int res_id, BUN offset, BUN nr)
    1966             : {
    1967             :         int res = 0;
    1968        7497 :         res_table *t = res_tables_find(b->results, res_id);
    1969             :         BAT *order = NULL;
    1970             :         BUN cnt;
    1971             : 
    1972        7497 :         if (!s || !t)
    1973             :                 return 0;
    1974             : 
    1975        7485 :         order = BATdescriptor(t->order);
    1976        7485 :         if (!order)
    1977             :                 return -2;
    1978             :         cnt = nr;
    1979        7485 :         if (cnt == 0)
    1980           0 :                 cnt = t->nr_rows;
    1981        7485 :         if (offset >= t->nr_rows)
    1982             :                 cnt = 0;
    1983        7485 :         if (cnt == BUN_NONE || offset + cnt > t->nr_rows)
    1984           2 :                 cnt = t->nr_rows - offset;
    1985             : 
    1986             :         /* query type: Q_BLOCK */
    1987        7485 :         if (mnstr_write(s, "&6 ", 3, 1) != 1)
    1988           0 :                 return export_error(order);
    1989             : 
    1990             :         /* result id */
    1991        7485 :         if (mvc_send_int(s, res_id) != 1 || mnstr_write(s, " ", 1, 1) != 1)
    1992           0 :                 return export_error(order);
    1993             : 
    1994             :         /* column count */
    1995        7485 :         if (mvc_send_int(s, t->nr_cols) != 1 || mnstr_write(s, " ", 1, 1) != 1)
    1996           0 :                 return export_error(order);
    1997             : 
    1998             :         /* row count */
    1999        7485 :         if (mvc_send_lng(s, (lng) cnt) != 1 || mnstr_write(s, " ", 1, 1) != 1)
    2000           0 :                 return export_error(order);
    2001             : 
    2002             :         /* block offset */
    2003        7485 :         if (mvc_send_lng(s, (lng) offset) != 1)
    2004           0 :                 return export_error(order);
    2005             : 
    2006        7485 :         if (mnstr_write(s, "\n", 1, 1) != 1)
    2007           0 :                 return export_error(order);
    2008             : 
    2009             :         res = mvc_export_table(b, s, t, order, offset, cnt, "[ ", ",\t", "\t]\n", "\"", "NULL");
    2010        7485 :         BBPunfix(order->batCacheid);
    2011        7485 :         return res;
    2012             : }
    2013             : 
    2014             : int
    2015       77673 : mvc_result_table(backend *be, oid query_id, int nr_cols, mapi_query_t type, BAT *order)
    2016             : {
    2017       77673 :         res_table *t = res_table_create(be->mvc->session->tr, be->result_id++, query_id, nr_cols, type, be->results, order);
    2018       77673 :         be->results = t;
    2019       77673 :         return t ? t->id : -1;
    2020             : }
    2021             : 
    2022             : int
    2023      222135 : mvc_result_column(backend *be, char *tn, char *name, char *typename, int digits, int scale, BAT *b)
    2024             : {
    2025             :         /* return 0 on success, non-zero on failure */
    2026      222135 :         return res_col_create(be->mvc->session->tr, be->results, tn, name, typename, digits, scale, TYPE_bat, b, false) ? 0 : -1;
    2027             : }
    2028             : 
    2029             : int
    2030       28866 : mvc_result_value(backend *be, const char *tn, const char *name, const char *typename, int digits, int scale, ptr *p, int mtype)
    2031             : {
    2032             :         /* return 0 on success, non-zero on failure */
    2033       28866 :         return res_col_create(be->mvc->session->tr, be->results, tn, name, typename, digits, scale, mtype, p, false) ? 0 : -1;
    2034             : }
    2035             : 
    2036             : /* Translate error code from export function to error string */
    2037             : const char *
    2038           0 : mvc_export_error(backend *be, stream *s, int err_code)
    2039             : {
    2040             :         (void) be;
    2041           0 :         switch (err_code) {
    2042             :                 case -1: /* Allocation failure */
    2043             :                         return MAL_MALLOC_FAIL;
    2044           0 :                 case -2: /* BAT descriptor error */
    2045           0 :                         return RUNTIME_OBJECT_MISSING;
    2046           0 :                 case -3: /* GDK error */
    2047           0 :                         return GDKerrbuf;
    2048           0 :                 case -4: /* Stream error */
    2049           0 :                         return mnstr_peek_error(s);
    2050           0 :                 default: /* Unknown, must be a bug */
    2051           0 :                         return "Unknown internal error";
    2052             :         }
    2053             : }

Generated by: LCOV version 1.14