cdbpartindex.c 43.3 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 28
#include "nodes/makefuncs.h"
#include "parser/parse_expr.h"
29
#include "utils/builtins.h"
30
#include "utils/fmgroids.h"
31 32 33 34 35 36
#include "utils/lsyscache.h"
#include "utils/memutils.h"

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

A
Ashwin Agrawal 已提交
37 38 39
static int	logicalIndexId = 1;
static int	numLogicalIndexes = 0;
static int	numIndexesOnDefaultParts = 0;
40

A
Ashwin Agrawal 已提交
41
/*
42 43 44 45 46 47 48 49
 * 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 已提交
50
/*
51
 * Hash entry for PartitionIndexHash
52 53
 * hashkey is (indexkey + indexpred + indexexprs)
 */
A
Ashwin Agrawal 已提交
54 55 56 57
typedef struct
{
	char	   *key;
	int			logicalIndexId;
58 59 60 61 62 63 64 65
} PartitionIndexHashEntry;

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

/*
 * Each node in the PartitionIndexNode tree describes a partition
 * and a list of it's logical indexes
 */
typedef struct PartitionIndexNode
{
A
Ashwin Agrawal 已提交
81 82 83 84 85 86 87 88
	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 */
89 90 91
} PartitionIndexNode;

static void recordIndexesOnLeafPart(PartitionIndexNode **pNodePtr,
A
Ashwin Agrawal 已提交
92
						Oid partOid, Oid rootOid);
93
static void recordIndexes(PartitionIndexNode **partIndexTree);
94
static void getPartitionIndexNode(Oid rootOid, int2 level,
A
Ashwin Agrawal 已提交
95 96
					  Oid parent, PartitionIndexNode **n,
					  bool isDefault, List *defaultLevels);
97 98
static void indexParts(PartitionIndexNode **np, bool isDefault);
static void dumpPartsIndexInfo(PartitionIndexNode *n, int level);
A
Ashwin Agrawal 已提交
99
static LogicalIndexes *createPartsIndexResult(Oid root);
100
static bool collapseIndexes(PartitionIndexNode **partitionIndexNode,
A
Ashwin Agrawal 已提交
101
				LogicalIndexInfoHashEntry **entry);
102
static void createIndexHashTables(void);
103
static IndexInfo *populateIndexInfo(Relation indRel);
104 105 106 107 108 109 110 111 112 113 114 115 116
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 已提交
117 118

	Assert(keysize == sizeof(char *));
119 120 121 122 123 124 125
	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 已提交
126 127
	Assert(keysize == sizeof(char *));
	return strcmp(((PartitionIndexHashEntry *) key1)->key, key2);
128 129 130 131 132 133
}

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

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

140
/*-------------------------------------------------------------------------
141 142 143 144 145 146 147 148
 * 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 已提交
149
 *
150
 *  This function does the following
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
 *	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 已提交
173
 *
174 175 176 177 178
 *	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 已提交
179
 *				Root
180 181 182 183 184 185 186 187 188 189 190 191 192 193
 *		  / 		|		\
 *		 /		|		 \
 *		/		|		  \
 *		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 已提交
194 195
 *		/		|		\
 * 	       /             	|		 \
196 197 198 199 200 201 202
 *   	    A1 (I1)		A2		default	(I1)
 *	 /      \            /      \            /     \
 *	/        \          /        \	 	/       \
 *     /          \	   /          \	       /         \
 *    B1         def   B1(I1)         def   B1(I4)    def(I3)
 *
 * The output returned from BuildLogicalIndexInfo will be
A
Ashwin Agrawal 已提交
203
 *
204 205
 * logicalIndexOid 	nColumns  indexKeys  indPred indExprs  indIsUnique  partCons   				defaultLevels
 * 	I2		..	  ..	     ..	     ..	       ..           -						-
A
Ashwin Agrawal 已提交
206
 * 	I1		..	  ..	     ..	     ..	       ..           pk1=A1 OR (pk1=A2 AND pk2=B1)		-
207 208 209
 * 	I1'		..	  ..	     ..	     ..	       ..           -						0
 * 	I3		..	  ..	     ..	     ..	       ..           -						0,1
 * 	I4		..	  ..	     ..	     ..	       ..           pk2=B1	 				0
210
 *-------------------------------------------------------------------------
211 212 213 214
 */
LogicalIndexes *
BuildLogicalIndexInfo(Oid relid)
{
A
Ashwin Agrawal 已提交
215 216
	MemoryContext callerContext = NULL;
	MemoryContext partContext = NULL;
217 218 219 220 221 222
	LogicalIndexes *partsLogicalIndexes = NULL;
	HASH_SEQ_STATUS hash_seq;
	LogicalIndexInfoHashEntry *entry;
	PartitionIndexNode *n = NULL;

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

	/* 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 已提交
248

249 250

	/* now walk the tree and annotate with logical index id at each leaf */
251
	recordIndexes(&n);
252 253 254

	hash_freeze(LogicalIndexInfoHash);

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

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
	/* 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 已提交
278
	if ((numLogicalIndexes + numIndexesOnDefaultParts) > 0)
279 280 281 282 283 284
		partsLogicalIndexes = createPartsIndexResult(relid);

	hash_destroy(LogicalIndexInfoHash);

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

286 287 288
	return partsLogicalIndexes;
}

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

	if (Gp_role != GP_ROLE_DISPATCH)
		return;
A
Ashwin Agrawal 已提交
313 314 315 316

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

320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
	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,
							   SnapshotNow, 3, scankey);
	tuple = systable_getnext(sscan);
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
	if (HeapTupleIsValid(tuple))
	{
		parOid = HeapTupleGetOid(tuple);
		partDesc = (Form_pg_partition) GETSTRUCT(tuple);

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

			/* handle root part specially */
			*n = palloc0(sizeof(PartitionIndexNode));
			(*n)->paroid = parOid;
			(*n)->parrelid = (*n)->parchildrelid = partDesc->parrelid;
			(*n)->isDefault = false;
		}
