Re: FUNCTIONs and CASTs - Mailing list pgsql-sql

From Richard Huxton
Subject Re: FUNCTIONs and CASTs
Date
Msg-id 47B55DA1.1060706@archonet.com
Whole thread Raw
In response to Re: FUNCTIONs and CASTs  ("Dean Gibson (DB Administrator)" <postgresql@ultimeth.com>)
Responses Re: FUNCTIONs and CASTs  ("Dean Gibson (DB Administrator)" <postgresql@ultimeth.com>)
List pgsql-sql
Dean Gibson (DB Administrator) wrote:
> On 2008-02-14 15:19, Tom Lane wrote:
>> It's not exactly clear what you checked, but it works as expected for 
>> me.  See test case below, proving that indexscan works just fine with 
>> a parameter declared using %type.
> 
> Consider:
> 
> CREATE TABLE zzz( aaa CHAR( 10 ) );
> 
> CREATE FUNCTION dummy( zzz.aaa%TYPE ) RETURNS zzz.aaa%TYPE
>    LANGUAGE SQL AS 'SELECT * FROM zzz WHERE CAST( $1 AS zzz.aaa%TYPE) = 
> aaa';
> 
> The notation "zzz.aaa%TYPE" fails when specified in the cast;  it's fine 
> in the function prototype.  However, specifying it in the function 
> prototype doesn't appear to help the performance issue:

I get the same result: "works here".

richardh=> CREATE TABLE zzz( aaa CHAR( 10 ) );
CREATE TABLE

richardh=> INSERT INTO zzz SELECT generate_series(1,100000)::text;
INSERT 0 100000

richardh=> CREATE INDEX zzz_aaa_idx ON zzz (aaa);
CREATE INDEX

richardh=> CREATE OR REPLACE FUNCTION dummy2( zzz.aaa%TYPE ) RETURNS 
zzz.aaa%TYPE
richardh->    LANGUAGE SQL AS $$SELECT * FROM zzz WHERE aaa = $1 $$;
NOTICE:  type reference zzz.aaa%TYPE converted to character
NOTICE:  type reference zzz.aaa%TYPE converted to character
CREATE FUNCTION
Time: 15.268 ms
richardh=> SELECT dummy2('99999');   dummy2
------------ 99999
(1 row)

Time: 1.962 ms
richardh=> DROP INDEX zzz_aaa_idx;
DROP INDEX

richardh=> SELECT dummy2('99999');   dummy2
------------ 99999
(1 row)

Time: 45.418 ms


What does this do on your machine?

> Here is the actual function that caused be heartburn.  The types in the 
> function prototype match EXACTLY the types of the actual parameters 
> being passed (and I also tried it with the tablename.columnname%TYPE 
> notation), and yet this function is slow.  However, if I replace the 
> "$1" in the function body with "CAST( $1 AS CHAR( 10 ) )", the function 
> is very fast.  Note that ALL of the column names in the function below 
> are indexed, so this function should be very fast (and is, with the CASTs).

Hang on though - this function isn't using %TYPE, it's using explicit 
type definitions. If this function is slow, how can it be anything do 
with %TYPE ?

> CREATE OR REPLACE FUNCTION      "Functions".prior_call( CHAR( 10 ), 
> CHAR( 9 ), DATE)  RETURNS BOOLEAN
>    STABLE  RETURNS NULL ON NULL INPUT  LANGUAGE SQL AS $SQL$
>        SELECT  COALESCE(       (SELECT TRUE
>                                    FROM                lic_hd
>                                        NATURAL JOIN    lic_en
>                                        NATURAL JOIN    lic_am
>                                    WHERE        $1 = licensee_id
>                                      AND       $2                      
> IN( callsign, prev_callsign )
>                                      AND       $3                      > 
> grant_date
>                                    LIMIT 1),
>                                (SELECT TRUE
>                                    FROM                _preuls
>                                    WHERE        $1 = licensee_id
>                                      AND       $2                      
> IN( callsign, prev_callsign )
>                                    LIMIT 1),
>                                FALSE )
>    $SQL$;
> 
> So, I think you can see why it would be nice if the 
> tablename.columnname%TYPE notation could be used in the function body.

Shouldn't be necessary (see above).

> I'm not asking for that as an enhancement; rather, I'm trying to 
> understand what the tablename.columnname%TYPE notation accomplishes, 
> since specifying it in the function prototype doesn't appear to 
> accomplish anything (at least for me) over just specifying "TEXT".

It specifies the type of the variable (or parameter) in question. The 
reason you can't use %TYPE directly in your SQL is because afaik it's 
not SQL - it's a PostgreSQL extension designed to specify variable types 
in functions. SQL constructs tend to expect a literal type name.

I'm not sure what your problem is, but it's not the %TYPE operator, 
that's clear.

Can you try reproducing the function as a prepared query? That way you 
can run EXPLAIN ANALYSE on it and see what's actually happening here.

--   Richard Huxton  Archonet Ltd


pgsql-sql by date:

Previous
From: Richard Huxton
Date:
Subject: Re: Function description
Next
From: Richard Huxton
Date:
Subject: Re: Function description