You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ko...@apache.org on 2023/04/02 15:59:36 UTC

[arrow-adbc] branch main updated: feat(glib): add gadbc_connection_get_info() (#571)

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

kou 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 140ed33  feat(glib): add gadbc_connection_get_info() (#571)
140ed33 is described below

commit 140ed330bb53206bf05c721d04507efd0fca0d6f
Author: Sutou Kouhei <ko...@clear-code.com>
AuthorDate: Mon Apr 3 00:59:30 2023 +0900

    feat(glib): add gadbc_connection_get_info() (#571)
    
    Fixes #548.
---
 glib/adbc-glib/connection.c  | 58 +++++++++++++++++++++++++++++++++++++++
 glib/adbc-glib/connection.h  | 31 +++++++++++++++++++++
 glib/test/test-connection.rb | 56 ++++++++++++++++++++++++++++++++++++++
 ruby/lib/adbc/connection.rb  | 29 ++++++++++++++++++++
 ruby/test/test-connection.rb | 65 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 239 insertions(+)

diff --git a/glib/adbc-glib/connection.c b/glib/adbc-glib/connection.c
index 0c83b1e..ebf4b61 100644
--- a/glib/adbc-glib/connection.c
+++ b/glib/adbc-glib/connection.c
@@ -183,6 +183,64 @@ gboolean gadbc_connection_init(GADBCConnection* connection, GADBCDatabase* datab
   return success;
 }
 
+/**
+ * gadbc_connection_get_info:
+ * @connection: A #GADBCConnection.
+ * @info_codes: (nullable) (array length=n_info_codes): A list of
+ *   metadata codes to fetch, or %NULL to fetch all.
+ * @n_info_codes: The length of the info_codes parameter. Ignored if
+ *   info_codes is %NULL.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * The result is an Arrow dataset with the following schema:
+ *
+ * Field Name                  | Field Type
+ * ----------------------------|------------------------
+ * info_name                   | uint32 not null
+ * info_value                  | INFO_SCHEMA
+ *
+ * INFO_SCHEMA is a dense union with members:
+ *
+ * Field Name (Type Code)      | Field Type
+ * ----------------------------|------------------------
+ * string_value (0)            | utf8
+ * bool_value (1)              | bool
+ * int64_value (2)             | int64
+ * int32_bitmask (3)           | int32
+ * string_list (4)             | list<utf8>
+ * int32_to_int32_list_map (5) | map<int32, list<int32>>
+ *
+ * Each metadatum is identified by an integer code.  The recognized
+ * codes are defined as constants.  Codes [0, 10_000) are reserved
+ * for ADBC usage.  Drivers/vendors will ignore requests for
+ * unrecognized codes (the row will be omitted from the result).
+ *
+ * Returns: The result set as `struct ArrowArrayStream *`. It should
+ *   be freed with the `ArrowArrayStream::release` callback then
+ *   g_free() when no longer needed.
+ *
+ * Since: 0.4.0
+ */
+gpointer gadbc_connection_get_info(GADBCConnection* connection, guint32* info_codes,
+                                   gsize n_info_codes, GError** error) {
+  const gchar* context = "[adbc][connection][get-info]";
+  struct AdbcConnection* adbc_connection =
+      gadbc_connection_get_raw(connection, context, error);
+  if (!adbc_connection) {
+    return NULL;
+  }
+  struct ArrowArrayStream* array_stream = g_new0(struct ArrowArrayStream, 1);
+  struct AdbcError adbc_error = {};
+  AdbcStatusCode status_code = AdbcConnectionGetInfo(
+      adbc_connection, info_codes, n_info_codes, array_stream, &adbc_error);
+  if (gadbc_error_check(error, status_code, &adbc_error, context)) {
+    return array_stream;
+  } else {
+    g_free(array_stream);
+    return NULL;
+  }
+}
+
 /**
  * gadbc_connection_get_table_types:
  * @connection: A #GADBCConnection.
diff --git a/glib/adbc-glib/connection.h b/glib/adbc-glib/connection.h
index 50d1a15..a5c3868 100644
--- a/glib/adbc-glib/connection.h
+++ b/glib/adbc-glib/connection.h
@@ -23,6 +23,34 @@
 
 G_BEGIN_DECLS
 
+/**
+ * GADBCInfo:
+ * @GADBC_INFO_VENDOR_NAME: The database vendor/product name (e.g. the
+ *   server name). (type: utf8).
+ * @GADBC_INFO_VENDOR_VERSION: The database vendor/product library version
+ *   (type: utf8).
+ * @GADBC_INFO_VENDOR_ARROW_VERSION: The database vendor/product Arrow
+ *   library version (type: utf8).
+ * @GADBC_INFO_DRIVER_NAME: The driver name (type: utf8).
+ * @GADBC_INFO_DRIVER_VERSION: The driver version (type: utf8).
+ * @GADBC_INFO_DRIVER_ARROW_VERSION: The driver Arrow library version
+ *   (type: utf8).
+ *
+ * The information code that is used by gadbc_connection_get_info().
+ *
+ * They are corresponding to `ADBC_INFO_*` values.
+ *
+ * Since: 0.4.0
+ */
+typedef enum {
+  GADBC_INFO_VENDOR_NAME = 0,
+  GADBC_INFO_VENDOR_VERSION = 1,
+  GADBC_INFO_VENDOR_ARROW_VERSION = 2,
+  GADBC_INFO_DRIVER_NAME = 100,
+  GADBC_INFO_DRIVER_VERSION = 101,
+  GADBC_INFO_DRIVER_ARROW_VERSION = 102,
+} GADBCInfo;
+
 #define GADBC_TYPE_CONNECTION (gadbc_connection_get_type())
 G_DECLARE_DERIVABLE_TYPE(GADBCConnection, gadbc_connection, GADBC, CONNECTION, GObject)
 struct _GADBCConnectionClass {
@@ -41,6 +69,9 @@ gboolean gadbc_connection_init(GADBCConnection* connection, GADBCDatabase* datab
                                GError** error);
 
 GADBC_AVAILABLE_IN_0_4
+gpointer gadbc_connection_get_info(GADBCConnection* connection, guint32* info_codes,
+                                   gsize n_info_codes, GError** error);
+GADBC_AVAILABLE_IN_0_4
 gpointer gadbc_connection_get_table_types(GADBCConnection* connection, GError** error);
 
 G_END_DECLS
diff --git a/glib/test/test-connection.rb b/glib/test/test-connection.rb
index c219178..130f2a0 100644
--- a/glib/test/test-connection.rb
+++ b/glib/test/test-connection.rb
@@ -30,6 +30,62 @@ class ConnectionTest < Test::Unit::TestCase
     end
   end
 
+  def normalize_version(version)
+    return nil if version.nil?
+    version.gsub(/\A\d+\.\d+\.\d+(?:-SNAPSHOT)?\z/, "X.Y.Z")
+  end
+
+  def normalize_info(info)
+    info.collect do |code, value|
+      value = value.values[0] if value.is_a?(Hash)
+      case code
+      when ADBC::Info::VENDOR_VERSION,
+           ADBC::Info::DRIVER_ARROW_VERSION
+        value = normalize_version(value)
+      end
+      [code, value]
+    end
+  end
+
+  sub_test_case("#get_info") do
+    def test_all
+      c_abi_array_stream = @connection.get_info
+      begin
+        reader = Arrow::RecordBatchReader.import(c_abi_array_stream)
+        table = reader.read_all
+        assert_equal([
+                       [ADBC::Info::VENDOR_NAME, "SQLite"],
+                       [ADBC::Info::VENDOR_VERSION, "X.Y.Z"],
+                       [ADBC::Info::DRIVER_NAME, "ADBC SQLite Driver"],
+                       [ADBC::Info::DRIVER_VERSION, "(unknown)"],
+                       [ADBC::Info::DRIVER_ARROW_VERSION, "X.Y.Z"],
+                     ],
+                     normalize_info(table.raw_records))
+        ensure
+        GLib.free(c_abi_array_stream)
+      end
+    end
+
+    def test_multiple
+      codes = [
+        ADBC::Info::VENDOR_NAME,
+        ADBC::Info::DRIVER_NAME,
+      ]
+      c_abi_array_stream = @connection.get_info(codes)
+      begin
+        reader = Arrow::RecordBatchReader.import(c_abi_array_stream)
+        table = reader.read_all
+        assert_equal([
+                       [ADBC::Info::VENDOR_NAME, "SQLite"],
+                       [ADBC::Info::DRIVER_NAME, "ADBC SQLite Driver"],
+                     ],
+                     normalize_info(table.raw_records))
+      ensure
+        GLib.free(c_abi_array_stream)
+      end
+    end
+  end
+
   def test_table_types
     c_abi_array_stream = @connection.table_types
     begin
diff --git a/ruby/lib/adbc/connection.rb b/ruby/lib/adbc/connection.rb
index eeed95c..739f611 100644
--- a/ruby/lib/adbc/connection.rb
+++ b/ruby/lib/adbc/connection.rb
@@ -32,5 +32,34 @@ module ADBC
         statement.ingest(table_name, values, mode: mode)
       end
     end
+
+    def info(codes=nil)
+      unless codes.nil?
+        codes = codes.collect do |code|
+          ADBC::Info.try_convert(code)
+        end
+      end
+      c_abi_array_stream = get_info(codes)
+      begin
+        reader = Arrow::RecordBatchReader.import(c_abi_array_stream)
+        table = reader.read_all
+        values = {}
+        table.raw_records.each do |code, value|
+          value = value.values[0] if value.is_a?(Hash)
+          code = ADBC::Info.try_convert(code)
+          values[code.nick.gsub("-", "_").to_sym] = value
+        end
+        values
+      ensure
+        GLib.free(c_abi_array_stream)
+      end
+    end
+
+    ADBC::Info.values.each do |value|
+      name = value.nick.gsub("-", "_").to_sym
+      define_method(name) do
+        info([name])[name]
+      end
+    end
   end
 end
diff --git a/ruby/test/test-connection.rb b/ruby/test/test-connection.rb
index 2568035..4541449 100644
--- a/ruby/test/test-connection.rb
+++ b/ruby/test/test-connection.rb
@@ -52,4 +52,69 @@ class ConnectionTest < Test::Unit::TestCase
                    @connection.query("SELECT 1"))
     end
   end
+
+  sub_test_case("#info") do
+    def test_all
+      info = @connection.info
+      [
+        :vendor_version,
+        :driver_arrow_version,
+      ].each do |version_name|
+        next unless info.key?(version_name)
+        info[version_name] = normalize_version(info[version_name])
+      end
+      assert_equal({
+                     vendor_name: "SQLite",
+                     vendor_version: "X.Y.Z",
+                     driver_name: "ADBC SQLite Driver",
+                     driver_version: "(unknown)",
+                     driver_arrow_version: "X.Y.Z"
+                   },
+                   info)
+    end
+
+    def test_integer
+      assert_equal({vendor_name: "SQLite"},
+                   @connection.info([ADBC::Info::VENDOR_NAME]))
+    end
+
+    def test_symbol
+      assert_equal({vendor_name: "SQLite"},
+                   @connection.info([:vendor_name]))
+    end
+
+    def test_STRING
+      assert_equal({vendor_name: "SQLite"},
+                   @connection.info(["VENDOR_NAME"]))
+    end
+  end
+
+  def test_vendor_name
+    assert_equal("SQLite", @connection.vendor_name)
+  end
+
+  def test_vendor_version
+    assert_equal("X.Y.Z", normalize_version(@connection.vendor_version))
+  end
+
+  def test_vendor_arrow_version
+    assert_equal(nil, normalize_version(@connection.vendor_arrow_version))
+  end
+
+  def test_driver_name
+    assert_equal("ADBC SQLite Driver", @connection.driver_name)
+  end
+
+  def test_driver_version
+    assert_equal("(unknown)", normalize_version(@connection.driver_version))
+  end
+
+  def test_driver_arrow_version
+    assert_equal("X.Y.Z", normalize_version(@connection.driver_arrow_version))
+  end
+
+  private
+  def normalize_version(version)
+    version&.gsub(/\A\d+\.\d+\.\d+(?:-SNAPSHOT)?\z/, "X.Y.Z")
+  end
 end