Drizzled Public API Documentation

result.cc
Go to the documentation of this file.
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2  *
3  * Drizzle Client & Protocol Library
4  *
5  * Copyright (C) 2008 Eric Day (eday@oddments.org)
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following disclaimer
17  * in the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * * The names of its contributors may not be used to endorse or
21  * promote products derived from this software without specific prior
22  * written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
43 #include <libdrizzle/common.h>
44 
45 /*
46  * Common definitions
47  */
48 
49 drizzle_result_st *drizzle_result_create(drizzle_con_st *con,
50  drizzle_result_st *result)
51 {
52  if (con == NULL)
53  {
54  return NULL;
55  }
56 
57  if (result == NULL)
58  {
59  result= new (std::nothrow) drizzle_result_st;
60  if (result == NULL)
61  {
62  drizzle_set_error(con->drizzle, __func__, "Failed to allocate.");
63  return NULL;
64  }
65 
66  result->options|= DRIZZLE_RESULT_ALLOCATED;
67  }
68  else
69  {
70  memset(result, 0, sizeof(drizzle_result_st));
71  }
72 
73  result->con= con;
74  con->result= result;
75 
76  if (con->result_list)
77  con->result_list->prev= result;
78  result->next= con->result_list;
79  con->result_list= result;
80  con->result_count++;
81 
82  return result;
83 }
84 
85 drizzle_result_st *drizzle_result_clone(drizzle_con_st *con,
86  drizzle_result_st *result,
87  drizzle_result_st *from)
88 {
89  // A NULL con will return a NULL result
90  result= drizzle_result_create(con, result);
91  if (result == NULL)
92  {
93  return NULL;
94  }
95 
96  result->options|= (from->options & ~int(DRIZZLE_RESULT_ALLOCATED));
97 
98  drizzle_result_set_info(result, from->info);
99  result->error_code= from->error_code;
100  drizzle_result_set_sqlstate(result, from->sqlstate);
101  result->warning_count= from->warning_count;
102  result->insert_id= from->insert_id;
103  result->affected_rows= from->affected_rows;
104  result->column_count= from->column_count;
105  result->row_count= from->row_count;
106 
107  return result;
108 }
109 
110 void drizzle_result_free(drizzle_result_st *result)
111 {
112  if (result == NULL)
113  {
114  return;
115  }
116 
117  for (drizzle_column_st* column= result->column_list; column != NULL; column= result->column_list)
118  {
119  drizzle_column_free(column);
120  }
121 
122  delete [] result->column_buffer;
123 
124  if (result->options & DRIZZLE_RESULT_BUFFER_ROW)
125  {
126  for (uint64_t x= 0; x < result->row_count; x++)
127  {
128  drizzle_row_free(result, result->row_list[x]);
129  }
130 
131  free(result->row_list);
132  free(result->field_sizes_list);
133  }
134 
135  if (result->con)
136  {
137  result->con->result_count--;
138  if (result->con->result_list == result)
139  result->con->result_list= result->next;
140  }
141 
142  if (result->prev)
143  {
144  result->prev->next= result->next;
145  }
146  if (result->next)
147  {
148  result->next->prev= result->prev;
149  }
150 
151  if (result->options & DRIZZLE_RESULT_ALLOCATED)
152  {
153  delete result;
154  }
155 }
156 
157 void drizzle_result_free_all(drizzle_con_st *con)
158 {
159  if (con == NULL)
160  {
161  return;
162  }
163 
164  while (con->result_list != NULL)
165  {
166  drizzle_result_free(con->result_list);
167  }
168 }
169 
170 drizzle_con_st *drizzle_result_drizzle_con(drizzle_result_st *result)
171 {
172  if (result == NULL)
173  {
174  return NULL;
175  }
176 
177  return result->con;
178 }
179 
180 bool drizzle_result_eof(drizzle_result_st *result)
181 {
182  if (result == NULL)
183  {
184  return false;
185  }
186 
187  return result->options & DRIZZLE_RESULT_EOF_PACKET;
188 }
189 
190 const char *drizzle_result_info(drizzle_result_st *result)
191 {
192  if (result == NULL)
193  {
194  return NULL;
195  }
196 
197  return result->info;
198 }
199 
200 const char *drizzle_result_error(drizzle_result_st *result)
201 {
202  if (result == NULL)
203  {
204  return NULL;
205  }
206 
207  return result->info;
208 }
209 
210 uint16_t drizzle_result_error_code(drizzle_result_st *result)
211 {
212  if (result == NULL)
213  {
214  return 0;
215  }
216 
217  return result->error_code;
218 }
219 
220 const char *drizzle_result_sqlstate(drizzle_result_st *result)
221 {
222  if (result == NULL)
223  {
224  return NULL;
225  }
226 
227  return result->sqlstate;
228 }
229 
230 uint16_t drizzle_result_warning_count(drizzle_result_st *result)
231 {
232  if (result == NULL)
233  {
234  return 0;
235  }
236 
237  return result->warning_count;
238 }
239 
240 uint64_t drizzle_result_insert_id(drizzle_result_st *result)
241 {
242  if (result == NULL)
243  {
244  return 0;
245  }
246 
247  return result->insert_id;
248 }
249 
250 uint64_t drizzle_result_affected_rows(drizzle_result_st *result)
251 {
252  if (result == NULL)
253  {
254  return 0;
255  }
256 
257  return result->affected_rows;
258 }
259 
260 uint16_t drizzle_result_column_count(drizzle_result_st *result)
261 {
262  if (result == NULL)
263  {
264  return 0;
265  }
266 
267  return result->column_count;
268 }
269 
270 uint64_t drizzle_result_row_count(drizzle_result_st *result)
271 {
272  if (result == NULL)
273  {
274  return 0;
275  }
276 
277  return result->row_count;
278 }
279 
280 /*
281  * Client definitions
282  */
283 
284 drizzle_result_st *drizzle_result_read(drizzle_con_st *con,
285  drizzle_result_st *result,
286  drizzle_return_t *ret_ptr)
287 {
288  drizzle_return_t unused;
289  if (ret_ptr == NULL)
290  {
291  ret_ptr= &unused;
292  }
293 
294  if (con == NULL)
295  {
296  *ret_ptr= DRIZZLE_RETURN_INVALID_ARGUMENT;
297  return NULL;
298  }
299 
300  if (drizzle_state_none(con))
301  {
302  con->result= drizzle_result_create(con, result);
303  if (con->result == NULL)
304  {
305  *ret_ptr= DRIZZLE_RETURN_MEMORY;
306  return NULL;
307  }
308 
309  drizzle_state_push(con, drizzle_state_result_read);
310  drizzle_state_push(con, drizzle_state_packet_read);
311  }
312 
313  *ret_ptr= drizzle_state_loop(con);
314  return con->result;
315 }
316 
317 drizzle_return_t drizzle_result_buffer(drizzle_result_st *result)
318 {
319  if (result == NULL)
320  {
321  return DRIZZLE_RETURN_INVALID_ARGUMENT;
322  }
323 
324  drizzle_return_t ret;
325  drizzle_row_t row;
326  drizzle_row_t *row_list;
327  size_t **field_sizes_list;
328 
329  if (!(result->options & DRIZZLE_RESULT_BUFFER_COLUMN))
330  {
331  ret= drizzle_column_buffer(result);
332  if (ret != DRIZZLE_RETURN_OK)
333  return ret;
334  }
335 
336  if (result->column_count == 0)
337  {
338  result->options|= DRIZZLE_RESULT_BUFFER_ROW;
339  return DRIZZLE_RETURN_OK;
340  }
341 
342  while (1)
343  {
344  row= drizzle_row_buffer(result, &ret);
345  if (ret != DRIZZLE_RETURN_OK)
346  return ret;
347 
348  if (row == NULL)
349  break;
350 
351  if (result->row_list_size < result->row_count)
352  {
353  row_list= (drizzle_row_t *)realloc(result->row_list, sizeof(drizzle_row_t) * ((size_t)(result->row_list_size) + DRIZZLE_ROW_GROW_SIZE));
354  if (row_list == NULL)
355  {
356  drizzle_row_free(result, row);
357  drizzle_set_error(result->con->drizzle, __func__, "Failed to realloc row_list.");
358  return DRIZZLE_RETURN_MEMORY;
359  }
360 
361  result->row_list= row_list;
362 
363  field_sizes_list= (size_t **)realloc(result->field_sizes_list, sizeof(size_t *) * ((size_t)(result->row_list_size) + DRIZZLE_ROW_GROW_SIZE));
364  if (field_sizes_list == NULL)
365  {
366  drizzle_row_free(result, row);
367  drizzle_set_error(result->con->drizzle, "drizzle_result_buffer", "Failed to realloc field list.");
368  return DRIZZLE_RETURN_MEMORY;
369  }
370 
371  result->field_sizes_list= field_sizes_list;
372 
373  result->row_list_size+= DRIZZLE_ROW_GROW_SIZE;
374  }
375 
376  result->row_list[result->row_current - 1]= row;
377  result->field_sizes_list[result->row_current - 1]= result->field_sizes;
378  }
379 
380  result->options|= DRIZZLE_RESULT_BUFFER_ROW;
381  return DRIZZLE_RETURN_OK;
382 }
383 
384 size_t drizzle_result_row_size(drizzle_result_st *result)
385 {
386  if (result == NULL)
387  {
388  return 0;
389  }
390 
391  return result->con->packet_size;
392 }
393 
394 /*
395  * Server definitions
396  */
397 
398 drizzle_return_t drizzle_result_write(drizzle_con_st *con,
399  drizzle_result_st *result, bool flush)
400 {
401  if (con == NULL)
402  {
403  return DRIZZLE_RETURN_INVALID_ARGUMENT;
404  }
405 
406  if (drizzle_state_none(con))
407  {
408  con->result= result;
409 
410  if (flush)
411  drizzle_state_push(con, drizzle_state_write);
412 
413  drizzle_state_push(con, drizzle_state_result_write);
414  }
415 
416  return drizzle_state_loop(con);
417 }
418 
419 void drizzle_result_set_row_size(drizzle_result_st *result, size_t size)
420 {
421  if (result == NULL)
422  {
423  return;
424  }
425 
426  result->con->packet_size= size;
427 }
428 
429 void drizzle_result_calc_row_size(drizzle_result_st *result,
430  const drizzle_field_t *field,
431  const size_t *size)
432 {
433  if (result == NULL)
434  {
435  return;
436  }
437 
438  result->con->packet_size= 0;
439 
440  for (uint16_t x= 0; x < result->column_count; x++)
441  {
442  if (field[x] == NULL)
443  {
444  result->con->packet_size++;
445  }
446  else if (size[x] < 251)
447  {
448  result->con->packet_size+= (1 + size[x]);
449  }
450  else if (size[x] < 65536)
451  {
452  result->con->packet_size+= (3 + size[x]);
453  }
454  else if (size[x] < 16777216)
455  {
456  result->con->packet_size+= (4 + size[x]);
457  }
458  else
459  {
460  result->con->packet_size+= (9 + size[x]);
461  }
462  }
463 }
464 
465 void drizzle_result_set_eof(drizzle_result_st *result, bool is_eof)
466 {
467  if (result == NULL)
468  {
469  return;
470  }
471 
472  if (is_eof)
473  result->options|= DRIZZLE_RESULT_EOF_PACKET;
474  else
475  result->options&= ~int(DRIZZLE_RESULT_EOF_PACKET);
476 }
477 
478 void drizzle_result_set_info(drizzle_result_st *result, const char *info)
479 {
480  if (result == NULL)
481  {
482  return;
483  }
484 
485  if (info == NULL)
486  {
487  result->info[0]= 0;
488  }
489  else
490  {
491  strncpy(result->info, info, DRIZZLE_MAX_INFO_SIZE);
492  result->info[DRIZZLE_MAX_INFO_SIZE - 1]= 0;
493  }
494 }
495 
496 void drizzle_result_set_error(drizzle_result_st *result, const char *error)
497 {
498  if (result == NULL)
499  {
500  return;
501  }
502 
503  drizzle_result_set_info(result, error);
504 }
505 
506 void drizzle_result_set_error_code(drizzle_result_st *result,
507  uint16_t error_code)
508 {
509  if (result == NULL)
510  {
511  return;
512  }
513 
514  result->error_code= error_code;
515 }
516 
517 void drizzle_result_set_sqlstate(drizzle_result_st *result,
518  const char *sqlstate)
519 {
520  if (result == NULL)
521  {
522  return;
523  }
524 
525  if (sqlstate == NULL)
526  {
527  result->sqlstate[0]= 0;
528  }
529  else
530  {
531  strncpy(result->sqlstate, sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE + 1);
532  result->sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE]= 0;
533  }
534 }
535 
536 void drizzle_result_set_warning_count(drizzle_result_st *result,
537  uint16_t warning_count)
538 {
539  if (result == NULL)
540  {
541  return;
542  }
543 
544  result->warning_count= warning_count;
545 }
546 
547 void drizzle_result_set_insert_id(drizzle_result_st *result,
548  uint64_t insert_id)
549 {
550  if (result == NULL)
551  {
552  return;
553  }
554 
555  result->insert_id= insert_id;
556 }
557 
558 void drizzle_result_set_affected_rows(drizzle_result_st *result,
559  uint64_t affected_rows)
560 {
561  if (result == NULL)
562  {
563  return;
564  }
565 
566  result->affected_rows= affected_rows;
567 }
568 
569 void drizzle_result_set_column_count(drizzle_result_st *result,
570  uint16_t column_count)
571 {
572  if (result == NULL)
573  {
574  return;
575  }
576 
577  result->column_count= column_count;
578 }
579 
580 /*
581  * Internal state functions.
582  */
583 
584 drizzle_return_t drizzle_state_result_read(drizzle_con_st *con)
585 {
586  drizzle_return_t ret;
587 
588  if (con == NULL)
589  {
590  return DRIZZLE_RETURN_INVALID_ARGUMENT;
591  }
592 
593  drizzle_log_debug(con->drizzle, "drizzle_state_result_read");
594 
595  /* Assume the entire result packet will fit in the buffer. */
596  if (con->buffer_size < con->packet_size)
597  {
598  drizzle_state_push(con, drizzle_state_read);
599  return DRIZZLE_RETURN_OK;
600  }
601 
602  if (con->buffer_ptr[0] == 0)
603  {
604  con->buffer_ptr++;
605  /* We can ignore the returns since we've buffered the entire packet. */
606  con->result->affected_rows= drizzle_unpack_length(con, &ret);
607  con->result->insert_id= drizzle_unpack_length(con, &ret);
608  con->status= drizzle_con_status_t(drizzle_get_byte2(con->buffer_ptr));
609  con->result->warning_count= drizzle_get_byte2(con->buffer_ptr + 2);
610  con->buffer_ptr+= 4;
611  con->buffer_size-= 5;
612  con->packet_size-= 5;
613  if (con->packet_size > 0)
614  {
615  /* Skip one byte for message size. */
616  con->buffer_ptr+= 1;
617  con->buffer_size-= 1;
618  con->packet_size-= 1;
619  }
620  ret= DRIZZLE_RETURN_OK;
621  }
622  else if (con->buffer_ptr[0] == 254)
623  {
624  con->result->options= DRIZZLE_RESULT_EOF_PACKET;
625  con->result->warning_count= drizzle_get_byte2(con->buffer_ptr + 1);
626  con->status= drizzle_con_status_t(drizzle_get_byte2(con->buffer_ptr + 3));
627  con->buffer_ptr+= 5;
628  con->buffer_size-= 5;
629  con->packet_size-= 5;
630  ret= DRIZZLE_RETURN_OK;
631  }
632  else if (con->buffer_ptr[0] == 255)
633  {
634  con->result->error_code= drizzle_get_byte2(con->buffer_ptr + 1);
635  con->drizzle->error_code= con->result->error_code;
636  /* Byte 3 is always a '#' character, skip it. */
637  memcpy(con->result->sqlstate, con->buffer_ptr + 4,
638  DRIZZLE_MAX_SQLSTATE_SIZE);
639  con->result->sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE]= 0;
640  memcpy(con->drizzle->sqlstate, con->result->sqlstate,
641  DRIZZLE_MAX_SQLSTATE_SIZE + 1);
642  con->buffer_ptr+= 9;
643  con->buffer_size-= 9;
644  con->packet_size-= 9;
645  ret= DRIZZLE_RETURN_ERROR_CODE;
646  }
647  else
648  {
649  /* We can ignore the return since we've buffered the entire packet. */
650  con->result->column_count= (uint16_t)drizzle_unpack_length(con, &ret);
651  ret= DRIZZLE_RETURN_OK;
652  }
653 
654  if (con->packet_size > 0)
655  {
656  snprintf(con->drizzle->last_error, DRIZZLE_MAX_ERROR_SIZE, "%.*s",
657  (int32_t)con->packet_size, con->buffer_ptr);
658  con->drizzle->last_error[DRIZZLE_MAX_ERROR_SIZE-1]= 0;
659  snprintf(con->result->info, DRIZZLE_MAX_INFO_SIZE, "%.*s",
660  (int32_t)con->packet_size, con->buffer_ptr);
661  con->result->info[DRIZZLE_MAX_INFO_SIZE-1]= 0;
662  con->buffer_ptr+= con->packet_size;
663  con->buffer_size-= con->packet_size;
664  con->packet_size= 0;
665  }
666 
667  drizzle_state_pop(con);
668  return ret;
669 }
670 
671 drizzle_return_t drizzle_state_result_write(drizzle_con_st *con)
672 {
673  if (con == NULL)
674  {
675  return DRIZZLE_RETURN_INVALID_ARGUMENT;
676  }
677 
678  uint8_t *start= con->buffer_ptr + con->buffer_size;
679  uint8_t *ptr;
680  drizzle_result_st *result= con->result;
681 
682  drizzle_log_debug(con->drizzle, "drizzle_state_result_write");
683 
684  /* Calculate max packet size. */
685  con->packet_size= 1 /* OK/Field Count/EOF/Error */
686  + 9 /* Affected rows */
687  + 9 /* Insert ID */
688  + 2 /* Status */
689  + 2 /* Warning count */
690  + strlen(result->info); /* Info/error message */
691 
692  /* Assume the entire result packet will fit in the buffer. */
693  if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
694  {
695  drizzle_set_error(con->drizzle, "drizzle_state_result_write",
696  "buffer too small:%zu", con->packet_size + 4);
697  return DRIZZLE_RETURN_INTERNAL_ERROR;
698  }
699 
700  /* Flush buffer if there is not enough room. */
701  if (((size_t)DRIZZLE_MAX_BUFFER_SIZE - (size_t)(start - con->buffer)) <
702  con->packet_size)
703  {
704  drizzle_state_push(con, drizzle_state_write);
705  return DRIZZLE_RETURN_OK;
706  }
707 
708  /* Store packet size at the end since it may change. */
709  ptr= start;
710  ptr[3]= con->packet_number;
711  con->packet_number++;
712  ptr+= 4;
713 
714  if (result->options & DRIZZLE_RESULT_EOF_PACKET)
715  {
716  ptr[0]= 254;
717  ptr++;
718 
719  drizzle_set_byte2(ptr, result->warning_count);
720  ptr+= 2;
721 
722  drizzle_set_byte2(ptr, con->status);
723  ptr+= 2;
724  }
725  else if (result->error_code != 0)
726  {
727  ptr[0]= 255;
728  ptr++;
729 
730  drizzle_set_byte2(ptr, result->error_code);
731  ptr+= 2;
732 
733  ptr[0]= '#';
734  ptr++;
735 
736  memcpy(ptr, result->sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE);
737  ptr+= DRIZZLE_MAX_SQLSTATE_SIZE;
738 
739  memcpy(ptr, result->info, strlen(result->info));
740  ptr+= strlen(result->info);
741  }
742  else if (result->column_count == 0)
743  {
744  ptr[0]= 0;
745  ptr++;
746 
747  ptr= drizzle_pack_length(result->affected_rows, ptr);
748  ptr= drizzle_pack_length(result->insert_id, ptr);
749 
750  drizzle_set_byte2(ptr, con->status);
751  ptr+= 2;
752 
753  drizzle_set_byte2(ptr, result->warning_count);
754  ptr+= 2;
755 
756  memcpy(ptr, result->info, strlen(result->info));
757  ptr+= strlen(result->info);
758  }
759  else
760  ptr= drizzle_pack_length(result->column_count, ptr);
761 
762  con->packet_size= ((size_t)(ptr - start) - 4);
763  con->buffer_size+= (4 + con->packet_size);
764 
765  /* Store packet size now. */
766  drizzle_set_byte3(start, con->packet_size);
767 
768  drizzle_state_pop(con);
769  return DRIZZLE_RETURN_OK;
770 }