//---------------------------------------------------------------------------
//	Greenplum Database
//	Copyright (C) 2010 Greenplum, Inc.
//
//	@filename:
//		CDXLOperatorFactory.cpp
//
//	@doc:
//		Implementation of the factory methods for creation of DXL elements.
//---------------------------------------------------------------------------

#include "naucrates/dxl/operators/CDXLOperatorFactory.h"

#include <xercesc/util/NumberFormatException.hpp>

#include "gpos/common/clibwrapper.h"
#include "gpos/memory/stack.h"
#include "gpos/string/CWStringConst.h"
#include "gpos/string/CWStringDynamic.h"

#include "naucrates/dxl/CDXLUtils.h"
#include "naucrates/dxl/operators/CDXLDatumBool.h"
#include "naucrates/dxl/operators/CDXLDatumGeneric.h"
#include "naucrates/dxl/operators/CDXLDatumInt2.h"
#include "naucrates/dxl/operators/CDXLDatumInt4.h"
#include "naucrates/dxl/operators/CDXLDatumInt8.h"
#include "naucrates/dxl/operators/CDXLDatumOid.h"
#include "naucrates/dxl/operators/CDXLDatumStatsDoubleMappable.h"
#include "naucrates/dxl/operators/CDXLDatumStatsLintMappable.h"
#include "naucrates/dxl/operators/CDXLLogicalJoin.h"
#include "naucrates/dxl/operators/CDXLPhysicalAgg.h"
#include "naucrates/dxl/operators/CDXLPhysicalAppend.h"
#include "naucrates/dxl/operators/CDXLPhysicalBroadcastMotion.h"
#include "naucrates/dxl/operators/CDXLPhysicalGatherMotion.h"
#include "naucrates/dxl/operators/CDXLPhysicalHashJoin.h"
#include "naucrates/dxl/operators/CDXLPhysicalLimit.h"
#include "naucrates/dxl/operators/CDXLPhysicalMaterialize.h"
#include "naucrates/dxl/operators/CDXLPhysicalMergeJoin.h"
#include "naucrates/dxl/operators/CDXLPhysicalNLJoin.h"
#include "naucrates/dxl/operators/CDXLPhysicalRandomMotion.h"
#include "naucrates/dxl/operators/CDXLPhysicalRedistributeMotion.h"
#include "naucrates/dxl/operators/CDXLPhysicalResult.h"
#include "naucrates/dxl/operators/CDXLPhysicalRoutedDistributeMotion.h"
#include "naucrates/dxl/operators/CDXLPhysicalSort.h"
#include "naucrates/dxl/operators/CDXLPhysicalTableScan.h"
#include "naucrates/dxl/operators/CDXLScalarAggref.h"
#include "naucrates/dxl/operators/CDXLScalarArray.h"
#include "naucrates/dxl/operators/CDXLScalarArrayCoerceExpr.h"
#include "naucrates/dxl/operators/CDXLScalarArrayComp.h"
#include "naucrates/dxl/operators/CDXLScalarCast.h"
#include "naucrates/dxl/operators/CDXLScalarCoerceToDomain.h"
#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"
#include "naucrates/dxl/operators/CDXLScalarIfStmt.h"
#include "naucrates/dxl/operators/CDXLScalarLimitCount.h"
#include "naucrates/dxl/operators/CDXLScalarLimitOffset.h"
#include "naucrates/dxl/operators/CDXLScalarNullTest.h"
#include "naucrates/dxl/operators/CDXLScalarOpExpr.h"
#include "naucrates/dxl/operators/CDXLScalarParam.h"
#include "naucrates/dxl/operators/CDXLScalarProjElem.h"
#include "naucrates/dxl/operators/CDXLScalarSortCol.h"
#include "naucrates/dxl/operators/CDXLScalarWindowRef.h"
#include "naucrates/exception.h"
#include "naucrates/md/CMDIdCast.h"
#include "naucrates/md/CMDIdColStats.h"
#include "naucrates/md/CMDIdGPDB.h"
#include "naucrates/md/CMDIdGPDBCtas.h"
#include "naucrates/md/CMDIdRelStats.h"
#include "naucrates/md/CMDIdScCmp.h"

using namespace gpos;
using namespace gpdxl;


XERCES_CPP_NAMESPACE_USE

#define GPDXL_GPDB_MDID_COMPONENTS 3
#define GPDXL_DEFAULT_USERID 0

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLTblScan
//
//	@doc:
//		Construct a table scan operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLTblScan(CDXLMemoryManager *dxl_memory_manager,
									const Attributes &	// attrs
)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	return GPOS_NEW(mp) CDXLPhysicalTableScan(mp);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLResult
//
//	@doc:
//		Construct a result operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLResult(CDXLMemoryManager *dxl_memory_manager)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	return GPOS_NEW(mp) CDXLPhysicalResult(mp);
}

//		Construct a hashjoin operator
CDXLPhysical *
CDXLOperatorFactory::MakeDXLHashJoin(CDXLMemoryManager *dxl_memory_manager,
									 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	const XMLCh *join_type_xml =
		ExtractAttrValue(attrs, EdxltokenJoinType, EdxltokenPhysicalHashJoin);

	EdxlJoinType join_type = ParseJoinType(
		join_type_xml, CDXLTokens::GetDXLTokenStr(EdxltokenPhysicalHashJoin));

	return GPOS_NEW(mp) CDXLPhysicalHashJoin(mp, join_type);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLNLJoin
//
//	@doc:
//		Construct a nested loop join operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLNLJoin(CDXLMemoryManager *dxl_memory_manager,
								   const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	const XMLCh *join_type_xml =
		ExtractAttrValue(attrs, EdxltokenJoinType, EdxltokenPhysicalNLJoin);

	BOOL is_index_nlj = false;
	const XMLCh *index_nlj_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenPhysicalNLJoinIndex));
	if (nullptr != index_nlj_xml)
	{
		is_index_nlj = ConvertAttrValueToBool(dxl_memory_manager, index_nlj_xml,
											  EdxltokenPhysicalNLJoinIndex,
											  EdxltokenPhysicalNLJoin);
	}

	// identify if nest params are expected in dxl
	BOOL nest_params_exists = false;
	const XMLCh *nest_param_exists_xml = attrs.getValue(
		CDXLTokens::XmlstrToken(EdxltokenNLJIndexOuterRefAsParam));
	if (nullptr != nest_param_exists_xml)
	{
		nest_params_exists = ConvertAttrValueToBool(
			dxl_memory_manager, nest_param_exists_xml,
			EdxltokenNLJIndexOuterRefAsParam, EdxltokenPhysicalNLJoin);
	}

	EdxlJoinType join_type = ParseJoinType(
		join_type_xml, CDXLTokens::GetDXLTokenStr(EdxltokenPhysicalNLJoin));

	return GPOS_NEW(mp)
		CDXLPhysicalNLJoin(mp, join_type, is_index_nlj, nest_params_exists);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLMergeJoin
//
//	@doc:
//		Construct a merge join operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLMergeJoin(CDXLMemoryManager *dxl_memory_manager,
									  const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	const XMLCh *join_type_xml =
		ExtractAttrValue(attrs, EdxltokenJoinType, EdxltokenPhysicalMergeJoin);

	EdxlJoinType join_type = ParseJoinType(
		join_type_xml, CDXLTokens::GetDXLTokenStr(EdxltokenPhysicalMergeJoin));

	BOOL is_unique_outer = ExtractConvertAttrValueToBool(
		dxl_memory_manager, attrs, EdxltokenMergeJoinUniqueOuter,
		EdxltokenPhysicalMergeJoin);

	return GPOS_NEW(mp) CDXLPhysicalMergeJoin(mp, join_type, is_unique_outer);
}

//		Construct a gather motion operator
CDXLPhysical *
CDXLOperatorFactory::MakeDXLGatherMotion(CDXLMemoryManager *dxl_memory_manager,
										 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	CDXLPhysicalGatherMotion *dxl_op =
		GPOS_NEW(mp) CDXLPhysicalGatherMotion(mp);
	SetSegmentInfo(dxl_memory_manager, dxl_op, attrs,
				   EdxltokenPhysicalGatherMotion);

	return dxl_op;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLBroadcastMotion
//
//	@doc:
//		Construct a broadcast motion operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLBroadcastMotion(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	CDXLPhysicalBroadcastMotion *dxl_op =
		GPOS_NEW(mp) CDXLPhysicalBroadcastMotion(mp);
	SetSegmentInfo(dxl_memory_manager, dxl_op, attrs,
				   EdxltokenPhysicalBroadcastMotion);

	return dxl_op;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLRedistributeMotion
//
//	@doc:
//		Construct a redistribute motion operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLRedistributeMotion(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	BOOL is_duplicate_sensitive = false;

	const XMLCh *duplicate_sensitive_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenDuplicateSensitive));
	if (nullptr != duplicate_sensitive_xml)
	{
		is_duplicate_sensitive = ConvertAttrValueToBool(
			dxl_memory_manager, duplicate_sensitive_xml,
			EdxltokenDuplicateSensitive, EdxltokenPhysicalRedistributeMotion);
	}

	CDXLPhysicalRedistributeMotion *dxl_op =
		GPOS_NEW(mp) CDXLPhysicalRedistributeMotion(mp, is_duplicate_sensitive);
	SetSegmentInfo(dxl_memory_manager, dxl_op, attrs,
				   EdxltokenPhysicalRedistributeMotion);

	return dxl_op;
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLRoutedMotion
//
//	@doc:
//		Construct a routed motion operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLRoutedMotion(CDXLMemoryManager *dxl_memory_manager,
										 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	ULONG segment_colid = CDXLOperatorFactory::ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenSegmentIdCol,
		EdxltokenPhysicalRoutedDistributeMotion);

	CDXLPhysicalRoutedDistributeMotion *dxl_op =
		GPOS_NEW(mp) CDXLPhysicalRoutedDistributeMotion(mp, segment_colid);
	SetSegmentInfo(dxl_memory_manager, dxl_op, attrs,
				   EdxltokenPhysicalRoutedDistributeMotion);

	return dxl_op;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLRandomMotion
//
//	@doc:
//		Construct a random motion operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLRandomMotion(CDXLMemoryManager *dxl_memory_manager,
										 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	BOOL is_duplicate_sensitive = false;

	const XMLCh *duplicate_sensitive_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenDuplicateSensitive));
	if (nullptr != duplicate_sensitive_xml)
	{
		is_duplicate_sensitive = ConvertAttrValueToBool(
			dxl_memory_manager, duplicate_sensitive_xml,
			EdxltokenDuplicateSensitive, EdxltokenPhysicalRandomMotion);
	}

	CDXLPhysicalRandomMotion *dxl_op =
		GPOS_NEW(mp) CDXLPhysicalRandomMotion(mp, is_duplicate_sensitive);
	SetSegmentInfo(dxl_memory_manager, dxl_op, attrs,
				   EdxltokenPhysicalRandomMotion);

	return dxl_op;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLAppend
//	@doc:
//		Construct an Append operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLAppend(CDXLMemoryManager *dxl_memory_manager,
								   const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	BOOL is_target = ExtractConvertAttrValueToBool(dxl_memory_manager, attrs,
												   EdxltokenAppendIsTarget,
												   EdxltokenPhysicalAppend);

	BOOL is_zapped = ExtractConvertAttrValueToBool(dxl_memory_manager, attrs,
												   EdxltokenAppendIsZapped,
												   EdxltokenPhysicalAppend);

	return GPOS_NEW(mp) CDXLPhysicalAppend(mp, is_target, is_zapped);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLLimit
//	@doc:
//		Construct a Limit operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLLimit(CDXLMemoryManager *dxl_memory_manager,
								  const Attributes &  // attrs
)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	return GPOS_NEW(mp) CDXLPhysicalLimit(mp);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLLimitCount
//
//	@doc:
//		Construct a Limit Count operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLLimitCount(CDXLMemoryManager *dxl_memory_manager,
									   const Attributes &  // attrs
)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	return GPOS_NEW(mp) CDXLScalarLimitCount(mp);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLLimitOffset
//
//	@doc:
//		Construct a Limit Offset operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLLimitOffset(CDXLMemoryManager *dxl_memory_manager,
										const Attributes &	// attrs
)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	return GPOS_NEW(mp) CDXLScalarLimitOffset(mp);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLAgg
//
//	@doc:
//		Construct an aggregate operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLAgg(CDXLMemoryManager *dxl_memory_manager,
								const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	const XMLCh *agg_strategy_xml = ExtractAttrValue(
		attrs, EdxltokenAggStrategy, EdxltokenPhysicalAggregate);

	EdxlAggStrategy dxl_agg_strategy = EdxlaggstrategySentinel;

	if (0 == XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenAggStrategyPlain),
				 agg_strategy_xml))
	{
		dxl_agg_strategy = EdxlaggstrategyPlain;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenAggStrategySorted),
					  agg_strategy_xml))
	{
		dxl_agg_strategy = EdxlaggstrategySorted;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenAggStrategyHashed),
					  agg_strategy_xml))
	{
		dxl_agg_strategy = EdxlaggstrategyHashed;
	}
	else
	{
		GPOS_RAISE(
			gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
			CDXLTokens::GetDXLTokenStr(EdxltokenAggStrategy)->GetBuffer(),
			CDXLTokens::GetDXLTokenStr(EdxltokenPhysicalAggregate)
				->GetBuffer());
	}

	BOOL stream_safe = false;

	const XMLCh *stream_safe_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenAggStreamSafe));
	if (nullptr != stream_safe_xml)
	{
		stream_safe = ConvertAttrValueToBool(
			dxl_memory_manager, stream_safe_xml, EdxltokenAggStreamSafe,
			EdxltokenPhysicalAggregate);
	}

	return GPOS_NEW(mp) CDXLPhysicalAgg(mp, dxl_agg_strategy, stream_safe);
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLSort
//
//	@doc:
//		Construct a sort operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLSort(CDXLMemoryManager *dxl_memory_manager,
								 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse discard duplicates and nulls first properties from the attributes
	BOOL discard_duplicates = ExtractConvertAttrValueToBool(
		dxl_memory_manager, attrs, EdxltokenSortDiscardDuplicates,
		EdxltokenPhysicalSort);

	return GPOS_NEW(mp) CDXLPhysicalSort(mp, discard_duplicates);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLMaterialize
//
//	@doc:
//		Construct a materialize operator
//
//---------------------------------------------------------------------------
CDXLPhysical *
CDXLOperatorFactory::MakeDXLMaterialize(CDXLMemoryManager *dxl_memory_manager,
										const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse spooling info from the attributes

	CDXLPhysicalMaterialize *materialize_dxlnode = nullptr;

	// is this a multi-slice spool
	BOOL eager_materialize = ExtractConvertAttrValueToBool(
		dxl_memory_manager, attrs, EdxltokenMaterializeEager,
		EdxltokenPhysicalMaterialize);

	if (1 == attrs.getLength())
	{
		// no spooling info specified -> create a non-spooling materialize operator
		materialize_dxlnode =
			GPOS_NEW(mp) CDXLPhysicalMaterialize(mp, eager_materialize);
	}
	else
	{
		// parse spool id
		ULONG spool_id = ExtractConvertAttrValueToUlong(
			dxl_memory_manager, attrs, EdxltokenSpoolId,
			EdxltokenPhysicalMaterialize);

		// parse id of executor slice
		INT executor_slice = ExtractConvertAttrValueToInt(
			dxl_memory_manager, attrs, EdxltokenExecutorSliceId,
			EdxltokenPhysicalMaterialize);

		ULONG num_consumer_slices = ExtractConvertAttrValueToUlong(
			dxl_memory_manager, attrs, EdxltokenConsumerSliceCount,
			EdxltokenPhysicalMaterialize);

		materialize_dxlnode = GPOS_NEW(mp)
			CDXLPhysicalMaterialize(mp, eager_materialize, spool_id,
									executor_slice, num_consumer_slices);
	}

	return materialize_dxlnode;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLScalarCmp
//
//	@doc:
//		Construct a scalar comparison operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLScalarCmp(CDXLMemoryManager *dxl_memory_manager,
									  const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// get comparison operator from attributes
	const XMLCh *scalar_cmp_xml =
		ExtractAttrValue(attrs, EdxltokenComparisonOp, EdxltokenScalarComp);

	// parse op no and function id
	IMDId *op_id = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenOpNo, EdxltokenScalarComp);

	// parse comparison operator from string
	CWStringDynamic *comp_op_name =
		CDXLUtils::CreateDynamicStringFromXMLChArray(dxl_memory_manager,
													 scalar_cmp_xml);

	// copy dynamic string into const string
	CWStringConst *comp_op_name_copy =
		GPOS_NEW(mp) CWStringConst(mp, comp_op_name->GetBuffer());

	// cleanup
	GPOS_DELETE(comp_op_name);

	return GPOS_NEW(mp) CDXLScalarComp(mp, op_id, comp_op_name_copy);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLDistinctCmp
//
//	@doc:
//		Construct a scalar distinct comparison operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLDistinctCmp(CDXLMemoryManager *dxl_memory_manager,
										const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse operator and function id
	IMDId *op_id = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenOpNo, EdxltokenScalarDistinctComp);

	return GPOS_NEW(mp) CDXLScalarDistinctComp(mp, op_id);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLOpExpr
//
//	@doc:
//		Construct a scalar OpExpr
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLOpExpr(CDXLMemoryManager *dxl_memory_manager,
								   const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// get scalar OpExpr from attributes
	const XMLCh *op_expr_xml =
		ExtractAttrValue(attrs, EdxltokenOpName, EdxltokenScalarOpExpr);

	IMDId *op_id = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenOpNo, EdxltokenScalarOpExpr);

	IMDId *return_type_mdid = nullptr;
	const XMLCh *return_type_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenOpType));

	if (nullptr != return_type_xml)
	{
		return_type_mdid = ExtractConvertAttrValueToMdId(
			dxl_memory_manager, attrs, EdxltokenOpType, EdxltokenScalarOpExpr);
	}

	CWStringDynamic *value = CDXLUtils::CreateDynamicStringFromXMLChArray(
		dxl_memory_manager, op_expr_xml);
	CWStringConst *value_copy =
		GPOS_NEW(mp) CWStringConst(mp, value->GetBuffer());
	GPOS_DELETE(value);

	return GPOS_NEW(mp)
		CDXLScalarOpExpr(mp, op_id, return_type_mdid, value_copy);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLScalarParam
//
//	@doc:
//		Construct a scalar param operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLScalarParam(CDXLMemoryManager *dxl_memory_manager,
										const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	INT param_id = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenParamId, EdxltokenScalarParam);
	IMDId *mdid_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId, EdxltokenScalarParam);
	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod, EdxltokenScalarParam, true,
		default_type_modifier);

	return GPOS_NEW(mp) CDXLScalarParam(mp, param_id, mdid_type, type_modifier);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLArrayComp
//
//	@doc:
//		Construct a scalar array comparison
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLArrayComp(CDXLMemoryManager *dxl_memory_manager,
									  const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// get attributes
	const XMLCh *op_expr_xml =
		ExtractAttrValue(attrs, EdxltokenOpName, EdxltokenScalarArrayComp);

	const XMLCh *op_type_xml =
		ExtractAttrValue(attrs, EdxltokenOpType, EdxltokenScalarArrayComp);

	// parse operator no and function id
	IMDId *op_id = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenOpNo, EdxltokenScalarArrayComp);

	EdxlArrayCompType array_comp_type = Edxlarraycomptypeany;

	if (0 == XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenOpTypeAll), op_type_xml))
	{
		array_comp_type = Edxlarraycomptypeall;
	}
	else if (0 != XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenOpTypeAny), op_type_xml))
	{
		GPOS_RAISE(
			gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
			CDXLTokens::GetDXLTokenStr(EdxltokenOpType)->GetBuffer(),
			CDXLTokens::GetDXLTokenStr(EdxltokenScalarArrayComp)->GetBuffer());
	}

	CWStringDynamic *opname = CDXLUtils::CreateDynamicStringFromXMLChArray(
		dxl_memory_manager, op_expr_xml);
	CWStringConst *opname_copy =
		GPOS_NEW(mp) CWStringConst(mp, opname->GetBuffer());
	GPOS_DELETE(opname);

	return GPOS_NEW(mp)
		CDXLScalarArrayComp(mp, op_id, opname_copy, array_comp_type);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLBoolExpr
//
//	@doc:
//		Construct a scalar BoolExpr
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLBoolExpr(CDXLMemoryManager *dxl_memory_manager,
									 const EdxlBoolExprType edxlboolexprType)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	return GPOS_NEW(mp) CDXLScalarBoolExpr(mp, edxlboolexprType);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLBooleanTest
//
//	@doc:
//		Construct a scalar BooleanTest
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLBooleanTest(
	CDXLMemoryManager *dxl_memory_manager,
	const EdxlBooleanTestType edxlbooleantesttype)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	return GPOS_NEW(mp) CDXLScalarBooleanTest(mp, edxlbooleantesttype);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLSubPlan
//
//	@doc:
//		Construct a SubPlan node
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLSubPlan(CDXLMemoryManager *dxl_memory_manager,
									IMDId *mdid,
									CDXLColRefArray *dxl_colref_array,
									EdxlSubPlanType dxl_subplan_type,
									CDXLNode *dxlnode_test_expr)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	return GPOS_NEW(mp) CDXLScalarSubPlan(mp, mdid, dxl_colref_array,
										  dxl_subplan_type, dxlnode_test_expr);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLNullTest
//
//	@doc:
//		Construct a scalar NullTest
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLNullTest(CDXLMemoryManager *dxl_memory_manager,
									 const BOOL is_null)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	return GPOS_NEW(mp) CDXLScalarNullTest(mp, is_null);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLCast
//
//	@doc:
//		Construct a scalar RelabelType
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLCast(CDXLMemoryManager *dxl_memory_manager,
								 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse type id and function id
	IMDId *mdid_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId, EdxltokenScalarCast);

	IMDId *mdid_func = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenFuncId, EdxltokenScalarCast);

	return GPOS_NEW(mp) CDXLScalarCast(mp, mdid_type, mdid_func);
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLCoerceToDomain
//
//	@doc:
//		Construct a scalar coerce
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLCoerceToDomain(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse type id and function id
	IMDId *mdid_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId,
		EdxltokenScalarCoerceToDomain);
	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod,
		EdxltokenScalarCoerceToDomain, true, default_type_modifier);
	ULONG coercion_form = ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenCoercionForm,
		EdxltokenScalarCoerceToDomain);
	INT location = ExtractConvertAttrValueToInt(dxl_memory_manager, attrs,
												EdxltokenLocation,
												EdxltokenScalarCoerceToDomain);

	return GPOS_NEW(mp)
		CDXLScalarCoerceToDomain(mp, mdid_type, type_modifier,
								 (EdxlCoercionForm) coercion_form, location);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLCoerceViaIO
//
//	@doc:
//		Construct a scalar coerce
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLCoerceViaIO(CDXLMemoryManager *dxl_memory_manager,
										const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse type id and function id
	IMDId *mdid_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId, EdxltokenScalarCoerceViaIO);
	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod, EdxltokenScalarCoerceViaIO,
		true, default_type_modifier);
	ULONG coercion_form = ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenCoercionForm,
		EdxltokenScalarCoerceViaIO);
	INT location = ExtractConvertAttrValueToInt(dxl_memory_manager, attrs,
												EdxltokenLocation,
												EdxltokenScalarCoerceViaIO);

	return GPOS_NEW(mp)
		CDXLScalarCoerceViaIO(mp, mdid_type, type_modifier,
							  (EdxlCoercionForm) coercion_form, location);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLArrayCoerceExpr
//
//	@doc:
//		Construct a scalar array coerce expression
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLArrayCoerceExpr(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs)
{
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	IMDId *mdid_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId,
		EdxltokenScalarArrayCoerceExpr);
	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod,
		EdxltokenScalarArrayCoerceExpr, true, default_type_modifier);
	ULONG coercion_form = ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenCoercionForm,
		EdxltokenScalarArrayCoerceExpr);
	INT location = ExtractConvertAttrValueToInt(dxl_memory_manager, attrs,
												EdxltokenLocation,
												EdxltokenScalarArrayCoerceExpr);

	return GPOS_NEW(mp)
		CDXLScalarArrayCoerceExpr(mp, mdid_type, type_modifier,
								  (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
//
//	@doc:
//		Construct a scalar Const
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLConstValue(CDXLMemoryManager *dxl_memory_manager,
									   const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();
	CDXLDatum *dxl_datum =
		GetDatumVal(dxl_memory_manager, attrs, EdxltokenScalarConstValue);

	return GPOS_NEW(mp) CDXLScalarConstValue(mp, dxl_datum);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLIfStmt
//
//	@doc:
//		Construct an if statement operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLIfStmt(CDXLMemoryManager *dxl_memory_manager,
								   const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// get the type id
	IMDId *mdid_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId, EdxltokenScalarIfStmt);

	return GPOS_NEW(mp) CDXLScalarIfStmt(mp, mdid_type);
}


//		Construct an funcexpr operator
CDXLScalar *
CDXLOperatorFactory::MakeDXLFuncExpr(CDXLMemoryManager *dxl_memory_manager,
									 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	IMDId *mdid_func = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenFuncId, EdxltokenScalarFuncExpr);

	BOOL is_retset = ExtractConvertAttrValueToBool(dxl_memory_manager, attrs,
												   EdxltokenFuncRetSet,
												   EdxltokenScalarFuncExpr);

	BOOL is_funcvariadic = ExtractConvertAttrValueToBool(
		dxl_memory_manager, attrs, EdxltokenFuncVariadic,
		EdxltokenScalarFuncExpr, true, false);

	IMDId *mdid_return_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId, EdxltokenScalarFuncExpr);

	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod, EdxltokenScalarCast, true,
		default_type_modifier);

	return GPOS_NEW(mp)
		CDXLScalarFuncExpr(mp, mdid_func, mdid_return_type, type_modifier,
						   is_retset, is_funcvariadic);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLAggFunc
//
//	@doc:
//		Construct an AggRef operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLAggFunc(CDXLMemoryManager *dxl_memory_manager,
									const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	IMDId *agg_mdid = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenAggrefOid, EdxltokenScalarAggref);

	const XMLCh *agg_stage_xml =
		ExtractAttrValue(attrs, EdxltokenAggrefStage, EdxltokenScalarAggref);

	BOOL is_distinct = ExtractConvertAttrValueToBool(dxl_memory_manager, attrs,
													 EdxltokenAggrefDistinct,
													 EdxltokenScalarAggref);

	const XMLCh *agg_kind_xml =
		ExtractAttrValue(attrs, EdxltokenAggrefKind, EdxltokenScalarAggref);

	ULongPtrArray *argtypelist = ExtractConvertValuesToArray(
		dxl_memory_manager, attrs, EdxltokenAggrefArgTypes,
		EdxltokenScalarAggref);

	EdxlAggrefStage agg_stage = EdxlaggstageFinal;

	if (0 ==
		XMLString::compareString(
			CDXLTokens::XmlstrToken(EdxltokenAggrefStageNormal), agg_stage_xml))
	{
		agg_stage = EdxlaggstageNormal;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenAggrefStagePartial),
					  agg_stage_xml))
	{
		agg_stage = EdxlaggstagePartial;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenAggrefStageIntermediate),
					  agg_stage_xml))
	{
		agg_stage = EdxlaggstageIntermediate;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenAggrefStageFinal),
					  agg_stage_xml))
	{
		agg_stage = EdxlaggstageFinal;
	}
	else
	{
		// turn Xerces exception in optimizer exception
		GPOS_RAISE(
			gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
			CDXLTokens::GetDXLTokenStr(EdxltokenAggrefStage)->GetBuffer(),
			CDXLTokens::GetDXLTokenStr(EdxltokenScalarAggref)->GetBuffer());
	}

	EdxlAggrefKind agg_kind = EdxlaggkindNormal;
	if (0 ==
		XMLString::compareString(
			CDXLTokens::XmlstrToken(EdxltokenAggrefKindNormal), agg_kind_xml))
	{
		agg_kind = EdxlaggkindNormal;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenAggrefKindOrderedSet),
					  agg_kind_xml))
	{
		agg_kind = EdxlaggkindOrderedSet;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenAggrefKindHypothetical),
					  agg_kind_xml))
	{
		agg_kind = EdxlaggkindHypothetical;
	}
	else
	{
		// turn Xerces exception in optimizer exception
		GPOS_RAISE(
			gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
			CDXLTokens::GetDXLTokenStr(EdxltokenAggrefKind)->GetBuffer(),
			CDXLTokens::GetDXLTokenStr(EdxltokenScalarAggref)->GetBuffer());
	}

	IMDId *resolved_rettype = nullptr;
	const XMLCh *return_type_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenTypeId));
	if (nullptr != return_type_xml)
	{
		resolved_rettype = ExtractConvertAttrValueToMdId(
			dxl_memory_manager, attrs, EdxltokenTypeId, EdxltokenScalarAggref);
	}

	return GPOS_NEW(mp)
		CDXLScalarAggref(mp, agg_mdid, resolved_rettype, is_distinct, agg_stage,
						 agg_kind, argtypelist);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseDXLFrameBoundary
//
//	@doc:
//		Parse the frame boundary
//
//---------------------------------------------------------------------------
EdxlFrameBoundary
CDXLOperatorFactory::ParseDXLFrameBoundary(const Attributes &attrs,
										   Edxltoken token_type)
{
	const XMLCh *frame_boundary_xml =
		ExtractAttrValue(attrs, token_type, EdxltokenWindowFrame);

	EdxlFrameBoundary frame_boundary = EdxlfbSentinel;
	ULONG window_frame_boundary_to_frame_boundary_mapping[][2] = {
		{EdxlfbUnboundedPreceding, EdxltokenWindowBoundaryUnboundedPreceding},
		{EdxlfbBoundedPreceding, EdxltokenWindowBoundaryBoundedPreceding},
		{EdxlfbCurrentRow, EdxltokenWindowBoundaryCurrentRow},
		{EdxlfbUnboundedFollowing, EdxltokenWindowBoundaryUnboundedFollowing},
		{EdxlfbBoundedFollowing, EdxltokenWindowBoundaryBoundedFollowing},
		{EdxlfbDelayedBoundedPreceding,
		 EdxltokenWindowBoundaryDelayedBoundedPreceding},
		{EdxlfbDelayedBoundedFollowing,
		 EdxltokenWindowBoundaryDelayedBoundedFollowing}};

	const ULONG arity =
		GPOS_ARRAY_SIZE(window_frame_boundary_to_frame_boundary_mapping);
	for (ULONG ul = 0; ul < arity; ul++)
	{
		ULONG *current = window_frame_boundary_to_frame_boundary_mapping[ul];
		Edxltoken current_window = (Edxltoken) current[1];
		if (0 ==
			XMLString::compareString(CDXLTokens::XmlstrToken(current_window),
									 frame_boundary_xml))
		{
			frame_boundary = (EdxlFrameBoundary) current[0];
			break;
		}
	}

	if (EdxlfbSentinel == frame_boundary)
	{
		// turn Xerces exception in optimizer exception
		GPOS_RAISE(
			gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
			CDXLTokens::GetDXLTokenStr(token_type)->GetBuffer(),
			CDXLTokens::GetDXLTokenStr(EdxltokenWindowFrame)->GetBuffer());
	}

	return frame_boundary;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseDXLFrameSpec
//
//	@doc:
//		Parse the frame specification
//
//---------------------------------------------------------------------------
EdxlFrameSpec
CDXLOperatorFactory::ParseDXLFrameSpec(const Attributes &attrs)
{
	const XMLCh *frame_spec_xml =
		ExtractAttrValue(attrs, EdxltokenWindowFrameSpec, EdxltokenWindowFrame);

	EdxlFrameSpec frame_spec = EdxlfsSentinel;
	if (0 == XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenWindowFSRow), frame_spec_xml))
	{
		frame_spec = EdxlfsRow;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenWindowFSRange),
					  frame_spec_xml))
	{
		frame_spec = EdxlfsRange;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenWindowFSGroups),
					  frame_spec_xml))
	{
		frame_spec = EdxlfsGroups;
	}
	else
	{
		// turn Xerces exception in optimizer exception
		GPOS_RAISE(
			gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
			CDXLTokens::GetDXLTokenStr(EdxltokenWindowFrameSpec)->GetBuffer(),
			CDXLTokens::GetDXLTokenStr(EdxltokenWindowFrame)->GetBuffer());
	}

	return frame_spec;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseFrameExclusionStrategy
//
//	@doc:
//		Parse the frame exclusion strategy
//
//---------------------------------------------------------------------------
EdxlFrameExclusionStrategy
CDXLOperatorFactory::ParseFrameExclusionStrategy(const Attributes &attrs)
{
	const XMLCh *frame_exc_strategy_xml = ExtractAttrValue(
		attrs, EdxltokenWindowExclusionStrategy, EdxltokenWindowFrame);

	ULONG window_frame_boundary_to_frame_boundary_mapping[][2] = {
		{EdxlfesNone, EdxltokenWindowESNone},
		{EdxlfesNulls, EdxltokenWindowESNulls},
		{EdxlfesCurrentRow, EdxltokenWindowESCurrentRow},
		{EdxlfesGroup, EdxltokenWindowESGroup},
		{EdxlfesTies, EdxltokenWindowESTies}};

	EdxlFrameExclusionStrategy frame_exc_strategy = EdxlfesSentinel;
	const ULONG arity =
		GPOS_ARRAY_SIZE(window_frame_boundary_to_frame_boundary_mapping);
	for (ULONG ul = 0; ul < arity; ul++)
	{
		ULONG *current = window_frame_boundary_to_frame_boundary_mapping[ul];
		Edxltoken current_window = (Edxltoken) current[1];
		if (0 ==
			XMLString::compareString(CDXLTokens::XmlstrToken(current_window),
									 frame_exc_strategy_xml))
		{
			frame_exc_strategy = (EdxlFrameExclusionStrategy) current[0];
			break;
		}
	}

	if (EdxlfesSentinel == frame_exc_strategy)
	{
		// turn Xerces exception in optimizer exception
		GPOS_RAISE(
			gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
			CDXLTokens::GetDXLTokenStr(EdxltokenWindowExclusionStrategy)
				->GetBuffer(),
			CDXLTokens::GetDXLTokenStr(EdxltokenWindowFrame)->GetBuffer());
	}

	return frame_exc_strategy;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLArray
//
//	@doc:
//		Construct an array operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLArray(CDXLMemoryManager *dxl_memory_manager,
								  const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	IMDId *elem_type_mdid = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenArrayElementType,
		EdxltokenScalarArray);
	IMDId *array_type_mdid = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenArrayType, EdxltokenScalarArray);
	BOOL is_multidimenstional = ExtractConvertAttrValueToBool(
		dxl_memory_manager, attrs, EdxltokenArrayMultiDim,
		EdxltokenScalarArray);

	return GPOS_NEW(mp) CDXLScalarArray(mp, elem_type_mdid, array_type_mdid,
										is_multidimenstional);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLScalarIdent
//
//	@doc:
//		Construct a scalar identifier operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLScalarIdent(CDXLMemoryManager *dxl_memory_manager,
										const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	CDXLColRef *dxl_colref =
		MakeDXLColRef(dxl_memory_manager, attrs, EdxltokenScalarIdent);

	return GPOS_NEW(mp) CDXLScalarIdent(mp, dxl_colref);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLProjElem
//
//	@doc:
//		Construct a proj elem operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLProjElem(CDXLMemoryManager *dxl_memory_manager,
									 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse alias from attributes
	const XMLCh *xml_alias =
		ExtractAttrValue(attrs, EdxltokenAlias, EdxltokenScalarProjElem);

	// parse column id
	ULONG id = ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenColId, EdxltokenScalarProjElem);

	CWStringDynamic *alias = CDXLUtils::CreateDynamicStringFromXMLChArray(
		dxl_memory_manager, xml_alias);

	// create a copy of the string in the CMDName constructor
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, alias);

	GPOS_DELETE(alias);

	return GPOS_NEW(mp) CDXLScalarProjElem(mp, id, mdname);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLHashExpr
//
//	@doc:
//		Construct a hash expr operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLHashExpr(CDXLMemoryManager *dxl_memory_manager,
									 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// get column type id and type name from attributes

	IMDId *mdid_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenOpfamily, EdxltokenScalarHashExpr,
		true /* is_optional */, nullptr /* default_val */
	);

	return GPOS_NEW(mp) CDXLScalarHashExpr(mp, mdid_type);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLSortCol
//
//	@doc:
//		Construct a sorting column description
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeDXLSortCol(CDXLMemoryManager *dxl_memory_manager,
									const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// get column id from attributes
	ULONG colid = ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenColId, EdxltokenScalarSortCol);

	// get sorting operator name
	const XMLCh *sort_op_xml =
		ExtractAttrValue(attrs, EdxltokenSortOpName, EdxltokenScalarSortCol);
	CWStringDynamic *sort_op_name =
		CDXLUtils::CreateDynamicStringFromXMLChArray(dxl_memory_manager,
													 sort_op_xml);

	// get null first property
	BOOL nulls_first = ExtractConvertAttrValueToBool(dxl_memory_manager, attrs,
													 EdxltokenSortNullsFirst,
													 EdxltokenPhysicalSort);

	// parse sorting operator id
	IMDId *sort_op_id = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenSortOpId, EdxltokenPhysicalSort);

	// copy dynamic string into const string
	CWStringConst *sort_op_name_copy =
		GPOS_NEW(mp) CWStringConst(mp, sort_op_name->GetBuffer());

	GPOS_DELETE(sort_op_name);

	return GPOS_NEW(mp) CDXLScalarSortCol(mp, colid, sort_op_id,
										  sort_op_name_copy, nulls_first);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLOperatorCost
//
//	@doc:
//		Construct a cost estimates element
//
//---------------------------------------------------------------------------
CDXLOperatorCost *
CDXLOperatorFactory::MakeDXLOperatorCost(CDXLMemoryManager *dxl_memory_manager,
										 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	const XMLCh *startup_cost_xml =
		ExtractAttrValue(attrs, EdxltokenStartupCost, EdxltokenCost);

	const XMLCh *total_cost_xml =
		ExtractAttrValue(attrs, EdxltokenTotalCost, EdxltokenCost);

	const XMLCh *rows_xml =
		ExtractAttrValue(attrs, EdxltokenRows, EdxltokenCost);

	const XMLCh *width_xml =
		ExtractAttrValue(attrs, EdxltokenWidth, EdxltokenCost);

	CWStringDynamic *startup_cost_str =
		CDXLUtils::CreateDynamicStringFromXMLChArray(dxl_memory_manager,
													 startup_cost_xml);
	CWStringDynamic *total_cost_str =
		CDXLUtils::CreateDynamicStringFromXMLChArray(dxl_memory_manager,
													 total_cost_xml);
	CWStringDynamic *rows_out_str =
		CDXLUtils::CreateDynamicStringFromXMLChArray(dxl_memory_manager,
													 rows_xml);
	CWStringDynamic *width_str = CDXLUtils::CreateDynamicStringFromXMLChArray(
		dxl_memory_manager, width_xml);

	return GPOS_NEW(mp) CDXLOperatorCost(startup_cost_str, total_cost_str,
										 rows_out_str, width_str);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLTableDescr
//
//	@doc:
//		Construct a table descriptor
//
//---------------------------------------------------------------------------
CDXLTableDescr *
CDXLOperatorFactory::MakeDXLTableDescr(CDXLMemoryManager *dxl_memory_manager,
									   const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse table descriptor from attributes
	const XMLCh *xml_str_table_name =
		ExtractAttrValue(attrs, EdxltokenTableName, EdxltokenTableDescr);

	CMDName *mdname = CDXLUtils::CreateMDNameFromXMLChar(dxl_memory_manager,
														 xml_str_table_name);

	// parse metadata id
	IMDId *mdid = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenMdid, EdxltokenTableDescr);

	// parse execute as user value if the attribute is specified
	ULONG user_id = GPDXL_DEFAULT_USERID;
	const XMLCh *execute_as_user_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenExecuteAsUser));

	INT lockmode = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenLockMode, EdxltokenTableDescr,
		true /* is_optional */, -1);

	ULONG acl_mode = ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenAclMode, EdxltokenTableDescr,
		true /* is_optional */, GPDXL_ACL_UNDEFINED);

	if (nullptr != execute_as_user_xml)
	{
		user_id = ConvertAttrValueToUlong(
			dxl_memory_manager, execute_as_user_xml, EdxltokenExecuteAsUser,
			EdxltokenTableDescr);
	}

	ULONG assigned_query_id_for_target_rel = ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenAssignedQueryIdForTargetRel,
		EdxltokenTableDescr, true /* is_optional */, UNASSIGNED_QUERYID);

	return GPOS_NEW(mp)
		CDXLTableDescr(mp, mdid, mdname, user_id, lockmode, acl_mode,
					   assigned_query_id_for_target_rel);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLIndexDescr
//
//	@doc:
//		Construct an index descriptor
//
//---------------------------------------------------------------------------
CDXLIndexDescr *
CDXLOperatorFactory::MakeDXLIndexDescr(CDXLMemoryManager *dxl_memory_manager,
									   const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse index descriptor from attributes
	const XMLCh *index_name_xml =
		ExtractAttrValue(attrs, EdxltokenIndexName, EdxltokenIndexDescr);

	CWStringDynamic *index_name = CDXLUtils::CreateDynamicStringFromXMLChArray(
		dxl_memory_manager, index_name_xml);

	// parse metadata id
	IMDId *mdid = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenMdid, EdxltokenIndexDescr);

	// create a copy of the string in the CMDName constructor
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, index_name);
	GPOS_DELETE(index_name);

	return GPOS_NEW(mp) CDXLIndexDescr(mdid, mdname);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeColumnDescr
//
//	@doc:
//		Construct a column descriptor
//
//---------------------------------------------------------------------------
CDXLColDescr *
CDXLOperatorFactory::MakeColumnDescr(CDXLMemoryManager *dxl_memory_manager,
									 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse column name from attributes
	const XMLCh *column_name_xml =
		ExtractAttrValue(attrs, EdxltokenColName, EdxltokenColDescr);

	// parse column id
	ULONG id = ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenColId, EdxltokenColDescr);

	// parse attno
	INT attno = ExtractConvertAttrValueToInt(dxl_memory_manager, attrs,
											 EdxltokenAttno, EdxltokenColDescr);

	if (0 == attno)
	{
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(EdxltokenAttno)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(EdxltokenColDescr)->GetBuffer());
	}

	// parse column type id
	IMDId *mdid_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId, EdxltokenColDescr);

	// parse optional type modifier from attributes
	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod, EdxltokenColDescr, true,
		default_type_modifier);

	BOOL col_dropped = false;

	const XMLCh *col_dropped_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenColDropped));

	if (nullptr != col_dropped_xml)
	{
		// attribute is present: get value
		col_dropped =
			ConvertAttrValueToBool(dxl_memory_manager, col_dropped_xml,
								   EdxltokenColDropped, EdxltokenColDescr);
	}

	ULONG col_len = gpos::ulong_max;

	// parse column length from attributes
	const XMLCh *col_len_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenColWidth));

	if (nullptr != col_len_xml)
	{
		col_len = ConvertAttrValueToUlong(dxl_memory_manager, col_len_xml,
										  EdxltokenColWidth, EdxltokenColDescr);
	}

	CWStringDynamic *col_name = CDXLUtils::CreateDynamicStringFromXMLChArray(
		dxl_memory_manager, column_name_xml);

	// create a copy of the string in the CMDName constructor
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, col_name);

	GPOS_DELETE(col_name);

	return GPOS_NEW(mp) CDXLColDescr(mdname, id, attno, mdid_type,
									 type_modifier, col_dropped, col_len);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeDXLColRef
//
//	@doc:
//		Construct a column reference
//
//---------------------------------------------------------------------------
CDXLColRef *
CDXLOperatorFactory::MakeDXLColRef(CDXLMemoryManager *dxl_memory_manager,
								   const Attributes &attrs,
								   Edxltoken target_elem)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	// parse column name from attributes
	const XMLCh *column_name_xml =
		ExtractAttrValue(attrs, EdxltokenColName, target_elem);

	// parse column id
	ULONG id = 0;
	const XMLCh *colid_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenColId));
	if (nullptr == colid_xml)
	{
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLMissingAttribute,
				   CDXLTokens::GetDXLTokenStr(EdxltokenColRef)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(target_elem)->GetBuffer());
	}

	id = XMLString::parseInt(colid_xml, dxl_memory_manager);

	CWStringDynamic *col_name = CDXLUtils::CreateDynamicStringFromXMLChArray(
		dxl_memory_manager, column_name_xml);

	// create a copy of the string in the CMDName constructor
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, col_name);

	GPOS_DELETE(col_name);

	IMDId *mdid_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId, target_elem);

	// parse optional type modifier
	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod, target_elem, true,
		default_type_modifier);

	return GPOS_NEW(mp) CDXLColRef(mdname, id, mdid_type, type_modifier);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseOutputSegId
//
//	@doc:
//		Parse an output segment index
//
//---------------------------------------------------------------------------
INT
CDXLOperatorFactory::ParseOutputSegId(CDXLMemoryManager *dxl_memory_manager,
									  const Attributes &attrs)
{
	// get output segment index from attributes
	const XMLCh *seg_id_xml =
		ExtractAttrValue(attrs, EdxltokenSegId, EdxltokenSegment);

	// parse segment id from string
	INT segment_id = -1;
	try
	{
		segment_id = XMLString::parseInt(seg_id_xml, dxl_memory_manager);
	}
	catch (const NumberFormatException &toCatch)
	{
		// turn Xerces exception into GPOS exception
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(EdxltokenSegId)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(EdxltokenSegment)->GetBuffer());
	}

	return segment_id;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractAttrValue
//
//	@doc:
//    	Extracts the value for the given attribute.
// 		If there is no such attribute defined, and the given optional
// 		flag is set to false then it will raise an exception
//---------------------------------------------------------------------------
const XMLCh *
CDXLOperatorFactory::ExtractAttrValue(const Attributes &attrs,
									  Edxltoken target_attr,
									  Edxltoken target_elem, BOOL is_optional)
{
	const XMLCh *attribute_val_xml =
		attrs.getValue(CDXLTokens::XmlstrToken(target_attr));

	if (nullptr == attribute_val_xml && !is_optional)
	{
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLMissingAttribute,
				   CDXLTokens::GetDXLTokenStr(target_attr)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(target_elem)->GetBuffer());
	}

	return attribute_val_xml;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ConvertAttrValueToUlong
//
//	@doc:
//	  	Converts the attribute value to ULONG
//
//---------------------------------------------------------------------------
ULONG
CDXLOperatorFactory::ConvertAttrValueToUlong(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *attribute_val_xml,
	Edxltoken target_attr, Edxltoken target_elem)
{
	GPOS_ASSERT(attribute_val_xml != nullptr);
	ULONG attr = 0;
	try
	{
		attr = XMLString::parseInt(attribute_val_xml, dxl_memory_manager);
	}
	catch (const NumberFormatException &toCatch)
	{
		// turn Xerces exception into GPOS exception
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(target_attr)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(target_elem)->GetBuffer());
	}
	return attr;
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ConvertAttrValueToUllong
//
//	@doc:
//	  	Converts the attribute value to ULLONG
//
//---------------------------------------------------------------------------
ULLONG
CDXLOperatorFactory::ConvertAttrValueToUllong(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *attribute_val_xml,
	Edxltoken target_attr, Edxltoken target_elem)
{
	GPOS_ASSERT(attribute_val_xml != nullptr);

	CHAR *attr = XMLString::transcode(attribute_val_xml, dxl_memory_manager);
	GPOS_ASSERT(nullptr != attr);

	CHAR **end = nullptr;
	LINT converted_val = clib::Strtoll(attr, end, 10 /*ulBase*/);

	if ((nullptr != end && attr == *end) || gpos::lint_max == converted_val ||
		gpos::lint_min == converted_val || 0 > converted_val)
	{
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(target_attr)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(target_elem)->GetBuffer());
	}

	XMLString::release(&attr, dxl_memory_manager);

	return (ULLONG) converted_val;
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ConvertAttrValueToBool
//
//	@doc:
//	  	Converts the attribute value to BOOL
//
//---------------------------------------------------------------------------
BOOL
CDXLOperatorFactory::ConvertAttrValueToBool(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *attribute_val_xml,
	Edxltoken target_attr, Edxltoken target_elem)
{
	GPOS_ASSERT(attribute_val_xml != nullptr);
	BOOL flag = false;
	CHAR *attr = XMLString::transcode(attribute_val_xml, dxl_memory_manager);

	if (0 == strncasecmp(attr, "true", 4))
	{
		flag = true;
	}
	else if (0 != strncasecmp(attr, "false", 5))
	{
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(target_attr)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(target_elem)->GetBuffer());
	}

	XMLString::release(&attr, dxl_memory_manager);
	return flag;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ConvertAttrValueToInt
//
//	@doc:
//	  	Converts the attribute value from xml string to INT
//
//---------------------------------------------------------------------------
INT
CDXLOperatorFactory::ConvertAttrValueToInt(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *attribute_val_xml,
	Edxltoken target_attr, Edxltoken target_elem)
{
	GPOS_ASSERT(attribute_val_xml != nullptr);
	INT attr = 0;
	try
	{
		attr = XMLString::parseInt(attribute_val_xml, dxl_memory_manager);
	}
	catch (const NumberFormatException &toCatch)
	{
		// turn Xerces exception into GPOS exception
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(target_attr)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(target_elem)->GetBuffer());
	}
	return attr;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToInt
//
//	@doc:
//	  	Extracts the value for the given attribute and converts it into INT
//
//---------------------------------------------------------------------------
INT
CDXLOperatorFactory::ExtractConvertAttrValueToInt(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem, BOOL is_optional,
	INT default_val)
{
	const XMLCh *attr_val_xml = CDXLOperatorFactory::ExtractAttrValue(
		attrs, target_attr, target_elem, is_optional);

	if (nullptr == attr_val_xml)
	{
		return default_val;
	}

	return ConvertAttrValueToInt(dxl_memory_manager, attr_val_xml, target_attr,
								 target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ConvertAttrValueToShortInt
//
//	@doc:
//	  	Converts the attribute value from xml string to short int
//
//---------------------------------------------------------------------------
SINT
CDXLOperatorFactory::ConvertAttrValueToShortInt(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *attribute_val_xml,
	Edxltoken target_attr, Edxltoken target_elem)
{
	GPOS_ASSERT(attribute_val_xml != nullptr);
	SINT attr = 0;
	try
	{
		attr =
			(SINT) XMLString::parseInt(attribute_val_xml, dxl_memory_manager);
	}
	catch (const NumberFormatException &toCatch)
	{
		// turn Xerces exception into GPOS exception
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(target_attr)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(target_elem)->GetBuffer());
	}
	return attr;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToShortInt
//
//	@doc:
//	  	Extracts the value for the given attribute and converts it into short
//		int
//
//---------------------------------------------------------------------------
SINT
CDXLOperatorFactory::ExtractConvertAttrValueToShortInt(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem, BOOL is_optional,
	SINT default_val)
{
	const XMLCh *attr_val_xml = CDXLOperatorFactory::ExtractAttrValue(
		attrs, target_attr, target_elem, is_optional);

	if (nullptr == attr_val_xml)
	{
		return default_val;
	}

	return ConvertAttrValueToShortInt(dxl_memory_manager, attr_val_xml,
									  target_attr, target_elem);
}

// Converts the attribute value from xml string to char
CHAR
CDXLOperatorFactory::ConvertAttrValueToChar(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *xml_val,
	Edxltoken,	// target_attr,
	Edxltoken	// target_elem
)
{
	GPOS_ASSERT(xml_val != nullptr);
	CHAR *attr = XMLString::transcode(xml_val, dxl_memory_manager);
	CHAR val = *attr;
	XMLString::release(&attr, dxl_memory_manager);
	return val;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ConvertAttrValueToOid
//
//	@doc:
//	  	Converts the attribute value to OID
//
//---------------------------------------------------------------------------
OID
CDXLOperatorFactory::ConvertAttrValueToOid(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *attribute_val_xml,
	Edxltoken target_attr, Edxltoken target_elem)
{
	GPOS_ASSERT(attribute_val_xml != nullptr);
	OID oid = 0;
	try
	{
		oid = XMLString::parseInt(attribute_val_xml, dxl_memory_manager);
	}
	catch (const NumberFormatException &toCatch)
	{
		// turn Xerces exception into GPOS exception
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(target_attr)->GetBuffer(),
				   CDXLTokens::GetDXLTokenStr(target_elem)->GetBuffer());
	}
	return oid;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToOid
//
//	@doc:
//	  	Extracts the value for the given attribute and converts it into OID
//
//---------------------------------------------------------------------------
OID
CDXLOperatorFactory::ExtractConvertAttrValueToOid(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem, BOOL is_optional,
	OID OidDefaultValue)
{
	const XMLCh *attr_val_xml = CDXLOperatorFactory::ExtractAttrValue(
		attrs, target_attr, target_elem, is_optional);

	if (nullptr == attr_val_xml)
	{
		return OidDefaultValue;
	}

	return ConvertAttrValueToOid(dxl_memory_manager, attr_val_xml, target_attr,
								 target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ConvertAttrValueToSz
//
//	@doc:
//	  	Converts the string attribute value
//
//---------------------------------------------------------------------------
CHAR *
CDXLOperatorFactory::ConvertAttrValueToSz(CDXLMemoryManager *dxl_memory_manager,
										  const XMLCh *xml_val,
										  Edxltoken,  // target_attr,
										  Edxltoken	  // target_elem
)
{
	GPOS_ASSERT(nullptr != xml_val);
	return XMLString::transcode(xml_val, dxl_memory_manager);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToSz
//
//	@doc:
//	  	Extracts the value for the given attribute and converts it into CHAR*
//
//---------------------------------------------------------------------------
CHAR *
CDXLOperatorFactory::ExtractConvertAttrValueToSz(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem, BOOL is_optional,
	CHAR *default_value)
{
	const XMLCh *attr_val_xml = CDXLOperatorFactory::ExtractAttrValue(
		attrs, target_attr, target_elem, is_optional);

	if (nullptr == attr_val_xml)
	{
		return default_value;
	}

	return CDXLOperatorFactory::ConvertAttrValueToSz(
		dxl_memory_manager, attr_val_xml, target_attr, target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToStr
//
//	@doc:
//	  	Extracts the string value for the given attribute
//
//---------------------------------------------------------------------------
CWStringDynamic *
CDXLOperatorFactory::ExtractConvertAttrValueToStr(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem)
{
	const XMLCh *attr_val_xml =
		CDXLOperatorFactory::ExtractAttrValue(attrs, target_attr, target_elem);
	return CDXLUtils::CreateDynamicStringFromXMLChArray(dxl_memory_manager,
														attr_val_xml);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToBool
//
//	@doc:
//	  	Extracts the value for the given attribute and converts it into BOOL
//
//---------------------------------------------------------------------------
BOOL
CDXLOperatorFactory::ExtractConvertAttrValueToBool(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem, BOOL is_optional,
	BOOL default_value)
{
	const XMLCh *attr_val_xml = CDXLOperatorFactory::ExtractAttrValue(
		attrs, target_attr, target_elem, is_optional);

	if (nullptr == attr_val_xml)
	{
		return default_value;
	}

	return ConvertAttrValueToBool(dxl_memory_manager, attr_val_xml, target_attr,
								  target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToUlong
//
//	@doc:
//	  	Extracts the value for the given attribute and converts it into ULONG
//
//---------------------------------------------------------------------------
ULONG
CDXLOperatorFactory::ExtractConvertAttrValueToUlong(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem, BOOL is_optional,
	ULONG default_value)
{
	const XMLCh *attr_val_xml = CDXLOperatorFactory::ExtractAttrValue(
		attrs, target_attr, target_elem, is_optional);

	if (nullptr == attr_val_xml)
	{
		return default_value;
	}

	return ConvertAttrValueToUlong(dxl_memory_manager, attr_val_xml,
								   target_attr, target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToUllong
//
//	@doc:
//	  	Extracts the value for the given attribute and converts it into ULLONG
//
//---------------------------------------------------------------------------
ULLONG
CDXLOperatorFactory::ExtractConvertAttrValueToUllong(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem, BOOL is_optional,
	ULLONG default_value)
{
	const XMLCh *attr_val_xml = CDXLOperatorFactory::ExtractAttrValue(
		attrs, target_attr, target_elem, is_optional);

	if (nullptr == attr_val_xml)
	{
		return default_value;
	}

	return ConvertAttrValueToUllong(dxl_memory_manager, attr_val_xml,
									target_attr, target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseGroupingColId
//
//	@doc:
//		Parse a grouping column id
//
//---------------------------------------------------------------------------
ULONG
CDXLOperatorFactory::ParseGroupingColId(CDXLMemoryManager *dxl_memory_manager,
										const Attributes &attrs)
{
	const CWStringConst *grouping_colid_str =
		CDXLTokens::GetDXLTokenStr(EdxltokenGroupingCol);
	const CWStringConst *colid_str = CDXLTokens::GetDXLTokenStr(EdxltokenColId);

	// get grouping column id from attributes
	INT colid = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenColId, EdxltokenGroupingCol);

	if (colid < 0)
	{
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   colid_str->GetBuffer(), grouping_colid_str->GetBuffer());
	}

	return (ULONG) colid;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToMdId
//
//	@doc:
//		Parse a metadata id object from the XML attributes of the specified element.
//
//---------------------------------------------------------------------------
IMDId *
CDXLOperatorFactory::ExtractConvertAttrValueToMdId(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem, BOOL is_optional,
	IMDId *default_val)
{
	// extract mdid
	const XMLCh *mdid_xml =
		ExtractAttrValue(attrs, target_attr, target_elem, is_optional);

	if (nullptr == mdid_xml)
	{
		if (nullptr != default_val)
		{
			default_val->AddRef();
		}

		return default_val;
	}

	return MakeMdIdFromStr(dxl_memory_manager, mdid_xml, target_attr,
						   target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeMdIdFromStr
//
//	@doc:
//		Parse a metadata id object from the XML attributes of the specified element.
//
//---------------------------------------------------------------------------
IMDId *
CDXLOperatorFactory::MakeMdIdFromStr(CDXLMemoryManager *dxl_memory_manager,
									 const XMLCh *mdid_xml,
									 Edxltoken target_attr,
									 Edxltoken target_elem)
{
	// extract mdid's components: MdidType.Oid.Major.Minor
	XMLStringTokenizer mdid_components(
		mdid_xml, CDXLTokens::XmlstrToken(EdxltokenDotSemicolon));

	GPOS_ASSERT(1 < mdid_components.countTokens());

	// get mdid type from first component
	XMLCh *mdid_type = mdid_components.nextToken();

	// collect the remaining tokens in an array
	XMLChArray *remaining_tokens = GPOS_NEW(dxl_memory_manager->Pmp())
		XMLChArray(dxl_memory_manager->Pmp());

	XMLCh *xml_val = nullptr;
	while (nullptr != (xml_val = mdid_components.nextToken()))
	{
		remaining_tokens->Append(xml_val);
	}

	IMDId::EMDIdType typ = (IMDId::EMDIdType) ConvertAttrValueToUlong(
		dxl_memory_manager, mdid_type, target_attr, target_elem);

	IMDId *mdid = nullptr;
	switch (typ)
	{
		case IMDId::EmdidGeneral:
		case IMDId::EmdidRel:
		case IMDId::EmdidInd:
		case IMDId::EmdidCheckConstraint:
		case IMDId::EmdidExtStatsInfo:
		case IMDId::EmdidExtStats:
			mdid = GetGPDBMdId(dxl_memory_manager, remaining_tokens,
							   target_attr, target_elem, typ);
			break;

		case IMDId::EmdidGPDBCtas:
			mdid = GetGPDBCTASMdId(dxl_memory_manager, remaining_tokens,
								   target_attr, target_elem);
			break;

		case IMDId::EmdidColStats:
			mdid = GetColStatsMdId(dxl_memory_manager, remaining_tokens,
								   target_attr, target_elem);
			break;

		case IMDId::EmdidRelStats:
			mdid = GetRelStatsMdId(dxl_memory_manager, remaining_tokens,
								   target_attr, target_elem);
			break;

		case IMDId::EmdidCastFunc:
			mdid = GetCastFuncMdId(dxl_memory_manager, remaining_tokens,
								   target_attr, target_elem);
			break;

		case IMDId::EmdidScCmp:
			mdid = GetScCmpMdId(dxl_memory_manager, remaining_tokens,
								target_attr, target_elem);
			break;

		default:
			GPOS_ASSERT(!"Unrecognized mdid type");
	}

	remaining_tokens->Release();

	return mdid;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetGPDBMdId
//
//	@doc:
//		Construct a GPDB mdid from an array of XML string components.
//
//---------------------------------------------------------------------------
CMDIdGPDB *
CDXLOperatorFactory::GetGPDBMdId(CDXLMemoryManager *dxl_memory_manager,
								 XMLChArray *remaining_tokens,
								 Edxltoken target_attr, Edxltoken target_elem,
								 IMDId::EMDIdType mdidType)
{
	GPOS_ASSERT(GPDXL_GPDB_MDID_COMPONENTS <= remaining_tokens->Size());

	XMLCh *xml_oid = (*remaining_tokens)[0];
	ULONG oid_colid = ConvertAttrValueToUlong(dxl_memory_manager, xml_oid,
											  target_attr, target_elem);

	XMLCh *version_major_xml = (*remaining_tokens)[1];
	ULONG version_major = ConvertAttrValueToUlong(
		dxl_memory_manager, version_major_xml, target_attr, target_elem);

	XMLCh *xmlszVersionMinor = (*remaining_tokens)[2];
	;
	ULONG version_minor = ConvertAttrValueToUlong(
		dxl_memory_manager, xmlszVersionMinor, target_attr, target_elem);

	// construct metadata id object
	return GPOS_NEW(dxl_memory_manager->Pmp())
		CMDIdGPDB(mdidType, oid_colid, version_major, version_minor);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetGPDBCTASMdId
//
//	@doc:
//		Construct a GPDB CTAS mdid from an array of XML string components.
//
//---------------------------------------------------------------------------
CMDIdGPDB *
CDXLOperatorFactory::GetGPDBCTASMdId(CDXLMemoryManager *dxl_memory_manager,
									 XMLChArray *remaining_tokens,
									 Edxltoken target_attr,
									 Edxltoken target_elem)
{
	GPOS_ASSERT(GPDXL_GPDB_MDID_COMPONENTS <= remaining_tokens->Size());

	XMLCh *xml_oid = (*remaining_tokens)[0];
	ULONG oid_colid = ConvertAttrValueToUlong(dxl_memory_manager, xml_oid,
											  target_attr, target_elem);

	// construct metadata id object
	return GPOS_NEW(dxl_memory_manager->Pmp()) CMDIdGPDBCtas(oid_colid);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetColStatsMdId
//
//	@doc:
//		Construct a column stats mdid from an array of XML string components.
//
//---------------------------------------------------------------------------
CMDIdColStats *
CDXLOperatorFactory::GetColStatsMdId(CDXLMemoryManager *dxl_memory_manager,
									 XMLChArray *remaining_tokens,
									 Edxltoken target_attr,
									 Edxltoken target_elem)
{
	GPOS_ASSERT(GPDXL_GPDB_MDID_COMPONENTS + 1 == remaining_tokens->Size());

	CMDIdGPDB *rel_mdid =
		GetGPDBMdId(dxl_memory_manager, remaining_tokens, target_attr,
					target_elem, IMDId::EmdidRel);

	XMLCh *attno_xml = (*remaining_tokens)[3];
	ULONG attno = ConvertAttrValueToUlong(dxl_memory_manager, attno_xml,
										  target_attr, target_elem);

	// construct metadata id object
	return GPOS_NEW(dxl_memory_manager->Pmp()) CMDIdColStats(rel_mdid, attno);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetRelStatsMdId
//
//	@doc:
//		Construct a relation stats mdid from an array of XML string components.
//
//---------------------------------------------------------------------------
CMDIdRelStats *
CDXLOperatorFactory::GetRelStatsMdId(CDXLMemoryManager *dxl_memory_manager,
									 XMLChArray *remaining_tokens,
									 Edxltoken target_attr,
									 Edxltoken target_elem)
{
	GPOS_ASSERT(GPDXL_GPDB_MDID_COMPONENTS == remaining_tokens->Size());

	CMDIdGPDB *rel_mdid =
		GetGPDBMdId(dxl_memory_manager, remaining_tokens, target_attr,
					target_elem, IMDId::EmdidRel);

	// construct metadata id object
	return GPOS_NEW(dxl_memory_manager->Pmp()) CMDIdRelStats(rel_mdid);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetCastFuncMdId
//
//	@doc:
//		Construct a cast function mdid from the array of XML string components.
//
//---------------------------------------------------------------------------
CMDIdCast *
CDXLOperatorFactory::GetCastFuncMdId(CDXLMemoryManager *dxl_memory_manager,
									 XMLChArray *remaining_tokens,
									 Edxltoken target_attr,
									 Edxltoken target_elem)
{
	GPOS_ASSERT(2 * GPDXL_GPDB_MDID_COMPONENTS == remaining_tokens->Size());

	CMDIdGPDB *mdid_src = GetGPDBMdId(dxl_memory_manager, remaining_tokens,
									  target_attr, target_elem);
	XMLChArray *dest_xml = GPOS_NEW(dxl_memory_manager->Pmp())
		XMLChArray(dxl_memory_manager->Pmp());

	for (ULONG ul = GPDXL_GPDB_MDID_COMPONENTS;
		 ul < GPDXL_GPDB_MDID_COMPONENTS * 2; ul++)
	{
		dest_xml->Append((*remaining_tokens)[ul]);
	}

	CMDIdGPDB *mdid_dest =
		GetGPDBMdId(dxl_memory_manager, dest_xml, target_attr, target_elem);
	dest_xml->Release();

	return GPOS_NEW(dxl_memory_manager->Pmp()) CMDIdCast(mdid_src, mdid_dest);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetScCmpMdId
//
//	@doc:
//		Construct a scalar comparison operator mdid from the array of XML string components.
//
//---------------------------------------------------------------------------
CMDIdScCmp *
CDXLOperatorFactory::GetScCmpMdId(CDXLMemoryManager *dxl_memory_manager,
								  XMLChArray *remaining_tokens,
								  Edxltoken target_attr, Edxltoken target_elem)
{
	GPOS_ASSERT(2 * GPDXL_GPDB_MDID_COMPONENTS + 1 == remaining_tokens->Size());

	CMDIdGPDB *left_mdid = GetGPDBMdId(dxl_memory_manager, remaining_tokens,
									   target_attr, target_elem);
	XMLChArray *right_xml = GPOS_NEW(dxl_memory_manager->Pmp())
		XMLChArray(dxl_memory_manager->Pmp());

	for (ULONG ul = GPDXL_GPDB_MDID_COMPONENTS;
		 ul < GPDXL_GPDB_MDID_COMPONENTS * 2 + 1; ul++)
	{
		right_xml->Append((*remaining_tokens)[ul]);
	}

	CMDIdGPDB *right_mdid =
		GetGPDBMdId(dxl_memory_manager, right_xml, target_attr, target_elem);

	// parse the comparison type from the last component of the mdid
	XMLCh *xml_str_comp_type = (*right_xml)[right_xml->Size() - 1];
	IMDType::ECmpType cmp_type = (IMDType::ECmpType) ConvertAttrValueToUlong(
		dxl_memory_manager, xml_str_comp_type, target_attr, target_elem);
	GPOS_ASSERT(IMDType::EcmptOther > cmp_type);

	right_xml->Release();

	return GPOS_NEW(dxl_memory_manager->Pmp())
		CMDIdScCmp(left_mdid, right_mdid, cmp_type);
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetDatumVal
//
//	@doc:
//		Parses a DXL datum from the given attributes
//
//---------------------------------------------------------------------------
CDXLDatum *
CDXLOperatorFactory::GetDatumVal(CDXLMemoryManager *dxl_memory_manager,
								 const Attributes &attrs, Edxltoken target_elem)
{
	// get the type id and value of the datum from attributes
	IMDId *mdid = ExtractConvertAttrValueToMdId(dxl_memory_manager, attrs,
												EdxltokenTypeId, target_elem);
	GPOS_ASSERT(IMDId::EmdidGeneral == mdid->MdidType());
	CMDIdGPDB *gpdb_mdid = CMDIdGPDB::CastMdid(mdid);

	// get the type id from string
	BOOL is_const_null = ExtractConvertAttrValueToBool(
		dxl_memory_manager, attrs, EdxltokenIsNull, target_elem, true, false);

	switch (gpdb_mdid->Oid())
	{
		default:
		{
			const XMLCh *attr_val_xml =
				attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenLintValue));
			if (attr_val_xml)
			{
				return GetDatumStatsLintMappable(dxl_memory_manager, attrs,
												 target_elem, mdid,
												 is_const_null);
			}
			// generate a datum of generic type
			return GetDatumGeneric(dxl_memory_manager, attrs, target_elem, mdid,
								   is_const_null);
		}
		// native support
		case GPDB_INT2:
		{
			return GetDatumInt2(dxl_memory_manager, attrs, target_elem, mdid,
								is_const_null);
		}
		case GPDB_INT4:
		{
			return GetDatumInt4(dxl_memory_manager, attrs, target_elem, mdid,
								is_const_null);
		}
		case GPDB_INT8:
		{
			return GetDatumInt8(dxl_memory_manager, attrs, target_elem, mdid,
								is_const_null);
		}
		case GPDB_BOOL:
		{
			return GetDatumBool(dxl_memory_manager, attrs, target_elem, mdid,
								is_const_null);
		}
		case GPDB_OID:
		{
			return GetDatumOid(dxl_memory_manager, attrs, target_elem, mdid,
							   is_const_null);
		}
		// types with long int mapping
		case GPDB_CHAR:
		case GPDB_VARCHAR:
		case GPDB_TEXT:
		case GPDB_CASH:
		case GPDB_UUID:
		{
			return GetDatumStatsLintMappable(dxl_memory_manager, attrs,
											 target_elem, mdid, is_const_null);
		}
		// non-integer numeric types
		case GPDB_NUMERIC:
		case GPDB_FLOAT4:
		case GPDB_FLOAT8:
		// network-related types
		case GPDB_INET:
		case GPDB_CIDR:
		case GPDB_MACADDR:
		// time-related types
		case GPDB_DATE:
		case GPDB_TIME:
		case GPDB_TIMETZ:
		case GPDB_TIMESTAMP:
		case GPDB_TIMESTAMPTZ:
		case GPDB_ABSTIME:
		case GPDB_RELTIME:
		case GPDB_INTERVAL:
		case GPDB_TIMEINTERVAL:
		{
			return GetDatumStatsDoubleMappable(
				dxl_memory_manager, attrs, target_elem, mdid, is_const_null);
		}
	}
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetDatumOid
//
//	@doc:
//		Parses a DXL datum of oid type
//
//---------------------------------------------------------------------------
CDXLDatum *
CDXLOperatorFactory::GetDatumOid(CDXLMemoryManager *dxl_memory_manager,
								 const Attributes &attrs, Edxltoken target_elem,
								 IMDId *mdid, BOOL is_const_null)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	OID val = 0;
	if (!is_const_null)
	{
		val = ExtractConvertAttrValueToOid(dxl_memory_manager, attrs,
										   EdxltokenValue, target_elem);
	}

	return GPOS_NEW(mp) CDXLDatumOid(mp, mdid, is_const_null, val);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetDatumInt2
//
//	@doc:
//		Parses a DXL datum of int2 type
//
//---------------------------------------------------------------------------
CDXLDatum *
CDXLOperatorFactory::GetDatumInt2(CDXLMemoryManager *dxl_memory_manager,
								  const Attributes &attrs,
								  Edxltoken target_elem, IMDId *mdid,
								  BOOL is_const_null)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	SINT val = 0;
	if (!is_const_null)
	{
		val = ExtractConvertAttrValueToShortInt(dxl_memory_manager, attrs,
												EdxltokenValue, target_elem);
	}

	return GPOS_NEW(mp) CDXLDatumInt2(mp, mdid, is_const_null, val);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetDatumInt4
//
//	@doc:
//		Parses a DXL datum of int4 type
//
//---------------------------------------------------------------------------
CDXLDatum *
CDXLOperatorFactory::GetDatumInt4(CDXLMemoryManager *dxl_memory_manager,
								  const Attributes &attrs,
								  Edxltoken target_elem, IMDId *mdid,
								  BOOL is_const_null)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	INT val = 0;
	if (!is_const_null)
	{
		val = ExtractConvertAttrValueToInt(dxl_memory_manager, attrs,
										   EdxltokenValue, target_elem);
	}

	return GPOS_NEW(mp) CDXLDatumInt4(mp, mdid, is_const_null, val);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetDatumInt8
//
//	@doc:
//		Parses a DXL datum of int8 type
//
//---------------------------------------------------------------------------
CDXLDatum *
CDXLOperatorFactory::GetDatumInt8(CDXLMemoryManager *dxl_memory_manager,
								  const Attributes &attrs,
								  Edxltoken target_elem, IMDId *mdid,
								  BOOL is_const_null)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	LINT val = 0;
	if (!is_const_null)
	{
		val = ExtractConvertAttrValueToLint(dxl_memory_manager, attrs,
											EdxltokenValue, target_elem);
	}

	return GPOS_NEW(mp) CDXLDatumInt8(mp, mdid, is_const_null, val);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetDatumBool
//
//	@doc:
//		Parses a DXL datum of boolean type
//
//---------------------------------------------------------------------------
CDXLDatum *
CDXLOperatorFactory::GetDatumBool(CDXLMemoryManager *dxl_memory_manager,
								  const Attributes &attrs,
								  Edxltoken target_elem, IMDId *mdid,
								  BOOL is_const_null)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	BOOL value = false;
	if (!is_const_null)
	{
		value = ExtractConvertAttrValueToBool(dxl_memory_manager, attrs,
											  EdxltokenValue, target_elem);
	}

	return GPOS_NEW(mp) CDXLDatumBool(mp, mdid, is_const_null, value);
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetDatumGeneric
//
//	@doc:
//		Parses a DXL datum of generic type
//
//---------------------------------------------------------------------------
CDXLDatum *
CDXLOperatorFactory::GetDatumGeneric(CDXLMemoryManager *dxl_memory_manager,
									 const Attributes &attrs,
									 Edxltoken target_elem, IMDId *mdid,
									 BOOL is_const_null)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	ULONG len = 0;
	BYTE *data = nullptr;

	if (!is_const_null)
	{
		data = GetByteArray(dxl_memory_manager, attrs, target_elem, &len);
		if (nullptr == data)
		{
			// unable to decode value. probably not Base64 encoded.
			GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
					   CDXLTokens::XmlstrToken(EdxltokenValue),
					   CDXLTokens::GetDXLTokenStr(target_elem));
		}
	}

	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod, EdxltokenScalarCast, true,
		default_type_modifier);

	return GPOS_NEW(mp)
		CDXLDatumGeneric(mp, mdid, type_modifier, is_const_null, data, len);
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetDatumStatsLintMappable
//
//	@doc:
//		Parses a DXL datum of types having lint mapping
//
//---------------------------------------------------------------------------
CDXLDatum *
CDXLOperatorFactory::GetDatumStatsLintMappable(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_elem, IMDId *mdid, BOOL is_const_null)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	ULONG len = 0;
	BYTE *data = nullptr;

	LINT value = 0;
	if (!is_const_null)
	{
		data = GetByteArray(dxl_memory_manager, attrs, target_elem, &len);
		value = Value(dxl_memory_manager, attrs, target_elem, data);
	}

	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod, EdxltokenScalarCast, true,
		-1 /* default_val value */
	);

	return GPOS_NEW(mp) CDXLDatumStatsLintMappable(
		mp, mdid, type_modifier, is_const_null, data, len, value);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::Value
//
//	@doc:
//		Return the LINT value of byte array
//
//---------------------------------------------------------------------------
LINT
CDXLOperatorFactory::Value(CDXLMemoryManager *dxl_memory_manager,
						   const Attributes &attrs, Edxltoken target_elem,
						   const BYTE *data)
{
	if (nullptr == data)
	{
		// unable to decode value. probably not Base64 encoded.
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::XmlstrToken(EdxltokenValue),
				   CDXLTokens::GetDXLTokenStr(target_elem));
	}

	return ExtractConvertAttrValueToLint(dxl_memory_manager, attrs,
										 EdxltokenLintValue, target_elem);
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetByteArray
//
//	@doc:
//		Parses a byte array representation of the datum
//
//---------------------------------------------------------------------------
BYTE *
CDXLOperatorFactory::GetByteArray(CDXLMemoryManager *dxl_memory_manager,
								  const Attributes &attrs,
								  Edxltoken target_elem, ULONG *length)
{
	const XMLCh *attr_val_xml =
		ExtractAttrValue(attrs, EdxltokenValue, target_elem);

	return CDXLUtils::CreateStringFrom64XMLStr(dxl_memory_manager, attr_val_xml,
											   length);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::GetDatumStatsDoubleMappable
//
//	@doc:
//		Parses a DXL datum of types that need double mapping
//
//---------------------------------------------------------------------------
CDXLDatum *
CDXLOperatorFactory::GetDatumStatsDoubleMappable(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_elem, IMDId *mdid, BOOL is_const_null)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	ULONG len = 0;
	BYTE *data = nullptr;
	CDouble value = 0;

	if (!is_const_null)
	{
		data = GetByteArray(dxl_memory_manager, attrs, target_elem, &len);

		if (nullptr == data)
		{
			// unable to decode value. probably not Base64 encoded.
			GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
					   CDXLTokens::XmlstrToken(EdxltokenValue),
					   CDXLTokens::GetDXLTokenStr(target_elem));
		}

		value = ExtractConvertAttrValueToDouble(
			dxl_memory_manager, attrs, EdxltokenDoubleValue, target_elem);
	}
	INT type_modifier = ExtractConvertAttrValueToInt(
		dxl_memory_manager, attrs, EdxltokenTypeMod, EdxltokenScalarCast, true,
		-1 /* default_val value */
	);
	return GPOS_NEW(mp) CDXLDatumStatsDoubleMappable(
		mp, mdid, type_modifier, is_const_null, data, len, value);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertValuesToArray
//
//	@doc:
//		Parse a comma-separated list of unsigned long integers ids into a dynamic array.
//		Will raise an exception if list is not well-formed
//
//---------------------------------------------------------------------------
ULongPtrArray *
CDXLOperatorFactory::ExtractConvertValuesToArray(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem)
{
	const XMLCh *xml_val =
		CDXLOperatorFactory::ExtractAttrValue(attrs, target_attr, target_elem);

	return ExtractIntsToUlongArray(dxl_memory_manager, xml_val, target_attr,
								   target_elem);
}

IntPtrArray *
CDXLOperatorFactory::ExtractConvertValuesToIntArray(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem)
{
	const XMLCh *xml_val =
		CDXLOperatorFactory::ExtractAttrValue(attrs, target_attr, target_elem);

	return ExtractIntsToIntArray(dxl_memory_manager, xml_val, target_attr,
								 target_elem);
}

CBitSet *
CDXLOperatorFactory::ExtractConvertValuesToIntBitSet(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem)
{
	const XMLCh *xml_val =
		CDXLOperatorFactory::ExtractAttrValue(attrs, target_attr, target_elem);

	return ExtractIntsToIntBitSet(dxl_memory_manager, xml_val, target_attr,
								  target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertMdIdsToArray
//
//	@doc:
//		Parse a comma-separated list of MDids into a dynamic array.
//		Will raise an exception if list is not well-formed
//
//---------------------------------------------------------------------------
IMdIdArray *
CDXLOperatorFactory::ExtractConvertMdIdsToArray(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *mdid_list_xml,
	Edxltoken target_attr, Edxltoken target_elem)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	IMdIdArray *mdid_array = GPOS_NEW(mp) IMdIdArray(mp);

	XMLStringTokenizer mdid_components(mdid_list_xml,
									   CDXLTokens::XmlstrToken(EdxltokenComma));
	const ULONG num_tokens = mdid_components.countTokens();

	for (ULONG ul = 0; ul < num_tokens; ul++)
	{
		XMLCh *mdid_xml = mdid_components.nextToken();
		GPOS_ASSERT(nullptr != mdid_xml);

		IMDId *mdid = MakeMdIdFromStr(dxl_memory_manager, mdid_xml, target_attr,
									  target_elem);
		mdid_array->Append(mdid);
	}

	return mdid_array;
}

// Parse a comma-separated list of CHAR partition types into a dynamic array.
// Will raise an exception if list is not well-formed
CharPtrArray *
CDXLOperatorFactory::ExtractConvertPartitionTypeToArray(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *xml_val,
	Edxltoken target_attr, Edxltoken target_elem)
{
	return ExtractIntsToArray<CHAR, CleanupDelete, ConvertAttrValueToChar>(
		dxl_memory_manager, xml_val, target_attr, target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertUlongTo2DArray
//
//	@doc:
//		Parse a semicolon-separated list of comma-separated unsigned long
//		integers into a dynamic array.
//		Will raise an exception if list is not well-formed
//
//---------------------------------------------------------------------------
ULongPtr2dArray *
CDXLOperatorFactory::ExtractConvertUlongTo2DArray(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *xml_val,
	Edxltoken target_attr, Edxltoken target_elem)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	ULongPtr2dArray *array_2D = GPOS_NEW(mp) ULongPtr2dArray(mp);

	XMLStringTokenizer mdid_components(
		xml_val, CDXLTokens::XmlstrToken(EdxltokenSemicolon));
	const ULONG num_tokens = mdid_components.countTokens();

	for (ULONG ul = 0; ul < num_tokens; ul++)
	{
		XMLCh *comp_xml = mdid_components.nextToken();

		GPOS_ASSERT(nullptr != comp_xml);

		ULongPtrArray *array_1D = ExtractIntsToUlongArray(
			dxl_memory_manager, comp_xml, target_attr, target_elem);
		array_2D->Append(array_1D);
	}

	return array_2D;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertSegmentIdsToArray
//
//	@doc:
//		Parse a comma-separated list of segment ids into a dynamic array.
//		Will raise an exception if list is not well-formed
//
//---------------------------------------------------------------------------
IntPtrArray *
CDXLOperatorFactory::ExtractConvertSegmentIdsToArray(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *seg_id_list_xml,
	Edxltoken target_attr, Edxltoken target_elem)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	GPOS_ASSERT(nullptr != seg_id_list_xml);

	IntPtrArray *seg_ids = GPOS_NEW(mp) IntPtrArray(mp);

	XMLStringTokenizer mdid_components(seg_id_list_xml,
									   CDXLTokens::XmlstrToken(EdxltokenComma));

	const ULONG num_of_segments = mdid_components.countTokens();
	GPOS_ASSERT(0 < num_of_segments);

	for (ULONG ul = 0; ul < num_of_segments; ul++)
	{
		XMLCh *seg_id_xml = mdid_components.nextToken();

		GPOS_ASSERT(nullptr != seg_id_xml);

		INT *seg_id = GPOS_NEW(mp) INT(ConvertAttrValueToInt(
			dxl_memory_manager, seg_id_xml, target_attr, target_elem));
		seg_ids->Append(seg_id);
	}

	return seg_ids;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertStrsToArray
//
//	@doc:
//		Parse a comma-separated list of strings into a dynamic array.
//
//---------------------------------------------------------------------------
StringPtrArray *
CDXLOperatorFactory::ExtractConvertStrsToArray(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *xml_val)
{
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	StringPtrArray *array_strs = GPOS_NEW(mp) StringPtrArray(mp);

	XMLStringTokenizer mdid_components(xml_val,
									   CDXLTokens::XmlstrToken(EdxltokenComma));
	const ULONG num_tokens = mdid_components.countTokens();

	for (ULONG ul = 0; ul < num_tokens; ul++)
	{
		XMLCh *current_str = mdid_components.nextToken();
		GPOS_ASSERT(nullptr != current_str);

		CWStringDynamic *str = CDXLUtils::CreateDynamicStringFromXMLChArray(
			dxl_memory_manager, current_str);
		array_strs->Append(str);
	}

	return array_strs;
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertStrToDirectionedJoinNode
//
//	@doc:
//		Parse a directed Leading hint string into a JoinNode.
//
//		Examples: "((t1 (t2 t3)) t4)"
//
//---------------------------------------------------------------------------
CJoinHint::JoinNode *
CDXLOperatorFactory::ExtractConvertStrToDirectionedJoinNode(
	CMemoryPool *mp, const XMLCh *xml_val)
{
	auto is_name_char = [](WCHAR c) -> bool {
		return c != u'(' && c != u')' && c != u' ' && c != '\0';
	};

	gpos::stack<CJoinHint::JoinNode *> s(mp);
	for (int i = 0; xml_val[i] != '\0'; i++)
	{
		char curr = xml_val[i];
		switch (curr)
		{
			case '(':
			{
				break;
			}
			case ')':
			{
				// a closing paran indicates the second argument to a directed
				// hint has finished
				//
				// Example: "(T1 (T2 T3))"
				CJoinHint::JoinNode *right = s.top();
				s.pop();
				CJoinHint::JoinNode *left = s.top();
				s.pop();

				s.push(GPOS_NEW(mp) CJoinHint::JoinNode(left, right, true));

				break;
			}
			case ' ':
			{
				break;
			}
			default:
			{
				// consume name and push it onto the stack.
				int j = i;
				std::string str;
				while (is_name_char(xml_val[j]))
				{
					str += xml_val[j];
					j += 1;
				}
				char *str_buffer = GPOS_NEW_ARRAY(mp, char, str.size() + 1);
				memcpy(str_buffer, str.c_str(), str.size() * sizeof(char));
				str_buffer[str.size()] = '\0';

				CJoinHint::JoinNode *pair = GPOS_NEW(mp) CJoinHint::JoinNode(
					GPOS_NEW(mp) CWStringConst(mp, str_buffer));

				GPOS_DELETE_ARRAY(str_buffer);

				s.push(pair);

				i = j - 1;
				break;
			}
		}
	}

	return s.top();
}


//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertStrToNonDirectionedJoinNode
//
//	@doc:
//		Parse a directed Leading hint string into a JoinNode.
//
//		Examples: "t1 t2 t3 t4"
//
//---------------------------------------------------------------------------
CJoinHint::JoinNode *
CDXLOperatorFactory::ExtractConvertStrToNonDirectionedJoinNode(
	CMemoryPool *mp, const XMLCh *xml_val)
{
	auto is_name_char = [](WCHAR c) -> bool {
		return c != u'(' && c != u')' && c != u' ' && c != '\0';
	};

	gpos::stack<CJoinHint::JoinNode *> s(mp);
	for (int i = 0; xml_val[i] != '\0'; i++)
	{
		if (' ' == xml_val[i])
		{
			continue;
		}

		// consume name and push it onto the stack.
		int j = i;
		std::string str;
		while (is_name_char(xml_val[j]))
		{
			str += xml_val[j];
			j += 1;
		}
		char *str_buffer = GPOS_NEW_ARRAY(mp, char, str.size() + 1);
		memcpy(str_buffer, str.c_str(), str.size() * sizeof(char));
		str_buffer[str.size()] = '\0';

		CJoinHint::JoinNode *right = GPOS_NEW(mp)
			CJoinHint::JoinNode(GPOS_NEW(mp) CWStringConst(mp, str_buffer));

		GPOS_DELETE_ARRAY(str_buffer);

		if (s.size() > 0)
		{
			// if there is 1 item on the stack, then construct a new node out
			// of the two children.
			//
			// Example: "T1 T2 T3"
			CJoinHint::JoinNode *left = s.top();
			s.pop();

			s.push(GPOS_NEW(mp) CJoinHint::JoinNode(left, right, false));
		}
		else
		{
			s.push(right);
		}

		i = j - 1;
	}

	return s.top();
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertStrToJoinNode
//
//	@doc:
//		Parse a Leading hint string into a JoinNode.
//
//		Examples: "((t1 (t2 t3)) t4)" and "t1 t2 t3 t4"
//
//---------------------------------------------------------------------------
CJoinHint::JoinNode *
CDXLOperatorFactory::ExtractConvertStrToJoinNode(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *xml_val)
{
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	bool is_directed = false;
	for (int i = 0; xml_val[i] != '\0'; i++)
	{
		char curr = xml_val[i];
		if (curr == '(')
		{
			is_directed = true;
			break;
		}
	}

	if (is_directed)
	{
		return ExtractConvertStrToDirectionedJoinNode(mp, xml_val);
	}
	return ExtractConvertStrToNonDirectionedJoinNode(mp, xml_val);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::SetSegmentInfo
//
//	@doc:
//		Parses the input and output segment ids from Xerces attributes and
//		stores them in the provided DXL Motion operator.
//		Will raise an exception if lists are not well-formed
//
//---------------------------------------------------------------------------
void
CDXLOperatorFactory::SetSegmentInfo(CDXLMemoryManager *dxl_memory_manager,
									CDXLPhysicalMotion *motion,
									const Attributes &attrs,
									Edxltoken target_elem)
{
	const XMLCh *input_seglist_xml =
		ExtractAttrValue(attrs, EdxltokenInputSegments, target_elem);
	IntPtrArray *input_segments =
		ExtractConvertSegmentIdsToArray(dxl_memory_manager, input_seglist_xml,
										EdxltokenInputSegments, target_elem);
	motion->SetInputSegIds(input_segments);

	const XMLCh *output_seglist_xml =
		ExtractAttrValue(attrs, EdxltokenOutputSegments, target_elem);
	IntPtrArray *output_segments =
		ExtractConvertSegmentIdsToArray(dxl_memory_manager, output_seglist_xml,
										EdxltokenOutputSegments, target_elem);
	motion->SetOutputSegIds(output_segments);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseJoinType
//
//	@doc:
//		Parse a join type from the attribute value.
//		Raise an exception if join type value is invalid.
//
//---------------------------------------------------------------------------
EdxlJoinType
CDXLOperatorFactory::ParseJoinType(const XMLCh *join_type_xml,
								   const CWStringConst *join_name)
{
	EdxlJoinType join_type = EdxljtSentinel;

	if (0 == XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenJoinInner), join_type_xml))
	{
		join_type = EdxljtInner;
	}
	else if (0 ==
			 XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenJoinLeft), join_type_xml))
	{
		join_type = EdxljtLeft;
	}
	else if (0 ==
			 XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenJoinFull), join_type_xml))
	{
		join_type = EdxljtFull;
	}
	else if (0 ==
			 XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenJoinRight), join_type_xml))
	{
		join_type = EdxljtRight;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenJoinIn), join_type_xml))
	{
		join_type = EdxljtIn;
	}
	else if (0 == XMLString::compareString(
					  CDXLTokens::XmlstrToken(EdxltokenJoinLeftAntiSemiJoin),
					  join_type_xml))
	{
		join_type = EdxljtLeftAntiSemijoin;
	}
	else if (0 ==
			 XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenJoinLeftAntiSemiJoinNotIn),
				 join_type_xml))
	{
		join_type = EdxljtLeftAntiSemijoinNotIn;
	}
	else
	{
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(EdxltokenJoinType)->GetBuffer(),
				   join_name->GetBuffer());
	}

	return join_type;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseIndexScanDirection
//
//	@doc:
//		Parse the index scan direction from the attribute value. Raise
//		exception if it is invalid
//
//---------------------------------------------------------------------------
EdxlIndexScanDirection
CDXLOperatorFactory::ParseIndexScanDirection(const XMLCh *direction_xml,
											 const CWStringConst *index_scan)
{
	if (0 == XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenIndexScanDirectionBackward),
				 direction_xml))
	{
		return EdxlisdBackward;
	}
	else if (0 ==
			 XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenIndexScanDirectionForward),
				 direction_xml))
	{
		return EdxlisdForward;
	}
	else if (0 ==
			 XMLString::compareString(
				 CDXLTokens::XmlstrToken(EdxltokenIndexScanDirectionNoMovement),
				 direction_xml))
	{
		return EdxlisdNoMovement;
	}
	else
	{
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
				   CDXLTokens::GetDXLTokenStr(EdxltokenIndexScanDirection)
					   ->GetBuffer(),
				   index_scan->GetBuffer());
	}

	return EdxlisdSentinel;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeLogicalJoin
//
//	@doc:
//		Construct a logical join operator
//
//---------------------------------------------------------------------------
CDXLLogical *
CDXLOperatorFactory::MakeLogicalJoin(CDXLMemoryManager *dxl_memory_manager,
									 const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	const XMLCh *join_type_xml =
		ExtractAttrValue(attrs, EdxltokenJoinType, EdxltokenLogicalJoin);
	EdxlJoinType join_type = ParseJoinType(
		join_type_xml, CDXLTokens::GetDXLTokenStr(EdxltokenLogicalJoin));

	return GPOS_NEW(mp) CDXLLogicalJoin(mp, join_type);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ConvertAttrValueToDouble
//
//	@doc:
//	  Converts the attribute value to CDouble
//
//---------------------------------------------------------------------------
CDouble
CDXLOperatorFactory::ConvertAttrValueToDouble(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *attribute_val_xml,
	Edxltoken,	//target_attr,
	Edxltoken	//target_elem
)
{
	GPOS_ASSERT(attribute_val_xml != nullptr);
	CHAR *sz = XMLString::transcode(attribute_val_xml, dxl_memory_manager);

	CDouble value(clib::Strtod(sz));

	XMLString::release(&sz, dxl_memory_manager);
	return value;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToDouble
//
//	@doc:
//	  Extracts the value for the given attribute and converts it into CDouble
//
//---------------------------------------------------------------------------
CDouble
CDXLOperatorFactory::ExtractConvertAttrValueToDouble(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem)
{
	const XMLCh *attr_val_xml =
		CDXLOperatorFactory::ExtractAttrValue(attrs, target_attr, target_elem);
	return ConvertAttrValueToDouble(dxl_memory_manager, attr_val_xml,
									target_attr, target_elem);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ConvertAttrValueToLint
//
//	@doc:
//	  Converts the attribute value to LINT
//
//---------------------------------------------------------------------------
LINT
CDXLOperatorFactory::ConvertAttrValueToLint(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *attribute_val_xml,
	Edxltoken,	//target_attr,
	Edxltoken	//target_elem
)
{
	GPOS_ASSERT(nullptr != attribute_val_xml);
	CHAR *sz = XMLString::transcode(attribute_val_xml, dxl_memory_manager);
	CHAR *szEnd = nullptr;

	LINT value = clib::Strtoll(sz, &szEnd, 10);
	XMLString::release(&sz, dxl_memory_manager);

	return value;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertAttrValueToLint
//
//	@doc:
//	  Extracts the value for the given attribute and converts it into LINT
//
//---------------------------------------------------------------------------
LINT
CDXLOperatorFactory::ExtractConvertAttrValueToLint(
	CDXLMemoryManager *dxl_memory_manager, const Attributes &attrs,
	Edxltoken target_attr, Edxltoken target_elem, BOOL is_optional,
	LINT default_value)
{
	const XMLCh *attr_val_xml = CDXLOperatorFactory::ExtractAttrValue(
		attrs, target_attr, target_elem, is_optional);

	if (nullptr == attr_val_xml)
	{
		return default_value;
	}

	return ConvertAttrValueToLint(dxl_memory_manager, attr_val_xml, target_attr,
								  target_elem);
}


CSystemId
CDXLOperatorFactory::Sysid(CDXLMemoryManager *dxl_memory_manager,
						   const Attributes &attrs, Edxltoken target_attr,
						   Edxltoken target_elem)
{
	// extract systemids
	const XMLCh *xml_val = ExtractAttrValue(attrs, target_attr, target_elem);

	// get sysid components
	XMLStringTokenizer sys_id_components(xml_val,
										 CDXLTokens::XmlstrToken(EdxltokenDot));
	GPOS_ASSERT(2 == sys_id_components.countTokens());

	XMLCh *sys_id_comp = sys_id_components.nextToken();
	ULONG type = CDXLOperatorFactory::ConvertAttrValueToUlong(
		dxl_memory_manager, sys_id_comp, target_attr, target_elem);

	XMLCh *xml_str_name = sys_id_components.nextToken();
	CWStringDynamic *str_name = CDXLUtils::CreateDynamicStringFromXMLChArray(
		dxl_memory_manager, xml_str_name);

	CSystemId sys_id((IMDId::EMDIdType) type, str_name->GetBuffer(),
					 str_name->Length());
	GPOS_DELETE(str_name);

	return sys_id;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::MakeWindowRef
//
//	@doc:
//		Construct an WindowRef operator
//
//---------------------------------------------------------------------------
CDXLScalar *
CDXLOperatorFactory::MakeWindowRef(CDXLMemoryManager *dxl_memory_manager,
								   const Attributes &attrs)
{
	// get the memory pool from the memory manager
	CMemoryPool *mp = dxl_memory_manager->Pmp();
	IMDId *mdid_func = ExtractConvertAttrValueToMdId(dxl_memory_manager, attrs,
													 EdxltokenWindowrefOid,
													 EdxltokenScalarWindowref);
	IMDId *mdid_return_type = ExtractConvertAttrValueToMdId(
		dxl_memory_manager, attrs, EdxltokenTypeId, EdxltokenScalarWindowref);
	BOOL is_distinct = ExtractConvertAttrValueToBool(dxl_memory_manager, attrs,
													 EdxltokenWindowrefDistinct,
													 EdxltokenScalarWindowref);
	BOOL is_star_arg = ExtractConvertAttrValueToBool(dxl_memory_manager, attrs,
													 EdxltokenWindowrefStarArg,
													 EdxltokenScalarWindowref);
	BOOL is_simple_agg = ExtractConvertAttrValueToBool(
		dxl_memory_manager, attrs, EdxltokenWindowrefSimpleAgg,
		EdxltokenScalarWindowref);
	ULONG win_spec_pos = ExtractConvertAttrValueToUlong(
		dxl_memory_manager, attrs, EdxltokenWindowrefWinSpecPos,
		EdxltokenScalarWindowref);

	const XMLCh *agg_stage_xml = ExtractAttrValue(
		attrs, EdxltokenWindowrefStrategy, EdxltokenScalarWindowref);
	EdxlWinStage dxl_win_stage = EdxlwinstageSentinel;

	ULONG window_frame_boundary_to_frame_boundary_mapping[][2] = {
		{EdxlwinstageImmediate, EdxltokenWindowrefStageImmediate},
		{EdxlwinstagePreliminary, EdxltokenWindowrefStagePreliminary},
		{EdxlwinstageRowKey, EdxltokenWindowrefStageRowKey}};

	const ULONG arity =
		GPOS_ARRAY_SIZE(window_frame_boundary_to_frame_boundary_mapping);
	for (ULONG ul = 0; ul < arity; ul++)
	{
		ULONG *mapping = window_frame_boundary_to_frame_boundary_mapping[ul];
		Edxltoken frame_bound = (Edxltoken) mapping[1];
		if (0 == XMLString::compareString(CDXLTokens::XmlstrToken(frame_bound),
										  agg_stage_xml))
		{
			dxl_win_stage = (EdxlWinStage) mapping[0];
			break;
		}
	}
	GPOS_ASSERT(EdxlwinstageSentinel != dxl_win_stage);

	return GPOS_NEW(mp) CDXLScalarWindowRef(
		mp, mdid_func, mdid_return_type, is_distinct, is_star_arg,
		is_simple_agg, dxl_win_stage, win_spec_pos);
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseCmpType
//
//	@doc:
//		Parse comparison type
//
//---------------------------------------------------------------------------
IMDType::ECmpType
CDXLOperatorFactory::ParseCmpType(const XMLCh *xml_str_comp_type)
{
	ULONG parse_cmp_type_mapping[][2] = {
		{EdxltokenCmpEq, IMDType::EcmptEq},
		{EdxltokenCmpNeq, IMDType::EcmptNEq},
		{EdxltokenCmpLt, IMDType::EcmptL},
		{EdxltokenCmpLeq, IMDType::EcmptLEq},
		{EdxltokenCmpGt, IMDType::EcmptG},
		{EdxltokenCmpGeq, IMDType::EcmptGEq},
		{EdxltokenCmpIDF, IMDType::EcmptIDF},
		{EdxltokenCmpOther, IMDType::EcmptOther}};

	for (ULONG ul = 0; ul < GPOS_ARRAY_SIZE(parse_cmp_type_mapping); ul++)
	{
		ULONG *mapping = parse_cmp_type_mapping[ul];
		Edxltoken cmp_type = (Edxltoken) mapping[0];

		if (0 == XMLString::compareString(CDXLTokens::XmlstrToken(cmp_type),
										  xml_str_comp_type))
		{
			return (IMDType::ECmpType) mapping[1];
		}
	}

	GPOS_RAISE(
		gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
		CDXLTokens::GetDXLTokenStr(EdxltokenGPDBScalarOpCmpType)->GetBuffer(),
		CDXLTokens::GetDXLTokenStr(EdxltokenGPDBScalarOp)->GetBuffer());
	return (IMDType::ECmpType) IMDType::EcmptOther;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseRelationDistPolicy
//
//	@doc:
//		Parse relation distribution policy from XML string
//
//---------------------------------------------------------------------------
IMDRelation::Ereldistrpolicy
CDXLOperatorFactory::ParseRelationDistPolicy(const XMLCh *xml_val)
{
	GPOS_ASSERT(nullptr != xml_val);
	IMDRelation::Ereldistrpolicy rel_distr_policy =
		IMDRelation::EreldistrSentinel;

	if (0 ==
		XMLString::compareString(
			xml_val, CDXLTokens::XmlstrToken(EdxltokenRelDistrCoordinatorOnly)))
	{
		rel_distr_policy = IMDRelation::EreldistrCoordinatorOnly;
	}
	else if (0 == XMLString::compareString(
					  xml_val, CDXLTokens::XmlstrToken(EdxltokenRelDistrHash)))
	{
		rel_distr_policy = IMDRelation::EreldistrHash;
	}
	else if (0 ==
			 XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenRelDistrRandom)))
	{
		rel_distr_policy = IMDRelation::EreldistrRandom;
	}
	else if (0 ==
			 XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenRelDistrReplicated)))
	{
		rel_distr_policy = IMDRelation::EreldistrReplicated;
	}
	else if (0 ==
			 XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenRelDistrUniversal)))
	{
		rel_distr_policy = IMDRelation::EreldistrUniversal;
	}

	return rel_distr_policy;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseRelationStorageType
//
//	@doc:
//		Parse relation storage type from XML string
//
//---------------------------------------------------------------------------
IMDRelation::Erelstoragetype
CDXLOperatorFactory::ParseRelationStorageType(const XMLCh *xml_val)
{
	GPOS_ASSERT(nullptr != xml_val);

	if (0 == XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenRelStorageHeap)))
	{
		return IMDRelation::ErelstorageHeap;
	}

	if (0 == XMLString::compareString(
				 xml_val,
				 CDXLTokens::XmlstrToken(EdxltokenRelStorageAppendOnlyCols)))
	{
		return IMDRelation::ErelstorageAppendOnlyCols;
	}

	if (0 == XMLString::compareString(
				 xml_val,
				 CDXLTokens::XmlstrToken(EdxltokenRelStorageAppendOnlyRows)))
	{
		return IMDRelation::ErelstorageAppendOnlyRows;
	}

	if (0 == XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenRelStorageForeign)))
	{
		return IMDRelation::ErelstorageForeign;
	}

	if (0 == XMLString::compareString(
				 xml_val,
				 CDXLTokens::XmlstrToken(EdxltokenRelStorageMixedPartitioned)))
	{
		return IMDRelation::ErelstorageMixedPartitioned;
	}

	GPOS_ASSERT(!"Unrecognized storage type");

	return IMDRelation::ErelstorageSentinel;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseOnCommitActionSpec
//
//	@doc:
//		Parse on commit action spec from XML attributes
//
//---------------------------------------------------------------------------
CDXLCtasStorageOptions::ECtasOnCommitAction
CDXLOperatorFactory::ParseOnCommitActionSpec(const Attributes &attrs)
{
	const XMLCh *xml_val =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenOnCommitAction));

	if (nullptr == xml_val)
	{
		GPOS_RAISE(
			gpdxl::ExmaDXL, gpdxl::ExmiDXLMissingAttribute,
			CDXLTokens::GetDXLTokenStr(EdxltokenOnCommitAction)->GetBuffer(),
			CDXLTokens::GetDXLTokenStr(EdxltokenCTASOptions)->GetBuffer());
	}

	if (0 == XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenOnCommitPreserve)))
	{
		return CDXLCtasStorageOptions::EctascommitPreserve;
	}

	if (0 == XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenOnCommitDelete)))
	{
		return CDXLCtasStorageOptions::EctascommitDelete;
	}

	if (0 == XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenOnCommitDrop)))
	{
		return CDXLCtasStorageOptions::EctascommitDrop;
	}

	if (0 != XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenOnCommitNOOP)))
	{
		GPOS_RAISE(
			gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
			CDXLTokens::GetDXLTokenStr(EdxltokenOnCommitAction)->GetBuffer(),
			CDXLTokens::GetDXLTokenStr(EdxltokenCTASOptions)->GetBuffer());
	}

	return CDXLCtasStorageOptions::EctascommitNOOP;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ParseIndexType
