CTranslatorRelcacheToDXL.cpp 99.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
//---------------------------------------------------------------------------
//	Greenplum Database
//	Copyright (C) 2011 EMC Corp.
//
//	@filename:
//		CTranslatorRelcacheToDXL.cpp
//
//	@doc:
//		Class translating relcache entries into DXL objects
//
//	@test:
//
//
//---------------------------------------------------------------------------

#include "postgres.h"
#include "utils/array.h"
#include "utils/rel.h"
#include "utils/relcache.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
#include "utils/datum.h"
#include "utils/elog.h"
#include "utils/guc.h"
#include "cdb/cdbhash.h"
#include "access/heapam.h"
#include "catalog/pg_exttable.h"
29
#include "catalog/pg_proc.h"
30 31 32 33 34

#include "cdb/cdbpartition.h"
#include "catalog/namespace.h"
#include "catalog/pg_statistic.h"

35 36 37 38 39 40
#include "naucrates/md/CMDIdCast.h"
#include "naucrates/md/CMDIdScCmp.h"

#include "naucrates/dxl/gpdb_types.h"

#include "naucrates/md/CMDCastGPDB.h"
41
#include "naucrates/md/CMDArrayCoerceCastGPDB.h"
42 43 44 45 46 47 48
#include "naucrates/md/CMDScCmpGPDB.h"

#include "gpopt/translate/CTranslatorUtils.h"
#include "gpopt/translate/CTranslatorRelcacheToDXL.h"
#include "gpopt/translate/CTranslatorScalarToDXL.h"
#include "gpopt/mdcache/CMDAccessor.h"

49 50 51
#include "gpos/base.h"
#include "gpos/error/CException.h"

52
#include "naucrates/exception.h"
53

54 55
#include "naucrates/dxl/CDXLUtils.h"
#include "naucrates/dxl/xml/dxltokens.h"
56

57 58 59 60 61 62 63 64 65 66 67 68
#include "naucrates/md/CMDTypeBoolGPDB.h"
#include "naucrates/md/CMDTypeGenericGPDB.h"
#include "naucrates/md/CMDTypeInt2GPDB.h"
#include "naucrates/md/CMDTypeInt4GPDB.h"
#include "naucrates/md/CMDTypeInt8GPDB.h"
#include "naucrates/md/CMDTypeOidGPDB.h"
#include "naucrates/md/CMDIndexGPDB.h"
#include "naucrates/md/CMDPartConstraintGPDB.h"
#include "naucrates/md/CMDIdRelStats.h"
#include "naucrates/md/CDXLRelStats.h"
#include "naucrates/md/CMDIdColStats.h"
#include "naucrates/md/CDXLColStats.h"
69 70 71 72 73 74 75 76 77 78

#include "gpopt/base/CUtils.h"

#include "gpopt/gpdbwrappers.h"

using namespace gpdxl;
using namespace gpopt;


static 
79
const ULONG cmp_type_mappings[][2] =
80 81 82 83 84 85 86 87 88 89 90
{
	{IMDType::EcmptEq, CmptEq},
	{IMDType::EcmptNEq, CmptNEq},
	{IMDType::EcmptL, CmptLT},
	{IMDType::EcmptG, CmptGT},
	{IMDType::EcmptGEq, CmptGEq},
	{IMDType::EcmptLEq, CmptLEq}
};

//---------------------------------------------------------------------------
//	@function:
91
//		CTranslatorRelcacheToDXL::RetrieveObject
92 93 94 95 96 97
//
//	@doc:
//		Retrieve a metadata object from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
IMDCacheObject *
98
CTranslatorRelcacheToDXL::RetrieveObject
99
	(
100 101 102
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	IMDId *mdid
103 104
	)
{
105 106
	IMDCacheObject *md_obj = NULL;
	GPOS_ASSERT(NULL != md_accessor);
107

108
#ifdef FAULT_INJECTOR
109
	gpdb::InjectFaultInOptTasks(OptRelcacheTranslatorCatalogAccess);
110 111
#endif // FAULT_INJECTOR

112
	switch(mdid->MdidType())
113 114
	{
		case IMDId::EmdidGPDB:
115
			md_obj = RetrieveObjectGPDB(mp, md_accessor, mdid);
116 117 118
			break;
		
		case IMDId::EmdidRelStats:
119
			md_obj = RetrieveRelStats(mp, mdid);
120 121 122
			break;
		
		case IMDId::EmdidColStats:
123
			md_obj = RetrieveColStats(mp, md_accessor, mdid);
124 125 126
			break;
		
		case IMDId::EmdidCastFunc:
127
			md_obj = RetrieveCast(mp, mdid);
128 129 130
			break;
		
		case IMDId::EmdidScCmp:
131
			md_obj = RetrieveScCmp(mp, mdid);
132 133 134 135 136 137
			break;
			
		default:
			break;
	}

138
	if (NULL == md_obj)
139 140
	{
		// no match found
141
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
142 143
	}

144
	return md_obj;
145 146 147 148
}

//---------------------------------------------------------------------------
//	@function:
149
//		CTranslatorRelcacheToDXL::RetrieveMDObjGPDB
150 151 152 153 154 155
//
//	@doc:
//		Retrieve a GPDB metadata object from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
IMDCacheObject *
156
CTranslatorRelcacheToDXL::RetrieveObjectGPDB
157
	(
158 159 160
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	IMDId *mdid
161 162
	)
{
163
	GPOS_ASSERT(mdid->MdidType() == CMDIdGPDB::EmdidGPDB);
164

165
	OID oid = CMDIdGPDB::CastMdid(mdid)->Oid();
166 167 168 169 170

	GPOS_ASSERT(0 != oid);

	// find out what type of object this oid stands for

171
	if (gpdb::IndexExists(oid))
172
	{
173
		return RetrieveIndex(mp, md_accessor, mdid);
174 175
	}

176
	if (gpdb::TypeExists(oid))
177
	{
178
		return RetrieveType(mp, mdid);
179 180
	}

181
	if (gpdb::RelationExists(oid))
182
	{
183
		return RetrieveRel(mp, md_accessor, mdid);
184 185
	}

186
	if (gpdb::OperatorExists(oid))
187
	{
188
		return RetrieveScOp(mp, mdid);
189 190
	}

191
	if (gpdb::AggregateExists(oid))
192
	{
193
		return RetrieveAgg(mp, mdid);
194 195
	}

196
	if (gpdb::FunctionExists(oid))
197
	{
198
		return RetrieveFunc(mp, mdid);
199 200
	}

201
	if (gpdb::TriggerExists(oid))
202
	{
203
		return RetrieveTrigger(mp, mdid);
204 205
	}

206
	if (gpdb::CheckConstraintExists(oid))
207
	{
208
		return RetrieveCheckConstraints(mp, md_accessor, mdid);
209 210 211 212 213 214 215 216 217
	}

	// no match found
	return NULL;

}

//---------------------------------------------------------------------------
//	@function:
218
//		CTranslatorRelcacheToDXL::GetRelName
219 220 221 222 223 224
//
//	@doc:
//		Return a relation name
//
//---------------------------------------------------------------------------
CMDName *
225
CTranslatorRelcacheToDXL::GetRelName
226
	(
227
	IMemoryPool *mp,
228 229 230 231
	Relation rel
	)
{
	GPOS_ASSERT(NULL != rel);
232 233 234 235 236
	CHAR *relname = NameStr(rel->rd_rel->relname);
	CWStringDynamic *relname_str = CDXLUtils::CreateDynamicStringFromCharArray(mp, relname);
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, relname_str);
	GPOS_DELETE(relname_str);
	return mdname;
237 238 239 240
}

//---------------------------------------------------------------------------
//	@function:
241
//		CTranslatorRelcacheToDXL::RetrieveRelIndexInfo
242 243 244 245 246
//
//	@doc:
//		Return the indexes defined on the given relation
//
//---------------------------------------------------------------------------
247 248
CMDIndexInfoArray *
CTranslatorRelcacheToDXL::RetrieveRelIndexInfo
249
	(
250
	IMemoryPool *mp,
251 252 253 254 255
	Relation rel
	)
{
	GPOS_ASSERT(NULL != rel);

256
	if (gpdb::RelPartIsNone(rel->rd_id) || gpdb::IsLeafPartition(rel->rd_id))
257
	{
258
		return RetrieveRelIndexInfoForNonPartTable(mp, rel);
259
	}
260
	else if (gpdb::RelPartIsRoot(rel->rd_id))
261
	{
262
		return RetrieveRelIndexInfoForPartTable(mp, rel);
263 264 265
	}
	else  
	{
266
		// interior partition: do not consider indexes
267 268
		CMDIndexInfoArray *md_index_info_array = GPOS_NEW(mp) CMDIndexInfoArray(mp);
		return md_index_info_array;
269
	}
270 271 272
}

// return index info list of indexes defined on a partitioned table
273 274
CMDIndexInfoArray *
CTranslatorRelcacheToDXL::RetrieveRelIndexInfoForPartTable
275
	(
276 277
	IMemoryPool *mp,
	Relation root_rel
278 279
	)
{
280
	CMDIndexInfoArray *md_index_info_array = GPOS_NEW(mp) CMDIndexInfoArray(mp);
281 282

	// root of partitioned table: aggregate index information across different parts
283
	List *plLogicalIndexInfo = RetrievePartTableIndexInfo(root_rel);
284

285
	ListCell *lc = NULL;
286

287
	ForEach (lc, plLogicalIndexInfo)
288
	{
289 290
		LogicalIndexInfo *logicalIndexInfo = (LogicalIndexInfo *) lfirst(lc);
		OID index_oid = logicalIndexInfo->logicalIndexOid;
291 292

		// only add supported indexes
293
		Relation index_rel = gpdb::GetRelation(index_oid);
294

295
		if (NULL == index_rel)
296
		{
297 298
			WCHAR wstr[1024];
			CWStringStatic str(wstr, 1024);
299
			COstreamString oss(&str);
300 301
			oss << (ULONG) index_oid;
			GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, str.GetBuffer());
302 303
		}

304
		GPOS_ASSERT(NULL != index_rel->rd_indextuple);
305 306 307

		GPOS_TRY
		{
308
			if (IsIndexSupported(index_rel))
309
			{
310 311 312 313
				CMDIdGPDB *mdid_index = GPOS_NEW(mp) CMDIdGPDB(index_oid);
				BOOL is_partial = (NULL != logicalIndexInfo->partCons) || (NIL != logicalIndexInfo->defaultLevels);
				CMDIndexInfo *md_index_info = GPOS_NEW(mp) CMDIndexInfo(mdid_index, is_partial);
				md_index_info_array->Append(md_index_info);
314 315
			}

316
			gpdb::CloseRelation(index_rel);
317 318 319
		}
		GPOS_CATCH_EX(ex)
		{
320
			gpdb::CloseRelation(index_rel);
321 322 323 324
			GPOS_RETHROW(ex);
		}
		GPOS_CATCH_END;
	}
325
	return md_index_info_array;
326 327 328
}

// return index info list of indexes defined on regular, external tables or leaf partitions
329 330
CMDIndexInfoArray *
CTranslatorRelcacheToDXL::RetrieveRelIndexInfoForNonPartTable
331
	(
332
	IMemoryPool *mp,
333 334 335
	Relation rel
	)
{
336
	CMDIndexInfoArray *md_index_info_array = GPOS_NEW(mp) CMDIndexInfoArray(mp);
337 338

	// not a partitioned table: obtain indexes directly from the catalog
339
	List *index_oids = gpdb::GetRelationIndexes(rel);
340

341
	ListCell *lc = NULL;
342

343
	ForEach (lc, index_oids)
344
	{
345
		OID index_oid = lfirst_oid(lc);
346 347

		// only add supported indexes
348
		Relation index_rel = gpdb::GetRelation(index_oid);
349

350
		if (NULL == index_rel)
351
		{
352 353
			WCHAR wstr[1024];
			CWStringStatic str(wstr, 1024);
354
			COstreamString oss(&str);
355 356
			oss << (ULONG) index_oid;
			GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, str.GetBuffer());
357 358
		}

359
		GPOS_ASSERT(NULL != index_rel->rd_indextuple);
360 361 362

		GPOS_TRY
		{
363
			if (IsIndexSupported(index_rel))
364
			{
365
				CMDIdGPDB *mdid_index = GPOS_NEW(mp) CMDIdGPDB(index_oid);
366
				// for a regular table, external table or leaf partition, an index is always complete
367 368
				CMDIndexInfo *md_index_info = GPOS_NEW(mp) CMDIndexInfo(mdid_index, false /* is_partial */);
				md_index_info_array->Append(md_index_info);
369 370
			}

371
			gpdb::CloseRelation(index_rel);
372 373 374
		}
		GPOS_CATCH_EX(ex)
		{
375
			gpdb::CloseRelation(index_rel);
376 377 378 379 380
			GPOS_RETHROW(ex);
		}
		GPOS_CATCH_END;
	}

381
	return md_index_info_array;
382 383 384 385
}

//---------------------------------------------------------------------------
//	@function:
386
//		CTranslatorRelcacheToDXL::RetrievePartTableIndexInfo
387 388
//
//	@doc:
389
//		Return the index info list of on a partitioned table
390 391 392
//
//---------------------------------------------------------------------------
List *
393
CTranslatorRelcacheToDXL::RetrievePartTableIndexInfo
394 395 396 397
	(
	Relation rel
	)
{
398
	List *index_info_list = NIL;
399
	
400
	LogicalIndexes *logical_indexes = gpdb::GetLogicalPartIndexes(rel->rd_id);
401

402
	if (NULL == logical_indexes)
403 404 405
	{
		return NIL;
	}
406 407
	GPOS_ASSERT(NULL != logical_indexes);
	GPOS_ASSERT(0 <= logical_indexes->numLogicalIndexes);
408
	
409 410
	const ULONG num_indexes = (ULONG) logical_indexes->numLogicalIndexes;
	for (ULONG ul = 0; ul < num_indexes; ul++)
411
	{
412 413
		LogicalIndexInfo *index_info = (logical_indexes->logicalIndexInfo)[ul];
		index_info_list = gpdb::LAppend(index_info_list, index_info);
414 415
	}
	
416
	gpdb::GPDBFree(logical_indexes);
417
	
418
	return index_info_list;
419 420 421 422
}

//---------------------------------------------------------------------------
//	@function:
423
//		CTranslatorRelcacheToDXL::RetrieveRelTriggers
424 425 426 427 428
//
//	@doc:
//		Return the triggers defined on the given relation
//
//---------------------------------------------------------------------------
429 430
IMdIdArray *
CTranslatorRelcacheToDXL::RetrieveRelTriggers
431
	(
432
	IMemoryPool *mp,
433 434 435 436 437 438 439 440 441 442 443 444 445
	Relation rel
	)
{
	GPOS_ASSERT(NULL != rel);
	if (0 < rel->rd_rel->reltriggers && NULL == rel->trigdesc)
	{
		gpdb::BuildRelationTriggers(rel);
		if (NULL == rel->trigdesc)
		{
			rel->rd_rel->reltriggers = 0;
		}
	}

446
	IMdIdArray *mdid_triggers_array = GPOS_NEW(mp) IMdIdArray(mp);
447 448
	const ULONG ulTriggers = rel->rd_rel->reltriggers;

449 450 451 452 453 454 455
		for (ULONG ul = 0; ul < ulTriggers; ul++)
		{
			Trigger trigger = rel->trigdesc->triggers[ul];
			OID trigger_oid = trigger.tgoid;
			CMDIdGPDB *mdid_trigger = GPOS_NEW(mp) CMDIdGPDB(trigger_oid);
			mdid_triggers_array->Append(mdid_trigger);

456 457
	}

458
	return mdid_triggers_array;
459 460 461 462
}

//---------------------------------------------------------------------------
//	@function:
463
//		CTranslatorRelcacheToDXL::RetrieveRelCheckConstraints
464 465 466 467 468
//
//	@doc:
//		Return the check constraints defined on the relation with the given oid
//
//---------------------------------------------------------------------------
469 470
IMdIdArray *
CTranslatorRelcacheToDXL::RetrieveRelCheckConstraints
471
	(
472
	IMemoryPool *mp,
473 474 475
	OID oid
	)
{
476 477
	IMdIdArray *check_constraint_mdids = GPOS_NEW(mp) IMdIdArray(mp);
	List *check_constraints = gpdb::GetCheckConstraintOids(oid);
478

479 480
	ListCell *lc = NULL;
	ForEach (lc, check_constraints)
481
	{
482 483 484 485
		OID check_constraint_oid = lfirst_oid(lc);
		GPOS_ASSERT(0 != check_constraint_oid);
		CMDIdGPDB *mdid_check_constraint = GPOS_NEW(mp) CMDIdGPDB(check_constraint_oid);
		check_constraint_mdids->Append(mdid_check_constraint);
486 487
	}

488
	return check_constraint_mdids;
489 490 491 492 493 494 495 496 497 498 499 500 501
}

//---------------------------------------------------------------------------
//	@function:
//		CTranslatorRelcacheToDXL::CheckUnsupportedRelation
//
//	@doc:
//		Check and fall back to planner for unsupported relations
//
//---------------------------------------------------------------------------
void
CTranslatorRelcacheToDXL::CheckUnsupportedRelation
	(
502
	OID rel_oid
503 504
	)
{
505
	if (gpdb::RelPartIsInterior(rel_oid))
506 507 508 509
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDObjUnsupported, GPOS_WSZ_LIT("Query on intermediate partition"));
	}

510 511
	List *part_keys = gpdb::GetPartitionAttrs(rel_oid);
	ULONG num_of_levels = gpdb::ListLength(part_keys);
512

513
	if (0 == num_of_levels && gpdb::FHasSubclass(rel_oid))
514 515 516 517
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDObjUnsupported, GPOS_WSZ_LIT("Inherited tables"));
	}

518
	if (1 < num_of_levels)
519 520 521 522 523 524
	{
		if (!optimizer_multilevel_partitioning)
		{
			GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDObjUnsupported, GPOS_WSZ_LIT("Multi-level partitioned tables"));
		}

525
		if (!gpdb::IsMultilevelPartitionUniform(rel_oid))
526 527 528 529 530 531 532 533
		{
			GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDObjUnsupported, GPOS_WSZ_LIT("Multi-level partitioned tables with non-uniform partitioning structure"));
		}
	}
}

