~skinny.moey/drizzle/branch-rev

« back to all changes in this revision

Viewing changes to sql/sql_test.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2006 MySQL AB
 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/* Write some debug info */
 
18
 
 
19
 
 
20
#include "mysql_priv.h"
 
21
#include "sql_select.h"
 
22
#include <hash.h>
 
23
#include <thr_alarm.h>
 
24
#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
 
25
#include <malloc.h>
 
26
#elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H)
 
27
#include <sys/malloc.h>
 
28
#endif
 
29
 
 
30
static const char *lock_descriptions[] =
 
31
{
 
32
  "No lock",
 
33
  "Low priority read lock",
 
34
  "Shared Read lock",
 
35
  "High priority read lock",
 
36
  "Read lock  without concurrent inserts",
 
37
  "Write lock that allows other writers",
 
38
  "Write lock, but allow reading",
 
39
  "Concurrent insert lock",
 
40
  "Lock Used by delayed insert",
 
41
  "Low priority write lock",
 
42
  "High priority write lock",
 
43
  "Highest priority write lock"
 
44
};
 
45
 
 
46
 
 
47
#ifndef DBUG_OFF
 
48
 
 
49
void
 
50
print_where(COND *cond,const char *info, enum_query_type query_type)
 
51
{
 
52
  if (cond)
 
53
  {
 
54
    char buff[256];
 
55
    String str(buff,(uint32) sizeof(buff), system_charset_info);
 
56
    str.length(0);
 
57
    cond->print(&str, query_type);
 
58
    str.append('\0');
 
59
    DBUG_LOCK_FILE;
 
60
    (void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info);
 
61
    (void) fputs(str.ptr(),DBUG_FILE);
 
62
    (void) fputc('\n',DBUG_FILE);
 
63
    DBUG_UNLOCK_FILE;
 
64
  }
 
65
}
 
66
        /* This is for debugging purposes */
 
67
 
 
68
 
 
69
void print_cached_tables(void)
 
70
{
 
71
  uint idx,count,unused;
 
72
  TABLE *start_link,*lnk;
 
73
 
 
74
  /* purecov: begin tested */
 
75
  VOID(pthread_mutex_lock(&LOCK_open));
 
76
  puts("DB             Table                            Version  Thread  Open  Lock");
 
77
 
 
78
  for (idx=unused=0 ; idx < open_cache.records ; idx++)
 
79
  {
 
80
    TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
 
81
    printf("%-14.14s %-32s%6ld%8ld%6d  %s\n",
 
82
           entry->s->db.str, entry->s->table_name.str, entry->s->version,
 
83
           entry->in_use ? entry->in_use->thread_id : 0L,
 
84
           entry->db_stat ? 1 : 0,
 
85
           entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
 
86
    if (!entry->in_use)
 
87
      unused++;
 
88
  }
 
89
  count=0;
 
90
  if ((start_link=lnk=unused_tables))
 
91
  {
 
92
    do
 
93
    {
 
94
      if (lnk != lnk->next->prev || lnk != lnk->prev->next)
 
95
      {
 
96
        printf("unused_links isn't linked properly\n");
 
97
        return;
 
98
      }
 
99
    } while (count++ < open_cache.records && (lnk=lnk->next) != start_link);
 
100
    if (lnk != start_link)
 
101
    {
 
102
      printf("Unused_links aren't connected\n");
 
103
    }
 
104
  }
 
105
  if (count != unused)
 
106
    printf("Unused_links (%d) doesn't match open_cache: %d\n", count,unused);
 
107
  printf("\nCurrent refresh version: %ld\n",refresh_version);
 
108
  if (hash_check(&open_cache))
 
109
    printf("Error: File hash table is corrupted\n");
 
110
  fflush(stdout);
 
111
  VOID(pthread_mutex_unlock(&LOCK_open));
 
112
  /* purecov: end */
 
113
  return;
 
114
}
 
115
 
 
116
 
 
117
void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
 
118
{
 
119
  char buff[256],buff2[256];
 
120
  String str(buff,sizeof(buff),system_charset_info);
 
121
  String out(buff2,sizeof(buff2),system_charset_info);
 
122
  const char *sep;
 
123
  DBUG_ENTER("TEST_filesort");
 
124
 
 
125
  out.length(0);
 
126
  for (sep=""; s_length-- ; sortorder++, sep=" ")
 
127
  {
 
128
    out.append(sep);
 
129
    if (sortorder->reverse)
 
130
      out.append('-');
 
131
    if (sortorder->field)
 
132
    {
 
133
      if (sortorder->field->table_name)
 
134
      {
 
135
        out.append(*sortorder->field->table_name);
 
136
        out.append('.');
 
137
      }
 
138
      out.append(sortorder->field->field_name ? sortorder->field->field_name:
 
139
                 "tmp_table_column");
 
140
    }
 
141
    else
 
142
    {
 
143
      str.length(0);
 
144
      sortorder->item->print(&str, QT_ORDINARY);
 
145
      out.append(str);
 
146
    }
 
147
  }
 
148
  out.append('\0');                             // Purify doesn't like c_ptr()
 
149
  DBUG_LOCK_FILE;
 
150
  VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE));
 
