[GENERAL] Aborted pg_dump run empties existing archive file

2016-05-26 Thread Ken Winter
I just discovered that a run of pg_dump that gets aborted empties any
pre-existing backup file of the same name.  It happens whether the run was
deliberately canceled by the user or just failed because of a bad password
(as in the example below).

~/dba$ pg_dump --host=localhost -U ken  --format=c
--file=mess_development.bak --no-owner --no-privileges mess_development
Password: 

~/dba$ ls -l mess_development.bak
-rw-rw-r-- 1 ken ken *87070* May 26 14:20 mess_development.bak

~/dba$ pg_dump --host=localhost -U ken  --format=c
--file=mess_development.bak --no-owner --no-privileges mess_development
Password: 
pg_dump: [archiver (db)] connection to database "mess_development" failed:
FATAL:  password authentication failed for user "ken"
FATAL:  password authentication failed for user "ken"

~/dba$ ls -l mess_development.bak
-rw-rw-r-- 1 ken ken *0* May 26 14:21 mess_development.bak

~/dba$

This is troubling because I can imagine a disaster scenario where one loses
one's previous backup and, perhaps because of a forgotten password, can't
generate a new one.  (This scenario hasn't happened to *me* yet, but seems
like it could.)  In general, a failed run of a piece of software should
leave everything unchanged.  So maybe this is a bug that needs to be fixed?

~ Ken


Re: [GENERAL] Generate PG schemas from the Oracle Data Modeler tool?

2016-03-08 Thread Ken Winter
I have established a connection between the Oracle tool and my PG databases
by installing the PG JDBC driver from
https://jdbc.postgresql.org/download.html and following instructions at
http://stackoverflow.com/questions/7592519/oracle-sql-developer-and-postgresql/22299552
and https://www.youtube.com/watch?v=UGG_N9Mlgdw=youtu.be .

While the connection thus established seems solid, it delivers access to
only part of the PG database objects.  Most weirdly, the public schema is
invisible in the Oracle tool browser, though it displays other schemas I
create.  For full details of this weirdness, see
http://stackoverflow.com/questions/35809963/cant-see-postgresql-public-schema-in-oracle-sql-developer.
Any advice from the PG world would be very welcome.

~ Thanks, Ken

On Wed, Feb 24, 2016 at 10:52 PM, Ken Winter <k...@sunward.org> wrote:

