Lightweight Transactions (Compare-and-set)

Lightweight Transactions (LWTs) are mostly pass-through CQL for the driver. However, the server returns some specialized results indicating the outcome and optional state preceding the transaction.

For pertinent execution parameters, see Statement.serial_consistency_level.

This section discusses working with specialized result sets returned by the server for LWTs, and how to work with them using the driver.

Specialized Results

The result returned from a LWT request is always a single row result. It will always have prepended a special column named [applied]. How this value appears in your results depends on the row factory in use. See below for examples.

The value of this [applied] column is boolean value indicating whether or not the transaction was applied. If True, it is the only column in the result. If False, the additional columns depend on the LWT operation being executed:

  • When using a UPDATE ... IF "col" = ... clause, the result will contain the [applied] column, plus the existing columns and values for any columns in the IF clause (and thus the value that caused the transaction to fail).
  • When using INSERT ... IF NOT EXISTS, the result will contain the [applied] column, plus all columns and values of the existing row that rejected the transaction.
  • UPDATE .. IF EXISTS never has additional columns, regardless of [applied] status.

How the [applied] column manifests depends on the row factory in use. Considering the following (initially empty) table:

CREATE TABLE test.t (
    k int PRIMARY KEY,
    v int,
    x int
)

... the following sections show the expected result for a number of example statements, using the three base row factories.

named_tuple_factory (default)

The name [applied] is not a valid Python identifier, so the square brackets are actually removed from the attribute for the resulting namedtuple. The row always has a boolean column applied in position 0:

>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
Row(applied=True)

>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
Row(applied=False, k=0, v=0, x=None)

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0")
Row(applied=True)

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0 AND x = 1")
Row(applied=False, v=1, x=2)

tuple_factory

This return type does not refer to names, but the boolean value applied is always present in position 0:

>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
(True,)

>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
(False, 0, 0, None)

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0")
(True,)

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0 AND x = 1")
(False, 1, 2)

dict_factory

The retuned dict contains the [applied] key:

>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
{u'[applied]': True}

>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
{u'x': 2, u'[applied]': False, u'v': 1}

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0")
{u'x': None, u'[applied]': False, u'k': 0, u'v': 0}

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0 AND x = 1")
{u'[applied]': True}