1

I'm trying to write a function that makes an insert to the table defined below:

DROP TABLE IF EXISTS pl_table;
CREATE TABLE pl_table
(
    id          SERIAL PRIMARY KEY,
    mandatory   VARCHAR NOT NULL,
    option1     VARCHAR DEFAULT null,
    option2     VARCHAR DEFAULT null
);

The idea is to make only one argument mandatory and other two optional. The function listed below works well for all three inputs being present, but doesn't make an insert if less than three arguments are provided. What should I do to to make the function work for the Case1?

CREATE OR REPLACE FUNCTION pl_test_function(mand_arg varchar
                                          , opt_arg1 varchar DEFAULT NULL
                                          , opt_arg2 varchar DEFAULT NULL) RETURNS void AS 
$$
BEGIN
      INSERT INTO pl_table (mandatory, option1, option2) VALUES
             (mand_arg, opt_arg1, opt_arg2);
END;
$$
      LANGUAGE plpgsql STRICT;

SELECT pl_test_function('abc'); -- Case1: doesn't work
SELECT pl_test_function('abc', 'xyz', 'def'); -- Case2: works

Please note that the pl_test_function doesn't return anything in this toy example, but in reality its more complex production cousin returns an integer.

2 Answers 2

2

You need to remove the clause STRICT according to the documentation :

...RETURNS NULL ON NULL INPUT or STRICT indicates that the function always returns null whenever any of its arguments are null. If this parameter is specified, the function is not executed when there are null arguments; instead a null result is assumed automatically...

Use your code like this:

CREATE OR REPLACE FUNCTION pl_test_function(mand_arg varchar
                                          , opt_arg1 varchar DEFAULT NULL
                                          , opt_arg2 varchar DEFAULT NULL) RETURNS void AS 
$$
BEGIN
      INSERT INTO pl_table (mandatory, option1, option2) VALUES
             (mand_arg, opt_arg1, opt_arg2);
END;
$$
      LANGUAGE plpgsql ;

1

You can do it with a CASE statement:

CASE WHEN opt_arg1 IS NOT NULL AND opt_arg2 IS NOT NULL
     THEN INSERT INTO pl_table (mandatory, option1, option2) VALUES
             (mand_arg, opt_arg1, opt_arg2);
     WHEN opt_arg1 IS     NULL AND opt_arg2 IS NOT NULL
     THEN INSERT INTO pl_table (mandatory, option1, option2) VALUES
             (mand_arg, DEFAULT, opt_arg2);
     WHEN opt_arg1 IS NOT NULL AND opt_arg2 IS     NULL
     THEN INSERT INTO pl_table (mandatory, option1, option2) VALUES
             (mand_arg, opt_arg1, DEFAULT);
     ELSE INSERT INTO pl_table (mandatory, option1, option2) VALUES
             (mand_arg, DEFAULT, DEFAULT);
END CASE;

or you can use dynamic SQL:

DECLARE
   sql text;
BEGIN
   sql := format(
             'INSERT INTO pl_table (mandatory, option1, option2) VALUES (%L, %s, %s)',
             mand_arg,
             CASE WHEN opt_arg1 IS NULL THEN 'DEFAULT' ELSE quote_literal(opt_arg1),
             CASE WHEN opt_arg2 IS NULL THEN 'DEFAULT' ELSE quote_literal(opt_arg2),
          );
   EXECUTE sql;
END;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.