Apache HTTPD
apr_dbd_pgsql.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include "apu.h"
18
19#if APU_HAVE_PGSQL
20
21#include "apu_config.h"
22
23#include <ctype.h>
24#include <stdlib.h>
25
26#ifdef HAVE_LIBPQ_FE_H
27#include <libpq-fe.h>
28#elif defined(HAVE_POSTGRESQL_LIBPQ_FE_H)
29#include <postgresql/libpq-fe.h>
30#endif
31
32#include "apr_strings.h"
33#include "apr_time.h"
34#include "apr_buckets.h"
35
36#include "apr_dbd_internal.h"
37
39 int mode;
40 int errnum;
42};
43
44struct apr_dbd_t {
45 PGconn *conn;
47};
48
49struct apr_dbd_results_t {
50 int random;
53 size_t ntuples;
54 size_t sz;
55 size_t index;
57};
58
59struct apr_dbd_row_t {
60 int n;
62};
63
64struct apr_dbd_prepared_t {
65 const char *name;
66 int prepared;
67 int nargs;
68 int nvals;
70};
71
72#define dbd_pgsql_is_success(x) (((x) == PGRES_EMPTY_QUERY) \
73 || ((x) == PGRES_COMMAND_OK) \
74 || ((x) == PGRES_TUPLES_OK))
75
76static apr_status_t clear_result(void *data)
77{
79 return APR_SUCCESS;
80}
81
83 apr_dbd_results_t **results,
84 const char *query, int seek)
85{
87 int ret;
88 if ( sql->trans && sql->trans->errnum ) {
89 return sql->trans->errnum;
90 }
91 if (seek) { /* synchronous query */
92 if (TXN_IGNORE_ERRORS(sql->trans)) {
93 PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
94 if (res) {
95 int ret = PQresultStatus(res);
96 PQclear(res);
98 sql->trans->errnum = ret;
99 return PGRES_FATAL_ERROR;
100 }
101 } else {
102 return sql->trans->errnum = PGRES_FATAL_ERROR;
103 }
104 }
105 res = PQexec(sql->conn, query);
106 if (res) {
109 ret = 0;
110 } else {
111 PQclear(res);
112 }
113 } else {
115 }
116 if (ret != 0) {
117 if (TXN_IGNORE_ERRORS(sql->trans)) {
118 PGresult *res = PQexec(sql->conn,
119 "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
120 if (res) {
121 int ret = PQresultStatus(res);
122 PQclear(res);
124 sql->trans->errnum = ret;
125 return PGRES_FATAL_ERROR;
126 }
127 } else {
128 return sql->trans->errnum = PGRES_FATAL_ERROR;
129 }
130 } else if (TXN_NOTICE_ERRORS(sql->trans)){
131 sql->trans->errnum = ret;
132 }
133 return ret;
134 } else {
135 if (TXN_IGNORE_ERRORS(sql->trans)) {
136 PGresult *res = PQexec(sql->conn,
137 "RELEASE SAVEPOINT APR_DBD_TXN_SP");
138 if (res) {
139 int ret = PQresultStatus(res);
140 PQclear(res);
142 sql->trans->errnum = ret;
143 return PGRES_FATAL_ERROR;
144 }
145 } else {
146 return sql->trans->errnum = PGRES_FATAL_ERROR;
147 }
148 }
149 }
150 if (!*results) {
151 *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
152 }
153 (*results)->res = res;
154 (*results)->ntuples = PQntuples(res);
155 (*results)->sz = PQnfields(res);
156 (*results)->random = seek;
157 (*results)->pool = pool;
160 }
161 else {
162 if (TXN_IGNORE_ERRORS(sql->trans)) {
163 PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
164 if (res) {
165 int ret = PQresultStatus(res);
166 PQclear(res);
168 sql->trans->errnum = ret;
169 return PGRES_FATAL_ERROR;
170 }
171 } else {
172 return sql->trans->errnum = PGRES_FATAL_ERROR;
173 }
174 }
175 if (PQsendQuery(sql->conn, query) == 0) {
176 if (TXN_IGNORE_ERRORS(sql->trans)) {
177 PGresult *res = PQexec(sql->conn,
178 "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
179 if (res) {
180 int ret = PQresultStatus(res);
181 PQclear(res);
183 sql->trans->errnum = ret;
184 return PGRES_FATAL_ERROR;
185 }
186 } else {
187 return sql->trans->errnum = PGRES_FATAL_ERROR;
188 }
189 } else if (TXN_NOTICE_ERRORS(sql->trans)){
190 sql->trans->errnum = 1;
191 }
192 return 1;
193 } else {
194 if (TXN_IGNORE_ERRORS(sql->trans)) {
195 PGresult *res = PQexec(sql->conn,
196 "RELEASE SAVEPOINT APR_DBD_TXN_SP");
197 if (res) {
198 int ret = PQresultStatus(res);
199 PQclear(res);
201 sql->trans->errnum = ret;
202 return PGRES_FATAL_ERROR;
203 }
204 } else {
205 return sql->trans->errnum = PGRES_FATAL_ERROR;
206 }
207 }
208 }
209 if (*results == NULL) {
210 *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
211 }
212 (*results)->random = seek;
213 (*results)->handle = sql->conn;
214 (*results)->pool = pool;
215 }
216 return 0;
217}
218
219static const char *dbd_pgsql_get_name(const apr_dbd_results_t *res, int n)
220{
221 if (res->res) {
222 if ((n>=0) && (PQnfields(res->res) > n)) {
223 return PQfname(res->res,n);
224 }
225 }
226 return NULL;
227}
228
231{
233 int sequential = ((rownum >= 0) && res->random) ? 0 : 1;
234
235 if (row == NULL) {
236 row = apr_palloc(pool, sizeof(apr_dbd_row_t));
237 *rowp = row;
238 row->res = res;
239 if ( sequential ) {
240 row->n = 0;
241 }
242 else {
243 if (rownum > 0) {
244 row->n = --rownum;
245 }
246 else {
247 return -1; /* invalid row */
248 }
249 }
250 }
251 else {
252 if ( sequential ) {
253 ++row->n;
254 }
255 else {
256 if (rownum > 0) {
257 row->n = --rownum;
258 }
259 else {
260 return -1; /* invalid row */
261 }
262 }
263 }
264
265 if (res->random) {
266 if ((row->n >= 0) && (size_t)row->n >= res->ntuples) {
267 *rowp = NULL;
269 res->res = NULL;
270 return -1;
271 }
272 }
273 else {
274 if ((row->n >= 0) && (size_t)row->n >= res->ntuples) {
275 /* no data; we have to fetch some */
276 row->n -= res->ntuples;
277 if (res->res != NULL) {
278 PQclear(res->res);
279 }
280 res->res = PQgetResult(res->handle);
281 if (res->res) {
282 res->ntuples = PQntuples(res->res);
283 while (res->ntuples == 0) {
284 /* if we got an empty result, clear it, wait a mo, try
285 * again */
286 PQclear(res->res);
287 apr_sleep(100000); /* 0.1 secs */
288 res->res = PQgetResult(res->handle);
289 if (res->res) {
290 res->ntuples = PQntuples(res->res);
291 }
292 else {
293 return -1;
294 }
295 }
296 if (res->sz == 0) {
297 res->sz = PQnfields(res->res);
298 }
299 }
300 else {
301 return -1;
302 }
303 }
304 }
305 return 0;
306}
307
308static const char *dbd_pgsql_get_entry(const apr_dbd_row_t *row, int n)
309{
310 return PQgetvalue(row->res->res, row->n, n);
311}
312
314 apr_dbd_type_e type, void *data)
315{
316 if (PQgetisnull(row->res->res, row->n, n)) {
317 return APR_ENOENT;
318 }
319
320 switch (type) {
322 *(char*)data = atoi(PQgetvalue(row->res->res, row->n, n));
323 break;
325 *(unsigned char*)data = atoi(PQgetvalue(row->res->res, row->n, n));
326 break;
328 *(short*)data = atoi(PQgetvalue(row->res->res, row->n, n));
329 break;
331 *(unsigned short*)data = atoi(PQgetvalue(row->res->res, row->n, n));
332 break;
333 case APR_DBD_TYPE_INT:
334 *(int*)data = atoi(PQgetvalue(row->res->res, row->n, n));
335 break;
337 *(unsigned int*)data = atoi(PQgetvalue(row->res->res, row->n, n));
338 break;
340 *(long*)data = atol(PQgetvalue(row->res->res, row->n, n));
341 break;
343 *(unsigned long*)data = atol(PQgetvalue(row->res->res, row->n, n));
344 break;
346 *(apr_int64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n));
347 break;
349 *(apr_uint64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n));
350 break;
352 *(float*)data = (float)atof(PQgetvalue(row->res->res, row->n, n));
353 break;
355 *(double*)data = atof(PQgetvalue(row->res->res, row->n, n));
356 break;
364 *(char**)data = PQgetvalue(row->res->res, row->n, n);
365 break;
368 {
369 apr_bucket *e;
371
372 e = apr_bucket_pool_create(PQgetvalue(row->res->res, row->n, n),
373 PQgetlength(row->res->res, row->n, n),
374 row->res->pool, b->bucket_alloc);
376 }
377 break;
379 *(void**)data = NULL;
380 break;
381 default:
382 return APR_EGENERAL;
383 }
384
385 return APR_SUCCESS;
386}
387
388static const char *dbd_pgsql_error(apr_dbd_t *sql, int n)
389{
390 return PQerrorMessage(sql->conn);
391}
392
393static int dbd_pgsql_query(apr_dbd_t *sql, int *nrows, const char *query)
394{
395 PGresult *res;
396 int ret;
397 if (sql->trans && sql->trans->errnum) {
398 return sql->trans->errnum;
399 }
400
401 if (TXN_IGNORE_ERRORS(sql->trans)) {
402 PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
403 if (res) {
404 int ret = PQresultStatus(res);
405 PQclear(res);
407 sql->trans->errnum = ret;
408 return PGRES_FATAL_ERROR;
409 }
410 } else {
411 return sql->trans->errnum = PGRES_FATAL_ERROR;
412 }
413 }
414
415 res = PQexec(sql->conn, query);
416 if (res) {
419 /* ugh, making 0 return-success doesn't fit */
420 ret = 0;
421 }
423 PQclear(res);
424 }
425 else {
427 }
428
429 if (ret != 0){
430 if (TXN_IGNORE_ERRORS(sql->trans)) {
431 PGresult *res = PQexec(sql->conn,
432 "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
433 if (res) {
434 int ret = PQresultStatus(res);
435 PQclear(res);
437 sql->trans->errnum = ret;
438 return PGRES_FATAL_ERROR;
439 }
440 } else {
441 sql->trans->errnum = ret;
442 return PGRES_FATAL_ERROR;
443 }
444 } else if (TXN_NOTICE_ERRORS(sql->trans)){
445 sql->trans->errnum = ret;
446 }
447 } else {
448 if (TXN_IGNORE_ERRORS(sql->trans)) {
449 PGresult *res = PQexec(sql->conn,
450 "RELEASE SAVEPOINT APR_DBD_TXN_SP");
451 if (res) {
452 int ret = PQresultStatus(res);
453 PQclear(res);
455 sql->trans->errnum = ret;
456 return PGRES_FATAL_ERROR;
457 }
458 } else {
459 sql->trans->errnum = ret;
460 return PGRES_FATAL_ERROR;
461 }
462 }
463 }
464
465 return ret;
466}
467
468static const char *dbd_pgsql_escape(apr_pool_t *pool, const char *arg,
469 apr_dbd_t *sql)
470{
471 size_t len = strlen(arg);
472 char *ret = apr_palloc(pool, 2*len + 2);
474 return ret;
475}
476
478 const char *query, const char *label,
479 int nargs, int nvals, apr_dbd_type_e *types,
481{
482 char *sqlcmd;
483 char *sqlptr;
484 size_t length, qlen;
485 int i = 0;
486 const char **args;
487 size_t alen;
488 int ret;
489 PGresult *res;
490
491 if (!*statement) {
493 }
494 (*statement)->nargs = nargs;
495 (*statement)->nvals = nvals;
496 (*statement)->types = types;
497
498 args = apr_palloc(pool, nargs * sizeof(*args));
499
500 qlen = strlen(query);
501 length = qlen + 1;
502
503 for (i = 0; i < nargs; i++) {
504 switch (types[i]) {
505 case APR_DBD_TYPE_TINY:
506 case APR_DBD_TYPE_UTINY:
507 case APR_DBD_TYPE_SHORT:
509 args[i] = "smallint";
510 break;
511 case APR_DBD_TYPE_INT:
513 args[i] = "integer";
514 break;
515 case APR_DBD_TYPE_LONG:
516 case APR_DBD_TYPE_ULONG:
519 args[i] = "bigint";
520 break;
522 args[i] = "real";
523 break;
525 args[i] = "double precision";
526 break;
528 args[i] = "text";
529 break;
531 args[i] = "time";
532 break;
534 args[i] = "date";
535 break;
538 args[i] = "timestamp";
539 break;
541 args[i] = "timestamp with time zone";
542 break;
545 args[i] = "bytea";
546 break;
548 args[i] = "varchar"; /* XXX Eh? */
549 break;
550 default:
551 args[i] = "varchar";
552 break;
553 }
554 length += 1 + strlen(args[i]);
555 }
556
557 if (!label) {
558 /* don't really prepare; use in execParams instead */
559 (*statement)->prepared = 0;
560 (*statement)->name = apr_pstrdup(pool, query);
561 return 0;
562 }
563 (*statement)->name = apr_pstrdup(pool, label);
564
565 /* length of SQL query that prepares this statement */
566 length = 8 + strlen(label) + 2 + 4 + length + 1;
568 sqlptr = sqlcmd;
569 memcpy(sqlptr, "PREPARE ", 8);
570 sqlptr += 8;
571 length = strlen(label);
573 sqlptr += length;
574 if (nargs > 0) {
575 memcpy(sqlptr, " (",2);
576 sqlptr += 2;
577 for (i=0; i < nargs; ++i) {
578 alen = strlen(args[i]);
579 memcpy(sqlptr, args[i], alen);
580 sqlptr += alen;
581 *sqlptr++ = ',';
582 }
583 sqlptr[-1] = ')';
584 }
585 memcpy(sqlptr, " AS ", 4);
586 sqlptr += 4;
588 sqlptr += qlen;
589 *sqlptr = 0;
590
591 res = PQexec(sql->conn, sqlcmd);
592 if ( res ) {
595 ret = 0;
596 }
597 /* Hmmm, do we do this here or register it on the pool? */
598 PQclear(res);
599 }
600 else {
602 }
603 (*statement)->prepared = 1;
604
605 return ret;
606}
607
610 const char **values,
611 const int *len, const int *fmt)
612{
613 int ret;
614 PGresult *res;
615
616 if (TXN_IGNORE_ERRORS(sql->trans)) {
617 PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
618 if (res) {
619 int ret = PQresultStatus(res);
620 PQclear(res);
622 sql->trans->errnum = ret;
623 return PGRES_FATAL_ERROR;
624 }
625 } else {
626 return sql->trans->errnum = PGRES_FATAL_ERROR;
627 }
628 }
629
630 if (statement->prepared) {
631 res = PQexecPrepared(sql->conn, statement->name, statement->nargs,
632 values, len, fmt, 0);
633 }
634 else {
635 res = PQexecParams(sql->conn, statement->name, statement->nargs, 0,
636 values, len, fmt, 0);
637 }
638 if (res) {
641 ret = 0;
642 }
644 PQclear(res);
645 }
646 else {
648 }
649
650 if (ret != 0){
651 if (TXN_IGNORE_ERRORS(sql->trans)) {
652 PGresult *res = PQexec(sql->conn,
653 "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
654 if (res) {
655 int ret = PQresultStatus(res);
656 PQclear(res);
658 sql->trans->errnum = ret;
659 return PGRES_FATAL_ERROR;
660 }
661 } else {
662 sql->trans->errnum = ret;
663 return PGRES_FATAL_ERROR;
664 }
665 } else if (TXN_NOTICE_ERRORS(sql->trans)){
666 sql->trans->errnum = ret;
667 }
668 } else {
669 if (TXN_IGNORE_ERRORS(sql->trans)) {
670 PGresult *res = PQexec(sql->conn,
671 "RELEASE SAVEPOINT APR_DBD_TXN_SP");
672 if (res) {
673 int ret = PQresultStatus(res);
674 PQclear(res);
676 sql->trans->errnum = ret;
677 return PGRES_FATAL_ERROR;
678 }
679 } else {
680 sql->trans->errnum = ret;
681 return PGRES_FATAL_ERROR;
682 }
683 }
684 }
685
686 return ret;
687}
688
690 const char **values,
691 const char **val, int *len, int *fmt)
692{
693 int i, j;
694
695 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
696 if (values[j] == NULL) {
697 val[i] = NULL;
698 }
699 else {
700 switch (statement->types[i]) {
703 val[i] = (char *)values[j];
704 len[i] = atoi(values[++j]);
705 fmt[i] = 1;
706
707 /* skip table and column */
708 j += 2;
709 break;
710 default:
711 val[i] = values[j];
712 break;
713 }
714 }
715 }
716
717 return;
718}
719
722 const char **values)
723{
724 int *len, *fmt;
725 const char **val;
726
727 if (sql->trans && sql->trans->errnum) {
728 return sql->trans->errnum;
729 }
730
731 val = apr_palloc(pool, sizeof(*val) * statement->nargs);
732 len = apr_pcalloc(pool, sizeof(*len) * statement->nargs);
733 fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs);
734
736
738 val, len, fmt);
739}
740
744{
745 const char **values;
746 int i;
747
748 if (sql->trans && sql->trans->errnum) {
749 return sql->trans->errnum;
750 }
751
752 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
753
754 for (i = 0; i < statement->nvals; i++) {
755 values[i] = va_arg(args, const char*);
756 }
757
759}
760
762 apr_dbd_results_t **results,
764 int seek, const char **values,
765 const int *len, const int *fmt)
766{
767 PGresult *res;
768 int rv;
769 int ret = 0;
770
771 if (seek) { /* synchronous query */
772 if (TXN_IGNORE_ERRORS(sql->trans)) {
773 PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
774 if (res) {
775 int ret = PQresultStatus(res);
776 PQclear(res);
778 sql->trans->errnum = ret;
779 return PGRES_FATAL_ERROR;
780 }
781 } else {
782 sql->trans->errnum = ret;
783 return PGRES_FATAL_ERROR;
784 }
785 }
786 if (statement->prepared) {
787 res = PQexecPrepared(sql->conn, statement->name, statement->nargs,
788 values, len, fmt, 0);
789 }
790 else {
791 res = PQexecParams(sql->conn, statement->name, statement->nargs, 0,
792 values, len, fmt, 0);
793 }
794 if (res) {
797 ret = 0;
798 }
799 else {
800 PQclear(res);
801 }
802 }
803 else {
805 }
806 if (ret != 0) {
807 if (TXN_IGNORE_ERRORS(sql->trans)) {
808 PGresult *res = PQexec(sql->conn,
809 "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
810 if (res) {
811 int ret = PQresultStatus(res);
812 PQclear(res);
814 sql->trans->errnum = ret;
815 return PGRES_FATAL_ERROR;
816 }
817 } else {
818 sql->trans->errnum = ret;
819 return PGRES_FATAL_ERROR;
820 }
821 } else if (TXN_NOTICE_ERRORS(sql->trans)){
822 sql->trans->errnum = ret;
823 }
824 return ret;
825 } else {
826 if (TXN_IGNORE_ERRORS(sql->trans)) {
827 PGresult *res = PQexec(sql->conn,
828 "RELEASE SAVEPOINT APR_DBD_TXN_SP");
829 if (res) {
830 int ret = PQresultStatus(res);
831 PQclear(res);
833 sql->trans->errnum = ret;
834 return PGRES_FATAL_ERROR;
835 }
836 } else {
837 sql->trans->errnum = ret;
838 return PGRES_FATAL_ERROR;
839 }
840 }
841 }
842 if (!*results) {
843 *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
844 }
845 (*results)->res = res;
846 (*results)->ntuples = PQntuples(res);
847 (*results)->sz = PQnfields(res);
848 (*results)->random = seek;
849 (*results)->pool = pool;
852 }
853 else {
854 if (TXN_IGNORE_ERRORS(sql->trans)) {
855 PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
856 if (res) {
857 int ret = PQresultStatus(res);
858 PQclear(res);
860 sql->trans->errnum = ret;
861 return PGRES_FATAL_ERROR;
862 }
863 } else {
864 sql->trans->errnum = ret;
865 return PGRES_FATAL_ERROR;
866 }
867 }
868 if (statement->prepared) {
869 rv = PQsendQueryPrepared(sql->conn, statement->name,
870 statement->nargs, values, len, fmt, 0);
871 }
872 else {
873 rv = PQsendQueryParams(sql->conn, statement->name,
874 statement->nargs, 0, values, len, fmt, 0);
875 }
876 if (rv == 0) {
877 if (TXN_IGNORE_ERRORS(sql->trans)) {
878 PGresult *res = PQexec(sql->conn,
879 "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
880 if (res) {
881 int ret = PQresultStatus(res);
882 PQclear(res);
884 sql->trans->errnum = ret;
885 return PGRES_FATAL_ERROR;
886 }
887 } else {
888 sql->trans->errnum = ret;
889 return PGRES_FATAL_ERROR;
890 }
891 } else if (TXN_NOTICE_ERRORS(sql->trans)){
892 sql->trans->errnum = 1;
893 }
894 return 1;
895 } else {
896 if (TXN_IGNORE_ERRORS(sql->trans)) {
897 PGresult *res = PQexec(sql->conn,
898 "RELEASE SAVEPOINT APR_DBD_TXN_SP");
899 if (res) {
900 int ret = PQresultStatus(res);
901 PQclear(res);
903 sql->trans->errnum = ret;
904 return PGRES_FATAL_ERROR;
905 }
906 } else {
907 sql->trans->errnum = ret;
908 return PGRES_FATAL_ERROR;
909 }
910 }
911 }
912 if (!*results) {
913 *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
914 }
915 (*results)->random = seek;
916 (*results)->handle = sql->conn;
917 (*results)->pool = pool;
918 }
919
920 return ret;
921}
922
924 apr_dbd_results_t **results,
926 int seek, const char **values)
927{
928 int *len, *fmt;
929 const char **val;
930
931 if (sql->trans && sql->trans->errnum) {
932 return sql->trans->errnum;
933 }
934
935 val = apr_palloc(pool, sizeof(*val) * statement->nargs);
936 len = apr_pcalloc(pool, sizeof(*len) * statement->nargs);
937 fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs);
938
940
942 seek, val, len, fmt);
943}
944
946 apr_dbd_results_t **results,
948 int seek, va_list args)
949{
950 const char **values;
951 int i;
952
953 if (sql->trans && sql->trans->errnum) {
954 return sql->trans->errnum;
955 }
956
957 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
958
959 for (i = 0; i < statement->nvals; i++) {
960 values[i] = va_arg(args, const char*);
961 }
962
963 return dbd_pgsql_pselect(pool, sql, results, statement, seek, values);
964}
965
967 const void **values,
968 const char **val, int *len, int *fmt)
969{
970 int i, j;
972
973 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
974 type = (values[j] == NULL ? APR_DBD_TYPE_NULL : statement->types[i]);
975
976 switch (type) {
978 val[i] = apr_itoa(pool, *(char*)values[j]);
979 break;
981 val[i] = apr_itoa(pool, *(unsigned char*)values[j]);
982 break;
984 val[i] = apr_itoa(pool, *(short*)values[j]);
985 break;
987 val[i] = apr_itoa(pool, *(unsigned short*)values[j]);
988 break;
989 case APR_DBD_TYPE_INT:
990 val[i] = apr_itoa(pool, *(int*)values[j]);
991 break;
993 val[i] = apr_itoa(pool, *(unsigned int*)values[j]);
994 break;
996 val[i] = apr_ltoa(pool, *(long*)values[j]);
997 break;
999 val[i] = apr_ltoa(pool, *(unsigned long*)values[j]);
1000 break;
1003 *(apr_int64_t*)values[j]);
1004 break;
1007 *(apr_uint64_t*)values[j]);
1008 break;
1009 case APR_DBD_TYPE_FLOAT:
1010 val[i] = apr_psprintf(pool, "%f", *(float*)values[j]);
1011 break;
1013 val[i] = apr_psprintf(pool, "%lf", *(double*)values[j]);
1014 break;
1016 case APR_DBD_TYPE_TEXT:
1017 case APR_DBD_TYPE_TIME:
1018 case APR_DBD_TYPE_DATE:
1022 val[i] = values[j];
1023 break;
1024 case APR_DBD_TYPE_BLOB:
1025 case APR_DBD_TYPE_CLOB:
1026 val[i] = (char*)values[j];
1027 len[i] = *(apr_size_t*)values[++j];
1028 fmt[i] = 1;
1029
1030 /* skip table and column */
1031 j += 2;
1032 break;
1033 case APR_DBD_TYPE_NULL:
1034 default:
1035 val[i] = NULL;
1036 break;
1037 }
1038 }
1039
1040 return;
1041}
1042
1045 const void **values)
1046{
1047 int *len, *fmt;
1048 const char **val;
1049
1050 if (sql->trans && sql->trans->errnum) {
1051 return sql->trans->errnum;
1052 }
1053
1054 val = apr_palloc(pool, sizeof(*val) * statement->nargs);
1055 len = apr_pcalloc(pool, sizeof(*len) * statement->nargs);
1056 fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs);
1057
1059
1061 val, len, fmt);
1062}
1063
1066 va_list args)
1067{
1068 const void **values;
1069 int i;
1070
1071 if (sql->trans && sql->trans->errnum) {
1072 return sql->trans->errnum;
1073 }
1074
1075 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1076
1077 for (i = 0; i < statement->nvals; i++) {
1078 values[i] = va_arg(args, const void*);
1079 }
1080
1082}
1083
1085 apr_dbd_results_t ** results,
1087 int seek, const void **values)
1088{
1089 int *len, *fmt;
1090 const char **val;
1091
1092 if (sql->trans && sql->trans->errnum) {
1093 return sql->trans->errnum;
1094 }
1095
1096 val = apr_palloc(pool, sizeof(*val) * statement->nargs);
1097 len = apr_pcalloc(pool, sizeof(*len) * statement->nargs);
1098 fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs);
1099
1101
1102 return dbd_pgsql_pselect_internal(pool, sql, results, statement,
1103 seek, val, len, fmt);
1104}
1105
1107 apr_dbd_results_t ** results,
1109 va_list args)
1110{
1111 const void **values;
1112 int i;
1113
1114 if (sql->trans && sql->trans->errnum) {
1115 return sql->trans->errnum;
1116 }
1117
1118 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1119
1120 for (i = 0; i < statement->nvals; i++) {
1121 values[i] = va_arg(args, const void*);
1122 }
1123
1124 return dbd_pgsql_pbselect(pool, sql, results, statement, seek, values);
1125}
1126
1129{
1130 int ret = 0;
1131 PGresult *res;
1132
1133 /* XXX handle recursive transactions here */
1134
1135 res = PQexec(handle->conn, "BEGIN TRANSACTION");
1136 if (res) {
1139 ret = 0;
1140 if (!*trans) {
1142 }
1143 }
1144 PQclear(res);
1145 (*trans)->handle = handle;
1146 handle->trans = *trans;
1147 }
1148 else {
1150 }
1151 return ret;
1152}
1153
1155{
1156 PGresult *res;
1157 int ret = -1; /* no transaction is an error cond */
1158 if (trans) {
1159 /* rollback on error or explicit rollback request */
1160 if (trans->errnum || TXN_DO_ROLLBACK(trans)) {
1161 trans->errnum = 0;
1162 res = PQexec(trans->handle->conn, "ROLLBACK");
1163 }
1164 else {
1165 res = PQexec(trans->handle->conn, "COMMIT");
1166 }
1167 if (res) {
1170 ret = 0;
1171 }
1172 PQclear(res);
1173 }
1174 else {
1176 }
1177 trans->handle->trans = NULL;
1178 }
1179 return ret;
1180}
1181
1183{
1184 if (!trans)
1186
1187 return trans->mode;
1188}
1189
1191 int mode)
1192{
1193 if (!trans)
1195
1196 return trans->mode = (mode & TXN_MODE_BITS);
1197}
1198
1199static void null_notice_receiver(void *arg, const PGresult *res)
1200{
1201 /* nothing */
1202}
1203
1204static void null_notice_processor(void *arg, const char *message)
1205{
1206 /* nothing */
1207}
1208
1209static apr_dbd_t *dbd_pgsql_open(apr_pool_t *pool, const char *params,
1210 const char **error)
1211{
1212 apr_dbd_t *sql;
1213
1214 PGconn *conn = PQconnectdb(params);
1215
1216 /* if there's an error in the connect string or something we get
1217 * back a * bogus connection object, and things like PQreset are
1218 * liable to segfault, so just close it out now. it would be nice
1219 * if we could give an indication of why we failed to connect... */
1220 if (PQstatus(conn) != CONNECTION_OK) {
1221 if (error) {
1223 }
1224 PQfinish(conn);
1225 return NULL;
1226 }
1227
1230
1231 sql = apr_pcalloc (pool, sizeof (*sql));
1232
1233 sql->conn = conn;
1234
1235 return sql;
1236}
1237
1239{
1240 PQfinish(handle->conn);
1241 return APR_SUCCESS;
1242}
1243
1246{
1247 if (PQstatus(handle->conn) != CONNECTION_OK) {
1248 PQreset(handle->conn);
1249 if (PQstatus(handle->conn) != CONNECTION_OK) {
1250 return APR_EGENERAL;
1251 }
1252 }
1253 return APR_SUCCESS;
1254}
1255
1257 const char *name)
1258{
1259 return APR_ENOTIMPL;
1260}
1261
1262static void *dbd_pgsql_native(apr_dbd_t *handle)
1263{
1264 return handle->conn;
1265}
1266
1268{
1269 return res->sz;
1270}
1271
1273{
1274 if (res->random) {
1275 return res->ntuples;
1276 }
1277 else {
1278 return -1;
1279 }
1280}
1281
1283 "pgsql",
1284 NULL,
1308 "$%d",
1314};
1315#endif
int n
Definition ap_regex.h:278
const char apr_size_t len
Definition ap_regex.h:187
APR-UTIL Buckets/Bucket Brigades.
#define TXN_NOTICE_ERRORS(t)
#define TXN_IGNORE_ERRORS(t)
#define TXN_MODE_BITS
#define TXN_DO_ROLLBACK(t)
APR Strings library.
APR Time Library.
void const char * arg
Definition http_vhost.h:63
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_ENOENT
Definition apr_errno.h:662
#define APR_BRIGADE_INSERT_TAIL(b, e)
apr_bucket * e
int apr_off_t * length
apr_pool_t apr_dbd_t const char * query
Definition apr_dbd.h:396
apr_dbd_type_e
Definition apr_dbd.h:55
apr_pool_t const char apr_dbd_t const char ** error
Definition apr_dbd.h:143
struct apr_dbd_prepared_t apr_dbd_prepared_t
Definition apr_dbd.h:87
apr_pool_t apr_dbd_t const char const char * label
Definition apr_dbd.h:397
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
struct apr_dbd_t apr_dbd_t
Definition apr_dbd.h:83
apr_dbd_t int const char * statement
Definition apr_dbd.h:272
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
struct apr_dbd_results_t apr_dbd_results_t
Definition apr_dbd.h:85
apr_pool_t const char apr_dbd_t ** handle
Definition apr_dbd.h:142
apr_dbd_t int errnum
Definition apr_dbd.h:353
apr_pool_t apr_dbd_results_t apr_dbd_row_t int rownum
Definition apr_dbd.h:321
apr_pool_t apr_dbd_t int apr_dbd_prepared_t int nargs
Definition apr_dbd.h:414
struct apr_dbd_transaction_t apr_dbd_transaction_t
Definition apr_dbd.h:84
apr_pool_t apr_dbd_results_t apr_dbd_row_t ** row
Definition apr_dbd.h:320
apr_pool_t const char * params
Definition apr_dbd.h:141
apr_dbd_t int * nrows
Definition apr_dbd.h:272
struct apr_dbd_row_t apr_dbd_row_t
Definition apr_dbd.h:86
#define APR_DBD_TRANSACTION_COMMIT
Definition apr_dbd.h:239
@ APR_DBD_TYPE_SHORT
Definition apr_dbd.h:59
@ APR_DBD_TYPE_FLOAT
Definition apr_dbd.h:67
@ APR_DBD_TYPE_TIME
Definition apr_dbd.h:71
@ APR_DBD_TYPE_ULONG
Definition apr_dbd.h:64
@ APR_DBD_TYPE_STRING
Definition apr_dbd.h:69
@ APR_DBD_TYPE_INT
Definition apr_dbd.h:61
@ APR_DBD_TYPE_UINT
Definition apr_dbd.h:62
@ APR_DBD_TYPE_TIMESTAMP
Definition apr_dbd.h:74
@ APR_DBD_TYPE_BLOB
Definition apr_dbd.h:76
@ APR_DBD_TYPE_NULL
Definition apr_dbd.h:78
@ APR_DBD_TYPE_DATETIME
Definition apr_dbd.h:73
@ APR_DBD_TYPE_DOUBLE
Definition apr_dbd.h:68
@ APR_DBD_TYPE_LONGLONG
Definition apr_dbd.h:65
@ APR_DBD_TYPE_UTINY
Definition apr_dbd.h:58
@ APR_DBD_TYPE_DATE
Definition apr_dbd.h:72
@ APR_DBD_TYPE_TINY
Definition apr_dbd.h:57
@ APR_DBD_TYPE_ULONGLONG
Definition apr_dbd.h:66
@ APR_DBD_TYPE_LONG
Definition apr_dbd.h:63
@ APR_DBD_TYPE_CLOB
Definition apr_dbd.h:77
@ APR_DBD_TYPE_TEXT
Definition apr_dbd.h:70
@ APR_DBD_TYPE_ZTIMESTAMP
Definition apr_dbd.h:75
@ APR_DBD_TYPE_USHORT
Definition apr_dbd.h:60
const char apr_hash_t ** values
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void * data
int type
apr_vformatter_buff_t const char * fmt
Definition apr_lib.h:175
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
void * random
Definition apr_random.h:99
const char const char *const * args
static const char *const types[]
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
static const char *const trans[040]
Definition sed1.c:28
char * name