PG迁移必读(二):复现Sybase的host_name函数
Barry Chen

前言:本文介绍了如何在PostgreSQL中实现类似Sybase的host_name函数,旨在帮助开发者解决PG迁移过程中遇到的函数兼容性问题。

Sybase有一个特有的host_name()函数,光看名字容易误解为获取服务器的host name,但实际上这个函数是返回客户端的host name的。上个官方文档
host_name, a system function, returns the current host computer name of the client process (not the server process).

当前项目中,约有20多个存储过程用到了这个函数,主要用途有三个:

  1. audit log
  2. 根据host name进行授权

  3. 根据host name更新数据

PG是没有相对应的函数,因此需要在PG实现该函数。PG中最接近host_name的函数是获取client的ip函数inet_client_addr()。我们可以利用这个函数实现Sybase的host_name函数功能。

方案一

 

总体思路在数据库中建立并维护一张iphost name的关系表,然后通过查表获得客户端host name。步骤如下:

  1. 创建ip2hostname表。
    CREATE TABLE ip2hostname(

hostname varchar(255),

ip varchar(255)

)


    2. 创建host_name() 函数。

Create or replace function host_name()

Returns varchar

Language plpgsql

AS $$

Declare v_ip varchar;

v_hostname varchar;

BEGIN

SELECT inet_client_addr() INTO v_ip; 

Select hostname into v_hostname from ip2hostname where ip=v_ip;  

RETURN COALESCE(v_hostname, 'Unkown');

END;

$$;

这样,host_name()函数就能顺利在PG中运行了。但本方案的缺点也是很明显的,需要人工维护这个映射表,如果网络中采用了DHCP动态IP地址分配,情况会更加复杂。

方案二

 

方案二是基于方案一的改进版,通过客户端应用主动发送host name到数据库,来消除人工维护映射表的工作。步骤如下:

  1. 创建ip2hostname表和host_name() 函数,同方案一。

  2. 创建set_host_name()函数。
     

    CREATE OR REPLACE FUNCTION set_host_name(p_hostname text)

RETURNS void AS $$

DECLARE found_count integer;

BEGIN

  UPDATE ip2hostname SET ip = inet_client_addr() WHERE hostname = p_hostname;

  GET DIAGNOSTICS found_count = ROW_COUNT;

  IF found_count = 0 THEN

INSERT INTO ip2hostname (hostname, ip) VALUES (p_hostname, inet_client_addr());

  END IF;

END;

$$ LANGUAGE plpgsql;
 

  3. 修改Application,在Application启动后,调用一次set_host_name()函数。
 如果客户端是采用Springboot框架开发,可以继承ApplicationRunner,该类会在Springboot启动后,自动运行。

@Component
public class MyApplicationRunner implements ApplicationRunner {
@Autowired
JdbcTemplate jdbcTemplate;
@Override
public void run(ApplicationArguments args) throws Exception {
String hostname= InetAddress.getLocalHost().getHostName();
jdbcTemplate.execute("select set_host_name('"+hostname+"')");
}
}

这样,当应用程序正常启动后,会向数据库中的ip2hostname表插入或更新客户端的host name,后面无论何处执行host_name()函数,都能正确返回客户端的host name了。

 

总的来说,方案一适用于固定不变的网络环境;方案二适用于偶有变化或频繁变化的网络环境。