~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
54
54
namespace drizzled
55
55
{
56
56
 
 
57
extern plugin::StorageEngine *myisam_engine;
57
58
extern pid_t current_pid;
58
59
 
59
60
bool is_primary_key(KEY *key_info)
184
185
      table->db_type= share->db_type();
185
186
  }
186
187
 
187
 
  if (!drop_temporary && lock_table_names_exclusively(session, tables))
 
188
  if (not drop_temporary && lock_table_names_exclusively(session, tables))
188
189
  {
189
190
    pthread_mutex_unlock(&LOCK_open);
190
191
    return 1;
231
232
        goto err_with_placeholders;
232
233
      }
233
234
    }
234
 
    TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? INTERNAL_TMP_TABLE : NO_TMP_TABLE);
 
235
    TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? INTERNAL_TMP_TABLE : STANDARD_TABLE);
235
236
 
236
237
    if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
237
238
    {
249
250
 
250
251
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
251
252
      {
252
 
        error= 0;
 
253
        error= 0;
253
254
        session->clear_error();
254
255
      }
255
256
 
261
262
    }
262
263
 
263
264
    if (error == 0 || (if_exists && foreign_key_error == false))
264
 
        write_bin_log_drop_table(session, if_exists, db, table->table_name);
 
265
    {
 
266
      ReplicationServices &replication_services= ReplicationServices::singleton();
 
267
      replication_services.dropTable(session, string(db), string(table->table_name), if_exists);
 
268
    }
265
269
 
266
270
    if (error)
267
271
    {
757
761
        }
758
762
      }
759
763
    }
760
 
    /* Don't pack rows in old tables if the user has requested this */
761
 
    if ((sql_field->flags & BLOB_FLAG) ||
762
 
        (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED))
 
764
 
 
765
    /** @todo Get rid of this MyISAM-specific crap. */
 
766
    if (create_info->db_type == myisam_engine &&
 
767
        ((sql_field->flags & BLOB_FLAG) ||
 
768
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED)))
763
769
      (*db_options)|= HA_OPTION_PACK_RECORD;
764
770
    it2.rewind();
765
771
  }
1451
1457
    }
1452
1458
  }
1453
1459
 
1454
 
  /*
1455
 
    Don't write statement if:
1456
 
    - It is an internal temporary table,
1457
 
    - Row-based logging is used and it we are creating a temporary table, or
1458
 
    - The binary log is not open.
1459
 
    Otherwise, the statement shall be binlogged.
1460
 
   */
1461
1460
  if (not internal_tmp_table && not lex_identified_temp_table)
1462
 
    write_bin_log(session, session->query.c_str());
 
1461
  {
 
1462
    ReplicationServices &replication_services= ReplicationServices::singleton();
 
1463
    replication_services.createTable(session, *table_proto);
 
1464
  }
1463
1465
  error= false;
1464
1466
unlock_and_end:
1465
1467
  pthread_mutex_unlock(&LOCK_open);
1949
1951
}
1950
1952
 
1951
1953
/*
 
1954
  We have to write the query before we unlock the named table.
 
1955
 
 
1956
  Since temporary tables are not replicated under row-based
 
1957
  replication, CREATE TABLE ... LIKE ... needs special
 
1958
  treatement.  We have four cases to consider, according to the
 
1959
  following decision table:
 
1960
 
 
1961
  ==== ========= ========= ==============================
 
1962
  Case    Target    Source Write to binary log
 
1963
  ==== ========= ========= ==============================
 
1964
  1       normal    normal Original statement
 
1965
  2       normal temporary Generated statement
 
1966
  3    temporary    normal Nothing
 
1967
  4    temporary temporary Nothing
 
1968
  ==== ========= ========= ==============================
 
1969
*/
 
1970
static bool replicateCreateTableLike(Session *session, TableList *table, Table *name_lock,
 
1971
                                     bool is_src_table_tmp, bool is_if_not_exists)
 
