amend Dockerfile to embed interpreters from diff build stages

# Conflicts:
#	go/cmd/dolt/doltversion/version.go
#	go/go.mod
#	go/go.sum
This commit is contained in:
elianddb
2025-10-11 21:41:00 -07:00
parent 49592b4bdf
commit c38d3827c1
17 changed files with 488 additions and 386 deletions

View File

@@ -1,4 +0,0 @@
**/.git
**/.github
**/docker/
**/images/

View File

@@ -4,7 +4,6 @@ ENV CGO_ENABLED=1
ENV GO_LDFLAGS="-linkmode external -extldflags '-static'" ENV GO_LDFLAGS="-linkmode external -extldflags '-static'"
RUN apk add --no-cache build-base RUN apk add --no-cache build-base
FROM golang_cgo125 AS dolt_build FROM golang_cgo125 AS dolt_build
COPY dolt/go/go.mod /build/dolt/go/ COPY dolt/go/go.mod /build/dolt/go/
COPY go-mysql-server*/ /build/go-mysql-server/ COPY go-mysql-server*/ /build/go-mysql-server/
@@ -13,18 +12,16 @@ WORKDIR /build/dolt/go/
RUN go mod download RUN go mod download
RUN apk add --no-cache icu-dev icu-static RUN apk add --no-cache icu-dev icu-static
COPY dolt/go/ /build/dolt/go/ 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 FROM golang_cgo125 AS go_clients_build
COPY dolt/integration-tests/mysql-client-tests/go /build/go/ COPY dolt/integration-tests/mysql-client-tests/go /build/go/
WORKDIR /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/ COPY dolt/integration-tests/mysql-client-tests/go-mysql/ /build/go-mysql/
WORKDIR /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 FROM rust:1.90-alpine3.22 AS rust_clients_build
COPY dolt/integration-tests/mysql-client-tests/rust/ /build/rust/ 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 apk add --no-cache musl-dev
RUN cargo build --release --target-dir /build/bin/ # exe is in release/ 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 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/ /build/dotnet/MySqlClient/
WORKDIR /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/ WORKDIR /build/dotnet/MySqlConnector/
RUN dotnet publish -c Release -o /build/bin RUN dotnet publish -c Release -o /build/bin
FROM gcc:12.5-bookworm AS c_clients_build
FROM mcr.microsoft.com/devcontainers/cpp:1-bookworm AS c_clients_build RUN apt-get update && apt-get install -y \
COPY dolt/integration-tests/mysql-client-tests/c/vcpkg.json /build/c/vcpkg.json default-libmysqlclient-dev \
WORKDIR /build/c/ && rm -rf /var/lib/apt/lists/*
RUN vcpkg install --triplet=x64-linux-release
COPY dolt/integration-tests/mysql-client-tests/c/ /build/c/ COPY dolt/integration-tests/mysql-client-tests/c/ /build/c/
ENV CMAKE_TOOLCHAIN_FILE=/usr/local/vcpkg/scripts/buildsystems/vcpkg.cmake WORKDIR /build/c/
RUN cmake -B build -S . RUN make
RUN cmake --build build
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"

View File

@@ -0,0 +1,5 @@
**/.git/
**/.github/
**/docker/
**/images/
**/node_modules/

View File

@@ -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++)

View File

@@ -1,11 +1,18 @@
CFLAGS := $(shell pkg-config --cflags mysqlclient) CC = gcc
LDFLAGS := $(shell pkg-config --libs mysqlclient)
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) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
.PHONY: clean
clean: clean:
rm -f mysql-connector-c-test rm -f /build/bin/c-mysql-client-test

View File

@@ -1,7 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <memory.h> #include <memory.h>
#include <mysql/mysql.h> #include <mysql.h>
#define QUERIES_SIZE 14 #define QUERIES_SIZE 14

View File

@@ -1,4 +0,0 @@
{
"name": "mysql-client-test-c",
"dependencies": [ "libmysql" ]
}

View File

@@ -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()

View File

@@ -1,14 +1,14 @@
MYSQL_CONCPP_DIR = /usr/local/Cellar/mysql-connector-c++/8.0.21 CXX = g++
CPPFLAGS = -I $(MYSQL_CONCPP_DIR)/include -L $(MYSQL_CONCPP_DIR)/lib64 CXXFLAGS = -I/usr/include/cppconn -std=c++11 -Wall -O2
LDLIBS = -lmysqlcppconn8 LDFLAGS = -lmysqlcppconn
CXX = clang++ -stdlib=libc++ TARGET = /build/bin/cpp-mysql-connector-test
CXXFLAGS = -std=c++11 SRCS = mysql-connector-cpp-test.cpp
all: mysql-connector-cpp-test all: $(TARGET)
mysql-connector-cpp-test: mysql-connector-cpp-test.cpp $(TARGET): $(SRCS)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $^ $(LDLIBS) @mkdir -p /build/bin
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
.PHONY: clean
clean: clean:
rm -f mysql-connector-cpp-test rm -f $(TARGET)

View File

@@ -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 is_update[QUERIES_SIZE] = {1,0,0,1,0,0,0,0,0,1,0,0,0,0};
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc < 4) {
std::cerr << "Usage: " << argv[0] << " <user> <port> <database>" << std::endl;
return 1;
}
std::string user = argv[1]; std::string user = argv[1];
std::string port = argv[2]; std::string port = argv[2];
std::string db = argv[3]; std::string db = argv[3];

View File

@@ -1,16 +1,26 @@
defmodule SmokeTest do defmodule SmokeTest do
def myTestFunc(arg1, arg2) do def main(_args \\ []) do
if arg1 != arg2 do IO.puts("Starting SmokeTest.main/1")
raise "Test error"
end cli_args = Burrito.Util.Args.get_arguments()
IO.puts("Received CLI args: #{inspect(cli_args)}")
result = run(cli_args)
System.halt(0)
result
end end
@spec run :: nil defp run(args) do
def run do if length(args) < 3 do
args = System.argv() IO.puts("Usage: simple <user> <port> <database>")
System.halt(1)
end
user = Enum.at(args, 0) user = Enum.at(args, 0)
{port, _} = Integer.parse(Enum.at(args, 1)) port_str = Enum.at(args, 1)
database = Enum.at(args, 2) database = Enum.at(args, 2)
{port, _} = Integer.parse(port_str)
{:ok, pid} = MyXQL.start_link(username: user, port: port, database: database) {:ok, pid} = MyXQL.start_link(username: user, port: port, database: database)
{:ok, _} = MyXQL.query(pid, "drop table if exists test") {:ok, _} = MyXQL.query(pid, "drop table if exists test")
@@ -21,8 +31,6 @@ defmodule SmokeTest do
myTestFunc(result.num_rows, 0) myTestFunc(result.num_rows, 0)
{:ok, _} = MyXQL.query(pid, "insert into test (pk, `value`) values (0,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") {:ok, result} = MyXQL.query(pid, "UPDATE test SET pk = pk where pk = 0")
myTestFunc(result.num_rows, 1) myTestFunc(result.num_rows, 1)
@@ -31,7 +39,7 @@ defmodule SmokeTest do
{:ok, result} = MyXQL.query(pid, "SELECT * FROM test") {:ok, result} = MyXQL.query(pid, "SELECT * FROM test")
myTestFunc(result.num_rows, 1) 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_add('-A');")
{:ok, _} = MyXQL.query(pid, "call dolt_commit('-m', 'my commit')") {: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") {:ok, result} = MyXQL.query(pid, "select COUNT(*) FROM dolt_log")
myTestFunc(result.num_rows, 1) myTestFunc(result.num_rows, 1)
myTestFunc(result.rows, [[3]]) 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
end end

View File

@@ -5,15 +5,38 @@ defmodule Simple.MixProject do
[ [
app: :simple, app: :simple,
version: "0.1.0", version: "0.1.0",
elixir: "~> 1.18",
start_permanent: Mix.env() == :prod, 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 end
# Run "mix help deps" to learn about dependencies.
defp deps do defp deps do
[ [
{:myxql, "~> 0.5.0"}, {:myxql, "~> 0.5.0"},
{:burrito, "~> 1.4.0"}
] ]
end end
end end

View File

@@ -1,173 +1,173 @@
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
public class MySQLConnectorTest { public class MySQLConnectorTest {
// test queries to be run against Dolt // test queries to be run against Dolt
private static final String[] queries = { private static final String[] queries = {
"create table test (pk int, `value` int, primary key(pk))", "create table test (pk int, `value` int, primary key(pk))",
"describe test", "describe test",
"select * from test", "select * from test",
"insert into test (pk, `value`) values (0,0)", "insert into test (pk, `value`) values (0,0)",
"select * from test", "select * from test",
"call dolt_add('-A')", "call dolt_add('-A')",
"call dolt_commit('-m', 'my commit')", "call dolt_commit('-m', 'my commit')",
"select COUNT(*) FROM dolt_log", "select COUNT(*) FROM dolt_log",
"call dolt_checkout('-b', 'mybranch')", "call dolt_checkout('-b', 'mybranch')",
"insert into test (pk, `value`) values (1,1)", "insert into test (pk, `value`) values (1,1)",
"call dolt_commit('-a', '-m', 'my commit2')", "call dolt_commit('-a', '-m', 'my commit2')",
"call dolt_checkout('main')", "call dolt_checkout('main')",
"call dolt_merge('mybranch')", "call dolt_merge('mybranch')",
"select COUNT(*) FROM dolt_log", "select COUNT(*) FROM dolt_log",
}; };
// We currently only test a single field value in the first row // We currently only test a single field value in the first row
private static final String[] expectedResults = { private static final String[] expectedResults = {
"0", "0",
"pk", "pk",
null, null,
"1", "1",
"0", "0",
"0", "0",
"0", "0",
"2", "2",
"0", "0",
"1", "1",
"1", "1",
"0", "0",
"", "",
"3" "3"
}; };
// fieldAccessors are the value used to access a field in a row in a result set. Currently, only // 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. // String (i.e column name) and Integer (i.e. field position) values are supported.
private static final Object[] fieldAccessors = { private static final Object[] fieldAccessors = {
1, 1,
1, 1,
"pk", "pk",
1, 1,
"test.pk", "test.pk",
1, 1,
1, 1,
1, 1,
1, 1,
1, 1,
1, 1,
1, 1,
1, 1,
"COUNT(*)", "COUNT(*)",
}; };
public static void main(String[] args) { public static void main(String[] args) {
testStatements(args); testStatements(args);
testServerSideCursors(args); testServerSideCursors(args);
System.exit(0); System.exit(0);
} }
// testServerSideCursors does a simple smoke test with server-side cursors to make sure // 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 // 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. // 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 // 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 // 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 // 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. // is printed and this function exits with a non-zero code.
// For more details, see: https://github.com/dolthub/dolt/issues/9125 // For more details, see: https://github.com/dolthub/dolt/issues/9125
private static void testServerSideCursors(String[] args) { private static void testServerSideCursors(String[] args) {
String user = args[0]; String user = args[0];
String port = args[1]; String port = args[1];
String db = args[2]; String db = args[2];
try { try {
String url = "jdbc:mysql://127.0.0.1:" + port + "/" + db + String url = "jdbc:mysql://127.0.0.1:" + port + "/" + db +
"?useServerPrepStmts=true&useCursorFetch=true"; "?useServerPrepStmts=true&useCursorFetch=true";
Connection conn = DriverManager.getConnection(url, user, ""); Connection conn = DriverManager.getConnection(url, user, "");
executePreparedQuery(conn, "SELECT 1;"); executePreparedQuery(conn, "SELECT 1;");
executePreparedQuery(conn, "SELECT database();"); executePreparedQuery(conn, "SELECT database();");
executePreparedQuery(conn, "SHOW COLLATION;"); executePreparedQuery(conn, "SHOW COLLATION;");
executePreparedQuery(conn, "SHOW COLLATION;"); executePreparedQuery(conn, "SHOW COLLATION;");
executePreparedQuery(conn, "SHOW COLLATION;"); executePreparedQuery(conn, "SHOW COLLATION;");
} catch (SQLException ex) { } catch (SQLException ex) {
System.out.println("An error occurred."); System.out.println("An error occurred.");
ex.printStackTrace(); ex.printStackTrace();
System.exit(1); System.exit(1);
} }
} }
// executePreparedQuery executes the specified |query| using |conn| as a prepared statement, // 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 // 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. // 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 { private static void executePreparedQuery(Connection conn, String query) throws SQLException {
PreparedStatement stmt = conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY); PreparedStatement stmt = conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY);
stmt.setFetchSize(25); // needed to ensure a server-side cursor is used stmt.setFetchSize(25); // needed to ensure a server-side cursor is used
ResultSet rs = stmt.executeQuery(); ResultSet rs = stmt.executeQuery();
while (rs.next()) {} while (rs.next()) {}
rs.close(); rs.close();
stmt.close(); stmt.close();
} }
// testStatements executes the queries from |queries| and asserts their results from // testStatements executes the queries from |queries| and asserts their results from
// |expectedResults|. If any errors are encountered, a stack trace is printed and this // |expectedResults|. If any errors are encountered, a stack trace is printed and this
// function exits with a non-zero code. // function exits with a non-zero code.
private static void testStatements(String[] args) { private static void testStatements(String[] args) {
Connection conn = null; Connection conn = null;
String user = args[0]; String user = args[0];
String port = args[1]; String port = args[1];
String db = args[2]; String db = args[2];
try { try {
String url = "jdbc:mysql://127.0.0.1:" + port + "/" + db; String url = "jdbc:mysql://127.0.0.1:" + port + "/" + db;
String password = ""; String password = "";
conn = DriverManager.getConnection(url, user, password); conn = DriverManager.getConnection(url, user, password);
Statement st = conn.createStatement(); Statement st = conn.createStatement();
for (int i = 0; i < queries.length; i++) { for (int i = 0; i < queries.length; i++) {
String query = queries[i]; String query = queries[i];
String expected = expectedResults[i]; String expected = expectedResults[i];
if ( st.execute(query) ) { if ( st.execute(query) ) {
ResultSet rs = st.getResultSet(); ResultSet rs = st.getResultSet();
if (rs.next()) { if (rs.next()) {
String result = ""; String result = "";
Object fieldAccessor = fieldAccessors[i]; Object fieldAccessor = fieldAccessors[i];
if (fieldAccessor instanceof String) { if (fieldAccessor instanceof String) {
result = rs.getString((String)fieldAccessor); result = rs.getString((String)fieldAccessor);
} else if (fieldAccessor instanceof Integer) { } else if (fieldAccessor instanceof Integer) {
result = rs.getString((Integer)fieldAccessor); result = rs.getString((Integer)fieldAccessor);
} else { } else {
System.out.println("Unsupported field accessor value: " + fieldAccessor); System.out.println("Unsupported field accessor value: " + fieldAccessor);
System.exit(1); System.exit(1);
} }
if (!expected.equals(result) && !(query.contains("dolt_commit")) && !(query.contains("dolt_merge"))) { if (!expected.equals(result) && !(query.contains("dolt_commit")) && !(query.contains("dolt_merge"))) {
System.out.println("Query: \n" + query); System.out.println("Query: \n" + query);
System.out.println("Expected:\n" + expected); System.out.println("Expected:\n" + expected);
System.out.println("Result:\n" + result); System.out.println("Result:\n" + result);
System.exit(1); System.exit(1);
} }
} }
} else { } else {
String result = Integer.toString(st.getUpdateCount()); String result = Integer.toString(st.getUpdateCount());
if ( !expected.equals(result) ) { if ( !expected.equals(result) ) {
System.out.println("Query: \n" + query); System.out.println("Query: \n" + query);
System.out.println("Expected:\n" + expected); System.out.println("Expected:\n" + expected);
System.out.println("Rows Updated:\n" + result); System.out.println("Rows Updated:\n" + result);
System.exit(1); System.exit(1);
} }
} }
} }
} catch (SQLException ex) { } catch (SQLException ex) {
System.out.println("An error occurred."); System.out.println("An error occurred.");
ex.printStackTrace(); ex.printStackTrace();
System.exit(1); System.exit(1);
} }
} }
} }

