Bug #110774 'show replica status' set the field_flag of 'Second_Behind_Source' NOTNULL
Submitted: 23 Apr 2023 13:52 Modified: 25 Apr 2023 2:49
Reporter: huigen yang Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: Replication Severity:S3 (Non-critical)
Version:8.0.33 OS:Any
Assigned to: MySQL Verification Team CPU Architecture:Any

[23 Apr 2023 13:52] huigen yang
Description:
Dear MySQL team,
The value of Second_Behind_Source can be NULL,just as the source code shows:
sql/replica.cc#3595

if (mi->rli->slave_running) {
    if ((mi->get_master_log_pos() == mi->rli->get_group_master_log_pos()) &&
        (!strcmp(mi->get_master_log_name(),
                 mi->rli->get_group_master_log_name()))) {
      if (mi->slave_running == MYSQL_SLAVE_RUN_CONNECT)
        protocol->store(0LL);
      else
        protocol->store_null();
    } else {
      long time_diff = ((long)(time(nullptr) - mi->rli->last_master_timestamp) -
                        mi->clock_diff_with_master);
      protocol->store(
          (longlong)(mi->rli->last_master_timestamp ? max(0L, time_diff) : 0));
    }
  } else {
    protocol->store_null();
  }

But Second_Behind_Source's field_flag is actually NOT_NULL.
Because of this code:
sql/replica.cc#3390
field_list->push_back(
      new Item_return_int("Seconds_Behind_Source", 10, MYSQL_TYPE_LONGLONG));

class Item_return_int inherits properties m_nullable(defalut false) from parent class Item, so that has the wrong flag NOTNULL.

How to repeat:
I find this bug when I using golang reflect.
Normally,I can use this function to get scanTypeNullInt,
but because of the wrong NOTNULL flag,I get scanTypeInt64 instead.
codes below:
"github.com/go-sql-driver/mysql/fields.go"#140
if mf.flags&flagNotNULL != 0 {
    if mf.flags&flagUnsigned != 0 {
	return scanTypeUint64
    }
    return scanTypeInt64
}
return scanTypeNullInt

Suggested fix:
I have tried a not good enough but useful way.Just add a subclass named Item_return_null_int.
Just like this:

class Item_return_null_int : public Item_int {
 public:
  Item_return_null_int(const char *name_arg, uint length,
                  enum_field_types field_type_arg, longlong value_arg = 0)
      : Item_int(Name_string(name_arg, name_arg ? strlen(name_arg) : 0),
                 value_arg, length) {
    set_data_type(field_type_arg);
    set_nullable(true);  // add this
    unsigned_flag = true;
  }
};

field_list->push_back(
      new Item_return_null_int("Seconds_Behind_Source", 10, MYSQL_TYPE_LONGLONG));
[24 Apr 2023 12:49] MySQL Verification Team
Hi Mr. yang,

Thank you for your bug report.

Your code analysis is quite correct.

However, it is intended behaviour that replica can not be NULL seconds behind master. Replica is always some seconds behind master, which is why NOT NULL is forced and some value is inserted.

Let us know whether this is understandable.
[25 Apr 2023 2:49] huigen yang
Dear MYSQL Team,
Thanks for your reply.
But Replica behind source is not always null indeed.
Probably SQL thread or IO thread is not running,It may also be possible slave don't connect to the master.These situations may all lead to the value of Second_Behind_Source is NULL.
Actually,I found the value of Second_Behind_Source is NULL when i executed ‘show replica status’ in a master.
The same situation also occurs in SQL_Remaining_Delay.I find this description in your Official document:
SQL_Remaining_Delay: When Replica_SQL_Running_State is Waiting until MASTER_DELAY seconds after master executed event, this field contains an integer indicating the number of seconds left of the delay. At other times, this field is NULL.  #https://dev.mysql.com/doc/refman/8.0/en/replication-delayed.html
Best Regards.