插入protobuf时SQLite无法识别的令牌错误:要处理哪些令牌&怎么样?

时间:2017-12-08 13:49:43

标签: c++ sqlite sql-insert

我正在使用 double secondsSinceEpoch = 1.511554592277516E9; long longSeconds = (long) secondsSinceEpoch; long micros = Math.round((secondsSinceEpoch - longSeconds) * 1_000_000); Instant inst = Instant.ofEpochSecond(longSeconds).plus(micros , ChronoUnit.MICROS); 函数来执行查询。我知道,根据以下帖子,使用sqlite3_exec()组合可以获得各种好处。

sqllite query with encrypted std::string (unrecognized token)

但是,在我的情况下,我已经有一个库,它与_prepare, _bind, _step, _finalize紧密耦合,很难改变。即使是出于教育目的,我想知道,如何在sqlite3数据库中输入特殊标记。目前,我正在使用C ++以编程方式从文件中读取此语句,并使用sqlite3_exec()

插入到数据库中

目前,以下声明给出错误:

sqlite3_exec()

错误在此符号INSERT INTO Convey(username, data, id, type) VALUES('12345', '^Z^Dfine* ^HºÉÙ<98>ö÷×^B2^@', 'abcd', 31); 处显示为^@。当我拆除语句并检查每个字符的ascii时,它显示SQL error: unrecognized token:代替0^@的类型,dataTEXT并没有什么区别。

请注意,&#34;数据&#34;,我想在这里输入一个序列化形式的Google protobuf消息。

逃避此类&#34; nul&#34;的正确方法是什么?喜欢sqlite中的字符,当必须使用BLOB

[注意:1种方法是用一些预定义的模式替换0,这种模式不太可能在二进制字符串中找到,然后在读取时恢复它们。我也对这个解决方案持开放态度。]

2 个答案:

答案 0 :(得分:0)

值为零的字符不是有效的UTF-8字符,因此无法直接在SQL中编写。

仅供记录:您应该使用参数。 但是如果你想在SQL中这样做,你必须写一个blob literal

... VALUES('12345', x'1A0466696E652A2008BAC9D998F6F7D7023200', 'abcd', 31);

答案 1 :(得分:0)

似乎INSERT具有blob性质的数据是不可能的,即包含NUL('\ 0')字符(或可能是新行'\ n'字符)。

因此,现在我按以下方式插入:

  • 在插入之前,检查是否有任何此类特殊字符(即'\ 0','\ n')
  • 如果是,则在字符串中,在末尾添加一个特殊的已知标记,例如'%'
  • 列出该令牌后用逗号分隔的位置;这些职位可以由临时占位符取代,例如'0'

即。 '^Z^Dfine* ^HºÉÙ<98>ö÷×^B2^@'看起来像'^Z^Dfine* ^HºÉÙ<98>ö÷×^B20#<position>'

在读取字符串时,必须对其进行解码。到目前为止,这非常有用且工作得很好!

对于有兴趣的人,这里是替换'\ 0'的代码:

#define SQLa_STRING_END      '%'
#define SQLa_NUL_SEPARATOR   ','
#define SQLa_NUL_TOKEN       '0'

string
ToString (const string& s_,  // need to enclose with '' and add ' before '
          const bool isEncodingString = false)
{
  string s = s_;
  const char apostrophe = '\'';
  bool isStringEndPending = isEncodingString;
  for(size_t i = 0, length = s.length(); i < length; ++i)
    switch(s[i])
    {
    case apostrophe:
      s.insert(i++, 1, apostrophe);
      ++length;
    break;
    case 0:
      if(isEncodingString)
      {
        if(isStringEndPending)
        {
          s += SQLa_STRING_END;
          isStringEndPending = false;
        }
        s[i] = SQLa_NUL_TOKEN; ;
        s += std::to_string(i) + SQLa_NUL_SEPARATOR;
      }
    default:
    break;
    }
  s.insert(0, 1, '\'');
  return s += '\'';
}

string
FromString (const char value[])  // enclosing '' are not present
{
  string s = value;
  if(const auto posEnd = s.rfind(SQLa_STRING_END) + 1)
  {
    std::replace(s.begin() + posEnd, s.end(), SQLa_NUL_SEPARATOR, '\0');
    for(auto pos = posEnd, length = s.length() - 1;
        pos < length;
        s[::atoll(&s[pos])] = 0, pos = s.find(SQLa_NUL_SEPARATOR, pos) + 1);
    s.erase(posEnd - 1);
  }
  return s;
}