352
		systable_endscan(sscan);
353 354 355 356
		heap_close(partRel, AccessShareLock);
	}
	else
	{
357
		systable_endscan(sscan);
358 359 360 361 362 363 364
		heap_close(partRel, AccessShareLock);
		return;
	}

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

A
Ashwin Agrawal 已提交
365 366 367 368
	/*
	 * SELECT * FROM pg_partition_rule WHERE paroid = :1 AND parparentrule =
	 * :2
	 */
369 370 371 372 373 374 375 376 377 378 379 380 381
	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,
							   SnapshotNow, 2, scankey);
	while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
	{
		PartitionIndexNode *child;
A
Ashwin Agrawal 已提交
382 383
		Form_pg_partition_rule rule_desc = (Form_pg_partition_rule) GETSTRUCT(tuple);

384 385 386 387 388 389
		child = palloc(sizeof(PartitionIndexNode));
		memset(child, 0, sizeof(PartitionIndexNode));
		child->paroid = HeapTupleGetOid(tuple);
		child->parrelid = partDesc->parrelid;
		child->parchildrelid = rule_desc->parchildrelid;

A
Ashwin Agrawal 已提交
390 391 392 393
		/*
		 * For every node, we keep track of every level at which this node has
		 * default partitioning
		 */
394 395 396 397 398 399 400 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;
			child->defaultLevels = lappend_int(child->defaultLevels, partDesc->parlevel);
		}

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

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

411
	systable_endscan(sscan);
412 413 414
	heap_close(partRuleRel, AccessShareLock);
}

A
Ashwin Agrawal 已提交
415
/*
416 417 418 419 420
 * 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 已提交
421
 */
422 423
static char *
constructIndexHashKey(Oid partOid,
A
Ashwin Agrawal 已提交
424 425 426 427 428
					  Oid rootOid,
					  HeapTuple tup,
					  AttrNumber *attMap,
					  IndexInfo *ii,
					  LogicalIndexType indType)
429
{
A
Ashwin Agrawal 已提交
430 431 432 433
	StringInfoData buf;
	Expr	   *predExpr = NULL;
	Expr	   *exprsExpr = NULL;

434 435 436 437 438 439 440 441 442 443
	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 已提交
444
	}
445 446

	/* map the attrnos in indPred */
A
Ashwin Agrawal 已提交
447 448 449
	predExpr = (Expr *) ii->ii_Predicate;

	change_varattnos_of_a_node((Node *) predExpr, attMap);
450 451 452 453

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

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

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

A
Ashwin Agrawal 已提交
458
	change_varattnos_of_a_node((Node *) exprsExpr, attMap);
459 460 461 462 463

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

	/* remember mapped exprsList */
A
Ashwin Agrawal 已提交
464
	ii->ii_Expressions = (List *) exprsExpr;
465 466

	return buf.data;
A
Ashwin Agrawal 已提交
467
}
468

A
Ashwin Agrawal 已提交
469
/*
470
 * createIndexHashTables
A
Ashwin Agrawal 已提交
471
 *  create the hash tables to hold logical indexes
472 473 474 475
 */
static void
createIndexHashTables()
{
A
Ashwin Agrawal 已提交
476
	MemoryContext context = NULL;
477 478
	HASHCTL		hash_ctl;

A
Ashwin Agrawal 已提交
479 480 481 482
	/*
	 * this hash is to identify the logical indexes. 1 logical index
	 * corresponds to multiple physical indexes which have the same indkey +
	 * indpred + indexprs
483 484 485 486 487 488 489 490 491
	 */
	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 已提交
492 493 494 495 496
									 INITIAL_NUM_LOGICAL_INDEXES_ESTIMATE,
									 &hash_ctl,
									 HASH_ELEM | HASH_FUNCTION |
									 HASH_COMPARE | HASH_KEYCOPY |
									 HASH_CONTEXT);
497 498 499

	Assert(PartitionIndexHash != NULL);

A
Ashwin Agrawal 已提交
500
	/* this hash is used to hold the logical indexes for easy lookup */
501 502 503 504 505 506
	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 已提交
507 508 509
									   INITIAL_NUM_LOGICAL_INDEXES_ESTIMATE,
									   &hash_ctl,
									   HASH_ELEM | HASH_FUNCTION);
510 511 512 513 514 515 516 517
	Assert(LogicalIndexInfoHash != NULL);
}

/*
 * recordIndexes
 *   Invoke the recordIndexesOnPart routine on every leaf partition.
 */
static void
518
recordIndexes(PartitionIndexNode **partIndexTree)
519
{
A
Ashwin Agrawal 已提交
520
	ListCell   *lc;
521 522 523 524
	PartitionIndexNode *partIndexNode = *partIndexTree;

	if (partIndexNode->children)
	{
A
Ashwin Agrawal 已提交
525
		foreach(lc, partIndexNode->children)
526 527
		{
			PartitionIndexNode *child = (PartitionIndexNode *) lfirst(lc);
A
Ashwin Agrawal 已提交
528

529
			recordIndexes(&child);
530 531
		}
	}
A
Ashwin Agrawal 已提交
532
	else
533
		/* at a leaf */
A
Ashwin Agrawal 已提交
534 535 536
		recordIndexesOnLeafPart(partIndexTree,
								partIndexNode->parchildrelid,
								partIndexNode->parrelid);
537 538 539
}

/*
A
Ashwin Agrawal 已提交
540
 * recordIndexesOnLeafPart
541 542 543 544 545 546 547 548 549 550 551
 *   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 已提交
552 553
						Oid partOid,
						Oid rootOid)
554
{
A
Ashwin Agrawal 已提交
555 556 557 558 559 560 561 562 563 564
	char	   *partIndexHashKey;
	bool		foundPartIndexHash;
	bool		foundLogicalIndexHash;
	AttrNumber *attmap = NULL;
	struct IndexInfo *ii = NULL;
	PartitionIndexHashEntry *partIndexHashEntry;
	LogicalIndexInfoHashEntry *logicalIndexInfoHashEntry;
	PartitionIndexNode *pNode = *pNodePtr;
	List	   *indexoidlist;
	ListCell   *lc;
565

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

A
Ashwin Agrawal 已提交
568
	char		relstorage = partRel->rd_rel->relstorage;
569 570 571 572

	heap_close(partRel, AccessShareLock);

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

		/*
		 * 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);

A
Ashwin Agrawal 已提交
586 587 588
		/*
		 * for AO and AOCO tables we assume the index is bitmap, for heap
		 * partitions look up the access method from the catalog
589 590 591 592 593 594 595 596 597
		 */
		if (RELSTORAGE_HEAP == relstorage)
		{
			if (BTREE_AM_OID == indRel->rd_rel->relam)
			{
				indType = INDTYPE_BTREE;
			}
		}

A
Ashwin Agrawal 已提交
598
		/*
599 600 601 602 603
		 * 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 已提交
604 605 606 607 608
			Relation	partRel = heap_open(partOid, AccessShareLock);
			Relation	rootRel = heap_open(rootOid, AccessShareLock);

			TupleDesc	rootTupDesc = rootRel->rd_att;
			TupleDesc	partTupDesc = partRel->rd_att;
609 610

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

612 613 614 615 616 617
			/* can we close here ? */
			heap_close(partRel, AccessShareLock);
			heap_close(rootRel, AccessShareLock);
		}

		/* populate index info structure */
618 619 620 621
		ii = populateIndexInfo(indRel);

		index_close(indRel, NoLock);

622
		/* construct hash key for the index */
623
		partIndexHashKey = constructIndexHashKey(partOid, rootOid, indRel->rd_indextuple, attmap, ii, indType);
624 625

		/* lookup PartitionIndexHash table */
A
Ashwin Agrawal 已提交
626 627 628 629
		partIndexHashEntry = (PartitionIndexHashEntry *) hash_search(PartitionIndexHash,
																	 (void *) partIndexHashKey,
																	 HASH_ENTER,
																	 &foundPartIndexHash);
630 631 632 633 634 635 636 637

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

			/* assign a logical index id */
			partIndexHashEntry->logicalIndexId = logicalIndexId++;
A
Ashwin Agrawal 已提交
638 639 640 641 642 643 644 645 646

			/*
			 * insert the entry into LogicalIndexInfoHash to keep track of
			 * logical indexes
			 */
			logicalIndexInfoHashEntry = (LogicalIndexInfoHashEntry *) hash_search(LogicalIndexInfoHash,
																				  (void *) &(partIndexHashEntry->logicalIndexId),
																				  HASH_ENTER,
																				  &foundLogicalIndexHash);
647 648 649 650


			if (foundLogicalIndexHash)
			{
A
Ashwin Agrawal 已提交
651 652 653
				/*
				 * we should not find the entry in the logical index hash as
				 * this is the first time we are seeing it
654
				 */
655 656 657 658
				ereport(ERROR,
						(errcode(ERRCODE_INTERNAL_ERROR),
						 errmsg("error during BuildLogicalIndexInfo. Found indexrelid \"%d\" in hash",
								indexoid
A
Ashwin Agrawal 已提交
659
								)));
660 661 662
			}

			logicalIndexInfoHashEntry->logicalIndexId = partIndexHashEntry->logicalIndexId;
663
			logicalIndexInfoHashEntry->logicalIndexOid = indexoid;
664 665 666 667 668 669 670
			logicalIndexInfoHashEntry->ii = ii;
			logicalIndexInfoHashEntry->partList = NIL;
			logicalIndexInfoHashEntry->defaultPartList = NIL;
			logicalIndexInfoHashEntry->indType = indType;
		}
		else
		{
A
Ashwin Agrawal 已提交
671 672 673 674
			/*
			 * we can release IndexInfo as we already have the information in
			 * the hash
			 */
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
			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);
	}
}

