Lindorm Cassandra Query Language (CQL) DDL statements let you create and manage keyspaces, tables, and indexes. This page covers the complete DDL syntax with examples.
Statements covered
Key concepts
Keyspaces and tables
Lindorm CQL stores data in tables grouped into keyspaces. A keyspace applies options — most commonly a replication strategy — to all tables it contains. In Lindorm CQL, the replication strategy and replica count use fixed defaults and cannot be modified.
Naming rules
Keyspace and table names follow the same rules:
name ::= unquoted_name | quoted_name
unquoted_name ::= re('[a-zA-Z_0-9]{1, 48}')
quoted_name ::= '"' unquoted_name '"'Names can contain letters, digits, and underscores.
Length: 1–48 characters.
Unquoted names are case-insensitive:
myTableandmytablerefer to the same table.Quoted names are case-sensitive:
"myTable"and"mytable"are different tables.Qualify a table name with its keyspace to avoid ambiguity:
ks.tableandgs.tableare distinct even if both contain a table namedtable.
Indexes
Lindorm CQL supports two index types:
Secondary indexes — query data by non-primary-key columns. The index name pattern is
re('[a-zA-Z_0-9]+').Search Index — powered by Lindorm's search engine. Supports multidimensional queries,
ORDER BYsorting, and fuzzy match.
Before using Search Index, enable both the Search Index feature and Lindorm Tunnel Service (LTS). For details, see Overview.
CREATE KEYSPACE
Creates a keyspace.
Syntax
CREATE KEYSPACE [ IF NOT EXISTS ] keyspace_name WITH optionsKeyspaces in Lindorm CQL are equivalent to namespaces. The replication strategy and replica count cannot be configured — Lindorm always uses double-replica storage with durable_writes set to true.
Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
keyspace_name | Yes | — | Name of the keyspace. Example: testks |
replication | No | {'class': 'SimpleStrategy', 'replication_factor': 2} | MAP type. Specifies replica count. Lindorm ignores the configured value and uses double-replica storage. |
durable_writes | No | true | BOOLEAN type. Specifies whether durable writes are enabled. Always true in Lindorm CQL. |
Example
CREATE KEYSPACE testks WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}ALTER KEYSPACE
Modifies keyspace options.
Syntax
ALTER KEYSPACE keyspace_name WITH optionsThe options parameter is the same as in CREATE KEYSPACE. Configuring replication or durable_writes has no effect — Lindorm CQL always uses the default values.
Example
ALTER KEYSPACE testks WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}USE
Sets the active keyspace for the session. Objects such as tables, user-defined types (UDTs), and user-defined functions (UDFs) are scoped to a keyspace.
Syntax
USE keyspace_nameExample
USE testks;DROP KEYSPACE
Deletes a keyspace and all its contents.
Syntax
DROP KEYSPACE [ IF EXISTS ] keyspace_nameDropping a keyspace immediately and permanently deletes all tables, UDTs, and UDFs it contains. This action cannot be undone.
Usage notes
Use
IF EXISTSto suppress the error when the keyspace does not exist.Only the root user can drop keyspaces.
Example
DROP KEYSPACE testks;CREATE TABLE
Creates a table.
Syntax
CREATE TABLE [ IF NOT EXISTS ] table_name
'('
column_definition
( ',' column_definition )*
[ ',' PRIMARY KEY '(' primary_key ')' ]
')' [ WITH table_options ]
column_definition ::= column_name cql_type [ STATIC ] [ PRIMARY KEY ]
primary_key ::= partition_key [ ',' clustering_columns ]
partition_key ::= column_name
| '(' column_name ( ',' column_name )* ')'
clustering_columns ::= column_name ( ',' column_name )*
table_options ::= CLUSTERING ORDER BY '(' clustering_order ')' [ AND options ]
| options
clustering_order ::= column_name (ASC | DESC) ( ',' column_name (ASC | DESC) )*Use IF NOT EXISTS to skip the statement silently when the table already exists.
Primary key
Every table requires a primary key that uniquely identifies each row. A primary key has two parts:
Partition key
The partition key is the first element of the primary key. It determines how data is distributed across nodes. A table must have at least one partition key column. To define a composite partition key, wrap multiple column names in parentheses.
In Lindorm CQL, the partition key alone does not identify the physical node storing a row — it must be combined with clustering columns. This differs from standard Apache Cassandra CQL behavior.
Clustering columns
Clustering columns follow the partition key in the primary key definition. They are optional and determine the sort order of rows within a partition.
Primary key examples
| Definition | Partition key | Clustering columns |
|---|---|---|
PRIMARY KEY (a) | a | none |
PRIMARY KEY (a, b, c) | a | b, c |
PRIMARY KEY ((a, b), c) | a, b (composite) | c |
Partition behavior example
CREATE TABLE personinfo (
a int,
b int,
c int,
d int,
PRIMARY KEY ((a, b), c, d)
);
SELECT * FROM personinfo;
a | b | c | d
---+---+---+---
0 | 0 | 0 | 0 -- row 1: same partition as row 2 (a=0, b=0)
0 | 0 | 1 | 1 -- row 2
0 | 1 | 2 | 2 -- row 3: different partition (a=0, b=1)
0 | 1 | 3 | 3 -- row 4
1 | 1 | 4 | 4 -- row 5: different partition (a=1, b=1)Rows 1 and 2 share the same partition (a=0, b=0) and reside on the same node. In standard Apache Cassandra CQL, the partition key alone determines placement — in Lindorm CQL, the full primary key (partition key + clustering columns) determines placement.
Table options
Supported options
| Option | Type | Default | Description |
|---|---|---|---|
default_time_to_live | int | 0 | Default TTL for all rows, in seconds. 0 means no expiration. |
compression | map | SnappyCompressor | Compression algorithm for SSTables. See Compression. |
extensions | map | — | Lindorm-specific properties: storage policy, cold/hot data separation, consistency level, and mutability. See Extensions. |
Unsupported options
The following Cassandra table options are not supported by Lindorm CQL:
| Option | Cassandra default |
|---|---|
comment | (none) |
speculative_retry | 99PERCENTILE |
cdc | false |
gc_grace_seconds | 86400 |
bloom_filter_fp_chance | 0.00075 |
compaction | STCS |
caching | — |
memtable_flush_period_in_ms | 0 |
read_repair | BLOCKING |
Compression
Lindorm CQL supports three compression algorithms. Use the compression option to specify one when creating a table.
LZ4
CREATE TABLE personinfo (
id int,
name text,
address text,
PRIMARY KEY (id, name)
) WITH compression = {'class': 'LZ4Compressor'};Zstd
CREATE TABLE personinfo (
id int,
name text,
address text,
PRIMARY KEY (id, name)
) WITH compression = {'class': 'ZstdCompressor'};Snappy (default)
CREATE TABLE personinfo (
id int,
name text,
address text,
PRIMARY KEY (id, name)
) WITH compression = {'class': 'SnappyCompressor'};Change the compression algorithm at any time with ALTER TABLE.
Extensions
Use the extensions option to configure Lindorm-specific table properties.
STORAGE_POLICY — controls whether data is stored on cold or hot media.
| Value | Description |
|---|---|
COLD | Store data on cold (capacity) storage |
DEFAULT | Store data on hot storage (default) |
-- Create a table with cold storage
CREATE TABLE personinfo (name text PRIMARY KEY, age int)
WITH extensions = {'STORAGE_POLICY': 'COLD'};
-- Switch from cold to hot storage
ALTER TABLE personinfo WITH extensions = {'STORAGE_POLICY': 'DEFAULT'};COLD_BOUNDARY — enables cold/hot data separation. Data written before the boundary (in seconds) is stored on cold media; newer data goes to hot media.
Do not set STORAGE_POLICY to COLD on a table that uses COLD_BOUNDARY. If STORAGE_POLICY is COLD, disable cold/hot data separation first. For details, see Capacity storage.
-- Enable cold/hot data separation with an 86400-second (1 day) boundary
CREATE TABLE personinfo (name text PRIMARY KEY, age int)
WITH extensions = {'COLD_BOUNDARY': '86400'};
-- Update the boundary to 1000 seconds
ALTER TABLE personinfo WITH extensions = {'COLD_BOUNDARY': '1000'};
-- Disable cold/hot data separation
ALTER TABLE personinfo WITH extensions = {'COLD_BOUNDARY': ''};CONSISTENCY_TYPE — sets the consistency level for multi-zone deployments.
| Value | Description |
|---|---|
eventual | Eventual consistency |
timestamp | Timestamp-based consistency |
basic | Basic consistency |
strong | Strong consistency |
-- Set strong consistency
CREATE TABLE personinfo (name text PRIMARY KEY, age int)
WITH extensions = {'CONSISTENCY_TYPE': 'strong'};
-- Change to eventual consistency
ALTER TABLE personinfo WITH extensions = {'CONSISTENCY_TYPE': 'eventual'};MUTABILITY — required before creating secondary or full-text indexes.
| Value | Requires CONSISTENCY_TYPE=strong |
|---|---|
IMMUTABLE | No |
MUTABLE_ALL (default) | Yes |
IMMUTABLE_ROWS | Yes |
MUTABLE_LATEST | Yes |
-- Set IMMUTABLE mutability
CREATE TABLE personinfo (name text PRIMARY KEY, age int)
WITH extensions = {'MUTABILITY': 'IMMUTABLE'};
-- Change to MUTABLE_LATEST
ALTER TABLE personinfo WITH extensions = {'MUTABILITY': 'MUTABLE_LATEST'};Limitations
The
STATICcolumn modifier is not supported.The partition key alone does not identify the physical storage node for a row.
Examples
-- Basic table with a single-column primary key
CREATE TABLE tb (name text PRIMARY KEY, age int);
-- Table with a 1000-second default TTL
CREATE TABLE ttltb (name text PRIMARY KEY, age int)
WITH default_time_to_live = 1000;
-- Table with LZ4 compression
CREATE TABLE cptb (name text PRIMARY KEY, age int)
WITH compression = {'sstable_compression': 'LZ4Compressor'};
-- Table with a 10-second cold/hot data separation boundary
CREATE TABLE hct (name text PRIMARY KEY, age int)
WITH extensions = {'COLD_BOUNDARY': '10'};ALTER TABLE
Modifies a table's columns or options.
Syntax
ALTER TABLE table_name alter_table_instruction
alter_table_instruction ::= ADD column_name cql_type ( ',' column_name cql_type )*
| DROP column_name ( column_name )*
| WITH optionsUsage notes
ADD — adds one or more columns. The primary key cannot be changed after table creation, so new columns cannot be part of the primary key.
DROP — not supported in Lindorm CQL. Column drop operations are ignored.
WITH — modifies table options. All options set at creation time can be changed except
CLUSTERING ORDER. Modifiable options:default_time_to_live,compression, andextensions.
Example
CREATE TABLE personinfo (name text PRIMARY KEY, age int);
ALTER TABLE personinfo ADD address text;DROP TABLE
Deletes a table and all its data.
Syntax
DROP TABLE [ IF EXISTS ] table_nameDropping a table immediately and permanently deletes all data. This action cannot be undone.
Usage notes
Use
IF EXISTSto suppress the error when the table does not exist.Only the root user can drop tables.
Example
DROP TABLE personinfo;TRUNCATE
Deletes all rows from a table while keeping the table schema.
Syntax
TRUNCATE [ TABLE ] table_nameTRUNCATE permanently deletes all data in the table. This action cannot be undone.
Usage notes
Only the root user can truncate tables.
Example
TRUNCATE TABLE personinfo;CREATE INDEX
Creates a secondary index on a table column.
Syntax
CREATE [ CUSTOM ] INDEX [ IF NOT EXISTS ] [ index_name ]
ON table_name '(' index_identifier ')'
[ USING string [ WITH OPTIONS = map_literal ] ]
index_identifier ::= column_name
| '(' column_name ')'Existing data in the indexed column is indexed asynchronously after the index is created. New data is indexed automatically.
Use IF NOT EXISTS to suppress the error when the index already exists.
Single-column index
CREATE INDEX myindex ON personinfo (c2);
CREATE INDEX ON personinfo (c2); -- index name is optionalMulti-column index
To index multiple columns, use CREATE CUSTOM INDEX with the Lindorm secondary index class:
CREATE CUSTOM INDEX myindex ON personinfo (c1, c2)
USING 'com.alibaba.lindorm.cserver.schema.index.LindormSecondaryIndex';DROP INDEX
Deletes a secondary index.
Syntax
DROP INDEX [ IF EXISTS ] index_nameUsage notes
index_nameincludes the keyspace qualifier.Use
IF EXISTSto suppress the error when the index does not exist.
Example
DROP INDEX myindex;CREATE SEARCH INDEX
Creates a full-text index on one or more columns of a table.
Syntax
CREATE SEARCH INDEX [ IF NOT EXISTS ] index_name ON [keyspace_name.]table_name
[ WITH COLUMNS (column1, ..., columnn) ]
| [ WITH COLUMNS (*) ]Usage notes
WITH COLUMNS (col1, col2, ...)— indexes the specified columns.WITH COLUMNS (*)— indexes all columns.In multi-zone deployments, set
CONSISTENCY_TYPEandMUTABILITYon the table using theextensionsoption before creating a Search Index.After creation, the index status is
INACTIVE. Run REBUILD SEARCH INDEX to activate it.
Example
CREATE SEARCH INDEX schidx ON personinfo WITH COLUMNS (c2, c3);DROP SEARCH INDEX
Deletes a full-text index.
Syntax
DROP SEARCH INDEX [IF EXISTS] ON [keyspace_name.]table_name;Example
DROP SEARCH INDEX ON testks.personinfo;REBUILD SEARCH INDEX
Activates a full-text index and builds the index for existing data.
Syntax
REBUILD SEARCH INDEX [ASYNC] [IF EXISTS] ON [keyspace_name.]table_name;After CREATE SEARCH INDEX, the index status is INACTIVE. Run REBUILD SEARCH INDEX to set it to active and index any existing data.
Indexing existing data may take a significant amount of time. Use the ASYNC option to run the rebuild in the background.
Examples
-- Synchronous rebuild
REBUILD SEARCH INDEX ON personinfo;
-- Asynchronous rebuild
REBUILD SEARCH INDEX ASYNC ON personinfo;ALTER SEARCH INDEX
Adds or removes indexed columns from a full-text index.
Syntax
ALTER SEARCH INDEX SCHEMA [IF EXISTS] ON [keyspace_name.]table_name
( ADD FIELD column_name
| DROP FIELD column_name );After altering a Search Index, run REBUILD SEARCH INDEX to apply the changes and reset the index status.
The column specified in ADD FIELD or DROP FIELD must exist in the table.
Examples
-- Add a column to the index
ALTER SEARCH INDEX SCHEMA ON personinfo ADD (c3);
-- Remove a column from the index
ALTER SEARCH INDEX SCHEMA ON personinfo DROP (c2);