Thread: Re: BUG #15977: Inconsistent behavior in chained transactions

Re: BUG #15977: Inconsistent behavior in chained transactions

From
Peter Eisentraut
Date:
On 2019-08-29 16:58, Fabien COELHO wrote:
> 
>> Thanks, I got it. I have never made a patch before so I'll keep it in my 
>> mind. Self-contained patch is now attached.
> 
> v3 applies, compiles, "make check" ok.
> 
> I turned it ready on the app.

Should we make it an error instead of a warning?

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services



Re: BUG #15977: Inconsistent behavior in chained transactions

From
Fabien COELHO
Date:
>> v3 applies, compiles, "make check" ok.
>>
>> I turned it ready on the app.
>
> Should we make it an error instead of a warning?

ISTM that it made sense to have the same behavior as out of transaction 
COMMIT or ROLLBACK.

-- 
Fabien.



Re: BUG #15977: Inconsistent behavior in chained transactions

From
fn ln
Date:
We have three options:
  1. Prohibit AND CHAIN outside a transaction block, but do nothing in plain COMMIT/ROLLBACK or AND NO CHAIN.
  2. Deal "there is no transaction in progress" (and "there is already a transaction in progress" if needed) as an error.
  3. Leave as it is.

Option 1 makes overall behavior more inconsistent, and option 2 might cause the backward-compatibility issues.
So I think 3 is a better solution for now.

2019年9月3日(火) 18:55 Peter Eisentraut <peter.eisentraut@2ndquadrant.com>:
On 2019-08-29 16:58, Fabien COELHO wrote:
>
>> Thanks, I got it. I have never made a patch before so I'll keep it in my
>> mind. Self-contained patch is now attached.
>
> v3 applies, compiles, "make check" ok.
>
> I turned it ready on the app.

Should we make it an error instead of a warning?

--
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Re: BUG #15977: Inconsistent behavior in chained transactions

From
Andres Freund
Date:
Hi,

On 2019-09-03 11:54:57 +0200, Peter Eisentraut wrote:
> On 2019-08-29 16:58, Fabien COELHO wrote:
> > 
> >> Thanks, I got it. I have never made a patch before so I'll keep it in my 
> >> mind. Self-contained patch is now attached.
> > 
> > v3 applies, compiles, "make check" ok.
> > 
> > I turned it ready on the app.

I don't think is quite sufficient. Note that the same problem also
exists for commits, one just needs force the commit to be part of a
multi-statement implicit transaction (i.e. a simple protocol exec /
PQexec(), with multiple statements).

E.g.:

postgres[32545][1]=# ROLLBACK;
WARNING:  25P01: there is no transaction in progress
LOCATION:  UserAbortTransactionBlock, xact.c:3914
ROLLBACK
Time: 0.790 ms
postgres[32545][1]=# SELECT 1\;COMMIT AND CHAIN;
WARNING:  25P01: there is no transaction in progress
LOCATION:  EndTransactionBlock, xact.c:3728
COMMIT
Time: 0.945 ms
postgres[32545][1]*=# COMMIT ;
COMMIT
Time: 0.539 ms

the \; bit forces psql to not split command into two separate protocol
level commands, but to submit them together.


> Should we make it an error instead of a warning?

Yea, I think for AND CHAIN we have to either error, or always start a
new transaction. I can see arguments for both, as long as it's
consistent.

The historical behaviour of issuing only WARNINGS when issuing COMMIT or
ROLLBACK outside of an explicit transaction seems to weigh in favor of
not erroring. Given that the result of such a transaction command is not
an error, the AND CHAIN portion should work.

Additionally, we actually have COMMIT; ROLLBACK; PREPARE TRANSACTION all
work meaningfully for implicit transactions. E.g.:

postgres[32545][1]=# CREATE TABLE test()\; PREPARE TRANSACTION 'frak';
WARNING:  25P01: there is no transaction in progress
LOCATION:  EndTransactionBlock, xact.c:3728
PREPARE TRANSACTION
Time: 15.094 ms
postgres[32545][1]=# \d test
Did not find any relation named "test".
postgres[32545][1]=# COMMIT PREPARED 'frak';
COMMIT PREPARED
Time: 4.727 ms
postgres[32545][1]=# \d test
               Table "public.test"
┌────────┬──────┬───────────┬──────────┬─────────┐
│ Column │ Type │ Collation │ Nullable │ Default │
├────────┼──────┼───────────┼──────────┼─────────┤
└────────┴──────┴───────────┴──────────┴─────────┘


The argument in the other direction is that not erroring out hides bugs,
like an accidentally already committed transaction (which is
particularly bad for ROLLBACK). We can't easily change that for plain
COMMIT/ROLLBACK due to backward compat concerns, but for COMMIT|ROLLBACK
AND CHAIN there's no such such concern.

I think there's an argument that we ought to behave differently for
COMMIT/ROLLBACK/PREPARE in implicit transactions where multiple commands
exist, and ones where that's not the case. Given that they all actually
have an effect if there's a preceding statement in the implicit
transaction, the WARNING doesn't actually seem that appropriate?

There's some arguments that it's sometimes useful to be able to force
committing an implicit transaction. Consider e.g. executing batch schema
modifications with some sensitivity to latency (and thus wanting to use
reduce latency by executing multiple statements via one protocol
message). There's a few cases where committing earlier is quite useful
in that scenario, e.g.:

CREATE TYPE test_enum AS ENUM ('a', 'b', 'c');
CREATE TABLE uses_test_enum(v test_enum);

without explicit commit:

postgres[32545][1]=# ALTER TYPE test_enum ADD VALUE 'd'\;INSERT INTO uses_test_enum VALUES('d');
ERROR:  55P04: unsafe use of new value "d" of enum type test_enum
LINE 1: ...t_enum ADD VALUE 'd';INSERT INTO uses_test_enum VALUES('d');
                                                                  ^
HINT:  New enum values must be committed before they can be used.
LOCATION:  check_safe_enum_use, enum.c:98


with explicit commit:

postgres[32545][1]=# ALTER TYPE test_enum ADD VALUE 'd'\;COMMIT\;INSERT INTO uses_test_enum VALUES('d');
WARNING:  25P01: there is no transaction in progress
LOCATION:  EndTransactionBlock, xact.c:3728
INSERT 0 1

There's also the case that one might want to batch execute statements,
but not have to redo them if a later command fails.

Greetings,

Andres Freund



Re: BUG #15977: Inconsistent behavior in chained transactions

From
fn ln
Date:
I made another patch for suggested behavior (COMMIT/ROLLBACK AND CHAIN now gives us an error when used in an implicit block).

2019年9月4日(水) 16:53 Andres Freund <andres@anarazel.de>:
Hi,

On 2019-09-03 11:54:57 +0200, Peter Eisentraut wrote:
> On 2019-08-29 16:58, Fabien COELHO wrote:
> >
> >> Thanks, I got it. I have never made a patch before so I'll keep it in my
> >> mind. Self-contained patch is now attached.
> >
> > v3 applies, compiles, "make check" ok.
> >
> > I turned it ready on the app.

I don't think is quite sufficient. Note that the same problem also
exists for commits, one just needs force the commit to be part of a
multi-statement implicit transaction (i.e. a simple protocol exec /
PQexec(), with multiple statements).

E.g.:

postgres[32545][1]=# ROLLBACK;
WARNING:  25P01: there is no transaction in progress
LOCATION:  UserAbortTransactionBlock, xact.c:3914
ROLLBACK
Time: 0.790 ms
postgres[32545][1]=# SELECT 1\;COMMIT AND CHAIN;
WARNING:  25P01: there is no transaction in progress
LOCATION:  EndTransactionBlock, xact.c:3728
COMMIT
Time: 0.945 ms
postgres[32545][1]*=# COMMIT ;
COMMIT
Time: 0.539 ms

the \; bit forces psql to not split command into two separate protocol
level commands, but to submit them together.


> Should we make it an error instead of a warning?

Yea, I think for AND CHAIN we have to either error, or always start a
new transaction. I can see arguments for both, as long as it's
consistent.

The historical behaviour of issuing only WARNINGS when issuing COMMIT or
ROLLBACK outside of an explicit transaction seems to weigh in favor of
not erroring. Given that the result of such a transaction command is not
an error, the AND CHAIN portion should work.

