Search code examples
c++cassandracql3datastax

Cassandra cppdriver Query String Buffer Overflow?


I have been writing a wrapper for the Cassandra cppdriver for CQL3.0 and I have come across some odd behavior, and I am not sure if it is typical or a bug.

For reference, I am working with with the cppdriver code release on 4 September (from the repository), libuv0.10 and off of the songs / playlist example posted on the datastax website (http://www.datastax.com/documentation/cql/3.1/cql/ddl/ddl_music_service_c.html)

The problem that I am having is with executing query strings. There seems to be some threshold of characters after which the query string being sent to Cassandra becomes garbage. The code that I am using to construct and send the string to the cppdriver library (and parse the results) is provided below. I added a function (cass_session_print_query) to the cassandra.h and session.cpp files to print out generated statement.

map<string, vector<string> > retresults;
int i = 0, ccount;
stringstream ss;
vector<string> keys = get.GetList();
vector<string>::iterator kit = keys.begin();
map<int, pair<string, string> > primkeys = get.GetMap();
map<int, pair<string, string> >::iterator mit = primkeys.begin();

if (!keys.empty())
{
    ss << "SELECT " << (*kit);
    ++kit;
    for ( ; kit != keys.end(); ++kit)
        ss << "," << (*kit);

    ss << " FROM " << tablename;
    if (!primkeys.empty())
    {
        ss << " WHERE ";
        ss << mit->second.first << " = ?";
        ++mit;
        for ( ; mit != primkeys.end(); ++mit)
            ss << " and " << mit->second.first << " = ?";
        mit = primkeys.begin();
    }

    ss << ";";

    cass_bool_t has_more_pages = cass_false;
    const CassResult* result = NULL;
    CassString query = cass_string_init(ss.str().c_str());
    CassStatement* statement = cass_statement_new(query, primkeys.size());
    for ( ; mit != primkeys.end(); ++mit)
        cass_statement_bind_string(statement, i++, cass_string_init(mit->second.second.c_str()));

    cass_statement_set_paging_size(statement, 100);
    do
    {
        cass_session_print_query(statement);
        CassIterator* iterator;
        CassFuture* future = cass_session_execute(session_, statement);
        if (cass_future_error_code(future) != 0)
        {
            CassString message = cass_future_error_message(future);
            fprintf(stderr, "Error: %.*s\n", (int)message.length, message.data);
            break;
        }

        result = cass_future_get_result(future);
        ccount = cass_result_column_count(result);
        vector<string> cnames;
        for (i = 0; i < ccount; i++)
            cnames.push_back(cass_result_column_name(result, i).data);

        iterator = cass_iterator_from_result(result);
        ListVector::iterator vit;
        while (cass_iterator_next(iterator))
        {
            const CassRow* row = cass_iterator_get_row(iterator);
            for (vit = cnames.begin(); vit != cnames.end(); ++vit)
            {
                CassString value;
                char value_buffer[256];
                cass_value_get_string(cass_row_get_column_by_name(row, (*vit).c_str()), &value);
                if (value.length == 0 || value.data == NULL)
                    continue;
                memcpy(value_buffer, value.data, value.length);
                value_buffer[value.length] = '\0';
                retresults[(*vit)].push_back(value_buffer);
            }
        }

        has_more_pages = cass_result_has_more_pages(result);
        if (has_more_pages)
        cass_statement_set_paging_state(statement, result);

        cass_iterator_free(iterator);
        cass_result_free(result);
    } while (has_more_pages);
}

return retresults;

With this, an initial query string of SELECT id,album,title,artist,data FROM songs; results in a Cassandra query string of SELECT id,album,title,artist,data FROM songs;. However, if I add one more column to the SELECT portion SELECT id,album,title,artist,data,tags FROM songs; the query string in the Cassandra cppdriver library becomes something like: ,ar����,dat�� jOM songX. This results in the following error from Cassandra / library: Error: line 1:49 no viable alternative at character '�'.

I have also tried fewer columns, but with a WHERE clause, and that results in the same problem.

Is this a bug? Or am I building and sending strings to the cppdriver library incorrectly?


Solution

  • You should cass_future_wait() on the execute future before testing the error code.

    Unrelated: there are also a couple of things that should be freed (future, statement), but I'm assuming that was omitted to keep this concise.