Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
11fd9157
Commit
11fd9157
authored
Mar 17, 2001
by
Peter Eisentraut
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Repair.
parent
406183fb
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
368 additions
and
310 deletions
+368
-310
doc/src/sgml/plsql.sgml
doc/src/sgml/plsql.sgml
+368
-310
No files found.
doc/src/sgml/plsql.sgml
View file @
11fd9157
<
!--
<
!--
$
Header
:
/
cvsroot
/
pgsql
/
doc
/
src
/
sgml
/
Attic
/
plsql
.
sgml
,
v
2.2
3
2001
/
03
/
17
01
:
53
:
22
thomas
Exp
$
$
Header
:
/
cvsroot
/
pgsql
/
doc
/
src
/
sgml
/
Attic
/
plsql
.
sgml
,
v
2.2
4
2001
/
03
/
17
18
:
08
:
14
petere
Exp
$
-->
-->
<
chapter
id
=
"plpgsql"
>
<
chapter
id
=
"plpgsql"
>
<
title
>
PL
/
pgSQL
-
<
acronym
>
SQL
<
acronym
>
Procedural
Language
</
title
>
<
title
>
PL
/
pgSQL
-
<
acronym
>
SQL
<
/
acronym
>
Procedural
Language
</
title
>
<
para
>
<
para
>
PL
/
pgSQL
is
a
loadable
procedural
language
for
the
PL
/
pgSQL
is
a
loadable
procedural
language
for
the
...
@@ -12,8 +12,8 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/plsql.sgml,v 2.23 2001/03/17 01:53:22
...
@@ -12,8 +12,8 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/plsql.sgml,v 2.23 2001/03/17 01:53:22
<
para
>
<
para
>
This
package
was
originally
written
by
Jan
Wieck
.
This
This
package
was
originally
written
by
Jan
Wieck
.
This
documentation
was
re
-
organized
and
in
part
written
documentation
was
in
part
written
by
Roberto
Mello
(
rmello
@
fslc
.
usu
.
edu
).
by
Roberto
Mello
(
<
email
>
rmello
@
fslc
.
usu
.
edu
</
email
>
).
</
para
>
</
para
>
<
sect1
id
=
"plpgsql-overview"
>
<
sect1
id
=
"plpgsql-overview"
>
...
@@ -80,20 +80,23 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/plsql.sgml,v 2.23 2001/03/17 01:53:22
...
@@ -80,20 +80,23 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/plsql.sgml,v 2.23 2001/03/17 01:53:22
This
means
that
you
have
to
be
careful
about
your
user
-
defined
This
means
that
you
have
to
be
careful
about
your
user
-
defined
functions
.
For
example
:
functions
.
For
example
:
<
programlisting
>
<
programlisting
>
CREATE
FUNCTION
populate
()
RETURNS
INTEGER
AS
'
CREATE
FUNCTION
populate
()
RETURNS
INTEGER
AS
'
DECLARE
DECLARE
-- Declarations
-- Declarations
BEGIN
BEGIN
PERFORM my_function();
PERFORM my_function();
END;
END;
'
language
'plpgsql'
;
'
LANGUAGE
'plpgsql'
;
</
programlisting
>
</
programlisting
>
If
you
CREATE
the
above
function
,
it
will
reference
the
ID
for
If
you
create
the
above
function
,
it
will
reference
the
OID
for
my_function
()
in
its
bytecode
.
Later
,
if
you
DROP
and
re
-
CREATE
<
function
>
my_function
()</
function
>
in
its
bytecode
.
Later
,
if
you
my_function
(),
populate
()
will
not
be
able
to
find
my_function
()
drop
and
re
-
create
<
function
>
my_function
()</
function
>,
then
anymore
.
You
'll have to re-CREATE populate().
<
function
>
populate
()</
function
>
will
not
be
able
to
find
<
function
>
my_function
()</
function
>
anymore
.
You
would
then
have
to
re
-
create
<
function
>
populate
()</
function
>.
</
para
>
</
para
>
<
para
>
<
para
>
Because
PL
/
pgSQL
saves
execution
plans
in
this
way
,
queries
that
appear
Because
PL
/
pgSQL
saves
execution
plans
in
this
way
,
queries
that
appear
directly
in
a
PL
/
pgSQL
function
must
refer
to
the
same
tables
and
fields
directly
in
a
PL
/
pgSQL
function
must
refer
to
the
same
tables
and
fields
...
@@ -116,23 +119,26 @@ END;
...
@@ -116,23 +119,26 @@ END;
<
itemizedlist
>
<
itemizedlist
>
<
listitem
>
<
listitem
>
<
para
>
<
para
>
<xref linkend="plpgsql-advantages-performance">Better performance</xref>
Better
performance
(
see
<
xref
linkend
=
"plpgsql-advantages-performance"
>)
</
para
>
</
para
>
</
listitem
>
</
listitem
>
<
listitem
>
<
listitem
>
<
para
>
<
para
>
<xref linkend="plpgsql-advantages-sqlsupport">SQL Support</xref>
SQL
support
(
see
<
xref
linkend
=
"plpgsql-advantages-sqlsupport"
>)
</
para
>
</
para
>
</
listitem
>
</
listitem
>
<
listitem
>
<
listitem
>
<
para
>
<
para
>
<xref linkend="plpgsql-advantages-portability">Portability</xref>
Portability
(
see
<
xref
linkend
=
"plpgsql-advantages-portability"
>)
</
para
>
</
para
>
</
listitem
>
</
listitem
>
</
itemizedlist
>
</
itemizedlist
>
<
sect3
id
=
"plpgsql-advantages-performance"
>
<
sect3
id
=
"plpgsql-advantages-performance"
>
<
title
>
Better
Performance
</
title
>
<
title
>
Better
Performance
</
title
>
<
para
>
<
para
>
<
acronym
>
SQL
</
acronym
>
is
the
language
PostgreSQL
(
and
<
acronym
>
SQL
</
acronym
>
is
the
language
PostgreSQL
(
and
most
other
Relational
Databases
)
use
as
query
most
other
Relational
Databases
)
use
as
query
...
@@ -140,6 +146,7 @@ END;
...
@@ -140,6 +146,7 @@ END;
<acronym>SQL</acronym> statement must be executed
<acronym>SQL</acronym> statement must be executed
individually by the database server.
individually by the database server.
</para>
</para>
<para>
<para>
That means that your client application must send each
That means that your client application must send each
query to the database server, wait for it to process it,
query to the database server, wait for it to process it,
...
@@ -149,6 +156,7 @@ END;
...
@@ -149,6 +156,7 @@ END;
overhead if your client is on a different machine than
overhead if your client is on a different machine than
the database server.
the database server.
</para>
</para>
<para>
<para>
With PL/pgSQL you can group a block of computation and a
With PL/pgSQL you can group a block of computation and a
series of queries <emphasis>inside</emphasis> the
series of queries <emphasis>inside</emphasis> the
...
@@ -159,8 +167,10 @@ END;
...
@@ -159,8 +167,10 @@ END;
considerable
performance
increase
by
using
PL
/
pgSQL
.
considerable
performance
increase
by
using
PL
/
pgSQL
.
</
para
>
</
para
>
</
sect3
>
</
sect3
>
<
sect3
id
=
"plpgsql-advantages-sqlsupport"
>
<
sect3
id
=
"plpgsql-advantages-sqlsupport"
>
<
title
>
SQL
Support
</
title
>
<
title
>
SQL
Support
</
title
>
<
para
>
<
para
>
PL
/
pgSQL
adds
the
power
of
a
procedural
language
to
the
PL
/
pgSQL
adds
the
power
of
a
procedural
language
to
the
flexibility
and
ease
of
<
acronym
>
SQL
</
acronym
>.
With
flexibility
and
ease
of
<
acronym
>
SQL
</
acronym
>.
With
...
@@ -168,8 +178,10 @@ END;
...
@@ -168,8 +178,10 @@ END;
and
functions
of
SQL
.
and
functions
of
SQL
.
</
para
>
</
para
>
</
sect3
>
</
sect3
>
<
sect3
id
=
"plpgsql-advantages-portability"
>
<
sect3
id
=
"plpgsql-advantages-portability"
>
<
title
>
Portability
</
title
>
<
title
>
Portability
</
title
>
<
para
>
<
para
>
Because
PL
/
pgSQL
functions
run
inside
PostgreSQL
,
these
Because
PL
/
pgSQL
functions
run
inside
PostgreSQL
,
these
functions
will
run
on
any
platform
where
PostgreSQL
functions
will
run
on
any
platform
where
PostgreSQL
...
@@ -186,12 +198,14 @@ END;
...
@@ -186,12 +198,14 @@ END;
if
you
have
developed
in
other
database
procedural
languages
,
if
you
have
developed
in
other
database
procedural
languages
,
such
as
Oracle
's PL/SQL. Two good ways of developing in
such
as
Oracle
's PL/SQL. Two good ways of developing in
PL/pgSQL are:
PL/pgSQL are:
<itemizedlist>
<itemizedlist>
<listitem>
<listitem>
<para>
<para>
Using a text editor and reloading the file with <command>psql</command>
Using a text editor and reloading the file with <command>psql</command>
</para>
</para>
</listitem>
</listitem>
<listitem>
<listitem>
<para>
<para>
Using PostgreSQL'
s
GUI
Tool
:
pgaccess
Using PostgreSQL'
s
GUI
Tool
:
pgaccess
...
@@ -199,6 +213,7 @@ END;
...
@@ -199,6 +213,7 @@ END;
</
listitem
>
</
listitem
>
</
itemizedlist
>
</
itemizedlist
>
</
para
>
</
para
>
<
para
>
<
para
>
One
good
way
to
develop
in
PL
/
pgSQL
is
to
simply
use
the
text
One
good
way
to
develop
in
PL
/
pgSQL
is
to
simply
use
the
text
editor
of
your
choice
to
create
your
functions
,
and
in
another
editor
of
your
choice
to
create
your
functions
,
and
in
another
...
@@ -208,26 +223,26 @@ END;
...
@@ -208,26 +223,26 @@ END;
always <command>DROP</command> your function before creating it. That way
always <command>DROP</command> your function before creating it. That way
when you reload the file, it'
ll
drop
your
functions
and
then
when you reload the file, it'
ll
drop
your
functions
and
then
re
-
create
them
.
For
example
:
re
-
create
them
.
For
example
:
</para>
<
programlisting
>
<para>
<programlisting>
drop
function
testfunc
(
integer
);
drop
function
testfunc
(
integer
);
create
function
testfunc
(
integer
)
return
integer
as
'
create
function
testfunc
(
integer
)
return
integer
as
'
....
....
end;
end;
'
language
'plpgsql'
;
'
language
'plpgsql'
;
</programlisting>
</
programlisting
>
</
para
>
<
para
>
When
you
load
the
file
for
the
first
time
,
When
you
load
the
file
for
the
first
time
,
<
productname
>
PostgreSQL
</>
will
raise
a
warning
saying
this
<
productname
>
PostgreSQL
</>
will
raise
a
warning
saying
this
function
doesn
't exist and go on to create it. To load an SQL
function
doesn
't exist and go on to create it. To load an SQL
file (filename.sql) into a database named "dbname", use the command:
file (filename.sql) into a database named "dbname", use the command:
</
para
>
<programlisting>
<
para
>
<
programlisting
>
psql -f filename.sql dbname
psql -f filename.sql dbname
</
programlisting
>
</programlisting>
</para>
<para>
Another good way to develop in PL/pgSQL is using
Another good way to develop in PL/pgSQL is using
<productname>PostgreSQL</>'
s
GUI
tool
:
pgaccess
.
It
does
some
<productname>PostgreSQL</>'
s
GUI
tool
:
pgaccess
.
It
does
some
nice
things
for
you
,
like
escaping
single
-
quotes
,
and
making
nice
things
for
you
,
like
escaping
single
-
quotes
,
and
making
...
@@ -247,31 +262,31 @@ psql -f filename.sql dbname
...
@@ -247,31 +262,31 @@ psql -f filename.sql dbname
<
title
>
Structure
of
PL
/
pgSQL
</
title
>
<
title
>
Structure
of
PL
/
pgSQL
</
title
>
<
para
>
<
para
>
PL/pgSQL is a <emphasis>block structured</emphasis>, case
PL
/
pgSQL
is
a
<
emphasis
>
block
structured
</
emphasis
>
language
.
All
insensitive language. All keywords and identifiers can be
keywords
and
identifiers
can
be
used
in
mixed
upper
and
used in mixed upper- and lower-case. A block is defined as:
lower
-
case
.
A
block
is
defined
as
:
</para>
<synopsis>
<
synopsis
>
<
optional
>&
lt
;&
lt
;
label
&
gt
;&
gt
;</
optional
>
<
optional
>&
lt
;&
lt
;
label
&
gt
;&
gt
;</
optional
>
<
optional
>
DECLARE
<
optional
>
DECLARE
<
replaceable
>
declarations
</
replaceable
></
optional
>
<
replaceable
>
declarations
</
replaceable
></
optional
>
BEGIN
BEGIN
<
replaceable
>
statements
</
replaceable
>
<
replaceable
>
statements
</
replaceable
>
END
;
END
;
</synopsis>
</
synopsis
>
</
para
>
<
para
>
<
para
>
There
can
be
any
number
of
sub
-
blocks
in
the
statement
section
There
can
be
any
number
of
sub
-
blocks
in
the
statement
section
of
a
block
.
Sub
-
blocks
can
be
used
to
hide
variables
from
outside
a
of
a
block
.
Sub
-
blocks
can
be
used
to
hide
variables
from
outside
a
block
of
statements
.
block
of
statements
.
</
para
>
</
para
>
<
para
>
<
para
>
The
variables
declared
in
the
declarations
section
preceding
a
The
variables
declared
in
the
declarations
section
preceding
a
block
are
initialized
to
their
default
values
every
time
the
block
are
initialized
to
their
default
values
every
time
the
block
is
entered
,
not
only
once
per
function
call
.
For
example
:
block
is
entered
,
not
only
once
per
function
call
.
For
example
:
</para>
<
programlisting
>
<programlisting>
CREATE
FUNCTION
somefunc
()
RETURNS
INTEGER
AS
'
CREATE
FUNCTION
somefunc
()
RETURNS
INTEGER
AS
'
DECLARE
DECLARE
quantity INTEGER := 30;
quantity INTEGER := 30;
...
@@ -289,8 +304,9 @@ BEGIN
...
@@ -289,8 +304,9 @@ BEGIN
RAISE NOTICE ''Quantity here is %'',quantity; -- Quantity here is 50
RAISE NOTICE ''Quantity here is %'',quantity; -- Quantity here is 50
END;
END;
' language '
plpgsql
';
'
LANGUAGE
'plpgsql'
;
</programlisting>
</
programlisting
>
</
para
>
<
para
>
<
para
>
It
is
important
not
to
confuse
the
use
of
BEGIN
/
END
for
It
is
important
not
to
confuse
the
use
of
BEGIN
/
END
for
...
@@ -326,30 +342,33 @@ END;
...
@@ -326,30 +342,33 @@ END;
The exception being the loop variable of a FOR loop iterating over a range
The exception being the loop variable of a FOR loop iterating over a range
of integer values.
of integer values.
</para>
</para>
<para>
<para>
PL/pgSQL variables can have any SQL datatype, such as
PL/pgSQL variables can have any SQL datatype, such as
<type>INTEGER</type>, <type>VARCHAR</type> and
<type>INTEGER</type>, <type>VARCHAR</type> and
<type>CHAR</type>. All variables have as default value the
<type>CHAR</type>. All variables have as default value the
<acronym>SQL</acronym> NULL value.
<acronym>SQL</acronym> NULL value.
</para>
</para>
<para>
<para>
Here are some examples of variable declarations:
Here are some examples of variable declarations:
</
para
>
<programlisting>
<
programlisting
>
user_id INTEGER;
user_id INTEGER;
quantity NUMBER(5);
quantity NUMBER(5);
url VARCHAR;
url VARCHAR;
</
programlisting
>
</programlisting>
</para>
<sect3 id="plpgsql-description-default-vars">
<sect3 id="plpgsql-description-default-vars">
<title>Constants and Variables With Default Values</title>
<title>Constants and Variables With Default Values</title>
<para>
<para>
The declarations have the following syntax:
The declarations have the following syntax:
</
para
>
<synopsis>
<
synopsis
>
<replaceable>name</replaceable> <optional> CONSTANT </optional> <replaceable>type</replaceable> <optional> NOT NULL </optional> <optional> { DEFAULT | := } <replaceable>value</replaceable> </optional>;
<replaceable>name</replaceable> <optional> CONSTANT </optional> <replaceable>type</replaceable> <optional> NOT NULL </optional> <optional> { DEFAULT | := } <replaceable>value</replaceable> </optional>;
</
synopsis
>
</synopsis>
</para>
<para>
<para>
The value of variables declared as CONSTANT cannot be changed. If NOT NULL
The value of variables declared as CONSTANT cannot be changed. If NOT NULL
is specified, an assignment of a NULL value results in a runtime
is specified, an assignment of a NULL value results in a runtime
...
@@ -357,6 +376,7 @@ url VARCHAR;
...
@@ -357,6 +376,7 @@ url VARCHAR;
<acronym>SQL</acronym> NULL value, all variables declared as NOT NULL
<acronym>SQL</acronym> NULL value, all variables declared as NOT NULL
must also have a default value specified.
must also have a default value specified.
</para>
</para>
<para>
<para>
The default value is evaluated every time the function is called. So
The default value is evaluated every time the function is called. So
assigning '
<
literal
>
now
</
literal
>
' to a variable of type
assigning '
<
literal
>
now
</
literal
>
' to a variable of type
...
@@ -364,14 +384,15 @@ url VARCHAR;
...
@@ -364,14 +384,15 @@ url VARCHAR;
time of the actual function call, not when the function was
time of the actual function call, not when the function was
precompiled into its bytecode.
precompiled into its bytecode.
</para>
</para>
<para>
<para>
Examples:
Examples:
</
para
>
<programlisting>
<
programlisting
>
quantity INTEGER := 32;
quantity INTEGER := 32;
url varchar := ''http://mysite.com'';
url varchar := ''http://mysite.com'';
user_id CONSTANT INTEGER := 10;
user_id CONSTANT INTEGER := 10;
</
programlisting
>
</programlisting>
</para>
</sect3>
</sect3>
<sect3 id="plpgsql-description-passed-vars">
<sect3 id="plpgsql-description-passed-vars">
...
@@ -381,15 +402,14 @@ user_id CONSTANT INTEGER := 10;
...
@@ -381,15 +402,14 @@ user_id CONSTANT INTEGER := 10;
Variables passed to functions are named with the identifiers
Variables passed to functions are named with the identifiers
<literal>$1</literal>, <literal>$2</literal>,
<literal>$1</literal>, <literal>$2</literal>,
etc. (maximum is 16). Some examples:
etc. (maximum is 16). Some examples:
</
para
>
<programlisting>
<
programlisting
>
CREATE FUNCTION sales_tax(REAL) RETURNS REAL AS '
CREATE FUNCTION sales_tax(REAL) RETURNS REAL AS '
DECLARE
DECLARE
subtotal
ALIAS
FOR
$
1
;
subtotal
ALIAS
FOR
$
1
;
BEGIN
BEGIN
return
subtotal
*
0.06
;
return
subtotal
*
0.06
;
END
;
END
;
'
language
'plpgsql'
;
'
LANGUAGE
'
plpgsql
';
CREATE FUNCTION instr(VARCHAR,INTEGER) RETURNS INTEGER AS '
CREATE FUNCTION instr(VARCHAR,INTEGER) RETURNS INTEGER AS '
...
@@ -399,8 +419,9 @@ DECLARE
...
@@ -399,8 +419,9 @@ DECLARE
BEGIN
BEGIN
--
Some
computations
here
--
Some
computations
here
END
;
END
;
'
language
'plpgsql'
;
' LANGUAGE '
plpgsql
';
</
programlisting
>
</programlisting>
</para>
</sect3>
</sect3>
<sect3 id="plpgsql-description-attributes">
<sect3 id="plpgsql-description-attributes">
...
@@ -427,10 +448,11 @@ END;
...
@@ -427,10 +448,11 @@ END;
named
<
type
>
user_id
</
type
>
in
your
named
<
type
>
user_id
</
type
>
in
your
<
type
>
users
</
type
>
table
.
To
declare
a
variable
with
<
type
>
users
</
type
>
table
.
To
declare
a
variable
with
the
same
datatype
as
users
you
do
:
the
same
datatype
as
users
you
do
:
</para>
<
programlisting
>
<programlisting>
user_id
users
.
user_id
%
TYPE
;
user_id
users
.
user_id
%
TYPE
;
</programlisting>
</
programlisting
>
</
para
>
<
para
>
<
para
>
By
using
<
type
>%
TYPE
</
type
>
you
don
't need to know
By
using
<
type
>%
TYPE
</
type
>
you
don
't need to know
the datatype of the structure you are referencing,
the datatype of the structure you are referencing,
...
@@ -449,22 +471,23 @@ user_id users.user_id%TYPE;
...
@@ -449,22 +471,23 @@ user_id users.user_id%TYPE;
</
term
>
</
term
>
<
listitem
>
<
listitem
>
<
para
>
<
para
>
Declares a row with the structure of the given table. <replaceable>table</replaceable> must be
Declares
a
row
with
the
structure
of
the
given
an existing table or view name of the database. The fields of the row
table
.
<
replaceable
>
table
</
replaceable
>
must
be
an
existing
are accessed in the dot notation. Parameters to a function can
table
or
view
name
of
the
database
.
The
fields
of
the
row
are
be composite types (complete table rows). In that case, the
accessed
in
the
dot
notation
.
Parameters
to
a
function
can
be
corresponding identifier $n will be a rowtype, but it
composite
types
(
complete
table
rows
).
In
that
case
,
the
must be aliased using the ALIAS command described above.
corresponding
identifier
$
n
will
be
a
rowtype
,
but
it
must
be
aliased
using
the
ALIAS
command
described
above
.
</
para
>
</
para
>
<
para
>
<
para
>
Only the user
Only
the
user
attributes
of
a
table
row
are
accessible
in
the
attributes of a table row are accessible in the row, no OID or other
row
,
no
OID
or
other
system
attributes
(
because
the
row
could
system attributes (because the row could be from a view).
be
from
a
view
).
The
fields
of
the
rowtype
inherit
the
The fields of the rowtype inherit the table'
s
field
sizes
table
's field sizes or precision for <type>char()</type>
or
precision
for
<
type
>
char
()</
type
>
etc
.
data
types
.
etc. data types.
</para>
</para>
<
programlisting
>
<programlisting>
DECLARE
DECLARE
users_rec users%ROWTYPE;
users_rec users%ROWTYPE;
user_id users%TYPE;
user_id users%TYPE;
...
@@ -493,8 +516,8 @@ create function cs_refresh_one_mv(integer) returns integer as '
...
@@ -493,8 +516,8 @@ create function cs_refresh_one_mv(integer) returns integer as '
return
1
;
return
1
;
end
;
end
;
'
language
'plpgsql'
;
'
LANGUAGE
'
plpgsql
';
</
programlisting
>
</programlisting>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>
</variablelist>
...
@@ -504,20 +527,22 @@ end;
...
@@ -504,20 +527,22 @@ end;
<title>
<title>
RENAME
RENAME
</title>
</title>
<para>
<para>
Using RENAME you can change the name of a variable, record
Using RENAME you can change the name of a variable, record
or row. This is useful if NEW or OLD should be referenced
or row. This is useful if NEW or OLD should be referenced
by another name inside a trigger procedure.
by another name inside a trigger procedure.
</para>
</para>
<para>
<para>
Syntax and examples:
Syntax and examples:
</
para
>
<programlisting>
<
programlisting
>
RENAME <replaceable>oldname</replaceable> TO <replaceable>newname</replaceable>;
RENAME <replaceable>oldname</replaceable> TO <replaceable>newname</replaceable>;
RENAME id TO user_id;
RENAME id TO user_id;
RENAME this_var TO that_var;
RENAME this_var TO that_var;
</
programlisting
>
</programlisting>
</para>
</sect3>
</sect3>
</sect2>
</sect2>
...
@@ -535,9 +560,9 @@ RENAME this_var TO that_var;
...
@@ -535,9 +560,9 @@ RENAME this_var TO that_var;
it
is
impossible
for
the
PL
/
pgSQL
parser
it
is
impossible
for
the
PL
/
pgSQL
parser
to
identify
real
constant
values
other
than
the
NULL
keyword
.
All
to
identify
real
constant
values
other
than
the
NULL
keyword
.
All
expressions
are
evaluated
internally
by
executing
a
query
expressions
are
evaluated
internally
by
executing
a
query
<synopsis>
<
synopsis
>
SELECT
<
replaceable
>
expression
</
replaceable
>
SELECT
<
replaceable
>
expression
</
replaceable
>
</synopsis>
</
synopsis
>
using
the
<
acronym
>
SPI
</
acronym
>
manager
.
In
the
expression
,
occurrences
of
variable
using
the
<
acronym
>
SPI
</
acronym
>
manager
.
In
the
expression
,
occurrences
of
variable
identifiers
are
substituted
by
parameters
and
the
actual
values
from
identifiers
are
substituted
by
parameters
and
the
actual
values
from
the
variables
are
passed
to
the
executor
in
the
parameter
array
.
All
the
variables
are
passed
to
the
executor
in
the
parameter
array
.
All
...
@@ -545,13 +570,14 @@ SELECT <replaceable>expression</replaceable>
...
@@ -545,13 +570,14 @@ SELECT <replaceable>expression</replaceable>
saved
once
.
The
only
exception
to
this
rule
is
an
EXECUTE
statement
saved
once
.
The
only
exception
to
this
rule
is
an
EXECUTE
statement
if
parsing
of
a
query
is
needed
each
time
it
is
encountered
.
if
parsing
of
a
query
is
needed
each
time
it
is
encountered
.
</
para
>
</
para
>
<
para
>
<
para
>
The
type
checking
done
by
the
<
productname
>
Postgres
</
productname
>
The
type
checking
done
by
the
<
productname
>
Postgres
</
productname
>
main
parser
has
some
side
main
parser
has
some
side
effects
to
the
interpretation
of
constant
values
.
In
detail
there
effects
to
the
interpretation
of
constant
values
.
In
detail
there
is
a
difference
between
what
these
two
functions
do
:
is
a
difference
between
what
these
two
functions
do
:
<programlisting>
<
programlisting
>
CREATE
FUNCTION
logfunc1
(
text
)
RETURNS
timestamp
AS
'
CREATE
FUNCTION
logfunc1
(
text
)
RETURNS
timestamp
AS
'
DECLARE
DECLARE
logtxt ALIAS FOR $1;
logtxt ALIAS FOR $1;
...
@@ -560,11 +586,11 @@ CREATE FUNCTION logfunc1 (text) RETURNS timestamp AS '
...
@@ -560,11 +586,11 @@ CREATE FUNCTION logfunc1 (text) RETURNS timestamp AS '
RETURN ''now'';
RETURN ''now'';
END;
END;
'
LANGUAGE
'plpgsql'
;
'
LANGUAGE
'plpgsql'
;
</programlisting>
</
programlisting
>
and
and
<programlisting>
<
programlisting
>
CREATE
FUNCTION
logfunc2
(
text
)
RETURNS
timestamp
AS
'
CREATE
FUNCTION
logfunc2
(
text
)
RETURNS
timestamp
AS
'
DECLARE
DECLARE
logtxt ALIAS FOR $1;
logtxt ALIAS FOR $1;
...
@@ -575,7 +601,7 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
...
@@ -575,7 +601,7 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
RETURN curtime;
RETURN curtime;
END;
END;
'
LANGUAGE
'plpgsql'
;
'
LANGUAGE
'plpgsql'
;
</programlisting>
</
programlisting
>
In
the
case
of
<
function
>
logfunc1
()</
function
>,
the
In
the
case
of
<
function
>
logfunc1
()</
function
>,
the
<
productname
>
Postgres
</
productname
>
main
parser
knows
when
<
productname
>
Postgres
</
productname
>
main
parser
knows
when
...
@@ -588,6 +614,7 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
...
@@ -588,6 +614,7 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
backend
.
Needless
to
say
that
this
isn
't what the
backend
.
Needless
to
say
that
this
isn
't what the
programmer wanted.
programmer wanted.
</para>
</para>
<para>
<para>
In the case of <function>logfunc2()</function>, the
In the case of <function>logfunc2()</function>, the
<productname>Postgres</productname> main parser does not know
<productname>Postgres</productname> main parser does not know
...
@@ -599,6 +626,7 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
...
@@ -599,6 +626,7 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
<function>text_out()</function> and <function>timestamp_in()</function>
<function>text_out()</function> and <function>timestamp_in()</function>
functions for the conversion.
functions for the conversion.
</para>
</para>
<para>
<para>
This type checking done by the <productname>Postgres</productname> main
This type checking done by the <productname>Postgres</productname> main
parser got implemented after PL/pgSQL was nearly done.
parser got implemented after PL/pgSQL was nearly done.
...
@@ -608,6 +636,7 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
...
@@ -608,6 +636,7 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
variable in the above manner is currently the only way in PL/pgSQL to get
variable in the above manner is currently the only way in PL/pgSQL to get
those values interpreted correctly.
those values interpreted correctly.
</para>
</para>
<para>
<para>
If record fields are used in expressions or statements, the data types of
If record fields are used in expressions or statements, the data types of
fields should not change between calls of one and the same expression.
fields should not change between calls of one and the same expression.
...
@@ -632,9 +661,9 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
...
@@ -632,9 +661,9 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
<para>
<para>
An assignment of a value to a variable or row/record field is
An assignment of a value to a variable or row/record field is
written as:
written as:
<
synopsis
>
<synopsis>
<replaceable>identifier</replaceable> := <replaceable>expression</replaceable>;
<replaceable>identifier</replaceable> := <replaceable>expression</replaceable>;
</
synopsis
>
</synopsis>
If the expressions result data type doesn'
t
match
the
variables
If the expressions result data type doesn'
t
match
the
variables
data
type
,
or
the
variable
has
a
size
/
precision
that
is
known
data
type
,
or
the
variable
has
a
size
/
precision
that
is
known
...
@@ -644,10 +673,10 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
...
@@ -644,10 +673,10 @@ CREATE FUNCTION logfunc2 (text) RETURNS timestamp AS '
result
in
runtime
errors
generated
by
the
types
input
functions
.
result
in
runtime
errors
generated
by
the
types
input
functions
.
</
para
>
</
para
>
<programlisting>
<
programlisting
>
user_id
:=
20
;
user_id
:=
20
;
tax
:=
subtotal
*
0.06
;
tax
:=
subtotal
*
0.06
;
</programlisting>
</
programlisting
>
</
sect3
>
</
sect3
>
<
sect3
id
=
"plpgsql-statements-calling-other-funcs"
>
<
sect3
id
=
"plpgsql-statements-calling-other-funcs"
>
...
@@ -659,26 +688,25 @@ tax := subtotal * 0.06;
...
@@ -659,26 +688,25 @@ tax := subtotal * 0.06;
is
to
execute
a
SELECT
query
or
doing
an
assignment
(
resulting
is
to
execute
a
SELECT
query
or
doing
an
assignment
(
resulting
in
a
PL
/
pgSQL
internal
SELECT
).
in
a
PL
/
pgSQL
internal
SELECT
).
</
para
>
</
para
>
<
para
>
<
para
>
But
there
are
cases
where
someone
is
not
interested
in
the
But
there
are
cases
where
someone
is
not
interested
in
the
function
's result. In these cases, use the PERFORM
function
's result. In these cases, use the PERFORM
statement.
statement.
</
para
>
<synopsis>
<
synopsis
>
PERFORM <replaceable>query</replaceable>
PERFORM <replaceable>query</replaceable>
</
synopsis
>
</synopsis>
<
para
>
This executes a <literal>SELECT <replaceable>query</replaceable></literal> over the
executes
a
<
literal
>
SELECT
<
replaceable
>
query
</
replaceable
></
literal
>
over
the
<acronym>SPI manager</acronym> and discards the result. Identifiers like local
<acronym>SPI manager</acronym> and discards the result. Identifiers like local
variables are still substituted into parameters.
variables are still substituted into parameters.
</para>
</para>
<
programlisting
>
<programlisting>
PERFORM create_mv(''cs_session_page_requests_mv'',''
PERFORM create_mv(''cs_session_page_requests_mv'',''
select session_id, page_id, count(*) as n_hits,
select session_id, page_id, count(*) as n_hits,
sum(dwell_time) as dwell_time, count(dwell_time) as dwell_count
sum(dwell_time) as dwell_time, count(dwell_time) as dwell_count
from cs_fact_table
from cs_fact_table
group by session_id, page_id '');
group by session_id, page_id '');
</
programlisting
>
</programlisting>
</sect3>
</sect3>
<sect3 id="plpgsql-statements-executing-dyn-queries">
<sect3 id="plpgsql-statements-executing-dyn-queries">
...
@@ -690,14 +718,16 @@ PERFORM create_mv(''cs_session_page_requests_mv'',''
...
@@ -690,14 +718,16 @@ PERFORM create_mv(''cs_session_page_requests_mv'',''
generate other functions. PL/pgSQL provides the EXECUTE
generate other functions. PL/pgSQL provides the EXECUTE
statement for these occasions.
statement for these occasions.
</para>
</para>
<para>
<para>
<
synopsis
>
<synopsis>
EXECUTE <replaceable class="command">query-string</replaceable>
EXECUTE <replaceable class="command">query-string</replaceable>
</
synopsis
>
</synopsis>
where
<
replaceable
>
query
-
string
</
replaceable
>
is
a
string
of
where <replaceable>query-string</replaceable> is a string of type
type
<
type
>
text
</
type
>
containing
the
<
replaceable
>
query
</
replaceable
>
to
be
<type>text</type> containing the <replaceable>query</replaceable>
executed
.
to be
executed.
</para>
</para>
<para>
<para>
When working with dynamic queries you will have to face
When working with dynamic queries you will have to face
escaping of single quotes in PL/pgSQL. Please refer to the
escaping of single quotes in PL/pgSQL. Please refer to the
...
@@ -707,32 +737,33 @@ EXECUTE <replaceable class="command">query-string</replaceable>
...
@@ -707,32 +737,33 @@ EXECUTE <replaceable class="command">query-string</replaceable>
<para>
<para>
Unlike all other queries in PL/pgSQL, a
Unlike all other queries in PL/pgSQL, a
<
replaceable
>
query
</
replaceable
>
run
by
an
EXECUTE
statement
<replaceable>query</replaceable> run by an EXECUTE statement is
is
not
prepared
and
saved
just
once
during
the
life
of
the
not prepared and saved just once during the life of the server.
server
.
Instead
,
the
<
replaceable
>
query
</
replaceable
>
is
Instead, the <replaceable>query</replaceable> is prepared each
prepared
each
time
the
statement
is
run
.
The
time the statement is run. The
<
replaceable
>
query
-
string
</
replaceable
>
can
be
dynamically
created
<replaceable>query-string</replaceable> can be dynamically
within
the
procedure
to
perform
actions
on
variable
tables
and
created within the procedure to perform actions on variable
fields
.
tables and
fields.
</para>
</para>
<para>
<para>
The results from SELECT queries are discarded by EXECUTE, and
The results from SELECT queries are discarded by EXECUTE, and
SELECT INTO is not currently supported within EXECUTE. So, the
SELECT INTO is not currently supported within EXECUTE. So, the
only
way
to
extract
a
result
from
a
dynamically
-
created
SELECT
only way to extract a result from a dynamically-created SELECT is
is
to
use
the
FOR
...
EXECUTE
form
described
later
.
to use the FOR ... EXECUTE form described later.
</para>
</para>
<para>
<para>
An example:
An example:
<
synopsis
>
<synopsis>
EXECUTE ''UPDATE tbl SET ''
EXECUTE ''UPDATE tbl SET ''
|| quote_ident(fieldname)
|| quote_ident(fieldname)
|| '' = ''
|| '' = ''
|| quote_literal(newvalue)
|| quote_literal(newvalue)
|| '' WHERE ...'';
|| '' WHERE ...'';
</
synopsis
>
</synopsis>
</para>
</para>
<para>
<para>
This example shows use of the functions
This example shows use of the functions
<function>quote_ident</function>(<type>TEXT</type>) and
<function>quote_ident</function>(<type>TEXT</type>) and
...
@@ -745,9 +776,10 @@ EXECUTE ''UPDATE tbl SET ''
...
@@ -745,9 +776,10 @@ EXECUTE ''UPDATE tbl SET ''
appropriate steps to return the input text enclosed in single
appropriate steps to return the input text enclosed in single
or double quotes and with any embedded special characters.
or double quotes and with any embedded special characters.
</para>
</para>
<para>
<para>
Here is a much larger example of a dynamic query and EXECUTE:
Here is a much larger example of a dynamic query and EXECUTE:
<
programlisting
>
<programlisting>
CREATE FUNCTION cs_update_referrer_type_proc() RETURNS INTEGER AS '
CREATE FUNCTION cs_update_referrer_type_proc() RETURNS INTEGER AS '
DECLARE
DECLARE
referrer_keys
RECORD
;
--
Declare
a
generic
record
to
be
used
in
a
FOR
referrer_keys
RECORD
;
--
Declare
a
generic
record
to
be
used
in
a
FOR
...
@@ -778,26 +810,29 @@ BEGIN
...
@@ -778,26 +810,29 @@ BEGIN
EXECUTE
a_output
;
EXECUTE
a_output
;
end
;
end
;
'
language
'plpgsql'
;
'
LANGUAGE
'
plpgsql
';
</
programlisting
>
</programlisting>
</para>
</para>
</sect3>
</sect3>
<sect3 id="plpgsql-statements-diagnostics">
<sect3 id="plpgsql-statements-diagnostics">
<title>Obtaining other results status</title>
<title>Obtaining other results status</title>
<para>
<para>
<
synopsis
>
<synopsis>
GET DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replaceable> <optional> , ... </optional>
GET DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replaceable> <optional> , ... </optional>
</
synopsis
>
</synopsis>
This command allows retrieval of system status indicators. Each
This command allows retrieval of system status indicators. Each
<replaceable>item</replaceable> is a keyword identifying a state
<replaceable>item</replaceable> is a keyword identifying a state
value
to
be
assigned
to
the
specified
variable
(
which
should
be
of
value to be assigned to the specified variable (which should be
the
right
datatype
to
receive
it
).
The
currently
available
status
of the right datatype to receive it). The currently available
items
are
<
varname
>
ROW_COUNT
</>,
the
number
of
rows
processed
by
status items are <varname>ROW_COUNT</>, the number of rows
the
last
<
acronym
>
SQL
</
acronym
>
query
sent
down
to
the
<
acronym
>
SQL
</
acronym
>
engine
;
and
processed by the last <acronym>SQL</acronym> query sent down to
<
varname
>
RESULT_OID
</>,
the
Oid
of
the
last
row
inserted
by
the
the <acronym>SQL</acronym> engine; and <varname>RESULT_OID</>,
most
recent
<
acronym
>
SQL
</
acronym
>
query
.
Note
that
<
varname
>
RESULT_OID
</>
is
only
the Oid of the last row inserted by the most recent
useful
after
an
INSERT
query
.
<acronym>SQL</acronym> query. Note that <varname>RESULT_OID</>
is only useful after an INSERT query.
</para>
</para>
</sect3>
</sect3>
...
@@ -805,15 +840,17 @@ GET DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replace
...
@@ -805,15 +840,17 @@ GET DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replace
<title>Returning from a function</title>
<title>Returning from a function</title>
<para>
<para>
<
synopsis
>
<synopsis>
RETURN <replaceable>expression</replaceable>
RETURN <replaceable>expression</replaceable>
</
synopsis
>
</synopsis>
The
function
terminates
and
the
value
of
<
replaceable
>
expression
</
replaceable
>
The function terminates and the value of
will
be
returned
to
the
upper
executor
.
The
return
value
of
a
function
<replaceable>expression</replaceable> will be returned to the
cannot
be
undefined
.
If
control
reaches
the
end
of
the
top
-
level
block
upper executor. The return value of a function cannot be
of
the
function
without
hitting
a
RETURN
statement
,
a
runtime
error
undefined. If control reaches the end of the top-level block of
the function without hitting a RETURN statement, a runtime error
will occur.
will occur.
</para>
</para>
<para>
<para>
The expressions result will be automatically casted into the
The expressions result will be automatically casted into the
function'
s
return
type
as
described
for
assignments
.
function'
s
return
type
as
described
for
assignments
.
...
@@ -833,7 +870,7 @@ RETURN <replaceable>expression</replaceable>
...
@@ -833,7 +870,7 @@ RETURN <replaceable>expression</replaceable>
flexible and powerful way.
flexible and powerful way.
</para>
</para>
<
sect3
id
=
"plpgsql-description-con
trol-structures-con
ditionals"
>
<sect3 id="plpgsql-description-conditionals">
<title>Conditional Control: IF statements</title>
<title>Conditional Control: IF statements</title>
<para>
<para>
...
@@ -850,17 +887,18 @@ RETURN <replaceable>expression</replaceable>
...
@@ -850,17 +887,18 @@ RETURN <replaceable>expression</replaceable>
<term>
<term>
IF-THEN
IF-THEN
</term>
</term>
<listitem>
<listitem>
<para>
<para>
IF-THEN statements is the simplest form of an IF. The
IF-THEN statements is the simplest form of an IF. The
statements between THEN and END IF will be executed if
statements between THEN and END IF will be executed if
the condition is true. Otherwise, the statements
the condition is true. Otherwise, the statements
following END IF will be executed.
following END IF will be executed.
<
programlisting
>
<programlisting>
IF v_user_id <> 0 THEN
IF v_user_id <> 0 THEN
UPDATE users SET email = v_email WHERE user_id = v_user_id;
UPDATE users SET email = v_email WHERE user_id = v_user_id;
END IF;
END IF;
</
programlisting
>
</programlisting>
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -869,12 +907,13 @@ END IF;
...
@@ -869,12 +907,13 @@ END IF;
<term>
<term>
IF-THEN-ELSE
IF-THEN-ELSE
</term>
</term>
<listitem>
<listitem>
<para>
<para>
IF-THEN-ELSE statements adds to IF-THEN by letting you
IF-THEN-ELSE statements adds to IF-THEN by letting you
specify the statements that should be executed if the
specify the statements that should be executed if the
condition evaluates to FALSE.
condition evaluates to FALSE.
<
programlisting
>
<programlisting>
IF parentid IS NULL or parentid = ''''
IF parentid IS NULL or parentid = ''''
THEN
THEN
return fullname;
return fullname;
...
@@ -889,12 +928,13 @@ IF v_count > 0 THEN
...
@@ -889,12 +928,13 @@ IF v_count > 0 THEN
ELSE
ELSE
return ''f'';
return ''f'';
END IF;
END IF;
</
programlisting
>
</programlisting>
</para>
</para>
<para>
<para>
IF statements can be nested and in the following
IF statements can be nested and in the following
example:
example:
<
programlisting
>
<programlisting>
IF demo_row.sex = ''m'' THEN
IF demo_row.sex = ''m'' THEN
pretty_sex := ''man'';
pretty_sex := ''man'';
ELSE
ELSE
...
@@ -902,7 +942,7 @@ ELSE
...
@@ -902,7 +942,7 @@ ELSE
pretty_sex := ''woman'';
pretty_sex := ''woman'';
END IF;
END IF;
END IF;
END IF;
</
programlisting
>
</programlisting>
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -911,6 +951,7 @@ END IF;
...
@@ -911,6 +951,7 @@ END IF;
<term>
<term>
IF-THEN-ELSE IF
IF-THEN-ELSE IF
</term>
</term>
<listitem>
<listitem>
<para>
<para>
When you use the "ELSE IF" statement, you are actually
When you use the "ELSE IF" statement, you are actually
...
@@ -918,16 +959,17 @@ END IF;
...
@@ -918,16 +959,17 @@ END IF;
statement. Thus you need one END IF statement for each
statement. Thus you need one END IF statement for each
nested IF and one for the parent IF-ELSE.
nested IF and one for the parent IF-ELSE.
</para>
</para>
<para>
<para>
For example:
For example:
<
programlisting
>
<programlisting>
IF demo_row.sex = ''m'' THEN
IF demo_row.sex = ''m'' THEN
pretty_sex := ''man'';
pretty_sex := ''man'';
ELSE IF demo_row.sex = ''f'' THEN
ELSE IF demo_row.sex = ''f'' THEN
pretty_sex := ''woman'';
pretty_sex := ''woman'';
END IF;
END IF;
END IF;
END IF;
</
programlisting
>
</programlisting>
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -942,19 +984,21 @@ END IF;
...
@@ -942,19 +984,21 @@ END IF;
control the flow of execution of your PL/pgSQL program
control the flow of execution of your PL/pgSQL program
iteratively.
iteratively.
</para>
</para>
<variablelist>
<variablelist>
<varlistentry>
<varlistentry>
<term>
<term>
LOOP
LOOP
</term>
</term>
<listitem>
<listitem>
<para>
<para>
<
synopsis
>
<synopsis>
<optional><<label>></optional>
<optional><<label>></optional>
LOOP
LOOP
<replaceable>statements</replaceable>
<replaceable>statements</replaceable>
END LOOP;
END LOOP;
</
synopsis
>
</synopsis>
An unconditional loop that must be terminated explicitly
An unconditional loop that must be terminated explicitly
by an EXIT statement. The optional label can be used by
by an EXIT statement. The optional label can be used by
EXIT statements of nested loops to specify which level of
EXIT statements of nested loops to specify which level of
...
@@ -967,11 +1011,12 @@ END LOOP;
...
@@ -967,11 +1011,12 @@ END LOOP;
<term>
<term>
EXIT
EXIT
</term>
</term>
<listitem>
<listitem>
<para>
<para>
<
synopsis
>
<synopsis>
EXIT <optional> <replaceable>label</replaceable> </optional> <optional> WHEN <replaceable>expression</replaceable> </optional>;
EXIT <optional> <replaceable>label</replaceable> </optional> <optional> WHEN <replaceable>expression</replaceable> </optional>;
</
synopsis
>
</synopsis>
If no <replaceable>label</replaceable> is given,
If no <replaceable>label</replaceable> is given,
the innermost loop is terminated and the
the innermost loop is terminated and the
statement following END LOOP is executed next.
statement following END LOOP is executed next.
...
@@ -981,9 +1026,10 @@ EXIT <optional> <replaceable>label</replaceable> </optional> <optional> WHEN <re
...
@@ -981,9 +1026,10 @@ EXIT <optional> <replaceable>label</replaceable> </optional> <optional> WHEN <re
continues with the statement after the loops/blocks corresponding
continues with the statement after the loops/blocks corresponding
END.
END.
</para>
</para>
<para>
<para>
Examples:
Examples:
<
programlisting
>
<programlisting>
LOOP
LOOP
-- some computations
-- some computations
IF count > 0 THEN
IF count > 0 THEN
...
@@ -1002,7 +1048,7 @@ BEGIN
...
@@ -1002,7 +1048,7 @@ BEGIN
EXIT; -- illegal. Can'
t
use
EXIT
outside
of
a
LOOP
EXIT; -- illegal. Can'
t
use
EXIT
outside
of
a
LOOP
END
IF
;
END
IF
;
END
;
END
;
</programlisting>
</
programlisting
>
</
para
>
</
para
>
</
listitem
>
</
listitem
>
</
varlistentry
>
</
varlistentry
>
...
@@ -1011,23 +1057,20 @@ END;
...
@@ -1011,23 +1057,20 @@ END;
<
term
>
<
term
>
WHILE
WHILE
</
term
>
</
term
>
<
listitem
>
<
listitem
>
<
para
>
<
para
>
With
the
WHILE
statement
,
you
can
loop
through
a
With
the
WHILE
statement
,
you
can
loop
through
a
sequence
of
statements
as
long
as
the
evaluation
of
sequence
of
statements
as
long
as
the
evaluation
of
the
condition
expression
is
true
.
the
condition
expression
is
true
.
</para>
<
synopsis
>
<para>
<synopsis>
<
optional
>&
lt
;&
lt
;
label
&
gt
;&
gt
;</
optional
>
<
optional
>&
lt
;&
lt
;
label
&
gt
;&
gt
;</
optional
>
WHILE
<
replaceable
>
expression
</
replaceable
>
LOOP
WHILE
<
replaceable
>
expression
</
replaceable
>
LOOP
<
replaceable
>
statements
</
replaceable
>
<
replaceable
>
statements
</
replaceable
>
END
LOOP
;
END
LOOP
;
</synopsis>
</
synopsis
>
<para>
For
example
:
For
example
:
</para>
<
programlisting
>
<programlisting>
WHILE
amount_owed
>
0
AND
gift_certificate_balance
>
0
LOOP
WHILE
amount_owed
>
0
AND
gift_certificate_balance
>
0
LOOP
--
some
computations
here
--
some
computations
here
END
LOOP
;
END
LOOP
;
...
@@ -1035,7 +1078,7 @@ END LOOP;
...
@@ -1035,7 +1078,7 @@ END LOOP;
WHILE
NOT
boolean_expression
LOOP
WHILE
NOT
boolean_expression
LOOP
--
some
computations
here
--
some
computations
here
END
LOOP
;
END
LOOP
;
</programlisting>
</
programlisting
>
</
para
>
</
para
>
</
listitem
>
</
listitem
>
</
varlistentry
>
</
varlistentry
>
...
@@ -1044,24 +1087,27 @@ END LOOP;
...
@@ -1044,24 +1087,27 @@ END LOOP;
<
term
>
<
term
>
FOR
FOR
</
term
>
</
term
>
<
listitem
>
<
listitem
>
<
para
>
<
para
>
<synopsis>
<
synopsis
>
<
optional
>&
lt
;&
lt
;
label
&
gt
;&
gt
;</
optional
>
<
optional
>&
lt
;&
lt
;
label
&
gt
;&
gt
;</
optional
>
FOR
<
replaceable
>
name
</
replaceable
>
IN
<
optional
>
REVERSE
</
optional
>
<
replaceable
>
expression
</
replaceable
>
..
<
replaceable
>
expression
</
replaceable
>
LOOP
FOR
<
replaceable
>
name
</
replaceable
>
IN
<
optional
>
REVERSE
</
optional
>
<
replaceable
>
expression
</
replaceable
>
..
<
replaceable
>
expression
</
replaceable
>
LOOP
<
replaceable
>
statements
</
replaceable
>
<
replaceable
>
statements
</
replaceable
>
END
LOOP
;
END
LOOP
;
</synopsis>
</
synopsis
>
A
loop
that
iterates
over
a
range
of
integer
values
.
The
variable
A
loop
that
iterates
over
a
range
of
integer
values
.
The
variable
<
replaceable
>
name
</
replaceable
>
is
automatically
created
as
type
<
replaceable
>
name
</
replaceable
>
is
automatically
created
as
type
integer
and
exists
only
inside
the
loop
.
The
two
expressions
giving
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
lower
and
upper
bound
of
the
range
are
evaluated
only
when
entering
the
loop
.
The
iteration
step
is
always
1.
the
loop
.
The
iteration
step
is
always
1.
</
para
>
</
para
>
<
para
>
<
para
>
Some examples of FOR loops (see <xref linkend="plpgsql-description-records"></xref> for
Some
examples
of
FOR
loops
(
see
<
xref
iterating over records in FOR loops):
linkend
=
"plpgsql-description-records"
>
for
iterating
over
<programlisting>
records
in
FOR
loops
):
<
programlisting
>
FOR
i
IN
1..10
LOOP
FOR
i
IN
1..10
LOOP
--
some
expressions
here
--
some
expressions
here
...
@@ -1071,7 +1117,7 @@ END LOOP;
...
@@ -1071,7 +1117,7 @@ END LOOP;
FOR
i
IN
REVERSE
1..10
LOOP
FOR
i
IN
REVERSE
1..10
LOOP
--
some
expressions
here
--
some
expressions
here
END
LOOP
;
END
LOOP
;
</programlisting>
</
programlisting
>
</
para
>
</
para
>
</
listitem
>
</
listitem
>
</
varlistentry
>
</
varlistentry
>
...
@@ -1083,6 +1129,7 @@ END LOOP;
...
@@ -1083,6 +1129,7 @@ END LOOP;
<
sect2
id
=
"plpgsql-description-records"
>
<
sect2
id
=
"plpgsql-description-records"
>
<
title
>
Working
with
RECORDs
</
title
>
<
title
>
Working
with
RECORDs
</
title
>
<
para
>
<
para
>
Records
are
similar
to
rowtypes
,
but
they
have
no
predefined
structure
.
Records
are
similar
to
rowtypes
,
but
they
have
no
predefined
structure
.
They
are
used
in
selections
and
FOR
loops
to
hold
one
actual
They
are
used
in
selections
and
FOR
loops
to
hold
one
actual
...
@@ -1091,46 +1138,51 @@ END LOOP;
...
@@ -1091,46 +1138,51 @@ END LOOP;
<
sect3
id
=
"plpgsql-description-records-declaration"
>
<
sect3
id
=
"plpgsql-description-records-declaration"
>
<
title
>
Declaration
</
title
>
<
title
>
Declaration
</
title
>
<
para
>
<
para
>
One
variables
of
type
RECORD
can
be
used
for
different
One
variables
of
type
RECORD
can
be
used
for
different
selections
.
Accessing
a
record
or
an
attempt
to
assign
selections
.
Accessing
a
record
or
an
attempt
to
assign
a
value
to
a
record
field
when
there
is
no
actual
row
in
it
results
a
value
to
a
record
field
when
there
is
no
actual
row
in
it
results
in
a
runtime
error
.
They
can
be
declared
like
this
:
in
a
runtime
error
.
They
can
be
declared
like
this
:
</
para
>
</
para
>
<
para
>
<
para
>
<synopsis>
<
synopsis
>
<
replaceable
>
name
</
replaceable
>
RECORD
;
<
replaceable
>
name
</
replaceable
>
RECORD
;
</synopsis>
</
synopsis
>
</
para
>
</
para
>
</
sect3
>
</
sect3
>
<
sect3
id
=
"plpgsql-description-records-assignment"
>
<
sect3
id
=
"plpgsql-description-records-assignment"
>
<
title
>
Assignments
</
title
>
<
title
>
Assignments
</
title
>
<
para
>
<
para
>
An
assignment
of
a
complete
selection
into
a
record
or
row
can
An
assignment
of
a
complete
selection
into
a
record
or
row
can
be
done
by
:
be
done
by
:
<synopsis>
<
synopsis
>
SELECT
INTO
<
replaceable
>
target
</
replaceable
>
<
replaceable
>
expressions
</
replaceable
>
FROM
...;
SELECT
INTO
<
replaceable
>
target
</
replaceable
>
<
replaceable
>
expressions
</
replaceable
>
FROM
...;
</synopsis>
</
synopsis
>
<replaceable>target</replaceable> can be a record, a row variable or a
<
replaceable
>
target
</
replaceable
>
can
be
a
record
,
a
row
variable
comma separated list of variables and record-/row-fields. Note that
or
a
comma
separated
list
of
variables
and
this is quite different from Postgres'
normal
interpretation
of
record
-/
row
-
fields
.
Note
that
this
is
quite
different
from
SELECT
INTO
,
which
is
that
the
INTO
target
is
a
newly
created
table
.
Postgres
' normal interpretation of SELECT INTO, which is that the
(
If
you
want
to
create
a
table
from
a
SELECT
result
inside
a
PL
/
pgSQL
INTO target is a newly created table. (If you want to create a
function
,
use
the
equivalent
syntax
<
command
>
CREATE
TABLE
AS
SELECT
</
command
>.)
table from a SELECT result inside a PL/pgSQL function, use the
equivalent syntax <command>CREATE TABLE AS SELECT</command>.)
</para>
</para>
<para>
<para>
If a row or a variable list is used as target, the selected values
If a row or a variable list is used as target, the selected values
must exactly match the structure of the target(s) or a runtime error
must exactly match the structure of the target(s) or a runtime error
occurs. The FROM keyword can be followed by any valid qualification,
occurs. The FROM keyword can be followed by any valid qualification,
grouping, sorting etc. that can be given for a SELECT statement.
grouping, sorting etc. that can be given for a SELECT statement.
</para>
</para>
<para>
<para>
Once a record or row has been assigned to a RECORD variable,
Once a record or row has been assigned to a RECORD variable,
you can use the "." (dot) notation to access fields in that
you can use the "." (dot) notation to access fields in that
record:
record:
</
para
>
<programlisting>
<
para
>
<
programlisting
>
DECLARE
DECLARE
users_rec RECORD;
users_rec RECORD;
full_name varchar;
full_name varchar;
...
@@ -1138,26 +1190,29 @@ BEGIN
...
@@ -1138,26 +1190,29 @@ BEGIN
SELECT INTO users_rec * FROM users WHERE user_id=3;
SELECT INTO users_rec * FROM users WHERE user_id=3;
full_name := users_rec.first_name || '' '' || users_rec.last_name;
full_name := users_rec.first_name || '' '' || users_rec.last_name;
</
programlisting
>
</programlisting>
</para>
</para>
<para>
<para>
There
is
a
special
variable
named
FOUND
of
type
<
type
>
boolean
</
type
>
that
can
be
used
There is a special variable named FOUND of type
immediately
after
a
SELECT
INTO
to
check
if
an
assignment
had
success
.
<type>boolean</type> that can be used immediately after a SELECT
INTO to check if an assignment had success.
<
programlisting
>
<programlisting>
SELECT INTO myrec * FROM EMP WHERE empname = myname;
SELECT INTO myrec * FROM EMP WHERE empname = myname;
IF NOT FOUND THEN
IF NOT FOUND THEN
RAISE EXCEPTION ''employee % not found'', myname;
RAISE EXCEPTION ''employee % not found'', myname;
END IF;
END IF;
</
programlisting
>
</programlisting>
You can also use the IS NULL (or ISNULL) conditionals to
You can also use the IS NULL (or ISNULL) conditionals to
test for NULLity of a RECORD/ROW. If the selection returns
test for NULLity of a RECORD/ROW. If the selection returns
multiple rows, only the first is moved into the target
multiple rows, only the first is moved into the target
fields. All others are silently discarded.
fields. All others are silently discarded.
</para>
</para>
<para>
<para>
<
programlisting
>
<programlisting>
DECLARE
DECLARE
users_rec RECORD;
users_rec RECORD;
full_name varchar;
full_name varchar;
...
@@ -1170,9 +1225,10 @@ BEGIN
...
@@ -1170,9 +1225,10 @@ BEGIN
return ''http://'';
return ''http://'';
END IF;
END IF;
END;
END;
</
programlisting
>
</programlisting>
</para>
</para>
</sect3>
</sect3>
<sect3 id="plpgsql-description-records-iterating">
<sect3 id="plpgsql-description-records-iterating">
<title>Iterating Through Records</title>
<title>Iterating Through Records</title>
...
@@ -1180,20 +1236,19 @@ END;
...
@@ -1180,20 +1236,19 @@ END;
Using a special type of FOR loop, you can iterate through
Using a special type of FOR loop, you can iterate through
the results of a query and manipulate that data
the results of a query and manipulate that data
accordingly. The syntax is as follow:
accordingly. The syntax is as follow:
</
para
>
<synopsis>
<
para
>
<
synopsis
>
<optional><<label>></optional>
<optional><<label>></optional>
FOR <replaceable>record | row</replaceable> IN <replaceable>select_clause</replaceable> LOOP
FOR <replaceable>record | row</replaceable> IN <replaceable>select_clause</replaceable> LOOP
<replaceable>statements</replaceable>
<replaceable>statements</replaceable>
END LOOP;
END LOOP;
</
synopsis
>
</synopsis>
The record or row is assigned all the rows
The record or row is assigned all the rows
resulting from the select clause and the loop body executed
resulting from the select clause and the loop body executed
for each. Here is an example:
for each. Here is an example:
</para>
</para>
<para>
<para>
<
programlisting
>
<programlisting>
create function cs_refresh_mviews () returns integer as '
create function cs_refresh_mviews () returns integer as '
DECLARE
DECLARE
mviews
RECORD
;
mviews
RECORD
;
...
@@ -1218,22 +1273,21 @@ BEGIN
...
@@ -1218,22 +1273,21 @@ BEGIN
return
1
;
return
1
;
end
;
end
;
' language '
plpgsql
';
' language '
plpgsql
';
</
programlisting
>
</programlisting>
If
the
loop
is
terminated
with
an
EXIT
statement
,
If the loop is terminated with an EXIT statement, the last
the
last
assigned
row
is
still
accessible
after
the
loop
.
assigned row is still accessible after the loop.
</para>
</para>
<para>
<para>
The FOR-IN EXECUTE statement is another way to iterate over
The FOR-IN EXECUTE statement is another way to iterate over
records:
records:
</
para
>
<synopsis>
<
para
>
<
synopsis
>
<optional><<label>></optional>
<optional><<label>></optional>
FOR <replaceable>record | row</replaceable> IN EXECUTE <replaceable>text_expression</replaceable> LOOP
FOR <replaceable>record | row</replaceable> IN EXECUTE <replaceable>text_expression</replaceable> LOOP
<replaceable>statements</replaceable>
<replaceable>statements</replaceable>
END LOOP;
END LOOP;
</
synopsis
>
</synopsis>
This is like the previous form, except that the source SELECT
This is like the previous form, except that the source SELECT
statement is specified as a string expression, which is evaluated
statement is specified as a string expression, which is evaluated
and re-planned on each entry to the FOR loop. This allows the
and re-planned on each entry to the FOR loop. This allows the
...
@@ -1251,27 +1305,30 @@ END LOOP;
...
@@ -1251,27 +1305,30 @@ END LOOP;
Use the RAISE statement to throw messages into the
Use the RAISE statement to throw messages into the
<productname>Postgres</productname> elog mechanism.
<productname>Postgres</productname> elog mechanism.
<
synopsis
>
<synopsis>
RAISE <replaceable class="parameter">level</replaceable> '
<
replaceable
class
=
"parameter"
>
format
</
replaceable
>
' <optional>, <replaceable class="parameter">identifier</replaceable> <optional>...</optional></optional>;
RAISE <replaceable class="parameter">level</replaceable> '
<
replaceable
class
=
"parameter"
>
format
</
replaceable
>
' <optional>, <replaceable class="parameter">identifier</replaceable> <optional>...</optional></optional>;
</
synopsis
>
</synopsis>
Inside the format, <literal>%</literal> is used as a placeholder for the
Inside the format, <literal>%</literal> is used as a placeholder for the
subsequent comma-separated identifiers. Possible levels are
subsequent comma-separated identifiers. Possible levels are
DEBUG (silently suppressed in production running databases), NOTICE
DEBUG (silently suppressed in production running databases), NOTICE
(written into the database log and forwarded to the client application)
(written into the database log and forwarded to the client application)
and EXCEPTION (written into the database log and aborting the transaction).
and EXCEPTION (written into the database log and aborting the transaction).
</para>
</para>
<para>
<para>
<
programlisting
>
<programlisting>
RAISE NOTICE ''Id number '' || key || '' not found!'';
RAISE NOTICE ''Id number '' || key || '' not found!'';
RAISE NOTICE ''Calling cs_create_job(%)'',v_job_id;
RAISE NOTICE ''Calling cs_create_job(%)'',v_job_id;
</
programlisting
>
</programlisting>
In this last example, v_job_id will replace the % in the
In this last example, v_job_id will replace the % in the
string.
string.
</para>
</para>
<para>
<para>
<
programlisting
>
<programlisting>
RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
</
programlisting
>
</programlisting>
This will abort the transaction and write to the database log.
This will abort the transaction and write to the database log.
</para>
</para>
</sect2>
</sect2>
...
@@ -1288,6 +1345,7 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
...
@@ -1288,6 +1345,7 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
the whole transaction gets aborted and the system jumps back
the whole transaction gets aborted and the system jumps back
into the main loop to get the next query from the client application.
into the main loop to get the next query from the client application.
</para>
</para>
<para>
<para>
It is possible to hook into the error mechanism to notice that this
It is possible to hook into the error mechanism to notice that this
happens. But currently it is impossible to tell what really
happens. But currently it is impossible to tell what really
...
@@ -1299,6 +1357,7 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
...
@@ -1299,6 +1357,7 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
is aborted, is already sent to the client application, so resuming
is aborted, is already sent to the client application, so resuming
operation does not make any sense.
operation does not make any sense.
</para>
</para>
<para>
<para>
Thus, the only thing PL/pgSQL currently does when it encounters
Thus, the only thing PL/pgSQL currently does when it encounters
an abort during execution of a function or trigger
an abort during execution of a function or trigger
...
@@ -1315,21 +1374,20 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
...
@@ -1315,21 +1374,20 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
<sect1 id="plpgsql-trigger">
<sect1 id="plpgsql-trigger">
<title>Trigger Procedures</title>
<title>Trigger Procedures</title>
<
sect2
id
=
"plpgsql-trigger-description"
>
<
title
>
Description
</
title
>
<para>
<para>
PL/pgSQL can be used to define trigger procedures. They are created
PL/pgSQL can be used to define trigger procedures. They are created
with the usual <command>CREATE FUNCTION</command> command as a function with no
with the usual <command>CREATE FUNCTION</command> command as a function with no
arguments and a return type of <type>OPAQUE</type>.
arguments and a return type of <type>OPAQUE</type>.
</para>
</para>
<para>
<para>
There are some <productname>Postgres</productname> specific details
There are some <productname>Postgres</productname> specific details
in functions used as trigger procedures.
in functions used as trigger procedures.
</para>
</para>
<para>
<para>
First they have some special variables created automatically in the
First they have some special variables created automatically in the
top-level blocks declaration section. They are
top-level blocks declaration section. They are
</
para
>
<variablelist>
<variablelist>
<varlistentry>
<varlistentry>
...
@@ -1438,6 +1496,7 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
...
@@ -1438,6 +1496,7 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
</listitem>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>
</variablelist>
</para>
<para>
<para>
Second they must return either NULL or a record/row containing
Second they must return either NULL or a record/row containing
...
@@ -1450,7 +1509,6 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
...
@@ -1450,7 +1509,6 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
in NEW and return that or to build a complete new record/row to
in NEW and return that or to build a complete new record/row to
return.
return.
</para>
</para>
</
sect2
>
<example>
<example>
<title>A PL/pgSQL Trigger Procedure Example</title>
<title>A PL/pgSQL Trigger Procedure Example</title>
...
@@ -1461,12 +1519,13 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
...
@@ -1461,12 +1519,13 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
row. And it ensures that an employees name is given and that the
row. And it ensures that an employees name is given and that the
salary is a positive value.
salary is a positive value.
<
programlisting
>
<programlisting>
CREATE TABLE emp (
CREATE TABLE emp (
empname text,
empname text,
salary integer,
salary integer,
last_date timestamp,
last_date timestamp,
last_user
text
);
last_user text
);
CREATE FUNCTION emp_stamp () RETURNS OPAQUE AS '
CREATE FUNCTION emp_stamp () RETURNS OPAQUE AS '
BEGIN
BEGIN
...
@@ -1492,7 +1551,7 @@ CREATE FUNCTION emp_stamp () RETURNS OPAQUE AS '
...
@@ -1492,7 +1551,7 @@ CREATE FUNCTION emp_stamp () RETURNS OPAQUE AS '
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
</
programlisting
>
</programlisting>
</para>
</para>
</example>
</example>
</sect1>
</sect1>
...
@@ -1519,10 +1578,10 @@ CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
...
@@ -1519,10 +1578,10 @@ CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
in
future
versions
of
<
productname
>
Postgres
</
productname
>
will
be
in
future
versions
of
<
productname
>
Postgres
</
productname
>
will
be
forward
compatible
.
forward
compatible
.
</
para
>
</
para
>
<
para
>
<
para
>
For
a
detailed
explanation
and
examples
of
how
to
escape
single
For
a
detailed
explanation
and
examples
of
how
to
escape
single
quotes in different situations, please see <xref linkend="plpgsql-quote"></xref> in
quotes
in
different
situations
,
please
see
<
xref
linkend
=
"plpgsql-quote"
>.
<xref linkend="plpgsql-porting">Porting From Oracle PL/SQL</xref>.
</
para
>
</
para
>
<
example
>
<
example
>
...
@@ -1535,13 +1594,13 @@ CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
...
@@ -1535,13 +1594,13 @@ CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
one
,
returning
the
incremented
value
.
one
,
returning
the
incremented
value
.
</
para
>
</
para
>
<programlisting>
<
programlisting
>
CREATE
FUNCTION
add_one
(
integer
)
RETURNS
integer
AS
'
CREATE
FUNCTION
add_one
(
integer
)
RETURNS
integer
AS
'
BEGIN
BEGIN
RETURN $1 + 1;
RETURN $1 + 1;
END;
END;
'
LANGUAGE
'plpgsql'
;
'
LANGUAGE
'plpgsql'
;
</programlisting>
</
programlisting
>
</
example
>
</
example
>
<
example
>
<
example
>
...
@@ -1552,29 +1611,30 @@ CREATE FUNCTION add_one (integer) RETURNS integer AS '
...
@@ -1552,29 +1611,30 @@ CREATE FUNCTION add_one (integer) RETURNS integer AS '
returns
the
result
of
concatenating
them
.
returns
the
result
of
concatenating
them
.
</
para
>
</
para
>
<programlisting>
<
programlisting
>
CREATE
FUNCTION
concat_text
(
text
,
text
)
RETURNS
text
AS
'
CREATE
FUNCTION
concat_text
(
text
,
text
)
RETURNS
text
AS
'
BEGIN
BEGIN
RETURN $1 || $2;
RETURN $1 || $2;
END;
END;
'
LANGUAGE
'plpgsql'
;
'
LANGUAGE
'plpgsql'
;
</programlisting>
</
programlisting
>
</
example
>
</
example
>
<
example
>
<
example
>
<
title
>
A
PL
/
pgSQL
Function
on
Composite
Type
</
title
>
<
title
>
A
PL
/
pgSQL
Function
on
Composite
Type
</
title
>
<
para
>
<
para
>
In this example, we take EMP (a table) and an <type>integer</type> as
In
this
example
,
we
take
EMP
(
a
table
)
and
an
arguments to our function, which returns a <type>boolean</type>. If the
<
type
>
integer
</
type
>
as
arguments
to
our
function
,
which
returns
"salary" field of the EMP table is <literal>NULL</literal>, we return
a
<
type
>
boolean
</
type
>.
If
the
"salary"
field
of
the
EMP
table
is
"f". Otherwise we compare with that field with the <type>integer</type>
<
literal
>
NULL
</
literal
>,
we
return
"f"
.
Otherwise
we
compare
with
passed to the function and return the <type>boolean</type> result of the
that
field
with
the
<
type
>
integer
</
type
>
passed
to
the
function
comparison (t or f). This is the PL/pgSQL equivalent to the
and
return
the
<
type
>
boolean
</
type
>
result
of
the
comparison
(
t
example from the C functions.
or
f
).
This
is
the
PL
/
pgSQL
equivalent
to
the
example
from
the
C
functions
.
</
para
>
</
para
>
<para>
<programlisting>
<
programlisting
>
CREATE
FUNCTION
c_overpaid
(
EMP
,
integer
)
RETURNS
boolean
AS
'
CREATE
FUNCTION
c_overpaid
(
EMP
,
integer
)
RETURNS
boolean
AS
'
DECLARE
DECLARE
emprec ALIAS FOR $1;
emprec ALIAS FOR $1;
...
@@ -1586,8 +1646,7 @@ CREATE FUNCTION c_overpaid (EMP, integer) RETURNS boolean AS '
...
@@ -1586,8 +1646,7 @@ CREATE FUNCTION c_overpaid (EMP, integer) RETURNS boolean AS '
RETURN emprec.salary > sallim;
RETURN emprec.salary > sallim;
END;
END;
'
LANGUAGE
'plpgsql'
;
'
LANGUAGE
'plpgsql'
;
</programlisting>
</
programlisting
>
</para>
</
example
>
</
example
>
</
sect1
>
</
sect1
>
...
@@ -1681,7 +1740,7 @@ CREATE FUNCTION c_overpaid (EMP, integer) RETURNS boolean AS '
...
@@ -1681,7 +1740,7 @@ CREATE FUNCTION c_overpaid (EMP, integer) RETURNS boolean AS '
<
listitem
>
<
listitem
>
<
para
>
<
para
>
In
PostgreSQL
you
<
emphasis
>
need
</
emphasis
>
to
escape
single
In
PostgreSQL
you
<
emphasis
>
need
</
emphasis
>
to
escape
single
quotes. See <xref linkend="plpgsql-quote">
</xref>
.
quotes
.
See
<
xref
linkend
=
"plpgsql-quote"
>.
</
para
>
</
para
>
</
listitem
>
</
listitem
>
</
itemizedlist
>
</
itemizedlist
>
...
@@ -1695,7 +1754,7 @@ CREATE FUNCTION c_overpaid (EMP, integer) RETURNS boolean AS '
...
@@ -1695,7 +1754,7 @@ CREATE FUNCTION c_overpaid (EMP, integer) RETURNS boolean AS '
function
definition
.
This
can
lead
to
quite
amusing
code
at
function
definition
.
This
can
lead
to
quite
amusing
code
at
times
,
especially
if
you
are
creating
a
function
that
generates
times
,
especially
if
you
are
creating
a
function
that
generates
other
function
(
s
),
as
in
other
function
(
s
),
as
in
<xref linkend="plpgsql-porting-nastyquote">
this example</xref>
.
<
xref
linkend
=
"plpgsql-porting-nastyquote"
>.
One
thing
to
keep
in
mind
One
thing
to
keep
in
mind
when
escaping
lots
of
single
quotes
is
that
,
except
for
the
when
escaping
lots
of
single
quotes
is
that
,
except
for
the
beginning
/
ending
quotes
,
all
the
others
will
come
in
even
beginning
/
ending
quotes
,
all
the
others
will
come
in
even
...
@@ -1703,7 +1762,7 @@ CREATE FUNCTION c_overpaid (EMP, integer) RETURNS boolean AS '
...
@@ -1703,7 +1762,7 @@ CREATE FUNCTION c_overpaid (EMP, integer) RETURNS boolean AS '
</
para
>
</
para
>
<
para
>
<
para
>
<xref linkend="plpgsql-quoting-table">
</xref>
gives the scoop. (You'
ll
<
xref
linkend
=
"plpgsql-quoting-table"
>
gives
the
scoop
.
(
You
'll
love this little chart.)
love this little chart.)
</para>
</para>
...
@@ -1776,7 +1835,7 @@ a_output := a_output || '' AND name
...
@@ -1776,7 +1835,7 @@ a_output := a_output || '' AND name
(which accounts for 8 quotes) <emphasis>and</emphasis>
(which accounts for 8 quotes) <emphasis>and</emphasis>
terminate that string (2 more). You will probably only need
terminate that string (2 more). You will probably only need
that if you were using a function to generate other functions
that if you were using a function to generate other functions
(
like
in
<
xref
linkend
=
"plpgsql-porting-nastyquote"
>
</
xref
>
).
(like in <xref linkend="plpgsql-porting-nastyquote">).
</entry>
</entry>
<entry><programlisting>
<entry><programlisting>
a_output := a_output || '' if v_'' ||
a_output := a_output || '' if v_'' ||
...
@@ -1865,7 +1924,7 @@ SHOW ERRORS;
...
@@ -1865,7 +1924,7 @@ SHOW ERRORS;
On
PostgreSQL
functions
are
created
using
single
quotes
as
On
PostgreSQL
functions
are
created
using
single
quotes
as
delimiters
,
so
you
have
to
escape
single
quotes
inside
your
delimiters
,
so
you
have
to
escape
single
quotes
inside
your
functions
(
which
can
be
quite
annoying
at
times
;
see
<
xref
functions
(
which
can
be
quite
annoying
at
times
;
see
<
xref
linkend="plpgsql-quote">
this example</xref>
).
linkend
=
"plpgsql-quote"
>).
</
para
>
</
para
>
</
listitem
>
</
listitem
>
...
@@ -1986,7 +2045,7 @@ end;
...
@@ -1986,7 +2045,7 @@ end;
The following Oracle PL/SQL procedure is used to parse a URL and
The following Oracle PL/SQL procedure is used to parse a URL and
return several elements (host, path and query). It is an
return several elements (host, path and query). It is an
procedure because in PL/pgSQL functions only one value can be returned
procedure because in PL/pgSQL functions only one value can be returned
(
see
<
xref
linkend
=
"plpgsql-porting-procedures"
>
</
xref
>
).
In
(see <xref linkend="plpgsql-porting-procedures">). In
PostgreSQL, one way to work around this is to split the procedure
PostgreSQL, one way to work around this is to split the procedure
in three different functions: one to return the host, another for
in three different functions: one to return the host, another for
the path and another for the query.
the path and another for the query.
...
@@ -2036,16 +2095,16 @@ show errors;
...
@@ -2036,16 +2095,16 @@ show errors;
Here
is
how
this
procedure
could
be
translated
for
PostgreSQL
:
Here
is
how
this
procedure
could
be
translated
for
PostgreSQL
:
<
programlisting
>
<
programlisting
>
drop function cs_parse_url_host(varchar);
drop
function
cs_parse_url_host
(
varchar
);
create function cs_parse_url_host(varchar) returns varchar as '
create
function
cs_parse_url_host
(
varchar
)
returns
varchar
as
'
declare
declare
v_url ALIAS FOR $1;
v_url ALIAS FOR $1;
v_host varchar;
v_host varchar;
v_path varchar;
v_path varchar;
a_pos1 integer;
a_pos1 integer;
a_pos2 integer;
a_pos2 integer;
a_pos3 integer;
a_pos3 integer;
begin
begin
v_host := NULL;
v_host := NULL;
a_pos1 := instr(v_url,''//'');
a_pos1 := instr(v_url,''//'');
...
@@ -2062,8 +2121,8 @@ show errors;
...
@@ -2062,8 +2121,8 @@ show errors;
v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2 );
v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2 );
return v_host;
return v_host;
end
;
end;
' language '
plpgsql
';
'
language
'plpgsql'
;
</
programlisting
>
</
programlisting
>
</
para
>
</
para
>
</
example
>
</
example
>
...
@@ -2075,7 +2134,7 @@ show errors;
...
@@ -2075,7 +2134,7 @@ show errors;
I
got
tired
of
doing
this
and
created
my
own
I
got
tired
of
doing
this
and
created
my
own
<
function
>
instr
</
function
>
functions
that
behave
exactly
like
<
function
>
instr
</
function
>
functions
that
behave
exactly
like
Oracle
's (it makes life easier). See the <xref
Oracle
's (it makes life easier). See the <xref
linkend
=
"plpgsql-porting-appendix"
>
</
xref
>
for
the
code
.
linkend="plpgsql-porting-appendix"> for the code.
</para>
</para>
</note>
</note>
</sect2>
</sect2>
...
@@ -2098,15 +2157,15 @@ show errors;
...
@@ -2098,15 +2157,15 @@ show errors;
create or replace procedure cs_create_job(v_job_id in integer)
create or replace procedure cs_create_job(v_job_id in integer)
is
is
a_running_job_count integer;
a_running_job_count integer;
pragma
autonomous_transaction
;<
co
id
=
"co.plpgsql-porting-pragma"
>
</
co
>
pragma autonomous_transaction;<co id="co.plpgsql-porting-pragma">
begin
begin
lock
table
cs_jobs
in
exclusive
mode
;<
co
id
=
"co.plpgsql-porting-locktable"
>
</
co
>
lock table cs_jobs in exclusive mode;<co id="co.plpgsql-porting-locktable">
select count(*) into a_running_job_count from cs_jobs
select count(*) into a_running_job_count from cs_jobs
where end_stamp is null;
where end_stamp is null;
if a_running_job_count > 0 then
if a_running_job_count > 0 then
commit
;
--
free
lock
<
co
id
=
"co.plpgsql-porting-commit"
>
</
co
>
commit; -- free lock<co id="co.plpgsql-porting-commit">
raise_application_error(-20000, '
Unable
to
create
a
new
job
:
a
job
is
currently
running
.
');
raise_application_error(-20000, '
Unable
to
create
a
new
job
:
a
job
is
currently
running
.
');
end if;
end if;
...
@@ -2115,7 +2174,7 @@ begin
...
@@ -2115,7 +2174,7 @@ begin
begin
begin
insert into cs_jobs(job_id, start_stamp) values(v_job_id, sysdate);
insert into cs_jobs(job_id, start_stamp) values(v_job_id, sysdate);
exception
when
dup_val_on_index
then
null
;
--
don
't worry if it already exists<co id="co.plpgsql-porting-exception">
</co>
exception when dup_val_on_index then null; -- don'
t
worry
if
it
already
exists
<
co
id
=
"co.plpgsql-porting-exception"
>
end
;
end
;
commit
;
commit
;
end
;
end
;
...
@@ -2190,7 +2249,7 @@ begin
...
@@ -2190,7 +2249,7 @@ begin
insert
into
cs_jobs
(
job_id
,
start_stamp
)
values
(
v_job_id
,
sysdate
());
insert
into
cs_jobs
(
job_id
,
start_stamp
)
values
(
v_job_id
,
sysdate
());
return
1
;
return
1
;
ELSE
ELSE
raise NOTICE ''Job already running.'';<co id="co.plpgsql-porting-raise">
</co>
raise
NOTICE
''
Job
already
running
.
''
;<
co
id
=
"co.plpgsql-porting-raise"
>
END
IF
;
END
IF
;
return
0
;
return
0
;
...
@@ -2301,7 +2360,7 @@ END;
...
@@ -2301,7 +2360,7 @@ END;
nicely
,
but
you
have
to
remember
to
use
nicely
,
but
you
have
to
remember
to
use
<
function
>
quote_literal
(
TEXT
)</
function
>
and
<
function
>
quote_literal
(
TEXT
)</
function
>
and
<
function
>
quote_string
(
TEXT
)</
function
>
as
described
in
<
xref
<
function
>
quote_string
(
TEXT
)</
function
>
as
described
in
<
xref
linkend="plpgsql-statements
"></xref
>. Constructs of the type
linkend
=
"plpgsql-statements
-executing-dyn-queries"
>.
Constructs
of
the
type
<
literal
>
EXECUTE
''
SELECT
*
from
$
1
''
;</
literal
>
will
not
work
<
literal
>
EXECUTE
''
SELECT
*
from
$
1
''
;</
literal
>
will
not
work
unless
you
use
these
functions
.
unless
you
use
these
functions
.
</
para
>
</
para
>
...
@@ -2486,8 +2545,7 @@ CREATE FUNCTION instr(varchar, varchar, integer, integer) RETURNS integer AS '
...
@@ -2486,8 +2545,7 @@ CREATE FUNCTION instr(varchar, varchar, integer, integer) RETURNS integer AS '
return [expr $pos + 1]
return [expr $pos + 1]
}
}
'
LANGUAGE
'pltcl'
;
'
LANGUAGE
'pltcl'
;
</
programlisting
>
</programlisting>
</
sect3
>
</
sect3
>
</
sect2
>
</
sect2
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment