thobbs / phpcassa

PHP client library for Apache Cassandra
thobbs.github.com/phpcassa
MIT License
248 stars 78 forks source link

Column metadata not recognized with composite keys #83

Closed lafka closed 12 years ago

lafka commented 12 years ago

When using composite keys for column names their validation class is not respected.

If i insert a string to into the any of the AsciiType columns the value stored in the database is set to 0, same if default_validation_class is BytesType and any inserts to a IntegerType will yield the ascii value of that number (1 becomes 49, 2 becomes 50 and so on).

Cassandra database scheme

create column family NodeState
    with comparator = 'CompositeType(AsciiType, AsciiType)'
    and key_validation_class = 'CompositeType(AsciiType, AsciiType)'
    and default_validation_class = 'IntegerType'
    and column_metadata = [
        {column_name      : 'meta:network',
         validation_class : 'AsciiType',
         index_type       : KEYS
        },
        {column_name      : 'meta:node', 
         validation_class : 'AsciiType'
        },
        {column_name      : 'meta:name', 
         validation_class : 'UTF8Type'
        },
        {column_name      : 'meta:type',
         validation_class : 'AsciiType'
        },
        {column_name      : 'config:system_id',
         validation_class : 'IntegerType',
         index_type       : KEYS
        },
        {column_name      : 'config:node_id', 
         validation_class : 'IntegerType',
         index_type       : KEYS
        }
    ];

Code to reproduce

<?php
use phpcassa\Connection\ConnectionPool, phpcassa\ColumnFamily;

if ($argc !== 6) {
    echo "usage: {$argv[0]} <keyspace> <cf> <row-key> <column-key> <value>\r\n";
    exit(1);
}

include 'phpcassa/lib/autoload.php';

$argv[3] = false !== strpos($argv[3], ':') ? explode(':', $argv[3]) : $argv[3];
$argv[4] = explode(':', $argv[4]);

$pool = new ConnectionPool($argv[1], array('127.0.0.1'));
$cf   = new ColumnFamily($pool, $argv[2]);
$cf->insert_format = ColumnFamily::ARRAY_FORMAT;
$cf->return_format = ColumnFamily::ARRAY_FORMAT;

$cf->insert($argv[3], array(array($argv[4], $argv[5])));

// usage: php bin/set-column.php TestKS TypeTest comp1:comp2 meta:network test-network
// then list content in cassandra

Point of failure

After some research it seems like ColumnFamily::col_type_dict uses the thrift serialization and phpcassa uses php serialization for the column keys. This can partly be fixed by adding this line, but it seems that it can't unpack correctly after this.

diff --git a/lib/phpcassa/ColumnFamily.php b/lib/phpcassa/ColumnFamily.php
index dd4aa3f..f6a5757 100644
--- a/lib/phpcassa/ColumnFamily.php
+++ b/lib/phpcassa/ColumnFamily.php
@@ -244,7 +244,7 @@ class ColumnFamily {
             $this->autopack_values = true;
             $this->cf_data_type = DataType::get_type_for($this->cfdef->default_validation_class
             foreach($this->cfdef->column_metadata as $coldef) {
-                $this->col_type_dict[$coldef->name] =
+                $this->col_type_dict[$this->col_name_type->unpack($coldef->name)] =
                         DataType::get_type_for($coldef->validation_class);
             }
         } else {
@@ -1090,7 +1090,7 @@ class ColumnFamily {
                 $sub->ttl = $ttl;
             }
             $sub->name = $this->pack_name(
-                $name, false, self::NON_SLICE, false);
+                serialize($name), false, self::NON_SLICE, false);
             $sub->value = $this->pack_value($value, $name);
             $ret[] = $c_or_sc;
         }