Drizzled Public API Documentation

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