~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/show.cc

  • Committer: Andrew Hutchings
  • Date: 2011-01-21 11:23:19 UTC
  • mto: (2100.1.1 build)
  • mto: This revision was merged to the branch mainline in revision 2101.
  • Revision ID: andrew@linuxjedi.co.uk-20110121112319-nj1cvg0yt3nnf2rr
Add errors page to drizzle client docs
Add link to specific error in migration docs
Minor changes to migration docs

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems
 
4
 *  Copyright (C) 2008 Sun Microsystems, Inc.
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
34
34
#include <drizzled/item/return_date_time.h>
35
35
#include <drizzled/sql_base.h>
36
36
#include <drizzled/db.h>
37
 
#include <drizzled/field/timestamp.h>
 
37
#include <drizzled/field/epoch.h>
38
38
#include <drizzled/field/decimal.h>
39
39
#include <drizzled/lock.h>
40
40
#include <drizzled/item/return_date_time.h>
41
41
#include <drizzled/item/empty_string.h>
42
 
#include "drizzled/plugin/registry.h"
43
 
#include "drizzled/session_list.h"
 
42
#include "drizzled/session/cache.h"
44
43
#include <drizzled/message/schema.pb.h>
45
44
#include <drizzled/plugin/client.h>
46
45
#include <drizzled/cached_directory.h>
49
48
#include "drizzled/pthread_globals.h"
50
49
#include "drizzled/internal/m_string.h"
51
50
#include "drizzled/internal/my_sys.h"
 
51
#include "drizzled/message/statement_transform.h"
 
52
 
52
53
 
53
54
#include <sys/stat.h>
54
55
 
69
70
  return str ? str : "<nil>";
70
71
}
71
72
 
72
 
static void store_key_options(String *packet, Table *table, KEY *key_info);
73
 
 
74
 
 
75
73
int wild_case_compare(const CHARSET_INFO * const cs, const char *str, const char *wildstr)
76
74
{
77
75
  register int flag;
120
118
  return (*str != '\0');
121
119
}
122
120
 
123
 
 
124
 
bool drizzled_show_create(Session *session, TableList *table_list, bool is_if_not_exists)
125
 
{
126
 
  char buff[2048];
127
 
  String buffer(buff, sizeof(buff), system_charset_info);
128
 
 
129
 
  /* Only one table for now, but VIEW can involve several tables */
130
 
  if (session->openTables(table_list))
131
 
  {
132
 
    if (session->is_error())
133
 
      return true;
134
 
 
135
 
    /*
136
 
      Clear all messages with 'error' level status and
137
 
      issue a warning with 'warning' level status in
138
 
      case of invalid view and last error is ER_VIEW_INVALID
139
 
    */
140
 
    drizzle_reset_errors(session, true);
141
 
    session->clear_error();
142
 
  }
143
 
 
144
 
  buffer.length(0);
145
 
 
146
 
  if (store_create_info(table_list, &buffer, is_if_not_exists))
147
 
    return true;
148
 
 
149
 
  List<Item> field_list;
150
 
  {
151
 
    field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
152
 
    // 1024 is for not to confuse old clients
153
 
    field_list.push_back(new Item_empty_string("Create Table",
154
 
                                               max(buffer.length(),(uint32_t)1024)));
155
 
  }
156
 
 
157
 
  if (session->client->sendFields(&field_list))
158
 
    return true;
159
 
  {
160
 
    session->client->store(table_list->table->alias);
161
 
  }
162
 
 
163
 
  session->client->store(buffer.ptr(), buffer.length());
164
 
 
165
 
  if (session->client->flush())
166
 
    return true;
167
 
 
168
 
  session->my_eof();
169
 
  return false;
170
 
}
171
 
 
172
 
