cdbpartindex.c 43.6 KB
Newer Older
1 2 3 4 5 6
/*--------------------------------------------------------------------------
 *
 * cdbpartindex.c
 *	Provides utility routines to support indexes over partitioned tables
 *	within Greenplum Database.
 *
7 8 9 10 11 12
 * Portions Copyright (c) 2005-2010, Greenplum inc
 * Portions Copyright (c) 2012-Present Pivotal Software, Inc.
 *
 *
 * IDENTIFICATION
 *	    src/backend/cdb/cdbpartindex.c
13 14 15 16
 *
 *--------------------------------------------------------------------------
 */
#include "postgres.h"
17

18
#include "access/genam.h"
19 20
#include "access/hash.h"
#include "catalog/index.h"
21
#include "catalog/indexing.h"
22 23 24
#include "catalog/pg_constraint.h"
#include "catalog/pg_partition_rule.h"
#include "cdb/cdbpartition.h"
25
#include "cdb/partitionselection.h"
26
#include "cdb/cdbvars.h"
27
#include "executor/executor.h"
28 29
#include "nodes/makefuncs.h"
#include "parser/parse_expr.h"
A
Asim R P 已提交
30
#include "utils/array.h"
31
#include "utils/builtins.h"
32
#include "utils/fmgroids.h"
33 34
#include "utils/lsyscache.h"
#include "utils/memutils.h"
35
#include "utils/tqual.h"
36 37 38 39

/* initial estimate for number of logical indexes */
#define INITIAL_NUM_LOGICAL_INDEXES_ESTIMATE 100

A
Ashwin Agrawal 已提交
40 41 42
static int	logicalIndexId = 1;
static int	numLogicalIndexes = 0;
static int	numIndexesOnDefaultParts = 0;
43

A
Ashwin Agrawal 已提交
44
/*
45 46 47 48 49 50 51 52
 * hash table to identify distinct "logical indexes". Each index with the same
 * index key, index pred, index expr is considered equivalent.
 */
static HTAB *PartitionIndexHash;

/* hash table to hold information about distinct logical indexes. */
static HTAB *LogicalIndexInfoHash;

A
Ashwin Agrawal 已提交
53
/*
54
 * Hash entry for PartitionIndexHash
55 56
 * hashkey is (indexkey + indexpred + indexexprs)
 */
A
Ashwin Agrawal 已提交
57 58 59 60
typedef struct
{
	char	   *key;
	int			logicalIndexId;
61 62 63 64 65 66 67 68
} PartitionIndexHashEntry;

/*
 * Hashentry for LogicalIndexInfoHash
 * hashkey is (logicalIndexId)
 */
typedef struct
{
A
Ashwin Agrawal 已提交
69 70 71 72
	char	   *key;
	int			logicalIndexId;
	Oid			logicalIndexOid;
	struct IndexInfo *ii;
73
	LogicalIndexType indType;
A
Ashwin Agrawal 已提交
74 75
	List	   *partList;
	List	   *defaultPartList;
76 77 78 79 80 81 82 83
} LogicalIndexInfoHashEntry;

/*
 * Each node in the PartitionIndexNode tree describes a partition
 * and a list of it's logical indexes
 */
typedef struct PartitionIndexNode
{
A
Ashwin Agrawal 已提交
84 85 86 87 88 89 90 91
	Oid			paroid;			/* OID of row in pg_partition */
	Oid			parparentrule;	/* OID of row in pg_partition_rule */
	Oid			parchildrelid;	/* table oid of the part */
	Oid			parrelid;		/* needed to map attnums */
	bool		isDefault;		/* is this a default part */
	Bitmapset  *index;			/* logical indexes for this part */
	List	   *children;		/* child parts */
	List	   *defaultLevels;	/* the level at which the part key is default */
92 93 94
} PartitionIndexNode;

static void recordIndexesOnLeafPart(PartitionIndexNode **pNodePtr,
A
Ashwin Agrawal 已提交
95
						Oid partOid, Oid rootOid);
96
static void recordIndexes(PartitionIndexNode **partIndexTree);
97
static void getPartitionIndexNode(Oid rootOid, int16 level,
A
Ashwin Agrawal 已提交
98 99
					  Oid parent, PartitionIndexNode **n,
					  bool isDefault, List *defaultLevels);
100 101
static void indexParts(PartitionIndexNode **np, bool isDefault);
static void dumpPartsIndexInfo(PartitionIndexNode *n, int level);
A
Ashwin Agrawal 已提交
102
static LogicalIndexes *createPartsIndexResult(Oid root);
103
static bool collapseIndexes(PartitionIndexNode **partitionIndexNode,
A
Ashwin Agrawal 已提交
104
				LogicalIndexInfoHashEntry **entry);
105
static void createIndexHashTables(void);
106
static IndexInfo *populateIndexInfo(Relation indRel);
107 108 109 110 111 112 113 114 115 116 117 118 119
static Node *mergeIntervals(Node *intervalFst, Node *intervalSnd);
static void extractStartEndRange(Node *clause, Node **ppnodeStart, Node **ppnodeEnd);
static void extractOpExprComponents(OpExpr *opexpr, Var **ppvar, Const **ppconst, Oid *opno);

/*
 * TODO: similar routines in cdbpartition.c. Move up to cdbpartition.h ?
 */

/* Hash entire string */
static uint32
key_string_hash(const void *key, Size keysize)
{
	Size		s_len = strlen((const char *) key);
A
Ashwin Agrawal 已提交
120 121

	Assert(keysize == sizeof(char *));
122 123 124 125 126 127 128
	return DatumGetUInt32(hash_any((const unsigned char *) key, (int) s_len));
}

/* Compare entire string. */
static int
key_string_compare(const void *key1, const void *key2, Size keysize)
{
A
Ashwin Agrawal 已提交
129 130
	Assert(keysize == sizeof(char *));
	return strcmp(((PartitionIndexHashEntry *) key1)->key, key2);
131 132 133 134 135 136
}

/* Copy string by copying pointer. */
static void *
key_string_copy(void *dest, const void *src, Size keysize)
{
A
Ashwin Agrawal 已提交
137 138 139 140
	Assert(keysize == sizeof(char *));

	*((char **) dest) = (char *) src;	/* trust caller re allocation */
	return NULL;				/* not used */
141 142
}

143
/*-------------------------------------------------------------------------
144 145 146 147 148 149 150 151
 * BuildLogicalIndexInfo
 *   Returns an array of "logical indexes" on partitioned
 *   tables.
 *
 *   Memory for result is allocated from caller context.
 *
 *   If input relid does not represent a partitioned table, the function
 *   returns NULL.
A
Ashwin Agrawal 已提交
152
 *
153
 *  This function does the following
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
 *	1) Builds a PartitionIndexNode tree representing the partitioned
 *	   table hierarchy.
 * 	2) Builds 2 hash tables -
 *	 	- 1st hash table is used to find the logical indexes in a
 *		  partitioning tree hierarchy - a logical
 * 		  index corresponds to multiple physical indexes each
 *		  of which have the same index key + index pred + index exprs. Each
 *		  logical index is assigned a unique logicalIndexId.
 *		- The 2nd hash table table is used to hold information associated
 *		  with a logical index for easy lookup.
 *	3) Annotates leaves of hierarchy with logical index ids.
 *	   See recordIndexes function comments.
 *	4) Consolidates logical index information i.e. if a logical index exists on all
 * 	   child parts of a parent part, the parent part is annotated with the logical
 *	   index id and logical index id is cleared from child parts.
 *	5) For each logical index, OR the check constraints of the part on which
 * 	   the index exists (i.e. generate a partial index predicate for each
 *	   logical index)
 * 	6) Since default parts, don't have constraints associated with them,
 * 	   each logical index on a default part is represented as a separate
 *	   logical index in the output. Some additional information is
 *	   included so the specific default partition may be identified.
A
Ashwin Agrawal 已提交
176
 *
177 178 179 180 181
 *	Example of a partitioning hierarchy, and the output generated.
 *	I1..In are logical index ids.
 *
 *	After Step 3 (leaves annotated with logical index ids)
 *
A
Ashwin Agrawal 已提交
182
 *				Root
183 184 185 186 187 188 189 190 191 192 193 194 195 196
 *		  / 		|		\
 *		 /		|		 \
 *		/		|		  \
 *		A1 		A2		default  - pk1 is partkey at level 0
 *	     /      \	       /    \		/       \
 *	    /	     \        /      \	       /         \
 *	   /          \	     /        \	      /           \
 * B1(I1,I2)   def(I1,I2) B1(I1,I2)  def(I2) B1(I1,I2,I4) def(I1,I2,I3) - pk2 is partkey at level 1
 *
 *
 * 	After step 4 - (consolidation of logical indexes)
 *
 *			      Root (I2)
 *		 / 		| 	       \
A
Ashwin Agrawal 已提交
197 198
 *		/		|		\
 * 	       /             	|		 \
199 200 201 202 203 204 205
 *   	    A1 (I1)		A2		default	(I1)
 *	 /      \            /      \            /     \
 *	/        \          /        \	 	/       \
 *     /          \	   /          \	       /         \
 *    B1         def   B1(I1)         def   B1(I4)    def(I3)
 *
 * The output returned from BuildLogicalIndexInfo will be
A
Ashwin Agrawal 已提交
206
 *
207 208
 * logicalIndexOid 	nColumns  indexKeys  indPred indExprs  indIsUnique  partCons   				defaultLevels
 * 	I2		..	  ..	     ..	     ..	       ..           -						-
A
Ashwin Agrawal 已提交
209
 * 	I1		..	  ..	     ..	     ..	       ..           pk1=A1 OR (pk1=A2 AND pk2=B1)		-
210 211 212
 * 	I1'		..	  ..	     ..	     ..	       ..           -						0
 * 	I3		..	  ..	     ..	     ..	       ..           -						0,1
 * 	I4		..	  ..	     ..	     ..	       ..           pk2=B1	 				0
213
 *-------------------------------------------------------------------------
214 215 216 217
 */
LogicalIndexes *
BuildLogicalIndexInfo(Oid relid)
{
A
Ashwin Agrawal 已提交
218 219
	MemoryContext callerContext = NULL;
	MemoryContext partContext = NULL;
220 221 222 223 224 225
	LogicalIndexes *partsLogicalIndexes = NULL;
	HASH_SEQ_STATUS hash_seq;
	LogicalIndexInfoHashEntry *entry;
	PartitionIndexNode *n = NULL;

	/*
A
Ashwin Agrawal 已提交
226 227
	 * create a memory context to hold allocations, so we can get rid of at
	 * the end of this function.
228 229
	 */
	partContext = AllocSetContextCreate(CurrentMemoryContext,
A
Ashwin Agrawal 已提交
230 231 232 233
										"Partitioned Logical Index Context",
										ALLOCSET_DEFAULT_MINSIZE,
										ALLOCSET_DEFAULT_INITSIZE,
										ALLOCSET_DEFAULT_MAXSIZE);
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

	/* switch to the new context */
	callerContext = MemoryContextSwitchTo(partContext);

	/* initialize globals */
	logicalIndexId = 1;
	numLogicalIndexes = 0;
	numIndexesOnDefaultParts = 0;

	/* construct the partition node tree */
	getPartitionIndexNode(relid, 0, InvalidOid, &n, false, NIL);

	if (!n)
		return NULL;

	/* create the hash tables to hold the logical index info */
	createIndexHashTables();
A
Ashwin Agrawal 已提交
251

252 253

	/* now walk the tree and annotate with logical index id at each leaf */
254
	recordIndexes(&n);
255 256 257

	hash_freeze(LogicalIndexInfoHash);

A
Ashwin Agrawal 已提交
258 259 260 261
	/*
	 * get rid of first hash table here as we have identified all logical
	 * indexes
	 */
262
	hash_destroy(PartitionIndexHash);
A
Ashwin Agrawal 已提交
263

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
	/* walk the tree and pull-up indexes for each logical index */
	hash_seq_init(&hash_seq, LogicalIndexInfoHash);
	while ((entry = hash_seq_search(&hash_seq)))
	{
		collapseIndexes(&n, &entry);
		numLogicalIndexes++;
	}

	dumpPartsIndexInfo(n, 0);

	/* associate index with parts */
	indexParts(&n, false);

	/* switch to caller context and handle results */
	MemoryContextSwitchTo(callerContext);

	/* generate output rows */
A
Ashwin Agrawal 已提交
281
	if ((numLogicalIndexes + numIndexesOnDefaultParts) > 0)
282 283 284 285 286 287
		partsLogicalIndexes = createPartsIndexResult(relid);

	hash_destroy(LogicalIndexInfoHash);

	/* all information has been copied into caller context */
	MemoryContextDelete(partContext);
A
Ashwin Agrawal 已提交
288

289 290 291
	return partsLogicalIndexes;
}

A
Ashwin Agrawal 已提交
292
/*
293 294
 * getPartitionIndexNode
 *   Construct a PartitionIndexNode tree for the given part.
A
Ashwin Agrawal 已提交
295
 *   Recurs to construct branches.
296 297 298
 */
static void
getPartitionIndexNode(Oid rootOid,
299
					  int16 level,
A
Ashwin Agrawal 已提交
300 301 302 303
					  Oid parent,
					  PartitionIndexNode **n,
					  bool isDefault,
					  List *defaultLevels)
304 305
{
	HeapTuple	tuple;
306 307
	ScanKeyData scankey[3];
	SysScanDesc sscan;
308 309
	Relation	partRel;
	Relation	partRuleRel;
A
Ashwin Agrawal 已提交
310 311
	Oid			parOid;
	bool		inctemplate = false;
312 313
	Oid			parrelid;
	int			parlevel;
314 315 316

	if (Gp_role != GP_ROLE_DISPATCH)
		return;
A
Ashwin Agrawal 已提交
317 318 319 320

	/*
	 * select oid as partid, * from pg_partition where parrelid = :relid and
	 * parlevel = :level and paristemplate = false;
321 322 323
	 */
	partRel = heap_open(PartitionRelationId, AccessShareLock);

324 325 326 327 328 329 330 331 332 333 334 335 336 337
	ScanKeyInit(&scankey[0],
				Anum_pg_partition_parrelid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(rootOid));
	ScanKeyInit(&scankey[1],
				Anum_pg_partition_parlevel,
				BTEqualStrategyNumber, F_INT2EQ,
				Int16GetDatum(level));
	ScanKeyInit(&scankey[2],
				Anum_pg_partition_paristemplate,
				BTEqualStrategyNumber, F_BOOLEQ,
				BoolGetDatum(inctemplate));

	sscan = systable_beginscan(partRel, PartitionParrelidParlevelParistemplateIndexId, true,
338
							   NULL, 3, scankey);
339
	tuple = systable_getnext(sscan);
340

341 342 343
	if (HeapTupleIsValid(tuple))
	{
		parOid = HeapTupleGetOid(tuple);
344 345 346
		Form_pg_partition partDesc = (Form_pg_partition) GETSTRUCT(tuple);
		parrelid = partDesc->parrelid;
		parlevel = partDesc->parlevel;
347 348 349 350 351 352 353 354 355

		if (level == 0)
		{
			Assert(parent == InvalidOid);
			Assert(*n == NULL);

			/* handle root part specially */
			*n = palloc0(sizeof(PartitionIndexNode));
			(*n)->paroid = parOid;
356
			(*n)->parrelid = (*n)->parchildrelid = parrelid;
357 358
			(*n)->isDefault = false;
		}
359
		systable_endscan(sscan);
360 361 362 363
		heap_close(partRel, AccessShareLock);
	}
	else
	{
364
		systable_endscan(sscan);
365 366 367 368 369 370 371
		heap_close(partRel, AccessShareLock);
		return;
	}

	/* recurse to fill the children */
	partRuleRel = heap_open(PartitionRuleRelationId, AccessShareLock);

A
Ashwin Agrawal 已提交
372 373 374 375
	/*
	 * SELECT * FROM pg_partition_rule WHERE paroid = :1 AND parparentrule =
	 * :2
	 */
376 377 378 379 380 381 382 383 384
	ScanKeyInit(&scankey[0],
				Anum_pg_partition_rule_paroid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(parOid));
	ScanKeyInit(&scankey[1],
				Anum_pg_partition_rule_parparentrule,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(parent));
	sscan = systable_beginscan(partRuleRel, PartitionRuleParoidParparentruleParruleordIndexId, true,
385
							   NULL, 2, scankey);
386 387 388
	while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
	{
		PartitionIndexNode *child;
A
Ashwin Agrawal 已提交
389 390
		Form_pg_partition_rule rule_desc = (Form_pg_partition_rule) GETSTRUCT(tuple);

391 392 393
		child = palloc(sizeof(PartitionIndexNode));
		memset(child, 0, sizeof(PartitionIndexNode));
		child->paroid = HeapTupleGetOid(tuple);
394
		child->parrelid = parrelid;
395 396
		child->parchildrelid = rule_desc->parchildrelid;

A
Ashwin Agrawal 已提交
397 398 399 400
		/*
		 * For every node, we keep track of every level at which this node has
		 * default partitioning
		 */
401 402 403 404 405 406 407
		child->isDefault = isDefault;
		child->defaultLevels = defaultLevels;

		/* current part is a default part */
		if (rule_desc->parisdefault)
		{
			child->isDefault = true;
408
			child->defaultLevels = lappend_int(child->defaultLevels, parlevel);
409 410 411 412 413 414
		}

		/* insert child into children */
		(*n)->children = lappend((*n)->children, child);

		getPartitionIndexNode(rootOid, level + 1, HeapTupleGetOid(tuple),
A
Ashwin Agrawal 已提交
415
							  &child, child->isDefault, child->defaultLevels);
416 417
	}

418
	systable_endscan(sscan);
419 420 421
	heap_close(partRuleRel, AccessShareLock);
}

A
Ashwin Agrawal 已提交
422
/*
423 424 425 426 427
 * constructIndexHashKey
 *   The index hash key is a string representing the index key,
 *   index predicate, and index exprs
 *
 *   Note, all attnums are mapped to the root.
A
Ashwin Agrawal 已提交
428
 */
429 430
static char *
constructIndexHashKey(Oid partOid,
A
Ashwin Agrawal 已提交
431 432 433 434
					  Oid rootOid,
					  AttrNumber *attMap,
					  IndexInfo *ii,
					  LogicalIndexType indType)
435
{
A
Ashwin Agrawal 已提交
436 437 438 439
	StringInfoData buf;
	Expr	   *predExpr = NULL;
	Expr	   *exprsExpr = NULL;

440 441 442 443 444 445 446 447 448 449
	initStringInfo(&buf);

	/* map the attrnos in the indKey to root part */
	for (int i = 0; i < ii->ii_NumIndexAttrs; i++)
	{
		if (attMap && ii->ii_KeyAttrNumbers[i] != 0)
		{
			ii->ii_KeyAttrNumbers[i] = attMap[(ii->ii_KeyAttrNumbers[i]) - 1];
		}
		appendStringInfo(&buf, "%d", ii->ii_KeyAttrNumbers[i]);
A
Ashwin Agrawal 已提交
450
	}
451 452

	/* map the attrnos in indPred */
A
Ashwin Agrawal 已提交
453 454 455
	predExpr = (Expr *) ii->ii_Predicate;

	change_varattnos_of_a_node((Node *) predExpr, attMap);
456 457 458 459

	appendStringInfo(&buf, "%s", nodeToString(predExpr));

	/* remember mapped predicate */
A
Ashwin Agrawal 已提交
460
	ii->ii_Predicate = (List *) predExpr;
461

A
Ashwin Agrawal 已提交
462
	exprsExpr = (Expr *) ii->ii_Expressions;
463

A
Ashwin Agrawal 已提交
464
	change_varattnos_of_a_node((Node *) exprsExpr, attMap);
465 466 467 468 469

	appendStringInfo(&buf, "%s", nodeToString(exprsExpr));
	appendStringInfo(&buf, "%d", (int) indType);

	/* remember mapped exprsList */
A
Ashwin Agrawal 已提交
470
	ii->ii_Expressions = (List *) exprsExpr;
471 472

	return buf.data;
A
Ashwin Agrawal 已提交
473
}
474

A
Ashwin Agrawal 已提交
475
/*
476
 * createIndexHashTables
A
Ashwin Agrawal 已提交
477
 *  create the hash tables to hold logical indexes
478 479 480 481
 */
static void
createIndexHashTables()
{
A
Ashwin Agrawal 已提交
482
	MemoryContext context = NULL;
483 484
	HASHCTL		hash_ctl;

A
Ashwin Agrawal 已提交
485 486 487 488
	/*
	 * this hash is to identify the logical indexes. 1 logical index
	 * corresponds to multiple physical indexes which have the same indkey +
	 * indpred + indexprs
489 490 491 492 493 494 495 496 497
	 */
	memset(&hash_ctl, 0, sizeof(hash_ctl));
	hash_ctl.keysize = sizeof(char *);
	hash_ctl.entrysize = sizeof(PartitionIndexHashEntry);
	hash_ctl.hash = key_string_hash;
	hash_ctl.match = key_string_compare;
	hash_ctl.keycopy = key_string_copy;
	hash_ctl.hcxt = context;
	PartitionIndexHash = hash_create("Partition Index Hash",
A
Ashwin Agrawal 已提交
498 499 500 501 502
									 INITIAL_NUM_LOGICAL_INDEXES_ESTIMATE,
									 &hash_ctl,
									 HASH_ELEM | HASH_FUNCTION |
									 HASH_COMPARE | HASH_KEYCOPY |
									 HASH_CONTEXT);
503 504 505

	Assert(PartitionIndexHash != NULL);

A
Ashwin Agrawal 已提交
506
	/* this hash is used to hold the logical indexes for easy lookup */
507 508 509 510 511 512
	memset(&hash_ctl, 0, sizeof(hash_ctl));
	hash_ctl.keysize = sizeof(uint32);
	hash_ctl.entrysize = sizeof(LogicalIndexInfoHashEntry);
	hash_ctl.hash = tag_hash;
	hash_ctl.hcxt = context;
	LogicalIndexInfoHash = hash_create("Logical Index Info Hash",
A
Ashwin Agrawal 已提交
513 514 515
									   INITIAL_NUM_LOGICAL_INDEXES_ESTIMATE,
									   &hash_ctl,
									   HASH_ELEM | HASH_FUNCTION);
516 517 518 519 520 521 522 523
	Assert(LogicalIndexInfoHash != NULL);
}

/*
 * recordIndexes
 *   Invoke the recordIndexesOnPart routine on every leaf partition.
 */
static void
524
recordIndexes(PartitionIndexNode **partIndexTree)
525
{
A
Ashwin Agrawal 已提交
526
	ListCell   *lc;
527 528 529 530
	PartitionIndexNode *partIndexNode = *partIndexTree;

	if (partIndexNode->children)
	{
A
Ashwin Agrawal 已提交
531
		foreach(lc, partIndexNode->children)
532 533
		{
			PartitionIndexNode *child = (PartitionIndexNode *) lfirst(lc);
A
Ashwin Agrawal 已提交
534

535
			recordIndexes(&child);
536 537
		}
	}
A
Ashwin Agrawal 已提交
538
	else
539
		/* at a leaf */
A
Ashwin Agrawal 已提交
540 541 542
		recordIndexesOnLeafPart(partIndexTree,
								partIndexNode->parchildrelid,
								partIndexNode->parrelid);
543 544 545
}

/*
A
Ashwin Agrawal 已提交
546
 * recordIndexesOnLeafPart
547 548 549 550 551 552 553 554 555 556 557
 *   Given a part
 * 	- fetch each index on the part from pg_index
 *	- map attnums in index key, index expr, index pred to the root attnums
 *	- insert the logical index into the PartitionIndexHash using the
 *		index key, index exprs, index pred as hash  key.
 *	- fetch the associated logical index id from the hash and record it in the tree.
 *	- insert the logical index into the LogicalIndexInfo Hash using the logical index id
 * 	  as the hash key.
 */
static void
recordIndexesOnLeafPart(PartitionIndexNode **pNodePtr,
A
Ashwin Agrawal 已提交
558 559
						Oid partOid,
						Oid rootOid)
560
{
A
Ashwin Agrawal 已提交
561 562 563 564 565 566 567 568 569 570
	char	   *partIndexHashKey;
	bool		foundPartIndexHash;
	bool		foundLogicalIndexHash;
	AttrNumber *attmap = NULL;
	struct IndexInfo *ii = NULL;
	PartitionIndexHashEntry *partIndexHashEntry;
	LogicalIndexInfoHashEntry *logicalIndexInfoHashEntry;
	PartitionIndexNode *pNode = *pNodePtr;
	List	   *indexoidlist;
	ListCell   *lc;
571

A
Ashwin Agrawal 已提交
572
	Relation	partRel = heap_open(partOid, AccessShareLock);
573

A
Ashwin Agrawal 已提交
574
	char		relstorage = partRel->rd_rel->relstorage;
575 576

	/* fetch each index on part */
577 578
	indexoidlist = RelationGetIndexList(partRel);
	foreach(lc, indexoidlist)
579
	{
580
		Oid			indexoid = lfirst_oid(lc);
581
		LogicalIndexType indType = INDTYPE_BITMAP;
A
Ashwin Agrawal 已提交
582
		Relation	indRel;
583 584 585 586 587 588 589

		/*
		 * We're holding a lock on the table. We assume that's enough to
		 * prevent concurrent DDL on the index.
		 */
		indRel = index_open(indexoid, NoLock);

590 591 592 593 594
		if (GIN_AM_OID == indRel->rd_rel->relam)
		{
			indType = INDTYPE_GIN;
		}
		else if (GIST_AM_OID == indRel->rd_rel->relam)
595
		{
A
Ashuka Xue 已提交
596 597 598 599 600 601 602 603 604
			indType = INDTYPE_GIST;
		}
		else if (RELSTORAGE_HEAP == relstorage && BTREE_AM_OID == indRel->rd_rel->relam)
		{
			/*
			 * we only send btree indexes as type btree if it is a normal heap table,
			 * AO and AOCO tables with btree indexes are sent as type bitmap
			 */
			indType = INDTYPE_BTREE;
605 606
		}

A
Ashuka Xue 已提交
607
		/* 
608 609 610 611 612
		 * when constructing hash key, we need to map attnums in part indexes
		 * to root attnums. Get the attMap needed for mapping.
		 */
		if (!attmap)
		{
A
Ashwin Agrawal 已提交
613 614 615 616
			Relation	rootRel = heap_open(rootOid, AccessShareLock);

			TupleDesc	rootTupDesc = rootRel->rd_att;
			TupleDesc	partTupDesc = partRel->rd_att;
617 618

			attmap = varattnos_map(partTupDesc, rootTupDesc);
A
Ashwin Agrawal 已提交
619

620 621 622 623 624
			/* can we close here ? */
			heap_close(rootRel, AccessShareLock);
		}

		/* populate index info structure */
625 626 627 628
		ii = populateIndexInfo(indRel);

		index_close(indRel, NoLock);

629
		/* construct hash key for the index */
630
		partIndexHashKey = constructIndexHashKey(partOid, rootOid, attmap, ii, indType);
631 632

		/* lookup PartitionIndexHash table */
A
Ashwin Agrawal 已提交
633 634 635 636
		partIndexHashEntry = (PartitionIndexHashEntry *) hash_search(PartitionIndexHash,
																	 (void *) partIndexHashKey,
																	 HASH_ENTER,
																	 &foundPartIndexHash);
637 638 639 640 641 642 643 644

		if (!foundPartIndexHash)
		{
			/* first time seeing this index */
			partIndexHashEntry->key = partIndexHashKey;

			/* assign a logical index id */
			partIndexHashEntry->logicalIndexId = logicalIndexId++;
A
Ashwin Agrawal 已提交
645 646 647 648 649 650 651 652 653

			/*
			 * insert the entry into LogicalIndexInfoHash to keep track of
			 * logical indexes
			 */
			logicalIndexInfoHashEntry = (LogicalIndexInfoHashEntry *) hash_search(LogicalIndexInfoHash,
																				  (void *) &(partIndexHashEntry->logicalIndexId),
																				  HASH_ENTER,
																				  &foundLogicalIndexHash);
654 655 656 657


			if (foundLogicalIndexHash)
			{
A
Ashwin Agrawal 已提交
658 659 660
				/*
				 * we should not find the entry in the logical index hash as
				 * this is the first time we are seeing it
661
				 */
662 663 664 665
				ereport(ERROR,
						(errcode(ERRCODE_INTERNAL_ERROR),
						 errmsg("error during BuildLogicalIndexInfo. Found indexrelid \"%d\" in hash",
								indexoid
A
Ashwin Agrawal 已提交
666
								)));
667 668 669
			}

			logicalIndexInfoHashEntry->logicalIndexId = partIndexHashEntry->logicalIndexId;
670
			logicalIndexInfoHashEntry->logicalIndexOid = indexoid;
671 672 673 674 675 676 677
			logicalIndexInfoHashEntry->ii = ii;
			logicalIndexInfoHashEntry->partList = NIL;
			logicalIndexInfoHashEntry->defaultPartList = NIL;
			logicalIndexInfoHashEntry->indType = indType;
		}
		else
		{
A
Ashwin Agrawal 已提交
678 679 680 681
			/*
			 * we can release IndexInfo as we already have the information in
			 * the hash
			 */
682 683 684 685 686 687 688 689 690 691 692
			if (ii->ii_Expressions)
				pfree(ii->ii_Expressions);
			if (ii->ii_Predicate)
				pfree(ii->ii_Predicate);
			pfree(ii);
		}


		/* update the PartitionIndexNode -> index bitmap */
		pNode->index = bms_add_member(pNode->index, partIndexHashEntry->logicalIndexId);
	}
693 694

	heap_close(partRel, AccessShareLock);
695 696 697 698
}

/*
 * collapseIndexes
A
Ashwin Agrawal 已提交
699 700
 *   Walk the PartitionNode tree
 *	- For every node
701 702 703 704 705 706
 *		- If a logical index exists on all the children of the node, record the index
 *	  	  on the node and wipeout the index from the children
 *	- recurse up the tree to the root.
 */
static bool
collapseIndexes(PartitionIndexNode **partitionIndexNode,
A
Ashwin Agrawal 已提交
707
				LogicalIndexInfoHashEntry **entry)
708
{
A
Ashwin Agrawal 已提交
709 710
	ListCell   *lc,
			   *lc1;
711
	PartitionIndexNode *pn = *partitionIndexNode;
A
Ashwin Agrawal 已提交
712 713 714
	bool		exists = TRUE;
	int			lid = (*entry)->logicalIndexId;
	int			childStatus = TRUE;
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736

	if (pn->children)
	{
		foreach(lc, pn->children)
		{
			PartitionIndexNode *child = (PartitionIndexNode *) lfirst(lc);

			/* not a leaf, so check the children */
			exists = collapseIndexes(&child, entry);

			/* For every logical index we are traversing the WHOLE tree. */
			if (!exists)
			{
				/* there is a child that doesn't have the index */
				childStatus = FALSE;
			}
		}

		if (childStatus)
		{
			/* if index exists on every child, record in the parent */
			pn->index = bms_add_member(pn->index, lid);
A
Ashwin Agrawal 已提交
737

738
			/* remove the index from the children */
A
Ashwin Agrawal 已提交
739
			foreach(lc1, pn->children)
740 741
			{
				PartitionIndexNode *child = (PartitionIndexNode *) lfirst(lc1);
A
Ashwin Agrawal 已提交
742

743 744 745 746 747 748 749 750 751 752 753 754 755 756
				bms_del_member(child->index, lid);
			}
		}
	}
	else
	{
		/* a leaf - check if index exists */
		if (!bms_is_member(lid, pn->index))
			exists = FALSE;
	}

	return exists;
}

D
Daniel Gustafsson 已提交
757
/*
758 759 760
 * indexParts
 *   Walks the tree of nodes and for each logical index that exists on the node,
 *   records the node (partition id) with the logical index in the hash.
D
Daniel Gustafsson 已提交
761
 *   If the logical index exists on a default part, record some additional
762 763
 *   information to indentify the specific default part.
 *
D
Daniel Gustafsson 已提交
764
 *   This consolidates all the information regarding the logical index in the
765 766 767 768
 *   hash table. As we exit from the function we have a hash table with an entry
 *   for every logical index
 * 	logical index id -> (logicalIndexOid, IndexInfo, partList, defaultPartList)
 */
D
Daniel Gustafsson 已提交
769 770
static void
indexParts(PartitionIndexNode **np, bool isDefault)
771
{
A
Ashwin Agrawal 已提交
772 773 774 775
	LogicalIndexInfoHashEntry *entry;
	PartitionIndexNode *n = *np;
	bool		found;
	int			x;
776

777 778
	if (!n)
		return;
A
Ashwin Agrawal 已提交
779

780 781
	x = -1;
	while ((x = bms_next_member(n->index, x)) >= 0)
782
	{
D
Daniel Gustafsson 已提交
783
		entry = (LogicalIndexInfoHashEntry *) hash_search(LogicalIndexInfoHash,
A
Ashwin Agrawal 已提交
784
														  (void *) &x, HASH_FIND, &found);
785
		if (!found)
786
		{
D
Daniel Gustafsson 已提交
787 788
			ereport(ERROR,
					(errcode(ERRCODE_INTERNAL_ERROR),
A
Ashwin Agrawal 已提交
789 790
					 errmsg("error during BuildLogicalIndexInfo. Index not found \"%d\" in hash",
							x)));
791
		}
792

793 794
		if (n->isDefault || isDefault)
		{
D
Daniel Gustafsson 已提交
795
			/*
796
			 * We keep track of the default node in the PartitionIndexNode
A
Ashwin Agrawal 已提交
797 798
			 * tree, since we need to output the defaultLevels information to
			 * the caller.
799 800
			 */
			entry->defaultPartList = lappend(entry->defaultPartList, n);
D
Daniel Gustafsson 已提交
801
			numIndexesOnDefaultParts++;
802
		}
803
		else
804
		{
D
Daniel Gustafsson 已提交
805
			/*
A
Ashwin Agrawal 已提交
806 807
			 * For regular non-default parts we just track the part oid which
			 * will be used to get the part constraint.
D
Daniel Gustafsson 已提交
808
			 */
809
			entry->partList = lappend_oid(entry->partList, n->parchildrelid);
810
		}
811 812 813 814
	}

	if (n->children)
	{
A
Ashwin Agrawal 已提交
815 816 817
		ListCell   *lc;

		foreach(lc, n->children)
818 819
		{
			PartitionIndexNode *child = (PartitionIndexNode *) lfirst(lc);
A
Ashwin Agrawal 已提交
820

821 822 823 824 825 826 827 828 829 830 831 832 833 834
			indexParts(&child, n->isDefault);
		}
	}
}