1972
{
 
1973
  if (is_src_table_tmp)
 
1974
  {
 
1975
    char buf[2048];
 
1976
    String query(buf, sizeof(buf), system_charset_info);
 
1977
    query.length(0);  // Have to zero it since constructor doesn't
 
1978
 
 
1979
 
 
1980
    /*
 
1981
      Here we open the destination table, on which we already have
 
1982
      name-lock. This is needed for store_create_info() to work.
 
1983
      The table will be closed by unlink_open_table() at the end
 
1984
      of this function.
 
1985
    */
 
1986
    table->table= name_lock;
 
1987
    pthread_mutex_lock(&LOCK_open); /* Open new table we have just acquired */
 
1988
    if (session->reopen_name_locked_table(table, false))
 
1989
    {
 
1990
      pthread_mutex_unlock(&LOCK_open);
 
1991
      return false;
 
1992
    }
 
1993
    pthread_mutex_unlock(&LOCK_open);
 
1994
 
 
1995
    int result= store_create_info(table, &query, is_if_not_exists);
 
1996
 
 
1997
    assert(result == 0); // store_create_info() always return 0
 
1998
    write_bin_log(session, query.ptr());
 
1999
  }
 
2000
  else                                      // Case 1
 
2001
  {
 
2002
    write_bin_log(session, session->query.c_str());
 
2003
  }
 
2004
 
 
2005
  return true;
 
2006
}
 
2007
 
 
2008
  /*
 
2009
    Create a new table by copying from source table
 
2010
 
 
2011
    Altough exclusive name-lock on target table protects us from concurrent
 
2012
    DML and DDL operations on it we still want to wrap .FRM creation and call
 
2013
    to plugin::StorageEngine::createTable() in critical section protected by
 
2014
    LOCK_open in order to provide minimal atomicity against operations which
 
2015
    disregard name-locks, like I_S implementation, for example. This is a
 
2016
    temporary and should not be copied. Instead we should fix our code to
 
2017
    always honor name-locks.
 
2018
 
 
2019
    Also some engines (e.g. NDB cluster) require that LOCK_open should be held
 
2020
    during the call to plugin::StorageEngine::createTable().
 
2021
    See bug #28614 for more info.
 
2022
  */
 
2023
static bool create_table_wrapper(Session &session, message::Table& create_table_proto,
 
2024
                                 TableIdentifier &destination_identifier,
 
2025
                                 TableIdentifier &src_table,
 
2026
                                 bool lex_identified_temp_table, bool is_engine_set)
 
2027
{
 
2028
  int protoerr= EEXIST;
 
2029
  message::Table new_proto;
 
2030
  message::Table src_proto;
 
2031
 
 
2032
  protoerr= plugin::StorageEngine::getTableDefinition(session,
 
2033
                                                      src_table,
 
2034
                                                      &src_proto);
 
2035
  new_proto.CopyFrom(src_proto);
 
2036
 
 
2037
  if (lex_identified_temp_table)
 
2038
  {
 
2039
    new_proto.set_type(message::Table::TEMPORARY);
 
2040
  }
 
2041
  else
 
2042
  {
 
2043
    new_proto.set_type(message::Table::STANDARD);
 
2044
  }
 
2045
 
 
2046
  if (is_engine_set)
 
2047
  {
 
2048
    message::Table::StorageEngine *protoengine;
 
2049
 
 
2050
    protoengine= new_proto.mutable_engine();
 
2051
    protoengine->set_name(create_table_proto.engine().name());
 
2052
  }
 
2053
 
 
2054
  if (protoerr == EEXIST)
 
2055
  {
 
2056
    plugin::StorageEngine* engine= plugin::StorageEngine::findByName(session,
 
2057
                                                                     new_proto.engine().name());
 
2058
 
 
2059
    if (engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY) == false)
 
2060
    {
 
2061
      string dst_proto_path(destination_identifier.getPath());
 
2062
      dst_proto_path.append(".dfe");
 
2063
 
 
2064
      protoerr= drizzle_write_proto_file(dst_proto_path.c_str(), &new_proto);
 
2065
    }
 
2066
    else
 
2067
    {
 
2068
      protoerr= 0;
 
2069
    }
 
2070
  }
 
2071
 
 
2072
  if (protoerr)
 
2073
  {
 
2074
    if (errno == ENOENT)
 
2075
      my_error(ER_BAD_DB_ERROR,MYF(0), destination_identifier.getSchemaName());
 
2076
    else
 
2077
      my_error(ER_CANT_CREATE_FILE, MYF(0), destination_identifier.getPath(), errno);
 
2078
 
 
2079
    return false;
 
2080
  }
 
