presto-postgresql/src/main/java/io/prestosql/plugin/postgresql/PostgreSqlClient.java/PostgreSqlClient/toPrestoType
class PostgreSqlClient:    @Override
    public Optional<ColumnMapping> toPrestoType(ConnectorSession session, Connection connection, JdbcTypeHandle typeHandle)
    {
        String jdbcTypeName = typeHandle.getJdbcTypeName()
                .orElseThrow(() -> new PrestoException(JDBC_ERROR, "Type name is missing: " + typeHandle));

        Optional<ColumnMapping> mapping = getForcedMappingToVarchar(typeHandle);
        if (mapping.isPresent()) {
            return mapping;
        }
        switch (jdbcTypeName) {
            case "uuid":
                return Optional.of(uuidColumnMapping());
            case "jsonb":
            case "json":
                return Optional.of(jsonColumnMapping());
            case "timestamptz":
                // PostgreSQL's "timestamp with time zone" is reported as Types.TIMESTAMP rather than Types.TIMESTAMP_WITH_TIMEZONE
                return Optional.of(timestampWithTimeZoneColumnMapping());
            case "hstore":
                return Optional.of(hstoreColumnMapping(session));
        }
        if (typeHandle.getJdbcType() == Types.VARCHAR && !jdbcTypeName.equals("varchar")) {
            // This can be e.g. an ENUM
            return Optional.of(typedVarcharColumnMapping(jdbcTypeName));
        }
        if (typeHandle.getJdbcType() == Types.TIMESTAMP) {
            return Optional.of(ColumnMapping.longMapping(
                    TIMESTAMP,
                    timestampReadFunction(session),
                    timestampWriteFunction(session)));
        }
        if (typeHandle.getJdbcType() == Types.ARRAY) {
            ArrayMapping arrayMapping = getArrayMapping(session);
            if (arrayMapping == DISABLED) {
                return Optional.empty();
            }
            // resolve and map base array element type
            JdbcTypeHandle baseElementTypeHandle = getArrayElementTypeHandle(connection, typeHandle);
            String baseElementTypeName = baseElementTypeHandle.getJdbcTypeName()
                    .orElseThrow(() -> new PrestoException(JDBC_ERROR, "Element type name is missing: " + baseElementTypeHandle));
            if (baseElementTypeHandle.getJdbcType() == Types.VARBINARY) {
                // PostgreSQL jdbc driver doesn't currently support array of varbinary (bytea[])
                // https://github.com/pgjdbc/pgjdbc/pull/1184
                return Optional.empty();
            }
            Optional<ColumnMapping> baseElementMapping = toPrestoType(session, connection, baseElementTypeHandle);

            if (arrayMapping == AS_ARRAY) {
                if (!typeHandle.getArrayDimensions().isPresent()) {
                    return Optional.empty();
                }
                return baseElementMapping
                        .map(elementMapping -> {
                            ArrayType prestoArrayType = new ArrayType(elementMapping.getType());
                            ColumnMapping arrayColumnMapping = arrayColumnMapping(session, prestoArrayType, elementMapping, baseElementTypeName);

                            int arrayDimensions = typeHandle.getArrayDimensions().get();
                            for (int i = 1; i < arrayDimensions; i++) {
                                prestoArrayType = new ArrayType(prestoArrayType);
                                arrayColumnMapping = arrayColumnMapping(session, prestoArrayType, arrayColumnMapping, baseElementTypeName);
                            }
                            return arrayColumnMapping;
                        });
            }
            if (arrayMapping == AS_JSON) {
                return baseElementMapping
                        .map(elementMapping -> arrayAsJsonColumnMapping(session, elementMapping));
            }
            throw new IllegalStateException("Unsupported array mapping type: " + arrayMapping);
        }
        // TODO support PostgreSQL's TIME WITH TIME ZONE explicitly, otherwise predicate pushdown for these types may be incorrect
        return super.toPrestoType(session, connection, typeHandle);
    }