summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2022-07-16 16:54:03 +0400
committerAlexey Botchkov <holyfoot@askmonty.org>2022-07-17 01:10:43 +0400
commit8911823f65a6557ce66ea5f8aecd55b115a85606 (patch)
treeeeeeee73708c22dbf584ca1444be46321a670fa1
parent65cc89ed9eb9367a7e068286ddc9a896c478c012 (diff)
downloadmariadb-git-8911823f65a6557ce66ea5f8aecd55b115a85606.tar.gz
MDEV-26546 SIGSEGV's in spider_db_connect on SHOW TABLE and spider_db… …_mbase::connect (and SIGSEGV's in check_vcol_forward_refs and inline_mysql_mutex_lock)
Not the SPIDER issue - happens to INSERT DELAYED. the field::make_new_field does't copy the LONG_UNIQUE_HASH_FIELD flag to the new field. Though the Delayed_insert::get_local_table copies the field->vcol_info for this field. Ad a result the parse_vcol_defs doesn't create the expression for that column so the field->vcol_info->expr is NULL. Which leads to crash. Backported fix for this from 10.5 - the flagg added in the Delayed_insert::get_local_table. Another problem with the USING HASH key is thst the parse_vcol_defs modifies the table->keys content. Then the same parse_vcol_defs is called on the table copy that has keys already modified. Backported fix for that from 10.5 - key copying added tot the Delayed_insert::get_local_table. Finally - the created copy has to clear the expr_arena as this table is not in the thd->open_tables list so won't be cleared automatically.
-rw-r--r--mysql-test/main/delayed.result9
-rw-r--r--mysql-test/main/delayed.test12
-rw-r--r--sql/field.h2
-rw-r--r--sql/sql_insert.cc11
-rw-r--r--sql/table.cc49
-rw-r--r--sql/table.h1
6 files changed, 83 insertions, 1 deletions
diff --git a/mysql-test/main/delayed.result b/mysql-test/main/delayed.result
index ec36e3af46d..fe284dfcdad 100644
--- a/mysql-test/main/delayed.result
+++ b/mysql-test/main/delayed.result
@@ -510,3 +510,12 @@ a b
2 2
3 3
drop table t1;
+#
+# MDEV-26546 SIGSEGV's in spider_db_connect on SHOW TABLE and
+# spider_db_mbase::connect (and SIGSEGV's in check_vcol_forward_refs
+# and inline_mysql_mutex_lock)
+#
+CREATE TABLE t1 (c0 INT,UNIQUE (c0) USING HASH) ENGINE=MYISAM;
+INSERT DELAYED INTO t1 VALUES (0);
+INSERT DELAYED INTO t1 VALUES (0);
+DROP TABLE t1;
diff --git a/mysql-test/main/delayed.test b/mysql-test/main/delayed.test
index 573985fec1f..428a3d4c4b0 100644
--- a/mysql-test/main/delayed.test
+++ b/mysql-test/main/delayed.test
@@ -642,3 +642,15 @@ insert delayed into t1 values (3,3);
flush tables t1;
select * from t1;
drop table t1;
+
+--echo #
+--echo # MDEV-26546 SIGSEGV's in spider_db_connect on SHOW TABLE and
+--echo # spider_db_mbase::connect (and SIGSEGV's in check_vcol_forward_refs
+--echo # and inline_mysql_mutex_lock)
+--echo #
+
+CREATE TABLE t1 (c0 INT,UNIQUE (c0) USING HASH) ENGINE=MYISAM;
+INSERT DELAYED INTO t1 VALUES (0);
+INSERT DELAYED INTO t1 VALUES (0);
+DROP TABLE t1;
+
diff --git a/sql/field.h b/sql/field.h
index d31be2a96cc..7534a506edc 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -706,7 +706,7 @@ public:
enum imagetype { itRAW, itMBR};
utype unireg_check;
- const uint32 field_length; // Length of field
+ uint32 field_length; // Length of field
uint32 flags;
uint16 field_index; // field number in fields array
uchar null_bit; // Bit used to test null bit
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 7e848b3906e..085bb4ac764 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1288,6 +1288,10 @@ values_loop_end:
thd->lex->current_select->first_cond_optimization= 0;
}
+#ifndef EMBEDDED_LIBRARY
+ if (lock_type == TL_WRITE_DELAYED && table->expr_arena)
+ table->expr_arena->free_items();
+#endif
DBUG_RETURN(FALSE);
abort:
@@ -1304,6 +1308,8 @@ abort:
*/
for (Field **ptr= table_list->table->field ; *ptr ; ptr++)
(*ptr)->free();
+ if (table_list->table->expr_arena)
+ table_list->table->expr_arena->free_items();
}
#endif
if (table != NULL)
@@ -2663,6 +2669,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
(*field)->invisible= (*org_field)->invisible;
(*field)->orig_table= copy; // Remove connection
(*field)->move_field_offset(adjust_ptrs); // Point at copy->record[0]
+ (*field)->flags|= ((*org_field)->flags & LONG_UNIQUE_HASH_FIELD);
memdup_vcol(client_thd, (*field)->vcol_info);
memdup_vcol(client_thd, (*field)->default_value);
memdup_vcol(client_thd, (*field)->check_constraint);
@@ -2671,6 +2678,10 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
}
*field=0;
+ if (copy_keys_from_share(copy, client_thd->mem_root))
+ goto error;
+
+
if (share->virtual_fields || share->default_expressions ||
share->default_fields)
{
diff --git a/sql/table.cc b/sql/table.cc
index 00b498fdd77..7957f2da593 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -3682,6 +3682,55 @@ static void print_long_unique_table(TABLE *table)
}
#endif
+bool copy_keys_from_share(TABLE *outparam, MEM_ROOT *root)
+{
+ TABLE_SHARE *share= outparam->s;
+ if (share->key_parts)
+ {
+ KEY *key_info, *key_info_end;
+ KEY_PART_INFO *key_part;
+
+ if (!multi_alloc_root(root, &key_info, share->keys*sizeof(KEY),
+ &key_part, share->ext_key_parts*sizeof(KEY_PART_INFO),
+ NullS))
+ return 1;
+
+ outparam->key_info= key_info;
+
+ memcpy(key_info, share->key_info, sizeof(*key_info)*share->keys);
+ memcpy(key_part, key_info->key_part, sizeof(*key_part)*share->ext_key_parts);
+
+ my_ptrdiff_t adjust_ptrs= PTR_BYTE_DIFF(key_part, key_info->key_part);
+ for (key_info_end= key_info + share->keys ;
+ key_info < key_info_end ;
+ key_info++)
+ {
+ key_info->table= outparam;
+ key_info->key_part= reinterpret_cast<KEY_PART_INFO*>
+ (reinterpret_cast<char*>(key_info->key_part) + adjust_ptrs);
+ if (key_info->algorithm == HA_KEY_ALG_LONG_HASH)
+ key_info->flags&= ~HA_NOSAME;
+ }
+ for (KEY_PART_INFO *key_part_end= key_part+share->ext_key_parts;
+ key_part < key_part_end;
+ key_part++)
+ {
+ Field *field= key_part->field= outparam->field[key_part->fieldnr - 1];
+ if (field->key_length() != key_part->length &&
+ !(field->flags & BLOB_FLAG))
+ {
+ /*
+ We are using only a prefix of the column as a key:
+ Create a new field for the key part that matches the index
+ */
+ field= key_part->field=field->make_new_field(root, outparam, 0);
+ field->field_length= key_part->length;
+ }
+ }
+ }
+ return 0;
+}
+
/*
Open a table based on a TABLE_SHARE
diff --git a/sql/table.h b/sql/table.h
index 214b90a4171..c9503b54934 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -3214,6 +3214,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
uint ha_open_flags, TABLE *outparam,
bool is_create_table,
List<String> *partitions_to_open= NULL);
+bool copy_keys_from_share(TABLE *outparam, MEM_ROOT *root);
bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
bool *error_reported, vcol_init_mode expr);
TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,