Skip to content

HeliosDB Data Types Reference

HeliosDB Data Types Reference

Last Updated: November 1, 2025 Version: v6.0 Phase 2 M1

Complete reference for all data types supported by HeliosDB.


Table of Contents

  1. Numeric Types
  2. String Types
  3. Date/Time Types
  4. Boolean Type
  5. Binary Types
  6. JSON Types
  7. Array Types
  8. UUID Type
  9. Vector Types
  10. Spatial Types
  11. Network Address Types
  12. Custom Types

Numeric Types

Integer Types

TypeStorageRangeUse Case
SMALLINT2 bytes-32,768 to 32,767Small counters
INTEGER / INT4 bytes-2,147,483,648 to 2,147,483,647Default integer
BIGINT8 bytes-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807Large numbers
SERIAL4 bytesAuto-increment integerPrimary keys
BIGSERIAL8 bytesAuto-increment bigintLarge table PKs
CREATE TABLE products (
id SERIAL PRIMARY KEY,
category_id INT,
stock_count SMALLINT,
views BIGINT
);

Decimal Types

TypeStoragePrecisionUse Case
DECIMAL(p,s) / NUMERIC(p,s)VariableUser-definedExact decimal (money)
REAL / FLOAT44 bytes6 decimal digitsApproximate
DOUBLE PRECISION / FLOAT88 bytes15 decimal digitsScientific
CREATE TABLE financial (
price DECIMAL(10, 2), -- $99,999,999.99
exchange_rate DECIMAL(18, 8), -- Precise rates
temperature REAL, -- Approximate
scientific_value DOUBLE PRECISION
);

Important: Use DECIMAL for money to avoid floating-point errors!

-- CORRECT
SELECT 0.1::DECIMAL + 0.2::DECIMAL; -- Exactly 0.3
-- ❌ WRONG
SELECT 0.1::REAL + 0.2::REAL; -- 0.30000001 (floating-point error)

String Types

Character Types

TypeDescriptionMax SizeUse Case
VARCHAR(n)Variable-lengthn charsGeneral text
CHAR(n)Fixed-length (padded)n charsFixed codes
TEXTUnlimited variable1 GBLarge text
CREATE TABLE users (
username VARCHAR(50), -- Max 50 chars
country_code CHAR(2), -- Always 2 chars (US, UK)
bio TEXT -- Unlimited
);

Best Practices:

  • Use VARCHAR(n) when you have a length limit
  • Use TEXT when length is unknown or unlimited
  • Avoid CHAR(n) unless truly fixed-length (codes, hashes)

Text Search Types

CREATE TABLE documents (
content TEXT,
content_tsv TSVECTOR -- Full-text search vector
);
-- Create index for fast search
CREATE INDEX idx_content_fts ON documents USING GIN(content_tsv);

Date/Time Types

TypeStorageResolutionRangeUse Case
DATE4 bytes1 day4713 BC - 5874897 ADBirthdates
TIME8 bytes1 microsecond00:00:00 - 24:00:00Time of day
TIMESTAMP8 bytes1 microsecond4713 BC - 294276 ADEvent time (no TZ)
TIMESTAMPTZ8 bytes1 microsecond4713 BC - 294276 ADEvent time (with TZ)
INTERVAL16 bytes1 microsecond+/- 178,000,000 yearsDurations
CREATE TABLE events (
event_date DATE, -- 2025-11-01
event_time TIME, -- 14:30:00
created_at TIMESTAMP, -- 2025-11-01 14:30:00 (no timezone)
updated_at TIMESTAMPTZ -- 2025-11-01 14:30:00+00 (with timezone)
);

Best Practice: Always use TIMESTAMPTZ instead of TIMESTAMP for timestamps!

Date/Time Functions

-- Current date/time
SELECT NOW(); -- 2025-11-01 14:30:00+00
SELECT CURRENT_DATE; -- 2025-11-01
SELECT CURRENT_TIME; -- 14:30:00+00
SELECT CURRENT_TIMESTAMP; -- 2025-11-01 14:30:00+00
-- Date arithmetic
SELECT NOW() + INTERVAL '7 days';
SELECT NOW() - INTERVAL '1 month';
SELECT NOW() + INTERVAL '2 hours 30 minutes';
-- Extract parts
SELECT EXTRACT(YEAR FROM NOW());
SELECT EXTRACT(MONTH FROM NOW());
SELECT EXTRACT(DAY FROM NOW());
SELECT EXTRACT(HOUR FROM NOW());
-- Date truncation
SELECT DATE_TRUNC('day', NOW()); -- Start of today
SELECT DATE_TRUNC('month', NOW()); -- Start of month
SELECT DATE_TRUNC('hour', NOW()); -- Start of hour
-- Age calculation
SELECT AGE(NOW(), '1990-01-15'::DATE); -- 35 years 9 mons 17 days

Boolean Type

