我的应用程序使用slick(v2.0.0)来管理postgresql(9.1)数据库。
我的一个表包含网络设备,因此包含mac和ip地址。我使用了postgres类型macaddr
和inet
,因为它们似乎是完成任务的完美工具。现在我想使用浮动的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
或
更新
正如Craig所描述的那样,我使用围绕macaddr_in
和inet_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
答案 0 :(得分:5)
这是许多人对json
或XML
的问题的变体,并且归结为PostgreSQL对数据类型之间的强制转换过于严格。
请参阅this answer,其中讨论了json
的类似问题。使用转换函数创建转换的相同方法在这里是合适的。
您的演员阵容是macaddr_in
和inet_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
,因为这是输入所需要的。它有点类似于可以隐式转换为任何输入函数的类型。相比之下,text
和varchar
是具体类型,Pg必须参考投射规则,因此如果不创建强制转换,这将无效:
INSERT INTO inetmac(i) VALUES ('10.1.1.1'::text);
我将在-hackers列表上对此进行大惊小怪,人们从客户端接口使用PostgreSQL的扩展类型是多么困难。当然,客户端接口应该公开一种告诉JDBC驱动程序基本类型是什么的方法,但是如果大多数事情都能应对索引和复合键等极端基础知识,那么我们很幸运,更不用说类型处理。 Pg确实需要对此不太关注,或者提供一种在参数绑定中指定'unknown'
伪类型的方法。
Fuss提出: