From d5e9ecc6bbc196759a4593b38ad35947fc1c186a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 26 Aug 2025 18:38:47 +0200 Subject: [PATCH 01/23] Fix libconfig compilation with GCC 15 Port of commit 690342b9cbc8b39787a1501bd890d63ca63a003c into 'gcc-15.patch'. --- deps/Makefile | 1 + deps/libconfig/gcc-15.patch | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 deps/libconfig/gcc-15.patch diff --git a/deps/Makefile b/deps/Makefile index 87d2a20e8f..f2598c6099 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -255,6 +255,7 @@ sqlite3: sqlite3/sqlite3/sqlite3.o libconfig/libconfig/lib/.libs/libconfig++.a: cd libconfig && rm -rf libconfig-*/ || true cd libconfig && tar -zxf libconfig-*.tar.gz + cd libconfig/libconfig && patch -p0 < ../gcc-15.patch cd libconfig/libconfig && ./configure --disable-examples cd libconfig/libconfig && CC=${CC} CXX=${CXX} ${MAKE} diff --git a/deps/libconfig/gcc-15.patch b/deps/libconfig/gcc-15.patch new file mode 100644 index 0000000000..3ea6ed763f --- /dev/null +++ b/deps/libconfig/gcc-15.patch @@ -0,0 +1,26 @@ +diff --git lib/grammar.y lib/grammar.y +index f614fa7..b7d6989 100644 +--- lib/grammar.y ++++ lib/grammar.y +@@ -40,8 +40,7 @@ + #include "wincompat.h" + + /* These declarations are provided to suppress compiler warnings. */ +-extern int libconfig_yylex(); +-extern int libconfig_yyget_lineno(); ++extern int libconfig_yyget_lineno(void *); + + #define YYMALLOC libconfig_malloc + +@@ -82,6 +81,11 @@ void libconfig_yyerror(void *scanner, struct parse_context *ctx, + char *sval; + } + ++%{ ++/* These declarations are provided to suppress compiler warnings. */ ++extern int libconfig_yylex(YYSTYPE *, void *); ++%} ++ + %token TOK_BOOLEAN TOK_INTEGER TOK_HEX + %token TOK_INTEGER64 TOK_HEX64 + %token TOK_FLOAT From 6ca8413c1d78bd7395a1a15673604fd854277079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 26 Aug 2025 18:43:41 +0200 Subject: [PATCH 02/23] Fix obsolescent 'egrep' warnings during compilation --- Makefile | 4 ++-- deps/Makefile | 4 ++-- lib/Makefile | 4 ++-- src/Makefile | 4 ++-- test/tap/tap/Makefile | 4 ++-- test/tap/tests/Makefile | 4 ++-- test/tap/tests_with_deps/deprecate_eof_support/Makefile | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index e34ff5629f..aa634f1861 100644 --- a/Makefile +++ b/Makefile @@ -50,9 +50,9 @@ export MAKE export CURVER ### detect compiler support for c++11/17 -CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | egrep -o '[0-9]{6}L') +CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201703L) - CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | egrep -o '[0-9]{6}L') + CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | grep -Eo '[0-9]{6}L') LEGACY_BUILD := 1 ifneq ($(CPLUSPLUS),201103L) $(error Compiler must support at least c++11) diff --git a/deps/Makefile b/deps/Makefile index f2598c6099..6dbd35eaf3 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -35,9 +35,9 @@ endif ### detect compiler support for c++11/17 -CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | egrep -o '[0-9]{6}L') +CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201703L) - CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | egrep -o '[0-9]{6}L') + CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201103L) $(error Compiler must support at least c++11) endif diff --git a/lib/Makefile b/lib/Makefile index 5d68eb27c5..18b5364a6a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -120,9 +120,9 @@ endif ### detect compiler support for c++11/17 -CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | egrep -o '[0-9]{6}L') +CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201703L) - CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | egrep -o '[0-9]{6}L') + CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201103L) $(error Compiler must support at least c++11) endif diff --git a/src/Makefile b/src/Makefile index 53d0d9b004..246969fac6 100644 --- a/src/Makefile +++ b/src/Makefile @@ -121,9 +121,9 @@ endif ### detect compiler support for c++11/17 -CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | egrep -o '[0-9]{6}L') +CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201703L) - CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | egrep -o '[0-9]{6}L') + CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201103L) $(error Compiler must support at least c++11) endif diff --git a/test/tap/tap/Makefile b/test/tap/tap/Makefile index a39395352e..627505b4ee 100644 --- a/test/tap/tap/Makefile +++ b/test/tap/tap/Makefile @@ -53,9 +53,9 @@ LIBPROXYSQLAR := $(PROXYSQL_LDIR)/libproxysql.a IDIRS := -I$(PROXYSQL_IDIR) -I$(JSON_IDIR) -I${CURL_IDIR} -I${SQLITE3_IDIR} -I$(DOTENV_IDIR) -I$(RE2_IDIR) ### detect compiler support for c++11/17 -CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | egrep -o '[0-9]{6}L') +CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201703L) - CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | egrep -o '[0-9]{6}L') + CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201103L) $(error Compiler must support at least c++11) endif diff --git a/test/tap/tests/Makefile b/test/tap/tests/Makefile index 0f83f476c0..3272b5fdd0 100644 --- a/test/tap/tests/Makefile +++ b/test/tap/tests/Makefile @@ -160,9 +160,9 @@ ifeq ($(UNAME_S),Linux) endif ### detect compiler support for c++11/17 -CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | egrep -o '[0-9]{6}L') +CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201703L) - CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | egrep -o '[0-9]{6}L') + CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201103L) $(error Compiler must support at least c++11) endif diff --git a/test/tap/tests_with_deps/deprecate_eof_support/Makefile b/test/tap/tests_with_deps/deprecate_eof_support/Makefile index 672bcef56b..3d629b9ec8 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/Makefile +++ b/test/tap/tests_with_deps/deprecate_eof_support/Makefile @@ -88,9 +88,9 @@ POSTGRESQL_IDIR := $(POSTGRESQL_PATH)/include -I$(POSTGRESQL_PATH)/interfaces/li POSTGRESQL_LDIR := $(POSTGRESQL_PATH)/interfaces/libpq -L$(POSTGRESQL_PATH)/common -L$(POSTGRESQL_PATH)/port ### detect compiler support for c++11/17 -CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | egrep -o '[0-9]{6}L') +CPLUSPLUS := $(shell ${CC} -std=c++17 -dM -E -x c++ /dev/null 2>/dev/null | grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201703L) - CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | egrep -o '[0-9]{6}L') + CPLUSPLUS := $(shell ${CC} -std=c++11 -dM -E -x c++ /dev/null 2>/dev/null| grep -F __cplusplus | grep -Eo '[0-9]{6}L') ifneq ($(CPLUSPLUS),201103L) $(error Compiler must support at least c++11) endif From acd90f2ecfff02c0b780e43d3817143144c71eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 26 Aug 2025 18:48:21 +0200 Subject: [PATCH 03/23] Fix coredumper compilation on CMake >= 4.0 --- deps/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/Makefile b/deps/Makefile index 6dbd35eaf3..d487a73d91 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -112,7 +112,7 @@ coredumper/coredumper/src/libcoredumper.a: cd coredumper && rm -rf coredumper-*/ || true cd coredumper && tar -zxf coredumper-*.tar.gz cd coredumper/coredumper && patch -p1 < ../includes.patch - cd coredumper/coredumper && cmake . -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Debug + cd coredumper/coredumper && cmake . -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cd coredumper/coredumper && CC=${CC} CXX=${CXX} ${MAKE} coredumper: coredumper/coredumper/src/libcoredumper.a From baff856b0ba4036208295a23edeb424b78119328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 26 Aug 2025 18:58:50 +0200 Subject: [PATCH 04/23] Fix 'clickhose-cpp' compilation on C++17 and CMake >= 4.0 --- deps/Makefile | 3 ++- deps/clickhouse-cpp/ciso646-options.h.patch | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 deps/clickhouse-cpp/ciso646-options.h.patch diff --git a/deps/Makefile b/deps/Makefile index d487a73d91..39072ed754 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -161,7 +161,8 @@ clickhouse-cpp/clickhouse-cpp/clickhouse/libclickhouse-cpp-lib-static.a: cd clickhouse-cpp && tar -zxf v2.3.0.tar.gz cd clickhouse-cpp && ln -fs clickhouse-cpp-*/ clickhouse-cpp cd clickhouse-cpp/clickhouse-cpp && patch clickhouse/base/wire_format.h < ../wire_format.patch - cd clickhouse-cpp/clickhouse-cpp && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo . + cd clickhouse-cpp/clickhouse-cpp && patch -p0 < ../ciso646-options.h.patch + cd clickhouse-cpp/clickhouse-cpp && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_POLICY_VERSION_MINIMUM=3.5 . cd clickhouse-cpp/clickhouse-cpp && CC=${CC} CXX=${CXX} ${MAKE} clickhouse-cpp: clickhouse-cpp/clickhouse-cpp/clickhouse/libclickhouse-cpp-lib-static.a diff --git a/deps/clickhouse-cpp/ciso646-options.h.patch b/deps/clickhouse-cpp/ciso646-options.h.patch new file mode 100644 index 0000000000..9c45d8a2f8 --- /dev/null +++ b/deps/clickhouse-cpp/ciso646-options.h.patch @@ -0,0 +1,15 @@ +--- contrib/absl/base/options.h 2022-11-23 10:33:15.000000000 +0100 ++++ contrib/absl/base/options.h 2022-11-23 10:33:15.000000000 +0100 +@@ -70,7 +70,11 @@ + // Include a standard library header to allow configuration based on the + // standard library in use. + #ifdef __cplusplus +-#include ++#if __has_include() ++#include ++#else ++#include ++#endif + #endif + + // ----------------------------------------------------------------------------- From 3d494d08a3412aa190512d0d9eca451f1f5b18e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 26 Aug 2025 19:49:45 +0200 Subject: [PATCH 05/23] Fix 'mariadb-client' compilation on GCC 15 and CMake >= 4.0 --- deps/Makefile | 3 ++- deps/mariadb-client-library/ma_global.h.patch | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 deps/mariadb-client-library/ma_global.h.patch diff --git a/deps/Makefile b/deps/Makefile index 39072ed754..e7125696d9 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -195,7 +195,7 @@ mariadb-client-library/mariadb_client/libmariadb/libmariadbclient.a: cd mariadb-client-library && rm -rf mariadb-connector-c-*/ || true cd mariadb-client-library && tar -zxf mariadb-connector-c-3.3.8-src.tar.gz cd mariadb-client-library/mariadb_client && patch -p0 < ../plugin_auth_CMakeLists.txt.patch - cd mariadb-client-library/mariadb_client && cmake . -Wno-dev -DCMAKE_BUILD_TYPE=RelWithDebInfo -DOPENSSL_ROOT_DIR=$(SSL_IDIR) -DOPENSSL_LIBRARIES=$(SSL_LDIR) -DICONV_LIBRARIES=$(brew --prefix libiconv)/lib -DICONV_INCLUDE=$(brew --prefix libiconv)/include . + cd mariadb-client-library/mariadb_client && cmake . -Wno-dev -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DOPENSSL_ROOT_DIR=$(SSL_IDIR) -DOPENSSL_LIBRARIES=$(SSL_LDIR) -DICONV_LIBRARIES=$(brew --prefix libiconv)/lib -DICONV_INCLUDE=$(brew --prefix libiconv)/include . ifeq ($(PROXYDEBUG),1) cd mariadb-client-library/mariadb_client && patch -p0 < ../ma_context.h.patch else ifeq ($(USEVALGRIND),1) @@ -235,6 +235,7 @@ endif cd mariadb-client-library/mariadb_client && patch -p0 < ../mariadb_rpl.patch cd mariadb-client-library/mariadb_client && patch -p0 < ../cmakelists.txt.patch cd mariadb-client-library/mariadb_client && patch -p0 < ../mariadb_lib.c.metadata_column_check.patch + cd mariadb-client-library/mariadb_client && patch -p0 < ../ma_global.h.patch cd mariadb-client-library/mariadb_client && CC=${CC} CXX=${CXX} ${MAKE} mariadbclient # cd mariadb-client-library/mariadb_client/include && make my_config.h diff --git a/deps/mariadb-client-library/ma_global.h.patch b/deps/mariadb-client-library/ma_global.h.patch new file mode 100644 index 0000000000..e2deaf400f --- /dev/null +++ b/deps/mariadb-client-library/ma_global.h.patch @@ -0,0 +1,13 @@ +--- include/ma_global.h 2023-11-01 11:28:04.000000000 +0100 ++++ include/ma_global.h 2023-11-01 11:28:04.000000000 +0100 +@@ -683,9 +683,9 @@ + typedef int myf; /* Type of MyFlags in my_funcs */ + typedef char my_bool; /* Small bool */ + typedef unsigned long long my_ulonglong; +-#if !defined(bool) && !defined(bool_defined) && (!defined(HAVE_BOOL) || !defined(__cplusplus)) ++#if !defined(bool) && !defined(bool_defined) && (!defined(HAVE_BOOL) || !defined(__cplusplus)) && (__STDC_VERSION__ < 202300L) + typedef char bool; /* Ordinary boolean values 0 1 */ + #endif + /* Macros for converting *constants* to the right type */ + #define INT8(v) (int8) (v) + #define INT16(v) (int16) (v) From 240a97d0613d3e1a827eb48a0cf20ed63d76d432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 26 Aug 2025 20:37:47 +0200 Subject: [PATCH 06/23] Fix 'libpq' compilation on GCC 15 --- deps/Makefile | 1 + deps/postgresql/c23_bool-c.h.patch | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 deps/postgresql/c23_bool-c.h.patch diff --git a/deps/Makefile b/deps/Makefile index e7125696d9..6c2134b1e5 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -310,6 +310,7 @@ postgresql/postgresql/src/interfaces/libpq/libpq.a: cd postgresql/postgresql && patch -p0 < ../get_result_from_pgconn.patch cd postgresql/postgresql && patch -p0 < ../handle_row_data.patch cd postgresql/postgresql && patch -p0 < ../fmt_err_msg.patch + cd postgresql/postgresql && patch -p0 < ../c23_bool-c.h.patch #cd postgresql/postgresql && LD_LIBRARY_PATH="$(shell pwd)/libssl/openssl" ./configure --with-ssl=openssl --with-includes="$(shell pwd)/libssl/openssl/include/" --with-libraries="$(shell pwd)/libssl/openssl/" --without-readline --enable-debug CFLAGS="-ggdb -O0 -fno-omit-frame-pointer" CPPFLAGS="-g -O0" cd postgresql/postgresql && LD_LIBRARY_PATH="$(SSL_LDIR)" ./configure --with-ssl=openssl --with-includes="$(SSL_IDIR)" --with-libraries="$(SSL_LDIR)" --without-readline cd postgresql/postgresql/src/interfaces/libpq && CC=${CC} CXX=${CXX} ${MAKE} MAKELEVEL=0 diff --git a/deps/postgresql/c23_bool-c.h.patch b/deps/postgresql/c23_bool-c.h.patch new file mode 100644 index 0000000000..3e70aebf7c --- /dev/null +++ b/deps/postgresql/c23_bool-c.h.patch @@ -0,0 +1,14 @@ +--- src/include/c.h 2025-06-23 13:30:51.563824789 +0200 ++++ src/include/c.h 2025-06-23 13:30:51.563824789 +0200 +@@ -436,10 +436,10 @@ + #include + #else + +-#ifndef bool ++#if !defined(bool) && (__STDC_VERSION__ < 202300L) + typedef unsigned char bool; + #endif + + #ifndef true + #define true ((bool) 1) + #endif From 24fdb11a4fcf5f81831b4c7f4b684f9861f9525e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 26 Aug 2025 20:39:35 +0200 Subject: [PATCH 07/23] Remove obsolete comments on 'lib/Makefile' --- lib/Makefile | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 18b5364a6a..1d9132ac1f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -182,13 +182,5 @@ libproxysql.a: $(ODIR) $(OBJ) $(OBJ_CXX) $(SQLITE3_DIR)/sqlite3.o $(ODIR): mkdir $(ODIR) -#all: $(EXECUTABLE) - - clean: rm -rf *.pid $(ODIR)/*.oo $(ODIR)/*.o $(ODIR)/*.gcno $(ODIR)/*.gcda *.ko *.so *~ core libproxysql.a $(ODIR) - - -## self note -# ../deps/protobuf/protobuf/src/protoc -I=. --cpp_out=. ./mysql_logger.proto -# mv mysql_logger.pb.cc mysql_logger.pb.cpp From 63f0d00b535741526c93005586570f5a420d3592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Wed, 27 Aug 2025 10:36:53 +0200 Subject: [PATCH 08/23] Improve OpenSSL library search in 'openssl_flags.mk' --- common_mk/openssl_flags.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common_mk/openssl_flags.mk b/common_mk/openssl_flags.mk index 4b709e7aa9..9326eadf64 100644 --- a/common_mk/openssl_flags.mk +++ b/common_mk/openssl_flags.mk @@ -21,8 +21,8 @@ ifeq ($(CUSTOM_OPENSSL_PATH),) else SSL_IDIR := $(shell export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1; export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1; pkg-config --cflags $(OPENSSL_PACKAGE) | grep -oP "(?<=-I)[^ ]+") SSL_LDIR := $(shell pkg-config --variable=libdir $(OPENSSL_PACKAGE)) - LIB_SSL_PATH := $(shell find $(SSL_LDIR) -name "libssl.so" 2>/dev/null | head -n 1) - LIB_CRYPTO_PATH := $(shell find $(SSL_LDIR) -name "libcrypto.so" 2>/dev/null | head -n 1) + LIB_SSL_PATH := $(shell find $(SSL_LDIR) --maxdepth 1 -name "libssl.so" 2>/dev/null | head -n 1) + LIB_CRYPTO_PATH := $(shell find $(SSL_LDIR) --maxdepth 1 -name "libcrypto.so" 2>/dev/null | head -n 1) endif else SSL_IDIR := $(CUSTOM_OPENSSL_PATH)/include @@ -44,4 +44,4 @@ else endif else $(error Warning: OpenSSL headers (SSL_IDIR) not found. Exiting. Please install OpenSSL version 3.) -endif \ No newline at end of file +endif From 7989847c7ef1faeaebdaabff2d3faae1049940d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Wed, 27 Aug 2025 18:46:08 +0200 Subject: [PATCH 09/23] Fix 'cpp-dotenv' compilation on CMake >= 4.0 --- test/tap/tap/Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/tap/tap/Makefile b/test/tap/tap/Makefile index 627505b4ee..299556d29e 100644 --- a/test/tap/tap/Makefile +++ b/test/tap/tap/Makefile @@ -144,7 +144,8 @@ cpp-dotenv/static/cpp-dotenv/libcpp_dotenv.a: cd cpp-dotenv/static/cpp-dotenv && patch src/dotenv.cpp < ../../dotenv.cpp.patch cd cpp-dotenv/static/cpp-dotenv && patch include/dotenv.h < ../../dotenv.h.patch cd cpp-dotenv/static/cpp-dotenv && patch -p0 < ../../nm_clang_fix.patch - cd cpp-dotenv/static/cpp-dotenv && cmake . -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Debug + cd cpp-dotenv/static/cpp-dotenv && cmake . -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cd cpp-dotenv/static/cpp-dotenv && CC=${CC} CXX=${CXX} ${MAKE} cpp-dotenv/dynamic/cpp-dotenv/libcpp_dotenv.so: @@ -153,7 +154,8 @@ cpp-dotenv/dynamic/cpp-dotenv/libcpp_dotenv.so: cd cpp-dotenv/dynamic/cpp-dotenv && patch src/dotenv.cpp < ../../dotenv.cpp.patch cd cpp-dotenv/dynamic/cpp-dotenv && patch include/dotenv.h < ../../dotenv.h.patch cd cpp-dotenv/dynamic/cpp-dotenv && patch -p0 < ../../nm_clang_fix.patch - cd cpp-dotenv/dynamic/cpp-dotenv && cmake . -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_RPATH="../tap:../../tap" -DCMAKE_BUILD_TYPE=Debug + cd cpp-dotenv/dynamic/cpp-dotenv && cmake . -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_BUILD_RPATH="../tap:../../tap" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cd cpp-dotenv/dynamic/cpp-dotenv && CC=${CC} CXX=${CXX} ${MAKE} From 195379555b17906c8e8840a1bcdb2aa43ecc4469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Wed, 27 Aug 2025 18:49:09 +0200 Subject: [PATCH 10/23] Fix 'mariadb-client' tests dep compilation on GCC 15 and CMake >= 4.0 --- test/deps/Makefile | 3 ++- test/deps/mariadb-connector-c/ma_global.h.patch | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 test/deps/mariadb-connector-c/ma_global.h.patch diff --git a/test/deps/Makefile b/test/deps/Makefile index 0eabf53c1a..ff26b0fe1c 100644 --- a/test/deps/Makefile +++ b/test/deps/Makefile @@ -20,7 +20,8 @@ mariadb-connector-c/mariadb-connector-c/libmariadb/libmariadbclient.a: cd mariadb-connector-c && tar -zxf mariadb-connector-c-*.tar.gz cd mariadb-connector-c/mariadb-connector-c && patch -p0 < ../CMakeLists.txt.patch cd mariadb-connector-c/mariadb-connector-c && patch -p0 < ../ConnectorName.cmake.patch - cd mariadb-connector-c/mariadb-connector-c && cmake . -DCMAKE_BUILD_TYPE=RelWithDebInfo + cd mariadb-connector-c/mariadb-connector-c && patch -p0 < ../ma_global.h.patch + cd mariadb-connector-c/mariadb-connector-c && cmake . -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cd mariadb-connector-c/mariadb-connector-c && CC=${CC} CXX=${CXX} ${MAKE} mariadbclient mariadb_client: mariadb-connector-c/mariadb-connector-c/libmariadb/libmariadbclient.a diff --git a/test/deps/mariadb-connector-c/ma_global.h.patch b/test/deps/mariadb-connector-c/ma_global.h.patch new file mode 100644 index 0000000000..d8469e8d8e --- /dev/null +++ b/test/deps/mariadb-connector-c/ma_global.h.patch @@ -0,0 +1,14 @@ +--- include/ma_global.h 2023-11-01 11:28:04.000000000 +0100 ++++ include/ma_global.h 2023-11-01 11:28:04.000000000 +0100 +@@ -699,9 +699,10 @@ + typedef int myf; /* Type of MyFlags in my_funcs */ + typedef char my_bool; /* Small bool */ + typedef unsigned long long my_ulonglong; +-#if !defined(bool) && !defined(bool_defined) && (!defined(HAVE_BOOL) || !defined(__cplusplus)) ++#if !defined(bool) && !defined(bool_defined) && (!defined(HAVE_BOOL) || !defined(__cplusplus)) && __STDC_VERSION__ < 202311L + typedef char bool; /* Ordinary boolean values 0 1 */ + #endif ++ + /* Macros for converting *constants* to the right type */ + #define INT8(v) (int8) (v) + #define INT16(v) (int16) (v) From 03297687fad1979675869d1c01e2f1e07efb9159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Wed, 27 Aug 2025 18:50:12 +0200 Subject: [PATCH 11/23] Fix 'mysql-connector-c-5.7' tests dep compilation on GCC 15 - Updated command with `-DWITHOUT_SERVER=ON` preventing unnecessary compilations. - Compatibility seems broken with CMake >= 4.0. For now, 'CMake' version 3.x should be used for building the tests locally. --- test/deps/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/deps/Makefile b/test/deps/Makefile index ff26b0fe1c..a27dc026ea 100644 --- a/test/deps/Makefile +++ b/test/deps/Makefile @@ -33,7 +33,11 @@ mysql-connector-c/mysql-connector-c/libmysql/libmysqlclient.a: mysql-connector-c cd mysql-connector-c && rm -rf mysql-*/ || true cd mysql-connector-c && tar -zxf mysql-boost-5.7.*.tar.gz cd mysql-connector-c && ln -fsT $$(ls -1d mysql-5.7.*/) mysql-connector-c - cd mysql-connector-c/mysql-connector-c && cmake . -DWITH_BOOST=./boost -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O0 -ggdb -DNDEBUG -fPIC" + cd mysql-connector-c/mysql-connector-c && mkdir -p storage/ndb + cd mysql-connector-c/mysql-connector-c && touch storage/ndb/CMakeLists.txt + cd mysql-connector-c/mysql-connector-c && cmake . -DWITHOUT_SERVER=ON -DWITH_BOOST=./boost \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-Wno-incompatible-pointer-types" \ + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O0 -ggdb -DNDEBUG -fPIC -Wno-incompatible-pointer-types" cd mysql-connector-c/mysql-connector-c && CC=${CC} CXX=${CXX} ${MAKE} mysqlclient mysql cd mysql-connector-c/mysql-connector-c && cp archive_output_directory/libmysqlclient.a libmysql/ From db8f1b25a9636c89b36398ec15059aa9144ef618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Wed, 27 Aug 2025 19:01:33 +0200 Subject: [PATCH 12/23] Improve compilation time for 'mysql-connector-c-8.4.0' test dependency - Updated command with `-DWITHOUT_SERVER=ON` preventing unnecessary compilations. --- test/deps/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/deps/Makefile b/test/deps/Makefile index a27dc026ea..0b62fa15e5 100644 --- a/test/deps/Makefile +++ b/test/deps/Makefile @@ -50,9 +50,10 @@ mysql-connector-c-8.4.0/mysql-connector-c/libmysql/libmysqlclient.a: mysql-conne cd mysql-connector-c-8.4.0 && rm -rf mysql-*/ || true cd mysql-connector-c-8.4.0 && tar -zxf mysql-*.tar.gz cd mysql-connector-c-8.4.0 && ln -fsT $$(ls -1d mysql-8.4.*/) mysql-connector-c - cd mysql-connector-c-8.4.0/mysql-connector-c && cmake . -DFORCE_INSOURCE_BUILD=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DWITHOUT_SERVER=ON -DDOWNLOAD_BOOST=1 -DWITH_BOOST=./mysql-server/downloads/ -DWITH_UNIT_TESTS=OFF \ - -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O0 -ggdb -DNDEBUG -fPIC" + cd mysql-connector-c-8.4.0/mysql-connector-c && cmake . -DWITHOUT_SERVER=ON -DFORCE_INSOURCE_BUILD=1 \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITHOUT_SERVER=ON -DDOWNLOAD_BOOST=1 \ + -DWITH_BOOST=./mysql-server/downloads/ -DWITH_UNIT_TESTS=OFF \ + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O0 -ggdb -DNDEBUG -fPIC" -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cd mysql-connector-c-8.4.0/mysql-connector-c && CC=${CC} CXX=${CXX} ${MAKE} cd mysql-connector-c-8.4.0/mysql-connector-c && cp archive_output_directory/libmysqlclient.a libmysql/ From cfd370729c6ff509ca1d1894e2876af3045c96e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Wed, 27 Aug 2025 19:05:08 +0200 Subject: [PATCH 13/23] Fix 'btree.h' compilation under GCC 15 Error was "Use of undeclared identifier 'uint16_t'". --- include/btree.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/btree.h b/include/btree.h index bb22e0cf33..fcc599e0b2 100644 --- a/include/btree.h +++ b/include/btree.h @@ -105,6 +105,7 @@ #include #include #include +#include #include #include #include From a008523fe917f4cdd6b52c3177f38469fd31d6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Wed, 27 Aug 2025 19:07:52 +0200 Subject: [PATCH 14/23] Remove unused header from 'MySQL_Set_Stmt_Parser.h' --- include/MySQL_Set_Stmt_Parser.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/MySQL_Set_Stmt_Parser.h b/include/MySQL_Set_Stmt_Parser.h index fd2e77db11..8b5b4471f3 100644 --- a/include/MySQL_Set_Stmt_Parser.h +++ b/include/MySQL_Set_Stmt_Parser.h @@ -6,7 +6,6 @@ #include #include "re2/re2.h" -#include "re2/regexp.h" //#define PARSERDEBUG From 05204671e1efab8142deb3aa0c5449196f5416c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Thu, 28 Aug 2025 13:35:55 +0200 Subject: [PATCH 15/23] Fix compilation on GCC 15 with forward declarations --- include/proxysql_glovars.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/proxysql_glovars.hpp b/include/proxysql_glovars.hpp index c5b52b2db1..18166fdca7 100644 --- a/include/proxysql_glovars.hpp +++ b/include/proxysql_glovars.hpp @@ -50,6 +50,16 @@ class ProxySQL_Checksum_Value { } }; +// Forward declarations +//////////////////////////////////////////////////////////////////////////////// + +typedef struct ssl_ctx_st SSL_CTX; +typedef struct ssl_st SSL; + +typedef struct _debug_level debug_level; + +//////////////////////////////////////////////////////////////////////////////// + class ProxySQL_GlobalVariables { public: ez::ezOptionParser *opt; From 097dad2afd332e0bd029e0b09ba6143f4487e2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Thu, 28 Aug 2025 16:24:15 +0200 Subject: [PATCH 16/23] Add initial version of SQL (MySQL) parser for SET statements - Added initial SQL parser and abstractions. - Added utilities for integration with current SET processing. - Added new value (3) for 'mysql-set_parser_algorithm'. This mode replaces the previous regex based SET parser (MySQL_Set_Stmt_Parser) in favor of the new SQL Parser. - Added example of expression verification for set statements handling 'sql_mode'. This new verification improves previous logic, and fixes previous logical failures of the parsing. There are extra TODO comments left with potential improvements for these kind of verifications in the future. --- include/MySQL_AST.h | 301 +++++ include/MySQL_Parser.h | 109 ++ include/MySQL_SET_Parser_Utils.h | 153 +++ include/MySQL_Session.h | 7 +- include/MySQL_Thread.h | 2 + include/proxysql_structs.h | 18 + include/proxysql_utils.h | 149 +++ lib/Makefile | 61 +- lib/MySQL_Lexer.l | 335 ++++++ lib/MySQL_Parser.cpp | 115 ++ lib/MySQL_Parser.y | 1871 ++++++++++++++++++++++++++++++ lib/MySQL_SET_Parser_Utils.cpp | 504 ++++++++ lib/MySQL_Session.cpp | 297 +++-- lib/MySQL_Thread.cpp | 2 +- lib/proxysql_utils.cpp | 17 + src/proxysql_global.cpp | 40 + 16 files changed, 3862 insertions(+), 119 deletions(-) create mode 100644 include/MySQL_AST.h create mode 100644 include/MySQL_Parser.h create mode 100644 include/MySQL_SET_Parser_Utils.h create mode 100644 lib/MySQL_Lexer.l create mode 100644 lib/MySQL_Parser.cpp create mode 100644 lib/MySQL_Parser.y create mode 100644 lib/MySQL_SET_Parser_Utils.cpp diff --git a/include/MySQL_AST.h b/include/MySQL_AST.h new file mode 100644 index 0000000000..4591f11abc --- /dev/null +++ b/include/MySQL_AST.h @@ -0,0 +1,301 @@ +#ifndef MYSQL_PARSER_AST_H +#define MYSQL_PARSER_AST_H + +#include +#include +#include + +namespace MySQLParser { + +// Enum for Abstract Syntax Tree Node Types +enum class NodeType { + NODE_UNKNOWN, + NODE_COMMAND, // General command like QUIT + NODE_SELECT_STATEMENT, + NODE_INSERT_STATEMENT, + NODE_DELETE_STATEMENT, + NODE_IDENTIFIER, + NODE_STRING_LITERAL, + NODE_NUMBER_LITERAL, // For numeric values + NODE_BOOLEAN_LITERAL, // For boolean values + NODE_NULL_LITERAL, // For NULL literal + NODE_VALUE_LITERAL, // For values with no type; options like 'ON' + NODE_TIMESTAMP, // For dates + NODE_INTERVAL, // For dates + NODE_ASTERISK, // For '*' in SELECT + NODE_SET_STATEMENT, + NODE_SET_OPTION_VALUE_LIST, + NODE_VARIABLE_ASSIGNMENT, + NODE_USER_VARIABLE, // e.g., @my_var + NODE_SYSTEM_VARIABLE, // e.g., @@global.var + NODE_VARIABLE_SCOPE, // GLOBAL, SESSION, PERSIST, etc. + NODE_EXPR, // Placeholder for more complex expressions (and functions) + NODE_SIMPLE_EXPRESSION, // More specific expression type + NODE_INTERVAL_EXPRESSION, // More specific expression type + NODE_AGGREGATE_FUNCTION_CALL, // For COUNT, SUM, AVG etc. + NODE_SET_NAMES, + NODE_SET_CHARSET, + NODE_DELETE_OPTIONS, // LOW_PRIORITY, QUICK, IGNORE for DELETE + NODE_TABLE_NAME_LIST, // For multi-table DELETE or other lists of tables + NODE_FROM_CLAUSE, + NODE_USING_CLAUSE, // For JOIN ... USING (...) + NODE_WHERE_CLAUSE, + NODE_HAVING_CLAUSE, // Added for HAVING + NODE_ORDER_BY_CLAUSE, + NODE_ORDER_BY_ITEM, + NODE_LIMIT_CLAUSE, + NODE_ESCAPE_CLAUSE, + NODE_COMPARISON_EXPRESSION, // e.g., col = 5 + NODE_LOGICAL_AND_EXPRESSION, // For AND operator + NODE_OPERATOR, // e.g., =, <, +, -, JOIN type strings + NODE_LEFT_SHIFT_OPERATOR, // e.g., << + NODE_RIGHT_SHIFT_OPERATOR, // e.g., >> + NODE_QUALIFIED_IDENTIFIER, // e.g., table.column + + // For SELECT specific parts + NODE_SELECT_OPTIONS, // DISTINCT, SQL_CALC_FOUND_ROWS etc. + NODE_SELECT_ITEM_LIST, // List of expressions/columns in SELECT + NODE_SELECT_ITEM, // A single item in the SELECT list + NODE_SELECT_RAW_SUBQUERY, // Subquery parsing placeholder + NODE_ALIAS, // For 'AS alias_name' + NODE_TABLE_REFERENCE, // Reference to a table (name, derived, join result) + NODE_GROUP_BY_CLAUSE, + NODE_GROUPING_ELEMENT, // Item in GROUP BY + + // For JOIN clauses + NODE_JOIN_CLAUSE, // Represents a join operation (e.g., t1 JOIN t2) + NODE_JOIN_TYPE_NATURAL_SPEC,// For 'NATURAL [LEFT|RIGHT|INNER] JOIN' specifier + NODE_JOIN_CONDITION_ON, // ON + NODE_JOIN_CONDITION_USING, // USING (col1, col2) + NODE_COLUMN_LIST, // For USING (col_list) or INTO (var_list) + + // Nodes for INTO, LOCKING, DERIVED TABLES + NODE_INTO_CLAUSE, // Wrapper for INTO ... variants + NODE_INTO_VAR_LIST, // INTO @var1, @var2 + NODE_INTO_OUTFILE, // INTO OUTFILE 'filename' [options] + NODE_INTO_DUMPFILE, // INTO DUMPFILE 'filename' + NODE_LOCKING_CLAUSE_LIST, // Wrapper for one or more locking clauses + NODE_LOCKING_CLAUSE, // FOR UPDATE | FOR SHARE + NODE_LOCK_STRENGTH, // Stores "UPDATE" or "SHARE" + NODE_LOCK_TABLE_LIST, // Optional 'OF table_list' for locking + NODE_LOCK_OPTION, // Optional 'NOWAIT' or 'SKIP LOCKED' + NODE_DERIVED_TABLE, // Represents (SELECT ...) AS alias + NODE_SUBQUERY, // The (SELECT ...) part of a derived table or sub-expression + + // For INTO OUTFILE options + NODE_FILE_OPTIONS, // Wrapper for all file format options + NODE_FIELDS_OPTIONS_CLAUSE, // Wrapper for FIELDS related options + NODE_LINES_OPTIONS_CLAUSE, // Wrapper for LINES related options + NODE_FIELDS_TERMINATED_BY, + NODE_FIELDS_ENCLOSED_BY, + NODE_FIELDS_OPTIONALLY_ENCLOSED_BY, + NODE_FIELDS_ESCAPED_BY, + NODE_LINES_STARTING_BY, + NODE_LINES_TERMINATED_BY, + NODE_CHARSET_OPTION, // For CHARACTER SET 'name' in OUTFILE + + NODE_KEYWORD, // For storing keywords like ALL, DISTINCT (as value) in some contexts + + // Added for SHOW, BEGIN, COMMIT + NODE_SHOW_STATEMENT, + NODE_BEGIN_STATEMENT, + NODE_COMMIT_STATEMENT, + NODE_SHOW_OPTION_FULL, // For SHOW FULL ... + NODE_SHOW_OPTION_FIELDS, // For SHOW ... FIELDS + NODE_SHOW_TARGET_DATABASES, // For SHOW DATABASES + NODE_TABLE_SPECIFICATION, // For FROM table_name in SHOW FIELDS + + // Added for IS NULL / IS NOT NULL + NODE_IS_NULL_EXPRESSION, + NODE_IS_NOT_NULL_EXPRESSION +}; + +struct AstNode; + +inline void print_ast(const AstNode* node, int indent = 0); + +/** + * @brief Structure for an Abstract Syntax Tree (AST) Node. + * @details Represents a node in the AST, storing its type, value, children, and position information. + */ +struct AstNode { + /** + * @brief The type of the AST node. + */ + NodeType type; + /** + * @brief The value of the AST node. + * @details Identifier name, literal value, operator type, etc. + */ + std::string value; + /** + * @brief The child nodes of this AST node. + */ + std::vector children; + /** + * @brief The starting position of the value in the source code. + */ + size_t val_init_pos { 0 }; + /** + * @brief The ending position of the value in the source code. + */ + size_t val_end_pos { 0 }; + /** + * @brief Constructor for AstNode. + * @param t The type of the node. + * @param val The value of the node (default: ""). + */ + AstNode(NodeType t, const std::string& val = "") : type(t), value(val) {} + /** + * @brief Move constructor for value. + * @param t The type of the node. + * @param val The value of the node (rvalue reference). + */ + AstNode(NodeType t, std::string&& val) : type(t), value(std::move(val)) {} + /** + * @brief Destructor. + * @details Iterates through the childs, freeing resources. + */ + ~AstNode() { + for (AstNode* child : children) { + delete child; + } + } + /** + * @brief Deleted copy constructor to prevent implicit copying. + */ + AstNode(const AstNode&) = delete; + /** + * @brief Deleted copy assignment operator to prevent implicit copying. + */ + AstNode& operator=(const AstNode&) = delete; + /** + * @brief Deleted move constructor. + */ + AstNode(AstNode&&) = delete; + /** + * @brief Deleted move assignment operator. + */ + AstNode& operator=(AstNode&&) = delete; + /** + * @brief Adds a child node to the current node. + * @param child Pointer to the child node to be added. If the pointer is null, the child is not added. + */ + void add_child(AstNode* child) { + if (child) { + children.push_back(child); + } + } +}; + +inline std::string to_string(NodeType t) { + if (t == NodeType::NODE_UNKNOWN) { return "UNKNOWN"; } + else if (t == NodeType::NODE_COMMAND) { return "COMMAND"; } + else if (t == NodeType::NODE_SELECT_STATEMENT) { return "SELECT_STMT"; } + else if (t == NodeType::NODE_INSERT_STATEMENT) { return "INSERT_STMT"; } + else if (t == NodeType::NODE_DELETE_STATEMENT) { return "DELETE_STMT"; } + else if (t == NodeType::NODE_IDENTIFIER) { return "IDENTIFIER"; } + else if (t == NodeType::NODE_STRING_LITERAL) { return "STRING_LITERAL"; } + else if (t == NodeType::NODE_NUMBER_LITERAL) { return "NUMBER_LITERAL"; } + else if (t == NodeType::NODE_BOOLEAN_LITERAL) { return "BOOLEAN_LITERAL"; } + else if (t == NodeType::NODE_NULL_LITERAL) { return "NULL_LITERAL"; } + else if (t == NodeType::NODE_VALUE_LITERAL) { return "VALUE_LITERAL"; } + else if (t == NodeType::NODE_TIMESTAMP) { return "TIMESTAMP"; } + else if (t == NodeType::NODE_INTERVAL) { return "INTERVAL"; } + else if (t == NodeType::NODE_ASTERISK) { return "ASTERISK"; } + else if (t == NodeType::NODE_SET_STATEMENT) { return "SET_STATEMENT"; } + else if (t == NodeType::NODE_VARIABLE_ASSIGNMENT) { return "VAR_ASSIGN"; } + else if (t == NodeType::NODE_SET_OPTION_VALUE_LIST) { return "SET_OPTION_VALUE_LIST"; } + else if (t == NodeType::NODE_USER_VARIABLE) { return "USER_VAR"; } + else if (t == NodeType::NODE_SYSTEM_VARIABLE) { return "SYSTEM_VAR"; } + else if (t == NodeType::NODE_VARIABLE_SCOPE) { return "VAR_SCOPE"; } + else if (t == NodeType::NODE_EXPR) { return "EXPR"; } + else if (t == NodeType::NODE_SIMPLE_EXPRESSION) { return "SIMPLE_EXPRESSION"; } + else if (t == NodeType::NODE_INTERVAL_EXPRESSION) { return "INTERVAL_EXPRESSION"; } + else if (t == NodeType::NODE_AGGREGATE_FUNCTION_CALL) { return "AGGREGATE_FUNC_CALL"; } + else if (t == NodeType::NODE_SET_NAMES) { return "SET_NAMES"; } + else if (t == NodeType::NODE_SET_CHARSET) { return "SET_CHARSET"; } + else if (t == NodeType::NODE_DELETE_OPTIONS) { return "DELETE_OPTIONS"; } + else if (t == NodeType::NODE_TABLE_NAME_LIST) { return "TABLE_NAME_LIST"; } + else if (t == NodeType::NODE_FROM_CLAUSE) { return "FROM_CLAUSE"; } + else if (t == NodeType::NODE_USING_CLAUSE) { return "USING_CLAUSE"; } + else if (t == NodeType::NODE_WHERE_CLAUSE) { return "WHERE_CLAUSE"; } + else if (t == NodeType::NODE_HAVING_CLAUSE) { return "HAVING_CLAUSE"; } + else if (t == NodeType::NODE_ORDER_BY_CLAUSE) { return "ORDER_BY_CLAUSE"; } + else if (t == NodeType::NODE_ORDER_BY_ITEM) { return "ORDER_BY_ITEM"; } + else if (t == NodeType::NODE_LIMIT_CLAUSE) { return "LIMIT_CLAUSE"; } + else if (t == NodeType::NODE_ESCAPE_CLAUSE) { return "ESCAPE_CLAUSE"; } + else if (t == NodeType::NODE_COMPARISON_EXPRESSION) { return "COMPARISON_EXPR"; } + else if (t == NodeType::NODE_LOGICAL_AND_EXPRESSION) { return "LOGICAL_AND_EXPR"; } + else if (t == NodeType::NODE_OPERATOR) { return "OPERATOR"; } + else if (t == NodeType::NODE_QUALIFIED_IDENTIFIER) { return "QUALIFIED_IDENTIFIER"; } + else if (t == NodeType::NODE_SELECT_OPTIONS) { return "SELECT_OPTIONS"; } + else if (t == NodeType::NODE_SELECT_ITEM_LIST) { return "SELECT_ITEM_LIST"; } + else if (t == NodeType::NODE_SELECT_ITEM) { return "SELECT_ITEM"; } + else if (t == NodeType::NODE_SELECT_RAW_SUBQUERY) { return "NODE_SELECT_RAW_SUBQUERY"; } + else if (t == NodeType::NODE_ALIAS) { return "ALIAS"; } + else if (t == NodeType::NODE_TABLE_REFERENCE) { return "TABLE_REFERENCE"; } + else if (t == NodeType::NODE_GROUP_BY_CLAUSE) { return "GROUP_BY_CLAUSE"; } + else if (t == NodeType::NODE_GROUPING_ELEMENT) { return "GROUPING_ELEMENT"; } + else if (t == NodeType::NODE_JOIN_CLAUSE) { return "JOIN_CLAUSE"; } + else if (t == NodeType::NODE_JOIN_TYPE_NATURAL_SPEC) { return "JOIN_TYPE_NATURAL_SPEC"; } + else if (t == NodeType::NODE_JOIN_CONDITION_ON) { return "JOIN_CONDITION_ON"; } + else if (t == NodeType::NODE_JOIN_CONDITION_USING) { return "JOIN_CONDITION_USING"; } + else if (t == NodeType::NODE_COLUMN_LIST) { return "COLUMN_LIST"; } + else if (t == NodeType::NODE_INTO_CLAUSE) { return "INTO_CLAUSE"; } + else if (t == NodeType::NODE_INTO_VAR_LIST) { return "INTO_VAR_LIST"; } + else if (t == NodeType::NODE_INTO_OUTFILE) { return "INTO_OUTFILE"; } + else if (t == NodeType::NODE_INTO_DUMPFILE) { return "INTO_DUMPFILE"; } + else if (t == NodeType::NODE_LOCKING_CLAUSE_LIST) { return "LOCKING_CLAUSE_LIST"; } + else if (t == NodeType::NODE_LOCKING_CLAUSE) { return "LOCKING_CLAUSE"; } + else if (t == NodeType::NODE_LOCK_STRENGTH) { return "LOCK_STRENGTH"; } + else if (t == NodeType::NODE_LOCK_TABLE_LIST) { return "LOCK_TABLE_LIST"; } + else if (t == NodeType::NODE_LOCK_OPTION) { return "LOCK_OPTION"; } + else if (t == NodeType::NODE_DERIVED_TABLE) { return "DERIVED_TABLE"; } + else if (t == NodeType::NODE_SUBQUERY) { return "SUBQUERY"; } + else if (t == NodeType::NODE_FILE_OPTIONS) { return "FILE_OPTIONS"; } + else if (t == NodeType::NODE_FIELDS_OPTIONS_CLAUSE) { return "FIELDS_OPTIONS_CLAUSE"; } + else if (t == NodeType::NODE_LINES_OPTIONS_CLAUSE) { return "LINES_OPTIONS_CLAUSE"; } + else if (t == NodeType::NODE_FIELDS_TERMINATED_BY) { return "FIELDS_TERMINATED_BY"; } + else if (t == NodeType::NODE_FIELDS_ENCLOSED_BY) { return "FIELDS_ENCLOSED_BY"; } + else if (t == NodeType::NODE_FIELDS_OPTIONALLY_ENCLOSED_BY) { return "FIELDS_OPTIONALLY_ENCLOSED_BY"; } + else if (t == NodeType::NODE_FIELDS_ESCAPED_BY) { return "FIELDS_ESCAPED_BY"; } + else if (t == NodeType::NODE_LINES_STARTING_BY) { return "LINES_STARTING_BY"; } + else if (t == NodeType::NODE_LINES_TERMINATED_BY) { return "LINES_TERMINATED_BY"; } + else if (t == NodeType::NODE_CHARSET_OPTION) { return "CHARSET_OPTION"; } + else if (t == NodeType::NODE_KEYWORD) { return "KEYWORD"; } + else if (t == NodeType::NODE_SHOW_STATEMENT) { return "SHOW_STMT"; } + else if (t == NodeType::NODE_BEGIN_STATEMENT) { return "BEGIN_STMT"; } + else if (t == NodeType::NODE_COMMIT_STATEMENT) { return "COMMIT_STMT"; } + else if (t == NodeType::NODE_SHOW_OPTION_FULL) { return "SHOW_OPT_FULL"; } + else if (t == NodeType::NODE_SHOW_OPTION_FIELDS) { return "SHOW_OPT_FIELDS"; } + else if (t == NodeType::NODE_SHOW_TARGET_DATABASES) { return "SHOW_TARGET_DB"; } + else if (t == NodeType::NODE_TABLE_SPECIFICATION) { return "TABLE_SPEC"; } + else if (t == NodeType::NODE_IS_NULL_EXPRESSION) { return "IS_NULL_EXPR"; } + else if (t == NodeType::NODE_IS_NOT_NULL_EXPRESSION) { return "IS_NOT_NULL_EXPR"; } + else { + return "UNHANDLED_TYPE(" + std::to_string(static_cast(t)) + ")"; + } +} + +// Helper function to print the AST (for debugging) +inline void print_ast(const AstNode* node, int indent) { + if (!node) return; + + for (int i = 0; i < indent; ++i) std::cout << " "; + + std::cout << "Type: " << to_string(node->type); + if (!node->value.empty()) { + std::cout << ", Value: '" << node->value << "'"; + } + std::cout << std::endl; + + for (const AstNode* child : node->children) { + print_ast(child, indent + 1); + } +} + +} // namespace MySQLParser + +#endif // MYSQL_PARSER_AST_H + diff --git a/include/MySQL_Parser.h b/include/MySQL_Parser.h new file mode 100644 index 0000000000..a572301f3e --- /dev/null +++ b/include/MySQL_Parser.h @@ -0,0 +1,109 @@ +#ifndef MYSQL_PARSER_PARSER_H +#define MYSQL_PARSER_PARSER_H + +#include "MySQL_AST.h" // Uses MySQLParser::AstNode +#include +#include +#include + +/** + * @brief Opaque type for Flex holding the scanner state + */ +typedef void* yyscan_t; + +namespace MySQLParser { + +/** + * @class Parser + * @brief Parses SQL queries and generates an Abstract Syntax Tree (AST). + * @details Uses Flex and Bison to tokenize and parse SQL queries. The class itself acts as a + * closure, holding the internal parser state and error reporting. This state is shared with the + * Bison parser through `this` pointer. + */ +class Parser { +public: + /** + * @brief Constructor for the Parser class. + * @details Initializes the Flex scanner. + * @throws std::runtime_error On scanner initialization fails. + */ + Parser(); + /** + * @brief Destructor for the Parser class. + * @details Cleanups Flex scanner internal state. + */ + ~Parser(); + /** + * @brief Parses an SQL query string. + * @param sql_query The SQL query string to parse. + * @return Root node of the generated AST, or nullptr on failure. + */ + std::unique_ptr parse(const std::string& sql_query); + /** + * @brief Retrieves the list of errors encountered during parsing. + * @return A constant reference to the vector of error messages. + */ + const std::vector& get_errors() const; + /** + * @brief Clears the list of errors. + */ + void clear_errors(); + + /** + * @brief Internal method used by Bison to set the root of the AST. + * @details Called by the Bison-generated parsing code to set the root + * of the Abstract Syntax Tree (AST) after a successful parse. + * @param root The root AstNode of the AST. Parser takes ownership. + */ + void internal_set_ast(AstNode* root); + /** + * @brief Internal method used by Flex/Bison to add a generic error message. + * @param msg The error message to add. + */ + void internal_add_error(const std::string& msg); + /** + * @brief Internal method used by Flex/Bison to add an error message with line and column information. + * @param msg The error message to add. + * @param line The line number where the error occurred. + * @param column The column number where the error occurred. + */ + void internal_add_error_at(const std::string& msg, int line, int column); + +private: + /** + * @brief The root node of the Abstract Syntax Tree (AST). + */ + std::unique_ptr ast_root_; + /** + * @brief Vector with the error messages encountered during parsing. + */ + std::vector errors_; + /** + * @brief The Flex scanner state. + */ + yyscan_t scanner_state_; +}; + +} // namespace MySQLParser + +struct MYSQL_YYLTYPE; + +/** + * @brief Declaration for mysql_yyerror, called by Bison's mysql_yyparse. + * @param yyscanner The scanner state. + * @param parser_context The parser context. + * @param msg The error message. + */ +void mysql_yyerror(yyscan_t yyscanner, MySQLParser::Parser* parser_context, const char* msg); +/** + * @brief Overload for mysql_yyerror, including an extra parameter for location tracking. + * @param yyloc The location of the token where the error occurred, provided by the lexer. + * @param yyscanner The scanner state. + * @param parser_context The parser context. + * @param msg The error message. + */ +void mysql_yyerror( + MYSQL_YYLTYPE* yyloc, yyscan_t yyscanner, MySQLParser::Parser* parser_context, const char* msg +); + +#endif // MYSQL_PARSER_PARSER_H diff --git a/include/MySQL_SET_Parser_Utils.h b/include/MySQL_SET_Parser_Utils.h new file mode 100644 index 0000000000..1232fc7f2f --- /dev/null +++ b/include/MySQL_SET_Parser_Utils.h @@ -0,0 +1,153 @@ +#ifndef MYSQL_SET_PARSER_UTILS_H +#define MYSQL_SET_PARSER_UTILS_H + +#include "MySQL_AST.h" + +#include + +/** + * @brief Map where the key is the variable name and the value is a vector of strings representing the + * assigned values for that variable. + */ +using var_map_t = std::map>>; + +/** + * @brief Extracts the AST nodes corresponding to variable assignments from a SQL SET statement's AST. + * @details This function performs a breadth-first traversal of the Abstract Syntax Tree (AST) rooted at + * `root` to identify and extract all nodes representing variable assignments (NODE_VARIABLE_ASSIGNMENT). It + * prunes the search space by considering the depth of the nodes. Once the first variable assignment node is + * found, subsequent nodes at the same depth are also added to the result. Deeper nodes are ignored, and + * shallower nodes terminate the search. + * + * @param root A pointer to the root node of the AST. If `root` is `nullptr`, an empty vector is returned. + * @return A vector containing pointers to the AST nodes of type `NODE_VARIABLE_ASSIGNMENT` that represent + * variable assignments within the SQL SET statement. Returns an empty vector if no such nodes are found, + * or if the input `root` is `nullptr`. + */ +std::vector ext_vars_assigns(const MySQLParser::AstNode* root); +/** + * @brief Extracts variable assignments and maps them to their corresponding values from a SQL SET + * statement's AST. + * @details This function leverages the `ext_vars_assigns` function to identify variable assignment nodes + * within the AST and then extracts the variable name and assigned value for each assignment. + * + * @param root A pointer to the root node of the AST. If `root` is `nullptr`, an empty map is returned. + * @param q The original SQL query string from which the AST was generated. Used to extract the values. + * @return A map where the key is the variable name (string) and the value is a vector of strings + * representing the assigned values for that variable. Returns an empty map if no variable assignments are + * found or if the input `root` is `nullptr`. + */ +var_map_t ext_vars_assigns_map(const MySQLParser::AstNode* root, const std::string& q); + +/** + * @brief Helper type that holds an RC and an extra value. + * @details The kind of the contained object is { error_code, value }: + * - { rc, {} }: When holding an error, and empty (default constructed) value. + * - { 0, val }: On succeed operation. + */ +template +using rc_t = std::pair; +/** + * @brief Helper type used to specify a child type and expected index in the AST tree. + * @details The first element of the pair is the expected `NodeType` of the child, and the second element is + * the index of the child within the parent's `children` vector. + */ +using child_idx_t = std::pair; +/** + * @brief Retrieves a node from the AST based on a provided path. + * @details Traverses the Abstract Syntax Tree (AST) from a given root node, following a specified path of + * child indices. It checks the node type at each step against the expected type in the path. + * + * @param root A pointer to the root node of the AST to traverse. + * @param c_path A vector of child_idx_t, where each pair represents a child index to follow. + * + * @return A `rc_t`: + * - The first element of the pair is an integer return code, `0` on success, `-1` otherwise. + * - The second element of the pair is a pointer to the `AstNode` where the traversal ended, either the + * target node or the node where an error occurred. + * + * @details The function iterates through the `c_path` vector. For each `c_idx` in the path: + * 1. It checks if the current node has children and if the child index `c_idx.second` is within the bounds + * of the `children` vector. + * 2. If the index is valid, it updates `cur_node` to point to the child node. + * 3. It then checks the `NodeType` of the child. + * - If the expected `NodeType` is `NODE_UNKNOWN`, the check is skipped, and traversal continues. + * - Otherwise, it compares the `type` of the current node with the expected `NodeType` `c_idx.first`. + * If they don't match, it returns an error code of `-1` along with the current node. + * 4. If the index is invalid (either no children or index out of bounds), it returns an error code of `-1` + * along with the current node. + * If the entire path is traversed successfully, the function returns a success code of `0` along with the + * final `cur_node`. + */ +rc_t get_node( + const MySQLParser::AstNode* root, const std::vector& c_path +); +/** + * @brief Checks if a given AST node matches a specific pattern related to SET statements. + * @details Hanldes both `NODE_SET_STATEMENT` and `NODE_SET_NAMES` node types. This implementation + * serves as an equivalent to a previous regex-based approach (`match_regexes[1]`): + * - `NODE_SET_STATEMENT`: Verifies that the statement contains variable assignments, that each assigned + * variable is a tracked system variable (or "autocommit"), and that the system variable is present in + * the `tracked_vars` list. + * - `NODE_SET_NAMES`: Returns `true`, expected to be verified later. + * - Other node type: Returns `false`. + * @param node A pointer to the AST node to check. + * @return `true` if the node matches the expected pattern, `false` otherwise. + */ +bool p_match_regex_1(const MySQLParser::AstNode* node); +/** + * @brief Checks if a given AST node matches a specific pattern related to transaction SET statements. + * @details Handles `NODE_SET_STATEMENT` node types. This implementation + * serves as an equivalent to a previous regex-based approach (`match_regexes[2]`): + * - `NODE_SET_STATEMENT`: Verifies that the node's value is either "SET_SESSION_TRANSACTION" or + * "SET_TRANSACTION". + * - Other node type: Returns `false`. + * @param node A pointer to the AST node to check. + * @return `true` if the node matches the expected pattern, `false` otherwise. + */ +bool p_match_regex_2(const MySQLParser::AstNode* node); +/** + * @brief Checks if a given AST node matches a specific pattern related to SET CHARSET statements. + * @details Handles `NODE_SET_CHARSET` node types. This implementation + * serves as an equivalent to a previous regex-based approach (`match_regexes[3]`): + * - `NODE_SET_CHARSET`: Returns `true`. + * - Other node type: Returns `false`. + * @param node A pointer to the AST node to check. + * @return `true` if the node matches the expected pattern, `false` otherwise. + */ +bool p_match_regex_3(const MySQLParser::AstNode* node); +/** + * @brief Type used for improved error reporting for AST based validation. + * @details When returning an AST error message, it's expected to. + */ +struct perr_t { + /// Return code used for error identification. + int rc { 0 }; + /// Error message to report to the caller. + std::string msg {}; + /// Chain of conditions, or sub-errors, that add context to the error. + std::vector ctx {}; +}; + +/** + * @brief Verifies recurring simple expressions. + * @details The allowed expressions kinds are: + * + * - STRING_LITERAL + * - SYSTEM_VAR + * - EXPR + * |-- FUNCTION CALL EXPRS, eg: 'REPLACE(@@sql_mode, 'STRICT_ALL_TABLES', 'STRICT_TRANS_TABLES')' + * |-- STRING_LITERAL + * |-- SYSTEM_VAR (SQL_MODE), eg: 'CONCAT(@@sql_mode, LITERAL)' + * `-- SELECT_SUBQUERY, of kind '(SELECT STRING_LITERAL)' + * - (SELECT EXPR) - Previously defined 'EXPR' + * + * These definitions allows recursion, but only through the EXPR. Allowing generic recursion for + * '(SELECT EXPR)' was out of the scope. This can be enabled in the future. + * @param n The node from which to start the expression verification. + * @param offset Offset of the original query at which AST represented by 'n' is found. + * @return A pair of kind { success, error_message }. + */ +perr_t verf_sql_mode_val(const MySQLParser::AstNode* n, const std::string& v, const std::string& q); + +#endif // MYSQL_SET_PARSER_UTILS_H diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h index 8474499fc4..69bc9761f9 100644 --- a/include/MySQL_Session.h +++ b/include/MySQL_Session.h @@ -150,6 +150,11 @@ class MySQL_Session: public Base_Session& e, + const std::string& q + ); void handler___client_DSS_QUERY_SENT___server_DSS_NOT_INITIALIZED__get_connection(); @@ -437,7 +442,7 @@ class MySQL_Session: public Base_Session +#include +#include +#include +#include + #ifdef max_allowed_packet #undef max_allowed_packet #endif @@ -1793,9 +1799,21 @@ mysql_variable_st mysql_tracked_variables[] { */ }; +/** + * @brief Holds an sorted vector (s_vector) of the variable names being tracked. + * @details This ordered vector is used for set statement matches by `p_match_regex_1`. + * It's always defined as 'extern' in headers, symbol is defined in 'proxysql_global.cpp'. + */ +extern const s_vector tracked_vars; #else extern mysql_variable_st mysql_tracked_variables[]; extern var_track_err_st perm_track_errs[]; +/** + * @brief Holds an sorted vector (s_vector) of the variable names being tracked. + * @details This ordered vector is used for set statement matches by `p_match_regex_1`. + * It's always defined as 'extern' in headers, symbol is defined in 'proxysql_global.cpp'. + */ +extern const s_vector tracked_vars; #endif // PROXYSQL_EXTERN #endif // MYSQL_TRACKED_VARIABLES diff --git a/include/proxysql_utils.h b/include/proxysql_utils.h index df8e13600b..87a712408c 100644 --- a/include/proxysql_utils.h +++ b/include/proxysql_utils.h @@ -2,6 +2,7 @@ #define __PROXYSQL_UTILS_H #include +#include #include #include #include @@ -141,6 +142,82 @@ cfmt_t cstr_format(char (&out_buf)[N], const char* fmt, ...) { } } +template +struct rm_cvref +{ + using type = std::remove_cv_t>; +}; + +template< class T > +using rm_cvref_t = typename rm_cvref::type; + +template +struct _h_fold : _h_fold +{}; + +/** + * @brief Helper type for 'fold', responsible for performing the type deduction. + * @tparam C Inferred type for the lambda, class or function object. + * @tparam R The return type of the function object. + * @tparam B The second parameter type (accumulator) of the function object. + * @tparam A The first parameter type (range value) of the function object. + */ +template +struct _h_fold +{ + template