Add to git.
[pthrlib.git] / src / pthr_dbi.c
1 /* Database interface library.
2  * - by Richard W.M. Jones <rich@annexia.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * $Id: pthr_dbi.c,v 1.18 2003/06/17 18:10:30 rich Exp $
19  */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <ctype.h>
27
28 #ifdef HAVE_ASSERT_H
29 #include <assert.h>
30 #endif
31
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #endif
35
36 #ifdef HAVE_POSTGRESQL_LIBPQ_FE_H
37 #include <postgresql/libpq-fe.h>
38 #endif
39
40 #ifdef HAVE_LIBPQ_FE_H
41 #include <libpq-fe.h>
42 #endif
43
44 #ifndef HAVE_PQESCAPESTRING
45 size_t PQescapeString(char *to, const char *from, size_t length);
46 #endif
47
48 #include <pool.h>
49 #include <hash.h>
50 #include <vector.h>
51 #include <pstring.h>
52 #include <pre.h>
53
54 #include "pthr_pseudothread.h"
55 #include "pthr_dbi.h"
56
57 #define DBI_FORCE_DEBUG 0
58 #define DBI_POOLS_DEBUG 0
59
60 #define DEBUG(dbh,sth,fs,args...) do { if (DBI_FORCE_DEBUG || ((dbh)->flags & DBI_DEBUG)) { if ((sth) == 0) fprintf (stderr, "dbi: dbh %p: " fs, (dbh) , ## args); else fprintf (stderr, "dbi: dbh %p sth %p: " fs, (dbh), (void *) (sth) , ## args); fputc ('\n', stderr); } } while (0)
61
62 /* Database handle. */
63 struct db_handle
64 {
65   pool pool;                    /* Pool for allocations. */
66   const char *conninfo;         /* Connection string. */
67   int flags;                    /* Flags. */
68   int in_transaction;           /* Are we in a transaction yet? */
69   PGconn *conn;                 /* The database connection object. */
70 };
71
72 /* Statement handle. */
73 struct st_handle
74 {
75   pool pool;                    /* Subpool used for allocations. */
76   db_handle dbh;                /* Parent database connection. */
77   const char *orig_query;       /* Original query string. */
78   vector query;                 /* Query, split into string, '?' and '@'. */
79   vector intypes;               /* Placeholder types (vector of int). */
80   PGresult *result;             /* Last result. */
81   int fetch_allowed;            /* True if there are tuples to fetch. */
82   int next_tuple;               /* Next row to fetch. */
83   vector outtypes;              /* Output types (vector of struct otype). */
84 };
85
86 struct otype
87 {
88   int type;                     /* Type of this element. */
89   void *varptr;                 /* Pointer to variable for result. */
90 };
91
92 static void init_dbi (void) __attribute__((constructor));
93 static void free_dbi (void) __attribute__((destructor));
94 static void disconnect (void *vdbh);
95 static void parse_timestamp (st_handle sth, const char *str, struct dbi_timestamp *ts);
96 static void parse_interval (st_handle sth, const char *str, struct dbi_interval *inv);
97
98 /* Global variables. */
99 static pool dbi_pool;
100 static const pcre *re_qs, *re_timestamp, *re_interval;
101
102 /* For connection pools. */
103 static shash connpools;         /* Hash conninfo string -> vector of dbh. */
104 static hash inuse;              /* Hash dbh -> subpool, of handles in use. */
105
106 /* Initialise the library. */
107 static void
108 init_dbi ()
109 {
110 #ifndef __OpenBSD__
111   dbi_pool = new_subpool (global_pool);
112 #else
113   dbi_pool = new_pool ();
114 #endif
115   re_qs = precomp (dbi_pool, "\\?|@", 0);
116   re_timestamp = precomp (dbi_pool,
117 " (?:(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d))     # date (YYYY-MM-DD)\n"
118 " \\s*                                     # space between date and time\n"
119 " (?:(\\d\\d):(\\d\\d)                     # HH:MM\n"
120 "    (?::(\\d\\d))?                        # optional :SS\n"
121 "    (?:\\.(\\d+))?                        # optional .microseconds\n"
122 "    (?:([+-])(\\d\\d))?                   # optional +/-OO offset from UTC\n"
123 " )?", PCRE_EXTENDED);
124   re_interval = precomp (dbi_pool,
125 " (?:(\\d+)\\syears?)?                     # years\n"
126 " \\s*                                     # \n"
127 " (?:(\\d+)\\smons?)?                      # months\n"
128 " \\s*                                     # \n"
129 " (?:(\\d+)\\sdays?)?                      # days\n"
130 " \\s*                                     # \n"
131 " (?:(\\d\\d):(\\d\\d)                     # HH:MM\n"
132 "    (?::(\\d\\d))?                        # optional :SS\n"
133 " )?", PCRE_EXTENDED);
134
135   /* Set up connection pools. */
136   connpools = new_shash (dbi_pool, vector);
137   inuse = new_hash (dbi_pool, db_handle, pool);
138 }
139
140 /* Free up global memory used by the library. */
141 static void
142 free_dbi ()
143 {
144   delete_pool (dbi_pool);
145 }
146
147 db_handle
148 new_db_handle (pool pool, const char *conninfo, int flags)
149 {
150   db_handle dbh = pmalloc (pool, sizeof *dbh);
151   int status, fd;
152
153   dbh->pool = pool;
154   dbh->conninfo = pstrdup (pool, conninfo);
155   dbh->flags = flags;
156   dbh->in_transaction = 0;
157
158   /* Begin the database connection. */
159   dbh->conn = PQconnectStart (conninfo);
160   if (dbh->conn == 0)           /* Failed. */
161     return 0;
162
163   /* See the PostgreSQL documentation for the libpq connect functions
164    * for details about how the following loop works.
165    */
166   status = PQstatus (dbh->conn);
167   if (status == CONNECTION_BAD)
168     {
169       PQfinish (dbh->conn);
170       return 0;                 /* Connection failed immediately. */
171     }
172
173   if (PQsetnonblocking (dbh->conn, 1) == -1) abort ();
174   fd = PQsocket (dbh->conn);
175
176   status = PGRES_POLLING_WRITING;
177
178   while (status != PGRES_POLLING_OK &&
179          status != PGRES_POLLING_FAILED)
180     {
181       switch (status)
182         {
183         case PGRES_POLLING_WRITING:
184           pth_wait_writable (fd);
185           break;
186         case PGRES_POLLING_READING:
187           pth_wait_readable (fd);
188           break;
189         }
190       status = PQconnectPoll (dbh->conn);
191     }
192
193   if (status == PGRES_POLLING_FAILED)
194     {
195       PQfinish (dbh->conn);
196       return 0;                 /* Connection failed. */
197     }
198
199   /*- Connected! -*/
200
201   DEBUG (dbh, 0, "connected");
202
203   /* Remember to clean up this connection when the pool gets deleted. */
204   pool_register_cleanup_fn (dbh->pool, disconnect, dbh);
205
206   return dbh;
207 }
208
209 static void
210 disconnect (void *vdbh)
211 {
212   db_handle dbh = (db_handle) vdbh;
213
214   PQfinish (dbh->conn);
215
216   DEBUG (dbh, 0, "disconnected");
217 }
218
219 void
220 db_set_debug (db_handle dbh, int d)
221 {
222   if (d)
223     {
224       dbh->flags |= DBI_DEBUG;
225       DEBUG (dbh, 0, "debugging enabled");
226     }
227   else
228     {
229       DEBUG (dbh, 0, "debugging disabled");
230       dbh->flags &= ~DBI_DEBUG;
231     }
232 }
233
234 int
235 db_get_debug (db_handle dbh)
236 {
237   return dbh->flags & DBI_DEBUG;
238 }
239
240 void
241 db_commit (db_handle dbh)
242 {
243   st_handle sth;
244
245   sth = st_prepare_cached (dbh, "commit work");
246   st_execute (sth);
247
248   dbh->in_transaction = 0;
249 }
250
251 void
252 db_rollback (db_handle dbh)
253 {
254   st_handle sth;
255
256   sth = st_prepare_cached (dbh, "rollback work");
257   st_execute (sth);
258
259   dbh->in_transaction = 0;
260 }
261
262 int
263 db_in_transaction (db_handle dbh)
264 {
265   return dbh->in_transaction;
266 }
267
268 static void return_dbh (void *vdbh);
269
270 db_handle
271 get_db_handle (const char *conninfo, int flags)
272 {
273   pool pool;
274   vector free_dbhs;
275   db_handle dbh = 0;
276
277   /* Allocate a subpool of the current thread's pool. If the thread dies
278    * or if the thread calls put_db_handle, this subpool will be deleted,
279    * resulting in the return_dbh function being called.
280    */
281   pool = new_subpool (pth_get_pool (current_pth));
282
283   /* Get a free handle. */
284   if (shash_get (connpools, conninfo, free_dbhs) &&
285       vector_size (free_dbhs) > 0)
286     {
287       /* Push back, pop front to ensure handles are circulated and used
288        * equally.
289        */
290       vector_pop_front (free_dbhs, dbh);
291       dbh->flags = flags;
292
293       assert (strcmp (dbh->conninfo, conninfo) == 0);
294     }
295
296   if (!dbh) /* Need to create a new handle. */
297     dbh = new_db_handle (dbi_pool, conninfo, flags);
298
299   /* Remember to return this handle when the subpool is deleted. */
300   pool_register_cleanup_fn (pool, return_dbh, dbh);
301
302   /* Remember this handle is in use. */
303   hash_insert (inuse, dbh, pool);
304
305 #if DBI_POOLS_DEBUG
306   fprintf (stderr, "get_db_handle: conninfo \"%s\" -> dbh %p\n",
307            conninfo, dbh);
308 #endif
309
310   return dbh;
311 }
312
313 void
314 put_db_handle (db_handle dbh)
315 {
316   pool pool;
317
318 #if DBI_POOLS_DEBUG
319   fprintf (stderr, "put_db_handle: dbh %p (conninfo \"%s\")\n",
320            dbh, dbh->conninfo);
321 #endif
322
323   /* Find the corresponding subpool and delete it. */
324   if (!hash_get (inuse, dbh, pool)) abort ();
325   delete_pool (pool);
326 }
327
328 /* This function is called when the thread exits or calls put_db_handle. We
329  * need to return this handle to the correct connection pool.
330  */
331 static void
332 return_dbh (void *vdbh)
333 {
334   db_handle dbh = (db_handle) vdbh;
335   vector free_dbhs;
336
337 #if DBI_POOLS_DEBUG
338   fprintf (stderr, "return_dbh: dbh %p (conninfo \"%s\")\n",
339            dbh, dbh->conninfo);
340 #endif
341
342   if (dbh->in_transaction) db_rollback (dbh);
343
344   /* Remove from the in-use list. */
345   if (!hash_erase (inuse, dbh)) abort ();
346
347   if (shash_get (connpools, dbh->conninfo, free_dbhs))
348     vector_push_back (free_dbhs, dbh);
349   else
350     {
351       /* Need to create the free dbhs vector. */
352       free_dbhs = new_vector (dbi_pool, db_handle);
353       vector_push_back (free_dbhs, dbh);
354       shash_insert (connpools, dbh->conninfo, free_dbhs);
355     }
356 }
357
358 int
359 st_serial (st_handle sth, const char *seq_name)
360 {
361   db_handle dbh = sth->dbh;
362   st_handle sth2;
363   int serial;
364
365   /* In PostgreSQL, to fetch the serial number we need to issue another
366    * command to the database.
367    */
368   sth2 = st_prepare_cached (dbh, "select currval (?)", DBI_STRING);
369   st_execute (sth2, seq_name);
370
371   st_bind (sth2, 0, serial, DBI_INT);
372
373   if (!st_fetch (sth2))
374     {
375       if ((dbh->flags & DBI_THROW_ERRORS))
376         pth_die ("dbi: st_serial: failed to fetch sequence value");
377       else
378         return -1;
379     }
380
381   return serial;
382 }
383
384 static void finish_handle (void *vsth);
385
386 st_handle
387 new_st_handle (db_handle dbh, const char *query, int flags, ...)
388 {
389   st_handle sth;
390   pool pool;
391   int i;
392   va_list args;
393
394   /* XXX Ignore the caching flag at the moment. Statement handles cannot
395    * be trivially cached, because the same handle might then be used
396    * concurrently in two different threads, which would cause serious
397    * problems. Also since PostgreSQL doesn't support PREPARE yet, we
398    * don't get the particular performance boost by caching query plans
399    * on the server side anyway.
400    *
401    * Actually the first statement isn't strictly true. We should never
402    * be sharing database handles across threads, so as long as we only
403    * cache statements in the database handle, we ought to be OK.
404    *
405    * (And the second statement isn't true anymore either - since 7.3,
406    * PostgreSQL supports PREPAREd statements).
407    */
408
409   /* Allocating in a subpool isn't strictly necessary at the moment. However
410    * in the future it will allow us to safely free up the memory associated
411    * with the statement handle when the handle is 'finished'.
412    */
413   pool = new_subpool (dbh->pool);
414   sth = pmalloc (pool, sizeof *sth);
415
416   sth->pool = pool;
417   sth->dbh = dbh;
418   sth->orig_query = query;
419   sth->result = 0;
420   sth->fetch_allowed = 0;
421   sth->outtypes = 0;
422
423   /* Examine the query string looking for ? and @ placeholders which
424    * don't occur inside strings.
425    * XXX Haven't implemented the test for placeholders inside strings
426    * yet, so avoid using ? and @ as anything but placeholders for the
427    * moment XXX
428    */
429   sth->query = pstrresplit2 (pool, query, re_qs);
430
431   /* Set up the array of input types. */
432   sth->intypes = new_vector (pool, int);
433   va_start (args, flags);
434
435   for (i = 0; i < vector_size (sth->query); ++i)
436     {
437       char *q;
438
439       vector_get (sth->query, i, q);
440
441       if (strcmp (q, "?") == 0 || strcmp (q, "@") == 0)
442         {
443           int type = va_arg (args, int);
444
445           assert (DBI_MIN_TYPE <= type && type <= DBI_MAX_TYPE);
446           vector_push_back (sth->intypes, type);
447         }
448     }
449
450   va_end (args);
451
452   /* Remember to clean up this handle when the pool gets deleted. */
453   pool_register_cleanup_fn (pool, finish_handle, sth);
454
455   DEBUG (dbh, sth, "handle created for query: %s", sth->orig_query);
456
457   return sth;
458 }
459
460 static void
461 finish_handle (void *vsth)
462 {
463   st_handle sth = (st_handle) vsth;
464
465   if (sth->result)
466     PQclear (sth->result);
467   sth->result = 0;
468
469   DEBUG (sth->dbh, sth, "finished (implicit)");
470 }
471
472 static int exec_error (st_handle sth, PGresult *result);
473 static char *escape_string (pool, const char *);
474
475 int
476 st_execute (st_handle sth, ...)
477 {
478   pool pool = sth->pool;
479   int i, typeidx;
480   va_list args;
481   char *query;
482   PGconn *conn;
483   PGresult *result;
484   int fd;
485   ExecStatusType status;
486
487   /* Formulate a query with the types substituted as appropriate. */
488   query = pstrdup (pool, "");
489   va_start (args, sth);
490
491   for (i = 0, typeidx = 0; i < vector_size (sth->query); ++i)
492     {
493       char *q;
494       int type;
495
496       vector_get (sth->query, i, q);
497
498       if (strcmp (q, "?") == 0) /* Simple placeholder. */
499         {
500           vector_get (sth->intypes, typeidx, type); typeidx++;
501
502           switch (type)
503             {
504             case DBI_INT:
505               query = pstrcat (pool, query, pitoa (pool, va_arg (args, int)));
506               break;
507
508             case DBI_INT_OR_NULL:
509               {
510                 int r = va_arg (args, int);
511
512                 if (r != 0)
513                   query = pstrcat (pool, query, pitoa (pool, r));
514                 else
515                   query = pstrcat (pool, query, "null");
516               }
517               break;
518
519             case DBI_STRING:
520               {
521                 const char *str = va_arg (args, const char *);
522
523                 if (str)
524                   {
525                     query = pstrcat (pool, query, "'");
526                     query = pstrcat (pool, query, escape_string (pool, str));
527                     query = pstrcat (pool, query, "'");
528                   }
529                 else
530                   query = pstrcat (pool, query, "null");
531               }
532               break;
533
534             case DBI_BOOL:
535               query =
536                 pstrcat (pool, query, va_arg (args, int) ? "'t'" : "'f'");
537               break;
538
539             case DBI_CHAR:
540               {
541                 char str[2] = { va_arg (args, int), '\0' }; /* sic */
542
543                 query = pstrcat (pool, query, "'");
544                 query = pstrcat (pool, query, escape_string (pool, str));
545                 query = pstrcat (pool, query, "'");
546               }
547               break;
548
549             case DBI_TIMESTAMP:
550             case DBI_INTERVAL:
551               abort ();         /* Not implemented yet! */
552
553             default:
554               abort ();
555             }
556         }
557       else if (strcmp (q, "@") == 0) /* List placeholder. */
558         {
559           vector v;
560
561           vector_get (sth->intypes, typeidx, type); typeidx++;
562
563           /* We don't know yet if v is a vector of int or char *. */
564           v = va_arg (args, vector);
565
566           /* But we _do_ know that if the vector is empty, PG will fail.
567            * Stupid bug in PostgreSQL.
568            */
569           assert (vector_size (v) > 0);
570
571           switch (type)
572             {
573             case DBI_INT:
574               v = pvitostr (pool, v);
575               query = pstrcat (pool, query, pjoin (pool, v, ","));
576               break;
577
578             case DBI_STRING:
579               /* XXX Does not handle nulls correctly. */
580               query = pstrcat (pool, query, "'");
581               query = pstrcat (pool, query,
582                                pjoin (pool,
583                                       pmap (pool, v, escape_string), "','"));
584               query = pstrcat (pool, query, "'");
585               break;
586
587             case DBI_BOOL:
588             case DBI_CHAR:
589             case DBI_INT_OR_NULL:
590             case DBI_TIMESTAMP:
591             case DBI_INTERVAL:
592               abort ();         /* Not implemented yet! */
593
594             default:
595               abort ();
596             }
597         }
598       else                      /* String. */
599         query = pstrcat (pool, query, q);
600     }
601
602   va_end (args);
603
604   /* In transaction? If not, we need to issue a BEGIN WORK command. */
605   if (!sth->dbh->in_transaction)
606     {
607       st_handle sth_bw;
608
609       /* So we don't go into infinite recursion here ... */
610       sth->dbh->in_transaction = 1;
611
612       sth_bw = st_prepare_cached (sth->dbh, "begin work");
613       if (st_execute (sth_bw) == -1)
614         {
615           sth->dbh->in_transaction = 0;
616           return exec_error (sth, 0);
617         }
618     }
619
620   DEBUG (sth->dbh, sth, "execute: %s", query);
621
622   /* Get the connection. */
623   conn = sth->dbh->conn;
624   assert (PQisnonblocking (conn));
625   fd = PQsocket (conn);
626
627   /* Run it. */
628   if (PQsendQuery (conn, query) != 1)
629     return exec_error (sth, 0);
630
631   /* Get all the command results. Ignore all but the last one. */
632   do
633     {
634       /* Wait for the result. */
635       while (PQisBusy (conn))
636         {
637           /* Blocks ..? */
638           if (PQflush (conn) == EOF)
639             return exec_error (sth, 0);
640
641           pth_wait_readable (fd);
642
643           if (PQconsumeInput (conn) != 1)
644             return exec_error (sth, 0);
645         }
646
647       result = PQgetResult (conn);
648       if (result)
649         {
650           if (sth->result) PQclear (sth->result);
651           sth->result = result;
652         }
653     }
654   while (result);
655
656   /* Get the result status. */
657   status = PQresultStatus (sth->result);
658
659   if (status == PGRES_COMMAND_OK) /* INSERT, UPDATE, DELETE, etc. */
660     {
661       char *s = PQcmdTuples (sth->result);
662       int rv;
663
664       sth->fetch_allowed = 0;
665
666       if (s && strlen (s) > 0 && sscanf (s, "%d", &rv) == 1)
667         return rv;              /* Return rows affected. */
668       else
669         return 0;               /* Command OK, unknown # rows affected. */
670     }
671   else if (status == PGRES_TUPLES_OK)
672     {
673       sth->fetch_allowed = 1;
674       sth->next_tuple = 0;
675
676       /* SELECT OK, return number of rows in the result. */
677       return PQntuples (sth->result);
678     }
679   else
680     /* Some other error. */
681     return exec_error (sth, sth->result);
682 }
683
684 static char *
685 escape_string (pool pool, const char *s)
686 {
687   int len = strlen (s);
688   char *r = pmalloc (pool, len * 2 + 1);
689
690   PQescapeString (r, s, len);
691   return r;
692 }
693
694 static int
695 exec_error (st_handle sth, PGresult *result)
696 {
697   if (!result)                  /* Some sort of connection-related error. */
698     {
699       perror ("dbi: st_execute: database connection error");
700       if ((sth->dbh->flags & DBI_THROW_ERRORS))
701         pth_die ("dbi: st_execute: database execution error");
702       else
703         return -1;
704     }
705   else                          /* Execution error. */
706     {
707       char *error = psprintf (sth->pool,
708                               "dbi: st_execute: %s",
709                               PQresultErrorMessage (result));
710
711       fprintf (stderr, "%s\n", error);
712       if ((sth->dbh->flags & DBI_THROW_ERRORS))
713         pth_die (error);
714       else
715         return -1;
716     }
717 }
718
719 void
720 _st_bind (st_handle sth, int colidx, void *varptr, int type)
721 {
722   struct otype zero = { 0, 0 };
723   struct otype ot;
724   int extend_by;
725
726   if (sth->outtypes == 0)
727     sth->outtypes = new_vector (sth->pool, struct otype);
728
729   /* Is the vector large enough? If not, extend it. */
730   extend_by = colidx - vector_size (sth->outtypes) + 1;
731   if (extend_by > 0)
732     vector_fill (sth->outtypes, zero, extend_by);
733
734   ot.type = type;
735   ot.varptr = varptr;
736   vector_replace (sth->outtypes, colidx, ot);
737 }
738
739 int
740 st_fetch (st_handle sth)
741 {
742   int nr_rows, i;
743   struct otype ot;
744
745   if (!sth->result || !sth->fetch_allowed)
746     {
747       const char *error =
748         "dbi: st_fetch: fetch without execute, or on a non-SELECT statement";
749
750       fprintf (stderr, "%s\n", error);
751       if ((sth->dbh->flags & DBI_THROW_ERRORS))
752         pth_die (error);
753       else
754         return -1;
755     }
756
757   /* Get number of rows in the result. */
758   nr_rows = PQntuples (sth->result);
759
760   if (sth->next_tuple >= nr_rows)
761     {
762       DEBUG (sth->dbh, sth, "fetch: no more rows in query");
763       return 0;                 /* Finished. */
764     }
765
766   DEBUG (sth->dbh, sth, "fetch: starting row fetch");
767
768   /* Fetch it. */
769   if (sth->outtypes)
770     for (i = 0; i < vector_size (sth->outtypes); ++i)
771       {
772         vector_get (sth->outtypes, i, ot);
773
774         if (ot.type != 0 && ot.varptr != 0)
775           {
776             int is_null = PQgetisnull (sth->result, sth->next_tuple, i);
777             char *r = !is_null ? PQgetvalue (sth->result, sth->next_tuple, i)
778                                : 0;
779
780             DEBUG (sth->dbh, sth, "fetch: col %d: %s", i, r);
781
782             switch (ot.type)
783               {
784               case DBI_STRING:
785                 * (char **) ot.varptr = r;
786                 break;
787
788               case DBI_INT:
789               case DBI_INT_OR_NULL:
790                 if (is_null)
791                   * (int *) ot.varptr = 0; /* Best we can do in C ! */
792                 else
793                   sscanf (r, "%d", (int *) ot.varptr);
794                 break;
795
796               case DBI_BOOL:
797                 if (is_null)
798                   * (int *) ot.varptr = 0; /* Best we can do! */
799                 else
800                   * (int *) ot.varptr = strcmp (r, "t") == 0;
801                 break;
802
803               case DBI_CHAR:
804                 if (is_null)
805                   * (char *) ot.varptr = 0; /* Best we can do! */
806                 else
807                   * (char *) ot.varptr = r[0];
808                 break;
809
810               case DBI_TIMESTAMP:
811                 {
812                   struct dbi_timestamp *ts =
813                     (struct dbi_timestamp *) ot.varptr;
814
815                   memset (ts, 0, sizeof *ts);
816                   if (is_null)
817                     ts->is_null = 1;
818                   else
819                     parse_timestamp (sth, r, ts);
820                 }
821                 break;
822
823               case DBI_INTERVAL:
824                 {
825                   struct dbi_interval *inv =
826                     (struct dbi_interval *) ot.varptr;
827
828                   memset (inv, 0, sizeof *inv);
829                   if (is_null)
830                     inv->is_null = 1;
831                   else
832                     parse_interval (sth, r, inv);
833                 }
834                 break;
835
836               default:
837                 abort ();
838               }
839           }
840       }
841
842   DEBUG (sth->dbh, sth, "fetch: ended row fetch");
843
844   sth->next_tuple++;
845
846   return 1;                     /* Row returned. */
847 }
848
849 static inline int
850 parse_fixed_width_int (const char *str, int width)
851 {
852   int r = 0, i;
853
854   for (i = 0; i < width; ++i)
855     {
856       r *= 10;
857       r += str[i] - '0';
858     }
859
860   return r;
861 }
862
863 /* Parse a timestamp field from a PostgreSQL database, and return it
864  * broken out into the dbi_timestamp structure. This can also parse
865  * dates and times.
866  */
867 static void
868 parse_timestamp (st_handle sth, const char *str, struct dbi_timestamp *ts)
869 {
870   vector v;
871   const char *s, *sign;
872
873   /* Parse the timestamp. */
874   v = prematch (sth->pool, str, re_timestamp, 0);
875
876   if (!v)
877     pth_die (psprintf (sth->pool,
878                        "dbi: parse_timestamp: invalid timestamp: %s",
879                        str));
880
881   if (vector_size (v) <= 1) return;
882   vector_get (v, 1, s);
883   if (s) ts->year = parse_fixed_width_int (s, 4);
884
885   if (vector_size (v) <= 2) return;
886   vector_get (v, 2, s);
887   if (s) ts->month = parse_fixed_width_int (s, 2);
888
889   if (vector_size (v) <= 3) return;
890   vector_get (v, 3, s);
891   if (s) ts->day = parse_fixed_width_int (s, 2);
892
893   if (vector_size (v) <= 4) return;
894   vector_get (v, 4, s);
895   if (s) ts->hour = parse_fixed_width_int (s, 2);
896
897   if (vector_size (v) <= 5) return;
898   vector_get (v, 5, s);
899   if (s) ts->min = parse_fixed_width_int (s, 2);
900
901   if (vector_size (v) <= 6) return;
902   vector_get (v, 6, s);
903   if (s) ts->sec = parse_fixed_width_int (s, 2);
904
905   if (vector_size (v) <= 7) return;
906   vector_get (v, 7, s);
907   if (s) sscanf (s, "%d", &ts->microsecs);
908
909   if (vector_size (v) <= 9) return;
910   vector_get (v, 8, sign);
911   vector_get (v, 9, s);
912   if (sign && s)
913     {
914       ts->utc_offset = parse_fixed_width_int (s, 2);
915       if (sign[0] == '-') ts->utc_offset = -ts->utc_offset;
916     }
917 }
918
919 /* Parse an interval field from a PostgreSQL database, and return it
920  * broken out into the dbi_interval structure.
921  */
922 static void
923 parse_interval (st_handle sth, const char *str, struct dbi_interval *inv)
924 {
925   vector v;
926   const char *s;
927
928   /* Parse the interval. */
929   v = prematch (sth->pool, str, re_interval, 0);
930
931   if (!v)
932     pth_die (psprintf (sth->pool,
933                        "dbi: parse_interval: invalid interval: %s",
934                        str));
935
936   if (vector_size (v) <= 1) return;
937   vector_get (v, 1, s);
938   if (s) sscanf (s, "%d", &inv->years);
939
940   if (vector_size (v) <= 2) return;
941   vector_get (v, 2, s);
942   if (s) sscanf (s, "%d", &inv->months);
943
944   if (vector_size (v) <= 3) return;
945   vector_get (v, 3, s);
946   if (s) sscanf (s, "%d", &inv->days);
947
948   if (vector_size (v) <= 4) return;
949   vector_get (v, 4, s);
950   if (s) inv->hours = parse_fixed_width_int (s, 2);
951
952   if (vector_size (v) <= 5) return;
953   vector_get (v, 5, s);
954   if (s) inv->mins = parse_fixed_width_int (s, 2);
955
956   if (vector_size (v) <= 6) return;
957   vector_get (v, 6, s);
958   if (s) inv->secs = parse_fixed_width_int (s, 2);
959 }
960
961 vector
962 st_fetch_all_rows (st_handle sth)
963 {
964   vector result;
965   int row, nr_rows;
966   int col, nr_cols;
967
968   if (!sth->result || !sth->fetch_allowed)
969     {
970       const char *error =
971         "dbi: st_fetch_all_rows: fetch without execute, or on a non-SELECT statement";
972
973       fprintf (stderr, "%s\n", error);
974       if ((sth->dbh->flags & DBI_THROW_ERRORS))
975         pth_die (error);
976       else
977         return 0;
978     }
979
980   DEBUG (sth->dbh, sth, "fetch_all_rows");
981
982   result = new_vector (sth->pool, vector);
983
984   /* Get number of rows, columns in the result. */
985   nr_rows = PQntuples (sth->result);
986   nr_cols = PQnfields (sth->result);
987
988   /* Fetch it. */
989   for (row = 0; row < nr_rows; ++row)
990     {
991       vector v = new_vector (sth->pool, char *);
992
993       for (col = 0; col < nr_cols; ++col)
994         {
995           char *s = PQgetisnull (sth->result, row, col)
996             ? 0 : PQgetvalue (sth->result, row, col);
997
998           vector_push_back (v, s);
999         }
1000
1001       vector_push_back (result, v);
1002     }
1003
1004   return result;
1005 }
1006
1007 void
1008 st_finish (st_handle sth)
1009 {
1010   if (sth->result)
1011     PQclear (sth->result);
1012   sth->result = 0;
1013
1014   DEBUG (sth->dbh, sth, "finished (explicit)");
1015 }
1016
1017 #ifndef HAVE_PQESCAPESTRING
1018 /* This is taken from the PostgreSQL source code. */
1019
1020 /* ---------------
1021  * Escaping arbitrary strings to get valid SQL strings/identifiers.
1022  *
1023  * Replaces "\\" with "\\\\" and "'" with "''".
1024  * length is the length of the buffer pointed to by
1025  * from.  The buffer at to must be at least 2*length + 1 characters
1026  * long.  A terminating NUL character is written.
1027  * ---------------
1028  */
1029
1030 size_t
1031 PQescapeString(char *to, const char *from, size_t length)
1032 {
1033         const char *source = from;
1034         char       *target = to;
1035         unsigned int remaining = length;
1036
1037         while (remaining > 0)
1038         {
1039                 switch (*source)
1040                 {
1041                         case '\\':
1042                                 *target = '\\';
1043                                 target++;
1044                                 *target = '\\';
1045                                 /* target and remaining are updated below. */
1046                                 break;
1047
1048                         case '\'':
1049                                 *target = '\'';
1050                                 target++;
1051                                 *target = '\'';
1052                                 /* target and remaining are updated below. */
1053                                 break;
1054
1055                         default:
1056                                 *target = *source;
1057                                 /* target and remaining are updated below. */
1058                 }
1059                 source++;
1060                 target++;
1061                 remaining--;
1062         }
1063
1064         /* Write the terminating NUL character. */
1065         *target = '\0';
1066
1067         return target - to;
1068 }
1069 #endif
1070
1071 #if 0
1072 /*
1073  *              PQescapeBytea   - converts from binary string to the
1074  *              minimal encoding necessary to include the string in an SQL
1075  *              INSERT statement with a bytea type column as the target.
1076  *
1077  *              The following transformations are applied
1078  *              '\0' == ASCII  0 == \\000
1079  *              '\'' == ASCII 39 == \'
1080  *              '\\' == ASCII 92 == \\\\
1081  *              anything >= 0x80 ---> \\ooo (where ooo is an octal expression)
1082  */
1083 unsigned char *
1084 PQescapeBytea(unsigned char *bintext, size_t binlen, size_t *bytealen)
1085 {
1086         unsigned char *vp;
1087         unsigned char *rp;
1088         unsigned char *result;
1089         size_t          i;
1090         size_t          len;
1091
1092         /*
1093          * empty string has 1 char ('\0')
1094          */
1095         len = 1;
1096
1097         vp = bintext;
1098         for (i = binlen; i > 0; i--, vp++)
1099         {
1100                 if (*vp == 0 || *vp >= 0x80)
1101                         len += 5;                       /* '5' is for '\\ooo' */
1102                 else if (*vp == '\'')
1103                         len += 2;
1104                 else if (*vp == '\\')
1105                         len += 4;
1106                 else
1107                         len++;
1108         }
1109
1110         rp = result = (unsigned char *) malloc(len);
1111         if (rp == NULL)
1112                 return NULL;
1113
1114         vp = bintext;
1115         *bytealen = len;
1116
1117         for (i = binlen; i > 0; i--, vp++)
1118         {
1119                 if (*vp == 0 || *vp >= 0x80)
1120                 {
1121                         (void) sprintf(rp, "\\\\%03o", *vp);
1122                         rp += 5;
1123                 }
1124                 else if (*vp == '\'')
1125                 {
1126                         rp[0] = '\\';
1127                         rp[1] = '\'';
1128                         rp += 2;
1129                 }
1130                 else if (*vp == '\\')
1131                 {
1132                         rp[0] = '\\';
1133                         rp[1] = '\\';
1134                         rp[2] = '\\';
1135                         rp[3] = '\\';
1136                         rp += 4;
1137                 }
1138                 else
1139                         *rp++ = *vp;
1140         }
1141         *rp = '\0';
1142
1143         return result;
1144 }
1145 #endif