~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/show.cc

  • Committer: Monty Taylor
  • Date: 2009-12-25 08:50:15 UTC
  • mto: This revision was merged to the branch mainline in revision 1255.
  • Revision ID: mordred@inaugust.com-20091225085015-83sux5qsvy312gew
MEM_ROOT == memory::Root

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) 2010 Brian Aker
5
 
 *  Copyright (C) 2008 Sun Microsystems, Inc.
 
4
 *  Copyright (C) 2008 Sun Microsystems
6
5
 *
7
6
 *  This program is free software; you can redistribute it and/or modify
8
7
 *  it under the terms of the GNU General Public License as published by
21
20
 
22
21
/* Function with list databases, tables or fields */
23
22
#include "config.h"
24
 
 
25
 
#include "drizzled/data_home.h"
26
 
#include "drizzled/error.h"
 
23
#include <drizzled/sql_select.h>
 
24
#include <drizzled/show.h>
 
25
#include <drizzled/gettext.h>
 
26
#include <drizzled/util/convert.h>
 
27
#include <drizzled/error.h>
 
28
#include <drizzled/tztime.h>
 
29
#include <drizzled/data_home.h>
 
30
#include <drizzled/item/blob.h>
 
31
#include <drizzled/item/cmpfunc.h>
 
32
#include <drizzled/item/return_int.h>
 
33
#include <drizzled/item/empty_string.h>
 
34
#include <drizzled/item/return_date_time.h>
 
35
#include <drizzled/sql_base.h>
 
36
#include <drizzled/db.h>
 
37
#include <drizzled/field/timestamp.h>
 
38
#include <drizzled/field/decimal.h>
 
39
#include <drizzled/lock.h>
 
40
#include <drizzled/item/return_date_time.h>
 
41
#include <drizzled/item/empty_string.h>
 
42
#include "drizzled/plugin/registry.h"
 
43
#include "drizzled/session_list.h"
 
44
#include <drizzled/plugin/info_schema_table.h>
 
45
#include <drizzled/message/schema.pb.h>
 
46
#include <drizzled/plugin/client.h>
 
47
#include <drizzled/cached_directory.h>
 
48
#include "drizzled/sql_table.h"
 
49
#include "drizzled/global_charset_info.h"
 
50
#include "drizzled/pthread_globals.h"
 
51
#include "drizzled/internal/m_string.h"
27
52
#include "drizzled/internal/my_sys.h"
28
 
#include "drizzled/plugin/storage_engine.h"
29
 
#include "drizzled/session.h"
30
 
#include "drizzled/show.h"
31
 
#include "drizzled/sql_select.h"
32
 
 
33
 
#include "drizzled/statement/show.h"
34
 
#include "drizzled/statement/show_errors.h"
35
 
#include "drizzled/statement/show_warnings.h"
36
 
 
37
53
 
38
54
#include <sys/stat.h>
39
55
 
44
60
#include <algorithm>
45
61
 
46
62
using namespace std;
47
 
 
48
 
namespace drizzled
49
 
{
 
63
using namespace drizzled;
50
64
 
51
65
inline const char *
52
66
str_or_nil(const char *str)
54
68
  return str ? str : "<nil>";
55
69
}
56
70
 
57
 
int wild_case_compare(const charset_info_st * const cs, const char *str, const char *wildstr)
 
71
static void store_key_options(String *packet, Table *table, KEY *key_info);
 
