LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_bincopyconvert.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 271 294 92.2 %
Date: 2024-04-25 20:03:45 Functions: 24 24 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : 
      15             : #include "copybinary.h"
      16             : #include "copybinary_support.h"
      17             : #include "sql_bincopyconvert.h"
      18             : #include "sql.h"
      19             : #include "gdk.h"
      20             : #include "mal_backend.h"
      21             : #include "mal_interpreter.h"
      22             : #include "mstring.h"
      23             : 
      24             : 
      25             : #define bailout(...) do { \
      26             :                 msg = createException(MAL, mal_operator, SQLSTATE(42000) __VA_ARGS__); \
      27             :                 goto end; \
      28             :         } while (0)
      29             : 
      30             : 
      31             : static str
      32           4 : validate_bit(void *dst_, size_t count, int width, const char *filename)
      33             : {
      34           4 :         (void)width;
      35           4 :         const unsigned char *data = dst_;
      36             : 
      37          10 :         for (size_t i = 0; i < count; i++) {
      38           6 :                 if (data[i] > 1 && data[i] != 0x80)
      39           0 :                         throw(SQL, "convert_bit", SQLSTATE(22003) "invalid boolean byte value %d in %s", data[i], filename);
      40             :         }
      41             :         return MAL_SUCCEED;
      42             : }
      43             : 
      44             : // width is only nonzero for DECIMAL types. For plain integer types it is 0.
      45             : #define VALIDATE_DECIMAL(TYP,NIL_VALUE) do { \
      46             :                 if (width) { \
      47             :                         TYP m = 1; \
      48             :                         for (int i = 0; i < width; i++) \
      49             :                                 m *= 10; \
      50             :                         TYP *dst = dst_; \
      51             :                         for (size_t i = 0; i < count; i++) { \
      52             :                                 if (dst[i] == NIL_VALUE) \
      53             :                                         continue; \
      54             :                                 if (dst[i] >= m || dst[i] <= -m) \
      55             :                                         throw(SQL, "convert", SQLSTATE(22003) "decimal out of range in %s", filename); \
      56             :                         } \
      57             :                 } \
      58             :     } while (0)
      59             : 
      60             : 
      61             : static str
      62           9 : byteswap_sht(void *dst_, void *src_, size_t count, bool byteswap)
      63             : {
      64           9 :         assert(byteswap); (void)byteswap; // otherwise, why call us?
      65             :         sht *dst = dst_;
      66             :         const sht *src = src_;
      67     4000015 :         for (size_t i = 0; i < count; i++)
      68     4000006 :                 *dst++ = copy_binary_byteswap16(*src++);
      69           9 :         return MAL_SUCCEED;
      70             : }
      71             : 
      72             : static str
      73          42 : validate_sht(void *dst_, size_t count, int width, const char *filename)
      74             : {
      75     3000087 :         VALIDATE_DECIMAL(sht, sht_nil);
      76             :         return MAL_SUCCEED;
      77             : }
      78             : 
      79             : static str
      80          41 : byteswap_int(void *dst_, void *src_, size_t count, bool byteswap)
      81             : {
      82          41 :         assert(byteswap); (void)byteswap; // otherwise, why call us?
      83             :         int *dst = dst_;
      84             :         const int *src = src_;
      85     8000071 :         for (size_t i = 0; i < count; i++)
      86     8000030 :                 *dst++ = copy_binary_byteswap32(*src++);
      87          41 :         return MAL_SUCCEED;
      88             : }
      89             : 
      90             : static str
      91         284 : validate_int(void *dst_, size_t count, int width, const char *filename)
      92             : {
      93     4000447 :         VALIDATE_DECIMAL(int, int_nil);
      94             :         return MAL_SUCCEED;
      95             : }
      96             : 
      97             : static str
      98          33 : byteswap_lng(void *dst_, void *src_, size_t count, bool byteswap)
      99             : {
     100          33 :         assert(byteswap); (void)byteswap; // otherwise, why call us?
     101             :         lng *dst = dst_;
     102             :         const lng *src = src_;
     103     4000039 :         for (size_t i = 0; i < count; i++)
     104     4000006 :                 *dst++ = copy_binary_byteswap64(*src++);
     105          33 :         return MAL_SUCCEED;
     106             : }
     107             : 
     108             : static str
     109         103 : validate_lng(void *dst_, size_t count, int width, const char *filename)
     110             : {
     111     4000433 :         VALIDATE_DECIMAL(lng, lng_nil);
     112             :         return MAL_SUCCEED;
     113             : }
     114             : 
     115             : #ifdef HAVE_HGE
     116             : static str
     117           1 : byteswap_hge(void *dst_, void *src_, size_t count, bool byteswap)
     118             : {
     119           1 :         assert(byteswap); (void)byteswap; // otherwise, why call us?
     120             :         hge *dst = dst_;
     121             :         const hge *src = src_;
     122           7 :         for (size_t i = 0; i < count; i++)
     123           6 :                 *dst++ = copy_binary_byteswap128(*src++);
     124           1 :         return MAL_SUCCEED;
     125             : }
     126             : 
     127             : static str
     128          94 : validate_hge(void *dst_, size_t count, int width, const char *filename)
     129             : {
     130     4001215 :         VALIDATE_DECIMAL(hge, hge_nil);
     131             :         return MAL_SUCCEED;
     132             : }
     133             : #endif
     134             : 
     135             : static str
     136          17 : byteswap_flt(void *dst_, void *src_, size_t count, bool byteswap)
     137             : {
     138             :         // Verify that size and alignment requirements of flt do not exceed int.
     139             :         // This is important because we use the int32 byteswap to byteswap the floats.
     140          17 :         assert(sizeof(uint32_t) == sizeof(flt));
     141          17 :         assert(sizeof(struct { char dummy; uint32_t ui; }) >= sizeof(struct { char dummy; flt f; }));
     142             : 
     143          17 :         assert(byteswap); (void)byteswap; // otherwise, why call us?
     144             :         int *dst = dst_;
     145             :         const int *src = src_;
     146     4000020 :         for (size_t i = 0; i < count; i++)
     147     4000003 :                 *dst++ = copy_binary_byteswap32(*src++);
     148          17 :         return MAL_SUCCEED;
     149             : }
     150             : 
     151             : static str
     152          33 : byteswap_dbl(void *dst_, void *src_, size_t count, bool byteswap)
     153             : {
     154             :         // Verify that size and alignment requirements of dbl do not exceed lng
     155             :         // This is important because we use the int64 byteswap to byteswap the doubles.
     156          33 :         assert(sizeof(uint64_t) == sizeof(dbl));
     157          33 :         assert(sizeof(struct { char dummy; uint64_t ui; }) >= sizeof(struct { char dummy; dbl f; }));
     158             : 
     159          33 :         assert(byteswap); (void)byteswap; // otherwise, why call us?
     160             :         lng *dst = dst_;
     161             :         const lng *src = src_;
     162     4000036 :         for (size_t i = 0; i < count; i++)
     163     4000003 :                 *dst++ = copy_binary_byteswap64(*src++);
     164          33 :         return MAL_SUCCEED;
     165             : }
     166             : 
     167             : 
     168             : static str
     169          10 : decode_date(void *dst_, void *src_, size_t count, bool byteswap)
     170             : {
     171          10 :         date *dst = dst_;
     172          10 :         copy_binary_date *src = src_;
     173             : 
     174     2000014 :         for (size_t i = 0; i < count; i++) {
     175     2000004 :                 copy_binary_date incoming;
     176     2000004 :                 if (!byteswap)
     177     2000002 :                         incoming = *src++;
     178             :                 else
     179           2 :                         incoming = copy_binary_byteswap_date(*src++);
     180     2000004 :                 date value = date_create(incoming.year, incoming.month, incoming.day);
     181     2000004 :                 *dst++ = value;
     182             :         }
     183          10 :         return MAL_SUCCEED;
     184             : }
     185             : 
     186             : static str
     187          10 : encode_date(void *dst_, void *src_, size_t count, bool byteswap)
     188             : {
     189          10 :         copy_binary_date *dst = dst_;
     190          10 :         date *src = src_;
     191     2000526 :         for (size_t i = 0; i < count; i++) {
     192     2000516 :                 date dt = *src++;
     193     2000516 :                 if (is_date_nil(dt)) {
     194      199526 :                         *dst++ = (copy_binary_date){
     195             :                                 .day = 0xFF,
     196             :                                 .month = 0xFF,
     197             :                                 .year = -1,
     198             :                         };
     199      199526 :                         continue;
     200             :                 }
     201     1800990 :                 int16_t year = date_year(dt);
     202     1800990 :                 if (byteswap)
     203           0 :                         year = copy_binary_byteswap16(year);
     204     1800990 :                 *dst++ = (copy_binary_date){
     205     1800990 :                         .day = date_day(dt),
     206     1800990 :                         .month = date_month(dt),
     207             :                         .year = year,
     208             :                 };
     209             :         }
     210          10 :         return MAL_SUCCEED;
     211             : }
     212             : 
     213             : static str
     214          16 : decode_time(void *dst_, void *src_, size_t count, bool byteswap)
     215             : {
     216          16 :         daytime *dst = dst_;
     217          16 :         copy_binary_time *src = src_;
     218             : 
     219     2000016 :         for (size_t i = 0; i < count; i++) {
     220     2000000 :                 copy_binary_time incoming;
     221     2000000 :                 if (!byteswap)
     222     2000000 :                         incoming = *src++;
     223             :                 else
     224           0 :                         incoming = copy_binary_byteswap_time(*src++);
     225     2000000 :                 daytime value = daytime_create(incoming.hours, incoming.minutes, incoming.seconds, incoming.ms);
     226     2000000 :                 *dst++ = value;
     227             :         }
     228          16 :         return MAL_SUCCEED;
     229             : }
     230             : 
     231             : static str
     232          16 : encode_time(void *dst_, void *src_, size_t count, bool byteswap)
     233             : {
     234          16 :         copy_binary_time *dst = dst_;
     235          16 :         daytime *src = src_;
     236     2000016 :         for (size_t i = 0; i < count; i++) {
     237     2000000 :                 daytime tm = *src++;
     238     2000000 :                 if (is_daytime_nil(tm)) {
     239      199402 :                         *dst++ = (copy_binary_time){
     240             :                                 .ms = 0xFFFFFFFF,
     241             :                                 .seconds = 0xFF,
     242             :                                 .minutes = 0xFF,
     243             :                                 .hours = 0xFF,
     244             :                                 .padding = 0xFF,
     245             :                         };
     246      199402 :                         continue;
     247             :                 }
     248     1800598 :                 uint32_t ms = daytime_usec(tm);
     249     1800598 :                 if (byteswap)
     250           0 :                         ms = copy_binary_byteswap32(ms);
     251     1800598 :                 *dst++ = (copy_binary_time){
     252             :                         .ms = ms,
     253     1800598 :                         .seconds = daytime_sec(tm),
     254     1800598 :                         .minutes = daytime_min(tm),
     255     1800598 :                         .hours = daytime_hour(tm),
     256             :                 };
     257             :         }
     258          16 :         return MAL_SUCCEED;
     259             : }
     260             : 
     261             : static str
     262          37 : decode_timestamp(void *dst_, void *src_, size_t count, bool byteswap)
     263             : {
     264          37 :         timestamp *dst = dst_;
     265          37 :         copy_binary_timestamp *src = src_;
     266             : 
     267     2000041 :         for (size_t i = 0; i < count; i++) {
     268     2000004 :                 copy_binary_timestamp incoming;
     269     2000004 :                 if (!byteswap)
     270     2000002 :                         incoming = *src++;
     271             :                 else
     272           2 :                         incoming = copy_binary_byteswap_timestamp(*src++);
     273     2000004 :                 date dt = date_create(incoming.date.year, incoming.date.month, incoming.date.day);
     274     2000004 :                 daytime tm = daytime_create(incoming.time.hours, incoming.time.minutes, incoming.time.seconds, incoming.time.ms);
     275     2000004 :                 timestamp value = timestamp_create(dt, tm);
     276     2000004 :                 *dst++ = value;
     277             :         }
     278          37 :         return MAL_SUCCEED;
     279             : }
     280             : 
     281             : 
     282             : static str
     283          24 : encode_timestamp(void *dst_, void *src_, size_t count, bool byteswap)
     284             : {
     285          24 :         copy_binary_timestamp *dst = dst_;
     286          24 :         timestamp *src = src_;
     287     2000024 :         for (size_t i = 0; i < count; i++) {
     288     2000000 :                 timestamp value = *src++;
     289     2000000 :                 if (is_timestamp_nil(value)) {
     290      199402 :                         *dst++ = (copy_binary_timestamp) {
     291             :                                 .time = {
     292             :                                         .ms = 0xFFFFFFFF,
     293             :                                         .seconds = 0xFF,
     294             :                                         .minutes = 0xFF,
     295             :                                         .hours = 0xFF,
     296             :                                         .padding = 0xFF,
     297             :                                 },
     298             :                                 .date = {
     299             :                                         .day = 0xFF,
     300             :                                         .month = 0xFF,
     301             :                                         .year = -1,
     302             :                                 }
     303             :                         };
     304      199402 :                         continue;
     305             :                 }
     306     1800598 :                 date dt = timestamp_date(value);
     307     1800598 :                 daytime tm = timestamp_daytime(value);
     308     1800598 :                 int16_t year = date_year(dt);
     309     1800598 :                 uint32_t ms = daytime_usec(tm);
     310     1800598 :                 if (byteswap) {
     311           0 :                         ms = copy_binary_byteswap32(ms);
     312           0 :                         year = copy_binary_byteswap16(year);
     313             :                 }
     314     1800598 :                 *dst++ = (copy_binary_timestamp) {
     315             :                         .time = {
     316             :                                 .ms = ms,
     317     1800598 :                                 .seconds = daytime_sec(tm),
     318     1800598 :                                 .minutes = daytime_min(tm),
     319     1800598 :                                 .hours = daytime_hour(tm),
     320             :                         },
     321             :                         .date = {
     322     1800598 :                                 .day = date_day(dt),
     323     1800598 :                                 .month = date_month(dt),
     324             :                                 .year = year,
     325             :                         },
     326             :                 };
     327             :         }
     328          24 :         return MAL_SUCCEED;
     329             : }
     330             : 
     331             : // Load NUL-terminated items from the stream and put them in the BAT.
     332             : static str
     333          23 : load_zero_terminated_text(BAT *bat, stream *s, int *eof_reached, int width, bool byteswap)
     334             : {
     335          23 :         (void)byteswap;
     336          23 :         const char *mal_operator = "sql.importColumn";
     337          23 :         str msg = MAL_SUCCEED;
     338          23 :         bstream *bs = NULL;
     339          23 :         int tpe = BATttype(bat);
     340          23 :         void *buffer = NULL;
     341          23 :         size_t buffer_len = 0;
     342             : 
     343             :         // convert_and_validate_utf8() above counts on the following property to hold:
     344          23 :         assert(strNil((const char[2]){ 0x80, 0 }));
     345             : 
     346          23 :         bs = bstream_create(s, 1 << 20);
     347          23 :         if (bs == NULL) {
     348           0 :                 msg = createException(SQL, "sql", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     349           0 :                 goto end;
     350             :         }
     351             : 
     352             :         // In the outer loop we refill the buffer until the stream ends.
     353             :         // In the inner loop we look for complete \0-terminated strings.
     354         849 :         while (1) {
     355         436 :                 ssize_t nread = bstream_next(bs);
     356         436 :                 if (nread < 0)
     357           0 :                         bailout("%s", mnstr_peek_error(s));
     358         436 :                 if (nread == 0)
     359             :                         break;
     360             : 
     361         418 :                 char *buf_start = &bs->buf[bs->pos];
     362         418 :                 char *buf_end = &bs->buf[bs->len];
     363         418 :                 char *start, *end;
     364    14247341 :                 for (start = buf_start; (end = memchr(start, '\0', buf_end - start)) != NULL; start = end + 1) {
     365    14246928 :                         char *value;
     366    14246928 :                         if (!checkUTF8(start)) {
     367           3 :                                 msg = createException(SQL, "load_zero_terminated_text", SQLSTATE(42000) "malformed utf-8 byte sequence");
     368           3 :                                 goto end;
     369             :                         }
     370    14246925 :                         if (tpe == TYPE_str) {
     371    10246923 :                                         if (width > 0) {
     372     2000006 :                                                 int w = UTF8_strwidth(start);
     373     2000006 :                                                 if (w > width) {
     374           1 :                                                         msg = createException(SQL, "sql.importColumn", "string too wide for column");
     375           1 :                                                         goto end;
     376             :                                                 }
     377             :                                         }
     378             :                                         value = start;
     379             :                         } else {
     380     4000002 :                                         ssize_t n = ATOMfromstr(tpe, &buffer, &buffer_len, start, false);
     381     4000002 :                                         if (n <= 0) {
     382           1 :                                                         msg = createException(SQL, "sql.importColumn", GDK_EXCEPTION);
     383           1 :                                                         goto end;
     384             :                                         }
     385     4000001 :                                         value = buffer;
     386             :                         }
     387    14246923 :                         if (BUNappend(bat, value, false) != GDK_SUCCEED) {
     388           0 :                                         msg = createException(SQL, "sql.importColumn", GDK_EXCEPTION);
     389           0 :                                         goto end;
     390             :                         }
     391             :                 }
     392         413 :                 bs->pos = start - buf_start;
     393             :         }
     394             : 
     395             :         // It's an error to have date left after falling out of the outer loop
     396          18 :         if (bs->pos < bs->len)
     397           0 :                 bailout("unterminated string at end");
     398             : 
     399          18 : end:
     400          23 :         *eof_reached = 0;
     401          23 :         GDKfree(buffer);
     402          23 :         if (bs != NULL) {
     403          23 :                 *eof_reached = (int)bs->eof;
     404          23 :                 bs->s = NULL;
     405          23 :                 bstream_destroy(bs);
     406             :         }
     407          23 :         return msg;
     408             : }
     409             : 
     410             : static str
     411         599 : dump_zero_terminated_text(BAT *bat, stream *s, BUN start, BUN length, bool byteswap)
     412             : {
     413         599 :         (void)byteswap;
     414         599 :         const char *mal_operator = "sql.export_bin_column";
     415         599 :         str msg = MAL_SUCCEED;
     416         599 :         int tpe = BATttype(bat);
     417         599 :         assert(ATOMstorage(tpe) == TYPE_str); (void)tpe;
     418         599 :         assert(mnstr_isbinary(s));
     419             : 
     420             : 
     421         599 :         BUN end = start + length;
     422         599 :         assert(end <= BATcount(bat));
     423         599 :         BATiter bi = bat_iterator(bat);
     424    10943231 :         for (BUN p = start; p < end; p++) {
     425    10942632 :                 const char *v = BUNtvar(bi, p);
     426    10942632 :                 if (mnstr_writeStr(s, v) < 0 || mnstr_writeBte(s, 0) < 0) {
     427    10942632 :                         bailout("%s", mnstr_peek_error(s));
     428             :                 }
     429             :         }
     430             : 
     431         599 : end:
     432         599 :         bat_iterator_end(&bi);
     433         599 :         return msg;
     434             : }
     435             : 
     436             : // Some streams, in particular the mapi upload stream, sometimes read fewer
     437             : // bytes than requested. This function wraps the read in a loop to force it to
     438             : // read the whole block
     439             : static ssize_t
     440     9996006 : read_exact(stream *s, void *buffer, size_t length)
     441             : {
     442     9996006 :         char *p = buffer;
     443             : 
     444    19992963 :         while (length > 0) {
     445     9996963 :                 ssize_t nread = mnstr_read(s, p, 1, length);
     446     9996963 :                 if (nread < 0) {
     447           0 :                         return nread;
     448     9996963 :                 } else if (nread == 0) {
     449             :                         break;
     450             :                 } else {
     451     9996957 :                         p += nread;
     452     9996957 :                         length -= nread;
     453             :                 }
     454             :         }
     455             : 
     456     9996006 :         return p - (char*)buffer;
     457             : }
     458             : 
     459             : // Read BLOBs.  Every blob is preceded by a 64bit header word indicating its length.
     460             : // NULLs are indicated by length==-1
     461             : static str
     462           6 : load_blob(BAT *bat, stream *s, int *eof_reached, int width, bool byteswap)
     463             : {
     464           6 :         (void)width;
     465           6 :         const char *mal_operator = "sql.importColumn";
     466           6 :         str msg = MAL_SUCCEED;
     467           6 :         const blob *nil_value = ATOMnilptr(TYPE_blob);
     468           6 :         blob *buffer = NULL;
     469           6 :         size_t buffer_size = 0;
     470           6 :         union {
     471             :                 uint64_t length;
     472             :                 char bytes[8];
     473             :         } header;
     474             : 
     475           6 :         *eof_reached = 0;
     476             : 
     477     6000006 :         while (1) {
     478     6000006 :                 const blob *value;
     479             :                 // Read the header
     480     6000006 :                 ssize_t nread = read_exact(s, header.bytes, 8);
     481     6000006 :                 if (nread < 0) {
     482           0 :                         bailout("%s", mnstr_peek_error(s));
     483     6000006 :                 } else if (nread == 0) {
     484           6 :                         *eof_reached = 1;
     485           6 :                         break;
     486     6000000 :                 } else if (nread < 8) {
     487           0 :                         bailout("incomplete blob at end of file");
     488             :                 }
     489     6000000 :                 if (byteswap) {
     490     2000000 :                         copy_binary_convert64(&header.length);
     491             :                 }
     492             : 
     493     6000000 :                 if (header.length == ~(uint64_t)0) {
     494             :                         value = nil_value;
     495             :                 } else {
     496     4000002 :                         size_t length;
     497     4000002 :                         size_t needed;
     498             : 
     499     4000002 :                         if (header.length >= VAR_MAX) {
     500           0 :                                 bailout("blob too long");
     501             :                         }
     502     4000002 :                         length = (size_t) header.length;
     503             : 
     504             :                         // Reallocate the buffer
     505     4000002 :                         needed = sizeof(blob) + length;
     506     4000002 :                         if (buffer_size < needed) {
     507             :                                 // do not use GDKrealloc, no need to copy the old contents
     508           6 :                                 GDKfree(buffer);
     509           6 :                                 size_t allocate = needed;
     510           6 :                                 allocate += allocate / 16;   // add a little margin
     511             : #ifdef _MSC_VER
     512             : #pragma warning(suppress:4146)
     513             : #endif
     514           6 :                                 allocate += ((~allocate + 1) % 0x100000);   // round up to nearest MiB
     515           6 :                                 assert(allocate >= needed);
     516           6 :                                 buffer = GDKmalloc(allocate);
     517           6 :                                 if (!buffer) {
     518           0 :                                         msg = createException(SQL, "sql", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     519           0 :                                         goto end;
     520             :                                 }
     521             :                                 buffer_size = allocate;
     522             :                         }
     523             : 
     524             :                         // Fill the buffer
     525     4000002 :                         buffer->nitems = length;
     526     4000002 :                         if (length > 0) {
     527     3996000 :                                 nread = read_exact(s, buffer->data, length);
     528     3996000 :                                 if (nread < 0) {
     529           0 :                                         bailout("%s", mnstr_peek_error(s));
     530     3996000 :                                 } else if ((size_t)nread < length) {
     531           0 :                                         bailout("Incomplete blob at end of file");
     532             :                                 }
     533             :                         }
     534             : 
     535             :                         value = buffer;
     536             :                 }
     537             : 
     538     6000000 :                 if (BUNappend(bat, value, false) != GDK_SUCCEED) {
     539           0 :                                 msg = createException(SQL, mal_operator, GDK_EXCEPTION);
     540           0 :                                 goto end;
     541             :                 }
     542             :         }
     543             : 
     544           6 : end:
     545           6 :         GDKfree(buffer);
     546           6 :         return msg;
     547             : }
     548             : 
     549             : static str
     550           6 : dump_blob(BAT *bat, stream *s, BUN start, BUN length, bool byteswap)
     551             : {
     552           6 :         const char *mal_operator = "sql.export_bin_column";
     553           6 :         str msg = MAL_SUCCEED;
     554           6 :         int tpe = BATttype(bat);
     555           6 :         assert(ATOMstorage(tpe) == TYPE_blob); (void)tpe;
     556           6 :         assert(mnstr_isbinary(s));
     557             : 
     558           6 :         BUN end = start + length;
     559           6 :         assert(end <= BATcount(bat));
     560           6 :         BATiter bi = bat_iterator(bat);
     561           6 :         uint64_t nil_header = ~(uint64_t)0;
     562     6000006 :         for (BUN p = start; p < end; p++) {
     563     6000000 :                 const blob *b = BUNtvar(bi, p);
     564     6000000 :                 uint64_t header = is_blob_nil(b) ? nil_header : (uint64_t)b->nitems;
     565     6000000 :                 if (byteswap)
     566     2000000 :                         copy_binary_convert64(&header);
     567     6000000 :                 if (mnstr_write(s, &header, 8, 1) != 1) {
     568           0 :                         bailout("%s", mnstr_peek_error(s));
     569             :                 }
     570     6000000 :                 if (!is_blob_nil(b) && mnstr_write(s, b->data,b->nitems, 1) != 1) {
     571     6000000 :                         bailout("%s", mnstr_peek_error(s));
     572             :                 }
     573             :         }
     574             : 
     575           6 : end:
     576           6 :         bat_iterator_end(&bi);
     577           6 :         return msg;
     578             : 
     579             : }
     580             : 
     581             : 
     582             : static struct type_record_t type_recs[] = {
     583             : 
     584             :         // no conversion, no byteswapping
     585             :         { "bte", "bte", .encoder_trivial=true, .decoder_trivial=true},
     586             :         { "uuid", "uuid", .encoder_trivial=true, .decoder_trivial=true},
     587             :         { "bit", "bit", .encoder_trivial=true, .decoder_trivial=true, .validate=validate_bit },
     588             : 
     589             :         // vanilla integer types
     590             :         { "sht", "sht", .trivial_if_no_byteswap=true, .decoder=byteswap_sht, .encoder=byteswap_sht, .validate=validate_sht },
     591             :         { "int", "int", .trivial_if_no_byteswap=true, .decoder=byteswap_int, .encoder=byteswap_int, .validate=validate_int },
     592             :         { "lng", "lng", .trivial_if_no_byteswap=true, .decoder=byteswap_lng, .encoder=byteswap_lng, .validate=validate_lng },
     593             :         { "flt", "flt", .trivial_if_no_byteswap=true, .decoder=byteswap_flt, .encoder=byteswap_flt},
     594             :         { "dbl", "dbl", .trivial_if_no_byteswap=true, .decoder=byteswap_dbl, .encoder=byteswap_dbl},
     595             : #ifdef HAVE_HGE
     596             :         { "hge", "hge", .trivial_if_no_byteswap=true, .decoder=byteswap_hge, .encoder=byteswap_hge, .validate=validate_hge },
     597             : #endif
     598             : 
     599             :         { "blob", "blob", .loader=load_blob, .dumper=dump_blob },
     600             : 
     601             :         // \0-terminated text records
     602             :         { "str", "str", .loader=load_zero_terminated_text, .dumper=dump_zero_terminated_text },
     603             :         { "url", "url", .loader=load_zero_terminated_text, .dumper=dump_zero_terminated_text },
     604             :         { "json", "json", .loader=load_zero_terminated_text, .dumper=dump_zero_terminated_text },
     605             : 
     606             :         // temporal types have record size different from the underlying gdk type
     607             :         { "date", "date", .decoder=decode_date, .encoder=encode_date, .record_size=sizeof(copy_binary_date), },
     608             :         { "daytime", "daytime", .decoder=decode_time, .encoder=encode_time, .record_size=sizeof(copy_binary_time), },
     609             :         { "timestamp", "timestamp", .decoder=decode_timestamp, .encoder=encode_timestamp, .record_size=sizeof(copy_binary_timestamp), },
     610             : };
     611             : 
     612             : 
     613             : type_record_t*
     614        3599 : find_type_rec(const char *name)
     615             : {
     616        3599 :         struct type_record_t *end = (struct type_record_t*)((char *)type_recs + sizeof(type_recs));
     617       23803 :         for (struct type_record_t *t = &type_recs[0]; t < end; t++)
     618       23803 :                 if (strcmp(t->method, name) == 0)
     619        3599 :                         return t;
     620             :         return NULL;
     621             : }
     622             : 
     623             : bool
     624        3232 : can_dump_binary_column(type_record_t *rec)
     625             : {
     626        3232 :         return rec->encoder_trivial || rec->dumper || rec->encoder;
     627             : }

Generated by: LCOV version 1.14