[Commits] Rev 3504: Cassandra SE in file:///data0/psergey/dev2/5.5-cassandra-r01/

Sergey Petrunya psergey at askmonty.org
Fri Aug 31 09:49:37 EEST 2012


At file:///data0/psergey/dev2/5.5-cassandra-r01/

------------------------------------------------------------
revno: 3504
revision-id: psergey at askmonty.org-20120831064936-4ceo6hdr6hror7fl
parent: psergey at askmonty.org-20120829162711-cdqfvic3os2rkd0o
committer: Sergey Petrunya <psergey at askmonty.org>
branch nick: 5.5-cassandra-r01
timestamp: Fri 2012-08-31 10:49:36 +0400
message:
  Cassandra SE
  - add support for Cassandra's UUID datatype. We map it to CHAR(36).
=== modified file 'mysql-test/r/cassandra.result'
--- a/mysql-test/r/cassandra.result	2012-08-29 16:27:11 +0000
+++ b/mysql-test/r/cassandra.result	2012-08-31 06:49:36 +0000
@@ -226,3 +226,37 @@
 delete from t2;
 drop table t2;
 drop table t0;
+# 
+# UUID datatype support
+#
+CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36)) ENGINE=CASSANDRA
+thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
+delete from t2;
+insert into t2 values(1,'9b5658dc-f32f-11e1-94cd-f46d046e9f09');
+insert into t2 values(2,'not-an-uuid');
+ERROR 22003: Out of range value for column 'uuidcol' at row 1
+insert into t2 values(3,'9b5658dc-f32f-11e1=94cd-f46d046e9f09');
+ERROR 22003: Out of range value for column 'uuidcol' at row 1
+insert into t2 values(4,'9b5658dc-fzzf-11e1-94cd-f46d046e9f09');
+ERROR 22003: Out of range value for column 'uuidcol' at row 1
+insert into t2 values
+(5,'9b5658dc-f11f-11e1-94cd-f46d046e9f09'),
+(6,'9b5658dc-f11f011e1-94cd-f46d046e9f09');
+ERROR 22003: Out of range value for column 'uuidcol' at row 2
+select * from t2;
+rowkey	uuidcol
+1	9b5658dc-f32f-11e1-94cd-f46d046e9f09
+5	9b5658dc-f11f-11e1-94cd-f46d046e9f09
+delete from t2;
+drop table t2;
+CREATE TABLE t2 (rowkey char(36) PRIMARY KEY, col1 int) ENGINE=CASSANDRA
+thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf6';
+delete from t2;
+insert into t2 values('9b5658dc-f32f-11e1-94cd-f46d046e9f09', 1234);
+insert into t2 values('not-an-uuid', 563);
+ERROR 22003: Out of range value for column 'rowkey' at row 1
+select * from t2;
+rowkey	col1
+9b5658dc-f32f-11e1-94cd-f46d046e9f09	1234
+delete from t2;
+drop table t2;

=== modified file 'mysql-test/t/cassandra.test'
--- a/mysql-test/t/cassandra.test	2012-08-29 16:27:11 +0000
+++ b/mysql-test/t/cassandra.test	2012-08-31 06:49:36 +0000
@@ -49,6 +49,10 @@
 
 create columnfamily cf4 (rowkey bigint primary key, datecol timestamp);
 
+create columnfamily cf5 (rowkey bigint primary key, uuidcol uuid);
+
+create columnfamily cf6 (rowkey uuid primary key, col1 int);
+
 ./cassandra-cli 
 
 CREATE COLUMN FAMILY cf10
@@ -277,12 +281,57 @@
 drop table t2;
 drop table t0;
 
+--echo # 
+--echo # UUID datatype support
+--echo #
+#create columnfamily cf5 (rowkey bigint primary key, uuidcol uuid);
+CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36)) ENGINE=CASSANDRA
+  thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
+delete from t2;
+
+insert into t2 values(1,'9b5658dc-f32f-11e1-94cd-f46d046e9f09');
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+insert into t2 values(2,'not-an-uuid');
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+insert into t2 values(3,'9b5658dc-f32f-11e1=94cd-f46d046e9f09');
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+insert into t2 values(4,'9b5658dc-fzzf-11e1-94cd-f46d046e9f09');
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+insert into t2 values
+ (5,'9b5658dc-f11f-11e1-94cd-f46d046e9f09'),
+ (6,'9b5658dc-f11f011e1-94cd-f46d046e9f09');
+
+select * from t2;
+
+delete from t2;
+drop table t2;
+
+# create columnfamily cf6 (rowkey uuid primary key, col1 int);
+CREATE TABLE t2 (rowkey char(36) PRIMARY KEY, col1 int) ENGINE=CASSANDRA
+  thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf6';
+delete from t2;
+
+insert into t2 values('9b5658dc-f32f-11e1-94cd-f46d046e9f09', 1234);
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+insert into t2 values('not-an-uuid', 563);
+
+select * from t2;
+delete from t2;
+drop table t2;
+
 ############################################################################
 ## Cassandra cleanup
 ############################################################################
 --disable_parsing
 drop columnfamily cf1;
 drop columnfamily cf2;
+drop columnfamily cf3;
+drop columnfamily cf4;
 --enable_parsing
 ############################################################################
 ## Cassandra cleanup ends

=== modified file 'storage/cassandra/cassandra_se.cc'
--- a/storage/cassandra/cassandra_se.cc	2012-08-29 16:27:11 +0000
+++ b/storage/cassandra/cassandra_se.cc	2012-08-31 06:49:36 +0000
@@ -416,9 +416,8 @@
   cparent.column_family= column_family;
   
   /* SlicePredicate can be used to limit columns we will retrieve */
-   // Try passing nothing...
 
-  KeyRange key_range; // Try passing nothing, too.
+  KeyRange key_range;
   key_range.__isset.start_key= true;
   key_range.__isset.end_key= true;
 

=== modified file 'storage/cassandra/ha_cassandra.cc'
--- a/storage/cassandra/ha_cassandra.cc	2012-08-29 07:14:04 +0000
+++ b/storage/cassandra/ha_cassandra.cc	2012-08-31 06:49:36 +0000
@@ -302,6 +302,7 @@
   }
 
   info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+  insert_lineno= 0;
 
   DBUG_RETURN(0);
 }
@@ -407,6 +408,7 @@
     my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), "setup_field_converters");
     DBUG_RETURN(HA_ERR_NO_CONNECTION);
   }
+  insert_lineno= 0;
   DBUG_RETURN(0);
 }
 
@@ -430,8 +432,13 @@
   /*
     This will get data from the Field pointer, store Cassandra's form
     in internal buffer, and return pointer/size.
+
+    @return
+      false - OK
+      true  - Failed to convert value (completely, there is no value to insert
+              at all).
   */
-  virtual void mariadb_to_cassandra(char **cass_data, int *cass_data_len)=0;
+  virtual bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)=0;
   virtual ~ColumnDataConverter() {};
 };
 
@@ -447,11 +454,12 @@
     field->store(*pdata);
   }
   
-  void mariadb_to_cassandra(char **cass_data, int *cass_data_len)
+  bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
   {
     buf= field->val_real();
     *cass_data= (char*)&buf;
     *cass_data_len=sizeof(double);
+    return false;
   }
   ~DoubleDataConverter(){}
 };
@@ -468,11 +476,12 @@
     field->store(*pdata);
   }
   
-  void mariadb_to_cassandra(char **cass_data, int *cass_data_len)
+  bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
   {
     buf= field->val_real();
     *cass_data= (char*)&buf;
     *cass_data_len=sizeof(float);
+    return false;
   }
   ~FloatDataConverter(){}
 };
@@ -501,12 +510,13 @@
     field->store(tmp);
   }
   
-  void mariadb_to_cassandra(char **cass_data, int *cass_data_len)
+  bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
   {
     longlong tmp= field->val_int();
     flip64((const char*)&tmp, (char*)&buf);
     *cass_data= (char*)&buf;
     *cass_data_len=sizeof(longlong);
+    return false;
   }
   ~BigintDataConverter(){}
 };
@@ -531,12 +541,13 @@
     field->store(tmp);
   }
   
-  void mariadb_to_cassandra(char **cass_data, int *cass_data_len)
+  bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
   {
     int32_t tmp= field->val_int();
     flip32((const char*)&tmp, (char*)&buf);
     *cass_data= (char*)&buf;
     *cass_data_len=sizeof(int32_t);
+    return false;
   }
   ~Int32DataConverter(){}
 };
