CompanyOctober 29, 2015

DataStax C/C++ Driver: 2.2 GA released!

Michael Penick
Michael PenickDataStax
DataStax C/C++ Driver: 2.2 GA released!

We are pleased to announce the 2.2 GA release of the C/C++ driver for Apache Cassandra. This release includes all the features necessary to take full advantage of Apache Cassandra 2.2 including support for new data types ('tinyint', 'smallint', 'time', and 'date') and support for user defined function/aggregate (UDF/UDA) schema metadata. In addition to 2.2 features the release also brings with it the whitelist load balancing policy, a streamlined schema metadata API, and several internal improvements.

What's new

New data types

'tinyint' and 'smallint' can be used in cases where a smaller range would be a better fit than 'int' or 'bigint'.

CREATE TABLE integers (key text PRIMARY KEY,
                       tiny tinyint,
                       small smallint);

INSERTing the new 'tinyint' and 'smallint' types

CassStatement* statement = cass_statement_new("INSERT INTO integers (key, tiny, small)
                                              "VALUES (?, ?, ?)"
);

cass_statement_bind_string(statement, "abc");

/* 'tinyint' is a signed 8-bit integer. It can represent values between -128 and 127 */
cass_statement_bind_int8(statement, 127);

/* 'smallint' is a signed 16-bit integer. It can represent values between -32768 and 32767 */
cass_statement_bind_int16(statement, 32767);

CassFuture* future = cass_session_execute(session, statement);

/* Handle future result */

/* CassStatement and CassFuture both need to be freed */
cass_statement_free(statement);
cass_future_free(future);

The 'date' type uses an unsigned 32-bit integer (cass_uint32_t) to represent the number of days with Epoch (January 1, 1970) centered at 2^31. Because it's centered at Epoch it can be used to represent days before Epoch. The 'time' type uses a signed 64-bit integer (cass_int64_t) to represent the number of nanoseconds since midnight and valid values are in the range 0 to 86399999999999. The following examples both use this schema:

CREATE TABLE date_time (key text PRIMARY KEY,
                        year_month_day date,
                        time_of_day time);

INSERTing the new 'date' and 'time' types

#include <time.h>

/* ... */

CassStatement* statement = cass_statement_new("INSERT INTO date_time (key, year_month_day, time_of_day) "
                                              "VALUES (?, ?, ?)"
);

time_t
now = time(NULL); /* Time in seconds from Epoch */

/* Converts the time since the Epoch in seconds to the 'date' type */
cass_uint_32_t year_month_day = cass_date_from_epoch(now);

/* Converts the time since the Epoch in seconds to the 'time' type */
cass_int64_t time_of_day = cass_time_from_epoch(now);

cass_statement_bind_string(statement, 0, "xyz");

/* 'date' uses an unsigned 32-bit integer */
cass_statement_bind_uint32(statement, 1, year_month_day);

/* 'time' uses a signed 64-bit integer */
cass_statement_bind_int64(statement, 2, time_of_day)

CassFuture* future = cass_session_execute(session, statement);

/* Handle future result */

/* CassStatement and CassFuture both need to be freed */
cass_statement_free(statement);
cass_future_free(future);

SELECTing the new 'date' and 'time' types

#include <time.h>

/* ... */

CassStatement* statement = cass_statement_new("SELECT * FROM examples.date_time WHERE key = ?");

CassFuture* future = cass_session_execute(session, statement);

const
CassResult* result = cass_future_get_result(future);
/* Make sure there's a valid result */
if
(result != NULL && cass_result_row_count(resut) > 0) {
  const
CassRow* row = cass_result_first_row(result);

  /* Get the value of the "year_month_day" column */
  cass_uint32_t year_month_day;
  cass_value_get_uint32(cass_row_get_column(row, 1), &year_month_day);

  /* Get the value of the "time_of_day" column */
  cass_int64_t time_of_day
  cass_value_get_int64(cass_row_get_column(row, 2), &time_of_day);

  /* Convert 'date' and 'time' to Epoch time */
  time_t
time = (time_t)cass_date_time_to_epoch(year_month_day, time_of_day);
  printf
("Date and time: %s", asctime(localtime(&time)))
} else
{
  /* Handle error */
}

/* CassStatement and CassFuture both need to be freed */
cass_statement_free(statement);
cass_future_free(future);

Whitelist load balancing policy

By default the driver auto-discovers and connects to all the nodes in a Cassandra cluster. The whitelist load balancing policy can override this behavior by only connecting to a predefined set of hosts. This policy is useful for testing or debugging and is not optimal for production deployments. If the goal is to limit connections to a local data center then use the data center aware load balancing policy (cass_cluster_set_load_balance_dc_aware()).

CassCluster* cluster = cass_cluster_new();

/* Enable a whitelist by setting a comma-delimited lists of hosts */
cass_cluster_set_whitelist_filtering(cluster, "127.0.0.1, 127.0.0.2, ..."
);

CassFuture* future = cass_session_connect(session, cluster);

/* ... */

cass_future_free(future);
cass_cluster_free(cluster);

New schema metadata API

This release improves the schema metadata API by adding concrete types for each of the different metadata types (CassKeyspaceMetaCassTableMeta and CassColumnMeta) instead of the single CassSchemaMeta type used in the previous API. This allows for specific functions to handle each of the metadata types and better represents the metadata hierarchy i.e. user types, functions and aggregates metadata now live under the keyspace metadata. Applications that used the previous schema metadata API will require some small modifications to use the new API.

