aboutsummaryrefslogtreecommitdiff
path: root/src/mysql.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mysql.c')
-rw-r--r--src/mysql.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/mysql.c b/src/mysql.c
new file mode 100644
index 0000000..9f304a6
--- /dev/null
+++ b/src/mysql.c
@@ -0,0 +1,263 @@
+#include "dbrw.h"
+#include <mysql/mysql.h>
+#include <mysql/errmsg.h>
+#include <mysql/mysqld_error.h>
+
+struct vmod_mysql_data
+{
+ MYSQL *mysql;
+ MYSQL_RES *result;
+ char *buffer;
+ size_t bufsize;
+};
+
+
+static void
+check_errno(struct dbrw_connection *conn)
+{
+ struct vmod_mysql_data *mp = conn->data;
+
+ switch (mysql_errno(mp->mysql)) {
+ case CR_SERVER_GONE_ERROR:
+ case CR_SERVER_LOST:
+ case ER_SERVER_SHUTDOWN:
+ case ER_ABORTING_CONNECTION:
+ sql_disconnect(conn);
+ if (conn->state == state_error) {
+ conn->state = state_disabled;
+ syslog(LOG_DAEMON|LOG_NOTICE,
+ "disabling MySQL connection");
+ }
+ break;
+ case ER_UNKNOWN_COM_ERROR:
+ case ER_ACCESS_DENIED_ERROR:
+ case ER_BAD_DB_ERROR:
+ case ER_WRONG_DB_NAME:
+ case ER_BAD_FIELD_ERROR:
+ case ER_BAD_HOST_ERROR:
+ case ER_BAD_TABLE_ERROR:
+ case ER_WRONG_FIELD_SPEC:
+ case ER_PARSE_ERROR:
+ case ER_EMPTY_QUERY:
+ case ER_FIELD_SPECIFIED_TWICE:
+ case ER_NO_SUCH_TABLE:
+ case ER_NOT_ALLOWED_COMMAND:
+ sql_disconnect(conn);
+ conn->state = state_disabled;
+ syslog(LOG_DAEMON|LOG_NOTICE, "disabling MySQL connection");
+ }
+}
+
+/* ************************************************************************* */
+/* Interface routines */
+
+static int
+s_mysql_init(struct dbrw_connection *conn)
+{
+ struct vmod_mysql_data *mp = calloc(1, sizeof (*mp));
+ if (!mp) {
+ dbrw_error("not enough memory");
+ return -1;
+ }
+ conn->data = mp;
+ return 0;
+}
+
+static void
+s_mysql_destroy(struct dbrw_connection *conn)
+{
+ struct vmod_mysql_data *mp = conn->data;
+ free(mp->buffer);
+ free(mp->mysql);
+ free(mp);
+ conn->data = NULL;
+}
+
+
+static int
+s_mysql_connect(struct dbrw_connection *conn)
+{
+ struct vmod_mysql_data *mp = conn->data;
+ char *host, *socket_name = NULL;
+ char *s;
+ int port;
+
+ mp->mysql = malloc(sizeof(MYSQL));
+ if (!mp->mysql) {
+ dbrw_error("not enough memory");
+ conn->state = state_disabled;
+ return -1;
+ }
+
+ mysql_init(mp->mysql);
+
+ host = findparam(conn->conf->param, "server");
+ if (host && host[0] == '/') {
+ host = "localhost";
+ socket_name = host;
+ }
+
+ s = findparam(conn->conf->param, "port");
+ if (s)
+ port = atoi(s);
+
+ s = findparam(conn->conf->param, "config");
+ if (s)
+ mysql_options(mp->mysql, MYSQL_READ_DEFAULT_FILE, s);
+
+ s = findparam(conn->conf->param, "group");
+ if (s)
+ mysql_options(mp->mysql, MYSQL_READ_DEFAULT_GROUP, s);
+
+ s = findparam(conn->conf->param, "cacert");
+ if (s)
+ mysql_ssl_set(mp->mysql, NULL, NULL, s, NULL, NULL);
+ debug(conn->conf, 1, ("connecting to database"));
+ if (!mysql_real_connect(mp->mysql,
+ host,
+ findparam(conn->conf->param, "user"),
+ findparam(conn->conf->param, "password"),
+ findparam(conn->conf->param, "database"),
+ port,
+ socket_name,
+ CLIENT_MULTI_RESULTS))
+ return -1;
+ debug(conn->conf, 1, ("connected to database"));
+
+ return 0;
+}
+
+static int
+s_mysql_disconnect(struct dbrw_connection *conn)
+{
+ struct vmod_mysql_data *mp = conn->data;
+ mysql_close(mp->mysql);
+ return 0;
+}
+
+static int
+s_mysql_query(struct dbrw_connection *conn, const char *query)
+{
+ struct vmod_mysql_data *mp = conn->data;
+ int rc;
+ int i;
+ MYSQL *mysql;
+
+ for (i = 0; i < 10; i++) {
+ mysql = mp->mysql;
+ rc = mysql_query(mysql, query);
+ if (rc) {
+ check_errno(conn);
+ if (conn->state != state_init)
+ return -1;
+ sql_connect(conn);
+ if (conn->state != state_connected)
+ return -1;
+ continue;
+ }
+ if (!(mp->result = mysql_store_result(mp->mysql))) {
+ dbrw_error("cannot store result: %s",
+ mysql_error (mp->mysql));
+ conn->state = state_error;
+ rc = 1;
+ }
+ break;
+ }
+ return rc;
+}
+
+static int
+s_mysql_free_result(struct dbrw_connection *conn)
+{
+ struct vmod_mysql_data *mp = conn->data;
+ mysql_free_result(mp->result);
+ mp->result = NULL;
+ return 0;
+}
+
+static unsigned
+s_mysql_num_fields(struct dbrw_connection *conn)
+{
+ struct vmod_mysql_data *mp = conn->data;
+ return mysql_num_fields(mp->result);
+}
+
+static unsigned
+s_mysql_num_tuples(struct dbrw_connection *conn)
+{
+ struct vmod_mysql_data *mp = conn->data;
+ return mysql_num_rows(mp->result);
+}
+
+static const char *
+s_mysql_get_column(struct dbrw_connection *conn, size_t nrow, size_t ncol)
+{
+ struct vmod_mysql_data *mp = conn->data;
+ MYSQL_ROW row;
+
+ if (nrow >= mysql_num_rows(mp->result) ||
+ ncol >= mysql_num_fields (mp->result))
+ return NULL;
+
+ mysql_data_seek(mp->result, nrow);
+ row = mysql_fetch_row(mp->result);
+ if (!row)
+ return NULL;
+ return row[ncol];
+}
+
+static char *
+s_mysql_escape (struct dbrw_connection *conn, const char *arg)
+{
+ struct vmod_mysql_data *mp = conn->data;
+ size_t len, size;
+ char *p;
+
+ switch (conn->state) {
+ case state_connected:
+ case state_result:
+ break;
+
+ case state_error:
+ case state_init:
+ if (sql_connect(conn))
+ return NULL;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ len = strlen(arg);
+ size = 2 * len + 1;
+ if (mp->bufsize < size) {
+ p = realloc(mp->buffer, size);
+ if (!p) {
+ dbrw_error("not enough memory");
+ return NULL;
+ }
+ mp->buffer = p;
+ mp->bufsize = size;
+ }
+
+ mysql_real_escape_string(mp->mysql, mp->buffer, arg, len);
+
+ p = strdup(mp->buffer);
+ if (!p)
+ dbrw_error("not enough memory");
+ return p;
+}
+
+struct dbrw_backend mysql_backend = {
+ "mysql",
+ s_mysql_init,
+ s_mysql_destroy,
+ s_mysql_connect,
+ s_mysql_disconnect,
+ s_mysql_escape,
+ s_mysql_query,
+ s_mysql_num_tuples,
+ s_mysql_num_fields,
+ s_mysql_free_result,
+ s_mysql_get_column
+};

Return to:

Send suggestions and report system problems to the System administrator.