Changeset: 5d4b4ab2be35 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=5d4b4ab2be35 Modified Files: clients/mapilib/mapi.c common/utils/conversion.c common/utils/conversion.h monetdb5/modules/atoms/blob.c sql/backends/monet5/sql_result.c Branch: protocol Log Message:
Binary transfer of blobs. diffs (truncated from 343 to 300 lines): diff --git a/clients/mapilib/mapi.c b/clients/mapilib/mapi.c --- a/clients/mapilib/mapi.c +++ b/clients/mapilib/mapi.c @@ -837,6 +837,7 @@ struct MapiColumn { void *null_value; char* buffer_ptr; char *dynamic_write_buf; + size_t dynamic_write_bufsiz; char write_buf[COLBUFSIZ]; mapi_converter converter; }; @@ -4139,6 +4140,25 @@ static char* mapi_convert_timestamptz(st return (char*) col->write_buf; } +static char* mapi_convert_blob(struct MapiColumn *col) { + lng length = *((lng*) col->buffer_ptr); + if (length < 0) { + return NULL; + } + if (24 + 3 * length > col->dynamic_write_bufsiz) { + col->dynamic_write_bufsiz = (size_t) 24 + 3 * length; + if (col->dynamic_write_buf) free(col->dynamic_write_buf); + col->dynamic_write_buf = malloc(col->dynamic_write_bufsiz); + if (!col->dynamic_write_buf) { + return NULL; + } + } + if (conversion_blob_to_string(col->dynamic_write_buf, col->dynamic_write_bufsiz, col->buffer_ptr + sizeof(lng), length) < 0) { + return NULL; + } + return (char*) col->dynamic_write_buf; +} + static char* mapi_convert_null(struct MapiColumn *col) { (void) col; return NULL; @@ -4271,14 +4291,18 @@ read_into_cache(MapiHdl hdl, int lookahe result->fields[i].typelen = typelen; result->fields[i].columnlength = (int) column_print_length; result->fields[i].dynamic_write_buf = NULL; + result->fields[i].dynamic_write_bufsiz = 0; result->fields[i].converter = NULL; - if (result->fields[i].null_value == NULL) { + if (strcasecmp(type_sql_name, "blob") == 0) { + result->fields[i].converter = (mapi_converter) mapi_convert_blob; + } else if (result->fields[i].null_value == NULL) { result->fields[i].converter = (mapi_converter) mapi_convert_null; } else if (strcasecmp(type_sql_name, "varchar") == 0 || strcasecmp(type_sql_name, "char") == 0) { if (typelen > 0) { result->fields[i].converter = (mapi_converter) mapi_convert_varchar; - result->fields[i].dynamic_write_buf = malloc(result->fields[i].typelen * sizeof(char)); + result->fields[i].dynamic_write_bufsiz = result->fields[i].typelen * sizeof(char); + result->fields[i].dynamic_write_buf = malloc(result->fields[i].dynamic_write_bufsiz); } else { result->fields[i].converter = (mapi_converter) mapi_convert_clob; } @@ -5562,7 +5586,9 @@ mapi_fetch_row(MapiHdl hdl) mapi_hdl_check(hdl, "mapi_fetch_row"); if (result && result->prot10_resultset) { char* buf; + // check if we are done reading this result set if (result->rows_read >= result->row_count) { + // if we are done, check if there is another result set we have to read do { if ((reply = mapi_fetch_line(hdl)) == NULL) return 0; @@ -5573,15 +5599,14 @@ mapi_fetch_row(MapiHdl hdl) } return 0; } - // if not, check if our cache is empty + // if we are not done, check if our cache is empty if (result->rows_read >= result->tuple_count) { // if our cache is empty, we read data from the socket lng nrows = -1; result->cur_row = 1; +#ifdef CONTINUATION_MESSAGE // first we write a prompt to the server indicating that we want another block of the result set - -#ifdef CONTINUATION_MESSAGE if (!mnstr_writeChr(hdl->mid->to, 42) || mnstr_flush(hdl->mid->to)) { return hdl->mid->error; } @@ -5649,11 +5674,25 @@ mapi_fetch_row(MapiHdl hdl) bs2_resetbuf(hdl->mid->from); } } else { + // the requested row is in the cache, simply move each column pointer to the next row for (i = 0; i < (size_t) result->fieldcnt; i++) { if (result->fields[i].typelen < 0) { // variable-length column - result->fields[i].buffer_ptr += strlen(result->fields[i].buffer_ptr) + 1; + if (result->fields[i].converter == (mapi_converter) mapi_convert_blob) { + // blobs are prefixed by their length + // so we can read the length to know how to get to the next blob + lng length = *((lng*) result->fields[i].buffer_ptr); + result->fields[i].buffer_ptr += sizeof(lng); + if (length > 0) { + result->fields[i].buffer_ptr += length; + } + } else { + // strings are null-terminated + // so we call strlen to figure out how far to jump + result->fields[i].buffer_ptr += strlen(result->fields[i].buffer_ptr) + 1; + } } else { + // fixed-length column, so we just jump forward typelen result->fields[i].buffer_ptr += result->fields[i].typelen; } } diff --git a/common/utils/conversion.c b/common/utils/conversion.c --- a/common/utils/conversion.c +++ b/common/utils/conversion.c @@ -350,4 +350,38 @@ conversion_epoch_tz_to_string(char *dst, return conversion_epoch_optional_tz_to_string(dst, len, src, null_value, 1, timezone_diff); } +static char hexit[] = "0123456789ABCDEF"; +int +conversion_blob_to_string(char *dst, int len, const char *blobdata, size_t nitems) +{ + char *s; + size_t i; + size_t expectedlen; + + if (nitems == ~(size_t) 0) + expectedlen = 4; + else + expectedlen = 24 + (nitems * 3); + + if (len < expectedlen) return -1; + + if (nitems == ~(size_t) 0) { + strcpy(dst, NULL_STRING); + return 3; + } + + strcpy(dst, "\0"); + s = dst; + + for (i = 0; i < nitems; i++) { + int val = (blobdata[i] >> 4) & 15; + + *s++ = hexit[val]; + val = blobdata[i] & 15; + *s++ = hexit[val]; + } + *s = '\0'; + return (int) (s - dst); /* 64bit: check for overflow */ +} + diff --git a/common/utils/conversion.h b/common/utils/conversion.h --- a/common/utils/conversion.h +++ b/common/utils/conversion.h @@ -70,4 +70,5 @@ int conversion_epoch_to_string(char *dst // *src is time since epoch in ms int conversion_epoch_tz_to_string(char *dst, int len, const lng *src, lng null_value, int timezone_diff); +int conversion_blob_to_string(char *dst, int len, const char *blobdata, size_t nitems); #endif diff --git a/monetdb5/modules/atoms/blob.c b/monetdb5/modules/atoms/blob.c --- a/monetdb5/modules/atoms/blob.c +++ b/monetdb5/modules/atoms/blob.c @@ -226,23 +226,26 @@ sqlblob_tostr(str *tostr, int *l, const return 0; *l = (int) expectedlen; } - if (p->nitems == ~(size_t) 0) { - strcpy(*tostr, "nil"); - return 3; - } - strcpy(*tostr, "\0"); - s = *tostr; + return conversion_blob_to_string(*tostr, expectedlen, p->data, p->nitems); - for (i = 0; i < p->nitems; i++) { - int val = (p->data[i] >> 4) & 15; + // if (p->nitems == ~(size_t) 0) { + // strcpy(*tostr, "nil"); + // return 3; + // } - *s++ = hexit[val]; - val = p->data[i] & 15; - *s++ = hexit[val]; - } - *s = '\0'; - return (int) (s - *tostr); /* 64bit: check for overflow */ + // strcpy(*tostr, "\0"); + // s = *tostr; + + // for (i = 0; i < p->nitems; i++) { + // int val = (p->data[i] >> 4) & 15; + + // *s++ = hexit[val]; + // val = p->data[i] & 15; + // *s++ = hexit[val]; + // } + // *s = '\0'; + // return (int) (s - *tostr); /* 64bit: check for overflow */ } static int diff --git a/sql/backends/monet5/sql_result.c b/sql/backends/monet5/sql_result.c --- a/sql/backends/monet5/sql_result.c +++ b/sql/backends/monet5/sql_result.c @@ -1828,6 +1828,7 @@ static int type_supports_binary_transfer type->eclass == EC_CHAR || type->eclass == EC_STRING || type->eclass == EC_DEC || + type->eclass == EC_BLOB || type->eclass == EC_FLT || type->eclass == EC_NUM || type->eclass == EC_DATE || @@ -1938,6 +1939,10 @@ int mvc_export_resultset_prot10(mvc *m, goto cleanup; } + if (type->eclass == EC_BLOB) { + nil_len = 0; + } + // write NULL values for this column to the stream // NULL values are encoded as <size:int> <NULL value> (<size> is always <typelen> for fixed size columns) if (!mnstr_writeInt(s, nil_len)) { @@ -1959,40 +1964,42 @@ int mvc_export_resultset_prot10(mvc *m, iterators[i] = bat_iterator(BATdescriptor(ret)); } - switch(ATOMstorage(mtype)) { - case TYPE_str: - retval = write_str_term(s, str_nil); - break; - case TYPE_bit: - case TYPE_bte: - retval = mnstr_writeBte(s, bte_nil); - break; - case TYPE_sht: - retval = mnstr_writeSht(s, sht_nil); - break; - case TYPE_int: - retval = mnstr_writeInt(s, int_nil); - break; - case TYPE_lng: - retval = mnstr_writeLng(s, lng_nil); - break; - case TYPE_flt: - retval = mnstr_writeFlt(s, flt_nil); - break; - case TYPE_dbl: - retval = mnstr_writeDbl(s, dbl_nil); - break; -#ifdef HAVE_HGE - case TYPE_hge: - retval = mnstr_writeHge(s, hge_nil); - break; -#endif - case TYPE_void: - break; - default: - assert(0); - fres = -1; - goto cleanup; + if (type->eclass != EC_BLOB) { + switch(ATOMstorage(mtype)) { + case TYPE_str: + retval = write_str_term(s, str_nil); + break; + case TYPE_bit: + case TYPE_bte: + retval = mnstr_writeBte(s, bte_nil); + break; + case TYPE_sht: + retval = mnstr_writeSht(s, sht_nil); + break; + case TYPE_int: + retval = mnstr_writeInt(s, int_nil); + break; + case TYPE_lng: + retval = mnstr_writeLng(s, lng_nil); + break; + case TYPE_flt: + retval = mnstr_writeFlt(s, flt_nil); + break; + case TYPE_dbl: + retval = mnstr_writeDbl(s, dbl_nil); + break; + #ifdef HAVE_HGE + case TYPE_hge: + retval = mnstr_writeHge(s, hge_nil); + break; + #endif + case TYPE_void: + break; + default: _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list