wrong character in the GSM 03.38 table (ç for Ç)
[gammu.git] / smsd / services / dbi.c
blobd204a9657d29e082b503b91395318cbafdbc82fc
1 /**
2 * libdbi database backend
4 * Part of Gammu project
6 * Copyright (c) 2009 - 2011 Michal Cihar <michal@cihar.com>
8 * Licensed under GNU GPL version 2 or later
9 */
11 #include <gammu.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <time.h>
18 #include <assert.h>
19 #ifdef WIN32
20 #include <windows.h>
21 #ifndef __GNUC__
22 #pragma comment(lib, "libdbi.lib")
23 #endif
24 #endif
26 #include "../core.h"
27 #include "sql.h"
29 long long SMSDDBI_GetNumber(GSM_SMSDConfig * Config, SQL_result *res, unsigned int field)
31 unsigned int type;
33 field++;
34 type = dbi_result_get_field_type_idx(res->dbi, field);
36 switch (type) {
37 case DBI_TYPE_INTEGER:
38 type = dbi_result_get_field_attribs_idx(res->dbi, field);
39 if ((type & DBI_INTEGER_SIZEMASK) == DBI_INTEGER_SIZE1) {
40 return dbi_result_get_int_idx(res->dbi, field);
41 } else if ((type & DBI_INTEGER_SIZEMASK) == DBI_INTEGER_SIZE2) {
42 return dbi_result_get_int_idx(res->dbi, field);
43 } else if ((type & DBI_INTEGER_SIZEMASK) == DBI_INTEGER_SIZE3) {
44 return dbi_result_get_int_idx(res->dbi, field);
45 } else if ((type & DBI_INTEGER_SIZEMASK) == DBI_INTEGER_SIZE4) {
46 return dbi_result_get_int_idx(res->dbi, field);
47 } else if ((type & DBI_INTEGER_SIZEMASK) == DBI_INTEGER_SIZE8) {
48 return dbi_result_get_longlong_idx(res->dbi, field);
50 SMSD_Log(DEBUG_ERROR, Config, "Wrong integer field subtype from DBI: %d", type);
51 return -1;
52 case DBI_TYPE_DECIMAL:
53 type = dbi_result_get_field_attribs_idx(res->dbi, field);
54 if ((type & DBI_DECIMAL_SIZEMASK) == DBI_DECIMAL_SIZE4) {
55 return dbi_result_get_int_idx(res->dbi, field);
56 } else if ((type & DBI_DECIMAL_SIZEMASK) == DBI_DECIMAL_SIZE8) {
57 return dbi_result_get_longlong_idx(res->dbi, field);
59 SMSD_Log(DEBUG_ERROR, Config, "Wrong decimal field subtype from DBI: %d", type);
60 return -1;
61 default:
62 SMSD_Log(DEBUG_ERROR, Config, "Wrong field type for number (not INTEGER nor DECIMAL) from DBI: %d", type);
63 return -1;
67 time_t SMSDDBI_GetDate(GSM_SMSDConfig * Config, SQL_result *res, unsigned int field)
69 unsigned int type;
70 const char *date;
72 field++;
73 type = dbi_result_get_field_type_idx(res->dbi, field);
75 switch (type) {
76 case DBI_TYPE_INTEGER:
77 case DBI_TYPE_DECIMAL:
78 return SMSDDBI_GetNumber(Config, res, field);
79 case DBI_TYPE_STRING:
80 date = dbi_result_get_string_idx(res->dbi, field);
81 return SMSDSQL_ParseDate(Config, date);
82 case DBI_TYPE_DATETIME:
83 return dbi_result_get_datetime_idx(res->dbi, field);
84 case DBI_TYPE_ERROR:
85 default:
86 SMSD_Log(DEBUG_ERROR, Config, "Wrong field type for date from DBI: %d", type);
87 return -1;
91 gboolean SMSDDBI_GetBool(GSM_SMSDConfig * Config, SQL_result *res, unsigned int field)
93 unsigned int type;
94 const char *value;
95 int num;
97 field++;
98 type = dbi_result_get_field_type_idx(res->dbi, field);
100 switch (type) {
101 case DBI_TYPE_INTEGER:
102 case DBI_TYPE_DECIMAL:
103 num = SMSDDBI_GetNumber(Config, res, field);
104 if (num == -1) {
105 return -1;
106 } else if (num == 0) {
107 return FALSE;
108 } else {
109 return TRUE;
111 case DBI_TYPE_STRING:
112 value = dbi_result_get_string_idx(res->dbi, field);
113 return GSM_StringToBool(value);
114 case DBI_TYPE_ERROR:
115 default:
116 SMSD_Log(DEBUG_ERROR, Config, "Wrong field type for boolean from DBI: %d", type);
117 return -1;
121 const char *SMSDDBI_GetString(GSM_SMSDConfig * Config, SQL_result *res, unsigned int col)
123 return dbi_result_get_string_idx(res->dbi, col+1);
126 static void SMSDDBI_LogError(GSM_SMSDConfig * Config)
128 int rc;
129 const char *msg;
130 rc = dbi_conn_error(Config->conn.dbi, &msg);
131 if (rc == -1) {
132 SMSD_Log(DEBUG_ERROR, Config, "Unknown DBI error!");
133 } else {
134 SMSD_Log(DEBUG_ERROR, Config, "DBI error %d: %s", rc, msg);
138 void SMSDDBI_Callback(dbi_conn Conn, void *Config)
140 SMSDDBI_LogError((GSM_SMSDConfig *) Config);
143 /* Disconnects from a database */
144 void SMSDDBI_Free(GSM_SMSDConfig * Config)
146 if (Config->conn.dbi != NULL) {
147 dbi_conn_close(Config->conn.dbi);
148 dbi_shutdown();
149 Config->conn.dbi = NULL;
153 /* Connects to database */
154 static SQL_Error SMSDDBI_Connect(GSM_SMSDConfig * Config)
156 int rc;
157 struct GSM_SMSDdbobj *db = Config->db;
159 rc = dbi_initialize(Config->driverspath);
161 if (rc == 0) {
162 SMSD_Log(DEBUG_ERROR, Config, "DBI did not find any drivers, try using DriversPath option");
163 dbi_shutdown();
164 return SQL_FAIL;
165 } else if (rc < 0) {
166 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to initialize!");
167 return SQL_FAIL;
170 Config->conn.dbi = dbi_conn_new(Config->driver);
171 if (Config->conn.dbi == NULL) {
172 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to init %s driver!", Config->driver);
173 dbi_shutdown();
174 return SQL_FAIL;
175 } else {
176 SMSD_Log(DEBUG_SQL, Config, "Using DBI driver '%s'", dbi_driver_get_name(dbi_conn_get_driver(Config->conn.dbi)));
179 dbi_conn_error_handler(Config->conn.dbi, SMSDDBI_Callback, Config);
181 if (dbi_conn_set_option(Config->conn.dbi, "sqlite_dbdir", Config->dbdir) != 0) {
182 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to set sqlite_dbdir!");
183 SMSDDBI_Free(Config);
184 return SQL_FAIL;
186 if (dbi_conn_set_option(Config->conn.dbi, "sqlite3_dbdir", Config->dbdir) != 0) {
187 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to set sqlite3_dbdir!");
188 SMSDDBI_Free(Config);
189 return SQL_FAIL;
191 if (dbi_conn_set_option(Config->conn.dbi, "host", Config->host) != 0) {
192 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to set host!");
193 SMSDDBI_Free(Config);
194 return SQL_FAIL;
196 if (dbi_conn_set_option(Config->conn.dbi, "username", Config->user) != 0) {
197 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to set username!");
198 SMSDDBI_Free(Config);
199 return SQL_FAIL;
201 if (dbi_conn_set_option(Config->conn.dbi, "password", Config->password) != 0) {
202 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to set password!");
203 SMSDDBI_Free(Config);
204 return SQL_FAIL;
206 if (dbi_conn_set_option(Config->conn.dbi, "dbname", Config->database) != 0) {
207 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to set dbname!");
208 SMSDDBI_Free(Config);
209 return SQL_FAIL;
211 if (dbi_conn_set_option(Config->conn.dbi, "encoding", "UTF-8") != 0) {
212 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to set encoding!");
213 SMSDDBI_Free(Config);
214 return SQL_FAIL;
217 if (dbi_conn_connect(Config->conn.dbi) != 0) {
218 SMSD_Log(DEBUG_ERROR, Config, "DBI failed to connect!");
219 SMSDDBI_Free(Config);
220 return SQL_FAIL;
222 Config->db = db;
223 return SQL_OK;
226 static SQL_Error SMSDDBI_Query(GSM_SMSDConfig * Config, const char *query, SQL_result * res)
228 const char *msg;
229 int rc;
231 res->dbi = NULL;
233 SMSD_Log(DEBUG_SQL, Config, "Execute SQL: %s", query);
234 res->dbi = dbi_conn_query(Config->conn.dbi, query);
235 if (res->dbi != NULL)
236 return SQL_OK;
238 SMSD_Log(DEBUG_INFO, Config, "SQL failed: %s", query);
239 /* Black magic to decide whether we should bail out or attempt to retry */
240 rc = dbi_conn_error(Config->conn.dbi, &msg);
241 if (rc != -1) {
242 SMSD_Log(DEBUG_INFO, Config, "SQL failure: %s", msg);
243 if (strstr(msg, "syntax") != NULL) {
244 return SQL_FAIL;
246 if (strstr(msg, "violation") != NULL) {
247 return SQL_FAIL;
249 if (strstr(msg, "violates") != NULL) {
250 return SQL_FAIL;
252 if (strstr(msg, "SQL error") != NULL) {
253 return SQL_FAIL;
255 if (strstr(msg, "duplicate") != NULL) {
256 return SQL_FAIL;
258 if (strstr(msg, "unique") != NULL) {
259 return SQL_FAIL;
261 if (strstr(msg, "need to rewrite") != NULL) {
262 return SQL_FAIL;
264 if (strstr(msg, "locked") != NULL) {
265 return SQL_TIMEOUT;
268 return SQL_TIMEOUT;
271 /* free sql results */
272 void SMSDDBI_FreeResult(GSM_SMSDConfig * Config, SQL_result *res)
274 dbi_result_free(res->dbi);
277 /* set pointer to next row */
278 int SMSDDBI_NextRow(GSM_SMSDConfig * Config, SQL_result *res)
280 return dbi_result_next_row(res->dbi);
282 /* quote strings */
283 char * SMSDDBI_QuoteString(GSM_SMSDConfig * Config, const char *string)
285 char *encoded_text = NULL;
286 dbi_conn_quote_string_copy(Config->conn.dbi, string, &encoded_text);
287 return encoded_text;
289 /* LAST_INSERT_ID */
290 unsigned long long SMSDDBI_SeqID(GSM_SMSDConfig * Config, const char *id)
292 unsigned long long new_id;
293 char buffer[100];
295 new_id = dbi_conn_sequence_last(Config->conn.dbi, NULL);
296 if (new_id == 0) {
297 new_id = dbi_conn_sequence_last(Config->conn.dbi, id);
298 /* Need to escape for PostgreSQL */
299 if (new_id == 0) {
300 sprintf(buffer, "\"%s\"", id);
301 new_id = dbi_conn_sequence_last(Config->conn.dbi, buffer);
304 return new_id;
307 unsigned long SMSDDBI_AffectedRows(GSM_SMSDConfig * Config, SQL_result *res)
309 return dbi_result_get_numrows_affected(res->dbi);
312 struct GSM_SMSDdbobj SMSDDBI = {
313 SMSDDBI_Connect,
314 SMSDDBI_Query,
315 SMSDDBI_Free,
316 SMSDDBI_FreeResult,
317 SMSDDBI_NextRow,
318 SMSDDBI_SeqID,
319 SMSDDBI_AffectedRows,
320 SMSDDBI_GetString,
321 SMSDDBI_GetNumber,
322 SMSDDBI_GetDate,
323 SMSDDBI_GetBool,
324 SMSDDBI_QuoteString,
327 /* How should editor hadle tabs in this file? Add editor commands here.
328 * vim: noexpandtab sw=8 ts=8 sts=8: