Обсуждение: Truncate if exists

Поиск
Список
Период
Сортировка

Truncate if exists

От
Sébastien Lardière
Дата:
Hi,

With the help of Cédric, here's a patch changing the TRUNCATE TABLE
command, adding the IF EXISTS option to allow the presence in the list
of tables of a missing or invisible table.

This meets the needs of scripts that should be run in different stages,
and do not always have the same visibility on the tables, as well as
DROP TABLE. Rather than rollback the entire TRUNCATE or transaction, we
prefer to ignore the absence of the table.

It is a small patch which changes very little code, but that could be
quite useful.

Regards,

--
Sébastien Lardière
PostgreSQL DBA Team Manager
Hi-Media

Вложения

Re: Truncate if exists

От
Simon Riggs
Дата:
On 9 October 2012 09:33, Sébastien Lardière <slardiere@hi-media.com> wrote:

> With the help of Cédric, here's a patch changing the TRUNCATE TABLE
> command, adding the IF EXISTS option to allow the presence in the list
> of tables of a missing or invisible table.
>
> This meets the needs of scripts that should be run in different stages,
> and do not always have the same visibility on the tables, as well as
> DROP TABLE. Rather than rollback the entire TRUNCATE or transaction, we
> prefer to ignore the absence of the table.
>
> It is a small patch which changes very little code, but that could be
> quite useful.

Agreed.

Patch looks fine, but please observe the coding standards wrt nested brackets.

Will apply in 48 hours barring objections.

Anyone want to check for any other missing IF EXISTS capability in other DDL?

-- Simon Riggs                   http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training & Services



Re: Truncate if exists

От
Sébastien Lardière
Дата:
On 10/09/2012 11:09 AM, Simon Riggs wrote:
> On 9 October 2012 09:33, Sébastien Lardière <slardiere@hi-media.com> wrote:
>
>> With the help of Cédric, here's a patch changing the TRUNCATE TABLE
>> command, adding the IF EXISTS option to allow the presence in the list
>> of tables of a missing or invisible table.
>>
>> This meets the needs of scripts that should be run in different stages,
>> and do not always have the same visibility on the tables, as well as
>> DROP TABLE. Rather than rollback the entire TRUNCATE or transaction, we
>> prefer to ignore the absence of the table.
>>
>> It is a small patch which changes very little code, but that could be
>> quite useful.
> Agreed.
>
> Patch looks fine, but please observe the coding standards wrt nested brackets.
>
> Will apply in 48 hours barring objections.
>
> Anyone want to check for any other missing IF EXISTS capability in other DDL?
>

Indeed, brackets was not correct, it's better now (I think), and correct
some comments.

Thanks,

--
Sébastien Lardière
PostgreSQL DBA Team Manager
Hi-Media


Вложения

Re: Truncate if exists

От
Vik Reykja
Дата:
<div class="gmail_quote">On Tue, Oct 9, 2012 at 11:09 AM, Simon Riggs <span dir="ltr"><<a
href="mailto:simon@2ndquadrant.com"target="_blank">simon@2ndquadrant.com</a>></span> wrote:<br /><blockquote
class="gmail_quote"style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> Anyone want to check for any
othermissing IF EXISTS capability in other DDL? <br /></blockquote></div><br />Yes, DEALLOCATE.<br /> 

Re: Truncate if exists

От
Vik Reykja
Дата:
On Tue, Oct 9, 2012 at 11:51 AM, Vik Reykja <vikreykja@gmail.com> wrote:
On Tue, Oct 9, 2012 at 11:09 AM, Simon Riggs <simon@2ndquadrant.com> wrote:
Anyone want to check for any other missing IF EXISTS capability in other DDL?

Yes, DEALLOCATE.

Patch attached.
Вложения

Re: Truncate if exists

От
Tom Lane
Дата:
Simon Riggs <simon@2ndQuadrant.com> writes:
> On 9 October 2012 09:33, S�bastien Lardi�re <slardiere@hi-media.com> wrote:
>> With the help of C�dric, here's a patch changing the TRUNCATE TABLE
>> command, adding the IF EXISTS option to allow the presence in the list
>> of tables of a missing or invisible table.

> Will apply in 48 hours barring objections.

I object: this doesn't deserve to be fast-tracked like that with no
thought about whether the semantics are actually useful or sensible.

For starters, the use-case hasn't been explained to my satisfaction.
In what situation is it actually helpful to TRUNCATE a table that's
not there yet?  Aren't you going to have to do a CREATE IF NOT EXISTS
to keep from failing later in the script?  If so, why not just do that
first?

Second, to my mind the point of a multi-table TRUNCATE is to ensure that
all the referenced tables get reset to empty *together*.  With something
like this, you'd have no such guarantee.  Consider a timeline like this:
Session 1            Session 2
TRUNCATE IF EXISTS a, b, c;... finds c doesn't exist ...... working on a and b ...                CREATE TABLE c ( ...
);               INSERT INTO c ...;... commits ...
 

Now we have a, b, and c, but c isn't empty, violating the expectations
of session 1.  So even if there's a use-case for IF EXISTS on a single
table, I think it's very very dubious to allow it in multi-table
commands.
        regards, tom lane



Re: Truncate if exists

От
Tom Lane
Дата:
Sébastien Lardière <slardiere@hi-media.com> writes:
> Indeed, brackets was not correct, it's better now (I think), and correct
> some comments.

Still wrong ... at the very least you missed copyfuncs/equalfuncs.
In general, when adding a field to a struct, it's good practice to
grep for all uses of that struct.
        regards, tom lane



Re: Truncate if exists

От
Sébastien Lardière
Дата:
On 10/09/2012 04:06 PM, Tom Lane wrote:
> Simon Riggs <simon@2ndQuadrant.com> writes:
>> On 9 October 2012 09:33, Sébastien Lardière <slardiere@hi-media.com> wrote:
>>> With the help of Cédric, here's a patch changing the TRUNCATE TABLE
>>> command, adding the IF EXISTS option to allow the presence in the list
>>> of tables of a missing or invisible table.
>> Will apply in 48 hours barring objections.
> I object: this doesn't deserve to be fast-tracked like that with no
> thought about whether the semantics are actually useful or sensible.
>
> For starters, the use-case hasn't been explained to my satisfaction.
> In what situation is it actually helpful to TRUNCATE a table that's
> not there yet?  Aren't you going to have to do a CREATE IF NOT EXISTS
> to keep from failing later in the script?  If so, why not just do that
> first?

it could be useful to not rollback transactions :
- if a table is not yet or no more visible, because of search_path
modification- if a table was dropped, for any reason

> Second, to my mind the point of a multi-table TRUNCATE is to ensure that
> all the referenced tables get reset to empty *together*.  With something
> like this, you'd have no such guarantee.  Consider a timeline like this:
>
>     Session 1            Session 2
>
>     TRUNCATE IF EXISTS a, b, c;
>     ... finds c doesn't exist ...
>     ... working on a and b ...
>                     CREATE TABLE c ( ... );
>                     INSERT INTO c ...;
>     ... commits ...
>
> Now we have a, b, and c, but c isn't empty, violating the expectations
> of session 1.  So even if there's a use-case for IF EXISTS on a single
> table, I think it's very very dubious to allow it in multi-table
> commands.

Well, I have to say that if I'm the guy who create the table c, I don't
want to see the table empty after my insert, don't you think ?

I understand your point about the multi-table TRUNCATE, but my point is
to commit transaction, whatever the visibility or presence of a given
table.
In a perfect world, we could review all our processes, and change them
to guarantee commit, then we don't need IF EXISTS ; But i'm not in this
case, and maybe some others neither, are you ?

--
Sébastien Lardière
PostgreSQL DBA Team Manager
Hi-Media




Re: Truncate if exists

От
Robert Haas
Дата:
On Tue, Oct 9, 2012 at 12:28 PM, Sébastien Lardière
<slardiere@hi-media.com> wrote:
>> For starters, the use-case hasn't been explained to my satisfaction.
>> In what situation is it actually helpful to TRUNCATE a table that's
>> not there yet?  Aren't you going to have to do a CREATE IF NOT EXISTS
>> to keep from failing later in the script?  If so, why not just do that
>> first?
>
> it could be useful to not rollback transactions :
>
>  - if a table is not yet or no more visible, because of search_path
> modification

I don't think I understand the case you are describing here.

>  - if a table was dropped, for any reason

But in this case surely you could use DROP IF EXISTS.

I've been a big proponent of adding "IF EXISTS" support to CREATE
TABLE and ALTER TABLE but I'm having a hard time getting excited about
this one.  I can't imagine that many people would use it, and those
who do can implement it in about 10 lines of PL/pgsql.  The existence
of DO blocks and the fact that PL/pgsql is now installed by default
have made it much more convenient to solve these kinds of problems
using those tools rather than needing dedicated syntax.  That does not
mean that the most frequently used cases shouldn't have dedicated
syntax anyway, for convenience, but I'm doubtful that this falls into
that category.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Truncate if exists

От
Simon Riggs
Дата:
On 9 October 2012 15:06, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Simon Riggs <simon@2ndQuadrant.com> writes:
>> On 9 October 2012 09:33, Sébastien Lardière <slardiere@hi-media.com> wrote:
>>> With the help of Cédric, here's a patch changing the TRUNCATE TABLE
>>> command, adding the IF EXISTS option to allow the presence in the list
>>> of tables of a missing or invisible table.
>
>> Will apply in 48 hours barring objections.
>
> I object: this doesn't deserve to be fast-tracked like that with no
> thought about whether the semantics are actually useful or sensible.

I wasn't fast tracking it, just looking to apply small uncontentious
patches quickly.

Your objection is enough to stall until next commitfest for further discussion.

-- Simon Riggs                   http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training & Services



Re: Truncate if exists

От
Josh Berkus
Дата:
Robert,

> I've been a big proponent of adding "IF EXISTS" support to CREATE
> TABLE and ALTER TABLE but I'm having a hard time getting excited about
> this one.  I can't imagine that many people would use it, and those
> who do can implement it in about 10 lines of PL/pgsql.  The existence
> of DO blocks and the fact that PL/pgsql is now installed by default
> have made it much more convenient to solve these kinds of problems
> using those tools rather than needing dedicated syntax.  That does not
> mean that the most frequently used cases shouldn't have dedicated
> syntax anyway, for convenience, but I'm doubtful that this falls into
> that category.

On the other hand, it's useful to consistently have "IF EXISTS" syntax
for the majority of utility commands.  It's confusing to users that they
can do "DROP TABLE IF EXISTS" but not "TRUNCATE IF EXISTS", even if the
latter is less useful than the former.  So that's one reason to support
this.

