Macaddr / Inet类型的postgres in slick

时间:2014-01-22 14:19:07

标签: postgresql jdbc slick

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

我的一个表包含网络设备,因此包含mac和ip地址。我使用了postgres类型macaddrinet,因为它们似乎是完成任务的完美工具。现在我想使用浮动的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 / inet
  • 类型

  • 此collumn需要在插入之前进行转换,否则可以将其视为字符串

更新

正如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 <tablename>中的

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;

UPDATE2:

我将其缩小为权限错误,因为如果我以用户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;

UPDATE3:

Update2仅仅是问题,因为创建的表由postgres而不是myuser

拥有

1 个答案:

答案 0 :(得分:5)

这是许多人对jsonXML的问题的变体,并且归结为PostgreSQL对数据类型之间的强制转换过于严格。

请参阅this answer,其中讨论了json的类似问题。使用转换函数创建转换的相同方法在这里是合适的。

您的演员阵容是macaddr_ininet_in。由于一些恼人的类型问题,您需要编写带有text参数的包装SQL函数。见上面的链接。

另见this related answer for the xml type


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

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=# 

...但是,相当令人惊讶的是,为了使用varchar强制转型,Pg不会隐式地从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属于伪类型unknown,并被解释为inet,因为这是输入所需要的。它有点类似于可以隐式转换为任何输入函数的类型。相比之下,textvarchar具体类型,Pg必须参考投射规则,因此如果不创建强制转换,这将无效:

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

我将在-hackers列表上对此进行大惊小怪,人们从客户端接口使用PostgreSQL的扩展类型是多么困难。当然,客户端接口应该公开一种告诉JDBC驱动程序基本类型是什么的方法,但是如果大多数事情都能应对索引和复合键等极端基础知识,那么我们很幸运,更不用说类型处理。 Pg确实需要对此不太关注,或者提供一种在参数绑定中指定'unknown'伪类型的方法。

Fuss提出: