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.git
The following commit(s) were added to refs/heads/main by this push:
new 7da0bfff0a GH-37257: [Ruby][FlightSQL] Use the same options for auto
prepared statement close request (#37258)
7da0bfff0a is described below
commit 7da0bfff0a710e5ec7b9e44f5d060c781e233d92
Author: Sutou Kouhei <[email protected]>
AuthorDate: Wed Aug 23 10:12:49 2023 +0900
GH-37257: [Ruby][FlightSQL] Use the same options for auto prepared
statement close request (#37258)
### Rationale for this change
If we don't pass the same options for auto prepared statement close
request, the close request may be failed.
For example, it's caused when authentication information in the options.
### What changes are included in this PR?
`ArrowFlightSQL::Client#prepare` change is the main change to use the given
options for auto prepared statement close request too.
Other changes (`gaflight_server_call_context_foreach_incoming_header()` and
related changes) are for testing the above change.
### Are these changes tested?
Yes.
### Are there any user-facing changes?
Yes.
* Closes: #37257
Authored-by: Sutou Kouhei <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
---
c_glib/arrow-flight-glib/client.cpp | 2 +-
c_glib/arrow-flight-glib/server.cpp | 63 ++++++++++++++++++----
c_glib/arrow-flight-glib/server.h | 19 ++++---
.../arrow-flight-glib/arrow-flight-glib-docs.xml | 4 ++
.../lib/arrow-flight-sql/client.rb | 6 +--
ruby/red-arrow-flight-sql/test/helper/server.rb | 7 ++-
ruby/red-arrow-flight-sql/test/test-client.rb | 6 ++-
ruby/red-arrow-flight/lib/arrow-flight/loader.rb | 1 +
.../lib/arrow-flight/server-call-context.rb} | 23 ++++----
9 files changed, 94 insertions(+), 37 deletions(-)
diff --git a/c_glib/arrow-flight-glib/client.cpp
b/c_glib/arrow-flight-glib/client.cpp
index 65bc2d56a5..60dec29dbb 100644
--- a/c_glib/arrow-flight-glib/client.cpp
+++ b/c_glib/arrow-flight-glib/client.cpp
@@ -148,7 +148,7 @@ gaflight_call_options_clear_headers(GAFlightCallOptions
*options)
* @func: (scope call): The user's callback function.
* @user_data: (closure): Data for @func.
*
- * Iterates over all header in the options.
+ * Iterates over all headers in the options.
*
* Since: 9.0.0
*/
diff --git a/c_glib/arrow-flight-glib/server.cpp
b/c_glib/arrow-flight-glib/server.cpp
index 53ecbf6e08..9deb1623b1 100644
--- a/c_glib/arrow-flight-glib/server.cpp
+++ b/c_glib/arrow-flight-glib/server.cpp
@@ -293,9 +293,11 @@
gaflight_message_reader_get_descriptor(GAFlightMessageReader *reader)
}
-typedef struct GAFlightServerCallContextPrivate_ {
+struct GAFlightServerCallContextPrivate {
arrow::flight::ServerCallContext *call_context;
-} GAFlightServerCallContextPrivate;
+ std::string current_incoming_header_key;
+ std::string current_incoming_header_value;
+};
enum {
PROP_CALL_CONTEXT = 1,
@@ -310,6 +312,15 @@ G_DEFINE_TYPE_WITH_PRIVATE(GAFlightServerCallContext,
gaflight_server_call_context_get_instance_private( \
GAFLIGHT_SERVER_CALL_CONTEXT(obj)))
+static void
+gaflight_server_call_context_finalize(GObject *object)
+{
+ auto priv = GAFLIGHT_SERVER_CALL_CONTEXT_GET_PRIVATE(object);
+ priv->current_incoming_header_key.~basic_string();
+ priv->current_incoming_header_value.~basic_string();
+ G_OBJECT_CLASS(gaflight_server_call_context_parent_class)->finalize(object);
+}
+
static void
gaflight_server_call_context_set_property(GObject *object,
guint prop_id,
@@ -333,6 +344,9 @@ gaflight_server_call_context_set_property(GObject *object,
static void
gaflight_server_call_context_init(GAFlightServerCallContext *object)
{
+ auto priv = GAFLIGHT_SERVER_CALL_CONTEXT_GET_PRIVATE(object);
+ new(&(priv->current_incoming_header_key)) std::string;
+ new(&(priv->current_incoming_header_value)) std::string;
}
static void
@@ -340,6 +354,7 @@
gaflight_server_call_context_class_init(GAFlightServerCallContextClass *klass)
{
auto gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->finalize = gaflight_server_call_context_finalize;
gobject_class->set_property = gaflight_server_call_context_set_property;
GParamSpec *spec;
@@ -351,6 +366,33 @@
gaflight_server_call_context_class_init(GAFlightServerCallContextClass *klass)
g_object_class_install_property(gobject_class, PROP_CALL_CONTEXT, spec);
}
+/**
+ * gaflight_server_call_context_foreach_incoming_header:
+ * @context: A #GAFlightServerCallContext.
+ * @func: (scope call): The user's callback function.
+ * @user_data: (closure): Data for @func.
+ *
+ * Iterates over all incoming headers.
+ *
+ * Since: 14.0.0
+ */
+void
+gaflight_server_call_context_foreach_incoming_header(
+ GAFlightServerCallContext *context,
+ GAFlightHeaderFunc func,
+ gpointer user_data)
+{
+ auto priv = GAFLIGHT_SERVER_CALL_CONTEXT_GET_PRIVATE(context);
+ auto flight_context = gaflight_server_call_context_get_raw(context);
+ for (const auto &header : flight_context->incoming_headers()) {
+ priv->current_incoming_header_key = std::string(header.first);
+ priv->current_incoming_header_value = std::string(header.second);
+ func(priv->current_incoming_header_key.c_str(),
+ priv->current_incoming_header_value.c_str(),
+ user_data);
+ }
+}
+
struct GAFlightServerAuthSenderPrivate {
arrow::flight::ServerAuthSender *sender;
@@ -630,9 +672,8 @@ namespace gaflight {
auto klass = GAFLIGHT_SERVER_CUSTOM_AUTH_HANDLER_GET_CLASS(handler_);
auto gacontext = gaflight_server_call_context_new_raw(&context);
auto gtoken = g_bytes_new_static(token.data(), token.size());
- GBytes *gpeer_identity = nullptr;
GError *error = nullptr;
- klass->is_valid(handler_, gacontext, gtoken, &gpeer_identity, &error);
+ auto gpeer_identity = klass->is_valid(handler_, gacontext, gtoken,
&error);
g_bytes_unref(gtoken);
g_object_unref(gacontext);
if (gpeer_identity) {
@@ -718,20 +759,20 @@ gaflight_server_custom_auth_handler_authenticate(
* @context: A #GAFlightServerCallContext.
* @token: The client token. May be the empty string if the client does not
* provide a token.
- * @peer_identity: (out): The identity of the peer, if this authentication
- * method supports it.
* @error: (nullable): Return location for a #GError or %NULL.
*
* Validates a per-call client token.
*
+ * Returns: (nullable) (transfer full): The identity of the peer, if
+ * this authentication method supports it.
+ *
* Since: 12.0.0
*/
-void
+GBytes *
gaflight_server_custom_auth_handler_is_valid(
GAFlightServerCustomAuthHandler *handler,
GAFlightServerCallContext *context,
GBytes *token,
- GBytes **peer_identity,
GError **error)
{
auto flight_handler =
@@ -749,8 +790,10 @@ gaflight_server_custom_auth_handler_is_valid(
status,
"[flight-server-custom-auth-handler]"
"[is-valid]")) {
- *peer_identity = g_bytes_new(flight_peer_identity.data(),
- flight_peer_identity.size());
+ return g_bytes_new(flight_peer_identity.data(),
+ flight_peer_identity.size());
+ } else {
+ return nullptr;
}
}
diff --git a/c_glib/arrow-flight-glib/server.h
b/c_glib/arrow-flight-glib/server.h
index 7fa0dcf878..77ecf36fd5 100644
--- a/c_glib/arrow-flight-glib/server.h
+++ b/c_glib/arrow-flight-glib/server.h
@@ -84,6 +84,13 @@ struct _GAFlightServerCallContextClass
GObjectClass parent_class;
};
+GARROW_AVAILABLE_IN_14_0
+void
+gaflight_server_call_context_foreach_incoming_header(
+ GAFlightServerCallContext *context,
+ GAFlightHeaderFunc func,
+ gpointer user_data);
+
#define GAFLIGHT_TYPE_SERVER_AUTH_SENDER \
(gaflight_server_auth_sender_get_type())
@@ -158,11 +165,10 @@ struct _GAFlightServerCustomAuthHandlerClass
GAFlightServerAuthSender *sender,
GAFlightServerAuthReader *reader,
GError **error);
- void (*is_valid)(GAFlightServerCustomAuthHandler *handler,
- GAFlightServerCallContext *context,
- GBytes *token,
- GBytes **peer_identity,
- GError **error);
+ GBytes *(*is_valid)(GAFlightServerCustomAuthHandler *handler,
+ GAFlightServerCallContext *context,
+ GBytes *token,
+ GError **error);
};
GARROW_AVAILABLE_IN_12_0
@@ -175,12 +181,11 @@ gaflight_server_custom_auth_handler_authenticate(
GError **error);
GARROW_AVAILABLE_IN_12_0
-void
+GBytes *
gaflight_server_custom_auth_handler_is_valid(
GAFlightServerCustomAuthHandler *handler,
GAFlightServerCallContext *context,
GBytes *token,
- GBytes **peer_identity,
GError **error);
diff --git a/c_glib/doc/arrow-flight-glib/arrow-flight-glib-docs.xml
b/c_glib/doc/arrow-flight-glib/arrow-flight-glib-docs.xml
index e078b1c037..e58ff375c5 100644
--- a/c_glib/doc/arrow-flight-glib/arrow-flight-glib-docs.xml
+++ b/c_glib/doc/arrow-flight-glib/arrow-flight-glib-docs.xml
@@ -55,6 +55,10 @@
<title>Index of deprecated API</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback
/></xi:include>
</index>
+ <index id="api-index-14-0-0" role="14.0.0">
+ <title>Index of new symbols in 14.0.0</title>
+ <xi:include href="xml/api-index-14.0.0.xml"><xi:fallback /></xi:include>
+ </index>
<index id="api-index-12-0-0" role="12.0.0">
<title>Index of new symbols in 12.0.0</title>
<xi:include href="xml/api-index-12.0.0.xml"><xi:fallback /></xi:include>
diff --git a/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
b/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
index ff3169d562..dc8815fced 100644
--- a/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
+++ b/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
@@ -18,13 +18,13 @@
module ArrowFlightSQL
class Client
alias_method :prepare_raw, :prepare
- def prepare(*args)
- statement = prepare_raw(*args)
+ def prepare(query, options=nil)
+ statement = prepare_raw(query, options)
if block_given?
begin
yield(statement)
ensure
- statement.close unless statement.closed?
+ statement.close(options) unless statement.closed?
end
else
statement
diff --git a/ruby/red-arrow-flight-sql/test/helper/server.rb
b/ruby/red-arrow-flight-sql/test/helper/server.rb
index f7c935fab9..6426e11f29 100644
--- a/ruby/red-arrow-flight-sql/test/helper/server.rb
+++ b/ruby/red-arrow-flight-sql/test/helper/server.rb
@@ -39,7 +39,7 @@ module Helper
end
def virtual_do_create_prepared_statement(context, request)
- unless request.query == "INSERT INTO page_view_table VALUES (?, true)"
+ unless request.query == "INSERT INTO page_view_table VALUES ($1, true)"
raise Arrow::Error::Invalid.new("invalid SQL")
end
result = ArrowFlightSQL::CreatePreparedStatementResult.new
@@ -62,6 +62,11 @@ module Helper
unless request.handle.to_s == "valid-handle"
raise Arrow::Error::Invalid.new("invalid handle")
end
+ access_key = context.incoming_headers.assoc("x-access-key")
+ unless access_key == ["x-access-key", "secret"]
+ message = "invalid access key: #{access_key.inspect}"
+ raise Arrow::Error::Invalid.new(message)
+ end
end
end
end
diff --git a/ruby/red-arrow-flight-sql/test/test-client.rb
b/ruby/red-arrow-flight-sql/test/test-client.rb
index 21554c1bda..1fff21da01 100644
--- a/ruby/red-arrow-flight-sql/test/test-client.rb
+++ b/ruby/red-arrow-flight-sql/test/test-client.rb
@@ -41,9 +41,11 @@ class TestClient < Test::Unit::TestCase
end
def test_prepare
- insert_sql = "INSERT INTO page_view_table VALUES (?, true)"
+ insert_sql = "INSERT INTO page_view_table VALUES ($1, true)"
block_called = false
- @sql_client.prepare(insert_sql) do |statement|
+ options = ArrowFlight::CallOptions.new
+ options.add_header("x-access-key", "secret")
+ @sql_client.prepare(insert_sql, options) do |statement|
block_called = true
assert_equal([
Arrow::Schema.new(count: :uint64, private: :boolean),
diff --git a/ruby/red-arrow-flight/lib/arrow-flight/loader.rb
b/ruby/red-arrow-flight/lib/arrow-flight/loader.rb
index 042e157693..e9e9e08f32 100644
--- a/ruby/red-arrow-flight/lib/arrow-flight/loader.rb
+++ b/ruby/red-arrow-flight/lib/arrow-flight/loader.rb
@@ -34,6 +34,7 @@ module ArrowFlight
require "arrow-flight/client-options"
require "arrow-flight/location"
require "arrow-flight/record-batch-reader"
+ require "arrow-flight/server-call-context"
require "arrow-flight/server-options"
require "arrow-flight/ticket"
end
diff --git a/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
b/ruby/red-arrow-flight/lib/arrow-flight/server-call-context.rb
similarity index 72%
copy from ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
copy to ruby/red-arrow-flight/lib/arrow-flight/server-call-context.rb
index ff3169d562..7cbad1fd07 100644
--- a/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
+++ b/ruby/red-arrow-flight/lib/arrow-flight/server-call-context.rb
@@ -15,20 +15,17 @@
# specific language governing permissions and limitations
# under the License.
-module ArrowFlightSQL
- class Client
- alias_method :prepare_raw, :prepare
- def prepare(*args)
- statement = prepare_raw(*args)
- if block_given?
- begin
- yield(statement)
- ensure
- statement.close unless statement.closed?
- end
- else
- statement
+module ArrowFlight
+ class ServerCallContext
+ def each_incoming_header
+ return to_enum(__method__) unless block_given?
+ foreach_incoming_header do |key, value|
+ yield(key, value)
end
end
+
+ def incoming_headers
+ each_incoming_header.to_a
+ end
end
end