Thread: inconsistent automatic casting between psql and function

inconsistent automatic casting between psql and function

From
"Stefano Buliani"
Date:
Hello all,
 
I'm experiencing a strange problem with postgresql 8.3.4.
 
I have the following table
 
tx_queue
txid serial
securityid integer
portfolioid integer
datequeued timestamp default now()
tradedate date
numshares numeric(25,7)
transactiontype char(1)
tradeprice numeric(25,7)
 
every time a new tx is created in the table I need to check if it's the result of 2 previous transaction being aggregated:
 
I receive 2 tx with the following values:
securityid, portfolioid, tradedate, numshares, transactiontype, tradeprice
2, 1, '2008-12-08', 2, 'B', 15.23
2, 1, '2008-12-08', 6, 'B', 15.23
 
Later I'll receive another tx:
2, 1, '2008-12-08', 8, 'B', 15.23
 
This isn't a new trade but just the sum of the previous 2 it should be therefore ignored.
 
To create the tx in the table I use a function which receives all the values and runs the following query to check whether it's a sum of previous txs. (The tradedate is passed as a timestamp)
 
 SELECT INTO  vpsum sub1.possible_sum
        FROM (
          SELECT tq.securityid, date_trunc('hour', tq.datequeued) AS split_tq_time, count(*) AS cnt,
          sum(tq.numshares) as possible_sum, tq.transactiontype, tq.tradeprice, tq.portfolioid
          FROM tx_queue AS tq
          WHERE tq.securityid= 2
            AND tq.tradeprice = 15.23
            AND tq.portfolioid = 1
            AND tq.tradedate = '2008-12-08 02:00:00'
            AND tq.datequeued + interval '1 hour' <= now() -- tx received more than 1 hour ago
          GROUP BY date_trunc('hour', tq.datequeued), tq.securityid, tq.portfolioid, tq.tradeprice, tq.transactiontype  
          HAVING count(*)>1
        ) AS sub1
        WHERE sub1.possible_sum = 8.0000000
        ORDER BY sub1.split_tq_time DESC
        LIMIT 1;
 
If I run this query from the psql client it works just fine. From the function it doesn't return anything.
What I discovered is that for it to work from the function I need to explicitly cast the tradedate variable to DATE (ie '2008-12-08 02:00:00'::DATE - Note the field is of type date).
 
It would seem that the psql client casts the value automatically.
Any reason why this should be?
This inconsistent behaviour makes code much harder to debug.
 
Regards,
  Stefano
 
 
---------------------------------
Stefano Buliani
Covestor
This message is intended solely for the recipient(s) to whom it is addressed.  If you are not the intended recipient, you should not disclose, distribute or copy this email.  Please notify the sender immediately and delete this email from your system.

Re: inconsistent automatic casting between psql and function

From
Richard Huxton
Date:
Stefano Buliani wrote:
> If I run this query from the psql client it works just fine. From the function it doesn't return anything.
> What I discovered is that for it to work from the function I need to explicitly cast the tradedate variable to DATE
(ie'2008-12-08 02:00:00'::DATE - Note the field is of type date).
 
> 
> It would seem that the psql client casts the value automatically. 
> Any reason why this should be? 
> This inconsistent behaviour makes code much harder to debug.

Seems unlikely. Can't reproduce the problem assuming you're using a
quoted literal as your query shows.

=> CREATE FUNCTION date_test() RETURNS boolean AS $$BEGIN RETURN
current_date = '2008-12-09 02:00:00'; END;$$ LANGUAGE plpgsql;
CREATE FUNCTION
=> SELECT date_test();date_test
-----------t

=> SELECT current_date = '2008-12-09 02:00:00';?column?
----------t

On the other hand, if you are using variable interpolation:

CREATE OR REPLACE FUNCTION date_test2(timestamp) RETURNS boolean AS
$$BEGIN RETURN current_date = $1; END;$$ LANGUAGE plpgsql;
CREATE FUNCTION
=> SELECT date_test2('2008-12-09 02:00:00');date_test2
------------f

=> SELECT current_date = '2008-12-09 02:00:00'::timestamp;?column?
----------f

That's because a quoted literal isn't necessarily a timestamp. Without
context it could be anything, and in the context of comparing to a date
the planner probably tries to make it a date.

Your variable is definitely a timestamp though (you've said so
explicitly) so PG has to decide what it means to compare a date to a
timestamp. It decides the reasonable approach is to turn the date into a
timestamp (by adding '00:00:00' to it) and then the comparison fails.
That seems reasonable to me - you're unlikely to want to discard
information from an equality test.


The obvious question is - why are you comparing a date to a timestamp in
the first place?

--  Richard Huxton Archonet Ltd