//---------------------------------------------------------------------------
//	@function:
534
//		CTranslatorRelcacheToDXL::RetrieveRel
535 536 537 538 539 540
//
//	@doc:
//		Retrieve a relation from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
IMDRelation *
541
CTranslatorRelcacheToDXL::RetrieveRel
542
	(
543 544 545
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	IMDId *mdid
546 547
	)
{
548
	OID oid = CMDIdGPDB::CastMdid(mdid)->Oid();
549 550 551 552
	GPOS_ASSERT(InvalidOid != oid);

	CheckUnsupportedRelation(oid);

553
	Relation rel = gpdb::GetRelation(oid);
554 555 556

	if (NULL == rel)
	{
557
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
558 559
	}

560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
	CMDName *mdname = NULL;
	IMDRelation::Erelstoragetype rel_storage_type = IMDRelation::ErelstorageSentinel;
	CMDColumnArray *mdcol_array = NULL;
	IMDRelation::Ereldistrpolicy dist = IMDRelation::EreldistrSentinel;
	ULongPtrArray *distr_cols = NULL;
	CMDIndexInfoArray *md_index_info_array = NULL;
	IMdIdArray *mdid_triggers_array = NULL;
	ULongPtrArray *part_keys = NULL;
	CharPtrArray *part_types = NULL;
	ULONG num_leaf_partitions = 0;
	BOOL convert_hash_to_random = false;
	ULongPtr2dArray *keyset_array = NULL;
	IMdIdArray *check_constraint_mdids = NULL;
	BOOL is_temporary = false;
	BOOL has_oids = false;
	BOOL is_partitioned = false;
	IMDRelation *md_rel = NULL;
577 578 579 580 581


	GPOS_TRY
	{
		// get rel name
582
		mdname = GetRelName(mp, rel);
583 584

		// get storage type
585
		rel_storage_type = RetrieveRelStorageType(rel->rd_rel->relstorage);
586 587

		// get relation columns
588 589 590
		mdcol_array = RetrieveRelColumns(mp, md_accessor, rel, rel_storage_type);
		const ULONG max_cols = GPDXL_SYSTEM_COLUMNS + (ULONG) rel->rd_att->natts + 1;
		ULONG *attno_mapping = ConstructAttnoMapping(mp, mdcol_array, max_cols);
591 592

		// get distribution policy
593 594
		GpPolicy *gp_policy = gpdb::GetDistributionPolicy(rel);
		dist = GetRelDistribution(gp_policy);
595 596

		// get distribution columns
597
		if (IMDRelation::EreldistrHash == dist)
598
		{
599
			distr_cols = RetrieveRelDistrbutionCols(mp, gp_policy, mdcol_array, max_cols);
600 601
		}

602
		convert_hash_to_random = gpdb::IsChildPartDistributionMismatched(rel);
E
Entong Shen 已提交
603

604
		// collect relation indexes
605
		md_index_info_array = RetrieveRelIndexInfo(mp, rel);
606 607

		// collect relation triggers
608
		mdid_triggers_array = RetrieveRelTriggers(mp, rel);
609 610

		// get partition keys
611
		if (IMDRelation::ErelstorageExternal != rel_storage_type)
612
		{
613
			RetrievePartKeysAndTypes(mp, rel, oid, &part_keys, &part_types);
614
		}
615
		is_partitioned = (NULL != part_keys && 0 < part_keys->Size());
616

617
		if (is_partitioned && IMDRelation::ErelstorageAppendOnlyParquet != rel_storage_type && IMDRelation::ErelstorageExternal != rel_storage_type)
618 619
		{
			// mark relation as Parquet if one of its children is parquet
620
			if (gpdb::HasParquetChildren(oid))
621
			{
622
				rel_storage_type = IMDRelation::ErelstorageAppendOnlyParquet;
623 624
			}
		}
625 626

		// get number of leaf partitions
627
		if (gpdb::RelPartIsRoot(oid))
628
		{
629
			num_leaf_partitions = gpdb::CountLeafPartTables(oid);
630 631
		}

632
		// get key sets
633 634
		BOOL should_add_default_keys = RelHasSystemColumns(rel->rd_rel->relkind);
		keyset_array = RetrieveRelKeysets(mp, oid, should_add_default_keys, is_partitioned, attno_mapping);
635 636

		// collect all check constraints
637
		check_constraint_mdids = RetrieveRelCheckConstraints(mp, oid);
638

639 640
		is_temporary = rel->rd_istemp;
		has_oids = rel->rd_rel->relhasoids;
641
	
642
		GPOS_DELETE_ARRAY(attno_mapping);
643 644 645 646 647 648 649 650 651
		gpdb::CloseRelation(rel);
	}
	GPOS_CATCH_EX(ex)
	{
		gpdb::CloseRelation(rel);
		GPOS_RETHROW(ex);
	}
	GPOS_CATCH_END;

652 653
	GPOS_ASSERT(IMDRelation::ErelstorageSentinel != rel_storage_type);
	GPOS_ASSERT(IMDRelation::EreldistrSentinel != dist);
654

655
	mdid->AddRef();
656

657
	if (IMDRelation::ErelstorageExternal == rel_storage_type)
658
	{
659
		ExtTableEntry *extentry = gpdb::GetExternalTableEntry(oid);
660 661 662 663 664

		// get format error table id
		IMDId *pmdidFmtErrTbl = NULL;
		if (InvalidOid != extentry->fmterrtbl)
		{
665
			pmdidFmtErrTbl = GPOS_NEW(mp) CMDIdGPDB(extentry->fmterrtbl);
666 667
		}

668
		md_rel = GPOS_NEW(mp) CMDRelationExternalGPDB
669
							(
670 671 672 673 674 675 676 677 678 679 680
							mp,
							mdid,
							mdname,
							dist,
							mdcol_array,
							distr_cols,
							convert_hash_to_random,
							keyset_array,
							md_index_info_array,
							mdid_triggers_array,
							check_constraint_mdids,
681 682 683 684 685 686 687
							extentry->rejectlimit,
							('r' == extentry->rejectlimittype),
							pmdidFmtErrTbl
							);
	}
	else
	{
688
		CMDPartConstraintGPDB *mdpart_constraint = NULL;
689 690

		// retrieve the part constraints if relation is partitioned
691 692
		if (is_partitioned)
			mdpart_constraint = RetrievePartConstraintForRel(mp, md_accessor, oid, mdcol_array, md_index_info_array->Size() > 0 /*has_index*/);
693

694
		md_rel = GPOS_NEW(mp) CMDRelationGPDB
695
							(
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
							mp,
							mdid,
							mdname,
							is_temporary,
							rel_storage_type,
							dist,
							mdcol_array,
							distr_cols,
							part_keys,
							part_types,
							num_leaf_partitions,
							convert_hash_to_random,
							keyset_array,
							md_index_info_array,
							mdid_triggers_array,
							check_constraint_mdids,
							mdpart_constraint,
							has_oids
714 715 716
							);
	}

717
	return md_rel;
718 719 720 721
}

//---------------------------------------------------------------------------
//	@function:
722
//		CTranslatorRelcacheToDXL::RetrieveRelColumns
723 724 725 726 727
//
//	@doc:
//		Get relation columns
//
//---------------------------------------------------------------------------
728 729
CMDColumnArray *
CTranslatorRelcacheToDXL::RetrieveRelColumns
730
	(
731 732
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
733
	Relation rel,
734
	IMDRelation::Erelstoragetype rel_storage_type
735 736
	)
{
737
	CMDColumnArray *mdcol_array = GPOS_NEW(mp) CMDColumnArray(mp);
738 739 740 741

	for (ULONG ul = 0;  ul < (ULONG) rel->rd_att->natts; ul++)
	{
		Form_pg_attribute att = rel->rd_att->attrs[ul];
742
		CMDName *md_colname = CDXLUtils::CreateMDNameFromCharArray(mp, NameStr(att->attname));
743 744
	
		// translate the default column value
745
		CDXLNode *dxl_default_col_val = NULL;
746 747 748
		
		if (!att->attisdropped)
		{
749
			dxl_default_col_val = GetDefaultColumnValue(mp, md_accessor, rel->rd_att, att->attnum);
750 751
		}

752 753 754
		ULONG col_len = gpos::ulong_max;
		CMDIdGPDB *mdid_col = GPOS_NEW(mp) CMDIdGPDB(att->atttypid);
		HeapTuple stats_tup = gpdb::GetAttStats(rel->rd_id, ul+1);
755 756 757 758 759 760 761 762

		// Column width priority:
		// 1. If there is average width kept in the stats for that column, pick that value.
		// 2. If not, if it is a fixed length text type, pick the size of it. E.g if it is
		//    varchar(10), assign 10 as the column length.
		// 3. Else if it not dropped and a fixed length type such as int4, assign the fixed
		//    length.
		// 4. Otherwise, assign it to default column width which is 8.
763
		if(HeapTupleIsValid(stats_tup))
764
		{
765
			Form_pg_statistic form_pg_stats = (Form_pg_statistic) GETSTRUCT(stats_tup);
766 767

			// column width
768 769
			col_len = form_pg_stats->stawidth;
			gpdb::FreeHeapTuple(stats_tup);
770
		}
771
		else if ((mdid_col->Equals(&CMDIdGPDB::m_mdid_bpchar) || mdid_col->Equals(&CMDIdGPDB::m_mdid_varchar)) && (VARHDRSZ < att->atttypmod))
772
		{
773
			col_len = (ULONG) att->atttypmod - VARHDRSZ;
774
		}
775 776
		else
		{
777 778
			DOUBLE width = CStatistics::DefaultColumnWidth.Get();
			col_len = (ULONG) width;
779 780 781

			if (!att->attisdropped)
			{
782 783
				IMDType *md_type = CTranslatorRelcacheToDXL::RetrieveType(mp, mdid_col);
				if(md_type->IsFixedLength())
784
				{
785
					col_len = md_type->Length();
786
				}
787
				md_type->Release();
788 789
			}
		}
790

791
		CMDColumn *md_col = GPOS_NEW(mp) CMDColumn
792
										(
793
										md_colname,
794
										att->attnum,
795
										mdid_col,
796
										att->atttypmod,
797 798
										!att->attnotnull,
										att->attisdropped,
799 800
										dxl_default_col_val /* default value */,
										col_len
801 802
										);

803
		mdcol_array->Append(md_col);
804 805 806
	}

	// add system columns
807
	if (RelHasSystemColumns(rel->rd_rel->relkind))
808
	{
809 810 811
		BOOL is_ao_table = IMDRelation::ErelstorageAppendOnlyRows == rel_storage_type ||
				IMDRelation::ErelstorageAppendOnlyCols == rel_storage_type;
		AddSystemColumns(mp, mdcol_array, rel, is_ao_table);
812 813
	}

814
	return mdcol_array;
815 816 817 818
}

//---------------------------------------------------------------------------
//	@function:
819
//		CTranslatorRelcacheToDXL::GetDefaultColumnValue
820 821 822 823 824 825
//
//	@doc:
//		Return the dxl representation of column's default value
//
//---------------------------------------------------------------------------
CDXLNode *
826
CTranslatorRelcacheToDXL::GetDefaultColumnValue
827
	(
828 829
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
830 831 832 833 834 835
	TupleDesc rd_att,
	AttrNumber attno
	)
{
	GPOS_ASSERT(attno > 0);

836
	Node *node = NULL;
837 838 839 840 841

	// Scan to see if relation has a default for this column
	if (NULL != rd_att->constr && 0 < rd_att->constr->num_defval)
	{
		AttrDefault *defval = rd_att->constr->defval;
842
		INT	num_def = rd_att->constr->num_defval;
843 844

		GPOS_ASSERT(NULL != defval);
845
		for (ULONG ul = 0; ul < (ULONG) num_def; ul++)
846
		{
847
			if (attno == defval[ul].adnum)
848 849
			{
				// found it, convert string representation to node tree.
850
				node = gpdb::StringToNode(defval[ul].adbin);
851 852 853 854 855
				break;
			}
		}
	}

856
	if (NULL == node)
857 858 859
	{
		// get the default value for the type
		Form_pg_attribute att_tup = rd_att->attrs[attno - 1];
860
		node = gpdb::GetTypeDefault(att_tup->atttypid);
861 862
	}

863
	if (NULL == node)
864 865 866 867 868
	{
		return NULL;
	}

	// translate the default value expression
869
	CTranslatorScalarToDXL scalar_translator
870
							(
871 872
							mp,
							md_accessor,
873 874
							NULL, /* pulidgtorCol */
							NULL, /* pulidgtorCTE */
875
							0, /* query_level */
876
							true, /* m_fQuery */
877 878
							NULL, /* query_level_to_cte_map */
							NULL /* cte_dxlnode_array */
879 880
							);

881
	return scalar_translator.TranslateScalarToDXL
882
							(
883 884
							(Expr *) node,
							NULL /* var_colid_mapping --- subquery or external variable are not supported in default expression */
885 886 887 888 889
							);
}

//---------------------------------------------------------------------------
//	@function:
890
//		CTranslatorRelcacheToDXL::GetRelDistribution
891 892 893 894 895 896
//
//	@doc:
//		Return the distribution policy of the relation
//
//---------------------------------------------------------------------------
IMDRelation::Ereldistrpolicy
897
CTranslatorRelcacheToDXL::GetRelDistribution
898
	(
899
	GpPolicy *gp_policy
900 901
	)
{
902
	if (NULL == gp_policy)
903 904 905 906
	{
		return IMDRelation::EreldistrMasterOnly;
	}

907
	if (POLICYTYPE_PARTITIONED == gp_policy->ptype)
908
	{
909
		if (0 == gp_policy->nattrs)
910 911 912 913 914 915 916
		{
			return IMDRelation::EreldistrRandom;
		}

		return IMDRelation::EreldistrHash;
	}

917
	if (POLICYTYPE_ENTRY == gp_policy->ptype)
918 919 920 921 922 923 924 925 926 927
	{
		return IMDRelation::EreldistrMasterOnly;
	}

	GPOS_ASSERT(!"Unrecognized distribution policy");
	return IMDRelation::EreldistrSentinel;
}

//---------------------------------------------------------------------------
//	@function:
928
//		CTranslatorRelcacheToDXL::RetrieveRelDistrbutionCols
929 930 931 932 933
//
//	@doc:
//		Get distribution columns
//
//---------------------------------------------------------------------------
934 935
ULongPtrArray *
CTranslatorRelcacheToDXL::RetrieveRelDistrbutionCols
936
	(
937 938 939 940
	IMemoryPool *mp,
	GpPolicy *gp_policy,
	CMDColumnArray *mdcol_array,
	ULONG size
941 942
	)
{
943
	ULONG *attno_mapping = GPOS_NEW_ARRAY(mp , ULONG, size);
944

945
	for (ULONG ul = 0;  ul < mdcol_array->Size(); ul++)
946
	{
947 948
		const IMDColumn *md_col = (*mdcol_array)[ul];
		INT attno = md_col->AttrNum();
949

950 951
		ULONG idx = (ULONG) (GPDXL_SYSTEM_COLUMNS + attno);
		attno_mapping[idx] = ul;
952 953
	}

954
	ULongPtrArray *distr_cols = GPOS_NEW(mp) ULongPtrArray(mp);
955

956
	for (ULONG ul = 0; ul < (ULONG) gp_policy->nattrs; ul++)
957
	{
958 959
		AttrNumber attno = gp_policy->attrs[ul];
		distr_cols->Append(GPOS_NEW(mp) ULONG(GetAttributePosition(attno, attno_mapping)));
960 961
	}

962 963
	GPOS_DELETE_ARRAY(attno_mapping);
	return distr_cols;
964 965 966 967 968 969 970 971 972 973 974 975 976
}

//---------------------------------------------------------------------------
//	@function:
//		CTranslatorRelcacheToDXL::AddSystemColumns
//
//	@doc:
//		Adding system columns (oid, tid, xmin, etc) in table descriptors
//
//---------------------------------------------------------------------------
void
CTranslatorRelcacheToDXL::AddSystemColumns
	(
977 978
	IMemoryPool *mp,
	CMDColumnArray *mdcol_array,
979
	Relation rel,
980
	BOOL is_ao_table
981 982
	)
{
983 984
	BOOL has_oids = rel->rd_att->tdhasoid;
	is_ao_table = is_ao_table || gpdb::IsAppendOnlyPartitionTable(rel->rd_id);
985

986 987 988 989 990
	for (INT i= SelfItemPointerAttributeNumber; i > FirstLowInvalidHeapAttributeNumber; i--)
	{
		AttrNumber attno = AttrNumber(i);
		GPOS_ASSERT(0 != attno);

991
		if (ObjectIdAttributeNumber == i && !has_oids)
992 993 994
		{
			continue;
		}
995

996
		if (IsTransactionVisibilityAttribute(i) && is_ao_table)
997 998 999 1000
		{
			// skip transaction attrbutes like xmin, xmax, cmin, cmax for AO tables
			continue;
		}
1001

1002
		// get system name for that attribute
1003 1004
		const CWStringConst *sys_colname = CTranslatorUtils::GetSystemColName(attno);
		GPOS_ASSERT(NULL != sys_colname);
1005 1006

		// copy string into column name
1007
		CMDName *md_colname = GPOS_NEW(mp) CMDName(mp, sys_colname);
1008

1009
		CMDColumn *md_col = GPOS_NEW(mp) CMDColumn
1010
										(
1011
										md_colname,
1012
										attno, 
1013 1014 1015 1016
										CTranslatorUtils::GetSystemColType(mp, attno),
										default_type_modifier,
										false,	// is_nullable
										false,	// is_dropped
1017
										NULL,	// default value
1018
										CTranslatorUtils::GetSystemColLength(attno)
1019 1020
										);

1021
		mdcol_array->Append(md_col);
1022 1023 1024 1025 1026
	}
}

//---------------------------------------------------------------------------
//	@function:
1027
//		CTranslatorRelcacheToDXL::IsTransactionVisibilityAttribute
1028 1029 1030 1031 1032 1033 1034
//
//	@doc:
//		Check if attribute number is one of the system attributes related to 
//		transaction visibility such as xmin, xmax, cmin, cmax
//
//---------------------------------------------------------------------------
BOOL
1035
CTranslatorRelcacheToDXL::IsTransactionVisibilityAttribute
1036
	(
1037
	INT attno
1038 1039
	)
{
1040 1041
	return attno == MinTransactionIdAttributeNumber || attno == MaxTransactionIdAttributeNumber ||
			attno == MinCommandIdAttributeNumber || attno == MaxCommandIdAttributeNumber;
1042 1043 1044 1045
}

