Appendix B: SQL Compatibility Reference
This appendix provides a comprehensive reference for SQL compatibility in Cognica, documenting supported statements, data types, operators, functions, and PostgreSQL compatibility features. Cognica implements a substantial subset of PostgreSQL SQL dialect, enabling compatibility with most PostgreSQL client applications and tools.
B.1 Statement Support Matrix
B.1.1 Data Query Language (DQL)
| Statement | Support | Notes |
|---|
| SELECT | Full | All standard clauses supported |
| FROM | Full | Tables, subqueries, joins, LATERAL |
| WHERE | Full | All predicates and subqueries |
| GROUP BY | Full | Including GROUPING SETS, CUBE, ROLLUP |
| HAVING | Full | Aggregate filtering |
| ORDER BY | Full | ASC/DESC, NULLS FIRST/LAST |
| LIMIT/OFFSET | Full | Row limiting, parameterized expressions |
| DISTINCT | Full | Including DISTINCT ON |
| UNION/INTERSECT/EXCEPT | Full | Set operations with ALL |
| WITH (CTE) | Full | Including WITH RECURSIVE |
| EXPLAIN | Full | ANALYZE, VERBOSE options |
SELECT Clause Features:
SELECT column1, column2 FROM table_name;
SELECT id, price * quantity AS total FROM orders;
SELECT DISTINCT category FROM products;
SELECT DISTINCT ON (department) employee_id, name, salary
FROM employees ORDER BY department, salary DESC;
SELECT name, (SELECT COUNT(*) FROM orders WHERE orders.customer_id = c.id)
FROM customers c;
SELECT id FROM users LIMIT $1 + 1 OFFSET $2;
B.1.2 Data Manipulation Language (DML)
| Statement | Support | Notes |
|---|
| INSERT | Full | VALUES, SELECT, RETURNING, ON CONFLICT |
| UPDATE | Full | SET, WHERE, RETURNING |
| DELETE | Full | WHERE, RETURNING |
| COPY | Full | Import/export operations |
| TRUNCATE | Full | Fast table emptying |
DML Examples:
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
INSERT INTO archive SELECT * FROM logs WHERE created_at < '2024-01-01';
INSERT INTO orders (product_id, quantity) VALUES (1, 5)
RETURNING id, created_at;
UPDATE products SET price = price * 1.1 WHERE category = 'electronics'
RETURNING id, name, price;
DELETE FROM sessions WHERE expires_at < NOW() RETURNING user_id;
INSERT INTO users (id, name, email) VALUES (1, 'Alice', 'alice@example.com')
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, email = EXCLUDED.email;
INSERT INTO tags (name) VALUES ('important')
ON CONFLICT (name) DO NOTHING;
COPY users TO '/tmp/users.csv' WITH (FORMAT CSV, HEADER);
COPY users FROM '/tmp/users.csv' WITH (FORMAT CSV, HEADER);
B.1.3 Data Definition Language (DDL)
| Statement | Support | Notes |
|---|
| CREATE TABLE | Full | All constraint types |
| DROP TABLE | Full | IF EXISTS, CASCADE |
| ALTER TABLE | Full | Add/drop columns, constraints |
| CREATE INDEX | Full | B-tree indexes |
| DROP INDEX | Full | IF EXISTS |
| CREATE VIEW | Full | Virtual tables |
| DROP VIEW | Full | IF EXISTS, CASCADE |
| CREATE MATERIALIZED VIEW | Full | Cached query results |
| REFRESH MATERIALIZED VIEW | Full | Update cached data |
| CREATE SEQUENCE | Full | Auto-increment values |
| ALTER SEQUENCE | Full | Modify sequence properties |
| CREATE TRIGGER | Full | Event-based actions |
| CREATE FUNCTION | Full | User-defined functions |
| CREATE PROCEDURE | Full | Stored procedures |
| CALL | Full | Procedure invocation |
| CREATE SCHEMA | Full | Namespace management |
| DROP SCHEMA | Full | IF EXISTS, CASCADE |
| ALTER SCHEMA | Full | RENAME TO |
| CREATE DATABASE | Full | Workspace-based isolation |
| DROP DATABASE | Full | IF EXISTS |
| CREATE TYPE | Partial | ENUM types supported |
DDL Examples:
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
customer_id BIGINT NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
total DECIMAL(10,2) CHECK (total >= 0),
status VARCHAR(20) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE (customer_id, created_at)
);
ALTER TABLE orders ADD COLUMN notes TEXT;
ALTER TABLE orders DROP COLUMN notes;
ALTER TABLE orders ALTER COLUMN status SET DEFAULT 'new';
ALTER TABLE orders ADD CONSTRAINT positive_total CHECK (total > 0);
ALTER TABLE orders RENAME COLUMN total TO order_total;
ALTER TABLE orders RENAME TO customer_orders;
CREATE INDEX idx_orders_customer ON orders(customer_id);
CREATE INDEX idx_orders_status ON orders(status) WHERE status != 'completed';
CREATE VIEW active_orders AS
SELECT * FROM orders WHERE status IN ('pending', 'processing');
CREATE MATERIALIZED VIEW monthly_sales AS
SELECT DATE_TRUNC('month', created_at) AS month,
SUM(total) AS revenue,
COUNT(*) AS order_count
FROM orders
GROUP BY DATE_TRUNC('month', created_at);
REFRESH MATERIALIZED VIEW monthly_sales;
CREATE SEQUENCE order_number_seq START 1000 INCREMENT 1;
CREATE TRIGGER update_timestamp
BEFORE UPDATE ON orders
FOR EACH ROW EXECUTE FUNCTION update_modified_column();
B.1.4 Transaction Control
| Statement | Support | Notes |
|---|
| BEGIN / START TRANSACTION | Full | Transaction start |
| COMMIT | Full | Persist changes |
| ROLLBACK | Full | Discard changes |
| SAVEPOINT | Full | Nested transactions |
| RELEASE SAVEPOINT | Full | Release savepoint |
| SET TRANSACTION | Full | Isolation levels |
| PREPARE TRANSACTION | Full | Two-phase commit |
Transaction Examples:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
BEGIN;
INSERT INTO orders (customer_id, total) VALUES (1, 500);
SAVEPOINT order_created;
INSERT INTO order_items (order_id, product_id) VALUES (currval('orders_id_seq'), 1);
ROLLBACK TO SAVEPOINT order_created;
INSERT INTO order_items (order_id, product_id) VALUES (currval('orders_id_seq'), 2);
COMMIT;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
COMMIT;
B.1.5 Access Control
| Statement | Support | Notes |
|---|
| CREATE ROLE | Full | User/role creation |
| ALTER ROLE | Full | Modify role properties |
| DROP ROLE | Full | Remove roles |
| GRANT | Full | Object and role privileges |
| REVOKE | Full | Remove privileges |
| CREATE POLICY | Full | Row-level security |
| ALTER POLICY | Full | Modify RLS policies |
| SET ROLE | Full | Switch active role |
Access Control Examples:
CREATE ROLE app_user WITH LOGIN PASSWORD 'secret';
GRANT SELECT, INSERT, UPDATE ON orders TO app_user;
GRANT USAGE ON SEQUENCE orders_id_seq TO app_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO admin;
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY orders_isolation ON orders
USING (customer_id = current_setting('app.current_customer')::BIGINT);
GRANT admin TO app_user;
B.2 Data Type Reference
B.2.1 Numeric Types
| SQL Type | Aliases | Internal Storage | Range |
|---|
| SMALLINT | INT2 | 64-bit integer | -32768 to 32767 |
| INTEGER | INT, INT4 | 64-bit integer | -2^31 to 2^31-1 |
| BIGINT | INT8 | 64-bit integer | -2^63 to 2^63-1 |
| REAL | FLOAT4 | 64-bit double | IEEE 754 single |
| DOUBLE PRECISION | FLOAT8, FLOAT | 64-bit double | IEEE 754 double |
| NUMERIC | DECIMAL | 64-bit double | Approximate |
| SERIAL | - | 64-bit integer | Auto-increment |
| BIGSERIAL | - | 64-bit integer | Auto-increment |
| SMALLSERIAL | - | 64-bit integer | Auto-increment |
| MONEY | - | 64-bit double | Currency values |
Numeric Type Notes:
- All integer types are stored as 64-bit integers internally for uniformity
- NUMERIC/DECIMAL are stored as double-precision floating point
- SERIAL types automatically create associated sequences
CREATE TABLE metrics (
id BIGSERIAL PRIMARY KEY,
count INTEGER NOT NULL DEFAULT 0,
rate DOUBLE PRECISION,
amount NUMERIC(10, 2)
);
B.2.2 Character Types
| SQL Type | Aliases | Internal Storage | Notes |
|---|
| TEXT | - | UTF-8 string | Unlimited length |
| VARCHAR(n) | CHARACTER VARYING | UTF-8 string | Length limit |
| CHAR(n) | CHARACTER | UTF-8 string | Fixed length |
| BPCHAR | - | UTF-8 string | Blank-padded |
| NAME | - | UTF-8 string | PostgreSQL identifier |
Character Type Notes:
- All character types stored as UTF-8 strings internally
- Length constraints enforced at input time
- CHAR pads with spaces to specified length
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT,
code CHAR(10)
);
B.2.3 Date/Time Types
| SQL Type | Aliases | Internal Storage | Precision |
|---|
| DATE | - | Date value | Day |
| TIME | - | Time value | Microsecond |
| TIMESTAMP | - | Timestamp | Microsecond |
| TIMESTAMPTZ | TIMESTAMP WITH TIME ZONE | UTC timestamp | Microsecond |
| TIMETZ | TIME WITH TIME ZONE | Time with zone | Microsecond |
| INTERVAL | - | Interval | Microsecond |
Date/Time Type Notes:
- TIMESTAMP WITHOUT TIME ZONE stores local time
- TIMESTAMPTZ stores UTC, converts on display
- INTERVAL supports year-month and day-time components
CREATE TABLE events (
id BIGSERIAL PRIMARY KEY,
event_date DATE NOT NULL,
start_time TIME,
created_at TIMESTAMPTZ DEFAULT NOW(),
duration INTERVAL
);
SELECT DATE '2024-01-15';
SELECT TIME '14:30:00';
SELECT TIMESTAMP '2024-01-15 14:30:00';
SELECT INTERVAL '2 hours 30 minutes';
B.2.4 Boolean Type
| SQL Type | Aliases | True Values | False Values |
|---|
| BOOLEAN | BOOL | TRUE, 't', 'true', 'y', 'yes', 'on', '1' | FALSE, 'f', 'false', 'n', 'no', 'off', '0' |
CREATE TABLE features (
name VARCHAR(100) PRIMARY KEY,
enabled BOOLEAN DEFAULT FALSE,
visible BOOLEAN DEFAULT TRUE
);
SELECT * FROM features WHERE enabled AND visible;
B.2.5 Binary Types
| SQL Type | Aliases | Internal Storage | Notes |
|---|
| BYTEA | BLOB | Base64 string | Binary data |
CREATE TABLE files (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255),
content BYTEA
);
INSERT INTO files (name, content) VALUES ('test', '\x48454C4C4F');
B.2.6 JSON Types
| SQL Type | Internal Storage | Operators | Notes |
|---|
| JSON | JSON string | ->, ->>, #>, #>> | Text JSON |
| JSONB | Binary JSON | All JSON + @>, <@, ?, ? | , ?& |
JSON Type Features:
- Full JSONPath support with @? and @@ operators
- JSONB indexing for efficient queries
- Nested object and array access
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
data JSONB NOT NULL,
metadata JSON
);
SELECT data->'name' FROM documents;
SELECT data->>'name' FROM documents;
SELECT data
SELECT * FROM documents WHERE data @> '{"active": true}';
SELECT * FROM documents WHERE data ? 'email';
SELECT * FROM documents WHERE data @@ '$.price > 100';
B.2.7 Special Types
| SQL Type | Internal Storage | Notes |
|---|
| UUID | String | 128-bit identifier |
| OID | 64-bit integer | Object identifier |
| ARRAY | JSON array | Multi-dimensional |
CREATE TABLE sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id BIGINT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE tags (
id BIGSERIAL PRIMARY KEY,
labels TEXT[] NOT NULL
);
B.2.8 ENUM Types
User-defined enumeration types with automatic vectorized analysis:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
CREATE TABLE journal (
id BIGSERIAL PRIMARY KEY,
entry_date DATE NOT NULL,
current_mood mood NOT NULL
);
SELECT * FROM journal WHERE current_mood > 'ok';
B.2.9 Range Types
PostgreSQL-compatible range types for representing intervals:
| SQL Type | Element Type | Description |
|---|
| INT4RANGE | INTEGER | Integer range |
| INT8RANGE | BIGINT | Big integer range |
| NUMRANGE | NUMERIC | Numeric range |
| TSRANGE | TIMESTAMP | Timestamp range |
| TSTZRANGE | TIMESTAMPTZ | Timestamptz range |
| DATERANGE | DATE | Date range |
CREATE TABLE reservations (
id BIGSERIAL PRIMARY KEY,
room_id INTEGER NOT NULL,
during TSRANGE NOT NULL,
EXCLUDE USING gist (room_id WITH =, during WITH &&)
);
SELECT * FROM reservations WHERE during @> NOW()::timestamp;
SELECT * FROM reservations WHERE during && '[2026-01-01, 2026-02-01)';
SELECT lower(during), upper(during) FROM reservations;
INSERT INTO tags (labels) VALUES (ARRAY['important', 'urgent']);
SELECT * FROM tags WHERE 'urgent' = ANY(labels);
B.3 Operator Reference
B.3.1 Arithmetic Operators
| Operator | Description | Example | Result |
|---|
| + | Addition | 2 + 3 | 5 |
| - | Subtraction | 5 - 2 | 3 |
| * | Multiplication | 3 * 4 | 12 |
| / | Division | 10 / 3 | 3 |
| % | Modulo | 10 % 3 | 1 |
| ^ | Power | 2 ^ 10 | 1024 |
B.3.2 Comparison Operators
| Operator | Description | Example |
|---|
| = | Equal | a = b |
| <> or != | Not equal | a <> b |
| < | Less than | a < b |
| > | Greater than | a > b |
| <= | Less than or equal | a <= b |
| >= | Greater than or equal | a >= b |
| IS NULL | Null test | a IS NULL |
| IS NOT NULL | Not null test | a IS NOT NULL |
| IS DISTINCT FROM | Null-safe inequality | a IS DISTINCT FROM b |
| IS NOT DISTINCT FROM | Null-safe equality | a IS NOT DISTINCT FROM b |
| BETWEEN | Range test | a BETWEEN x AND y |
| IN | Set membership | a IN (1, 2, 3) |
B.3.3 Logical Operators
| Operator | Description | Example |
|---|
| AND | Logical conjunction | a AND b |
| OR | Logical disjunction | a OR b |
| NOT | Logical negation | NOT a |
Three-Valued Logic:
| a | b | a AND b | a OR b | NOT a |
|---|
| TRUE | TRUE | TRUE | TRUE | FALSE |
| TRUE | FALSE | FALSE | TRUE | FALSE |
| TRUE | NULL | NULL | TRUE | FALSE |
| FALSE | FALSE | FALSE | FALSE | TRUE |
| FALSE | NULL | FALSE | NULL | TRUE |
| NULL | NULL | NULL | NULL | NULL |
B.3.4 Pattern Matching Operators
| Operator | Description | Case Sensitive | Example |
|---|
| LIKE | Pattern match | Yes | name LIKE 'A%' |
| NOT LIKE | Negated pattern match | Yes | name NOT LIKE 'A%' |
| ILIKE | Pattern match | No | name ILIKE 'a%' |
| NOT ILIKE | Negated pattern match | No | name NOT ILIKE 'a%' |
| SIMILAR TO | SQL regex | Yes | name SIMILAR TO 'A.*' |
| ~ | POSIX regex | Yes | name ~ '^A' |
| ~* | POSIX regex | No | name ~* '^a' |
| !~ | Negated POSIX regex | Yes | name !~ '^A' |
| !~* | Negated POSIX regex | No | name !~* '^a' |
Pattern Wildcards:
| Pattern | LIKE Meaning | Regex Meaning |
|---|
| % | Any string | N/A |
| _ | Any single character | N/A |
| . | Literal dot | Any character |
| .* | N/A | Any string |
| ^ | N/A | Start of string |
| $ | N/A | End of string |
B.3.5 String Operators
| Operator | Description | Example | Result |
|---|
| || | Concatenation | 'Hello' || ' ' || 'World' | 'Hello World' |
B.3.6 JSON/JSONB Operators
| Operator | Description | Example | Result Type |
|---|
| -> | Get JSON field | data->'name' | JSON |
| ->> | Get JSON field as text | data->>'name' | TEXT |
| #> | Get JSON at path | data#>'{a,b}' | JSON |
| #>> | Get JSON at path as text | data#>>'{a,b}' | TEXT |
| @> | Contains | data @> '{"a":1}' | BOOLEAN |
| <@ | Contained by | '{"a":1}' <@ data | BOOLEAN |
| ? | Key exists | data ? 'name' | BOOLEAN |
| ?| | Any key exists | data ?| ARRAY['a','b'] | BOOLEAN |
| ?& | All keys exist | data ?& ARRAY['a','b'] | BOOLEAN |
| || | Merge/concatenate | data1 || data2 | JSONB |
| - | Delete key | data - 'key' | JSONB |
| #- | Delete at path | data #- '{a,b}' | JSONB |
| @? | JSONPath exists | data @? '$.a' | BOOLEAN |
| @@ | JSONPath predicate | data @@ '$.price > 10' | BOOLEAN |
JSON Operator Examples:
SELECT data->'address'->>'city' FROM customers;
SELECT data
SELECT * FROM products WHERE specs @> '{"color": "red"}';
SELECT * FROM documents WHERE data ? 'email';
SELECT * FROM products WHERE data @@ '$.price < 100';
SELECT * FROM products WHERE data @? '$.reviews[*] ? (@.rating > 4)';
B.3.7 Array Operators
| Operator | Description | Example |
|---|
| = ANY(array) | Element in array | 5 = ANY(ARRAY[1,3,5]) |
| <> ALL(array) | Element not in array | 5 <> ALL(ARRAY[1,2,3]) |
| @> | Contains | ARRAY[1,2] @> ARRAY[1] |
| <@ | Contained by | ARRAY[1] <@ ARRAY[1,2] |
| && | Overlap | ARRAY[1,2] && ARRAY[2,3] |
| || | Concatenation | ARRAY[1,2] || ARRAY[3] |
B.3.8 Full-Text Search Operators
| Operator | Description | Example |
|---|
| @@ | Text search match | to_tsvector('text') @@ to_tsquery('word') |
B.4 Function Reference
B.4.1 Mathematical Functions
| Function | Description | Example | Result |
|---|
| abs(x) | Absolute value | abs(-5) | 5 |
| ceil(x) | Ceiling | ceil(4.2) | 5 |
| floor(x) | Floor | floor(4.8) | 4 |
| round(x) | Round to nearest | round(4.5) | 5 |
| round(x, n) | Round to n decimals | round(4.567, 2) | 4.57 |
| trunc(x) | Truncate to integer | trunc(4.9) | 4 |
| trunc(x, n) | Truncate to n decimals | trunc(4.567, 2) | 4.56 |
| mod(x, y) | Modulo | mod(10, 3) | 1 |
| power(x, y) | Exponentiation | power(2, 3) | 8 |
| sqrt(x) | Square root | sqrt(16) | 4 |
| cbrt(x) | Cube root | cbrt(27) | 3 |
| exp(x) | Exponential | exp(1) | 2.718... |
| ln(x) | Natural logarithm | ln(2.718) | 1 |
| log(x) | Base-10 logarithm | log(100) | 2 |
| log(b, x) | Logarithm base b | log(2, 8) | 3 |
| sign(x) | Sign (-1, 0, 1) | sign(-5) | -1 |
| random() | Random [0, 1) | random() | 0.xxx |
| rand() | Alias for random() | rand() | 0.xxx |
| e() | Euler's number | e() | 2.718... |
Trigonometric Functions:
| Function | Description |
|---|
| sin(x), cos(x), tan(x) | Trigonometric (radians) |
| asin(x), acos(x), atan(x) | Inverse trigonometric |
| atan2(y, x) | Two-argument arctangent |
| sinh(x), cosh(x), tanh(x) | Hyperbolic |
| sind(x), cosd(x), tand(x) | Trigonometric (degrees) |
| asind(x), acosd(x), atand(x) | Inverse trigonometric (degrees) |
| atan2d(y, x) | Two-argument arctangent (degrees) |
| cotd(x) | Cotangent (degrees) |
| degrees(x) | Radians to degrees |
| radians(x) | Degrees to radians |
| pi() | Pi constant |
B.4.2 String Functions
| Function | Description | Example | Result |
|---|
| length(s) | String length | length('hello') | 5 |
| char_length(s) | Character count | char_length('hello') | 5 |
| upper(s) | Uppercase | upper('Hello') | 'HELLO' |
| lower(s) | Lowercase | lower('Hello') | 'hello' |
| initcap(s) | Title case | initcap('hello world') | 'Hello World' |
| concat(s1, s2, ...) | Concatenate | concat('a', 'b', 'c') | 'abc' |
| concat_ws(sep, s1, s2) | Concatenate with separator | concat_ws('-', 'a', 'b') | 'a-b' |
| substring(s, start, len) | Extract substring | substring('hello', 2, 3) | 'ell' |
| substr(s, start, len) | Extract substring | substr('hello', 2, 3) | 'ell' |
| left(s, n) | Left n characters | left('hello', 2) | 'he' |
| right(s, n) | Right n characters | right('hello', 2) | 'lo' |
| trim(s) | Remove whitespace | trim(' hi ') | 'hi' |
| ltrim(s) | Left trim | ltrim(' hi') | 'hi' |
| rtrim(s) | Right trim | rtrim('hi ') | 'hi' |
| lpad(s, len, fill) | Left pad | lpad('hi', 5, '*') | '***hi' |
| rpad(s, len, fill) | Right pad | rpad('hi', 5, '*') | 'hi***' |
| replace(s, from, to) | Replace substring | replace('hello', 'l', 'L') | 'heLLo' |
| reverse(s) | Reverse string | reverse('hello') | 'olleh' |
| repeat(s, n) | Repeat string | repeat('ab', 3) | 'ababab' |
| position(sub IN s) | Find position | position('ll' IN 'hello') | 3 |
| strpos(s, sub) | Find position | strpos('hello', 'll') | 3 |
| split_part(s, del, n) | Split and get part | split_part('a-b-c', '-', 2) | 'b' |
| ascii(s) | ASCII code | ascii('A') | 65 |
| chr(n) | Character from code | chr(65) | 'A' |
| starts_with(s, prefix) | Prefix test | starts_with('hello', 'he') | true |
| ends_with(s, suffix) | Suffix test | ends_with('hello', 'lo') | true |
| md5(s) | MD5 hash | md5('hello') | '5d41402abc4b...' |
| encode(data, format) | Encode binary | encode('hello', 'base64') | 'aGVsbG8=' |
| decode(s, format) | Decode to binary | decode('aGVsbG8=', 'base64') | 'hello' |
| quote_ident(s) | Quote identifier | quote_ident('user') | '"user"' |
| quote_literal(s) | Quote literal | quote_literal('it''s') | '''it''s''' |
| quote_nullable(s) | Quote or NULL | quote_nullable(NULL) | 'NULL' |
| to_hex(n) | Integer to hex | to_hex(255) | 'ff' |
Function Aliases:
| Alias | Equivalent |
|---|
| toupper(s) | upper(s) |
| tolower(s) | lower(s) |
| split(s, del) | string_to_array(s, del) |
| len(s) | length(s) |
Regular Expression Functions:
| Function | Description | Example |
|---|
| regexp_match(s, pattern) | First match | regexp_match('abc123', '\d+') |
| regexp_matches(s, pattern, flags) | All matches | regexp_matches('a1b2', '\d', 'g') |
| regexp_replace(s, pattern, repl) | Replace matches | regexp_replace('abc', '[a-z]', 'X', 'g') |
| regexp_split_to_array(s, pattern) | Split to array | regexp_split_to_array('a1b2c', '\d') |
| regexp_split_to_table(s, pattern) | Split to rows | regexp_split_to_table('a1b2c', '\d') |
B.4.3 Date/Time Functions
| Function | Description | Example |
|---|
| now() | Current timestamp | now() |
| current_timestamp | Current timestamp | current_timestamp |
| current_date | Current date | current_date |
| current_time | Current time | current_time |
| transaction_timestamp() | Transaction start time | transaction_timestamp() |
| statement_timestamp() | Statement start time | statement_timestamp() |
| clock_timestamp() | Actual current time | clock_timestamp() |
| date_trunc(unit, ts) | Truncate to unit | date_trunc('month', now()) |
| extract(unit FROM ts) | Extract component | extract(year FROM now()) |
| date_part(unit, ts) | Extract component | date_part('month', now()) |
| age(ts1, ts2) | Interval between | age(now(), '2020-01-01') |
| age(ts) | Age from now | age('2020-01-01') |
| to_timestamp(epoch) | Unix timestamp to timestamp | to_timestamp(1700000000) |
| to_timestamp(s, fmt) | Parse timestamp | to_timestamp('2024-01-15', 'YYYY-MM-DD') |
| to_date(s, fmt) | Parse date | to_date('2024-01-15', 'YYYY-MM-DD') |
| to_char(ts, fmt) | Format timestamp | to_char(now(), 'YYYY-MM-DD HH24:MI') |
Extract/Date_Part Units:
| Unit | Description |
|---|
| year, month, day | Date components |
| hour, minute, second | Time components |
| millisecond, microsecond | Sub-second precision |
| dow | Day of week (0=Sunday) |
| doy | Day of year |
| week | ISO week number |
| quarter | Quarter (1-4) |
| epoch | Unix timestamp |
B.4.4 JSON Functions
| Function | Description |
|---|
| json_build_object(k1, v1, ...) | Build JSON object |
| json_build_array(v1, v2, ...) | Build JSON array |
| jsonb_build_object(k1, v1, ...) | Build JSONB object |
| jsonb_build_array(v1, v2, ...) | Build JSONB array |
| json_object(keys, values) | Build from arrays |
| json_array_length(json) | Array element count |
| jsonb_array_length(jsonb) | Array element count |
| json_typeof(json) | JSON value type |
| jsonb_typeof(jsonb) | JSONB value type |
| jsonb_pretty(jsonb) | Pretty-print JSONB |
| jsonb_strip_nulls(jsonb) | Remove null values |
| jsonb_set(jsonb, path, value) | Set value at path |
| jsonb_insert(jsonb, path, value) | Insert at path |
| jsonb_path_query(jsonb, path) | JSONPath query |
| jsonb_path_query_array(jsonb, path) | JSONPath to array |
| jsonb_path_query_first(jsonb, path) | First JSONPath match |
| jsonb_path_exists(jsonb, path) | JSONPath exists |
| jsonb_path_match(jsonb, path) | JSONPath predicate |
| jsonb_object_keys_array(jsonb) | Object keys as array |
| json_object_keys_array(json) | Object keys as array |
JSON Set-Returning Functions:
| Function | Description |
|---|
| json_each(json) | Key-value pairs |
| jsonb_each(jsonb) | Key-value pairs |
| json_each_text(json) | Key-text pairs |
| jsonb_each_text(jsonb) | Key-text pairs |
| json_array_elements(json) | Array elements |
| jsonb_array_elements(jsonb) | Array elements |
| json_array_elements_text(json) | Array elements as text |
| jsonb_array_elements_text(jsonb) | Array elements as text |
| jsonb_object_keys(jsonb) | Object keys |
| json_to_record(json) | JSON to record |
| jsonb_to_record(jsonb) | JSONB to record |
| json_to_recordset(json) | JSON array to records |
| jsonb_to_recordset(jsonb) | JSONB array to records |
B.4.5 Array Functions
| Function | Description | Example |
|---|
| array_length(arr, dim) | Array length | array_length(ARRAY[1,2,3], 1) |
| array_dims(arr) | Array dimensions | array_dims(ARRAY[[1,2],[3,4]]) |
| array_upper(arr, dim) | Upper bound | array_upper(ARRAY[1,2,3], 1) |
| array_lower(arr, dim) | Lower bound | array_lower(ARRAY[1,2,3], 1) |
| array_append(arr, elem) | Append element | array_append(ARRAY[1,2], 3) |
| array_prepend(elem, arr) | Prepend element | array_prepend(0, ARRAY[1,2]) |
| array_cat(arr1, arr2) | Concatenate | array_cat(ARRAY[1], ARRAY[2]) |
| array_remove(arr, elem) | Remove element | array_remove(ARRAY[1,2,2], 2) |
| array_replace(arr, from, to) | Replace elements | array_replace(ARRAY[1,2], 2, 3) |
| array_position(arr, elem) | Find position | array_position(ARRAY['a','b'], 'b') |
| array_positions(arr, elem) | Find all positions | array_positions(ARRAY[1,2,1], 1) |
| array_to_string(arr, del) | Join to string | array_to_string(ARRAY[1,2], ',') |
| string_to_array(s, del) | Split to array | string_to_array('a,b,c', ',') |
| unnest(arr) | Expand to rows | unnest(ARRAY[1,2,3]) |
B.4.6 Conditional Functions
| Function | Description | Example |
|---|
| COALESCE(v1, v2, ...) | First non-null | COALESCE(null, 'default') |
| NULLIF(v1, v2) | Null if equal | NULLIF(x, 0) |
| GREATEST(v1, v2, ...) | Maximum value | GREATEST(1, 2, 3) |
| LEAST(v1, v2, ...) | Minimum value | LEAST(1, 2, 3) |
| CASE | Conditional expression | See below |
CASE Expression:
SELECT CASE status
WHEN 'A' THEN 'Active'
WHEN 'I' THEN 'Inactive'
ELSE 'Unknown'
END FROM items;
SELECT CASE
WHEN price < 10 THEN 'Cheap'
WHEN price < 100 THEN 'Moderate'
ELSE 'Expensive'
END FROM products;
B.4.7 Type Conversion Functions
| Function | Description | Example |
|---|
| CAST(expr AS type) | Type conversion | CAST('123' AS INTEGER) |
| expr::type | Type conversion | '123'::INTEGER |
| to_char(num, fmt) | Number to string | to_char(123.45, '999.99') |
| to_number(s, fmt) | String to number | to_number('123.45', '999.99') |
B.4.8 System Functions
| Function | Description |
|---|
| current_user | Current user name |
| session_user | Session user name |
| current_database() | Current database name |
| current_schema() | Current schema name |
| current_schemas(bool) | Search path schemas |
| pg_typeof(expr) | Expression type |
| version() | Database version |
| gen_random_uuid() | Generate UUID |
| txid_current() | Current transaction ID |
B.4.9 Sequence Functions
| Function | Description |
|---|
| nextval(sequence) | Get and increment |
| currval(sequence) | Get current value |
| setval(sequence, value) | Set sequence value |
| lastval() | Last returned value |
B.5 Aggregate Functions
B.5.1 General-Purpose Aggregates
| Function | Description | NULL Handling |
|---|
| COUNT(*) | Row count | Counts all rows |
| COUNT(expr) | Non-null count | Ignores NULL |
| SUM(expr) | Sum of values | Ignores NULL |
| AVG(expr) | Average | Ignores NULL |
| MIN(expr) | Minimum value | Ignores NULL |
| MAX(expr) | Maximum value | Ignores NULL |
| ANY_VALUE(expr) | Any value from group | Returns non-NULL if available |
B.5.2 Statistical Aggregates
| Function | Description |
|---|
| STDDEV(expr) | Standard deviation (sample) |
| STDDEV_POP(expr) | Population standard deviation |
| STDDEV_SAMP(expr) | Sample standard deviation |
| VARIANCE(expr) | Variance (sample) |
| VAR_POP(expr) | Population variance |
| VAR_SAMP(expr) | Sample variance |
| CORR(y, x) | Correlation coefficient |
| COVAR_POP(y, x) | Population covariance |
| COVAR_SAMP(y, x) | Sample covariance |
B.5.3 Regression Aggregates
| Function | Description |
|---|
| REGR_SLOPE(y, x) | Slope of regression line |
| REGR_INTERCEPT(y, x) | Y-intercept |
| REGR_R2(y, x) | R-squared (coefficient of determination) |
| REGR_AVGX(y, x) | Average of X |
| REGR_AVGY(y, x) | Average of Y |
| REGR_COUNT(y, x) | Non-null pair count |
| REGR_SXX(y, x) | Sum of squares of X |
| REGR_SYY(y, x) | Sum of squares of Y |
| REGR_SXY(y, x) | Sum of products |
B.5.4 Ordered-Set Aggregates
| Function | Description |
|---|
| PERCENTILE_CONT(frac) WITHIN GROUP (ORDER BY col) | Continuous percentile |
| PERCENTILE_DISC(frac) WITHIN GROUP (ORDER BY col) | Discrete percentile |
| MODE() WITHIN GROUP (ORDER BY col) | Most frequent value |
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary)
FROM employees;
SELECT MODE() WITHIN GROUP (ORDER BY department)
FROM employees;
B.5.5 Hypothetical-Set Aggregates
| Function | Description |
|---|
| RANK(value) WITHIN GROUP (ORDER BY col) | Hypothetical rank |
| DENSE_RANK(value) WITHIN GROUP (ORDER BY col) | Hypothetical dense rank |
| PERCENT_RANK(value) WITHIN GROUP (ORDER BY col) | Hypothetical percent rank |
| CUME_DIST(value) WITHIN GROUP (ORDER BY col) | Hypothetical cumulative distribution |
B.5.6 String and Array Aggregates
| Function | Description |
|---|
| STRING_AGG(expr, delimiter) | Concatenate strings |
| STRING_AGG(expr, delimiter ORDER BY ...) | Ordered concatenation |
| ARRAY_AGG(expr) | Collect into array |
| ARRAY_AGG(expr ORDER BY ...) | Ordered array |
SELECT department, STRING_AGG(name, ', ' ORDER BY name)
FROM employees GROUP BY department;
SELECT customer_id, ARRAY_AGG(product_id ORDER BY order_date)
FROM orders GROUP BY customer_id;
B.5.7 JSON Aggregates
| Function | Description |
|---|
| JSON_AGG(expr) | Aggregate to JSON array |
| JSONB_AGG(expr) | Aggregate to JSONB array |
| JSON_AGG_STRICT(expr) | Aggregate, exclude NULL |
| JSONB_AGG_STRICT(expr) | Aggregate, exclude NULL |
| JSON_OBJECT_AGG(key, value) | Aggregate to JSON object |
| JSONB_OBJECT_AGG(key, value) | Aggregate to JSONB object |
B.5.8 Bitwise Aggregates
| Function | Description |
|---|
| BIT_AND(expr) | Bitwise AND |
| BIT_OR(expr) | Bitwise OR |
| BIT_XOR(expr) | Bitwise XOR |
| BOOL_AND(expr) | Logical AND |
| BOOL_OR(expr) | Logical OR |
B.5.9 Aggregate Modifiers
FILTER Clause:
SELECT
COUNT(*) AS total,
COUNT(*) FILTER (WHERE status = 'active') AS active_count,
SUM(amount) FILTER (WHERE type = 'credit') AS total_credits
FROM transactions;
DISTINCT in Aggregates:
SELECT COUNT(DISTINCT category) FROM products;
SELECT SUM(DISTINCT price) FROM products;
B.6 Window Functions
B.6.1 Ranking Functions
| Function | Description |
|---|
| ROW_NUMBER() | Sequential row number |
| RANK() | Rank with gaps |
| DENSE_RANK() | Rank without gaps |
| NTILE(n) | Divide into n buckets |
| PERCENT_RANK() | Relative rank (0-1) |
| CUME_DIST() | Cumulative distribution |
SELECT name, department, salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num,
RANK() OVER (ORDER BY salary DESC) AS rank,
DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank,
NTILE(4) OVER (ORDER BY salary DESC) AS quartile
FROM employees;
SELECT name, department, salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank
FROM employees;
B.6.2 Value Functions
| Function | Description |
|---|
| LAG(expr, offset, default) | Previous row value |
| LEAD(expr, offset, default) | Next row value |
| FIRST_VALUE(expr) | First value in frame |
| LAST_VALUE(expr) | Last value in frame |
| NTH_VALUE(expr, n) | Nth value in frame |
SELECT date, value,
LAG(value, 1, 0) OVER (ORDER BY date) AS prev_value,
LEAD(value, 1, 0) OVER (ORDER BY date) AS next_value,
value - LAG(value, 1, 0) OVER (ORDER BY date) AS change
FROM metrics;
SELECT date, category, value,
FIRST_VALUE(value) OVER w AS first_val,
LAST_VALUE(value) OVER w AS last_val
FROM sales
WINDOW w AS (PARTITION BY category ORDER BY date
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING);
B.6.3 Aggregate Window Functions
All standard aggregates can be used as window functions:
SELECT date, amount,
SUM(amount) OVER (ORDER BY date) AS running_total,
AVG(amount) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_avg
FROM transactions;
SELECT department, name, salary,
AVG(salary) OVER (PARTITION BY department) AS dept_avg,
salary - AVG(salary) OVER (PARTITION BY department) AS diff_from_avg
FROM employees;
B.6.4 Window Frame Specification
Frame Types:
| Type | Description |
|---|
| ROWS | Physical row offset |
| RANGE | Logical value range |
| GROUPS | Peer group offset |
Frame Bounds:
| Bound | Description |
|---|
| UNBOUNDED PRECEDING | Start of partition |
| n PRECEDING | n rows/values before |
| CURRENT ROW | Current row |
| n FOLLOWING | n rows/values after |
| UNBOUNDED FOLLOWING | End of partition |
Frame Exclusion:
| Option | Description |
|---|
| EXCLUDE CURRENT ROW | Exclude current row |
| EXCLUDE GROUP | Exclude current row's peers |
| EXCLUDE TIES | Exclude peers except current |
| EXCLUDE NO OTHERS | Include all (default) |
SELECT value,
SUM(value) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW),
SUM(value) OVER (ORDER BY value RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),
AVG(value) OVER (ORDER BY id ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
EXCLUDE CURRENT ROW)
FROM data;
B.6.5 Named Windows
SELECT name, department, salary,
RANK() OVER w AS rank,
SUM(salary) OVER w AS running_total,
AVG(salary) OVER w AS running_avg
FROM employees
WINDOW w AS (PARTITION BY department ORDER BY salary DESC);
B.7 Table-Valued Functions
B.7.1 Series Generation
SELECT * FROM generate_series(1, 10);
SELECT * FROM generate_series(1, 10, 2);
SELECT * FROM generate_series(10, 1, -1);
SELECT * FROM generate_series(
'2024-01-01'::timestamp,
'2024-01-07'::timestamp,
'1 day'::interval
);
B.7.2 Array Expansion
SELECT unnest(ARRAY[1, 2, 3]);
SELECT * FROM unnest(ARRAY['a', 'b', 'c']) WITH ORDINALITY AS t(value, idx);
B.7.3 JSON Expansion
SELECT * FROM jsonb_array_elements('[1, 2, 3]'::jsonb);
SELECT * FROM jsonb_array_elements_text('["a", "b", "c"]'::jsonb);
SELECT * FROM jsonb_each('{"a": 1, "b": 2}'::jsonb);
SELECT * FROM jsonb_each_text('{"a": "x", "b": "y"}'::jsonb);
SELECT * FROM jsonb_object_keys('{"a": 1, "b": 2}'::jsonb);
B.7.4 Regular Expression Expansion
SELECT * FROM regexp_matches('abc123def456', '\d+', 'g');
SELECT * FROM regexp_split_to_table('a1b2c3', '\d');
SELECT * FROM string_to_table('a,b,c', ',');
B.8 JOIN Support
B.8.1 Supported JOIN Types
| JOIN Type | Syntax |
|---|
| Inner Join | JOIN, INNER JOIN |
| Left Outer Join | LEFT JOIN, LEFT OUTER JOIN |
| Right Outer Join | RIGHT JOIN, RIGHT OUTER JOIN |
| Full Outer Join | FULL JOIN, FULL OUTER JOIN |
| Cross Join | CROSS JOIN |
| Natural Join | NATURAL JOIN |
| Semi Join | EXISTS subquery |
| Anti Join | NOT EXISTS subquery |
B.8.2 JOIN Syntax
SELECT * FROM orders o
JOIN customers c ON o.customer_id = c.id;
SELECT * FROM orders
JOIN customers USING (customer_id);
SELECT * FROM orders
NATURAL JOIN order_items;
SELECT o.id, c.name, p.name AS product
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id;
SELECT c.name, COALESCE(SUM(o.total), 0) AS total_orders
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
GROUP BY c.name;
B.8.3 LATERAL Joins
SELECT c.name, recent.order_date, recent.total
FROM customers c
LEFT JOIN LATERAL (
SELECT order_date, total
FROM orders
WHERE customer_id = c.id
ORDER BY order_date DESC
LIMIT 3
) recent ON true;
SELECT e.name, t.tag
FROM entities e
LEFT JOIN LATERAL unnest(e.tags) AS t(tag) ON true;
B.9 Subquery Support
B.9.1 Scalar Subqueries
SELECT name,
(SELECT COUNT(*) FROM orders WHERE customer_id = c.id) AS order_count
FROM customers c;
SELECT * FROM products
WHERE price > (SELECT AVG(price) FROM products);
B.9.2 Table Subqueries
SELECT dept, avg_salary
FROM (
SELECT department AS dept, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
) AS dept_stats
WHERE avg_salary > 50000;
SELECT * FROM (
SELECT id, name, salary
FROM employees
) AS e(emp_id, emp_name, emp_salary);
B.9.3 EXISTS and IN Subqueries
SELECT * FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
SELECT * FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
SELECT * FROM products
WHERE category_id IN (
SELECT id FROM categories WHERE active = true
);
SELECT e.name, e.salary,
(SELECT AVG(salary) FROM employees e2
WHERE e2.department = e.department) AS dept_avg
FROM employees e;
SELECT * FROM departments d
WHERE EXISTS (
SELECT 1 FROM employees e
WHERE e.department_id = d.id AND e.salary > 100000
);
B.10 Common Table Expressions (CTE)
B.10.1 Basic CTE
WITH active_customers AS (
SELECT * FROM customers WHERE status = 'active'
)
SELECT * FROM active_customers WHERE created_at > '2024-01-01';
WITH
active_customers AS (
SELECT * FROM customers WHERE status = 'active'
),
recent_orders AS (
SELECT * FROM orders WHERE order_date > CURRENT_DATE - INTERVAL '30 days'
)
SELECT c.name, COUNT(o.id) AS recent_order_count
FROM active_customers c
LEFT JOIN recent_orders o ON c.id = o.customer_id
GROUP BY c.name;
B.10.2 Recursive CTE
WITH RECURSIVE org_tree AS (
SELECT id, name, manager_id, 1 AS level
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.id, e.name, e.manager_id, t.level + 1
FROM employees e
JOIN org_tree t ON e.manager_id = t.id
)
SELECT * FROM org_tree ORDER BY level, name;
WITH RECURSIVE nums AS (
SELECT 1 AS n
UNION ALL
SELECT n + 1 FROM nums WHERE n < 100
)
SELECT * FROM nums;
B.10.3 CTE Materialization Hints
WITH active_users AS MATERIALIZED (
SELECT * FROM users WHERE active = true
)
SELECT * FROM active_users a1
JOIN active_users a2 ON a1.department = a2.department;
WITH user_stats AS NOT MATERIALIZED (
SELECT user_id, COUNT(*) AS cnt FROM events GROUP BY user_id
)
SELECT * FROM user_stats WHERE cnt > 10;
B.11 Set Operations
B.11.1 UNION
SELECT name FROM customers
UNION
SELECT name FROM suppliers;
SELECT name FROM customers
UNION ALL
SELECT name FROM suppliers;
B.11.2 INTERSECT
SELECT customer_id FROM orders_2023
INTERSECT
SELECT customer_id FROM orders_2024;
SELECT product_id FROM warehouse_a
INTERSECT ALL
SELECT product_id FROM warehouse_b;
B.11.3 EXCEPT
SELECT customer_id FROM all_customers
EXCEPT
SELECT customer_id FROM active_customers;
SELECT item_id FROM inventory
EXCEPT ALL
SELECT item_id FROM sold_items;
B.11.4 Combining Set Operations
(SELECT id FROM table_a
UNION
SELECT id FROM table_b)
INTERSECT
SELECT id FROM table_c
ORDER BY id;
B.12 GROUP BY Extensions
B.12.1 GROUPING SETS
SELECT region, product, SUM(sales)
FROM sales_data
GROUP BY GROUPING SETS (
(region, product),
(region),
(product),
()
);
B.12.2 ROLLUP
SELECT year, quarter, month, SUM(revenue)
FROM sales
GROUP BY ROLLUP (year, quarter, month);
B.12.3 CUBE
SELECT region, product, SUM(sales)
FROM sales_data
GROUP BY CUBE (region, product);
B.12.4 GROUPING Function
SELECT
CASE WHEN GROUPING(region) = 1 THEN 'All Regions' ELSE region END AS region,
CASE WHEN GROUPING(product) = 1 THEN 'All Products' ELSE product END AS product,
SUM(sales)
FROM sales_data
GROUP BY CUBE (region, product);
B.13 PostgreSQL System Catalog Compatibility
B.13.1 pg_catalog Tables
Cognica implements the following PostgreSQL system catalog tables:
| Table | Description |
|---|
| pg_class | Tables, indexes, sequences, views |
| pg_attribute | Table columns |
| pg_type | Data types |
| pg_namespace | Schemas |
| pg_proc | Functions, procedures, aggregates |
| pg_index | Index definitions |
| pg_constraint | Constraints |
| pg_roles | Roles/users |
| pg_trigger | Triggers |
| pg_views | View definitions |
| pg_matviews | Materialized views |
| pg_depend | Object dependencies |
| pg_description | Object comments |
| pg_sequence | Sequences |
| pg_aggregate | Aggregate functions |
| pg_operator | Operators |
| pg_tables | Table listing |
| pg_indexes | Index listing |
| pg_stat_user_tables | Table statistics |
| pg_statio_user_tables | I/O statistics |
| pg_stat_activity | Session activity |
| Table | Description |
|---|
| schemata | Schema information |
| tables | Table information |
| columns | Column information |
| views | View information |
| table_constraints | Constraint information |
| key_column_usage | Key columns |
| referential_constraints | Foreign key references |
| check_constraints | Check constraints |
| routines | Functions and procedures |
| parameters | Routine parameters |
| sequences | Sequence information |
| triggers | Trigger information |
B.13.3 System Catalog Queries
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public';
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'users';
SELECT tc.constraint_name, tc.table_name, kcu.column_name,
ccu.table_name AS foreign_table, ccu.column_name AS foreign_column
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu
ON tc.constraint_name = ccu.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY';
SELECT relname, n_live_tup, n_dead_tup
FROM pg_stat_user_tables;
B.14 EXPLAIN Output
B.14.1 Basic EXPLAIN
EXPLAIN SELECT * FROM orders WHERE customer_id = 123;
Output shows:
- Execution plan tree
- Estimated costs (startup and total)
- Estimated row counts
- Access methods used
B.14.2 EXPLAIN ANALYZE
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 123;
Additional information:
- Actual execution time
- Actual row counts
- Number of loops
- Memory usage
B.14.3 EXPLAIN VERBOSE
EXPLAIN VERBOSE SELECT * FROM orders WHERE customer_id = 123;
Additional details:
- Output column lists
- Schema-qualified names
- Detailed cost breakdown
B.15 Limitations and Differences
B.15.1 Features Not Supported
| Feature | Notes |
|---|
| Table Inheritance | PostgreSQL-specific feature |
| Domain Types | User-defined constrained types |
| Composite Types | As first-class storage |
| Large Objects | BYTEA supported, not true LO |
| Tablespaces | Catalog present, not enforced |
| Custom Operators | User-defined operators |
| Partitioning | Table partitioning |
| Constraint Triggers | Special trigger type |
B.15.2 Behavioral Differences
| Area | PostgreSQL | Cognica |
|---|
| NUMERIC precision | Arbitrary | Double precision |
| Integer types | Various sizes | All 64-bit internally |
| Array storage | Native | JSON representation |
| Default isolation | Read Committed | Snapshot |
| MVCC | Tuple-based | Document-based |
B.15.3 Extensions
Cognica includes features not in standard PostgreSQL:
| Feature | Description |
|---|
| Document queries | Native JSON document operations |
| Full-text search | Integrated FTS with BM25 and Bayesian BM25 |
| Vector search | HNSW-based similarity search with calibrated scoring |
| Hybrid search | Log-odds probabilistic fusion of text and vector signals |
| Graph queries | Property graph operations via table functions and Cypher |
| Cypher language | openCypher-compatible graph query language via cypher() |
| SSI | True SERIALIZABLE isolation via Serializable Snapshot Isolation |
B.16 Graph Query Support
Cognica provides property graph capabilities through two complementary interfaces: SQL table functions for programmatic graph operations, and the openCypher query language for declarative graph pattern matching.
B.16.1 Graph Table Functions
Graph operations are exposed as SQL table functions that can be composed with standard SQL clauses including JOINs, WHERE filters, and aggregations.
Graph Management:
| Function | Description |
|---|
| graph_create(name) | Create a new graph |
| graph_drop(name) | Drop an existing graph |
| graph_list() | List all graphs |
Node Operations:
| Function | Description |
|---|
| graph_create_node(graph, label, properties) | Create a node |
| graph_get_node(graph, node_id) | Get node by ID |
| graph_update_node(graph, node_id, properties) | Update node properties |
| graph_nodes(graph, label?, properties?) | Query nodes |
| graph_delete_node(graph, node_id) | Delete a node |
Edge Operations:
| Function | Description |
|---|
| graph_create_edge(graph, type, source, target, properties) | Create an edge |
| graph_get_edge(graph, edge_id) | Get edge by ID |
| graph_update_edge(graph, edge_id, properties) | Update edge properties |
| graph_edges(graph, node_id, type?, direction?) | Query edges |
| graph_delete_edge(graph, edge_id) | Delete an edge |
Traversal Functions:
| Function | Description |
|---|
| graph_traverse(graph, start, type?, direction?, depth?) | Traverse from a node |
| graph_neighbors(graph, node_id, type?, direction?, depth?) | Find neighbor nodes |
| graph_shortest_path(graph, start, end, type?, direction?) | Find shortest path |
Graph Table Function Examples:
SELECT * FROM graph_create('social');
SELECT * FROM graph_create_node('social', 'Person', '{"name": "Alice", "age": 30}');
SELECT * FROM graph_create_node('social', 'Person', '{"name": "Bob", "age": 25}');
SELECT * FROM graph_create_edge('social', 'KNOWS', 'alice_id', 'bob_id',
'{"since": 2024}');
SELECT * FROM graph_nodes('social', 'Person');
SELECT * FROM graph_update_node('social', 'alice_id', '{"age": 31}');
SELECT u.success FROM social_edges e
CROSS JOIN LATERAL graph_update_edge(
'social', e._id, '{"since": 2025}'
) AS u(success)
WHERE e._type = 'KNOWS';
SELECT * FROM graph_traverse('social', 'alice_id', 'KNOWS', 'outgoing', 3);
SELECT * FROM graph_shortest_path('social', 'alice_id', 'bob_id');
B.16.2 Cypher Query Language
Cognica supports the openCypher query language through the cypher() table function in FROM clauses. Cypher queries are transparently rewritten into optimized SQL subqueries at parse time, allowing full integration with the SQL query planner and optimizer.
Syntax:
SELECT <columns>
FROM cypher('<graph_name>', $$ <cypher_query> $$) AS (<column_definitions>)
Supported Cypher Clauses:
| Clause | Description |
|---|
| MATCH | Pattern matching on nodes and relationships |
| OPTIONAL MATCH | Pattern matching with NULL for unmatched patterns |
| WHERE | Filtering conditions |
| RETURN | Projection of results |
| ORDER BY | Result ordering |
| LIMIT / SKIP | Result pagination |
| CREATE | Create nodes and relationships |
| SET | Update properties and labels |
| REMOVE | Remove properties and labels |
| DELETE / DETACH DELETE | Delete nodes and relationships |
| MERGE | Match or create patterns |
| WITH | Query chaining and aggregation |
| UNWIND | Expand lists into rows |
| CALL { ... } | Subquery execution |
| FOREACH | Iterative updates |
Node Pattern Matching:
SELECT * FROM cypher('social', $$
MATCH (p:Person)
RETURN p.name AS name, p.age AS age
$$) AS (name text, age bigint);
SELECT * FROM cypher('social', $$
MATCH (p:Person {name: 'Alice'})
RETURN p.age AS age
$$) AS (age bigint);
Relationship Pattern Matching:
SELECT * FROM cypher('social', $$
MATCH (a:Person)-[r:KNOWS]->(b:Person)
RETURN a.name AS source, b.name AS target
$$) AS (source text, target text);
SELECT * FROM cypher('social', $$
MATCH (a:Person {name: 'Alice'})-[:KNOWS*1..3]->(b:Person)
RETURN b.name AS name
$$) AS (name text);
SELECT * FROM cypher('social', $$
MATCH p = (a:Person {name: 'Alice'})-[:KNOWS*1..3]->(b:Person)
RETURN nodes(p) AS path_nodes, relationships(p) AS path_edges,
length(p) AS hops
$$) AS (path_nodes jsonb, path_edges jsonb, hops bigint);
Graph Mutation:
SELECT * FROM cypher('social', $$
CREATE (p:Person {name: 'Carol', age: 28})
RETURN p.name AS name
$$) AS (name text);
SELECT * FROM cypher('social', $$
MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Carol'})
CREATE (a)-[:KNOWS {since: 2025}]->(b)
RETURN a.name AS source, b.name AS target
$$) AS (source text, target text);
SELECT * FROM cypher('social', $$
MATCH (p:Person {name: 'Alice'})
SET p.age = 31
RETURN p.name AS name, p.age AS age
$$) AS (name text, age bigint);
SELECT * FROM cypher('social', $$
MERGE (p:Person {name: 'Dave'})
ON CREATE SET p.age = 35
ON MATCH SET p.last_seen = timestamp()
RETURN p.name AS name
$$) AS (name text);
Cypher Functions:
| Function | Description |
|---|
| id(node_or_edge) | Get the internal ID |
| labels(node) | Get node labels |
| type(relationship) | Get relationship type |
| properties(node_or_edge) | Get all properties as JSON |
| start_id(relationship) | Get source node ID |
| end_id(relationship) | Get target node ID |
| startNode(relationship) | Get source node |
| endNode(relationship) | Get target node |
| nodes(path) | Get nodes from a path |
| relationships(path) | Get relationships from a path |
| length(path) | Get path length (hop count) |
| size(list) | List element count |
| head(list) | First element of a list |
| last(list) | Last element of a list |
| tail(list) | All elements except the first |
| range(start, end, step?) | Generate integer list |
| keys(map) | Get map keys |
| vertex_stats(node) | Node statistics (degree counts) |
| toBoolean(expr) | Convert to boolean |
| toFloat(expr) | Convert to float |
| toInteger(expr) | Convert to integer |
| toString(expr) | Convert to string |
| timestamp() | Current time in milliseconds |
Integration with SQL:
Cypher queries integrate naturally with SQL through the FROM clause, enabling hybrid queries that combine graph pattern matching with relational operations:
SELECT c.*, o.total
FROM cypher('social', $$
MATCH (p:Person)-[:LIVES_IN]->(c:City)
RETURN p.name AS person_name, c.name AS city
$$) AS c(person_name text, city text)
JOIN orders o ON o.customer_name = c.person_name;
WITH friends AS (
SELECT * FROM cypher('social', $$
MATCH (a:Person {name: 'Alice'})-[:KNOWS]->(f:Person)
RETURN f.name AS name
$$) AS (name text)
)
SELECT * FROM friends ORDER BY name;
B.17.1 SQL Standard Features
Cognica supports the following SQL standard features:
| Feature | SQL Standard |
|---|
| Basic SELECT | SQL-92 |
| Subqueries | SQL-92 |
| JOIN operations | SQL-92, SQL:1999 |
| Set operations | SQL-92 |
| GROUP BY, HAVING | SQL-92 |
| ORDER BY with NULLS | SQL:2003 |
| CTEs (WITH clause) | SQL:1999 |
| Recursive CTEs | SQL:1999 |
| Window functions | SQL:2003 |
| FILTER clause | SQL:2003 |
| GROUPING SETS | SQL:1999 |
| CUBE, ROLLUP | SQL:1999 |
| LATERAL joins | SQL:1999 |
| Ordered-set aggregates | SQL:2003 |
B.17.2 PostgreSQL Extensions
| Feature | PostgreSQL Version |
|---|
| DISTINCT ON | PostgreSQL |
| ILIKE operator | PostgreSQL |
| JSONB type | PostgreSQL 9.4+ |
| JSONPath | PostgreSQL 12+ |
| MATERIALIZED hints | PostgreSQL 12+ |
| Row-level security | PostgreSQL 9.5+ |
Summary
Cognica provides comprehensive SQL support compatible with PostgreSQL, enabling seamless migration of applications and queries. The implementation covers:
- Full DQL support: SELECT with all clauses, joins, subqueries, CTEs, parameterized LIMIT/OFFSET
- Complete DML: INSERT (with ON CONFLICT upsert), UPDATE, DELETE with RETURNING
- Extensive DDL: Tables, views, indexes (including partial), triggers, functions, schemas
- Transaction control: ACID compliance with isolation levels
- Rich function library: 200+ scalar, aggregate, and window functions
- PostgreSQL compatibility: System catalogs, operators, extensions
- Graph queries: Property graph operations via SQL table functions and openCypher language
Understanding these compatibility features enables developers to leverage existing PostgreSQL knowledge while taking advantage of Cognica's unique capabilities in document storage, full-text search, vector similarity operations, and graph query processing.