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 9fea4eedf5 GH-37143: [GLib][FlightSQL] Add support for prepared INSERT
(#37196)
9fea4eedf5 is described below
commit 9fea4eedf5ceb06943d6443d08b00bc2fd248226
Author: Sutou Kouhei <[email protected]>
AuthorDate: Fri Aug 18 17:10:07 2023 +0900
GH-37143: [GLib][FlightSQL] Add support for prepared INSERT (#37196)
### Rationale for this change
Prepared INSERT is useful for large INSERT.
### What changes are included in this PR?
Sorry. This is too large I thought.
Core bindings are the followings:
* `GAFLightSQLPreparedStatement`
* `gaflightsql_client_prepare()`
Others are for writing test of them. We need to implement a test server for
prepared INSERT. Others are for it.
An exception is `ruby/red-arrow-flight-sql/lib/` change. It's for
convenient API for `gaflightsql_client_prepare()`.
### Are these changes tested?
Yes.
### Are there any user-facing changes?
Yes.
* Closes: #37143
Authored-by: Sutou Kouhei <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
---
c_glib/arrow-flight-glib/client.cpp | 18 +-
c_glib/arrow-flight-glib/client.hpp | 4 +-
c_glib/arrow-flight-glib/common.cpp | 23 +-
c_glib/arrow-flight-glib/server.cpp | 57 ++
c_glib/arrow-flight-glib/server.h | 17 +
c_glib/arrow-flight-glib/server.hpp | 8 +
c_glib/arrow-flight-sql-glib/client.cpp | 383 ++++++++++++-
c_glib/arrow-flight-sql-glib/client.h | 70 +++
c_glib/arrow-flight-sql-glib/client.hpp | 11 +-
c_glib/arrow-flight-sql-glib/server.cpp | 611 ++++++++++++++++++++-
c_glib/arrow-flight-sql-glib/server.h | 151 +++++
c_glib/arrow-flight-sql-glib/server.hpp | 21 +
c_glib/arrow-glib/version.h.in | 23 +
.../arrow-flight-sql-glib-docs.xml | 8 +
c_glib/test/flight-sql/test-client.rb | 29 +
.../test-create-prepared-statement-result.rb | 47 ++
c_glib/test/helper/buildable.rb | 10 +
c_glib/test/helper/flight-sql-server.rb | 26 +
.../lib/arrow-flight-sql/{loader.rb => client.rb} | 30 +-
.../lib/arrow-flight-sql/loader.rb | 1 +
ruby/red-arrow-flight-sql/test/helper/server.rb | 26 +
ruby/red-arrow-flight-sql/test/test-client.rb | 21 +
22 files changed, 1552 insertions(+), 43 deletions(-)
diff --git a/c_glib/arrow-flight-glib/client.cpp
b/c_glib/arrow-flight-glib/client.cpp
index 7097195f5f..65bc2d56a5 100644
--- a/c_glib/arrow-flight-glib/client.cpp
+++ b/c_glib/arrow-flight-glib/client.cpp
@@ -689,16 +689,14 @@ gaflight_client_do_get(GAFlightClient *client,
if (options) {
flight_options = gaflight_call_options_get_raw(options);
}
- std::unique_ptr<arrow::flight::FlightStreamReader> flight_reader;
auto result = flight_client->DoGet(*flight_options, *flight_ticket);
- auto status = std::move(result).Value(&flight_reader);
- if (garrow::check(error,
- status,
- "[flight-client][do-get]")) {
- return gaflight_stream_reader_new_raw(flight_reader.release());
- } else {
- return NULL;
+ if (!garrow::check(error,
+ result,
+ "[flight-client][do-get]")) {
+ return nullptr;
}
+ auto flight_reader = std::move(*result);
+ return gaflight_stream_reader_new_raw(flight_reader.release(), TRUE);
}
@@ -707,11 +705,13 @@ G_END_DECLS
GAFlightStreamReader *
gaflight_stream_reader_new_raw(
- arrow::flight::FlightStreamReader *flight_reader)
+ arrow::flight::FlightStreamReader *flight_reader,
+ gboolean is_owner)
{
return GAFLIGHT_STREAM_READER(
g_object_new(GAFLIGHT_TYPE_STREAM_READER,
"reader", flight_reader,
+ "is-owner", is_owner,
NULL));
}
diff --git a/c_glib/arrow-flight-glib/client.hpp
b/c_glib/arrow-flight-glib/client.hpp
index 28d15ef2c4..b6b768b8d3 100644
--- a/c_glib/arrow-flight-glib/client.hpp
+++ b/c_glib/arrow-flight-glib/client.hpp
@@ -25,7 +25,9 @@
GAFlightStreamReader *
-gaflight_stream_reader_new_raw(arrow::flight::FlightStreamReader
*flight_reader);
+gaflight_stream_reader_new_raw(
+ arrow::flight::FlightStreamReader *flight_reader,
+ gboolean is_owner);
arrow::flight::FlightCallOptions *
gaflight_call_options_get_raw(GAFlightCallOptions *options);
diff --git a/c_glib/arrow-flight-glib/common.cpp
b/c_glib/arrow-flight-glib/common.cpp
index 952f7ec6bc..5aee348303 100644
--- a/c_glib/arrow-flight-glib/common.cpp
+++ b/c_glib/arrow-flight-glib/common.cpp
@@ -1223,10 +1223,12 @@ gaflight_stream_chunk_get_metadata(GAFlightStreamChunk
*chunk)
typedef struct GAFlightRecordBatchReaderPrivate_ {
arrow::flight::MetadataRecordBatchReader *reader;
+ bool is_owner;
} GAFlightRecordBatchReaderPrivate;
enum {
PROP_READER = 1,
+ PROP_IS_OWNER,
};
G_DEFINE_TYPE_WITH_PRIVATE(GAFlightRecordBatchReader,
@@ -1242,9 +1244,9 @@ static void
gaflight_record_batch_reader_finalize(GObject *object)
{
auto priv = GAFLIGHT_RECORD_BATCH_READER_GET_PRIVATE(object);
-
- delete priv->reader;
-
+ if (priv->is_owner) {
+ delete priv->reader;
+ }
G_OBJECT_CLASS(gaflight_info_parent_class)->finalize(object);
}
@@ -1262,6 +1264,9 @@ gaflight_record_batch_reader_set_property(GObject *object,
static_cast<arrow::flight::MetadataRecordBatchReader *>(
g_value_get_pointer(value));
break;
+ case PROP_IS_OWNER:
+ priv->is_owner = g_value_get_boolean(value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -1283,11 +1288,19 @@
gaflight_record_batch_reader_class_init(GAFlightRecordBatchReaderClass *klass)
GParamSpec *spec;
spec = g_param_spec_pointer("reader",
- "Reader",
- "The raw
arrow::flight::MetadataRecordBatchReader *",
+ nullptr,
+ nullptr,
static_cast<GParamFlags>(G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property(gobject_class, PROP_READER, spec);
+
+ spec = g_param_spec_boolean("is-owner",
+ nullptr,
+ nullptr,
+ TRUE,
+ static_cast<GParamFlags>(G_PARAM_WRITABLE |
+
G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property(gobject_class, PROP_IS_OWNER, spec);
}
/**
diff --git a/c_glib/arrow-flight-glib/server.cpp
b/c_glib/arrow-flight-glib/server.cpp
index 0df710df6f..53ecbf6e08 100644
--- a/c_glib/arrow-flight-glib/server.cpp
+++ b/c_glib/arrow-flight-glib/server.cpp
@@ -41,6 +41,10 @@ G_BEGIN_DECLS
* IPC payloads to be sent in `FlightData` protobuf messages by
* #GArrowRecordBatchReader`.
*
+ * #GAFlightMessageReader is a class for IPC payloads uploaded by a
+ * client. Also allows reading application-defined metadata via the
+ * Flight protocol.
+ *
* #GAFlightServerAuthSender is a class for sending messages to the
* client during an authentication handshake.
*
@@ -258,6 +262,37 @@ gaflight_record_batch_stream_new(GArrowRecordBatchReader
*reader,
}
+G_DEFINE_TYPE(GAFlightMessageReader,
+ gaflight_message_reader,
+ GAFLIGHT_TYPE_RECORD_BATCH_READER)
+
+static void
+gaflight_message_reader_init(GAFlightMessageReader *object)
+{
+}
+
+static void
+gaflight_message_reader_class_init(GAFlightMessageReaderClass *klass)
+{
+}
+
+/**
+ * gaflight_message_reader_get_descriptor:
+ * @reader: A #GAFlightMessageReader.
+ *
+ * Returns: (transfer full): The descriptor for this upload.
+ *
+ * Since: 14.0.0
+ */
+GAFlightDescriptor *
+gaflight_message_reader_get_descriptor(GAFlightMessageReader *reader)
+{
+ auto flight_reader = gaflight_message_reader_get_raw(reader);
+ const auto &flight_descriptor = flight_reader->descriptor();
+ return gaflight_descriptor_new_raw(&flight_descriptor);
+}
+
+
typedef struct GAFlightServerCallContextPrivate_ {
arrow::flight::ServerCallContext *call_context;
} GAFlightServerCallContextPrivate;
@@ -1215,6 +1250,28 @@ gaflight_data_stream_get_raw(GAFlightDataStream *stream)
return priv->stream;
}
+
+GAFlightMessageReader *
+gaflight_message_reader_new_raw(
+ arrow::flight::FlightMessageReader *flight_reader,
+ gboolean is_owner)
+{
+ return GAFLIGHT_MESSAGE_READER(
+ g_object_new(GAFLIGHT_TYPE_MESSAGE_READER,
+ "reader", flight_reader,
+ "is-owner", is_owner,
+ NULL));
+}
+
+arrow::flight::FlightMessageReader *
+gaflight_message_reader_get_raw(GAFlightMessageReader *reader)
+{
+ auto flight_reader =
+ gaflight_record_batch_reader_get_raw(GAFLIGHT_RECORD_BATCH_READER(reader));
+ return static_cast<arrow::flight::FlightMessageReader *>(flight_reader);
+}
+
+
GAFlightServerCallContext *
gaflight_server_call_context_new_raw(
const arrow::flight::ServerCallContext *flight_call_context)
diff --git a/c_glib/arrow-flight-glib/server.h
b/c_glib/arrow-flight-glib/server.h
index 3ad93d05d2..7fa0dcf878 100644
--- a/c_glib/arrow-flight-glib/server.h
+++ b/c_glib/arrow-flight-glib/server.h
@@ -55,6 +55,23 @@ gaflight_record_batch_stream_new(GArrowRecordBatchReader
*reader,
GArrowWriteOptions *options);
+#define GAFLIGHT_TYPE_MESSAGE_READER \
+ (gaflight_message_reader_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightMessageReader,
+ gaflight_message_reader,
+ GAFLIGHT,
+ MESSAGE_READER,
+ GAFlightRecordBatchReader)
+struct _GAFlightMessageReaderClass
+{
+ GAFlightRecordBatchReaderClass parent_class;
+};
+
+GARROW_AVAILABLE_IN_14_0
+GAFlightDescriptor *
+gaflight_message_reader_get_descriptor(GAFlightMessageReader *reader);
+
+
#define GAFLIGHT_TYPE_SERVER_CALL_CONTEXT \
(gaflight_server_call_context_get_type())
G_DECLARE_DERIVABLE_TYPE(GAFlightServerCallContext,
diff --git a/c_glib/arrow-flight-glib/server.hpp
b/c_glib/arrow-flight-glib/server.hpp
index 4cd9b4cf34..6b273dc9e5 100644
--- a/c_glib/arrow-flight-glib/server.hpp
+++ b/c_glib/arrow-flight-glib/server.hpp
@@ -27,6 +27,14 @@
arrow::flight::FlightDataStream *
gaflight_data_stream_get_raw(GAFlightDataStream *stream);
+GAFlightMessageReader *
+gaflight_message_reader_new_raw(
+ arrow::flight::FlightMessageReader *flight_reader,
+ gboolean is_owner);
+arrow::flight::FlightMessageReader *
+gaflight_message_reader_get_raw(GAFlightMessageReader *reader);
+
+
GAFlightServerCallContext *
gaflight_server_call_context_new_raw(
const arrow::flight::ServerCallContext *flight_call_context);
diff --git a/c_glib/arrow-flight-sql-glib/client.cpp
b/c_glib/arrow-flight-sql-glib/client.cpp
index f05319532c..8e1cf11549 100644
--- a/c_glib/arrow-flight-sql-glib/client.cpp
+++ b/c_glib/arrow-flight-sql-glib/client.cpp
@@ -32,11 +32,327 @@ G_BEGIN_DECLS
*
* #GAFlightSQLClient is a class for Apache Arrow Flight SQL client.
*
+ * #GAFlightSQLPreparedStatement is a class for prepared statement.
+ *
* Since: 9.0.0
*/
+struct GAFlightSQLPreparedStatementPrivate {
+ std::shared_ptr<arrow::flight::sql::PreparedStatement> statement;
+ GAFlightSQLClient *client;
+};
+
+enum {
+ PROP_STATEMENT = 1,
+ PROP_PREPARED_STATEMENT_CLIENT,
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GAFlightSQLPreparedStatement,
+ gaflightsql_prepared_statement,
+ G_TYPE_OBJECT)
+
+#define GAFLIGHTSQL_PREPARED_STATEMENT_GET_PRIVATE(object) \
+ static_cast<GAFlightSQLPreparedStatementPrivate *>( \
+ gaflightsql_prepared_statement_get_instance_private( \
+ GAFLIGHTSQL_PREPARED_STATEMENT(object)))
+
+static void
+gaflightsql_prepared_statement_dispose(GObject *object)
+{
+ auto priv = GAFLIGHTSQL_PREPARED_STATEMENT_GET_PRIVATE(object);
+
+ if (priv->client) {
+ g_object_unref(priv->client);
+ priv->client = nullptr;
+ }
+
+ G_OBJECT_CLASS(gaflightsql_prepared_statement_parent_class)->dispose(object);
+}
+
+static void
+gaflightsql_prepared_statement_finalize(GObject *object)
+{
+ auto priv = GAFLIGHTSQL_PREPARED_STATEMENT_GET_PRIVATE(object);
+ priv->statement.~shared_ptr();
+
G_OBJECT_CLASS(gaflightsql_prepared_statement_parent_class)->finalize(object);
+}
+
+static void
+gaflightsql_prepared_statement_set_property(GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ auto priv = GAFLIGHTSQL_PREPARED_STATEMENT_GET_PRIVATE(object);
+
+ switch (prop_id) {
+ case PROP_STATEMENT:
+ priv->statement =
+ *static_cast<std::shared_ptr<arrow::flight::sql::PreparedStatement> *>(
+ g_value_get_pointer(value));
+ break;
+ case PROP_PREPARED_STATEMENT_CLIENT:
+ priv->client = GAFLIGHTSQL_CLIENT(g_value_dup_object(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gaflightsql_prepared_statement_get_property(GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ auto priv = GAFLIGHTSQL_PREPARED_STATEMENT_GET_PRIVATE(object);
+
+ switch (prop_id) {
+ case PROP_PREPARED_STATEMENT_CLIENT:
+ g_value_set_object(value, priv->client);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gaflightsql_prepared_statement_init(GAFlightSQLPreparedStatement *object)
+{
+ auto priv = GAFLIGHTSQL_PREPARED_STATEMENT_GET_PRIVATE(object);
+ new(&priv->statement) std::shared_ptr<arrow::flight::sql::PreparedStatement>;
+}
+
+static void
+gaflightsql_prepared_statement_class_init(
+ GAFlightSQLPreparedStatementClass *klass)
+{
+ auto gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->dispose = gaflightsql_prepared_statement_dispose;
+ gobject_class->finalize = gaflightsql_prepared_statement_finalize;
+ gobject_class->set_property = gaflightsql_prepared_statement_set_property;
+ gobject_class->get_property = gaflightsql_prepared_statement_get_property;
+
+ GParamSpec *spec;
+ spec = g_param_spec_pointer("statement",
+ nullptr,
+ nullptr,
+ static_cast<GParamFlags>(G_PARAM_WRITABLE |
+
G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property(gobject_class, PROP_STATEMENT, spec);
+
+ /**
+ * GAFlightSQLPreparedStatement:client:
+ *
+ * The underlying Flight SQL client.
+ *
+ * Since: 14.0.0
+ */
+ spec = g_param_spec_object("client",
+ nullptr,
+ nullptr,
+ GAFLIGHTSQL_TYPE_CLIENT,
+ static_cast<GParamFlags>(G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property(gobject_class,
+ PROP_PREPARED_STATEMENT_CLIENT,
+ spec);
+}
+
+/**
+ * gaflightsql_prepared_statement_execute:
+ * @statement: A #GAFlightSQLPreparedStatement.
+ * @options: (nullable): A #GAFlightCallOptions.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: (nullable) (transfer full): The #GAFlightInfo describing
+ * where to access the dataset on success, %NULL on error.
+ *
+ * Since: 14.0.0
+ */
+GAFlightInfo *
+gaflightsql_prepared_statement_execute(GAFlightSQLPreparedStatement *statement,
+ GAFlightCallOptions *options,
+ GError **error)
+{
+ auto flight_sql_statement =
gaflightsql_prepared_statement_get_raw(statement);
+ arrow::flight::FlightCallOptions flight_default_options;
+ auto flight_options = &flight_default_options;
+ if (options) {
+ flight_options = gaflight_call_options_get_raw(options);
+ }
+ auto result = flight_sql_statement->Execute(*flight_options);
+ if (!garrow::check(error,
+ result,
+ "[flight-sql-prepared-statement][execute]")) {
+ return nullptr;
+ }
+ auto flight_info = std::move(*result);
+ return gaflight_info_new_raw(flight_info.release());
+}
+
+/**
+ * gaflightsql_prepared_statement_execute_update:
+ * @statement: A #GAFlightSQLPreparedStatement.
+ * @options: (nullable): A #GAFlightCallOptions.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: The number of changed records.
+ *
+ * Since: 14.0.0
+ */
+gint64
+gaflightsql_prepared_statement_execute_update(
+ GAFlightSQLPreparedStatement *statement,
+ GAFlightCallOptions *options,
+ GError **error)
+{
+ auto flight_sql_statement =
gaflightsql_prepared_statement_get_raw(statement);
+ arrow::flight::FlightCallOptions flight_default_options;
+ auto flight_options = &flight_default_options;
+ if (options) {
+ flight_options = gaflight_call_options_get_raw(options);
+ }
+ auto result = flight_sql_statement->ExecuteUpdate(*flight_options);
+ if (!garrow::check(error,
+ result,
+ "[flight-sql-prepared-statement][execute-update]")) {
+ return 0;
+ }
+ return *result;
+}
+
+/**
+ * gaflightsql_prepared_statement_get_parameter_schema:
+ * @statement: A #GAFlightSQLPreparedStatement.
+ *
+ * Returns: (nullable) (transfer full): The #GArrowSchema for parameter.
+ *
+ * Since: 14.0.0
+ */
+GArrowSchema *
+gaflightsql_prepared_statement_get_parameter_schema(
+ GAFlightSQLPreparedStatement *statement)
+{
+ auto flight_sql_statement =
gaflightsql_prepared_statement_get_raw(statement);
+ auto arrow_schema = flight_sql_statement->parameter_schema();
+ return garrow_schema_new_raw(&arrow_schema);
+}
+
+/**
+ * gaflightsql_prepared_statement_get_dataset_schema:
+ * @statement: A #GAFlightSQLPreparedStatement.
+ *
+ * Returns: (nullable) (transfer full): The #GArrowSchema for dataset.
+ *
+ * Since: 14.0.0
+ */
+GArrowSchema *
+gaflightsql_prepared_statement_get_dataset_schema(
+ GAFlightSQLPreparedStatement *statement)
+{
+ auto flight_sql_statement =
gaflightsql_prepared_statement_get_raw(statement);
+ auto arrow_schema = flight_sql_statement->dataset_schema();
+ return garrow_schema_new_raw(&arrow_schema);
+}
+
+/**
+ * gaflightsql_prepared_statement_set_record_batch:
+ * @statement: A #GAFlightSQLPreparedStatement.
+ * @record_batch: A #GArrowRecordBatch that contains the parameters that
+ * will be bound.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * Since: 14.0.0
+ */
+gboolean
+gaflightsql_prepared_statement_set_record_batch(
+ GAFlightSQLPreparedStatement *statement,
+ GArrowRecordBatch *record_batch,
+ GError **error)
+{
+ auto flight_sql_statement =
gaflightsql_prepared_statement_get_raw(statement);
+ auto arrow_record_batch = garrow_record_batch_get_raw(record_batch);
+ return garrow::check(error,
+ flight_sql_statement->SetParameters(arrow_record_batch),
+ "[flight-sql-prepared-statement][set-record-batch]");
+}
+
+/**
+ * gaflightsql_prepared_statement_set_record_batch_reader:
+ * @statement: A #GAFlightSQLPreparedStatement.
+ * @reader: A #GArrowRecordBatchReader that contains the parameters that
+ * will be bound.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * Since: 14.0.0
+ */
+gboolean
+gaflightsql_prepared_statement_set_record_batch_reader(
+ GAFlightSQLPreparedStatement *statement,
+ GArrowRecordBatchReader *reader,
+ GError **error)
+{
+ auto flight_sql_statement =
gaflightsql_prepared_statement_get_raw(statement);
+ auto arrow_reader = garrow_record_batch_reader_get_raw(reader);
+ return garrow::check(error,
+ flight_sql_statement->SetParameters(arrow_reader),
+
"[flight-sql-prepared-statement][set-record-batch-reader]");
+}
+
+/**
+ * gaflightsql_prepared_statement_close:
+ * @statement: A #GAFlightSQLPreparedStatement.
+ * @options: (nullable): A #GAFlightCallOptions.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * After this, the prepared statement may not be used anymore.
+ *
+ * Since: 14.0.0
+ */
+gboolean
+gaflightsql_prepared_statement_close(GAFlightSQLPreparedStatement *statement,
+ GAFlightCallOptions *options,
+ GError **error)
+{
+ auto flight_sql_statement =
gaflightsql_prepared_statement_get_raw(statement);
+ arrow::flight::FlightCallOptions flight_default_options;
+ auto flight_options = &flight_default_options;
+ if (options) {
+ flight_options = gaflight_call_options_get_raw(options);
+ }
+ return garrow::check(error,
+ flight_sql_statement->Close(*flight_options),
+ "[flight-sql-prepared-statement][close]");
+}
+
+/**
+ * gaflightsql_prepared_statement_is_closed:
+ * @statement: A #GAFlightSQLPreparedStatement.
+ *
+ * Returns: Whether the prepared statement is closed or not.
+ *
+ * Since: 14.0.0
+ */
+gboolean
+gaflightsql_prepared_statement_is_closed(GAFlightSQLPreparedStatement
*statement)
+{
+ auto flight_sql_statement =
gaflightsql_prepared_statement_get_raw(statement);
+ return flight_sql_statement->IsClosed();
+}
+
+
struct GAFlightSQLClientPrivate {
- arrow::flight::sql::FlightSqlClient* client;
+ arrow::flight::sql::FlightSqlClient *client;
GAFlightClient *flight_client;
};
@@ -273,20 +589,68 @@ gaflightsql_client_do_get(GAFlightSQLClient *client,
return nullptr;
}
auto flight_reader = std::move(*result);
- return gaflight_stream_reader_new_raw(flight_reader.release());
+ return gaflight_stream_reader_new_raw(flight_reader.release(), TRUE);
+}
+
+/**
+ * gaflightsql_client_prepare:
+ * @client: A #GAFlightSQLClient.
+ * @query: A query to be prepared in the UTF-8 format.
+ * @options: (nullable): A #GAFlightCallOptions.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: (nullable) (transfer full): The #GAFlightSQLPreparedStatement
+ * on success, %NULL on error.
+ *
+ * Since: 14.0.0
+ */
+GAFlightSQLPreparedStatement *
+gaflightsql_client_prepare(GAFlightSQLClient *client,
+ const gchar *query,
+ GAFlightCallOptions *options,
+ GError **error)
+{
+ auto flight_sql_client = gaflightsql_client_get_raw(client);
+ arrow::flight::FlightCallOptions flight_default_options;
+ auto flight_options = &flight_default_options;
+ if (options) {
+ flight_options = gaflight_call_options_get_raw(options);
+ }
+ auto result = flight_sql_client->Prepare(*flight_options, query);
+ if (!garrow::check(error,
+ result,
+ "[flight-sql-client][prepare]")) {
+ return nullptr;
+ }
+ auto flight_sql_statement = std::move(*result);
+ return gaflightsql_prepared_statement_new_raw(&flight_sql_statement,
+ client);
}
G_END_DECLS
-arrow::flight::sql::FlightSqlClient *
-gaflightsql_client_get_raw(GAFlightSQLClient *client)
+GAFlightSQLPreparedStatement *
+gaflightsql_prepared_statement_new_raw(
+ std::shared_ptr<arrow::flight::sql::PreparedStatement> *flight_sql_statement,
+ GAFlightSQLClient *client)
{
- auto priv = GAFLIGHTSQL_CLIENT_GET_PRIVATE(client);
- return priv->client;
+ return GAFLIGHTSQL_PREPARED_STATEMENT(
+ g_object_new(GAFLIGHTSQL_TYPE_PREPARED_STATEMENT,
+ "statement", flight_sql_statement,
+ "client", client,
+ nullptr));
+}
+
+std::shared_ptr<arrow::flight::sql::PreparedStatement>
+gaflightsql_prepared_statement_get_raw(GAFlightSQLPreparedStatement *statement)
+{
+ auto priv = GAFLIGHTSQL_PREPARED_STATEMENT_GET_PRIVATE(statement);
+ return priv->statement;
}
+
GAFlightSQLClient *
gaflightsql_client_new_raw(
arrow::flight::sql::FlightSqlClient *flight_sql_client,
@@ -298,3 +662,10 @@ gaflightsql_client_new_raw(
"flight_client", client,
nullptr));
}
+
+arrow::flight::sql::FlightSqlClient *
+gaflightsql_client_get_raw(GAFlightSQLClient *client)
+{
+ auto priv = GAFLIGHTSQL_CLIENT_GET_PRIVATE(client);
+ return priv->client;
+}
diff --git a/c_glib/arrow-flight-sql-glib/client.h
b/c_glib/arrow-flight-sql-glib/client.h
index 6374fece22..f2a025fef0 100644
--- a/c_glib/arrow-flight-sql-glib/client.h
+++ b/c_glib/arrow-flight-sql-glib/client.h
@@ -24,6 +24,69 @@
G_BEGIN_DECLS
+#define GAFLIGHTSQL_TYPE_PREPARED_STATEMENT \
+ (gaflightsql_prepared_statement_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightSQLPreparedStatement,
+ gaflightsql_prepared_statement,
+ GAFLIGHTSQL,
+ PREPARED_STATEMENT,
+ GObject)
+struct _GAFlightSQLPreparedStatementClass
+{
+ GObjectClass parent_class;
+};
+
+GARROW_AVAILABLE_IN_14_0
+GAFlightInfo *
+gaflightsql_prepared_statement_execute(
+ GAFlightSQLPreparedStatement *statement,
+ GAFlightCallOptions *options,
+ GError **error);
+
+GARROW_AVAILABLE_IN_14_0
+gint64
+gaflightsql_prepared_statement_execute_update(
+ GAFlightSQLPreparedStatement *statement,
+ GAFlightCallOptions *options,
+ GError **error);
+
+GARROW_AVAILABLE_IN_14_0
+GArrowSchema *
+gaflightsql_prepared_statement_get_parameter_schema(
+ GAFlightSQLPreparedStatement *statement);
+
+GARROW_AVAILABLE_IN_14_0
+GArrowSchema *
+gaflightsql_prepared_statement_get_dataset_schema(
+ GAFlightSQLPreparedStatement *statement);
+
+GARROW_AVAILABLE_IN_14_0
+gboolean
+gaflightsql_prepared_statement_set_record_batch(
+ GAFlightSQLPreparedStatement *statement,
+ GArrowRecordBatch *record_batch,
+ GError **error);
+
+GARROW_AVAILABLE_IN_14_0
+gboolean
+gaflightsql_prepared_statement_set_record_batch_reader(
+ GAFlightSQLPreparedStatement *statement,
+ GArrowRecordBatchReader *reader,
+ GError **error);
+
+GARROW_AVAILABLE_IN_14_0
+gboolean
+gaflightsql_prepared_statement_close(
+ GAFlightSQLPreparedStatement *statement,
+ GAFlightCallOptions *options,
+ GError **error);
+
+GARROW_AVAILABLE_IN_14_0
+gboolean
+gaflightsql_prepared_statement_is_closed(
+ GAFlightSQLPreparedStatement *statement);
+
+
#define GAFLIGHTSQL_TYPE_CLIENT (gaflightsql_client_get_type())
G_DECLARE_DERIVABLE_TYPE(GAFlightSQLClient,
gaflightsql_client,
@@ -60,5 +123,12 @@ gaflightsql_client_do_get(GAFlightSQLClient *client,
GAFlightCallOptions *options,
GError **error);
+GARROW_AVAILABLE_IN_14_0
+GAFlightSQLPreparedStatement *
+gaflightsql_client_prepare(GAFlightSQLClient *client,
+ const gchar *query,
+ GAFlightCallOptions *options,
+ GError **error);
+
G_END_DECLS
diff --git a/c_glib/arrow-flight-sql-glib/client.hpp
b/c_glib/arrow-flight-sql-glib/client.hpp
index d9c04e5108..09136f8819 100644
--- a/c_glib/arrow-flight-sql-glib/client.hpp
+++ b/c_glib/arrow-flight-sql-glib/client.hpp
@@ -24,9 +24,16 @@
#include <arrow-flight-sql-glib/client.h>
-arrow::flight::sql::FlightSqlClient *
-gaflightsql_client_get_raw(GAFlightSQLClient *client);
+GAFlightSQLPreparedStatement *
+gaflightsql_prepared_statement_new_raw(
+ std::shared_ptr<arrow::flight::sql::PreparedStatement> *flight_sql_statement,
+ GAFlightSQLClient *client);
+std::shared_ptr<arrow::flight::sql::PreparedStatement>
+gaflightsql_prepared_statement_get_raw(GAFlightSQLPreparedStatement
*statement);
+
GAFlightSQLClient *
gaflightsql_client_new_raw(
arrow::flight::sql::FlightSqlClient *flight_sql_client,
GAFlightClient *client);
+arrow::flight::sql::FlightSqlClient *
+gaflightsql_client_get_raw(GAFlightSQLClient *client);
diff --git a/c_glib/arrow-flight-sql-glib/server.cpp
b/c_glib/arrow-flight-sql-glib/server.cpp
index 750dff2232..518b771732 100644
--- a/c_glib/arrow-flight-sql-glib/server.cpp
+++ b/c_glib/arrow-flight-sql-glib/server.cpp
@@ -33,6 +33,18 @@ G_BEGIN_DECLS
* @title: Server related classes
* @include: arrow-flight-sql-glib/arrow-flight-sql-glib.h
*
+ * #GAFlightSQLPreparedStatementUpdate is a class for a request
+ * that executes an update SQL prepared statement.
+ *
+ * #GAFlightSQLCreatePreparedStatementRequest is a class for a request
+ * that creates a SQL prepared statement.
+ *
+ * #GAFlightSQLCreatePreparedStatementResult is a class for a result
+ * of the request that creates a SQL prepared statement.
+ *
+ * #GAFlightSQLClosePreparedStatementRequest is a class for a request
+ * that closes a SQL prepared statement.
+ *
* #GAFlightSQLServer is a class to develop an Apache Arrow Flight SQL
* server.
*
@@ -156,6 +168,41 @@
gaflightsql_statement_update_get_query(GAFlightSQLStatementUpdate *command)
}
+G_DEFINE_TYPE(GAFlightSQLPreparedStatementUpdate,
+ gaflightsql_prepared_statement_update,
+ GAFLIGHTSQL_TYPE_COMMAND)
+
+static void
+gaflightsql_prepared_statement_update_init(
+ GAFlightSQLPreparedStatementUpdate *object)
+{
+}
+
+static void
+gaflightsql_prepared_statement_update_class_init(
+ GAFlightSQLPreparedStatementUpdateClass *klass)
+{
+}
+
+/**
+ * gaflightsql_prepared_statement_update_get_handle:
+ * @command: A #GAFlightSQLPreparedStatementUpdate.
+ *
+ * Returns: (transfer full): The server-generated opaque identifier
+ * for the statement.
+ *
+ * Since: 14.0.0
+ */
+GBytes *
+gaflightsql_prepared_statement_update_get_handle(
+ GAFlightSQLPreparedStatementUpdate *command)
+{
+ auto update = gaflightsql_prepared_statement_update_get_raw(command);
+ return g_bytes_new_static(update->prepared_statement_handle.data(),
+ update->prepared_statement_handle.size());
+}
+
+
G_DEFINE_TYPE(GAFlightSQLStatementQueryTicket,
gaflightsql_statement_query_ticket,
GAFLIGHTSQL_TYPE_COMMAND)
@@ -221,6 +268,341 @@ gaflightsql_statement_query_ticket_get_handle(
}
+struct GAFlightSQLCreatePreparedStatementRequestPrivate {
+ arrow::flight::sql::ActionCreatePreparedStatementRequest *request;
+};
+
+enum {
+ PROP_REQUEST = 1,
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GAFlightSQLCreatePreparedStatementRequest,
+ gaflightsql_create_prepared_statement_request,
+ G_TYPE_OBJECT)
+
+#define GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_REQUEST_GET_PRIVATE(object) \
+ static_cast<GAFlightSQLCreatePreparedStatementRequestPrivate *>( \
+ gaflightsql_create_prepared_statement_request_get_instance_private( \
+ GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_REQUEST(object)))
+
+static void
+gaflightsql_create_prepared_statement_request_set_property(GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ auto priv =
GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_REQUEST_GET_PRIVATE(object);
+
+ switch (prop_id) {
+ case PROP_REQUEST:
+ priv->request =
+ static_cast<arrow::flight::sql::ActionCreatePreparedStatementRequest *>(
+ g_value_get_pointer(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gaflightsql_create_prepared_statement_request_init(
+ GAFlightSQLCreatePreparedStatementRequest *object)
+{
+}
+
+static void
+gaflightsql_create_prepared_statement_request_class_init(
+ GAFlightSQLCreatePreparedStatementRequestClass *klass)
+{
+ auto gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->set_property =
+ gaflightsql_create_prepared_statement_request_set_property;
+
+ GParamSpec *spec;
+ spec = g_param_spec_pointer("request",
+ nullptr,
+ nullptr,
+ static_cast<GParamFlags>(G_PARAM_WRITABLE |
+
G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property(gobject_class, PROP_REQUEST, spec);
+}
+
+/**
+ * gaflightsql_create_prepared_statement_request_get_query:
+ * @request: A #GAFlightSQLCreatePreparedStatementRequest.
+ *
+ * Returns: The SQL query to be prepared.
+ *
+ * Since: 14.0.0
+ */
+const gchar *
+gaflightsql_create_prepared_statement_request_get_query(
+ GAFlightSQLCreatePreparedStatementRequest *request)
+{
+ auto priv =
GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_REQUEST_GET_PRIVATE(request);
+ return priv->request->query.c_str();
+}
+
+/**
+ * gaflightsql_create_prepared_statement_request_get_transaction_id:
+ * @request: A #GAFlightSQLCreatePreparedStatementRequest.
+ *
+ * Returns: The transaction ID, if specified (else a blank string).
+ *
+ * Since: 14.0.0
+ */
+const gchar *
+gaflightsql_create_prepared_statement_request_get_transaction_id(
+ GAFlightSQLCreatePreparedStatementRequest *request)
+{
+ auto priv =
GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_REQUEST_GET_PRIVATE(request);
+ return priv->request->transaction_id.c_str();
+}
+
+
+struct GAFlightSQLCreatePreparedStatementResultPrivate {
+ arrow::flight::sql::ActionCreatePreparedStatementResult result;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GAFlightSQLCreatePreparedStatementResult,
+ gaflightsql_create_prepared_statement_result,
+ G_TYPE_OBJECT)
+
+#define GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(object) \
+ static_cast<GAFlightSQLCreatePreparedStatementResultPrivate *>( \
+ gaflightsql_create_prepared_statement_result_get_instance_private( \
+ GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT(object)))
+
+static void
+gaflightsql_create_prepared_statement_result_finalize(GObject *object)
+{
+ auto priv = GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(object);
+ priv->result.~ActionCreatePreparedStatementResult();
+
G_OBJECT_CLASS(gaflightsql_create_prepared_statement_result_parent_class)->finalize(object);
+}
+
+static void
+gaflightsql_create_prepared_statement_result_init(
+ GAFlightSQLCreatePreparedStatementResult *object)
+{
+ auto priv = GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(object);
+ new(&(priv->result))
arrow::flight::sql::ActionCreatePreparedStatementResult();
+}
+
+static void
+gaflightsql_create_prepared_statement_result_class_init(
+ GAFlightSQLCreatePreparedStatementResultClass *klass)
+{
+ auto gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->finalize =
+ gaflightsql_create_prepared_statement_result_finalize;
+}
+
+/**
+ * gaflightsql_create_prepared_statement_result_new:
+ *
+ * Returns:: The newly created #GAFlightSQLCreatePreparedStatementResult.
+ *
+ * Since: 14.0.0
+ */
+GAFlightSQLCreatePreparedStatementResult *
+gaflightsql_create_prepared_statement_result_new(void)
+{
+ return GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT(
+ g_object_new(GAFLIGHTSQL_TYPE_CREATE_PREPARED_STATEMENT_RESULT,
+ nullptr));
+}
+
+/**
+ * gaflightsql_create_prepared_statement_result_set_dataset_schema:
+ * @result: A #GAFlightSQLCreatePreparedStatementResult.
+ * @schema: A #GArrowSchema of dataset.
+ *
+ * Since: 14.0.0
+ */
+void
+gaflightsql_create_prepared_statement_result_set_dataset_schema(
+ GAFlightSQLCreatePreparedStatementResult *result,
+ GArrowSchema *schema)
+{
+ auto priv =
+ GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(result);
+ priv->result.dataset_schema = garrow_schema_get_raw(schema);
+}
+
+/**
+ * gaflightsql_create_prepared_statement_result_get_dataset_schema:
+ * @result: A #GAFlightSQLCreatePreparedStatementResult.
+ *
+ * Returns: (nullable) (transfer full): The current dataset schema.
+ *
+ * Since: 14.0.0
+ */
+GArrowSchema *
+gaflightsql_create_prepared_statement_result_get_dataset_schema(
+ GAFlightSQLCreatePreparedStatementResult *result)
+{
+ auto priv =
+ GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(result);
+ if (!priv->result.dataset_schema) {
+ return nullptr;
+ }
+ return garrow_schema_new_raw(&(priv->result.dataset_schema));
+}
+
+/**
+ * gaflightsql_create_prepared_statement_result_set_parameter_schema:
+ * @result: A #GAFlightSQLCreatePreparedStatementResult.
+ * @schema: A #GArrowSchema of parameter.
+ *
+ * Since: 14.0.0
+ */
+void
+gaflightsql_create_prepared_statement_result_set_parameter_schema(
+ GAFlightSQLCreatePreparedStatementResult *result,
+ GArrowSchema *schema)
+{
+ auto priv =
+ GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(result);
+ priv->result.parameter_schema = garrow_schema_get_raw(schema);
+}
+
+/**
+ * gaflightsql_create_prepared_statement_result_get_parameter_schema:
+ * @result: A #GAFlightSQLCreatePreparedStatementResult.
+ *
+ * Returns: (nullable) (transfer full): The current parameter schema.
+ *
+ * Since: 14.0.0
+ */
+GArrowSchema *
+gaflightsql_create_prepared_statement_result_get_parameter_schema(
+ GAFlightSQLCreatePreparedStatementResult *result)
+{
+ auto priv =
+ GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(result);
+ if (!priv->result.parameter_schema) {
+ return nullptr;
+ }
+ return garrow_schema_new_raw(&(priv->result.parameter_schema));
+}
+
+/**
+ * gaflightsql_create_prepared_statement_result_set_handle:
+ * @result: A #GAFlightSQLCreatePreparedStatementResult.
+ * @handle: A #GBytes for server-generated opaque identifier.
+ *
+ * Since: 14.0.0
+ */
+void
+gaflightsql_create_prepared_statement_result_set_handle(
+ GAFlightSQLCreatePreparedStatementResult *result,
+ GBytes *handle)
+{
+ auto priv =
+ GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(result);
+ size_t handle_size;
+ auto handle_data = g_bytes_get_data(handle, &handle_size);
+ priv->result.prepared_statement_handle =
+ std::string(static_cast<const char *>(handle_data), handle_size);
+}
+
+/**
+ * gaflightsql_create_prepared_statement_result_get_handle:
+ * @result: A #GAFlightSQLCreatePreparedStatementResult.
+ *
+ * Returns: (transfer full): The current server-generated opaque
+ * identifier.
+ *
+ * Since: 14.0.0
+ */
+GBytes *
+gaflightsql_create_prepared_statement_result_get_handle(
+ GAFlightSQLCreatePreparedStatementResult *result)
+{
+ auto priv =
+ GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(result);
+ return g_bytes_new_static(priv->result.prepared_statement_handle.data(),
+ priv->result.prepared_statement_handle.length());
+}
+
+
+struct GAFlightSQLClosePreparedStatementRequestPrivate {
+ arrow::flight::sql::ActionClosePreparedStatementRequest *request;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GAFlightSQLClosePreparedStatementRequest,
+ gaflightsql_close_prepared_statement_request,
+ G_TYPE_OBJECT)
+
+#define GAFLIGHTSQL_CLOSE_PREPARED_STATEMENT_REQUEST_GET_PRIVATE(object) \
+ static_cast<GAFlightSQLClosePreparedStatementRequestPrivate *>( \
+ gaflightsql_close_prepared_statement_request_get_instance_private( \
+ GAFLIGHTSQL_CLOSE_PREPARED_STATEMENT_REQUEST(object)))
+
+static void
+gaflightsql_close_prepared_statement_request_set_property(GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ auto priv = GAFLIGHTSQL_CLOSE_PREPARED_STATEMENT_REQUEST_GET_PRIVATE(object);
+
+ switch (prop_id) {
+ case PROP_REQUEST:
+ priv->request =
+ static_cast<arrow::flight::sql::ActionClosePreparedStatementRequest *>(
+ g_value_get_pointer(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gaflightsql_close_prepared_statement_request_init(
+ GAFlightSQLClosePreparedStatementRequest *object)
+{
+}
+
+static void
+gaflightsql_close_prepared_statement_request_class_init(
+ GAFlightSQLClosePreparedStatementRequestClass *klass)
+{
+ auto gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->set_property =
+ gaflightsql_close_prepared_statement_request_set_property;
+
+ GParamSpec *spec;
+ spec = g_param_spec_pointer("request",
+ nullptr,
+ nullptr,
+ static_cast<GParamFlags>(G_PARAM_WRITABLE |
+
G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property(gobject_class, PROP_REQUEST, spec);
+}
+
+/**
+ * gaflightsql_close_prepared_statement_request_get_handle:
+ * @request: A #GAFlightSQLClosePreparedStatementRequest.
+ *
+ * Returns: (transfer full): The server-generated opaque identifier
+ * for the statement.
+ *
+ * Since: 14.0.0
+ */
+GBytes *
+gaflightsql_close_prepared_statement_request_get_handle(
+ GAFlightSQLClosePreparedStatementRequest *request)
+{
+ auto priv =
GAFLIGHTSQL_CLOSE_PREPARED_STATEMENT_REQUEST_GET_PRIVATE(request);
+ return g_bytes_new_static(priv->request->prepared_statement_handle.data(),
+ priv->request->prepared_statement_handle.length());
+}
+
+
G_END_DECLS
namespace gaflightsql {
class Server : public arrow::flight::sql::FlightSqlServerBase {
@@ -283,7 +665,7 @@ namespace gaflightsql {
arrow::Result<int64_t>
DoPutCommandStatementUpdate(
const arrow::flight::ServerCallContext &context,
- const arrow::flight::sql::StatementUpdate& command) override {
+ const arrow::flight::sql::StatementUpdate &command) override {
auto gacontext = gaflight_server_call_context_new_raw(&context);
auto gacommand = gaflightsql_statement_update_new_raw(&command);
GError *gerror = nullptr;
@@ -303,6 +685,83 @@ namespace gaflightsql {
return n_changed_records;
}
+ arrow::Result<int64_t>
+ DoPutPreparedStatementUpdate(
+ const arrow::flight::ServerCallContext &context,
+ const arrow::flight::sql::PreparedStatementUpdate &command,
+ arrow::flight::FlightMessageReader *reader) override {
+ auto gacontext = gaflight_server_call_context_new_raw(&context);
+ auto gacommand = gaflightsql_prepared_statement_update_new_raw(&command);
+ auto gareader = gaflight_message_reader_new_raw(reader, FALSE);
+ GError *gerror = nullptr;
+ auto n_changed_records =
+ gaflightsql_server_do_put_prepared_statement_update(gaserver_,
+ gacontext,
+ gacommand,
+ gareader,
+ &gerror);
+ g_object_unref(gareader);
+ g_object_unref(gacommand);
+ g_object_unref(gacontext);
+ if (gerror) {
+ return garrow_error_to_status(
+ gerror,
+ arrow::StatusCode::UnknownError,
+ "[flight-sql-server][do-put-prepared-statement-update]");
+ }
+ return n_changed_records;
+ }
+
+ arrow::Result<arrow::flight::sql::ActionCreatePreparedStatementResult>
+ CreatePreparedStatement(
+ const arrow::flight::ServerCallContext &context,
+ const arrow::flight::sql::ActionCreatePreparedStatementRequest &request)
override {
+ auto gacontext = gaflight_server_call_context_new_raw(&context);
+ auto garequest =
gaflightsql_create_prepared_statement_request_new_raw(&request);
+ GError *gerror = nullptr;
+ auto garesult =
+ gaflightsql_server_create_prepared_statement(gaserver_,
+ gacontext,
+ garequest,
+ &gerror);
+ g_object_unref(garequest);
+ g_object_unref(gacontext);
+ if (gerror) {
+ return garrow_error_to_status(
+ gerror,
+ arrow::StatusCode::UnknownError,
+ "[flight-sql-server][create-prepared-statement]");
+ }
+ auto garesult_priv =
+ GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_RESULT_GET_PRIVATE(garesult);
+ auto flightsql_result = garesult_priv->result;
+ g_object_unref(garesult);
+ return flightsql_result;
+ }
+
+ arrow::Status
+ ClosePreparedStatement(
+ const arrow::flight::ServerCallContext &context,
+ const arrow::flight::sql::ActionClosePreparedStatementRequest &request)
override {
+ auto gacontext = gaflight_server_call_context_new_raw(&context);
+ auto garequest =
gaflightsql_close_prepared_statement_request_new_raw(&request);
+ GError *gerror = nullptr;
+ gaflightsql_server_close_prepared_statement(gaserver_,
+ gacontext,
+ garequest,
+ &gerror);
+ g_object_unref(garequest);
+ g_object_unref(gacontext);
+ if (gerror) {
+ return garrow_error_to_status(
+ gerror,
+ arrow::StatusCode::UnknownError,
+ "[flight-sql-server][close-prepared-statement]");
+ } else {
+ return arrow::Status::OK();
+ }
+ }
+
private:
GAFlightSQLServer *gaserver_;
};
@@ -351,7 +810,6 @@ gaflightsql_server_finalize(GObject *object)
{
auto priv = GAFLIGHTSQL_SERVER_GET_PRIVATE(object);
priv->server.~Server();
-
G_OBJECT_CLASS(gaflightsql_server_parent_class)->finalize(object);
}
@@ -463,6 +921,97 @@ gaflightsql_server_do_put_command_statement_update(
return klass->do_put_command_statement_update(server, context, command,
error);
}
+/**
+ * gaflightsql_server_do_put_prepared_statement_update:
+ * @server: A #GAFlightServer.
+ * @context: A #GAFlightServerCallContext.
+ * @command: A #GAFlightSQLPreparedStatementUpdate.
+ * @reader: A #GAFlightMessageReader that reads uploaded record batches.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: The number of changed records.
+ *
+ * Since: 14.0.0
+ */
+gint64
+gaflightsql_server_do_put_prepared_statement_update(
+ GAFlightSQLServer *server,
+ GAFlightServerCallContext *context,
+ GAFlightSQLPreparedStatementUpdate *command,
+ GAFlightMessageReader *reader,
+ GError **error)
+{
+ auto klass = GAFLIGHTSQL_SERVER_GET_CLASS(server);
+ if (!(klass && klass->do_put_prepared_statement_update)) {
+ g_set_error(error,
+ GARROW_ERROR,
+ GARROW_ERROR_NOT_IMPLEMENTED,
+ "not implemented");
+ return 0;
+ }
+ return klass->do_put_prepared_statement_update(
+ server, context, command, reader, error);
+}
+
+/**
+ * gaflightsql_server_create_prepared_statement:
+ * @server: A #GAFlightServer.
+ * @context: A #GAFlightServerCallContext.
+ * @request: A #GAFlightSQLCreatePreparedStatementRequest.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Returns: (nullable) (transfer full): A
+ * #GAFlightSQLCreatePreparedStatementResult containing the dataset
+ * and parameter schemas and a handle for created statement on
+ * success, %NULL on error.
+ *
+ * Since: 14.0.0
+ */
+GAFlightSQLCreatePreparedStatementResult *
+gaflightsql_server_create_prepared_statement(
+ GAFlightSQLServer *server,
+ GAFlightServerCallContext *context,
+ GAFlightSQLCreatePreparedStatementRequest *request,
+ GError **error)
+{
+ auto klass = GAFLIGHTSQL_SERVER_GET_CLASS(server);
+ if (!(klass && klass->create_prepared_statement)) {
+ g_set_error(error,
+ GARROW_ERROR,
+ GARROW_ERROR_NOT_IMPLEMENTED,
+ "not implemented");
+ return nullptr;
+ }
+ return klass->create_prepared_statement(server, context, request, error);
+}
+
+/**
+ * gaflightsql_server_close_prepared_statement:
+ * @server: A #GAFlightServer.
+ * @context: A #GAFlightServerCallContext.
+ * @request: A #GAFlightSQLClosePreparedStatementRequest.
+ * @error: (nullable): Return location for a #GError or %NULL.
+ *
+ * Since: 14.0.0
+ */
+void
+gaflightsql_server_close_prepared_statement(
+ GAFlightSQLServer *server,
+ GAFlightServerCallContext *context,
+ GAFlightSQLClosePreparedStatementRequest *request,
+ GError **error)
+{
+ auto klass = GAFLIGHTSQL_SERVER_GET_CLASS(server);
+ if (!(klass && klass->close_prepared_statement)) {
+ g_set_error(error,
+ GARROW_ERROR,
+ GARROW_ERROR_NOT_IMPLEMENTED,
+ "not implemented");
+ return;
+ }
+ return klass->close_prepared_statement(server, context, request, error);
+}
+
G_END_DECLS
@@ -503,6 +1052,26 @@
gaflightsql_statement_update_get_raw(GAFlightSQLStatementUpdate *command)
}
+GAFlightSQLPreparedStatementUpdate *
+gaflightsql_prepared_statement_update_new_raw(
+ const arrow::flight::sql::PreparedStatementUpdate *flight_command)
+{
+ return GAFLIGHTSQL_PREPARED_STATEMENT_UPDATE(
+ g_object_new(GAFLIGHTSQL_TYPE_PREPARED_STATEMENT_UPDATE,
+ "command", flight_command,
+ nullptr));
+}
+
+const arrow::flight::sql::PreparedStatementUpdate *
+gaflightsql_prepared_statement_update_get_raw(
+ GAFlightSQLPreparedStatementUpdate *command)
+{
+ auto priv = GAFLIGHTSQL_COMMAND_GET_PRIVATE(command);
+ return static_cast<const arrow::flight::sql::PreparedStatementUpdate *>(
+ priv->command);
+}
+
+
GAFlightSQLStatementQueryTicket *
gaflightsql_statement_query_ticket_new_raw(
const arrow::flight::sql::StatementQueryTicket *flight_command)
@@ -521,3 +1090,41 @@ gaflightsql_statement_query_ticket_get_raw(
return static_cast<const arrow::flight::sql::StatementQueryTicket *>(
priv->command);
}
+
+
+GAFlightSQLCreatePreparedStatementRequest *
+gaflightsql_create_prepared_statement_request_new_raw(
+ const arrow::flight::sql::ActionCreatePreparedStatementRequest
*flight_request)
+{
+ return GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_REQUEST(
+ g_object_new(GAFLIGHTSQL_TYPE_CREATE_PREPARED_STATEMENT_REQUEST,
+ "request", flight_request,
+ nullptr));
+}
+
+const arrow::flight::sql::ActionCreatePreparedStatementRequest *
+gaflightsql_create_prepared_statement_request_get_raw(
+ GAFlightSQLCreatePreparedStatementRequest *request)
+{
+ auto priv =
GAFLIGHTSQL_CREATE_PREPARED_STATEMENT_REQUEST_GET_PRIVATE(request);
+ return priv->request;
+}
+
+
+GAFlightSQLClosePreparedStatementRequest *
+gaflightsql_close_prepared_statement_request_new_raw(
+ const arrow::flight::sql::ActionClosePreparedStatementRequest
*flight_request)
+{
+ return GAFLIGHTSQL_CLOSE_PREPARED_STATEMENT_REQUEST(
+ g_object_new(GAFLIGHTSQL_TYPE_CLOSE_PREPARED_STATEMENT_REQUEST,
+ "request", flight_request,
+ nullptr));
+}
+
+const arrow::flight::sql::ActionClosePreparedStatementRequest *
+gaflightsql_close_prepared_statement_request_get_raw(
+ GAFlightSQLClosePreparedStatementRequest *request)
+{
+ auto priv =
GAFLIGHTSQL_CLOSE_PREPARED_STATEMENT_REQUEST_GET_PRIVATE(request);
+ return priv->request;
+}
diff --git a/c_glib/arrow-flight-sql-glib/server.h
b/c_glib/arrow-flight-sql-glib/server.h
index 60e5b300d4..106b6e40db 100644
--- a/c_glib/arrow-flight-sql-glib/server.h
+++ b/c_glib/arrow-flight-sql-glib/server.h
@@ -68,6 +68,24 @@ const gchar *
gaflightsql_statement_update_get_query(GAFlightSQLStatementUpdate *command);
+#define GAFLIGHTSQL_TYPE_PREPARED_STATEMENT_UPDATE \
+ (gaflightsql_prepared_statement_update_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightSQLPreparedStatementUpdate,
+ gaflightsql_prepared_statement_update,
+ GAFLIGHTSQL,
+ PREPARED_STATEMENT_UPDATE,
+ GAFlightSQLCommand)
+struct _GAFlightSQLPreparedStatementUpdateClass
+{
+ GAFlightSQLCommandClass parent_class;
+};
+
+GARROW_AVAILABLE_IN_14_0
+GBytes *
+gaflightsql_prepared_statement_update_get_handle(
+ GAFlightSQLPreparedStatementUpdate *command);
+
+
#define GAFLIGHTSQL_TYPE_STATEMENT_QUERY_TICKET \
(gaflightsql_statement_query_ticket_get_type())
G_DECLARE_DERIVABLE_TYPE(GAFlightSQLStatementQueryTicket,
@@ -90,6 +108,91 @@ gaflightsql_statement_query_ticket_get_handle(
GAFlightSQLStatementQueryTicket *command);
+#define GAFLIGHTSQL_TYPE_CREATE_PREPARED_STATEMENT_REQUEST \
+ (gaflightsql_create_prepared_statement_request_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightSQLCreatePreparedStatementRequest,
+ gaflightsql_create_prepared_statement_request,
+ GAFLIGHTSQL,
+ CREATE_PREPARED_STATEMENT_REQUEST,
+ GObject)
+struct _GAFlightSQLCreatePreparedStatementRequestClass
+{
+ GObjectClass parent_class;
+};
+
+GARROW_AVAILABLE_IN_14_0
+const gchar *
+gaflightsql_create_prepared_statement_request_get_query(
+ GAFlightSQLCreatePreparedStatementRequest *request);
+
+GARROW_AVAILABLE_IN_14_0
+const gchar *
+gaflightsql_create_prepared_statement_request_get_transaction_id(
+ GAFlightSQLCreatePreparedStatementRequest *request);
+
+
+#define GAFLIGHTSQL_TYPE_CREATE_PREPARED_STATEMENT_RESULT \
+ (gaflightsql_create_prepared_statement_result_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightSQLCreatePreparedStatementResult,
+ gaflightsql_create_prepared_statement_result,
+ GAFLIGHTSQL,
+ CREATE_PREPARED_STATEMENT_RESULT,
+ GObject)
+struct _GAFlightSQLCreatePreparedStatementResultClass
+{
+ GObjectClass parent_class;
+};
+
+GARROW_AVAILABLE_IN_14_0
+GAFlightSQLCreatePreparedStatementResult *
+gaflightsql_create_prepared_statement_result_new(void);
+GARROW_AVAILABLE_IN_14_0
+void
+gaflightsql_create_prepared_statement_result_set_dataset_schema(
+ GAFlightSQLCreatePreparedStatementResult *result,
+ GArrowSchema *schema);
+GARROW_AVAILABLE_IN_14_0
+GArrowSchema *
+gaflightsql_create_prepared_statement_result_get_dataset_schema(
+ GAFlightSQLCreatePreparedStatementResult *result);
+GARROW_AVAILABLE_IN_14_0
+void
+gaflightsql_create_prepared_statement_result_set_parameter_schema(
+ GAFlightSQLCreatePreparedStatementResult *result,
+ GArrowSchema *schema);
+GARROW_AVAILABLE_IN_14_0
+GArrowSchema *
+gaflightsql_create_prepared_statement_result_get_parameter_schema(
+ GAFlightSQLCreatePreparedStatementResult *result);
+GARROW_AVAILABLE_IN_14_0
+void
+gaflightsql_create_prepared_statement_result_set_handle(
+ GAFlightSQLCreatePreparedStatementResult *result,
+ GBytes *handle);
+GARROW_AVAILABLE_IN_14_0
+GBytes *
+gaflightsql_create_prepared_statement_result_get_handle(
+ GAFlightSQLCreatePreparedStatementResult *result);
+
+
+#define GAFLIGHTSQL_TYPE_CLOSE_PREPARED_STATEMENT_REQUEST \
+ (gaflightsql_close_prepared_statement_request_get_type())
+G_DECLARE_DERIVABLE_TYPE(GAFlightSQLClosePreparedStatementRequest,
+ gaflightsql_close_prepared_statement_request,
+ GAFLIGHTSQL,
+ CLOSE_PREPARED_STATEMENT_REQUEST,
+ GObject)
+struct _GAFlightSQLClosePreparedStatementRequestClass
+{
+ GObjectClass parent_class;
+};
+
+GARROW_AVAILABLE_IN_14_0
+GBytes *
+gaflightsql_close_prepared_statement_request_get_handle(
+ GAFlightSQLClosePreparedStatementRequest *request);
+
+
#define GAFLIGHTSQL_TYPE_SERVER (gaflightsql_server_get_type())
G_DECLARE_DERIVABLE_TYPE(GAFlightSQLServer,
gaflightsql_server,
@@ -105,6 +208,13 @@ G_DECLARE_DERIVABLE_TYPE(GAFlightSQLServer,
* that gets a #GAFlightDataStream containing the query results.
* @do_put_command_statement_update: A virtual function to implement
* `DoPutCommandStatementUpdate` API that executes an update SQL statement.
+ * @do_put_prepared_statement_update: A virtual function to implement
+ * `DoPutPreparedStatementUpdate` API that executes an update prepared
+ * statement.
+ * @create_prepared_statement: A virtual function to implement
+ * `CreatePreparedStatement` API that creates a prepared statement
+ * @close_prepared_statement: A virtual function to implement
+ * `ClosePreparedStatement` API that closes a prepared statement.
*
* Since: 9.0.0
*/
@@ -128,6 +238,22 @@ struct _GAFlightSQLServerClass
GAFlightServerCallContext *context,
GAFlightSQLStatementUpdate *command,
GError **error);
+ gint64 (*do_put_prepared_statement_update)(
+ GAFlightSQLServer *server,
+ GAFlightServerCallContext *context,
+ GAFlightSQLPreparedStatementUpdate *command,
+ GAFlightMessageReader *reader,
+ GError **error);
+ GAFlightSQLCreatePreparedStatementResult *(*create_prepared_statement)(
+ GAFlightSQLServer *server,
+ GAFlightServerCallContext *context,
+ GAFlightSQLCreatePreparedStatementRequest *request,
+ GError **error);
+ void (*close_prepared_statement)(
+ GAFlightSQLServer *server,
+ GAFlightServerCallContext *context,
+ GAFlightSQLClosePreparedStatementRequest *request,
+ GError **error);
};
GARROW_AVAILABLE_IN_9_0
@@ -152,5 +278,30 @@ gaflightsql_server_do_put_command_statement_update(
GAFlightServerCallContext *context,
GAFlightSQLStatementUpdate *command,
GError **error);
+/* We can restore this after we bump version to 14.0.0-SNAPSHOT. */
+/* GARROW_AVAILABLE_IN_14_0 */
+gint64
+gaflightsql_server_do_put_prepared_statement_update(
+ GAFlightSQLServer *server,
+ GAFlightServerCallContext *context,
+ GAFlightSQLPreparedStatementUpdate *command,
+ GAFlightMessageReader *reader,
+ GError **error);
+/* We can restore this after we bump version to 14.0.0-SNAPSHOT. */
+/* GARROW_AVAILABLE_IN_14_0 */
+GAFlightSQLCreatePreparedStatementResult *
+gaflightsql_server_create_prepared_statement(
+ GAFlightSQLServer *server,
+ GAFlightServerCallContext *context,
+ GAFlightSQLCreatePreparedStatementRequest *request,
+ GError **error);
+/* We can restore this after we bump version to 14.0.0-SNAPSHOT. */
+/* GARROW_AVAILABLE_IN_14_0 */
+void
+gaflightsql_server_close_prepared_statement(
+ GAFlightSQLServer *server,
+ GAFlightServerCallContext *context,
+ GAFlightSQLClosePreparedStatementRequest *request,
+ GError **error);
G_END_DECLS
diff --git a/c_glib/arrow-flight-sql-glib/server.hpp
b/c_glib/arrow-flight-sql-glib/server.hpp
index 9159a66489..bdecf054a4 100644
--- a/c_glib/arrow-flight-sql-glib/server.hpp
+++ b/c_glib/arrow-flight-sql-glib/server.hpp
@@ -38,9 +38,30 @@ const arrow::flight::sql::StatementUpdate *
gaflightsql_statement_update_get_raw(
GAFlightSQLStatementUpdate *command);
+GAFlightSQLPreparedStatementUpdate *
+gaflightsql_prepared_statement_update_new_raw(
+ const arrow::flight::sql::PreparedStatementUpdate *flight_command);
+const arrow::flight::sql::PreparedStatementUpdate *
+gaflightsql_prepared_statement_update_get_raw(
+ GAFlightSQLPreparedStatementUpdate *command);
+
GAFlightSQLStatementQueryTicket *
gaflightsql_statement_query_ticket_new_raw(
const arrow::flight::sql::StatementQueryTicket *flight_command);
const arrow::flight::sql::StatementQueryTicket *
gaflightsql_statement_query_ticket_get_raw(
GAFlightSQLStatementQueryTicket *command);
+
+GAFlightSQLCreatePreparedStatementRequest *
+gaflightsql_create_prepared_statement_request_new_raw(
+ const arrow::flight::sql::ActionCreatePreparedStatementRequest
*flight_request);
+const arrow::flight::sql::ActionCreatePreparedStatementRequest *
+gaflightsql_create_prepared_statement_request_get_raw(
+ GAFlightSQLCreatePreparedStatementRequest *request);
+
+GAFlightSQLClosePreparedStatementRequest *
+gaflightsql_close_prepared_statement_request_new_raw(
+ const arrow::flight::sql::ActionClosePreparedStatementRequest
*flight_request);
+const arrow::flight::sql::ActionClosePreparedStatementRequest *
+gaflightsql_close_prepared_statement_request_get_raw(
+ GAFlightSQLClosePreparedStatementRequest *request);
diff --git a/c_glib/arrow-glib/version.h.in b/c_glib/arrow-glib/version.h.in
index 1d43271a8b..60c0293619 100644
--- a/c_glib/arrow-glib/version.h.in
+++ b/c_glib/arrow-glib/version.h.in
@@ -110,6 +110,15 @@
# define GARROW_UNAVAILABLE(major, minor) G_UNAVAILABLE(major, minor)
#endif
+/**
+ * GARROW_VERSION_14_0:
+ *
+ * You can use this macro value for compile time API version check.
+ *
+ * Since: 14.0.0
+ */
+#define GARROW_VERSION_14_0 G_ENCODE_VERSION(14, 0)
+
/**
* GARROW_VERSION_13_0:
*
@@ -337,6 +346,20 @@
#define GARROW_AVAILABLE_IN_ALL
+#if GARROW_VERSION_MIN_REQUIRED >= GARROW_VERSION_14_0
+# define GARROW_DEPRECATED_IN_14_0 GARROW_DEPRECATED
+# define GARROW_DEPRECATED_IN_14_0_FOR(function)
GARROW_DEPRECATED_FOR(function)
+#else
+# define GARROW_DEPRECATED_IN_14_0
+# define GARROW_DEPRECATED_IN_14_0_FOR(function)
+#endif
+
+#if GARROW_VERSION_MAX_ALLOWED < GARROW_VERSION_14_0
+# define GARROW_AVAILABLE_IN_14_0 GARROW_UNAVAILABLE(14, 0)
+#else
+# define GARROW_AVAILABLE_IN_14_0
+#endif
+
#if GARROW_VERSION_MIN_REQUIRED >= GARROW_VERSION_13_0
# define GARROW_DEPRECATED_IN_13_0 GARROW_DEPRECATED
# define GARROW_DEPRECATED_IN_13_0_FOR(function)
GARROW_DEPRECATED_FOR(function)
diff --git a/c_glib/doc/arrow-flight-sql-glib/arrow-flight-sql-glib-docs.xml
b/c_glib/doc/arrow-flight-sql-glib/arrow-flight-sql-glib-docs.xml
index be8c003ea2..f87d657461 100644
--- a/c_glib/doc/arrow-flight-sql-glib/arrow-flight-sql-glib-docs.xml
+++ b/c_glib/doc/arrow-flight-sql-glib/arrow-flight-sql-glib-docs.xml
@@ -54,6 +54,14 @@
<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-13-0-0" role="13.0.0">
+ <title>Index of new symbols in 13.0.0</title>
+ <xi:include href="xml/api-index-13.0.0.xml"><xi:fallback /></xi:include>
+ </index>
<index id="api-index-9-0-0" role="9.0.0">
<title>Index of new symbols in 9.0.0</title>
<xi:include href="xml/api-index-9.0.0.xml"><xi:fallback /></xi:include>
diff --git a/c_glib/test/flight-sql/test-client.rb
b/c_glib/test/flight-sql/test-client.rb
index adfb47fe0b..ab80fc2cb8 100644
--- a/c_glib/test/flight-sql/test-client.rb
+++ b/c_glib/test/flight-sql/test-client.rb
@@ -16,6 +16,7 @@
# under the License.
class TestFlightSQLClient < Test::Unit::TestCase
+ include Helper::Buildable
include Helper::Omittable
def setup
@@ -67,4 +68,32 @@ class TestFlightSQLClient < Test::Unit::TestCase
end
end
end
+
+ sub_test_case("#prepare") do
+ def test_success
+ insert_sql = "INSERT INTO page_view_table VALUES (?, true)"
+ statement = @sql_client.prepare(insert_sql)
+ begin
+ assert_equal([
+ build_schema(count: :uint64, private: :boolean),
+ build_schema(count: :uint64),
+ ],
+ [
+ statement.dataset_schema,
+ statement.parameter_schema,
+ ])
+ parameters = build_record_batch(count: build_uint64_array([1, 2, 3]))
+ statement.set_record_batch(parameters)
+ assert_equal(3, statement.execute_update)
+ ensure
+ statement.close
+ end
+ end
+
+ def test_error
+ assert_raise(Arrow::Error::Invalid) do
+ @sql_client.prepare("INSERT")
+ end
+ end
+ end
end
diff --git a/c_glib/test/flight-sql/test-create-prepared-statement-result.rb
b/c_glib/test/flight-sql/test-create-prepared-statement-result.rb
new file mode 100644
index 0000000000..bcaeb1dddc
--- /dev/null
+++ b/c_glib/test/flight-sql/test-create-prepared-statement-result.rb
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+class TestFlightSQLCreatePreparedStatementResult < Test::Unit::TestCase
+ include Helper::Buildable
+ include Helper::Omittable
+
+ def setup
+ omit("Arrow Flight SQL is required") unless defined?(ArrowFlightSQL)
+ @result = ArrowFlightSQL::CreatePreparedStatementResult.new
+ end
+
+ def test_dataset_schema
+ assert_nil(@result.dataset_schema)
+ schema = build_schema(text: :string, number: :int32)
+ @result.dataset_schema = schema
+ assert_equal(schema, @result.dataset_schema)
+ end
+
+ def test_parameter_schema
+ assert_nil(@result.parameter_schema)
+ schema = build_schema(text: :string, number: :int32)
+ @result.parameter_schema = schema
+ assert_equal(schema, @result.parameter_schema)
+ end
+
+ def test_handle
+ assert_equal("", @result.handle.to_s)
+ @result.handle = "valid-handle"
+ assert_equal("valid-handle".to_s,
+ @result.handle.to_s)
+ end
+end
diff --git a/c_glib/test/helper/buildable.rb b/c_glib/test/helper/buildable.rb
index 29d7b6ba03..b0156f9c8e 100644
--- a/c_glib/test/helper/buildable.rb
+++ b/c_glib/test/helper/buildable.rb
@@ -19,6 +19,16 @@ module Helper
module Buildable
def build_schema(fields)
fields = fields.collect do |name, data_type|
+ if data_type.is_a?(Symbol)
+ data_type_class_name =
+ data_type.
+ to_s.
+ split("_").
+ collect(&:capitalize).
+ join.
+ gsub(/\AUint/, "UInt") + "DataType"
+ data_type = Arrow.const_get(data_type_class_name).new
+ end
Arrow::Field.new(name, data_type)
end
Arrow::Schema.new(fields)
diff --git a/c_glib/test/helper/flight-sql-server.rb
b/c_glib/test/helper/flight-sql-server.rb
index 8b664ca112..8cbba51f84 100644
--- a/c_glib/test/helper/flight-sql-server.rb
+++ b/c_glib/test/helper/flight-sql-server.rb
@@ -46,5 +46,31 @@ module Helper
end
1
end
+
+ def virtual_do_create_prepared_statement(context, request)
+ unless request.query == "INSERT INTO page_view_table VALUES (?, true)"
+ raise Arrow::Error::Invalid.new("invalid SQL")
+ end
+ result = ArrowFlightSQL::CreatePreparedStatementResult.new
+ generator = FlightInfoGenerator.new
+ table = generator.page_view_table
+ result.dataset_schema = table.schema
+ result.parameter_schema = table.schema.remove_field(1)
+ result.handle = "valid-handle"
+ result
+ end
+
+ def virtual_do_do_put_prepared_statement_update(context, command, reader)
+ unless command.handle.to_s == "valid-handle"
+ raise Arrow::Error::Invalid.new("invalid handle")
+ end
+ reader.read_all.n_rows
+ end
+
+ def virtual_do_close_prepared_statement(context, request)
+ unless request.handle.to_s == "valid-handle"
+ raise Arrow::Error::Invalid.new("invalid handle")
+ end
+ end
end
end
diff --git a/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/loader.rb
b/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
similarity index 67%
copy from ruby/red-arrow-flight-sql/lib/arrow-flight-sql/loader.rb
copy to ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
index 3ff71094db..ff3169d562 100644
--- a/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/loader.rb
+++ b/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/client.rb
@@ -16,25 +16,19 @@
# under the License.
module ArrowFlightSQL
- class Loader < GObjectIntrospection::Loader
- class << self
- def load
- super("ArrowFlightSQL", 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
end
end
-
- private
- def post_load(repository, namespace)
- require_libraries
- end
-
- def require_libraries
- require_relative "server"
- end
-
- def prepare_function_info_lock_gvl(function_info, klass)
- super
- function_info.lock_gvl_default = false
- end
end
end
diff --git a/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/loader.rb
b/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/loader.rb
index 3ff71094db..5c920d9780 100644
--- a/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/loader.rb
+++ b/ruby/red-arrow-flight-sql/lib/arrow-flight-sql/loader.rb
@@ -29,6 +29,7 @@ module ArrowFlightSQL
end
def require_libraries
+ require_relative "client"
require_relative "server"
end
diff --git a/ruby/red-arrow-flight-sql/test/helper/server.rb
b/ruby/red-arrow-flight-sql/test/helper/server.rb
index ab03499639..f7c935fab9 100644
--- a/ruby/red-arrow-flight-sql/test/helper/server.rb
+++ b/ruby/red-arrow-flight-sql/test/helper/server.rb
@@ -37,5 +37,31 @@ module Helper
table = generator.page_view_table
ArrowFlight::RecordBatchStream.new(table)
end
+
+ def virtual_do_create_prepared_statement(context, request)
+ unless request.query == "INSERT INTO page_view_table VALUES (?, true)"
+ raise Arrow::Error::Invalid.new("invalid SQL")
+ end
+ result = ArrowFlightSQL::CreatePreparedStatementResult.new
+ generator = InfoGenerator.new
+ table = generator.page_view_table
+ result.dataset_schema = table.schema
+ result.parameter_schema = table.schema.remove_field(1)
+ result.handle = "valid-handle"
+ result
+ end
+
+ def virtual_do_do_put_prepared_statement_update(context, command, reader)
+ unless command.handle.to_s == "valid-handle"
+ raise Arrow::Error::Invalid.new("invalid handle")
+ end
+ reader.read_all.n_rows
+ end
+
+ def virtual_do_close_prepared_statement(context, request)
+ unless request.handle.to_s == "valid-handle"
+ raise Arrow::Error::Invalid.new("invalid handle")
+ 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 de87328989..21554c1bda 100644
--- a/ruby/red-arrow-flight-sql/test/test-client.rb
+++ b/ruby/red-arrow-flight-sql/test/test-client.rb
@@ -39,4 +39,25 @@ class TestClient < Test::Unit::TestCase
assert_equal(generator.page_view_table,
reader.read_all)
end
+
+ def test_prepare
+ insert_sql = "INSERT INTO page_view_table VALUES (?, true)"
+ block_called = false
+ @sql_client.prepare(insert_sql) do |statement|
+ block_called = true
+ assert_equal([
+ Arrow::Schema.new(count: :uint64, private: :boolean),
+ Arrow::Schema.new(count: :uint64),
+ ],
+ [
+ statement.dataset_schema,
+ statement.parameter_schema,
+ ])
+ counts = Arrow::UInt64Array.new([1, 2, 3])
+ parameters = Arrow::RecordBatch.new(count: counts)
+ statement.set_record_batch(parameters)
+ assert_equal(3, statement.execute_update)
+ end
+ assert_true(block_called)
+ end
end