72
 
 
73
 
 
74
 
 
75
int wild_case_compare(const CHARSET_INFO * const cs, const char *str,const char *wildstr)
58
76
{
59
77
  register int flag;
60
 
 
61
78
  while (*wildstr)
62
79
  {
63
 
    while (*wildstr && *wildstr != internal::wild_many && *wildstr != internal::wild_one)
 
80
    while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
64
81
    {
65
 
      if (*wildstr == internal::wild_prefix && wildstr[1])
 
82
      if (*wildstr == wild_prefix && wildstr[1])
66
83
        wildstr++;
67
84
      if (my_toupper(cs, *wildstr++) != my_toupper(cs, *str++))
68
85
        return (1);
69
86
    }
70
87
    if (! *wildstr )
71
88
      return (*str != 0);
72
 
    if (*wildstr++ == internal::wild_one)
 
89
    if (*wildstr++ == wild_one)
73
90
    {
74
91
      if (! *str++)
75
92
        return (1);     /* One char; skip */
78
95
    {                                           /* Found '*' */
79
96
      if (! *wildstr)
80
97
        return (0);             /* '*' as last char: OK */
81
 
      flag=(*wildstr != internal::wild_many && *wildstr != internal::wild_one);
 
98
      flag=(*wildstr != wild_many && *wildstr != wild_one);
82
99
      do
83
100
      {
84
101
        if (flag)
85
102
        {
86
103
          char cmp;
87
 
          if ((cmp= *wildstr) == internal::wild_prefix && wildstr[1])
 
104
          if ((cmp= *wildstr) == wild_prefix && wildstr[1])
88
105
            cmp= wildstr[1];
89
106
          cmp= my_toupper(cs, cmp);
90
107
          while (*str && my_toupper(cs, *str) != cmp)
98
115
      return (1);
99
116
    }
100
117
  }
101
 
 
102
118
  return (*str != '\0');
103
119
}
104
120
 
 
121
 
 
122
/**
 
123
 * @brief
 
124
 *   Find subdirectories (schemas) in a given directory (datadir).
 
125
 *
 
126
 * @param[in]  session    Thread Cursor
 
127
 * @param[out] files      Put found entries in this list
 
128
 * @param[in]  path       Path to database
 
129
 * @param[in]  wild       Filter for found entries
 
130
 *
 
131
 * @retval false   Success
 
132
 * @retval true    Error
 
133
 */
 
134
static bool find_schemas(Session *session, vector<LEX_STRING*> &files,
 
135
                         const char *path, const char *wild)
 
136
{
 
137
  if (wild && (wild[0] == '\0'))
 
138
    wild= 0;
 
139
 
 
140
  CachedDirectory directory(path);
 
141
 
 
142
  if (directory.fail())
 
143
  {
 
144
    errno= directory.getError();
 
145
    my_error(ER_CANT_READ_DIR, MYF(0), path, errno);
 
146
 
 
147
    return true;
 
148
  }
 
149
 
 
150
  CachedDirectory::Entries entries= directory.getEntries();
 
151
  CachedDirectory::Entries::iterator entry_iter= entries.begin();
 
152
 
 
153
  while (entry_iter != entries.end())
 
154
  {
 
155
    uint32_t file_name_len;
 
156
    char uname[NAME_LEN + 1];                   /* Unencoded name */
 
157
    struct stat entry_stat;
 
158
    CachedDirectory::Entry *entry= *entry_iter;
 
159
 
 
160
    if ((entry->filename == ".") || (entry->filename == ".."))
 
161
    {
 
162
      ++entry_iter;
 
163
      continue;
 
164
    }
 
165
 
 
166
    if (stat(entry->filename.c_str(), &entry_stat))
 
167
    {
 
168
      errno= errno;
 
169
      my_error(ER_CANT_GET_STAT, MYF(0), entry->filename.c_str(), errno);
 
170
      return(true);
 
171
    }
 
172
 
 
173
    if (! S_ISDIR(entry_stat.st_mode))
 
174
    {
 
175
      ++entry_iter;
 
176
      continue;
 
177
    }
 
178
 
 
179
    file_name_len= filename_to_tablename(entry->filename.c_str(), uname,
 
180
                                         sizeof(uname));
 
181
    if (wild && wild_compare(uname, wild, 0))
 
182
    {
 
183
      ++entry_iter;
 
184
      continue;
 
185
    }
 
186
 
 
187
    LEX_STRING *file_name= 0;
 
188
    file_name= session->make_lex_string(file_name, uname, file_name_len, true);
 
189
    if (file_name == NULL)
 
190
      return(true);
 
191
 
 
192
    files.push_back(file_name);
 
193
    ++entry_iter;
 
194
  }
 
195
 
 
196
  return false;
 
197
}
 
198
 
 
199
 
 
200
bool drizzled_show_create(Session *session, TableList *table_list, bool is_if_not_exists)
 
201
{
 
202
  char buff[2048];
 
203
  String buffer(buff, sizeof(buff), system_charset_info);
 
204
 
 
205
  /* Only one table for now, but VIEW can involve several tables */
 
206
  if (session->openTables(table_list))
 
207
  {
 
208
    if (session->is_error())
 
209
      return true;
 
210
 
 
211
    /*
 
212
      Clear all messages with 'error' level status and
 
213
      issue a warning with 'warning' level status in
 
214
      case of invalid view and last error is ER_VIEW_INVALID
 
215
    */
 
216
    drizzle_reset_errors(session, true);
 
217
    session->clear_error();
 
218
  }
 
219
 
 
220
  buffer.length(0);
 
221
 
 
222
  if (store_create_info(table_list, &buffer, is_if_not_exists))
 
223
    return true;
 
224
 
 
225
  List<Item> field_list;
 
226
  {
 
227
    field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
 
228
    // 1024 is for not to confuse old clients
 
229
    field_list.push_back(new Item_empty_string("Create Table",
 
230
                                               max(buffer.length(),(uint32_t)1024)));
 
231
  }
 
232
 
 
233
  if (session->client->sendFields(&field_list))
 
234
    return true;
 
235
  {
 
236
    session->client->store(table_list->table->alias);
 
237
  }
 
238
 
 
239
  session->client->store(buffer.ptr(), buffer.length());
 
240
 
 
241
  if (session->client->flush())
 
242
    return true;
 
243
 
 
244
  session->my_eof();
 
245
  return false;
 
246
}
 
247
 
 
248
/**
 
249
  Get a CREATE statement for a given database.
 
250
 
 
251
  The database is identified by its name, passed as @c dbname parameter.
 
252
  The name should be encoded using the system character set (UTF8 currently).
 
253
 
 
254
  Resulting statement is stored in the string pointed by @c buffer. The string
 
255
  is emptied first and its character set is set to the system character set.
 
256
 
 
257
  If is_if_not_exists is set, then
 
258
  the resulting CREATE statement contains "IF NOT EXISTS" clause. Other flags
 
259
  in @c create_options are ignored.
 
260
 
 
261
  @param  session           The current thread instance.
 
262
  @param  dbname        The name of the database.
 
263
  @param  buffer        A String instance where the statement is stored.
 
264
  @param  create_info   If not NULL, the options member influences the resulting
 
265
                        CRATE statement.
 
266
 
 
267
  @returns true if errors are detected, false otherwise.
 
268
*/
 
269
 
 
270
static bool store_db_create_info(const char *dbname, String *buffer, bool if_not_exists)
 
271
{
 
272
  message::Schema schema;
 
273
 
 
274
  if (!my_strcasecmp(system_charset_info, dbname,
 
275
                     INFORMATION_SCHEMA_NAME.c_str()))
 
276
  {
 
277
    dbname= INFORMATION_SCHEMA_NAME.c_str();
 
278
  }
 
279
  else
 
280
  {
 
281
    int r= get_database_metadata(dbname, &schema);
 
282
    if(r < 0)
 
283
      return true;
 
284
  }
 
285
 
 
286
  buffer->length(0);
 
287
  buffer->free();
 
288
  buffer->set_charset(system_charset_info);
 
289
  buffer->append(STRING_WITH_LEN("CREATE DATABASE "));
 
290
 
 
291
  if (if_not_exists)
 
292
    buffer->append(STRING_WITH_LEN("IF NOT EXISTS "));
 
293
 
 
294
  buffer->append_identifier(dbname, strlen(dbname));
 
295
 
 
296
  if (schema.has_collation() && strcmp(schema.collation().c_str(),
 
297
                                       default_charset_info->name))
 
298
  {
 
299
    buffer->append(" COLLATE = ");
 
300
    buffer->append(schema.collation().c_str());
 
301
  }
 
302
 
 
303
  return false;
 
304
}
 
305
 
 
306
bool mysqld_show_create_db(Session *session, const NormalisedDatabaseName &database_name, bool if_not_exists)
 
307
{
 
308
  char buff[2048];
 
309
  String buffer(buff, sizeof(buff), system_charset_info);
 
310
 
 
311
  if (store_db_create_info(database_name.to_string().c_str(), &buffer, if_not_exists))
 
312
  {
 
313
    /*
 
314
      This assumes that the only reason for which store_db_create_info()
 
315
      can fail is incorrect database name (which is the case now).
 
316
    */
 
317
    my_error(ER_BAD_DB_ERROR, MYF(0), database_name.to_string().c_str());
 
318
    return true;
 
319
  }
 
320
 
 
321
  List<Item> field_list;
 
322
  field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
 
323
  field_list.push_back(new Item_empty_string("Create Database",1024));
 
324
 
 
325
  if (session->client->sendFields(&field_list))
 
326
    return true;
 
327
 
 
328
  session->client->store(database_name.to_string().c_str(), database_name.to_string().length());
 
329
  session->client->store(buffer.ptr(), buffer.length());
 
330
 
 
331
  if (session->client->flush())
 
332
    return true;
 
333
  session->my_eof();
 
334
  return false;
 
335
}
 
336
 
105
337
/*
106
338
  Get the quote character for displaying an identifier.
107
339
 
127
359
  return '`';
128
360
}
129
361
 
130
 
namespace show {
131
 
 
132
 
bool buildScemas(Session *session)
133
 
{
134
 
  session->getLex()->sql_command= SQLCOM_SELECT;
135
 
  session->getLex()->statement= new statement::Show(session);
136
 
 
137
 
  std::string column_name= "Database";
138
 
  if (session->getLex()->wild)
139
 
  {
140
 
    column_name.append(" (");
141
 
    column_name.append(session->getLex()->wild->ptr());
142
 
    column_name.append(")");
143
 
  }
144
 
 
145
 
  if (session->getLex()->current_select->where)
146
 
  {
147
 
    if (prepare_new_schema_table(session, session->getLex(), "SCHEMAS"))
148
 
      return false;
149
 
  }
150
 
  else
151
 
  {
152
 
    if (prepare_new_schema_table(session, session->getLex(), "SHOW_SCHEMAS"))
153
 
      return false;
154
 
  }
155
 
 
156
 
  Item_field *my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "SCHEMA_NAME");
157
 
  my_field->is_autogenerated_name= false;
158
 
  my_field->set_name(column_name.c_str(), column_name.length(), system_charset_info);
159
 
 
160
 
  if (session->add_item_to_list(my_field))
161
 
    return false;
162
 
 
163
 
  if (session->add_order_to_list(my_field, true))
164
 
    return false;
165
 
 
166
 
  return true;
167
 
}
168
 
 
169
 
bool buildTables(Session *session, const char *ident)
170
 
{
171
 
  session->getLex()->sql_command= SQLCOM_SELECT;
172
 
 
173
 
  drizzled::statement::Show *select= new statement::Show(session);
174
 
  session->getLex()->statement= select;
175
 
 
176
 
  std::string column_name= "Tables_in_";
177
 
 
178
 
  util::string::const_shared_ptr schema(session->schema());
179
 
  if (ident)
180
 
  {
181
 
    identifier::Schema identifier(ident);
182
 
    column_name.append(ident);
183
 
    session->getLex()->select_lex.db= const_cast<char *>(ident);
184
 
    if (not plugin::StorageEngine::doesSchemaExist(identifier))
185
 
    {
186
 
      my_error(ER_BAD_DB_ERROR, MYF(0), ident);
187
 
    }
188
 
    select->setShowPredicate(ident, "");
189
 
  }
190
 
  else if (schema and not schema->empty())
191
 
  {
192
 
    column_name.append(*schema);
193
 
    select->setShowPredicate(*schema, "");
194
 
  }
195
 
  else
196
 
  {
197
 
    my_error(ER_NO_DB_ERROR, MYF(0));
198
 
    return false;
199
 
  }
200
 
 
201
 
 
202
 
  if (session->getLex()->wild)
203
 
  {
204
 
    column_name.append(" (");
205
 
    column_name.append(session->getLex()->wild->ptr());
206
 
    column_name.append(")");
207
 
  }
208
 
 
209
 
  if (prepare_new_schema_table(session, session->getLex(), "SHOW_TABLES"))
210
 
    return false;
211
 
 
212
 
  Item_field *my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "TABLE_NAME");
213
 
  my_field->is_autogenerated_name= false;
214
 
  my_field->set_name(column_name.c_str(), column_name.length(), system_charset_info);
215
 
 
216
 
  if (session->add_item_to_list(my_field))
217
 
    return false;
218
 
 
219
 
  if (session->add_order_to_list(my_field, true))
220
 
    return false;
221
 
 
222
 
  return true;
223
 
}
224
 
 
225
 
bool buildTemporaryTables(Session *session)
226
 
{
227
 
  session->getLex()->sql_command= SQLCOM_SELECT;
228
 
 
229
 
  session->getLex()->statement= new statement::Show(session);
230
 
 
231
 
 
232
 
  if (prepare_new_schema_table(session, session->getLex(), "SHOW_TEMPORARY_TABLES"))
233
 
    return false;
234
 
 
235
 
  if (session->add_item_to_list( new Item_field(&session->lex->current_select->context, NULL, NULL, "*")))
236
 
    return false;
237
 
 
238
 
  (session->lex->current_select->with_wild)++;
239
 
 
240
 
  return true;
241
 
}
242
 
 
243
 
bool buildTableStatus(Session *session, const char *ident)
244
 
{
245
 
  session->getLex()->sql_command= SQLCOM_SELECT;
246
 
  drizzled::statement::Show *select= new statement::Show(session);
247
 
  session->getLex()->statement= select;
248
 
 
249
 
  std::string column_name= "Tables_in_";
250
 
 
251
 
  util::string::const_shared_ptr schema(session->schema());
252
 
  if (ident)
253
 
  {
254
 
    session->getLex()->select_lex.db= const_cast<char *>(ident);
255
 
 
256
 
    identifier::Schema identifier(ident);
257
 
    if (not plugin::StorageEngine::doesSchemaExist(identifier))
258
 
    {
259
 
      my_error(ER_BAD_DB_ERROR, MYF(0), ident);
260
 
    }
261
 
 
262
 
    select->setShowPredicate(ident, "");
263
 
  }
264
 
  else if (schema)
265
 
  {
266
 
    select->setShowPredicate(*schema, "");
267
 
  }
268
 
  else
269
 
  {
270
 
    my_error(ER_NO_DB_ERROR, MYF(0));
271
 
    return false;
272
 
  }
273
 
 
274
 
  if (prepare_new_schema_table(session, session->getLex(), "SHOW_TABLE_STATUS"))
275
 
    return false;
276
 
 
277
 
  if (session->add_item_to_list( new Item_field(&session->lex->current_select->
278
 
                                                  context,
279
 
                                                  NULL, NULL, "*")))
280
 
    return false;
281
 
 
282
 
  (session->lex->current_select->with_wild)++;
283
 
 
284
 
  return true;
285
 
}
286
 
 
287
 
bool buildEngineStatus(Session *session, LEX_STRING)
288
 
{
289
 
  session->getLex()->sql_command= SQLCOM_SELECT;
290
 
  drizzled::statement::Show *select= new statement::Show(session);
291
 
  session->getLex()->statement= select;
292
 
 
293
 
  my_error(ER_USE_DATA_DICTIONARY);
 
362
 
 
363
#define LIST_PROCESS_HOST_LEN 64
 
364
 
 
365
static bool get_field_default_value(Field *timestamp_field,
 
366
                                    Field *field, String *def_value,
 
367
                                    bool quoted)
 
368
{
 
369
  bool has_default;
 
370
  bool has_now_default;
 
371
 
 
372
  /*
 
373
     We are using CURRENT_TIMESTAMP instead of NOW because it is
 
374
     more standard
 
375
  */
 
376
  has_now_default= (timestamp_field == field &&
 
377
                    field->unireg_check != Field::TIMESTAMP_UN_FIELD);
 
378
 
 
379
  has_default= (field->type() != DRIZZLE_TYPE_BLOB &&
 
380
                !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
 
381
                field->unireg_check != Field::NEXT_NUMBER);
 
382
 
 
383
  def_value->length(0);
 
384
  if (has_default)
 
385
  {
 
386
    if (has_now_default)
 
387
      def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
 
388
    else if (!field->is_null())
 
389
    {                                             // Not null by default
 
390
      char tmp[MAX_FIELD_WIDTH];
 
391
      String type(tmp, sizeof(tmp), field->charset());
 
392
      field->val_str(&type);
 
393
      if (type.length())
 
394
      {
 
395
        String def_val;
 
396
        uint32_t dummy_errors;
 
397
        /* convert to system_charset_info == utf8 */
 
398
        def_val.copy(type.ptr(), type.length(), field->charset(),
 
399
                     system_charset_info, &dummy_errors);
 
400
        if (quoted)
 
401
          append_unescaped(def_value, def_val.ptr(), def_val.length());
 
402
        else
 
403
          def_value->append(def_val.ptr(), def_val.length());
 
404
      }
 
405
      else if (quoted)
 
406
        def_value->append(STRING_WITH_LEN("''"));
 
407
    }
 
408
    else if (field->maybe_null() && quoted)
 
409
      def_value->append(STRING_WITH_LEN("NULL"));    // Null as default
 
410
    else
 
411
      return false;
 
412
  }
 
413
  return has_default;
 
414
}
 
415
 
 
416
/*
 
417
  Build a CREATE TABLE statement for a table.
 
418
 
 
419
  SYNOPSIS
 
420
    store_create_info()
 
421
    table_list        A list containing one table to write statement
 
422
                      for.
 
423
    packet            Pointer to a string where statement will be
 
424
                      written.
 
425
 
 
426
  NOTE
 
427
    Currently always return 0, but might return error code in the
 
428
    future.
 
429
 
 
430
  RETURN
 
431
    0       OK
 
432
 */
 
433
 
 
434
int store_create_info(TableList *table_list, String *packet, bool is_if_not_exists)
 
435
{
 
436
  List<Item> field_list;
 
437
  char tmp[MAX_FIELD_WIDTH], *for_str, def_value_buf[MAX_FIELD_WIDTH];
 
438
  const char *alias;
 
439
  string buff;
 
440
  String type(tmp, sizeof(tmp), system_charset_info);
 
441
  String def_value(def_value_buf, sizeof(def_value_buf), system_charset_info);
 
442
  Field **ptr,*field;
 
443
  uint32_t primary_key;
 
444
  KEY *key_info;
 
445
  Table *table= table_list->table;
 
446
  Cursor *cursor= table->cursor;
 
447
  TableShare *share= table->s;
 
448
  HA_CREATE_INFO create_info;
 
449
  bool show_table_options= false;
 
450
  my_bitmap_map *old_map;
 
451
 
 
452
  table->restoreRecordAsDefault(); // Get empty record
 
453
 
 
454
  if (share->tmp_table)
 
455
    packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
 
456
  else
 
457
    packet->append(STRING_WITH_LEN("CREATE TABLE "));
 
458
  if (is_if_not_exists)
 
459
    packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
 
460
  alias= share->table_name.str;
 
461
 
 
462
  packet->append_identifier(alias, strlen(alias));
 
463
  packet->append(STRING_WITH_LEN(" (\n"));
 
464
  /*
 
465
    We need this to get default values from the table
 
466
    We have to restore the read_set if we are called from insert in case
 
467
    of row based replication.
 
468
  */
 
469
  old_map= table->use_all_columns(table->read_set);
 
470
 
 
471
  for (ptr=table->field ; (field= *ptr); ptr++)
 
472
  {
 
473
    uint32_t flags = field->flags;
 
474
 
 
475
    if (ptr != table->field)
 
476
      packet->append(STRING_WITH_LEN(",\n"));
 
477
 
 
478
    packet->append(STRING_WITH_LEN("  "));
 
479
    packet->append_identifier(field->field_name, strlen(field->field_name));
 
480
    packet->append(' ');
 
481
    // check for surprises from the previous call to Field::sql_type()
 
482
    if (type.ptr() != tmp)
 
483
      type.set(tmp, sizeof(tmp), system_charset_info);
 
484
    else
 
485
      type.set_charset(system_charset_info);
 
486
 
 
487
    field->sql_type(type);
 
488
    packet->append(type.ptr(), type.length(), system_charset_info);
 
489
 
 
490
    if (field->has_charset())
 
491
    {
 
492
      if (field->charset() != share->table_charset)
 
493
      {
 
494
        packet->append(STRING_WITH_LEN(" CHARACTER SET "));
 
495
        packet->append(field->charset()->csname);
 
496
      }
 
497
 
 
498
      /*
 
499
        For string types dump collation name only if
 
500
        collation is not primary for the given charset
 
501
      */
 
502
      if (!(field->charset()->state & MY_CS_PRIMARY))
 
503
      {
 
504
        packet->append(STRING_WITH_LEN(" COLLATE "));
 
505
        packet->append(field->charset()->name);
 
506
      }
 
507
    }
 
508
 
 
509
    if (flags & NOT_NULL_FLAG)
 
510
      packet->append(STRING_WITH_LEN(" NOT NULL"));
 
511
    else if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
512
    {
 
513
      /*
 
514
        TIMESTAMP field require explicit NULL flag, because unlike
 
515
        all other fields they are treated as NOT NULL by default.
 
516
      */
 
517
      packet->append(STRING_WITH_LEN(" NULL"));
 
518
    }
 
519
    {
 
520
      /*
 
521
        Add field flags about FIELD FORMAT (FIXED or DYNAMIC)
 
522
        and about STORAGE (DISK or MEMORY).
 
523
      */
 
524
      enum column_format_type column_format= (enum column_format_type)
 
525
        ((flags >> COLUMN_FORMAT_FLAGS) & COLUMN_FORMAT_MASK);
 
526
      if (column_format)
 
527
      {
 
528
        packet->append(STRING_WITH_LEN(" /*!"));
 
529
        packet->append(STRING_WITH_LEN(" COLUMN_FORMAT"));
 
530
        if (column_format == COLUMN_FORMAT_TYPE_FIXED)
 
531
          packet->append(STRING_WITH_LEN(" FIXED */"));
 
532
        else
 
533
          packet->append(STRING_WITH_LEN(" DYNAMIC */"));
 
534
      }
 
535
    }
 
536
    if (get_field_default_value(table->timestamp_field, field, &def_value, 1))
 
537
    {
 
538
      packet->append(STRING_WITH_LEN(" DEFAULT "));
 
539
      packet->append(def_value.ptr(), def_value.length(), system_charset_info);
 
540
    }
 
541
 
 
542
    if (table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD)
 
543
      packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
 
544
 
 
545
    if (field->unireg_check == Field::NEXT_NUMBER)
 
546
      packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
 
547
 
 
548
    if (field->comment.length)
 
549
    {
 
550
      packet->append(STRING_WITH_LEN(" COMMENT "));
 
551
      append_unescaped(packet, field->comment.str, field->comment.length);
 
552
    }
 
553
  }
 
554
 
 
555
  key_info= table->key_info;
 
556
  memset(&create_info, 0, sizeof(create_info));
 
557
  /* Allow update_create_info to update row type */
 
558
  create_info.row_type= share->row_type;
 
559
  cursor->update_create_info(&create_info);
 
560
  primary_key= share->primary_key;
 
561
 
 
562
  for (uint32_t i=0 ; i < share->keys ; i++,key_info++)
 
563
  {
 
564
    KEY_PART_INFO *key_part= key_info->key_part;
 
565
    bool found_primary=0;
 
566
    packet->append(STRING_WITH_LEN(",\n  "));
 
567
 
 
568
    if (i == primary_key && is_primary_key(key_info))
 
569
    {
 
570
      found_primary=1;
 
571
      /*
 
572
        No space at end, because a space will be added after where the
 
573
        identifier would go, but that is not added for primary key.
 
574
      */
 
575
      packet->append(STRING_WITH_LEN("PRIMARY KEY"));
 
576
    }
 
577
    else if (key_info->flags & HA_NOSAME)
 
578
      packet->append(STRING_WITH_LEN("UNIQUE KEY "));
 
579
    else
 
580
      packet->append(STRING_WITH_LEN("KEY "));
 
581
 
 
582
    if (!found_primary)
 
583
     packet->append_identifier(key_info->name, strlen(key_info->name));
 
584
 
 
585
    packet->append(STRING_WITH_LEN(" ("));
 
586
 
 
587
    for (uint32_t j=0 ; j < key_info->key_parts ; j++,key_part++)
 
588
    {
 
589
      if (j)
 
590
        packet->append(',');
 
591
 
 
592
      if (key_part->field)
 
593
        packet->append_identifier(key_part->field->field_name,
 
594
                                  strlen(key_part->field->field_name));
 
595
      if (key_part->field &&
 
596
          (key_part->length !=
 
597
           table->field[key_part->fieldnr-1]->key_length()))
 
598
      {
 
599
        buff.assign("(");
 
600
        buff.append(to_string((int32_t) key_part->length /
 
601
                              key_part->field->charset()->mbmaxlen));
 
602
        buff.append(")");
 
603
        packet->append(buff.c_str(), buff.length());
 
604
      }
 
605
    }
 
606
    packet->append(')');
 
607
    store_key_options(packet, table, key_info);
 
608
  }
 
609
 
 
610
  /*
 
611
    Get possible foreign key definitions stored in InnoDB and append them
 
612
    to the CREATE TABLE statement
 
613
  */
 
614
 
 
615
  if ((for_str= cursor->get_foreign_key_create_info()))
 
616
  {
 
617
    packet->append(for_str, strlen(for_str));
 
618
    cursor->free_foreign_key_create_info(for_str);
 
619
  }
 
620
 
 
621
  packet->append(STRING_WITH_LEN("\n)"));
 
622
  {
 
623
    show_table_options= true;
 
624
    /*
 
625
      Get possible table space definitions and append them
 
626
      to the CREATE TABLE statement
 
627
    */
 
628
 
 
629
    /* 
 
630
      We should always store engine since we will now be 
 
631
      making sure engines accept options (aka... no
 
632
      dangling arguments for engines.
 
633
    */
 
634
    packet->append(STRING_WITH_LEN(" ENGINE="));
 
635
    packet->append(cursor->engine->getName().c_str());
 
636
 
 
637
    if (share->db_create_options & HA_OPTION_PACK_KEYS)
 
638
      packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
 
639
    if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
 
640
      packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
 
641
    if (create_info.row_type != ROW_TYPE_DEFAULT)
 
642
    {
 
643
      packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
 
644
      packet->append(ha_row_type[(uint32_t) create_info.row_type]);
 
645
    }
 
646
    if (table->s->hasKeyBlockSize())
 
647
    {
 
648
      packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
 
649
      buff= to_string(table->s->getKeyBlockSize());
 
650
      packet->append(buff.c_str(), buff.length());
 
651
    }
 
652
    if (share->block_size)
 
653
    {
 
654
      packet->append(STRING_WITH_LEN(" BLOCK_SIZE="));
 
655
      buff= to_string(share->block_size);
 
656
      packet->append(buff.c_str(), buff.length());
 
657
    }
 
658
    table->cursor->append_create_info(packet);
 
659
    if (share->hasComment() && share->getCommentLength())
 
660
    {
 
661
      packet->append(STRING_WITH_LEN(" COMMENT="));
 
662
      append_unescaped(packet, share->getComment(),
 
663
                       share->getCommentLength());
 
664
    }
 
665
  }
 
666
  table->restore_column_map(old_map);
 
667
  return(0);
 
668
}
 
669
 
 
670
static void store_key_options(String *packet, Table *table, KEY *key_info)
 
671
{
 
672
  char *end, buff[32];
 
673
 
 
674
  if (key_info->algorithm == HA_KEY_ALG_BTREE)
 
675
    packet->append(STRING_WITH_LEN(" USING BTREE"));
 
676
 
 
677
  if (key_info->algorithm == HA_KEY_ALG_HASH)
 
678
    packet->append(STRING_WITH_LEN(" USING HASH"));
 
679
 
 
680
  if ((key_info->flags & HA_USES_BLOCK_SIZE) &&
 
681
      table->s->getKeyBlockSize() != key_info->block_size)
 
682
  {
 
683
    packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
 
684
    end= int64_t10_to_str(key_info->block_size, buff, 10);
 
685
    packet->append(buff, (uint32_t) (end - buff));
 
686
  }
 
687
 
 
688
  assert(test(key_info->flags & HA_USES_COMMENT) ==
 
689
              (key_info->comment.length > 0));
 
690
  if (key_info->flags & HA_USES_COMMENT)
 
691
  {
 
692
    packet->append(STRING_WITH_LEN(" COMMENT "));
 
693
    append_unescaped(packet, key_info->comment.str,
 
694
                     key_info->comment.length);
 
695
  }
 
696
}
 
697
 
 
698
 
 
699
/****************************************************************************
 
700
  Return info about all processes
 
701
  returns for each thread: thread id, user, host, db, command, info
 
702
****************************************************************************/
 
703
 
 
704
class thread_info :public ilink {
 
705
public:
 
706
  static void *operator new(size_t size)
 
707
  {
 
708
    return (void*) sql_alloc((uint32_t) size);
 
709
  }
 
710
  static void operator delete(void *, size_t)
 
711
  { }
 
712
 
 
713
  uint64_t thread_id;
 
714
  time_t start_time;
 
715
  uint32_t   command;
 
716
  const char *user,*host,*db,*proc_info,*state_info;
 
717
  char *query;
 
718
};
 
719
 
 
720
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
 
721
template class I_List<thread_info>;
 
722
#endif
 
723
 
 
724
void mysqld_list_processes(Session *session,const char *user, bool)
 
725
{
 
726
  Item *field;
 
727
  List<Item> field_list;
 
728
  I_List<thread_info> thread_infos;
 
729
 
 
730
  field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
 
731
  field_list.push_back(new Item_empty_string("User",16));
 
732
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
 
733
  field_list.push_back(field=new Item_empty_string("db",NAME_CHAR_LEN));
 
734
  field->maybe_null= true;
 
735
  field_list.push_back(new Item_empty_string("Command",16));
 
736
  field_list.push_back(new Item_return_int("Time",7, DRIZZLE_TYPE_LONG));
 
737
  field_list.push_back(field=new Item_empty_string("State",30));
 
738
  field->maybe_null= true;
 
739
  field_list.push_back(field=new Item_empty_string("Info", PROCESS_LIST_WIDTH));
 
740
  field->maybe_null= true;
 
741
  if (session->client->sendFields(&field_list))
 
742
    return;
 
743
 
 
744
  pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
 
745
  if (!session->killed)
 
746
  {
 
747
    Session *tmp;
 
748
    for(vector<Session*>::iterator it= getSessionList().begin(); it != getSessionList().end(); ++it)
 
749
    {
 
750
      tmp= *it;
 
751
      Security_context *tmp_sctx= &tmp->security_ctx;
 
752
      struct st_my_thread_var *mysys_var;
 
753
      if (tmp->client->isConnected() && (!user || (tmp_sctx->user.c_str() && !strcmp(tmp_sctx->user.c_str(), user))))
 
754
      {
 
755
        thread_info *session_info= new thread_info;
 
756
 
 
757
        session_info->thread_id=tmp->thread_id;
 
758
        session_info->user= session->strdup(tmp_sctx->user.c_str() ? tmp_sctx->user.c_str() : "unauthenticated user");
 
759
        session_info->host= session->strdup(tmp_sctx->ip.c_str());
 
760
        if ((session_info->db= tmp->db.c_str()))             // Safe test
 
761
          session_info->db=session->strdup(session_info->db);
 
762
        session_info->command=(int) tmp->command;
 
763
        if ((mysys_var= tmp->mysys_var))
 
764
          pthread_mutex_lock(&mysys_var->mutex);
 
765
 
 
766
        if (tmp->killed == Session::KILL_CONNECTION)
 
767
          session_info->proc_info= (char*) "Killed";
 
768
        else
 
769
          session_info->proc_info= command_name[session_info->command].str;
 
770
 
 
771
        session_info->state_info= (char*) (tmp->client->isWriting() ?
 
772
                                           "Writing to net" :
 
773
                                           tmp->client->isReading() ?
 
774
                                           (session_info->command == COM_SLEEP ?
 
775
                                            NULL : "Reading from net") :
 
776
                                       tmp->get_proc_info() ? tmp->get_proc_info() :
 
777
                                       tmp->mysys_var &&
 
778
                                       tmp->mysys_var->current_cond ?
 
779
                                       "Waiting on cond" : NULL);
 
780
        if (mysys_var)
 
781
          pthread_mutex_unlock(&mysys_var->mutex);
 
782
 
 
783
        session_info->start_time= tmp->start_time;
 
784
        session_info->query= NULL;
 
785
        if (tmp->process_list_info[0])
 
786
          session_info->query= session->strdup(tmp->process_list_info);
 
787
        thread_infos.append(session_info);
 
788
      }
 
789
    }
 
790
  }
 
791
  pthread_mutex_unlock(&LOCK_thread_count);
 
792
 
 
793
  thread_info *session_info;
 
794
  time_t now= time(NULL);
 
795
  while ((session_info=thread_infos.get()))
 
796
  {
 
797
    session->client->store((uint64_t) session_info->thread_id);
 
798
    session->client->store(session_info->user);
 
799
    session->client->store(session_info->host);
 
800
    session->client->store(session_info->db);
 
801
    session->client->store(session_info->proc_info);
 
802
 
 
803
    if (session_info->start_time)
 
804
      session->client->store((uint32_t) (now - session_info->start_time));
 
805
    else
 
806
      session->client->store();
 
807
 
 
808
    session->client->store(session_info->state_info);
 
809
    session->client->store(session_info->query);
 
810
 
 
811
    if (session->client->flush())
 
812
      break;
 
813
  }
 
814
  session->my_eof();
 
815
  return;
 
816
}
 
817
 
 
818
/*****************************************************************************
 
819
  Status functions
 
820
*****************************************************************************/
 
821
 
 
822
static vector<SHOW_VAR *> all_status_vars;
 
823
static bool status_vars_inited= 0;
 
824
static int show_var_cmp(const void *var1, const void *var2)
 
825
{
 
826
  return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
 
827
}
 
828
 
 
829
class show_var_cmp_functor
 
830
{
 
831
  public:
 
832
  show_var_cmp_functor() { }
 
833
  inline bool operator()(const SHOW_VAR *var1, const SHOW_VAR *var2) const
 
834
  {
 
835
    int val= strcmp(var1->name, var2->name);
 
836
    return (val < 0);
 
837
  }
 
838
};
 
839
 
 
840
class show_var_remove_if
 
841
{
 
842
  public:
 
843
  show_var_remove_if() { }
 
844
  inline bool operator()(const SHOW_VAR *curr) const
 
845
  {
 
846
    return (curr->type == SHOW_UNDEF);
 
847
  }
 
848
};
 
849
 
 
850
SHOW_VAR *getFrontOfStatusVars()
 
851
{
 
852
  return all_status_vars.front();
 
853
}
 
854
 
 
855
/*
 
856
  Adds an array of SHOW_VAR entries to the output of SHOW STATUS
 
857
 
 
858
  SYNOPSIS
 
859
    add_status_vars(SHOW_VAR *list)
 
860
    list - an array of SHOW_VAR entries to add to all_status_vars
 
861
           the last entry must be {0,0,SHOW_UNDEF}
 
862
 
 
863
  NOTE
 
864
    The handling of all_status_vars[] is completely internal, it's allocated
 
865
    automatically when something is added to it, and deleted completely when
 
866
    the last entry is removed.
 
867
 
 
868
    As a special optimization, if add_status_vars() is called before
 
869
    init_status_vars(), it assumes "startup mode" - neither concurrent access
 
870
    to the array nor SHOW STATUS are possible (thus it skips locks and qsort)
 
871
*/
 
872
int add_status_vars(SHOW_VAR *list)
 
873
{
 
874
  int res= 0;
 
875
  if (status_vars_inited)
 
876
    pthread_mutex_lock(&LOCK_status);
 
877
  while (list->name)
 
878
    all_status_vars.insert(all_status_vars.begin(), list++);
 
879
  if (status_vars_inited)
 
880
    sort(all_status_vars.begin(), all_status_vars.end(),
 
881
         show_var_cmp_functor());
 
882
  if (status_vars_inited)
 
883
    pthread_mutex_unlock(&LOCK_status);
 
884
  return res;
 
885
}
 
886
 
 
887
/*
 
888
  Make all_status_vars[] usable for SHOW STATUS
 
889
 
 
890
  NOTE
 
891
    See add_status_vars(). Before init_status_vars() call, add_status_vars()
 
892
    works in a special fast "startup" mode. Thus init_status_vars()
 
893
    should be called as late as possible but before enabling multi-threading.
 
894
*/
 
895
void init_status_vars()
 
896
{
 
897
  status_vars_inited= 1;
 
898
  sort(all_status_vars.begin(), all_status_vars.end(),
 
899
       show_var_cmp_functor());
 
900
}
 
901
 
 
902
void reset_status_vars()
 
903
{
 
904
  vector<SHOW_VAR *>::iterator p= all_status_vars.begin();
 
905
  while (p != all_status_vars.end())
 
906
  {
 
907
    /* Note that SHOW_LONG_NOFLUSH variables are not reset */
 
908
    if ((*p)->type == SHOW_LONG)
 
909
      (*p)->value= 0;
 
910
    ++p;
 
911
  }
 
912
}
 
913
 
 
914
/*
 
915
  catch-all cleanup function, cleans up everything no matter what
 
916
 
 
917
  DESCRIPTION
 
918
    This function is not strictly required if all add_to_status/
 
919
    remove_status_vars are properly paired, but it's a safety measure that
 
920
    deletes everything from the all_status_vars vector even if some
 
921
    remove_status_vars were forgotten
 
922
*/
 
923
void free_status_vars()
 
924
{
 
925
  all_status_vars.clear();
 
926
}
 
927
 
 
928
/*
 
929
  Removes an array of SHOW_VAR entries from the output of SHOW STATUS
 
930
 
 
931
  SYNOPSIS
 
932
    remove_status_vars(SHOW_VAR *list)
 
933
    list - an array of SHOW_VAR entries to remove to all_status_vars
 
934
           the last entry must be {0,0,SHOW_UNDEF}
 
935
 
 
936
  NOTE
 
937
    there's lots of room for optimizing this, especially in non-sorted mode,
 
938
    but nobody cares - it may be called only in case of failed plugin
 
939
    initialization in the mysqld startup.
 
940
*/
 
941
 
 
942
void remove_status_vars(SHOW_VAR *list)
 
943
{
 
944
  if (status_vars_inited)
 
945
  {
 
946
    pthread_mutex_lock(&LOCK_status);
 
947
    SHOW_VAR *all= all_status_vars.front();
 
948
    int a= 0, b= all_status_vars.size(), c= (a+b)/2;
 
949
 
 
950
    for (; list->name; list++)
 
951
    {
 
952
      int res= 0;
 
953
      for (a= 0, b= all_status_vars.size(); b-a > 1; c= (a+b)/2)
 
954
      {
 
955
        res= show_var_cmp(list, all+c);
 
956
        if (res < 0)
 
957
          b= c;
 
958
        else if (res > 0)
 
959
          a= c;
 
960
        else
 
961
          break;
 
962
      }
 
963
      if (res == 0)
 
964
        all[c].type= SHOW_UNDEF;
 
965
    }
 
966
    /* removes all the SHOW_UNDEF elements from the vector */
 
967
    all_status_vars.erase(std::remove_if(all_status_vars.begin(),
 
968
                            all_status_vars.end(),show_var_remove_if()),
 
969
                            all_status_vars.end());
 
970
    pthread_mutex_unlock(&LOCK_status);
 
971
  }
 
972
  else
 
973
  {
 
974
    SHOW_VAR *all= all_status_vars.front();
 
975
    uint32_t i;
 
976
    for (; list->name; list++)
 
977
    {
 
978
      for (i= 0; i < all_status_vars.size(); i++)
 
979
      {
 
980
        if (show_var_cmp(list, all+i))
 
981
          continue;
 
982
        all[i].type= SHOW_UNDEF;
 
983
        break;
 
984
      }
 
985
    }
 
986
    /* removes all the SHOW_UNDEF elements from the vector */
 
987
    all_status_vars.erase(std::remove_if(all_status_vars.begin(),
 
988
                            all_status_vars.end(),show_var_remove_if()),
 
989
                            all_status_vars.end());
 
990
  }
 
991
}
 
992
 
 
993
/* collect status for all running threads */
 
994
 
 
995
void calc_sum_of_all_status(STATUS_VAR *to)
 
996
{
 
997
  /* Ensure that thread id not killed during loop */
 
998
  pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
 
999
 
 
1000
  /* Get global values as base */
 
1001
  *to= global_status_var;
 
1002
 
 
1003
  /* Add to this status from existing threads */
 
1004
  for(vector<Session*>::iterator it= getSessionList().begin(); it != getSessionList().end(); ++it )
 
1005
  {
 
1006
    add_to_status(to, &((*it)->status_var));
 
1007
  }
 
1008
 
 
1009
  pthread_mutex_unlock(&LOCK_thread_count);
 
1010
  return;
 
1011
}
 
1012
 
 
1013
 
 
1014
static int make_table_list(Session *session, Select_Lex *sel,
 
1015
                           LEX_STRING *db_name, LEX_STRING *table_name)
 
1016
{
 
1017
  Table_ident *table_ident;
 
1018
  table_ident= new Table_ident(*db_name, *table_name);
 
1019
  sel->init_query();
 
1020
  if (! sel->add_table_to_list(session, table_ident, 0, 0, TL_READ))
 
1021
    return 1;
 
1022
  return 0;
 
1023
}
 
1024
 
 
1025
 
 
1026
/**
 
1027
  @brief    Get lookup value from the part of 'WHERE' condition
 
1028
 
 
1029
  @details This function gets lookup value from
 
1030
           the part of 'WHERE' condition if it's possible and
 
1031
           fill appropriate lookup_field_vals struct field
 
1032
           with this value.
 
1033
 
 
1034
  @param[in]      session                   thread Cursor
 
1035
  @param[in]      item_func             part of WHERE condition
 
1036
  @param[in]      table                 I_S table
 
1037
  @param[in, out] lookup_field_vals     Struct which holds lookup values
 
1038
 
 
1039
  @return
 
1040
    0             success
 
1041
    1             error, there can be no matching records for the condition
 
1042
*/
 
1043
 
 
1044
static bool get_lookup_value(Session *session, Item_func *item_func,
 
1045
                             TableList *table,
 
1046
                             LOOKUP_FIELD_VALUES *lookup_field_vals,
 
1047
                             plugin::InfoSchemaTable *schema_table)
 
1048
{
 
1049
  const char *field_name1= schema_table->getFirstColumnIndex() >= 0 ?
 
1050
    schema_table->getColumnName(schema_table->getFirstColumnIndex()).c_str() : "";
 
1051
  const char *field_name2= schema_table->getSecondColumnIndex() >= 0 ?
 
1052
    schema_table->getColumnName(schema_table->getSecondColumnIndex()).c_str() : "";
 
1053
 
 
1054
  if (item_func->functype() == Item_func::EQ_FUNC ||
 
1055
      item_func->functype() == Item_func::EQUAL_FUNC)
 
1056
  {
 
1057
    int idx_field, idx_val;
 
1058
    char tmp[MAX_FIELD_WIDTH];
 
1059
    String *tmp_str, str_buff(tmp, sizeof(tmp), system_charset_info);
 
1060
    Item_field *item_field;
 
1061
    const CHARSET_INFO * const cs= system_charset_info;
 
1062
 
 
1063
    if (item_func->arguments()[0]->type() == Item::FIELD_ITEM &&
 
1064
        item_func->arguments()[1]->const_item())
 
1065
    {
 
1066
      idx_field= 0;
 
1067
      idx_val= 1;
 
1068
    }
 
1069
    else if (item_func->arguments()[1]->type() == Item::FIELD_ITEM &&
 
1070
             item_func->arguments()[0]->const_item())
 
1071
    {
 
1072
      idx_field= 1;
 
1073
      idx_val= 0;
 
1074
    }
 
1075
    else
 
1076
      return 0;
 
1077
 
 
1078
    item_field= (Item_field*) item_func->arguments()[idx_field];
 
1079
    if (table->table != item_field->field->table)
 
1080
      return 0;
 
1081
    tmp_str= item_func->arguments()[idx_val]->val_str(&str_buff);
 
1082
 
 
1083
    /* impossible value */
 
1084
    if (!tmp_str)
 
1085
      return 1;
 
1086
 
 
1087
    /* Lookup value is database name */
 
1088
    if (!cs->coll->strnncollsp(cs, (unsigned char *) field_name1, strlen(field_name1),
 
1089
                               (unsigned char *) item_field->field_name,
 
1090
                               strlen(item_field->field_name), 0))
 
1091
    {
 
1092
      session->make_lex_string(&lookup_field_vals->db_value, tmp_str->ptr(),
 
1093
                           tmp_str->length(), false);
 
1094
    }
 
1095
    /* Lookup value is table name */
 
1096
    else if (!cs->coll->strnncollsp(cs, (unsigned char *) field_name2,
 
1097
                                    strlen(field_name2),
 
1098
                                    (unsigned char *) item_field->field_name,
 
1099
                                    strlen(item_field->field_name), 0))
 
1100
    {
 
1101
      session->make_lex_string(&lookup_field_vals->table_value, tmp_str->ptr(),
 
1102
                           tmp_str->length(), false);
 
1103
    }
 
1104
  }
 
1105
  return 0;
 
1106
}
 
1107
 
 
1108
 
 
1109
/**
 
1110
  @brief    Calculates lookup values from 'WHERE' condition
 
1111
 
 
1112
  @details This function calculates lookup value(database name, table name)
 
1113
           from 'WHERE' condition if it's possible and
 
1114
           fill lookup_field_vals struct fields with these values.
 
1115
 
 
1116
  @param[in]      session                   thread Cursor
 
1117
  @param[in]      cond                  WHERE condition
 
1118
  @param[in]      table                 I_S table
 
1119
  @param[in, out] lookup_field_vals     Struct which holds lookup values
 
1120
 
 
1121
  @return
 
1122
    0             success
 
1123
    1             error, there can be no matching records for the condition
 
1124
*/
 
1125
 
 
1126
bool calc_lookup_values_from_cond(Session *session, COND *cond, TableList *table,
 
1127
                                  LOOKUP_FIELD_VALUES *lookup_field_vals,
 
1128
                                  plugin::InfoSchemaTable *schema_table)
 
1129
{
 
1130
  if (!cond)
 
1131
    return 0;
 
1132
 
 
1133
  if (cond->type() == Item::COND_ITEM)
 
1134
  {
 
1135
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
 
1136
    {
 
1137
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
 
1138
      Item *item;
 
1139
      while ((item= li++))
 
1140
      {
 
1141
        if (item->type() == Item::FUNC_ITEM)
 
1142
        {
 
1143
          if (get_lookup_value(session, (Item_func*)item, table, lookup_field_vals, schema_table))
 
1144
            return 1;
 
1145
        }
 
1146
        else
 
1147
        {
 
1148
          if (calc_lookup_values_from_cond(session, item, table, lookup_field_vals, schema_table))
 
1149
            return 1;
 
1150
        }
 
1151
      }
 
1152
    }
 
1153
    return 0;
 
1154
  }
 
1155
  else if (cond->type() == Item::FUNC_ITEM &&
 
1156
           get_lookup_value(session, (Item_func*) cond, table, lookup_field_vals, schema_table))
 
1157
    return 1;
 
1158
  return 0;
 
1159
}
 
1160
 
 
1161
 
 
1162
static bool uses_only_table_name_fields(Item *item, Table *table, plugin::InfoSchemaTable *schema_table)
 
1163
{
 
1164
  if (item->type() == Item::FUNC_ITEM)
 
1165
  {
 
1166
    Item_func *item_func= (Item_func*)item;
 
1167
    for (uint32_t i=0; i<item_func->argument_count(); i++)
 
1168
    {
 
1169
      if (! uses_only_table_name_fields(item_func->arguments()[i], table, schema_table))
 
1170
        return 0;
 
1171
    }
 
1172
  }
 
1173
  else if (item->type() == Item::FIELD_ITEM)
 
1174
  {
 
1175
    Item_field *item_field= (Item_field*)item;
 
1176
    const CHARSET_INFO * const cs= system_charset_info;
 
1177
    const char *field_name1= schema_table->getFirstColumnIndex() >= 0 ?
 
1178
      schema_table->getColumnName(schema_table->getFirstColumnIndex()).c_str() : "";
 
1179
    const char *field_name2= schema_table->getSecondColumnIndex() >= 0 ?
 
1180
      schema_table->getColumnName(schema_table->getSecondColumnIndex()).c_str() : "";
 
1181
    if (table != item_field->field->table ||
 
1182
        (cs->coll->strnncollsp(cs, (unsigned char *) field_name1, strlen(field_name1),
 
1183
                               (unsigned char *) item_field->field_name,
 
1184
                               strlen(item_field->field_name), 0) &&
 
1185
         cs->coll->strnncollsp(cs, (unsigned char *) field_name2, strlen(field_name2),
 
1186
                               (unsigned char *) item_field->field_name,
 
1187
                               strlen(item_field->field_name), 0)))
 
1188
      return 0;
 
1189
  }
 
1190
  else if (item->type() == Item::REF_ITEM)
 
1191
    return uses_only_table_name_fields(item->real_item(), table, schema_table);
 
1192
 
 
1193
  if (item->type() == Item::SUBSELECT_ITEM && !item->const_item())
 
1194
    return 0;
 
1195
 
 
1196
  return 1;
 
1197
}
 
1198
 
 
1199
 
 
1200
static COND * make_cond_for_info_schema(COND *cond, Table *table, plugin::InfoSchemaTable *schema_table)
 
1201
{
 
1202
  if (!cond)
 
1203
    return (COND*) 0;
 
1204
  if (cond->type() == Item::COND_ITEM)
 
1205
  {
 
1206
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
 
1207
    {
 
1208
      /* Create new top level AND item */
 
1209
      Item_cond_and *new_cond=new Item_cond_and;
 
1210
      if (!new_cond)
 
1211
        return (COND*) 0;
 
1212
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
 
1213
      Item *item;
 
1214
      while ((item=li++))
 
1215
      {
 
1216
        Item *fix= make_cond_for_info_schema(item, table, schema_table);
 
1217
        if (fix)
 
1218
          new_cond->argument_list()->push_back(fix);
 
1219
      }
 
1220
      switch (new_cond->argument_list()->elements) {
 
1221
        case 0:
 
1222
          return (COND*) 0;
 
1223
        case 1:
 
1224
          return new_cond->argument_list()->head();
 
1225
        default:
 
1226
          new_cond->quick_fix_field();
 
1227
          return new_cond;
 
1228
      }
 
1229
    }
 
1230
    else
 
1231
    {                                           // Or list
 
1232
      Item_cond_or *new_cond=new Item_cond_or;
 
1233
      if (!new_cond)
 
1234
        return (COND*) 0;
 
1235
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
 
1236
      Item *item;
 
1237
      while ((item=li++))
 
1238
      {
 
1239
        Item *fix=make_cond_for_info_schema(item, table, schema_table);
 
1240
        if (!fix)
 
1241
          return (COND*) 0;
 
1242
        new_cond->argument_list()->push_back(fix);
 
1243
      }
 
1244
      new_cond->quick_fix_field();
 
1245
      new_cond->top_level_item();
 
1246
      return new_cond;
 
1247
    }
 
1248
  }
 
1249
 
 
1250
  if (! uses_only_table_name_fields(cond, table, schema_table))
 
1251
    return (COND*) 0;
 
1252
  return cond;
 
1253
}
 
1254
 
 
1255
 
 
1256
/**
 
1257
  @brief   Calculate lookup values(database name, table name)
 
1258
 
 
1259
  @details This function calculates lookup values(database name, table name)
 
1260
           from 'WHERE' condition or wild values (for 'SHOW' commands only)
 
1261
           from LEX struct and fill lookup_field_vals struct field
 
1262
           with these values.
 
1263
 
 
1264
  @param[in]      session                   thread Cursor
 
1265
  @param[in]      cond                  WHERE condition
 
1266
  @param[in]      tables                I_S table
 
1267
  @param[in, out] lookup_field_values   Struct which holds lookup values
 
1268
 
 
1269
  @return
 
1270
    0             success
 
1271
    1             error, there can be no matching records for the condition
 
1272
*/
 
1273
 
 
1274
bool get_lookup_field_values(Session *session, COND *cond, TableList *tables,
 
1275
                             LOOKUP_FIELD_VALUES *lookup_field_values,
 
1276
                             plugin::InfoSchemaTable *schema_table)
 
1277
{
 
1278
  LEX *lex= session->lex;
 
1279
  const char *wild= lex->wild ? lex->wild->ptr() : NULL;
 
1280
  memset(lookup_field_values, 0, sizeof(LOOKUP_FIELD_VALUES));
 
1281
  switch (lex->sql_command) {
 
1282
  case SQLCOM_SHOW_DATABASES:
 
1283
    if (wild)
 
1284
    {
 
1285
      lookup_field_values->db_value.str= (char*) wild;
 
1286
      lookup_field_values->db_value.length= strlen(wild);
 
1287
      lookup_field_values->wild_db_value= 1;
 
1288
    }
 
1289
    return 0;
 
1290
  case SQLCOM_SHOW_TABLES:
 
1291
  case SQLCOM_SHOW_TABLE_STATUS:
 
1292
    lookup_field_values->db_value.str= lex->select_lex.db;
 
1293
    lookup_field_values->db_value.length=strlen(lex->select_lex.db);
 
1294
    if (wild)
 
1295
    {
 
1296
      lookup_field_values->table_value.str= (char*)wild;
 
1297
      lookup_field_values->table_value.length= strlen(wild);
 
1298
      lookup_field_values->wild_table_value= 1;
 
1299
    }
 
1300
    return 0;
 
1301
  default:
 
1302
    /*
 
1303
      The "default" is for queries over I_S.
 
1304
      All previous cases handle SHOW commands.
 
1305
    */
 
1306
    return calc_lookup_values_from_cond(session, cond, tables, lookup_field_values, schema_table);
 
1307
  }
 
1308
}
 
1309
 
 
1310
 
 
1311
/**
 
1312
 * Function used for sorting with std::sort within make_db_list.
 
1313
 *
 
1314
 * @returns true if a < b, false otherwise
 
1315
 */
 
1316
 
 
1317
static bool lex_string_sort(const LEX_STRING *a, const LEX_STRING *b)
 
1318
{
 
1319
  return (strcmp(a->str, b->str) < 0);
 
1320
}
 
1321
 
 
1322
 
 
1323
/**
 
1324
 * @brief
 
1325
 *   Create db names list. Information schema name always is first in list
 
1326
 *
 
1327
 * @param[in]  session          Thread Cursor
 
1328
 * @param[out] files            List of db names
 
1329
 * @param[in]  wild             Wild string
 
1330
 * @param[in]  idx_field_vals   idx_field_vals->db_name contains db name or
 
1331
 *                              wild string
 
1332
 * @param[out] with_i_schema    Returns 1 if we added 'IS' name to list
 
1333
 *                              otherwise returns 0
 
1334
 *
 
1335
 * @retval 0   Success
 
1336
 * @retval 1   Error
 
1337
 */
 
1338
int make_db_list(Session *session, vector<LEX_STRING*> &files,
 
1339
                 LOOKUP_FIELD_VALUES *lookup_field_vals,
 
1340
                 bool *with_i_schema)
 
1341
{
 
1342
  LEX_STRING *i_s_name_copy= 0;
 
1343
  i_s_name_copy= session->make_lex_string(i_s_name_copy,
 
1344
                                      INFORMATION_SCHEMA_NAME.c_str(),
 
1345
                                      INFORMATION_SCHEMA_NAME.length(), true);
 
1346
  *with_i_schema= 0;
 
1347
  if (lookup_field_vals->wild_db_value)
 
1348
  {
 
1349
    /*
 
1350
      This part of code is only for SHOW DATABASES command.
 
1351
      idx_field_vals->db_value can be 0 when we don't use
 
1352
      LIKE clause (see also get_index_field_values() function)
 
1353
    */
 
1354
    if (!lookup_field_vals->db_value.str ||
 
1355
        !wild_case_compare(system_charset_info,
 
1356
                           INFORMATION_SCHEMA_NAME.c_str(),
 
1357
                           lookup_field_vals->db_value.str))
 
1358
    {
 
1359
      *with_i_schema= 1;
 
1360
      files.push_back(i_s_name_copy);
 
1361
    }
 
1362
 
 
1363
    if (find_schemas(session, files, drizzle_data_home,
 
1364
                     lookup_field_vals->db_value.str) == true)
 
1365
    {
 
1366
      return 1;
 
1367
    }
 
1368
 
 
1369
    sort(files.begin()+1, files.end(), lex_string_sort);
 
1370
    return 0;
 
1371
  }
 
1372
 
 
1373
 
 
1374
  /*
 
1375
    If we have db lookup vaule we just add it to list and
 
1376
    exit from the function
 
1377
  */
 
1378
  if (lookup_field_vals->db_value.str)
 
1379
  {
 
1380
    if (!my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.c_str(),
 
1381
                       lookup_field_vals->db_value.str))
 
1382
    {
 
1383
      *with_i_schema= 1;
 
1384
      files.push_back(i_s_name_copy);
 
1385
      return 0;
 
1386
    }
 
1387
 
 
1388
    files.push_back(&lookup_field_vals->db_value);
 
1389
    return 0;
 
1390
  }
 
1391
 
 
1392
  /*
 
1393
    Create list of existing databases. It is used in case
 
1394
    of select from information schema table
 
1395
  */
 
1396
  files.push_back(i_s_name_copy);
 
1397
 
 
1398
  *with_i_schema= 1;
 
1399
 
 
1400
  if (find_schemas(session, files, drizzle_data_home, NULL) == true)
 
1401
  {
 
1402
    return 1;
 
1403
  }
 
1404
 
 
1405
  sort(files.begin()+1, files.end(), lex_string_sort);
 
1406
  return 0;
 
1407
}
 
1408
 
 
1409
 
 
1410
/**
 
1411
  @brief          Create table names list
 
1412
 
 
1413
  @details        The function creates the list of table names in
 
1414
                  database
 
1415
 
 
1416
  @param[in]      session                   thread Cursor
 
1417
  @param[in]      table_names           List of table names in database
 
1418
  @param[in]      lex                   pointer to LEX struct
 
1419
  @param[in]      lookup_field_vals     pointer to LOOKUP_FIELD_VALUE struct
 
1420
  @param[in]      with_i_schema         true means that we add I_S tables to list
 
1421
  @param[in]      db_name               database name
 
1422
 
 
1423
  @return         Operation status
 
1424
    @retval       0           ok
 
1425
    @retval       1           fatal error
 
1426
    @retval       2           Not fatal error; Safe to ignore this cursor list
 
1427
*/
 
1428
 
 
1429
static int
 
1430
make_table_name_list(Session *session, vector<LEX_STRING*> &table_names,
 
1431
                     LOOKUP_FIELD_VALUES *lookup_field_vals,
 
1432
                     bool with_i_schema, LEX_STRING *db_name)
 
1433
{
 
1434
  char path[FN_REFLEN];
 
1435
  set<string> set_of_names;
 
1436
 
 
1437
  build_table_filename(path, sizeof(path), db_name->str, "", false);
 
1438
 
 
1439
  if (!lookup_field_vals->wild_table_value &&
 
1440
      lookup_field_vals->table_value.str)
 
1441
  {
 
1442
    if (with_i_schema)
 
1443
    {
 
1444
      if (plugin::InfoSchemaTable::getTable(lookup_field_vals->table_value.str))
 
1445
      {
 
1446
        table_names.push_back(&lookup_field_vals->table_value);
 
1447
      }
 
1448
    }
 
1449
    else
 
1450
    {
 
1451
      table_names.push_back(&lookup_field_vals->table_value);
 
1452
    }
 
1453
    return 0;
 
1454
  }
 
1455
 
 
1456
  string db(db_name->str);
 
1457
  plugin::StorageEngine::getTableNames(db, set_of_names);
 
1458
 
 
1459
  /*  
 
1460
    New I_S engine will make this go away, so ignore lack of foreach() usage.
 
1461
 
 
1462
    Notice how bad this design is... sure we created a set... but then we
 
1463
    are just pushing to another set. --
 
1464
    Also... callback design won't work, so we need to rewrite this to
 
1465
    feed (which means new I_S). For the moment we will not optimize this.
 
1466
 
 
1467
  */
 
1468
  for (set<string>::iterator it= set_of_names.begin(); it != set_of_names.end(); it++)
 
1469
  {
 
1470
    LEX_STRING *file_name= NULL;
 
1471
    
 
1472
    file_name= session->make_lex_string(file_name, (*it).c_str(),
 
1473
                                        (*it).length(), true);
 
1474
    const char* wild= lookup_field_vals->table_value.str;
 
1475
    if (wild && wild_compare((*it).c_str(), wild, 0))
 
1476
      continue;
 
1477
 
 
1478
    table_names.push_back(file_name);
 
1479
  }
 
1480
 
 
1481
  return 0;
 
1482
}
 
1483
 
 
1484
 
 
1485
/**
 
1486
  @brief          Fill I_S table for SHOW COLUMNS|INDEX commands
 
1487
 
 
1488
  @param[in]      session                      thread Cursor
 
1489
  @param[in]      tables                   TableList for I_S table
 
1490
  @param[in]      schema_table             pointer to I_S structure
 
1491
  @param[in]      open_tables_state_backup pointer to Open_tables_state object
 
1492
                                           which is used to save|restore original
 
1493
                                           status of variables related to
 
1494
                                           open tables state
 
1495
 
 
1496
  @return         Operation status
 
1497
    @retval       0           success
 
1498
    @retval       1           error
 
1499
*/
 
1500
 
 
1501
static int
 
1502
fill_schema_show_cols_or_idxs(Session *session, TableList *tables,
 
1503
                              plugin::InfoSchemaTable *schema_table,
 
1504
                              Open_tables_state *open_tables_state_backup)
 
1505
{
 
1506
  LEX *lex= session->lex;
 
1507
  bool res;
 
1508
  LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name;
 
1509
  enum_sql_command save_sql_command= lex->sql_command;
 
1510
  TableList *show_table_list= (TableList*) tables->schema_select_lex->
 
1511
    table_list.first;
 
1512
  Table *table= tables->table;
 
1513
  int error= 1;
 
1514
 
 
1515
  lex->all_selects_list= tables->schema_select_lex;
 
1516
  /*
 
1517
    Restore session->temporary_tables to be able to process
 
1518
    temporary tables(only for 'show index' & 'show columns').
 
1519
    This should be changed when processing of temporary tables for
 
1520
    I_S tables will be done.
 
1521
  */
 
1522
  session->temporary_tables= open_tables_state_backup->temporary_tables;
 
1523
  /*
 
1524
    Let us set fake sql_command so views won't try to merge
 
1525
    themselves into main statement. If we don't do this,
 
1526
    SELECT * from information_schema.xxxx will cause problems.
 
1527
    SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()'
 
1528
  */
 
1529
  lex->sql_command= SQLCOM_SHOW_FIELDS;
 
1530
  res= session->openTables(show_table_list, DRIZZLE_LOCK_IGNORE_FLUSH);
 
1531
  lex->sql_command= save_sql_command;
 
1532
  /*
 
1533
    get_all_tables() returns 1 on failure and 0 on success thus
 
1534
    return only these and not the result code of ::process_table()
 
1535
 
 
1536
    We should use show_table_list->alias instead of
 
1537
    show_table_list->table_name because table_name
 
1538
    could be changed during opening of I_S tables. It's safe
 
1539
    to use alias because alias contains original table name
 
1540
    in this case(this part of code is used only for
 
1541
    'show columns' & 'show statistics' commands).
 
1542
  */
 
1543
   table_name= session->make_lex_string(&tmp_lex_string1, show_table_list->alias,
 
1544
                                    strlen(show_table_list->alias), false);
 
1545
   db_name= session->make_lex_string(&tmp_lex_string, show_table_list->db,
 
1546
                                 show_table_list->db_length, false);
 
1547
 
 
1548
 
 
1549
   table->setWriteSet();
 
1550
   error= test(schema_table->processTable(session, show_table_list,
 
1551
                                          table, res, db_name,
 
1552
                                          table_name));
 
1553
   session->temporary_tables= 0;
 
1554
   session->close_tables_for_reopen(&show_table_list);
 
1555
 
 
1556
   return(error);
 
1557
}
 
1558
 
 
1559
 
 
1560
/**
 
1561
  @brief          Fill I_S table for SHOW Table NAMES commands
 
1562
 
 
1563
  @param[in]      session                      thread Cursor
 
1564
  @param[in]      table                    Table struct for I_S table
 
1565
  @param[in]      db_name                  database name
 
1566
  @param[in]      table_name               table name
 
1567
  @param[in]      with_i_schema            I_S table if true
 
1568
 
 
1569
  @return         Operation status
 
1570
    @retval       0           success
 
1571
    @retval       1           error
 
1572
*/
 
1573
 
 
1574
static int fill_schema_table_names(Session *session, Table *table,
 
1575
                                   LEX_STRING *db_name, LEX_STRING *table_name,
 
1576
                                   bool with_i_schema,
 
1577
                                   plugin::InfoSchemaTable *schema_table)
 
1578
{
 
1579
  if (with_i_schema)
 
1580
  {
 
1581
    table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
 
1582
                           system_charset_info);
 
1583
  }
 
1584
  else
 
1585
  {
 
1586
    char path[FN_REFLEN];
 
1587
    (void) build_table_filename(path, sizeof(path), db_name->str,
 
1588
                                table_name->str, false);
 
1589
 
 
1590
      table->field[3]->store(STRING_WITH_LEN("BASE Table"),
 
1591
                             system_charset_info);
 
1592
 
 
1593
    if (session->is_error() && session->main_da.sql_errno() == ER_NO_SUCH_TABLE)
 
1594
    {
 
1595
      session->clear_error();
 
1596
      return 0;
 
1597
    }
 
1598
  }
 
1599
  schema_table->addRow(table->record[0], table->s->reclength);
 
1600
  return 0;
 
1601
}
 
1602
 
 
1603
 
 
1604
/**
 
1605
  @brief          Fill I_S tables whose data are retrieved
 
1606
                  from frm files and storage engine
 
1607
 
 
1608
  @details        The information schema tables are internally represented as
 
1609
                  temporary tables that are filled at query execution time.
 
1610
                  Those I_S tables whose data are retrieved
 
1611
                  from frm files and storage engine are filled by the function
 
1612
                  plugin::InfoSchemaMethods::fillTable().
 
1613
 
 
1614
  @param[in]      session                      thread Cursor
 
1615
  @param[in]      tables                   I_S table
 
1616
 
 
1617
  @return         Operation status
 
1618
    @retval       0                        success
 
1619
    @retval       1                        error
 
1620
*/
 
1621
int plugin::InfoSchemaMethods::fillTable(Session *session, 
 
1622
                                         Table *table,
 
1623
                                         plugin::InfoSchemaTable *schema_table)
 
1624
{
 
1625
  LEX *lex= session->lex;
 
1626
  Select_Lex *old_all_select_lex= lex->all_selects_list;
 
1627
  enum_sql_command save_sql_command= lex->sql_command;
 
1628
  Select_Lex *lsel= table->pos_in_table_list->schema_select_lex;
 
1629
  Select_Lex sel;
 
1630
  LOOKUP_FIELD_VALUES lookup_field_vals;
 
1631
  bool with_i_schema;
 
1632
  vector<LEX_STRING*> db_names, table_names;
 
1633
  /* the WHERE clause */
 
1634
  COND *cond= table->reginfo.join_tab->select_cond;
 
1635
  COND *partial_cond= 0;
 
1636
  uint32_t derived_tables= lex->derived_tables;
 
1637
  int error= 1;
 
1638
  Open_tables_state open_tables_state_backup;
 
1639
  Query_tables_list query_tables_list_backup;
 
1640
  bool old_value= session->no_warnings_for_error;
 
1641
 
 
1642
  /*
 
1643
    We should not introduce deadlocks even if we already have some
 
1644
    tables open and locked, since we won't lock tables which we will
 
1645
    open and will ignore possible name-locks for these tables.
 
1646
  */
 
1647
  session->reset_n_backup_open_tables_state(&open_tables_state_backup);
 
1648
 
 
1649
  /*
 
1650
    this branch processes SHOW FIELDS, SHOW INDEXES commands.
 
1651
    see sql_parse.cc, prepare_schema_table() function where
 
1652
    this values are initialized
 
1653
  */
 
1654
  if (lsel && lsel->table_list.first)
 
1655
  {
 
1656
    error= fill_schema_show_cols_or_idxs(session, table->pos_in_table_list, schema_table,
 
1657
                                         &open_tables_state_backup);
 
1658
    goto err;
 
1659
  }
 
1660
 
 
1661
  if (get_lookup_field_values(session, 
 
1662
                              cond, 
 
1663
                              table->pos_in_table_list, 
 
1664
                              &lookup_field_vals,
 
1665
                              schema_table))
 
1666
  {
 
1667
    error= 0;
 
1668
    goto err;
 
1669
  }
 
1670
 
 
1671
  if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
 
1672
  {
 
1673
    /*
 
1674
      if lookup value is empty string then
 
1675
      it's impossible table name or db name
 
1676
    */
 
1677
    if ((lookup_field_vals.db_value.str && !lookup_field_vals.db_value.str[0]) ||
 
1678
        (lookup_field_vals.table_value.str && !lookup_field_vals.table_value.str[0]))
 
1679
    {
 
1680
      error= 0;
 
1681
      goto err;
 
1682
    }
 
1683
  }
 
1684
 
 
1685
  if (lookup_field_vals.db_value.length &&
 
1686
      !lookup_field_vals.wild_db_value)
 
1687
    table->pos_in_table_list->has_db_lookup_value= true;
 
1688
 
 
1689
  if (lookup_field_vals.table_value.length &&
 
1690
      !lookup_field_vals.wild_table_value)
 
1691
    table->pos_in_table_list->has_table_lookup_value= true;
 
1692
 
 
1693
  if (table->pos_in_table_list->has_db_lookup_value && 
 
1694
      table->pos_in_table_list->has_table_lookup_value)
 
1695
    partial_cond= 0;
 
1696
  else
 
1697
    partial_cond= make_cond_for_info_schema(cond, table, schema_table);
 
1698
 
 
1699
  if (lex->describe)
 
1700
  {
 
1701
    /* EXPLAIN SELECT */
 
1702
    error= 0;
 
1703
    goto err;
 
1704
  }
 
1705
 
 
1706
  table->setWriteSet();
 
1707
  if (make_db_list(session, db_names, &lookup_field_vals, &with_i_schema))
 
1708
    goto err;
 
1709
 
 
1710
  for (vector<LEX_STRING*>::iterator db_name= db_names.begin(); db_name != db_names.end(); ++db_name )
 
1711
  {
 
1712
    session->no_warnings_for_error= 1;
 
1713
    table_names.clear();
 
1714
    int res= make_table_name_list(session, table_names,
 
1715
                                  &lookup_field_vals,
 
1716
                                  with_i_schema, *db_name);
 
1717
 
 
1718
    if (res == 2)   /* Not fatal error, continue */
 
1719
      continue;
 
1720
 
 
1721
    if (res)
 
1722
      goto err;
 
1723
 
 
1724
    
 
1725
    for (vector<LEX_STRING*>::iterator table_name= table_names.begin(); table_name != table_names.end(); ++table_name)
 
1726
    {
 
1727
      table->restoreRecordAsDefault();
 
1728
      table->field[schema_table->getFirstColumnIndex()]->
 
1729
        store((*db_name)->str, (*db_name)->length, system_charset_info);
 
1730
      table->field[schema_table->getSecondColumnIndex()]->
 
1731
        store((*table_name)->str, (*table_name)->length, system_charset_info);
 
1732
 
 
1733
      if (!partial_cond || partial_cond->val_int())
 
1734
      {
 
1735
        /* SHOW Table NAMES command */
 
1736
        if (schema_table->getTableName().compare("TABLE_NAMES") == 0)
 
1737
        {
 
1738
          if (fill_schema_table_names(session, 
 
1739
                                      table, 
 
1740
                                      *db_name,
 
1741
                                      *table_name, 
 
1742
                                      with_i_schema,
 
1743
                                      schema_table))
 
1744
            continue;
 
1745
        }
 
1746
        else
 
1747
        {
 
1748
          LEX_STRING tmp_lex_string, orig_db_name;
 
1749
          /*
 
1750
            Set the parent lex of 'sel' because it is needed by
 
1751
            sel.init_query() which is called inside make_table_list.
 
1752
          */
 
1753
          session->no_warnings_for_error= 1;
 
1754
          sel.parent_lex= lex;
 
1755
          /* db_name can be changed in make_table_list() func */
 
1756
          if (! session->make_lex_string(&orig_db_name, 
 
1757
                                         (*db_name)->str,
 
1758
                                         (*db_name)->length, 
 
1759
                                         false))
 
1760
          {
 
1761
            goto err;
 
1762
          }
 
1763
 
 
1764
          if (make_table_list(session, &sel, *db_name, *table_name))
 
1765
            goto err;
 
1766
 
 
1767
          TableList *show_table_list= (TableList*) sel.table_list.first;
 
1768
          lex->all_selects_list= &sel;
 
1769
          lex->derived_tables= 0;
 
1770
          lex->sql_command= SQLCOM_SHOW_FIELDS;
 
1771
          show_table_list->i_s_requested_object=
 
1772
            schema_table->getRequestedObject();
 
1773
          res= session->openTables(show_table_list, DRIZZLE_LOCK_IGNORE_FLUSH);
 
1774
          lex->sql_command= save_sql_command;
 
1775
          /*
 
1776
            XXX->  show_table_list has a flag i_is_requested,
 
1777
            and when it's set, openTables()
 
1778
            can return an error without setting an error message
 
1779
            in Session, which is a hack. This is why we have to
 
1780
            check for res, then for session->is_error() only then
 
1781
            for session->main_da.sql_errno().
 
1782
          */
 
1783
          if (res && session->is_error() &&
 
1784
              session->main_da.sql_errno() == ER_NO_SUCH_TABLE)
 
1785
          {
 
1786
            /*
 
1787
              Hide error for not existing table.
 
1788
              This error can occur for example when we use
 
1789
              where condition with db name and table name and this
 
1790
              table does not exist.
 
1791
            */
 
1792
            res= 0;
 
1793
            session->clear_error();
 
1794
          }
 
1795
          else
 
1796
          {
 
1797
            /*
 
1798
              We should use show_table_list->alias instead of
 
1799
              show_table_list->table_name because table_name
 
1800
              could be changed during opening of I_S tables. It's safe
 
1801
              to use alias because alias contains original table name
 
1802
              in this case.
 
1803
            */
 
1804
            session->make_lex_string(&tmp_lex_string, show_table_list->alias,
 
1805
                                     strlen(show_table_list->alias), false);
 
1806
            res= schema_table->processTable(session, show_table_list, table,
 
1807
                                            res, &orig_db_name,
 
1808
                                            &tmp_lex_string);
 
1809
            session->close_tables_for_reopen(&show_table_list);
 
1810
          }
 
1811
          assert(!lex->query_tables_own_last);
 
1812
          if (res)
 
1813
            goto err;
 
1814
        }
 
1815
      }
 
1816
    }
 
1817
    /*
 
1818
      If we have information schema its always the first table and only
 
1819
      the first table. Reset for other tables.
 
1820
    */
 
1821
    with_i_schema= 0;
 
1822
  }
 
1823
 
 
1824
  error= 0;
 
1825
 
 
1826
err:
 
1827
  session->restore_backup_open_tables_state(&open_tables_state_backup);
 
1828
  lex->derived_tables= derived_tables;
 
1829
  lex->all_selects_list= old_all_select_lex;
 
1830
  lex->sql_command= save_sql_command;
 
1831
  session->no_warnings_for_error= old_value;
 
1832
  return(error);
 
1833
}
 
1834
 
 
1835
 
 
1836
/**
 
1837
  @brief    Store field characteristics into appropriate I_S table columns
 
1838
 
 
1839
  @param[in]      table             I_S table
 
1840
  @param[in]      field             processed field
 
1841
  @param[in]      cs                I_S table charset
 
1842
  @param[in]      offset            offset from beginning of table
 
1843
                                    to DATE_TYPE column in I_S table
 
1844
 
 
1845
  @return         void
 
1846
*/
 
1847
 
 
1848
static void store_column_type(Table *table, Field *field,
 
1849
                              const CHARSET_INFO * const cs,
 
1850
                              uint32_t offset)
 
1851
{
 
1852
  bool is_blob;
 
1853
  int decimals, field_length;
 
1854
  const char *tmp_buff;
 
1855
  char column_type_buff[MAX_FIELD_WIDTH];
 
1856
  String column_type(column_type_buff, sizeof(column_type_buff), cs);
 
1857
 
 
1858
  field->sql_type(column_type);
 
1859
  /* DTD_IDENTIFIER column */
 
1860
  table->field[offset + 7]->store(column_type.ptr(), column_type.length(), cs);
 
1861
  table->field[offset + 7]->set_notnull();
 
1862
  tmp_buff= strchr(column_type.ptr(), '(');
 
1863
  /* DATA_TYPE column */
 
1864
  table->field[offset]->store(column_type.ptr(),
 
1865
                         (tmp_buff ? tmp_buff - column_type.ptr() :
 
1866
                          column_type.length()), cs);
 
1867
  is_blob= (field->type() == DRIZZLE_TYPE_BLOB);
 
1868
  if (field->has_charset() || is_blob ||
 
1869
      field->real_type() == DRIZZLE_TYPE_VARCHAR)  // For varbinary type
 
1870
  {
 
1871
    uint32_t octet_max_length= field->max_display_length();
 
1872
    if (is_blob && octet_max_length != (uint32_t) 4294967295U)
 
1873
      octet_max_length /= field->charset()->mbmaxlen;
 
1874
    int64_t char_max_len= is_blob ?
 
1875
      (int64_t) octet_max_length / field->charset()->mbminlen :
 
1876
      (int64_t) octet_max_length / field->charset()->mbmaxlen;
 
1877
    /* CHARACTER_MAXIMUM_LENGTH column*/
 
1878
    table->field[offset + 1]->store(char_max_len, true);
 
1879
    table->field[offset + 1]->set_notnull();
 
1880
    /* CHARACTER_OCTET_LENGTH column */
 
1881
    table->field[offset + 2]->store((int64_t) octet_max_length, true);
 
1882
    table->field[offset + 2]->set_notnull();
 
1883
  }
 
1884
 
 
1885
  /*
 
1886
    Calculate field_length and decimals.
 
1887
    They are set to -1 if they should not be set (we should return NULL)
 
1888
  */
 
1889
 
 
1890
  decimals= field->decimals();
 
1891
  switch (field->type()) {
 
1892
  case DRIZZLE_TYPE_DECIMAL:
 
1893
    field_length= ((Field_decimal*) field)->precision;
 
1894
    break;
 
1895
  case DRIZZLE_TYPE_LONG:
 
1896
  case DRIZZLE_TYPE_LONGLONG:
 
1897
    field_length= field->max_display_length() - 1;
 
1898
    break;
 
1899
  case DRIZZLE_TYPE_DOUBLE:
 
1900
    field_length= field->field_length;
 
1901
    if (decimals == NOT_FIXED_DEC)
 
1902
      decimals= -1;                           // return NULL
 
1903
    break;
 
1904
  default:
 
1905
    field_length= decimals= -1;
 
1906
    break;
 
1907
  }
 
1908
 
 
1909
  /* NUMERIC_PRECISION column */
 
1910
  if (field_length >= 0)
 
1911
  {
 
1912
    table->field[offset + 3]->store((int64_t) field_length, true);
 
1913
    table->field[offset + 3]->set_notnull();
 
1914
  }
 
1915
  /* NUMERIC_SCALE column */
 
1916
  if (decimals >= 0)
 
1917
  {
 
1918
    table->field[offset + 4]->store((int64_t) decimals, true);
 
1919
    table->field[offset + 4]->set_notnull();
 
1920
  }
 
1921
  if (field->has_charset())
 
1922
  {
 
1923
    /* CHARACTER_SET_NAME column*/
 
1924
    tmp_buff= field->charset()->csname;
 
1925
    table->field[offset + 5]->store(tmp_buff, strlen(tmp_buff), cs);
 
1926
    table->field[offset + 5]->set_notnull();
 
1927
    /* COLLATION_NAME column */
 
1928
    tmp_buff= field->charset()->name;
 
1929
    table->field[offset + 6]->store(tmp_buff, strlen(tmp_buff), cs);
 
1930
    table->field[offset + 6]->set_notnull();
 
1931
  }
 
1932
}
 