The second is for making deployment scripts idempotent.  For example,
say you have script A which creates table "josh", and script B which
needs table "josh" to be empty, if present.  Since the two scripts are
tied to different database features, and you don't know which one will
be deployed first, it's useful to have TRUNCATE IF EXISTS.  Yes, you can
solve that problem with DO, but why make users go to the extra effort?

Is it *as* useful as other IF EXISTS?  No.  Is it replaceable with a DO
$$ statement?  Yes.  Is that a reason to block a fairly trivial patch
which makes things 0.1% easier for users?  No.

Not if the patch itself is broken, that's another story.

-- 
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com



Re: Truncate if exists

От
Peter Eisentraut
Дата:
On 10/9/12 5:09 AM, Simon Riggs wrote:
> Anyone want to check for any other missing IF EXISTS capability in other DDL?

TRUNCATE is not really DDL.  If we allow TRUNCATE IF EXISTS, what is
stopping someone from requesting DELETE IF EXISTS or INSERT IF EXISTS next?




Re: Truncate if exists

От
Gavin Flower
Дата:
On 10/10/12 09:35, Peter Eisentraut wrote:
> On 10/9/12 5:09 AM, Simon Riggs wrote:
>> Anyone want to check for any other missing IF EXISTS capability in other DDL?
> TRUNCATE is not really DDL.  If we allow TRUNCATE IF EXISTS, what is
> stopping someone from requesting DELETE IF EXISTS or INSERT IF EXISTS next?
>
>
>
INSERT IF NOT EXISTS  ?




Re: Truncate if exists

От
Simon Riggs
Дата:
On 9 October 2012 21:35, Peter Eisentraut <peter_e@gmx.net> wrote:
> On 10/9/12 5:09 AM, Simon Riggs wrote:
>> Anyone want to check for any other missing IF EXISTS capability in other DDL?
>
> TRUNCATE is not really DDL.  If we allow TRUNCATE IF EXISTS, what is
> stopping someone from requesting DELETE IF EXISTS or INSERT IF EXISTS next?

I'm not involved in the planning or justification for this patch, and
have no opinion.

I discussed applying it because it was an uncontentious patch. It
clearly is not....

-- Simon Riggs                   http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training & Services



Re: Truncate if exists

От
Daniel Farina
Дата:
On Tue, Oct 9, 2012 at 2:04 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
> On 9 October 2012 21:35, Peter Eisentraut <peter_e@gmx.net> wrote:
>> On 10/9/12 5:09 AM, Simon Riggs wrote:
>>> Anyone want to check for any other missing IF EXISTS capability in other DDL?
>>
>> TRUNCATE is not really DDL.  If we allow TRUNCATE IF EXISTS, what is
>> stopping someone from requesting DELETE IF EXISTS or INSERT IF EXISTS next?
>
> I'm not involved in the planning or justification for this patch, and
> have no opinion.
>
> I discussed applying it because it was an uncontentious patch. It
> clearly is not....

I also read Simon's approach as not a push for inclusion, but
defaulting to commit for smaller patches that basically look
mechanically legitimate with no objections to streamline
communication.  Since pgsql-hackers has a good record objecting to
patches that require objection in a timely manner, I think that's
reasonable.  The cost of revert would not be that high, either.

Clearly those conditions were not met, but I don't think it's
justified to jump on Simon for this approach on a patch like this.

-- 
fdr



Re: Truncate if exists

От
Robert Haas
Дата:
On Tue, Oct 9, 2012 at 4:18 PM, Josh Berkus <josh@agliodbs.com> wrote:
> The second is for making deployment scripts idempotent.  For example,
> say you have script A which creates table "josh", and script B which
> needs table "josh" to be empty, if present.  Since the two scripts are
> tied to different database features, and you don't know which one will
> be deployed first, it's useful to have TRUNCATE IF EXISTS.  Yes, you can
> solve that problem with DO, but why make users go to the extra effort?

Hmm.  That's an interesting point.  I think we're currently in
somewhat of a limbo zone about where we ought to have IF EXISTS and IF
NOT EXISTS options, and where we should not.  Really, I'd like to
figure out what policy we want to have, and then go make everything
work that way.  I don't exactly know what the policy should be, but if
we don't have one then we're going to have to argue about every patch
individually, which is already getting to be more than tedious.  At
the one extreme, you have Tom, who probably would not have added any
of these given his druthers; at the other extreme, there are probably
some people who would say we ought to have this for every command in
the book, right down to INSERT IF EXISTS (and, hey, why not INSERT OR
CREATE for good measure?).  I'm not sure what the right thing to do
is... but we should probably come up with some consensus position we
can all live with, and then go make this uniform[1].

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

[1] And yes, I will volunteer to do some or all of the required
implementation work, if that's helpful.  Or else somebody else can do
it.  That's good, too.



Re: Truncate if exists

От
Tom Lane
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
> On Tue, Oct 9, 2012 at 4:18 PM, Josh Berkus <josh@agliodbs.com> wrote:
>> The second is for making deployment scripts idempotent.  For example,
>> say you have script A which creates table "josh", and script B which
>> needs table "josh" to be empty, if present.  Since the two scripts are
>> tied to different database features, and you don't know which one will
>> be deployed first, it's useful to have TRUNCATE IF EXISTS.  Yes, you can
>> solve that problem with DO, but why make users go to the extra effort?

> Hmm.  That's an interesting point.

I'm still not buying this as a realistic use-case.  The only way
TRUNCATE IF EXISTS helps script B is if B isn't going to do *anything*
with table "josh" except truncate it.  I will grant that there might be
a case or two out there where that's just the ticket, but I think
they're probably few and far between; not enough to justify bespoke
syntax.  As Robert already pointed out, a quick DO handles the problem
well enough if you only need it once in a blue moon.

I also note the lack of response to my point about IF EXISTS being
squishy to the point of outright dangerous in the multi-table case.
I might hold still and not complain if we didn't have the multi-table
syntax.  But with it, this looks a lot less like a well-considered
feature and a lot more like something that was implemented because
it could be done in two lines, as long as you aren't too picky about
what the semantics are.  TBH, I think most all of our ventures in
IF(NOT)EXISTS have suffered from that disease, but that doesn't mean
I'm not going to complain when we adopt the same cowboy approach to
command semantics for ever thinner justifications.
        regards, tom lane



Re: Truncate if exists

От
Noah Misch
Дата:
On Tue, Oct 09, 2012 at 09:10:13PM -0400, Robert Haas wrote:
> On Tue, Oct 9, 2012 at 4:18 PM, Josh Berkus <josh@agliodbs.com> wrote:
> > The second is for making deployment scripts idempotent.  For example,
> > say you have script A which creates table "josh", and script B which
> > needs table "josh" to be empty, if present.  Since the two scripts are
> > tied to different database features, and you don't know which one will
> > be deployed first, it's useful to have TRUNCATE IF EXISTS.  Yes, you can
> > solve that problem with DO, but why make users go to the extra effort?
> 
> Hmm.  That's an interesting point.  I think we're currently in
> somewhat of a limbo zone about where we ought to have IF EXISTS and IF
> NOT EXISTS options, and where we should not.  Really, I'd like to
> figure out what policy we want to have, and then go make everything
> work that way.  I don't exactly know what the policy should be, but if
> we don't have one then we're going to have to argue about every patch
> individually, which is already getting to be more than tedious.

Agreed.  I, too, struggle to envision the concrete use case for TRUNCATE IF
EXISTS, but adding IF [NOT] EXISTS to some marginal candidate commands would
not hurt as part of a broad plan.

>  At
> the one extreme, you have Tom, who probably would not have added any
> of these given his druthers; at the other extreme, there are probably
> some people who would say we ought to have this for every command in
> the book, right down to INSERT IF EXISTS (and, hey, why not INSERT OR
> CREATE for good measure?).  I'm not sure what the right thing to do
> is... but we should probably come up with some consensus position we
> can all live with, and then go make this uniform[1].

For what it's worth, I'm in that camp of disfavoring all IF [NOT] EXISTS
syntax.  I worked on a project that fed idempotent SQL scripts through psql to
migrate schema changes; I used such syntax then and appreciated the keystrokes
saved.  But the syntax is a bandage for raw psql input remaining a hostile
environment for implementing the full range of schema changes.  Switch to
submitting your SQL from a richer programming environment, and these additions
to core syntax cease to add much.

nm



Re: Truncate if exists

От
Simon Riggs
Дата:
On 10 October 2012 02:10, Robert Haas <robertmhaas@gmail.com> wrote:
> On Tue, Oct 9, 2012 at 4:18 PM, Josh Berkus <josh@agliodbs.com> wrote:
>> The second is for making deployment scripts idempotent.  For example,
>> say you have script A which creates table "josh", and script B which
>> needs table "josh" to be empty, if present.  Since the two scripts are
>> tied to different database features, and you don't know which one will
>> be deployed first, it's useful to have TRUNCATE IF EXISTS.  Yes, you can
>> solve that problem with DO, but why make users go to the extra effort?
>
> Hmm.  That's an interesting point.  I think we're currently in
> somewhat of a limbo zone about where we ought to have IF EXISTS and IF
> NOT EXISTS options, and where we should not.  Really, I'd like to
> figure out what policy we want to have, and then go make everything
> work that way.  I don't exactly know what the policy should be, but if
> we don't have one then we're going to have to argue about every patch
> individually, which is already getting to be more than tedious.  At
> the one extreme, you have Tom, who probably would not have added any
> of these given his druthers; at the other extreme, there are probably
> some people who would say we ought to have this for every command in
> the book, right down to INSERT IF EXISTS (and, hey, why not INSERT OR
> CREATE for good measure?).  I'm not sure what the right thing to do
> is... but we should probably come up with some consensus position we
> can all live with, and then go make this uniform[1].

Damn it, now I have an opinion.

I would say two things:

1) Consistency for DDL syntax is important. Sometimes humans still
write SQL and often, ORMs generate SQL. Asking poeple to guess what
our syntax is from release to release is a good way to have people not
bother to support us properly. As Peter says, Truncate is not DDL (and
argument I have used), but it is often used alongside DDL and does
have many of the same characteristics. INSERT IF EXISTS is simply an
argument ad absurdum, not a requirement that needs to be addressed.

2) Clearly, rollout scripts benefit from not throwing errors.
Personally I would prefer setting SET ddl_abort_on_missing_object =
false; at the top of a script than having to go through every SQL
statement and add extra syntax. That might even help people more than
littering SQL with extra clauses.

