This is an automated email from the ASF dual-hosted git repository.
paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new 5140bd4 chore(r/adbcpostgresql): Add windows build support (#583)
5140bd4 is described below
commit 5140bd426316c20597a863323084b265ef8a00e8
Author: Dewey Dunnington <[email protected]>
AuthorDate: Fri Apr 14 09:38:44 2023 -0400
chore(r/adbcpostgresql): Add windows build support (#583)
Following the approach here: https://github.com/r-dbi/RPostgres .
Thankfully, there are static builds of libpq (albeit an old ish version)
available via rwinlibs so we don't have to vendor.
There were a few changes required in the driver. First, there is no
`nthll()` in the gcc headers in mingw32/64, so we need a home-grown
bswap64. I took the approach that S2 did (
https://github.com/google/s2geometry/blob/master/src/s2/base/port.h#L236
). Second, the toolchain for R 3.6 on Windows is gcc 4.8, which doesn't
support enums as `unordered_map<>` keys. One could also conditionally
define a custom hasher but it seemed like a static cast to int wasn't
too intrusive.
---
.github/workflows/native-unix.yml | 1 +
c/driver/postgresql/type.cc | 10 ++++-----
c/driver/postgresql/type.h | 4 +++-
c/driver/postgresql/util.h | 13 +++++++++++-
r/adbcpostgresql/.Rbuildignore | 2 ++
r/adbcpostgresql/.gitignore | 1 +
r/adbcpostgresql/configure.win | 8 ++++++--
r/adbcpostgresql/{.gitignore => src/Makevars.ucrt} | 11 +++++++++-
r/adbcpostgresql/{.gitignore => src/Makevars.win} | 24 +++++++++++++++++++++-
.../tests/testthat/test-adbcpostgres-package.R | 5 +++--
r/adbcpostgresql/{.gitignore => tools/winlibs.R} | 9 +++++++-
11 files changed, 74 insertions(+), 14 deletions(-)
diff --git a/.github/workflows/native-unix.yml
b/.github/workflows/native-unix.yml
index f1ae9f3..ee3c5e9 100644
--- a/.github/workflows/native-unix.yml
+++ b/.github/workflows/native-unix.yml
@@ -458,6 +458,7 @@ jobs:
- {os: windows-latest, r: 'release', pkg: 'adbcsqlite'}
- {os: ubuntu-latest, r: 'release', pkg: 'adbcsqlite'}
- {os: macOS-latest, r: 'release', pkg: 'adbcpostgresql'}
+ - {os: windows-latest, r: 'release', pkg: 'adbcpostgresql'}
- {os: ubuntu-latest, r: 'release', pkg: 'adbcpostgresql'}
env:
diff --git a/c/driver/postgresql/type.cc b/c/driver/postgresql/type.cc
index f2f894a..b246604 100644
--- a/c/driver/postgresql/type.cc
+++ b/c/driver/postgresql/type.cc
@@ -29,21 +29,21 @@ void TypeMapping::Insert(uint32_t oid, const char* typname,
const char* typrecei
// Record 'canonical' types
if (std::strcmp(typname, "int4") == 0) {
// DCHECK_EQ(type, PgType::kInt4);
- canonical_types[PgType::kInt4] = oid;
+ canonical_types[static_cast<int32_t>(PgType::kInt4)] = oid;
} else if (std::strcmp(typname, "int8") == 0) {
// DCHECK_EQ(type, PgType::kInt8);
- canonical_types[PgType::kInt8] = oid;
+ canonical_types[static_cast<int32_t>(PgType::kInt8)] = oid;
} else if (std::strcmp(typname, "float8") == 0) {
// DCHECK_EQ(type, PgType::kFloat8);
- canonical_types[PgType::kFloat8] = oid;
+ canonical_types[static_cast<int32_t>(PgType::kFloat8)] = oid;
} else if (std::strcmp(typname, "text") == 0) {
- canonical_types[PgType::kText] = oid;
+ canonical_types[static_cast<int32_t>(PgType::kText)] = oid;
}
// TODO: fill in remainder
}
uint32_t TypeMapping::GetOid(PgType type) const {
- auto it = canonical_types.find(type);
+ auto it = canonical_types.find(static_cast<int32_t>(type));
if (it == canonical_types.end()) {
return 0;
}
diff --git a/c/driver/postgresql/type.h b/c/driver/postgresql/type.h
index 29bc8b7..1f2ce70 100644
--- a/c/driver/postgresql/type.h
+++ b/c/driver/postgresql/type.h
@@ -49,7 +49,9 @@ struct TypeMapping {
std::unordered_map<uint32_t, PgType> type_mapping;
// Maps standardized type names to the PostgreSQL type OID to use
// Example: kInt8 == 20
- std::unordered_map<PgType, uint32_t> canonical_types;
+ // We can't use enum PgType as the key because enums don't have a hash
+ // implementation on gcc 4.8 (i.e., R 3.6 on Windows)
+ std::unordered_map<int32_t, uint32_t> canonical_types;
void Insert(uint32_t oid, const char* typname, const char* typreceive);
/// \return 0 if not found
diff --git a/c/driver/postgresql/util.h b/c/driver/postgresql/util.h
index 264dda7..d8729fd 100644
--- a/c/driver/postgresql/util.h
+++ b/c/driver/postgresql/util.h
@@ -40,11 +40,22 @@ namespace adbcpq {
#define CONCAT(x, y) x##y
#define MAKE_NAME(x, y) CONCAT(x, y)
-#if defined(_WIN32)
+#if defined(_WIN32) && defined(_MSC_VER)
static inline uint32_t SwapNetworkToHost(uint32_t x) { return ntohl(x); }
static inline uint32_t SwapHostToNetwork(uint32_t x) { return htonl(x); }
static inline uint64_t SwapNetworkToHost(uint64_t x) { return ntohll(x); }
static inline uint64_t SwapHostToNetwork(uint64_t x) { return htonll(x); }
+#elif defined(_WIN32)
+// e.g., msys2, where ntohll is not necessarily defined
+static inline uint32_t SwapNetworkToHost(uint32_t x) { return ntohl(x); }
+static inline uint32_t SwapHostToNetwork(uint32_t x) { return htonl(x); }
+static inline uint64_t SwapNetworkToHost(uint64_t x) {
+ return (((x & 0xFFULL) << 56) | ((x & 0xFF00ULL) << 40) | ((x & 0xFF0000ULL)
<< 24) |
+ ((x & 0xFF000000ULL) << 8) | ((x & 0xFF00000000ULL) >> 8) |
+ ((x & 0xFF0000000000ULL) >> 24) | ((x & 0xFF000000000000ULL) >> 40) |
+ ((x & 0xFF00000000000000ULL) >> 56));
+}
+static inline uint64_t SwapHostToNetwork(uint64_t x) { return
SwapNetworkToHost(x); }
#elif defined(__APPLE__)
static inline uint32_t SwapNetworkToHost(uint32_t x) { return
OSSwapBigToHostInt32(x); }
static inline uint32_t SwapHostToNetwork(uint32_t x) { return
OSSwapHostToBigInt32(x); }
diff --git a/r/adbcpostgresql/.Rbuildignore b/r/adbcpostgresql/.Rbuildignore
index dfb192a..7e4b033 100644
--- a/r/adbcpostgresql/.Rbuildignore
+++ b/r/adbcpostgresql/.Rbuildignore
@@ -7,3 +7,5 @@
^src/sqlite3\.c$
^src/sqlite3\.h$
^docker-compose\.yml$
+^configure\.win$
+^windows$
diff --git a/r/adbcpostgresql/.gitignore b/r/adbcpostgresql/.gitignore
index 439ee9b..d025a1b 100644
--- a/r/adbcpostgresql/.gitignore
+++ b/r/adbcpostgresql/.gitignore
@@ -16,3 +16,4 @@
# under the License.
.Rproj.user
+windows/
diff --git a/r/adbcpostgresql/configure.win b/r/adbcpostgresql/configure.win
index 105bb7f..caf6740 100755
--- a/r/adbcpostgresql/configure.win
+++ b/r/adbcpostgresql/configure.win
@@ -15,5 +15,9 @@
# specific language governing permissions and limitations
# under the License.
-# Just call the original configure script
-./configure
+# See configure for a description of this process.
+# This is only for development: this file and bootstrap.R will be removed
+# prior to packaging
+if [ -f bootstrap.R ]; then
+ $R_HOME/bin/Rscript bootstrap.R
+fi
diff --git a/r/adbcpostgresql/.gitignore b/r/adbcpostgresql/src/Makevars.ucrt
similarity index 82%
copy from r/adbcpostgresql/.gitignore
copy to r/adbcpostgresql/src/Makevars.ucrt
index 439ee9b..ef55b83 100644
--- a/r/adbcpostgresql/.gitignore
+++ b/r/adbcpostgresql/src/Makevars.ucrt
@@ -15,4 +15,13 @@
# specific language governing permissions and limitations
# under the License.
-.Rproj.user
+CRT=-ucrt
+include Makevars.win
+
+OBJECTS = init.o \
+ connection.o \
+ database.o \
+ statement.o \
+ type.o \
+ postgresql.o \
+ nanoarrow/nanoarrow.o
diff --git a/r/adbcpostgresql/.gitignore b/r/adbcpostgresql/src/Makevars.win
similarity index 59%
copy from r/adbcpostgresql/.gitignore
copy to r/adbcpostgresql/src/Makevars.win
index 439ee9b..e930737 100644
--- a/r/adbcpostgresql/.gitignore
+++ b/r/adbcpostgresql/src/Makevars.win
@@ -15,4 +15,26 @@
# specific language governing permissions and limitations
# under the License.
-.Rproj.user
+VERSION = 13.2.0
+RWINLIB = ../windows/libpq-$(VERSION)
+PKG_CPPFLAGS = -I$(RWINLIB)/include -I../src -DADBC_EXPORT=""
+PKG_LIBS = -L$(RWINLIB)/lib${R_ARCH}${CRT} \
+ -lpq -lpgport -lpgcommon -lssl -lcrypto -lwsock32 -lsecur32 -lws2_32
-lgdi32 -lcrypt32 -lwldap32
+
+OBJECTS = init.o \
+ connection.o \
+ database.o \
+ statement.o \
+ type.o \
+ postgresql.o \
+ nanoarrow/nanoarrow.o
+
+$(SHLIB):
+
+$(OBJECTS): winlibs
+
+clean:
+ rm -f $(SHLIB) $(OBJECTS)
+
+winlibs:
+ "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/winlibs.R" $(VERSION)
diff --git a/r/adbcpostgresql/tests/testthat/test-adbcpostgres-package.R
b/r/adbcpostgresql/tests/testthat/test-adbcpostgres-package.R
index 0769976..e787b88 100644
--- a/r/adbcpostgresql/tests/testthat/test-adbcpostgres-package.R
+++ b/r/adbcpostgresql/tests/testthat/test-adbcpostgres-package.R
@@ -35,9 +35,10 @@ test_that("default options can open a database and execute a
query", {
stmt <- adbcdrivermanager::adbc_statement_init(con)
expect_s3_class(stmt, "adbcpostgresql_statement")
+ # Use BIGINT to make sure that endian swapping on Windows works
adbcdrivermanager::adbc_statement_set_sql_query(
stmt,
- "CREATE TABLE crossfit (exercise TEXT, difficulty_level INTEGER);"
+ "CREATE TABLE crossfit (exercise TEXT, difficulty_level BIGINT);"
)
adbcdrivermanager::adbc_statement_execute_query(stmt)
adbcdrivermanager::adbc_statement_release(stmt)
@@ -80,7 +81,7 @@ test_that("default options can open a database and execute a
query", {
as.data.frame(stream),
data.frame(
exercise = c("Push Ups", "Pull Ups", "Push Jerk", "Bar Muscle Up"),
- difficulty_level = c(3L, 5L, 7L, 10L),
+ difficulty_level = c(3, 5, 7, 10),
stringsAsFactors = FALSE
)
)
diff --git a/r/adbcpostgresql/.gitignore b/r/adbcpostgresql/tools/winlibs.R
similarity index 67%
copy from r/adbcpostgresql/.gitignore
copy to r/adbcpostgresql/tools/winlibs.R
index 439ee9b..fe0ba19 100644
--- a/r/adbcpostgresql/.gitignore
+++ b/r/adbcpostgresql/tools/winlibs.R
@@ -15,4 +15,11 @@
# specific language governing permissions and limitations
# under the License.
-.Rproj.user
+VERSION <- commandArgs(TRUE)
+if(!file.exists(sprintf("../windows/libpq-%s/include/libpq-fe.h", VERSION))){
+ if(getRversion() < "3.3.0") setInternet2()
+ download.file(sprintf("https://github.com/rwinlib/libpq/archive/v%s.zip",
VERSION), "lib.zip", quiet = TRUE)
+ dir.create("../windows", showWarnings = FALSE)
+ unzip("lib.zip", exdir = "../windows")
+ unlink("lib.zip")
+}