Ejemplo n.º 1
0
/**
 * @fn      Datum repack_index_swap(PG_FUNCTION_ARGS)
 * @brief   Swap out an original index on a table with the newly-created one.
 *
 * repack_index_swap(index)
 *
 * @param	index	Oid of the *original* index.
 * @retval	void
 */
Datum
repack_index_swap(PG_FUNCTION_ARGS)
{
	Oid                orig_idx_oid = PG_GETARG_OID(0);
	Oid                repacked_idx_oid;
	StringInfoData     str;
	SPITupleTable      *tuptable;
	TupleDesc          desc;
	HeapTuple          tuple;

	/* authority check */
	must_be_superuser("repack_index_swap");

	/* connect to SPI manager */
	repack_init();

	initStringInfo(&str);

	/* Find the OID of our new index. */
	appendStringInfo(&str, "SELECT oid FROM pg_class "
					 "WHERE relname = 'index_%u' AND relkind = 'i'",
					 orig_idx_oid);
	execute(SPI_OK_SELECT, str.data);
	if (SPI_processed != 1)
		elog(ERROR, "Could not find index 'index_%u', found " UINT64_FORMAT " matches",
			 orig_idx_oid, (uint64) SPI_processed);

	tuptable = SPI_tuptable;
	desc = tuptable->tupdesc;
	tuple = tuptable->vals[0];
	repacked_idx_oid = getoid(tuple, desc, 1);
	swap_heap_or_index_files(orig_idx_oid, repacked_idx_oid);
	SPI_finish();
	PG_RETURN_VOID();
}
Ejemplo n.º 2
0
/**
 * @fn      Datum reorg_swap(PG_FUNCTION_ARGS)
 * @brief   Swapping relfilenode of tables and relation ids of toast tables
 *          and toast indexes.
 *
 * reorg_swap(oid, relname)
 *
 * TODO: remove useless CommandCounterIncrement().
 *
 * @param	oid		Oid of table of target.
 * @retval			None.
 */
Datum
reorg_swap(PG_FUNCTION_ARGS)
{
    Oid				oid = PG_GETARG_OID(0);
    const char	   *relname = get_quoted_relname(oid);
    const char	   *nspname = get_quoted_nspname(oid);
    Oid 			argtypes[1] = { OIDOID };
    bool	 		nulls[1] = { 0 };
    Datum	 		values[1];
    SPITupleTable  *tuptable;
    TupleDesc		desc;
    HeapTuple		tuple;
    uint32			records;
    uint32			i;

    Oid				reltoastrelid1;
    Oid				reltoastidxid1;
    Oid				oid2;
    Oid				reltoastrelid2;
    Oid				reltoastidxid2;
    Oid				owner1;
    Oid				owner2;

    /* authority check */
    must_be_superuser("reorg_swap");

    /* connect to SPI manager */
    reorg_init();

    /* swap relfilenode and dependencies for tables. */
    values[0] = ObjectIdGetDatum(oid);
    execute_with_args(SPI_OK_SELECT,
                      "SELECT X.reltoastrelid, TX.reltoastidxid, X.relowner,"
                      "       Y.oid, Y.reltoastrelid, TY.reltoastidxid, Y.relowner"
                      "  FROM pg_catalog.pg_class X LEFT JOIN pg_catalog.pg_class TX"
                      "         ON X.reltoastrelid = TX.oid,"
                      "       pg_catalog.pg_class Y LEFT JOIN pg_catalog.pg_class TY"
                      "         ON Y.reltoastrelid = TY.oid"
                      " WHERE X.oid = $1"
                      "   AND Y.oid = ('reorg.table_' || X.oid)::regclass",
                      1, argtypes, values, nulls);

    tuptable = SPI_tuptable;
    desc = tuptable->tupdesc;
    records = SPI_processed;

    if (records == 0)
        elog(ERROR, "reorg_swap : no swap target");

    tuple = tuptable->vals[0];

    reltoastrelid1 = getoid(tuple, desc, 1);
    reltoastidxid1 = getoid(tuple, desc, 2);
    owner1 = getoid(tuple, desc, 3);
    oid2 = getoid(tuple, desc, 4);
    reltoastrelid2 = getoid(tuple, desc, 5);
    reltoastidxid2 = getoid(tuple, desc, 6);
    owner2 = getoid(tuple, desc, 7);

    /* change owner of new relation to original owner */
    if (owner1 != owner2)
    {
        ATExecChangeOwner(oid2, owner1, true, AccessExclusiveLock);
        CommandCounterIncrement();
    }

    /* swap tables. */
    swap_heap_or_index_files(oid, oid2);
    CommandCounterIncrement();

    /* swap indexes. */
    values[0] = ObjectIdGetDatum(oid);
    execute_with_args(SPI_OK_SELECT,
                      "SELECT X.oid, Y.oid"
                      "  FROM pg_catalog.pg_index I,"
                      "       pg_catalog.pg_class X,"
                      "       pg_catalog.pg_class Y"
                      " WHERE I.indrelid = $1"
                      "   AND I.indexrelid = X.oid"
                      "   AND I.indisvalid"
                      "   AND Y.oid = ('reorg.index_' || X.oid)::regclass",
                      1, argtypes, values, nulls);

    tuptable = SPI_tuptable;
    desc = tuptable->tupdesc;
    records = SPI_processed;

    for (i = 0; i < records; i++)
    {
        Oid		idx1, idx2;

        tuple = tuptable->vals[i];
        idx1 = getoid(tuple, desc, 1);
        idx2 = getoid(tuple, desc, 2);
        swap_heap_or_index_files(idx1, idx2);

        CommandCounterIncrement();
    }

    /* swap names for toast tables and toast indexes */
    if (reltoastrelid1 == InvalidOid)
    {
        if (reltoastidxid1 != InvalidOid ||
                reltoastrelid2 != InvalidOid ||
                reltoastidxid2 != InvalidOid)
            elog(ERROR, "reorg_swap : unexpected toast relations (T1=%u, I1=%u, T2=%u, I2=%u",
                 reltoastrelid1, reltoastidxid1, reltoastrelid2, reltoastidxid2);
        /* do nothing */
    }
    else if (reltoastrelid2 == InvalidOid)
    {
        char	name[NAMEDATALEN];

        if (reltoastidxid1 == InvalidOid ||
                reltoastidxid2 != InvalidOid)
            elog(ERROR, "reorg_swap : unexpected toast relations (T1=%u, I1=%u, T2=%u, I2=%u",
                 reltoastrelid1, reltoastidxid1, reltoastrelid2, reltoastidxid2);

        /* rename X to Y */
        snprintf(name, NAMEDATALEN, "pg_toast_%u", oid2);
        RENAME_REL(reltoastrelid1, name);
        snprintf(name, NAMEDATALEN, "pg_toast_%u_index", oid2);
        RENAME_REL(reltoastidxid1, name);
        CommandCounterIncrement();
    }
    else if (reltoastrelid1 != InvalidOid)
    {
        char	name[NAMEDATALEN];
        int		pid = getpid();

        /* rename X to TEMP */
        snprintf(name, NAMEDATALEN, "pg_toast_pid%d", pid);
        RENAME_REL(reltoastrelid1, name);
        snprintf(name, NAMEDATALEN, "pg_toast_pid%d_index", pid);
        RENAME_REL(reltoastidxid1, name);
        CommandCounterIncrement();

        /* rename Y to X */
        snprintf(name, NAMEDATALEN, "pg_toast_%u", oid);
        RENAME_REL(reltoastrelid2, name);
        snprintf(name, NAMEDATALEN, "pg_toast_%u_index", oid);
        RENAME_REL(reltoastidxid2, name);
        CommandCounterIncrement();

        /* rename TEMP to Y */
        snprintf(name, NAMEDATALEN, "pg_toast_%u", oid2);
        RENAME_REL(reltoastrelid1, name);
        snprintf(name, NAMEDATALEN, "pg_toast_%u_index", oid2);
        RENAME_REL(reltoastidxid1, name);
        CommandCounterIncrement();
    }

    /* drop reorg trigger */
    execute_with_format(
        SPI_OK_UTILITY,
        "DROP TRIGGER IF EXISTS z_reorg_trigger ON %s.%s CASCADE",
        nspname, relname);

    SPI_finish();

    PG_RETURN_VOID();
}