summaryrefslogtreecommitdiff
path: root/sql/sql_table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r--sql/sql_table.cc230
1 files changed, 76 insertions, 154 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index e94541b5711..a025bca286b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
*/
/* drop and alter of tables */
@@ -6543,8 +6543,16 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
*new_part= new_key->key_part;
key_part < end; key_part++, new_part++)
{
+ /*
+ For prefix keys KEY_PART_INFO::field points to cloned Field
+ object with adjusted length. So below we have to check field
+ indexes instead of simply comparing pointers to Field objects.
+ */
Create_field *new_field= alter_info->create_list.elem(new_part->fieldnr);
- const Field *old_field= table->field[key_part->fieldnr - 1];
+ if (!new_field->field ||
+ new_field->field->field_index != key_part->fieldnr - 1)
+ return Compare_keys::NotEqual;
+
/*
If there is a change in index length due to column expansion
like varchar(X) changed to varchar(X + N) and has a compatible
@@ -6554,6 +6562,7 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
Key definition has changed if we are using a different field or
if the user key part length is different.
*/
+ const Field *old_field= table->field[key_part->fieldnr - 1];
auto old_field_len= old_field->pack_length();
if (old_field->type() == MYSQL_TYPE_VARCHAR)
@@ -6571,15 +6580,6 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
}
else if (key_part->length != new_part->length)
return Compare_keys::NotEqual;
-
- /*
- For prefix keys KEY_PART_INFO::field points to cloned Field
- object with adjusted length. So below we have to check field
- indexes instead of simply comparing pointers to Field objects.
- */
- if (!new_field->field ||
- new_field->field->field_index != key_part->fieldnr - 1)
- return Compare_keys::NotEqual;
}
/*
@@ -8992,6 +8992,52 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table,
}
}
+ /*
+ Normally, an attempt to modify an FK parent table will cause
+ FK children to be prelocked, so the table-being-altered cannot
+ be modified by a cascade FK action, because ALTER holds a lock
+ and prelocking will wait.
+
+ But if a new FK is being added by this very ALTER, then the target
+ table is not locked yet (it's a temporary table). So, we have to
+ lock FK parents explicitly.
+ */
+ if (alter_info->flags & ALTER_ADD_FOREIGN_KEY)
+ {
+ List_iterator<Key> fk_list_it(alter_info->key_list);
+
+ while (Key *key= fk_list_it++)
+ {
+ if (key->type != Key::FOREIGN_KEY)
+ continue;
+
+ Foreign_key *fk= static_cast<Foreign_key*>(key);
+ char dbuf[NAME_LEN];
+ char tbuf[NAME_LEN];
+ const char *ref_db= (fk->ref_db.str ?
+ fk->ref_db.str :
+ alter_ctx->new_db.str);
+ const char *ref_table= fk->ref_table.str;
+ MDL_request mdl_request;
+
+ if (lower_case_table_names)
+ {
+ strmake_buf(dbuf, ref_db);
+ my_casedn_str(system_charset_info, dbuf);
+ strmake_buf(tbuf, ref_table);
+ my_casedn_str(system_charset_info, tbuf);
+ ref_db= dbuf;
+ ref_table= tbuf;
+ }
+
+ mdl_request.init(MDL_key::TABLE, ref_db, ref_table, MDL_SHARED_NO_WRITE,
+ MDL_TRANSACTION);
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
+ DBUG_RETURN(true);
+ }
+ }
+
DBUG_RETURN(false);
}
@@ -10039,6 +10085,7 @@ do_continue:;
/* Mark that we have created table in storage engine. */
no_ha_table= false;
+ DEBUG_SYNC(thd, "alter_table_intermediate_table_created");
/* Open the table since we need to copy the data. */
new_table= thd->create_and_open_tmp_table(&frm,
@@ -10054,54 +10101,6 @@ do_continue:;
/* in case of alter temp table send the tracker in OK packet */
SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
}
- else
- {
- /*
- Normally, an attempt to modify an FK parent table will cause
- FK children to be prelocked, so the table-being-altered cannot
- be modified by a cascade FK action, because ALTER holds a lock
- and prelocking will wait.
-
- But if a new FK is being added by this very ALTER, then the target
- table is not locked yet (it's a temporary table). So, we have to
- lock FK parents explicitly.
- */
- if (alter_info->flags & ALTER_ADD_FOREIGN_KEY)
- {
- List <FOREIGN_KEY_INFO> fk_list;
- List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
- FOREIGN_KEY_INFO *fk;
-
- /* tables_opened can be > 1 only for MERGE tables */
- DBUG_ASSERT(tables_opened == 1);
- DBUG_ASSERT(&table_list->next_global == thd->lex->query_tables_last);
-
- new_table->file->get_foreign_key_list(thd, &fk_list);
- while ((fk= fk_list_it++))
- {
- MDL_request mdl_request;
-
- if (lower_case_table_names)
- {
- char buf[NAME_LEN];
- size_t len;
- strmake_buf(buf, fk->referenced_db->str);
- len = my_casedn_str(files_charset_info, buf);
- thd->make_lex_string(fk->referenced_db, buf, len);
- strmake_buf(buf, fk->referenced_table->str);
- len = my_casedn_str(files_charset_info, buf);
- thd->make_lex_string(fk->referenced_table, buf, len);
- }
-
- mdl_request.init(MDL_key::TABLE,
- fk->referenced_db->str, fk->referenced_table->str,
- MDL_SHARED_NO_WRITE, MDL_TRANSACTION);
- if (thd->mdl_context.acquire_lock(&mdl_request,
- thd->variables.lock_wait_timeout))
- goto err_new_table_cleanup;
- }
- }
- }
/*
Note: In case of MERGE table, we do not attach children. We do not
@@ -10925,18 +10924,6 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
}
-static void flush_checksum(ha_checksum *row_crc, uchar **checksum_start,
- size_t *checksum_length)
-{
- if (*checksum_start)
- {
- *row_crc= my_checksum(*row_crc, *checksum_start, *checksum_length);
- *checksum_start= NULL;
- *checksum_length= 0;
- }
-}
-
-
bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
HA_CHECK_OPT *check_opt)
{
@@ -11013,96 +11000,31 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
if (!(check_opt->flags & T_EXTEND) &&
(((t->file->ha_table_flags() & HA_HAS_OLD_CHECKSUM) && thd->variables.old_mode) ||
((t->file->ha_table_flags() & HA_HAS_NEW_CHECKSUM) && !thd->variables.old_mode)))
- protocol->store((ulonglong)t->file->checksum());
+ {
+ if (t->file->info(HA_STATUS_VARIABLE))
+ protocol->store_null();
+ else
+ protocol->store((longlong)t->file->stats.checksum);
+ }
else if (check_opt->flags & T_QUICK)
protocol->store_null();
else
{
- /* calculating table's checksum */
- ha_checksum crc= 0;
- DBUG_ASSERT(t->s->last_null_bit_pos < 8);
- uchar null_mask= (t->s->last_null_bit_pos ?
- (256 - (1 << t->s->last_null_bit_pos)):
- 0);
-
- t->use_all_stored_columns();
-
- if (t->file->ha_rnd_init(1))
- protocol->store_null();
- else
+ int error= t->file->calculate_checksum();
+ if (thd->killed)
{
- for (;;)
- {
- if (thd->killed)
- {
- /*
- we've been killed; let handler clean up, and remove the
- partial current row from the recordset (embedded lib)
- */
- t->file->ha_rnd_end();
- thd->protocol->remove_last_row();
- goto err;
- }
- ha_checksum row_crc= 0;
- int error= t->file->ha_rnd_next(t->record[0]);
- if (unlikely(error))
- {
- break;
- }
- if (t->s->null_bytes)
- {
- /* fix undefined null bits */
- t->record[0][t->s->null_bytes-1] |= null_mask;
- if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
- t->record[0][0] |= 1;
-
- row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
- }
-
- uchar *checksum_start= NULL;
- size_t checksum_length= 0;
- for (uint i= 0; i < t->s->fields; i++ )
- {
- Field *f= t->field[i];
-
- if (! thd->variables.old_mode && f->is_real_null(0))
- {
- flush_checksum(&row_crc, &checksum_start, &checksum_length);
- continue;
- }
- /*
- BLOB and VARCHAR have pointers in their field, we must convert
- to string; GEOMETRY is implemented on top of BLOB.
- BIT may store its data among NULL bits, convert as well.
- */
- switch (f->type()) {
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_GEOMETRY:
- case MYSQL_TYPE_BIT:
- {
- flush_checksum(&row_crc, &checksum_start, &checksum_length);
- String tmp;
- f->val_str(&tmp);
- row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(),
- tmp.length());
- break;
- }
- default:
- if (!checksum_start)
- checksum_start= f->ptr;
- DBUG_ASSERT(checksum_start + checksum_length == f->ptr);
- checksum_length+= f->pack_length();
- break;
- }
- }
- flush_checksum(&row_crc, &checksum_start, &checksum_length);
-
- crc+= row_crc;
- }
- protocol->store((ulonglong)crc);
+ /*
+ we've been killed; let handler clean up, and remove the
+ partial current row from the recordset (embedded lib)
+ */
t->file->ha_rnd_end();
+ thd->protocol->remove_last_row();
+ goto err;
}
+ if (error)
+ protocol->store_null();
+ else
+ protocol->store((longlong)t->file->stats.checksum);
}
trans_rollback_stmt(thd);
close_thread_tables(thd);