Skip to content

Commit f7ee83d

Browse files
pikidbussink
authored andcommitted
Add rows_read
This adds an additional info bit that is JSON serialized and contains the number of rows read for a query so that the client can get access to this data. Signed-off-by: Dirkjan Bussink <[email protected]>
1 parent 49ef33f commit f7ee83d

File tree

12 files changed

+106
-18
lines changed

12 files changed

+106
-18
lines changed

client/mysql.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3412,7 +3412,13 @@ static int com_go(String *buffer, char *line [[maybe_unused]]) {
34123412
}
34133413
my_stpcpy(pos, time_buff);
34143414
put_info(buff, INFO_RESULT);
3415-
if (mysql_info(&mysql)) put_info(mysql_info(&mysql), INFO_RESULT);
3415+
const char *info = mysql_info(&mysql);
3416+
if (info) {
3417+
if (info[0])
3418+
put_info(mysql_info(&mysql), INFO_RESULT);
3419+
else if (info[1] && getenv("MYSQL_METRICS"))
3420+
printf("Metrics: %s\n", info+1);
3421+
}
34163422
put_info("", INFO_RESULT); // Empty row
34173423

34183424
if (result && !mysql_eof(result)) /* Something wrong when using quick */

client/mysqltest.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8381,7 +8381,7 @@ static void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows,
83818381
char buf[40], buff2[21];
83828382
sprintf(buf, "affected rows: %s\n", llstr(affected_rows, buff2));
83838383
dynstr_append(ds, buf);
8384-
if (info) {
8384+
if (info && info[0]) {
83858385
dynstr_append(ds, "info: ");
83868386
dynstr_append(ds, info);
83878387
dynstr_append_mem(ds, "\n", 1);

router/src/harness/tests/test_net_ts_internet.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,11 @@ TEST(NetTS_internet, tcp_ipv4_socket_bind_accept_connect_dynbuffer) {
661661
}
662662

663663
TEST(NetTS_internet, tcp_ipv6_socket_bind_accept_connect) {
664+
if (getenv("DISABLE_IPV6_TESTS")) {
665+
// fails when ipv6 is present but disabled
666+
GTEST_SKIP();
667+
}
668+
664669
net::io_context io_ctx;
665670

666671
net::ip::tcp::endpoint endp = net_ipv6_any_port_endpoint();
@@ -748,6 +753,11 @@ TEST(NetTS_internet, tcp_ipv6_socket_bind_accept_connect) {
748753
}
749754

750755
TEST(NetTS_internet, udp_ipv6_socket_bind_accept_connect) {
756+
if (getenv("DISABLE_IPV6_TESTS")) {
757+
// fails when ipv6 is present but disabled
758+
GTEST_SKIP();
759+
}
760+
751761
net::io_context io_ctx;
752762

753763
// any ip, any port

router/tests/component/test_http_server.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ static_assert(sizeof(kInvalidBindAddress) > 7 + 1,
6969
"kInvalidBindAddress is too short");
7070
#endif
7171

72+
const std::string localhost_ipv4("127.0.0.1");
73+
const std::string localhost_ipv6("::1");
74+
7275
using namespace std::chrono_literals;
7376

7477
const std::string kHttpBasedir(kPlaceholderHttpBaseDir);
@@ -211,6 +214,11 @@ TempDirectory HttpServerPlainTest::http_base_dir_;
211214
* - make a client connect to the http-server
212215
*/
213216
TEST_P(HttpServerPlainTest, ensure) {
217+
if (getenv("DISABLE_IPV6_TESTS") && GetParam().http_hostname == localhost_ipv6) {
218+
// fails when ipv6 is present but disabled
219+
GTEST_SKIP();
220+
}
221+
214222
std::vector<std::pair<std::string, std::string>> http_section;
215223
http_section.reserve(GetParam().http_section.size());
216224

@@ -310,9 +318,6 @@ TEST_P(HttpServerPlainTest, ensure) {
310318
}
311319
}
312320

313-
const std::string localhost_ipv4("127.0.0.1");
314-
const std::string localhost_ipv6("::1");
315-
316321
static const HttpServerPlainParams http_server_static_files_params[]{
317322
{"bind-address-ipv4-any",
318323
"WL11891::TS-3",

sql/auth/sql_security_ctx.cc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ void Security_context::init() {
9393
m_has_drop_policy = false;
9494
m_executed_drop_policy = false;
9595
m_registration_sandbox_mode = false;
96+
m_exclude_user_from_rows_read = false;
9697
}
9798

9899
void Security_context::logout() {
@@ -815,6 +816,8 @@ void Security_context::set_user_ptr(const char *user_arg,
815816

816817
// set new user value to m_user.
817818
m_user.set(user_arg, user_arg_length, system_charset_info);
819+
820+
recheck_exclude_rows_read();
818821
}
819822

820823
/**
@@ -837,6 +840,25 @@ void Security_context::assign_user(const char *user_arg,
837840
m_user.copy(user_arg, user_arg_length, system_charset_info);
838841
else
839842
m_user.set((const char *)nullptr, 0, system_charset_info);
843+
844+
recheck_exclude_rows_read();
845+
}
846+
847+
char *rows_read_exclude_users = nullptr;
848+
849+
void Security_context::recheck_exclude_rows_read() {
850+
m_exclude_user_from_rows_read = false;
851+
if (rows_read_exclude_users) {
852+
char *copy = strdup(rows_read_exclude_users);
853+
char *saveptr, *tok;
854+
for (tok=my_strtok_r(copy, ",", &saveptr); tok; tok=my_strtok_r(NULL, ",", &saveptr)) {
855+
if (!strcmp(tok, m_user.ptr())) {
856+
m_exclude_user_from_rows_read = true;
857+
break;
858+
}
859+
}
860+
free(copy);
861+
}
840862
}
841863

842864
/**
@@ -880,7 +902,7 @@ void Security_context::set_host_ptr(const char *host_arg,
880902
/**
881903
Setter method for member m_host.
882904
883-
Copies host_arg value to the m_host if it is not null else m_user is set
905+
Copies host_arg value to the m_host if it is not null else m_host is set
884906
to empty string.
885907
886908

sql/auth/sql_security_ctx.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class Security_context {
6262
void skip_grants(const char *user = "skip-grants user",
6363
const char *host = "skip-grants host");
6464
bool is_skip_grants_user();
65+
bool exclude_user_from_rows_read() const { return m_exclude_user_from_rows_read; }
6566

6667
/**
6768
Getter method for member m_user.
@@ -380,6 +381,9 @@ class Security_context {
380381
*/
381382
bool m_is_skip_grants_user;
382383

384+
bool m_exclude_user_from_rows_read;
385+
void recheck_exclude_rows_read();
386+
383387
bool m_executed_drop_policy;
384388
bool m_has_drop_policy;
385389
std::unique_ptr<std::function<void(Security_context *)>> m_drop_policy;

sql/protocol_classic.cc

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@
459459
#include "sql/sql_lex.h"
460460
#include "sql/sql_list.h"
461461
#include "sql/sql_prepare.h" // Prepared_statement
462+
#include "sql/sql_thd_internal_api.h"
462463
#include "sql/system_variables.h"
463464
#include "sql_string.h"
464465
#include "template_utils.h"
@@ -858,7 +859,7 @@ bool net_send_error(NET *net, uint sql_errno, const char *err) {
858859

859860
static bool net_send_ok(THD *thd, uint server_status, uint statement_warn_count,
860861
ulonglong affected_rows, ulonglong id,
861-
const char *message, bool eof_identifier) {
862+
const char *message, size_t msglen, bool eof_identifier) {
862863
Protocol *protocol = thd->get_protocol();
863864
NET *net = thd->get_protocol_classic()->get_net();
864865
uchar buff[MYSQL_ERRMSG_SIZE + 10];
@@ -927,9 +928,9 @@ static bool net_send_ok(THD *thd, uint server_status, uint statement_warn_count,
927928

928929
if (protocol->has_client_capability(CLIENT_SESSION_TRACK)) {
929930
/* the info field */
930-
if (state_changed || (message && message[0]))
931+
if (state_changed || (message && msglen))
931932
pos = net_store_data(pos, pointer_cast<const uchar *>(message),
932-
message ? strlen(message) : 0);
933+
message ? msglen : 0);
933934
/* session state change information */
934935
if (unlikely(state_changed)) {
935936
store.set_charset(thd->variables.collation_database);
@@ -946,10 +947,10 @@ static bool net_send_ok(THD *thd, uint server_status, uint statement_warn_count,
946947
start = (uchar *)store.ptr();
947948
pos = start + store.length();
948949
}
949-
} else if (message && message[0]) {
950+
} else if (message && msglen > 0 && (message[0] || message[1])) {
950951
/* the info field, if there is a message to store */
951952
pos = net_store_data(pos, pointer_cast<const uchar *>(message),
952-
strlen(message));
953+
msglen);
953954
}
954955

955956
/* OK packet length will be restricted to 16777215 bytes */
@@ -1299,7 +1300,7 @@ bool Protocol_classic::send_ok(uint server_status, uint statement_warn_count,
12991300
DBUG_TRACE;
13001301
const bool retval =
13011302
net_send_ok(m_thd, server_status, statement_warn_count, affected_rows,
1302-
last_insert_id, message, false);
1303+
last_insert_id, message, strlen(message), false);
13031304
// Reclaim some memory
13041305
convert.shrink(m_thd->variables.net_buffer_length);
13051306
return retval;
@@ -1321,9 +1322,19 @@ bool Protocol_classic::send_eof(uint server_status, uint statement_warn_count) {
13211322
*/
13221323
if (has_client_capability(CLIENT_DEPRECATE_EOF) &&
13231324
(m_thd->get_command() != COM_BINLOG_DUMP &&
1324-
m_thd->get_command() != COM_BINLOG_DUMP_GTID))
1325-
retval = net_send_ok(m_thd, server_status, statement_warn_count, 0, 0,
1326-
nullptr, true);
1325+
m_thd->get_command() != COM_BINLOG_DUMP_GTID)) {
1326+
ulonglong rows_read = m_thd->get_stmt_da()->rows_read();
1327+
if (rows_read) {
1328+
char message[64] = "";
1329+
snprintf(message+1, sizeof(message)-1, "{\"rows_read\":%llu}", rows_read);
1330+
retval = net_send_ok(m_thd, server_status, statement_warn_count, 0, 0,
1331+
message, 1+strlen(message+1), true);
1332+
}
1333+
else {
1334+
retval = net_send_ok(m_thd, server_status, statement_warn_count, 0, 0,
1335+
NULL, 0, true);
1336+
}
1337+
}
13271338
else
13281339
retval = net_send_eof(m_thd, server_status, statement_warn_count);
13291340
// Reclaim some memory
@@ -3708,7 +3719,7 @@ bool Protocol_binary::send_parameters(List<Item_param> *parameters,
37083719
(m_thd->server_status | SERVER_PS_OUT_PARAMS |
37093720
SERVER_MORE_RESULTS_EXISTS),
37103721
m_thd->get_stmt_da()->current_statement_cond_count(), 0,
3711-
0, nullptr, true);
3722+
0, nullptr, 0, true);
37123723
else
37133724
/*
37143725
In case of old clients send EOF packet.

sql/sql_error.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ Diagnostics_area::Diagnostics_area(bool allow_unlimited_conditions)
336336
m_status(DA_EMPTY),
337337
m_mysql_errno(0),
338338
m_affected_rows(0),
339+
m_rows_read(0),
339340
m_last_insert_id(0),
340341
m_last_statement_cond_count(0),
341342
m_current_statement_cond_count(0),
@@ -364,6 +365,7 @@ void Diagnostics_area::reset_diagnostics_area() {
364365
m_last_insert_id = 0;
365366
m_last_statement_cond_count = 0;
366367
#endif
368+
m_rows_read = 0;
367369
set_is_sent(false);
368370
// Tiny reset in debug mode to see garbage right away.
369371
m_status = DA_EMPTY;

sql/sql_error.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,11 @@ class Diagnostics_area {
397397
return m_affected_rows;
398398
}
399399

400+
ulonglong rows_read() const {
401+
assert(m_status == DA_OK || m_status == DA_EOF);
402+
return m_rows_read;
403+
}
404+
400405
ulonglong last_insert_id() const {
401406
assert(m_status == DA_OK);
402407
return m_last_insert_id;
@@ -456,6 +461,9 @@ class Diagnostics_area {
456461
/** Increment the current row counter to point at the next row. */
457462
void inc_current_row_for_condition() { m_current_row_for_condition++; }
458463

464+
/** Increment the rows-read counter. */
465+
void inc_rows_read() { m_rows_read++; }
466+
459467
/** Set the current row counter to point to the given row number. */
460468
void set_current_row_for_condition(ulong rowno) {
461469
m_current_row_for_condition = rowno;
@@ -659,6 +667,11 @@ class Diagnostics_area {
659667
*/
660668
ulonglong m_affected_rows;
661669

670+
/**
671+
The number of rows read by the last statement.
672+
*/
673+
ulonglong m_rows_read;
674+
662675
/**
663676
Similarly to the previous member, this is a replacement of
664677
thd->first_successful_insert_id_in_prev_stmt, which is used

sql/sys_vars.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,13 @@ static Sys_var_charptr Sys_my_bind_addr(
10801080
READ_ONLY NON_PERSIST GLOBAL_VAR(my_bind_addr_str), CMD_LINE(REQUIRED_ARG),
10811081
IN_FS_CHARSET, DEFAULT(MY_BIND_ALL_ADDRESSES));
10821082

1083+
extern char *rows_read_exclude_users;
1084+
static Sys_var_charptr Sys_my_rows_read_exclude_users(
1085+
"rows_read_exclude_users",
1086+
"Comma-separated list of users whose queries do not increment rows_read",
1087+
READ_ONLY NON_PERSIST GLOBAL_VAR(rows_read_exclude_users), CMD_LINE(REQUIRED_ARG),
1088+
IN_FS_CHARSET, DEFAULT(nullptr));
1089+
10831090
static Sys_var_charptr Sys_admin_addr(
10841091
"admin_address",
10851092
"IP address to bind to for service connection. Address can be an IPv4"

storage/innobase/handler/ha_innodb.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10295,9 +10295,10 @@ int ha_innobase::index_read(
1029510295
if (m_prebuilt->table->is_system_table) {
1029610296
srv_stats.n_system_rows_read.add(
1029710297
thd_get_thread_id(m_prebuilt->trx->mysql_thd), 1);
10298-
} else {
10298+
} else if (!m_user_thd->security_context()->exclude_user_from_rows_read()) {
1029910299
srv_stats.n_rows_read.add(thd_get_thread_id(m_prebuilt->trx->mysql_thd),
1030010300
1);
10301+
m_user_thd->get_stmt_da()->inc_rows_read();
1030110302
}
1030210303
break;
1030310304

@@ -10542,9 +10543,10 @@ int ha_innobase::general_fetch(
1054210543
if (m_prebuilt->table->is_system_table) {
1054310544
srv_stats.n_system_rows_read.add(
1054410545
thd_get_thread_id(m_prebuilt->trx->mysql_thd), 1);
10545-
} else {
10546+
} else if (!m_user_thd->security_context()->exclude_user_from_rows_read()) {
1054610547
srv_stats.n_rows_read.add(thd_get_thread_id(m_prebuilt->trx->mysql_thd),
1054710548
1);
10549+
m_user_thd->get_stmt_da()->inc_rows_read();
1054810550
}
1054910551
break;
1055010552
case DB_RECORD_NOT_FOUND:

unittest/gunit/mysys_pathfuncs-t.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ TEST(Mysys, LoadPathOverflow) {
142142

143143
#ifdef HAVE_O_TMPFILE
144144
TEST(Mysys, CreateTempFile) {
145+
if (getenv("DISABLE_TMPFILE_TESTS")) {
146+
// In Docker, /tmp is a plain subdirectory under /, which is an overlayfs
147+
// O_TMPFILE does not work on overlayfs
148+
GTEST_SKIP();
149+
}
150+
145151
char dst[FN_REFLEN];
146152
aset(dst, 0xaa);
147153

0 commit comments

Comments
 (0)