151
  fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
 
152
  DBUG_UNLOCK_FILE;
 
153
  DBUG_VOID_RETURN;
 
154
}
 
155
 
 
156
 
 
157
void
 
158
TEST_join(JOIN *join)
 
159
{
 
160
  uint i,ref;
 
161
  DBUG_ENTER("TEST_join");
 
162
 
 
163
  DBUG_LOCK_FILE;
 
164
  VOID(fputs("\nInfo about JOIN\n",DBUG_FILE));
 
165
  for (i=0 ; i < join->tables ; i++)
 
166
  {
 
167
    JOIN_TAB *tab=join->join_tab+i;
 
168
    TABLE *form=tab->table;
 
169
    char key_map_buff[128];
 
170
    fprintf(DBUG_FILE,"%-16.16s  type: %-7s  q_keys: %s  refs: %d  key: %d  len: %d\n",
 
171
            form->alias,
 
172
            join_type_str[tab->type],
 
173
            tab->keys.print(key_map_buff),
 
174
            tab->ref.key_parts,
 
175
            tab->ref.key,
 
176
            tab->ref.key_length);
 
177
    if (tab->select)
 
178
    {
 
179
      char buf[MAX_KEY/8+1];
 
180
      if (tab->use_quick == 2)
 
181
        fprintf(DBUG_FILE,
 
182
                "                  quick select checked for each record (keys: %s)\n",
 
183
                tab->select->quick_keys.print(buf));
 
184
      else if (tab->select->quick)
 
185
      {
 
186
        fprintf(DBUG_FILE, "                  quick select used:\n");
 
187
        tab->select->quick->dbug_dump(18, FALSE);
 
188
      }
 
189
      else
 
190
        VOID(fputs("                  select used\n",DBUG_FILE));
 
191
    }
 
192
    if (tab->ref.key_parts)
 
193
    {
 
194
      VOID(fputs("                  refs: ",DBUG_FILE));
 
195
      for (ref=0 ; ref < tab->ref.key_parts ; ref++)
 
196
      {
 
197
        Item *item=tab->ref.items[ref];
 
198
        fprintf(DBUG_FILE,"%s  ", item->full_name());
 
199
      }
 
200
      VOID(fputc('\n',DBUG_FILE));
 
201
    }
 
202
  }
 
203
  DBUG_UNLOCK_FILE;
 
204
  DBUG_VOID_RETURN;
 
205
}
 
206
 
 
207
#define FT_KEYPART   (MAX_REF_PARTS+10)
 
208
 
 
209
void print_keyuse(KEYUSE *keyuse)
 
210
{
 
211
  char buff[256];
 
212
  char buf2[64]; 
 
213
  const char *fieldname;
 
214
  String str(buff,(uint32) sizeof(buff), system_charset_info);
 
215
  str.length(0);
 
216
  keyuse->val->print(&str, QT_ORDINARY);
 
217
  str.append('\0');
 
218
  if (keyuse->keypart == FT_KEYPART)
 
219
    fieldname= "FT_KEYPART";
 
220
  else
 
221
    fieldname= keyuse->table->key_info[keyuse->key].key_part[keyuse->keypart].field->field_name;
 
222
  longlong2str(keyuse->used_tables, buf2, 16); 
 
223
  DBUG_LOCK_FILE;
 
224
  fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s  optimize= %d used_tables=%s "
 
225
          "ref_table_rows= %lu keypart_map= %0lx\n",
 
226
          keyuse->table->alias, fieldname, str.ptr(),
 
227
          keyuse->optimize, buf2, (ulong)keyuse->ref_table_rows, 
 
228
          keyuse->keypart_map);
 
229
  DBUG_UNLOCK_FILE;
 
230
  //key_part_map keypart_map; --?? there can be several? 
 
231
}
 
232
 
 
233
 
 
234
void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array)
 
235
{
 
236
  DBUG_LOCK_FILE;
 
237
  fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements);
 
238
  DBUG_UNLOCK_FILE;
 
239
  for(uint i=0; i < keyuse_array->elements; i++)
 
240
    print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i));
 
241
}
 
242
 
 
243
 
 
244
/* 
 
245
  Print the current state during query optimization.
 
246
 
 
247
  SYNOPSIS
 
248
    print_plan()
 
249
    join         pointer to the structure providing all context info for
 
250
                 the query
 
251
    read_time    the cost of the best partial plan
 
252
    record_count estimate for the number of records returned by the best
 
253
                 partial plan
 
254
    idx          length of the partial QEP in 'join->positions';
 
255
                 also an index in the array 'join->best_ref';
 
256
    info         comment string to appear above the printout
 
257
 
 
258
  DESCRIPTION
 
259
    This function prints to the log file DBUG_FILE the members of 'join' that
 
260
    are used during query optimization (join->positions, join->best_positions,
 
261
    and join->best_ref) and few other related variables (read_time,
 
262
    record_count).
 
263
    Useful to trace query optimizer functions.
 
264
 
 
265
  RETURN
 
266
    None
 
267
*/
 
268
 
 
269
void
 
270
print_plan(JOIN* join, uint idx, double record_count, double read_time,
 
271
           double current_read_time, const char *info)
 
272
{
 
273
  uint i;
 
274
  POSITION pos;
 
275
  JOIN_TAB *join_table;
 
276
  JOIN_TAB **plan_nodes;
 
277
  TABLE*   table;
 
278
 
 
279
  if (info == 0)
 
280
    info= "";
 
281
 
 
282
  DBUG_LOCK_FILE;
 
283
  if (join->best_read == DBL_MAX)
 
284
  {
 
285
    fprintf(DBUG_FILE,
 
286
            "%s; idx: %u  best: DBL_MAX  atime: %g  itime: %g  count: %g\n",
 
287
            info, idx, current_read_time, read_time, record_count);
 
288
  }
 
289
  else
 
290
  {
 
291
    fprintf(DBUG_FILE,
 
292
            "%s; idx :%u  best: %g  accumulated: %g  increment: %g  count: %g\n",
 
293
            info, idx, join->best_read, current_read_time, read_time,
 
294
            record_count);
 
295
  }
 
296
 
 
297
  /* Print the tables in JOIN->positions */
 
298
  fputs("     POSITIONS: ", DBUG_FILE);
 
299
  for (i= 0; i < idx ; i++)
 
300
  {
 
301
    pos = join->positions[i];
 
302
    table= pos.table->table;
 
303
    if (table)
 
304
      fputs(table->s->table_name.str, DBUG_FILE);
 
305
    fputc(' ', DBUG_FILE);
 
306
  }
 
307
  fputc('\n', DBUG_FILE);
 
308
 
 
309
  /*
 
310
    Print the tables in JOIN->best_positions only if at least one complete plan
 
311
    has been found. An indicator for this is the value of 'join->best_read'.
 
312
  */
 
313
  if (join->best_read < DBL_MAX)
 
314
  {
 
315
    fputs("BEST_POSITIONS: ", DBUG_FILE);
 
316
    for (i= 0; i < idx ; i++)
 
317
    {
 
318
      pos= join->best_positions[i];
 
319
      table= pos.table->table;
 
320
      if (table)
 
321
        fputs(table->s->table_name.str, DBUG_FILE);
 
322
      fputc(' ', DBUG_FILE);
 
323
    }
 
324
  }
 
325
  fputc('\n', DBUG_FILE);
 
326
 
 
327
  /* Print the tables in JOIN->best_ref */
 
328
  fputs("      BEST_REF: ", DBUG_FILE);
 
329
  for (plan_nodes= join->best_ref ; *plan_nodes ; plan_nodes++)
 
330
  {
 
331
    join_table= (*plan_nodes);
 
332
    fputs(join_table->table->s->table_name.str, DBUG_FILE);
 
333
    fprintf(DBUG_FILE, "(%lu,%lu,%lu)",
 
334
            (ulong) join_table->found_records,
 
335
            (ulong) join_table->records,
 
336
            (ulong) join_table->read_time);
 
337
    fputc(' ', DBUG_FILE);
 
338
  }
 
339
  fputc('\n', DBUG_FILE);
 
340
 
 
341
  DBUG_UNLOCK_FILE;
 
342
}
 
343
 
 
344
#endif
 
345
 
 
346
typedef struct st_debug_lock
 
347
{
 
348
  ulong thread_id;
 
349
  char table_name[FN_REFLEN];
 
350
  bool waiting;
 
351
  const char *lock_text;
 
352
  enum thr_lock_type type;
 
353
} TABLE_LOCK_INFO;
 
354
 
 
355
static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b)
 
356
{
 
357
  if (a->thread_id > b->thread_id)
 
358
    return 1;
 
359
  if (a->thread_id < b->thread_id)
 
360
    return -1;
 
361
  if (a->waiting == b->waiting)
 
362
    return 0;
 
363
  else if (a->waiting)
 
364
    return -1;
 
365
  return 1;
 
366
}
 
367
 
 
368
 
 
369
static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data,
 
370
                                  bool wait, const char *text)
 
371
{
 
372
  if (data)
 
373
  {
 
374
    TABLE *table=(TABLE *)data->debug_print_param;
 
375
    if (table && table->s->tmp_table == NO_TMP_TABLE)
 
376
    {
 
377
      TABLE_LOCK_INFO table_lock_info;
 
378
      table_lock_info.thread_id= table->in_use->thread_id;
 
379
      memcpy(table_lock_info.table_name, table->s->table_cache_key.str,
 
380
             table->s->table_cache_key.length);
 
381
      table_lock_info.table_name[strlen(table_lock_info.table_name)]='.';
 
382
      table_lock_info.waiting=wait;
 
383
      table_lock_info.lock_text=text;
 
384
      // lock_type is also obtainable from THR_LOCK_DATA
 
385
      table_lock_info.type=table->reginfo.lock_type;
 
386
      VOID(push_dynamic(ar,(uchar*) &table_lock_info));
 
387
    }
 
388
  }
 
389
}
 
390
 
 
391
 
 
392
/*
 
393
  Regarding MERGE tables:
 
394
 
 
395
  For now, the best option is to use the common TABLE *pointer for all
 
396
  cases;  The drawback is that for MERGE tables we will see many locks
 
397
  for the merge tables even if some of them are for individual tables.
 
398
 
 
399
  The way to solve this is to add to 'THR_LOCK' structure a pointer to
 
400
  the filename and use this when printing the data.
 
401
  (We can for now ignore this and just print the same name for all merge
 
402
  table parts;  Please add the above as a comment to the display_lock
 
403
  function so that we can easily add this if we ever need this.
 
404
*/
 
405
 
 
406
static void display_table_locks(void) 
 
407
{
 
408
  LIST *list;
 
409
  DYNAMIC_ARRAY saved_table_locks;
 
410
 
 
411
  VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50));
 
412
  VOID(pthread_mutex_lock(&THR_LOCK_lock));
 
413
  for (list= thr_lock_thread_list; list; list= list_rest(list))
 
414
  {
 
415
    THR_LOCK *lock=(THR_LOCK*) list->data;
 
416
 
 
417
    VOID(pthread_mutex_lock(&lock->mutex));
 
418
    push_locks_into_array(&saved_table_locks, lock->write.data, FALSE,
 
419
                          "Locked - write");
 
420
    push_locks_into_array(&saved_table_locks, lock->write_wait.data, TRUE,
 
421
                          "Waiting - write");
 
422
    push_locks_into_array(&saved_table_locks, lock->read.data, FALSE,
 
423
                          "Locked - read");
 
424
    push_locks_into_array(&saved_table_locks, lock->read_wait.data, TRUE,
 
425
                          "Waiting - read");
 
426
    VOID(pthread_mutex_unlock(&lock->mutex));
 
427
  }
 
428
  VOID(pthread_mutex_unlock(&THR_LOCK_lock));
 
429
  if (!saved_table_locks.elements) goto end;
 
430
  
 
431
  qsort((uchar*) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare);
 
432
  freeze_size(&saved_table_locks);
 
433
 
 
434
  puts("\nThread database.table_name          Locked/Waiting        Lock_type\n");
 
435
  
 
436
  unsigned int i;
 
437
  for (i=0 ; i < saved_table_locks.elements ; i++)
 
438
  {
 
439
    TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*);
 
440
    printf("%-8ld%-28.28s%-22s%s\n",
 
441
           dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]);
 
442
  }
 
443
  puts("\n\n");
 
444
end:
 
445
  delete_dynamic(&saved_table_locks);
 
446
}
 
447
 
 
448
 
 
449
static int print_key_cache_status(const char *name, KEY_CACHE *key_cache)
 
450
{
 
451
  char llbuff1[22];
 
452
  char llbuff2[22];
 
453
  char llbuff3[22];
 
454
  char llbuff4[22];
 
455
 
 
456
  if (!key_cache->key_cache_inited)
 
457
  {
 
458
    printf("%s: Not in use\n", name);
 
459
  }
 
460
  else
 
461
  {
 
462
    printf("%s\n\
 
463
Buffer_size:    %10lu\n\
 
464
Block_size:     %10lu\n\
 
465
Division_limit: %10lu\n\
 
466
Age_limit:      %10lu\n\
 
467
blocks used:    %10lu\n\
 
468
not flushed:    %10lu\n\
 
469
w_requests:     %10s\n\
 
470
writes:         %10s\n\
 
471
r_requests:     %10s\n\
 
472
reads:          %10s\n\n",
 
473
           name,
 
474
           (ulong) key_cache->param_buff_size, key_cache->param_block_size,
 
475
           key_cache->param_division_limit, key_cache->param_age_threshold,
 
476
           key_cache->blocks_used,key_cache->global_blocks_changed,
 
477
           llstr(key_cache->global_cache_w_requests,llbuff1),
 
478
           llstr(key_cache->global_cache_write,llbuff2),
 
479
           llstr(key_cache->global_cache_r_requests,llbuff3),
 
480
           llstr(key_cache->global_cache_read,llbuff4));
 
481
  }
 
482
  return 0;
 
483
}
 
484
 
 
485
 
 
486
void mysql_print_status()
 
