[GENERAL] Reset privileges to builtin defaults

2017-04-28 Thread Diego Augusto Molina
Hi, I've been charged with the administration of a couple of big
databases in an old 8.1 cluster. The databases have many
administrative issues, privileges being the most prominent for my job.
All objects have privileges for specific personal end-user roles
(dozens and dozens of privileges each object) instead of using profile
roles with the correct privileges and membership granted to specific
personal roles. I have identified the profiles and granted them to the
personal roles. Now I need to reset all privileges on all objects to
the builtin defaults and grant the correct privileges to the profile
roles.

Part of the job is also migrating to version 9.6 (current stable as of
today), but as far as I can see in the documentation there's no clean
way of achieving my task not even in that version, so postponing it
will not help. So I decided to take a risk and modify system catalogs
in a test 8.1 environment with success up to what I can see. What I
did is to create three functions that take an OID: one for databases,
one for functions and the last for relations (ordinary table,
sequence, view with extended capability for materialized view,
composite type or foreign table only for the case I'd use these
functions in a more recent cluster some time in the future). They all
perform three basic things:
1) Set the ACL field of the object to NULL in the correct catalog.
2) Delete the ACL dependencies of the object on any role by deleting
from "pg_shdepend".
3) Returning a useful thing: TRUE when privileges are set to the
builtin defaults (wether or not the function actually had to do
something) and FALSE when something goes wrong. They're declared
STRICT, so NULL is returned for NULL input.

These functions could be improved by marking them SECURITY DEFINER and
letting a role reset the privileges of it's owned objects. Also, other
functions should be added for other kind of objects like foreign
servers and such. Certainly, many things might also be useful for
general use but for my current purposes they suffice (although I
wouldn't bother to make these changes as an exercice if someone is
interested and, of course, if I'm on the riht way). I added two kind
of "properties" to the functions defined by "-- @PROTECT: OWNERSHIP
PRIVILEGES" in the code. That makes these functions immune to the
privilege reset function for functions (funny English). You might also
guess I have another function to change the ownership, but that's
another story. Also, superuser owned SECURITY DEFINER functions are
untouched and managed manually for now and only because of my
particular needs.

I tried these functions in the test environment and they seem to work
properly in every use case I could think of, although I would be more
comfortable if an experienced someone gives me it's impressions on
these before I go into production. Please, do!

Here goes the code:

/* BEGIN CODE */
CREATE OR REPLACE FUNCTION reset_privileges_on_database(oid) RETURNS
BOOLEAN AS $BODY$
-- @PROTECT: OWNERSHIP PRIVILEGES

-- Reset privileges on the database
  UPDATE pg_database
SET datacl = NULL
WHERE
  datacl IS NOT NULL AND  -- Only change when necessary
  oid = $1;   -- Change the requested database

-- Delete all ACL dependencies that might have been introduced
  DELETE
FROM pg_shdepend AS s
USING pg_class AS c -- USING list item #1
WHERE
  ( -- Join conditions for the USING list items
  s.classid = c.oid -- When introduced USING list item #1
) AND
  ( -- Specific conditions that normally make up the whole WHERE
clause in a SELECT statement
  s.dbid = 0AND -- We're deleting a shared
object's (databases) dependencies
  s.deptype = 'a'   AND -- The dependencies we're
deleting are ACLs
  c.relname = 'pg_database' AND -- The shared object we're
deleting dependencies of is a database
  s.objid = $1  -- Only delete dependencies of
the requested database
);

-- Return value
  SELECT EXISTS (
  SELECT 1
FROM pg_database
WHERE oid = $1 -- Only the requested database
);
$BODY$ LANGUAGE sql VOLATILE STRICT;
ALTER FUNCTION reset_privileges_on_database(oid) OWNER TO postgres;
REVOKE ALL ON FUNCTION reset_privileges_on_database(oid) FROM public;
COMMENT ON FUNCTION reset_privileges_on_database(oid) IS
'Diego Molina (20170427): Reset all privileges on a database given by
its OID to the builtin defaults.
Return values:
  * NULL: if NULL argument.
  * TRUE: Privileges have been reset.
  * FALSE: Privileges have not been reset. Reason: the given database
does not exist.';

CREATE OR REPLACE FUNCTION reset_privileges_on_function(oid) RETURNS
BOOLEAN AS $BODY$
-- @PROTECT: OWNERSHIP PRIVILEGES

-- Reset privileges on the function
  UPDATE pg_proc AS p
SET proacl = NULL
FROM pg_authid AS o -- FROM list item #1 (function's owner)
WHERE
  ( -- Join conditions
  p.proowner = 

Re: [GENERAL] [Solved] Generic logging system for pre-hstore using plperl triggers

2011-10-03 Thread Diego Augusto Molina
Some errata and round up comments.

First of all, I think it's relevant to give some info about the system
I'm running:
  OS: Linux
  Distro: Gentoo
  Perl: dev-lang/perl-5.12.3-r1 USE=-* berkdb gdbm
  Gentoo Base System release: 2.0.2
  PORTDIR/metadata/timestamp.chk: Tue, 12 Jul 2011 00:45:01 +

2011/10/2, Diego Augusto Molina diegoaugustomol...@gmail.com:
 solved if we use no composite at all! Instead of a field with an array
 of a composite of three instrinsics, use three fields, each of an
 intrinsic type. See your proposal:

Errata: use three fields, each *one being an array of an intrinsic type.*

 mentioned earlier (to reduce space: 2 bytes of type smallint against
 variable size of type text; and to keep track of names been used
 too). You can also set up something like this if you like dimensions:

Errata: and to keep track of names *being* used too)

 Implying that the first dimension is the before value and the second
 one is for the after value. Any of these prevents us from using
 composites and makes the box a little wider and simpler. Even further,
 I would like to keep the logging on demand:

Comment on I would like to keep the logging on demand:
With this I mean to log only those columns wich are part of the
primary key or whose values have changed

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

-- 
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] [Solved] Generic logging system for pre-hstore using plperl triggers

2011-10-02 Thread Diego Augusto Molina
2011/9/28, Merlin Moncure mmonc...@gmail.com:

 I disagree.  unnest() and array_agg() (or, even better, array()
 constructor syntax) are an absolute joy to work with and thinking in a
 more functional way, which is usually the key to making things run
 quickly.  Also both functions are trivial to emulate in userland for
 compatibility.  Arrays of composites IIRC only go back to 8.3 so  that
 would be a true stopper for any solution in that vein.

Ok, tastes are tastes: I hate to make two or three more levels of
subqueries. Regarding arrays of composites, that would be perfectly
solved if we use no composite at all! Instead of a field with an array
of a composite of three instrinsics, use three fields, each of an
intrinsic type. See your proposal:

 create type audit_field_t as (field text, old_value text, new_value text);

Instad, in the audit table you may use:

..., field smallint[], before text[], after text[],...

Note the smallint in field, that means I really want to keep the
reference to the field table. That is for the two reasons I had
mentioned earlier (to reduce space: 2 bytes of type smallint against
variable size of type text; and to keep track of names been used
too). You can also set up something like this if you like dimensions:

..., field smallint[], values text[][],...

Implying that the first dimension is the before value and the second
one is for the after value. Any of these prevents us from using
composites and makes the box a little wider and simpler. Even further,
I would like to keep the logging on demand:

..., field smallint[], is_pk boolean[], { before text[], after text[]
| values text[][] },...

You know what are the braces and pipe for...
So, at the end, we have the entire audet table inside the audit
table, as a series of arrays. We got a real compact table with only
enough data to fully log the changes which triggered the event. No
less, no more.
At this point we know querying this table will be much more slow and
rotation will have to be done more frequently. If we dumprestore the
table somewhere else we will still be able to split the table in the
original two ones, and make indexes, cluster them, and query as
desired. But this can get so complicated that maybe I should implement
a function doing all this. In an event, we are getting less
responsiveness because of this. But a couple of mins more may not be a
problem for most cases. I'm just trying to summarize.

