Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
304 views
in Technique[技术] by (71.8m points)

Is there a character length limit on TEXT NOT NULL UNIQUE columns in SQLite?

I want to avoid duplicates in a simple SpatiaLite database with 2 spatial tables and non-unique coordinates. For each table I've created a TEXT NOT NULL UNIQUE column for an identifier. One table has a 14 character identifier and it works fine but the 2nd table has a 51 character identifier and the text gets corrupted to 6 unprintable characters. After much trial and error I've determined that I have to limit these identifiers to 15 characters. Between 16 and 22 characters I get a "UNIQUE constraint failed" error. Above 22 characters I get the corruption described above and only occassionally the constraint failure. Colleagues and I have searched and found no documentation on any such limit particular to TEXT NOT NULL UNIQUE columns, with or without the SpatiaLite extensions. So what is this?

  • A bug in SQLite or SpatiaLite?
  • A known 15 character limit for TEXT NOT NULL UNIQUE columns?
  • A bad assumption on my part somewhere?

I'm using:

  • SQLite version: 3.22.0
  • SpatiaLite version: 4.3.0a
question from:https://stackoverflow.com/questions/66056705/is-there-a-character-length-limit-on-text-not-null-unique-columns-in-sqlite

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The problem appears to be the use of ostringstream to generate and contain the identifier string. Here's the code:

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

The str() method returns a temporary copy of ostringstream's internal string object and that copy is destroyed after the statement in which it it used. So it looks like the bind call is retaining the string pointer until a later statement, probably the step call, at which point the temporary has been destroyed. The tricky point is that this code worked for short identifiers up to 15 bytes and that can be explained if the string object contains a special 16 byte array to store short strings and it survives uncorrupted long enough for the code to work with short strings. The solution is to keep a copy of the identifier long enough for SQLite to finish with it. Something like:

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);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...