~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

  • Committer: Monty Taylor
  • Date: 2010-06-02 22:35:45 UTC
  • mto: This revision was merged to the branch mainline in revision 1586.
  • Revision ID: mordred@inaugust.com-20100602223545-q8ekf9b40a85nwuf
Rearragned unittests into a single exe because of how we need to link it
(thanks lifeless)
Link with server symbols without needing to build a library.
Added an additional atomics test which tests whatever version of the atomics
lib the running platform would actually use.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
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 */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/* drop and alter of tables */
17
17
 
36
36
#include "drizzled/transaction_services.h"
37
37
#include <drizzled/table_proto.h>
38
38
#include <drizzled/plugin/client.h>
39
 
#include <drizzled/identifier.h>
 
39
#include <drizzled/table_identifier.h>
40
40
#include "drizzled/internal/m_string.h"
41
41
#include "drizzled/global_charset_info.h"
42
42
#include "drizzled/charset.h"
43
43
 
44
 
#include "drizzled/definition/cache.h"
45
 
 
46
44
 
47
45
#include "drizzled/statement/alter_table.h"
48
46
#include "drizzled/sql_table.h"
51
49
#include <algorithm>
52
50
#include <sstream>
53
51
 
54
 
#include <boost/unordered_set.hpp>
55
 
 
56
52
using namespace std;
57
53
 
58
54
namespace drizzled
107
103
    cursor
108
104
*/
109
105
 
110
 
void write_bin_log(Session *session, const std::string &query)
 
106
void write_bin_log(Session *session,
 
107
                   char const *query)
111
108
{
112
109
  TransactionServices &transaction_services= TransactionServices::singleton();
113
110
  transaction_services.rawStatement(session, query);
114
111
}
115
112
 
 
113
 
 
114
/* Should should be refactored to go away */
 
115
void write_bin_log_drop_table(Session *session, bool if_exists, const char *db_name, const char *table_name)
 
116
{
 
117
  TransactionServices &transaction_services= TransactionServices::singleton();
 
118
  string built_query;
 
119
 
 
120
  if (if_exists)
 
121
    built_query.append("DROP TABLE IF EXISTS ");
 
122
  else
 
123
    built_query.append("DROP TABLE ");
 
124
 
 
125
  built_query.append("`");
 
126
  if (session->db.empty() || strcmp(db_name, session->db.c_str()) != 0)
 
127
  {
 
128
    built_query.append(db_name);
 
129
    built_query.append("`.`");
 
130
  }
 
131
 
 
132
  built_query.append(table_name);
 
133
  built_query.append("`");
 
134
  transaction_services.rawStatement(session, built_query);
 
135
}
 
136
 
116
137
/*
117
138
  Execute the drop of a normal or temporary table
118
139
 
124
145
                        In this case we give an warning of level 'NOTE'
125
146
    drop_temporary      Only drop temporary tables
126
147
 
127
 
  @todo
 
148
  TODO:
128
149
    When logging to the binary log, we should log
129
150
    tmp_tables and transactional tables as separate statements if we
130
151
    are in a transaction;  This is needed to get these tables into the
148
169
  int error= 0;
149
170
  bool foreign_key_error= false;
150
171
 
151
 
  {
152
 
    table::Cache::singleton().mutex().lock(); /* Part 2 of rm a table */
153
 
 
154
 
    if (not drop_temporary && session->lock_table_names_exclusively(tables))
155
 
    {
156
 
      table::Cache::singleton().mutex().unlock();
157
 
      return 1;
158
 
    }
159
 
 
160
 
    /* Don't give warnings for not found errors, as we already generate notes */
161
 
    session->no_warnings_for_error= 1;
162
 
 
163
 
    for (table= tables; table; table= table->next_local)
