Drizzled Public API Documentation

result.c
Go to the documentation of this file.
00001 /*
00002  * Drizzle Client & Protocol Library
00003  *
00004  * Copyright (C) 2008 Eric Day (eday@oddments.org)
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions are
00009  * met:
00010  *
00011  *     * Redistributions of source code must retain the above copyright
00012  * notice, this list of conditions and the following disclaimer.
00013  *
00014  *     * Redistributions in binary form must reproduce the above
00015  * copyright notice, this list of conditions and the following disclaimer
00016  * in the documentation and/or other materials provided with the
00017  * distribution.
00018  *
00019  *     * The names of its contributors may not be used to endorse or
00020  * promote products derived from this software without specific prior
00021  * written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00026  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  */
00036 
00042 #include "common.h"
00043 
00044 /*
00045  * Common definitions
00046  */
00047 
00048 drizzle_result_st *drizzle_result_create(drizzle_con_st *con,
00049                                          drizzle_result_st *result)
00050 {
00051   if (result == NULL)
00052   {
00053     result= malloc(sizeof(drizzle_result_st));
00054     if (result == NULL)
00055     {
00056       drizzle_set_error(con->drizzle, "drizzle_result_create", "malloc");
00057       return NULL;
00058     }
00059 
00060     memset(result, 0, sizeof(drizzle_result_st));
00061     result->options|= DRIZZLE_RESULT_ALLOCATED;
00062   }
00063   else
00064     memset(result, 0, sizeof(drizzle_result_st));
00065 
00066   result->con= con;
00067   con->result= result;
00068 
00069   if (con->result_list)
00070     con->result_list->prev= result;
00071   result->next= con->result_list;
00072   con->result_list= result;
00073   con->result_count++;
00074 
00075   return result;
00076 }
00077 
00078 drizzle_result_st *drizzle_result_clone(drizzle_con_st *con,
00079                                         drizzle_result_st *result,
00080                                         drizzle_result_st *from)
00081 {
00082   result= drizzle_result_create(con, result);
00083   if (result == NULL)
00084     return NULL;
00085 
00086   result->options|= (from->options &
00087                      (drizzle_result_options_t)~DRIZZLE_RESULT_ALLOCATED);
00088 
00089   drizzle_result_set_info(result, from->info);
00090   result->error_code= from->error_code;
00091   drizzle_result_set_sqlstate(result, from->sqlstate);
00092   result->warning_count= from->warning_count;
00093   result->insert_id= from->insert_id;
00094   result->affected_rows= from->affected_rows;
00095   result->column_count= from->column_count;
00096   result->row_count= from->row_count;
00097 
00098   return result;
00099 }
00100 
00101 void drizzle_result_free(drizzle_result_st *result)
00102 {
00103   drizzle_column_st *column;
00104   uint64_t x;
00105 
00106   for (column= result->column_list; column != NULL; column= result->column_list)
00107     drizzle_column_free(column);
00108 
00109   if (result->column_buffer != NULL)
00110     free(result->column_buffer);
00111 
00112   if (result->options & DRIZZLE_RESULT_BUFFER_ROW)
00113   {
00114     for (x= 0; x < result->row_count; x++)
00115       drizzle_row_free(result, result->row_list[x]);
00116 
00117     free(result->row_list);
00118     free(result->field_sizes_list);
00119   }
00120 
00121   if (result->con)
00122   {
00123     result->con->result_count--;
00124     if (result->con->result_list == result)
00125       result->con->result_list= result->next;
00126   }
00127   if (result->prev)
00128     result->prev->next= result->next;
00129   if (result->next)
00130     result->next->prev= result->prev;
00131 
00132   if (result->options & DRIZZLE_RESULT_ALLOCATED)
00133     free(result);
00134 }
00135 
00136 void drizzle_result_free_all(drizzle_con_st *con)
00137 {
00138   while (con->result_list != NULL)
00139     drizzle_result_free(con->result_list);
00140 }
00141 
00142 drizzle_con_st *drizzle_result_drizzle_con(drizzle_result_st *result)
00143 {
00144   return result->con;
00145 }
00146 
00147 bool drizzle_result_eof(drizzle_result_st *result)
00148 {
00149   return result->options & DRIZZLE_RESULT_EOF_PACKET;
00150 }
00151 
00152 const char *drizzle_result_info(drizzle_result_st *result)
00153 {
00154   return result->info;
00155 }
00156 
00157 const char *drizzle_result_error(drizzle_result_st *result)
00158 {
00159   return result->info;
00160 }
00161 
00162 uint16_t drizzle_result_error_code(drizzle_result_st *result)
00163 {
00164   return result->error_code;
00165 }
00166 
00167 const char *drizzle_result_sqlstate(drizzle_result_st *result)
00168 {
00169   return result->sqlstate;
00170 }
00171 
00172 uint16_t drizzle_result_warning_count(drizzle_result_st *result)
00173 {
00174   return result->warning_count;
00175 }
00176 
00177 uint64_t drizzle_result_insert_id(drizzle_result_st *result)
00178 {
00179   return result->insert_id;
00180 }
00181 
00182 uint64_t drizzle_result_affected_rows(drizzle_result_st *result)
00183 {
00184   return result->affected_rows;
00185 }
00186 
00187 uint16_t drizzle_result_column_count(drizzle_result_st *result)
00188 {
00189   return result->column_count;
00190 }
00191 
00192 uint64_t drizzle_result_row_count(drizzle_result_st *result)
00193 {
00194   return result->row_count;
00195 }
00196 
00197 /*
00198  * Client definitions
00199  */
00200 
00201 drizzle_result_st *drizzle_result_read(drizzle_con_st *con,
00202                                        drizzle_result_st *result,
00203                                        drizzle_return_t *ret_ptr)
00204 {
00205   if (drizzle_state_none(con))
00206   {
00207     con->result= drizzle_result_create(con, result);
00208     if (con->result == NULL)
00209     {
00210       *ret_ptr= DRIZZLE_RETURN_MEMORY;
00211       return NULL;
00212     }
00213 
00214     drizzle_state_push(con, drizzle_state_result_read);
00215     drizzle_state_push(con, drizzle_state_packet_read);
00216   }
00217 
00218   *ret_ptr= drizzle_state_loop(con);
00219   return con->result;
00220 }
00221 
00222 drizzle_return_t drizzle_result_buffer(drizzle_result_st *result)
00223 {
00224   drizzle_return_t ret;
00225   drizzle_row_t row;
00226   drizzle_row_t *row_list;
00227   size_t **field_sizes_list;
00228 
00229   if (!(result->options & DRIZZLE_RESULT_BUFFER_COLUMN))
00230   {
00231     ret= drizzle_column_buffer(result);
00232     if (ret != DRIZZLE_RETURN_OK)
00233       return ret;
00234   }
00235 
00236   if (result->column_count == 0)
00237   {
00238     result->options|= DRIZZLE_RESULT_BUFFER_ROW;
00239     return DRIZZLE_RETURN_OK;
00240   }
00241 
00242   while (1)
00243   {
00244     row= drizzle_row_buffer(result, &ret);
00245     if (ret != DRIZZLE_RETURN_OK)
00246       return ret;
00247 
00248     if (row == NULL)
00249       break;
00250 
00251     if (result->row_list_size < result->row_count)
00252     {
00253       row_list= realloc(result->row_list, sizeof(drizzle_row_t) *
00254                         ((size_t)(result->row_list_size) +
00255                          DRIZZLE_ROW_GROW_SIZE));
00256       if (row_list == NULL)
00257       {
00258         drizzle_row_free(result, row);
00259         drizzle_set_error(result->con->drizzle, "drizzle_result_buffer",
00260                           "realloc");
00261         return DRIZZLE_RETURN_MEMORY;
00262       }
00263 
00264       result->row_list= row_list;
00265 
00266       field_sizes_list= realloc(result->field_sizes_list, sizeof(size_t *) *
00267                                 ((size_t)(result->row_list_size) +
00268                                  DRIZZLE_ROW_GROW_SIZE));
00269       if (field_sizes_list == NULL)
00270       {
00271         drizzle_row_free(result, row);
00272         drizzle_set_error(result->con->drizzle, "drizzle_result_buffer",
00273                           "realloc");
00274         return DRIZZLE_RETURN_MEMORY;
00275       }
00276 
00277       result->field_sizes_list= field_sizes_list;
00278 
00279       result->row_list_size+= DRIZZLE_ROW_GROW_SIZE;
00280     }
00281 
00282     result->row_list[result->row_current - 1]= row;
00283     result->field_sizes_list[result->row_current - 1]= result->field_sizes;
00284   }
00285 
00286   result->options|= DRIZZLE_RESULT_BUFFER_ROW;
00287   return DRIZZLE_RETURN_OK;
00288 }
00289 
00290 size_t drizzle_result_row_size(drizzle_result_st *result)
00291 {
00292   return result->con->packet_size;
00293 }
00294 
00295 /*
00296  * Server definitions
00297  */
00298 
00299 drizzle_return_t drizzle_result_write(drizzle_con_st *con,
00300                                       drizzle_result_st *result, bool flush)
00301 {
00302   if (drizzle_state_none(con))
00303   {
00304     con->result= result;
00305 
00306     if (flush)
00307       drizzle_state_push(con, drizzle_state_write);
00308 
00309     drizzle_state_push(con, drizzle_state_result_write);
00310   }
00311 
00312   return drizzle_state_loop(con);
00313 }
00314 
00315 void drizzle_result_set_row_size(drizzle_result_st *result, size_t size)
00316 {
00317   result->con->packet_size= size;
00318 }
00319 
00320 void drizzle_result_calc_row_size(drizzle_result_st *result,
00321                                   const drizzle_field_t *field,
00322                                   const size_t *size)
00323 {
00324   uint16_t x;
00325 
00326   result->con->packet_size= 0;
00327 
00328   for (x= 0; x < result->column_count; x++)
00329   {
00330     if (field[x] == NULL)
00331       result->con->packet_size++;
00332     else if (size[x] < 251)
00333       result->con->packet_size+= (1 + size[x]);
00334     else if (size[x] < 65536)
00335       result->con->packet_size+= (3 + size[x]);
00336     else if (size[x] < 16777216)
00337       result->con->packet_size+= (4 + size[x]);
00338     else
00339       result->con->packet_size+= (9 + size[x]);
00340   }
00341 }
00342 
00343 void drizzle_result_set_eof(drizzle_result_st *result, bool is_eof)
00344 {
00345   if (is_eof)
00346     result->options|= DRIZZLE_RESULT_EOF_PACKET;
00347   else
00348     result->options&= (drizzle_result_options_t)~DRIZZLE_RESULT_EOF_PACKET;
00349 }
00350 
00351 void drizzle_result_set_info(drizzle_result_st *result, const char *info)
00352 {
00353   if (info == NULL)
00354     result->info[0]= 0;
00355   else
00356   {
00357     strncpy(result->info, info, DRIZZLE_MAX_INFO_SIZE);
00358     result->info[DRIZZLE_MAX_INFO_SIZE - 1]= 0;
00359   }
00360 }
00361 
00362 void drizzle_result_set_error(drizzle_result_st *result, const char *error)
00363 {
00364   drizzle_result_set_info(result, error);
00365 }
00366 
00367 void drizzle_result_set_error_code(drizzle_result_st *result,
00368                                    uint16_t error_code)
00369 {
00370   result->error_code= error_code;
00371 }
00372 
00373 void drizzle_result_set_sqlstate(drizzle_result_st *result,
00374                                  const char *sqlstate)
00375 {
00376   if (sqlstate == NULL)
00377     result->sqlstate[0]= 0;
00378   else
00379   {
00380     strncpy(result->sqlstate, sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE + 1);
00381     result->sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE]= 0;
00382   }
00383 }
00384 
00385 void drizzle_result_set_warning_count(drizzle_result_st *result,
00386                                       uint16_t warning_count)
00387 {
00388   result->warning_count= warning_count;
00389 }
00390 
00391 void drizzle_result_set_insert_id(drizzle_result_st *result,
00392                                   uint64_t insert_id)
00393 {
00394   result->insert_id= insert_id;
00395 }
00396 
00397 void drizzle_result_set_affected_rows(drizzle_result_st *result,
00398                                       uint64_t affected_rows)
00399 {
00400   result->affected_rows= affected_rows;
00401 }
00402 
00403 void drizzle_result_set_column_count(drizzle_result_st *result,
00404                                      uint16_t column_count)
00405 {
00406   result->column_count= column_count;
00407 }
00408 
00409 /*
00410  * Internal state functions.
00411  */
00412 
00413 drizzle_return_t drizzle_state_result_read(drizzle_con_st *con)
00414 {
00415   drizzle_return_t ret;
00416 
00417   drizzle_log_debug(con->drizzle, "drizzle_state_result_read");
00418 
00419   /* Assume the entire result packet will fit in the buffer. */
00420   if (con->buffer_size < con->packet_size)
00421   {
00422     drizzle_state_push(con, drizzle_state_read);
00423     return DRIZZLE_RETURN_OK;
00424   }
00425 
00426   if (con->buffer_ptr[0] == 0)
00427   {
00428     con->buffer_ptr++;
00429     /* We can ignore the returns since we've buffered the entire packet. */
00430     con->result->affected_rows= drizzle_unpack_length(con, &ret);
00431     con->result->insert_id= drizzle_unpack_length(con, &ret);
00432     con->status= drizzle_get_byte2(con->buffer_ptr);
00433     con->result->warning_count= drizzle_get_byte2(con->buffer_ptr + 2);
00434     con->buffer_ptr+= 4;
00435     con->buffer_size-= 5;
00436     con->packet_size-= 5;
00437     if (con->packet_size > 0)
00438     {
00439       /* Skip one byte for message size. */
00440       con->buffer_ptr+= 1;
00441       con->buffer_size-= 1;
00442       con->packet_size-= 1;
00443     }
00444     ret= DRIZZLE_RETURN_OK;
00445   }
00446   else if (con->buffer_ptr[0] == 254)
00447   {
00448     con->result->options= DRIZZLE_RESULT_EOF_PACKET;
00449     con->result->warning_count= drizzle_get_byte2(con->buffer_ptr + 1);
00450     con->status= drizzle_get_byte2(con->buffer_ptr + 3);
00451     con->buffer_ptr+= 5;
00452     con->buffer_size-= 5;
00453     con->packet_size-= 5;
00454     ret= DRIZZLE_RETURN_OK;
00455   }
00456   else if (con->buffer_ptr[0] == 255)
00457   {
00458     con->result->error_code= drizzle_get_byte2(con->buffer_ptr + 1);
00459     con->drizzle->error_code= con->result->error_code;
00460     /* Byte 3 is always a '#' character, skip it. */
00461     memcpy(con->result->sqlstate, con->buffer_ptr + 4,
00462            DRIZZLE_MAX_SQLSTATE_SIZE);
00463     con->result->sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE]= 0;
00464     memcpy(con->drizzle->sqlstate, con->result->sqlstate,
00465            DRIZZLE_MAX_SQLSTATE_SIZE + 1);
00466     con->buffer_ptr+= 9;
00467     con->buffer_size-= 9;
00468     con->packet_size-= 9;
00469     ret= DRIZZLE_RETURN_ERROR_CODE;
00470   }
00471   else
00472   {
00473     /* We can ignore the return since we've buffered the entire packet. */
00474     con->result->column_count= (uint16_t)drizzle_unpack_length(con, &ret);
00475     ret= DRIZZLE_RETURN_OK;
00476   }
00477 
00478   if (con->packet_size > 0)
00479   {
00480     snprintf(con->drizzle->last_error, DRIZZLE_MAX_ERROR_SIZE, "%.*s",
00481              (int32_t)con->packet_size, con->buffer_ptr);
00482     snprintf(con->result->info, DRIZZLE_MAX_INFO_SIZE, "%.*s",
00483              (int32_t)con->packet_size, con->buffer_ptr);
00484     con->buffer_ptr+= con->packet_size;
00485     con->buffer_size-= con->packet_size;
00486     con->packet_size= 0;
00487   }
00488 
00489   drizzle_state_pop(con);
00490   return ret;
00491 }
00492 
00493 drizzle_return_t drizzle_state_result_write(drizzle_con_st *con)
00494 {
00495   uint8_t *start= con->buffer_ptr + con->buffer_size;
00496   uint8_t *ptr;
00497   drizzle_result_st *result= con->result;
00498 
00499   drizzle_log_debug(con->drizzle, "drizzle_state_result_write");
00500 
00501   /* Calculate max packet size. */
00502   con->packet_size= 1 /* OK/Field Count/EOF/Error */
00503                   + 9 /* Affected rows */
00504                   + 9 /* Insert ID */
00505                   + 2 /* Status */
00506                   + 2 /* Warning count */
00507                   + strlen(result->info); /* Info/error message */
00508 
00509   /* Assume the entire result packet will fit in the buffer. */
00510   if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
00511   {
00512     drizzle_set_error(con->drizzle, "drizzle_state_result_write",
00513                       "buffer too small:%zu", con->packet_size + 4);
00514     return DRIZZLE_RETURN_INTERNAL_ERROR;
00515   }
00516 
00517   /* Flush buffer if there is not enough room. */
00518   if (((size_t)DRIZZLE_MAX_BUFFER_SIZE - (size_t)(start - con->buffer)) <
00519       con->packet_size)
00520   {
00521     drizzle_state_push(con, drizzle_state_write);
00522     return DRIZZLE_RETURN_OK;
00523   }
00524 
00525   /* Store packet size at the end since it may change. */
00526   ptr= start;
00527   ptr[3]= con->packet_number;
00528   con->packet_number++;
00529   ptr+= 4;
00530 
00531   if (result->options & DRIZZLE_RESULT_EOF_PACKET)
00532   {
00533     ptr[0]= 254;
00534     ptr++;
00535 
00536     drizzle_set_byte2(ptr, result->warning_count);
00537     ptr+= 2;
00538 
00539     drizzle_set_byte2(ptr, con->status);
00540     ptr+= 2;
00541   }
00542   else if (result->error_code != 0)
00543   {
00544     ptr[0]= 255;
00545     ptr++;
00546 
00547     drizzle_set_byte2(ptr, result->error_code);
00548     ptr+= 2;
00549 
00550     ptr[0]= '#';
00551     ptr++;
00552 
00553     memcpy(ptr, result->sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE);
00554     ptr+= DRIZZLE_MAX_SQLSTATE_SIZE;
00555 
00556     memcpy(ptr, result->info, strlen(result->info));
00557     ptr+= strlen(result->info);
00558   }
00559   else if (result->column_count == 0)
00560   {
00561     ptr[0]= 0;
00562     ptr++;
00563 
00564     ptr= drizzle_pack_length(result->affected_rows, ptr);
00565     ptr= drizzle_pack_length(result->insert_id, ptr);
00566 
00567     drizzle_set_byte2(ptr, con->status);
00568     ptr+= 2;
00569 
00570     drizzle_set_byte2(ptr, result->warning_count);
00571     ptr+= 2;
00572 
00573     memcpy(ptr, result->info, strlen(result->info));
00574     ptr+= strlen(result->info);
00575   }
00576   else
00577     ptr= drizzle_pack_length(result->column_count, ptr);
00578 
00579   con->packet_size= ((size_t)(ptr - start) - 4);
00580   con->buffer_size+= (4 + con->packet_size);
00581 
00582   /* Store packet size now. */
00583   drizzle_set_byte3(start, con->packet_size);
00584 
00585   drizzle_state_pop(con);
00586   return DRIZZLE_RETURN_OK;
00587 }