提交 9d40d472 编写于 作者: T Taylor Vesely 提交者: David Krieger

Add Partitioned Indexes

This commit adds partitioned indexes from upstream Postgres. This commit is
mostly cherry-picked from Postgres 11 and bug fixes from Postgres 12.

Differences from upstream:
 - Postgres has two additional relkind's - RELKIND_PARTITIONED_TABLE and
   RELKIND_PARTITIONED_INDEX, which have no on disk storage. Greenplum does not
   have these additional relkinds. Thus, partitioned indexes have physical
   storage.
 - CREATE INDEX ON ONLY <table> DDL has not yet been implemented
 - ALTER INDEX ATTACH PARTITION DDL has not yet been implemented

Constraint changes:
 - Constraints and their backing index have the same names. Thus, partitions of
   a table no longer share the same constraint name, and are instead related to
   their parent via INTERNAL_AUTO dependencies.

Index changes:
 - Child partition indexes can no longer be directly dropped, and must be
   dropped from their root. This includes mid-level and leaf indexes.
 - Adding indexes to mid-level partitions cascade to their children.

These changes are mostly cherry-picked from:
commit 8b08f7d4
Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date:   Fri Jan 19 11:49:22 2018 -0300

    Local partitioned indexes

    When CREATE INDEX is run on a partitioned table, create catalog entries
    for an index on the partitioned table (which is just a placeholder since
    the table proper has no data of its own), and recurse to create actual
    indexes on the existing partitions; create them in future partitions
    also.

    As a convenience gadget, if the new index definition matches some
    existing index in partitions, these are picked up and used instead of
    creating new ones.  Whichever way these indexes come about, they become
    attached to the index on the parent table and are dropped alongside it,
    and cannot be dropped on isolation unless they are detached first.

    To support pg_dump'ing these indexes, add commands
        CREATE INDEX ON ONLY <table>
    (which creates the index on the parent partitioned table, without
    recursing) and
        ALTER INDEX ATTACH PARTITION
    (which is used after the indexes have been created individually on each
    partition, to attach them to the parent index).  These reconstruct prior
    database state exactly.

    Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
            Langote, Jesper Pedersen, Simon Riggs, David Rowley
    Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql

Changes were also cherry-picked from the following Postgres commits:
  eb7ed3f3 - Allow UNIQUE indexes on partitioned tables
  ae366aa5 - Detach constraints when partitions are detached
  19184fcc - Simplify coding to detach constraints when detaching partition
  c7d43c4d - Correct attach/detach logic for FKs in partitions
  17f206fb - Set pg_class.relhassubclass for partitioned indexes