/*
 * getPartConstraints
 *   Given an OID, returns a Node that represents all the check constraints
 *   on the table AND'd together, only if these constraints cover the keys in
 *   the given list. Otherwise, it returns NULL
 */
static Node *
getPartConstraints(Oid partOid, Oid rootOid, List *partKey)
{
835 836
	ScanKeyData scankey;
	SysScanDesc sscan;
A
Ashwin Agrawal 已提交
837 838 839 840 841 842 843 844 845 846
	Relation	conRel;
	HeapTuple	conTup;
	Node	   *conExpr;
	Node	   *result = NULL;
	Datum		conBinDatum;
	Datum		conKeyDatum;
	char	   *conBin;
	bool		conbinIsNull = false;
	bool		conKeyIsNull = false;
	AttrMap    *map;
847 848

	/* create the map needed for mapping attnums */
A
Ashwin Agrawal 已提交
849 850
	Relation	rootRel = heap_open(rootOid, AccessShareLock);
	Relation	partRel = heap_open(partOid, AccessShareLock);
851

A
Ashwin Agrawal 已提交
852
	map_part_attrs(partRel, rootRel, &map, false);
853 854 855 856 857 858 859

	heap_close(rootRel, AccessShareLock);
	heap_close(partRel, AccessShareLock);

	/* Fetch the pg_constraint row. */
	conRel = heap_open(ConstraintRelationId, AccessShareLock);

860 861 862 863 864
	ScanKeyInit(&scankey,
				Anum_pg_constraint_conrelid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(partOid));
	sscan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
865
							   NULL, 1, &scankey);
866

A
Ashwin Agrawal 已提交
867 868
	/* list of keys referenced in the found constraints */
	List	   *keys = NIL;
869

870
	while (HeapTupleIsValid(conTup = systable_getnext(sscan)))
871
	{
A
Ashwin Agrawal 已提交
872 873 874 875
		/*
		 * we defer the filter on contype to here in order to take advantage
		 * of the index on conrelid
		 */
876
		Form_pg_constraint conEntry = (Form_pg_constraint) GETSTRUCT(conTup);
A
Ashwin Agrawal 已提交
877

878 879 880 881 882 883
		if (conEntry->contype != 'c')
		{
			continue;
		}
		/* Fetch the constraint expression in parsetree form */
		conBinDatum = heap_getattr(conTup, Anum_pg_constraint_conbin,
A
Ashwin Agrawal 已提交
884
								   RelationGetDescr(conRel), &conbinIsNull);
885

A
Ashwin Agrawal 已提交
886
		Assert(!conbinIsNull);
887 888 889 890 891 892
		/* map the attnums in constraint expression to root attnums */
		conBin = TextDatumGetCString(conBinDatum);
		conExpr = stringToNode(conBin);
		conExpr = attrMapExpr(map, conExpr);

		if (result)
A
Ashwin Agrawal 已提交
893
			result = (Node *) make_andclause(list_make2(result, conExpr));
894 895 896
		else
			result = conExpr;

A
Ashwin Agrawal 已提交
897
		/* fetch the key associated with this constraint */
898
		conKeyDatum = heap_getattr(conTup, Anum_pg_constraint_conkey,
A
Ashwin Agrawal 已提交
899 900 901
								   RelationGetDescr(conRel), &conKeyIsNull);
		Datum	   *dats = NULL;
		int			numKeys = 0;
902

A
Ashwin Agrawal 已提交
903
		/* extract key elements */
904 905 906
		deconstruct_array(DatumGetArrayTypeP(conKeyDatum), INT2OID, 2, true, 's', &dats, NULL, &numKeys);
		for (int i = 0; i < numKeys; i++)
		{
A
Ashwin Agrawal 已提交
907 908
			int16		key_elem = DatumGetInt16(dats[i]);

909 910 911 912
			keys = lappend_int(keys, key_elem);
		}
	}

913
	systable_endscan(sscan);
914 915
	heap_close(conRel, AccessShareLock);

A
Ashwin Agrawal 已提交
916 917 918
	ListCell   *lc = NULL;

	foreach(lc, partKey)
919
	{
A
Ashwin Agrawal 已提交
920
		int			partKeyCol = lfirst_int(lc);
921

922
		if (!list_member_int(keys, partKeyCol))
923
		{
A
Ashwin Agrawal 已提交
924
			/* passed in key is not found in the constraint. return NULL */
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
			if (NULL != result)
			{
				pfree(result);
			}

			result = NULL;
			break;
		}
	}

	if (map)
	{
		pfree(map);
	}
	list_free(keys);
	return result;
}

/*
 * get_relation_part_constraints
 *  return the part constraints for a partitioned table given the oid of the root
 */
Node *
get_relation_part_constraints(Oid rootOid, List **defaultLevels)
{
	if (!rel_is_partitioned(rootOid))
	{
		return NULL;
	}

A
Ashwin Agrawal 已提交
955 956 957 958 959
	/* get number of partitioning levels */
	List	   *partkeys = rel_partition_keys_ordered(rootOid);
	int			nLevels = list_length(partkeys);

	Node	   *allCons = NULL;
960 961 962

	for (int level = 0; level < nLevels; level++)
	{
A
Ashwin Agrawal 已提交
963
		List	   *partKey = (List *) list_nth(partkeys, level);
964

A
Ashwin Agrawal 已提交
965
		PartitionNode *pn = get_parts(rootOid, level, 0 /* parent */ , false /* inctemplate */ , false /* includesubparts */ );
966 967

		Assert(NULL != pn);
A
Ashwin Agrawal 已提交
968 969 970 971
		List	   *partOids = all_partition_relids(pn);

		Node	   *partCons = NULL;
		ListCell   *lc = NULL;
972 973 974

		foreach(lc, partOids)
		{
A
Ashwin Agrawal 已提交
975 976 977
			Oid			partOid = lfirst_oid(lc);

			/* fetch part constraint mapped to root */
978 979 980 981
			partCons = getPartConstraints(partOid, rootOid, partKey);

			if (NULL == partCons)
			{
A
Ashwin Agrawal 已提交
982
				/* default partition has NULL constriant in GPDB's catalog */
983 984 985 986
				*defaultLevels = lappend_int(*defaultLevels, level);
				continue;
			}

A
Ashwin Agrawal 已提交
987
			/* OR them to current constraints */
988 989 990 991 992 993 994 995 996 997 998 999 1000
			if (NULL == allCons)
			{
				allCons = partCons;
			}
			else
			{
				allCons = (Node *) mergeIntervals(allCons, partCons);
			}
		}
	}

	if (NULL == allCons)
	{
A
Ashwin Agrawal 已提交
1001
		allCons = makeBoolConst(false /* value */ , false /* isnull */ );
1002 1003 1004 1005 1006 1007 1008 1009
	}

	list_free(partkeys);
	return allCons;
}

/*
 * populateIndexInfo
A
Ashwin Agrawal 已提交
1010
 *  Populate the IndexInfo structure with the information from pg_index tuple.
1011 1012
 */
static IndexInfo *
1013
populateIndexInfo(Relation indRel)
1014
{
A
Ashwin Agrawal 已提交
1015
	IndexInfo  *ii;
1016

A
Ashwin Agrawal 已提交
1017 1018 1019 1020 1021
	/*
	 * We could just call existing BuildIndexInfo here. But BuildIndexInfo
	 * needs to open each index, and populate the relcache entry for the index
	 * relation. We can get the information by just looking into pg_index
	 * tuple.
1022 1023 1024
	 */
	ii = makeNode(IndexInfo);

1025 1026
	ii->ii_Unique = indRel->rd_index->indisunique;
	ii->ii_NumIndexAttrs = indRel->rd_index->indnatts;
1027

1028
	for (int i = 0; i < indRel->rd_index->indnatts; i++)
1029
	{
1030
		ii->ii_KeyAttrNumbers[i] = indRel->rd_index->indkey.values[i];
1031 1032
	}

1033 1034
	ii->ii_Expressions = RelationGetIndexExpressions(indRel);
	ii->ii_Predicate = RelationGetIndexPredicate(indRel);
1035 1036 1037 1038

	return ii;
}