164
 
    {
165
 
      TableIdentifier tmp_identifier(table->getSchemaName(), table->getTableName());
166
 
 
167
 
      error= session->drop_temporary_table(tmp_identifier);
168
 
 
169
 
      switch (error) {
170
 
      case  0:
171
 
        // removed temporary table
172
 
        continue;
173
 
      case -1:
 
172
  pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
 
173
 
 
174
  /*
 
175
    If we have the table in the definition cache, we don't have to check the
 
176
    .frm cursor to find if the table is a normal table (not view) and what
 
177
    engine to use.
 
178
  */
 
179
 
 
180
  for (table= tables; table; table= table->next_local)
 
181
  {
 
182
    TableIdentifier identifier(table->db, table->table_name);
 
183
    TableShare *share;
 
184
    table->db_type= NULL;
 
185
 
 
186
    if ((share= TableShare::getShare(identifier)))
 
187
    {
 
188
      table->db_type= share->db_type();
 
189
    }
 
190
  }
 
191
 
 
192
  if (not drop_temporary && lock_table_names_exclusively(session, tables))
 
193
  {
 
194
    pthread_mutex_unlock(&LOCK_open);
 
195
    return 1;
 
196
  }
 
197
 
 
198
  /* Don't give warnings for not found errors, as we already generate notes */
 
199
  session->no_warnings_for_error= 1;
 
200
 
 
201
  for (table= tables; table; table= table->next_local)
 
202
  {
 
203
    char *db=table->db;
 
204
 
 
205
    error= session->drop_temporary_table(table);
 
206
 
 
207
    switch (error) {
 
208
    case  0:
 
209
      // removed temporary table
 
210
      continue;
 
211
    case -1:
 
212
      error= 1;
 
213
      goto err_with_placeholders;
 
214
    default:
 
215
      // temporary table not found
 
216
      error= 0;
 
217
    }
 
218
 
 
219
    if (drop_temporary == false)
 
220
    {
 
221
      Table *locked_table;
 
222
      abort_locked_tables(session, db, table->table_name);
 
223
      remove_table_from_cache(session, db, table->table_name,
 
224
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
225
                              RTFC_CHECK_KILLED_FLAG);
 
226
      /*
 
227
        If the table was used in lock tables, remember it so that
 
228
        unlock_table_names can free it
 
229
      */
 
230
      if ((locked_table= drop_locked_tables(session, db, table->table_name)))
 
231
        table->table= locked_table;
 
232
 
 
233
      if (session->killed)
 
234
      {
 
235
        error= -1;
 
236
        goto err_with_placeholders;
 
237
      }
 
238
    }
 
239
    TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? message::Table::INTERNAL : message::Table::STANDARD);
 
240
 
 
241
    if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
 
242
    {
 
243
      // Table was not found on disk and table can't be created from engine
 
244
      if (if_exists)
 
245
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
246
                            ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
 
247
                            table->table_name);
 
248
      else
174
249
        error= 1;
175
 
        goto err_with_placeholders;
176
 
      default:
177
 
        // temporary table not found
 
250
    }
 
251
    else
 
252
    {
 
253
      error= plugin::StorageEngine::dropTable(*session, identifier);
 
254
 
 
255
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
 
256
      {
178
257
        error= 0;
179
 
      }
180
 
 
181
 
      if (drop_temporary == false)
182
 
      {
183
 
        Table *locked_table;
184
 
        abort_locked_tables(session, tmp_identifier);
185
 
        table::Cache::singleton().removeTable(session, tmp_identifier,
186
 
                                              RTFC_WAIT_OTHER_THREAD_FLAG |
187
 
                                              RTFC_CHECK_KILLED_FLAG);
188
 
        /*
189
 
          If the table was used in lock tables, remember it so that
190
 
          unlock_table_names can free it
191
 
        */
192
 
        if ((locked_table= drop_locked_tables(session, tmp_identifier)))
193
 
          table->table= locked_table;
194
 
 
195
 
        if (session->getKilled())
196
 
        {
197
 
          error= -1;
198
 
          goto err_with_placeholders;
199
 
        }
200
 
      }
201
 
      TableIdentifier identifier(table->getSchemaName(), table->getTableName(), table->getInternalTmpTable() ? message::Table::INTERNAL : message::Table::STANDARD);
202
 
 
203
 
      if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
204
 
      {
205
 
        // Table was not found on disk and table can't be created from engine
206
 
        if (if_exists)
207
 
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
208
 
                              ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
209
 
                              table->getTableName());
210
 
        else
211
 
          error= 1;
212
 
      }
213
 
      else
214
 
      {
215
 
        error= plugin::StorageEngine::dropTable(*session, identifier);
216
 
 
217
 
        if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
218
 
        {
219
 
          error= 0;
220
 
          session->clear_error();
221
 
        }
222
 
 
223
 
        if (error == HA_ERR_ROW_IS_REFERENCED)
224
 
        {
225
 
          /* the table is referenced by a foreign key constraint */
226
 
          foreign_key_error= true;
227
 
        }
228
 
      }
229
 
 
230
 
      if (error == 0 || (if_exists && foreign_key_error == false))
231
 
      {
232
 
        TransactionServices &transaction_services= TransactionServices::singleton();
233
 
        transaction_services.dropTable(session, string(table->getSchemaName()), string(table->getTableName()), if_exists);
234
 
      }
235
 
 
236
 
      if (error)
237
 
      {
238
 
        if (wrong_tables.length())
239
 
          wrong_tables.append(',');
240
 
        wrong_tables.append(String(table->getTableName(), system_charset_info));
241
 
      }
242
 
    }
243
 
    /*
244
 
      It's safe to unlock table::Cache::singleton().mutex(): we have an exclusive lock
245
 
      on the table name.
246
 
    */
247
 
    table::Cache::singleton().mutex().unlock();
 
258
        session->clear_error();
 
259
      }
 
260
 
 
261
      if (error == HA_ERR_ROW_IS_REFERENCED)
 
262
      {
 
263
        /* the table is referenced by a foreign key constraint */
 
264
        foreign_key_error= true;
 
265
      }
 