//---------------------------------------------------------------------------
//	@function:
1046
//		CTranslatorRelcacheToDXL::RetrieveIndex
1047 1048 1049 1050 1051 1052
//
//	@doc:
//		Retrieve an index from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
IMDIndex *
1053
CTranslatorRelcacheToDXL::RetrieveIndex
1054
	(
1055 1056 1057
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	IMDId *mdid_index
1058 1059
	)
{
1060 1061 1062
	OID index_oid = CMDIdGPDB::CastMdid(mdid_index)->Oid();
	GPOS_ASSERT(0 != index_oid);
	Relation index_rel = gpdb::GetRelation(index_oid);
1063

1064
	if (NULL == index_rel)
1065
	{
1066
		 GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid_index->GetBuffer());
1067 1068
	}

1069 1070 1071 1072 1073
	const IMDRelation *md_rel = NULL;
	Form_pg_index form_pg_index = NULL;
	CMDName *mdname = NULL;
	IMDIndex::EmdindexType index_type = IMDIndex::EmdindSentinel;
	IMDId *mdid_item_type = NULL;
1074 1075 1076
	bool index_clustered = false;
	ULongPtrArray *index_key_cols_array = NULL;
	ULONG *attno_mapping = NULL;
1077 1078 1079

	GPOS_TRY
	{
1080
		if (!IsIndexSupported(index_rel))
1081 1082 1083 1084
		{
			GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDObjUnsupported, GPOS_WSZ_LIT("Index type"));
		}

1085 1086
		form_pg_index = index_rel->rd_index;
		GPOS_ASSERT (NULL != form_pg_index);
1087
		index_clustered = form_pg_index->indisclustered;
1088

1089
		OID rel_oid = form_pg_index->indrelid;
1090

1091
		if (gpdb::IsLeafPartition(rel_oid))
1092
		{
1093
			rel_oid = gpdb::GetRootPartition(rel_oid);
1094 1095
		}

1096
		CMDIdGPDB *mdid_rel = GPOS_NEW(mp) CMDIdGPDB(rel_oid);
1097

1098
		md_rel = md_accessor->RetrieveRel(mdid_rel);
1099
	
1100
		if (md_rel->IsPartitioned())
1101
		{
1102 1103
			LogicalIndexes *logical_indexes = gpdb::GetLogicalPartIndexes(rel_oid);
			GPOS_ASSERT(NULL != logical_indexes);
1104

1105
			IMDIndex *index = RetrievePartTableIndex(mp, md_accessor, mdid_index, md_rel, logical_indexes);
1106 1107

			// cleanup
1108
			gpdb::GPDBFree(logical_indexes);
1109

1110
			if (NULL != index)
1111
			{
1112 1113 1114
				mdid_rel->Release();
				gpdb::CloseRelation(index_rel);
				return index;
1115
			}
1116 1117
		}
	
1118 1119 1120
		index_type = IMDIndex::EmdindBtree;
		IMDRelation::Erelstoragetype rel_storage_type = md_rel->RetrieveRelStorageType();
		if (GIST_AM_OID == index_rel->rd_rel->relam)
A
Ashuka Xue 已提交
1121
		{
1122 1123
			index_type = IMDIndex::EmdindGist;
			mdid_item_type = GPOS_NEW(mp) CMDIdGPDB(GPDB_ANY);
A
Ashuka Xue 已提交
1124
		}
1125
		else if (BITMAP_AM_OID == index_rel->rd_rel->relam || IMDRelation::ErelstorageAppendOnlyRows == rel_storage_type || IMDRelation::ErelstorageAppendOnlyCols == rel_storage_type)
1126
		{
1127 1128
			index_type = IMDIndex::EmdindBitmap;
			mdid_item_type = GPOS_NEW(mp) CMDIdGPDB(GPDB_ANY);
1129
		}
A
Ashuka Xue 已提交
1130

1131
		// get the index name
1132 1133 1134 1135
		CHAR *index_name = NameStr(index_rel->rd_rel->relname);
		CWStringDynamic *str_name = CDXLUtils::CreateDynamicStringFromCharArray(mp, index_name);
		mdname = GPOS_NEW(mp) CMDName(mp, str_name);
		GPOS_DELETE(str_name);
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152

		Relation table = gpdb::GetRelation(CMDIdGPDB::CastMdid(md_rel->MDId())->Oid());
		ULONG size = GPDXL_SYSTEM_COLUMNS + (ULONG) table->rd_att->natts + 1;
		gpdb::CloseRelation(table); // close relation as early as possible

		attno_mapping = PopulateAttnoPositionMap(mp, md_rel, size);

		// extract the position of the key columns
		index_key_cols_array = GPOS_NEW(mp) ULongPtrArray(mp);

		for (ULONG ul = 0; ul < form_pg_index->indnatts; ul++)
		{
			INT attno = form_pg_index->indkey.values[ul];
			GPOS_ASSERT(0 != attno && "Index expressions not supported");

			index_key_cols_array->Append(GPOS_NEW(mp) ULONG(GetAttributePosition(attno, attno_mapping)));
		}
1153 1154
		mdid_rel->Release();
		gpdb::CloseRelation(index_rel);
1155 1156 1157
	}
	GPOS_CATCH_EX(ex)
	{
1158
		gpdb::CloseRelation(index_rel);
1159 1160 1161 1162
		GPOS_RETHROW(ex);
	}
	GPOS_CATCH_END;

1163 1164 1165
	ULongPtrArray *included_cols = ComputeIncludedCols(mp, md_rel);
	mdid_index->AddRef();
	IMdIdArray *op_families_mdids = RetrieveIndexOpFamilies(mp, mdid_index);
1166

1167
	CMDIndexGPDB *index = GPOS_NEW(mp) CMDIndexGPDB
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
		(
		 mp,
		 mdid_index,
		 mdname,
		 index_clustered,
		 index_type,
		 mdid_item_type,
		 index_key_cols_array,
		 included_cols,
		 op_families_mdids,
		 NULL // mdpart_constraint
		);
1180

1181 1182
	GPOS_DELETE_ARRAY(attno_mapping);
	return index;
1183 1184 1185 1186
}

//---------------------------------------------------------------------------
//	@function:
1187
//		CTranslatorRelcacheToDXL::RetrievePartTableIndex
1188 1189 1190 1191 1192 1193 1194
//
//	@doc:
//		Retrieve an index over a partitioned table from the relcache given its 
//		mdid
//
//---------------------------------------------------------------------------
IMDIndex *
1195
CTranslatorRelcacheToDXL::RetrievePartTableIndex
1196
	(
1197 1198 1199 1200 1201
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	IMDId *mdid_index,
	const IMDRelation *md_rel,
	LogicalIndexes *logical_indexes
1202 1203
	)
{
1204 1205
	GPOS_ASSERT(NULL != logical_indexes);
	GPOS_ASSERT(0 < logical_indexes->numLogicalIndexes);
1206
	
1207
	OID oid = CMDIdGPDB::CastMdid(mdid_index)->Oid();
1208
	
1209 1210
	LogicalIndexInfo *index_info = LookupLogicalIndexById(logical_indexes, oid);
	if (NULL == index_info)
1211
	{
1212
		 return NULL;
1213 1214
	}
	
1215
	return RetrievePartTableIndex(mp, md_accessor, index_info, mdid_index, md_rel);
1216 1217 1218 1219
}

//---------------------------------------------------------------------------
//	@function:
1220
//		CTranslatorRelcacheToDXL::LookupLogicalIndexById
1221 1222 1223 1224 1225 1226
//
//	@doc:
//		Lookup an index given its id from the logical indexes structure
//
//---------------------------------------------------------------------------
LogicalIndexInfo *
1227
CTranslatorRelcacheToDXL::LookupLogicalIndexById
1228
	(
1229
	LogicalIndexes *logical_indexes,
1230 1231 1232
	OID oid
	)
{
1233
	GPOS_ASSERT(NULL != logical_indexes && 0 <= logical_indexes->numLogicalIndexes);
1234
	
1235
	const ULONG num_index = logical_indexes->numLogicalIndexes;
1236
	
1237
	for (ULONG ul = 0; ul < num_index; ul++)
1238
	{
1239
		LogicalIndexInfo *index_info = (logical_indexes->logicalIndexInfo)[ul];
1240
		
1241
		if (oid == index_info->logicalIndexOid)
1242
		{
1243
			return index_info;
1244 1245 1246 1247 1248 1249 1250 1251
		}
	}
	
	return NULL;
}

//---------------------------------------------------------------------------
//	@function:
1252
//		CTranslatorRelcacheToDXL::RetrievePartTableIndex
1253 1254 1255 1256 1257 1258
//
//	@doc:
//		Construct an MD cache index object given its logical index representation
//
//---------------------------------------------------------------------------
IMDIndex *
1259
CTranslatorRelcacheToDXL::RetrievePartTableIndex
1260
	(
1261 1262 1263 1264 1265
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	LogicalIndexInfo *index_info,
	IMDId *mdid_index,
	const IMDRelation *md_rel
1266 1267
	)
{
1268
	OID index_oid = index_info->logicalIndexOid;
1269
	
1270
	Relation index_rel = gpdb::GetRelation(index_oid);
1271

1272
	if (NULL == index_rel)
1273
	{
1274
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid_index->GetBuffer());
1275 1276
	}

1277
	if (!IsIndexSupported(index_rel))
1278
	{
1279
		gpdb::CloseRelation(index_rel);
1280 1281 1282 1283
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDObjUnsupported, GPOS_WSZ_LIT("Index type"));
	}
	
	// get the index name
1284 1285
	GPOS_ASSERT(NULL != index_rel->rd_index);
	Form_pg_index form_pg_index = index_rel->rd_index;
1286
	
1287 1288 1289
	CHAR *index_name = NameStr(index_rel->rd_rel->relname);
	CMDName *mdname = CDXLUtils::CreateMDNameFromCharArray(mp, index_name);
	gpdb::CloseRelation(index_rel);
1290

1291 1292 1293 1294
	OID rel_oid = CMDIdGPDB::CastMdid(md_rel->MDId())->Oid();
	Relation table = gpdb::GetRelation(rel_oid);
	ULONG size = GPDXL_SYSTEM_COLUMNS + (ULONG) table->rd_att->natts + 1;
	gpdb::CloseRelation(table);
1295

1296
	ULONG *attno_mapping = PopulateAttnoPositionMap(mp, md_rel, size);
1297

1298
	ULongPtrArray *included_cols = ComputeIncludedCols(mp, md_rel);
1299 1300

	// extract the position of the key columns
1301 1302 1303
	ULongPtrArray *index_key_cols_array = GPOS_NEW(mp) ULongPtrArray(mp);

	for (ULONG ul = 0; ul < index_info->nColumns; ul++)
1304
	{
1305 1306
		INT attno = index_info->indexKeys[ul];
		GPOS_ASSERT(0 != attno && "Index expressions not supported");
1307

1308
		index_key_cols_array->Append(GPOS_NEW(mp) ULONG(GetAttributePosition(attno, attno_mapping)));
1309 1310
	}
	
1311
	/*
1312
	 * If an index exists only on a leaf part, part_constraint refers to the expression
1313 1314 1315
	 * identifying the path to reach the partition holding the index. For indexes
	 * available on all parts it is set to NULL.
	 */
1316
	Node *part_constraint = index_info->partCons;
1317 1318 1319 1320 1321 1322 1323
	
	/*
	 * If an index exists all on the parts including default, the logical index
	 * info created marks defaultLevels as NIL. However, if an index exists only on
	 * leaf parts plDefaultLevel contains the default part level which come across while
	 * reaching to the leaf part from root.
	 */
1324
	List *default_levels = index_info->defaultLevels;
1325 1326
	
	// get number of partitioning levels
1327 1328 1329
	List *part_keys = gpdb::GetPartitionAttrs(rel_oid);
	const ULONG num_of_levels = gpdb::ListLength(part_keys);
	gpdb::ListFree(part_keys);
1330

1331
	/* get relation constraints
1332
	 * default_levels_rel indicates the levels on which default partitions exists
1333 1334
	 * for the partitioned table
	 */
1335 1336
	List *default_levels_rel = NIL;
	Node *part_constraints_rel = gpdb::GetRelationPartContraints(rel_oid, &default_levels_rel);
1337

1338 1339
	BOOL is_unbounded = (NULL == part_constraint) && (NIL == default_levels);
	for (ULONG ul = 0; ul < num_of_levels; ul++)
1340
	{
1341
		is_unbounded = is_unbounded && LevelHasDefaultPartition(default_levels_rel, ul);
1342 1343
	}

1344
	/*
1345
	 * If part_constraint is NULL and default_levels is NIL,
1346 1347 1348 1349 1350
	 * it indicates that the index is available on all the parts including
	 * default part. So, we can say that levels on which default partitions
	 * exists for the relation applies to the index as well and the relative
	 * scan will not be partial.
	 */
1351 1352 1353
	List *default_levels_derived_list = NIL;
	if (NULL == part_constraint && NIL == default_levels)
		default_levels_derived_list = default_levels_rel;
1354
	else
1355
		default_levels_derived_list = default_levels;
1356
	
1357 1358
	ULongPtrArray *default_levels_derived = GPOS_NEW(mp) ULongPtrArray(mp);
	for (ULONG ul = 0; ul < num_of_levels; ul++)
1359
	{
1360
		if (is_unbounded || LevelHasDefaultPartition(default_levels_derived_list, ul))
1361
		{
1362
			default_levels_derived->Append(GPOS_NEW(mp) ULONG(ul));
1363 1364
		}
	}
1365
	gpdb::ListFree(default_levels_derived_list);
1366

1367
	if (NULL == part_constraint)
1368
	{
1369
		if (NIL == default_levels)
1370 1371
		{
			// NULL part constraints means all non-default partitions -> get constraint from the part table
1372
			part_constraint = part_constraints_rel;
1373 1374 1375
		}
		else
		{
1376
			part_constraint = gpdb::MakeBoolConst(false /*value*/, false /*isull*/);
1377 1378 1379
		}
	}
		
1380
	CMDPartConstraintGPDB *mdpart_constraint = RetrievePartConstraintForIndex(mp, md_accessor, md_rel, part_constraint, default_levels_derived, is_unbounded);
A
Ashuka Xue 已提交
1381

1382 1383 1384 1385 1386 1387 1388 1389
	default_levels_derived->Release();
	mdid_index->AddRef();
	
	GPOS_ASSERT(INDTYPE_BITMAP == index_info->indType || INDTYPE_BTREE == index_info->indType || INDTYPE_GIST == index_info->indType);
	
	IMDIndex::EmdindexType index_type = IMDIndex::EmdindBtree;
	IMDId *mdid_item_type = NULL;
	if (INDTYPE_BITMAP == index_info->indType)
1390
	{
1391 1392
		index_type = IMDIndex::EmdindBitmap;
		mdid_item_type = GPOS_NEW(mp) CMDIdGPDB(GPDB_ANY);
1393
	}
1394
	else if (INDTYPE_GIST == index_info->indType)
A
Ashuka Xue 已提交
1395
	{
1396 1397
		index_type = IMDIndex::EmdindGist;
		mdid_item_type = GPOS_NEW(mp) CMDIdGPDB(GPDB_ANY);
A
Ashuka Xue 已提交
1398
	}
1399
	
1400
	IMdIdArray *pdrgpmdidOpFamilies = RetrieveIndexOpFamilies(mp, mdid_index);
1401
	
1402
	CMDIndexGPDB *index = GPOS_NEW(mp) CMDIndexGPDB
1403
										(
1404 1405 1406 1407 1408 1409 1410 1411
										mp,
										mdid_index,
										mdname,
										form_pg_index->indisclustered,
										index_type,
										mdid_item_type,
										index_key_cols_array,
										included_cols,
1412
										pdrgpmdidOpFamilies,
1413
										mdpart_constraint
1414 1415
										);
	
1416
	GPOS_DELETE_ARRAY(attno_mapping);
1417
	
1418
	return index;
1419 1420 1421 1422
}

//---------------------------------------------------------------------------
//	@function:
1423
//		CTranslatorRelcacheToDXL::LevelHasDefaultPartition
1424 1425 1426 1427 1428 1429
//
//	@doc:
//		Check whether the default partition at level one is included
//
//---------------------------------------------------------------------------
BOOL
1430
CTranslatorRelcacheToDXL::LevelHasDefaultPartition
1431
	(
1432 1433
	List *default_levels,
	ULONG level
1434 1435
	)
{
1436
	if (NIL == default_levels)
1437 1438 1439 1440
	{
		return false;
	}
	
1441 1442
	ListCell *lc = NULL;
	ForEach (lc, default_levels)
1443
	{
1444 1445
		ULONG default_level = (ULONG) lfirst_int(lc);
		if (level == default_level)
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455
		{
			return true;
		}
	}
	
	return false;
}

//---------------------------------------------------------------------------
//	@function:
1456
//		CTranslatorRelcacheToDXL::ComputeIncludedCols
1457 1458 1459 1460 1461
//
//	@doc:
//		Compute the included colunms in an index
//
//---------------------------------------------------------------------------
1462 1463
ULongPtrArray *
CTranslatorRelcacheToDXL::ComputeIncludedCols
1464
	(
1465 1466
	IMemoryPool *mp,
	const IMDRelation *md_rel
1467 1468 1469 1470 1471
	)
{
	// TODO: 3/19/2012; currently we assume that all the columns
	// in the table are available from the index.

1472 1473 1474
	ULongPtrArray *included_cols = GPOS_NEW(mp) ULongPtrArray(mp);
	const ULONG num_included_cols = md_rel->ColumnCount();
	for (ULONG ul = 0;  ul < num_included_cols; ul++)
1475
	{
1476
		if (!md_rel->GetMdCol(ul)->IsDropped())
1477
		{
1478
			included_cols->Append(GPOS_NEW(mp) ULONG(ul));
1479 1480 1481
		}
	}
	
1482
	return included_cols;
1483 1484 1485 1486 1487
}