-- Simon Riggs                   http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training & Services



Re: Truncate if exists

От
Christopher Browne
Дата:
On Wed, Oct 10, 2012 at 3:32 AM, Simon Riggs <simon@2ndquadrant.com> wrote:
> On 10 October 2012 02:10, Robert Haas <robertmhaas@gmail.com> wrote:
>> On Tue, Oct 9, 2012 at 4:18 PM, Josh Berkus <josh@agliodbs.com> wrote:
>>> The second is for making deployment scripts idempotent.  For example,
>>> say you have script A which creates table "josh", and script B which
>>> needs table "josh" to be empty, if present.  Since the two scripts are
>>> tied to different database features, and you don't know which one will
>>> be deployed first, it's useful to have TRUNCATE IF EXISTS.  Yes, you can
>>> solve that problem with DO, but why make users go to the extra effort?
>>
>> Hmm.  That's an interesting point.  I think we're currently in
>> somewhat of a limbo zone about where we ought to have IF EXISTS and IF
>> NOT EXISTS options, and where we should not.  Really, I'd like to
>> figure out what policy we want to have, and then go make everything
>> work that way.  I don't exactly know what the policy should be, but if
>> we don't have one then we're going to have to argue about every patch
>> individually, which is already getting to be more than tedious.  At
>> the one extreme, you have Tom, who probably would not have added any
>> of these given his druthers; at the other extreme, there are probably
>> some people who would say we ought to have this for every command in
>> the book, right down to INSERT IF EXISTS (and, hey, why not INSERT OR
>> CREATE for good measure?).  I'm not sure what the right thing to do
>> is... but we should probably come up with some consensus position we
>> can all live with, and then go make this uniform[1].
>
> Damn it, now I have an opinion.
>
> I would say two things:
>
> 1) Consistency for DDL syntax is important. Sometimes humans still
> write SQL and often, ORMs generate SQL. Asking poeple to guess what
> our syntax is from release to release is a good way to have people not
> bother to support us properly. As Peter says, Truncate is not DDL (and
> argument I have used), but it is often used alongside DDL and does
> have many of the same characteristics. INSERT IF EXISTS is simply an
> argument ad absurdum, not a requirement that needs to be addressed.

I think I agree.  We should not go down the "well, we haven't got
UPSERT yet, and that's why we shouldn't do this one" road.

> Clearly, rollout scripts benefit from not throwing errors.
> Personally I would prefer setting SET ddl_abort_on_missing_object =
> false; at the top of a script than having to go through every SQL
> statement and add extra syntax. That might even help people more than
> littering SQL with extra clauses.

Here, I'm rather less comfortable.

I could easily take the opposite tack, that rollout scripts benefit
from yes, indeed, throwing errors, so that inconsistencies get
rectified.  I don't want to take that argument *too* far, mind you.

Doing things that "avoid throwing errors" isn't purely a good thing.
If a DDL script is doing genuinely different things when running in
different environments, it's difficult to be confident that the result
is correct in all cases.  Hiding errors might lead to ignoring
important differences.

Given two further bits of "processing model," I might be made more
comfortable...

1.  A direction we're trying to go is to have good comparison tools to
see where schemas differ between environments.  (I need to poke at
getting a tool I call "pgcmp" released publicly.)  If you have the
capability to compare the starting schema against what you imagined it
was supposed to be, as well as to compare the post-rollout schema
against what it was supposed to become, then that keeps things
relatively under control.  If you can quickly determine divergence
from expected schema, then you can more easily keep on track.

2.  [More on the SQL syntax/clauses front]  In order to NOT litter the
SQL with extra clauses, I expect that there needs to be something of a
model of How You SHOULD Update Your Schema, in effect, some idiomatic
'best practice' that tends to cut risk and diminish the need for IF
EXISTS/IF NOT EXISTS.  I'd be interested to see an outline of that
model.
-- 
When confronted by a difficult problem, solve it by reducing it to the
question, "How would the Lone Ranger handle this?"



Re: Truncate if exists

От
Josh Berkus
Дата:
On 10/9/12 1:35 PM, Peter Eisentraut wrote:
> On 10/9/12 5:09 AM, Simon Riggs wrote:
>> Anyone want to check for any other missing IF EXISTS capability in other DDL?
> 
> TRUNCATE is not really DDL.  If we allow TRUNCATE IF EXISTS, what is
> stopping someone from requesting DELETE IF EXISTS or INSERT IF EXISTS next?

That's a very good point.  I tend to think of all utility commands as
DDL, which of course they're not.


-- 
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com



Re: Truncate if exists

От
Sébastien Lardière
Дата:
On 10/09/2012 10:04 PM, Robert Haas wrote:

>>  - if a table is not yet or no more visible, because of search_path
>> modification
>
> I don't think I understand the case you are describing here.

Here's a sample :


begin;
set search_path = foo, public;
create table c ( … ) ;
commit;

begin;
set search_path = bar, public;
create table d ( … );
truncate if exists c;
commit;

>
>>  - if a table was dropped, for any reason
>
> But in this case surely you could use DROP IF EXISTS.

Well, TRUNCATE and DROP TABLE are not the same, I don't see your point ?

>
> I've been a big proponent of adding "IF EXISTS" support to CREATE
> TABLE and ALTER TABLE but I'm having a hard time getting excited about
> this one.  I can't imagine that many people would use it, and those
> who do can implement it in about 10 lines of PL/pgsql.  The existence
> of DO blocks and the fact that PL/pgsql is now installed by default
> have made it much more convenient to solve these kinds of problems
> using those tools rather than needing dedicated syntax.  That does not
> mean that the most frequently used cases shouldn't have dedicated
> syntax anyway, for convenience, but I'm doubtful that this falls into
> that category.
>

I don't think we can ask people to do DO blocks for TRUNCATE, when they
simply use IF EXISTS with DROP TABLE.

Even if TRUNCATE is not a DDL, it's often use as is

--
Sébastien Lardière
PostgreSQL DBA Team Manager
Hi-Media



Re: Truncate if exists

От
Sébastien Lardière
Дата:
On 10/09/2012 04:06 PM, Tom Lane wrote:
> Second, to my mind the point of a multi-table TRUNCATE is to ensure that
> all the referenced tables get reset to empty *together*.  With something
> like this, you'd have no such guarantee.  Consider a timeline like this:
>
>     Session 1            Session 2
>
>     TRUNCATE IF EXISTS a, b, c;
>     ... finds c doesn't exist ...
>     ... working on a and b ...
>                     CREATE TABLE c ( ... );
>                     INSERT INTO c ...;
>     ... commits ...
>
> Now we have a, b, and c, but c isn't empty, violating the expectations
> of session 1.  So even if there's a use-case for IF EXISTS on a single
> table, I think it's very very dubious to allow it in multi-table
> commands.

Hi,

I've to say that I don't understand your timeline :

- If c exist in Session 1, CREATE TABLE in Session 2 can't be done,
neither INSERT
- If c doesn't exists in Session 1, it will be ignored, then, Session 2
work fine.

In any case, TRUNCATE is sent before INSERT, but it can't lock an object
which still not exists.

I understand that people don't want TRUNCATE IF EXISTS, but, in my point
of view, even if TRUNCATE is not a DDL, it's the same use-case as DROP
TABLE IF EXISTS.

Regards,

--
Sébastien Lardière
PostgreSQL DBA Team Manager
Hi-Media



Re: Truncate if exists

От
Cédric Villemain
Дата:
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;
-qt-user-state:0;">>For starters, the use-case hasn't been explained to my satisfaction.<p style=" margin-top:0px;
margin-bottom:0px;margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> In
whatsituation is it actually helpful to TRUNCATE a table that's<p style=" margin-top:0px; margin-bottom:0px;
margin-left:0px;margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> not there yet? Aren't
yougoing to have to do a CREATE IF NOT EXISTS<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px;
margin-right:0px;-qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> to keep from failing later in the script?
Ifso, why not just do that<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;
-qt-block-indent:0;text-indent:0px; -qt-user-state:0;">> first?<p style="-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px;margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> <p style=" margin-top:0px;
margin-bottom:0px;margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">There is a
usecase for the truncate 'mutliple' tables, maybe less clear for a single table.<p style=" margin-top:0px;
margin-bottom:0px;margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Sébastien
willspeak here I suppose.<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px;
margin-right:0px;-qt-block-indent:0; text-indent:0px; "> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px;
margin-right:0px;-qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> Second, to my mind the point of a
multi-tableTRUNCATE is to ensure that<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;
-qt-block-indent:0;text-indent:0px; -qt-user-state:0;">> all the referenced tables get reset to empty *together*.
Withsomething<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;-qt-user-state:0;">> like this, you'd have no such guarantee. Consider a timeline like this:<p
style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;
-qt-user-state:0;">><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;
-qt-block-indent:0;text-indent:0px; -qt-user-state:0;">> Session 1 Session 2<p style=" margin-top:0px;
margin-bottom:0px;margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> <p
style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;
-qt-user-state:0;">>TRUNCATE IF EXISTS a, b, c;<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px;
margin-right:0px;-qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> ... finds c doesn't exist ...<p style="
margin-top:0px;margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;
-qt-user-state:0;">>... working on a and b ...<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px;
margin-right:0px;-qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> CREATE TABLE c ( ... );<p style="
margin-top:0px;margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;
-qt-user-state:0;">>INSERT INTO c ...;<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px;
margin-right:0px;-qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> ... commits ...<p style=" margin-top:0px;
margin-bottom:0px;margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> <p
style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;
-qt-user-state:0;">>Now we have a, b, and c, but c isn't empty, violating the expectations<p style=" margin-top:0px;
margin-bottom:0px;margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> of
session1. So even if there's a use-case for IF EXISTS on a single<p style=" margin-top:0px; margin-bottom:0px;
margin-left:0px;margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">> table, I think it's very
verydubious to allow it in multi-table<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;
-qt-block-indent:0;text-indent:0px; -qt-user-state:0;">> commands.<p style="-qt-paragraph-type:empty;
margin-top:0px;margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> <p style="
margin-top:0px;margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;
-qt-user-state:0;">well,in such case you probably don't want to use IF EXISTS.<p style="-qt-paragraph-type:empty;
margin-top:0px;margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> <p style="
margin-top:0px;margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;
-qt-user-state:0;">--<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;
-qt-block-indent:0;text-indent:0px; -qt-user-state:0;">Cédric Villemain +33 (0)6 20 30 22 52<p style=" margin-top:0px;
margin-bottom:0px;margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;
-qt-user-state:0;">http://2ndQuadrant.fr/<pstyle=" margin-top:0px; margin-bottom:0px; margin-left:0px;
margin-right:0px;-qt-block-indent:0; text-indent:0px; -qt-user-state:0;">PostgreSQL: Support 24x7 - Développement,
Expertiseet Formation 

