/** * @fn Datum reorg_indexdef(PG_FUNCTION_ARGS) * @brief Reproduce DDL that create index at the temp table. * * reorg_indexdef(index, table) * * @param index Oid of target index. * @param table Oid of table of the index. * @retval Create index DDL for temp table. */ Datum reorg_indexdef(PG_FUNCTION_ARGS) { Oid index = PG_GETARG_OID(0); Oid table = PG_GETARG_OID(1); IndexDef stmt; StringInfoData str; parse_indexdef(&stmt, index, table); initStringInfo(&str); appendStringInfo(&str, "%s index_%u ON reorg.table_%u USING %s (%s)%s", stmt.create, index, table, stmt.type, stmt.columns, stmt.options); PG_RETURN_TEXT_P(cstring_to_text(str.data)); }
/** * @fn Datum repack_indexdef(PG_FUNCTION_ARGS) * @brief Reproduce DDL that create index at the temp table. * * repack_indexdef(index, table) * * @param index Oid of target index. * @param table Oid of table of the index. * @param tablespace Namespace for the index. If NULL keep the original. * @param boolean Whether to use CONCURRENTLY when creating the index. * @retval Create index DDL for temp table. */ Datum repack_indexdef(PG_FUNCTION_ARGS) { Oid index; Oid table; Name tablespace = NULL; IndexDef stmt; StringInfoData str; bool concurrent_index = PG_GETARG_BOOL(3); if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) PG_RETURN_NULL(); index = PG_GETARG_OID(0); table = PG_GETARG_OID(1); if (!PG_ARGISNULL(2)) tablespace = PG_GETARG_NAME(2); parse_indexdef(&stmt, index, table); initStringInfo(&str); if (concurrent_index) appendStringInfo(&str, "%s CONCURRENTLY index_%u ON %s USING %s (%s)%s", stmt.create, index, stmt.table, stmt.type, stmt.columns, stmt.options); else appendStringInfo(&str, "%s index_%u ON repack.table_%u USING %s (%s)%s", stmt.create, index, table, stmt.type, stmt.columns, stmt.options); /* specify the new tablespace or the original one if any */ if (tablespace || stmt.tablespace) appendStringInfo(&str, " TABLESPACE %s", (tablespace ? NameStr(*tablespace) : stmt.tablespace)); if (stmt.where) appendStringInfo(&str, " WHERE %s", stmt.where); PG_RETURN_TEXT_P(cstring_to_text(str.data)); }
/** * @fn Datum reorg_get_index_keys(PG_FUNCTION_ARGS) * @brief Get key definition of the index. * * reorg_get_index_keys(index, table) * * @param index Oid of target index. * @param table Oid of table of the index. * @retval Create index DDL for temp table. * * FIXME: this function is named get_index_keys, but actually returns * an expression for ORDER BY clause. get_order_by() might be a better name. */ Datum reorg_get_index_keys(PG_FUNCTION_ARGS) { Oid index = PG_GETARG_OID(0); Oid table = PG_GETARG_OID(1); IndexDef stmt; char *token; char *next; StringInfoData str; Relation indexRel = NULL; int nattr; parse_indexdef(&stmt, index, table); elog(DEBUG2, "indexdef.create = %s", stmt.create); elog(DEBUG2, "indexdef.index = %s", stmt.index); elog(DEBUG2, "indexdef.table = %s", stmt.table); elog(DEBUG2, "indexdef.type = %s", stmt.type); elog(DEBUG2, "indexdef.columns = %s", stmt.columns); elog(DEBUG2, "indexdef.options = %s", stmt.options); /* * FIXME: this is very unreliable implementation but I don't want to * re-implement customized versions of pg_get_indexdef_string... * * TODO: Support ASC/DESC and NULL FIRST/LAST. */ initStringInfo(&str); for (nattr = 0, next = stmt.columns; next; nattr++) { char *opcname; token = next; while (isspace((unsigned char) *token)) token++; next = skip_until(index, next, ','); opcname = skip_until(index, token, ' '); if (opcname) { /* lookup default operator name from operator class */ Oid opclass; Oid oprid; int16 strategy = BTLessStrategyNumber; Oid opcintype; Oid opfamily; HeapTuple tp; Form_pg_opclass opclassTup; opclass = OpclassnameGetOpcid(BTREE_AM_OID, opcname); /* Retrieve operator information. */ tp = SearchSysCache(CLAOID, ObjectIdGetDatum(opclass), 0, 0, 0); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for opclass %u", opclass); opclassTup = (Form_pg_opclass) GETSTRUCT(tp); opfamily = opclassTup->opcfamily; opcintype = opclassTup->opcintype; ReleaseSysCache(tp); if (!OidIsValid(opcintype)) { if (indexRel == NULL) indexRel = index_open(index, NoLock); opcintype = RelationGetDescr(indexRel)->attrs[nattr]->atttypid; } oprid = get_opfamily_member(opfamily, opcintype, opcintype, strategy); if (!OidIsValid(oprid)) elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", strategy, opcintype, opcintype, opfamily); opcname[-1] = '\0'; appendStringInfo(&str, "%s USING %s", token, get_opname(oprid)); } else appendStringInfoString(&str, token); if (next) appendStringInfoString(&str, ", "); } if (indexRel != NULL) index_close(indexRel, NoLock); PG_RETURN_TEXT_P(cstring_to_text(str.data)); }