> The best affordable (in this case, free) data modeling tool that I have
> found is the "Oracle SQL Developer Data Modeler" (
> http://www.oracle.com/technetwork/developer-tools/datamodeler/overview/index.html).
>
>
> The best DBMS (free or otherwise) that I have found is PostgreSQL.
>
> So of course it would be great to be able to connect the Oracle tool to a
> PG database, so one could forward- and reverse-engineer between the two.
> At present, apparently the Oracle tool only natively connects with Oracle,
> DB2, and SQL Server.
>
> So I'm wondering if anybody knows of a utility or an Oracle Data Modeler
> add-on that will take some dialect of SQL DDL that that tool generates and
> turn it into PG-readable SQL.
>
> I get it from the list at
> https://wiki.postgresql.org/wiki/Converting_from_other_Databases_to_PostgreSQL
> that there are tools that do something more ambitious: read schemas from
> actual Oracle databases and implement them as schemas in actual PG
> databases.  What I need is more modest than that: a tool that inputs a file
> of DDL from the Oracle Data Modeler tool and outputs that DDL in PG syntax.
>
> ~ Thanks for any leads you can provide
> ~ Ken
>
>
>


[GENERAL] Generate PG schemas from the Oracle Data Modeler tool?

2016-02-24 Thread Ken Winter
The best affordable (in this case, free) data modeling tool that I have
found is the "Oracle SQL Developer Data Modeler" (
http://www.oracle.com/technetwork/developer-tools/datamodeler/overview/index.html).


The best DBMS (free or otherwise) that I have found is PostgreSQL.

So of course it would be great to be able to connect the Oracle tool to a
PG database, so one could forward- and reverse-engineer between the two.
At present, apparently the Oracle tool only natively connects with Oracle,
DB2, and SQL Server.

So I'm wondering if anybody knows of a utility or an Oracle Data Modeler
add-on that will take some dialect of SQL DDL that that tool generates and
turn it into PG-readable SQL.

I get it from the list at
https://wiki.postgresql.org/wiki/Converting_from_other_Databases_to_PostgreSQL
that there are tools that do something more ambitious: read schemas from
actual Oracle databases and implement them as schemas in actual PG
databases.  What I need is more modest than that: a tool that inputs a file
of DDL from the Oracle Data Modeler tool and outputs that DDL in PG syntax.

~ Thanks for any leads you can provide
~ Ken


[GENERAL] Is IF EXISTS legit in ALTER TABLE ... RENAME?

2015-02-16 Thread Ken Winter
According to the PG 9.1 doc (
http://www.postgresql.org/docs/current/static/sql-altertable.html), this is
a valid flavor of ALTER TABLE:

ALTER TABLE [ IF EXISTS ] name
RENAME TO new_name

But when I try to execute such a command, I get:

ERROR:  syntax error at or near EXISTS
LINE 1: ALTER TABLE IF EXISTS event
   ^
QUERY:  ALTER TABLE IF EXISTS event
RENAME TO event_s;
CONTEXT:  PL/pgSQL function convert_table_to_history line 60 at EXECUTE
statement

As you'll see, in this case the command was issued from a function.  But
issuing it directly evokes the same error.

?!?

~ Thanks in advance
~ Ken


[GENERAL] EXECUTE command-string INTO target USING expression isn't working

2012-04-18 Thread Ken Winter
I swear this used to work, but in PostgreSQL 9.1 it doesn't work any more...

CASE 1: If I write it like this:

FOR func IN (
SELECT * FROM information_schema.routines 
WHERE routine_schema = 'tests' 
) LOOP
q := 'SELECT tests.' || func.routine_name || '()';
EXECUTE q INTO r;
   ...
END LOOP;

on the first time through the loop I get this error:

ERROR:  query has no destination for result data
HINT:  If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT:  PL/pgSQL function cre_supers_for_organization_i line 12 at SQL
statement
SQL statement INSERT INTO organization (name, status) VALUES (str, 'Closed
Ongoing Group')
PL/pgSQL function event line 32 at SQL statement
SQL statement SELECT tests.event()
PL/pgSQL function run_all_tests line 16 at EXECUTE statement
SQL state: 42601

CASE 2: If I write it like this:

FOR func IN (
SELECT * FROM information_schema.routines 
WHERE routine_schema = 'tests'  
) LOOP
q := 'SELECT tests.$1()';
EXECUTE q INTO r USING func.routine_name;
   ...
END LOOP;

on the first time through the loop I get this error:

ERROR:  syntax error at or near $1
LINE 1: SELECT tests.$1()
 ^
QUERY:  SELECT tests.$1()
CONTEXT:  PL/pgSQL function run_all_tests line 17 at EXECUTE statement
SQL state: 42601

In both cases, each of the functions to be called returns a string, and r is
a VARCHAR variable.

What's wrong with this picture?

~ Thanks in advance for your help
~ Ken



-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] Null comparisons and the transform_null_equals run-time parameter

2010-06-05 Thread Ken Winter
I get it.  Thanks, Tom.

In case anybody else needs this functionality, let me offer a family of
functions that do comparisons that treat NULL as a real value (rather than
as unknown).  For example:

CREATE OR REPLACE FUNCTION eqnull(varchar, varchar) RETURNS boolean AS
$BODY$
/*
Return True if both args have the same non-NULL values
or both args are NULL; otherwise False. 
*/
DECLARE
v1 ALIAS FOR $1;
v2 ALIAS FOR $2;
BEGIN
-- NULL = NULL
IF v1 IS NULL AND v2 IS NULL THEN
RETURN True;
-- NULL != Any non-NULL value
ELSIF v1 IS NULL AND v2 IS NOT NULL THEN
RETURN False;
-- Any non-NULL value != NULL
ELSIF v1 IS NOT NULL AND v2 IS NULL THEN
RETURN False;
-- Non-NULL value = non-NULL value
ELSIF v1 = v2 THEN
RETURN True; 
-- Non-NULL value != non-NULL value
ELSE 
RETURN False;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
;

You need a separate function for each data type you want to compare; the
only difference among these functions is their argument types.  I've
implemented variants for VARCHAR, NUMERIC, TIMESTAMP, and BOOLEAN.

The reason I need this is that I'm writing functions to test my database
programming (triggers, rules, etc), and these tests sometimes need to treat
Null as just another value in doing test comparisons.

~ Ken


 -Original Message-
 From: Tom Lane [mailto:t...@sss.pgh.pa.us]
 Sent: Saturday, June 05, 2010 9:41 AM
 To: Ken Winter
 Cc: 'PostgreSQL pg-general List'
 Subject: Re: [GENERAL] Null comparisons and the transform_null_equals run-
 time parameter
 
 Ken Winter k...@sunward.org writes:
  When the run-time parameter transform_null_equals is on, shouldn't two
  variables with NULL values evaluate as equal?
 
 No.  That setting does not change the runtime behavior of comparison.
 The only thing it does is change the literal syntax something = NULL
 to something IS NULL.
 
   regards, tom lane


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] Null comparisons and the transform_null_equals run-time parameter

2010-06-05 Thread Ken Winter
Steve ~

Thanks for the great tips.  See comments below.

 -Original Message-
 From: pgsql-general-ow...@postgresql.org [mailto:pgsql-general-
 ow...@postgresql.org] On Behalf Of Steve Atkins
 Sent: Saturday, June 05, 2010 1:04 PM
 To: PostgreSQL pg-general List
 Subject: Re: [GENERAL] Null comparisons and the transform_null_equals run-
 time parameter
 
 
 On Jun 5, 2010, at 9:46 AM, Ken Winter wrote:

  In case anybody else needs this functionality, let me offer a family of
  functions that do comparisons that treat NULL as a real value (rather
 than
  as unknown).  For example:
 
 You should take a look at is not distinct from.

Wow, that's the same wheel I just reinvented!  Works fine in my test
functions.  Guess I can scrap my home-brewed functions that do the same
thing.

  The reason I need this is that I'm writing functions to test my database
  programming (triggers, rules, etc), and these tests sometimes need to
 treat
  Null as just another value in doing test comparisons.
 
 You also might find http://pgtap.org/  useful.

Yes indeed, looks very promising.  

I see there are also test frameworks available at
http://en.dklab.ru/lib/dklab_pgunit/ and http://www.epictest.org/ .  

This will take me a while to digest, but hopefully I'll be able to scrap, or
greatly simplify, my elaborate homemade test functions too.  It's always a
joy to be able to replace my own code with somebody else's.

~ Ken


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


[GENERAL] Null comparisons and the transform_null_equals run-time parameter

2010-06-04 Thread Ken Winter
When the run-time parameter transform_null_equals is on, shouldn't two
variables with NULL values evaluate as equal?  They don't seem to.  

 

At the bottom of this message is a little test function.  It tries all
comparisons of NULL-valued variables and NULL constants, both before and
after turning transform_null_equals on.  Here's what it returns:

 

transform_null_equals OFF: NULL = NULL - Unknown

transform_null_equals OFF: v1 = NULL - Unknown

transform_null_equals OFF: NULL = v2 - Unknown

transform_null_equals OFF: v1 = v2 - Unknown

transform_null_equals ON: NULL = NULL - True

transform_null_equals ON: v1 = NULL - True

transform_null_equals ON: NULL = v2 - True

transform_null_equals ON: v1 = v2 - Unknown

 

My problem is in the last line: Comparing two NULL variables produces an
unknown result.  I need it to evaluate as True, like the preceding three
comparisons.

 

Any suggestions?

 

~ TIA

~ Ken

 

 

CREATE OR REPLACE FUNCTION test() RETURNS varchar AS

$BODY$

DECLARE

  v1 VARCHAR;

  v2 VARCHAR;

  s VARCHAR := '';

BEGIN

  v1 := Null;

  v2 := Null;

  IF NULL = NULL THEN

s := s || 'transform_null_equals OFF: NULL = NULL - True ';

  ELSIF NOT (NULL = NULL) THEN

s := s || 'transform_null_equals OFF: NULL = NULL - False ';

  ELSE

s := s || 'transform_null_equals OFF: NULL = NULL - Unknown ';

  END IF;

  s := s || chr(10);

  IF v1 = NULL THEN

s := s || 'transform_null_equals OFF: v1 = NULL - True ';

  ELSIF NOT (v1 = NULL) THEN

s := s || 'transform_null_equals OFF: v1 = NULL - False ';

  ELSE

s := s || 'transform_null_equals OFF: v1 = NULL - Unknown ';

  END IF;

  s := s || chr(10);

  IF NULL = v2 THEN

s := s || 'transform_null_equals OFF: NULL = v2 - True ';

  ELSIF NOT (NULL = v2) THEN

s := s || 'transform_null_equals OFF: NULL = v2 - False ';

  ELSE

s := s || 'transform_null_equals OFF: NULL = v2 - Unknown ';

  END IF;

  s := s || chr(10);

  IF v1 = v2 THEN

s := s || 'transform_null_equals OFF: v1 = v2 -  True ';

  ELSIF NOT v1 = v2 THEN

s := s || 'transform_null_equals OFF: v1 = v2 - False ';

  ELSE

s := s || 'transform_null_equals OFF: v1 = v2 - Unknown ';

  END IF;

  s := s || chr(10);

 

  SET LOCAL transform_null_equals TO ON;

 

  IF NULL = NULL THEN

s := s || 'transform_null_equals ON: NULL = NULL - True ';

  ELSIF NOT (NULL = NULL) THEN

s := s || 'transform_null_equals ON: NULL = NULL - False ';

  ELSE

s := s || 'transform_null_equals ON: NULL = NULL - Unknown ';

  END IF;

  s := s || chr(10);

  IF v1 = NULL THEN

s := s || 'transform_null_equals ON: v1 = NULL - True ';

  ELSIF NOT (v1 = NULL) THEN

s := s || 'transform_null_equals ON: v1 = NULL - False ';

  ELSE

s := s || 'transform_null_equals ON: v1 = NULL - Unknown ';

  END IF;

  s := s || chr(10);

  IF NULL = v2 THEN

s := s || 'transform_null_equals ON: NULL = v2 - True ';

  ELSIF NOT (NULL = v2) THEN

s := s || 'transform_null_equals ON: NULL = v2 - False ';

  ELSE

s := s || 'transform_null_equals ON: NULL = v2 - Unknown ';

  END IF;

  s := s || chr(10);

  IF v1 = v2 THEN

s := s || 'transform_null_equals ON: v1 = v2 - True ';

  ELSIF NOT v1 = v2 THEN

s := s || 'transform_null_equals ON: v1 = v2 - False ';

  ELSE

s := s || 'transform_null_equals ON: v1 = v2 - Unknown ';

  END IF;

  

  RETURN s;   

END;

$BODY$

LANGUAGE plpgsql VOLATILE;

 

 

SELECT test();



Re: [GENERAL] ROLLBACK in a function

2010-05-24 Thread Ken Winter
Craig ~

Your rollback solution works!  For anyone who wants to use Craig's solution,
the new version of my example (with the test code omitted to clarify the
structural pattern) is:

CREATE OR REPLACE FUNCTION tests() RETURNS varchar AS
$BODY$
DECLARE
errs VARCHAR = '';
-- Test declarations: omitted
BEGIN
-- Test code: omitted
RAISE EXCEPTION '';
EXCEPTION
WHEN raise_exception THEN
RETURN errs;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
;


By contrast, the old version (with the test code omitted) was:

CREATE OR REPLACE FUNCTION tests() RETURNS varchar AS
$BODY$
DECLARE
errs VARCHAR = '';
-- Test declarations: omitted
BEGIN
RAISE EXCEPTION '';
EXCEPTION
WHEN raise_exception THEN
-- Test code: omitted
RETURN errs;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
;

To clarify the purpose of this structure, for anyone who may want to do the
same thing:  

This is a framework for running test code whose job is to run one or more
tests against the database.  Every test that fails is supposed to simply add
a diagnostic message to the errs string, which is then returned.  Every
test that is passed is to do nothing.  All tests need to be designed so that
they do not cause an exception that causes the function to abort.  And then,
at the end, the framework of the function returns errs and rolls back all
data changes it has made.

~ Thanks!
~ Ken


 -Original Message-
 From: pgsql-general-ow...@postgresql.org [mailto:pgsql-general-
 ow...@postgresql.org] On Behalf Of Craig Ringer
 Sent: Sunday, May 23, 2010 8:48 PM
 To: Ken Winter
 Cc: PostgreSQL pg-general List
 Subject: Re: [GENERAL] ROLLBACK in a function
 
 On 24/05/10 02:51, Ken Winter wrote:
  How can I write a PL/PgSQL function that rolls back every database
  change it has done?
 
 Have it raise an exception, causing the surrounding transaction to
 terminate with an error.
 
 Another function calling yours can still catch the exception and handle
 it, so it's possible for your function's changes to be applied, but only
 if someone explicitly and intentionally catches and ignores the error.
 
  BEGIN
 
  RAISE EXCEPTION '';
 
  EXCEPTION
 
  WHEN raise_exception THEN
 
  SET search_path TO public, tests;
 
  -- Test code:
 
  SELECT count(*) INTO old_count FROM person_i;
 
  INSERT INTO person (last_name) VALUES ('_test');
 
  SELECT count(*) INTO new_count FROM person_i;
 
  IF NOT new_count = old_count + 1 THEN
 
  errs := errs || ': Failed to insert into ''person''';
 
  END IF;
 
 
  The function runs OK, but it does not roll back the actions it did (in
  this case, the INSERT).
 
 You're on the right track, but you've got the code that changes the
 database in the exception handler _after_ the exception is thrown.
 
 You want it in the BEGIN block _before_ the exception is thrown.
 However, you're also doing this quite an expensive way.
 
 An INSERT/UPDATE/DELETE  can only fail to have any effect without
 throwing an exception if if has a WHERE clause, is intercepted by a
 BEFORE trigger that returns NULL, or is rewritten by a rule. If none of
 those are possible, your INSERT/UPDATE/DELETE is guaranteed to work or
 throw an exception.
 
 eg (untested code, please verify before relying on it):
 
BEGIN
  SELECT count(*) INTO old_count FROM person_i;
  INSERT INTO person (last_name) VALUES ('_test');
  SELECT count(*) INTO new_count FROM person_i;
  IF NOT old_count + 1 = new_count THEN
  RAISE EXCEPTION 'Update failed';
  END IF;
EXCEPTION WHEN raise_exception THEN
  errs := errs || ': Failed to insert into ''person''';
END;
 
 
 But ... please consider whether you really need this check with two
 expensive count(*) queries. Unless you're using BEFORE triggers that
 return NULL or rewrite rules, you can trust that an INSERT without a
 WHERE clause will always succeed or throw an exception.
 
 If you *are* using triggers or rules, you should be able to use GET
 DIAGNOSTICS to see the affected row count, saving yourself those
 count(*) queries. See:
 
 http://www.postgresql.org/docs/current/static/plpgsql-
 statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS
 
 eg (untested code, should give you the idea):
 
 DECLARE
 rowcount INTEGER;
 BEGIN
-- function body here
BEGIN
  INSERT INTO person (last_name) VALUES ('_test');
  GET DIAGNOSTICS rowcount = ROW_COUNT;
  IF NOT rowcount = 1 THEN
 RAISE EXCEPTION 'Update failed';
  END IF;
EXCEPTION WHEN raise_exception THEN
  errs := errs || ': Failed to insert into ''person''';
END;
 END;
 
 
 You *can* trick Pg into not seeing that an update has happened even when
 it really has. For example, a BEFORE trigger can do its own  INSERT then
 return NULL to tell Pg to ignore the INSERT that invoked the trigger.
 Stored functions that do INSERTs don't set the rowcount either. If
 you're not doing anything like that, though

[GENERAL] ROLLBACK in a function

2010-05-23 Thread Ken Winter
How can I write a PL/PgSQL function that rolls back every database change it
has done?

 

I'm about to write a set of database test functions.  Each function needs to
do some INSERT, UPDATE, or DELETE actions, test whether they had their
intended effect, and then roll back the test changes to restore the database
to its prior state.  Here's a simple example:

 

CREATE OR REPLACE FUNCTION tests.person() RETURNS varchar AS

$BODY$

DECLARE

  errs VARCHAR = '';

  -- Test declarations:

  old_count BIGINT;

  new_count BIGINT;

BEGIN

--   RAISE EXCEPTION '';

-- EXCEPTION

--   WHEN raise_exception THEN

  SAVEPOINT s;

  SET search_path TO public, tests;

  -- Test code:

   SELECT count(*) INTO old_count FROM person_i;

   INSERT INTO person (last_name) VALUES ('_test');

   SELECT count(*) INTO new_count FROM person_i;

   IF NOT new_count = old_count + 1 THEN

 errs := errs || ': Failed to insert into
''person'';

   END IF;

  ROLLBACK TO SAVEPOINT s;

  RETURN errs;

END;

$BODY$

LANGUAGE plpgsql VOLATILE

;

When I run this function, I get this error:

 

ERROR: SPI_execute_plan failed executing query SAVEPOINT s:
SPI_ERROR_TRANSACTION

SQL state: XX000

Context: PL/pgSQL function person line 11 at SQL statement

 

I tried another way to make the rollback happen: The last paragraph of
http://www.postgresql.org/docs/8.3/static/plpgsql-structure.html said a
block containing an EXCEPTION clause effectively forms a subtransaction that
can be rolled back without affecting the outer transaction.  So I rewrote
the test function like this:

 

CREATE OR REPLACE FUNCTION tests.person() RETURNS varchar AS

$BODY$

DECLARE

  errs VARCHAR = '';

  -- Test declarations:

  old_count BIGINT;

  new_count BIGINT;

BEGIN

  RAISE EXCEPTION '';

EXCEPTION

  WHEN raise_exception THEN

   SET search_path TO public, tests;

   -- Test code:

 SELECT count(*) INTO old_count FROM person_i;

 INSERT INTO person (last_name) VALUES
('_test');

 SELECT count(*) INTO new_count FROM person_i;

 IF NOT new_count = old_count + 1 THEN

  errs := errs || ': Failed to insert
into ''person''';

 END IF;

   RETURN errs;

END;

$BODY$

LANGUAGE plpgsql VOLATILE

;

 

The function runs OK, but it does not roll back the actions it did (in this
case, the INSERT).

 

~ TIA

~ Ken

 

 



Re: [GENERAL] 'Infinity' in date columns?

2010-05-17 Thread Ken Winter


 -Original Message-
 From: pgsql-general-ow...@postgresql.org [mailto:pgsql-general-
 ow...@postgresql.org] On Behalf Of Tom Lane
...
 
 Ken Winter k...@sunward.org writes:
  The documentation at
  http://www.postgresql.org/docs/8.3/static/datatype-datetime.html seems
 to
  say that the special value 'infinity' (later than all other time
 stamps)
  should work for an date-time column, and the type date is listed as
 among
  the date-time data types.
  But I can't get 'infinity' to work for columns of type date.
 
 You seem to be carefully reading around the middle column in Table 8-13,
 which specifically shows that infinity doesn't work for type date.

Oh, duh, right you are...
 
 Now, if you were to update to Postgres 8.4, it *would* work.

I'll see if I can get my host to do that.
 
~ Thanks
~ Ken




-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


[GENERAL] 'Infinity' in date columns?

2010-05-16 Thread Ken Winter
The documentation at
http://www.postgresql.org/docs/8.3/static/datatype-datetime.html seems to
say that the special value 'infinity' (later than all other time stamps)
should work for an date-time column, and the type date is listed as among
the date-time data types.

 

But I can't get 'infinity' to work for columns of type date.

 

Here's a test case:

 

CREATE TABLE _test

(

  timestampx timestamp without time zone DEFAULT 'infinity'::timestamp
without time zone,

  datex date DEFAULT 'infinity'::timestamp without time zone

)

);

 

INSERT INTO _test DEFAULT VALUES;

 

SELECT * FROM _test;

 

This returns (as viewed through pgAdmin III):

 

timestampx datex

--- -

infinity 

 

When I tried to declared the datex column like this:

 

  datex date DEFAULT 'infinity'::date

 

I got this:

 

ERROR:  invalid input syntax for type date: infinity

 

Is there any way to get 'infinity' to work for a date column?  

 

Or any other way to get the equivalent functionality in a date column?

 

~ TIA

~ Ken



Re: [GENERAL] Problem with execution of an update rule

2010-01-26 Thread Ken Winter
Mark this one solved.  I finally stumbled across an old, forgotten e-mail
thread from 2006 where Tom Lane solved exactly this problem.  See
http://archives.postgresql.org/pgsql-general/2006-02/msg01039.php.

~ Thanks again, Tom!
~ Ken

 
 -Original Message-
 From: Ken Winter [mailto:k...@sunward.org] 
 Sent: Friday, January 22, 2010 7:00 PM
 To: 'PostgreSQL pg-general List'
 Subject: Problem with execution of an update rule
 
 I’m trying to implement a history-keeping scheme using PostgreSQL views
and update rules.  My problem is that one of the commands in one of my
crucial update rules apparently never executes.
 
 Briefly, the history-keeping scheme involves: 
 
 * Two tables: an h table that contains the columns for which we want to
preserve a full history of all updates, and an i table that contains
columns whose history we don't want to preserve.
 
 * A view of the two tables, showing all the columns of the h and I tables.

 
 * A set of rules that makes the view behave like a fully updatable table,
while invisibly preserving a copy of the record as it existed prior to each
update.
 
 The problem rule (see example in the PS below) is the one that fires
when the user issues a SQL UPDATE against the view.  This rule fires if the
UPDATE has changed any column value.  It is supposed to execute three
commands:
 
 1. Insert a new record into the _h table, containing the old values of the
record being updated.  This is the record that preserves the prior state of
the record.
 
 2. Update the existing h table record with the new values. 
 
 3. Update the existing i table record with the new values. 
 The problem is that command 1 apparently never executes.  That is, in
response to an UPDATE against the view, a new h table record is NOT inserted
- even though data changes in both the h and the i table are successfully
recorded, and no error messages occur.
 
 I have tried changing the order of the 3 commands in the rule - no effect.

 Can you tell me what's wrong with this picture? 
 
 ~ TIA 
 ~ Ken 
 
 PS: 
 This example involves a view named people, an h table named people_h
(including columns first_name and last_name), an i table named
people_i (including column birth_date), a sequence-assigned identifier
people_id in both tables, some effective and expiration timestamps in
people_h, and some rules including this troublesome one:
 
 CREATE OR REPLACE RULE on_update_2_preserve AS 
   ON UPDATE TO people 
   WHERE ( 
 (OLD.people_id  NEW.people_id 
   OR (OLD.people_id IS NULL AND NEW.people_id IS NOT NULL) 
   OR (OLD.people_id IS NOT NULL AND NEW.people_id IS NULL )) 
 OR (OLD.effective_date_and_time  NEW.effective_date_and_time 
   OR (OLD.effective_date_and_time IS NULL 
   AND NEW.effective_date_and_time IS NOT NULL) 
   OR (OLD.effective_date_and_time IS NOT NULL 
 AND NEW.effective_date_and_time IS NULL )) 
 OR (OLD.first_name  NEW.first_name 
   OR (OLD.first_name IS NULL AND NEW.first_name IS NOT NULL) 
   OR (OLD.first_name IS NOT NULL AND NEW.first_name IS NULL )) 
 OR (OLD.last_name  NEW.last_name 
   OR (OLD.last_name IS NULL AND NEW.last_name IS NOT NULL) 
   OR (OLD.last_name IS NOT NULL AND NEW.last_name IS NULL )) 
 OR (OLD._action  NEW._action 
   OR (OLD._action IS NULL AND NEW._action IS NOT NULL) 
   OR (OLD._action IS NOT NULL AND NEW._action IS NULL )) 
 OR (OLD.birth_date  NEW.birth_date 
   OR (OLD.birth_date IS NULL AND NEW.birth_date IS NOT NULL) 
   OR (OLD.birth_date IS NOT NULL AND NEW.birth_date IS NULL ))) 
 ) 
   DO 
 ( 
 /* Copy the old values to a new record. 
 Expire it either now (if no effective date 
 was provided) or whenever the update query specifies.*/ 
 INSERT INTO people_h ( 
   people_id, 
   first_name, 
   last_name, 
   effective_date_and_time, 
   expiration_date_and_time) 
 VALUES ( 
   OLD.people_id, 
   OLD.first_name, 
   OLD.last_name, 
   OLD.effective_date_and_time, 
   NEW.effective_date_and_time) 
 ; 
 /* Update the current H record and make it effective 
 as of either now (if no effective date 
 was provided) or whenever the update query specifies.*/ 
 UPDATE people_h 
   SET 
 people_id = NEW.people_id, 
 first_name = NEW.first_name, 
 last_name = NEW.last_name, 
 _action = 'preserved', 
   effective_date_and_time = 
 CASE 
   WHEN NEW.effective_date_and_time = OLD.effective_date_and_time 
    THEN CURRENT_TIMESTAMP 
   ELSE NEW.effective_date_and_time 
 END 
   WHERE 
 people_id = OLD.people_id 
 AND effective_date_and_time = OLD.effective_date_and_time 
 ; 
 /* Update I table. */ 
 UPDATE people_i 
   SET 
 people_id = NEW.people_id, 
 birth_date = NEW.birth_date, 
   WHERE 
 people_id = OLD.people_id; 
 SELECT public.debug

[GENERAL] Problem with execution of an update rule

2010-01-22 Thread Ken Winter
I'm trying to implement a history-keeping scheme using PostgreSQL views and
update rules.  My problem is that one of the commands in one of my crucial
update rules apparently never executes.

Briefly, the history-keeping scheme involves: 

* Two tables: an h table that contains the columns for which we want to
preserve a full history of all updates, and an i table that contains
columns whose history we don't want to preserve.

* A view of the two tables, showing all the columns of the h and I tables. 

* A set of rules that makes the view behave like a fully updatable table,
while invisibly preserving a copy of the record as it existed prior to each
update.

The problem rule (see example in the PS below) is the one that fires when
the user issues a SQL UPDATE against the view.  This rule fires if the
UPDATE has changed any column value.  It is supposed to execute three
commands:

1. Insert a new record into the _h table, containing the old values of the
record being updated.  This is the record that preserves the prior state of
the record.

2. Update the existing h table record with the new values. 

3. Update the existing i table record with the new values. 

The problem is that command 1 apparently never executes.  That is, in
response to an UPDATE against the view, a new h table record is NOT inserted
- even though data changes in both the h and the i table are successfully
recorded, and no error messages occur.

I have tried changing the order of the 3 commands in the rule - no effect. 

Can you tell me what's wrong with this picture? 

~ TIA 
~ Ken 

PS: 

This example involves a view named people, an h table named people_h
(including columns first_name and last_name), an i table named
people_i (including column birth_date), a sequence-assigned identifier
people_id in both tables, some effective and expiration timestamps in
people_h, and some rules including this troublesome one:

CREATE OR REPLACE RULE on_update_2_preserve AS 
ON UPDATE TO people 
WHERE ( 
(OLD.people_id  NEW.people_id 
OR (OLD.people_id IS NULL AND NEW.people_id IS NOT
NULL) 
OR (OLD.people_id IS NOT NULL AND NEW.people_id IS
NULL )) 
OR (OLD.effective_date_and_time 
NEW.effective_date_and_time 
OR (OLD.effective_date_and_time IS NULL 
AND NEW.effective_date_and_time IS NOT NULL) 
OR (OLD.effective_date_and_time IS NOT NULL 
AND NEW.effective_date_and_time IS NULL )) 
OR (OLD.first_name  NEW.first_name 
OR (OLD.first_name IS NULL AND NEW.first_name IS NOT
NULL) 
OR (OLD.first_name IS NOT NULL AND NEW.first_name IS
NULL )) 
OR (OLD.last_name  NEW.last_name 
OR (OLD.last_name IS NULL AND NEW.last_name IS NOT
NULL) 
OR (OLD.last_name IS NOT NULL AND NEW.last_name IS
NULL )) 
OR (OLD._action  NEW._action 
OR (OLD._action IS NULL AND NEW._action IS NOT NULL)

OR (OLD._action IS NOT NULL AND NEW._action IS NULL
)) 
OR (OLD.birth_date  NEW.birth_date 
OR (OLD.birth_date IS NULL AND NEW.birth_date IS NOT
NULL) 
OR (OLD.birth_date IS NOT NULL AND NEW.birth_date IS
NULL ))) 
) 
DO 
( 
/* Copy the old values to a new record. 
Expire it either now (if no effective date 
was provided) or whenever the update query specifies.*/ 
INSERT INTO people_h ( 
people_id, 
first_name, 
last_name, 
effective_date_and_time, 
expiration_date_and_time) 
VALUES ( 
OLD.people_id, 
OLD.first_name, 
OLD.last_name, 
OLD.effective_date_and_time, 
NEW.effective_date_and_time) 
; 
/* Update the current H record and make it effective 
as of either now (if no effective date 
was provided) or whenever the update query specifies.*/ 
UPDATE people_h 
SET 
people_id = NEW.people_id, 
first_name = NEW.first_name, 
last_name = NEW.last_name, 
_action = 'preserved', 
effective_date_and_time = 
CASE 
WHEN NEW.effective_date_and_time =
OLD.effective_date_and_time 
 THEN CURRENT_TIMESTAMP 
 

Re: [GENERAL] Array in nested query

2009-02-15 Thread Ken Winter
Thanks, Osvaldo and Fernando - your solution works!

 -Original Message-
 From: Osvaldo Kussama [mailto:osvaldo.kuss...@gmail.com]
 Sent: Saturday, February 14, 2009 8:24 PM
 To: Ken Winter
 Subject: Re: [GENERAL] Array in nested query
 
 2009/2/14 Ken Winter k...@sunward.org:
  I'm trying to look up the columns in a constraint in pg_catalog (of
  PostgreSQL 8.0.x).  I can't figure out how to join the elements of the
  array that lists the 'attnum's of the columns in the table to the
 'conkey'
  array in the constraint definition (see
  http://www.postgresql.org/docs/8.0/static/catalog-pg-constraint.html and
  http://www.postgresql.org/docs/8.0/static/catalog-pg-attribute.html ).
 
 
 
  The problem is in the last line of this query:
 
 
 
  SELECT a.attname AS name
 
  FROM pg_catalog.pg_class t, pg_catalog.pg_attribute a
 
  WHERE t.oid = 3626912
 
  AND a.attrelid = t.oid
 
  AND a.attnum = any (select conkey FROM pg_catalog.pg_constraint
 WHERE
  oid = 3708025)
 
 
 
  I have tried all the variations on this syntax that I can think of,
 after
  plowing through all the documentation of arrays I can find in
  http://www.postgresql.org/docs/8.0/static/index.html, and none of them
 work.
 
 
 
 I've a similar problem.
 Try explicit cast and an extra parenthesis:
 
 SELECT a.attname AS name
   FROM pg_catalog.pg_class t, pg_catalog.pg_attribute a
  WHERE t.oid = 3626912
AND a.attrelid = t.oid
AND a.attnum = any ((select conkey FROM pg_catalog.pg_constraint
 WHERE oid = 3708025)::smallint[]);
 
 Osvaldo


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


[GENERAL] Problem with non-unique constraint names

2009-02-14 Thread Ken Winter
The following query against my PostgreSQL 8.0.x 'public' schema:

SELECT 
fkc.table_name as fk_table_name,
fkc.constraint_name AS fk_constraint_name
FROM information_schema.table_constraints fkc
WHERE fkc.constraint_schema = 'public'
AND fkc.constraint_type = 'FOREIGN KEY'
AND (
SELECT count(*) FROM information_schema.table_constraints dup
WHERE dup.constraint_schema = 'public'
AND dup.constraint_name = fkc.constraint_name
)  1

Returns this:

fk_table_name   fk_constraint_name
-   --
site_role___site_permission fk_site_rol_site_role_site_rol
site_role_criterion fk_site_rol_site_role_site_rol
teachingfk_teaching_teaching__teaching
teaching_package_distribution   fk_teaching_teaching__teaching

Since constraint name uniqueness is a SQL standard, I was surprised that
PostgreSQL doesn't enforce it.  I found one thread (from 2002) in the
archive that discusses this, but the thread ended inconclusively.  And I
just discovered a warning at
http://www.postgresql.org/docs/8.0/static/catalog-pg-constraint.html that
these names aren't necessarily unique.

This is more than just a quibble about standards.  When there are duplicate
constraint names, I'm having trouble writing queries against the
information_schema that accurately return the FK columns of all the FKs that
reference a given table.

For example, this query gives some details of the two constraints named
'fk_teaching_teaching__teaching':

SELECT
fkc.table_name as fk_table_name,
fkc.constraint_name AS fk_constraint_name
FROM information_schema.table_constraints fkc
WHERE fkc.table_schema = 'public'
AND fkc.constraint_name = 'fk_teaching_teaching__teaching'

It returns:

fk_table_name   fk_constraint_name
-   --
teachingfk_teaching_teaching__teaching
teaching_package_distribution   fk_teaching_teaching__teaching

So far so good.  But what table is referenced by the FK in the 'teaching'
table?  One way to bridge across is via the info schema view
'referential_constraints':

SELECT
fkc.table_name as fk_table_name,
fkc.constraint_name AS fk_constraint_name,
pkc.constraint_name AS pk_constraint_name,
pkc.table_name as pk_table_name
FROM information_schema.table_constraints fkc,
information_schema.referential_constraints r,
information_schema.table_constraints pkc
WHERE fkc.table_schema = 'public'
AND fkc.constraint_name = 'fk_teaching_teaching__teaching'
AND fkc.table_name = 'teaching'
AND r.constraint_schema = fkc.constraint_schema
AND r.constraint_name = fkc.constraint_name
AND pkc.constraint_schema = r.unique_constraint_schema
AND pkc.constraint_name = r.unique_constraint_name

This returns:

fk_table_name fk_constraint_name   pk_constraint_name   pk_table_name
-   -
teaching  fk_teaching_teaching pk_teaching_type_lov teaching_type_lov
__teaching
teaching  fk_teaching_teaching pk_teaching_package  teaching_package
__teaching

The second row returned is bogus: there is no FK from 'teaching' to
'teaching package'.  The problem is that
information_schema.referential_constraints does not contain a table_name
column identifying the table that contains the FK, so there is no way to
specify which of the redundantly named constraints you want.

The other way to find the referenced table of a FK constraint is via
information_schema.constraint_column_usage, but it has the same problem: the
FK constraint you want to follow can be identified in
constraint_column_usage only by its schema and its name, which ain't enough
when constraints are redundantly named.

I shudder at the horrors that might ensue if PK constraints also had
duplicate names!

I can do what I need with queries on pk_catalog, but I would rather do it
through information_schema because it's based on a broader standard.  Is
there some way that I have missed to do it that way?

~ TIA
~ Ken


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


[GENERAL] Array in nested query

2009-02-14 Thread Ken Winter
I'm trying to look up the columns in a constraint in pg_catalog (of
PostgreSQL 8.0.x).  I can't figure out how to join the elements of the
array that lists the 'attnum's of the columns in the table to the 'conkey'
array in the constraint definition (see
http://www.postgresql.org/docs/8.0/static/catalog-pg-constraint.html and
http://www.postgresql.org/docs/8.0/static/catalog-pg-attribute.html ).  

 

The problem is in the last line of this query:

 

SELECT a.attname AS name

FROM pg_catalog.pg_class t, pg_catalog.pg_attribute a

WHERE t.oid = 3626912

AND a.attrelid = t.oid

AND a.attnum = any (select conkey FROM pg_catalog.pg_constraint WHERE
oid = 3708025)

 

I have tried all the variations on this syntax that I can think of, after
plowing through all the documentation of arrays I can find in
http://www.postgresql.org/docs/8.0/static/index.html, and none of them work.

 

Any ideas?

 

~ TIA 

~ Ken



Re: [GENERAL] Extracting data from deprecated MONEY fields

2008-06-07 Thread Ken Winter
Right you are, Tom!  

In case anyone else is facing the same migration, pasted in below is a
pl/pgsql function that does the conversion.

~ Thanks to all
~ Ken

 -Original Message-
 From: [EMAIL PROTECTED] [mailto:pgsql-general-
 [EMAIL PROTECTED] On Behalf Of Tom Lane
 Sent: Saturday, June 07, 2008 11:25 AM
 Subject: Re: [GENERAL] Extracting data from deprecated MONEY fields
 
...

 If you do it within plpgsql it should work.  Just assign the money value
 to a text variable (or vice versa).
 
   regards, tom lane

CREATE OR REPLACE FUNCTION public.convert_money_column(varchar, varchar,
varchar)
RETURNS varchar AS
$BODY$
/*
Converts the column given by arg 3 (in the table given by arg 2
in the schema given by arg 1) from a money type to a numeric(10,2)
type, and repopulates the new column with the values from the old.
Before doing that, it makes a backup of the original table,
which should be deleted manually after verifying the results.
*/
DECLARE
this_schema ALIAS FOR $1;
this_table ALIAS FOR $2;
this_column ALIAS FOR $3;
q varchar := '';
q2 varchar := '';
rec record;
this_oid oid;
this_varchar varchar := '';
this_numeric numeric(10,2);
n integer := 0;
BEGIN
q := 'CREATE TABLE ' || this_schema  || '.' || this_table || '_bak'
|| ' AS SELECT * FROM ' || this_schema  || '.' || this_table;
EXECUTE q;
q := 'ALTER TABLE ' || this_schema  || '.' || this_table
|| ' ADD COLUMN ' || this_column || '_ money';
EXECUTE q;
q := 'UPDATE ' || this_schema  || '.' || this_table
|| ' SET ' || this_column || '_ = ' || this_column;
EXECUTE q;
q := 'ALTER TABLE ' || this_schema  || '.' || this_table
|| ' DROP COLUMN ' || this_column || ' CASCADE';
EXECUTE q;
q := 'ALTER TABLE ' || this_schema  || '.' || this_table
|| ' ADD COLUMN ' || this_column || ' numeric(10,2)';
EXECUTE q;
q := 'SELECT oid, ' || this_column || '_ AS money_column FROM '
|| this_schema  || '.' || this_table ;
FOR rec IN EXECUTE q LOOP
this_oid := rec.oid;
this_varchar := rec.money_column;
this_varchar := replace(this_varchar, '$', '');
this_varchar := replace(this_varchar, ',', '');
this_numeric := this_varchar;
q2 := 'UPDATE ' || this_schema  || '.' || this_table
|| ' SET ' || this_column || ' = ' || this_numeric
|| ' WHERE oid = ' || this_oid;
EXECUTE q2;
n := n + 1;
END LOOP;
q := 'ALTER TABLE ' || this_schema  || '.' || this_table
|| ' DROP COLUMN ' || this_column || '_ CASCADE';
EXECUTE q;
RETURN 'Did ' || n || ' records';
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] Extracting data from deprecated MONEY fields

2008-06-06 Thread Ken Winter
Thanks, Joshua ~

What you suggest is basically what I'm trying to do.  Where I'm stuck is in
finding a construct (a CAST or whatever) to turn the existing money column
data (directly or indirectly) into numeric.  I've tried to convert a column
named amount in the following ways, with the following results:

CAST(amount AS numeric) - cannot cast type money to numeric
CAST(amount AS numeric(10,2)) - cannot cast type money to numeric
CAST(amount AS decimal) - cannot cast type money to numeric
CAST(amount AS text) - cannot cast type money to text
CAST(amount AS varchar) - cannot cast type money to character varying
to_char(money) - function to_char(money) does not exist

~ Ken

 -Original Message-
 From: Joshua D. Drake [mailto:[EMAIL PROTECTED]
 Sent: Thursday, June 05, 2008 11:22 PM
 To: Ken Winter
 Cc: PostgreSQL pg-general List
 Subject: Re: [GENERAL] Extracting data from deprecated MONEY fields
 
 Ken Winter wrote:
  I understand from
  http://www.postgresql.org/docs/8.0/static/datatype-money.html that the
  money data type is deprecated.
 
 Money is no longer deprecated in newer releases (specifically 8.3),
 although I do think it would be wise to push it to numeric.
 
 I think the way to do it would be to backup the table and edit the table
 definition from the file. Make the money a numeric. Then reload the
 table from the backup.
 
 Sincerely,
 
 Joshua D. Drake
 


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] Extracting data from deprecated MONEY fields

2008-06-06 Thread Ken Winter
Thanks Adrian ~ See comments at end.

 -Original Message-
 From: [EMAIL PROTECTED] [mailto:pgsql-general-
 [EMAIL PROTECTED] On Behalf Of Adrian Klaver
 Sent: Friday, June 06, 2008 11:49 AM
 To: pgsql-general@postgresql.org
 Cc: Ken Winter
 Subject: Re: [GENERAL] Extracting data from deprecated MONEY fields
 
 On Friday 06 June 2008 8:25 am, Ken Winter wrote:
  Thanks, Joshua ~
 
  What you suggest is basically what I'm trying to do.  Where I'm stuck is
 in
  finding a construct (a CAST or whatever) to turn the existing money
  column data (directly or indirectly) into numeric.  I've tried to
 convert a
  column named amount in the following ways, with the following results:
 
  CAST(amount AS numeric) - cannot cast type money to numeric
  CAST(amount AS numeric(10,2)) - cannot cast type money to numeric
  CAST(amount AS decimal) - cannot cast type money to numeric
  CAST(amount AS text) - cannot cast type money to text
  CAST(amount AS varchar) - cannot cast type money to character varying
  to_char(money) - function to_char(money) does not exist
 
 I don't know if this helps.
...
 **There is no simple way of doing the reverse in a locale-independent
 manner,
 namely casting a money value to a numeric type. If you know the currency
 symbol and thousands separator you can use regexp_replace():
 
 SELECT regexp_replace('52093.89'::money::text, '[$,]', '', 'g')::numeric;
 
I'm indeed trying to get rid of US$ notation.  

Alas, here's what I get from trying the regexp pattern on my amount column
(type=money):

regexp_replace(amount::money::text, '[$,]', '', 'g')::numeric - cannot
cast type money to text

regexp_replace(amount::text, '[$,]', '', 'g')::numeric - cannot cast type
money to text

And if remove the cast to text, I get:

regexp_replace(amount::money, '[$,]', '', 'g')::numeric -  function
regexp_replace(money, unknown, unknown, unknown) does not exist

~ Ken


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


[GENERAL] Extracting data from deprecated MONEY fields

2008-06-05 Thread Ken Winter
I understand from
http://www.postgresql.org/docs/8.0/static/datatype-money.html that the
money data type is deprecated.  

 

So I want to convert the data from my existing money columns into new
un-deprecated columns, e.g. with type decimal(10,2).  But every SQL
command I try tells me I can't cast or convert money data into any other
type I have tried, including decimal, numeric, varchar, and text.  

 

Is there any way to do this?

 

~ TIA 

~ Ken



[GENERAL] Converting empty input strings to Nulls

2008-05-31 Thread Ken Winter
Applications accessing my PostgreSQL 8.0 database like to submit no-value
date column values as empty strings rather than as Nulls.  This, of course,
causes this PG error:

SQL State: 22007
ERROR: invalid input syntax for type date: 

I'm looking for a way to trap this bad input at the database level, quietly
convert the input empty strings to Null, and store the Null in the date
column.  I tried a BEFORE INSERT OR UPDATE trigger evoking this function ...

CREATE OR REPLACE FUNCTION public.empty_string_to_null()
RETURNS trigger AS
$BODY$
BEGIN
IF CAST(NEW.birth_date AS text) = '' THEN
NEW.birth_date = Null;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

... but an empty string still evokes the error even before this function is
triggered.

Is there a way to convert empty strings to Nulls before the error is evoked?

~ TIA
~ Ken


-- 
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: [GENERAL] What pg_restore does to a non-empty target database

2008-01-14 Thread Ken Winter
Based on Tom Lane's response, here is version 2 of my attempt to document
what pg_restore does to a target database that already contains objects.  

Version 2 has been limited to the case where pg_dump was run with the 
--column-inserts option and pg_restore is run with the --clean option.
Also, when there is a possible difference between what pg_restore tries to
do (i.e. the SQL actions it invokes) and what actually happens, Version 2
indicates the latter on a line labeled Exception:.

Version 2 depends on the answer to the following question:  Is it true that
the sequence of SQL commands that is extracted into a file by:

pg_restore --file=foo.sql [other arguments] foo.bak

is exactly the sequence of SQL commands that will be executed in database
foo by the command:

pg_restore --dbname=foo [other arguments] foo.bak

(assuming the same [other arguments] in both cases)?

If so, having looked at the extracted SQL from several examples, I'm
thinking it's a safe bet that no pg_restore DROP, DELETE, or CREATE action
will ever fail (except when a DROP's target object does not exist), because
pg_restore sequences the cleaning activities so they get rid of dependent
objects first.  Right?  

If so, that would seem to guarantee that every action that pg_restore tries
to do in the narrative below is guaranteed to succeed, except INSERTs, which
can fail only as described below.

If not, I have another version of the story below that is a lot more
qualified and complicated.

As before, I solicit your confirmations, corrections, and additions of this
document, hoping to get it to the point where my project team (and anyone
else who wants it) can use it with confidence.

~ Thanks
~ Ken

---

WHAT PG_RESTORE DOES
Version 2

Given a pg_restore command, where:
* A is the source archive file (as filtered and reordered by a ToC file, 
  if any) produced by pg_dump with --format=t and --column-inserts
  options.
* T is the target database.
* O is a database object (table, function, etc) that exists in A 
  and/or in C.
* The pg_restore command has the --clean option, and it does not have the
  --table= or --trigger= or --exit-on-error or --disable-triggers options.

The following are the changes that the pg_restore command will produce in
database T.  

EFFECTS ON SCHEMA OBJECTS 

If object O exists in both A and T, pg_restore:
* Drops T's version of O.
* Creates A's version of O.
If object O exists in T but not in A, pg_restore:
* Leaves T's version of O unchanged.
If object O exists in A but not in T, pg_restore:
  * Creates A's version of O.

EFFECTS ON TABLES AND THEIR DATA

Suppose in addition that:
* Database object O is a base table.
* O contains data in both archive A and target database T.

If the command says --data-only, pg_restore:
* Leaves T's schema definition of O unchanged.
* Tries to delete all of T's O data.
If this causes FK violations, the result depends row-by-row
on 
the ON DELETE action of the FK constraint.
* Tries to insert all of A's O data.
The INSERT of any row that causes constraint violations 
or other fatal errors (see below) fails.
If the command says --schema-only, pg_restore:
* Drops T's version of O, which deletes T's O data as a side-effect.
* Create A's version of O.
* Does not try to insert any of A's O data, so O ends up empty.
If the command says --data-only and --schema-only, pg_restore:
* Leaves O and its data unchanged.
If the command says neither --data-only nor --schema-only, pg_restore:
* Drops T's version of O.
* Assumes that T's O data were deleted (as a side-product of the
DROP)
* Creates A's version of O.
* Inserts all of A's O data.

EFFECTS OF DIFFERENCES BETWEEN A AND T TABLE SCHEMAS

Suppose in addition that: 
* The pg_restore command says --data-only.
* T's schema definition of table O is different from A's.

If column O.C exists in T's schema but not in A's:
* O.C is set to Null in all rows that pg_restore inserts.
If column O.C exists in A's schema but not in T's:
* The O.C values are lost from all rows that pg_restore inserts.
If column O.C exists in both schemas with incompatible types:
* All inserts of rows from A fail.
If constraint K exists in T's schema but not in A's:
* Inserts of rows from A that would violate K fail.
If constraint K exists in A's schema but not in T's:
* K has no effect on the insertion of rows from A.



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


[GENERAL] What pg_restore does to a non-empty target database

2008-01-13 Thread Ken Winter
I need to understand, in as much detail as possible, the results that will
occur when pg_restore restores from an archive file into a target database
that already contains some database objects.  I can't find any reference
that spells this out.  (The PG manual isn't specific enough.)

Instead of just asking questions, I decided to make my best guess about the
answers (below), and ask you to confirm, refute, and correct my guesses
until this becomes a complete and accurate statement.  If I have left out
any conditions that would affect the results, please add them into the
account.  A definitive version of this story might be worth posting in some
more permanent and visible place than an e-mail thread.

In case it matters, I'm currently working with PostgreSQL 8.0.  I don't know
if the truth I'm seeking here is version-dependent.  Also, I'm assuming the
archive is in compressed format.  I don't know how different the story would
be if the archive were in a different format.

~ TIA
~ Ken



Given a pg_restore command (possibly filtered and reordered by a ToC file),
where:
 * A is the source archive file (as filtered and reordered by the ToC file, 
   if any)
 * T is the target database
 * O is a database object (table, function, etc) that exists in A 
   and/or in C

The following are the changes that the pg_restore will produce in T.

If object O exists in both A and T:
  If the command says --clean:
T's version of O is dropped
A's version of O is created
Else:
T's version of O is left unchanged
If object O exists in T but not in A:
T's version of O is left unchanged
If object O exists in A but not in T:
A's version is created

Suppose in addition that O is a data object (a table or sequence) that is
defined by the database schema and contains data in both A and T.

If the command says --data-only:
T's schema definition of O is left unchanged
T's O data are deleted
A's O data are inserted
If the command says --schema-only:
T's schema definition of O is dropped
T's O data are deleted (as a side-product of the drop)
A's schema definition of O is created
No O data are inserted
If the command says --data-only and --schema-only:
T's schema definition of O is left unchanged
T's O data are left unchanged
In other words, nothing changes
If the command says neither --data-only nor --schema-only:
T's schema definition of O is dropped
T's O data are deleted (as a side-product of the drop)
A's schema definition of O is created
A's O data are inserted
In other words, A's version of O entirely replaces T's version

Suppose in addition that the command says --data-only, it doesn't say
--exit-on-error, and T's schema definition of O is different from A's.

If T's schema includes a column O.C that does not exist in A's schema:
A's O data are inserted, and O.C is Null in all rows
If A's schema includes a column O.C that does not exist in T's schema:
A's O data are inserted, but A's values of O.C are lost
If T's schema includes a constraint K that does not exist in A's schema:
A's O data are inserted, except for those that violate K
If A's schema includes a constraint K that does not exist in T's schema:
A's O data are all inserted




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


[GENERAL] Problem with pg_dump?

2008-01-04 Thread Ken Winter
When I do a pg_dump from an 8.1 database (with options schema-only,
no-owner, and plain format), the dump file includes the following:


--
-- TOC entry 1623 (class 1259 OID 17618)
-- Dependencies: 5 1624
-- Name: transaction_transaction_id_seq; Type: SEQUENCE; Schema: public; 
-- Owner: -
--

CREATE SEQUENCE transaction_transaction_id_seq
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;

--
-- TOC entry 3403 (class 0 OID 0)
-- Dependencies: 1623
-- Name: transaction_transaction_id_seq; Type: SEQUENCE OWNED BY; Schema: 
-- public; Owner: -
--


ALTER SEQUENCE transaction_transaction_id_seq OWNED BY
transaction.transaction_id;

When I try to execute the dump script, the second command produces this
error:


ERROR:   syntax error at or near OWNED 


as well it should, since the OWNED clause is not part of the ALTER
SEQUENCE syntax (see
http://www.postgresql.org/docs/8.1/static/sql-altersequence.html), which is:


ALTER SEQUENCE name [ INCREMENT [ BY ] increment ]
[ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
[ RESTART [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]
ALTER SEQUENCE name SET SCHEMA new_schema


(Full disclosure: I am actually getting this error when working through the
tool PG Lightning Assistant (see
http://www.amsoftwaredesign.com/lightning_admin.php).  I assume that PGLA
uses pg_dump to execute its backup database command.  However, if no one
else in PostgreSQL-land has encountered this problem, presumably it is a bug
in PGLA, not in pg_dump, and I will take my problem there.)

If it is a pg_dump bug, are there plans to fix it?  And, meanwhile, any
workarounds other than manually editing the pg_dump DDL file?

~ TIA
~ Ken


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

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


Re: [GENERAL] Problem with pg_dump?

2008-01-04 Thread Ken Winter
Everything I'm doing involves only 8.1.  I don't have any 8.2 instances at
all...

Oops, just I just got a message from my tool's developer that the tool uses
the 8.2 pg_dump no matter what actual PostgreSQL version it's working on.
Sigh.

~ Thanks
~ Ken



 -Original Message-
 From: [EMAIL PROTECTED] [mailto:pgsql-general-
 [EMAIL PROTECTED] On Behalf Of Tom Lane
 Sent: Friday, January 04, 2008 3:35 PM
 To: Ken Winter
 Cc: PostgreSQL pg-general List
 Subject: Re: [GENERAL] Problem with pg_dump?
 
 Ken Winter [EMAIL PROTECTED] writes:
  When I do a pg_dump from an 8.1 database (with options schema-only,
  no-owner, and plain format), the dump file includes the following:
 
  ALTER SEQUENCE transaction_transaction_id_seq OWNED BY
  transaction.transaction_id;
 
 Don't use 8.2 pg_dump if you are intending to reload the output into
 8.1.  In general, pg_dump's output is not promised to be backward
 compatible with older server versions.
 
  (Full disclosure: I am actually getting this error when working through
 the
  tool PG Lightning Assistant (see
  http://www.amsoftwaredesign.com/lightning_admin.php).
 
 There are some helpful tools that seem not to be aware that pg_dump
 and server versions are closely linked.
 
   regards, tom lane
 
 ---(end of broadcast)---
 TIP 3: Have you checked our extensive FAQ?
 
http://www.postgresql.org/docs/faq


---(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


[GENERAL] How to uninstall the geometry package?

2007-11-12 Thread Ken Winter
While installing PostgreSQL (8.1) recently, I was offered the option to
install the geometry functions.  Why not? I said to myself, and to the
installer I said yes.

 

Well, the answer  to Why not? is that I have a couple hundred functions
that I'll probably never use junking up my installation.  

 

The install was from the Win installer package postgresql-8.1.msi.  

 

My question is: Is there any setup routine or something that I can run to
get rid of all the geometry objects, or is the only way to do this to
completely uninstall and reinstall PostgreSQL?

 

~ TIA

~ Ken



[GENERAL] How to convert money columns to numeric?

2007-01-01 Thread Ken Winter
I want to convert a column named amount, currently of type money, to type
numeric(10,2).   

When I try to do this using:

ALTER TABLE transaction ALTER COLUMN amount TYPE NUMERIC(10,2);

I get:

PostgreSQL Error Code: (1)
ERROR:  column amount cannot be cast to type pg_catalog.numeric 

So then I figure I need to do it with SQL of the form:

ALTER TABLE transaction ALTER COLUMN amount TYPE NUMERIC(10,2) USING
expression;

But I can't find a conversion function or operator that will accept a
money column as input.  For example:

ALTER TABLE transaction ALTER COLUMN amount TYPE NUMERIC(10,2) USING
to_number(amount, '.99');

Evokes this error message:

PostgreSQL Error Code: (1)
ERROR:  function to_number(money, unknown) does not exist
HINT:  No function matches the given name and argument types. You may need
to add explicit type casts.

And I can't seem to cast a money column into anything else.  For example: 

ALTER TABLE transaction ALTER COLUMN amount TYPE NUMERIC(10,2) USING
cast(amount as numeric);

Evokes:

PostgreSQL Error Code: (1)
ERROR:  column amount cannot be cast to type pg_catalog.numeric

So I'm fresh out of ideas - other than dropping and recreating the column,
which would lose a lot of data.

~ TIA
~ Ken


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

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


Re: [GENERAL] Disabling and enabling constraints and triggers to make pg_restore work

2006-08-07 Thread Ken Winter
Tom et al ~

I understand that this is all a risky business.  So maybe someone can tell
me a safer way to accomplish what I was trying to accomplish with pg_dump
and data-only pg_restore.

It's a basic bit of database administration work.  I'm trying to establish
two (or if necessary more) instances of the same database - a production
instance and a development instance - and a change management process for
coordinating them.  As you can probably guess:

1. The production instance is the one the users are actually using.  Its
data are The Truth.

2. The development instance is where design changes (to tables, procedures,
and all other database objects) are developed, tested, and readied to go
into production.  Its data are of no value except for testing purposes.  

3. The crucial purpose of the change management process is to put into
production each new release of the database design.  The required outcome is
that the new design (from the development instance) be up and running in the
production instance, managing the production data (from the production
instance), which have been preserved without loss.  (Of course, certain
changes in the new design - dropping a table, for example - will cause
certain data to be lost.  That's not the problem I'm wrestling with here.)

So, the process I have in mind goes like this:

1. At the start of a release cycle, drop everything from the development
instance, and copy the schema (with the production data if you want) from
the production instance into the development instance.

2. During the release cycle, the users use the production instance
(including modifying the data in it), and the developers do their work
(which is modifying the design) in the development instance.  The developers
can do whatever they want to the data in the development instance.

3. At the end of the release cycle, empty all the data from the development
instance, shut down the production instance (or at least write-lock up its
data), and copy the production data (data only) into the development
instance.  Then shut down the production instance to users, drop everything
in the production instance, copy everything (data + schema) from development
into production, and reopen it to users.

Note that step 3 also accomplishes step 1 of the next release cycle, so as
soon as step 3 is done, the users can go on using the data and the
developers can begin developing the next release.

It seemed to me that the PostgreSQL utilities for accomplishing this process
would be pg_dump and pg_restore.  And I've been successful using them -
except for that point in step 3 where I need to do a data-only restore from
production into development.  Then I run into the FK violations (when a FK
table gets restored before its PK table) that led me to start this
discussion thread.

So, to say it again:  What I *have* to accomplish is to separate my
production environment from my development environment, and periodically to
move the new version of the design from development into production.  I've
spelled out my whole approach from top to bottom in hopes that someone can
suggest something at some level (different process? different utilities?
different something else?) that will make this possible with PostgreSQL.
There must be thousands of DBAs out there who have solved this problem, and
I hope one of you can tell me how to join your happy ranks.

~ TIA
~ Ken



-Original Message-
From: Tom Lane [mailto:[EMAIL PROTECTED]
Sent: Sunday, August 06, 2006 11:35 AM
To: [EMAIL PROTECTED]
Cc: PostgreSQL pg-general List
Subject: Re: [GENERAL] Disabling and enabling constraints and triggers
to make pg_restore work

Ken Winter [EMAIL PROTECTED] writes:
 I'm trying to do a data-only pg_restore.  I'm running into a roadblock
 whenever the restore tries to populate a table with a foreign key
before it
 has populated the primary key table that it refers to: This violates
the FK
 constraint, which aborts the restore.

The simplest answer is don't do that.  A full restore (schema+data)
will work correctly.  A data-only restore cannot hope to guarantee
referential integrity, other than by dropping and later recreating all
the FK constraints, and there's a fatal flaw in that plan: what if it
doesn't know about all the FK constraints that are in the database it's
trying to load into?  There could be permissions problems too, if you're
trying to do it as non-superuser.

 Someone on that forum suggested update
 pg_catalog.pg_class set relchecks=0 where relname ='mytab' to disable
and
 update pg_catalog.pg_class set relchecks=1 where relname ='mytab' to
 re-enable.  But to write to pg_catalog you apparently need to be a
 superuser, which alas I'm not.

You should certainly not do anything as risky as messing with relchecks
by hand --- there was a case just a couple weeks ago where someone
destroyed

[GENERAL] Disabling and enabling constraints and triggers to make pg_restore work

2006-08-06 Thread Ken Winter
I’m trying to do a data-only pg_restore.  I’m running into a roadblock
whenever the restore tries to populate a table with a foreign key before it
has populated the primary key table that it refers to: This violates the FK
constraint, which aborts the restore.

Given the complexity of the database I’m trying to restore, the prospect of
having to manual order the restore process so that all PK tables are always
populated before all FK tables that reference them is daunting.  Even if I
did that, I don’t think that would handle recursive relationships, where a
FK refers to its own table’s PK.

What I need is a way to disable FKs, so I can then restore all the data, and
then re-enable the FKs.  I first looked for something like “ALTER TABLE
mytab DISABLE CONSTRAINT mycon” and “ALTER TABLE mytab ENABLE CONSTRAINT
mycon” à la Oracle.  I finally found a French PostgreSQL forum
(http://www.postgresqlfr.org/?q=node/156#comment) that says there’s no such
thing in PostgreSQL.  Someone on that forum suggested “update
pg_catalog.pg_class set relchecks=0 where relname =’mytab’” to disable and
“update pg_catalog.pg_class set relchecks=1 where relname =’mytab’” to
re-enable.  But to write to pg_catalog you apparently need to be a
superuser, which alas I'm not.

I also have some triggers that I think I may need to be able to disable.
pg_restore does have an option to do that, but according to
http://www.postgresql.org/docs/8.1/static/app-pgrestore.html this option is
available to superusers only.

(Perhaps I could write a program that drops all my FKs and triggers, and a
second program that recreates them after the data restore is complete.  But
that seems a rather brutal and scary way to patch up a gap in the PostgreSQL
utilities.)

Any suggestions?

~ TIA
~ Ken Winter



---(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: [GENERAL] Confused about a function returning SETOF

2006-03-22 Thread Ken Winter
Well, duh!  Thank you.  I could have stared at it for hours without seeing
it...

 -Original Message-
 From: Tom Lane [mailto:[EMAIL PROTECTED]
 Sent: Tuesday, March 21, 2006 11:12 PM
 To: [EMAIL PROTECTED]
 Cc: PostgreSQL pg-general List
 Subject: Re: [GENERAL] Confused about a function returning SETOF
 
 Ken Winter [EMAIL PROTECTED] writes:
  select lov_personinorganization_role_status('Student','Applicant');
  ERROR:  set-valued function called in context that cannot accept a set
 
 You need to write
   select * from
 lov_personinorganization_role_status('Student','Applicant');
 
   regards, tom lane



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


[GENERAL] Confused about a function returning SETOF

2006-03-21 Thread Ken Winter








I have the following function:



CREATE or REPLACE FUNCTION public.lov_personinorganization_role_status(

varchar,

varchar)

RETURNS SETOF person_status_in_organization AS 

$BODY$

DECLARE

 rec person_status_in_organization%ROWTYPE;

 role ALIAS FOR $1;

 from_status ALIAS FOR $2;

BEGIN

 FOR rec IN

 SELECT * FROM person_status_in_organization
lov,


status_in_organization_change_lov res

 WHERE res.role
= role


AND res.from_status = from_status


AND lov.role = res.role

 AND
lov.status = res.to_status

 ORDER BY lov.display_order

 LOOP

 RETURN NEXT rec;

 END LOOP; -- FOR rec IN person_status_in_organization

 RETURN;

END; -- of lov_personinorganization_role_status

$BODY$

LANGUAGE 'plpgsql' VOLATILE;



Where person_status_in_organization is a table.



When I try to invoke it with:



select lov_personinorganization_role_status('Student','Applicant');



I get the error message:



ERROR: set-valued function called in context that
cannot accept a set

CONTEXT: PL/pgSQL function lov_personinorganization_role_status
line 15 at return next



Where have I gone astray?



~ TIA

~ Ken








Re: [GENERAL] Another perplexity with PG rules

2006-02-26 Thread Ken Winter
Tom ~

Thanks ever so much for - again - helping me get unstuck.  See comments and
results inserted below.

~ Ken

 -Original Message-
 From: Tom Lane [mailto:[EMAIL PROTECTED]
 Sent: Sunday, February 26, 2006 1:47 PM
 To: [EMAIL PROTECTED]
 Cc: PostgreSQL pg-general List
 Subject: Re: [GENERAL] Another perplexity with PG rules
 
 Ken Winter [EMAIL PROTECTED] writes:
  After trying about a million things, I'm wondering about the meaning of
  OLD. as the actions in a rule are successively executed.  What I have
 done
  assumes that:
  ...
  (b) The OLD. values that appear in the second (INSERT) action in the
 rule
  are not changed by the execution of the first (UPDATE) rule.
 
 I believe this is mistaken.  OLD is effectively a macro for the
 existing row(s) satisfying the rule's WHERE clause.  You've got two
 problems here --- one is that the UPDATE may have changed the data in
 those rows, and the other is that the UPDATE may cause them to not
 satisfy the WHERE clause anymore.

I was afraid of this.  Your conclusions do seem to fit my results.
 
  (c) Whatever the truth of the above assumptions, the second (INSERT)
 action
  in the 'on_update_2_preserve_h' rule should insert SOMEthing.
 
 See above.  If no rows remain satisfying WHERE, nothing will happen.

Yep, that's what was happening.
 
  How to make this whole thing do what is required?
 
 I'd suggest seeing if you can't do the INSERT first then the UPDATE.
 This may require rethinking which of the two resulting rows is the
 historical one and which the updated one, but it could probably
 be made to work.

Yes, I had already had it working with such a scheme.  It expired the
existing record, and then inserted a new record with the updated values.
However this scheme seemed to be causing troubles with other triggers on the
base tables.  That's why I was trying to recast it into a scheme that
updated the existing record and then inserted a new record containing the
old data.
 
 Also, you might think about keeping the historical info in a separate
 table (possibly it could be an inheritance child of the master table).
 This would make it easier to distinguish the historical and current info
 when you need to.

I've been striving mightily to avoid taking this path, because it threatens
to hopelessly complicate my foreign keys.
 
 Lastly, I'd advise using triggers not rules wherever you possibly can.
 In particular, generation of the historical-log records would be far
 more reliable if implemented as an AFTER UPDATE trigger on the base
 table.

This appears to be the WINNER!  I eliminated the INSERT action from my
UPDATE rule:

CREATE OR REPLACE RULE on_update_2_preserve_h AS
ON UPDATE TO person
...
DO
(
/* Update the current H record and make it effective
as of either now (if no effective date
was provided) or whenever the update query specifies.*/
UPDATE person_h
SET person_id = NEW.person_id,
first_name = NEW.first_name,
middle_names = NEW.middle_names,
last_name_prefix = NEW.last_name_prefix,
last_name = NEW.last_name,
name_suffix = NEW.name_suffix,
preferred_full_name = NEW.preferred_full_name,
preferred_business_name = NEW.preferred_business_name,
user_name = NEW.user_name,
_action = NEW._action,
effective_date_and_time =
CASE
WHEN NEW.effective_date_and_time =
OLD.effective_date_and_time
 THEN CURRENT_TIMESTAMP -- Query assigned no value
ELSE NEW.effective_date_and_time -- Query assigned value
END
WHERE person_id = OLD.person_id
AND effective_date_and_time = OLD.effective_date_and_time
;
/* Copy the old values to a new record.
Expire it either now (if no effective date
was provided) or whenever the update query specifies.*/
INSERT INTO person_h (
person_id,
first_name,
middle_names,
last_name_prefix,
last_name,
name_suffix,
preferred_full_name,
preferred_business_name,
user_name,
_action,
effective_date_and_time,
expiration_date_and_time)
VALUES (
OLD.person_id,
OLD.first_name,
OLD.middle_names,
OLD.last_name_prefix,
OLD.last_name,
OLD.name_suffix,
OLD.preferred_full_name,
OLD.preferred_business_name,
OLD.user_name,
OLD._action,
OLD.effective_date_and_time,
CASE
WHEN NEW.effective_date_and_time =
OLD.effective_date_and_time
 THEN CURRENT_TIMESTAMP-- Query assigned no value
ELSE NEW.effective_date_and_time-- Query assigned a value
END

[GENERAL] Another perplexity with PG rules

2006-02-24 Thread Ken Winter
I'm stumped on the following problem.  

Everything between the --- rows should be executable.

Please advise.

~ TIA
~ Ken

---

-- Here's a table:

CREATE TABLE public.person_h
(
person_id bigint DEFAULT nextval('pop_seq'::text),
effective_date_and_time timestamptz DEFAULT ('now'::text)::timestamp(6) with
time zone,
expiration_date_and_time timestamptz DEFAULT 'infinity'::timestamp with time
zone,
first_name varchar(255),
middle_names varchar(255),
last_name_prefix varchar(255),
last_name varchar(255),
name_suffix varchar(255),
preferred_full_name varchar(255),
preferred_business_name varchar(255),
user_name varchar(255),
_action varchar(32) DEFAULT 'preserve'::character varying,
CONSTRAINT pk_person_h_identifier_2 PRIMARY KEY (person_id,
effective_date_and_time)
);
-- Indexes
CREATE UNIQUE INDEX personal_data_px ON person_h USING btree (person_id,
effective_date_and_time);

-- Here's a view of that table plus a few ALTERs on the view:

CREATE OR REPLACE VIEW person AS
SELECT h.person_id AS person_id,
h.effective_date_and_time AS effective_date_and_time,
h.expiration_date_and_time AS expiration_date_and_time,
h.first_name AS first_name,
h.middle_names AS middle_names,
h.last_name_prefix AS last_name_prefix,
h.last_name AS last_name,
h.name_suffix AS name_suffix,
h.preferred_full_name AS preferred_full_name,
h.preferred_business_name AS preferred_business_name,
h.user_name AS user_name,
h._action AS _action
FROM person_h AS h
WHERE h.effective_date_and_time = CURRENT_TIMESTAMP
AND h.expiration_date_and_time = CURRENT_TIMESTAMP

ALTER TABLE person
ALTER COLUMN person_id
SET DEFAULT nextval('pop_seq'::text)
;
ALTER TABLE person
ALTER COLUMN effective_date_and_time
SET DEFAULT ('now'::text)::timestamp(6) with time zone
;
ALTER TABLE person
ALTER COLUMN expiration_date_and_time
SET DEFAULT 'infinity'::timestamp with time zone
;
ALTER TABLE person
ALTER COLUMN _action
SET DEFAULT 'preserve'::character varying

-- Here are a couple of rules on that view:

/*** Rule on_insert inserts the object's first history record into person_h.
***/
CREATE OR REPLACE RULE on_insert AS
ON INSERT TO person
DO INSTEAD (
/* Insert the row into the H table.
Effective and expiration dates take the defaults,
unless query overrides them. */
INSERT INTO person_h
( person_id,
effective_date_and_time,
first_name,
middle_names,
last_name_prefix,
last_name,
name_suffix,
preferred_full_name,
preferred_business_name,
user_name,
_action )
VALUES ( nextval('pop_seq'::text),
NEW.effective_date_and_time,
NEW.first_name,
NEW.middle_names,
NEW.last_name_prefix,
NEW.last_name,
NEW.name_suffix,
NEW.preferred_full_name,
NEW.preferred_business_name,
NEW.user_name,
NEW._action )
)
;

/*** Rule on_update_1_nothing meets the PostgreSQL requirement for one
unconditional UPDATE rule. ***/
CREATE OR REPLACE RULE on_update_1_nothing AS
ON UPDATE TO person
DO INSTEAD NOTHING
;
 
/*** Rule on_update_2_preserve_h inserts a new record with the old data into
history table person_h,
expires this record effective either now or at the effective time given in
the query,
and updates the current record as of the same time. ***/
CREATE OR REPLACE RULE on_update_2_preserve_h AS
ON UPDATE TO person
WHERE (
(OLD.person_id  NEW.person_id
OR (OLD.person_id IS NULL AND NEW.person_id IS NOT NULL)
OR (OLD.person_id IS NOT NULL AND NEW.person_id IS NULL ))
OR (OLD.effective_date_and_time  NEW.effective_date_and_time
OR (OLD.effective_date_and_time IS NULL AND
NEW.effective_date_and_time IS NOT NULL)
OR (OLD.effective_date_and_time IS NOT NULL AND
NEW.effective_date_and_time IS NULL ))
OR (OLD.first_name  NEW.first_name
OR (OLD.first_name IS NULL AND NEW.first_name IS NOT NULL)
OR (OLD.first_name IS NOT NULL AND NEW.first_name IS NULL ))
OR (OLD.middle_names  NEW.middle_names
OR (OLD.middle_names IS NULL AND NEW.middle_names IS NOT NULL)
OR (OLD.middle_names IS NOT NULL AND NEW.middle_names IS NULL ))
OR (OLD.last_name_prefix  NEW.last_name_prefix
OR (OLD.last_name_prefix IS NULL AND NEW.last_name_prefix IS NOT
NULL)
OR (OLD.last_name_prefix IS NOT NULL AND NEW.last_name_prefix IS
NULL ))
OR (OLD.last_name  NEW.last_name
OR (OLD.last_name IS NULL AND NEW.last_name IS NOT NULL)
OR (OLD.last_name IS NOT NULL AND NEW.last_name IS NULL ))
OR (OLD.name_suffix  NEW.name_suffix
OR (OLD.name_suffix IS 

Re: [GENERAL] Does PG really lack a time zone for India?

2006-02-16 Thread Ken Winter
 -Original Message-
 From: Tom Lane [mailto:[EMAIL PROTECTED]
 Sent: Wednesday, February 15, 2006 5:39 PM
 To: [EMAIL PROTECTED]
 Cc: 'PostgreSQL pg-general List'
 Subject: Re: [GENERAL] Does PG really lack a time zone for India?
 
 Ken Winter [EMAIL PROTECTED] writes:
  Yes, that's what I'm trying to do.  My problem has been: how to enter
 the
  equivalent of '2006-02-15 10:22:46-05' when the time I want to enter and
  convert to EST is a variable value or now().
 
 This still shows a problem in your grasp of what's going on.  now() is
 absolute and should never need to be converted ...
 
   regards, tom lane

Tom ~

OK, let me show a little example, in hopes that you can show where I'm
making things needlessly complicated:

/* The table payment records when particular payments were received and 
when they were due.  The requirement is that the due dates are in the local 
time of the office receiving the payment, and late fees must be calculated 
based on that time.  (In the real world, this very denormalized table would 
actually be the result of a query joining many tables, but I'm trying to 
distill the essence here.)  */

CREATE TABLE payment (
office_location character varying NOT NULL, 
-- City of the office to which the payment is due
office_time_zone character varying(10),
-- PostgreSQL time zone code of the office where the payment is due.

-- I had to lie about Bangalore, because PostgreSQL has no code 
-- for Indian Time (GMT+5:30) and the payment_calcs view evokes 
-- an error if not given a valid tz code.
office_gmt_offset interval,
-- Offset of office time zone from GMT
due_date_in_office_time_zone timestamp with time zone,
-- Timestamp for when the pmt is due.
-- IMPORTANT: This is interpreted as a time in the office's time
zone.
-- Note that they due dates all the same clock-time, namely 5 pm.
paid_date_in_server_time_zone timestamp with time zone
-- The time when the payment was received.  As these payments were
-- all entered with no tz modifier, the time entered was interpreted
-- as the server's time zone, which happens to be CST (GMT-06).
-- IMPORTANT: The payment date was entered as a literal, not as
-- now(), but that makes no difference; once the timestamp is
-- stored it is impossible to tell which way it was entered.
);

/* This view makes several calculations from the payment table that may help
understand what is going on.  The most important is 
paid_date_in_office_time, because that is the one that I believe has to be
used in the real system, either when the payment time is entered or when 
the late calcs are being made, in order to get the right results in terms 
of assessing late fees. */

CREATE VIEW payment_calcs AS
SELECT 
payment.office_location, 
payment.office_time_zone, 
payment.office_gmt_offset, 
payment.due_date_in_office_time_zone, 
payment.paid_date_in_server_time_zone, 
(payment.due_date_in_office_time_zone - payment.office_gmt_offset) 
AS due_date_in_gmt, 
-- The GMT when the payment is due.
timezone('GMT'::text, payment.paid_date_in_server_time_zone) 
AS paid_date_in_gmt,
-- The GMT when the payment was received. 
(timezone('GMT'::text, 
payment.paid_date_in_server_time_zone) + 
payment.office_gmt_offset) AS paid_date_in_office_time, 
-- The time when the payment was received, converted into
-- the time zone of the receiving office.
((timezone((payment.office_time_zone)::text,
payment.paid_date_in_server_time_zone))::timestamp 
with time zone - payment.due_date_in_office_time_zone) 
AS late_by_time_zone_code,
-- The time interval between the due date and the payment,
-- calculated using the PostgreSQL time zone code.
-- Note that the Bangalore result is wrong by 1/2 hour
-- because the nearest PG code is wrong by 1/2 hour.
(((timezone('GMT'::text, payment.paid_date_in_server_time_zone) + 
payment.office_gmt_offset))::timestamp with time zone 
- payment.due_date_in_office_time_zone) AS late_by_offset
-- The time interval between the due date and the payment,
-- calculated using the office_gmt_offset.
-- Note that the Bangalore result is right 
-- because the offset is right.
FROM payment 
ORDER BY (payment.office_gmt_offset)::time without time zone;


INSERT INTO payment VALUES ('Paris', 'CET', '01:00:00', '2006-02-15
17:00:00-06', '2006-02-15 08:00:00-06');
INSERT INTO payment VALUES ('Baghdad', 'BT', '03:00:00', '2006-02-15
17:00:00-06', '2006-02-15 08:00:00-06');
INSERT

Re: [GENERAL] Does PG really lack a time zone for India?

2006-02-15 Thread Ken Winter
Tom ~

Thanks for yet another prompt and helpful response.  May I submit a
follow-up question?

Briefly, what I'm trying to do is build a (web-front-ended) system that
translates a now() entry into a timestamptz column into now at a
specified time zone (which is looked up from the database).  

Why?  Say there's a payment deadline recorded in a database column, and that
deadline is supposed to be as of the local time of the office that accepted
the order.  The database has tables and columns that record the time zone of
each office and associate each order with the office that accepted it.  Say
there's an actual payment column that records the actual time when a payment
is received, and that column is compared to the deadline column to determine
whether to charge a late fee.  Say I place an order with the London office
(GMT), but I am in California (GMT+8) (and the PostgreSQL server is there,
too).  If I pay one hour before the deadline, CA time, I should be charged a
late fee, because the deadline actually occurred 7 hours ago in London.  To
have that come out right, the system needs to translate now() on input to
now() AT TIME ZONE 'GMT', so that the timestamp that gets stored in the
payment column is 7 hours after the deadline.  As far as I can tell, that
works fine - that is, I submit such a query to PostgreSQL and it returns the
correct time in that zone.  The problem comes when PostgreSQL has no time
zone code that gives me the GMT offset that I need - most painfully, that is
the case with India (GMT+5:30).

So, I'm wondering if the AT TIME ZONE construct can accept the offset in
any syntax that isn't dependent on the time zone code.  I tried entries such
as now() AT TIME ZONE 'GMT+5:30' and now() AT TIME ZONE '+5:30', but
they didn't work.  Any suggestions?

~ Thanks again
~ Ken

PS: If it would be of any help, I would be happy to share the country uses
timezone table that I cobbled together yesterday, mapping the existing PG
7.4 time zone codes (sometimes renamed) to a country list derived from lists
of countries that have postal codes and/or international dialing prefixes.
It's yet another hack, but hey it's free for the asking.  (Given the lack of
a worldwide standard for time zone names and abbreviations, any such effort
is going to be something of a hack; I think the best we can hope for is a
list of names and codes that most people can recognize, but a fully correct
list of the GMT offsets.)

PPS:  I'm glad that PG 8.x has discovered India.  Alas, my web host informs
me that I'm stuck with 7.4 until a production version of the psycopg2
connector comes out.


 -Original Message-
 From: Tom Lane [mailto:[EMAIL PROTECTED]
 Sent: Wednesday, February 15, 2006 12:34 AM
 To: [EMAIL PROTECTED]
 Cc: 'PostgreSQL pg-general List'
 Subject: Re: [GENERAL] Does PG really lack a time zone for India?
 
 Ken Winter [EMAIL PROTECTED] writes:
  The documentation
  (http://www.postgresql.org/docs/7.4/static/datetime-keywords.html) =
  doesn't
  have an entry for Indian Standard Time, nor for any other time zone with
 =
  a
  GMT+5:30 offset.
 
 I don't see any such entry in datetktbl in datetime.c, either.  You
 could enter it explicitly as +5:30, though, and (as of PG 8.0) there
 are settings in the main timezone database for India.  (In PG 7.4
 it'd depend on what zone names your operating system knows.)
 
 regression=# set timezone = 'GMT';
 SET
 regression=# select now();
   now
 ---
  2006-02-15 05:20:33.317049+00
 (1 row)
 
 regression=# select '2006-02-15 05:20:33.317049+05:30'::timestamptz;
   timestamptz
 ---
  2006-02-14 23:50:33.317049+00
 (1 row)
 
 regression=# set timezone = 'Asia/Calcutta';
 SET
 regression=# select now();
now
 --
  2006-02-15 10:51:19.241808+05:30
 (1 row)
 
 The existence of duplicate timezone abbreviations is certainly a pain
 :-(.  The solution I would like to see is to factor all the hardwired
 timezone abbreviations in datetktbl out into a configuration file that
 could be adjusted for local conditions.  However, it's not entirely
 clear how to deal with words that could be either a zone name or some
 other date keyword, for instance SAT is not just a day of the week
 but a known zone name in Australia.
 
 Plan B would be to extend the existing australian_timezones hack with
 some other specialized options, but I think that way madness lies ...
 
 Anyway, what this area needs is for somebody to get annoyed enough
 to design and then code a generally acceptable solution.
 
   regards, tom lane


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


Re: [GENERAL] Does PG really lack a time zone for India?

2006-02-15 Thread Ken Winter
 -Original Message-
 From: Tom Lane [mailto:[EMAIL PROTECTED]
 Sent: Wednesday, February 15, 2006 10:25 AM
 To: [EMAIL PROTECTED]
 Cc: 'PostgreSQL pg-general List'
 Subject: Re: [GENERAL] Does PG really lack a time zone for India?
 
 Ken Winter [EMAIL PROTECTED] writes:
  Briefly, what I'm trying to do is build a (web-front-ended) system that
  translates a now() entry into a timestamptz column into now at a
  specified time zone (which is looked up from the database).
 
  Why?  Say there's a payment deadline recorded in a database column, and
 that
  deadline is supposed to be as of the local time of the office that
 accepted
  the order.  The database has tables and columns that record the time
 zone of
  each office and associate each order with the office that accepted it.
 Say
  there's an actual payment column that records the actual time when a
 payment
  is received, and that column is compared to the deadline column to
 determine
  whether to charge a late fee.  Say I place an order with the London
 office
  (GMT), but I am in California (GMT+8) (and the PostgreSQL server is
 there,
  too).  If I pay one hour before the deadline, CA time, I should be
 charged a
  late fee, because the deadline actually occurred 7 hours ago in London.
 To
  have that come out right, the system needs to translate now() on input
 to
  now() AT TIME ZONE 'GMT', so that the timestamp that gets stored in
 the
  payment column is 7 hours after the deadline.
 
 I think you're thinking about this in entirely the wrong fashion.
 
 What you are really saying is that you want to deal with absolute time:
 the payment deadline is a fixed time instant and you don't want the
 observer's timezone to affect the decision about whether the deadline
 has passed or not.  The way to do that in Postgres is to store all
 timestamps as TIMESTAMP WITH TIME ZONE and not do any explicit timezone
 translations.  When you enter a timestamp value, either write the
 correct GMT offset in it, eg '2006-02-15 10:22:46-05', or leave it out
 and the database will assume that it's expressed in the current TimeZone
 zone.  Either way, it'll get converted to UTC internally and all
 subsequent comparisons are absolute.
 
   regards, tom lane

Yes, that's what I'm trying to do.  My problem has been: how to enter the
equivalent of '2006-02-15 10:22:46-05' when the time I want to enter and
convert to EST is a variable value or now().

I've finally figured out the answer - do data entry through:
timestamptz variable value AT TIME ZONE 'GMT' + '-5:00'
and
now() AT TIME ZONE 'GMT' + '-5:00'
You can substitute a variable of type interval for the '-5:00' constant.

These could of course also be accomplished by:
timestamptz variable value AT TIME ZONE 'EST'
and
now() AT TIME ZONE 'EST'
But the first solution bypasses PostgreSQL's incomplete list of time zone
codes.  So it can be used to handle the missing time codes for (for example)
India (GMT+5:30) and Nepal (GMT+5:45), which is what I need.

~ Thanks to all for the help!
~ Ken


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


[GENERAL] Does PG really lack a time zone for India?

2006-02-14 Thread Ken Winter








The documentation (http://www.postgresql.org/docs/7.4/static/datetime-keywords.html)
doesnt have an entry for Indian Standard Time, nor for any other time
zone with a GMT+5:30 offset. 



Is this just an omission from the documentation? If
so, what are the name and codes of the GMT+5:30 time
zone? 



Or does PostgreSQL really have no time zone that it can
read for this rather important place? If so, can this problem be fixed?




(I believe the standard code for Indian Standard Time is
IST, which alas conflicts with PostgreSQLs code for Israel Standard Time,
so I guess some other code needs to be used for India.)



The documentation and/or PostgreSQL itself are also
missing some other GMT offsets:




 GMT+5:45 (Nepal)
 GMT+11 (various mid-Pacific islands)  There actually
 is one zone with this offset, but it is an Australian daylight saving time
 zone (AESST), so using it for standard time is a bit untidy.
 GMT+11:30 (Norfolk
  Island)
 GMT+13 and GMT+14 (Kribali, Tonga) 
 Yes indeed, these Pacific islands are actually more than 12 hours ahead of
 GMT!




These are less important than India because
(except for Nepal) they only apply to a few Pacific
islands, but if someone were to go in there and fix the India problem,
it might be a good time to tidy these up as well.



~ TIA 

~ Ken








Re: [GENERAL] Why does an ON SELECT rule have to be named _RETURN?

2006-02-13 Thread Ken Winter
Stephan ~

You're right: This thing I call a view-table would behave *exactly* like a
view that has insert, update, and delete rules.  

The *only* difference I'm trying to achieve is to get it stored in
pg_catalog.pg_class with relkind = 'r' (ordinary table) rather than 'v'
(view).  

The *only* reason I'm trying to disguise a view as a table is to trick my
client tools into letting me use their handy pre-made forms and grids to
read and write to these structures.

The reason I'm trying to activate these forms and grids is to enable my
testing users to start entering and viewing test data immediately - without
their having to learn and write SQL, and without my having to build data
entry and review forms for them.

I thought, all things considered, my little trick - admittedly a workaround
- would be the easiest way to achieve what I need without requiring anything
of either the PostgreSQL architects or the tool builders.  So it is
frustrating to be defeated by this one PostgreSQL constraint (which isn't
even published in the documentation, as far as I can see).  

I just had another workaround idea - declare the view-table as an ordinary
table and put triggers on it that implement the functionality of the rules -
but before resorting to that I thought I'd try my simpler trick once more.

So let me ask again: Is there any way to disable this constraint that forces
the SELECT rule to be named _RETURN?  Or is there any other way to
accomplish what I'm trying to do?

~ Thanks again
~ Ken

 -Original Message-
 From: Stephan Szabo [mailto:[EMAIL PROTECTED]
 Sent: Sunday, February 12, 2006 11:39 PM
 To: Ken Winter
 Cc: 'Tom Lane'; 'PostgreSQL pg-general List'
 Subject: Re: [GENERAL] Why does an ON SELECT rule have to be named
 _RETURN?
 
 On Sun, 12 Feb 2006, Ken Winter wrote:
 
   -Original Message-
   From: Stephan Szabo [mailto:[EMAIL PROTECTED]
   Sent: Sunday, February 12, 2006 8:47 PM
   To: Ken Winter
   Cc: 'Tom Lane'; 'PostgreSQL pg-general List'
   Subject: Re: [GENERAL] Why does an ON SELECT rule have to be named
   _RETURN?
  
   On Sun, 12 Feb 2006, Ken Winter wrote:
  
Hi Tom ~
   
You're right:  I appealed to the PostgreSQL folks rather than the
 client
tool builders.  I did so because my guess is that the latter have a
   harder
row to hoe:  They have to figure out whether a view really IS
 updatable
   -
most presumably aren't, so if they provide forms that offer to
 update
   views,
most of the time these forms are going to crash.  It seems harder
 for
   the
client tool builders to figure out the updatability question than
 for
PostgreSQL to let people (like me) do the real table with ON
 SELECT
   trick
and take responsibility for making it work.  I don't see why that is
inherently broken.
  
   What does a real table with ON SELECT mean?
 
  It means a table that, due to the rules on it, works exactly like a view
  (from the client's perspective).  (Here, let me call it a view-table.)
 No
  row ever gets inserted into the view-table.  The rules deflect inserts
 into
  one or more base tables.  Updates and deletes, though from the client's
 view
  they modify or remove rows in the view-table, actually update and delete
 in
  the underlying base tables.
 
 How is this different from a view with on insert, on update and on delete
 rules right now?
 
   For example, if a row is
   inserted that doesn't come into the on select output, was a row
   inserted?
 
  In what I'm doing, that would not happen.  But there might be a case
 where
  someone would want a design where rows inserted through the view-table,
  though they do get inserted into the underlying base tables, would not
 be
  visible through SELECT actions on the view-table.  I can't imagine
 offhand
  why anyone would want to do this, but I don't see why PostgreSQL should
 stop
  them.  (...Actually, on second thought, I have thought of doing a trick
 like
  this myself, to get around the PostgreSQL constraint I'm complaining
 about:
  Define a view-table with all of the update rules on it, so no rows ever
 get
  inserted into it but my client tools can do updates against it; then
 define
  a second, read-only, view for SELECTs to reveal the data entered through
 the
  first view.  Right; I would rather not stoop to this.)
 
   Can it cause unique key violations, can it satisfy a foreign key
   constraint?
 
  PK, UK, FK, and check constraints would all be defined on the base
 tables,
  not on the view-table.  So actions on the view-table would satisfy or
  violate these constraints, like any other actions redirected through
  PostgreSQL update rules.
 
 But then this view-table isn't really a real table. If it's not a
 real table, it pretty much defeats the original stated argument of having
 real tables with on select rules.


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

[GENERAL] Why does an ON SELECT rule have to be named _RETURN?

2006-02-12 Thread Ken Winter
I'm trying to build something that behaves like an updatable view but that
PostgreSQL (version 7.4) regards and presents to the world as a table.  

The reason I want to do this odd thing is that my front-end tools
(phpPgAdmin and PostgreSQL Lightning Admin) have handy pre-made data entry
and viewing forms, but they only work against tables (not against views).

The PostgreSQL documentation
(http://www.postgresql.org/docs/7.4/static/rules-views.html) says that:

There is essentially no difference between

CREATE VIEW myview AS SELECT * FROM mytab;

compared against the two commands

CREATE TABLE myview (same column list as mytab);
CREATE RULE _RETURN AS ON SELECT TO myview DO INSTEAD
SELECT * FROM mytab;

because this is exactly what the CREATE VIEW command does internally.

OK, I figured, so if I turn my existing view (made updatable by suitable ON
INSERT, ON UPDATE, and ON DELETE rules), which works fine, into a table with
an ON SELECT rule on the above pattern, that ought to work.  But I decided
to name my ON SELECT rule something other than _RETURN, so PostgreSQL
wouldn't suspect what I was up to.  Alas, PostgreSQL responded with an error
message saying that a view rule...must be named _RETURN'.  When I renamed
it thus, PostgreSQL accepted the whole thing - but ended up classifying the
resulting structure as a view, which defeated my purpose of making it
accessible through my front-end tools.

So I'm wondering:  

* Why this constraint?  
* Would anything break if I were allowed to get away with my little trick?  
* Is there any way to get around the constraint?

~ TIA
~ Ken


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


Re: [GENERAL] Why does an ON SELECT rule have to be named _RETURN?

2006-02-12 Thread Ken Winter
Hi Tom ~

You're right:  I appealed to the PostgreSQL folks rather than the client
tool builders.  I did so because my guess is that the latter have a harder
row to hoe:  They have to figure out whether a view really IS updatable -
most presumably aren't, so if they provide forms that offer to update views,
most of the time these forms are going to crash.  It seems harder for the
client tool builders to figure out the updatability question than for
PostgreSQL to let people (like me) do the real table with ON SELECT trick
and take responsibility for making it work.  I don't see why that is
inherently broken.  

Everybody from E.F. Codd onward has struggled with the view updatability
problem; it seems like PostgreSQL is one unnecessary constraint away from
letting users find a pragmatic solution (a.k.a. workaround) for it.

~ Ken


 -Original Message-
 From: Tom Lane [mailto:[EMAIL PROTECTED]
 Sent: Sunday, February 12, 2006 6:43 PM
 To: [EMAIL PROTECTED]
 Cc: 'PostgreSQL pg-general List'
 Subject: Re: [GENERAL] Why does an ON SELECT rule have to be named
 _RETURN?
 
 Ken Winter [EMAIL PROTECTED] writes:
  * Why this constraint?
  * Would anything break if I were allowed to get away with my little
 trick?
  * Is there any way to get around the constraint?
 
 The reason why the table is converted to a view is that ancient pg_dump
 dumps used to create views in exactly that way (make a table and then
 add an ON SELECT rule) and so when we started making a hard distinction
 between tables and views, we needed to force the conversion to occur.
 
 The notion of a real table that has an ON SELECT rule seems fairly
 broken to me in any case.  I think you should be complaining to the
 authors of your client-side tools that they won't do what you want.
 It would probably be quite a trivial change to get them to support
 data entry forms against views, but changing the backend on this
 point won't be an easy sell.
 
   regards, tom lane


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


Re: [GENERAL] Why does an ON SELECT rule have to be named _RETURN?

2006-02-12 Thread Ken Winter


 -Original Message-
 From: Stephan Szabo [mailto:[EMAIL PROTECTED]
 Sent: Sunday, February 12, 2006 8:47 PM
 To: Ken Winter
 Cc: 'Tom Lane'; 'PostgreSQL pg-general List'
 Subject: Re: [GENERAL] Why does an ON SELECT rule have to be named
 _RETURN?
 
 On Sun, 12 Feb 2006, Ken Winter wrote:
 
  Hi Tom ~
 
  You're right:  I appealed to the PostgreSQL folks rather than the client
  tool builders.  I did so because my guess is that the latter have a
 harder
  row to hoe:  They have to figure out whether a view really IS updatable
 -
  most presumably aren't, so if they provide forms that offer to update
 views,
  most of the time these forms are going to crash.  It seems harder for
 the
  client tool builders to figure out the updatability question than for
  PostgreSQL to let people (like me) do the real table with ON SELECT
 trick
  and take responsibility for making it work.  I don't see why that is
  inherently broken.
 
 What does a real table with ON SELECT mean? 

It means a table that, due to the rules on it, works exactly like a view
(from the client's perspective).  (Here, let me call it a view-table.)  No
row ever gets inserted into the view-table.  The rules deflect inserts into
one or more base tables.  Updates and deletes, though from the client's view
they modify or remove rows in the view-table, actually update and delete in
the underlying base tables.

 For example, if a row is
 inserted that doesn't come into the on select output, was a row
 inserted?

In what I'm doing, that would not happen.  But there might be a case where
someone would want a design where rows inserted through the view-table,
though they do get inserted into the underlying base tables, would not be
visible through SELECT actions on the view-table.  I can't imagine offhand
why anyone would want to do this, but I don't see why PostgreSQL should stop
them.  (...Actually, on second thought, I have thought of doing a trick like
this myself, to get around the PostgreSQL constraint I'm complaining about:
Define a view-table with all of the update rules on it, so no rows ever get
inserted into it but my client tools can do updates against it; then define
a second, read-only, view for SELECTs to reveal the data entered through the
first view.  Right; I would rather not stoop to this.)

 Can it cause unique key violations, can it satisfy a foreign key
 constraint?

PK, UK, FK, and check constraints would all be defined on the base tables,
not on the view-table.  So actions on the view-table would satisfy or
violate these constraints, like any other actions redirected through
PostgreSQL update rules.

~ Ken


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

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


Re: [GENERAL] NEW variable values in actions in rules

2006-02-01 Thread Ken Winter
Tom ~

Your answers (below) to my questions about the values of NEW columns in
trigger functions was very clarifying for me (as well as being correct!).
Now I'm having similar problems with NEW values in actions that are embedded
in rules, and the answers don't seem to be the same.

I have a table person_h with a not-null column effective_date_and_time
that defaults to CURRENT_TIMESTAMP.

I have a view person with the following rule defined on it:

CREATE RULE on_insert AS 
ON INSERT TO person 
DO INSTEAD (
INSERT INTO person_i (person_id, birth_date) 
VALUES (nextval('pop_seq'::text), new.birth_date); 
INSERT INTO person_h (person_id, ...
effective_date_and_time,...) 
VALUES (currval('pop_seq'::text), last_name, ...
new.effective_date_and_time, new.last_name, ...);

where the ...s are some other columns not of interest here.

So now when I do this query:

insert into public.person (last_name) values ('Jones');

I get this error:

PostgreSQL Error Code: (1)
ERROR:  null value in column effective_date_and_time violates not-null
constraint--0 Rows Affected

So the query processor seems not to be behaving as you described in
answering my question 2 below: it is not taking the
NEW.effective_date_and_time value to be whatever the default is for the
column.

If I submit the same INSERT INTO person_h... query directly, rather than
as part of the rule, it works fine.

Help?

~ TIA
~ Ken


 -Original Message-
 From: Tom Lane [mailto:[EMAIL PROTECTED]
 Sent: Thursday, January 05, 2006 7:49 PM
 To: Ken Winter
 Cc: PostgreSQL pg-general List
 Subject: Re: [GENERAL] NEW variable values in trigger functions
 
 Ken Winter [EMAIL PROTECTED] writes:
  1. What is the value of the NEW variable for a column that is not
 mentioned
  in an UPDATE statement?  Is it NULL?  If not NULL, what?
 
 No, it's whatever value is going to be assigned to the new row (which in
 this particular case would be the same as the OLD value).
 
  2. Same questions re the value of a NEW variable that is not assigned a
  value in an INSERT statement.
 
 Same answer: whatever value is due to go into the row (in this case,
 whatever the default is for the column).
 
  3. If an UPDATE query set a column to DEFAULT, what value does a trigger
  function see for the column's NEW variable?
 
 Same answer.
 
   regards, tom lane



---(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


[GENERAL] Seeking a better PL/pgSQL editor-debugger

2006-01-28 Thread Ken Winter








Is a better PL/pgSQL editor / debugger than pgAdmin III or
phpPgAdmin available anywhere?



I ask because I was stuck for two days on the following
error message:



ERROR: syntax error at or near LOOP

CONTEXT: compile of PL/pgSQL function gen_history
near line 126



and neither of those tools offered any more help
than that. It turned out the error was a missing ; way back
in line 53, and it took two days of trial and error and staring at the code to
find it. (On the positive side, pgAdmin IIIs use of different
colors to distinguish different program elements [variables, keywords, string
constants, comments] made the staring part easier to do.)



Ive learned that pgAdmin syntax error
can mean anything from a missing ; to a faulty block structure to
an undeclared variable to I dont know what else, and as witness
the example that error may be nowhere near the line that is flagged. So Im
looking for a PL/pgSQL tool that would at least provide more diagnostic error messages.
Preferably, it would also offer some sort of breakpoint function
to let the developer see the values of variables at specified points in the
code. 



I looked on the pgAdmin web site. The only place a PL/pgSQL
debugger was mentioned was on the to do page, under major projects
(http://www.pgadmin.org/development/todo.php),
which I guess means dont hold your breath. 



As editors, the two pgAdmin tools apparently dont offer
elementary functions such as find and replace, which means I have to slurp my
code out into a text editor when I really need these things.



So I guess my questions are:




 Is it the case that the pgAdmin tools actually do
 offer these features, but I just havent found them yet? If
 so, can you show me where they are?
 Are these functions available through add-ons to either
 pgAdmin tool? If so, where can I get these add-ons?
 Are there other PL/pgSQL editors that provide these functions?
 If so, what? Obviously, Id prefer a free one, but would pay
 for one if necessary.




~ TIA

~ Ken








Re: [GENERAL] Seeking a better PL/pgSQL editor-debugger

2006-01-28 Thread Ken Winter
Tom ~

Thanks for the news.  I'm on PostgreSQL 7.4.7, alas, and there's nothing I
can do about it because it resides on a host that I don't control.  I
suppose if I don't find an alternative, I could move my development work to
a local installation of PostgreSQL 8.1.

~ Ken

 -Original Message-
 From: Tom Lane [mailto:[EMAIL PROTECTED]
 Sent: Saturday, January 28, 2006 1:26 PM
 To: Ken Winter
 Cc: PostgreSQL pg-general List
 Subject: Re: [GENERAL] Seeking a better PL/pgSQL editor-debugger
 
 Ken Winter [EMAIL PROTECTED] writes:
  I ask because I was stuck for two days on the following error message:
  ERROR:  syntax error at or near LOOP
  CONTEXT:  compile of PL/pgSQL function gen_history near line 126
  and neither of those tools offered any more help than that.  It turned
 out
  the error was a missing ; way back in line 53, and it took two days of
  trial and error and staring at the code to find it.
 
 What Postgres version are you using?
 
 I would blame the backend more than the client tools for the failure to
 localize this syntax error.  We've made significant progress in 8.0
 and again in 8.1 on improving plpgsql's error messages --- if you are
 not on 8.1 the first thing to try is a backend upgrade.
 
   regards, tom lane






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

   http://archives.postgresql.org


[GENERAL] NEW variable values in trigger functions

2006-01-05 Thread Ken Winter
1. What is the value of the NEW variable for a column that is not mentioned
in an UPDATE statement?  Is it NULL?  If not NULL, what?

For example, given this table:

   my_tbl (id integer, att1 varchar, att2 varchar)

and a row-wise ON UPDATE OR INSERT trigger function containing this
conditional:

   IF NEW.att2 IS NULL THEN
do stuff
   END IF;
   
and this UPDATE query:

UPDATE my_tbl SET att1 = 'foo' where id = 1;

will that conditional be satisfied?

2. Same questions re the value of a NEW variable that is not assigned a
value in an INSERT statement.  

For example, how would the previous conditional behave in response to:

INSERT INTO my_tbl (id) VALUES (1);

?

3. If an UPDATE query set a column to DEFAULT, what value does a trigger
function see for the column's NEW variable?  Is it the string 'DEFAULT', a
reserved word DEFAULT, an empty string, or what?

For example, what would you put in place of ?? in this UPDATE trigger
function:

   IF NEW.att2 ?? THEN
do stuff
   END IF;

to get it to do stuff in response to this UPDATE query:

UPDATE my_tbl SET att2 = DEFAULT where id = 1;

?

~ TIA
~ Ken



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


Re: [GENERAL] In processing DDL, when does pg_catalog get updated?

2005-12-31 Thread Ken Winter
Tom ~

Right you are!  I added some code to trim off the schema name, and it works
fine.

You also alerted me to the NOTICE facility.  (I'm new to PostgreSQL, and
have been learning it in wade right in mode rather than properly studying
the whole environment.)  I have a PostgreSQL for Dummies question about
RAISE NOTICE:  Where do I find its output?  According to the documentation
(http://www.postgresql.org/docs/7.4/static/plpgsql-errors-and-messages.htmlh
ttp://www.postgresql.org/docs/7.4/static/plpgsql-errors-and-messages.html),
the messages are either reported to the client, written to the server log,
or both.  My database is on a web host (zettai.net), and I'm working on it
via phpPgAdmin.  I don't know where to find messages reported to the
client, and I don't know how to access the system log.  Can anyone help?

~ Thanks!
~ Ken


 -Original Message-
 From: Tom Lane [mailto:[EMAIL PROTECTED]
 Sent: Friday, December 30, 2005 12:10 PM
 To: Ken Winter
 Cc: 'PostgreSQL pg-general List'
 Subject: Re: [GENERAL] In processing DDL, when does pg_catalog get
 updated?
 
 Ken Winter [EMAIL PROTECTED] writes:
  My question is: Why didn't the chunk of gen_sequences code that
 consults
  pg_catalog find a record of e_mail_address_invisible_id_seq, and
 thereby
  refrain from trying to create it again?
 
 I added a few raise notice commands to your function, and got this:
 
 NOTICE:  sub_idcol = invisible_id
 NOTICE:  default_exp =
 nextval('public.e_mail_address_invisible_id_seq'::text)
 NOTICE:  sequence_name = public.e_mail_address_invisible_id_seq
 NOTICE:  not found
 NOTICE:  sub_idcol = pop_id
 NOTICE:  default_exp = nextval('pop_seq'::text)
 NOTICE:  sequence_name = pop_seq
 NOTICE:  found
 ERROR:  relation e_mail_address_invisible_id_seq already exists
 CONTEXT:  SQL statement CREATE SEQUENCE
 public.e_mail_address_invisible_id_seq;
 PL/pgSQL function gen_sequences line 51 at execute statement
 
 The problem seems to be that you're not accounting for a schema name
 possibly appearing in nextval's argument.
 
   regards, tom lane



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

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


Re: [GENERAL] In processing DDL, when does pg_catalog get updated?

2005-12-30 Thread Ken Winter
Tom ~

Good idea.  The grisly details are as follows.



Here is the DDL script (generated from PowerDesigner 10.1.0.1134):

/*==*/
/* DBMS name:  PostgreSQL 7.3   */
/* Created on: 12/30/2005 11:08:02 AM   */
/*==*/

SET search_path TO public;

/*==*/
/* Table: e_mail_address*/
/*==*/
create table e_mail_address (
pop_id   INT8 not null default
nextval('pop_seq'),
effective_date_and_time TIMESTAMP WITH TIME ZONE not null default
CURRENT_TIMESTAMP,
invisible_id BIGSERIALnot null,
e_mail_type  VARCHAR(255) null,
expiration_date_and_time TIMESTAMP WITH TIME ZONE null default 'infinity',
user_nameVARCHAR(255) not null,
domain_name  VARCHAR(255) not null,
use_this_e_mail_for_administrative_matters BOOL null,
use_this_e_mail_for_teaching_and_practice BOOL null,
use_this_e_mail_for_personal_messages BOOL null,
omit_this_e_mail_from_school_directory BOOL null,
comments VARCHAR(4000)null,
constraint PK_e_mail_address_priority_pk primary key (pop_id,
effective_date_and_time, invisible_id),
constraint fk_contact___e_mail_address foreign key (pop_id)
   references pop (pop_id)
on delete cascade on update cascade,
constraint fk_e_mail_type___e_mail_address foreign key (e_mail_type)
   references e_mail_type (e_mail_type)
on delete cascade on update cascade
)
INHERITS (when_and_who)
WITH OIDS;

SELECT gen_sequences('e_mail_address', 'public');



Here is the function gen_sequences that is evoking the error:

CREATE OR REPLACE FUNCTION gen_sequences ( VARCHAR, VARCHAR ) RETURNS
VARCHAR AS
'
DECLARE
table_name ALIAS FOR $1; 
schema_name ALIAS FOR $2;
this_table RECORD;
dummy RECORD;
sequence_name VARCHAR;
cre_seq_arr VARCHAR [] := ''{}'';
cre_seq_code VARCHAR := ;
BEGIN
EXECUTE ''SET search_path TO '' || schema_name;

/* Create a CREATE SEQUENCE statement for the sequence
of each sequence-assigned column, 
if the sequence doesnt exist already. */
FOR this_table IN 
SELECT c.column_name AS sub_idcol, 
c.column_default AS default_expr
FROM information_schema.columns c
WHERE c.table_name = table_name
AND c.table_schema = schema_name
AND c.column_default LIKE ''nextval%''
LOOP
sequence_name := split_part(this_table.default_expr, ,
2);
IF NOT EXISTS (SELECT 1 
FROM pg_catalog.pg_class AS t, 
pg_catalog.pg_namespace AS s
WHERE t.relname = sequence_name
AND s.nspname = schema_name
AND t.relnamespace = s.oid
AND t.relkind = ''S'') 
THEN
IF array_upper(cre_seq_arr, 1) IS NULL THEN
cre_seq_arr[1] := ''CREATE SEQUENCE '' || sequence_name
|| '';'' ;  
ELSE  
cre_seq_arr[array_upper(cre_seq_arr, 1) + 1] := ''CREATE
SEQUENCE '' || sequence_name || '';'' ;
END IF;
cre_seq_code := cre_seq_code ||
cre_seq_arr[array_upper(cre_seq_arr, 1)] || ''
''; 
END IF;
END LOOP;

/* Execute the CREATE SEQUENCE statements, if any. */
IF array_upper(cre_seq_arr, 1) IS NOT NULL THEN
FOR n IN 1..array_upper(cre_seq_arr, 1) LOOP
EXECUTE cre_seq_arr[n];
END LOOP;
END IF;
RETURN  cre_seq_code;
END;
'
LANGUAGE plpgsql
;



And here is the error message from phpPgAdmin:

SQL error:

ERROR:  relation e_mail_address_invisible_id_seq already exists
CONTEXT:  PL/pgSQL function gen_sequences line 45 at execute statement



Line 45 is the line that contains the execute statement.

Those are the raw facts.  

My question is: Why didn't the chunk of gen_sequences code that consults
pg_catalog find a record of e_mail_address_invisible_id_seq, and thereby
refrain from trying to create it again?

~ Thanks again
~ Ken



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


[GENERAL] In processing DDL, when does pg_catalog get updated?

2005-12-29 Thread Ken Winter
I'm running a DDL script that does the following (in this order):

1. Creates a table containing a BIGSERIAL primary key column declaration,
which apparently automatically creates a sequence to populate this column.

2. Runs a gen_sequences function that I wrote, which executes CREATE
SEQUENCE statements for all columns in the table that have defaults like
'nextval%' but that don't already have sequences.  The part of the function
that checks that the sequence doesn't already exist consults the pg_catalog,
as follows:
IF NOT EXISTS (SELECT 1 
FROM pg_catalog.pg_class AS t, 
pg_catalog.pg_namespace AS s
WHERE t.relname = sequence_name
AND s.nspname = schema_name
AND t.relnamespace = s.oid
AND t.relkind = 'S') 
THEN  
execute the CREATE SEQUENCE statement
END IF;   

This script aborts with a message like this:

ERROR:  relation my_table_id_seq already exists

...which implies that the code above is not finding my_table_id_seq in the
catalog.  I know that the code works OK in detecting sequences that
pre-existed the execution of this script.  So the only explanation that I
can come up with is that, at step 2, the pg_catalog has not yet been updated
to reflect the results of step 1 - namely, that the new sequence has been
created.

Is it possible that the pg_catalog is not updated with the results of a DDL
script until the whole script has executed?

If this is so, is there any way to force the pg_catalog to be updated along
the way?

~ TIA
~ Ken




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


[GENERAL] Error in 7.4.9 Documentation

2005-12-08 Thread Ken Winter








FWIW: At http://www.postgresql.org/docs/7.4/static/infoschema-triggers.html,
it says there is a column in the information_schema triggers
table named event_object_name. The name actually is event_object_table.



~ Ken








Re: [GENERAL] How to run a stored PL/pgSQL function?

2005-12-01 Thread Ken Winter
That works.  Thanks!  (Thanks also to Joshua Drake, who contributed the same
answer.) 

~ Ken

 -Original Message-
 From: Michael Glaesemann [mailto:[EMAIL PROTECTED]
 Sent: Wednesday, November 30, 2005 11:19 PM
 To: Ken Winter
 Cc: PostgreSQL pg-general List
 Subject: Re: How to run a stored PL/pgSQL function?
 
 
 On Dec 1, 2005, at 12:38 , Ken Winter wrote:
 
  How can I cause a PL/pgSQL function to be executed from a SQL script?
 snip /
  I have a PL/pgSQL foo (varchar).
 select foo(bar); -- where bar is of type varchar
 
 
 Michael Glaesemann
 grzm myrealbox com
 
 




---(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