A
Ashwin Agrawal 已提交
1039
/*
1040 1041 1042 1043 1044 1045 1046
 * generateLogicalIndexPred
 *  generate the partial index predicate associated with each logical index.
 *  The predicate is generated by OR'ing the constraints of all parts on which the logical
 *  index exists.
 */
static void
generateLogicalIndexPred(LogicalIndexes *li,
A
Ashwin Agrawal 已提交
1047 1048 1049 1050
						 int *curIdx,
						 LogicalIndexInfoHashEntry *entry,
						 Oid root,
						 int *numLogicalIndexes)
1051
{
A
Ashwin Agrawal 已提交
1052 1053 1054
	Node	   *conList;
	ListCell   *lc;
	AttrNumber *indexKeys;
1055 1056 1057 1058 1059 1060 1061 1062

	if (list_length(entry->partList) > 0)
	{
		/* populate the index information */
		li->logicalIndexInfo[*curIdx]->partCons = NULL;
		li->logicalIndexInfo[*curIdx]->logicalIndexOid = entry->logicalIndexOid;
		li->logicalIndexInfo[*curIdx]->nColumns = entry->ii->ii_NumIndexAttrs;
		indexKeys = palloc(sizeof(AttrNumber) * entry->ii->ii_NumIndexAttrs);
A
Ashwin Agrawal 已提交
1063 1064 1065 1066 1067
		memcpy((char *) indexKeys,
			   &(entry->ii->ii_KeyAttrNumbers), sizeof(AttrNumber) * entry->ii->ii_NumIndexAttrs);
		li->logicalIndexInfo[*curIdx]->indexKeys = indexKeys;
		li->logicalIndexInfo[*curIdx]->indExprs = (List *) copyObject(entry->ii->ii_Expressions);
		li->logicalIndexInfo[*curIdx]->indPred = (List *) copyObject(entry->ii->ii_Predicate);
1068 1069 1070 1071 1072 1073
		li->logicalIndexInfo[*curIdx]->indIsUnique = entry->ii->ii_Unique;
		li->logicalIndexInfo[*curIdx]->indType = entry->indType;

		/* fetch the partList from the logical index hash entry */
		foreach(lc, entry->partList)
		{
A
Ashwin Agrawal 已提交
1074 1075
			Oid			partOid = lfirst_oid(lc);

1076
			if (partOid != root)
A
Ashwin Agrawal 已提交
1077
			{
1078
				/* fetch part constraint mapped to root */
A
Ashwin Agrawal 已提交
1079 1080
				conList = getPartConstraints(partOid, root, NIL /* partKey */ );

1081 1082 1083
				/* OR them to current constraints */
				if (li->logicalIndexInfo[*curIdx]->partCons)
				{
A
Ashwin Agrawal 已提交
1084
					li->logicalIndexInfo[*curIdx]->partCons = mergeIntervals(li->logicalIndexInfo[*curIdx]->partCons, conList);
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
				}
				else
				{
					li->logicalIndexInfo[*curIdx]->partCons = conList;
				}
			}
		}

		(*curIdx)++;
		(*numLogicalIndexes)++;
	}

	/* from the hash entry, fetch the defaultPartList */
	foreach(lc, entry->defaultPartList)
	{
A
Ashwin Agrawal 已提交
1100
		PartitionIndexNode *node = (PartitionIndexNode *) lfirst(lc);
1101 1102 1103 1104 1105 1106
		AttrNumber *indexKeys;

		li->logicalIndexInfo[*curIdx]->partCons = NULL;
		li->logicalIndexInfo[*curIdx]->logicalIndexOid = entry->logicalIndexOid;
		li->logicalIndexInfo[*curIdx]->nColumns = entry->ii->ii_NumIndexAttrs;
		indexKeys = palloc(sizeof(AttrNumber) * entry->ii->ii_NumIndexAttrs);
A
Ashwin Agrawal 已提交
1107 1108
		memcpy((char *) indexKeys,
			   &(entry->ii->ii_KeyAttrNumbers), sizeof(AttrNumber) * entry->ii->ii_NumIndexAttrs);
1109
		li->logicalIndexInfo[*curIdx]->indexKeys = indexKeys;
A
Ashwin Agrawal 已提交
1110 1111
		li->logicalIndexInfo[*curIdx]->indExprs = (List *) copyObject(entry->ii->ii_Expressions);
		li->logicalIndexInfo[*curIdx]->indPred = (List *) copyObject(entry->ii->ii_Predicate);
1112 1113 1114
		li->logicalIndexInfo[*curIdx]->indIsUnique = entry->ii->ii_Unique;
		li->logicalIndexInfo[*curIdx]->indType = entry->indType;

A
Ashwin Agrawal 已提交
1115
		/*
1116
		 * Default parts don't have constraints, so they cannot be represented
A
Ashwin Agrawal 已提交
1117 1118 1119 1120 1121 1122
		 * as part of the partial index predicate.
		 *
		 * Instead each index on a default part is represented as a different
		 * logical index. Since we need a way to identify the specific default
		 * part, we include the defaultLevels information, in addition to ANY
		 * constraint on the default part.
1123
		 */
A
Ashwin Agrawal 已提交
1124
		li->logicalIndexInfo[*curIdx]->partCons = getPartConstraints(node->parchildrelid, root, NIL /* partKey */ );
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134

		/* get the level on which partitioning key is default */
		li->logicalIndexInfo[*curIdx]->defaultLevels = list_copy(node->defaultLevels);
		(*curIdx)++;
		(*numLogicalIndexes)++;
	}
}

/*
 * createPartsIndexResult
A
Ashwin Agrawal 已提交
1135
 *  Populate the result array of logical indexes. Most of the information needed
1136 1137 1138 1139 1140 1141 1142
 *  is in the IndexInfoHash. The partial index predicate needs to be generated
 *  by a call to generateLogicalIndexPred.
 */
static LogicalIndexes *
createPartsIndexResult(Oid root)
{
	HASH_SEQ_STATUS hash_seq;
A
Ashwin Agrawal 已提交
1143
	int			numResultRows = 0;
1144 1145 1146 1147 1148
	LogicalIndexes *li;
	LogicalIndexInfoHashEntry *entry;

	hash_seq_init(&hash_seq, LogicalIndexInfoHash);

A
Ashwin Agrawal 已提交
1149 1150 1151 1152
	/*
	 * we allocate space for twice the number of logical indexes. this is
	 * because, every index on a default part will be returned as a separate
	 * index.
1153 1154 1155 1156 1157 1158 1159 1160
	 */
	numResultRows = numLogicalIndexes + numIndexesOnDefaultParts;

	li = (LogicalIndexes *) palloc0(sizeof(LogicalIndexes));

	li->numLogicalIndexes = 0;
	li->logicalIndexInfo = NULL;

A
Ashwin Agrawal 已提交
1161
	li->logicalIndexInfo = (LogicalIndexInfo **) palloc0(numResultRows * sizeof(LogicalIndexInfo *));
1162 1163

	/* should we limit the amount of memory being allocated here ? */
A
Ashwin Agrawal 已提交
1164 1165
	for (int i = 0; i < numResultRows; i++)
		li->logicalIndexInfo[i] = (LogicalIndexInfo *) palloc0(sizeof(LogicalIndexInfo));
1166

A
Ashwin Agrawal 已提交
1167
	int			curIdx = 0;
1168

A
Ashwin Agrawal 已提交
1169 1170 1171 1172
	/*
	 * for each logical index, get the part constraints as partial index
	 * predicates
	 */
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
	while ((entry = hash_seq_search(&hash_seq)))
	{
		generateLogicalIndexPred(li, &curIdx, entry, root, &li->numLogicalIndexes);
	}

	return li;
}

/*
 * getPhysicalIndexRelid
 *   This function returns the physical index relid corresponding
 *   to the index described by the logicalIndexInfo input structure
 *   in the relation identified by the partOid.
 *   The 1st matching index is returned.
A
Ashwin Agrawal 已提交
1187
 *
1188 1189 1190 1191
 * NOTE: index attnums in the provided logicalIndexInfo input structure
 * have to be mapped to the root.
 */