/*
 * collapseIndexes
A
Ashwin Agrawal 已提交
690 691
 *   Walk the PartitionNode tree
 *	- For every node
692 693 694 695 696 697
 *		- 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 已提交
698
				LogicalIndexInfoHashEntry **entry)
699
{
A
Ashwin Agrawal 已提交
700 701
	ListCell   *lc,
			   *lc1;
702
	PartitionIndexNode *pn = *partitionIndexNode;
A
Ashwin Agrawal 已提交
703 704 705
	bool		exists = TRUE;
	int			lid = (*entry)->logicalIndexId;
	int			childStatus = TRUE;
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727

	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 已提交
728

729
			/* remove the index from the children */
A
Ashwin Agrawal 已提交
730
			foreach(lc1, pn->children)
731 732
			{
				PartitionIndexNode *child = (PartitionIndexNode *) lfirst(lc1);
A
Ashwin Agrawal 已提交
733

734 735 736 737 738 739 740 741 742 743 744 745 746 747
				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 已提交
748
/*
749 750 751
 * 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 已提交
752
 *   If the logical index exists on a default part, record some additional
753 754
 *   information to indentify the specific default part.
 *
D
Daniel Gustafsson 已提交
755
 *   This consolidates all the information regarding the logical index in the
756 757 758 759
 *   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 已提交
760 761
static void
indexParts(PartitionIndexNode **np, bool isDefault)
762
{
A
Ashwin Agrawal 已提交
763 764 765 766
	LogicalIndexInfoHashEntry *entry;
	PartitionIndexNode *n = *np;
	bool		found;
	int			x;
767

768 769
	if (!n)
		return;
A
Ashwin Agrawal 已提交
770

771 772
	x = bms_first_from(n->index, 0);
	while (x >= 0)
773
	{
D
Daniel Gustafsson 已提交
774
		entry = (LogicalIndexInfoHashEntry *) hash_search(LogicalIndexInfoHash,
A
Ashwin Agrawal 已提交
775
														  (void *) &x, HASH_FIND, &found);
776
		if (!found)
777
		{
D
Daniel Gustafsson 已提交
778 779
			ereport(ERROR,
					(errcode(ERRCODE_INTERNAL_ERROR),
A
Ashwin Agrawal 已提交
780 781
					 errmsg("error during BuildLogicalIndexInfo. Index not found \"%d\" in hash",
							x)));
782
		}
783

784 785
		if (n->isDefault || isDefault)
		{
D
Daniel Gustafsson 已提交
786
			/*
787
			 * We keep track of the default node in the PartitionIndexNode
A
Ashwin Agrawal 已提交
788 789
			 * tree, since we need to output the defaultLevels information to
			 * the caller.
790 791
			 */
			entry->defaultPartList = lappend(entry->defaultPartList, n);
D
Daniel Gustafsson 已提交
792
			numIndexesOnDefaultParts++;
793
		}
794
		else
A
Ashwin Agrawal 已提交
795

D
Daniel Gustafsson 已提交
796
			/*
A
Ashwin Agrawal 已提交
797 798
			 * For regular non-default parts we just track the part oid which
			 * will be used to get the part constraint.
D
Daniel Gustafsson 已提交
799
			 */
800
			entry->partList = lappend_oid(entry->partList, n->parchildrelid);
D
Daniel Gustafsson 已提交
801

802
		x = bms_first_from(n->index, x + 1);