1933
 
 
1934
 
 
1935
int plugin::InfoSchemaMethods::processTable(
 
1936
            plugin::InfoSchemaTable *store_table,
 
1937
            Session *session, 
 
1938
            TableList *tables,
 
1939
                                    Table *table, bool res,
 
1940
                                    LEX_STRING *db_name,
 
1941
                                    LEX_STRING *table_name)
 
1942
{
 
1943
  LEX *lex= session->lex;
 
1944
  const char *wild= lex->wild ? lex->wild->ptr() : NULL;
 
1945
  const CHARSET_INFO * const cs= system_charset_info;
 
1946
  Table *show_table;
 
1947
  TableShare *show_table_share;
 
1948
  Field **ptr, *field, *timestamp_field;
 
1949
  int count;
 
1950
 
 
1951
  if (res)
 
1952
  {
 
1953
    if (lex->sql_command != SQLCOM_SHOW_FIELDS)
 
1954
    {
 
1955
      /*
 
1956
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
 
1957
        rather than in SHOW COLUMNS
 
1958
      */
 
1959
      if (session->is_error())
 
1960
        push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
1961
                     session->main_da.sql_errno(), session->main_da.message());
 
1962
      session->clear_error();
 
1963
      res= 0;
 
1964
    }
 
1965
    return(res);
 
1966
  }
 