266
    }
 
267
 
 
268
    if (error == 0 || (if_exists && foreign_key_error == false))
 
269
    {
 
270
      TransactionServices &transaction_services= TransactionServices::singleton();
 
271
      transaction_services.dropTable(session, string(db), string(table->table_name), if_exists);
 
272
    }
 
273
 
 
274
    if (error)
 
275
    {
 
276
      if (wrong_tables.length())
 
277
        wrong_tables.append(',');
 
278
      wrong_tables.append(String(table->table_name,system_charset_info));
 
279
    }
248
280
  }
 
281
  /*
 
282
    It's safe to unlock LOCK_open: we have an exclusive lock
 
283
    on the table name.
 
284
  */
 
285
  pthread_mutex_unlock(&LOCK_open);
249
286
  error= 0;
250
287
 
251
288
  if (wrong_tables.length())
262
299
    error= 1;
263
300
  }
264
301
 
265
 
  table::Cache::singleton().mutex().lock(); /* final bit in rm table lock */
 
302
  pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
266
303
 
267
304
err_with_placeholders:
268
 
  tables->unlock_table_names();
269
 
  table::Cache::singleton().mutex().unlock();
 
305
  unlock_table_names(tables, NULL);
 
306
  pthread_mutex_unlock(&LOCK_open);
270
307
  session->no_warnings_for_error= 0;
271
308
 
272
309
  return error;
273
310
}
274
311
 
 
312
 
 
313
/*
 
314
  Quickly remove a table.
 
315
 
 
316
  SYNOPSIS
 
317
    quick_rm_table()
 
318
      base                      The plugin::StorageEngine handle.
 
319
      db                        The database name.
 
320
      table_name                The table name.
 
321
      is_tmp                    If the table is temp.
 
322
 
 
323
  RETURN
 
324
    0           OK
 
325
    != 0        Error
 
326
*/
 
327
bool quick_rm_table(Session& session,
 
328
                    TableIdentifier &identifier)
 
329
{
 
330
  return (plugin::StorageEngine::dropTable(session, identifier));
 
331
}
 
332
 
275
333
/*
276
334
  Sort keys in the following order:
277
335
  - PRIMARY KEY
337
395
    1             Error
338
396
*/
339
397
 
340
 
class typelib_set_member
341
 
{
342
 
public:
343
 
  string s;
344
 
  const CHARSET_INFO * const cs;
345
 
 
346
 
  typelib_set_member(const char* value, unsigned int length,
347
 
                     const CHARSET_INFO * const charset)
348
 
    : s(value, length),
349
 
      cs(charset)
350
 
  {}
351
 
};
352
 
 
353
 
static bool operator==(typelib_set_member const& a, typelib_set_member const& b)
354
 
{
355
 
  return (my_strnncoll(a.cs,
356
 
                       (const unsigned char*)a.s.c_str(), a.s.length(),
357
 
                       (const unsigned char*)b.s.c_str(), b.s.length())==0);
358
 
}
359
 
 
360
 
 
361
 
namespace
362
 
{
363
 
class typelib_set_member_hasher
364
 
{
365
 
  boost::hash<string> hasher;
366
 
public:
367
 
  std::size_t operator()(const typelib_set_member& t) const
368
 
  {
369
 
    return hasher(t.s);
370
 
  }
371
 
};
372
 
}
373
 
 
374
398
static bool check_duplicates_in_interval(const char *set_or_name,
375
399
                                         const char *name, TYPELIB *typelib,
376
400
                                         const CHARSET_INFO * const cs,
381
405
  unsigned int *cur_length= typelib->type_lengths;
382
406
  *dup_val_count= 0;
383
407
 
384
 
  boost::unordered_set<typelib_set_member, typelib_set_member_hasher> interval_set;
385
 
 
386
 
  for ( ; tmp.count > 0; cur_value++, cur_length++)
 
408
  for ( ; tmp.count > 1; cur_value++, cur_length++)
387
409
  {
388
410
    tmp.type_names++;
389
411
    tmp.type_lengths++;
390
412
    tmp.count--;
391
 
    if (interval_set.find(typelib_set_member(*cur_value, *cur_length, cs)) != interval_set.end())
 
413
    if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
392
414
    {
393
415
      my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
394
416
               name,*cur_value,set_or_name);
395
417
      return 1;
396
418
    }
397
 
    else
398
 
      interval_set.insert(typelib_set_member(*cur_value, *cur_length, cs));
399
419
  }
400
420
  return 0;
401
421
}
606
626
 
607
627
    if (sql_field->sql_type == DRIZZLE_TYPE_ENUM)
