Ferrosa implements CQL native protocol v5. This page documents what's supported, what's different, and what Ferrosa adds on top.
Ferrosa implements CQL native protocol version 5 with the standard 9-byte frame header. All 16 opcodes are handled:
| Opcode | Name | Direction |
|---|---|---|
| 0x00 | ERROR | Response |
| 0x01 | STARTUP | Request |
| 0x02 | READY | Response |
| 0x03 | AUTHENTICATE | Response |
| 0x05 | OPTIONS | Request |
| 0x06 | SUPPORTED | Response |
| 0x07 | QUERY | Request |
| 0x08 | RESULT | Response |
| 0x09 | PREPARE | Request |
| 0x0A | EXECUTE | Request |
| 0x0B | REGISTER | Request |
| 0x0C | EVENT | Response |
| 0x0D | BATCH | Request |
| 0x0E | AUTH_CHALLENGE | Response |
| 0x0F | AUTH_RESPONSE | Request |
| 0x10 | AUTH_SUCCESS | Response |
Frame-level compression is negotiated during STARTUP via the COMPRESSION option:
Compression is optional. Uncompressed frames are always accepted.
SASL PLAIN authentication via the standard org.apache.cassandra.auth.PasswordAuthenticator flow. Passwords are hashed with bcrypt or argon2. Disable with FERROSA_AUTH_DISABLED=true for development.
| CQL Type | Protocol ID | Status |
|---|---|---|
| ascii | 0x0001 | Supported |
| bigint | 0x0002 | Supported |
| blob | 0x0003 | Supported |
| boolean | 0x0004 | Supported |
| counter | 0x0005 | Supported |
| decimal | 0x0006 | Supported |
| double | 0x0007 | Supported |
| float | 0x0008 | Supported |
| int | 0x0009 | Supported |
| timestamp | 0x000B | Supported |
| uuid | 0x000C | Supported |
| varchar / text | 0x000D | Supported |
| varint | 0x000E | Supported |
| timeuuid | 0x000F | Supported |
| inet | 0x0010 | Supported |
| date | 0x0011 | Supported |
| time | 0x0012 | Supported |
| smallint | 0x0013 | Supported |
| tinyint | 0x0014 | Supported |
| list<T> | 0x0020 | Supported |
| map<K, V> | 0x0021 | Supported |
| set<T> | 0x0022 | Supported |
| tuple<...> | 0x0031 | Supported |
| frozen<T> | — | Supported |
| duration | 0x0015 | Supported |
| UDT | 0x0030 | Supported |
| Statement | Status | Notes |
|---|---|---|
| CREATE KEYSPACE | Supported | WITH replication, IF NOT EXISTS, DURABLE_WRITES |
| ALTER KEYSPACE | Supported | Change replication, durable_writes |
| DROP KEYSPACE | Supported | IF EXISTS |
| CREATE TABLE | Supported | Partition key, clustering key with order, IF NOT EXISTS, table options |
| ALTER TABLE | Supported | ADD column, DROP column |
| DROP TABLE | Supported | IF EXISTS |
| CREATE INDEX | Supported | USING type, WITH OPTIONS, IF NOT EXISTS — see below |
| DROP INDEX | Supported | IF EXISTS |
| CREATE MATERIALIZED VIEW | Not yet | — |
| CREATE TYPE (UDT) | Supported | CREATE TYPE, ALTER TYPE, DROP TYPE — full UDT DDL lifecycle |
| CREATE FUNCTION / AGGREGATE | Supported | CREATE/DROP FUNCTION (WASM), CREATE/DROP AGGREGATE — full DDL lifecycle with cluster replication |
CREATE KEYSPACE social WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': 3 } AND durable_writes = true; CREATE TABLE social.users ( user_id uuid, name text, email text, created_at timestamp, tags set<text>, PRIMARY KEY (user_id) );
| Statement | Status | Notes |
|---|---|---|
| SELECT | Supported | WHERE, ORDER BY, LIMIT, bind markers (?), named bind markers (:name), IN clause |
| INSERT | Supported | IF NOT EXISTS, USING TTL, USING TIMESTAMP |
| UPDATE | Supported | SET, WHERE, IF conditions |
| DELETE | Supported | WHERE, IF EXISTS, column-level delete |
| BATCH | Supported | BEGIN BATCH ... APPLY BATCH (unlogged) |
| TRUNCATE | Supported | — |
| USE | Supported | Set default keyspace for session |
Full PREPARE/EXECUTE support. The prepared statement cache uses moka with W-TinyLFU eviction (64 MB default). Bind markers (?) and named bind markers (:name) are both supported.
-- Prepare PREPARE stmt FROM 'SELECT * FROM social.users WHERE user_id = ?'; -- Execute with positional bind EXECUTE stmt USING 550e8400-e29b-41d4-a716-446655440000;
WHERE clauses support: =, <, >, <=, >=, !=, IN
Ferrosa supports the following consistency levels for reads and writes:
ONETWOTHREEQUORUMALLLOCAL_ONELOCAL_QUORUMEACH_QUORUMSet per-query via the standard CQL protocol flags, or configure a default with FERROSA_DEFAULT_CL (default: QUORUM).
| Statement | Status | Notes |
|---|---|---|
| CREATE ROLE | Supported | WITH PASSWORD, SUPERUSER, LOGIN, IF NOT EXISTS |
| ALTER ROLE | Supported | Change password, superuser, login |
| DROP ROLE | Supported | IF EXISTS |
| GRANT | Supported | GRANT permission ON resource TO role |
| REVOKE | Supported | REVOKE permission ON resource FROM role |
Ferrosa supports column-level permissions, rate limiting per role, and audit logging to configurable sinks (log file, audit table).
Standard Cassandra system schema tables for driver compatibility:
system_schema.keyspacessystem_schema.tablessystem_schema.columnssystem_schema.typessystem_schema.functionssystem_schema.aggregatessystem_schema.triggerssystem_schema.viewssystem_schema.indexesNode metadata including tokens column for driver topology awareness.
Virtual tables backed by live in-memory state, not persisted:
system_observability.connections — active CQL client connectionssystem_observability.active_queries — currently executing queriessystem_observability.storage_stats — storage engine metricssystem_views.secondary_indexes — per-index build status, staleness, pending work-- Check active connections SELECT * FROM system_observability.connections; -- Monitor running queries SELECT * FROM system_observability.active_queries; -- Storage engine stats SELECT * FROM system_observability.storage_stats;
| Type | USING clause | Use case |
|---|---|---|
| B-tree | 'btree' (default) | Ordered range queries and sorted scans |
| Hash | 'hash' | O(1) equality point lookups |
| Composite | 'composite' | Multi-column prefix-based lookups |
| Phonetic | 'phonetic' | Fuzzy name matching (Soundex, Metaphone, Double Metaphone, Caverphone) |
| Filtered | Any + WHERE | Partial index over a subset of rows |
| Vector (HNSW) | 'vector' | Approximate nearest neighbor — graph-based, best query performance |
| Vector (IVFFlat) | 'vector' | Approximate nearest neighbor — k-means clustering, faster builds |
-- B-tree index (default when USING is omitted) CREATE INDEX idx_email ON users (email) USING 'btree'; -- Hash index for fast equality lookups CREATE INDEX idx_user_id ON sessions (user_id) USING 'hash'; -- Composite index across multiple columns CREATE INDEX idx_name ON users (last_name, first_name) USING 'composite'; -- Phonetic index for "sounds like" matching CREATE INDEX idx_name_phonetic ON users (last_name) USING 'phonetic' WITH OPTIONS = {'algorithm': 'double_metaphone'}; -- Filtered index — only index active users CREATE INDEX idx_active_email ON users (email) USING 'btree' WHERE status = 'active'; -- IF NOT EXISTS is supported CREATE INDEX IF NOT EXISTS idx_email ON users (email); -- Drop an index DROP INDEX idx_email; DROP INDEX IF EXISTS idx_email;
Ferrosa includes two vector index algorithms for approximate nearest neighbor (ANN) search, supporting AI embeddings, semantic search, and recommendation systems:
-- HNSW index — best query performance, incremental builds CREATE INDEX idx_embed ON documents (embedding) USING 'vector' WITH OPTIONS = { 'method': 'hnsw', 'metric': 'cosine', 'dimensions': '768', 'm': '16', 'ef_construction': '200' }; -- IVFFlat index — faster builds, good for batch imports CREATE INDEX idx_embed_ivf ON documents (embedding) USING 'vector' WITH OPTIONS = { 'method': 'ivfflat', 'metric': 'l2', 'dimensions': '1536', 'lists': '100' };
| Metric | Value | Use case |
|---|---|---|
| L2 (Euclidean) | 'l2' | Standard distance — smaller = more similar |
| Cosine | 'cosine' | Angle-based similarity — ideal for text embeddings |
| Inner product | 'inner_product' | Dot product — larger = more similar |
Supports up to 4,096 dimensions (f32) or 8,192 dimensions (f16 half-precision).
| Algorithm | Value | Best for |
|---|---|---|
| Soundex | 'soundex' | Standard American English names |
| Metaphone | 'metaphone' | General English pronunciation |
| Double Metaphone | 'double_metaphone' | Multi-origin names (returns primary + alternate codes) |
| Caverphone | 'caverphone' | New Zealand English names |
Ferrosa indexes are storage-attached — built as companion files alongside SSTables. Indexes are built asynchronously after memtable flush, with zero impact on the write path. This means:
system_views.secondary_indexes lets you monitor how far behind each index is-- Check index build status and staleness SELECT index_name, status, pending_sstable_count, lag_seconds FROM system_views.secondary_indexes; -- View index metadata SELECT index_name, kind, target, options FROM system_schema.indexes WHERE keyspace_name = 'myapp';
All index DDL (CREATE INDEX, DROP INDEX) replicates automatically in pair mode. Each node independently builds indexes for its local SSTables — no cross-node index coordination needed.
-- Subscribe to a table with polling interval SUBSCRIBE keyspace.table EVERY 5s; -- Subscribe with push-on-write (change data capture) SUBSCRIBE keyspace.table DELTA; -- Subscribe to a SELECT query SUBSCRIBE SELECT name, email FROM social.users WHERE active = true EVERY 10s; -- Subscribe to observability tables SUBSCRIBE system_observability.connections EVERY 5s; -- Unsubscribe from a specific stream UNSUBSCRIBE 42; -- Unsubscribe from all streams UNSUBSCRIBE;
| Mode | Syntax | Behavior |
|---|---|---|
| EVERY | EVERY 5s | Server re-executes the query at the given interval and pushes results |
| DELTA | DELTA | Push-on-write via SubscriptionObserver in the commit log; only changed rows are sent |
SUBSCRIBE responses use the standard CQL RESULT opcode (0x08) with the STREAMING flag set in the frame header. Drivers that don't understand the flag will simply see it as a normal result set. The subscription lifecycle is managed server-side — clients don't need to implement any new protocol logic.
-- Mark a table as a vertex type ALTER TABLE social.users WITH extensions = {'graph.type': 'vertex', 'graph.label': 'Person'}; -- Mark a table as an edge type ALTER TABLE social.follows WITH extensions = { 'graph.type': 'edge', 'graph.label': 'FOLLOWS', 'graph.source': 'Person', 'graph.target': 'Person' };
| Statement | Status | Notes |
|---|---|---|
| MATCH ... RETURN | Supported | Pattern matching, WHERE clause, multi-hop |
| CREATE | Parsed | Parsed; mutate via CQL INSERT (see Cypher reference) |
| SET | Parsed | Parsed; mutate via CQL UPDATE |
| DELETE / DETACH DELETE | Parsed | Parsed; mutate via CQL DELETE |
| SUBSCRIBE MATCH | Supported | Real-time subscription to graph traversals with EVERY/DELTA |
-- Subscribe to a graph traversal SUBSCRIBE MATCH (a:Person {name: 'Alice'})-[:FOLLOWS]->(b:Person) RETURN b.name, b.email EVERY 10s; -- Push-on-write for graph changes SUBSCRIBE MATCH (a:Person)-[r:FOLLOWS]->(b:Person) RETURN a.name, b.name DELTA;
The following Cassandra features are not yet implemented. They are planned for future releases:
| Feature | Status |
|---|---|
| Logged batch atomicity | Planned |
| Query tracing | Planned |
| Materialized views | Planned |
| Lightweight transactions (LWT) | Planned |