Re: inconsistent automatic casting between psql and function

From
Richard Huxton
Date:
Stefano Buliani wrote:
> Richard,
> 
> understand I shouldn't be comparing a date to a timestamp. Fact is I
> need the full timestamp to process other info in the rest of the function.
> 
> My question is: why is the planner casting the timestamp to date when I
> run the query from psql and the other way around from the function?

It's not. As I said, a quoted literal isn't necessarily a timestamp.

This: '2008-12-09 18:23:00' is not a timestamp.

It is an untyped quoted literal that contains something I'll grant
*looks* like a timestamp, but we can't tell what it is really supposed
to be until it's used.

SELECT length('2008-12-09 18:00:00');

Here it must be text (because we don't have a length() defined for
timestamps - see \df length).

=> SELECT date_trunc('month', '2008-12-09 18:00:00');
ERROR:  function date_trunc(unknown, unknown) is not unique
LINE 1: SELECT date_trunc('month', '2008-12-09 18:00:00');              ^
HINT:  Could not choose a best candidate function. You might need to add
explicit type casts.

Here it couldn't decide (\df date_trunc to see what it was choosing between)

And in the next one it guesses it has an interval (because that's what
the other thing is, I'm guessing).

=> SELECT '2008-12-09 18:00:00' + '2 hours'::interval;
ERROR:  invalid input syntax for type interval: "2008-12-09 18:00:00"


So - it's not casting from timestamp to date, it's casting from
"unknown" to date in your interactive sql.

--  Richard Huxton Archonet Ltd


Re: inconsistent automatic casting between psql and function

From
Tom Lane
Date:
Richard Huxton <dev@archonet.com> writes:
> That's because a quoted literal isn't necessarily a timestamp. Without
> context it could be anything, and in the context of comparing to a date
> the planner probably tries to make it a date.

I think the real point here is this:

regression=# select '2008-12-09 02:00:00'::date;   date    
------------2008-12-09
(1 row)

ie, when it does decide that a literal should be a date, it will happily
throw away any additional time-of-day fields that might be in there.
Had it raised an error, Stefano might have figured out his mistake
sooner.

ISTM we deliberately chose this behavior awhile back, but I wonder
whether it does more harm than good.
        regards, tom lane


unique constraint on views

From
"Jyoti Seth"
Date:
Hi All,

Is it possible to add unique constraint on updateable views in postgres?

Thanks,
Jyoti Seth



Re: unique constraint on views

From
"A. Kretschmer"
Date:
In response to Jyoti Seth :
> Hi All,
> 
> Is it possible to add unique constraint on updateable views in postgres?

Add the constraint to the base-table.

Andreas
-- 
Andreas Kretschmer
Kontakt:  Heynitz: 035242/47150,   D1: 0160/7141639 (mehr: -> Header)
GnuPG-ID:   0x3FFF606C, privat 0x7F4584DA   http://wwwkeys.de.pgp.net


Re: inconsistent automatic casting between psql and function

From
Bruce Momjian
Date:
Tom Lane wrote:
> Richard Huxton <dev@archonet.com> writes:
> > That's because a quoted literal isn't necessarily a timestamp. Without
> > context it could be anything, and in the context of comparing to a date
> > the planner probably tries to make it a date.
> 
> I think the real point here is this:
> 
> regression=# select '2008-12-09 02:00:00'::date;
>     date    
> ------------
>  2008-12-09
> (1 row)
> 
> ie, when it does decide that a literal should be a date, it will happily
> throw away any additional time-of-day fields that might be in there.
> Had it raised an error, Stefano might have figured out his mistake
> sooner.
> 
> ISTM we deliberately chose this behavior awhile back, but I wonder
> whether it does more harm than good.

Well, it seems fine to me because it works just like the cast of a float
to an integer:
test=> select 1.23432::integer; int4------    1(1 row)

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: unique constraint on views

From
"Jyoti Seth"
Date:
I want to put unique constraint on columns of more than one table. 

-----Original Message-----
From: pgsql-sql-owner@postgresql.org [mailto:pgsql-sql-owner@postgresql.org]
On Behalf Of A. Kretschmer
Sent: Wednesday, December 10, 2008 6:04 PM
To: pgsql-sql@postgresql.org
Subject: Re: [SQL] unique constraint on views

In response to Jyoti Seth :
> Hi All,
> 
> Is it possible to add unique constraint on updateable views in postgres?

Add the constraint to the base-table.

Andreas
-- 
Andreas Kretschmer
Kontakt:  Heynitz: 035242/47150,   D1: 0160/7141639 (mehr: -> Header)
GnuPG-ID:   0x3FFF606C, privat 0x7F4584DA   http://wwwkeys.de.pgp.net

-- 
Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-sql