Re: \if, \elseif, \else, \endif (was Re: [HACKERS] PSQL commands:\quit_if, \quit_unless)

Поиск
Список
Период
Сортировка
От Corey Huinker
Тема Re: \if, \elseif, \else, \endif (was Re: [HACKERS] PSQL commands:\quit_if, \quit_unless)
Дата
Msg-id CADkLM=dm+d_FgtK4wqVkKr-X+naHXw60x+0veb04idFxYB141g@mail.gmail.com
обсуждение исходный текст
Ответ на Re: \if, \elseif, \else, \endif (was Re: [HACKERS] PSQL commands:\quit_if, \quit_unless)  (Fabien COELHO <coelho@cri.ensmp.fr>)
Ответы Re: \if, \elseif, \else, \endif (was Re: [HACKERS] PSQL commands:\quit_if, \quit_unless)  (Fabien COELHO <coelho@cri.ensmp.fr>)
Re: \if, \elseif, \else, \endif (was Re: [HACKERS] PSQL commands: \quit_if, \quit_unless)  ("Daniel Verite" <daniel@manitou-mail.org>)
Список pgsql-hackers

I'm wondering what pg would do on "EXISTS(SELECT 1 FROM customer)" if there are many employees. EXPLAIN suggests a seq_scan, which seems bad. With "(SELECT COUNT(*) FROM pgbench_accounts) <> 0" pg seems to generate an index only scan on a large table, so maybe it is a better way to do it. It seems strange that there is no better way to do that in a relational tool, the relational model being an extension of set theory... and there is no easy way (?) to check whether a set is empty.

I believe that the scan stops on the first row it finds, because the EXITS() clause is met. But it's not relevant to the documentation, I simply wanted to demonstrate some results that couldn't be resolved at parse time, so that the \if tests were meaningful. If the query example is distracting from the point of the documentation, we should change it.
 

"""If an EOF is reached on the main file or an <command>\include</command>-ed file before all <command>\if</command>-<command>\endif</command> are matched, then psql will raise an error."""

In sentence above: "before all" -> "before all local"? "then" -> ""?

+1 

"other options booleans" -> "other booleans of options"? or "options' booleans" maybe, but that is for people?

+1 

"unabigous" -> "unambiguous"

+1
 

I think that the three paragraph explanation about non evaluation could be factor into one, maybe something like: """Lines within false branches are not evaluated in any way: queries are not sent to the server, non conditional commands are not evaluated but bluntly ignored, nested if expressions in such branches are also not evaluated but are tallied to check for nesting."""

I would suggest to merge elif/else constraints by describing what is expected rather than what is not expected. """An \if command may contain any number of \elif clauses and may end with one \else clause""".

I'll give it another shot, as I forgot to mention the non-evaluation of expressions in dead branches.

 


## CODE

In "read_boolean_expression":

 + if (value)

"if (value != NULL)" is usually used, I think.

 + if (value == NULL)
 +   return false; /* not set -> assume "off" */

This is dead code, because value has been checked to be non NULL a few lines above.

 + (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
 + (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)

Hmmm, not easy to parse. Maybe it deserves a comment?
"check at least two chars to distinguish on & off"

",action" -> ", action" (space after commas).

The "result" is not set on errors, but maybe it should be set to false anyway and explicitely, instead of relying on some prior initialization?
Or document that the result is not set on errors.

This is code lifted from variable.c's ParseVariableBool().  When the other patch for "psql hooks" is committed (the one that detects when the string wasn't a valid boolean), this code will go away and we'll just use ParseVariableBool() again.
 

if command:

  if (is active) {
    success = ...
    if (success) {
      ...
    }
  }
  if (success) {
    ...
  }

The second test on success may not rely on the value set above. That looks very strange. ISTM that the state should be pushed whether parsing succeeded or not. Moreover, it results in:

  \if ERROR
     \echo X
  \else
     \echo Y
  \endif

having both X & Y printed and error reported on else and endif. I think that an expression error should just put the stuff in ignore state.

Not just false, but ignore the whole if-endif? interesting. I hadn't thought of that. Can do.
 


On "else" when in state ignored, ISTM that it should remain in state ignore, not switch to else-false.

That's how I know if this is the first "else" I encountered. I could split the if-state back into a struct of booleans if you think that makes more sense.

 


Comment about "IFSTATE_FALSE" talks about the state being true, maybe a copy-paste error?

Yes.
 

In comments: "... variables the branch" -> "variables if the branch"

Yes.
 

The "if_endifs_balanced" variable is not very useful. Maybe just the test and error reporting in the right place:

 if (... && !psqlscan_branch_empty(scan_state))
   psql_error("found EOF before closing \\endif(s)\n");

+1
I think I got the idea at some point that psql_error broke out of the current execution block.
 
History saving: I'm wondering whether all read line should be put into history, whether executed or not.

Good question. I gave it some thought and I decided it shouldn't.  First, because history is a set of statements that were attempted, and those statements were not. But perhaps more importantly, because the statement could have contained an expandable variable, and since that variable would not be evaluated the SQL stored would be subtly altered from the original intent, perhaps in ways that might drastically alter the meaning of the statement. A highly contrived example:

\set clause 'where cust_id = 1'
\if false
delete from customers :clause;
\endif

So yeah, it just seemed easier to not store in history.
 
Is it possible to make some of the added functions static? If so, do it.

I try to. I think some of the functions that used to be called in mainloop.c or command.c might not be anymore, and those can be made static. I'll recheck which ones can be.


I checked that it does stop on errors with -v ON_ERROR_STOP=1. However I would be more at ease if this was tested somewhere.

Yes, TAP tests forthcoming. I'll probably put out one more intermediate patch to get the 'just-ignore-til-endif' functionality of an invalid \if or \elseif, but the final push for a committed patch will have to wait until after the ParseVariableBool() issue is worked out.



В списке pgsql-hackers по дате отправления:

Предыдущее
От: "Daniel Verite"
Дата:
Сообщение: Re: [HACKERS] One-shot expanded output in psql using \G
Следующее
От: Fabrízio de Royes Mello
Дата:
Сообщение: Re: [HACKERS] Add support to COMMENT ON CURRENT DATABASE