Co-authored-by: NKalen Krempely <kkrempely@pivotal.io>
上级 11529a7e
......@@ -2997,6 +2997,29 @@
</listitem>
</varlistentry>
<varlistentry>
<term><symbol>DEPENDENCY_INTERNAL_AUTO</symbol> (<literal>I</literal>)</term>
<listitem>
<para>
The dependent object was created as part of creation of the
referenced object, and is really just a part of its internal
implementation. A <command>DROP</command> of the dependent object
will be disallowed outright (we'll tell the user to issue a
<command>DROP</command> against the referenced object, instead).
While a regular internal dependency will prevent
the dependent object from being dropped while any such dependencies
remain, <literal>DEPENDENCY_INTERNAL_AUTO</literal> will allow such
a drop as long as the object can be found by following any of such
dependencies.
Example: an index on a partition is made internal-auto-dependent on
both the partition itself as well as on the index on the parent
partitioned table; so the partition index is dropped together with
either the partition it indexes, or with the parent index it is
attached to.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><symbol>DEPENDENCY_EXTENSION</> (<literal>e</>)</term>
<listitem>
......
......@@ -238,6 +238,8 @@ _bitmap_create_lov_heapandindex(Relation rel,
}
idxid = index_create(lov_heap_rel, lovIndexName, InvalidOid,
InvalidOid,
InvalidOid,
InvalidOid,
indexInfo,
indexColNames,
......
......@@ -172,6 +172,8 @@ CreateAOAuxiliaryTable(
aoauxiliary_idxname,
InvalidOid,
InvalidOid,
InvalidOid,
InvalidOid,
indexInfo,
indexColNames,
BTREE_AM_OID,
......
......@@ -621,7 +621,7 @@ findDependentObjects(const ObjectAddress *object,
/* FALL THRU */
case DEPENDENCY_INTERNAL:
case DEPENDENCY_INTERNAL_AUTO:
/*
* This object is part of the internal implementation of
* another object, or is part of the extension that is the
......@@ -672,6 +672,14 @@ findDependentObjects(const ObjectAddress *object,
* transform this deletion request into a delete of this
* owning object.
*
* For INTERNAL_AUTO dependencies, we don't enforce this;
* in other words, we don't follow the links back to the
* owning object.
*/
if (foundDep->deptype == DEPENDENCY_INTERNAL_AUTO)
break;
/*
* First, release caller's lock on this object and get
* deletion lock on the owning object. (We must release
* caller's lock to avoid deadlock against a concurrent
......@@ -799,6 +807,7 @@ findDependentObjects(const ObjectAddress *object,
case DEPENDENCY_AUTO:
subflags = DEPFLAG_AUTO;
break;
case DEPENDENCY_INTERNAL_AUTO:
case DEPENDENCY_INTERNAL:
subflags = DEPFLAG_INTERNAL;
break;
......
......@@ -45,6 +45,7 @@
#include "catalog/oid_dispatch.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opclass.h"
......@@ -60,6 +61,7 @@
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "parser/parser.h"
#include "rewrite/rewriteManip.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
......@@ -755,6 +757,8 @@ Oid
index_create(Relation heapRelation,
const char *indexRelationName,
Oid indexRelationId,
Oid parentIndexRelid,
Oid parentConstraintId,
Oid relFileNode,
IndexInfo *indexInfo,
List *indexColNames,
......@@ -772,7 +776,7 @@ index_create(Relation heapRelation,
bool skip_build,
bool concurrent,
bool is_internal,
const char *altConName)
Oid *constraintId)
{
Oid heapRelationId = RelationGetRelid(heapRelation);
Relation pg_class;
......@@ -999,6 +1003,13 @@ index_create(Relation heapRelation,
*/
CacheInvalidateRelcache(heapRelation);
/* update pg_inherits and the parent's relhassubclass, if needed */
if (OidIsValid(parentIndexRelid))
{
StoreSingleInheritance(indexRelationId, parentIndexRelid, 1);
SetRelationHasSubclass(parentIndexRelid, true);
}
/*
* Register constraint and dependencies for the index.
*
......@@ -1025,26 +1036,22 @@ index_create(Relation heapRelation,
if (isconstraint)
{
char constraintType;
const char *constraintName = indexRelationName;
ObjectAddress localaddr;
if ( altConName )
{
constraintName = altConName;
}
/*
* Let's make sure that the constraint name is unique
* for this relation.
*/
Assert(constraintName);
Assert(indexRelationName);
if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
RelationGetRelid(heapRelation),
RelationGetNamespace(heapRelation),
constraintName))
indexRelationName))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("constraint \"%s\" for relation \"%s\" already exists",
constraintName, RelationGetRelationName(heapRelation))));
indexRelationName, RelationGetRelationName(heapRelation))));
if (isprimary)
constraintType = CONSTRAINT_PRIMARY;
......@@ -1058,10 +1065,11 @@ index_create(Relation heapRelation,
constraintType = 0; /* keep compiler quiet */
}
index_constraint_create(heapRelation,
localaddr = index_constraint_create(heapRelation,
indexRelationId,
parentConstraintId,
indexInfo,
constraintName,
indexRelationName,
constraintType,
deferrable,
initdeferred,
......@@ -1070,10 +1078,15 @@ index_create(Relation heapRelation,
false, /* no old dependencies */
allow_system_table_mods,
is_internal);
if (constraintId)
*constraintId = localaddr.objectId;
}
else
{
bool have_simple_col = false;
DependencyType deptype;
deptype = OidIsValid(parentIndexRelid) ? DEPENDENCY_INTERNAL_AUTO : DEPENDENCY_AUTO;
/* Create auto dependencies on simply-referenced columns */
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
......@@ -1084,7 +1097,7 @@ index_create(Relation heapRelation,
referenced.objectId = heapRelationId;
referenced.objectSubId = indexInfo->ii_KeyAttrNumbers[i];
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
recordDependencyOn(&myself, &referenced, deptype);
have_simple_col = true;
}
......@@ -1102,7 +1115,7 @@ index_create(Relation heapRelation,
referenced.objectId = heapRelationId;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
recordDependencyOn(&myself, &referenced, deptype);
}
/* Non-constraint indexes can't be deferrable */
......@@ -1110,6 +1123,16 @@ index_create(Relation heapRelation,
Assert(!initdeferred);
}
/* Store dependency on parent index, if any */
if (OidIsValid(parentIndexRelid))
{
referenced.classId = RelationRelationId;
referenced.objectId = parentIndexRelid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL_AUTO);
}
/* Store dependency on collations */
/* The default collation is pinned, so don't bother recording it */
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
......@@ -1254,9 +1277,10 @@ index_create(Relation heapRelation,
* allow_system_table_mods: allow table to be a system catalog
* is_internal: index is constructed due to internal process
*/
void
ObjectAddress
index_constraint_create(Relation heapRelation,
Oid indexRelationId,
Oid parentConstraintId,
IndexInfo *indexInfo,
const char *constraintName,
char constraintType,
......@@ -1272,6 +1296,9 @@ index_constraint_create(Relation heapRelation,
ObjectAddress myself,
referenced;
Oid conOid;
bool islocal;
bool noinherit;
int inhcount;
/* constraint creation support doesn't work while bootstrapping */
Assert(!IsBootstrapProcessingMode());
......@@ -1302,6 +1329,19 @@ index_constraint_create(Relation heapRelation,
deleteDependencyRecordsForClass(RelationRelationId, indexRelationId,
RelationRelationId, DEPENDENCY_AUTO);
if (OidIsValid(parentConstraintId))
{
islocal = false;
inhcount = 1;
noinherit = false;
}
else
{
islocal = true;
inhcount = 0;
noinherit = true;
}
/*
* Construct a pg_constraint entry.
*/
......@@ -1329,9 +1369,9 @@ index_constraint_create(Relation heapRelation,
NULL, /* no check constraint */
NULL,
NULL,
true, /* islocal */
0, /* inhcount */
true, /* noinherit */
islocal,
inhcount,
noinherit,
is_internal);
/*
......@@ -1350,6 +1390,18 @@ index_constraint_create(Relation heapRelation,
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
/*
* Also, if this is a constraint on a partition, mark it as depending
* on the constraint in the parent.
*/
if (OidIsValid(parentConstraintId))
{
ObjectAddress parentConstr;
ObjectAddressSet(parentConstr, ConstraintRelationId, parentConstraintId);
recordDependencyOn(&referenced, &parentConstr, DEPENDENCY_INTERNAL_AUTO);
}
/*
* If the constraint is deferrable, create the deferred uniqueness
* checking trigger. (The trigger will be given an internal dependency on
......@@ -1442,6 +1494,8 @@ index_constraint_create(Relation heapRelation,
heap_freetuple(indexTuple);
heap_close(pg_index, RowExclusiveLock);
}
return referenced;
}
/*
......@@ -1710,6 +1764,11 @@ index_drop(Oid indexId, bool concurrent)
*/
DeleteRelationTuple(indexId);
/*
* fix INHERITS relation
*/
DeleteInheritsTuple(indexId, InvalidOid);
/* MPP-6929: metadata tracking */
MetaTrackDropObject(RelationRelationId,
indexId);
......@@ -1803,9 +1862,118 @@ BuildIndexInfo(Relation index)
ii->ii_Concurrent = false;
ii->ii_BrokenHotChain = false;
ii->ii_Am = index->rd_rel->relam;
return ii;
}
/*
* CompareIndexInfo
* Return whether the properties of two indexes (in different tables)
* indicate that they have the "same" definitions.
*
* Note: passing collations and opfamilies separately is a kludge. Adding
* them to IndexInfo may result in better coding here and elsewhere.
*
* Use convert_tuples_by_name_map(index2, index1) to build the attmap.
*/
bool
CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
Oid *collations1, Oid *collations2,
Oid *opfamilies1, Oid *opfamilies2,
AttrNumber *attmap, int maplen)
{
int i;
if (info1->ii_Unique != info2->ii_Unique)
return false;
/* indexes are only equivalent if they have the same access method */
if (info1->ii_Am != info2->ii_Am)
return false;
/* and same number of attributes */
if (info1->ii_NumIndexAttrs != info2->ii_NumIndexAttrs)
return false;
/*
* and columns match through the attribute map (actual attribute numbers
* might differ!) Note that this implies that index columns that are
* expressions appear in the same positions. We will next compare the
* expressions themselves.
*/
for (i = 0; i < info1->ii_NumIndexAttrs; i++)
{
if (maplen < info2->ii_KeyAttrNumbers[i])
elog(ERROR, "incorrect attribute map");
if (attmap[info2->ii_KeyAttrNumbers[i] - 1] !=
info1->ii_KeyAttrNumbers[i])
return false;
if (collations1[i] != collations2[i])
return false;
if (opfamilies1[i] != opfamilies2[i])
return false;
}
/*
* For expression indexes: either both are expression indexes, or neither
* is; if they are, make sure the expressions match.
*/
if ((info1->ii_Expressions != NIL) != (info2->ii_Expressions != NIL))
return false;
if (info1->ii_Expressions != NIL)
{
bool found_whole_row;
Node *mapped;
mapped = map_variable_attnos((Node *) info2->ii_Expressions,
1, 0, attmap, maplen,
&found_whole_row);
if (found_whole_row)
{
/*
* we could throw an error here, but seems out of scope for this
* routine.
*/
return false;
}
if (!equal(info1->ii_Expressions, mapped))
return false;
}
/* Partial index predicates must be identical, if they exist */
if ((info1->ii_Predicate == NULL) != (info2->ii_Predicate == NULL))
return false;
if (info1->ii_Predicate != NULL)
{
bool found_whole_row;
Node *mapped;
mapped = map_variable_attnos((Node *) info2->ii_Predicate,
1, 0, attmap, maplen,
&found_whole_row);
if (found_whole_row)
{
/*
* we could throw an error here, but seems out of scope for this
* routine.
*/
return false;
}
if (!equal(info1->ii_Predicate, mapped))
return false;
}
/* No support currently for comparing exclusion indexes. */
if (info1->ii_ExclusionOps != NULL || info2->ii_ExclusionOps != NULL)
return false;
return true;
}
/* ----------------
* FormIndexDatum
* Construct values[] and isnull[] arrays for a new index tuple.
......
......@@ -777,6 +777,64 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
heap_close(conRel, RowExclusiveLock);
}
/*
* ConstraintSetParentConstraint
* Set a partition's constraint as child of its parent table's
*
* This updates the constraint's pg_constraint row to show it as inherited, and
* add a dependency to the parent so that it cannot be removed on its own.
*/
void
ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId)
{
Relation constrRel;
Form_pg_constraint constrForm;
HeapTuple tuple,
newtup;
ObjectAddress depender;
ObjectAddress referenced;
constrRel = heap_open(ConstraintRelationId, RowExclusiveLock);
tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(childConstrId));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for constraint %u", childConstrId);
newtup = heap_copytuple(tuple);
constrForm = (Form_pg_constraint) GETSTRUCT(newtup);
if (OidIsValid(parentConstrId))
{
/* don't allow setting parent for a constraint that already has one */
Assert(constrForm->coninhcount == 0);
constrForm->conislocal = false;
constrForm->coninhcount++;
simple_heap_update(constrRel, &tuple->t_self, newtup);
CatalogUpdateIndexes(constrRel, newtup);
ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId);
ObjectAddressSet(depender, ConstraintRelationId, childConstrId);
recordDependencyOn(&depender, &referenced, DEPENDENCY_INTERNAL_AUTO);
}
else
{
constrForm->coninhcount--;
constrForm->conislocal = true;
/* Make sure there's no further inheritance. */
Assert(constrForm->coninhcount == 0);
deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
ConstraintRelationId,
DEPENDENCY_INTERNAL_AUTO);
simple_heap_update(constrRel, &tuple->t_self, newtup);
CatalogUpdateIndexes(constrRel, newtup);
}
ReleaseSysCache(tuple);
heap_close(constrRel, RowExclusiveLock);
}
/*
* get_constraint_relation_oids
* Find the IDs of the relations to which a constraint refers.
......@@ -854,6 +912,45 @@ get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
return conOid;
}
/*
* Return the OID of the constraint associated with the given index in the
* given relation; or InvalidOid if no such index is catalogued.
*/
Oid
get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
{
Relation pg_constraint;
SysScanDesc scan;
ScanKeyData key;
HeapTuple tuple;
Oid constraintId = InvalidOid;
pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
ScanKeyInit(&key,
Anum_pg_constraint_conrelid,
BTEqualStrategyNumber,
F_OIDEQ,
ObjectIdGetDatum(relationId));
scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId,
true, NULL, 1, &key);
while ((tuple = systable_getnext(scan)) != NULL)
{
Form_pg_constraint constrForm;
constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
if (constrForm->conindid == indexId)
{
constraintId = HeapTupleGetOid(tuple);
break;
}
}
systable_endscan(scan);
heap_close(pg_constraint, AccessShareLock);
return constraintId;
}
/*
* get_domain_constraint_oid
* Find a constraint on the specified domain with the specified name.
......
......@@ -283,6 +283,30 @@ has_subclass(Oid relationId)
return result;
}
/*
* has_superclass - does this relation inherit from another? The caller
* should hold a lock on the given relation so that it can't be concurrently
* added to or removed from an inheritance hierarchy.
*/
bool
has_superclass(Oid relationId)
{
Relation catalog;
SysScanDesc scan;
ScanKeyData skey;
bool result;
catalog = heap_open(InheritsRelationId, AccessShareLock);
ScanKeyInit(&skey, Anum_pg_inherits_inhrelid, BTEqualStrategyNumber,
F_OIDEQ, ObjectIdGetDatum(relationId));
scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
NULL, 1, &skey);
result = HeapTupleIsValid(systable_getnext(scan));
systable_endscan(scan);
heap_close(catalog, AccessShareLock);
return result;
}
/*
* Given two type OIDs, determine whether the first is a complex type
......@@ -387,6 +411,86 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
return result;
}
/*
* Create a single pg_inherits row with the given data
*/
void
StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
{
Datum values[Natts_pg_inherits];
bool nulls[Natts_pg_inherits];
HeapTuple tuple;
Relation inhRelation;
inhRelation = heap_open(InheritsRelationId, RowExclusiveLock);
/*
* Make the pg_inherits entry
*/
values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(relationId);
values[Anum_pg_inherits_inhparent - 1] = ObjectIdGetDatum(parentOid);
values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(seqNumber);
memset(nulls, 0, sizeof(nulls));
tuple = heap_form_tuple(RelationGetDescr(inhRelation), values, nulls);
simple_heap_insert(inhRelation, tuple);
CatalogUpdateIndexes(inhRelation, tuple);
heap_freetuple(tuple);
heap_close(inhRelation, RowExclusiveLock);
}
/*
* DeleteInheritsTuple
*
* Delete pg_inherits tuples with the given inhrelid. inhparent may be given
* as InvalidOid, in which case all tuples matching inhrelid are deleted;
* otherwise only delete tuples with the specified inhparent.
*
* Returns whether at least one row was deleted.
*/
bool
DeleteInheritsTuple(Oid inhrelid, Oid inhparent)
{
bool found = false;
Relation catalogRelation;
ScanKeyData key;
SysScanDesc scan;
HeapTuple inheritsTuple;
/*
* Find pg_inherits entries by inhrelid.
*/
catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
ScanKeyInit(&key,
Anum_pg_inherits_inhrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(inhrelid));
scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
true, NULL, 1, &key);
while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
{
Oid parent;
/* Compare inhparent if it was given, and do the actual deletion. */
parent = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent;
if (!OidIsValid(inhparent) || parent == inhparent)
{
simple_heap_delete(catalogRelation, &inheritsTuple->t_self);
found = true;
}
}
/* Done */
systable_endscan(scan);
heap_close(catalogRelation, RowExclusiveLock);
return found;
}
/* qsort comparison function */
static int
......
......@@ -384,6 +384,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
toastIndexOid = GetPreassignedOidForRelation(namespaceid, toast_idxname);
toast_idxid = index_create(toast_rel, toast_idxname, toastIndexOid, InvalidOid,
InvalidOid, InvalidOid,
indexInfo,
list_make2("chunk_id", "chunk_seq"),
BTREE_AM_OID,
......
......@@ -48,6 +48,7 @@
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parser/parse_utilcmd.h"
#include "storage/lmgr.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
......@@ -67,6 +68,7 @@
typedef struct
{
char *key;
bool indexed_cons;
List *table_cons;
List *part_cons;
List *cand_cons;
......
......@@ -24,6 +24,9 @@
#include "catalog/catalog.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_tablespace.h"
......@@ -276,6 +279,7 @@ CheckIndexCompatible(Oid oldId,
indexInfo->ii_ExclusionOps = NULL;
indexInfo->ii_ExclusionProcs = NULL;
indexInfo->ii_ExclusionStrats = NULL;
indexInfo->ii_Am = accessMethodId;
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
......@@ -408,6 +412,7 @@ DefineIndex(Oid relationId,
Oid accessMethodId;
Oid namespaceId;
Oid tablespaceId;
Oid createdConstraintId = InvalidOid;
List *indexColNames;
Relation rel;
Relation indexRelation;
......@@ -429,7 +434,6 @@ DefineIndex(Oid relationId,
Snapshot snapshot;
bool need_longlock = true;
bool shouldDispatch;
char *altconname = stmt ? stmt->altconname : NULL;
int i;
if (Gp_role == GP_ROLE_DISPATCH && !IsBootstrapProcessingMode())
......@@ -707,6 +711,7 @@ DefineIndex(Oid relationId,
indexInfo->ii_ReadyForInserts = !stmt->concurrent;
indexInfo->ii_Concurrent = stmt->concurrent;
indexInfo->ii_BrokenHotChain = false;
indexInfo->ii_Am = accessMethodId;
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
......@@ -797,14 +802,15 @@ DefineIndex(Oid relationId,
* index. The caller should also decline any index build.
*/
Assert(!OidIsValid(stmt->oldNode) || (skip_build && !stmt->concurrent));
/*
* Make the catalog entries for the index, including constraints. Then, if
* not skip_build || concurrent, actually build the index.
*/
indexRelationId =
index_create(rel, indexRelationName, indexRelationId, stmt->oldNode,
indexInfo, indexColNames,
index_create(rel, indexRelationName, indexRelationId, stmt->parentIndexId,
stmt->parentConstraintId,
stmt->oldNode, indexInfo, indexColNames,
accessMethodId, tablespaceId,
collationObjectId, classObjectId,
coloptions, reloptions, stmt->primary,
......@@ -812,7 +818,7 @@ DefineIndex(Oid relationId,
allowSystemTableMods,
skip_build || stmt->concurrent,
stmt->concurrent, !check_rights,
altconname);
&createdConstraintId);
if (shouldDispatch)
{
......@@ -874,12 +880,16 @@ DefineIndex(Oid relationId,
foreach(lc, my_part_oids)
{
Oid childRelid = lfirst_oid(lc);
Relation childrel;
Relation childrel;
List *childidxs;
ListCell *cell;
AttrNumber *attmap;
int maplen;
bool found = false;
int maplen;
char *childnamespace_name;
childrel = heap_open(childRelid, lockmode);
childidxs = RelationGetIndexList(childrel);
attmap =
convert_tuples_by_name_map(RelationGetDescr(childrel),
parentDesc,
......@@ -888,8 +898,100 @@ DefineIndex(Oid relationId,
childnamespace_name = get_namespace_name(RelationGetNamespace(childrel));
foreach(cell, childidxs)
{
Oid cldidxid = lfirst_oid(cell);
Relation cldidx;
IndexInfo *cldIdxInfo;
/* this index is already partition of another one */
if (has_superclass(cldidxid))
continue;
cldidx = index_open(cldidxid, lockmode);
cldIdxInfo = BuildIndexInfo(cldidx);
if (CompareIndexInfo(cldIdxInfo, indexInfo,
cldidx->rd_indcollation,
collationObjectId,
cldidx->rd_opfamily,
opfamOids,
attmap, maplen))
{
Oid cldConstrOid = InvalidOid;
/*
* Found a match.
*
* If this index is being created in the parent
* because of a constraint, then the child needs to
* have a constraint also, so look for one. If there
* is no such constraint, this index is no good, so
* keep looking.
*/
if (createdConstraintId != InvalidOid)
{
cldConstrOid =
get_relation_idx_constraint_oid(childRelid,
cldidxid);
if (cldConstrOid == InvalidOid)
{
index_close(cldidx, lockmode);
continue;
}
}
/* Attach index to parent and we're done. */
IndexSetParentIndex(cldidx, indexRelationId);
if (createdConstraintId != InvalidOid)
ConstraintSetParentConstraint(cldConstrOid,
createdConstraintId);
if (shouldDispatch)
{
AlterTableCmd *altertableCmd = makeNode(AlterTableCmd);
altertableCmd->subtype = AT_PartAttachIndex;
AlterPartitionId *alterpartId = makeNode(AlterPartitionId);
alterpartId->idtype = AT_AP_IDRangeVar;
alterpartId->partiddef = (Node*) makeRangeVar(get_namespace_name(cldidx->rd_rel->relnamespace),
RelationGetRelationName(cldidx), -1);
AlterPartitionCmd * alterpartCmd = makeNode(AlterPartitionCmd);
alterpartCmd->partid = (Node*) alterpartId;
altertableCmd->def = (Node*) alterpartCmd;
AlterTableStmt *alterstmt = makeNode(AlterTableStmt);
alterstmt->relation = makeRangeVar(get_namespace_name(namespaceId),
indexRelationName, -1);
alterstmt->relkind = OBJECT_INDEX;
alterstmt->cmds = lappend(alterstmt->cmds, altertableCmd);
CdbDispatchUtilityStatement((Node *) alterstmt,
DF_CANCEL_ON_ERROR |
DF_WITH_SNAPSHOT |
DF_NEED_TWO_PHASE,
GetAssignedOidsForDispatch(),
NULL);
}
found = true;
/* keep lock till commit */
index_close(cldidx, NoLock);
break;
}
index_close(cldidx, lockmode);
}
list_free(childidxs);
heap_close(childrel, NoLock);
/*
* If no matching index was found, create our own.
*/
if (!found)
{
IndexStmt *childStmt = copyObject(stmt);
bool found_whole_row;
......@@ -928,6 +1030,14 @@ DefineIndex(Oid relationId,
childStmt->relation = makeRangeVar(childnamespace_name,
get_rel_name(childRelid), -1);
childStmt->idxname = NULL;
/*
* GPDB: Because we need to dispatch these values to the
* segments, put the parentIndexId and the
* parentConstraintId in the IndexStmt. In upstream
* Postgres these fields are parameters to DefineIndex.
*/
childStmt->parentIndexId = indexRelationId;
childStmt->parentConstraintId = createdConstraintId;
DefineIndex(childRelid, childStmt,
InvalidOid, /* no predefined OID */
......@@ -937,8 +1047,12 @@ DefineIndex(Oid relationId,
pfree(attmap);
}
}
/*
* In postgres the base relation of partitioned tables does not have
* storage. In GPDB the base relation DOES have storage so we probably need to
* finish up here?
*/
else
{
if (need_longlock)
......@@ -946,6 +1060,10 @@ DefineIndex(Oid relationId,
else
heap_close(rel, lockmode);
}
/*
* Indexes on partitioned tables are not themselves built, so we're
* done here.
*/
return indexRelationId;
}
......@@ -2432,3 +2550,148 @@ ReindexDatabase(ReindexStmt *stmt)
return MyDatabaseId;
}
/*
* Insert or delete an appropriate pg_inherits tuple to make the given index
* be a partition of the indicated parent index.
*
* This also corrects the pg_depend information for the affected index.
*/
void
IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
{
Relation pg_inherits;
ScanKeyData key[2];
SysScanDesc scan;
Oid partRelid = RelationGetRelid(partitionIdx);
HeapTuple tuple;
bool fix_dependencies;
/* Make sure this is an index */
Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX);
/*
* Scan pg_inherits for rows linking our index to some parent.
*/
pg_inherits = relation_open(InheritsRelationId, RowExclusiveLock);
ScanKeyInit(&key[0],
Anum_pg_inherits_inhrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(partRelid));
ScanKeyInit(&key[1],
Anum_pg_inherits_inhseqno,
BTEqualStrategyNumber, F_INT4EQ,
Int32GetDatum(1));
scan = systable_beginscan(pg_inherits, InheritsRelidSeqnoIndexId, true,
NULL, 2, key);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
{
if (parentOid == InvalidOid)
{
/*
* No pg_inherits row, and no parent wanted: nothing to do in
* this case.
*/
fix_dependencies = false;
}
else
{
Datum values[Natts_pg_inherits];
bool isnull[Natts_pg_inherits];
/*
* No pg_inherits row exists, and we want a parent for this index,
* so insert it.
*/
values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(partRelid);
values[Anum_pg_inherits_inhparent - 1] =
ObjectIdGetDatum(parentOid);
values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(1);
memset(isnull, false, sizeof(isnull));
tuple = heap_form_tuple(RelationGetDescr(pg_inherits),
values, isnull);
simple_heap_insert(pg_inherits, tuple);
CatalogUpdateIndexes(pg_inherits, tuple);
fix_dependencies = true;
}
}
else
{
Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
if (parentOid == InvalidOid)
{
/*
* There exists a pg_inherits row, which we want to clear; do so.
*/
simple_heap_delete(pg_inherits, &tuple->t_self);
fix_dependencies = true;
}
else
{
/*
* A pg_inherits row exists. If it's the same we want, then we're
* good; if it differs, that amounts to a corrupt catalog and
* should not happen.
*/
if (inhForm->inhparent != parentOid)
{
/* unexpected: we should not get called in this case */
elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
inhForm->inhrelid, inhForm->inhparent);
}
/* already in the right state */
fix_dependencies = false;
}
}
/* done with pg_inherits */
systable_endscan(scan);
relation_close(pg_inherits, RowExclusiveLock);
/* set relhassubclass if an index partition has been added to the parent */
if (OidIsValid(parentOid))
SetRelationHasSubclass(parentOid, true);
if (fix_dependencies)
{
ObjectAddress partIdx;
/*
* Insert/delete pg_depend rows. If setting a parent, add an
* INTERNAL_AUTO dependency to the parent index; if making standalone,
* remove all existing rows and put back the regular dependency on the
* table.
*/
ObjectAddressSet(partIdx, RelationRelationId, partRelid);
if (OidIsValid(parentOid))
{
ObjectAddress parentIdx;
ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
recordDependencyOn(&partIdx, &parentIdx, DEPENDENCY_INTERNAL_AUTO);
}
else
{
ObjectAddress partitionTbl;
ObjectAddressSet(partitionTbl, RelationRelationId,
partitionIdx->rd_index->indrelid);
deleteDependencyRecordsForClass(RelationRelationId, partRelid,
RelationRelationId,
DEPENDENCY_INTERNAL_AUTO);
recordDependencyOn(&partIdx, &partitionTbl, DEPENDENCY_AUTO);
}
/* make our updates visible */
CommandCounterIncrement();
}
}
此差异已折叠。
......@@ -3851,8 +3851,9 @@ _copyIndexStmt(const IndexStmt *from)
COPY_SCALAR_FIELD(deferrable);
COPY_SCALAR_FIELD(initdeferred);
COPY_SCALAR_FIELD(concurrent);
COPY_STRING_FIELD(altconname);
COPY_SCALAR_FIELD(is_split_part);
COPY_SCALAR_FIELD(parentIndexId);
COPY_SCALAR_FIELD(parentConstraintId);
return newnode;
}
......
......@@ -1388,8 +1388,9 @@ _equalIndexStmt(const IndexStmt *a, const IndexStmt *b)
COMPARE_SCALAR_FIELD(deferrable);
COMPARE_SCALAR_FIELD(initdeferred);
COMPARE_SCALAR_FIELD(concurrent);
COMPARE_STRING_FIELD(altconname);
COMPARE_SCALAR_FIELD(is_split_part);
COMPARE_SCALAR_FIELD(parentIndexId);
COMPARE_SCALAR_FIELD(parentConstraintId);
return true;
}
......
......@@ -2661,8 +2661,9 @@ _outIndexStmt(StringInfo str, const IndexStmt *node)
WRITE_BOOL_FIELD(deferrable);
WRITE_BOOL_FIELD(initdeferred);
WRITE_BOOL_FIELD(concurrent);
WRITE_STRING_FIELD(altconname);
WRITE_BOOL_FIELD(is_split_part);
WRITE_OID_FIELD(parentIndexId);
WRITE_OID_FIELD(parentConstraintId);
}
static void
......
......@@ -885,8 +885,9 @@ _readIndexStmt(void)
READ_BOOL_FIELD(deferrable);
READ_BOOL_FIELD(initdeferred);
READ_BOOL_FIELD(concurrent);
READ_STRING_FIELD(altconname);
READ_BOOL_FIELD(is_split_part);
READ_OID_FIELD(parentIndexId);
READ_OID_FIELD(parentConstraintId);
READ_DONE();
}
......
......@@ -151,6 +151,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString, bool createPartit
CreateStmtContext cxt;
List *result;
List *save_alist;
List *save_root_partition_alist = NIL;
ListCell *elements;
Oid namespaceid;
Oid existing_relid;
......@@ -340,7 +341,8 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString, bool createPartit
/*
* Postprocess constraints that give rise to index definitions.
*/
transformIndexConstraints(&cxt, stmt->is_add_part || stmt->is_split_part);
if (!stmt->is_part_child || stmt->is_split_part || stmt->is_add_part)
transformIndexConstraints(&cxt, stmt->is_add_part || stmt->is_split_part);
/*
* Carry any deferred analysis statements forward. Added for MPP-13750
......@@ -449,6 +451,17 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString, bool createPartit
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("PARTITION BY clause cannot be used with DISTRIBUTED REPLICATED clause")));
/*
* Save the alist for root partitions before transformPartitionBy adds the
* child create statements.
*/
if (stmt->partitionBy && !stmt->is_part_child)
{
save_root_partition_alist = cxt.alist;
cxt.alist = NIL;
}
/*
* Process table partitioning clause
*/
......@@ -462,6 +475,8 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString, bool createPartit
result = lappend(cxt.blist, stmt);
result = list_concat(result, cxt.alist);
if (stmt->partitionBy && !stmt->is_part_child)
result = list_concat(result, save_root_partition_alist);
result = list_concat(result, save_alist);
MemoryContextDelete(cxt.tempCtx);
......@@ -1204,7 +1219,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
List *indexprs;
ListCell *indexpr_item;
Oid indrelid;
Oid constraintId;
Oid constraintId = InvalidOid;
int keyno;
Oid keycoltype;
Datum datum;
......@@ -1345,24 +1360,13 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
index->isconstraint = false;
/*
* If the index backs a constraint, use the same name for the constraint
* as the source uses. This is particularly important for partitioned
* tables, as some places assume that when a partitioned table has
* a constraint, the constraint has the same name in all the partitions.
* GPDB: If we are splitting a partition, or creating a new child
* partition, set the parents of the relation in the index statement.
*/
if (index->isconstraint)
if (cxt->issplitpart || cxt->iscreatepart)
{
char *conname;
if (!OidIsValid(constraintId))
constraintId = get_index_constraint(source_relid);
conname = GetConstraintNameByOid(constraintId);
if (!conname)
elog(ERROR, "could not find constraint that index \"%s\" backs in source table",
RelationGetRelationName(source_idx));
index->altconname = conname;
index->parentIndexId = source_relid;
index->parentConstraintId = constraintId;
}
/* Get the index expressions, if any */
......@@ -2655,14 +2659,10 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
index->deferrable = constraint->deferrable;
index->initdeferred = constraint->initdeferred;
/*
* We used to force the index name to be the constraint name, but they
* are in different namespaces and so have different requirements for
* uniqueness. Here we leave the index name alone and put the constraint
* name in the IndexStmt, for use in DefineIndex.
*/
index->idxname = NULL; /* DefineIndex will choose name */
index->altconname = constraint->conname; /* User may have picked the name. */
if (constraint->conname != NULL)
index->idxname = pstrdup(constraint->conname);
else
index->idxname = NULL; /* DefineIndex will choose name */
index->relation = cxt->relation;
index->accessMethod = constraint->access_method ? constraint->access_method : DEFAULT_INDEX_TYPE;
......
......@@ -49,6 +49,20 @@
* Example: a trigger that's created to enforce a foreign-key constraint
* is made internally dependent on the constraint's pg_constraint entry.
*
* DEPENDENCY_INTERNAL_AUTO ('I'): the dependent object was created as
* part of creation of the referenced object, and is really just a part
* of its internal implementation. A DROP of the dependent object will
* be disallowed outright (we'll tell the user to issue a DROP against the
* referenced object, instead). While a regular internal dependency will
* prevent the dependent object from being dropped while any such
* dependencies remain, DEPENDENCY_INTERNAL_AUTO will allow such a drop as
* long as the object can be found by following any of such dependencies.
* Example: an index on a partition is made internal-auto-dependent on
* both the partition itself as well as on the index on the parent
* partitioned table; so the partition index is dropped together with
* either the partition it indexes, or with the parent index it is attached
* to.
*
* DEPENDENCY_EXTENSION ('e'): the dependent object is a member of the
* extension that is the referenced object. The dependent object can be
* dropped only via DROP EXTENSION on the referenced object. Functionally
......@@ -69,6 +83,7 @@ typedef enum DependencyType
DEPENDENCY_NORMAL = 'n',
DEPENDENCY_AUTO = 'a',
DEPENDENCY_INTERNAL = 'i',
DEPENDENCY_INTERNAL_AUTO = 'I',
DEPENDENCY_EXTENSION = 'e',
DEPENDENCY_PIN = 'p'
} DependencyType;
......
......@@ -15,6 +15,7 @@
#define INDEX_H
#include "access/relscan.h" /* Relation, Snapshot */
#include "catalog/objectaddress.h"
#include "executor/tuptable.h" /* TupTableSlot */
#include "nodes/execnodes.h"
......@@ -50,6 +51,8 @@ extern void index_check_primary_key(Relation heapRel,
extern Oid index_create(Relation heapRelation,
const char *indexRelationName,
Oid indexRelationId,
Oid parentIndexRelid,
Oid parentConstraintId,
Oid relFileNode,
IndexInfo *indexInfo,
List *indexColNames,
......@@ -67,10 +70,11 @@ extern Oid index_create(Relation heapRelation,
bool skip_build,
bool concurrent,
bool is_internal,
const char *altConName);
Oid *constraintId);
extern void index_constraint_create(Relation heapRelation,
extern ObjectAddress index_constraint_create(Relation heapRelation,
Oid indexRelationId,
Oid parentConstraintId,
IndexInfo *indexInfo,
const char *constraintName,
char constraintType,
......@@ -86,6 +90,11 @@ extern void index_drop(Oid indexId, bool concurrent);
extern IndexInfo *BuildIndexInfo(Relation index);
extern bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
Oid *collations1, Oid *collations2,
Oid *opfamilies1, Oid *opfamilies2,
AttrNumber *attmap, int maplen);
extern void FormIndexDatum(IndexInfo *indexInfo,
TupleTableSlot *slot,
struct EState *estate,
......@@ -125,4 +134,6 @@ extern bool ReindexIsProcessingHeap(Oid heapOid);
extern bool ReindexIsProcessingIndex(Oid indexOid);
extern Oid IndexGetRelation(Oid indexId, bool missing_ok);
extern void IndexSetParentIndex(Relation idx, Oid parentOid);
#endif /* INDEX_H */
......@@ -28,6 +28,16 @@ typedef struct ObjectAddress
int32 objectSubId; /* Subitem within object (eg column), or 0 */
} ObjectAddress;
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id) \
do { \
(addr).classId = (class_id); \
(addr).objectId = (object_id); \
(addr).objectSubId = (object_sub_id); \
} while (0)
#define ObjectAddressSet(addr, class_id, object_id) \
ObjectAddressSubSet(addr, class_id, object_id, 0)
extern ObjectAddress get_object_address(ObjectType objtype, List *objname,
List *objargs, Relation *relp,
LOCKMODE lockmode, bool missing_ok);
......
......@@ -256,6 +256,8 @@ extern char * GetConstraintNameByOid(Oid constraintId);
extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
Oid newNspId, bool isType, ObjectAddresses *objsMoved);
extern void ConstraintSetParentConstraint(Oid childConstrId,
Oid parentConstrId);
/**
* Identify primary key column from foreign key column.
*/
......@@ -264,6 +266,7 @@ extern bool ConstraintGetPrimaryKeyOf(Oid relid, AttrNumber attno,
extern void get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid);
extern Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok);
extern Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok);
extern Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId);
extern bool check_functional_grouping(Oid relid,
Index varno, Index varlevelsup,
......
......@@ -21,6 +21,10 @@ extern List *find_inheritance_children(Oid parentrelId, LOCKMODE lockmode);
extern List *find_all_inheritors(Oid parentrelId, LOCKMODE lockmode,
List **parents);
extern bool has_subclass(Oid relationId);
extern bool has_superclass(Oid relationId);
extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
extern void StoreSingleInheritance(Oid relationId, Oid parentOid,
int32 seqNumber);
extern bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent);
#endif /* PG_INHERITS_FN_H */
......@@ -84,6 +84,7 @@ typedef struct IndexInfo
bool ii_ReadyForInserts;
bool ii_Concurrent;
bool ii_BrokenHotChain;
Oid ii_Am;
} IndexInfo;
/* ----------------
......
......@@ -1507,7 +1507,8 @@ typedef enum AlterTableType
AT_PartSetTemplate, /* Set Subpartition Template */
AT_PartSplit, /* Split */
AT_PartTruncate, /* Truncate */
AT_PartAddInternal /* CREATE TABLE time partition addition */
AT_PartAddInternal, /* CREATE TABLE time partition addition */
AT_PartAttachIndex /* ALTER INDEX ATTACH PARTITION (not exposed to user) */
} AlterTableType;
typedef struct ReplicaIdentityStmt
......@@ -1555,7 +1556,8 @@ typedef enum AlterPartitionIdType
AT_AP_ID_oid, /* IDentifier by oid (for internal use only) */
AT_AP_IDList, /* List of IDentifier(for internal use only) */
AT_AP_IDRule, /* partition rule (for internal use only) */
AT_AP_IDDefault /* IDentify DEFAULT partition */
AT_AP_IDDefault, /* IDentify DEFAULT partition */
AT_AP_IDRangeVar /* IDentify Partition by RangeVar */
} AlterPartitionIdType;
typedef struct AlterPartitionId /* Identify a partition by name, val, pos */
......@@ -2713,9 +2715,9 @@ typedef struct IndexStmt
bool deferrable; /* is the constraint DEFERRABLE? */
bool initdeferred; /* is the constraint INITIALLY DEFERRED? */
bool concurrent; /* should this be a concurrent index build? */
char *altconname; /* constraint name, if desired name differs
* from idxname and isconstraint, else NULL. */
bool is_split_part; /* Is this for SPLIT PARTITION command? */
Oid parentIndexId; /* attach to a parent index if set */
Oid parentConstraintId; /* attach to a parent constraint if set */
} IndexStmt;
/* ----------------------
......
......@@ -4110,6 +4110,13 @@ select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
public | ti_1_prt_p3 | ti_1_prt_p3_j_idx | | CREATE INDEX ti_1_prt_p3_j_idx ON public.ti_1_prt_p3 USING bitmap (j)
(8 rows)
-- Should not be able to drop child indexes added implicitly via ADD PARTITION
drop index ti_1_prt_p3_i_idx;
ERROR: cannot drop index ti_1_prt_p3_i_idx because index ti_pkey requires it
HINT: You can drop index ti_pkey instead.
drop index ti_1_prt_p3_j_idx;
ERROR: cannot drop index ti_1_prt_p3_j_idx because index ti_j_idx requires it
HINT: You can drop index ti_j_idx instead.
alter table ti split partition p3 at (7) into (partition pnew1, partition pnew2);
NOTICE: exchanged partition "p3" of relation "ti" with relation "pg_temp_4039681"
NOTICE: dropped partition "p3" for relation "ti"
......@@ -4130,6 +4137,28 @@ select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
public | ti_1_prt_pnew2 | ti_1_prt_pnew2_j_idx | | CREATE INDEX ti_1_prt_pnew2_j_idx ON public.ti_1_prt_pnew2 USING bitmap (j)
(10 rows)
-- Should not be able to drop child indexes added implicitly via SPLIT PARTITION
drop index ti_1_prt_pnew1_i_idx;
ERROR: cannot drop index ti_1_prt_pnew1_i_idx because index ti_pkey requires it
HINT: You can drop index ti_pkey instead.
drop index ti_1_prt_pnew1_j_idx;
ERROR: cannot drop index ti_1_prt_pnew1_j_idx because index ti_j_idx requires it
HINT: You can drop index ti_j_idx instead.
drop index ti_1_prt_pnew2_i_idx;
ERROR: cannot drop index ti_1_prt_pnew2_i_idx because index ti_pkey requires it
HINT: You can drop index ti_pkey instead.
drop index ti_1_prt_pnew2_j_idx;
ERROR: cannot drop index ti_1_prt_pnew2_j_idx because index ti_j_idx requires it
HINT: You can drop index ti_j_idx instead.
-- Index drop should cascade to all partitions- including those later added via
-- ADD PARTITION or SPLIT PARTITION
drop index ti_pkey;
drop index ti_j_idx;
select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
schemaname | tablename | indexname | tablespace | indexdef
------------+-----------+-----------+------------+----------
(0 rows)
drop table ti;
-- MPP-6611, make sure rename works with default partitions
create table it (i int, j int) partition by range(i)
......
......@@ -1245,3 +1245,37 @@ insert into mpp6379( a, b ) values( 2, '20090102' );
ERROR: duplicate key value violates unique constraint "mpp6379_1_prt_p2_pkey"
DETAIL: Key (a, b)=(2, 01-02-2009) already exists.
drop table mpp6379;
-- Creating an index on a partitioned table makes the partitions
-- automatically get the index
create table idxpart (a int, b int, c text)
partition by range (a)
subpartition by range(b)
subpartition template
(start(1) end (3))
(start (1) end (3));
NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table.
HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
NOTICE: CREATE TABLE will create partition "idxpart_1_prt_1" for table "idxpart"
NOTICE: CREATE TABLE will create partition "idxpart_1_prt_1_2_prt_1" for table "idxpart_1_prt_1"
-- relhassubclass of a partitioned index is false before creating any partition.
-- It will be set after the first partition is created.
create index idxpart_idx on idxpart (a);
select relhassubclass from pg_class where relname = 'idxpart_idx';
relhassubclass
----------------
t
(1 row)
drop index idxpart_idx;
-- Even with partitions, relhassubclass should not be set if a partitioned
-- index is created only on the parent.
set sql_inheritance to off;
create index idxpart_idx on idxpart(a);
set sql_inheritance to on;
select relhassubclass from pg_class where relname = 'idxpart_idx';
relhassubclass
----------------
f
(1 row)
drop index idxpart_idx;
......@@ -4113,6 +4113,13 @@ select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
public | ti_1_prt_p3 | ti_1_prt_p3_j_idx | | CREATE INDEX ti_1_prt_p3_j_idx ON public.ti_1_prt_p3 USING bitmap (j)
(8 rows)
-- Should not be able to drop child indexes added implicitly via ADD PARTITION
drop index ti_1_prt_p3_i_idx;
ERROR: cannot drop index ti_1_prt_p3_i_idx because index ti_pkey requires it
HINT: You can drop index ti_pkey instead.
drop index ti_1_prt_p3_j_idx;
ERROR: cannot drop index ti_1_prt_p3_j_idx because index ti_j_idx requires it
HINT: You can drop index ti_j_idx instead.
alter table ti split partition p3 at (7) into (partition pnew1, partition pnew2);
NOTICE: exchanged partition "p3" of relation "ti" with relation "pg_temp_4039681"
NOTICE: dropped partition "p3" for relation "ti"
......@@ -4133,6 +4140,28 @@ select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
public | ti_1_prt_pnew1 | ti_1_prt_pnew1_j_idx | | CREATE INDEX ti_1_prt_pnew1_j_idx ON public.ti_1_prt_pnew1 USING bitmap (j)
(10 rows)
-- Should not be able to drop child indexes added implicitly via SPLIT PARTITION
drop index ti_1_prt_pnew1_i_idx;
ERROR: cannot drop index ti_1_prt_pnew1_i_idx because index ti_pkey requires it
HINT: You can drop index ti_pkey instead.
drop index ti_1_prt_pnew1_j_idx;
ERROR: cannot drop index ti_1_prt_pnew1_j_idx because index ti_j_idx requires it
HINT: You can drop index ti_j_idx instead.
drop index ti_1_prt_pnew2_i_idx;
ERROR: cannot drop index ti_1_prt_pnew2_i_idx because index ti_pkey requires it
HINT: You can drop index ti_pkey instead.
drop index ti_1_prt_pnew2_j_idx;
ERROR: cannot drop index ti_1_prt_pnew2_j_idx because index ti_j_idx requires it
HINT: You can drop index ti_j_idx instead.
-- Index drop should cascade to all partitions- including those later added via
-- ADD PARTITION or SPLIT PARTITION
drop index ti_pkey;
drop index ti_j_idx;
select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
schemaname | tablename | indexname | tablespace | indexdef
------------+-----------+-----------+------------+----------
(0 rows)
drop table ti;
-- MPP-6611, make sure rename works with default partitions
create table it (i int, j int) partition by range(i)
......
......@@ -2114,8 +2114,21 @@ create index ti_j_idx on ti using bitmap(j);
select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
alter table ti add partition p3 start(3) end(10);
select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
-- Should not be able to drop child indexes added implicitly via ADD PARTITION
drop index ti_1_prt_p3_i_idx;
drop index ti_1_prt_p3_j_idx;
alter table ti split partition p3 at (7) into (partition pnew1, partition pnew2);
select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
-- Should not be able to drop child indexes added implicitly via SPLIT PARTITION
drop index ti_1_prt_pnew1_i_idx;
drop index ti_1_prt_pnew1_j_idx;
drop index ti_1_prt_pnew2_i_idx;
drop index ti_1_prt_pnew2_j_idx;
-- Index drop should cascade to all partitions- including those later added via
-- ADD PARTITION or SPLIT PARTITION
drop index ti_pkey;
drop index ti_j_idx;
select * from pg_indexes where schemaname = 'public' and tablename like 'ti%';
drop table ti;
-- MPP-6611, make sure rename works with default partitions
......
......@@ -406,3 +406,26 @@ alter table mpp6379 add partition p2 end(date '2009-01-03');
insert into mpp6379( a, b ) values( 2, '20090102' );
insert into mpp6379( a, b ) values( 2, '20090102' );
drop table mpp6379;
-- Creating an index on a partitioned table makes the partitions
-- automatically get the index
create table idxpart (a int, b int, c text)
partition by range (a)
subpartition by range(b)
subpartition template
(start(1) end (3))
(start (1) end (3));
-- relhassubclass of a partitioned index is false before creating any partition.
-- It will be set after the first partition is created.
create index idxpart_idx on idxpart (a);
select relhassubclass from pg_class where relname = 'idxpart_idx';
drop index idxpart_idx;
-- Even with partitions, relhassubclass should not be set if a partitioned
-- index is created only on the parent.
set sql_inheritance to off;
create index idxpart_idx on idxpart(a);
set sql_inheritance to on;
select relhassubclass from pg_class where relname = 'idxpart_idx';
drop index idxpart_idx;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册