General editing
authorPeter Eisentraut
Mon, 7 Apr 2003 01:29:26 +0000 (01:29 +0000)
committerPeter Eisentraut
Mon, 7 Apr 2003 01:29:26 +0000 (01:29 +0000)
doc/src/sgml/datetime.sgml
doc/src/sgml/jdbc.sgml
doc/src/sgml/plperl.sgml
doc/src/sgml/plpgsql.sgml
doc/src/sgml/plpython.sgml
doc/src/sgml/pltcl.sgml
doc/src/sgml/pygresql.sgml
doc/src/sgml/xplang.sgml

index f237bdea253d59ee939f959594b679a0bd5bf9ea..d7a76dab2331d17e123f6bdce2c30bb5d1b03a44 100644 (file)
@@ -1,5 +1,5 @@
 
 
  
@@ -210,7 +210,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/datetime.sgml,v 2.30 2003/03/13 01:30:27 pe
   
 
 
-  
+   id="datetime-keywords">
    Date/Time Key Words
 
    
index 817a0a7e2f66158a152e495df29fd96c588b1c86..525cc07175ded378fccc1a4e70149f6bfbe5b62f 100644 (file)
@@ -1,18 +1,10 @@
 
 
  
   <acronym>JDBC</acronym> Interface
 
-  
-   Author
-   
-    Originally written by Peter T. Mount ([email protected]), 
-    the original author of the JDBC driver.
-   
-  
-
   
    JDBC is a core API of Java 1.1 and later.
    It provides a standard set of
@@ -21,7 +13,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/jdbc.sgml,v 1.43 2003/03/25 16:15:37
 
   
    PostgreSQL provides a type
-   4 JDBC Driver.  Type 4 indicates
+   4 JDBC driver.  Type 4 indicates
    that the driver is written in Pure Java, and communicates in the
    database system's own network protocol. Because of this, the driver
    is platform independent; once compiled, the driver can be used on
@@ -33,13 +25,17 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/jdbc.sgml,v 1.43 2003/03/25 16:15:37
    JDBC programming, but should help to get you
    started. For more information refer to the standard
    JDBC API documentation.
-   Also, take a look at the examples included with the source. The
-   basic example is used here.
+   Also, take a look at the examples included with the source.
   
 
  
   Setting up the <acronym>JDBC</acronym> Driver
 
+  
+   This section describes the steps you need to take before you can
+   write or run programs that use the JDBC interface.
+  
+
   
    Getting the Driver
 
@@ -71,8 +67,8 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/jdbc.sgml,v 1.43 2003/03/25 16:15:37
    
     To use the driver, the JAR archive (named
     postgresql.jar if you built from source, otherwise
-    it will likely be named jdbc7.2-1.1.jar or 
-    jdbc7.2-1.2.jar for the JDBC 1 and JDBC 2 versions
+    it will likely be named jdbc&majorversion;-1.1.jar or 
+    jdbc&majorversion;-1.2.jar for the JDBC 1 and JDBC 2 versions
     respectively)
     needs to be included in the
     class path, either by putting it in the CLASSPATH
@@ -80,26 +76,18 @@ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/jdbc.sgml,v 1.43 2003/03/25 16:15:37
     java command line.
    
 
-    
-     For instance, I have an application that uses the
-     JDBC driver to access a large database
-     containing astronomical objects. I have the application and the
-     JDBC driver installed in the 
-     class="directory">/usr/local/lib directory, and the
-     Java JDK installed in
-     /usr/local/jdk1.3.1.  To run the
-     application, I would use:
+   
+    For instance, assume we have an application that uses the
+    JDBC driver to access a database, and that
+    application is installed as
+    /usr/local/lib/myapp.jar.  The PostgreSQL
+    JDBC driver installed as
+    /usr/local/pgsql/share/java/postgresql.jar.  To run
+    the application, we would use:
 
-export CLASSPATH=/usr/local/lib/finder.jar:/usr/local/pgsql/share/java/postgresql.jar:.
-java Finder
+export CLASSPATH=/usr/local/lib/myapp.jar:/usr/local/pgsql/share/java/postgresql.jar:.
+java MyApp
 
-     
-      
-       
-        finder.jar contains the Finder application.
-       
-      
-     
     
 
     
@@ -109,7 +97,7 @@ java Finder
   
 
   
-   Preparing the Database for <acronym>JDBC</acronym>
+   Preparing the Database <span class="marked">Server </span>for <acronym>JDBC</acronym>
 
    
     Because Java only uses TCP/IP connections, the
@@ -125,14 +113,19 @@ java Finder
     Also, the client authentication setup in the
     pg_hba.conf file may need to be configured.
     Refer to  for details.  The
-    JDBC Driver supports the trust, ident,
+    JDBC driver supports the trust, ident,
     password, md5, and crypt authentication methods.
    
   
  
 
  
-  Using the Driver
+  Initializing the Driver
+
+  
+   This section describes how to load and initialize the JDBC driver
+   in your programs.
+  
 
   
    Importing <acronym>JDBC</acronym>
@@ -144,15 +137,15 @@ java Finder
 
 import java.sql.*;
 
+   
 
-    <important>
+    <note>
      
       Do not import the org.postgresql package. If
       you do, your source will not compile, as
       javac will get confused.
      
-    
-   
+    
   
 
   
@@ -175,6 +168,7 @@ Class.forName("org.postgresql.Driver");
 
     This will load the driver, and while loading, the driver will automatically
     register itself with JDBC.
+   
 
     
      
@@ -183,7 +177,6 @@ Class.forName("org.postgresql.Driver");
       not available.
      
     
-   
 
    
     This is the most common method to use, but restricts your code to
@@ -250,7 +243,7 @@ jdbc:postgresql://host:
      
     
 
-    where:
+    The parametes have the following meanings:
 
     
      
@@ -292,7 +285,7 @@ jdbc:postgresql://host:
    
     To connect, you need to get a Connection instance from 
     JDBC. To do this,
-    you would use the DriverManager.getConnection() method:
+    you use the DriverManager.getConnection() method:
 
 
 Connection db = DriverManager.getConnection(url, username, password);
@@ -336,8 +329,8 @@ db.close();
      column of each row using a Statement.
 
 Statement st = db.createStatement();