Re: Truncate if exists

От
Robert Haas
Дата:
On Wed, Oct 10, 2012 at 3:32 AM, Simon Riggs <simon@2ndquadrant.com> wrote:
> 2) Clearly, rollout scripts benefit from not throwing errors.
> Personally I would prefer setting SET ddl_abort_on_missing_object =
> false; at the top of a script than having to go through every SQL
> statement and add extra syntax. That might even help people more than
> littering SQL with extra clauses.

I've been thinking about this a bit more.  It seems to me that the
awkwardness here has a lot to do with the fact that the IF EXISTS is
attached to the command rather than sitting outside it.  We're
basically trying to put the control logic inside the command itself,
whereas probably what we really want is for the control logic to be
able to exist around the command, like this:

IF TABLE foo EXISTS THEN   TRUNCATE TABLE foo;
END IF

But of course that doesn't work.  I think you have to write something like this:

do $$   begin       if (select 1 from pg_class where relname = 'foo' and
pg_table_is_visible(oid)) then           truncate table foo;       end if;   end
$$;

That is a lot more typing and it's not exactly intuitive.  One obvious
thing that would help is a function pg_table_exists(text) that would
return true or false.  But even with that there's a lot of syntactic
sugar in there that is less than ideal: begin/end, dollar-quoting, do.Whatever becomes of this particular patch, I
thinkwe'd make a lot of
 
people really happy if we could find a way to dispense with some of
that stuff in simple cases.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Truncate if exists

От
Simon Riggs
Дата:
On 11 October 2012 19:59, Robert Haas <robertmhaas@gmail.com> wrote:
> On Wed, Oct 10, 2012 at 3:32 AM, Simon Riggs <simon@2ndquadrant.com> wrote:
>> 2) Clearly, rollout scripts benefit from not throwing errors.
>> Personally I would prefer setting SET ddl_abort_on_missing_object =
>> false; at the top of a script than having to go through every SQL
>> statement and add extra syntax. That might even help people more than
>> littering SQL with extra clauses.
>
> I've been thinking about this a bit more.  It seems to me that the
> awkwardness here has a lot to do with the fact that the IF EXISTS is
> attached to the command rather than sitting outside it.  We're
> basically trying to put the control logic inside the command itself,
> whereas probably what we really want is for the control logic to be
> able to exist around the command, like this:
>
> IF TABLE foo EXISTS THEN
>     TRUNCATE TABLE foo;
> END IF
>
> But of course that doesn't work.  I think you have to write something like this:
>
> do $$
>     begin
>         if (select 1 from pg_class where relname = 'foo' and
> pg_table_is_visible(oid)) then
>             truncate table foo;
>         end if;
>     end
> $$;
>
> That is a lot more typing and it's not exactly intuitive.  One obvious
> thing that would help is a function pg_table_exists(text) that would
> return true or false.  But even with that there's a lot of syntactic
> sugar in there that is less than ideal: begin/end, dollar-quoting, do.
>  Whatever becomes of this particular patch, I think we'd make a lot of
> people really happy if we could find a way to dispense with some of
> that stuff in simple cases.

Yeh, definitely.

So we just need a function called pg_if_table_exists(table, SQL) which
wraps a test in a subtransaction.

And you write

SELECT pg_if_table_exists('foo', 'TRUNCATE TABLE foo');

and we can even get rid of all that other DDL crud that's been added....

and we can have pg_if_table_not_exists() also.

-- Simon Riggs                   http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training & Services



Re: Truncate if exists

От
Sébastien Lardière
Дата:
On 10/11/2012 09:22 PM, Simon Riggs wrote:

>>
>> That is a lot more typing and it's not exactly intuitive.  One obvious
>> thing that would help is a function pg_table_exists(text) that would
>> return true or false.  But even with that there's a lot of syntactic
>> sugar in there that is less than ideal: begin/end, dollar-quoting, do.
>>  Whatever becomes of this particular patch, I think we'd make a lot of
>> people really happy if we could find a way to dispense with some of
>> that stuff in simple cases.
>
> Yeh, definitely.
>
> So we just need a function called pg_if_table_exists(table, SQL) which
> wraps a test in a subtransaction.
>
> And you write
>
> SELECT pg_if_table_exists('foo', 'TRUNCATE TABLE foo');
>
> and we can even get rid of all that other DDL crud that's been added....
>
> and we can have pg_if_table_not_exists() also.
>

If we can do something like :