2081
 
 
2082
  /*
 
2083
    As mysql_truncate don't work on a new table at this stage of
 
2084
    creation, instead create the table directly (for both normal
 
2085
    and temporary tables).
 
2086
  */
 
2087
  int err= plugin::StorageEngine::createTable(session,
 
2088
                                              destination_identifier,
 
2089
                                              true, new_proto);
 
2090
 
 
2091
  return err ? false : true;
 
2092
}
 
2093
 
 
2094
/*
1952
2095
  Create a table identical to the specified table
1953
2096
 
1954
2097
  SYNOPSIS
1972
2115
  Table *name_lock= 0;
1973
2116
  char *db= table->db;
1974
2117
  char *table_name= table->table_name;
1975
 
  int  err;
1976
2118
  bool res= true;
1977
2119
  uint32_t not_used;
1978
 
  message::Table src_proto;
1979
2120
  bool lex_identified_temp_table=
1980
2121
    (create_table_proto.type() == message::Table::TEMPORARY);
 
2122
  bool was_created;
1981
2123
 
1982
2124
  /*
1983
2125
    By opening source table we guarantee that it exists and no concurrent
1991
2133
  if (session->open_tables_from_list(&src_table, &not_used))
1992
2134
    return true;
1993
2135
 
1994
 
  TableIdentifier destination_identifier(db, table_name, lex_identified_temp_table ? TEMP_TABLE : NO_TMP_TABLE);
 
2136
  TableIdentifier destination_identifier(db, table_name,
 
2137
                                         lex_identified_temp_table ? TEMP_TABLE : STANDARD_TABLE);
 
2138
 
 
2139
  TableIdentifier src_identifier(src_table->table->s->db.str,
 
2140
                                 src_table->table->s->table_name.str, src_table->table->s->tmp_table);
 
2141
 
 
2142
 
1995
2143
 
1996
2144
  /*
1997
2145
    Check that destination tables does not exist. Note that its name
1998
2146
    was already checked when it was added to the table list.
1999
2147
  */
 
2148
  bool table_exists= false;
2000
2149
  if (lex_identified_temp_table)
2001
2150
  {
2002
2151
    if (session->find_temporary_table(db, table_name))
2003
 
      goto table_exists;
 
2152
    {
 
2153
      table_exists= true;
 
2154
    }
2004
2155
  }
2005
2156
  else
2006
2157
  {
2007
2158
    if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
2008
 
      goto err;
 
2159
    {
 
2160
      if (name_lock)
 
2161
      {
 
2162
        pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
 
2163
        session->unlink_open_table(name_lock);
 
2164
        pthread_mutex_unlock(&LOCK_open);
 
2165
      }
 
2166
 
 
2167
      return res;
 
2168
    }
 
2169
 
2009
2170
    if (not name_lock)
2010
 
      goto table_exists;
2011
 
 
2012
 
    if (plugin::StorageEngine::doesTableExist(*session, destination_identifier))
2013
 
      goto table_exists;
 
2171
    {
 
2172
      table_exists= true;
 
2173
    }
 
2174
    else if (plugin::StorageEngine::doesTableExist(*session, destination_identifier))
 
2175
    {
 
2176
      table_exists= true;
 
2177
    }
2014
2178
  }
2015
2179
 
2016
 
  /*
2017
 
    Create a new table by copying from source table
2018
 
 
2019
 
    Altough exclusive name-lock on target table protects us from concurrent
2020
 
    DML and DDL operations on it we still want to wrap .FRM creation and call
2021
 
    to plugin::StorageEngine::createTable() in critical section protected by
2022
 
    LOCK_open in order to provide minimal atomicity against operations which
2023
 
    disregard name-locks, like I_S implementation, for example. This is a
2024
 
    temporary and should not be copied. Instead we should fix our code to
2025
 
    always honor name-locks.
2026
 
 
2027
 
    Also some engines (e.g. NDB cluster) require that LOCK_open should be held
2028
 
    during the call to plugin::StorageEngine::createTable().
2029
 
    See bug #28614 for more info.
2030
 
  */
