You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by li...@apache.org on 2022/11/07 19:56:57 UTC

[arrow-adbc] branch main updated: fix(c/driver/postgres): fix wheel builds (#161)

This is an automated email from the ASF dual-hosted git repository.

lidavidm 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 25338f4  fix(c/driver/postgres): fix wheel builds (#161)
25338f4 is described below

commit 25338f4e14627e3dc5fbea3cdf1540f603874b97
Author: David Li <li...@gmail.com>
AuthorDate: Mon Nov 7 14:56:52 2022 -0500

    fix(c/driver/postgres): fix wheel builds (#161)
    
    - Link to nanoarrow
    - Build nanoarrow with -fPIC
    - Run tests on Python wheels
    - Correctly import `importlib.resources`
    - Fake support for prepared statements returning result sets, to
      satisfy how the DBAPI adapter works
    - Pin red-arrow for now
---
 c/cmake_modules/AdbcDefines.cmake                         |  1 +
 c/driver/postgres/CMakeLists.txt                          |  2 ++
 c/driver/postgres/postgres_test.cc                        |  1 -
 c/driver/postgres/statement.cc                            | 15 ++++++++++++++-
 ci/scripts/python_wheel_unix_test.sh                      |  9 +++++----
 glib/Gemfile                                              |  2 +-
 python/adbc_driver_manager/pyproject.toml                 |  5 +++++
 python/adbc_driver_manager/tests/test_dbapi.py            |  6 ++++++
 python/adbc_driver_manager/tests/test_lowlevel.py         |  8 ++++++++
 .../adbc_driver_postgres/adbc_driver_postgres/__init__.py |  2 +-
 python/adbc_driver_postgres/tests/test_lowlevel.py        |  7 +++++++
 ruby/Gemfile                                              |  2 +-
 12 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/c/cmake_modules/AdbcDefines.cmake b/c/cmake_modules/AdbcDefines.cmake
index cf18cd0..6329f88 100644
--- a/c/cmake_modules/AdbcDefines.cmake
+++ b/c/cmake_modules/AdbcDefines.cmake
@@ -73,6 +73,7 @@ endif()
 # Nanoarrow definition
 add_library(nanoarrow STATIC EXCLUDE_FROM_ALL
             ${REPOSITORY_ROOT}/c/vendor/nanoarrow/nanoarrow.c)
+set_property(TARGET nanoarrow PROPERTY POSITION_INDEPENDENT_CODE ON)
 
 # Set common build options
 macro(adbc_configure_target TARGET)
diff --git a/c/driver/postgres/CMakeLists.txt b/c/driver/postgres/CMakeLists.txt
index 2831456..d7d7a72 100644
--- a/c/driver/postgres/CMakeLists.txt
+++ b/c/driver/postgres/CMakeLists.txt
@@ -42,7 +42,9 @@ add_arrow_lib(adbc_driver_postgres
               ${ADBC_LINK_FLAGS}
               SHARED_LINK_LIBS
               ${LIBPQ_LINK_LIBRARIES}
+              nanoarrow
               STATIC_LINK_LIBS
+              ${LIBPQ_LINK_LIBRARIES}
               nanoarrow
               ${LIBPQ_STATIC_LIBRARIES})
 include_directories(SYSTEM ${REPOSITORY_ROOT})
diff --git a/c/driver/postgres/postgres_test.cc b/c/driver/postgres/postgres_test.cc
index 145f545..bd9e824 100644
--- a/c/driver/postgres/postgres_test.cc
+++ b/c/driver/postgres/postgres_test.cc
@@ -101,7 +101,6 @@ class PostgresStatementTest : public ::testing::Test,
 
   void TestSqlPrepareErrorParamCountMismatch() { GTEST_SKIP() << "Not yet implemented"; }
   void TestSqlPrepareGetParameterSchema() { GTEST_SKIP() << "Not yet implemented"; }
-  void TestSqlPrepareSelectNoParams() { GTEST_SKIP() << "Not yet implemented"; }
   void TestSqlPrepareSelectParams() { GTEST_SKIP() << "Not yet implemented"; }
 
   void TestConcurrentStatements() {
diff --git a/c/driver/postgres/statement.cc b/c/driver/postgres/statement.cc
index ecca6c2..2ed645c 100644
--- a/c/driver/postgres/statement.cc
+++ b/c/driver/postgres/statement.cc
@@ -736,10 +736,12 @@ AdbcStatusCode PostgresStatement::ExecutePreparedStatement(
     struct ArrowArrayStream* stream, int64_t* rows_affected, struct AdbcError* error) {
   if (!bind_.release) {
     // TODO: set an empty stream just to unify the code paths
+    SetError(error, "Prepared statements without parameters are not implemented");
     return ADBC_STATUS_NOT_IMPLEMENTED;
   }
   if (stream) {
     // TODO:
+    SetError(error, "Prepared statements returning result sets are not implemented");
     return ADBC_STATUS_NOT_IMPLEMENTED;
   }
 
@@ -758,7 +760,18 @@ AdbcStatusCode PostgresStatement::ExecuteQuery(struct ArrowArrayStream* stream,
                                                struct AdbcError* error) {
   ClearResult();
   if (prepared_) {
-    return ExecutePreparedStatement(stream, rows_affected, error);
+    if (bind_.release || !stream) {
+      return ExecutePreparedStatement(stream, rows_affected, error);
+    }
+    // XXX: don't use a prepared statement to execute a no-parameter
+    // result-set-returning query for now, since we can't easily get
+    // access to COPY there. (This might have to become sequential
+    // executions of COPY (EXECUTE ($n, ...)) TO STDOUT which won't
+    // get all the benefits of a prepared statement.) At preparation
+    // time we don't know whether the query will be used with a result
+    // set or not without analyzing the query (we could prepare both?)
+    // and https://stackoverflow.com/questions/69233792 suggests that
+    // you can't PREPARE a query containing COPY.
   }
   if (!stream) {
     if (!ingest_.target.empty()) {
diff --git a/ci/scripts/python_wheel_unix_test.sh b/ci/scripts/python_wheel_unix_test.sh
index 09cf7f7..e6cd5d9 100755
--- a/ci/scripts/python_wheel_unix_test.sh
+++ b/ci/scripts/python_wheel_unix_test.sh
@@ -41,7 +41,8 @@ import adbc_driver_postgres
 import adbc_driver_postgres.dbapi
 "
 
-# Can't yet run tests (need Postgres database, SQLite driver)
-# for component in adbc_driver_manager adbc_driver_postgres; do
-#     python -m pytest -vvx ${source_dir}/python/$component/tests
-# done
+# Will only run some smoke tests
+echo "=== Testing adbc_driver_manager ==="
+python -m pytest -vvx -k "not sqlite" ${source_dir}/python/adbc_driver_manager/tests
+echo "=== Testing adbc_driver_postgres ==="
+python -m pytest -vvx ${source_dir}/python/adbc_driver_postgres/tests
diff --git a/glib/Gemfile b/glib/Gemfile
index 4af8f0a..4e2fee2 100644
--- a/glib/Gemfile
+++ b/glib/Gemfile
@@ -20,5 +20,5 @@
 source "https://rubygems.org/"
 
 gem "gobject-introspection", ">= 4.0.1"
-gem "red-arrow"
+gem "red-arrow", "< 10.0.0"
 gem "test-unit"
diff --git a/python/adbc_driver_manager/pyproject.toml b/python/adbc_driver_manager/pyproject.toml
index 67a5959..b65723d 100644
--- a/python/adbc_driver_manager/pyproject.toml
+++ b/python/adbc_driver_manager/pyproject.toml
@@ -35,6 +35,11 @@ repository = "https://github.com/apache/arrow-adbc"
 requires = ["Cython", "setuptools >= 61.0.0", "setuptools-scm"]
 build-backend = "setuptools.build_meta"
 
+[tool.pytest.ini_options]
+markers = [
+    "sqlite: tests that require the SQLite driver",
+]
+
 [tool.setuptools_scm]
 root = "../.."
 write_to = "python/adbc_driver_manager/adbc_driver_manager/_version.py"
diff --git a/python/adbc_driver_manager/tests/test_dbapi.py b/python/adbc_driver_manager/tests/test_dbapi.py
index 72b3ec4..f8e6d0f 100644
--- a/python/adbc_driver_manager/tests/test_dbapi.py
+++ b/python/adbc_driver_manager/tests/test_dbapi.py
@@ -42,6 +42,7 @@ def test_type_objects():
     assert dbapi.NUMBER == dbapi.ROWID
 
 
+@pytest.mark.sqlite
 def test_attrs(sqlite):
     assert sqlite.Warning == dbapi.Warning
     assert sqlite.Error == dbapi.Error
@@ -61,6 +62,7 @@ def test_attrs(sqlite):
         assert cur.rowcount == -1
 
 
+@pytest.mark.sqlite
 def test_query_fetch_py(sqlite):
     with sqlite.cursor() as cur:
         cur.execute('SELECT 1, "foo", 2.0')
@@ -86,6 +88,7 @@ def test_query_fetch_py(sqlite):
         assert list(cur) == [(1, "foo", 2.0)]
 
 
+@pytest.mark.sqlite
 def test_query_fetch_arrow(sqlite):
     with sqlite.cursor() as cur:
         cur.execute('SELECT 1, "foo", 2.0')
@@ -98,6 +101,7 @@ def test_query_fetch_arrow(sqlite):
         )
 
 
+@pytest.mark.sqlite
 def test_query_fetch_df(sqlite):
     with sqlite.cursor() as cur:
         cur.execute('SELECT 1, "foo", 2.0')
@@ -113,12 +117,14 @@ def test_query_fetch_df(sqlite):
         )
 
 
+@pytest.mark.sqlite
 def test_query_parameters(sqlite):
     with sqlite.cursor() as cur:
         cur.execute("SELECT ? + 1, ?", (1.0, 2))
         assert cur.fetchall() == [(2.0, 2)]
 
 
+@pytest.mark.sqlite
 def test_executemany(sqlite):
     with sqlite.cursor() as cur:
         cur.execute("CREATE TABLE foo (a, b)")
diff --git a/python/adbc_driver_manager/tests/test_lowlevel.py b/python/adbc_driver_manager/tests/test_lowlevel.py
index 889470b..03f71fd 100644
--- a/python/adbc_driver_manager/tests/test_lowlevel.py
+++ b/python/adbc_driver_manager/tests/test_lowlevel.py
@@ -58,6 +58,7 @@ def test_database_init():
             pass
 
 
+@pytest.mark.sqlite
 def test_connection_get_info(sqlite):
     _, conn = sqlite
     codes = [
@@ -81,6 +82,7 @@ def test_connection_get_info(sqlite):
     assert set(codes) == set(table[0].to_pylist())
 
 
+@pytest.mark.sqlite
 def test_connection_get_objects(sqlite):
     _, conn = sqlite
     data = pyarrow.record_batch(
@@ -109,6 +111,7 @@ def test_connection_get_objects(sqlite):
     assert "strs" in column_names.to_pylist()
 
 
+@pytest.mark.sqlite
 def test_connection_get_table_schema(sqlite):
     _, conn = sqlite
     data = pyarrow.record_batch(
@@ -127,6 +130,7 @@ def test_connection_get_table_schema(sqlite):
     assert data.schema == _import(handle)
 
 
+@pytest.mark.sqlite
 def test_connection_get_table_types(sqlite):
     _, conn = sqlite
     handle = conn.get_table_types()
@@ -134,6 +138,7 @@ def test_connection_get_table_types(sqlite):
     assert "table" in table[0].to_pylist()
 
 
+@pytest.mark.sqlite
 def test_query(sqlite):
     _, conn = sqlite
     with adbc_driver_manager.AdbcStatement(conn) as stmt:
@@ -143,6 +148,7 @@ def test_query(sqlite):
         assert table == pyarrow.table([[1]], names=["1"])
 
 
+@pytest.mark.sqlite
 def test_prepared(sqlite):
     _, conn = sqlite
     with adbc_driver_manager.AdbcStatement(conn) as stmt:
@@ -155,6 +161,7 @@ def test_prepared(sqlite):
         assert table == pyarrow.table([[1, 2, 3, 4]], names=["?"])
 
 
+@pytest.mark.sqlite
 def test_ingest(sqlite):
     _, conn = sqlite
     data = pyarrow.record_batch(
@@ -175,6 +182,7 @@ def test_ingest(sqlite):
         assert table == pyarrow.Table.from_batches([data])
 
 
+@pytest.mark.sqlite
 def test_autocommit(sqlite):
     _, conn = sqlite
 
diff --git a/python/adbc_driver_postgres/adbc_driver_postgres/__init__.py b/python/adbc_driver_postgres/adbc_driver_postgres/__init__.py
index d1186ea..b09c2f4 100644
--- a/python/adbc_driver_postgres/adbc_driver_postgres/__init__.py
+++ b/python/adbc_driver_postgres/adbc_driver_postgres/__init__.py
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-import importlib.metadata
+import importlib.resources
 
 import adbc_driver_manager
 
diff --git a/python/adbc_driver_postgres/tests/test_lowlevel.py b/python/adbc_driver_postgres/tests/test_lowlevel.py
index 66e9b4d..917652e 100644
--- a/python/adbc_driver_postgres/tests/test_lowlevel.py
+++ b/python/adbc_driver_postgres/tests/test_lowlevel.py
@@ -44,3 +44,10 @@ def test_query_trivial(postgres):
 
 def test_version():
     assert adbc_driver_postgres.__version__
+
+
+def test_failed_connection():
+    with pytest.raises(
+        adbc_driver_manager.OperationalError, match=".*libpq.*Failed to connect.*"
+    ):
+        adbc_driver_postgres.connect("invalid")
diff --git a/ruby/Gemfile b/ruby/Gemfile
index c38075c..ae941e9 100644
--- a/ruby/Gemfile
+++ b/ruby/Gemfile
@@ -23,5 +23,5 @@ gemspec
 
 gem "bundler"
 gem "rake"
-gem "red-arrow"
+gem "red-arrow", "< 10.0.0"
 gem "test-unit"