Additionally, we actually have COMMIT; ROLLBACK; PREPARE TRANSACTION all
work meaningfully for implicit transactions. E.g.:

postgres[32545][1]=# CREATE TABLE test()\; PREPARE TRANSACTION 'frak';
WARNING:  25P01: there is no transaction in progress
LOCATION:  EndTransactionBlock, xact.c:3728
PREPARE TRANSACTION
Time: 15.094 ms
postgres[32545][1]=# \d test
Did not find any relation named "test".
postgres[32545][1]=# COMMIT PREPARED 'frak';
COMMIT PREPARED
Time: 4.727 ms
postgres[32545][1]=# \d test
               Table "public.test"
┌────────┬──────┬───────────┬──────────┬─────────┐
│ Column │ Type │ Collation │ Nullable │ Default │
├────────┼──────┼───────────┼──────────┼─────────┤
└────────┴──────┴───────────┴──────────┴─────────┘


The argument in the other direction is that not erroring out hides bugs,
like an accidentally already committed transaction (which is
particularly bad for ROLLBACK). We can't easily change that for plain
COMMIT/ROLLBACK due to backward compat concerns, but for COMMIT|ROLLBACK
AND CHAIN there's no such such concern.

I think there's an argument that we ought to behave differently for
COMMIT/ROLLBACK/PREPARE in implicit transactions where multiple commands
exist, and ones where that's not the case. Given that they all actually
have an effect if there's a preceding statement in the implicit
transaction, the WARNING doesn't actually seem that appropriate?

There's some arguments that it's sometimes useful to be able to force
committing an implicit transaction. Consider e.g. executing batch schema
modifications with some sensitivity to latency (and thus wanting to use
reduce latency by executing multiple statements via one protocol
message). There's a few cases where committing earlier is quite useful
in that scenario, e.g.:

CREATE TYPE test_enum AS ENUM ('a', 'b', 'c');
CREATE TABLE uses_test_enum(v test_enum);

without explicit commit:

postgres[32545][1]=# ALTER TYPE test_enum ADD VALUE 'd'\;INSERT INTO uses_test_enum VALUES('d');
ERROR:  55P04: unsafe use of new value "d" of enum type test_enum
LINE 1: ...t_enum ADD VALUE 'd';INSERT INTO uses_test_enum VALUES('d');
                                                                  ^
HINT:  New enum values must be committed before they can be used.
LOCATION:  check_safe_enum_use, enum.c:98


with explicit commit:

postgres[32545][1]=# ALTER TYPE test_enum ADD VALUE 'd'\;COMMIT\;INSERT INTO uses_test_enum VALUES('d');
WARNING:  25P01: there is no transaction in progress
LOCATION:  EndTransactionBlock, xact.c:3728
INSERT 0 1

There's also the case that one might want to batch execute statements,
but not have to redo them if a later command fails.

Greetings,

Andres Freund
Attachment

Re: BUG #15977: Inconsistent behavior in chained transactions

From
Peter Eisentraut
Date:
On 2019-09-04 16:49, fn ln wrote:
> I made another patch for suggested behavior (COMMIT/ROLLBACK AND CHAIN
> now gives us an error when used in an implicit block).

I'm content with this patch.  Better disable questionable cases now and
maybe re-enable them later if someone wants to make a case for it.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services



Re: BUG #15977: Inconsistent behavior in chained transactions

From
Andres Freund
Date:
Hi,


On 2019-09-05 14:16:11 +0200, Peter Eisentraut wrote:
> On 2019-09-04 16:49, fn ln wrote:
> > I made another patch for suggested behavior (COMMIT/ROLLBACK AND CHAIN
> > now gives us an error when used in an implicit block).
> 
> I'm content with this patch.

Would need tests.


> Better disable questionable cases now and maybe re-enable them later
> if someone wants to make a case for it.

I do think the fact that COMMIT in multi-statement implicit transaction
has some usecase, is an argument for just implementing it properly...


Greetings,

Andres Freund



Re: BUG #15977: Inconsistent behavior in chained transactions