2031
 
  pthread_mutex_lock(&LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
 
2180
  if (table_exists)
2032
2181
  {
2033
 
    int protoerr= EEXIST;
2034
 
 
2035
 
    TableIdentifier identifier(src_table->table->s->db.str,
2036
 
                               src_table->table->s->table_name.str, src_table->table->s->tmp_table);
2037
 
    protoerr= plugin::StorageEngine::getTableDefinition(*session,
2038
 
                                                        identifier,
2039
 
                                                        &src_proto);
2040
 
 
2041
 
    message::Table new_proto(src_proto);
2042
 
 
2043
 
    if (lex_identified_temp_table)
 
2182
    if (is_if_not_exists)
2044
2183
    {
2045
 
      new_proto.set_type(message::Table::TEMPORARY);
 
2184
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
 
2185
      snprintf(warn_buff, sizeof(warn_buff),
 
2186
               ER(ER_TABLE_EXISTS_ERROR), table_name);
 
2187
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
2188
                   ER_TABLE_EXISTS_ERROR,warn_buff);
 
2189
      res= false;
2046
2190
    }
2047
2191
    else
2048
2192
    {
2049
 
      new_proto.set_type(message::Table::STANDARD);
2050
 
    }
2051
 
 
2052
 
    if (is_engine_set)
2053
 
    {
2054
 
      message::Table::StorageEngine *protoengine;
2055
 
 
2056
 
      protoengine= new_proto.mutable_engine();
2057
 
      protoengine->set_name(create_table_proto.engine().name());
2058
 
    }
2059
 
 
2060
 
    if (protoerr == EEXIST)
2061
 
    {
2062
 
      plugin::StorageEngine* engine= plugin::StorageEngine::findByName(*session,
2063
 
                                                                       new_proto.engine().name());
2064
 
 
2065
 
      if (engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY) == false)
2066
 
      {
2067
 
        string dst_proto_path(destination_identifier.getPath());
2068
 
        dst_proto_path.append(".dfe");
2069
 
 
2070
 
        protoerr= drizzle_write_proto_file(dst_proto_path.c_str(), &new_proto);
2071
 
      }
2072
 
      else
2073
 
      {
2074
 
        protoerr= 0;
2075
 
      }
2076
 
    }
2077
 
 
2078
 
    if (protoerr)
2079
 
    {
2080
 
      if (errno == ENOENT)
2081
 
        my_error(ER_BAD_DB_ERROR,MYF(0),db);
2082
 
      else
2083
 
        my_error(ER_CANT_CREATE_FILE, MYF(0), destination_identifier.getPath(), errno);
2084
 
      pthread_mutex_unlock(&LOCK_open);
2085
 
      goto err;
2086
 
    }
2087
 
 
2088
 
    /*
2089
 
      As mysql_truncate don't work on a new table at this stage of
2090
 
      creation, instead create the table directly (for both normal
2091
 
      and temporary tables).
2092
 
    */
2093
 
    err= plugin::StorageEngine::createTable(*session,
2094
 
                                            destination_identifier,
2095
 
                                            true, new_proto);
 
2193
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
 
2194
    }
2096
2195
  }
2097
 
  pthread_mutex_unlock(&LOCK_open);
2098
 
 
2099
 
  if (lex_identified_temp_table)
 
2196
  else // Otherwise we create the table
2100
2197
  {
2101
 
    if (err || !session->open_temporary_table(destination_identifier))
2102
 
    {
 
2198
    pthread_mutex_lock(&LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
 
2199
    was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
 
2200
                                      src_identifier, lex_identified_temp_table, is_engine_set);
 
2201
    pthread_mutex_unlock(&LOCK_open);
 
2202
 
 
2203
    // So we blew the creation of the table, and we scramble to clean up
 
2204
    // anything that might have been created (read... it is a hack)
 
2205
    if (not was_created)
 
2206
    {
 
2207
      if (lex_identified_temp_table)
 
2208
      {
 
2209
        (void) session->rm_temporary_table(engine_arg, destination_identifier);
 
2210
      }
 
2211
      else
 
2212
      {
 
2213
        TableIdentifier identifier(db, table_name, STANDARD_TABLE);
 
2214
        quick_rm_table(*session, identifier);
 
2215
      }
 
2216
    } 
 
2217
    else if (lex_identified_temp_table && not session->open_temporary_table(destination_identifier))
 
2218
    {
 
2219
      // We created, but we can't open... also, a hack.
2103
2220
      (void) session->rm_temporary_table(engine_arg, destination_identifier);
2104
 
      goto err;
2105
2221
    }
2106
 
  }
2107
 
  else if (err)
2108
 
  {
2109
 
    TableIdentifier identifier(db, table_name, NO_TMP_TABLE);
2110
 
    quick_rm_table(*session, identifier);
2111
 
 
2112
 
    goto err;
2113
 
  }
2114
 
 
2115
 
  /*
2116
 
    We have to write the query before we unlock the tables.
2117
 
  */
2118
 
  {
2119
 
    /*
2120
 
       Since temporary tables are not replicated under row-based
2121
 
       replication, CREATE TABLE ... LIKE ... needs special
2122
 
       treatement.  We have four cases to consider, according to the
2123
 
       following decision table:
2124
 
 
2125
 
           ==== ========= ========= ==============================
2126
 
           Case    Target    Source Write to binary log
2127
 
           ==== ========= ========= ==============================
2128
 
           1       normal    normal Original statement
2129
 
           2       normal temporary Generated statement
2130
 
           3    temporary    normal Nothing
2131
 
           4    temporary temporary Nothing
2132
 
           ==== ========= ========= ==============================
2133
 
    */
2134
 
    if (! lex_identified_temp_table)
 
2222
    else
2135
2223
    {
2136
 
      if (src_table->table->s->tmp_table)               // Case 2
 
2224
      if (not lex_identified_temp_table)
2137
2225
      {
2138
 
        char buf[2048];
2139
 
        String query(buf, sizeof(buf), system_charset_info);
2140
 
        query.length(0);  // Have to zero it since constructor doesn't
2141
 
 
2142
 
 
2143
 
        /*
2144
 
          Here we open the destination table, on which we already have
2145
 
          name-lock. This is needed for store_create_info() to work.
2146
 
          The table will be closed by unlink_open_table() at the end
2147
 
          of this function.
2148
 
        */
2149
 
        table->table= name_lock;
2150
 
        pthread_mutex_lock(&LOCK_open); /* Open new table we have just acquired */
2151
 
        if (session->reopen_name_locked_table(table, false))
2152
 
        {
2153
 
          pthread_mutex_unlock(&LOCK_open);
2154
 
          goto err;
2155
 
        }
2156
 
        pthread_mutex_unlock(&LOCK_open);
2157
 
 
2158
 
        int result= store_create_info(table, &query, is_if_not_exists);
2159
 
 
2160
 
        assert(result == 0); // store_create_info() always return 0
2161
 
        write_bin_log(session, query.ptr());
 
2226
        bool rc= replicateCreateTableLike(session, table, name_lock, (src_table->table->s->tmp_table), is_if_not_exists);
 
2227
        (void)rc;
2162
2228
      }
2163
 
      else                                      // Case 1
2164
 
        write_bin_log(session, session->query.c_str());
 
2229
 
 
2230
      res= false;
2165
2231
    }
2166
2232
  }
2167
2233
 
2168
 
  res= false;
2169
 
  goto err;
2170
 
 
2171
 
table_exists:
2172
 
  if (is_if_not_exists)
2173
 
  {
2174
 
    char warn_buff[DRIZZLE_ERRMSG_SIZE];
2175
 
    snprintf(warn_buff, sizeof(warn_buff),
2176
 
             ER(ER_TABLE_EXISTS_ERROR), table_name);
2177
 
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2178
 
                 ER_TABLE_EXISTS_ERROR,warn_buff);
2179
 
    res= false;
2180
 
  }
2181
 
  else
2182
 
    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
2183
 
 
2184
 
err:
2185
2234
  if (name_lock)
2186
2235
  {
2187
2236
    pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2188
2237
    session->unlink_open_table(name_lock);
2189
2238
    pthread_mutex_unlock(&LOCK_open);
2190
2239
  }
 
2240
 
2191
2241
  return(res);
2192
2242
}
2193
2243