~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/show.cc

Updated an include guard thanks to a nice catch during code review from Jay. Thanks Jay!

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
 
21
21
/* Function with list databases, tables or fields */
22
 
#include "config.h"
 
22
#include <drizzled/server_includes.h>
23
23
#include <drizzled/sql_select.h>
24
24
#include <drizzled/show.h>
25
25
#include <drizzled/gettext.h>
40
40
#include <drizzled/item/return_date_time.h>
41
41
#include <drizzled/item/empty_string.h>
42
42
#include "drizzled/plugin/registry.h"
43
 
#include "drizzled/session_list.h"
 
43
#include <drizzled/plugin/info_schema_table.h>
44
44
#include <drizzled/message/schema.pb.h>
45
45
#include <drizzled/plugin/client.h>
46
 
#include <drizzled/cached_directory.h>
47
 
#include "drizzled/sql_table.h"
48
 
#include "drizzled/global_charset_info.h"
49
 
#include "drizzled/pthread_globals.h"
50
 
#include "drizzled/internal/m_string.h"
51
 
#include "drizzled/internal/my_sys.h"
52
 
 
 
46
#include <mysys/cached_directory.h>
53
47
#include <sys/stat.h>
54
48
 
55
49
#include <string>
59
53
#include <algorithm>
60
54
 
61
55
using namespace std;
62
 
 
63
 
namespace drizzled
64
 
