Re: [HACKERS] Partitioned tables constraint_exclusion

2007-04-09 Thread Weslee Bilodeau
Jim Nasby wrote:
 See Simon's reply... timestamptz math is *not* IMMUTABLE, because
 sessions are free to change their timezone at any time. I bet you can
 get some invalid results using that function with a clever test case.
 

I'm pretty sure it could easily be broken.
But to make it easier for me, I know that the reporting system connects,
runs the query, and disconnects.

So I'm so far safe using my current system.

If the system had persistent connections and changed timezones a lot, it
might however cause problems.

Its been the only way that I could get it to be smart enough to not use
the tables outside its range.

With the tables growing 2+ million rows a day, approaching 1 billion
rows, its helps performance a lot.

This works at least until the ongoing discussion of partitioned tables
hopefully improves things in this area.

 On Mar 26, 2007, at 3:48 PM, Weslee Bilodeau wrote:
 This works -

 CREATE FUNCTION now_interval( interval ) RETURNS timestamptz IMMUTABLE
 STRICT AS $$ SELECT NOW() - $1 $$ LANGUAGE SQL ;

 SELECT count(*) FROM master WHERE var_ts  now_interval( '1 month' );

 This doesn't work -

 SELECT count(*) FROM master WHERE var_ts  ( NOW() - '1
 month'::interval );


 This works for me, as the reporting system I know doesn't change
 timezones, and function cache doesn't last longer then the current
 select?


 But, its basically the exact same logic in both cases?

 Weslee


 ---(end of broadcast)---
 TIP 1: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to [EMAIL PROTECTED] so that your
message can get through to the mailing list cleanly

 
 -- 
 Jim Nasby[EMAIL PROTECTED]
 EnterpriseDB  http://enterprisedb.com  512.569.9461 (cell)
 
 
 

Weslee


---(end of broadcast)---
TIP 5: don't forget to increase your free space map settings


[HACKERS] Partitioned tables constraint_exclusion

2007-03-26 Thread Weslee Bilodeau
I'm not sure if this is a bug, missing feature, misunderstanding on my part?

I checked the TODO list and couldn't find anything on it.

I currently have a 750 million row table, indexes are  10 GB, so trying
to partition it.

The basic -

constraint_exclusion + exact match = OK
constraint_exclusion + ( var + var )::case = Not OK


Weslee


I tried to break it down to a simple case -
(kid_200601 should never show up in the plan)

mytest=# create table master ( var_text text not null, var_ts timestamp
with time zone not null, unique ( var_ts ) );
NOTICE:  CREATE TABLE / UNIQUE will create implicit index
master_var_ts_key for table master
CREATE TABLE
mytest=# create table kid_200601 ( check ( var_ts = '2006-01-01
00:00:00' AND var_ts  '2006-02-01 00:00:00' ) ) inherits ( master ) ;
CREATE TABLE
mytest=# create table kid_200602 ( check ( var_ts = '2006-02-01
00:00:00' AND var_ts  '2006-03-01 00:00:00' ) ) inherits ( master ) ;
CREATE TABLE
mytest=# create table kid_200603 ( check ( var_ts = '2006-03-01
00:00:00' AND var_ts  '2006-04-01 00:00:00' ) ) inherits ( master ) ;
CREATE TABLE
mytest=# explain select count(*) from master where var_ts  '2006-02-22
00:00:00' ;
  QUERY PLAN
