Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions R/EXADBI-internal.R
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,45 @@ processIDs <- function(id, quotes = "\"") {
paste0(quotes,make.unique(encodeString(id)),quotes)
}

.parse_exasol_db_version <- function(db_version) {
if (length(db_version) != 1 || is.na(db_version) || !nzchar(db_version)) {
stop("Unsupported Exasol database version: missing DBMS_Ver metadata.")
}

db_version <- trimws(db_version)
parsed_version <- strsplit(db_version, " ", fixed = TRUE)[[1]]
parsed_version <- parsed_version[nzchar(parsed_version)][1]

if (length(parsed_version) == 0 || identical(parsed_version, "")) {
stop(paste0(
"Unsupported Exasol database version: '",
db_version,
"'. Cannot determine compatible IMPORT/EXPORT certificate syntax."
))
}

version_parts <- strsplit(parsed_version, ".", fixed = TRUE)[[1]]
version_parts <- version_parts[nzchar(version_parts)]

if (length(version_parts) < 2 || any(is.na(as.integer(version_parts)))) {
stop(paste0(
"Unsupported Exasol database version: '",
db_version,
"'. Cannot determine compatible IMPORT/EXPORT certificate syntax."
))
}

package_version(parsed_version)
}

.exa_etl_certificate_clause <- function(db_version) {
if (.parse_exasol_db_version(db_version) >= package_version("2025.1.0")) {
" IGNORE CERTIFICATE"
} else {
""
}
}

