Funkce rownum()

Z PostgreSQL
Přejít na: navigace, hledání

Číslování řádků je takový docela typický problém, který v PostgreSQL není uspokojivě vyřešený. Můžeme použít dočasné sekvence. Ty však musíme vytvářet a resetovat. Tomův návrh tímto neduhem netrpí. Je založený na tom, že každá funkce má pro každý výraz přiřazenou cache omezenou na dobu provádění dotazu. Obyčejně tato cache slouží pro uložení prováděcích plánů, oid funkcí, atd. Nicméně, jelikož toto řešení má daleko do ideálu, není funkce rownum() standardně k dispozici.

regression=# create function rownum() returns int as '/home/tgl/pgsql/rownum'
regression-# language c;
CREATE FUNCTION

regression=# select rownum(),* from int8_tbl;
 rownum |        q1        |        q2
--------+------------------+-------------------
      1 |              123 |               456
      2 |              123 |  4567890123456789
      3 | 4567890123456789 |               123
      4 | 4567890123456789 |  4567890123456789
      5 | 4567890123456789 | -4567890123456789
(5 rows)

Řazení probíhá až po vyhodnocení položek v SELECTu. Pokud se tato funkce objeví v SELECTu spolu s klauzulí ORDER BY, dopadne to špatně. Zapouzdřením SUBSELECTu do derivované tabulky už se funkce rownum bude vyhodnocovat až po vyhodnocení ORDER BY, a dostaneme očekávaný výsledek.

regression=# select rownum(),* from int8_tbl order by q2;
 rownum |        q1        |        q2
--------+------------------+-------------------
      5 | 4567890123456789 | -4567890123456789
      3 | 4567890123456789 |               123
      1 |              123 |               456
      2 |              123 |  4567890123456789
      4 | 4567890123456789 |  4567890123456789
(5 rows)

regression=# select rownum(),* from (select * from int8_tbl order by q2) ss;
 rownum |        q1        |        q2
--------+------------------+-------------------
      1 | 4567890123456789 | -4567890123456789
      2 | 4567890123456789 |               123
      3 |              123 |               456
      4 |              123 |  4567890123456789
      5 | 4567890123456789 |  4567890123456789
(5 rows)

Vlastní kód funkce:

#include "postgres.h"

#include "fmgr.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

Datum rownum(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(rownum);

Datum
rownum(PG_FUNCTION_ARGS)
{
       int32      *ptr;

       ptr = (int32 *) fcinfo->flinfo->fn_extra;
       if (ptr == NULL)
       {
               /* First time through for the current query: allocate storage */
               fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                                                                                   sizeof(int32));
               ptr = (int32 *) fcinfo->flinfo->fn_extra;
               /* ... and initialize counter */
               *ptr = 1;
       }
       else
               (*ptr)++;

   PG_RETURN_INT32(*ptr);
}