/**
173
 
  Get a CREATE statement for a given database.
174
 
 
175
 
  The database is identified by its name, passed as @c dbname parameter.
176
 
  The name should be encoded using the system character set (UTF8 currently).
177
 
 
178
 
  Resulting statement is stored in the string pointed by @c buffer. The string
179
 
  is emptied first and its character set is set to the system character set.
180
 
 
181
 
  If is_if_not_exists is set, then
182
 
  the resulting CREATE statement contains "IF NOT EXISTS" clause. Other flags
183
 
  in @c create_options are ignored.
184
 
 
185
 
  @param  session           The current thread instance.
186
 
  @param  dbname        The name of the database.
187
 
  @param  buffer        A String instance where the statement is stored.
188
 
  @param  create_info   If not NULL, the options member influences the resulting
189
 
                        CRATE statement.
190
 
 
191
 
  @returns true if errors are detected, false otherwise.
192
 
*/
193
 
 
194
 
static bool store_db_create_info(SchemaIdentifier &schema_identifier, string &buffer, bool if_not_exists)
195
 
{
196
 
  message::Schema schema;
197
 
 
198
 
  bool found= plugin::StorageEngine::getSchemaDefinition(schema_identifier, schema);
199
 
  if (not found)
200
 
    return false;
201
 
 
202
 
  buffer.append("CREATE DATABASE ");
203
 
 
204
 
  if (if_not_exists)
205
 
    buffer.append("IF NOT EXISTS ");
206
 
 
207
 
  buffer.append("`");
208
 
  buffer.append(schema.name());
209
 
  buffer.append("`");
210
 
 
211
 
  if (schema.has_collation())
212
 
  {
213
 
    buffer.append(" COLLATE = ");
214
 
    buffer.append(schema.collation());
215
 
  }
216
 
 
217
 
  return true;
218
 
}
219
 
 
220
 
bool mysqld_show_create_db(Session &session, SchemaIdentifier &schema_identifier, bool if_not_exists)
221
 
{
222
 
  message::Schema schema_message;
223
 
  string buffer;
224
 
 
225
 
  if (not plugin::StorageEngine::getSchemaDefinition(schema_identifier, schema_message))
226
 
  {
227
 
    /*
228
 
      This assumes that the only reason for which store_db_create_info()
229
 
      can fail is incorrect database name (which is the case now).
230
 
    */
231
 
    my_error(ER_BAD_DB_ERROR, MYF(0), schema_identifier.getSQLPath().c_str());
232
 
    return true;
233
 
  }
234
 
 
235
 
  if (not store_db_create_info(schema_identifier, buffer, if_not_exists))
236
 
  {
237
 
    /*
238
 
      This assumes that the only reason for which store_db_create_info()
239
 
      can fail is incorrect database name (which is the case now).
240
 
    */
241
 
    my_error(ER_BAD_DB_ERROR, MYF(0), schema_identifier.getSQLPath().c_str());
242
 
    return true;
243
 
  }
244
 
 
245
 
  List<Item> field_list;
246
 
  field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
247
 
  field_list.push_back(new Item_empty_string("Create Database",1024));
248
 
 
249
 
  if (session.client->sendFields(&field_list))
250
 
    return true;
251
 
 
252
 
  session.client->store(schema_message.name());
253
 
  session.client->store(buffer);
254
 
 
255
 
  if (session.client->flush())
256
 
    return true;
257
 
 
258
 
  session.my_eof();
259
 
 
260
 
  return false;
261
 
}
262
 
 
263
121
/*
264
122
  Get the quote character for displaying an identifier.
265
123
 
285
143
  return '`';
286
144
}
287
145
 
288
 
 
289
 
#define LIST_PROCESS_HOST_LEN 64
290
 
 
291
 
static bool get_field_default_value(Field *timestamp_field,
292
 
                                    Field *field, String *def_value,
293
 
                                    bool quoted)
294
 
{
295
 
  bool has_default;
296
 
  bool has_now_default;
297
 
 
298
 
  /*
299
 
     We are using CURRENT_TIMESTAMP instead of NOW because it is
300
 
     more standard
301
 
  */
302
 
  has_now_default= (timestamp_field == field &&
303
 
                    field->unireg_check != Field::TIMESTAMP_UN_FIELD);
304
 
 
305
 
  has_default= (field->type() != DRIZZLE_TYPE_BLOB &&
306
 
                !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
307
 
                field->unireg_check != Field::NEXT_NUMBER);
308
 
 
309
 
  def_value->length(0);
310
 
  if (has_default)
311
 
  {
312
 
    if (has_now_default)
313
 
      def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
314
 
    else if (!field->is_null())
315
 
    {                                             // Not null by default
316
 
      char tmp[MAX_FIELD_WIDTH];
317
 
      String type(tmp, sizeof(tmp), field->charset());
318
 
      field->val_str(&type);
319
 
      if (type.length())
320
 
      {
321
 
        String def_val;
322
 
        uint32_t dummy_errors;
323
 
        /* convert to system_charset_info == utf8 */
324
 
        def_val.copy(type.ptr(), type.length(), field->charset(),
325
 
                     system_charset_info, &dummy_errors);
326
 
        if (quoted)
327
 
          append_unescaped(def_value, def_val.ptr(), def_val.length());
328
 
        else
329
 
          def_value->append(def_val.ptr(), def_val.length());
330
 
      }
331
 
      else if (quoted)
332
 
        def_value->append(STRING_WITH_LEN("''"));
333
 
    }
334
 
    else if (field->maybe_null() && quoted)
335
 
      def_value->append(STRING_WITH_LEN("NULL"));    // Null as default
336
 
    else
337
 
      return false;
338
 
  }
339
 
  return has_default;
340
 
}
341
 
 
342
 
/*
343
 
  Build a CREATE TABLE statement for a table.
344
 
 
345
 
  SYNOPSIS
346
 
    store_create_info()
347
 
    table_list        A list containing one table to write statement
348
 
                      for.
349
 
    packet            Pointer to a string where statement will be
350
 
                      written.
351
 
 
352
 
  NOTE
353
 
    Currently always return 0, but might return error code in the
354
 
    future.
355
 
 
356
 
  RETURN
357
 
    0       OK
358
 
 */
359
 
 
360
 
int store_create_info(TableList *table_list, String *packet, bool is_if_not_exists)
361
 
{
362
 
  List<Item> field_list;
363
 
  char tmp[MAX_FIELD_WIDTH], *for_str, def_value_buf[MAX_FIELD_WIDTH];
364
 
  const char *alias;
365
 
  string buff;
366
 
  String type(tmp, sizeof(tmp), system_charset_info);
367
 
  String def_value(def_value_buf, sizeof(def_value_buf), system_charset_info);
368
 
  Field **ptr,*field;
369
 
  uint32_t primary_key;
370
 
  KEY *key_info;
371
 
  Table *table= table_list->table;
372
 
  Cursor *cursor= table->cursor;
373
 
  TableShare *share= table->s;
374
 
  HA_CREATE_INFO create_info;
375
 
  bool show_table_options= false;
376
 
  my_bitmap_map *old_map;
377
 
 
378
 
  table->restoreRecordAsDefault(); // Get empty record
379
 
 
380
 
  if (share->tmp_table)
381
 
    packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
382
 
  else
383
 
    packet->append(STRING_WITH_LEN("CREATE TABLE "));
384
 
  if (is_if_not_exists)
385
 
    packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
386
 
  alias= share->table_name.str;
387
 
 
388
 
  packet->append_identifier(alias, strlen(alias));
389
 
  packet->append(STRING_WITH_LEN(" (\n"));
390
 
  /*
391
 
    We need this to get default values from the table
392
 
    We have to restore the read_set if we are called from insert in case
393
 
    of row based replication.
394
 
  */
395
 
  old_map= table->use_all_columns(table->read_set);
396
 
 
397
 
  for (ptr=table->field ; (field= *ptr); ptr++)
398
 
  {
399
 
    uint32_t flags = field->flags;
400
 
 
401
 
    if (ptr != table->field)
402
 
      packet->append(STRING_WITH_LEN(",\n"));
403
 
 
404
 
    packet->append(STRING_WITH_LEN("  "));
405
 
    packet->append_identifier(field->field_name, strlen(field->field_name));
406
 
    packet->append(' ');
407
 
    // check for surprises from the previous call to Field::sql_type()
408
 
    if (type.ptr() != tmp)
409
 
      type.set(tmp, sizeof(tmp), system_charset_info);
410
 
    else
411
 
      type.set_charset(system_charset_info);
412
 
 
413
 
    field->sql_type(type);
414
 
    packet->append(type.ptr(), type.length(), system_charset_info);
415
 
 
416
 
    if (field->has_charset())
417
 
    {
418
 
      /*
419
 
        For string types dump collation name only if
420
 
        collation is not primary for the given charset
421
 
      */
422
 
      if (!(field->charset()->state & MY_CS_PRIMARY))
423
 
      {
424
 
        packet->append(STRING_WITH_LEN(" COLLATE "));
425
 
        packet->append(field->charset()->name);
426
 
      }
427
 
    }
428
 
 
429
 
    if (flags & NOT_NULL_FLAG)
430
 
      packet->append(STRING_WITH_LEN(" NOT NULL"));
431
 
    else if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
432
 
    {
433
 
      /*
434
 
        TIMESTAMP field require explicit NULL flag, because unlike
435
 
        all other fields they are treated as NOT NULL by default.
436
 
      */
437
 
      packet->append(STRING_WITH_LEN(" NULL"));
438
 
    }
439
 
    {
440
 
      /*
441
 
        Add field flags about FIELD FORMAT (FIXED or DYNAMIC)
442
 
        and about STORAGE (DISK or MEMORY).
443
 
      */
444
 
      enum column_format_type column_format= (enum column_format_type)
445
 
        ((flags >> COLUMN_FORMAT_FLAGS) & COLUMN_FORMAT_MASK);
446
 
      if (column_format)
447
 
      {
448
 
        packet->append(STRING_WITH_LEN(" /*!"));
449
 
        packet->append(STRING_WITH_LEN(" COLUMN_FORMAT"));
450
 
        if (column_format == COLUMN_FORMAT_TYPE_FIXED)
451
 
          packet->append(STRING_WITH_LEN(" FIXED */"));
452
 
        else
453
 
          packet->append(STRING_WITH_LEN(" DYNAMIC */"));
454
 
      }
455
 
    }
456
 
    if (get_field_default_value(table->timestamp_field, field, &def_value, 1))
457
 
    {
458
 
      packet->append(STRING_WITH_LEN(" DEFAULT "));
459
 
      packet->append(def_value.ptr(), def_value.length(), system_charset_info);
460
 
    }
461
 
 
462
 
    if (table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD)
463
 
      packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
464
 
 
465
 
    if (field->unireg_check == Field::NEXT_NUMBER)
466
 
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
467
 
 
468
 
    if (field->comment.length)
469
 
    {
470
 
      packet->append(STRING_WITH_LEN(" COMMENT "));
471
 
      append_unescaped(packet, field->comment.str, field->comment.length);
472
 
    }
473
 
  }
474
 
 
475
 
  key_info= table->key_info;
476
 
  memset(&create_info, 0, sizeof(create_info));
477
 
  /* Allow update_create_info to update row type */
478
 
  create_info.row_type= share->row_type;
479
 
  cursor->update_create_info(&create_info);
480
 
  primary_key= share->primary_key;
481
 
 
482
 
  for (uint32_t i=0 ; i < share->keys ; i++,key_info++)
483
 
  {
484
 
    KEY_PART_INFO *key_part= key_info->key_part;
485
 
    bool found_primary=0;
486
 
    packet->append(STRING_WITH_LEN(",\n  "));
487
 
 
488
 
    if (i == primary_key && is_primary_key(key_info))
489
 
    {
490
 
      found_primary=1;
491
 
      /*
492
 
        No space at end, because a space will be added after where the
493
 
        identifier would go, but that is not added for primary key.
494
 
      */
495
 
      packet->append(STRING_WITH_LEN("PRIMARY KEY"));
496
 
    }
497
 
    else if (key_info->flags & HA_NOSAME)
498
 
      packet->append(STRING_WITH_LEN("UNIQUE KEY "));
499
 
    else
500
 
      packet->append(STRING_WITH_LEN("KEY "));
501
 
 
502
 
    if (!found_primary)
503
 
     packet->append_identifier(key_info->name, strlen(key_info->name));
504
 
 
505
 
    packet->append(STRING_WITH_LEN(" ("));
506
 
 
507
 
    for (uint32_t j=0 ; j < key_info->key_parts ; j++,key_part++)
508
 
    {
509
 
      if (j)
510
 
        packet->append(',');
511
 
 
512
 
      if (key_part->field)
513
 
        packet->append_identifier(key_part->field->field_name,
514
 
                                  strlen(key_part->field->field_name));
515
 
      if (key_part->field &&
516
 
          (key_part->length !=
517
 
           table->field[key_part->fieldnr-1]->key_length()))
518
 
      {
519
 
        buff.assign("(");
520
 
        buff.append(to_string((int32_t) key_part->length /
521
 
                              key_part->field->charset()->mbmaxlen));
522
 
        buff.append(")");
523
 
        packet->append(buff.c_str(), buff.length());
524
 
      }
525
 
    }
526
 
    packet->append(')');
527
 
    store_key_options(packet, table, key_info);
528
 
  }
529
 
 
530
 
  /*
531
 
    Get possible foreign key definitions stored in InnoDB and append them
532
 
    to the CREATE TABLE statement
533
 
  */
534
 
 
535
 
  if ((for_str= cursor->get_foreign_key_create_info()))
536
 
  {
537
 
    packet->append(for_str, strlen(for_str));
538
 
    cursor->free_foreign_key_create_info(for_str);
539
 
  }
540
 
 
541
 
  packet->append(STRING_WITH_LEN("\n)"));
542
 
  {
543
 
    show_table_options= true;
544
 
    /*
545
 
      Get possible table space definitions and append them
546
 
      to the CREATE TABLE statement
547
 
    */
548
 
 
549
 
    /* 
550
 
      We should always store engine since we will now be 
551
 
      making sure engines accept options (aka... no
552
 
      dangling arguments for engines.
553
 
    */
554
 
    packet->append(STRING_WITH_LEN(" ENGINE="));
555
 
    packet->append(cursor->engine->getName().c_str());
556
 
 
557
 
    if (share->db_create_options & HA_OPTION_PACK_KEYS)
558
 
      packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
559
 
    if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
560
 
      packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
561
 
    if (create_info.row_type != ROW_TYPE_DEFAULT)
562
 
    {
563
 
      packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
564
 
      packet->append(ha_row_type[(uint32_t) create_info.row_type]);
565
 
    }
566
 
    if (table->s->hasKeyBlockSize())
567
 
    {
568
 
      packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
569
 
      buff= to_string(table->s->getKeyBlockSize());
570
 
      packet->append(buff.c_str(), buff.length());
571
 
    }
572
 
    if (share->block_size)
573
 
    {
574
 
      packet->append(STRING_WITH_LEN(" BLOCK_SIZE="));
575
 
      buff= to_string(share->block_size);
576
 
      packet->append(buff.c_str(), buff.length());
577
 
    }
578
 
    table->cursor->append_create_info(packet);
579
 
    if (share->hasComment() && share->getCommentLength())
580
 
    {
581
 
      packet->append(STRING_WITH_LEN(" COMMENT="));
582
 
      append_unescaped(packet, share->getComment(),
583
 
                       share->getCommentLength());
584
 
    }
585
 
  }
586
 
  table->restore_column_map(old_map);
587
 
  return(0);
588
 
}
589
 
 
590
 
static void store_key_options(String *packet, Table *table, KEY *key_info)
591
 
{
592
 
  char *end, buff[32];
593
 
 
594
 
  if (key_info->algorithm == HA_KEY_ALG_BTREE)
595
 
    packet->append(STRING_WITH_LEN(" USING BTREE"));
596
 
 
597
 
  if (key_info->algorithm == HA_KEY_ALG_HASH)
598
 
    packet->append(STRING_WITH_LEN(" USING HASH"));
599
 
 
600
 
  if ((key_info->flags & HA_USES_BLOCK_SIZE) &&
601
 
      table->s->getKeyBlockSize() != key_info->block_size)
602
 
  {
603
 
    packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
604
 
    end= internal::int64_t10_to_str(key_info->block_size, buff, 10);
605
 
    packet->append(buff, (uint32_t) (end - buff));
606
 
  }
607
 
 
608
 
  assert(test(key_info->flags & HA_USES_COMMENT) ==
609
 
              (key_info->comment.length > 0));
610
 
  if (key_info->flags & HA_USES_COMMENT)
611
 
  {
612
 
    packet->append(STRING_WITH_LEN(" COMMENT "));
613
 
    append_unescaped(packet, key_info->comment.str,
614
 
                     key_info->comment.length);
615
 
  }
616
 
}
617
 
 
618
 
 
619
 
/****************************************************************************
620
 
  Return info about all processes
621
 
  returns for each thread: thread id, user, host, db, command, info
622
 
****************************************************************************/
623
 
 
624
 
class thread_info
625
 
{
626
 
  thread_info();
627
 
public:
628
 
  uint64_t thread_id;
629
 
  time_t start_time;
630
 
  uint32_t   command;
631
 
  string user;
632
 
  string host;
633
 
  string db;
634
 
  string proc_info;
635
 
  string state_info;
636
 
  string query;
637
 
  thread_info(uint64_t thread_id_arg,
638
 
              time_t start_time_arg,
639
 
              uint32_t command_arg,
640
 
              const string &user_arg,
641
 
              const string &host_arg,
642
 
              const string &db_arg,
643
 
              const string &proc_info_arg,
644
 
              const string &state_info_arg,
645
 
              const string &query_arg)
646
 
    : thread_id(thread_id_arg), start_time(start_time_arg), command(command_arg),
647
 
      user(user_arg), host(host_arg), db(db_arg), proc_info(proc_info_arg),
648
 
      state_info(state_info_arg), query(query_arg)
649
 
  {}
650
 
};
651
 
 
652
 
/*****************************************************************************
653
 
  Status functions
654
 
*****************************************************************************/
655
 
 
656
 
static vector<drizzle_show_var *> all_status_vars;
657
 
static vector<drizzle_show_var *> com_status_vars;
658
 
static bool status_vars_inited= 0;
659
 
static int show_var_cmp(const void *var1, const void *var2)
660
 
{
661
 
  return strcmp(((drizzle_show_var*)var1)->name, ((drizzle_show_var*)var2)->name);
662
 
}
663
 
 
664
 
class show_var_cmp_functor
665
 
{
666
 
  public:
667
 
  show_var_cmp_functor() { }
668
 
  inline bool operator()(const drizzle_show_var *var1, const drizzle_show_var *var2) const
669
 
  {
670
 
    int val= strcmp(var1->name, var2->name);
671
 
    return (val < 0);
672
 
  }
673
 
};
674
 
 
675
 
class show_var_remove_if
676
 
{
677
 
  public:
678
 
  show_var_remove_if() { }
679
 
  inline bool operator()(const drizzle_show_var *curr) const
680
 
  {
681
 
    return (curr->type == SHOW_UNDEF);
682
 
  }
683
 
};
684
 
 
685
 