TypeStorageValuesUse Case
BOOLEAN / BOOL1 byteTRUE, FALSE, NULLFlags
CREATE TABLE users (
is_active BOOLEAN DEFAULT TRUE,
is_verified BOOLEAN DEFAULT FALSE,
is_admin BOOLEAN
);
-- Query
SELECT * FROM users WHERE is_active = TRUE;
SELECT * FROM users WHERE is_admin; -- Same as = TRUE
SELECT * FROM users WHERE NOT is_banned;

Boolean literals:

  • TRUE: TRUE, 't', 'true', 'y', 'yes', 'on', '1'
  • FALSE: FALSE, 'f', 'false', 'n', 'no', 'off', '0'

Binary Types

TypeMax SizeUse Case
BYTEA1 GBBinary data, images, files
CREATE TABLE files (
filename VARCHAR(255),
content BYTEA,
content_hash BYTEA -- SHA-256 hash
);
-- Insert binary data
INSERT INTO files (filename, content) VALUES
('logo.png', '\xDEADBEEF'::BYTEA);
-- Or from file
INSERT INTO files (filename, content) VALUES
('logo.png', pg_read_binary_file('/path/to/logo.png'));

Better Practice: Store large files in object storage (S3, Azure Blob) and store URL in database:

CREATE TABLE files (
filename VARCHAR(255),
s3_url TEXT,
size_bytes BIGINT
);

JSON Types

TypeStorageIndexedUse Case
JSONVariableNoSlow, exact storage
JSONBVariableYesFast, recommended

Always use JSONB unless you need to preserve exact JSON formatting.

CREATE TABLE users (
id SERIAL PRIMARY KEY,
profile JSONB
);
-- Insert JSON
INSERT INTO users (profile) VALUES
('{"name": "Alice", "age": 30, "tags": ["developer", "rust"]}');
-- Query JSON
SELECT profile->>'name' AS name FROM users;
SELECT * FROM users WHERE profile->>'role' = 'admin';
SELECT * FROM users WHERE profile @> '{"verified": true}';
-- Create index for fast queries
CREATE INDEX idx_profile ON users USING GIN(profile);
-- Update JSON
UPDATE users
SET profile = profile || '{"verified": true}'
WHERE id = 1;

JSON Operators

OperatorDescriptionExample
->Get JSON field (as JSON)profile->'address'
->>Get JSON field (as text)profile->>'name'
@>Containsprofile @> '{"verified": true}'
<@Contained by'{"a":1}' <@ profile
?Key existsprofile ? 'premium'
`?`Any key exists
?&All keys existprofile ?& array['a','b']

Array Types

Any type can be an array by adding []:

CREATE TABLE posts (
id SERIAL PRIMARY KEY,
tags TEXT[], -- Array of strings
ratings INTEGER[], -- Array of integers
locations POINT[] -- Array of points
);
-- Insert arrays
INSERT INTO posts (tags, ratings) VALUES
(ARRAY['rust', 'database'], ARRAY[5, 4, 5]);
-- Alternative syntax
INSERT INTO posts (tags) VALUES
('{rust,database,tutorial}');
-- Query arrays
SELECT * FROM posts WHERE 'rust' = ANY(tags);
SELECT * FROM posts WHERE tags && ARRAY['rust', 'python'];
SELECT * FROM posts WHERE tags @> ARRAY['rust'];
-- Array functions
SELECT array_length(tags, 1) FROM posts;
SELECT unnest(tags) FROM posts; -- Expand to rows

UUID Type

TypeStorageFormatUse Case
UUID16 bytesxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxDistributed PKs
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Insert with auto-generated UUID
INSERT INTO orders (user_id) VALUES ('550e8400-e29b-41d4-a716-446655440000');
-- Query
SELECT * FROM orders WHERE id = '550e8400-e29b-41d4-a716-446655440000'::UUID;

When to use UUID vs SERIAL:

  • UUID: Distributed systems, public APIs, privacy
  • SERIAL: Single database, internal PKs, better performance

Vector Types

TypeDescriptionDimensionsUse Case
VECTOR(n)Dense embedding1-4096Semantic search
SPARSEVEC(n)Sparse vectorUp to 65535Keyword search
-- Enable vector extension
CREATE EXTENSION IF NOT EXISTS helios_vector;
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
embedding VECTOR(768), -- 768-dimensional dense vector
keywords SPARSEVEC(10000) -- Sparse keyword vector
);
-- Insert vectors
INSERT INTO products (name, embedding) VALUES
('Laptop', '[0.1, 0.2, 0.3, ...]'::VECTOR(768));
-- Find similar products (cosine similarity)
SELECT
name,
embedding <=> query_vector AS distance
FROM products
ORDER BY distance
LIMIT 10;
-- Create HNSW index for fast search
CREATE INDEX idx_products_embedding ON products
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

See Vector Search Guide.


Spatial Types