@@ -551,11 +562,12 @@
     field->store(cass_data, cass_data_len,field->charset());
   }
   
-  void mariadb_to_cassandra(char **cass_data, int *cass_data_len)
+  bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
   {
     String *pstr= field->val_str(&buf);
     *cass_data= (char*)pstr->c_ptr();
     *cass_data_len= pstr->length();
+    return false;
   }
   ~StringCopyConverter(){}
 };
@@ -579,7 +591,7 @@
     ((Field_timestamp*)field)->store_TIME(tmp / 1000, (tmp % 1000)*1000);
   }
 
-  void mariadb_to_cassandra(char **cass_data, int *cass_data_len)
+  bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
   {
     my_time_t ts_time;
     ulong ts_microsec;
@@ -592,10 +604,85 @@
 
     *cass_data= (char*)&buf;
     *cass_data_len= 8;
+    return false;
   }
   ~TimestampDataConverter(){}
 };
 
+
+
+static int convert_hex_digit(const char c)
+{
+  int num;
+  if (c >= '0' && c <= '9')
+    num= c - '0';
+  else if (c >= 'A' && c <= 'F')
+    num= c - 'A' + 10;
+  else if (c >= 'a' && c <= 'f')
+    num= c - 'a' + 10;
+  else
+    return -1; /* Couldn't convert */
+  return num;
+}
+
+
+const char map2number[]="0123456789abcdef";
+
+class UuidDataConverter : public ColumnDataConverter
+{
+  char buf[16]; /* Binary UUID representation */
+  String str_buf;
+public:
+  void cassandra_to_mariadb(const char *cass_data, int cass_data_len)
+  {
+    DBUG_ASSERT(cass_data_len==16);
+    char str[37];
+    char *ptr= str;
+    /* UUID arrives as 16-byte number in network byte order */
+    for (uint i=0; i < 16; i++)
+    {
+      *(ptr++)= map2number[(cass_data[i] >> 4) & 0xF];
+      *(ptr++)= map2number[cass_data[i] & 0xF];
+      if (i == 3 || i == 5 || i == 7 || i == 9)
+        *(ptr++)= '-';
+    }
+    *ptr= 0;
+    field->store(str, 36,field->charset());
+  }
+
+  bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
+  {
+    String *uuid_str= field->val_str(&str_buf);
+    char *pstr= (char*)uuid_str->c_ptr();
+
+    if (uuid_str->length() != 36) 
+      return true;
+    
+    int lower, upper;
+    for (uint i=0; i < 16; i++)
+    {
+      if ((upper= convert_hex_digit(pstr[0])) == -1 ||
+          (lower= convert_hex_digit(pstr[1])) == -1)
+      {
+        return true;
+      }
+      buf[i]= lower | (upper << 4);
+      pstr += 2;
+      if (i == 3 || i == 5 || i == 7 || i == 9)
+      {
+        if (pstr[0] != '-')
+          return true;
+        pstr++;
+      }
+    }
+     
+    *cass_data= buf;
+    *cass_data_len= 16;
+    return false;
+  }
+  ~UuidDataConverter(){}
+};
+
 const char * const validator_bigint=  "org.apache.cassandra.db.marshal.LongType";
 const char * const validator_int=     "org.apache.cassandra.db.marshal.Int32Type";
 const char * const validator_counter= "org.apache.cassandra.db.marshal.CounterColumnType";
@@ -609,6 +696,8 @@
 
 const char * const validator_timestamp="org.apache.cassandra.db.marshal.DateType";
 
