Using a plpgsql procedure to extract a record if it exists, and then if it does, do something with it.
The variable is a rowtype:
my_var my_table%rowtype;
I populate it with a SQL statement:
select * from my_table where owner_id = 6 into my_var;
I know it definitely has the row:
raise notice 'my_var is %', my_var;
Returns:
NOTICE:  my_var is (383,6,10)
But now I want to test that it got the record and BOTH of these if conditions fail:
if my_var is null then
  raise notice 'IT IS NULL';
end if;
if my_var is not null then
  raise notice 'IT IS NOT NULL';
end if;
Neither of these raises appear in my messages log - it just never enters the blocks.  What's the correct way to test if you received a row from a SELECT * INTO?
I see two possible reasons, why ...
Neither of these raises appear in my messages log
Firstly, a NOTICE is not normally written to the database log with default settings. The manual:
log_min_messages(enum)Controls which message levels are written to the server log. Valid values are
DEBUG5,DEBUG4,DEBUG3,DEBUG2,DEBUG1,INFO,NOTICE,WARNING,ERROR,LOG,FATAL, andPANIC. (...)
The default is WARNING. Note thatLOGhas a different rank here than inclient_min_messages.
Bold emphasis mine. Also note the different default (NOTICE) for client_min_messages (preceding item in the manual).
Secondly, consider how a row expression is evaluated. A test row_variable IS NULL returns TRUE if (and only if) every single element is NULL. Consider:
SELECT (1, NULL) IS NULL     AS a  -- FALSE
     , (1, NULL) IS NOT NULL AS b  -- also FALSE!
Both expressions return FALSE. In other words, a row (or record) variable (1, NULL) is neither NULL, nor is it NOT NULL. Therefore, both of your tests fail.
sqlfiddle with more details
Related:
You can even assign a record variable with NULL (rec := NULL), which results in every element being NULL - if the type is a well-known row type. Otherwise, we are dealing with an anonymous record and the structure is undefined and you cannot access elements to begin with. But that's not the case with a rowtype like in your example (which is always well-known).
FOUND
What's the correct way to test if you received a row from a
SELECT * INTO?
You have to consider that the row could be NULL, even if it was assigned. The query could very well have returned a bunch of NULL values (if the table definition in your query allows NULL values).
There is a simple and secure approach. Use GET DIAGNOSTICS or, where applicable, the special variable FOUND:
SELECT * FROM my_table WHERE owner_id = 6 INTO my_var;
IF NOT FOUND THEN
   RAISE NOTICE 'Query did not return a row!';
END IF;
Details in the manual.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With