summaryrefslogtreecommitdiffstatsabout
path: root/src/mod_log_sql_pgsql.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_log_sql_pgsql.c')
-rw-r--r--src/mod_log_sql_pgsql.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/mod_log_sql_pgsql.c b/src/mod_log_sql_pgsql.c
new file mode 100644
index 0000000..dcfbd73
--- /dev/null
+++ b/src/mod_log_sql_pgsql.c
@@ -0,0 +1,247 @@
1/* $Id:mod_log_sql_pgsql.c 180 2008-09-21 15:54:12Z urkle@drip.ws $ */
2
3#if defined(WITH_APACHE20)
4# include "apache20.h"
5#elif defined(WITH_APACHE13)
6# include "apache13.h"
7#else
8# error Unsupported Apache version
9#endif
10
11
12#ifdef HAVE_CONFIG_H
13/* Undefine these to prevent conflicts between Apache ap_config_auto.h and
14 * my config.h. Only really needed for Apache < 2.0.48, but it can't hurt.
15 */
16#undef PACKAGE_BUGREPORT
17#undef PACKAGE_NAME
18#undef PACKAGE_STRING
19#undef PACKAGE_TARNAME
20#undef PACKAGE_VERSION
21
22#include "autoconfig.h"
23#endif
24
25#include "mod_log_sql.h"
26
27#include "libpq-fe.h"
28
29/* Connect to the PGSQL database */
30static logsql_opendb_ret log_sql_pgsql_connect(server_rec *s, logsql_dbconnection *db)
31{
32 const char *host = apr_table_get(db->parms,"hostname");
33 const char *user = apr_table_get(db->parms,"username");
34 const char *passwd = apr_table_get(db->parms,"password");
35 const char *database = apr_table_get(db->parms,"database");
36 const char *s_tcpport = apr_table_get(db->parms,"port");
37
38 db->handle = PQsetdbLogin(host, s_tcpport, NULL, NULL, database, user, passwd);
39
40 if (PQstatus(db->handle) == CONNECTION_OK) {
41 log_error(APLOG_MARK,APLOG_DEBUG,0, s,"HOST: '%s' PORT: '%s' DB: '%s' USER: '%s'",
42 host, s_tcpport, database, user);
43 return LOGSQL_OPENDB_SUCCESS;
44 } else {
45 log_error(APLOG_MARK,APLOG_DEBUG,0, s,"mod_log_sql: database connection error: %s",
46 PQerrorMessage(db->handle));
47 log_error(APLOG_MARK,APLOG_DEBUG, 0, s,"HOST: '%s' PORT: '%s' DB: '%s' USER: '%s'",
48 host, s_tcpport, database, user);
49 return LOGSQL_OPENDB_FAIL;
50 }
51}
52
53/* Close the DB link */
54static void log_sql_pgsql_close(logsql_dbconnection *db)
55{
56 PQfinish((PGconn*)(db->handle));
57}
58
59/* Routine to escape the 'dangerous' characters that would otherwise
60 * corrupt the INSERT string: ', \, and "
61 * Also PQescapeString does not place the ' around the string. So we have
62 * to do this manually
63 */
64static const char *log_sql_pgsql_escape(const char *from_str, apr_pool_t *p,
65 logsql_dbconnection *db)
66{
67 char *temp;
68 if (!from_str)
69 return NULL;
70 else {
71 char *to_str;
72 unsigned long length = strlen(from_str);
73 unsigned long retval;
74
75 /* Pre-allocate a new string that could hold twice the original, which would only
76 * happen if the whole original string was 'dangerous' characters.
77 * And forsee the space for the 2 '
78 */
79 temp = to_str = (char *) apr_palloc(p, length * 2 + 3);
80 if (!to_str) {
81 return from_str;
82 }
83
84 *temp = '\'';
85 temp++;
86
87 retval = PQescapeString(temp, from_str, length);
88
89 /* avoid the string to be tolong for the sql database*/
90 if (retval > 250) retval = 250;
91
92 *(temp+retval) = '\'';
93 *(temp+retval+1) = '\0';
94
95 /* We must always return the to_str, because we always need the ' added */
96// if (retval)
97 return to_str;
98// else
99// return from_str;
100 }
101}
102
103/* Run a sql insert query and return a categorized error or success */
104static logsql_query_ret log_sql_pgsql_query(request_rec *r,logsql_dbconnection *db,
105 const char *query)
106{
107 PGresult *result;
108 void (*handler) (int);
109 unsigned int real_error = 0;
110 /*const char *real_error_str = NULL;*/
111
112 PGconn *conn = db->handle;
113
114 if (PQstatus(conn) != CONNECTION_OK) {
115 return LOGSQL_QUERY_NOLINK;
116 }
117 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
118 /* Does postgresql do this also ??? */
119 handler = signal(SIGPIPE, SIG_IGN);
120
121 result = PQexec(conn, query);
122 /* Run the query */
123 if (PQresultStatus(result) == PGRES_COMMAND_OK) {
124 signal(SIGPIPE, handler);
125 PQclear(result);
126 return LOGSQL_QUERY_SUCCESS;
127 }
128 /* Check to see if the error is "nonexistent table" */
129 /* removed ... don't know how ! (sorry)
130 real_error = mysql_errno(dblink);
131
132 if (real_error == ER_NO_SUCH_TABLE) {
133 log_error(APLOG_MARK,APLOG_ERR,0, r->server,"table does not exist, preserving query");
134 signal(SIGPIPE, handler);
135 PQclear(result);
136 return LOGSQL_QUERY_NOTABLE;
137 }*/
138
139 /* Restore SIGPIPE to its original handler function */
140 signal(SIGPIPE, handler);
141 PQclear(result);
142 return LOGSQL_QUERY_FAIL;
143}
144
145/* Create table table_name of type table_type. */
146static logsql_table_ret log_sql_pgsql_create(request_rec *r, logsql_dbconnection *db,
147 logsql_tabletype table_type, const char *table_name)
148{
149 PGresult *result;
150 const char *tabletype = apr_table_get(db->parms,"tabletype");
151 void (*handler) (int);
152 char *type_suffix = NULL;
153
154 char *create_prefix = "create table if not exists `";
155 char *create_suffix = NULL;
156 char *create_sql;
157
158 PGconn *conn = db->handle;
159
160/* if (!global_config.createtables) {
161 return APR_SUCCESS;
162 }*/
163
164 switch (table_type) {
165 case LOGSQL_TABLE_ACCESS:
166 create_suffix =
167 "` (id char(19),\
168 agent varchar(255),\
169 bytes_sent int unsigned,\
170 child_pid smallint unsigned,\
171 cookie varchar(255),\
172 machine_id varchar(25),\
173 request_file varchar(255),\
174 referer varchar(255),\
175 remote_host varchar(50),\
176 remote_logname varchar(50),\
177 remote_user varchar(50),\
178 request_duration smallint unsigned,\
179 request_line varchar(255),\
180 request_method varchar(10),\
181 request_protocol varchar(10),\
182 request_time char(28),\
183 request_uri varchar(255),\
184 request_args varchar(255),\
185 server_port smallint unsigned,\
186 ssl_cipher varchar(25),\
187 ssl_keysize smallint unsigned,\
188 ssl_maxkeysize smallint unsigned,\
189 status smallint unsigned,\
190 time_stamp int unsigned,\
191 virtual_host varchar(255))";
192 break;
193 case LOGSQL_TABLE_COOKIES:
194 case LOGSQL_TABLE_HEADERSIN:
195 case LOGSQL_TABLE_HEADERSOUT:
196 case LOGSQL_TABLE_NOTES:
197 create_suffix =
198 "` (id char(19),\
199 item varchar(80),\
200 val varchar(80))";
201 break;
202 }
203
204 if (tabletype) {
205 type_suffix = apr_pstrcat(r->pool, " TYPE=",
206 tabletype, NULL);
207 }
208 /* Find memory long enough to hold the whole CREATE string + \0 */
209 create_sql = apr_pstrcat(r->pool, create_prefix, table_name, create_suffix,
210 type_suffix, NULL);
211
212 log_error(APLOG_MARK,APLOG_DEBUG,0, r->server,"create string: %s", create_sql);
213
214 if (PQstatus(conn) != CONNECTION_OK) {
215 return LOGSQL_QUERY_NOLINK;
216 }
217 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
218 handler = signal(SIGPIPE, SIG_IGN);
219
220 /* Run the create query */
221 result = PQexec(conn, create_sql);
222 if (PQresultStatus(result) != PGRES_COMMAND_OK) {
223 log_error(APLOG_MARK,APLOG_ERR,0, r->server,"failed to create table: %s",
224 table_name);
225 signal(SIGPIPE, handler);
226 PQclear(result);
227 return LOGSQL_TABLE_FAIL;
228 }
229 signal(SIGPIPE, handler);
230 PQclear(result);
231 return LOGSQL_TABLE_SUCCESS;
232}
233
234static char *supported_drivers[] = {"pgsql",NULL};
235static logsql_dbdriver pgsql_driver = {
236 supported_drivers,
237 log_sql_pgsql_connect, /* open DB connection */
238 log_sql_pgsql_close, /* close DB connection */
239 log_sql_pgsql_escape, /* escape query */
240 log_sql_pgsql_query, /* insert query */
241 log_sql_pgsql_create /* create table */
242};
243
244LOGSQL_REGISTER(pgsql) {
245 log_sql_register_driver(p,&pgsql_driver);
246 LOGSQL_REGISTER_RETURN;
247}