1967
 
 
1968
  show_table= tables->table;
 
1969
  show_table_share= show_table->s;
 
1970
  count= 0;
 
1971
 
 
1972
  ptr= show_table_share->field;
 
1973
  timestamp_field= show_table_share->timestamp_field;
 
1974
 
 
1975
  /* For the moment we just set everything to read */
 
1976
  if (!show_table->read_set)
 
1977
  {
 
1978
    show_table->def_read_set.setAll();
 
1979
    show_table->read_set= &show_table->def_read_set;
 
1980
  }
 
1981
  show_table->use_all_columns();               // Required for default
 
1982
 
 
1983
  for (; (field= *ptr) ; ptr++)
 
1984
  {
 
1985
    unsigned char *pos;
 
1986
    char tmp[MAX_FIELD_WIDTH];
 
1987
    String type(tmp,sizeof(tmp), system_charset_info);
 
1988
    char *end;
 
1989
 
 
1990
    /* to satisfy 'field->val_str' ASSERTs */
 
1991
    field->table= show_table;
 
1992
    show_table->in_use= session;
 
1993
 
 
1994
    if (wild && wild[0] &&
 
1995
        wild_case_compare(system_charset_info, field->field_name,wild))
 
1996
      continue;
 
1997
 
 
1998
    count++;
 
1999
    /* Get default row, with all NULL fields set to NULL */
 
2000
    table->restoreRecordAsDefault();
 
2001
 
 
2002
    table->field[1]->store(db_name->str, db_name->length, cs);
 
2003
    table->field[2]->store(table_name->str, table_name->length, cs);
 
2004
    table->field[3]->store(field->field_name, strlen(field->field_name),
 
2005
                           cs);
 
2006
    table->field[4]->store((int64_t) count, true);
 
2007
 
 
2008
    if (get_field_default_value(timestamp_field, field, &type, 0))
 
2009
    {
 
2010
      table->field[5]->store(type.ptr(), type.length(), cs);
 
2011
      table->field[5]->set_notnull();
 
2012
    }
 
2013
    pos=(unsigned char*) ((field->flags & NOT_NULL_FLAG) ?  "NO" : "YES");
 
2014
    table->field[6]->store((const char*) pos,
 
2015
                           strlen((const char*) pos), cs);
 
2016
    store_column_type(table, field, cs, 7);
 
2017
 
 
2018
    pos=(unsigned char*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
 
2019
                 (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
 
2020
                 (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
 
2021
    table->field[15]->store((const char*) pos,
 
2022
                            strlen((const char*) pos), cs);
 
2023
 
 
2024
    end= tmp;
 
2025
    if (field->unireg_check == Field::NEXT_NUMBER)
 
2026
      table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs);
 
2027
    if (timestamp_field == field &&
 
2028
        field->unireg_check != Field::TIMESTAMP_DN_FIELD)
 
2029
      table->field[16]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
 
2030
                              cs);
 
2031
    table->field[18]->store(field->comment.str, field->comment.length, cs);
 
2032
    {
 
2033
      enum column_format_type column_format= (enum column_format_type)
 
2034
        ((field->flags >> COLUMN_FORMAT_FLAGS) & COLUMN_FORMAT_MASK);
 
2035
      pos=(unsigned char*)"Default";
 
2036
      table->field[19]->store((const char*) pos,
 
2037
                              strlen((const char*) pos), cs);
 
2038
      pos=(unsigned char*)(column_format == COLUMN_FORMAT_TYPE_DEFAULT ? "Default" :
 
2039
                   column_format == COLUMN_FORMAT_TYPE_FIXED ? "Fixed" :
 
2040
                                                             "Dynamic");
 
2041
      table->field[20]->store((const char*) pos,
 
2042
                              strlen((const char*) pos), cs);
 
2043
    }
 
2044
    store_table->addRow(table->record[0], table->s->reclength);
 
2045
  }
 
2046
  return(0);
 
2047
}
 
