yegor256/pgtk

Pgtk::Stash caches non-deterministic queries (CURRENT_TIMESTAMP, RANDOM, etc.)

Open

#378 aperta il 6 giu 2026

Vedi su GitHub
 (1 commento) (0 reazioni) (0 assegnatari)Ruby (6 fork)github user discovery
bughelp wanted

Metriche repository

Star
 (8 star)
Metriche merge PR
 (Metriche PR in attesa)

Descrizione

Description

Pgtk::Stash#select skips caching only for queries containing NOW() (with spaces):

cache(pure, key, params, result, ret, tables, marks) unless pure.include?(" NOW() ")

This misses many other non-deterministic SQL functions, which get cached with incorrect (stale) results:

Expression Cached? Correct?
NOW() (with spaces) No Yes
CURRENT_TIMESTAMP Yes No — bug
CURRENT_DATE Yes No — bug
CURRENT_TIME Yes No — bug
LOCALTIMESTAMP Yes No — bug
RANDOM() Yes No — bug
GEN_RANDOM_UUID() Yes No — bug
CLOCK_TIMESTAMP() Yes No — bug
NOW() (no spaces: NOW()) Yes No — bug

The check is also whitespace-sensitive: SELECT NOW() is skipped, but SELECT NOW() with exactly no space before the paren passes through.

Impact

  • Queries using any non-deterministic function besides NOW() return stale cached data
  • Example: SELECT CURRENT_TIMESTAMP returns the same timestamp on every call
  • Example: SELECT RANDOM() FROM generate_series(1,10) returns the same values every call
  • The cache silently serves incorrect data with no indication of staleness

Suggested fix

Replace the single NOW() check with a regex covering the common non-deterministic expressions:

NONDETERMINISTIC = /\b(NOW|CURRENT_TIMESTAMP|CURRENT_DATE|CURRENT_TIME|LOCALTIMESTAMP|LOCALTIME|RANDOM|GEN_RANDOM_UUID|CLOCK_TIMESTAMP|TIMEZONE)\s*\(/i

def select(pure, params, result)
  # ...
  cache(pure, key, params, result, ret, tables, marks) unless pure.match?(NONDETERMINISTIC)
  # ...
end

Related previous work

This is a continuation of the same caching-correctness theme addressed in earlier issues:

  • #368 — Stash table_mod non-monotonic stamp
  • #364 — Stash skips invalidation for tables with underscores/digits
  • #336 — Stash persistently-stale empty SELECT

Unlike those issues (which were about cache invalidation), this one is about cache prevention — queries that should never be cached in the first place because they are non-deterministic by nature.

Guida contributor