Пример #1
0
/**
 * @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));
}
Пример #2
0
/*
 * Copied from src/backend/commands/indexcmds.c, not exported.
 * Resolve possibly-defaulted operator class specification
 */
Oid
GetIndexOpClass(List *opclass, Oid attrType,
				char *accessMethodName, Oid accessMethodId)
{
	char	   *schemaname;
	char	   *opcname;
	HeapTuple	tuple;
	Oid			opClassId,
				opInputType;

	/*
	 * Release 7.0 removed network_ops, timespan_ops, and datetime_ops, so we
	 * ignore those opclass names so the default *_ops is used.  This can be
	 * removed in some later release.  bjm 2000/02/07
	 *
	 * Release 7.1 removes lztext_ops, so suppress that too for a while.  tgl
	 * 2000/07/30
	 *
	 * Release 7.2 renames timestamp_ops to timestamptz_ops, so suppress that
	 * too for awhile.  I'm starting to think we need a better approach. tgl
	 * 2000/10/01
	 *
	 * Release 8.0 removes bigbox_ops (which was dead code for a long while
	 * anyway).  tgl 2003/11/11
	 */
	if (list_length(opclass) == 1)
	{
		char	   *claname = strVal(linitial(opclass));

		if (strcmp(claname, "network_ops") == 0 ||
			strcmp(claname, "timespan_ops") == 0 ||
			strcmp(claname, "datetime_ops") == 0 ||
			strcmp(claname, "lztext_ops") == 0 ||
			strcmp(claname, "timestamp_ops") == 0 ||
			strcmp(claname, "bigbox_ops") == 0)
			opclass = NIL;
	}

	if (opclass == NIL)
	{
		/* no operator class specified, so find the default */
		opClassId = GetDefaultOpClass(attrType, accessMethodId);
		if (!OidIsValid(opClassId))
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_OBJECT),
					 errmsg("data type %s has no default operator class for access method \"%s\"",
							format_type_be(attrType), accessMethodName),
					 errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
		return opClassId;
	}

	/*
	 * Specific opclass name given, so look up the opclass.
	 */

	/* deconstruct the name list */
	DeconstructQualifiedName(opclass, &schemaname, &opcname);

	if (schemaname)
	{
		/* Look in specific schema only */
		Oid			namespaceId;

#if PG_VERSION_NUM >= 90300
		namespaceId = LookupExplicitNamespace(schemaname, false);
#else
		namespaceId = LookupExplicitNamespace(schemaname);
#endif
		tuple = SearchSysCache3(CLAAMNAMENSP,
								ObjectIdGetDatum(accessMethodId),
								PointerGetDatum(opcname),
								ObjectIdGetDatum(namespaceId));
	}
	else
	{
		/* Unqualified opclass name, so search the search path */
		opClassId = OpclassnameGetOpcid(accessMethodId, opcname);
		if (!OidIsValid(opClassId))
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_OBJECT),
					 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
							opcname, accessMethodName)));
		tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId));
	}

	if (!HeapTupleIsValid(tuple))
	{
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
						NameListToString(opclass), accessMethodName)));
	}

	/*
	 * Verify that the index operator class accepts this datatype.  Note we
	 * will accept binary compatibility.
	 */
	opClassId = HeapTupleGetOid(tuple);
	opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;

	if (!IsBinaryCoercible(attrType, opInputType))
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("operator class \"%s\" does not accept data type %s",
					  NameListToString(opclass), format_type_be(attrType))));

	ReleaseSysCache(tuple);

	return opClassId;
}