//
//	@doc:
//		Parse index type from XML attributes
//
//---------------------------------------------------------------------------
IMDIndex::EmdindexType
CDXLOperatorFactory::ParseIndexType(const Attributes &attrs)
{
	const XMLCh *xml_val =
		attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenIndexType));

	if (nullptr == xml_val ||
		0 == XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenIndexTypeBtree)))
	{
		// default_val is btree
		return IMDIndex::EmdindBtree;
	}


	if (0 == XMLString::compareString(
				 xml_val, CDXLTokens::XmlstrToken(EdxltokenIndexTypeBitmap)))
	{
		return IMDIndex::EmdindBitmap;
	}
	else if (0 == XMLString::compareString(
					  xml_val, CDXLTokens::XmlstrToken(EdxltokenIndexTypeGist)))
	{
		return IMDIndex::EmdindGist;
	}
	else if (0 == XMLString::compareString(
					  xml_val, CDXLTokens::XmlstrToken(EdxltokenIndexTypeGin)))
	{
		return IMDIndex::EmdindGin;
	}
	else if (0 == XMLString::compareString(
					  xml_val, CDXLTokens::XmlstrToken(EdxltokenIndexTypeBrin)))
	{
		return IMDIndex::EmdindBrin;
	}
	else if (0 == XMLString::compareString(
					  xml_val, CDXLTokens::XmlstrToken(EdxltokenIndexTypeHash)))
	{
		return IMDIndex::EmdindHash;
	}

	GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLInvalidAttributeValue,
			   CDXLTokens::GetDXLTokenStr(EdxltokenIndexType)->GetBuffer(),
			   CDXLTokens::GetDXLTokenStr(EdxltokenIndex)->GetBuffer());

	return IMDIndex::EmdindSentinel;
}