As a rule of thumb, you may need to run a cron job every night or so
to check if 'select count(*) from audit' is bigger than X then rotate
the table (or maybe each X days/weeks/etc.). The smaller the X, the
bigger responsiveness _in_ some cases: if we know an interval in time
we will just have to dumprestore those logs. In other cases this
would not be of much help: if you need to track a tupple to the very
beggining of the times, you'll have a lot of work to do
dumpingrestoring (and so forth... remember to split the table,
indexing...). Still, rotation seems to be a good practice, and you can
include in the cron job the dump/restore part into another server and
then delete the old table. That would save a lot of space in your
production environment.

 As for the rest of it, I'd be looking to try and come up with an all
 sql implementation.  Also you should give an honest comparison between
 what you've come up with vs. this:
 http://pgfoundry.org/projects/tablelog/.

 merlin


All SQL implementation? Didn't we agree that's not possible in
pg=8.4? then what do you mean by that?

About project tablelog, I didn't really try it, but read it's
documentation and seems not appropiate at all for my case. First of
all, it's propose seems to be to log everything in a table to be able
to restore it later as of any time in the past. My propose is to log
to run analysis. Also, it needs to create one table per logged table,
consisting of the same structure of the logged table (without
constraints) plus three, four or five columns for control (depending
on usage, four or five recommended). I have a lot of tables to log
(hundreds!) with small changes to each of them; that means to
duplicate the amount of tables for a few changes. Speaking of
compactness... It also logs everything, not only changed values.
It is written in C, so I assume it runs much, much faster (specially
needed for highly transactional DBs). But it's not proven to be binary
safe (which I don't remember what that is). Bugs: nothing known.

So, if you need to be able to restore your table as of any time, use
tablelog. If you need to run analysis on who did what, use my option.


Finally attaching the code!

Cheers.

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

		/* Created by Diego Augusto Molina in 2011 for Tucuman Government

Re: [GENERAL] [Solved] Generic logging system for pre-hstore using plperl triggers

2011-09-28 Thread Diego Augusto Molina
 a maximum time
for that ;). If instead we would have made a string from the record,
we wouldn't have been able to easily track the tupple.

Note also the rotate(character) function. It hot-rotates the
audit/audet tables similarly to a logrotate program in *nix. At the
same time, you never stop logging, and you can dump the old table
before dropping it (to save space) and restore it somewhere else to
exploit it. We would usually rotate each 6 months or so, but that is
shortening each time with the growing system.

The *real* system is very discreet with I/U/D operations: it's not
usual to have more than one of those operations per second. For higher
transactional systems I think this logging system would be more
noticeable (right now things go smooth). As I said before, if you have
test cases they're very welcome.

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

-- 
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] [Solved] Generic logging system for pre-hstore using plperl triggers

2011-09-28 Thread Diego Augusto Molina
2011/9/28, Merlin Moncure mmonc...@gmail.com:
 Yup -- I get it now.  Well, one point about this is that it seems
 directed towards your personal requirements. This is a very 'heavy'
 audit system that will not be suitable for high performance
 transactional systems.  That said, it looks well thought out.  Storing
 only the changed fields is pretty clever, but I can't help but wonder
 if you're better off using arrays for that purpose:

 create type audit_field_t as (field text, old_value text, new_value text);

 and inside the audit table itself having
   fields audit_field_t,

 and, if at all possible, constructing the array of audit fields in a
 single expression.  This will be much more compact than one record per
 field -- normally, arrays in table definitions tend to be bad mojo but
 this is one case they could be useful.  Audit records are WORM, 'Write
 Once Read Maybe', so compactness is important.   Obviously, for 9.0+,
 I would be rigging a solution around hstore for an 'all sql' solution
 which is usually better if you can get away with it.

 merlin


Well that sounds pretty fair to me. But that flow would not allow me
to make partial indexes on primary key fields. As you can see in the
audet table, there's a column named is_pk which tells if that
column was considered a primary key at the moment of the logging.
Normally there's no indexes, but when I have to make some audits I do
the following:
1) Dump the audits.
2) Restore somewhere else.
3) Generate some indexes on: timestamp, schema|table, field|is_pk and
id (I think, I've got the procedure annotated too, but not here hehe).
This indexing is a pain sometimes but even adding it to the time it
takes to run one query it is really cheap. Making the indexes gets far
more necessary if you run more than one query (which is probably the
case).
I had considered the solution you're posting, but it would get a
_real_ pain to run a query with 'unnest's and 'array_agg's. Also, note
that some of these may not be available in versions of PostgreSQL
prior to 8.4 (I think), so if you're planning to track the tupple you
won't be able to do it in clear (maybe using temp tables).

But! all those arguments above get beat by only one you asserted: that
WORM thing. You are defintly right about that. Logging in the
majority of the cases should be meaningful, light to run,
compact/compressed, and rotated so that it doesn't take up all your
space with time.

Having said that, I'm going to take your advice for the next version,
which I hope that also checks some TODO's in the list. When I get home
I'll send the current code attached and when I get some fresh air at
work I'll make the changes and post the new version.

Any other ideas for the new version? (get some previews in the TODO
list at the top of the perl trigger function in the attachment of the
next mail).

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

-- 
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] [Solved] Generic logging system for pre-hstore using plperl triggers

2011-09-27 Thread Diego Augusto Molina
/* Created by Diego Augusto Molina in 2011 for Tucuman 
Government,
Argentina. */

/*
-- Execute the following accordingly to your needs.
  CREATE TRUSTED PROCEDURAL LANGUAGE 'plpgsql';
  CREATE TRUSTED PROCEDURAL LANGUAGE 'plperl';
*/

CREATE ROLE auditor NOSUPERUSER NOINHERIT NOCREATEDB NOCREATEROLE;
CREATE ROLE audit LOGIN ENCRYPTED PASSWORD 'test.1234' NOSUPERUSER
NOINHERIT NOCREATEDB NOCREATEROLE;
CREATE SCHEMA audit AUTHORIZATION audit;
ALTER ROLE auditor SET search_path=audit;
ALTER ROLE audit SET search_path=audit;
SET search_path=audit;
SET SESSION AUTHORIZATION audit;

CREATE SEQUENCE seq_audit
  INCREMENT 1
  MINVALUE -9223372036854775808
  MAXVALUE 9223372036854775807
  START 0
  CACHE 1
  CYCLE;
ALTER TABLE seq_audit OWNER TO audit;

CREATE SEQUENCE seq_elems
  INCREMENT 1
  MINVALUE -32768
  MAXVALUE 32767
  START 0
  CACHE 1
  CYCLE;
ALTER TABLE seq_elems OWNER TO audit;


CREATE TABLE field
(
  id smallint NOT NULL DEFAULT nextval('seq_elems'::regclass),
  value name NOT NULL,
  CONSTRAINT field_pk PRIMARY KEY (id)
  WITH (FILLFACTOR=100),
  CONSTRAINT field_uq_value UNIQUE (value)
  WITH (FILLFACTOR=100)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE field OWNER TO audit;
GRANT ALL ON TABLE field TO audit;
GRANT SELECT ON TABLE field TO auditor;

CREATE TABLE client_inet
(
  id smallint NOT NULL DEFAULT nextval('seq_elems'::regclass),
  value inet NOT NULL DEFAULT inet_client_addr(),
  CONSTRAINT dir_inet_pk PRIMARY KEY (id )
  WITH (FILLFACTOR=100),
  CONSTRAINT dir_inet_uq_value UNIQUE (value)
  WITH (FILLFACTOR=95)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE client_inet
  OWNER TO audit;
GRANT ALL ON TABLE client_inet TO audit;
GRANT SELECT ON TABLE client_inet TO auditor;

CREATE TABLE schema
(
  id smallint NOT NULL DEFAULT nextval('seq_elems'::regclass),
  value name NOT NULL,
  CONSTRAINT schema_pk PRIMARY KEY (id )
  WITH (FILLFACTOR=100),
  CONSTRAINT schema_uq_value UNIQUE (value )
  WITH (FILLFACTOR=100)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE schema
  OWNER TO audit;
GRANT ALL ON TABLE schema TO audit;
GRANT SELECT ON TABLE schema TO auditor;

CREATE TABLE table
(
  id smallint NOT NULL DEFAULT nextval('seq_elems'::regclass),
  value name NOT NULL,
  CONSTRAINT table_pk PRIMARY KEY (id )
  WITH (FILLFACTOR=100),
  CONSTRAINT table_uq_value UNIQUE (value )
  WITH (FILLFACTOR=100)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE table
  OWNER TO audit;
GRANT ALL ON TABLE table TO audit;
GRANT SELECT ON TABLE table TO auditor;

CREATE TABLE user
(
  id smallint NOT NULL DEFAULT nextval('seq_elems'::regclass),
  value name NOT NULL DEFAULT current_user(),
  CONSTRAINT user_pk PRIMARY KEY (id )
  WITH (FILLFACTOR=100),
  CONSTRAINT user_uq_value UNIQUE (value )
  WITH (FILLFACTOR=95)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE user
  OWNER TO audit;
GRANT ALL ON TABLE user TO audit;
GRANT SELECT ON TABLE user TO auditor;

CREATE TABLE audit
(
  id bigint,
  type character(1),
  tstmp timestamp with time zone DEFAULT now(),
  schema smallint,
  table smallint,
  user smallint,
  client_inet smallint,
  client_port integer DEFAULT inet_client_port(),
  pid integer DEFAULT pg_backend_pid()
)
WITH (
  OIDS=FALSE
);
ALTER TABLE audit OWNER TO audit;
GRANT ALL ON TABLE audit TO audit;
GRANT SELECT ON TABLE audit TO auditor;

CREATE TABLE audet
(
  id bigint,
  field smallint,
  is_pk boolean,
  before text,
  after text
)
WITH (
  OIDS=FALSE
);
ALTER TABLE audet OWNER TO audit;
GRANT ALL ON TABLE audet TO audit;
GRANT SELECT ON TABLE audet TO auditor;

CREATE OR REPLACE FUNCTION tgf_ins_audet()
  RETURNS trigger AS
$BODY$
begin
  execute E'insert into audet_' || tg_argv[0] || E'
(
  id,
  field,
  is_pk,
  before,
  after
) values
(
  '||coalesce(new.id::text,'NULL')||E',
  '||coalesce(new.field::text,'NULL')||E',
  '||coalesce(new.is_pk::text,'NULL')||E',
  '||coalesce(quote_literal(new.before),'NULL')||E',
  '||coalesce(quote_literal(new.after),'NULL')||E'
)';
  return null;
  end;$BODY$ LANGUAGE plpgsql VOLATILE;
ALTER FUNCTION tgf_ins_audet() SET search_path=auditoria;
ALTER FUNCTION tgf_ins_audet() OWNER TO audit;
GRANT EXECUTE ON FUNCTION tgf_ins_audet() TO audit;

CREATE OR REPLACE FUNCTION tgf_ins_audit()
  RETURNS trigger AS
$BODY$
begin
  execute E'insert into audit_' || tg_argv[0] || E'
(
  id,
  type,
  tstmp,
  schema,
  table,
  user,
  client_inet,
  client_port,
  pid
) values
(
  '||coalesce(new.id::text,'NULL')||E',
  '||coalesce(quote_literal(new.type),'NULL')||E',
  '||coalesce(quote_literal(new.tstmp),'NULL')||E',
  '||coalesce(new.schema::text,'NULL')||E',
  '||coalesce(new.table::text,'NULL')||E',
  '||coalesce(new.user::text,'NULL')||E',
  '||coalesce(new.client_inet::text,'NULL')||E

Re: [GENERAL] [Solved] Generic logging system for pre-hstore using plperl triggers

2011-09-27 Thread Diego Augusto Molina
Sh*#@, the code was wrapped! if you can suggest me an external web to
host the code I can put it there and send the link.

Maybe the wiki
Nevertheless, I can't seem to publish in the wiki. I think I've
followed all the steps but still can't.

Anyway, there aren't many long-long lines, except for those whoch are comments.

Honestly, I don't remember why I used triggers instead of rules in the
audit and audet tables.

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

-- 
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] [Solved] Generic logging system for pre-hstore using plperl triggers

2011-09-27 Thread Diego Augusto Molina
2011/9/27, Diego Augusto Molina diegoaugustomol...@gmail.com:
 Honestly, I don't remember why I used triggers instead of rules in the
 audit and audet tables.

I remember now, that's because in my case, operations over tuples are
done very lightly (one or two in the same sentence at a time). So, for
a case as such, rules end up beeing more expensive than triggers
(right?).

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

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


[GENERAL] [Solved] Generic logging system for pre-hstore using plperl triggers

2011-09-26 Thread Diego Augusto Molina
Hi, I had to implement a logging system for some DBs in work. It's
generic and implemented using plperl. I've seen tons of mails on the
list from newbies asking for something like this using plpgsql, but no
specific solution is pointed for them. I think this may discourage
some of them.
The system is implemented using a separate schema with whatever name
you want, and has some really nice features: relevant tables can be
rotated to facilitate auditing, each logged action refers to the
modified tuple by pk, which you don't even have to (but can) specify
when reating the trigger, and some more. Performance is very
acceptable (test cases and suggestions are welcome), and never had a
problem since the about 8 months it's been working.
In the wiki some points are mentioned, but all is _too_ general and
for a vanilla pg-8.4 you won't have the hstore facility (note that
upgrading is not always a choice).
Will it worth pasting the little code in here or that'll be ignored?

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

-- 
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] Clean way to insert records if they don't exist, update if they do

2011-09-19 Thread Diego Augusto Molina
Hi, first of all, I still haven't tried PG further that 8.4

2011/9/18, Mike Christensen m...@kitchenpc.com:
 CREATE RULE Pages_Upsert AS ON INSERT TO Pages
WHERE EXISTS (SELECT 1 from Pages P where NEW.Url = P.Url)
DO INSTEAD
   UPDATE Pages SET LastCrawled = NOW(), Html = NEW.Html WHERE Url =
 NEW.Url;

 This seems to actually work great.  It probably loses some points on
 the code readability standpoint, as someone looking at my code for
 the first time would have to magically know about this rule, but I
 guess that could be solved with good code commenting and
 documentation.

I was in a situation like yours and did exactly what you are saying.
The insert rule and the documentation (after a week I forgot about the
matter and was surprise by the resolution I had taken when I reviewed
the comment :).

 Are there any other drawbacks to this idea, or maybe a your idea
 sucks, you should do it /this/ way instead comment?  I'm on PG 9.0 if
 that matters.  BTW, add my name to the long list of people who would
 love to see UPSERT and/or MERGE commands in the next version of PG.

I used that code for quiet a long time with no drawbacks; it worked
perfectly fine for me (tested it nice with a heavy load, in production
things were more quiet).
What's more, I find this approach very appropiate from the
programming point of view. Correct me if I'm wrong.

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

-- 
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] Grouping by timestamp, how to return 0 when there's no record

2011-09-19 Thread Diego Augusto Molina
Hi, this may be a start:

  -- This will make our day better :)
with base_query (tstmp) as (
select DATE_TRUNC('hour',timestamp) as tstmp
  FROM record
  WHERE
record.timestamp BETWEEN ( CURRENT_TIMESTAMP + INTERVAL '-7 day') and
(CURRENT_TIMESTAMP) -- this I don't understand
  )
  -- The following will make the same as your query
select count(*) as qt, tstmp as dfilter from base_query
  -- And this adds the zero's
union
select 0 as qt, min(tstmp) + interval generate_series( 0, max(tstmp) -
min(tstmp) ) || ' hours' as dfilter
  from base_query
  where dfilter not in tstmp; -- Only for those who don't!

Don't forget to tell us how you ended up!

-- 
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] How can I merge two tables?

2011-09-01 Thread Diego Augusto Molina
Mmm... maybe if you can dump them as inserts you'll be able to restore
them in one DB only. Important: make the restore connection autocommit
(i.e. don't put the --single-transaction flag). That way individual
INSERTs will fail without affecting the other data if that INSERT
violates the PK. This is slow! specially with large data sets.
Once you've got the data in one DB, you can use some replication
system if you want to have that DB in all your machines. One of that
systems is Slony-I, though I haven't tried it.

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

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


[GENERAL] Dump database roles for full restoration

2011-08-19 Thread Diego Augusto Molina
Short description:
* Need: migration of database, with roles relevant to it.
* From server: pg 8.1; no superuser access.
* To server: pg 8.4; full access.
* Database in question: depends on few roles, mainly group roles used
to set permission; there are other roles (login roles) which are
members of these and are intended for the users of the system.
* Proposed solution: migrate the database and reset users passwords.

Long description:
I've been searching a way to achieve this. Having not found it, I
proposed the following solution:

1) Get the roles which are explicitly part of the database through
ownership or acl.
2) Get the roles which descend into the membership graph (members of
roles in (1) plus the members of these and so on).
3) Dump them all (which includes the statements CREATE ROLE, ALTER
ROLE and GRANT's referred to role membership).

Why not include the upper part of the graph (parent roles)? well,
unless any of these are superusers any other permission is irrelevant
for the purpose of that single database. In fact, that's a TODO which
is not needed for my particular case.
I wrote two functions for this: the first one is a privileged one and
the second is not. I did the second because I can't access to the
passwords of the users in the server I'm migrating and asking the
admins to do this is such a pain. After the restoration I will reset
the application users' passwords and securely transmit them to them.
Additionally, the functions can dump the roles of any number of
databases in the cluster.
In the attachment you'll find two queries which are later combined and
slightly modified to compose the functions. One of the queries is a
WITH RECURSIVE ... query, so the PostgreSQL version should be 8.3 or
above I guess. Given the case that the cluster which I'm migrating
from is 8.1, I had to take a workaround in order for this to work:

1) Dump the needed catalog tables: pg_auth_members, pg_authid for
privileged role OR pg_roles for unprivileged role (which is in fact a
view), pg_database and pg_shdepend.
2) Restore the tables in some user-schema of some database in the 8.4 cluster.
3) Modify the functions to query the specified schema instead of pg_catalog.

