> david.g.johns...@gmail.com wrote:
> 
>> b...@yugabyte.com wrote:
>> 
>> *Summary*
>> 
>> My tests show that, when a WITHOUT HOLD cursor has to cache results (see 
>> Note 1), then the WHERE clause (if present) is stripped off the cursor's 
>> defining SELECT statement and the entire unrestricted result set is cached. 
>> But when a WITH HOLD cursor is used, then it’s the *restricted* result set 
>> that’s cached.
>> 
>> I do see that this wouldn't have a detectable effect when the cursor's 
>> defining query doesn't involve any volatile functions. But it does seem that 
>> too much data is cached in the "not holdable" case—and this seems to be a 
>> bad thing for space use and for speed.
> 
> IIUC, all you've demonstrated here is the (sometimes) case for the WITHOUT 
> HOLD cursor where a cache is not used (i.e., the typical case). In this 
> situation the executor, when asked to rewind back to the beginning, goes and 
> restarts execution at the beginning (executor nodes form a tree, it is 
> probable that certain nodes are more efficient at this "start over" thing 
> that others - e.g., I suspect a materialize node sitting in the tree would 
> prevent a sequential scan node from being asked to "start over"), which 
> necessarily involves potentially re-evaluating volatile functions/expressions 
> as noted.

Forgive me. I don't understand your reply. I do understand (having read 
Laurenz's blog post) that sometimes the execution plan for the cursor's 
defining SELECT cannot be run backwards. I'm not sure that it matters whether 
this case is typical or not. It's enough that it can occur. And this is the 
case that I'm interested in. Laurenz says that in this case, for a WITHOUT HOLD 
cursor, the results must be cached to allow scrollability. And the results of 
my tests are consistent with this—up to a point.

However, my results show that for the WITHOUT HOLD case, the restriction that 
the cursor's SELECT might have is *not* applied to what's cached. But the 
restriction *is* applied when the WITH HOLD cache is populated.

And it's this that I'm asking about.

Forget that I ever said "volatile". I just edited the code that I included in 
my previous post. I globally replaced "rndm_series" with "series". And I 
globally replaced "rndm_filter" with "filter". I also removed the "create 
procedure init_rndm()" statement and removed the calls of the procedure. Here 
are the new implementations of "series()" and "filter()""

create function series()
  returns table(v int)
  set search_path = s1, pg_catalog, pg_temp
  language plpgsql
as $body$
begin
  raise info 'series() invoked';

  for v in (select generate_series(1, 10))loop
    return next;
  end loop;
end;
$body$;

and

create function filter()
  returns boolean
  set search_path = pg_catalog, pg_temp
  language plpgsql
as $body$
begin
  raise info 'filter() invoked';
  return true;
end;
$body$;

Then I ran the four tests by hand because I don't know how to spool the "raise 
info" output to a file. In all cases, the "cursor_rows()" invocation just 
reports the ten rows with values in 1 through 10 — of course.

Here's what I saw:

* (1) open_holdable_cursor(holdable=>false, filter_series=>false, caption=>'') *

The "open_holdable_cursor()" call completes silently.

The first "cursor_rows()" invocation reports "series() invoked" once.

Subsequent "cursor_rows()" invocations produce their rows without that message.

* (2) call open_holdable_cursor(holdable=>false, filter_series=>true, 
caption=>'') *

The "open_holdable_cursor()" call completes silently again.

The first "cursor_rows()" invocation again reports "series() invoked" once. And 
then it reports "filter() invoked" ten times.

The second "cursor_rows()" invocation again does *not* report "series() 
invoked". But it *does* report "filter() invoked" ten times. This tells me that 
its the *unrestricted* results that are cached.

It's the same for the third invocation (and any more that I care to do).

*  (3) open_holdable_cursor(holdable=>true, filter_series=>false, caption=>'') *

The "open_holdable_cursor()" call now reports "series() invoked".

The first, and all subsequent, "cursor_rows()" invocations do not say "series() 
invoked".

* (4) open_holdable_cursor(holdable=>true, filter_series=>true, caption=>'') *

The "open_holdable_cursor()" call now reports "series() invoked" followed by 
"filter() invoked" ten times.

The first, and all subsequent, "cursor_rows()" invocations do not bring any 
"raise info" output because the *restricted* results are cached.

I hope that my question is clearer now.

Reply via email to