From 5d65542bd3b5cbdfe8ebed7892fce7e06e7779f0 Mon Sep 17 00:00:00 2001 From: Sylvain Lebresne Date: Wed, 15 Jun 2016 09:29:22 +0200 Subject: [PATCH] Fix CQL doc (incomplete) --- doc/cql3/CQL.textile | 4 +- doc/source/_static/extra.css | 4 + doc/source/architecture.rst | 2 + doc/source/cql.rst | 3516 ++++++++++++++++++---------------- doc/source/operations.rst | 15 +- 5 files changed, 1871 insertions(+), 1670 deletions(-) diff --git a/doc/cql3/CQL.textile b/doc/cql3/CQL.textile index 275717c342..e354524189 100644 --- a/doc/cql3/CQL.textile +++ b/doc/cql3/CQL.textile @@ -1678,7 +1678,9 @@ Show any permissions granted to @carlos@ or any of @carlos@'s roles, limited to h2(#types). Data Types -CQL supports a rich set of data types for columns defined in a table, including collection types. On top of those native and collection types, users can also provide custom types (through a JAVA class extending @AbstractType@ loadable by Cassandra). The syntax of types is thus: +CQL supports a rich set of data types for columns defined in a table, including collection types. On top of those native +and collection types, users can also provide custom types (through a JAVA class extending @AbstractType@ loadable by +Cassandra). The syntax of types is thus: bc(syntax).. ::= diff --git a/doc/source/_static/extra.css b/doc/source/_static/extra.css index ff9f1d110e..1b65a86063 100644 --- a/doc/source/_static/extra.css +++ b/doc/source/_static/extra.css @@ -12,10 +12,14 @@ a.reference.internal code.literal { border: none; font-size: 12px; color: #2980B9; + padding: 0; + background: none; } a.reference.internal:visited code.literal { color: #9B59B6; + padding: 0; + background: none; } diff --git a/doc/source/architecture.rst b/doc/source/architecture.rst index cb5247723b..920941440f 100644 --- a/doc/source/architecture.rst +++ b/doc/source/architecture.rst @@ -40,6 +40,8 @@ Token Ring/Ranges .. todo:: todo +.. _replication-strategy: + Replication ^^^^^^^^^^^ diff --git a/doc/source/cql.rst b/doc/source/cql.rst index 8d36258ac1..8d185a2ee6 100644 --- a/doc/source/cql.rst +++ b/doc/source/cql.rst @@ -16,15 +16,11 @@ .. highlight:: sql +.. _UUID: https://en.wikipedia.org/wiki/Universally_unique_identifier + The Cassandra Query Language (CQL) ================================== -CQL Syntax ----------- - -Preamble -^^^^^^^^ - This document describes the Cassandra Query Language (CQL) [#]_. Note that this document describes the last version of the languages. However, the `changes <#changes>`_ section provides the diff between the different versions of CQL. @@ -33,6 +29,13 @@ that reason, when used in this document, these terms (tables, rows and columns) in SQL. But please note that as such, they do **not** refer to the concept of rows and columns found in the deprecated thrift API (and earlier version 1 and 2 of CQL). +.. _definitions: + +Definitions +----------- + +.. _conventions: + Conventions ^^^^^^^^^^^ @@ -41,12 +44,18 @@ To aid in specifying the CQL syntax, we will use the following conventions in th - Language rules will be given in an informal `BNF variant `_ notation. In particular, we'll use square brakets (``[ item ]``) for optional items, ``*`` and ``+`` for repeated items (where ``+`` imply at least one). -- The grammar is provided for documentation purposes and leave some minor details out (only conveniences that can be - ignored). For instance, the comma on the last column definition in a ``CREATE TABLE`` statement is optional but - supported if present even though the grammar in this document suggests otherwise. Also, not everything accepted by the - grammar will be valid CQL. +- The grammar will also use the following convention for convenience: non-terminal term will be lowercase (and link to + their definition) while terminal keywords will be provided "all caps". Note however that keywords are + :ref:`identifiers` and are thus case insensitive in practice. We will also define some early construction using + regexp, which we'll indicate with ``re()``. +- The grammar is provided for documentation purposes and leave some minor details out. For instance, the comma on the + last column definition in a ``CREATE TABLE`` statement is optional but supported if present even though the grammar in + this document suggests otherwise. Also, not everything accepted by the grammar is necessarily valid CQL. - References to keywords or pieces of CQL code in running text will be shown in a ``fixed-width font``. + +.. _identifiers: + Identifiers and keywords ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,7 +63,7 @@ The CQL language uses *identifiers* (or *names*) to identify tables, columns and matching the regular expression ``[a-zA-Z][a-zA-Z0-9_]*``. A number of such identifiers, like ``SELECT`` or ``WITH``, are *keywords*. They have a fixed meaning for the language -and most are reserved. The list of those keywords can be found in `Appendix A <#appendixA>`__. +and most are reserved. The list of those keywords can be found in :ref:`appendix-A`. Identifiers and (unquoted) keywords are case insensitive. Thus ``SELECT`` is the same than ``select`` or ``sElEcT``, and ``myId`` is the same than ``myid`` or ``MYID``. A convention often used (in particular by the samples of this @@ -69,468 +78,1098 @@ sensitive (``"My Quoted Id"`` is *different* from ``"my quoted id"``). A fully l ``"myid"`` is equivalent to ``myid`` and to ``myId`` but different from ``"myId"``). Inside a quoted identifier, the double-quote character can be repeated to escape it, so ``"foo "" bar"`` is a valid identifier. -**Warning**: *quoted identifiers* allows to declare columns with arbitrary names, and those can sometime clash with -specific names used by the server. For instance, when using conditional update, the server will respond with a -result-set containing a special result named ``"[applied]"``. If you’ve declared a column with such a name, this could -potentially confuse some tools and should be avoided. In general, unquoted identifiers should be preferred but if you -use quoted identifiers, it is strongly advised to avoid any name enclosed by squared brackets (like ``"[applied]"``) and -any name that looks like a function call (like ``"f(x)"``). +.. note:: *quoted identifiers* allows to declare columns with arbitrary names, and those can sometime clash with + specific names used by the server. For instance, when using conditional update, the server will respond with a + result-set containing a special result named ``"[applied]"``. If you’ve declared a column with such a name, this + could potentially confuse some tools and should be avoided. In general, unquoted identifiers should be preferred but + if you use quoted identifiers, it is strongly advised to avoid any name enclosed by squared brackets (like + ``"[applied]"``) and any name that looks like a function call (like ``"f(x)"``). -To sum up, we have: +More formally, we have: .. productionlist:: - identifer: `unquoted_identifier` | `quoted_identifier` - unquoted_identifier: [a-zA-Z][a-zA-Z0-9_]* - quoted_identifier: "\"" [any character where " can appear if doubled]+ "\"" + identifier: `unquoted_identifier` | `quoted_identifier` + unquoted_identifier: re('[a-zA-Z][a-zA-Z0-9_]*') + quoted_identifier: '"' (any character where " can appear if doubled)+ '"' + +.. _constants: Constants ^^^^^^^^^ -CQL defines the following kind of *constants*: strings, integers, -floats, booleans, uuids and blobs: +CQL defines the following kind of *constants*: -- A string constant is an arbitrary sequence of characters characters - enclosed by single-quote(\ ``'``). One can include a single-quote in - a string by repeating it, e.g. ``'It''s raining today'``. Those are - not to be confused with quoted identifiers that use double-quotes. -- An integer constant is defined by ``'-'?[0-9]+``. -- A float constant is defined by - ``'-'?[0-9]+('.'[0-9]*)?([eE][+-]?[0-9+])?``. On top of that, ``NaN`` - and ``Infinity`` are also float constants. -- A boolean constant is either ``true`` or ``false`` up to - case-insensitivity (i.e. ``True`` is a valid boolean constant). -- A - `UUID `__ - constant is defined by ``hex{8}-hex{4}-hex{4}-hex{4}-hex{12}`` where - ``hex`` is an hexadecimal character, e.g. ``[0-9a-fA-F]`` and ``{4}`` - is the number of such characters. -- A blob constant is an hexadecimal number defined by ``0[xX](hex)+`` - where ``hex`` is an hexadecimal character, e.g. ``[0-9a-fA-F]``. +.. productionlist:: + constant: `string` | `integer` | `float` | `boolean` | `uuid` | `blob` | NULL + string: '\'' (any character where ' can appear if doubled)+ '\'' + : '$$' (any character other than '$$') '$$' + integer: re('-?[0-9]+') + float: re('-?[0-9]+(\.[0-9]*)?([eE][+-]?[0-9+])?') | NAN | INFINITY + boolean: TRUE | FALSE + uuid: `hex`{8}-`hex`{4}-`hex`{4}-`hex`{4}-`hex`{12} + hex: re("[0-9a-fA-F]") + blob: '0' ('x' | 'X') `hex`+ + +In other words: + +- A string constant is an arbitrary sequence of characters enclosed by single-quote(``'``). A single-quote + can be included by repeating it, e.g. ``'It''s raining today'``. Those are not to be confused with quoted + :ref:`identifiers` that use double-quotes. Alternatively, a string can be defined by enclosing the arbitrary sequence + of characters by two dollar characters, in which case single-quote can be use without escaping (``$$It's raining + today$$``). That latter form is often used when defining :ref:`user-defined functions ` to avoid having to + escape single-quote characters in function body (as they are more likely to occur than ``$$``). +- Integer, float and boolean constant are defined as expected. Note however than float allows the special ``NaN`` and + ``Infinity`` constants. +- CQL supports UUID_ constants. +- Blobs content are provided in hexadecimal and prefixed by ``0x``. +- The special ``NULL`` constant denotes the absence of value. + +For how these constants are typed, see the :ref:`data-types` section. + +Terms +^^^^^ + +CQL has the notion of a *term*, which denotes the kind of values that CQL support. Terms are defined by: + +.. productionlist:: + term: `constant` | `literal` | `function_call` | `type_hint` | `bind_marker` + literal: `collection_literal` | `udt_literal` | `tuple_literal` + function_call: `identifier` '(' [ `term` (',' `term`)* ] ')' + type_hint: '(' `cql_type` `)` term + bind_marker: '?' | ':' `identifier` + +A term is thus one of: + +- A :ref:`constant `. +- A literal for either :ref:`a collection `, :ref:`a user-defined type ` or :ref:`a tuple ` + (see the linked sections for details). +- A function call: see :ref:`the section on functions ` for details on which :ref:`native function + ` exists and how to define your own :ref:`user-defined ones `. +- A *type hint*: see the :ref:`related section ` for details. +- A bind marker, which denotes a variable to be bound at execution time. See the section on :ref:`prepared-statements` + for details. A bind marker can be either anonymous (``?``) or named (``:some_name``). The latter form provides a more + convenient way to refer to the variable for binding it and should generally be preferred. -For how these constants are typed, see the `data types -section <#types>`__. Comments ^^^^^^^^ -A comment in CQL is a line beginning by either double dashes (``--``) or -double slash (``//``). +A comment in CQL is a line beginning by either double dashes (``--``) or double slash (``//``). -Multi-line comments are also supported through enclosure within ``/*`` -and ``*/`` (but nesting is not supported). +Multi-line comments are also supported through enclosure within ``/*`` and ``*/`` (but nesting is not supported). -| bc(sample). -| — This is a comment -| // This is a comment too -| /\* This is -| a multi-line comment \*/ +:: + + — This is a comment + // This is a comment too + /* This is + a multi-line comment */ Statements ^^^^^^^^^^ -CQL consists of statements. As in SQL, these statements can be divided -in 3 categories: +CQL consists of statements that can be divided in the following categories: -- Data definition statements, that allow to set and change the way data - is stored. -- Data manipulation statements, that allow to change data -- Queries, to look up data +- :ref:`data-definition` statements, to define and change how the data is stored (keyspaces and tables). +- :ref:`data-manipulation` statements, for selecting, inserting and deleting data. +- :ref:`index-and-views` statements. +- :ref:`roles-and-permissions` statements. +- :ref:`udfs` statements. +- :ref:`udts` statements. +- :ref:`triggers` statements. -All statements end with a semicolon (``;``) but that semicolon can be -omitted when dealing with a single statement. The supported statements -are described in the following sections. When describing the grammar of -said statements, we will reuse the non-terminal symbols defined below: +All the statements are listed below and are described in the rest of this documentation (see links above): -| bc(syntax).. -| ::= any quoted or unquoted identifier, excluding reserved keywords -| ::= ( ‘.’)? +.. productionlist:: + cql_statement: `statement` [ ';' ] + statement: `ddl_statement` + : | `dml_statement` + : | `index_or_view_statement` + : | `role_or_permission_statement` + : | `udf_statement` + : | `udt_statement` + : | `trigger_statement` + ddl_statement: `use_statement` + : | `create_keyspace_statement` + : | `alter_keyspace_statement` + : | `drop_keyspace_statement` + : | `create_table_statement` + : | `alter_table_statement` + : | `drop_table_statement` + : | `truncate_statement` + dml_statement: `select_statement` + : | `insert_statement` + : | `update_statement` + : | `delete_statement` + : | `batch_statement` + index_or_view_statement: `create_index_statement` + : | `drop_index_statement` + : | `create_materialized_view_statement` + : | `drop_materialized_view_statement` + role_or_permission_statement: `create_role_statement` + : | `alter_role_statement` + : | `drop_role_statement` + : | `grant_role_statement` + : | `revoke_role_statement` + : | `list_role_statement` + : | `grant_permission_statement` + : | `revoke_permission_statement` + : | `list_permission_statement` + : | `create_user_statement` + : | `alter_user_statement` + : | `drop_user_statement` + : | `list_user_statement` + udf_statement: `create_function_statement` + : | `drop_function_statement` + : | `create_aggregate_statement` + : | `drop_aggregate_statement` + udt_statement: `create_type_statement` + : | `alter_type_statement` + : | `drop_type_statement` + trigger_statement: `create_trigger_statement` + : | `drop_trigger_statement` -| ::= a string constant -| ::= an integer constant -| ::= a float constant -| ::= \| -| ::= a uuid constant -| ::= a boolean constant -| ::= a blob constant +.. _prepared-statements: -| ::= -| \| -| \| -| \| -| \| -| ::= ‘?’ -| \| ‘:’ -| ::= -| \| -| \| -| \| ‘(’ ( (‘,’ )\*)? ‘)’ +Prepared Statements +^^^^^^^^^^^^^^^^^^^ -| ::= -| \| -| \| -| ::= ‘{’ ( ‘:’ ( ‘,’ ‘:’ )\* )? ‘}’ -| ::= ‘{’ ( ( ‘,’ )\* )? ‘}’ -| ::= ‘[’ ( ( ‘,’ )\* )? ‘]’ +CQL supports *prepared statements*. Prepared statements are an optimization that allows to parse a query only once but +execute it multiple times with different concrete values. - ::= +Any statement that uses at least one bind marker (see :token:`bind_marker`) will need to be *prepared*. After which the statement +can be *executed* by provided concrete values for each of its marker. The exact details of how a statement is prepared +and then executed depends on the CQL driver used and you should refer to your driver documentation. -| ::= (AND )\* -| ::= ‘=’ ( \| \| ) -| p. -| Please note that not every possible productions of the grammar above - will be valid in practice. Most notably, ```` and nested - ```` are currently not allowed inside - ````. -A ```` can be either anonymous (a question mark (``?``)) or -named (an identifier preceded by ``:``). Both declare a bind variables -for `prepared statements <#preparedStatement>`__. The only difference -between an anymous and a named variable is that a named one will be -easier to refer to (how exactly depends on the client driver used). +.. _data-types: -The ```` production is use by statement that create and -alter keyspaces and tables. Each ```` is either a *simple* -one, in which case it just has a value, or a *map* one, in which case -it’s value is a map grouping sub-options. The following will refer to -one or the other as the *kind* (*simple* or *map*) of the property. +Data Types +---------- -A ```` will be used to identify a table. This is an -identifier representing the table name that can be preceded by a -keyspace name. The keyspace name, if provided, allow to identify a table -in another keyspace than the currently active one (the currently active -keyspace is set through the \ ``USE``\ statement). +CQL is a typed language and supports a rich set of data types, including :ref:`native types `, +:ref:`collection types `, :ref:`user-defined types `, :ref:`tuple types ` and :ref:`custom +types `: -For supported ````, see the section on -`functions <#functions>`__. +.. productionlist:: + cql_type: `native_type` | `collection_type` | `user_defined_type` | `tuple_type` | `custom_type` -Strings can be either enclosed with single quotes or two dollar -characters. The second syntax has been introduced to allow strings that -contain single quotes. Typical candidates for such strings are source -code fragments for user-defined functions. -*Sample:* +.. _native-types: -| bc(sample).. -| ‘some string value’ +Native Types +^^^^^^^^^^^^ -| $$double-dollar string can contain single ’ quotes$$ -| p. +The native types supported by CQL are: -Prepared Statement +.. productionlist:: + native_type: ASCII + : | BIGINT + : | BLOB + : | BOOLEAN + : | COUNTER + : | DATE + : | DECIMAL + : | DOUBLE + : | FLOAT + : | INET + : | INT + : | SMALLINT + : | TEXT + : | TIME + : | TIMESTAMP + : | TIMEUUID + : | TINYINT + : | UUID + : | VARCHAR + : | VARINT + +The following table gives additional informations on the native data types, and on which kind of :ref:`constants +` each type supports: + +=============== ===================== ================================================================================== + type constants supported description +=============== ===================== ================================================================================== + ``ascii`` :token:`string` ASCII character string + ``bigint`` :token:`integer` 64-bit signed long + ``blob`` :token:`blob` Arbitrary bytes (no validation) + ``boolean`` :token:`boolean` Either ``true`` or ``false`` + ``counter`` :token:`integer` Counter column (64-bit signed value). See :ref:`counters` for details + ``date`` :token:`integer`, A date (with no corresponding time value). See :ref:`dates` below for details + :token:`string` + ``decimal`` :token:`integer`, Variable-precision decimal + :token:`float` + ``double`` :token:`integer` 64-bit IEEE-754 floating point + :token:`float` + ``float`` :token:`integer`, 32-bit IEEE-754 floating point + :token:`float` + ``inet`` :token:`string` An IP address, either IPv4 (4 bytes long) or IPv6 (16 bytes long). Note that + there is no ``inet`` constant, IP address should be input as strings + ``int`` :token:`integer` 32-bit signed int + ``smallint`` :token:`integer` 16-bit signed int + ``text`` :token:`string` UTF8 encoded string + ``time`` :token:`integer`, A time (with no corresponding date value) with nanosecond precision. See + :token:`string` :ref:`times` below for details + ``timestamp`` :token:`integer`, A timestamp (date and time) with millisecond precision. See :ref:`timestamps` + :token:`string` below for details + ``timeuuid`` :token:`uuid` Version 1 UUID_, generally used as a “conflict-free” timestamp. Also see + :ref:`timeuuid-functions` + ``tinyint`` :token:`integer` 8-bit signed int + ``uuid`` :token:`uuid` A UUID_ (of any version) + ``varchar`` :token:`string` UTF8 encoded string + ``varint`` :token:`integer` Arbitrary-precision integer +=============== ===================== ================================================================================== + +.. _counters: + +Counters +~~~~~~~~ + +The ``counter`` type is used to define *counter columns*. A counter column is a column whose value is a 64-bit signed +integer and on which 2 operations are supported: incrementing and decrementing (see the :ref:`UPDATE statement +` for syntax). Note that the value of a counter cannot be set: a counter does not exist until first +incremented/decremented, and that first increment/decrement is made as if the prior value was 0. + +.. _counter-limitations: + +Counters have a number of important limitations: + +- They cannot be used for columns part of the ``PRIMARY KEY`` of a table. +- A table that contains a counter can only contain counters. In other words, either all the columns of a table outside + the ``PRIMARY KEY`` have the ``counter`` type, or none of them have it. +- Counters do not support :ref:`expiration `. +- The deletion of counters is supported, but is only guaranteed to work the first time you delete a counter. In other + words, you should not re-update a counter that you have deleted (if you do, proper behavior is not guaranteed). +- Counter updates are, by nature, not `idemptotent `__. An important + consequence is that if a counter update fails unexpectedly (timeout or loss of connection to the coordinator node), + the client has no way to know if the update has been applied or not. In particular, replaying the update may or may + not lead to an over count. + +.. _timestamps: + +Working with timestamps +^^^^^^^^^^^^^^^^^^^^^^^ + +Values of the ``timestamp`` type are encoded as 64-bit signed integers representing a number of milliseconds since the +standard base time known as `the epoch `__: January 1 1970 at 00:00:00 GMT. + +Timestamps can be input in CQL either using their value as an :token:`integer`, or using a :token:`string` that +represents an `ISO 8601 `__ date. For instance, all of the values below are +valid ``timestamp`` values for Mar 2, 2011, at 04:05:00 AM, GMT: + +- ``1299038700000`` +- ``'2011-02-03 04:05+0000'`` +- ``'2011-02-03 04:05:00+0000'`` +- ``'2011-02-03 04:05:00.000+0000'`` +- ``'2011-02-03T04:05+0000'`` +- ``'2011-02-03T04:05:00+0000'`` +- ``'2011-02-03T04:05:00.000+0000'`` + +The ``+0000`` above is an RFC 822 4-digit time zone specification; ``+0000`` refers to GMT. US Pacific Standard Time is +``-0800``. The time zone may be omitted if desired (``'2011-02-03 04:05:00'``), and if so, the date will be interpreted +as being in the time zone under which the coordinating Cassandra node is configured. There are however difficulties +inherent in relying on the time zone configuration being as expected, so it is recommended that the time zone always be +specified for timestamps when feasible. + +The time of day may also be omitted (``'2011-02-03'`` or ``'2011-02-03+0000'``), in which case the time of day will +default to 00:00:00 in the specified or default time zone. However, if only the date part is relevant, consider using +the :ref:`date ` type. + +.. _dates: + +Working with dates ^^^^^^^^^^^^^^^^^^ -CQL supports *prepared statements*. Prepared statement is an -optimization that allows to parse a query only once but execute it -multiple times with different concrete values. +Values of the ``date`` type are encoded as 32-bit unsigned integers representing a number of days with “the epoch” at +the center of the range (2^31). Epoch is January 1st, 1970 -In a statement, each time a column value is expected (in the data -manipulation and query statements), a ```` (see above) can be -used instead. A statement with bind variables must then be *prepared*. -Once it has been prepared, it can executed by providing concrete values -for the bind variables. The exact procedure to prepare a statement and -execute a prepared statement depends on the CQL driver used and is -beyond the scope of this document. +As for :ref:`timestamp `, a date can be input either as an :token:`integer` or using a date +:token:`string`. In the later case, the format should be ``yyyy-mm-dd`` (so ``'2011-02-03'`` for instance). -In addition to providing column values, bind markers may be used to -provide values for ``LIMIT``, ``TIMESTAMP``, and ``TTL`` clauses. If -anonymous bind markers are used, the names for the query parameters will -be ``[limit]``, ``[timestamp]``, and ``[ttl]``, respectively. +.. _times: + +Working with times +^^^^^^^^^^^^^^^^^^ + +Values of the ``time`` type are encoded as 64-bit signed integers representing the number of nanoseconds since midnight. + +As for :ref:`timestamp `, a time can be input either as an :token:`integer` or using a :token:`string` +representing the time. In the later case, the format should be ``hh:mm:ss[.fffffffff]`` (where the sub-second precision +is optional and if provided, can be less than the nanosecond). So for instance, the following are valid inputs for a +time: + +- ``'08:12:54'`` +- ``'08:12:54.123'`` +- ``'08:12:54.123456'`` +- ``'08:12:54.123456789'`` + + +.. _collections: + +Collections +^^^^^^^^^^^ + +CQL supports 3 kind of collections: :ref:`maps`, :ref:`sets` and :ref:`lists`. The types of those collections is defined +by: + +.. productionlist:: + collection_type: MAP '<' `cql_type` ',' `cql_type` '>' + : | SET '<' `cql_type` '>' + : | LIST '<' `cql_type` '>' + +and their values can be inputd using collection literals: + +.. productionlist:: + collection_literal: `map_literal` | `set_literal` | `list_literal` + map_literal: '{' [ `term` ':' `term` (',' `term` : `term`)* ] '}' + set_literal: '{' [ `term` (',' `term`)* ] '}' + list_literal: '[' [ `term` (',' `term`)* ] ']' + +Note however that neither :token:`bind_marker` nor ``NULL`` are supported inside collection literals. + +Noteworthy characteristics +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Collections are meant for storing/denormalizing relatively small amount of data. They work well for things like “the +phone numbers of a given user”, “labels applied to an email”, etc. But when items are expected to grow unbounded (“all +messages sent by a user”, “events registered by a sensor”...), then collections are not appropriate and a specific table +(with clustering columns) should be used. Concretely, (non-frozen) collections have the following noteworthy +characteristics and limitations: + +- Individual collections are not indexed internally. Which means that even to access a single element of a collection, + the while collection has to be read (and reading one is not paged internally). +- While insertion operations on sets and maps never incur a read-before-write internally, some operations on lists do. + Further, some lists operations are not idempotent by nature (see the section on :ref:`lists ` below for + details), making their retry in case of timeout problematic. It is thus advised to prefer sets over lists when + possible. + +Please note that while some of those limitations may or may not be removed/improved upon in the future, it is a +anti-pattern to use a (single) collection to store large amounts of data. + +.. _maps: + +Maps +~~~~ + +A ``map`` is a (sorted) set of key-value pairs, where keys are unique and the map is sorted by its keys. You can define +and insert a map with:: + + CREATE TABLE users ( + id text PRIMARY KEY, + name text, + favs map // A map of text keys, and text values + ); + + INSERT INTO users (id, name, favs) + VALUES ('jsmith', 'John Smith', { 'fruit' : 'Apple', 'band' : 'Beatles' }); + + // Replace the existing map entirely. + UPDATE users SET favs = { 'fruit' : 'Banana' } WHERE id = 'jsmith'; + +Further, maps support: + +- Updating or inserting one or more elements:: + + UPDATE users SET favs['author'] = 'Ed Poe' WHERE id = 'jsmith'; + UPDATE users SET favs = favs + { 'movie' : 'Cassablanca', 'band' : 'ZZ Top' } WHERE id = 'jsmith'; + +- Removing one or more element (if an element doesn't exist, removing it is a no-op but no error is thrown):: + + DELETE favs['author'] FROM users WHERE id = 'jsmith'; + UPDATE users SET favs = favs - { 'movie', 'band'} WHERE id = 'jsmith'; + + Note that for removing multiple elements in a ``map``, you remove from it a ``set`` of keys. + +Lastly, TTLs are allowed for both ``INSERT`` and ``UPDATE``, but in both case the TTL set only apply to the newly +inserted/updated elements. In other words:: + + UPDATE users USING TTL 10 SET favs['color'] = 'green' WHERE id = 'jsmith'; + +will only apply the TTL to the ``{ 'color' : 'green' }`` record, the rest of the map remaining unaffected. + + +.. _sets: + +Sets +~~~~ + +A ``set`` is a (sorted) collection of unique values. You can define and insert a map with:: + + CREATE TABLE images ( + name text PRIMARY KEY, + owner text, + tags set // A set of text values + ); + + INSERT INTO images (name, owner, tags) + VALUES ('cat.jpg', 'jsmith', { 'pet', 'cute' }); + + // Replace the existing set entirely + UPDATE images SET tags = { 'kitten', 'cat’, 'lol' } WHERE id = 'jsmith'; + +Further, sets support: + +- Adding one or multiple elements (as this is a set, inserting an already existing element is a no-op):: + + UPDATE images SET tags = tags + { 'gray', 'cuddly' } WHERE name = 'cat.jpg'; + +- Removing one or multiple elements (if an element doesn't exist, removing it is a no-op but no error is thrown):: + + UPDATE images SET tags = tags - { 'cat' } WHERE name = 'cat.jpg'; + +Lastly, as for :ref:`maps `, TTLs if used only apply to the newly inserted values. + +.. _lists: + +Lists +~~~~~ + +.. note:: As mentioned above and further discussed at the end of this section, lists have limitations and specific + performance considerations that you should take into account before using them. In general, if you can use a + :ref:`set ` instead of list, always prefer a set. + +A ``list`` is a (sorted) collection of non-unique values where elements are ordered by there position in the list. You +can define and insert a list with:: + + CREATE TABLE plays ( + id text PRIMARY KEY, + game text, + players int, + scores list // A list of integers + ) + + INSERT INTO plays (id, game, players, scores) + VALUES ('123-afde', 'quake', 3, [17, 4, 2]); + + // Replace the existing list entirely + UPDATE plays SET scores = [ 3, 9, 4] WHERE id = '123-afde'; + +Further, lists support: + +- Appending and prepending values to a list:: + + UPDATE plays SET players = 5, scores = scores + [ 14, 21 ] WHERE id = '123-afde'; + UPDATE plays SET players = 6, scores = [ 3 ] + scores WHERE id = '123-afde'; + +- Setting the value at a particular position in the list. This imply that the list has a pre-existing element for that + position or an error will be thrown that the list is too small:: + + UPDATE plays SET scores[1] = 7 WHERE id = '123-afde'; + +- Removing an element by its position in the list. This imply that the list has a pre-existing element for that position + or an error will be thrown that the list is too small. Further, as the operation removes an element from the list, the + list size will be diminished by 1, shifting the position of all the elements following the one deleted:: + + DELETE scores[1] FROM plays WHERE id = '123-afde'; + +- Deleting *all* the occurrences of particular values in the list (if a particular element doesn't occur at all in the + list, it is simply ignored and no error is thrown):: + + UPDATE plays SET scores = scores - [ 12, 21 ] WHERE id = '123-afde'; + +.. warning:: The append and prepend operations are not idempotent by nature. So in particular, if one of these operation + timeout, then retrying the operation is not safe and it may (or may not) lead to appending/prepending the value + twice. + +.. warning:: Setting and removing an element by position and removing occurences of particular values incur an internal + *read-before-write*. They will thus run more slowly and take more ressources than usual updates (with the exclusion + of conditional write that have their own cost). + +Lastly, as for :ref:`maps `, TTLs when used only apply to the newly inserted values. + +.. _udts: + +User-Defined Types +^^^^^^^^^^^^^^^^^^ + +CQL support the definition of user-defined types (UDT for short). Such a type can be created, modified and removed using +the :token:`create_type_statement`, :token:`alter_type_statement` and :token:`drop_type_statement` described below. But +once created, a UDT is simply referred to by its name: + +.. productionlist:: + user_defined_type: `udt_name` + udt_name: [ `keyspace_name` '.' ] `identifier` + + +Creating a UDT +~~~~~~~~~~~~~~ + +Creating a new user-defined type is done using a ``CREATE TYPE`` statement defined by: + +.. productionlist:: + create_type_statement: CREATE TYPE [ IF NOT EXISTS ] `udt_name` + : '(' `field_definition` ( ',' `field_definition` )* ')' + field_definition: `identifier` `cql_type` + +A UDT has a name (used to declared columns of that type) and is a set of named and typed fields. Fields name can be any +type, including collections or other UDT. For instance:: + + CREATE TYPE phone ( + country_code int, + number text, + ) + + CREATE TYPE address ( + street text, + city text, + zip int, + phones map + ) + + CREATE TABLE user ( + name text PRIMARY KEY, + addresses map> + ) + +Note that: + +- Attempting to create an already existing type will result in an error unless the ``IF NOT EXISTS`` option is used. If + it is used, the statement will be a no-op if the type already exists. +- A type is intrinsically bound to the keyspace in which it is created, and can only be used in that keyspace. At + creation, if the type name is prefixed by a keyspace name, it is created in that keyspace. Otherwise, it is created in + the current keyspace. +- As of Cassandra |version|, UDT have to be frozen in most cases, hence the ``frozen
`` in the table definition + above. Please see the section on :ref:`frozen ` for more details. + +UDT literals +~~~~~~~~~~~~ + +Once a used-defined type has been created, value can be input using a UDT literal: + +.. productionlist:: + udt_literal: '{' `identifier` ':' `term` ( ',' `identifier` ':' `term` )* '}' + +In other words, a UDT literal is like a :ref:`map ` literal but its keys are the names of the fields of the type. +For instance, one could insert into the table define in the previous section using:: + + INSERT INTO user (name, addresses) + VALUES ('z3 Pr3z1den7', { + 'home' : { + street: '1600 Pennsylvania Ave NW', + city: 'Washington', + zip: '20500', + phones: { 'cell' : { country_code: 1, number: '202 456-1111' }, + 'landline' : { country_code: 1, number: '...' } } + } + 'work' : { + street: '1600 Pennsylvania Ave NW', + city: 'Washington', + zip: '20500', + phones: { 'fax' : { country_code: 1, number: '...' } } + } + }) + +To be valid, a UDT literal should only include fields defined by the type it is a literal of, but it can omit some field +(in which case those will be ``null``). + +Altering a UDT +~~~~~~~~~~~~~~ + +An existing user-defined type can be modified using an ``ALTER TYPE`` statement: + +.. productionlist:: + alter_type_statement: ALTER TYPE `udt_name` `alter_type_modification` + alter_type_modification: ALTER `identifier` TYPE `cql_type` + : | ADD `field_definition` + : | RENAME `identifier` TO `identifier` ( `identifier` TO `identifier` )* + +You can: + +- modify the type of particular field (``ALTER TYPE address ALTER zip TYPE bigint``). The restrictions for such change + are the same than when :ref:`altering the type of column `. +- add a new field to the type (``ALTER TYPE address ADD country text``). That new field will be ``null`` for any values + of the type created before the addition. +- rename the fields of the type (``ALTER TYPE address RENAME zip TO zipcode``). + +Dropping a UDT +~~~~~~~~~~~~~~ + +You can drop an existing user-defined type using a ``DROP TYPE`` statement: + +.. productionlist:: + drop_type_statement: DROP TYPE [ IF EXISTS ] `udt_name` + +Dropping a type results in the immediate, irreversible removal of that type. However, attempting to drop a type that is +still in use by another type, table or function will result in an error. + +If the type dropped does not exist, an error will be returned unless ``IF EXISTS`` is used, in which case the operation +is a no-op. + +.. _tuples: + +Tuples +^^^^^^ + +CQL also support tuples and tuple types (where the elements can be of different types). Functionally, tuples can be +though as anonymous UDT with anonymous fields. Tuple types and tuple literals are defined by: + +.. productionlist:: + tuple_type: TUPLE '<' `cql_type` ( ',' `cql_type` )* '>' + tuple_literal: '(' `term` ( ',' `term` )* ')' + +and can be used thusly:: + + CREATE TABLE durations ( + event text, + duration tuple, + ) + + INSERT INTO durations (event, duration) VALUES ('ev1', (3, 'hours')); + +Unlike other "composed" types (collections and UDT), a tuple is always :ref:`frozen ` (without the need of the +`frozen` keyword) and it is not possible to update only some elements of a tuple (without updating the whole tuple). +Also, a tuple literal should always have the same number of value than declared in the type it is a tuple of (some of +those values can be null but they need to be explicitly declared as so). + +.. _custom-types: + +Custom Types +^^^^^^^^^^^^ + +.. note:: Custom types exists mostly for backward compatiliby purposes and their usage is discouraged. Their usage is + complex, not user friendly and the other provided types, particularly :ref:`user-defined types `, should almost + always be enough. + +A custom type is defined by: + +.. productionlist:: + custom_type: `string` + +A custom type is a :token:`string` that contains the name of Java class that extends the server side ``AbstractType`` +class and that can be loaded by Cassandra (it should thus be in the ``CLASSPATH`` of every node running Cassandra). That +class will define what values are valid for the type and how the time sorts when used for a clustering column. For any +other purpose, a value of a custom type is the same than that of a ``blob``, and can in particular be input using the +:token:`blob` literal syntax. + + +.. _data-definition: Data Definition --------------- +CQL stores data in *tables*, whose schema defines the layout of said data in the table, and those tables are grouped in +*keyspaces*. A keyspace defines a number of options that applies to all the tables it contains, most prominently of +which is the :ref:`replication strategy ` used by the keyspace. It is generally encouraged to use +one keyspace by *application*, and thus many cluster may define only one keyspace. + +This section describes the statements used to create, modify, and remove those keyspace and tables. + +Common definitions +^^^^^^^^^^^^^^^^^^ + +The names of the keyspaces and tables are defined by the following grammar: + +.. productionlist:: + keyspace_name: `name` + table_name: [ `keyspace_name` '.' ] `name` + name: `unquoted_name` | `quoted_name` + unquoted_name: re('[a-zA-Z_0-9]{1, 48}') + quoted_name: '"' `unquoted_name` '"' + +Both keyspace and table name should be comprised of only alphanumeric characters, cannot be empty and are limited in +size to 48 characters (that limit exists mostly to avoid filenames (which may include the keyspace and table name) to go +over the limits of certain file systems). By default, keyspace and table names are case insensitive (``myTable`` is +equivalent to ``mytable``) but case sensitivity can be forced by using double-quotes (``"myTable"`` is different from +``mytable``). + +Further, a table is always part of a keyspace and a table name can be provided fully-qualified by the keyspace it is +part of. If is is not fully-qualified, the table is assumed to be in the *current* keyspace (see :ref:`USE statement +`). + +We also define the notion of statement options for use in the following section: + +.. productionlist:: + options: `option` ( AND `option` )* + option: `identifier` '=' ( `identifier` | `constant` | `map_literal` ) + +.. _create-keyspace-statement: + CREATE KEYSPACE ^^^^^^^^^^^^^^^ -*Syntax:* +A keyspace is created using a ``CREATE KEYSPACE`` statement: -| bc(syntax).. -| ::= CREATE KEYSPACE (IF NOT EXISTS)? WITH -| p. -| *Sample:* +.. productionlist:: + create_keyspace_statement: CREATE KEYSPACE [ IF NOT EXISTS ] `keyspace_name` WITH `options` -| bc(sample).. -| CREATE KEYSPACE Excelsior -| WITH replication = {’class’: ‘SimpleStrategy’, ‘replication\_factor’ - : 3}; +For instance:: -| CREATE KEYSPACE Excalibur -| WITH replication = {’class’: ‘NetworkTopologyStrategy’, ‘DC1’ : 1, - ‘DC2’ : 3} -| AND durable\_writes = false; -| p. -| The ``CREATE KEYSPACE`` statement creates a new top-level *keyspace*. - A keyspace is a namespace that defines a replication strategy and some - options for a set of tables. Valid keyspaces names are identifiers - composed exclusively of alphanumerical characters and whose length is - lesser or equal to 32. Note that as identifiers, keyspace names are - case insensitive: use a quoted identifier for case sensitive keyspace - names. + CREATE KEYSPACE Excelsior + WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 3}; -The supported ```` for ``CREATE KEYSPACE`` are: + CREATE KEYSPACE Excalibur + WITH replication = {'class': 'NetworkTopologyStrategy', 'DC1' : 1, 'DC2' : 3} + AND durable_writes = false; -+----------------------+------------+-------------+-----------+-------------------------------------------------------------------------------------------------------+ -| name | kind | mandatory | default | description | -+======================+============+=============+===========+=======================================================================================================+ -| ``replication`` | *map* | yes | | The replication strategy and options to use for the keyspace. | -+----------------------+------------+-------------+-----------+-------------------------------------------------------------------------------------------------------+ -| ``durable_writes`` | *simple* | no | true | Whether to use the commit log for updates on this keyspace (disable this option at your own risk!). | -+----------------------+------------+-------------+-----------+-------------------------------------------------------------------------------------------------------+ -The ``replication`` ```` is mandatory. It must at least -contains the ``'class'`` sub-option which defines the replication -strategy class to use. The rest of the sub-options depends on that -replication strategy class. By default, Cassandra support the following -``'class'``: +.. _create-keyspace-options: +The supported ``options`` are: -- ``'SimpleStrategy'``: A simple strategy that defines a simple - replication factor for the whole cluster. The only sub-options - supported is ``'replication_factor'`` to define that replication - factor and is mandatory. -- ``'NetworkTopologyStrategy'``: A replication strategy that allows to - set the replication factor independently for each data-center. The - rest of the sub-options are key-value pairs where each time the key - is the name of a datacenter and the value the replication factor for - that data-center. -- ``'OldNetworkTopologyStrategy'``: A legacy replication strategy. You - should avoid this strategy for new keyspaces and prefer - ``'NetworkTopologyStrategy'``. +=================== ========== =========== ========= =================================================================== +name kind mandatory default description +=================== ========== =========== ========= =================================================================== +``replication`` *map* yes The replication strategy and options to use for the keyspace (see + details below). +``durable_writes`` *simple* no true Whether to use the commit log for updates on this keyspace + (disable this option at your own risk!). +=================== ========== =========== ========= =================================================================== -Attempting to create an already existing keyspace will return an error -unless the ``IF NOT EXISTS`` option is used. If it is used, the -statement will be a no-op if the keyspace already exists. +The ``replication`` property is mandatory and must at least contains the ``'class'`` sub-option which defines the +:ref:`replication strategy ` class to use. The rest of the sub-options depends on what replication +strategy is used. By default, Cassandra support the following ``'class'``: + +- ``'SimpleStrategy'``: A simple strategy that defines a replication factor for the whole cluster. The only sub-options + supported is ``'replication_factor'`` to define that replication factor and is mandatory. +- ``'NetworkTopologyStrategy'``: A replication strategy that allows to set the replication factor independently for + each data-center. The rest of the sub-options are key-value pairs where a key is a data-center name and its value is + the associated replication factor. + +Attempting to create a keyspace that already exists will return an error unless the ``IF NOT EXISTS`` option is used. If +it is used, the statement will be a no-op if the keyspace already exists. + +.. _use-statement: USE ^^^ -*Syntax:* +The ``USE`` statement allows to change the *current* keyspace (for the *connection* on which it is executed). A number +of objects in CQL are bound to a keyspace (tables, user-defined types, functions, ...) and the current keyspace is the +default keyspace used when those objects are referred without a fully-qualified name (that is, without being prefixed a +keyspace name). A ``USE`` statement simply takes the keyspace to use as current as argument: -bc(syntax). ::= USE +.. productionlist:: + use_statement: USE `keyspace_name` -*Sample:* - -bc(sample). USE myApp; - -The ``USE`` statement takes an existing keyspace name as argument and -set it as the per-connection current working keyspace. All subsequent -keyspace-specific actions will be performed in the context of the -selected keyspace, unless `otherwise specified <#statements>`__, until -another USE statement is issued or the connection terminates. +.. _alter-keyspace-statement: ALTER KEYSPACE ^^^^^^^^^^^^^^ -*Syntax:* +An ``ALTER KEYSPACE`` statement allows to modify the options of a keyspace: -| bc(syntax).. -| ::= ALTER KEYSPACE WITH -| p. -| *Sample:* +.. productionlist:: + alter_keyspace_statement: ALTER KEYSPACE `keyspace_name` WITH `options` -| bc(sample).. -| ALTER KEYSPACE Excelsior -| WITH replication = {’class’: ‘SimpleStrategy’, ‘replication\_factor’ - : 4}; +For instance:: -The ``ALTER KEYSPACE`` statement alters the properties of an existing -keyspace. The supported ```` are the same as for the -```CREATE KEYSPACE`` <#createKeyspaceStmt>`__ statement. + ALTER KEYSPACE Excelsior + WITH replication = {’class’: ‘SimpleStrategy’, ‘replication_factor’ : 4}; + +The supported options are the same than for :ref:`creating a keyspace `. + +.. _drop-keyspace-statement: DROP KEYSPACE ^^^^^^^^^^^^^ -*Syntax:* +Dropping a keyspace can be done using the ``DROP KEYSPACE`` statement: -bc(syntax). ::= DROP KEYSPACE ( IF EXISTS )? +.. productionlist:: + drop_keyspace_statement: DROP KEYSPACE [ IF EXISTS ] `keyspace_name` -*Sample:* +For instance:: -bc(sample). DROP KEYSPACE myApp; + DROP KEYSPACE Excelsior; -A ``DROP KEYSPACE`` statement results in the immediate, irreversible -removal of an existing keyspace, including all column families in it, -and all data contained in those column families. +Dropping a keyspace results in the immediate, irreversible removal of that keyspace, including all the tables, UTD and +functions in it, and all the data contained in those tables. -If the keyspace does not exists, the statement will return an error, -unless ``IF EXISTS`` is used in which case the operation is a no-op. +If the keyspace does not exists, the statement will return an error, unless ``IF EXISTS`` is used in which case the +operation is a no-op. + +.. _create-table-statement: CREATE TABLE ^^^^^^^^^^^^ -*Syntax:* +Creating a new table uses the ``CREATE TABLE`` statement: -| bc(syntax).. -| ::= CREATE ( TABLE \| COLUMNFAMILY ) ( IF NOT EXISTS )? -| ‘(’ ( ‘,’ )\* ‘)’ -| ( WITH ( AND )\* )? +.. productionlist:: + create_table_statement: CREATE TABLE [ IF NOT EXISTS ] `table_name` + : '(' + : `column_definition` + : ( ',' `column_definition` )* + : [ ',' PRIMARY KEY '(' `primary_key` ')' ] + : ')' [ WITH `table_options` ] + column_definition: `identifier` `cql_type` [ STATIC ] [ PRIMARY KEY] + primary_key: `partition_key` [ ',' `clustering_columns` ] + partition_key: `identifier` + : | '(' `identifier` ( ',' `identifier` )* ')' + clustering_columns: `identifier` ( ',' `identifier` )* + table_options: COMPACT STORAGE [ AND `table_options` ] + : | CLUSTERING ORDER BY '(' `clustering_order` ')' [ AND `table_options` ] + : | `options` + clustering_order: `identifier` (ASC | DESC) ( ',' `identifier` (ASC | DESC) )* -| ::= ( STATIC )? ( PRIMARY KEY )? -| \| PRIMARY KEY ‘(’ ( ‘,’ )\* ‘)’ +For instance:: -| ::= -| \| ‘(’ (‘,’ )\* ‘)’ + CREATE TABLE monkeySpecies ( + species text PRIMARY KEY, + common_name text, + population varint, + average_size int + ) WITH comment=‘Important biological records’ + AND read_repair_chance = 1.0; -| ::= -| \| COMPACT STORAGE -| \| CLUSTERING ORDER -| p. -| *Sample:* + CREATE TABLE timeline ( + userid uuid, + posted_month int, + posted_time uuid, + body text, + posted_by text, + PRIMARY KEY (userid, posted_month, posted_time) + ) WITH compaction = { ‘class’ : ‘LeveledCompactionStrategy’ }; -| bc(sample).. -| CREATE TABLE monkeySpecies ( -| species text PRIMARY KEY, -| common\_name text, -| population varint, -| average\_size int -| ) WITH comment=‘Important biological records’ -| AND read\_repair\_chance = 1.0; + CREATE TABLE loads ( + machine inet, + cpu int, + mtime timeuuid, + load float, + PRIMARY KEY ((machine, cpu), mtime) + ) WITH CLUSTERING ORDER BY (mtime DESC); -| CREATE TABLE timeline ( -| userid uuid, -| posted\_month int, -| posted\_time uuid, -| body text, -| posted\_by text, -| PRIMARY KEY (userid, posted\_month, posted\_time) -| ) WITH compaction = { ‘class’ : ‘LeveledCompactionStrategy’ }; -| p. -| The ``CREATE TABLE`` statement creates a new table. Each such table is - a set of *rows* (usually representing related entities) for which it - defines a number of properties. A table is defined by a - `name <#createTableName>`__, it defines the columns composing rows of - the table and have a number of `options <#createTableOptions>`__. Note - that the ``CREATE COLUMNFAMILY`` syntax is supported as an alias for - ``CREATE TABLE`` (for historical reasons). +A CQL table has a name and is composed of a set of *rows*. Creating a table amounts to defining which :ref:`columns +` the rows will be composed, which of those columns compose the :ref:`primary key `, as +well as optional :ref:`options ` for the table. -Attempting to create an already existing table will return an error -unless the ``IF NOT EXISTS`` option is used. If it is used, the -statement will be a no-op if the table already exists. +Attempting to create an already existing table will return an error unless the ``IF NOT EXISTS`` directive is used. If +it is used, the statement will be a no-op if the table already exists. -```` -^^^^^^^^^^^^^^^ -Valid table names are the same as valid `keyspace -names <#createKeyspaceStmt>`__ (up to 32 characters long alphanumerical -identifiers). If the table name is provided alone, the table is created -within the current keyspace (see \ ``USE``\ ), but if it is prefixed by -an existing keyspace name (see ````` <#statements>`__ -grammar), it is created in the specified keyspace (but does **not** -change the current keyspace). +.. _column-definition: -```` -^^^^^^^^^^^^^^^^^^^^^^^ +Column definitions +~~~~~~~~~~~~~~~~~~ -A ``CREATE TABLE`` statement defines the columns that rows of the table -can have. A *column* is defined by its name (an identifier) and its type -(see the `data types <#types>`__ section for more details on allowed -types and their properties). +Every rows in a CQL table has a set of predefined columns defined at the time of the table creation (or added later +using an :ref:`alter statement`). -Within a table, a row is uniquely identified by its ``PRIMARY KEY`` (or -more simply the key), and hence all table definitions **must** define a -PRIMARY KEY (and only one). A ``PRIMARY KEY`` is composed of one or more -of the columns defined in the table. If the ``PRIMARY KEY`` is only one -column, this can be specified directly after the column definition. -Otherwise, it must be specified by following ``PRIMARY KEY`` by the -comma-separated list of column names composing the key within -parenthesis. Note that: +A :token:`column_definition` is primarily comprised of the name of the column defined and it's :ref:`type `, +which restrict which values are accepted for that column. Additionally, a column definition can have the following +modifiers: -| bc(sample). -| CREATE TABLE t ( -| k int PRIMARY KEY, -| other text -| ) +``STATIC`` + it declares the column as being a :ref:`static column `. -is equivalent to +``PRIMARY KEY`` + it declares the column as being the sole component of the :ref:`primary key ` of the table. -| bc(sample). -| CREATE TABLE t ( -| k int, -| other text, -| PRIMARY KEY (k) -| ) +.. _static-columns: -Partition key and clustering columns -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Static columns +`````````````` +Some columns can be declared as ``STATIC`` in a table definition. A column that is static will be “shared” by all the +rows belonging to the same partition (having the same :ref:`partition key `). For instance:: -In CQL, the order in which columns are defined for the ``PRIMARY KEY`` -matters. The first column of the key is called the *partition key*. It -has the property that all the rows sharing the same partition key (even -across table in fact) are stored on the same physical node. Also, -insertion/update/deletion on rows sharing the same partition key for a -given table are performed *atomically* and in *isolation*. Note that it -is possible to have a composite partition key, i.e. a partition key -formed of multiple columns, using an extra set of parentheses to define -which columns forms the partition key. + CREATE TABLE t ( + pk int, + t int, + v text, + s text static, + PRIMARY KEY (pk, t) + ); -The remaining columns of the ``PRIMARY KEY`` definition, if any, are -called \_\_clustering columns. On a given physical node, rows for a -given partition key are stored in the order induced by the clustering -columns, making the retrieval of rows in that clustering order -particularly efficient (see \ ``SELECT``\ ). + INSERT INTO t (pk, t, v, s) VALUES (0, 0, 'val0', 'static0'); + INSERT INTO t (pk, t, v, s) VALUES (0, 1, 'val1', 'static1'); -``STATIC`` columns -^^^^^^^^^^^^^^^^^^ + SELECT * FROM t; + pk | t | v | s + ----+---+--------+----------- + 0 | 0 | 'val0' | 'static1' + 0 | 1 | 'val1' | 'static1' -Some columns can be declared as ``STATIC`` in a table definition. A -column that is static will be “shared” by all the rows belonging to the -same partition (having the same partition key). For instance, in: +As can be seen, the ``s`` value is the same (``static1``) for both of the row in the partition (the partition key in +that example being ``pk``, both rows are in that same partition): the 2nd insertion has overridden the value for ``s``. -| bc(sample). -| CREATE TABLE test ( -| pk int, -| t int, -| v text, -| s text static, -| PRIMARY KEY (pk, t) -| ); -| INSERT INTO test(pk, t, v, s) VALUES (0, 0, ‘val0’, ‘static0’); -| INSERT INTO test(pk, t, v, s) VALUES (0, 1, ‘val1’, ‘static1’); -| SELECT \* FROM test WHERE pk=0 AND t=0; +The use of static columns as the following restrictions: -the last query will return ``'static1'`` as value for ``s``, since ``s`` -is static and thus the 2nd insertion modified this “shared” value. Note -however that static columns are only static within a given partition, -and if in the example above both rows where from different partitions -(i.e. if they had different value for ``pk``), then the 2nd insertion -would not have modified the value of ``s`` for the first row. +- tables with the ``COMPACT STORAGE`` option (see below) cannot use them. +- a table without clustering columns cannot have static columns (in a table without clustering columns, every partition + has only one row, and so every column is inherently static). +- only non ``PRIMARY KEY`` columns can be static. -A few restrictions applies to when static columns are allowed: +.. _primary-key: -- tables with the ``COMPACT STORAGE`` option (see below) cannot have - them -- a table without clustering columns cannot have static columns (in a - table without clustering columns, every partition has only one row, - and so every column is inherently static). -- only non ``PRIMARY KEY`` columns can be static +The Primary key +~~~~~~~~~~~~~~~ -``