Ejemplo n.º 1
0
static char *
format_type_internal(Oid type_oid, int32 typemod,
					 bool typemod_given, bool allow_invalid)
{
	bool		with_typemod = typemod_given && (typemod >= 0);
	HeapTuple	tuple;
	Form_pg_type typeform;
	Oid			array_base_type;
	bool		is_array;
	char	   *buf;

	if (type_oid == InvalidOid && allow_invalid)
		return pstrdup("-");

	tuple = SearchSysCache(TYPEOID,
						   ObjectIdGetDatum(type_oid),
						   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
	{
		if (allow_invalid)
			return pstrdup("???");
		else
			elog(ERROR, "cache lookup failed for type %u", type_oid);
	}
	typeform = (Form_pg_type) GETSTRUCT(tuple);

	/*
	 * Check if it's an array (and not a domain --- we don't want to show the
	 * substructure of a domain type).	Fixed-length array types such as
	 * "name" shouldn't get deconstructed either.  As of Postgres 8.1, rather
	 * than checking typlen we check the toast property, and don't deconstruct
	 * "plain storage" array types --- this is because we don't want to show
	 * oidvector as oid[].
	 */
	array_base_type = typeform->typelem;

	if (array_base_type != InvalidOid &&
		typeform->typstorage != 'p' &&
		typeform->typtype != TYPTYPE_DOMAIN)
	{
		/* Switch our attention to the array element type */
		ReleaseSysCache(tuple);
		tuple = SearchSysCache(TYPEOID,
							   ObjectIdGetDatum(array_base_type),
							   0, 0, 0);
		if (!HeapTupleIsValid(tuple))
		{
			if (allow_invalid)
				return pstrdup("???[]");
			else
				elog(ERROR, "cache lookup failed for type %u", type_oid);
		}
		typeform = (Form_pg_type) GETSTRUCT(tuple);
		type_oid = array_base_type;
		is_array = true;
	}
	else
		is_array = false;

	/*
	 * See if we want to special-case the output for certain built-in types.
	 * Note that these special cases should all correspond to special
	 * productions in gram.y, to ensure that the type name will be taken as a
	 * system type, not a user type of the same name.
	 *
	 * If we do not provide a special-case output here, the type name will be
	 * handled the same way as a user type name --- in particular, it will be
	 * double-quoted if it matches any lexer keyword.  This behavior is
	 * essential for some cases, such as types "bit" and "char".
	 */
	buf = NULL;					/* flag for no special case */

	switch (type_oid)
	{
		case BITOID:
			if (with_typemod)
				buf = printTypmod("bit", typemod, typeform->typmodout);
			else if (typemod_given)
			{
				/*
				 * bit with typmod -1 is not the same as BIT, which means
				 * BIT(1) per SQL spec.  Report it as the quoted typename so
				 * that parser will not assign a bogus typmod.
				 */
			}
			else
				buf = pstrdup("bit");
			break;

		case BOOLOID:
			buf = pstrdup("boolean");
			break;

		case BPCHAROID:
			if (with_typemod)
				buf = printTypmod("character", typemod, typeform->typmodout);
			else if (typemod_given)
			{
				/*
				 * bpchar with typmod -1 is not the same as CHARACTER, which
				 * means CHARACTER(1) per SQL spec.  Report it as bpchar so
				 * that parser will not assign a bogus typmod.
				 */
			}
			else
				buf = pstrdup("character");
			break;

		case FLOAT4OID:
			buf = pstrdup("real");
			break;

		case FLOAT8OID:
			buf = pstrdup("double precision");
			break;

		case INT2OID:
			buf = pstrdup("smallint");
			break;

		case INT4OID:
			buf = pstrdup("integer");
			break;

		case INT8OID:
			buf = pstrdup("bigint");
			break;

		case NUMERICOID:
			if (with_typemod)
				buf = printTypmod("numeric", typemod, typeform->typmodout);
			else
				buf = pstrdup("numeric");
			break;

		case INTERVALOID:
			if (with_typemod)
				buf = printTypmod("interval", typemod, typeform->typmodout);
			else
				buf = pstrdup("interval");
			break;

		case TIMEOID:
			if (with_typemod)
				buf = printTypmod("time", typemod, typeform->typmodout);
			else
				buf = pstrdup("time without time zone");
			break;

		case TIMETZOID:
			if (with_typemod)
				buf = printTypmod("time", typemod, typeform->typmodout);
			else
				buf = pstrdup("time with time zone");
			break;

		case TIMESTAMPOID:
			if (with_typemod)
				buf = printTypmod("timestamp", typemod, typeform->typmodout);
			else
				buf = pstrdup("timestamp without time zone");
			break;

		case TIMESTAMPTZOID:
			if (with_typemod)
				buf = printTypmod("timestamp", typemod, typeform->typmodout);
			else
				buf = pstrdup("timestamp with time zone");
			break;

		case VARBITOID:
			if (with_typemod)
				buf = printTypmod("bit varying", typemod, typeform->typmodout);
			else
				buf = pstrdup("bit varying");
			break;

		case VARCHAROID:
			if (with_typemod)
				buf = printTypmod("character varying", typemod, typeform->typmodout);
			else
				buf = pstrdup("character varying");
			break;
	}

	if (buf == NULL)
	{
		/*
		 * Default handling: report the name as it appears in the catalog.
		 * Here, we must qualify the name if it is not visible in the search
		 * path, and we must double-quote it if it's not a standard identifier
		 * or if it matches any keyword.
		 */
		char	   *nspname;
		char	   *typname;

		if (TypeIsVisible(type_oid))
			nspname = NULL;
		else
			nspname = get_namespace_name(typeform->typnamespace);

		typname = NameStr(typeform->typname);

		buf = quote_qualified_identifier(nspname, typname);

		if (with_typemod)
			buf = printTypmod(buf, typemod, typeform->typmodout);
	}

	if (is_array)
		buf = psnprintf(strlen(buf) + 3, "%s[]", buf);

	ReleaseSysCache(tuple);

	return buf;
}
Ejemplo n.º 2
0
static char *format_type_internal(oid_t type_oid, int32 typemod, bool typemod_given, bool allow_invalid)
{
    bool with_typemod = typemod_given && (typemod >= 0);
    struct heap_tuple * tuple;
    Form_pg_type typeform;
    oid_t array_base_type;
    bool is_array;
    char *buf;

    if (type_oid == INVALID_OID && allow_invalid)
        return pstrdup("-");

    tuple = search_syscache1(TYPEOID, OID_TO_D(type_oid));
    if (!HT_VALID(tuple)) {
        if (allow_invalid)
            return pstrdup("???");
        else
            elog(ERROR, "cache lookup failed for type %u", type_oid);
    }

    typeform = (Form_pg_type) GET_STRUCT(tuple);

    /*
     * Check if it's a regular (variable length) array type.  Fixed-length
     * array types such as "name" shouldn't get deconstructed.  As of
     * Postgres 8.1, rather than checking typlen we check the toast
     * property, and don't deconstruct "plain storage" array types --- this
     * is because we don't want to show oid_vector_s as oid[].
     */
    array_base_type = typeform->typelem;

    if (array_base_type != INVALID_OID && typeform->typstorage != 'p') {
        /* Switch our attention to the array element type */
        release_syscache(tuple);
        tuple = search_syscache1(TYPEOID, OID_TO_D(array_base_type));
        if (!HT_VALID(tuple)) {
            if (allow_invalid)
                return pstrdup("???[]");
            else
                elog(ERROR, "cache lookup failed for type %u", type_oid);
        }

        typeform = (Form_pg_type) GET_STRUCT(tuple);
        type_oid = array_base_type;
        is_array = true;
    } else {
        is_array = false;
    }

    /*
     * See if we want to special-case the output for certain built-in types.
     * Note that these special cases should all correspond to special
     * productions in gram.y, to ensure that the type name will be taken as
     * a system type, not a user type of the same name.
     *
     * If we do not provide a special-case output here, the type name will
     * be handled the same way as a user type name --- in particular, it
     * will be double-quoted if it matches any lexer keyword.
     *
     * This behavior is essential for some cases, such as types "bit" and
     * "char".
     */
    buf = NULL;		/* flag for no special case */

    switch (type_oid) {
    case BITOID:
        if (with_typemod) {
            buf = printTypmod("bit", typemod, typeform->typmodout);
        } else if (typemod_given) {
            /*
             * bit with typmod -1 is not the same as BIT, which
             * means BIT(1) per SQL spec. Report it as the quoted
             * typename so that parser will not assign a bogus
             * typmod.
             */
        } else {
            buf = pstrdup("bit");
        }
        break;

    case BOOLOID:
        buf = pstrdup("boolean");
        break;

    case BPCHAROID:
        if (with_typemod) {
            buf = printTypmod("character", typemod, typeform->typmodout);
        } else if (typemod_given) {
            /*
             * bpchar with typmod -1 is not the same as CHARACTER,
             * which means CHARACTER(1) per SQL spec. Report it as
             * bpchar so that parser will not assign a bogus typmod.
             */
        } else {
            buf = pstrdup("character");
        }
        break;

    case FLOAT4OID:
        buf = pstrdup("real");
        break;

    case FLOAT8OID:
        buf = pstrdup("double precision");
        break;

    case INT2OID:
        buf = pstrdup("smallint");
        break;

    case INT4OID:
        buf = pstrdup("integer");
        break;

    case INT8OID:
        buf = pstrdup("bigint");
        break;

    case NUMERICOID:
        if (with_typemod)
            buf = printTypmod("numeric", typemod, typeform->typmodout);
        else
            buf = pstrdup("numeric");

        break;

    case INTERVALOID:
        if (with_typemod)
            buf = printTypmod("interval", typemod, typeform->typmodout);
        else
            buf = pstrdup("interval");
        break;

    case TIMEOID:
        if (with_typemod)
            buf = printTypmod("time", typemod, typeform->typmodout);
        else
            buf = pstrdup("time without time zone");
        break;

    case TIMETZOID:
        if (with_typemod)
            buf = printTypmod("time", typemod, typeform->typmodout);
        else
            buf = pstrdup("time with time zone");
        break;

    case TIMESTAMPOID:
        if (with_typemod)
            buf = printTypmod("timestamp", typemod, typeform->typmodout);
        else
            buf = pstrdup("timestamp without time zone");
        break;

    case TIMESTAMPTZOID:
        if (with_typemod)
            buf = printTypmod("timestamp", typemod, typeform->typmodout);
        else
            buf = pstrdup("timestamp with time zone");
        break;

    case VARBITOID:
        if (with_typemod)
            buf = printTypmod("bit varying", typemod, typeform->typmodout);
        else
            buf = pstrdup("bit varying");
        break;

    case VARCHAROID:
        if (with_typemod)
            buf = printTypmod("character varying", typemod, typeform->typmodout);
        else
            buf = pstrdup("character varying");
        break;
    }

    if (buf == NULL) {
        /*
         * Default handling: report the name as it appears in the
         * catalog. Here, we must qualify the name if it is not visible
         * in the search path, and we must double-quote it if it's not
         * a standard identifier or if it matches any keyword.
         */
        char *nspname;
        char *typname;

        if (type_is_visible(type_oid))
            nspname = NULL;
        else
            nspname = get_ns_name(typeform->typnamespace);

        typname = NAME_TO_STR(typeform->typname);
        buf = quote_qualified_identifier(nspname, typname);
        if (with_typemod)
            buf = printTypmod(buf, typemod, typeform->typmodout);
    }

    if (is_array)
        buf = psnprintf(strlen(buf) + 3, "%s[]", buf);

    release_syscache(tuple);

    return buf;
}