//---------------------------------------------------------------------------
//	@function:
1488
//		CTranslatorRelcacheToDXL::GetAttributePosition
1489 1490 1491 1492 1493 1494
//
//	@doc:
//		Return the position of a given attribute
//
//---------------------------------------------------------------------------
ULONG
1495
CTranslatorRelcacheToDXL::GetAttributePosition
1496
	(
1497 1498
	INT attno,
	ULONG *GetAttributePosition
1499 1500
	)
{
1501 1502 1503
	ULONG idx = (ULONG) (GPDXL_SYSTEM_COLUMNS + attno);
	ULONG pos = GetAttributePosition[idx];
	GPOS_ASSERT(gpos::ulong_max != pos);
1504

1505
	return pos;
1506 1507 1508 1509
}

//---------------------------------------------------------------------------
//	@function:
1510
//		CTranslatorRelcacheToDXL::PopulateAttnoPositionMap
1511 1512 1513 1514 1515 1516
//
//	@doc:
//		Populate the attribute to position mapping
//
//---------------------------------------------------------------------------
ULONG *
1517
CTranslatorRelcacheToDXL::PopulateAttnoPositionMap
1518
	(
1519 1520 1521
	IMemoryPool *mp,
	const IMDRelation *md_rel,
	ULONG size
1522 1523
	)
{
1524 1525
	GPOS_ASSERT(NULL != md_rel);
	const ULONG num_included_cols = md_rel->ColumnCount();
1526

1527 1528
	GPOS_ASSERT(num_included_cols <= size);
	ULONG *attno_mapping = GPOS_NEW_ARRAY(mp , ULONG, size);
1529

1530
	for (ULONG ul = 0; ul < size; ul++)
1531
	{
1532
		attno_mapping[ul] = gpos::ulong_max;
1533 1534
	}

1535
	for (ULONG ul = 0;  ul < num_included_cols; ul++)
1536
	{
1537
		const IMDColumn *md_col = md_rel->GetMdCol(ul);
1538

1539
		INT attno = md_col->AttrNum();
1540

1541 1542 1543
		ULONG idx = (ULONG) (GPDXL_SYSTEM_COLUMNS + attno);
		GPOS_ASSERT(size > idx);
		attno_mapping[idx] = ul;
1544 1545
	}

1546
	return attno_mapping;
1547 1548 1549 1550 1551
}


//---------------------------------------------------------------------------
//	@function:
1552
//		CTranslatorRelcacheToDXL::RetrieveType
1553 1554 1555 1556 1557 1558
//
//	@doc:
//		Retrieve a type from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
IMDType *
1559
CTranslatorRelcacheToDXL::RetrieveType
1560
	(
1561 1562
	IMemoryPool *mp,
	IMDId *mdid
1563 1564
	)
{
1565 1566
	OID oid_type = CMDIdGPDB::CastMdid(mdid)->Oid();
	GPOS_ASSERT(InvalidOid != oid_type);
1567 1568
	
	// check for supported base types
1569
	switch (oid_type)
1570 1571
	{
		case GPDB_INT2_OID:
1572
			return GPOS_NEW(mp) CMDTypeInt2GPDB(mp);
1573 1574

		case GPDB_INT4_OID:
1575
			return GPOS_NEW(mp) CMDTypeInt4GPDB(mp);
1576 1577

		case GPDB_INT8_OID:
1578
			return GPOS_NEW(mp) CMDTypeInt8GPDB(mp);
1579 1580

		case GPDB_BOOL:
1581
			return GPOS_NEW(mp) CMDTypeBoolGPDB(mp);
1582 1583

		case GPDB_OID_OID:
1584
			return GPOS_NEW(mp) CMDTypeOidGPDB(mp);
1585 1586 1587 1588 1589 1590
	}

	// continue to construct a generic type
	INT iFlags = TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR |
				 TYPECACHE_CMP_PROC | TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO | TYPECACHE_TUPDESC;

1591
	TypeCacheEntry *ptce = gpdb::LookupTypeCache(oid_type, iFlags);
1592 1593

	// get type name
1594
	CMDName *mdname = GetTypeName(mp, mdid);
1595

1596 1597
	BOOL is_fixed_length = false;
	ULONG length = 0;
1598 1599 1600

	if (0 < ptce->typlen)
	{
1601 1602
		is_fixed_length = true;
		length = ptce->typlen;
1603 1604
	}

1605
	BOOL is_passed_by_value = ptce->typbyval;
1606 1607

	// collect ids of different comparison operators for types
1608 1609 1610 1611 1612 1613 1614 1615 1616
	CMDIdGPDB *mdid_op_eq = GPOS_NEW(mp) CMDIdGPDB(ptce->eq_opr);
	CMDIdGPDB *mdid_op_neq = GPOS_NEW(mp) CMDIdGPDB(gpdb::GetInverseOp(ptce->eq_opr));
	CMDIdGPDB *mdid_op_lt = GPOS_NEW(mp) CMDIdGPDB(ptce->lt_opr);
	CMDIdGPDB *mdid_op_leq = GPOS_NEW(mp) CMDIdGPDB(gpdb::GetInverseOp(ptce->gt_opr));
	CMDIdGPDB *mdid_op_gt = GPOS_NEW(mp) CMDIdGPDB(ptce->gt_opr);
	CMDIdGPDB *mdid_op_geq = GPOS_NEW(mp) CMDIdGPDB(gpdb::GetInverseOp(ptce->lt_opr));
	CMDIdGPDB *mdid_op_cmp = GPOS_NEW(mp) CMDIdGPDB(ptce->cmp_proc);
	BOOL is_hashable = gpdb::IsOpHashJoinable(ptce->eq_opr);
	BOOL is_composite_type = gpdb::IsCompositeType(oid_type);
1617 1618

	// get standard aggregates
1619 1620 1621 1622
	CMDIdGPDB *mdid_min = GPOS_NEW(mp) CMDIdGPDB(gpdb::GetAggregate("min", oid_type));
	CMDIdGPDB *mdid_max = GPOS_NEW(mp) CMDIdGPDB(gpdb::GetAggregate("max", oid_type));
	CMDIdGPDB *mdid_avg = GPOS_NEW(mp) CMDIdGPDB(gpdb::GetAggregate("avg", oid_type));
	CMDIdGPDB *mdid_sum = GPOS_NEW(mp) CMDIdGPDB(gpdb::GetAggregate("sum", oid_type));
1623 1624
	
	// count aggregate is the same for all types
1625
	CMDIdGPDB *mdid_count = GPOS_NEW(mp) CMDIdGPDB(COUNT_ANY_OID);
1626 1627
	
	// check if type is composite
1628 1629
	CMDIdGPDB *mdid_type_relid = NULL;
	if (is_composite_type)
1630
	{
1631
		mdid_type_relid = GPOS_NEW(mp) CMDIdGPDB(gpdb::GetTypeRelid(oid_type));
1632 1633 1634
	}

	// get array type mdid
1635
	CMDIdGPDB *mdid_type_array = GPOS_NEW(mp) CMDIdGPDB(gpdb::GetArrayType(oid_type));
1636

1637
	BOOL is_redistributable = gpdb::IsGreenplumDbHashable(oid_type);
1638

1639
	mdid->AddRef();
1640

1641
	return GPOS_NEW(mp) CMDTypeGenericGPDB
1642
						 (
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
						 mp,
						 mdid,
						 mdname,
						 is_redistributable,
						 is_fixed_length,
						 length,
						 is_passed_by_value,
						 mdid_op_eq,
						 mdid_op_neq,
						 mdid_op_lt,
						 mdid_op_leq,
						 mdid_op_gt,
						 mdid_op_geq,
						 mdid_op_cmp,
						 mdid_min,
						 mdid_max,
						 mdid_avg,
						 mdid_sum,
						 mdid_count,
						 is_hashable,
						 is_composite_type,
						 mdid_type_relid,
						 mdid_type_array,
1666 1667 1668 1669 1670 1671 1672
						 ptce->typlen
						 );
}


//---------------------------------------------------------------------------
//	@function:
1673
//		CTranslatorRelcacheToDXL::RetrieveScOp
1674 1675 1676 1677 1678 1679
//
//	@doc:
//		Retrieve a scalar operator from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
CMDScalarOpGPDB *
1680
CTranslatorRelcacheToDXL::RetrieveScOp
1681
	(
1682 1683
	IMemoryPool *mp,
	IMDId *mdid
1684 1685
	)
{
1686
	OID op_oid = CMDIdGPDB::CastMdid(mdid)->Oid();
1687

1688
	GPOS_ASSERT(InvalidOid != op_oid);
1689 1690

	// get operator name
1691
	CHAR *name = gpdb::GetOpName(op_oid);
1692

1693
	if (NULL == name)
1694
	{
1695
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
1696 1697
	}

1698
	CMDName *mdname = CDXLUtils::CreateMDNameFromCharArray(mp, name);
1699
	
1700 1701
	OID left_oid = InvalidOid;
	OID right_oid = InvalidOid;
1702 1703

	// get operator argument types
1704
	gpdb::GetOpInputTypes(op_oid, &left_oid, &right_oid);
1705

1706 1707
	CMDIdGPDB *mdid_type_left = NULL;
	CMDIdGPDB *mdid_type_right = NULL;
1708

1709
	if (InvalidOid != left_oid)
1710
	{
1711
		mdid_type_left = GPOS_NEW(mp) CMDIdGPDB(left_oid);
1712 1713
	}

1714
	if (InvalidOid != right_oid)
1715
	{
1716
		mdid_type_right = GPOS_NEW(mp) CMDIdGPDB(right_oid);
1717 1718 1719
	}

	// get comparison type
1720 1721
	CmpType cmpt = (CmpType) gpdb::GetComparisonType(op_oid, left_oid, right_oid);
	IMDType::ECmpType cmp_type = ParseCmpType(cmpt);
1722 1723
	
	// get func oid
1724 1725
	OID func_oid = gpdb::GetOpFunc(op_oid);
	GPOS_ASSERT(InvalidOid != func_oid);
1726

1727
	CMDIdGPDB *mdid_func = GPOS_NEW(mp) CMDIdGPDB(func_oid);
1728 1729

	// get result type
1730
	OID result_oid = gpdb::GetFuncRetType(func_oid);
1731

1732
	GPOS_ASSERT(InvalidOid != result_oid);
1733

1734
	CMDIdGPDB *result_type_mdid = GPOS_NEW(mp) CMDIdGPDB(result_oid);
1735 1736

	// get commutator and inverse
1737
	CMDIdGPDB *mdid_commute_opr = NULL;
1738

1739
	OID commute_oid = gpdb::GetCommutatorOp(op_oid);
1740

1741
	if(InvalidOid != commute_oid)
1742
	{
1743
		mdid_commute_opr = GPOS_NEW(mp) CMDIdGPDB(commute_oid);
1744 1745
	}

1746
	CMDIdGPDB *m_mdid_inverse_opr = NULL;
1747

1748
	OID inverse_oid = gpdb::GetInverseOp(op_oid);
1749

1750
	if(InvalidOid != inverse_oid)
1751
	{
1752
		m_mdid_inverse_opr = GPOS_NEW(mp) CMDIdGPDB(inverse_oid);
1753 1754
	}

1755
	BOOL returns_null_on_null_input = gpdb::IsOpStrict(op_oid);
1756

1757 1758
	mdid->AddRef();
	CMDScalarOpGPDB *md_scalar_op = GPOS_NEW(mp) CMDScalarOpGPDB
1759
											(
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771
											mp,
											mdid,
											mdname,
											mdid_type_left,
											mdid_type_right,
											result_type_mdid,
											mdid_func,
											mdid_commute_opr,
											m_mdid_inverse_opr,
											cmp_type,
											returns_null_on_null_input,
											RetrieveScOpOpFamilies(mp, mdid)
1772
											);
1773
	return md_scalar_op;
1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
}


//---------------------------------------------------------------------------
//	@function:
//		CTranslatorRelcacheToDXL::LookupFuncProps
//
//	@doc:
//		Lookup function properties
//
//---------------------------------------------------------------------------
void
CTranslatorRelcacheToDXL::LookupFuncProps
	(
1788 1789 1790 1791 1792
	OID func_oid,
	IMDFunction::EFuncStbl *stability, // output: function stability
	IMDFunction::EFuncDataAcc *access, // output: function datya access
	BOOL *is_strict, // output: is function strict?
	BOOL *returns_set // output: does function return set?
1793 1794
	)
{
1795 1796 1797 1798
	GPOS_ASSERT(NULL != stability);
	GPOS_ASSERT(NULL != access);
	GPOS_ASSERT(NULL != is_strict);
	GPOS_ASSERT(NULL != returns_set);
1799

1800 1801
	CHAR cFuncStability = gpdb::FuncStability(func_oid);
	*stability = GetFuncStability(cFuncStability);
1802

1803 1804
	CHAR cFuncDataAccess = gpdb::FuncDataAccess(func_oid);
	*access = GetEFuncDataAccess(cFuncDataAccess);
1805

1806 1807
	*returns_set = gpdb::GetFuncRetset(func_oid);
	*is_strict = gpdb::FuncStrict(func_oid);
1808 1809 1810 1811 1812
}


//---------------------------------------------------------------------------
//	@function:
1813
//		CTranslatorRelcacheToDXL::RetrieveFunc
1814 1815 1816 1817 1818 1819
//
//	@doc:
//		Retrieve a function from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
CMDFunctionGPDB *
1820
CTranslatorRelcacheToDXL::RetrieveFunc
1821
	(
1822 1823
	IMemoryPool *mp,
	IMDId *mdid
1824 1825
	)
{
1826
	OID func_oid = CMDIdGPDB::CastMdid(mdid)->Oid();
1827

1828
	GPOS_ASSERT(InvalidOid != func_oid);
1829 1830

	// get func name
1831
	CHAR *name = gpdb::GetFuncName(func_oid);
1832

1833
	if (NULL == name)
1834 1835
	{

1836
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
1837 1838
	}

1839 1840
	CWStringDynamic *func_name_str = CDXLUtils::CreateDynamicStringFromCharArray(mp, name);
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, func_name_str);
1841 1842

	// CMDName ctor created a copy of the string
1843
	GPOS_DELETE(func_name_str);
1844 1845

	// get result type
1846
	OID result_oid = gpdb::GetFuncRetType(func_oid);
1847

1848
	GPOS_ASSERT(InvalidOid != result_oid);
1849

1850
	CMDIdGPDB *result_type_mdid = GPOS_NEW(mp) CMDIdGPDB(result_oid);
1851 1852

	// get output argument types if any
1853
	List *out_arg_types_list = gpdb::GetFuncOutputArgTypes(func_oid);
1854

1855 1856
	IMdIdArray *arg_type_mdids = NULL;
	if (NULL != out_arg_types_list)
1857
	{
1858 1859
		ListCell *lc = NULL;
		arg_type_mdids = GPOS_NEW(mp) IMdIdArray(mp);
1860

1861
		ForEach (lc, out_arg_types_list)
1862
		{
1863
			OID oidArgType = lfirst_oid(lc);
1864
			GPOS_ASSERT(InvalidOid != oidArgType);
1865 1866
			CMDIdGPDB *pmdidArgType = GPOS_NEW(mp) CMDIdGPDB(oidArgType);
			arg_type_mdids->Append(pmdidArgType);
1867 1868
		}

1869
		gpdb::GPDBFree(out_arg_types_list);
1870 1871
	}

1872 1873 1874 1875 1876
	IMDFunction::EFuncStbl stability = IMDFunction::EfsImmutable;
	IMDFunction::EFuncDataAcc access = IMDFunction::EfdaNoSQL;
	BOOL is_strict = true;
	BOOL returns_set = true;
	LookupFuncProps(func_oid, &stability, &access, &is_strict, &returns_set);
1877

1878 1879
	mdid->AddRef();
	CMDFunctionGPDB *md_func = GPOS_NEW(mp) CMDFunctionGPDB
1880
											(
1881 1882 1883 1884 1885 1886 1887 1888 1889
											mp,
											mdid,
											mdname,
											result_type_mdid,
											arg_type_mdids,
											returns_set,
											stability,
											access,
											is_strict
1890 1891
											);

1892
	return md_func;
1893 1894 1895 1896
}

//---------------------------------------------------------------------------
//	@function:
1897
//		CTranslatorRelcacheToDXL::RetrieveAgg
1898 1899 1900 1901 1902 1903
//
//	@doc:
//		Retrieve an aggregate from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
CMDAggregateGPDB *
1904
CTranslatorRelcacheToDXL::RetrieveAgg
1905
	(
1906 1907
	IMemoryPool *mp,
	IMDId *mdid
1908 1909
	)
{
1910
	OID agg_oid = CMDIdGPDB::CastMdid(mdid)->Oid();
1911

1912
	GPOS_ASSERT(InvalidOid != agg_oid);
1913 1914

	// get agg name
1915
	CHAR *name = gpdb::GetFuncName(agg_oid);
1916

1917
	if (NULL == name)
1918 1919
	{

1920
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
1921 1922
	}

1923 1924
	CWStringDynamic *agg_name_str = CDXLUtils::CreateDynamicStringFromCharArray(mp, name);
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, agg_name_str);
1925 1926

	// CMDName ctor created a copy of the string
1927
	GPOS_DELETE(agg_name_str);
1928 1929

	// get result type
1930
	OID result_oid = gpdb::GetFuncRetType(agg_oid);
1931

1932
	GPOS_ASSERT(InvalidOid != result_oid);
1933

1934 1935
	CMDIdGPDB *result_type_mdid = GPOS_NEW(mp) CMDIdGPDB(result_oid);
	IMDId *intermediate_result_type_mdid = RetrieveAggIntermediateResultType(mp, mdid);
1936

1937
	mdid->AddRef();
1938
	
1939
	BOOL is_ordered = gpdb::IsOrderedAgg(agg_oid);
1940 1941 1942
	
	// GPDB does not support splitting of ordered aggs and aggs without a
	// preliminary function
1943
	BOOL is_splittable = !is_ordered && gpdb::AggHasPrelimFunc(agg_oid);
1944 1945 1946
	
	// cannot use hash agg for ordered aggs or aggs without a prelim func
	// due to the fact that hashAgg may spill
1947
	BOOL is_hash_agg_capable = !is_ordered && gpdb::AggHasPrelimFunc(agg_oid);
1948

1949
	CMDAggregateGPDB *pmdagg = GPOS_NEW(mp) CMDAggregateGPDB
