Home / Alt manpages / pg_updatedicts(8)

  • pg_updatedicts(8)
  • Admin command
  • linux

Rebuild PostgreSQL Search Dictionaries with pg_updatedicts

pg_updatedicts turns installed Hunspell or Myspell dictionaries into the UTF-8 files Debian's PostgreSQL uses for text search. Ten minutes, most of it verification.

It refreshes a shared cache and creates links for every installed PostgreSQL version. You will not usually run it by hand at all: postgresql-common's dpkg trigger normally fires it automatically whenever a Hunspell or MySpell dictionary is installed or upgraded. This guide is for the times you need to check that actually happened, or force it yourself.

Before you start

This is Debian's postgresql-common utility. On the machine used for these examples, the package version is 257build1.1 and the command lives at /usr/sbin/pg_updatedicts. The installed manpage is dated 9 August 2024, and the implementation quietly also searches /usr/share/hunspell, though the manpage still only describes the traditional /usr/share/myspell/dicts/ location.

You need root, because it writes below /var/cache/postgresql/dicts/ and /usr/share/postgresql/. It takes no dictionary name, no output directory, no options at all. The complete command is:

sudo /usr/sbin/pg_updatedicts

You will need a PostgreSQL package and at least one matching dictionary package installed before it has anything to build. It does not install dictionaries for you.

1. Check the inputs and PostgreSQL targets

First look at the source directories and the PostgreSQL text-search directories. Neither of these changes anything:

find /usr/share/hunspell /usr/share/myspell/dicts -maxdepth 1 \
  \( -name '*.aff' -o -name '*.dic' \) -type f -print 2>/dev/null
find /usr/share/postgresql -maxdepth 2 -type d -name tsearch_data -print 2>/dev/null

Each usable dictionary needs both files, say en_US.aff and en_US.dic. The script skips a symbolic-link .aff file, reports an error for an .aff with no matching .dic, and reports an error if the affix file has no SET encoding line. An absent source directory just means no dictionary package supplied it, not that PostgreSQL is broken.

Checkpoint

Note down the source file names and the PostgreSQL versions printed by both commands. You will compare these against the generated links later.

2. Run the rebuild as root

One run converts each accepted pair to UTF-8, using the locale name in lower case. The cache files end in .affix and .dict, not the input suffixes:

sudo /usr/sbin/pg_updatedicts

Normal output looks like this:

Building PostgreSQL dictionaries from installed myspell/hunspell packages...
  en_us
Removing obsolete dictionary files:

That en_us line is an example, not a promise it will show up on your machine. With no usable dictionaries at all, you still get the headings, just with nothing listed under them. A conversion failure prints to standard error and the incomplete output gets removed rather than left half-built.

Warning

This command synchronises, it does not just add. After processing the current inputs, it removes obsolete generated files from the cache and obsolete generated symbolic links from PostgreSQL's tsearch_data directories. Never hand-maintain files in those generated locations; put your source dictionary files in the package-managed directory instead, then rerun this to regenerate everything around them.

Check the cache first. Its contents are generated, so treat it as read-only:

sudo find /var/cache/postgresql/dicts -maxdepth 1 -type f \
  \( -name '*.affix' -o -name '*.dict' \) -printf '%f\n' | sort

Every accepted input pair should give you one .affix and one .dict file, both converted to UTF-8. A missing pair usually traces back to an absent source file, an affix file with no SET line, an unsupported encoding, or a write that failed silently.

Then check the links for each installed PostgreSQL version:

find /usr/share/postgresql -path '*/tsearch_data/*.affix' -o \
  -path '*/tsearch_data/*.dict' -type l -printf '%p -> %l\n' | sort

That one-liner's precedence is easy to misread, so use this clearer loop instead when you are actually diagnosing something:

while IFS= read -r dir; do
  printf '%s\n' "$dir"
  find "$dir" -maxdepth 1 -type l -printf '  %f -> %l\n' | sort
done < <(find /usr/share/postgresql -maxdepth 2 -type d \
  -name tsearch_data -print | sort)

Every link should point back into /var/cache/postgresql/dicts/. Existing non-symbolic files in a target directory get preserved rather than replaced, which protects anything you manage locally, but can also leave PostgreSQL quietly using an older file. Investigate any same-named regular file before you call the rebuild done.

pg_updatedicts makes dictionary files available to PostgreSQL; it does not create a text search configuration or touch a database. PostgreSQL configurations refer to the generated base name, so a fresh en_us.dict is just the file a text search dictionary definition can point at, depending on how you configure it.

Keep the two checks separate: confirm the files and links exist first, then test the actual database configuration with the relevant SQL commands. A successful rebuild alone proves nothing about whether your application is using the text search configuration you intended.

5. Diagnose and recover

If the command fails, read both output streams and check the paths before you touch any permissions. The useful checks:

sudo test -d /var/cache/postgresql/dicts && echo cache-present
namei -l /var/cache/postgresql/dicts
namei -l /usr/share/postgresql/16/tsearch_data

Swap in the version you actually got from step 1 instead of 16. Permission errors, unwritable filesystems and failed iconv conversions all need fixing at the source, never by hand-copying generated files or changing the PostgreSQL service configuration to compensate.

If a dictionary package was repaired, reinstalled or upgraded, just rerun sudo /usr/sbin/pg_updatedicts. That is the fix for a failed or incomplete generated state: it rebuilds from the current source files and recreates the links from scratch. If a source package was deliberately removed, rerunning also removes its generated cache files and links, which is exactly what should happen.

Done means

  • Expected .aff and .dic inputs found in a supported source directory.
  • pg_updatedicts completed without error for the dictionaries you actually need.
  • Cache contains matching UTF-8 .affix and .dict files.
  • Each PostgreSQL tsearch_data directory links to the right cache files.
  • SQL text search configuration tested separately, not assumed from a clean rebuild.