在 C 語言中向 SQLite3 動態插入資料,手動拼接 SQL 字串極易導致注入風險與格式錯誤。SQLite 官方提供 sqlite3_mprintf() 格式化函數,支援 %q 自動轉義單引號,是構建動態 SQL 的標準做法。
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
void insertText(sqlite3* db, const char* text) {
// %q 自動處理單引號轉義:' -> ''
char* sql = sqlite3_mprintf("INSERT INTO mytable VALUES('%q')", text);
if (!sql) {
fprintf(stderr, "OOM\n");
return;
}
char* errMsg = NULL;
int rc = sqlite3_exec(db, sql, 0, 0, &errMsg);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
}
sqlite3_free(sql); // 必須釋放 mprintf 分配的記憶體
}
int main() {
sqlite3* db;
if (sqlite3_open("test.db", &db) != SQLITE_OK) {
fprintf(stderr, "Cannot open DB: %s\n", sqlite3_errmsg(db));
return 1;
}
// 建表
sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS mytable (txt TEXT)", 0, 0, 0);
// 測試含單引號的字串
insertText(db, "It's a happy day!");
insertText(db, "Normal text");
insertText(db, "O''Reilly"); // 已轉義的輸入也能正確處理
sqlite3_close(db);
return 0;
}
| 符號 | 用途 | 特殊處理 |
|---|---|---|
%q | 字串插入 SQL | 自動雙寫單引號(' → ''),防注入 |
%Q | 字串插入 SQL(帶雙引號) | 同 %q 並外加雙引號,NULL 變 SQL NULL |
%s | 普通字串 | 無轉義,禁用於 SQL 構建 |
sqlite3_mprintf 返回 malloc 分配的記憶體,必須呼叫 sqlite3_free() 釋放。errMsg 同樣需 sqlite3_free()。若同一 SQL 重複執行(批量插入),請改用 sqlite3_prepare_v2 + sqlite3_bind_text,避免重複解析編譯,效能提升數倍。
掌握 %q 與 sqlite3_mprintf,是 C/C++ 安全操作 SQLite 的入門必修課。