Prepared statements

Prepared statements are used to prepare a write query only once and execute it multiple times with different values. A bind variable marker ? is used to represent a dynamic value in a statement.

The driver caches prepared statement id’s in such a way that when a query is to be prepared for a node, the “preparation” is bypassed if the statement has previously been prepared on any other node. This reduces a round-trip to the node while also optimizing query execution performance.

An INSERT statement is prepared

Given
a running cassandra cluster with schema:
CREATE KEYSPACE simplex WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
CREATE TABLE simplex.playlists (
  id uuid,
  title text,
  album text,
  artist text,
  song_id uuid,
  PRIMARY KEY (id, title, album, artist)
);
And
the following example:
require 'cassandra'

cluster = Cassandra.cluster
session = cluster.connect("simplex")
insert  = session.prepare(
            "INSERT INTO playlists (id, song_id, title, artist, album) " \
            "VALUES (62c36092-82a1-3a00-93d1-46196ee77204, ?, ?, ?, ?)"
          )

songs = [
  {
    :id     => Cassandra::Uuid.new('756716f7-2e54-4715-9f00-91dcbea6cf50'),
    :title  => 'La Petite Tonkinoise',
    :album  => 'Bye Bye Blackbird',
    :artist => 'Joséphine Baker'
  },
  {
    :id     => Cassandra::Uuid.new('f6071e72-48ec-4fcb-bf3e-379c8a696488'),
    :title  => 'Die Mösch',
    :album  => 'In Gold',
    :artist => 'Willi Ostermann'
  },
  {
    :id     => Cassandra::Uuid.new('fbdf82ed-0063-4796-9c7c-a3d4f47b4b25'),
    :title  => 'Memo From Turner',
    :album  => 'Performance',
    :artist => 'Mick Jager'
  },
]

songs.each do |song|
  session.execute(insert, arguments: [song[:id], song[:title], song[:artist], song[:album]], consistency: :all)
end

session.execute("SELECT * FROM playlists").each do |row|
  puts("#{row["artist"]}: #{row["title"]} / #{row["album"]}")
end
When
it is executed
Then
its output should contain:
Joséphine Baker: La Petite Tonkinoise / Bye Bye Blackbird
And
its output should contain:
Willi Ostermann: Die Mösch / In Gold
And
its output should contain:
Mick Jager: Memo From Turner / Performance
since cassadra v2.1

An INSERT statement is prepared with named parameters

Given
a running cassandra cluster with schema:
  CREATE KEYSPACE simplex WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
  CREATE TABLE simplex.playlists (
    id uuid,
    title text,
    album text,
    artist text,
    song_id uuid,
    PRIMARY KEY (id, title, album, artist)
  );
And
the following example:
  require 'cassandra'

  cluster = Cassandra.cluster
  session = cluster.connect("simplex")
  insert  = session.prepare(
              "INSERT INTO playlists (id, song_id, title, artist, album) " \
              "VALUES (62c36092-82a1-3a00-93d1-46196ee77204, :a, :b, :c, :d)"
            )

  songs = [
    {
      :id     => Cassandra::Uuid.new('756716f7-2e54-4715-9f00-91dcbea6cf50'),
      :title  => 'La Petite Tonkinoise',
      :album  => 'Bye Bye Blackbird',
      :artist => 'Joséphine Baker'
    },
    {
      :id     => Cassandra::Uuid.new('f6071e72-48ec-4fcb-bf3e-379c8a696488'),
      :title  => 'Die Mösch',
      :album  => 'In Gold',
      :artist => 'Willi Ostermann'
    },
    {
      :id     => Cassandra::Uuid.new('fbdf82ed-0063-4796-9c7c-a3d4f47b4b25'),
      :title  => 'Memo From Turner',
      :album  => 'Performance',
      :artist => 'Mick Jager'
    },
  ]

  songs.each do |song|
    session.execute(insert, arguments: {:a => song[:id], :b => song[:title], :c => song[:artist], :d => song[:album]}, consistency: :all)
  end

  session.execute("SELECT * FROM playlists").each do |row|
    puts("#{row["artist"]}: #{row["title"]} / #{row["album"]}")
  end
When
it is executed
Then
its output should contain:
Joséphine Baker: La Petite Tonkinoise / Bye Bye Blackbird
And
its output should contain:
Willi Ostermann: Die Mösch / In Gold
And
its output should contain:
Mick Jager: Memo From Turner / Performance
since cassadra v2.0

A SELECT statement with parameterized LIMIT is prepared

