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

reshke pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit 08e0b7489ca4083b7f232ab16a9e972ff9ff0b30
Author: Hari krishna <[email protected]>
AuthorDate: Thu Aug 31 14:53:07 2023 +0530

    Support FIELDSELECT node from ORCA (#16265)
    
    * Support FIELDSELECT node from ORCA
    
    Currently, ORCA does not support to handle FIELDSELECT nodes.
    Consequently, when a query involves a FIELDSELECT node, the query
    fallsback to planner.
    
    Solution:
    In order to facilitate FieldSelect nodes within ORCA, several additions
    have been made. This includes introducing the ScalardxlFieldSelect
    operator to translate Query's fieldselect nodes to DXLscalarFieldNodes
    nodes, and the ScalarFieldSelect operator to accommodate fieldSelect
    nodes during optimization. Additionally, a parse handler
    (ParseHandlerScalarFieldSelect) is implemented to support the parsing of
    mdp files containing fieldselect nodes.
---
 .../gpopt/translate/CTranslatorDXLToScalar.cpp     |  36 +++
 .../gpopt/translate/CTranslatorQueryToDXL.cpp      |   1 -
 .../gpopt/translate/CTranslatorScalarToDXL.cpp     |  39 +++
 .../gporca/data/dxl/minidump/FieldSelect.mdp       | 323 +++++++++++++++++++++
 .../libgpopt/include/gpopt/operators/COperator.h   |   2 +
 .../include/gpopt/operators/CScalarFieldSelect.h   | 138 +++++++++
 .../include/gpopt/translate/CTranslatorDXLToExpr.h |   3 +
 .../include/gpopt/translate/CTranslatorExprToDXL.h |   3 +
 .../libgpopt/src/operators/CScalarFieldSelect.cpp  |  96 ++++++
 src/backend/gporca/libgpopt/src/operators/Makefile |   1 +
 .../src/translate/CTranslatorDXLToExpr.cpp         |  33 +++
 .../src/translate/CTranslatorExprToDXL.cpp         |  34 +++
 .../include/naucrates/dxl/operators/CDXLOperator.h |   1 +
 .../naucrates/dxl/operators/CDXLOperatorFactory.h  |   4 +
 .../dxl/operators/CDXLScalarFieldSelect.h          | 109 +++++++
 .../naucrates/dxl/parser/CParseHandlerFactory.h    |   5 +
 .../dxl/parser/CParseHandlerScalarFieldSelect.h    |  66 +++++
 .../include/naucrates/dxl/parser/parsehandlers.h   |   1 +
 .../include/naucrates/dxl/xml/dxltokens.h          |   7 +
 .../src/operators/CDXLOperatorFactory.cpp          |  32 ++
 .../src/operators/CDXLScalarFieldSelect.cpp        | 205 +++++++++++++
 .../gporca/libnaucrates/src/operators/Makefile     |   1 +
 .../src/parser/CParseHandlerFactory.cpp            |  11 +
 .../src/parser/CParseHandlerScalarFieldSelect.cpp  | 129 ++++++++
 .../gporca/libnaucrates/src/parser/Makefile        |   1 +
 .../gporca/libnaucrates/src/xml/dxltokens.cpp      |   8 +-
 src/backend/gporca/server/CMakeLists.txt           |   3 +
 .../gpopt/translate/CTranslatorDXLToScalar.h       |   3 +
 .../gpopt/translate/CTranslatorScalarToDXL.h       |   4 +
 src/test/regress/expected/gporca.out               | 207 +++++++++++++
 src/test/regress/expected/gporca_optimizer.out     | 213 +++++++++++++-
 ...nal_table_persistent_error_log_optimizer.source |   4 +-
 src/test/regress/sql/gporca.sql                    |  50 ++++
 33 files changed, 1759 insertions(+), 14 deletions(-)

diff --git a/src/backend/gpopt/translate/CTranslatorDXLToScalar.cpp 
b/src/backend/gpopt/translate/CTranslatorDXLToScalar.cpp
index 13f626c561..d9e002992c 100644
--- a/src/backend/gpopt/translate/CTranslatorDXLToScalar.cpp
+++ b/src/backend/gpopt/translate/CTranslatorDXLToScalar.cpp
@@ -56,6 +56,7 @@ extern "C" {
 #include "naucrates/dxl/operators/CDXLScalarCoerceToDomain.h"
 #include "naucrates/dxl/operators/CDXLScalarCoerceViaIO.h"
 #include "naucrates/dxl/operators/CDXLScalarDistinctComp.h"
+#include "naucrates/dxl/operators/CDXLScalarFieldSelect.h"
 #include "naucrates/dxl/operators/CDXLScalarFuncExpr.h"
 #include "naucrates/dxl/operators/CDXLScalarIfStmt.h"
 #include "naucrates/dxl/operators/CDXLScalarMinMax.h"
@@ -216,6 +217,10 @@ CTranslatorDXLToScalar::TranslateDXLToScalar(const 
CDXLNode *dxlnode,
                {
                        return TranslateDXLScalarArrayRefToScalar(dxlnode, 
colid_var);
                }
+               case EdxlopScalarFieldSelect:
+               {
+                       return TranslateDXLFieldSelectToScalar(dxlnode, 
colid_var);
+               }
                case EdxlopScalarDMLAction:
                {
                        return TranslateDXLScalarDMLActionToScalar(dxlnode, 
colid_var);
@@ -2123,6 +2128,37 @@ 
CTranslatorDXLToScalar::TranslateDXLScalarArrayRefToScalar(
        return (Expr *) array_ref;
 }
 
+//---------------------------------------------------------------------------
+//     @function:
+//             CTranslatorDXLToScalar::TranslateDXLFieldSelectToScalar
+//
+//     @doc:
+//             Translates a DXL Scalar FieldSelect into a GPDB FieldSelect node
+//
+//---------------------------------------------------------------------------
+Expr *
+CTranslatorDXLToScalar::TranslateDXLFieldSelectToScalar(
+       const CDXLNode *scalar_field_select, CMappingColIdVar *colid_var)
+{
+       GPOS_ASSERT(nullptr != scalar_field_select);
+
+       CDXLScalarFieldSelect *dxlop =
+               CDXLScalarFieldSelect::Cast(scalar_field_select->GetOperator());
+
+       FieldSelect *fieldSelect = MakeNode(FieldSelect);
+
+       fieldSelect->arg =
+               TranslateDXLToScalar((*scalar_field_select)[0], colid_var);
+       fieldSelect->fieldnum = dxlop->GetDXLFieldNumber();
+       fieldSelect->resulttype =
+               CMDIdGPDB::CastMdid(dxlop->GetDXLFieldType())->Oid();
+       fieldSelect->resulttypmod = dxlop->GetDXLTypeModifier();
+       fieldSelect->resultcollid =
+               CMDIdGPDB::CastMdid(dxlop->GetDXLFieldCollation())->Oid();
+
+       return (Expr *) fieldSelect;
+}
+
 //---------------------------------------------------------------------------
 //     @function:
 //             CTranslatorDXLToScalar::TranslateDXLArrayRefIndexListToScalar
diff --git a/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp 
b/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp
index 4e58884fe9..48e34a3119 100644
--- a/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp
+++ b/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp
@@ -295,7 +295,6 @@ CTranslatorQueryToDXL::CheckUnsupportedNodeTypes(Query 
*query)
        static const SUnsupportedFeature unsupported_features[] = {
                {T_RowExpr, GPOS_WSZ_LIT("ROW EXPRESSION")},
                {T_RowCompareExpr, GPOS_WSZ_LIT("ROW COMPARE")},
-               {T_FieldSelect, GPOS_WSZ_LIT("FIELDSELECT")},
                {T_FieldStore, GPOS_WSZ_LIT("FIELDSTORE")},
                {T_CoerceToDomainValue, GPOS_WSZ_LIT("COERCETODOMAINVALUE")},
                {T_GroupId, GPOS_WSZ_LIT("GROUPID")},
diff --git a/src/backend/gpopt/translate/CTranslatorScalarToDXL.cpp 
b/src/backend/gpopt/translate/CTranslatorScalarToDXL.cpp
index c934cab4e1..5a7a7f94e5 100644
--- a/src/backend/gpopt/translate/CTranslatorScalarToDXL.cpp
+++ b/src/backend/gpopt/translate/CTranslatorScalarToDXL.cpp
@@ -55,6 +55,7 @@ extern "C" {
 #include "naucrates/dxl/operators/CDXLScalarCoerceToDomain.h"
 #include "naucrates/dxl/operators/CDXLScalarCoerceViaIO.h"
 #include "naucrates/dxl/operators/CDXLScalarDistinctComp.h"
+#include "naucrates/dxl/operators/CDXLScalarFieldSelect.h"
 #include "naucrates/dxl/operators/CDXLScalarFilter.h"
 #include "naucrates/dxl/operators/CDXLScalarFuncExpr.h"
 #include "naucrates/dxl/operators/CDXLScalarIdent.h"
@@ -419,6 +420,11 @@ CTranslatorScalarToDXL::TranslateScalarToDXL(
                        return 
CTranslatorScalarToDXL::TranslateSortGroupClauseToDXL(
                                expr, var_colid_mapping);
                }
+               case T_FieldSelect:
+               {
+                       return 
CTranslatorScalarToDXL::TranslateFieldSelectToDXL(
+                               expr, var_colid_mapping);
+               }
        }
 }
 
@@ -1299,6 +1305,39 @@ CTranslatorScalarToDXL::TranslateArrayCoerceExprToDXL(
        return dxlnode;
 }
 
+//---------------------------------------------------------------------------
+//     @function:
+//             CTranslatorScalarToDXL::TranslateFieldSelectToDXL
+//
+//     @doc:
+//             Create a DXL node for a scalar FieldSelect from a GPDB 
FieldSelect
+//---------------------------------------------------------------------------
+CDXLNode *
+CTranslatorScalarToDXL::TranslateFieldSelectToDXL(
+       const Expr *expr, const CMappingVarColId *var_colid_mapping)
+{
+       GPOS_ASSERT(IsA(expr, FieldSelect));
+
+       const FieldSelect *fieldselect = (FieldSelect *) expr;
+       GPOS_ASSERT(nullptr != fieldselect->arg);
+
+       CDXLNode *child_node =
+               TranslateScalarToDXL(fieldselect->arg, var_colid_mapping);
+       GPOS_ASSERT(nullptr != child_node);
+
+       // create the DXL node holding the scalar boolean operator
+       CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(
+               m_mp, GPOS_NEW(m_mp) CDXLScalarFieldSelect(
+                                 m_mp,
+                                 GPOS_NEW(m_mp)
+                                         CMDIdGPDB(IMDId::EmdidGeneral, 
fieldselect->resulttype),
+                                 GPOS_NEW(m_mp)
+                                         CMDIdGPDB(IMDId::EmdidGeneral, 
fieldselect->resultcollid),
+                                 fieldselect->resulttypmod, 
fieldselect->fieldnum));
+
+       dxlnode->AddChild(child_node);
+       return dxlnode;
+}
 
 
 //---------------------------------------------------------------------------
diff --git a/src/backend/gporca/data/dxl/minidump/FieldSelect.mdp 
b/src/backend/gporca/data/dxl/minidump/FieldSelect.mdp
new file mode 100644
index 0000000000..1edd3f9a32
--- /dev/null
+++ b/src/backend/gporca/data/dxl/minidump/FieldSelect.mdp
@@ -0,0 +1,323 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dxl:DXLMessage xmlns:dxl="http://greenplum.com/dxl/2010/12/";>
+  <dxl:Comment><![CDATA[
+     Objective:Orca should generate a plan when extracting a field from a 
composite datatype
+     setup:
+       CREATE TYPE inventory_item AS (name text, supplier_id integer, price 
numeric);
+       CREATE TABLE foo (item inventory_item, count integer);
+       INSERT INTO foo VALUES (ROW('fuzzy dice', 42, 1.99), 1000);
+       explain select (item).name from foo where (item).price > 0;
+                                     QUERY PLAN
+       
------------------------------------------------------------------------------
+       Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 
width=8)
+         ->  Seq Scan on foo  (cost=0.00..431.00 rows=1 width=8)
+               Filter: ((item).price > '0'::numeric)
+       Optimizer: Pivotal Optimizer (GPORCA)
+   ]]>
+  </dxl:Comment>
+  <dxl:Thread Id="0">
+    <dxl:OptimizerConfig>
+      <dxl:EnumeratorConfig Id="0" PlanSamples="0" CostThreshold="0"/>
+      <dxl:StatisticsConfig DampingFactorFilter="0.750000" 
DampingFactorJoin="0.000000" DampingFactorGroupBy="0.750000" 
MaxStatsBuckets="100"/>
+      <dxl:CTEConfig CTEInliningCutoff="0"/>
+      <dxl:WindowOids RowNumber="3100" Rank="3101"/>
+      <dxl:CostModelConfig CostModelType="1" SegmentsForCosting="3">
+        <dxl:CostParams>
+          <dxl:CostParam Name="NLJFactor" Value="1024.000000" 
LowerBound="1023.500000" UpperBound="1024.500000"/>
+        </dxl:CostParams>
+      </dxl:CostModelConfig>
+      <dxl:Hint JoinArityForAssociativityCommutativity="18" 
ArrayExpansionThreshold="20" JoinOrderDynamicProgThreshold="10" 
BroadcastThreshold="100000" EnforceConstraintsOnDML="false" 
PushGroupByBelowSetopThreshold="10" XformBindThreshold="0" SkewFactor="0"/>
+      <dxl:TraceFlags 
Value="101013,102001,102002,102003,102043,102074,102120,102144,102162,102163,103001,103014,103022,103026,103027,103029,103033,103038,103040,104002,104003,104004,104005,106000"/>
+    </dxl:OptimizerConfig>
+    <dxl:Metadata SystemIds="0.GPDB">
+      <dxl:Type Mdid="0.16.1.0" Name="bool" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="1" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.2222.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7124.1.0"/>
+        <dxl:PartOpfamily Mdid="0.424.1.0"/>
+        <dxl:EqualityOp Mdid="0.91.1.0"/>
+        <dxl:InequalityOp Mdid="0.85.1.0"/>
+        <dxl:LessThanOp Mdid="0.58.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.1694.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.59.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.1695.1.0"/>
+        <dxl:ComparisonOp Mdid="0.1693.1.0"/>
+        <dxl:ArrayType Mdid="0.1000.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.23.1.0" Name="int4" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7100.1.0"/>
+        <dxl:PartOpfamily Mdid="0.1976.1.0"/>
+        <dxl:EqualityOp Mdid="0.96.1.0"/>
+        <dxl:InequalityOp Mdid="0.518.1.0"/>
+        <dxl:LessThanOp Mdid="0.97.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.523.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.521.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.525.1.0"/>
+        <dxl:ComparisonOp Mdid="0.351.1.0"/>
+        <dxl:ArrayType Mdid="0.1007.1.0"/>
+        <dxl:MinAgg Mdid="0.2132.1.0"/>
+        <dxl:MaxAgg Mdid="0.2116.1.0"/>
+        <dxl:AvgAgg Mdid="0.2101.1.0"/>
+        <dxl:SumAgg Mdid="0.2108.1.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.25.1.0" Name="text" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="true" IsFixedLength="false" Length="-1" PassByValue="false">
+        <dxl:DistrOpfamily Mdid="0.1995.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7105.1.0"/>
+        <dxl:PartOpfamily Mdid="0.1994.1.0"/>
+        <dxl:EqualityOp Mdid="0.98.1.0"/>
+        <dxl:InequalityOp Mdid="0.531.1.0"/>
+        <dxl:LessThanOp Mdid="0.664.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.665.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.666.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.667.1.0"/>
+        <dxl:ComparisonOp Mdid="0.360.1.0"/>
+        <dxl:ArrayType Mdid="0.1009.1.0"/>
+        <dxl:MinAgg Mdid="0.2145.1.0"/>
+        <dxl:MaxAgg Mdid="0.2129.1.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.26.1.0" Name="oid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.1990.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7109.1.0"/>
+        <dxl:PartOpfamily Mdid="0.1989.1.0"/>
+        <dxl:EqualityOp Mdid="0.607.1.0"/>
+        <dxl:InequalityOp Mdid="0.608.1.0"/>
+        <dxl:LessThanOp Mdid="0.609.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.611.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.610.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.612.1.0"/>
+        <dxl:ComparisonOp Mdid="0.356.1.0"/>
+        <dxl:ArrayType Mdid="0.1028.1.0"/>
+        <dxl:MinAgg Mdid="0.2134.1.0"/>
+        <dxl:MaxAgg Mdid="0.2118.1.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.27.1.0" Name="tid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="6" PassByValue="false">
+        <dxl:DistrOpfamily Mdid="0.2227.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7110.1.0"/>
+        <dxl:PartOpfamily Mdid="0.2789.1.0"/>
+        <dxl:EqualityOp Mdid="0.387.1.0"/>
+        <dxl:InequalityOp Mdid="0.402.1.0"/>
+        <dxl:LessThanOp Mdid="0.2799.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.2801.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.2800.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.2802.1.0"/>
+        <dxl:ComparisonOp Mdid="0.2794.1.0"/>
+        <dxl:ArrayType Mdid="0.1010.1.0"/>
+        <dxl:MinAgg Mdid="0.2798.1.0"/>
+        <dxl:MaxAgg Mdid="0.2797.1.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.29.1.0" Name="cid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="false" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.2226.1.0"/>
+        <dxl:EqualityOp Mdid="0.385.1.0"/>
+        <dxl:InequalityOp Mdid="0.0.0.0"/>
+        <dxl:LessThanOp Mdid="0.0.0.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:ComparisonOp Mdid="0.0.0.0"/>
+        <dxl:ArrayType Mdid="0.1012.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.28.1.0" Name="xid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="false" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.2225.1.0"/>
+        <dxl:EqualityOp Mdid="0.352.1.0"/>
+        <dxl:InequalityOp Mdid="0.3315.1.0"/>
+        <dxl:LessThanOp Mdid="0.0.0.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:ComparisonOp Mdid="0.0.0.0"/>
+        <dxl:ArrayType Mdid="0.1011.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.17310.1.0" Name="inventory_item" 
IsRedistributable="false" IsHashable="false" IsMergeJoinable="true" 
IsComposite="true" BaseRelationMdid="6.17308.1.0" IsTextRelated="false" 
IsFixedLength="false" Length="-1" PassByValue="false">
+        <dxl:PartOpfamily Mdid="0.2994.1.0"/>
+        <dxl:EqualityOp Mdid="0.2988.1.0"/>
+        <dxl:InequalityOp Mdid="0.2989.1.0"/>
+        <dxl:LessThanOp Mdid="0.2990.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.2992.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.2991.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.2993.1.0"/>
+        <dxl:ComparisonOp Mdid="0.2987.1.0"/>
+        <dxl:ArrayType Mdid="0.17309.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.1700.1.0" Name="numeric" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="false" Length="-1" PassByValue="false">
+        <dxl:DistrOpfamily Mdid="0.1998.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7103.1.0"/>
+        <dxl:PartOpfamily Mdid="0.1988.1.0"/>
+        <dxl:EqualityOp Mdid="0.1752.1.0"/>
+        <dxl:InequalityOp Mdid="0.1753.1.0"/>
+        <dxl:LessThanOp Mdid="0.1754.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.1755.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.1756.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.1757.1.0"/>
+        <dxl:ComparisonOp Mdid="0.1769.1.0"/>
+        <dxl:ArrayType Mdid="0.1231.1.0"/>
+        <dxl:MinAgg Mdid="0.2146.1.0"/>
+        <dxl:MaxAgg Mdid="0.2130.1.0"/>
+        <dxl:AvgAgg Mdid="0.2103.1.0"/>
+        <dxl:SumAgg Mdid="0.2114.1.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:RelationStatistics Mdid="2.17311.1.0" Name="foo" Rows="0.000000" 
RelPages="0" RelAllVisible="0" EmptyRelation="true"/>
+      <dxl:Relation Mdid="6.17311.1.0" Name="foo" IsTemporary="false" 
StorageType="Heap" DistributionPolicy="Hash" DistributionColumns="1" Keys="8,2">
+        <dxl:Columns>
+          <dxl:Column Name="item" Attno="1" Mdid="0.17310.1.0" Nullable="true" 
ColWidth="8"/>
+          <dxl:Column Name="count" Attno="2" Mdid="0.23.1.0" Nullable="true" 
ColWidth="4"/>
+          <dxl:Column Name="ctid" Attno="-1" Mdid="0.27.1.0" Nullable="false" 
ColWidth="6"/>
+          <dxl:Column Name="xmin" Attno="-2" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4"/>
+          <dxl:Column Name="cmin" Attno="-3" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4"/>
+          <dxl:Column Name="xmax" Attno="-4" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4"/>
+          <dxl:Column Name="cmax" Attno="-5" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4"/>
+          <dxl:Column Name="tableoid" Attno="-6" Mdid="0.26.1.0" 
Nullable="false" ColWidth="4"/>
+          <dxl:Column Name="gp_segment_id" Attno="-7" Mdid="0.23.1.0" 
Nullable="false" ColWidth="4"/>
+        </dxl:Columns>
+        <dxl:IndexInfoList/>
+        <dxl:CheckConstraints/>
+        <dxl:DistrOpfamilies>
+          <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        </dxl:DistrOpfamilies>
+      </dxl:Relation>
+      <dxl:ColumnStatistics Mdid="1.17311.1.0.1" Name="count" Width="4.000000" 
NullFreq="0.000000" NdvRemain="0.000000" FreqRemain="0.000000" 
ColStatsMissing="true"/>
+      <dxl:ColumnStatistics Mdid="1.17311.1.0.0" Name="item" Width="8.000000" 
NullFreq="0.000000" NdvRemain="0.000000" FreqRemain="0.000000" 
ColStatsMissing="true"/>
+      <dxl:RelationExtendedStatistics Mdid="10.17311.1.0" Name="foo"/>
+      <dxl:GPDBScalarOp Mdid="0.1756.1.0" Name="&gt;" ComparisonType="GT" 
ReturnsNullOnNullInput="true" IsNDVPreserving="false">
+        <dxl:LeftType Mdid="0.1700.1.0"/>
+        <dxl:RightType Mdid="0.1700.1.0"/>
+        <dxl:ResultType Mdid="0.16.1.0"/>
+        <dxl:OpFunc Mdid="0.1720.1.0"/>
+        <dxl:Commutator Mdid="0.1754.1.0"/>
+        <dxl:InverseOp Mdid="0.1755.1.0"/>
+        <dxl:Opfamilies>
+          <dxl:Opfamily Mdid="0.1988.1.0"/>
+          <dxl:Opfamily Mdid="0.4055.1.0"/>
+          <dxl:Opfamily Mdid="0.10013.1.0"/>
+        </dxl:Opfamilies>
+      </dxl:GPDBScalarOp>
+    </dxl:Metadata>
+    <dxl:Query>
+      <dxl:OutputColumns>
+        <dxl:Ident ColId="10" ColName="name" TypeMdid="0.25.1.0"/>
+      </dxl:OutputColumns>
+      <dxl:CTEList/>
+      <dxl:LogicalProject>
+        <dxl:ProjList>
+          <dxl:ProjElem ColId="10" Alias="name">
+            <dxl:FIELDSELECT FieldType="0.25.1.0" FieldCollation="0.100.1.0" 
TypeModifier="-1" FieldNumber="1">
+              <dxl:Ident ColId="1" ColName="item" TypeMdid="0.17310.1.0"/>
+            </dxl:FIELDSELECT>
+          </dxl:ProjElem>
+        </dxl:ProjList>
+        <dxl:LogicalSelect>
+          <dxl:Comparison ComparisonOperator="&gt;" OperatorMdid="0.1756.1.0">
+            <dxl:FIELDSELECT FieldType="0.1700.1.0" FieldCollation="0.0.0.0" 
TypeModifier="-1" FieldNumber="3">
+              <dxl:Ident ColId="1" ColName="item" TypeMdid="0.17310.1.0"/>
+            </dxl:FIELDSELECT>
+            <dxl:ConstValue TypeMdid="0.1700.1.0" Value="AAAABgCA" 
DoubleValue="0.000000"/>
+          </dxl:Comparison>
+          <dxl:LogicalGet>
+            <dxl:TableDescriptor Mdid="6.17311.1.0" TableName="foo" 
LockMode="1" AclMode="2">
+              <dxl:Columns>
+                <dxl:Column ColId="1" Attno="1" ColName="item" 
TypeMdid="0.17310.1.0" ColWidth="8"/>
+                <dxl:Column ColId="2" Attno="2" ColName="count" 
TypeMdid="0.23.1.0" ColWidth="4"/>
+                <dxl:Column ColId="3" Attno="-1" ColName="ctid" 
TypeMdid="0.27.1.0" ColWidth="6"/>
+                <dxl:Column ColId="4" Attno="-2" ColName="xmin" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+                <dxl:Column ColId="5" Attno="-3" ColName="cmin" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+                <dxl:Column ColId="6" Attno="-4" ColName="xmax" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+                <dxl:Column ColId="7" Attno="-5" ColName="cmax" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+                <dxl:Column ColId="8" Attno="-6" ColName="tableoid" 
TypeMdid="0.26.1.0" ColWidth="4"/>
+                <dxl:Column ColId="9" Attno="-7" ColName="gp_segment_id" 
TypeMdid="0.23.1.0" ColWidth="4"/>
+              </dxl:Columns>
+            </dxl:TableDescriptor>
+          </dxl:LogicalGet>
+        </dxl:LogicalSelect>
+      </dxl:LogicalProject>
+    </dxl:Query>
+    <dxl:Plan Id="0" SpaceSize="2">
+      <dxl:GatherMotion InputSegments="0,1,2" OutputSegments="-1">
+        <dxl:Properties>
+          <dxl:Cost StartupCost="0" TotalCost="431.000056" Rows="1.000000" 
Width="8"/>
+        </dxl:Properties>
+        <dxl:ProjList>
+          <dxl:ProjElem ColId="9" Alias="name">
+            <dxl:Ident ColId="9" ColName="name" TypeMdid="0.25.1.0"/>
+          </dxl:ProjElem>
+        </dxl:ProjList>
+        <dxl:Filter/>
+        <dxl:SortingColumnList/>
+        <dxl:Result>
+          <dxl:Properties>
+            <dxl:Cost StartupCost="0" TotalCost="431.000026" Rows="1.000000" 
Width="8"/>
+          </dxl:Properties>
+          <dxl:ProjList>
+            <dxl:ProjElem ColId="9" Alias="name">
+              <dxl:FIELDSELECT FieldType="0.25.1.0" FieldCollation="0.100.1.0" 
TypeModifier="-1" FieldNumber="1">
+                <dxl:Ident ColId="0" ColName="item" TypeMdid="0.17310.1.0"/>
+              </dxl:FIELDSELECT>
+            </dxl:ProjElem>
+          </dxl:ProjList>
+          <dxl:Filter/>
+          <dxl:OneTimeFilter/>
+          <dxl:TableScan>
+            <dxl:Properties>
+              <dxl:Cost StartupCost="0" TotalCost="431.000024" Rows="1.000000" 
Width="8"/>
+            </dxl:Properties>
+            <dxl:ProjList>
+              <dxl:ProjElem ColId="0" Alias="item">
+                <dxl:Ident ColId="0" ColName="item" TypeMdid="0.17310.1.0"/>
+              </dxl:ProjElem>
+            </dxl:ProjList>
+            <dxl:Filter>
+              <dxl:Comparison ComparisonOperator="&gt;" 
OperatorMdid="0.1756.1.0">
+                <dxl:FIELDSELECT FieldType="0.1700.1.0" 
FieldCollation="0.0.0.0" TypeModifier="-1" FieldNumber="3">
+                  <dxl:Ident ColId="0" ColName="item" TypeMdid="0.17310.1.0"/>
+                </dxl:FIELDSELECT>
+                <dxl:ConstValue TypeMdid="0.1700.1.0" Value="AAAABgCA" 
DoubleValue="0.000000"/>
+              </dxl:Comparison>
+            </dxl:Filter>
+            <dxl:TableDescriptor Mdid="6.17311.1.0" TableName="foo" 
LockMode="1" AclMode="2">
+              <dxl:Columns>
+                <dxl:Column ColId="0" Attno="1" ColName="item" 
TypeMdid="0.17310.1.0" ColWidth="8"/>
+                <dxl:Column ColId="1" Attno="2" ColName="count" 
TypeMdid="0.23.1.0" ColWidth="4"/>
+                <dxl:Column ColId="2" Attno="-1" ColName="ctid" 
TypeMdid="0.27.1.0" ColWidth="6"/>
+                <dxl:Column ColId="3" Attno="-2" ColName="xmin" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+                <dxl:Column ColId="4" Attno="-3" ColName="cmin" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+                <dxl:Column ColId="5" Attno="-4" ColName="xmax" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+                <dxl:Column ColId="6" Attno="-5" ColName="cmax" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+                <dxl:Column ColId="7" Attno="-6" ColName="tableoid" 
TypeMdid="0.26.1.0" ColWidth="4"/>
+                <dxl:Column ColId="8" Attno="-7" ColName="gp_segment_id" 
TypeMdid="0.23.1.0" ColWidth="4"/>
+              </dxl:Columns>
+            </dxl:TableDescriptor>
+          </dxl:TableScan>
+        </dxl:Result>
+      </dxl:GatherMotion>
+    </dxl:Plan>
+  </dxl:Thread>
+</dxl:DXLMessage>
diff --git a/src/backend/gporca/libgpopt/include/gpopt/operators/COperator.h 
b/src/backend/gporca/libgpopt/include/gpopt/operators/COperator.h
index 0ec9dd213c..51ac8ddd8a 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/operators/COperator.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/operators/COperator.h
@@ -183,6 +183,8 @@ public:
                EopScalarBitmapIndexProbe,
                EopScalarBitmapBoolOp,
 
+               EopScalarFieldSelect,
+
                EopPhysicalTableScan,
                EopPhysicalForeignScan,
                EopPhysicalIndexScan,
diff --git 
a/src/backend/gporca/libgpopt/include/gpopt/operators/CScalarFieldSelect.h 
b/src/backend/gporca/libgpopt/include/gpopt/operators/CScalarFieldSelect.h
new file mode 100644
index 0000000000..d5c7955b5f
--- /dev/null
+++ b/src/backend/gporca/libgpopt/include/gpopt/operators/CScalarFieldSelect.h
@@ -0,0 +1,138 @@
+//---------------------------------------------------------------------------
+//     Greenplum Database
+//     Copyright (C) 2023 VMware, Inc. or its affiliates. All Rights Reserved.
+//
+//     @filename:
+//             CScalarFieldSelect.h
+//
+//     @doc:
+//             Class for representing FIELDSELECT
+//---------------------------------------------------------------------------
+
+#ifndef GPOPT_CSCALARFIELDSELECT_H
+#define GPOPT_CSCALARFIELDSELECT_H
+
+#include "gpos/base.h"
+
+#include "gpopt/operators/CScalar.h"
+#include "naucrates/md/IMDId.h"
+
+namespace gpopt
+{
+using namespace gpos;
+using namespace gpmd;
+
+//---------------------------------------------------------------------------
+//     @class:
+//             CScalarFieldSelect
+//
+//     @doc:
+//             Class for representing scalar FieldSelect
+//
+//---------------------------------------------------------------------------
+class CScalarFieldSelect : public CScalar
+{
+private:
+       // type of the field
+       IMDId *m_field_type;
+
+       // collation OID of the field
+       IMDId *m_field_collation;
+
+       // output typmod (usually -1)
+       INT m_type_modifier;
+
+       // attribute number of field to extract
+       SINT m_field_number;
+
+public:
+       CScalarFieldSelect(const CScalarFieldSelect &) = delete;
+
+       // ctor/dtor
+       CScalarFieldSelect(CMemoryPool *mp, IMDId *field_type,
+                                          IMDId *field_collation, INT 
type_modifier,
+                                          SINT field_number);
+
+       ~CScalarFieldSelect() override;
+
+       // ident accessors
+       EOperatorId
+       Eopid() const override
+       {
+               return EopScalarFieldSelect;
+       }
+
+       // operator name
+       const CHAR *
+       SzId() const override
+       {
+               return "CScalarFieldSelect";
+       }
+
+       // operator specific hash function
+       ULONG HashValue() const override;
+
+       // match function
+       BOOL Matches(COperator *pop) const override;
+
+
+       // mdid of the field
+       IMDId *
+       MdidType() const override
+       {
+               return m_field_type;
+       }
+
+       // field collation mdid
+       IMDId *
+       FieldCollation() const
+       {
+               return m_field_collation;
+       }
+
+       // output mode type
+       INT
+       TypeModifier() const override
+       {
+               return m_type_modifier;
+       }
+
+       // attribute number of field
+       SINT
+       FieldNumber() const
+       {
+               return m_field_number;
+       }
+
+       // conversion function
+       static CScalarFieldSelect *
+       PopConvert(COperator *pop)
+       {
+               GPOS_ASSERT(nullptr != pop);
+               GPOS_ASSERT(EopScalarFieldSelect == pop->Eopid());
+
+               return dynamic_cast<CScalarFieldSelect *>(pop);
+       }
+
+       // sensitivity to order of inputs
+       BOOL
+       FInputOrderSensitive() const override
+       {
+               return true;
+       }
+
+       // return a copy of the operator with remapped columns
+       COperator *
+       PopCopyWithRemappedColumns(CMemoryPool *,               //mp,
+                                                          UlongToColRefMap *,  
//colref_mapping,
+                                                          BOOL                 
                //must_exist
+                                                          ) override
+       {
+               return PopCopyDefault();
+       }
+};
+}  // namespace gpopt
+
+#endif // !GPDB_CSCALARFIELDSELECT_H
+
+// EOF
diff --git 
a/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorDXLToExpr.h 
b/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorDXLToExpr.h
index f1563a5014..71b073335c 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorDXLToExpr.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorDXLToExpr.h
@@ -321,6 +321,9 @@ private:
 
        CExpression *PexprSortGroupClause(const CDXLNode *pdxlnSortGroupClause);
 
+       // translate a DXL FieldSelect node into a FieldSelect expression
+       CExpression *PexprFieldSelect(const CDXLNode *pdxlnConst);
+
        // translate a DXL project list node into a project list expression
        CExpression *PexprScalarProjList(const CDXLNode *proj_list_dxlnode);
 
diff --git 
a/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h 
b/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h
index 89846a91b7..2b29de28d6 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h
@@ -511,6 +511,9 @@ private:
        // translate an arrayref
        CDXLNode *PdxlnArrayRef(CExpression *pexpr);
 
+       // translate a FieldSelect expr
+       CDXLNode *PdxlnFieldSelect(CExpression *pexpr);
+
        // translate an arrayref index list
        CDXLNode *PdxlnArrayRefIndexList(CExpression *pexpr);
 
diff --git a/src/backend/gporca/libgpopt/src/operators/CScalarFieldSelect.cpp 
b/src/backend/gporca/libgpopt/src/operators/CScalarFieldSelect.cpp
new file mode 100644
index 0000000000..d3fd3e1d34
--- /dev/null
+++ b/src/backend/gporca/libgpopt/src/operators/CScalarFieldSelect.cpp
@@ -0,0 +1,96 @@
+//---------------------------------------------------------------------------
+//     Greenplum Database
+//     Copyright (C) 2023 VMware, Inc. or its affiliates. All Rights Reserved.
+//
+//     @filename:
+//             CScalarFieldSelect.cpp
+//
+//     @doc:
+//             Implementation of scalar FIELDSELECT
+//---------------------------------------------------------------------------
+
+#include "gpopt/operators/CScalarFieldSelect.h"
+
+#include "gpos/base.h"
+
+using namespace gpopt;
+using namespace gpmd;
+
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CScalarFieldSelect::CScalarFieldSelect
+//
+//     @doc:
+//             Ctor
+//
+//---------------------------------------------------------------------------
+CScalarFieldSelect::CScalarFieldSelect(CMemoryPool *mp, IMDId *field_type,
+                                                                          
IMDId *field_collation,
+                                                                          INT 
type_modifier, SINT field_number)
+       : CScalar(mp),
+         m_field_type(field_type),
+         m_field_collation(field_collation),
+         m_type_modifier(type_modifier),
+         m_field_number(field_number)
+{
+       GPOS_ASSERT(m_field_type->IsValid());
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CScalarFieldSelect::~CScalarFieldSelect
+//
+//     @doc:
+//             Dtor
+//
+//---------------------------------------------------------------------------
+CScalarFieldSelect::~CScalarFieldSelect()
+{
+       m_field_type->Release();
+       m_field_collation->Release();
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CScalarFieldSelect::HashValue
+//
+//     @doc:
+//             Operator specific hash function
+//
+//---------------------------------------------------------------------------
+ULONG
+CScalarFieldSelect::HashValue() const
+{
+       return gpos::CombineHashes(
+               COperator::HashValue(),
+               CombineHashes(CombineHashes(m_field_type->HashValue(),
+                                                                       
m_field_collation->HashValue()),
+                                         
gpos::HashValue<SINT>(&m_field_number)));
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CScalarFieldSelect::Matches
+//
+//     @doc:
+//             Match function on operator level
+//
+//---------------------------------------------------------------------------
+BOOL
+CScalarFieldSelect::Matches(COperator *pop) const
+{
+       if (pop->Eopid() != Eopid())
+       {
+               return false;
+       }
+       CScalarFieldSelect *popFieldSelect = 
CScalarFieldSelect::PopConvert(pop);
+
+       // match attribute field number and type of the field
+       return popFieldSelect->MdidType()->Equals(MdidType()) &&
+                  popFieldSelect->FieldCollation()->Equals(FieldCollation()) &&
+                  popFieldSelect->FieldNumber() == FieldNumber();
+}
+
+
+// EOF
diff --git a/src/backend/gporca/libgpopt/src/operators/Makefile 
b/src/backend/gporca/libgpopt/src/operators/Makefile
index 28bf1f9e6b..97218fe075 100644
--- a/src/backend/gporca/libgpopt/src/operators/Makefile
+++ b/src/backend/gporca/libgpopt/src/operators/Makefile
@@ -163,6 +163,7 @@ OBJS        = CExpression.o \
               CScalarCoerceViaIO.o \
               CScalarConst.o \
               CScalarDMLAction.o \
+              CScalarFieldSelect.o \
               CScalarFunc.o \
               CScalarIdent.o \
               CScalarIf.o \
diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp 
b/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp
index 778b801f1c..347ae4227b 100644
--- a/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp
+++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp
@@ -58,6 +58,7 @@
 #include "gpopt/operators/CScalarCoalesce.h"
 #include "gpopt/operators/CScalarCoerceToDomain.h"
 #include "gpopt/operators/CScalarCoerceViaIO.h"
+#include "gpopt/operators/CScalarFieldSelect.h"
 #include "gpopt/operators/CScalarIdent.h"
 #include "gpopt/operators/CScalarIf.h"
 #include "gpopt/operators/CScalarIsDistinctFrom.h"
@@ -105,6 +106,7 @@
 #include "naucrates/dxl/operators/CDXLScalarCoerceToDomain.h"
 #include "naucrates/dxl/operators/CDXLScalarCoerceViaIO.h"
 #include "naucrates/dxl/operators/CDXLScalarDistinctComp.h"
+#include "naucrates/dxl/operators/CDXLScalarFieldSelect.h"
 #include "naucrates/dxl/operators/CDXLScalarFuncExpr.h"
 #include "naucrates/dxl/operators/CDXLScalarIdent.h"
 #include "naucrates/dxl/operators/CDXLScalarIfStmt.h"
@@ -2660,6 +2662,8 @@ CTranslatorDXLToExpr::PexprScalar(const CDXLNode *dxlnode)
                        return CTranslatorDXLToExpr::PexprValuesList(dxlnode);
                case EdxlopScalarSortGroupClause:
                        return 
CTranslatorDXLToExpr::PexprSortGroupClause(dxlnode);
+               case EdxlopScalarFieldSelect:
+                       return CTranslatorDXLToExpr::PexprFieldSelect(dxlnode);
                default:
                        GPOS_RAISE(gpopt::ExmaGPOPT, gpopt::ExmiUnsupportedOp,
                                           dxl_op->GetOpNameStr()->GetBuffer());
@@ -3330,6 +3334,35 @@ CTranslatorDXLToExpr::PexprValuesList(const CDXLNode 
*dxlnode)
                CExpression(m_mp, popScalarValuesList, pdrgpexprChildren);
 }
 
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CTranslatorDXLToExpr::PexprFieldSelect
+//
+//     @doc:
+//             Create a scalar FieldSelect operator expression from a DXL 
FieldSelect node
+//
+//---------------------------------------------------------------------------
+CExpression *
+CTranslatorDXLToExpr::PexprFieldSelect(const CDXLNode *dxlnode)
+{
+       CDXLScalarFieldSelect *dxl_op =
+               CDXLScalarFieldSelect::Cast(dxlnode->GetOperator());
+
+       IMDId *field_type = dxl_op->GetDXLFieldType();
+       field_type->AddRef();
+       IMDId *field_collation = dxl_op->GetDXLFieldCollation();
+       field_collation->AddRef();
+       INT type_modifier = dxl_op->GetDXLTypeModifier();
+       SINT field_number = dxl_op->GetDXLFieldNumber();
+
+       CScalarFieldSelect *popFieldSelect = GPOS_NEW(m_mp) CScalarFieldSelect(
+               m_mp, field_type, field_collation, type_modifier, field_number);
+       CExpressionArray *pdrgpexprChildren = PdrgpexprChildren(dxlnode);
+
+       return GPOS_NEW(m_mp) CExpression(m_mp, popFieldSelect, 
pdrgpexprChildren);
+}
+
 //---------------------------------------------------------------------------
 //     @function:
 //             CTranslatorDXLToExpr::PexprArrayRefIndexList
diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp 
b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
index 6105af847c..0d757f0f77 100644
--- a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
+++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
@@ -80,6 +80,7 @@
 #include "gpopt/operators/CScalarCoalesce.h"
 #include "gpopt/operators/CScalarCoerceToDomain.h"
 #include "gpopt/operators/CScalarCoerceViaIO.h"
+#include "gpopt/operators/CScalarFieldSelect.h"
 #include "gpopt/operators/CScalarIdent.h"
 #include "gpopt/operators/CScalarIf.h"
 #include "gpopt/operators/CScalarIsDistinctFrom.h"
@@ -145,6 +146,7 @@
 #include "naucrates/dxl/operators/CDXLScalarComp.h"
 #include "naucrates/dxl/operators/CDXLScalarDMLAction.h"
 #include "naucrates/dxl/operators/CDXLScalarDistinctComp.h"
+#include "naucrates/dxl/operators/CDXLScalarFieldSelect.h"
 #include "naucrates/dxl/operators/CDXLScalarFuncExpr.h"
 #include "naucrates/dxl/operators/CDXLScalarHashCondList.h"
 #include "naucrates/dxl/operators/CDXLScalarHashExpr.h"
@@ -645,6 +647,8 @@ CTranslatorExprToDXL::PdxlnScalar(CExpression *pexpr)
                        return CTranslatorExprToDXL::PdxlnArrayCmp(pexpr);
                case COperator::EopScalarArrayRef:
                        return CTranslatorExprToDXL::PdxlnArrayRef(pexpr);
+               case COperator::EopScalarFieldSelect:
+                       return CTranslatorExprToDXL::PdxlnFieldSelect(pexpr);
                case COperator::EopScalarArrayRefIndexList:
                        return 
CTranslatorExprToDXL::PdxlnArrayRefIndexList(pexpr);
                case COperator::EopScalarAssertConstraintList:
@@ -6548,6 +6552,36 @@ CTranslatorExprToDXL::PdxlnArrayRef(CExpression *pexpr)
        return pdxlnArrayref;
 }
 
+//---------------------------------------------------------------------------
+//     @function:
+//             CTranslatorExprToDXL::PdxlnFieldSelect
+//
+//     @doc:
+//             Create a DXL FieldSelect node from an optimizer FieldSelect 
expression
+//
+//---------------------------------------------------------------------------
+CDXLNode *
+CTranslatorExprToDXL::PdxlnFieldSelect(CExpression *pexpr)
+{
+       GPOS_ASSERT(nullptr != pexpr);
+       CScalarFieldSelect *pop = CScalarFieldSelect::PopConvert(pexpr->Pop());
+
+       IMDId *field_type = pop->MdidType();
+       field_type->AddRef();
+       IMDId *field_collation = pop->FieldCollation();
+       field_collation->AddRef();
+       INT type_modifier = pop->TypeModifier();
+       SINT field_number = pop->FieldNumber();
+
+       CDXLNode *pdxlnFieldSelect = GPOS_NEW(m_mp) CDXLNode(
+               m_mp,
+               GPOS_NEW(m_mp) CDXLScalarFieldSelect(m_mp, field_type, 
field_collation,
+                                                                               
         type_modifier, field_number));
+       TranslateScalarChildren(pexpr, pdxlnFieldSelect);
+
+       return pdxlnFieldSelect;
+}
+
 //---------------------------------------------------------------------------
 //     @function:
 //             CTranslatorExprToDXL::PdxlnArrayRefIndexList
diff --git 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLOperator.h
 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLOperator.h
index f168329935..220ad08437 100644
--- 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLOperator.h
+++ 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLOperator.h
@@ -68,6 +68,7 @@ enum Edxlopid
        EdxlopScalarHashCondList,
        EdxlopScalarArray,
        EdxlopScalarArrayRef,
+       EdxlopScalarFieldSelect,
        EdxlopScalarArrayRefIndexList,
 
        EdxlopScalarAssertConstraintList,
diff --git 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLOperatorFactory.h
 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLOperatorFactory.h
index e515c69b01..6ece3ce380 100644
--- 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLOperatorFactory.h
+++ 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLOperatorFactory.h
@@ -251,6 +251,10 @@ public:
        static CDXLScalar *MakeDXLArrayCoerceExpr(
                CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs);
 
+       // create a FieldSelectExpr
+       static CDXLScalar *MakeDXLFieldSelect(CDXLMemoryManager 
*dxl_memory_manager,
+                                                                               
  const Attributes &attrs);
+
        // create a scalar identifier operator
        static CDXLScalar *MakeDXLScalarIdent(CDXLMemoryManager 
*dxl_memory_manager,
                                                                                
  const Attributes &attrs);
diff --git 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLScalarFieldSelect.h
 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLScalarFieldSelect.h
new file mode 100644
index 0000000000..cd9996f952
--- /dev/null
+++ 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLScalarFieldSelect.h
@@ -0,0 +1,109 @@
+//---------------------------------------------------------------------------
+//     Greenplum Database
+//     Copyright (C) 2023 VMware, Inc. or its affiliates. All Rights Reserved.
+//
+//     @filename:
+//             CDXLScalarFieldSelect.cpp
+//
+//     @doc:
+//             Implementation of DXL Scalar FIELDSELECT operator
+//---------------------------------------------------------------------------
+
+#ifndef GPDXL_CDXLSCALARFIELDSELECT_H
+#define GPDXL_CDXLSCALARFIELDSELECT_H
+
+#include "gpos/base.h"
+
+#include "naucrates/dxl/operators/CDXLScalar.h"
+#include "naucrates/md/IMDId.h"
+
+namespace gpdxl
+{
+using namespace gpos;
+using namespace gpmd;
+
+//---------------------------------------------------------------------------
+//     @class:
+//             CDXLScalarAggref
+//
+//     @doc:
+//             Class for representing DXL FIELDSELECT
+//
+//---------------------------------------------------------------------------
+class CDXLScalarFieldSelect : public CDXLScalar
+{
+private:
+       // type of the field
+       IMDId *m_dxl_field_type;
+
+       // collation OID of the field
+       IMDId *m_dxl_field_collation;
+
+       // output typmod (usually -1)
+       INT m_dxl_type_modifier;
+
+       // attribute number of field to extract
+       SINT m_dxl_field_number;
+
+public:
+       CDXLScalarFieldSelect(const CDXLScalarFieldSelect &) = delete;
+
+       // ctor/dtor
+       CDXLScalarFieldSelect(CMemoryPool *mp, IMDId *field_type,
+                                                 IMDId *field_collation, INT 
type_modifier,
+                                                 SINT field_number);
+
+       ~CDXLScalarFieldSelect() override;
+
+       // ident accessors
+       Edxlopid GetDXLOperator() const override;
+
+       // DXL operator name
+       const CWStringConst *GetOpNameStr() const override;
+
+       // serialize operator in DXL format
+       void SerializeToDXL(CXMLSerializer *xml_serializer,
+                                               const CDXLNode *dxlnode) const 
override;
+
+       // mdid of the field
+       IMDId *GetDXLFieldType() const;
+
+       // collation mdid of the field
+       IMDId *GetDXLFieldCollation() const;
+
+       // output type mode
+       INT GetDXLTypeModifier() const;
+
+       // attribute number of the field
+       SINT GetDXLFieldNumber() const;
+
+       // conversion function
+       static CDXLScalarFieldSelect *
+       Cast(CDXLOperator *dxl_op)
+       {
+               GPOS_ASSERT(nullptr != dxl_op);
+               GPOS_ASSERT(EdxlopScalarFieldSelect == 
dxl_op->GetDXLOperator());
+
+               return dynamic_cast<CDXLScalarFieldSelect *>(dxl_op);
+       }
+
+       // does the operator return a boolean result
+       BOOL
+       HasBoolResult(CMDAccessor *      //md_accessor
+       ) const override
+       {
+               return true;
+       }
+
+#ifdef GPOS_DEBUG
+       // checks whether the operator has valid structure, i.e. number and
+       // types of child nodes
+       void AssertValid(const CDXLNode *dxlnode,
+                                        BOOL validate_children) const override;
+#endif // GPOS_DEBUG
+};
+}  // namespace gpdxl
+
+#endif // !GPDB_CDXLSCALARFIELDSELECT_H
+
+// EOF
diff --git 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerFactory.h
 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerFactory.h
index e322008906..c90ffedf16 100644
--- 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerFactory.h
+++ 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerFactory.h
@@ -401,6 +401,11 @@ private:
                CMemoryPool *mp, CParseHandlerManager *parse_handler_mgr,
                CParseHandlerBase *parse_handler_root);
 
+       // construct an FieldSelect parse handler
+       static CParseHandlerBase *CreateScalarFieldSelectParseHandler(
+               CMemoryPool *mp, CParseHandlerManager *parse_handler_mgr,
+               CParseHandlerBase *parse_handler_root);
+
        // construct an arrayref index list parse handler
        static CParseHandlerBase *CreateScArrayRefIdxListParseHandler(
                CMemoryPool *mp, CParseHandlerManager *parse_handler_mgr,
diff --git 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerScalarFieldSelect.h
 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerScalarFieldSelect.h
new file mode 100644
index 0000000000..86b14d9ce9
--- /dev/null
+++ 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerScalarFieldSelect.h
@@ -0,0 +1,66 @@
+//---------------------------------------------------------------------------
+//     Greenplum Database
+//     Copyright (C) 2023 VMware, Inc. or its affiliates. All Rights Reserved.
+//
+//     @filename:
+//             CParseHandlerScalarFieldSelect.h
+//
+//     @doc:
+//             SAX parse handler class for parsing scalar FieldSelect operator 
nodes
+//---------------------------------------------------------------------------
+
+#ifndef GPDXL_CParseHandlerScalarFieldSelect_H
+#define GPDXL_CParseHandlerScalarFieldSelect_H
+
+#include "gpos/base.h"
+
+#include "naucrates/dxl/operators/CDXLScalarFieldSelect.h"
+#include "naucrates/dxl/parser/CParseHandlerScalarOp.h"
+
+namespace gpdxl
+{
+using namespace gpos;
+
+XERCES_CPP_NAMESPACE_USE
+
+//---------------------------------------------------------------------------
+//     @class:
+//             CParseHandlerScalarFieldSelect
+//
+//     @doc:
+//             Parse handler class for parsing scalar FieldSelect
+//
+//---------------------------------------------------------------------------
+class CParseHandlerScalarFieldSelect : public CParseHandlerScalarOp
+{
+private:
+       // process the start of an element
+       void StartElement(
+               const XMLCh *const element_uri,                 // URI of 
element's namespace
+               const XMLCh *const element_local_name,  // local part of 
element's name
+               const XMLCh *const element_qname,               // element's 
qname
+               const Attributes &attr                                  // 
element's attributes
+               ) override;
+
+       // process the end of an element
+       void EndElement(
+               const XMLCh *const element_uri,                 // URI of 
element's namespace
+               const XMLCh *const element_local_name,  // local part of 
element's name
+               const XMLCh *const element_qname                // element's 
qname
+               ) override;
+
+public:
+       CParseHandlerScalarFieldSelect(const CParseHandlerScalarFieldSelect &) =
+               delete;
+
+       // ctor/dtor
+       CParseHandlerScalarFieldSelect(CMemoryPool *mp,
+                                                                  
CParseHandlerManager *parse_handler_mgr,
+                                                                  
CParseHandlerBase *parse_handler_root);
+       ~CParseHandlerScalarFieldSelect() override = default;
+};
+}  // namespace gpdxl
+
+#endif // !GPDXL_CParseHandlerScalarFieldSelect_H
+
+// EOF
diff --git 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/parsehandlers.h 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/parsehandlers.h
index b53f3bce15..909bc3cae3 100644
--- 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/parsehandlers.h
+++ 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/parsehandlers.h
@@ -140,6 +140,7 @@
 #include "naucrates/dxl/parser/CParseHandlerScalarConstValue.h"
 #include "naucrates/dxl/parser/CParseHandlerScalarDMLAction.h"
 #include "naucrates/dxl/parser/CParseHandlerScalarExpr.h"
+#include "naucrates/dxl/parser/CParseHandlerScalarFieldSelect.h"
 #include "naucrates/dxl/parser/CParseHandlerScalarFuncExpr.h"
 #include "naucrates/dxl/parser/CParseHandlerScalarIdent.h"
 #include "naucrates/dxl/parser/CParseHandlerScalarIfStmt.h"
diff --git 
a/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h 
b/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h
index b7485b28d4..8812a65170 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h
@@ -268,6 +268,13 @@ enum Edxltoken
        EdxltokenWindowrefStageRowKey,
        EdxltokenWindowrefWinSpecPos,
 
+       // FIELDSELECT
+       EdxltokenScalarFieldSelect,
+       EdxltokenScalarFieldSelectFieldType,
+       EdxltokenScalarFieldSelectFieldCollation,
+       EdxltokenScalarFieldSelectFieldNumber,
+       EdxltokenScalarFieldSelectTypeModifier,
+
        EdxltokenValue,
        EdxltokenTypeId,
        EdxltokenTypeIds,
diff --git 
a/src/backend/gporca/libnaucrates/src/operators/CDXLOperatorFactory.cpp 
b/src/backend/gporca/libnaucrates/src/operators/CDXLOperatorFactory.cpp
index 22ca4ac142..e787b192ab 100644
--- a/src/backend/gporca/libnaucrates/src/operators/CDXLOperatorFactory.cpp
+++ b/src/backend/gporca/libnaucrates/src/operators/CDXLOperatorFactory.cpp
@@ -52,6 +52,7 @@
 #include "naucrates/dxl/operators/CDXLScalarCoerceViaIO.h"
 #include "naucrates/dxl/operators/CDXLScalarComp.h"
 #include "naucrates/dxl/operators/CDXLScalarDistinctComp.h"
+#include "naucrates/dxl/operators/CDXLScalarFieldSelect.h"
 #include "naucrates/dxl/operators/CDXLScalarFuncExpr.h"
 #include "naucrates/dxl/operators/CDXLScalarHashExpr.h"
 #include "naucrates/dxl/operators/CDXLScalarIdent.h"
@@ -965,6 +966,37 @@ CDXLOperatorFactory::MakeDXLArrayCoerceExpr(
                                                                  
(EdxlCoercionForm) coercion_form, location);
 }
 
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLOperatorFactory::MakeDXLFieldSelectExpr
+//
+//     @doc:
+//             Construct a scalar FieldSelect expression
+//
+//---------------------------------------------------------------------------
+CDXLScalar *
+CDXLOperatorFactory::MakeDXLFieldSelect(CDXLMemoryManager *dxl_memory_manager,
+                                                                               
const Attributes &attrs)
+{
+       CMemoryPool *mp = dxl_memory_manager->Pmp();
+
+       IMDId *field_type = ExtractConvertAttrValueToMdId(
+               dxl_memory_manager, attrs, EdxltokenScalarFieldSelectFieldType,
+               EdxltokenScalarFieldSelect);
+       IMDId *field_collation = ExtractConvertAttrValueToMdId(
+               dxl_memory_manager, attrs, 
EdxltokenScalarFieldSelectFieldCollation,
+               EdxltokenScalarFieldSelect);
+       INT type_modifier = ExtractConvertAttrValueToInt(
+               dxl_memory_manager, attrs, 
EdxltokenScalarFieldSelectTypeModifier,
+               EdxltokenScalarFieldSelect);
+       SINT field_number = ExtractConvertAttrValueToInt(
+               dxl_memory_manager, attrs, 
EdxltokenScalarFieldSelectFieldNumber,
+               EdxltokenScalarFieldSelect);
+
+       return GPOS_NEW(mp) CDXLScalarFieldSelect(mp, field_type, 
field_collation,
+                                                                               
          type_modifier, field_number);
+}
+
 //---------------------------------------------------------------------------
 //     @function:
 //             CDXLOperatorFactory::MakeDXLConstValue
diff --git 
a/src/backend/gporca/libnaucrates/src/operators/CDXLScalarFieldSelect.cpp 
b/src/backend/gporca/libnaucrates/src/operators/CDXLScalarFieldSelect.cpp
new file mode 100644
index 0000000000..91dc0313db
--- /dev/null
+++ b/src/backend/gporca/libnaucrates/src/operators/CDXLScalarFieldSelect.cpp
@@ -0,0 +1,205 @@
+//---------------------------------------------------------------------------
+//     Greenplum Database
+//     Copyright (C) 2023 VMware, Inc. or its affiliates. All Rights Reserved.
+//
+//     @filename:
+//             CDXLScalarFieldSelect.cpp
+//
+//     @doc:
+//             Implementation of DXL Scalar FIELDSELECT operator
+//---------------------------------------------------------------------------
+
+#include "naucrates/dxl/operators/CDXLScalarFieldSelect.h"
+
+#include "gpopt/mdcache/CMDAccessor.h"
+#include "naucrates/dxl/operators/CDXLNode.h"
+#include "naucrates/dxl/xml/CXMLSerializer.h"
+
+using namespace gpos;
+using namespace gpdxl;
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::CDXLScalarFieldSelect
+//
+//     @doc:
+//             Ctor
+//
+//---------------------------------------------------------------------------
+CDXLScalarFieldSelect::CDXLScalarFieldSelect(CMemoryPool *mp, IMDId 
*field_type,
+                                                                               
         IMDId *field_collation,
+                                                                               
         INT type_modifier,
+                                                                               
         SINT field_number)
+       : CDXLScalar(mp),
+         m_dxl_field_type(field_type),
+         m_dxl_field_collation(field_collation),
+         m_dxl_type_modifier(type_modifier),
+         m_dxl_field_number(field_number)
+{
+       GPOS_ASSERT(m_dxl_field_type->IsValid());
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::~CDXLScalarFieldSelect
+//
+//     @doc:
+//             Dtor
+//
+//---------------------------------------------------------------------------
+CDXLScalarFieldSelect::~CDXLScalarFieldSelect()
+{
+       m_dxl_field_type->Release();
+       m_dxl_field_collation->Release();
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::GetDXLOperator
+//
+//     @doc:
+//             Operator type
+//
+//---------------------------------------------------------------------------
+Edxlopid
+CDXLScalarFieldSelect::GetDXLOperator() const
+{
+       return EdxlopScalarFieldSelect;
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::GetDXLFieldType
+//
+//     @doc:
+//             Returns mdid of the field
+//
+//---------------------------------------------------------------------------
+IMDId *
+CDXLScalarFieldSelect::GetDXLFieldType() const
+{
+       return m_dxl_field_type;
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::GetDXLFieldCollation
+//
+//     @doc:
+//             Returns collation mdid of the field
+//
+//---------------------------------------------------------------------------
+IMDId *
+CDXLScalarFieldSelect::GetDXLFieldCollation() const
+{
+       return m_dxl_field_collation;
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::GetDXLFieldTypeModifier
+//
+//     @doc:
+//             Returns output type mode
+//
+//---------------------------------------------------------------------------
+INT
+CDXLScalarFieldSelect::GetDXLTypeModifier() const
+{
+       return m_dxl_type_modifier;
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::GetDXLFieldNumber()
+//
+//     @doc:
+//             Returns attribute number of the field to extract
+//
+//---------------------------------------------------------------------------
+SINT
+CDXLScalarFieldSelect::GetDXLFieldNumber() const
+{
+       return m_dxl_field_number;
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::GetOpNameStr
+//
+//     @doc:
+//             Operator name
+//
+//---------------------------------------------------------------------------
+const CWStringConst *
+CDXLScalarFieldSelect::GetOpNameStr() const
+{
+       return CDXLTokens::GetDXLTokenStr(EdxltokenScalarFieldSelect);
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::SerializeToDXL
+//
+//     @doc:
+//             Serialize operator in DXL format
+//
+//---------------------------------------------------------------------------
+void
+CDXLScalarFieldSelect::SerializeToDXL(CXMLSerializer *xml_serializer,
+                                                                         const 
CDXLNode *dxlnode) const
+{
+       const CWStringConst *element_name = GetOpNameStr();
+
+       xml_serializer->OpenElement(
+               CDXLTokens::GetDXLTokenStr(EdxltokenNamespacePrefix), 
element_name);
+
+       m_dxl_field_type->Serialize(
+               xml_serializer,
+               
CDXLTokens::GetDXLTokenStr(EdxltokenScalarFieldSelectFieldType));
+       m_dxl_field_collation->Serialize(
+               xml_serializer,
+               
CDXLTokens::GetDXLTokenStr(EdxltokenScalarFieldSelectFieldCollation));
+       xml_serializer->AddAttribute(
+               
CDXLTokens::GetDXLTokenStr(EdxltokenScalarFieldSelectTypeModifier),
+               m_dxl_type_modifier);
+       xml_serializer->AddAttribute(
+               
CDXLTokens::GetDXLTokenStr(EdxltokenScalarFieldSelectFieldNumber),
+               m_dxl_field_number);
+
+       dxlnode->SerializeChildrenToDXL(xml_serializer);
+
+       xml_serializer->CloseElement(
+               CDXLTokens::GetDXLTokenStr(EdxltokenNamespacePrefix), 
element_name);
+}
+
+#ifdef GPOS_DEBUG
+//---------------------------------------------------------------------------
+//     @function:
+//             CDXLScalarFieldSelect::AssertValid
+//
+//     @doc:
+//             Checks whether operator node is well-structured
+//
+//---------------------------------------------------------------------------
+void
+CDXLScalarFieldSelect::AssertValid(const CDXLNode *dxlnode,
+                                                                  BOOL 
validate_children) const
+{
+       const ULONG arity = dxlnode->Arity();
+       for (ULONG ul = 0; ul < arity; ++ul)
+       {
+               CDXLNode *child_dxlnode = (*dxlnode)[ul];
+               GPOS_ASSERT(EdxloptypeScalar ==
+                                       
child_dxlnode->GetOperator()->GetDXLOperatorType());
+
+               if (validate_children)
+               {
+                       child_dxlnode->GetOperator()->AssertValid(child_dxlnode,
+                                                                               
                          validate_children);
+               }
+       }
+}
+#endif // GPOS_DEBUG
+
+// EOF
diff --git a/src/backend/gporca/libnaucrates/src/operators/Makefile 
b/src/backend/gporca/libnaucrates/src/operators/Makefile
index ace5344d52..aa89bd295a 100644
--- a/src/backend/gporca/libnaucrates/src/operators/Makefile
+++ b/src/backend/gporca/libnaucrates/src/operators/Makefile
@@ -112,6 +112,7 @@ OBJS        = CDXLColDescr.o \
               CDXLScalarConstValue.o \
               CDXLScalarDMLAction.o \
               CDXLScalarDistinctComp.o \
+             CDXLScalarFieldSelect.o \
               CDXLScalarFilter.o \
               CDXLScalarFuncExpr.o \
               CDXLScalarHashCondList.o \
diff --git 
a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerFactory.cpp 
b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerFactory.cpp
index 26cc898d01..01be8a12a5 100644
--- a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerFactory.cpp
+++ b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerFactory.cpp
@@ -178,6 +178,7 @@ CParseHandlerFactory::Init(CMemoryPool *mp)
                {EdxltokenScalarCoerceToDomain, 
CreateScCoerceToDomainParseHandler},
                {EdxltokenScalarCoerceViaIO, CreateScCoerceViaIOParseHandler},
                {EdxltokenScalarArrayCoerceExpr, 
CreateScArrayCoerceExprParseHandler},
+               {EdxltokenScalarFieldSelect, 
&CreateScalarFieldSelectParseHandler},
                {EdxltokenScalarHashExpr, &CreateHashExprParseHandler},
                {EdxltokenScalarHashCondList, &CreateCondListParseHandler},
                {EdxltokenScalarMergeCondList, &CreateCondListParseHandler},
@@ -1240,6 +1241,16 @@ 
CParseHandlerFactory::CreateScArrayCoerceExprParseHandler(
                mp, parse_handler_mgr, parse_handler_root);
 }
 
+// creates a parse handler for parsing FIELDSELECT operator
+CParseHandlerBase *
+CParseHandlerFactory::CreateScalarFieldSelectParseHandler(
+       CMemoryPool *mp, CParseHandlerManager *parse_handler_mgr,
+       CParseHandlerBase *parse_handler_root)
+{
+       return GPOS_NEW(mp) CParseHandlerScalarFieldSelect(mp, 
parse_handler_mgr,
+                                                                               
                           parse_handler_root);
+}
+
 // creates a parse handler for parsing a SubPlan.
 CParseHandlerBase *
 CParseHandlerFactory::CreateScSubPlanParseHandler(
diff --git 
a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerScalarFieldSelect.cpp 
b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerScalarFieldSelect.cpp
new file mode 100644
index 0000000000..8e588b2788
--- /dev/null
+++ 
b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerScalarFieldSelect.cpp
@@ -0,0 +1,129 @@
+//---------------------------------------------------------------------------
+//     Greenplum Database
+//     Copyright (C) 2023 VMware, Inc. or its affiliates. All Rights Reserved.
+//
+//     @filename:
+//             CParseHandlerScalarFieldSelect.cpp
+//
+//     @doc:
+//             Implementation of the SAX parse handler class for FieldSelect
+//             operators
+//---------------------------------------------------------------------------
+
+#include "naucrates/dxl/parser/CParseHandlerScalarFieldSelect.h"
+
+#include "naucrates/dxl/CDXLUtils.h"
+#include "naucrates/dxl/operators/CDXLOperatorFactory.h"
+#include "naucrates/dxl/parser/CParseHandlerFactory.h"
+#include "naucrates/dxl/parser/CParseHandlerScalarOp.h"
+
+
+using namespace gpdxl;
+
+
+XERCES_CPP_NAMESPACE_USE
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CParseHandlerScalarFieldSelect::CParseHandlerScalarFieldSelect
+//
+//     @doc:
+//             Ctor
+//
+//---------------------------------------------------------------------------
+CParseHandlerScalarFieldSelect::CParseHandlerScalarFieldSelect(
+       CMemoryPool *mp, CParseHandlerManager *parse_handler_mgr,
+       CParseHandlerBase *parse_handler_root)
+       : CParseHandlerScalarOp(mp, parse_handler_mgr, parse_handler_root)
+{
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CParseHandlerScalarFieldSelect::StartElement
+//
+//     @doc:
+//             Processes a Xerces start element event
+//
+//---------------------------------------------------------------------------
+void
+CParseHandlerScalarFieldSelect::StartElement(
+       const XMLCh *const,      // element_uri,
+       const XMLCh *const element_local_name,
+       const XMLCh *const,      // element_qname
+       const Attributes &attrs)
+{
+       if (0 == XMLString::compareString(
+                                
CDXLTokens::XmlstrToken(EdxltokenScalarFieldSelect),
+                                element_local_name))
+       {
+               if (nullptr != m_dxl_node)
+               {
+                       CWStringDynamic *str = 
CDXLUtils::CreateDynamicStringFromXMLChArray(
+                               m_parse_handler_mgr->GetDXLMemoryManager(), 
element_local_name);
+                       GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLUnexpectedTag,
+                                          str->GetBuffer());
+               }
+
+               // parse and create scalar fieldselect
+               CDXLScalarFieldSelect *dxl_op =
+                       (CDXLScalarFieldSelect *) 
CDXLOperatorFactory::MakeDXLFieldSelect(
+                               m_parse_handler_mgr->GetDXLMemoryManager(), 
attrs);
+
+               m_dxl_node = GPOS_NEW(m_mp) CDXLNode(m_mp, dxl_op);
+
+               // parse handler for child scalar node
+               CParseHandlerBase *child_parse_handler =
+                       CParseHandlerFactory::GetParseHandler(
+                               m_mp, CDXLTokens::XmlstrToken(EdxltokenScalar),
+                               m_parse_handler_mgr, this);
+               m_parse_handler_mgr->ActivateParseHandler(child_parse_handler);
+
+               // store parse handler
+               this->Append(child_parse_handler);
+       }
+       else
+       {
+               CWStringDynamic *str = 
CDXLUtils::CreateDynamicStringFromXMLChArray(
+                       m_parse_handler_mgr->GetDXLMemoryManager(), 
element_local_name);
+               GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLUnexpectedTag,
+                                  str->GetBuffer());
+       }
+}
+
+//---------------------------------------------------------------------------
+//     @function:
+//             CParseHandlerScalarFieldSelect::EndElement
+//
+//     @doc:
+//             Processes a Xerces end element event
+//
+//---------------------------------------------------------------------------
+void
+CParseHandlerScalarFieldSelect::EndElement(
+       const XMLCh *const,      // element_uri,
+       const XMLCh *const element_local_name,
+       const XMLCh *const      // element_qname
+)
+{
+       if (0 != XMLString::compareString(
+                                
CDXLTokens::XmlstrToken(EdxltokenScalarFieldSelect),
+                                element_local_name))
+       {
+               CWStringDynamic *str = 
CDXLUtils::CreateDynamicStringFromXMLChArray(
+                       m_parse_handler_mgr->GetDXLMemoryManager(), 
element_local_name);
+               GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLUnexpectedTag,
+                                  str->GetBuffer());
+       }
+       GPOS_ASSERT(1 == this->Length());
+
+       // add constructed child from child parse handlers
+       CParseHandlerScalarOp *child_parse_handler =
+               dynamic_cast<CParseHandlerScalarOp *>((*this)[0]);
+       AddChildFromParseHandler(child_parse_handler);
+
+       // deactivate handler
+       m_parse_handler_mgr->DeactivateHandler();
+}
+
+// EOF
diff --git a/src/backend/gporca/libnaucrates/src/parser/Makefile 
b/src/backend/gporca/libnaucrates/src/parser/Makefile
index 509a1c84a6..2a53a251af 100644
--- a/src/backend/gporca/libnaucrates/src/parser/Makefile
+++ b/src/backend/gporca/libnaucrates/src/parser/Makefile
@@ -144,6 +144,7 @@ OBJS        = CParseHandlerAgg.o \
               CParseHandlerScalarConstValue.o \
               CParseHandlerScalarDMLAction.o \
               CParseHandlerScalarExpr.o \
+              CParseHandlerScalarFieldSelect.o \
               CParseHandlerScalarFuncExpr.o \
               CParseHandlerScalarIdent.o \
               CParseHandlerScalarIfStmt.o \
diff --git a/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp 
b/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp
index 22ff13dea6..0b147cc5c7 100644
--- a/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp
+++ b/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp
@@ -222,10 +222,16 @@ CDXLTokens::Init(CMemoryPool *mp)
                {EdxltokenScalarSortColList, GPOS_WSZ_LIT("SortingColumnList")},
                {EdxltokenScalarGroupingColList, 
GPOS_WSZ_LIT("GroupingColumns")},
                {EdxltokenScalarSortGroupClause, 
GPOS_WSZ_LIT("SortGroupClause")},
-
                {EdxltokenScalarBitmapAnd, GPOS_WSZ_LIT("BitmapAnd")},
                {EdxltokenScalarBitmapOr, GPOS_WSZ_LIT("BitmapOr")},
 
+               {EdxltokenScalarFieldSelect, GPOS_WSZ_LIT("FIELDSELECT")},
+               {EdxltokenScalarFieldSelectFieldType, 
GPOS_WSZ_LIT("FieldType")},
+               {EdxltokenScalarFieldSelectFieldCollation,
+                GPOS_WSZ_LIT("FieldCollation")},
+               {EdxltokenScalarFieldSelectFieldNumber, 
GPOS_WSZ_LIT("FieldNumber")},
+               {EdxltokenScalarFieldSelectTypeModifier, 
GPOS_WSZ_LIT("TypeModifier")},
+
                {EdxltokenScalarArray, GPOS_WSZ_LIT("Array")},
                {EdxltokenScalarArrayRef, GPOS_WSZ_LIT("ArrayRef")},
                {EdxltokenScalarArrayRefIndexList, 
GPOS_WSZ_LIT("ArrayIndexList")},
diff --git a/src/backend/gporca/server/CMakeLists.txt 
b/src/backend/gporca/server/CMakeLists.txt
index 4bce67a677..8e4acdeba6 100644
--- a/src/backend/gporca/server/CMakeLists.txt
+++ b/src/backend/gporca/server/CMakeLists.txt
@@ -398,6 +398,9 @@ SqlFuncNullReject SqlFuncPredFactorize SqlFuncDmlScalar 
SqlFuncDmlTvf CompositeT
 CScalarFuncPushDownTest:
 ScalarFuncPushedBelowGather ConstScalarFuncNotPushedBelowGather;
 
+CScalarTest:
+FieldSelect;
+
 COrderedAggTest:
 CTAS_OrderedAgg_multiple_cols OrderedAgg_multiple_diffcol 
OrderedAgg_with_groupby OrderedAgg_computed_col
 OrderedAggUsingGroupColumnInDirectArg OrderedAgg_multiple_samecol 
OrderedAgg_with_nonOrderedAgg OrderedAgg_single
diff --git a/src/include/gpopt/translate/CTranslatorDXLToScalar.h 
b/src/include/gpopt/translate/CTranslatorDXLToScalar.h
index db304388f8..e80a386731 100644
--- a/src/include/gpopt/translate/CTranslatorDXLToScalar.h
+++ b/src/include/gpopt/translate/CTranslatorDXLToScalar.h
@@ -113,6 +113,9 @@ private:
        Expr *TranslateDXLScalarArrayCoerceExprToScalar(
                const CDXLNode *coerce_node, CMappingColIdVar *colid_var);
 
+       Expr *TranslateDXLFieldSelectToScalar(const CDXLNode *field_select_node,
+                                                                               
  CMappingColIdVar *colid_var);
+
        Expr *TranslateDXLScalarNullTestToScalar(
                const CDXLNode *scalar_null_test_node, CMappingColIdVar 
*colid_var);
 
diff --git a/src/include/gpopt/translate/CTranslatorScalarToDXL.h 
b/src/include/gpopt/translate/CTranslatorScalarToDXL.h
index d9a0c0cb24..4f9c6a3dd1 100644
--- a/src/include/gpopt/translate/CTranslatorScalarToDXL.h
+++ b/src/include/gpopt/translate/CTranslatorScalarToDXL.h
@@ -117,6 +117,10 @@ private:
        CDXLNode *TranslateScalarArrayOpExprToDXL(
                const Expr *expr, const CMappingVarColId *var_colid_mapping);
 
+       // create a DXL node for a fieldselect node from gpdb expression
+       CDXLNode *TranslateFieldSelectToDXL(
+               const Expr *expr, const CMappingVarColId *var_colid_mapping);
+
        // create a DXL scalar array comparison node from a GPDB expression
        CDXLNode *CreateScalarArrayCompFromExpr(
                const Expr *expr, const CMappingVarColId *var_colid_mapping);
diff --git a/src/test/regress/expected/gporca.out 
b/src/test/regress/expected/gporca.out
index b0b43d6944..ab827b5ae4 100644
--- a/src/test/regress/expected/gporca.out
+++ b/src/test/regress/expected/gporca.out
@@ -14545,6 +14545,213 @@ select c from mix_func_cast();
  t
 (1 row)
 
+----------------------------------
+-- Test ORCA support for FIELDSELECT
+----------------------------------
+create type comp_type as ( a text, b numeric, c int, d float, e int);
+create table comp_table(id int, item comp_type) distributed by (id);
+create table comp_part (id int, item comp_type) distributed by (id) partition 
by range(id) (start(1) end(4) every(1));
+insert into comp_table values (1, ROW('GP', 10.5, 10, 10.5, 20)), (2, 
ROW('VM',20.5, 20, 10.5, 20)), (3, ROW('DB',10.5, 10, 10.5, 10));
+insert into comp_part values (1, ROW('GP', 10.5, 10, 10.5, 20)), (2, 
ROW('VM',20.5, 20, 10.5, 20)), (3, ROW('DB',10.5, 10, 10.5, 10));
+analyze comp_table;
+analyze comp_part;
+select sum((item).b) from comp_table where (item).c=20;
+ sum  
+------
+ 20.5
+(1 row)
+
+explain (costs off) select sum((item).b) from comp_table where (item).c=20;
+                   QUERY PLAN                   
+------------------------------------------------
+ Aggregate
+   ->  Gather Motion 3:1  (slice1; segments: 3)
+         ->  Seq Scan on comp_table
+               Filter: ((item).c = 20)
+ Optimizer: Postgres-based planner
+(5 rows)
+
+select distinct (item).b from comp_table where (item).c=20;
+  b   
+------
+ 20.5
+(1 row)
+
+explain (costs off) select distinct (item).b from comp_table where (item).c=20;
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   Merge Key: ((item).b)
+   ->  Unique
+         Group Key: ((item).b)
+         ->  Sort
+               Sort Key: ((item).b)
+               ->  Redistribute Motion 3:3  (slice2; segments: 3)
+                     Hash Key: ((item).b)
+                     ->  Seq Scan on comp_table
+                           Filter: ((item).c = 20)
+ Optimizer: Postgres-based planner
+(11 rows)
+
+-- verify the query output using predicate with the same composite type
+select (item).a from comp_table where (item).c=20 and (item).e >10;
+ a  
+----
+ VM
+(1 row)
+
+explain (costs off) select (item).a from comp_table where (item).c=20 and 
(item).e >10;
+                      QUERY PLAN                       
+-------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Seq Scan on comp_table
+         Filter: (((item).e > 10) AND ((item).c = 20))
+ Optimizer: Postgres-based planner
+(4 rows)
+
+-- verify the query output using predicate with the different composite type
+select * from comp_table where (item).c>(item).d;
+ id |         item         
+----+----------------------
+  2 | (VM,20.5,20,10.5,20)
+(1 row)
+
+explain (costs off) select * from comp_table where (item).c>(item).d ;
+                        QUERY PLAN                         
+-----------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Seq Scan on comp_table
+         Filter: (((item).c)::double precision > (item).d)
+ Optimizer: Postgres-based planner
+(4 rows)
+
+-- verify the query output by using a composite type in a join query
+select (x.item).a from comp_table x join comp_table y on (x.item).c=(y.item).c;
+ a  
+----
+ DB
+ DB
+ GP
+ GP
+ VM
+(5 rows)
+
+explain (costs off) select (x.item).a from comp_table x join comp_table y on 
(x.item).c=(y.item).c;
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Hash Join
+         Hash Cond: ((x.item).c = (y.item).c)
+         ->  Redistribute Motion 3:3  (slice2; segments: 3)
+               Hash Key: (x.item).c
+               ->  Seq Scan on comp_table x
+         ->  Hash
+               ->  Redistribute Motion 3:3  (slice3; segments: 3)
+                     Hash Key: (y.item).c
+                     ->  Seq Scan on comp_table y
+ Optimizer: Postgres-based planner
+(11 rows)
+
+-- verify the query output by using a composite type in a TVF query
+select (x.item).a, (select count(*) from generate_series(1, (x.item).c)) from 
comp_table x;
+ a  | count 
+----+-------
+ GP |    10
+ VM |    20
+ DB |    10
+(3 rows)
+
+explain (costs off) select (x.item).a, (select count(*) from 
generate_series(1, (x.item).c)) from comp_table x;
+                      QUERY PLAN                      
+------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Seq Scan on comp_table x
+         SubPlan 1
+           ->  Aggregate
+                 ->  Function Scan on generate_series
+ Optimizer: Postgres-based planner
+(6 rows)
+
+-- verify the query output by using a composite type in a cte query
+with cte1 as (select * from comp_table where (item).c>10) select id, (item).a, 
(item).b, (item).c, (item).e from cte1;
+ id | a  |  b   | c  | e  
+----+----+------+----+----
+  2 | VM | 20.5 | 20 | 20
+(1 row)
+
+explain (costs off) with cte1 as (select * from comp_table where (item).c>10) 
select id, (item).a, (item).b, (item).c, (item).e from cte1;
+                QUERY PLAN                
+------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Subquery Scan on cte1
+         ->  Seq Scan on comp_table
+               Filter: ((item).c > 10)
+ Optimizer: Postgres-based planner
+(5 rows)
+
+-- verify the query output by using a composite type in a  subquery
+select (item).a from comp_table where (item).c=10 and (item).e IN (SELECT 
(item).e FROM comp_table WHERE (item).c = 10);
+ a  
+----
+ GP
+ DB
+(2 rows)
+
+explain (costs off) select (item).a from comp_table where (item).c=10 and 
(item).e IN (SELECT (item).e FROM comp_table WHERE (item).c = 10);
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Hash Semi Join
+         Hash Cond: ((comp_table.item).e = (comp_table_1.item).e)
+         ->  Redistribute Motion 3:3  (slice2; segments: 3)
+               Hash Key: (comp_table.item).e
+               ->  Seq Scan on comp_table
+                     Filter: ((item).c = 10)
+         ->  Hash
+               ->  Redistribute Motion 3:3  (slice3; segments: 3)
+                     Hash Key: (comp_table_1.item).e
+                     ->  Seq Scan on comp_table comp_table_1
+                           Filter: ((item).c = 10)
+ Optimizer: Postgres-based planner
+(13 rows)
+
+-- verify the query output by using a composite type in a partition table query
+select (x.item).a from comp_part x join comp_part y on (X.item).c=(Y.item).c;
+ a  
+----
+ DB
+ DB
+ GP
+ GP
+ VM
+(5 rows)
+
+explain (costs off) select (x.item).a from comp_part x join comp_part y on 
(X.item).c=(Y.item).c;
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Hash Join
+         Hash Cond: ((x.item).c = (y.item).c)
+         ->  Redistribute Motion 3:3  (slice2; segments: 3)
+               Hash Key: (x.item).c
+               ->  Append
+                     ->  Seq Scan on comp_part_1_prt_1 x
+                     ->  Seq Scan on comp_part_1_prt_2 x_1
+                     ->  Seq Scan on comp_part_1_prt_3 x_2
+         ->  Hash
+               ->  Redistribute Motion 3:3  (slice3; segments: 3)
+                     Hash Key: (y.item).c
+                     ->  Append
+                           ->  Seq Scan on comp_part_1_prt_1 y
+                           ->  Seq Scan on comp_part_1_prt_2 y_1
+                           ->  Seq Scan on comp_part_1_prt_3 y_2
+ Optimizer: Postgres-based planner
+(17 rows)
+
+-- clean up
+drop table comp_table;
+drop table comp_part;
+drop type comp_type;
 -- the query with empty CTE producer target list should fall back to Postgres
 -- optimizer without any error on build without asserts
 drop table if exists empty_cte_tl_test;
diff --git a/src/test/regress/expected/gporca_optimizer.out 
b/src/test/regress/expected/gporca_optimizer.out
index 74df1cd8d5..4d14cbbcde 100644
--- a/src/test/regress/expected/gporca_optimizer.out
+++ b/src/test/regress/expected/gporca_optimizer.out
@@ -14541,21 +14541,17 @@ explain select c2 from quad_func_cast();
 (2 rows)
 
 explain select (c1).r from quad_func_cast();
-INFO:  GPORCA failed to produce a plan, falling back to Postgres-based planner
-DETAIL:  Falling back to Postgres-based planner because GPORCA does not 
support the following feature: FIELDSELECT
                             QUERY PLAN                             
 -------------------------------------------------------------------
- Function Scan on quad_func_cast  (cost=0.00..0.01 rows=1 width=8)
- Optimizer: Postgres query optimizer
+ Function Scan on quad_func_cast  (cost=0.00..0.00 rows=1 width=8)
+ Optimizer: Pivotal Optimizer (GPORCA)
 (2 rows)
 
 explain select (c2).i from quad_func_cast();
-INFO:  GPORCA failed to produce a plan, falling back to Postgres-based planner
-DETAIL:  Falling back to Postgres-based planner because GPORCA does not 
support the following feature: FIELDSELECT
                             QUERY PLAN                             
 -------------------------------------------------------------------
- Function Scan on quad_func_cast  (cost=0.00..0.01 rows=1 width=8)
- Optimizer: Postgres query optimizer
+ Function Scan on quad_func_cast  (cost=0.00..0.00 rows=1 width=8)
+ Optimizer: Pivotal Optimizer (GPORCA)
 (2 rows)
 
 select c1 from quad_func_cast();
@@ -14571,8 +14567,6 @@ select c2 from quad_func_cast();
 (1 row)
 
 select (c1).r from quad_func_cast();
-INFO:  GPORCA failed to produce a plan, falling back to Postgres-based planner
-DETAIL:  Falling back to Postgres-based planner because GPORCA does not 
support the following feature: FIELDSELECT
   r  
 -----
  1.1
@@ -14627,6 +14621,205 @@ select c from mix_func_cast();
  t
 (1 row)
 
+----------------------------------
+-- Test ORCA support for FIELDSELECT
+----------------------------------
+create type comp_type as ( a text, b numeric, c int, d float, e int);
+create table comp_table(id int, item comp_type) distributed by (id);
+create table comp_part (id int, item comp_type) distributed by (id) partition 
by range(id) (start(1) end(4) every(1));
+insert into comp_table values (1, ROW('GP', 10.5, 10, 10.5, 20)), (2, 
ROW('VM',20.5, 20, 10.5, 20)), (3, ROW('DB',10.5, 10, 10.5, 10));
+insert into comp_part values (1, ROW('GP', 10.5, 10, 10.5, 20)), (2, 
ROW('VM',20.5, 20, 10.5, 20)), (3, ROW('DB',10.5, 10, 10.5, 10));
+analyze comp_table;
+analyze comp_part;
+select sum((item).b) from comp_table where (item).c=20;
+ sum  
+------
+ 20.5
+(1 row)
+
+explain (costs off) select sum((item).b) from comp_table where (item).c=20;
+                   QUERY PLAN                   
+------------------------------------------------
+ Finalize Aggregate
+   ->  Gather Motion 3:1  (slice1; segments: 3)
+         ->  Partial Aggregate
+               ->  Seq Scan on comp_table
+                     Filter: ((item).c = 20)
+ Optimizer: GPORCA
+(6 rows)
+
+select distinct (item).b from comp_table where (item).c=20;
+  b   
+------
+ 20.5
+(1 row)
+
+explain (costs off) select distinct (item).b from comp_table where (item).c=20;
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  GroupAggregate
+         Group Key: ((item).b)
+         ->  Sort
+               Sort Key: ((item).b)
+               ->  Redistribute Motion 3:3  (slice2; segments: 3)
+                     Hash Key: ((item).b)
+                     ->  Seq Scan on comp_table
+                           Filter: ((item).c = 20)
+ Optimizer: GPORCA
+(10 rows)
+
+-- verify the query output using predicate with the same composite type
+select (item).a from comp_table where (item).c=20 and (item).e >10;
+ a  
+----
+ VM
+(1 row)
+
+explain (costs off) select (item).a from comp_table where (item).c=20 and 
(item).e >10;
+                      QUERY PLAN                       
+-------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Seq Scan on comp_table
+         Filter: (((item).c = 20) AND ((item).e > 10))
+ Optimizer: GPORCA
+(4 rows)
+
+-- verify the query output using predicate with the different composite type
+select * from comp_table where (item).c>(item).d;
+ id |         item         
+----+----------------------
+  2 | (VM,20.5,20,10.5,20)
+(1 row)
+
+explain (costs off) select * from comp_table where (item).c>(item).d ;
+                        QUERY PLAN                         
+-----------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Seq Scan on comp_table
+         Filter: (((item).c)::double precision > (item).d)
+ Optimizer: GPORCA
+(4 rows)
+
+-- verify the query output by using a composite type in a join query
+select (x.item).a from comp_table x join comp_table y on (x.item).c=(y.item).c;
+ a  
+----
+ DB
+ DB
+ GP
+ GP
+ VM
+(5 rows)
+
+explain (costs off) select (x.item).a from comp_table x join comp_table y on 
(x.item).c=(y.item).c;
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Hash Join
+         Hash Cond: ((comp_table.item).c = (comp_table_1.item).c)
+         ->  Redistribute Motion 3:3  (slice2; segments: 3)
+               Hash Key: (comp_table.item).c
+               ->  Seq Scan on comp_table
+         ->  Hash
+               ->  Redistribute Motion 3:3  (slice3; segments: 3)
+                     Hash Key: (comp_table_1.item).c
+                     ->  Seq Scan on comp_table comp_table_1
+ Optimizer: GPORCA
+(11 rows)
+
+-- verify the query output by using a composite type in a TVF query
+select (x.item).a, (select count(*) from generate_series(1, (x.item).c)) from 
comp_table x;
+ a  | count 
+----+-------
+ GP |    10
+ VM |    20
+ DB |    10
+(3 rows)
+
+explain (costs off) select (x.item).a, (select count(*) from 
generate_series(1, (x.item).c)) from comp_table x;
+                      QUERY PLAN                      
+------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Seq Scan on comp_table
+         SubPlan 1
+           ->  Aggregate
+                 ->  Function Scan on generate_series
+ Optimizer: GPORCA
+(6 rows)
+
+-- verify the query output by using a composite type in a cte query
+with cte1 as (select * from comp_table where (item).c>10) select id, (item).a, 
(item).b, (item).c, (item).e from cte1;
+ id | a  |  b   | c  | e  
+----+----+------+----+----
+  2 | VM | 20.5 | 20 | 20
+(1 row)
+
+explain (costs off) with cte1 as (select * from comp_table where (item).c>10) 
select id, (item).a, (item).b, (item).c, (item).e from cte1;
+                QUERY PLAN                
+------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Seq Scan on comp_table
+         Filter: ((item).c > 10)
+ Optimizer: GPORCA
+(4 rows)
+
+-- verify the query output by using a composite type in a  subquery
+select (item).a from comp_table where (item).c=10 and (item).e IN (SELECT 
(item).e FROM comp_table WHERE (item).c = 10);
+ a  
+----
+ DB
+ GP
+(2 rows)
+
+explain (costs off) select (item).a from comp_table where (item).c=10 and 
(item).e IN (SELECT (item).e FROM comp_table WHERE (item).c = 10);
+                             QUERY PLAN                             
+--------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Hash Semi Join
+         Hash Cond: ((comp_table.item).e = ((comp_table_1.item).e))
+         ->  Seq Scan on comp_table
+               Filter: ((item).c = 10)
+         ->  Hash
+               ->  Broadcast Motion 3:3  (slice2; segments: 3)
+                     ->  Seq Scan on comp_table comp_table_1
+                           Filter: ((item).c = 10)
+ Optimizer: GPORCA
+(10 rows)
+
+-- verify the query output by using a composite type in a partition table query
+select (x.item).a from comp_part x join comp_part y on (X.item).c=(Y.item).c;
+ a  
+----
+ GP
+ GP
+ VM
+ DB
+ DB
+(5 rows)
+
+explain (costs off) select (x.item).a from comp_part x join comp_part y on 
(X.item).c=(Y.item).c;
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   ->  Hash Join
+         Hash Cond: ((comp_part.item).c = (comp_part_1.item).c)
+         ->  Redistribute Motion 3:3  (slice2; segments: 3)
+               Hash Key: (comp_part.item).c
+               ->  Dynamic Seq Scan on comp_part
+                     Number of partitions to scan: 3 (out of 3)
+         ->  Hash
+               ->  Redistribute Motion 3:3  (slice3; segments: 3)
+                     Hash Key: (comp_part_1.item).c
+                     ->  Dynamic Seq Scan on comp_part comp_part_1
+                           Number of partitions to scan: 3 (out of 3)
+ Optimizer: GPORCA
+(13 rows)
+
+-- clean up
+drop table comp_table;
+drop table comp_part;
+drop type comp_type;
 -- the query with empty CTE producer target list should fall back to Postgres
 -- optimizer without any error on build without asserts
 drop table if exists empty_cte_tl_test;
diff --git 
a/src/test/regress/output/external_table_persistent_error_log_optimizer.source 
b/src/test/regress/output/external_table_persistent_error_log_optimizer.source
index b8004d088d..cb9249e6d0 100644
--- 
a/src/test/regress/output/external_table_persistent_error_log_optimizer.source
+++ 
b/src/test/regress/output/external_table_persistent_error_log_optimizer.source
@@ -40,7 +40,7 @@ NOTICE:  found 2 data formatting errors (2 or more input 
rows), rejected related
 
 SELECT (gp_read_persistent_error_log('ext_error_persistent')).errmsg;
 INFO:  GPORCA failed to produce a plan, falling back to Postgres-based planner
-DETAIL:  Falling back to Postgres-based planner because GPORCA does not 
support the following feature: FIELDSELECT
+DETAIL:  Falling back to Postgres-based planner because GPORCA does not 
support the following feature: unsupported exec location
                 errmsg                 
 ---------------------------------------
  extra data after last expected column
@@ -80,7 +80,7 @@ DETAIL:  Falling back to Postgres-based planner because 
GPORCA does not support
 
 SELECT (gp_read_persistent_error_log('ext_error_persistent')).errmsg;
 INFO:  GPORCA failed to produce a plan, falling back to Postgres-based planner
-DETAIL:  Falling back to Postgres-based planner because GPORCA does not 
support the following feature: FIELDSELECT
+DETAIL:  Falling back to Postgres-based planner because GPORCA does not 
support the following feature: unsupported exec location
                 errmsg                 
 ---------------------------------------
  extra data after last expected column
diff --git a/src/test/regress/sql/gporca.sql b/src/test/regress/sql/gporca.sql
index 524ac0c788..ff08636b68 100644
--- a/src/test/regress/sql/gporca.sql
+++ b/src/test/regress/sql/gporca.sql
@@ -3555,6 +3555,56 @@ select a from mix_func_cast();
 select b from mix_func_cast();
 select c from mix_func_cast();
 
+----------------------------------
+-- Test ORCA support for FIELDSELECT
+----------------------------------
+create type comp_type as ( a text, b numeric, c int, d float, e int);
+create table comp_table(id int, item comp_type) distributed by (id);
+create table comp_part (id int, item comp_type) distributed by (id) partition 
by range(id) (start(1) end(4) every(1));
+insert into comp_table values (1, ROW('GP', 10.5, 10, 10.5, 20)), (2, 
ROW('VM',20.5, 20, 10.5, 20)), (3, ROW('DB',10.5, 10, 10.5, 10));
+insert into comp_part values (1, ROW('GP', 10.5, 10, 10.5, 20)), (2, 
ROW('VM',20.5, 20, 10.5, 20)), (3, ROW('DB',10.5, 10, 10.5, 10));
+analyze comp_table;
+analyze comp_part;
+
+select sum((item).b) from comp_table where (item).c=20;
+explain (costs off) select sum((item).b) from comp_table where (item).c=20;
+
+select distinct (item).b from comp_table where (item).c=20;
+explain (costs off) select distinct (item).b from comp_table where (item).c=20;
+
+-- verify the query output using predicate with the same composite type
+select (item).a from comp_table where (item).c=20 and (item).e >10;
+explain (costs off) select (item).a from comp_table where (item).c=20 and 
(item).e >10;
+
+-- verify the query output using predicate with the different composite type
+select * from comp_table where (item).c>(item).d;
+explain (costs off) select * from comp_table where (item).c>(item).d ;
+
+-- verify the query output by using a composite type in a join query
+select (x.item).a from comp_table x join comp_table y on (x.item).c=(y.item).c;
+explain (costs off) select (x.item).a from comp_table x join comp_table y on 
(x.item).c=(y.item).c;
+
+-- verify the query output by using a composite type in a TVF query
+select (x.item).a, (select count(*) from generate_series(1, (x.item).c)) from 
comp_table x;
+explain (costs off) select (x.item).a, (select count(*) from 
generate_series(1, (x.item).c)) from comp_table x;
+
+-- verify the query output by using a composite type in a cte query
+with cte1 as (select * from comp_table where (item).c>10) select id, (item).a, 
(item).b, (item).c, (item).e from cte1;
+explain (costs off) with cte1 as (select * from comp_table where (item).c>10) 
select id, (item).a, (item).b, (item).c, (item).e from cte1;
+
+-- verify the query output by using a composite type in a  subquery
+select (item).a from comp_table where (item).c=10 and (item).e IN (SELECT 
(item).e FROM comp_table WHERE (item).c = 10);
+explain (costs off) select (item).a from comp_table where (item).c=10 and 
(item).e IN (SELECT (item).e FROM comp_table WHERE (item).c = 10);
+
+-- verify the query output by using a composite type in a partition table query
+select (x.item).a from comp_part x join comp_part y on (X.item).c=(Y.item).c;
+explain (costs off) select (x.item).a from comp_part x join comp_part y on 
(X.item).c=(Y.item).c;
+
+-- clean up
+drop table comp_table;
+drop table comp_part;
+drop type comp_type;
+
 -- the query with empty CTE producer target list should fall back to Postgres
 -- optimizer without any error on build without asserts
 drop table if exists empty_cte_tl_test;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to