code for Global-Partition-Index feature

Signed-off-by: xiliu <xiliu_h@163.com>
This commit is contained in:
xiliu
2020-08-25 15:10:14 +08:00
parent 339cd59f26
commit c040d78287
157 changed files with 12502 additions and 939 deletions

View File

@ -2149,9 +2149,10 @@ static IndexStmt* generateClonedIndexStmt(
}
/* Build the list of IndexElem */
index->indexParams = NIL;
index->indexIncludingParams = NIL;
indexprItem = list_head(indexprs);
for (keyno = 0; keyno < idxrec->indnatts; keyno++) {
for (keyno = 0; keyno < idxrec->indnkeyatts; keyno++) {
IndexElem* iparam = NULL;
AttrNumber attnum = idxrec->indkey.values[keyno];
uint16 opt = (uint16)source_idx->rd_indoption[keyno];
@ -2240,6 +2241,12 @@ static IndexStmt* generateClonedIndexStmt(
}
}
/* Handle included columns separately */
if (idxrec->indnkeyatts != idxrec->indnatts) {
/* Only global-partition-index would satisfy this condition in the current code */
index->isGlobal = true;
}
/* Copy reloptions if any */
datum = SysCacheGetAttr(RELOID, htIdxrel, Anum_pg_class_reloptions, &isnull);
if (!isnull)
@ -2473,6 +2480,7 @@ static void transformIndexConstraints(CreateStmtContext* cxt)
IndexStmt* priorindex = (IndexStmt*)lfirst(k);
if (equal(index->indexParams, priorindex->indexParams) &&
equal(index->indexIncludingParams, priorindex->indexIncludingParams) &&
equal(index->whereClause, priorindex->whereClause) &&
equal(index->excludeOpNames, priorindex->excludeOpNames) &&
strcmp(index->accessMethod, priorindex->accessMethod) == 0 &&
@ -2630,6 +2638,7 @@ static IndexStmt* transformIndexConstraint(Constraint* constraint, CreateStmtCon
index->tableSpace = constraint->indexspace;
index->whereClause = constraint->where_clause;
index->indexParams = NIL;
index->indexIncludingParams = NIL;
index->excludeOpNames = NIL;
index->idxcomment = NULL;
index->indexOid = InvalidOid;
@ -2724,22 +2733,26 @@ static IndexStmt* transformIndexConstraint(Constraint* constraint, CreateStmtCon
RELATION_HAS_BUCKET(heapRel));
attname = pstrdup(NameStr(attform->attname));
/*
* Insist on default opclass and sort options. While the index
* would still work as a constraint with non-default settings, it
* might not provide exactly the same uniqueness semantics as
* you'd get from a normally-created constraint; and there's also
* the dump/reload problem mentioned above.
*/
defopclass = GetDefaultOpClass(attform->atttypid, indexRel->rd_rel->relam);
if (indclass->values[i] != defopclass || indexRel->rd_indoption[i] != 0)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("index \"%s\" does not have default sorting behavior", indexName),
errdetail("Cannot create a primary key or unique constraint using such an index."),
parser_errposition(cxt->pstate, constraint->location)));
if (i < indexForm->indnkeyatts) {
/*
* Insist on default opclass and sort options. While the
* index would still work as a constraint with non-default
* settings, it might not provide exactly the same uniqueness
* semantics as you'd get from a normally-created constraint;
* and there's also the dump/reload problem mentioned above.
*/
defopclass = GetDefaultOpClass(attform->atttypid, indexRel->rd_rel->relam);
if (indclass->values[i] != defopclass || indexRel->rd_indoption[i] != 0)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("index \"%s\" does not have default sorting behavior", indexName),
errdetail("Cannot create a primary key or unique constraint using such an index."),
parser_errposition(cxt->pstate, constraint->location)));
constraint->keys = lappend(constraint->keys, makeString(attname));
constraint->keys = lappend(constraint->keys, makeString(attname));
} else {
constraint->including = lappend(constraint->including, makeString(attname));
}
}
/* Close the index relation but keep the lock */
@ -2768,80 +2781,200 @@ static IndexStmt* transformIndexConstraint(Constraint* constraint, CreateStmtCon
index->indexParams = lappend(index->indexParams, elem);
index->excludeOpNames = lappend(index->excludeOpNames, opname);
}
} else {
return index;
/*
* For UNIQUE and PRIMARY KEY, we just have a list of column names.
*
* Make sure referenced keys exist. If we are making a PRIMARY KEY index,
* also make sure they are NOT NULL, if possible. (Although we could leave
* it to DefineIndex to mark the columns NOT NULL, it's more efficient to
* get it right the first time.)
*/
foreach (lc, constraint->keys) {
char* key = strVal(lfirst(lc));
bool found = false;
ColumnDef* column = NULL;
ListCell* columns = NULL;
IndexElem* iparam = NULL;
foreach (columns, cxt->columns) {
column = (ColumnDef*)lfirst(columns);
AssertEreport(IsA(column, ColumnDef), MOD_OPT, "");
if (strcmp(column->colname, key) == 0) {
found = true;
break;
}
}
if (found) {
/* found column in the new table; force it to be NOT NULL */
if (constraint->contype == CONSTR_PRIMARY && !constraint->inforConstraint->nonforced)
column->is_not_null = TRUE;
} else if (SystemAttributeByName(key, cxt->hasoids) != NULL) {
/*
* column will be a system column in the new table, so accept it.
* System columns can't ever be null, so no need to worry about
* PRIMARY/NOT NULL constraint.
*/
found = true;
} else if (cxt->inhRelations != NIL) {
/* try inherited tables */
ListCell* inher = NULL;
foreach (inher, cxt->inhRelations) {
RangeVar* inh = (RangeVar*)lfirst(inher);
Relation rel;
int count;
AssertEreport(IsA(inh, RangeVar), MOD_OPT, "");
rel = heap_openrv(inh, AccessShareLock);
if (rel->rd_rel->relkind != RELKIND_RELATION)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("inherited relation \"%s\" is not a table", inh->relname)));
for (count = 0; count < rel->rd_att->natts; count++) {
Form_pg_attribute inhattr = rel->rd_att->attrs[count];
char* inhname = NameStr(inhattr->attname);
if (inhattr->attisdropped)
continue;
if (strcmp(key, inhname) == 0) {
found = true;
/*
* We currently have no easy way to force an inherited
* column to be NOT NULL at creation, if its parent
* wasn't so already. We leave it to DefineIndex to
* fix things up in this case.
*/
break;
}
}
heap_close(rel, NoLock);
if (found)
break;
}
}
/*
* In the ALTER TABLE case, don't complain about index keys not
* created in the command; they may well exist already. DefineIndex
* will complain about them if not, and will also take care of marking
* them NOT NULL.
*/
if (!found && !cxt->isalter)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" named in key does not exist", key),
parser_errposition(cxt->pstate, constraint->location)));
/* Check for PRIMARY KEY(foo, foo) */
foreach (columns, index->indexParams) {
iparam = (IndexElem*)lfirst(columns);
if (iparam->name && strcmp(key, iparam->name) == 0) {
if (index->primary)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column \"%s\" appears twice in primary key constraint", key),
parser_errposition(cxt->pstate, constraint->location)));
else
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column \"%s\" appears twice in unique constraint", key),
parser_errposition(cxt->pstate, constraint->location)));
}
}
#ifdef PGXC
/*
* Set fallback distribution column.
* If not set, set it to first column in index.
* If primary key, we prefer that over a unique constraint.
*/
if (index->indexParams == NIL && (index->primary || cxt->fallback_dist_col == NULL)) {
if (cxt->fallback_dist_col != NULL) {
list_free_deep(cxt->fallback_dist_col);
cxt->fallback_dist_col = NULL;
}
cxt->fallback_dist_col = lappend(cxt->fallback_dist_col, makeString(pstrdup(key)));
}
#endif
/* OK, add it to the index definition */
iparam = makeNode(IndexElem);
iparam->name = pstrdup(key);
iparam->expr = NULL;
iparam->indexcolname = NULL;
iparam->collation = NIL;
iparam->opclass = NIL;
iparam->ordering = SORTBY_DEFAULT;
iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
index->indexParams = lappend(index->indexParams, iparam);
}
}
/*
* For UNIQUE and PRIMARY KEY, we just have a list of column names.
*
* Make sure referenced keys exist. If we are making a PRIMARY KEY index,
* also make sure they are NOT NULL, if possible. (Although we could leave
* it to DefineIndex to mark the columns NOT NULL, it's more efficient to
* get it right the first time.)
*/
foreach (lc, constraint->keys) {
/* Add included columns to index definition */
foreach (lc, constraint->including) {
char* key = strVal(lfirst(lc));
bool found = false;
ColumnDef* column = NULL;
ListCell* columns = NULL;
IndexElem* iparam = NULL;
ListCell* columns;
IndexElem* iparam;
foreach (columns, cxt->columns) {
column = (ColumnDef*)lfirst(columns);
AssertEreport(IsA(column, ColumnDef), MOD_OPT, "");
column = lfirst_node(ColumnDef, columns);
if (strcmp(column->colname, key) == 0) {
found = true;
break;
}
}
if (found) {
/* found column in the new table; force it to be NOT NULL */
if (constraint->contype == CONSTR_PRIMARY && !constraint->inforConstraint->nonforced)
column->is_not_null = TRUE;
} else if (SystemAttributeByName(key, cxt->hasoids) != NULL) {
/*
* column will be a system column in the new table, so accept it.
* System columns can't ever be null, so no need to worry about
* PRIMARY/NOT NULL constraint.
*/
found = true;
} else if (cxt->inhRelations != NIL) {
/* try inherited tables */
ListCell* inher = NULL;
foreach (inher, cxt->inhRelations) {
RangeVar* inh = (RangeVar*)lfirst(inher);
Relation rel;
int count;
if (!found) {
if (SystemAttributeByName(key, cxt->hasoids) != NULL) {
/*
* column will be a system column in the new table, so accept
* it. System columns can't ever be null, so no need to worry
* about PRIMARY/NOT NULL constraint.
*/
found = true;
} else if (cxt->inhRelations) {
/* try inherited tables */
ListCell* inher;
AssertEreport(IsA(inh, RangeVar), MOD_OPT, "");
rel = heap_openrv(inh, AccessShareLock);
if (rel->rd_rel->relkind != RELKIND_RELATION)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("inherited relation \"%s\" is not a table", inh->relname)));
for (count = 0; count < rel->rd_att->natts; count++) {
Form_pg_attribute inhattr = rel->rd_att->attrs[count];
char* inhname = NameStr(inhattr->attname);
foreach (inher, cxt->inhRelations) {
RangeVar* inh = lfirst_node(RangeVar, inher);
Relation rel;
int count;
if (inhattr->attisdropped)
continue;
if (strcmp(key, inhname) == 0) {
found = true;
rel = heap_openrv(inh, AccessShareLock);
/* check user requested inheritance from valid relkind */
if (rel->rd_rel->relkind != RELKIND_RELATION && rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
rel->rd_rel->relkind != PARTTYPE_PARTITIONED_RELATION)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("inherited relation \"%s\" is not a table or foreign table", inh->relname)));
for (count = 0; count < rel->rd_att->natts; count++) {
Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att, count);
char* inhname = NameStr(inhattr->attname);
/*
* We currently have no easy way to force an inherited
* column to be NOT NULL at creation, if its parent
* wasn't so already. We leave it to DefineIndex to
* fix things up in this case.
*/
break;
if (inhattr->attisdropped)
continue;
if (strcmp(key, inhname) == 0) {
found = true;
/*
* We currently have no easy way to force an
* inherited column to be NOT NULL at creation, if
* its parent wasn't so already. We leave it to
* DefineIndex to fix things up in this case.
*/
break;
}
}
heap_close(rel, NoLock);
if (found)
break;
}
heap_close(rel, NoLock);
if (found)
break;
}
}
@ -2857,38 +2990,6 @@ static IndexStmt* transformIndexConstraint(Constraint* constraint, CreateStmtCon
errmsg("column \"%s\" named in key does not exist", key),
parser_errposition(cxt->pstate, constraint->location)));
/* Check for PRIMARY KEY(foo, foo) */
foreach (columns, index->indexParams) {
iparam = (IndexElem*)lfirst(columns);
if (iparam->name && strcmp(key, iparam->name) == 0) {
if (index->primary)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column \"%s\" appears twice in primary key constraint", key),
parser_errposition(cxt->pstate, constraint->location)));
else
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column \"%s\" appears twice in unique constraint", key),
parser_errposition(cxt->pstate, constraint->location)));
}
}
#ifdef PGXC
/*
* Set fallback distribution column.
* If not set, set it to first column in index.
* If primary key, we prefer that over a unique constraint.
*/
if (index->indexParams == NIL && (index->primary || cxt->fallback_dist_col == NULL)) {
if (cxt->fallback_dist_col != NULL) {
list_free_deep(cxt->fallback_dist_col);
cxt->fallback_dist_col = NULL;
}
cxt->fallback_dist_col = lappend(cxt->fallback_dist_col, makeString(pstrdup(key)));
}
#endif
/* OK, add it to the index definition */
iparam = makeNode(IndexElem);
iparam->name = pstrdup(key);
@ -2896,9 +2997,7 @@ static IndexStmt* transformIndexConstraint(Constraint* constraint, CreateStmtCon
iparam->indexcolname = NULL;
iparam->collation = NIL;
iparam->opclass = NIL;
iparam->ordering = SORTBY_DEFAULT;
iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
index->indexParams = lappend(index->indexParams, iparam);
index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
}
return index;
@ -3062,9 +3161,23 @@ IndexStmt* transformIndexStmt(Oid relid, IndexStmt* stmt, const char* queryStrin
/* row store using btree index by default */
stmt->accessMethod = DEFAULT_INDEX_TYPE;
} else {
if (stmt->isGlobal) {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Global partition index does not support column store.")));
}
/* column store using psort index by default */
stmt->accessMethod = DEFAULT_CSTORE_INDEX_TYPE;
}
} else if (stmt->isGlobal) {
/* Global partition index only support btree index */
if (pg_strcasecmp(stmt->accessMethod, DEFAULT_INDEX_TYPE) != 0) {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Global partition index only support btree.")));
}
if (isColStore) {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Global partition index does not support column store.")));
}
} else {
bool isDfsStore = RelationIsDfsStore(rel);
const bool isPsortMothed = (0 == pg_strcasecmp(stmt->accessMethod, DEFAULT_CSTORE_INDEX_TYPE));