SELECT pg_if_table_exists('bar' , pg_if_table_exists('foo', 'TRUNCATE
TABLE foo, bar, foobar')) ;

or

SELECT pg_if_tables_exists('TRUNCATE TABLE foo, bar, foobar', 'foo',
'bar') ;

I say yes !


--
Sébastien Lardière
PostgreSQL DBA Team Manager
Hi-Media



Re: Truncate if exists

От
Andrew Dunstan
Дата:
On 10/12/2012 12:03 PM, Sébastien Lardière wrote:
>
> If we can do something like :
>
> SELECT pg_if_table_exists('bar' , pg_if_table_exists('foo', 'TRUNCATE
> TABLE foo, bar, foobar')) ;
>
> or
>
> SELECT pg_if_tables_exists('TRUNCATE TABLE foo, bar, foobar', 'foo',
> 'bar') ;
>
> I say yes !
>
>



This strikes me as just highly un-SQL-like.

Someone could fairly easily write it for themselves in Plpgsql or C, but
it doesn't seem to me like something we should be doing.

I tend to agree with Noah's comment upthread:

> But the syntax is a bandage for raw psql input remaining a hostile
> environment for implementing the full range of schema changes.  Switch to
> submitting your SQL from a richer programming environment, and these additions
> to core syntax cease to add much.


I think this goes a fortiori for Heath Robinson-like devices such as this.


cheers

andrew




Re: Truncate if exists

От
Pavel Stehule
Дата:
Hello

2012/10/12 Sébastien Lardière <slardiere@hi-media.com>:
> On 10/11/2012 09:22 PM, Simon Riggs wrote:
>
>>>
>>> That is a lot more typing and it's not exactly intuitive.  One obvious
>>> thing that would help is a function pg_table_exists(text) that would
>>> return true or false.  But even with that there's a lot of syntactic
>>> sugar in there that is less than ideal: begin/end, dollar-quoting, do.
>>>  Whatever becomes of this particular patch, I think we'd make a lot of
>>> people really happy if we could find a way to dispense with some of
>>> that stuff in simple cases.
>>
>> Yeh, definitely.
>>
>> So we just need a function called pg_if_table_exists(table, SQL) which
>> wraps a test in a subtransaction.
>>
>> And you write
>>
>> SELECT pg_if_table_exists('foo', 'TRUNCATE TABLE foo');
>>
>> and we can even get rid of all that other DDL crud that's been added....
>>
>> and we can have pg_if_table_not_exists() also.
>>
>
> If we can do something like :
>
> SELECT pg_if_table_exists('bar' , pg_if_table_exists('foo', 'TRUNCATE
> TABLE foo, bar, foobar')) ;
>
> or
>
> SELECT pg_if_tables_exists('TRUNCATE TABLE foo, bar, foobar', 'foo',
> 'bar') ;
>
> I say yes !

I don't like it in core - it can be used for SQL injection - it is dynamic SQL.

Regards

Pavel

>
>
> --
> Sébastien Lardière
> PostgreSQL DBA Team Manager
> Hi-Media
>
>
> --
> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-hackers



Re: Truncate if exists

От
Dimitri Fontaine
Дата:
Andrew Dunstan <andrew@dunslane.net> writes:
> This strikes me as just highly un-SQL-like.

+1

> I tend to agree with Noah's comment upthread:
>
>> But the syntax is a bandage for raw psql input remaining a hostile
>> environment for implementing the full range of schema changes.  Switch to
>> submitting your SQL from a richer programming environment, and these additions
>> to core syntax cease to add much.

I think the comment is generally true, but fails in the face of the
simplicity of this particular grammar addition. Also, I have the same
problem as Sébastien to understand Tom's usage example.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support



Re: Truncate if exists

От
Stephen Frost
Дата:
* Robert Haas (robertmhaas@gmail.com) wrote:
> INSERT IF EXISTS (and, hey, why not INSERT OR
> CREATE for good measure?).  I'm not sure what the right thing to do
> is... but we should probably come up with some consensus position we
> can all live with, and then go make this uniform[1].

'INSERT OR CREATE' was specifically mentioned as something which would
be very useful for certain development-type activities at PGOpen.  I'm
on the fence about it myself, but it is kind of a neat idea.
Thanks,
    Stephen

Re: Truncate if exists

От
Robert Haas
Дата:
On Thu, Oct 11, 2012 at 3:22 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
> So we just need a function called pg_if_table_exists(table, SQL) which
> wraps a test in a subtransaction.
>
> And you write
>
> SELECT pg_if_table_exists('foo', 'TRUNCATE TABLE foo');
>
> and we can even get rid of all that other DDL crud that's been added....
>
> and we can have pg_if_table_not_exists() also.

You could make this more composable by having pg_table_exists() and
pg_execute_sql_from_string().  Then you can write: SELECT CASE WHEN
pg_table_exists(...) THEN pg_execute_sql_from_string(...) END.  And if
you want the if-not-exists case then just stick a NOT in there.  And
if you want a more complicated condition, you can easily write that as
well.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Truncate if exists

От
Stephen Frost
Дата:
* Tom Lane (tgl@sss.pgh.pa.us) wrote:
> Second, to my mind the point of a multi-table TRUNCATE is to ensure that
> all the referenced tables get reset to empty *together*.  With something
> like this, you'd have no such guarantee.  Consider a timeline like this:

Don't we have the exact same issue with DROP TABLE and multi-table
support for it today..?
Session 1            Session 2
DROP IF EXISTS a, b, c;... finds c doesn't exist ...... working on a and b ...                CREATE TABLE c ( ...
);...commits ...
 

But now we have a table 'c' where we didn't expect to because we DROP'd
it?  If you COMMIT then you can't expect things to not have changed under
you after your transaction is over, you're going to have to be ready to
deal with the consequences either way..

Heck, even if your scenario, don't you have to be concerned in Session 1
that someone insert'd data into 'c' after your commit but before you
open your next transaction?

The TRUNCATE in a multi-table case, imv, is typically to address FK
relationships.  Provided we don't allow a situation where data could be
stored which violates a FK due to a TRUNCATE IF EXISTS happening in some
other session concurrently (which I don't think could happen, but it'd
be something to verify, I suppose), the precedent of proceeding with
multi-table IF EXISTS commands even in the face of a given table not
existing should hold.

If we don't feel that is appropriate for TRUNCATE, then I would question
if we should have it for DROP TABLE- but if we don't have that semantic,
what are we going to have?  All tables have to either exist or not
exist?  Disallow IF EXISTS when a multi-table command is given?  Neither
strikes me as better.
Thanks,
    Stephen

Re: Truncate if exists

От
Alvaro Herrera
Дата:
Robert Haas escribió:
> On Thu, Oct 11, 2012 at 3:22 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
> > So we just need a function called pg_if_table_exists(table, SQL) which
> > wraps a test in a subtransaction.
> >
> > And you write
> >
> > SELECT pg_if_table_exists('foo', 'TRUNCATE TABLE foo');
> >
> > and we can even get rid of all that other DDL crud that's been added....
> >
> > and we can have pg_if_table_not_exists() also.
>
> You could make this more composable by having pg_table_exists() and
> pg_execute_sql_from_string().  Then you can write: SELECT CASE WHEN
> pg_table_exists(...) THEN pg_execute_sql_from_string(...) END.  And if
> you want the if-not-exists case then just stick a NOT in there.  And
> if you want a more complicated condition, you can easily write that as
> well.

Uh, we had an execute() function of sorts in the extensions patch; that
seems to have been ripped out.  Do we want it back?

--
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services



Re: Truncate if exists

От
Stephen Frost
Дата:
* Josh Berkus (josh@agliodbs.com) wrote:
> On 10/9/12 1:35 PM, Peter Eisentraut wrote:
> > On 10/9/12 5:09 AM, Simon Riggs wrote:
> >> Anyone want to check for any other missing IF EXISTS capability in other DDL?
> >
> > TRUNCATE is not really DDL.  If we allow TRUNCATE IF EXISTS, what is
> > stopping someone from requesting DELETE IF EXISTS or INSERT IF EXISTS next?
>
> That's a very good point.  I tend to think of all utility commands as
> DDL, which of course they're not.

I don't actually see why that's, inherently, a bad idea.  Nor do I see
why IF EXISTS should only apply to DDL and not to all commands.

Obviously, if you write 'IF EXISTS', you've got a plan to deal with the
fact that it doesn't exist.  In a lossy system that's using partitions,
I could actually see a pretty good use-case for wanting INSERT IF
EXISTS (rather than having to constantly poll, waiting for the partition
table that's supposted to be created by some other process to show up).
Thanks,
    Stephen

Re: Truncate if exists

От
Dimitri Fontaine
Дата:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
> Uh, we had an execute() function of sorts in the extensions patch; that
> seems to have been ripped out.  Do we want it back?

It was pretty different from what's being proposed here, as it was the
server-side version of psql \i feature, that is, executing commands read
directly from a SQL file on the server file's system.

I'd much prefer that we spend time making such an hypothetical feature
that irrelevant in all cases. There's still some work here, because the
feature only is hypothetical to end users, that's exactly what we rely
on today in the backend internal code…

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support



Re: Truncate if exists

От
Robert Haas
Дата:
On Fri, Oct 12, 2012 at 3:23 PM, Alvaro Herrera
<alvherre@2ndquadrant.com> wrote:
> Uh, we had an execute() function of sorts in the extensions patch; that
> seems to have been ripped out.  Do we want it back?

Well, it wasn't necessary for that patch, which is why it got ripped
out.  But I don't remember anybody saying it was a bad idea in
general.  Which also doesn't mean that it's a good idea in general.
I'm open to whatever other people think is best.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Truncate if exists

От
Christopher Browne
Дата:
On Fri, Oct 12, 2012 at 3:04 PM, Robert Haas <robertmhaas@gmail.com> wrote:
> On Thu, Oct 11, 2012 at 3:22 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
>> So we just need a function called pg_if_table_exists(table, SQL) which
>> wraps a test in a subtransaction.
>>
>> And you write
>>
>> SELECT pg_if_table_exists('foo', 'TRUNCATE TABLE foo');
>>
>> and we can even get rid of all that other DDL crud that's been added....
>>
>> and we can have pg_if_table_not_exists() also.
>
> You could make this more composable by having pg_table_exists() and
> pg_execute_sql_from_string().  Then you can write: SELECT CASE WHEN
> pg_table_exists(...) THEN pg_execute_sql_from_string(...) END.  And if
> you want the if-not-exists case then just stick a NOT in there.  And
> if you want a more complicated condition, you can easily write that as
> well.

While that certainly has the merit of being compact, it mixes kinds of
evaluation (e.g. - parts of it are parsed at different times) and
requires quoting that isn't true for the other sorts of "IF EXISTS"
queries.

To be sure, you can do anything you like inside a DO $$ $$ language
plpgsql; block, but it's not nice to have to do a lot of work
involving embedding code between languages.  Makes it harder to
manipulate, analyze, and verify.

Let me observe that Perl has, as one of its conditional concepts, the
notion of a "statement modifier"
<http://perldoc.perl.org/perlsyn.html#Statement-Modifiers>, which
corresponds pretty much to the IF EXISTS/IF NOT EXISTS modifiers that
have gotten added to Postgres over the last few versions.  (I *think*
statement modifiers are attributable to SNOBOL, not 100% sure.  I'm
pretty sure it predates Perl.)

I suggest the though of embracing statement modifiers in DDL, with
some options possible: a) { DDL STATEMENT } IF CONDITION; b) { DDL STATEMENT } UNLESS CONDITION;

where CONDITION has several possible forms: i) {IF|UNLESS} ( SQL expression returning T/F ) ii) {IF|UNLESS} {EXISTS|NOT
EXISTS}
{TABLE|SCHEMA|COLUMN|FUNCTION|...} object_name

That feels like a cleaner extension than what we have had, with the IF
EXISTS/IF NOT EXISTS clauses that have been added to various
CREATE/DROP/ALTER commands.
-- 
When confronted by a difficult problem, solve it by reducing it to the
question, "How would the Lone Ranger handle this?"



Re: Truncate if exists

От
Josh Berkus
Дата:
On 10/12/12 2:05 PM, Christopher Browne wrote:
> That feels like a cleaner extension than what we have had, with the IF
> EXISTS/IF NOT EXISTS clauses that have been added to various
> CREATE/DROP/ALTER commands.

+1

Josh like!

-- 
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com



Re: Truncate if exists

От
Hannu Krosing
Дата:
On 10/12/2012 11:05 PM, Christopher Browne wrote:
> On Fri, Oct 12, 2012 at 3:04 PM, Robert Haas <robertmhaas@gmail.com> wrote:
>> On Thu, Oct 11, 2012 at 3:22 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
>>> So we just need a function called pg_if_table_exists(table, SQL) which
>>> wraps a test in a subtransaction.
>>>
>>> And you write
>>>
>>> SELECT pg_if_table_exists('foo', 'TRUNCATE TABLE foo');
>>>
>>> and we can even get rid of all that other DDL crud that's been added....
>>>
>>> and we can have pg_if_table_not_exists() also.
>> You could make this more composable by having pg_table_exists() and
>> pg_execute_sql_from_string().  Then you can write: SELECT CASE WHEN
>> pg_table_exists(...) THEN pg_execute_sql_from_string(...) END.  And if
>> you want the if-not-exists case then just stick a NOT in there.  And
>> if you want a more complicated condition, you can easily write that as
>> well.
> While that certainly has the merit of being compact, it mixes kinds of
> evaluation (e.g. - parts of it are parsed at different times) and
> requires quoting that isn't true for the other sorts of "IF EXISTS"
> queries.
>
> To be sure, you can do anything you like inside a DO $$ $$ language
> plpgsql; block, but it's not nice to have to do a lot of work
> involving embedding code between languages.  Makes it harder to
> manipulate, analyze, and verify.
>
> Let me observe that Perl has, as one of its conditional concepts, the
> notion of a "statement modifier"
> <http://perldoc.perl.org/perlsyn.html#Statement-Modifiers>, which
> corresponds pretty much to the IF EXISTS/IF NOT EXISTS modifiers that
> have gotten added to Postgres over the last few versions.  (I *think*
> statement modifiers are attributable to SNOBOL, not 100% sure.  I'm
> pretty sure it predates Perl.)
>
> I suggest the though of embracing statement modifiers in DDL, with
> some options possible:
>    a) { DDL STATEMENT } IF CONDITION;
>    b) { DDL STATEMENT } UNLESS CONDITION;
We could even go as far as

{ DDL STATEMENT } IF CONDITION ELSE {ANOTHER DDL STATEMENT };

For example

CREATE TABLE mytable(...)
IF NOT EXISTS TABLE mytable
ELSE TRUNCATE mytable;

>
> where CONDITION has several possible forms:
>    i) {IF|UNLESS} ( SQL expression returning T/F )
>    ii) {IF|UNLESS} {EXISTS|NOT EXISTS}
> {TABLE|SCHEMA|COLUMN|FUNCTION|...} object_name
>
> That feels like a cleaner extension than what we have had, with the IF
> EXISTS/IF NOT EXISTS clauses that have been added to various
> CREATE/DROP/ALTER commands.




Re: Truncate if exists

От
Dimitri Fontaine
Дата:
Christopher Browne <cbbrowne@gmail.com> writes:
> I suggest the though of embracing statement modifiers in DDL, with
> some options possible:
>   a) { DDL STATEMENT } IF CONDITION;
>   b) { DDL STATEMENT } UNLESS CONDITION;

Just saying. I hate that. Makes it harder to read, that last bit at the
end of the command changes it all. It's cool for a linguist, I guess,
but we're not typing sentences at the psql prompt…

> where CONDITION has several possible forms:
>   i) {IF|UNLESS} ( SQL expression returning T/F )
>   ii) {IF|UNLESS} {EXISTS|NOT EXISTS}
> {TABLE|SCHEMA|COLUMN|FUNCTION|...} object_name

Now we're talking about T-SQL? Sorry, I suppose you didn't mean to lead
us that way, but I couldn't resist comparing. Soon enough you want a
full programming language there.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support



Re: Truncate if exists

От
Josh Berkus
Дата:
>> where CONDITION has several possible forms:
>>   i) {IF|UNLESS} ( SQL expression returning T/F )
>>   ii) {IF|UNLESS} {EXISTS|NOT EXISTS}
>> {TABLE|SCHEMA|COLUMN|FUNCTION|...} object_name
> 
> Now we're talking about T-SQL? Sorry, I suppose you didn't mean to lead
> us that way, but I couldn't resist comparing. Soon enough you want a
> full programming language there.

Well, embedding such a thing into plpgsql wouldn't be a bad thing.  It's
a lot less hard on the DevOps person to request that they write a DO
statement if the DO statement is one line:

DO $$
BEGIN
TRUNCATE TABLE foo IF EXISTS foo;
END;$$;

Come to think of it, I've *often* wished for the perl-ish "do x if y"
syntax for plpgsql, and not just for DDL.

-- 
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com



Re: Truncate if exists

От
Christopher Browne
Дата:
On Fri, Oct 12, 2012 at 5:52 PM, Dimitri Fontaine
<dimitri@2ndquadrant.fr> wrote:
> Christopher Browne <cbbrowne@gmail.com> writes:
>> I suggest the though of embracing statement modifiers in DDL, with
>> some options possible:
>>   a) { DDL STATEMENT } IF CONDITION;
>>   b) { DDL STATEMENT } UNLESS CONDITION;
>
> Just saying. I hate that. Makes it harder to read, that last bit at the
> end of the command changes it all. It's cool for a linguist, I guess,
> but we're not typing sentences at the psql prompt…

I could see it beingWHEN CONDITION { STATEMENT } OTHERWISE { STATEMENT };

It's all a strawman proposal, where I'm perfectly happy if there's
something people like better.  I like to think this is cleaner than
the present proliferation of {IF EXISTS|IF NOT EXISTS}, but if others
don't concur, there's little point to taking it further.

>> where CONDITION has several possible forms:
>>   i) {IF|UNLESS} ( SQL expression returning T/F )
>>   ii) {IF|UNLESS} {EXISTS|NOT EXISTS}
>> {TABLE|SCHEMA|COLUMN|FUNCTION|...} object_name
>
> Now we're talking about T-SQL? Sorry, I suppose you didn't mean to lead
> us that way, but I couldn't resist comparing. Soon enough you want a
> full programming language there.

Heh.  Next, I'll be proposing LETREC*, or of adopting the EVERY
operator from Icon, and coroutines from BCPL :-).  Keen on LOOP? :-)

The fact that we now have WITH RECURSIVE does extend what's reasonable
to hope for :-).
--
When confronted by a difficult problem, solve it by reducing it to the
question, "How would the Lone Ranger handle this?"



Re: Truncate if exists

От
Greg Stark
Дата:
On Tue, Oct 9, 2012 at 9:04 PM, Robert Haas <robertmhaas@gmail.com> wrote:
> I've been a big proponent of adding "IF EXISTS" support to CREATE
> TABLE and ALTER TABLE but I'm having a hard time getting excited about
> this one.  I can't imagine that many people would use it

The reason CREATE IF NOT EXISTS and DROP IF EXISTS are so useful is
because they're shortcuts for ensuring some specific state is always
true. Regardless of whether the table existed before, now it does or
doesn't as desired. (The concern about create was in fact specifically
that it wouldn't guarantee that the same table definition would exist
afterwards)

The same is not true of TRUNCATE IF EXISTS. In that case after the
command has run either the table exists and is empty or it doesn't
exist and still needs to be created.

I take it the intended use is something like
TRUNCATE IF EXISTS foo;
CREATE IF NOT EXISTS foo...

So perhaps what we really need is a CREATE OR TRUNCATE foo(...), but
just plain TRUNCATE IF EXISTS doesn't seem to make sense.




-- 
greg



Re: Truncate if exists

От
Josh Berkus
Дата:
On 10/12/12 3:49 PM, Greg Stark wrote:
> TRUNCATE IF EXISTS foo;
> CREATE IF NOT EXISTS foo...

Thing is, this can be written:

CREATE IF NOT EXISTS foo ...
TRUNCATE foo;

For the exact same result.

So, based on all of the objections and discussion on this feature, I
personally no longer support it.

-- 
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com



Re: Truncate if exists

От
Robert Haas
Дата:
On Fri, Oct 12, 2012 at 5:52 PM, Dimitri Fontaine
<dimitri@2ndquadrant.fr> wrote:
> Christopher Browne <cbbrowne@gmail.com> writes:
>> I suggest the though of embracing statement modifiers in DDL, with
>> some options possible:
>>   a) { DDL STATEMENT } IF CONDITION;
>>   b) { DDL STATEMENT } UNLESS CONDITION;
>
> Just saying. I hate that. Makes it harder to read, that last bit at the
> end of the command changes it all. It's cool for a linguist, I guess,
> but we're not typing sentences at the psql prompt…
>
>> where CONDITION has several possible forms:
>>   i) {IF|UNLESS} ( SQL expression returning T/F )
>>   ii) {IF|UNLESS} {EXISTS|NOT EXISTS}
>> {TABLE|SCHEMA|COLUMN|FUNCTION|...} object_name
>
> Now we're talking about T-SQL? Sorry, I suppose you didn't mean to lead
> us that way, but I couldn't resist comparing. Soon enough you want a
> full programming language there.

To be perfectly frank, I think that's exactly where we ought to be
going.  Oracle and Microsoft both did it, so why are we convinced it's
a bad idea?  One of the huge problems with PL/pgsql is that every SQL
expression in there has to be passed to the executor separately, which
is painfully slow.  It frequently doesn't matter because writing loops
in a procedural language is often the wrong approach anyway, but it is
not always the wrong approach and people sometimes do it even when it
is, and then they end up unhappy.

In the short term this is not a practical outcome for us; what we can
reasonably do is add a few convenience functions to what we already
have to make it easy to test for things like the presence of a table,
the presence of a column, the presence of a schema, etc.  But in the
longer term, this is definitely something that people want.  Being
able to wrap control-flow statements around SQL is fundamentally
useful, which is why every major database supports it.  Being able to
do it without a lot of superfluous syntactic sugar and with good
performance is even more useful.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Truncate if exists

От
Greg Stark
Дата:
On Mon, Oct 15, 2012 at 3:26 PM, Robert Haas <robertmhaas@gmail.com> wrote:
> To be perfectly frank, I think that's exactly where we ought to be
> going.  Oracle and Microsoft both did it, so why are we convinced it's
> a bad idea?  One of the huge problems with PL/pgsql is that every SQL
> expression in there has to be passed to the executor separately, which
> is painfully slow.

I'm a bit lost. I would think pl/pgsql is precisely the same as
Oracle's pl/sql and MS's T-SQL. I see the complaint you have as a
purely implementation detail. I don't think pl/pgsql is the best
implemented part of Postgres but I don't see how integrating it into
the core is going to automatically make it all wonderful either.

Fwiw my experience has consistently been that life got better whenever
I moved anything I had implemented as PL/SQL or PL/pgsql into client
code in Perl or Python.


-- 
greg



Re: Truncate if exists

От
Hannu Krosing
Дата:
On 10/15/2012 04:34 PM, Greg Stark wrote:
> On Mon, Oct 15, 2012 at 3:26 PM, Robert Haas <robertmhaas@gmail.com> wrote:
>> To be perfectly frank, I think that's exactly where we ought to be
>> going.  Oracle and Microsoft both did it, so why are we convinced it's
>> a bad idea?  One of the huge problems with PL/pgsql is that every SQL
>> expression in there has to be passed to the executor separately, which
>> is painfully slow.
> I'm a bit lost. I would think pl/pgsql is precisely the same as
> Oracle's pl/sql and MS's T-SQL. I see the complaint you have as a
> purely implementation detail. I don't think pl/pgsql is the best
> implemented part of Postgres but I don't see how integrating it into
> the core is going to automatically make it all wonderful either.
>
> Fwiw my experience has consistently been that life got better whenever
> I moved anything I had implemented as PL/SQL or PL/pgsql into client
> code in Perl or Python.
Just curious - why did you move it into _client_ code ?

Why not pl/perl or pl/python ?

Was performance not a concern and it was easier (administratively?) to 
manage it on the client side ?

---------
Hannu

>




Re: Truncate if exists

От
Robert Haas
Дата:
On Mon, Oct 15, 2012 at 10:34 AM, Greg Stark <stark@mit.edu> wrote:
> I'm a bit lost. I would think pl/pgsql is precisely the same as
> Oracle's pl/sql and MS's T-SQL. I see the complaint you have as a
> purely implementation detail. I don't think pl/pgsql is the best
> implemented part of Postgres but I don't see how integrating it into
> the core is going to automatically make it all wonderful either.

It isn't.  But (1) there would be a significant usability benefit in
not having to surround procedural logic with DO $$ BEGIN ... END $$
and (2) PL/pgsql's performance issues seem to revolve around the fact
that you don't get one big ol' plan thingy that can be passed to the
executor and run; instead, you interpret each statement separately and
pass them off to the executor one piece at a time.

It wouldn't technically be necessary to integrate the code fully into
core into realize these benefits; you could maintain some abstraction
layer in between and provide an API to push information back and
forth.  But to take a trivial example, consider a FOR loop that
executes an enclosed SQL statement a large number of times.  Right
now, we build a plan tree for the SQL statement and then start up and
shut down the executor N times.  If we could instead push an "iterate"
not on top of the plan tree to handle the iteration, and then start up
the executor, run the plan, and shut down the executor, my guess is
that it would be way faster than our current implementation.
Everything I've seen leads me to believe that the executor is quite
zippy when it gets going, but bouncing in and out of it repeatedly
seems to be a source of real pain.

> Fwiw my experience has consistently been that life got better whenever
> I moved anything I had implemented as PL/SQL or PL/pgsql into client
> code in Perl or Python.

Hmm... I've had the opposite experience, which I guess is why I've got
strong feelings about this.  I've found that checking for uniqueness
violations without relying on the database doesn't really work due to
concurrency issues, and once I've got to catch that error from the
database side and expose it to the user as a nicely-formatted
complaint (the name you have chosen is already in use; please choose
another) I have found that it seems to make sense to push everything
other than the initial, relatively trivial syntax checking into
PostgreSQL.  Anyway, I think there's probably more than one sensible
design decision there and may come down to personal preference and
toolchain selection more than anything.

Whatever either of us think, though, the complaint at the top of this
thread indicates that people are NOT happy doing this on the client
side and DO isn't convenient enough either.  What do we do about that?I'm not extraordinarily attached to any specific
proposalbut I think
 
we should be looking for ways to make this better.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Truncate if exists