{
 
56
using namespace drizzled;
65
57
 
66
58
inline const char *
67
59
str_or_nil(const char *str)
72
64
static void store_key_options(String *packet, Table *table, KEY *key_info);
73
65
 
74
66
 
75
 
int wild_case_compare(const CHARSET_INFO * const cs, const char *str, const char *wildstr)
 
67
 
 
68
int wild_case_compare(const CHARSET_INFO * const cs, const char *str,const char *wildstr)
76
69
{
77
70
  register int flag;
78
 
 
79
71
  while (*wildstr)
80
72
  {
81
 
    while (*wildstr && *wildstr != internal::wild_many && *wildstr != internal::wild_one)
 
73
    while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
82
74
    {
83
 
      if (*wildstr == internal::wild_prefix && wildstr[1])
 
75
      if (*wildstr == wild_prefix && wildstr[1])
84
76
        wildstr++;
85
77
      if (my_toupper(cs, *wildstr++) != my_toupper(cs, *str++))
86
78
        return (1);
87
79
    }
88
80
    if (! *wildstr )
89
81
      return (*str != 0);
90
 
    if (*wildstr++ == internal::wild_one)
 
82
    if (*wildstr++ == wild_one)
91
83
    {
92
84
      if (! *str++)
93
85
        return (1);     /* One char; skip */
96
88
    {                                           /* Found '*' */
97
89
      if (! *wildstr)
98
90
        return (0);             /* '*' as last char: OK */
99
 
      flag=(*wildstr != internal::wild_many && *wildstr != internal::wild_one);
 
91
      flag=(*wildstr != wild_many && *wildstr != wild_one);
100
92
      do
101
93
      {
102
94
        if (flag)
103
95
        {
104
96
          char cmp;
105
 
          if ((cmp= *wildstr) == internal::wild_prefix && wildstr[1])
 
97
          if ((cmp= *wildstr) == wild_prefix && wildstr[1])
106
98
            cmp= wildstr[1];
107
99
          cmp= my_toupper(cs, cmp);
108
100
          while (*str && my_toupper(cs, *str) != cmp)
116
108
      return (1);
117
109
    }
118
110
  }
119
 
 
120
111
  return (*str != '\0');
121
112
}
122
113
 
123
114
 
 
115
/**
 
116
 * @brief
 
117
 *   Find subdirectories (schemas) in a given directory (datadir).
 
118
 *
 
119
 * @param[in]  session    Thread Cursor
 
120
 * @param[out] files      Put found entries in this list
 
121
 * @param[in]  path       Path to database
 
122
 * @param[in]  wild       Filter for found entries
 
123
 *
 
124
 * @retval false   Success
 
125
 * @retval true    Error
 
126
 */
 
127
static bool find_schemas(Session *session, vector<LEX_STRING*> &files,
 
128
                         const char *path, const char *wild)
 
129
{
 
130
  if (wild && (wild[0] == '\0'))
 
131
    wild= 0;
 
132
 
 
133
  CachedDirectory directory(path);
 
134
 
 
135
  if (directory.fail())
 
136
  {
 
137
    my_errno= directory.getError();
 
138
    my_error(ER_CANT_READ_DIR, MYF(0), path, my_errno);
 
139
 
 
140
    return true;
 
141
  }
 
142
 
 
143
  CachedDirectory::Entries entries= directory.getEntries();
 
144
  CachedDirectory::Entries::iterator entry_iter= entries.begin();
 
145
 
 
146
  while (entry_iter != entries.end())
 
147
  {
 
148
    uint32_t file_name_len;
 
149
    char uname[NAME_LEN + 1];                   /* Unencoded name */
 
150
    struct stat entry_stat;
 
151
    CachedDirectory::Entry *entry= *entry_iter;
 
152
 
 
153
    if ((entry->filename == ".") || (entry->filename == ".."))
 
154
    {
 
155
      ++entry_iter;
 
156
      continue;
 
157
    }
 
158
 
 
159
    if (stat(entry->filename.c_str(), &entry_stat))
 
160
    {
 
161
      my_errno= errno;
 
162
      my_error(ER_CANT_GET_STAT, MYF(0), entry->filename.c_str(), my_errno);
 
163
      return(true);
 
164
    }
 
165
 
 
166
    if (! S_ISDIR(entry_stat.st_mode))
 
167
    {
 
168
      ++entry_iter;
 
169
      continue;
 
170
    }
 
171
 
 
172
    file_name_len= filename_to_tablename(entry->filename.c_str(), uname,
 
173
                                         sizeof(uname));
 
174
    if (wild && wild_compare(uname, wild, 0))
 
175
    {
 
176
      ++entry_iter;
 
177
      continue;
 
178
    }
 
179
 
 
180
    LEX_STRING *file_name= 0;
 
181
    file_name= session->make_lex_string(file_name, uname, file_name_len, true);
 
182
    if (file_name == NULL)
 
183
      return(true);
 
184
 
 
185
    files.push_back(file_name);
 
186
    ++entry_iter;
 
187
  }
 
188
 
 
189
  return false;
 
190
}
 
191
 
 
192
 
124
193
bool drizzled_show_create(Session *session, TableList *table_list, bool is_if_not_exists)
125
194
{
126
195
  char buff[2048];
191
260
  @returns true if errors are detected, false otherwise.
192
261
*/
193
262
 
194
 
static bool store_db_create_info(SchemaIdentifier &schema_identifier, string &buffer, bool if_not_exists)
 
263
static bool store_db_create_info(const char *dbname, String *buffer, bool if_not_exists)
195
264
{
196
265
  message::Schema schema;
197
266
 
198
 
  bool found= plugin::StorageEngine::getSchemaDefinition(schema_identifier, schema);
199
 
  if (not found)
200
 
    return false;
 
267
  if (!my_strcasecmp(system_charset_info, dbname,
 
268
                     INFORMATION_SCHEMA_NAME.c_str()))
 
269
  {
 
270
    dbname= INFORMATION_SCHEMA_NAME.c_str();
 
271
  }
 
272
  else
 
273
  {
 
274
    int r= get_database_metadata(dbname, &schema);
 
275
    if(r < 0)
 
276
      return true;
 
277
  }
201
278
 
202
 
  buffer.append("CREATE DATABASE ");
 
279
  buffer->length(0);
 
280
  buffer->free();
 
281
  buffer->set_charset(system_charset_info);
 
282
  buffer->append(STRING_WITH_LEN("CREATE DATABASE "));
203
283
 
204
284
  if (if_not_exists)
205
 
    buffer.append("IF NOT EXISTS ");
206
 
 
207
 
  buffer.append("`");
208
 
  buffer.append(schema.name());
209
 
  buffer.append("`");
210
 
 
211
 
  if (schema.has_collation())
 
285
    buffer->append(STRING_WITH_LEN("IF NOT EXISTS "));
 
286
 
 
287
  buffer->append_identifier(dbname, strlen(dbname));
 
288
 
 
289
  if (schema.has_collation() && strcmp(schema.collation().c_str(),
 
290
                                       default_charset_info->name))
212
291
  {
213
 
    buffer.append(" COLLATE = ");
214
 
    buffer.append(schema.collation());
 
292
    buffer->append(" COLLATE = ");
 
293
    buffer->append(schema.collation().c_str());
215
294
  }
216
295
 
217
 
  return true;
 
296
  return false;
218
297
}
219
298
 
220
 
bool mysqld_show_create_db(Session &session, SchemaIdentifier &schema_identifier, bool if_not_exists)
 
299
bool mysqld_show_create_db(Session *session, char *dbname, bool if_not_exists)
221
300
{
222
 
  message::Schema schema_message;
223
 
  string buffer;
224
 
 
225
 
  if (not plugin::StorageEngine::getSchemaDefinition(schema_identifier, schema_message))
226
 
  {
227
 
    /*
228
 
      This assumes that the only reason for which store_db_create_info()
229
 
      can fail is incorrect database name (which is the case now).
230
 
    */
231
 
    my_error(ER_BAD_DB_ERROR, MYF(0), schema_identifier.getSQLPath().c_str());
232
 
    return true;
233
 
  }
234
 
 
235
 
  if (not store_db_create_info(schema_identifier, buffer, if_not_exists))
236
 
  {
237
 
    /*
238
 
      This assumes that the only reason for which store_db_create_info()
239
 
      can fail is incorrect database name (which is the case now).
240
 
    */
241
 
    my_error(ER_BAD_DB_ERROR, MYF(0), schema_identifier.getSQLPath().c_str());
 
301
  char buff[2048];
 
302
  String buffer(buff, sizeof(buff), system_charset_info);
 
303
 
 
304
  if (store_db_create_info(dbname, &buffer, if_not_exists))
 
305
  {
 
306
    /*
 
307
      This assumes that the only reason for which store_db_create_info()
 
308
      can fail is incorrect database name (which is the case now).
 
309
    */
 
310
    my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
242
311
    return true;
243
312
  }
244
313
 
246
315
  field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
247
316
  field_list.push_back(new Item_empty_string("Create Database",1024));
248
317
 
249
 
  if (session.client->sendFields(&field_list))
250
 
    return true;
251
 
 
252
 
  session.client->store(schema_message.name());
253
 
  session.client->store(buffer);
254
 
 
255
 
  if (session.client->flush())
256
 
    return true;
257
 
 
258
 
  session.my_eof();
259
 
 
 
318
  if (session->client->sendFields(&field_list))
 
319
    return true;
 
320
 
 
321
  session->client->store(dbname, strlen(dbname));
 
322
  session->client->store(buffer.ptr(), buffer.length());
 
323
 
 
324
  if (session->client->flush())
 
325
    return true;
 
326
  session->my_eof();
260
327
  return false;
261
328
}
262
329
 
415
482
 
416
483
    if (field->has_charset())
417
484
    {
 
485
      if (field->charset() != share->table_charset)
 
486
      {
 
487
        packet->append(STRING_WITH_LEN(" CHARACTER SET "));
 
488
        packet->append(field->charset()->csname);
 
489
      }
 
490
 
418
491
      /*
419
492
        For string types dump collation name only if
420
493
        collation is not primary for the given charset
601
674
      table->s->getKeyBlockSize() != key_info->block_size)
602
675
  {
603
676
    packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
604
 
    end= internal::int64_t10_to_str(key_info->block_size, buff, 10);
 
677
    end= int64_t10_to_str(key_info->block_size, buff, 10);
605
678
    packet->append(buff, (uint32_t) (end - buff));
606
679
  }
607
680
 
621
694
  returns for each thread: thread id, user, host, db, command, info
622
695
****************************************************************************/
623
696
 
624
 
class thread_info
625
 
{
626
 
  thread_info();
 
697
class thread_info :public ilink {
627
698
public:
628
 
  uint64_t thread_id;
 
699
  static void *operator new(size_t size)
 
700
  {
 
701
    return (void*) sql_alloc((uint32_t) size);
 
702
  }
 
703
  static void operator delete(void *, size_t)
 
704
  { TRASH(ptr, size); }
 
705
 
 
706
  my_thread_id thread_id;
629
707
  time_t start_time;
630
708
  uint32_t   command;
631
 
  string user;
632
 
  string host;
633
 
  string db;
634
 
  string proc_info;
635
 
  string state_info;
636
 
  string query;
637
 
  thread_info(uint64_t thread_id_arg,
638
 
              time_t start_time_arg,
639
 
              uint32_t command_arg,
640
 
              const string &user_arg,
641
 
              const string &host_arg,
642
 
              const string &db_arg,
643
 
              const string &proc_info_arg,
644
 
              const string &state_info_arg,
645
 
              const string &query_arg)
646
 
    : thread_id(thread_id_arg), start_time(start_time_arg), command(command_arg),
647
 
      user(user_arg), host(host_arg), db(db_arg), proc_info(proc_info_arg),
648
 
      state_info(state_info_arg), query(query_arg)
649
 
  {}
 
709
  const char *user,*host,*db,*proc_info,*state_info;
 
710
  char *query;
650
711
};
651
712
 
 
713
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
 
714
template class I_List<thread_info>;
 
715
#endif
 
716
 
 
717
void mysqld_list_processes(Session *session,const char *user, bool)
 
718
{
 
719
  Item *field;
 
720
  List<Item> field_list;
 
721
  I_List<thread_info> thread_infos;
 
722
 
 
723
  field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
 
724
  field_list.push_back(new Item_empty_string("User",16));
 
725
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
 
726
  field_list.push_back(field=new Item_empty_string("db",NAME_CHAR_LEN));
 
727
  field->maybe_null= true;
 
728
  field_list.push_back(new Item_empty_string("Command",16));
 
729
  field_list.push_back(new Item_return_int("Time",7, DRIZZLE_TYPE_LONG));
 
730
  field_list.push_back(field=new Item_empty_string("State",30));
 
731
  field->maybe_null= true;
 
732
  field_list.push_back(field=new Item_empty_string("Info", PROCESS_LIST_WIDTH));
 
733
  field->maybe_null= true;
 
734
  if (session->client->sendFields(&field_list))
 
735
    return;
 
736
 
 
737
  pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
 
738
  if (!session->killed)
 
739
  {
 
740
    Session *tmp;
 
741
    for( vector<Session*>::iterator it= session_list.begin(); it != session_list.end(); ++it )
 
742
    {
 
743
      tmp= *it;
 
744
      Security_context *tmp_sctx= &tmp->security_ctx;
 
745
      struct st_my_thread_var *mysys_var;
 
746
      if (tmp->client->isConnected() && (!user || (tmp_sctx->user.c_str() && !strcmp(tmp_sctx->user.c_str(), user))))
 
747
      {
 
748
        thread_info *session_info= new thread_info;
 
749
 
 
750
        session_info->thread_id=tmp->thread_id;
 
751
        session_info->user= session->strdup(tmp_sctx->user.c_str() ? tmp_sctx->user.c_str() : "unauthenticated user");
 
752
        session_info->host= session->strdup(tmp_sctx->ip.c_str());
 
753
        if ((session_info->db= tmp->db.c_str()))             // Safe test
 
754
          session_info->db=session->strdup(session_info->db);
 
755
        session_info->command=(int) tmp->command;
 
756
        if ((mysys_var= tmp->mysys_var))
 
757
          pthread_mutex_lock(&mysys_var->mutex);
 
758
 
 
759
        if (tmp->killed == Session::KILL_CONNECTION)
 
760
          session_info->proc_info= (char*) "Killed";
 
761
        else
 
762
          session_info->proc_info= command_name[session_info->command].str;
 
763
 
 
764
        session_info->state_info= (char*) (tmp->client->isWriting() ?
 
765
                                           "Writing to net" :
 
766
                                           tmp->client->isReading() ?
 
767
                                           (session_info->command == COM_SLEEP ?
 
768
                                            NULL : "Reading from net") :
 
769
                                       tmp->get_proc_info() ? tmp->get_proc_info() :
 
770
                                       tmp->mysys_var &&
 
771
                                       tmp->mysys_var->current_cond ?
 
772
                                       "Waiting on cond" : NULL);
 
773
        if (mysys_var)
 
774
          pthread_mutex_unlock(&mysys_var->mutex);
 
775
 
 
776
        session_info->start_time= tmp->start_time;
 
777
        session_info->query= NULL;
 
778
        if (tmp->process_list_info[0])
 
779
          session_info->query= session->strdup(tmp->process_list_info);
 
780
        thread_infos.append(session_info);
 
781
      }
 
782
    }
 
783
  }
 
784
  pthread_mutex_unlock(&LOCK_thread_count);
 
785
 
 
786
  thread_info *session_info;
 
787
  time_t now= time(NULL);
 
788
  while ((session_info=thread_infos.get()))
 
789
  {
 
790
    session->client->store((uint64_t) session_info->thread_id);
 
791
    session->client->store(session_info->user);
 
792
    session->client->store(session_info->host);
 
793
    session->client->store(session_info->db);
 
794
    session->client->store(session_info->proc_info);
 
795
 
 
796
    if (session_info->start_time)
 
797
      session->client->store((uint32_t) (now - session_info->start_time));
 
798
    else
 
799
      session->client->store();
 
800
 
 
801
    session->client->store(session_info->state_info);
 
802
    session->client->store(session_info->query);
 
803
 
 
804
    if (session->client->flush())
 
805
      break;
 
806
  }
 
807
  session->my_eof();
 
808
  return;
 
809
}
 
810
 
652
811
/*****************************************************************************
653
812
  Status functions
654
813
*****************************************************************************/
655
814
 
656
 
static vector<drizzle_show_var *> all_status_vars;
657
 
static vector<drizzle_show_var *> com_status_vars;
 
815
static vector<SHOW_VAR *> all_status_vars;
658
816
static bool status_vars_inited= 0;
659
817
static int show_var_cmp(const void *var1, const void *var2)
660
818
{
661
 
  return strcmp(((drizzle_show_var*)var1)->name, ((drizzle_show_var*)var2)->name);
 
819
  return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
662
820
}
663
821
 
664
822
class show_var_cmp_functor
665
823
{
666
824
  public:
667
825
  show_var_cmp_functor() { }
668
 
  inline bool operator()(const drizzle_show_var *var1, const drizzle_show_var *var2) const
 
826
  inline bool operator()(const SHOW_VAR *var1, const SHOW_VAR *var2) const
669
827
  {
670
828
    int val= strcmp(var1->name, var2->name);
671
829
    return (val < 0);
676
834
{
677
835
  public:
678
836
  show_var_remove_if() { }
679
 
  inline bool operator()(const drizzle_show_var *curr) const
 
837
  inline bool operator()(const SHOW_VAR *curr) const
680
838
  {
681
839
    return (curr->type == SHOW_UNDEF);
682
840
  }
683
841
};
684
842
 
685
 
drizzle_show_var *getFrontOfStatusVars()
 
843
SHOW_VAR *getFrontOfStatusVars()
686
844
{
687
845
  return all_status_vars.front();
688
846
}
689
847
 
690
 
drizzle_show_var *getCommandStatusVars()
691
 
{
692
 
  return com_status_vars.front();
693
 
}
694
 
 
695
848
/*
696
 
  Adds an array of drizzle_show_var entries to the output of SHOW STATUS
 
849
  Adds an array of SHOW_VAR entries to the output of SHOW STATUS
697
850
 
698
851
  SYNOPSIS
699
 
    add_status_vars(drizzle_show_var *list)
700
 
    list - an array of drizzle_show_var entries to add to all_status_vars
 
852
    add_status_vars(SHOW_VAR *list)
 
853
    list - an array of SHOW_VAR entries to add to all_status_vars
701
854
           the last entry must be {0,0,SHOW_UNDEF}
702
855
 
703
856
  NOTE
709
862
    init_status_vars(), it assumes "startup mode" - neither concurrent access
710
863
    to the array nor SHOW STATUS are possible (thus it skips locks and qsort)
711
864
*/
712
 
int add_status_vars(drizzle_show_var *list)
 
865
int add_status_vars(SHOW_VAR *list)
713
866
{
714
867
  int res= 0;
715
868
  if (status_vars_inited)
724
877
  return res;
725
878
}
726
879
 
727
 
int add_com_status_vars(drizzle_show_var *list)
728
 
{
729
 
  int res= 0;
730
 
 
731
 
  while (list->name)
732
 
    com_status_vars.insert(com_status_vars.begin(), list++);
733
 
  if (status_vars_inited)
734
 
    sort(com_status_vars.begin(), com_status_vars.end(),
735
 
         show_var_cmp_functor());
736
 
 
737
 
  return res;
738
 
}
739
 
 
740
880
/*
741
881
  Make all_status_vars[] usable for SHOW STATUS
742
882
 
750
890
  status_vars_inited= 1;
751
891
  sort(all_status_vars.begin(), all_status_vars.end(),
752
892
       show_var_cmp_functor());
753
 
  sort(com_status_vars.begin(), com_status_vars.end(),
754
 
       show_var_cmp_functor());
755
893
}
756
894
 
757
895
void reset_status_vars()
758
896
{
759
 
  vector<drizzle_show_var *>::iterator p;
760
 
 
761
 
  p= all_status_vars.begin();
 
897
  vector<SHOW_VAR *>::iterator p= all_status_vars.begin();
762
898
  while (p != all_status_vars.end())
763
899
  {
764
900
    /* Note that SHOW_LONG_NOFLUSH variables are not reset */
766
902
      (*p)->value= 0;
767
903
    ++p;
768
904
  }
769
 
 
770
 
  p= com_status_vars.begin();
771
 
  while (p != com_status_vars.end())
772
 
  {
773
 
    /* Note that SHOW_LONG_NOFLUSH variables are not reset */
774
 
    if ((*p)->type == SHOW_LONG)
775
 
      (*p)->value= 0;
776
 
    ++p;
777
 
  }
778
905
}
779
906
 
780
907
/*
789
916
void free_status_vars()
790
917
{
791
918
  all_status_vars.clear();
792
 
  com_status_vars.clear();
793
919
}
794
920
 
795
921
/*
796
 
  Removes an array of drizzle_show_var entries from the output of SHOW STATUS
 
922
  Removes an array of SHOW_VAR entries from the output of SHOW STATUS
797
923
 
798
924
  SYNOPSIS
799
 
    remove_status_vars(drizzle_show_var *list)
800
 
    list - an array of drizzle_show_var entries to remove to all_status_vars
 
925
    remove_status_vars(SHOW_VAR *list)
 
926
    list - an array of SHOW_VAR entries to remove to all_status_vars
801
927
           the last entry must be {0,0,SHOW_UNDEF}
802
928
 
803
929
  NOTE
806
932
    initialization in the mysqld startup.
807
933
*/
808
934
 
809
 
void remove_status_vars(drizzle_show_var *list)
 
935
void remove_status_vars(SHOW_VAR *list)
810
936
{
811
937
  if (status_vars_inited)
812
938
  {
813
939
    pthread_mutex_lock(&LOCK_status);
814
 
    drizzle_show_var *all= all_status_vars.front();
 
940
    SHOW_VAR *all= all_status_vars.front();
815
941
    int a= 0, b= all_status_vars.size(), c= (a+b)/2;
816
942
 
817
943
    for (; list->name; list++)
838
964
  }
839
965
  else
840
966
  {
841
 
    drizzle_show_var *all= all_status_vars.front();
 
967
    SHOW_VAR *all= all_status_vars.front();
842
968
    uint32_t i;
843
969
    for (; list->name; list++)
844
970
    {
859
985
 
860
986
/* collect status for all running threads */
861
987
 
862
 
void calc_sum_of_all_status(system_status_var *to)
 
988
void calc_sum_of_all_status(STATUS_VAR *to)
863
989
{
864
990
  /* Ensure that thread id not killed during loop */
865
991
  pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
868
994
  *to= global_status_var;
869
995
 
870
996
  /* Add to this status from existing threads */
871
 
  for(SessionList::iterator it= getSessionList().begin(); it != getSessionList().end(); ++it )
 
997
  for( vector<Session*>::iterator it= session_list.begin(); it != session_list.end(); ++it )
872
998
  {
873
999
    add_to_status(to, &((*it)->status_var));
874
1000
  }
877
1003
  return;
878
1004
}
879
1005
 
880
 
} /* namespace drizzled */
 
1006
 
 
1007
static int make_table_list(Session *session, Select_Lex *sel,
 
1008
                           LEX_STRING *db_name, LEX_STRING *table_name)
 
1009
{
 
1010
  Table_ident *table_ident;
 
1011
  table_ident= new Table_ident(*db_name, *table_name);
 
1012
  sel->init_query();
 
1013
  if (! sel->add_table_to_list(session, table_ident, 0, 0, TL_READ))
 
1014
    return 1;
 
1015
  return 0;
 
1016
}
 
1017
 
 
1018
 
 
1019
/**
 
1020
  @brief    Get lookup value from the part of 'WHERE' condition
 
1021
 
 
1022
  @details This function gets lookup value from
 
1023
           the part of 'WHERE' condition if it's possible and
 
1024
           fill appropriate lookup_field_vals struct field
 
1025
           with this value.
 
1026
 
 
1027
  @param[in]      session                   thread Cursor
 
1028
  @param[in]      item_func             part of WHERE condition
 
1029
  @param[in]      table                 I_S table
 
1030
  @param[in, out] lookup_field_vals     Struct which holds lookup values
 
1031
 
 
1032
  @return
 
1033
    0             success
 
1034
    1             error, there can be no matching records for the condition
 
1035
*/
 
1036
 
 
1037
static bool get_lookup_value(Session *session, Item_func *item_func,
 
1038
                             TableList *table,
 
1039
                             LOOKUP_FIELD_VALUES *lookup_field_vals,
 
1040
                             plugin::InfoSchemaTable *schema_table)
 
1041
{
 
1042
  const char *field_name1= schema_table->getFirstColumnIndex() >= 0 ?
 
1043
    schema_table->getColumnName(schema_table->getFirstColumnIndex()).c_str() : "";
 
1044
  const char *field_name2= schema_table->getSecondColumnIndex() >= 0 ?
 
1045
    schema_table->getColumnName(schema_table->getSecondColumnIndex()).c_str() : "";
 
1046
 
 
1047
  if (item_func->functype() == Item_func::EQ_FUNC ||
 
1048
      item_func->functype() == Item_func::EQUAL_FUNC)
 
1049
  {
 
1050
    int idx_field, idx_val;
 
1051
    char tmp[MAX_FIELD_WIDTH];
 
1052
    String *tmp_str, str_buff(tmp, sizeof(tmp), system_charset_info);
 
1053
    Item_field *item_field;
 
1054
    const CHARSET_INFO * const cs= system_charset_info;
 
1055
 
 
1056
    if (item_func->arguments()[0]->type() == Item::FIELD_ITEM &&
 
1057
        item_func->arguments()[1]->const_item())
 
1058
    {
 
1059
      idx_field= 0;
 
1060
      idx_val= 1;
 
1061
    }
 
1062
    else if (item_func->arguments()[1]->type() == Item::FIELD_ITEM &&
 
1063
             item_func->arguments()[0]->const_item())
 
1064
    {
 
1065
      idx_field= 1;
 
1066
      idx_val= 0;
 
1067
    }
 
1068
    else
 
1069
      return 0;
 
1070
 
 
1071
    item_field= (Item_field*) item_func->arguments()[idx_field];
 
1072
    if (table->table != item_field->field->table)
 
1073
      return 0;
 
1074
    tmp_str= item_func->arguments()[idx_val]->val_str(&str_buff);
 
1075
 
 
1076
    /* impossible value */
 
1077
    if (!tmp_str)
 
1078
      return 1;
 
1079
 
 
1080
    /* Lookup value is database name */
 
1081
    if (!cs->coll->strnncollsp(cs, (unsigned char *) field_name1, strlen(field_name1),
 
1082
                               (unsigned char *) item_field->field_name,
 
1083
                               strlen(item_field->field_name), 0))
 
1084
    {
 
1085
      session->make_lex_string(&lookup_field_vals->db_value, tmp_str->ptr(),
 
1086
                           tmp_str->length(), false);
 
1087
    }
 
1088
    /* Lookup value is table name */
 
1089
    else if (!cs->coll->strnncollsp(cs, (unsigned char *) field_name2,
 
1090
                                    strlen(field_name2),
 
1091
                                    (unsigned char *) item_field->field_name,
 
1092
                                    strlen(item_field->field_name), 0))
 
1093
    {
 
1094
      session->make_lex_string(&lookup_field_vals->table_value, tmp_str->ptr(),
 
1095
                           tmp_str->length(), false);
 
1096
    }
 
1097
  }
 
1098
  return 0;
 
1099
}
 
1100
 
 
1101
 
 
1102
/**
 
1103
  @brief    Calculates lookup values from 'WHERE' condition
 
1104
 
 
1105
  @details This function calculates lookup value(database name, table name)
 
1106
           from 'WHERE' condition if it's possible and
 
1107
           fill lookup_field_vals struct fields with these values.
 
1108
 
 
1109
  @param[in]      session                   thread Cursor
 
1110
  @param[in]      cond                  WHERE condition
 
1111
  @param[in]      table                 I_S table
 
1112
  @param[in, out] lookup_field_vals     Struct which holds lookup values
 
1113
 
 
1114
  @return
 
1115
    0             success
 
1116
    1             error, there can be no matching records for the condition
 
1117
*/
 
1118
 
 
1119
bool calc_lookup_values_from_cond(Session *session, COND *cond, TableList *table,
 
1120
                                  LOOKUP_FIELD_VALUES *lookup_field_vals,
 
1121
                                  plugin::InfoSchemaTable *schema_table)
 
1122
{
 
1123
  if (!cond)
 
1124
    return 0;
 
1125
 
 
1126
  if (cond->type() == Item::COND_ITEM)
 
1127
  {
 
1128
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
 
1129
    {
 
1130
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
 
1131
      Item *item;
 
1132
      while ((item= li++))
 
1133
      {
 
1134
        if (item->type() == Item::FUNC_ITEM)
 
1135
        {
 
1136
          if (get_lookup_value(session, (Item_func*)item, table, lookup_field_vals, schema_table))
 
1137
            return 1;
 
1138
        }
 
1139
        else
 
1140
        {
 
1141
          if (calc_lookup_values_from_cond(session, item, table, lookup_field_vals, schema_table))
 
1142
            return 1;
 
1143
        }
 
1144
      }
 
1145
    }
 
1146
    return 0;
 
1147
  }
 
1148
  else if (cond->type() == Item::FUNC_ITEM &&
 
1149
           get_lookup_value(session, (Item_func*) cond, table, lookup_field_vals, schema_table))
 
1150
    return 1;
 
1151
  return 0;
 
1152
}
 
1153
 
 
1154
 
 
1155
static bool uses_only_table_name_fields(Item *item, Table *table, plugin::InfoSchemaTable *schema_table)
 
1156
{
 
1157
  if (item->type() == Item::FUNC_ITEM)
 
1158
  {
 
1159
    Item_func *item_func= (Item_func*)item;
 
1160
    for (uint32_t i=0; i<item_func->argument_count(); i++)
 
1161
    {
 
1162
      if (! uses_only_table_name_fields(item_func->arguments()[i], table, schema_table))
 
1163
        return 0;
 
1164
    }
 
1165
  }
 
1166
  else if (item->type() == Item::FIELD_ITEM)
 
1167
  {
 
1168
    Item_field *item_field= (Item_field*)item;
 
1169
    const CHARSET_INFO * const cs= system_charset_info;
 
1170
    const char *field_name1= schema_table->getFirstColumnIndex() >= 0 ?
 
1171
      schema_table->getColumnName(schema_table->getFirstColumnIndex()).c_str() : "";
 
1172
    const char *field_name2= schema_table->getSecondColumnIndex() >= 0 ?
 
1173
      schema_table->getColumnName(schema_table->getSecondColumnIndex()).c_str() : "";
 
1174
    if (table != item_field->field->table ||
 
1175
        (cs->coll->strnncollsp(cs, (unsigned char *) field_name1, strlen(field_name1),
 
1176
                               (unsigned char *) item_field->field_name,
 
1177
                               strlen(item_field->field_name), 0) &&
 
1178
         cs->coll->strnncollsp(cs, (unsigned char *) field_name2, strlen(field_name2),
 
1179
                               (unsigned char *) item_field->field_name,
 
1180
                               strlen(item_field->field_name), 0)))
 
1181
      return 0;
 
1182
  }
 
1183
  else if (item->type() == Item::REF_ITEM)
 
1184
    return uses_only_table_name_fields(item->real_item(), table, schema_table);
 
1185
 
 
1186
  if (item->type() == Item::SUBSELECT_ITEM && !item->const_item())
 
1187
    return 0;
 
1188
 
 
1189
  return 1;
 
1190
}
 
1191
 
 
1192
 
 
1193
static COND * make_cond_for_info_schema(COND *cond, Table *table, plugin::InfoSchemaTable *schema_table)
 
1194
{
 
1195
  if (!cond)
 
1196
    return (COND*) 0;
 
1197
  if (cond->type() == Item::COND_ITEM)
 
1198
  {
 
1199
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
 
1200
    {
 
1201
      /* Create new top level AND item */
 
1202
      Item_cond_and *new_cond=new Item_cond_and;
 
1203
      if (!new_cond)
 
1204
        return (COND*) 0;
 
1205
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
 
1206
      Item *item;
 
1207
      while ((item=li++))
 
1208
      {
 
1209
        Item *fix= make_cond_for_info_schema(item, table, schema_table);
 
1210
        if (fix)
 
1211
          new_cond->argument_list()->push_back(fix);
 
1212
      }
 
1213
      switch (new_cond->argument_list()->elements) {
 
1214
        case 0:
 
1215
          return (COND*) 0;
 
1216
        case 1:
 
1217
          return new_cond->argument_list()->head();
 
1218
        default:
 
1219
          new_cond->quick_fix_field();
 
1220
          return new_cond;
 
1221
      }
 
1222
    }
 
1223
    else
 
1224
    {                                           // Or list
 
1225
      Item_cond_or *new_cond=new Item_cond_or;
 
1226
      if (!new_cond)
 
1227
        return (COND*) 0;
 
1228
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
 
1229
      Item *item;
 
1230
      while ((item=li++))
 
1231
      {
 
1232
        Item *fix=make_cond_for_info_schema(item, table, schema_table);
 
1233
        if (!fix)
 
1234
          return (COND*) 0;
 
1235
        new_cond->argument_list()->push_back(fix);
 
1236
      }
 
1237
      new_cond->quick_fix_field();
 
1238
      new_cond->top_level_item();
 
1239
      return new_cond;
 
1240
    }
 
1241
  }
 
1242
 
 
1243
  if (! uses_only_table_name_fields(cond, table, schema_table))
 
1244
    return (COND*) 0;
 
1245
  return cond;
 
1246
}
 
1247
 
 
1248
 
 
1249
/**
 
1250
  @brief   Calculate lookup values(database name, table name)
 
1251
 
 
1252
  @details This function calculates lookup values(database name, table name)
 
1253
           from 'WHERE' condition or wild values (for 'SHOW' commands only)
 
1254
           from LEX struct and fill lookup_field_vals struct field
 
1255
           with these values.
 
1256
 
 
1257
  @param[in]      session                   thread Cursor
 
1258
  @param[in]      cond                  WHERE condition
 
1259
  @param[in]      tables                I_S table
 
1260
  @param[in, out] lookup_field_values   Struct which holds lookup values
 
1261
 
 
1262
  @return
 
1263
    0             success
 
1264
    1             error, there can be no matching records for the condition
 
1265
*/
 
1266
 
 
1267
bool get_lookup_field_values(Session *session, COND *cond, TableList *tables,
 
1268
                             LOOKUP_FIELD_VALUES *lookup_field_values,
 
1269
                             plugin::InfoSchemaTable *schema_table)
 
1270
{
 
1271
  LEX *lex= session->lex;
 
1272
  const char *wild= lex->wild ? lex->wild->ptr() : NULL;
 
1273
  memset(lookup_field_values, 0, sizeof(LOOKUP_FIELD_VALUES));
 
1274
  switch (lex->sql_command) {
 
1275
  case SQLCOM_SHOW_DATABASES:
 
1276
    if (wild)
 
1277
    {
 
1278
      lookup_field_values->db_value.str= (char*) wild;
 
1279
      lookup_field_values->db_value.length= strlen(wild);
 
1280
      lookup_field_values->wild_db_value= 1;
 
1281
    }
 
1282
    return 0;
 
1283
  case SQLCOM_SHOW_TABLES:
 
1284
  case SQLCOM_SHOW_TABLE_STATUS:
 
1285
    lookup_field_values->db_value.str= lex->select_lex.db;
 
1286
    lookup_field_values->db_value.length=strlen(lex->select_lex.db);
 
1287
    if (wild)
 
1288
    {
 
1289
      lookup_field_values->table_value.str= (char*)wild;
 
1290
      lookup_field_values->table_value.length= strlen(wild);
 
1291
      lookup_field_values->wild_table_value= 1;
 
1292
    }
 
1293
    return 0;
 
1294
  default:
 
1295
    /*
 
1296
      The "default" is for queries over I_S.
 
1297
      All previous cases handle SHOW commands.
 
1298
    */
 
1299
    return calc_lookup_values_from_cond(session, cond, tables, lookup_field_values, schema_table);
 
1300
  }
 
1301
}
 
1302
 
 
1303
 
 
1304
/**
 
1305
 * Function used for sorting with std::sort within make_db_list.
 
1306
 *
 
1307
 * @returns true if a < b, false otherwise
 
1308
 */
 
1309
 
 
1310
static bool lex_string_sort(const LEX_STRING *a, const LEX_STRING *b)
 
1311
{
 
1312
  return (strcmp(a->str, b->str) < 0);
 
1313
}
 
1314
 
 
1315
 
 
1316
/**
 
1317
 * @brief
 
1318
 *   Create db names list. Information schema name always is first in list
 
1319
 *
 
1320
 * @param[in]  session          Thread Cursor
 
1321
 * @param[out] files            List of db names
 
1322
 * @param[in]  wild             Wild string
 
1323
 * @param[in]  idx_field_vals   idx_field_vals->db_name contains db name or
 
1324
 *                              wild string
 
1325
 * @param[out] with_i_schema    Returns 1 if we added 'IS' name to list
 
1326
 *                              otherwise returns 0
 
1327
 *
 
1328
 * @retval 0   Success
 
1329
 * @retval 1   Error
 
1330
 */
 
1331
int make_db_list(Session *session, vector<LEX_STRING*> &files,
 
1332
                 LOOKUP_FIELD_VALUES *lookup_field_vals,
 
1333
                 bool *with_i_schema)
 
1334
{
 
1335
  LEX_STRING *i_s_name_copy= 0;
 
1336
  i_s_name_copy= session->make_lex_string(i_s_name_copy,
 
1337
                                      INFORMATION_SCHEMA_NAME.c_str(),
 
1338
                                      INFORMATION_SCHEMA_NAME.length(), true);
 
1339
  *with_i_schema= 0;
 
1340
  if (lookup_field_vals->wild_db_value)
 
1341
  {
 
1342
    /*
 
1343
      This part of code is only for SHOW DATABASES command.
 
1344
      idx_field_vals->db_value can be 0 when we don't use
 
1345
      LIKE clause (see also get_index_field_values() function)
 
1346
    */
 
1347
    if (!lookup_field_vals->db_value.str ||
 
1348
        !wild_case_compare(system_charset_info,
 
1349
                           INFORMATION_SCHEMA_NAME.c_str(),
 
1350
                           lookup_field_vals->db_value.str))
 
1351
    {
 
1352
      *with_i_schema= 1;
 
1353
      files.push_back(i_s_name_copy);
 
1354
    }
 
1355
 
 
1356
    if (find_schemas(session, files, drizzle_data_home,
 
1357
                     lookup_field_vals->db_value.str) == true)
 
1358
    {
 
1359
      return 1;
 
1360
    }
 
1361
 
 
1362
    sort(files.begin()+1, files.end(), lex_string_sort);
 
1363
    return 0;
 
1364
  }
 
1365
 
 
1366
 
 
1367
  /*
 
1368
    If we have db lookup vaule we just add it to list and
 
1369
    exit from the function
 
1370
  */
 
1371
  if (lookup_field_vals->db_value.str)
 
1372
  {
 
1373
    if (!my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.c_str(),
 
1374
                       lookup_field_vals->db_value.str))
 
1375
    {
 
1376
      *with_i_schema= 1;
 
1377
      files.push_back(i_s_name_copy);
 
1378
      return 0;
 
1379
    }
 
1380
 
 
1381
    files.push_back(&lookup_field_vals->db_value);
 
1382
    return 0;
 
1383
  }
 
1384
 
 
1385
  /*
 
1386
    Create list of existing databases. It is used in case
 
1387
    of select from information schema table
 
1388
  */
 
1389
  files.push_back(i_s_name_copy);
 
1390
 
 
1391
  *with_i_schema= 1;
 
1392
 
 
1393
  if (find_schemas(session, files, drizzle_data_home, NULL) == true)
 
1394
  {
 
1395
    return 1;
 
1396
  }
 
1397
 
 
1398
  sort(files.begin()+1, files.end(), lex_string_sort);
 
1399
  return 0;
 
1400
}
 
1401
 
 
1402
 
 
1403
/**
 
1404
  @brief          Create table names list
 
1405
 
 
1406
  @details        The function creates the list of table names in
 
1407
                  database
 
1408
 
 
1409
  @param[in]      session                   thread Cursor
 
1410
  @param[in]      table_names           List of table names in database
 
1411
  @param[in]      lex                   pointer to LEX struct
 
1412
  @param[in]      lookup_field_vals     pointer to LOOKUP_FIELD_VALUE struct
 
1413
  @param[in]      with_i_schema         true means that we add I_S tables to list
 
1414
  @param[in]      db_name               database name
 
1415
 
 
1416
  @return         Operation status
 
1417
    @retval       0           ok
 
1418
    @retval       1           fatal error
 
1419
    @retval       2           Not fatal error; Safe to ignore this cursor list
 
1420
*/
 
1421
 
 
1422
static int
 
1423
make_table_name_list(Session *session, vector<LEX_STRING*> &table_names,
 
1424
                     LOOKUP_FIELD_VALUES *lookup_field_vals,
 
1425
                     bool with_i_schema, LEX_STRING *db_name)
 
1426
{
 
1427
  char path[FN_REFLEN];
 
1428
  set<string> set_of_names;
 
1429
 
 
1430
  build_table_filename(path, sizeof(path), db_name->str, "", false);
 
1431
 
 
1432
  if (!lookup_field_vals->wild_table_value &&
 
1433
      lookup_field_vals->table_value.str)
 
1434
  {
 
1435
    if (with_i_schema)
 
1436
    {
 
1437
      if (plugin::InfoSchemaTable::getTable(lookup_field_vals->table_value.str))
 
1438
      {
 
1439
        table_names.push_back(&lookup_field_vals->table_value);
 
1440
      }
 
1441
    }
 
1442
    else
 
1443
    {
 
1444
      table_names.push_back(&lookup_field_vals->table_value);
 
1445
    }
 
1446
    return 0;
 
1447
  }
 
1448
 
 
1449
  string db(db_name->str);
 
1450
  plugin::StorageEngine::getTableNames(db, set_of_names);
 
1451
 
 
1452
  /*  
 
1453
    New I_S engine will make this go away, so ignore lack of foreach() usage.
 
1454
 
 
1455
    Notice how bad this design is... sure we created a set... but then we
 
1456
    are just pushing to another set. --
 
1457
    Also... callback design won't work, so we need to rewrite this to
 
1458
    feed (which means new I_S). For the moment we will not optimize this.
 
1459
 
 
1460
  */
 
1461
  for (set<string>::iterator it= set_of_names.begin(); it != set_of_names.end(); it++)
 
1462
  {
 
1463
    LEX_STRING *file_name= NULL;
 
1464
    
 
1465
    file_name= session->make_lex_string(file_name, (*it).c_str(),
 
1466
                                        (*it).length(), true);
 
1467
    const char* wild= lookup_field_vals->table_value.str;
 
1468
    if (wild && wild_compare((*it).c_str(), wild, 0))
 
1469
      continue;
 
1470
 
 
1471
    table_names.push_back(file_name);
 
1472
  }
 
1473
 
 
1474
  return 0;
 
1475
}
 
1476
 
 
1477
 
 
1478
/**
 
1479
  @brief          Fill I_S table for SHOW COLUMNS|INDEX commands
 
1480
 
 
1481
  @param[in]      session                      thread Cursor
 
1482
  @param[in]      tables                   TableList for I_S table
 
1483
  @param[in]      schema_table             pointer to I_S structure
 
1484
  @param[in]      open_tables_state_backup pointer to Open_tables_state object
 
1485
                                           which is used to save|restore original
 
1486
                                           status of variables related to
 
1487
                                           open tables state
 
1488
 
 
1489
  @return         Operation status
 
1490
    @retval       0           success
 
1491
    @retval       1           error
 
1492
*/
 
1493
 
 
1494
static int
 
1495
fill_schema_show_cols_or_idxs(Session *session, TableList *tables,
 
1496
                              plugin::InfoSchemaTable *schema_table,
 
1497
                              Open_tables_state *open_tables_state_backup)
 
1498
{
 
1499
  LEX *lex= session->lex;
 
1500
  bool res;
 
1501
  LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name;
 
1502
  enum_sql_command save_sql_command= lex->sql_command;
 
1503
  TableList *show_table_list= (TableList*) tables->schema_select_lex->
 
1504
    table_list.first;
 
1505
  Table *table= tables->table;
 
1506
  int error= 1;
 
1507
 
 
1508
  lex->all_selects_list= tables->schema_select_lex;
 
1509
  /*
 
1510
    Restore session->temporary_tables to be able to process
 
1511
    temporary tables(only for 'show index' & 'show columns').
 
1512
    This should be changed when processing of temporary tables for
 
1513
    I_S tables will be done.
 
1514
  */
 
1515
  session->temporary_tables= open_tables_state_backup->temporary_tables;
 
1516
  /*
 
1517
    Let us set fake sql_command so views won't try to merge
 
1518
    themselves into main statement. If we don't do this,
 
1519
    SELECT * from information_schema.xxxx will cause problems.
 
1520
    SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()'
 
1521
  */
 
1522
  lex->sql_command= SQLCOM_SHOW_FIELDS;
 
1523
  res= session->openTables(show_table_list, DRIZZLE_LOCK_IGNORE_FLUSH);
 
1524
  lex->sql_command= save_sql_command;
 
1525
  /*
 
1526
    get_all_tables() returns 1 on failure and 0 on success thus
 
1527
    return only these and not the result code of ::process_table()
 
1528
 
 
1529
    We should use show_table_list->alias instead of
 
1530
    show_table_list->table_name because table_name
 
1531
    could be changed during opening of I_S tables. It's safe
 
1532
    to use alias because alias contains original table name
 
1533
    in this case(this part of code is used only for
 
1534
    'show columns' & 'show statistics' commands).
 
1535
  */
 
1536
   table_name= session->make_lex_string(&tmp_lex_string1, show_table_list->alias,
 
1537
                                    strlen(show_table_list->alias), false);
 
1538
   db_name= session->make_lex_string(&tmp_lex_string, show_table_list->db,
 
1539
                                 show_table_list->db_length, false);
 
1540
 
 
1541
 
 
1542
   table->setWriteSet();
 
1543
   error= test(schema_table->processTable(session, show_table_list,
 
1544
                                          table, res, db_name,
 
1545
                                          table_name));
 
1546
   session->temporary_tables= 0;
 
1547
   session->close_tables_for_reopen(&show_table_list);
 
1548
 
 
1549
   return(error);
 
1550
}
 
1551
 
 
1552
 
 
1553
/**
 
1554
  @brief          Fill I_S table for SHOW Table NAMES commands
 
1555
 
 
1556
  @param[in]      session                      thread Cursor
 
1557
  @param[in]      table                    Table struct for I_S table
 
1558
  @param[in]      db_name                  database name
 
1559
  @param[in]      table_name               table name
 
1560
  @param[in]      with_i_schema            I_S table if true
 
1561
 
 
1562
  @return         Operation status
 
1563
    @retval       0           success
 
1564
    @retval       1           error
 
1565
*/
 
1566
 
 
1567
static int fill_schema_table_names(Session *session, Table *table,
 
1568
                                   LEX_STRING *db_name, LEX_STRING *table_name,
 
1569
                                   bool with_i_schema,
 
1570
                                   plugin::InfoSchemaTable *schema_table)
 
1571
{
 
1572
  if (with_i_schema)
 
1573
  {
 
1574
    table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
 
1575
                           system_charset_info);
 
1576
  }
 
1577
  else
 
1578
  {
 
1579
    char path[FN_REFLEN];
 
1580
    (void) build_table_filename(path, sizeof(path), db_name->str,
 
1581
                                table_name->str, false);
 
1582
 
 
1583
      table->field[3]->store(STRING_WITH_LEN("BASE Table"),
 
1584
                             system_charset_info);
 
1585
 
 
1586
    if (session->is_error() && session->main_da.sql_errno() == ER_NO_SUCH_TABLE)
 
1587
    {
 
1588
      session->clear_error();
 
1589
      return 0;
 
1590
    }
 
1591
  }
 
1592
  schema_table->addRow(table->record[0], table->s->reclength);
 
1593
  return 0;
 
1594
}
 
1595
 
 
1596
 
 
1597
/**
 
1598
  @brief          Fill I_S tables whose data are retrieved
 
1599
                  from frm files and storage engine
 
1600
 
 
1601
  @details        The information schema tables are internally represented as
 
1602
                  temporary tables that are filled at query execution time.
 
1603
                  Those I_S tables whose data are retrieved
 
1604
                  from frm files and storage engine are filled by the function
 
1605
                  plugin::InfoSchemaMethods::fillTable().
 
1606
 
 
1607
  @param[in]      session                      thread Cursor
 
1608
  @param[in]      tables                   I_S table
 
1609
 
 
1610
  @return         Operation status
 
1611
    @retval       0                        success
 
1612
    @retval       1                        error
 
1613
*/
 
1614
int plugin::InfoSchemaMethods::fillTable(Session *session, 
 
1615
                                         Table *table,
 
1616
                                         plugin::InfoSchemaTable *schema_table)
 
1617
{
 
1618
  LEX *lex= session->lex;
 
1619
  Select_Lex *old_all_select_lex= lex->all_selects_list;
 
1620
  enum_sql_command save_sql_command= lex->sql_command;
 
1621
  Select_Lex *lsel= table->pos_in_table_list->schema_select_lex;
 
1622
  Select_Lex sel;
 
1623
  LOOKUP_FIELD_VALUES lookup_field_vals;
 
1624
  bool with_i_schema;
 
1625
  vector<LEX_STRING*> db_names, table_names;
 
1626
  /* the WHERE clause */
 
1627
  COND *cond= table->reginfo.join_tab->select_cond;
 
1628
  COND *partial_cond= 0;
 
1629
  uint32_t derived_tables= lex->derived_tables;
 
1630
  int error= 1;
 
1631
  Open_tables_state open_tables_state_backup;
 
1632
  Query_tables_list query_tables_list_backup;
 
1633
  bool old_value= session->no_warnings_for_error;
 
1634
 
 
1635
  /*
 
1636
    We should not introduce deadlocks even if we already have some
 
1637
    tables open and locked, since we won't lock tables which we will
 
1638
    open and will ignore possible name-locks for these tables.
 
1639
  */
 
1640
  session->reset_n_backup_open_tables_state(&open_tables_state_backup);
 
1641
 
 
1642
  /*
 
1643
    this branch processes SHOW FIELDS, SHOW INDEXES commands.
 
1644
    see sql_parse.cc, prepare_schema_table() function where
 
1645
    this values are initialized
 
1646
  */
 
1647
  if (lsel && lsel->table_list.first)
 
1648
  {
 
1649
    error= fill_schema_show_cols_or_idxs(session, table->pos_in_table_list, schema_table,
 
1650
                                         &open_tables_state_backup);
 
1651
    goto err;
 
1652
  }
 
1653
 
 
1654
  if (get_lookup_field_values(session, 
 
1655
                              cond, 
 
1656
                              table->pos_in_table_list, 
 
1657
                              &lookup_field_vals,
 
1658
                              schema_table))
 
1659
  {
 
1660
    error= 0;
 
1661
    goto err;
 
1662
  }
 
1663
 
 
1664
  if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
 
1665
  {
 
1666
    /*
 
1667
      if lookup value is empty string then
 
1668
      it's impossible table name or db name
 
1669
    */
 
1670
    if ((lookup_field_vals.db_value.str && !lookup_field_vals.db_value.str[0]) ||
 
1671
        (lookup_field_vals.table_value.str && !lookup_field_vals.table_value.str[0]))
 
1672
    {
 
1673
      error= 0;
 
1674
      goto err;
 
1675
    }
 
1676
  }
 
1677
 
 
1678
  if (lookup_field_vals.db_value.length &&
 
1679
      !lookup_field_vals.wild_db_value)
 
1680
    table->pos_in_table_list->has_db_lookup_value= true;
 
1681
 
 
1682
  if (lookup_field_vals.table_value.length &&
 
1683
      !lookup_field_vals.wild_table_value)
 
1684
    table->pos_in_table_list->has_table_lookup_value= true;
 
1685
 
 
1686
  if (table->pos_in_table_list->has_db_lookup_value && 
 
1687
      table->pos_in_table_list->has_table_lookup_value)
 
1688
    partial_cond= 0;
 
1689
  else
 
1690
    partial_cond= make_cond_for_info_schema(cond, table, schema_table);
 
1691
 
 
1692
  if (lex->describe)
 
1693
  {
 
1694
    /* EXPLAIN SELECT */
 
1695
    error= 0;
 
1696
    goto err;
 
1697
  }
 
1698
 
 
1699
  table->setWriteSet();
 
1700
  if (make_db_list(session, db_names, &lookup_field_vals, &with_i_schema))
 
1701
    goto err;
 
1702
 
 
1703
  for (vector<LEX_STRING*>::iterator db_name= db_names.begin(); db_name != db_names.end(); ++db_name )
 
1704
  {
 
1705
    session->no_warnings_for_error= 1;
 
1706
    table_names.clear();
 
1707
    int res= make_table_name_list(session, table_names,
 
1708
                                  &lookup_field_vals,
 
1709
                                  with_i_schema, *db_name);
 
1710
 
 
1711
    if (res == 2)   /* Not fatal error, continue */
 
1712
      continue;
 
1713
 
 
1714
    if (res)
 
1715
      goto err;
 
1716
 
 
1717
    
 
1718
    for (vector<LEX_STRING*>::iterator table_name= table_names.begin(); table_name != table_names.end(); ++table_name)
 
1719
    {
 
1720
      table->restoreRecordAsDefault();
 
1721
      table->field[schema_table->getFirstColumnIndex()]->
 
1722
        store((*db_name)->str, (*db_name)->length, system_charset_info);
 
1723
      table->field[schema_table->getSecondColumnIndex()]->
 
1724
        store((*table_name)->str, (*table_name)->length, system_charset_info);
 
1725
 
 
1726
      if (!partial_cond || partial_cond->val_int())
 
1727
      {
 
1728
        /* SHOW Table NAMES command */
 
1729
        if (schema_table->getTableName().compare("TABLE_NAMES") == 0)
 
1730
        {
 
1731
          if (fill_schema_table_names(session, 
 
1732
                                      table, 
 
1733
                                      *db_name,
 
1734
                                      *table_name, 
 
1735
                                      with_i_schema,
 
1736
                                      schema_table))
 
1737
            continue;
 
1738
        }
 
1739
        else
 
1740
        {
 
1741
          LEX_STRING tmp_lex_string, orig_db_name;
 
1742
          /*
 
1743
            Set the parent lex of 'sel' because it is needed by
 
1744
            sel.init_query() which is called inside make_table_list.
 
1745
          */
 
1746
          session->no_warnings_for_error= 1;
 
1747
          sel.parent_lex= lex;
 
1748
          /* db_name can be changed in make_table_list() func */
 
1749
          if (! session->make_lex_string(&orig_db_name, 
 
1750
                                         (*db_name)->str,
 
1751
                                         (*db_name)->length, 
 
1752
                                         false))
 
1753
          {
 
1754
            goto err;
 
1755
          }
 
1756
 
 
1757
          if (make_table_list(session, &sel, *db_name, *table_name))
 
1758
            goto err;
 
1759
 
 
1760
          TableList *show_table_list= (TableList*) sel.table_list.first;
 
1761
          lex->all_selects_list= &sel;
 
1762
          lex->derived_tables= 0;
 
1763
          lex->sql_command= SQLCOM_SHOW_FIELDS;
 
1764
          show_table_list->i_s_requested_object=
 
1765
            schema_table->getRequestedObject();
 
1766
          res= session->openTables(show_table_list, DRIZZLE_LOCK_IGNORE_FLUSH);
 
1767
          lex->sql_command= save_sql_command;
 
1768
          /*
 
1769
            XXX->  show_table_list has a flag i_is_requested,
 
1770
            and when it's set, openTables()
 
1771
            can return an error without setting an error message
 
1772
            in Session, which is a hack. This is why we have to
 
1773
            check for res, then for session->is_error() only then
 
1774
            for session->main_da.sql_errno().
 
1775
          */
 
1776
          if (res && session->is_error() &&
 
1777
              session->main_da.sql_errno() == ER_NO_SUCH_TABLE)
 
1778
          {
 
1779
            /*
 
1780
              Hide error for not existing table.
 
1781
              This error can occur for example when we use
 
1782
              where condition with db name and table name and this
 
1783
              table does not exist.
 
1784
            */
 
1785
            res= 0;
 
1786
            session->clear_error();
 
1787
          }
 
1788
          else
 
1789
          {
 
1790
            /*
 
1791
              We should use show_table_list->alias instead of
 
1792
              show_table_list->table_name because table_name
 
1793
              could be changed during opening of I_S tables. It's safe
 
1794
              to use alias because alias contains original table name
 
1795
              in this case.
 
1796
            */
 
1797
            session->make_lex_string(&tmp_lex_string, show_table_list->alias,
 
1798
                                     strlen(show_table_list->alias), false);
 
1799
            res= schema_table->processTable(session, show_table_list, table,
 
1800
                                            res, &orig_db_name,
 
1801
                                            &tmp_lex_string);
 
1802
            session->close_tables_for_reopen(&show_table_list);
 
1803
          }
 
1804
          assert(!lex->query_tables_own_last);
 
1805
          if (res)
 
1806
            goto err;
 
1807
        }
 
1808
      }
 
1809
    }
 
1810
    /*
 
1811
      If we have information schema its always the first table and only
 
1812
      the first table. Reset for other tables.
 
1813
    */
 
1814
    with_i_schema= 0;
 
1815
  }
 
1816
 
 
1817
  error= 0;
 
1818
 
 
1819
err:
 
1820
  session->restore_backup_open_tables_state(&open_tables_state_backup);
 
1821
  lex->derived_tables= derived_tables;
 
1822
  lex->all_selects_list= old_all_select_lex;
 
1823
  lex->sql_command= save_sql_command;
 
1824
  session->no_warnings_for_error= old_value;
 
1825
  return(error);
 
1826
}
 
1827
 
 
1828
 
 
1829
/**
 
1830
  @brief    Store field characteristics into appropriate I_S table columns
 
1831
 
 
1832
  @param[in]      table             I_S table
 
1833
  @param[in]      field             processed field
 
1834
  @param[in]      cs                I_S table charset
 
1835
  @param[in]      offset            offset from beginning of table
 
1836
                                    to DATE_TYPE column in I_S table
 
1837
 
 
1838
  @return         void
 
1839
*/
 
1840
 
 
1841
static void store_column_type(Table *table, Field *field,
 
1842
                              const CHARSET_INFO * const cs,
 
1843
                              uint32_t offset)
 
1844
{
 
1845
  bool is_blob;
 
1846
  int decimals, field_length;
 
1847
  const char *tmp_buff;
 
1848
  char column_type_buff[MAX_FIELD_WIDTH];
 
1849
  String column_type(column_type_buff, sizeof(column_type_buff), cs);
 
1850
 
 
1851
  field->sql_type(column_type);
 
1852
  /* DTD_IDENTIFIER column */
 
1853
  table->field[offset + 7]->store(column_type.ptr(), column_type.length(), cs);
 
1854
  table->field[offset + 7]->set_notnull();
 
1855
  tmp_buff= strchr(column_type.ptr(), '(');
 
1856
  /* DATA_TYPE column */
 
1857
  table->field[offset]->store(column_type.ptr(),
 
1858
                         (tmp_buff ? tmp_buff - column_type.ptr() :
 
1859
                          column_type.length()), cs);
 
1860
  is_blob= (field->type() == DRIZZLE_TYPE_BLOB);
 
1861
  if (field->has_charset() || is_blob ||
 
1862
      field->real_type() == DRIZZLE_TYPE_VARCHAR)  // For varbinary type
 
1863
  {
 
1864
    uint32_t octet_max_length= field->max_display_length();
 
1865
    if (is_blob && octet_max_length != (uint32_t) 4294967295U)
 
1866
      octet_max_length /= field->charset()->mbmaxlen;
 
1867
    int64_t char_max_len= is_blob ?
 
1868
      (int64_t) octet_max_length / field->charset()->mbminlen :
 
1869
      (int64_t) octet_max_length / field->charset()->mbmaxlen;
 
1870
    /* CHARACTER_MAXIMUM_LENGTH column*/
 
1871
    table->field[offset + 1]->store(char_max_len, true);
 
1872
    table->field[offset + 1]->set_notnull();
 
1873
    /* CHARACTER_OCTET_LENGTH column */
 
1874
    table->field[offset + 2]->store((int64_t) octet_max_length, true);
 
1875
    table->field[offset + 2]->set_notnull();
 
1876
  }
 
1877
 
 
1878
  /*
 
1879
    Calculate field_length and decimals.
 
1880
    They are set to -1 if they should not be set (we should return NULL)
 
1881
  */
 
1882
 
 
1883
  decimals= field->decimals();
 
1884
  switch (field->type()) {
 
1885
  case DRIZZLE_TYPE_DECIMAL:
 
1886
    field_length= ((Field_decimal*) field)->precision;
 
1887
    break;
 
1888
  case DRIZZLE_TYPE_LONG:
 
1889
  case DRIZZLE_TYPE_LONGLONG:
 
1890
    field_length= field->max_display_length() - 1;
 
1891
    break;
 
1892
  case DRIZZLE_TYPE_DOUBLE:
 
1893
    field_length= field->field_length;
 
1894
    if (decimals == NOT_FIXED_DEC)
 
1895
      decimals= -1;                           // return NULL
 
1896
    break;
 
1897
  default:
 
1898
    field_length= decimals= -1;
 
1899
    break;
 
1900
  }
 
1901
 
 
1902
  /* NUMERIC_PRECISION column */
 
1903
  if (field_length >= 0)
 
1904
  {
 
1905
    table->field[offset + 3]->store((int64_t) field_length, true);
 
1906
    table->field[offset + 3]->set_notnull();
 
1907
  }
 
1908
  /* NUMERIC_SCALE column */
 
1909
  if (decimals >= 0)
 
1910
  {
 
1911
    table->field[offset + 4]->store((int64_t) decimals, true);
 
1912
    table->field[offset + 4]->set_notnull();
 
1913
  }
 
1914
  if (field->has_charset())
 
1915
  {
 
1916
    /* CHARACTER_SET_NAME column*/
 
1917
    tmp_buff= field->charset()->csname;
 
1918
    table->field[offset + 5]->store(tmp_buff, strlen(tmp_buff), cs);
 
1919
    table->field[offset + 5]->set_notnull();
 
1920
    /* COLLATION_NAME column */
 
1921
    tmp_buff= field->charset()->name;
 
1922
    table->field[offset + 6]->store(tmp_buff, strlen(tmp_buff), cs);
 
1923
    table->field[offset + 6]->set_notnull();
 
1924
  }
 
1925
}
 
1926
 
 
1927
 
 
1928
int plugin::InfoSchemaMethods::processTable(
 
1929
            plugin::InfoSchemaTable *store_table,
 
1930
            Session *session, 
 
1931
            TableList *tables,
 
1932
                                    Table *table, bool res,
 
1933
                                    LEX_STRING *db_name,
 
1934
                                    LEX_STRING *table_name)
 
1935
{
 
1936
  LEX *lex= session->lex;
 
1937
  const char *wild= lex->wild ? lex->wild->ptr() : NULL;
 
1938
  const CHARSET_INFO * const cs= system_charset_info;
 
1939
  Table *show_table;
 
1940
  TableShare *show_table_share;
 
1941
  Field **ptr, *field, *timestamp_field;
 
1942
  int count;
 
1943
 
 
1944
  if (res)
 
1945
  {
 
1946
    if (lex->sql_command != SQLCOM_SHOW_FIELDS)
 
1947
    {
 
1948
      /*
 
1949
        I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
 
1950
        rather than in SHOW COLUMNS
 
1951
      */
 
1952
      if (session->is_error())
 
1953
        push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
1954
                     session->main_da.sql_errno(), session->main_da.message());
 
1955
      session->clear_error();
 
1956
      res= 0;
 
1957
    }
 
1958
    return(res);
 
1959
  }
 
1960
 
 
1961
  show_table= tables->table;
 
1962
  show_table_share= show_table->s;
 
1963
  count= 0;
 
1964
 
 
1965
  ptr= show_table_share->field;
 
1966
  timestamp_field= show_table_share->timestamp_field;
 
1967
 
 
1968
  /* For the moment we just set everything to read */
 
1969
  if (!show_table->read_set)
 
1970
  {
 
1971
    show_table->def_read_set.setAll();
 
1972
    show_table->read_set= &show_table->def_read_set;
 
1973
  }
 
1974
  show_table->use_all_columns();               // Required for default
 
1975
 
 
1976
  for (; (field= *ptr) ; ptr++)
 
1977
  {
 
1978
    unsigned char *pos;
 
1979
    char tmp[MAX_FIELD_WIDTH];
 
1980
    String type(tmp,sizeof(tmp), system_charset_info);
 
1981
    char *end;
 
1982
 
 
1983
    /* to satisfy 'field->val_str' ASSERTs */
 
1984
    field->table= show_table;
 
1985
    show_table->in_use= session;
 
1986
 
 
1987
    if (wild && wild[0] &&
 
1988
        wild_case_compare(system_charset_info, field->field_name,wild))
 
1989
      continue;
 
1990
 
 
1991
    count++;
 
1992
    /* Get default row, with all NULL fields set to NULL */
 
1993
    table->restoreRecordAsDefault();
 
1994
 
 
1995
    table->field[1]->store(db_name->str, db_name->length, cs);
 
1996
    table->field[2]->store(table_name->str, table_name->length, cs);
 
1997
    table->field[3]->store(field->field_name, strlen(field->field_name),
 
1998
                           cs);
 
1999
    table->field[4]->store((int64_t) count, true);
 
2000
 
 
2001
    if (get_field_default_value(timestamp_field, field, &type, 0))
 
2002
    {
 
2003
      table->field[5]->store(type.ptr(), type.length(), cs);
 
2004
      table->field[5]->set_notnull();
 
2005
    }
 
2006
    pos=(unsigned char*) ((field->flags & NOT_NULL_FLAG) ?  "NO" : "YES");
 
2007
    table->field[6]->store((const char*) pos,
 
2008
                           strlen((const char*) pos), cs);
 
2009
    store_column_type(table, field, cs, 7);
 
2010
 
 
2011
    pos=(unsigned char*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
 
2012
                 (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
 
2013
                 (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
 
2014
    table->field[15]->store((const char*) pos,
 
2015
                            strlen((const char*) pos), cs);
 
2016
 
 
2017
    end= tmp;
 
2018
    if (field->unireg_check == Field::NEXT_NUMBER)
 
2019
      table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs);
 
2020
    if (timestamp_field == field &&
 
2021
        field->unireg_check != Field::TIMESTAMP_DN_FIELD)
 
2022
      table->field[16]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
 
2023
                              cs);
 
2024
    table->field[18]->store(field->comment.str, field->comment.length, cs);
 
2025
    {
 
2026
      enum column_format_type column_format= (enum column_format_type)
 
2027
        ((field->flags >> COLUMN_FORMAT_FLAGS) & COLUMN_FORMAT_MASK);
 
2028
      pos=(unsigned char*)"Default";
 
2029
      table->field[19]->store((const char*) pos,
 
2030
                              strlen((const char*) pos), cs);
 
2031
      pos=(unsigned char*)(column_format == COLUMN_FORMAT_TYPE_DEFAULT ? "Default" :
 
2032
                   column_format == COLUMN_FORMAT_TYPE_FIXED ? "Fixed" :
 
2033
                                                             "Dynamic");
 
2034
      table->field[20]->store((const char*) pos,
 
2035
                              strlen((const char*) pos), cs);
 
2036
    }
 
2037
    store_table->addRow(table->record[0], table->s->reclength);
 
2038
  }
 
2039
  return(0);
 
2040
}
 
2041
 
 
2042
 
 
2043
/*
 
2044
  For old SHOW compatibility. It is used when
 
2045
  old SHOW doesn't have generated column names
 
2046
  Make list of fields for SHOW
 
2047
 
 
2048
  SYNOPSIS
 
2049
    plugin::InfoSchemaMethods::oldFormat()
 
2050
    session                     thread Cursor
 
2051
    schema_table        pointer to 'schema_tables' element
 
2052
 
 
2053
  RETURN
 
2054
   1    error
 
2055
   0    success
 
2056
*/
 
2057
 
 
2058
int plugin::InfoSchemaMethods::oldFormat(Session *session, plugin::InfoSchemaTable *schema_table)
 
2059
  const
 
2060
{
 
2061
  Name_resolution_context *context= &session->lex->select_lex.context;
 
2062
  const plugin::InfoSchemaTable::Columns columns= schema_table->getColumns();
 
2063
  plugin::InfoSchemaTable::Columns::const_iterator iter= columns.begin();
 
2064
 
 
2065
  while (iter != columns.end())
 
2066
  {
 
2067
    const plugin::ColumnInfo *column= *iter;
 
2068
    if (column->getOldName().length() != 0)
 
2069
    {
 
2070
      Item_field *field= new Item_field(context,
 
2071
                                        NULL, NULL,
 
2072
                                        column->getName().c_str());
 
2073
      if (field)
 
2074
      {
 
2075
        field->set_name(column->getOldName().c_str(),
 
2076
                        column->getOldName().length(),
 
2077
                        system_charset_info);
 
2078
        if (session->add_item_to_list(field))
 
2079
          return 1;
 
2080
      }
 
2081
    }
 
2082
    ++iter;
 
2083
  }
 
2084
  return 0;
 
2085
}
 
2086
 
 
2087
 
 
2088
/*
 
2089
  Generate select from information_schema table
 
2090
 
 
2091
  SYNOPSIS
 
2092
    make_schema_select()
 
2093
    session                  thread Cursor
 
2094
    sel                  pointer to Select_Lex
 
2095
    schema_table_name    name of 'schema_tables' element
 
2096
 
 
2097
  RETURN
 
2098
    true on error
 
2099
*/
 
2100
 
 
2101
bool make_schema_select(Session *session, Select_Lex *sel,
 
2102
                        const string& schema_table_name)
 
2103
{
 
2104
  plugin::InfoSchemaTable *schema_table= plugin::InfoSchemaTable::getTable(schema_table_name.c_str());
 
2105
  LEX_STRING db, table;
 
2106
  /*
 
2107
     We have to make non const db_name & table_name
 
2108
     because of lower_case_table_names
 
2109
  */
 
2110
  session->make_lex_string(&db, INFORMATION_SCHEMA_NAME.c_str(),
 
2111
                       INFORMATION_SCHEMA_NAME.length(), 0);
 
2112
  session->make_lex_string(&table, schema_table->getTableName().c_str(),
 
2113
                           schema_table->getTableName().length(), 0);
 
2114
  if (schema_table->oldFormat(session, schema_table) ||   /* Handle old syntax */
 
2115
      ! sel->add_table_to_list(session, new Table_ident(db, table), 0, 0, TL_READ))
 
2116
  {
 
2117
    return true;
 
2118
  }
 
2119
  return false;
 
2120
}
 
2121