487
{
 
488
  char current_dir[FN_REFLEN];
 
489
  STATUS_VAR tmp;
 
490
 
 
491
  calc_sum_of_all_status(&tmp);
 
492
  printf("\nStatus information:\n\n");
 
493
  VOID(my_getwd(current_dir, sizeof(current_dir),MYF(0)));
 
494
  printf("Current dir: %s\n", current_dir);
 
495
  printf("Running threads: %d  Stack size: %ld\n", thread_count,
 
496
         (long) my_thread_stack_size);
 
497
  thr_print_locks();                            // Write some debug info
 
498
#ifndef DBUG_OFF
 
499
  print_cached_tables();
 
500
#endif
 
501
  /* Print key cache status */
 
502
  puts("\nKey caches:");
 
503
  process_key_caches(print_key_cache_status);
 
504
  pthread_mutex_lock(&LOCK_status);
 
505
  printf("\nhandler status:\n\
 
506
read_key:   %10lu\n\
 
507
read_next:  %10lu\n\
 
508
read_rnd    %10lu\n\
 
509
read_first: %10lu\n\
 
510
write:      %10lu\n\
 
511
delete      %10lu\n\
 
512
update:     %10lu\n",
 
513
         tmp.ha_read_key_count,
 
514
         tmp.ha_read_next_count,
 
515
         tmp.ha_read_rnd_count,
 
516
         tmp.ha_read_first_count,
 
517
         tmp.ha_write_count,
 
518
         tmp.ha_delete_count,
 
519
         tmp.ha_update_count);
 
520
  pthread_mutex_unlock(&LOCK_status);
 
521
  printf("\nTable status:\n\
 
522
Opened tables: %10lu\n\
 
523
Open tables:   %10lu\n\
 
524
Open files:    %10lu\n\
 
525
Open streams:  %10lu\n",
 
526
         tmp.opened_tables,
 
527
         (ulong) cached_open_tables(),
 
528
         (ulong) my_file_opened,
 
529
         (ulong) my_stream_opened);
 
530
 
 
531
  ALARM_INFO alarm_info;
 
532
#ifndef DONT_USE_THR_ALARM
 
533
  thr_alarm_info(&alarm_info);
 
534
  printf("\nAlarm status:\n\
 
535
Active alarms:   %u\n\
 
536
Max used alarms: %u\n\
 
537
Next alarm time: %lu\n",
 
538
         alarm_info.active_alarms,
 
539
         alarm_info.max_used_alarms,
 
540
         alarm_info.next_alarm_time);
 
541
#endif
 
542
  display_table_locks();
 
543
  fflush(stdout);
 
544
  my_checkmalloc();
 
545
  fprintf(stdout,"\nBegin safemalloc memory dump:\n"); // tag needed for test suite
 
546
  TERMINATE(stdout, 1);                         // Write malloc information
 
547
  fprintf(stdout,"\nEnd safemalloc memory dump.\n");  
 
548
 
 
549
#ifdef HAVE_MALLINFO
 
550
  struct mallinfo info= mallinfo();
 
551
  printf("\nMemory status:\n\
 
552
Non-mmapped space allocated from system: %d\n\
 
553
Number of free chunks:                   %d\n\
 
554
Number of fastbin blocks:                %d\n\
 
555
Number of mmapped regions:               %d\n\
 
556
Space in mmapped regions:                %d\n\
 
557
Maximum total allocated space:           %d\n\
 
558
Space available in freed fastbin blocks: %d\n\
 
559
Total allocated space:                   %d\n\
 
560
Total free space:                        %d\n\
 
561
Top-most, releasable space:              %d\n\
 
562
Estimated memory (with thread stack):    %ld\n",
 
563
         (int) info.arena       ,
 
564
         (int) info.ordblks,
 
565
         (int) info.smblks,
 
566
         (int) info.hblks,
 
567
         (int) info.hblkhd,
 
568
         (int) info.usmblks,
 
569
         (int) info.fsmblks,
 
570
         (int) info.uordblks,
 
571
         (int) info.fordblks,
 
572
         (int) info.keepcost,
 
573
         (long) (thread_count * my_thread_stack_size + info.hblkhd + info.arena));
 
574
#endif
 
575
 
 
576
  puts("");
 
577
}
 
578
 
 
579
 
 
580
#ifndef DBUG_OFF
 
581
#ifdef EXTRA_DEBUG_DUMP_TABLE_LISTS
 
582
 
 
583
 
 
584
/*
 
585
  A fixed-size FIFO pointer queue that also doesn't allow one to put an
 
586
  element that has previously been put into it. 
 
587
  
 
588
  There is a hard-coded limit of the total number of queue put operations.
 
589
  The implementation is trivial and is intended for use in debug dumps only.
 
590
*/
 
591
 
 
592
template <class T> class Unique_fifo_queue
 
593
{
 
594
public:
 
595
  /* Add an element to the queue */
 
596
  void push_back(T *tbl)
 
597
  {
 
598
    if (!tbl)
 
599
      return;
 
600
    // check if we've already scheduled and/or dumped the element
 
601
    for (int i= 0; i < last; i++)
 
602
    {
 
603
      if (elems[i] == tbl)
 
604
        return;
 
605
    }
 
606
    elems[last++]=  tbl;
 
607
  }
 
608
 
 
609
  bool pop_first(T **elem)
 
610
  {
 
611
    if (first < last)
 
612
    {
 
613
      *elem= elems[first++];
 
614
      return TRUE;
 
615
    }
 
616
    return FALSE;
 
617
  }
 
618
 
 
619
  void reset()
 
620
  {
 
621
    first= last= 0;
 
622
  }
 
623
  enum { MAX_ELEMS=1000};
 
624
  T *elems[MAX_ELEMS];
 
625
  int first; // First undumped table
 
626
  int last;  // Last undumped element
 
627
};
 
628
 
 
629
class Dbug_table_list_dumper
 
630
{
 
631
  FILE *out;
 
632
  Unique_fifo_queue<TABLE_LIST> tables_fifo;
 
633
  Unique_fifo_queue<List<TABLE_LIST> > tbl_lists;
 
634
public:
 
635
  void dump_one_struct(TABLE_LIST *tbl);
 
636
 
 
637
  int dump_graph(st_select_lex *select_lex, TABLE_LIST *first_leaf);
 
638
};
 
639
 
 
640
 
 
641
void dump_TABLE_LIST_graph(SELECT_LEX *select_lex, TABLE_LIST* tl)
 
642
{
 
643
  Dbug_table_list_dumper dumper;
 
644
  dumper.dump_graph(select_lex, tl);
 
645
}
 
646
 
 
647
 
 
648
/* 
 
649
  - Dump one TABLE_LIST objects and its outgoing edges
 
650
  - Schedule that other objects seen along the edges are dumped too.
 
651
*/
 
652
 
 
653
void Dbug_table_list_dumper::dump_one_struct(TABLE_LIST *tbl)
 
654
{
 
655
  fprintf(out, "\"%p\" [\n", tbl);
 
656
  fprintf(out, "  label = \"%p|", tbl);
 
657
  fprintf(out, "alias=%s|", tbl->alias? tbl->alias : "NULL");
 
658
  fprintf(out, "<next_leaf>next_leaf=%p|", tbl->next_leaf);
 
659
  fprintf(out, "<next_local>next_local=%p|", tbl->next_local);
 
660
  fprintf(out, "<next_global>next_global=%p|", tbl->next_global);
 
661
  fprintf(out, "<embedding>embedding=%p", tbl->embedding);
 
662
 
 
663
  if (tbl->nested_join)
 
664
    fprintf(out, "|<nested_j>nested_j=%p", tbl->nested_join);
 
665
  if (tbl->join_list)
 
666
    fprintf(out, "|<join_list>join_list=%p", tbl->join_list);
 
667
  if (tbl->on_expr)
 
668
    fprintf(out, "|<on_expr>on_expr=%p", tbl->on_expr);
 
669
  fprintf(out, "\"\n");
 
670
  fprintf(out, "  shape = \"record\"\n];\n\n");
 
671
 
 
672
  if (tbl->next_leaf)
 
673
  {
 
674
    fprintf(out, "\n\"%p\":next_leaf -> \"%p\"[ color = \"#000000\" ];\n",  
 
675
            tbl, tbl->next_leaf);
 
676
    tables_fifo.push_back(tbl->next_leaf);
 
677
  }
 
678
  if (tbl->next_local)
 
679
  {
 
680
    fprintf(out, "\n\"%p\":next_local -> \"%p\"[ color = \"#404040\" ];\n",  
 
681
            tbl, tbl->next_local);
 
682
    tables_fifo.push_back(tbl->next_local);
 
683
  }
 
684
  if (tbl->next_global)
 
685
  {
 
686
    fprintf(out, "\n\"%p\":next_global -> \"%p\"[ color = \"#808080\" ];\n",  
 
687
            tbl, tbl->next_global);
 
688
    tables_fifo.push_back(tbl->next_global);
 
689
  }
 
690
 
 
691
  if (tbl->embedding)
 
692
  {
 
693
    fprintf(out, "\n\"%p\":embedding -> \"%p\"[ color = \"#FF0000\" ];\n",  
 
694
            tbl, tbl->embedding);
 
695
    tables_fifo.push_back(tbl->embedding);
 
696
  }
 
697
 
 
698
  if (tbl->join_list)
 
699
  {
 
700
    fprintf(out, "\n\"%p\":join_list -> \"%p\"[ color = \"#0000FF\" ];\n",  
 
701
            tbl, tbl->join_list);
 
702
    tbl_lists.push_back(tbl->join_list);
 
703
  }
 
704
}
 
