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 2018/11/22 14:24:07 UTC

[arrow] branch master updated: ARROW-3845: [Gandiva] [GLib] Add GGandivaNode

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

kou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new 2591454  ARROW-3845: [Gandiva] [GLib] Add GGandivaNode
2591454 is described below

commit 2591454e586f51817a89519a6fcae331d13b07e1
Author: Yosuke Shiro <yo...@gmail.com>
AuthorDate: Thu Nov 22 23:23:53 2018 +0900

    ARROW-3845: [Gandiva] [GLib] Add GGandivaNode
    
    This PR adds Node classes to create `GGandivaExpression` with the specified `GGandivaNode`.
    
    Author: Yosuke Shiro <yo...@gmail.com>
    Author: Kouhei Sutou <ko...@clear-code.com>
    
    Closes #3006 from shiro615/glib-add-ggandiva-node and squashes the following commits:
    
    c166c8fa <Yosuke Shiro> Fix argument names
    1903653b <Yosuke Shiro> Use each classes name not 'gandiva'
    e06a323a <Yosuke Shiro> Change document in ggandiva_expression_new()
    75798e60 <Yosuke Shiro> Change property names to use root_node and result_field
    f45ca8d1 <Yosuke Shiro> Fix indents
    1fcc2230 <Yosuke Shiro> Keep reference to GGandivaNode in GGandivaExpression
    62c3d8d2 <Yosuke Shiro> Remove (transfer full) in ggandiva_expression_new()
    55fa3e52 <Yosuke Shiro> Keep reference to GArrowField in GGandivaExpression
    f4c4420b <Yosuke Shiro> Change parameter name in ggandiva_expression_new()
    c2bcc807 <Yosuke Shiro> Use 'Expression Tree' in document
    84a5d67c <Kouhei Sutou> Keep reference to argument to prevent freeing while using
    f36ad385 <Kouhei Sutou> Keep reference to GArrowField to prevent freeing while using
    ec774ca9 <Kouhei Sutou> Use get_instance_private() for GET_PRIVATE()
    428e91eb <Kouhei Sutou> Add "Gandiva" prefix
    6f34b8d6 <Kouhei Sutou> Specify section ID explicitly
    a4deb089 <Yosuke Shiro> Fix red-gandiva test case
    6f15863c <Yosuke Shiro> Add missing include
    eb5ec7a6 <Yosuke Shiro> Fix a typo
    cd1a8e12 <Yosuke Shiro> Create GGandivaExpression with the specified GGandivaNode
    900fb337 <Yosuke Shiro>  Add Node classes for GGandiva
---
 c_glib/arrow-glib/codec.cpp                        |   2 +-
 c_glib/doc/gandiva-glib/gandiva-glib-docs.xml      |   8 +
 c_glib/gandiva-glib/Makefile.am                    |   3 +
 c_glib/gandiva-glib/expression.cpp                 | 131 +++++--
 c_glib/gandiva-glib/expression.h                   |   7 +-
 c_glib/gandiva-glib/expression.hpp                 |   5 +-
 c_glib/gandiva-glib/gandiva-glib.h                 |   1 +
 c_glib/gandiva-glib/gandiva-glib.hpp               |   1 +
 c_glib/gandiva-glib/meson.build                    |   3 +
 c_glib/gandiva-glib/node.cpp                       | 436 +++++++++++++++++++++
 c_glib/gandiva-glib/node.h                         |  70 ++++
 c_glib/gandiva-glib/{expression.hpp => node.hpp}   |  14 +-
 c_glib/gandiva-glib/projector.cpp                  |  12 +-
 c_glib/test/gandiva/test-expression.rb             |  28 +-
 .../{test-expression.rb => test-field-node.rb}     |  12 +-
 .../{test-projector.rb => test-function-node.rb}   |  35 +-
 c_glib/test/gandiva/test-projector.rb              |  18 +-
 ruby/red-gandiva/test/test-projector.rb            |  14 +-
 18 files changed, 711 insertions(+), 89 deletions(-)

diff --git a/c_glib/arrow-glib/codec.cpp b/c_glib/arrow-glib/codec.cpp
index 205ae89..4586387 100644
--- a/c_glib/arrow-glib/codec.cpp
+++ b/c_glib/arrow-glib/codec.cpp
@@ -34,7 +34,7 @@ G_BEGIN_DECLS
  * #GArrowCompressionType provides compression types corresponding to
  * `arrow::Compression::type`.
  *
