Обсуждение: Unpredicatable behavior of volatile functions used in cursors

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

Unpredicatable behavior of volatile functions used in cursors

От
Aleksander Kmetec
Дата:
Hi,

I'm running into some inconsistent behavior when using volatile functions with cursors under PG 8.1.

We're using the following technique for counting the number of rows in a cursor:

-----------
DECLARE instance_cur_1 SCROLL CURSOR FOR
SELECT util.row_number(), *
FROM (
    $LONG_RUNNING_QUERY
) ss

FETCH LAST IN instance_cur_1;
-----------

util.row_number() is a volatile function written in C which simply returns "++internal_counter" every time it is
called.

What's unusual is that for some queries FETCH LAST returns a row_number value which matches the actual number of rows,
while for others it returns the actual number +1 (and adds +1 for each consecutive call). It seems that under some
conditions util.row_number() gets re-evaluated for every call.

Could someone explain why and under which conditions this happens?
Is there a way to make this behavior more consistent?

Regards,
Aleksander

Re: Unpredicatable behavior of volatile functions used in cursors

От
Tom Lane
Дата:
Aleksander Kmetec <aleksander.kmetec@intera.si> writes:
> We're using the following technique for counting the number of rows in a cursor:
> DECLARE instance_cur_1 SCROLL CURSOR FOR
> SELECT util.row_number(), *
> FROM (
>     $LONG_RUNNING_QUERY
> ) ss
> FETCH LAST IN instance_cur_1;

> util.row_number() is a volatile function written in C which simply returns "++internal_counter" every time it is
called.

This isn't gonna work very well if your query involves sorting, because
the SELECT-list is evaluated before the sort step ...

            regards, tom lane

Re: Unpredicatable behavior of volatile functions used

От
Aleksander Kmetec
Дата:
Tom Lane wrote:
> This isn't gonna work very well if your query involves sorting, because
> the SELECT-list is evaluated before the sort step ...
>
>             regards, tom lane
>

Thanks, this seems to solve my problem.

Some quick testing shows that util.row_number() only gets re-evaluated at every call if the subquery contains an ORDER
BY clause. Now we can predict whether we need to compensate for that just by looking at the original query.

Regards,
Aleksander

Re: Unpredicatable behavior of volatile functions used

От
Tom Lane
Дата:
Aleksander Kmetec <aleksander.kmetec@intera.si> writes:
> Some quick testing shows that util.row_number() only gets re-evaluated at every call if the subquery contains an
ORDER 
> BY clause. Now we can predict whether we need to compensate for that just by looking at the original query.

If you're going to use a cursor, I don't understand why you don't just
MOVE FORWARD ALL and look at the returned rowcount to determine how
many rows in the query.  This won't be any more expensive than fetching
the last row ...

            regards, tom lane

Re: Unpredicatable behavior of volatile functions used

От
Aleksander Kmetec
Дата:
Tom Lane wrote:
> Aleksander Kmetec <aleksander.kmetec@intera.si> writes:
>> Some quick testing shows that util.row_number() only gets re-evaluated at every call if the subquery contains an
ORDER 
>> BY clause. Now we can predict whether we need to compensate for that just by looking at the original query.
>
> If you're going to use a cursor, I don't understand why you don't just
> MOVE FORWARD ALL and look at the returned rowcount to determine how
> many rows in the query.  This won't be any more expensive than fetching
> the last row ...

That's a very good question...

It's more than a year now since I originally wrote that code, and I remember testing MOVE FORWARD ALL, but being unable

to get my hands on the row count for that operation. At that time I just accepted it as the way things work and created

that row_number() workaround instead.

But after your last message I went to investigate why that had happened in the first place. And sure enough, there was
a 
bug in the 3rd party database library we're using. After a quick fix everything is working as it should and I can
remove 
  row_number() altogether.

Thank you for your patience. :-)

Aleksander