Retrieving a user defined type using the new API

/* Obtain a snapshot of the schema from the session */
const
CassSchemaMeta* schema_meta = cass_session_get_schema_meta(session);

/* There is no need to free metadata types derived from the snapshot. Their lifetime's are bound
 * the snapshot.
 */
const
CassKeyspaceMeta* keyspace_meta = cass_schema_meta_keyspace_by_name(schema_meta, "some_keyspace");

 if
(keyspace_meta != NULL) {
  const
CassDataType* some_user_type = cass_keyspace_meta_user_type_by_name(keyspace_meta, "some_user_type");

  /* Use user type */
 }
else {
   /* Handle error */
 }

/* Only the snapshot needs to be freed */
cass_schema_meta_free(schema_meta);

A more complete example of using the new schema metadata API can be found here.

User function's and user aggregate's metadata

Cassandra 2.2 added user defined function (UDF) and aggregates (UDA). The 2.2 release of the C/C++ driver adds support to inspect the metadata of these new types.

Retrieving and printing UDF metadata

USE keyspace1;

CREATE FUNCTION multiplyBy (x int, n int)
RETURNS NULL ON NULL INPUT
RETURNS int LANGUAGE javascript AS 'x * n';

/* Obtain a snapshot of the schema metadata */
const
CassSchemaMeta* schema_meta
  = cass_session_get_schema_meta(session);

/* Search for the function's keyspace by name */
const
CassKeyspaceMeta* keyspace_meta
  = cass_schema_meta_keyspace_by_name(schema_meta,
"keyspace1");

/* Search for the function by name and argument types (overloads are possible) */
const
CassFunctionMeta* function_meta
  = cass_keyspace_meta_function_by_name(keyspace_meta,
"multiplyBy", "int, int");

/* Inspect the function's metadata */

const
char* full_name;
size_t
full_name_length;
cass_function_meta_full_name(function_meta, &full_name, &full_name_length);

const
CassDataType* arg1_type = cass_function_meta_type_by_name(function_meta, "x");

const
CassDataType* arg2_type = cass_function_meta_type_by_name(function_meta, "m");

const
CassDataType* return_type = cass_function_meta_return_type(function_meta);

/* ... */

/* Only the snapshot needs to be freed */
cass_schema_meta_free(schema_meta);

Retrieving and printing UDA metadata

USE keyspace1;

CREATE OR REPLACE FUNCTION avgState ( state tuple<int,bigint>, val int ) CALLED ON
NULL INPUT RETURNS tuple<int,bigint> LANGUAGE java AS

 


  'if (val !=null) { state.setInt(0, state.getInt(0)+1); state.setLong(1,
state.getLong(1)+val.intValue()); } return state;';

CREATE OR REPLACE FUNCTION avgFinal ( state tuple<int,bigint> ) CALLED ON NULL INPUT
RETURNS double LANGUAGE java AS

  'double r = 0; if (state.getInt(0) == 0) return null; r = state.getLong(1); r/=
state.getInt(0); return Double.valueOf(r);';

CREATE AGGREGATE IF NOT EXISTS average ( int )
  SFUNC avgState STYPE tuple<int,bigint> FINALFUNC avgFinal INITCOND (0,0);

 

/* Obtain a snapshot of the schema metadata */
const
CassSchemaMeta* schema_meta
  = cass_session_get_schema_meta(session);

/* Search for the aggregate's keyspace by name */
const
CassKeyspaceMeta* keyspace_meta
 = cass_schema_meta_keyspace_by_name(schema_meta,
"keyspace1");

/* Search for the aggregate by name and argument types (overloads are possible) */
const
CassAggregateMeta* aggregate_meta
  = cass_keyspace_meta_aggregate_by_name(keyspace_meta,
"multiplyBy", "int, int");

/* Inspect the aggregate's metadata */

const
char* full_name;
size_t
full_name_length;
cass_aggregate_meta_full_name(aggregate, &full_name, &full_name_length);

const
CassFunctionMeta* avg_state_func = cass_aggregate_meta_state_func(aggregate_meta);

const CassFunctionMeta* avg_final_func = cass_aggregate_meta_final_func(aggregate_meta);

const
CassDataType* state_type = cass_aggregate_meta_state_type(aggregate_meta);

const
CassDataType* return_type = cass_aggregate_meta_return_type(aggregate_meta);

const
CassValue* init_cond = cass_aggregate_meta_init_cond(aggregate_meta);

/* ... */

/* Only the snapshot needs to be freed */

cass_schema_meta_free(schema_meta);

Internal improvements

This release also includes the following internal improvements:

  • The default consistency is now LOCAL_QUORUM instead of ONE
  • Improved the performance of string to/from conversion UUID functions
  • Support for server-side warnings that are logged at the CASS_LOG_WARN level

Looking forward

This release brings with it full support for Apache Cassandra 2.2 along with many other great features. In the next release we will be focusing our efforts on supporting Apache Cassandra 3.0. Let us know what you think about the 2.2 GA release. Your feedback is important to us and it influences what features we prioritize. To provide feedback use the following:

Discover more
DriversC++
Share

One-stop Data API for Production GenAI

Astra DB gives JavaScript developers a complete data API and out-of-the-box integrations that make it easier to build production RAG apps with high relevancy and low latency.