От
Christopher Browne
Дата:
On Mon, Oct 15, 2012 at 11:57 AM, Robert Haas <robertmhaas@gmail.com> wrote:
> On Mon, Oct 15, 2012 at 10:34 AM, Greg Stark <stark@mit.edu> wrote:
>> I'm a bit lost. I would think pl/pgsql is precisely the same as
>> Oracle's pl/sql and MS's T-SQL. I see the complaint you have as a
>> purely implementation detail. I don't think pl/pgsql is the best
>> implemented part of Postgres but I don't see how integrating it into
>> the core is going to automatically make it all wonderful either.
>
> It isn't.  But (1) there would be a significant usability benefit in
> not having to surround procedural logic with DO $$ BEGIN ... END $$
> and (2) PL/pgsql's performance issues seem to revolve around the fact
> that you don't get one big ol' plan thingy that can be passed to the
> executor and run; instead, you interpret each statement separately and
> pass them off to the executor one piece at a time.

The places where *I* care about this are places where performance is
almost entirely irrelevant to the question.

When I'm writing 'scripts' that are doing this kind of thing, I'm
doing schema 'surgery', and, within reason, it's not particularly
performance sensitive.  I'm much more worried about DDL scripts being
repeatable and manageable than I am about them being fast.

So I'm going to elide the performance bits.

Robert, when you first tossed out the notion of:

do $$   begin       if (select 1 from pg_class where relname = 'foo' and
pg_table_is_visible(oid)) then           truncate table foo;       end if;   end
$$;

my first reaction was "Ick!   Why am I switching languages (e.g. -
from plain SQL to pl/pgsql), and running functions to do this?!?"

In retrospect, your later comments make it pretty clear that you're
not proposing that as the end state, just that that's the
functionality that needs to be run.

That would would be equivalent to my would-be-strawman syntax of:
   TRUNCATE TABLE public.foo IF EXISTS TABLE public.foo;

I'm comfortable that Dimitri didn't particularly love the idea of
stowing the conditional at the end; it was just a strawman proposal,
and what was particularly important to me was to make sure that it was
recognizable that other systems (e.g. - Perl, Ruby, probably SNOBOL)
have done the very same thing.  I'd be perfectly happy if someone came
up with something better.  The number of "+1"'s thus far is pretty
gratifying, mind you.

>> Fwiw my experience has consistently been that life got better whenever
>> I moved anything I had implemented as PL/SQL or PL/pgsql into client
>> code in Perl or Python.
>
> Hmm... I've had the opposite experience, which I guess is why I've got
> strong feelings about this.

When I'm "managing schema", I have exactly *zero* interest in
switching over to Perl or Python.  Those aren't languages for managing
database schemas, and, if I wind up using them, my code is going to be
rife with context switches as I'm switching between  "oh, am I writing Perl code?"   and  "Am I attached to the right
Perldatabase connection object, with
 
the proper transaction context?"   and  "Oh, here is the SQL DDL for managing the schema."

Two of these three varieties of contexts are distracting sidelines to
me.  Guess which are the two?  :-)
-- 
When confronted by a difficult problem, solve it by reducing it to the
question, "How would the Lone Ranger handle this?"



Re: Truncate if exists

От
Robert Haas
Дата:
On Mon, Oct 15, 2012 at 12:53 PM, Christopher Browne <cbbrowne@gmail.com> wrote:
> The places where *I* care about this are places where performance is
> almost entirely irrelevant to the question.
>
> When I'm writing 'scripts' that are doing this kind of thing, I'm
> doing schema 'surgery', and, within reason, it's not particularly
> performance sensitive.  I'm much more worried about DDL scripts being
> repeatable and manageable than I am about them being fast.
>
> So I'm going to elide the performance bits.
>
> Robert, when you first tossed out the notion of:
>
> do $$
>     begin
>         if (select 1 from pg_class where relname = 'foo' and
> pg_table_is_visible(oid)) then
>             truncate table foo;
>         end if;
>     end
> $$;
>
> my first reaction was "Ick!   Why am I switching languages (e.g. -
> from plain SQL to pl/pgsql), and running functions to do this?!?"
>
> In retrospect, your later comments make it pretty clear that you're
> not proposing that as the end state, just that that's the
> functionality that needs to be run.

Yeah, I think the functionality that we need is pretty much there
already today.  What we need to do is to get the syntax to a point
where people can write the code they want to write without getting
tangled up by it.

I think the invention of DO was a big step in the right direction,
because before that if you wanted procedural logic in your script, you
had to create a function, call it, and then drop the function.  That
is exceedingly awkward and introduces a number of unpleasant and
unnecessary failure modes.  With DO, you can write the logic you want
as an SQL statement, it's just a clunky and awkward SQL statement.  In
my view the goal ought to be to refine that mechanism to remove the
clunkiness and awkwardness, rather than to invent something completely
new.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Truncate if exists

От
Dimitri Fontaine
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
>>         if (select 1 from pg_class where relname = 'foo' and
>> pg_table_is_visible(oid)) then
>>             truncate table foo;
>>         end if;
>
> Yeah, I think the functionality that we need is pretty much there
> already today.  What we need to do is to get the syntax to a point
> where people can write the code they want to write without getting
> tangled up by it.

What about continuing to extend on that incredibly useful WITH syntax we
already have:
  WITH target AS (     SELECT oid::regclass AS t       FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid
 WHERE pg_table_is_visible(oid)        AND nspname = 'public' AND NOT relname ~ 'exclude-pattern'  )  TRUNCATE TABLE t
FROMtarget;
 

Maybe somewhat involved as far as code support is concerned. That said,
full integration of a PL into the main parser doesn't strike me as that
easier. Maybe a simpler way to reach the feature would be:
  WITH target AS (     SELECT oid::regclass AS t       FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid
 WHERE pg_table_is_visible(oid)        AND nspname = 'public' AND NOT relname ~ 'exclude-pattern'  )  EXECUTE 'TRUNCATE
TABLE$1' USING target(t);
 

But I'm not sure it gives anything else than a hint about how to
implement the first idea.

> I think the invention of DO was a big step in the right direction,
> because before that if you wanted procedural logic in your script, you
> had to create a function, call it, and then drop the function.  That

Yes, that's the sentence that got me to think about the above proposal,
because we are already talking about implementing WITH FUNCTION in
another thread, to answer some of Pavel's needs.

> my view the goal ought to be to refine that mechanism to remove the
> clunkiness and awkwardness, rather than to invent something completely
> new.

So, what do you think? Smells like empowered SQL this time, right?

Regards,
-- 
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support



Re: Truncate if exists

От
Robert Haas
Дата:
On Mon, Oct 15, 2012 at 3:14 PM, Dimitri Fontaine
<dimitri@2ndquadrant.fr> wrote:
> What about continuing to extend on that incredibly useful WITH syntax we
> already have:
>
>    WITH target AS (
>       SELECT oid::regclass AS t
>         FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid
>        WHERE pg_table_is_visible(oid)
>          AND nspname = 'public' AND NOT relname ~ 'exclude-pattern'
>    )
>    TRUNCATE TABLE t FROM target;

I'm not exactly sure what that is supposed to do, but it doesn't seem
like an easy-to-use substitute for truncate-if-exists...

>> my view the goal ought to be to refine that mechanism to remove the
>> clunkiness and awkwardness, rather than to invent something completely
>> new.
>
> So, what do you think? Smells like empowered SQL this time, right?

I like the idea of making our SQL dialect capable of working with DDL
in more powerful ways; I'm not sold on the concrete proposal.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Truncate if exists

От
Dimitri Fontaine
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
>>    WITH target AS (
>>    TRUNCATE TABLE t FROM target;
>
> I'm not exactly sure what that is supposed to do, but it doesn't seem
> like an easy-to-use substitute for truncate-if-exists...

Indeed. I'm still a supporter of truncate-if-exists. Still, we're also
talking about a more flexible and powerful design, it seems to me.

> I like the idea of making our SQL dialect capable of working with DDL
> in more powerful ways; I'm not sold on the concrete proposal.

Cool,
-- 
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support



Re: Truncate if exists

От
Christopher Browne
Дата:
On Mon, Oct 15, 2012 at 3:14 PM, Dimitri Fontaine
<dimitri@2ndquadrant.fr> wrote:
> Robert Haas <robertmhaas@gmail.com> writes:
>>>         if (select 1 from pg_class where relname = 'foo' and
>>> pg_table_is_visible(oid)) then
>>>             truncate table foo;
>>>         end if;
>>
>> Yeah, I think the functionality that we need is pretty much there
>> already today.  What we need to do is to get the syntax to a point
>> where people can write the code they want to write without getting
>> tangled up by it.
>
> What about continuing to extend on that incredibly useful WITH syntax we
> already have:
>
>    WITH target AS (
>       SELECT oid::regclass AS t
>         FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid
>        WHERE pg_table_is_visible(oid)
>          AND nspname = 'public' AND NOT relname ~ 'exclude-pattern'
>    )
>    TRUNCATE TABLE t FROM target;

This still seems to be trying rather too hard.

The original suggestion was that, given the original query:
 truncate table public.foo;

that we add syntax to make the request optional:
 truncate table if exists public.foo;

Throwing in $$, oid, pg_class, joins, and such all seem like way more
syntax than we started with.

There are only so many 'clean' ways to modify the truncate request:

a) We could augment TRUNCATE with an "IF EXISTS" modifier, as
described in the initial patch.

b) Perhaps the IF EXIST might fit well afterwards, or be reversed somehow.
  truncate table unless not exists public.foo;  truncate table public.foo if exists;  truncate table where exists
public.foo;

c) My proposal was to add in a more generic modifier that wouldn't be
specific to TRUNCATE.

Thus:
  truncate table public.foo if exists table public.foo;

That's a *little* longer than what's in b), but this would allow
extending the conditional to any kind of statement, which seems like a
more powerful idea to me.  It would also support doing other actions
on the same conditional basis:
  insert into bar (select id, name from public.foo)     if exists table public.foo;

If you want a more "prefix-y" version, well, here's how it might look
using a leading WITH clause:
  with exists table public.foo     truncate public.foo;
 with exists table public.foo    insert into bar (select id, name from public.foo);

I don't terribly much like that.  I think I'd rather use WHEN than WITH.
  when exists table public.foo     truncate public.foo;
 when exists table public.foo    insert into bar (select id, name from public.foo);

That does seem a bit nicer than the { STATEMENT } if (conditional)
idea.  And nary a $$, oid, or pg_class to be seen.
-- 
When confronted by a difficult problem, solve it by reducing it to the
question, "How would the Lone Ranger handle this?"



Re: Truncate if exists

От
"Stafford, David x78061"
Дата:
On Mon, 15 Oct 2012 10:21:18 -0700, Robert Haas <robertmhaas@gmail.com> wrote:
> Yeah, I think the functionality that we need is pretty much there
> already today.  What we need to do is to get the syntax to a point
> where people can write the code they want to write without getting
> tangled up by it.
>
> I think the invention of DO was a big step in the right direction
> ...
> With DO, you can write the logic you want
> as an SQL statement, it's just a clunky and awkward SQL statement.  In
> my view the goal ought to be to refine that mechanism to remove the
> clunkiness and awkwardness, rather than to invent something completely
> new.

As someone who has worked with a number of databases now, none of them really get this DDL integration completely
right. What I'd like to see is 1) a predicate to easily test things about the schema (does this table, column, index,
schema,etc. exist?  does it have the right type?) and 2) a way to conditionally execute DDL (and DML, which should fall
rightout, but it isn't really what this discussion is covering).  I would propose extending the current EXISTS / NOT
EXISTSpredicate as follows: 

[NOT] EXISTS TABLE tab [ ( col [type] [ , col [type]]... ) ]
[NOT] EXISTS COLUMN tab.col [type]
[NOT] EXISTS INDEX tab.idx [ ( col [ , col]... ) ]
[NOT] EXISTS CONSTRAINT tab.cstrt -- not sure what else might be useful here
[NOT] EXISTS ( select ) -- this is the current EXISTS predicate, of course
[NOT] EXISTS ANY ROWS FROM tab [join] [WHERE predicate] [GROUP BY col [ , col]...] -- exactly the same as
                                                                   -- (select 1 FROM etc.)
                                                   -- only because I like
                                   -- it better 
(the latter [which by no means am I nuts over; it's just that when extending EXISTS I can't stop neatening it up to my
personalpreferences] could be extended with [NOT] EXISTS MORE THAN n ROWS FROM and [NOT] EXISTS EXACTLY n ROWS FROM.) 

There is a new SQL statement: IF predicate true-statement [ELSE false-statement].

To actually execute this new IF statement, the executor would need an IF node that evaluates the predicate (with ANDs
andORs, just like all SQL predicates) and then executes the rest only if the predicate came out TRUE (or NOT FALSE; I
forgetwhich is usually used, and the difference with NULL could be useful, as long as it matches other predicates).
Thismoves one more bit of procedural logic into the executor.   

Another wrinkle is that the dependent statement might not compile, due to missing tables or whatnot.  Actually
executingit while it doesn't compile is an error, but we want to defer that error until we actually decide we need to
executeit.  Also, it's probably good to try compiling it again at that point.  So my thought would be to try planning
thedependent statement(s); if they compile, hook them to the IF node; if not, hook a DEFERRED node to the IF node.  The
DEFERREDnode has the parse tree (or raw string, whatever makes sense) of the statement; on execution it tries again to
planthat statement; if it succeeds, run it; if not, error out. 

I'd also add a SEQUENCE node to the executor.  It just runs its children in order (could be n-ary, or if fixed arity
nodesare what is in the planner/executor today, could be binary, first left, then right, and right could be another
SEQUENCE). The DEFERRED node means that a CREATE statement could precede use of what is created in the same sequence
andall could get planned (with some deferral to execution time) in advance and run in one lump.  This implements DO at
theexecutor level. 

The biggest concepts left from plpgsql are looping and variables.  Most variables could be modeled as a single row
value;SQL already can update a row, so the planning of assignments and calculations of scalars (and arrays, I think)
alreadyfits into things the planner knows about.  Table variables (which I don't know that plpgsql supports, but
somedayit should) are less defined.  Adding plpgsql's loops to the executor would let whole functions run under one
tripthrough the executor.  This is beyond just improving the DDL support for scripts. 

I have written a number of database upgrade scripts.  Over time we've made them less fragile, by checking for the
existenceof tables, indexes, and most recently, columns.  The usual sequence is: 
1) check the existence of an index; check that the first few columns are correct; if not, drop the index
2) repeat for other indexes that have changed definition over time
3) check the existence of the table; create with current layout if it is missing
4) check for the presence of a column; if missing, alter the table to add it (of course, we can only add new columns at
theend, and occasionally delete a column) 
5) repeat for more columns
6) check the existence of an index; if missing, create it
7) repeat for all the indexes
This is doable in most databases, but pretty messy.  You need to join with infoschema tables, or system tables, or use
clunkyfunctions to check for existence; checking types is usually pretty horrid.  Consequently, we only check a few
thingsand trust that the schema is only in a few different states.  A true schema comparator and upgrade solver would
begreat, but I don't know anyone who has written such a thing.  The extended EXISTS predicate that could check tables
andindexes would declutter a lot of our upgrade scripts.  That's the use case for me. 

Much as I'd like to, I'm not volunteering to write this.  And I'm not volunteering anyone else either, or demanding
anything,or requesting or pleading.  I did want to write it down and send it along just to clarify my thoughts.  And if
somedayI get time, maybe I can learn enough internals to write a patch.  But that day isn't today.... 


This message and any attachments are intended only for the use of the addressee and may contain information that is
privilegedand confidential. If the reader of the message is not the intended recipient or an authorized representative
ofthe intended recipient, you are hereby notified that any dissemination of this communication is strictly prohibited.
Ifyou have received this communication in error, please notify us immediately by e-mail and delete the message and any
attachmentsfrom your system. 



Re: Truncate if exists

От
Robert Haas
Дата:
On Tue, Oct 16, 2012 at 2:12 PM, Stafford, David x78061
<David.Stafford@broadridge.com> wrote:
> On Mon, 15 Oct 2012 10:21:18 -0700, Robert Haas <robertmhaas@gmail.com> wrote:
>> Yeah, I think the functionality that we need is pretty much there
>> already today.  What we need to do is to get the syntax to a point
>> where people can write the code they want to write without getting
>> tangled up by it.
>>
>> I think the invention of DO was a big step in the right direction
>> ...
>> With DO, you can write the logic you want
>> as an SQL statement, it's just a clunky and awkward SQL statement.  In
>> my view the goal ought to be to refine that mechanism to remove the
>> clunkiness and awkwardness, rather than to invent something completely
>> new.
>
> As someone who has worked with a number of databases now, none of them really get this DDL integration completely
right. What I'd like to see is 1) a predicate to easily test things about the schema (does this table, column, index,
schema,etc. exist?  does it have the right type?) and 2) a way to conditionally execute DDL (and DML, which should fall
rightout, but it isn't really what this discussion is covering).  I would propose extending the current EXISTS / NOT
EXISTSpredicate as follows: 
>
> [NOT] EXISTS TABLE tab [ ( col [type] [ , col [type]]... ) ]
> [NOT] EXISTS COLUMN tab.col [type]
> [NOT] EXISTS INDEX tab.idx [ ( col [ , col]... ) ]
> [NOT] EXISTS CONSTRAINT tab.cstrt -- not sure what else might be useful here
> [NOT] EXISTS ( select ) -- this is the current EXISTS predicate, of course
> [NOT] EXISTS ANY ROWS FROM tab [join] [WHERE predicate] [GROUP BY col [ , col]...] -- exactly the same as
>                                                                                    -- (select 1 FROM etc.)
>                                                                                    -- only because I like
>                                                                                    -- it better
> (the latter [which by no means am I nuts over; it's just that when extending EXISTS I can't stop neatening it up to
mypersonal preferences] could be extended with [NOT] EXISTS MORE THAN n ROWS FROM and [NOT] EXISTS EXACTLY n ROWS
FROM.)
>
> There is a new SQL statement: IF predicate true-statement [ELSE false-statement].
>
> To actually execute this new IF statement, the executor would need an IF node that evaluates the predicate (with ANDs
andORs, just like all SQL predicates) and then executes the rest only if the predicate came out TRUE (or NOT FALSE; I
forgetwhich is usually used, and the difference with NULL could be useful, as long as it matches other predicates).
Thismoves one more bit of procedural logic into the executor. 
>
> Another wrinkle is that the dependent statement might not compile, due to missing tables or whatnot.  Actually
executingit while it doesn't compile is an error, but we want to defer that error until we actually decide we need to
executeit.  Also, it's probably good to try compiling it again at that point.  So my thought would be to try planning
thedependent statement(s); if they compile, hook them to the IF node; if not, hook a DEFERRED node to the IF node.  The
DEFERREDnode has the parse tree (or raw string, whatever makes sense) of the statement; on execution it tries again to
planthat statement; if it succeeds, run it; if not, error out. 
>
> I'd also add a SEQUENCE node to the executor.  It just runs its children in order (could be n-ary, or if fixed arity
nodesare what is in the planner/executor today, could be binary, first left, then right, and right could be another
SEQUENCE). The DEFERRED node means that a CREATE statement could precede use of what is created in the same sequence
andall could get planned (with some deferral to execution time) in advance and run in one lump.  This implements DO at
theexecutor level. 
>
> The biggest concepts left from plpgsql are looping and variables.  Most variables could be modeled as a single row
value;SQL already can update a row, so the planning of assignments and calculations of scalars (and arrays, I think)
alreadyfits into things the planner knows about.  Table variables (which I don't know that plpgsql supports, but
somedayit should) are less defined.  Adding plpgsql's loops to the executor would let whole functions run under one
tripthrough the executor.  This is beyond just improving the DDL support for scripts. 
>
> I have written a number of database upgrade scripts.  Over time we've made them less fragile, by checking for the
existenceof tables, indexes, and most recently, columns.  The usual sequence is: 
> 1) check the existence of an index; check that the first few columns are correct; if not, drop the index
> 2) repeat for other indexes that have changed definition over time
> 3) check the existence of the table; create with current layout if it is missing
> 4) check for the presence of a column; if missing, alter the table to add it (of course, we can only add new columns
atthe end, and occasionally delete a column) 
> 5) repeat for more columns
> 6) check the existence of an index; if missing, create it
> 7) repeat for all the indexes
> This is doable in most databases, but pretty messy.  You need to join with infoschema tables, or system tables, or
useclunky functions to check for existence; checking types is usually pretty horrid.  Consequently, we only check a few
thingsand trust that the schema is only in a few different states.  A true schema comparator and upgrade solver would
begreat, but I don't know anyone who has written such a thing.  The extended EXISTS predicate that could check tables
andindexes would declutter a lot of our upgrade scripts.  That's the use case for me. 

I agree.  I think something like this would be great.  But figuring
out how to make it happen is, of course, the trick.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company