Thread: Passing a null value in pl/pgsql

Passing a null value in pl/pgsql

From
Mike Finn
Date:
I have two stored procedures and one calls the other.  If
the caller passes a null for one of the parameters (the fourth) a delete
query in the called function will not work.

If I pass a null as the 4th parameter (_seqSalesOrderLine) the delete
query below will not match any records, and my business rule fails.  If I
temporarily (for testing only) change the asterisked line to read
   and seqSalesOrderLine = null
the query works as I would expect.

Am I missing something (please tell me) or is this a bug when passing in a
null value?

Thanks for any help,
Mike.


Bits of called function (asterisks mark important lines)
===========================================================================
    create function salesOrderTax_apply(int8,int8,
                                        text,int8,float8,
                                        int8,text) returns integer as '
        declare
            ...
*           _seqSalesOrderLine  alias for $4;
            ...
        begin
            ...
            delete from salesOrderTax
            where seqSalesOrder = soRec.seqSalesOrder
            and codeSalesOrderTax = _codeSalesOrderTax
*           and seqSalesOrderLine = _seqSalesOrderLine
            ;
            ...
            return null; --bogus return value
        end;
    ' language 'plpgsql';


Bits of calling function (asterisks mark important lines)
===========================================================================
    create function salesOrderControl_freightTax(int8, int8,text)
                                                  returns integer as '
        declare
            ...
            _seqTaxSchedule    int8;
            ...
        begin
            ...
            -- get the appropriate tax schedule
            select seqTaxSchedule
            into _seqTaxSchedule
            from carrier
            where name = soRec.carrier_name
            ;
            ...
            perform
               salesOrderTax_apply(soRec.seqSalesOrder, _seqTaxSchedule,
*                                  ''Freight'', null, socRec.totalFreight,
                                   _txSeq, _txUser
                                  );

            return null; --bogus return value
        end;
    ' language 'plpgsql';


=========================================
Mike Finn
mike.finn@tacticalExecutive.com


Re: Passing a null value in pl/pgsql

From
Stephan Szabo
Date:
On Mon, 14 Jan 2002, Mike Finn wrote:

> I have two stored procedures and one calls the other.  If
> the caller passes a null for one of the parameters (the fourth) a delete
> query in the called function will not work.
>
> If I pass a null as the 4th parameter (_seqSalesOrderLine) the delete
> query below will not match any records, and my business rule fails.  If I
> temporarily (for testing only) change the asterisked line to read
>    and seqSalesOrderLine = null
> the query works as I would expect.

The only reason the above works is probably due to the hack that treats
the explicit = NULL token sequence as IS NULL which is the correct way to
compare for nulls.  SQL basically wants = between a NULL value and
anything to be unknown.


Re: Passing a null value in pl/pgsql

From
Tom Lane
Date:
Mike Finn <mike.finn@tacticalExecutive.com> writes:
> If I temporarily (for testing only) change the asterisked line to read
>    and seqSalesOrderLine = null
> the query works as I would expect.

Unfortunately "NULL = NULL" does not return TRUE in SQL, it returns
NULL, which is treated as FALSE in the context of a WHERE clause.

The reason the hacked query appears to work is that "foo = NULL" (where
the word NULL appears explicitly) is presently converted to "foo IS NULL"
(the behavior you actually want) by the Postgres parser.  This behavior
is not valid per standard and has confused a lot of people besides you,
so it's going away in the next release.

If you want to have NULL in your parameter match up with NULL in your
database then you'll need to write something like

    (seqSalesOrderLine = _seqSalesOrderLine OR
     (seqSalesOrderLine IS NULL AND _seqSalesOrderLine IS NULL))

which is not only ugly as sin but probably won't run quickly, since it
won't be indexable.

I counsel rethinking how you are using NULLs ... if you are trying to
search for them then you probably aren't using them the way SQL expects,
and you are going to find yourself constantly fighting the language
rather than working comfortably with it.

            regards, tom lane