From
Michael Paquier
Date:
On Thu, Sep 05, 2019 at 02:11:35PM -0700, Andres Freund wrote:
> On 2019-09-05 14:16:11 +0200, Peter Eisentraut wrote:
>> I'm content with this patch.
>
> Would need tests.

The latest patch sends adds coverage for all the new code paths
added.  Do you have something else in mind?

>> Better disable questionable cases now and maybe re-enable them later
>> if someone wants to make a case for it.
>
> I do think the fact that COMMIT in multi-statement implicit transaction
> has some usecase, is an argument for just implementing it properly...

Like Peter, I would also keep an ERROR for now, as we could always
relax that later on.

Looking at the latest patch, the comment blocks on top of TBLOCK_STARTED
and TBLOCK_IMPLICIT_INPROGRESS in EndTransactionBlock() need an update
to mention the difference of behavior with chained transactions.  And
the same comment rework should be done in UserAbortTransactionBlock()
for TBLOCK_IMPLICIT_INPROGRESS/TBLOCK_STARTED?
--
Michael

Attachment

Re: BUG #15977: Inconsistent behavior in chained transactions

From
Fabien COELHO
Date:
Hello,

>> I do think the fact that COMMIT in multi-statement implicit transaction
>> has some usecase, is an argument for just implementing it properly...
>
> Like Peter, I would also keep an ERROR for now, as we could always
> relax that later on.

I can agree with both warning and error, but for me the choice should be 
consistent with the current behavior of COMMIT and ROLLBACK in the same 
context.

  pg> CREATE OR REPLACE PROCEDURE warn(msg TEXT) LANGUAGE plpgsql AS
      $$ BEGIN RAISE WARNING 'warning: %', msg ; END ; $$;

Then an out-of-transaction multi-statement commit:

  pg> CALL warn('1') \; COMMIT \; CALL warn('2') ;
    WARNING:  warning: 1
    WARNING:  there is no transaction in progress
    WARNING:  warning: 2
    CALL

But v4 creates an non uniform behavior that I find surprising and 
unwelcome:

  pg> CALL warn('1') \; COMMIT AND CHAIN \; CALL warn('2') ;
    WARNING:  warning: 1
    ERROR:  COMMIT AND CHAIN can only be used in transaction blocks

Why "commit" & "commit and chain" should behave differently in the same 
context? For me they can error or warn, but consistency implies that they 
should do the exact same thing.

From a user perspective, I really want to know if a commit did not do what 
I thought, and I'm certainly NOT expecting the stuff I sent to go on as if 
nothing happened. Basically I agree with everybody that raising an error 
is the right behavior in this case, which suggest that out-of-transaction 
commit and rollback should error.

So my opinion is that commit & rollback issued out-of-transaction should 
also generate an error.

If it is too much a change and potential regression, then I think that the 
"and chain" variants should be consistent and just raise warnings.

-- 
Fabien.



Re: BUG #15977: Inconsistent behavior in chained transactions

From
fn ln
Date:
> Looking at the latest patch, the comment blocks on top of TBLOCK_STARTED
> and TBLOCK_IMPLICIT_INPROGRESS in EndTransactionBlock() need an update
> to mention the difference of behavior with chained transactions.  And
> the same comment rework should be done in UserAbortTransactionBlock()
> for TBLOCK_IMPLICIT_INPROGRESS/TBLOCK_STARTED?
I made another patch for that.
I don't have much confidence with my English spelling so further improvements may be needed.

> If it is too much a change and potential regression, then I think that the
> "and chain" variants should be consistent and just raise warnings.
We don't have an exact answer for implicit transaction chaining behavior yet.
So I think it's better to disable this feature until someone discovers the use cases for this.
Permitting AND CHAIN without a detailed specification might cause troubles in future.
Attachment

Re: BUG #15977: Inconsistent behavior in chained transactions

From
Andres Freund
Date:
Hi,

On 2019-09-06 16:54:15 +0900, Michael Paquier wrote:
> On Thu, Sep 05, 2019 at 02:11:35PM -0700, Andres Freund wrote:
> > On 2019-09-05 14:16:11 +0200, Peter Eisentraut wrote:
> >> I'm content with this patch.
> > 
> > Would need tests.
> 
> The latest patch sends adds coverage for all the new code paths
> added.  Do you have something else in mind?

Missed them somehow. But I don't think they're quite sufficient. I think
at least we also need tests that test things like multi-statement
exec_simple-query() *with* explicit transactions and chaining.


> >> Better disable questionable cases now and maybe re-enable them later
> >> if someone wants to make a case for it.
> > 
> > I do think the fact that COMMIT in multi-statement implicit transaction
> > has some usecase, is an argument for just implementing it properly...
> 
> Like Peter, I would also keep an ERROR for now, as we could always
> relax that later on.

I mean, I agree it's better to err that way, but it still seems
unnecessary to design things in a way that prevents legit cases, that we
then may have to allow later. Error -> no error is a behavioural change
too, even if obviously less likely to cause problems.


Greetings,

Andres Freund



Re: BUG #15977: Inconsistent behavior in chained transactions

From
Fabien COELHO
Date:
> I made another patch for that.
> I don't have much confidence with my English spelling so further
> improvements may be needed.
>
>> If it is too much a change and potential regression, then I think that the
>> "and chain" variants should be consistent and just raise warnings.

> We don't have an exact answer for implicit transaction chaining behavior
> yet.

> So I think it's better to disable this feature until someone discovers the
> use cases for this.

> Permitting AND CHAIN without a detailed specification might cause troubles
> in future.

I think that it would be too bad to remove this feature for a small 
implementation-dependent corner case.

Documentation says that COMMIT/ROLLBACK [AND CHAIN] apply to the "current 
transaction", and "BEGIN initiates a transaction block".

If there is no BEGIN, there is no "current transaction", so basically the 
behavior is unspecified, whether AND CHAIN or not, and we are free 
somehow.

In such case, I'm simply arguing for consistency: whatever the behavior, 
the chain and no chain variants should behave the same.

Now, I'd prefer error in all cases, no doubt about that, which might be 
considered a regression. A way around that could be to have a GUC decide 
between a strict behavior (error) and the old behavior (warning).

-- 
Fabien.



Re: BUG #15977: Inconsistent behavior in chained transactions

From
fn ln
Date:
> Missed them somehow. But I don't think they're quite sufficient. I think
> at least we also need tests that test things like multi-statement
> exec_simple-query() *with* explicit transactions and chaining.
Added a few more tests for that.

> Now, I'd prefer error in all cases, no doubt about that, which might be
> considered a regression. A way around that could be to have a GUC decide
> between a strict behavior (error) and the old behavior (warning).
I think it's more better to have a GUC to disable implicit transaction 'block' feature, because that's probably the root of all issues.

2019年9月7日(土) 22:23 Fabien COELHO <coelho@cri.ensmp.fr>:

> I made another patch for that.
> I don't have much confidence with my English spelling so further
> improvements may be needed.
>
>> If it is too much a change and potential regression, then I think that the
>> "and chain" variants should be consistent and just raise warnings.

> We don't have an exact answer for implicit transaction chaining behavior
> yet.

> So I think it's better to disable this feature until someone discovers the
> use cases for this.

> Permitting AND CHAIN without a detailed specification might cause troubles
> in future.

I think that it would be too bad to remove this feature for a small
implementation-dependent corner case.

Documentation says that COMMIT/ROLLBACK [AND CHAIN] apply to the "current
transaction", and "BEGIN initiates a transaction block".

If there is no BEGIN, there is no "current transaction", so basically the
behavior is unspecified, whether AND CHAIN or not, and we are free
somehow.

In such case, I'm simply arguing for consistency: whatever the behavior,
the chain and no chain variants should behave the same.

Now, I'd prefer error in all cases, no doubt about that, which might be
considered a regression. A way around that could be to have a GUC decide
between a strict behavior (error) and the old behavior (warning).

--
Fabien.
Attachment

Re: BUG #15977: Inconsistent behavior in chained transactions

From
Fabien COELHO
Date:
>> Now, I'd prefer error in all cases, no doubt about that, which might be
>> considered a regression. A way around that could be to have a GUC decide
>> between a strict behavior (error) and the old behavior (warning).
>
> I think it's more better to have a GUC to disable implicit transaction
> 'block' feature, because that's probably the root of all issues.