1950
											(
1951 1952 1953 1954 1955 1956 1957 1958
											mp,
											mdid,
											mdname,
											result_type_mdid,
											intermediate_result_type_mdid,
											is_ordered,
											is_splittable,
											is_hash_agg_capable
1959 1960 1961 1962 1963 1964
											);
	return pmdagg;
}

//---------------------------------------------------------------------------
//	@function:
1965
//		CTranslatorRelcacheToDXL::RetrieveTrigger
1966 1967 1968 1969 1970 1971
//
//	@doc:
//		Retrieve a trigger from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
CMDTriggerGPDB *
1972
CTranslatorRelcacheToDXL::RetrieveTrigger
1973
	(
1974 1975
	IMemoryPool *mp,
	IMDId *mdid
1976 1977
	)
{
1978
	OID trigger_oid = CMDIdGPDB::CastMdid(mdid)->Oid();
1979

1980
	GPOS_ASSERT(InvalidOid != trigger_oid);
1981 1982

	// get trigger name
1983
	CHAR *name = gpdb::GetTriggerName(trigger_oid);
1984

1985
	if (NULL == name)
1986
	{
1987
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
1988 1989
	}

1990 1991 1992
	CWStringDynamic *trigger_name_str = CDXLUtils::CreateDynamicStringFromCharArray(mp, name);
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, trigger_name_str);
	GPOS_DELETE(trigger_name_str);
1993 1994

	// get relation oid
1995 1996 1997
	OID rel_oid = gpdb::GetTriggerRelid(trigger_oid);
	GPOS_ASSERT(InvalidOid != rel_oid);
	CMDIdGPDB *mdid_rel = GPOS_NEW(mp) CMDIdGPDB(rel_oid);
1998 1999

	// get function oid
2000 2001 2002
	OID func_oid = gpdb::GetTriggerFuncid(trigger_oid);
	GPOS_ASSERT(InvalidOid != func_oid);
	CMDIdGPDB *mdid_func = GPOS_NEW(mp) CMDIdGPDB(func_oid);
2003 2004

	// get type
2005
	INT trigger_type = gpdb::GetTriggerType(trigger_oid);
2006 2007

	// is trigger enabled
2008
	BOOL is_enabled = gpdb::IsTriggerEnabled(trigger_oid);
2009

2010 2011
	mdid->AddRef();
	CMDTriggerGPDB *pmdtrigger = GPOS_NEW(mp) CMDTriggerGPDB
2012
											(
2013 2014 2015 2016 2017 2018 2019
											mp,
											mdid,
											mdname,
											mdid_rel,
											mdid_func,
											trigger_type,
											is_enabled
2020 2021 2022 2023 2024 2025
											);
	return pmdtrigger;
}

//---------------------------------------------------------------------------
//	@function:
2026
//		CTranslatorRelcacheToDXL::RetrieveCheckConstraints
2027 2028 2029 2030 2031 2032
//
//	@doc:
//		Retrieve a check constraint from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
CMDCheckConstraintGPDB *
2033
CTranslatorRelcacheToDXL::RetrieveCheckConstraints
2034
	(
2035 2036 2037
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	IMDId *mdid
2038 2039
	)
{
2040 2041
	OID check_constraint_oid = CMDIdGPDB::CastMdid(mdid)->Oid();
	GPOS_ASSERT(InvalidOid != check_constraint_oid);
2042 2043

	// get name of the check constraint
2044 2045
	CHAR *name = gpdb::GetCheckConstraintName(check_constraint_oid);
	if (NULL == name)
2046
	{
2047
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
2048
	}
2049 2050 2051
	CWStringDynamic *check_constr_name = CDXLUtils::CreateDynamicStringFromCharArray(mp, name);
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, check_constr_name);
	GPOS_DELETE(check_constr_name);
2052 2053

	// get relation oid associated with the check constraint
2054 2055 2056
	OID rel_oid = gpdb::GetCheckConstraintRelid(check_constraint_oid);
	GPOS_ASSERT(InvalidOid != rel_oid);
	CMDIdGPDB *mdid_rel = GPOS_NEW(mp) CMDIdGPDB(rel_oid);
2057 2058

	// translate the check constraint expression
2059 2060
	Node *node = gpdb::PnodeCheckConstraint(check_constraint_oid);
	GPOS_ASSERT(NULL != node);
2061

2062
	CTranslatorScalarToDXL scalar_translator
2063
							(
2064 2065
							mp,
							md_accessor,
2066 2067
							NULL, /* pulidgtorCol */
							NULL, /* pulidgtorCTE */
2068
							0, /* query_level */
2069
							true, /* m_fQuery */
2070 2071
							NULL, /* query_level_to_cte_map */
							NULL /* cte_dxlnode_array */
2072 2073 2074
							);

	// generate a mock mapping between var to column information
2075 2076 2077 2078 2079
	CMappingVarColId *var_colid_mapping = GPOS_NEW(mp) CMappingVarColId(mp);
	CDXLColDescrArray *dxl_col_descr_array = GPOS_NEW(mp) CDXLColDescrArray(mp);
	const IMDRelation *md_rel = md_accessor->RetrieveRel(mdid_rel);
	const ULONG length = md_rel->ColumnCount();
	for (ULONG ul = 0; ul < length; ul++)
2080
	{
2081 2082 2083 2084
		const IMDColumn *md_col = md_rel->GetMdCol(ul);
		CMDName *md_colname = GPOS_NEW(mp) CMDName(mp, md_col->Mdname().GetMDName());
		CMDIdGPDB *mdid_col_type = CMDIdGPDB::CastMdid(md_col->MdidType());
		mdid_col_type->AddRef();
2085 2086

		// create a column descriptor for the column
2087
		CDXLColDescr *dxl_col_descr = GPOS_NEW(mp) CDXLColDescr
2088
										(
2089 2090 2091 2092 2093 2094
										mp,
										md_colname,
										ul + 1 /*colid*/,
										md_col->AttrNum(),
										mdid_col_type,
										md_col->TypeModifier(),
2095 2096
										false /* fColDropped */
										);
2097
		dxl_col_descr_array->Append(dxl_col_descr);
2098
	}
2099
	var_colid_mapping->LoadColumns(0 /*query_level */, 1 /* rteIndex */, dxl_col_descr_array);
2100 2101

	// translate the check constraint expression
2102
	CDXLNode *scalar_dxlnode = scalar_translator.TranslateScalarToDXL((Expr *) node, var_colid_mapping);
2103 2104

	// cleanup
2105 2106
	dxl_col_descr_array->Release();
	GPOS_DELETE(var_colid_mapping);
2107

2108
	mdid->AddRef();
2109

2110
	return GPOS_NEW(mp) CMDCheckConstraintGPDB
2111
						(
2112 2113 2114 2115 2116
						mp,
						mdid,
						mdname,
						mdid_rel,
						scalar_dxlnode
2117 2118 2119 2120 2121
						);
}

//---------------------------------------------------------------------------
//	@function:
2122
//		CTranslatorRelcacheToDXL::GetTypeName
2123 2124 2125 2126 2127 2128
//
//	@doc:
//		Retrieve a type's name from the relcache given its metadata id.
//
//---------------------------------------------------------------------------
CMDName *
2129
CTranslatorRelcacheToDXL::GetTypeName
2130
	(
2131 2132
	IMemoryPool *mp,
	IMDId *mdid
2133 2134
	)
{
2135
	OID oid_type = CMDIdGPDB::CastMdid(mdid)->Oid();
2136

2137
	GPOS_ASSERT(InvalidOid != oid_type);
2138

2139 2140
	CHAR *typename_str = gpdb::GetTypeName(oid_type);
	GPOS_ASSERT(NULL != typename_str);
2141

2142 2143
	CWStringDynamic *str_name = CDXLUtils::CreateDynamicStringFromCharArray(mp, typename_str);
	CMDName *mdname = GPOS_NEW(mp) CMDName(mp, str_name);
2144 2145

	// cleanup
2146 2147
	GPOS_DELETE(str_name);
	return mdname;
2148 2149 2150 2151
}

//---------------------------------------------------------------------------
//	@function:
2152
//		CTranslatorRelcacheToDXL::GetFuncStability
2153 2154 2155 2156 2157 2158
//
//	@doc:
//		Get function stability property from the GPDB character representation
//
//---------------------------------------------------------------------------
CMDFunctionGPDB::EFuncStbl
2159
CTranslatorRelcacheToDXL::GetFuncStability
2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185
	(
	CHAR c
	)
{
	CMDFunctionGPDB::EFuncStbl efuncstbl = CMDFunctionGPDB::EfsSentinel;

	switch (c)
	{
		case 's':
			efuncstbl = CMDFunctionGPDB::EfsStable;
			break;
		case 'i':
			efuncstbl = CMDFunctionGPDB::EfsImmutable;
			break;
		case 'v':
			efuncstbl = CMDFunctionGPDB::EfsVolatile;
			break;
		default:
			GPOS_ASSERT(!"Invalid stability property");
	}

	return efuncstbl;
}

//---------------------------------------------------------------------------
//	@function:
2186
//		CTranslatorRelcacheToDXL::GetEFuncDataAccess
2187 2188 2189 2190 2191 2192
//
//	@doc:
//		Get function data access property from the GPDB character representation
//
//---------------------------------------------------------------------------
CMDFunctionGPDB::EFuncDataAcc
2193
CTranslatorRelcacheToDXL::GetEFuncDataAccess
2194 2195 2196 2197
	(
	CHAR c
	)
{
2198
	CMDFunctionGPDB::EFuncDataAcc access = CMDFunctionGPDB::EfdaSentinel;
2199 2200 2201 2202

	switch (c)
	{
		case 'n':
2203
			access = CMDFunctionGPDB::EfdaNoSQL;
2204 2205
			break;
		case 'c':
2206
			access = CMDFunctionGPDB::EfdaContainsSQL;
2207 2208
			break;
		case 'r':
2209
			access = CMDFunctionGPDB::EfdaReadsSQLData;
2210 2211
			break;
		case 'm':
2212
			access = CMDFunctionGPDB::EfdaModifiesSQLData;
2213 2214 2215 2216 2217 2218 2219
			break;
		case 's':
			GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("unknown data access"));
		default:
			GPOS_ASSERT(!"Invalid data access property");
	}

2220
	return access;
2221 2222 2223 2224
}

//---------------------------------------------------------------------------
//	@function:
2225
//		CTranslatorRelcacheToDXL::RetrieveAggIntermediateResultType
2226 2227 2228 2229 2230 2231
//
//	@doc:
//		Retrieve the type id of an aggregate's intermediate results
//
//---------------------------------------------------------------------------
IMDId *
2232
CTranslatorRelcacheToDXL::RetrieveAggIntermediateResultType
2233
	(
2234 2235
	IMemoryPool *mp,
	IMDId *mdid
2236 2237
	)
{
2238
	OID agg_oid = CMDIdGPDB::CastMdid(mdid)->Oid();
2239

2240 2241
	GPOS_ASSERT(InvalidOid != agg_oid);
	return GPOS_NEW(mp) CMDIdGPDB(gpdb::GetAggIntermediateResultType(agg_oid));
2242 2243 2244 2245
}

//---------------------------------------------------------------------------
//	@function:
2246
//		CTranslatorRelcacheToDXL::RetrieveRelStats
2247 2248 2249 2250 2251 2252
//
//	@doc:
//		Retrieve relation statistics from relcache
//
//---------------------------------------------------------------------------
IMDCacheObject *
2253
CTranslatorRelcacheToDXL::RetrieveRelStats
2254
	(
2255 2256
	IMemoryPool *mp,
	IMDId *mdid
2257 2258
	)
{
2259 2260 2261
	CMDIdRelStats *m_rel_stats_mdid = CMDIdRelStats::CastMdid(mdid);
	IMDId *mdid_rel = m_rel_stats_mdid->GetRelMdId();
	OID rel_oid = CMDIdGPDB::CastMdid(mdid_rel)->Oid();
2262

2263
	Relation rel = gpdb::GetRelation(rel_oid);
2264 2265
	if (NULL == rel)
	{
2266
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
2267 2268
	}

2269 2270
	double num_rows = 0.0;
	CMDName *mdname = NULL;
2271 2272 2273 2274

	GPOS_TRY
	{
		// get rel name
2275 2276 2277
		CHAR *relname = NameStr(rel->rd_rel->relname);
		CWStringDynamic *relname_str = CDXLUtils::CreateDynamicStringFromCharArray(mp, relname);
		mdname = GPOS_NEW(mp) CMDName(mp, relname_str);
2278
		// CMDName ctor created a copy of the string
2279
		GPOS_DELETE(relname_str);
2280 2281

		BlockNumber pages = 0;
2282 2283
		GpPolicy *gp_policy = gpdb::GetDistributionPolicy(rel);
		if (!gp_policy ||gp_policy->ptype != POLICYTYPE_PARTITIONED)
2284
		{
2285
			gpdb::EstimateRelationSize(rel, NULL, &pages, &num_rows);
2286 2287 2288
		}
		else
		{
2289
			num_rows = rel->rd_rel->reltuples;
2290

2291
			if (num_rows == 0 && gp_enable_relsize_collection)
2292 2293
			{
				RelOptInfo *relOptInfo = makeNode(RelOptInfo);
2294
				relOptInfo->cdbpolicy = gpdb::GetDistributionPolicy(rel);
2295
				bool default_stats_used = false;
2296
				gpdb::CdbEstimateRelationSize(relOptInfo, rel, NULL, &pages, &num_rows, &default_stats_used);
2297 2298
				pfree(relOptInfo);
			}
2299 2300
		}

2301
		m_rel_stats_mdid->AddRef();
2302 2303 2304 2305 2306 2307 2308 2309 2310
		gpdb::CloseRelation(rel);
	}
	GPOS_CATCH_EX(ex)
	{
		gpdb::CloseRelation(rel);
		GPOS_RETHROW(ex);
	}
	GPOS_CATCH_END;
	
2311 2312
	BOOL stats_empty = false;
	if (num_rows == 0.0)
2313
	{
2314
		stats_empty = true;
2315 2316
	}
		
2317
	CDXLRelStats *dxl_rel_stats = GPOS_NEW(mp) CDXLRelStats
2318
												(
2319 2320 2321 2322 2323
												mp,
												m_rel_stats_mdid,
												mdname,
												CDouble(num_rows),
												stats_empty
2324 2325 2326
												);


2327
	return dxl_rel_stats;
2328 2329
}