Oid
1192
getPhysicalIndexRelid(Relation partRel, LogicalIndexInfo *iInfo)
1193
{
A
Ashwin Agrawal 已提交
1194
	Oid			resultOid = InvalidOid;
1195
	bool		indKeyEqual;
1196 1197 1198
	List	   *indexoidlist;
	ListCell   *lc;
	Relation	indRel = NULL;
1199

1200 1201 1202
	/* fetch each index on partition */
	indexoidlist = RelationGetIndexList(partRel);
	foreach(lc, indexoidlist)
1203
	{
1204 1205
		Oid			indexoid = lfirst_oid(lc);
		Form_pg_index indForm;
1206

1207 1208
		if (indRel)
			index_close(indRel, NoLock);
1209

1210 1211 1212 1213 1214 1215
		/*
		 * We're holding a lock on the table. We assume that's enough to
		 * prevent concurrent DDL on the index.
		 */
		indRel = index_open(indexoid, NoLock);
		indForm = indRel->rd_index;
1216

1217
		if (indForm->indnatts != iInfo->nColumns)
1218 1219 1220 1221
			continue;

		/* compare indKey */
		indKeyEqual = true;
1222
		for (int i = 0; i < indForm->indnatts; i++)
1223
		{
1224
			if (indForm->indkey.values[i] != iInfo->indexKeys[i])
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
			{
				indKeyEqual = false;
				break;
			}
		}

		if (!indKeyEqual)
			continue;

		/* compare uniqueness attribute */
1235
		if (iInfo->indIsUnique != indForm->indisunique)
1236 1237 1238
			continue;

		/* compare indPred */
A
Ashwin Agrawal 已提交
1239 1240
		List	   *indPred = RelationGetIndexPredicate(indRel);

1241
		if (!equal(iInfo->indPred, indPred))
1242
			continue;
1243
		list_free(indPred);
1244 1245

		/* compare indExprs */
A
Ashwin Agrawal 已提交
1246 1247
		List	   *indExprs = RelationGetIndexExpressions(indRel);

1248
		if (equal(iInfo->indExprs, indExprs))
1249 1250 1251 1252 1253
		{
			/* found matching index */
			resultOid = indForm->indexrelid;
			break;
		}
1254
		list_free(indExprs);
A
Ashwin Agrawal 已提交
1255 1256

		/* TODO: antova - Mar 28, 2014; compare if this is a bitmap index */
1257 1258
	}

1259 1260
	if (indRel)
		index_close(indRel, NoLock);
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271

	return resultOid;
}

/*
 * dumpPartsIndexInfo
 *   print debugging info
 */
static void
dumpPartsIndexInfo(PartitionIndexNode *n, int level)
{
A
Ashwin Agrawal 已提交
1272 1273 1274
	ListCell   *lc;
	StringInfoData logicalIndexes;
	int			x;
D
Daniel Gustafsson 已提交
1275

1276 1277
	initStringInfo(&logicalIndexes);

1278 1279
	if (!n)
		return;
1280

1281 1282
	for (int i = 0; i <= level; i++)
		appendStringInfo(&logicalIndexes, "%s", "   ");
1283

1284
	appendStringInfo(&logicalIndexes, "%d ", n->parchildrelid);
1285

1286
	appendStringInfo(&logicalIndexes, "%s ", " (");
1287

1288 1289
	x = -1;
	while ((x = bms_next_member(n->index, x)) >= 0)
1290
		appendStringInfo(&logicalIndexes, "%d ", x);
1291

1292 1293 1294
	appendStringInfo(&logicalIndexes, "%s ", " )");

	elog(DEBUG5, "%s", logicalIndexes.data);
1295 1296 1297

	if (n->children)
	{
A
Ashwin Agrawal 已提交
1298
		foreach(lc, n->children)
1299 1300
		{
			PartitionIndexNode *child = (PartitionIndexNode *) lfirst(lc);
A
Ashwin Agrawal 已提交
1301 1302

			dumpPartsIndexInfo(child, level + 1);
1303 1304 1305 1306 1307 1308 1309 1310 1311
			appendStringInfo(&logicalIndexes, "     ");
		}
	}
}

/*
 * 	mergeIntervals
 *   merge the two intervals by creating a disjunction of the given intervals, or collapsing
 *   them into one interval when possible
A
Ashwin Agrawal 已提交
1312
 *
1313
 *   This function's arguments represent two range constraints, which the function attempts
A
Ashwin Agrawal 已提交
1314
 *   to collapse into one if they share a common boundary. If no collapse is possible,
1315 1316 1317 1318 1319
 *   the function returns a disjunction of the two intervals.
 */
static Node *
mergeIntervals(Node *intervalFst, Node *intervalSnd)
{
A
Ashwin Agrawal 已提交
1320 1321 1322 1323 1324
	Node	   *pnodeStart1 = NULL;
	Node	   *pnodeEnd1 = NULL;
	Node	   *pnodeStart2 = NULL;
	Node	   *pnodeEnd2 = NULL;

1325 1326
	extractStartEndRange(intervalFst, &pnodeStart1, &pnodeEnd1);
	extractStartEndRange(intervalSnd, &pnodeStart2, &pnodeEnd2);
A
Ashwin Agrawal 已提交
1327

1328 1329
	if (NULL != pnodeEnd1 && NULL != pnodeStart2)
	{
A
Ashwin Agrawal 已提交
1330 1331 1332 1333 1334 1335 1336 1337 1338
		OpExpr	   *opexprEnd1 = (OpExpr *) pnodeEnd1;
		OpExpr	   *opexprStart2 = (OpExpr *) pnodeStart2;
		Var		   *pvarEnd1 = NULL;
		Var		   *pvarStart2 = NULL;
		Const	   *pconstEnd1 = NULL;
		Const	   *pconstStart2 = NULL;
		Oid			opnoEnd1 = InvalidOid;
		Oid			opnoStart2 = InvalidOid;

1339 1340 1341
		/* extract boundaries of the two intervals */
		extractOpExprComponents(opexprEnd1, &pvarEnd1, &pconstEnd1, &opnoEnd1);
		extractOpExprComponents(opexprStart2, &pvarStart2, &pconstStart2, &opnoStart2);
A
Ashwin Agrawal 已提交
1342 1343 1344 1345 1346 1347
		if (InvalidOid != opnoEnd1 && InvalidOid != opnoStart2 &&
			equal(pvarEnd1, pvarStart2) && equal(pconstEnd1, pconstStart2) &&	/* middle point is the
																				 * same */
			opnoEnd1 == get_negator(opnoStart2) /* this guaranteed that the
												 * middle point is included in
												 * exactly 1 of the intervals */
1348 1349 1350 1351 1352 1353 1354
			)
		{
			if (NULL != pnodeStart1 && NULL != pnodeEnd2)
			{
				/* merge intervals of the form (x,y), [y, z) into (x,z) */
				return (Node *) make_andclause(list_make2(pnodeStart1, pnodeEnd2));
			}
A
Ashwin Agrawal 已提交
1355

1356 1357 1358
			if (NULL != pnodeStart1)
			{
				/* merge intervals of the form (x,y), [y, inf) into (x, inf) */
A
Ashwin Agrawal 已提交
1359 1360 1361 1362 1363
				Var		   *pvarStart1 = NULL;
				Const	   *pconstStart1 = NULL;
				Oid			opnoStart1 = InvalidOid;
				OpExpr	   *opexprStart1 = (OpExpr *) pnodeStart1;

1364
				extractOpExprComponents(opexprStart1, &pvarStart1, &pconstStart1, &opnoStart1);
A
Ashwin Agrawal 已提交
1365

A
Asim R P 已提交
1366 1367 1368 1369 1370 1371 1372
				return (Node *) make_opclause(opnoStart1,
											  opexprStart1->opresulttype,
											  opexprStart1->opretset,
											  (Expr *) pvarStart1,
											  (Expr *) pconstStart1,
											  opexprStart1->opcollid,
											  opexprStart1->inputcollid);
1373
			}
A
Ashwin Agrawal 已提交
1374

1375 1376 1377
			if (NULL != pnodeEnd2)
			{
				/* merge intervals of the form (-inf,x), [x, y) into (-inf, y) */
A
Ashwin Agrawal 已提交
1378 1379 1380 1381
				Var		   *pvarEnd2 = NULL;
				Const	   *pconstEnd2 = NULL;
				Oid			opnoEnd2 = InvalidOid;
				OpExpr	   *opexprEnd2 = (OpExpr *) pnodeEnd2;
1382 1383

				extractOpExprComponents(opexprEnd2, &pvarEnd2, &pconstEnd2, &opnoEnd2);
A
Ashwin Agrawal 已提交
1384

A
Asim R P 已提交
1385 1386 1387 1388 1389 1390 1391
				return (Node *) make_opclause(opnoEnd2,
											  opexprEnd2->opresulttype,
											  opexprEnd2->opretset,
											  (Expr *) pvarEnd2,
											  (Expr *) pconstEnd2,
											  opexprEnd2->opcollid,
											  opexprEnd2->inputcollid);
1392
			}
A
Ashwin Agrawal 已提交
1393

1394
			Assert(NULL == pnodeStart1 && NULL == pnodeEnd2);
A
Ashwin Agrawal 已提交
1395

1396
			/* merge (-inf, x), [x,inf) into true */
A
Ashwin Agrawal 已提交
1397 1398

			return (Node *) makeBoolConst(true /* value */ , false /* isnull */ );
1399 1400 1401 1402 1403 1404 1405
		}
	}
	return (Node *) make_orclause(list_make2(intervalFst, intervalSnd));
}

