Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions mysql-test/main/gtid_check_pos.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# MDEV-8235 Expose check_slave_start_position as SQL function
#
# 1. Set up some basic GTID history
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);
# Get the current GTID position manually and verify it exists
SELECT GTID_CHECK_POS('GTID_POS');
GTID_CHECK_POS('GTID_POS')
1
# 2. Verify invalid inputs
SELECT GTID_CHECK_POS('invalid-format');
ERROR HY000: Could not parse GTID list
SELECT GTID_CHECK_POS(NULL);
GTID_CHECK_POS(NULL)
NULL
# 3. Check for a very old purged GTID
# (Simulate purging all logs)
FLUSH LOGS;
PURGE BINARY LOGS BEFORE NOW();
# Depending on when it is executed, '0-1-1' might still be
# reachable if we haven't actually purged the very first file
# but purge binary logs before now() should remove everything
# except the active one.
# Since we want a deterministic test, let's check
# a completely fake server_id / seq_no that shouldn't exist
SELECT GTID_CHECK_POS('99-99-9999999');
GTID_CHECK_POS('99-99-9999999')
1
# 4. Check for an otherwise valid GTID (right domain and server)
# that is absent (sequence number is in the future).
SELECT GTID_CHECK_POS('ABSENT_GTID');
GTID_CHECK_POS('ABSENT_GTID')
1
# Cleanup
DROP TABLE t1;
44 changes: 44 additions & 0 deletions mysql-test/main/gtid_check_pos.test
Comment thread
gkodinov marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
--source include/have_log_bin.inc

--echo #
--echo # MDEV-8235 Expose check_slave_start_position as SQL function
--echo #

--echo # 1. Set up some basic GTID history
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);

--echo # Get the current GTID position manually and verify it exists
let $pos= `SELECT @@GLOBAL.gtid_binlog_pos`;
--replace_result $pos GTID_POS
eval SELECT GTID_CHECK_POS('$pos');
Comment thread
gkodinov marked this conversation as resolved.

--echo # 2. Verify invalid inputs
--error ER_INCORRECT_GTID_STATE
SELECT GTID_CHECK_POS('invalid-format');
SELECT GTID_CHECK_POS(NULL);

--echo # 3. Check for a very old purged GTID
--echo # (Simulate purging all logs)
FLUSH LOGS;
PURGE BINARY LOGS BEFORE NOW();

--echo # Depending on when it is executed, '0-1-1' might still be
--echo # reachable if we haven't actually purged the very first file
--echo # but purge binary logs before now() should remove everything
--echo # except the active one.

--echo # Since we want a deterministic test, let's check
--echo # a completely fake server_id / seq_no that shouldn't exist
SELECT GTID_CHECK_POS('99-99-9999999');

--echo # 4. Check for an otherwise valid GTID (right domain and server)
--echo # that is absent (sequence number is in the future).
let $server_id= `SELECT @@GLOBAL.server_id`;
let $absent_gtid= 0-$server_id-99999999;
--replace_result $absent_gtid ABSENT_GTID
eval SELECT GTID_CHECK_POS('$absent_gtid');

--echo # Cleanup
DROP TABLE t1;
23 changes: 23 additions & 0 deletions sql/item_cmpfunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2920,6 +2920,29 @@ class Item_func_null_predicate :public Item_bool_func
};


class Item_func_gtid_check_pos :public Item_bool_func
{
String tmp_value;
public:
Item_func_gtid_check_pos(THD *thd, Item *a): Item_bool_func(thd, a) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("gtid_check_pos") };
return name;
}
bool val_bool() override;
bool fix_length_and_dec(THD *thd) override
{
set_maybe_null();
return FALSE;
}

protected:
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_gtid_check_pos>(thd, this); }
};


class Item_func_isnull :public Item_func_null_predicate
{
public:
Expand Down
23 changes: 23 additions & 0 deletions sql/item_create.cc
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,19 @@ class Create_func_connection_id : public Create_func_arg0
};


class Create_func_gtid_check_pos : public Create_func_arg1
{
public:
Item *create_1_arg(THD *thd, Item *arg1) override;

static Create_func_gtid_check_pos s_singleton;

protected:
Create_func_gtid_check_pos() = default;
~Create_func_gtid_check_pos() override = default;
};


class Create_func_database : public Create_func_arg0
{
public:
Expand Down Expand Up @@ -3576,6 +3589,15 @@ Create_func_connection_id::create_builder(THD *thd)
}


Create_func_gtid_check_pos Create_func_gtid_check_pos::s_singleton;

Item*
Create_func_gtid_check_pos::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_gtid_check_pos(thd, arg1);
}


Create_func_database Create_func_database::s_singleton;

Item*
Expand Down Expand Up @@ -6355,6 +6377,7 @@ const Native_func_registry func_array[] =
{ { STRING_WITH_LEN("CONCAT_OPERATOR_ORACLE") }, BUILDER(Create_func_concat_operator_oracle)},
{ { STRING_WITH_LEN("CONCAT_WS") }, BUILDER(Create_func_concat_ws)},
{ { STRING_WITH_LEN("CONNECTION_ID") }, BUILDER(Create_func_connection_id)},
{ { STRING_WITH_LEN("GTID_CHECK_POS") }, BUILDER(Create_func_gtid_check_pos)},
{ { STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)},
{ { STRING_WITH_LEN("CONVERT_TZ") }, BUILDER(Create_func_convert_tz)},
{ { STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)},
Expand Down
26 changes: 26 additions & 0 deletions sql/item_func.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "sql_acl.h" // EXECUTE_ACL
#include "mysqld.h" // LOCK_short_uuid_generator
#include "rpl_mi.h"

