146

Being completely new to PL/pgSQL , what is the meaning of double dollar signs in this function:

CREATE OR REPLACE FUNCTION check_phone_number(text)
RETURNS boolean AS $$
BEGIN
  IF NOT $1 ~  e'^\\+\\d{3}\\ \\d{3} \\d{3} \\d{3}$' THEN
    RAISE EXCEPTION 'Wrong formated string "%". Expected format is +999 999';
  END IF;
  RETURN true; 
END;
$$ LANGUAGE plpgsql STRICT IMMUTABLE;

I'm guessing that, in RETURNS boolean AS $$, $$ is a placeholder.

The last line is a bit of a mystery: $$ LANGUAGE plpgsql STRICT IMMUTABLE;

By the way, what does the last line mean?

mu is too short
  • 426,620
  • 70
  • 833
  • 800
vector
  • 7,334
  • 8
  • 52
  • 80
  • 4
    Please consider marking Erwin response as answer to this question, his description explains what actually are `$$` and you can learn something new by reading it e.g. there is also `$foo$` – csharpfolk Aug 06 '16 at 06:33

2 Answers2

212

These dollar signs ($$) are used for dollar quoting, which is in no way specific to function definitions. It can be used to replace single quotes enclosing string literals (constants) anywhere in SQL scripts.

The body of a function happens to be such a string literal. Dollar quoting is a PostgreSQL-specific substitute for single quotes to avoid escaping of nested single quotes (recursively). You can enclose the function body in single-quotes just as well. But then you have to escape all nested single quotes:

CREATE OR REPLACE FUNCTION check_phone_number(text)
  RETURNS boolean
  LANGUAGE plpgsql STRICT IMMUTABLE AS
'
BEGIN
  IF NOT $1 ~  e''^\\+\\d{3}\\ \\d{3} \\d{3} \\d{3}$'' THEN
    RAISE EXCEPTION ''Malformed string: "%". Expected format is +999 999'', $1;
  END IF;
  RETURN true; 
END
';

(Added the missing parameter for RAISE, btw.)

This isn't such a good idea. Use dollar-quoting instead. More specifically, also put a (meaningful) token inside the $$ to avoid confusion with nested quotes in the function body. A common case, actually.

CREATE OR REPLACE FUNCTION check_phone_number(text)
  RETURNS boolean  
  LANGUAGE plpgsql STRICT IMMUTABLE AS
$func$
BEGIN
 ...
END
$func$;

See:

To your second question:
Read the most excellent manual on CREATE FUNCTION to understand the last line of your example.

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • 2
    You're supposed to say *fine manual*, RTEM just doesn't have the right ring to it :) – mu is too short Aug 29 '12 at 07:34
  • @muistooshort: My bad, trying a variation on the theme seems to have broken the harmony. How do you like RTMEM? :) – Erwin Brandstetter Aug 29 '12 at 08:03
  • 1
    I tried yelling it and it just wasn't the same. Although, there are some situations where politeness counts. – mu is too short Aug 29 '12 at 08:16
  • @ErwinBrandstetter Okay, but what is `$body$`? From `CREATE OR REPLACE FUNCTION update_ts() RETURNS TRIGGER AS $BODY$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $BODY$ LANGUAGE plpgsql` - I don't see `body` defined anywhere. I really have no idea what is going on here – user3871 Feb 02 '17 at 03:55
  • 2
    @Growler: `$body$` is just "dollar-quoting", like I explained. More details: http://stackoverflow.com/a/12320729/939860 – Erwin Brandstetter Feb 02 '17 at 04:19
  • Thanks for that man, faced with a strange behavior creating PG function via Terraform and using $$. Change to single quotes has helped. – kolyaiks Jun 27 '22 at 17:16
  • I'm getting an exception. "No function body specified" – MA1 Jul 28 '23 at 15:49
  • @MA1 I can't reproduce that exception. Fixed an unrelated syntax error in `RAISE` that I had copied from the OP, though. – Erwin Brandstetter Jul 30 '23 at 22:21
25

The $$ is a delimiter you use to indicate where the function definition starts and ends. Consider the following,

CREATE TABLE <name> <definition goes here> <options go here, eg: WITH OIDS>

The create function syntax is similar, but because you are going to use all sorts of SQL in your function (especially the end of statement ; character), the parser would trip if you didn't delimit it. So you should read your statement as:

CREATE OR REPLACE FUNCTION check_phone_number(text)
RETURNS boolean AS <code delimited by $$> LANGUAGE plpgsql STRICT IMMUTABLE;

The stuff after the actual definition are options to give the database more information about your function, so it can optimize its usage.

In fact, if you look under "4.1.2.4. Dollar-Quoted String Constants" in the manual, you will see that you can even use characters in between the dollar symbols and it will all count as one delimiter.

jdhao
  • 24,001
  • 18
  • 134
  • 273
Captain Coder
  • 798
  • 5
  • 12
  • As stated in the correct answer, this is inaccurate, double dollar signs delimit a constant string and are not specific to functions. – Guido Tarsia Apr 27 '23 at 00:12