pgsqlite provides comprehensive support for PostgreSQL array types, allowing you to store and query array data in SQLite databases using familiar PostgreSQL syntax.
PostgreSQL arrays are fully supported and stored as JSON in SQLite. Key features include:
- All base type arrays: Support for INTEGER[], TEXT[], BOOLEAN[], REAL[], and 30+ other array types
- Multi-dimensional arrays: Support for nested arrays like INTEGER[][] or TEXT[][][]
- Automatic validation: Array columns include JSON validation constraints
- PostgreSQL syntax: Both ARRAY[1,2,3] constructor and '{1,2,3}' literal formats
- Wire protocol support: Proper array type OIDs transmitted to clients
pgsqlite supports arrays for all major PostgreSQL types:
SMALLINT[]/INT2[]- Small integer arraysINTEGER[]/INT4[]- Integer arraysBIGINT[]/INT8[]- Big integer arraysREAL[]/FLOAT4[]- Single precision float arraysDOUBLE PRECISION[]/FLOAT8[]- Double precision float arraysNUMERIC[]/DECIMAL[]- Arbitrary precision number arrays
TEXT[]- Variable length text arraysVARCHAR[]- Variable length character arraysCHAR[]- Fixed length character arraysNAME[]- Name type arrays (63 byte strings)
BOOLEAN[]/BOOL[]- Boolean value arrays
DATE[]- Date arraysTIME[]- Time without timezone arraysTIMESTAMP[]- Timestamp without timezone arraysTIMESTAMPTZ[]- Timestamp with timezone arraysINTERVAL[]- Time interval arrays
BYTEA[]- Binary data arrays
UUID[]- UUID arraysJSON[]- JSON arraysJSONB[]- JSONB arraysINET[]- IPv4/IPv6 address arraysCIDR[]- Network address arraysMACADDR[]- MAC address arrays
CREATE TABLE example (
id SERIAL PRIMARY KEY,
tags TEXT[],
scores INTEGER[],
matrix INTEGER[][],
active_days BOOLEAN[7]
);-- Single-dimensional arrays
INSERT INTO example (tags, scores) VALUES
('{"red", "blue", "green"}', '{95, 87, 92}'),
('{"urgent", "bug"}', '{100}');
-- Empty arrays
INSERT INTO example (tags, scores) VALUES
('{}', '{}');
-- Arrays with NULL values
INSERT INTO example (tags, scores) VALUES
('{"first", NULL, "third"}', '{1, NULL, 3}');
-- Multi-dimensional arrays
INSERT INTO example (matrix) VALUES
('{{1,2,3}, {4,5,6}}'),
('{{{1,2}, {3,4}}, {{5,6}, {7,8}}}');-- Note: ARRAY constructor is converted to JSON internally
INSERT INTO example (scores) VALUES
(ARRAY[10, 20, 30]);-- Select all rows with non-empty arrays
SELECT * FROM example WHERE tags != '{}';
-- Select rows with NULL arrays
SELECT * FROM example WHERE scores IS NULL;
-- Array equality
SELECT * FROM example WHERE tags = '{"urgent", "bug"}';Since arrays are stored as JSON, you can use SQLite's JSON functions:
-- Get array length
SELECT id, json_array_length(scores) as num_scores
FROM example;
-- Extract array element (0-based index)
SELECT id, json_extract(tags, '$[0]') as first_tag
FROM example;
-- Extract multiple elements
SELECT id,
json_extract(scores, '$[0]') as first_score,
json_extract(scores, '$[1]') as second_score
FROM example;
-- Check if array contains a value (using JSON)
SELECT * FROM example
WHERE json_extract(tags, '$') LIKE '%urgent%';-- Create table with 2D array
CREATE TABLE matrices (
id INTEGER PRIMARY KEY,
data INTEGER[][]
);
-- Insert 2D array
INSERT INTO matrices (id, data) VALUES
(1, '{{1,2,3}, {4,5,6}, {7,8,9}}');
-- Access nested elements
SELECT json_extract(data, '$[0][0]') as top_left,
json_extract(data, '$[1][1]') as center
FROM matrices;Arrays are stored as JSON TEXT in SQLite with automatic validation:
- Storage format: JSON arrays preserve PostgreSQL array structure
- Type preservation: Numbers stay numbers, strings stay strings
- NULL handling: JSON null represents SQL NULL in arrays
- Validation: CHECK constraint ensures valid JSON using
json_valid()
Example of how arrays are stored:
- PostgreSQL:
'{1,2,3}'→ SQLite:'[1,2,3]' - PostgreSQL:
'{"a","b","c"}'→ SQLite:'["a","b","c"]' - PostgreSQL:
'{{1,2},{3,4}}'→ SQLite:'[[1,2],[3,4]]'
pgsqlite supports most PostgreSQL array operators and functions:
-
@>(contains): Check if array contains another arraySELECT * FROM products WHERE tags @> '["electronics"]';
-
<@(is contained by): Check if array is contained by anotherSELECT * FROM products WHERE '["laptop"]' <@ tags;
-
&&(overlap): Check if arrays have any elements in commonSELECT * FROM products WHERE tags && '["electronics", "books"]';
-
||(concatenation): Concatenate arraysSELECT tags || '["new-tag"]' FROM products;
-
array_length(array, dimension): Get array length for specified dimensionSELECT array_length(tags, 1) FROM products;
-
array_upper(array, dimension)/array_lower(array, dimension): Get array bounds (always 1-based)SELECT array_upper(scores, 1), array_lower(scores, 1) FROM example;
-
array_append(array, element)/array_prepend(element, array): Add elementsSELECT array_append(tags, 'new-tag') FROM products; SELECT array_prepend('first', tags) FROM products;
-
array_cat(array1, array2): Concatenate arrays (same as || operator)SELECT array_cat(tags, '["extra", "tags"]') FROM products;
-
array_remove(array, element): Remove all occurrences of an element-- Note: element must be JSON-encoded for now SELECT array_remove(tags, '"electronics"') FROM products;
-
array_replace(array, search, replace): Replace all occurrencesSELECT array_replace(tags, '"old"', '"new"') FROM products;
-
array_position(array, element)/array_positions(array, element): Find element positions (1-based)SELECT array_position(tags, '"electronics"') FROM products;
-
array_slice(array, start, end): Extract array sliceSELECT array_slice(tags, 2, 4) FROM products;
-
array_agg(expression): Aggregate values into an arraySELECT category, array_agg(name) FROM products GROUP BY category;
-
Subscript access: Access individual elements (1-based indexing)
SELECT tags[1] FROM products; -- First element
-
Array slicing: Extract a range of elements
SELECT tags[2:4] FROM products; -- Elements 2 through 4
-
value = ANY(array): Check if value equals any array elementSELECT * FROM products WHERE 'electronics' = ANY(tags);
-
value = ALL(array): Check if value satisfies condition for all elementsSELECT * FROM orders WHERE 100 < ALL(quantities);
The following features are not yet supported:
-
Advanced Array Functions:
unnest(array)- Set-returning function (requires table function support)array_aggwith ORDER BY or DISTINCT
-
Binary Protocol:
- Arrays are returned as JSON strings, not in PostgreSQL binary array format
- Clients expecting binary array encoding may have issues
-
Array Constructors:
- Limited ARRAY[...] constructor support (converted to JSON internally)
- Array input/output functions
Use SQLite's json_each() function:
-- PostgreSQL: SELECT unnest(tags) FROM example
-- pgsqlite workaround:
SELECT value FROM example, json_each(tags);-- Check if array contains a specific value
SELECT * FROM example
WHERE EXISTS (
SELECT 1 FROM json_each(tags)
WHERE value = 'urgent'
);Use SQLite's json_group_array():
-- PostgreSQL: SELECT array_agg(name) FROM users
-- pgsqlite workaround:
SELECT json_group_array(name) as names FROM users;- JSON Validation: Happens during INSERT/UPDATE operations
- No Indexing: Cannot create indexes on array elements
- Full Table Scans: Array content searches require scanning all rows
- Large Arrays: Very large arrays may impact performance
When migrating from PostgreSQL:
- Table definitions work without changes - array types are recognized
- INSERT statements work with PostgreSQL array literal syntax
- Simple queries comparing entire arrays work as expected
- Complex array operations need to be rewritten using JSON functions
- Consider performance implications for large arrays or complex queries
- Use appropriate array types for your data (INTEGER[] for numbers, TEXT[] for strings)
- Keep arrays reasonably sized - very large arrays impact performance
- Consider normalization for frequently queried array elements
- Use JSON functions for array manipulation rather than string operations
- Test with your data to ensure performance meets requirements
-- Create articles with tags
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
tags TEXT[]
);
-- Insert articles with tags
INSERT INTO articles (title, tags) VALUES
('PostgreSQL Arrays', '{"database", "postgresql", "arrays"}'),
('SQLite Tips', '{"database", "sqlite", "performance"}'),
('pgsqlite Guide', '{"database", "postgresql", "sqlite"}');
-- Find articles with specific tag
SELECT id, title
FROM articles
WHERE EXISTS (
SELECT 1 FROM json_each(tags)
WHERE value = 'postgresql'
);
-- Count tags per article
SELECT title, json_array_length(tags) as tag_count
FROM articles;
-- Get all unique tags (using json_each)
SELECT DISTINCT value as tag
FROM articles, json_each(tags)
ORDER BY tag;Array support is fully tested in pgsqlite's CI/CD pipeline:
- Integration tests in
test_queries.sql - Rust unit tests in
array_types_test.rs - Tested across all connection modes (TCP, Unix socket, with/without SSL)
- Automatic migration creates necessary metadata tables