View File

@@ -1,70 +1,70 @@
import mysql.connector import mysql.connector
import sys import sys
QUERY_RESPONSE = [ QUERY_RESPONSE = [
{"create table test (pk int, `value` int, primary key(pk))": []}, {"create table test (pk int, `value` int, primary key(pk))": []},
{"describe test": [ {"describe test": [
('pk', 'int', 'NO', 'PRI', None, ''), ('pk', 'int', 'NO', 'PRI', None, ''),
('value', 'int', 'YES', '', None, '') ('value', 'int', 'YES', '', None, '')
]}, ]},
{"insert into test (pk, `value`) values (0,0)": []}, {"insert into test (pk, `value`) values (0,0)": []},
{"select * from test": [(0, 0)]}, {"select * from test": [(0, 0)]},
# We used to have a bug where spaces after a semicolon in a query # We used to have a bug where spaces after a semicolon in a query
# would cause a client/server disconnect. # would cause a client/server disconnect.
# https://github.com/dolthub/vitess/pull/65 # https://github.com/dolthub/vitess/pull/65
# The following regression tests it. # The following regression tests it.
{"select * from test; ": [(0, 0)]}, {"select * from test; ": [(0, 0)]},
{"select * from test; ": [(0, 0)]}, {"select * from test; ": [(0, 0)]},
# Test the Dolt SQL functions # Test the Dolt SQL functions
{"call dolt_add('-A');": [(0,)]}, {"call dolt_add('-A');": [(0,)]},
{"call dolt_commit('-m', 'my commit')": [('',)]}, {"call dolt_commit('-m', 'my commit')": [('',)]},
{"select COUNT(*) FROM dolt_log": [(2,)]}, {"select COUNT(*) FROM dolt_log": [(2,)]},
{"call dolt_checkout('-b', 'mybranch')": [(0, "Switched to branch 'mybranch'")]}, {"call dolt_checkout('-b', 'mybranch')": [(0, "Switched to branch 'mybranch'")]},
{"insert into test (pk, `value`) values (1,1)": []}, {"insert into test (pk, `value`) values (1,1)": []},
{"call dolt_commit('-a', '-m', 'my commit2')": [('',)]}, {"call dolt_commit('-a', '-m', 'my commit2')": [('',)]},
{"call dolt_checkout('main')": [(0, "Switched to branch 'main'")]}, {"call dolt_checkout('main')": [(0, "Switched to branch 'main'")]},
{"call dolt_merge('mybranch')": [('',1,0,)]}, {"call dolt_merge('mybranch')": [('',1,0,)]},
{"select COUNT(*) FROM dolt_log": [(3,)]}, {"select COUNT(*) FROM dolt_log": [(3,)]},
] ]
def main(): def main():
user = sys.argv[1] user = sys.argv[1]
port = sys.argv[2] port = sys.argv[2]
db = sys.argv[3] db = sys.argv[3]
connection = mysql.connector.connect(user=user, connection = mysql.connector.connect(user=user,
host="127.0.0.1", host="127.0.0.1",
port=port, port=port,
database=db) database=db)
for query_response in QUERY_RESPONSE: for query_response in QUERY_RESPONSE:
query = list(query_response.keys())[0] query = list(query_response.keys())[0]
exp_results = query_response[query] exp_results = query_response[query]
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute(query) cursor.execute(query)
try: try:
results = cursor.fetchall() results = cursor.fetchall()
print(exp_results) print(exp_results)
print(results) print(results)
if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query):
print("Query:") print("Query:")
print(query) print(query)
print("Expected:") print("Expected:")
print(exp_results) print(exp_results)
print("Received:") print("Received:")
print(results) print(results)
exit(1) exit(1)
except mysql.connector.errors.InterfaceError: except mysql.connector.errors.InterfaceError:
# This is a write query # This is a write query
pass pass
cursor.close() cursor.close()
connection.close() connection.close()
exit(0) exit(0)
main() main()

View File

@@ -1,67 +1,67 @@
import sqlalchemy import sqlalchemy
from sqlalchemy.engine import Engine from sqlalchemy.engine import Engine
from sqlalchemy import create_engine from sqlalchemy import create_engine
import sys import sys
QUERY_RESPONSE = [ QUERY_RESPONSE = [
{"create table test (pk int, `value` int, primary key(pk))": []}, {"create table test (pk int, `value` int, primary key(pk))": []},
{"describe test": [ {"describe test": [
('pk', 'int', 'NO', 'PRI', None, ''), ('pk', 'int', 'NO', 'PRI', None, ''),
('value', 'int', 'YES', '', None, '') ('value', 'int', 'YES', '', None, '')
]}, ]},
{"insert into test (pk, `value`) values (0,0)": ()}, {"insert into test (pk, `value`) values (0,0)": ()},
{"select * from test": [(0, 0)]}, {"select * from test": [(0, 0)]},
{"call dolt_add('-A');": [(0,)]}, {"call dolt_add('-A');": [(0,)]},
{"call dolt_commit('-m', 'my commit')": [('',)]}, {"call dolt_commit('-m', 'my commit')": [('',)]},
{"select COUNT(*) FROM dolt_log": [(2,)]}, {"select COUNT(*) FROM dolt_log": [(2,)]},
{"call dolt_checkout('-b', 'mybranch')": [(0, "Switched to branch 'mybranch'")]}, {"call dolt_checkout('-b', 'mybranch')": [(0, "Switched to branch 'mybranch'")]},
{"insert into test (pk, `value`) values (1,1)": []}, {"insert into test (pk, `value`) values (1,1)": []},
{"call dolt_commit('-a', '-m', 'my commit2')": [('',)]}, {"call dolt_commit('-a', '-m', 'my commit2')": [('',)]},
{"call dolt_checkout('main')": [(0, "Switched to branch 'main'")]}, {"call dolt_checkout('main')": [(0, "Switched to branch 'main'")]},
{"call dolt_merge('mybranch')": [('',1,0,)]}, {"call dolt_merge('mybranch')": [('',1,0,)]},
{"select COUNT(*) FROM dolt_log": [(3,)]}, {"select COUNT(*) FROM dolt_log": [(3,)]},
] ]
def main(): def main():
user = sys.argv[1] user = sys.argv[1]
port = int(sys.argv[2]) port = int(sys.argv[2])
db = sys.argv[3] db = sys.argv[3]
conn_string_base = "mysql+mysqlconnector://" conn_string_base = "mysql+mysqlconnector://"
engine = create_engine(conn_string_base + engine = create_engine(conn_string_base +
"{user}@127.0.0.1:{port}/{db}".format(user=user, "{user}@127.0.0.1:{port}/{db}".format(user=user,
port=port, port=port,
db=db) db=db)
) )
with engine.connect() as con: with engine.connect() as con:
for query_response in QUERY_RESPONSE: for query_response in QUERY_RESPONSE:
query = list(query_response.keys())[0] query = list(query_response.keys())[0]
exp_results = query_response[query] exp_results = query_response[query]
result_proxy = con.execute(query) result_proxy = con.execute(query)
try: try:
results = result_proxy.fetchall() results = result_proxy.fetchall()
if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query): if (results != exp_results) and ("dolt_commit" not in query) and ("dolt_merge" not in query):
print("Query:") print("Query:")
print(query) print(query)
print("Expected:") print("Expected:")
print(exp_results) print(exp_results)
print("Received:") print("Received:")
print(results) print(results)
exit(1) exit(1)
# You can't call fetchall on an insert # You can't call fetchall on an insert
# so we'll just ignore the exception # so we'll just ignore the exception
except sqlalchemy.exc.ResourceClosedError: except sqlalchemy.exc.ResourceClosedError:
pass pass
con.close() con.close()
exit(0) exit(0)
main() main()