Line data Source code
1 : /* This file is part of the cmail project (http://cmail.rocks/)
2 : * (c) 2015 Fabian "cbdev" Stumpf
3 : * License: Simplified BSD (2-Clause)
4 : * For further information, consult LICENSE.txt
5 : */
6 :
7 0 : void database_instr(sqlite3_context* context, int argc, sqlite3_value** argv){
8 : //mostly copied from sqlite-src/func.c
9 :
10 : int nHaystack;
11 : int nNeedle;
12 0 : int N = 1;
13 :
14 : const unsigned char* hay;
15 : const unsigned char* needle;
16 0 : bool text=false;
17 :
18 0 : if(sqlite3_value_type(argv[0]) == SQLITE_NULL
19 0 : || sqlite3_value_type(argv[1]) == SQLITE_NULL){
20 : //bail out
21 0 : return;
22 : }
23 :
24 0 : nHaystack = sqlite3_value_bytes(argv[0]);
25 0 : nNeedle = sqlite3_value_bytes(argv[1]);
26 :
27 0 : if(sqlite3_value_type(argv[0]) == SQLITE_BLOB
28 0 : && sqlite3_value_type(argv[1]) == SQLITE_BLOB){
29 :
30 0 : hay = sqlite3_value_blob(argv[0]);
31 0 : needle = sqlite3_value_blob(argv[1]);
32 : }
33 : else{
34 0 : hay = sqlite3_value_text(argv[0]);
35 0 : needle = sqlite3_value_text(argv[1]);
36 0 : text = true;
37 : }
38 :
39 0 : while(nNeedle <= nHaystack && memcmp(hay, needle, nNeedle) != 0){
40 0 : N++;
41 : do{
42 0 : nHaystack--;
43 0 : hay++;
44 : }
45 : //this includes checks for UTF-8 characters
46 0 : while(text && (hay[0] & 0xc0) == 0x80);
47 : }
48 :
49 0 : if(nNeedle > nHaystack){
50 0 : N = 0;
51 : }
52 0 : sqlite3_result_int(context, N);
53 : }
54 :
55 12 : sqlite3_stmt* database_prepare(LOGGER log, sqlite3* conn, char* query){
56 : int status;
57 12 : sqlite3_stmt* target = NULL;
58 :
59 12 : status = sqlite3_prepare_v2(conn, query, strlen(query), &target, NULL);
60 :
61 12 : switch(status){
62 : case SQLITE_OK:
63 12 : logprintf(log, LOG_DEBUG, "Statement (%s) compiled ok\n", query);
64 12 : return target;
65 : default:
66 0 : logprintf(log, LOG_ERROR, "Failed to prepare statement (%s): %s\n", query, sqlite3_errmsg(conn));
67 : }
68 :
69 0 : return NULL;
70 : }
71 :
72 4 : sqlite3* database_open(LOGGER log, const char* filename, int flags){
73 4 : sqlite3* db = NULL;
74 :
75 4 : switch(sqlite3_open_v2(filename, &db, flags, NULL)){
76 : case SQLITE_OK:
77 3 : logprintf(log, LOG_INFO, "Opened database %s\n", filename);
78 3 : break;
79 : default:
80 1 : logprintf(log, LOG_ERROR, "Failed to open database %s: %s\n", filename, sqlite3_errmsg(db));
81 1 : sqlite3_close(db);
82 1 : return NULL;
83 : }
84 :
85 3 : switch(sqlite3_exec(db, "PRAGMA foreign_keys = ON;", NULL, NULL, NULL)){
86 : case SQLITE_OK:
87 : case SQLITE_DONE:
88 3 : break;
89 : default:
90 0 : logprintf(log, LOG_ERROR, "Failed to enable foreign key support: %s\n", sqlite3_errmsg(db));
91 0 : sqlite3_close(db);
92 0 : return NULL;
93 : }
94 :
95 3 : if(sqlite3_create_function(db, "instr", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC, NULL, database_instr, NULL, NULL) != SQLITE_OK){
96 0 : logprintf(log, LOG_ERROR, "Failed to register instr() with sqlite: %s\n", sqlite3_errmsg(db));
97 0 : sqlite3_close(db);
98 0 : return NULL;
99 : }
100 :
101 3 : if(sqlite3_busy_timeout(db, 500000) != SQLITE_OK){
102 0 : logprintf(log, LOG_ERROR, "Failed to set sqlite busy timeout\n");
103 0 : sqlite3_close(db);
104 0 : return NULL;
105 : }
106 :
107 3 : return db;
108 : }
109 :
110 1 : int database_schema_version(LOGGER log, sqlite3* conn){
111 : int status;
112 1 : char* QUERY_SCHEMA_VERSION = "SELECT value FROM meta WHERE key='schema_version'";
113 1 : sqlite3_stmt* query_version = database_prepare(log, conn, QUERY_SCHEMA_VERSION);
114 :
115 1 : if(!query_version){
116 0 : logprintf(log, LOG_ERROR, "Failed to query the database schema version, your database file might not be a valid master database\n");
117 0 : return -1;
118 : }
119 :
120 1 : switch(sqlite3_step(query_version)){
121 : case SQLITE_ROW:
122 1 : status = strtoul((char*)sqlite3_column_text(query_version, 0), NULL, 10);
123 1 : logprintf(log, LOG_INFO, "Database schema version is %d\n", status);
124 1 : break;
125 : case SQLITE_DONE:
126 0 : logprintf(log, LOG_ERROR, "The database did not contain a schema_version key\n");
127 0 : status = -1;
128 0 : break;
129 : default:
130 0 : logprintf(log, LOG_ERROR, "Failed to get schema version: %s\n", sqlite3_errmsg(conn));
131 0 : status = -1;
132 : }
133 :
134 1 : sqlite3_finalize(query_version);
135 1 : return status;
136 : }
|