使用动态文件名复制

时间:2013-04-15 15:51:22

标签: sql postgresql plpgsql dynamic-sql postgresql-copy

我正在尝试编写一个函数来将csv数据加载到表中。我希望输入参数是文件的路径。

CREATE OR REPLACE FUNCTION public.loaddata(filepathname varchar)
  RETURNS void AS
$BODY$
BEGIN
COPY climatedata(
    climatestationid, 
    date,
    prcp,
    prcpqflag,
    prcpmflag,
    prcpsflag,
    tmax,
    tmaxqflag,
    tmaxmflag,
    tmaxsflag,
    tmin,
    tminqflag,
    tminmflag,
    tminsflag)
  FROM $1
  WITH csv header;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION public.filltmaxa(character varying)
  OWNER TO postgres;

当我尝试创建此功能时,我得到了

  

$ 1的语法错误

它出了什么问题?

1 个答案:

答案 0 :(得分:10)

首先,您的功能名称不匹配:

CREATE OR REPLACE FUNCTION public.loaddata(filepathname varchar)
...
ALTER FUNCTION public.filltmaxa(character varying)

但这是一个额外的问题。

答案

您需要动态SQL:

CREATE OR REPLACE FUNCTION loaddata(filepathname text)
  RETURNS void AS
$func$
BEGIN

EXECUTE format ('
COPY climatedata(
      climatestationid
     ,date
     ,prcp
     ,prcpqflag
     ,prcpmflag
     ,prcpsflag
     ,tmax
     ,tmaxqflag
     ,tmaxmflag
     ,tmaxsflag
     ,tmin
     ,tminqflag
     ,tminmflag
     ,tminsflag)
FROM %L
(FORMAT CSV, HEADER)', $1);  -- current syntax
--- WITH CSV HEADER', $1);   -- tolerated legacy syntax

END
$func$ LANGUAGE plpgsql;

format()需要PostgreSQL 9.1+ 这样,我们可以提供文件名而无需额外的一组(转义)单引号。拨打:

SELECT loaddata('/absolute/path/to/my/file.csv')

这非常容易受到 SQL注入的影响。为了防范它,我使用format()%L来清理文件名。这也包括必要的封闭单引号。