diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 7699388b..cfe014bc 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -40,6 +40,7 @@ jobs:
- 5.34.0
- 5.36.0
- 5.38.0
+ - 5.40.0
- system
dbi-version:
- 1.627
@@ -104,6 +105,7 @@ jobs:
- mysql-8.0.22
- mysql-8.0.33
- mysql-8.0.34
+ - mysql-8.0.35
- mariadb-5.5.40
- mariadb-5.5.44
- mariadb-5.5.47
@@ -255,6 +257,32 @@ jobs:
client-version: mariadbconc-3.0.2
- server-version: mysql-4.1.22
client-version: mariadbconc-3.0.6
+ # MySQL client versions 8.0.4 - 8.4.0 and 8.1.0 have bug which
+ # prevents connection to MySQL server versions prior 5.5.7.
+ # Moreover, old server versions don't send Warning Count and Server
+ # Status fields in the response to prepare, but the client doesn't
+ # check the packet length and dereferences the memory out of the
+ # buffer.
+ #- server-version: mysql-4.1.22
+ # client-version: mysql-8.0.3-rc
+ - server-version: mysql-5.1.72
+ client-version: mysql-8.0.3-rc
+ # This combination stops responding during the first test and
+ # times out in GHA. We haven't found the cause.
+ - server-version: system-pic
+ client-version: system-pic
+ - server-version: mysql-5.7.43
+ client-version: system-pic
+ - server-version: mysql-8.0.35
+ client-version: system-pic
+ - server-version: mariadb-5.5.40
+ client-version: system-pic
+ - server-version: mariadb-10.0.38
+ client-version: system-pic
+ - server-version: mariadb-10.2.44
+ client-version: system-pic
+ - server-version: mariadb-10.4.2
+ client-version: system-pic
- server-version: none
client-version: system
- perl-version: 5.12.0
@@ -286,16 +314,18 @@ jobs:
with:
path: ~/.cpan/sources
key: cache-cpan
- - name: Install client dependences (1)
- if: ${{ matrix.client-version != 'system' && ( matrix.server-version != 'system' || matrix.client-version != 'same-as-server' ) }}
+ - name: Update apt
run: |
- sudo apt install libgnutls28-dev libncurses5 libncursesw5 libstdc++5
- - name: Install client dependences (2)
+ sudo apt update
+ - name: Uninstall system MySQL/MariaDB
+ run: |
+ sudo apt purge `{ dpkg --get-selections '*mysql*'; dpkg --get-selections '*mariadb*'; } | sed 's/[:\t].*//'`
+ - name: Install client dependencies
if: ${{ matrix.client-version != 'system' && ( matrix.server-version != 'system' || matrix.client-version != 'same-as-server' ) }}
run: |
wget --progress=bar:force http://security.ubuntu.com/ubuntu/pool/main/o/openssl1.0/libssl1.0.0_1.0.2n-1ubuntu5_amd64.deb -O /tmp/libssl1.0.0_1.0.2n-1ubuntu5_amd64.deb
wget --progress=bar:force http://security.ubuntu.com/ubuntu/pool/universe/j/jemalloc/libjemalloc1_3.6.0-11_amd64.deb -O /tmp/libjemalloc1_3.6.0-11_amd64.deb
- sudo dpkg -i /tmp/libssl1.0.0_1.0.2n-1ubuntu5_amd64.deb /tmp/libjemalloc1_3.6.0-11_amd64.deb
+ sudo apt install libgnutls28-dev libncurses5 libncursesw5 libstdc++5 /tmp/libssl1.0.0_1.0.2n-1ubuntu5_amd64.deb /tmp/libjemalloc1_3.6.0-11_amd64.deb
- name: Install MariaDB client system
if: ${{ matrix.client-version == 'system' || ( matrix.server-version == 'system' && matrix.client-version == 'same-as-server' ) }}
run: |
@@ -306,6 +336,21 @@ jobs:
sudo apt install mariadb-server
sudo systemctl start mariadb.service
sudo mariadb -e "GRANT ALL PRIVILEGES ON test.* TO 'test'@'localhost' IDENTIFIED BY 'test'"
+ - name: Install MySQL embedded PIC library
+ if: ${{ matrix.client-version == 'system-pic' || matrix.server-version == 'system-pic' }}
+ run: |
+ wget --progress=bar:force http://archive.ubuntu.com/ubuntu/pool/universe/m/mysql-5.5/libmysqld-pic_5.5.62-0ubuntu0.14.04.1_amd64.deb -O /tmp/libmysqld-pic_5.5.62-0ubuntu0.14.04.1_amd64.deb
+ wget --progress=bar:force http://archive.ubuntu.com/ubuntu/pool/main/m/mysql-5.5/libmysqlclient-dev_5.5.62-0ubuntu0.14.04.1_amd64.deb -O /tmp/libmysqlclient-dev_5.5.62-0ubuntu0.14.04.1_amd64.deb
+ wget --progress=bar:force http://archive.ubuntu.com/ubuntu/pool/main/m/mysql-5.5/libmysqlclient18_5.5.62-0ubuntu0.14.04.1_amd64.deb -O /tmp/libmysqlclient18_5.5.62-0ubuntu0.14.04.1_amd64.deb
+ wget --progress=bar:force http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/multiarch-support_2.27-3ubuntu1.6_amd64.deb -O /tmp/multiarch-support_2.27-3ubuntu1.6_amd64.deb
+ sudo apt install libaio-dev libwrap0-dev
+ sudo apt install /tmp/libmysqld-pic_5.5.62-0ubuntu0.14.04.1_amd64.deb /tmp/libmysqlclient-dev_5.5.62-0ubuntu0.14.04.1_amd64.deb /tmp/libmysqlclient18_5.5.62-0ubuntu0.14.04.1_amd64.deb /tmp/multiarch-support_2.27-3ubuntu1.6_amd64.deb
+ echo 'extern int sched_yield(void); int pthread_yield(void) { return sched_yield(); }' > "$HOME/libpthread_yield.c"
+ gcc -O2 -o "$HOME/libpthread_yield.o" -c "$HOME/libpthread_yield.c"
+ rm -f "$HOME/libpthread_yield.a"
+ ar rcs "$HOME/libpthread_yield.a" "$HOME/libpthread_yield.o"
+ sudo cp "$HOME/libpthread_yield.a" /usr/lib/mysql/
+
- name: Install Perl system
if: ${{ matrix.perl-version == 'system' }}
run: |
@@ -327,18 +372,20 @@ jobs:
mariadb*) DB=MariaDB ;;
none) DB=""; ;;
system) DB=""; ;;
+ system-pic) DB=""; ;;
*) DB=unknown ;;
esac
case "${{ matrix.client-version }}" in
- mysql*) CONC_DB=MySQL ;;
- mariadb*) CONC_DB=MariaDB ;;
- system) CONC_DB=""; ;;
- system-pic) CONC_DB=""; ;;
- same-as-server) CONC_DB=""; ;;
- *) CONC_DB=unknown ;;
+ mysql-*) CLIENT_DB=MySQL-Server ;;
+ mysqlconc-*) CLIENT_DB=MySQL-ConC ;;
+ mariadbconc-*) CLIENT_DB=MariaDB-ConC ;;
+ system) CLIENT_DB=""; ;;
+ system-pic) CLIENT_DB=""; ;;
+ same-as-server) CLIENT_DB=""; ;;
+ *) CLIENT_DB=unknown ;;
esac
VERSION=`echo "${{ matrix.server-version }}" | sed 's/^[^-]*-//'`
- CONC_VERSION=`echo "${{ matrix.client-version }}" | sed 's/^[^-]*-//'`
+ CLIENT_VERSION=`echo "${{ matrix.client-version }}" | sed 's/^[^-]*-//'`
if [ "$DB" = "MySQL" ]; then
case "$VERSION" in
4.1.*) SANDBOX_URL=https://mysql.linux.cz/Downloads/MySQL-4.1/mysql-standard-$VERSION-unknown-linux-gnu-x86_64-glibc23.tar.gz ;;
@@ -381,34 +428,46 @@ jobs:
SANDBOX_OPTIONS="$SANDBOX_OPTIONS --init_options=--innodb_use_native_aio=0 --my_clause=innodb_use_native_aio=0 --my_clause=performance_schema=ON"
fi
fi
- if [ "$CONC_DB" = "MySQL" ]; then
- case "$CONC_VERSION" in
- *-labs) CONC_URL=https://downloads.mysql.com/snapshots/pb/mysql-connector-c-$CONC_VERSION/mysql-connector-c-$CONC_VERSION-linux-glibc2.5-x86_64.tar.gz ;;
- 6.0.*) CONC_URL=https://dev.mysql.com/get/mysql-connector-c-$CONC_VERSION-linux-glibc2.3-x86-64bit.tar.gz ;;
- 6.1.[0123456789]) CONC_URL=https://dev.mysql.com/get/mysql-connector-c-$CONC_VERSION-linux-glibc2.5-x86_64.tar.gz ;;
- 6.1.*) CONC_URL=https://dev.mysql.com/get/mysql-connector-c-$CONC_VERSION-linux-glibc2.12-x86_64.tar.gz ;;
- *) echo "Unsupported MySQL Connector/C version '$CONC_VERSION'"; exit 1 ;;
+ if [ "$CLIENT_DB" = "MySQL-ConC" ]; then
+ case "$CLIENT_VERSION" in
+ *-labs) CLIENT_URL=https://downloads.mysql.com/snapshots/pb/mysql-connector-c-$CLIENT_VERSION/mysql-connector-c-$CLIENT_VERSION-linux-glibc2.5-x86_64.tar.gz ;;
+ 6.0.*) CLIENT_URL=https://dev.mysql.com/get/mysql-connector-c-$CLIENT_VERSION-linux-glibc2.3-x86-64bit.tar.gz ;;
+ 6.1.[0123456789]) CLIENT_URL=https://dev.mysql.com/get/mysql-connector-c-$CLIENT_VERSION-linux-glibc2.5-x86_64.tar.gz ;;
+ 6.1.*) CLIENT_URL=https://dev.mysql.com/get/mysql-connector-c-$CLIENT_VERSION-linux-glibc2.12-x86_64.tar.gz ;;
+ *) echo "Unsupported MySQL Connector/C version '$CLIENT_VERSION'"; exit 1 ;;
+ esac
+ CLIENT_FILE="$HOME/cache/$(basename "$CLIENT_URL")"
+ elif [ "$CLIENT_DB" = "MariaDB-ConC" ]; then
+ case "$CLIENT_VERSION" in
+ 3.0.*) CLIENT_URL=https://downloads.mariadb.com/Connectors/c/connector-c-${CLIENT_VERSION/-*/}/mariadb-connector-c-$CLIENT_VERSION-linux-x86_64.tar.gz ;;
+ 3.1.[01234567]) CLIENT_URL=https://downloads.mariadb.com/Connectors/c/connector-c-${CLIENT_VERSION/-*/}/mariadb-connector-c-$CLIENT_VERSION-linux-x86_64.tar.gz ;;
+ 3.*) CLIENT_URL=https://downloads.mariadb.com/Connectors/c/connector-c-${CLIENT_VERSION/-*/}/mariadb-connector-c-$CLIENT_VERSION-ubuntu-focal-amd64.tar.gz ;;
+ *) CLIENT_URL=https://downloads.mariadb.com/Connectors/c/connector-c-${CLIENT_VERSION/-*/}/mariadb-connector-c-$CLIENT_VERSION-linux-x86_64.tar.gz ;;
esac
- CONC_FILE="$HOME/cache/$(basename "$CONC_URL")"
- elif [ "$CONC_DB" = "MariaDB" ]; then
- case "$CONC_VERSION" in
- 3.0.*) CONC_URL=https://downloads.mariadb.com/Connectors/c/connector-c-${CONC_VERSION/-*/}/mariadb-connector-c-$CONC_VERSION-linux-x86_64.tar.gz ;;
- 3.1.[01234567]) CONC_URL=https://downloads.mariadb.com/Connectors/c/connector-c-${CONC_VERSION/-*/}/mariadb-connector-c-$CONC_VERSION-linux-x86_64.tar.gz ;;
- 3.*) CONC_URL=https://downloads.mariadb.com/Connectors/c/connector-c-${CONC_VERSION/-*/}/mariadb-connector-c-$CONC_VERSION-ubuntu-focal-amd64.tar.gz ;;
- *) CONC_URL=https://downloads.mariadb.com/Connectors/c/connector-c-${CONC_VERSION/-*/}/mariadb-connector-c-$CONC_VERSION-linux-x86_64.tar.gz ;;
+ CLIENT_FILE="$HOME/cache/$(basename "$CLIENT_URL")"
+ elif [ "$CLIENT_DB" = "MySQL-Server" ]; then
+ case "$CLIENT_VERSION" in
+ # FIXME: Only MySQL 8.x server versions are defined here for usage as client library for now
+ 8.0.?-*|8.0.11) CLIENT_URL=https://dev.mysql.com/get/mysql-$CLIENT_VERSION-linux-glibc2.12-x86_64.tar.gz ;;
+ 8.0.*) CLIENT_URL=https://dev.mysql.com/get/mysql-$CLIENT_VERSION-linux-glibc2.12-x86_64.tar.xz ;;
+ 8.1.*) CLIENT_URL=https://dev.mysql.com/get/mysql-$CLIENT_VERSION-linux-glibc2.28-x86_64.tar.xz ;;
+ *) echo "Unsupported MySQL version '$CLIENT_VERSION'"; exit 1 ;;
esac
- CONC_FILE="$HOME/cache/$(basename "$CONC_URL")"
- elif [ -n "$CONC_DB" ]; then
- echo "Unsupported Connector/C '$CONC_DB'"; exit 1
+ CLIENT_FILE="$HOME/cache/$(basename "$CLIENT_URL")"
+ elif [ -n "$CLIENT_DB" ]; then
+ echo "Unsupported Connector/C '$CLIENT_DB'"; exit 1
fi
- if [ -n "$CONC_DB" ]; then
- if [ ! -f "$CONC_FILE" ]; then wget --progress=bar:force "$CONC_URL" -O "$CONC_FILE" || exit 1; fi
+ if [ -n "$CLIENT_DB" ]; then
+ if [ ! -f "$CLIENT_FILE" ]; then wget --progress=bar:force "$CLIENT_URL" -O "$CLIENT_FILE" || exit 1; fi
fi
if [ "${{ matrix.client-version }}" = "system-pic" ]; then
- sed 's/-L\$pkglibdir *-lmysqld/-L\/usr\/lib\/mysql -lmysqld_pic /' `which mysql_config_pic` > "$HOME/mysql_config_pic"
+ sed 's/-L\$pkglibdir *-lmysqld/-L\/usr\/lib\/mysql -lmysqld_pic -lpthread_yield /' `which mysql_config_pic` > "$HOME/mysql_config_pic"
chmod +x $HOME/mysql_config_pic
- apt download mysql-server-core-5.5
- dpkg -x mysql-server-core-5.5_*.deb $HOME/mysql-server-core-5.5
+ fi
+ if [ "${{ matrix.client-version }}" = "system-pic" ] || [ "${{ matrix.server-version }}" = "system-pic" ]; then
+ wget --progress=bar:force http://archive.ubuntu.com/ubuntu/pool/main/m/mysql-5.5/mysql-server-core-5.5_5.5.62-0ubuntu0.14.04.1_amd64.deb -O /tmp/mysql-server-core-5.5_5.5.62-0ubuntu0.14.04.1_amd64.deb
+ dpkg -x /tmp/mysql-server-core-5.5_5.5.62-0ubuntu0.14.04.1_amd64.deb $HOME/mysql-server-core-5.5
+ mkdir -p "$HOME/datadir"
fi
if [ -n "$DB" ]; then
cpanm --quiet --notest --skip-satisfied MySQL::Sandbox || exit 1
@@ -422,28 +481,17 @@ jobs:
printf '#!/bin/sh\nexec %s/msb/my sql_config "$@"\n' $SANDBOX_HOME > "$HOME/mysql_config"
chmod +x $HOME/mysql_config
fi
- if [ -n "$CONC_DB" ]; then
- mkdir -p "$HOME/conc"
- tar --strip-components=1 --directory="$HOME/conc" -xf "$CONC_FILE" || exit 1
- if $HOME/conc/bin/mysql_config 2>&1 | grep -q /usr/local; then
- rm -f $HOME/conc/bin/mysql_config
+ if [ -n "$CLIENT_DB" ]; then
+ mkdir -p "$HOME/client"
+ tar --strip-components=1 --directory="$HOME/client" -xf "$CLIENT_FILE" || exit 1
+ if $HOME/client/bin/mysql_config 2>&1 | grep -q /usr/local; then
+ rm -f $HOME/client/bin/mysql_config
fi
- if [ -x $HOME/conc/bin/mysql_config ]; then
- sed 's/-l "/-lmysqlclient "/g' -i "$HOME/conc/bin/mysql_config" || exit 1
+ if [ -x $HOME/client/bin/mysql_config ]; then
+ sed 's/-l "/-lmysqlclient "/g' -i "$HOME/client/bin/mysql_config" || exit 1
fi
fi
- - name: Install dependences
- run: |
- if [ "${{ matrix.perl-version }}" = "system" ]; then
- eval $(perl -I"$HOME/perl5/lib/perl5" -Mlocal::lib)
- fi
- perl '-MExtUtils::MakeMaker 7.00' -e '' || cpanm --quiet --notest ExtUtils::MakeMaker@7.00
- perl '-MCPAN::Meta 2.112580' -e '' || cpanm --quiet --notest CPAN::Meta@2.112580
- perl '-Mv5.12' -e '' || cpanm --quiet --notest Test::Deep@1.130
- if [ "${{ matrix.dbi-version }}" != "latest" ]; then cpanm --quiet --notest DBI@${{ matrix.dbi-version }}; fi
- cpanm --quiet --notest --skip-satisfied DBI~1.608 Devel::CheckLib~1.12
- cpanm --quiet --notest --skip-satisfied --installdeps --with-configure --with-develop --with-recommends --with-suggests .
- - name: Configure
+ - name: Setup DBD_MARIADB_* env
run: |
if [ "${{ matrix.perl-version }}" = "system" ]; then
eval $(perl -I"$HOME/perl5/lib/perl5" -Mlocal::lib)
@@ -453,6 +501,9 @@ jobs:
export DBD_MARIADB_TESTPASSWORD=test
export DBD_MARIADB_TESTHOST=127.0.0.1
export DBD_MARIADB_TESTPORT=3306
+ elif [ "${{ matrix.server-version }}" = "system-pic" ]; then
+ export DBD_MARIADB_TESTHOST=embedded
+ export DBD_MARIADB_TESTEMBDATADIR="$HOME/datadir"
elif [ "${{ matrix.server-version }}" = "none" ]; then
export DBD_MARIADB_TESTHOST=0.0.0.0
export DBD_MARIADB_TESTPORT=0
@@ -462,13 +513,16 @@ jobs:
export DBD_MARIADB_TESTHOST=127.0.0.1
export DBD_MARIADB_TESTPORT=3310
fi
+ if [[ ${{ matrix.client-version }} =~ mysql-8 ]]; then
+ export DBD_MARIADB_TESTAUTHPLUGIN=mysql_native_password
+ fi
if [ "${{ matrix.client-version }}" != "system" ] && [ "${{ matrix.client-version }}" != "system-pic" ] && [ "${{ matrix.client-version }}" != "same-as-server" ]; then
- if [ -x $HOME/conc/bin/mysql_config ]; then
- export DBD_MARIADB_CONFIG="$HOME/conc/bin/mysql_config"
+ if [ -x $HOME/client/bin/mysql_config ]; then
+ export DBD_MARIADB_CONFIG="$HOME/client/bin/mysql_config"
else
- INCLUDE_PATH=`find "$HOME/conc" -name "mysql.h" | sort | head -1`
+ INCLUDE_PATH=`find "$HOME/client" -name "mysql.h" | sort | head -1`
if [ -z "$INCLUDE_PATH" ]; then echo "File mysql.h was not found"; exit 1; fi
- LIB_PATH=`find "$HOME/conc" -name "lib*.so" | sort | head -1`
+ LIB_PATH=`find "$HOME/client" -name "lib*.so" | sort | head -1`
if [ -z "$INCLUDE_PATH" ]; then echo "File lib*.so was not found"; exit 1; fi
export DBD_MARIADB_CFLAGS="-I`dirname $INCLUDE_PATH`"
export DBD_MARIADB_LIBS="-L`dirname $LIB_PATH` -l`echo $LIB_PATH | sed 's/.*\/lib//;s/\.so//'`"
@@ -476,8 +530,29 @@ jobs:
fi
elif [ "${{ matrix.client-version }}" = "same-as-server" ] && [ "${{ matrix.server-version }}" != "system" ]; then
export DBD_MARIADB_CONFIG="$HOME/mysql_config"
+ export DBD_MARIADB_TESTEMBOPTIONS="--language=`find $HOME/sandbox/* -name english | sed 's/english//'`,--log-error=/dev/null"
elif [ "${{ matrix.client-version }}" = "system-pic" ]; then
export DBD_MARIADB_CONFIG="$HOME/mysql_config_pic"
+ export DBD_MARIADB_TESTEMBOPTIONS="--language=$HOME/mysql-server-core-5.5/usr/share/mysql/,--log-error=/dev/null"
+ export DBD_MARIADB_REQUIREEMBSUP=1
+ fi
+ export | sed 's/^declare -x //;s/="/=/;s/"$//' | grep '^DBD_MARIADB_' >> $GITHUB_ENV
+ - name: Install dependencies
+ run: |
+ if [ "${{ matrix.perl-version }}" = "system" ]; then
+ eval $(perl -I"$HOME/perl5/lib/perl5" -Mlocal::lib)
+ fi
+ perl -M5.008003 || cpanm --quiet --notest ExtUtils::ParseXS@3.51
+ perl '-MExtUtils::MakeMaker 7.00' -e '' || cpanm --quiet --notest ExtUtils::MakeMaker@7.00
+ perl '-MCPAN::Meta 2.112580' -e '' || cpanm --quiet --notest CPAN::Meta@2.112580
+ perl '-Mv5.12' -e '' || cpanm --quiet --notest Test::Deep@1.130
+ if [ "${{ matrix.dbi-version }}" != "latest" ]; then cpanm --quiet --notest DBI@${{ matrix.dbi-version }}; fi
+ cpanm --quiet --notest --skip-satisfied DBI~1.608 Devel::CheckLib~1.12
+ cpanm --quiet --notest --skip-satisfied --installdeps --with-configure --with-develop --with-recommends --with-suggests .
+ - name: Configure
+ run: |
+ if [ "${{ matrix.perl-version }}" = "system" ]; then
+ eval $(perl -I"$HOME/perl5/lib/perl5" -Mlocal::lib)
fi
make realclean || true
perl Makefile.PL
@@ -488,16 +563,14 @@ jobs:
fi
make
- name: Test
+ if: ${{ matrix.server-version != 'system-pic' }}
run: |
if [ "${{ matrix.perl-version }}" = "system" ]; then
eval $(perl -I"$HOME/perl5/lib/perl5" -Mlocal::lib)
fi
- if [ "${{ matrix.client-version }}" = "system-pic" ]; then
- export DBD_MARIADB_TESTLANGDIR="$HOME/mysql-server-core-5.5/usr/share/mysql/english"
- elif [ "${{ matrix.server-version }}" != "none" ] && [ "${{ matrix.server-version }}" != "system" ]; then
- export DBD_MARIADB_TESTLANGDIR=`find $HOME/sandbox/* -name english | head -1`
+ if [ "${{ matrix.server-version }}" != "system-pic" ]; then
+ export HARNESS_OPTIONS=j4
fi
- export HARNESS_OPTIONS=j4
export RELEASE_TESTING=1
if [ "${{ matrix.server-version }}" != "none" ]; then
export CONNECTION_TESTING=1
diff --git a/Makefile.PL b/Makefile.PL
index 8be7df01..e46b4ac7 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -24,9 +24,9 @@ push @mysql_headers, 'mysql.h';
our $opt = { "help" => \&Usage, };
-my ($test_host, $test_port, $test_socket, $test_authplugin);
+my ($test_host, $test_port, $test_socket, $test_embdatadir);
{
-local ($::test_host, $::test_port, $::test_user, $::test_socket, $::test_authplugin, $::test_password, $::test_db, $::test_mysql_config, $::test_cflags, $::test_libs);
+local ($::test_host, $::test_port, $::test_user, $::test_socket, $::test_embdatadir, $::test_emboptions, $::test_authplugin, $::test_password, $::test_db, $::test_mysql_config, $::test_cflags, $::test_libs);
eval { require "./t/MariaDB.mtest" } and do {
$opt->{'testuser'} = $::test_user;
$opt->{'testpassword'} = $::test_password;
@@ -34,10 +34,12 @@ $opt->{'testdb'} = $::test_db;
$opt->{'mysql_config'} = $::test_mysql_config;
$opt->{'cflags'} = $::test_cflags;
$opt->{'libs'} = $::test_libs;
+$opt->{'testemboptions'} = $::test_emboptions;
+$opt->{'testauthplugin'} = $::test_authplugin;
$test_host = $::test_host;
$test_port = $::test_port;
$test_socket = $::test_socket;
-$test_authplugin = $::test_authplugin;
+$test_embdatadir = $::test_embdatadir;
}
}
@@ -50,7 +52,10 @@ Getopt::Long::GetOptions(
"testuser:s",
"testpassword:s",
"testsocket:s",
+ "testembdatadir:s",
+ "testemboptions:s",
"testauthplugin:s",
+ "requireembsup!",
"cflags:s",
"libs:s",
"mysql_config:s",
@@ -106,62 +111,112 @@ MSG
}
}
-for my $key (qw(testdb testhost testuser testpassword testsocket testauthplugin testport cflags libs))
+if (exists $opt->{requireembsup})
+{
+ $source->{'requireembsup'} = "User's choice";
+}
+elsif (defined $ENV{'DBD_MARIADB_REQUIREEMBSUP'})
+{
+ $source->{'requireembsup'} = 'environment';
+ $opt->{'requireembsup'} = !!$ENV{DBD_MARIADB_REQUIREEMBSUP};
+}
+else
+{
+ $source->{'requireembsup'} = 'default';
+ $opt->{'requireembsup'} = 0;
+}
+
+for my $key (qw(testdb testhost testuser testpassword testsocket testport testembdatadir testemboptions testauthplugin cflags libs))
{
Configure($opt, $source, $key);
}
-if (!$opt->{testport} && (!$opt->{testhost} || $opt->{testhost} eq 'localhost') && !defined $opt->{testsocket} && $test_socket) {
+# Reusing old test host is possible if it does not conflict with new test port, new test socket or new test embdatadir
+if (!defined $opt->{testhost} && defined $test_host && length $test_host &&
+ ((defined $opt->{testport} && $test_host ne 'localhost' && $test_host ne 'embedded') ||
+ (defined $opt->{testsocket} && $test_host eq 'localhost') ||
+ (defined $opt->{testembdatadir} && $test_host eq 'embedded') ||
+ (!defined $opt->{testsocket} && !defined $opt->{testembdatadir} && !defined $opt->{testport}))) {
+ $opt->{testhost} = $test_host;
+ $source->{testhost} = "User's choice";
+}
+
+# Reusing old test port is possible if it does not conflict with new test host, new test socket or new test embdatadir
+if (!defined $opt->{testport} && defined $test_port && length $test_port &&
+ (!defined $opt->{testhost} || ($opt->{testhost} ne 'localhost' && $opt->{testhost} ne 'embedded')) &&
+ !defined $opt->{testsocket} &&
+ !defined $opt->{testembdatadir}) {
+ $opt->{testport} = $test_port;
+ $source->{testport} = "User's choice";
+}
+
+# Reusing old test socket is possible if it does not conflict with new test host, new test port or new test embdatadir
+if (!defined $opt->{testsocket} && defined $test_socket && length $test_socket &&
+ (!defined $opt->{testhost} || $opt->{testhost} eq 'localhost') &&
+ !defined $opt->{testport} &&
+ !defined $opt->{testembdatadir}) {
$opt->{testsocket} = $test_socket;
$source->{testsocket} = "User's choice";
}
-if (!$opt->{testsocket}) {
- if (!defined $opt->{testhost} && $test_host && (!$opt->{testport} || $test_host ne 'localhost')) {
- $opt->{testhost} = $test_host;
- $source->{testhost} = "User's choice";
- }
- if (!defined $opt->{testport} && $test_port && (!$opt->{testhost} || $opt->{testhost} ne 'localhost')) {
- $opt->{testport} = $test_port;
- $source->{testport} = "User's choice";
- }
-} else {
- if (!defined $opt->{testhost} && $test_host && $test_host eq 'localhost') {
- $opt->{testhost} = 'localhost';
- $source->{testhost} = "User's choice";
- }
+# Reusing old test embdatadir is possible if it does not conflict with new test host, new test port or new test socket
+if (!defined $opt->{testembdatadir} && defined $test_embdatadir && length $test_embdatadir &&
+ (!defined $opt->{testhost} || $opt->{testhost} eq 'embedded') &&
+ !defined $opt->{testport} &&
+ !defined $opt->{testsocket}) {
+ $opt->{testembdatadir} = $test_embdatadir;
+ $source->{testembdatadir} = "User's choice";
+}
+
+# if we have a testsocket but no host, set localhost
+if (defined $opt->{testsocket} && !defined $opt->{testhost}) {
+ $opt->{testhost} = 'localhost';
+ $source->{testhost} = 'guessed';
}
-#if we have a testport but no host, assume 127.0.0.1
-if ( $opt->{testport} && !$opt->{testhost} ) {
+# if we have a testembdatadir but no host, set embedded
+if (defined $opt->{testembdatadir} && !defined $opt->{testhost}) {
+ $opt->{testhost} = 'embedded';
+ $source->{testhost} = 'guessed';
+}
+
+# if we have a testport but no host, assume 127.0.0.1
+if (defined $opt->{testport} && !defined $opt->{testhost}) {
$opt->{testhost} = '127.0.0.1';
$source->{testhost} = 'guessed';
}
-foreach (qw(testhost testport testsocket testauthplugin)) {
+foreach (qw(testhost testport testsocket testembdatadir)) {
next if defined $opt->{$_};
$opt->{$_} = '';
$source->{$_} = 'default';
}
# testsocket makes sense only when testhost is localhost
-if ($opt->{testsocket} && $opt->{testhost} && $opt->{testhost} ne 'localhost') {
+if (length $opt->{testsocket} && $opt->{testhost} ne 'localhost') {
die << "MSG";
-Option --testport or --testhost different from localhost cannot be specified together with option --testsocket.
+Option --testhost different from localhost cannot be specified together with option --testsocket.
MSG
}
-# testport cannot be specified when host is localhost
-if ($opt->{testport} && $opt->{testhost} && $opt->{testhost} eq 'localhost') {
+# testembdatadir makes sense only when testhost is embedded
+if (length $opt->{testembdatadir} && $opt->{testhost} ne 'embedded') {
die << "MSG";
-Option --testport cannot be specified when --testhost is localhost.
+Option --testhost different from embedded cannot be specified together with option --testembdatadir.
MSG
}
-# testhost cannot be embedded
-if ($opt->{testhost} && $opt->{testhost} eq 'embedded') {
+# there is no default testembdatadir, so check that it is set
+if ($opt->{testhost} eq 'embedded' && !length $opt->{testembdatadir}) {
die << "MSG";
-Option --testhost cannot be embedded.
+Option --testembdatadir must be specified when --testhost is embedded.
+MSG
+}
+
+# testport cannot be specified when host is localhost or embedded
+if (length $opt->{testport} && ($opt->{testhost} eq 'localhost' || $opt->{testhost} eq 'embedded')) {
+ die << "MSG";
+Option --testport cannot be specified when --testhost is localhost or embedded.
MSG
}
@@ -262,6 +317,14 @@ my $have_embedded = check_lib(
print "Embedded server: " . ($have_embedded ? "supported" : "not supported by client library") . "\n\n";
+if (!$have_embedded && ($opt->{testhost} eq 'embedded' || $opt->{requireembsup})) {
+ die << "MSG";
+Cannot run test suite against Embedded server (specified via
+option --testhost=embedded or option --requireembsup) because
+Embedded server is not supported by client library.
+MSG
+}
+
my $have_get_charset_number = check_lib(
LIBS => (join ' ', @libdirs, $main_lib),
ccflags => $opt->{cflags},
@@ -414,13 +477,17 @@ EOF
print "Client library deinitialize OpenSSL library functions: " . ($have_problem_with_openssl ? "yes" : "no") . "\n\n";
my $fileName = File::Spec->catfile("t", "MariaDB.mtest");
+print "Writing $fileName for test suite\n";
(open(FILE, ">$fileName") &&
- (print FILE ("{ local " . Data::Dumper->Dump([$opt], ["opt"]) .
- " local " . Data::Dumper->Dump([$source], ["source"]) .
+ (print FILE ("{\n" .
+ "local " . Data::Dumper->new([$opt], ["opt"])->Sortkeys(1)->Indent(1)->Dump() .
+ "local " . Data::Dumper->new([$source], ["source"])->Sortkeys(1)->Indent(1)->Dump() .
"\$::test_host = \$opt->{'testhost'};\n" .
"\$::test_port = \$opt->{'testport'};\n" .
"\$::test_user = \$opt->{'testuser'};\n" .
"\$::test_socket = \$opt->{'testsocket'};\n" .
+ "\$::test_embdatadir = \$opt->{'testembdatadir'};\n" .
+ "\$::test_emboptions = \$opt->{'testemboptions'};\n" .
"\$::test_authplugin = \$opt->{'testauthplugin'};\n" .
"\$::test_password = \$opt->{'testpassword'};\n" .
"\$::test_db = \$opt->{'testdb'};\n" .
@@ -428,6 +495,8 @@ my $fileName = File::Spec->catfile("t", "MariaDB.mtest");
"\$::test_dsn .= \":\$::test_host\" if \$::test_host;\n" .
"\$::test_dsn .= \":\$::test_port\" if \$::test_port;\n".
"\$::test_dsn .= \";mariadb_socket=\$::test_socket\" if \$::test_socket;\n" .
+ "\$::test_dsn .= \";mariadb_embedded_options=--datadir=\$::test_embdatadir\" if \$::test_embdatadir;\n" .
+ "\$::test_dsn .= \",\$::test_emboptions\" if \$::test_embdatadir and \$::test_emboptions;\n" .
"\$::test_dsn .= \";mariadb_auth_plugin=\$::test_authplugin\" if \$::test_authplugin;\n" .
"\$::test_dsn .= \";mariadb_connect_timeout=120;mariadb_read_timeout=120;mariadb_write_timeout=120\";\n" .
"\$::test_mysql_config = \$opt->{'mysql_config'} if \$source->{'mysql_config'} eq 'User\\'s choice';\n" .
@@ -661,9 +730,19 @@ Possible options are:
the database server; by default unix socket is chosen
by mariadb/mysqlclient library; takes effect only
when --testhost is set to "localhost"
+ --testembdatadir=
Use as database directory for embedded server,
+ it may be and it is suggested to be empty, which means
+ that database is uninitialized; takes effect only when
+ --testhost is set to "embedded"
+ --testemboptions= Use as additional options for embedded server
+ separated by comma, it is recommended to set output
+ log file (e.g. '--log-error=/dev/null') and language
+ directory (e.g. '--language=/usr/local/share/mysql')
+ if language directory is different than system one
--testauthplugin= Use auth plugin when doing user authentication
handshake with server; for older server versions it is
needed to pass "mysql_native_password"
+ --requireembsup Require client library with embedded server support
--mariadb_config Synonym for --mysql_config, override it
--mysql_config= Specify for mariadb_config or mysql_config script
--help Print this message and exit
@@ -858,6 +937,14 @@ perl Makefile.PL --testuser=username
$source->{$param} = "default";
$opt->{$param} = "";
}
+ elsif ($param eq "testauthplugin") {
+ $source->{$param} = "default";
+ $opt->{$param} = "";
+ }
+ elsif ($param eq "testemboptions") {
+ $source->{$param} = "default";
+ $opt->{$param} = "";
+ }
elsif ($param eq "cflags") {
$source->{$param} = "guessed";
my ($dir, $file) = SearchFor('include', 'mysql.h');
@@ -900,7 +987,7 @@ section "Linker flags" or type
perl Makefile.PL --help
MSG
}
- elsif ($param eq "testhost" || $param eq "testport" || $param eq "testsocket" || $param eq "testauthplugin") {
+ elsif (grep { $param eq $_ } ("testhost", "testport", "testsocket", "testembdatadir")) {
# known parameter, but do nothing
}
else {
diff --git a/dbdimp.c b/dbdimp.c
index 7b276cc7..951a81e5 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -1693,6 +1693,7 @@ static bool mariadb_dr_connect(
(void)hv_stores(processed, "mariadb_embedded_options", &PL_sv_yes);
mysql_options(sock, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);
+ imp_dbh->is_embedded = TRUE;
host = NULL;
}
else
@@ -2146,8 +2147,20 @@ static bool mariadb_dr_connect(
}
}
+ #if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80300
+ if (mysql_options(sock, MYSQL_OPT_SSL_KEY, client_key) != 0 ||
+ mysql_options(sock, MYSQL_OPT_SSL_CERT, client_cert) != 0 ||
+ mysql_options(sock, MYSQL_OPT_SSL_CA, ca_file) != 0 ||
+ mysql_options(sock, MYSQL_OPT_SSL_CAPATH, ca_path) != 0 ||
+ mysql_options(sock, MYSQL_OPT_SSL_CIPHER, cipher) != 0) {
+ mariadb_dr_do_error(dbh, CR_SSL_CONNECTION_ERROR, "SSL connection error: Setting SSL options failed", "HY000");
+ mariadb_db_disconnect(dbh, imp_dbh);
+ return FALSE;
+ }
+ #else
mysql_ssl_set(sock, client_key, client_cert, ca_file,
ca_path, cipher);
+ #endif
if (ssl_verify && !(ca_file || ca_path)) {
mariadb_dr_do_error(dbh, CR_SSL_CONNECTION_ERROR, "SSL connection error: mariadb_ssl_verify_server_cert=1 is not supported without mariadb_ssl_ca_file or mariadb_ssl_ca_path", "HY000");
@@ -2375,6 +2388,12 @@ static bool mariadb_dr_connect(
sock->reconnect = FALSE;
#endif
+ /* Connection to Embedded server does not have socket */
+ if (imp_dbh->is_embedded)
+ {
+ imp_dbh->sock_fd = -1;
+ }
+ else
{
my_socket sock_os;
int retval;
@@ -2645,6 +2664,7 @@ int mariadb_db_login6_sv(SV *dbh, imp_dbh_t *imp_dbh, SV *dsn, SV *user, SV *pas
imp_dbh->bind_comment_placeholders= FALSE;
imp_dbh->auto_reconnect = FALSE;
imp_dbh->connected = FALSE; /* Will be switched to TRUE after DBI->connect finish */
+ imp_dbh->is_embedded = FALSE;
if (!mariadb_db_my_login(aTHX_ dbh, imp_dbh))
return 0;
@@ -2662,7 +2682,7 @@ int mariadb_db_login6_sv(SV *dbh, imp_dbh_t *imp_dbh, SV *dsn, SV *user, SV *pas
static my_ulonglong mariadb_st_internal_execute(SV *h, char *sbuf, STRLEN slen, int num_params, imp_sth_ph_t *params, MYSQL_RES **result, MYSQL **svsock, bool use_mysql_use_result);
-static my_ulonglong mariadb_st_internal_execute41(SV *h, char *sbuf, STRLEN slen, bool has_params, MYSQL_RES **result, MYSQL_STMT **stmt_ptr, MYSQL_BIND *bind, MYSQL **svsock, bool *has_been_bound);
+static my_ulonglong mariadb_st_internal_execute41(SV *h, char *sbuf, STRLEN slen, int num_params, MYSQL_RES **result, MYSQL_STMT **stmt_ptr, MYSQL_BIND *bind, MYSQL **svsock, bool *has_been_bound);
/**************************************************************************
*
@@ -2784,6 +2804,11 @@ IV mariadb_db_do6(SV *dbh, imp_dbh_t *imp_dbh, SV *statement_sv, SV *attribs, I3
if (async)
{
+ if (imp_dbh->is_embedded)
+ {
+ mariadb_dr_do_error(dbh, CR_UNKNOWN_ERROR, "Async option not supported for Embedded server", "HY000");
+ return -2;
+ }
if (disable_fallback_for_server_prepare)
{
mariadb_dr_do_error(dbh, ER_UNSUPPORTED_PS, "Async option not supported with server side prepare", "HY000");
@@ -2821,7 +2846,7 @@ IV mariadb_db_do6(SV *dbh, imp_dbh_t *imp_dbh, SV *statement_sv, SV *attribs, I3
#endif
/* This is error for previous unfetched result ret. So do not report server errors to caller which is expecting new result set. */
error = mysql_errno(imp_dbh->pmysql);
- if (error == CR_COMMANDS_OUT_OF_SYNC || error == CR_OUT_OF_MEMORY || error == CR_SERVER_GONE_ERROR || error == CR_SERVER_LOST || error == CR_UNKNOWN_ERROR)
+ if (error == CR_COMMANDS_OUT_OF_SYNC || error == CR_OUT_OF_MEMORY || error == CR_SERVER_GONE_ERROR || error == CR_SERVER_LOST || error == ER_CLIENT_INTERACTION_TIMEOUT || error == CR_UNKNOWN_ERROR)
{
mariadb_dr_do_error(dbh, mysql_errno(imp_dbh->pmysql), mysql_error(imp_dbh->pmysql), mysql_sqlstate(imp_dbh->pmysql));
return -2;
@@ -3164,8 +3189,11 @@ static void mariadb_db_close_mysql(pTHX_ imp_drh_t *imp_drh, imp_dbh_t *imp_dbh)
socket from C file descriptor sock_fd via _set_osfhnd() function and then
close sock_fd via close() function.
*/
+ if (imp_dbh->sock_fd >= 0)
+ {
_set_osfhnd(imp_dbh->sock_fd, INVALID_HANDLE_VALUE);
close(imp_dbh->sock_fd);
+ }
#endif
imp_dbh->sock_fd = -1;
svp = hv_fetchs((HV*)DBIc_MY_H(imp_dbh), "ChildHandles", FALSE);
@@ -3480,6 +3508,11 @@ mariadb_db_STORE_attrib(
#endif
else if (memEQs(key, kl, "mariadb_max_allowed_packet"))
{
+ if (imp_dbh->is_embedded)
+ {
+ mariadb_dr_do_error(dbh, CR_UNKNOWN_ERROR, "mariadb_max_allowed_packet is not supported for Embedded server", "HY000");
+ return 0;
+ }
#if (!defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709 && MYSQL_VERSION_ID != 60000) || (defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100206 && MYSQL_VERSION_ID != 100300)
/* MYSQL_OPT_MAX_ALLOWED_PACKET was added in mysql 5.7.9 */
/* MYSQL_OPT_MAX_ALLOWED_PACKET was added in MariaDB 10.2.6 and MariaDB 10.3.1 */
@@ -3666,7 +3699,7 @@ SV* mariadb_db_FETCH_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv)
}
else if (memEQs(key, kl, "mariadb_hostinfo"))
{
- const char *hostinfo = imp_dbh->pmysql ? mysql_get_host_info(imp_dbh->pmysql) : NULL;
+ const char *hostinfo = imp_dbh->pmysql ? (imp_dbh->is_embedded ? "Embedded" : mysql_get_host_info(imp_dbh->pmysql)) : NULL;
result = hostinfo ? sv_2mortal(newSVpv(hostinfo, 0)) : &PL_sv_undef;
sv_utf8_decode(result);
}
@@ -3684,6 +3717,11 @@ SV* mariadb_db_FETCH_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv)
else if (memEQs(key, kl, "mariadb_max_allowed_packet"))
{
unsigned long packet_size;
+ if (imp_dbh->is_embedded)
+ {
+ mariadb_dr_do_error(dbh, CR_UNKNOWN_ERROR, "mariadb_max_allowed_packet is not supported for Embedded server", "HY000");
+ return Nullsv;
+ }
#if (!defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709 && MYSQL_VERSION_ID != 60000) || (defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100206 && MYSQL_VERSION_ID != 100300)
/* mysql_get_option() is not available in all versions */
/* if we do not have mysql_get_option() we cannot retrieve max_allowed_packet */
@@ -3961,6 +3999,11 @@ mariadb_st_prepare_sv(
(void)hv_stores(processed, "mariadb_async", &PL_sv_yes);
svp = MARIADB_DR_ATTRIB_GET_SVPS(attribs, "mariadb_async");
if(svp && SvTRUE(*svp)) {
+ if (imp_dbh->is_embedded)
+ {
+ mariadb_dr_do_error(sth, CR_UNKNOWN_ERROR, "Async option not supported for Embedded server", "HY000");
+ return 0;
+ }
imp_sth->is_async = TRUE;
if (imp_sth->disable_fallback_for_server_prepare)
{
@@ -4210,7 +4253,7 @@ static bool mariadb_st_free_result_sets(SV *sth, imp_sth_t *imp_sth, bool free_l
/* This is error for previous unfetched result ret. So do not report server errors to caller which is expecting new result set. */
error = mysql_errno(imp_dbh->pmysql);
- if (error == CR_COMMANDS_OUT_OF_SYNC || error == CR_OUT_OF_MEMORY || error == CR_SERVER_GONE_ERROR || error == CR_SERVER_LOST || error == CR_UNKNOWN_ERROR)
+ if (error == CR_COMMANDS_OUT_OF_SYNC || error == CR_OUT_OF_MEMORY || error == CR_SERVER_GONE_ERROR || error == CR_SERVER_LOST || error == ER_CLIENT_INTERACTION_TIMEOUT || error == CR_UNKNOWN_ERROR)
{
mariadb_dr_do_error(sth, mysql_errno(imp_dbh->pmysql), mysql_error(imp_dbh->pmysql), mysql_sqlstate(imp_dbh->pmysql));
return FALSE;
@@ -4558,7 +4601,7 @@ static my_ulonglong mariadb_st_internal_execute(
* Inputs: h - object handle, for storing error messages
* statement - query being executed
* attribs - statement attributes, currently ignored
- * has_params - non-zero parameters being bound
+ * num_params - number of parameters being bound
* params - parameter array
* result - where to store results, if any
* svsock - socket connected to the database
@@ -4569,7 +4612,7 @@ static my_ulonglong mariadb_st_internal_execute41(
SV *h,
char *sbuf,
STRLEN slen,
- bool has_params,
+ int num_params,
MYSQL_RES **result,
MYSQL_STMT **stmt_ptr,
MYSQL_BIND *bind,
@@ -4612,9 +4655,13 @@ static my_ulonglong mariadb_st_internal_execute41(
we have to rebind them
*/
- if (!reconnected && has_params && !(*has_been_bound))
+ if (!reconnected && num_params > 0 && !(*has_been_bound))
{
+#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80300
+ if (mysql_stmt_bind_named_param(stmt, bind, num_params, NULL) == 0)
+#else
if (mysql_stmt_bind_param(stmt,bind) == 0)
+#endif
{
*has_been_bound = TRUE;
}
@@ -4627,7 +4674,9 @@ static my_ulonglong mariadb_st_internal_execute41(
}
if (DBIc_TRACE_LEVEL(imp_xxh) >= 2)
- PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\t\tmariadb_st_internal_execute41 calling mysql_execute\n");
+ PerlIO_printf(DBIc_LOGPIO(imp_xxh),
+ "\t\tmariadb_st_internal_execute41 calling mysql_execute with %d num_params\n",
+ num_params);
if (!reconnected)
{
@@ -4652,9 +4701,13 @@ static my_ulonglong mariadb_st_internal_execute41(
}
mysql_stmt_close(*stmt_ptr);
*stmt_ptr = stmt;
- if (has_params)
+ if (num_params > 0)
{
+#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80300
+ if (mysql_stmt_bind_named_param(stmt, bind, num_params, NULL) == 0)
+#else
if (mysql_stmt_bind_param(stmt,bind))
+#endif
goto error;
*has_been_bound = TRUE;
}
@@ -4813,7 +4866,7 @@ IV mariadb_st_execute_iv(SV* sth, imp_sth_t* imp_sth)
sth,
imp_sth->statement,
imp_sth->statement_len,
- !!(DBIc_NUM_PARAMS(imp_sth) > 0),
+ DBIc_NUM_PARAMS(imp_sth),
&imp_sth->result,
&imp_sth->stmt,
imp_sth->bind,
@@ -6401,8 +6454,10 @@ bool mariadb_db_reconnect(SV *h, MYSQL_STMT *stmt)
if (imp_dbh->pmysql &&
mysql_errno(imp_dbh->pmysql) != CR_SERVER_GONE_ERROR &&
mysql_errno(imp_dbh->pmysql) != CR_SERVER_LOST &&
+ mysql_errno(imp_dbh->pmysql) != ER_CLIENT_INTERACTION_TIMEOUT &&
(!stmt || (mysql_stmt_errno(stmt) != CR_SERVER_GONE_ERROR &&
mysql_stmt_errno(stmt) != CR_SERVER_LOST &&
+ mysql_stmt_errno(stmt) != ER_CLIENT_INTERACTION_TIMEOUT &&
mysql_stmt_errno(stmt) != CR_STMT_CLOSED)))
{
/* Other error */
diff --git a/dbdimp.h b/dbdimp.h
index 8b715810..765306b2 100644
--- a/dbdimp.h
+++ b/dbdimp.h
@@ -86,6 +86,11 @@
#define CR_STMT_CLOSED 2056
#endif
+/* Macro was added in MySQL 8.0.24 */
+#ifndef ER_CLIENT_INTERACTION_TIMEOUT
+#define ER_CLIENT_INTERACTION_TIMEOUT 4031
+#endif
+
/********************************************************************
* Standard Perl macros which are not defined in every Perl version *
@@ -527,6 +532,7 @@ struct imp_dbh_st {
MYSQL *pmysql;
int sock_fd;
bool connected; /* Set to true after DBI->connect finished */
+ bool is_embedded;
bool auto_reconnect;
bool bind_type_guessing;
bool bind_comment_placeholders;
diff --git a/lib/DBD/MariaDB.pm b/lib/DBD/MariaDB.pm
index bd5c6488..515c8f17 100644
--- a/lib/DBD/MariaDB.pm
+++ b/lib/DBD/MariaDB.pm
@@ -731,7 +731,6 @@ my %odbc_info_constants = (
169 => 127, # SQL_AGGREGATE_FUNCTIONS
117 => 0, # SQL_ALTER_DOMAIN
86 => 3, # SQL_ALTER_TABLE
- 10021 => 2, # SQL_ASYNC_MODE
120 => 2, # SQL_BATCH_ROW_COUNT
121 => 2, # SQL_BATCH_SUPPORT
82 => 0, # SQL_BOOKMARK_PERSISTENCE
@@ -905,6 +904,7 @@ my %odbc_info_constants = (
);
my %odbc_info_subs = (
+ 10021 => sub { $_[0]->FETCH('mariadb_hostinfo') eq 'Embedded' ? 0 : 2 }, # SQL_ASYNC_MODE
2 => sub { "DBI:MariaDB:" . $_[0]->{Name} }, # SQL_DATA_SOURCE_NAME
17 => sub { ($_[0]->FETCH('mariadb_serverinfo') =~ /MariaDB|-maria-/) ? 'MariaDB' : 'MySQL' }, # SQL_DBMS_NAME
18 => sub { my $ver = $_[0]->FETCH('mariadb_serverversion'); sprintf("%02u.%02u.%02u00", $ver/10000, ($ver%10000)/100, $ver%100) }, # SQL_DBMS_VER
diff --git a/lib/DBD/MariaDB.pod b/lib/DBD/MariaDB.pod
index c5cf8d04..4ea097b1 100644
--- a/lib/DBD/MariaDB.pod
+++ b/lib/DBD/MariaDB.pod
@@ -364,15 +364,20 @@ Example:
use DBI;
my $datadir = '/var/lib/mysql/';
- my $langdir = '/usr/share/mysql/english';
+ my $langdir = '/usr/share/mysql/';
my $dsn = 'DBI:MariaDB:host=embedded;database=test;'
- . "mariadb_embedded_options=--datadir=$datadir,--language=$langdir";
+ . "mariadb_embedded_options=--datadir=$datadir,'
+ . '--language=$langdir,'
+ . '--log-error=/dev/null";
my $dbh = DBI->connect($dsn, undef, undef);
This would start embedded server with language directory C<$langdir>, database
-directory C<$datadir> and connects to database C. Embedded server does not
-have to be supported by configured MariaDB or MySQL library. In that case
-Lconnect() >>|/connect> returns an error.
+directory C<$datadir>, drop error messages and connects to database C.
+It is suggested to specify C<--log-error=> option which defines location for
+warning messages because by default Embedded server prints its warning and
+error messages to C which is not expected by Perl or application.
+Embedded server does not have to be supported by configured MariaDB or MySQL
+library. In that case Lconnect() >>|/connect> returns an error.
=item mariadb_embedded_groups
diff --git a/t/10connect.t b/t/10connect.t
index e629af0f..abc677b0 100644
--- a/t/10connect.t
+++ b/t/10connect.t
@@ -32,8 +32,9 @@ for my $attribute ( qw(
mariadb_stat
mariadb_protoinfo
) ) {
- ok($dbh->{$attribute}, "Value of '$attribute'");
- diag "$attribute is: ". $dbh->{$attribute};
+ my $value = $dbh->{$attribute};
+ ok(defined $value, "Value of '$attribute'");
+ diag "$attribute is: ". (defined $value ? $value : "(undef)");
}
my $sql_dbms_name = $dbh->get_info($GetInfoType{SQL_DBMS_NAME});
diff --git a/t/12embedded.t b/t/12embedded.t
index 88327cf3..901eee22 100644
--- a/t/12embedded.t
+++ b/t/12embedded.t
@@ -3,32 +3,27 @@ use warnings;
use Test::More;
use DBI;
+use DBD::MariaDB;
use File::Temp;
-use vars qw($test_dsn $test_user $test_password);
+use vars qw($test_dsn $test_user $test_password $test_emboptions);
use lib 't', '.';
require 'lib.pl';
-sub fatal_tmpdir_error {
+sub get_error {
my $err = $@;
$err =~ s/ at \S+ line \d+\.?\s*$//;
$err = 'unknown error' unless $err;
- fatal("Cannot create temporary directory: $err");
- if ( $ENV{CONNECTION_TESTING} ) {
- BAIL_OUT "Cannot create temporary directory: $err";
- } else {
- plan skip_all => "Cannot create temporary directory: $err";
- }
+ return $err;
}
sub fatal_connection_error {
- my $err = $@;
- $err =~ s/ at \S+ line \d+\.?\s*$//;
- $err = 'unknown error' unless $err;
+ my ($type) = @_;
+ my $err = get_error();
if ( $ENV{CONNECTION_TESTING} ) {
- BAIL_OUT "No connection to embedded server: $err";
+ BAIL_OUT "No connection to $type server: $err";
} else {
- diag "No connection to embedded server: $err";
+ diag "No connection to $type server: $err";
done_testing;
exit;
}
@@ -36,41 +31,36 @@ sub fatal_connection_error {
sub connect_to_embedded_server {
my ($tmpdir, $database) = @_;
- my $lang_arg = $ENV{DBD_MARIADB_TESTLANGDIR} ? ",--language=$ENV{DBD_MARIADB_TESTLANGDIR}" : '';
- my $emb_dsn = "DBI:MariaDB:host=embedded;mariadb_embedded_options=--datadir=$tmpdir$lang_arg;";
- $emb_dsn .= "database=$database" if defined $database;
+ my $emb_dsn = "DBI:MariaDB:host=embedded;mariadb_embedded_options=--datadir=$tmpdir";
+ $emb_dsn .= ",$test_emboptions" if length $test_emboptions;
+ $emb_dsn .= ";database=$database" if defined $database;
return eval { DBI->connect($emb_dsn, undef, undef, { RaiseError => 1, PrintError => 0 }) };
}
sub connect_to_real_server {
- my $dbh = eval { DBI->connect($test_dsn, $test_user, $test_password, { RaiseError => 1, PrintError => 0, AutoCommit => 0 }) };
- if (not defined $dbh) {
- my $err = $@;
- $err =~ s/ at \S+ line \d+\.?\s*$//;
- $err = 'unknown error' unless $err;
- if ( $ENV{CONNECTION_TESTING} ) {
- BAIL_OUT "No connection to real non-embedded server: $err";
- } else {
- diag "No connection to real non-embedded server: $err";
- }
- }
- return $dbh;
+ return eval { DBI->connect($test_dsn, $test_user, $test_password, { RaiseError => 1, PrintError => 0, AutoCommit => 0 }) };
+}
+
+sub test_dsn_uses_embedded_server {
+ my ($dbi_dsn, $driver_dsn) = ($test_dsn =~ /^([^:]*:[^:]*:)(.*)$/);
+ my $attr_dsn = DBD::MariaDB->parse_dsn($driver_dsn);
+ return exists $attr_dsn->{host} && $attr_dsn->{host} eq 'embedded';
}
-my $tmpdir1 = eval { File::Temp::tempdir(CLEANUP => 1) } or fatal_tmpdir_error();
-my $tmpdir2 = eval { File::Temp::tempdir(CLEANUP => 1) } or fatal_tmpdir_error();
+my $tmpdir1 = File::Temp::tempdir(CLEANUP => 1);
+my $tmpdir2 = File::Temp::tempdir(CLEANUP => 1);
my $dbh1 = connect_to_embedded_server($tmpdir1);
plan skip_all => $DBI::errstr if not defined $dbh1 and $DBI::errstr =~ /Embedded server is not supported/;
-ok(defined $dbh1, "Connected to embedded server with datadir in $tmpdir1") or fatal_connection_error();
+ok(defined $dbh1, "Connected to embedded server with datadir in $tmpdir1") or fatal_connection_error('embedded');
ok($dbh1->do('CREATE DATABASE dbd_mariadb_embedded'), 'Created database');
ok($dbh1->do('USE dbd_mariadb_embedded'), 'Switched to database');
my $dbh2 = connect_to_embedded_server($tmpdir1, 'dbd_mariadb_embedded');
-ok(defined $dbh2, "Second connection to embedded server with datadir in $tmpdir1") or fatal_connection_error();
+ok(defined $dbh2, "Second connection to embedded server with datadir in $tmpdir1") or fatal_connection_error('embedded');
my $dbh3 = connect_to_embedded_server($tmpdir1, 'dbd_mariadb_embedded');
-ok(defined $dbh3, "Third conection to embedded server with datadir in $tmpdir1") or fatal_connection_error();
+ok(defined $dbh3, "Third connection to embedded server with datadir in $tmpdir1") or fatal_connection_error('embedded');
ok($dbh1->do('CREATE TABLE dbd_mariadb_embedded(id INT)'), 'Created table with first connection');
ok($dbh2->do('INSERT INTO dbd_mariadb_embedded(id) VALUES(10)'), 'Inserted values into table with second connection');
@@ -81,9 +71,10 @@ is(scalar $dbh3->selectrow_array('SELECT id FROM dbd_mariadb_embedded'), 10, 'Fe
ok(!defined connect_to_embedded_server($tmpdir2), "Not connected to different embedded server with datadir in $tmpdir2 while previous connection to embedded server are still active");
SKIP: {
+ skip 'No connection to real non-embedded server: Test suite uses embedded server only', 3 if test_dsn_uses_embedded_server();
my $dbh4 = connect_to_real_server();
- skip 'No connection to real non-embedded server', 3 unless defined $dbh4;
- ok(defined $dbh4, 'Connected to real non-embedded server');
+ skip 'No connection to real non-embeeded server: ' . get_error(), 3 if not defined $dbh4 and not $ENV{CONNECTION_TESTING};
+ ok(defined $dbh4, 'Connected to real non-embedded server') or fatal_connection_error('real non-embedded');
ok(!defined $dbh4->selectrow_array('SHOW TABLES LIKE "dbd_mariadb_embedded"'), 'Real non-embedded server does not have tables from embedded server');
ok($dbh4->disconnect(), 'Disconnected from real non-embedded server');
}
diff --git a/t/15reconnect.t b/t/15reconnect.t
index 9c501c37..b6c4d82f 100644
--- a/t/15reconnect.t
+++ b/t/15reconnect.t
@@ -16,7 +16,7 @@ $dbh = DbiTestConnect($test_dsn, $test_user, $test_password,
{ RaiseError => 1, PrintError => 0 });
$dbh->disconnect();
-plan tests => 21 * 2;
+plan tests => 30 * 2;
for my $mariadb_server_prepare (0, 1) {
$dbh= DBI->connect("$test_dsn;mariadb_server_prepare=$mariadb_server_prepare;mariadb_server_prepare_disable_fallback=1", $test_user, $test_password,
@@ -38,12 +38,18 @@ ok($dbh->do("SELECT 1"), "implicitly reconnecting handle with 'do'");
ok($dbh->{Active}, "checking for reactivated handle");
+SKIP: {
+
+skip "Connection to Embedded server does not have socket", 3 if $dbh->{mariadb_hostinfo} eq 'Embedded';
+
ok(shutdown_mariadb_socket($dbh), "shutdown socket handle");
ok($dbh->do("SELECT 1"), "implicitly reconnecting handle after shutdown with 'do'");
ok($dbh->{Active}, "checking for reactivated handle");
+}
+
ok($dbh->disconnect(), "disconnecting active handle");
ok(!$dbh->{Active}, "checking for inactive handle");
@@ -68,5 +74,34 @@ ok($dbh->{Active}, "checking for reactivated handle");
$sth->finish();
+ok($dbh->do("SET SESSION wait_timeout=1"), "set wait_timeout to 1");
+
+note("call perl sleep 2 for implicit disconnect due to wait_timeout");
+sleep(2);
+
+ok($sth = $dbh->prepare("SELECT 1"), "implicitly reconnecting handle with preparing statement");
+
+ok($sth->execute(), "execute prepared statement");
+
+ok($dbh->{Active}, "checking for reactivated handle");
+
+ok($sth = $dbh->prepare("SELECT 1"), "prepare statement");
+
+note("call perl sleep 2 for implicit disconnect due to wait_timeout");
+sleep(2);
+
+ok($sth->execute(), "implicitly reconnecting handle with executing prepared statement");
+
+ok($dbh->{Active}, "checking for reactivated handle");
+
+$sth->finish();
+
+note("call perl sleep 2 for implicit disconnect due to wait_timeout");
+sleep(2);
+
+ok($dbh->do("SELECT 1"), "implicitly reconnecting handle with 'do'");
+
+ok($dbh->{Active}, "checking for reactivated handle");
+
$dbh->disconnect();
}
diff --git a/t/17close_on_exec.t b/t/17close_on_exec.t
index c34e2389..d7b2acd0 100644
--- a/t/17close_on_exec.t
+++ b/t/17close_on_exec.t
@@ -10,6 +10,8 @@ require 'lib.pl';
my $dbh = DbiTestConnect($test_dsn, $test_user, $test_password, { RaiseError => 1, PrintError => 0 });
+plan skip_all => "Connection to Embedded server does not have socket" if $dbh->{mariadb_hostinfo} eq 'Embedded';
+
plan tests => 2;
# Spawn new perl child process with MariaDB file descriptor passed as first argument and check that it is invalid (EBADF) in spawned process
diff --git a/t/18begin_work_without_raise_error.t b/t/18begin_work_without_raise_error.t
index 816cbcb4..605b563d 100644
--- a/t/18begin_work_without_raise_error.t
+++ b/t/18begin_work_without_raise_error.t
@@ -10,6 +10,8 @@ require 'lib.pl';
my $dbh = DbiTestConnect($test_dsn, $test_user, $test_password, { RaiseError => 0, PrintError => 1 });
+plan skip_all => "Connection to Embedded server does not have socket" if $dbh->{mariadb_hostinfo} eq 'Embedded';
+
plan tests => 12;
my $warn;
diff --git a/t/78use_result.t b/t/78use_result.t
index a0c903df..1d9723bd 100644
--- a/t/78use_result.t
+++ b/t/78use_result.t
@@ -4,6 +4,7 @@ use warnings;
use Test::More;
use Test::Deep;
use DBI;
+use DBI::Const::GetInfoType;
use vars qw($test_dsn $test_user $test_password);
use lib 't', '.';
@@ -11,7 +12,10 @@ require 'lib.pl';
my $dbh1 = DbiTestConnect($test_dsn, $test_user, $test_password, { RaiseError => 1, PrintError => 0 });
-plan tests => 12 + 2*2*2*1 + 3 * (2*2*2*13 + 2*2*2 + 2*2*9);
+my $have_async_support = $dbh1->get_info($GetInfoType{'SQL_ASYNC_MODE'});
+
+my $mult = ($have_async_support ? 2 : 1);
+plan tests => 12 + 2*$mult*2*1 + 3 * (2*$mult*2*13 + 2*$mult*9) + ($have_async_support ? 3*2*2*2 : 0);
$SIG{__WARN__} = sub { die @_ };
@@ -45,7 +49,7 @@ for my $multi_statements (0, 1) {
$dbh->do('INSERT INTO t VALUES(1, 20)');
$dbh->do('INSERT INTO t VALUES(2, 30)');
- for my $async (0, 1) {
+ for my $async (0, ($have_async_support ? 1 : ())) {
for my $use_result (0, 1) {
diff --git a/t/87async.t b/t/87async.t
index b65b6172..eb9afad5 100644
--- a/t/87async.t
+++ b/t/87async.t
@@ -16,7 +16,10 @@ my $dbh = DbiTestConnect($test_dsn, $test_user, $test_password,
if ($dbh->{mariadb_serverversion} < 50012) {
plan skip_all => "Servers < 5.0.12 do not support SLEEP()";
}
-plan tests => 147;
+if ($dbh->{mariadb_hostinfo} eq 'Embedded') {
+ plan skip_all => 'Async mode is not supported for Embedded server';
+}
+plan tests => 150;
is $dbh->get_info($GetInfoType{'SQL_ASYNC_MODE'}), 2; # statement-level async
is $dbh->get_info($GetInfoType{'SQL_MAX_ASYNC_CONCURRENT_STATEMENTS'}), 1;
@@ -46,7 +49,7 @@ cmp_ok(($end - $start), '>=', 1.9);
$start = Time::HiRes::gettimeofday();
$rows = $dbh->do('INSERT INTO async_test VALUES (SLEEP(2), 0, 0)', { mariadb_async => 1 });
-ok(defined($dbh->mariadb_async_ready)) or die;
+ok defined($dbh->mariadb_async_ready);
$end = Time::HiRes::gettimeofday();
ok $rows;
@@ -54,7 +57,11 @@ is $rows, '0E0';
cmp_ok(($end - $start), '<', 2);
-sleep 1 until $dbh->mariadb_async_ready;
+for (1..120) {
+ last if $dbh->mariadb_async_ready;
+ sleep 1;
+}
+ok $dbh->mariadb_async_ready;
$end = Time::HiRes::gettimeofday();
cmp_ok(($end - $start), '>=', 1.9);
@@ -65,7 +72,7 @@ is $rows, 1;
$start = Time::HiRes::gettimeofday();
$rows = $dbh->do('INSERT INTO async_test VALUES (SLEEP(2), 0, 0)', { mariadb_async => 1 });
-ok(defined($dbh->mariadb_async_ready)) or die;
+ok defined($dbh->mariadb_async_ready);
$end = Time::HiRes::gettimeofday();
ok $rows;
@@ -104,7 +111,11 @@ is $rows, '0E0';
cmp_ok(($end - $start), '<', 2);
-sleep 1 until $dbh->mariadb_async_ready;
+for (1..120) {
+ last if $dbh->mariadb_async_ready;
+ sleep 1;
+}
+ok $dbh->mariadb_async_ready;
$end = Time::HiRes::gettimeofday();
cmp_ok(($end - $start), '>=', 1.9);
@@ -139,7 +150,11 @@ $end = Time::HiRes::gettimeofday();
cmp_ok(($end - $start), '<', 2);
ok $sth->{Active};
-sleep 1 until $sth->mariadb_async_ready;
+for (1..120) {
+ last if $sth->mariadb_async_ready;
+ sleep 1;
+}
+ok $sth->mariadb_async_ready;
ok $sth->{Active};
my $row = $sth->fetch;
diff --git a/t/88async-multi-stmts.t b/t/88async-multi-stmts.t
index aa4befa3..629624f5 100644
--- a/t/88async-multi-stmts.t
+++ b/t/88async-multi-stmts.t
@@ -10,6 +10,7 @@ require 'lib.pl';
my $dbh = DbiTestConnect($test_dsn, $test_user, $test_password,
{ RaiseError => 0, PrintError => 0, AutoCommit => 0, mariadb_multi_statements => 1 });
+plan skip_all => 'Async mode is not supported for Embedded server' if $dbh->{mariadb_hostinfo} eq 'Embedded';
plan tests => 104;
ok $dbh->do(< 0, PrintError => 0, AutoCommit => 0 });
+plan skip_all => 'Async mode is not supported for Embedded server' if $dbh->{mariadb_hostinfo} eq 'Embedded';
plan tests =>
2 * @db_safe_methods +
4 * @db_unsafe_methods +
diff --git a/t/lib.pl b/t/lib.pl
index 2139d144..b0ca8809 100644
--- a/t/lib.pl
+++ b/t/lib.pl
@@ -3,7 +3,7 @@
use Test::More;
use FindBin qw($Bin);
-use vars qw($test_dsn $test_user $test_password $test_db);
+use vars qw($test_dsn $test_user $test_password $test_db $test_emboptions);
use DBD::MariaDB;
@@ -91,7 +91,10 @@ sub shutdown_mariadb_socket {
# close automatically close C file descriptor in Perl file handle
# mysql client library does not expect if somebody closes its file descriptors
# so always take a copy of mariadb_sockfd() C file descriptor and just shutdown it
- open my $socket, '+<&', $dbh->mariadb_sockfd();
+ my $fd = $dbh->mariadb_sockfd();
+ return undef unless defined $fd;
+ open my $socket, '+<&', $fd;
+ return undef unless defined $socket;
my $ret = shutdown($socket, 2);
close $socket;
return $ret;
diff --git a/t/rt110983-valid-mysqlfd.t b/t/rt110983-valid-mysqlfd.t
index 914fd862..909d0d05 100644
--- a/t/rt110983-valid-mysqlfd.t
+++ b/t/rt110983-valid-mysqlfd.t
@@ -10,6 +10,8 @@ require "lib.pl";
my $dbh = DbiTestConnect($test_dsn, $test_user, $test_password, { RaiseError => 1, PrintError => 0, AutoCommit => 0 });
+plan skip_all => "Connection to Embedded server does not have socket" if $dbh->{mariadb_hostinfo} eq 'Embedded';
+
plan tests => 4;
my $fd = $dbh->mariadb_sockfd;
diff --git a/t/rt85919-fetch-lost-connection.t b/t/rt85919-fetch-lost-connection.t
index f418a7c5..d1684d8d 100644
--- a/t/rt85919-fetch-lost-connection.t
+++ b/t/rt85919-fetch-lost-connection.t
@@ -8,6 +8,9 @@ require 'lib.pl';
my $dbh = DbiTestConnect($test_dsn, $test_user, $test_password,
{ RaiseError => 1, PrintError => 0, AutoCommit => 0 });
+if ($dbh->{mariadb_hostinfo} eq 'Embedded') {
+ plan skip_all => "Connection to Embedded server is not disconnected on wait_timeout";
+}
my $sth;
my $ok = eval {
note "Connecting...\n";