📄 indexcmds.c
字号:
int overhead = 0; /* chars needed for label and underscores */ int availchars; /* chars available for name(s) */ int name1chars; /* chars allocated to name1 */ int name2chars; /* chars allocated to name2 */ int ndx; name1chars = strlen(name1); if (name2) { name2chars = strlen(name2); overhead++; /* allow for separating underscore */ } else name2chars = 0; if (label) overhead += strlen(label) + 1; availchars = NAMEDATALEN - 1 - overhead; Assert(availchars > 0); /* else caller chose a bad label */ /* * If we must truncate, preferentially truncate the longer name. This * logic could be expressed without a loop, but it's simple and obvious as * a loop. */ while (name1chars + name2chars > availchars) { if (name1chars > name2chars) name1chars--; else name2chars--; } name1chars = pg_mbcliplen(name1, name1chars, name1chars); if (name2) name2chars = pg_mbcliplen(name2, name2chars, name2chars); /* Now construct the string using the chosen lengths */ name = palloc(name1chars + name2chars + overhead + 1); memcpy(name, name1, name1chars); ndx = name1chars; if (name2) { name[ndx++] = '_'; memcpy(name + ndx, name2, name2chars); ndx += name2chars; } if (label) { name[ndx++] = '_'; strcpy(name + ndx, label); } else name[ndx] = '\0'; return name;}/* * Select a nonconflicting name for a new relation. This is ordinarily * used to choose index names (which is why it's here) but it can also * be used for sequences, or any autogenerated relation kind. * * name1, name2, and label are used the same way as for makeObjectName(), * except that the label can't be NULL; digits will be appended to the label * if needed to create a name that is unique within the specified namespace. * * Note: it is theoretically possible to get a collision anyway, if someone * else chooses the same name concurrently. This is fairly unlikely to be * a problem in practice, especially if one is holding an exclusive lock on * the relation identified by name1. However, if choosing multiple names * within a single command, you'd better create the new object and do * CommandCounterIncrement before choosing the next one! * * Returns a palloc'd string. */char *ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespace){ int pass = 0; char *relname = NULL; char modlabel[NAMEDATALEN]; /* try the unmodified label first */ StrNCpy(modlabel, label, sizeof(modlabel)); for (;;) { relname = makeObjectName(name1, name2, modlabel); if (!OidIsValid(get_relname_relid(relname, namespace))) break; /* found a conflict, so try a new name component */ pfree(relname); snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass); } return relname;}/* * relationHasPrimaryKey - * * See whether an existing relation has a primary key. */static boolrelationHasPrimaryKey(Relation rel){ bool result = false; List *indexoidlist; ListCell *indexoidscan; /* * Get the list of index OIDs for the table from the relcache, and look up * each one in the pg_index syscache until we find one marked primary key * (hopefully there isn't more than one such). */ indexoidlist = RelationGetIndexList(rel); foreach(indexoidscan, indexoidlist) { Oid indexoid = lfirst_oid(indexoidscan); HeapTuple indexTuple; indexTuple = SearchSysCache(INDEXRELID, ObjectIdGetDatum(indexoid), 0, 0, 0); if (!HeapTupleIsValid(indexTuple)) /* should not happen */ elog(ERROR, "cache lookup failed for index %u", indexoid); result = ((Form_pg_index) GETSTRUCT(indexTuple))->indisprimary; ReleaseSysCache(indexTuple); if (result) break; } list_free(indexoidlist); return result;}/* * RemoveIndex * Deletes an index. */voidRemoveIndex(RangeVar *relation, DropBehavior behavior){ Oid indOid; char relkind; ObjectAddress object; indOid = RangeVarGetRelid(relation, false); relkind = get_rel_relkind(indOid); if (relkind != RELKIND_INDEX) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not an index", relation->relname))); object.classId = RelationRelationId; object.objectId = indOid; object.objectSubId = 0; performDeletion(&object, behavior);}/* * ReindexIndex * Recreate a specific index. */voidReindexIndex(RangeVar *indexRelation){ Oid indOid; HeapTuple tuple; indOid = RangeVarGetRelid(indexRelation, false); tuple = SearchSysCache(RELOID, ObjectIdGetDatum(indOid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for relation %u", indOid); if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not an index", indexRelation->relname))); /* Check permissions */ if (!pg_class_ownercheck(indOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, indexRelation->relname); ReleaseSysCache(tuple); reindex_index(indOid);}/* * ReindexTable * Recreate all indexes of a table (and of its toast table, if any) */voidReindexTable(RangeVar *relation){ Oid heapOid; HeapTuple tuple; heapOid = RangeVarGetRelid(relation, false); tuple = SearchSysCache(RELOID, ObjectIdGetDatum(heapOid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for relation %u", heapOid); if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_RELATION && ((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_TOASTVALUE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", relation->relname))); /* Check permissions */ if (!pg_class_ownercheck(heapOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, relation->relname); /* Can't reindex shared tables except in standalone mode */ if (((Form_pg_class) GETSTRUCT(tuple))->relisshared && IsUnderPostmaster) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("shared table \"%s\" can only be reindexed in stand-alone mode", relation->relname))); ReleaseSysCache(tuple); if (!reindex_relation(heapOid, true)) ereport(NOTICE, (errmsg("table \"%s\" has no indexes", relation->relname)));}/* * ReindexDatabase * Recreate indexes of a database. * * To reduce the probability of deadlocks, each table is reindexed in a * separate transaction, so we can release the lock on it right away. */voidReindexDatabase(const char *databaseName, bool do_system, bool do_user){ Relation relationRelation; HeapScanDesc scan; HeapTuple tuple; MemoryContext private_context; MemoryContext old; List *relids = NIL; ListCell *l; AssertArg(databaseName); if (strcmp(databaseName, get_database_name(MyDatabaseId)) != 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("can only reindex the currently open database"))); if (!pg_database_ownercheck(MyDatabaseId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, databaseName); /* * We cannot run inside a user transaction block; if we were inside a * transaction, then our commit- and start-transaction-command calls would * not have the intended effect! */ PreventTransactionChain((void *) databaseName, "REINDEX DATABASE"); /* * Create a memory context that will survive forced transaction commits we * do below. Since it is a child of PortalContext, it will go away * eventually even if we suffer an error; there's no need for special * abort cleanup logic. */ private_context = AllocSetContextCreate(PortalContext, "ReindexDatabase", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* * We always want to reindex pg_class first. This ensures that if there * is any corruption in pg_class' indexes, they will be fixed before we * process any other tables. This is critical because reindexing itself * will try to update pg_class. */ if (do_system) { old = MemoryContextSwitchTo(private_context); relids = lappend_oid(relids, RelationRelationId); MemoryContextSwitchTo(old); } /* * Scan pg_class to build a list of the relations we need to reindex. * * We only consider plain relations here (toast rels will be processed * indirectly by reindex_relation). */ relationRelation = heap_open(RelationRelationId, AccessShareLock); scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple); if (classtuple->relkind != RELKIND_RELATION) continue; /* Check user/system classification, and optionally skip */ if (IsSystemClass(classtuple)) { if (!do_system) continue; } else { if (!do_user) continue; } if (IsUnderPostmaster) /* silently ignore shared tables */ { if (classtuple->relisshared) continue; } if (HeapTupleGetOid(tuple) == RelationRelationId) continue; /* got it already */ old = MemoryContextSwitchTo(private_context); relids = lappend_oid(relids, HeapTupleGetOid(tuple)); MemoryContextSwitchTo(old); } heap_endscan(scan); heap_close(relationRelation, AccessShareLock); /* Now reindex each rel in a separate transaction */ CommitTransactionCommand(); foreach(l, relids) { Oid relid = lfirst_oid(l); StartTransactionCommand(); /* functions in indexes may want a snapshot set */ ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); if (reindex_relation(relid, true)) ereport(NOTICE, (errmsg("table \"%s\" was reindexed", get_rel_name(relid)))); CommitTransactionCommand(); } StartTransactionCommand(); MemoryContextDelete(private_context);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -