~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/show.cc

  • Committer: LinuxJedi
  • Date: 2010-08-12 17:36:08 UTC
  • mto: (1735.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1736.
  • Revision ID: linuxjedi@linuxjedi-laptop-20100812173608-ccr246iaa8gv3s97
Remove module pointer from registry when module doesn't load to avoid a double-free on shutdown.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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/session/cache.h"
 
42
#include "drizzled/session_list.h"
43
43
#include <drizzled/message/schema.pb.h>
44
44
#include <drizzled/plugin/client.h>
45
45
#include <drizzled/cached_directory.h>
48
48
#include "drizzled/pthread_globals.h"
49
49
#include "drizzled/internal/m_string.h"
50
50
#include "drizzled/internal/my_sys.h"
51
 
#include "drizzled/message/statement_transform.h"
52
 
 
53
51
 
54
52
#include <sys/stat.h>
55
53
 
70
68
  return str ? str : "<nil>";
71
69
}
72
70
 
 
71
static void store_key_options(String *packet, Table *table, KeyInfo *key_info);
 
72
 
 
73
 
73
74
int wild_case_compare(const CHARSET_INFO * const cs, const char *str, const char *wildstr)
74
75
{
75
76
  register int flag;
118
119
  return (*str != '\0');
119
120
}
120
121
 
 
122
 
 
123
bool drizzled_show_create(Session *session, TableList *table_list, bool is_if_not_exists)
 
124
{
 
125
  char buff[2048];
 
126
  String buffer(buff, sizeof(buff), system_charset_info);
 
127
 
 
128
  /* Only one table for now, but VIEW can involve several tables */
 
129
  if (session->openTables(table_list))
 
130
  {
 
131
    if (session->is_error())
 
132
      return true;
 
133
 
 
134
    /*
 
135
      Clear all messages with 'error' level status and
 
136
      issue a warning with 'warning' level status in
 
137
      case of invalid view and last error is ER_VIEW_INVALID
 
138
    */
 
139
    drizzle_reset_errors(session, true);
 
140
    session->clear_error();
 
141
  }
 
142
 
 
143
  buffer.length(0);
 
144
 
 
145
  if (store_create_info(table_list, &buffer, is_if_not_exists))
 
146
    return true;
 
147
 
 
148
  List<Item> field_list;
 
149
  {
 
150
    field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
 
151
    // 1024 is for not to confuse old clients
 
152
    field_list.push_back(new Item_empty_string("Create Table",
 
153
                                               max(buffer.length(),(uint32_t)1024)));
 
154
  }
 
155
 
 
156
  if (session->client->sendFields(&field_list))
 
157
    return true;
 
158
  {
 
159
    session->client->store(table_list->table->getAlias());
 
160
  }
 
161
 
 
162
  session->client->store(buffer.ptr(), buffer.length());
 
163
 
 
164
  if (session->client->flush())
 
165
    return true;
 
166
 
 
167
  session->my_eof();
 
168
  return false;
 
169
}
 
170
 
 
171
/**
 
172
  Get a CREATE statement for a given database.
 
173
 
 
174
  The database is identified by its name, passed as @c dbname parameter.
 
175
  The name should be encoded using the system character set (UTF8 currently).
 
176
 
 
177
  Resulting statement is stored in the string pointed by @c buffer. The string
 
178
  is emptied first and its character set is set to the system character set.
 
179
 
 
180
  If is_if_not_exists is set, then
 
181
  the resulting CREATE statement contains "IF NOT EXISTS" clause. Other flags
 
182
  in @c create_options are ignored.
 
183
 
 
184
  @param  session           The current thread instance.
 
185
  @param  dbname        The name of the database.
 
186
  @param  buffer        A String instance where the statement is stored.
 
187
  @param  create_info   If not NULL, the options member influences the resulting
 
188
                        CRATE statement.
 
189
 
 
190
  @returns true if errors are detected, false otherwise.
 
191
*/
 
192
 
 
193
static bool store_db_create_info(SchemaIdentifier &schema_identifier, string &buffer, bool if_not_exists)
 
194
{
 
195
  message::Schema schema;
 
196
 
 
197
  bool found= plugin::StorageEngine::getSchemaDefinition(schema_identifier, schema);
 
198
  if (not found)
 
199
    return false;
 
200
 
 
201
  buffer.append("CREATE DATABASE ");
 
202
 
 
203
  if (if_not_exists)
 
204
    buffer.append("IF NOT EXISTS ");
 
205
 
 
206
  buffer.append("`");
 
207
  buffer.append(schema.name());
 
208
  buffer.append("`");
 
209
 
 
210
  if (schema.has_collation())
 
211
  {
 
212
    buffer.append(" COLLATE = ");
 
213
    buffer.append(schema.collation());
 
214
  }
 
215
 
 
216
  return true;
 
217
}
 
218
 
 
219
bool mysqld_show_create_db(Session &session, SchemaIdentifier &schema_identifier, bool if_not_exists)
 
220
{
 
221
  message::Schema schema_message;
 
222
  string buffer;
 
223
 
 
224
  if (not plugin::StorageEngine::getSchemaDefinition(schema_identifier, schema_message))
 
225
  {
 
226
    /*
 
227
      This assumes that the only reason for which store_db_create_info()
 
228
      can fail is incorrect database name (which is the case now).
 
229
    */
 
230
    my_error(ER_BAD_DB_ERROR, MYF(0), schema_identifier.getSQLPath().c_str());
 
231
    return true;
 
232
  }
 
233
 
 
234
  if (not store_db_create_info(schema_identifier, buffer, if_not_exists))
 
235
  {
 
236
    /*
 
237
      This assumes that the only reason for which store_db_create_info()
 
238
      can fail is incorrect database name (which is the case now).
 
239
    */
 
240
    my_error(ER_BAD_DB_ERROR, MYF(0), schema_identifier.getSQLPath().c_str());
 
241
    return true;
 
242
  }
 
243
 
 
244
  List<Item> field_list;
 
245
  field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
 
246
  field_list.push_back(new Item_empty_string("Create Database",1024));
 
247
 
 
248
  if (session.client->sendFields(&field_list))
 
249
    return true;
 
250
 
 
251
  session.client->store(schema_message.name());
 
252
  session.client->store(buffer);
 
253
 
 
254
  if (session.client->flush())
 
255
    return true;
 
256
 
 
257
  session.my_eof();
 
258
 
 
259
  return false;
 
260
}
 
261
 
121
262
/*
122
263
  Get the quote character for displaying an identifier.
123
264
 
143
284
  return '`';
144
285
}
145
286
 
 
287
 
 
288
#define LIST_PROCESS_HOST_LEN 64
 
289
 
 
290
static bool get_field_default_value(Field *timestamp_field,
 
291
                                    Field *field, String *def_value,
 
292
                                    bool quoted)
 
293
{
 
294
  bool has_default;
 
295
  bool has_now_default;
 
296
 
 
297
  /*
 
298
     We are using CURRENT_TIMESTAMP instead of NOW because it is
 
299
     more standard
 
300
  */
 
301
  has_now_default= (timestamp_field == field &&
 
302
                    field->unireg_check != Field::TIMESTAMP_UN_FIELD);
 
303
 
 
304
  has_default= (field->type() != DRIZZLE_TYPE_BLOB &&
 
305
                !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
 
306
                field->unireg_check != Field::NEXT_NUMBER);
 
307
 
 
308
  def_value->length(0);
 
309
  if (has_default)
 
310
  {
 
311
    if (has_now_default)
 
312
      def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
 
313
    else if (!field->is_null())
 
314
    {                                             // Not null by default
 
315
      char tmp[MAX_FIELD_WIDTH];
 
316
      String type(tmp, sizeof(tmp), field->charset());
 
317
      field->val_str(&type);
 
318
      if (type.length())
 
319
      {
 
320
        String def_val;
 
321
        uint32_t dummy_errors;
 
322
        /* convert to system_charset_info == utf8 */
 
323
        def_val.copy(type.ptr(), type.length(), field->charset(),
 
324
                     system_charset_info, &dummy_errors);
 
325
        if (quoted)
 
326
          append_unescaped(def_value, def_val.ptr(), def_val.length());
 
327
        else
 
328
          def_value->append(def_val.ptr(), def_val.length());
 
329
      }
 
330
      else if (quoted)
 
331
        def_value->append(STRING_WITH_LEN("''"));
 
332
    }
 
333
    else if (field->maybe_null() && quoted)
 
334
      def_value->append(STRING_WITH_LEN("NULL"));    // Null as default
 
335
    else
 
336
      return false;
 
337
  }
 
