1 /* Copyright (C) 2005 MySQL AB
2    Copyright (C) 2005-2017 Alexey Kopytov <akopytov@gmail.com>
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program 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
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 
23 #ifdef HAVE_STRING_H
24 # include <string.h>
25 #endif
26 #ifdef HAVE_STRINGS_H
27 # include <strings.h>
28 #endif
29 
30 #include <libpq-fe.h>
31 
32 #include "sb_options.h"
33 #include "db_driver.h"
34 #include "sb_rand.h"
35 
36 #define xfree(ptr) ({ if (ptr) free((void *)ptr); ptr = NULL; })
37 
38 /* Maximum length of text representation of bind parameters */
39 #define MAX_PARAM_LENGTH 256UL
40 
41 /* PostgreSQL driver arguments */
42 
43 static sb_arg_t pgsql_drv_args[] =
44 {
45   SB_OPT("pgsql-host", "PostgreSQL server host", "localhost", STRING),
46   SB_OPT("pgsql-port", "PostgreSQL server port", "5432", INT),
47   SB_OPT("pgsql-user", "PostgreSQL user", "sbtest", STRING),
48   SB_OPT("pgsql-password", "PostgreSQL password", "", STRING),
49   SB_OPT("pgsql-db", "PostgreSQL database name", "sbtest", STRING),
50 
51   SB_OPT_END
52 };
53 
54 typedef struct
55 {
56   char               *host;
57   char               *port;
58   char               *user;
59   char               *password;
60   char               *db;
61 } pgsql_drv_args_t;
62 
63 /* Structure used for DB-to-PgSQL bind types map */
64 
65 typedef struct
66 {
67   db_bind_type_t   db_type;
68   int              pg_type;
69 } db_pgsql_bind_map_t;
70 
71 /* DB-to-PgSQL bind types map */
72 db_pgsql_bind_map_t db_pgsql_bind_map[] =
73 {
74   {DB_TYPE_TINYINT,   0},
75   {DB_TYPE_SMALLINT,  21},
76   {DB_TYPE_INT,       23},
77   {DB_TYPE_BIGINT,    20},
78   {DB_TYPE_FLOAT,     700},
79   {DB_TYPE_DOUBLE,    701},
80   {DB_TYPE_DATETIME,  0},
81   {DB_TYPE_TIMESTAMP, 1114},
82   {DB_TYPE_CHAR,      18},
83   {DB_TYPE_VARCHAR,   1043},
84   {DB_TYPE_NONE,      0}
85 };
86 
87 /* PgSQL driver capabilities */
88 
89 static drv_caps_t pgsql_drv_caps =
90 {
91   1,    /* multi_rows_insert */
92   1,    /* prepared_statements */
93   0,    /* auto_increment */
94   0,    /* needs_commit */
95   1,    /* serial */
96   0,    /* unsigned int */
97 };
98 
99 /* Describes the PostgreSQL prepared statement */
100 typedef struct pg_stmt
101 {
102   char     *name;
103   int      prepared;
104   int      nparams;
105   Oid      *ptypes;
106   char     **pvalues;
107 } pg_stmt_t;
108 
109 static pgsql_drv_args_t args;          /* driver args */
110 
111 static char use_ps; /* whether server-side prepared statemens should be used */
112 
113 /* PgSQL driver operations */
114 
115 static int pgsql_drv_init(void);
116 static int pgsql_drv_describe(drv_caps_t *);
117 static int pgsql_drv_connect(db_conn_t *);
118 static int pgsql_drv_disconnect(db_conn_t *);
119 static int pgsql_drv_prepare(db_stmt_t *, const char *, size_t);
120 static int pgsql_drv_bind_param(db_stmt_t *, db_bind_t *, size_t);
121 static int pgsql_drv_bind_result(db_stmt_t *, db_bind_t *, size_t);
122 static db_error_t pgsql_drv_execute(db_stmt_t *, db_result_t *);
123 static int pgsql_drv_fetch(db_result_t *);
124 static int pgsql_drv_fetch_row(db_result_t *, db_row_t *);
125 static db_error_t pgsql_drv_query(db_conn_t *, const char *, size_t,
126                                   db_result_t *);
127 static int pgsql_drv_free_results(db_result_t *);
128 static int pgsql_drv_close(db_stmt_t *);
129 static int pgsql_drv_done(void);
130 
131 /* PgSQL driver definition */
132 
133 static db_driver_t pgsql_driver =
134 {
135   .sname = "pgsql",
136   .lname = "PostgreSQL driver",
137   .args = pgsql_drv_args,
138   .ops =
139   {
140     .init = pgsql_drv_init,
141     .describe = pgsql_drv_describe,
142     .connect = pgsql_drv_connect,
143     .disconnect = pgsql_drv_disconnect,
144     .prepare = pgsql_drv_prepare,
145     .bind_param = pgsql_drv_bind_param,
146     .bind_result = pgsql_drv_bind_result,
147     .execute = pgsql_drv_execute,
148     .fetch = pgsql_drv_fetch,
149     .fetch_row = pgsql_drv_fetch_row,
150     .free_results = pgsql_drv_free_results,
151     .close = pgsql_drv_close,
152     .query = pgsql_drv_query,
153     .done = pgsql_drv_done
154   }
155 };
156 
157 
158 /* Local functions */
159 
160 static int get_pgsql_bind_type(db_bind_type_t);
161 static int get_unique_stmt_name(char *, int);
162 
163 /* Register PgSQL driver */
164 
165 
register_driver_pgsql(sb_list_t * drivers)166 int register_driver_pgsql(sb_list_t *drivers)
167 {
168   SB_LIST_ADD_TAIL(&pgsql_driver.listitem, drivers);
169 
170   return 0;
171 }
172 
173 /* PgSQL driver initialization */
174 
pgsql_drv_init(void)175 int pgsql_drv_init(void)
176 {
177   args.host = sb_get_value_string("pgsql-host");
178   args.port = sb_get_value_string("pgsql-port");
179   args.user = sb_get_value_string("pgsql-user");
180   args.password = sb_get_value_string("pgsql-password");
181   args.db = sb_get_value_string("pgsql-db");
182 
183   use_ps = 0;
184   pgsql_drv_caps.prepared_statements = 1;
185   if (db_globals.ps_mode != DB_PS_MODE_DISABLE)
186     use_ps = 1;
187 
188   return 0;
189 }
190 
191 
192 /* Describe database capabilities */
193 
194 
pgsql_drv_describe(drv_caps_t * caps)195 int pgsql_drv_describe(drv_caps_t *caps)
196 {
197   PGconn *con;
198 
199   *caps = pgsql_drv_caps;
200 
201   /* Determine the server version */
202   con = PQsetdbLogin(args.host,
203                      args.port,
204                      NULL,
205                      NULL,
206                      args.db,
207                      args.user,
208                      args.password);
209   if (PQstatus(con) != CONNECTION_OK)
210   {
211     log_text(LOG_FATAL, "Connection to database failed: %s",
212              PQerrorMessage(con));
213     PQfinish(con);
214     return 1;
215   }
216 
217   /* Support for multi-row INSERTs is not available before 8.2 */
218   if (PQserverVersion(con) < 80200)
219     caps->multi_rows_insert = 0;
220 
221   PQfinish(con);
222 
223   return 0;
224 }
225 
empty_notice_processor(void * arg,const char * msg)226 static void empty_notice_processor(void *arg, const char *msg)
227 {
228   (void) arg; /* unused */
229   (void) msg; /* unused */
230 }
231 
232 /* Connect to database */
233 
pgsql_drv_connect(db_conn_t * sb_conn)234 int pgsql_drv_connect(db_conn_t *sb_conn)
235 {
236   PGconn *con;
237 
238   con = PQsetdbLogin(args.host,
239                      args.port,
240                      NULL,
241                      NULL,
242                      args.db,
243                      args.user,
244                      args.password);
245   if (PQstatus(con) != CONNECTION_OK)
246   {
247     log_text(LOG_FATAL, "Connection to database failed: %s",
248              PQerrorMessage(con));
249     PQfinish(con);
250     return 1;
251   }
252 
253   /* Silence the default notice receiver spitting NOTICE message to stderr */
254   PQsetNoticeProcessor(con, empty_notice_processor, NULL);
255   sb_conn->ptr = con;
256 
257   return 0;
258 }
259 
260 /* Disconnect from database */
261 
pgsql_drv_disconnect(db_conn_t * sb_conn)262 int pgsql_drv_disconnect(db_conn_t *sb_conn)
263 {
264   PGconn *con = (PGconn *)sb_conn->ptr;
265 
266   /* These might be allocated in pgsql_check_status() */
267   xfree(sb_conn->sql_state);
268   xfree(sb_conn->sql_errmsg);
269 
270   if (con != NULL)
271     PQfinish(con);
272 
273   return 0;
274 }
275 
276 
277 /* Prepare statement */
278 
279 
pgsql_drv_prepare(db_stmt_t * stmt,const char * query,size_t len)280 int pgsql_drv_prepare(db_stmt_t *stmt, const char *query, size_t len)
281 {
282   PGconn       *con = (PGconn *)stmt->connection->ptr;
283   PGresult     *pgres;
284   pg_stmt_t    *pgstmt;
285   char         *buf = NULL;
286   unsigned int vcnt;
287   unsigned int need_realloc;
288   unsigned int i,j;
289   unsigned int buflen;
290   int          n;
291   char         name[32];
292 
293   (void) len; /* unused */
294 
295   if (con == NULL)
296     return 1;
297 
298   if (!use_ps)
299   {
300     /* Use client-side PS */
301     stmt->emulated = 1;
302     stmt->query = strdup(query);
303 
304     return 0;
305   }
306 
307   /* Convert query to PgSQL-style named placeholders */
308   need_realloc = 1;
309   vcnt = 1;
310   buflen = 0;
311   for (i = 0, j = 0; query[i] != '\0'; i++)
312   {
313   again:
314     if (j+1 >= buflen || need_realloc)
315     {
316       buflen = (buflen > 0) ? buflen * 2 : 256;
317       buf = realloc(buf, buflen);
318       if (buf == NULL)
319         goto error;
320       need_realloc = 0;
321     }
322 
323     if (query[i] != '?')
324     {
325       buf[j++] = query[i];
326       continue;
327     }
328 
329     n = snprintf(buf + j, buflen - j, "$%d", vcnt);
330     if (n < 0 || n >= (int)(buflen - j))
331     {
332       need_realloc = 1;
333       goto again;
334     }
335 
336     j += n;
337     vcnt++;
338   }
339   buf[j] = '\0';
340 
341   /* Store the query to be prepared later on the first bind_param call */
342   stmt->query = strdup(buf);
343   free(buf);
344 
345   pgstmt = (pg_stmt_t *)calloc(1, sizeof(pg_stmt_t));
346   if (pgstmt == NULL)
347     goto error;
348   /* Generate random statement name */
349   get_unique_stmt_name(name, sizeof(name));
350   pgstmt->name = strdup(name);
351   pgstmt->nparams = vcnt - 1;
352 
353   /*
354     Special keys for statements without parameters, since we don't need
355     to know the types of arguments, and no calls to bind_param() will be made
356   */
357   if (pgstmt->nparams == 0)
358   {
359     /* Do prepare */
360     pgres = PQprepare(con, pgstmt->name, stmt->query, pgstmt->nparams,
361                       NULL);
362 
363     if (PQresultStatus(pgres) != PGRES_COMMAND_OK)
364     {
365       log_text(LOG_FATAL, "PQprepare() failed: %s", PQerrorMessage(con));
366 
367       PQclear(pgres);
368 
369       free(stmt->query);
370       free(pgstmt->name);
371       free(pgstmt);
372 
373       return 1;
374     }
375     PQclear(pgres);
376     pgstmt->prepared = 1;
377   }
378 
379   stmt->ptr = pgstmt;
380 
381   return 0;
382 
383  error:
384 
385   return 1;
386 }
387 
388 
389 /* Bind parameters for prepared statement */
390 
391 
pgsql_drv_bind_param(db_stmt_t * stmt,db_bind_t * params,size_t len)392 int pgsql_drv_bind_param(db_stmt_t *stmt, db_bind_t *params, size_t len)
393 {
394   PGconn       *con = (PGconn *)stmt->connection->ptr;
395   PGresult     *pgres;
396   pg_stmt_t    *pgstmt;
397   unsigned int i;
398 
399   if (con == NULL)
400     return 1;
401 
402   if (stmt->bound_param != NULL)
403     free(stmt->bound_param);
404   stmt->bound_param = (db_bind_t *)malloc(len * sizeof(db_bind_t));
405   if (stmt->bound_param == NULL)
406     return 1;
407   memcpy(stmt->bound_param, params, len * sizeof(db_bind_t));
408   stmt->bound_param_len = len;
409 
410   if (stmt->emulated)
411     return 0;
412 
413   pgstmt = stmt->ptr;
414   if (pgstmt->prepared)
415     return 0;
416 
417   /* Prepare statement here, since we need to know types of parameters */
418   /* Validate parameters count */
419   if ((unsigned)pgstmt->nparams != len)
420   {
421     log_text(LOG_ALERT, "wrong number of parameters in prepared statement");
422     log_text(LOG_DEBUG, "counted: %d, passed to bind_param(): %zd",
423              pgstmt->nparams, len);
424     return 1;
425   }
426 
427   pgstmt->ptypes = (Oid *)malloc(len * sizeof(int));
428   if (pgstmt->ptypes == NULL)
429     return 1;
430 
431   /* Convert sysbench data types to PgSQL ones */
432   for (i = 0; i < len; i++)
433     pgstmt->ptypes[i] = get_pgsql_bind_type(params[i].type);
434 
435   /* Do prepare */
436   pgres = PQprepare(con, pgstmt->name, stmt->query, pgstmt->nparams,
437                     pgstmt->ptypes);
438 
439   if (PQresultStatus(pgres) != PGRES_COMMAND_OK)
440   {
441     log_text(LOG_FATAL, "PQprepare() failed: %s", PQerrorMessage(con));
442     return 1;
443   }
444 
445   PQclear(pgres);
446 
447   pgstmt->pvalues = (char **)calloc(len, sizeof(char *));
448   if (pgstmt->pvalues == NULL)
449     return 1;
450 
451   /* Allocate buffers for bind parameters */
452   for (i = 0; i < len; i++)
453   {
454     if (pgstmt->pvalues[i] != NULL)
455     {
456       free(pgstmt->pvalues[i]);
457     }
458 
459     pgstmt->pvalues[i] = (char *)malloc(MAX_PARAM_LENGTH);
460     if (pgstmt->pvalues[i] == NULL)
461       return 1;
462   }
463   pgstmt->prepared = 1;
464 
465   return 0;
466 }
467 
468 
469 /* Bind results for prepared statement */
470 
471 
pgsql_drv_bind_result(db_stmt_t * stmt,db_bind_t * params,size_t len)472 int pgsql_drv_bind_result(db_stmt_t *stmt, db_bind_t *params, size_t len)
473 {
474   /* unused */
475   (void)stmt;
476   (void)params;
477   (void)len;
478 
479   return 0;
480 }
481 
482 
483 /* Check query execution status */
484 
485 
pgsql_check_status(db_conn_t * con,PGresult * pgres,const char * funcname,const char * query,db_result_t * rs)486 static db_error_t pgsql_check_status(db_conn_t *con, PGresult *pgres,
487                                      const char *funcname, const char *query,
488                                      db_result_t *rs)
489 {
490   ExecStatusType status;
491   db_error_t     rc;
492   PGconn * const pgcon = con->ptr;
493 
494   status = PQresultStatus(pgres);
495   switch(status) {
496   case PGRES_TUPLES_OK:
497     rs->nrows = PQntuples(pgres);
498     rs->nfields = PQnfields(pgres);
499     rs->counter = SB_CNT_READ;
500 
501     rc = DB_ERROR_NONE;
502 
503     break;
504 
505   case PGRES_COMMAND_OK:
506     rs->nrows = strtoul(PQcmdTuples(pgres), NULL, 10);;
507     rs->counter = (rs->nrows > 0) ? SB_CNT_WRITE : SB_CNT_OTHER;
508     rc = DB_ERROR_NONE;
509 
510     /*
511       Since we are not returning a result set, the SQL layer will never call
512       pgsql_drv_free_results(). So we must call PQclear() here.
513     */
514     PQclear(pgres);
515 
516     break;
517 
518   case PGRES_FATAL_ERROR:
519     rs->nrows = 0;
520     rs->counter = SB_CNT_ERROR;
521 
522     /*
523       Duplicate strings here, because PostgreSQL will deallocate them on
524       PQclear() call below. They will be deallocated either on subsequent calls
525       to pgsql_check_status() or in pgsql_drv_disconnect().
526     */
527     xfree(con->sql_state);
528     xfree(con->sql_errmsg);
529 
530     con->sql_state = strdup(PQresultErrorField(pgres, PG_DIAG_SQLSTATE));
531     con->sql_errmsg = strdup(PQresultErrorField(pgres, PG_DIAG_MESSAGE_PRIMARY));
532 
533     if (!strcmp(con->sql_state, "40P01") /* deadlock_detected */ ||
534         !strcmp(con->sql_state, "23505") /* unique violation */ ||
535         !strcmp(con->sql_state, "40001"))/* serialization_failure */
536     {
537       PGresult *tmp;
538       tmp = PQexec(pgcon, "ROLLBACK");
539       PQclear(tmp);
540       rc = DB_ERROR_IGNORABLE;
541     }
542     else
543     {
544       log_text(LOG_FATAL, "%s() failed: %d %s", funcname, status,
545                con->sql_errmsg);
546 
547       if (query != NULL)
548         log_text(LOG_FATAL, "failed query was: %s", query);
549 
550       rc =  DB_ERROR_FATAL;
551     }
552 
553     PQclear(pgres);
554 
555     break;
556 
557   default:
558     rs->nrows = 0;
559     rs->counter = SB_CNT_ERROR;
560     rc = DB_ERROR_FATAL;
561   }
562 
563   return rc;
564 }
565 
566 
567 /* Execute prepared statement */
568 
569 
pgsql_drv_execute(db_stmt_t * stmt,db_result_t * rs)570 db_error_t pgsql_drv_execute(db_stmt_t *stmt, db_result_t *rs)
571 {
572   db_conn_t       *con = stmt->connection;
573   PGconn          *pgcon = (PGconn *)con->ptr;
574   PGresult        *pgres;
575   pg_stmt_t       *pgstmt;
576   char            *buf = NULL;
577   unsigned int    buflen = 0;
578   unsigned int    i, j, vcnt;
579   char            need_realloc;
580   int             n;
581   db_error_t      rc;
582   unsigned long   len;
583 
584   con->sql_errno = 0;
585   xfree(con->sql_state);
586   xfree(con->sql_errmsg);
587 
588   if (!stmt->emulated)
589   {
590     pgstmt = stmt->ptr;
591     if (pgstmt == NULL)
592     {
593       log_text(LOG_DEBUG,
594                "ERROR: exiting mysql_drv_execute(), uninitialized statement");
595       return DB_ERROR_FATAL;
596     }
597 
598     /* Convert sysbench bind structures to PgSQL data */
599     for (i = 0; i < (unsigned)pgstmt->nparams; i++)
600     {
601       if (stmt->bound_param[i].is_null && *(stmt->bound_param[i].is_null))
602         continue;
603 
604       switch (stmt->bound_param[i].type) {
605         case DB_TYPE_CHAR:
606         case DB_TYPE_VARCHAR:
607 
608           len = stmt->bound_param[i].data_len[0];
609 
610           memcpy(pgstmt->pvalues[i], stmt->bound_param[i].buffer,
611                  SB_MIN(MAX_PARAM_LENGTH, len));
612           /* PostgreSQL requires a zero-terminated string */
613           pgstmt->pvalues[i][len] = '\0';
614 
615           break;
616         default:
617           db_print_value(stmt->bound_param + i, pgstmt->pvalues[i],
618                          MAX_PARAM_LENGTH);
619       }
620     }
621 
622     pgres = PQexecPrepared(pgcon, pgstmt->name, pgstmt->nparams,
623                            (const char **)pgstmt->pvalues, NULL, NULL, 1);
624 
625     rc = pgsql_check_status(con, pgres, "PQexecPrepared", NULL, rs);
626 
627     rs->ptr = (rs->counter == SB_CNT_READ) ? (void *) pgres : NULL;
628 
629     return rc;
630   }
631 
632   /* Use emulation */
633   /* Build the actual query string from parameters list */
634   need_realloc = 1;
635   vcnt = 0;
636   for (i = 0, j = 0; stmt->query[i] != '\0'; i++)
637   {
638   again:
639     if (j+1 >= buflen || need_realloc)
640     {
641       buflen = (buflen > 0) ? buflen * 2 : 256;
642       buf = realloc(buf, buflen);
643       if (buf == NULL)
644         return DB_ERROR_FATAL;
645       need_realloc = 0;
646     }
647 
648     if (stmt->query[i] != '?')
649     {
650       buf[j++] = stmt->query[i];
651       continue;
652     }
653 
654     n = db_print_value(stmt->bound_param + vcnt, buf + j, buflen - j);
655     if (n < 0)
656     {
657       need_realloc = 1;
658       goto again;
659     }
660     j += n;
661     vcnt++;
662   }
663   buf[j] = '\0';
664 
665   rc = pgsql_drv_query(con, buf, j, rs);
666 
667   free(buf);
668 
669   return rc;
670 }
671 
672 
673 /* Execute SQL query */
674 
675 
pgsql_drv_query(db_conn_t * sb_conn,const char * query,size_t len,db_result_t * rs)676 db_error_t pgsql_drv_query(db_conn_t *sb_conn, const char *query, size_t len,
677                            db_result_t *rs)
678 {
679   PGconn         *pgcon = sb_conn->ptr;
680   PGresult       *pgres;
681   db_error_t     rc;
682 
683   (void)len; /* unused */
684 
685   sb_conn->sql_errno = 0;
686   xfree(sb_conn->sql_state);
687   xfree(sb_conn->sql_errmsg);
688 
689   pgres = PQexec(pgcon, query);
690   rc = pgsql_check_status(sb_conn, pgres, "PQexec", query, rs);
691 
692   rs->ptr = (rs->counter == SB_CNT_READ) ? (void *) pgres : NULL;
693 
694   return rc;
695 }
696 
697 
698 /* Fetch row from result set of a prepared statement */
699 
700 
pgsql_drv_fetch(db_result_t * rs)701 int pgsql_drv_fetch(db_result_t *rs)
702 {
703   /* NYI */
704   (void)rs;
705 
706   return 1;
707 }
708 
709 
710 /* Fetch row from result set of a query */
711 
712 
pgsql_drv_fetch_row(db_result_t * rs,db_row_t * row)713 int pgsql_drv_fetch_row(db_result_t *rs, db_row_t *row)
714 {
715   intptr_t rownum;
716   int      i;
717 
718   /*
719     Use row->ptr as a row number, rather than a pointer to avoid dynamic
720     memory management.
721   */
722   rownum = (intptr_t) row->ptr;
723   if (rownum >= (int) rs->nrows)
724     return DB_ERROR_IGNORABLE;
725 
726   for (i = 0; i < (int) rs->nfields; i++)
727   {
728     /*
729       PQgetvalue() returns an empty string, not a NULL value for a NULL
730       field. Callers of this function expect a NULL pointer in this case.
731     */
732     if (PQgetisnull(rs->ptr, rownum, i))
733       row->values[i].ptr = NULL;
734     else
735     {
736       row->values[i].len = PQgetlength(rs->ptr, rownum, i);
737       row->values[i].ptr = PQgetvalue(rs->ptr, rownum, i);
738     }
739   }
740 
741   row->ptr = (void *) (rownum + 1);
742 
743   return DB_ERROR_NONE;
744 }
745 
746 
747 /* Free result set */
748 
749 
pgsql_drv_free_results(db_result_t * rs)750 int pgsql_drv_free_results(db_result_t *rs)
751 {
752   if (rs->ptr != NULL)
753   {
754     PQclear((PGresult *)rs->ptr);
755     rs->ptr = NULL;
756 
757     rs->row.ptr = 0;
758     return 0;
759   }
760 
761   return 1;
762 }
763 
764 
765 /* Close prepared statement */
766 
767 
pgsql_drv_close(db_stmt_t * stmt)768 int pgsql_drv_close(db_stmt_t *stmt)
769 {
770   pg_stmt_t *pgstmt = stmt->ptr;
771   int       i;
772 
773   if (pgstmt == NULL)
774     return 1;
775 
776   if (pgstmt->name != NULL)
777     free(pgstmt->name);
778   if (pgstmt->ptypes != NULL)
779     free(pgstmt->ptypes);
780   if (pgstmt->pvalues != NULL)
781   {
782     for (i = 0; i < pgstmt->nparams; i++)
783       if (pgstmt->pvalues[i] != NULL)
784         free(pgstmt->pvalues[i]);
785     free(pgstmt->pvalues);
786   }
787 
788   xfree(stmt->ptr);
789 
790   return 0;
791 }
792 
793 
794 /* Uninitialize driver */
pgsql_drv_done(void)795 int pgsql_drv_done(void)
796 {
797   return 0;
798 }
799 
800 
801 /* Map SQL data type to bind_type value in MYSQL_BIND */
802 
803 
get_pgsql_bind_type(db_bind_type_t type)804 int get_pgsql_bind_type(db_bind_type_t type)
805 {
806   unsigned int i;
807 
808   for (i = 0; db_pgsql_bind_map[i].db_type != DB_TYPE_NONE; i++)
809     if (db_pgsql_bind_map[i].db_type == type)
810       return db_pgsql_bind_map[i].pg_type;
811 
812   return -1;
813 }
814 
815 
get_unique_stmt_name(char * name,int len)816 int get_unique_stmt_name(char *name, int len)
817 {
818   return snprintf(name, len, "sbstmt%d%d",
819                   (int) sb_rand_uniform_uint64(),
820                   (int) sb_rand_uniform_uint64());
821 }
822