1 /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include "apu_config.h"
26 #ifdef HAVE_LIBPQ_FE_H
28 #elif defined(HAVE_POSTGRESQL_LIBPQ_FE_H)
29 #include <postgresql/libpq-fe.h>
32 #include "apr_strings.h"
35 #include "apr_dbd_internal.h"
37 #define QUERY_MAX_ARGS 40
39 struct apr_dbd_transaction_t
{
46 apr_dbd_transaction_t
*trans
;
49 struct apr_dbd_results_t
{
58 struct apr_dbd_row_t
{
60 apr_dbd_results_t
*res
;
63 struct apr_dbd_prepared_t
{
68 #define dbd_pgsql_is_success(x) (((x) == PGRES_EMPTY_QUERY) \
69 || ((x) == PGRES_COMMAND_OK) \
70 || ((x) == PGRES_TUPLES_OK))
72 static apr_status_t
clear_result(void *data
)
78 static int dbd_pgsql_select(apr_pool_t
*pool
, apr_dbd_t
*sql
,
79 apr_dbd_results_t
**results
,
80 const char *query
, int seek
)
84 if ( sql
->trans
&& sql
->trans
->errnum
) {
85 return sql
->trans
->errnum
;
87 if (seek
) { /* synchronous query */
88 res
= PQexec(sql
->conn
, query
);
90 ret
= PQresultStatus(res
);
91 if (dbd_pgsql_is_success(ret
)) {
97 ret
= PGRES_FATAL_ERROR
;
101 sql
->trans
->errnum
= ret
;
106 *results
= apr_pcalloc(pool
, sizeof(apr_dbd_results_t
));
108 (*results
)->res
= res
;
109 (*results
)->ntuples
= PQntuples(res
);
110 (*results
)->sz
= PQnfields(res
);
111 (*results
)->random
= seek
;
112 apr_pool_cleanup_register(pool
, res
, clear_result
,
113 apr_pool_cleanup_null
);
116 if (PQsendQuery(sql
->conn
, query
) == 0) {
118 sql
->trans
->errnum
= 1;
122 if (*results
== NULL
) {
123 *results
= apr_pcalloc(pool
, sizeof(apr_dbd_results_t
));
125 (*results
)->random
= seek
;
126 (*results
)->handle
= sql
->conn
;
131 static const char *dbd_pgsql_get_name(const apr_dbd_results_t
*res
, int n
)
133 return (res
->res
? PQfname(res
->res
, n
) : NULL
);
136 static int dbd_pgsql_get_row(apr_pool_t
*pool
, apr_dbd_results_t
*res
,
137 apr_dbd_row_t
**rowp
, int rownum
)
139 apr_dbd_row_t
*row
= *rowp
;
140 int sequential
= ((rownum
>= 0) && res
->random
) ? 0 : 1;
143 row
= apr_palloc(pool
, sizeof(apr_dbd_row_t
));
146 row
->n
= sequential
? 0 : rownum
;
158 if (row
->n
>= res
->ntuples
) {
160 apr_pool_cleanup_kill(pool
, res
->res
, (void*)PQclear
);
167 if (row
->n
>= res
->ntuples
) {
168 /* no data; we have to fetch some */
169 row
->n
-= res
->ntuples
;
170 if (res
->res
!= NULL
) {
173 res
->res
= PQgetResult(res
->handle
);
175 res
->ntuples
= PQntuples(res
->res
);
176 while (res
->ntuples
== 0) {
177 /* if we got an empty result, clear it, wait a mo, try
180 apr_sleep(100000); /* 0.1 secs */
181 res
->res
= PQgetResult(res
->handle
);
183 res
->ntuples
= PQntuples(res
->res
);
190 res
->sz
= PQnfields(res
->res
);
201 static const char *dbd_pgsql_get_entry(const apr_dbd_row_t
*row
, int n
)
203 return PQgetvalue(row
->res
->res
, row
->n
, n
);
206 static const char *dbd_pgsql_error(apr_dbd_t
*sql
, int n
)
208 return PQerrorMessage(sql
->conn
);
211 static int dbd_pgsql_query(apr_dbd_t
*sql
, int *nrows
, const char *query
)
215 if (sql
->trans
&& sql
->trans
->errnum
) {
216 return sql
->trans
->errnum
;
218 res
= PQexec(sql
->conn
, query
);
220 ret
= PQresultStatus(res
);
221 if (dbd_pgsql_is_success(ret
)) {
222 /* ugh, making 0 return-success doesn't fit */
225 *nrows
= atoi(PQcmdTuples(res
));
229 ret
= PGRES_FATAL_ERROR
;
232 sql
->trans
->errnum
= ret
;
237 static const char *dbd_pgsql_escape(apr_pool_t
*pool
, const char *arg
,
240 size_t len
= strlen(arg
);
241 char *ret
= apr_palloc(pool
, 2*len
+ 2);
242 PQescapeString(ret
, arg
, len
);
246 static int dbd_pgsql_prepare(apr_pool_t
*pool
, apr_dbd_t
*sql
,
247 const char *query
, const char *label
,
248 apr_dbd_prepared_t
**statement
)
254 const char *args
[QUERY_MAX_ARGS
];
263 *statement
= apr_palloc(pool
, sizeof(apr_dbd_prepared_t
));
265 /* Translate from apr_dbd to native query format */
266 for (sqlptr
= (char*)query
; *sqlptr
; ++sqlptr
) {
267 if (sqlptr
[0] == '%') {
268 if (isalpha(sqlptr
[1])) {
271 else if (sqlptr
[1] == '%') {
276 length
= strlen(query
) + 1;
280 pgptr
= pgquery
= apr_palloc(pool
, length
) ;
282 for (sqlptr
= (char*)query
; *sqlptr
; ++sqlptr
) {
283 if ((sqlptr
[0] == '%') && isalpha(sqlptr
[1])) {
289 *pgptr
++ = '0' + ((i
+1)/10);
290 *pgptr
++ = '0' + ((i
+1)%10);
303 length
+= 1 + strlen(args
[i
]);
306 else if ((sqlptr
[0] == '%') && (sqlptr
[1] == '%')) {
308 *pgptr
++ = *sqlptr
++;
317 /* don't really prepare; use in execParams instead */
318 (*statement
)->prepared
= 0;
319 (*statement
)->name
= apr_pstrdup(pool
, pgquery
);
322 (*statement
)->name
= apr_pstrdup(pool
, label
);
324 /* length of SQL query that prepares this statement */
325 length
= 8 + strlen(label
) + 2 + 4 + length
+ 1;
326 sqlcmd
= apr_palloc(pool
, length
);
328 memcpy(sqlptr
, "PREPARE ", 8);
330 length
= strlen(label
);
331 memcpy(sqlptr
, label
, length
);
334 memcpy(sqlptr
, " (",2);
336 for (i
=0; i
<nargs
; ++i
) {
337 alen
= strlen(args
[i
]);
338 memcpy(sqlptr
, args
[i
], alen
);
344 memcpy(sqlptr
, " AS ", 4);
346 memcpy(sqlptr
, pgquery
, strlen(pgquery
));
347 sqlptr
+= strlen(pgquery
);
350 res
= PQexec(sql
->conn
, sqlcmd
);
352 ret
= PQresultStatus(res
);
353 if (dbd_pgsql_is_success(ret
)) {
356 /* Hmmm, do we do this here or register it on the pool? */
360 ret
= PGRES_FATAL_ERROR
;
362 (*statement
)->prepared
= 1;
367 static int dbd_pgsql_pquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
368 int *nrows
, apr_dbd_prepared_t
*statement
,
369 int nargs
, const char **values
)
374 if (sql
->trans
&& sql
->trans
->errnum
) {
375 return sql
->trans
->errnum
;
378 if (statement
->prepared
) {
379 res
= PQexecPrepared(sql
->conn
, statement
->name
, nargs
, values
, 0, 0,
383 res
= PQexecParams(sql
->conn
, statement
->name
, nargs
, 0, values
, 0, 0,
387 ret
= PQresultStatus(res
);
388 if (dbd_pgsql_is_success(ret
)) {
391 *nrows
= atoi(PQcmdTuples(res
));
395 ret
= PGRES_FATAL_ERROR
;
399 sql
->trans
->errnum
= ret
;
404 static int dbd_pgsql_pvquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
405 int *nrows
, apr_dbd_prepared_t
*statement
,
410 const char *values
[QUERY_MAX_ARGS
];
412 if (sql
->trans
&& sql
->trans
->errnum
) {
413 return sql
->trans
->errnum
;
415 while ( arg
= va_arg(args
, const char*), arg
) {
416 if ( nargs
>= QUERY_MAX_ARGS
) {
420 values
[nargs
++] = apr_pstrdup(pool
, arg
);
422 values
[nargs
] = NULL
;
423 return dbd_pgsql_pquery(pool
, sql
, nrows
, statement
, nargs
, values
);
426 static int dbd_pgsql_pselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
427 apr_dbd_results_t
**results
,
428 apr_dbd_prepared_t
*statement
,
429 int seek
, int nargs
, const char **values
)
435 if (sql
->trans
&& sql
->trans
->errnum
) {
436 return sql
->trans
->errnum
;
439 if (seek
) { /* synchronous query */
440 if (statement
->prepared
) {
441 res
= PQexecPrepared(sql
->conn
, statement
->name
, nargs
, values
, 0,
445 res
= PQexecParams(sql
->conn
, statement
->name
, nargs
, 0, values
, 0,
449 ret
= PQresultStatus(res
);
450 if (dbd_pgsql_is_success(ret
)) {
458 ret
= PGRES_FATAL_ERROR
;
462 sql
->trans
->errnum
= ret
;
467 *results
= apr_pcalloc(pool
, sizeof(apr_dbd_results_t
));
469 (*results
)->res
= res
;
470 (*results
)->ntuples
= PQntuples(res
);
471 (*results
)->sz
= PQnfields(res
);
472 (*results
)->random
= seek
;
473 apr_pool_cleanup_register(pool
, res
, clear_result
,
474 apr_pool_cleanup_null
);
477 if (statement
->prepared
) {
478 rv
= PQsendQueryPrepared(sql
->conn
, statement
->name
, nargs
, values
,
482 rv
= PQsendQueryParams(sql
->conn
, statement
->name
, nargs
, 0,
487 sql
->trans
->errnum
= 1;
492 *results
= apr_pcalloc(pool
, sizeof(apr_dbd_results_t
));
494 (*results
)->random
= seek
;
495 (*results
)->handle
= sql
->conn
;
499 sql
->trans
->errnum
= ret
;
504 static int dbd_pgsql_pvselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
505 apr_dbd_results_t
**results
,
506 apr_dbd_prepared_t
*statement
,
507 int seek
, va_list args
)
511 const char *values
[QUERY_MAX_ARGS
];
513 if (sql
->trans
&& sql
->trans
->errnum
) {
514 return sql
->trans
->errnum
;
517 while (arg
= va_arg(args
, const char*), arg
) {
518 if ( nargs
>= QUERY_MAX_ARGS
) {
522 values
[nargs
++] = apr_pstrdup(pool
, arg
);
524 return dbd_pgsql_pselect(pool
, sql
, results
, statement
,
525 seek
, nargs
, values
) ;
528 static int dbd_pgsql_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*handle
,
529 apr_dbd_transaction_t
**trans
)
534 /* XXX handle recursive transactions here */
536 res
= PQexec(handle
->conn
, "BEGIN TRANSACTION");
538 ret
= PQresultStatus(res
);
539 if (dbd_pgsql_is_success(ret
)) {
542 *trans
= apr_pcalloc(pool
, sizeof(apr_dbd_transaction_t
));
546 (*trans
)->handle
= handle
;
547 handle
->trans
= *trans
;
550 ret
= PGRES_FATAL_ERROR
;
555 static int dbd_pgsql_end_transaction(apr_dbd_transaction_t
*trans
)
558 int ret
= -1; /* no transaction is an error cond */
562 res
= PQexec(trans
->handle
->conn
, "ROLLBACK");
565 res
= PQexec(trans
->handle
->conn
, "COMMIT");
568 ret
= PQresultStatus(res
);
569 if (dbd_pgsql_is_success(ret
)) {
575 ret
= PGRES_FATAL_ERROR
;
577 trans
->handle
->trans
= NULL
;
582 static apr_dbd_t
*dbd_pgsql_open(apr_pool_t
*pool
, const char *params
)
586 PGconn
*conn
= PQconnectdb(params
);
588 /* if there's an error in the connect string or something we get
589 * back a * bogus connection object, and things like PQreset are
590 * liable to segfault, so just close it out now. it would be nice
591 * if we could give an indication of why we failed to connect... */
592 if (PQstatus(conn
) != CONNECTION_OK
) {
597 sql
= apr_pcalloc (pool
, sizeof (*sql
));
604 static apr_status_t
dbd_pgsql_close(apr_dbd_t
*handle
)
606 PQfinish(handle
->conn
);
610 static apr_status_t
dbd_pgsql_check_conn(apr_pool_t
*pool
,
613 if (PQstatus(handle
->conn
) != CONNECTION_OK
) {
614 PQreset(handle
->conn
);
615 if (PQstatus(handle
->conn
) != CONNECTION_OK
) {
622 static int dbd_pgsql_select_db(apr_pool_t
*pool
, apr_dbd_t
*handle
,
628 static void *dbd_pgsql_native(apr_dbd_t
*handle
)
633 static int dbd_pgsql_num_cols(apr_dbd_results_t
* res
)
638 static int dbd_pgsql_num_tuples(apr_dbd_results_t
* res
)
648 APU_DECLARE_DATA
const apr_dbd_driver_t apr_dbd_pgsql_driver
= {
653 dbd_pgsql_check_conn
,
656 dbd_pgsql_start_transaction
,
657 dbd_pgsql_end_transaction
,
661 dbd_pgsql_num_tuples
,