---
 Aggregate  (cost=71.94..71.95 rows=1 width=0)
   -  Append  (cost=7.09..69.18 rows=1101 width=0)
 -  Bitmap Heap Scan on master  (cost=7.09..21.68 rows=367 width=0)
   Recheck Cond: (var_ts  '2006-02-22
00:00:00+00'::timestamp with time zone)
   -  Bitmap Index Scan on master_var_ts_key
(cost=0.00..7.00 rows=367 width=0)
 Index Cond: (var_ts  '2006-02-22
00:00:00+00'::timestamp with time zone)
 -  Seq Scan on kid_200602 master  (cost=0.00..23.75 rows=367
width=0)
   Filter: (var_ts  '2006-02-22 00:00:00+00'::timestamp
with time zone)
 -  Seq Scan on kid_200603 master  (cost=0.00..23.75 rows=367
width=0)
   Filter: (var_ts  '2006-02-22 00:00:00+00'::timestamp
with time zone)
(10 rows)

mytest=# select now() ;
  now
---
 2007-03-26 16:02:29.360435+00
(1 row)

mytest=# explain select count(*) from master where var_ts  ( now() - '1
month'::interval )::timestamptz ;
  QUERY PLAN
--
 Aggregate  (cost=114.94..114.95 rows=1 width=0)
   -  Append  (cost=7.10..111.27 rows=1468 width=0)
 -  Bitmap Heap Scan on master  (cost=7.10..23.52 rows=367 width=0)
   Recheck Cond: (var_ts  (now() - '1 mon'::interval))
   -  Bitmap Index Scan on master_var_ts_key
(cost=0.00..7.01 rows=367 width=0)
 Index Cond: (var_ts  (now() - '1 mon'::interval))
 -  Seq Scan on kid_200601 master  (cost=0.00..29.25 rows=367
width=0)
   Filter: (var_ts  (now() - '1 mon'::interval))
 -  Seq Scan on kid_200602 master  (cost=0.00..29.25 rows=367
width=0)
   Filter: (var_ts  (now() - '1 mon'::interval))
 -  Seq Scan on kid_200603 master  (cost=0.00..29.25 rows=367
width=0)
   Filter: (var_ts  (now() - '1 mon'::interval))
(12 rows)

mytest=# show constraint_exclusion ;
 constraint_exclusion
--
 on
(1 row)

mytest=# explain select count(*) from master where var_ts  (
'2007-03-26 16:03:27.370627+00'::timestamptz - '1 month'::interval
)::timestamptz ;
 QUERY PLAN

 Aggregate  (cost=105.77..105.78 rows=1 width=0)
   -  Append  (cost=7.10..102.10 rows=1468 width=0)
 -  Bitmap Heap Scan on master  (cost=7.10..22.60 rows=367 width=0)
   Recheck Cond: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone - '1 mon'::interval))
   -  Bitmap Index Scan on master_var_ts_key
(cost=0.00..7.01 rows=367 width=0)
 Index Cond: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone - '1 mon'::interval))
 -  Seq Scan on kid_200601 master  (cost=0.00..26.50 rows=367
width=0)
   Filter: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone - '1 mon'::interval))
 -  Seq Scan on kid_200602 master  (cost=0.00..26.50 rows=367
width=0)
   Filter: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone - '1 mon'::interval))
 -  Seq Scan on kid_200603 master  (cost=0.00..26.50 rows=367
width=0)
   Filter: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone - '1 mon'::interval))
(12 rows)

mytest=#

---(end of broadcast)---
TIP 1: if posting/reading through Usenet, please send an 

Re: [HACKERS] Partitioned tables constraint_exclusion

2007-03-26 Thread Weslee Bilodeau
Simon Riggs wrote:
 On Mon, 2007-03-26 at 09:38 -0700, Weslee Bilodeau wrote:
 
 mytest=# explain select count(*) from master where var_ts  (
 '2007-03-26 16:03:27.370627+00'::timestamptz - '1 month'::interval
 )::timestamptz ;
 
 If you're able to supply a constant value, why not subtract 1 month
 before you submit the query?
 
 AFAIK timestamptz arithmetic depends upon the current timezone which is
 a STABLE value and so won't currently work with partitioning.
 
 Having partitioning work with STABLE functions should be a TODO item if
 it isn't already, but that requires some thought to implement and won't
 happen for 8.3.
 

Mainly its because the value comes from a reporting system that has
minimal brains, it passes values it gets from the user directly into a
query.

IE, they enter '1 month', which I use to populate the interval value,
ts  ( NOW() - $VALUE )

But, in the example I did a timestamp - interval, the exact date, not
NOW() - Still didn't work.

I'm guessing anything that has to think, math, etc is not valid for
constrain_exclusion?

Its not in the docs anywhere, so trying to isolate what can and can't be
done.

Weslee

mytest=# explain select count(*) from master where var_ts  (
'2007-03-26 16:03:27.370627+00'::timestamptz + '1 second'::interval
)::timestamptz ;
  QUERY PLAN