+const char * const validator_uuid= "org.apache.cassandra.db.marshal.UUIDType";
+
 ColumnDataConverter *map_field_to_validator(Field *field, const char *validator_name)
 {
   ColumnDataConverter *res= NULL;
@@ -617,8 +706,7 @@
     case MYSQL_TYPE_TINY:
     case MYSQL_TYPE_SHORT:
     case MYSQL_TYPE_LONGLONG:
-      if (!strcmp(validator_name, validator_bigint) ||
-          0/*!strcmp(validator_name, validator_timestamp)*/)
+      if (!strcmp(validator_name, validator_bigint))
         res= new BigintDataConverter;
       break;
 
@@ -637,9 +725,18 @@
         res= new TimestampDataConverter;
       break;
 
+    case MYSQL_TYPE_STRING: // these are space padded CHAR(n) strings.
+      if (!strcmp(validator_name, validator_uuid) && 
+          field->real_type() == MYSQL_TYPE_STRING &&
+          field->field_length == 36) 
+      {
+        // UUID maps to CHAR(36), its text representation
+        res= new UuidDataConverter;
+        break;
+      }
+      /* fall through: */
+    case MYSQL_TYPE_VARCHAR:
     case MYSQL_TYPE_VAR_STRING:
-    case MYSQL_TYPE_VARCHAR:
-    case MYSQL_TYPE_STRING: // these are space padded strings.
       if (!strcmp(validator_name, validator_blob) ||
           !strcmp(validator_name, validator_ascii) ||
           !strcmp(validator_name, validator_text))
@@ -698,7 +795,11 @@
   }
 
   if (n_mapped != n_fields - 1)
+  {
+    se->print_error("Some of SQL fields were not mapped to Cassandra's fields"); 
+    my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
     return true;
+  }
   
   /* 
     Setup type conversion for row_key.
@@ -775,7 +876,11 @@
 
   old_map= dbug_tmp_use_all_columns(table, table->read_set);
 
-  rowkey_converter->mariadb_to_cassandra(&cass_key, &cass_key_len);
+  if (rowkey_converter->mariadb_to_cassandra(&cass_key, &cass_key_len))
+  {
+    /* We get here when making lookups like uuid_column='not-an-uuid' */
+    DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
+  }
 
   dbug_tmp_restore_column_map(table->read_set, old_map);
 
@@ -858,10 +963,18 @@
 
   old_map= dbug_tmp_use_all_columns(table, table->read_set);
   
+  insert_lineno++;
+
   /* Convert the key */
   char *cass_key;
   int cass_key_len;
-  rowkey_converter->mariadb_to_cassandra(&cass_key, &cass_key_len);
+  if (rowkey_converter->mariadb_to_cassandra(&cass_key, &cass_key_len))
+  {
+    my_error(ER_WARN_DATA_OUT_OF_RANGE, MYF(0),
+             rowkey_converter->field->field_name, insert_lineno);
+    dbug_tmp_restore_column_map(table->read_set, old_map);
+    DBUG_RETURN(HA_ERR_AUTOINC_ERANGE);
+  }
   se->start_row_insert(cass_key, cass_key_len);
 
   /* Convert other fields */
@@ -869,7 +982,13 @@
   {
     char *cass_data;
     int cass_data_len;
-    field_converters[i]->mariadb_to_cassandra(&cass_data, &cass_data_len);
+    if (field_converters[i]->mariadb_to_cassandra(&cass_data, &cass_data_len))
+    {
+      my_error(ER_WARN_DATA_OUT_OF_RANGE, MYF(0),
+               field_converters[i]->field->field_name, insert_lineno);
+      dbug_tmp_restore_column_map(table->read_set, old_map);
+      DBUG_RETURN(HA_ERR_AUTOINC_ERANGE);
+    }
     se->add_insert_column(field_converters[i]->field->field_name, 
                           cass_data, cass_data_len);
   }
@@ -892,7 +1011,7 @@
 
   if (res)
     my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
-
+  
   DBUG_RETURN(res? HA_ERR_INTERNAL_ERROR: 0);
 }
 
@@ -1060,6 +1179,7 @@
 int ha_cassandra::reset()
 {
   doing_insert_batch= false;
+  insert_lineno= 0;
   return 0;
 }
 

=== modified file 'storage/cassandra/ha_cassandra.h'
--- a/storage/cassandra/ha_cassandra.h	2012-08-29 03:39:22 +0000
+++ b/storage/cassandra/ha_cassandra.h	2012-08-31 06:49:36 +0000
@@ -48,6 +48,9 @@
 
   bool doing_insert_batch;
   ha_rows insert_rows_batched;
+  
+  /* Used to produce 'wrong column %s at row %lu' warnings */
+  ha_rows insert_lineno;
 public:
   ha_cassandra(handlerton *hton, TABLE_SHARE *table_arg);
   ~ha_cassandra()



More information about the commits mailing list