Bug #109994 Unexpected 1748 error returns when update stored generated column partition key
Submitted: 8 Feb 2023 19:44 Modified: 9 Feb 2023 5:34
Reporter: Chen Wang (OCA) Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Partitions Severity:S3 (Non-critical)
Version:5.7, 8.0 OS:Any
Assigned to: CPU Architecture:Any
Tags: generated columns, partition, update partiton table

[8 Feb 2023 19:44] Chen Wang
Description:
When update a partition table with a partition key which includes stored generated columns. An Unexpected 1748 error will return if the update change the original rows from one partition to another partition. 

This is because partition_key_modified function doesn't consider partition key with stored generated column.

bool partition_key_modified(TABLE *table, const MY_BITMAP *fields) {
  Field **fld;
  partition_info *part_info = table->part_info;
  DBUG_TRACE;

  if (!part_info) return false;
  if (table->s->db_type()->partition_flags &&
      (table->s->db_type()->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY))
    return false;
  for (fld = part_info->full_part_field_array; *fld; fld++)
--->    if (bitmap_is_set(fields, (*fld)->field_index()) return true;
  return false;
}

(gdb) p/t *fields.bitmap
$74 = 11
(gdb) p (*fld)->gcol_info
$75 = (Value_generator *) 0x7f0b00ce0dc0
(gdb) p (*fld)->m_field_index
$76 = 2

How to repeat:
create table t1 (a int, b int, c int as (a + b) stored, primary key (a,b,c)) partition by key(c) partitions 8;

insert into t1 (a,b) values (1,1),(2,2);

update t1 set a = 4, b = 4 where a = 1 and b = 1 and c = 2;
ERROR 1748 (HY000): Found a row not matching the given partition set

Suggested fix:
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 8920efaa..57f0cbf 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -2475,8 +2475,14 @@ bool partition_key_modified(TABLE *table, const MY_BITMAP *fields) {
   if (table->s->db_type()->partition_flags &&
       (table->s->db_type()->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY))
     return false;
-  for (fld = part_info->full_part_field_array; *fld; fld++)
+  for (fld = part_info->full_part_field_array; *fld; fld++) {
+    if ((*fld)->gcol_info &&
+        bitmap_is_overlapping(fields, &(*fld)->gcol_info->base_columns_map)) {
+      assert((*fld)->gcol_info->get_field_stored());
+      return true;
+    }
     if (bitmap_is_set(fields, (*fld)->field_index())) return true;
+  }
   return false;
 }
[9 Feb 2023 5:34] MySQL Verification Team
Hello Chen Wang,

Thank you for the report and test case.
Verified as described.

regards,
Umesh