- * #GArrowCocec is a class for compressing and decompressing data.
+ * #GArrowCodec is a class for compressing and decompressing data.
  */
 
 typedef struct GArrowCodecPrivate_ {
diff --git a/c_glib/doc/gandiva-glib/gandiva-glib-docs.xml b/c_glib/doc/gandiva-glib/gandiva-glib-docs.xml
index 2618750..2335e11 100644
--- a/c_glib/doc/gandiva-glib/gandiva-glib-docs.xml
+++ b/c_glib/doc/gandiva-glib/gandiva-glib-docs.xml
@@ -48,6 +48,14 @@
     </chapter>
   </part>
 
+  <part id="expression-tree">
+    <title>Expression Tree</title>
+    <chapter id="node">
+      <title>Node</title>
+      <xi:include href="xml/node.xml"/>
+    </chapter>
+  </part>
+
   <chapter id="object-tree">
     <title>Object Hierarchy</title>
     <xi:include href="xml/tree_index.sgml"/>
diff --git a/c_glib/gandiva-glib/Makefile.am b/c_glib/gandiva-glib/Makefile.am
index 1c42f53..5869dc7 100644
--- a/c_glib/gandiva-glib/Makefile.am
+++ b/c_glib/gandiva-glib/Makefile.am
@@ -54,16 +54,19 @@ libgandiva_glib_la_LIBADD =			\
 libgandiva_glib_la_headers =			\
 	expression.h				\
 	gandiva-glib.h				\
+	node.h					\
 	projector.h
 
 libgandiva_glib_la_sources =			\
 	expression.cpp				\
+	node.cpp				\
 	projector.cpp				\
 	$(libgandiva_glib_la_headers)
 
 libgandiva_glib_la_cpp_headers =		\
 	expression.hpp				\
 	gandiva-glib.hpp			\
+	node.hpp				\
 	projector.hpp
 
 libgandiva_glib_la_SOURCES =			\
diff --git a/c_glib/gandiva-glib/expression.cpp b/c_glib/gandiva-glib/expression.cpp
index 873f78b..529d851 100644
--- a/c_glib/gandiva-glib/expression.cpp
+++ b/c_glib/gandiva-glib/expression.cpp
@@ -24,6 +24,7 @@
 #include <arrow-glib/field.hpp>
 
 #include <gandiva-glib/expression.hpp>
+#include <gandiva-glib/node.hpp>
 
 G_BEGIN_DECLS
 
@@ -40,21 +41,42 @@ G_BEGIN_DECLS
 
 typedef struct GGandivaExpressionPrivate_ {
   std::shared_ptr<gandiva::Expression> expression;
+  GGandivaNode *root_node;
+  GArrowField *result_field;
 } GGandivaExpressionPrivate;
 
 enum {
-  PROP_0,
-  PROP_EXPRESSION
+  PROP_EXPRESSION = 1,
+  PROP_ROOT_NODE,
+  PROP_RESULT_FIELD
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE(GGandivaExpression,
                            ggandiva_expression,
                            G_TYPE_OBJECT)
 
-#define GGANDIVA_EXPRESSION_GET_PRIVATE(obj)                 \
-  (G_TYPE_INSTANCE_GET_PRIVATE((obj),                        \
-                               GGANDIVA_TYPE_EXPRESSION,     \
-                               GGandivaExpressionPrivate))
+#define GGANDIVA_EXPRESSION_GET_PRIVATE(object)                 \
+  static_cast<GGandivaExpressionPrivate *>(                     \
+    ggandiva_expression_get_instance_private(                   \
+      GGANDIVA_EXPRESSION(object)))
+
+static void
+ggandiva_expression_dispose(GObject *object)
+{
+  auto priv = GGANDIVA_EXPRESSION_GET_PRIVATE(object);
+
+  if (priv->root_node) {
+    g_object_unref(priv->root_node);
+    priv->root_node = nullptr;
+  }
+
+  if (priv->result_field) {
+    g_object_unref(priv->result_field);
+    priv->result_field = nullptr;
+  }
+
+  G_OBJECT_CLASS(ggandiva_expression_parent_class)->dispose(object);
+}
 
 static void
 ggandiva_expression_finalize(GObject *object)
@@ -79,6 +101,33 @@ ggandiva_expression_set_property(GObject *object,
     priv->expression =
       *static_cast<std::shared_ptr<gandiva::Expression> *>(g_value_get_pointer(value));
     break;
+  case PROP_ROOT_NODE:
+    priv->root_node = GGANDIVA_NODE(g_value_dup_object(value));
+    break;
+  case PROP_RESULT_FIELD:
+    priv->result_field = GARROW_FIELD(g_value_dup_object(value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+ggandiva_expression_get_property(GObject *object,
+                                 guint prop_id,
+                                 GValue *value,
+                                 GParamSpec *pspec)
+{
+  auto priv = GGANDIVA_EXPRESSION_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_ROOT_NODE:
+    g_value_set_object(value, priv->root_node);
+    break;
+  case PROP_RESULT_FIELD:
+    g_value_set_object(value, priv->result_field);
+    break;
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     break;
@@ -93,49 +142,59 @@ ggandiva_expression_init(GGandivaExpression *object)
 static void
 ggandiva_expression_class_init(GGandivaExpressionClass *klass)
 {
-  GParamSpec *spec;
-
   auto gobject_class = G_OBJECT_CLASS(klass);
 
+  gobject_class->dispose      = ggandiva_expression_dispose;
   gobject_class->finalize     = ggandiva_expression_finalize;
   gobject_class->set_property = ggandiva_expression_set_property;
+  gobject_class->get_property = ggandiva_expression_get_property;
 
+  GParamSpec *spec;
   spec = g_param_spec_pointer("expression",
                               "Expression",
                               "The raw std::shared<gandiva::Expression> *",
                               static_cast<GParamFlags>(G_PARAM_WRITABLE |
                                                        G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property(gobject_class, PROP_EXPRESSION, spec);
+
+  spec = g_param_spec_object("root-node",
+                             "Root Node",
+                             "The root node for the expression",
+                             GGANDIVA_TYPE_NODE,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_ROOT_NODE, spec);
+
+  spec = g_param_spec_object("result-field",
+                             "Result Field",
+                             "The name and type of returned value as #GArrowField",
+                             GARROW_TYPE_FIELD,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_RESULT_FIELD, spec);
 }
 
 /**
  * ggandiva_expression_new:
- * @function: The function name in the expression.
- * @input_fields: (element-type GArrowField): The input fields.
- * @output_field: A #GArrowField to be output.
+ * @root_node: The root node for the expression.
+ * @result_field: The name and type of returned value as #GArrowField.
  *
- * Returns: (transfer full): The expression tree with a root node,
- *   and a result field.
+ * Returns: A newly created #GGandivaExpression.
  *
  * Since: 0.12.0
  */
 GGandivaExpression *
-ggandiva_expression_new(const gchar *function,
-                        GList *input_fields,
-                        GArrowField *output_field)
+ggandiva_expression_new(GGandivaNode *root_node,
+                        GArrowField *result_field)
 {
-  std::vector<std::shared_ptr<arrow::Field>> arrow_input_fields;
-  for (GList *node = input_fields; node; node = g_list_next(node)) {
-    auto field = GARROW_FIELD(node->data);
-    auto arrow_input_field = garrow_field_get_raw(field);
-    arrow_input_fields.push_back(arrow_input_field);
-  }
-  auto arrow_output_field = garrow_field_get_raw(output_field);
+  auto gandiva_root_node = ggandiva_node_get_raw(root_node);
+  auto arrow_result_field = garrow_field_get_raw(result_field);
   auto gandiva_expression =
-    gandiva::TreeExprBuilder::MakeExpression(function,
-                                             arrow_input_fields,
-                                             arrow_output_field);
-  return ggandiva_expression_new_raw(&gandiva_expression);
+    gandiva::TreeExprBuilder::MakeExpression(gandiva_root_node,
+                                             arrow_result_field);
+  return ggandiva_expression_new_raw(&gandiva_expression,
+                                     root_node,
+                                     result_field);
 }
 
 /**
@@ -158,17 +217,21 @@ ggandiva_expression_to_string(GGandivaExpression *expression)
 G_END_DECLS
 
 GGandivaExpression *
-ggandiva_expression_new_raw(std::shared_ptr<gandiva::Expression> *gandiva_expression)
+ggandiva_expression_new_raw(std::shared_ptr<gandiva::Expression> *gandiva_expression,
+                            GGandivaNode *root_node,
+                            GArrowField *result_field)
 {
-  auto gandiva = g_object_new(GGANDIVA_TYPE_EXPRESSION,
-                              "expression", gandiva_expression,
-                              NULL);
-  return GGANDIVA_EXPRESSION(gandiva);
+  auto expression = g_object_new(GGANDIVA_TYPE_EXPRESSION,
+                                 "expression", gandiva_expression,
+                                 "root-node", root_node,
+                                 "result-field", result_field,
+                                 NULL);
+  return GGANDIVA_EXPRESSION(expression);
 }
 
 std::shared_ptr<gandiva::Expression>
-ggandiva_expression_get_raw(GGandivaExpression *gandiva)
+ggandiva_expression_get_raw(GGandivaExpression *expression)
 {
-  auto priv = GGANDIVA_EXPRESSION_GET_PRIVATE(gandiva);
+  auto priv = GGANDIVA_EXPRESSION_GET_PRIVATE(expression);
   return priv->expression;
 }
diff --git a/c_glib/gandiva-glib/expression.h b/c_glib/gandiva-glib/expression.h
index 4160210..f86b6c5 100644
--- a/c_glib/gandiva-glib/expression.h
+++ b/c_glib/gandiva-glib/expression.h
@@ -21,6 +21,8 @@
 
 #include <arrow-glib/arrow-glib.h>
 
+#include <gandiva-glib/node.h>
+
 G_BEGIN_DECLS
 
 #define GGANDIVA_TYPE_EXPRESSION (ggandiva_expression_get_type())
@@ -35,9 +37,8 @@ struct _GGandivaExpressionClass
   GObjectClass parent_class;
 };
 
-GGandivaExpression *ggandiva_expression_new(const gchar *function,
-                                            GList *input_fields,
-                                            GArrowField *output_field);
+GGandivaExpression *ggandiva_expression_new(GGandivaNode *root_node,
+                                            GArrowField *result_field);
 gchar *ggandiva_expression_to_string(GGandivaExpression *expression);
 
 G_END_DECLS
diff --git a/c_glib/gandiva-glib/expression.hpp b/c_glib/gandiva-glib/expression.hpp
index f6c2781..a0d0e64 100644
--- a/c_glib/gandiva-glib/expression.hpp
+++ b/c_glib/gandiva-glib/expression.hpp
@@ -26,5 +26,8 @@
 
 #include <gandiva-glib/expression.h>
 
-GGandivaExpression *ggandiva_expression_new_raw(std::shared_ptr<gandiva::Expression> *gandiva_expression);
+GGandivaExpression
+*ggandiva_expression_new_raw(std::shared_ptr<gandiva::Expression> *gandiva_expression,
+                             GGandivaNode *root_node,
+                             GArrowField *result_field);
 std::shared_ptr<gandiva::Expression> ggandiva_expression_get_raw(GGandivaExpression *expression);
diff --git a/c_glib/gandiva-glib/gandiva-glib.h b/c_glib/gandiva-glib/gandiva-glib.h
index 62fd2b5..10a91f53 100644
--- a/c_glib/gandiva-glib/gandiva-glib.h
+++ b/c_glib/gandiva-glib/gandiva-glib.h
@@ -20,4 +20,5 @@
 #pragma once
 
 #include <gandiva-glib/expression.h>
+#include <gandiva-glib/node.h>
 #include <gandiva-glib/projector.h>
diff --git a/c_glib/gandiva-glib/gandiva-glib.hpp b/c_glib/gandiva-glib/gandiva-glib.hpp
index 08563ca..8d857a3 100644
--- a/c_glib/gandiva-glib/gandiva-glib.hpp
+++ b/c_glib/gandiva-glib/gandiva-glib.hpp
@@ -22,4 +22,5 @@
 #include <gandiva-glib/gandiva-glib.h>
 
 #include <gandiva-glib/expression.hpp>
+#include <gandiva-glib/node.hpp>
 #include <gandiva-glib/projector.hpp>
diff --git a/c_glib/gandiva-glib/meson.build b/c_glib/gandiva-glib/meson.build
index 32bd307..7c288e4 100644
--- a/c_glib/gandiva-glib/meson.build
+++ b/c_glib/gandiva-glib/meson.build
@@ -21,18 +21,21 @@ project_name = 'gandiva-glib'
 
 sources = files(
   'expression.cpp',
+  'node.cpp',
   'projector.cpp',
 )
 
 c_headers = files(
   'expression.h',
   'gandiva-glib.h',
+  'node.h',
   'projector.h',
 )
 
 cpp_headers = files(
   'expression.hpp',
   'gandiva-glib.hpp',
+  'node.hpp',
   'projector.hpp',
 )
 
diff --git a/c_glib/gandiva-glib/node.cpp b/c_glib/gandiva-glib/node.cpp
new file mode 100644
index 0000000..49d1d0b
--- /dev/null
+++ b/c_glib/gandiva-glib/node.cpp
@@ -0,0 +1,436 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <arrow-glib/data-type.hpp>
+#include <arrow-glib/field.hpp>
+
+#include <gandiva-glib/node.hpp>
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION: node
+ * @section_id: node-classes
+ * @title: Node classes
+ * @include: gandiva-glib/gandiva-glib.h
+ *
+ * #GGandivaNode is a base class for a node in the expression tree.
+ *
+ * #GGandivaFieldNode is a class for a node in the expression tree, representing an Arrow field.
+ *
+ * #GGandivaFunctionNode is a class for a node in the expression tree, representing a function.
+ *
+ * Since: 0.12.0
+ */
+
+typedef struct GGandivaNodePrivate_ {
+  std::shared_ptr<gandiva::Node> node;
+} GGandivaNodePrivate;
+
+enum {
+  PROP_NODE = 1
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GGandivaNode,
+                           ggandiva_node,
+                           G_TYPE_OBJECT)
+
+#define GGANDIVA_NODE_GET_PRIVATE(object)                       \
+  static_cast<GGandivaNodePrivate *>(                           \
+    ggandiva_node_get_instance_private(                         \
+      GGANDIVA_NODE(object)))
+
+static void
+ggandiva_node_finalize(GObject *object)
+{
+  auto priv = GGANDIVA_NODE_GET_PRIVATE(object);
+
+  priv->node = nullptr;
+
+  G_OBJECT_CLASS(ggandiva_node_parent_class)->finalize(object);
+}
+
+static void
+ggandiva_node_set_property(GObject *object,
+                           guint prop_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
+{
+  auto priv = GGANDIVA_NODE_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_NODE:
+    priv->node =
+      *static_cast<std::shared_ptr<gandiva::Node> *>(g_value_get_pointer(value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+ggandiva_node_init(GGandivaNode *object)
+{
+}
+
+static void
+ggandiva_node_class_init(GGandivaNodeClass *klass)
+{
+  GParamSpec *spec;
+
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->finalize     = ggandiva_node_finalize;
+  gobject_class->set_property = ggandiva_node_set_property;
+
+  spec = g_param_spec_pointer("node",
+                              "Node",
+                              "The raw std::shared<gandiva::Node> *",
+                              static_cast<GParamFlags>(G_PARAM_WRITABLE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_NODE, spec);
+}
+
+
+typedef struct GGandivaFieldNodePrivate_ {
+  GArrowField *field;
+} GGandivaFieldNodePrivate;
+
+enum {
+  PROP_FIELD = 1
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GGandivaFieldNode,
+                           ggandiva_field_node,
+                           GGANDIVA_TYPE_NODE)
+
+#define GGANDIVA_FIELD_NODE_GET_PRIVATE(object)                 \
+  static_cast<GGandivaFieldNodePrivate *>(                      \
+    ggandiva_field_node_get_instance_private(                   \
+      GGANDIVA_FIELD_NODE(object)))
+
+static void
+ggandiva_field_node_dispose(GObject *object)
+{
+  auto priv = GGANDIVA_FIELD_NODE_GET_PRIVATE(object);
+
+  if (priv->field) {
+    g_object_unref(priv->field);
+    priv->field = nullptr;
+  }
+
+  G_OBJECT_CLASS(ggandiva_field_node_parent_class)->dispose(object);
+}
+
+static void
+ggandiva_field_node_set_property(GObject *object,
+                                 guint prop_id,
+                                 const GValue *value,
+                                 GParamSpec *pspec)
+{
+  auto priv = GGANDIVA_FIELD_NODE_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_FIELD:
+    priv->field = GARROW_FIELD(g_value_dup_object(value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+ggandiva_field_node_get_property(GObject *object,
+                                 guint prop_id,
+                                 GValue *value,
+                                 GParamSpec *pspec)
+{
+  auto priv = GGANDIVA_FIELD_NODE_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_FIELD:
+    g_value_set_object(value, priv->field);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+ggandiva_field_node_init(GGandivaFieldNode *field_node)
+{
+}
+
+static void
+ggandiva_field_node_class_init(GGandivaFieldNodeClass *klass)
+{
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->dispose      = ggandiva_field_node_dispose;
+  gobject_class->set_property = ggandiva_field_node_set_property;
+  gobject_class->get_property = ggandiva_field_node_get_property;
+
+  GParamSpec *spec;
+  spec = g_param_spec_object("field",
+                             "Field",
+                             "The field",
+                             GARROW_TYPE_FIELD,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_FIELD, spec);
+}
+
+/**
+ * ggandiva_field_node_new:
+ * @field: A #GArrowField.
+ *
+ * Returns: A newly created #GGandivaFieldNode for the given field.
+ *
+ * Since: 0.12.0
+ */
+GGandivaFieldNode *
+ggandiva_field_node_new(GArrowField *field)
+{
+  auto arrow_field = garrow_field_get_raw(field);
+  auto gandiva_node = gandiva::TreeExprBuilder::MakeField(arrow_field);
+  return ggandiva_field_node_new_raw(&gandiva_node, field);
+}
+
+
+typedef struct GGandivaFunctionNodePrivate_ {
+  gchar *name;
+  GList *parameters;
+  GArrowDataType *return_type;
+} GGandivaFunctionNodePrivate;
+
+enum {
+  PROP_NAME = 1,
+  PROP_RETURN_TYPE
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(GGandivaFunctionNode,
+                           ggandiva_function_node,
+                           GGANDIVA_TYPE_NODE)
+
+#define GGANDIVA_FUNCTION_NODE_GET_PRIVATE(object)      \
+  static_cast<GGandivaFunctionNodePrivate *>(           \
+    ggandiva_function_node_get_instance_private(        \
+      GGANDIVA_FUNCTION_NODE(object)))                  \
+
+static void
+ggandiva_function_node_dispose(GObject *object)
+{
+  auto priv = GGANDIVA_FUNCTION_NODE_GET_PRIVATE(object);
+
+  if (priv->parameters) {
+    for (auto node = priv->parameters; node; node = g_list_next(node)) {
+      auto parameter = GGANDIVA_NODE(node->data);
+      g_object_unref(parameter);
+    }
+    g_list_free(priv->parameters);
+    priv->parameters = nullptr;
+  }
+
+  if (priv->return_type) {
+    g_object_unref(priv->return_type);
+    priv->return_type = nullptr;
+  }
+
+  G_OBJECT_CLASS(ggandiva_function_node_parent_class)->dispose(object);
+}
+
+static void
+ggandiva_function_node_finalize(GObject *object)
+{
+  auto priv = GGANDIVA_FUNCTION_NODE_GET_PRIVATE(object);
+
+  g_free(priv->name);
+
+  G_OBJECT_CLASS(ggandiva_function_node_parent_class)->finalize(object);
+}
+
+static void
+ggandiva_function_node_set_property(GObject *object,
+                                    guint prop_id,
+                                    const GValue *value,
+                                    GParamSpec *pspec)
+{
+  auto priv = GGANDIVA_FUNCTION_NODE_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_NAME:
+    priv->name = g_value_dup_string(value);
+    break;
+  case PROP_RETURN_TYPE:
+    priv->return_type = GARROW_DATA_TYPE(g_value_dup_object(value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+ggandiva_function_node_get_property(GObject *object,
+                                    guint prop_id,
+                                    GValue *value,
+                                    GParamSpec *pspec)
+{
+  auto priv = GGANDIVA_FUNCTION_NODE_GET_PRIVATE(object);
+
+  switch (prop_id) {
+  case PROP_NAME:
+    g_value_set_string(value, priv->name);
+    break;
+  case PROP_RETURN_TYPE:
+    g_value_set_object(value, priv->return_type);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    break;
+  }
+}
+
+static void
+ggandiva_function_node_init(GGandivaFunctionNode *function_node)
+{
+  auto priv = GGANDIVA_FUNCTION_NODE_GET_PRIVATE(function_node);
+  priv->parameters = nullptr;
+}
+
+static void
+ggandiva_function_node_class_init(GGandivaFunctionNodeClass *klass)
+{
+  auto gobject_class = G_OBJECT_CLASS(klass);
+
+  gobject_class->dispose      = ggandiva_function_node_dispose;
+  gobject_class->finalize     = ggandiva_function_node_finalize;
+  gobject_class->set_property = ggandiva_function_node_set_property;
+  gobject_class->get_property = ggandiva_function_node_get_property;
+
+  GParamSpec *spec;
+  spec = g_param_spec_string("name",
+                             "Name",
+                             "The name of the function",
+                             nullptr,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_NAME, spec);
+
+  spec = g_param_spec_object("return-type",
+                             "Return type",
+                             "The return type of the function",
+                             GARROW_TYPE_DATA_TYPE,
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property(gobject_class, PROP_RETURN_TYPE, spec);
+}
+
+/**
+ * ggandiva_function_node_new:
+ * @name: The name of the function to be called.
+ * @parameters: (element-type GGandivaNode): The parameters of the function call.
+ * @return_type: The return type of the function call.
+ *
+ * Returns: A newly created #GGandivaFunctionNode for the function call.
+ *
+ * Since: 0.12.0
+ */
+GGandivaFunctionNode *
+ggandiva_function_node_new(const gchar *name,
+                           GList *parameters,
+                           GArrowDataType *return_type)
+{
+  std::vector<std::shared_ptr<gandiva::Node>> gandiva_nodes;
+  for (auto node = parameters; node; node = g_list_next(node)) {
+    auto gandiva_node = ggandiva_node_get_raw(GGANDIVA_NODE(node->data));
+    gandiva_nodes.push_back(gandiva_node);
+  }
+  auto arrow_return_type = garrow_data_type_get_raw(return_type);
+  auto gandiva_node = gandiva::TreeExprBuilder::MakeFunction(name,
+                                                             gandiva_nodes,
+                                                             arrow_return_type);
+  return ggandiva_function_node_new_raw(&gandiva_node,
+                                        name,
+                                        parameters,
+                                        return_type);
+}
+
+/**
+ * ggandiva_function_node_get_parameters:
+ * @node: A #GGandivaFunctionNode.
+ *
+ * Returns: (transfer none) (element-type GGandivaNode):
+ *   The parameters of the function node.
+ *
+ * Since: 0.12.0
+ */
+GList *
+ggandiva_function_node_get_parameters(GGandivaFunctionNode *node)
+{
+  auto priv = GGANDIVA_FUNCTION_NODE_GET_PRIVATE(node);
+  return priv->parameters;
+}
+
+G_END_DECLS
+
+std::shared_ptr<gandiva::Node>
+ggandiva_node_get_raw(GGandivaNode *node)
+{
+  auto priv = GGANDIVA_NODE_GET_PRIVATE(node);
+  return priv->node;
+}
+
+GGandivaFieldNode *
+ggandiva_field_node_new_raw(std::shared_ptr<gandiva::Node> *gandiva_node,
+                            GArrowField *field)
+{
+  auto field_node = g_object_new(GGANDIVA_TYPE_FIELD_NODE,
+                                 "node", gandiva_node,
+                                 "field", field,
+                                 NULL);
+  return GGANDIVA_FIELD_NODE(field_node);
+}
+
+GGandivaFunctionNode *
+ggandiva_function_node_new_raw(std::shared_ptr<gandiva::Node> *gandiva_node,
+                               const gchar *name,
+                               GList *parameters,
+                               GArrowDataType *return_type)
+{
+  auto function_node = g_object_new(GGANDIVA_TYPE_FUNCTION_NODE,
+                                    "node", gandiva_node,
+                                    "name", name,
+                                    "return-type", return_type,
+                                    NULL);
+  auto priv = GGANDIVA_FUNCTION_NODE_GET_PRIVATE(function_node);
+  for (auto node = parameters; node; node = g_list_next(node)) {
+    auto parameter = GGANDIVA_NODE(node->data);
+    priv->parameters = g_list_prepend(priv->parameters, g_object_ref(parameter));
+  }
+  priv->parameters = g_list_reverse(priv->parameters);
+  return GGANDIVA_FUNCTION_NODE(function_node);
+}
diff --git a/c_glib/gandiva-glib/node.h b/c_glib/gandiva-glib/node.h
new file mode 100644
index 0000000..98ab3af
--- /dev/null
+++ b/c_glib/gandiva-glib/node.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <arrow-glib/arrow-glib.h>
+
+G_BEGIN_DECLS
+
+#define GGANDIVA_TYPE_NODE (ggandiva_node_get_type())
+G_DECLARE_DERIVABLE_TYPE(GGandivaNode,
+                         ggandiva_node,
+                         GGANDIVA,
+                         NODE,
+                         GObject)
+
+struct _GGandivaNodeClass
+{
+  GObjectClass parent_class;
+};
+
+#define GGANDIVA_TYPE_FIELD_NODE (ggandiva_field_node_get_type())
+G_DECLARE_DERIVABLE_TYPE(GGandivaFieldNode,
+                         ggandiva_field_node,
+                         GGANDIVA,
+                         FIELD_NODE,
+                         GGandivaNode)
+struct _GGandivaFieldNodeClass
+{
+  GGandivaNodeClass parent_class;
+};
+
+GGandivaFieldNode *ggandiva_field_node_new(GArrowField *field);
+
+
+#define GGANDIVA_TYPE_FUNCTION_NODE (ggandiva_function_node_get_type())
+G_DECLARE_DERIVABLE_TYPE(GGandivaFunctionNode,
+                         ggandiva_function_node,
+                         GGANDIVA,
+                         FUNCTION_NODE,
+                         GGandivaNode)
+struct _GGandivaFunctionNodeClass
+{
+  GGandivaNodeClass parent_class;
+};
+
+GGandivaFunctionNode *
+ggandiva_function_node_new(const gchar *name,
+                           GList *parameters,
+                           GArrowDataType *return_type);
+GList *
+ggandiva_function_node_get_parameters(GGandivaFunctionNode *node);
+
+G_END_DECLS
diff --git a/c_glib/gandiva-glib/expression.hpp b/c_glib/gandiva-glib/node.hpp
similarity index 63%
copy from c_glib/gandiva-glib/expression.hpp
copy to c_glib/gandiva-glib/node.hpp
index f6c2781..953c214 100644
--- a/c_glib/gandiva-glib/expression.hpp
+++ b/c_glib/gandiva-glib/node.hpp
@@ -21,10 +21,16 @@
 
 #include <memory>
 
-#include <gandiva/expression.h>
 #include <gandiva/tree_expr_builder.h>
 
-#include <gandiva-glib/expression.h>
+#include <gandiva-glib/node.h>
 
-GGandivaExpression *ggandiva_expression_new_raw(std::shared_ptr<gandiva::Expression> *gandiva_expression);
-std::shared_ptr<gandiva::Expression> ggandiva_expression_get_raw(GGandivaExpression *expression);
+std::shared_ptr<gandiva::Node> ggandiva_node_get_raw(GGandivaNode *node);
+GGandivaFieldNode *
+ggandiva_field_node_new_raw(std::shared_ptr<gandiva::Node> *gandiva_node,
+                            GArrowField *field);
+GGandivaFunctionNode *
+ggandiva_function_node_new_raw(std::shared_ptr<gandiva::Node> *gandiva_node,
+                               const gchar *name,
+                               GList *parameters,
+                               GArrowDataType *return_type);
diff --git a/c_glib/gandiva-glib/projector.cpp b/c_glib/gandiva-glib/projector.cpp
index 983ecda..036576f 100644
--- a/c_glib/gandiva-glib/projector.cpp
+++ b/c_glib/gandiva-glib/projector.cpp
@@ -188,15 +188,15 @@ G_END_DECLS
 GGandivaProjector *
 ggandiva_projector_new_raw(std::shared_ptr<gandiva::Projector> *gandiva_projector)
 {
-  auto gandiva = g_object_new(GGANDIVA_TYPE_PROJECTOR,
-                              "projector", gandiva_projector,
-                              NULL);
-  return GGANDIVA_PROJECTOR(gandiva);
+  auto projector = g_object_new(GGANDIVA_TYPE_PROJECTOR,
+                                "projector", gandiva_projector,
+                                NULL);
+  return GGANDIVA_PROJECTOR(projector);
 }
 
 std::shared_ptr<gandiva::Projector>
-ggandiva_projector_get_raw(GGandivaProjector *gandiva)
+ggandiva_projector_get_raw(GGandivaProjector *projector)
 {
-  auto priv = GGANDIVA_PROJECTOR_GET_PRIVATE(gandiva);
+  auto priv = GGANDIVA_PROJECTOR_GET_PRIVATE(projector);
   return priv->projector;
 }
diff --git a/c_glib/test/gandiva/test-expression.rb b/c_glib/test/gandiva/test-expression.rb
index fa826b1..2e27d6e 100644
--- a/c_glib/test/gandiva/test-expression.rb
+++ b/c_glib/test/gandiva/test-expression.rb
@@ -15,16 +15,32 @@
 # specific language governing permissions and limitations
 # under the License.
 
-class TestExpression < Test::Unit::TestCase
+class TestGandivaExpression < Test::Unit::TestCase
   def setup
     omit("Gandiva is required") unless defined?(::Gandiva)
+    augend = Arrow::Field.new("augend", Arrow::Int32DataType.new)
+    addend = Arrow::Field.new("addend", Arrow::Int32DataType.new)
+    augend_node = Gandiva::FieldNode.new(augend)
+    addend_node = Gandiva::FieldNode.new(addend)
+    @function_node = Gandiva::FunctionNode.new("add",
+                                               [augend_node, addend_node],
+                                               Arrow::Int32DataType.new)
+    @sum = Arrow::Field.new("sum", Arrow::Int32DataType.new)
+    @expression = Gandiva::Expression.new(@function_node, @sum)
+  end
+
+  def test_readers
+    assert_equal([
+                   @function_node,
+                   @sum
+                 ],
+                 [
+                   @expression.root_node,
+                   @expression.result_field
+                 ])
   end
 
   def test_to_s
-    augend = Arrow::Field.new("augend", Arrow::Int32DataType.new)
-    addend = Arrow::Field.new("addend", Arrow::Int32DataType.new)
-    sum = Arrow::Field.new("sum", Arrow::Int32DataType.new)
-    expression = Gandiva::Expression.new("add", [augend, addend], sum)
-    assert_equal("int32 add((int32) augend, (int32) addend)", expression.to_s)
+    assert_equal("int32 add((int32) augend, (int32) addend)", @expression.to_s)
   end
 end
diff --git a/c_glib/test/gandiva/test-expression.rb b/c_glib/test/gandiva/test-field-node.rb
similarity index 68%
copy from c_glib/test/gandiva/test-expression.rb
copy to c_glib/test/gandiva/test-field-node.rb
index fa826b1..c5bfe6c 100644
--- a/c_glib/test/gandiva/test-expression.rb
+++ b/c_glib/test/gandiva/test-field-node.rb
@@ -15,16 +15,14 @@
 # specific language governing permissions and limitations
 # under the License.
 
-class TestExpression < Test::Unit::TestCase
+class TestGandivaFieldNode < Test::Unit::TestCase
   def setup
     omit("Gandiva is required") unless defined?(::Gandiva)
   end
 
-  def test_to_s
-    augend = Arrow::Field.new("augend", Arrow::Int32DataType.new)
-    addend = Arrow::Field.new("addend", Arrow::Int32DataType.new)
-    sum = Arrow::Field.new("sum", Arrow::Int32DataType.new)
-    expression = Gandiva::Expression.new("add", [augend, addend], sum)
-    assert_equal("int32 add((int32) augend, (int32) addend)", expression.to_s)
+  def test_field
+    field = Arrow::Field.new("valid", Arrow::BooleanDataType.new)
+    field_node = Gandiva::FieldNode.new(field)
+    assert_equal(field, field_node.field)
   end
 end
diff --git a/c_glib/test/gandiva/test-projector.rb b/c_glib/test/gandiva/test-function-node.rb
similarity index 53%
copy from c_glib/test/gandiva/test-projector.rb
copy to c_glib/test/gandiva/test-function-node.rb
index 682ef25..cb4fe0a 100644
--- a/c_glib/test/gandiva/test-projector.rb
+++ b/c_glib/test/gandiva/test-function-node.rb
@@ -15,32 +15,29 @@
 # specific language governing permissions and limitations
 # under the License.
 
-class TestProjector < Test::Unit::TestCase
-  include Helper::Buildable
-
+class TestGandivaFunctionNode < Test::Unit::TestCase
   def setup
     omit("Gandiva is required") unless defined?(::Gandiva)
   end
 
-  def test_evaluate
+  def test_readers
     field1 = Arrow::Field.new("field1", Arrow::Int32DataType.new)
     field2 = Arrow::Field.new("field2", Arrow::Int32DataType.new)
-    schema = Arrow::Schema.new([field1, field2])
-    add_result = Arrow::Field.new("add_result", Arrow::Int32DataType.new)
-    subtract_result = Arrow::Field.new("subtract_result", Arrow::Int32DataType.new)
-    add_expression = Gandiva::Expression.new("add", [field1, field2], add_result)
-    subtract_expression = Gandiva::Expression.new("subtract", [field1, field2], subtract_result)
-    projector = Gandiva::Projector.new(schema, [add_expression, subtract_expression])
-    input_arrays = [
-      build_int32_array([1, 2, 3, 4]),
-      build_int32_array([11, 13, 15, 17]),
-    ]
-    record_batch = Arrow::RecordBatch.new(schema, 4, input_arrays)
-    outputs = projector.evaluate(record_batch)
+    field1_node = Gandiva::FieldNode.new(field1)
+    field2_node = Gandiva::FieldNode.new(field2)
+    return_type = Arrow::Int64DataType.new
+    function_node = Gandiva::FunctionNode.new("add",
+                                              [field1_node, field2_node],
+                                              return_type)
     assert_equal([
-                   [12, 15, 18, 21],
-                   [-10, -11, -12, -13],
+                   "add",
+                   [field1_node, field2_node],
+                   return_type,
                  ],
-                 outputs.collect(&:values))
+                 [
+                   function_node.name,
+                   function_node.parameters,
+                   function_node.return_type,
+                 ])
   end
 end
diff --git a/c_glib/test/gandiva/test-projector.rb b/c_glib/test/gandiva/test-projector.rb
index 682ef25..4d33756 100644
--- a/c_glib/test/gandiva/test-projector.rb
+++ b/c_glib/test/gandiva/test-projector.rb
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-class TestProjector < Test::Unit::TestCase
+class TestGandivaProjector < Test::Unit::TestCase
   include Helper::Buildable
 
   def setup
@@ -26,11 +26,21 @@ class TestProjector < Test::Unit::TestCase
     field1 = Arrow::Field.new("field1", Arrow::Int32DataType.new)
     field2 = Arrow::Field.new("field2", Arrow::Int32DataType.new)
     schema = Arrow::Schema.new([field1, field2])
+    field_node1 = Gandiva::FieldNode.new(field1)
+    field_node2 = Gandiva::FieldNode.new(field2)
+    add_function_node = Gandiva::FunctionNode.new("add",
+                                                  [field_node1, field_node2],
+                                                  Arrow::Int32DataType.new)
+    subtract_function_node = Gandiva::FunctionNode.new("subtract",
+                                                       [field_node1, field_node2],
+                                                       Arrow::Int32DataType.new)
     add_result = Arrow::Field.new("add_result", Arrow::Int32DataType.new)
+    add_expression = Gandiva::Expression.new(add_function_node, add_result)
     subtract_result = Arrow::Field.new("subtract_result", Arrow::Int32DataType.new)
-    add_expression = Gandiva::Expression.new("add", [field1, field2], add_result)
-    subtract_expression = Gandiva::Expression.new("subtract", [field1, field2], subtract_result)
-    projector = Gandiva::Projector.new(schema, [add_expression, subtract_expression])
+    subtract_expression = Gandiva::Expression.new(subtract_function_node, subtract_result)
+
+    projector = Gandiva::Projector.new(schema,
+                                       [add_expression, subtract_expression])
     input_arrays = [
       build_int32_array([1, 2, 3, 4]),
       build_int32_array([11, 13, 15, 17]),
diff --git a/ruby/red-gandiva/test/test-projector.rb b/ruby/red-gandiva/test/test-projector.rb
index d4a2221..f0d01d9 100644
--- a/ruby/red-gandiva/test/test-projector.rb
+++ b/ruby/red-gandiva/test/test-projector.rb
@@ -22,13 +22,19 @@ class TestProjector < Test::Unit::TestCase
     schema = table.schema
     field1 = schema[:field1]
     field2 = schema[:field2]
+    field_node1 = Gandiva::FieldNode.new(field1)
+    field_node2 = Gandiva::FieldNode.new(field2)
+    add_function_node = Gandiva::FunctionNode.new("add",
+                                                  [field_node1, field_node2],
+                                                  Arrow::Int32DataType.new)
     add_result = Arrow::Field.new("add_result", :int32)
-    add_expression = Gandiva::Expression.new("add",
-                                             [field1, field2],
+    add_expression = Gandiva::Expression.new(add_function_node,
                                              add_result)
+    subtract_function_node = Gandiva::FunctionNode.new("subtract",
+                                                       [field_node1, field_node2],
+                                                       Arrow::Int32DataType.new)
     subtract_result = Arrow::Field.new("subtract_result", :int32)
-    subtract_expression = Gandiva::Expression.new("subtract",
-                                                  [field1, field2],
+    subtract_expression = Gandiva::Expression.new(subtract_function_node,
                                                   subtract_result)
     projector = Gandiva::Projector.new(schema,
                                        [add_expression, subtract_expression])