mirror of
https://github.com/dolthub/dolt.git
synced 2025-12-21 11:59:41 -06:00
add mariadb connectors for existing langs
This commit is contained in:
59
.github/actions/mysql-client-tests/Dockerfile
vendored
59
.github/actions/mysql-client-tests/Dockerfile
vendored
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
199
integration-tests/mysql-client-tests/c/mariadb-connector-test.c
Normal file
199
integration-tests/mysql-client-tests/c/mariadb-connector-test.c
Normal file
@@ -0,0 +1,199 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
#include <mariadb/mysql.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -0,0 +1,88 @@
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <mariadb/conncpp.hpp>
|
||||
|
||||
#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] << " <user> <port> <database>" << 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<sql::Connection> con(driver->connect(url, properties));
|
||||
|
||||
for ( int i = 0; i < QUERIES_SIZE; i++ ) {
|
||||
try {
|
||||
std::unique_ptr<sql::Statement> stmt(con->createStatement());
|
||||
|
||||
if ( is_update[i] ) {
|
||||
stmt->executeUpdate(queries[i]);
|
||||
} else {
|
||||
std::unique_ptr<sql::ResultSet> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<AssemblyName>dotnet-mysql-client-test</AssemblyName>
|
||||
<AssemblyName>mysql-client-test</AssemblyName>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<AssemblyName>dotnet-mysql-connector-test</AssemblyName>
|
||||
<AssemblyName>mysql-connector-test</AssemblyName>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <user> <port> <database>")
|
||||
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
|
||||
|
||||
43
integration-tests/mysql-client-tests/elixir/mysql/mix.exs
Normal file
43
integration-tests/mysql-client-tests/elixir/mysql/mix.exs
Normal file
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -40,3 +40,4 @@ defmodule Simple.MixProject do
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
117
integration-tests/mysql-client-tests/java/pom.xml
Normal file
117
integration-tests/mysql-client-tests/java/pom.xml
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.dolthub</groupId>
|
||||
<artifactId>j</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>8.0.33</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mariadb.jdbc</groupId>
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
<version>3.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mariadb</groupId>
|
||||
<artifactId>r2dbc-mariadb</artifactId>
|
||||
<version>1.2.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>mysql-connector-test</id>
|
||||
<phase>package</phase>
|
||||
<goals><goal>shade</goal></goals>
|
||||
<configuration>
|
||||
<finalName>mysql-connector-test</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>MySQLConnectorTest</mainClass>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>mysql-connector-test-collation</id>
|
||||
<phase>package</phase>
|
||||
<goals><goal>shade</goal></goals>
|
||||
<configuration>
|
||||
<finalName>mysql-connector-test-collation</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>MySQLConnectorTest_Collation</mainClass>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>mariadb-connector-test</id>
|
||||
<phase>package</phase>
|
||||
<goals><goal>shade</goal></goals>
|
||||
<configuration>
|
||||
<finalName>mariadb-connector-test</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>MariaDBConnectorTest</mainClass>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>mariadb-R2DBC-test</id>
|
||||
<phase>package</phase>
|
||||
<goals><goal>shade</goal></goals>
|
||||
<configuration>
|
||||
<finalName>mariadb-R2DBC-test</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>MariaDBR2DBCTest</mainClass>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <user> <port> <database>");
|
||||
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<Void> 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user