803 804 805 806
	}

	if (n->children)
	{
A
Ashwin Agrawal 已提交
807 808 809
		ListCell   *lc;

		foreach(lc, n->children)
810 811
		{
			PartitionIndexNode *child = (PartitionIndexNode *) lfirst(lc);
A
Ashwin Agrawal 已提交
812

813 814 815 816 817 818 819 820 821 822 823 824 825 826
			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)
{
827 828
	ScanKeyData scankey;
	SysScanDesc sscan;
A
Ashwin Agrawal 已提交
829 830 831 832 833 834 835 836 837 838
	Relation	conRel;
	HeapTuple	conTup;
	Node	   *conExpr;
	Node	   *result = NULL;
	Datum		conBinDatum;
	Datum		conKeyDatum;
	char	   *conBin;
	bool		conbinIsNull = false;
	bool		conKeyIsNull = false;
	AttrMap    *map;
839 840

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

A
Ashwin Agrawal 已提交
844
	map_part_attrs(partRel, rootRel, &map, false);
845 846 847 848 849 850 851

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

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

852 853 854 855 856 857
	ScanKeyInit(&scankey,
				Anum_pg_constraint_conrelid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(partOid));
	sscan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
							   SnapshotNow, 1, &scankey);
858

A
Ashwin Agrawal 已提交
859 860
	/* list of keys referenced in the found constraints */
	List	   *keys = NIL;
861

862
	while (HeapTupleIsValid(conTup = systable_getnext(sscan)))
863
	{
A
Ashwin Agrawal 已提交
864 865 866 867
		/*
		 * we defer the filter on contype to here in order to take advantage
		 * of the index on conrelid
		 */
868
		Form_pg_constraint conEntry = (Form_pg_constraint) GETSTRUCT(conTup);
A
Ashwin Agrawal 已提交
869

870 871 872 873 874 875
		if (conEntry->contype != 'c')
		{
			continue;
		}
		/* Fetch the constraint expression in parsetree form */
		conBinDatum = heap_getattr(conTup, Anum_pg_constraint_conbin,
A
Ashwin Agrawal 已提交
876
								   RelationGetDescr(conRel), &conbinIsNull);
877

A
Ashwin Agrawal 已提交
878
		Assert(!conbinIsNull);
879 880 881 882 883 884
		/* map the attnums in constraint expression to root attnums */
		conBin = TextDatumGetCString(conBinDatum);
		conExpr = stringToNode(conBin);
		conExpr = attrMapExpr(map, conExpr);

		if (result)
A
Ashwin Agrawal 已提交
885
			result = (Node *) make_andclause(list_make2(result, conExpr));
886 887 888
		else
			result = conExpr;

A
Ashwin Agrawal 已提交
889
		/* fetch the key associated with this constraint */
890
		conKeyDatum = heap_getattr(conTup, Anum_pg_constraint_conkey,
A
Ashwin Agrawal 已提交
891 892 893
								   RelationGetDescr(conRel), &conKeyIsNull);
		Datum	   *dats = NULL;
		int			numKeys = 0;
894

A
Ashwin Agrawal 已提交
895
		/* extract key elements */
896 897 898
		deconstruct_array(DatumGetArrayTypeP(conKeyDatum), INT2OID, 2, true, 's', &dats, NULL, &numKeys);
		for (int i = 0; i < numKeys; i++)
		{
A
Ashwin Agrawal 已提交
899 900
			int16		key_elem = DatumGetInt16(dats[i]);

901 902 903 904
			keys = lappend_int(keys, key_elem);
		}
	}

905
	systable_endscan(sscan);
906 907
	heap_close(conRel, AccessShareLock);

A
Ashwin Agrawal 已提交
908 909 910
	ListCell   *lc = NULL;

	foreach(lc, partKey)
911
	{
A
Ashwin Agrawal 已提交
912
		int			partKeyCol = lfirst_int(lc);
913

914
		if (!list_member_int(keys, partKeyCol))
915
		{
A
Ashwin Agrawal 已提交
916
			/* passed in key is not found in the constraint. return NULL */
917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
			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 已提交
947 948 949 950 951
	/* get number of partitioning levels */
	List	   *partkeys = rel_partition_keys_ordered(rootOid);
	int			nLevels = list_length(partkeys);

	Node	   *allCons = NULL;
952 953 954

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

A
Ashwin Agrawal 已提交
957
		PartitionNode *pn = get_parts(rootOid, level, 0 /* parent */ , false /* inctemplate */ , false /* includesubparts */ );
958 959

		Assert(NULL != pn);
A
Ashwin Agrawal 已提交
960 961 962 963
		List	   *partOids = all_partition_relids(pn);

		Node	   *partCons = NULL;
		ListCell   *lc = NULL;
964 965 966

		foreach(lc, partOids)
		{
A
Ashwin Agrawal 已提交
967 968 969
			Oid			partOid = lfirst_oid(lc);

			/* fetch part constraint mapped to root */
970 971 972 973
			partCons = getPartConstraints(partOid, rootOid, partKey);

			if (NULL == partCons)
			{
A
Ashwin Agrawal 已提交
974
				/* default partition has NULL constriant in GPDB's catalog */
975 976 977 978
				*defaultLevels = lappend_int(*defaultLevels, level);
				continue;
			}

A
Ashwin Agrawal 已提交
979
			/* OR them to current constraints */
980 981 982 983 984 985 986 987 988 989 990 991 992
			if (NULL == allCons)
			{
				allCons = partCons;
			}
			else
			{
				allCons = (Node *) mergeIntervals(allCons, partCons);
			}
		}
	}

	if (NULL == allCons)
	{
A
Ashwin Agrawal 已提交
993
		allCons = makeBoolConst(false /* value */ , false /* isnull */ );
994 995 996 997 998 999 1000 1001
	}

	list_free(partkeys);
	return allCons;
}

/*
 * populateIndexInfo
A
Ashwin Agrawal 已提交
1002
 *  Populate the IndexInfo structure with the information from pg_index tuple.
1003 1004
 */
static IndexInfo *
1005
populateIndexInfo(Relation indRel)
1006
{
A
Ashwin Agrawal 已提交
1007
	IndexInfo  *ii;
1008

A
Ashwin Agrawal 已提交
1009 1010 1011 1012 1013
	/*
	 * 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.
1014 1015 1016
	 */
	ii = makeNode(IndexInfo);

1017 1018
	ii->ii_Unique = indRel->rd_index->indisunique;
	ii->ii_NumIndexAttrs = indRel->rd_index->indnatts;
1019

1020
	for (int i = 0; i < indRel->rd_index->indnatts; i++)
1021
	{
1022
		ii->ii_KeyAttrNumbers[i] = indRel->rd_index->indkey.values[i];
1023 1024
	}

1025 1026
	ii->ii_Expressions = RelationGetIndexExpressions(indRel);
	ii->ii_Predicate = RelationGetIndexPredicate(indRel);
1027 1028 1029 1030

	return ii;
}

A
Ashwin Agrawal 已提交
1031
/*
1032 1033 1034 1035 1036 1037 1038
 * 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 已提交
1039 1040 1041 1042
						 int *curIdx,
						 LogicalIndexInfoHashEntry *entry,
						 Oid root,
						 int *numLogicalIndexes)
1043
{
A
Ashwin Agrawal 已提交
1044 1045 1046
	Node	   *conList;
	ListCell   *lc;
	AttrNumber *indexKeys;
1047 1048 1049 1050 1051 1052 1053 1054

	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 已提交
1055 1056 1057 1058 1059
		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);
1060 1061 1062 1063 1064 1065
		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 已提交
1066 1067
			Oid			partOid = lfirst_oid(lc);

1068
			if (partOid != root)
A
Ashwin Agrawal 已提交
1069
			{
1070
				/* fetch part constraint mapped to root */
A
Ashwin Agrawal 已提交
1071 1072
				conList = getPartConstraints(partOid, root, NIL /* partKey */ );

1073 1074 1075
				/* OR them to current constraints */
				if (li->logicalIndexInfo[*curIdx]->partCons)
				{
A
Ashwin Agrawal 已提交
1076
					li->logicalIndexInfo[*curIdx]->partCons = mergeIntervals(li->logicalIndexInfo[*curIdx]->partCons, conList);
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
				}
				else
				{
					li->logicalIndexInfo[*curIdx]->partCons = conList;
				}
			}
		}

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

	/* from the hash entry, fetch the defaultPartList */
	foreach(lc, entry->defaultPartList)
	{
A
Ashwin Agrawal 已提交
1092
		PartitionIndexNode *node = (PartitionIndexNode *) lfirst(lc);
1093 1094 1095 1096 1097 1098
		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 已提交
1099 1100
		memcpy((char *) indexKeys,
			   &(entry->ii->ii_KeyAttrNumbers), sizeof(AttrNumber) * entry->ii->ii_NumIndexAttrs);
1101
		li->logicalIndexInfo[*curIdx]->indexKeys = indexKeys;
A
Ashwin Agrawal 已提交
1102 1103
		li->logicalIndexInfo[*curIdx]->indExprs = (List *) copyObject(entry->ii->ii_Expressions);
		li->logicalIndexInfo[*curIdx]->indPred = (List *) copyObject(entry->ii->ii_Predicate);
1104 1105 1106
		li->logicalIndexInfo[*curIdx]->indIsUnique = entry->ii->ii_Unique;
		li->logicalIndexInfo[*curIdx]->indType = entry->indType;

A
Ashwin Agrawal 已提交
1107
		/*
1108
		 * Default parts don't have constraints, so they cannot be represented
A
Ashwin Agrawal 已提交
1109 1110 1111 1112 1113 1114
		 * 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.
1115
		 */
A
Ashwin Agrawal 已提交
1116
		li->logicalIndexInfo[*curIdx]->partCons = getPartConstraints(node->parchildrelid, root, NIL /* partKey */ );
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126

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

/*
 * createPartsIndexResult
A
Ashwin Agrawal 已提交
1127
 *  Populate the result array of logical indexes. Most of the information needed
1128 1129 1130 1131 1132 1133 1134
 *  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 已提交
1135
	int			numResultRows = 0;
1136 1137 1138 1139 1140
	LogicalIndexes *li;
	LogicalIndexInfoHashEntry *entry;

	hash_seq_init(&hash_seq, LogicalIndexInfoHash);

A
Ashwin Agrawal 已提交
1141 1142 1143 1144
	/*
	 * 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.
1145 1146 1147 1148 1149 1150 1151 1152
	 */
	numResultRows = numLogicalIndexes + numIndexesOnDefaultParts;

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

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

A
Ashwin Agrawal 已提交
1153
	li->logicalIndexInfo = (LogicalIndexInfo **) palloc0(numResultRows * sizeof(LogicalIndexInfo *));
1154 1155

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

A
Ashwin Agrawal 已提交
1159
	int			curIdx = 0;
1160

A
Ashwin Agrawal 已提交
1161 1162 1163 1164
	/*
	 * for each logical index, get the part constraints as partial index
	 * predicates
	 */
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
	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 已提交
1179
 *
1180 1181 1182 1183
 * NOTE: index attnums in the provided logicalIndexInfo input structure
 * have to be mapped to the root.
 */
Oid
1184
getPhysicalIndexRelid(Relation partRel, LogicalIndexInfo *iInfo)
1185
{
A
Ashwin Agrawal 已提交
1186
	Oid			resultOid = InvalidOid;
1187
	bool		indKeyEqual;
1188 1189 1190
	List	   *indexoidlist;
	ListCell   *lc;
	Relation	indRel = NULL;
1191

1192 1193 1194
	/* fetch each index on partition */
	indexoidlist = RelationGetIndexList(partRel);
	foreach(lc, indexoidlist)
1195
	{
1196 1197
		Oid			indexoid = lfirst_oid(lc);
		Form_pg_index indForm;
1198

1199 1200
		if (indRel)
			index_close(indRel, NoLock);
1201

1202 1203 1204 1205 1206 1207
		/*
		 * 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;
1208

1209
		if (indForm->indnatts != iInfo->nColumns)
1210 1211 1212 1213
			continue;

		/* compare indKey */
		indKeyEqual = true;
1214
		for (int i = 0; i < indForm->indnatts; i++)
1215
		{
1216
			if (indForm->indkey.values[i] != iInfo->indexKeys[i])
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
			{
				indKeyEqual = false;
				break;
			}
		}

		if (!indKeyEqual)
			continue;

		/* compare uniqueness attribute */
1227
		if (iInfo->indIsUnique != indForm->indisunique)
1228 1229 1230
			continue;

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

1233
		if (!equal(iInfo->indPred, indPred))
1234
			continue;
1235
		list_free(indPred);
1236 1237

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

1240
		if (equal(iInfo->indExprs, indExprs))
1241 1242 1243 1244 1245
		{
			/* found matching index */
			resultOid = indForm->indexrelid;
			break;
		}
1246
		list_free(indExprs);
A
Ashwin Agrawal 已提交
1247 1248

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

1251 1252
	if (indRel)
		index_close(indRel, NoLock);
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263

	return resultOid;
}

/*
 * dumpPartsIndexInfo
 *   print debugging info
 */
static void
dumpPartsIndexInfo(PartitionIndexNode *n, int level)
{
A
Ashwin Agrawal 已提交
1264 1265 1266
	ListCell   *lc;
	StringInfoData logicalIndexes;
	int			x;
D
Daniel Gustafsson 已提交
1267

1268 1269
	initStringInfo(&logicalIndexes);

1270 1271
	if (!n)
		return;
1272

1273 1274
	for (int i = 0; i <= level; i++)
		appendStringInfo(&logicalIndexes, "%s", "   ");
1275

1276
	appendStringInfo(&logicalIndexes, "%d ", n->parchildrelid);
1277

1278 1279
	x = bms_first_from(n->index, 0);
	appendStringInfo(&logicalIndexes, "%s ", " (");
1280

1281 1282 1283 1284
	while (x >= 0)
	{
		appendStringInfo(&logicalIndexes, "%d ", x);
		x = bms_first_from(n->index, x + 1);
1285 1286
	}

1287 1288 1289
	appendStringInfo(&logicalIndexes, "%s ", " )");

	elog(DEBUG5, "%s", logicalIndexes.data);
1290 1291 1292

	if (n->children)
	{
A
Ashwin Agrawal 已提交
1293
		foreach(lc, n->children)
1294 1295
		{
			PartitionIndexNode *child = (PartitionIndexNode *) lfirst(lc);
A
Ashwin Agrawal 已提交
1296 1297

			dumpPartsIndexInfo(child, level + 1);
1298 1299 1300 1301 1302 1303 1304 1305 1306
			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 已提交
1307
 *
1308
 *   This function's arguments represent two range constraints, which the function attempts
A
Ashwin Agrawal 已提交
1309
 *   to collapse into one if they share a common boundary. If no collapse is possible,
1310 1311 1312 1313 1314
 *   the function returns a disjunction of the two intervals.
 */
static Node *
mergeIntervals(Node *intervalFst, Node *intervalSnd)
{
A
Ashwin Agrawal 已提交
1315 1316 1317 1318 1319
	Node	   *pnodeStart1 = NULL;
	Node	   *pnodeEnd1 = NULL;
	Node	   *pnodeStart2 = NULL;
	Node	   *pnodeEnd2 = NULL;

1320 1321
	extractStartEndRange(intervalFst, &pnodeStart1, &pnodeEnd1);
	extractStartEndRange(intervalSnd, &pnodeStart2, &pnodeEnd2);
A
Ashwin Agrawal 已提交
1322

1323 1324
	if (NULL != pnodeEnd1 && NULL != pnodeStart2)
	{
A
Ashwin Agrawal 已提交
1325 1326 1327 1328 1329 1330 1331 1332 1333
		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;

1334 1335 1336
		/* extract boundaries of the two intervals */
		extractOpExprComponents(opexprEnd1, &pvarEnd1, &pconstEnd1, &opnoEnd1);
		extractOpExprComponents(opexprStart2, &pvarStart2, &pconstStart2, &opnoStart2);
A
Ashwin Agrawal 已提交
1337 1338 1339 1340 1341 1342
		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 */
1343 1344 1345 1346 1347 1348 1349
			)
		{
			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 已提交
1350

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

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

1361 1362
				return (Node *) make_opclause(opnoStart1, opexprStart1->opresulttype, opexprStart1->opretset, (Expr *) pvarStart1, (Expr *) pconstStart1);
			}
A
Ashwin Agrawal 已提交
1363

1364 1365 1366
			if (NULL != pnodeEnd2)
			{
				/* merge intervals of the form (-inf,x), [x, y) into (-inf, y) */
A
Ashwin Agrawal 已提交
1367 1368 1369 1370
				Var		   *pvarEnd2 = NULL;
				Const	   *pconstEnd2 = NULL;
				Oid			opnoEnd2 = InvalidOid;
				OpExpr	   *opexprEnd2 = (OpExpr *) pnodeEnd2;
1371 1372

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

1374 1375
				return (Node *) make_opclause(opnoEnd2, opexprEnd2->opresulttype, opexprEnd2->opretset, (Expr *) pvarEnd2, (Expr *) pconstEnd2);
			}
A
Ashwin Agrawal 已提交
1376

1377
			Assert(NULL == pnodeStart1 && NULL == pnodeEnd2);
A
Ashwin Agrawal 已提交
1378

1379
			/* merge (-inf, x), [x,inf) into true */
A
Ashwin Agrawal 已提交
1380 1381

			return (Node *) makeBoolConst(true /* value */ , false /* isnull */ );
1382 1383 1384 1385 1386 1387 1388
		}
	}
	return (Node *) make_orclause(list_make2(intervalFst, intervalSnd));
}

/*
 * extractStartEndRange
A
Ashwin Agrawal 已提交
1389
 *   Given an expression representing an interval constraint, extract the expressions defining the interval's start and end
1390
 */
A
Ashwin Agrawal 已提交
1391 1392
static void
extractStartEndRange(Node *clause, Node **ppnodeStart, Node **ppnodeEnd)
1393 1394 1395
{
	if (IsA(clause, OpExpr))
	{
A
Ashwin Agrawal 已提交
1396 1397 1398 1399
		OpExpr	   *opexpr = (OpExpr *) clause;
		Expr	   *pexprLeft = list_nth(opexpr->args, 0);
		Expr	   *pexprRight = list_nth(opexpr->args, 1);
		CmpType		cmptype = get_comparison_type(opexpr->opno, exprType((Node *) pexprLeft), exprType((Node *) pexprRight));
1400 1401 1402 1403 1404 1405

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

1407 1408 1409 1410 1411 1412 1413
		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 已提交
1414

1415 1416 1417 1418 1419 1420 1421 1422 1423
		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 已提交
1424 1425 1426 1427 1428 1429 1430 1431
	/*
	 * 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))
1432 1433 1434
	{
		return;
	}
A
Ashwin Agrawal 已提交
1435 1436 1437 1438 1439 1440 1441

	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))
1442 1443 1444
	{
		return;
	}
A
Ashwin Agrawal 已提交
1445 1446 1447 1448 1449 1450 1451

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

	CmpType		cmptLeft = get_comparison_type(opexprStart->opno, exprType(list_nth(opexprStart->args, 0)), exprType(list_nth(opexprStart->args, 1)));
	CmpType		cmptRight = get_comparison_type(opexprEnd->opno, exprType(list_nth(opexprEnd->args, 0)), exprType(list_nth(opexprEnd->args, 1)));

1452 1453 1454 1455
	if ((CmptGT != cmptLeft && CmptGEq != cmptLeft) || (CmptLT != cmptRight && CmptLEq != cmptRight))
	{
		return;
	}
A
Ashwin Agrawal 已提交
1456

1457 1458 1459 1460 1461 1462 1463 1464
	*ppnodeStart = nodeStart;
	*ppnodeEnd = nodeEnd;
}

/*
 * extractOpExprComponents
 *   for an opexpr of type Var op Const, extract its components
 */
A
Ashwin Agrawal 已提交
1465 1466
static void
extractOpExprComponents(OpExpr *opexpr, Var **ppvar, Const **ppconst, Oid *opno)
1467
{
A
Ashwin Agrawal 已提交
1468 1469 1470 1471
	Node	   *pnodeLeft = list_nth(opexpr->args, 0);
	Node	   *pnodeRight = list_nth(opexpr->args, 1);

	if (IsA(pnodeLeft, Var) &&IsA(pnodeRight, Const))
1472 1473 1474 1475 1476
	{
		*ppvar = (Var *) pnodeLeft;
		*ppconst = (Const *) pnodeRight;
		*opno = opexpr->opno;
	}
A
Ashwin Agrawal 已提交
1477
	else if (IsA(pnodeLeft, Const) &&IsA(pnodeRight, Var) &&InvalidOid != get_commutator(opexpr->opno))
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
	{
		*ppvar = (Var *) pnodeRight;
		*ppconst = (Const *) pnodeLeft;
		*opno = get_commutator(opexpr->opno);
	}
}


/*
 * LogicalIndexInfoForIndexOid
 *   construct the logical index info for a given index oid
 */
1490 1491
LogicalIndexInfo *
logicalIndexInfoForIndexOid(Oid rootOid, Oid indexOid)
1492
{
1493
	Relation	indRel;
1494

1495
	indRel = index_open(indexOid, AccessShareLock);
1496

A
Ashwin Agrawal 已提交
1497 1498 1499 1500 1501 1502
	IndexInfo  *pindexInfo = populateIndexInfo(indRel);
	Oid			partOid = indRel->rd_index->indrelid;

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

A
Ashwin Agrawal 已提交
1504 1505
	TupleDesc	rootTupDesc = rootRel->rd_att;
	TupleDesc	partTupDesc = partRel->rd_att;
1506

A
Ashwin Agrawal 已提交
1507 1508
	char		relstorage = partRel->rd_rel->relstorage;
	AttrNumber *attMap = varattnos_map(rootTupDesc, partTupDesc);
1509 1510 1511

	heap_close(rootRel, AccessShareLock);
	heap_close(partRel, AccessShareLock);
A
Ashwin Agrawal 已提交
1512 1513

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

1516 1517 1518
	plogicalIndexInfo->nColumns = pindexInfo->ii_NumIndexAttrs;
	plogicalIndexInfo->indIsUnique = pindexInfo->ii_Unique;
	plogicalIndexInfo->logicalIndexOid = indexOid;
A
Ashwin Agrawal 已提交
1519 1520 1521

	int			numIndexKeys = pindexInfo->ii_NumIndexAttrs;

1522
	plogicalIndexInfo->indexKeys = palloc(sizeof(AttrNumber) * numIndexKeys);
A
Ashwin Agrawal 已提交
1523
	memcpy((char *) plogicalIndexInfo->indexKeys, &(pindexInfo->ii_KeyAttrNumbers), sizeof(AttrNumber) * numIndexKeys);
1524 1525 1526

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

1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
	/* 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 已提交
1542

1543 1544 1545 1546 1547 1548 1549 1550
	plogicalIndexInfo->indType = INDTYPE_BITMAP;
	if (RELSTORAGE_HEAP == relstorage)
	{
		if (BTREE_AM_OID == indRel->rd_rel->relam)
		{
			plogicalIndexInfo->indType = INDTYPE_BTREE;
		}
	}
1551 1552 1553

	index_close(indRel, AccessShareLock);

1554 1555
	return plogicalIndexInfo;
}