Orange-OpenSource / YACassandraPDO

Cassandra PDO Driver fork
Apache License 2.0
84 stars 32 forks source link

IP Addresses (cassandra inet data type) are returned as garbage #61

Open martin-marinov-securax opened 10 years ago

martin-marinov-securax commented 10 years ago

Issue: When you insert an IP address (php string) into a cassandra inet column and select it you get garbage.

My code: $ip = "127.0.0.1"; var_dump($ip); $stmt = $db->prepare("INSERT INTO test (id, ip) VALUES (1, :ip)"); $stmt->bindValue(':ip', $ip, \PDO::PARAM_STR); $stmt->execute();

    $stmt2 = $db->prepare("SELECT * FROM test");
    $stmt2->execute();

    var_dump($stmt2->fetchAll(\PDO::FETCH_ASSOC));

Output: string(9) "127.0.0.1" array(1) { [0]=> array(2) { ["id"]=> int(1) ["ip"]=> string(4) "" } }

Table: CREATE TABLE test ( id int, ip inet, PRIMARY KEY ((id)) )

Workaround that worked for me:

    function garbageIpToOriginalIp($garbageIp)
    {
        $octets = array();
        for($i = 0, $max = 4; $i < $max; $i++) {
            $octets[] = ord($garbageIp[$i]);
        }
        $originalIp = implode(".", $octets);
        return $originalIp;
    }
sandvige commented 10 years ago

Yes, I've seen that right after posting, that's why I removed the comment

LexLythius commented 10 years ago

I was working on this myself. Here's what I got, a bit raw I think (need to try some IPv6 corner cases). Look out for silly pointer errors, I'm no expert in C++:

diff --git a/cassandra_statement.cpp b/cassandra_statement.cpp
index c433e81..19e4b30 100755
--- a/cassandra_statement.cpp
+++ b/cassandra_statement.cpp
@@ -243,6 +243,8 @@ static pdo_cassandra_type pdo_cassandra_get_cassandra_type(const std::string &ty
         return PDO_CASSANDRA_TYPE_MAP;
     if (!real_type.compare(0, 8, "ListType"))
         return PDO_CASSANDRA_TYPE_LIST;
+    if (!real_type.compare("InetAddressType"))
+        return PDO_CASSANDRA_TYPE_INET;
     return PDO_CASSANDRA_TYPE_UTF8;
 }
 /* }}} */
@@ -296,6 +298,56 @@ namespace StreamExtraction {
         return x < 10 ? x + '0' : (x - 10) + 'a';
     }

+    /**
+     * Evaluator: Inet (IPv4 or IPv6) extraction
+     */
+    zval *evaluate_inet(const unsigned char *binary, int size) {
+        zval *ret;
+        MAKE_STD_ZVAL(ret);
+        Z_TYPE_P(ret) = IS_STRING;
+        char *str;
+        switch (size) {
+        case 4: {
+            str = (char *) emalloc(16);
+            sprintf(str, "%d.%d.%d.%d", (int) binary[0], (int) binary[1], (int) binary[2], (int) binary[3]);
+            break;
+        }
+        default: {
+            unsigned short word = 0;
+            int empty_words = 0;
+            str = (char *) emalloc(40);
+            int writepos = 0;
+            char parsedword[5];
+            int parsedwordlen = 0;
+            for (int i = 0; i < size; i += 2) {
+                word = (i < (size - 1)) ? ((((unsigned short) binary[i]) << 8) + (unsigned short) binary[i + 1])
+                        : (unsigned short) binary[i];
+                if (i && empty_words < 2) {
+                    str[writepos++] = ':';
+                }
+                if (word) {
+                    parsedwordlen = sprintf(parsedword, "%x", (unsigned int) word);
+                    memcpy(str + writepos, parsedword, parsedwordlen);
+                    writepos += parsedwordlen;
+                    empty_words = 0;
+                }
+                else {
+                    ++empty_words;
+                }
+            }
+            if (writepos < 2) {
+                str[writepos++] = ':';
+            }
+            str[writepos] = 0;
+            break;
+        }
+        }
+        Z_STRVAL_P(ret) = str;
+        Z_STRLEN_P(ret) = strlen(str);
+
+        return ret;
+    }
+
     char *raw_uuid_to_str(const unsigned char *binary, int size) {

         int size_str = size * 2 + 4;
@@ -425,6 +477,7 @@ namespace StreamExtraction {
             m_evaluation_map[PDO_CASSANDRA_TYPE_BYTES]          = 0;
             m_evaluation_map[PDO_CASSANDRA_TYPE_ASCII]          = evaluate_string;
             m_evaluation_map[PDO_CASSANDRA_TYPE_UTF8]           = evaluate_string;
+            m_evaluation_map[PDO_CASSANDRA_TYPE_INET]           = evaluate_inet;
             m_evaluation_map[PDO_CASSANDRA_TYPE_INTEGER]        = evaluate_integer_type<int>;
             m_evaluation_map[PDO_CASSANDRA_TYPE_LONG]           = evaluate_integer_type<long>;
             m_evaluation_map[PDO_CASSANDRA_TYPE_DECIMAL]        = evaluate_decimal_type;