Hmmm… I'm not sure that erroring out on "SELECT 1" because there is no 
explicit "BEGIN" is sellable, even under some GUC.

-- 
Fabien.

Re: BUG #15977: Inconsistent behavior in chained transactions

From
fn ln
Date:
No, but instead always do an implicit COMMIT after each statement, like SELECT 1; SELECT 2; (not \;) in psql.
The PostgreSQL document even states that 'Issuing COMMIT when not inside a transaction does no harm, but it will provoke a warning message.' for a long time,
but in fact it have side-effect when used in an implicit transactions.
If we can ensure that the COMMIT/ROLLBACK really does nothing, we don't have to distinguish CHAIN and NO CHAIN errors anymore.

2019年9月8日(日) 2:04 Fabien COELHO <coelho@cri.ensmp.fr>:

>> Now, I'd prefer error in all cases, no doubt about that, which might be
>> considered a regression. A way around that could be to have a GUC decide
>> between a strict behavior (error) and the old behavior (warning).
>
> I think it's more better to have a GUC to disable implicit transaction
> 'block' feature, because that's probably the root of all issues.

Hmmm… I'm not sure that erroring out on "SELECT 1" because there is no
explicit "BEGIN" is sellable, even under some GUC.

--
Fabien.

Re: BUG #15977: Inconsistent behavior in chained transactions

From
Peter Eisentraut
Date:
On 2019-09-07 18:32, fn ln wrote:
>> Missed them somehow. But I don't think they're quite sufficient. I think
>> at least we also need tests that test things like multi-statement
>> exec_simple-query() *with* explicit transactions and chaining.
> Added a few more tests for that.

I committed this patch with some cosmetic changes and documentation updates.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services



Re: BUG #15977: Inconsistent behavior in chained transactions

From
fn ln
Date:
Confirmed. Thank you all for your help.

The only concern is that this test:

   SET TRANSACTION READ WRITE\; COMMIT AND CHAIN;  -- error
   SHOW transaction_read_only;

   SET TRANSACTION READ WRITE\; ROLLBACK AND CHAIN;  -- error
   SHOW transaction_read_only;

makes more sense with READ ONLY because default_transaction_read_only is off at this point.

2019年9月9日(月) 5:27 Peter Eisentraut <peter.eisentraut@2ndquadrant.com>:
On 2019-09-07 18:32, fn ln wrote:
>> Missed them somehow. But I don't think they're quite sufficient. I think
>> at least we also need tests that test things like multi-statement
>> exec_simple-query() *with* explicit transactions and chaining.
> Added a few more tests for that.

I committed this patch with some cosmetic changes and documentation updates.

--
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Re: BUG #15977: Inconsistent behavior in chained transactions

From
Peter Eisentraut
Date:
On 2019-09-09 05:58, fn ln wrote:
> Confirmed. Thank you all for your help.
> 
> The only concern is that this test:
> 
>    SET TRANSACTION READ WRITE\; COMMIT AND CHAIN;  -- error
>    SHOW transaction_read_only;
> 
>    SET TRANSACTION READ WRITE\; ROLLBACK AND CHAIN;  -- error
>    SHOW transaction_read_only;
> 
> makes more sense with READ ONLY because default_transaction_read_only is
> off at this point.

Oh you're right.  Fixed.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services



Re: BUG #15977: Inconsistent behavior in chained transactions

From
fn ln
Date:
It looks good now. Thank you again.

2019年9月9日(月) 17:43 Peter Eisentraut <peter.eisentraut@2ndquadrant.com>:
On 2019-09-09 05:58, fn ln wrote:
> Confirmed. Thank you all for your help.
>
> The only concern is that this test:
>
>    SET TRANSACTION READ WRITE\; COMMIT AND CHAIN;  -- error
>    SHOW transaction_read_only;
>
>    SET TRANSACTION READ WRITE\; ROLLBACK AND CHAIN;  -- error
>    SHOW transaction_read_only;
>
> makes more sense with READ ONLY because default_transaction_read_only is
> off at this point.

Oh you're right.  Fixed.

--
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services