libdrizzle Developer Documentation

libdrizzle/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  * Use and distribution licensed under the BSD license.  See
00008  * the COPYING file in this directory for full text.
00009  */
00010 
00016 #include "common.h"
00017 
00018 /*
00019  * Common definitions
00020  */
00021 
00022 drizzle_result_st *drizzle_result_create(drizzle_con_st *con,
00023                                          drizzle_result_st *result)
00024 {
00025   if (result == NULL)
00026   {
00027     result= malloc(sizeof(drizzle_result_st));
00028     if (result == NULL)
00029     {
00030       drizzle_set_error(con->drizzle, "drizzle_result_create", "malloc");
00031       return NULL;
00032     }
00033 
00034     memset(result, 0, sizeof(drizzle_result_st));
00035     result->options|= DRIZZLE_RESULT_ALLOCATED;
00036   }
00037   else
00038     memset(result, 0, sizeof(drizzle_result_st));
00039 
00040   result->con= con;
00041   con->result= result;
00042 
00043   if (con->result_list)
00044     con->result_list->prev= result;
00045   result->next= con->result_list;
00046   con->result_list= result;
00047   con->result_count++;
00048 
00049   return result;
00050 }
00051 
00052 drizzle_result_st *drizzle_result_clone(drizzle_con_st *con,
00053                                         drizzle_result_st *result,
00054                                         drizzle_result_st *from)
00055 {
00056   result= drizzle_result_create(con, result);
00057   if (result == NULL)
00058     return NULL;
00059 
00060   result->options|= (from->options &
00061                      (drizzle_result_options_t)~DRIZZLE_RESULT_ALLOCATED);
00062 
00063   drizzle_result_set_info(result, from->info);
00064   result->error_code= from->error_code;
00065   drizzle_result_set_sqlstate(result, from->sqlstate);
00066   result->warning_count= from->warning_count;
00067   result->insert_id= from->insert_id;
00068   result->affected_rows= from->affected_rows;
00069   result->column_count= from->column_count;
00070   result->row_count= from->row_count;
00071 
00072   return result;
00073 }
00074 
00075 void drizzle_result_free(drizzle_result_st *result)
00076 {
00077   drizzle_column_st *column;
00078   uint64_t x;
00079 
00080   for (column= result->column_list; column != NULL; column= result->column_list)
00081     drizzle_column_free(column);
00082 
00083   if (result->column_buffer != NULL)
00084     free(result->column_buffer);
00085 
00086   if (result->options & DRIZZLE_RESULT_BUFFER_ROW)
00087   {
00088     for (x= 0; x < result->row_count; x++)
00089       drizzle_row_free(result, result->row_list[x]);
00090 
00091     free(result->row_list);
00092     free(result->field_sizes_list);
00093   }
00094 
00095   if (result->con->result_list == result)
00096     result->con->result_list= result->next;
00097   if (result->prev)
00098     result->prev->next= result->next;
00099   if (result->next)
00100     result->next->prev= result->prev;
00101   result->con->result_count--;
00102 
00103   if (result->options & DRIZZLE_RESULT_ALLOCATED)
00104     free(result);
00105 }
00106 
00107 void drizzle_result_free_all(drizzle_con_st *con)
00108 {
00109   while (con->result_list != NULL)
00110     drizzle_result_free(con->result_list);
00111 }
00112 
00113 drizzle_con_st *drizzle_result_drizzle_con(drizzle_result_st *result)
00114 {
00115   return result->con;
00116 }
00117 
00118 bool drizzle_result_eof(drizzle_result_st *result)
00119 {
00120   return result->options & DRIZZLE_RESULT_EOF_PACKET;
00121 }
00122 
00123 const char *drizzle_result_info(drizzle_result_st *result)
00124 {
00125   return result->info;
00126 }
00127 
00128 const char *drizzle_result_error(drizzle_result_st *result)
00129 {
00130   return result->info;
00131 }
00132 
00133 uint16_t drizzle_result_error_code(drizzle_result_st *result)
00134 {
00135   return result->error_code;
00136 }
00137 
00138 const char *drizzle_result_sqlstate(drizzle_result_st *result)
00139 {
00140   return result->sqlstate;
00141 }
00142 
00143 uint16_t drizzle_result_warning_count(drizzle_result_st *result)
00144 {
00145   return result->warning_count;
00146 }
00147 
00148 uint64_t drizzle_result_insert_id(drizzle_result_st *result)
00149 {
00150   return result->insert_id;
00151 }
00152 
00153 uint64_t drizzle_result_affected_rows(drizzle_result_st *result)
00154 {
00155   return result->affected_rows;
00156 }
00157 
00158 uint16_t drizzle_result_column_count(drizzle_result_st *result)
00159 {
00160   return result->column_count;
00161 }
00162 
00163 uint64_t drizzle_result_row_count(drizzle_result_st *result)
00164 {
00165   return result->row_count;
00166 }
00167 
00168 /*
00169  * Client definitions
00170  */
00171 
00172 drizzle_result_st *drizzle_result_read(drizzle_con_st *con,
00173                                        drizzle_result_st *result,
00174                                        drizzle_return_t *ret_ptr)
00175 {
00176   if (drizzle_state_none(con))
00177   {
00178     con->result= drizzle_result_create(con, result);
00179     if (con->result == NULL)
00180     {
00181       *ret_ptr= DRIZZLE_RETURN_MEMORY;
00182       return NULL;
00183     }
00184 
00185     drizzle_state_push(con, drizzle_state_result_read);
00186     drizzle_state_push(con, drizzle_state_packet_read);
00187   }
00188 
00189   *ret_ptr= drizzle_state_loop(con);
00190   return con->result;
00191 }
00192 
00193 drizzle_return_t drizzle_result_buffer(drizzle_result_st *result)
00194 {
00195   drizzle_return_t ret;
00196   drizzle_row_t row;
00197   drizzle_row_t *row_list;
00198   size_t **field_sizes_list;
00199 
00200   if (!(result->options & DRIZZLE_RESULT_BUFFER_COLUMN))
00201   {
00202     ret= drizzle_column_buffer(result);
00203     if (ret != DRIZZLE_RETURN_OK)
00204       return ret;
00205   }
00206 
00207   if (result->column_count == 0)
00208   {
00209     result->options|= DRIZZLE_RESULT_BUFFER_ROW;
00210     return DRIZZLE_RETURN_OK;
00211   }
00212 
00213   while (1)
00214   {
00215     row= drizzle_row_buffer(result, &ret);
00216     if (ret != DRIZZLE_RETURN_OK)
00217       return ret;
00218 
00219     if (row == NULL)
00220       break;
00221 
00222     if (result->row_list_size < result->row_count)
00223     {
00224       row_list= realloc(result->row_list, sizeof(drizzle_row_t) *
00225                         ((size_t)(result->row_list_size) +
00226                          DRIZZLE_ROW_GROW_SIZE));
00227       if (row_list == NULL)
00228       {
00229         drizzle_row_free(result, row);
00230         drizzle_set_error(result->con->drizzle, "drizzle_result_buffer",
00231                           "realloc");
00232         return DRIZZLE_RETURN_MEMORY;
00233       }
00234 
00235       result->row_list= row_list;
00236 
00237       field_sizes_list= realloc(result->field_sizes_list, sizeof(size_t *) *
00238                                 ((size_t)(result->row_list_size) +
00239                                  DRIZZLE_ROW_GROW_SIZE));
00240       if (field_sizes_list == NULL)
00241       {
00242         drizzle_row_free(result, row);
00243         drizzle_set_error(result->con->drizzle, "drizzle_result_buffer",
00244                           "realloc");
00245         return DRIZZLE_RETURN_MEMORY;
00246       }
00247 
00248       result->field_sizes_list= field_sizes_list;
00249 
00250       result->row_list_size+= DRIZZLE_ROW_GROW_SIZE;
00251     }
00252 
00253     result->row_list[result->row_current - 1]= row;
00254     result->field_sizes_list[result->row_current - 1]= result->field_sizes;
00255   }
00256 
00257   result->options|= DRIZZLE_RESULT_BUFFER_ROW;
00258   return DRIZZLE_RETURN_OK;
00259 }
00260 
00261 size_t drizzle_result_row_size(drizzle_result_st *result)
00262 {
00263   return result->con->packet_size;
00264 }
00265 
00266 /*
00267  * Server definitions
00268  */
00269 
00270 drizzle_return_t drizzle_result_write(drizzle_con_st *con,
00271                                       drizzle_result_st *result, bool flush)
00272 {
00273   if (drizzle_state_none(con))
00274   {
00275     con->result= result;
00276 
00277     if (flush)
00278       drizzle_state_push(con, drizzle_state_write);
00279 
00280     drizzle_state_push(con, drizzle_state_result_write);
00281   }
00282 
00283   return drizzle_state_loop(con);
00284 }
00285 
00286 void drizzle_result_set_row_size(drizzle_result_st *result, size_t size)
00287 {
00288   result->con->packet_size= size;
00289 }
00290 
00291 void drizzle_result_calc_row_size(drizzle_result_st *result,
00292                                   const drizzle_field_t *field,
00293                                   const size_t *size)
00294 {
00295   uint16_t x;
00296 
00297   result->con->packet_size= 0;
00298 
00299   for (x= 0; x < result->column_count; x++)
00300   {
00301     if (field[x] == NULL)
00302       result->con->packet_size++;
00303     else if (size[x] < 251)
00304       result->con->packet_size+= (1 + size[x]);
00305     else if (size[x] < 65536)
00306       result->con->packet_size+= (3 + size[x]);
00307     else if (size[x] < 16777216)
00308       result->con->packet_size+= (4 + size[x]);
00309     else
00310       result->con->packet_size+= (9 + size[x]);
00311   }
00312 }
00313 
00314 void drizzle_result_set_eof(drizzle_result_st *result, bool eof)
00315 {
00316   if (eof)
00317     result->options|= DRIZZLE_RESULT_EOF_PACKET;
00318   else
00319     result->options&= (drizzle_result_options_t)~DRIZZLE_RESULT_EOF_PACKET;
00320 }
00321 
00322 void drizzle_result_set_info(drizzle_result_st *result, const char *info)
00323 {
00324   if (info == NULL)
00325     result->info[0]= 0;
00326   else
00327   {
00328     strncpy(result->info, info, DRIZZLE_MAX_INFO_SIZE);
00329     result->info[DRIZZLE_MAX_INFO_SIZE - 1]= 0;
00330   }
00331 }
00332 
00333 void drizzle_result_set_error(drizzle_result_st *result, const char *error)
00334 {
00335   drizzle_result_set_info(result, error);
00336 }
00337 
00338 void drizzle_result_set_error_code(drizzle_result_st *result,
00339                                    uint16_t error_code)
00340 {
00341   result->error_code= error_code;
00342 }
00343 
00344 void drizzle_result_set_sqlstate(drizzle_result_st *result,
00345                                  const char *sqlstate)
00346 {
00347   if (sqlstate == NULL)
00348     result->sqlstate[0]= 0;
00349   else
00350   {
00351     strncpy(result->sqlstate, sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE + 1);
00352     result->sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE]= 0;
00353   }
00354 }
00355 
00356 void drizzle_result_set_warning_count(drizzle_result_st *result,
00357                                       uint16_t warning_count)
00358 {
00359   result->warning_count= warning_count;
00360 }
00361 
00362 void drizzle_result_set_insert_id(drizzle_result_st *result,
00363                                   uint64_t insert_id)
00364 {
00365   result->insert_id= insert_id;
00366 }
00367 
00368 void drizzle_result_set_affected_rows(drizzle_result_st *result,
00369                                       uint64_t affected_rows)
00370 {
00371   result->affected_rows= affected_rows;
00372 }
00373 
00374 void drizzle_result_set_column_count(drizzle_result_st *result,
00375                                      uint16_t column_count)
00376 {
00377   result->column_count= column_count;
00378 }
00379 
00380 /*
00381  * Internal state functions.
00382  */
00383 
00384 drizzle_return_t drizzle_state_result_read(drizzle_con_st *con)
00385 {
00386   drizzle_return_t ret;
00387 
00388   drizzle_log_debug(con->drizzle, "drizzle_state_result_read");
00389 
00390   /* Assume the entire result packet will fit in the buffer. */
00391   if (con->buffer_size < con->packet_size)
00392   {
00393     drizzle_state_push(con, drizzle_state_read);
00394     return DRIZZLE_RETURN_OK;
00395   }
00396 
00397   if (con->buffer_ptr[0] == 0)
00398   {
00399     con->buffer_ptr++;
00400     /* We can ignore the returns since we've buffered the entire packet. */
00401     con->result->affected_rows= drizzle_unpack_length(con, &ret);
00402     con->result->insert_id= drizzle_unpack_length(con, &ret);
00403     con->status= drizzle_get_byte2(con->buffer_ptr);
00404     con->result->warning_count= drizzle_get_byte2(con->buffer_ptr + 2);
00405     con->buffer_ptr+= 4;
00406     con->buffer_size-= 5;
00407     con->packet_size-= 5;
00408     if (con->packet_size > 0)
00409     {
00410       /* Skip one byte for message size. */
00411       con->buffer_ptr+= 1;
00412       con->buffer_size-= 1;
00413       con->packet_size-= 1;
00414     }
00415     ret= DRIZZLE_RETURN_OK;
00416   }
00417   else if (con->buffer_ptr[0] == 254)
00418   {
00419     con->result->options= DRIZZLE_RESULT_EOF_PACKET;
00420     con->result->warning_count= drizzle_get_byte2(con->buffer_ptr + 1);
00421     con->status= drizzle_get_byte2(con->buffer_ptr + 3);
00422     con->buffer_ptr+= 5;
00423     con->buffer_size-= 5;
00424     con->packet_size-= 5;
00425     ret= DRIZZLE_RETURN_OK;
00426   }
00427   else if (con->buffer_ptr[0] == 255)
00428   {
00429     con->result->error_code= drizzle_get_byte2(con->buffer_ptr + 1);
00430     con->drizzle->error_code= con->result->error_code;
00431     /* Byte 3 is always a '#' character, skip it. */
00432     memcpy(con->result->sqlstate, con->buffer_ptr + 4,
00433            DRIZZLE_MAX_SQLSTATE_SIZE);
00434     con->result->sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE]= 0;
00435     memcpy(con->drizzle->sqlstate, con->result->sqlstate,
00436            DRIZZLE_MAX_SQLSTATE_SIZE + 1);
00437     con->buffer_ptr+= 9;
00438     con->buffer_size-= 9;
00439     con->packet_size-= 9;
00440     ret= DRIZZLE_RETURN_ERROR_CODE;
00441   }
00442   else
00443   {
00444     /* We can ignore the return since we've buffered the entire packet. */
00445     con->result->column_count= (uint16_t)drizzle_unpack_length(con, &ret);
00446     ret= DRIZZLE_RETURN_OK;
00447   }
00448 
00449   if (con->packet_size > 0)
00450   {
00451     snprintf(con->drizzle->last_error, DRIZZLE_MAX_ERROR_SIZE, "%.*s",
00452              (int32_t)con->packet_size, con->buffer_ptr);
00453     snprintf(con->result->info, DRIZZLE_MAX_INFO_SIZE, "%.*s",
00454              (int32_t)con->packet_size, con->buffer_ptr);
00455     con->buffer_ptr+= con->packet_size;
00456     con->buffer_size-= con->packet_size;
00457     con->packet_size= 0;
00458   }
00459 
00460   drizzle_state_pop(con);
00461   return ret;
00462 }
00463 
00464 drizzle_return_t drizzle_state_result_write(drizzle_con_st *con)
00465 {
00466   uint8_t *start= con->buffer_ptr + con->buffer_size;
00467   uint8_t *ptr;
00468   drizzle_result_st *result= con->result;
00469 
00470   drizzle_log_debug(con->drizzle, "drizzle_state_result_write");
00471 
00472   /* Calculate max packet size. */
00473   con->packet_size= 1 /* OK/Field Count/EOF/Error */
00474                   + 9 /* Affected rows */
00475                   + 9 /* Insert ID */
00476                   + 2 /* Status */
00477                   + 2 /* Warning count */
00478                   + strlen(result->info); /* Info/error message */
00479 
00480   /* Assume the entire result packet will fit in the buffer. */
00481   if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
00482   {
00483     drizzle_set_error(con->drizzle, "drizzle_state_result_write",
00484                       "buffer too small:%zu", con->packet_size + 4);
00485     return DRIZZLE_RETURN_INTERNAL_ERROR;
00486   }
00487 
00488   /* Flush buffer if there is not enough room. */
00489   if (((size_t)DRIZZLE_MAX_BUFFER_SIZE - (size_t)(start - con->buffer)) <
00490       con->packet_size)
00491   {
00492     drizzle_state_push(con, drizzle_state_write);
00493     return DRIZZLE_RETURN_OK;
00494   }
00495 
00496   /* Store packet size at the end since it may change. */
00497   ptr= start;
00498   ptr[3]= con->packet_number;
00499   con->packet_number++;
00500   ptr+= 4;
00501 
00502   if (result->options & DRIZZLE_RESULT_EOF_PACKET)
00503   {
00504     ptr[0]= 254;
00505     ptr++;
00506 
00507     drizzle_set_byte2(ptr, result->warning_count);
00508     ptr+= 2;
00509 
00510     drizzle_set_byte2(ptr, con->status);
00511     ptr+= 2;
00512   }
00513   else if (result->error_code != 0)
00514   {
00515     ptr[0]= 255;
00516     ptr++;
00517 
00518     drizzle_set_byte2(ptr, result->error_code);
00519     ptr+= 2;
00520 
00521     ptr[0]= '#';
00522     ptr++;
00523 
00524     memcpy(ptr, result->sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE);
00525     ptr+= DRIZZLE_MAX_SQLSTATE_SIZE;
00526 
00527     memcpy(ptr, result->info, strlen(result->info));
00528     ptr+= strlen(result->info);
00529   }
00530   else if (result->column_count == 0)
00531   {
00532     ptr[0]= 0;
00533     ptr++;
00534 
00535     ptr= drizzle_pack_length(result->affected_rows, ptr);
00536     ptr= drizzle_pack_length(result->insert_id, ptr);
00537 
00538     drizzle_set_byte2(ptr, con->status);
00539     ptr+= 2;
00540 
00541     drizzle_set_byte2(ptr, result->warning_count);
00542     ptr+= 2;
00543 
00544     memcpy(ptr, result->info, strlen(result->info));
00545     ptr+= strlen(result->info);
00546   }
00547   else
00548     ptr= drizzle_pack_length(result->column_count, ptr);
00549 
00550   con->packet_size= ((size_t)(ptr - start) - 4);
00551   con->buffer_size+= (4 + con->packet_size);
00552 
00553   /* Store packet size now. */
00554   drizzle_set_byte3(start, con->packet_size);
00555 
00556   drizzle_state_pop(con);
00557   return DRIZZLE_RETURN_OK;
00558 }