---
 Aggregate  (cost=105.77..105.78 rows=1 width=0)
   -  Append  (cost=7.10..102.10 rows=1468 width=0)
 -  Bitmap Heap Scan on master  (cost=7.10..22.60 rows=367 width=0)
   Recheck Cond: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone + '00:00:01'::interval))
   -  Bitmap Index Scan on master_var_ts_key
(cost=0.00..7.01 rows=367 width=0)
 Index Cond: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone + '00:00:01'::interval))
 -  Seq Scan on kid_200601 master  (cost=0.00..26.50 rows=367
width=0)
   Filter: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone + '00:00:01'::interval))
 -  Seq Scan on kid_200602 master  (cost=0.00..26.50 rows=367
width=0)
   Filter: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone + '00:00:01'::interval))
 -  Seq Scan on kid_200603 master  (cost=0.00..26.50 rows=367
width=0)
   Filter: (var_ts  ('2007-03-26
16:03:27.370627+00'::timestamp with time zone + '00:00:01'::interval))
(12 rows)

mytest=# explain select count(*) from master where var_ts  (
'2007-03-26 16:03:27.370627+00' ) ;
  QUERY PLAN
--
 Aggregate  (cost=22.60..22.61 rows=1 width=0)
   -  Append  (cost=7.09..21.68 rows=367 width=0)
 -  Bitmap Heap Scan on master  (cost=7.09..21.68 rows=367 width=0)
   Recheck Cond: (var_ts  '2007-03-26
16:03:27.370627+00'::timestamp with time zone)
   -  Bitmap Index Scan on master_var_ts_key
(cost=0.00..7.00 rows=367 width=0)
 Index Cond: (var_ts  '2007-03-26
16:03:27.370627+00'::timestamp with time zone)
(6 rows)

mytest=#

---(end of broadcast)---
TIP 9: In versions below 8.0, the planner will ignore your desire to
   choose an index scan if your joining column's datatypes do not
   match


Re: [HACKERS] Partitioned tables constraint_exclusion

2007-03-26 Thread Weslee Bilodeau
Weslee Bilodeau wrote:
 Mainly its because the value comes from a reporting system that has
 minimal brains, it passes values it gets from the user directly into a
 query.
 
 IE, they enter '1 month', which I use to populate the interval value,
 ts  ( NOW() - $VALUE )
 
 But, in the example I did a timestamp - interval, the exact date, not
 NOW() - Still didn't work.
 
 I'm guessing anything that has to think, math, etc is not valid for
 constrain_exclusion?
 
 Its not in the docs anywhere, so trying to isolate what can and can't be
 done.

This works -

CREATE FUNCTION now_interval( interval ) RETURNS timestamptz IMMUTABLE
STRICT AS $$ SELECT NOW() - $1 $$ LANGUAGE SQL ;

SELECT count(*) FROM master WHERE var_ts  now_interval( '1 month' );

This doesn't work -

SELECT count(*) FROM master WHERE var_ts  ( NOW() - '1 month'::interval );


This works for me, as the reporting system I know doesn't change
timezones, and function cache doesn't last longer then the current select?


But, its basically the exact same logic in both cases?

Weslee


---(end of broadcast)---
TIP 1: if posting/reading through Usenet, please send an appropriate
   subscribe-nomail command to [EMAIL PROTECTED] so that your
   message can get through to the mailing list cleanly


Re: [HACKERS] Acclerating INSERT/UPDATE using UPS

2007-02-12 Thread Weslee Bilodeau
Christopher Browne wrote:
 [EMAIL PROTECTED] (Hideyuki Kawashima) wrote:
 Joshua,

 I appreciate your quick  informative reply. And, I also really
 appreciate your kind comments. Since I have joined this ML 3 hours
 ago, I tried to be polite and slightly nervous. But I was relieved
 by your message.
 
 Your idea sounds interesting; there is likely to be a considerable
 resistance to mechanisms, however, that would be likely to make
 PostgreSQL less robust.
 
 Be aware, also, that in a public forum like this, people are sometimes
 less gentle than Joshua.
 
 The fundamental trouble with this mechanism is that a power outage can
 instantly turn a database into crud.

I can think of a few places where I don't care about the data if the
power is lost -

* Web-based session data

A lot of web sites have separate session-only databases.
If the database goes down, we have to truncate the tables anyways when
it comes back up.


* Reporting slaves

We have replication slaves setup for internal (staff-only) reporting.
Often a lot of temp and summary tables as well.

If the data is lost, don't care. Its a reporting database.

Re-syncing from another slave is no biggie for total data loss.

Less a concern given the speed increase of the data it creates as well
as data coming in from the master.


* Front-end cache slaves

Same type of situation as the reporting slaves.
Basic front-end cache that replicates data to take load off the master.

The slaves still have to do all the same insert/updates, but this means
they'll spend less time in locks.

They crash, point the apps to the master or another slave while you fix it.



Weslee

---(end of broadcast)---
TIP 3: Have you checked our extensive FAQ?

   http://www.postgresql.org/docs/faq


Re: [HACKERS] Getting the type Oid in a CREATE TYPE output function

2006-10-18 Thread Weslee Bilodeau
Marko Kreen wrote:
 On 10/16/06, Weslee Bilodeau [EMAIL PROTECTED] wrote:
 Marko Kreen wrote:
  The PGP functions happen to do it already - pgp_key_id().

 Actually, Tom helped me realize I made a mistake, which I'm following
 his suggestion. Not tying keys to OIDs which change when backup/restored.
 
 Yeah, tying to oids is bad, you should link to names,
 preferably schema-qualified.  Anyway, that was just off-hand
 suggestion.
 
 
 [ snip nice description ]
 
 
 I'm not sure if anyone else needs something like it, but it allows us to
 transparently encrypt data directly in the tables. Minimum application
 changes ('select enc_key' at connection) - the main requirement when
 working on legacy code that needs to match todays security polices
 quickly.
 
 Some want row-level access control, then your scheme would not be enough.

Right now once I have it working, at least in the column-level keys I'm
looking for, I can worry about this.

My main concern at having multiple keys on the same column is the
ability to index it.

Right now you can index the encrypted values, however you can only do
exact matches to use the index.

IE -

select * from table where credit_card = '';

That would work, as it encrypts the '' then compares the encrypted
values in the index.

By having multiple keys, I can't do that.

Aside from breaking the index, you can't do any comparisons at all anymore.

Because '' is encrypted then compared.
If credit_card was encrypted using key1, and '' is encrypted using
key2, there can be no match, even if the unencrytped values match.

You'd have to decrypt everything and then compare, which is a large
performance hit.

Also, I like the ability to do this -

insert into table ( credit_card ) values ( '' ) ;

And its automatically encrypted. To support multiple keys, there has to
be a way to switch the keys.

Something like -

select enc_key( 'key1' );
insert into table ( credit_card ) values ( '' ) ;

select enc_key( 'key2' );
insert into table ( credit_card ) values ( '' ) ;

Its possible, just a bit messy.

The other thing is when doing -

select * from table;

If you only specified key1, you can view the '', but if you don't
specify the key2, what is displayed as it doesn't have the decryption
key for ''?

Right now it errors out if attempting to view a record you haven't
provided the key for. In this case you need to give all keys before you
can do the select.



 
 Maybe it would be better to avoid combining the keys, instead have
 hidden key in database and several user keys that grant access to that
 key, thus you can revoke access from only some users.

I like more security. Its a combined two keys for the basic idea that -

The database itself does not have the key. If you hack into the server,
you will not be able to decrypt the values.

The application itself does not have the key.

If you hack the application and have access to enc_raw_read() (this
allows backups to work - selects the raw-encrypted values), you can't
decrypt the values.

Basically you call enc_key( 'application_key' ), the encrypt function is
called with a basic database_key || application_key, ensuring both parts
are always needed.

Thus backups are secure, and the application is a little more secure.

For things like storing credit cards, SSNs, personal information, this
allows us to say if you run off with the server, you can't do anything.

By storing the key in the database as you suggest and just giving access
to that key, any DBA can decrypt the values, and anyone who runs off
with a backup can as well. Your only securing the SQL-access, not the
backups. Which, more often its backups that are stolen, lost, etc.

 
 But one thing I suggest strongly - use PGP encryption instead
 of old encrypt()/decrypt().  PGP hides the data much better,
 espacially in case of lot of small data with same key.
 
 

I may look into PGP once I get this part working.
Smaller steps for me, I'm new to postgres internal API. :)

Weslee

---(end of broadcast)---
TIP 3: Have you checked our extensive FAQ?

   http://www.postgresql.org/docs/faq


Re: [HACKERS] Getting the type Oid in a CREATE TYPE output function

2006-10-18 Thread Weslee Bilodeau
Jim C. Nasby wrote:
 On Tue, Oct 17, 2006 at 04:34:35PM +0300, Marko Kreen wrote:
 I'm not sure if anyone else needs something like it, but it allows us to
 transparently encrypt data directly in the tables. Minimum application
 changes ('select enc_key' at connection) - the main requirement when
 working on legacy code that needs to match todays security polices quickly.
 Some want row-level access control, then your scheme would not be enough.

 Maybe it would be better to avoid combining the keys, instead have
 hidden key in database and several user keys that grant access to that
 key, thus you can revoke access from only some users.

 But one thing I suggest strongly - use PGP encryption instead
 of old encrypt()/decrypt().  PGP hides the data much better,
 espacially in case of lot of small data with same key.

 Better yet, allow the user to plug in encryption modules. Different
 people want different kinds of encryption. For example, I believe credit
 card companies require AES192.


As its really just a type wrapper around automatically calling
pgcrypto's encrypt/decrypt functions, this should be very easy to do.

I currently default it to 'bf' (blowfish) I can just make the type
creator have an additional parameter that takes any method recognized by
the crypto library.


Weslee

---(end of broadcast)---
TIP 5: don't forget to increase your free space map settings


[HACKERS] Performance/Security question on caching function OIDs for a connection

2006-10-18 Thread Weslee Bilodeau
I'm working on my custom encryption types (as outlined in another
thread) and was curious of one potential performance hit.

On the input and output functions for the new type, I lookup the
encrypt/decrypt functions using -

FuncnameGetCandidates( list_make1( makeString( decrypt ) )

Running through the list and getting the functions OID, then calling
with OidFunctionCall3().

I'm concerned about the performance impact if say, importing thousands
of rows in a COPY, doing the lookup for every row. To get around this I
was thinking of doing the lookup once then caching the OIDs for the
functions (a per-connection cache, not globally).

I know the function can be dropped, I'm trapping the error so I'm not as
concerned, but is it possible for someone to replace the same OID with
another function?

My thoughts were if the call failed, perform another lookup for the new
OID, if it can't be found error out. But if the OID just points to a new
function it may not generate an error and just return something unexpected.

I'm not sure if its safe, or if I shouldn't even bother trying to cache
for performance?

I know it makes little difference when inserting one row as encryption
takes the bulk of the time, but when you scale to thousands+ inserts at
once?

Weslee

---(end of broadcast)---
TIP 3: Have you checked our extensive FAQ?

   http://www.postgresql.org/docs/faq


Re: [HACKERS] Getting the type Oid in a CREATE TYPE output function

2006-10-16 Thread Weslee Bilodeau
Marko Kreen wrote:
 On 10/12/06, Tom Lane [EMAIL PROTECTED] wrote:
 Weslee Bilodeau [EMAIL PROTECTED] writes:
  It works perfectly so long as I used the same key for all my custom
  types. When I want a different key for each type though (so for
 example,
  encrypt credit cards with one key, addresses with another, etc) I
 need a
  way to tell them apart.

 [ shrug... ]  Seems like you should be putting the key ID into the
 stored encrypted datums, then.
 
 The PGP functions happen to do it already - pgp_key_id().
 

Actually, Tom helped me realize I made a mistake, which I'm following
his suggestion. Not tying keys to OIDs which change when backup/restored.


But actually for me, the key ID is not a PGP key.

When you create a new type you create a key ID, and map that key ID to
the OID attached to that type, it stores a hashed password value in a
little far-off place that it can use to ensure all inserts into that
same type are using the exact same encryption key (the key is actually
only half, the database has its own key. It combines the two keys to
encrypt/decrypt data).


Having the same column encrypted with 20 different keys is a bit of a
mess. So I just needed a way to ensure it was the same key with each
INSERT/UPDATE.


At login, you call -

SELECT enc_key( 'type', 'password' );

Returns OK if its the real key for that type, otherwise returns an
error with Invalid Key and refuses all read/writes (SELECT, INSERT,
UPDATE, etc) to those types, as it would if you never called enc_key()
in the first place.


If anyone else is curious I'll release the code once I have it actually
working. A few more days basically.

Allows things like -

-- Create the new type, just hides all the CREATE TYPE
-- and assigns the key to the type
select enc_type_new( 'enc_cardnumber', 'new_password' );

create table credit_card (
card_number enc_cardnumber not null,
card_name varchar(20) not null
);


insert into credit_card values ( '1234', 'test' ) ;

Login again -

select * from credit_card ;

ERROR: Please provide key

select enc_key( 'enc_cardnumber', 'new_password' );

SELECT * from credit_card ;

1234 | test

And yes, you can back it up. Map a user to be able to read/write raw
encrypted values and it allows backup/restores using pg_(dump|restore).


I'm not sure if anyone else needs something like it, but it allows us to
transparently encrypt data directly in the tables. Minimum application
changes ('select enc_key' at connection) - the main requirement when
working on legacy code that needs to match todays security polices quickly.


Weslee

---(end of broadcast)---
TIP 6: explain analyze is your friend


[HACKERS] Getting the type Oid in a CREATE TYPE output function ..

2006-10-12 Thread Weslee Bilodeau
I'm trying to create a few new types, and based on the type in/out
functions will operate a bit differently.

For the input function finding the type Oid is easy -

  Oid our_type_oid = PG_GETARG_OID(1);

For output though I'm having difficulty finding out the type Oid.

I've tried using getBaseType, get_rel_type_id, and get_typ_typrelid.

Maybe I'm using the options wrong?
Or not looking in the right place?

I'm only interested in getting it working on 8.1 or greater, so if it
changes in older versions I'm not as concerned.

Any help is appreciated.


Weslee


---(end of broadcast)---
TIP 3: Have you checked our extensive FAQ?

   http://www.postgresql.org/docs/faq


Re: [HACKERS] Getting the type Oid in a CREATE TYPE output function

2006-10-12 Thread Weslee Bilodeau
Tom Lane wrote:
 Weslee Bilodeau [EMAIL PROTECTED] writes:
 I'm trying to create a few new types, and based on the type in/out
 functions will operate a bit differently.
 For the input function finding the type Oid is easy -
   Oid our_type_oid = PG_GETARG_OID(1);
 For output though I'm having difficulty finding out the type Oid.
 
 You can't, and if you could, relying on it would be a security hole
 in your function (somebody could invoke the function manually and pass
 it a false OID value).  You have to put everything you need to know
 right into the Datum.


I'm not as worried about them running it manually, since I want it to
operate something like -

select output_function( 'test'::text );

It would have the type OID for text.

select output_function( 'test'::varchar );

It would have the type OID for varchar.

I don't want them to tell me the OID they want, I just want to know what
type the function was called with.

Was it called as a varchar, text, my own type, bytea, etc ?

Is this possible?



A bit of what I'm trying to do -

I'm creating an encrypted data type wrapped around pgcrypto.

create table test ( test enctype );

insert into test values ( 'encrypt_me' );

The value in input is encrypted, then stored using byteain. The key used
to encrypt it is based of the type. So I can use the same functions for
10 different CREATE TYPE statements.

The output function descrypts the value, then hands it off to byteaout.

It works perfectly so long as I used the same key for all my custom
types. When I want a different key for each type though (so for example,
encrypt credit cards with one key, addresses with another, etc) I need a
way to tell them apart.

The long way around is just create a new function for each type, but
that seems messy since at least input can tell what type the input Datum
is. Was hoping output can figure out the Datum type so I can decrypt it.

Basically -

create table test ( card enctype_card, addrress enctype_address );

Both types have different encryption keys.

I know its best to encrypt in the application, and they can log the SQL
on the server, or if your not using SSL it can be read, etc. Can't
change the application to encrypt or use pgcrypto directly.


Weslee


---(end of broadcast)---
TIP 4: Have you searched our list archives?

   http://archives.postgresql.org