705
 
 
706
 
 
707
int Dbug_table_list_dumper::dump_graph(st_select_lex *select_lex, 
 
708
                                       TABLE_LIST *first_leaf)
 
709
{
 
710
  DBUG_ENTER("Dbug_table_list_dumper::dump_graph");
 
711
  char filename[500];
 
712
  int no = 0;
 
713
  do
 
714
  {
 
715
    sprintf(filename, "tlist_tree%.3d.g", no);
 
716
    if ((out= fopen(filename, "rt")))
 
717
    {
 
718
      /* File exists, try next name */
 
719
      fclose(out);
 
720
    }
 
721
    no++;
 
722
  } while (out);
 
723
 
 
724
  /* Ok, found an unoccupied name, create the file */
 
725
  if (!(out= fopen(filename, "wt")))
 
726
  {
 
727
    DBUG_PRINT("tree_dump", ("Failed to create output file"));
 
728
    DBUG_RETURN(1);
 
729
  }
 
730
 
 
731
  DBUG_PRINT("tree_dump", ("dumping tree to %s", filename));
 
732
     
 
733
  fputs("digraph g {\n", out);
 
734
  fputs("graph [", out);
 
735
  fputs("  rankdir = \"LR\"", out);
 
736
  fputs("];", out);
 
737
   
 
738
  TABLE_LIST *tbl;
 
739
  tables_fifo.reset();
 
740
  dump_one_struct(first_leaf);   
 
741
  while (tables_fifo.pop_first(&tbl))
 
742
  {
 
743
    dump_one_struct(tbl);
 
744
  }
 
745
 
 
746
  List<TABLE_LIST> *plist;
 
747
  tbl_lists.push_back(&select_lex->top_join_list);
 
748
  while (tbl_lists.pop_first(&plist))
 
749
  {
 
750
    fprintf(out, "\"%p\" [\n", plist);
 
751
    fprintf(out, "  bgcolor = \"\"");
 
752
    fprintf(out, "  label = \"L %p\"", plist);
 
753
    fprintf(out, "  shape = \"record\"\n];\n\n");
 
754
  }
 
755
 
 
756
  fprintf(out, " { rank = same; ");
 
757
  for (TABLE_LIST *tl=first_leaf; tl; tl= tl->next_leaf)
 
758
    fprintf(out, " \"%p\"; ", tl);
 
759
  fprintf(out, "};\n");
 
760
  fputs("}", out);
 
761
  fclose(out);
 
762
 
 
763
  char filename2[500];
 
764
  filename[strlen(filename) - 1]= 0;
 
765
  filename[strlen(filename) - 1]= 0;
 
766
  sprintf(filename2, "%s.query", filename);
 
767
  
 
768
  if ((out= fopen(filename2, "wt")))
 
769
  {
 
770
    fprintf(out, "%s", current_thd->query);
 
771
    fclose(out);
 
772
  }
 
773
  DBUG_RETURN(0);
 
774
}
 
775
 
 
776
#endif
 
777
 
 
778
#endif 
 
779