2048
 
 
2049
 
 
2050
/*
 
2051
  For old SHOW compatibility. It is used when
 
2052
  old SHOW doesn't have generated column names
 
2053
  Make list of fields for SHOW
 
2054
 
 
2055
  SYNOPSIS
 
2056
    plugin::InfoSchemaMethods::oldFormat()
 
2057
    session                     thread Cursor
 
2058
    schema_table        pointer to 'schema_tables' element
 
2059
 
 
2060
  RETURN
 
2061
   1    error
 
2062
   0    success
 
2063
*/
 
2064
 
 
2065
int plugin::InfoSchemaMethods::oldFormat(Session *session, plugin::InfoSchemaTable *schema_table)
 
2066
  const
 
2067
{
 
2068
  Name_resolution_context *context= &session->lex->select_lex.context;
 
2069
  const plugin::InfoSchemaTable::Columns columns= schema_table->getColumns();
 
2070
  plugin::InfoSchemaTable::Columns::const_iterator iter= columns.begin();
 
2071
 
 
2072
  while (iter != columns.end())
 
2073
  {
 
2074
    const plugin::ColumnInfo *column= *iter;
 
2075
    if (column->getOldName().length() != 0)
 
2076
    {
 
2077
      Item_field *field= new Item_field(context,
 
2078
                                        NULL, NULL,
 
2079
                                        column->getName().c_str());
 
2080
      if (field)
 
2081
      {
 
2082
        field->set_name(column->getOldName().c_str(),
 
2083
                        column->getOldName().length(),
 
2084
                        system_charset_info);
 
2085
        if (session->add_item_to_list(field))
 
2086
          return 1;
 
2087
      }
 
2088
    }
 
2089
    ++iter;
 
2090
  }
 
2091
  return 0;
 
2092
}
 
2093
 
 
2094
 
 
2095
/*
 
2096
  Generate select from information_schema table
 
2097
 
 
2098
  SYNOPSIS
 
2099
    make_schema_select()
 
2100
    session                  thread Cursor
 
2101
    sel                  pointer to Select_Lex
 
2102
    schema_table_name    name of 'schema_tables' element
 
2103
 
 
2104
  RETURN
 
2105
    true on error
 
2106
*/
 
2107
 
 
2108
bool make_schema_select(Session *session, Select_Lex *sel,
 
2109
                        const string& schema_table_name)
 
2110
{
 
2111
  plugin::InfoSchemaTable *schema_table= plugin::InfoSchemaTable::getTable(schema_table_name.c_str());
 
2112
  LEX_STRING db, table;
 
2113
  /*
 
2114
     We have to make non const db_name & table_name
 
2115
     because of lower_case_table_names
 
2116
  */
 
2117
  session->make_lex_string(&db, INFORMATION_SCHEMA_NAME.c_str(),
 
2118
                       INFORMATION_SCHEMA_NAME.length(), 0);
 
2119
  session->make_lex_string(&table, schema_table->getTableName().c_str(),
 
2120
                           schema_table->getTableName().length(), 0);
 
2121
  if (schema_table->oldFormat(session, schema_table) ||   /* Handle old syntax */
 
2122
      ! sel->add_table_to_list(session, new Table_ident(db, table), 0, 0, TL_READ))
 
2123
  {
 
2124
    return true;
 
2125
  }
294
2126
  return false;
295
2127
}
296
2128
 
