DEV Community

umzzil nng
umzzil nng

Posted on • Originally published at oraerror.com

PostgreSQL 2200B Error: Causes and Solutions Complete Guide

PostgreSQL Error 2200B: escape_character_conflict

PostgreSQL error 2200B (escape_character_conflict) occurs when the escape character specified in a LIKE or SIMILAR TO clause conflicts with the wildcard characters (% or _) used in pattern matching. This error is thrown when PostgreSQL detects that the designated escape character is ambiguous or violates SQL standard rules, making it impossible to correctly interpret the pattern. It commonly surfaces in applications that dynamically build search queries or process user-supplied input.


Top 3 Causes

1. Using a Wildcard Character as the ESCAPE Character

Specifying % or _ as the escape character directly conflicts with their reserved roles in pattern matching.

-- ❌ Bad: using wildcard '%' as escape character
SELECT * FROM products
WHERE product_code LIKE '50%_off' ESCAPE '%';
-- ERROR: 2200B escape_character_conflict

-- ✅ Fix: use a neutral character like '!' or '\'
SELECT * FROM products
WHERE product_code LIKE '50!%!_off' ESCAPE '!';
-- Matches literal string '50%_off'

-- ✅ Alternative with backslash
SELECT * FROM products
WHERE product_code LIKE '50\%\_off' ESCAPE '\';
Enter fullscreen mode Exit fullscreen mode

2. Specifying a Multi-Character Escape String

The ESCAPE clause strictly requires a single character. Passing a two-or-more character string causes PostgreSQL to raise this error.

-- ❌ Bad: multi-character escape string
SELECT * FROM orders
WHERE note LIKE '%discount!!%' ESCAPE '!!';
-- ERROR: 2200B - escape string must be a single character

-- ✅ Fix: use exactly one character
SELECT * FROM orders
WHERE note LIKE '%discount\!%' ESCAPE '\';

-- ✅ Safe dynamic pattern building in PL/pgSQL
DO $$
DECLARE
    v_esc  CHAR(1) := '!';   -- strictly typed as single char
    v_pat  TEXT;
BEGIN
    v_pat := '%'
          || replace(replace('50%_off', '%', '!%'), '_', '!_')
          || '%';
    RAISE NOTICE 'Pattern: %', v_pat;  -- outputs: %50!%!_off%
END;
$$;
Enter fullscreen mode Exit fullscreen mode

3. Escape Character Conflicts in SIMILAR TO

SIMILAR TO supports SQL-standard regex syntax, where characters like |, *, (, ) carry special meaning. Using one of these as the escape character causes a conflict.

-- ❌ Bad: using regex meta-character '|' as escape
SELECT * FROM event_logs
WHERE message SIMILAR TO '%(error|warning)%' ESCAPE '|';
-- ERROR: 2200B escape_character_conflict

-- ✅ Fix: use a neutral escape character
SELECT * FROM event_logs
WHERE message SIMILAR TO '%(error|warning)%' ESCAPE '\';

-- ✅ Better: use PostgreSQL native regex operator instead
SELECT * FROM event_logs
WHERE message ~ 'error|warning';

-- ✅ Case-insensitive regex match
SELECT * FROM event_logs
WHERE message ~* 'error|warning';
Enter fullscreen mode Exit fullscreen mode

Quick Fix Solutions

  • Always use neutral characters such as !, #, or \ for the ESCAPE clause.
  • Validate escape input before injecting it into dynamic SQL.
  • Prefer ~ or ~* (PostgreSQL regex operators) over SIMILAR TO for complex patterns — they are more flexible and avoid this class of errors entirely.
-- Reusable safe pattern helper function
CREATE OR REPLACE FUNCTION safe_like_pattern(p_input TEXT, p_esc CHAR(1) DEFAULT '!')
RETURNS TEXT LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
    IF p_esc IN ('%', '_') THEN
        RAISE EXCEPTION 'Escape char cannot be a wildcard (2200B)';
    END IF;
    RETURN '%'
        || replace(replace(
               replace(p_input, p_esc::TEXT, p_esc::TEXT || p_esc::TEXT),
           '%', p_esc::TEXT || '%'), '_', p_esc::TEXT || '_')
        || '%';
END;
$$;

-- Usage
SELECT * FROM products
WHERE name LIKE safe_like_pattern('50%_off') ESCAPE '!';
Enter fullscreen mode Exit fullscreen mode

Prevention Tips

  • Standardize escape characters across your codebase — pick one (e.g., !) and enforce it through shared utility functions or ORM-level abstractions. Never let developers use % or _ as escape characters.
  • Use parameterized queries and server-side escaping together — never interpolate raw user input into a LIKE pattern. Combine prepared statements with a sanitization function like safe_like_pattern() above to prevent both SQL injection and escape conflicts simultaneously.

Related Errors

Code Name Description
22025 invalid_escape_sequence Escape character followed by an invalid character in the pattern
2201B invalid_regular_expression Malformed regex syntax in SIMILAR TO or regexp_* functions
22000 data_exception Parent error class for 2200B; can be caught as a broader handler

📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.

Top comments (0)