Given
a running cassandra cluster with schema:
CREATE KEYSPACE simplex WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
CREATE TABLE simplex.playlists (
  id uuid,
  title text,
  album text,
  artist text,
  song_id uuid,
  PRIMARY KEY (id, title, album, artist)
);
INSERT INTO simplex.playlists (id, song_id, title, album, artist)
VALUES (
   2cc9ccb7-6221-4ccb-8387-f22b6a1b354d,
   756716f7-2e54-4715-9f00-91dcbea6cf50,
   'La Petite Tonkinoise',
   'Bye Bye Blackbird',
   'Joséphine Baker'
);
INSERT INTO simplex.playlists (id, song_id, title, album, artist)
VALUES (
   2cc9ccb7-6221-4ccb-8387-f22b6a1b354d,
   f6071e72-48ec-4fcb-bf3e-379c8a696488,
   'Die Mösch',
   'In Gold',
   'Willi Ostermann'
);
INSERT INTO simplex.playlists (id, song_id, title, album, artist)
VALUES (
   3fd2bedf-a8c8-455a-a462-0cd3a4353c54,
   fbdf82ed-0063-4796-9c7c-a3d4f47b4b25,
   'Memo From Turner',
   'Performance',
   'Mick Jager'
);
INSERT INTO simplex.playlists (id, song_id, title, album, artist)
VALUES (
   3fd2bedf-a8c8-455a-a462-0cd3a4353c54,
   756716f7-2e54-4715-9f00-91dcbea6cf50,
   'La Petite Tonkinoise',
   'Bye Bye Blackbird',
   'Joséphine Baker'
);
And
the following example:
require 'cassandra'

cluster = Cassandra.cluster
session = cluster.connect("simplex")
select  = session.prepare("SELECT * FROM playlists LIMIT ?")
limits  = [1, 2, 3]

limits.each do |limit|
  rows = session.execute(select, arguments: [limit])
  puts "selected #{rows.size} row(s)"
end
When
it is executed
Then
its output should contain:
selected 1 row(s)
selected 2 row(s)
selected 3 row(s)
since cassadra v2.2

Unbound arguments are ignored

Given
a running cassandra cluster with schema:
  CREATE KEYSPACE simplex WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
  CREATE TABLE simplex.playlists (
    id uuid PRIMARY KEY,
    title text,
    album text,
    artist text,
    song_id uuid
  );
And
the following example:
  require 'cassandra'

  cluster = Cassandra.cluster
  session = cluster.connect("simplex")

  insert  = session.prepare("INSERT INTO playlists (id, song_id, title, artist, album) VALUES (" \
                            "62c36092-82a1-3a00-93d1-46196ee77204, :id, :title, :artist, :album)"
            )

  session.execute(insert, arguments: { title: 'La Petite Tonkinoise', album: 'Bye Bye Blackbird' })

  session.execute(insert, arguments: { artist: 'Joséphine Baker' })

  playlist = session.execute("SELECT * FROM playlists WHERE id=62c36092-82a1-3a00-93d1-46196ee77204",
                             consistency: :all).first

  puts("#{playlist["artist"]}: #{playlist["title"]} / #{playlist["album"]}")
When
it is executed
Then
its output should contain:
Joséphine Baker: La Petite Tonkinoise / Bye Bye Blackbird
since cassadra v2.2

Unbound arguments can be explicitly provided

Given
a running cassandra cluster with schema:
  CREATE KEYSPACE simplex WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
  CREATE TABLE simplex.playlists (
    id uuid PRIMARY KEY,
    title text,
    album text,
    artist text,
    song_id uuid
  );
And
the following example:
  require 'cassandra'

  cluster = Cassandra.cluster
  session = cluster.connect("simplex")

  insert  = session.prepare("INSERT INTO playlists (id, song_id, title, artist, album) VALUES (" \
                            "62c36092-82a1-3a00-93d1-46196ee77204, :id, :title, :artist, :album)"
            )

  session.execute(insert, arguments: { title: 'La Petite Tonkinoise', album: 'Bye Bye Blackbird' })

  session.execute(insert, arguments: { title: Cassandra::NOT_SET, album: Cassandra::NOT_SET,
                                      artist: 'Joséphine Baker', song_id: Cassandra::NOT_SET })

  playlist = session.execute("SELECT * FROM playlists WHERE id=62c36092-82a1-3a00-93d1-46196ee77204",
                             consistency: :all).first

  puts("#{playlist["artist"]}: #{playlist["title"]} / #{playlist["album"]}")
When
it is executed
Then
its output should contain:
Joséphine Baker: La Petite Tonkinoise / Bye Bye Blackbird