#include "sql_time.h"
#include <m_ctype.h>
#include <hash.h>
Expand All @@ -53,6 +54,7 @@
#include "sql_cte.h"
#ifdef WITH_WSREP
#include "mysql/service_wsrep.h"
#include "sql_repl.h"
#endif /* WITH_WSREP */

#ifdef NO_EMBEDDED_ACCESS_CHECKS
Expand Down Expand Up @@ -824,6 +826,30 @@ String *Item_int_func::val_str(String *str)
}


bool Item_func_gtid_check_pos::val_bool()
{
DBUG_ASSERT(fixed());
String *gtid_str= args[0]->val_str(&tmp_value);
if ((null_value= args[0]->null_value))
return 0;

#ifndef HAVE_REPLICATION
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "GTID_CHECK_POS");
null_value= 1;
return 0;
#else
bool is_reachable= false;
if (rpl_gtid_pos_check_reachable(gtid_str, &is_reachable))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails to compile on buildbot (I'm assuming for the unit tests) as follows:

/home/buildbot/aarch64-debian-11/build/sql/item_func.cc: In member function ‘virtual bool Item_func_gtid_check_pos::val_bool()’:
/home/buildbot/aarch64-debian-11/build/sql/item_func.cc:841:7: error: ‘rpl_gtid_pos_check_reachable’ was not declared in this scope
  841 |   if (rpl_gtid_pos_check_reachable(gtid_str, &is_reachable))
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

Please have a look.

{
null_value= 1;
return 0;
}
null_value= 0;
return is_reachable;
#endif
}


bool Item_func_connection_id::fix_length_and_dec(THD *thd)
{
if (Item_long_func::fix_length_and_dec(thd))
Expand Down
3 changes: 3 additions & 0 deletions sql/item_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -1505,6 +1505,9 @@ class Item_func_connection_id :public Item_long_func
};





class Item_func_signed :public Item_int_func
{
public:
Expand Down
60 changes: 60 additions & 0 deletions sql/sql_repl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "semisync_slave.h"
#include "mysys_err.h"
#include "gtid_index.h"
#include "item_cmpfunc.h"


enum enum_gtid_until_state {
Expand Down Expand Up @@ -2122,6 +2123,9 @@ gtid_state_from_binlog_pos(const char *in_name, uint32 pos, String *out_str)
}



Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no space only changes please.



static bool
is_until_reached(binlog_send_info *info, ulong *ev_offset,
Log_event_type event_type, const char **errmsg,
Expand Down Expand Up @@ -5838,4 +5842,60 @@ int compare_log_name(const char *log_1, const char *log_2) {
return res;
}

bool rpl_gtid_pos_check_reachable(String *gtid_str, bool *is_reachable)
{

slave_connection_state state;
char buf[FN_REFLEN] = {0};
const char *errormsg;

if (!mysql_bin_log.is_open())
{
my_error(ER_NO_BINARY_LOGGING, MYF(0));
return true;
}

if (state.load(gtid_str->ptr(), gtid_str->length()))
{
/*
We purposefully do not swallow the error here. If the user passes an
ill-formed string, state.load throws ER_INCORRECT_GTID_STATE which
will correctly abort the statement and notify the user.
*/
return true;
}

/*
gtid_find_binlog_pos will natively iterate over the entire `state` hash,
evaluating every GTID provided in the comma-separated list.

If ANY of the requested GTIDs are found to be purged from the binary logs,
it returns a non-null error message pinpointing the purged GTID.

If ALL GTIDs within the requested state natively resolve (meaning they exist
in our index/binlogs, or are safely in the future), it returns a null errormsg.

We disregard `found_in_index` and `out_start_seek` counts since we are only doing
boolean viability checking of the provided GTIDs, not actually initializing a dump thread.
*/
bool found_in_index= false;
uint32 out_start_seek= 0;
rpl_binlog_state until_binlog_state;
until_binlog_state.init();
slave_connection_state until_gtid_state;

errormsg= gtid_find_binlog_pos(&state, buf, &until_gtid_state, &until_binlog_state, &found_in_index, &out_start_seek);

until_binlog_state.free();

if (errormsg)
{
*is_reachable= false;
return false; // At least one requested GTID has been purged.
}

*is_reachable= true;
return false; // All requested GTIDs are currently viable/reachable.
}

#endif /* HAVE_REPLICATION */
2 changes: 2 additions & 0 deletions sql/sql_repl.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ int rpl_append_gtid_state(String *dest, bool use_binlog);
int rpl_load_gtid_state(slave_connection_state *state, bool use_binlog);
bool rpl_gtid_pos_check(THD *thd, char *str, size_t len);
bool rpl_gtid_pos_update(THD *thd, char *str, size_t len);
bool rpl_gtid_pos_check_reachable(String *gtid_str, bool *is_reachable);

#else

struct LOAD_FILE_IO_CACHE : public IO_CACHE { };
Expand Down
Loading