首页 > 解决方案 > SQLite 中的 TEXT NOT NULL UNIQUE 列是否有字符长度限制?

问题描述

我想避免在具有 2 个空间表和非唯一坐标的简单 SpatiaLite 数据库中出现重复。对于每个表,我都为标识符创建了一个 TEXT NOT NULL UNIQUE 列。一个表有 14 个字符的标识符,它工作正常,但第二个表有 51 个字符的标识符,文本被损坏为 6 个不可打印的字符。经过多次试验和错误,我确定我必须将这些标识符限制为 15 个字符。在 16 到 22 个字符之间,我收到“唯一约束失败”错误。超过 22 个字符时,我会遇到上述损坏,并且偶尔会出现约束失败。我和同事搜索并发现没有任何关于 TEXT NOT NULL UNIQUE 列特有的此类限制的文档,无论是否有 SpatiaLite 扩展。那么这是什么?

我在用着:

标签: sqlite

解决方案


问题似乎是使用 ostringstream 来生成和包含标识符字符串。这是代码:

std::ostringstream blid;
blid << ...    
sqlite3_bind_text(pStmt, 1, blid.str().c_str(), blid.str().length(), nullptr);   

str() 方法返回 ostringstream 的内部字符串对象的临时副本,并且该副本在它使用的语句之后被销毁。所以看起来绑定调用保留了字符串指针,直到后面的语句,可能是步骤调用,此时临时文件已被销毁。棘手的一点是,这段代码适用于最多 15 个字节的短标识符,如果字符串对象包含一个特殊的 16 字节数组来存储短字符串,并且它在未损坏的情况下存在足够长的时间以使代码可以处理短字符串,则可以解释这一点。解决方案是将标识符的副本保留足够长的时间,以便 SQLite 完成它。就像是:

std::ostringstream idBuf;
idBuf << ...    
std::string blid = idBuf.str();
sqlite3_bind_text(pStmt, 1, blid.str().c_str(), blid.str().length(), nullptr);
...
int rc = sqlite3_step(pStmt);

推荐阅读