diff --git a/.github/issue_template.md b/.github/issue_template.md
index b3eea73693..0d7f157578 100644
--- a/.github/issue_template.md
+++ b/.github/issue_template.md
@@ -1,17 +1,23 @@
-This is the place for paid support and community users to report a **reproducible bug** in ProxySQL, suggest enhancements or make feature requests. This also includes documentation errors and/or missing documentation.
+This is the place to report a **reproducible bug**, **documentation error** or **feature request** for ProxySQL.
-* Remember, this is the place for fixing and improving ProxySQL rather than the place to get free support.
-* If you do not have a paid support contract please try https://groups.google.com/forum/#!forum/proxysql. Due to the high volume of requests, we are unable to always provide timely support for community users.
+Support questions will not be answered here. For community support, use the Google forum: https://groups.google.com/forum/#!forum/proxysql
+* Note that due to time constraints ProxySQL engineers may be slow to respond to forum posts
+* For information on paid support contracts: https://proxysql.com/services/support/
If you are submitting a reproducible bug report, please provide:
-[ ] A clear description of your issue
-[ ] The version of OS and ProxySQL
-[ ] Every step to reproduce the issue
-[ ] The FULL error log (not just the last few lines)
-[ ] If it is a crashing bug, please check here: https://github.com/sysown/proxysql/wiki/How-to-report-a-crash-bug
+- [ ] A clear description of the issue
+- [ ] ProxySQL version
+- [ ] OS version
+- [ ] The steps to reproduce the issue
+- [ ] The **full** ProxySQL error log (default location: `/var/lib/proxysql/proxysql.log`)
-If the above is not provided, the issue is likely to be closed.
+If this is a crashing bug, please also include:
+- [ ] The package used to install ProxySQL
+- [ ] The compressed proxysql binary
+- [ ] The compressed core dump (Note: if you're worried it may contain sensitive data, please contact us for information on sharing it securely: https://proxysql.com/contact-us/)
-Please use markdown to format code or SQL: https://guides.github.com/features/mastering-markdown/
+If the above information is not provided, this issue is likely to be closed.
+
+Please use markdown to format any code or SQL: https://guides.github.com/features/mastering-markdown/
Thank you!
diff --git a/.gitignore b/.gitignore
index 643411a12d..549562a1f4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -170,3 +170,6 @@ heaptrack.*
#tap tests
*-t
+
+#prometheus in 1.4
+deps/prometheus-cpp/prometheus-cpp-0.9.0/
diff --git a/Makefile b/Makefile
index b275a5d45f..a045861eb6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,10 @@
+ifndef GIT_VERSION
+GIT_VERSION := $(shell git describe --long)
+ifndef GIT_VERSION
+$(error GIT_VERSION is not set)
+endif
+endif
+
O0=-O0
O2=-O2
O1=-O1
@@ -11,7 +18,7 @@ DEBUG=${ALL_DEBUG}
#export OPTZ
#export EXTRALINK
export MAKE
-export CURVER?=2.0.10
+export CURVER?=2.0.13
ifneq (,$(wildcard /etc/os-release))
DISTRO := $(shell gawk -F= '/^NAME/{print $$2}' /etc/os-release)
else
@@ -157,7 +164,7 @@ clean:
cd src && ${MAKE} clean
cd test/tap && ${MAKE} clean
-packages: centos7 centos7-dbg centos7-clickhouse centos8 centos8-dbg centos8-clickhouse ubuntu14 ubuntu14-dbg ubuntu16 ubuntu16-dbg ubuntu16-clickhouse ubuntu18 ubuntu18-dbg ubuntu18-clickhouse debian8 debian8-dbg debian9 debian9-dbg debian9-clickhouse debian10 debian10-dbg debian10-clickhouse fedora24 fedora24-dbg fedora24-clickhouse fedora27 fedora27-dbg fedora27-clickhouse fedora28 fedora28-dbg fedora28-clickhouse
+packages: centos6.7 centos6.7-dbg centos7 centos7-dbg centos7-clickhouse centos8 centos8-dbg centos8-clickhouse ubuntu14 ubuntu14-dbg ubuntu16 ubuntu16-dbg ubuntu16-clickhouse ubuntu18 ubuntu18-dbg ubuntu18-clickhouse debian8 debian8-dbg debian9 debian9-dbg debian9-clickhouse debian10 debian10-dbg debian10-clickhouse fedora24 fedora24-dbg fedora24-clickhouse fedora27 fedora27-dbg fedora27-clickhouse fedora28 fedora28-dbg fedora28-clickhouse
.PHONY: packages
centos5: binaries/proxysql-${CURVER}-1-centos5.x86_64.rpm
diff --git a/README.md b/README.md
index ef3229fe8f..6a0fd9ae1e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
Introduction
============
@@ -143,7 +143,15 @@ Admin> proxysql restart
#### Reinitializing ProxySQL from the config file (after first startup the DB file is used instead of the config file):
```bash
+# If you are using the init script run:
+/etc/init.d/proxysql initial
+# or
service proxysql initial
+
+# If you are using the systemd unit file run:
+systemctl start proxysql-initial
+# or
+service proxysql-initial start
```
### Upgrades
diff --git a/docker-compose.yml b/docker-compose.yml
index b5a16e49b8..d0a217efcd 100755
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,32 +1,5 @@
version: "2.0"
services:
- centos5_build:
- image: proxysql/packaging:build-centos5
- volumes:
- - ./docker/images/proxysql/rhel-compliant/rpmmacros/:/root/
- - ./docker/images/proxysql/rhel-compliant/entrypoint/:/opt/entrypoint/
- - ./:/opt/proxysql/
- environment:
- - MAKE
- - MAKEOPT
- - CURVER
- - PKG_RELEASE=centos5
- command:
- - /opt/entrypoint/entrypoint.bash
- centos5_dbg_build:
- image: proxysql/packaging:build-centos5
- volumes:
- - ./docker/images/proxysql/rhel-compliant/rpmmacros/:/root/
- - ./docker/images/proxysql/rhel-compliant/entrypoint/:/opt/entrypoint/
- - ./:/opt/proxysql/
- environment:
- - MAKE
- - MAKEOPT
- - CURVER
- - PKG_RELEASE=dbg-centos5
- - PROXYSQL_BUILD_TYPE=debug
- command:
- - /opt/entrypoint/entrypoint.bash
centos67_build:
image: proxysql/packaging:build-centos6.7
volumes:
@@ -261,33 +234,6 @@ services:
- PROXYSQL_BUILD_TYPE=clickhouse
command:
- /opt/entrypoint/entrypoint.bash
- debian7_build:
- image: proxysql/packaging:build-debian7
- volumes:
- - ./docker/images/proxysql/deb-compliant/pre-systemd/ctl/:/root/ctl/
- - ./docker/images/proxysql/deb-compliant/entrypoint/:/opt/entrypoint/
- - ./:/opt/proxysql/
- environment:
- - MAKE
- - MAKEOPT
- - CURVER
- - PKG_RELEASE=debian7
- command:
- - /opt/entrypoint/entrypoint.bash
- debian7_dbg_build:
- image: proxysql/packaging:build-debian7
- volumes:
- - ./docker/images/proxysql/deb-compliant/pre-systemd/ctl/:/root/ctl/
- - ./docker/images/proxysql/deb-compliant/entrypoint/:/opt/entrypoint/
- - ./:/opt/proxysql/
- environment:
- - MAKE
- - MAKEOPT
- - CURVER
- - PKG_RELEASE=dbg-debian7
- - PROXYSQL_BUILD_TYPE=debug
- command:
- - /opt/entrypoint/entrypoint.bash
debian8_build:
image: proxysql/packaging:build-debian8
volumes:
@@ -438,33 +384,6 @@ services:
- PROXYSQL_BUILD_TYPE=clickhouse
command:
- /opt/entrypoint/entrypoint.bash
- ubuntu12_build:
- image: proxysql/packaging:build-ubuntu12
- volumes:
- - ./docker/images/proxysql/deb-compliant/pre-systemd/ctl/:/root/ctl/
- - ./docker/images/proxysql/deb-compliant/entrypoint/:/opt/entrypoint/
- - ./:/opt/proxysql/
- environment:
- - MAKE
- - MAKEOPT
- - CURVER
- - PKG_RELEASE=ubuntu12
- command:
- - /opt/entrypoint/entrypoint.bash
- ubuntu12_dbg_build:
- image: proxysql/packaging:build-ubuntu12
- volumes:
- - ./docker/images/proxysql/deb-compliant/pre-systemd/ctl/:/root/ctl/
- - ./docker/images/proxysql/deb-compliant/entrypoint/:/opt/entrypoint/
- - ./:/opt/proxysql/
- environment:
- - MAKE
- - MAKEOPT
- - CURVER
- - PKG_RELEASE=dbg-ubuntu12
- - PROXYSQL_BUILD_TYPE=debug
- command:
- - /opt/entrypoint/entrypoint.bash
ubuntu14_build:
image: proxysql/packaging:build-ubuntu14
volumes:
diff --git a/docker/images/proxysql/deb-compliant/ctl/proxysql.ctl b/docker/images/proxysql/deb-compliant/ctl/proxysql.ctl
index 3e47657975..764b93cf24 100644
--- a/docker/images/proxysql/deb-compliant/ctl/proxysql.ctl
+++ b/docker/images/proxysql/deb-compliant/ctl/proxysql.ctl
@@ -1,17 +1,19 @@
Section: misc
Priority: optional
-Homepage: http://www.proxysql.com
+Homepage: https://proxysql.com
Standards-Version: 3.9.2
Package: proxysql
Version: PKG_VERSION_CURVER
-Maintainer: Rene Cannao
+Maintainer: ProxySQL LLC
Architecture: amd64
+Depends: libgnutls28 | libgnutls-deb0-28 | libgnutls30
# Changelog: CHANGELOG.md
# Readme: README.md
Files: proxysql /usr/bin/
etc/proxysql.cnf /
etc/logrotate.d/proxysql /etc/logrotate.d/
+ systemd/system/proxysql-initial.service /lib/
systemd/system/proxysql.service /lib/
tools/proxysql_galera_checker.sh /usr/share/proxysql/
tools/proxysql_galera_writer.pl /usr/share/proxysql/
diff --git a/docker/images/proxysql/deb-compliant/latest-package/ctl/proxysql.ctl b/docker/images/proxysql/deb-compliant/latest-package/ctl/proxysql.ctl
index aa33787ad4..f333e32e32 100644
--- a/docker/images/proxysql/deb-compliant/latest-package/ctl/proxysql.ctl
+++ b/docker/images/proxysql/deb-compliant/latest-package/ctl/proxysql.ctl
@@ -1,17 +1,19 @@
Section: misc
Priority: optional
-Homepage: http://www.proxysql.com
+Homepage: https://proxysql.com
Standards-Version: 3.9.2
Package: proxysql
Version: PKG_VERSION_CURVER
-Maintainer: Rene Cannao
+Maintainer: ProxySQL LLC
Architecture: amd64
+Depends: libgnutls28 | libgnutls30
# Changelog: CHANGELOG.md
# Readme: README.md
Files: proxysql /usr/bin/
etc/proxysql.cnf /etc/
etc/logrotate.d/proxysql /etc/logrotate.d/
+ systemd/system/proxysql-initial.service /lib/systemd/system/
systemd/system/proxysql.service /lib/systemd/system/
tools/proxysql_galera_checker.sh /usr/share/proxysql/tools/
tools/proxysql_galera_writer.pl /usr/share/proxysql/tools/
diff --git a/docker/images/proxysql/deb-compliant/pre-systemd/ctl/proxysql.ctl b/docker/images/proxysql/deb-compliant/pre-systemd/ctl/proxysql.ctl
index 04b76dc28c..eaf179bcc8 100644
--- a/docker/images/proxysql/deb-compliant/pre-systemd/ctl/proxysql.ctl
+++ b/docker/images/proxysql/deb-compliant/pre-systemd/ctl/proxysql.ctl
@@ -1,12 +1,13 @@
Section: misc
Priority: optional
-Homepage: http://www.proxysql.com
+Homepage: https://proxysql.com
Standards-Version: 3.9.2
Package: proxysql
Version: PKG_VERSION_CURVER
-Maintainer: Rene Cannao
+Maintainer: ProxySQL LLC
Architecture: amd64
+Depends: libgnutls28 | libgnutls30 | libgnutls-deb0-28
# Changelog: CHANGELOG.md
# Readme: README.md
Files: proxysql /usr/bin/
diff --git a/docker/images/proxysql/rhel-compliant/rhel7/rpmmacros/rpmbuild/SPECS/proxysql.spec b/docker/images/proxysql/rhel-compliant/rhel7/rpmmacros/rpmbuild/SPECS/proxysql.spec
index 4049b45dfa..06a41c513f 100644
--- a/docker/images/proxysql/rhel-compliant/rhel7/rpmmacros/rpmbuild/SPECS/proxysql.spec
+++ b/docker/images/proxysql/rhel-compliant/rhel7/rpmmacros/rpmbuild/SPECS/proxysql.spec
@@ -9,8 +9,8 @@ Release: 1
License: GPL+
Group: Development/Tools
SOURCE0 : %{name}-%{version}.tar.gz
-URL: http://www.proxysql.com/
-
+URL: https://proxysql.com/
+Requires: gnutls
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
%description
@@ -84,6 +84,7 @@ fi
%config(noreplace) %attr(640,root,%{name}) %{_sysconfdir}/logrotate.d/%{name}
%{_bindir}/*
%{_sysconfdir}/systemd/system/%{name}.service
+%{_sysconfdir}/systemd/system/%{name}-initial.service
/usr/share/proxysql/tools/proxysql_galera_checker.sh
/usr/share/proxysql/tools/proxysql_galera_writer.pl
diff --git a/docker/images/proxysql/rhel-compliant/rpmmacros/rpmbuild/SPECS/proxysql.spec b/docker/images/proxysql/rhel-compliant/rpmmacros/rpmbuild/SPECS/proxysql.spec
index 8432928c72..02ace66b50 100644
--- a/docker/images/proxysql/rhel-compliant/rpmmacros/rpmbuild/SPECS/proxysql.spec
+++ b/docker/images/proxysql/rhel-compliant/rpmmacros/rpmbuild/SPECS/proxysql.spec
@@ -13,7 +13,7 @@ License: GPL+
Group: Development/Tools
SOURCE0 : %{name}-%{version}.tar.gz
URL: http://www.proxysql.com/
-
+Requires: gnutls
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
%description
diff --git a/etc/init.d/proxysql b/etc/init.d/proxysql
index 768ca07d2b..a823cbd1e2 100755
--- a/etc/init.d/proxysql
+++ b/etc/init.d/proxysql
@@ -18,7 +18,7 @@
OLDDATADIR="/var/run/proxysql"
DATADIR="/var/lib/proxysql"
-OPTS="-c /etc/proxysql.cnf -D $DATADIR"
+OPTS="--idle-threads -c /etc/proxysql.cnf -D $DATADIR"
PIDFILE="$DATADIR/proxysql.pid"
USER="proxysql"
diff --git a/etc/proxysql.cnf b/etc/proxysql.cnf
index 833713d559..19669df532 100644
--- a/etc/proxysql.cnf
+++ b/etc/proxysql.cnf
@@ -27,7 +27,7 @@
# file is only used to initial the on-disk database read on the first startup.
#
# In order to FORCE a re-initialise of the on-disk database from the configuration file
-# the ProxySQL service should be started with "service proxysql initial".
+# the ProxySQL service should be started with "systemctl start proxysql-initial".
#
########################################################################################
diff --git a/include/MySQL_HostGroups_Manager.h b/include/MySQL_HostGroups_Manager.h
index 4b1514bc8d..069e2e5d5b 100644
--- a/include/MySQL_HostGroups_Manager.h
+++ b/include/MySQL_HostGroups_Manager.h
@@ -6,6 +6,7 @@
#include
#include
+#include
#include "thread.h"
#include "wqueue.h"
@@ -313,6 +314,7 @@ class MySQL_HostGroups_Manager {
umap_mysql_errors mysql_errors_umap;
public:
+ std::mutex galera_set_writer_mutex;
pthread_rwlock_t gtid_rwlock;
std::unordered_map gtid_map;
struct ev_async * gtid_ev_async;
diff --git a/include/MySQL_Thread.h b/include/MySQL_Thread.h
index f5d38b8b79..d0db853578 100644
--- a/include/MySQL_Thread.h
+++ b/include/MySQL_Thread.h
@@ -306,7 +306,7 @@ class MySQL_Threads_Handler
char *interfaces;
char *server_version;
char *keep_multiplexing_variables;
- unsigned int default_charset;
+ //unsigned int default_charset; // removed in 2.0.13 . Obsoleted previously using MySQL_Variables instead
unsigned int handle_unknown_charset;
bool servers_stats;
bool commands_stats;
@@ -394,6 +394,7 @@ class MySQL_Threads_Handler
} variables;
struct {
unsigned int mirror_sessions_current;
+ int threads_initialized = 0;
} status_variables;
unsigned int num_threads;
proxysql_mysql_thread_t *mysql_threads;
diff --git a/include/MySQL_Variables.h b/include/MySQL_Variables.h
index 674ee42202..79b98b8275 100644
--- a/include/MySQL_Variables.h
+++ b/include/MySQL_Variables.h
@@ -28,6 +28,9 @@ class MySQL_Variables {
static verify_var verifiers[SQL_NAME_LAST];
static update_var updaters[SQL_NAME_LAST];
+public:
+ std::string variables_regexp;
+
public:
MySQL_Variables();
diff --git a/include/mysql_connection.h b/include/mysql_connection.h
index 74b11c90ba..f946dbb1e6 100644
--- a/include/mysql_connection.h
+++ b/include/mysql_connection.h
@@ -18,6 +18,7 @@ using json = nlohmann::json;
#define STATUS_MYSQL_CONNECTION_SQL_LOG_BIN0 0x00000100
#define STATUS_MYSQL_CONNECTION_FOUND_ROWS 0x00000200
#define STATUS_MYSQL_CONNECTION_NO_BACKSLASH_ESCAPES 0x00000400
+#define STATUS_MYSQL_CONNECTION_HAS_SAVEPOINT 0x00000800
class Variable {
public:
@@ -146,6 +147,7 @@ class MySQL_Connection {
void set_status_no_backslash_escapes(bool);
void set_status_prepared_statement(bool);
void set_status_user_variable(bool);
+ void set_status_has_savepoint(bool);
void set_status_no_multiplex(bool);
void set_status_sql_log_bin0(bool);
void set_status_found_rows(bool);
@@ -157,6 +159,7 @@ class MySQL_Connection {
bool get_status_no_backslash_escapes();
bool get_status_prepared_statement();
bool get_status_user_variable();
+ bool get_status_has_savepoint();
bool get_status_no_multiplex();
bool get_status_sql_log_bin0();
bool get_status_found_rows();
diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h
index 97f8e1e1c5..e9ca940fb1 100644
--- a/include/proxysql_structs.h
+++ b/include/proxysql_structs.h
@@ -166,6 +166,7 @@ enum variable_name {
SQL_MAX_JOIN_SIZE,
SQL_LOG_BIN,
SQL_WSREP_SYNC_WAIT,
+ SQL_GROUP_CONCAT_MAX_LEN,
SQL_NAME_LAST
};
@@ -211,6 +212,7 @@ typedef struct {
char * set_variable_name; // what variable name (or string) will be used when setting it to backend
char * internal_variable_name; // variable name as displayed in admin , WITHOUT "default_"
char * default_value; // default value
+ bool is_global_variable; // is it a global variable?
} mysql_variable_st;
#endif
@@ -350,12 +352,14 @@ enum MYSQL_COM_QUERY_command {
MYSQL_COM_QUERY_OPTIMIZE,
MYSQL_COM_QUERY_PREPARE,
MYSQL_COM_QUERY_PURGE,
+ MYSQL_COM_QUERY_RELEASE_SAVEPOINT,
MYSQL_COM_QUERY_RENAME_TABLE,
MYSQL_COM_QUERY_RESET_MASTER,
MYSQL_COM_QUERY_RESET_SLAVE,
MYSQL_COM_QUERY_REPLACE,
MYSQL_COM_QUERY_REVOKE,
MYSQL_COM_QUERY_ROLLBACK,
+ MYSQL_COM_QUERY_ROLLBACK_SAVEPOINT,
MYSQL_COM_QUERY_SAVEPOINT,
MYSQL_COM_QUERY_SELECT,
MYSQL_COM_QUERY_SELECT_FOR_UPDATE,
@@ -988,28 +992,30 @@ typedef struct {
char * set_variable_name; // what variable name (or string) will be used when setting it to backend
char * internal_variable_name; // variable name as displayed in admin , WITHOUT "default_"
char * default_value; // default value
+ bool is_global_variable; // is it a global variable?
} mysql_variable_st;
*/
mysql_variable_st mysql_tracked_variables[] {
- { SQL_CHARACTER_SET, SETTING_CHARSET, false, true, false, false, false, (char *)"CHARSET", (char *)"CHARSET", (char *)"UTF8" } , // should be before SQL_CHARACTER_SET_RESULTS
- { SQL_CHARACTER_ACTION, NONE, false, false, false, false, false, (char *)"action", (char *)"action", (char *)"1" } ,
- { SQL_SET_NAMES, SETTING_SET_NAMES, false, false, false, false, false, (char *)"names", (char *)"names", (char *)"DEFAULT" } ,
- { SQL_SAFE_UPDATES, SETTING_VARIABLE, true, false, true, false, true, (char *)"sql_safe_updates", (char *)"sql_safe_updates", (char *)"OFF" } ,
- { SQL_SELECT_LIMIT, SETTING_VARIABLE, false, false, true, true, false, (char *)"sql_select_limit", (char *)"sql_select_limit", (char *)"DEFAULT" } ,
- { SQL_SQL_MODE, SETTING_VARIABLE, true, false, true, false, false, (char *)"sql_mode" , (char *)"sql_mode" , (char *)"" } ,
- { SQL_TIME_ZONE, SETTING_VARIABLE, true, false, true, false, false, (char *)"time_zone", (char *)"time_zone", (char *)"SYSTEM" } ,
- { SQL_CHARACTER_SET_RESULTS, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_results", (char *)"character_set_results", (char *)"UTF8" } ,
- { SQL_CHARACTER_SET_CONNECTION, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_connection", (char *)"character_set_connection", (char *)"UTF8" } ,
- { SQL_CHARACTER_SET_CLIENT, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_client", (char *)"character_set_client", (char *)"UTF8" } ,
- { SQL_CHARACTER_SET_DATABASE, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_database", (char *)"character_set_database", (char *)"UTF8" } ,
- { SQL_ISOLATION_LEVEL, SETTING_ISOLATION_LEVEL, false, true, true, false, false, (char *)"SESSION TRANSACTION ISOLATION LEVEL", (char *)"isolation_level", (char *)"READ COMMITTED" } ,
- { SQL_TRANSACTION_READ, SETTING_TRANSACTION_READ, false, true, true, false, false, (char *)"SESSION TRANSACTION READ", (char *)"transaction_read", (char *)"WRITE" } ,
- { SQL_SQL_AUTO_IS_NULL, SETTING_VARIABLE, true, false, true, false, true, (char *)"sql_auto_is_null", (char *)"sql_auto_is_null", (char *)"OFF" } ,
- { SQL_COLLATION_CONNECTION, SETTING_VARIABLE, true, false, true, false, false, (char *)"collation_connection", (char *)"collation_connection", (char *)"utf8_general_ci" } ,
- { SQL_NET_WRITE_TIMEOUT, SETTING_VARIABLE, false, false, true, true, false, (char *)"net_write_timeout", (char *)"net_write_timeout", (char *)"60" } ,
- { SQL_MAX_JOIN_SIZE, SETTING_VARIABLE, false, false, true, true, false, (char *)"max_join_size", (char *)"max_join_size", (char *)"18446744073709551615" } ,
- { SQL_LOG_BIN, SETTING_VARIABLE, false, false, true, false, false, (char *)"sql_log_bin", (char *)"sql_log_bin", (char *)"1" } ,
- { SQL_WSREP_SYNC_WAIT, SETTING_VARIABLE, false, false, true, true, false, (char *)"wsrep_sync_wait", (char *)"wsrep_sync_wait", (char *)"0" } ,
+ { SQL_CHARACTER_SET, SETTING_CHARSET, false, true, false, false, false, (char *)"charset", (char *)"charset", (char *)"utf8" , true} , // should be before SQL_CHARACTER_SET_RESULTS
+ { SQL_CHARACTER_ACTION, NONE, false, false, false, false, false, (char *)"action", (char *)"action", (char *)"1" , false} ,
+ { SQL_SET_NAMES, SETTING_SET_NAMES, false, false, false, false, false, (char *)"names", (char *)"names", (char *)"DEFAULT" , false} ,
+ { SQL_SAFE_UPDATES, SETTING_VARIABLE, true, false, true, false, true, (char *)"sql_safe_updates", (char *)"sql_safe_updates", (char *)"OFF" , false} ,
+ { SQL_SELECT_LIMIT, SETTING_VARIABLE, false, false, true, true, false, (char *)"sql_select_limit", (char *)"sql_select_limit", (char *)"DEFAULT" , false} ,
+ { SQL_SQL_MODE, SETTING_VARIABLE, true, false, true, false, false, (char *)"sql_mode" , (char *)"sql_mode" , (char *)"" , false} ,
+ { SQL_TIME_ZONE, SETTING_VARIABLE, true, false, true, false, false, (char *)"time_zone", (char *)"time_zone", (char *)"SYSTEM" , false} ,
+ { SQL_CHARACTER_SET_RESULTS, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_results", (char *)"character_set_results", (char *)"utf8" , false} ,
+ { SQL_CHARACTER_SET_CONNECTION, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_connection", (char *)"character_set_connection", (char *)"utf8", false } ,
+ { SQL_CHARACTER_SET_CLIENT, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_client", (char *)"character_set_client", (char *)"utf8" , false} ,
+ { SQL_CHARACTER_SET_DATABASE, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_database", (char *)"character_set_database", (char *)"utf8" , false} ,
+ { SQL_ISOLATION_LEVEL, SETTING_ISOLATION_LEVEL, false, true, true, false, false, (char *)"SESSION TRANSACTION ISOLATION LEVEL", (char *)"isolation_level", (char *)"READ COMMITTED" , false} ,
+ { SQL_TRANSACTION_READ, SETTING_TRANSACTION_READ, false, true, true, false, false, (char *)"SESSION TRANSACTION READ", (char *)"transaction_read", (char *)"WRITE" , false} ,
+ { SQL_SQL_AUTO_IS_NULL, SETTING_VARIABLE, true, false, true, false, true, (char *)"sql_auto_is_null", (char *)"sql_auto_is_null", (char *)"OFF" , false} ,
+ { SQL_COLLATION_CONNECTION, SETTING_VARIABLE, true, false, true, false, false, (char *)"collation_connection", (char *)"collation_connection", (char *)"utf8_general_ci" , true} ,
+ { SQL_NET_WRITE_TIMEOUT, SETTING_VARIABLE, false, false, true, true, false, (char *)"net_write_timeout", (char *)"net_write_timeout", (char *)"60" , false} ,
+ { SQL_MAX_JOIN_SIZE, SETTING_VARIABLE, false, false, true, true, false, (char *)"max_join_size", (char *)"max_join_size", (char *)"18446744073709551615" , false} ,
+ { SQL_LOG_BIN, SETTING_VARIABLE, false, false, true, false, false, (char *)"sql_log_bin", (char *)"sql_log_bin", (char *)"1" , false} ,
+ { SQL_WSREP_SYNC_WAIT, SETTING_VARIABLE, false, false, true, true, false, (char *)"wsrep_sync_wait", (char *)"wsrep_sync_wait", (char *)"0" , false} ,
+ { SQL_GROUP_CONCAT_MAX_LEN, SETTING_VARIABLE, false, false, true, true, false, (char *)"group_concat_max_len", (char *)"group_concat_max_len", (char *)"1024" , false} ,
};
#else
extern mysql_variable_st mysql_tracked_variables[];
diff --git a/lib/Makefile b/lib/Makefile
index ba33b8359a..db3b10d85c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,6 +1,9 @@
-
-
+ifndef GIT_VERSION
GIT_VERSION := $(shell git describe --long)
+ifndef GIT_VERSION
+$(error GIT_VERSION is not set)
+endif
+endif
DEPS_PATH=../deps
diff --git a/lib/MySQL_HostGroups_Manager.cpp b/lib/MySQL_HostGroups_Manager.cpp
index cce7f218e2..a2f79f3823 100644
--- a/lib/MySQL_HostGroups_Manager.cpp
+++ b/lib/MySQL_HostGroups_Manager.cpp
@@ -15,12 +15,10 @@
#include
-#define USE_MYSRVC_ARRAY
-
-#ifdef USE_MYSRVC_ARRAY
+#ifdef TEST_AURORA
static unsigned long long array_mysrvc_total = 0;
static unsigned long long array_mysrvc_cands = 0;
-#endif // USE_MYSRVC_ARRAY
+#endif // TEST_AURORA
#define SAFE_SQLITE3_STEP(_stmt) do {\
do {\
@@ -172,6 +170,7 @@ static void gtid_async_cb(struct ev_loop *loop, struct ev_async *watcher, int re
}
static void gtid_timer_cb (struct ev_loop *loop, struct ev_timer *timer, int revents) {
+ if (GloMTH == nullptr) { return; }
ev_timer_stop(loop, timer);
ev_timer_set(timer, __sync_add_and_fetch(&GloMTH->variables.binlog_reader_connect_retry_msec,0)/1000, 0);
if (glovars.shutdown) {
@@ -1713,7 +1712,7 @@ void MySQL_HostGroups_Manager::generate_mysql_gtid_executed_tables() {
it = gtid_map.begin();
while(it != gtid_map.end()) {
GTID_Server_Data * gtid_si = it->second;
- if (gtid_si->active == false) {
+ if (gtid_si && gtid_si->active == false) {
to_remove.push_back(it->first);
}
it++;
@@ -2280,7 +2279,6 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
unsigned int sum=0;
unsigned int TotalUsedConn=0;
unsigned int l=mysrvs->cnt();
-#ifdef USE_MYSRVC_ARRAY
#ifdef TEST_AURORA
unsigned long long a1 = array_mysrvc_total/10000;
array_mysrvc_total += l;
@@ -2295,7 +2293,6 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
if (l>32) {
mysrvcCandidates = (MySrvC **)malloc(sizeof(MySrvC *)*l);
}
-#endif // USE_MYSRVC_ARRAY
if (l) {
//int j=0;
for (j=0; jgtid_exists(mysrvc, gtid_uuid, gtid_trxid)) {
sum+=mysrvc->weight;
TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
mysrvcCandidates[num_candidates]=mysrvc;
num_candidates++;
-#endif // USE_MYSRVC_ARRAY
}
} else {
if (max_lag_ms >= 0) {
if (max_lag_ms >= mysrvc->aws_aurora_current_lag_us/1000) {
sum+=mysrvc->weight;
TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
mysrvcCandidates[num_candidates]=mysrvc;
num_candidates++;
-#endif // USE_MYSRVC_ARRAY
} else {
sess->thread->status_variables.aws_aurora_replicas_skipped_during_query++;
}
} else {
sum+=mysrvc->weight;
TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
mysrvcCandidates[num_candidates]=mysrvc;
num_candidates++;
-#endif // USE_MYSRVC_ARRAY
}
}
}
@@ -2367,28 +2358,22 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
if (MyHGM->gtid_exists(mysrvc, gtid_uuid, gtid_trxid)) {
sum+=mysrvc->weight;
TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
mysrvcCandidates[num_candidates]=mysrvc;
num_candidates++;
-#endif // USE_MYSRVC_ARRAY
}
} else {
if (max_lag_ms >= 0) {
if (max_lag_ms >= mysrvc->aws_aurora_current_lag_us/1000) {
sum+=mysrvc->weight;
TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
mysrvcCandidates[num_candidates]=mysrvc;
num_candidates++;
-#endif // USE_MYSRVC_ARRAY
}
} else {
sum+=mysrvc->weight;
TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
mysrvcCandidates[num_candidates]=mysrvc;
num_candidates++;
-#endif // USE_MYSRVC_ARRAY
}
}
}
@@ -2398,7 +2383,6 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
}
}
}
-#ifdef USE_MYSRVC_ARRAY
if (max_lag_ms) { // we are using AWS Aurora, as this logic is implemented only here
unsigned int min_num_replicas = sess->thread->variables.aurora_max_lag_ms_only_read_from_replicas;
if (min_num_replicas) {
@@ -2425,7 +2409,6 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
}
}
}
-#endif // USE_MYSRVC_ARRAY
if (sum==0) {
// per issue #531 , we try a desperate attempt to bring back online any shunned server
// we do this lowering the maximum wait time to 10%
@@ -2450,28 +2433,22 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
if (MyHGM->gtid_exists(mysrvc, gtid_uuid, gtid_trxid)) {
sum+=mysrvc->weight;
TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
mysrvcCandidates[num_candidates]=mysrvc;
num_candidates++;
-#endif // USE_MYSRVC_ARRAY
}
} else {
if (max_lag_ms >= 0) {
if (max_lag_ms >= mysrvc->aws_aurora_current_lag_us/1000) {
sum+=mysrvc->weight;
TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
mysrvcCandidates[num_candidates]=mysrvc;
num_candidates++;
-#endif // USE_MYSRVC_ARRAY
}
} else {
sum+=mysrvc->weight;
TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
mysrvcCandidates[num_candidates]=mysrvc;
num_candidates++;
-#endif // USE_MYSRVC_ARRAY
}
}
}
@@ -2481,12 +2458,12 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
}
if (sum==0) {
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySrvC NULL because no backend ONLINE or with weight\n");
-#ifdef USE_MYSRVC_ARRAY
if (l>32) {
free(mysrvcCandidates);
}
+#ifdef TEST_AURORA
array_mysrvc_cands += num_candidates;
-#endif // USE_MYSRVC_ARRAY
+#endif // TEST_AURORA
return NULL; // if we reach here, we couldn't find any target
}
@@ -2494,75 +2471,35 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
unsigned int New_TotalUsedConn=0;
// we will now scan again to ignore overloaded servers
-#ifdef USE_MYSRVC_ARRAY
for (j=0; jidx(j);
- if (mysrvc->status==MYSQL_SERVER_STATUS_ONLINE) { // consider this server only if ONLINE
-#endif // USE_MYSRVC_ARRAY
- unsigned int len=mysrvc->ConnectionsUsed->conns_length();
-#ifdef USE_MYSRVC_ARRAY
-#else
-
- if (len < mysrvc->max_connections) { // consider this server only if didn't reach max_connections
- if ( mysrvc->current_latency_us < ( mysrvc->max_latency_us ? mysrvc->max_latency_us : mysql_thread___default_max_latency_ms*1000 ) ) { // consider the host only if not too far
-#endif // USE_MYSRVC_ARRAY
- if ((len * sum) <= (TotalUsedConn * mysrvc->weight * 1.5 + 1)) {
+ unsigned int len=mysrvc->ConnectionsUsed->conns_length();
+ if ((len * sum) <= (TotalUsedConn * mysrvc->weight * 1.5 + 1)) {
-#ifdef USE_MYSRVC_ARRAY
- New_sum+=mysrvc->weight;
- New_TotalUsedConn+=len;
-#else
- if (gtid_trxid) {
- if (MyHGM->gtid_exists(mysrvc, gtid_uuid, gtid_trxid)) {
- New_sum+=mysrvc->weight;
- New_TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length();
- }
- } else {
- if (max_lag_ms >= 0) {
- if (max_lag_ms >= mysrvc->aws_aurora_current_lag_us/1000) {
- New_sum+=mysrvc->weight;
- New_TotalUsedConn+=len;
- }
- } else {
- New_sum+=mysrvc->weight;
- New_TotalUsedConn+=len;
- }
- }
-#endif // USE_MYSRVC_ARRAY
-#ifdef USE_MYSRVC_ARRAY
- } else {
- // remove the candidate
- if (j+1 < num_candidates) {
- mysrvcCandidates[j] = mysrvcCandidates[num_candidates-1];
- }
- j--;
- num_candidates--;
-#endif // USE_MYSRVC_ARRAY
- }
-#ifdef USE_MYSRVC_ARRAY
-#else
- }
+ New_sum+=mysrvc->weight;
+ New_TotalUsedConn+=len;
+ } else {
+ // remove the candidate
+ if (j+1 < num_candidates) {
+ mysrvcCandidates[j] = mysrvcCandidates[num_candidates-1];
}
+ j--;
+ num_candidates--;
}
-#endif // USE_MYSRVC_ARRAY
}
if (New_sum==0) {
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySrvC NULL because no backend ONLINE or with weight\n");
-#ifdef USE_MYSRVC_ARRAY
if (l>32) {
free(mysrvcCandidates);
}
+#ifdef TEST_AURORA
array_mysrvc_cands += num_candidates;
-#endif // USE_MYSRVC_ARRAY
+#endif // TEST_AURORA
return NULL; // if we reach here, we couldn't find any target
}
-#ifdef USE_MYSRVC_ARRAY
// latency awareness algorithm is enabled only when compiled with USE_MYSRVC_ARRAY
if (sess->thread->variables.min_num_servers_lantency_awareness) {
if (num_candidates >= sess->thread->variables.min_num_servers_lantency_awareness) {
@@ -2603,7 +2540,6 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
}
}
}
-#endif // USE_MYSRVC_ARRAY
unsigned int k;
@@ -2615,62 +2551,28 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
k++;
New_sum=0;
-#ifdef USE_MYSRVC_ARRAY
for (j=0; jidx(j);
- if (mysrvc->status==MYSQL_SERVER_STATUS_ONLINE) { // consider this server only if ONLINE
- unsigned int len=mysrvc->ConnectionsUsed->conns_length();
- if (len < mysrvc->max_connections) { // consider this server only if didn't reach max_connections
- if ( mysrvc->current_latency_us < ( mysrvc->max_latency_us ? mysrvc->max_latency_us : mysql_thread___default_max_latency_ms*1000 ) ) { // consider the host only if not too far
- if ((len * sum) <= (TotalUsedConn * mysrvc->weight * 1.5 + 1)) {
-#endif // USE_MYSRVC_ARRAY
-#ifdef USE_MYSRVC_ARRAY
- New_sum+=mysrvc->weight;
-#else
- if (gtid_trxid) {
- if (MyHGM->gtid_exists(mysrvc, gtid_uuid, gtid_trxid)) {
- New_sum+=mysrvc->weight;
- //TotalUsedConn+=mysrvc->ConnectionsUsed->conns_length(); // this line is a bug
- }
- } else {
- if (max_lag_ms >= 0) {
- if (max_lag_ms >= mysrvc->aws_aurora_current_lag_us/1000) {
- New_sum+=mysrvc->weight;
- }
- } else {
- New_sum+=mysrvc->weight;
- }
- }
-#endif // USE_MYSRVC_ARRAY
- if (k<=New_sum) {
- proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySrvC %p, server %s:%d\n", mysrvc, mysrvc->address, mysrvc->port);
-#ifdef USE_MYSRVC_ARRAY
- if (l>32) {
- free(mysrvcCandidates);
- }
- array_mysrvc_cands += num_candidates;
-#endif // USE_MYSRVC_ARRAY
- return mysrvc;
- }
-#ifdef USE_MYSRVC_ARRAY
-#else
- }
- }
+ New_sum+=mysrvc->weight;
+ if (k<=New_sum) {
+ proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySrvC %p, server %s:%d\n", mysrvc, mysrvc->address, mysrvc->port);
+ if (l>32) {
+ free(mysrvcCandidates);
}
+#ifdef TEST_AURORA
+ array_mysrvc_cands += num_candidates;
+#endif // TEST_AURORA
+ return mysrvc;
}
-#endif // USE_MYSRVC_ARRAY
}
}
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySrvC NULL\n");
-#ifdef USE_MYSRVC_ARRAY
if (l>32) {
free(mysrvcCandidates);
}
+#ifdef TEST_AURORA
array_mysrvc_cands += num_candidates;
-#endif // USE_MYSRVC_ARRAY
+#endif // TEST_AURORA
return NULL; // if we reach here, we couldn't find any target
}
@@ -4379,7 +4281,7 @@ void MySQL_HostGroups_Manager::update_galera_set_offline(char *_hostname, int _p
mydb->execute(query);
//free(query);
} else {
- q=(char *)"UPDATE mysql_servers_incoming SET status=1 WHERE hostname='%s' AND port=%d AND hostgroup_id = %d";
+ q=(char *)"UPDATE mysql_servers_incoming SET status=1 WHERE hostname='%s' AND port=%d";
sprintf(query,q,_hostname,_port,_writer_hostgroup);
mydb->execute(query);
}
@@ -4493,7 +4395,7 @@ void MySQL_HostGroups_Manager::update_galera_set_read_only(char *_hostname, int
sprintf(query, q, info->reader_hostgroup, _hostname, _port, info->writer_hostgroup, info->backup_writer_hostgroup, info->offline_hostgroup);
mydb->execute(query);
//free(query);
- q=(char *)"DELETE FROM mysql_servers_incoming WHERE hostname='%s' AND port=%d AND hostgroup_id in (%d, %d, %d) FROM mysql_galera_hostgroups WHERE writer_hostgroup=%d)";
+ q=(char *)"DELETE FROM mysql_servers_incoming WHERE hostname='%s' AND port=%d AND hostgroup_id in (%d, %d, %d)";
//query=(char *)malloc(strlen(q)+strlen(_hostname)+64);
sprintf(query,q,_hostname,_port, info->offline_hostgroup, info->backup_writer_hostgroup, info->writer_hostgroup, info->writer_hostgroup);
mydb->execute(query);
@@ -4555,8 +4457,7 @@ Galera_Info *MySQL_HostGroups_Manager::get_galera_node_info(int hostgroup) {
}
void MySQL_HostGroups_Manager::update_galera_set_writer(char *_hostname, int _port, int _writer_hostgroup) {
- std::mutex local_mutex;
- std::lock_guard lock(local_mutex);
+ std::lock_guard lock(galera_set_writer_mutex);
int cols=0;
int affected_rows=0;
SQLite3_result *resultset=NULL;
@@ -4566,7 +4467,7 @@ void MySQL_HostGroups_Manager::update_galera_set_writer(char *_hostname, int _po
q=(char *)"SELECT hostgroup_id FROM mysql_servers JOIN mysql_galera_hostgroups ON hostgroup_id=writer_hostgroup OR hostgroup_id=reader_hostgroup OR hostgroup_id=backup_writer_hostgroup OR hostgroup_id=offline_hostgroup WHERE hostname='%s' AND port=%d";
query=(char *)malloc(strlen(q)+strlen(_hostname)+32);
sprintf(query,q,_hostname,_port);
- mydb->execute_statement(query, &error, &cols , &affected_rows , &resultset);
+ mydb->execute_statement(query, &error, &cols , &affected_rows , &resultset);
if (error) {
free(error);
error=NULL;
@@ -4639,7 +4540,9 @@ void MySQL_HostGroups_Manager::update_galera_set_writer(char *_hostname, int _po
if (
(writer_is_also_reader==0 && found_reader==false)
||
- (writer_is_also_reader > 0 && found_reader==true)
+ (writer_is_also_reader == 1 && found_reader==true)
+ ||
+ (writer_is_also_reader == 2)
) { // either both true or both false
delete resultset;
resultset=NULL;
diff --git a/lib/MySQL_Protocol.cpp b/lib/MySQL_Protocol.cpp
index b66d602cb2..58ccb51b02 100644
--- a/lib/MySQL_Protocol.cpp
+++ b/lib/MySQL_Protocol.cpp
@@ -1549,6 +1549,7 @@ bool MySQL_Protocol::process_pkt_handshake_response(unsigned char *pkt, unsigned
//(*myds)->switching_auth_stage=2;
charset=(*myds)->tmp_charset;
proxy_debug(PROXY_DEBUG_MYSQL_PROTOCOL,2,"Session=%p , DS=%p . Encrypted: %d , switching_auth: %d, auth_plugin_id: %d\n", (*myds)->sess, (*myds), (*myds)->encrypted, (*myds)->switching_auth_stage, auth_plugin_id);
+ capabilities = (*myds)->myconn->options.client_flag;
goto __do_auth;
}
@@ -1556,6 +1557,7 @@ bool MySQL_Protocol::process_pkt_handshake_response(unsigned char *pkt, unsigned
(*myds)->myconn->options.client_flag = capabilities;
pkt += sizeof(uint32_t);
max_pkt = CPY4(pkt);
+ (*myds)->myconn->options.max_allowed_pkt = max_pkt;
pkt += sizeof(uint32_t);
charset = *(uint8_t *)pkt;
if ( (*myds)->encrypted == false ) { // client wants to use SSL
@@ -2000,7 +2002,6 @@ bool MySQL_Protocol::process_pkt_handshake_response(unsigned char *pkt, unsigned
if (ret==true) {
- (*myds)->myconn->options.max_allowed_pkt=max_pkt;
(*myds)->DSS=STATE_CLIENT_HANDSHAKE;
if (!userinfo->username) // if set already, ignore
@@ -2311,7 +2312,7 @@ bool MySQL_Protocol::generate_COM_QUERY_from_COM_FIELD_LIST(PtrSize_t *pkt) {
(*myds)->com_field_wild=strdup(wild);
}
- char *qt = (char *)"SELECT * FROM %s WHERE 1=0";
+ char *qt = (char *)"SELECT * FROM `%s` WHERE 1=0";
q = (char *)malloc(strlen(qt)+strlen(tablename));
sprintf(q,qt,tablename);
l_free(pkt->size, pkt->ptr);
diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp
index a6a78793c0..e447a3ebfd 100644
--- a/lib/MySQL_Session.cpp
+++ b/lib/MySQL_Session.cpp
@@ -1013,6 +1013,7 @@ void MySQL_Session::generate_proxysql_internal_session_json(json &j) {
j["backends"][i]["conn"]["no_backslash_escapes"] = _myconn->options.no_backslash_escapes;
j["backends"][i]["conn"]["status"]["get_lock"] = _myconn->get_status_get_lock();
j["backends"][i]["conn"]["status"]["lock_tables"] = _myconn->get_status_lock_tables();
+ j["backends"][i]["conn"]["status"]["has_savepoint"] = _myconn->get_status_has_savepoint();
j["backends"][i]["conn"]["status"]["temporary_table"] = _myconn->get_status_temporary_table();
j["backends"][i]["conn"]["status"]["user_variable"] = _myconn->get_status_user_variable();
j["backends"][i]["conn"]["status"]["found_rows"] = _myconn->get_status_found_rows();
@@ -1574,7 +1575,24 @@ bool MySQL_Session::handler_again___verify_backend__generic_variable(uint32_t *b
*be_var = strdup(def);
uint32_t tmp_int = SpookyHash::Hash32(*be_var, strlen(*be_var), 10);
*be_int = tmp_int;
+
+ switch(status) { // this switch can be replaced with a simple previous_status.push(status), but it is here for readibility
+ case PROCESSING_QUERY:
+ previous_status.push(PROCESSING_QUERY);
+ break;
+ case PROCESSING_STMT_PREPARE:
+ previous_status.push(PROCESSING_STMT_PREPARE);
+ break;
+ case PROCESSING_STMT_EXECUTE:
+ previous_status.push(PROCESSING_STMT_EXECUTE);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ NEXT_IMMEDIATE_NEW(next_sess_status);
}
+
if (*fe_int) {
if (*fe_int != *be_int) {
{
@@ -2308,7 +2326,36 @@ bool MySQL_Session::handler_again___status_SETTING_MULTI_STMT(int *_rc) {
NEXT_IMMEDIATE_NEW(st);
} else {
if (rc==-1) {
- proxy_error("Error setting multistatement on server %s , %d : %d, %s\n", myconn->parent->address, myconn->parent->port, mysql_errno(myconn->mysql), mysql_error(myconn->mysql));
+ // the command failed
+ int myerr=mysql_errno(myconn->mysql);
+ if (myerr >= 2000) {
+ bool retry_conn=false;
+ // client error, serious
+ proxy_error("Detected a broken connection during setting MYSQL_OPTION_MULTI_STATEMENTS on %s , %d : %d, %s\n", myconn->parent->address, myconn->parent->port, myerr, mysql_error(myconn->mysql));
+ //if ((myds->myconn->reusable==true) && ((myds->myprot.prot_status & SERVER_STATUS_IN_TRANS)==0)) {
+ if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) {
+ retry_conn=true;
+ }
+ myds->destroy_MySQL_Connection_From_Pool(false);
+ myds->fd=0;
+ if (retry_conn) {
+ myds->DSS=STATE_NOT_INITIALIZED;
+ NEXT_IMMEDIATE_NEW(CONNECTING_SERVER);
+ }
+ *_rc=-1; // an error happened, we should destroy the Session
+ return ret;
+ } else {
+ proxy_warning("Error during MYSQL_OPTION_MULTI_STATEMENTS : %d, %s\n", myerr, mysql_error(myconn->mysql));
+ // we won't go back to PROCESSING_QUERY
+ st=previous_status.top();
+ previous_status.pop();
+ char sqlstate[10];
+ sprintf(sqlstate,"%s",mysql_sqlstate(myconn->mysql));
+ client_myds->myprot.generate_pkt_ERR(true,NULL,NULL,1,mysql_errno(myconn->mysql),sqlstate,mysql_error(myconn->mysql));
+ myds->destroy_MySQL_Connection_From_Pool(true);
+ myds->fd=0;
+ RequestEnd(myds);
+ }
} else {
// rc==1 , nothing to do for now
}
@@ -2560,7 +2607,8 @@ bool MySQL_Session::handler_again___status_CHANGING_USER_SERVER(int *_rc) {
__sync_fetch_and_add(&MyHGM->status.backend_change_user, 1);
myds->myconn->userinfo->set(client_myds->myconn->userinfo);
myds->myconn->reset();
- st=previous_status.top();
+ myds->DSS = STATE_MARIADB_GENERIC;
+ st = previous_status.top();
previous_status.pop();
NEXT_IMMEDIATE_NEW(st);
} else {
@@ -3282,7 +3330,7 @@ int MySQL_Session::handler() {
// break;
case _MYSQL_COM_QUIT:
proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Got COM_QUIT packet\n");
- GloMyLogger->log_audit_entry(PROXYSQL_MYSQL_AUTH_QUIT, this, NULL);
+ if (GloMyLogger) { GloMyLogger->log_audit_entry(PROXYSQL_MYSQL_AUTH_QUIT, this, NULL); }
l_free(pkt.size,pkt.ptr);
handler_ret = -1;
return handler_ret;
@@ -3369,7 +3417,7 @@ int MySQL_Session::handler() {
c=*((unsigned char *)pkt.ptr+sizeof(mysql_hdr));
if (c==_MYSQL_COM_QUIT) {
proxy_error("Unexpected COM_QUIT from client %s . Session_status: %d , client_status: %d Disconnecting it\n", buf, status, client_myds->status);
- GloMyLogger->log_audit_entry(PROXYSQL_MYSQL_AUTH_QUIT, this, NULL);
+ if (GloMyLogger) { GloMyLogger->log_audit_entry(PROXYSQL_MYSQL_AUTH_QUIT, this, NULL); }
proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Got COM_QUIT packet\n");
l_free(pkt.size,pkt.ptr);
if (thread) {
@@ -3576,7 +3624,9 @@ int MySQL_Session::handler() {
mybe->server_myds->wait_until=0;
if (qpo) {
if (qpo->timeout > 0) {
- mybe->server_myds->wait_until=thread->curtime+qpo->timeout*1000;
+ unsigned long long qr_timeout=qpo->timeout;
+ mybe->server_myds->wait_until=thread->curtime;
+ mybe->server_myds->wait_until+=qr_timeout*1000;
}
}
if (mysql_thread___default_query_timeout) {
@@ -4859,7 +4909,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Parsing SET command = %s\n", nqn.c_str());
}
#endif
- if (index(dig,';')) {
+ if (index(dig,';') && (index(dig,';') != dig + strlen(dig)-1)) {
string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength);
proxy_warning("Unable to parse multi-statements command with SET statement: setting lock hostgroup . Command: %s\n", nqn.c_str());
*lock_hostgroup = true;
@@ -5023,7 +5073,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
return false;
}
}
- } else if ( (var == "sql_select_limit") || (var == "net_write_timeout") || (var == "max_join_size") || (var == "wsrep_sync_wait") ) {
+ } else if ( (var == "sql_select_limit") || (var == "net_write_timeout") || (var == "max_join_size") || (var == "wsrep_sync_wait") || (var == "group_concat_max_len") ) {
int idx = SQL_NAME_LAST;
for (int i = 0 ; i < SQL_NAME_LAST ; i++) {
if (mysql_tracked_variables[i].is_number) {
diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp
index 60b6a1fe8e..6f10569725 100644
--- a/lib/MySQL_Thread.cpp
+++ b/lib/MySQL_Thread.cpp
@@ -364,7 +364,7 @@ static char * mysql_thread_variables_names[]= {
(char *)"eventslog_format",
(char *)"auditlog_filename",
(char *)"auditlog_filesize",
- (char *)"default_charset",
+ //(char *)"default_charset", // removed in 2.0.13 . Obsoleted previously using MySQL_Variables instead
(char *)"handle_unknown_charset",
(char *)"free_connections_pct",
(char *)"connection_warming",
@@ -793,6 +793,8 @@ char * MySQL_Threads_Handler::get_variable_string(char *name) {
}
if (!strncmp(name,"default_",8)) {
for (int i=0; i 8) {
+ if (strncmp(name, "default_", 8) == 0) {
+ for (unsigned int i = 0; i < SQL_NAME_LAST ; i++) {
+ if (mysql_tracked_variables[i].is_global_variable) {
+ size_t var_len = strlen(mysql_tracked_variables[i].internal_variable_name);
+ if (strlen(name) == (var_len+8)) {
+ if (!strncmp(name+8, mysql_tracked_variables[i].internal_variable_name, var_len)) {
+ return strdup(variables.default_variables[i]);
+ }
+ }
+ }
+ }
}
}
if (!strcasecmp(name,"firewall_whitelist_errormsg")) return strdup(variables.firewall_whitelist_errormsg);
@@ -2446,9 +2457,11 @@ bool MySQL_Threads_Handler::set_variable(char *name, const char *value) { // thi
if (!strncmp(name,"default_",8)) {
for (int i=0; i 8) {
- if (strncmp(name, "default_", 8)) {
+ if (strncmp(name, "default_", 8) == 0) {
for (unsigned int i = 0; i < SQL_NAME_LAST ; i++) {
- size_t var_len = strlen(mysql_tracked_variables[i].internal_variable_name);
- if (strlen(name) == (var_len+8)) {
- if (!strncmp(name+8, (mysql_tracked_variables[i].internal_variable_name), var_len)) {
- return true;
+ if (mysql_tracked_variables[i].is_global_variable) {
+ size_t var_len = strlen(mysql_tracked_variables[i].internal_variable_name);
+ if (strlen(name) == (var_len+8)) {
+ if (!strncmp(name+8, mysql_tracked_variables[i].internal_variable_name, var_len)) {
+ return true;
+ }
}
}
}
@@ -3167,7 +3194,7 @@ MySQL_Thread::~MySQL_Thread() {
if (sess->session_type == PROXYSQL_SESSION_ADMIN || sess->session_type == PROXYSQL_SESSION_STATS) {
char _buf[1024];
sprintf(_buf,"%s:%d:%s()", __FILE__, __LINE__, __func__);
- GloMyLogger->log_audit_entry(PROXYSQL_MYSQL_AUTH_CLOSE, sess, NULL, _buf);
+ if (GloMyLogger) { GloMyLogger->log_audit_entry(PROXYSQL_MYSQL_AUTH_CLOSE, sess, NULL, _buf); }
}
delete sess;
}
@@ -3373,7 +3400,11 @@ bool MySQL_Thread::init() {
match_regexes=(Session_Regex **)malloc(sizeof(Session_Regex *)*4);
match_regexes[0]=new Session_Regex((char *)"^SET (|SESSION |@@|@@session.)SQL_LOG_BIN( *)(:|)=( *)");
- match_regexes[1]=new Session_Regex((char *)"^SET (|SESSION |@@|@@session.)(SQL_MODE|TIME_ZONE|CHARACTER_SET_RESULTS|CHARACTER_SET_CLIENT|CHARACTER_SET_DATABASE|SESSION_TRACK_GTIDS|SQL_AUTO_IS_NULL|SQL_SELECT_LIMIT|SQL_SAFE_UPDATES|COLLATION_CONNECTION|CHARACTER_SET_CONNECTION|NET_WRITE_TIMEOUT|WSREP_SYNC_WAIT|TX_ISOLATION|MAX_JOIN_SIZE( *)(:|)=( *))");
+
+ std::stringstream ss;
+ ss << "^SET (|SESSION |@@|@@session.)(" << mysql_variables.variables_regexp << "SESSION_TRACK_GTIDS|TX_ISOLATION( *)(:|)=( *))";
+ match_regexes[1]=new Session_Regex((char *)ss.str().c_str());
+
match_regexes[2]=new Session_Regex((char *)"^SET(?: +)(|SESSION +)TRANSACTION(?: +)(?:(?:(ISOLATION(?: +)LEVEL)(?: +)(REPEATABLE(?: +)READ|READ(?: +)COMMITTED|READ(?: +)UNCOMMITTED|SERIALIZABLE))|(?:(READ)(?: +)(WRITE|ONLY)))");
match_regexes[3]=new Session_Regex((char *)"^(set)(?: +)((charset)|(character +set))(?: )");
@@ -4434,10 +4465,13 @@ void MySQL_Thread::refresh_variables() {
for (int i=0; iget_variable_string(buf);
+ if (mysql_tracked_variables[i].is_global_variable) {
+ sprintf(buf,"default_%s",mysql_tracked_variables[i].internal_variable_name);
+ mysql_thread___default_variables[i] = GloMTH->get_variable_string(buf);
+ }
}
if (mysql_thread___server_version) free(mysql_thread___server_version);
@@ -4587,6 +4621,10 @@ MySQL_Thread::MySQL_Thread() {
variables.stats_time_backend_query=false;
variables.stats_time_query_processor=false;
variables.query_cache_stores_empty_result=true;
+
+ for (int i=0; ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;ishutdown_) return 0;
unsigned long long q=0;
unsigned int i;
for (i=0;iwrlock();
+ char * previous_default_charset = GloMTH->get_variable_string((char *)"default_charset");
+ char * previous_default_collation_connection = GloMTH->get_variable_string((char *)"default_collation_connection");
+ assert(previous_default_charset);
+ assert(previous_default_collation_connection);
for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) {
SQLite3_row *r=*it;
const char *value = r->fields[1];
+/*
+ // COMPLETELY DISABLING THIS because we disable must mysql-default_ variables
+ //
if (!strcasecmp(r->fields[0], "default_character_set_results") || !strcasecmp(r->fields[0], "default_character_set_client") ||
!strcasecmp(r->fields[0], "default_character_set_database") || !strcasecmp(r->fields[0], "default_character_set_connection") ||
!strcasecmp(r->fields[0], "default_charset")) {
@@ -5464,6 +5471,7 @@ void ProxySQL_Admin::flush_mysql_variables___database_to_runtime(SQLite3DB *db,
GloMTH->set_variable(r->fields[0],ci->csname);
}
} else {
+*/
bool rc=GloMTH->set_variable(r->fields[0],value);
if (rc==false) {
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Impossible to set variable %s with value \"%s\"\n", r->fields[0],value);
@@ -5494,32 +5502,80 @@ void ProxySQL_Admin::flush_mysql_variables___database_to_runtime(SQLite3DB *db,
variables.mysql_show_processlist_extended = atoi(value);
}
}
- }
+// }
}
- char* connection = GloMTH->get_variable_string((char *)"default_character_set_connection");
- char* collation= GloMTH->get_variable_string((char *)"default_collation_connection");
- const MARIADB_CHARSET_INFO *ci = NULL;
char q[1000];
- ci = proxysql_find_charset_name(connection);
- if (strcasecmp(ci->name, collation)) {
- proxy_warning("Changing default_collation_connection to %s\n", ci->name);
- bool rc=GloMTH->set_variable("default_collation_connection",ci->name);
- sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"mysql-%s\",\"%s\")","default_collation_connection",ci->name);
- GloMTH->set_variable("default_collation_connection",ci->name);
- if (ci->nr == 45) {
- rc=GloMTH->set_variable("default_collation_connection","utf8mb4_general_ci");
- db->execute("INSERT OR REPLACE INTO global_variables VALUES(\"mysql-default_collation_connection\",\"utf8mb4_general_ci\")");
- GloMTH->set_variable("default_collation_connection","utf8mb4_general_ci");
+ char * default_charset = GloMTH->get_variable_string((char *)"default_charset");
+ char * default_collation_connection = GloMTH->get_variable_string((char *)"default_collation_connection");
+ assert(default_charset);
+ assert(default_collation_connection);
+ MARIADB_CHARSET_INFO * ci = NULL;
+ ci = proxysql_find_charset_name(default_charset);
+ if (ci == NULL) {
+ // invalid charset
+ proxy_error("Found an incorrect value for mysql-default_charset: %s\n", default_charset);
+ // let's try to get a charset from collation connection
+ ci = proxysql_find_charset_collate(default_collation_connection);
+ if (ci == NULL) {
+ proxy_error("Found an incorrect value for mysql-default_collation_connection: %s\n", default_collation_connection);
+ const char *p = mysql_tracked_variables[SQL_CHARACTER_SET].default_value;
+ ci = proxysql_find_charset_name(p);
+ assert(ci);
+ proxy_info("Resetting mysql-default_charset to hardcoded default value: %s\n", ci->csname);
+ sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"mysql-default_charset\",\"%s\")", ci->csname);
+ db->execute(q);
+ GloMTH->set_variable((char *)"default_charset",ci->csname);
+ proxy_info("Resetting mysql-default_collation_connection to hardcoded default value: %s\n", ci->name);
+ sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"mysql-default_collation_connection\",\"%s\")", ci->name);
+ db->execute(q);
+ GloMTH->set_variable((char *)"default_collation_connection",ci->name);
+ } else {
+ proxy_info("Changing mysql-default_charset to %s using configured mysql-default_collation_connection %s\n", ci->csname, ci->name);
+ sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"mysql-default_charset\",\"%s\")", ci->csname);
+ db->execute(q);
+ GloMTH->set_variable((char *)"default_charset",ci->csname);
}
} else {
- GloMTH->set_variable("default_collation_connection",ci->name);
- sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"mysql-%s\",\"%s\")","default_collation_connection",ci->name);
- db->execute(q);
+ MARIADB_CHARSET_INFO * cic = NULL;
+ cic = proxysql_find_charset_collate(default_collation_connection);
+ if (cic == NULL) {
+ proxy_error("Found an incorrect value for mysql-default_collation_connection: %s\n", default_collation_connection);
+ proxy_info("Changing mysql-default_collation_connection to %s using configured mysql-default_charset: %s\n", ci->name, ci->csname);
+ sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"mysql-default_collation_connection\",\"%s\")", ci->name);
+ db->execute(q);
+ GloMTH->set_variable((char *)"default_collation_connection",ci->name);
+ } else {
+ if (strcmp(cic->csname,ci->csname)==0) {
+ // mysql-default_collation_connection and mysql-default_charset are compatible
+ } else {
+ proxy_error("Found incompatible values for mysql-default_charset (%s) and mysql-default_collation_connection (%s)\n", default_charset, default_collation_connection);
+ bool use_collation = true;
+ if (strcmp(default_charset, previous_default_charset)) { // charset changed
+ if (strcmp(default_collation_connection, previous_default_collation_connection)==0) { // collation didn't change
+ // the user has changed the charset but not the collation
+ // we use charset as source of truth
+ use_collation = false;
+ }
+ }
+ if (use_collation) {
+ proxy_info("Changing mysql-default_charset to %s using configured mysql-default_collation_connection %s\n", cic->csname, cic->name);
+ sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"mysql-default_charset\",\"%s\")", cic->csname);
+ db->execute(q);
+ GloMTH->set_variable("default_charset",cic->csname);
+ } else {
+ proxy_info("Changing mysql-default_collation_connection to %s using configured mysql-default_charset: %s\n", ci->name, ci->csname);
+ sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"mysql-default_collation_connection\",\"%s\")", ci->name);
+ db->execute(q);
+ GloMTH->set_variable((char *)"default_collation_connection",ci->name);
+ }
+ }
+ }
}
- free(connection);
- free(collation);
-
+ free(default_charset);
+ free(default_collation_connection);
+ free(previous_default_charset);
+ free(previous_default_collation_connection);
GloMTH->commit();
GloMTH->wrunlock();
}
@@ -9955,6 +10011,7 @@ void ProxySQL_Admin::load_mysql_servers_to_runtime() {
}
// commit all the changes
MyHGM->commit();
+ GloAdmin->save_mysql_servers_runtime_to_database(true);
// clean up
if (resultset) delete resultset;
diff --git a/lib/Query_Cache.cpp b/lib/Query_Cache.cpp
index a4f7d8a892..b807ca8a23 100644
--- a/lib/Query_Cache.cpp
+++ b/lib/Query_Cache.cpp
@@ -294,7 +294,7 @@ void KV_BtreeArray::empty() {
};
uint64_t Query_Cache::get_data_size_total() {
- int r=0;
+ uint64_t r=0;
int i;
for (i=0; iget_data_size();
diff --git a/lib/Query_Processor.cpp b/lib/Query_Processor.cpp
index 4d8eee4662..f47d9e4e8d 100644
--- a/lib/Query_Processor.cpp
+++ b/lib/Query_Processor.cpp
@@ -480,12 +480,14 @@ Query_Processor::Query_Processor() {
commands_counters_desc[MYSQL_COM_QUERY_OPTIMIZE]=(char *)"OPTIMIZE";
commands_counters_desc[MYSQL_COM_QUERY_PREPARE]=(char *)"PREPARE";
commands_counters_desc[MYSQL_COM_QUERY_PURGE]=(char *)"PURGE";
+ commands_counters_desc[MYSQL_COM_QUERY_RELEASE_SAVEPOINT]=(char *)"RELEASE_SAVEPOINT";
commands_counters_desc[MYSQL_COM_QUERY_RENAME_TABLE]=(char *)"RENAME_TABLE";
commands_counters_desc[MYSQL_COM_QUERY_RESET_MASTER]=(char *)"RESET_MASTER";
commands_counters_desc[MYSQL_COM_QUERY_RESET_SLAVE]=(char *)"RESET_SLAVE";
commands_counters_desc[MYSQL_COM_QUERY_REPLACE]=(char *)"REPLACE";
commands_counters_desc[MYSQL_COM_QUERY_REVOKE]=(char *)"REVOKE";
commands_counters_desc[MYSQL_COM_QUERY_ROLLBACK]=(char *)"ROLLBACK";
+ commands_counters_desc[MYSQL_COM_QUERY_ROLLBACK_SAVEPOINT]=(char *)"ROLLBACK_SAVEPOINT";
commands_counters_desc[MYSQL_COM_QUERY_SAVEPOINT]=(char *)"SAVEPOINT";
commands_counters_desc[MYSQL_COM_QUERY_SELECT]=(char *)"SELECT";
commands_counters_desc[MYSQL_COM_QUERY_SELECT_FOR_UPDATE]=(char *)"SELECT_FOR_UPDATE";
@@ -2262,6 +2264,14 @@ enum MYSQL_COM_QUERY_command Query_Processor::__query_parser_command_type(SQP_pa
break;
case 'r':
case 'R':
+ if (!strcasecmp("RELEASE",token)) { // RELEASE
+ token=(char *)tokenize(&tok);
+ if (token==NULL) break;
+ if (!strcasecmp("SAVEPOINT",token)) {
+ ret=MYSQL_COM_QUERY_RELEASE_SAVEPOINT;
+ break;
+ }
+ }
if (!strcasecmp("RENAME",token)) { // RENAME
token=(char *)tokenize(&tok);
if (token==NULL) break;
@@ -2292,7 +2302,20 @@ enum MYSQL_COM_QUERY_command Query_Processor::__query_parser_command_type(SQP_pa
break;
}
if (!strcasecmp("ROLLBACK",token)) { // ROLLBACK
- ret=MYSQL_COM_QUERY_ROLLBACK;
+ token=(char *)tokenize(&tok);
+ if (token==NULL) {
+ ret=MYSQL_COM_QUERY_ROLLBACK;
+ break;
+ } else {
+ if (!strcasecmp("TO",token)) {
+ token=(char *)tokenize(&tok);
+ if (token==NULL) break;
+ if (!strcasecmp("SAVEPOINT",token)) {
+ ret=MYSQL_COM_QUERY_ROLLBACK_SAVEPOINT;
+ break;
+ }
+ }
+ }
break;
}
break;
diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp
index bdb917dd67..7caa5fe823 100644
--- a/lib/mysql_connection.cpp
+++ b/lib/mysql_connection.cpp
@@ -9,6 +9,8 @@
#include "query_processor.h"
#include "MySQL_Variables.h"
+#include
+
extern const MARIADB_CHARSET_INFO * proxysql_find_charset_nr(unsigned int nr);
MARIADB_CHARSET_INFO * proxysql_find_charset_name(const char *name);
@@ -77,7 +79,10 @@ void Variable::fill_client_internal_session(json &j, int idx) {
} else if (idx == SQL_CHARACTER_SET_CONNECTION) {
const MARIADB_CHARSET_INFO *ci = NULL;
- ci = proxysql_find_charset_nr(atoi(value));
+ if (!value)
+ ci = proxysql_find_charset_collate(mysql_tracked_variables[idx].default_value);
+ else
+ ci = proxysql_find_charset_nr(atoi(value));
j["conn"][mysql_tracked_variables[idx].internal_variable_name] = (ci && ci->csname)?ci->csname:"";
} else if (idx == SQL_COLLATION_CONNECTION) {
const MARIADB_CHARSET_INFO *ci = NULL;
@@ -387,6 +392,7 @@ MySQL_Connection::~MySQL_Connection() {
if (variables[i].value) {
free(variables[i].value);
variables[i].value = NULL;
+ var_hash[i] = 0;
}
}
@@ -508,6 +514,14 @@ void MySQL_Connection::set_status_user_variable(bool v) {
}
}
+void MySQL_Connection::set_status_has_savepoint(bool v) {
+ if (v) {
+ status_flags |= STATUS_MYSQL_CONNECTION_HAS_SAVEPOINT;
+ } else {
+ status_flags &= ~STATUS_MYSQL_CONNECTION_HAS_SAVEPOINT;
+ }
+}
+
void MySQL_Connection::set_status_prepared_statement(bool v) {
if (v) {
status_flags |= STATUS_MYSQL_CONNECTION_PREPARED_STATEMENT;
@@ -547,6 +561,10 @@ bool MySQL_Connection::get_status_user_variable() {
return status_flags & STATUS_MYSQL_CONNECTION_USER_VARIABLE;
}
+bool MySQL_Connection::get_status_has_savepoint() {
+ return status_flags & STATUS_MYSQL_CONNECTION_HAS_SAVEPOINT;
+}
+
bool MySQL_Connection::get_status_get_lock() {
return status_flags & STATUS_MYSQL_CONNECTION_GET_LOCK;
}
@@ -1941,6 +1959,12 @@ bool MySQL_Connection::IsActiveTransaction() {
ret = true;
}
}
+ if (ret == false) {
+ if (get_status_has_savepoint()) {
+ // there are savepoints
+ ret = true;
+ }
+ }
}
return ret;
}
@@ -1973,7 +1997,7 @@ bool MySQL_Connection::MultiplexDisabled() {
// status_flags stores information about the status of the connection
// can be used to determine if multiplexing can be enabled or not
bool ret=false;
- if (status_flags & (STATUS_MYSQL_CONNECTION_TRANSACTION|STATUS_MYSQL_CONNECTION_USER_VARIABLE|STATUS_MYSQL_CONNECTION_PREPARED_STATEMENT|STATUS_MYSQL_CONNECTION_LOCK_TABLES|STATUS_MYSQL_CONNECTION_TEMPORARY_TABLE|STATUS_MYSQL_CONNECTION_GET_LOCK|STATUS_MYSQL_CONNECTION_NO_MULTIPLEX|STATUS_MYSQL_CONNECTION_SQL_LOG_BIN0|STATUS_MYSQL_CONNECTION_FOUND_ROWS|STATUS_MYSQL_CONNECTION_NO_BACKSLASH_ESCAPES) ) {
+ if (status_flags & (STATUS_MYSQL_CONNECTION_TRANSACTION|STATUS_MYSQL_CONNECTION_USER_VARIABLE|STATUS_MYSQL_CONNECTION_PREPARED_STATEMENT|STATUS_MYSQL_CONNECTION_LOCK_TABLES|STATUS_MYSQL_CONNECTION_TEMPORARY_TABLE|STATUS_MYSQL_CONNECTION_GET_LOCK|STATUS_MYSQL_CONNECTION_NO_MULTIPLEX|STATUS_MYSQL_CONNECTION_SQL_LOG_BIN0|STATUS_MYSQL_CONNECTION_FOUND_ROWS|STATUS_MYSQL_CONNECTION_NO_BACKSLASH_ESCAPES|STATUS_MYSQL_CONNECTION_HAS_SAVEPOINT) ) {
ret=true;
}
if (auto_increment_delay_token) return true;
@@ -2158,6 +2182,35 @@ void MySQL_Connection::ProcessQueryAndSetStatusFlags(char *query_digest_text) {
set_status_found_rows(true);
}
}
+ if (get_status_has_savepoint()==false) {
+ if (mysql) {
+ if (
+ (mysql->server_status & SERVER_STATUS_IN_TRANS)
+ ||
+ ((mysql->server_status & SERVER_STATUS_AUTOCOMMIT) == 0)
+ ) {
+ if (!strncasecmp(query_digest_text,"SAVEPOINT ", strlen("SAVEPOINT "))) {
+ set_status_has_savepoint(true);
+ }
+ }
+ }
+ } else {
+ if (
+ (
+ // make sure we don't have a transaction running
+ // checking just for COMMIT and ROLLBACK is not enough, because `SET autocommit=1` can commit too
+ (mysql->server_status & SERVER_STATUS_AUTOCOMMIT)
+ &&
+ ( (mysql->server_status & SERVER_STATUS_IN_TRANS) == 0 )
+ )
+ ||
+ !strcasecmp(query_digest_text,"COMMIT")
+ ||
+ !strcasecmp(query_digest_text,"ROLLBACK")
+ ) {
+ set_status_has_savepoint(false);
+ }
+ }
}
void MySQL_Connection::optimize() {
@@ -2264,6 +2317,7 @@ void MySQL_Connection::reset() {
if (variables[i].value) {
free(variables[i].value);
variables[i].value = NULL;
+ var_hash[i] = 0;
}
}
diff --git a/lib/mysql_data_stream.cpp b/lib/mysql_data_stream.cpp
index 7b26faf62f..f8f1a55314 100644
--- a/lib/mysql_data_stream.cpp
+++ b/lib/mysql_data_stream.cpp
@@ -880,6 +880,7 @@ int MySQL_Data_Stream::buffer2array() {
proxy_debug(PROXY_DEBUG_PKT_ARRAY, 5, "Session=%p . Reading the header of a new compressed packet\n", sess);
memcpy(&queueIN.hdr,queue_r_ptr(queueIN), sizeof(mysql_hdr));
queue_r(queueIN,sizeof(mysql_hdr));
+ pkt_sid=queueIN.hdr.pkt_id;
queueIN.pkt.size=queueIN.hdr.pkt_length+sizeof(mysql_hdr)+3;
queueIN.pkt.ptr=l_alloc(queueIN.pkt.size);
memcpy(queueIN.pkt.ptr, &queueIN.hdr, sizeof(mysql_hdr)); // immediately copy the header into the packet
diff --git a/lib/set_parser.cpp b/lib/set_parser.cpp
index f700a98ad8..335217c0dc 100644
--- a/lib/set_parser.cpp
+++ b/lib/set_parser.cpp
@@ -40,7 +40,9 @@ std::map> SetParser::parse1() {
#define VAR_VALUE_P1 "(((?:CONCAT\\()*(?:((?: )*REPLACE|IFNULL|CONCAT)\\()+(?: )*(?:NULL|@OLD_SQL_MODE|@@sql_mode),(?:(?:'|\\w|,| |\"|\\))+(?:\\))*)|(?:[@\\w/\\d:\\+\\-]|,)+|(?:)))"
const string pattern="(?:" NAMES SPACES QUOTES NAME_VALUE QUOTES "(?: +COLLATE +" QUOTES NAME_VALUE QUOTES "|)" "|" SESSION_P1 VAR_P1 SPACES "(?:|:)=" SPACES QUOTES VAR_VALUE_P1 QUOTES ") *,? *";
+VALGRIND_DISABLE_ERROR_REPORTING;
re2::RE2 re(pattern, *opt2);
+VALGRIND_ENABLE_ERROR_REPORTING;
string var;
string value1, value2, value3, value4, value5;
re2::StringPiece input(query);
diff --git a/src/Makefile b/src/Makefile
index 29cbe816aa..1537d641fd 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,6 +1,9 @@
-
-
+ifndef GIT_VERSION
GIT_VERSION := $(shell git describe --long)
+ifndef GIT_VERSION
+$(error GIT_VERSION is not set)
+endif
+endif
DEPS_PATH=../deps
diff --git a/src/main.cpp b/src/main.cpp
index 6bc9c778af..f5001ff905 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -935,7 +935,6 @@ void ProxySQL_Main_init_main_modules() {
GloQPro=NULL;
GloMTH=NULL;
GloMyAuth=NULL;
- GloMyLdapAuth = NULL;
#ifdef PROXYSQLCLICKHOUSE
GloClickHouseAuth=NULL;
#endif /* PROXYSQLCLICKHOUSE */
@@ -1212,6 +1211,7 @@ void ProxySQL_Main_init() {
static void LoadPlugins() {
+ GloMyLdapAuth = NULL;
if (GloVars.web_interface_plugin) {
dlerror();
char * dlsym_error = NULL;
@@ -1358,6 +1358,7 @@ void ProxySQL_Main_init_phase3___start_all() {
do { /* nothing */ } while (load_ != 1);
load_ = 0;
+ __sync_fetch_and_add(&GloMTH->status_variables.threads_initialized, 1);
{
cpu_timer t;
@@ -1754,6 +1755,7 @@ int main(int argc, const char * argv[]) {
} else {
GloAdmin->flush_error_log();
+ GloVars.install_signal_handler();
}
__start_label:
diff --git a/systemd/system/proxysql-initial.service b/systemd/system/proxysql-initial.service
new file mode 100644
index 0000000000..55f3445119
--- /dev/null
+++ b/systemd/system/proxysql-initial.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=High Performance Advanced Proxy for MySQL, this service will reset the database and start ProxySQL
+After=network.target
+
+[Service]
+Type=oneshot
+ExecStartPre=/bin/systemctl set-environment PROXYSQL_OPTS="--initial"
+ExecStart=/bin/systemctl start proxysql
+ExecStartPost=/bin/systemctl unset-environment PROXYSQL_OPTS
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/systemd/system/proxysql.service b/systemd/system/proxysql.service
index 2a13307939..6506a57b1c 100644
--- a/systemd/system/proxysql.service
+++ b/systemd/system/proxysql.service
@@ -8,7 +8,7 @@ RuntimeDirectory=proxysql
#PermissionsStartOnly=true
#ExecStartPre=/usr/bin/mkdir -p /var/run/proxysql /var/run/proxysql
#ExecStartPre=/usr/bin/chown -R proxysql: /var/run/proxysql/
-ExecStart=/usr/bin/proxysql -c /etc/proxysql.cnf
+ExecStart=/usr/bin/proxysql --idle-threads -c /etc/proxysql.cnf $PROXYSQL_OPTS
PIDFile=/var/lib/proxysql/proxysql.pid
#StandardError=null # all output is in stderr
SyslogIdentifier=proxysql
diff --git a/test/tap/Makefile b/test/tap/Makefile
index 36ff643bec..ebe60a1fc1 100644
--- a/test/tap/Makefile
+++ b/test/tap/Makefile
@@ -1,4 +1,3 @@
-
.PHONY: all
all: tap tests
@@ -7,12 +6,12 @@ clean:
cd tap && ${MAKE} clean
cd tests && ${MAKE} clean
-OPT=-O2
+debug: tap tests
.PHONY: tap
tap:
- cd tap && OPTZ="${O0} -ggdb " CC=${CC} CXX=${CXX} ${MAKE}
+ cd tap && CC=${CC} CXX=${CXX} ${MAKE} $(MAKECMDGOALS)
tests: tap
- cd tests && OPTZ="${O0} -ggdb " CC=${CC} CXX=${CXX} ${MAKE}
+ cd tests && CC=${CC} CXX=${CXX} ${MAKE} $(MAKECMDGOALS)
diff --git a/test/tap/constants b/test/tap/constants
new file mode 100644
index 0000000000..cc385c79fe
--- /dev/null
+++ b/test/tap/constants
@@ -0,0 +1,13 @@
+# This file should be modified locally according to proxysql configuration.
+# All TAP tests depend on these environment variables.
+#
+# Usage: source this file before running TAP tests
+# $ . constants
+# or
+# $ source constants
+#
+export TAP_HOST=127.0.0.1
+export TAP_PORT=6033
+export TAP_USERNAME=root
+export TAP_PASSWORD=REDACTED
+export TAP_WORKDIR=./tests/
diff --git a/test/tap/tap/Makefile b/test/tap/tap/Makefile
index e783286087..9be38ee36b 100644
--- a/test/tap/tap/Makefile
+++ b/test/tap/tap/Makefile
@@ -14,6 +14,9 @@ clean:
OPT=-O2
+debug: OPT = -O0 -DDEBUG -ggdb
+debug: libtap.a
+
libtap.a: tap.cpp tap.h command_line.cpp command_line.h utils.cpp utils.h
g++ -c tap.cpp command_line.cpp utils.cpp -std=c++11 -I$(JSON_IDIR) -I$(MARIADB_IDIR) $(OPT)
ar rcs libtap.a tap.o command_line.o utils.o
diff --git a/test/tap/tap/command_line.cpp b/test/tap/tap/command_line.cpp
index 50c1ef507c..128ebfc1db 100644
--- a/test/tap/tap/command_line.cpp
+++ b/test/tap/tap/command_line.cpp
@@ -13,7 +13,7 @@
using nlohmann::json;
CommandLine::CommandLine() :
- host(NULL), username(NULL), password(NULL), admin_username(NULL), admin_password(NULL) {}
+ host(NULL), username(NULL), password(NULL), admin_username(NULL), admin_password(NULL), workdir(NULL) {}
CommandLine::~CommandLine() {
if (host)
@@ -26,11 +26,13 @@ CommandLine::~CommandLine() {
free(admin_username);
if (admin_password)
free(admin_password);
+ if (workdir)
+ free(workdir);
}
int CommandLine::parse(int argc, char** argv) {
int opt;
- while ((opt = getopt(argc, argv, "ncsu:p:h:P:")) != -1) {
+ while ((opt = getopt(argc, argv, "ncsu:p:h:P:W:")) != -1) {
switch (opt) {
case 'c':
checksum = true;
@@ -59,11 +61,14 @@ int CommandLine::parse(int argc, char** argv) {
case 'U':
admin_username = strdup(optarg);
break;
+ case 'W':
+ workdir = strdup(optarg);
+ break;
case 'S':
admin_password = strdup(optarg);
break;
default: /* '?' */
- fprintf(stderr, "Usage: %s -u username -p password -h host [ -P port ] [ -A port ] [ -U admin_username ] [ -S admin_password ] [ -c ] [ -s ] [ -n ]\n", argv[0]);
+ fprintf(stderr, "Usage: %s -u username -p password -h host [ -P port ] [ -A port ] [ -U admin_username ] [ -S admin_password ] [ -W workdir] [ -c ] [ -s ] [ -n ]\n", argv[0]);
return 0;
}
}
@@ -101,6 +106,7 @@ int CommandLine::read(const std::string& file) {
admin_port = 6032;
username = strdup("root");
password = strdup("a");
+ workdir = strdup("./tests/");
return 0;
}
@@ -152,5 +158,9 @@ int CommandLine::getEnv() {
if(env_port>0 && env_port<65536)
admin_port=env_port;
+ value=getenv("TAP_WORKDIR");
+ if(!value) return -1;
+ workdir = strdup(value);
+
return 0;
}
diff --git a/test/tap/tap/command_line.h b/test/tap/tap/command_line.h
index a8f93c029c..c4857c2992 100644
--- a/test/tap/tap/command_line.h
+++ b/test/tap/tap/command_line.h
@@ -17,6 +17,7 @@ class CommandLine {
char* admin_password;
int port;
int admin_port;
+ char* workdir;
int read(const std::string& file);
int getEnv();
diff --git a/test/tap/tap/utils.cpp b/test/tap/tap/utils.cpp
index e31c47e5f7..33a0cbde2f 100644
--- a/test/tap/tap/utils.cpp
+++ b/test/tap/tap/utils.cpp
@@ -1,4 +1,6 @@
#include
+#include
+#include
#include "tap.h"
#include "utils.h"
@@ -102,3 +104,96 @@ int get_server_version(MYSQL *mysql, std::string& version) {
return 0;
}
+
+// Pipes definition
+constexpr uint8_t NUM_PIPES = 3;
+constexpr uint8_t PARENT_WRITE_PIPE = 0;
+constexpr uint8_t PARENT_READ_PIPE = 1;
+constexpr uint8_t PARENT_ERR_PIPE = 2;
+int pipes[NUM_PIPES][2];
+// Pipe selection
+constexpr uint8_t READ_FD = 0;
+constexpr uint8_t WRITE_FD = 1;
+// Parent pipes
+const auto& PARENT_READ_FD = pipes[PARENT_READ_PIPE][READ_FD];
+const auto& PARENT_READ_ERR = pipes[PARENT_ERR_PIPE][READ_FD];
+const auto& PARENT_WRITE_FD = pipes[PARENT_WRITE_PIPE][WRITE_FD];
+// Child pipes
+const auto& CHILD_READ_FD = pipes[PARENT_WRITE_PIPE][READ_FD];
+const auto& CHILD_WRITE_FD = pipes[PARENT_READ_PIPE][WRITE_FD];
+const auto& CHILD_WRITE_ERR = pipes[PARENT_ERR_PIPE][WRITE_FD];
+
+int execvp(const std::string& cmd, const std::vector& argv, std::string& result) {
+ int err = 0;
+ std::string result_ = "";
+ std::vector _argv = argv;
+
+ // Append null to end of _argv for extra safety
+ _argv.push_back(nullptr);
+
+ int outfd[2];
+ int infd[2];
+
+ // Pipes for parent to write and read
+ pipe(pipes[PARENT_READ_PIPE]);
+ pipe(pipes[PARENT_WRITE_PIPE]);
+ pipe(pipes[PARENT_ERR_PIPE]);
+
+ pid_t child_pid = fork();
+ if(child_pid == 0) {
+ // Copy the pipe descriptors
+ dup2(CHILD_READ_FD, STDIN_FILENO);
+ dup2(CHILD_WRITE_FD, STDOUT_FILENO);
+ dup2(CHILD_WRITE_ERR, STDERR_FILENO);
+
+ // Close no longer needed pipes
+ close(CHILD_READ_FD);
+ close(CHILD_WRITE_FD);
+ close(CHILD_WRITE_ERR);
+
+ close(PARENT_READ_FD);
+ close(PARENT_READ_ERR);
+ close(PARENT_WRITE_FD);
+
+ char** args = const_cast(_argv.data());
+ err = execvp(cmd.c_str(), args);
+
+ if (err) {
+ exit(errno);
+ } else {
+ exit(0);
+ }
+ } else {
+ char buffer[128];
+ int count;
+
+ // Close no longer needed pipes
+ close(CHILD_READ_FD);
+ close(CHILD_WRITE_FD);
+ close(CHILD_WRITE_ERR);
+
+ if (err == 0) {
+ // Read from child’s stdout
+ count = read(PARENT_READ_FD, buffer, sizeof(buffer));
+ while (count > 0) {
+ buffer[count] = 0;
+ result_ += buffer;
+ count = read(PARENT_READ_FD, buffer, sizeof(buffer));
+ }
+ } else {
+ // Read from child’s stderr
+ count = read(PARENT_READ_ERR, buffer, sizeof(buffer));
+ while (count > 0) {
+ buffer[count] = 0;
+ result_ += buffer;
+ count = read(PARENT_READ_ERR, buffer, sizeof(buffer));
+ }
+ }
+
+ waitpid(child_pid, &err, 0);
+ }
+
+ result = result_;
+
+ return err;
+}
diff --git a/test/tap/tap/utils.h b/test/tap/tap/utils.h
index ac740ec45f..b79effb9df 100644
--- a/test/tap/tap/utils.h
+++ b/test/tap/tap/utils.h
@@ -3,6 +3,7 @@
#include
#include
+#include
#define MYSQL_QUERY(mysql, query) \
do { \
@@ -27,5 +28,15 @@ int select_config_file(MYSQL* mysql, std::string& resultset);
}
#endif
+/**
+ * @brief Execute the given comand, and stores it's output.
+ *
+ * @param file File to be executed.
+ * @param argv Arguments to be given to the executable.
+ * @param result The output of the file execution. If the execution succeed it contains `stdout` output,
+ * in case of failure `stderr` contents are returned.
+ * @return int Zero in case of success, or the errno returned by `execvp` in case of failure.
+ */
+int execvp(const std::string& file, const std::vector& argv, std::string& result);
#endif // #define UTILS_H
diff --git a/test/tap/tests/Makefile b/test/tap/tests/Makefile
index 43124fcde0..2ad644bc4f 100644
--- a/test/tap/tests/Makefile
+++ b/test/tap/tests/Makefile
@@ -68,55 +68,37 @@ INCLUDEDIRS=-I../tap -I$(RE2_PATH) -I$(IDIR) -I$(JEMALLOC_IDIR) -I$(SQLITE3_DIR)
LDIRS=-L$(TAP_LIBDIR) -L$(LDIR) -L$(JEMALLOC_LDIR) $(LIBCONFIG_LDIR) -L$(RE2_PATH)/obj -L$(MARIADB_LDIR) -L$(DAEMONPATH_LDIR) -L$(PCRE_LDIR) -L$(MICROHTTPD_LDIR) -L$(LIBHTTPSERVER_LDIR) -L$(LIBINJECTION_LDIR) -L$(CURL_LDIR) -L$(EV_LDIR) -L$(SSL_LDIR)
MYLIBS=-Wl,--export-dynamic -Wl,-Bstatic -lconfig -lproxysql -ldaemon -ljemalloc -lconfig++ -lre2 -lpcrecpp -lpcre -lmariadbclient -lhttpserver -lmicrohttpd -linjection -lcurl -lssl -lcrypto -lev -Wl,-Bdynamic -lgnutls -lpthread -lm -lz -lrt $(EXTRALINK)
-STATIC_LIBS=$(MARIADB_LDIR)/libmariadbclient.a
+STATIC_LIBS= $(SSL_LDIR)/libssl.a $(SSL_LDIR)/libcrypto.a
.PHONY: all
all: tests
.PHONY: clean
clean:
- rm -f basic-t set_character_set-t charset_unsigned_int-t select_config_file-t sqlite3-t galera_1_timeout_count galera_2_timeout_no_count aurora test_set_character_results-t test_ps_large_result-t set_testing-t test_firewall-t || true
+ rm -f *-t galera_1_timeout_count galera_2_timeout_no_count aurora || true
-OPT=-O2
+OPT=-O2 -Wl,--no-as-needed
+debug: OPT=-O0 -DDEBUG -ggdb -Wl,--no-as-needed
+debug: tests
-SRC=basic-t.cpp set_character_set-t.cpp charset_unsigned_int-t.cpp select_config_file-t.cpp sqlite3-t.cpp galera_1_timeout_count.cpp galera_2_timeout_no_count.cpp aurora.cpp test_set_character_results-t.cpp test_ps_large_result-t.cpp set_testing-t.cpp test_firewall-t.cpp
-
-tests: basic-t set_character_set-t charset_unsigned_int-t select_config_file-t sqlite3-t test_set_character_results-t test_ps_large_result-t set_testing-t test_firewall-t
+tests: $(patsubst %.cpp,%,$(wildcard *-t.cpp))
testgalera: galera_1_timeout_count galera_2_timeout_no_count
testaurora: aurora
-sqlite3-t: $(TAP_LIBDIR)/libtap.a sqlite3-t.cpp
- g++ sqlite3-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) $(MYLIBS) -lpthread -ldl -std=c++11 -ltap -o sqlite3-t
-
-basic-t: $(TAP_LIBDIR)/libtap.a
- g++ basic-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 -ltap -o basic-t
-
-set_character_set-t: set_character_set-t.cpp $(TAP_LIBDIR)/libtap.a
- g++ set_character_set-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 -ltap -ldl $(MYLIBS) -o set_character_set-t
-
-charset_unsigned_int-t: charset_unsigned_int-t.cpp $(TAP_LIBDIR)/libtap.a
- g++ charset_unsigned_int-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 -ltap -ldl $(MYLIBS) -o charset_unsigned_int-t
-
-select_config_file-t: select_config_file-t.cpp $(TAP_LIBDIR)/libtap.a
- g++ select_config_file-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 -ltap -ldl $(MYLIBS) -o select_config_file-t
-
-test_set_character_results-t: test_set_character_results-t.cpp $(TAP_LIBDIR)/libtap.a
- g++ test_set_character_results-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(MYLIBS) -ltap -lssl -lcrypto -ldl -lpthread -o test_set_character_results-t
-
-test_ps_large_result-t: test_ps_large_result-t.cpp $(TAP_LIBDIR)/libtap.a
- g++ test_ps_large_result-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(MYLIBS) -ltap -lssl -lcrypto -ldl -lpthread -o test_ps_large_result-t
-
-test_firewall-t: test_firewall-t.cpp $(TAP_LIBDIR)/libtap.a
- g++ test_firewall-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(MYLIBS) -ltap -lssl -lcrypto -ldl -lpthread -o test_firewall-t
+%-t:%-t.cpp $(TAP_LIBDIR)/libtap.a
+ $(CXX) $^ $(INCLUDEDIRS) $(LDIRS) $(OPT) $(MYLIBS) -lpthread -ldl -std=c++11 -ltap $(STATIC_LIBS) -o $@
galera_1_timeout_count: galera_1_timeout_count.cpp $(TAP_LIBDIR)/libtap.a
- g++ -DTEST_GALERA -DDEBUG galera_1_timeout_count.cpp ../tap/SQLite3_Server.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl -o galera_1_timeout_count -DGITVERSION=\"$(GIT_VERSION)\"
+ g++ -DTEST_GALERA -DDEBUG galera_1_timeout_count.cpp ../tap/SQLite3_Server.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl $(STATIC_LIBS) -o galera_1_timeout_count -DGITVERSION=\"$(GIT_VERSION)\"
galera_2_timeout_no_count: galera_2_timeout_no_count.cpp $(TAP_LIBDIR)/libtap.a
- g++ -DTEST_GALERA -DDEBUG galera_2_timeout_no_count.cpp ../tap/SQLite3_Server.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl -o galera_2_timeout_no_count -DGITVERSION=\"$(GIT_VERSION)\"
+ g++ -DTEST_GALERA -DDEBUG galera_2_timeout_no_count.cpp ../tap/SQLite3_Server.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl $(STATIC_LIBS) -o galera_2_timeout_no_count -DGITVERSION=\"$(GIT_VERSION)\"
aurora: aurora.cpp $(TAP_LIBDIR)/libtap.a
- g++ -DTEST_AURORA -DDEBUG aurora.cpp ../tap/SQLite3_Server.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl -o aurora -DGITVERSION=\"$(GIT_VERSION)\"
+ g++ -DTEST_AURORA -DDEBUG aurora.cpp ../tap/SQLite3_Server.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl $(STATIC_LIBS) -o aurora -DGITVERSION=\"$(GIT_VERSION)\"
+
+1493_mixed_compression: reg_test_1493-mixed_compression-t.cpp
+ g++ -DTEST_AURORA -DDEBUG test_mixed_compression-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl $(STATIC_LIBS) -o reg_test_1493-mixed_compression-t -DGITVERSION=\"$(GIT_VERSION)\"
-set_testing-t: set_testing-t.cpp $(TAP_LIBDIR)/libtap.a
- g++ set_testing-t.cpp -Wall $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(MYLIBS) -ltap -pthread -O0 -ggdb -ldl -lssl -lcrypto -o set_testing-t
+2793_compression: reg_test_2793-compression-t.cpp
+ g++ -DTEST_AURORA -DDEBUG reg_test_2793-compression-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl $(STATIC_LIBS) -o reg_test_2793-compression-t -DGITVERSION=\"$(GIT_VERSION)\"
diff --git a/test/tap/tests/proxysql_reference_select_config_file.cnf b/test/tap/tests/proxysql_reference_select_config_file.cnf
index 71f3bc75b0..8b209102fe 100644
--- a/test/tap/tests/proxysql_reference_select_config_file.cnf
+++ b/test/tap/tests/proxysql_reference_select_config_file.cnf
@@ -88,13 +88,21 @@ mysql_variables =
connect_timeout_server_max="mysql"
connection_delay_multiplex_ms="mysql"
connection_max_age_ms="mysql"
+ connection_warming="mysql"
connpoll_reset_queue_length="mysql"
+ default_CHARSET="mysql"
+ default_action="mysql"
+ default_character_set_client="mysql"
+ default_character_set_connection="mysql"
+ default_character_set_database="mysql"
default_character_set_results="mysql"
default_charset="mysql"
default_collation_connection="mysql"
+ default_group_concat_max_len="mysql"
default_isolation_level="mysql"
default_max_join_size="mysql"
default_max_latency_ms="mysql"
+ default_names="mysql"
default_net_write_timeout="mysql"
default_query_delay="mysql"
default_query_timeout="mysql"
@@ -102,12 +110,14 @@ mysql_variables =
default_schema="mysql"
default_session_track_gtids="mysql"
default_sql_auto_is_null="mysql"
+ default_sql_log_bin="mysql"
default_sql_mode="mysql"
default_sql_safe_updates="mysql"
default_sql_select_limit="mysql"
default_time_zone="mysql"
default_transaction_read="mysql"
default_tx_isolation="mysql"
+ default_wsrep_sync_wait="mysql"
enforce_autocommit_on_reads="mysql"
eventslog_default_log="mysql"
eventslog_filename="mysql"
diff --git a/test/tap/tests/reg_test_1493-mixed_compression-t.cpp b/test/tap/tests/reg_test_1493-mixed_compression-t.cpp
new file mode 100644
index 0000000000..75edafffba
--- /dev/null
+++ b/test/tap/tests/reg_test_1493-mixed_compression-t.cpp
@@ -0,0 +1,85 @@
+/**
+ * @file reg_test_1493-mixed_compression-t.cpp
+ * @brief This test is a regression test for issue #1493.
+ * @date 2020-05-14
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include "tap.h"
+#include "command_line.h"
+#include "utils.h"
+
+using std::string;
+
+int main(int argc, char** argv) {
+ CommandLine cl;
+
+ if (cl.getEnv()) {
+ diag("Failed to get the required environmental variables.");
+ return -1;
+ }
+
+ plan(2);
+
+ MYSQL* proxysql_admin = mysql_init(NULL);
+
+ // Initialize connections
+ if (!proxysql_admin) {
+ fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
+ return -1;
+ }
+
+ // Connnect to local proxysql
+ if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
+ fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
+ return -1;
+ }
+
+ const char* disable_select_query_rules =
+ "UPDATE mysql_query_rules SET active=0 WHERE match_digest='^SELECT'";
+ const char* enable_select_query_rules =
+ "UPDATE mysql_query_rules SET active=1 WHERE match_digest='^SELECT'";
+ const char* update_mysql_query_rules =
+ "INSERT INTO mysql_query_rules (active, username, match_digest, destination_hostgroup, apply, cache_ttl, comment) "
+ "VALUES (1,'root','^SELECT.*', 1, 1, 1000000, 'test_mixed_compression_rule')";
+ const char* delete_mysql_query_rule =
+ "DELETE FROM mysql_query_rules WHERE "
+ "comment='test_mixed_compression_rule'";
+ const char* load_mysql_queries_runtime =
+ "LOAD MYSQL QUERY RULES TO RUNTIME";
+
+ // Setup config - query_rules
+ MYSQL_QUERY(proxysql_admin, disable_select_query_rules);
+ MYSQL_QUERY(proxysql_admin, update_mysql_query_rules);
+ MYSQL_QUERY(proxysql_admin, load_mysql_queries_runtime);
+
+ // Mixed compressed / uncompressed queries test #1493
+ const std::string mysql_client = "mysql";
+ const std::string tg_port = std::string("-P") + std::to_string(cl.port);
+ const std::string name = std::string("-u") + cl.username;
+ const std::string pass = std::string("-p") + cl.password;
+ const std::vector n_auth_cargs = { "mysql", name.c_str(), pass.c_str(), "-h", cl.host, tg_port.c_str(), "-C", "-e", "select 1", "--default-auth=mysql_native_password" };
+ const std::vector n_auth_args = { "mysql", name.c_str(), pass.c_str(), "-h", cl.host, tg_port.c_str(), "-e", "select 1", "--default-auth=mysql_native_password" };
+
+ // Query the mysql server in a compressed connection
+ std::string result = "";
+ int query_res = execvp(mysql_client, n_auth_cargs, result);
+ ok(query_res == 0 && result != "", "Native auth compressed query should be executed correctly.");
+
+ // Now query again using a uncompressed connection
+ query_res = execvp(mysql_client, n_auth_args, result);
+ ok(query_res == 0 && result != "", "Native auth uncompressed query should be executed correctly.");
+
+ // Teardown config
+ MYSQL_QUERY(proxysql_admin, delete_mysql_query_rule);
+ MYSQL_QUERY(proxysql_admin, enable_select_query_rules);
+ MYSQL_QUERY(proxysql_admin, load_mysql_queries_runtime);
+
+ return exit_status();
+}
diff --git a/test/tap/tests/reg_test_2793-compression-t.cpp b/test/tap/tests/reg_test_2793-compression-t.cpp
new file mode 100644
index 0000000000..5f493f0b7d
--- /dev/null
+++ b/test/tap/tests/reg_test_2793-compression-t.cpp
@@ -0,0 +1,41 @@
+/**
+ * @file reg_test_2793-compression-t.cpp
+ * @brief This test is a regression test for issue #2793.
+ * @date 2020-05-14
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "tap.h"
+#include "command_line.h"
+#include "utils.h"
+
+using std::string;
+
+int main(int argc, char** argv) {
+ CommandLine cl;
+
+ if (cl.getEnv()) {
+ diag("Failed to get the required environmental variables.");
+ return -1;
+ }
+
+ plan(1);
+
+ const std::string mysql_client = "mysql";
+ const std::string name = std::string("-u") + cl.username;
+ const std::string pass = std::string("-p") + cl.password;
+ const std::string tg_port = std::string("-P") + std::to_string(cl.port);
+ const std::vector cargs = { "mysql", name.c_str(), pass.c_str(), "-h", cl.host, tg_port.c_str(), "-C", "-e", "select 1" };
+
+ // Query the mysql server in a compressed connection
+ std::string result = "";
+ int query_res = execvp(mysql_client, cargs, result);
+ ok(query_res == 0 && result != "", "Compressed query should be executed correctly.");
+
+ return exit_status();
+}
diff --git a/test/tap/tests/savepoint-948-t.cpp b/test/tap/tests/savepoint-948-t.cpp
new file mode 100644
index 0000000000..981f5e4200
--- /dev/null
+++ b/test/tap/tests/savepoint-948-t.cpp
@@ -0,0 +1,401 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "tap.h"
+#include "utils.h"
+#include "command_line.h"
+
+
+unsigned long long monotonic_time() {
+ struct timespec ts;
+ //clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); // this is faster, but not precise
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (((unsigned long long) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000);
+}
+
+struct cpu_timer
+{
+ cpu_timer() {
+ begin = monotonic_time();
+ }
+ ~cpu_timer()
+ {
+ unsigned long long end = monotonic_time();
+ std::cerr << double( end - begin ) / 1000000 << " secs.\n" ;
+ begin=end-begin;
+ };
+ unsigned long long begin;
+};
+
+unsigned int num_threads=1;
+int count=0;
+char *username=NULL;
+char *password=NULL;
+char *host=(char *)"localhost";
+int port=3306;
+char *schema=(char *)"information_schema";
+int silent = 0;
+int sysbench = 0;
+int local=0;
+int transactions=0;
+int uniquequeries=0;
+int histograms=-1;
+
+unsigned int g_passed=0;
+unsigned int g_failed=0;
+
+std::atomic cnt_transactions;
+std::atomic cnt_SELECT_outside_transactions;
+
+unsigned int status_connections = 0;
+unsigned int connect_phase_completed = 0;
+unsigned int query_phase_completed = 0;
+
+__thread int g_seed;
+std::mutex mtx_;
+
+inline int fastrand() {
+ g_seed = (214013*g_seed+2531011);
+ return (g_seed>>16)&0x7FFF;
+}
+
+void gen_random(char *s, const int len) {
+ static const char alphanum[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+ for (int i = 0; i < len; ++i) {
+ s[i] = alphanum[fastrand() % (sizeof(alphanum) - 1)];
+ }
+
+ s[len] = 0;
+}
+
+void * my_conn_thread(void *arg) {
+ g_seed = time(NULL) ^ getpid() ^ pthread_self();
+ unsigned int select_OK=0;
+ unsigned int select_ERR=0;
+ int i, j;
+ MYSQL **mysqlconns=(MYSQL **)malloc(sizeof(MYSQL *)*count);
+
+ if (mysqlconns==NULL) {
+ exit(EXIT_FAILURE);
+ }
+
+
+ for (i=0; i 7) {
+ q = "RELEASE SAVEPOINT ";
+ q += buf;
+ if (mysql_query(mysql, q.c_str())) {
+ fprintf(stderr,"Error running query: %s. Error: %s\n", q.c_str(), mysql_error(mysql));
+ exit(EXIT_FAILURE);
+ }
+ sleepDelay = fastrand()%100;
+ usleep(sleepDelay * 100);
+ }
+ }
+ {
+ std::string q;
+ int f = fr%3;
+ if (f==0) {
+ q = "COMMIT";
+ } else {
+ q = "ROLLBACK";
+/*
+ // FIXME: this code is currently commented because of another bug
+ if (explicit_transaction==false) {
+ if (f!=1) {
+ q = "SET AUTOCOMMIT=1";
+ }
+ }
+*/
+ }
+ if (mysql_query(mysql, q.c_str())) {
+ fprintf(stderr,"Error running query: %s. Error: %s\n", q.c_str(), mysql_error(mysql));
+ exit(EXIT_FAILURE);
+ }
+ cnt_transactions++;
+ sleepDelay = fastrand()%100;
+ usleep(sleepDelay * 100);
+ }
+/*
+ // we do not log every single transaction, too verbose
+ bool testPassed = true;
+ {
+ std::lock_guard lock(mtx_);
+ ok(testPassed, "mysql connection [%p], thread_id [%lu], transaction completed", mysql, mysql->thread_id);
+ }
+*/
+ }
+ for (i=0; i= cnt_transactions+cnt_SELECT_outside_transactions-10) , "Number of transactions [%d] , Queries outside transaction [%d] , total connections returned [%d]", cnt_transactions.load(std::memory_order_relaxed), cnt_SELECT_outside_transactions.load(std::memory_order_relaxed), MyHGM_myconnpoll_push);
+ MYSQL_QUERY(mysqladmin, "DELETE FROM mysql_query_rules");
+ MYSQL_QUERY(mysqladmin, "INSERT INTO mysql_query_rules SELECT * FROM mysql_query_rules_948");
+ MYSQL_QUERY(mysqladmin, "LOAD MYSQL QUERY RULES TO RUNTIME");
+ return exit_status();
+}
diff --git a/test/tap/tests/select_config_file-t.cpp b/test/tap/tests/select_config_file-t.cpp
deleted file mode 100644
index 276780b5a0..0000000000
--- a/test/tap/tests/select_config_file-t.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include
-#include
-
-#include "tap.h"
-#include "command_line.h"
-#include "utils.h"
-
-int select_config_file(MYSQL* mysql, std::string& resultset) {
- if (mysql_query(mysql, "select config file")) {
- fprintf(stderr, "File %s, line %d, Error: 2 %s\n",
- __FILE__, __LINE__, mysql_error(mysql));
- return exit_status();
- }
-
- MYSQL_RES *result;
- MYSQL_ROW row;
- result = mysql_store_result(mysql);
- if (result) {
- row = mysql_fetch_row(result);
- resultset = row[0];
- mysql_free_result(result);
- } else {
- fprintf(stderr, "error\n");
- }
-
-}
-
-
-int main(int argc, char** argv) {
- CommandLine cl;
-
- if(cl.getEnv())
- return exit_status();
-
- plan(1);
- diag("Testing SELECT CONFIG INTO OUTFILE");
-
- MYSQL* mysql = mysql_init(NULL);
- if (!mysql)
- return exit_status();
-
- if (!mysql_real_connect(mysql, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
- fprintf(stderr, "File %s, line %d, Error: %s\n",
- __FILE__, __LINE__, mysql_error(mysql));
- return exit_status();
- }
-
- MYSQL_QUERY(mysql, "delete from global_variables");
- MYSQL_QUERY(mysql, "delete from mysql_users");
- MYSQL_QUERY(mysql, "delete from mysql_servers");
- MYSQL_QUERY(mysql, "delete from mysql_query_rules");
- MYSQL_QUERY(mysql, "delete from mysql_replication_hostgroups");
- MYSQL_QUERY(mysql, "delete from mysql_group_replication_hostgroups");
- MYSQL_QUERY(mysql, "delete from mysql_galera_hostgroups");
- MYSQL_QUERY(mysql, "delete from mysql_aws_aurora_hostgroups");
- MYSQL_QUERY(mysql, "delete from scheduler");
- MYSQL_QUERY(mysql, "delete from restapi_routes");
- MYSQL_QUERY(mysql, "delete from proxysql_servers");
-
- MYSQL_QUERY(mysql, "insert into proxysql_servers (hostname, port, weight, comment) values ('hostname', 3333, 12, 'comment');");
- MYSQL_QUERY(mysql, "insert into scheduler (id, active, interval_ms, filename, arg1, arg2, arg3, arg4, arg5, comment) values "
- " (1,1,1000,'filename','a1','a2','a3','a4','a5','comment');");
- MYSQL_QUERY(mysql, "insert into restapi_routes values "
- " (1,1,1000,'GET', 'test','./scripts/script.py','comment');");
- MYSQL_QUERY(mysql, "insert into mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, aurora_port, "
- " domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, "
- " add_lag_ms, min_lag_ms, lag_num_checks, comment) "
- " values (1,2,1,3,'.domain.net',20,106,107,1,9,10,20,1,'comment');");
- MYSQL_QUERY(mysql, "insert into mysql_galera_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, "
- " active, max_writers, writer_is_also_reader, max_transactions_behind, comment) values (1,2,3,4,1,23,1,1,'comment');");
- MYSQL_QUERY(mysql, "insert into mysql_group_replication_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, "
- " active, max_writers, writer_is_also_reader, max_transactions_behind, comment) values (1,2,3,4,1,23,1,1,'comment');");
- MYSQL_QUERY(mysql, "insert into mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup, check_type, comment) "
- " values (10,20,'read_only','Master / Slave App 1');");
- MYSQL_QUERY(mysql, "insert into mysql_servers (hostgroup_id, hostname, port, gtid_port, status, weight, compression, max_connections, "
- " max_replication_lag, use_ssl, max_latency_ms, comment) values (0,'127.0.0.1',3306,0,'ONLINE',1,0,1000,0,0,0,'comment2');");
- MYSQL_QUERY(mysql, "insert into mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, "
- " match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, "
- " cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, "
- " error_msg, OK_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, comment) values "
- " (1, 1, 'user', 'schema', 0, '.domain.com', '.proxy.com', 3333, 'ABC1', 'ABC', '^SELECT *', 0, 'CASE', 0, 1, 1, "
- " 1, 1, 100, 1, 1, 100, 100, 0, 0, 1, 'Error', 'OK', 0, 0, 0, 0, 0, 'comm1')");
- MYSQL_QUERY(mysql, "insert into mysql_users (username, password, active, use_ssl, default_hostgroup, default_schema, schema_locked, "
- " transaction_persistent, fast_forward, backend, frontend, max_connections, comment) values "
- " ('user', 'password', 1, 0, 0, 'schema', 1, 0, 1, 1, 1, 10, 'comm1')");
-
- MYSQL_QUERY(mysql, "update global_variables set variable_value='admin' where variable_name like 'admin-%'");
- MYSQL_QUERY(mysql, "update global_variables set variable_value='mysql' where variable_name like 'mysql-%'");
-
- MYSQL_QUERY(mysql, "load mysql servers to runtime");
-
- std::string resultset;
- resultset.reserve(100000);
- select_config_file(mysql, resultset);
-
- {
- std::ifstream inFile;
- inFile.open("./tests/proxysql_reference_select_config_file.cnf"); //open the input file
-
- std::stringstream strStream;
- strStream << inFile.rdbuf(); //read the file
- std::string str = strStream.str(); //str holds the content of the file
-
- ok(!str.compare(resultset), "Files are equal");
-#if 0
- std::ofstream f;
- f.open("out.txt", std::ios::out);
- f << resultset;
- f.close();
-#endif
-
- }
-
-#if 0
- std::ofstream out("output.cnf");
- out << resultset;
- out.close();
-#endif
-
- MYSQL_QUERY(mysql, "load mysql variables from disk");
- MYSQL_QUERY(mysql, "load admin variables from disk");
- MYSQL_QUERY(mysql, "load mysql users from disk");
- MYSQL_QUERY(mysql, "load mysql servers from disk");
- MYSQL_QUERY(mysql, "load scheduler from disk");
- MYSQL_QUERY(mysql, "load restapi from disk");
- MYSQL_QUERY(mysql, "load proxysql servers from disk");
-
- mysql_close(mysql);
-
- return exit_status();
-}
-
diff --git a/test/tap/tests/set_testing-multi-t.cpp b/test/tap/tests/set_testing-multi-t.cpp
new file mode 100644
index 0000000000..0ff0ef1aa8
--- /dev/null
+++ b/test/tap/tests/set_testing-multi-t.cpp
@@ -0,0 +1,659 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "json.hpp"
+
+#include "tap.h"
+#include "utils.h"
+#include "command_line.h"
+
+std::vector split(const std::string& s, char delimiter)
+{
+ std::vector tokens;
+ std::string token;
+ std::istringstream tokenStream(s);
+ while (std::getline(tokenStream, token, delimiter))
+ {
+ tokens.push_back(token);
+ }
+ return tokens;
+}
+
+using nlohmann::json;
+
+struct TestCase {
+ std::string command;
+ json expected_vars;
+};
+
+std::vector testCases;
+
+#define MAX_LINE 1024
+
+int readTestCases(const std::string& fileName) {
+ FILE* fp = fopen(fileName.c_str(), "r");
+ if (!fp) return 0;
+
+ char buf[MAX_LINE], col1[MAX_LINE], col2[MAX_LINE];
+ int n = 0;
+ for(;;) {
+ if (fgets(buf, sizeof(buf), fp) == NULL) break;
+ n = sscanf(buf, " \"%[^\"]\", \"%[^\"]\"", col1, col2);
+ if (n == 0) break;
+
+ char *p = col2;
+ while(*p++) if(*p == '\'') *p = '\"';
+
+ json vars = json::parse(col2);
+ testCases.push_back({col1, vars});
+ }
+
+ fclose(fp);
+ return 1;
+}
+
+unsigned long long monotonic_time() {
+ struct timespec ts;
+ //clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); // this is faster, but not precise
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (((unsigned long long) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000);
+}
+
+struct cpu_timer
+{
+ cpu_timer() {
+ begin = monotonic_time();
+ }
+ ~cpu_timer()
+ {
+ unsigned long long end = monotonic_time();
+ std::cerr << double( end - begin ) / 1000000 << " secs.\n" ;
+ begin=end-begin;
+ };
+ unsigned long long begin;
+};
+
+std::string bn = "";
+int queries_per_connections=1;
+unsigned int num_threads=1;
+int count=0;
+char *username=NULL;
+char *password=NULL;
+char *host=(char *)"localhost";
+int port=3306;
+int multiport=1;
+char *schema=(char *)"information_schema";
+int silent = 0;
+int sysbench = 0;
+int local=0;
+int queries=0;
+int uniquequeries=0;
+int histograms=-1;
+int multi_users=0;
+
+bool is_mariadb = false;
+bool is_cluster = false;
+unsigned int g_connect_OK=0;
+unsigned int g_connect_ERR=0;
+unsigned int g_select_OK=0;
+unsigned int g_select_ERR=0;
+
+unsigned int g_passed=0;
+unsigned int g_failed=0;
+
+unsigned int status_connections = 0;
+unsigned int connect_phase_completed = 0;
+unsigned int query_phase_completed = 0;
+
+__thread int g_seed;
+std::mutex mtx_;
+
+inline int fastrand() {
+ g_seed = (214013*g_seed+2531011);
+ return (g_seed>>16)&0x7FFF;
+}
+
+void parseResultJsonColumn(MYSQL_RES *result, json& j) {
+ if(!result) return;
+ MYSQL_ROW row;
+
+ while ((row = mysql_fetch_row(result)))
+ j = json::parse(row[0]);
+}
+
+void parseResult(MYSQL_RES *result, json& j) {
+ if(!result) return;
+ MYSQL_ROW row;
+
+ while ((row = mysql_fetch_row(result))) {
+ j[row[0]] = row[1];
+ }
+}
+
+void dumpResult(MYSQL_RES *result) {
+ if(!result) return;
+ MYSQL_ROW row;
+
+ int num_fields = mysql_num_fields(result);
+
+ while ((row = mysql_fetch_row(result)))
+ {
+ for(int i = 0; i < num_fields; i++)
+ {
+ printf("%s ", row[i] ? row[i] : "NULL");
+ }
+ printf("\n");
+ }
+}
+
+void queryVariables(MYSQL *mysql, json& j) {
+ std::stringstream query;
+ if (is_mariadb) {
+ query << "SELECT /* mysql " << mysql << " */ lower(variable_name), variable_value FROM information_schema.session_variables WHERE variable_name IN "
+ " ('hostname', 'sql_log_bin', 'sql_mode', 'init_connect', 'time_zone', 'sql_auto_is_null', "
+ " 'sql_safe_updates', 'max_join_size', 'net_write_timeout', 'sql_select_limit', "
+ " 'sql_select_limit', 'character_set_results', 'tx_isolation', 'tx_read_only', "
+ " 'sql_auto_is_null', 'collation_connection', 'character_set_connection', 'character_set_client', 'character_set_database', 'group_concat_max_len');";
+ }
+ if (is_cluster) {
+ query << "SELECT /* mysql " << mysql << " */ * FROM performance_schema.session_variables WHERE variable_name IN "
+ " ('hostname', 'sql_log_bin', 'sql_mode', 'init_connect', 'time_zone', 'sql_auto_is_null', "
+ " 'sql_safe_updates', 'session_track_gtids', 'max_join_size', 'net_write_timeout', 'sql_select_limit', "
+ " 'sql_select_limit', 'character_set_results', 'transaction_isolation', 'transaction_read_only', "
+ " 'sql_auto_is_null', 'collation_connection', 'character_set_connection', 'character_set_client', 'character_set_database', 'wsrep_sync_wait', 'group_concat_max_len');";
+ }
+ if (!is_mariadb && !is_cluster) {
+ query << "SELECT /* mysql " << mysql << " */ * FROM performance_schema.session_variables WHERE variable_name IN "
+ " ('hostname', 'sql_log_bin', 'sql_mode', 'init_connect', 'time_zone', 'sql_auto_is_null', "
+ " 'sql_safe_updates', 'session_track_gtids', 'max_join_size', 'net_write_timeout', 'sql_select_limit', "
+ " 'sql_select_limit', 'character_set_results', 'transaction_isolation', 'transaction_read_only', "
+ " 'sql_auto_is_null', 'collation_connection', 'character_set_connection', 'character_set_client', 'character_set_database', 'group_concat_max_len');";
+ }
+ //fprintf(stderr, "TRACE : QUERY 3 : variables %s\n", query.str().c_str());
+ if (mysql_query(mysql, query.str().c_str())) {
+ if (silent==0) {
+ fprintf(stderr,"ERROR while running -- \"%s\" : (%d) %s\n", query.str().c_str(), mysql_errno(mysql), mysql_error(mysql));
+ }
+ } else {
+ MYSQL_RES *result = mysql_store_result(mysql);
+ parseResult(result, j);
+
+ mysql_free_result(result);
+ __sync_fetch_and_add(&g_select_OK,1);
+ }
+}
+
+void queryInternalStatus(MYSQL *mysql, json& j) {
+ char *query = (char*)"PROXYSQL INTERNAL SESSION";
+
+ //fprintf(stderr, "TRACE : QUERY 4 : variables %s\n", query);
+ if (mysql_query(mysql, query)) {
+ if (silent==0) {
+ fprintf(stderr,"ERROR while running -- \"%s\" : (%d) %s\n", query, mysql_errno(mysql), mysql_error(mysql));
+ }
+ } else {
+ MYSQL_RES *result = mysql_store_result(mysql);
+ parseResultJsonColumn(result, j);
+
+ mysql_free_result(result);
+ __sync_fetch_and_add(&g_select_OK,1);
+ }
+
+ // value types in mysql and in proxysql are different
+ // we should convert proxysql values to mysql format to compare
+ for (auto& el : j.items()) {
+ if (el.key() == "conn") {
+ std::string sql_log_bin_value;
+
+ // sql_log_bin {0|1}
+ if (el.value()["sql_log_bin"] == 1) {
+ el.value().erase("sql_log_bin");
+ j["conn"]["sql_log_bin"] = "ON";
+ }
+ else if (el.value()["sql_log_bin"] == 0) {
+ el.value().erase("sql_log_bin");
+ j["conn"]["sql_log_bin"] = "OFF";
+ }
+
+ // sql_auto_is_null {true|false}
+ if (!el.value()["sql_auto_is_null"].dump().compare("ON") ||
+ !el.value()["sql_auto_is_null"].dump().compare("1") ||
+ !el.value()["sql_auto_is_null"].dump().compare("on") ||
+ el.value()["sql_auto_is_null"] == 1) {
+ el.value().erase("sql_auto_is_null");
+ j["conn"]["sql_auto_is_null"] = "ON";
+ }
+ else if (!el.value()["sql_auto_is_null"].dump().compare("OFF") ||
+ !el.value()["sql_auto_is_null"].dump().compare("0") ||
+ !el.value()["sql_auto_is_null"].dump().compare("off") ||
+ el.value()["sql_auto_is_null"] == 0) {
+ el.value().erase("sql_auto_is_null");
+ j["conn"]["sql_auto_is_null"] = "OFF";
+ }
+
+ // completely remove autocommit test
+/*
+ // autocommit {true|false}
+ if (!el.value()["autocommit"].dump().compare("ON") ||
+ !el.value()["autocommit"].dump().compare("1") ||
+ !el.value()["autocommit"].dump().compare("on") ||
+ el.value()["autocommit"] == 1) {
+ el.value().erase("autocommit");
+ j["conn"]["autocommit"] = "ON";
+ }
+ else if (!el.value()["autocommit"].dump().compare("OFF") ||
+ !el.value()["autocommit"].dump().compare("0") ||
+ !el.value()["autocommit"].dump().compare("off") ||
+ el.value()["autocommit"] == 0) {
+ el.value().erase("autocommit");
+ j["conn"]["autocommit"] = "OFF";
+ }
+*/
+ // sql_safe_updates
+ if (!el.value()["sql_safe_updates"].dump().compare("\"ON\"") ||
+ !el.value()["sql_safe_updates"].dump().compare("\"1\"") ||
+ !el.value()["sql_safe_updates"].dump().compare("\"on\"") ||
+ el.value()["sql_safe_updates"] == 1) {
+ el.value().erase("sql_safe_updates");
+ j["conn"]["sql_safe_updates"] = "ON";
+ }
+ else if (!el.value()["sql_safe_updates"].dump().compare("\"OFF\"") ||
+ !el.value()["sql_safe_updates"].dump().compare("\"0\"") ||
+ !el.value()["sql_safe_updates"].dump().compare("\"off\"") ||
+ el.value()["sql_safe_updates"] == 0) {
+ el.value().erase("sql_safe_updates");
+ j["conn"]["sql_safe_updates"] = "OFF";
+ }
+
+ std::stringstream ss;
+ ss << 0xFFFFFFFFFFFFFFFF;
+ // sql_select_limit
+ if (!el.value()["sql_select_limit"].dump().compare("\"DEFAULT\"")) {
+ el.value().erase("sql_select_limit");
+ j["conn"]["sql_select_limit"] = strdup(ss.str().c_str());
+ }
+
+ if (!is_mariadb) {
+ // transaction_isolation (level)
+ if (!el.value()["isolation_level"].dump().compare("\"REPEATABLE READ\"")) {
+ el.value().erase("isolation_level");
+ j["conn"]["transaction_isolation"] = "REPEATABLE-READ";
+ }
+ else if (!el.value()["isolation_level"].dump().compare("\"READ COMMITTED\"")) {
+ el.value().erase("isolation_level");
+ j["conn"]["transaction_isolation"] = "READ-COMMITTED";
+ }
+ else if (!el.value()["isolation_level"].dump().compare("\"READ UNCOMMITTED\"")) {
+ el.value().erase("isolation_level");
+ j["conn"]["transaction_isolation"] = "READ-UNCOMMITTED";
+ }
+ else if (!el.value()["isolation_level"].dump().compare("\"SERIALIZABLE\"")) {
+ el.value().erase("isolation_level");
+ j["conn"]["transaction_isolation"] = "SERIALIZABLE";
+ }
+ }
+ else {
+ // transaction_isolation (level)
+ if (!el.value()["isolation_level"].dump().compare("\"REPEATABLE READ\"")) {
+ el.value().erase("isolation_level");
+ j["conn"]["tx_isolation"] = "REPEATABLE-READ";
+ }
+ else if (!el.value()["isolation_level"].dump().compare("\"READ COMMITTED\"")) {
+ el.value().erase("isolation_level");
+ j["conn"]["tx_isolation"] = "READ-COMMITTED";
+ }
+ else if (!el.value()["isolation_level"].dump().compare("\"READ UNCOMMITTED\"")) {
+ el.value().erase("isolation_level");
+ j["conn"]["tx_isolation"] = "READ-UNCOMMITTED";
+ }
+ else if (!el.value()["isolation_level"].dump().compare("\"SERIALIZABLE\"")) {
+ el.value().erase("isolation_level");
+ j["conn"]["tx_isolation"] = "SERIALIZABLE";
+ }
+ }
+
+ if (!is_mariadb) {
+ // transaction_read (write|only)
+ if (!el.value()["transaction_read"].dump().compare("\"ONLY\"")) {
+ el.value().erase("transaction_read");
+ j["conn"]["transaction_read_only"] = "ON";
+ }
+ else if (!el.value()["transaction_read"].dump().compare("\"WRITE\"")) {
+ el.value().erase("transaction_read");
+ j["conn"]["transaction_read_only"] = "OFF";
+ }
+ } else {
+ // transaction_read (write|only)
+ if (!el.value()["transaction_read"].dump().compare("\"ONLY\"")) {
+ el.value().erase("transaction_read");
+ j["conn"]["tx_read_only"] = "ON";
+ }
+ else if (!el.value()["transaction_read"].dump().compare("\"WRITE\"")) {
+ el.value().erase("transaction_read");
+ j["conn"]["tx_read_only"] = "OFF";
+ }
+ }
+
+ if (!is_mariadb) {
+ // session_track_gtids
+ if (!el.value()["session_track_gtids"].dump().compare("\"OFF\"")) {
+ el.value().erase("session_track_gtids");
+ j["conn"]["session_track_gtids"] = "OFF";
+ }
+ else if (!el.value()["session_track_gtids"].dump().compare("\"OWN_GTID\"")) {
+ el.value().erase("session_track_gtids");
+ j["conn"]["session_track_gtids"] = "OWN_GTID";
+ }
+ else if (!el.value()["session_track_gtids"].dump().compare("\"ALL_GTIDS\"")) {
+ el.value().erase("session_track_gtids");
+ j["conn"]["session_track_gtids"] = "ALL_GTIDS";
+ }
+ }
+
+ }
+ }
+}
+
+void * my_conn_thread(void *arg) {
+ g_seed = time(NULL) ^ getpid() ^ pthread_self();
+ unsigned int select_OK=0;
+ unsigned int select_ERR=0;
+ int i, j;
+ MYSQL **mysqlconns=(MYSQL **)malloc(sizeof(MYSQL *)*count);
+ std::vector varsperconn(count);
+
+ if (mysqlconns==NULL) {
+ exit(EXIT_FAILURE);
+ }
+
+ std::vector cs = {"latin1", "utf8", "utf8mb4", "latin2", "latin7"};
+
+ for (i=0; i lock(mtx_);
+ skip(1, "mysql connection [%p], command [%s]", mysql, testCases[r2].command.c_str());
+ continue;
+ }
+ if (strstr(testCases[r2].command.c_str(),"sql_log_bin")) {
+ std::lock_guard lock(mtx_);
+ skip(1, "mysql connection [%p], command [%s]", mysql, testCases[r2].command.c_str());
+ continue;
+ }
+ }
+ std::vector commands = split(testCases[r2].command.c_str(), ';');
+ for (auto c : commands) {
+ if (mysql_query(mysql, c.c_str())) {
+ if (silent==0) {
+ fprintf(stderr,"ERROR while running -- \"%s\" : (%d) %s\n", c.c_str(), mysql_errno(mysql), mysql_error(mysql));
+ }
+ } else {
+ MYSQL_RES *result = mysql_store_result(mysql);
+ mysql_free_result(result);
+ select_OK++;
+ __sync_fetch_and_add(&g_select_OK,1);
+ }
+ }
+
+ for (auto& el : testCases[r2].expected_vars.items()) {
+ if (el.key() == "transaction_isolation") {
+ if (is_mariadb) {
+ vars["tx_isolation"] = el.value();
+ }
+ else {
+ vars[el.key()] = el.value();
+ }
+ }
+ else if (el.key() == "session_track_gtids") {
+ if (!is_mariadb) {
+ vars[el.key()] = el.value();
+ }
+ }
+ else if (el.key() == "wsrep_sync_wait") {
+ if (is_cluster) {
+ vars[el.key()] = el.value();
+ }
+ }
+ else if (el.key() == "transaction_read_only") {
+ if (is_mariadb) {
+ vars["tx_read_only"] = el.value();
+ } else {
+ vars[el.key()] = el.value();
+ }
+ }
+ else {
+ vars[el.key()] = el.value();
+ }
+ }
+
+ int sleepDelay = fastrand()%100;
+ usleep(sleepDelay * 1000);
+
+ char query[128];
+ sprintf(query, "SELECT /* %p */ %d;", mysql, sleepDelay);
+ if (mysql_query(mysql,query)) {
+ select_ERR++;
+ __sync_fetch_and_add(&g_select_ERR,1);
+ } else {
+ MYSQL_RES *result = mysql_store_result(mysql);
+ mysql_free_result(result);
+ select_OK++;
+ __sync_fetch_and_add(&g_select_OK,1);
+ }
+
+ json mysql_vars;
+ queryVariables(mysql, mysql_vars);
+
+ json proxysql_vars;
+ queryInternalStatus(mysql, proxysql_vars);
+
+ bool testPassed = true;
+ int variables_tested = 0;
+ for (auto& el : vars.items()) {
+ auto k = mysql_vars.find(el.key());
+ auto s = proxysql_vars["conn"].find(el.key());
+
+ if (k == mysql_vars.end())
+ fprintf(stderr, "Variable %s->%s in mysql resultset was not found.\nmysql data : %s\nproxysql data: %s\ncsv data %s\n",
+ el.value().dump().c_str(), el.key().c_str(), mysql_vars.dump().c_str(), proxysql_vars.dump().c_str(), vars.dump().c_str());
+
+ if (s == proxysql_vars["conn"].end())
+ fprintf(stderr, "Variable %s->%s in proxysql resultset was not found.\nmysql data : %s\nproxysql data: %s\ncsv data %s\n",
+ el.value().dump().c_str(), el.key().c_str(), mysql_vars.dump().c_str(), proxysql_vars.dump().c_str(), vars.dump().c_str());
+
+ if (k.value() != el.value() || s.value() != el.value()) {
+ __sync_fetch_and_add(&g_failed, 1);
+ testPassed = false;
+ fprintf(stderr, "Test failed for this case %s->%s.\n\nmysql data %s\n\n proxysql data %s\n\n csv data %s\n\n\n",
+ el.value().dump().c_str(), el.key().c_str(), mysql_vars.dump().c_str(), proxysql_vars.dump().c_str(), vars.dump().c_str());
+ ok(testPassed, "mysql connection [%p], thread_id [%lu], command [%s]", mysql, mysql->thread_id, testCases[r2].command.c_str());
+ exit(0);
+ } else {
+ variables_tested++;
+ }
+ }
+ {
+ std::lock_guard lock(mtx_);
+ ok(testPassed, "mysql connection [%p], thread_id [%lu], variables_tested [%d], command [%s]", mysql, mysql->thread_id, variables_tested, testCases[r2].command.c_str());
+ }
+ }
+ __sync_fetch_and_add(&query_phase_completed,1);
+
+ return NULL;
+}
+
+
+int main(int argc, char *argv[]) {
+ CommandLine cl;
+
+ if(cl.getEnv())
+ return exit_status();
+
+ {
+ bn = basename(argv[0]);
+ std::string bn = basename(argv[0]);
+ std::cerr << "Filename: " << bn << std::endl;
+ if (bn == "set_testing-multi-t") {
+ multi_users=4;
+ }
+ }
+
+ std::string fileName(std::string(cl.workdir) + "/set_testing-t.csv");
+
+ MYSQL* mysqladmin = mysql_init(NULL);
+ if (!mysqladmin)
+ return exit_status();
+
+ if (!mysql_real_connect(mysqladmin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
+ fprintf(stderr, "File %s, line %d, Error: %s\n",
+ __FILE__, __LINE__, mysql_error(mysqladmin));
+ return exit_status();
+ }
+/*
+ MYSQL_QUERY(mysqladmin, "update global_variables set variable_value='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION' where variable_name='mysql-default_sql_mode'");
+ MYSQL_QUERY(mysqladmin, "update global_variables set variable_value='OFF' where variable_name='mysql-default_sql_safe_update'");
+ MYSQL_QUERY(mysqladmin, "update global_variables set variable_value='UTF8' where variable_name='mysql-default_character_set_results'");
+ MYSQL_QUERY(mysqladmin, "update global_variables set variable_value='REPEATABLE READ' where variable_name='mysql-default_isolation_level'");
+ MYSQL_QUERY(mysqladmin, "update global_variables set variable_value='REPEATABLE READ' where variable_name='mysql-default_tx_isolation'");
+ MYSQL_QUERY(mysqladmin, "update global_variables set variable_value='utf8_general_ci' where variable_name='mysql-default_collation_connection'");
+ MYSQL_QUERY(mysqladmin, "update global_variables set variable_value='true' where variable_name='mysql-enforce_autocommit_on_reads'");
+ MYSQL_QUERY(mysqladmin, "load mysql variables to runtime");
+
+*/
+ if (multi_users) {
+ for (int i=1; i<=multi_users; i++) {
+ std::string q = "INSERT OR IGNORE INTO mysql_users (username,password) VALUES ('sbtest" + std::to_string(i) + "','sbtest" + std::to_string(i) + "')";
+ std::cerr << bn << ": " << q << std::endl;
+ MYSQL_QUERY(mysqladmin, q.c_str());
+ }
+ std::string q = "LOAD MYSQL USERS TO RUNTIME";
+ std::cerr << bn << ": " << q << std::endl;
+ MYSQL_QUERY(mysqladmin, q.c_str());
+ q = "UPDATE mysql_servers SET max_connections=3 WHERE hostgroup_id=0;";
+ std::cerr << bn << ": " << q << std::endl;
+ MYSQL_QUERY(mysqladmin, q.c_str());
+ q = "LOAD MYSQL SERVERS TO RUNTIME";
+ std::cerr << bn << ": " << q << std::endl;
+ MYSQL_QUERY(mysqladmin, q.c_str());
+ }
+ MYSQL* mysql = mysql_init(NULL);
+ if (!mysql)
+ return exit_status();
+ if (!mysql_real_connect(mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
+ fprintf(stderr, "File %s, line %d, Error: %s\n",
+ __FILE__, __LINE__, mysql_error(mysql));
+ return exit_status();
+ }
+ MYSQL_QUERY(mysql, "select @@version");
+ MYSQL_RES *result = mysql_store_result(mysql);
+ MYSQL_ROW row;
+ while ((row = mysql_fetch_row(result)))
+ {
+ if (strstr(row[0], "Maria")) {
+ is_mariadb = true;
+ }
+ else {
+ is_mariadb = false;
+ }
+
+ char* first_dash = strstr(row[0], "-");
+ if (!first_dash || !strstr(first_dash+1, "-")) {
+ is_cluster = false;
+ } else {
+ is_cluster = true;
+ }
+ }
+
+ mysql_free_result(result);
+ mysql_close(mysql);
+
+ num_threads = 10;
+ queries = 1000;
+ queries_per_connections = 10;
+ count = 10;
+ username = cl.username;
+ password = cl.password;
+ host = cl.host;
+ port = cl.port;
+
+ plan(queries * num_threads);
+ if (!readTestCases(fileName)) {
+ fprintf(stderr, "Cannot read %s\n", fileName.c_str());
+ return exit_status();
+ }
+
+ if (strcmp(host,"localhost")==0) {
+ local = 1;
+ }
+ if (uniquequeries == 0) {
+ if (queries) uniquequeries=queries;
+ }
+ if (uniquequeries) {
+ uniquequeries=(int)sqrt(uniquequeries);
+ }
+
+ pthread_t *thi=(pthread_t *)malloc(sizeof(pthread_t)*num_threads);
+ if (thi==NULL)
+ return exit_status();
+
+ for (unsigned int i=0; i lock(mtx_);
+ skip(1, "mysql connection [%p], command [%s]", mysql, testCases[r2].command.c_str());
+ continue;
+ }
+ if (strstr(testCases[r2].command.c_str(),"sql_log_bin")) {
+ std::lock_guard lock(mtx_);
+ skip(1, "mysql connection [%p], command [%s]", mysql, testCases[r2].command.c_str());
+ continue;
+ }
+ }
std::vector commands = split(testCases[r2].command.c_str(), ';');
for (auto c : commands) {
if (mysql_query(mysql, c.c_str())) {
if (silent==0) {
- fprintf(stderr,"%s\n", mysql_error(mysql));
+ fprintf(stderr,"ERROR while running -- \"%s\" : (%d) %s\n", c.c_str(), mysql_errno(mysql), mysql_error(mysql));
}
} else {
MYSQL_RES *result = mysql_store_result(mysql);
@@ -476,6 +489,7 @@ void * my_conn_thread(void *arg) {
queryInternalStatus(mysql, proxysql_vars);
bool testPassed = true;
+ int variables_tested = 0;
for (auto& el : vars.items()) {
auto k = mysql_vars.find(el.key());
auto s = proxysql_vars["conn"].find(el.key());
@@ -495,11 +509,13 @@ void * my_conn_thread(void *arg) {
el.value().dump().c_str(), el.key().c_str(), mysql_vars.dump().c_str(), proxysql_vars.dump().c_str(), vars.dump().c_str());
ok(testPassed, "mysql connection [%p], thread_id [%lu], command [%s]", mysql, mysql->thread_id, testCases[r2].command.c_str());
exit(0);
+ } else {
+ variables_tested++;
}
}
{
std::lock_guard lock(mtx_);
- ok(testPassed, "mysql connection [%p], thread_id [%lu], command [%s]", mysql, mysql->thread_id, testCases[r2].command.c_str());
+ ok(testPassed, "mysql connection [%p], thread_id [%lu], variables_tested [%d], command [%s]", mysql, mysql->thread_id, variables_tested, testCases[r2].command.c_str());
}
}
__sync_fetch_and_add(&query_phase_completed,1);
@@ -510,11 +526,13 @@ void * my_conn_thread(void *arg) {
int main(int argc, char *argv[]) {
CommandLine cl;
- std::string fileName("./tests/set_testing-t.csv");
if(cl.getEnv())
return exit_status();
+ std::string fileName(std::string(cl.workdir) + "/set_testing-t.csv");
+/*
+ // do not connect to admin at all
MYSQL* mysqladmin = mysql_init(NULL);
if (!mysqladmin)
return exit_status();
@@ -534,8 +552,7 @@ int main(int argc, char *argv[]) {
MYSQL_QUERY(mysqladmin, "update global_variables set variable_value='true' where variable_name='mysql-enforce_autocommit_on_reads'");
MYSQL_QUERY(mysqladmin, "load mysql variables to runtime");
- mysql_close(mysqladmin);
-
+*/
MYSQL* mysql = mysql_init(NULL);
if (!mysql)
return exit_status();
diff --git a/test/tap/tests/set_testing-t.csv b/test/tap/tests/set_testing-t.csv
index db8114f171..beccbd8e34 100644
--- a/test/tap/tests/set_testing-t.csv
+++ b/test/tap/tests/set_testing-t.csv
@@ -31,7 +31,6 @@
"SET sql_mode='PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION'", "{'sql_mode':'PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION'}"
"SET time_zone='+01:00'","{'time_zone':'+01:00'}"
"SET time_zone='-03:00', sql_mode='ALLOW_INVALID_DATES'","{'time_zone':'-03:00', 'sql_mode':'ALLOW_INVALID_DATES'}"
-"SET autocommit=0","{'autocommit':'OFF'}"
"SET time_zone='+04:00', sql_mode='NO_ENGINE_SUBSTITUTION'", "{'time_zone':'+04:00','sql_mode':'NO_ENGINE_SUBSTITUTION'}"
"SET sql_safe_updates='OFF'", "{'sql_safe_updates':'OFF'}"
"SET sql_safe_updates='ON'", "{'sql_safe_updates':'ON'}"
@@ -62,3 +61,5 @@
"set max_join_size=18446744073709551615", "{'max_join_size':'18446744073709551615'}"
"set wsrep_sync_wait=1", "{'wsrep_sync_wait':'1'}"
"set wsrep_sync_wait=0", "{'wsrep_sync_wait':'0'}"
+"set group_concat_max_len=2048", "{'group_concat_max_len':'2048'}"
+"set group_concat_max_len=4096", "{'group_concat_max_len':'4096'}"
diff --git a/test/tap/tests/test_default_value_transaction_isolation-t.cpp b/test/tap/tests/test_default_value_transaction_isolation-t.cpp
new file mode 100644
index 0000000000..cca5d20806
--- /dev/null
+++ b/test/tap/tests/test_default_value_transaction_isolation-t.cpp
@@ -0,0 +1,91 @@
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "tap.h"
+#include "command_line.h"
+#include "utils.h"
+
+int main(int argc, char** argv) {
+ CommandLine cl;
+
+ if(cl.getEnv())
+ return exit_status();
+
+ plan(3);
+ diag("Testing default value for session varable transaction isolation");
+
+ MYSQL* mysqladmin = mysql_init(NULL);
+ if (!mysqladmin)
+ return exit_status();
+
+ if (!mysql_real_connect(mysqladmin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
+ fprintf(stderr, "File %s, line %d, Error: %s\n",
+ __FILE__, __LINE__, mysql_error(mysqladmin));
+ return exit_status();
+ }
+
+ // Set default non-existing value for transaction isolation level
+ MYSQL_QUERY(mysqladmin, "set mysql-default_isolation_level='non-existing-value-1'");
+ MYSQL_QUERY(mysqladmin, "load mysql variables to runtime");
+
+ MYSQL* mysql_1 = mysql_init(NULL);
+ if (!mysql_1)
+ return exit_status();
+
+ if (!mysql_real_connect(mysql_1, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
+ fprintf(stderr, "Failed to connect to database: Error: %s\n",
+ mysql_error(mysql_1));
+ return exit_status();
+ }
+ MYSQL_QUERY(mysql_1, "select 1");
+ MYSQL_RES* result = mysql_store_result(mysql_1);
+ ok(mysql_num_rows(result) == 1, "Select statement should be executed on connection 1");
+ mysql_free_result(result);
+
+ MYSQL* mysql_2 = mysql_init(NULL);
+ if (!mysql_2)
+ return exit_status();
+
+ if (!mysql_real_connect(mysql_2, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
+ fprintf(stderr, "Failed to connect to database: Error: %s\n",
+ mysql_error(mysql_2));
+ return exit_status();
+ }
+ MYSQL_QUERY(mysql_2, "select 1");
+ result = mysql_store_result(mysql_2);
+ ok(mysql_num_rows(result) == 1, "Select statement should be executed on connection 1");
+ mysql_free_result(result);
+
+ // Change default non-existing value for transaction isolation level
+ MYSQL_QUERY(mysqladmin, "set mysql-default_isolation_level='non-existing-value-2'");
+ MYSQL_QUERY(mysqladmin, "load mysql variables to runtime");
+
+ // Try third connection with different default value of the session variable
+ MYSQL* mysql_3 = mysql_init(NULL);
+ if (!mysql_3)
+ return exit_status();
+
+ if (!mysql_real_connect(mysql_3, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
+ fprintf(stderr, "Failed to connect to database: Error: %s\n",
+ mysql_error(mysql_3));
+ return exit_status();
+ }
+ MYSQL_QUERY(mysql_3, "select 1");
+ result = mysql_store_result(mysql_3);
+ ok(mysql_num_rows(result) == 1, "Select statement should be executed on connection 1");
+ mysql_free_result(result);
+
+ mysql_close(mysql_3);
+ mysql_close(mysql_2);
+ mysql_close(mysql_1);
+ mysql_close(mysqladmin);
+
+ return exit_status();
+}
+
diff --git a/test/tap/tests/test_firewall-t.cpp b/test/tap/tests/test_firewall-t.cpp
index b15cf47d0d..70fbafbee6 100644
--- a/test/tap/tests/test_firewall-t.cpp
+++ b/test/tap/tests/test_firewall-t.cpp
@@ -17,7 +17,7 @@ int main(int argc, char** argv) {
if(cl.getEnv())
return exit_status();
- plan(3);
+ plan(7);
diag("Testing firewall whitelist functionality");
MYSQL* mysqladmin = mysql_init(NULL);
@@ -55,7 +55,7 @@ int main(int argc, char** argv) {
mysql_free_result(result);
MYSQL_QUERY(mysqladmin, "update global_variables set variable_value=1 where variable_name='mysql-firewall_whitelist_enabled'");
- MYSQL_QUERY(mysqladmin, "load mysql users to runtime");
+ MYSQL_QUERY(mysqladmin, "load mysql variables to runtime");
// Test that firewall initialized and blocks all queries
if (mysql_query(mysql, "select @@version")) {
@@ -138,6 +138,15 @@ int main(int argc, char** argv) {
ok(false, "Query should be allowed by firewall, but it is blocked after active=1 update");
}
+ // Cleanup firewall rules
+ MYSQL_QUERY(mysqladmin, "load mysql firewall from disk");
+ MYSQL_QUERY(mysqladmin, "load mysql firewall to runtime");
+
+ // Clean up variables
+ MYSQL_QUERY(mysqladmin, "load mysql variables from disk");
+ MYSQL_QUERY(mysqladmin, "load mysql variables to runtime");
+
+
mysql_close(mysql);
mysql_close(mysqladmin);
diff --git a/test/tap/tests/test_mysql_query_rules_fast_routing-t.cpp b/test/tap/tests/test_mysql_query_rules_fast_routing-t.cpp
new file mode 100644
index 0000000000..814263e671
--- /dev/null
+++ b/test/tap/tests/test_mysql_query_rules_fast_routing-t.cpp
@@ -0,0 +1,72 @@
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+#include "tap.h"
+#include "command_line.h"
+#include "utils.h"
+
+int main(int argc, char** argv) {
+ CommandLine cl;
+
+ std::random_device rd; //Will be used to obtain a seed for the random number engine
+ std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
+ std::uniform_int_distribution<> dis(100000, 1000000);
+
+ if(cl.getEnv())
+ return exit_status();
+
+ plan(6);
+ diag("Testing query rules fast routing");
+
+ MYSQL* mysqlAdmin = mysql_init(NULL);
+ if (!mysqlAdmin) return exit_status();
+ if (!mysql_real_connect(mysqlAdmin, cl.host, "admin", "admin", NULL, 6032, NULL, 0)) return exit_status();
+
+ const auto NUM_REPS=3;
+ char query[1024] = {0};
+ for (auto i=0; i