【问题标题】:Is it possible to save '0' character in sqlite as a text是否可以将sqlite中的'0'字符保存为文本
【发布时间】:2013-03-05 17:38:55
【问题描述】:

我在 sqlite 表中有一个带有 \0 字符和文本字段的 UTF 字符串。
当我尝试将字符串插入表格文本字段然后从数据库中读取它时,我注意到字符串值在 \0 字符之后被截断。

问题:是否可以在 \0 之后在 sqlite 中保存/恢复此类字符串而不会丢失数据?

代码sn-p:

 public static void IssueWith0Character()
    {
        const string sql = "DROP TABLE IF EXISTS SomeTable;" +
                           "CREATE TABLE SomeTable (SomeField TEXT not null);"
                           + "INSERT INTO SomeTable (SomeField) Values ( :value )";

        var csb = new SQLiteConnectionStringBuilder
                      {DataSource = "stringWithNull.db", Version = 3};

        // string with '0' character
        const string stringWithNull = "beforeNull\0afterNull";

        using (var c = new SQLiteConnection(csb.ConnectionString))
        {
            c.Open();

            using (var cmd = c.CreateCommand())
            {
                var p = new SQLiteParameter(":value", DbType.String) {Value = stringWithNull};
                cmd.CommandText = sql;
                cmd.Parameters.Add(p);
                cmd.ExecuteNonQuery();
            }

            using (var cmd = c.CreateCommand())
            {
                cmd.CommandText = "SELECT SomeField FROM SomeTable;";
                var restoredValue = (string) cmd.ExecuteScalar();
                Debug.Assert(stringWithNull == restoredValue);
            }
        }
    }    

UPDATE #1 看起来问题出在阅读阶段。数据库文件中至少存在字符串的“afterNull”部分。

UPDATE #2 这被认为是 System.Data.SQLite 错误 (http://system.data.sqlite.org/index.html/tktview/3567020edf12d438cb7cf757b774ff3a04dc381e

【问题讨论】:

  • 我认为这就是BLOB 的用途。
  • 当字符串被传递给 sqlite 时,它​​可能会将 '\0' 视为字符串终止符。你能改用'\\0'吗?
  • 约阿希姆,谢谢。我几乎可以肯定使用 BLOB 将解决持久性问题。可能这对我来说是唯一的选择。在我的情况下,大多数时候我只有人类可读的字符串,没有 \0s。我很少有带有 \0 的人类可读字符串。 А 引入 BLOB 后,将需要进行额外的 ToBytes/FromBytes 字符串转换,并且在我的应用程序中引入搜索功能将更加困难。
  • Zenox,问题是为什么 \0 被视为在 sqlite 中保存 UTF 字符串的字符串终止符。 Sqlite 使用 UTF 存储文本。 \0 只是巨大 UTF 表中的第一个字符。我希望所有其他符号都可以保存而没有任何问题。
  • sqlite API 中有 sqlite3_bind_text 函数,实际上是由 Sqlite 数据适配器调用的。这里sqlite.org/c3ref/bind_blob.html提到如果参数传递正确然后引用:[如果任何NUL字符出现在小于第四个参数值的字节偏移处,那么结果字符串值将包含嵌入的NUL]

标签: sqlite system.data.sqlite


【解决方案1】:

在 SQLite 中,\0 字符被认为是无效的。

虽然可以将此类字符串放入数据库(使用各种函数的指针+长度形式),但许多对字符串进行操作的函数在遇到 \0 时会停止。因此,documentation 表示:

涉及带有嵌入 NUL 的字符串的表达式的结果是未定义的。

如果您确实需要使用空字节存储数据,则应将其存储为 blob (DbType.Binary)。

【讨论】:

  • 感谢您的回复。看起来我应该在那种情况下使用 BLOB/DbType.Binary。但是,对我来说,\0 在 UTF 中不是有效字符似乎很奇怪。我认为它只是任何 UTF 表中的第一个字符。它在 .NET 字符串中也是 100% 有效的。所以至少对我来说,sqlite 中的默认字符串编码是 UTF8 看起来很奇怪,但不可能使用 UTF8 表中的一个字符(即使该字符在 C 字符串中用作特殊字符)。
  • \0 字符在 UTF 编码的字符串中有效,并且 SQLite 允许您存储它们。 U+0000 是 \0,这是一个有效的 UTF-8 字符 en.wikipedia.org/wiki/UTF-8 。有关第二部分的更多详细信息,请参阅sqlite.org/c3ref/bind_blob.html
  • @ryantm "涉及带有嵌入 NUL 的字符串的表达式的结果未定义。"
  • 我不完全确定这意味着什么,但我的猜测是它正在谈论查询表达式 sqlite.org/lang_expr.html 。当我将 \0 放入其中时,它会将其视为查询的结尾位于该字符处(通常在字符串中间时出现语法错误)。当我使用绑定(文本或 blob)时,它接受 \0,这与您引用的前一句一致:“如果任何 NUL 字符出现在小于第四个参数值的字节偏移处,则结果字符串value 将包含嵌入的 NUL。"
猜你喜欢
  • 2012-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2018-05-13
  • 1970-01-01
  • 1970-01-01
  • 2017-05-18
相关资源
最近更新 更多