608
628
    {
609
 
      size_t dummy;
 
629
      uint32_t dummy;
610
630
      const CHARSET_INFO * const cs= sql_field->charset;
611
631
      TYPELIB *interval= sql_field->interval;
612
632
 
639
659
          if (String::needs_conversion(tmp->length(), tmp->charset(),
640
660
                                       cs, &dummy))
641
661
          {
642
 
            size_t cnv_errs;
 
662
            uint32_t cnv_errs;
643
663
            conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
644
664
            interval->type_names[i]= session->mem_root->strmake_root(conv.ptr(), conv.length());
645
665
            interval->type_lengths[i]= conv.length();
681
701
            }
682
702
          }
683
703
        }
684
 
        uint32_t new_dummy;
685
 
        calculate_interval_lengths(cs, interval, &field_length, &new_dummy);
 
704
        calculate_interval_lengths(cs, interval, &field_length, &dummy);
686
705
        sql_field->length= field_length;
687
706
      }
688
707
      set_if_smaller(sql_field->length, (uint32_t)MAX_FIELD_WIDTH-1);
750
769
    /** @todo Get rid of this MyISAM-specific crap. */
751
770
    if (not create_proto.engine().name().compare("MyISAM") &&
752
771
        ((sql_field->flags & BLOB_FLAG) ||
753
 
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)))
 
772
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED)))
754
773
      (*db_options)|= HA_OPTION_PACK_RECORD;
755
774
    it2.rewind();
756
775
  }
818
837
      fk_key_count++;
819
838
      if (((Foreign_key *)key)->validate(alter_info->create_list))
820
839
        return true;
821
 
 
822
840
      Foreign_key *fk_key= (Foreign_key*) key;
823
 
 
824
 
      add_foreign_key_to_table_message(&create_proto,
825
 
                                       fk_key->name.str,
826
 
                                       fk_key->columns,
827
 
                                       fk_key->ref_table,
828
 
                                       fk_key->ref_columns,
829
 
                                       fk_key->delete_opt,
830
 
                                       fk_key->update_opt,
831
 
                                       fk_key->match_opt);
832
 
 
833
841
      if (fk_key->ref_columns.elements &&
834
842
          fk_key->ref_columns.elements != fk_key->columns.elements)
835
843
      {
864
872
             key2->name.str != ignore_key &&
865
873
             !foreign_key_prefix(key, key2)))
866
874
        {
867
 
          /* @todo issue warning message */
 
875
          /* TODO: issue warning message */
868
876
          /* mark that the generated key should be ignored */
869
877
          if (!key2->generated ||
870
878
              (key->generated && key->columns.elements <
1265
1273
}
1266
1274
 
1267
1275
static bool locked_create_event(Session *session,
1268
 
                                const TableIdentifier &identifier,
 
1276
                                TableIdentifier &identifier,
1269
1277
                                HA_CREATE_INFO *create_info,
1270
1278
                                message::Table &table_proto,
1271
1279
                                AlterInfo *alter_info,
1300
1308
        return error;
1301
1309
      }
1302
1310
 
1303
 
      std::string path;
1304
 
      identifier.getSQLPath(path);
1305
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
1306
 
 
 
1311
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1307
1312
      return error;
1308
1313
    }
1309
1314
 
1320
1325
      /*
1321
1326
        @todo improve this error condition.
1322
1327
      */
1323
 
      if (definition::Cache::singleton().find(identifier.getKey()))
 
1328
      if (TableShare::getShare(identifier))
1324
1329
      {
1325
 
        std::string path;
1326
 
        identifier.getSQLPath(path);
1327
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
1328
 
 
 
1330
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1329
1331
        return error;
1330
1332
      }
1331
1333
    }
1401
1403
*/
1402
1404
 
1403
1405
bool mysql_create_table_no_lock(Session *session,
1404
 
                                const TableIdentifier &identifier,
 
1406
                                TableIdentifier &identifier,
1405
1407
                                HA_CREATE_INFO *create_info,
1406
1408
                                message::Table &table_proto,
1407
1409
                                AlterInfo *alter_info,
1423
1425
  assert(identifier.getTableName() == table_proto.name());
1424
1426
  db_options= create_info->table_options;
1425
1427
 
 
1428
  if (create_info->row_type == ROW_TYPE_DYNAMIC)
 
1429
    db_options|=HA_OPTION_PACK_RECORD;
 
1430
 
1426
1431
  set_table_default_charset(create_info, identifier.getSchemaName().c_str());
1427
1432
 
1428
1433
  /* Build a Table object to pass down to the engine, and the do the actual create. */
1429
1434
  if (not mysql_prepare_create_table(session, create_info, table_proto, alter_info,
1430
 
                                     internal_tmp_table,
1431
 
                                     &db_options,
1432
 
                                     &key_info_buffer, &key_count,
1433
 
                                     select_field_count))
 
1435
                                 internal_tmp_table,
 
1436
                                 &db_options,
 
1437
                                 &key_info_buffer, &key_count,
 
1438
                                 select_field_count))
1434
1439
  {
1435
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* CREATE TABLE (some confussion on naming, double check) */
 
1440
    pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
1436
1441
    error= locked_create_event(session,
1437
1442
                               identifier,
1438
1443
                               create_info,
1442
1447
                               internal_tmp_table,
1443
1448
                               db_options, key_count,
1444
1449
                               key_info_buffer);
 
1450
    pthread_mutex_unlock(&LOCK_open);
1445
1451
  }