O
Omer Arap 已提交
2330 2331 2332 2333 2334
// Retrieve column statistics from relcache
// If all statistics are missing, create dummy statistics
// Also, if the statistics are broken, create dummy statistics
// However, if any statistics are present and not broken,
// create column statistics using these statistics
2335
IMDCacheObject *
2336
CTranslatorRelcacheToDXL::RetrieveColStats
2337
	(
2338 2339 2340
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	IMDId *mdid
2341 2342
	)
{
2343 2344 2345 2346
	CMDIdColStats *mdid_col_stats = CMDIdColStats::CastMdid(mdid);
	IMDId *mdid_rel = mdid_col_stats->GetRelMdId();
	ULONG pos = mdid_col_stats->Position();
	OID rel_oid = CMDIdGPDB::CastMdid(mdid_rel)->Oid();
2347

2348
	Relation rel = gpdb::GetRelation(rel_oid);
2349 2350
	if (NULL == rel)
	{
2351
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
2352 2353
	}

2354 2355 2356
	const IMDRelation *md_rel = md_accessor->RetrieveRel(mdid_rel);
	const IMDColumn *md_col = md_rel->GetMdCol(pos);
	AttrNumber attno = (AttrNumber) md_col->AttrNum();
2357 2358

	// number of rows from pg_class
2359
	CDouble num_rows(rel->rd_rel->reltuples);
2360 2361

	// extract column name and type
2362 2363
	CMDName *md_colname = GPOS_NEW(mp) CMDName(mp, md_col->Mdname().GetMDName());
	OID att_type = CMDIdGPDB::CastMdid(md_col->MdidType())->Oid();
2364 2365
	gpdb::CloseRelation(rel);

2366
	CDXLBucketArray *dxl_stats_bucket_array = GPOS_NEW(mp) CDXLBucketArray(mp);
2367

2368
	if (0 > attno)
2369
	{
2370 2371
		mdid_col_stats->AddRef();
		return GenerateStatsForSystemCols
2372
				(
2373 2374 2375 2376 2377 2378 2379 2380
				mp,
				rel_oid,
				mdid_col_stats,
				md_colname,
				att_type,
				attno,
				dxl_stats_bucket_array,
				num_rows
2381 2382 2383 2384
				);
	}

	// extract out histogram and mcv information from pg_statistic
2385
	HeapTuple stats_tup = gpdb::GetAttStats(rel_oid, attno);
2386 2387

	// if there is no colstats
2388
	if (!HeapTupleIsValid(stats_tup))
2389
	{
2390 2391
		dxl_stats_bucket_array->Release();
		mdid_col_stats->AddRef();
2392

2393
		CDouble width = CStatistics::DefaultColumnWidth;
2394

2395
		if (!md_col->IsDropped())
2396
		{
2397 2398 2399 2400 2401
			CMDIdGPDB *mdid_atttype = GPOS_NEW(mp) CMDIdGPDB(att_type);
			IMDType *md_type = RetrieveType(mp, mdid_atttype);
			width = CStatisticsUtils::DefaultColumnWidth(md_type);
			md_type->Release();
			mdid_atttype->Release();
2402 2403
		}

2404
		return CDXLColStats::CreateDXLDummyColStats(mp, mdid_col_stats, md_colname, width);
2405 2406
	}

2407
	Form_pg_statistic form_pg_stats = (Form_pg_statistic) GETSTRUCT(stats_tup);
2408 2409

	// null frequency and NDV
2410 2411 2412
	CDouble null_freq(0.0);
	int null_ndv = 0;
	if (CStatistics::Epsilon < form_pg_stats->stanullfrac)
2413
	{
2414 2415
		null_freq = form_pg_stats->stanullfrac;
		null_ndv = 1;
2416 2417 2418
	}

	// column width
2419
	CDouble width = CDouble(form_pg_stats->stawidth);
2420 2421

	// calculate total number of distinct values
2422 2423
	CDouble num_distinct(1.0);
	if (form_pg_stats->stadistinct < 0)
2424
	{
2425 2426
		GPOS_ASSERT(form_pg_stats->stadistinct > -1.01);
		num_distinct = num_rows * CDouble(-form_pg_stats->stadistinct);
2427 2428 2429
	}
	else
	{
2430
		num_distinct = CDouble(form_pg_stats->stadistinct);
2431
	}
2432
	num_distinct = num_distinct.Ceil();
2433

2434
	BOOL is_dummy_stats = false;
O
Omer Arap 已提交
2435 2436
	// most common values and their frequencies extracted from the pg_statistic
	// tuple for a given column
2437
	AttStatsSlot mcv_slot;
O
Omer Arap 已提交
2438

2439
	(void)	gpdb::GetAttrStatsSlot
O
Omer Arap 已提交
2440
			(
2441 2442
					&mcv_slot,
					stats_tup,
O
Omer Arap 已提交
2443 2444 2445 2446
					STATISTIC_KIND_MCV,
					InvalidOid,
					ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS
			);
2447
	if (InvalidOid != mcv_slot.valuetype && mcv_slot.valuetype != att_type)
O
Omer Arap 已提交
2448 2449 2450
	{
		char msgbuf[NAMEDATALEN * 2 + 100];
		snprintf(msgbuf, sizeof(msgbuf), "Type mismatch between attribute %ls of table %ls having type %d and statistic having type %d, please ANALYZE the table again",
2451
				 md_col->Mdname().GetMDName()->GetBuffer(), md_rel->Mdname().GetMDName()->GetBuffer(), att_type, mcv_slot.valuetype);
O
Omer Arap 已提交
2452 2453 2454 2455 2456
		GpdbEreport(ERRCODE_SUCCESSFUL_COMPLETION,
					NOTICE,
					msgbuf,
					NULL);

2457 2458
		gpdb::FreeAttrStatsSlot(&mcv_slot);
		is_dummy_stats = true;
O
Omer Arap 已提交
2459 2460
	}

2461
	else if (mcv_slot.nvalues != mcv_slot.nnumbers)
O
Omer Arap 已提交
2462 2463 2464
	{
		char msgbuf[NAMEDATALEN * 2 + 100];
		snprintf(msgbuf, sizeof(msgbuf), "The number of most common values and frequencies do not match on column %ls of table %ls.",
2465
				 md_col->Mdname().GetMDName()->GetBuffer(), md_rel->Mdname().GetMDName()->GetBuffer());
O
Omer Arap 已提交
2466 2467 2468 2469 2470 2471
		GpdbEreport(ERRCODE_SUCCESSFUL_COMPLETION,
					NOTICE,
					msgbuf,
					NULL);

		// if the number of MCVs(nvalues) and number of MCFs(nnumbers) do not match, we discard the MCVs and MCFs
2472 2473
		gpdb::FreeAttrStatsSlot(&mcv_slot);
		is_dummy_stats = true;
O
Omer Arap 已提交
2474 2475
	}
	else
2476
	{
O
Omer Arap 已提交
2477
		// fix mcv and null frequencies (sometimes they can add up to more than 1.0)
2478
		NormalizeFrequencies(mcv_slot.numbers, (ULONG) mcv_slot.nvalues, &null_freq);
O
Omer Arap 已提交
2479 2480

		// total MCV frequency
2481 2482
		CDouble sum_mcv_freq = 0.0;
		for (int i = 0; i < mcv_slot.nvalues; i++)
O
Omer Arap 已提交
2483
		{
2484
			sum_mcv_freq = sum_mcv_freq + CDouble(mcv_slot.numbers[i]);
O
Omer Arap 已提交
2485
		}
2486 2487
	}

O
Omer Arap 已提交
2488
	// histogram values extracted from the pg_statistic tuple for a given column
2489
	AttStatsSlot hist_slot;
O
Omer Arap 已提交
2490

2491
	// get histogram datums from pg_statistic entry
2492
	(void) gpdb::GetAttrStatsSlot
2493
			(
2494 2495
					&hist_slot,
					stats_tup,
2496 2497
					STATISTIC_KIND_HISTOGRAM,
					InvalidOid,
2498 2499
					ATTSTATSSLOT_VALUES
			);
2500

2501
	if (InvalidOid != hist_slot.valuetype && hist_slot.valuetype != att_type)
O
Omer Arap 已提交
2502 2503 2504
	{
		char msgbuf[NAMEDATALEN * 2 + 100];
		snprintf(msgbuf, sizeof(msgbuf), "Type mismatch between attribute %ls of table %ls having type %d and statistic having type %d, please ANALYZE the table again",
2505
				 md_col->Mdname().GetMDName()->GetBuffer(), md_rel->Mdname().GetMDName()->GetBuffer(), att_type, hist_slot.valuetype);
O
Omer Arap 已提交
2506 2507 2508 2509 2510
		GpdbEreport(ERRCODE_SUCCESSFUL_COMPLETION,
					NOTICE,
					msgbuf,
					NULL);

2511 2512
		gpdb::FreeAttrStatsSlot(&hist_slot);
		is_dummy_stats = true;
O
Omer Arap 已提交
2513 2514
	}

2515
	if (is_dummy_stats)
O
Omer Arap 已提交
2516
	{
2517 2518
		dxl_stats_bucket_array->Release();
		mdid_col_stats->AddRef();
O
Omer Arap 已提交
2519

2520 2521 2522
		CDouble col_width = CStatistics::DefaultColumnWidth;
		gpdb::FreeHeapTuple(stats_tup);
		return CDXLColStats::CreateDXLDummyColStats(mp, mdid_col_stats, md_colname, col_width);
O
Omer Arap 已提交
2523 2524
	}

2525 2526 2527 2528
	CDouble num_ndv_buckets(0.0);
	CDouble num_freq_buckets(0.0);
	CDouble distinct_remaining(0.0);
	CDouble freq_remaining(0.0);
2529 2530 2531

	// We only want to create statistics buckets if the column is NOT a text, varchar, char or bpchar type
	// For the above column types we will use NDVRemain and NullFreq to do cardinality estimation.
2532
	if (CTranslatorUtils::ShouldCreateStatsBucket(att_type))
2533 2534 2535
	{
		// transform all the bits and pieces from pg_statistic
		// to a single bucket structure
2536 2537
		CDXLBucketArray *dxl_stats_bucket_array_transformed =
		TransformStatsToDXLBucketArray
2538
		(
2539 2540 2541 2542 2543 2544 2545 2546 2547
		 mp,
		 att_type,
		 num_distinct,
		 null_freq,
		 mcv_slot.values,
		 mcv_slot.numbers,
		 ULONG(mcv_slot.nvalues),
		 hist_slot.values,
		 ULONG(hist_slot.nvalues)
2548 2549
		 );

2550
		GPOS_ASSERT(NULL != dxl_stats_bucket_array_transformed);
2551

2552 2553
		const ULONG num_buckets = dxl_stats_bucket_array_transformed->Size();
		for (ULONG ul = 0; ul < num_buckets; ul++)
2554
		{
2555 2556 2557
			CDXLBucket *dxl_bucket = (*dxl_stats_bucket_array_transformed)[ul];
			num_ndv_buckets = num_ndv_buckets + dxl_bucket->GetNumDistinct();
			num_freq_buckets = num_freq_buckets + dxl_bucket->GetFrequency();
2558 2559
		}

2560 2561
		CUtils::AddRefAppend(dxl_stats_bucket_array, dxl_stats_bucket_array_transformed);
		dxl_stats_bucket_array_transformed->Release();
2562

2563 2564
		// there will be remaining tuples if the merged histogram and the NULLS do not cover
		// the total number of distinct values
2565 2566
		if ((1 - CStatistics::Epsilon > num_freq_buckets + null_freq) &&
			(0 < num_distinct - num_ndv_buckets - null_ndv))
2567
		{
2568 2569
			distinct_remaining = std::max(CDouble(0.0), (num_distinct - num_ndv_buckets - null_ndv));
			freq_remaining = std::max(CDouble(0.0), (1 - num_freq_buckets - null_freq));
2570 2571 2572
		}
	}
	else
2573
	{
2574 2575 2576
		// in case of text, varchar, char or bpchar, there are no stats buckets, so the
		// remaining frequency is everything excluding NULLs, and distinct remaining is the
		// stadistinct as available in pg_statistic
2577 2578
		distinct_remaining = num_distinct;
 		freq_remaining = 1 - null_freq;
2579 2580 2581
	}

	// free up allocated datum and float4 arrays
2582 2583
	gpdb::FreeAttrStatsSlot(&mcv_slot);
	gpdb::FreeAttrStatsSlot(&hist_slot);
2584

2585
	gpdb::FreeHeapTuple(stats_tup);
2586 2587

	// create col stats object
2588 2589
	mdid_col_stats->AddRef();
	CDXLColStats *dxl_col_stats = GPOS_NEW(mp) CDXLColStats
2590
											(
2591 2592 2593 2594 2595 2596 2597 2598 2599
											mp,
											mdid_col_stats,
											md_colname,
											width,
											null_freq,
											distinct_remaining,
											freq_remaining,
											dxl_stats_bucket_array,
											false /* is_col_stats_missing */
2600 2601
											);

2602
	return dxl_col_stats;
2603 2604 2605 2606 2607
}


//---------------------------------------------------------------------------
//      @function:
2608
//              CTranslatorRelcacheToDXL::GenerateStatsForSystemCols
2609 2610 2611 2612 2613 2614
//
//      @doc:
//              Generate statistics for the system level columns
//
//---------------------------------------------------------------------------
CDXLColStats *
2615
CTranslatorRelcacheToDXL::GenerateStatsForSystemCols
2616
       (
2617 2618 2619 2620 2621 2622 2623 2624
       IMemoryPool *mp,
       OID rel_oid,
       CMDIdColStats *mdid_col_stats,
       CMDName *md_colname,
       OID att_type,
       AttrNumber attno,
       CDXLBucketArray *dxl_stats_bucket_array,
       CDouble num_rows
2625 2626
       )
{
2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643
       GPOS_ASSERT(NULL != mdid_col_stats);
       GPOS_ASSERT(NULL != md_colname);
       GPOS_ASSERT(InvalidOid != att_type);
       GPOS_ASSERT(0 > attno);
       GPOS_ASSERT(NULL != dxl_stats_bucket_array);

       CMDIdGPDB *mdid_atttype = GPOS_NEW(mp) CMDIdGPDB(att_type);
       IMDType *md_type = RetrieveType(mp, mdid_atttype);
       GPOS_ASSERT(md_type->IsFixedLength());

       BOOL is_col_stats_missing = true;
       CDouble null_freq(0.0);
       CDouble width(md_type->Length());
       CDouble distinct_remaining(0.0);
       CDouble freq_remaining(0.0);

       if (CStatistics::MinRows <= num_rows)
2644
	   {
2645
		   switch(attno)
2646 2647 2648
			{
				case GpSegmentIdAttributeNumber: // gp_segment_id
					{
2649 2650 2651
						is_col_stats_missing = false;
						freq_remaining = CDouble(1.0);
						distinct_remaining = CDouble(gpdb::GetGPSegmentCount());
2652 2653 2654 2655
						break;
					}
				case TableOidAttributeNumber: // tableoid
					{
2656 2657 2658
						is_col_stats_missing = false;
						freq_remaining = CDouble(1.0);
						distinct_remaining = CDouble(RetrieveNumChildPartitions(rel_oid));
2659 2660 2661 2662
						break;
					}
				case SelfItemPointerAttributeNumber: // ctid
					{
2663 2664 2665
						is_col_stats_missing = false;
						freq_remaining = CDouble(1.0);
						distinct_remaining = num_rows;
2666 2667 2668 2669 2670 2671 2672 2673
						break;
					}
				default:
					break;
			}
        }

       // cleanup
2674 2675
       mdid_atttype->Release();
       md_type->Release();
2676

2677
       return GPOS_NEW(mp) CDXLColStats
2678
                       (
2679 2680 2681 2682 2683 2684 2685 2686 2687
                       mp,
                       mdid_col_stats,
                       md_colname,
                       width,
                       null_freq,
                       distinct_remaining,
                       freq_remaining,
                       dxl_stats_bucket_array,
                       is_col_stats_missing
2688 2689 2690 2691 2692 2693
                       );
}


//---------------------------------------------------------------------------
//     @function:
2694
//     CTranslatorRelcacheToDXL::RetrieveNumChildPartitions
2695 2696 2697 2698 2699 2700 2701
//
//  @doc:
//      For non-leaf partition tables return the number of child partitions
//      else return 1
//
//---------------------------------------------------------------------------
ULONG
2702
CTranslatorRelcacheToDXL::RetrieveNumChildPartitions
2703
       (
2704
       OID rel_oid
2705 2706
       )
{
2707
       GPOS_ASSERT(InvalidOid != rel_oid);
2708

2709 2710
       ULONG num_part_tables = gpos::ulong_max;
       if (gpdb::RelPartIsNone(rel_oid))
2711 2712
       {
    	   // not a partitioned table
2713
            num_part_tables = 1;
2714
       }
2715
       else if (gpdb::IsLeafPartition(rel_oid))
2716 2717
       {
           // leaf partition
2718
           num_part_tables = 1;
2719 2720 2721
       }
       else
       {
2722
           num_part_tables = gpdb::CountLeafPartTables(rel_oid);
2723
       }
2724
       GPOS_ASSERT(gpos::ulong_max != num_part_tables);
2725

2726
       return num_part_tables;
2727 2728 2729 2730 2731
}


//---------------------------------------------------------------------------
//	@function:
2732
//		CTranslatorRelcacheToDXL::RetrieveCast
2733 2734 2735 2736 2737 2738
//
//	@doc:
//		Retrieve a cast function from relcache
//
//---------------------------------------------------------------------------
IMDCacheObject *
2739
CTranslatorRelcacheToDXL::RetrieveCast
2740
	(
2741 2742
	IMemoryPool *mp,
	IMDId *mdid
2743 2744
	)
{
2745 2746 2747
	CMDIdCast *mdid_cast = CMDIdCast::CastMdid(mdid);
	IMDId *mdid_src = mdid_cast->MdidSrc();
	IMDId *mdid_dest = mdid_cast->MdidDest();
2748
	IMDCast::EmdCoercepathType coercePathType;
2749

2750 2751
	OID src_oid = CMDIdGPDB::CastMdid(mdid_src)->Oid();
	OID dest_oid = CMDIdGPDB::CastMdid(mdid_dest)->Oid();
2752
	CoercionPathType	pathtype;
2753

2754 2755
	OID cast_fn_oid = 0;
	BOOL is_binary_coercible = false;
2756
	
2757
	BOOL cast_exists = gpdb::GetCastFunc(src_oid, dest_oid, &is_binary_coercible, &cast_fn_oid, &pathtype);
2758
	
2759
	if (!cast_exists)
2760
	{
2761
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
2762 2763
	} 
	
2764 2765
	CHAR *func_name = NULL;
	if (InvalidOid != cast_fn_oid)
2766
	{
2767
		func_name = gpdb::GetFuncName(cast_fn_oid);
2768 2769 2770 2771
	}
	else
	{
		// no explicit cast function: use the destination type name as the cast name
2772
		func_name = gpdb::GetTypeName(dest_oid);
2773 2774
	}
	
2775
	if (NULL == func_name)
2776
	{
2777
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
2778 2779
	}

2780 2781 2782
	mdid->AddRef();
	mdid_src->AddRef();
	mdid_dest->AddRef();
2783

2784
	CMDName *mdname = CDXLUtils::CreateMDNameFromCharArray(mp, func_name);
2785
	
2786 2787 2788 2789
	switch (pathtype) {
		case COERCION_PATH_ARRAYCOERCE:
		{
			coercePathType = IMDCast::EmdtArrayCoerce;
2790
			return GPOS_NEW(mp) CMDArrayCoerceCastGPDB(mp, mdid, mdname, mdid_src, mdid_dest, is_binary_coercible, GPOS_NEW(mp) CMDIdGPDB(cast_fn_oid), IMDCast::EmdtArrayCoerce, default_type_modifier, false, EdxlcfImplicitCast, -1);
2791 2792 2793
		}
			break;
		case COERCION_PATH_FUNC:
2794
			return GPOS_NEW(mp) CMDCastGPDB(mp, mdid, mdname, mdid_src, mdid_dest, is_binary_coercible, GPOS_NEW(mp) CMDIdGPDB(cast_fn_oid), IMDCast::EmdtFunc);
2795 2796 2797 2798 2799 2800
			break;
		default:
			break;
	}

	// fall back for none path types
2801
	return GPOS_NEW(mp) CMDCastGPDB(mp, mdid, mdname, mdid_src, mdid_dest, is_binary_coercible, GPOS_NEW(mp) CMDIdGPDB(cast_fn_oid));
2802 2803 2804 2805
}

//---------------------------------------------------------------------------
//	@function:
2806
//		CTranslatorRelcacheToDXL::RetrieveScCmp
2807 2808 2809 2810 2811 2812
//
//	@doc:
//		Retrieve a scalar comparison from relcache
//
//---------------------------------------------------------------------------
IMDCacheObject *
2813
CTranslatorRelcacheToDXL::RetrieveScCmp
2814
	(
2815 2816
	IMemoryPool *mp,
	IMDId *mdid
2817 2818
	)
{
2819 2820 2821
	CMDIdScCmp *mdid_scalar_cmp = CMDIdScCmp::CastMdid(mdid);
	IMDId *mdid_left = mdid_scalar_cmp->GetLeftMdid();
	IMDId *mdid_right = mdid_scalar_cmp->GetRightMdid();
2822
	
2823
	IMDType::ECmpType cmp_type = mdid_scalar_cmp->ParseCmpType();
2824

2825 2826 2827
	OID left_oid = CMDIdGPDB::CastMdid(mdid_left)->Oid();
	OID right_oid = CMDIdGPDB::CastMdid(mdid_right)->Oid();
	CmpType cmpt = (CmpType) GetComparisonType(cmp_type);
2828
	
2829
	OID scalar_cmp_oid = gpdb::GetComparisonOperator(left_oid, right_oid, cmpt);
2830
	
2831
	if (InvalidOid == scalar_cmp_oid)
2832
	{
2833
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
2834 2835
	} 

2836
	CHAR *name = gpdb::GetOpName(scalar_cmp_oid);
2837

2838
	if (NULL == name)
2839
	{
2840
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, mdid->GetBuffer());
2841 2842
	}

2843 2844 2845
	mdid->AddRef();
	mdid_left->AddRef();
	mdid_right->AddRef();
2846

2847
	CMDName *mdname = CDXLUtils::CreateMDNameFromCharArray(mp, name);
2848

2849
	return GPOS_NEW(mp) CMDScCmpGPDB(mp, mdid, mdname, mdid_left, mdid_right, cmp_type, GPOS_NEW(mp) CMDIdGPDB(scalar_cmp_oid));
2850 2851 2852 2853
}

//---------------------------------------------------------------------------
//	@function:
2854
//		CTranslatorRelcacheToDXL::TransformStatsToDXLBucketArray
2855 2856 2857 2858 2859
//
//	@doc:
//		transform stats from pg_stats form to optimizer's preferred form
//
//---------------------------------------------------------------------------
2860 2861
CDXLBucketArray *
CTranslatorRelcacheToDXL::TransformStatsToDXLBucketArray
2862
	(
2863 2864 2865 2866 2867 2868 2869 2870 2871
	IMemoryPool *mp,
	OID att_type,
	CDouble num_distinct,
	CDouble null_freq,
	const Datum *mcv_values,
	const float4 *mcv_frequencies,
	ULONG num_mcv_values,
	const Datum *hist_values,
	ULONG num_hist_values
2872 2873
	)
{
2874 2875
	CMDIdGPDB *mdid_atttype = GPOS_NEW(mp) CMDIdGPDB(att_type);
	IMDType *md_type = RetrieveType(mp, mdid_atttype);
2876 2877

	// translate MCVs to Orca histogram. Create an empty histogram if there are no MCVs.
2878
	CHistogram *gpdb_mcv_hist = TransformMcvToOrcaHistogram
2879
							(
2880 2881 2882 2883 2884
							mp,
							md_type,
							mcv_values,
							mcv_frequencies,
							num_mcv_values
2885 2886
							);

2887
	GPOS_ASSERT(gpdb_mcv_hist->IsValid());
2888

2889 2890
	CDouble mcv_freq = gpdb_mcv_hist->GetFrequency();
	BOOL has_mcv = 0 < num_mcv_values && CStatistics::Epsilon < mcv_freq;
2891

2892 2893
	CDouble hist_freq = 0.0;
	if (1 < num_hist_values)
2894
	{
2895
		hist_freq = CDouble(1.0) - null_freq - mcv_freq;
2896
	}
2897
	BOOL has_hist = 1 < num_hist_values && CStatistics::Epsilon < hist_freq;
2898

2899
	CHistogram *histogram = NULL;
2900 2901

	// if histogram has any significant information, then extract it
2902
	if (has_hist)
2903 2904
	{
		// histogram from gpdb histogram
2905
		histogram = TransformHistToOrcaHistogram
2906
						(
2907 2908 2909 2910 2911 2912
						mp,
						md_type,
						hist_values,
						num_hist_values,
						num_distinct,
						hist_freq
2913
						);
2914
		if (0 == histogram->Buckets())
2915
		{
2916
			has_hist = false;
2917
		}
2918 2919
	}

2920
	CDXLBucketArray *dxl_stats_bucket_array = NULL;
2921

2922
	if (has_hist && !has_mcv)
2923 2924
	{
		// if histogram exists and dominates, use histogram only
2925
		dxl_stats_bucket_array = TransformHistogramToDXLBucketArray(mp, md_type, histogram);
2926
	}
2927
	else if (!has_hist && has_mcv)
2928 2929
	{
		// if MCVs exist and dominate, use MCVs only
2930
		dxl_stats_bucket_array = TransformHistogramToDXLBucketArray(mp, md_type, gpdb_mcv_hist);
2931
	}
2932
	else if (has_hist && has_mcv)
2933 2934
	{
		// both histogram and MCVs exist and have significant info, merge MCV and histogram buckets
2935 2936 2937
		CHistogram *merged_hist = CStatisticsUtils::MergeMCVHist(mp, gpdb_mcv_hist, histogram);
		dxl_stats_bucket_array = TransformHistogramToDXLBucketArray(mp, md_type, merged_hist);
		GPOS_DELETE(merged_hist);
2938 2939 2940 2941
	}
	else
	{
		// no MCVs nor histogram
2942 2943
		GPOS_ASSERT(!has_hist && !has_mcv);
		dxl_stats_bucket_array = GPOS_NEW(mp) CDXLBucketArray(mp);
2944 2945 2946
	}

	// cleanup
2947 2948 2949
	mdid_atttype->Release();
	md_type->Release();
	GPOS_DELETE(gpdb_mcv_hist);
2950

2951
	if (NULL != histogram)
2952
	{
2953
		GPOS_DELETE(histogram);
2954 2955
	}

2956
	return dxl_stats_bucket_array;
2957 2958 2959 2960
}

//---------------------------------------------------------------------------
//	@function:
2961
//		CTranslatorRelcacheToDXL::TransformMcvToOrcaHistogram
2962 2963 2964 2965 2966 2967
//
//	@doc:
//		Transform gpdb's mcv info to optimizer histogram
//
//---------------------------------------------------------------------------
CHistogram *
2968
CTranslatorRelcacheToDXL::TransformMcvToOrcaHistogram
2969
	(
2970 2971 2972 2973 2974
	IMemoryPool *mp,
	const IMDType *md_type,
	const Datum *mcv_values,
	const float4 *mcv_frequencies,
	ULONG num_mcv_values
2975 2976
	)
{
2977 2978
	IDatumArray *datums = GPOS_NEW(mp) IDatumArray(mp);
	CDoubleArray *freqs = GPOS_NEW(mp) CDoubleArray(mp);
2979

2980
	for (ULONG ul = 0; ul < num_mcv_values; ul++)
2981
	{
2982 2983 2984 2985
		Datum datumMCV = mcv_values[ul];
		IDatum *datum = CTranslatorScalarToDXL::CreateIDatumFromGpdbDatum(mp, md_type, false /* is_null */, datumMCV);
		datums->Append(datum);
		freqs->Append(GPOS_NEW(mp) CDouble(mcv_frequencies[ul]));
2986

2987
		if (!datum->StatsAreComparable(datum))
2988 2989 2990
		{
			// if less than operation is not supported on this datum, then no point
			// building a histogram. return an empty histogram
2991 2992 2993
			datums->Release();
			freqs->Release();
			return GPOS_NEW(mp) CHistogram(GPOS_NEW(mp) CBucketArray(mp));
2994 2995 2996
		}
	}

2997
	CHistogram *hist = CStatisticsUtils::TransformMCVToHist
2998
												(
2999 3000 3001 3002 3003
												mp,
												md_type,
												datums,
												freqs,
												num_mcv_values
3004 3005
												);

3006 3007 3008
	datums->Release();
	freqs->Release();
	return hist;
3009 3010 3011 3012
}

//---------------------------------------------------------------------------
//	@function:
3013
//		CTranslatorRelcacheToDXL::TransformHistToOrcaHistogram
3014 3015 3016 3017 3018 3019
//
//	@doc:
//		Transform GPDB's hist info to optimizer's histogram
//
//---------------------------------------------------------------------------
CHistogram *
3020
CTranslatorRelcacheToDXL::TransformHistToOrcaHistogram
3021
	(
3022 3023 3024 3025 3026 3027
	IMemoryPool *mp,
	const IMDType *md_type,
	const Datum *hist_values,
	ULONG num_hist_values,
	CDouble num_distinct,
	CDouble hist_freq
3028 3029
	)
{
3030
	GPOS_ASSERT(1 < num_hist_values);
3031

3032 3033 3034
	const ULONG num_buckets = num_hist_values - 1;
	CDouble distinct_per_bucket = num_distinct / CDouble(num_buckets);
	CDouble freq_per_bucket = hist_freq / CDouble(num_buckets);
3035

3036
	BOOL last_bucket_was_singleton = false;
3037
	// create buckets
3038 3039
	CBucketArray *buckets = GPOS_NEW(mp) CBucketArray(mp);
	for (ULONG ul = 0; ul < num_buckets; ul++)
3040
	{
3041 3042 3043
		IDatum *min_datum = CTranslatorScalarToDXL::CreateIDatumFromGpdbDatum(mp, md_type, false /* is_null */, hist_values[ul]);
		IDatum *max_datum = CTranslatorScalarToDXL::CreateIDatumFromGpdbDatum(mp, md_type, false /* is_null */, hist_values[ul + 1]);
		BOOL is_lower_closed, is_upper_closed;
3044

3045
		if (min_datum->StatsAreEqual(max_datum))
3046 3047
		{
			// Singleton bucket !!!!!!!!!!!!!
3048 3049 3050
			is_lower_closed = true;
			is_upper_closed = true;
			last_bucket_was_singleton = true;
3051
		}
3052
		else if (last_bucket_was_singleton)
3053 3054
		{
			// Last bucket was a singleton, so lower must be open now.
3055 3056 3057
			is_lower_closed = false;
			is_upper_closed = false;
			last_bucket_was_singleton = false;
3058 3059 3060 3061 3062
		}
		else
		{
			// Normal bucket
			// GPDB histograms assumes lower bound to be closed and upper bound to be open
3063 3064
			is_lower_closed = true;
			is_upper_closed = false;
3065
		}
3066

3067
		if (ul == num_buckets - 1)
3068 3069
		{
			// last bucket upper bound is also closed
3070
			is_upper_closed = true;
3071 3072
		}

3073
		CBucket *bucket = GPOS_NEW(mp) CBucket
3074
									(
3075 3076 3077 3078 3079 3080
									GPOS_NEW(mp) CPoint(min_datum),
									GPOS_NEW(mp) CPoint(max_datum),
									is_lower_closed,
									is_upper_closed,
									freq_per_bucket,
									distinct_per_bucket
3081
									);
3082
		buckets->Append(bucket);
3083

3084
		if (!min_datum->StatsAreComparable(max_datum) || !min_datum->StatsAreLessThan(max_datum))
3085 3086 3087 3088 3089 3090 3091 3092
		{
			// if less than operation is not supported on this datum,
			// or the translated histogram does not conform to GPDB sort order (e.g. text column in Linux platform),
			// then no point building a histogram. return an empty histogram

			// TODO: 03/01/2014 translate histogram into Orca even if sort
			// order is different in GPDB, and use const expression eval to compare
			// datums in Orca (MPP-22780)
3093 3094
			buckets->Release();
			return GPOS_NEW(mp) CHistogram(GPOS_NEW(mp) CBucketArray(mp));
3095 3096 3097
		}
	}

3098 3099
	CHistogram *hist = GPOS_NEW(mp) CHistogram(buckets);
	return hist;
3100 3101 3102 3103 3104
}


//---------------------------------------------------------------------------
//	@function:
3105
//		CTranslatorRelcacheToDXL::TransformHistogramToDXLBucketArray
3106 3107 3108 3109 3110
//
//	@doc:
//		Histogram to array of dxl buckets
//
//---------------------------------------------------------------------------
3111 3112
CDXLBucketArray *
CTranslatorRelcacheToDXL::TransformHistogramToDXLBucketArray
3113
	(
3114 3115 3116
	IMemoryPool *mp,
	const IMDType *md_type,
	const CHistogram *hist
3117 3118
	)
{
3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129
	CDXLBucketArray *dxl_stats_bucket_array = GPOS_NEW(mp) CDXLBucketArray(mp);
	const CBucketArray *buckets = hist->ParseDXLToBucketsArray();
	ULONG num_buckets = buckets->Size();
	for (ULONG ul = 0; ul < num_buckets; ul++)
	{
		CBucket *bucket = (*buckets)[ul];
		IDatum *datum_lower = bucket->GetLowerBound()->GetDatum();
		CDXLDatum *dxl_lower = md_type->GetDatumVal(mp, datum_lower);
		IDatum *datum_upper = bucket->GetUpperBound()->GetDatum();
		CDXLDatum *dxl_upper = md_type->GetDatumVal(mp, datum_upper);
		CDXLBucket *dxl_bucket = GPOS_NEW(mp) CDXLBucket
3130
											(
3131 3132 3133 3134 3135 3136
											dxl_lower,
											dxl_upper,
											bucket->IsLowerClosed(),
											bucket->IsUpperClosed(),
											bucket->GetFrequency(),
											bucket->GetNumDistinct()
3137
											);
3138
		dxl_stats_bucket_array->Append(dxl_bucket);
3139
	}
3140
	return dxl_stats_bucket_array;
3141 3142 3143 3144
}

//---------------------------------------------------------------------------
//	@function:
3145
//		CTranslatorRelcacheToDXL::RetrieveRelStorageType
3146 3147 3148 3149 3150 3151
//
//	@doc:
//		Get relation storage type
//
//---------------------------------------------------------------------------
IMDRelation::Erelstoragetype
3152
CTranslatorRelcacheToDXL::RetrieveRelStorageType
3153
	(
3154
	CHAR storage_type
3155 3156
	)
{
3157
	IMDRelation::Erelstoragetype rel_storage_type = IMDRelation::ErelstorageSentinel;
3158

3159
	switch (storage_type)
3160 3161
	{
		case RELSTORAGE_HEAP:
3162
			rel_storage_type = IMDRelation::ErelstorageHeap;
3163 3164
			break;
		case RELSTORAGE_AOCOLS:
3165
			rel_storage_type = IMDRelation::ErelstorageAppendOnlyCols;
3166 3167
			break;
		case RELSTORAGE_AOROWS:
3168
			rel_storage_type = IMDRelation::ErelstorageAppendOnlyRows;
3169 3170
			break;
		case RELSTORAGE_VIRTUAL:
3171
			rel_storage_type = IMDRelation::ErelstorageVirtual;
3172 3173
			break;
		case RELSTORAGE_EXTERNAL:
3174
			rel_storage_type = IMDRelation::ErelstorageExternal;
3175 3176 3177 3178 3179
			break;
		default:
			GPOS_ASSERT(!"Unsupported relation type");
	}

3180
	return rel_storage_type;
3181 3182 3183 3184
}

//---------------------------------------------------------------------------
//	@function:
3185
//		CTranslatorRelcacheToDXL::RetrievePartKeysAndTypes
3186 3187
//
//	@doc:
3188
//		Get partition keys and types for relation or NULL if relation not partitioned.
3189 3190 3191
//		Caller responsible for closing the relation if an exception is raised
//
//---------------------------------------------------------------------------
3192
void
3193
CTranslatorRelcacheToDXL::RetrievePartKeysAndTypes
3194
	(
3195
	IMemoryPool *mp,
3196
	Relation rel,
3197
	OID oid,
3198 3199
	ULongPtrArray **part_keys,
	CharPtrArray **part_types
3200 3201 3202 3203
	)
{
	GPOS_ASSERT(NULL != rel);

3204
	if (!gpdb::RelPartIsRoot(oid))
3205 3206
	{
		// not a partitioned table
3207 3208
		*part_keys = NULL;
		*part_types = NULL;
3209
		return;
3210 3211 3212 3213
	}

	// TODO: Feb 23, 2012; support intermediate levels

3214 3215
	*part_keys = GPOS_NEW(mp) ULongPtrArray(mp);
	*part_types = GPOS_NEW(mp) CharPtrArray(mp);
3216

3217
	PartitionNode *pn = gpdb::GetParts(oid, 0 /*level*/, 0 /*parent*/, false /*inctemplate*/, true /*includesubparts*/);
3218
	GPOS_ASSERT(NULL != pn);
3219

3220 3221 3222 3223 3224
	if (gpdb::FHashPartitioned(pn->part->parkind))
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDObjUnsupported, GPOS_WSZ_LIT("Hash partitioning"));
	}

3225 3226 3227 3228 3229 3230 3231
	List *part_keys_list = NIL;
	List *part_types_list = NIL;
	gpdb::GetOrderedPartKeysAndKinds(oid, &part_keys_list, &part_types_list);

	ListCell *lc_key = NULL;
	ListCell *lc_type = NULL;
	ForBoth (lc_key, part_keys_list, lc_type, part_types_list)
3232
	{
3233
		List *part_key = (List *) lfirst(lc_key);
3234

3235
		if (1 < gpdb::ListLength(part_key))
3236 3237 3238 3239
		{
			GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDObjUnsupported, GPOS_WSZ_LIT("Composite part key"));
		}

3240 3241 3242 3243 3244
		INT attno = linitial_int(part_key);
		CHAR part_type = (CHAR) lfirst_int(lc_type);
		GPOS_ASSERT(0 < attno);
		(*part_keys)->Append(GPOS_NEW(mp) ULONG(attno - 1));
		(*part_types)->Append(GPOS_NEW(mp) CHAR(part_type));
3245 3246
	}

3247 3248
	gpdb::ListFree(part_keys_list);
	gpdb::ListFree(part_types_list);
3249 3250 3251 3252 3253
}


//---------------------------------------------------------------------------
//	@function:
3254
//		CTranslatorRelcacheToDXL::ConstructAttnoMapping
3255 3256 3257 3258 3259 3260
//
//	@doc:
//		Construct a mapping for GPDB attnos to positions in the columns array
//
//---------------------------------------------------------------------------
ULONG *
3261
CTranslatorRelcacheToDXL::ConstructAttnoMapping
3262
	(
3263 3264 3265
	IMemoryPool *mp,
	CMDColumnArray *mdcol_array,
	ULONG max_cols
3266 3267
	)
{
3268 3269 3270
	GPOS_ASSERT(NULL != mdcol_array);
	GPOS_ASSERT(0 < mdcol_array->Size());
	GPOS_ASSERT(max_cols > mdcol_array->Size());
3271 3272

	// build a mapping for attnos->positions
3273 3274
	const ULONG num_of_cols = mdcol_array->Size();
	ULONG *attno_mapping = GPOS_NEW_ARRAY(mp, ULONG, max_cols);
3275

3276
	// initialize all positions to gpos::ulong_max
3277
	for (ULONG ul = 0;  ul < max_cols; ul++)
3278
	{
3279
		attno_mapping[ul] = gpos::ulong_max;
3280 3281
	}
	
3282
	for (ULONG ul = 0;  ul < num_of_cols; ul++)
3283
	{
3284 3285
		const IMDColumn *md_col = (*mdcol_array)[ul];
		INT attno = md_col->AttrNum();
3286

3287 3288
		ULONG idx = (ULONG) (GPDXL_SYSTEM_COLUMNS + attno);
		attno_mapping[idx] = ul;
3289 3290
	}

3291
	return attno_mapping;
3292 3293 3294 3295
}