# This method recognises schema and table identifiers, and applies proper quoting.
# @param string The input string containing identifiers.
# @param statement A boolean indicating whether the input string is a whole statement, or a fully qualified identifier.
Expand Down
7 changes: 5 additions & 2 deletions R/exa.readData.R
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,11 @@ exa.readData <- function(channel, query, encoding = 'UTF-8',
try(.Call(C_asyncRODBCQueryFinish, 0))

protocol <- ifelse(channel@encrypted, "https", "http")
odbc_info <- odbcGetInfo(channel)
certificate_clause <- .exa_etl_certificate_clause(odbc_info[["DBMS_Ver"]])

if (is.na(server)) {
server <- odbcGetInfo(channel)[["Server_Name"]]
server <- odbc_info[["Server_Name"]]
}

serverAddress <- strsplit(server, ":")[[1]]
Expand All @@ -71,7 +73,8 @@ exa.readData <- function(channel, query, encoding = 'UTF-8',
proxyHost <- .Call(C_asyncRODBCProxyHost)
proxyPort <- .Call(C_asyncRODBCProxyPort)
query <- paste0("EXPORT (", query, ") INTO CSV AT '", protocol, "://", proxyHost, ":",
proxyPort, "' FILE 'executeSQL.csv' ENCODING = '",encoding,"' BOOLEAN = 'TRUE/FALSE' WITH COLUMN NAMES IGNORE CERTIFICATE")
proxyPort, "' FILE 'executeSQL.csv' ENCODING = '",encoding,"' BOOLEAN = 'TRUE/FALSE' WITH COLUMN NAMES",
certificate_clause)

on.exit(.Call(C_asyncRODBCQueryFinish, 0))

Expand Down
7 changes: 5 additions & 2 deletions R/exa.writeData.R
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ exa.writeData <- function(channel, data, tableName, tableColumns = NA,
protocol <- ifelse(channel@encrypted, "https", "http")

try(.Call(C_asyncRODBCQueryFinish, 0))
odbc_info <- odbcGetInfo(channel)
certificate_clause <- .exa_etl_certificate_clause(odbc_info[["DBMS_Ver"]])

if (missing(server)) {
server <- odbcGetInfo(channel)[["Server_Name"]]
server <- odbc_info[["Server_Name"]]
}

serverAddress <- strsplit(server, ":")[[1]]
Expand All @@ -82,7 +84,8 @@ exa.writeData <- function(channel, data, tableName, tableColumns = NA,
query <- paste0("IMPORT INTO ", tableName,
columns,
" FROM CSV AT '" , protocol, "://", proxyHost, ":",
proxyPort, "' FILE 'importData.csv' ENCODING = '", encoding, "' IGNORE CERTIFICATE")
proxyPort, "' FILE 'importData.csv' ENCODING = '", encoding, "'",
certificate_clause)
on.exit(.Call(C_asyncRODBCQueryFinish, 0))

fd <- .Call(C_asyncRODBCQueryStart, attr(channel, "handle_ptr"),
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Github CI build validates the package r-exasol against R versions 4.0, 4.1, 4.2,
- https://github.com/marcelboldt/DBItest

For Windows only:
* As this package uses C++14 code, it needs at least RTools >= 4.0.0. Hence, it works only on R >= 4.0.0.
* As this package uses C++17 code, it needs at least RTools >= 4.0.0. Hence, it works only on R >= 4.0.0.
* Please note that the version of RTools must match the installed version of R (RTools 4.2 for R >= 4.2, RTools 4.0 for R4.0/4.1), check https://cran.r-project.org/bin/windows/Rtools/ for further information

The low-level methods such as regards `exa.readData`, `exa.writeData` and `exa.createScript` may work as expected, so
Expand All @@ -42,6 +42,7 @@ Following test were implemented:

1. ODBC drivers 7.1.1 & 7.1.2 under MacOsX BigSur have a dependency issue. If you have problems under MacOsX and see an error message like ```...libexaodbc-io418sys.dylib not found```, please update to the latest ODBC driver, version 7.1.3 works fine.
2. The Exasol ODBC driver does not support encoding of curly braces for passwords in the connection string: You can use curly braces to encode semicolons in passwords in the connection string, like `...,PWD={he;llo},...`. However, passwords like `he{{;o` are currently not supported.
3. `exa.readData()` and `exa.writeData()` adapt the `IMPORT`/`EXPORT` certificate syntax to the connected database version. Exasol 2025.1.0 and later require `IGNORE CERTIFICATE`, while older releases do not accept it. If the server version cannot be determined, the package stops with an error instead of guessing.

## Getting started

Expand Down
13 changes: 6 additions & 7 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ fi
## Setup RBin
RBIN="${R_HOME}/bin/R"

CXX14=`"${RBIN}" CMD config CXX14`
if test -z "$CXX14"; then
AC_MSG_ERROR([No C++14 compiler is available])
CXX17=`"${RBIN}" CMD config CXX17`
if test -z "$CXX17"; then
AC_MSG_ERROR([No C++17 compiler is available])
fi
CXX14STD=`"${RBIN}" CMD config CXX14STD`
CXX17STD=`"${RBIN}" CMD config CXX17STD`
CPPFLAGS=`"${RBIN}" CMD config CPPFLAGS`
CXXFLAGS=`"${RBIN}" CMD config CXX14FLAGS`
CXX="${CXX14} ${CXX14STD}"
CXXFLAGS=`"${RBIN}" CMD config CXX17FLAGS`
CXX="${CXX17} ${CXX17STD}"
echo "CPPFLAGS:${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} -I. ${UNIT_TESTFLAGS_CPPFLAGS} ${OPENSSL_INCLUDES} ${ODBC_CFLAGS}"
echo "CPPFLAGS:${CPPFLAGS}"
Expand Down
1 change: 1 addition & 0 deletions doc/changes/changes_7.2.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ t.b.d.
- #146: Update cran repo used in CI to focal-cran40 and with that removes tests for Ubuntu 18.04 and R3.5/6, because they are end of life.
- #157: Fixed clone connection with ssl certificate
- #162: Ignore certificate in EXPORT/IMPORT statements
- #170: Version-gated certificate syntax for EXPORT/IMPORT statements
- #163: Fixed nightly tests

## Refactorings
Expand Down
2 changes: 1 addition & 1 deletion src/Makevars.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ PKG_CPPFLAGS = @CPPFLAGS@
CPP_SOURCES = @PKG_SOURCES@
CPP_TEST_SOURCES = @PKG_TEST_SOURCES@
SOURCES = $(CPP_SOURCES) $(CPP_TEST_SOURCES)
CXX_STD = CXX14
CXX_STD = CXX17
OBJECTS = @PKG_OBJ_FILES@
2 changes: 1 addition & 1 deletion src/Makevars.ucrt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
PKG_LIBS=-lodbc32 -lpthread -lws2_32 -lssl -lcrypto -lws2_32 -lcrypt32 -lz
PKG_CPPFLAGS = -I.
SOURCES = r_exasol/connection_context.cpp r_exasol/rconnection/r_reader_connection.cpp r_exasol/rconnection/r_writer_connection.cpp r_exasol/ssl/certificate.cpp r_exasol/connection/socket/socket_impl.cpp r_exasol/connection/socket/ssl_socket_impl.cpp r_exasol/connection/protocol/meta_info_reader.cpp r_exasol/connection/protocol/common.cpp r_exasol/connection/protocol/http/writer/http_chunk_writer.cpp r_exasol/connection/protocol/http/reader/http_chunk_reader.cpp r_exasol/connection/protocol/http/conn/http_connection_establisher.cpp r_exasol/connection/protocol/https/conn/https_connection_establisher.cpp r_exasol/connection/connection_controller.cpp r_exasol/connection/connection_factory_impl.cpp r_exasol/odbc/odbc_query_executor.cpp r_exasol/odbc/odbc_session_info_impl.cpp connection.cpp r_exasol/debug_print/debug_printer.cpp r_exasol/debug_print/file_logger.cpp tests/test_runner.cpp
CXX_STD = CXX14
CXX_STD = CXX17
OBJECTS = r_exasol/connection_context.o r_exasol/rconnection/r_reader_connection.o r_exasol/rconnection/r_writer_connection.o r_exasol/ssl/certificate.o r_exasol/connection/socket/socket_impl.o r_exasol/connection/socket/ssl_socket_impl.o r_exasol/connection/protocol/meta_info_reader.o r_exasol/connection/protocol/common.o r_exasol/connection/protocol/http/writer/http_chunk_writer.o r_exasol/connection/protocol/http/reader/http_chunk_reader.o r_exasol/connection/protocol/http/conn/http_connection_establisher.o r_exasol/connection/protocol/https/conn/https_connection_establisher.o r_exasol/connection/connection_controller.o r_exasol/connection/connection_factory_impl.o r_exasol/odbc/odbc_query_executor.o r_exasol/odbc/odbc_session_info_impl.o connection.o r_exasol/debug_print/debug_printer.o r_exasol/debug_print/file_logger.o tests/test_runner.o
OBJECTS += exasol.o

Expand Down
2 changes: 1 addition & 1 deletion src/Makevars.win
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ OPENSSL_VERSION=1.1.1k
PKG_LIBS=-lodbc32 -lpthread -lws2_32 -L../windows/openssl-$(OPENSSL_VERSION)/lib${R_ARCH}${CRT} -lssl -lcrypto -lws2_32 -lcrypt32
PKG_CPPFLAGS = -I. -I../windows/openssl-$(OPENSSL_VERSION)/include
SOURCES = r_exasol/connection_context.cpp r_exasol/rconnection/r_reader_connection.cpp r_exasol/rconnection/r_writer_connection.cpp r_exasol/ssl/certificate.cpp r_exasol/connection/socket/socket_impl.cpp r_exasol/connection/socket/ssl_socket_impl.cpp r_exasol/connection/protocol/meta_info_reader.cpp r_exasol/connection/protocol/common.cpp r_exasol/connection/protocol/http/writer/http_chunk_writer.cpp r_exasol/connection/protocol/http/reader/http_chunk_reader.cpp r_exasol/connection/protocol/http/conn/http_connection_establisher.cpp r_exasol/connection/protocol/https/conn/https_connection_establisher.cpp r_exasol/connection/connection_controller.cpp r_exasol/connection/connection_factory_impl.cpp r_exasol/odbc/odbc_query_executor.cpp r_exasol/odbc/odbc_session_info_impl.cpp connection.cpp r_exasol/debug_print/debug_printer.cpp r_exasol/debug_print/file_logger.cpp tests/test_runner.cpp
CXX_STD = CXX14
CXX_STD = CXX17
OBJECTS = r_exasol/connection_context.o r_exasol/rconnection/r_reader_connection.o r_exasol/rconnection/r_writer_connection.o r_exasol/ssl/certificate.o r_exasol/connection/socket/socket_impl.o r_exasol/connection/socket/ssl_socket_impl.o r_exasol/connection/protocol/meta_info_reader.o r_exasol/connection/protocol/common.o r_exasol/connection/protocol/http/writer/http_chunk_writer.o r_exasol/connection/protocol/http/reader/http_chunk_reader.o r_exasol/connection/protocol/http/conn/http_connection_establisher.o r_exasol/connection/protocol/https/conn/https_connection_establisher.o r_exasol/connection/connection_controller.o r_exasol/connection/connection_factory_impl.o r_exasol/odbc/odbc_query_executor.o r_exasol/odbc/odbc_session_info_impl.o connection.o r_exasol/debug_print/debug_printer.o r_exasol/debug_print/file_logger.o tests/test_runner.o
OBJECTS += exasol.o

Expand Down
3 changes: 2 additions & 1 deletion tests/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ RUN add-apt-repository -y ppa:deadsnakes/ppa
RUN apt-get update && \
apt-get install -y --no-install-recommends "r-base-core=$R_VERSION" "r-base-dev=$R_VERSION" curl \
libcurl4-openssl-dev libssl-dev \
libfontconfig1-dev libssh2-1-dev libxml2-dev zlib1g-dev unixodbc-dev \
libfontconfig1-dev libssh2-1-dev libxml2-dev libuv1-dev zlib1g-dev unixodbc-dev \
libfreetype6-dev libpng-dev libtiff5-dev libjpeg-dev \
libharfbuzz-dev libfribidi-dev cmake && \
apt-get -y clean && apt-get -y autoremove
ENV GITHUB_PAT=$GH_TOKEN
RUN Rscript -e 'install.packages("testthat")'
RUN Rscript -e 'install.packages("assertthat")'
RUN Rscript -e 'install.packages("devtools", dependencies = TRUE)'
RUN Rscript -e 'install.packages("remotes")'
RUN Rscript -e 'install.packages("RODBC")'
Expand Down
4 changes: 2 additions & 2 deletions tests/cran-submission/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ RUN add-apt-repository -y ppa:deadsnakes/ppa
RUN apt-get update && \
apt-get install -y --no-install-recommends "r-base-core=$R_VERSION" "r-base-dev=$R_VERSION" curl \
libcurl4-openssl-dev libssl-dev \
libssh2-1-dev libxml2-dev zlib1g-dev unixodbc-dev \
libssh2-1-dev libxml2-dev libuv1-dev zlib1g-dev unixodbc-dev \
texlive-latex-base texlive-fonts-recommended texlive-fonts-extra \
texlive-latex-extra texinfo && \
apt-get -y clean && apt-get -y autoremove
RUN Rscript -e 'install.packages("testthat")'
RUN Rscript -e 'install.packages("DBI")'
RUN Rscript -e 'install.packages("assertthat")'
RUN Rscript -e 'install.packages("DBI")'
RUN Rscript -e 'install.packages("xml2")'
RUN Rscript -e 'install.packages("DBItest")'
RUN Rscript -e 'install.packages("devtools", dependencies=TRUE)'
Expand Down
7 changes: 4 additions & 3 deletions tests/run_test_within_docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ fi

TEST_DIR="$1"

#Install r-exasol library via devtools
# Install r-exasol directly so the test container does not depend on devtools
# at runtime.
cd "${TEST_DIR}"
Rscript -e 'devtools::install()'
R CMD INSTALL --no-multiarch --with-keep.source .

export HAS_LOCAL_EXASOL_TEST_DB=true

Expand Down Expand Up @@ -39,4 +40,4 @@ fi

#run unit tests
cd tests
$TST_CMD
$TST_CMD
21 changes: 21 additions & 0 deletions tests/testthat/test-etl-certificate-clause.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
test_that("etl certificate clause is enabled for 2025.1.0 and later", {
expect_equal(exasol:::.exa_etl_certificate_clause("2025.1.0"), " IGNORE CERTIFICATE")
expect_equal(exasol:::.exa_etl_certificate_clause("2025.1.0 build 12"), " IGNORE CERTIFICATE")
expect_equal(exasol:::.exa_etl_certificate_clause("2026.2.3"), " IGNORE CERTIFICATE")
})

test_that("etl certificate clause is omitted for older versions", {
expect_equal(exasol:::.exa_etl_certificate_clause("7.1.17"), "")
expect_equal(exasol:::.exa_etl_certificate_clause("2024.12.99"), "")
})

test_that("etl certificate clause fails closed for unknown versions", {
expect_error(
exasol:::.exa_etl_certificate_clause("unknown"),
"Cannot determine compatible IMPORT/EXPORT certificate syntax"
)
expect_error(
exasol:::.exa_etl_certificate_clause(""),
"missing DBMS_Ver metadata"
)
})
Loading