-ResultSet rs = st.executeQuery("SELECT * FROM mytable where columnfoo = 500");
-while(rs.next()) {
+ResultSet rs = st.executeQuery("SELECT * FROM mytable WHERE columnfoo = 500");
+while (rs.next()) {
     System.out.print("Column 1 returned ");
     System.out.println(rs.getString(1));
 }
@@ -347,15 +340,15 @@ st.close();
     
 
     
-     This example will issue the same query as before using 
+     This example issues the same query as before but uses
      a PreparedStatement
      and a bind value in the query.
 
 int foovalue = 500;
-PreparedStatement st = db.prepareStatement("SELECT * FROM mytable where columnfoo = ?");
+PreparedStatement st = db.prepareStatement("SELECT * FROM mytable WHERE columnfoo = ?");
 st.setInt(1, foovalue);
 ResultSet rs = st.executeQuery();
-while(rs.next()) {
+while (rs.next()) {
     System.out.print("Column 1 returned ");
     System.out.println(rs.getString(1));
 }
@@ -366,8 +359,7 @@ st.close();
    
 
    
-    Using the <classname>Statement</classname> or <classname></div> <div class="diff rem">-    PreparedStatement</classname> Interface
+    Using the <classname>Statement</classname> or <classname>PreparedStatement</classname> Interface
 
     
      The following must be considered when using the
@@ -463,10 +455,10 @@ st.close();
        
         ResultSet is currently read only.
         You can not update data through the ResultSet.
-        If you want to update data you need to do it the old fashioned way
-        by issuing a SQL update statement.  This is 
+        If you want to update data you need to do it the normal way
+        by using the SQL statement UPDATE.  This is 
         in conformance with the JDBC specification 
-        which does not require drivers to provide this functionality.
+        which does not require drivers to provide updatable result sets.
        
       
      
@@ -478,23 +470,25 @@ st.close();
    Performing Updates
 
    
-    To change data (perform an insert, update, or delete) 
-    you use the executeUpdate() method.
-    executeUpdate() is similar to the
-    executeQuery() used to issue a select,
-    however it doesn't return a ResultSet,
-    instead it returns the number of records affected by the insert,
-    update, or delete statement.
+    To change data (perform an INSERT,
+    UPDATE, or DELETE) you use
+    the executeUpdate() method.  This method is
+    similar to the method executeQuery() used to
+    issue a SELECT statement, but it doesn't return
+    a ResultSet; instead it returns the number
+    of rows affected by the INSERT,
+    UPDATE, or DELETE statement.
+     illustrates the usage.
    
 
   
-   <span class="marked">Simple Delete Example</span>
+   <span class="marked">Deleting Rows in <acronym>JDBC</acronym></span>
    
-     This example will issue a simple delete and print out the number
-     of rows deleted.
+     This example will issue a simple DELETE
+     statement and print out the number of rows deleted.
 
 int foovalue = 500;
-PreparedStatement st = db.prepareStatement("DELETE FROM mytable where columnfoo = ?");
+PreparedStatement st = db.prepareStatement("DELETE FROM mytable WHERE columnfoo = ?");
 st.setInt(1, foovalue);
 int rowsDeleted = st.executeUpdate();
 System.out.println(rowsDeleted + " rows deleted");
@@ -509,19 +503,19 @@ st.close();
 
    
     To create, modify or drop a database object like a table or view
-    you use the execute() method.
-    execute is similar to the
-    executeQuery() used to issue a select,
-    however it doesn't return a result.
+    you use the execute() method.  This method is
+    similar to the method executeQuery(), but it
+    doesn't return a result.  
+    illustrates the usage.
    
 
   
-   Drop<span class="marked"> Table Example</span>
+   Drop<span class="marked">ping a Table in JDBC</span>
    
      This example will drop a table.
 
 Statement st = db.createStatement();
-ResultSet rs = st.executeQuery("DROP TABLE mytable");
+st.execute("DROP TABLE mytable");
 st.close();
 
    
@@ -534,11 +528,10 @@ st.close();
   
     PostgreSQL provides two distinct ways to 
     store binary data.  Binary data can be stored in a table using 
-    PostgreSQL's binary data type 
-    bytea, or by using the Large Object
+    the data type bytea or by using the Large Object
     feature which stores the binary data in a separate table in a special 
-    format, and refers to that table by storing a value of type 
-    OID in your table.
+    format and refers to that table by storing a value of type 
+    oid in your table.
   
 
   
@@ -547,32 +540,32 @@ st.close();
     bytea data type is not well suited for storing very 
     large amounts of binary data.  While a column of type 
     bytea can hold up to 1 GB of binary data, it would 
-    require a huge amount of memory (RAMto 
+    require a huge amount of memory to 
     process such a large value.  The Large Object method for 
     storing binary data is better suited to storing very large values, 
     but it has its own limitations.  Specifically deleting a row 
-    that contains a Large Object does not delete the Large Object.
+    that contains a Large Object reference does not delete the Large Object.
     Deleting the Large Object is a separate operation that needs to
     be performed.  Large Objects also have some security
-    issues since anyone connected to the database case view 
+    issues since anyone connected to the database cann view 
     and/or modify any Large Object, even if they don't have 
-    permissions to view/update the row containing the Large Object.
+    permissions to view/update the row containing the Large Object reference.
   
 
   
-    7.2 is the first release of the JDBC Driver 
+    Version 7.2 was the first release of the JDBC driver 
     that supports the bytea data type.  The introduction of 
     this functionality in 7.2 has introduced a change in behavior 
-    as compared to previous releases.  In 7.2 the methods 
+    as compared to previous releases.  Since 7.2, the methods 
     getBytes()setBytes()
     getBinaryStream(), and 
     setBinaryStream() operate on 
-    the bytea data type.  In 7.1 these methods operated 
-    on the OID data type associated with Large Objects.  
+    the bytea data type.  In 7.1 and earlier, these methods operated 
+    on the oid data type associated with Large Objects.  
     It is possible to revert the driver back to the old 7.1 behavior 
-    by setting the compatible property on 
-    the Connection to a value of 
-    7.1
+    by setting the property compatible on 
+    the Connection object to the value
+    7.1.
   
 
   
@@ -584,39 +577,44 @@ st.close();
 
   
     To use the Large Object functionality you can use either the 
-    LargeObject API
+    LargeObject class
     provided by the PostgreSQL 
-    JDBC Driver, or by using the 
+    JDBC driver, or by using the 
     getBLOB() and setBLOB()
     methods.
   
 
   
    
-    For PostgreSQL, you must access Large
-    Objects within an SQL transaction.  You would
-    open a transaction by using the
-    setAutoCommit() method with an input
-    parameter of false.
+    You must access Large Objects within an SQL
+    transaction block.  You can start a transaction block by calling
+    setAutoCommit(false).
    
   
 
-  In a future release of the
-      JDBC Driver, the getBLOB()
+  
+   
+      In a future release of the
+      JDBC driver, the getBLOB()
       and setBLOB() methods may no longer 
-      interact with Large Objects and will instead work on 
-      bytea data types.  So it is recommended that you 
+      interact with Large Objects and will instead work on the data type
+      bytea.  So it is recommended that you 
       use the LargeObject API 
       if you intend to use Large Objects.
-  
+   
+  
 
+  
+    contains some examples on
+   how to process binary data using the PostgreSQL JDBC driver.
+  
 
   
-   <span class="marked">Binary Data Examples</span>
+   <span class="marked">Processing Binary Data in JDBC</span>
 
    
-    For example, suppose you have a table containing the file name of
-    an image and you also want to store the image in a bytea
+    For example, suppose you have a table containing the file names of
+    images and you also want to store the image in a bytea
     column:
 
 CREATE TABLE images (imgname text, img bytea);
@@ -649,13 +647,13 @@ fis.close();
     Statement class can equally be used.)
 
 
-PreparedStatement ps = con.prepareStatement("SELECT img FROM images WHERE imgname=?");
+PreparedStatement ps = con.prepareStatement("SELECT img FROM images WHERE imgname = ?");
 ps.setString(1, "myimage.gif");
 ResultSet rs = ps.executeQuery();
 if (rs != null) {
-    while(rs.next()) {
+    while (rs.next()) {
         byte[] imgBytes = rs.getBytes(1);
-        // use the stream in some way here
+        // use the data in some way here
     }
     rs.close();
 }
@@ -674,76 +672,76 @@ ps.close();
     the LargeObject API to 
     store the file:
 
-CREATE TABLE imagesLO (imgname text, imgOID OID);
+CREATE TABLE imageslo (imgname text, imgoid oid);
 
    
 
    
     To insert an image, you would use:
 
-// All LargeObject API calls must be within a transaction
+// All LargeObject API calls must be within a transaction block
 conn.setAutoCommit(false);
 
 // Get the Large Object Manager to perform operations with
 LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI();
 
-//create a new large object
+// Create a new large object
 int oid = lobj.create(LargeObjectManager.READ | LargeObjectManager.WRITE);
 
-//open the large object for write
+// Open the large object for writing
 LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);
 
 // Now open the file
 File file = new File("myimage.gif");
 FileInputStream fis = new FileInputStream(file);
 
-// copy the data from the file to the large object
+// Copy the data from the file to the large object
 byte buf[] = new byte[2048];
 int s, tl = 0;
-while ((s = fis.read(buf, 0, 2048)) > 0)
-{
-   obj.write(buf, 0, s);
-   tl += s;
+while ((s = fis.read(buf, 0, 2048)) > 0) {
+    obj.write(buf, 0, s);
+    tl += s;
 }
 
 // Close the large object
 obj.close();
 
-//Now insert the row into imagesLO
-PreparedStatement ps = conn.prepareStatement("INSERT INTO imagesLO VALUES (?, ?)");
+// Now insert the row into imageslo
+PreparedStatement ps = conn.prepareStatement("INSERT INTO imageslo VALUES (?, ?)");
 ps.setString(1, file.getName());
 ps.setInt(2, oid);
 ps.executeUpdate();
 ps.close();
 fis.close();
 
-
+   
+
    
     Retrieving the image from the Large Object:
 
 
-// All LargeObject API calls must be within a transaction
+// All LargeObject API calls must be within a transaction block
 conn.setAutoCommit(false);
 
 // Get the Large Object Manager to perform operations with
 LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI();
 
-PreparedStatement ps = con.prepareStatement("SELECT imgOID FROM imagesLO WHERE imgname=?");
+PreparedStatement ps = con.prepareStatement("SELECT imgoid FROM imageslo WHERE imgname = ?");
 ps.setString(1, "myimage.gif");
 ResultSet rs = ps.executeQuery();
 if (rs != null) {
-    while(rs.next()) {
-   //open the large object for reading
-   int oid = rs.getInt(1);
-   LargeObject obj = lobj.open(oid, LargeObjectManager.READ);
-
-   //read the data
-   byte buf[] = new byte[obj.size()];
-   obj.read(buf, 0, obj.size());
-   //do something with the data read here
-
-   // Close the object
-   obj.close();
+    while (rs.next()) {
+        // Open the large object for reading
+        int oid = rs.getInt(1);
+        LargeObject obj = lobj.open(oid, LargeObjectManager.READ);
+
+        // Read the data
+        byte buf[] = new byte[obj.size()];
+        obj.read(buf, 0, obj.size());
+        // Do something with the data read here
+
+        // Close the object
+        obj.close();
     }
     rs.close();
 }
@@ -2441,93 +2439,78 @@ public void unlink(int oid) throws SQLException
 
 
  
-  Using the <span class="marked">driver in a multithreaded or a servlet e</span>nvironment
+  Using the <span class="marked">Driver in a Multithreaded or a Servlet E</span>nvironment
 
   
    A problem with many JDBC drivers is that only
    one thread can use a Connection at any one
-   time -- otherwise a thread could send a query while another one is
-   receiving results, and this would be a bad thing for the database
-   engine.
+   time --- otherwise a thread could send a query while another one is
+   receiving results, and this could cause severe confusion.
   
 
   
-   The PostgreSQL JDBC Driver
+   The PostgreSQL JDBC driver
    is thread safe.
    Consequently, if your application uses multiple threads then you do
-   not have to worry about complex algorithms to ensure that only one
-   uses the database at any time.
+   not have to worry about complex algorithms to ensure that only one thread
+   uses the database at a time.
   
 
   
    If a thread attempts to use the connection while another one is
    using it, it will wait until the other thread has finished its
-   current operation.  If it is a regular SQL
+   current operation.  If the operation is a regular SQL
    statement, then the operation consists of sending the statement and
    retrieving any ResultSet (in full).  If it
-   is a Fastpath call (e.g., reading a block
-   from a LargeObject) then it is the time to
-   send and retrieve that block.
+   is a fast-path call (e.g., reading a block
+   from a large object) then it consists of
+   sending and retrieving the respective data.
   
 
   
    This is fine for applications and applets but can cause a
-   performance problem with servlets.  With servlets you can have a
-   heavy load on the connection. If you have several threads
-   performing queries then each but one will pause, which may not be what
-   you are after.
-  
-
-  
-   To solve this, you would be advised to create a pool of
-   connections.  When ever a thread needs to use the database, it asks
-   a manager class for a Connection. The
-   manager hands a free connection to the thread and marks it as
-   busy. If a free connection is not available, it opens one.  Once
-   the thread has finished with it, it returns it to the manager who
-   can then either close it or add it to the pool. The manager would
-   also check that the connection is still alive and remove it from
-   the pool if it is dead.
-  
-
-  
-   So, with servlets, it is up to you to use either a single
-   connection, or a pool. The plus side for a pool is that threads
-   will not be hit by the bottle neck caused by a single network
-   connection. The down side is that it increases the load on the
-   server, as a backend process is created for each
-   Connection.  It is up to you and your
-   applications requirements.
+   performance problem with servlets.  If you have several threads
+   performing queries then each but one will pause.
+   To solve this, you are advised to create a pool of connections.
+   When ever a thread needs to use the database, it asks a manager
+   class for a Connection object. The manager
+   hands a free connection to the thread and marks it as busy. If a
+   free connection is not available, it opens one.  Once the thread
+   has finished using the connection, it returns it to the manager
+   which can then either close it or add it to the pool. The manager
+   would also check that the connection is still alive and remove it
+   from the pool if it is dead.  The down side of a connection pool is
+   that it increases the load on the server because a new session is
+   created for each Connection object.  It is
+   up to you and your applications' requirements.
   
  
 
  
-  Connection Pools And DataSources
-
-  
-   JDBC, JDK Version Support
+  Connection Pools and Data Sources
 
-   
+  
     JDBC 2 introduced standard connection pooling features in an
     add-on API known as the JDBC 2.0 Optional
     Package (also known as the JDBC 2.0
     Standard Extension).  These features have since been included in
     the core JDBC 3 API.  The PostgreSQL
-    JDBC drivers support these features with
+    JDBC drivers support these features if it has been compiled with
     JDK 1.3.x in combination with the
     JDBC 2.0 Optional Package
-    (JDBC 2), or with JDK 1.4+
+    (JDBC 2), or with JDK 1.4 or higher
     (JDBC 3).  Most application servers include
     the JDBC 2.0 Optional Package, but it is
     also available separately from the Sun
     
     url="http://java.sun.com/products/jdbc/download.html#spec">JDBC download site.
    
-  
 
   
-    JDBC Connection Pooling API
-    The JDBC API provides a client
+   Overview
+
+    
+     The JDBC API provides a client
      and a server interface for connection pooling.  The client
      interface is javax.sql.DataSource,
      which is what application code will typically use to
@@ -2535,16 +2518,22 @@ public void unlink(int oid) throws SQLException
      is javax.sql.ConnectionPoolDataSource,
      which is how most application servers will interface with
      the PostgreSQL JDBC
-     driver.
-    In an application server environment, the
+     driver.
+    
+
+    
+     In an application server environment, the
      application server configuration will typically refer to
      the PostgreSQL
      ConnectionPoolDataSource implementation,
      while the application component code will typically acquire a
      DataSource implementation provided by
      the application server (not by
-     PostgreSQL).
-    In an environment without an application server,
+     PostgreSQL).
+    
+
+    
+     For an environment without an application server,
      PostgreSQL provides two implementations
      of DataSource which an application can use
      directly.  One implementation performs connection pooling,
@@ -2553,19 +2542,23 @@ public void unlink(int oid) throws SQLException
      any pooling.  Again, these implementations should not be used
      in an application server environment unless the application
      server does not support the
-     ConnectionPoolDataSource interface.
+     ConnectionPoolDataSource interface.
+    
   
    
   
-    Application Servers: ConnectionPoolDataSource
-    PostgreSQL includes one
-     implementation of ConnectionPoolDataSource
-     for JDBC 2, and one for 
-     JDBC 3:
+   Application Servers: <classname>ConnectionPoolDataSource</classname>
+
+   
+    PostgreSQL includes one implementation
+    of ConnectionPoolDataSource for
+    JDBC 2 and one for JDBC 3,
+    as shown in .
+   
 
   
-    >
-    <span class="marked">ConnectionPoolDataSource</span> Implementations
+   >
+    <span class="marked"><classname>ConnectionPoolDataSource</classname></span> Implementations
   
     
      
@@ -2587,15 +2580,18 @@ public void unlink(int oid) throws SQLException
       
      
     
-    
+   
 
-    Both implementations use the same configuration scheme.
-     JDBC requires that a
-     ConnectionPoolDataSource be configured via
-     JavaBean properties, so there are get and set methods for each of
-     these properties:
-    
-    ConnectionPoolDataSource Configuration Properties
+   
+    Both implementations use the same configuration scheme.
+    JDBC requires that a
+    ConnectionPoolDataSource be configured via
+    JavaBean properties, shown in ,
+    so there are get and set methods for each of these properties.
+   
+
+   
+    <classname>ConnectionPoolDataSource</> Configuration Properties
   
     
      
@@ -2608,97 +2604,98 @@ public void unlink(int oid) throws SQLException
  
      
       
-       serverName
-       <literal>String>
+       serverName
+       <type>String>
        PostgreSQL database server
-         hostname
+         host name
       
  
       
-       databaseName
-       <literal>String>
+       databaseName
+       <type>String>
        PostgreSQL database name
       
  
       
-       portNumber
-       int
-       TCP/IP port which the 
-        PostgreSQL database server is
-   listening on (or 0 to use the default port)
+       portNumber
+       int
+       
+        TCP port which the PostgreSQL
+        database server is listening on (or 0 to use the default port)
+       
       
  
       
-       user
-       <literal>String>
+       user
+       <type>String>
        User used to make database connections
       
  
       
-       password
-       <literal>String>
+       password
+       <type>String>
        Password used to make database connections
       
  
       
-       defaultAutoCommit
-       boolean
-       Whether connections should have autoCommit
-   enabled or disabled when they are supplied to the
-   caller.  The default is false, to
-   disable autoCommit.
+       defaultAutoCommit
+       boolean
+       
+        Whether connections should have autocommit enabled or disabled
+        when they are supplied to the caller.  The default is
+        false, to disable autocommit.
+       
       
      
     
-    
-
-    Many application servers use a properties-style syntax to
-     configure these properties, so it would not be unusual to
-     enter properties as a block of text.
+   
 
-   <example id="jdbc-cpds-config">
-    <literal>ConnectionPoolDataSource</literal> Configuration Example
-
-    
-     If the application server provides a single area to enter all
-      the properties, they might be listed like this:
+   <para>
+    Many application servers use a properties-style syntax to
+    configure these properties, so it would not be unusual to enter
+    properties as a block of text.  If the application server provides
+    a single area to enter all the properties, they might be listed
+    like this:
 
 serverName=localhost
 databaseName=test
 user=testuser
 password=testpassword
 
-      Or, separated by semicolons instead of newlines, like this:
+    Or, if semicolons are used as separators instead of newlines, it
+    could look like this:
 
 serverName=localhost;databaseName=test;user=testuser;password=testpassword
 
-    
-   
+   
 
   
 
   
-    Applications: DataSource
+   Applications: <classname>DataSource</>
+
     PostgreSQL includes two
      implementations of DataSource
-     for JDBC 2, and two for JDBC
-     3.  The pooling implementations do not actually close connections
+     for JDBC 2 and two for JDBC
+     3, as shown in .
+     The pooling implementations do not actually close connections
      when the client calls the close method, but
      instead return the connections to a pool of available connections
      for other clients to use.  This avoids any overhead of repeatedly
      opening and closing connections, and allows a large number of
      clients to share a small number of database connections.
-    The pooling datasource implementation provided here is not
+    The pooling data-source implementation provided here is not
      the most feature-rich in the world.  Among other things,
      connections are never closed until the pool itself is closed;
      there is no way to shrink the pool.  As well, connections
      requested for users other than the default configured user are
      not pooled.  Many application servers
-     provide more advanced pooling features, and use the
+     provide more advanced pooling features and use the
      ConnectionPoolDataSource implementation
      instead.
-    
-    DataSource Implementations
+
+   
+    <classname>DataSource</> Implementations
   
     
      
@@ -2738,14 +2735,16 @@ serverName=localhost;databaseName=test;user=testuser;password=testpassword
     
     
 
-    All the implementations use the same configuration scheme.
+    
+     All the implementations use the same configuration scheme.
      JDBC requires that a
-     DataSource be configured via
-     JavaBean properties, so there are get and set methods for each of
-     these properties.
+     DataSource be configured via JavaBean
+     properties, shown in , so there
+     are get and set methods for each of these properties.
+    
 
-    
-    <span class="marked">DataSource</span> Configuration Properties
+     id="jdbc-ds-ds-props">
+    <span class="marked"><classname>DataSource</></span> Configuration Properties
   
     
      
@@ -2758,35 +2757,35 @@ serverName=localhost;databaseName=test;user=testuser;password=testpassword
  
      
       
-       serverName
-       <literal>String>
+       serverName
+       <type>String>
        PostgreSQL database server
-         hostname
+         host name
       
  
       
-       databaseName
-       <literal>String>
+       databaseName
+       <type>String>
        PostgreSQL database name
       
  
       
-       portNumber
-       <literal>int>
-       TCP/IP port which the 
+       portNumber
+       <type>int>
+       TCP port which the 
         PostgreSQL database server is
    listening on (or 0 to use the default port)
       
  
       
-       user
-       <literal>String>
+       user
+       <type>String>
        User used to make database connections
       
  
       
-       password
-       <literal>String>
+       password
+       <type>String>
        Password used to make database connections
       
      
@@ -2794,10 +2793,10 @@ serverName=localhost;databaseName=test;user=testuser;password=testpassword
     
 
     The pooling implementations require some additional
-      configuration properties:
+      configuration properties, which are shown in .
 
-    >
-    Additional Pooling <span class="marked">DataSource</span> Configuration Properties
+   >
+    Additional Pooling <span class="marked"><classname>DataSource</></span> Configuration Properties
   
     
      
@@ -2810,22 +2809,22 @@ serverName=localhost;databaseName=test;user=testuser;password=testpassword
  
      
       
-       dataSourceName
-       <literal>String>
+       dataSourceName
+       <type>String>
        Every pooling DataSource must have a
-    unique name
+    unique name.
       
  
       
-       initialConnections
-       <literal>int>
+       initialConnections
+       <type>int>
        The number of database connections to be created
    when the pool is initialized.
       
  
       
-       maxConnections
-       <literal>int>
+       maxConnections
+       <type>int>
        The maximum number of open database connections to
    allow.  When more connections are requested, the caller
    will hang until a connection is returned to the pool.
@@ -2834,14 +2833,14 @@ serverName=localhost;databaseName=test;user=testuser;password=testpassword
     
     
 
-    Here's an example of typical application code using a
-     pooling DataSource:
+     shows an example of typical application code using a
+     pooling DataSource.
  
-   code">
+   example">
     <literal>DataSource</literal> Code Example
 
     
-     Code to initialize a pooling DataSource might look like this:
+     Code to initialize a pooling DataSource might look like this:
 
 Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource();
 source.setDataSourceName("A Data Source");
@@ -2853,18 +2852,18 @@ source.setMaxConnections(10);
 
       Then code to use a connection from the pool might look
       like this.  Note that it is critical that the connections
-      are closed, or else the pool will "leak" connections, and
-      eventually lock all the clients out.
+      are eventually closed.  Else the pool will leak connections and
+      will eventually lock all the clients out.
 
 Connection con = null;
 try {
     con = source.getConnection();
     // use connection
-} catch(SQLException e) {
+} catch (SQLException e) {
     // log error
 } finally {
-    if(con != null) {
-        try {con.close();}catch(SQLException e) {}
+    if (con != null) {
+        try { con.close(); } catch (SQLException e) {}
     }
 }
 
@@ -2873,34 +2872,44 @@ try {
   
 
   
-    DataSources and <acronym>JNDI</acronym>
-    All the ConnectionPoolDataSource and
+    Data Sources and <acronym>JNDI</acronym>
+
+    
+     All the ConnectionPoolDataSource and
      DataSource implementations can be stored
-     in JNDI.  In the case of the non-pooling
+     in JNDI.  In the case of the nonpooling
      implementations, a new instance will be created every time the
      object is retrieved from JNDI, with the
-     same settings as the instance which was stored.  For the
+     same settings as the instance that was stored.  For the
      pooling implementations, the same instance will be retrieved
-     as long as it is available (e.g. not a different
+     as long as it is available (e.g., not a different
      JVM retrieving the pool from
      JNDI), or a new instance with the same
-     settings created otherwise.
-    In the application server environment, typically the
+     settings created otherwise.
+    
+
+    
+     In the application server environment, typically the
      application server's DataSource instance
      will be stored in JNDI, instead of the
      PostgreSQL
      ConnectionPoolDataSource implementation.
-     
-    In an application environment, the application may store
+    
+
+    
+     In an application environment, the application may store
      the DataSource in JNDI
      so that it doesn't have to make a reference to the
      DataSource available to all application
-     components that may need to use it:
+     components that may need to use it.  An example of this is
+     shown in .
+    
+
    
-    <<span class="marked">literal>DataSource</literal</span>> <acronym>JNDI</acronym> Code Example
+    <<span class="marked">classname>DataSource</classname</span>> <acronym>JNDI</acronym> Code Example
 
     
-     Application code to initialize a pooling DataSource and add
+     Application code to initialize a pooling DataSource and add
      it to JNDI might look like this:
 
 Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource();
@@ -2920,13 +2929,13 @@ try {
     DataSource source = (DataSource)new InitialContext().lookup("DataSource");
     con = source.getConnection();
     // use connection
-} catch(SQLException e) {
+} catch (SQLException e) {
     // log error
-} catch(NamingException e) {
+} catch (NamingException e) {
     // DataSource wasn't found in JNDI
 } finally {
-    if(con != null) {
-        try {con.close();}catch(SQLException e) {}
+    if (con != null) {
+        try { con.close(); } catch (SQLException e) {}
     }
 }
 
@@ -2934,30 +2943,25 @@ try {
    
   
 
-  
-    Specific Application Server Configurations
-    Configuration examples for specific application servers
-     will be included here.
-  
  
 
  
   Further Reading
 
   
-   If you have not yet read it, I'd advise you read the
+   If you have not yet read it, you are advised you read the
    JDBC API Documentation
-   (supplied with Sun's JDK), and the
+   (supplied with Sun's JDK) and the
    JDBC Specification.  Both are available from
    
-   url="http://java.sun.com/products/jdbc/index.html">http://java.sun.com/products/jdbc/index.html.
+   url="http://java.sun.com/products/jdbc/index.html">.
   
 
   
    
-   url="http://jdbc.postgresql.org">http://jdbc.postgresql.org
-   contains updated information not included in this document, and
-   also includes precompiled drivers.
+   url="http://jdbc.postgresql.org">
+   contains updated information not included in this chapter and
+   also offers precompiled drivers.
   
  
 
index b17892a4f669ab8ccdacf14ce625d76d8447591e..02d38bc53403442a5e665a54fe46ef02f8655835 100644 (file)
@@ -1,5 +1,5 @@
 
 
  
@@ -34,8 +34,8 @@ $Header: /cvsroot/pgsql/doc/src/sgml/plperl.sgml,v 2.18 2002/09/21 18:32:53 pete
   
    
     Users of source packages must specially enable the build of
-    PL/Perl during the installation process (refer to the installation
-    instructions for more information).  Users of binary packages
+    PL/Perl during the installation process.  (Refer to the installation
+    instructions for more information.)  Users of binary packages
     might find PL/Perl in a separate subpackage.
    
   
@@ -57,8 +57,12 @@ CREATE FUNCTION funcname (argument-types
    Arguments and results are handled as in any other Perl subroutine:
    Arguments are passed in @_, and a result value
    is returned with return or as the last expression
-   evaluated in the function.  For example, a function returning the
-   greater of two integer values could be defined as:
+   evaluated in the function.
+  
+
+  
+   For example, a function returning the greater of two integer values
+   could be defined as:
 
 
 CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS '
@@ -145,7 +149,7 @@ SELECT name, empcomp(employee) FROM employee;
   Data Values in PL/Perl
 
   
-   The argument values supplied to a PL/Perl function's script are
+   The argument values supplied to a PL/Perl function's code are
    simply the input arguments converted to text form (just as if they
    had been displayed by a SELECT statement).
    Conversely, the return command will accept any string
@@ -206,8 +210,8 @@ SELECT name, empcomp(employee) FROM employee;
    environment. This includes file handle operations,
    require, and use (for
    external modules).  There is no way to access internals of the
-   database backend process or to gain OS-level access with the
-   permissions of the PostgreSQL user ID,
+   database server process or to gain OS-level access with the
+   permissions of the server process,
    as a C function can do.  Thus, any unprivileged database user may
    be permitted to use this language.
   
@@ -227,7 +231,7 @@ CREATE FUNCTION badfunc() RETURNS integer AS '
 
   
    Sometimes it is desirable to write Perl functions that are not
-   restricted --- for example, one might want a Perl function that
+   restricted.  For example, one might want a Perl function that
    sends mail.  To handle these cases, PL/Perl can also be installed
    as an untrusted language (usually called
    PL/PerlU).  In this case the full Perl language is
@@ -255,7 +259,7 @@ CREATE FUNCTION badfunc() RETURNS integer AS '
 
   
    The following features are currently missing from PL/Perl, but they
-   would make welcome contributions:
+   would make welcome contributions.
 
    
     
index 84862b041d11c126026c72965c982a7446189035..38306e100b2d15b09d31a1e27418a9066eae7789 100644 (file)
@@ -1,5 +1,5 @@
 
 
  
@@ -10,22 +10,11 @@ $Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.16 2003/03/25 16:15:37 pet
  
 
  
-  PL/pgSQL is a loadable procedural language for the
-  PostgreSQL database system.
-   
-  This package was originally written by Jan Wieck. This
-  documentation was in part written 
-  by Roberto Mello ([email protected]).
+  PL/pgSQL is a loadable procedural
+  language for the PostgreSQL database
+  system.  The design goals of PL/pgSQL were to create
+  a loadable procedural language that
 
-  
-   Overview
-
-   
-    The design goals of PL/pgSQL were to create a loadable procedural
-    language that
     
      
       
@@ -44,7 +33,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.16 2003/03/25 16:15:37 pet
      
      
       
-       inherits all user defined types, functions and operators,
+       inherits all user-defined types, functions, and operators,
       
      
      
@@ -59,57 +48,61 @@ $Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.16 2003/03/25 16:15:37 pet
      
     
    
+
+  
+   Overview
+
    
     The PL/pgSQL call handler parses the function's source text and
     produces an internal binary instruction tree the first time the
-    function is called (within any one backend process).  The instruction tree
+    function is called (within each session).  The instruction tree
     fully translates the 
     PL/pgSQL statement structure, but individual
-    SQL expressions and SQL queries
+    SQL expressions and SQL commands
     used in the function are not translated immediately.
    
 
    
-    As each expression and SQL query is first used
+    As each expression and SQL command is first used
    in the function, the PL/pgSQL interpreter creates
    a prepared execution plan (using the SPI
    manager's SPI_prepare and
    SPI_saveplan functions).  Subsequent visits
-   to that expression or query re-use the prepared plan.  Thus, a
+   to that expression or command reuse the prepared plan.  Thus, a
    function with conditional code that contains many statements for
    which execution plans might be required will only prepare and save
    those plans that are really used during the lifetime of the
    database connection.  This can substantially reduce the total
-   amount of time required to parse, and generate query plans for the
-   statements in a procedural language function. A disadvantage is
-   that errors in a specific expression or query may not be detected
+   amount of time required to parse, and generate execution plans for the
+   statements in a PL/pgSQL function. A disadvantage is
+   that errors in a specific expression or command may not be detected
    until that part of the function is reached in execution.
    
 
    
-    Once PL/pgSQL has made a query plan for a particular
-    query in a function, it will re-use that plan for the life of the
+    Once PL/pgSQL has made an execution plan for a particular
+    command in a function, it will reuse that plan for the life of the
     database connection.  This is usually a win for performance, but it
     can cause some problems if you dynamically
     alter your database schema. For example:
 
 
-CREATE FUNCTION populate() RETURNS INTEGER AS '
+CREATE FUNCTION populate() RETURNS integer AS '
 DECLARE
-    -- Declarations
+    -- declarations
 BEGIN
     PERFORM my_function();
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
 
     If you execute the above function, it will reference the OID for
-    my_function() in the query plan produced for
+    my_function() in the execution plan produced for
     the PERFORM statement. Later, if you
-    drop and re-create my_function(), then
+    drop and recreate my_function(), then
     populate() will not be able to find
     my_function() anymore. You would then have to
-    re-create populate(), or at least start a new
+    recreate populate(), or at least start a new
     database session so that it will be compiled afresh. Another way
     to avoid this problem is to use CREATE OR REPLACE
     FUNCTION when updating the definition of
@@ -119,13 +112,13 @@ END;
 
    
     Because PL/pgSQL saves execution plans
-   in this way, queries that appear directly in a
+   in this way, SQL commands that appear directly in a
    PL/pgSQL function must refer to the
-   same tables and fields on every execution; that is, you cannot use
-   a parameter as the name of a table or field in a query.  To get
-   around this restriction, you can construct dynamic queries using
+   same tables and columns on every execution; that is, you cannot use
+   a parameter as the name of a table or column in an SQL command.  To get
+   around this restriction, you can construct dynamic commands using
    the PL/pgSQL EXECUTE
-   statement --- at the price of constructing a new query plan on
+   statement --- at the price of constructing a new execution plan on
    every execution.
    
 
@@ -134,7 +127,7 @@ END;
     The PL/pgSQL
     EXECUTE statement is not related to the
     EXECUTE statement supported by the
-    PostgreSQL backend. The backend
+    PostgreSQL server. The server's
     EXECUTE statement cannot be used within
     PL/pgSQL functions (and is not needed).
    
@@ -142,50 +135,27 @@ END;
 
    
     Except for input/output conversion and calculation functions
-    for user defined types, anything that can be defined in C language
-    functions can also be done with PL/pgSQLIt is possible to
+    for user-defined types, anything that can be defined in C language
+    functions can also be done with PL/pgSQLFor example, it is possible to
     create complex conditional computation functions and later use
     them to define operators or use them in functional indexes.
    
+
   
    Advantages of Using <application>PL/pgSQL</application>
 
-   
-    
-     
-      Better performance (see )
-     
-    
-
-    
-     
-      SQL support (see )
-     
-     
-
-    
-     
-      Portability (see )
-     
-    
-   
-
-   
-    Better Performance
-
     
-     SQL is the language
-     PostgreSQL (and most other relational databases)
-     use as query language. It's portable and easy to learn. But
-     every SQL statement must be executed
-     individually by the database server.
+     SQL is the language PostgreSQL
+     (and most other relational databases) use as query language. It's
+     portable and easy to learn. But every SQL
+     statement must be executed individually by the database server.
     
 
     
      That means that your client application must send each query to
      the database server, wait for it to process it, receive the
      results, do some computation, then send other queries to the
-     server. All this incurs inter-process communication and may also
+     server. All this incurs interprocess communication and may also
      incur network overhead if your client is on a different machine
      than the database server.
     
@@ -199,51 +169,29 @@ END;
      communication overhead. This can make for a
      considerable performance increase.
     
-   
-
-   
-    SQL Support
-
-    
-     PL/pgSQL adds the power of a procedural language to the
-     flexibility and ease of SQL. With
-     PL/pgSQL you can use all the data types, columns, operators
-     and functions of SQL.    
-    
-   
-
-   
-    Portability
 
     
-     Because PL/pgSQL functions run inside
-     PostgreSQL, these functions will run on any
-     platform where PostgreSQL runs. Thus you can
-     reuse code and reduce development costs.
+     Also, with PL/pgSQL you can use all
+     the data types, operators and functions of SQL.
     
-   
   
 
   
    Developing in <application>PL/pgSQL</application>
 
    
-    Developing in PL/pgSQL is pretty
-    straight forward, especially if you have developed in other
-    database procedural languages, such as Oracle's
-    PL/SQL.  One good way to develop in
+    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 window, use
-    psql (PostgreSQL's interactive
-    monitor) to load those functions. If you are doing it this way, it
+    psql to load those functions. If you are doing it this way, it
     is a good idea to write the function using CREATE OR
     REPLACE FUNCTION. That way you can reload the file to update
     the function definition.  For example:
 
-CREATE OR REPLACE FUNCTION testfunc(INTEGER) RETURNS INTEGER AS '
+CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS '
      ....
 end;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
    
 
@@ -251,7 +199,7 @@ end;
     While running psql, you can load or reload such a
     function definition file with
 
-    \i filename.sql
+\i filename.sql
 
     and then immediately issue SQL commands to test the function.
    
@@ -261,22 +209,123 @@ end;
     GUI database access tool that facilitates development in a
     procedural language. One example of such as a tool is
     PgAccess, although others exist. These tools often
-    provide convenient features such as escaping single-quotes, and
+    provide convenient features such as escaping single quotes and
     making it easier to recreate and debug functions.
    
   
  
 
+  Handling of Quotations Marks
+
+  
+   Since the code of any procedural language function is specified
+   CREATE FUNCTION as a string literal, single
+   quotes inside the function body must be escaped. This can lead to
+   rather complicated code at times, especially if you are writing a
+   function that generates other functions, as in the example in 
+   linkend="plpgsql-statements-executing-dyn">.  The list below gives
+   you an overview over the needed levels of quotation marks in
+   various situations.  Keep this chart handy.
+  
+
+  
+   
+    1 quotation mark
+    
+     
+      To begin/end function bodies, for example:
+
+CREATE FUNCTION foo() RETURNS integer AS '...'
+    LANGUAGE plpgsql;
+
+     
+    
+   
+
+   
+    2 quotation marks
+    
+     
+      For string literals inside the function body, for example:
+
+a_output := ''Blah'';
+SELECT * FROM users WHERE f_name=''foobar'';
+
+      The second line is interpreted as
+
+SELECT * FROM users WHERE f_name='foobar';
+
+     
+    
+   
+
+   
+    4 quotation marks
+    
+     
+      When you need a single quote in a string inside the function
+      body, for example:
+
+a_output := a_output || '' AND name LIKE ''''foobar'''' AND xyz''
+
+      The value of a_output would then be: 
+      AND name LIKE 'foobar' AND xyz.
+     
+    
+   
+
+   
+    6 quotation marks
+    
+     
+      When a single quote in a string inside the function body is
+      adjacent to the end of that string constant, for example:
+
+a_output := a_output || '' AND name LIKE ''''foobar''''''
+
+      The value of a_output would then be:
+       AND name LIKE 'foobar'.
+     
+    
+   
+
+   
+    10 quotation marks
+    
+     
+      When you want two single quotes in a string constant (which
+      accounts for 8 quotes) and this is adjacent to the end of that
+      string constant (2 more).  You will probably only need that if
+      you are writing a function that generates other functions.  For
+      example:
+
+a_output := a_output || '' if v_'' || 
+    referrer_keys.kind || '' like '''''''''' 
+    || referrer_keys.key_string || '''''''''' 
+    then return ''''''  || referrer_keys.referrer_type 
+    || ''''''; end if;''; 
+
+      The value of a_output would then be:
+
+if v_... like ''...'' then return ''...''; end if;
+
+     
+    
+   
+  
+
  
   Structure of <application>PL/pgSQL</application>
 
-    
-     PL/pgSQL is a block
-     structured language.  The complete text of a function
-     definition must be a block. A block is defined as:
+  
+   PL/pgSQL is a block-structured language.
+   The complete text of a function definition must be a
+   block. A block is defined as:
 
 
- <<label>> 
+ <<label>> 
  DECLARE
     declarations 
 BEGIN
@@ -286,8 +335,28 @@ END;
     
 
     
-     Any statement in the statement section of a block
-     can be a sub-block.  Sub-blocks can be used for
+     Each declaration and each statement within a block is terminated
+     by a semicolon.
+    
+
+    
+     All key words and identifiers can be written in mixed upper and
+     lower case.  Identifiers are implicitly converted to lower-case
+     unless double-quoted.
+    
+
+    
+     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 occurrence of */.
+     Block comments cannot be nested, but double dash comments can be
+     enclosed into a block comment and a double dash can hide
+     the block comment delimiters /* and */.
+    
+
+    
+     Any statement in the statement section of a block
+     can be a subblock.  Subblocks can be used for
      logical grouping or to localize variables to a small group
      of statements.
     
@@ -297,89 +366,65 @@ END;
      block are initialized to their default values every time the
      block is entered, not only once per function call. For example:
 
-CREATE FUNCTION somefunc() RETURNS INTEGER AS '
+CREATE FUNCTION somefunc() RETURNS integer AS '
 DECLARE
-   quantity INTEGER := 30;
+    quantity integer := 30;
 BEGIN
-   RAISE NOTICE ''Quantity here is %'',quantity;  -- Quantity here is 30
-   quantity := 50;
-   --
-   -- Create a sub-block
-   --
-   DECLARE
-      quantity INTEGER := 80;
-   BEGIN
-      RAISE NOTICE ''Quantity here is %'',quantity;  -- Quantity here is 80
-   END;
-
-   RAISE NOTICE ''Quantity here is %'',quantity;  -- Quantity here is 50
-
-   RETURN quantity;
+    RAISE NOTICE ''Quantity here is %'', quantity;  -- Quantity here is 30
+    quantity := 50;
+    --
+    -- Create a subblock
+    --
+    DECLARE
+        quantity integer := 80;
+    BEGIN
+        RAISE NOTICE ''Quantity here is %'', quantity;  -- Quantity here is 80
+    END;
+
+    RAISE NOTICE ''Quantity here is %'', quantity;  -- Quantity here is 50
+
+    RETURN quantity;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
     
 
     
-     It is important not to confuse the use of BEGIN/END for
+     It is important not to confuse the use of BEGIN/END for
      grouping statements in PL/pgSQL with the database commands for
-     transaction control.  PL/pgSQL's BEGIN/END are only for grouping;
+     transaction control.  PL/pgSQL's BEGIN/END are only for grouping;
      they do not start or end a transaction.  Functions and trigger procedures
      are always executed within a transaction established by an outer query
      --- they cannot start or commit transactions, since
      PostgreSQL does not have nested transactions.
     
-
-   
-    Lexical Details
-
-    
-     Each statement and declaration within a block is terminated
-     by a semicolon.
-    
-
-    
-     All keywords and identifiers can be written in mixed upper- and
-     lower-case.  Identifiers are implicitly converted to lower-case
-     unless double-quoted.
-    
-
-    
-     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 occurrence of */.
-     Block comments cannot be nested, but double dash comments can be
-     enclosed into a block comment and a double dash can hide
-     the block comment delimiters /* and */.
-    
-   
   
 
   
     Declarations
 
     
-     All variables, rows and records used in a block must be declared in the
+     All variables used in a block must be declared in the
      declarations section of the block. 
-     (The only exception is that the loop variable of a FOR loop iterating
+     (The only exception is that the loop variable of a FOR loop iterating
      over a range of integer values is automatically declared as an integer
      variable.)
     
 
     
      PL/pgSQL variables can have any SQL data type, such as
-     INTEGERVARCHAR and
-     CHAR.
+     integervarchar, and
+     char.
     
 
     
      Here are some examples of variable declarations:
 
-user_id INTEGER;
-quantity NUMERIC(5);
-url VARCHAR;
+user_id integer;
+quantity numeric(5);
+url varchar;
 myrow tablename%ROWTYPE;
-myfield tablename.fieldname%TYPE;
+myfield tablename.columnname%TYPE;
 arow RECORD;
 
     
@@ -389,104 +434,125 @@ arow RECORD;
 
 name  CONSTANT  type  NOT NULL   { DEFAULT | := } expression ;
 
-     
-
-     
-      The DEFAULT clause, if given, specifies the initial value assigned
-      to the variable when the block is entered.  If the DEFAULT clause
+      The DEFAULT clause, if given, specifies the initial value assigned
+      to the variable when the block is entered.  If the DEFAULT clause
       is not given then the variable is initialized to the
-     SQL NULL value. 
-     
-
-     
-      The CONSTANT option prevents the variable from being assigned to,
+      SQL null value. 
+      The CONSTANT option prevents the variable from being assigned to,
       so that its value remains constant for the duration of the block.
-      If NOT NULL
-      is specified, an assignment of a NULL value results in a run-time
-      error. All variables declared as NOT NULL
-      must have a non-NULL default value specified.
+      If NOT NULL
+      is specified, an assignment of a null value results in a run-time
+      error. All variables declared as NOT NULL
+      must have a nonnull default value specified.
      
 
      
       The default value is evaluated every time the block is entered. So,
-      for example, assigning 'now' to a variable of type
+      for example, assigning 'now' to a variable of type
       timestamp causes the variable to have the
-      time of the current function call, not when the function was
+      time of the current function call, not the time when the function was
       precompiled.
      
 
      
       Examples:
 
-quantity INTEGER DEFAULT 32;
+quantity integer DEFAULT 32;
 url varchar := ''http://mysite.com'';
-user_id CONSTANT INTEGER := 10;
+user_id CONSTANT integer := 10;
 
      
 
     
      Aliases for Function Parameters
 
-    
 
-name ALIAS FOR $n;
+name ALIAS FOR $n;
 
-    
 
      
       Parameters passed to functions are named with the identifiers
       $1$2,
-      etc.  Optionally, aliases can be declared for $n
+      etc.  Optionally, aliases can be declared for $n
       parameter names for increased readability.  Either the alias or the
       numeric identifier can then be used to refer to the parameter value.
       Some examples:
 
-CREATE FUNCTION sales_tax(REAL) RETURNS REAL AS '
+CREATE FUNCTION sales_tax(real) RETURNS real AS '
 DECLARE
     subtotal ALIAS FOR $1;
 BEGIN
-    return subtotal * 0.06;
+    RETURN subtotal * 0.06;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
 
-CREATE FUNCTION instr(VARCHAR,INTEGER) RETURNS INTEGER AS '
+CREATE FUNCTION instr(varchar, integer) RETURNS integer AS '
 DECLARE
     v_string ALIAS FOR $1;
     index ALIAS FOR $2;
 BEGIN
-    -- Some computations here
+    -- some computations here
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
 
-CREATE FUNCTION use_many_fields(tablename) RETURNS TEXT AS '
+CREATE FUNCTION use_many_fields(tablename) RETURNS text AS '
 DECLARE
     in_t ALIAS FOR $1;
 BEGIN
     RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
      
     
 
+  
+   Copying Types
+
+
+variable%TYPE
+
+
+   
+    %TYPE provides the data type of a variable or
+    table column. You can use this to declare variables that will hold
+    database values. For example, let's say you have a column named
+    user_id in your users
+    table. To declare a variable with the same data type as
+    users.user_id you write:
+
+user_id users.user_id%TYPE;
+
+   
+
+   
+    By using %TYPE you don't need to know the data
+    type of the structure you are referencing, and most importantly,
+    if the data type of the referenced item changes in the future (for
+    instance: you change the type of user_id
+    from integer to real), you may not need
+    to change your function definition.
+   
+  
+
     
      Row Types
 
-    
 
 name tablename%ROWTYPE;
 
-    
 
    
     A variable of a composite type is called a row
-    variable (or row-type variable).  Such a variable can hold a
-    whole row of a SELECT or FOR
-    query result, so long as that query's column set matches the declared
-    type of the variable.  The individual fields of the row value are
-    accessed using the usual dot notation, for example
+    variable (or row-type variable).  Such a variable
+    can hold a whole row of a SELECT or FOR
+    query result, so long as that query's column set matches the
+    declared type of the variable.
+    tablename must be an existing table or
+    view name in the database. The individual fields of the row value
+    are accessed using the usual dot notation, for example
     rowvar.field.
    
 
@@ -500,18 +566,22 @@ END;
    
     Parameters to a function can be
     composite types (complete table rows). In that case, the
-    corresponding identifier $n will be a row variable, and fields can
+    corresponding identifier $n will be a row variable, and fields can
     be selected from it, for example $1.user_id.
    
 
    
-    Only the user-defined attributes of a table row are accessible in a
-    row-type variable, not OID or other system attributes (because the
+    Only the user-defined columns of a table row are accessible in a
+    row-type variable, not the OID or other system columns (because the
     row could be from a view).  The fields of the row type inherit the
     table's field size or precision for data types such as
-    char(n).
+    char(n).
+   
+
+   
+    Here is an example of using composite types:
 
-CREATE FUNCTION use_two_tables(tablename) RETURNS TEXT AS '
+CREATE FUNCTION use_two_tables(tablename) RETURNS text AS '
 DECLARE
     in_t ALIAS FOR $1;
     use_t table2name%ROWTYPE;
@@ -519,13 +589,13 @@ BEGIN
     SELECT * INTO use_t FROM table2name WHERE ... ;
     RETURN in_t.f1 || use_t.f3 || in_t.f5 || use_t.f7;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
    
   
 
     
-     Records
+     Record<span class="marked"> Type</span>s
 
     
 
@@ -536,10 +606,10 @@ END;
    
     Record variables are similar to row-type variables, but they have no
     predefined structure.  They take on the actual row structure of the
-    row they are assigned during a SELECT or FOR command.  The substructure
+    row they are assigned during a SELECT or FOR command.  The substructure
     of a record variable can change each time it is assigned to.
     A consequence of this is that until a record variable is first assigned
-    to, it has no substructure, and any attempt to access a
+    to, it has no substructure, and any attempt to access a
     field in it will draw a run-time error.
    
 
@@ -548,89 +618,8 @@ END;
    
   
 
-    
-     Attributes
-
-     
-      Using the %TYPE and %ROWTYPE
-      attributes, you can declare variables with the same
-      data type or structure as another database item (e.g: a
-      table field).
-     
-
-     
-      
-       
-        variable%TYPE
-       
-       
-        
-         %TYPE provides the data type of a
-         variable or database column. You can use this to
-         declare variables that will hold database
-         values. For example, let's say you have a column
-         named user_id in your
-         users table. To declare a variable with
-         the same data type as users.user_id you write:
-
-user_id   users.user_id%TYPE;
-
-        
-
-        
-         By using %TYPE you do not need to know
-         the data type of the structure you are referencing,
-         and most important, if the data type of the
-         referenced item changes in the future (e.g: you
-         change your table definition of user_id from INTEGER to
-         REAL), you may not need to change your function
-         definition.
-        
-       
-      
-
-      
-       
-        table%ROWTYPE
-       
-       
-        
-    %ROWTYPE provides the composite data type corresponding
-    to a whole row of the specified table.
-    table must be an existing
-    table or view name of the database.
-        
-
-
-DECLARE
-    users_rec users%ROWTYPE;
-    user_id users.user_id%TYPE;
-BEGIN
-    user_id := users_rec.user_id;
-    ...
-
-CREATE FUNCTION does_view_exist(INTEGER) RETURNS bool AS '
-   DECLARE
-        key ALIAS FOR $1;
-        table_data cs_materialized_views%ROWTYPE;
-   BEGIN
-        SELECT INTO table_data * FROM cs_materialized_views
-               WHERE sort_key=key;
-
-        IF NOT FOUND THEN
-           RETURN false;
-        END IF;
-        RETURN true;
-   END;
-' LANGUAGE 'plpgsql';
-
-       
-      
-     
-    
-
     
-     <span class="marked">RENAME</span>
+     <span class="marked"><literal>RENAME</></span>
 
      
 
@@ -669,20 +658,20 @@ RENAME this_var TO that_var;
      statements are processed using the server's regular
      SQL executor. Expressions that appear to
      contain constants may in fact require run-time evaluation
-     (e.g. 'now' for the timestamp
+     (e.g., 'now' for the timestamp
      type) so it is impossible for the
      PL/pgSQL parser to identify real
-     constant values other than the NULL keyword. All expressions are
+     constant values other than the key word NULL. All expressions are
      evaluated internally by executing a query
 
 SELECT expression
 
-     using the SPI manager. In the expression,
+     using the SPI manager. For evaluation,
      occurrences of PL/pgSQL variable
-     identifiers are replaced by parameters and the actual values from
+     identifiers are replaced by parameters, and the actual values from
      the variables are passed to the executor in the parameter array.
      This allows the query plan for the SELECT to
-     be prepared just once and then re-used for subsequent
+     be prepared just once and then reused for subsequent
      evaluations.
     
 
@@ -693,20 +682,20 @@ SELECT expression
      is a difference between what these two functions do:
 
 
-CREATE FUNCTION logfunc1 (TEXT) RETURNS TIMESTAMP AS '
+CREATE FUNCTION logfunc1(text) RETURNS timestamp AS '
     DECLARE
         logtxt ALIAS FOR $1;
     BEGIN
         INSERT INTO logtable VALUES (logtxt, ''now'');
         RETURN ''now'';
     END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
 
      and
 
 
-CREATE FUNCTION logfunc2 (TEXT) RETURNS TIMESTAMP AS '
+CREATE FUNCTION logfunc2(text) RETURNS timestamp AS '
     DECLARE
         logtxt ALIAS FOR $1;
         curtime timestamp;
@@ -715,31 +704,33 @@ CREATE FUNCTION logfunc2 (TEXT) RETURNS TIMESTAMP AS '
         INSERT INTO logtable VALUES (logtxt, curtime);
         RETURN curtime;
     END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
+    
 
-     In the case of logfunc1(), the 
+    
+     In the case of logfunc1, the 
      PostgreSQL main parser knows when 
-     preparing the plan for the INSERT, that the string 
+     preparing the plan for the INSERT, that the string 
      'now' should be interpreted as 
-     timestamp because the target field of logtable
+     timestamp because the target column of logtable
      is of that type. Thus, it will make a constant from it at this
      time and this constant value is then used in all invocations of 
-     logfunc1() during the lifetime of the
-     backend. Needless to say that this isn't what the
+     logfunc1 during the lifetime of the
+     session. Needless to say that this isn't what the
      programmer wanted.
     
 
     
-     In the case of logfunc2(), the 
+     In the case of logfunc2, the 
      PostgreSQL main parser does not know
      what type 'now' should become and therefore 
      it returns a data value of type text containing the string 
-     'now'. During the ensuing assignment
+     now. During the ensuing assignment
      to the local variable curtime, the
      PL/pgSQL interpreter casts this
      string to the timestamp type by calling the
-     text_out() and timestamp_in()
+     text_out and timestamp_in
      functions for the conversion.  So, the computed time stamp is updated
      on each execution as the programmer expects.
     
@@ -765,12 +756,12 @@ CREATE FUNCTION logfunc2 (TEXT) RETURNS TIMESTAMP AS '
     types that are explicitly understood by
     PL/pgSQL.
     Anything not recognized as one of these statement types is presumed
-    to be an SQL query, and is sent to the main database engine to execute
-    (after substitution for any PL/pgSQL variables
+    to be an SQL command and is sent to the main database engine to execute
+    (after substitution of any PL/pgSQL variables
     used in the statement).  Thus,
-    for example, SQL INSERT, UPDATE, and
-    DELETE commands may be considered to be statements of
-    PL/pgSQL.  But they are not specifically
+    for example, the SQL commands INSERT, UPDATE, and
+    DELETE may be considered to be statements of
+    PL/pgSQL, but they are not specifically
     listed here.
    
    
@@ -809,10 +800,10 @@ tax := subtotal * 0.06;
    
 
    
-    <span class="marked">SELECT INTO</span>
+    <span class="marked"><command>SELECT INTO</command></span>
 
     
-     The result of a SELECT command yielding multiple columns (but
+     The result of a SELECT command yielding multiple columns (but
      only one row) can be assigned to a record variable, row-type
      variable, or list of scalar variables.  This is done by:
 
@@ -822,60 +813,67 @@ SELECT INTO target expressions
 
      where target can be a record variable, a row
      variable, or a comma-separated list of simple variables and
-     record/row fields. Note that this is quite different from
-     PostgreSQL's normal interpretation of SELECT INTO, which is that the
-     INTO target is a newly created table.  (If you want to create a
-     table from a SELECT result inside a PL/pgSQL function, use the
-     syntax CREATE TABLE ... AS SELECT.)
+     record/row fields.
+    
+
+    
+     Note that this is quite different from
+     PostgreSQL's normal interpretation of
+     SELECT INTO, where the INTO target
+     is a newly created table.  If you want to create a table from a
+     SELECT result inside a
+     PL/pgSQL function, use the syntax
+     CREATE TABLE ... AS SELECT.
     
 
     
      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 run-time error
+     must exactly match the structure of the target, or a run-time error
      occurs.  When a record variable is the target, it automatically
      configures itself to the row type of the query result columns.
     
 
     
-     Except for the INTO clause, the SELECT statement is the same as a normal
-     SQL SELECT query and can use the full power of SELECT.
+     Except for the INTO clause, the SELECT
+     statement is the same as a normal SQL SELECT command
+     and can use its full power.
     
 
     
-     If the SELECT query returns zero rows, null values are assigned to the
-     target(s).  If the SELECT query returns multiple rows, the first
+     If the query returns zero rows, null values are assigned to the
+     target(s).  If the query returns multiple rows, the first
      row is assigned to the target(s) and the rest are discarded.
      (Note that the first row is not well-defined unless you've
-     used ORDER BY.)
+     used ORDER BY.)
     
 
     
-     At present, the INTO clause can appear almost anywhere in the SELECT
-     query, but it is recommended to place it immediately after the SELECT
-     keyword as depicted above.  Future versions of
+     At present, the INTO clause can appear almost anywhere in the SELECT
+     statement, but it is recommended to place it immediately after the SELECT
+     key word as depicted above.  Future versions of
      PL/pgSQL may be less forgiving about
-     placement of the INTO clause.
+     placement of the INTO clause.
     
 
     
-     You can use FOUND immediately after a SELECT
-     INTO statement to determine whether the assignment was successful
-     (that is, at least one row was was returned by the SELECT
-     statement). For example:
+     You can use FOUND immediately after a SELECT
+     INTO statement to determine whether the assignment was successful
+     (that is, at least one row was was returned by the query). For example:
   
 
-SELECT INTO myrec * FROM EMP WHERE empname = myname;
+SELECT INTO myrec * FROM emp WHERE empname = myname;
 IF NOT FOUND THEN
     RAISE EXCEPTION ''employee % not found'', myname;
 END IF;
 
-
-     Alternatively, you can use the IS NULL (or ISNULL) conditional to
-     test for whether a RECORD/ROW result is null.  Note that there is no
-     way to tell whether any additional rows might have been discarded.
     
 
     
+     To test for whether a record/row result is null, you can use the
+     IS NULL conditional.  There is, however, no
+     way to tell whether any additional rows might have been
+     discarded.  Here is an example that handles the case where no
+     rows have been returned:
 
 DECLARE
     users_rec RECORD;
@@ -885,7 +883,6 @@ BEGIN
 
     IF users_rec.homepage IS NULL THEN
         -- user entered no homepage, return "http://"
-
         RETURN ''http://'';
     END IF;
 END;
@@ -894,7 +891,7 @@ END;
    
 
    
-    Executing an <span class="marked">expression or query with no r</span>esult
+    Executing an <span class="marked">Expression or Query With No R</span>esult
 
     
      Sometimes one wishes to evaluate an expression or query but
@@ -907,21 +904,22 @@ END;
 PERFORM query;
 
 
-     This executes SELECT
-     <replaceable>query and discards the
+     This executes query, which must be a
+     <command>SELECT statement, and discards the
      result. PL/pgSQL variables are
      substituted in the query as usual.  Also, the special variable
      FOUND is set to true if the query produced at
-     least one row, or false if it produced no rows.
+     least one row or false if it produced no rows.
     
 
     
-    
-     One might expect that SELECT with no INTO
-     clause would accomplish this result, but at present the only
-     accepted way to do it is PERFORM.
-    
-   
+     
+      One might expect that SELECT with no
+      INTO clause would accomplish this result, but at
+      present the only accepted way to do it is
+      PERFORM.
+     
+    
 
     
      An example:
@@ -931,109 +929,103 @@ PERFORM create_mv(''cs_session_page_requests_mv'', my_query);
     
    
    
-   -queries">
-    Executing <span class="marked">dynamic querie</span>s
+   
+    Executing <span class="marked">Dynamic Command</span>s
     
     
-     Oftentimes you will want to generate dynamic queries inside your
-     PL/pgSQL functions, that is, queries
+     Oftentimes you will want to generate dynamic commands inside your
+     PL/pgSQL functions, that is, commands
      that will involve different tables or different data types each
      time they are executed.  PL/pgSQL's
-     normal attempts to cache plans for queries will not work in such
+     normal attempts to cache plans for commands will not work in such
      scenarios.  To handle this sort of problem, the
      EXECUTE statement is provided:
 
 
-EXECUTE query-string;
+EXECUTE command-string;
 
 
-     where query-string is an expression
+     where command-string is an expression
      yielding a string (of type
-     text) containing the query
+     text) containing the command
      to be executed.  This string is fed literally to the SQL engine.
     
 
     
      Note in particular that no substitution of PL/pgSQL
-     variables is done on the query string.  The values of variables must
-     be inserted in the query string as it is constructed.
+     variables is done on the command string.  The values of variables must
+     be inserted in the command string as it is constructed.
     
 
     
-    When working with dynamic queries you will have to face
+    When working with dynamic commands you will have to face
     escaping of single quotes in PL/pgSQL. Please refer to the
-    table in 
-    for a detailed explanation that will save you some effort.
+    overview in ,
+    which can save you some effort.
     
      
     
-     Unlike all other queries in PL/pgSQL, a
-     query run by an
-     EXECUTE statement is not prepared and saved
-     just once during the life of the server.  Instead, the
-     query is prepared each time the
-     statement is run. The query-string can
-     be dynamically created within the procedure to perform actions on
-     variable tables and fields.
+     Unlike all other commands in PL/pgSQL, a command
+     run by an EXECUTE statement is not prepared
+     and saved just once during the life of the session.  Instead, the
+     command is prepared each time the statement is run. The command
+     string can be dynamically created within the function to perform
+     actions on variable tables and columns.
     
   
     
-     The results from SELECT queries are discarded
+     The results from SELECT commands are discarded
      by EXECUTE, and SELECT INTO
      is not currently supported within EXECUTE.
      So, the only way to extract a result from a dynamically-created
-     SELECT is to use the FOR-IN-EXECUTE form
+     SELECT is to use the FOR-IN-EXECUTE form
      described later.
     
 
     
      An example:
-
 
 EXECUTE ''UPDATE tbl SET ''
-        || quote_ident(fieldname)
+        || quote_ident(colname)
         || '' = ''
         || quote_literal(newvalue)
         || '' WHERE ...'';
 
-
     
 
     
      This example shows use of the functions
-     quote_ident(TEXT) and
-     quote_literal(TEXT).
-     Variables containing field and table identifiers should be
-     passed to function quote_ident().
-     Variables containing literal elements of the dynamic query
+     quote_ident(text) and
+     quote_literal(text).
+     Variables containing column and table identifiers should be
+     passed to function quote_ident.
+     Variables containing values that act as value literals in the constructed command
      string should be passed to
-     quote_literal().  Both take the
+     quote_literal.  Both take the
      appropriate steps to return the input text enclosed in single
      or double quotes and with any embedded special characters
      properly escaped.
     
 
     
-     Here is a much larger example of a dynamic query and
+     Here is a much larger example of a dynamic command and
      EXECUTE:
 
-CREATE FUNCTION cs_update_referrer_type_proc() RETURNS INTEGER AS '
+CREATE FUNCTION cs_update_referrer_type_proc() RETURNS integer AS '
 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
     a_output varchar(4000);
 BEGIN 
-    a_output := ''CREATE FUNCTION cs_find_referrer_type(varchar,varchar,varchar) 
-                  RETURNS VARCHAR AS '''' 
+    a_output := ''CREATE FUNCTION cs_find_referrer_type(varchar, varchar, varchar) 
+                  RETURNS varchar AS '''' 
                      DECLARE 
                          v_host ALIAS FOR $1; 
                          v_domain ALIAS FOR $2; 
                          v_url ALIAS FOR $3;
                      BEGIN ''; 
 
-    -- 
     -- Notice how we scan through the results of a query in a FOR loop
     -- using the FOR <record> construct.
-    --
 
     FOR referrer_keys IN SELECT * FROM cs_referrer_keys ORDER BY try_order LOOP
         a_output := a_output || '' IF v_'' || referrer_keys.kind || '' LIKE '''''''''' 
@@ -1041,24 +1033,21 @@ BEGIN
                  || referrer_keys.referrer_type || ''''''; END IF;''; 
     END LOOP; 
   
-    a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE ''''plpgsql'''';''; 
+    a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE plpgsql;''; 
  
-    -- This works because we are not substituting any variables
-    -- Otherwise it would fail. Look at PERFORM for another way to run functions
-    
     EXECUTE a_output; 
 END; 
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
     
    
 
    
-    Obtaining <span class="marked">result s</span>tatus
+    Obtaining <span class="marked">the Result S</span>tatus
 
     
     There are several ways to determine the effect of a command. The
-    first method is to use the <literal>GET DIAGNOSTICS>,
+    first method is to use the <command>GET DIAGNOSTICS>,
     which has the form:
 
 
@@ -1066,26 +1055,27 @@ GET DIAGNOSTICS variable = item
 
 
      This command allows retrieval of system status indicators.  Each
-     item is a keyword identifying a state
+     item is a key word identifying a state
      value to be assigned to the specified variable (which should be
      of the right data type to receive it).  The currently available
      status items are ROW_COUNT, the number of rows
-     processed by the last SQL query sent down to
-     the SQL engine; and RESULT_OID,
+     processed by the last SQL command sent down to
+     the SQL engine, and RESULT_OID,
      the OID of the last row inserted by the most recent
-     SQL query.  Note that RESULT_OID
-     is only useful after an INSERT query.
+     SQL command.  Note that RESULT_OID
+     is only useful after an INSERT command.
     
+
     
-
+     An example:
 
-      GET DIAGNOSTICS var_integer = ROW_COUNT;
+GET DIAGNOSTICS var_integer = ROW_COUNT;
 
-
     
 
     
-     There is a special variable named FOUND of
+     The second method to determine the effects of a command is the
+     special variable named FOUND of
      type boolean.  FOUND starts out
      false within each PL/pgSQL function.
      It is set by each of the following types of statements:
@@ -1152,7 +1142,7 @@ GET DIAGNOSTICS variable = item
    
    
    
-    Returning <span class="marked">from a f</span>unction
+    Returning <span class="marked">From a F</span>unction
 
     
      There are two commands available that allow you to return data
@@ -1163,23 +1153,24 @@ GET DIAGNOSTICS variable = item
     
      <command>RETURN</>
 
-     
 
 RETURN expression;
 
 
-      RETURN with an expression is used to return
-      from a PL/pgSQL function that does not return a
-      set.  The function terminates and the value of
-      expression is returned to the caller.
+     
+      RETURN with an expression terminates the
+      function and returns the value of
+      expression to the caller.  This form
+      is to be used for PL/pgSQL functions that does
+      not return a set.
      
 
      
-      To return a composite (row) value, you must write a record or row
-      variable as the expression.  When
-      returning a scalar type, any expression can be used.
-      The expression's result will be automatically cast into the
-      function's return type as described for assignments.
+      When returning a scalar type, any expression can be used. The
+      expression's result will be automatically cast into the
+      function's return type as described for assignments. To return a
+      composite (row) value, you must write a record or row variable
+      as the expression.
      
 
      
@@ -1188,8 +1179,8 @@ RETURN expression;
       without hitting a RETURN statement, a run-time
       error will occur. Note that if you have declared the function to
       return void, a RETURN statement
-      must still be specified; however, the expression following
-      RETURN is optional, and will be ignored in
+      must still be specified; the expression following
+      RETURN is, however, optional and will be ignored in
       any case.
      
     
@@ -1203,7 +1194,7 @@ RETURN NEXT expression;
 
      
       When a PL/pgSQL function is declared to return
-      SETOF sometype>, the procedure
+      SETOF sometype>, the procedure
       to follow is slightly different.  In that case, the individual
       items to return are specified in RETURN NEXT
       commands, and then a final RETURN command
@@ -1211,6 +1202,9 @@ RETURN NEXT expression;
       finished executing.  RETURN NEXT can be used
       with both scalar and composite data types; in the later case, an
       entire table of results will be returned.
+     
+
+     
       Functions that use RETURN NEXT should be
       called in the following fashion:
 
@@ -1218,7 +1212,7 @@ RETURN NEXT expression;
 SELECT * FROM some_func();
 
 
-      That is, the function is used as a table source in a FROM
+      That is, the function is used as a table source in a FROM
       clause.
      
 
@@ -1233,11 +1227,6 @@ SELECT * FROM some_func();
       have no argument, causes control to exit the function.
      
 
-     
-      For more information on using set-returning functions in
-      PostgreSQL, refer to XXX.
-     
-
      
       
        The current implementation of RETURN NEXT
@@ -1251,7 +1240,7 @@ SELECT * FROM some_func();
        allow users to allow users to define set-returning functions
        that do not have this limitation.  Currently, the point at
        which data begins being written to disk is controlled by the
-       SORT_MEM configuration variable.  Administrators
+       sort_mem configuration variable.  Administrators
        who have sufficient memory to store larger result sets in
        memory should consider increasing this parameter.
       
@@ -1274,7 +1263,7 @@ SELECT * FROM some_func();
       IF ... THEN ... ELSE
      
      
-      IF ... THEN ... ELSE IF and
+      IF ... THEN ... ELSE IF
      
      
       IF ... THEN ... ELSIF ... THEN ... ELSE
@@ -1285,19 +1274,22 @@ SELECT * FROM some_func();
     
      <literal>IF-THEN</>
 
-       
 
 IF boolean-expression THEN
     statements
 END IF;
 
 
+       
         IF-THEN statements are the simplest form of
         IF. The statements between
         THEN and END IF will be
         executed if the condition is true. Otherwise, they are
         skipped.
+       
 
+       
+        Example:
 
 IF v_user_id <> 0 THEN
     UPDATE users SET email = v_email WHERE user_id = v_user_id;
@@ -1309,7 +1301,6 @@ END IF;
      
       <literal>IF-THEN-ELSE</>
 
-       
 
 IF boolean-expression THEN
     statements
@@ -1318,25 +1309,30 @@ ELSE
 END IF;
 
 
+       
         IF-THEN-ELSE statements add to
         IF-THEN by letting you specify an
         alternative set of statements that should be executed if the
-        condition evaluates to FALSE.
+        condition evaluates to false.
+       
 
+       
+        Examples:
 
-IF parentid IS NULL or parentid = ''''
-THEN 
-    return fullname;
+IF parentid IS NULL OR parentid = ''''
+THEN
+    RETURN fullname;
 ELSE
-    return hp_true_filename(parentid) || ''/'' || fullname;
+    RETURN hp_true_filename(parentid) || ''/'' || fullname;
 END IF;
+
 
-
+
 IF v_count > 0 THEN 
-    INSERT INTO users_count(count) VALUES(v_count);
-    return ''t'';
-ELSE 
-    return ''f'';
+    INSERT INTO users_count (count) VALUES (v_count);
+    RETURN ''t'';
+ELSE
+    RETURN ''f'';
 END IF;
 
      
@@ -1351,11 +1347,11 @@ END IF;
 
 
 IF demo_row.sex = ''m'' THEN
-  pretty_sex := ''man'';
+    pretty_sex := ''man'';
 ELSE
-  IF demo_row.sex = ''f'' THEN
-    pretty_sex := ''woman'';
-  END IF;
+    IF demo_row.sex = ''f'' THEN
+        pretty_sex := ''woman'';
+    END IF;
 END IF;
 
        
@@ -1365,16 +1361,16 @@ END IF;
         IF statement inside the
         ELSE part of an outer IF
         statement. Thus you need one END IF
-        statement for each nested IF and one for the parent
+        statement for each nested IF and one for the parent
         IF-ELSE.  This is workable but grows
         tedious when there are many alternatives to be checked.
+        Hence the next form.
        
      
 
      
       <literal>IF-THEN-ELSIF-ELSE</>
 
-       
 
 IF boolean-expression THEN
     statements
@@ -1390,6 +1386,7 @@ IF boolean-expression THEN
 END IF;
 
 
+       
         IF-THEN-ELSIF-ELSE provides a more convenient
         method of checking many alternatives in one statement.
         Formally it is equivalent to nested
@@ -1408,16 +1405,11 @@ ELSIF number > 0 THEN
 ELSIF number < 0 THEN
     result := ''negative'';
 ELSE
-    -- hmm, the only other possibility is that number IS NULL
+    -- hmm, the only other possibility is that number is null
     result := ''NULL'';
 END IF;
 
        
-
-       
-        The final ELSE statement is optional.
-       
-
      
    
 
@@ -1425,51 +1417,52 @@ END IF;
     Simple Loops
 
     
-     With the LOOP, EXIT, WHILE and FOR statements, you can arrange
-     for your PL/pgSQL function to repeat
-     a series of commands.
+     With the LOOP, EXIT, WHILE,
+     and FOR statements, you can arrange for your
+     PL/pgSQL function to repeat a series
+     of commands.
     
 
     
-     <span class="marked">LOOP</span>
+     <span class="marked"><literal>LOOP</></span>
 
-     
 
-<<label>>
+<<label>>
 LOOP
     statements
 END LOOP;
 
 
-      LOOP defines an unconditional loop that is repeated indefinitely
-      until terminated by an EXIT or RETURN
-      statement.  The optional label can be used by EXIT statements in
+     
+      LOOP defines an unconditional loop that is repeated indefinitely
+      until terminated by an EXIT or RETURN
+      statement.  The optional label can be used by EXIT statements in
       nested loops to specify which level of nesting should be
       terminated.
      
     
 
      
-      <span class="marked">EXIT</span>
+      <span class="marked"><literal>EXIT</></span>
 
-       
 
 EXIT  label   WHEN expression ;
 
 
+       
         If no label is given,
         the innermost loop is terminated and the
-        statement following END LOOP is executed next.
+        statement following END LOOP is executed next.
         If label is given, it
         must be the label of the current or some outer level of nested loop
         or block. Then the named loop or block is terminated and control
         continues with the statement after the loop's/block's corresponding
-        END.
+        END.
        
 
        
-        If WHEN is present, loop exit occurs only if the specified condition
-   is true, otherwise control passes to the statement after EXIT.
+        If WHEN is present, loop exit occurs only if the specified condition
+   is true, otherwise control passes to the statement after EXIT.
        
 
        
@@ -1490,7 +1483,7 @@ END LOOP;
 BEGIN
     -- some computations
     IF stocks > 100000 THEN
-        EXIT;  -- illegal. Can't use EXIT outside of a LOOP
+        EXIT;  -- invalid; cannot use EXIT outside of LOOP
     END IF;
 END;
 
@@ -1498,17 +1491,17 @@ END;
      
 
      
-      <span class="marked">WHILE</span>
+      <span class="marked"><literal>WHILE</></span>
 
-       
 
-<<label>>
+<<label>>
 WHILE expression LOOP
     statements
 END LOOP;
 
 
-        The WHILE statement repeats a
+       
+        The WHILE statement repeats a
         sequence of statements so long as the condition expression
    evaluates to true.  The condition is checked just before
    each entry to the loop body.
@@ -1529,32 +1522,31 @@ END LOOP;
      
 
      
-      <span class="marked">FOR (integer for-loop</span>)
+      <span class="marked"><literal>FOR</> (integer variant</span>)
 
-       
 
-<<label>>
+<<label>>
 FOR name IN  REVERSE  expression .. expression LOOP
     statements
 END LOOP;
 
 
-        This form of FOR creates a loop that iterates over a range of integer
+       
+        This form of FOR creates a loop that iterates over a range of integer
    values. The variable 
         name is automatically defined 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 once when entering
-        the loop. The iteration step is normally 1, but is -1 when REVERSE is
+        the loop. The iteration step is normally 1, but is -1 when REVERSE is
    specified.
        
 
        
-        Some examples of integer FOR loops:
+        Some examples of integer FOR loops:
 
 FOR i IN 1..10 LOOP
-  -- some expressions here
-
-    RAISE NOTICE ''i is %'',i;
+    -- some expressions here
+    RAISE NOTICE ''i is %'', i;
 END LOOP;
 
 FOR i IN REVERSE 10..1 LOOP
@@ -1569,73 +1561,70 @@ END LOOP;
     Looping Through Query Results
 
     
-     Using a different type of FOR loop, you can iterate through
+     Using a different type of FOR loop, you can iterate through
      the results of a query and manipulate that data
      accordingly. The syntax is:
 
-<<label>>
-FOR record | row IN select_query LOOP
+<<label>>
+FOR record_or_row IN query LOOP
     statements
 END LOOP;
 
-     The record or row variable is successively assigned all the rows
-     resulting from the SELECT query and the loop
+     The record or row variable is successively assigned each row
+     resulting from the query (a SELECT command) and the loop
      body is executed for each row. Here is an example:
-    
-
-    
 
-CREATE FUNCTION cs_refresh_mviews () RETURNS INTEGER AS '
+CREATE FUNCTION cs_refresh_mviews() RETURNS integer AS '
 DECLARE
-     mviews RECORD;
+    mviews RECORD;
 BEGIN
-     PERFORM cs_log(''Refreshing materialized views...'');
+    PERFORM cs_log(''Refreshing materialized views...'');
 
-     FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP
+    FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP
 
-         -- Now "mviews" has one record from cs_materialized_views
+        -- Now "mviews" has one record from cs_materialized_views
 
-         PERFORM cs_log(''Refreshing materialized view '' || quote_ident(mviews.mv_name) || ''...'');
-         EXECUTE ''TRUNCATE TABLE  '' || quote_ident(mviews.mv_name);
-         EXECUTE ''INSERT INTO '' || quote_ident(mviews.mv_name) || '' '' || mviews.mv_query;
-     END LOOP;
+        PERFORM cs_log(''Refreshing materialized view '' || quote_ident(mviews.mv_name) || ''...'');
+        EXECUTE ''TRUNCATE TABLE  '' || quote_ident(mviews.mv_name);
+        EXECUTE ''INSERT INTO '' || quote_ident(mviews.mv_name) || '' '' || mviews.mv_query;
+    END LOOP;
 
-     PERFORM cs_log(''Done refreshing materialized views.'');
-     RETURN 1;
-end;
-' LANGUAGE 'plpgsql';
+    PERFORM cs_log(''Done refreshing materialized views.'');
+    RETURN 1;
+END;
+' LANGUAGE plpgsql;
 
 
-     If the loop is terminated by an EXIT statement, the last
+     If the loop is terminated by an EXIT statement, the last
      assigned row value is still accessible after the loop.
     
 
     
-     The FOR-IN-EXECUTE statement is another way to iterate over
+     The FOR-IN-EXECUTE statement is another way to iterate over
      records:
 
-<<label>>
-FOR record | row IN EXECUTE text_expression LOOP 
+<<label>>
+FOR record_or_row IN EXECUTE text_expression LOOP 
     statements
 END LOOP;
 
      This is like the previous form, except that the source
      SELECT statement is specified as a string
-     expression, which is evaluated and re-planned on each entry to
-     the FOR loop.  This allows the programmer to choose the speed of
-     a pre-planned query or the flexibility of a dynamic query, just
+     expression, which is evaluated and replanned on each entry to
+     the FOR loop.  This allows the programmer to choose the speed of
+     a preplanned query or the flexibility of a dynamic query, just
      as with a plain EXECUTE statement.
     
 
     
     
      The PL/pgSQL parser presently distinguishes the
-     two kinds of FOR loops (integer or record-returning) by checking
-     whether the target variable mentioned just after FOR has been
-     declared as a record/row variable.  If not, it's presumed to be
-     an integer FOR loop.  This can cause rather nonintuitive error
+     two kinds of FOR loops (integer or query result) by checking
+     whether the target variable mentioned just after FOR has been
+     declared as a record or row variable.  If not, it's presumed to be
+     an integer FOR loop.  This can cause rather nonintuitive error
      messages when the true problem is, say, that one has
-     misspelled the FOR variable name.
+     misspelled the variable name after the FOR.
     
     
   
@@ -1650,7 +1639,7 @@ END LOOP;
     the query result a few rows at a time. One reason for doing this is
     to avoid memory overrun when the result contains a large number of
     rows. (However, PL/pgSQL users do not normally need
-    to worry about that, since FOR loops automatically use a cursor
+    to worry about that, since FOR loops automatically use a cursor
     internally to avoid memory problems.) A more interesting usage is to
     return a reference to a cursor that it has created, allowing the
     caller to read the rows. This provides an efficient way to return
@@ -1668,13 +1657,13 @@ END LOOP;
      Another way is to use the cursor declaration syntax,
      which in general is:
 
-name CURSOR  ( arguments )  FOR select_query ;
+name CURSOR  ( arguments )  FOR query ;
 
      (FOR may be replaced by IS for
      Oracle compatibility.)
-     arguments, if any, are a
-     comma-separated list of name
-     datatype pairs that define names to be
+     arguments, if specified, is a
+     comma-separated list of pairs name
+     datatype that define names to be
      replaced by parameter values in the given query.  The actual
      values to substitute for these names will be specified later,
      when the cursor is opened.
@@ -1684,8 +1673,8 @@ END LOOP;
 
 DECLARE
     curs1 refcursor;
-    curs2 CURSOR FOR SELECT * from tenk1;
-    curs3 CURSOR (key int) IS SELECT * from tenk1 where unique1 = key;
+    curs2 CURSOR FOR SELECT * FROM tenk1;
+    curs3 CURSOR (key integer) IS SELECT * FROM tenk1 WHERE unique1 = key;
 
      All three of these variables have the data type refcursor,
      but the first may be used with any query, while the second has
@@ -1705,18 +1694,18 @@ DECLARE
      Before a cursor can be used to retrieve rows, it must be
      opened. (This is the equivalent action to the SQL
      command DECLARE CURSOR.) PL/pgSQL has
-     four forms of the OPEN statement, two of which use unbound cursor
-     variables and the other two use bound cursor variables.
+     three forms of the OPEN statement, two of which use unbound cursor
+     variables and the other uses a bound cursor variable.
     
 
     
-     <span class="marked">OPEN FOR SELECT</span>
+     <span class="marked"><command>OPEN FOR SELECT</command></span>
 
-       
 
 OPEN unbound-cursor FOR SELECT ...;
 
 
+       
     The cursor variable is opened and given the specified query to
    execute.  The cursor cannot be open already, and it must have been
    declared as an unbound cursor (that is, as a simple
@@ -1724,8 +1713,11 @@ OPEN unbound-cursor FOR SELECT ...;
    is treated in the same way as other SELECT
    statements in PL/pgSQL: PL/pgSQL
    variable names are substituted, and the query plan is cached for
-   possible re-use.
+   possible reuse.
+       
 
+       
+        An example:
 
 OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
 
@@ -1733,13 +1725,13 @@ OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
      
 
     
-     <span class="marked">OPEN FOR EXECUTE</span>
+     <span class="marked"><command>OPEN FOR EXECUTE</command></span>
 
-    
 
 OPEN unbound-cursor FOR EXECUTE query-string;
 
 
+    
      The cursor variable is opened and given the specified query to
      execute.  The cursor cannot be open already, and it must have been
      declared as an unbound cursor (that is, as a simple
@@ -1747,7 +1739,10 @@ OPEN unbound-cursor FOR EXECUTE 
      expression in the same way as in the EXECUTE
      command.  As usual, this gives flexibility so the query can vary
      from one run to the next.
+       
 
+       
+        An example:
 
 OPEN curs1 FOR EXECUTE ''SELECT * FROM '' || quote_ident($1);
 
@@ -1755,21 +1750,24 @@ OPEN curs1 FOR EXECUTE ''SELECT * FROM '' || quote_ident($1);
      
 
     
-     Opening a <span class="marked">bound c</span>ursor
+     Opening a <span class="marked">Bound C</span>ursor
 
-    
 
 OPEN bound-cursor  ( argument_values ) ;
 
 
+    
      This form of OPEN is used to open a cursor
      variable whose query was bound to it when it was declared.  The
      cursor cannot be open already.  A list of actual argument value
      expressions must appear if and only if the cursor was declared to
      take arguments.  These values will be substituted in the query.
-     The query plan for a bound cursor is always considered cacheable
-     --- there is no equivalent of EXECUTE in this case.
+     The query plan for a bound cursor is always considered cacheable;
+     there is no equivalent of EXECUTE in this case.
+         
 
+    
+     Examples:
 
 OPEN curs2;
 OPEN curs3(42);
@@ -1791,51 +1789,57 @@ OPEN curs3(42);
      opened the cursor to begin with.  You can return a refcursor
      value out of a function and let the caller operate on the cursor.
      (Internally, a refcursor value is simply the string name
-     of a Portal containing the active query for the cursor.  This name
+     of a so-called portal containing the active query for the cursor.  This name
      can be passed around, assigned to other refcursor variables,
-     and so on, without disturbing the Portal.)
+     and so on, without disturbing the portal.)
     
 
     
-     All Portals are implicitly closed at transaction end.  Therefore
-     a refcursor value is useful to reference an open cursor
+     All portals are implicitly closed at transaction end.  Therefore
+     a refcursor value is usable to reference an open cursor
      only until the end of the transaction.
     
 
     
-     <span class="marked">FETCH</span>
+     <span class="marked"><literal>FETCH</></span>
 
-    
 
 FETCH cursor INTO target;
 
 
+    
      FETCH retrieves the next row from the
      cursor into a target, which may be a row variable, a record
      variable, or a comma-separated list of simple variables, just like
      SELECT INTO.  As with SELECT
       INTO, the special variable FOUND may
      be checked to see whether a row was obtained or not.
+         
 
+    
+     An example:
 
 FETCH curs1 INTO rowvar;
-FETCH curs2 INTO foo,bar,baz;
+FETCH curs2 INTO foo, bar, baz;
 
        
      
 
     
-     <span class="marked">CLOSE</span>
+     <span class="marked"><literal>CLOSE</></span>
 
-       
 
 CLOSE cursor;
 
 
+       
     CLOSE closes the Portal underlying an open
    cursor.  This can be used to release resources earlier than end of
    transaction, or to free up the cursor variable to be opened again.
+       
 
+       
+        An example:
 
 CLOSE curs1;
 
@@ -1846,15 +1850,13 @@ CLOSE curs1;
      Returning Cursors
 
        
-
         PL/pgSQL functions can return cursors to the
         caller. This is used to return multiple rows or columns from
-        the function. The function opens the cursor and returns the
+        the function. To do this, the function opens the cursor and returns the
         cursor name to the caller. The caller can then
-        FETCH rows from the cursor. The cursor can
+        fetch rows from the cursor. The cursor can
         be closed by the caller, or it will be closed automatically
         when the transaction closes.
-
        
 
        
@@ -1868,10 +1870,10 @@ INSERT INTO test VALUES ('123');
 
 CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS '
 BEGIN
-        OPEN $1 FOR SELECT col FROM test;
-        RETURN $1;
+    OPEN $1 FOR SELECT col FROM test;
+    RETURN $1;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
 BEGIN;
 SELECT reffunc('funccursor');
@@ -1886,20 +1888,20 @@ COMMIT;
 
 CREATE FUNCTION reffunc2() RETURNS refcursor AS '
 DECLARE
-        ref refcursor;
+    ref refcursor;
 BEGIN
-        OPEN ref FOR SELECT col FROM test;
-        RETURN ref;
+    OPEN ref FOR SELECT col FROM test;
+    RETURN ref;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
 BEGIN;
 SELECT reffunc2();
   
-        reffunc2      
-  --------------------
  <unnamed cursor 1>
-  (1 row)
+      reffunc2      
+--------------------
+ <unnamed cursor 1>
+(1 row)
 
 FETCH ALL IN "<unnamed cursor 1>";
 COMMIT;
@@ -1917,7 +1919,7 @@ COMMIT;
     raise errors.
 
 
-RAISE level 'format' variable ...;
+RAISE level 'format' variable ...;
 
 
     Possible levels are DEBUG (write the message to
@@ -1926,17 +1928,17 @@ RAISE level '
     NOTICE and WARNING (write
     the message to the server log and send it to the client, with
     respectively higher priorities), and EXCEPTION
-    (raise an error and abort the current transaction). Whether error
+    (raise an error and abort the current transaction). Whether
     messages of a particular priority are reported to the client,
     written to the server log, or both is controlled by the
-     and
-     configuration variables. See
+     and
+     configuration variables. See
      for more information.
    
 
    
     Inside the format string, % is replaced by the
-    next optional argument's external representation. Write
+    next optional argument's string representation. Write
     %% to emit a literal %. Note
     that the optional arguments must presently be simple variables,
     not expressions, and the format must be a simple string literal.
@@ -1949,38 +1951,33 @@ RAISE level '
     -->
 
    
-    Examples:
+    In this example, the value of v_job_id will replace the
+    % in the string.
 
-RAISE NOTICE ''Calling cs_create_job(%)'',v_job_id;
+RAISE NOTICE ''Calling cs_create_job(%)'', v_job_id;
 
-
-    In this example, the value of v_job_id will replace the
-    % in the string.
    
 
    
+    This example will abort the transaction with the given error message.
 
-RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
+RAISE EXCEPTION ''Inexistent ID --> %'', user_id;
 
-    This will abort the transaction with the given error message.
    
 
-  
-   Exceptions
-
     
      PostgreSQL does not 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 system jumps back
-     into the main loop to get the next query from the client application.
+     into the main loop to get the next command from the client application.
     
 
     
      It is possible to hook into the error mechanism to notice that this
      happens. But currently it is impossible to tell what really
-     caused the abort (input/output conversion error, floating-point
-     error, parse error). And it is possible that the database backend
+     caused the abort (data type format error, floating-point
+     error, parse error, etc.). And it is possible that the database server
      is in an inconsistent state at this point so returning to the upper
      executor or issuing more commands might corrupt the whole database.
     
@@ -1993,7 +1990,6 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
      function and where (line number and type of statement) this
      happened.  The error always stops execution of the function.
     
-  
  
 
  
@@ -2021,8 +2017,8 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
      
       
        Data type RECORD; variable holding the new
-       database row for INSERT/UPDATE operations in ROW level
-       triggers. This variable is NULL in STATEMENT level triggers.
+       database row for INSERT/UPDATE operations in row-level
+       triggers. This variable is null in statement-level triggers.
       
      
     
@@ -2032,8 +2028,8 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
      
       
        Data type RECORD; variable holding the old
-       database row for UPDATE/DELETE operations in ROW level
-       triggers. This variable is NULL in STATEMENT level triggers.
+       database row for UPDATE/DELETE operations in row-level
+       triggers. This variable is null in statement-level triggers.
       
      
     
@@ -2075,9 +2071,9 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
      
       
        Data type text; a string of
-       INSERTUPDATE or
+       INSERTUPDATE, or
        DELETE telling for which operation the
-       trigger is fired.
+       trigger was fired.
       
      
     
@@ -2118,8 +2114,8 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
       
        Data type array of text; the arguments from
               the CREATE TRIGGER statement.
-       The index counts from 0 and can be given as an expression. Invalid
-       indices (< 0 or >= tg_nargs) result in a null value.
+       The index counts from 0. Invalid
+       indices (less than 0 or greater than or equal to tg_nargs) result in a null value.
       
      
     
@@ -2127,34 +2123,40 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
   
 
    
-    A trigger function must return either NULL or a record/row value
+    A trigger function must return either null or a record/row value
     having exactly the structure of the table the trigger was fired
-    for. The return value of a BEFORE or AFTER STATEMENT level
-    trigger, or an AFTER ROW level trigger is ignored; it may as well
-    return NULL. However, any of these types of triggers can still
+    for. The return value of a BEFORE or AFTER statement-level
+    trigger or an AFTER row-level trigger is ignored; it may as well
+    be null. However, any of these types of triggers can still
     abort the entire trigger operation by raising an error.
    
 
    
-    ROW level triggers fired BEFORE may return NULL to signal the
+    Row-level triggers fired BEFORE may return null to signal the
     trigger manager to skip the rest of the operation for this row
-    (ie, subsequent triggers are not fired, and the
-    INSERT/UPDATE/DELETE does not occur for this row).  If a non-NULL
+    (i.e., subsequent triggers are not fired, and the
+    INSERT/UPDATE/DELETE does not occur for this row).  If a nonnull
     value is returned then the operation proceeds with that row value.
-    Note that returning a row value different from the original value
-    of NEW alters the row that will be inserted or updated.  It is
-    possible to replace single values directly in NEW and return that,
+    Returning a row value different from the original value
+    of NEW alters the row that will be inserted or updated.  It is
+    possible to replace single values directly in NEW and return NEW,
     or to build a complete new record/row to return.
    
 
-   
-    A <application>PL/pgSQL</application> Trigger Procedure Example
+   
+     shows an example of a
+    trigger procedure in PL/pgSQL.
+   
+
+   
+    A <application>PL/pgSQL</application> Trigger Procedure
 
     
      This example trigger ensures that any time a row is inserted or updated
      in the table, the current user name and time are stamped into the
      row. And it ensures that an employee's name is given and that the
      salary is a positive value.
+    
 
 
 CREATE TABLE emp (
@@ -2164,18 +2166,18 @@ CREATE TABLE emp (
     last_user text
 );
 
-CREATE FUNCTION emp_stamp () RETURNS TRIGGER AS '
+CREATE FUNCTION emp_stamp() RETURNS trigger AS '
     BEGIN
         -- Check that empname and salary are given
-        IF NEW.empname ISNULL THEN
-            RAISE EXCEPTION ''empname cannot be NULL value'';
+        IF NEW.empname IS NULL THEN
+            RAISE EXCEPTION ''empname cannot be null'';
         END IF;
-        IF NEW.salary ISNULL THEN
-            RAISE EXCEPTION ''% cannot have NULL salary'', NEW.empname;
+        IF NEW.salary IS NULL THEN
+            RAISE EXCEPTION ''% cannot have null salary'', NEW.empname;
         END IF;
 
         -- Who works for us when she must pay for it?
-        IF NEW.salary < 0 THEN
+        IF NEW.salary < 0 THEN
             RAISE EXCEPTION ''% cannot have a negative salary'', NEW.empname;
         END IF;
 
@@ -2184,106 +2186,10 @@ CREATE FUNCTION emp_stamp () RETURNS TRIGGER AS '
         NEW.last_user := current_user;
         RETURN NEW;
     END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
 CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
     FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
-
-    
-   
-  
-
-  
-
-  
-   Examples
-
-   
-    Here are only a few functions to demonstrate how easy it is to
-    write PL/pgSQL
-    functions. For more complex examples the programmer
-    might look at the regression test for PL/pgSQL.
-   
-
-   
-    One painful detail in writing functions in
-   PL/pgSQL is the handling of single
-   quotes. The function's source text in CREATE FUNCTION
-   must be a literal string. Single quotes inside of literal strings
-   must be either doubled or quoted with a backslash. We are still
-   looking for an elegant alternative. In the meantime, doubling the
-   single quotes as in the examples below should be used. Any
-   solution for this in future versions of
-   PostgreSQL will be forward compatible.
-   
-
-   
-    For a detailed explanation and examples of how to escape single
-    quotes in different situations, please see .
-   
-
-   
-    A Simple <application>PL/pgSQL</application> Function to Increment an Integer
-
-    
-     The following two PL/pgSQL functions are identical to their
-     counterparts from the C language function discussion. This
-     function receives an integer and increments it by
-     one, returning the incremented value.
-    
-
-
-CREATE FUNCTION add_one (integer) RETURNS INTEGER AS '
-    BEGIN
-        RETURN $1 + 1;
-    END;
-' LANGUAGE 'plpgsql';
-
-   
-
-   
-    A Simple <application>PL/pgSQL</application> Function to Concatenate Text
-
-    
-     This function receives two text parameters and
-     returns the result of concatenating them.
-    
-
-
-CREATE FUNCTION concat_text (TEXT, TEXT) RETURNS TEXT AS '
-    BEGIN
-        RETURN $1 || $2;
-    END;
-' LANGUAGE 'plpgsql';
-
-   
-
-   
-    A <application>PL/pgSQL</application> Function on Composite Type
-
-    
-     In this example, we take EMP (a table) and an
-     integer as arguments to our function, which returns
-     a boolean. If the salary field of the EMP table is
-     NULL, we return f. Otherwise we compare with
-     that field with the integer passed to the function
-     and return the boolean result of the comparison (t
-     or f). This is the PL/pgSQL equivalent to the example from the C
-     functions.
-    
-
-
-CREATE FUNCTION c_overpaid (EMP, INTEGER) RETURNS BOOLEAN AS '
-    DECLARE
-        emprec ALIAS FOR $1;
-        sallim ALIAS FOR $2;
-    BEGIN
-        IF emprec.salary ISNULL THEN
-            RETURN ''f'';
-        END IF;
-        RETURN emprec.salary > sallim;
-    END;
-' LANGUAGE 'plpgsql';
 
    
   
@@ -2291,31 +2197,6 @@ CREATE FUNCTION c_overpaid (EMP, INTEGER) RETURNS BOOLEAN AS '
   
 
  
-
-  
-   
-    February 2001
-   
-   
-    Roberto
-    Mello
-    
-     
-      [email protected]
-     
-    
-   
-
-   
-
   Porting from <productname>Oracle</productname> PL/SQL
 
   
@@ -2326,43 +2207,26 @@ CREATE FUNCTION c_overpaid (EMP, INTEGER) RETURNS BOOLEAN AS '
    PL/SQL
   
 
-  
-   Author
-   
-    Roberto Mello ([email protected])
-   
-  
-
   
-   This section explains differences between Oracle's PL/SQL and
-   PostgreSQL's PL/pgSQL languages in the hopes of helping developers
-   port applications from Oracle to PostgreSQL.  Most of the code here
-   is from the ArsDigita
-   Clickstream
-   module that I ported to PostgreSQL when I took an
-   internship with OpenForce
-   Inc. in the Summer of 2000.
+   This section explains differences between
+   PostgreSQL's PL/pgSQL
+   language and Oracle's PL/SQL language,
+   to help developers that port applications from Oracle to
+   PostgreSQL.
   
 
   
-   PL/pgSQL is similar to PL/SQL in many aspects. It is a block
-   structured, imperative language (all variables have to be
-   declared). PL/SQL has many more features than its PostgreSQL
-   counterpart, but PL/pgSQL allows for a great deal of functionality
-   and it is being improved constantly.
-  
-
-  
-   Main Differences
-
-   
-    Some things you should keep in mind when porting from
-    Oracle to PostgreSQL:
+   PL/pgSQL is similar to PL/SQL in many
+   aspects. It is a block-structured, imperative language, and all
+   variables have to be declared.  Assignments, loops, conditionals
+   are similar.  The main differences you should keep in mind when
+   porting from PL/SQL to
+   PL/pgSQL are:
 
     
      
       
-       No default parameters in PostgreSQL.
+       There are no default values for parameters in PostgreSQL.
       
      
 
@@ -2375,146 +2239,41 @@ CREATE FUNCTION c_overpaid (EMP, INTEGER) RETURNS BOOLEAN AS '
 
      
       
-       Assignments, loops and conditionals are similar. 
+       No need for cursors in PL/pgSQL, just put the
+       query in the FOR statement.  (See 
+       linkend="plpgsql-porting-ex2">.)
       
      
 
      
       
-       No need for cursors in PostgreSQL, just put the query in the FOR 
-       statement (see example below)
+       In PostgreSQL you need to escape single
+       quotes in the function body. See .
       
      
 
      
       
-       In PostgreSQL you need to escape single
-       quotes. See .
+       Instead of packages, use schemas to organize your functions
+       into groups.
       
      
     
    
 
-   
-    Quote Me on That: Escaping Single Quotes
-
-    
-     In PostgreSQL you need to escape single quotes inside your
-     function definition. This can lead to quite amusing code at
-     times, especially if you are creating a function that generates
-     other function(s), as in 
-     .  
-     One thing to keep in mind
-     when escaping lots of single quotes is that, except for the
-     beginning/ending quotes, all the others will come in even
-     quantity.
-    
-
-    
-      gives the scoop.  (You'll
-     love this little chart.)
-    
-
-    
-     Single Quotes Escaping Chart
-
-     
-      
-       
-        No. of Quotes
-        Usage
-        Example
-        Result
-       
-      
-
-      
-       
-        1
-        To begin/terminate function bodies
-        
-CREATE FUNCTION foo() RETURNS INTEGER AS '...'
-LANGUAGE 'plpgsql';
-
-        as is
-       
-
-       
-        2
-        In assignments, SELECT statements, to delimit strings, etc.
-        
-a_output := ''Blah'';
-SELECT * FROM users WHERE f_name=''foobar'';
-
-        SELECT * FROM users WHERE f_name='foobar';
-       
-
-       
-        4
-        
-         When you need two single quotes in your resulting string
-         without terminating that string.
-        
-        
-a_output := a_output || '' AND name 
-    LIKE ''''foobar'''' AND ...''
-
-        AND name LIKE 'foobar' AND ...
-       
-
-       
-        6
-        
-         When you want double quotes in your resulting string
-         and terminate that string.
-        
-        
-a_output := a_output || '' AND name 
-    LIKE ''''foobar''''''
-
-        
-         AND name LIKE 'foobar'
-        
-       
-
-       
-        10
-        
-         When you want two single quotes in the resulting string
-         (which accounts for 8 quotes) and
-         terminate that string (2 more).  You will probably only need
-         that if you were using a function to generate other functions
-         (like in ).
-        
-        
-a_output := a_output || '' if v_'' || 
-    referrer_keys.kind || '' like '''''''''' 
-    || referrer_keys.key_string || '''''''''' 
-    then return ''''''  || referrer_keys.referrer_type 
-    || ''''''; end if;''; 
-
-        
-         if v_<...> like ''<...>'' then return ''<...>''; end if;
-        
-       
-      
-     
-    
-   
-    
+  
+   Porting Examples
 
-  >
-   </div> <div class="diff rem">-    Porting Functions</div> <div class="diff rem">-   </<span class="marked">title</span>></div> <div class="diff add">+  <span class="marked"> <para</span>></div> <div class="diff add">+    <xref linkend="pgsql-porting-ex1"> shows how to port a simple</div> <div class="diff add">+    function from <application>PL/SQL</> to <application>PL/pgSQL</>.</div> <div class="diff add">+   </<span class="marked">para</span>></div> <div class="diff ctx"> </div> <div class="diff rem">-   <example></div> <div class="diff rem">-    <title></div> <div class="diff rem">-     A Simple Function</div> <div class="diff rem">-    
+   
+    Porting a Simple Function from <application>PL/SQL</> to <application>PL/pgSQL</>
 
     
-     Here is an Oracle function:
+     Here is an Oracle PL/SQL function:
 
 CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name IN varchar, v_version IN varchar)
 RETURN varchar IS
@@ -2525,7 +2284,7 @@ BEGIN
     RETURN v_name || '/' || v_version;
 END;
 /
-SHOW ERRORS;
+show errors;
 
     
 
@@ -2545,11 +2304,11 @@ SHOW ERRORS;
        
         Oracle can have
         INOUT, and
-        INOUT parameters passed to functions.  The
+        INOUT parameters passed to functions.
         INOUT, for example, means that the
         parameter will receive a value and return
-        another. PostgreSQL only has <quote>IN>
-        parameters and functions can return only a single value.
+        another. PostgreSQL only has <literal>IN>
+        parameters.
        
       
 
@@ -2557,16 +2316,15 @@ SHOW ERRORS;
        
         The RETURN key word in the function
         prototype (not the function body) becomes
-        RETURNS in PostgreSQL.
+        RETURNS in PostgreSQL.
        
       
 
       
        
-        On PostgreSQL functions are created using single quotes as
-        delimiters, so you have to escape single quotes inside your
-        functions (which can be quite annoying at times; see 
-        linkend="plpgsql-quote">).
+        In PostgreSQL, functions are created using
+        single quotes as the delimiters of the function body, so you
+        have to escape single quotes inside the function body.
        
       
 
@@ -2580,12 +2338,12 @@ SHOW ERRORS;
     
 
     
-     So let's see how this function would look when ported to
+     This is how this function would look when ported to
      PostgreSQL:
 
 
-CREATE OR REPLACE FUNCTION cs_fmt_browser_version(VARCHAR, VARCHAR)
-RETURNS VARCHAR AS '
+CREATE OR REPLACE FUNCTION cs_fmt_browser_version(varchar, varchar)
+RETURNS varchar AS '
 DECLARE
     v_name ALIAS FOR $1;
     v_version ALIAS FOR $2;
@@ -2595,24 +2353,30 @@ BEGIN
     END IF;
     RETURN v_name || ''/'' || v_version;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
     
    
+
+   
+     shows how to port a
+    function that creates another function and how to handle to
+    ensuing quoting problems.
+   
  
-   
-    </div> <div class="diff rem">-     A Function that Creates Another Function</div> <div class="diff rem">-    
+   
+    Porting a Function that Creates Another Function from <application>PL/SQL</> to <application>PL/pgSQL</>
 
     
      The following procedure grabs rows from a
      SELECT statement and builds a large function
      with the results in IF statements, for the
-     sake of efficiency. Notice particularly the differences in
-     cursors, FOR loops, and the need to escape
-     single quotes in PostgreSQL.
+     sake of efficiency. Notice particularly the differences in the
+     cursor and the FOR loop,
+    
 
+    
+     This is the Oracle version:
 
 CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc IS
     CURSOR referrer_keys IS 
@@ -2634,7 +2398,7 @@ referrer_key.key_string || ''' THEN RETURN ''' || referrer_key.referrer_type ||
     EXECUTE IMMEDIATE a_output; 
 END; 
 / 
-show errors
+show errors;
 
     
 
@@ -2642,23 +2406,21 @@ show errors
      Here is how this function would end up in PostgreSQL:
 
 
-CREATE FUNCTION cs_update_referrer_type_proc() RETURNS INTEGER AS '
+CREATE FUNCTION cs_update_referrer_type_proc() RETURNS integer AS '
 DECLARE
     referrer_keys RECORD;  -- Declare a generic record to be used in a FOR
     a_output varchar(4000);
 BEGIN 
-    a_output := ''CREATE FUNCTION cs_find_referrer_type(VARCHAR,VARCHAR,VARCHAR
-                  RETURNS VARCHAR AS '''' 
+    a_output := ''CREATE FUNCTION cs_find_referrer_type(varchar, varchar, varchar
+                  RETURNS varchar AS '''' 
                      DECLARE 
                          v_host ALIAS FOR $1; 
                          v_domain ALIAS FOR $2; 
                          v_url ALIAS FOR $3;
                      BEGIN ''; 
 
-    -- 
     -- Notice how we scan through the results of a query in a FOR loop
     -- using the FOR <record> construct.
-    --
 
     FOR referrer_keys IN SELECT * FROM cs_referrer_keys ORDER BY try_order LOOP
         a_output := a_output || '' IF v_'' || referrer_keys.kind || '' LIKE '''''''''' 
@@ -2666,47 +2428,60 @@ BEGIN
                  || referrer_keys.referrer_type || ''''''; END IF;''; 
     END LOOP; 
   
-    a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE ''''plpgsql'''';''; 
+    a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE plpgsql;''; 
  
-    -- This works because we are not substituting any variables
-    -- Otherwise it would fail. Look at PERFORM for another way to run functions
+    -- EXECUTE will work because we are not substituting any variables.
+    -- Otherwise it would fail.  Look at PERFORM for another way to run functions.
     
     EXECUTE a_output; 
 END; 
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
     
    
  
-   
-    </div> <div class="diff rem">-     A Procedure with a lot of String Manipulation and <literal>OUT</> Parameters</div> <div class="diff rem">-    
+   
+     shows how to port a function
+    with OUT parameters and string manipulation.
+    PostgreSQL does not have an
+    instr function, but you can work around it
+    using a combination of other functions.  In 
+    linkend="plpgsql-porting-appendix"> there is a
+    PL/pgSQL implementation of
+    instr that you can use to make your porting
+    easier.
+   
+
+   
+    Porting a Procedure With String Manipulation and</div> <div class="diff add">+    <literal>OUT</> Parameters from <application>PL/SQL</> to</div> <div class="diff add">+    <application>PL/pgSQL</>
 
     
      The following Oracle PL/SQL procedure is used to parse a URL and
-     return several elements (host, path and query). It is an
-     procedure because in PL/pgSQL functions only one value can be returned
-     (see ).  In
+     return several elements (host, path, and query).
+     PL/pgSQL functions can return only one value.  In
      PostgreSQL, one way to work around this is to split the procedure
      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.
     
 
+    
+     This is the Oracle version:
 
 CREATE OR REPLACE PROCEDURE cs_parse_url(
     v_url IN VARCHAR,
     v_host OUT VARCHAR,  -- This will be passed back
     v_path OUT VARCHAR,  -- This one too
     v_query OUT VARCHAR) -- And this one
-is
+IS
     a_pos1 INTEGER;
     a_pos2 INTEGER;
-begin
+BEGIN
     v_host := NULL;
     v_path := NULL;
     v_query := NULL;
-    a_pos1 := instr(v_url, '//'); -- PostgreSQL doesn't have an instr function
+    a_pos1 := instr(v_url, '//');
 
     IF a_pos1 = 0 THEN
         RETURN;
@@ -2732,28 +2507,30 @@ END;
 /
 show errors;
 
+    
 
     
-     Here is how this procedure could be translated for PostgreSQL:
+     Here is how the PL/pgSQL function that returns
+     the host part could look like:
 
 
-CREATE OR REPLACE FUNCTION cs_parse_url_host(VARCHAR) RETURNS VARCHAR AS ' 
-DECLARE 
-    v_url ALIAS FOR $1; 
-    v_host VARCHAR; 
-    v_path VARCHAR; 
-    a_pos1 INTEGER; 
-    a_pos2 INTEGER; 
-    a_pos3 INTEGER; 
+CREATE OR REPLACE FUNCTION cs_parse_url_host(varchar) RETURNS varchar AS '
+DECLARE
+    v_url ALIAS FOR $1;
+    v_host varchar;
+    v_path varchar;
+    a_pos1 integer;
+    a_pos2 integer;
+    a_pos3 integer;
 BEGIN 
     v_host := NULL; 
-    a_pos1 := instr(v_url,''//''); 
+    a_pos1 := instr(v_url, ''//'');
 
     IF a_pos1 = 0 THEN 
         RETURN '''';  -- Return a blank
     END IF; 
 
-    a_pos2 := instr(v_url,''/'',a_pos1 + 2); 
+    a_pos2 := instr(v_url,''/'',a_pos1 + 2);
     IF a_pos2 = 0 THEN 
         v_host := substr(v_url, a_pos1 + 2); 
         v_path := ''/''; 
@@ -2763,37 +2540,21 @@ BEGIN
     v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2 ); 
     RETURN v_host; 
 END; 
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
     
    
 
-   
-    
-     PostgreSQL does not have an instr function,
-     so you can work around it using a combination of other functions.
-     I got tired of doing this and created my own
-     instr functions that behave exactly like
-     Oracle's (it makes life easier). See the 
-     linkend="plpgsql-porting-appendix"> for the code.
-    
-   
-  
-
-  
-   </div> <div class="diff rem">-    Procedures</div> <div class="diff rem">-   
-
    
-    Oracle procedures give a little more
-    flexibility to the developer because nothing needs to be
-    explicitly returned, but it can be through the use of
-    INOUT or OUT parameters.
+     shows how to port a procedure
+    that uses numerous features that are specific to Oracle.
    
 
-   
-    An example:
+   
+    Porting a Procedure from <application>PL/SQL</> to <application>PL/pgSQL</>
+
+    
+     The Oracle version:
 
 
 CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id IN INTEGER) IS
@@ -2802,9 +2563,7 @@ CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id IN INTEGER) IS
 BEGIN
     LOCK TABLE cs_jobs IN EXCLUSIVE MODE;
 
-    SELECT count(*) INTO a_running_job_count 
-    FROM cs_jobs
-    WHERE end_stamp IS NULL;
+    SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
 
     IF a_running_job_count > 0 THEN
         COMMIT; -- free lock
@@ -2827,13 +2586,13 @@ show errors
 
    
     Procedures like this can be easily converted into PostgreSQL
-    functions returning an INTEGER. This procedure in
+    functions returning an integer. This procedure in
     particular is interesting because it can teach us some things:
 
     
      
       
-       There is no pragma statement in PostgreSQL.
+       There is no PRAGMA statement in PostgreSQL.
       
      
 
@@ -2846,11 +2605,10 @@ show errors
 
      
       
-       You also cannot have transactions in PL/pgSQL procedures. The
+       You also cannot have transactions in PL/pgSQL functions. The
        entire function (and other functions called from therein) is
-       executed in a transaction and PostgreSQL rolls back the results if
-       something goes wrong. Therefore only one
-       BEGIN statement is allowed.
+       executed in one transaction and PostgreSQL rolls back the transaction if
+       something goes wrong.
       
      
 
@@ -2864,36 +2622,30 @@ show errors
    
 
    
-    So let's see one of the ways we could port this procedure to PL/pgSQL:
+    This is how we could port this procedure to PL/pgSQL:
 
 
-CREATE OR REPLACE FUNCTION cs_create_job(INTEGER) RETURNS INTEGER AS '
+CREATE OR REPLACE FUNCTION cs_create_job(integer) RETURNS integer AS '
 DECLARE
     v_job_id ALIAS FOR $1;
-    a_running_job_count INTEGER;
-    a_num INTEGER;
-    -- PRAGMA AUTONOMOUS_TRANSACTION;
+    a_running_job_count integer;
+    a_num integer;
 BEGIN
     LOCK TABLE cs_jobs IN EXCLUSIVE MODE;
-    SELECT count(*) INTO a_running_job_count 
-    FROM cs_jobs 
-    WHERE end_stamp IS NULL;
+    SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
 
     IF a_running_job_count > 0
     THEN
-        -- COMMIT; -- free lock
         RAISE EXCEPTION ''Unable to create a new job: a job is currently running.'';
     END IF;
 
     DELETE FROM cs_active_job;
     INSERT INTO cs_active_job(job_id) VALUES (v_job_id);
 
-    SELECT count(*) into a_num 
-    FROM cs_jobs 
-    WHERE job_id=v_job_id;
+    SELECT count(*) INTO a_num FROM cs_jobs WHERE job_id=v_job_id;
     IF NOT FOUND THEN  -- If nothing was returned in the last query
         -- This job is not in the table so lets insert it.
-        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, current_timestamp);
         RETURN 1;
     ELSE
         RAISE NOTICE ''Job already running.'';
@@ -2901,7 +2653,7 @@ BEGIN
 
     RETURN 0;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
 
     
@@ -2912,102 +2664,29 @@ END;
      
     
    
+   
   
 
-  
-   </div> <div class="diff rem">-    Packages</div> <div class="diff rem">-   
-
-   
-    
-     I haven't done much with packages myself, so if there are
-     mistakes here, please let me know.
-    
-   
-
-   
-    Packages are a way Oracle gives you to
-    encapsulate PL/SQL statements and functions into one entity, like
-    Java classes, where you define methods and objects. You can access
-    these objects/methods with a .
-    (dot). Here is an example of an Oracle
-    package from ACS 4 (the 
-    url="http://www.arsdigita.com/doc/">ArsDigita Community
-    System):
-
-
-CREATE OR REPLACE PACKAGE BODY acs
-AS
-  FUNCTION add_user (
-    user_id     IN users.user_id%TYPE DEFAULT NULL,
-    object_type     IN acs_objects.object_type%TYPE DEFAULT 'user',
-    creation_date   IN acs_objects.creation_date%TYPE DEFAULT sysdate,
-    creation_user   IN acs_objects.creation_user%TYPE DEFAULT NULL,
-    creation_ip     IN acs_objects.creation_ip%TYPE DEFAULT NULL,
-  ...
-  ) RETURN users.user_id%TYPE
-  IS
-    v_user_id       users.user_id%TYPE;
-    v_rel_id        membership_rels.rel_id%TYPE;
-  BEGIN
-    v_user_id := acs_user.new (user_id, object_type, creation_date,
-                creation_user, creation_ip, email, ...
-    RETURN v_user_id;
-  END;
-END acs;
-/
-show errors
-
-   
+  
+   Other Things to Watch For
 
    
-    We port this to PostgreSQL by creating the
-    different objects of the Oracle package
-    as functions with a standard naming convention. We have to pay
-    attention to some other details, like the lack of default
-    parameters in PostgreSQL functions. The above
-    package would become something like this:
-
-CREATE FUNCTION acs__add_user(INTEGER,INTEGER,VARCHAR,TIMESTAMP,INTEGER,INTEGER,...)
-RETURNS INTEGER AS '
-DECLARE
-    user_id ALIAS FOR $1;
-    object_type ALIAS FOR $2;
-    creation_date ALIAS FOR $3;
-    creation_user ALIAS FOR $4;
-    creation_ip ALIAS FOR $5;
-    ...
-    v_user_id users.user_id%TYPE;
-    v_rel_id membership_rels.rel_id%TYPE;
-BEGIN
-    v_user_id := acs_user__new(user_id,object_type,creation_date,creation_user,creation_ip, ...);
-    ...
-
-    RETURN v_user_id;
-END;
-' LANGUAGE 'plpgsql';
-
+    This section explains a few other things to watch for when porting
+    Oracle PL/SQL functions to PostgreSQL.
    
-  
-
-  
-   </div> <div class="diff rem">-    Other Things to Watch For</div> <div class="diff rem">-   
 
    
-    <span class="marked">EXECUTE</span>
+    <span class="marked"><command>EXECUTE</command></span>
 
     
-     The PostgreSQL version of EXECUTE works
-     nicely, but you have to remember to use
-     quote_literal(TEXT) and
-     quote_string(TEXT) as described in 
-     linkend="plpgsql-statements-executing-dyn-queries">.  Constructs of the type
-     EXECUTE ''SELECT * from $1''; will not work
-     unless you use these functions.
+     The PL/pgSQL version of
+     EXECUTE works similar to the
+     PL/SQL version, but you have to remember to use
+     quote_literal(text) and
+     quote_string(text) as described in 
+     linkend="plpgsql-statements-executing-dyn">.  Constructs of the
+     type EXECUTE ''SELECT * FROM $1''; will not
+     work unless you use these functions.
     
    
 
@@ -3015,125 +2694,112 @@ END;
     Optimizing <application>PL/pgSQL</application> Functions
 
     
-     PostgreSQL gives you two function creation modifiers to optimize
-     execution: iscachable (function always returns
-     the same result when given the same arguments) and
-     isstrict (function returns NULL if any
-     argument is NULL).  Consult the CREATE
-     FUNCTION reference for details.
+     PostgreSQL gives you two function creation
+     modifiers to optimize execution: the volatility (whether the
+     function always returns the same result when given the same
+     arguments) and the strictness (whether the
+     function returns null if any argument is null).  Consult the description of
+     CREATE FUNCTION for details.
     
 
     
-     To make use of these optimization attributes, you have to use the
-     <literal>WITH modifier in your CREATE
-     FUNCTION statement.  Something like:
+     To make use of these optimization attributes, your
+     <command>CREATE FUNCTION statement could look something
+     like this:
 
 
-CREATE FUNCTION foo(...) RETURNS INTEGER AS '
+CREATE FUNCTION foo(...) RETURNS integer AS '
 ...
-' LANGUAGE 'plpgsql'
-WITH (isstrict, iscachable);
+' LANGUAGE plpgsql STRICT IMMUTABLE;
 
     
    
   
 
   
-   </div> <div class="diff rem">-    Appendix</div> <div class="diff rem">-   
-
-   
-    </div> <div class="diff rem">-     Code for my <function>instr</function> functions</div> <div class="diff rem">-    
+   Appendix
 
-    
-     This function should probably be integrated into the core.
-    
+   
+    This section contains the code for an Oracle-compatible
+    instr function that you can use to simplify
+    your porting efforts.
+   
 
 
 --
 -- instr functions that mimic Oracle's counterpart
--- Syntax: instr(string1,string2,[n],[m]) where [] denotes optional params.
+-- Syntax: instr(string1, string2, [n], [m]) where [] denotes optional parameters.
 -- 
--- Searches string1 beginning at the nth character for the mth
--- occurrence of string2. If n is negative, search backwards. If m is
--- not passed, assume 1 (search starts at first character).
---
--- by Roberto Mello ([email protected])
--- modified by Robert Gaszewski ([email protected])
--- Licensed under the GPL v2 or later.
+-- Searches string1 beginning at the nth character for the mth occurrence
+-- of string2.  If n is negative, search backwards.  If m is not passed,
+-- assume 1 (search starts at first character).
 --
 
-CREATE FUNCTION instr(VARCHAR,VARCHAR) RETURNS INTEGER AS '
+CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS '
 DECLARE
     pos integer;
 BEGIN
-    pos:= instr($1,$2,1);
+    pos:= instr($1, $2, 1);
     RETURN pos;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
 
-CREATE FUNCTION instr(VARCHAR,VARCHAR,INTEGER) RETURNS INTEGER AS '
+CREATE FUNCTION instr(varchar, varchar, varchar) RETURNS integer AS '
 DECLARE
     string ALIAS FOR $1;
     string_to_search ALIAS FOR $2;
     beg_index ALIAS FOR $3;
     pos integer NOT NULL DEFAULT 0;
-    temp_str VARCHAR;
-    beg INTEGER;
-    length INTEGER;
-    ss_length INTEGER;
+    temp_str varchar;
+    beg integer;
+    length integer;
+    ss_length integer;
 BEGIN
     IF beg_index > 0 THEN
+        temp_str := substring(string FROM beg_index);
+        pos := position(string_to_search IN temp_str);
 
-       temp_str := substring(string FROM beg_index);
-       pos := position(string_to_search IN temp_str);
-
-       IF pos = 0 THEN
-            RETURN 0;
-        ELSE
-            RETURN pos + beg_index - 1;
-        END IF;
+        IF pos = 0 THEN
+            RETURN 0;
+        ELSE
+            RETURN pos + beg_index - 1;
+        END IF;
     ELSE
-       ss_length := char_length(string_to_search);
-       length := char_length(string);
-       beg := length + beg_index - ss_length + 2;
+        ss_length := char_length(string_to_search);
+        length := char_length(string);
+        beg := length + beg_index - ss_length + 2;
 
-       WHILE beg > 0 LOOP
-           temp_str := substring(string FROM beg FOR ss_length);
-            pos := position(string_to_search IN temp_str);
+        WHILE beg > 0 LOOP
+            temp_str := substring(string FROM beg FOR ss_length);
+            pos := position(string_to_search IN temp_str);
+
+            IF pos > 0 THEN
+                RETURN beg;
+            END IF;
 
-            IF pos > 0 THEN
-                  RETURN beg;
-            END IF;
+            beg := beg - 1;
+        END LOOP;
 
-            beg := beg - 1;
-       END LOOP;
-       RETURN 0;
+        RETURN 0;
     END IF;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
---
--- Written by Robert Gaszewski ([email protected])
--- Licensed under the GPL v2 or later.
---
-CREATE FUNCTION instr(VARCHAR,VARCHAR,INTEGER,INTEGER) RETURNS INTEGER AS '
+
+CREATE FUNCTION instr(varchar, varchar, integer, integer) RETURNS integer AS '
 DECLARE
     string ALIAS FOR $1;
     string_to_search ALIAS FOR $2;
     beg_index ALIAS FOR $3;
     occur_index ALIAS FOR $4;
     pos integer NOT NULL DEFAULT 0;
-    occur_number INTEGER NOT NULL DEFAULT 0;
-    temp_str VARCHAR;
-    beg INTEGER;
-    i INTEGER;
-    length INTEGER;
-    ss_length INTEGER;
+    occur_number integer NOT NULL DEFAULT 0;
+    temp_str varchar;
+    beg integer;
+    i integer;
+    length integer;
+    ss_length integer;
 BEGIN
     IF beg_index > 0 THEN
         beg := beg_index;
@@ -3179,9 +2845,8 @@ BEGIN
         RETURN 0;
     END IF;
 END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
 
-   
   
   
  
index 7a36c074dca29a46fb62336649b8500b5cab28ad..6ec19c6e8eaf7a4a84fb89e9b86465c5f181fc9f 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  PL/Python - Python Procedural Language
   createlang plpython dbname.
  
 
+  
+   
+    If a language is installed into template1, all subsequently
+    created databases will have the language installed automatically.
+   
+  
+
  
   
    Users of source packages must specially enable the build of
-   PL/Python during the installation process (refer to the
-   installation instructions for more information).  Users of binary
+   PL/Python during the installation process.  (Refer to the
+   installation instructions for more information.)  Users of binary
    packages might find PL/Python in a separate subpackage.
   
  
   PL/Python Functions
 
   
-   The Python code you write gets transformed into a function.  E.g.,
+   The Python code you write gets transformed into a Python function.  E.g.,
 
 CREATE FUNCTION myfunc(text) RETURNS text
     AS 'return args[0]'
-    LANGUAGE 'plpython';
+    LANGUAGE plpython;
 
 
    gets transformed into
@@ -49,7 +56,7 @@ def __plpython_procedure_myfunc_23456():
 
   
    If you do not provide a return value, Python returns the default
-   None which may or may not be what you want.  The
+   None. The
    language module translates Python's None into the
    SQL null value.
   
@@ -60,8 +67,8 @@ def __plpython_procedure_myfunc_23456():
    myfunc example, args[0] contains
    whatever was passed in as the text argument.  For
    myfunc2(text, integer)args[0]
-   would contain the text variable and
-   args[1] the integer variable.
+   would contain the text argument and
+   args[1] the integer argument.
   
 
   
@@ -95,14 +102,14 @@ def __plpython_procedure_myfunc_23456():
    TD["level"] contains one of ROW,
    STATEMENT, and UNKNOWN.
    TD["name"] contains the trigger name, and
-   TD["relid"] contains the relation ID of the table on
+   TD["relid"] contains the OID of the table on
    which the trigger occurred.  If the trigger was called with
    arguments they are available in TD["args"][0] to
    TD["args"][(n-1)].
   
 
   
-   If the TD["when"] is BEFORE, you may
+   If TD["when"] is BEFORE, you may
    return None or "OK" from the
    Python function to indicate the row is unmodified,
    "SKIP" to abort the event, or "MODIFY" to
@@ -147,10 +154,10 @@ def __plpython_procedure_myfunc_23456():
    optional limit argument causes that query to be run and the result
    to be returned in a result object.  The result object emulates a
    list or dictionary object.  The result object can be accessed by
-   row number and field name.  It has these additional methods:
-   nrows() which returns the number of rows
+   row number and column name.  It has these additional methods:
+   nrows which returns the number of rows
    returned by the query, and status which is the
-   SPI_exec return variable.  The result object
+   SPI_exec() return value.  The result object
    can be modified.
   
 
@@ -161,27 +168,27 @@ rv = plpy.execute("SELECT * FROM my_table", 5)
 
    returns up to 5 rows from my_table.  If
    my_table has a column
-   my_field, it would be accessed as
+   my_column, it would be accessed as
 
-foo = rv[i]["my_field"]
+foo = rv[i]["my_column"]
 
   
 
   
-   The second function plpy.prepare is called
-   with a query string and a list of argument types if you have bind
-   variables in the query.  For example:
+   The second function, plpy.prepare, prepares the
+   execution plan for a query.  It is called with a query string and a
+   list of parameter types, if you have parameter references in the
+   query.  For example:
 
 plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", [ "text" ])
 
    text is the type of the variable you will be
-   passing as $1.  After preparing a statement, you
+   passing for $1.  After preparing a statement, you
    use the function plpy.execute to run it:
 
 rv = plpy.execute(plan, [ "name" ], 5)
 
-   The limit argument is optional in the call to
-   plpy.execute.
+   The third argument is the limit and is optional.
   
 
   
@@ -190,7 +197,7 @@ rv = plpy.execute(plan, [ "name" ], 5)
    in the immediate termination of that function by the server; it is
    not possible to trap error conditions using Python try
    ... catch constructs.  For example, a syntax error in an
-   SQL statement passed to the plpy.execute() call
+   SQL statement passed to the plpy.execute call
    will terminate the function.  This behavior may be changed in a
    future release.
   
@@ -199,22 +206,19 @@ rv = plpy.execute(plan, [ "name" ], 5)
    When you prepare a plan using the PL/Python module it is
    automatically saved.  Read the SPI documentation (
    linkend="spi">) for a description of what this means.
-  
-
-  
    In order to make effective use of this across function calls
    one needs to use one of the persistent storage dictionaries
-   SD or GDsee
-   . For example:
+   SD or GD (see
+   ). For example:
 
-CREATE FUNCTION usesavedplan ( ) RETURNS TRIGGER AS '
-   if SD.has_key("plan"):
-      plan = SD["plan"]
-   else:
-      plan = plpy.prepare("SELECT 1")
-      SD["plan"] = plan
-   # rest of function
-' LANGUAGE 'plpython';
+CREATE FUNCTION usesavedplan() RETURNS trigger AS '
+    if SD.has_key("plan"):
+        plan = SD["plan"]
+    else:
+        plan = plpy.prepare("SELECT 1")
+        SD["plan"] = plan
+    # rest of function
+' LANGUAGE plpython;
 
   
  
index ed724153bb405b14b4a1cdfccd98046474d5efad..f3b85952dbffad468cfc31c0cdb4dabc19c96291 100644 (file)
@@ -1,5 +1,5 @@
 
 
  
@@ -20,10 +20,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.22 2002/09/21 18:32:53 peter
    trigger procedures.
   
 
-  
-   This package was originally written by Jan Wieck.
-  
-
   
 
   
@@ -38,19 +34,19 @@ $Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.22 2002/09/21 18:32:53 peter
     Tcl interpreter. In addition to the limited command set of safe Tcl, only
     a few commands are available to access the database via SPI and to raise
     messages via elog(). There is no way to access internals of the
-    database backend or to gain OS-level access under the permissions of the
-    PostgreSQL user ID, as a C function can do.
+    database server or to gain OS-level access under the permissions of the
+    PostgreSQL server process, as a C function can do.
     Thus, any unprivileged database user may be
     permitted to use this language.
    
    
-    The other, implementation restriction is that Tcl procedures cannot
+    The other, implementation restriction is that Tcl functions cannot
     be used to create input/output functions for new data types.
    
    
     Sometimes it is desirable to write Tcl functions that are not restricted
-    to safe Tcl --- for example, one might want a Tcl function that sends
-    mail.  To handle these cases, there is a variant of PL/Tcl called PL/TclU
+    to safe Tcl.  For example, one might want a Tcl function that sends
+    email.  To handle these cases, there is a variant of PL/Tcl called PL/TclU
     (for untrusted Tcl).  This is the exact same language except that a full
     Tcl interpreter is used.  If PL/TclU is used, it must be
     installed as an untrusted procedural language so that only
@@ -66,7 +62,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.22 2002/09/21 18:32:53 peter
     library directory if Tcl/Tk support is specified
     in the configuration step of the installation procedure.  To install
     PL/Tcl and/or PL/TclU in a particular database, use the
-    <filename>createlang script, for example
+    <command>createlang program, for example
     createlang pltcl dbname or
     createlang pltclu dbname.
    
@@ -74,58 +70,59 @@ $Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.22 2002/09/21 18:32:53 peter
 
   
 
-  
-   Description
-
-   
+   
     PL/Tcl Functions and Arguments
 
     
-     To create a function in the PL/Tcl language, use the standard syntax
+     To create a function in the PL/Tcl language, use the standard syntax:
 
-     
+
 CREATE FUNCTION funcname (argument-types) RETURNS return-type AS '
     # PL/Tcl function body
-' LANGUAGE 'pltcl';
-     
+' LANGUAGE pltcl;
+
 
-     PL/TclU is the same, except that the language should be specified as
+     PL/TclU is the same, except that the language has to be specified as
      pltclu.
     
 
     
      The body of the function is simply a piece of Tcl script.
      When the function is called, the argument values are passed as
-     variables $1 ... $n to the
+     variables $1 ... $n to the
      Tcl script.  The result is returned
      from the Tcl code in the usual way, with a return
-     statement.  For example, a function
+     statement.
+    
+
+    
+     For example, a function
      returning the greater of two integer values could be defined as:
 
-     
-CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS '
+
+CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS '
     if {$1 > $2} {return $1}
     return $2
-' LANGUAGE 'pltcl' WITH (isStrict);
-     
+' LANGUAGE pltcl STRICT;
+
 
-     Note the clause WITH (isStrict), which saves us from
-     having to think about NULL input values: if a NULL is passed, the
-     function will not be called at all, but will just return a NULL
+     Note the clause STRICT, which saves us from
+     having to think about null input values: if a null value is passed, the
+     function will not be called at all, but will just return a null
      result automatically.
     
 
     
-     In a non-strict function,
-     if the actual value of an argument is NULL, the corresponding
-     $n variable will be set to an empty string.
-     To detect whether a particular argument is NULL, use the function
+     In a nonstrict function,
+     if the actual value of an argument is null, the corresponding
+     $n variable will be set to an empty string.
+     To detect whether a particular argument is null, use the function
      argisnull.  For example, suppose that we wanted tcl_max
-     with one null and one non-null argument to return the non-null
-     argument, rather than NULL:
+     with one null and one nonnull argument to return the nonnull
+     argument, rather than null:
 
-     
-CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS '
+
+CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS '
     if {[argisnull 1]} {
         if {[argisnull 2]} { return_null }
         return $2
@@ -133,8 +130,8 @@ CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS '
     if {[argisnull 2]} { return $1 }
     if {$1 > $2} {return $1}
     return $2
-' LANGUAGE 'pltcl';
-     
+' LANGUAGE pltcl;
+
     
 
     
@@ -145,15 +142,19 @@ CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS '
     
 
     
-     Composite-type arguments are passed to the procedure as Tcl arrays.
-     The element names of the array are the attribute names of the composite
-     type. If an attribute in the passed row
-     has the NULL value, it will not appear in the array! Here is
-     an example that defines the overpaid_2 function (as found in the
-     older PostgreSQL documentation) in PL/Tcl:
-
-     
-CREATE FUNCTION overpaid_2 (EMP) RETURNS bool AS '
+     Composite-type arguments are passed to the function as Tcl
+     arrays.  The element names of the array are the attribute names
+     of the composite type. If an attribute in the passed row has the
+     null value, it will not appear in the array. Here is an example:
+
+
+CREATE TABLE employee (
+    name text,
+    salary integer,
+    age integer
+);
+
+CREATE FUNCTION overpaid(employee) RETURNS boolean AS '
     if {200000.0 < $1(salary)} {
         return "t"
     }
@@ -161,110 +162,109 @@ CREATE FUNCTION overpaid_2 (EMP) RETURNS bool AS '
         return "t"
     }
     return "f"
-' LANGUAGE 'pltcl';
-     
+' LANGUAGE pltcl;
+
     
 
     
-     There is not currently any support for returning a composite-type
+     There is currently no support for returning a composite-type
      result value.
     
 
-   2>
+   1>
 
-   2>
+   1 id="pltcl-data">
     Data Values in PL/Tcl
 
     
-     The argument values supplied to a PL/Tcl function's script are simply
+     The argument values supplied to a PL/Tcl function's code are simply
      the input arguments converted to text form (just as if they had been
-     displayed by a SELECT statement).  Conversely, the return
+     displayed by a SELECT statement).  Conversely, the return
      command will accept any string that is acceptable input format for
      the function's declared return type.  So, the PL/Tcl programmer can
      manipulate data values as if they were just text.
     
 
-   2>
+   1>
 
-   2>
+   1 id="pltcl-global">
     Global Data in PL/Tcl
 
     
      Sometimes it
-     is useful to have some global status data that is held between two
-     calls to a procedure or is shared between different procedures.
+     is useful to have some global data that is held between two
+     calls to a function or is shared between different functions.
      This is easily done since
-     all PL/Tcl procedures executed in one backend share the same
+     all PL/Tcl functions executed in one session share the same
      safe Tcl interpreter.  So, any global Tcl variable is accessible to
-     all PL/Tcl procedure calls, and will persist for the duration of the
-     SQL client connection.  (Note that PL/TclU functions likewise share
+     all PL/Tcl function calls and will persist for the duration of the
+     SQL session.  (Note that PL/TclU functions likewise share
      global data, but they are in a different Tcl interpreter and cannot
      communicate with PL/Tcl functions.)
     
     
-     To help protect PL/Tcl procedures from unintentionally interfering
+     To help protect PL/Tcl functions from unintentionally interfering
      with each other, a global
-     array is made available to each procedure via the upvar
-     command. The global name of this variable is the procedure's internal
-     name and the local name is GD.  It is recommended that
+     array is made available to each function via the upvar
+     command. The global name of this variable is the function's internal
+     name, and the local name is GD.  It is recommended that
      GD be used
-     for private status data of a procedure.  Use regular Tcl global variables
+     for private data of a function.  Use regular Tcl global variables
      only for values that you specifically intend to be shared among multiple
-     procedures.
+     functions.
     
 
     
      An example of using GD appears in the
      spi_execp example below.
     
-   2>
+   1>
 
-   2>
+   1 id="pltcl-dbaccess">
     Database Access from PL/Tcl
 
     
      The following commands are available to access the database from
-     the body of a PL/Tcl procedure:
-    
+     the body of a PL/Tcl function:
 
     
 
      
-      spi_exec ?-count n? ?-array namequery ?loop-body?
+      spi_exec ?-count n? ?-array namecommand ?loop-body?
       
        
-   Execute an SQL query given as a string.  An error in the query
-   causes an error to be raised.  Otherwise, the command's return value
+   Executes an SQL command given as a string.  An error in the command
+   causes an error to be raised.  Otherwise, the return value of spi_exec
    is the number of rows processed (selected, inserted, updated, or
-   deleted) by the query, or zero if the query is a utility
-   statement.  In addition, if the query is a SELECT statement, the
+   deleted) by the command, or zero if the command is a utility
+   statement.  In addition, if the command is a SELECT statement, the
    values of the selected columns are placed in Tcl variables as
    described below.
        
        
    The optional -count value tells
    spi_exec the maximum number of rows
-   to process in the query.  The effect of this is comparable to
-   setting up the query as a cursor and then saying FETCH n.
+   to process in the command.  The effect of this is comparable to
+   setting up a query as a cursor and then saying FETCH n.
        
        
-   If the query is a SELECT statement, the values of the statement's
+   If the command is a SELECT statement, the values of the
    result columns are placed into Tcl variables named after the columns.
         If the -array option is given, the column values are
-   instead stored into the named associative array, with the SELECT
+   instead stored into the named associative array, with the
    column names used as array indexes.
        
        
-        If the query is a SELECT statement and no loop-body
+        If the command is a SELECT statement and no loop-body
    script is given, then only the first row of results are stored into
-   Tcl variables; remaining rows, if any, are ignored.  No store occurs
+   Tcl variables; remaining rows, if any, are ignored.  No storing occurs
    if the 
-   SELECT returns no rows (this case can be detected by checking the
-   result of spi_exec).  For example,
+   query returns no rows.  (This case can be detected by checking the
+   result of spi_exec.)  For example,
 
-   
+
 spi_exec "SELECT count(*) AS cnt FROM pg_proc"
-   
+
 
    will set the Tcl variable $cnt to the number of rows in
    the pg_proc system catalog.
@@ -272,23 +272,23 @@ spi_exec "SELECT count(*) AS cnt FROM pg_proc"
        
         If the optional loop-body argument is given, it is
    a piece of Tcl script that is executed once for each row in the
-   SELECT result (note: loop-body is ignored if the given
-   query is not a SELECT).  The values of the current row's fields
+   query result.  (loop-body is ignored if the given
+   command is not a SELECT.)  The values of the current row's columns
    are stored into Tcl variables before each iteration.  For example,
 
-   
+
 spi_exec -array C "SELECT * FROM pg_class" {
     elog DEBUG "have table $C(relname)"
 }
-   
+
 
-   will print a DEBUG log message for every row of pg_class.  This
+   will print a log message for every row of pg_class.  This
    feature works similarly to other Tcl looping constructs; in
    particular continue and break work in the
    usual way inside the loop body.
        
        
-        If a field of a SELECT result is NULL, the target
+        If a column of a query result is null, the target
    variable for it is unset rather than being set.
        
       
@@ -299,18 +299,18 @@ spi_exec -array C "SELECT * FROM pg_class" {
       
        
    Prepares and saves a query plan for later execution.  The saved plan
-   will be retained for the life of the current backend.
+   will be retained for the life of the current session.
        
        
-        The query may use arguments, which are placeholders for
+        The query may use parameters, that is, placeholders for
    values to be supplied whenever the plan is actually executed.
-   In the query string, refer to arguments
-   by the symbols $1 ... $n.
-   If the query uses arguments, the names of the argument types
+   In the query string, refer to parameters
+   by the symbols $1 ... $n.
+   If the query uses parameters, the names of the parameter types
    must be given as a Tcl list.  (Write an empty list for
-   typelist if no arguments are used.)
-   Presently, the argument types must be identified by the internal
-   type names shown in pg_type; for example int4 not
+   typelist if no parameters are used.)
+   Presently, the parameter types must be identified by the internal
+   type names shown in the system table pg_type; for example int4 not
    integer.
        
        
@@ -325,24 +325,24 @@ spi_exec -array C "SELECT * FROM pg_class" {
       spi_execp ?-count n? ?-array name? ?-nulls stringqueryid ?value-list? ?loop-body?
       
        
-   Execute a query previously prepared with spi_prepare.
+   Executes a query previously prepared with spi_prepare.
    queryid is the ID returned by
-   spi_prepare.  If the query references arguments,
-   a value-list must be supplied: this
-   is a Tcl list of actual values for the arguments.  This must be
-   the same length as the argument type list previously given to
+   spi_prepare.  If the query references parameters,
+   a value-list must be supplied.  This
+   is a Tcl list of actual values for the parameters.  The list must be
+   the same length as the parameter type list previously given to
    spi_prepare.  Omit value-list
-   if the query has no arguments.
+   if the query has no parameters.
        
        
    The optional value for -nulls is a string of spaces and
    'n' characters telling spi_execp
-   which of the arguments are null values. If given, it must have exactly the
+   which of the parameters are null values. If given, it must have exactly the
    same length as the value-list.  If it
-   is not given, all the argument values are non-NULL.
+   is not given, all the parameter values are nonnull.
        
        
-        Except for the way in which the query and its arguments are specified,
+        Except for the way in which the query and its parameters are specified,
    spi_execp works just like spi_exec.
         The -count, -array, and
    loop-body options are the same,
@@ -351,7 +351,7 @@ spi_exec -array C "SELECT * FROM pg_class" {
        
    Here's an example of a PL/Tcl function using a prepared plan:
 
-   
+
 CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS '
     if {![ info exists GD(plan) ]} {
         # prepare the saved plan on the first call
@@ -361,14 +361,14 @@ CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS '
     }
     spi_execp -count 1 $GD(plan) [ list $1 $2 ]
     return $cnt
-' LANGUAGE 'pltcl';
-   
+' LANGUAGE pltcl;
+
 
    Note that each backslash that Tcl should see must be doubled when
    we type in the function, since the main parser processes
-   backslashes too in CREATE FUNCTION.  We need backslashes inside
+   backslashes, too, in CREATE FUNCTION.  We need backslashes inside
    the query string given to spi_prepare to ensure that
-   the $n markers will be passed through to
+   the $n markers will be passed through to
    spi_prepare as-is, and not
    replaced by Tcl variable substitution.
        
@@ -383,8 +383,8 @@ CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS '
       
        
    Returns the OID of the row inserted by the last
-   spi_exec'd or spi_execp'd query,
-   if that query was a single-row INSERT.  (If not, you get zero.)
+   spi_exec or spi_execp,
+   if the command was a single-row INSERT.  (If not, you get zero.)
        
       
      
@@ -395,18 +395,18 @@ CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS '
        
    Duplicates all occurrences of single quote and backslash characters
    in the given string.  This may be used to safely quote strings
-   that are to be inserted into SQL queries given
+   that are to be inserted into SQL commands given
    to spi_exec or
    spi_prepare.
-   For example, think about a query string like
+   For example, think about an SQL command string like
 
 
 "SELECT '$val' AS ret"
 
 
-   where the Tcl variable val actually contains
+   where the Tcl variable val actually contains
    doesn't. This would result
-   in the final query string
+   in the final command string
 
 
 SELECT 'doesn't' AS ret
@@ -415,21 +415,21 @@ SELECT 'doesn't' AS ret
    which would cause a parse error during
    spi_exec or
    spi_prepare.
-   The submitted query should contain
+   The submitted command should contain
 
 
 SELECT 'doesn''t' AS ret
 
 
-   which can be formed in PL/Tcl as
+   which can be formed in PL/Tcl using
 
 
 "SELECT '[ quote $val ]' AS ret"
 
 
         One advantage of spi_execp is that you don't
-   have to quote argument values like this, since the arguments are never
-   parsed as part of an SQL query string.
+   have to quote parameter values like this, since the parameters are never
+   parsed as part of an SQL command string.
        
       
      
@@ -441,26 +441,27 @@ SELECT 'doesn''t' AS ret
       elog level msg
       
        
-   Emit a log or error message. Possible levels are
+   Emits a log or error message. Possible levels are
    DEBUG, LOG, INFO,
    NOTICE, WARNING, ERROR, and
    FATAL. Most simply emit the given message just like
-   the elog backend C function. ERROR
+   the elog C function. ERROR
    raises an error condition: further execution of the function is
    abandoned, and the current transaction is aborted.
    FATAL aborts the transaction and causes the current
-   backend to shut down (there is probably no good reason to use
+   session to shut down.  (There is probably no good reason to use
    this error level in PL/Tcl functions, but it's provided for
-   completeness).
+   completeness.)
        
       
      
 
     
+    
 
-   2>
+   1>
 
-   2>
+   1 id="pltcl-trigger">
     Trigger Procedures in PL/Tcl
 
     
@@ -469,8 +470,8 @@ SELECT 'doesn''t' AS ret
     
 
     
-     Trigger procedures can be written in PL/Tcl.  As is customary in
-     PostgreSQL, a procedure that's to be called
+     Trigger procedures can be written in PL/Tcl.
+     PostgreSQL requires that a procedure that is to be called
      as a trigger must be declared as a function with no arguments
      and a return type of trigger.
     
@@ -481,16 +482,16 @@ SELECT 'doesn''t' AS ret
      
 
       
-       <replaceable class="Parameter">$TG_namee>
+       <varname>$TG_namee>
        
    
-    The name of the trigger from the CREATE TRIGGER statement.
+    The name of the trigger from the CREATE TRIGGER statement.
    
        
       
 
       
-       <replaceable class="Parameter">$TG_relide>
+       <varname>$TG_relide>
        
    
     The object ID of the table that caused the trigger procedure
@@ -500,20 +501,20 @@ SELECT 'doesn''t' AS ret
       
 
       
-       <replaceable class="Parameter">$TG_relattse>
+       <varname>$TG_relattse>
        
    
-    A Tcl list of the table field names, prefixed with an empty list
-         element. So looking up an element name in the list with Tcl's
+    A Tcl list of the table column names, prefixed with an empty list
+         element. So looking up a column name in the list with Tcl's
          lsearch command returns the element's number starting
-    with 1 for the first column, the same way the fields are customarily
+    with 1 for the first column, the same way the columns are customarily
     numbered in PostgreSQL.
    
        
       
 
       
-       <replaceable class="Parameter">$TG_whene>
+       <varname>$TG_whene>
        
    
     The string BEFORE or AFTER depending on the
@@ -523,7 +524,7 @@ SELECT 'doesn''t' AS ret
       
 
       
-       <replaceable class="Parameter">$TG_levele>
+       <varname>$TG_levele>
        
    
     The string ROW or STATEMENT depending on the
@@ -533,44 +534,46 @@ SELECT 'doesn''t' AS ret
       
 
       
-       <replaceable class="Parameter">$TG_ope>
+       <varname>$TG_ope>
        
    
-    The string INSERT, UPDATE or
+    The string INSERT, UPDATE, or
     DELETE depending on the type of trigger call.
    
        
       
 
       
-       <replaceable class="Parameter">$NEWe>
+       <varname>$NEWe>
        
    
-    An associative array containing the values of the new table row for
-    INSERT/UPDATE actions, or empty for DELETE.  The array is indexed
-    by field name.  Fields that are NULL will not appear in the array!
+    An associative array containing the values of the new table
+    row for INSERT or UPDATE actions, or
+    empty for DELETE.  The array is indexed by column
+    name.  Columns that are null will not appear in the array.
    
        
       
 
       
-       <replaceable class="Parameter">$OLDe>
+       <varname>$OLDe>
        
    
-    An associative array containing the values of the old table row for
-    UPDATE/DELETE actions, or empty for INSERT.  The array is indexed
-    by field name.  Fields that are NULL will not appear in the array!
+    An associative array containing the values of the old table
+    row for UPDATE or DELETE actions, or
+    empty for INSERT.  The array is indexed by column
+    name.  Columns that are null will not appear in the array.
    
        
       
 
       
-       <replaceable class="Parameter">$argse>
+       <varname>$argse>
        
    
     A Tcl list of the arguments to the procedure as given in the
-    CREATE TRIGGER statement. These arguments are also accessible as
-    $1 ... $n in the procedure body.
+    CREATE TRIGGER statement. These arguments are also accessible as
+    $1 ... $n in the procedure body.
    
        
       
@@ -582,22 +585,22 @@ SELECT 'doesn''t' AS ret
      The return value from a trigger procedure can be one of the strings
      OK or SKIP, or a list as returned by the
      array get Tcl command. If the return value is OK,
-     the operation (INSERT/UPDATE/DELETE) that fired the trigger will proceed
+     the operation (INSERT/UPDATE/DELETE) that fired the trigger will proceed
      normally. SKIP tells the trigger manager to silently suppress
      the operation for this row. If a list is returned, it tells PL/Tcl to
      return a modified row to the trigger manager that will be inserted
-     instead of the one given in $NEW (this works for INSERT/UPDATE
-     only). Needless to say that all this is only meaningful when the trigger
-     is BEFORE and FOR EACH ROW; otherwise the return value is ignored.
+     instead of the one given in $NEW.  (This works for INSERT and UPDATE
+     only.) Needless to say that all this is only meaningful when the trigger
+     is BEFORE and FOR EACH ROW; otherwise the return value is ignored.
     
     
      Here's a little example trigger procedure that forces an integer value
      in a table to keep track of the number of updates that are performed on the
      row. For new rows inserted, the value is initialized to 0 and then
-     incremented on every update operation:
+     incremented on every update operation.
 
-     
-CREATE FUNCTION trigfunc_modcount() RETURNS TRIGGER AS '
+
+CREATE FUNCTION trigfunc_modcount() RETURNS trigger AS '
     switch $TG_op {
         INSERT {
             set NEW($1) 0
@@ -611,24 +614,24 @@ CREATE FUNCTION trigfunc_modcount() RETURNS TRIGGER AS '
         }
     }
     return [array get NEW]
-' LANGUAGE 'pltcl';
+' LANGUAGE pltcl;
 
 CREATE TABLE mytab (num integer, description text, modcnt integer);
 
 CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
     FOR EACH ROW EXECUTE PROCEDURE trigfunc_modcount('modcnt');
-     
+
 
      Notice that the trigger procedure itself does not know the column
      name; that's supplied from the trigger arguments.  This lets the
-     trigger procedure be re-used with different tables.
+     trigger procedure be reused with different tables.
     
-   2>
+   1>
 
-   2>
-       <span class="marked"> </span>Modules and the <function>unknown</> command
+   1 id="pltcl-unknown">
+       Modules and the <function>unknown</> command
        
-   PL/Tcl has support for auto-loading Tcl code when used.
+   PL/Tcl has support for autoloading Tcl code when used.
    It recognizes a special table, pltcl_modules, which
    is presumed to contain modules of Tcl code.  If this table
    exists, the module unknown is fetched from the table
@@ -638,7 +641,7 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
        
         While the unknown module could actually contain any
    initialization script you need, it normally defines a Tcl
-   <quote>unknown procedure that is invoked whenever Tcl does
+   <function>unknown procedure that is invoked whenever Tcl does
    not recognize an invoked procedure name.  PL/Tcl's standard version
    of this procedure tries to find a module in pltcl_modules
    that will define the required procedure.  If one is found, it is
@@ -653,7 +656,7 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
    support scripts to maintain these tables:
    pltcl_loadmod, pltcl_listmod,
    pltcl_delmod, as well as source for the standard
-   unknown module share/unknown.pltcl.  This module
+   unknown module in share/unknown.pltcl.  This module
    must be loaded
    into each database initially to support the autoloading mechanism.
        
@@ -662,9 +665,9 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
    must be readable by all, but it is wise to make them owned and
    writable only by the database administrator.
        
-   2>
+   1>
 
-   2>
+   1 id="pltcl-procnames">
     Tcl Procedure Names
 
     
@@ -674,16 +677,14 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
      differ. Tcl, however, requires all procedure names to be distinct.
      PL/Tcl deals with this by making the internal Tcl procedure names contain
      the object 
-     ID of the procedure's pg_proc row as part of their name. Thus,
+     ID of the function from the system table pg_proc as part of their name. Thus,
      PostgreSQL functions with the same name
-     and different argument types will be different Tcl procedures too.  This
+     and different argument types will be different Tcl procedures, too.  This
      is not normally a concern for a PL/Tcl programmer, but it might be visible
      when debugging.
     
 
-   
-
-  
+   
  
 
 
+
 
 
  <application>PyGreSQL</application> - <application>Python</application> Interface
@@ -334,13 +334,10 @@ make && make install
   API at 
   url="http://www.python.org/topics/database/DatabaseAPI-2.0.html"
   >http://www.python.org/topics/database/DatabaseAPI-2.0.html.
-
   A tutorial-like introduction to the DB-API can be
   found at 
   url="http://www2.linuxjournal.com/lj-issues/issue49/2605.html"
-  >http://www2.linuxjournal.com/lj-issues/issue49/2605.html
+  >http://www2.linuxjournal.com/lj-issues/issue49/2605.html.
  
 
  
@@ -365,16 +362,15 @@ make && make install
 
     
      
-      pgqueryobject that handles query results.
+      pgqueryobject, which handles query results.
      
     
    
   
 
   
-   If you want to see a simple example of the use of some of these
-   functions, see 
-   >http://www.druid.net/rides where you can find a link at the
+   If you want to see a simple example of the use this module,
+   see  where you can find a link at the
    bottom to the actual Python code for the
    page.
   
@@ -395,9 +391,9 @@ make && make install
       INV_WRITE
       
        
-        large objects access modes, used by
+        Large objects access modes, used by
         (pgobject.)locreate and
-        (pglarge.)open.
+        (pglarge.)open
        
       
      
@@ -408,7 +404,7 @@ make && make install
       SEEK_END
       
        
-        positional flags, used by (pglarge.)seek.
+        Positional flags, used by (pglarge.)seek
        
       
      
@@ -418,7 +414,7 @@ make && make install
       __version__
       
        
-        constants that give the current version
+        Constants that give the current version
        
       
      
@@ -443,13 +439,13 @@ make && make install
    to handle general connection parameters without heavy code in your
    programs. You can prompt the user for a value, put it in the
    default variable, and forget it, without having to modify your
-   environment. The support for default variables can be disabled by
+   environment. The support for default variables can be disabled at build time by
    setting the  option in the Python
    Setup file. Methods relative to this are specified by the tag [DV].
   
 
   
-   All variables are set to None at module
+   All default values are set to None at module
    initialization, specifying that standard environment variables
    should be used.
   
@@ -478,7 +474,7 @@ connect(dbname
        dbname
 
        
-        Name of connected database (string/None).
+        Name of connected database (string/None)
        
       
 
@@ -486,7 +482,7 @@ connect(dbname
        host
 
        
-        Name of the server host (string/None).
+        Name of the server host (string/None)
        
       
 
@@ -494,7 +490,7 @@ connect(dbname
        port
 
        
-        Port used by the database server (integer/-1).
+        Port used by the database server (integer/-1)
        
       
 
@@ -503,7 +499,7 @@ connect(dbname
 
        
         
-         Options for the server (string/None).
+         Options for the server (string/None)
         
        
       
@@ -513,8 +509,8 @@ connect(dbname
 
        
         
-         File or tty for optional debug output from backend
-         (string/None).
+         File or TTY for optional debug output from server
+         (string/None)
         
        
       
@@ -524,7 +520,7 @@ connect(dbname
 
        
         
-         PostgreSQL user (string/None).
+         PostgreSQL user (string/None)
         
        
       
@@ -533,7 +529,7 @@ connect(dbname
        passwd
 
        
-        Password for user (string/None).
+        Password for user (string/None)
        
       
      
@@ -601,12 +597,11 @@ connect(dbname
 
     
      This method opens a connection to a specified database on a given
-     PostgreSQL server. You can use
-     key words here, as described in the
-     Python tutorial.  The names of the
+     PostgreSQL server. The arguments can be
+     given using key words here.  The names of the
      key words are the name of the parameters given in the syntax
      line. For a precise description of the parameters, please refer
-     to the PostgreSQL user manual.
+     to .
     
    
       
index 6e9e81c88cc65839a576ee49112660333b5d3616..26e05528b5f09f60868c288c67c5d9634a07af09 100644 (file)
@@ -1,13 +1,10 @@
 
 
  
   Procedural Languages
 
-  
-   Introduction
-
   
    PostgreSQL allows users to add new
    programming languages to be available for writing functions and
@@ -21,7 +18,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xplang.sgml,v 1.20 2003/01/31 00:10:51 tgl
    could serve as glue between
    PostgreSQL and an existing implementation
    of a programming language.  The handler itself is a special
-   programming language function compiled into a shared object and
+   C language function compiled into a shared object and
    loaded on demand.
   
 
@@ -31,7 +28,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xplang.sgml,v 1.20 2003/01/31 00:10:51 tgl
    available in the standard PostgreSQL
    distribution, which can serve as examples.
   
-  
 
   
    Installing Procedural Languages
@@ -39,22 +35,24 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xplang.sgml,v 1.20 2003/01/31 00:10:51 tgl
    
     A procedural language must be installed into each
     database where it is to be used.  But procedural languages installed in
-    the template1 database are automatically available in all
+    the database template1 are automatically available in all
     subsequently created databases. So the database administrator can
-    decide which languages are available in which databases, and can make
+    decide which languages are available in which databases and can make
     some languages available by default if he chooses.
    
 
    
     For the languages supplied with the standard distribution, the
-    shell script createlang may be used instead
-    of carrying out the details by hand.  For example, to install PL/pgSQL
-    into the template1 database, use
+    program createlang may be used to install the
+    language instead of carrying out the details by hand.  For
+    example, to install the language
+    PL/pgSQL into the database
+    template1, use
 
 createlang plpgsql template1
 
     The manual procedure described below is only recommended for
-    installing custom languages that <filename>createlang>
+    installing custom languages that <command>createlang>
     does not know about.
    
 
@@ -64,8 +62,11 @@ createlang plpgsql template1
     
 
     
-     A procedural language is installed in the database in three
-     steps, which must be carried out by a database superuser.
+     A procedural language is installed in a database in three steps,
+     which must be carried out by a database superuser.  The
+     createlang programm automates 
+     linkend="xplang-install-cr1"> and 
+     linkend="xplang-install-cr2">.
     
 
     
@@ -81,12 +82,13 @@ createlang plpgsql template1
      
       The handler must be declared with the command
 
-CREATE FUNCTION handler_function_name ()
-    RETURNS LANGUAGE_HANDLER AS
-    'path-to-shared-object' LANGUAGE C;
+CREATE FUNCTION handler_function_name()
+    RETURNS language_handler
+    AS 'path-to-shared-object'
+    LANGUAGE C;
 
-      The special return type of LANGUAGE_HANDLER tells
-      the database that this function does not return one of
+      The special return type of language_handler tells
+      the database system that this function does not return one of
       the defined SQL data types and is not directly usable
       in SQL statements.
      
@@ -99,7 +101,7 @@ CREATE FUNCTION handler_function_name ()
 CREATE TRUSTED PROCEDURAL LANGUAGE language-name
     HANDLER handler_function_name;
 
-      The optional key word TRUSTED tells whether
+      The optional key word TRUSTED specifies that
       ordinary database users that have no superuser privileges should
       be allowed to use this language to create functions and trigger
       procedures. Since PL functions are executed inside the database
@@ -119,20 +121,12 @@ CREATE TRUSTED PROCEDURAL LANGUAGE 
    
 
    
-    In a default PostgreSQL installation,
-    the handler for the PL/pgSQL language
-    is built and installed into the library
-    directory. If Tcl/Tk support is configured in, the handlers for
-    PL/Tcl and PL/TclU are also built and installed in the same
-    location.  Likewise, the PL/Perl and PL/PerlU handlers are built
-    and installed if Perl support is configured, and PL/Python is
-    installed if Python support is configured.  The
-    createlang script automates 
-    linkend="xplang-install-cr1"> and 
-    linkend="xplang-install-cr2"> described above.
+     shows how the manual
+    installation procedure would work with the language
+    PL/pgSQL.
    
 
-   
+    id="xplang-install-example">
     Manual Installation of <application>PL/pgSQL</application>
 
      
@@ -140,7 +134,7 @@ CREATE TRUSTED PROCEDURAL LANGUAGE 
       shared object for the PL/pgSQL language's call handler function.
 
 
-CREATE FUNCTION plpgsql_call_handler () RETURNS LANGUAGE_HANDLER AS
+CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler AS
     '$libdir/plpgsql' LANGUAGE C;
 
      
@@ -157,6 +151,17 @@ CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
      
   
 
+   
+    In a default PostgreSQL installation,
+    the handler for the PL/pgSQL language
+    is built and installed into the library
+    directory. If Tcl/Tk support is configured in, the handlers for
+    PL/Tcl and PL/TclU are also built and installed in the same
+    location.  Likewise, the PL/Perl and PL/PerlU handlers are built
+    and installed if Perl support is configured, and PL/Python is
+    installed if Python support is configured.
+   
+