338
  return has_default;
 
339
}
 
340
 
 
341
/*
 
342
  Build a CREATE TABLE statement for a table.
 
343
 
 
344
  SYNOPSIS
 
345
    store_create_info()
 
346
    table_list        A list containing one table to write statement
 
347
                      for.
 
348
    packet            Pointer to a string where statement will be
 
349
                      written.
 
350
 
 
351
  NOTE
 
352
    Currently always return 0, but might return error code in the
 
353
    future.
 
354
 
 
355
  RETURN
 
356
    0       OK
 
357
 */
 
358
 
 
359
int store_create_info(TableList *table_list, String *packet, bool is_if_not_exists)
 
360
{
 
361
  List<Item> field_list;
 
362
  char tmp[MAX_FIELD_WIDTH], *for_str, def_value_buf[MAX_FIELD_WIDTH];
 
363
  const char *alias;
 
364
  string buff;
 
365
  String type(tmp, sizeof(tmp), system_charset_info);
 
366
  String def_value(def_value_buf, sizeof(def_value_buf), system_charset_info);
 
367
  Field **ptr,*field;
 
368
  uint32_t primary_key;
 
369
  KeyInfo *key_info;
 
370
  Table *table= table_list->table;
 
371
  Cursor *cursor= table->cursor;
 
372
  HA_CREATE_INFO create_info;
 
373
  my_bitmap_map *old_map;
 
374
 
 
375
  table->restoreRecordAsDefault(); // Get empty record
 
376
 
 
377
  if (table->getShare()->getType())
 
378
    packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
 
379
  else
 
380
    packet->append(STRING_WITH_LEN("CREATE TABLE "));
 
381
  if (is_if_not_exists)
 
382
    packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
 
383
  alias= table->getShare()->getTableName();
 
384
 
 
385
  packet->append_identifier(alias, strlen(alias));
 
386
  packet->append(STRING_WITH_LEN(" (\n"));
 
387
  /*
 
388
    We need this to get default values from the table
 
389
    We have to restore the read_set if we are called from insert in case
 
390
    of row based replication.
 
391
  */
 
392
  old_map= table->use_all_columns(table->read_set);
 
393
 
 
394
  for (ptr= table->getFields() ; (field= *ptr); ptr++)
 
395
  {
 
396
    uint32_t flags = field->flags;
 
397
 
 
398
    if (ptr != table->getFields())
 
399
      packet->append(STRING_WITH_LEN(",\n"));
 
400
 
 
401
    packet->append(STRING_WITH_LEN("  "));
 
402
    packet->append_identifier(field->field_name, strlen(field->field_name));
 
403
    packet->append(' ');
 
404
    // check for surprises from the previous call to Field::sql_type()
 
405
    if (type.ptr() != tmp)
 
406
      type.set(tmp, sizeof(tmp), system_charset_info);
 
407
    else
 
408
      type.set_charset(system_charset_info);
 
409
 
 
410
    field->sql_type(type);
 
411
    packet->append(type.ptr(), type.length(), system_charset_info);
 
412
 
 
413
    if (field->has_charset())
 
414
    {
 
415
      /*
 
416
        For string types dump collation name only if
 
417
        collation is not primary for the given charset
 
418
      */
 
419
      if (!(field->charset()->state & MY_CS_PRIMARY))
 
420
      {
 
421
        packet->append(STRING_WITH_LEN(" COLLATE "));
 
422
        packet->append(field->charset()->name);
 
423
      }
 
424
    }
 
425
 
 
426
    if (flags & NOT_NULL_FLAG)
 
427
      packet->append(STRING_WITH_LEN(" NOT NULL"));
 
428
    else if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
429
    {
 
430
      /*
 
431
        TIMESTAMP field require explicit NULL flag, because unlike
 
432
        all other fields they are treated as NOT NULL by default.
 
433
      */
 
434
      packet->append(STRING_WITH_LEN(" NULL"));
 
435
    }
 
436
    {
 
437
      /*
 
438
        Add field flags about FIELD FORMAT (FIXED or DYNAMIC)
 
439
        and about STORAGE (DISK or MEMORY).
 
440
      */
 
441
      enum column_format_type column_format= (enum column_format_type)
 
442
        ((flags >> COLUMN_FORMAT_FLAGS) & COLUMN_FORMAT_MASK);
 
443
      if (column_format)
 
444
      {
 
445
        packet->append(STRING_WITH_LEN(" /*!"));
 
446
        packet->append(STRING_WITH_LEN(" COLUMN_FORMAT"));
 
447
        if (column_format == COLUMN_FORMAT_TYPE_FIXED)
 
448
          packet->append(STRING_WITH_LEN(" FIXED */"));
 
449
        else
 
450
          packet->append(STRING_WITH_LEN(" DYNAMIC */"));
 
451
      }
 
452
    }
 
453
    if (get_field_default_value(table->timestamp_field, field, &def_value, 1))
 
454
    {
 
455
      packet->append(STRING_WITH_LEN(" DEFAULT "));
 
456
      packet->append(def_value.ptr(), def_value.length(), system_charset_info);
 
457
    }
 
458
 
 
459
    if (table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD)
 
460
      packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
 
461
 
 
462
    if (field->unireg_check == Field::NEXT_NUMBER)
 
463
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
 
464
 
 
465
    if (field->comment.length)
 
466
    {
 
467
      packet->append(STRING_WITH_LEN(" COMMENT "));
 
468
      append_unescaped(packet, field->comment.str, field->comment.length);
 
469
    }
 
470
  }
 
471
 
 
472
  key_info= table->key_info;
 
473
  memset(&create_info, 0, sizeof(create_info));
 
474
 
 
475
  primary_key= table->getShare()->getPrimaryKey();
 
476
 
 
477
  for (uint32_t i=0 ; i < table->getShare()->sizeKeys() ; i++,key_info++)
 
478
  {
 
479
    KeyPartInfo *key_part= key_info->key_part;
 
480
    bool found_primary=0;
 
481
    packet->append(STRING_WITH_LEN(",\n  "));
 
482
 
 
483
    if (i == primary_key && is_primary_key(key_info))
 
484
    {
 
485
      found_primary=1;
 
486
      /*
 
487
        No space at end, because a space will be added after where the
 
488
        identifier would go, but that is not added for primary key.
 
489
      */
 
490
      packet->append(STRING_WITH_LEN("PRIMARY KEY"));
 
491
    }
 
492
    else if (key_info->flags & HA_NOSAME)
 
493
      packet->append(STRING_WITH_LEN("UNIQUE KEY "));
 
494
    else
 
495
      packet->append(STRING_WITH_LEN("KEY "));
 
496
 
 
497
    if (!found_primary)
 
498
     packet->append_identifier(key_info->name, strlen(key_info->name));
 
499
 
 
500
    packet->append(STRING_WITH_LEN(" ("));
 
501
 
 
502
    for (uint32_t j=0 ; j < key_info->key_parts ; j++,key_part++)
 
503
    {
 
504
      if (j)
 
505
        packet->append(',');
 
506
 
 
507
      if (key_part->field)
 
508
        packet->append_identifier(key_part->field->field_name,
 
509
                                  strlen(key_part->field->field_name));
 
510
      if (key_part->field &&
 
511
          (key_part->length !=
 
512
           table->getField(key_part->fieldnr-1)->key_length()))
 
513
      {
 
514
        buff.assign("(");
 
515
        buff.append(to_string((int32_t) key_part->length /
 
516
                              key_part->field->charset()->mbmaxlen));
 
517
        buff.append(")");
 
518
        packet->append(buff.c_str(), buff.length());
 
519
      }
 
520
    }
 
521
    packet->append(')');
 
522
    store_key_options(packet, table, key_info);
 
523
  }
 
524
 
 
525
  /*
 
526
    Get possible foreign key definitions stored in InnoDB and append them
 
527
    to the CREATE TABLE statement
 
528
  */
 
529
 
 
530
  if ((for_str= cursor->get_foreign_key_create_info()))
 
531
  {
 
532
    packet->append(for_str, strlen(for_str));
 
533
    cursor->free_foreign_key_create_info(for_str);
 
534
  }
 
535
 
 
536
  packet->append(STRING_WITH_LEN("\n)"));
 
537
  {
 
538
    /*
 
539
      Get possible table space definitions and append them
 
540
      to the CREATE TABLE statement
 
541
    */
 
542
 
 
543
    /* 
 
544
      We should always store engine since we will now be 
 
545
      making sure engines accept options (aka... no
 
546
      dangling arguments for engines.
 
547
    */
 
548
    packet->append(STRING_WITH_LEN(" ENGINE="));
 
549
    packet->append(cursor->getEngine()->getName().c_str());
 
550
 
 
551
    size_t num_engine_options= table->getShare()->getTableProto()->engine().options_size();
 
552
    for (size_t x= 0; x < num_engine_options; ++x)
 
553
    {
 
554
      const message::Engine::Option &option= table->getShare()->getTableProto()->engine().options(x);
 
555
      packet->append(" ");
 
556
      packet->append(option.name().c_str());
 
557
      packet->append("=");
 
558
      append_unescaped(packet, option.state().c_str(), option.state().length());
 
559
    }
 
560
 
 
561
    if (table->getShare()->block_size)
 
562
    {
 
563
      packet->append(STRING_WITH_LEN(" BLOCK_SIZE="));
 
564
      buff= to_string(table->getShare()->block_size);
 
565
      packet->append(buff.c_str(), buff.length());
 
566
    }
 
567
    table->cursor->append_create_info(packet);
 
568
    if (table->getMutableShare()->hasComment() && table->getMutableShare()->getCommentLength())
 
569
    {
 
570
      packet->append(STRING_WITH_LEN(" COMMENT="));
 
571
      append_unescaped(packet, table->getMutableShare()->getComment(),
 
572
                       table->getMutableShare()->getCommentLength());
 
573
    }
 
574
  }
 
575
  table->restore_column_map(old_map);
 
576
  return(0);
 
577
}
 
578
 
 
579
static void store_key_options(String *packet, Table *, KeyInfo *key_info)
 
580
{
 
581
  if (key_info->algorithm == HA_KEY_ALG_BTREE)
 
582
    packet->append(STRING_WITH_LEN(" USING BTREE"));
 
583
 
 
584
  if (key_info->algorithm == HA_KEY_ALG_HASH)
 
585
    packet->append(STRING_WITH_LEN(" USING HASH"));
 
586
 
 
587
  assert(test(key_info->flags & HA_USES_COMMENT) ==
 
588
              (key_info->comment.length > 0));
 
589
  if (key_info->flags & HA_USES_COMMENT)
 
590
  {
 
591
    packet->append(STRING_WITH_LEN(" COMMENT "));
 
592
    append_unescaped(packet, key_info->comment.str,
 
593
                     key_info->comment.length);
 
594
  }
 
595
}
 
596
 
 
597
 
 
598
/****************************************************************************
 
599
  Return info about all processes
 
600
  returns for each thread: thread id, user, host, db, command, info
 
601
****************************************************************************/
 
602
 
 
603
class thread_info
 
604
{
 
605
  thread_info();
 
606
public:
 
607
  uint64_t thread_id;
 
608
  time_t start_time;
 
609
  uint32_t   command;
 
610
  string user;
 
611
  string host;
 
612
  string db;
 
613
  string proc_info;
 
614
  string state_info;
 
615
  string query;
 
616
  thread_info(uint64_t thread_id_arg,
 
617
              time_t start_time_arg,
 
618
              uint32_t command_arg,
 
619
              const string &user_arg,
 
620
              const string &host_arg,
 
621
              const string &db_arg,
 
622
              const string &proc_info_arg,
 
623
              const string &state_info_arg,
 
624
              const string &query_arg)
 
625
    : thread_id(thread_id_arg), start_time(start_time_arg), command(command_arg),
 
626
      user(user_arg), host(host_arg), db(db_arg), proc_info(proc_info_arg),
 
627
      state_info(state_info_arg), query(query_arg)
 
628
  {}
 
629
};
 
630
 
146
631
} /* namespace drizzled */