drizzle_show_var *getFrontOfStatusVars()
686
 
{
687
 
  return all_status_vars.front();
688
 
}
689
 
 
690
 
drizzle_show_var *getCommandStatusVars()
691
 
{
692
 
  return com_status_vars.front();
693
 
}
694
 
 
695
 
/*
696
 
  Adds an array of drizzle_show_var entries to the output of SHOW STATUS
697
 
 
698
 
  SYNOPSIS
699
 
    add_status_vars(drizzle_show_var *list)
700
 
    list - an array of drizzle_show_var entries to add to all_status_vars
701
 
           the last entry must be {0,0,SHOW_UNDEF}
702
 
 
703
 
  NOTE
704
 
    The handling of all_status_vars[] is completely internal, it's allocated
705
 
    automatically when something is added to it, and deleted completely when
706
 
    the last entry is removed.
707
 
 
708
 
    As a special optimization, if add_status_vars() is called before
709
 
    init_status_vars(), it assumes "startup mode" - neither concurrent access
710
 
    to the array nor SHOW STATUS are possible (thus it skips locks and qsort)
711
 
*/
712
 
int add_status_vars(drizzle_show_var *list)
713
 
{
714
 
  int res= 0;
715
 
  if (status_vars_inited)
716
 
    pthread_mutex_lock(&LOCK_status);
717
 
  while (list->name)
718
 
    all_status_vars.insert(all_status_vars.begin(), list++);
719
 
  if (status_vars_inited)
720
 
    sort(all_status_vars.begin(), all_status_vars.end(),
721
 
         show_var_cmp_functor());
722
 
  if (status_vars_inited)
723
 
    pthread_mutex_unlock(&LOCK_status);
724
 
  return res;
725
 
}
726
 
 
727
 
int add_com_status_vars(drizzle_show_var *list)
728
 
{
729
 
  int res= 0;
730
 
 
731
 
  while (list->name)
732
 
    com_status_vars.insert(com_status_vars.begin(), list++);
733
 
  if (status_vars_inited)
734
 
    sort(com_status_vars.begin(), com_status_vars.end(),
735
 
         show_var_cmp_functor());
736
 
 
737
 
  return res;
738
 
}
739
 
 
740
 
/*
741
 
  Make all_status_vars[] usable for SHOW STATUS
742
 
 
743
 
  NOTE
744
 
    See add_status_vars(). Before init_status_vars() call, add_status_vars()
745
 
    works in a special fast "startup" mode. Thus init_status_vars()
746
 
    should be called as late as possible but before enabling multi-threading.
747
 
*/
748
 
void init_status_vars()
749
 
{
750
 
  status_vars_inited= 1;
751
 
  sort(all_status_vars.begin(), all_status_vars.end(),
752
 
       show_var_cmp_functor());
753
 
  sort(com_status_vars.begin(), com_status_vars.end(),
754
 
       show_var_cmp_functor());
755
 
}
756
 
 
757
 
void reset_status_vars()
758
 
{
759
 
  vector<drizzle_show_var *>::iterator p;
760
 
 
761
 
  p= all_status_vars.begin();
762
 
  while (p != all_status_vars.end())
763
 
  {
764
 
    /* Note that SHOW_LONG_NOFLUSH variables are not reset */
765
 
    if ((*p)->type == SHOW_LONG)
766
 
      (*p)->value= 0;
767
 
    ++p;
768
 
  }
769
 
 
770
 
  p= com_status_vars.begin();
771
 
  while (p != com_status_vars.end())
772
 
  {
773
 
    /* Note that SHOW_LONG_NOFLUSH variables are not reset */
774
 
    if ((*p)->type == SHOW_LONG)
775
 
      (*p)->value= 0;
776
 
    ++p;
777
 
  }
778
 
}
779
 
 
780
 
/*
781
 
  catch-all cleanup function, cleans up everything no matter what
782
 
 
783
 
  DESCRIPTION
784
 
    This function is not strictly required if all add_to_status/
785
 
    remove_status_vars are properly paired, but it's a safety measure that
786
 
    deletes everything from the all_status_vars vector even if some
787
 
    remove_status_vars were forgotten
788
 
*/
789
 
void free_status_vars()
790
 
{
791
 
  all_status_vars.clear();
792
 
  com_status_vars.clear();
793
 
}
794
 
 
795
 
/*
796
 
  Removes an array of drizzle_show_var entries from the output of SHOW STATUS
797
 
 
798
 
  SYNOPSIS
799
 
    remove_status_vars(drizzle_show_var *list)
800
 
    list - an array of drizzle_show_var entries to remove to all_status_vars
801
 
           the last entry must be {0,0,SHOW_UNDEF}
802
 
 
803
 
  NOTE
804
 
    there's lots of room for optimizing this, especially in non-sorted mode,
805
 
    but nobody cares - it may be called only in case of failed plugin
806
 
    initialization in the mysqld startup.
807
 
*/
808
 
 
809
 
void remove_status_vars(drizzle_show_var *list)
810
 
{
811
 
  if (status_vars_inited)
812
 
  {
813
 
    pthread_mutex_lock(&LOCK_status);
814
 
    drizzle_show_var *all= all_status_vars.front();
815
 
    int a= 0, b= all_status_vars.size(), c= (a+b)/2;
816
 
 
817
 
    for (; list->name; list++)
818
 
    {
819
 
      int res= 0;
820
 
      for (a= 0, b= all_status_vars.size(); b-a > 1; c= (a+b)/2)
821
 
      {
822
 
        res= show_var_cmp(list, all+c);
823
 
        if (res < 0)
824
 
          b= c;
825
 
        else if (res > 0)
826
 
          a= c;
827
 
        else
828
 
          break;
829
 
      }
830
 
      if (res == 0)
831
 
        all[c].type= SHOW_UNDEF;
832
 
    }
833
 
    /* removes all the SHOW_UNDEF elements from the vector */
834
 
    all_status_vars.erase(std::remove_if(all_status_vars.begin(),
835
 
                            all_status_vars.end(),show_var_remove_if()),
836
 
                            all_status_vars.end());
837
 
    pthread_mutex_unlock(&LOCK_status);
838
 
  }
839
 
  else
840
 
  {
841
 
    drizzle_show_var *all= all_status_vars.front();
842
 
    uint32_t i;
843
 
    for (; list->name; list++)
844
 
    {
845
 
      for (i= 0; i < all_status_vars.size(); i++)
846
 
      {
847
 
        if (show_var_cmp(list, all+i))
848
 
          continue;
849
 
        all[i].type= SHOW_UNDEF;
850
 
        break;
851
 
      }
852
 
    }
853
 
    /* removes all the SHOW_UNDEF elements from the vector */
854
 
    all_status_vars.erase(std::remove_if(all_status_vars.begin(),
855
 
                            all_status_vars.end(),show_var_remove_if()),
856
 
                            all_status_vars.end());
857
 
  }
858
 
}
859
 
 
860
 
/* collect status for all running threads */
861
 
 
862
 
void calc_sum_of_all_status(system_status_var *to)
863
 
{
864
 
  /* Ensure that thread id not killed during loop */
865
 
  pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
866
 
 
867
 
  /* Get global values as base */
868
 
  *to= global_status_var;
869
 
 
870
 
  /* Add to this status from existing threads */
871
 
  for(SessionList::iterator it= getSessionList().begin(); it != getSessionList().end(); ++it )
872
 
  {
873
 
    add_to_status(to, &((*it)->status_var));
874
 
  }
875
 
 
876
 
  pthread_mutex_unlock(&LOCK_thread_count);
877
 
  return;
878
 
}
879
 
 
880
146
} /* namespace drizzled */