From 49592b4bdfe46782782e31f98a34470703fce26a Mon Sep 17 00:00:00 2001 From: elianddb Date: Fri, 10 Oct 2025 09:47:33 -0700 Subject: [PATCH 01/14] docker process --- .../actions/mysql-client-tests/.dockerignore | 4 ++ .github/actions/mysql-client-tests/Dockerfile | 60 +++++++++++++++++++ .../mysql-client-tests/c/CMakeLists.txt | 5 ++ .../c/mysql-connector-c-test.c | 2 +- .../mysql-client-tests/c/vcpkg.json | 4 ++ .../dotnet/MySqlClient/dotnet.csproj | 3 + .../MySqlConnector/MySqlConnectorTest.csproj | 3 + .../mysql-client-tests/rust/Cargo.toml | 2 +- 8 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 .github/actions/mysql-client-tests/.dockerignore create mode 100644 .github/actions/mysql-client-tests/Dockerfile create mode 100644 integration-tests/mysql-client-tests/c/CMakeLists.txt create mode 100644 integration-tests/mysql-client-tests/c/vcpkg.json diff --git a/.github/actions/mysql-client-tests/.dockerignore b/.github/actions/mysql-client-tests/.dockerignore new file mode 100644 index 0000000000..aaa83ccc43 --- /dev/null +++ b/.github/actions/mysql-client-tests/.dockerignore @@ -0,0 +1,4 @@ +**/.git +**/.github +**/docker/ +**/images/ \ No newline at end of file diff --git a/.github/actions/mysql-client-tests/Dockerfile b/.github/actions/mysql-client-tests/Dockerfile new file mode 100644 index 0000000000..e80eb0c625 --- /dev/null +++ b/.github/actions/mysql-client-tests/Dockerfile @@ -0,0 +1,60 @@ +# syntax=docker/dockerfile:1 +FROM golang:1.25-alpine AS golang_cgo125 +ENV CGO_ENABLED=1 +ENV GO_LDFLAGS="-linkmode external -extldflags '-static'" +RUN apk add --no-cache build-base + + +FROM golang_cgo125 AS dolt_build +COPY dolt/go/go.mod /build/dolt/go/ +COPY go-mysql-server*/ /build/go-mysql-server/ +COPY vitess*/ /build/vitess/ +WORKDIR /build/dolt/go/ +RUN go mod download +RUN apk add --no-cache icu-dev icu-static +COPY dolt/go/ /build/dolt/go/ +RUN go build -tags icu_static -o /build/bin/dolt ./cmd/dolt + + +FROM golang_cgo125 AS go_clients_build +COPY dolt/integration-tests/mysql-client-tests/go /build/go/ +WORKDIR /build/go/ +RUN go build -o /build/bin/go-mysql-client-test + +COPY dolt/integration-tests/mysql-client-tests/go-mysql/ /build/go-mysql/ +WORKDIR /build/go-mysql/ +RUN go build -o /build/bin/go-sql-driver-test + + +FROM rust:1.90-alpine3.22 AS rust_clients_build +COPY dolt/integration-tests/mysql-client-tests/rust/ /build/rust/ +WORKDIR /build/rust/ +RUN apk add --no-cache musl-dev +RUN cargo build --release --target-dir /build/bin/ # exe is in release/ + + +FROM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim AS dotnet_clients_build +COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlClient/ /build/dotnet/MySqlClient/ +WORKDIR /build/dotnet/MySqlClient/ +RUN dotnet publish -c Release -o /build/bin + +COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlConnector/ /build/dotnet/MySqlConnector/ +WORKDIR /build/dotnet/MySqlConnector/ +RUN dotnet publish -c Release -o /build/bin + + +FROM mcr.microsoft.com/devcontainers/cpp:1-bookworm AS c_clients_build +COPY dolt/integration-tests/mysql-client-tests/c/vcpkg.json /build/c/vcpkg.json +WORKDIR /build/c/ +RUN vcpkg install --triplet=x64-linux-release +COPY dolt/integration-tests/mysql-client-tests/c/ /build/c/ +ENV CMAKE_TOOLCHAIN_FILE=/usr/local/vcpkg/scripts/buildsystems/vcpkg.cmake +RUN cmake -B build -S . +RUN cmake --build build + + + + + + + diff --git a/integration-tests/mysql-client-tests/c/CMakeLists.txt b/integration-tests/mysql-client-tests/c/CMakeLists.txt new file mode 100644 index 0000000000..3128143819 --- /dev/null +++ b/integration-tests/mysql-client-tests/c/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.24) +project(c_mysql_client_test C) +find_package(unofficial-libmysql REQUIRED) +add_executable("c-mysql-client-test" "mysql-connector-c-test.c") +target_link_libraries("c-mysql-client-test" PRIVATE unofficial::libmysql::libmysql stdc++) diff --git a/integration-tests/mysql-client-tests/c/mysql-connector-c-test.c b/integration-tests/mysql-client-tests/c/mysql-connector-c-test.c index 98a1a4fd4f..0731abd20c 100644 --- a/integration-tests/mysql-client-tests/c/mysql-connector-c-test.c +++ b/integration-tests/mysql-client-tests/c/mysql-connector-c-test.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #define QUERIES_SIZE 14 diff --git a/integration-tests/mysql-client-tests/c/vcpkg.json b/integration-tests/mysql-client-tests/c/vcpkg.json new file mode 100644 index 0000000000..52bf7048e7 --- /dev/null +++ b/integration-tests/mysql-client-tests/c/vcpkg.json @@ -0,0 +1,4 @@ +{ + "name": "mysql-client-test-c", + "dependencies": [ "libmysql" ] +} diff --git a/integration-tests/mysql-client-tests/dotnet/MySqlClient/dotnet.csproj b/integration-tests/mysql-client-tests/dotnet/MySqlClient/dotnet.csproj index f06a4d0402..c73549a89f 100644 --- a/integration-tests/mysql-client-tests/dotnet/MySqlClient/dotnet.csproj +++ b/integration-tests/mysql-client-tests/dotnet/MySqlClient/dotnet.csproj @@ -3,6 +3,9 @@ Exe net8.0 + dotnet-mysql-client-test + true + true diff --git a/integration-tests/mysql-client-tests/dotnet/MySqlConnector/MySqlConnectorTest.csproj b/integration-tests/mysql-client-tests/dotnet/MySqlConnector/MySqlConnectorTest.csproj index 71de47491f..dcb8f7feb4 100755 --- a/integration-tests/mysql-client-tests/dotnet/MySqlConnector/MySqlConnectorTest.csproj +++ b/integration-tests/mysql-client-tests/dotnet/MySqlConnector/MySqlConnectorTest.csproj @@ -3,6 +3,9 @@ Exe net8.0 + dotnet-mysql-connector-test + true + true diff --git a/integration-tests/mysql-client-tests/rust/Cargo.toml b/integration-tests/mysql-client-tests/rust/Cargo.toml index 0a26070a76..3bc2047e78 100644 --- a/integration-tests/mysql-client-tests/rust/Cargo.toml +++ b/integration-tests/mysql-client-tests/rust/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" mysql = "*" [[bin]] -name = "mysql_connector_test" +name = "rust-mysql-client-test" path = "src/mysql_connector_test.rs" From c38d3827c19a2385af63c0f223cb10a55f8e872c Mon Sep 17 00:00:00 2001 From: elianddb Date: Sat, 11 Oct 2025 21:41:00 -0700 Subject: [PATCH 02/14] amend Dockerfile to embed interpreters from diff build stages # Conflicts: # go/cmd/dolt/doltversion/version.go # go/go.mod # go/go.sum --- .../actions/mysql-client-tests/.dockerignore | 4 - .github/actions/mysql-client-tests/Dockerfile | 108 +++++- .../Dockerfile.dockerignore | 5 + .../mysql-client-tests/c/CMakeLists.txt | 5 - .../mysql-client-tests/c/Makefile | 19 +- .../c/mysql-connector-c-test.c | 2 +- .../mysql-client-tests/c/vcpkg.json | 4 - .../mysql-client-tests/cpp/CMakeLists.txt | 17 - .../mysql-client-tests/cpp/Makefile | 20 +- .../cpp/mysql-connector-cpp-test.cpp | 5 + .../cpp/third_party/mysql-connector-cpp | 1 - .../mysql-client-tests/elixir/lib/simple.ex | 37 +- .../mysql-client-tests/elixir/mix.exs | 27 +- .../main/java}/MySQLConnectorTest.java | 346 +++++++++--------- .../java}/MySQLConnectorTest_Collation.java | 0 ...tor-test.py => py-mysql-connector-test.py} | 140 +++---- ...lalchemy-test.py => py-sqlalchemy-test.py} | 134 +++---- 17 files changed, 488 insertions(+), 386 deletions(-) delete mode 100644 .github/actions/mysql-client-tests/.dockerignore create mode 100644 .github/actions/mysql-client-tests/Dockerfile.dockerignore delete mode 100644 integration-tests/mysql-client-tests/c/CMakeLists.txt delete mode 100644 integration-tests/mysql-client-tests/c/vcpkg.json delete mode 100644 integration-tests/mysql-client-tests/cpp/CMakeLists.txt delete mode 160000 integration-tests/mysql-client-tests/cpp/third_party/mysql-connector-cpp rename integration-tests/mysql-client-tests/java/{ => src/main/java}/MySQLConnectorTest.java (97%) rename integration-tests/mysql-client-tests/java/{ => src/main/java}/MySQLConnectorTest_Collation.java (100%) rename integration-tests/mysql-client-tests/python/{mysql.connector-test.py => py-mysql-connector-test.py} (97%) rename integration-tests/mysql-client-tests/python/{sqlalchemy-test.py => py-sqlalchemy-test.py} (97%) diff --git a/.github/actions/mysql-client-tests/.dockerignore b/.github/actions/mysql-client-tests/.dockerignore deleted file mode 100644 index aaa83ccc43..0000000000 --- a/.github/actions/mysql-client-tests/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -**/.git -**/.github -**/docker/ -**/images/ \ No newline at end of file diff --git a/.github/actions/mysql-client-tests/Dockerfile b/.github/actions/mysql-client-tests/Dockerfile index e80eb0c625..ff5c3c5b8a 100644 --- a/.github/actions/mysql-client-tests/Dockerfile +++ b/.github/actions/mysql-client-tests/Dockerfile @@ -4,7 +4,6 @@ ENV CGO_ENABLED=1 ENV GO_LDFLAGS="-linkmode external -extldflags '-static'" RUN apk add --no-cache build-base - FROM golang_cgo125 AS dolt_build COPY dolt/go/go.mod /build/dolt/go/ COPY go-mysql-server*/ /build/go-mysql-server/ @@ -13,18 +12,16 @@ WORKDIR /build/dolt/go/ RUN go mod download RUN apk add --no-cache icu-dev icu-static COPY dolt/go/ /build/dolt/go/ -RUN go build -tags icu_static -o /build/bin/dolt ./cmd/dolt - +RUN go build -tags icu_static -ldflags "$GO_LDFLAGS" -o /build/bin/dolt ./cmd/dolt FROM golang_cgo125 AS go_clients_build COPY dolt/integration-tests/mysql-client-tests/go /build/go/ WORKDIR /build/go/ -RUN go build -o /build/bin/go-mysql-client-test +RUN go build -ldflags "$GO_LDFLAGS" -o /build/bin/go-mysql-client-test COPY dolt/integration-tests/mysql-client-tests/go-mysql/ /build/go-mysql/ WORKDIR /build/go-mysql/ -RUN go build -o /build/bin/go-sql-driver-test - +RUN go build -ldflags "$GO_LDFLAGS" -o /build/bin/go-sql-driver-test FROM rust:1.90-alpine3.22 AS rust_clients_build COPY dolt/integration-tests/mysql-client-tests/rust/ /build/rust/ @@ -32,7 +29,6 @@ WORKDIR /build/rust/ RUN apk add --no-cache musl-dev RUN cargo build --release --target-dir /build/bin/ # exe is in release/ - FROM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim AS dotnet_clients_build COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlClient/ /build/dotnet/MySqlClient/ WORKDIR /build/dotnet/MySqlClient/ @@ -42,19 +38,101 @@ COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlConnector/ /build/dot WORKDIR /build/dotnet/MySqlConnector/ RUN dotnet publish -c Release -o /build/bin - -FROM mcr.microsoft.com/devcontainers/cpp:1-bookworm AS c_clients_build -COPY dolt/integration-tests/mysql-client-tests/c/vcpkg.json /build/c/vcpkg.json -WORKDIR /build/c/ -RUN vcpkg install --triplet=x64-linux-release +FROM gcc:12.5-bookworm AS c_clients_build +RUN apt-get update && apt-get install -y \ + default-libmysqlclient-dev \ + && rm -rf /var/lib/apt/lists/* COPY dolt/integration-tests/mysql-client-tests/c/ /build/c/ -ENV CMAKE_TOOLCHAIN_FILE=/usr/local/vcpkg/scripts/buildsystems/vcpkg.cmake -RUN cmake -B build -S . -RUN cmake --build build +WORKDIR /build/c/ +RUN make +FROM gcc:12.5-bookworm AS cpp_clients_build +RUN apt-get update && apt-get install -y \ + libmysqlcppconn-dev \ + && rm -rf /var/lib/apt/lists/* +COPY dolt/integration-tests/mysql-client-tests/cpp/ /build/cpp/ +WORKDIR /build/cpp/ +RUN make +FROM python:3.14-slim-bookworm AS python_clients_build +RUN apt-get update && apt-get install -y binutils && rm -rf /var/lib/apt/lists/* +RUN pip install --no-cache-dir mysql-connector-python==8.0.33 PyMySQL==1.0.2 sqlalchemy==1.4.46 pyinstaller +COPY dolt/integration-tests/mysql-client-tests/python/ /build/python/ +WORKDIR /build/python/ +RUN pyinstaller --onefile pymysql-test.py +RUN pyinstaller --onefile --collect-all mysql.connector py-sqlalchemy-test.py +RUN pyinstaller --onefile --collect-all mysql.connector py-mysql-connector-test.py +FROM elixir:1.18-slim AS elixir_clients_build +RUN apt-get update && apt-get install -y ca-certificates xz-utils curl && rm -rf /var/lib/apt/lists/* +RUN curl -sSL https://ziglang.org/download/0.14.1/zig-x86_64-linux-0.14.1.tar.xz | tar -xJ +ENV PATH="/zig-x86_64-linux-0.14.1:${PATH}" +COPY dolt/integration-tests/mysql-client-tests/elixir/mix.exs /build/elixir/ +WORKDIR /build/elixir/ +RUN mix local.hex --force && mix local.rebar --force +RUN mix deps.get +COPY dolt/integration-tests/mysql-client-tests/elixir/ /build/elixir/ +RUN MIX_ENV=prod mix release +RUN mkdir -p /build/bin && cp burrito_out/simple_linux /build/bin/elixir-mysql-client-test +FROM maven:3.9.11-amazoncorretto-21-debian-bookworm AS java_clients_build +RUN apt-get update && apt-get install -y binutils && rm -rf /var/lib/apt/lists/* +COPY dolt/integration-tests/mysql-client-tests/java/ /build/java/ +WORKDIR /build/java/ +RUN mvn package +RUN jlink \ + --add-modules java.base,java.sql,java.naming,java.xml,java.logging,java.management \ + --strip-debug \ + --no-man-pages \ + --no-header-files \ + --output /build/jre +FROM node:22-bookworm-slim AS node_clients_build +COPY dolt/integration-tests/mysql-client-tests/node/package.json /build/bin/ +WORKDIR /build/bin/ +RUN npm install --omit=dev +COPY dolt/integration-tests/mysql-client-tests/node/ /build/bin/ +FROM php:8.3-bookworm AS php_clients_build +RUN docker-php-ext-install mysqli pdo_mysql +COPY dolt/integration-tests/mysql-client-tests/php/ /build/bin/ +FROM ruby:3.4-bookworm AS ruby_clients_build +RUN apt-get update && apt-get install -y default-libmysqlclient-dev && rm -rf /var/lib/apt/lists/* +COPY dolt/integration-tests/mysql-client-tests/ruby/Gemfile /build/ruby/ +WORKDIR /build/ruby/ +RUN bundle install +COPY dolt/integration-tests/mysql-client-tests/ruby/ /build/bin/ + +FROM php:8.3-bookworm AS runtime +RUN apt-get update && apt-get install -y \ + default-libmysqlclient-dev \ + libmysqlcppconn-dev \ + r-base \ + && rm -rf /var/lib/apt/lists/* +RUN R -e "install.packages(c('RMariaDB', 'RMySQL', 'DBI'), repos='https://cloud.r-project.org/')" + +COPY --from=dolt_build /build/bin/ /usr/local/bin/ +COPY --from=go_clients_build /build/bin/ /build/bin/go/ +COPY --from=rust_clients_build /build/bin/release/ /build/bin/rust/ +COPY --from=dotnet_clients_build /build/bin/ /build/bin/dotnet/ +COPY --from=c_clients_build /build/bin/ /build/bin/c/ +COPY --from=cpp_clients_build /build/bin/ /build/bin/cpp/ +COPY --from=python_clients_build /build/python/dist/ /build/bin/python/ +COPY --from=elixir_clients_build /build/bin/ /build/bin/elixir/ +COPY --from=java_clients_build /build/java/target/ /build/bin/java/ +COPY --from=node_clients_build /build/bin/ /build/bin/node/ +COPY --from=php_clients_build /build/bin/ /build/bin/php/ +COPY --from=ruby_clients_build /build/bin/ /build/bin/ruby/ +COPY dolt/integration-tests/mysql-client-tests/r/ /build/bin/r/ + +COPY --from=java_clients_build /build/jre/ /opt/jre/ +COPY --from=node_clients_build /usr/local/bin/node /usr/local/bin/node +COPY --from=php_clients_build /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/ +COPY --from=php_clients_build /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/ +COPY --from=ruby_clients_build /usr/local/bin/ruby /usr/local/bin/ruby +COPY --from=ruby_clients_build /usr/local/lib/ /usr/local/lib/ +COPY --from=ruby_clients_build /usr/local/bundle/ /usr/local/bundle/ +ENV PATH="/opt/jre/bin:/usr/local/bundle/bin:${PATH}" +ENV GEM_HOME="/usr/local/bundle" +ENV BUNDLE_APP_CONFIG="/usr/local/bundle" diff --git a/.github/actions/mysql-client-tests/Dockerfile.dockerignore b/.github/actions/mysql-client-tests/Dockerfile.dockerignore new file mode 100644 index 0000000000..b92337fd15 --- /dev/null +++ b/.github/actions/mysql-client-tests/Dockerfile.dockerignore @@ -0,0 +1,5 @@ +**/.git/ +**/.github/ +**/docker/ +**/images/ +**/node_modules/ diff --git a/integration-tests/mysql-client-tests/c/CMakeLists.txt b/integration-tests/mysql-client-tests/c/CMakeLists.txt deleted file mode 100644 index 3128143819..0000000000 --- a/integration-tests/mysql-client-tests/c/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -cmake_minimum_required(VERSION 3.24) -project(c_mysql_client_test C) -find_package(unofficial-libmysql REQUIRED) -add_executable("c-mysql-client-test" "mysql-connector-c-test.c") -target_link_libraries("c-mysql-client-test" PRIVATE unofficial::libmysql::libmysql stdc++) diff --git a/integration-tests/mysql-client-tests/c/Makefile b/integration-tests/mysql-client-tests/c/Makefile index fdb63ba5cc..f1506e6949 100644 --- a/integration-tests/mysql-client-tests/c/Makefile +++ b/integration-tests/mysql-client-tests/c/Makefile @@ -1,11 +1,18 @@ -CFLAGS := $(shell pkg-config --cflags mysqlclient) -LDFLAGS := $(shell pkg-config --libs mysqlclient) +CC = gcc -all: mysql-connector-c-test +CFLAGS = -I/usr/include/mysql -Wall -O2 -mysql-connector-c-test: mysql-connector-c-test.c +LDFLAGS = -lmysqlclient + +TARGET = /build/bin/c-mysql-client-test + +SRCS = mysql-connector-c-test.c + +all: $(TARGET) + +$(TARGET): $(SRCS) + @mkdir -p /build/bin $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -.PHONY: clean clean: - rm -f mysql-connector-c-test + rm -f /build/bin/c-mysql-client-test diff --git a/integration-tests/mysql-client-tests/c/mysql-connector-c-test.c b/integration-tests/mysql-client-tests/c/mysql-connector-c-test.c index 0731abd20c..98a1a4fd4f 100644 --- a/integration-tests/mysql-client-tests/c/mysql-connector-c-test.c +++ b/integration-tests/mysql-client-tests/c/mysql-connector-c-test.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #define QUERIES_SIZE 14 diff --git a/integration-tests/mysql-client-tests/c/vcpkg.json b/integration-tests/mysql-client-tests/c/vcpkg.json deleted file mode 100644 index 52bf7048e7..0000000000 --- a/integration-tests/mysql-client-tests/c/vcpkg.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "mysql-client-test-c", - "dependencies": [ "libmysql" ] -} diff --git a/integration-tests/mysql-client-tests/cpp/CMakeLists.txt b/integration-tests/mysql-client-tests/cpp/CMakeLists.txt deleted file mode 100644 index fd02d226f2..0000000000 --- a/integration-tests/mysql-client-tests/cpp/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -project(DoltCxxConnectorTest - VERSION 0.1 - DESCRIPTION "A smoke test for mysql-connector-c++ connecting to Dolt" - LANGUAGES CXX) - -add_executable(test_mysql_connector_cxx mysql-connector-cpp-test.cpp) -set_property(TARGET test_mysql_connector_cxx PROPERTY CXX_STANDARD 11) - -if(WITH_JDBC) - add_subdirectory(third_party/mysql-connector-cpp EXCLUDE_FROM_ALL) - target_link_libraries(test_mysql_connector_cxx connector-jdbc) -else() - find_library(LIBMYSQLCPPCONN "mysqlcppconn") - target_link_libraries(test_mysql_connector_cxx "${LIBMYSQLCPPCONN}") -endif() diff --git a/integration-tests/mysql-client-tests/cpp/Makefile b/integration-tests/mysql-client-tests/cpp/Makefile index 1a26239014..9c973a4ba7 100644 --- a/integration-tests/mysql-client-tests/cpp/Makefile +++ b/integration-tests/mysql-client-tests/cpp/Makefile @@ -1,14 +1,14 @@ -MYSQL_CONCPP_DIR = /usr/local/Cellar/mysql-connector-c++/8.0.21 -CPPFLAGS = -I $(MYSQL_CONCPP_DIR)/include -L $(MYSQL_CONCPP_DIR)/lib64 -LDLIBS = -lmysqlcppconn8 -CXX = clang++ -stdlib=libc++ -CXXFLAGS = -std=c++11 +CXX = g++ +CXXFLAGS = -I/usr/include/cppconn -std=c++11 -Wall -O2 +LDFLAGS = -lmysqlcppconn +TARGET = /build/bin/cpp-mysql-connector-test +SRCS = mysql-connector-cpp-test.cpp -all: mysql-connector-cpp-test +all: $(TARGET) -mysql-connector-cpp-test: mysql-connector-cpp-test.cpp - $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $^ $(LDLIBS) +$(TARGET): $(SRCS) + @mkdir -p /build/bin + $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -.PHONY: clean clean: - rm -f mysql-connector-cpp-test + rm -f $(TARGET) diff --git a/integration-tests/mysql-client-tests/cpp/mysql-connector-cpp-test.cpp b/integration-tests/mysql-client-tests/cpp/mysql-connector-cpp-test.cpp index b1d5bd2c05..050dfed275 100644 --- a/integration-tests/mysql-client-tests/cpp/mysql-connector-cpp-test.cpp +++ b/integration-tests/mysql-client-tests/cpp/mysql-connector-cpp-test.cpp @@ -46,6 +46,11 @@ std::string queries[QUERIES_SIZE] = int is_update[QUERIES_SIZE] = {1,0,0,1,0,0,0,0,0,1,0,0,0,0}; int main(int argc, char **argv) { + if (argc < 4) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + std::string user = argv[1]; std::string port = argv[2]; std::string db = argv[3]; diff --git a/integration-tests/mysql-client-tests/cpp/third_party/mysql-connector-cpp b/integration-tests/mysql-client-tests/cpp/third_party/mysql-connector-cpp deleted file mode 160000 index 857a8d63d8..0000000000 --- a/integration-tests/mysql-client-tests/cpp/third_party/mysql-connector-cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 857a8d63d817a17160ca6062ceef6e9d6d0dd128 diff --git a/integration-tests/mysql-client-tests/elixir/lib/simple.ex b/integration-tests/mysql-client-tests/elixir/lib/simple.ex index 89a5237f2b..4585787a87 100644 --- a/integration-tests/mysql-client-tests/elixir/lib/simple.ex +++ b/integration-tests/mysql-client-tests/elixir/lib/simple.ex @@ -1,16 +1,26 @@ defmodule SmokeTest do - def myTestFunc(arg1, arg2) do - if arg1 != arg2 do - raise "Test error" - end + def main(_args \\ []) do + IO.puts("Starting SmokeTest.main/1") + + cli_args = Burrito.Util.Args.get_arguments() + IO.puts("Received CLI args: #{inspect(cli_args)}") + + result = run(cli_args) + System.halt(0) + result end - @spec run :: nil - def run do - args = System.argv() + defp run(args) do + if length(args) < 3 do + IO.puts("Usage: simple ") + System.halt(1) + end + user = Enum.at(args, 0) - {port, _} = Integer.parse(Enum.at(args, 1)) + port_str = Enum.at(args, 1) database = Enum.at(args, 2) + + {port, _} = Integer.parse(port_str) {:ok, pid} = MyXQL.start_link(username: user, port: port, database: database) {:ok, _} = MyXQL.query(pid, "drop table if exists test") @@ -21,8 +31,6 @@ defmodule SmokeTest do myTestFunc(result.num_rows, 0) {:ok, _} = MyXQL.query(pid, "insert into test (pk, `value`) values (0,0)") - - # MyXQL uses the CLIENT_FOUND_ROWS flag so we should return the number of rows matched {:ok, result} = MyXQL.query(pid, "UPDATE test SET pk = pk where pk = 0") myTestFunc(result.num_rows, 1) @@ -31,7 +39,7 @@ defmodule SmokeTest do {:ok, result} = MyXQL.query(pid, "SELECT * FROM test") myTestFunc(result.num_rows, 1) - myTestFunc(result.rows, [[0,0]]) + myTestFunc(result.rows, [[0, 0]]) {:ok, _} = MyXQL.query(pid, "call dolt_add('-A');") {:ok, _} = MyXQL.query(pid, "call dolt_commit('-m', 'my commit')") @@ -45,5 +53,12 @@ defmodule SmokeTest do {:ok, result} = MyXQL.query(pid, "select COUNT(*) FROM dolt_log") myTestFunc(result.num_rows, 1) myTestFunc(result.rows, [[3]]) + :ok + end + + defp myTestFunc(arg1, arg2) do + if arg1 != arg2 do + raise "Test error: expected #{inspect(arg2)}, got #{inspect(arg1)}" + end end end diff --git a/integration-tests/mysql-client-tests/elixir/mix.exs b/integration-tests/mysql-client-tests/elixir/mix.exs index 51a20bd6f6..5bfb76a824 100644 --- a/integration-tests/mysql-client-tests/elixir/mix.exs +++ b/integration-tests/mysql-client-tests/elixir/mix.exs @@ -5,15 +5,38 @@ defmodule Simple.MixProject do [ app: :simple, version: "0.1.0", + elixir: "~> 1.18", start_permanent: Mix.env() == :prod, - deps: deps() + deps: deps(), + releases: releases() + ] + end + + def application do + [ + extra_applications: [:logger, :crypto, :public_key, :ssl], + mod: {Simple.Application, []} + ] + end + + defp releases do + [ + simple: [ + steps: [:assemble, &Burrito.wrap/1], + burrito: [ + targets: [ + linux: [os: :linux, cpu: :x86_64] + ], + no_native_archivers: true + ] + ] ] end - # Run "mix help deps" to learn about dependencies. defp deps do [ {:myxql, "~> 0.5.0"}, + {:burrito, "~> 1.4.0"} ] end end diff --git a/integration-tests/mysql-client-tests/java/MySQLConnectorTest.java b/integration-tests/mysql-client-tests/java/src/main/java/MySQLConnectorTest.java similarity index 97% rename from integration-tests/mysql-client-tests/java/MySQLConnectorTest.java rename to integration-tests/mysql-client-tests/java/src/main/java/MySQLConnectorTest.java index 3bed99ab29..2cbc1a2a3e 100644 --- a/integration-tests/mysql-client-tests/java/MySQLConnectorTest.java +++ b/integration-tests/mysql-client-tests/java/src/main/java/MySQLConnectorTest.java @@ -1,173 +1,173 @@ -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; - -public class MySQLConnectorTest { - - // test queries to be run against Dolt - private static final String[] queries = { - "create table test (pk int, `value` int, primary key(pk))", - "describe test", - "select * from test", - "insert into test (pk, `value`) values (0,0)", - "select * from test", - "call dolt_add('-A')", - "call dolt_commit('-m', 'my commit')", - "select COUNT(*) FROM dolt_log", - "call dolt_checkout('-b', 'mybranch')", - "insert into test (pk, `value`) values (1,1)", - "call dolt_commit('-a', '-m', 'my commit2')", - "call dolt_checkout('main')", - "call dolt_merge('mybranch')", - "select COUNT(*) FROM dolt_log", - }; - - // We currently only test a single field value in the first row - private static final String[] expectedResults = { - "0", - "pk", - null, - "1", - "0", - "0", - "0", - "2", - "0", - "1", - "1", - "0", - "", - "3" - }; - - // fieldAccessors are the value used to access a field in a row in a result set. Currently, only - // String (i.e column name) and Integer (i.e. field position) values are supported. - private static final Object[] fieldAccessors = { - 1, - 1, - "pk", - 1, - "test.pk", - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - "COUNT(*)", - }; - - public static void main(String[] args) { - testStatements(args); - testServerSideCursors(args); - System.exit(0); - } - - // testServerSideCursors does a simple smoke test with server-side cursors to make sure - // results can be read. Note that we don't test results here; this is just a high level - // smoke test that we can execute server-side cursors logic without the server erroring out. - // This test was added for a regression where server-side cursor logic was getting - // corrupted result set memory and sending invalid data to the client, which caused the - // server to error out and crash the connection. If any errors are encountered, a stack trace - // is printed and this function exits with a non-zero code. - // For more details, see: https://github.com/dolthub/dolt/issues/9125 - private static void testServerSideCursors(String[] args) { - String user = args[0]; - String port = args[1]; - String db = args[2]; - - try { - String url = "jdbc:mysql://127.0.0.1:" + port + "/" + db + - "?useServerPrepStmts=true&useCursorFetch=true"; - Connection conn = DriverManager.getConnection(url, user, ""); - - executePreparedQuery(conn, "SELECT 1;"); - executePreparedQuery(conn, "SELECT database();"); - executePreparedQuery(conn, "SHOW COLLATION;"); - executePreparedQuery(conn, "SHOW COLLATION;"); - executePreparedQuery(conn, "SHOW COLLATION;"); - } catch (SQLException ex) { - System.out.println("An error occurred."); - ex.printStackTrace(); - System.exit(1); - } - } - - // executePreparedQuery executes the specified |query| using |conn| as a prepared statement, - // and uses server-side cursor to fetch results. This method does not do any validation of - // results from the query. It is simply a smoke test to ensure the connection doesn't crash. - private static void executePreparedQuery(Connection conn, String query) throws SQLException { - PreparedStatement stmt = conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY); - stmt.setFetchSize(25); // needed to ensure a server-side cursor is used - - ResultSet rs = stmt.executeQuery(); - while (rs.next()) {} - - rs.close(); - stmt.close(); - } - - // testStatements executes the queries from |queries| and asserts their results from - // |expectedResults|. If any errors are encountered, a stack trace is printed and this - // function exits with a non-zero code. - private static void testStatements(String[] args) { - Connection conn = null; - - String user = args[0]; - String port = args[1]; - String db = args[2]; - - try { - String url = "jdbc:mysql://127.0.0.1:" + port + "/" + db; - String password = ""; - - conn = DriverManager.getConnection(url, user, password); - Statement st = conn.createStatement(); - - for (int i = 0; i < queries.length; i++) { - String query = queries[i]; - String expected = expectedResults[i]; - if ( st.execute(query) ) { - ResultSet rs = st.getResultSet(); - if (rs.next()) { - String result = ""; - Object fieldAccessor = fieldAccessors[i]; - if (fieldAccessor instanceof String) { - result = rs.getString((String)fieldAccessor); - } else if (fieldAccessor instanceof Integer) { - result = rs.getString((Integer)fieldAccessor); - } else { - System.out.println("Unsupported field accessor value: " + fieldAccessor); - System.exit(1); - } - - if (!expected.equals(result) && !(query.contains("dolt_commit")) && !(query.contains("dolt_merge"))) { - System.out.println("Query: \n" + query); - System.out.println("Expected:\n" + expected); - System.out.println("Result:\n" + result); - System.exit(1); - } - } - } else { - String result = Integer.toString(st.getUpdateCount()); - if ( !expected.equals(result) ) { - System.out.println("Query: \n" + query); - System.out.println("Expected:\n" + expected); - System.out.println("Rows Updated:\n" + result); - System.exit(1); - } - } - } - } catch (SQLException ex) { - System.out.println("An error occurred."); - ex.printStackTrace(); - System.exit(1); - } - } -} +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; + +public class MySQLConnectorTest { + + // test queries to be run against Dolt + private static final String[] queries = { + "create table test (pk int, `value` int, primary key(pk))", + "describe test", + "select * from test", + "insert into test (pk, `value`) values (0,0)", + "select * from test", + "call dolt_add('-A')", + "call dolt_commit('-m', 'my commit')", + "select COUNT(*) FROM dolt_log", + "call dolt_checkout('-b', 'mybranch')", + "insert into test (pk, `value`) values (1,1)", + "call dolt_commit('-a', '-m', 'my commit2')", + "call dolt_checkout('main')", + "call dolt_merge('mybranch')", + "select COUNT(*) FROM dolt_log", + }; + + // We currently only test a single field value in the first row + private static final String[] expectedResults = { + "0", + "pk", + null, + "1", + "0", + "0", + "0", + "2", + "0", + "1", + "1", + "0", + "", + "3" + }; + + // fieldAccessors are the value used to access a field in a row in a result set. Currently, only + // String (i.e column name) and Integer (i.e. field position) values are supported. + private static final Object[] fieldAccessors = { + 1, + 1, + "pk", + 1, + "test.pk", + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + "COUNT(*)", + }; + + public static void main(String[] args) { + testStatements(args); + testServerSideCursors(args); + System.exit(0); + } + + // testServerSideCursors does a simple smoke test with server-side cursors to make sure + // results can be read. Note that we don't test results here; this is just a high level + // smoke test that we can execute server-side cursors logic without the server erroring out. + // This test was added for a regression where server-side cursor logic was getting + // corrupted result set memory and sending invalid data to the client, which caused the + // server to error out and crash the connection. If any errors are encountered, a stack trace + // is printed and this function exits with a non-zero code. + // For more details, see: https://github.com/dolthub/dolt/issues/9125 + private static void testServerSideCursors(String[] args) { + String user = args[0]; + String port = args[1]; + String db = args[2]; + + try { + String url = "jdbc:mysql://127.0.0.1:" + port + "/" + db + + "?useServerPrepStmts=true&useCursorFetch=true"; + Connection conn = DriverManager.getConnection(url, user, ""); + + executePreparedQuery(conn, "SELECT 1;"); + executePreparedQuery(conn, "SELECT database();"); + executePreparedQuery(conn, "SHOW COLLATION;"); + executePreparedQuery(conn, "SHOW COLLATION;"); + executePreparedQuery(conn, "SHOW COLLATION;"); + } catch (SQLException ex) { + System.out.println("An error occurred."); + ex.printStackTrace(); + System.exit(1); + } + } + + // executePreparedQuery executes the specified |query| using |conn| as a prepared statement, + // and uses server-side cursor to fetch results. This method does not do any validation of + // results from the query. It is simply a smoke test to ensure the connection doesn't crash. + private static void executePreparedQuery(Connection conn, String query) throws SQLException { + PreparedStatement stmt = conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY); + stmt.setFetchSize(25); // needed to ensure a server-side cursor is used + + ResultSet rs = stmt.executeQuery(); + while (rs.next()) {} + + rs.close(); + stmt.close(); + } + + // testStatements executes the queries from |queries| and asserts their results from + // |expectedResults|. If any errors are encountered, a stack trace is printed and this + // function exits with a non-zero code. + private static void testStatements(String[] args) { + Connection conn = null; + + String user = args[0]; + String port = args[1]; + String db = args[2]; + + try { + String url = "jdbc:mysql://127.0.0.1:" + port + "/" + db; + String password = ""; + + conn = DriverManager.getConnection(url, user, password); + Statement st = conn.createStatement(); + + for (int i = 0; i < queries.length; i++) { + String query = queries[i]; + String expected = expectedResults[i]; + if ( st.execute(query) ) { + ResultSet rs = st.getResultSet(); + if (rs.next()) { + String result = ""; + Object fieldAccessor = fieldAccessors[i]; + if (fieldAccessor instanceof String) { + result = rs.getString((String)fieldAccessor); + } else if (fieldAccessor instanceof Integer) { + result = rs.getString((Integer)fieldAccessor); + } else { + System.out.println("Unsupported field accessor value: " + fieldAccessor); + System.exit(1); + } + + if (!expected.equals(result) && !(query.contains("dolt_commit")) && !(query.contains("dolt_merge"))) { + System.out.println("Query: \n" + query); + System.out.println("Expected:\n" + expected); + System.out.println("Result:\n" + result); + System.exit(1); + } + } + } else { + String result = Integer.toString(st.getUpdateCount()); + if ( !expected.equals(result) ) { + System.out.println("Query: \n" + query); + System.out.println("Expected:\n" + expected); + System.out.println("Rows Updated:\n" + result); + System.exit(1); + } + } + } + } catch (SQLException ex) { + System.out.println("An error occurred."); + ex.printStackTrace(); + System.exit(1); + } + } +} diff --git a/integration-tests/mysql-client-tests/java/MySQLConnectorTest_Collation.java b/integration-tests/mysql-client-tests/java/src/main/java/MySQLConnectorTest_Collation.java similarity index 100% rename from integration-tests/mysql-client-tests/java/MySQLConnectorTest_Collation.java rename to integration-tests/mysql-client-tests/java/src/main/java/MySQLConnectorTest_Collation.java diff --git a/integration-tests/mysql-client-tests/python/mysql.connector-test.py b/integration-tests/mysql-client-tests/python/py-mysql-connector-test.py similarity index 97% rename from integration-tests/mysql-client-tests/python/mysql.connector-test.py rename to integration-tests/mysql-client-tests/python/py-mysql-connector-test.py index 5edde38009..b39b3f945d 100644 --- a/integration-tests/mysql-client-tests/python/mysql.connector-test.py +++ b/integration-tests/mysql-client-tests/python/py-mysql-connector-test.py @@ -1,70 +1,70 @@ -import mysql.connector -import sys - -QUERY_RESPONSE = [ - {"create table test (pk int, `value` int, primary key(pk))": []}, - {"describe test": [ - ('pk', 'int', 'NO', 'PRI', None, ''), - ('value', 'int', 'YES', '', None, '') - ]}, - {"insert into test (pk, `value`) values (0,0)": []}, - {"select * from test": [(0, 0)]}, - # We used to have a bug where spaces after a semicolon in a query - # would cause a client/server disconnect. - # https://github.com/dolthub/vitess/pull/65 - # The following regression tests it. - {"select * from test; ": [(0, 0)]}, - {"select * from test; ": [(0, 0)]}, - # Test the Dolt SQL functions - {"call dolt_add('-A');": [(0,)]}, - {"call dolt_commit('-m', 'my commit')": [('',)]}, - {"select COUNT(*) FROM dolt_log": [(2,)]}, - {"call dolt_checkout('-b', 'mybranch')": [(0, "Switched to branch 'mybranch'")]}, - {"insert into test (pk, `value`) values (1,1)": []}, - {"call dolt_commit('-a', '-m', 'my commit2')": [('',)]}, - {"call dolt_checkout('main')": [(0, "Switched to branch 'main'")]}, - {"call dolt_merge('mybranch')": [('',1,0,)]}, - {"select COUNT(*) FROM dolt_log": [(3,)]}, -] - - -def main(): - user = sys.argv[1] - port = sys.argv[2] - db = sys.argv[3] - - connection = mysql.connector.connect(user=user, - host="127.0.0.1", - port=port, - database=db) - - for query_response in QUERY_RESPONSE: - query = list(query_response.keys())[0] - exp_results = query_response[query] - cursor = connection.cursor() - cursor.execute(query) - try: - results = cursor.fetchall() - print(exp_results) - print(results) - if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): - print("Query:") - print(query) - print("Expected:") - print(exp_results) - print("Received:") - print(results) - exit(1) - except mysql.connector.errors.InterfaceError: - - # This is a write query - pass - - cursor.close() - - connection.close() - - exit(0) - - -main() +import mysql.connector +import sys + +QUERY_RESPONSE = [ + {"create table test (pk int, `value` int, primary key(pk))": []}, + {"describe test": [ + ('pk', 'int', 'NO', 'PRI', None, ''), + ('value', 'int', 'YES', '', None, '') + ]}, + {"insert into test (pk, `value`) values (0,0)": []}, + {"select * from test": [(0, 0)]}, + # We used to have a bug where spaces after a semicolon in a query + # would cause a client/server disconnect. + # https://github.com/dolthub/vitess/pull/65 + # The following regression tests it. + {"select * from test; ": [(0, 0)]}, + {"select * from test; ": [(0, 0)]}, + # Test the Dolt SQL functions + {"call dolt_add('-A');": [(0,)]}, + {"call dolt_commit('-m', 'my commit')": [('',)]}, + {"select COUNT(*) FROM dolt_log": [(2,)]}, + {"call dolt_checkout('-b', 'mybranch')": [(0, "Switched to branch 'mybranch'")]}, + {"insert into test (pk, `value`) values (1,1)": []}, + {"call dolt_commit('-a', '-m', 'my commit2')": [('',)]}, + {"call dolt_checkout('main')": [(0, "Switched to branch 'main'")]}, + {"call dolt_merge('mybranch')": [('',1,0,)]}, + {"select COUNT(*) FROM dolt_log": [(3,)]}, +] + + +def main(): + user = sys.argv[1] + port = sys.argv[2] + db = sys.argv[3] + + connection = mysql.connector.connect(user=user, + host="127.0.0.1", + port=port, + database=db) + + for query_response in QUERY_RESPONSE: + query = list(query_response.keys())[0] + exp_results = query_response[query] + cursor = connection.cursor() + cursor.execute(query) + try: + results = cursor.fetchall() + print(exp_results) + print(results) + if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): + print("Query:") + print(query) + print("Expected:") + print(exp_results) + print("Received:") + print(results) + exit(1) + except mysql.connector.errors.InterfaceError: + + # This is a write query + pass + + cursor.close() + + connection.close() + + exit(0) + + +main() diff --git a/integration-tests/mysql-client-tests/python/sqlalchemy-test.py b/integration-tests/mysql-client-tests/python/py-sqlalchemy-test.py similarity index 97% rename from integration-tests/mysql-client-tests/python/sqlalchemy-test.py rename to integration-tests/mysql-client-tests/python/py-sqlalchemy-test.py index a9a4b7b9fe..1ea67b7814 100644 --- a/integration-tests/mysql-client-tests/python/sqlalchemy-test.py +++ b/integration-tests/mysql-client-tests/python/py-sqlalchemy-test.py @@ -1,67 +1,67 @@ -import sqlalchemy - -from sqlalchemy.engine import Engine -from sqlalchemy import create_engine - -import sys - -QUERY_RESPONSE = [ - {"create table test (pk int, `value` int, primary key(pk))": []}, - {"describe test": [ - ('pk', 'int', 'NO', 'PRI', None, ''), - ('value', 'int', 'YES', '', None, '') - ]}, - {"insert into test (pk, `value`) values (0,0)": ()}, - {"select * from test": [(0, 0)]}, - {"call dolt_add('-A');": [(0,)]}, - {"call dolt_commit('-m', 'my commit')": [('',)]}, - {"select COUNT(*) FROM dolt_log": [(2,)]}, - {"call dolt_checkout('-b', 'mybranch')": [(0, "Switched to branch 'mybranch'")]}, - {"insert into test (pk, `value`) values (1,1)": []}, - {"call dolt_commit('-a', '-m', 'my commit2')": [('',)]}, - {"call dolt_checkout('main')": [(0, "Switched to branch 'main'")]}, - {"call dolt_merge('mybranch')": [('',1,0,)]}, - {"select COUNT(*) FROM dolt_log": [(3,)]}, -] - - -def main(): - user = sys.argv[1] - port = int(sys.argv[2]) - db = sys.argv[3] - - conn_string_base = "mysql+mysqlconnector://" - - engine = create_engine(conn_string_base + - "{user}@127.0.0.1:{port}/{db}".format(user=user, - port=port, - db=db) - ) - - with engine.connect() as con: - for query_response in QUERY_RESPONSE: - query = list(query_response.keys())[0] - exp_results = query_response[query] - - result_proxy = con.execute(query) - - try: - results = result_proxy.fetchall() - if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): - print("Query:") - print(query) - print("Expected:") - print(exp_results) - print("Received:") - print(results) - exit(1) - # You can't call fetchall on an insert - # so we'll just ignore the exception - except sqlalchemy.exc.ResourceClosedError: - pass - - con.close() - exit(0) - - -main() +import sqlalchemy + +from sqlalchemy.engine import Engine +from sqlalchemy import create_engine + +import sys + +QUERY_RESPONSE = [ + {"create table test (pk int, `value` int, primary key(pk))": []}, + {"describe test": [ + ('pk', 'int', 'NO', 'PRI', None, ''), + ('value', 'int', 'YES', '', None, '') + ]}, + {"insert into test (pk, `value`) values (0,0)": ()}, + {"select * from test": [(0, 0)]}, + {"call dolt_add('-A');": [(0,)]}, + {"call dolt_commit('-m', 'my commit')": [('',)]}, + {"select COUNT(*) FROM dolt_log": [(2,)]}, + {"call dolt_checkout('-b', 'mybranch')": [(0, "Switched to branch 'mybranch'")]}, + {"insert into test (pk, `value`) values (1,1)": []}, + {"call dolt_commit('-a', '-m', 'my commit2')": [('',)]}, + {"call dolt_checkout('main')": [(0, "Switched to branch 'main'")]}, + {"call dolt_merge('mybranch')": [('',1,0,)]}, + {"select COUNT(*) FROM dolt_log": [(3,)]}, +] + + +def main(): + user = sys.argv[1] + port = int(sys.argv[2]) + db = sys.argv[3] + + conn_string_base = "mysql+mysqlconnector://" + + engine = create_engine(conn_string_base + + "{user}@127.0.0.1:{port}/{db}".format(user=user, + port=port, + db=db) + ) + + with engine.connect() as con: + for query_response in QUERY_RESPONSE: + query = list(query_response.keys())[0] + exp_results = query_response[query] + + result_proxy = con.execute(query) + + try: + results = result_proxy.fetchall() + if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): + print("Query:") + print(query) + print("Expected:") + print(exp_results) + print("Received:") + print(results) + exit(1) + # You can't call fetchall on an insert + # so we'll just ignore the exception + except sqlalchemy.exc.ResourceClosedError: + pass + + con.close() + exit(0) + + +main() From 891ef9592f10beb56bd7621c9a8fa948e8d750bc Mon Sep 17 00:00:00 2001 From: elianddb Date: Sun, 12 Oct 2025 00:28:16 -0700 Subject: [PATCH 03/14] fix entrypoint --- .github/actions/mysql-client-tests/Dockerfile | 19 ++++- .../actions/mysql-client-tests/action.yaml | 3 +- .../mysql-client-tests-entrypoint.sh | 2 +- .../mysql-client-tests.bats | 84 ++++++------------- .../python/py-mysql-connector-test.py | 4 +- .../python/py-sqlalchemy-test.py | 4 +- .../mysql-client-tests/python/pymysql-test.py | 4 +- .../mysql-client-tests/r/rmariadb-test.r | 12 +-- 8 files changed, 57 insertions(+), 75 deletions(-) diff --git a/.github/actions/mysql-client-tests/Dockerfile b/.github/actions/mysql-client-tests/Dockerfile index ff5c3c5b8a..cbd7cfc80c 100644 --- a/.github/actions/mysql-client-tests/Dockerfile +++ b/.github/actions/mysql-client-tests/Dockerfile @@ -108,8 +108,17 @@ FROM php:8.3-bookworm AS runtime RUN apt-get update && apt-get install -y \ default-libmysqlclient-dev \ libmysqlcppconn-dev \ - r-base \ + libdbd-mysql-perl \ + default-mysql-client \ + postgresql \ + postgresql-contrib \ + postgresql-15-mysql-fdw \ + r-base-core \ + perl-base \ + lsof \ + bats \ && rm -rf /var/lib/apt/lists/* +# compiled, must come after above RUN R -e "install.packages(c('RMariaDB', 'RMySQL', 'DBI'), repos='https://cloud.r-project.org/')" COPY --from=dolt_build /build/bin/ /usr/local/bin/ @@ -125,6 +134,7 @@ COPY --from=node_clients_build /build/bin/ /build/bin/node/ COPY --from=php_clients_build /build/bin/ /build/bin/php/ COPY --from=ruby_clients_build /build/bin/ /build/bin/ruby/ COPY dolt/integration-tests/mysql-client-tests/r/ /build/bin/r/ +COPY dolt/integration-tests/mysql-client-tests/perl/ /build/bin/perl/ COPY --from=java_clients_build /build/jre/ /opt/jre/ COPY --from=node_clients_build /usr/local/bin/node /usr/local/bin/node @@ -136,3 +146,10 @@ COPY --from=ruby_clients_build /usr/local/bundle/ /usr/local/bundle/ ENV PATH="/opt/jre/bin:/usr/local/bundle/bin:${PATH}" ENV GEM_HOME="/usr/local/bundle" ENV BUNDLE_APP_CONFIG="/usr/local/bundle" + +COPY dolt/integration-tests/mysql-client-tests/mysql-client-tests.bats /build/bin/ +COPY dolt/integration-tests/mysql-client-tests/helpers.bash /build/bin/ +COPY dolt/integration-tests/mysql-client-tests/mysql-client-tests-entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/.github/actions/mysql-client-tests/action.yaml b/.github/actions/mysql-client-tests/action.yaml index aa05bed550..bbb9239830 100644 --- a/.github/actions/mysql-client-tests/action.yaml +++ b/.github/actions/mysql-client-tests/action.yaml @@ -2,4 +2,5 @@ name: 'Dolt MySQL client integration tests' description: 'Smoke tests for mysql client integrations' runs: using: 'docker' - image: '../../../integration-tests/MySQLDockerfile' + image: 'Dockerfile' + context: '../../../../' diff --git a/integration-tests/mysql-client-tests/mysql-client-tests-entrypoint.sh b/integration-tests/mysql-client-tests/mysql-client-tests-entrypoint.sh index 9ee3bc7e83..f89dc6a08c 100755 --- a/integration-tests/mysql-client-tests/mysql-client-tests-entrypoint.sh +++ b/integration-tests/mysql-client-tests/mysql-client-tests-entrypoint.sh @@ -7,4 +7,4 @@ dolt config --global --add user.name mysql-test-runner dolt config --global --add user.email mysql-test-runner@liquidata.co echo "Running mysql-client-tests:" -bats /mysql-client-tests/mysql-client-tests.bats +bats /build/bin/mysql-client-tests.bats diff --git a/integration-tests/mysql-client-tests/mysql-client-tests.bats b/integration-tests/mysql-client-tests/mysql-client-tests.bats index 1f8bd2172a..45524e8de7 100644 --- a/integration-tests/mysql-client-tests/mysql-client-tests.bats +++ b/integration-tests/mysql-client-tests/mysql-client-tests.bats @@ -1,5 +1,5 @@ #!/usr/bin/env bats -load $BATS_TEST_DIRNAME/helpers.bash +load /build/bin/helpers.bash # MySQL client tests are set up to test Dolt as a MySQL server and # standard MySQL Clients in a wide array of languages. I used BATS because @@ -26,103 +26,72 @@ teardown() { } @test "go go-sql-drive/mysql test" { - (cd $BATS_TEST_DIRNAME/go; go build .) - $BATS_TEST_DIRNAME/go/go $USER $PORT $REPO_NAME + /build/bin/go/go-mysql-client-test $USER $PORT $REPO_NAME } @test "go go-mysql test" { - (cd $BATS_TEST_DIRNAME/go-mysql; go build .) - $BATS_TEST_DIRNAME/go-mysql/go $USER $PORT $REPO_NAME + /build/bin/go/go-sql-driver-test $USER $PORT $REPO_NAME } @test "python mysql.connector client" { - python3.9 $BATS_TEST_DIRNAME/python/mysql.connector-test.py $USER $PORT $REPO_NAME + /build/bin/python/py-mysql-connector-test $USER $PORT $REPO_NAME } @test "python pymysql client" { - python3.9 $BATS_TEST_DIRNAME/python/pymysql-test.py $USER $PORT $REPO_NAME + /build/bin/python/pymysql-test $USER $PORT $REPO_NAME } @test "python sqlachemy client" { - python3.9 $BATS_TEST_DIRNAME/python/sqlalchemy-test.py $USER $PORT $REPO_NAME + /build/bin/python/py-sqlalchemy-test $USER $PORT $REPO_NAME } @test "mysql-connector-java client" { - javac $BATS_TEST_DIRNAME/java/MySQLConnectorTest.java - java -cp $BATS_TEST_DIRNAME/java:$BATS_TEST_DIRNAME/java/mysql-connector-java-8.0.21.jar MySQLConnectorTest $USER $PORT $REPO_NAME + java -jar /build/bin/java/mysql-connector-test.jar $USER $PORT $REPO_NAME } @test "mysql-connector-java client collations" { - javac $BATS_TEST_DIRNAME/java/MySQLConnectorTest_Collation.java - java -cp $BATS_TEST_DIRNAME/java:$BATS_TEST_DIRNAME/java/mysql-connector-java-8.0.21.jar MySQLConnectorTest_Collation $USER $PORT $REPO_NAME + java -jar /build/bin/java/mysql-connector-test-collation.jar $USER $PORT $REPO_NAME } @test "node mysql client" { - node $BATS_TEST_DIRNAME/node/index.js $USER $PORT $REPO_NAME - node $BATS_TEST_DIRNAME/node/knex.js $USER $PORT $REPO_NAME + node /build/bin/node/index.js $USER $PORT $REPO_NAME + node /build/bin/node/knex.js $USER $PORT $REPO_NAME } @test "node mysql client, hosted workbench stability" { - node $BATS_TEST_DIRNAME/node/workbench.js $USER $PORT $REPO_NAME $BATS_TEST_DIRNAME/node/testdata + node /build/bin/node/workbench.js $USER $PORT $REPO_NAME /build/bin/node/testdata } @test "c mysql connector" { - (cd $BATS_TEST_DIRNAME/c; make clean; make) - $BATS_TEST_DIRNAME/c/mysql-connector-c-test $USER $PORT $REPO_NAME + /build/bin/c/c-mysql-client-test $USER $PORT $REPO_NAME } @test "cpp mysql connector" { - if [ -d $BATS_TEST_DIRNAME/cpp/_build ] - then - rm -rf $BATS_TEST_DIRNAME/cpp/_build/* - else - mkdir $BATS_TEST_DIRNAME/cpp/_build - fi - cd $BATS_TEST_DIRNAME/cpp/_build - if [[ `uname` = "Darwin" ]]; then - PATH=/usr/local/Cellar/mysql-client/8.0.21/bin/:"$PATH" cmake .. -DWITH_SSL=/usr/local/Cellar/openssl@1.1/1.1.1g/ -DWITH_JDBC=yes; - else - cmake .. - fi -cmake .. - make -j 10 - $BATS_TEST_DIRNAME/cpp/_build/test_mysql_connector_cxx $USER $PORT $REPO_NAME - cd - + /build/bin/cpp/cpp-mysql-connector-test $USER $PORT $REPO_NAME } @test "dotnet mysql connector" { - cd $BATS_TEST_DIRNAME/dotnet/MySqlConnector - # dotnet run uses output channel 3 which conflicts with bats so we pipe it to null - dotnet run -- $USER $PORT $REPO_NAME 3>&- + /build/bin/dotnet/dotnet-mysql-connector-test $USER $PORT $REPO_NAME } @test "dotnet mysql client" { - cd $BATS_TEST_DIRNAME/dotnet/MySqlClient - # dotnet run uses output channel 3 which conflicts with bats so we pipe it to null - dotnet run -- $USER $PORT $REPO_NAME 3>&- + /build/bin/dotnet/dotnet-mysql-client-test $USER $PORT $REPO_NAME } @test "perl DBD:mysql client" { - perl $BATS_TEST_DIRNAME/perl/dbd-mysql-test.pl $USER $PORT $REPO_NAME + perl /build/bin/perl/dbd-mysql-test.pl $USER $PORT $REPO_NAME } @test "ruby ruby/mysql test" { - ruby $BATS_TEST_DIRNAME/ruby/ruby-mysql-test.rb $USER $PORT $REPO_NAME + ruby /build/bin/ruby/ruby-mysql-test.rb $USER $PORT $REPO_NAME } @test "ruby mysql2 test" { - ruby $BATS_TEST_DIRNAME/ruby/mysql2-test.rb $USER $PORT $REPO_NAME + ruby /build/bin/ruby/mysql2-test.rb $USER $PORT $REPO_NAME } @test "elixir myxql test" { - cd $BATS_TEST_DIRNAME/elixir/ - # install some mix dependencies - mix local.hex --force - mix local.rebar --force - mix deps.get - - # run the test - mix run -e "IO.puts(SmokeTest.run())" $USER $PORT $REPO_NAME + /build/bin/elixir/elixir-mysql-client-test $USER $PORT $REPO_NAME } @test "mysqldump works" { @@ -163,27 +132,22 @@ EOF" -m "postgres" } @test "R RMySQL client" { - Rscript $BATS_TEST_DIRNAME/r/rmysql-test.r $USER $PORT $REPO_NAME + Rscript /build/bin/r/rmysql-test.r $USER $PORT $REPO_NAME } @test "R RMariaDB client" { - skip "Error loading RMariaDB library" - # ex: https://github.com/dolthub/dolt/actions/runs/4428743682/jobs/7770282852 - Rscript $BATS_TEST_DIRNAME/r/rmariadb-test.r $USER $PORT $REPO_NAME + Rscript /build/bin/r/rmariadb-test.r $USER $PORT $REPO_NAME } @test "rust mysql client" { - cd $BATS_TEST_DIRNAME/rust - ./target/debug/mysql_connector_test $USER $PORT $REPO_NAME + /build/bin/rust/rust-mysql-client-test $USER $PORT $REPO_NAME } @test "php mysqli mysql client" { - cd $BATS_TEST_DIRNAME/php - php mysqli_connector_test.php $USER $PORT $REPO_NAME + php /build/bin/php/mysqli_connector_test.php $USER $PORT $REPO_NAME } @test "php pdo mysql client" { - cd $BATS_TEST_DIRNAME/php - php pdo_connector_test.php $USER $PORT $REPO_NAME + php /build/bin/php/pdo_connector_test.php $USER $PORT $REPO_NAME } diff --git a/integration-tests/mysql-client-tests/python/py-mysql-connector-test.py b/integration-tests/mysql-client-tests/python/py-mysql-connector-test.py index b39b3f945d..8ea0544709 100644 --- a/integration-tests/mysql-client-tests/python/py-mysql-connector-test.py +++ b/integration-tests/mysql-client-tests/python/py-mysql-connector-test.py @@ -54,7 +54,7 @@ def main(): print(exp_results) print("Received:") print(results) - exit(1) + sys.exit(1) except mysql.connector.errors.InterfaceError: # This is a write query @@ -64,7 +64,7 @@ def main(): connection.close() - exit(0) + sys.exit(0) main() diff --git a/integration-tests/mysql-client-tests/python/py-sqlalchemy-test.py b/integration-tests/mysql-client-tests/python/py-sqlalchemy-test.py index 1ea67b7814..41c882a798 100644 --- a/integration-tests/mysql-client-tests/python/py-sqlalchemy-test.py +++ b/integration-tests/mysql-client-tests/python/py-sqlalchemy-test.py @@ -54,14 +54,14 @@ def main(): print(exp_results) print("Received:") print(results) - exit(1) + sys.exit(1) # You can't call fetchall on an insert # so we'll just ignore the exception except sqlalchemy.exc.ResourceClosedError: pass con.close() - exit(0) + sys.exit(0) main() diff --git a/integration-tests/mysql-client-tests/python/pymysql-test.py b/integration-tests/mysql-client-tests/python/pymysql-test.py index dbbd8d61a8..ab542ce06c 100644 --- a/integration-tests/mysql-client-tests/python/pymysql-test.py +++ b/integration-tests/mysql-client-tests/python/pymysql-test.py @@ -44,11 +44,11 @@ def main(): print(exp_results) print("Received:") print(results) - exit(1) + sys.exit(1) connection.close() - exit(0) + sys.exit(0) main() diff --git a/integration-tests/mysql-client-tests/r/rmariadb-test.r b/integration-tests/mysql-client-tests/r/rmariadb-test.r index c4175ebbe3..7cae8d7de0 100644 --- a/integration-tests/mysql-client-tests/r/rmariadb-test.r +++ b/integration-tests/mysql-client-tests/r/rmariadb-test.r @@ -17,7 +17,7 @@ queries = list("create table test (pk int, value int, primary key(pk))", "select * from test") responses = list(NULL, - data.frame(Field = c("pk", "value"), Type = c("int", "int"), Null = c("NO", "YES"), Key = c("PRI", ""), Default = c(NA, NA), Extra = c("", ""), stringsAsFactors = FALSE), + data.frame(Field = c("pk", "value"), Type = c("int", "int"), Null = c("NO", "YES"), Key = c("PRI", ""), Default = c(NA_character_, NA_character_), Extra = c("", ""), stringsAsFactors = FALSE), NULL, data.frame(pk = c(0), value = c(0), stringsAsFactors = FALSE)) @@ -30,7 +30,7 @@ for(i in 1:length(queries)) { print(q) print(want) print(got) - quit(1) + quit(save="no", status=1) } } else { dbExecute(conn, q) @@ -45,7 +45,7 @@ dbClearResult(rs) if (rowsAff != 1) { print("failed to execute prepared statement") - quit(1) + quit(save="no", status=1) } got <- dbGetQuery(conn, "select * from test where pk = 1") @@ -53,7 +53,7 @@ want = data.frame(pk = c(1), value = c(1)) if (!isTRUE(all.equal(want, got))) { print("unexpected prepared statement result") print(got) - quit(1) + quit(save="no", status=1) } dolt_queries = list("call DOLT_ADD('-A')", @@ -74,7 +74,7 @@ want <- data.frame(c = c(3)) ret <- all.equal(count, want) if (!ret) { print("Number of commits is incorrect") - quit(1) + quit(save="no", status=1) } # Add a failing query and ensure that the connection does not quit. @@ -84,6 +84,6 @@ one <- dbGetQuery(conn, "select 1 as pk") ret <- one == data.frame(pk=1) if (!ret) { print("Number of commits is incorrect") - quit(1) + quit(save="no", status=1) } From 8f377dc9997c90b0ab0da94d6778f065a8467d73 Mon Sep 17 00:00:00 2001 From: elianddb Date: Sun, 12 Oct 2025 01:03:11 -0700 Subject: [PATCH 04/14] add c and cpp mariadb --- .github/actions/mysql-client-tests/Dockerfile | 14 ++++++----- .../mysql-client-tests/c/Makefile | 24 ++++++++++++------- .../mysql-client-tests/cpp/Makefile | 24 ++++++++++++------- .../mysql-client-tests.bats | 8 +++++++ 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/.github/actions/mysql-client-tests/Dockerfile b/.github/actions/mysql-client-tests/Dockerfile index cbd7cfc80c..96c543e3c2 100644 --- a/.github/actions/mysql-client-tests/Dockerfile +++ b/.github/actions/mysql-client-tests/Dockerfile @@ -39,17 +39,16 @@ WORKDIR /build/dotnet/MySqlConnector/ RUN dotnet publish -c Release -o /build/bin FROM gcc:12.5-bookworm AS c_clients_build -RUN apt-get update && apt-get install -y \ - default-libmysqlclient-dev \ - && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y default-libmysqlclient-dev libmariadb-dev && rm -rf /var/lib/apt/lists/* COPY dolt/integration-tests/mysql-client-tests/c/ /build/c/ WORKDIR /build/c/ RUN make FROM gcc:12.5-bookworm AS cpp_clients_build -RUN apt-get update && apt-get install -y \ - libmysqlcppconn-dev \ - && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y libmysqlcppconn-dev wget && rm -rf /var/lib/apt/lists/* +RUN wget https://dlm.mariadb.com/4464866/Connectors/cpp/connector-cpp-1.1.7/mariadb-connector-cpp_1.1.7-1+maria~bookworm_amd64.deb \ + && dpkg -i mariadb-connector-cpp_1.1.7-1+maria~bookworm_amd64.deb || apt-get install -y -f \ + && rm mariadb-connector-cpp_1.1.7-1+maria~bookworm_amd64.deb COPY dolt/integration-tests/mysql-client-tests/cpp/ /build/cpp/ WORKDIR /build/cpp/ RUN make @@ -108,6 +107,7 @@ FROM php:8.3-bookworm AS runtime RUN apt-get update && apt-get install -y \ default-libmysqlclient-dev \ libmysqlcppconn-dev \ + libmariadb3 \ libdbd-mysql-perl \ default-mysql-client \ postgresql \ @@ -136,6 +136,8 @@ COPY --from=ruby_clients_build /build/bin/ /build/bin/ruby/ COPY dolt/integration-tests/mysql-client-tests/r/ /build/bin/r/ COPY dolt/integration-tests/mysql-client-tests/perl/ /build/bin/perl/ +COPY --from=cpp_clients_build /usr/lib/x86_64-linux-gnu/libmariadb* /usr/lib/x86_64-linux-gnu/ +COPY --from=cpp_clients_build /usr/include/mariadb/ /usr/include/mariadb/ COPY --from=java_clients_build /build/jre/ /opt/jre/ COPY --from=node_clients_build /usr/local/bin/node /usr/local/bin/node COPY --from=php_clients_build /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/ diff --git a/integration-tests/mysql-client-tests/c/Makefile b/integration-tests/mysql-client-tests/c/Makefile index f1506e6949..393dfd15a3 100644 --- a/integration-tests/mysql-client-tests/c/Makefile +++ b/integration-tests/mysql-client-tests/c/Makefile @@ -1,18 +1,26 @@ CC = gcc -CFLAGS = -I/usr/include/mysql -Wall -O2 +CFLAGS_MYSQL = -I/usr/include/mysql -Wall -O2 +CFLAGS_MARIADB = -I/usr/include/mariadb -Wall -O2 -LDFLAGS = -lmysqlclient +LDFLAGS_MYSQL = -lmysqlclient +LDFLAGS_MARIADB = -lmariadb -TARGET = /build/bin/c-mysql-client-test +TARGET_MYSQL = /build/bin/c-mysql-client-test +TARGET_MARIADB = /build/bin/c-mariadb-client-test -SRCS = mysql-connector-c-test.c +SRCS_MYSQL = mysql-connector-c-test.c +SRCS_MARIADB = mariadb-connector-c-test.c -all: $(TARGET) +all: $(TARGET_MYSQL) $(TARGET_MARIADB) -$(TARGET): $(SRCS) +$(TARGET_MYSQL): $(SRCS_MYSQL) @mkdir -p /build/bin - $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + $(CC) $(CFLAGS_MYSQL) -o $@ $^ $(LDFLAGS_MYSQL) + +$(TARGET_MARIADB): $(SRCS_MARIADB) + @mkdir -p /build/bin + $(CC) $(CFLAGS_MARIADB) -o $@ $^ $(LDFLAGS_MARIADB) clean: - rm -f /build/bin/c-mysql-client-test + rm -f $(TARGET_MYSQL) $(TARGET_MARIADB) diff --git a/integration-tests/mysql-client-tests/cpp/Makefile b/integration-tests/mysql-client-tests/cpp/Makefile index 9c973a4ba7..cd5210a7e2 100644 --- a/integration-tests/mysql-client-tests/cpp/Makefile +++ b/integration-tests/mysql-client-tests/cpp/Makefile @@ -1,14 +1,22 @@ CXX = g++ -CXXFLAGS = -I/usr/include/cppconn -std=c++11 -Wall -O2 -LDFLAGS = -lmysqlcppconn -TARGET = /build/bin/cpp-mysql-connector-test -SRCS = mysql-connector-cpp-test.cpp +CXXFLAGS_MYSQL = -I/usr/include/cppconn -std=c++11 -Wall -O2 +CXXFLAGS_MARIADB = -std=c++11 -Wall -O2 +LDFLAGS_MYSQL = -lmysqlcppconn +LDFLAGS_MARIADB = -lmariadbcpp +TARGET_MYSQL = /build/bin/cpp-mysql-connector-test +TARGET_MARIADB = /build/bin/cpp-mariadb-connector-test +SRCS_MYSQL = mysql-connector-cpp-test.cpp +SRCS_MARIADB = mariadb-connector-cpp-test.cpp -all: $(TARGET) +all: $(TARGET_MYSQL) $(TARGET_MARIADB) -$(TARGET): $(SRCS) +$(TARGET_MYSQL): $(SRCS_MYSQL) @mkdir -p /build/bin - $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) + $(CXX) $(CXXFLAGS_MYSQL) -o $@ $^ $(LDFLAGS_MYSQL) + +$(TARGET_MARIADB): $(SRCS_MARIADB) + @mkdir -p /build/bin + $(CXX) $(CXXFLAGS_MARIADB) -o $@ $^ $(LDFLAGS_MARIADB) clean: - rm -f $(TARGET) + rm -f $(TARGET_MYSQL) $(TARGET_MARIADB) diff --git a/integration-tests/mysql-client-tests/mysql-client-tests.bats b/integration-tests/mysql-client-tests/mysql-client-tests.bats index 45524e8de7..177b1d59d9 100644 --- a/integration-tests/mysql-client-tests/mysql-client-tests.bats +++ b/integration-tests/mysql-client-tests/mysql-client-tests.bats @@ -66,10 +66,18 @@ teardown() { /build/bin/c/c-mysql-client-test $USER $PORT $REPO_NAME } +@test "c mariadb connector" { + /build/bin/c/c-mariadb-client-test $USER $PORT $REPO_NAME +} + @test "cpp mysql connector" { /build/bin/cpp/cpp-mysql-connector-test $USER $PORT $REPO_NAME } +@test "cpp mariadb connector" { + /build/bin/cpp/cpp-mariadb-connector-test $USER $PORT $REPO_NAME +} + @test "dotnet mysql connector" { /build/bin/dotnet/dotnet-mysql-connector-test $USER $PORT $REPO_NAME } From 5db5aac06c092cf45845252733d27f0fbb2dde5a Mon Sep 17 00:00:00 2001 From: elianddb Date: Sun, 12 Oct 2025 15:11:08 -0700 Subject: [PATCH 05/14] add mariadb connectors for existing langs --- .github/actions/mysql-client-tests/Dockerfile | 59 ++++-- .../mysql-client-tests/c/Makefile | 8 +- .../c/mariadb-connector-test.c | 199 ++++++++++++++++++ ...nector-c-test.c => mysql-connector-test.c} | 0 .../mysql-client-tests/cpp/Makefile | 10 +- .../mysql-client-tests/cpp/README.md | 28 --- .../cpp/mariadb-connector-test.cpp | 88 ++++++++ ...-cpp-test.cpp => mysql-connector-test.cpp} | 2 +- .../mysql-client-tests/dotnet/.gitignore | 136 ------------ .../dotnet/MySqlClient/dotnet.csproj | 2 +- .../MySqlConnector/MySqlConnectorTest.csproj | 2 +- .../elixir/mysql/lib/mysql_otp/application.ex | 25 +++ .../elixir/mysql/lib/mysql_otp_test.ex | 93 ++++++++ .../mysql-client-tests/elixir/mysql/mix.exs | 43 ++++ .../elixir/{ => myxql}/lib/simple.ex | 0 .../elixir/myxql/lib/simple/application.ex | 25 +++ .../elixir/{ => myxql}/mix.exs | 1 + ...{go-mysql-test.go => mysql-client-test.go} | 0 ...mysql-test.go => sql-driver-mysql-test.go} | 0 .../mysql-client-tests/java/pom.xml | 117 ++++++++++ .../src/main/java/MariaDBConnectorTest.java | 179 ++++++++++++++++ .../java/src/main/java/MariaDBR2DBCTest.java | 107 ++++++++++ .../mysql-client-tests.bats | 70 ++++-- .../node/mariadb-connector.js | 70 ++++++ .../mysql-client-tests/node/package.json | 1 + .../perl/dbd-mariadb-test.pl | 46 ++++ .../python/mariadb-connector-test.py | 81 +++++++ ...nector-test.py => mysql-connector-test.py} | 0 .../mysql-client-tests/python/pymysql-test.py | 108 +++++----- ...-sqlalchemy-test.py => sqlalchemy-test.py} | 0 .../mysql-client-tests/r/rmariadb-test.r | 178 ++++++++-------- ...uby-mysql-test.rb => mysql-client-test.rb} | 0 32 files changed, 1313 insertions(+), 365 deletions(-) create mode 100644 integration-tests/mysql-client-tests/c/mariadb-connector-test.c rename integration-tests/mysql-client-tests/c/{mysql-connector-c-test.c => mysql-connector-test.c} (100%) delete mode 100644 integration-tests/mysql-client-tests/cpp/README.md create mode 100644 integration-tests/mysql-client-tests/cpp/mariadb-connector-test.cpp rename integration-tests/mysql-client-tests/cpp/{mysql-connector-cpp-test.cpp => mysql-connector-test.cpp} (97%) delete mode 100644 integration-tests/mysql-client-tests/dotnet/.gitignore create mode 100644 integration-tests/mysql-client-tests/elixir/mysql/lib/mysql_otp/application.ex create mode 100644 integration-tests/mysql-client-tests/elixir/mysql/lib/mysql_otp_test.ex create mode 100644 integration-tests/mysql-client-tests/elixir/mysql/mix.exs rename integration-tests/mysql-client-tests/elixir/{ => myxql}/lib/simple.ex (100%) create mode 100644 integration-tests/mysql-client-tests/elixir/myxql/lib/simple/application.ex rename integration-tests/mysql-client-tests/elixir/{ => myxql}/mix.exs (99%) rename integration-tests/mysql-client-tests/go-mysql/{go-mysql-test.go => mysql-client-test.go} (100%) rename integration-tests/mysql-client-tests/go/{go-sql-driver-mysql-test.go => sql-driver-mysql-test.go} (100%) create mode 100644 integration-tests/mysql-client-tests/java/pom.xml create mode 100644 integration-tests/mysql-client-tests/java/src/main/java/MariaDBConnectorTest.java create mode 100644 integration-tests/mysql-client-tests/java/src/main/java/MariaDBR2DBCTest.java create mode 100644 integration-tests/mysql-client-tests/node/mariadb-connector.js create mode 100644 integration-tests/mysql-client-tests/perl/dbd-mariadb-test.pl create mode 100644 integration-tests/mysql-client-tests/python/mariadb-connector-test.py rename integration-tests/mysql-client-tests/python/{py-mysql-connector-test.py => mysql-connector-test.py} (100%) rename integration-tests/mysql-client-tests/python/{py-sqlalchemy-test.py => sqlalchemy-test.py} (100%) rename integration-tests/mysql-client-tests/ruby/{ruby-mysql-test.rb => mysql-client-test.rb} (100%) diff --git a/.github/actions/mysql-client-tests/Dockerfile b/.github/actions/mysql-client-tests/Dockerfile index 96c543e3c2..c5a651b6e5 100644 --- a/.github/actions/mysql-client-tests/Dockerfile +++ b/.github/actions/mysql-client-tests/Dockerfile @@ -17,11 +17,11 @@ RUN go build -tags icu_static -ldflags "$GO_LDFLAGS" -o /build/bin/dolt ./cmd/do FROM golang_cgo125 AS go_clients_build COPY dolt/integration-tests/mysql-client-tests/go /build/go/ WORKDIR /build/go/ -RUN go build -ldflags "$GO_LDFLAGS" -o /build/bin/go-mysql-client-test +RUN go build -ldflags "$GO_LDFLAGS" -o /build/bin/mysql-client-test COPY dolt/integration-tests/mysql-client-tests/go-mysql/ /build/go-mysql/ WORKDIR /build/go-mysql/ -RUN go build -ldflags "$GO_LDFLAGS" -o /build/bin/go-sql-driver-test +RUN go build -ldflags "$GO_LDFLAGS" -o /build/bin/sql-driver-mysql-test FROM rust:1.90-alpine3.22 AS rust_clients_build COPY dolt/integration-tests/mysql-client-tests/rust/ /build/rust/ @@ -37,8 +37,10 @@ RUN dotnet publish -c Release -o /build/bin COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlConnector/ /build/dotnet/MySqlConnector/ WORKDIR /build/dotnet/MySqlConnector/ RUN dotnet publish -c Release -o /build/bin +# devart dotconnect reqs a license so we've skipped it here FROM gcc:12.5-bookworm AS c_clients_build +# default-libmysqlclient-dev uses libmariadb under the hood but here we test both header interfaces RUN apt-get update && apt-get install -y default-libmysqlclient-dev libmariadb-dev && rm -rf /var/lib/apt/lists/* COPY dolt/integration-tests/mysql-client-tests/c/ /build/c/ WORKDIR /build/c/ @@ -54,25 +56,34 @@ WORKDIR /build/cpp/ RUN make FROM python:3.14-slim-bookworm AS python_clients_build -RUN apt-get update && apt-get install -y binutils && rm -rf /var/lib/apt/lists/* -RUN pip install --no-cache-dir mysql-connector-python==8.0.33 PyMySQL==1.0.2 sqlalchemy==1.4.46 pyinstaller +RUN apt-get update && apt-get install -y binutils libmariadb-dev gcc && rm -rf /var/lib/apt/lists/* +RUN pip install --no-cache-dir mysql-connector-python==8.0.33 PyMySQL==1.0.2 sqlalchemy==1.4.46 mariadb pyinstaller COPY dolt/integration-tests/mysql-client-tests/python/ /build/python/ WORKDIR /build/python/ RUN pyinstaller --onefile pymysql-test.py -RUN pyinstaller --onefile --collect-all mysql.connector py-sqlalchemy-test.py -RUN pyinstaller --onefile --collect-all mysql.connector py-mysql-connector-test.py +RUN pyinstaller --onefile --collect-all mysql.connector sqlalchemy-test.py +RUN pyinstaller --onefile --collect-all mysql.connector mysql-connector-test.py +RUN pyinstaller --onefile mariadb-connector-test.py FROM elixir:1.18-slim AS elixir_clients_build RUN apt-get update && apt-get install -y ca-certificates xz-utils curl && rm -rf /var/lib/apt/lists/* RUN curl -sSL https://ziglang.org/download/0.14.1/zig-x86_64-linux-0.14.1.tar.xz | tar -xJ ENV PATH="/zig-x86_64-linux-0.14.1:${PATH}" -COPY dolt/integration-tests/mysql-client-tests/elixir/mix.exs /build/elixir/ -WORKDIR /build/elixir/ +COPY dolt/integration-tests/mysql-client-tests/elixir/myxql/mix.exs /build/elixir/myxql/ +WORKDIR /build/elixir/myxql/ RUN mix local.hex --force && mix local.rebar --force RUN mix deps.get -COPY dolt/integration-tests/mysql-client-tests/elixir/ /build/elixir/ -RUN MIX_ENV=prod mix release -RUN mkdir -p /build/bin && cp burrito_out/simple_linux /build/bin/elixir-mysql-client-test +COPY dolt/integration-tests/mysql-client-tests/elixir/myxql/ /build/elixir/myxql/ +RUN MIX_ENV=prod mix release simple +COPY dolt/integration-tests/mysql-client-tests/elixir/mysql/mix.exs /build/elixir/mysql/ +WORKDIR /build/elixir/mysql/ +RUN mix local.hex --force && mix local.rebar --force +RUN mix deps.get +COPY dolt/integration-tests/mysql-client-tests/elixir/mysql/ /build/elixir/mysql/ +RUN MIX_ENV=prod mix release mysql_otp +RUN mkdir -p /build/bin && \ + cp /build/elixir/myxql/burrito_out/simple_linux /build/bin/myxql-driver-test && \ + cp /build/elixir/mysql/burrito_out/mysql_otp_linux /build/bin/mysql-otp-test FROM maven:3.9.11-amazoncorretto-21-debian-bookworm AS java_clients_build RUN apt-get update && apt-get install -y binutils && rm -rf /var/lib/apt/lists/* @@ -92,9 +103,8 @@ WORKDIR /build/bin/ RUN npm install --omit=dev COPY dolt/integration-tests/mysql-client-tests/node/ /build/bin/ -FROM php:8.3-bookworm AS php_clients_build +FROM php:8.3-bookworm AS php_deps RUN docker-php-ext-install mysqli pdo_mysql -COPY dolt/integration-tests/mysql-client-tests/php/ /build/bin/ FROM ruby:3.4-bookworm AS ruby_clients_build RUN apt-get update && apt-get install -y default-libmysqlclient-dev && rm -rf /var/lib/apt/lists/* @@ -103,23 +113,24 @@ WORKDIR /build/ruby/ RUN bundle install COPY dolt/integration-tests/mysql-client-tests/ruby/ /build/bin/ +FROM debian:bookworm-slim AS r_deps +RUN apt-get update && apt-get install -y r-base-core libmariadb-dev && rm -rf /var/lib/apt/lists/* +WORKDIR /build/r/ +RUN R -e "install.packages('DBI', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" +RUN R -e "install.packages('RMySQL', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" +RUN R -e "install.packages('RMariaDB', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" + FROM php:8.3-bookworm AS runtime RUN apt-get update && apt-get install -y \ - default-libmysqlclient-dev \ libmysqlcppconn-dev \ - libmariadb3 \ libdbd-mysql-perl \ + libdbd-mariadb-perl \ default-mysql-client \ - postgresql \ - postgresql-contrib \ postgresql-15-mysql-fdw \ r-base-core \ - perl-base \ lsof \ bats \ && rm -rf /var/lib/apt/lists/* -# compiled, must come after above -RUN R -e "install.packages(c('RMariaDB', 'RMySQL', 'DBI'), repos='https://cloud.r-project.org/')" COPY --from=dolt_build /build/bin/ /usr/local/bin/ COPY --from=go_clients_build /build/bin/ /build/bin/go/ @@ -131,7 +142,7 @@ COPY --from=python_clients_build /build/python/dist/ /build/bin/python/ COPY --from=elixir_clients_build /build/bin/ /build/bin/elixir/ COPY --from=java_clients_build /build/java/target/ /build/bin/java/ COPY --from=node_clients_build /build/bin/ /build/bin/node/ -COPY --from=php_clients_build /build/bin/ /build/bin/php/ +COPY dolt/integration-tests/mysql-client-tests/php/ /build/bin/php/ COPY --from=ruby_clients_build /build/bin/ /build/bin/ruby/ COPY dolt/integration-tests/mysql-client-tests/r/ /build/bin/r/ COPY dolt/integration-tests/mysql-client-tests/perl/ /build/bin/perl/ @@ -140,11 +151,13 @@ COPY --from=cpp_clients_build /usr/lib/x86_64-linux-gnu/libmariadb* /usr/lib/x86 COPY --from=cpp_clients_build /usr/include/mariadb/ /usr/include/mariadb/ COPY --from=java_clients_build /build/jre/ /opt/jre/ COPY --from=node_clients_build /usr/local/bin/node /usr/local/bin/node -COPY --from=php_clients_build /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/ -COPY --from=php_clients_build /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/ +COPY --from=php_deps /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/ +COPY --from=php_deps /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/ COPY --from=ruby_clients_build /usr/local/bin/ruby /usr/local/bin/ruby COPY --from=ruby_clients_build /usr/local/lib/ /usr/local/lib/ COPY --from=ruby_clients_build /usr/local/bundle/ /usr/local/bundle/ +COPY --from=r_deps /build/r/*.tar.gz /tmp/r-packages/ +RUN R CMD INSTALL /tmp/r-packages/*.tar.gz && rm -rf /tmp/r-packages/ ENV PATH="/opt/jre/bin:/usr/local/bundle/bin:${PATH}" ENV GEM_HOME="/usr/local/bundle" ENV BUNDLE_APP_CONFIG="/usr/local/bundle" diff --git a/integration-tests/mysql-client-tests/c/Makefile b/integration-tests/mysql-client-tests/c/Makefile index 393dfd15a3..6c5526a70c 100644 --- a/integration-tests/mysql-client-tests/c/Makefile +++ b/integration-tests/mysql-client-tests/c/Makefile @@ -6,11 +6,11 @@ CFLAGS_MARIADB = -I/usr/include/mariadb -Wall -O2 LDFLAGS_MYSQL = -lmysqlclient LDFLAGS_MARIADB = -lmariadb -TARGET_MYSQL = /build/bin/c-mysql-client-test -TARGET_MARIADB = /build/bin/c-mariadb-client-test +TARGET_MYSQL = /build/bin/mysql-client-test +TARGET_MARIADB = /build/bin/mariadb-client-test -SRCS_MYSQL = mysql-connector-c-test.c -SRCS_MARIADB = mariadb-connector-c-test.c +SRCS_MYSQL = mysql-connector-test.c +SRCS_MARIADB = mariadb-connector-test.c all: $(TARGET_MYSQL) $(TARGET_MARIADB) diff --git a/integration-tests/mysql-client-tests/c/mariadb-connector-test.c b/integration-tests/mysql-client-tests/c/mariadb-connector-test.c new file mode 100644 index 0000000000..02e2b426fe --- /dev/null +++ b/integration-tests/mysql-client-tests/c/mariadb-connector-test.c @@ -0,0 +1,199 @@ +#include +#include +#include +#include + +#define QUERIES_SIZE 14 + +char *queries[QUERIES_SIZE] = + { + "create table test (pk int, `value` int, primary key(pk))", + "describe test", + "select * from test", + "insert into test (pk, `value`) values (0,0)", + "select * from test", + "call dolt_add('-A');", + "call dolt_commit('-m', 'my commit')", + "select COUNT(*) FROM dolt_log", + "call dolt_checkout('-b', 'mybranch')", + "insert into test (pk, `value`) values (10,10)", + "call dolt_commit('-a', '-m', 'my commit2')", + "call dolt_checkout('main')", + "call dolt_merge('mybranch')", + "select COUNT(*) FROM dolt_log", + }; + +typedef struct statement_t { + char *query; + MYSQL_BIND bind[10]; + int expect_prepare_error; + int expect_exec_error; + int expect_result_metadata; +} statement; + +void test_statement(MYSQL *con, statement *stmt) { + MYSQL_STMT *mstmt = mysql_stmt_init(con); + if (!mstmt) { + fprintf(stderr, "failed to init stmt: %s\n", mysql_error(con)); + exit(1); + } + if ( mysql_stmt_prepare(mstmt, stmt->query, strlen(stmt->query)) ) { + if ( !stmt->expect_prepare_error) { + fprintf(stderr, "failed to prepare stmt: %s: %s\n", stmt->query, mysql_stmt_error(mstmt)); + exit(1); + } else { + goto close; + } + } + if ( mysql_stmt_bind_param(mstmt, stmt->bind) ) { + fprintf(stderr, "failed to bind stmt: %s: %s\n", stmt->query, mysql_stmt_error(mstmt)); + exit(1); + } + MYSQL_RES *metadata = mysql_stmt_result_metadata(mstmt); + if (stmt->expect_result_metadata && metadata == NULL) { + fprintf(stderr, "result metadata was unexpectedly NULL: %s\n", stmt->query); + exit(1); + } else if (!stmt->expect_result_metadata && metadata != NULL) { + fprintf(stderr, "result metadata was unexpectedly non-NULL: %s\n", stmt->query); + exit(1); + } + if ( mysql_stmt_execute(mstmt) ) { + if ( !stmt->expect_exec_error) { + fprintf(stderr, "failed to execute stmt: %s: %s\n", stmt->query, mysql_stmt_error(mstmt)); + exit(1); + } + } + // TODO: Add test for mysql_stmt_store_result when supported +close: + if ( mysql_stmt_close(mstmt) ) { + fprintf(stderr, "failed to close stmt: %s: %s\n", stmt->query, mysql_error(con)); + exit(1); + } +} + +statement LAST_STATEMENT = { +}; + +int main(int argc, char **argv) { + + char* user = argv[1]; + int port = atoi(argv[2]); + char* db = argv[3]; + + MYSQL *con = mysql_init(NULL); + + if ( con == NULL ) { + fprintf(stderr, "%s\n", mysql_error(con)); + exit(1); + } + + #ifndef MARIADB_CLIENT_VERSION_STR + fprintf(stderr, "Error: Not using MariaDB connector!\n"); + exit(1); + #endif + + if ( mysql_real_connect(con, + "127.0.0.1", + user, + "", + db, + port, + NULL, + 0 ) == NULL) { + fprintf(stderr, "%s\n", mysql_error(con)); + mysql_close(con); + exit(1); + } + + for ( int i = 0; i < QUERIES_SIZE; i++ ) { + if ( mysql_query(con, queries[i]) ) { + printf("QUERY FAILED: %s\n", queries[i]); + fprintf(stderr, "%s\n", mysql_error(con)); + mysql_close(con); + exit(1); + } else { + // Not checking validity of results for now + MYSQL_RES* result = mysql_use_result(con); + mysql_free_result(result); + } + } + + int pk = 1; + int value = 12; + unsigned long string_len = 16; + statement statements[] = { + { + .query = "select * from test where pk = ?", + .bind = { + [0] = { + .buffer_type = MYSQL_TYPE_LONG, + .buffer = (void *)(&pk), + .buffer_length = sizeof(pk), + }, + }, + .expect_result_metadata = 1, + }, + { + .query = "select * from test where pk = ?", + .bind = { + [0] = { + .buffer_type = MYSQL_TYPE_LONG, + .buffer = (void *)(&pk), + .buffer_length = sizeof(pk), + .is_unsigned = 1, + }, + }, + .expect_result_metadata = 1, + }, + { + .query = "insert into test values (?, ?)", + .bind = { + [0] = { + .buffer_type = MYSQL_TYPE_LONG, + .buffer = (void *)(&pk), + .buffer_length = sizeof(pk), + }, + [1] = { + .buffer_type = MYSQL_TYPE_LONG, + .buffer = (void *)(&value), + .buffer_length = sizeof(value), + }, + }, + .expect_result_metadata = 0, + }, + { + .query = "update test set `value` = ?", + .bind = { + [0] = { + .buffer_type = MYSQL_TYPE_STRING, + .buffer = (void *)"test string here", + .buffer_length = string_len, + .length = &string_len, + }, + }, + .expect_exec_error = 1, + .expect_result_metadata = 0, + }, + { + .query = "select * from test SYNTAX ERROR where pk = ?", + .bind = { + [0] = { + .buffer_type = MYSQL_TYPE_LONG, + .buffer = (void *)(&pk), + .buffer_length = sizeof(pk), + }, + }, + .expect_prepare_error = 1, + }, + LAST_STATEMENT, + }; + + for (int i = 0; statements[i].query; i++) { + test_statement(con, &statements[i]); + } + + mysql_close(con); + + return 0; +} + diff --git a/integration-tests/mysql-client-tests/c/mysql-connector-c-test.c b/integration-tests/mysql-client-tests/c/mysql-connector-test.c similarity index 100% rename from integration-tests/mysql-client-tests/c/mysql-connector-c-test.c rename to integration-tests/mysql-client-tests/c/mysql-connector-test.c diff --git a/integration-tests/mysql-client-tests/cpp/Makefile b/integration-tests/mysql-client-tests/cpp/Makefile index cd5210a7e2..441b42ef18 100644 --- a/integration-tests/mysql-client-tests/cpp/Makefile +++ b/integration-tests/mysql-client-tests/cpp/Makefile @@ -1,12 +1,12 @@ CXX = g++ CXXFLAGS_MYSQL = -I/usr/include/cppconn -std=c++11 -Wall -O2 -CXXFLAGS_MARIADB = -std=c++11 -Wall -O2 +CXXFLAGS_MARIADB = -I/usr/include/mariadb -std=c++11 -Wall -O2 LDFLAGS_MYSQL = -lmysqlcppconn LDFLAGS_MARIADB = -lmariadbcpp -TARGET_MYSQL = /build/bin/cpp-mysql-connector-test -TARGET_MARIADB = /build/bin/cpp-mariadb-connector-test -SRCS_MYSQL = mysql-connector-cpp-test.cpp -SRCS_MARIADB = mariadb-connector-cpp-test.cpp +TARGET_MYSQL = /build/bin/mysql-connector-test +TARGET_MARIADB = /build/bin/mariadb-connector-test +SRCS_MYSQL = mysql-connector-test.cpp +SRCS_MARIADB = mariadb-connector-test.cpp all: $(TARGET_MYSQL) $(TARGET_MARIADB) diff --git a/integration-tests/mysql-client-tests/cpp/README.md b/integration-tests/mysql-client-tests/cpp/README.md deleted file mode 100644 index 860d255c7b..0000000000 --- a/integration-tests/mysql-client-tests/cpp/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# General - -This code uses git submodules. You need to recursively pull all the submodules -in order for it to build. - -# Building on OS X - -```sh -$ brew install cmake openssl mysql-client boost -$ export PATH=/usr/local/Cellar/mysql-client/8.0.21/bin/:"$PATH" -$ mkdir _build -$ cd _build -$ cmake .. -DWITH_SSL=/usr/local/Cellar/openssl@1.1/1.1.1g/ -DWITH_JDBC=yes -$ make -j 10 -``` - -TODO: These instructions are coupled to openssl and mysql-client version that -happen to be installed... - -# Build on Ubuntu / Debian - -```sh -$ apt-get install g++ cmake libmysqlcppconn-dev -$ mkdir _build -$ cd _build -$ cmake .. -$ make -j 10 -``` diff --git a/integration-tests/mysql-client-tests/cpp/mariadb-connector-test.cpp b/integration-tests/mysql-client-tests/cpp/mariadb-connector-test.cpp new file mode 100644 index 0000000000..c7b4da1a80 --- /dev/null +++ b/integration-tests/mysql-client-tests/cpp/mariadb-connector-test.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include + +#define QUERIES_SIZE 14 + +std::string queries[QUERIES_SIZE] = + { + "create table test (pk int, `value` int, primary key(pk))", + "describe test", + "select * from test", + "insert into test (pk, `value`) values (0,0)", + "select * from test", + "call dolt_add('-A');", + "call dolt_commit('-m', 'my commit')", + "select COUNT(*) FROM dolt_log", + "call dolt_checkout('-b', 'mybranch')", + "insert into test (pk, `value`) values (1,1)", + "call dolt_commit('-a', '-m', 'my commit2')", + "call dolt_checkout('main')", + "call dolt_merge('mybranch')", + "select COUNT(*) FROM dolt_log", + }; + +int is_update[QUERIES_SIZE] = {1,0,0,1,0,0,0,0,0,1,0,0,0,0}; + +int main(int argc, char **argv) { + if (argc < 4) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + std::string user = argv[1]; + std::string port = argv[2]; + std::string db = argv[3]; + + try { + // Get the driver instance + sql::Driver* driver = sql::mariadb::get_driver_instance(); + + // Create connection properties + sql::SQLString url("jdbc:mariadb://127.0.0.1:" + port + "/" + db); + sql::Properties properties({{"user", user}, {"password", ""}}); + + // Establish connection + std::unique_ptr con(driver->connect(url, properties)); + + for ( int i = 0; i < QUERIES_SIZE; i++ ) { + try { + std::unique_ptr stmt(con->createStatement()); + + if ( is_update[i] ) { + stmt->executeUpdate(queries[i]); + } else { + std::unique_ptr res(stmt->executeQuery(queries[i])); + + // Assert that all columns have column name metadata populated + sql::ResultSetMetaData* metadata = res->getMetaData(); + const uint32_t columnCount = metadata->getColumnCount(); + for (uint32_t columnIndex = 1; columnIndex <= columnCount; ++columnIndex) { + sql::SQLString columnName = metadata->getColumnName(columnIndex); + if (columnName.length() == 0) { + std::cerr << "Column name is empty at index " << columnIndex << std::endl; + return 1; + } + } + } + } catch (sql::SQLException &e) { + std::cout << "QUERY: " << queries[i] << std::endl; + std::cout << "# ERR: " << e.what(); + std::cout << " (MariaDB error code: " << e.getErrorCode(); + std::cout << ", SQLState: " << e.getSQLState() << " )" << std::endl; + return 1; + } + } + + return 0; + } catch (sql::SQLException &e) { + std::cerr << "Connection error: " << e.what() << std::endl; + std::cerr << " (MariaDB error code: " << e.getErrorCode(); + std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl; + return 1; + } +} + diff --git a/integration-tests/mysql-client-tests/cpp/mysql-connector-cpp-test.cpp b/integration-tests/mysql-client-tests/cpp/mysql-connector-test.cpp similarity index 97% rename from integration-tests/mysql-client-tests/cpp/mysql-connector-cpp-test.cpp rename to integration-tests/mysql-client-tests/cpp/mysql-connector-test.cpp index 050dfed275..d95bccb683 100644 --- a/integration-tests/mysql-client-tests/cpp/mysql-connector-cpp-test.cpp +++ b/integration-tests/mysql-client-tests/cpp/mysql-connector-test.cpp @@ -68,7 +68,7 @@ int main(int argc, char **argv) { sql::Statement *stmt = con->createStatement(); if ( is_update[i] ) { - int affected_rows = stmt->executeUpdate(queries[i]); + stmt->executeUpdate(queries[i]); } else { sql::ResultSet *res = stmt->executeQuery(queries[i]); diff --git a/integration-tests/mysql-client-tests/dotnet/.gitignore b/integration-tests/mysql-client-tests/dotnet/.gitignore deleted file mode 100644 index da19d74625..0000000000 --- a/integration-tests/mysql-client-tests/dotnet/.gitignore +++ /dev/null @@ -1,136 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -.vs - -# User-specific files -*.suo -*.user -*.sln.docstates - -# Build results - -[Dd]ebug/ -[Rr]elease/ -x64/ -[Bb]in/ -[Oo]bj/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.log -*.svclog -*.scc - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# Click-Once directory -publish/ - -# Publish Web Output -*.Publish.xml -*.pubxml -*.azurePubxml - -# NuGet Packages Directory -## TODO: If you have NuGet Package Restore enabled, uncomment the next line -packages/ -## TODO: If the tool you use requires repositories.config, also uncomment the next line -!packages/repositories.config - -# Windows Azure Build Output -csx/ -*.build.csdef - -# Windows Store app package directory -AppPackages/ - -# Others -sql/ -*.Cache -ClientBin/ -[Ss]tyle[Cc]op.* -![Ss]tyle[Cc]op.targets -~$* -*~ -*.dbmdl -*.[Pp]ublish.xml - -*.publishsettings - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -App_Data/*.mdf -App_Data/*.ldf - -# ========================= -# Windows detritus -# ========================= - -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Mac desktop service store files -.DS_Store - -_NCrunch* -ZZ \ No newline at end of file diff --git a/integration-tests/mysql-client-tests/dotnet/MySqlClient/dotnet.csproj b/integration-tests/mysql-client-tests/dotnet/MySqlClient/dotnet.csproj index c73549a89f..d65c9db305 100644 --- a/integration-tests/mysql-client-tests/dotnet/MySqlClient/dotnet.csproj +++ b/integration-tests/mysql-client-tests/dotnet/MySqlClient/dotnet.csproj @@ -3,7 +3,7 @@ Exe net8.0 - dotnet-mysql-client-test + mysql-client-test true true diff --git a/integration-tests/mysql-client-tests/dotnet/MySqlConnector/MySqlConnectorTest.csproj b/integration-tests/mysql-client-tests/dotnet/MySqlConnector/MySqlConnectorTest.csproj index dcb8f7feb4..eb01c3e3d0 100755 --- a/integration-tests/mysql-client-tests/dotnet/MySqlConnector/MySqlConnectorTest.csproj +++ b/integration-tests/mysql-client-tests/dotnet/MySqlConnector/MySqlConnectorTest.csproj @@ -3,7 +3,7 @@ Exe net8.0 - dotnet-mysql-connector-test + mysql-connector-test true true diff --git a/integration-tests/mysql-client-tests/elixir/mysql/lib/mysql_otp/application.ex b/integration-tests/mysql-client-tests/elixir/mysql/lib/mysql_otp/application.ex new file mode 100644 index 0000000000..4f1a021333 --- /dev/null +++ b/integration-tests/mysql-client-tests/elixir/mysql/lib/mysql_otp/application.ex @@ -0,0 +1,25 @@ +defmodule MySQLOTP.Application do + use Application + + @impl true + def start(_type, _args) do + IO.puts("MySQLOTP.Application.start/2 called") + + # This is a CLI app, so we run the command and exit + # Start the application supervisor first + children = [] + opts = [strategy: :one_for_one, name: MySQLOTP.Supervisor] + + {:ok, pid} = Supervisor.start_link(children, opts) + IO.puts("Supervisor started") + + # Spawn a task to run the CLI command + IO.puts("Spawning MySQLOTPTest.main/1") + spawn(fn -> + MySQLOTPTest.main([]) + end) + + {:ok, pid} + end +end + diff --git a/integration-tests/mysql-client-tests/elixir/mysql/lib/mysql_otp_test.ex b/integration-tests/mysql-client-tests/elixir/mysql/lib/mysql_otp_test.ex new file mode 100644 index 0000000000..8cc01a032d --- /dev/null +++ b/integration-tests/mysql-client-tests/elixir/mysql/lib/mysql_otp_test.ex @@ -0,0 +1,93 @@ +defmodule MySQLOTPTest do + @moduledoc """ + Test for MySQL/OTP (Erlang native MySQL client) + Uses the :mysql Erlang library + """ + + def main(_args \\ []) do + IO.puts("Starting MySQL/OTP Test") + + cli_args = Burrito.Util.Args.get_arguments() + IO.puts("Received CLI args: #{inspect(cli_args)}") + + result = run(cli_args) + System.halt(0) + result + end + + defp run(args) do + if length(args) < 3 do + IO.puts("Usage: mysql-otp-test ") + System.halt(1) + end + + user = Enum.at(args, 0) + port_str = Enum.at(args, 1) + database = Enum.at(args, 2) + + {port, _} = Integer.parse(port_str) + + # Start MySQL/OTP connection using Erlang :mysql module + {:ok, pid} = :mysql.start_link([ + host: '127.0.0.1', + port: port, + user: String.to_charlist(user), + password: '', + database: String.to_charlist(database) + ]) + + IO.puts("Connected using MySQL/OTP (Erlang connector)") + + # Test queries + queries = [ + "create table test (pk int, `value` int, primary key(pk))", + "describe test", + "select * from test", + "insert into test (pk, `value`) values (0,0)", + "select * from test", + "call dolt_add('-A')", + "call dolt_commit('-m', 'my commit')", + "select COUNT(*) FROM dolt_log", + "call dolt_checkout('-b', 'mybranch')", + "insert into test (pk, `value`) values (1,1)", + "call dolt_commit('-a', '-m', 'my commit2')", + "call dolt_checkout('main')", + "call dolt_merge('mybranch')", + "select COUNT(*) FROM dolt_log" + ] + + # Execute each query + Enum.each(queries, fn query -> + IO.puts("Executing: #{query}") + + case :mysql.query(pid, query) do + :ok -> + IO.puts(" → OK") + + {:ok, column_names, rows} -> + IO.puts(" → #{length(rows)} row(s) returned with #{length(column_names)} column(s)") + + {:error, reason} -> + IO.puts("Query failed: #{query}") + IO.puts("Error: #{inspect(reason)}") + :mysql.stop(pid) + System.halt(1) + end + end) + + # Verify final log count + {:ok, _columns, rows} = :mysql.query(pid, "select COUNT(*) FROM dolt_log") + [[count]] = rows + + if count != 3 do + IO.puts("Expected 3 commits in dolt_log, got #{count}") + :mysql.stop(pid) + System.halt(1) + end + + :mysql.stop(pid) + IO.puts("\nAll MySQL/OTP tests passed!") + :ok + end +end + diff --git a/integration-tests/mysql-client-tests/elixir/mysql/mix.exs b/integration-tests/mysql-client-tests/elixir/mysql/mix.exs new file mode 100644 index 0000000000..31972424b8 --- /dev/null +++ b/integration-tests/mysql-client-tests/elixir/mysql/mix.exs @@ -0,0 +1,43 @@ +defmodule MySQLOTP.MixProject do + use Mix.Project + + def project do + [ + app: :mysql_otp_test, + version: "0.1.0", + elixir: "~> 1.18", + start_permanent: Mix.env() == :prod, + deps: deps(), + releases: releases() + ] + end + + def application do + [ + extra_applications: [:logger, :crypto, :public_key, :ssl], + mod: {MySQLOTP.Application, []} + ] + end + + defp releases do + [ + mysql_otp: [ + steps: [:assemble, &Burrito.wrap/1], + burrito: [ + targets: [ + linux: [os: :linux, cpu: :x86_64] + ], + no_native_archivers: true + ] + ] + ] + end + + defp deps do + [ + {:mysql, "~> 1.9.0"}, + {:burrito, "~> 1.4.0"} + ] + end +end + diff --git a/integration-tests/mysql-client-tests/elixir/lib/simple.ex b/integration-tests/mysql-client-tests/elixir/myxql/lib/simple.ex similarity index 100% rename from integration-tests/mysql-client-tests/elixir/lib/simple.ex rename to integration-tests/mysql-client-tests/elixir/myxql/lib/simple.ex diff --git a/integration-tests/mysql-client-tests/elixir/myxql/lib/simple/application.ex b/integration-tests/mysql-client-tests/elixir/myxql/lib/simple/application.ex new file mode 100644 index 0000000000..11a1363659 --- /dev/null +++ b/integration-tests/mysql-client-tests/elixir/myxql/lib/simple/application.ex @@ -0,0 +1,25 @@ +defmodule Simple.Application do + use Application + + @impl true + def start(_type, _args) do + IO.puts("Simple.Application.start/2 called") + + # This is a CLI app, so we run the command and exit + # Start the application supervisor first + children = [] + opts = [strategy: :one_for_one, name: Simple.Supervisor] + + {:ok, pid} = Supervisor.start_link(children, opts) + IO.puts("Supervisor started") + + # Spawn a task to run the CLI command + IO.puts("Spawning SmokeTest.main/1") + spawn(fn -> + SmokeTest.main([]) + end) + + {:ok, pid} + end +end + diff --git a/integration-tests/mysql-client-tests/elixir/mix.exs b/integration-tests/mysql-client-tests/elixir/myxql/mix.exs similarity index 99% rename from integration-tests/mysql-client-tests/elixir/mix.exs rename to integration-tests/mysql-client-tests/elixir/myxql/mix.exs index 5bfb76a824..27943f628f 100644 --- a/integration-tests/mysql-client-tests/elixir/mix.exs +++ b/integration-tests/mysql-client-tests/elixir/myxql/mix.exs @@ -40,3 +40,4 @@ defmodule Simple.MixProject do ] end end + diff --git a/integration-tests/mysql-client-tests/go-mysql/go-mysql-test.go b/integration-tests/mysql-client-tests/go-mysql/mysql-client-test.go similarity index 100% rename from integration-tests/mysql-client-tests/go-mysql/go-mysql-test.go rename to integration-tests/mysql-client-tests/go-mysql/mysql-client-test.go diff --git a/integration-tests/mysql-client-tests/go/go-sql-driver-mysql-test.go b/integration-tests/mysql-client-tests/go/sql-driver-mysql-test.go similarity index 100% rename from integration-tests/mysql-client-tests/go/go-sql-driver-mysql-test.go rename to integration-tests/mysql-client-tests/go/sql-driver-mysql-test.go diff --git a/integration-tests/mysql-client-tests/java/pom.xml b/integration-tests/mysql-client-tests/java/pom.xml new file mode 100644 index 0000000000..7792f5ed13 --- /dev/null +++ b/integration-tests/mysql-client-tests/java/pom.xml @@ -0,0 +1,117 @@ + + + 4.0.0 + + com.dolthub + j + 1.0.0 + + + 21 + 21 + UTF-8 + + + + + com.mysql + mysql-connector-j + 8.0.33 + + + org.mariadb.jdbc + mariadb-java-client + 3.5.3 + + + org.mariadb + r2dbc-mariadb + 1.2.2 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.1 + + + mysql-connector-test + package + shade + + mysql-connector-test + + + MySQLConnectorTest + + + + + + + + mysql-connector-test-collation + package + shade + + mysql-connector-test-collation + + + MySQLConnectorTest_Collation + + + + + + + + mariadb-connector-test + package + shade + + mariadb-connector-test + + + MariaDBConnectorTest + + + + + + + + mariadb-R2DBC-test + package + shade + + mariadb-R2DBC-test + + + MariaDBR2DBCTest + + + + + + + + + + diff --git a/integration-tests/mysql-client-tests/java/src/main/java/MariaDBConnectorTest.java b/integration-tests/mysql-client-tests/java/src/main/java/MariaDBConnectorTest.java new file mode 100644 index 0000000000..aa7e2f3e66 --- /dev/null +++ b/integration-tests/mysql-client-tests/java/src/main/java/MariaDBConnectorTest.java @@ -0,0 +1,179 @@ +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.ResultSet; +import java.util.Objects; + +public class MariaDBConnectorTest { + + // TestCase represents a single query test case + static class TestCase { + public String query; + public String expectedResult; + public Object fieldAccessor; // String (column name) or Integer (field position) + + public TestCase(String query, String expectedResult, Object fieldAccessor) { + this.query = query; + this.expectedResult = expectedResult; + this.fieldAccessor = fieldAccessor; + } + } + + // test queries to be run against Dolt + private static final TestCase[] testCases = { + new TestCase("create table test (pk int, `value` int, primary key(pk))", "0", 1), + new TestCase("describe test", "pk", 1), + new TestCase("select * from test", null, "pk"), + new TestCase("insert into test (pk, `value`) values (0,0)", "1", 1), + new TestCase("select * from test", "0", "test.pk"), + new TestCase("call dolt_add('-A')", "0", 1), + new TestCase("call dolt_commit('-m', 'my commit')", "0", 1), + new TestCase("select COUNT(*) FROM dolt_log", "2", 1), + new TestCase("call dolt_checkout('-b', 'mybranch')", "0", 1), + new TestCase("insert into test (pk, `value`) values (1,1)", "1", 1), + new TestCase("call dolt_commit('-a', '-m', 'my commit2')", "1", 1), + new TestCase("call dolt_checkout('main')", "0", 1), + new TestCase("call dolt_merge('mybranch')", "", 1), + new TestCase("select COUNT(*) FROM dolt_log", "3", "COUNT(*)"), + }; + + public static void main(String[] args) { + testStatements(args); + testServerSideCursors(args); + testCollation(args); + System.exit(0); + } + + // testServerSideCursors does a simple smoke test with server-side cursors to make sure + // results can be read. Note that we don't test results here; this is just a high level + // smoke test that we can execute server-side cursors logic without the server erroring out. + // This test was added for a regression where server-side cursor logic was getting + // corrupted result set memory and sending invalid data to the client, which caused the + // server to error out and crash the connection. If any errors are encountered, a stack trace + // is printed and this function exits with a non-zero code. + // For more details, see: https://github.com/dolthub/dolt/issues/9125 + private static void testServerSideCursors(String[] args) { + String user = args[0]; + String port = args[1]; + String db = args[2]; + + try { + // MariaDB JDBC URL format + String url = "jdbc:mariadb://127.0.0.1:" + port + "/" + db + + "?useCursorFetch=true"; + Connection conn = DriverManager.getConnection(url, user, ""); + + executePreparedQuery(conn, "SELECT 1;"); + executePreparedQuery(conn, "SELECT database();"); + executePreparedQuery(conn, "SHOW COLLATION;"); + executePreparedQuery(conn, "SHOW COLLATION;"); + executePreparedQuery(conn, "SHOW COLLATION;"); + } catch (SQLException ex) { + System.out.println("An error occurred."); + ex.printStackTrace(); + System.exit(1); + } + } + + // executePreparedQuery executes the specified |query| using |conn| as a prepared statement, + // and uses server-side cursor to fetch results. This method does not do any validation of + // results from the query. It is simply a smoke test to ensure the connection doesn't crash. + private static void executePreparedQuery(Connection conn, String query) throws SQLException { + PreparedStatement stmt = conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY); + stmt.setFetchSize(25); // needed to ensure a server-side cursor is used + + ResultSet rs = stmt.executeQuery(); + while (rs.next()) {} + + rs.close(); + stmt.close(); + } + + // testStatements executes the queries from |queries| and asserts their results from + // |expectedResults|. If any errors are encountered, a stack trace is printed and this + // function exits with a non-zero code. + private static void testStatements(String[] args) { + Connection conn = null; + + String user = args[0]; + String port = args[1]; + String db = args[2]; + + try { + // MariaDB JDBC URL format + String url = "jdbc:mariadb://127.0.0.1:" + port + "/" + db; + String password = ""; + + conn = DriverManager.getConnection(url, user, password); + Statement st = conn.createStatement(); + + for (TestCase test : testCases) { + if ( st.execute(test.query) ) { + ResultSet rs = st.getResultSet(); + if (rs.next()) { + String result = ""; + if (test.fieldAccessor instanceof String) { + result = rs.getString((String)test.fieldAccessor); + } else if (test.fieldAccessor instanceof Integer) { + result = rs.getString((Integer)test.fieldAccessor); + } else { + System.out.println("Unsupported field accessor value: " + test.fieldAccessor); + System.exit(1); + } + + if (!Objects.equals(test.expectedResult, result) && + !(test.query.contains("dolt_commit")) && + !(test.query.contains("dolt_merge"))) { + System.out.println("Query: \n" + test.query); + System.out.println("Expected:\n" + test.expectedResult); + System.out.println("Result:\n" + result); + System.exit(1); + } + } + } else { + String result = Integer.toString(st.getUpdateCount()); + if ( !Objects.equals(test.expectedResult, result) ) { + System.out.println("Query: \n" + test.query); + System.out.println("Expected:\n" + test.expectedResult); + System.out.println("Rows Updated:\n" + result); + System.exit(1); + } + } + } + } catch (SQLException ex) { + System.out.println("An error occurred."); + ex.printStackTrace(); + System.exit(1); + } + } + + // testCollation tests that metadata queries work properly with collations. + // This is a regression test for https://github.com/dolthub/dolt/issues/9890 + private static void testCollation(String[] args) { + String user = args[0]; + String port = args[1]; + String db = args[2]; + + try { + // MariaDB JDBC URL format + String url = "jdbc:mariadb://127.0.0.1:" + port + "/" + db; + Connection conn = DriverManager.getConnection(url, user, ""); + + // This should not throw an exception + ResultSet result = conn.getMetaData().getColumns(null, null, null, null); + + // Close the result set + if (result != null) { + result.close(); + } + conn.close(); + } catch (SQLException ex) { + System.out.println("Collation test failed."); + ex.printStackTrace(); + System.exit(1); + } + } +} + diff --git a/integration-tests/mysql-client-tests/java/src/main/java/MariaDBR2DBCTest.java b/integration-tests/mysql-client-tests/java/src/main/java/MariaDBR2DBCTest.java new file mode 100644 index 0000000000..7c2658db58 --- /dev/null +++ b/integration-tests/mysql-client-tests/java/src/main/java/MariaDBR2DBCTest.java @@ -0,0 +1,107 @@ +import io.r2dbc.spi.Connection; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.ConnectionFactoryOptions; +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.Result; +import org.mariadb.r2dbc.MariadbConnectionConfiguration; +import org.mariadb.r2dbc.MariadbConnectionFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +public class MariaDBR2DBCTest { + + // TestCase represents a single query test case + static class TestCase { + public String query; + public boolean isUpdate; + + public TestCase(String query, boolean isUpdate) { + this.query = query; + this.isUpdate = isUpdate; + } + } + + // test queries to be run against Dolt + private static final TestCase[] testCases = { + new TestCase("create table test (pk int, `value` int, primary key(pk))", true), + new TestCase("insert into test (pk, `value`) values (0,0)", true), + new TestCase("select * from test", false), + new TestCase("call dolt_add('-A')", false), + new TestCase("call dolt_commit('-m', 'my commit')", false), + new TestCase("select COUNT(*) FROM dolt_log", false), + new TestCase("call dolt_checkout('-b', 'mybranch')", false), + new TestCase("insert into test (pk, `value`) values (1,1)", true), + new TestCase("call dolt_commit('-a', '-m', 'my commit2')", false), + new TestCase("call dolt_checkout('main')", false), + new TestCase("call dolt_merge('mybranch')", false), + new TestCase("select COUNT(*) FROM dolt_log", false), + }; + + public static void main(String[] args) { + if (args.length < 3) { + System.err.println("Usage: MariaDBR2DBCTest "); + System.exit(1); + } + + String user = args[0]; + int port = Integer.parseInt(args[1]); + String database = args[2]; + + try { + runTests(user, port, database); + System.out.println("All R2DBC tests passed!"); + } catch (Exception e) { + System.err.println("R2DBC test failed: " + e.getMessage()); + e.printStackTrace(); + System.exit(1); + } + } + + private static void runTests(String user, int port, String database) { + // Create connection configuration + MariadbConnectionConfiguration config = MariadbConnectionConfiguration.builder() + .host("127.0.0.1") + .port(port) + .username(user) + .password("") + .database(database) + .build(); + + ConnectionFactory connectionFactory = new MariadbConnectionFactory(config); + + // Run tests reactively - block at the end for the test + Mono.from(connectionFactory.create()) + .flatMapMany(connection -> + Flux.fromArray(testCases) + .concatMap(testCase -> executeTest(connection, testCase)) + .doFinally(signalType -> + Mono.from(connection.close()).subscribe() + ) + ) + .blockLast(Duration.ofSeconds(30)); + } + + private static Mono executeTest(Connection connection, TestCase testCase) { + System.out.println("Executing: " + testCase.query); + + return Mono.from(connection.createStatement(testCase.query).execute()) + .flatMap(result -> { + if (testCase.isUpdate) { + // For updates, just get the rows affected + return Mono.from(result.getRowsUpdated()).then(); + } else { + // For selects, consume all rows + return Flux.from(result.map((row, metadata) -> row)) + .then(); + } + }) + .onErrorResume(e -> { + System.err.println("Error executing query: " + testCase.query); + System.err.println("Error: " + e.getMessage()); + return Mono.error(e); + }); + } +} + diff --git a/integration-tests/mysql-client-tests/mysql-client-tests.bats b/integration-tests/mysql-client-tests/mysql-client-tests.bats index 177b1d59d9..15e4860cb0 100644 --- a/integration-tests/mysql-client-tests/mysql-client-tests.bats +++ b/integration-tests/mysql-client-tests/mysql-client-tests.bats @@ -25,16 +25,20 @@ teardown() { fi } -@test "go go-sql-drive/mysql test" { - /build/bin/go/go-mysql-client-test $USER $PORT $REPO_NAME +@test "go go-sql-driver/mysql" { + /build/bin/go/sql-driver-mysql-test $USER $PORT $REPO_NAME } -@test "go go-mysql test" { - /build/bin/go/go-sql-driver-test $USER $PORT $REPO_NAME +@test "go go-mysql" { + /build/bin/go/mysql-client-test $USER $PORT $REPO_NAME } -@test "python mysql.connector client" { - /build/bin/python/py-mysql-connector-test $USER $PORT $REPO_NAME +@test "python mysql.connector" { + /build/bin/python/mysql-connector-test $USER $PORT $REPO_NAME +} + +@test "python mariadb connector" { + /build/bin/python/mariadb-connector-test $USER $PORT $REPO_NAME } @test "python pymysql client" { @@ -42,67 +46,87 @@ teardown() { } @test "python sqlachemy client" { - /build/bin/python/py-sqlalchemy-test $USER $PORT $REPO_NAME + /build/bin/python/sqlalchemy-test $USER $PORT $REPO_NAME } -@test "mysql-connector-java client" { +@test "java mysql-connector-j" { java -jar /build/bin/java/mysql-connector-test.jar $USER $PORT $REPO_NAME } -@test "mysql-connector-java client collations" { +@test "java mysql-connector-j collation" { java -jar /build/bin/java/mysql-connector-test-collation.jar $USER $PORT $REPO_NAME } +@test "java mariadb-java-client" { + java -jar /build/bin/java/mariadb-connector-test.jar $USER $PORT $REPO_NAME +} + +@test "java r2dbc-mariadb connector" { + java -jar /build/bin/java/mariadb-R2DBC-test.jar $USER $PORT $REPO_NAME +} + @test "node mysql client" { node /build/bin/node/index.js $USER $PORT $REPO_NAME node /build/bin/node/knex.js $USER $PORT $REPO_NAME } +@test "node mariadb connector" { + node /build/bin/node/mariadb-connector.js $USER $PORT $REPO_NAME +} + @test "node mysql client, hosted workbench stability" { node /build/bin/node/workbench.js $USER $PORT $REPO_NAME /build/bin/node/testdata } -@test "c mysql connector" { - /build/bin/c/c-mysql-client-test $USER $PORT $REPO_NAME +@test "c mysql client" { + /build/bin/c/mysql-client-test $USER $PORT $REPO_NAME } -@test "c mariadb connector" { - /build/bin/c/c-mariadb-client-test $USER $PORT $REPO_NAME +@test "c mariadb client" { + /build/bin/c/mariadb-client-test $USER $PORT $REPO_NAME } @test "cpp mysql connector" { - /build/bin/cpp/cpp-mysql-connector-test $USER $PORT $REPO_NAME + /build/bin/cpp/mysql-connector-test $USER $PORT $REPO_NAME } @test "cpp mariadb connector" { - /build/bin/cpp/cpp-mariadb-connector-test $USER $PORT $REPO_NAME + /build/bin/cpp/mariadb-connector-test $USER $PORT $REPO_NAME } @test "dotnet mysql connector" { - /build/bin/dotnet/dotnet-mysql-connector-test $USER $PORT $REPO_NAME + /build/bin/dotnet/mysql-connector-test $USER $PORT $REPO_NAME } @test "dotnet mysql client" { - /build/bin/dotnet/dotnet-mysql-client-test $USER $PORT $REPO_NAME + /build/bin/dotnet/mysql-client-test $USER $PORT $REPO_NAME } @test "perl DBD:mysql client" { perl /build/bin/perl/dbd-mysql-test.pl $USER $PORT $REPO_NAME } -@test "ruby ruby/mysql test" { - ruby /build/bin/ruby/ruby-mysql-test.rb $USER $PORT $REPO_NAME +@test "perl DBD:MariaDB client" { + perl /build/bin/perl/dbd-mariadb-test.pl $USER $PORT $REPO_NAME } -@test "ruby mysql2 test" { +@test "ruby ruby/mysql client" { + ruby /build/bin/ruby/mysql-client-test.rb $USER $PORT $REPO_NAME +} + +@test "ruby mysql2" { ruby /build/bin/ruby/mysql2-test.rb $USER $PORT $REPO_NAME } -@test "elixir myxql test" { - /build/bin/elixir/elixir-mysql-client-test $USER $PORT $REPO_NAME +@test "elixir myxql" { + /build/bin/elixir/myxql-driver-test $USER $PORT $REPO_NAME } -@test "mysqldump works" { +@test "elixir mysql-otp" { + /build/bin/elixir/mysql-otp-test $USER $PORT $REPO_NAME +} + +@test "mysqldump" { mysqldump $REPO_NAME -P $PORT -h 0.0.0.0 -u $USER } diff --git a/integration-tests/mysql-client-tests/node/mariadb-connector.js b/integration-tests/mysql-client-tests/node/mariadb-connector.js new file mode 100644 index 0000000000..c76e0ebcb7 --- /dev/null +++ b/integration-tests/mysql-client-tests/node/mariadb-connector.js @@ -0,0 +1,70 @@ +import mariadb from "mariadb"; +import { getArgs } from "./helpers.js"; + +const tests = [ + { q: "create table test (pk int, `value` int, primary key(pk))", isQuery: false }, + { q: "describe test", isQuery: true }, + { q: "select * from test", isQuery: true }, + { q: "insert into test (pk, `value`) values (0,0)", isQuery: false }, + { q: "select * from test", isQuery: true }, + { q: "call dolt_add('-A');", isQuery: true }, + { q: "call dolt_commit('-m', 'my commit')", isQuery: true }, + { q: "select COUNT(*) FROM dolt_log", isQuery: true }, + { q: "call dolt_checkout('-b', 'mybranch')", isQuery: true }, + { q: "insert into test (pk, `value`) values (1,1)", isQuery: false }, + { q: "call dolt_commit('-a', '-m', 'my commit2')", isQuery: true }, + { q: "call dolt_checkout('main')", isQuery: true }, + { q: "call dolt_merge('mybranch')", isQuery: true }, + { q: "select COUNT(*) FROM dolt_log", isQuery: true }, +]; + +async function main() { + const { user, port, dbName } = getArgs(); + + let conn; + try { + // Create connection pool + const pool = mariadb.createPool({ + host: "127.0.0.1", + port: port, + user: user, + database: dbName, + connectionLimit: 5, + }); + + // Get a connection from the pool + conn = await pool.getConnection(); + console.log("Connected to MariaDB!"); + + // Run all tests + for (const test of tests) { + console.log(`Executing: ${test.q}`); + + if (test.isQuery) { + // Execute query and fetch results + const rows = await conn.query(test.q); + console.log(` → ${rows.length} row(s) returned`); + } else { + // Execute update/insert + const result = await conn.query(test.q); + console.log(` → ${result.affectedRows} row(s) affected`); + } + } + + console.log("\nAll MariaDB connector tests passed!"); + + // Close connection and pool + if (conn) conn.release(); + await pool.end(); + + process.exit(0); + } catch (err) { + console.error("MariaDB connector test failed:"); + console.error(err); + if (conn) conn.release(); + process.exit(1); + } +} + +main(); + diff --git a/integration-tests/mysql-client-tests/node/package.json b/integration-tests/mysql-client-tests/node/package.json index ef66fdd14a..add06a0339 100644 --- a/integration-tests/mysql-client-tests/node/package.json +++ b/integration-tests/mysql-client-tests/node/package.json @@ -11,6 +11,7 @@ "license": "ISC", "dependencies": { "knex": "^2.4.0", + "mariadb": "^3.4.5", "mysql": "^2.18.1", "mysql2": "^3.9.8", "wtfnode": "^0.9.1", diff --git a/integration-tests/mysql-client-tests/perl/dbd-mariadb-test.pl b/integration-tests/mysql-client-tests/perl/dbd-mariadb-test.pl new file mode 100644 index 0000000000..588dba06e5 --- /dev/null +++ b/integration-tests/mysql-client-tests/perl/dbd-mariadb-test.pl @@ -0,0 +1,46 @@ +use strict; + +use DBI; + +my $QUERY_RESPONSE = [ + { "create table test (pk int, `value` int, primary key(pk))" => '0E0' }, + { "describe test" => 2 }, + { "insert into test (pk, `value`) values (0,0)" => 1 }, + { "select * from test" => 1 }, + {"call dolt_add('-A');" => 1 }, + {"call dolt_commit('-m', 'my commit')" => 1}, + {"call dolt_checkout('-b', 'mybranch')" => 1 }, + {"insert into test (pk, `value`) values (1,1)" => 1 }, + {"call dolt_commit('-a', '-m', 'my commit2')" => 1 }, + {"call dolt_checkout('main')" => 1 }, + {"call dolt_merge('mybranch')" => 1 }, + {"select COUNT(*) FROM dolt_log" => 1 }, +]; + +my $user = $ARGV[0]; +my $port = $ARGV[1]; +my $db = $ARGV[2]; + +# Use DBD::MariaDB driver +my $dsn = "DBI:MariaDB:database=$db;host=127.0.0.1;port=$port"; +my $dbh = DBI->connect($dsn, $user, "", {PrintError => 1, RaiseError => 1}); + +print "Connected using DBD::MariaDB\n"; + +foreach my $query_response ( @{$QUERY_RESPONSE} ) { + my @query_keys = keys %{$query_response}; + my $query = $query_keys[0]; + my $exp_result = $query_response->{$query}; + + my $result = $dbh->do($query); + if ( $result != $exp_result ) { + print "QUERY: $query\n"; + print "EXPECTED: $exp_result\n"; + print "RESULT: $result\n"; + exit 1 + } +} + +print "All DBD::MariaDB tests passed!\n"; +exit 0; + diff --git a/integration-tests/mysql-client-tests/python/mariadb-connector-test.py b/integration-tests/mysql-client-tests/python/mariadb-connector-test.py new file mode 100644 index 0000000000..ff9af39c3c --- /dev/null +++ b/integration-tests/mysql-client-tests/python/mariadb-connector-test.py @@ -0,0 +1,81 @@ +import mariadb +import sys + +QUERY_RESPONSE = [ + {"create table test (pk int, `value` int, primary key(pk))": ()}, + {"describe test": ( + ('pk', 'int', 'NO', 'PRI', None, ''), + ('value', 'int', 'YES', '', None, '') + )}, + {"insert into test (pk, `value`) values (0,0)": ()}, + {"select * from test": ((0, 0),)}, + {"call dolt_add('-A');": ((0,),)}, + {"call dolt_commit('-m', 'my commit')": (('',),)}, + {"select COUNT(*) FROM dolt_log": ((2,),)}, + {"call dolt_checkout('-b', 'mybranch')": ((0, "Switched to branch 'mybranch'"),)}, + {"insert into test (pk, `value`) values (1,1)": ()}, + {"call dolt_commit('-a', '-m', 'my commit2')": (('',),)}, + {"call dolt_checkout('main')": ((0, "Switched to branch 'main'"),)}, + {"call dolt_merge('mybranch')": (('',1,0,),)}, + {"select COUNT(*) FROM dolt_log": ((3,),)}, +] + + +def main(): + user = sys.argv[1] + port = int(sys.argv[2]) + db = sys.argv[3] + + try: + # Connect using MariaDB Connector/Python + connection = mariadb.connect( + user=user, + host="127.0.0.1", + port=port, + database=db + ) + + print(f"Connected to MariaDB using MariaDB Connector/Python v{mariadb.__version__}") + + cursor = connection.cursor() + + for query_response in QUERY_RESPONSE: + query = list(query_response.keys())[0] + exp_results = query_response[query] + + cursor.execute(query) + + try: + results = cursor.fetchall() + + # MariaDB Connector/Python returns lists, convert to tuples for comparison + results = tuple(tuple(row) if isinstance(row, list) else row for row in results) + + # Skip validation for dolt_commit and dolt_merge as their results vary + if ("dolt_commit" not in query) and ("dolt_merge" not in query): + if results != exp_results: + print("Query:") + print(query) + print("Expected:") + print(exp_results) + print("Received:") + print(results) + sys.exit(1) + except mariadb.Error: + # This is a write query with no results + pass + + cursor.close() + connection.close() + + print("All MariaDB Connector/Python tests passed!") + sys.exit(0) + + except mariadb.Error as e: + print(f"Error connecting to MariaDB: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() + diff --git a/integration-tests/mysql-client-tests/python/py-mysql-connector-test.py b/integration-tests/mysql-client-tests/python/mysql-connector-test.py similarity index 100% rename from integration-tests/mysql-client-tests/python/py-mysql-connector-test.py rename to integration-tests/mysql-client-tests/python/mysql-connector-test.py diff --git a/integration-tests/mysql-client-tests/python/pymysql-test.py b/integration-tests/mysql-client-tests/python/pymysql-test.py index ab542ce06c..f7cf4385a3 100644 --- a/integration-tests/mysql-client-tests/python/pymysql-test.py +++ b/integration-tests/mysql-client-tests/python/pymysql-test.py @@ -1,54 +1,54 @@ -import pymysql -import sys - -QUERY_RESPONSE = [ - {"create table test (pk int, `value` int, primary key(pk))": ()}, - {"describe test": ( - ('pk', 'int', 'NO', 'PRI', None, ''), - ('value', 'int', 'YES', '', None, '') - )}, - {"insert into test (pk, `value`) values (0,0)": ()}, - {"select * from test": ((0, 0),)}, - {"call dolt_add('-A');": ((0,),)}, - {"call dolt_commit('-m', 'my commit')": (('',),)}, - {"select COUNT(*) FROM dolt_log": ((2,),)}, - {"call dolt_checkout('-b', 'mybranch')": ((0, "Switched to branch 'mybranch'"),)}, - {"insert into test (pk, `value`) values (1,1)": ()}, - {"call dolt_commit('-a', '-m', 'my commit2')": (('',),)}, - {"call dolt_checkout('main')": ((0, "Switched to branch 'main'"),)}, - {"call dolt_merge('mybranch')": (('',1,0,),)}, - {"select COUNT(*) FROM dolt_log": ((3,),)}, -] - - -def main(): - user = sys.argv[1] - port = int(sys.argv[2]) - db = sys.argv[3] - - connection = pymysql.connect(host="127.0.0.1", - port=port, - user=user, - db=db) - - for query_response in QUERY_RESPONSE: - query = list(query_response.keys())[0] - exp_results = query_response[query] - with connection.cursor() as cursor: - cursor.execute(query) - results = cursor.fetchall() - if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): - print("Query:") - print(query) - print("Expected:") - print(exp_results) - print("Received:") - print(results) - sys.exit(1) - - connection.close() - - sys.exit(0) - - -main() +import pymysql +import sys + +QUERY_RESPONSE = [ + {"create table test (pk int, `value` int, primary key(pk))": ()}, + {"describe test": ( + ('pk', 'int', 'NO', 'PRI', None, ''), + ('value', 'int', 'YES', '', None, '') + )}, + {"insert into test (pk, `value`) values (0,0)": ()}, + {"select * from test": ((0, 0),)}, + {"call dolt_add('-A');": ((0,),)}, + {"call dolt_commit('-m', 'my commit')": (('',),)}, + {"select COUNT(*) FROM dolt_log": ((2,),)}, + {"call dolt_checkout('-b', 'mybranch')": ((0, "Switched to branch 'mybranch'"),)}, + {"insert into test (pk, `value`) values (1,1)": ()}, + {"call dolt_commit('-a', '-m', 'my commit2')": (('',),)}, + {"call dolt_checkout('main')": ((0, "Switched to branch 'main'"),)}, + {"call dolt_merge('mybranch')": (('',1,0,),)}, + {"select COUNT(*) FROM dolt_log": ((3,),)}, +] + + +def main(): + user = sys.argv[1] + port = int(sys.argv[2]) + db = sys.argv[3] + + connection = pymysql.connect(host="127.0.0.1", + port=port, + user=user, + db=db) + + for query_response in QUERY_RESPONSE: + query = list(query_response.keys())[0] + exp_results = query_response[query] + with connection.cursor() as cursor: + cursor.execute(query) + results = cursor.fetchall() + if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): + print("Query:") + print(query) + print("Expected:") + print(exp_results) + print("Received:") + print(results) + sys.exit(1) + + connection.close() + + sys.exit(0) + + +main() diff --git a/integration-tests/mysql-client-tests/python/py-sqlalchemy-test.py b/integration-tests/mysql-client-tests/python/sqlalchemy-test.py similarity index 100% rename from integration-tests/mysql-client-tests/python/py-sqlalchemy-test.py rename to integration-tests/mysql-client-tests/python/sqlalchemy-test.py diff --git a/integration-tests/mysql-client-tests/r/rmariadb-test.r b/integration-tests/mysql-client-tests/r/rmariadb-test.r index 7cae8d7de0..0481b4f347 100644 --- a/integration-tests/mysql-client-tests/r/rmariadb-test.r +++ b/integration-tests/mysql-client-tests/r/rmariadb-test.r @@ -1,89 +1,89 @@ -library(RMariaDB) -library(DBI) - -args = commandArgs(trailingOnly=TRUE) - -user = args[1] -port = args[2] -db = args[3] - -conn = dbConnect(RMariaDB::MariaDB(), host="127.0.0.1", port = port, - username = user, dbname = db) - -# check standard queries -queries = list("create table test (pk int, value int, primary key(pk))", - "describe test", - "insert into test (pk, `value`) values (0,0)", - "select * from test") - -responses = list(NULL, - data.frame(Field = c("pk", "value"), Type = c("int", "int"), Null = c("NO", "YES"), Key = c("PRI", ""), Default = c(NA_character_, NA_character_), Extra = c("", ""), stringsAsFactors = FALSE), - NULL, - data.frame(pk = c(0), value = c(0), stringsAsFactors = FALSE)) - -for(i in 1:length(queries)) { - q = queries[[i]] - want = responses[[i]] - if (!is.null(want)) { - got <- dbGetQuery(conn, q) - if (!isTRUE(all.equal(want, got))) { - print(q) - print(want) - print(got) - quit(save="no", status=1) - } - } else { - dbExecute(conn, q) - } -} - -# check prepared statements -stmt <- dbSendStatement(conn, "INSERT INTO test values (?, ?)") -rs <- dbBind(stmt, list(1,1)) -rowsAff <- dbGetRowsAffected(rs) -dbClearResult(rs) - -if (rowsAff != 1) { - print("failed to execute prepared statement") - quit(save="no", status=1) -} - -got <- dbGetQuery(conn, "select * from test where pk = 1") -want = data.frame(pk = c(1), value = c(1)) -if (!isTRUE(all.equal(want, got))) { - print("unexpected prepared statement result") - print(got) - quit(save="no", status=1) -} - -dolt_queries = list("call DOLT_ADD('-A')", - "call dolt_commit('-m', 'my commit')", - "call dolt_checkout('-b', 'mybranch')", - "insert into test (pk, `value`) values (2,2)", - "call dolt_commit('-a', '-m', 'my commit2')", - "call dolt_checkout('main')", - "call dolt_merge('mybranch')") - -for(i in 1:length(dolt_queries)) { - q = dolt_queries[[i]] - dbExecute(conn, q) -} - -count <- dbGetQuery(conn, "select COUNT(*) as c from dolt_log") -want <- data.frame(c = c(3)) -ret <- all.equal(count, want) -if (!ret) { - print("Number of commits is incorrect") - quit(save="no", status=1) -} - -# Add a failing query and ensure that the connection does not quit. -# cc. https://github.com/dolthub/dolt/issues/3418 -try(dbExecute(conn, "insert into test values (0, 1)"), silent = TRUE) -one <- dbGetQuery(conn, "select 1 as pk") -ret <- one == data.frame(pk=1) -if (!ret) { - print("Number of commits is incorrect") - quit(save="no", status=1) -} - +library(RMariaDB) +library(DBI) + +args = commandArgs(trailingOnly=TRUE) + +user = args[1] +port = args[2] +db = args[3] + +conn = dbConnect(RMariaDB::MariaDB(), host="127.0.0.1", port = port, + username = user, dbname = db) + +# check standard queries +queries = list("create table test (pk int, value int, primary key(pk))", + "describe test", + "insert into test (pk, `value`) values (0,0)", + "select * from test") + +responses = list(NULL, + data.frame(Field = c("pk", "value"), Type = c("int", "int"), Null = c("NO", "YES"), Key = c("PRI", ""), Default = c(NA_character_, NA_character_), Extra = c("", ""), stringsAsFactors = FALSE), + NULL, + data.frame(pk = c(0), value = c(0), stringsAsFactors = FALSE)) + +for(i in 1:length(queries)) { + q = queries[[i]] + want = responses[[i]] + if (!is.null(want)) { + got <- dbGetQuery(conn, q) + if (!isTRUE(all.equal(want, got))) { + print(q) + print(want) + print(got) + quit(save="no", status=1) + } + } else { + dbExecute(conn, q) + } +} + +# check prepared statements +stmt <- dbSendStatement(conn, "INSERT INTO test values (?, ?)") +rs <- dbBind(stmt, list(1,1)) +rowsAff <- dbGetRowsAffected(rs) +dbClearResult(rs) + +if (rowsAff != 1) { + print("failed to execute prepared statement") + quit(save="no", status=1) +} + +got <- dbGetQuery(conn, "select * from test where pk = 1") +want = data.frame(pk = c(1), value = c(1)) +if (!isTRUE(all.equal(want, got))) { + print("unexpected prepared statement result") + print(got) + quit(save="no", status=1) +} + +dolt_queries = list("call DOLT_ADD('-A')", + "call dolt_commit('-m', 'my commit')", + "call dolt_checkout('-b', 'mybranch')", + "insert into test (pk, `value`) values (2,2)", + "call dolt_commit('-a', '-m', 'my commit2')", + "call dolt_checkout('main')", + "call dolt_merge('mybranch')") + +for(i in 1:length(dolt_queries)) { + q = dolt_queries[[i]] + dbExecute(conn, q) +} + +count <- dbGetQuery(conn, "select COUNT(*) as c from dolt_log") +want <- data.frame(c = c(3)) +ret <- all.equal(count, want) +if (!ret) { + print("Number of commits is incorrect") + quit(save="no", status=1) +} + +# Add a failing query and ensure that the connection does not quit. +# cc. https://github.com/dolthub/dolt/issues/3418 +try(dbExecute(conn, "insert into test values (0, 1)"), silent = TRUE) +one <- dbGetQuery(conn, "select 1 as pk") +ret <- one == data.frame(pk=1) +if (!ret) { + print("Number of commits is incorrect") + quit(save="no", status=1) +} + diff --git a/integration-tests/mysql-client-tests/ruby/ruby-mysql-test.rb b/integration-tests/mysql-client-tests/ruby/mysql-client-test.rb similarity index 100% rename from integration-tests/mysql-client-tests/ruby/ruby-mysql-test.rb rename to integration-tests/mysql-client-tests/ruby/mysql-client-test.rb From 9fe5cf744e683e1d125f1e51d762c484e36f0c0c Mon Sep 17 00:00:00 2001 From: elianddb Date: Sun, 12 Oct 2025 17:23:02 -0700 Subject: [PATCH 06/14] amend workflow to use correct dir --- .../actions/mysql-client-tests/action.yaml | 6 - .github/workflows/ci-mysql-client-tests.yaml | 29 +++- integration-tests/MySQLDockerfile | 149 ------------------ .../MySQLDockerfile.dockerignore | 5 - .../mysql-client-tests/Dockerfile | 36 +++-- .../Dockerfile.dockerignore | 3 + .../mysql-client-tests.bats | 2 +- .../mysql-client-tests/python/pymysql-test.py | 108 ++++++------- .../mysql-client-tests/rust/Cargo.toml | 2 +- 9 files changed, 102 insertions(+), 238 deletions(-) delete mode 100644 .github/actions/mysql-client-tests/action.yaml delete mode 100644 integration-tests/MySQLDockerfile delete mode 100644 integration-tests/MySQLDockerfile.dockerignore rename {.github/actions => integration-tests}/mysql-client-tests/Dockerfile (99%) rename {.github/actions => integration-tests}/mysql-client-tests/Dockerfile.dockerignore (57%) diff --git a/.github/actions/mysql-client-tests/action.yaml b/.github/actions/mysql-client-tests/action.yaml deleted file mode 100644 index bbb9239830..0000000000 --- a/.github/actions/mysql-client-tests/action.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 'Dolt MySQL client integration tests' -description: 'Smoke tests for mysql client integrations' -runs: - using: 'docker' - image: 'Dockerfile' - context: '../../../../' diff --git a/.github/workflows/ci-mysql-client-tests.yaml b/.github/workflows/ci-mysql-client-tests.yaml index 18017f8bc9..5e07238019 100644 --- a/.github/workflows/ci-mysql-client-tests.yaml +++ b/.github/workflows/ci-mysql-client-tests.yaml @@ -10,15 +10,34 @@ concurrency: group: ci-mysql-client-tests-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true + jobs: mysql_client_integrations_job: runs-on: ubuntu-22.04 timeout-minutes: 45 - name: Run tests steps: + - name: Remove unused tools + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + - name: Checkout uses: actions/checkout@v4 - - name: Copy go package - run: cp -r ./go ./integration-tests/go - - name: Test mysql client integrations - uses: ./.github/actions/mysql-client-tests + with: + path: dolt + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build MySQL test image + uses: docker/build-push-action@v4 + with: + context: . + file: dolt/integration-tests/mysql-client-tests/Dockerfile + tags: mysql-client-tests:latest + load: true + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Test MySQL client integrations + run: docker run --rm mysql-client-tests:latest diff --git a/integration-tests/MySQLDockerfile b/integration-tests/MySQLDockerfile deleted file mode 100644 index 7f57cf3c16..0000000000 --- a/integration-tests/MySQLDockerfile +++ /dev/null @@ -1,149 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:20.04 - -# install python, libmysqlclient-dev, java, bats, git ruby, perl, cpan -ENV DEBIAN_FRONTEND=noninteractive -RUN apt update -y && \ - apt install -y \ - curl \ - gnupg \ - libwxbase3.0-0v5 \ - libwxgtk3.0-gtk3-0v5 \ - libncurses5 \ - libsctp1 \ - software-properties-common && \ - curl -sL https://deb.nodesource.com/setup_22.x | bash - && \ - add-apt-repository ppa:deadsnakes/ppa -y && \ - curl -OL https://binaries2.erlang-solutions.com/ubuntu/pool/contrib/e/esl-erlang/esl-erlang_25.0-1~ubuntu~focal_amd64.deb && \ - dpkg -i esl-erlang_25.0-1~ubuntu~focal_amd64.deb && \ - curl -LO https://binaries2.erlang-solutions.com/ubuntu/pool/contrib/e/elixir/elixir_1.14.3_1_otp_25.3~ubuntu~focal_all.deb && \ - dpkg -i elixir_1.14.3_1_otp_25.3~ubuntu~focal_all.deb -RUN apt update -y && \ - apt install -y \ - python3.9 \ - python3-pip \ - curl \ - wget \ - pkg-config \ - mysql-client \ - libmysqlclient-dev \ - openjdk-17-jdk \ - ant \ - ca-certificates-java \ - bats \ - perl \ - php \ - php-mysqli \ - cpanminus \ - cmake \ - g++ \ - libmysqlcppconn-dev \ - git \ - ruby \ - ruby-dev \ - gem \ - libc6 \ - libgcc1 \ - libgssapi-krb5-2 \ - libicu66 \ - libssl1.1 \ - libstdc++6 \ - zlib1g \ - r-base \ - postgresql \ - postgresql-contrib \ - libpq-dev \ - nodejs \ - lsof \ - postgresql-server-dev-all && \ - update-ca-certificates -f - -# install go -WORKDIR /root -ENV GO_VERSION=1.25.0 -ENV GOPATH=$HOME/go -ENV PATH=$PATH:$GOPATH/bin -ENV PATH=$PATH:$GOPATH/bin:/usr/local/go/bin -RUN curl -O "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" && \ - sha256sum "go${GO_VERSION}.linux-amd64.tar.gz" && \ - tar -xvf "go${GO_VERSION}.linux-amd64.tar.gz" -C /usr/local && \ - chown -R root:root /usr/local/go && \ - mkdir -p $HOME/go/{bin,src} && \ - go version - -# install MySQL dependency from source -RUN git clone https://github.com/go-sql-driver/mysql.git -WORKDIR mysql -RUN git checkout tags/v1.6.0 -b v1.6.0 -RUN go install . -WORKDIR / - -# install dotnet -RUN curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --version 8.0.412 --install-dir /usr/local/bin --no-path && \ - dotnet --version - -# install pip for python3.9 -RUN curl -LO https://bootstrap.pypa.io/get-pip.py && \ - python3.9 get-pip.py && \ - pip --version - -# install mysql connector and pymsql -RUN pip install mysql-connector-python==8.0.32 -RUN pip install PyMySQL==1.0.2 -RUN pip install sqlalchemy==1.4.46 - -# Setup JAVA_HOME -- useful for docker commandline -ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64/ - -# install mysql connector java -RUN mkdir -p /mysql-client-tests/java -RUN curl -L -o /mysql-client-tests/java/mysql-connector-java-8.0.21.jar \ - https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.21/mysql-connector-java-8.0.21.jar - -# install node deps -COPY mysql-client-tests/node/package.json /mysql-client-tests/node/ -COPY mysql-client-tests/node/package-lock.json /mysql-client-tests/node/ -WORKDIR /mysql-client-tests/node -RUN npm install - -# install cpan dependencies -RUN cpanm --force DBD::mysql - -# install ruby dependencies -COPY mysql-client-tests/ruby/Gemfile /mysql-client-tests/ruby/ -COPY mysql-client-tests/ruby/Gemfile.lock /mysql-client-tests/ruby/ -WORKDIR /mysql-client-tests/ruby -RUN gem install bundler -v 2.1.4 && bundle install - -# install R packages -RUN Rscript -e 'install.packages(c("DBI", "RMySQL", "RMariaDB"), \ - repos = c(RSPM="https://packagemanager.rstudio.com/cran/__linux__/focal/latest"))' - -# install rust -RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y -ENV PATH="/root/.cargo/bin:${PATH}" - -# install postgres and psql -RUN service postgresql start - -# install mysql_fdw -WORKDIR /mysql-client-tests/mysql_fdw -RUN git clone https://github.com/EnterpriseDB/mysql_fdw --branch REL-2_9_0 -WORKDIR /mysql-client-tests/mysql_fdw/mysql_fdw -RUN make USE_PGXS=1 && \ - make USE_PGXS=1 install - -# install dolt from source -WORKDIR /root/building -COPY ./go . -ENV GOFLAGS="-mod=readonly" -RUN go build -o /usr/local/bin/dolt ./cmd/dolt - -COPY mysql-client-tests /mysql-client-tests -COPY mysql-client-tests/mysql-client-tests-entrypoint.sh /mysql-client-tests/entrypoint.sh - -# install rust dependencies -WORKDIR /mysql-client-tests/rust -RUN cargo build --config net.git-fetch-with-cli=true - -WORKDIR /mysql-client-tests -ENTRYPOINT ["/mysql-client-tests/entrypoint.sh"] diff --git a/integration-tests/MySQLDockerfile.dockerignore b/integration-tests/MySQLDockerfile.dockerignore deleted file mode 100644 index efcd3e81bf..0000000000 --- a/integration-tests/MySQLDockerfile.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -mysql-client-tests/c/mysql-client-tests -mysql-client-tests/java/MySQLConnectorTest.class -mysql-client-tests/cpp/_build/**/* -mysql-client-tests/cpp/_build -bats diff --git a/.github/actions/mysql-client-tests/Dockerfile b/integration-tests/mysql-client-tests/Dockerfile similarity index 99% rename from .github/actions/mysql-client-tests/Dockerfile rename to integration-tests/mysql-client-tests/Dockerfile index c5a651b6e5..c2e4b8ef61 100644 --- a/.github/actions/mysql-client-tests/Dockerfile +++ b/integration-tests/mysql-client-tests/Dockerfile @@ -103,9 +103,6 @@ WORKDIR /build/bin/ RUN npm install --omit=dev COPY dolt/integration-tests/mysql-client-tests/node/ /build/bin/ -FROM php:8.3-bookworm AS php_deps -RUN docker-php-ext-install mysqli pdo_mysql - FROM ruby:3.4-bookworm AS ruby_clients_build RUN apt-get update && apt-get install -y default-libmysqlclient-dev && rm -rf /var/lib/apt/lists/* COPY dolt/integration-tests/mysql-client-tests/ruby/Gemfile /build/ruby/ @@ -113,6 +110,9 @@ WORKDIR /build/ruby/ RUN bundle install COPY dolt/integration-tests/mysql-client-tests/ruby/ /build/bin/ +FROM php:8.3-bookworm AS php_deps +RUN docker-php-ext-install mysqli pdo_mysql + FROM debian:bookworm-slim AS r_deps RUN apt-get update && apt-get install -y r-base-core libmariadb-dev && rm -rf /var/lib/apt/lists/* WORKDIR /build/r/ @@ -132,21 +132,8 @@ RUN apt-get update && apt-get install -y \ bats \ && rm -rf /var/lib/apt/lists/* +# Runtime COPY --from=dolt_build /build/bin/ /usr/local/bin/ -COPY --from=go_clients_build /build/bin/ /build/bin/go/ -COPY --from=rust_clients_build /build/bin/release/ /build/bin/rust/ -COPY --from=dotnet_clients_build /build/bin/ /build/bin/dotnet/ -COPY --from=c_clients_build /build/bin/ /build/bin/c/ -COPY --from=cpp_clients_build /build/bin/ /build/bin/cpp/ -COPY --from=python_clients_build /build/python/dist/ /build/bin/python/ -COPY --from=elixir_clients_build /build/bin/ /build/bin/elixir/ -COPY --from=java_clients_build /build/java/target/ /build/bin/java/ -COPY --from=node_clients_build /build/bin/ /build/bin/node/ -COPY dolt/integration-tests/mysql-client-tests/php/ /build/bin/php/ -COPY --from=ruby_clients_build /build/bin/ /build/bin/ruby/ -COPY dolt/integration-tests/mysql-client-tests/r/ /build/bin/r/ -COPY dolt/integration-tests/mysql-client-tests/perl/ /build/bin/perl/ - COPY --from=cpp_clients_build /usr/lib/x86_64-linux-gnu/libmariadb* /usr/lib/x86_64-linux-gnu/ COPY --from=cpp_clients_build /usr/include/mariadb/ /usr/include/mariadb/ COPY --from=java_clients_build /build/jre/ /opt/jre/ @@ -162,6 +149,21 @@ ENV PATH="/opt/jre/bin:/usr/local/bundle/bin:${PATH}" ENV GEM_HOME="/usr/local/bundle" ENV BUNDLE_APP_CONFIG="/usr/local/bundle" +# Binaries +COPY --from=go_clients_build /build/bin/ /build/bin/go/ +COPY --from=rust_clients_build /build/bin/release/ /build/bin/rust/ +COPY --from=dotnet_clients_build /build/bin/ /build/bin/dotnet/ +COPY --from=c_clients_build /build/bin/ /build/bin/c/ +COPY --from=cpp_clients_build /build/bin/ /build/bin/cpp/ +COPY --from=python_clients_build /build/python/dist/ /build/bin/python/ +COPY --from=elixir_clients_build /build/bin/ /build/bin/elixir/ +COPY --from=java_clients_build /build/java/target/ /build/bin/java/ +COPY --from=node_clients_build /build/bin/ /build/bin/node/ +COPY dolt/integration-tests/mysql-client-tests/php/ /build/bin/php/ +COPY --from=ruby_clients_build /build/bin/ /build/bin/ruby/ +COPY dolt/integration-tests/mysql-client-tests/r/ /build/bin/r/ +COPY dolt/integration-tests/mysql-client-tests/perl/ /build/bin/perl/ + COPY dolt/integration-tests/mysql-client-tests/mysql-client-tests.bats /build/bin/ COPY dolt/integration-tests/mysql-client-tests/helpers.bash /build/bin/ COPY dolt/integration-tests/mysql-client-tests/mysql-client-tests-entrypoint.sh /entrypoint.sh diff --git a/.github/actions/mysql-client-tests/Dockerfile.dockerignore b/integration-tests/mysql-client-tests/Dockerfile.dockerignore similarity index 57% rename from .github/actions/mysql-client-tests/Dockerfile.dockerignore rename to integration-tests/mysql-client-tests/Dockerfile.dockerignore index b92337fd15..c132eeedba 100644 --- a/.github/actions/mysql-client-tests/Dockerfile.dockerignore +++ b/integration-tests/mysql-client-tests/Dockerfile.dockerignore @@ -3,3 +3,6 @@ **/docker/ **/images/ **/node_modules/ +**/*Dockerfile +**/transactions/ +**/orm-tests/ \ No newline at end of file diff --git a/integration-tests/mysql-client-tests/mysql-client-tests.bats b/integration-tests/mysql-client-tests/mysql-client-tests.bats index 15e4860cb0..71978d4835 100644 --- a/integration-tests/mysql-client-tests/mysql-client-tests.bats +++ b/integration-tests/mysql-client-tests/mysql-client-tests.bats @@ -172,7 +172,7 @@ EOF" -m "postgres" } @test "rust mysql client" { - /build/bin/rust/rust-mysql-client-test $USER $PORT $REPO_NAME + /build/bin/rust/mysql-client-test $USER $PORT $REPO_NAME } @test "php mysqli mysql client" { diff --git a/integration-tests/mysql-client-tests/python/pymysql-test.py b/integration-tests/mysql-client-tests/python/pymysql-test.py index f7cf4385a3..ab542ce06c 100644 --- a/integration-tests/mysql-client-tests/python/pymysql-test.py +++ b/integration-tests/mysql-client-tests/python/pymysql-test.py @@ -1,54 +1,54 @@ -import pymysql -import sys - -QUERY_RESPONSE = [ - {"create table test (pk int, `value` int, primary key(pk))": ()}, - {"describe test": ( - ('pk', 'int', 'NO', 'PRI', None, ''), - ('value', 'int', 'YES', '', None, '') - )}, - {"insert into test (pk, `value`) values (0,0)": ()}, - {"select * from test": ((0, 0),)}, - {"call dolt_add('-A');": ((0,),)}, - {"call dolt_commit('-m', 'my commit')": (('',),)}, - {"select COUNT(*) FROM dolt_log": ((2,),)}, - {"call dolt_checkout('-b', 'mybranch')": ((0, "Switched to branch 'mybranch'"),)}, - {"insert into test (pk, `value`) values (1,1)": ()}, - {"call dolt_commit('-a', '-m', 'my commit2')": (('',),)}, - {"call dolt_checkout('main')": ((0, "Switched to branch 'main'"),)}, - {"call dolt_merge('mybranch')": (('',1,0,),)}, - {"select COUNT(*) FROM dolt_log": ((3,),)}, -] - - -def main(): - user = sys.argv[1] - port = int(sys.argv[2]) - db = sys.argv[3] - - connection = pymysql.connect(host="127.0.0.1", - port=port, - user=user, - db=db) - - for query_response in QUERY_RESPONSE: - query = list(query_response.keys())[0] - exp_results = query_response[query] - with connection.cursor() as cursor: - cursor.execute(query) - results = cursor.fetchall() - if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): - print("Query:") - print(query) - print("Expected:") - print(exp_results) - print("Received:") - print(results) - sys.exit(1) - - connection.close() - - sys.exit(0) - - -main() +import pymysql +import sys + +QUERY_RESPONSE = [ + {"create table test (pk int, `value` int, primary key(pk))": ()}, + {"describe test": ( + ('pk', 'int', 'NO', 'PRI', None, ''), + ('value', 'int', 'YES', '', None, '') + )}, + {"insert into test (pk, `value`) values (0,0)": ()}, + {"select * from test": ((0, 0),)}, + {"call dolt_add('-A');": ((0,),)}, + {"call dolt_commit('-m', 'my commit')": (('',),)}, + {"select COUNT(*) FROM dolt_log": ((2,),)}, + {"call dolt_checkout('-b', 'mybranch')": ((0, "Switched to branch 'mybranch'"),)}, + {"insert into test (pk, `value`) values (1,1)": ()}, + {"call dolt_commit('-a', '-m', 'my commit2')": (('',),)}, + {"call dolt_checkout('main')": ((0, "Switched to branch 'main'"),)}, + {"call dolt_merge('mybranch')": (('',1,0,),)}, + {"select COUNT(*) FROM dolt_log": ((3,),)}, +] + + +def main(): + user = sys.argv[1] + port = int(sys.argv[2]) + db = sys.argv[3] + + connection = pymysql.connect(host="127.0.0.1", + port=port, + user=user, + db=db) + + for query_response in QUERY_RESPONSE: + query = list(query_response.keys())[0] + exp_results = query_response[query] + with connection.cursor() as cursor: + cursor.execute(query) + results = cursor.fetchall() + if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): + print("Query:") + print(query) + print("Expected:") + print(exp_results) + print("Received:") + print(results) + sys.exit(1) + + connection.close() + + sys.exit(0) + + +main() diff --git a/integration-tests/mysql-client-tests/rust/Cargo.toml b/integration-tests/mysql-client-tests/rust/Cargo.toml index 3bc2047e78..db8cc4cf37 100644 --- a/integration-tests/mysql-client-tests/rust/Cargo.toml +++ b/integration-tests/mysql-client-tests/rust/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" mysql = "*" [[bin]] -name = "rust-mysql-client-test" +name = "mysql-client-test" path = "src/mysql_connector_test.rs" From 02b7c04b83a14c54eac421667c57e2d19f1f2410 Mon Sep 17 00:00:00 2001 From: elianddb Date: Sun, 12 Oct 2025 20:25:47 -0700 Subject: [PATCH 07/14] amend R deps layer --- .github/workflows/ci-mysql-client-tests.yaml | 3 +-- integration-tests/mysql-client-tests/Dockerfile | 6 +++--- integration-tests/mysql-client-tests/cpp/Makefile | 4 ++++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-mysql-client-tests.yaml b/.github/workflows/ci-mysql-client-tests.yaml index 5e07238019..fa2b1ae104 100644 --- a/.github/workflows/ci-mysql-client-tests.yaml +++ b/.github/workflows/ci-mysql-client-tests.yaml @@ -10,13 +10,12 @@ concurrency: group: ci-mysql-client-tests-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true - jobs: mysql_client_integrations_job: runs-on: ubuntu-22.04 timeout-minutes: 45 steps: - - name: Remove unused tools + - name: Clean up preinstalled .NET and agent tools run: | sudo rm -rf /usr/share/dotnet sudo rm -rf "$AGENT_TOOLSDIRECTORY" diff --git a/integration-tests/mysql-client-tests/Dockerfile b/integration-tests/mysql-client-tests/Dockerfile index c2e4b8ef61..ee7b31b426 100644 --- a/integration-tests/mysql-client-tests/Dockerfile +++ b/integration-tests/mysql-client-tests/Dockerfile @@ -116,9 +116,9 @@ RUN docker-php-ext-install mysqli pdo_mysql FROM debian:bookworm-slim AS r_deps RUN apt-get update && apt-get install -y r-base-core libmariadb-dev && rm -rf /var/lib/apt/lists/* WORKDIR /build/r/ -RUN R -e "install.packages('DBI', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" -RUN R -e "install.packages('RMySQL', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" -RUN R -e "install.packages('RMariaDB', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" +RUN R -e "install.packages('DBI', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" && \ + R -e "install.packages('RMySQL', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" && \ + R -e "install.packages('RMariaDB', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" FROM php:8.3-bookworm AS runtime RUN apt-get update && apt-get install -y \ diff --git a/integration-tests/mysql-client-tests/cpp/Makefile b/integration-tests/mysql-client-tests/cpp/Makefile index 441b42ef18..d00eeea100 100644 --- a/integration-tests/mysql-client-tests/cpp/Makefile +++ b/integration-tests/mysql-client-tests/cpp/Makefile @@ -1,10 +1,14 @@ CXX = g++ + CXXFLAGS_MYSQL = -I/usr/include/cppconn -std=c++11 -Wall -O2 CXXFLAGS_MARIADB = -I/usr/include/mariadb -std=c++11 -Wall -O2 + LDFLAGS_MYSQL = -lmysqlcppconn LDFLAGS_MARIADB = -lmariadbcpp + TARGET_MYSQL = /build/bin/mysql-connector-test TARGET_MARIADB = /build/bin/mariadb-connector-test + SRCS_MYSQL = mysql-connector-test.cpp SRCS_MARIADB = mariadb-connector-test.cpp From 1b05f9bc3ac3dfb457cafc64c0cca1daab15b002 Mon Sep 17 00:00:00 2001 From: elianddb Date: Mon, 13 Oct 2025 10:03:15 -0700 Subject: [PATCH 08/14] rm glob copy of other repos --- integration-tests/mysql-client-tests/Dockerfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/integration-tests/mysql-client-tests/Dockerfile b/integration-tests/mysql-client-tests/Dockerfile index ee7b31b426..c40c7d3163 100644 --- a/integration-tests/mysql-client-tests/Dockerfile +++ b/integration-tests/mysql-client-tests/Dockerfile @@ -6,8 +6,6 @@ RUN apk add --no-cache build-base FROM golang_cgo125 AS dolt_build COPY dolt/go/go.mod /build/dolt/go/ -COPY go-mysql-server*/ /build/go-mysql-server/ -COPY vitess*/ /build/vitess/ WORKDIR /build/dolt/go/ RUN go mod download RUN apk add --no-cache icu-dev icu-static From 17ab809bd128944548261891b97732ba8571ffbc Mon Sep 17 00:00:00 2001 From: elianddb Date: Mon, 13 Oct 2025 13:23:44 -0700 Subject: [PATCH 09/14] add odbc and swift test --- .github/workflows/ci-mysql-client-tests.yaml | 17 +- .../mysql-client-tests/Dockerfile | 57 ++++-- .../Dockerfile.dockerignore | 9 +- .../mysql-client-tests/c/Makefile | 12 +- .../mysql-client-tests/c/mariadb-odbc-test.c | 186 ++++++++++++++++++ .../mysql-client-tests.bats | 8 + .../mysql-client-tests/swift/Package.swift | 25 +++ .../swift/Sources/main.swift | 127 ++++++++++++ 8 files changed, 413 insertions(+), 28 deletions(-) create mode 100644 integration-tests/mysql-client-tests/c/mariadb-odbc-test.c create mode 100644 integration-tests/mysql-client-tests/swift/Package.swift create mode 100644 integration-tests/mysql-client-tests/swift/Sources/main.swift diff --git a/.github/workflows/ci-mysql-client-tests.yaml b/.github/workflows/ci-mysql-client-tests.yaml index fa2b1ae104..e472be9eaf 100644 --- a/.github/workflows/ci-mysql-client-tests.yaml +++ b/.github/workflows/ci-mysql-client-tests.yaml @@ -15,11 +15,14 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 45 steps: - - name: Clean up preinstalled .NET and agent tools - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - + - name: Maximize build space + uses: easimon/maximize-build-space@v10 + with: + remove-dotnet: 'true' + remove-codeql: 'true' + remove-haskell: 'true' + + - name: Checkout uses: actions/checkout@v4 with: @@ -29,14 +32,14 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Build MySQL test image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 with: context: . file: dolt/integration-tests/mysql-client-tests/Dockerfile tags: mysql-client-tests:latest load: true cache-from: type=gha - cache-to: type=gha,mode=max + cache-to: type=gha,mode=min - name: Test MySQL client integrations run: docker run --rm mysql-client-tests:latest diff --git a/integration-tests/mysql-client-tests/Dockerfile b/integration-tests/mysql-client-tests/Dockerfile index c40c7d3163..2ead533844 100644 --- a/integration-tests/mysql-client-tests/Dockerfile +++ b/integration-tests/mysql-client-tests/Dockerfile @@ -5,10 +5,10 @@ ENV GO_LDFLAGS="-linkmode external -extldflags '-static'" RUN apk add --no-cache build-base FROM golang_cgo125 AS dolt_build +RUN apk add --no-cache icu-dev icu-static COPY dolt/go/go.mod /build/dolt/go/ WORKDIR /build/dolt/go/ RUN go mod download -RUN apk add --no-cache icu-dev icu-static COPY dolt/go/ /build/dolt/go/ RUN go build -tags icu_static -ldflags "$GO_LDFLAGS" -o /build/bin/dolt ./cmd/dolt @@ -22,31 +22,43 @@ WORKDIR /build/go-mysql/ RUN go build -ldflags "$GO_LDFLAGS" -o /build/bin/sql-driver-mysql-test FROM rust:1.90-alpine3.22 AS rust_clients_build +RUN apk add --no-cache musl-dev COPY dolt/integration-tests/mysql-client-tests/rust/ /build/rust/ WORKDIR /build/rust/ -RUN apk add --no-cache musl-dev RUN cargo build --release --target-dir /build/bin/ # exe is in release/ FROM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim AS dotnet_clients_build -COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlClient/ /build/dotnet/MySqlClient/ +COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlClient/*.csproj /build/dotnet/MySqlClient/ WORKDIR /build/dotnet/MySqlClient/ -RUN dotnet publish -c Release -o /build/bin +RUN dotnet restore +COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlClient/ /build/dotnet/MySqlClient/ +RUN dotnet publish -c Release -o /build/bin --no-restore -COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlConnector/ /build/dotnet/MySqlConnector/ +COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlConnector/*.csproj /build/dotnet/MySqlConnector/ WORKDIR /build/dotnet/MySqlConnector/ -RUN dotnet publish -c Release -o /build/bin +RUN dotnet restore +COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlConnector/ /build/dotnet/MySqlConnector/ +RUN dotnet publish -c Release -o /build/bin --no-restore # devart dotconnect reqs a license so we've skipped it here FROM gcc:12.5-bookworm AS c_clients_build # default-libmysqlclient-dev uses libmariadb under the hood but here we test both header interfaces -RUN apt-get update && apt-get install -y default-libmysqlclient-dev libmariadb-dev && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y default-libmysqlclient-dev libmariadb-dev unixodbc-dev odbcinst wget && rm -rf /var/lib/apt/lists/* +RUN wget --progress=dot:giga https://dlm.mariadb.com/4465891/Connectors/odbc/connector-odbc-3.2.7/mariadb-connector-odbc_3.2.7-1+maria~bookworm_amd64.deb \ + && dpkg -i mariadb-connector-odbc_3.2.7-1+maria~bookworm_amd64.deb || apt-get install -y -f \ + && rm mariadb-connector-odbc_3.2.7-1+maria~bookworm_amd64.deb \ + && odbcinst -i -d -f /dev/stdin < +#include +#include +#include +#include + +#define QUERIES_SIZE 14 + +char *queries[QUERIES_SIZE] = { + "create table test (pk int, `value` int, primary key(pk))", + "describe test", + "select * from test", + "insert into test (pk, `value`) values (0,0)", + "select * from test", + "call dolt_add('-A')", + "call dolt_commit('-m', 'my commit')", + "select COUNT(*) FROM dolt_log", + "call dolt_checkout('-b', 'mybranch')", + "insert into test (pk, `value`) values (10,10)", + "call dolt_commit('-a', '-m', 'my commit2')", + "call dolt_checkout('main')", + "call dolt_merge('mybranch')", + "select COUNT(*) FROM dolt_log", +}; + +void check_error(SQLRETURN ret, SQLHANDLE handle, SQLSMALLINT type, const char *msg) { + if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { + SQLCHAR sqlstate[6]; + SQLCHAR message[SQL_MAX_MESSAGE_LENGTH]; + SQLINTEGER native_error; + SQLSMALLINT text_length; + + SQLGetDiagRec(type, handle, 1, sqlstate, &native_error, message, sizeof(message), &text_length); + fprintf(stderr, "%s\nSQLSTATE: %s\nMessage: %s\n", msg, sqlstate, message); + exit(1); + } +} + +typedef struct prepared_statement_t { + char *query; + int num_params; + int pk_param; + int value_param; + int expect_prepare_error; + int expect_exec_error; +} prepared_statement; + +void test_prepared_statement(SQLHDBC dbc, prepared_statement *pstmt) { + SQLHSTMT stmt; + SQLRETURN ret; + + ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); + check_error(ret, dbc, SQL_HANDLE_DBC, "Failed to allocate statement handle"); + + ret = SQLPrepare(stmt, (SQLCHAR *)pstmt->query, SQL_NTS); + if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { + if (!pstmt->expect_prepare_error) { + check_error(ret, stmt, SQL_HANDLE_STMT, "Failed to prepare statement"); + } else { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return; + } + } + + if (pstmt->num_params > 0) { + if (pstmt->pk_param) { + SQLINTEGER pk = 1; + ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &pk, 0, NULL); + check_error(ret, stmt, SQL_HANDLE_STMT, "Failed to bind pk parameter"); + } + if (pstmt->num_params > 1 && pstmt->value_param) { + SQLINTEGER value = 12; + ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &value, 0, NULL); + check_error(ret, stmt, SQL_HANDLE_STMT, "Failed to bind value parameter"); + } + } + + ret = SQLExecute(stmt); + if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { + if (!pstmt->expect_exec_error) { + check_error(ret, stmt, SQL_HANDLE_STMT, "Failed to execute statement"); + } + } + + SQLFreeHandle(SQL_HANDLE_STMT, stmt); +} + +int main(int argc, char **argv) { + if (argc < 4) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + char *user = argv[1]; + int port = atoi(argv[2]); + char *db = argv[3]; + + SQLHENV env; + SQLHDBC dbc; + SQLHSTMT stmt; + SQLRETURN ret; + + // Allocate environment handle + ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); + check_error(ret, env, SQL_HANDLE_ENV, "Failed to allocate environment handle"); + + // Set ODBC version + ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0); + check_error(ret, env, SQL_HANDLE_ENV, "Failed to set ODBC version"); + + // Allocate connection handle + ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc); + check_error(ret, env, SQL_HANDLE_ENV, "Failed to allocate connection handle"); + + // Build connection string + char connStr[512]; + snprintf(connStr, sizeof(connStr), + "DRIVER=MariaDB ODBC 3.2 Driver;SERVER=127.0.0.1;PORT=%d;DATABASE=%s;UID=%s;PWD=;", + port, db, user); + + // Connect to database + ret = SQLDriverConnect(dbc, NULL, (SQLCHAR *)connStr, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT); + check_error(ret, dbc, SQL_HANDLE_DBC, "Failed to connect to database"); + + printf("Connected to database successfully\n"); + + // Execute test queries + for (int i = 0; i < QUERIES_SIZE; i++) { + ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); + check_error(ret, dbc, SQL_HANDLE_DBC, "Failed to allocate statement handle"); + + ret = SQLExecDirect(stmt, (SQLCHAR *)queries[i], SQL_NTS); + if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { + printf("QUERY FAILED: %s\n", queries[i]); + check_error(ret, stmt, SQL_HANDLE_STMT, "Query execution failed"); + } + + // Fetch and discard results + while (SQLFetch(stmt) == SQL_SUCCESS) { + // Just consume the results + } + + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + + // Test prepared statements + prepared_statement statements[] = { + { + .query = "select * from test where pk = ?", + .num_params = 1, + .pk_param = 1, + .expect_prepare_error = 0, + .expect_exec_error = 0, + }, + { + .query = "insert into test values (?, ?)", + .num_params = 2, + .pk_param = 1, + .value_param = 1, + .expect_prepare_error = 0, + .expect_exec_error = 0, + }, + { + .query = "select * from test SYNTAX ERROR where pk = ?", + .num_params = 1, + .pk_param = 1, + .expect_prepare_error = 1, + .expect_exec_error = 0, + }, + {NULL, 0, 0, 0, 0, 0}, // Sentinel + }; + + for (int i = 0; statements[i].query; i++) { + test_prepared_statement(dbc, &statements[i]); + } + + printf("All tests passed\n"); + + // Cleanup + SQLDisconnect(dbc); + SQLFreeHandle(SQL_HANDLE_DBC, dbc); + SQLFreeHandle(SQL_HANDLE_ENV, env); + + return 0; +} + diff --git a/integration-tests/mysql-client-tests/mysql-client-tests.bats b/integration-tests/mysql-client-tests/mysql-client-tests.bats index 71978d4835..7d95832b9c 100644 --- a/integration-tests/mysql-client-tests/mysql-client-tests.bats +++ b/integration-tests/mysql-client-tests/mysql-client-tests.bats @@ -86,6 +86,10 @@ teardown() { /build/bin/c/mariadb-client-test $USER $PORT $REPO_NAME } +@test "c mariadb odbc connector" { + /build/bin/c/mariadb-odbc-test $USER $PORT $REPO_NAME +} + @test "cpp mysql connector" { /build/bin/cpp/mysql-connector-test $USER $PORT $REPO_NAME } @@ -175,6 +179,10 @@ EOF" -m "postgres" /build/bin/rust/mysql-client-test $USER $PORT $REPO_NAME } +@test "swift perfect-mariadb client" { + /build/bin/swift/mariadb-swift-test $USER $PORT $REPO_NAME +} + @test "php mysqli mysql client" { php /build/bin/php/mysqli_connector_test.php $USER $PORT $REPO_NAME } diff --git a/integration-tests/mysql-client-tests/swift/Package.swift b/integration-tests/mysql-client-tests/swift/Package.swift new file mode 100644 index 0000000000..6b965ee246 --- /dev/null +++ b/integration-tests/mysql-client-tests/swift/Package.swift @@ -0,0 +1,25 @@ +// swift-tools-version:5.5 +import PackageDescription + +let package = Package( + name: "MariaDBTest", + platforms: [ + .macOS(.v10_15) + ], + dependencies: [ + .package(url: "https://github.com/PerfectlySoft/Perfect-MariaDB.git", from: "3.0.0") + ], + targets: [ + .executableTarget( + name: "MariaDBTest", + dependencies: [ + .product(name: "MariaDB", package: "Perfect-MariaDB") + ], + path: "Sources", + linkerSettings: [ + .linkedLibrary("mariadb") + ] + ) + ] +) + diff --git a/integration-tests/mysql-client-tests/swift/Sources/main.swift b/integration-tests/mysql-client-tests/swift/Sources/main.swift new file mode 100644 index 0000000000..e3dceb2175 --- /dev/null +++ b/integration-tests/mysql-client-tests/swift/Sources/main.swift @@ -0,0 +1,127 @@ +import Foundation +import MariaDB + +func main() throws { + // Get connection parameters from command line + guard CommandLine.arguments.count >= 4 else { + print("Usage: MariaDBTest ") + exit(1) + } + + let user = CommandLine.arguments[1] + let port = UInt32(CommandLine.arguments[2]) ?? 3306 + let database = CommandLine.arguments[3] + + // Connect to the database + let mysql = MySQL() + + guard mysql.connect( + host: "127.0.0.1", + user: user, + password: "", + db: database, + port: port + ) else { + print("Connection failed: \(mysql.errorMessage())") + exit(1) + } + + print("Connected to MariaDB successfully") + + // Test queries + let queries = [ + "CREATE TABLE test (pk INT, value INT, PRIMARY KEY(pk))", + "INSERT INTO test (pk, value) VALUES (0, 0)", + "SELECT * FROM test", + "CALL dolt_add('-A')", + "CALL dolt_commit('-m', 'my commit')", + "SELECT COUNT(*) FROM dolt_log", + "CALL dolt_checkout('-b', 'mybranch')", + "INSERT INTO test (pk, value) VALUES (10, 10)", + "CALL dolt_commit('-a', '-m', 'my commit2')", + "CALL dolt_checkout('main')", + "CALL dolt_merge('mybranch')", + "SELECT COUNT(*) FROM dolt_log" + ] + + for query in queries { + guard mysql.query(statement: query) else { + print("Query failed: \(query)") + print("Error: \(mysql.errorMessage())") + exit(1) + } + + // Consume results if any + let results = mysql.storeResults() + results?.close() + } + + // Test prepared statements + print("Testing prepared statements...") + + let stmt = MySQLStmt(mysql) + + // Test SELECT with prepared statement + let selectQuery = "SELECT * FROM test WHERE pk = ?" + guard stmt.prepare(statement: selectQuery) else { + print("Failed to prepare SELECT statement: \(stmt.errorMessage())") + exit(1) + } + + stmt.bindParam(1) + + guard stmt.execute() else { + print("Failed to execute SELECT statement: \(stmt.errorMessage())") + exit(1) + } + + let resultSet = stmt.results() + resultSet.close() + stmt.close() + + // Test INSERT with prepared statement + let insertStmt = MySQLStmt(mysql) + + let insertQuery = "INSERT INTO test VALUES (?, ?)" + guard insertStmt.prepare(statement: insertQuery) else { + print("Failed to prepare INSERT statement: \(insertStmt.errorMessage())") + exit(1) + } + + insertStmt.bindParam(2) + insertStmt.bindParam(20) + + guard insertStmt.execute() else { + print("Failed to execute INSERT statement: \(insertStmt.errorMessage())") + exit(1) + } + + insertStmt.close() + + // Verify the insert + guard mysql.query(statement: "SELECT * FROM test WHERE pk = 2") else { + print("Failed to verify insert") + exit(1) + } + + if let verifyResults = mysql.storeResults() { + let row = verifyResults.next() + guard row != nil else { + print("Expected row not found after insert") + exit(1) + } + verifyResults.close() + } + + print("All Swift tests passed!") + + mysql.close() +} + +do { + try main() +} catch { + print("Error: \(error)") + exit(1) +} + From 287bba5959aa4ea7877b6bc4557c4dd22e70627a Mon Sep 17 00:00:00 2001 From: elianddb Date: Mon, 13 Oct 2025 16:53:08 -0700 Subject: [PATCH 10/14] amend image vers --- .github/workflows/ci-mysql-client-tests.yaml | 1 - .../mysql-client-tests/Dockerfile | 37 +++++++++---------- .../mysql-client-tests/java/pom.xml | 4 +- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci-mysql-client-tests.yaml b/.github/workflows/ci-mysql-client-tests.yaml index e472be9eaf..3d74520e5f 100644 --- a/.github/workflows/ci-mysql-client-tests.yaml +++ b/.github/workflows/ci-mysql-client-tests.yaml @@ -22,7 +22,6 @@ jobs: remove-codeql: 'true' remove-haskell: 'true' - - name: Checkout uses: actions/checkout@v4 with: diff --git a/integration-tests/mysql-client-tests/Dockerfile b/integration-tests/mysql-client-tests/Dockerfile index 2ead533844..7d3d00eb07 100644 --- a/integration-tests/mysql-client-tests/Dockerfile +++ b/integration-tests/mysql-client-tests/Dockerfile @@ -27,7 +27,12 @@ COPY dolt/integration-tests/mysql-client-tests/rust/ /build/rust/ WORKDIR /build/rust/ RUN cargo build --release --target-dir /build/bin/ # exe is in release/ -FROM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim AS dotnet_clients_build +FROM debian:bookworm-slim AS dotnet_clients_build +RUN apt-get update && apt-get install -y wget gnupg ca-certificates && rm -rf /var/lib/apt/lists/* +RUN wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb \ + && dpkg -i packages-microsoft-prod.deb \ + && rm packages-microsoft-prod.deb +RUN apt-get update && apt-get install -y dotnet-sdk-9.0 && rm -rf /var/lib/apt/lists/* COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlClient/*.csproj /build/dotnet/MySqlClient/ WORKDIR /build/dotnet/MySqlClient/ RUN dotnet restore @@ -41,9 +46,9 @@ COPY dolt/integration-tests/mysql-client-tests/dotnet/MySqlConnector/ /build/dot RUN dotnet publish -c Release -o /build/bin --no-restore # devart dotconnect reqs a license so we've skipped it here -FROM gcc:12.5-bookworm AS c_clients_build +FROM debian:bookworm-slim AS c_clients_build # default-libmysqlclient-dev uses libmariadb under the hood but here we test both header interfaces -RUN apt-get update && apt-get install -y default-libmysqlclient-dev libmariadb-dev unixodbc-dev odbcinst wget && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y default-libmysqlclient-dev libmariadb-dev unixodbc-dev odbcinst wget gcc make && rm -rf /var/lib/apt/lists/* RUN wget --progress=dot:giga https://dlm.mariadb.com/4465891/Connectors/odbc/connector-odbc-3.2.7/mariadb-connector-odbc_3.2.7-1+maria~bookworm_amd64.deb \ && dpkg -i mariadb-connector-odbc_3.2.7-1+maria~bookworm_amd64.deb || apt-get install -y -f \ && rm mariadb-connector-odbc_3.2.7-1+maria~bookworm_amd64.deb \ @@ -56,8 +61,8 @@ COPY dolt/integration-tests/mysql-client-tests/c/ /build/c/ WORKDIR /build/c/ RUN make -FROM gcc:12.5-bookworm AS cpp_clients_build -RUN apt-get update && apt-get install -y libmysqlcppconn-dev wget && rm -rf /var/lib/apt/lists/* +FROM debian:bookworm-slim AS cpp_clients_build +RUN apt-get update && apt-get install -y libmysqlcppconn-dev wget g++ make && rm -rf /var/lib/apt/lists/* RUN wget --progress=dot:giga https://dlm.mariadb.com/4464866/Connectors/cpp/connector-cpp-1.1.7/mariadb-connector-cpp_1.1.7-1+maria~bookworm_amd64.deb \ && dpkg -i mariadb-connector-cpp_1.1.7-1+maria~bookworm_amd64.deb || apt-get install -y -f \ && rm mariadb-connector-cpp_1.1.7-1+maria~bookworm_amd64.deb @@ -94,7 +99,7 @@ RUN mkdir -p /build/bin && \ cp /build/elixir/myxql/burrito_out/simple_linux /build/bin/myxql-driver-test && \ cp /build/elixir/mysql/burrito_out/mysql_otp_linux /build/bin/mysql-otp-test -FROM maven:3.9.11-amazoncorretto-21-debian-bookworm AS java_clients_build +FROM maven:3.8-openjdk-17-slim AS java_clients_build RUN apt-get update && apt-get install -y binutils && rm -rf /var/lib/apt/lists/* COPY dolt/integration-tests/mysql-client-tests/java/ /build/java/ WORKDIR /build/java/ @@ -112,16 +117,13 @@ WORKDIR /build/bin/ RUN npm install --omit=dev COPY dolt/integration-tests/mysql-client-tests/node/ /build/bin/ -FROM ruby:3.4-bookworm AS ruby_clients_build -RUN apt-get update && apt-get install -y default-libmysqlclient-dev && rm -rf /var/lib/apt/lists/* +FROM debian:bookworm-slim AS ruby_clients_build +RUN apt-get update && apt-get install -y default-libmysqlclient-dev ruby3.1-dev bundler && rm -rf /var/lib/apt/lists/* COPY dolt/integration-tests/mysql-client-tests/ruby/Gemfile /build/ruby/ WORKDIR /build/ruby/ RUN bundle install COPY dolt/integration-tests/mysql-client-tests/ruby/ /build/bin/ -FROM php:8.3-bookworm AS php_deps -RUN docker-php-ext-install mysqli pdo_mysql - FROM swift:5.10-bookworm AS swift_clients_build RUN apt-get update && apt-get install -y libmariadb-dev pkg-config libstdc++-12-dev && rm -rf /var/lib/apt/lists/* COPY dolt/integration-tests/mysql-client-tests/swift/ /build/swift/ @@ -129,13 +131,6 @@ WORKDIR /build/swift/ RUN swift build -c release --static-swift-stdlib RUN mkdir -p /build/bin && cp .build/release/MariaDBTest /build/bin/mariadb-swift-test -FROM debian:bookworm-slim AS r_deps -RUN apt-get update && apt-get install -y r-base-core libmariadb-dev && rm -rf /var/lib/apt/lists/* -WORKDIR /build/r/ -RUN R -e "install.packages('DBI', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" && \ - R -e "install.packages('RMySQL', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" && \ - R -e "install.packages('RMariaDB', INSTALL_opts='--build', repos='https://cloud.r-project.org/')" - FROM php:8.3-bookworm AS runtime RUN apt-get update && apt-get install -y \ libmysqlcppconn-dev \ @@ -160,8 +155,10 @@ COPY --from=ruby_clients_build /usr/local/bin/ruby /usr/local/bin/ COPY --from=ruby_clients_build /usr/local/lib/ /usr/local/lib/ COPY --from=ruby_clients_build /usr/local/bundle/ /usr/local/bundle/ -COPY --from=r_deps /build/r/*.tar.gz /tmp/r-packages/ -RUN R CMD INSTALL /tmp/r-packages/*.tar.gz && rm -rf /tmp/r-packages/ +RUN docker-php-ext-install mysqli pdo_mysql && \ + R -e "install.packages('DBI', repos='https://cloud.r-project.org/')" && \ + R -e "install.packages('RMySQL', repos='https://cloud.r-project.org/')" && \ + R -e "install.packages('RMariaDB', repos='https://cloud.r-project.org/')" ENV PATH="/opt/jre/bin:${PATH}" GEM_HOME="/usr/local/bundle" RUN ldconfig diff --git a/integration-tests/mysql-client-tests/java/pom.xml b/integration-tests/mysql-client-tests/java/pom.xml index 7792f5ed13..82224dbdb8 100644 --- a/integration-tests/mysql-client-tests/java/pom.xml +++ b/integration-tests/mysql-client-tests/java/pom.xml @@ -10,8 +10,8 @@ 1.0.0 - 21 - 21 + 17 + 17 UTF-8 From d8216be4b36caad22ccbdfdf8b23cce72556955a Mon Sep 17 00:00:00 2001 From: elianddb Date: Mon, 13 Oct 2025 17:28:32 -0700 Subject: [PATCH 11/14] fix ruby --- .github/workflows/ci-mysql-client-tests.yaml | 14 +++++++------- integration-tests/mysql-client-tests/Dockerfile | 6 ++---- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-mysql-client-tests.yaml b/.github/workflows/ci-mysql-client-tests.yaml index 3d74520e5f..3b417643b1 100644 --- a/.github/workflows/ci-mysql-client-tests.yaml +++ b/.github/workflows/ci-mysql-client-tests.yaml @@ -15,12 +15,13 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 45 steps: - - name: Maximize build space - uses: easimon/maximize-build-space@v10 + - name: Free Disk Space + uses: jlumbroso/free-disk-space@main with: - remove-dotnet: 'true' - remove-codeql: 'true' - remove-haskell: 'true' + android: true + dotnet: true + haskell: true + large-packages: true - name: Checkout uses: actions/checkout@v4 @@ -37,8 +38,7 @@ jobs: file: dolt/integration-tests/mysql-client-tests/Dockerfile tags: mysql-client-tests:latest load: true - cache-from: type=gha - cache-to: type=gha,mode=min + no-cache: true - name: Test MySQL client integrations run: docker run --rm mysql-client-tests:latest diff --git a/integration-tests/mysql-client-tests/Dockerfile b/integration-tests/mysql-client-tests/Dockerfile index 7d3d00eb07..01b924e1dd 100644 --- a/integration-tests/mysql-client-tests/Dockerfile +++ b/integration-tests/mysql-client-tests/Dockerfile @@ -25,7 +25,7 @@ FROM rust:1.90-alpine3.22 AS rust_clients_build RUN apk add --no-cache musl-dev COPY dolt/integration-tests/mysql-client-tests/rust/ /build/rust/ WORKDIR /build/rust/ -RUN cargo build --release --target-dir /build/bin/ # exe is in release/ +RUN cargo build --release --target-dir /build/bin/ && cargo clean # exe is in release/ FROM debian:bookworm-slim AS dotnet_clients_build RUN apt-get update && apt-get install -y wget gnupg ca-certificates && rm -rf /var/lib/apt/lists/* @@ -117,7 +117,7 @@ WORKDIR /build/bin/ RUN npm install --omit=dev COPY dolt/integration-tests/mysql-client-tests/node/ /build/bin/ -FROM debian:bookworm-slim AS ruby_clients_build +FROM ruby:3.4-bookworm AS ruby_clients_build RUN apt-get update && apt-get install -y default-libmysqlclient-dev ruby3.1-dev bundler && rm -rf /var/lib/apt/lists/* COPY dolt/integration-tests/mysql-client-tests/ruby/Gemfile /build/ruby/ WORKDIR /build/ruby/ @@ -149,8 +149,6 @@ COPY --from=c_clients_build /usr/lib/x86_64-linux-gnu/ /usr/lib/x86_64-linux-gnu COPY --from=c_clients_build /etc/odbcinst.ini /etc/odbcinst.ini COPY --from=java_clients_build /build/jre/ /opt/jre/ COPY --from=node_clients_build /usr/local/bin/node /usr/local/bin/ -COPY --from=php_deps /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/ -COPY --from=php_deps /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/ COPY --from=ruby_clients_build /usr/local/bin/ruby /usr/local/bin/ COPY --from=ruby_clients_build /usr/local/lib/ /usr/local/lib/ COPY --from=ruby_clients_build /usr/local/bundle/ /usr/local/bundle/ From c604fd772931775e57893682b038616a4f42fc75 Mon Sep 17 00:00:00 2001 From: elianddb Date: Mon, 13 Oct 2025 20:32:07 -0700 Subject: [PATCH 12/14] amend to use ref_name cache --- .github/workflows/ci-mysql-client-tests.yaml | 34 +++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-mysql-client-tests.yaml b/.github/workflows/ci-mysql-client-tests.yaml index 3b417643b1..e47ee184e4 100644 --- a/.github/workflows/ci-mysql-client-tests.yaml +++ b/.github/workflows/ci-mysql-client-tests.yaml @@ -15,22 +15,32 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 45 steps: - - name: Free Disk Space - uses: jlumbroso/free-disk-space@main - with: - android: true - dotnet: true - haskell: true - large-packages: true - - name: Checkout uses: actions/checkout@v4 with: path: dolt - + + - name: Free Disk Space + run: | + NAME="DISK-CLEANUP" + echo "[${NAME}] Starting background cleanup..." + [ -d "$AGENT_TOOLSDIRECTORY" ] && sudo rm -rf "$AGENT_TOOLSDIRECTORY" & + [ -d /usr/share/dotnet ] && sudo rm -rf /usr/share/dotnet & + [ -d /usr/local/lib/android ] && sudo rm -rf /usr/local/lib/android & + [ -d /opt/ghc ] && sudo rm -rf /opt/ghc & + [ -d /usr/local/share/boost ] && sudo rm -rf /usr/local/share/boost & + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /mnt/.buildx-cache + key: ${{ runner.os }}-docker-${{ github.ref }} + restore-keys: | + ${{ runner.os }}-docker- + - name: Build MySQL test image uses: docker/build-push-action@v6 with: @@ -38,7 +48,7 @@ jobs: file: dolt/integration-tests/mysql-client-tests/Dockerfile tags: mysql-client-tests:latest load: true - no-cache: true - + cache-from: type=local,src=/mnt/.buildx-cache + cache-to: type=local,dest=/mnt/.buildx-cache - name: Test MySQL client integrations run: docker run --rm mysql-client-tests:latest From e84c29cb84777d707beedabfd005ecd4ab7e286d Mon Sep 17 00:00:00 2001 From: elianddb Date: Mon, 13 Oct 2025 22:20:21 -0700 Subject: [PATCH 13/14] amend step name --- .github/workflows/ci-mysql-client-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-mysql-client-tests.yaml b/.github/workflows/ci-mysql-client-tests.yaml index e47ee184e4..37cf6da7ea 100644 --- a/.github/workflows/ci-mysql-client-tests.yaml +++ b/.github/workflows/ci-mysql-client-tests.yaml @@ -20,7 +20,7 @@ jobs: with: path: dolt - - name: Free Disk Space + - name: Free disk space run: | NAME="DISK-CLEANUP" echo "[${NAME}] Starting background cleanup..." From 0f8c40a8410bbcf56e355c16ca48045995005bdf Mon Sep 17 00:00:00 2001 From: elianddb Date: Mon, 13 Oct 2025 22:37:29 -0700 Subject: [PATCH 14/14] amend to global cache --- .github/workflows/ci-mysql-client-tests.yaml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-mysql-client-tests.yaml b/.github/workflows/ci-mysql-client-tests.yaml index 37cf6da7ea..1ec13cf467 100644 --- a/.github/workflows/ci-mysql-client-tests.yaml +++ b/.github/workflows/ci-mysql-client-tests.yaml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true jobs: - mysql_client_integrations_job: + mysql_client_integrations: runs-on: ubuntu-22.04 timeout-minutes: 45 steps: @@ -33,13 +33,18 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 + - name: Ensure cache directory exists + run: | + sudo mkdir -p /mnt/.buildx-cache + sudo chown $USER:$USER /mnt/.buildx-cache + - name: Cache Docker layers uses: actions/cache@v3 with: path: /mnt/.buildx-cache - key: ${{ runner.os }}-docker-${{ github.ref }} + key: ${{ runner.os }}-docker-mysql-client-integrations restore-keys: | - ${{ runner.os }}-docker- + ${{ runner.os }}-docker - name: Build MySQL test image uses: docker/build-push-action@v6 @@ -50,5 +55,6 @@ jobs: load: true cache-from: type=local,src=/mnt/.buildx-cache cache-to: type=local,dest=/mnt/.buildx-cache + - name: Test MySQL client integrations run: docker run --rm mysql-client-tests:latest