pgsql 函数无法执行

pgsql function cannot execute

提问人:Jules78 提问时间:9/19/2023 最后编辑:Pavel StehuleJules78 更新时间:9/21/2023 访问量:40

问:

我尝试执行此函数:

CREATE OR REPLACE FUNCTION public.increases_chrono(
    chrono_seq_name text,
    chrono_id_name text)
    RETURNS TABLE(chrono_id bigint) 
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE PARALLEL UNSAFE
    ROWS 1000

AS $$
DECLARE
    retval bigint;
BEGIN
    -- Check if sequence exist, if not create
    IF NOT EXISTS (SELECT 0 FROM pg_class where relname = chrono_seq_name ) THEN
      EXECUTE 'CREATE SEQUENCE "' || chrono_seq_name || '" INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1;';
    END IF;
    -- Check if chrono exist in parameters table, if not create
    IF NOT EXISTS (SELECT 0 FROM parameters where id = chrono_id_name ) THEN
      EXECUTE 'INSERT INTO parameters (id, param_value_int) VALUES ( ''' || chrono_id_name || ''', 1)';
    END IF;
    -- Get next value of sequence, update the value in parameters table before returning the value
    SELECT nextval(chrono_seq_name) INTO retval;
      UPDATE parameters set param_value_int = retval WHERE id =  chrono_id_name;
      RETURN QUERY SELECT retval;
END;
$$;

ALTER FUNCTION public.increases_chrono(text, text)
    OWNER TO maarch;

但是当我像这样称呼他时:

SELECT increases_chrono('chrono_DAP_2023_seq' ,'chrono_DAP_2023')

我有错误:错误:关系“chrono_dap_2023_seq”不存在 上下文:SQL 语句“SELECT nextval(chrono_seq_name)” PL/pgSQL 函数 increase_chrono(text,text) SQL 语句第 14 行

SQL 状态:42P01 有人可以帮我

plpgsql 注入 动态 sql pgadmin

评论


答:

0赞 Pavel Stehule 9/20/2023 #1

区分大小写存在问题。看起来像CREATE

CREATE SEQUENCE "chrono_DAP_2023_seq" 
   INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1;

标识符位于双引号内 - 因此区分大小写。

但是当你尝试使用它时,变量不会在双引号内传递,因此它不是区分大小写的标识符。使用功能修复它:chrono_seq_namequote_ident

-- Get next value of sequence, update the value in parameters 
---table before returning the value
SELECT nextval(quote_ident(chrono_seq_name)) INTO retval;

构建字符串 like 是错误的。永远不要这样做。它容易受到 SQL 注入的攻击。您应该再次使用函数,或带有占位符的函数:EXECUTE 'CREATE SEQUENCE "' || chrono_seq_name || '" INC ...quote_identformat%I

EXECUTE format('CREATE SEQUENCE %I', chrono_seq_name);

还有另一个问题。没有任何理由,返回表是适得其反的。表函数的调用成本更高。这个函数应该只返回 bigint:

CREATE OR REPLACE FUNCTION public.increases_chrono(
    chrono_seq_name text,
    chrono_id_name text)
    RETURNS bigint 
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE PARALLEL UNSAFE
    ROWS 1000

AS $$
BEGIN
  ...
  RETURN retval;
END;
$$;

评论

0赞 Jules78 9/21/2023
谢谢。。。现在的问题是指令IF NOT EXIST,以验证是否创建了序列
0赞 Pavel Stehule 9/21/2023
@Jules78 - 不,应该没有任何问题 - 列 relname 那里不包含双引号,并且 pg 中的字符串 compare 区分大小写。