Re: PSQL commands: \quit_if, \quit_unless

From: Corey Huinker <corey(dot)huinker(at)gmail(dot)com>
To: Robert Haas <robertmhaas(at)gmail(dot)com>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Fabien COELHO <coelho(at)cri(dot)ensmp(dot)fr>, Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>, Andrew Dunstan <andrew(at)dunslane(dot)net>, PostgreSQL <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: PSQL commands: \quit_if, \quit_unless
Date: 2016-12-17 20:39:22
Message-ID: CADkLM=cj6ds+Z2u28wkZFZ3-+WP+Rc6WnxF-LDDQrRaNsS_+mg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

>
> > (Or in other words, let's see \while ... \endloop in the minimal proposal
> > as well, or at least a sketch of how to get there.)
>
> It seems to me that we could implement \if ... \else ...\endif by
> having some kind of stack that indicates which constructs we're inside
> of and whether we're currently executing commands or discarding them.
> I think we want to avoid waiting until we see \endif to start running
> commands; it's better to execute or skip/discard each command as we
> see it.
>

+1

>
> To implement \while, we'd also need to remember previous commands so
> that when we reach the end of the loop, we can rewind and put all of
> those commands back on the stack to be executed again, or perhaps to
> be skipped if the \while condition turns out now to be false.
>

This might be what you meant when you said "those commands back on the
stack", but I think we'd have to remember not a list of commands, but the
raw string of bytes from the start of the \while to the \endwhile (or
equivalent), because any psql vars within that block could themselves be a
non-parameter part of a command:

-- this is how I fake an 'exit 0' now:
\set work_needs_to_be_done t
select
case
when :'work_needs_to_be_done'::boolean then ''
else '\q'
end as cmd
\gset
:cmd

-- ridiculous example to illustrate complications in remembering past
commands
select
case
when random() < 0.5 then '\ir my_script.sql'
when random() < 0.7 'select * from a_table; select count(*) from
another_table;'
else 'select null as foo;'
end as cmd
\gset
:cmd

And even then, things get complicated, because an \ir include which makes
it this iteration might not make it the next, and the \endwhile might have
been inside that include, or vice-versa, an included file starts a \while
it doesn't finish.

So maybe what we store is a stack of buffers that are currently open (STDIN
being captured as a buffer only when a \while starts, everything else being
files), and additionally have a stack of positions where a \while started
(buffer_id, position in buffer).

Additionally, we could assert that all \while-\endwhile pairs must happen
in the same MainLoop (aka file), and mismatches are an error.

I'm happy to keep sketching out what control structures might look like and
how to implement them. But I'm also happy to leave while/for loops out for
now.

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Tom Lane 2016-12-17 21:15:37 Re: Rethinking our fulltext phrase-search implementation
Previous Message Dean Rasheed 2016-12-17 20:30:29 Re: CREATE OR REPLACE VIEW bug