//---------------------------------------------------------------------------
//	@function:
//		CDXLOperatorFactory::ExtractConvertBooleanListToULongArray
//
//	@doc:
//		Parse boolean list to ULong Array, maps false_value in the list
//		to 0 and if value in list isn't equals to false_value it is mapped to 1.
//---------------------------------------------------------------------------
ULongPtrArray *
CDXLOperatorFactory::ExtractConvertBooleanListToULongArray(
	CDXLMemoryManager *dxl_memory_manager, const XMLCh *xml_val,
	const XMLCh *true_value GPOS_ASSERTS_ONLY, const XMLCh *false_value,
	ULONG num_of_keys)
{
	CMemoryPool *mp = dxl_memory_manager->Pmp();

	ULongPtrArray *ulong_array = GPOS_NEW(mp) ULongPtrArray(mp);

	// Only B-tree indices have sort and nulls directions in dxl
	// For mdps with btree indices that do not have sort/nulls direction
	// return array with 0s and consider ASC as default
	if (xml_val == nullptr)
	{
		for (ULONG ul = 0; ul < num_of_keys; ul++)
		{
			ulong_array->Append(GPOS_NEW(mp) ULONG(0));
		}
		return ulong_array;
	}

	XMLStringTokenizer commma_sep_str_components(
		xml_val, CDXLTokens::XmlstrToken(EdxltokenComma));
	const ULONG num_tokens = commma_sep_str_components.countTokens();

	if (num_tokens == 0)
	{
		return ulong_array;
	}

	for (ULONG ul = 0; ul < num_tokens; ul++)
	{
		XMLCh *current_str = commma_sep_str_components.nextToken();
		GPOS_ASSERT(nullptr != current_str);
		GPOS_ASSERT(0 == XMLString::compareString(current_str, true_value) ||
					0 == XMLString::compareString(current_str, false_value));
		ULONG value;
		value =
			(0 == XMLString::compareString(current_str, false_value)) ? 0 : 1;
		ulong_array->Append(GPOS_NEW(mp) ULONG(value));
	}
	return ulong_array;
}
// EOF
