Re: PostgreSQL Advocacy, Thoughts and Comments - Mailing list pgsql-general

From Rory Campbell-Lange
Subject Re: PostgreSQL Advocacy, Thoughts and Comments
Date
Msg-id 20031215173007.GA19426@campbell-lange.net
Whole thread Raw
In response to Re: PostgreSQL Advocacy, Thoughts and Comments  (merlyn@stonehenge.com (Randal L. Schwartz))
List pgsql-general
On 29/11/03, Randal L. Schwartz (merlyn@stonehenge.com) wrote:
> Well, since I need 2.5 ideas per month for the three columns I'm still
> writing, I'm certainly in a position to write nice things about PG,
> although I always have to work it in from a Perl slant.
>
> Actually, I'm sure that any of the magazines I'm in would appreciate
> an additional article or two from me.
>
> If you can think of something that fits in 2000 words or so (or 4000
> if it needs part 1 and 2), and can have a Perl wrapper, I'd appreciate
> some inspiration.

Hi Randal

I think I may have an idea for an article which would address a common
problem for people writing database client interfaces:

The problem is simply explained.

Problem title:

    The "page of pages" problem (!)

The problem:

    You want to return a subset of a large number items using some
    fairly complex search criteria. You want to make only one database
    call, benefit from a cached query, and don't want to have all the
    rows in memory. How do you get the total count of pages for the
    relevant search criteria?

Why is this relevant?

    Moving logic that is inherent to the database to the database
    provides a potentially rich yet simple interface to database
    queries that can benefit a number of client applications.

    Typically this sort of query would be written as at least two
    dynamically generated queries in the client program that has to be
    parsed by the backend before it is executed. By using functions we
    can hide complex joins behind simple field names, and provide
    flexible (if limited) search capabilites, as well as caching and
    sensible error messages.

Approach:

    Using Postgres one can construct a function and then do either

       SELECT * from function fn_explore($searchstring, $limit, $offset);
    OR
       SELECT
        *
       FROM
        function fn_explore()
       WHERE
        searchterm ~* 'test'
       LIMIT
        5
       OFFSET
        10;

    What is cool about the second format is that (if the function
    returned a type 'explore_result' as below), your PHP/Perl programmer
    can at their interface do something like

        '... where id <> 1 AND author IN ('james', 'bill')...'

    However I don't know how you get back the total rows in this case,
    also maybe the caching effects are minimised?

    --------------------------------------------------------------------
    Type definition:

    CREATE TYPE explore_result as (
        id                 INTEGER,   -- some sort of row id
        total              INTEGER,   -- total rows for query
        author             VARCHAR,
        image              BYTEA
        /*
        Not needed unless search is done outside db.
        , searchterm         VARCHAR
        */
    );

    --------------------------------------------------------------------
    Sketch function definition:

    CREATE OR REPLACE FUNCTION
        fn_explore (integer, integer, integer) RETURNS setof explore_result
    AS '
    DECLARE
        searchstring  ALIAS for $1;
        offsetter     ALIAS for $2;
        limiter       ALIAS for $3;
        resulter      explore_page%rowtype;
    BEGIN

        /*
          variable verifation section chopped
        */

        FOR resulter IN
            SELECT
                n_id                                          as id,
                LOJ.pagetotal                                 as total
                pers.t_name                                   as author,
                image.b_contents                              as image
                /*
                need searchterm returned if we are doing search outside
                the database
                , COALESCE(t_title || '' '' || t_text,  '''') as searchterm

            FROM
                db
                /*
                -> self join on db LOJ for unoffset, unlimited row count
                   refer to searchterm stuff below
                */
            WHERE
                /* note, if we are doing a search outside of the
                 * function and t_title or t_text could be empty then we
                 * need to coalesce to an empty string
                 * COALESCE(t_title || '' '' || t_text,  '''') as searchterm
                 */
                 searchstring ~ t_title || '' '' || t_text
            ORDER BY
                dt_modified DESC
            LIMIT
                limiter
            OFFSET
                offsetter
                ,

             LOOP

            RETURN NEXT
                resulter;

        END LOOP;

        RETURN;
    END;'
        LANGUAGE plpgsql;

--
Rory Campbell-Lange
<rory@campbell-lange.net>
<www.campbell-lange.net>

pgsql-general by date:

Previous
From: Joel Rodrigues
Date:
Subject: Re: make error Mac OS X (ar: illegal option -- s)
Next
From: "C G"
Date:
Subject: Re: Changing user