MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
emb_qcache.cc
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "sql_priv.h"
17 #include "my_global.h" // HAVE_*
18 
19 #ifdef HAVE_QUERY_CACHE
20 #include <mysql.h>
21 #include "emb_qcache.h"
22 #include "embedded_priv.h"
23 #include "sql_class.h" // THD
24 
25 void Querycache_stream::store_uchar(uchar c)
26 {
27  if (data_end == cur_data)
28  use_next_block(TRUE);
29  *(cur_data++)= c;
30 #ifndef DBUG_OFF
31  stored_size++;
32 #endif
33 }
34 
35 void Querycache_stream::store_short(ushort s)
36 {
37 #ifndef DBUG_OFF
38  stored_size+= 2;
39 #endif
40  if (data_end - cur_data > 1)
41  {
42  int2store(cur_data, s);
43  cur_data+= 2;
44  return;
45  }
46  if (data_end == cur_data)
47  {
48  use_next_block(TRUE);
49  int2store(cur_data, s);
50  cur_data+= 2;
51  return;
52  }
53  *cur_data= ((uchar *)(&s))[0];
54  use_next_block(TRUE);
55  *(cur_data++)= ((uchar *)(&s))[1];
56 }
57 
58 void Querycache_stream::store_int(uint i)
59 {
60 #ifndef DBUG_OFF
61  stored_size+= 4;
62 #endif
63  size_t rest_len= data_end - cur_data;
64  if (rest_len > 3)
65  {
66  int4store(cur_data, i);
67  cur_data+= 4;
68  return;
69  }
70  if (!rest_len)
71  {
72  use_next_block(TRUE);
73  int4store(cur_data, i);
74  cur_data+= 4;
75  return;
76  }
77  char buf[4];
78  int4store(buf, i);
79  memcpy(cur_data, buf, rest_len);
80  use_next_block(TRUE);
81  memcpy(cur_data, buf+rest_len, 4-rest_len);
82  cur_data+= 4-rest_len;
83 }
84 
85 void Querycache_stream::store_ll(ulonglong ll)
86 {
87 #ifndef DBUG_OFF
88  stored_size+= 8;
89 #endif
90  size_t rest_len= data_end - cur_data;
91  if (rest_len > 7)
92  {
93  int8store(cur_data, ll);
94  cur_data+= 8;
95  return;
96  }
97  if (!rest_len)
98  {
99  use_next_block(TRUE);
100  int8store(cur_data, ll);
101  cur_data+= 8;
102  return;
103  }
104  memcpy(cur_data, &ll, rest_len);
105  use_next_block(TRUE);
106  memcpy(cur_data, ((uchar*)&ll)+rest_len, 8-rest_len);
107  cur_data+= 8-rest_len;
108 }
109 
110 void Querycache_stream::store_str_only(const char *str, uint str_len)
111 {
112 #ifndef DBUG_OFF
113  stored_size+= str_len;
114 #endif
115  do
116  {
117  size_t rest_len= data_end - cur_data;
118  if (rest_len >= str_len)
119  {
120  memcpy(cur_data, str, str_len);
121  cur_data+= str_len;
122  return;
123  }
124  memcpy(cur_data, str, rest_len);
125  use_next_block(TRUE);
126  str_len-= rest_len;
127  str+= rest_len;
128  } while(str_len);
129 }
130 
131 void Querycache_stream::store_str(const char *str, uint str_len)
132 {
133  store_int(str_len);
134  store_str_only(str, str_len);
135 }
136 
137 void Querycache_stream::store_safe_str(const char *str, uint str_len)
138 {
139  if (str)
140  {
141  store_int(str_len+1);
142  store_str_only(str, str_len);
143  }
144  else
145  store_int(0);
146 }
147 
148 uchar Querycache_stream::load_uchar()
149 {
150  if (cur_data == data_end)
151  use_next_block(FALSE);
152  return *(cur_data++);
153 }
154 
155 ushort Querycache_stream::load_short()
156 {
157  ushort result;
158  if (data_end-cur_data > 1)
159  {
160  result= uint2korr(cur_data);
161  cur_data+= 2;
162  return result;
163  }
164  if (data_end == cur_data)
165  {
166  use_next_block(FALSE);
167  result= uint2korr(cur_data);
168  cur_data+= 2;
169  return result;
170  }
171  ((uchar*)&result)[0]= *cur_data;
172  use_next_block(FALSE);
173  ((uchar*)&result)[1]= *(cur_data++);
174  return result;
175 }
176 
177 uint Querycache_stream::load_int()
178 {
179  int result;
180  size_t rest_len= data_end - cur_data;
181  if (rest_len > 3)
182  {
183  result= uint4korr(cur_data);
184  cur_data+= 4;
185  return result;
186  }
187  if (!rest_len)
188  {
189  use_next_block(FALSE);
190  result= uint4korr(cur_data);
191  cur_data+= 4;
192  return result;
193  }
194  char buf[4], *buf_p= buf;
195  memcpy(buf, cur_data, rest_len);
196  use_next_block(FALSE);
197  memcpy(buf+rest_len, cur_data, 4-rest_len);
198  cur_data+= 4-rest_len;
199  result= uint4korr(buf_p);
200  return result;
201 }
202 
203 ulonglong Querycache_stream::load_ll()
204 {
205  ulonglong result;
206  size_t rest_len= data_end - cur_data;
207  if (rest_len > 7)
208  {
209  result= uint8korr(cur_data);
210  cur_data+= 8;
211  return result;
212  }
213  if (!rest_len)
214  {
215  use_next_block(FALSE);
216  result= uint8korr(cur_data);
217  cur_data+= 8;
218  return result;
219  }
220  memcpy(&result, cur_data, rest_len);
221  use_next_block(FALSE);
222  memcpy(((uchar*)&result)+rest_len, cur_data, 8-rest_len);
223  cur_data+= 8-rest_len;
224  return result;
225 }
226 
227 void Querycache_stream::load_str_only(char *buffer, uint str_len)
228 {
229  do
230  {
231  size_t rest_len= data_end - cur_data;
232  if (rest_len >= str_len)
233  {
234  memcpy(buffer, cur_data, str_len);
235  cur_data+= str_len;
236  buffer+= str_len;
237  break;
238  }
239  memcpy(buffer, cur_data, rest_len);
240  use_next_block(FALSE);
241  str_len-= rest_len;
242  buffer+= rest_len;
243  } while(str_len);
244  *buffer= 0;
245 }
246 
247 char *Querycache_stream::load_str(MEM_ROOT *alloc, uint *str_len)
248 {
249  char *result;
250  *str_len= load_int();
251  if (!(result= (char*) alloc_root(alloc, *str_len + 1)))
252  return 0;
253  load_str_only(result, *str_len);
254  return result;
255 }
256 
257 int Querycache_stream::load_safe_str(MEM_ROOT *alloc, char **str, uint *str_len)
258 {
259  if (!(*str_len= load_int()))
260  {
261  *str= NULL;
262  return 0;
263  }
264  (*str_len)--;
265  if (!(*str= (char*) alloc_root(alloc, *str_len + 1)))
266  return 1;
267  load_str_only(*str, *str_len);
268  return 0;
269 }
270 
271 int Querycache_stream::load_column(MEM_ROOT *alloc, char** column)
272 {
273  int len;
274  if (!(len = load_int()))
275  {
276  *column= NULL;
277  return 0;
278  }
279  len--;
280  if (!(*column= (char *)alloc_root(alloc, len + sizeof(uint) + 1)))
281  return 1;
282  *((uint*)*column)= len;
283  (*column)+= sizeof(uint);
284  load_str_only(*column, len);
285  return 1;
286 }
287 
288 uint emb_count_querycache_size(THD *thd)
289 {
290  uint result= 0;
291  MYSQL_FIELD *field;
292  MYSQL_FIELD *field_end;
293  MYSQL_ROWS *cur_row;
294  my_ulonglong n_rows;
295  MYSQL_DATA *data= thd->first_data;
296 
297  while (data->embedded_info->next)
298  data= data->embedded_info->next;
299  field= data->embedded_info->fields_list;
300  field_end= field + data->fields;
301 
302  if (!field)
303  return result;
304  *data->embedded_info->prev_ptr= NULL; // this marks the last record
305  cur_row= data->data;
306  n_rows= data->rows;
307  /* n_fields + n_rows + field_info * n_fields */
308  result+= (uint) (4+8 + 42*data->fields);
309 
310  for(; field < field_end; field++)
311  {
312  result+= field->name_length + field->table_length +
313  field->org_name_length + field->org_table_length + field->db_length +
314  field->catalog_length;
315  if (field->def)
316  result+= field->def_length;
317  }
318 
319  if (thd->protocol == &thd->protocol_binary)
320  {
321  result+= (uint) (4*n_rows);
322  for (; cur_row; cur_row=cur_row->next)
323  result+= cur_row->length;
324  }
325  else
326  {
327  result+= (uint) (4*n_rows*data->fields);
328  for (; cur_row; cur_row=cur_row->next)
329  {
330  MYSQL_ROW col= cur_row->data;
331  MYSQL_ROW col_end= col + data->fields;
332  for (; col < col_end; col++)
333  if (*col)
334  result+= *(uint *)((*col) - sizeof(uint));
335  }
336  }
337  return result;
338 }
339 
340 void emb_store_querycache_result(Querycache_stream *dst, THD *thd)
341 {
342  MYSQL_FIELD *field;
343  MYSQL_FIELD *field_end;
344  MYSQL_ROWS *cur_row;
345  my_ulonglong n_rows;
346  MYSQL_DATA *data= thd->first_data;
347 
348  DBUG_ENTER("emb_store_querycache_result");
349 
350  while (data->embedded_info->next)
351  data= data->embedded_info->next;
352  field= data->embedded_info->fields_list;
353  field_end= field + data->fields;
354 
355  if (!field)
356  DBUG_VOID_RETURN;
357 
358  *data->embedded_info->prev_ptr= NULL; // this marks the last record
359  cur_row= data->data;
360  n_rows= data->rows;
361 
362  dst->store_int((uint)data->fields);
363  dst->store_ll((ulonglong)n_rows);
364 
365  for(; field < field_end; field++)
366  {
367  dst->store_int((uint)field->length);
368  dst->store_int((uint)field->max_length);
369  dst->store_uchar((uchar)field->type);
370  dst->store_short((ushort)field->flags);
371  dst->store_short((ushort)field->charsetnr);
372  dst->store_uchar((uchar)field->decimals);
373  dst->store_str(field->name, field->name_length);
374  dst->store_str(field->table, field->table_length);
375  dst->store_str(field->org_name, field->org_name_length);
376  dst->store_str(field->org_table, field->org_table_length);
377  dst->store_str(field->db, field->db_length);
378  dst->store_str(field->catalog, field->catalog_length);
379  dst->store_safe_str(field->def, field->def_length);
380  }
381 
382  if (thd->protocol == &thd->protocol_binary)
383  {
384  for (; cur_row; cur_row=cur_row->next)
385  dst->store_str((char *) cur_row->data, cur_row->length);
386  }
387  else
388  {
389  for (; cur_row; cur_row=cur_row->next)
390  {
391  MYSQL_ROW col= cur_row->data;
392  MYSQL_ROW col_end= col + data->fields;
393  for (; col < col_end; col++)
394  {
395  uint len= *col ? *(uint *)((*col) - sizeof(uint)) : 0;
396  dst->store_safe_str(*col, len);
397  }
398  }
399  }
400  DBUG_ASSERT(emb_count_querycache_size(thd) == dst->stored_size);
401  DBUG_VOID_RETURN;
402 }
403 
404 int emb_load_querycache_result(THD *thd, Querycache_stream *src)
405 {
406  MYSQL_DATA *data= thd->alloc_new_dataset();
407  MYSQL_FIELD *field;
408  MYSQL_FIELD *field_end;
409  MEM_ROOT *f_alloc;
410  MYSQL_ROWS *row, *end_row;
411  MYSQL_ROWS **prev_row;
412  ulonglong rows;
413  MYSQL_ROW columns;
414  DBUG_ENTER("emb_load_querycache_result");
415 
416  if (!data)
417  goto err;
418  init_alloc_root(&data->alloc, 8192,0);
419  f_alloc= &data->alloc;
420 
421  data->fields= src->load_int();
422  rows= src->load_ll();
423 
424  if (!(field= (MYSQL_FIELD *)
425  alloc_root(f_alloc,data->fields*sizeof(MYSQL_FIELD))))
426  goto err;
427  data->embedded_info->fields_list= field;
428  for(field_end= field+data->fields; field < field_end; field++)
429  {
430  field->length= src->load_int();
431  field->max_length= (unsigned int)src->load_int();
432  field->type= (enum enum_field_types)src->load_uchar();
433  field->flags= (unsigned int)src->load_short();
434  field->charsetnr= (unsigned int)src->load_short();
435  field->decimals= src->load_uchar();
436 
437  if (!(field->name= src->load_str(f_alloc, &field->name_length)) ||
438  !(field->table= src->load_str(f_alloc,&field->table_length)) ||
439  !(field->org_name= src->load_str(f_alloc, &field->org_name_length)) ||
440  !(field->org_table= src->load_str(f_alloc, &field->org_table_length))||
441  !(field->db= src->load_str(f_alloc, &field->db_length)) ||
442  !(field->catalog= src->load_str(f_alloc, &field->catalog_length)) ||
443  src->load_safe_str(f_alloc, &field->def, &field->def_length))
444  goto err;
445  }
446 
447  data->rows= rows;
448  if (!rows)
449  goto return_ok;
450  if (thd->protocol == &thd->protocol_binary)
451  {
452  uint length;
453  row= (MYSQL_ROWS *)alloc_root(&data->alloc,
454  (size_t) (rows * sizeof(MYSQL_ROWS)));
455  end_row= row + rows;
456  data->data= row;
457 
458  for (prev_row= &row->next; row < end_row; prev_row= &row->next, row++)
459  {
460  *prev_row= row;
461  row->data= (MYSQL_ROW) src->load_str(&data->alloc, &length);
462  row->length= length;
463  }
464  }
465  else
466  {
467  row= (MYSQL_ROWS *)alloc_root(&data->alloc,
468  (uint) (rows * sizeof(MYSQL_ROWS) +
469  rows*(data->fields+1)*sizeof(char*)));
470  end_row= row + rows;
471  columns= (MYSQL_ROW)end_row;
472 
473  data->data= row;
474 
475  for (prev_row= &row->next; row < end_row; prev_row= &row->next, row++)
476  {
477  *prev_row= row;
478  row->data= columns;
479  MYSQL_ROW col_end= columns + data->fields;
480  for (; columns < col_end; columns++)
481  src->load_column(&data->alloc, columns);
482 
483  *(columns++)= NULL;
484  }
485  }
486  *prev_row= NULL;
487  data->embedded_info->prev_ptr= prev_row;
488 return_ok:
489  net_send_eof(thd, thd->server_status,
490  thd->get_stmt_da()->current_statement_warn_count());
491  DBUG_RETURN(0);
492 err:
493  DBUG_RETURN(1);
494 }
495 
496 #endif /*HAVE_QUERY_CACHE*/
497