TypeDescriptionUse Case
POINT2D point (x, y)Locations
LINEInfinite lineGeometry
LSEGLine segmentRoutes
BOXRectangleBounding boxes
PATHOpen/closed pathPolygons
POLYGONClosed shapeRegions
CIRCLECircleRadius search
CREATE TABLE locations (
name VARCHAR(100),
location POINT,
region POLYGON
);
-- Insert spatial data
INSERT INTO locations (name, location) VALUES
('Office', '(37.7749, -122.4194)'); -- San Francisco
-- Distance queries
SELECT
name,
location <-> '(37.7749, -122.4194)'::POINT AS distance
FROM locations
ORDER BY distance
LIMIT 10;

For advanced GIS: Use PostGIS extension (fully compatible with HeliosDB):

CREATE EXTENSION postgis;
CREATE TABLE places (
name VARCHAR(100),
geom GEOMETRY(Point, 4326) -- WGS84 coordinate system
);

Network Address Types

TypeDescriptionExample
INETIPv4 or IPv6 address192.168.1.1
CIDRNetwork address192.168.1.0/24
MACADDRMAC address08:00:2b:01:02:03
CREATE TABLE connections (
ip_address INET,
network CIDR,
mac_address MACADDR
);
-- Insert network data
INSERT INTO connections VALUES
('192.168.1.100', '192.168.1.0/24', '08:00:2b:01:02:03');
-- Query by network
SELECT * FROM connections WHERE ip_address << '192.168.1.0/24';

Custom Types

Enum Types

-- Create enum type
CREATE TYPE user_status AS ENUM ('active', 'inactive', 'banned', 'pending');
CREATE TABLE users (
id SERIAL PRIMARY KEY,
status user_status DEFAULT 'pending'
);
-- Insert
INSERT INTO users (status) VALUES ('active');
-- Query
SELECT * FROM users WHERE status = 'active';

Composite Types

-- Create composite type
CREATE TYPE address AS (
street VARCHAR(100),
city VARCHAR(50),
state CHAR(2),
zip_code VARCHAR(10)
);
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
shipping_address address
);
-- Insert
INSERT INTO customers (name, shipping_address) VALUES
('Alice', ROW('123 Main St', 'San Francisco', 'CA', '94102'));
-- Query
SELECT
name,
(shipping_address).city AS city
FROM customers;

Domain Types (Constrained Types)

-- Create domain with constraints
CREATE DOMAIN email_address AS VARCHAR(255)
CHECK (VALUE ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$');
CREATE DOMAIN positive_integer AS INTEGER
CHECK (VALUE > 0);
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email email_address,
age positive_integer
);
-- This will fail validation
INSERT INTO users (email, age) VALUES ('invalid', -5);

Type Conversion

Explicit Casting

-- Using ::
SELECT '123'::INTEGER;
SELECT 123::TEXT;
SELECT '2025-11-01'::DATE;
-- Using CAST()
SELECT CAST('123' AS INTEGER);
SELECT CAST(NOW() AS DATE);

Implicit Casting

-- Integer to BIGINT (safe)
SELECT 123::INTEGER + 456::BIGINT;
-- String to timestamp
SELECT NOW() > '2025-01-01';

Size Comparison

TypeStorageMax Value/Size
BOOLEAN1 byteTRUE/FALSE
SMALLINT2 bytes32,767
INTEGER4 bytes2.1 billion
BIGINT8 bytes9.2 quintillion
DECIMAL(10,2)VariableUser-defined
REAL4 bytes6 decimal places
DOUBLE PRECISION8 bytes15 decimal places
CHAR(10)10 bytes10 chars
VARCHAR(255)Variable255 chars
TEXTVariable1 GB
DATE4 bytes~10,000 years
TIMESTAMP8 bytesMicrosecond precision
UUID16 bytes128-bit unique ID
JSONBVariable~1 GB
VECTOR(768)3,072 bytes768 dimensions

Best Practices

  1. Use appropriate numeric types:

    • SMALLINT for small counters (< 32K)
    • INTEGER for general purpose (< 2B)
    • BIGINT for large numbers (> 2B)
    • DECIMAL for money (exact)
    • DOUBLE PRECISION for scientific (approximate)
  2. Use TEXT instead of VARCHAR (unless you have a specific length limit):

    -- GOOD
    CREATE TABLE posts (content TEXT);
    -- ⚠ OKAY if you have a limit
    CREATE TABLE users (username VARCHAR(50));
  3. Always use TIMESTAMPTZ (not TIMESTAMP):

    -- GOOD
    created_at TIMESTAMPTZ DEFAULT NOW()
    -- ❌ BAD (loses timezone info)
    created_at TIMESTAMP DEFAULT NOW()
  4. Use JSONB instead of JSON:

    -- GOOD (indexable, faster)
    profile JSONB
    -- ❌ BAD (slower, not indexable)
    profile JSON
  5. Index large columns appropriately:

    -- B-tree for exact matches
    CREATE INDEX idx_email ON users(email);
    -- GIN for JSONB
    CREATE INDEX idx_profile ON users USING GIN(profile);
    -- HNSW for vectors
    CREATE INDEX idx_embedding ON products USING hnsw(embedding);

Last Updated: November 1, 2025 Version: v6.0 Phase 2 M1 Maintained by: HeliosDB Documentation Team

Related: Query Guide | FAQ | Getting Started