diff options
author | Pali <pali@cpan.org> | 2022-04-22 00:38:19 +0200 |
---|---|---|
committer | Pali <pali@cpan.org> | 2022-04-22 00:38:19 +0200 |
commit | e4e1bd48ab33fc9b5eab99ac66debbde69be8338 (patch) | |
tree | c0c75e355ad911f7dc85037490eeb33def134174 | |
parent | 9e9b5f9abf50080a17fd406425ae2f7bf35c4461 (diff) | |
parent | 9743bec52db5e8f1beb2b31e4a55d6ea1a4edcdd (diff) |
Merge pull request https://github.com/perl5-dbi/DBD-MariaDB/pull/168
Fix compatibility with new MariaDB client and server versions
-rw-r--r-- | Makefile.PL | 8 | ||||
-rw-r--r-- | dbdimp.c | 25 | ||||
-rw-r--r-- | dbdimp.h | 26 | ||||
-rw-r--r-- | t/40server_prepare.t | 9 | ||||
-rw-r--r-- | t/45bind_no_backslash_escapes.t | 4 |
5 files changed, 60 insertions, 12 deletions
diff --git a/Makefile.PL b/Makefile.PL index b9b046c..f28a8df 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -757,7 +757,13 @@ sub Configure { # libmysqld.a from MySQL 8.x is broken too $function .= "\n#if !defined(MARIADB_BASE_VERSION) && !defined(MARIADB_PACKAGE_VERSION)\nif (mysql_get_client_version() >= 80000) return 1;\n#endif\n"; } - $function .= 'return (mysql_get_client_version() == MYSQL_VERSION_ID) ? 0 : 1;'; + # MariaDB Connector/C 3.1.10+ has broken mysql_get_client_version() function, so use mariadb_get_infov(MARIADB_CLIENT_VERSION_ID) instead + $function .= "size_t version;\n"; + $function .= "#if defined(MARIADB_PACKAGE_VERSION) && defined(MARIADB_PACKAGE_VERSION_ID) && MARIADB_PACKAGE_VERSION_ID >= 30000\n"; + $function .= "if (mariadb_get_infov((void *)0, MARIADB_CLIENT_VERSION_ID, &version) != 0)\n"; + $function .= "#endif\n"; + $function .= "version = mysql_get_client_version();\n"; + $function .= 'return (version == MYSQL_VERSION_ID) ? 0 : 1;'; # libmysqld is built using g++ rather than gcc and sometimes # we have to use libstdc++ to resolve linking problems foreach my $add_ldflags (undef, '-lstdc++') { @@ -627,6 +627,25 @@ static char **fill_out_embedded_options(char *options, return options_list; } +#if MYSQL_VERSION_ID < 50001 +/* MySQL client prior to version 5.0.1 does not implement mysql_real_escape_string() for SERVER_STATUS_NO_BACKSLASH_ESCAPES */ +static unsigned long string_escape_quotes(char *to, const char *from, unsigned long len) +{ + const char *to_start = to; + const char *end = from + len; + + while (from < end) + { + if (*from == '\'') + *to++ = '\''; + *to++ = *from++; + } + + *to = '\0'; + return to - to_start; +} +#endif + /* constructs an SQL statement previously prepared with actual values replacing placeholders @@ -838,9 +857,8 @@ static char *parse_params( #if MYSQL_VERSION_ID < 50001 if (sock->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) { - *ptr++ = 'X'; *ptr++ = '\''; - ptr += mysql_hex_string(ptr, ph->value, ph->len); + ptr += string_escape_quotes(ptr, ph->value, ph->len); *ptr++ = '\''; } else @@ -6411,9 +6429,8 @@ SV* mariadb_db_quote(SV *dbh, SV *str, SV *type) #if MYSQL_VERSION_ID < 50001 if (imp_dbh->pmysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) { - *sptr++ = 'X'; *sptr++ = '\''; - sptr += mysql_hex_string(sptr, ptr, len); + sptr += string_escape_quotes(sptr, ptr, len); *sptr++ = '\''; } else @@ -322,6 +322,32 @@ PERL_STATIC_INLINE UV SvUV_nomg(pTHX_ SV *sv) #define my_bool bool #endif +/* + * MariaDB Connector/C 3.1.10 changed API of mysql_get_client_version() + * function. Before that release it returned client version. With that release + * it started returning Connector/C package version. + * + * So when compiling with MariaDB Connector/C client library, redefine + * mysql_get_client_version() to always returns client version via function + * mariadb_get_infov(MARIADB_CLIENT_VERSION_ID) call. + * + * Driver code expects for a long time that mysql_get_client_version() call + * returns client version and not something different. + * + * Function mariadb_get_infov() is supported since MariaDB Connector/C 3.0+. + */ +#if defined(MARIADB_PACKAGE_VERSION) && defined(MARIADB_PACKAGE_VERSION_ID) && MARIADB_PACKAGE_VERSION_ID >= 30000 +PERL_STATIC_INLINE unsigned long mariadb_get_client_version(void) +{ + /* MARIADB_CLIENT_VERSION_ID really expects size_t type, documentation is wrong and says unsigned int. */ + size_t version; + if (mariadb_get_infov(NULL, MARIADB_CLIENT_VERSION_ID, &version) != 0) + version = mysql_get_client_version(); /* On error fallback to mysql_get_client_version() */ + return version; +} +#define mysql_get_client_version() mariadb_get_client_version() +#endif + /* MYSQL_SECURE_AUTH became a no-op from MySQL 5.7.5 and is removed from MySQL 8.0.3 */ #if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID <= 50704 #define HAVE_SECURE_AUTH diff --git a/t/40server_prepare.t b/t/40server_prepare.t index 6eb2cf1..29aa6fd 100644 --- a/t/40server_prepare.t +++ b/t/40server_prepare.t @@ -72,16 +72,19 @@ ok($sth3->execute(1, 2), "insert t3"); is_deeply($dbh->selectall_arrayref('SELECT id, mydata FROM t3'), [[1, 2]]); +# MariaDB server since version 10.6.2 can prepare all statements except PREPARE, EXECUTE, and DEALLOCATE / DROP PREPARE. Previous MariaDB and MySQL versions cannot prepare USE statement. +my $non_preparable_statement = ($dbh->{mariadb_serverversion} >= 100602) ? q(PREPARE stmt FROM "SELECT 1") : ("USE " . $dbh->quote_identifier($test_db)); + $dbh->{mariadb_server_prepare_disable_fallback} = 1; my $error_handler_called = 0; $dbh->{HandleError} = sub { $error_handler_called = 1; die $_[0]; }; -eval { $dbh->prepare("USE " . $dbh->quote_identifier($test_db)) }; +eval { $dbh->prepare($non_preparable_statement); }; $dbh->{HandleError} = undef; -ok($error_handler_called, 'USE is not supported with mariadb_server_prepare_disable_fallback=1'); +ok($error_handler_called, "Non-preparable statement '$non_preparable_statement' is not supported with mariadb_server_prepare_disable_fallback=1"); $dbh->{mariadb_server_prepare_disable_fallback} = 0; my $sth4; -ok($sth4 = $dbh->prepare("USE " . $dbh->quote_identifier($test_db)), 'USE is supported with mariadb_server_prepare_disable_fallback=0'); +ok($sth4 = $dbh->prepare($non_preparable_statement), "Non-preparable statement '$non_preparable_statement' is supported with mariadb_server_prepare_disable_fallback=0"); ok($sth4->execute()); ok ($dbh->do(qq{DROP TABLE t3}), "cleaning up"); diff --git a/t/45bind_no_backslash_escapes.t b/t/45bind_no_backslash_escapes.t index 13dce12..eaf011b 100644 --- a/t/45bind_no_backslash_escapes.t +++ b/t/45bind_no_backslash_escapes.t @@ -18,10 +18,6 @@ if ($dbh->{mariadb_serverversion} < 50001) { plan skip_all => "Servers < 5.0.1 do not support sql_mode NO_BACKSLASH_ESCAPES"; } -if ($dbh->{mariadb_clientversion} < 50001) { - $id2_quoted_no_backslash = q(X'737472696E675C737472696E6722737472696E6727737472696E67'); -} - plan tests => 20; ok $dbh->do('CREATE TEMPORARY TABLE t(id VARCHAR(255), value TEXT)'); |