                                PL/pgSQL
             A procedural language for the PostgreSQL RDBMS

                      Jan Wieck <jwieck@debis.com>



    Preface

        PL/pgSQL  is  a procedural language based on SQL designed for
        the PostgreSQL database system.

        The extensibility features of PostgreSQL are mostly based  on
        the  ability  to  define  functions  for  various operations.
        Functions could have been written in PostgreSQL's SQL dialect
        or  in the C programming language. Functions written in C are
        compiled into a shared object  and  loaded  by  the  database
        backend  process  on  demand.   Also  the trigger features of
        PostgreSQL are based on functions but required the use of the
        C language.

        Since  version  6.3  PostgreSQL  supports  the  definition of
        procedural languages. In the case of a  function  or  trigger
        procedure  defined in a procedural language, the database has
        no builtin knowlege how to  interpret  the  functions  source
        text. Instead, the function and trigger calls are passed into
        a handler that  knows  the  details  of  the  language.   The
        handler  itself  is  a function compiled into a shared object
        and loaded on demand.


    Overview

        The PL/pgSQL language is case insensitive. All  keywords  and
        identifiers can be used in upper-/lowercase mixed.

        PL/pgSQL is a block oriented language. A block is defined as

            [<<label>>]
            [DECLARE
                -- declarations]
            BEGIN
                -- statements
            END;

        There  can  be  any  number  of  subblocks  in the statements
        section of a block. Subblocks can be used to  hide  variables
        from  outside a block of statements (see Scope and visability
        below). The variables declared in  the  declarations  section
        preceding  a  block  are  initialized to their default values
        every time the block is entered, not only once  per  function
        call.

        It is important not to misunderstand the meaning of BEGIN/END
        for grouping statements in PL/pgSQL and the database commands
        for  transaction  control.  Functions  or  trigger procedures
        cannot  start   or   commit   transactions   and   PostgreSQL
        transactions cannot have subtransactions.


    Comments

        There  are  two  types of comments in PL/pgSQL. A double dash
        '--' starts a comment that extends to the end of the line.  A
        '/*'  starts  a  block comment that extends to the next '*/'.
        Block comments cannot be nested, but double dash comments can
        be  enclosed  into a block comment and double dashes can hide
        '/*' and '*/'.


    Declarations

        All variables, rows and records  used  in  a  block  or  it's
        subblocks must be declared in the declarations section of the
        block except for the loop variable of a  FOR  loop  iterating
        over  a range of integer values.  The parameters given to the
        function  are   automatically   declared   with   the   usual
        identifiers $n.  The declarations have the following syntax:

            <name> [CONSTANT] <type> [NOT NULL]
                                     [DEFAULT | := <value>];

                Declares  a  variable  of  the specified type. If the
                variable is declared as CONSTANT, the value cannot be
                changed. If NOT NULL is specified, an assignment of a
                NULL value results in  a  runtime  error.  Since  the
                default  value  of  a variable is the SQL NULL value,
                all variables declared as NOT NULL must also  have  a
                default value.

                The default value is evaluated at the actual function
                call. So  assigning  'now'  to  an  abstime  variable
                causes  the  variable  to have the time of the actual
                function call, not when  the  function  was  compiled
                (during  it's  first  call  since the lifetime of the
                database connection).

            <name> <class>%ROWTYPE;

                Declares a row with the structure of the given class.
                Class  must  be an existing table- or viewname of the
                database. The fields of the row are accessed  in  the
                dot  notation.  Parameters  to  a  procedure could be
                tuple  types.  In   that   case   the   corresponding
                identifier  $n  will  be  a  rowtype.  Only  the user
                attributes of a tuple  are  accessible  in  the  row.
                There  must  be no whitespaces between the classname,
                the percent and the ROWTYPE keyword.

                The  fields  of  the  rowtype  inherit   the   tables
                fieldsizes  for  char()  etc.   data types (atttypmod
                from pg_attribute).

            <name> RECORD;

                Records are similar to rowtypes,  but  they  have  no
                predefined  structure They are used in selections and
                FOR loops to hold one actual database  tuple  from  a
                select operation. One and the same record can be used
                in different selections. Accessing  a  record  or  an
                attempt  to  assign  a  value  to a record field when
                there's no actual tuple in it results  in  a  runtime
                error.

                The  new  and old tuples in triggers are given to the
                trigger procedure  as  records.  This  is  necessary,
                because  under  PostgreSQL  one  and the same trigger
                procedure can handle  trigger  events  for  different
                tables.

            <name> ALIAS FOR $n;

                For  better  readability of the code it's possible to
                define an alias for a  positional  parameter  to  the
                function.

            RENAME <oldname> TO <newname>;

                Change  the  name  of  a variable, record or rowtype.
                This is useful if new or old should be referenced  by
                another name inside a trigger procedure.

    Datatypes

        The  type of a variable can be any of the existing data types
        of the database. <type> above is defined as:

                postgesql-basetype
            or  variable%TYPE
            or  rowtype.field%TYPE
            or  class.field%TYPE

        As for the rowtype declaration, there must be no  whitespaces
        between the classname, the percent and the TYPE keyword.

    Expressions

        All  expressions  used  in  PL/pgSQL statements are processed
        using the backends executor. Since even  a  constant  looking
        expression  can  have  a  totally  different  meaning  for  a
        particular data type (as 'now' for abstime), it is impossible
        for  the  PL/pgSQL  parser  to  identify real constant values
        other than the NULL keyword. The expressions are evaluated by
        internally executing a query

            SELECT <expr>

        over  the  SPI  manager.  In  the  expression,  occurences of
        variable identifiers are substituted by  parameters  and  the
        actual  values  from the variables are passed to the executor
        as query parameters. All the expressions used in  a  PL/pgSQL
        function are only prepared and saved once.

        If   record  fields  are  used  in  expressions  or  database
        statements, the data types of the fields  should  not  change
        between  calls  of  one and the same expression. Keep this in
        mind when writing trigger procedures that handle  events  for
        more than one table.

    Statements

        Anything not understood by the parser as specified below will
        be put into a query and sent down to the database  engine  to
        execute.   The  resulting  query  should  not return any data
        (insert, update, delete queries and all utility  statements).

        Assignment

            An  assignment  of a value to a variable or rowtype field
            is written as:

                <identifier> := <expr>;

            If the expressions result data  type  doesn't  match  the
            variables  data type, or the variables atttypmod value is
            known  (as  for  char(20)),  the  result  value  will  be
            implicitly  casted  by  the  PL/pgSQL  executor using the
            result  types  output-  and  the  variables  type  input-
            functions.   Note  that  this could potentially result in
            runtime errors generated by the types input functions.

            An assignment of a complete selection into  a  record  or
            rowtype can be done as:

                SELECT expressions INTO <target> FROM fromlist;

            Target  can  be  a record or rowtype variable, or a comma
            separated list of variables and record/row fields.

            If a rowtype or a variable list is used  as  target,  the
            selected  values  must exactly match the structure of the
            target(s) or a runtime error occurs.  The fromlist can be
            followed  by  any  valid qualification, grouping, sorting
            etc.

            There is a special condition [NOT] FOUND that can be used
            immediately  after a SELECT INTO to check if the data has
            been found.

                SELECT * INTO myrec FROM EMP WHERE empname = myname;
                IF NOT FOUND THEN
                    RAISE EXCEPTION 'employee % not found', myname;
                END IF;

            If the selection returns multiple rows, only the first is
            moved into the target fields. All others are discarded.


        Calling another function

            If  a function should be called, this is normally done by
            a SELECT query. But there are cases where  someone  isn't
            interested in the functions result.

                PERFORM querystring;

            executes  a 'SELECT querystring' over the SPI manager and
            discards the result.


        Returning from the function

                RETURN <expr>;

            The function terminates and the value of <expr>  will  be
            returned  to  the  upper executor.  The return value of a
            function cannot be undefined.  If control reaches the end
            of  the  toplevel block of the function without hitting a
            RETURN statement, a runtime error will occur.


        Aborting and messages

            As indicated above there is an RAISE statement  that  can
            throw messages into the PostgreSQL elog mechanism.

                RAISE level 'format' [, identifier [...]];

            Inside the format, % can be used as a placeholder for the
            following, comma separated identifiers.  The  identifiers
            must specify an existing variable or row/record field.


        Conditionals

                IF <expr> THEN
                    -- statements
                [ELSE
                    -- statements]
                END IF;

            The  expression  <expr> must return a value that at least
            can be casted into a boolean.


        Loops

            There are multiple types of loops.

                [<<label>>]
                LOOP
                    -- statements
                END LOOP;

            An unconditional loop that must be terminated  explicitly
            by  an  EXIT statement. The optional label can be used by
            EXIT statements of nested loops to specify which level of
            nesting should be terminated.

                [<<label>>]
                WHILE <expr> LOOP
                    -- statements
                END LOOP;

            A  conditional  loop  that  is  executed  as  long as the
            evaluation of <expr> returns true.

                [<<label>>]
                FOR <name> IN [REVERSE] <expr>..<expr> LOOP
                    -- statements
                END LOOP.

            A loop that iterates over a range of integer values.  The
            variable  <name> is automatically created as type integer
            and exists only inside  the  loop.  The  two  expressions
            giving  the  lower  and  upper  bound  of  the  range are
            evaluated only when entering the loop. The iteration step
            is 1.

                FOR <recname|rowname> IN <select_clause> LOOP
                    -- statements
                END LOOP;

            The record or row is assigned all the rows resulting from
            the select clause and the statements executed  for  each.
            If  the  loop  is  terminated with an EXIT statement, the
            last accessed row is still accessible in  the  record  or
            rowtype.

                EXIT [label] [WHEN <expr>];

            If  no  label given, the innermost loop is terminated and
            the statement following END LOOP  is  executed  next.  If
            label is given, it must be the label of the current or an
            upper level of nested loops or blocks.   Then  the  named
            loop  or  block  is terminated and control continues with
            the statement after the loops/blocks corresponding END.

    Trigger procedures

        PL/pgSQL can also be used to define trigger procedures.  They
        are  created  using  CREATE  FUNCTION  as  a function with no
        arguments and a return type of opaque.

        There are some PostgreSQL specific details in functions  used
        as trigger procedures.

        First  they  have  some  special  variables created above the
        toplevel statement block. These are:

            new (record)
                The new database tuple on INSERT/UPDATE operations at
                ROW level.

            old (record)
                The old database tuple on UPDATE/DELETE operations at
                ROW level.

            tg_name (type name)
                The triggers name from pg_trigger.

            tg_when (type text)
                A string of either 'BEFORE' or 'AFTER'  depending  on
                the triggers definition.

            tg_level (type text)
                A  string of either 'ROW' or 'STATEMENT' depending on
                the triggers definition.

            tg_op (type text)
                A string of 'INSERT', 'UPDATE'  or  'DELETE'  telling
                for which operation the trigger is actually fired.

            tg_relid (type oid)
                The  Oid  of  the  relation  for which the trigger is
                actually fired.

            tg_relname (type name)
                The relations name for which the trigger is  actually
                fired.

            tg_nargs (type integer)
                The   number   of  arguments  given  to  the  trigger
                procedure in the CREATE TRIGGER statement.

            tg_argv[] (types text)
                The arguments from the CREATE TRIGGER statement.  The
                index  counts  from 0 and can be given as expression.
                Invalid indices (< 0 or >= tg_nargs) result in a NULL
                value.

        Second,  they  must  return  either NULL, or a record/rowtype
        containing exactly the structure of the table the trigger was
        fired  for.  Triggers  fired  AFTER might allways return NULL
        with no effect. Triggers  fired  BEFORE  signal  the  trigger
        manager  to  skip  the  operation  for  this  actual row when
        returning  NULL.  Otherwise,  the   returned   record/rowtype
        replaces  the  inserted/updated tuple in the operation. It is
        possible to replace single values directly in new and  return
        that, or to build a complete new record/rowtype to return.

    Exceptions

        PostgreSQL  doesn't  have  a  very  smart  exception handling
        model. Whenever the  parser,  planner/optimizer  or  executor
        decide  that  a statement cannot be processed any longer, the
        whole transaction gets aborted and the the system jumps  back
        into  the mainloop using longjmp() to get the next query from
        the client application.

        It is possible to hook into the longjmp() mechanism to notice
        that this happens. But currently it's impossible to tell what
        really  caused  the  abort  (input/output  conversion  error,
        floating point error, parse error) And it's possible that the
        backend  is  in  an  inconsistent  state  at  this  point  so
        returning  to  the  upper  executor  or issuing more commands
        might corrupt the whole database.

        Thus,  the  only  thing  PL/pgSQL  currently  does  when   it
        encounters an abort during execution of a function or trigger
        procedure is to write  some  additional  DEBUG  log  messages
        telling  in which function and where (line number and type of
        statement) this happened.

        This might change in the future.

































