提问者:小点点

Macaddr/Inet类型的postgres在光滑


我的应用程序使用slick(v2.0.0)来管理postgresql(9.1)数据库。

我的一个表包含网络设备,因此包含mac-和ip地址。我使用postgres类型macaddrine,因为它们似乎是完成任务的完美工具。现在我想使用slick和提升的emebedding,但很难定义我的表。当我自动为我的表生成代码时,我注意到使用了String而不是这些类型,但并不介意。

这适用于从DB读取,但当我尝试更新或插入一行时,它会导致

org.postgresql.util.PSQLException: ERROR: 
column "mac" is of type macaddr but expression is of type character varying
Hint: You will need to rewrite or cast the expression.

维奇似乎很合乎逻辑。

现在的问题是我如何告诉滑头:

  • 这个列实际上是macaddr/net
  • 类型

  • 此列需要在插入之前强制转换,但可以将其视为字符串

?

更新:

正如Craig所描述的,我使用macaddr_ininet_in周围的包装函数创建了隐式强制转换

\dC macaddr
                 List of casts
 Source type | Target type |    Function    | Implicit?
-------------+-------------+----------------+-----------
 text        | macaddr     | macaddr_intext | yes

\dC inet
                        List of casts
 Source type |    Target type    |      Function      |   Implicit?
-------------+-------------------+--------------------+---------------
 cidr        | inet              | (binary coercible) | yes
 inet        | character         | text               | in assignment
 inet        | character varying | text               | in assignment
 inet        | cidr              | cidr               | in assignment
 inet        | text              | text               | in assignment
 text        | inet              | inet_intext        | yes

\df+ macaddr_intext
                                                                  List of functions
 Schema |      Name      | Result data type | Argument data types |  Type  | Volatility |  Owner   | Language |           Source code           | Description
--------+----------------+------------------+---------------------+--------+------------+----------+----------+---------------------------------+-------------
 public | macaddr_intext | macaddr          | text                | normal | immutable  | postgres | sql      |                                 |
                                                                                                              : select macaddr_in($1::cstring);
                                                                                                              :

\df+ inet_intext
                                                               List of functions
 Schema |    Name     | Result data type | Argument data types |  Type  | Volatility |  Owner   | Language |         Source code          | Description
--------+-------------+------------------+---------------------+--------+------------+----------+----------+------------------------------+-------------
 public | inet_intext | inet             | text                | normal | immutable  | postgres | sql      |                              |
                                                                                                           : select inet_in($1::cstring);
                                                                                                           :

错误消息仍然与上面显示的完全相同。

要复制的标题:

psql

create or replace function macaddr_intext(text) returns macaddr as $$
select macaddr_in($1::cstring);
$$ language sql immutable;

create cast (text as macaddr) with function macaddr_intext(text) as implicit;

create or replace function inet_intext(text) returns inet as $$
select inet_in($1::cstring);
$$ language sql immutable;

create cast (text as inet) with function inet_intext(text) as implicit;

更新2:

我将其缩小到权限错误,因为如果我以用户postgres身份运行:

mydb=# create table test(i inet, m macaddr)
CREATE TABLE
mydb=# insert into test values ('1.1.1.1'::text, '00:00:00:00:00:00'::text);
INSERT 0 1

但是如果我尝试以实际尝试插入的用户身份运行它

mydb=> insert into test values ('1.1.1.1'::text, '00:00:00:00:00:00'::text);
ERROR: permission denied for relation test

设置我运行的数据库时:

template1=# GRANT ALL PRIVILEGES ON DATABASE mydb to myuser;

更新3:

Update2被证明是唯一的问题,因为创建的表归postgres所有,而不是myuser


共1个答案

匿名用户

这是许多人在jsonXML中遇到的问题的变体,归结为PostgreSQL对数据类型之间的转换过于严格。

请参阅这个答案,它讨论了json的类似问题。使用转换函数创建强制转换的相同方法在这里是合适的。

您的强制转换函数是macaddr_ininet_in。由于一些恼人的类型问题,您需要编写包装SQL函数来接受text参数。请参阅上面的链接。

另请参阅xml类型的相关答案。

更新后,我测试了您的功能,发现它们按预期工作:

postgres=# CREATE TABLE inetmac (i inet, m macaddr);
CREATE TABLE
postgres=# PREPARE insinet(text) AS INSERT INTO inetmac(i) VALUES ($1);
PREPARE
postgres=# EXECUTE insinet('10.1.1.1');
INSERT 0 1
postgres=# 

…但是,相当令人惊讶的是,Pg并没有隐式地从varchar转换为text以使用text转换:

postgres=# PREPARE insinet(varchar) AS INSERT INTO inetmac(i) VALUES ($1);
ERROR:  column "i" is of type inet but expression is of type character varying
LINE 1: ...PARE insinet(varchar) AS INSERT INTO inetmac(i) VALUES ($1);
                                                                   ^
HINT:  You will need to rewrite or cast the expression.

如果您使用varchar输入,您将需要另一组带有varchar而不是text输入的强制转换。

请注意,如果您只是:

INSERT INTO inetmac(i) VALUES ('10.1.1.1');

直接,因为这里'10.1.1.1是伪类型未知,并且被解释为net,因为这是输入所需要的。它有点像一个可以隐式转换为任何输入函数的类型。相比之下,textvarchar是Pg必须参考转换规则的具体类型,所以如果不创建转换,这将无法工作:

INSERT INTO inetmac(i) VALUES ('10.1.1.1'::text);

我要在-hacker列表上对此提出一个大惊小怪的问题,人们从客户端接口使用PostgreSQL的扩展类型是多么困难,这只是令人痛苦。当然,所说的客户端接口应该公开一种方法来告诉JDBC驱动程序基本类型是什么,但是如果大多数事情都能处理像索引和复合键这样的极端基础知识,我们就很幸运了,更不用说类型处理的细节了。Pg真的需要对此少一点疯狂,或者提供一种方法来指定参数绑定中的'未知'伪类型。

大惊小怪:

>

  • http://www.postgresql.org/message-id/CACTajFZ8 hg_kom6QiVBa94Kx9L3XUqZ99RdUsHBFkSb1MoCPQ@mail.gmail.com

    http://www.postgresql.org/message-id/52E87EB0.7010504@2ndquadrant.com