目前正在运行9.5.3版本。当然,计划更新。
我有一个PostgreSQL数据库,其模式早于表行级安全性(即创建策略…
)。行级安全性是使用视图实现的。在视图中,只选择所有者名称与当前用户匹配的行来实现安全性。
我正试图使用这样一个视图构建一个upsert查询。当我试图命名冲突\u目标时,问题就出现了。
使用
ON CONFLICT UPDATE...
的问题来自于命名违反了什么约束。
CREATE TABLE foo (id serial, num int, word text, data text, ownername varchar(64));
对于每个用户,
word
和num
的组合必须是唯一的。
CREATE UNIQUE INDEX foo_num_word_owner_idx ON foo (num, word, ownername);
行级别安全性是使用基于当前用户名的视图实现的。该视图的权限被授予,普通用户的基础表的权限被删除。
security_barrier
是在v9.5之后添加的。请注意,用户看不到ownername
。
CREATE VIEW foo_user WITH (security_barrier = True) AS
SELECT id, num, word, data FROM foo
WHERE foo.ownername = CURRENT_USER;
现在自动设置ownername:
CREATE OR REPLACE FUNCTION trf_set_owner() RETURNS trigger AS
$$
BEGIN
IF (TG_OP = 'INSERT') THEN
NEW.ownername = CURRENT_USER::varchar(64);
END IF;
IF (TG_OP = 'UPDATE') THEN
NEW.ownername = CURRENT_USER::varchar(64);
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';
CREATE TRIGGER foo_row_owner
BEFORE INSERT OR UPDATE ON foo FOR EACH ROW
EXECUTE PROCEDURE trf_set_owner();
请注意,
ownername
列不显示在视图中;行安全性对用户不可见。
现在添加一些数据:
INSERT INTO foo_user (num, word, data) VALUES (1, 'asdf', 'cat'), (2, 'qwer', 'dog');
SELECT * FROM foo;
-- normally, this would give an error related to privileges,
-- because we don't allow users to query the underlying table.
-- bypassed here for demo purposes.
id | num | word | data | ownername
----+-----+------+------+-----------
1 | 1 | asdf | cat | admin
2 | 2 | qwer | dog | admin
(2 rows)
SELECT * FROM foo_user;
id | num | word | data
----+-----+------+------
1 | 1 | asdf | cat
2 | 2 | qwer | dog
(2 rows)
到目前为止,一切都很好。
如上所述,对于每个用户,
num
和word
必须是唯一的。不同的所有者拥有相同的num
和word
(事实上,我们希望如此)。
我试图利用
INSERT
中的ON CONFLICT
子句来创建一些后端UPSERT-ish功能。它正在往下掉。
首先,一个简单的失败插入:
INSERT INTO foo_user (num, word, data) VALUES (2, 'qwer', 'frog');
ERROR: duplicate key value violates unique constraint "foo_num_word_owner_idx"
DETAIL: Key (num, word, ownername)=(2, qwer, admin) already exists.
完全意料之中。这没什么错。
现在,我们尝试让客户体验更顺畅:
INSERT INTO foo_user (num, word, data) VALUES (2, 'qwer', 'frog')
ON CONFLICT DO UPDATE
SET data = 'frog'
WHERE num = 2 AND word = 'qwer';
ERROR: ON CONFLICT DO UPDATE requires inference specification or constraint name
LINE 2: ON CONFLICT DO UPDATE
^
HINT: For example, ON CONFLICT (column_name).
是的,就像文件上说的。它需要知道它打破了什么规则。没问题:
INSERT INTO foo_user (num, word, data) VALUES (2, 'qwer', 'frog')
ON CONFLICT (num, word, ownername) DO UPDATE
SET data = 'frog'
WHERE num = 2 AND word = 'qwer';
ERROR: column "ownername" does not exist
LINE 2: ON CONFLICT (num, word, ownername) DO UPDATE
符合事实的视图中不存在Ownername。我们不能从唯一索引中删除
ownername
,因为我们完全希望不同的所有者拥有相同的num
和word
值。
因此,我尝试将索引转换为约束,并命名约束:
ALTER TABLE foo
ADD CONSTRAINT foo_num_word_owner_crt UNIQUE
USING INDEX foo_num_word_owner_idx;
NOTICE: ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index
"foo_num_word_owner_idx" to "foo_num_word_owner_crt"
好的,现在来测试:
INSERT INTO foo_user (num, word, data) VALUES (2, 'qwer', 'frog')
ON CONFLICT ON CONSTRAINT foo_num_word_owner_crt DO UPDATE
SET data = 'frog'
WHERE num = 2 AND word = 'qwer';
ERROR: constraint "foo_num_word_owner_crt" for table "foo_user" does not exist
这是有道理的:我们正在查询视图,但指定了一个表约束。
现在我没有主意了。我们如何才能在冲突中获得
,从而更好地处理这样的视图?还是不可能?
我很接近(举起大拇指和食指)建议我们从视图切换到具有行级安全性的表,但这是相当多的工作(不一定是API破坏者,但仍然如此)。
任何见解都非常感谢。
您可以通过删除ON CONFLICT
子句并使用手动测试任何索引冲突的INSTEAD OF
触发器来避免此问题:
CREATE OR REPLACE FUNCTION trf_set_num_word() RETURNS trigger AS $$
BEGIN
-- Check if (num, word, ownername) exists by trying an UPDATE
UPDATE foo SET data = 'frog'
WHERE num = NEW.num AND word = NEW.word AND ownername = CURRENT_USER::varchar(64);
IF FOUND THEN
RETURN NULL; -- If so, don't INSERT/UPDATE
END IF;
RETURN NEW; -- If not, do the INSERT
END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER foo_user_num_word
INSTEAD OF INSERT OR UPDATE ON foo_user FOR EACH ROW
EXECUTE PROCEDURE trf_set_num_word();
我想更新表中几行的主键。如果所有行都已更新,则键将再次是唯一的,但第一行的更新会导致与第二行的键发生临时冲突。有没有优雅的方法来解决这个问题? 例子: 错误:重复的键值违反了唯一约束“pk_erichtest”
当尝试使用PostgreSQL执行时,我遇到了一个我不理解的行为。文档似乎指示语句的冲突目标可以是索引表达式或约束名称。但是,当试图引用约束名称时,我得到了一个“列...不存在”错误。 我的第一次尝试是创建一个索引,它可以很好地处理约束推理: 在描述上表时,我在“索引”下看到了以下内容: 我的第二次尝试是将唯一约束显式地放在创建表中: 在描述上表时,“索引:”的输出略有不同(“唯一约束”与前一示例
在令牌冲突的情况下,如何定义ANTLR lexer行为?让我解释一下“冲突”标记的含义。例如,假设定义了以下内容: 这里有一个冲突,因为在读取一系列数字后,lexer将不知道是有一个INT还是多个INT\u阶段标记(或两者的不同组合)。测试之后,如果INT是在INT\u阶段之后定义的,那么lexer会更喜欢查找INT\u阶段,但可能不是INT?否则,将找不到INT\u阶段。 另一个例子是: 我被告
当您正在向上插入一行时(PostgreSQL) 还有更短的路吗?也就是说:使用所有排除值。 在SQLite中,我曾经做过:
使用: 所有类都在中生成,在中没有类。没有-p开关,所有xsd都是在它们自己的默认包中生成的。但无法告诉wsimport为每个XSD使用特定的包。现在我使用以下绑定文件,这可能是不正确的,但wsimport对此没有抱怨: 在包org.broker.wsi.b_2和org.broker.wsi.t_1中,不生成任何文件。 欢迎提出建议。