【问题标题】:Cassandra cppdriver Query String Buffer Overflow?Cassandra cppdriver 查询字符串缓冲区溢出?
【发布时间】:2014-11-07 05:43:23
【问题描述】:

我一直在为 CQL3.0 的 Cassandra cppdriver 编写一个包装器,我遇到了一些奇怪的行为,我不确定这是典型的还是错误的。

作为参考,我正在使用 9 月 4 日发布的 cppdriver 代码(来自存储库)、libuv0.10 以及发布在 datastax 网站 (http://www.datastax.com/documentation/cql/3.1/cql/ddl/ddl_music_service_c.html) 上的歌曲/播放列表示例

我遇到的问题是执行查询字符串。似乎有一些字符阈值,之后发送到 Cassandra 的查询字符串就会变成垃圾。下面提供了我用来构造字符串并将其发送到 cppdriver 库(并解析结果)的代码。我在 cassandra.h 和 session.cpp 文件中添加了一个函数(cass_session_print_query)来打印生成的语句。

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;

这样,SELECT id,album,title,artist,data FROM songs; 的初始查询字符串会生成 SELECT id,album,title,artist,data FROM songs; 的 Cassandra 查询字符串。但是,如果我在 SELECT 部分 SELECT id,album,title,artist,data,tags FROM songs; 中再添加一列,Cassandra cppdriver 库中的查询字符串将变为:,ar����,dat�� jOM songX。这会导致 Cassandra / library 出现以下错误:Error: line 1:49 no viable alternative at character '�'

我也尝试了更少的列,但使用了 WHERE 子句,这会导致同样的问题。

这是一个错误吗?还是我错误地构建字符串并将其发送到 cppdriver 库?

【问题讨论】:

  • 我不确定这是否解释了您所看到的问题,但有一点需要注意:在测试错误代码之前,您应该在未来使用 cass_future_wait()。还有一些东西应该被释放(未来,声明),但我假设为了保持简洁而省略了。
  • cass_future_wait(future) 是问题所在。谢谢!如果你想把它写成答案,我会这样标记。

标签: c++ cassandra cql3 datastax


【解决方案1】:

在测试错误代码之前,您应该在执行 future 上使用 cass_future_wait()。

不相关:还有一些东西应该被释放(未来,声明),但我假设为了保持简洁而省略了。

【讨论】:

  • 对于其他人,我还发现将单独的 CassString query = cass_string_init(..) 变量传递给 cass_statement_new() 函数也会导致问题。相反,只需将函数 cass_string_init() 作为第一个参数“传递”给新的 Cassandra 语句函数。
  • 这出乎意料。如果这很容易证明,您会考虑开一张显示该问题的票吗? datastax-oss.atlassian.net/browse/CPP
  • 如果你愿意,我可以。然而,事情有点复杂,因为事情的顺序是:Python Flask HTTP API -> C++ 处理文件(将 python 对象转换为映射和向量) -> 构建字符串的 cppdriver 包装类(您在原来的问题)。如果这仍然是一个很好的问题案例,我会发布它。
【解决方案2】:

所以,看起来(无论出于何种原因)我必须从结果中解析出行键。我检查了这个例子,我无法解析出行键信息,一切仍然有效。我还不完全确定是什么迫使我这样做(与提供的分页示例相比),但对于其他人,您需要在 while (cass_iterator_nex(iterator)) 块中包含以下内容以“神奇地”修复我上面的代码。

CassUuid key;
char key_buffer[CASS_UUID_STRING_LENGTH];
const CassRow* row = cass_iterator_get_row(iterator);
cass_value_get_uuid(cass_row_get_column(row, 0), key);
cass_uuid_string(key, key_buffer);

【讨论】:

    【解决方案3】:

    这确实是一个长镜头,但既然你提到了音乐服务的例子,你有没有可能下载并使用 cql_collections.zip 查询字符串?如果是这样,则字符串(现已修复)有轻微的语法错误:

    - 使用音乐 -CREATE TABLE music.songs(id uuid PRIMARY KEY、专辑文本、艺术家文本、数据 blob、评论列表、标签集、标题文本、场地地图 +使用音乐; +CREATE TABLE music.songs(id uuid PRIMARY KEY、专辑文本、艺术家文本、数据块、评论列表、标签集、标题文本、场地地图);

    【讨论】:

    • cql_collections.zip 没有响铃,所以我很有信心我从未使用过它。
    【解决方案4】:

    AeroBuffalo 的代码对我有用,只是我必须在 cass_value_get_uuid() 函数的第二个参数前面加上“&”。它需要引用类型。

    cass_value_get_uuid(cass_row_get_column(row, 0), &key);
    

    【讨论】:

      猜你喜欢
      • 2022-11-30
      • 2013-10-22
      • 2021-12-10
      • 2013-04-12
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多