Drizzled Public API Documentation

sql_table.cc
1 /* Copyright (C) 2000-2004 MySQL AB
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /* drop and alter of tables */
17 
18 #include <config.h>
19 #include <plugin/myisam/myisam.h>
20 #include <drizzled/show.h>
21 #include <drizzled/error.h>
22 #include <drizzled/gettext.h>
23 #include <drizzled/data_home.h>
24 #include <drizzled/sql_parse.h>
25 #include <drizzled/sql_lex.h>
26 #include <drizzled/session.h>
27 #include <drizzled/sql_base.h>
28 #include <drizzled/lock.h>
29 #include <drizzled/item/int.h>
30 #include <drizzled/item/empty_string.h>
31 #include <drizzled/transaction_services.h>
32 #include <drizzled/transaction_services.h>
33 #include <drizzled/table_proto.h>
34 #include <drizzled/plugin/client.h>
35 #include <drizzled/identifier.h>
36 #include <drizzled/internal/m_string.h>
37 #include <drizzled/charset.h>
38 #include <drizzled/definition/cache.h>
39 #include <drizzled/system_variables.h>
40 #include <drizzled/statement/alter_table.h>
41 #include <drizzled/sql_table.h>
42 #include <drizzled/pthread_globals.h>
43 #include <drizzled/typelib.h>
44 #include <drizzled/plugin/storage_engine.h>
45 #include <drizzled/diagnostics_area.h>
46 #include <drizzled/open_tables_state.h>
47 #include <drizzled/table/cache.h>
48 #include <drizzled/create_field.h>
49 
50 #include <algorithm>
51 #include <sstream>
52 
53 #include <boost/unordered_set.hpp>
54 
55 using namespace std;
56 
57 namespace drizzled {
58 
59 bool is_primary_key(const char* name)
60 {
61  return strcmp(name, "PRIMARY") == 0;
62 }
63 
64 static bool check_if_keyname_exists(const char *name,KeyInfo *start, KeyInfo *end);
65 static const char *make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end);
66 static bool prepare_blob_field(Session *session, CreateField *sql_field);
67 
68 void set_table_default_charset(const identifier::Catalog &catalog, HA_CREATE_INFO *create_info, const char *db)
69 {
70  /*
71  If the table character set was not given explicitly,
72  let's fetch the database default character set and
73  apply it to the table.
74  */
75  if (not create_info->default_table_charset)
76  create_info->default_table_charset= plugin::StorageEngine::getSchemaCollation(identifier::Schema(catalog, str_ref(db)));
77 }
78 
79 /*
80  Execute the drop of a normal or temporary table
81 
82  SYNOPSIS
83  rm_table_part2()
84  session Thread Cursor
85  tables Tables to drop
86  if_exists If set, don't give an error if table doesn't exists.
87  In this case we give an warning of level 'NOTE'
88  drop_temporary Only drop temporary tables
89 
90  @todo
91  When logging to the binary log, we should log
92  tmp_tables and transactional tables as separate statements if we
93  are in a transaction; This is needed to get these tables into the
94  cached binary log that is only written on COMMIT.
95 
96  The current code only writes DROP statements that only uses temporary
97  tables to the cache binary log. This should be ok on most cases, but
98  not all.
99 
100  RETURN
101  0 ok
102  1 Error
103  -1 Thread was killed
104 */
105 
106 int rm_table_part2(Session *session, TableList *tables, bool if_exists,
107  bool drop_temporary)
108 {
109  TableList *table;
110  util::string::vector wrong_tables;
111  int error= 0;
112  bool foreign_key_error= false;
113 
114  do
115  {
116  boost::mutex::scoped_lock scopedLock(table::Cache::mutex());
117 
118  if (not drop_temporary && session->lock_table_names_exclusively(tables))
119  {
120  return 1;
121  }
122 
123  /* Don't give warnings for not found errors, as we already generate notes */
124  session->no_warnings_for_error= 1;
125 
126  for (table= tables; table; table= table->next_local)
127  {
128  identifier::Table tmp_identifier(session->catalog().identifier(),
129  table->getSchemaName(),
130  table->getTableName());
131 
132  error= session->open_tables.drop_temporary_table(tmp_identifier);
133 
134  switch (error) {
135  case 0:
136  // removed temporary table
137  continue;
138  case -1:
139  error= 1;
140  break;
141  default:
142  // temporary table not found
143  error= 0;
144  }
145 
146  if (drop_temporary == false)
147  {
148  abort_locked_tables(session, tmp_identifier);
149  table::Cache::removeTable(*session, tmp_identifier, RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG);
150  /*
151  If the table was used in lock tables, remember it so that
152  unlock_table_names can free it
153  */
154  Table *locked_table= drop_locked_tables(session, tmp_identifier);
155  if (locked_table)
156  table->table= locked_table;
157 
158  if (session->getKilled())
159  {
160  error= -1;
161  break;
162  }
163  }
164  identifier::Table identifier(session->catalog().identifier(),
165  table->getSchemaName(),
166  table->getTableName(),
167  table->getInternalTmpTable() ? message::Table::INTERNAL : message::Table::STANDARD);
168 
169  message::table::shared_ptr message= plugin::StorageEngine::getTableMessage(*session, identifier, true);
170 
171  if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
172  {
173  // Table was not found on disk and table can't be created from engine
174  if (if_exists)
175  {
176  push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
177  ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
178  table->getTableName());
179  }
180  else
181  {
182  error= 1;
183  }
184  }
185  else
186  {
187  drizzled::error_t local_error;
188 
189  /* Generate transaction event ONLY when we successfully drop */
190  if (plugin::StorageEngine::dropTable(*session, identifier, local_error))
191  {
192  if (message) // If we have no definition, we don't know if the table should have been replicated
193  {
194  TransactionServices::dropTable(*session, identifier, *message, if_exists);
195  }
196  }
197  else
198  {
199  if (local_error == HA_ERR_NO_SUCH_TABLE and if_exists)
200  {
201  error= 0;
202  session->clear_error();
203  }
204 
205  if (local_error == HA_ERR_ROW_IS_REFERENCED)
206  {
207  /* the table is referenced by a foreign key constraint */
208  foreign_key_error= true;
209  }
210  error= local_error;
211  }
212  }
213 
214  if (error)
215  {
216  wrong_tables.push_back(table->getTableName());
217  }
218  }
219 
220  tables->unlock_table_names();
221 
222  } while (0);
223 
224  if (wrong_tables.size())
225  {
226  if (not foreign_key_error)
227  {
228  std::string table_error;
229 
230  BOOST_FOREACH(util::string::vector::reference iter, wrong_tables)
231  {
232  table_error+= iter;
233  table_error+= ',';
234  }
235  table_error.resize(table_error.size() -1);
236 
237  my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
238  table_error.c_str());
239  }
240  else
241  {
242  my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
243  }
244  error= 1;
245  }
246 
247  session->no_warnings_for_error= 0;
248 
249  return error;
250 }
251 
252 /*
253  Sort keys in the following order:
254  - PRIMARY KEY
255  - UNIQUE keys where all column are NOT NULL
256  - UNIQUE keys that don't contain partial segments
257  - Other UNIQUE keys
258  - Normal keys
259  - Fulltext keys
260 
261  This will make checking for duplicated keys faster and ensure that
262  PRIMARY keys are prioritized.
263 */
264 
265 static int sort_keys(KeyInfo *a, KeyInfo *b)
266 {
267  ulong a_flags= a->flags, b_flags= b->flags;
268 
269  if (a_flags & HA_NOSAME)
270  {
271  if (!(b_flags & HA_NOSAME))
272  return -1;
273  if ((a_flags ^ b_flags) & (HA_NULL_PART_KEY))
274  {
275  /* Sort NOT NULL keys before other keys */
276  return (a_flags & (HA_NULL_PART_KEY)) ? 1 : -1;
277  }
278  if (is_primary_key(a->name))
279  return -1;
280  if (is_primary_key(b->name))
281  return 1;
282  /* Sort keys don't containing partial segments before others */
283  if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG)
284  return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1;
285  }
286  else if (b_flags & HA_NOSAME)
287  return 1; // Prefer b
288 
289  /*
290  Prefer original key order. usable_key_parts contains here
291  the original key position.
292  */
293  return ((a->usable_key_parts < b->usable_key_parts) ? -1 :
294  (a->usable_key_parts > b->usable_key_parts) ? 1 :
295  0);
296 }
297 
298 /*
299  Check TYPELIB (set or enum) for duplicates
300 
301  SYNOPSIS
302  check_duplicates_in_interval()
303  set_or_name "SET" or "ENUM" string for warning message
304  name name of the checked column
305  typelib list of values for the column
306  dup_val_count returns count of duplicate elements
307 
308  DESCRIPTION
309  This function prints an warning for each value in list
310  which has some duplicates on its right
311 
312  RETURN VALUES
313  0 ok
314  1 Error
315 */
316 
318 {
319 public:
320  string s;
321  const charset_info_st * const cs;
322 
323  typelib_set_member(const char* value, unsigned int length,
324  const charset_info_st * const charset)
325  : s(value, length),
326  cs(charset)
327  {}
328 };
329 
330 static bool operator==(typelib_set_member const& a, typelib_set_member const& b)
331 {
332  return (my_strnncoll(a.cs,
333  (const unsigned char*)a.s.c_str(), a.s.length(),
334  (const unsigned char*)b.s.c_str(), b.s.length())==0);
335 }
336 
337 
338 namespace
339 {
340 class typelib_set_member_hasher
341 {
342  boost::hash<string> hasher;
343 public:
344  std::size_t operator()(const typelib_set_member& t) const
345  {
346  return hasher(t.s);
347  }
348 };
349 }
350 
351 static bool check_duplicates_in_interval(const char *set_or_name,
352  const char *name, TYPELIB *typelib,
353  const charset_info_st * const cs,
354  unsigned int *dup_val_count)
355 {
356  TYPELIB tmp= *typelib;
357  const char **cur_value= typelib->type_names;
358  unsigned int *cur_length= typelib->type_lengths;
359  *dup_val_count= 0;
360 
361  boost::unordered_set<typelib_set_member, typelib_set_member_hasher> interval_set;
362 
363  for ( ; tmp.count > 0; cur_value++, cur_length++)
364  {
365  tmp.type_names++;
366  tmp.type_lengths++;
367  tmp.count--;
368  if (interval_set.count(typelib_set_member(*cur_value, *cur_length, cs)))
369  {
370  my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
371  name,*cur_value,set_or_name);
372  return 1;
373  }
374  else
375  interval_set.insert(typelib_set_member(*cur_value, *cur_length, cs));
376  }
377  return 0;
378 }
379 
380 
381 /*
382  Check TYPELIB (set or enum) max and total lengths
383 
384  SYNOPSIS
385  calculate_interval_lengths()
386  cs charset+collation pair of the interval
387  typelib list of values for the column
388  max_length length of the longest item
389  tot_length sum of the item lengths
390 
391  DESCRIPTION
392  After this function call:
393  - ENUM uses max_length
394  - SET uses tot_length.
395 
396  RETURN VALUES
397  void
398 */
399 static void calculate_interval_lengths(const charset_info_st * const cs,
400  TYPELIB *interval,
401  uint32_t *max_length,
402  uint32_t *tot_length)
403 {
404  const char **pos;
405  uint32_t *len;
406  *max_length= *tot_length= 0;
407  for (pos= interval->type_names, len= interval->type_lengths;
408  *pos ; pos++, len++)
409  {
410  uint32_t length= cs->cset->numchars(cs, *pos, *pos + *len);
411  *tot_length+= length;
412  set_if_bigger(*max_length, (uint32_t)length);
413  }
414 }
415 
416 /*
417  Prepare a create_table instance for packing
418 
419  SYNOPSIS
420  prepare_create_field()
421  sql_field field to prepare for packing
422  blob_columns count for BLOBs
423  timestamps count for timestamps
424 
425  DESCRIPTION
426  This function prepares a CreateField instance.
427  Fields such as pack_flag are valid after this call.
428 
429  RETURN VALUES
430  0 ok
431  1 Error
432 */
433 int prepare_create_field(CreateField *sql_field,
434  uint32_t *blob_columns,
435  int *timestamps,
436  int *timestamps_with_niladic)
437 {
438  unsigned int dup_val_count;
439 
440  /*
441  This code came from mysql_prepare_create_table.
442  Indent preserved to make patching easier
443  */
444  assert(sql_field->charset);
445 
446  switch (sql_field->sql_type) {
447  case DRIZZLE_TYPE_BLOB:
448  sql_field->length= 8; // Unireg field length
449  (*blob_columns)++;
450  break;
451 
452  case DRIZZLE_TYPE_ENUM:
453  {
454  if (check_duplicates_in_interval("ENUM",
455  sql_field->field_name,
456  sql_field->interval,
457  sql_field->charset,
458  &dup_val_count))
459  {
460  return 1;
461  }
462  }
463  break;
464 
465  case DRIZZLE_TYPE_MICROTIME:
466  case DRIZZLE_TYPE_TIMESTAMP:
467  /* We should replace old TIMESTAMP fields with their newer analogs */
468  if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
469  {
470  if (!*timestamps)
471  {
472  sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
473  (*timestamps_with_niladic)++;
474  }
475  else
476  {
477  sql_field->unireg_check= Field::NONE;
478  }
479  }
480  else if (sql_field->unireg_check != Field::NONE)
481  {
482  (*timestamps_with_niladic)++;
483  }
484 
485  (*timestamps)++;
486 
487  break;
488 
489  case DRIZZLE_TYPE_BOOLEAN:
490  case DRIZZLE_TYPE_DATE: // Rest of string types
491  case DRIZZLE_TYPE_DATETIME:
492  case DRIZZLE_TYPE_DECIMAL:
493  case DRIZZLE_TYPE_DOUBLE:
494  case DRIZZLE_TYPE_LONG:
495  case DRIZZLE_TYPE_LONGLONG:
496  case DRIZZLE_TYPE_NULL:
497  case DRIZZLE_TYPE_TIME:
498  case DRIZZLE_TYPE_UUID:
499  case DRIZZLE_TYPE_IPV6:
500  case DRIZZLE_TYPE_VARCHAR:
501  break;
502  }
503 
504  return 0;
505 }
506 
507 static int prepare_create_table(Session *session,
508  HA_CREATE_INFO *create_info,
509  message::Table &create_proto,
510  AlterInfo *alter_info,
511  bool tmp_table,
512  uint32_t *db_options,
513  KeyInfo **key_info_buffer,
514  uint32_t *key_count,
515  int select_field_count)
516 {
517  const char *key_name;
518  CreateField *sql_field,*dup_field;
519  uint field,null_fields,blob_columns,max_key_length;
520  ulong record_offset= 0;
521  KeyInfo *key_info;
522  KeyPartInfo *key_part_info;
523  int timestamps= 0, timestamps_with_niladic= 0;
524  int dup_no;
525  int select_field_pos,auto_increment=0;
526  List<CreateField>::iterator it(alter_info->create_list.begin());
527  List<CreateField>::iterator it2(alter_info->create_list.begin());
528  uint32_t total_uneven_bit_length= 0;
529 
530  plugin::StorageEngine *engine= plugin::StorageEngine::findByName(create_proto.engine().name());
531 
532  select_field_pos= alter_info->create_list.size() - select_field_count;
533  null_fields=blob_columns=0;
534  max_key_length= engine->max_key_length();
535 
536  for (int32_t field_no=0; (sql_field=it++) ; field_no++)
537  {
538  const charset_info_st *save_cs;
539 
540  /*
541  Initialize length from its original value (number of characters),
542  which was set in the parser. This is necessary if we're
543  executing a prepared statement for the second time.
544  */
545  sql_field->length= sql_field->char_length;
546 
547  if (!sql_field->charset)
548  sql_field->charset= create_info->default_table_charset;
549 
550  /*
551  table_charset is set in ALTER Table if we want change character set
552  for all varchar/char columns.
553  But the table charset must not affect the BLOB fields, so don't
554  allow to change my_charset_bin to somethig else.
555  */
556  if (create_info->table_charset && sql_field->charset != &my_charset_bin)
557  sql_field->charset= create_info->table_charset;
558 
559  save_cs= sql_field->charset;
560  if ((sql_field->flags & BINCMP_FLAG) &&
561  !(sql_field->charset= get_charset_by_csname(sql_field->charset->csname, MY_CS_BINSORT)))
562  {
563  char tmp[64];
564  char *tmp_pos= tmp;
565  strncpy(tmp_pos, save_cs->csname, sizeof(tmp)-4);
566  tmp_pos+= strlen(tmp);
567  strncpy(tmp_pos, STRING_WITH_LEN("_bin"));
568  my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
569  return true;
570  }
571 
572  /*
573  Convert the default value from client character
574  set into the column character set if necessary.
575  */
576  if (sql_field->def &&
577  save_cs != sql_field->def->collation.collation &&
578  (sql_field->sql_type == DRIZZLE_TYPE_ENUM))
579  {
580  /*
581  Starting from 5.1 we work here with a copy of CreateField
582  created by the caller, not with the instance that was
583  originally created during parsing. It's OK to create
584  a temporary item and initialize with it a member of the
585  copy -- this item will be thrown away along with the copy
586  at the end of execution, and thus not introduce a dangling
587  pointer in the parsed tree of a prepared statement or a
588  stored procedure statement.
589  */
590  sql_field->def= sql_field->def->safe_charset_converter(save_cs);
591 
592  if (sql_field->def == NULL)
593  {
594  /* Could not convert */
595  my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
596  return true;
597  }
598  }
599 
600  if (sql_field->sql_type == DRIZZLE_TYPE_ENUM)
601  {
602  const charset_info_st * const cs= sql_field->charset;
603  TYPELIB *interval= sql_field->interval;
604 
605  /*
606  Create typelib from interval_list, and if necessary
607  convert strings from client character set to the
608  column character set.
609  */
610  if (!interval)
611  {
612  /*
613  Create the typelib in runtime memory - we will free the
614  occupied memory at the same time when we free this
615  sql_field -- at the end of execution.
616  */
617  interval= sql_field->interval= typelib(*session->mem_root, sql_field->interval_list);
618 
619  List<String>::iterator int_it(sql_field->interval_list.begin());
620  String conv, *tmp;
621  char comma_buf[4];
622  int comma_length= cs->cset->wc_mb(cs, ',', (unsigned char*) comma_buf, (unsigned char*) comma_buf + sizeof(comma_buf));
623  assert(comma_length > 0);
624 
625  for (uint32_t i= 0; (tmp= int_it++); i++)
626  {
627  uint32_t lengthsp;
628  if (String::needs_conversion(tmp->length(), tmp->charset(), cs))
629  {
630  conv.copy(tmp->ptr(), tmp->length(), cs);
631  interval->type_names[i]= session->mem.strdup(conv);
632  interval->type_lengths[i]= conv.length();
633  }
634 
635  // Strip trailing spaces.
636  lengthsp= cs->cset->lengthsp(cs, interval->type_names[i], interval->type_lengths[i]);
637  interval->type_lengths[i]= lengthsp;
638  ((unsigned char *)interval->type_names[i])[lengthsp]= '\0';
639  }
640  sql_field->interval_list.clear(); // Don't need interval_list anymore
641  }
642 
643  /* DRIZZLE_TYPE_ENUM */
644  {
645  uint32_t field_length;
646  assert(sql_field->sql_type == DRIZZLE_TYPE_ENUM);
647  if (sql_field->def != NULL)
648  {
649  String str, *def= sql_field->def->val_str(&str);
650  if (def == NULL) /* SQL "NULL" maps to NULL */
651  {
652  if (sql_field->flags & NOT_NULL_FLAG)
653  {
654  my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
655  return true;
656  }
657 
658  /* else, the defaults yield the correct length for NULLs. */
659  }
660  else /* not NULL */
661  {
662  def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
663  if (interval->find_type2(def->ptr(), def->length(), cs) == 0) /* not found */
664  {
665  my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
666  return true;
667  }
668  }
669  }
670  uint32_t new_dummy;
671  calculate_interval_lengths(cs, interval, &field_length, &new_dummy);
672  sql_field->length= field_length;
673  }
674  set_if_smaller(sql_field->length, (uint32_t)MAX_FIELD_WIDTH-1);
675  }
676 
678  if (prepare_blob_field(session, sql_field))
679  return true;
680 
681  if (!(sql_field->flags & NOT_NULL_FLAG))
682  null_fields++;
683 
684  if (check_column_name(sql_field->field_name))
685  {
686  my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name);
687  return true;
688  }
689 
690  /* Check if we have used the same field name before */
691  for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++)
692  {
693  if (system_charset_info->strcasecmp(sql_field->field_name, dup_field->field_name) == 0)
694  {
695  /*
696  If this was a CREATE ... SELECT statement, accept a field
697  redefinition if we are changing a field in the SELECT part
698  */
699  if (field_no < select_field_pos || dup_no >= select_field_pos)
700  {
701  my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name);
702  return true;
703  }
704  else
705  {
706  /* Field redefined */
707  sql_field->def= dup_field->def;
708  sql_field->sql_type= dup_field->sql_type;
709  sql_field->charset= (dup_field->charset ?
710  dup_field->charset :
711  create_info->default_table_charset);
712  sql_field->length= dup_field->char_length;
713  sql_field->pack_length= dup_field->pack_length;
714  sql_field->key_length= dup_field->key_length;
715  sql_field->decimals= dup_field->decimals;
717  sql_field->unireg_check= dup_field->unireg_check;
718  /*
719  We're making one field from two, the result field will have
720  dup_field->flags as flags. If we've incremented null_fields
721  because of sql_field->flags, decrement it back.
722  */
723  if (!(sql_field->flags & NOT_NULL_FLAG))
724  null_fields--;
725  sql_field->flags= dup_field->flags;
726  sql_field->interval= dup_field->interval;
727  it2.remove(); // Remove first (create) definition
728  select_field_pos--;
729  break;
730  }
731  }
732  }
733 
735  if (not create_proto.engine().name().compare("MyISAM") &&
736  ((sql_field->flags & BLOB_FLAG) ||
737  (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)))
738  {
739  (*db_options)|= HA_OPTION_PACK_RECORD;
740  }
741 
742  it2= alter_info->create_list.begin();
743  }
744 
745  /* record_offset will be increased with 'length-of-null-bits' later */
746  record_offset= 0;
747  null_fields+= total_uneven_bit_length;
748 
749  it= alter_info->create_list.begin();
750  while ((sql_field=it++))
751  {
752  assert(sql_field->charset != 0);
753 
754  if (prepare_create_field(sql_field, &blob_columns,
755  &timestamps, &timestamps_with_niladic))
756  return true;
757  sql_field->offset= record_offset;
758  if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
759  auto_increment++;
760  }
761  if (timestamps_with_niladic > 1)
762  {
763  my_message(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS,
764  ER(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS), MYF(0));
765  return true;
766  }
767  if (auto_increment > 1)
768  {
769  my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
770  return true;
771  }
772  if (auto_increment &&
773  (engine->check_flag(HTON_BIT_NO_AUTO_INCREMENT)))
774  {
775  my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
776  ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
777  return true;
778  }
779 
780  if (blob_columns && (engine->check_flag(HTON_BIT_NO_BLOBS)))
781  {
782  my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
783  MYF(0));
784  return true;
785  }
786 
787  /* Create keys */
788 
789  List<Key>::iterator key_iterator(alter_info->key_list.begin());
790  List<Key>::iterator key_iterator2(alter_info->key_list.begin());
791  uint32_t key_parts=0, fk_key_count=0;
792  bool primary_key=0,unique_key=0;
793  Key *key, *key2;
794  uint32_t tmp, key_number;
795  /* special marker for keys to be ignored */
796  static char ignore_key[1];
797 
798  /* Calculate number of key segements */
799  *key_count= 0;
800 
801  while ((key=key_iterator++))
802  {
803  if (key->type == Key::FOREIGN_KEY)
804  {
805  fk_key_count++;
806  if (((Foreign_key *)key)->validate(alter_info->create_list))
807  return true;
808 
809  Foreign_key *fk_key= (Foreign_key*) key;
810 
811  add_foreign_key_to_table_message(&create_proto,
812  fk_key->name.data(),
813  fk_key->columns,
814  fk_key->ref_table,
815  fk_key->ref_columns,
816  fk_key->delete_opt,
817  fk_key->update_opt,
818  fk_key->match_opt);
819 
820  if (fk_key->ref_columns.size() &&
821  fk_key->ref_columns.size() != fk_key->columns.size())
822  {
823  my_error(ER_WRONG_FK_DEF, MYF(0),
824  (fk_key->name.data() ? fk_key->name.data() : "foreign key without name"),
825  ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
826  return true;
827  }
828  continue;
829  }
830  (*key_count)++;
831  tmp= engine->max_key_parts();
832  if (key->columns.size() > tmp)
833  {
834  my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
835  return true;
836  }
837  if (check_identifier_name(key->name, ER_TOO_LONG_IDENT))
838  return true;
839  key_iterator2= alter_info->key_list.begin();
840  if (key->type != Key::FOREIGN_KEY)
841  {
842  while ((key2 = key_iterator2++) != key)
843  {
844  /*
845  foreign_key_prefix(key, key2) returns 0 if key or key2, or both, is
846  'generated', and a generated key is a prefix of the other key.
847  Then we do not need the generated shorter key.
848  */
849  if ((key2->type != Key::FOREIGN_KEY &&
850  key2->name.data() != ignore_key &&
851  !foreign_key_prefix(key, key2)))
852  {
853  /* @todo issue warning message */
854  /* mark that the generated key should be ignored */
855  if (!key2->generated ||
856  (key->generated && key->columns.size() <
857  key2->columns.size()))
858  key->name.assign(ignore_key, 1);
859  else
860  {
861  key2->name.assign(ignore_key, 1);
862  key_parts-= key2->columns.size();
863  (*key_count)--;
864  }
865  break;
866  }
867  }
868  }
869  if (key->name.data() != ignore_key)
870  key_parts+=key->columns.size();
871  else
872  (*key_count)--;
873  if (key->name.data() && !tmp_table && (key->type != Key::PRIMARY) && is_primary_key(key->name.data()))
874  {
875  my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.data());
876  return true;
877  }
878  }
879  tmp= engine->max_keys();
880  if (*key_count > tmp)
881  {
882  my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
883  return true;
884  }
885 
886  (*key_info_buffer)= key_info= (KeyInfo*) memory::sql_calloc(sizeof(KeyInfo) * (*key_count));
887  key_part_info=(KeyPartInfo*) memory::sql_calloc(sizeof(KeyPartInfo)*key_parts);
888 
889  key_iterator= alter_info->key_list.begin();
890  key_number=0;
891  for (; (key=key_iterator++) ; key_number++)
892  {
893  uint32_t key_length=0;
894  Key_part_spec *column;
895 
896  if (key->name.data() == ignore_key)
897  {
898  /* ignore redundant keys */
899  do
900  key=key_iterator++;
901  while (key && key->name.data() == ignore_key);
902  if (!key)
903  break;
904  }
905 
906  switch (key->type) {
907  case Key::MULTIPLE:
908  key_info->flags= 0;
909  break;
910  case Key::FOREIGN_KEY:
911  key_number--; // Skip this key
912  continue;
913  default:
914  key_info->flags = HA_NOSAME;
915  break;
916  }
917  if (key->generated)
918  key_info->flags|= HA_GENERATED_KEY;
919 
920  key_info->key_parts=(uint8_t) key->columns.size();
921  key_info->key_part=key_part_info;
922  key_info->usable_key_parts= key_number;
923  key_info->algorithm= key->key_create_info.algorithm;
924 
925  uint32_t tmp_len= system_charset_info->cset->charpos(system_charset_info,
926  key->key_create_info.comment.begin(),
927  key->key_create_info.comment.end(),
928  INDEX_COMMENT_MAXLEN);
929 
930  if (tmp_len < key->key_create_info.comment.size())
931  {
932  my_error(ER_WRONG_STRING_LENGTH, MYF(0), key->key_create_info.comment.data(), "INDEX COMMENT", (uint32_t) INDEX_COMMENT_MAXLEN);
933  return -1;
934  }
935 
936  key_info->comment.assign(key_info->comment.data(), key->key_create_info.comment.size());
937  if (key_info->comment.size() > 0)
938  {
939  key_info->flags|= HA_USES_COMMENT;
940  key_info->comment.assign(key->key_create_info.comment.data(), key_info->comment.size()); // weird
941  }
942 
943  message::Table::Field *protofield= NULL;
944 
945  List<Key_part_spec>::iterator cols(key->columns.begin());
946  List<Key_part_spec>::iterator cols2(key->columns.begin());
947  for (uint32_t column_nr=0 ; (column=cols++) ; column_nr++)
948  {
949  uint32_t length;
950  Key_part_spec *dup_column;
951  int proto_field_nr= 0;
952 
953  it= alter_info->create_list.begin();
954  field=0;
955  while ((sql_field=it++) && ++proto_field_nr &&
956  system_charset_info->strcasecmp(column->field_name.data(), sql_field->field_name))
957  {
958  field++;
959  }
960 
961  if (!sql_field)
962  {
963  my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.data());
964  return true;
965  }
966 
967  while ((dup_column= cols2++) != column)
968  {
969  if (!system_charset_info->strcasecmp(column->field_name.data(), dup_column->field_name.data()))
970  {
971  my_printf_error(ER_DUP_FIELDNAME,
972  ER(ER_DUP_FIELDNAME),MYF(0),
973  column->field_name.data());
974  return true;
975  }
976  }
977  cols2= key->columns.begin();
978 
979  if (create_proto.field_size() > 0)
980  protofield= create_proto.mutable_field(proto_field_nr - 1);
981 
982  {
983  column->length*= sql_field->charset->mbmaxlen;
984 
985  if (sql_field->sql_type == DRIZZLE_TYPE_BLOB)
986  {
987  if (! (engine->check_flag(HTON_BIT_CAN_INDEX_BLOBS)))
988  {
989  my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.data());
990  return true;
991  }
992  if (! column->length)
993  {
994  my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.data());
995  return true;
996  }
997  }
998 
999  if (! (sql_field->flags & NOT_NULL_FLAG))
1000  {
1001  if (key->type == Key::PRIMARY)
1002  {
1003  /* Implicitly set primary key fields to NOT NULL for ISO conf. */
1004  sql_field->flags|= NOT_NULL_FLAG;
1005  null_fields--;
1006 
1007  if (protofield)
1008  {
1010  constraints= protofield->mutable_constraints();
1011  constraints->set_is_notnull(true);
1012  }
1013 
1014  }
1015  else
1016  {
1017  key_info->flags|= HA_NULL_PART_KEY;
1018  if (! (engine->check_flag(HTON_BIT_NULL_IN_KEY)))
1019  {
1020  my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.data());
1021  return true;
1022  }
1023  }
1024  }
1025 
1026  if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
1027  {
1028  if (column_nr == 0 || (engine->check_flag(HTON_BIT_AUTO_PART_KEY)))
1029  auto_increment--; // Field is used
1030  }
1031  }
1032 
1033  key_part_info->fieldnr= field;
1034  key_part_info->offset= (uint16_t) sql_field->offset;
1035  key_part_info->key_type= 0;
1036  length= sql_field->key_length;
1037 
1038  if (column->length)
1039  {
1040  if (sql_field->sql_type == DRIZZLE_TYPE_BLOB)
1041  {
1042  if ((length=column->length) > max_key_length ||
1043  length > engine->max_key_part_length())
1044  {
1045  length= min(max_key_length, engine->max_key_part_length());
1046  if (key->type == Key::MULTIPLE)
1047  {
1048  /* not a critical problem */
1049  char warn_buff[DRIZZLE_ERRMSG_SIZE];
1050  snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
1051  length);
1052  push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1053  ER_TOO_LONG_KEY, warn_buff);
1054  /* Align key length to multibyte char boundary */
1055  length-= length % sql_field->charset->mbmaxlen;
1056  }
1057  else
1058  {
1059  my_error(ER_TOO_LONG_KEY,MYF(0),length);
1060  return true;
1061  }
1062  }
1063  }
1064  else if ((column->length > length ||
1065  ! Field::type_can_have_key_part(sql_field->sql_type)))
1066  {
1067  my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
1068  return true;
1069  }
1070  else if (! (engine->check_flag(HTON_BIT_NO_PREFIX_CHAR_KEYS)))
1071  {
1072  length=column->length;
1073  }
1074  }
1075  else if (length == 0)
1076  {
1077  my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name.data());
1078  return true;
1079  }
1080  if (length > engine->max_key_part_length())
1081  {
1082  length= engine->max_key_part_length();
1083  if (key->type == Key::MULTIPLE)
1084  {
1085  /* not a critical problem */
1086  char warn_buff[DRIZZLE_ERRMSG_SIZE];
1087  snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
1088  length);
1089  push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1090  ER_TOO_LONG_KEY, warn_buff);
1091  /* Align key length to multibyte char boundary */
1092  length-= length % sql_field->charset->mbmaxlen;
1093  }
1094  else
1095  {
1096  my_error(ER_TOO_LONG_KEY,MYF(0),length);
1097  return true;
1098  }
1099  }
1100  key_part_info->length=(uint16_t) length;
1101  /* Use packed keys for long strings on the first column */
1102  if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
1103  (length >= KEY_DEFAULT_PACK_LENGTH &&
1104  (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
1105  sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
1106  {
1107  if ((column_nr == 0 && sql_field->sql_type == DRIZZLE_TYPE_BLOB) ||
1108  sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)
1109  {
1110  key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
1111  }
1112  else
1113  {
1114  key_info->flags|= HA_PACK_KEY;
1115  }
1116  }
1117  /* Check if the key segment is partial, set the key flag accordingly */
1118  if (length != sql_field->key_length)
1119  key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
1120 
1121  key_length+=length;
1122  key_part_info++;
1123 
1124  /* Create the key name based on the first column (if not given) */
1125  if (column_nr == 0)
1126  {
1127  if (key->type == Key::PRIMARY)
1128  {
1129  if (primary_key)
1130  {
1131  my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY),
1132  MYF(0));
1133  return true;
1134  }
1135  static const char pkey_name[]= "PRIMARY";
1136  key_name=pkey_name;
1137  primary_key=1;
1138  }
1139  else if (!(key_name= key->name.data()))
1140  key_name=make_unique_key_name(sql_field->field_name,
1141  *key_info_buffer, key_info);
1142  if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
1143  {
1144  my_error(ER_DUP_KEYNAME, MYF(0), key_name);
1145  return true;
1146  }
1147  key_info->name=(char*) key_name;
1148  }
1149  }
1150 
1151  if (!key_info->name || check_column_name(key_info->name))
1152  {
1153  my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
1154  return true;
1155  }
1156 
1157  if (!(key_info->flags & HA_NULL_PART_KEY))
1158  {
1159  unique_key=1;
1160  }
1161 
1162  key_info->key_length=(uint16_t) key_length;
1163 
1164  if (key_length > max_key_length)
1165  {
1166  my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
1167  return true;
1168  }
1169 
1170  key_info++;
1171  }
1172 
1173  if (!unique_key && !primary_key &&
1174  (engine->check_flag(HTON_BIT_REQUIRE_PRIMARY_KEY)))
1175  {
1176  my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
1177  return true;
1178  }
1179 
1180  if (auto_increment > 0)
1181  {
1182  my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
1183  return true;
1184  }
1185  /* Sort keys in optimized order */
1186  internal::my_qsort((unsigned char*) *key_info_buffer, *key_count, sizeof(KeyInfo),
1187  (qsort_cmp) sort_keys);
1188 
1189  /* Check fields. */
1190  it= alter_info->create_list.begin();
1191  while ((sql_field=it++))
1192  {
1193  Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
1194 
1195  if (session->variables.sql_mode & MODE_NO_ZERO_DATE &&
1196  !sql_field->def &&
1197  (sql_field->sql_type == DRIZZLE_TYPE_TIMESTAMP or sql_field->sql_type == DRIZZLE_TYPE_MICROTIME) &&
1198  (sql_field->flags & NOT_NULL_FLAG) &&
1199  (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
1200  {
1201  /*
1202  An error should be reported if:
1203  - NO_ZERO_DATE SQL mode is active;
1204  - there is no explicit DEFAULT clause (default column value);
1205  - this is a TIMESTAMP column;
1206  - the column is not NULL;
1207  - this is not the DEFAULT CURRENT_TIMESTAMP column.
1208 
1209  In other words, an error should be reported if
1210  - NO_ZERO_DATE SQL mode is active;
1211  - the column definition is equivalent to
1212  'column_name TIMESTAMP DEFAULT 0'.
1213  */
1214 
1215  my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
1216  return true;
1217  }
1218  }
1219 
1220  return false;
1221 }
1222 
1223 /*
1224  Extend long VARCHAR fields to blob & prepare field if it's a blob
1225 
1226  SYNOPSIS
1227  prepare_blob_field()
1228  sql_field Field to check
1229 
1230  RETURN
1231  0 ok
1232  1 Error (sql_field can't be converted to blob)
1233  In this case the error is given
1234 */
1235 
1236 static bool prepare_blob_field(Session *,
1237  CreateField *sql_field)
1238 {
1239 
1240  if (sql_field->length > MAX_FIELD_VARCHARLENGTH &&
1241  !(sql_field->flags & BLOB_FLAG))
1242  {
1243  my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name,
1244  MAX_FIELD_VARCHARLENGTH / sql_field->charset->mbmaxlen);
1245  return 1;
1246  }
1247 
1248  if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
1249  {
1250  if (sql_field->sql_type == DRIZZLE_TYPE_BLOB)
1251  {
1252  /* The user has given a length to the blob column */
1253  sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0);
1254  }
1255  sql_field->length= 0;
1256  }
1257  return 0;
1258 }
1259 
1260 static bool locked_create_event(Session *session,
1261  const identifier::Table &identifier,
1262  HA_CREATE_INFO *create_info,
1263  message::Table &table_proto,
1264  AlterInfo *alter_info,
1265  bool is_if_not_exists,
1266  bool internal_tmp_table,
1267  uint db_options,
1268  uint key_count,
1269  KeyInfo *key_info_buffer)
1270 {
1271  bool error= true;
1272 
1273  {
1274 
1275  /*
1276  @note if we are building a temp table we need to check to see if a temp table
1277  already exists, otherwise we just need to find out if a normal table exists (aka it is fine
1278  to create a table under a temporary table.
1279  */
1280  bool exists=
1281  plugin::StorageEngine::doesTableExist(*session, identifier,
1282  identifier.getType() != message::Table::STANDARD );
1283 
1284  if (exists)
1285  {
1286  if (is_if_not_exists)
1287  {
1288  error= false;
1289  push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1290  ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1291  identifier.getTableName().c_str());
1292  create_info->table_existed= 1; // Mark that table existed
1293  return error;
1294  }
1295 
1296  my_error(ER_TABLE_EXISTS_ERROR, identifier);
1297 
1298  return error;
1299  }
1300 
1301  if (identifier.getType() == message::Table::STANDARD) // We have a real table
1302  {
1303  /*
1304  We don't assert here, but check the result, because the table could be
1305  in the table definition cache and in the same time the .frm could be
1306  missing from the disk, in case of manual intervention which deletes
1307  the .frm cursor. The user has to use FLUSH TABLES; to clear the cache.
1308  Then she could create the table. This case is pretty obscure and
1309  therefore we don't introduce a new error message only for it.
1310  */
1311  /*
1312  @todo improve this error condition.
1313  */
1314  if (definition::Cache::find(identifier.getKey()))
1315  {
1316  my_error(ER_TABLE_EXISTS_ERROR, identifier);
1317 
1318  return error;
1319  }
1320  }
1321  }
1322 
1323  session->set_proc_info("creating table");
1324  create_info->table_existed= 0; // Mark that table is created
1325 
1326  create_info->table_options= db_options;
1327 
1328  if (not rea_create_table(session, identifier,
1329  table_proto,
1330  create_info, alter_info->create_list,
1331  key_count, key_info_buffer))
1332  {
1333  return error;
1334  }
1335 
1336  if (identifier.getType() == message::Table::TEMPORARY)
1337  {
1338  /* Open table and put in temporary table list */
1339  if (not (session->open_temporary_table(identifier)))
1340  {
1341  (void) session->open_tables.rm_temporary_table(identifier);
1342  return error;
1343  }
1344  }
1345 
1346  /*
1347  We keep this behind the lock to make sure ordering is correct for a table.
1348  This is a very unlikely problem where before we would write out to the
1349  trans log, someone would do a delete/create operation.
1350  */
1351 
1352  if (table_proto.type() == message::Table::STANDARD && not internal_tmp_table)
1353  {
1354  TransactionServices::createTable(*session, table_proto);
1355  }
1356 
1357  return false;
1358 }
1359 
1360 
1361 /*
1362  Ignore the name of this function... it locks :(
1363 
1364  Create a table
1365 
1366  SYNOPSIS
1367  create_table_no_lock()
1368  session Thread object
1369  db Database
1370  table_name Table name
1371  create_info Create information (like MAX_ROWS)
1372  fields List of fields to create
1373  keys List of keys to create
1374  internal_tmp_table Set to 1 if this is an internal temporary table
1375  (From ALTER Table)
1376  select_field_count
1377 
1378  DESCRIPTION
1379  If one creates a temporary table, this is automatically opened
1380 
1381  Note that this function assumes that caller already have taken
1382  name-lock on table being created or used some other way to ensure
1383  that concurrent operations won't intervene. create_table()
1384  is a wrapper that can be used for this.
1385 
1386  RETURN VALUES
1387  false OK
1388  true error
1389 */
1390 
1391 bool create_table_no_lock(Session *session,
1392  const identifier::Table &identifier,
1393  HA_CREATE_INFO *create_info,
1394  message::Table &table_proto,
1395  AlterInfo *alter_info,
1396  bool internal_tmp_table,
1397  uint32_t select_field_count,
1398  bool is_if_not_exists)
1399 {
1400  uint db_options, key_count;
1401  KeyInfo *key_info_buffer;
1402  bool error= true;
1403 
1404  /* Check for duplicate fields and check type of table to create */
1405  if (not alter_info->create_list.size())
1406  {
1407  my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
1408  MYF(0));
1409  return true;
1410  }
1411  assert(identifier.getTableName() == table_proto.name());
1412  db_options= create_info->table_options;
1413 
1414  set_table_default_charset(session->catalog().identifier(),create_info, identifier.getSchemaName().c_str());
1415 
1416  /* Build a Table object to pass down to the engine, and the do the actual create. */
1417  if (not prepare_create_table(session, create_info, table_proto, alter_info,
1418  internal_tmp_table,
1419  &db_options,
1420  &key_info_buffer, &key_count,
1421  select_field_count))
1422  {
1423  boost::mutex::scoped_lock lock(table::Cache::mutex()); /* CREATE TABLE (some confussion on naming, double check) */
1424  error= locked_create_event(session,
1425  identifier,
1426  create_info,
1427  table_proto,
1428  alter_info,
1429  is_if_not_exists,
1430  internal_tmp_table,
1431  db_options, key_count,
1432  key_info_buffer);
1433  }
1434 
1435  session->set_proc_info("After create");
1436 
1437  return(error);
1438 }
1439 
1443 static bool drizzle_create_table(Session *session,
1444  const identifier::Table &identifier,
1445  HA_CREATE_INFO *create_info,
1446  message::Table &table_proto,
1447  AlterInfo *alter_info,
1448  bool internal_tmp_table,
1449  uint32_t select_field_count,
1450  bool is_if_not_exists)
1451 {
1452  Table *name_lock= session->lock_table_name_if_not_cached(identifier);
1453  bool result;
1454  if (name_lock == NULL)
1455  {
1456  if (is_if_not_exists)
1457  {
1458  push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1459  ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1460  identifier.getTableName().c_str());
1461  create_info->table_existed= 1;
1462  result= false;
1463  }
1464  else
1465  {
1466  my_error(ER_TABLE_EXISTS_ERROR, identifier);
1467  result= true;
1468  }
1469  }
1470  else
1471  {
1472  result= create_table_no_lock(session,
1473  identifier,
1474  create_info,
1475  table_proto,
1476  alter_info,
1477  internal_tmp_table,
1478  select_field_count,
1479  is_if_not_exists);
1480  }
1481 
1482  if (name_lock)
1483  {
1484  boost::mutex::scoped_lock lock(table::Cache::mutex()); /* Lock for removing name_lock during table create */
1485  session->unlink_open_table(name_lock);
1486  }
1487 
1488  return(result);
1489 }
1490 
1491 
1492 /*
1493  Database locking aware wrapper for create_table_no_lock(),
1494 */
1495 bool create_table(Session *session,
1496  const identifier::Table &identifier,
1497  HA_CREATE_INFO *create_info,
1498  message::Table &table_proto,
1499  AlterInfo *alter_info,
1500  bool internal_tmp_table,
1501  uint32_t select_field_count,
1502  bool is_if_not_exists)
1503 {
1504  if (identifier.isTmp())
1505  {
1506  return create_table_no_lock(session,
1507  identifier,
1508  create_info,
1509  table_proto,
1510  alter_info,
1511  internal_tmp_table,
1512  select_field_count,
1513  is_if_not_exists);
1514  }
1515 
1516  return drizzle_create_table(session,
1517  identifier,
1518  create_info,
1519  table_proto,
1520  alter_info,
1521  internal_tmp_table,
1522  select_field_count,
1523  is_if_not_exists);
1524 }
1525 
1526 
1527 /*
1528 ** Give the key name after the first field with an optional '_#' after
1529 **/
1530 
1531 static bool
1532 check_if_keyname_exists(const char *name, KeyInfo *start, KeyInfo *end)
1533 {
1534  for (KeyInfo *key= start; key != end; key++)
1535  {
1536  if (!system_charset_info->strcasecmp(name, key->name))
1537  return 1;
1538  }
1539  return 0;
1540 }
1541 
1542 
1543 static const char*
1544 make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end)
1545 {
1546  char buff[MAX_FIELD_NAME],*buff_end;
1547 
1548  if (not check_if_keyname_exists(field_name,start,end) && not is_primary_key(field_name))
1549  {
1550  return field_name; // Use fieldname
1551  }
1552 
1553  buff_end= strncpy(buff, field_name, sizeof(buff)-4);
1554  buff_end+= strlen(buff);
1555 
1556  /*
1557  Only 3 chars + '\0' left, so need to limit to 2 digit
1558  This is ok as we can't have more than 100 keys anyway
1559  */
1560  for (uint32_t i=2 ; i< 100; i++)
1561  {
1562  *buff_end= '_';
1563  internal::int10_to_str(i, buff_end+1, 10);
1564  if (!check_if_keyname_exists(buff,start,end))
1565  return memory::sql_strdup(buff);
1566  }
1567  return (char*) "not_specified"; // Should never happen
1568 }
1569 
1570 
1571 /****************************************************************************
1572 ** Alter a table definition
1573 ****************************************************************************/
1574 
1575 /*
1576  Rename a table.
1577 
1578  SYNOPSIS
1579  rename_table()
1580  session
1581  base The plugin::StorageEngine handle.
1582  old_db The old database name.
1583  old_name The old table name.
1584  new_db The new database name.
1585  new_name The new table name.
1586 
1587  RETURN
1588  false OK
1589  true Error
1590 */
1591 
1592 bool
1593 rename_table(Session &session,
1594  plugin::StorageEngine *base,
1595  const identifier::Table &from,
1596  const identifier::Table &to)
1597 {
1598  if (not plugin::StorageEngine::doesSchemaExist(to))
1599  {
1600  my_error(ER_NO_DB_ERROR, MYF(0), to.getSchemaName().c_str());
1601  return true;
1602  }
1603 
1604  int error= base->renameTable(session, from, to);
1605  if (error == HA_ERR_WRONG_COMMAND)
1606  my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER Table");
1607  else if (error)
1608  {
1609  my_error(ER_ERROR_ON_RENAME, MYF(0),
1610  from.isTmp() ? "#sql-temporary" : from.getSQLPath().c_str(),
1611  to.isTmp() ? "#sql-temporary" : to.getSQLPath().c_str(), error);
1612  }
1613  return error;
1614 }
1615 
1616 
1617 /*
1618  Force all other threads to stop using the table
1619 
1620  SYNOPSIS
1621  wait_while_table_is_used()
1622  session Thread Cursor
1623  table Table to remove from cache
1624  function HA_EXTRA_PREPARE_FOR_DROP if table is to be deleted
1625  HA_EXTRA_FORCE_REOPEN if table is not be used
1626  HA_EXTRA_PREPARE_FOR_RENAME if table is to be renamed
1627  NOTES
1628  When returning, the table will be unusable for other threads until
1629  the table is closed.
1630 
1631  PREREQUISITES
1632  Lock on table::Cache::mutex()
1633  Win32 clients must also have a WRITE LOCK on the table !
1634 */
1635 
1636 void wait_while_table_is_used(Session *session, Table *table,
1637  enum ha_extra_function function)
1638 {
1639 
1640  safe_mutex_assert_owner(table::Cache::mutex().native_handle());
1641 
1642  table->cursor->extra(function);
1643  /* Mark all tables that are in use as 'old' */
1644  session->abortLock(table); /* end threads waiting on lock */
1645 
1646  /* Wait until all there are no other threads that has this table open */
1647  identifier::Table identifier(session->catalog().identifier(),table->getShare()->getSchemaName(), table->getShare()->getTableName());
1648  table::Cache::removeTable(*session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
1649 }
1650 
1651 /*
1652  Close a cached table
1653 
1654  SYNOPSIS
1655  close_cached_table()
1656  session Thread Cursor
1657  table Table to remove from cache
1658 
1659  NOTES
1660  Function ends by signaling threads waiting for the table to try to
1661  reopen the table.
1662 
1663  PREREQUISITES
1664  Lock on table::Cache::mutex()
1665  Win32 clients must also have a WRITE LOCK on the table !
1666 */
1667 
1668 void Session::close_cached_table(Table *table)
1669 {
1670 
1671  wait_while_table_is_used(this, table, HA_EXTRA_FORCE_REOPEN);
1672  /* Close lock if this is not got with LOCK TABLES */
1673  if (open_tables.lock)
1674  {
1675  unlockTables(open_tables.lock);
1676  open_tables.lock= NULL; // Start locked threads
1677  }
1678  /* Close all copies of 'table'. This also frees all LOCK TABLES lock */
1679  unlink_open_table(table);
1680 
1681  /* When lock on table::Cache::mutex() is freed other threads can continue */
1683 }
1684 
1685 /*
1686  RETURN VALUES
1687  false Message sent to net (admin operation went ok)
1688  true Message should be sent by caller
1689  (admin operation or network communication failed)
1690 */
1691 static bool admin_table(Session* session, TableList* tables,
1692  const char *operator_name,
1693  thr_lock_type lock_type,
1694  bool open_for_modify,
1695  int (Cursor::*operator_func)(Session*))
1696 {
1697  TableList *table;
1698  Select_Lex *select= &session->lex().select_lex;
1699  List<Item> field_list;
1700  Item *item;
1701  int result_code= 0;
1702  const charset_info_st * const cs= system_charset_info;
1703 
1704  if (! session->endActiveTransaction())
1705  return 1;
1706 
1707  field_list.push_back(item = new Item_empty_string("Table", NAME_CHAR_LEN * 2, cs));
1708  item->maybe_null = 1;
1709  field_list.push_back(item = new Item_empty_string("Op", 10, cs));
1710  item->maybe_null = 1;
1711  field_list.push_back(item = new Item_empty_string("Msg_type", 10, cs));
1712  item->maybe_null = 1;
1713  field_list.push_back(item = new Item_empty_string("Msg_text", 255, cs));
1714  item->maybe_null = 1;
1715  session->getClient()->sendFields(field_list);
1716 
1717  for (table= tables; table; table= table->next_local)
1718  {
1719  identifier::Table table_identifier(session->catalog().identifier(), table->getSchemaName(), table->getTableName());
1720  bool fatal_error=0;
1721 
1722  std::string table_name = table_identifier.getSQLPath();
1723 
1724  table->lock_type= lock_type;
1725  /* open only one table from local list of command */
1726  {
1727  TableList *save_next_global, *save_next_local;
1728  save_next_global= table->next_global;
1729  table->next_global= 0;
1730  save_next_local= table->next_local;
1731  table->next_local= 0;
1732  select->table_list.first= (unsigned char*)table;
1733  /*
1734  Time zone tables and SP tables can be add to lex->query_tables list,
1735  so it have to be prepared.
1736  @todo Investigate if we can put extra tables into argument instead of using lex->query_tables
1737  */
1738  session->lex().query_tables= table;
1739  session->lex().query_tables_last= &table->next_global;
1740  session->lex().query_tables_own_last= 0;
1741  session->no_warnings_for_error= 0;
1742 
1743  session->openTablesLock(table);
1744  session->no_warnings_for_error= 0;
1745  table->next_global= save_next_global;
1746  table->next_local= save_next_local;
1747  }
1748 
1749  /*
1750  CHECK Table command is only command where VIEW allowed here and this
1751  command use only temporary teble method for VIEWs resolving => there
1752  can't be VIEW tree substitition of join view => if opening table
1753  succeed then table->table will have real Table pointer as value (in
1754  case of join view substitution table->table can be 0, but here it is
1755  impossible)
1756  */
1757  if (!table->table)
1758  {
1759  if (!session->main_da().m_warn_list.size())
1760  push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1761  ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE));
1762  result_code= HA_ADMIN_CORRUPT;
1763  goto send_result;
1764  }
1765 
1766  if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify)
1767  {
1768  char buff[FN_REFLEN + DRIZZLE_ERRMSG_SIZE];
1769  uint32_t length;
1770  session->getClient()->store(table_name.c_str());
1771  session->getClient()->store(operator_name);
1772  session->getClient()->store(STRING_WITH_LEN("error"));
1773  length= snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
1774  table_name.c_str());
1775  session->getClient()->store(buff, length);
1776  TransactionServices::autocommitOrRollback(*session, false);
1777  session->endTransaction(COMMIT);
1778  session->close_thread_tables();
1779  session->lex().reset_query_tables_list(false);
1780  table->table=0; // For query cache
1781  if (session->getClient()->flush())
1782  goto err;
1783  continue;
1784  }
1785 
1786  /* Close all instances of the table to allow repair to rename files */
1787  if (lock_type == TL_WRITE && table->table->getShare()->getVersion())
1788  {
1789  table::Cache::mutex().lock(); /* Lock type is TL_WRITE and we lock to repair the table */
1790  const char *old_message=session->enter_cond(COND_refresh, table::Cache::mutex(),
1791  "Waiting to get writelock");
1792  session->abortLock(table->table);
1793  identifier::Table identifier(session->catalog().identifier(),table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1794  table::Cache::removeTable(*session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG);
1795  session->exit_cond(old_message);
1796  if (session->getKilled())
1797  goto err;
1798  open_for_modify= 0;
1799  }
1800 
1801  result_code = (table->table->cursor->*operator_func)(session);
1802 
1803 send_result:
1804 
1805  session->lex().cleanup_after_one_table_open();
1806  session->clear_error(); // these errors shouldn't get client
1807  {
1808  BOOST_FOREACH(DRIZZLE_ERROR* err, session->main_da().m_warn_list)
1809  {
1810  session->getClient()->store(table_name.c_str());
1811  session->getClient()->store(operator_name);
1812  session->getClient()->store(warning_level_names[err->level].data(), warning_level_names[err->level].size());
1813  session->getClient()->store(err->msg);
1814  if (session->getClient()->flush())
1815  goto err;
1816  }
1817  drizzle_reset_errors(*session, true);
1818  }
1819  session->getClient()->store(table_name.c_str());
1820  session->getClient()->store(operator_name);
1821 
1822  switch (result_code) {
1823  case HA_ADMIN_NOT_IMPLEMENTED:
1824  {
1825  char buf[ERRMSGSIZE+20];
1826  uint32_t length=snprintf(buf, ERRMSGSIZE,
1827  ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
1828  session->getClient()->store(STRING_WITH_LEN("note"));
1829  session->getClient()->store(buf, length);
1830  }
1831  break;
1832 
1833  case HA_ADMIN_OK:
1834  session->getClient()->store(STRING_WITH_LEN("status"));
1835  session->getClient()->store(STRING_WITH_LEN("OK"));
1836  break;
1837 
1838  case HA_ADMIN_FAILED:
1839  session->getClient()->store(STRING_WITH_LEN("status"));
1840  session->getClient()->store(STRING_WITH_LEN("Operation failed"));
1841  break;
1842 
1843  case HA_ADMIN_REJECT:
1844  session->getClient()->store(STRING_WITH_LEN("status"));
1845  session->getClient()->store(STRING_WITH_LEN("Operation need committed state"));
1846  open_for_modify= false;
1847  break;
1848 
1849  case HA_ADMIN_ALREADY_DONE:
1850  session->getClient()->store(STRING_WITH_LEN("status"));
1851  session->getClient()->store(STRING_WITH_LEN("Table is already up to date"));
1852  break;
1853 
1854  case HA_ADMIN_CORRUPT:
1855  session->getClient()->store(STRING_WITH_LEN("error"));
1856  session->getClient()->store(STRING_WITH_LEN("Corrupt"));
1857  fatal_error=1;
1858  break;
1859 
1860  case HA_ADMIN_INVALID:
1861  session->getClient()->store(STRING_WITH_LEN("error"));
1862  session->getClient()->store(STRING_WITH_LEN("Invalid argument"));
1863  break;
1864 
1865  default: // Probably HA_ADMIN_INTERNAL_ERROR
1866  {
1867  char buf[ERRMSGSIZE+20];
1868  uint32_t length=snprintf(buf, ERRMSGSIZE,
1869  _("Unknown - internal error %d during operation"),
1870  result_code);
1871  session->getClient()->store(STRING_WITH_LEN("error"));
1872  session->getClient()->store(buf, length);
1873  fatal_error=1;
1874  break;
1875  }
1876  }
1877  if (table->table)
1878  {
1879  if (fatal_error)
1880  {
1881  table->table->getMutableShare()->resetVersion(); // Force close of table
1882  }
1883  else if (open_for_modify)
1884  {
1885  if (table->table->getShare()->getType())
1886  {
1887  table->table->cursor->info(HA_STATUS_CONST);
1888  }
1889  else
1890  {
1891  boost::unique_lock<boost::mutex> lock(table::Cache::mutex());
1892  identifier::Table identifier(session->catalog().identifier(),
1893  table->table->getShare()->getSchemaName(),
1894  table->table->getShare()->getTableName());
1895  table::Cache::removeTable(*session, identifier, RTFC_NO_FLAG);
1896  }
1897  }
1898  }
1899  TransactionServices::autocommitOrRollback(*session, false);
1900  session->endTransaction(COMMIT);
1901  session->close_thread_tables();
1902  table->table=0; // For query cache
1903  if (session->getClient()->flush())
1904  goto err;
1905  }
1906 
1907  session->my_eof();
1908  return false;
1909 
1910 err:
1911  TransactionServices::autocommitOrRollback(*session, true);
1912  session->endTransaction(ROLLBACK);
1913  session->close_thread_tables(); // Shouldn't be needed
1914  if (table)
1915  table->table=0;
1916  return true;
1917 }
1918 
1919  /*
1920  Create a new table by copying from source table
1921 
1922  Altough exclusive name-lock on target table protects us from concurrent
1923  DML and DDL operations on it we still want to wrap .FRM creation and call
1924  to plugin::StorageEngine::createTable() in critical section protected by
1925  table::Cache::mutex() in order to provide minimal atomicity against operations which
1926  disregard name-locks, like I_S implementation, for example. This is a
1927  temporary and should not be copied. Instead we should fix our code to
1928  always honor name-locks.
1929 
1930  Also some engines (e.g. NDB cluster) require that table::Cache::mutex() should be held
1931  during the call to plugin::StorageEngine::createTable().
1932  See bug #28614 for more info.
1933  */
1934 static bool create_table_wrapper(Session &session,
1935  const message::Table& create_table_proto,
1936  const identifier::Table& destination_identifier,
1937  const identifier::Table& source_identifier,
1938  bool is_engine_set)
1939 {
1940  // We require an additional table message because during parsing we used
1941  // a "new" message and it will not have all of the information that the
1942  // source table message would have.
1943  message::Table new_table_message;
1944 
1945  message::table::shared_ptr source_table_message= plugin::StorageEngine::getTableMessage(session, source_identifier);
1946 
1947  if (not source_table_message)
1948  {
1949  my_error(ER_TABLE_UNKNOWN, source_identifier);
1950  return false;
1951  }
1952 
1953  new_table_message.CopyFrom(*source_table_message);
1954  new_table_message.set_type(destination_identifier.isTmp() ? message::Table::TEMPORARY : message::Table::STANDARD);
1955 
1956  if (is_engine_set)
1957  {
1958  new_table_message.mutable_engine()->set_name(create_table_proto.engine().name());
1959  }
1960 
1961  { // We now do a selective copy of elements on to the new table.
1962  new_table_message.set_name(create_table_proto.name());
1963  new_table_message.set_schema(create_table_proto.schema());
1964  new_table_message.set_catalog(create_table_proto.catalog());
1965  }
1966 
1967  /* Fix names of foreign keys being added */
1968  for (int32_t j= 0; j < new_table_message.fk_constraint_size(); j++)
1969  {
1970  if (new_table_message.fk_constraint(j).has_name())
1971  {
1972  std::string name(new_table_message.name());
1973  char number[20];
1974 
1975  name.append("_ibfk_");
1976  snprintf(number, sizeof(number), "%d", j+1);
1977  name.append(number);
1978 
1979  message::Table::ForeignKeyConstraint *pfkey= new_table_message.mutable_fk_constraint(j);
1980  pfkey->set_name(name);
1981  }
1982  }
1983 
1984  /*
1985  As mysql_truncate don't work on a new table at this stage of
1986  creation, instead create the table directly (for both normal and temporary tables).
1987  */
1988  bool success= plugin::StorageEngine::createTable(session, destination_identifier, new_table_message);
1989 
1990  if (success && not destination_identifier.isTmp())
1991  {
1992  TransactionServices::createTable(session, new_table_message);
1993  }
1994 
1995  return success;
1996 }
1997 
1998 /*
1999  Create a table identical to the specified table
2000 
2001  SYNOPSIS
2002  create_like_table()
2003  session Thread object
2004  table Table list element for target table
2005  src_table Table list element for source table
2006  create_info Create info
2007 
2008  RETURN VALUES
2009  false OK
2010  true error
2011 */
2012 
2013 bool create_like_table(Session* session,
2014  const identifier::Table& destination_identifier,
2015  const identifier::Table& source_identifier,
2016  message::Table &create_table_proto,
2017  bool is_if_not_exists,
2018  bool is_engine_set)
2019 {
2020  bool res= true;
2021  bool table_exists= false;
2022 
2023  /*
2024  Check that destination tables does not exist. Note that its name
2025  was already checked when it was added to the table list.
2026 
2027  For temporary tables we don't aim to grab locks.
2028  */
2029  if (destination_identifier.isTmp())
2030  {
2031  if (session->open_tables.find_temporary_table(destination_identifier))
2032  {
2033  table_exists= true;
2034  }
2035  else
2036  {
2037  bool was_created= create_table_wrapper(*session,
2038  create_table_proto,
2039  destination_identifier,
2040  source_identifier,
2041  is_engine_set);
2042  if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2043  {
2044  (void) session->open_tables.rm_temporary_table(destination_identifier, true);
2045  }
2046  else if (not session->open_temporary_table(destination_identifier))
2047  {
2048  // We created, but we can't open... also, a hack.
2049  (void) session->open_tables.rm_temporary_table(destination_identifier, true);
2050  }
2051  else
2052  {
2053  res= false;
2054  }
2055  }
2056  }
2057  else // Standard table which will require locks.
2058  {
2059  Table *name_lock= session->lock_table_name_if_not_cached(destination_identifier);
2060  if (not name_lock)
2061  {
2062  table_exists= true;
2063  }
2064  else if (plugin::StorageEngine::doesTableExist(*session, destination_identifier))
2065  {
2066  table_exists= true;
2067  }
2068  else // Otherwise we create the table
2069  {
2070  bool was_created;
2071  {
2072  boost::mutex::scoped_lock lock(table::Cache::mutex()); /* We lock for CREATE TABLE LIKE to copy table definition */
2073  was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2074  source_identifier, is_engine_set);
2075  }
2076 
2077  // So we blew the creation of the table, and we scramble to clean up
2078  // anything that might have been created (read... it is a hack)
2079  if (not was_created)
2080  {
2081  plugin::StorageEngine::dropTable(*session, destination_identifier);
2082  }
2083  else
2084  {
2085  res= false;
2086  }
2087  }
2088 
2089  if (name_lock)
2090  {
2091  boost::mutex::scoped_lock lock(table::Cache::mutex()); /* unlink open tables for create table like*/
2092  session->unlink_open_table(name_lock);
2093  }
2094  }
2095 
2096  if (table_exists)
2097  {
2098  if (is_if_not_exists)
2099  {
2100  char warn_buff[DRIZZLE_ERRMSG_SIZE];
2101  snprintf(warn_buff, sizeof(warn_buff),
2102  ER(ER_TABLE_EXISTS_ERROR), destination_identifier.getTableName().c_str());
2103  push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2104  ER_TABLE_EXISTS_ERROR, warn_buff);
2105  return false;
2106  }
2107 
2108  my_error(ER_TABLE_EXISTS_ERROR, destination_identifier);
2109 
2110  return true;
2111  }
2112 
2113  return res;
2114 }
2115 
2116 
2117 bool analyze_table(Session* session, TableList* tables)
2118 {
2119  return admin_table(session, tables, "analyze", TL_READ_NO_INSERT, true, &Cursor::ha_analyze);
2120 }
2121 
2122 
2123 bool check_table(Session* session, TableList* tables)
2124 {
2125  return admin_table(session, tables, "check", TL_READ_NO_INSERT, false, &Cursor::ha_check);
2126 }
2127 
2128 } /* namespace drizzled */
static bool drizzle_create_table(Session *session, const identifier::Table &identifier, HA_CREATE_INFO *create_info, message::Table &table_proto, AlterInfo *alter_info, bool internal_tmp_table, uint32_t select_field_count, bool is_if_not_exists)
Definition: sql_table.cc:1443
void broadcast_refresh(void)
Definition: global.cc:1112
static int prepare_create_table(Session *session, HA_CREATE_INFO *create_info, message::Table &create_proto, AlterInfo *alter_info, bool tmp_table, uint32_t *db_options, KeyInfo **key_info_buffer, uint32_t *key_count, int select_field_count)
Definition: sql_table.cc:507
void unlink_open_table(Table *find)
Definition: sql_base.cc:591
void create_length_to_internal_length(void)
const char * field_name
Definition: create_field.h:35
int(* qsort_cmp)(const void *, const void *)
Definition: qsort_cmp.h:26
virtual String * val_str(String *str)=0
Field::utype unireg_check
Definition: create_field.h:61
Table * lock_table_name_if_not_cached(const identifier::Table &)
Definition: sql_base.cc:760
enum_field_types sql_type
Definition: create_field.h:40
#define KEY_DEFAULT_PACK_LENGTH
Definition: definitions.h:174
memory::Root * mem_root
Definition: session.h:118
drizzle_system_variables & variables
Definition: session.h:199
char * strdup(const char *)
Duplicate a null-terminated string into memory allocated from within the specified Root...
Definition: root.cc:328
const charset_info_st * charset
Definition: create_field.h:64