I provide this code in the hope that it will be useful to someone, but
I also expect some comments and/or corrections.
NOTICE: the privileged function was already successfully tested in a
production environment between two 8.4 servers.

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html
  -- ES: Consulta que lista los oid de los roles de los cuales depende la base de datos, así como los roles que dependen de éstos primeros.
  -- EN: Query that lists the oids of the roles in which the database deppends on as well as those roles which descend from them.
WITH RECURSIVE deps(rol) AS (
  SELECT DISTINCT roles.oid
FROM
  pg_catalog.pg_database db INNER JOIN
  pg_catalog.pg_shdepend dep ON (db.oid = dep.dbid) INNER JOIN
  pg_catalog.pg_roles roles ON (dep.refobjid = roles.oid)
WHERE
  dep.refclassid = 'pg_catalog.pg_authid'::REGCLASS AND
  ARRAY[db.datname] @ $1
  UNION ALL
  SELECT am.member AS rol
FROM
  pg_catalog.pg_auth_members am INNER JOIN
  deps ON (am.roleid = deps.rol)
)
SELECT * FROM deps

  -- ES: La siguiente consulta genera el dump de los roles. La columna 'orden' establece el orden en que deben ejecutarse las sentencias.
  -- EN: This query generates the dump of the roles. The column 'orden' sets the order in which the sentencies are to be executed.
SELECT 1::SMALLINT AS orden, 'CREATE ROLE ' || rolname || ' '
CASE WHEN NOT rolsuper  THEN 'NO' ELSE '' END || 'SUPERUSER ' ||-- 'NOSUPERUSER ' ||
CASE WHEN NOT rolinheritTHEN 'NO' ELSE '' END || 'INHERIT ' ||
CASE WHEN NOT rolcreaterole THEN 'NO' ELSE '' END || 'CREATEROLE ' ||   -- 'NOCREATEROLE ' ||
CASE WHEN NOT rolcreatedb   THEN 'NO' ELSE '' END || 'CREATEDB ' || -- 'NOCREATEDB ' ||
CASE WHEN NOT rolcanlogin   THEN 'NO' ELSE '' END || 'LOGIN ' ||
'CONNECTION LIMIT ' || rolconnlimit ||
CASE WHEN rolvaliduntil IS NULL THEN '' ELSE E' VALID UNTIL \'' ||  rolvaliduntil::text || E'\'' END ||
';' AS sentencia
  FROM pg_catalog.pg_roles
  --WHERE ARRAY[oid] @ $1
  --WHERE oid IN (LISTA_OID_ROLES)
UNION
SELECT 2::SMALLINT AS orden, 'ALTER ROLE ' || rolname || ' SET ' || array_to_string(
rolconfig, ';ALTER ROLE ' || rolname || ' SET '
) || ';' AS sentencia
  FROM pg_catalog.pg_roles
  WHERE rolconfig IS NOT NULL
  --AND ARRAY[oid] @ $1
  --AND oid IN (LISTA_OID_ROLES)
UNION
SELECT 2::SMALLINT AS orden, 'GRANT ' || rol.rolname || ' TO ' || member.rolname || '' ||
CASE WHEN am.admin_option THEN 'WITH ADMIN OPTION' ELSE '' END ||
';' AS sentencia
  FROM

Re: [GENERAL] is max connections in a database table somewhere

2011-08-11 Thread Diego Augusto Molina
2011/8/10, Greg Smith g...@2ndquadrant.com:
 On 08/10/2011 02:46 PM, Geoffrey Myers wrote:
 Is the max connections value in a system table somewhere?

Yes, it is in the table pg_catalog.pg_database. The column is named
datconnlimit and is of type int4. See this:
http://www.postgresql.org/docs/9.0/interactive/catalog-pg-database.html.

But this would be the appropiate way of getting the value:
 SELECT CAST(current_setting('max_connections') AS integer);

You would rather use that form instead of messing up with the catalogs.
-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

-- 
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] Indicating DEFAULT values in INSERT statement

2011-08-09 Thread Diego Augusto Molina
  Hi, when posting SQL it may be a good practice to post your PG
version so that answers may be more accurate and better fit your
needs. In this case, I don't think you'll be able to do what you are
trying to, because as of my understanding the DEFAULT is not part of
an expression but a keyword itself which is to be written *instead* of
an expression. I get your point and seems pretty fair to me, but if
I'm right you don't have access to the default value of the column
from within an expression.
  Assuming you're using the latest stable version of PostgreSQL (9.0
as of today), you can check the following page for an online reading
reference of the INSERT statement:
http://www.postgresql.org/docs/9.0/interactive/sql-insert.html
  If you look carefully, you'll see that for the value of a column you
may write: the DEFAULT keyword [exclusive or] an expression (which
includes specific values).
  The  [exclusive or] is deduced because of the pipe (`|') between the
two choices which are embraced by curly braces.
  So, if you were able to use the DEFAULT keyword inside an
expression, instead of having the { expression | DEFAULT } syntax
you would have the expression syntax, which would include the case
of having just DEFAULT as an expression. It's just a matter of
understanding the syntax.

  Cheers!

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

-- 
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] Indicating DEFAULT values in INSERT statement

2011-08-09 Thread Diego Augusto Molina
This is a bit hacky, but it may work (I haven't tried it yet). If it
works let us know and if it doesn't then maybe we can debug it and get
something useful, or move on to another solution.

code
 INSERT INTO public.test
(
userid, object_id, user_notes, object_status, created_ts
)
VALUES
(
p_userid, p_obj_id, p_user_notes, p_obj_status,
Case When p_created_ts Is Not Null Then p_created_ts Else
( -- You may want to be sure the field has a default value.
SELECT d.adsrc -- or should it be d.adbin?
FROM
pg_catalog.pg_attribute a INNER JOIN
pg_catalog.pg_attrdef d ON (a.attnum = d.adnum)
WHERE
a.attname = 'created_ts' AND
a.attrelid = 'public.test'::REGCLASS AND
d.adrelid = 'public.test'::REGCLASS
) End
);
/code

Well (thinking it thoroughly) it won't work at all as is. It will just
put the source code of the default expression but you would need to
*interpret* it first.
Looked for a way to do this (without `EXECUTE') but couldn't find it. Sorry.

-- 
Diego Augusto Molina
diegoaugustomol...@gmail.com

ES: Por favor, evite adjuntar documentos de Microsoft Office. Serán
desestimados.
EN: Please, avoid attaching Microsoft Office documents. They shall be discarded.
LINK: http://www.gnu.org/philosophy/no-word-attachments.html

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