/* * Drizzle Client & Protocol Library * * Copyright (C) 2008 Eric Day (eday@oddments.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * * The names of its contributors may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * @file * @brief Field definitions */ #include /* * Client definitions */ drizzle_field_t drizzle_field_read(drizzle_result_st *result, size_t *offset, size_t *size, size_t *total, drizzle_return_t *ret_ptr) { if (drizzle_state_none(result->con)) { if (result->field_current == result->column_count) { *ret_ptr= DRIZZLE_RETURN_ROW_END; return NULL; } drizzle_state_push(result->con, drizzle_state_field_read); } *ret_ptr= drizzle_state_loop(result->con); if (*ret_ptr == DRIZZLE_RETURN_OK && result->options & DRIZZLE_RESULT_ROW_BREAK) { *ret_ptr= DRIZZLE_RETURN_ROW_BREAK; } *offset= result->field_offset; *size= result->field_size; *total= result->field_total; return result->field; } drizzle_field_t drizzle_field_buffer(drizzle_result_st *result, size_t *total, drizzle_return_t *ret_ptr) { drizzle_field_t field; size_t offset= 0; size_t size= 0; field= drizzle_field_read(result, &offset, &size, total, ret_ptr); if (*ret_ptr != DRIZZLE_RETURN_OK) return NULL; if (field == NULL) { *total= 0; return NULL; } if (result->field_buffer == NULL) { result->field_buffer= malloc((*total) + 1); if (result->field_buffer == NULL) { drizzle_set_error(result->con->drizzle, "drizzle_field_buffer", "malloc"); *ret_ptr= DRIZZLE_RETURN_MEMORY; return NULL; } } memcpy(result->field_buffer + offset, field, size); while ((offset + size) != (*total)) { field= drizzle_field_read(result, &offset, &size, total, ret_ptr); if (*ret_ptr != DRIZZLE_RETURN_OK) return NULL; memcpy(result->field_buffer + offset, field, size); } field= result->field_buffer; result->field_buffer= NULL; field[*total]= 0; return field; } void drizzle_field_free(drizzle_field_t field) { free(field); } /* * Server definitions */ drizzle_return_t drizzle_field_write(drizzle_result_st *result, const drizzle_field_t field, size_t size, size_t total) { drizzle_return_t ret; if (drizzle_state_none(result->con)) { if (result->options & DRIZZLE_RESULT_ROW_BREAK) { result->options&= (drizzle_result_options_t)~DRIZZLE_RESULT_ROW_BREAK; result->field= field; result->field_size= size; } else { result->field= field; result->field_size= size; result->field_offset= 0; result->field_total= total; } drizzle_state_push(result->con, drizzle_state_field_write); } else if (result->field == NULL) { result->field= field; result->field_size= size; } ret= drizzle_state_loop(result->con); if (ret == DRIZZLE_RETURN_PAUSE) ret= DRIZZLE_RETURN_OK; return ret; } /* * Internal state functions. */ drizzle_return_t drizzle_state_field_read(drizzle_con_st *con) { drizzle_return_t ret; drizzle_log_debug(con->drizzle, "drizzle_state_field_read"); if (con->buffer_size == 0) { drizzle_state_push(con, drizzle_state_read); return DRIZZLE_RETURN_OK; } con->result->field_offset+= con->result->field_size; if (con->result->field_offset == con->result->field_total) { con->result->field_offset= 0; con->result->field_size= 0; con->result->field_total= (size_t)drizzle_unpack_length(con, &ret); if (ret == DRIZZLE_RETURN_NULL_SIZE) { con->result->field= NULL; con->result->field_current++; drizzle_state_pop(con); return DRIZZLE_RETURN_OK; } else if (ret != DRIZZLE_RETURN_OK) { if (ret == DRIZZLE_RETURN_IO_WAIT) { drizzle_state_push(con, drizzle_state_read); return DRIZZLE_RETURN_OK; } return ret; } drizzle_log_debug(con->drizzle, "field_offset= %zu, field_size= %zu, field_total= %zu", con->result->field_offset, con->result->field_size, con->result->field_total); if ((size_t)(con->buffer_size) >= con->result->field_total) con->result->field_size= con->result->field_total; else con->result->field_size= con->buffer_size; } else { if ((con->result->field_offset + con->buffer_size) >= con->result->field_total) { con->result->field_size= (con->result->field_total - con->result->field_offset); } else con->result->field_size= con->buffer_size; } /* This is a special case when a row is larger than the packet size. */ if (con->result->field_size > (size_t)con->packet_size) { con->result->field_size= con->packet_size; if (con->options & DRIZZLE_CON_RAW_PACKET) con->result->options|= DRIZZLE_RESULT_ROW_BREAK; else { drizzle_state_pop(con); drizzle_state_push(con, drizzle_state_packet_read); drizzle_state_push(con, drizzle_state_field_read); } } con->result->field= (char *)con->buffer_ptr; con->buffer_ptr+= con->result->field_size; con->buffer_size-= con->result->field_size; con->packet_size-= con->result->field_size; drizzle_log_debug(con->drizzle, "field_offset= %zu, field_size= %zu, field_total= %zu", con->result->field_offset, con->result->field_size, con->result->field_total); if ((con->result->field_offset + con->result->field_size) == con->result->field_total) { if (con->result->column_buffer != NULL && con->result->column_buffer[con->result->field_current].max_size < con->result->field_total) { con->result->column_buffer[con->result->field_current].max_size= con->result->field_total; } con->result->field_current++; } if (con->result->field_total == 0 || con->result->field_size > 0 || con->packet_size == 0) { drizzle_state_pop(con); } return DRIZZLE_RETURN_OK; } drizzle_return_t drizzle_state_field_write(drizzle_con_st *con) { uint8_t *start= con->buffer_ptr + con->buffer_size; uint8_t *ptr; size_t free_size; drizzle_result_st *result= con->result; drizzle_log_debug(con->drizzle, "drizzle_state_field_write"); if (result->field == NULL && result->field_total != 0) return DRIZZLE_RETURN_PAUSE; free_size= (size_t)DRIZZLE_MAX_BUFFER_SIZE - (size_t)(start - con->buffer); ptr= start; if (result->field_offset == 0) { /* Make sure we can fit the max length and 1 byte of data in (9 + 1). */ if (free_size < 10) { drizzle_state_push(con, drizzle_state_write); return DRIZZLE_RETURN_OK; } if (result->field == NULL) { ptr[0]= 251; ptr++; } else if (result->field_total == 0) { ptr[0]= 0; ptr++; } else ptr= drizzle_pack_length(result->field_total, ptr); free_size-= (size_t)(ptr - start); con->buffer_size+= (size_t)(ptr - start); con->packet_size-= (size_t)(ptr - start); } else if (result->field_size > DRIZZLE_BUFFER_COPY_THRESHOLD) { /* Flush the internal buffer first. */ if (con->buffer_size != 0) { drizzle_state_push(con, drizzle_state_write); return DRIZZLE_RETURN_OK; } /* We do this to write directly from the field buffer to avoid memcpy(). */ con->buffer_ptr= (uint8_t *)result->field; con->buffer_size= result->field_size; con->packet_size-= result->field_size; result->field_offset+= result->field_size; result->field= NULL; if (result->field_offset == result->field_total) drizzle_state_pop(con); else if (con->packet_size == 0) { con->result->options|= DRIZZLE_RESULT_ROW_BREAK; drizzle_state_pop(con); } drizzle_state_push(con, drizzle_state_write); return DRIZZLE_RETURN_OK; } if (result->field_size == 0) drizzle_state_pop(con); else { if (result->field_size < free_size) free_size= result->field_size; memcpy(ptr, result->field, free_size); result->field_offset+= free_size; con->buffer_size+= free_size; con->packet_size-= free_size; if (result->field_offset == result->field_total) { result->field= NULL; drizzle_state_pop(con); } else { if (con->packet_size == 0) { con->result->options|= DRIZZLE_RESULT_ROW_BREAK; drizzle_state_pop(con); } if (result->field_size == free_size) result->field= NULL; else { result->field+= free_size; result->field_size-= free_size; drizzle_state_push(con, drizzle_state_write); } } } return DRIZZLE_RETURN_OK; }