C语言 sqlite3_bind_blob什么时候释放内存是安全的?



我有这样的工作代码:

const char sql[] = "INSERT INTO test (pk, geom) VALUES (?, ?)";
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
for (...) {
sqlite3_reset (stmt);
sqlite3_clear_bindings (stmt);
int blob_size = ..;
unsigned char *blob = malloc(blob_size);
sqlite3_bind_int64 (stmt, 1, pk);
sqlite3_bind_blob (stmt, 2, blob, blob_size, free);
sqlite3_step (stmt);
}

我想知道是否有可能在周期的每一步都不分配和释放? 如果我通过SQLITE_STATIC而不是freesqlite3_bind_blob并在循环结束后调用free此代码是否仍然有效?

const char sql[] = "INSERT INTO test (pk, geom) VALUES (?, ?)";
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
int capacity = 1024;
unsigned char *blob = malloc(capacity);
for (...) {
sqlite3_reset (stmt);
sqlite3_clear_bindings (stmt);
int blob_size = ..;
if (capacity < blob_size) {
blob = realloc(blob, blob_size);
capacity = blob_size;
}
sqlite3_bind_int64 (stmt, 1, pk);
sqlite3_bind_blob (stmt, 2, blob, blob_size, SQLITE_STATIC);
sqlite3_step (stmt);
}
free(blob);

使用SQLITE_STATIC要求该值在语句可能访问它时保持有效。

你的代码应该是有效的;但可以肯定的是,将调用移动到循环的末尾sqlite3_clear_bindings()(和重置)。

问题:如果我将SQLITE_STATIC而不是free传递给sqlite3_bind_blob并在循环结束后调用free,此代码是否仍然有效?

答:不可以。

关于sqlite3_bind_blob()的SQLite文档:

如果第五个参数的值为 SQLITE_TRANSIENT,则 SQLite 会在 sqlite3_bind_*() 例程返回之前立即创建自己的数据私有副本。

这意味着当第五个参数没有这个值时(特别是当第五个参数的值为SQLITE_STATIC时),SQLite 在例程返回后可能仍然需要数据。在这种情况下,不保证SQLite可能需要多长时间的数据(除了,大概,SQLite在调用sqlite3_close()后不需要任何东西)。

来自 SQLite 文档:

BLOB

和字符串绑定接口的第五个参数是一个析构函数,用于在 SQLite 完成 BLOB 或字符串后释放它。调用析构函数以释放 BLOB 或字符串,即使对绑定 API 的调用失败也是如此。如果第五个参数是特殊值SQLITE_STATIC,则 SQLite 假定信息位于静态的非托管空间中,不需要释放。如果第五个参数的值为 SQLITE_TRANSIENT,则 SQLite 会在 sqlite3_bind_*() 例程返回之前立即创建自己的数据私有副本。

如果要重新分配内存,则应使用SQLITE_TRANSIENT。这样SQLite就不会对能够依赖该内存做出任何假设,它将制作自己的副本。

请注意,文档没有说明何时调用指定的析构函数(如果有的话)——只是在 SQLite 完成 BLOB 时调用它。如果你不想使用SQLITE_TRANSIENT,那么你不应该使用SQLITE_STATIC,因为SQLite可能会也可能不会假设内存可用,而实际上它不再可用。

最新更新