Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 插入冲突时的回滚触发器_Sql_Postgresql_Plpgsql_Postgresql 9.5 - Fatal编程技术网

Sql 插入冲突时的回滚触发器

Sql 插入冲突时的回滚触发器,sql,postgresql,plpgsql,postgresql-9.5,Sql,Postgresql,Plpgsql,Postgresql 9.5,我有这个: CREATE FUNCTION upsert_user(u_name text, u_fullname text, u_email text, u_suffix text) RETURNS integer LANGUAGE plpgsql AS $$ DECLARE userid users.id_user%TYPE; BEGIN LOOP -- first try to update UPDATE users SET

我有这个:

CREATE FUNCTION upsert_user(u_name text, u_fullname text, u_email text, u_suffix text) RETURNS integer
    LANGUAGE plpgsql
    AS $$
DECLARE
    userid users.id_user%TYPE;
BEGIN
    LOOP
        -- first try to update
        UPDATE users SET "fullname" = u_fullname, "email" = u_email, "suffix" = u_suffix WHERE "name" = u_name RETURNING "id_user" INTO userid;
        -- check if the row is found
        IF FOUND THEN
            RETURN userid;
        END IF;
        -- not found so insert the row
        BEGIN
            INSERT INTO users ("name", "fullname", "email", "suffix") VALUES (u_name, u_fullname, u_email, u_suffix) RETURNING "id_user" INTO userid;
            RETURN userid;
            EXCEPTION WHEN unique_violation THEN
                -- do nothing and loop
        END;
    END LOOP;
END;
$$;

CREATE TRIGGER link_entity
  BEFORE INSERT
  ON public.users
  FOR EACH ROW
  EXECUTE PROCEDURE public.link_entity();

CREATE FUNCTION link_entity() RETURNS trigger
    LANGUAGE plpgsql
    AS $$    DECLARE
        entityid integer;
    BEGIN
        INSERT INTO privileges_entities (name) VALUES (NEW.name) RETURNING privileges_entities.id_entity INTO entityid;
        IF NOT FOUND THEN
            RETURN NULL;
        END IF;
        NEW.ref_entity := entityid;
        RETURN NEW;
    END;
$$;
将postgresql更新到9.5版后,我修改了函数upsert_user,以使用新的冲突指令:

CREATE FUNCTION upsert_user(u_name text, u_fullname text, u_email text, u_suffix text) RETURNS integer
    LANGUAGE sql
    AS $$
  INSERT INTO users (name, fullname, email, suffix)
  VALUES (u_name, u_fullname, u_email, u_suffix)
  ON CONFLICT (name) DO UPDATE SET name=EXCLUDED.name, fullname=EXCLUDED.fullname, email=EXCLUDED.email, suffix=EXCLUDED.suffix
  RETURNING id_user;
$$;
问题是,现在,即使在用户表中插入失败,也会在privileges\u entities表中插入新行。
如果用户的插入导致冲突,是否可以回滚触发器?

这确实是使用新的ON conflict子句的副作用

我的解决方案是在link_entity()函数本身中添加一个检查,如果用户已经存在,就阻止它继续。像这样:

CREATE FUNCTION link_entity() RETURNS trigger
    LANGUAGE plpgsql
    AS $$    DECLARE
        entityid integer;
        nameExists boolean;
    BEGIN
        EXECUTE format('SELECT EXISTS(SELECT 1 FROM %I.%I WHERE name = NEW.name)', TG_TABLE_SCHEMA, TG_TABLE_NAME) INTO nameExists;
        IF nameExists THEN
            RETURN NEW; -- just return, entity already linked
        END IF;

        INSERT INTO privileges_entities (name) VALUES (NEW.name) RETURNING privileges_entities.id_entity INTO entityid;
        IF NOT FOUND THEN
            RETURN NULL;
        END IF;
        NEW.ref_entity := entityid;
        RETURN NEW;
    END;
$$;

让它成为“后”触发器可以吗?可能不会触发。触发器设置的列不能为空。因此,我不能将其设置为“AFTER”触发器。privileges\u实体可以是用户、组或其他对象,因此我无法检查users表。id\u entity和name列是从entity\u linkables表继承的。啊,privileges\u entities.name列是否唯一?不,它只是人类的指示;)id是唯一有意义的列。好吧,这变得有点棘手了。我已经更新了答案,因此它不再依赖于“users”表,但是它假定所有实体表上的相关列都称为“name”。这是否足够?