I have a function registration()
, which is supposed to add a row to a table under certain circumstances. I've included a snippet of code and output from a call.
If select *
returns a non-empty table row (which it does according to the RAISE NOTICE
) I want to raise the exception and not add the row. The example seems to show that rowt
is not null, and yet rowt IS NOT NULL
returns f
(and the exception is not raised).
I hope this is something minor I'm not seeing.
select * into rowt from Email where email_email = eml;
RAISE NOTICE '%, rowt IS NOT NULL:%',rowt, rowt IS NOT NULL;
if rowt IS NOT NULL THEN
RAISE EXCEPTION 'email address, %, already registered.' , eml;
END IF;
Output:
NOTICE: (7,,,), rowt IS NOT NULL:f
registration
--------------
21
(1 row)
CREATE TABLE IF NOT EXISTS Email (
email_email VARCHAR(50) NOT NULL,
email_password VARCHAR(50) NOT NULL,
email_id integer DEFAULT nextval('email_email_id_seq'::regclass) NOT NULL,
email_person_id integer
);
CREATE OR REPLACE FUNCTION registration( wr text ) RETURNS integer AS $rL$
DECLARE
eml text;
pwd text;
nm text;
rle text;
emid integer;
rowt Email%ROWTYPE;
BEGIN
eml := getWebVarValue( wr , 'email' );
select * into rowt from Email where email_email = eml;
RAISE NOTICE '%, rowt IS NOT NULL:%', rowt, rowt IS NOT NULL;
IF rowt IS NOT NULL THEN
RAISE EXCEPTION 'email address, %, already registered.' , eml;
END IF;
pwd := getWebVarValue( wr , 'password' );
IF pwd IS NULL THEN
RAISE EXCEPTION 'No password specified in registration.';
END IF;
INSERT INTO Email VALUES (eml,pwd) RETURNING Email.email_id INTO emid;
--nm = getWebVarValue( wr , 'name' );
--rle = getWebVarValue( wr , 'role' );
RETURN emid;
END;
$rL$ LANGUAGE plpgsql;
Test on NULL for ROW type is specific:
So
NOT NULL
returns true only when all fields are not null.I had the same problem and solved it by casting to
::text
(arr[1]::text is not null
) within an SQL select accessing some array within a composite/record type similar to this:So
as_txt_nn
condition properly checks for the problem to differentiate between row 2 and 3 related to the question, if the first array composite is null or given.The
nn
condition behaves (as mentioned in previous posts) in a way, that it only returnstrue
, if ALL composite columns arenot null
.It should work for PGPLSQL functions as well.
As @Pavel provided, the check
<row-type> IS NOT NULL
doesn't work like you seem to expect. It returnsTRUE
if (and only if) every single column isNOT NULL
.Test the special variable
FOUND
instead (like @Mike commented):Or you could invert your expression in the test.
Any existing row you would find contains at least one column that is
NOT NULL
, thereforerowt IS NULL
only returnsTRUE
if nothing is found.Related answers with more details:
You only want to test, whether the row with that email exists.
This can be achieved simply, with an
EXISTS
sub-query expression:The special variable
FOUND
could work too, but it's have more value, when you want to use some fields from the found row.In general,
<row-type> IS [ NOT ] [ DISTINCT FROM ] NULL
has special rules, and does not always inverse of each other (like @Pavel noted); there are 3 distinct method to test against some kind of unknown state:SQLFiddle
Also, there is some change in the handling of operators, when someone uses composite types, instead of row constructors:
1 though I could not find any query, which works that way.
From your code it follows that you want to register an email address by inserting it in a table, but only if the email address isn't already registered and a password is supplied. For starters, you should change your table definition to reflect those requirements:
The
UNIQUE
constraint onaddr
means that PG will not allow duplicate email addresses so you don't have to test for that. You should instead test for a unique violation when doing the insert.For the function I suggest you pass in the email address and password, instead of putting the business logic inside the function. Like this the function has fewer dependencies and can be re-used in other contexts more easily (such as registering an email address via some other means via your web app). Making the function
STRICT
ensures thatpwd
is not null so that saves you another test.