diff --git a/deps/mariadb-client-library/client_deprecate_eof.patch b/deps/mariadb-client-library/client_deprecate_eof.patch index 2c7a611f50..bca69d290d 100644 --- a/deps/mariadb-client-library/client_deprecate_eof.patch +++ b/deps/mariadb-client-library/client_deprecate_eof.patch @@ -170,7 +170,7 @@ index e475e25..1a04b2f 100644 + */ +int +unpack_field(const MYSQL *mysql, MA_MEM_ROOT *alloc, my_bool default_value, -+ MYSQL_ROWS *row, MYSQL_FIELD *field) ++ MYSQL_ROWS *row, MYSQL_FIELD *field, ulong* field_length) +{ + unsigned int i, field_count = sizeof(rset_field_offsets) / sizeof(size_t) / 2; + char *p = NULL; @@ -187,7 +187,7 @@ index e475e25..1a04b2f 100644 + // Copy data in case of not empty + else + { -+ uint length = (uint)(row->data[i+1] - row->data[i] - 1); ++ uint length = (uint)((field_length != NULL) ? field_length[i] : (row->data[i+1] - row->data[i] - 1)); + *(char **)(((char *)field) + rset_field_offsets[i*2]) = + ma_strdup_root(alloc, (char *)row->data[i]); + *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1]) = @@ -314,7 +314,7 @@ index e475e25..1a04b2f 100644 - field->def_length= 0; - - field->max_length= 0; -+ if (unpack_field(mysql, alloc, default_value, row, field) != 0) ++ if (unpack_field(mysql, alloc, default_value, row, field, NULL) != 0) + goto error; } if (field < result + fields) @@ -440,7 +440,7 @@ index e475e25..1a04b2f 100644 + { + if (mthd_my_read_one_row(mysql, m_field_count, m_rows.data, m_len) == -1) + return NULL; -+ if (unpack_field(mysql, mem_root, 0, &m_rows, m_fields++)) ++ if (unpack_field(mysql, mem_root, 0, &m_rows, m_fields++, m_len)) + return NULL; + } + // read EOF packet in case of client not supporting 'CLIENT_DEPRECATE_EOF' diff --git a/test/tap/tests/reg_test_4402-mysql_fields-t.cpp b/test/tap/tests/reg_test_4402-mysql_fields-t.cpp new file mode 100644 index 0000000000..7ab0a0bbdb --- /dev/null +++ b/test/tap/tests/reg_test_4402-mysql_fields-t.cpp @@ -0,0 +1,129 @@ +/** + * @file reg_test_4402-mysql-fields-t.cpp + * @brief This TAP test checks if the length of the column alias and table alias surpasses 250 characters, + * should not impact MySQL field name length (MySQL_FIELD::name_length) and the MySQL field database length (MySQL_FIELD::db_length) + */ + +#include +#include +#include +#include +#include "tap.h" +#include "command_line.h" +#include "utils.h" + +#define MYSQL_QUERY__(mysql, query) \ + do { \ + if (mysql_query(mysql, query)) { \ + fprintf(stderr, "File %s, line %d, Error: %s\n", \ + __FILE__, __LINE__, mysql_error(mysql)); \ + goto cleanup; \ + } \ + } while(0) + +CommandLine cl; + +std::string generate_random_string(size_t length) { + std::srand(static_cast(std::time(nullptr))); + static const char characters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + static const int numCharacters = (sizeof(characters) - 1)/ sizeof(char); + + std::string randomString; + randomString.reserve(length); + + for (size_t i = 0; i < length; ++i) { + char randomChar = characters[std::rand() % numCharacters]; + randomString.push_back(randomChar); + } + + return randomString; +} + +int main(int argc, char** argv) { + + if (cl.getEnv()) { + diag("Failed to get the required environmental variables."); + return -1; + } + + plan(256*2); + + // Initialize ProxySQL connection + MYSQL* proxysql = mysql_init(NULL); + if (!proxysql) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql)); + return -1; + } + + // Connect to ProxySQL + if (!mysql_real_connect(proxysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql)); + return exit_status(); + } + + MYSQL_QUERY__(proxysql, "DROP DATABASE IF EXISTS testdb"); + MYSQL_QUERY__(proxysql, "CREATE DATABASE testdb"); + + diag("Creating echo_int function..."); + MYSQL_QUERY__(proxysql, "CREATE FUNCTION testdb.echo_int(N INT) RETURNS INT DETERMINISTIC RETURN N;"); + + diag("Creating dummy_table..."); + MYSQL_QUERY__(proxysql, "CREATE TABLE testdb.dummy_table(data VARCHAR(10))"); + + // wait for replication + std::this_thread::sleep_for(std::chrono::seconds(2)); + + // alias maximum length is 256. + // https://dev.mysql.com/doc/refman/8.2/en/identifier-length.html + // https://mariadb.com/kb/en/identifier-names/#maximum-length + for (unsigned int length = 1; length <= 256; length++) { + + // to check column alias issue: + { + const std::string& query = "SELECT testdb.echo_int(1) AS " + generate_random_string(length); + MYSQL_QUERY__(proxysql, query.c_str()); + + MYSQL_RES* res = mysql_use_result(proxysql); + if (!res) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql)); + return exit_status(); + } + + MYSQL_FIELD* field = mysql_fetch_fields(res); + + ok(field->name_length == length, "name_length: '%u'. Expected length: '%u'", field->name_length, length); + + if (res) { + mysql_free_result(res); + res = NULL; + } + } + + // to check table alias issue: + { + const std::string& query = "SELECT data FROM testdb.dummy_table AS " + generate_random_string(length); + MYSQL_QUERY__(proxysql, query.c_str()); + + MYSQL_RES* res = mysql_use_result(proxysql); + if (!res) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql)); + return exit_status(); + } + + MYSQL_FIELD* field = mysql_fetch_fields(res); + + ok(field->db_length == (sizeof("testdb")-1), "db_length: '%u'. Expected length: '%u'", + field->db_length, (unsigned int)(sizeof("testdb")-1)); + + if (res) { + mysql_free_result(res); + res = NULL; + } + } + } +cleanup: + mysql_query(proxysql, "DROP DATABASE IF EXISTS testdb"); + mysql_close(proxysql); + + return exit_status(); +}