Saving file path in PostgreSQL, removes backslashes

The problem is the title. We have a postgreSQL database where we would like to save some paths and database removes backslashes( \ ) from the path.

Function:

CREATE OR REPLACE FUNCTION public.add_filenotification_array(IN fninput public.filenotification_input []) 
RETURNS Table(TYPE public."filenotification") AS 
$$
DECLARE
fn public.filenotification_input;
filenotification public.filenotification;
filenotificationlist public.filenotification [];
BEGIN
FOREACH fn IN ARRAY fninput LOOP
     INSERT INTO public."FileNotification"("FileLocation", "FileTargetLocation", "DocumentLanguage", "LastUpdate", "idStatus", "FileSize") 
 VALUES (fn.filelocation, fn.filetargetlocation, fn.documentlanguage, CURRENT_TIMESTAMP, 0, 0) 
 RETURNING "id", "FileLocation", "FileTargetLocation", "DocumentLanguage", "LastUpdate", "idStatus"
 INTO filenotification.id, filenotification.filelocation, filenotification.filetargetlocation, filenotification.documentlanguage, filenotification.lastupdate, filenotification.idstatus;
 filenotificationlist := array_append(filenotificationlist, filenotification);
END LOOP;
RETURN QUERY
 SELECT * FROM unnest(filenotificationlist::public.filenotification []);
END;
$$
LANGUAGE plpgsql;

File types:

TYPE filenotification AS (
  "id" integer,
  "filelocation" character varying,
  "filetargetlocation" character varying,
  "documentlanguage" character varying,
  "lastupdate" timestamp,
  "idstatus" integer
  );


TYPE filenotification_input AS (
  "filelocation" character varying,
  "filetargetlocation" character varying,
  "documentlanguage" character varying
);

From application we send a java.sql.Array of filenotification, with proper paths at filelocation and filetargetlocation parameters and the result is entirely without backlashes. Our question is: What is going on? Why does it remove backslashes?

Edit: if we put 4 backslashes into the function parameter then it outputs 1 backslash. If we put 8 backslashes into the function parameter then it outputs 2 backslash

Upvotes: 0

Views: 1436

Answers (1)

404
404

Reputation: 8572

Ok based on the dbfiddle I can see what the issue is. (BTW it doesn't like dollar quoting in there, that's why you can't run it. You just need to replace $$ with ' to quote it as a string, and it will run.)

Your input is '{"(c:\\\\\\\rs\\me, Path, lang)"}'. It's a an array of a type.

Let's take a simple type: CREATE TYPE public.t AS (txt TEXT). When you select a type as a row, rather than with the fields expanded, any "special" characters will be escaped.

So: SELECT ROW('C:\temp')::public.t returns ("C:\\temp"), and expanding it via SELECT (ROW('C:\temp')::public.t).* returns C:\temp.

Your input is a row (it uses the (data1,data2,etc) notation, which is a row literal, and unexpanded), therefore all backslashes are escaped. The path part of your expanded row (SELECT ('(c:\\\\\\\rs\\me, Path, lang)'::public.filenotification_input).*) would be c:\\\rs\me.

However there's one more level of escaping: the fact that the data is in an array. Same as with an unexpanded row, special characters will be escaped in an array. Running SELECT ARRAY['C:\temp'] returns ["C:\\temp"].

Put them together, and you have backslashes needing escaping in your row, and each of those then needs escaping in the array. So to get a single backslash in "normal" text, you have to escape it in the row (\\) and then escape each of those in the array (\\\\).

So you need 4 backslashes in order to insert a single backslash into your table, given the way you supply your input.

Run this and have a look at the various outputs: https://www.db-fiddle.com/f/83wBZsztETriNtZGDVXdcN/0

Upvotes: 1

Related Questions