Article directory
1 Overview
SQLite is an embedded SQL database engine. Unlike most other SQL databases, SQLite does not have a separate server process. SQLite reads and writes plain disk files directly. A complete SQL database with multiple tables, indexes, triggers and views contained in a single disk file.
SQLite is even more lightweight than MySQL, and the official package is about 1MB. But such a small content is actually a relational database, so SQLite is also very suitable as an entry-level database. Among them, the most basic function of SQL is query.
2. Detailed discussion
2.1. Open/close database
The first step in using the database is of course to open the database. For the C interface, the usual implementation is to provide an open interface, get a handle or pointer, and then perform further operations through this handle or pointer, including closing the database operation. SQLite is designed like this:
int nRes = sqlite3_open("D:/test.db", &pDB);
if (nRes != SQLITE_OK) {
cout << "Open database fail: " << sqlite3_errmsg(pDB);
return 1;
}
sqlite3_close(pDB);
Open the database file through the sqlite3_open() function. If the database.db file does not exist, this file will be created. Once created successfully, it is best to call the sqlite3_close() function to close at the end of the program, otherwise memory leaks will occur. If you need more fine-grained control over opening database files, it is best to use the sqlite3_open_v2() interface:
int flags =
SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE;
int nRes = sqlite3_open_v2("D:/test.db", &pDB, flags, nullptr);
sqlite3_open_v2() provides many configurations for opening database files. For example, if you need to create a database file when it does not exist, you can add SQLITE_OPEN_CREATE.
2.2. Data query
If in a visual management tool (such as SQLite Expert), whether it is a query, insert, modify or delete operation, you can directly enter the SQL statement and then execute the operation to get the corresponding result. SQLite also has such an interface sqlite3_exec(), for example, we query all the data in a table:
char* cErrMsg;
int res =
sqlite3_exec(pDB, "select * from metadata;", ResultCallBack, 0, &cErrMsg);
if (res != SQLITE_OK) {
cout << "select fail: " << cErrMsg << endl;
return false;
}
sqlite3_free(cErrMsg);
sqlite3_exec() is a callback function that is called every time a row of data is queried:
int ResultCallBack(void* NotUsed, int argc, char** argv,
char** azColName) {
for (int i = 0; i < argc; i++) {
cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL") << ", ";
}
cout << endl;
return 0;
}
If more fine-grained control is required, then a suitable approach is to use statement (statement). First, we compile the sql statement we need into the bytecode recognized by the database engine. This step can be called prepare (prepare):
sqlite3_stmt* statement = nullptr;
int ret = sqlite3_prepare_v2(pDB, sqlStr, -1, &statement, nullptr);
if (ret != SQLITE_OK) {
printf("prepare error ret : %d\n", ret);
return 1;
}
Next, execute the prepared SQL statement:
while (sqlite3_step(statement) == SQLITE_ROW) {
//...
}
sqlite3_setp() queries a row of records each time, and returns SQLITE_ROW; when the query is completed, it returns SQLIET_DONE. In this way, an iterator-like operation is implemented, looping through each query result.
Finally, we parse the results of each line of query:
while (sqlite3_step(statement) == SQLITE_ROW) {
cout << sqlite3_data_count(statement) << '\n';
cout << sqlite3_column_text(statement, 0) << '\t'
<< sqlite3_column_text(statement, 1) << '\n';
}
sqlite3_column_X is a series of functions that can directly obtain the data type of the corresponding column of each row. For example, to get an integer is sqlite3_column_int.
Also, don't forget to close this statement:
sqlite3_finalize(statement);