SPI_CURSOR_OPEN(3)

πŸ“¦ version 16.15, in opensuse-leap 16.0

πŸ’… SPI_CURSOR_OPEN(3) β€” ok bestie, let's talk cursors

Hey so this is the SPI_CURSOR_OPEN(3) page from the PostgreSQL 16.15 Documentation, and honestly? It's a good one. Let's go.


✨ NAME ✨

SPI_cursor_open β€” sets up a cursor using a statement you already made with SPI_prepare. That's it. That's the whole vibe.


πŸŽ€ SYNOPSIS πŸŽ€

Portal SPI_cursor_open(const char * name, SPIPlanPtr plan,
                       Datum * values, const char * nulls,
                       bool read_only)

🌸 DESCRIPTION 🌸

Okay so SPI_cursor_open sets up a cursor (internally, a portal β€” that's the secret name, iykyk) that will execute a statement prepared by SPI_prepare. All the parameters mean exactly the same thing as the corresponding parameters to SPI_execute_plan. Same energy, different function.

So why would you use a cursor instead of just executing the statement directly? Two reasons, and they're both lowkey iconic:

  1. The result rows can be retrieved a few at a time, which avoids memory overrun for queries that return many rows. Like, your query said "here's a million rows" and your RAM said "bestie no". The cursor fixes that.
  2. A portal can outlive the current C function β€” it can, in fact, live to the end of the current transaction. So returning the portal name to the C function's caller gives you a whole way of returning a row set as a result. Main character portal behaviour, fr fr.

And a little detail that matters: the passed-in parameter data will be copied into the cursor's portal, so you can free it while the cursor still exists. No dangling, no drama. πŸ’…


πŸ¦‹ ARGUMENTS πŸ¦‹

  • const char * name β€” the name for the portal, or NULL to let the system pick a name for you. Let the system choose, honestly, it's giving delegating queen.
  • SPIPlanPtr plan β€” the prepared statement (the thing SPI_prepare returned to you).
  • Datum * values β€” an array of actual parameter values. Must have the same length as the statement's number of arguments. No, you can't skip one. Yes, it has to match. ⭐
  • const char * nulls β€” an array describing which parameters are null. Also must have the same length as the statement's number of arguments. Matching set, periodt.

If nulls is NULL then SPI_cursor_open assumes that no parameters are null. Otherwise, each entry of the nulls array should be ' ' if the corresponding parameter value is non-null, or 'n' if the corresponding parameter value is null. (In that latter case, the actual value in the corresponding values entry doesn't matter β€” it's null, bestie, the value is in its flop era and we ignore it.) Note that nulls is not a text string, just an array: it does not need a '\0' terminator. Please don't add one, it's not that kind of array. 😭

  • bool read_only β€” true for read-only execution. Simple as that. 🫢

πŸ‘‘ RETURN VALUE πŸ‘‘

Pointer to the portal containing the cursor. 🌈

⚠️ Heads up: there is no error return convention. Any error will be reported via elog. So if something goes wrong, you're not getting a NULL back β€” you're getting an elog in your face. Plan accordingly. πŸ’€

🧚 sign-off 🧚

That's the page, bestie β€” brought to you by PostgreSQL 16.15, dated 2026. Go forth and open some cursors responsibly. πŸ’–βœ¨

πŸ“¦ where this page comes from