//---------------------------------------------------------------------------
//	@function:
3296
//		CTranslatorRelcacheToDXL::RetrieveRelKeysets
3297 3298 3299 3300 3301
//
//	@doc:
//		Get key sets for relation
//
//---------------------------------------------------------------------------
3302 3303
ULongPtr2dArray *
CTranslatorRelcacheToDXL::RetrieveRelKeysets
3304
	(
3305
	IMemoryPool *mp,
3306
	OID oid,
3307 3308 3309
	BOOL should_add_default_keys,
	BOOL is_partitioned,
	ULONG *attno_mapping
3310 3311
	)
{
3312
	ULongPtr2dArray *key_sets = GPOS_NEW(mp) ULongPtr2dArray(mp);
3313

3314
	List *rel_keys = gpdb::GetRelationKeys(oid);
3315

3316 3317
	ListCell *lc_key = NULL;
	ForEach (lc_key, rel_keys)
3318
	{
3319
		List *key_elem_list = (List *) lfirst(lc_key);
3320

3321
		ULongPtrArray *key_set = GPOS_NEW(mp) ULongPtrArray(mp);
3322

3323 3324
		ListCell *lc_key_elem = NULL;
		ForEach (lc_key_elem, key_elem_list)
3325
		{
3326 3327 3328
			INT key_idx = lfirst_int(lc_key_elem);
			ULONG pos = GetAttributePosition(key_idx, attno_mapping);
			key_set->Append(GPOS_NEW(mp) ULONG(pos));
3329
		}
3330
		GPOS_ASSERT(0 < key_set->Size());
3331

3332
		key_sets->Append(key_set);
3333 3334 3335 3336
	}
	
	// add {segid, ctid} as a key
	
3337
	if (should_add_default_keys)
3338
	{
3339 3340
		ULongPtrArray *key_set = GPOS_NEW(mp) ULongPtrArray(mp);
		if (is_partitioned)
3341 3342
		{
			// TableOid is part of default key for partitioned tables
3343 3344
			ULONG table_oid_pos = GetAttributePosition(TableOidAttributeNumber, attno_mapping);
			key_set->Append(GPOS_NEW(mp) ULONG(table_oid_pos));
3345
		}
3346 3347 3348 3349
		ULONG seg_id_pos= GetAttributePosition(GpSegmentIdAttributeNumber, attno_mapping);
		ULONG ctid_pos = GetAttributePosition(SelfItemPointerAttributeNumber, attno_mapping);
		key_set->Append(GPOS_NEW(mp) ULONG(seg_id_pos));
		key_set->Append(GPOS_NEW(mp) ULONG(ctid_pos));
3350
		
3351
		key_sets->Append(key_set);
3352 3353
	}
	
3354
	return key_sets;
3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368
}

//---------------------------------------------------------------------------
//	@function:
//		CTranslatorRelcacheToDXL::NormalizeFrequencies
//
//	@doc:
//		Sometimes a set of frequencies can add up to more than 1.0.
//		Fix these cases
//
//---------------------------------------------------------------------------
void
CTranslatorRelcacheToDXL::NormalizeFrequencies
	(
3369 3370 3371
	float4 *freqs,
	ULONG length,
	CDouble *null_freq
3372 3373
	)
{
3374
	if (length == 0 && (*null_freq) < 1.0)
3375 3376 3377 3378
	{
		return;
	}

3379 3380
	CDouble total = *null_freq;
	for (ULONG ul = 0; ul < length; ul++)
3381
	{
3382
		total = total + CDouble(freqs[ul]);
3383 3384
	}

3385
	if (total > CDouble(1.0))
3386
	{
3387
		float4 denom = (float4) (total + CStatistics::Epsilon).Get();
3388 3389

		// divide all values by the total
3390
		for (ULONG ul = 0; ul < length; ul++)
3391
		{
3392
			freqs[ul] = freqs[ul] / denom;
3393
		}
3394
		*null_freq = *null_freq / denom;
3395 3396 3397 3398
	}

#ifdef GPOS_DEBUG
	// recheck
3399 3400
	CDouble recheck_total = *null_freq;
	for (ULONG ul = 0; ul < length; ul++)
3401
	{
3402
		recheck_total = recheck_total + CDouble(freqs[ul]);
3403
	}
3404
	GPOS_ASSERT(recheck_total <= CDouble(1.0));
3405 3406 3407 3408 3409
#endif
}

//---------------------------------------------------------------------------
//	@function:
3410
//		CTranslatorRelcacheToDXL::IsIndexSupported
3411 3412 3413 3414 3415 3416
//
//	@doc:
//		Check if index type is supported
//
//---------------------------------------------------------------------------
BOOL
3417
CTranslatorRelcacheToDXL::IsIndexSupported
3418
	(
3419
	Relation index_rel
3420 3421
	)
{
3422
	HeapTupleData *tup = index_rel->rd_indextuple;
3423 3424
	
	// index expressions and index constraints not supported
3425 3426 3427
	return gpdb::HeapAttIsNull(tup, Anum_pg_index_indexprs) &&
		gpdb::HeapAttIsNull(tup, Anum_pg_index_indpred) &&
		(BTREE_AM_OID == index_rel->rd_rel->relam || BITMAP_AM_OID == index_rel->rd_rel->relam  || GIST_AM_OID == index_rel->rd_rel->relam);
3428 3429 3430 3431
}

//---------------------------------------------------------------------------
//	@function:
3432
//		CTranslatorRelcacheToDXL::RetrievePartConstraintForIndex
3433 3434 3435 3436 3437 3438
//
//	@doc:
//		Retrieve part constraint for index
//
//---------------------------------------------------------------------------
CMDPartConstraintGPDB *
3439
CTranslatorRelcacheToDXL::RetrievePartConstraintForIndex
3440
	(
3441 3442 3443 3444 3445 3446
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	const IMDRelation *md_rel,
	Node *part_constraint,
	ULongPtrArray *level_with_default_part_array,
	BOOL is_unbounded
3447 3448
	)
{
3449 3450
	CDXLColDescrArray *dxl_col_descr_array = GPOS_NEW(mp) CDXLColDescrArray(mp);
	const ULONG num_columns = md_rel->ColumnCount();
3451
	
3452
	for (ULONG ul = 0; ul < num_columns; ul++)
3453
	{
3454 3455 3456 3457
		const IMDColumn *md_col = md_rel->GetMdCol(ul);
		CMDName *md_colname = GPOS_NEW(mp) CMDName(mp, md_col->Mdname().GetMDName());
		CMDIdGPDB *mdid_col_type = CMDIdGPDB::CastMdid(md_col->MdidType());
		mdid_col_type->AddRef();
3458 3459

		// create a column descriptor for the column
3460
		CDXLColDescr *dxl_col_descr = GPOS_NEW(mp) CDXLColDescr
3461
										(
3462 3463 3464 3465 3466 3467
										mp,
										md_colname,
										ul + 1, // colid
										md_col->AttrNum(),
										mdid_col_type,
										md_col->TypeModifier(),
3468 3469
										false // fColDropped
										);
3470
		dxl_col_descr_array->Append(dxl_col_descr);
3471
	}
3472 3473

	CMDPartConstraintGPDB *mdpart_constraint = RetrievePartConstraintFromNode(mp, md_accessor, dxl_col_descr_array, part_constraint, level_with_default_part_array, is_unbounded);
3474
	
3475
	dxl_col_descr_array->Release();
3476

3477
	return mdpart_constraint;
3478 3479 3480 3481
}

//---------------------------------------------------------------------------
//	@function:
3482
//		CTranslatorRelcacheToDXL::RetrievePartConstraintForRel
3483 3484 3485 3486 3487 3488
//
//	@doc:
//		Retrieve part constraint for relation
//
//---------------------------------------------------------------------------
CMDPartConstraintGPDB *
3489
CTranslatorRelcacheToDXL::RetrievePartConstraintForRel
3490
	(
3491 3492 3493 3494 3495
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	OID rel_oid,
	CMDColumnArray *mdcol_array,
	bool has_index
3496 3497 3498
	)
{
	// get the part constraints
3499 3500
	List *default_levels_rel = NIL;
	Node *node = gpdb::GetRelationPartContraints(rel_oid, &default_levels_rel);
3501

3502 3503
	// don't retrieve part constraints if there are no indices
	// and no default partitions at any level
3504
	if (!has_index && NIL == default_levels_rel)
3505 3506 3507 3508
	{
		return NULL;
	}

3509 3510 3511
	List *part_keys = gpdb::GetPartitionAttrs(rel_oid);
	const ULONG num_of_levels = gpdb::ListLength(part_keys);
	gpdb::ListFree(part_keys);
3512

3513 3514 3515
	BOOL is_unbounded = true;
	ULongPtrArray *default_levels_derived = GPOS_NEW(mp) ULongPtrArray(mp);
	for (ULONG ul = 0; ul < num_of_levels; ul++)
3516
	{
3517
		if (LevelHasDefaultPartition(default_levels_rel, ul))
3518
		{
3519
			default_levels_derived->Append(GPOS_NEW(mp) ULONG(ul));
3520 3521 3522
		}
		else
		{
3523
			is_unbounded = false;
3524 3525 3526
		}
	}

3527
	CMDPartConstraintGPDB *mdpart_constraint = NULL;
3528

3529
	if (!has_index)
3530
	{
3531 3532 3533
		// if there are no indices then we don't need to construct the partition constraint
		// expression since ORCA is never going to use it.
		// only send the default partition information.
3534 3535
		default_levels_derived->AddRef();
		mdpart_constraint = GPOS_NEW(mp) CMDPartConstraintGPDB(mp, default_levels_derived, is_unbounded, NULL);
3536 3537 3538
	}
	else
	{
3539 3540 3541
		CDXLColDescrArray *dxl_col_descr_array = GPOS_NEW(mp) CDXLColDescrArray(mp);
		const ULONG num_columns = mdcol_array->Size();
		for (ULONG ul = 0; ul < num_columns; ul++)
3542
		{
3543 3544 3545 3546
			const IMDColumn *md_col = (*mdcol_array)[ul];
			CMDName *md_colname = GPOS_NEW(mp) CMDName(mp, md_col->Mdname().GetMDName());
			CMDIdGPDB *mdid_col_type = CMDIdGPDB::CastMdid(md_col->MdidType());
			mdid_col_type->AddRef();
3547

3548
			// create a column descriptor for the column
3549
			CDXLColDescr *dxl_col_descr = GPOS_NEW(mp) CDXLColDescr
3550
											(
3551 3552 3553 3554 3555 3556
											mp,
											md_colname,
											ul + 1, // colid
											md_col->AttrNum(),
											mdid_col_type,
											md_col->TypeModifier(),
3557 3558
											false // fColDropped
											);
3559
			dxl_col_descr_array->Append(dxl_col_descr);
3560 3561
		}

3562 3563
		mdpart_constraint = RetrievePartConstraintFromNode(mp, md_accessor, dxl_col_descr_array, node, default_levels_derived, is_unbounded);
		dxl_col_descr_array->Release();
3564 3565
	}

3566 3567
	gpdb::ListFree(default_levels_rel);
	default_levels_derived->Release();
3568

3569
	return mdpart_constraint;
3570 3571 3572 3573
}

//---------------------------------------------------------------------------
//	@function:
3574
//		CTranslatorRelcacheToDXL::RetrievePartConstraintFromNode
3575 3576 3577 3578 3579 3580
//
//	@doc:
//		Retrieve part constraint from GPDB node
//
//---------------------------------------------------------------------------
CMDPartConstraintGPDB *
3581
CTranslatorRelcacheToDXL::RetrievePartConstraintFromNode
3582
	(
3583 3584 3585 3586 3587 3588
	IMemoryPool *mp,
	CMDAccessor *md_accessor,
	CDXLColDescrArray *dxl_col_descr_array,
	Node *part_constraints,
	ULongPtrArray *level_with_default_part_array,
	BOOL is_unbounded
3589 3590
	)
{
3591
	if (NULL == part_constraints)
3592 3593 3594 3595
	{
		return NULL;
	}

3596
	CTranslatorScalarToDXL scalar_translator
3597
							(
3598 3599
							mp,
							md_accessor,
3600 3601
							NULL, // pulidgtorCol
							NULL, // pulidgtorCTE
3602
							0, // query_level
3603
							true, // m_fQuery
3604 3605
							NULL, // query_level_to_cte_map
							NULL // cte_dxlnode_array
3606 3607 3608
							);

	// generate a mock mapping between var to column information
3609
	CMappingVarColId *var_colid_mapping = GPOS_NEW(mp) CMappingVarColId(mp);
3610

3611
	var_colid_mapping->LoadColumns(0 /*query_level */, 1 /* rteIndex */, dxl_col_descr_array);
3612 3613

	// translate the check constraint expression
3614
	CDXLNode *scalar_dxlnode = scalar_translator.TranslateScalarToDXL((Expr *) part_constraints, var_colid_mapping);
3615 3616

	// cleanup
3617
	GPOS_DELETE(var_colid_mapping);
3618

3619 3620
	level_with_default_part_array->AddRef();
	return GPOS_NEW(mp) CMDPartConstraintGPDB(mp, level_with_default_part_array, is_unbounded, scalar_dxlnode);
3621 3622 3623 3624
}

//---------------------------------------------------------------------------
//	@function:
3625
//		CTranslatorRelcacheToDXL::RelHasSystemColumns
3626 3627 3628 3629 3630 3631 3632 3633
//
//	@doc:
//		Does given relation type have system columns.
//		Currently only regular relations, sequences, toast values relations and
//		AO segment relations have system columns
//
//---------------------------------------------------------------------------
BOOL
3634
CTranslatorRelcacheToDXL::RelHasSystemColumns
3635
	(
3636
	char rel_kind
3637 3638
	)
{
3639 3640 3641 3642
	return RELKIND_RELATION == rel_kind ||
			RELKIND_SEQUENCE == rel_kind ||
			RELKIND_AOSEGMENTS == rel_kind ||
			RELKIND_TOASTVALUE == rel_kind;
3643 3644 3645 3646
}

//---------------------------------------------------------------------------
//	@function:
3647
//		CTranslatorRelcacheToDXL::ParseCmpType
3648 3649 3650 3651 3652 3653
//
//	@doc:
//		Translate GPDB comparison types into optimizer comparison types
//
//---------------------------------------------------------------------------
IMDType::ECmpType
3654
CTranslatorRelcacheToDXL::ParseCmpType
3655
	(
3656
	ULONG cmpt
3657 3658
	)
{
3659
	for (ULONG ul = 0; ul < GPOS_ARRAY_SIZE(cmp_type_mappings); ul++)
3660
	{
3661 3662
		const ULONG *mapping = cmp_type_mappings[ul];
		if (mapping[1] == cmpt)
3663
		{
3664
			return (IMDType::ECmpType) mapping[0];
3665 3666 3667 3668 3669 3670 3671 3672
		}
	}
	
	return IMDType::EcmptOther;
}

//---------------------------------------------------------------------------
//	@function:
3673
//		CTranslatorRelcacheToDXL::GetComparisonType
3674 3675 3676 3677 3678 3679
//
//	@doc:
//		Translate optimizer comparison types into GPDB comparison types
//
//---------------------------------------------------------------------------
ULONG 
3680
CTranslatorRelcacheToDXL::GetComparisonType
3681
	(
3682
	IMDType::ECmpType cmp_type
3683 3684
	)
{
3685
	for (ULONG ul = 0; ul < GPOS_ARRAY_SIZE(cmp_type_mappings); ul++)
3686
	{
3687 3688
		const ULONG *mapping = cmp_type_mappings[ul];
		if (mapping[0] == cmp_type)
3689
		{
3690
			return (ULONG) mapping[1];
3691 3692 3693 3694 3695 3696 3697 3698
		}
	}
	
	return CmptOther;
}

//---------------------------------------------------------------------------
//	@function:
3699
//		CTranslatorRelcacheToDXL::RetrieveIndexOpFamilies
3700 3701
//
//	@doc:
3702
//		Retrieve the opfamilies for the keys of the given index
3703 3704
//
//---------------------------------------------------------------------------
3705 3706
IMdIdArray *
CTranslatorRelcacheToDXL::RetrieveIndexOpFamilies
3707
	(
3708 3709
	IMemoryPool *mp,
	IMDId *mdid_index
3710 3711
	)
{
3712 3713
	List *op_families = gpdb::GetIndexOpFamilies(CMDIdGPDB::CastMdid(mdid_index)->Oid());
	IMdIdArray *input_col_mdids = GPOS_NEW(mp) IMdIdArray(mp);
3714
	
3715
	ListCell *lc = NULL;
3716
	
3717
	ForEach(lc, op_families)
3718
	{
3719 3720
		OID op_family_oid = lfirst_oid(lc);
		input_col_mdids->Append(GPOS_NEW(mp) CMDIdGPDB(op_family_oid));
3721 3722
	}
	
3723
	return input_col_mdids;
3724 3725 3726 3727
}

//---------------------------------------------------------------------------
//	@function:
3728
//		CTranslatorRelcacheToDXL::RetrieveScOpOpFamilies
3729 3730
//
//	@doc:
3731
//		Retrieve the families for the keys of the given scalar operator
3732 3733
//
//---------------------------------------------------------------------------
3734 3735
IMdIdArray *
CTranslatorRelcacheToDXL::RetrieveScOpOpFamilies
3736
	(
3737 3738
	IMemoryPool *mp,
	IMDId *mdid_scalar_op
3739 3740
	)
{
3741 3742
	List *op_families = gpdb::GetOpFamiliesForScOp(CMDIdGPDB::CastMdid(mdid_scalar_op)->Oid());
	IMdIdArray *input_col_mdids = GPOS_NEW(mp) IMdIdArray(mp);
3743
	
3744
	ListCell *lc = NULL;
3745
	
3746
	ForEach(lc, op_families)
3747
	{
3748 3749
		OID op_family_oid = lfirst_oid(lc);
		input_col_mdids->Append(GPOS_NEW(mp) CMDIdGPDB(op_family_oid));
3750 3751
	}
	
3752
	return input_col_mdids;
3753 3754 3755 3756
}

// EOF