Pronto, encontrei a resposta. Aparentemente, eu preciso escapar da barra invertida na substituição. Além disso, preciso
E
-prefix e barras invertidas de escape duplo no padrão de pesquisa em versões mais antigas do postgres (8.3 no meu caso). O código final fica assim:regexp_replace('abc [def]', E'([\\[\\]\\(\\)\\\\\?\\|_%])', E'\\\\\\1', 'g')
Sim, parece horrível, mas funciona :)