297
 
bool buildColumns(Session *session, const char *schema_ident, Table_ident *table_ident)
298
 
{
299
 
  session->getLex()->sql_command= SQLCOM_SELECT;
300
 
 
301
 
  drizzled::statement::Show *select= new statement::Show(session);
302
 
  session->getLex()->statement= select;
303
 
 
304
 
  util::string::const_shared_ptr schema(session->schema());
305
 
  if (schema_ident)
306
 
  {
307
 
    select->setShowPredicate(schema_ident, table_ident->table.str);
308
 
  }
309
 
  else if (table_ident->db.str)
310
 
  {
311
 
    select->setShowPredicate(table_ident->db.str, table_ident->table.str);
312
 
  }
313
 
  else if (schema)
314
 
  {
315
 
    select->setShowPredicate(*schema, table_ident->table.str);
316
 
  }
317
 
  else
318
 
  {
319
 
    my_error(ER_NO_DB_ERROR, MYF(0));
320
 
    return false;
321
 
  }
322
 
 
323
 
  {
324
 
    drizzled::identifier::Table identifier(select->getShowSchema().c_str(), table_ident->table.str);
325
 
    if (not plugin::StorageEngine::doesTableExist(*session, identifier))
326
 
    {
327
 
      my_error(ER_TABLE_UNKNOWN, identifier);
328
 
    }
329
 
  }
330
 
 
331
 
  if (prepare_new_schema_table(session, session->getLex(), "SHOW_COLUMNS"))
332
 
    return false;
333
 
 
334
 
  if (session->add_item_to_list( new Item_field(&session->lex->current_select->context, NULL, NULL, "*")))
335
 
    return false;
336
 
 
337
 
  (session->lex->current_select->with_wild)++;
338
 
 
339
 
  return true;
340
 
}
341
 
 
342
 
void buildSelectWarning(Session *session)
343
 
{
344
 
  (void) create_select_for_variable(session, "warning_count");
345
 
  session->getLex()->statement= new statement::Show(session);
346
 
}
347
 
 
348
 
void buildSelectError(Session *session)
349
 
{
350
 
  (void) create_select_for_variable(session, "error_count");
351
 
  session->getLex()->statement= new statement::Show(session);
352
 
}
353
 
 
354
 
void buildWarnings(Session *session)
355
 
{
356
 
  session->getLex()->statement= new statement::ShowWarnings(session);
357
 
}
358
 
 
359
 
void buildErrors(Session *session)
360
 
{
361
 
  session->getLex()->statement= new statement::ShowErrors(session);
362
 
}
363
 
 
364
 
bool buildIndex(Session *session, const char *schema_ident, Table_ident *table_ident)
365
 
{
366
 
  session->getLex()->sql_command= SQLCOM_SELECT;
367
 
  drizzled::statement::Show *select= new statement::Show(session);
368
 
  session->getLex()->statement= select;
369
 
 
370
 
  util::string::const_shared_ptr schema(session->schema());
371
 
  if (schema_ident)
372
 
  {
373
 
    select->setShowPredicate(schema_ident, table_ident->table.str);
374
 
  }
375
 
  else if (table_ident->db.str)
376
 
  {
377
 
    select->setShowPredicate(table_ident->db.str, table_ident->table.str);
378
 
  }
379
 
  else if (schema)
380
 
  {
381
 
    select->setShowPredicate(*schema, table_ident->table.str);
382
 
  }
383
 
  else
384
 
  {
385
 
    my_error(ER_NO_DB_ERROR, MYF(0));
386
 
    return false;
387
 
  }
388
 
 
389
 
  {
390
 
    drizzled::identifier::Table identifier(select->getShowSchema().c_str(), table_ident->table.str);
391
 
    if (not plugin::StorageEngine::doesTableExist(*session, identifier))
392
 
    {
393
 
      my_error(ER_TABLE_UNKNOWN, identifier);
394
 
    }
395
 
  }
396
 
 
397
 
  if (prepare_new_schema_table(session, session->getLex(), "SHOW_INDEXES"))
398
 
    return false;
399
 
 
400
 
  if (session->add_item_to_list( new Item_field(&session->lex->current_select->context, NULL, NULL, "*")))
401
 
    return false;
402
 
 
403
 
  (session->lex->current_select->with_wild)++;
404
 
 
405
 
  return true;
406
 
}
407
 
 
408
 
bool buildStatus(Session *session, const drizzled::sql_var_t is_global)
409
 
{
410
 
  session->getLex()->sql_command= SQLCOM_SELECT;
411
 
  session->getLex()->statement= new statement::Show(session);
412
 
 
413
 
  if (is_global == OPT_GLOBAL)
414
 
  {
415
 
    if (prepare_new_schema_table(session, session->getLex(), "GLOBAL_STATUS"))
416
 
      return false;
417
 
  }
418
 
  else
419
 
  {
420
 
    if (prepare_new_schema_table(session, session->getLex(), "SESSION_STATUS"))
421
 
      return false;
422
 
  }
423
 
 
424
 
  std::string key("Variable_name");
425
 
  std::string value("Value");
426
 
 
427
 
  Item_field *my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "VARIABLE_NAME");
428
 
  my_field->is_autogenerated_name= false;
429
 
  my_field->set_name(key.c_str(), key.length(), system_charset_info);
430
 
 
431
 
  if (session->add_item_to_list(my_field))
432
 
    return false;
433
 
 
434
 
  my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "VARIABLE_VALUE");
435
 
  my_field->is_autogenerated_name= false;
436
 
  my_field->set_name(value.c_str(), value.length(), system_charset_info);
437
 
 
438
 
  if (session->add_item_to_list(my_field))
439
 
    return false;
440
 
 
441
 
  return true;
442
 
}
443
 
 
444
 
bool buildCreateTable(Session *session, Table_ident *ident)
445
 
{
446
 
  session->getLex()->sql_command= SQLCOM_SELECT;
447
 
  statement::Show *select= new statement::Show(session);
448
 
  session->getLex()->statement= select;
449
 
 
450
 
  if (session->getLex()->statement == NULL)
451
 
    return false;
452
 
 
453
 
  if (prepare_new_schema_table(session, session->getLex(), "TABLE_SQL_DEFINITION"))
454
 
    return false;
455
 
 
456
 
  util::string::const_shared_ptr schema(session->schema());
457
 
  if (ident->db.str)
458
 
  {
459
 
    select->setShowPredicate(ident->db.str, ident->table.str);
460
 
  }
461
 
  else if (schema)
462
 
  {
463
 
    select->setShowPredicate(*schema, ident->table.str);
464
 
  }
465
 
  else
466
 
  {
467
 
    my_error(ER_NO_DB_ERROR, MYF(0));
468
 
    return false;
469
 
  }
470
 
 
471
 
  std::string key("Table");
472
 
  std::string value("Create Table");
473
 
 
474
 
  Item_field *my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "TABLE_NAME");
475
 
  my_field->is_autogenerated_name= false;
476
 
  my_field->set_name(key.c_str(), key.length(), system_charset_info);
477
 
 
478
 
  if (session->add_item_to_list(my_field))
479
 
    return false;
480
 
 
481
 
  my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "TABLE_SQL_DEFINITION");
482
 
  my_field->is_autogenerated_name= false;
483
 
  my_field->set_name(value.c_str(), value.length(), system_charset_info);
484
 
 
485
 
  if (session->add_item_to_list(my_field))
486
 
    return false;
487
 
 
488
 
  return true;
489
 
}
490
 
 
491
 
bool buildProcesslist(Session *session)
492
 
{
493
 
  session->getLex()->sql_command= SQLCOM_SELECT;
494
 
  session->getLex()->statement= new statement::Show(session);
495
 
 
496
 
  if (prepare_new_schema_table(session, session->getLex(), "PROCESSLIST"))
497
 
    return false;
498
 
 
499
 
  if (session->add_item_to_list( new Item_field(&session->lex->current_select->context, NULL, NULL, "*")))
500
 
    return false;
501
 
 
502
 
  (session->lex->current_select->with_wild)++;
503
 
 
504
 
  return true;
505
 
}
506
 
 
507
 
bool buildVariables(Session *session, const drizzled::sql_var_t is_global)
508
 
{
509
 
  session->getLex()->sql_command= SQLCOM_SELECT;
510
 
  session->getLex()->statement= new statement::Show(session);
511
 
 
512
 
  if (is_global == OPT_GLOBAL)
513
 
  {
514
 
    if (prepare_new_schema_table(session, session->getLex(), "GLOBAL_VARIABLES"))
515
 
      return false;
516
 
  }
517
 
  else
518
 
  {
519
 
    if (prepare_new_schema_table(session, session->getLex(), "SESSION_VARIABLES"))
520
 
      return false;
521
 
  }
522
 
 
523
 
  std::string key("Variable_name");
524
 
  std::string value("Value");
525
 
 
526
 
  Item_field *my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "VARIABLE_NAME");
527
 
  my_field->is_autogenerated_name= false;
528
 
  my_field->set_name(key.c_str(), key.length(), system_charset_info);
529
 
 
530
 
  if (session->add_item_to_list(my_field))
531
 
    return false;
532
 
 
533
 
  my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "VARIABLE_VALUE");
534
 
  my_field->is_autogenerated_name= false;
535
 
  my_field->set_name(value.c_str(), value.length(), system_charset_info);
536
 
 
537
 
  if (session->add_item_to_list(my_field))
538
 
    return false;
539
 
 
540
 
  return true;
541
 
}
542
 
 
543
 
bool buildCreateSchema(Session *session, LEX_STRING &ident)
544
 
{
545
 
  session->getLex()->sql_command= SQLCOM_SELECT;
546
 
  drizzled::statement::Show *select= new statement::Show(session);
547
 
  session->getLex()->statement= select;
548
 
 
549
 
  if (prepare_new_schema_table(session, session->getLex(), "SCHEMA_SQL_DEFINITION"))
550
 
    return false;
551
 
 
552
 
  util::string::const_shared_ptr schema(session->schema());
553
 
  if (ident.str)
554
 
  {
555
 
    select->setShowPredicate(ident.str);
556
 
  }
557
 
  else if (schema)
558
 
  {
559
 
    select->setShowPredicate(*schema);
560
 
  }
561
 
  else
562
 
  {
563
 
    my_error(ER_NO_DB_ERROR, MYF(0));
564
 
    return false;
565
 
  }
566
 
 
567
 
  std::string key("Database");
568
 
  std::string value("Create Database");
569
 
 
570
 
  Item_field *my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "SCHEMA_NAME");
571
 
  my_field->is_autogenerated_name= false;
572
 
  my_field->set_name(key.c_str(), key.length(), system_charset_info);
573
 
 
574
 
  if (session->add_item_to_list(my_field))
575
 
    return false;
576
 
 
577
 
  my_field= new Item_field(&session->lex->current_select->context, NULL, NULL, "SCHEMA_SQL_DEFINITION");
578
 
  my_field->is_autogenerated_name= false;
579
 
  my_field->set_name(value.c_str(), value.length(), system_charset_info);
580
 
 
581
 
  if (session->add_item_to_list(my_field))
582
 
    return false;
583
 
 
584
 
  return true;
585
 
}
586
 
 
587
 
bool buildDescribe(Session *session, Table_ident *ident)
588
 
{
589
 
  session->getLex()->lock_option= TL_READ;
590
 
  init_select(session->getLex());
591
 
  session->getLex()->current_select->parsing_place= SELECT_LIST;
592
 
  session->getLex()->sql_command= SQLCOM_SELECT;
593
 
  drizzled::statement::Show *select= new statement::Show(session);
594
 
  session->getLex()->statement= select;
595
 
  session->getLex()->select_lex.db= 0;
596
 
 
597
 
  util::string::const_shared_ptr schema(session->schema());
598
 
  if (ident->db.str)
599
 
  {
600
 
    select->setShowPredicate(ident->db.str, ident->table.str);
601
 
  }
602
 
  else if (schema)
603
 
  {
604
 
    select->setShowPredicate(*schema, ident->table.str);
605
 
  }
606
 
  else
607
 
  {
608
 
    my_error(ER_NO_DB_ERROR, MYF(0));
609
 
    return false;
610
 
  }
611
 
 
612
 
  {
613
 
    drizzled::identifier::Table identifier(select->getShowSchema().c_str(), ident->table.str);
614
 
    if (not plugin::StorageEngine::doesTableExist(*session, identifier))
615
 
    {
616
 
      my_error(ER_TABLE_UNKNOWN, identifier);
617
 
    }
618
 
  }
619
 
 
620
 
  if (prepare_new_schema_table(session, session->getLex(), "SHOW_COLUMNS"))
621
 
  {
622
 
    return false;
623
 
  }
624
 
 
625
 
  if (session->add_item_to_list( new Item_field(&session->lex->current_select->
626
 
                                                  context,
627
 
                                                  NULL, NULL, "*")))
628
 
  {
629
 
    return false;
630
 
  }
631
 
 
632
 
  (session->lex->current_select->with_wild)++;
633
 
 
634
 
  return true;
635
 
}
636
 
 
637
 
} /* namespace drizzled */
638
 
 
639
 
} /* namespace drizzled */