1446
1452
 
1447
1453
  session->set_proc_info("After create");
1453
1459
  @note the following two methods implement create [temporary] table.
1454
1460
*/
1455
1461
static bool drizzle_create_table(Session *session,
1456
 
                                 const TableIdentifier &identifier,
 
1462
                                 TableIdentifier &identifier,
1457
1463
                                 HA_CREATE_INFO *create_info,
1458
1464
                                 message::Table &table_proto,
1459
1465
                                 AlterInfo *alter_info,
1480
1486
    }
1481
1487
    else
1482
1488
    {
1483
 
      std::string path;
1484
 
      identifier.getSQLPath(path);
1485
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
1489
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1486
1490
      result= true;
1487
1491
    }
1488
1492
  }
1500
1504
 
1501
1505
  if (name_lock)
1502
1506
  {
1503
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* Lock for removing name_lock during table create */
 
1507
    pthread_mutex_lock(&LOCK_open); /* Lock for removing name_lock during table create */
1504
1508
    session->unlink_open_table(name_lock);
 
1509
    pthread_mutex_unlock(&LOCK_open);
1505
1510
  }
1506
1511
 
1507
1512
  return(result);
1512
1517
  Database locking aware wrapper for mysql_create_table_no_lock(),
1513
1518
*/
1514
1519
bool mysql_create_table(Session *session,
1515
 
                        const TableIdentifier &identifier,
 
1520
                        TableIdentifier &identifier,
1516
1521
                        HA_CREATE_INFO *create_info,
1517
1522
                        message::Table &table_proto,
1518
1523
                        AlterInfo *alter_info,
1593
1598
 
1594
1599
  SYNOPSIS
1595
1600
    mysql_rename_table()
1596
 
      session
1597
1601
      base                      The plugin::StorageEngine handle.
1598
1602
      old_db                    The old database name.
1599
1603
      old_name                  The old table name.
1606
1610
*/
1607
1611
 
1608
1612
bool
1609
 
mysql_rename_table(Session &session,
1610
 
                   plugin::StorageEngine *base,
1611
 
                   const TableIdentifier &from,
1612
 
                   const TableIdentifier &to)
 
1613
mysql_rename_table(plugin::StorageEngine *base,
 
1614
                   TableIdentifier &from,
 
1615
                   TableIdentifier &to)
1613
1616
{
 
1617
  Session *session= current_session;
1614
1618
  int error= 0;
1615
1619
 
1616
1620
  assert(base);
1621
1625
    return true;
1622
1626
  }
1623
1627
 
1624
 
  error= base->renameTable(session, from, to);
 
1628
  error= base->renameTable(*session, from, to);
1625
1629
 
1626
1630
  if (error == HA_ERR_WRONG_COMMAND)
1627
1631
  {
1629
1633
  }
1630
1634
  else if (error)
1631
1635
  {
1632
 
    std::string from_path;
1633
 
    std::string to_path;
1634
 
 
1635
 
    from.getSQLPath(from_path);
1636
 
    to.getSQLPath(to_path);
1637
 
 
1638
 
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from_path.c_str();
1639
 
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to_path.c_str();
 
1636
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from.getSQLPath().c_str();
 
1637
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to.getSQLPath().c_str();
1640
1638
 
1641
1639
    my_error(ER_ERROR_ON_RENAME, MYF(0), from_identifier, to_identifier, error);
1642
1640
  }
1660
1658
   the table is closed.
1661
1659
 
1662
1660
  PREREQUISITES
1663
 
    Lock on table::Cache::singleton().mutex()
 
1661
    Lock on LOCK_open
1664
1662
    Win32 clients must also have a WRITE LOCK on the table !
1665
1663
*/
1666
1664
 
1668
1666
                              enum ha_extra_function function)
1669
1667
{
1670
1668
 
1671
 
  safe_mutex_assert_owner(table::Cache::singleton().mutex().native_handle());
 
1669
  safe_mutex_assert_owner(&LOCK_open);
1672
1670
 
1673
1671
  table->cursor->extra(function);
1674
1672
  /* Mark all tables that are in use as 'old' */
1675
 
  session->abortLock(table);    /* end threads waiting on lock */
 
1673
  mysql_lock_abort(session, table);     /* end threads waiting on lock */
1676
1674
 
1677
1675
  /* Wait until all there are no other threads that has this table open */
1678
 
  TableIdentifier identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName());
1679
 
  table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
 
1676
  remove_table_from_cache(session, table->getMutableShare()->getSchemaName(),
 
1677
                          table->getMutableShare()->getTableName(),
 
1678
                          RTFC_WAIT_OTHER_THREAD_FLAG);
1680
1679
}
1681
1680
 
1682
1681
/*
1692
1691
    reopen the table.
1693
1692
 
1694
1693
  PREREQUISITES
1695
 
    Lock on table::Cache::singleton().mutex()
 
1694
    Lock on LOCK_open
1696
1695
    Win32 clients must also have a WRITE LOCK on the table !
1697
1696
*/
1698
1697
 
1703
1702
  /* Close lock if this is not got with LOCK TABLES */
1704
1703
  if (lock)
1705
1704
  {
1706
 
    unlockTables(lock);
 
1705
    mysql_unlock_tables(this, lock);
1707
1706
    lock= NULL;                 // Start locked threads
1708
1707
  }
1709
1708
  /* Close all copies of 'table'.  This also frees all LOCK TABLES lock */
1710
1709
  unlink_open_table(table);
1711
1710
 
1712
 
  /* When lock on table::Cache::singleton().mutex() is freed other threads can continue */
1713
 
  locking::broadcast_refresh();
 
1711
  /* When lock on LOCK_open is freed other threads can continue */
 
1712
  broadcast_refresh();
1714
1713
}
1715
1714
 
1716
1715
/*
1754
1753
  for (table= tables; table; table= table->next_local)
1755
1754
  {
1756
1755
    char table_name[NAME_LEN*2+2];
 
1756
    char* db = table->db;
1757
1757
    bool fatal_error=0;
1758
1758
 
1759
 
    snprintf(table_name, sizeof(table_name), "%s.%s", table->getSchemaName(), table->getTableName());
 
1759
    snprintf(table_name, sizeof(table_name), "%s.%s",db,table->table_name);
1760
1760
    table->lock_type= lock_type;
1761
1761
    /* open only one table from local list of command */
1762
1762
    {
1769
1769
      /*
1770
1770
        Time zone tables and SP tables can be add to lex->query_tables list,
1771
1771
        so it have to be prepared.
1772
 
        @todo Investigate if we can put extra tables into argument instead of using lex->query_tables
 
1772
        TODO: Investigate if we can put extra tables into argument instead of
 
1773
        using lex->query_tables
1773
1774
      */
1774
1775
      lex->query_tables= table;
1775
1776
      lex->query_tables_last= &table->next_global;
1820
1821
    }
1821
1822
 
1822
1823
    /* Close all instances of the table to allow repair to rename files */
1823
 
    if (lock_type == TL_WRITE && table->table->getShare()->getVersion())
 
1824
    if (lock_type == TL_WRITE && table->table->getShare()->version)
1824
1825
    {
1825
 
      table::Cache::singleton().mutex().lock(); /* Lock type is TL_WRITE and we lock to repair the table */
1826
 
      const char *old_message=session->enter_cond(COND_refresh, table::Cache::singleton().mutex(),
1827
 
                                                  "Waiting to get writelock");
1828
 
      session->abortLock(table->table);
1829
 
      TableIdentifier identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1830
 
      table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG);
 
1826
      pthread_mutex_lock(&LOCK_open); /* Lock type is TL_WRITE and we lock to repair the table */
 
1827
      const char *old_message=session->enter_cond(&COND_refresh, &LOCK_open,
 
1828
                                              "Waiting to get writelock");
 
1829
      mysql_lock_abort(session,table->table);
 
1830
      remove_table_from_cache(session, table->table->getMutableShare()->getSchemaName(),
 
1831
                              table->table->getMutableShare()->getTableName(),
 
1832
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
1833
                              RTFC_CHECK_KILLED_FLAG);
1831
1834
      session->exit_cond(old_message);
1832
 
      if (session->getKilled())
 
1835
      if (session->killed)
1833
1836
        goto err;
1834
1837
      open_for_modify= 0;
1835
1838
    }
1916
1919
    if (table->table)
1917
1920
    {
1918
1921
      if (fatal_error)
1919
 
      {
1920
 
        table->table->getMutableShare()->resetVersion();               // Force close of table
1921
 
      }
 
1922
        table->table->getMutableShare()->version=0;               // Force close of table
1922
1923
      else if (open_for_modify)
1923
1924
      {
1924
 
        if (table->table->getShare()->getType())
1925
 
        {
 
1925
        if (table->table->getShare()->tmp_table)
1926
1926
          table->table->cursor->info(HA_STATUS_CONST);
1927
 
        }
1928
1927
        else
1929
1928
        {
1930
 
          boost::unique_lock<boost::mutex> lock(table::Cache::singleton().mutex());
1931
 
          TableIdentifier identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1932
 
          table::Cache::singleton().removeTable(session, identifier, RTFC_NO_FLAG);
 
1929
          pthread_mutex_lock(&LOCK_open);
 
1930
          remove_table_from_cache(session, table->table->getMutableShare()->getSchemaName(),
 
1931
                                  table->table->getMutableShare()->getTableName(), RTFC_NO_FLAG);
 
1932
          pthread_mutex_unlock(&LOCK_open);
1933
1933
        }
1934
1934
      }
1935
1935
    }
1953
1953
  return(true);
1954
1954
}
1955
1955
 
 
1956
/*
 
1957
  We have to write the query before we unlock the named table.
 
1958
 
 
1959
  Since temporary tables are not replicated under row-based
 
1960
  replication, CREATE TABLE ... LIKE ... needs special
 
1961
  treatement.  We have four cases to consider, according to the
 
1962
  following decision table:
 
1963
 
 
1964
  ==== ========= ========= ==============================
 
1965
  Case    Target    Source Write to binary log
 
1966
  ==== ========= ========= ==============================
 
1967
  1       normal    normal Original statement
 
1968
  2       normal temporary Generated statement
 
1969
  3    temporary    normal Nothing
 
1970
  4    temporary temporary Nothing
 
1971
  ==== ========= ========= ==============================
 
1972
*/
 
1973
static bool replicateCreateTableLike(Session *session, TableList *table, Table *name_lock,
 
1974
                                     bool is_src_table_tmp, bool is_if_not_exists)
 
1975
{
 
1976
  if (is_src_table_tmp)
 
1977
  {
 
1978
    char buf[2048];
 
1979
    String query(buf, sizeof(buf), system_charset_info);
 
1980
    query.length(0);  // Have to zero it since constructor doesn't
 
1981
 
 
1982
 
 
1983
    /*
 
1984
      Here we open the destination table, on which we already have
 
1985
      name-lock. This is needed for store_create_info() to work.
 
1986
      The table will be closed by unlink_open_table() at the end
 
1987
      of this function.
 
1988
    */
 
1989
    table->table= name_lock;
 
1990
    pthread_mutex_lock(&LOCK_open); /* Open new table we have just acquired */
 
1991
    if (session->reopen_name_locked_table(table, false))
 
1992
    {
 
1993
      pthread_mutex_unlock(&LOCK_open);
 
1994
      return false;
 
1995
    }
 
1996
    pthread_mutex_unlock(&LOCK_open);
 
1997
 
 
1998
    int result= store_create_info(table, &query, is_if_not_exists);
 
1999
 
 
2000
    assert(result == 0); // store_create_info() always return 0
 
2001
    write_bin_log(session, query.ptr());
 
2002
  }
 
2003
  else                                      // Case 1
 
2004
  {
 
2005
    write_bin_log(session, session->query.c_str());
 
2006
  }
 
2007
 
 
2008
  return true;
 
2009
}
 
2010
 
1956
2011
  /*
1957
2012
    Create a new table by copying from source table
1958
2013
 
1959
2014
    Altough exclusive name-lock on target table protects us from concurrent
1960
2015
    DML and DDL operations on it we still want to wrap .FRM creation and call
1961
2016
    to plugin::StorageEngine::createTable() in critical section protected by
1962
 
    table::Cache::singleton().mutex() in order to provide minimal atomicity against operations which
 
2017
    LOCK_open in order to provide minimal atomicity against operations which
1963
2018
    disregard name-locks, like I_S implementation, for example. This is a
1964
2019
    temporary and should not be copied. Instead we should fix our code to
1965
2020
    always honor name-locks.
1966
2021
 
1967
 
    Also some engines (e.g. NDB cluster) require that table::Cache::singleton().mutex() should be held
 
2022
    Also some engines (e.g. NDB cluster) require that LOCK_open should be held
1968
2023
    during the call to plugin::StorageEngine::createTable().
1969
2024
    See bug #28614 for more info.
1970
2025
  */
1971
2026
static bool create_table_wrapper(Session &session, const message::Table& create_table_proto,
1972
 
                                 const TableIdentifier &destination_identifier,
1973
 
                                 const TableIdentifier &src_table,
 
2027
                                 TableIdentifier &destination_identifier,
 
2028
                                 TableIdentifier &src_table,
1974
2029
                                 bool is_engine_set)
1975
2030
{
1976
2031
  int protoerr= EEXIST;
1977
2032
  message::Table new_proto;
1978
 
  message::table::shared_ptr src_proto;
 
2033
  message::Table src_proto;
1979
2034
 
1980
2035
  protoerr= plugin::StorageEngine::getTableDefinition(session,
1981
2036
                                                      src_table,
1982
2037
                                                      src_proto);
1983
 
  new_proto.CopyFrom(*src_proto);
 
2038
  new_proto.CopyFrom(src_proto);
1984
2039
 
1985
2040
  if (destination_identifier.isTmp())
1986
2041
  {
2021
2076
                                              destination_identifier,
2022
2077
                                              new_proto);
2023
2078
 
2024
 
  if (err == false && not destination_identifier.isTmp())
2025
 
  {
2026
 
    TransactionServices &transaction_services= TransactionServices::singleton();
2027
 
    transaction_services.createTable(&session, new_proto);
2028
 
  }
2029
 
 
2030
2079
  return err ? false : true;
2031
2080
}
2032
2081
 
2046
2095
*/
2047
2096
 
2048
2097
bool mysql_create_like_table(Session* session,
2049
 
                             const TableIdentifier &destination_identifier,
 
2098
                             TableIdentifier &destination_identifier,
2050
2099
                             TableList* table, TableList* src_table,
2051
2100
                             message::Table &create_table_proto,
2052
2101
                             bool is_if_not_exists,
2053
2102
                             bool is_engine_set)
2054
2103
{
 
2104
  char *db= table->db;
 
2105
  char *table_name= table->table_name;
2055
2106
  bool res= true;
2056
2107
  uint32_t not_used;
2057
2108
 
2067
2118
  if (session->open_tables_from_list(&src_table, &not_used))
2068
2119
    return true;
2069
2120
 
2070
 
  TableIdentifier src_identifier(src_table->table->getShare()->getSchemaName(),
2071
 
                                 src_table->table->getShare()->getTableName(), src_table->table->getShare()->getType());
 
2121
  TableIdentifier src_identifier(src_table->table->getMutableShare()->getSchemaName(),
 
2122
                                 src_table->table->getMutableShare()->getTableName(), src_table->table->getMutableShare()->tmp_table);
2072
2123
 
2073
2124
 
2074
2125
 
2081
2132
  bool table_exists= false;
2082
2133
  if (destination_identifier.isTmp())
2083
2134
  {
2084
 
    if (session->find_temporary_table(destination_identifier))
 
2135
    if (session->find_temporary_table(db, table_name))
2085
2136
    {
2086
2137
      table_exists= true;
2087
2138
    }
2088
2139
    else
2089
2140
    {
2090
2141
      bool was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2091
 
                                             src_identifier, is_engine_set);
 
2142
                                        src_identifier, is_engine_set);
2092
2143
      if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2093
2144
      {
2094
 
        (void) session->rm_temporary_table(destination_identifier, true);
 
2145
        (void) session->rm_temporary_table(destination_identifier);
2095
2146
      }
2096
2147
      else if (not session->open_temporary_table(destination_identifier))
2097
2148
      {
2098
2149
        // We created, but we can't open... also, a hack.
2099
 
        (void) session->rm_temporary_table(destination_identifier, true);
 
2150
        (void) session->rm_temporary_table(destination_identifier);
2100
2151
      }
2101
2152
      else
2102
2153
      {
2108
2159
  {
2109
2160
    Table *name_lock= 0;
2110
2161
 
2111
 
    if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
 
2162
    if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
2112
2163
    {
2113
2164
      if (name_lock)
2114
2165
      {
2115
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
 
2166
        pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2116
2167
        session->unlink_open_table(name_lock);
 
2168
        pthread_mutex_unlock(&LOCK_open);
2117
2169
      }
2118
2170
 
2119
2171
      return res;
2129
2181
    }
2130
2182
    else // Otherwise we create the table
2131
2183
    {
2132
 
      bool was_created;
2133
 
      {
2134
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* We lock for CREATE TABLE LIKE to copy table definition */
2135
 
        was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2136
 
                                               src_identifier, is_engine_set);
2137
 
      }
 
2184
      pthread_mutex_lock(&LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
 
2185
      bool was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
 
2186
                                        src_identifier, is_engine_set);
 
2187
      pthread_mutex_unlock(&LOCK_open);
2138
2188
 
2139
2189
      // So we blew the creation of the table, and we scramble to clean up
2140
2190
      // anything that might have been created (read... it is a hack)
2141
2191
      if (not was_created)
2142
2192
      {
2143
 
        plugin::StorageEngine::dropTable(*session, destination_identifier);
 
2193
        quick_rm_table(*session, destination_identifier);
2144
2194
      } 
2145
2195
      else
2146
2196
      {
 
2197
        bool rc= replicateCreateTableLike(session, table, name_lock, (src_table->table->getShare()->tmp_table), is_if_not_exists);
 
2198
        (void)rc;
 
2199
 
2147
2200
        res= false;
2148
2201
      }
2149
2202
    }
2150
2203
 
2151
2204
    if (name_lock)
2152
2205
    {
2153
 
      boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
 
2206
      pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2154
2207
      session->unlink_open_table(name_lock);
 
2208
      pthread_mutex_unlock(&LOCK_open);
2155
2209
    }
2156
2210
  }
2157
2211
 
2161
2215
    {
2162
2216
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
2163
2217
      snprintf(warn_buff, sizeof(warn_buff),
2164
 
               ER(ER_TABLE_EXISTS_ERROR), table->getTableName());
 
2218
               ER(ER_TABLE_EXISTS_ERROR), table_name);
2165
2219
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2166
2220
                   ER_TABLE_EXISTS_ERROR,warn_buff);
2167
2221
      res= false;
2168
2222
    }
2169
2223
    else
2170
2224
    {
2171
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table->getTableName());
 
2225
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
2172
2226
    }
2173
2227
  }
2174
2228