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")
+}

Reply via email to