/*
 * extractStartEndRange
A
Ashwin Agrawal 已提交
1406
 *   Given an expression representing an interval constraint, extract the expressions defining the interval's start and end
1407
 */
A
Ashwin Agrawal 已提交
1408 1409
static void
extractStartEndRange(Node *clause, Node **ppnodeStart, Node **ppnodeEnd)
1410 1411 1412
{
	if (IsA(clause, OpExpr))
	{
A
Ashwin Agrawal 已提交
1413 1414
		OpExpr	   *opexpr = (OpExpr *) clause;
		Expr	   *pexprRight = list_nth(opexpr->args, 1);
1415
		CmpType		cmptype = get_comparison_type(opexpr->opno);
1416 1417 1418 1419 1420 1421

		if (CmptEq == cmptype)
		{
			*ppnodeStart = *ppnodeEnd = clause;
			return;
		}
A
Ashwin Agrawal 已提交
1422

1423 1424 1425 1426 1427 1428 1429
		if ((CmptLEq == cmptype || CmptLT == cmptype) && IsA(pexprRight, Const))
		{
			/* op expr of the form pk <= Const or pk < Const */
			*ppnodeStart = NULL;
			*ppnodeEnd = clause;
			return;
		}
A
Ashwin Agrawal 已提交
1430

1431 1432 1433 1434 1435 1436 1437 1438 1439
		if ((CmptGEq == cmptype || CmptGT == cmptype) && IsA(pexprRight, Const))
		{
			/* op expr of the form pk >= Const or pk > Const */
			*ppnodeEnd = NULL;
			*ppnodeStart = clause;
			return;
		}
	}

A
Ashwin Agrawal 已提交
1440 1441 1442 1443 1444 1445 1446 1447
	/*
	 * only expressions of the form x > C1 and x < C2 supported: ignore all
	 * other expression types
	 */

	if (!IsA(clause, BoolExpr) ||
		AND_EXPR != ((BoolExpr *) clause)->boolop ||
		2 < list_length(((BoolExpr *) clause)->args))
1448 1449 1450
	{
		return;
	}
A
Ashwin Agrawal 已提交
1451 1452 1453 1454 1455 1456 1457

	BoolExpr   *bool_expr = (BoolExpr *) clause;

	Node	   *nodeStart = list_nth(bool_expr->args, 0);
	Node	   *nodeEnd = list_nth(bool_expr->args, 1);

	if (!IsA(nodeStart, OpExpr) ||!IsA(nodeEnd, OpExpr))
1458 1459 1460
	{
		return;
	}
A
Ashwin Agrawal 已提交
1461 1462 1463 1464

	OpExpr	   *opexprStart = (OpExpr *) nodeStart;
	OpExpr	   *opexprEnd = (OpExpr *) nodeEnd;

1465 1466
	CmpType		cmptLeft = get_comparison_type(opexprStart->opno);
	CmpType		cmptRight = get_comparison_type(opexprEnd->opno);
A
Ashwin Agrawal 已提交
1467

1468 1469 1470 1471
	if ((CmptGT != cmptLeft && CmptGEq != cmptLeft) || (CmptLT != cmptRight && CmptLEq != cmptRight))
	{
		return;
	}
A
Ashwin Agrawal 已提交
1472

1473 1474 1475 1476 1477 1478 1479 1480
	*ppnodeStart = nodeStart;
	*ppnodeEnd = nodeEnd;
}

/*
 * extractOpExprComponents
 *   for an opexpr of type Var op Const, extract its components
 */
A
Ashwin Agrawal 已提交
1481 1482
static void
extractOpExprComponents(OpExpr *opexpr, Var **ppvar, Const **ppconst, Oid *opno)
1483
{
A
Ashwin Agrawal 已提交
1484 1485 1486 1487
	Node	   *pnodeLeft = list_nth(opexpr->args, 0);
	Node	   *pnodeRight = list_nth(opexpr->args, 1);

	if (IsA(pnodeLeft, Var) &&IsA(pnodeRight, Const))
1488 1489 1490 1491 1492
	{
		*ppvar = (Var *) pnodeLeft;
		*ppconst = (Const *) pnodeRight;
		*opno = opexpr->opno;
	}
A
Ashwin Agrawal 已提交
1493
	else if (IsA(pnodeLeft, Const) &&IsA(pnodeRight, Var) &&InvalidOid != get_commutator(opexpr->opno))
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
	{
		*ppvar = (Var *) pnodeRight;
		*ppconst = (Const *) pnodeLeft;
		*opno = get_commutator(opexpr->opno);
	}
}


/*
 * LogicalIndexInfoForIndexOid
 *   construct the logical index info for a given index oid
 */
1506 1507
LogicalIndexInfo *
logicalIndexInfoForIndexOid(Oid rootOid, Oid indexOid)
1508
{
1509
	Relation	indRel;
1510

1511
	indRel = index_open(indexOid, AccessShareLock);
1512

A
Ashwin Agrawal 已提交
1513 1514 1515 1516 1517 1518
	IndexInfo  *pindexInfo = populateIndexInfo(indRel);
	Oid			partOid = indRel->rd_index->indrelid;

	/* remap attributes */
	Relation	rootRel = heap_open(rootOid, AccessShareLock);
	Relation	partRel = heap_open(partOid, AccessShareLock);
1519

A
Ashwin Agrawal 已提交
1520 1521
	TupleDesc	rootTupDesc = rootRel->rd_att;
	TupleDesc	partTupDesc = partRel->rd_att;
1522

A
Ashwin Agrawal 已提交
1523 1524
	char		relstorage = partRel->rd_rel->relstorage;
	AttrNumber *attMap = varattnos_map(rootTupDesc, partTupDesc);
1525 1526 1527

	heap_close(rootRel, AccessShareLock);
	heap_close(partRel, AccessShareLock);
A
Ashwin Agrawal 已提交
1528 1529

	/* populate the index information */
1530
	LogicalIndexInfo *plogicalIndexInfo = (LogicalIndexInfo *) palloc0(sizeof(LogicalIndexInfo));
A
Ashwin Agrawal 已提交
1531

1532 1533 1534
	plogicalIndexInfo->nColumns = pindexInfo->ii_NumIndexAttrs;
	plogicalIndexInfo->indIsUnique = pindexInfo->ii_Unique;
	plogicalIndexInfo->logicalIndexOid = indexOid;
A
Ashwin Agrawal 已提交
1535 1536 1537

	int			numIndexKeys = pindexInfo->ii_NumIndexAttrs;

1538
	plogicalIndexInfo->indexKeys = palloc(sizeof(AttrNumber) * numIndexKeys);
A
Ashwin Agrawal 已提交
1539
	memcpy((char *) plogicalIndexInfo->indexKeys, &(pindexInfo->ii_KeyAttrNumbers), sizeof(AttrNumber) * numIndexKeys);
1540 1541 1542

	plogicalIndexInfo->indExprs = copyObject(pindexInfo->ii_Expressions);
	plogicalIndexInfo->indPred = copyObject(pindexInfo->ii_Predicate);
A
Ashwin Agrawal 已提交
1543

1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
	/* remap expression fields */
	/* map the attrnos if necessary */
	if (attMap)
	{
		for (int i = 0; i < plogicalIndexInfo->nColumns; i++)
		{
			if (plogicalIndexInfo->indexKeys[i] != 0)
			{
				plogicalIndexInfo->indexKeys[i] = attMap[(plogicalIndexInfo->indexKeys[i]) - 1];
			}
		}
		change_varattnos_of_a_node((Node *) plogicalIndexInfo->indExprs, attMap);
		change_varattnos_of_a_node((Node *) plogicalIndexInfo->indPred, attMap);
	}
A
Ashwin Agrawal 已提交
1558

1559
	plogicalIndexInfo->indType = INDTYPE_BITMAP;
1560 1561 1562 1563 1564
	if (GIN_AM_OID == indRel->rd_rel->relam)
	{
		plogicalIndexInfo->indType = INDTYPE_GIN;
	}
	else if (GIST_AM_OID == indRel->rd_rel->relam)
1565
	{
A
Ashuka Xue 已提交
1566 1567 1568 1569 1570
		plogicalIndexInfo->indType = INDTYPE_GIST;
	}
	else if (RELSTORAGE_HEAP == relstorage && BTREE_AM_OID == indRel->rd_rel->relam)
	{
		plogicalIndexInfo->indType = INDTYPE_BTREE;
1571
	}
1572 1573 1574

	index_close(indRel, AccessShareLock);

1575 1576
	return plogicalIndexInfo;
}