PostgreSQL Source Code git master
connect.c
Go to the documentation of this file.
1/* src/interfaces/ecpg/ecpglib/connect.c */
2
3#define POSTGRES_ECPG_INTERNAL
4#include "postgres_fe.h"
5
7#include "ecpgerrno.h"
8#include "ecpglib.h"
9#include "ecpglib_extern.h"
10#include "ecpgtype.h"
11#include "sqlca.h"
12
13#ifdef HAVE_USELOCALE
14locale_t ecpg_clocale = (locale_t) 0;
15#endif
16
19static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT;
20static struct connection *actual_connection = NULL;
21static struct connection *all_connections = NULL;
22
23static void
25{
26 pthread_key_create(&actual_connection_key, NULL);
27}
28
29void
31{
33}
34
35static struct connection *
36ecpg_get_connection_nr(const char *connection_name)
37{
38 struct connection *ret = NULL;
39
40 if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
41 {
42 ecpg_pthreads_init(); /* ensure actual_connection_key is valid */
43
45
46 /*
47 * if no connection in TSD for this thread, get the global default
48 * connection and hope the user knows what they're doing (i.e. using
49 * their own mutex to protect that connection from concurrent accesses
50 */
51 if (ret == NULL)
52 /* no TSD connection, going for global */
54 }
55 else
56 {
57 struct connection *con;
58
59 for (con = all_connections; con != NULL; con = con->next)
60 {
61 if (strcmp(connection_name, con->name) == 0)
62 break;
63 }
64 ret = con;
65 }
66
67 return ret;
68}
69
70struct connection *
71ecpg_get_connection(const char *connection_name)
72{
73 struct connection *ret = NULL;
74
75 if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
76 {
77 ecpg_pthreads_init(); /* ensure actual_connection_key is valid */
78
80
81 /*
82 * if no connection in TSD for this thread, get the global default
83 * connection and hope the user knows what they're doing (i.e. using
84 * their own mutex to protect that connection from concurrent accesses
85 */
86 if (ret == NULL)
87 /* no TSD connection here either, using global */
89 }
90 else
91 {
93
94 ret = ecpg_get_connection_nr(connection_name);
95
97 }
98
99 return ret;
100}
101
102static void
104{
105 if (act != NULL)
106 {
107 struct ECPGtype_information_cache *cache,
108 *ptr;
109
111 PQfinish(act->connection);
112
113 /*
114 * no need to lock connections_mutex - we're always called by
115 * ECPGdisconnect or ECPGconnect, which are holding the lock
116 */
117
118 /* remove act from the list */
119 if (act == all_connections)
120 all_connections = act->next;
121 else
122 {
123 struct connection *con;
124
125 for (con = all_connections; con->next && con->next != act; con = con->next);
126 if (con->next)
127 con->next = act->next;
128 }
129
132 if (actual_connection == act)
134
135 ecpg_log("ecpg_finish: connection %s closed\n", act->name ? act->name : "(null)");
136
137 for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ecpg_free(ptr));
138 ecpg_free(act->name);
139 ecpg_free(act);
140 /* delete cursor variables when last connection gets closed */
141 if (all_connections == NULL)
142 {
143 struct var_list *iv_ptr;
144
145 for (; ivlist; iv_ptr = ivlist, ivlist = ivlist->next, ecpg_free(iv_ptr));
146 }
147 }
148 else
149 ecpg_log("ecpg_finish: called an extra time\n");
150}
151
152bool
153ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
154{
155 struct connection *con = ecpg_get_connection(connection_name);
156 PGresult *results;
157
158 if (!ecpg_init(con, connection_name, lineno))
159 return false;
160
161 ecpg_log("ECPGsetcommit on line %d: action \"%s\"; connection \"%s\"\n", lineno, mode, con->name);
162
163 if (con->autocommit && strncmp(mode, "off", strlen("off")) == 0)
164 {
166 {
167 results = PQexec(con->connection, "begin transaction");
168 if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
169 return false;
170 PQclear(results);
171 }
172 con->autocommit = false;
173 }
174 else if (!con->autocommit && strncmp(mode, "on", strlen("on")) == 0)
175 {
177 {
178 results = PQexec(con->connection, "commit");
179 if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
180 return false;
181 PQclear(results);
182 }
183 con->autocommit = true;
184 }
185
186 return true;
187}
188
189bool
190ECPGsetconn(int lineno, const char *connection_name)
191{
192 struct connection *con = ecpg_get_connection(connection_name);
193
194 if (!ecpg_init(con, connection_name, lineno))
195 return false;
196
198 return true;
199}
200
201
202static void
203ECPGnoticeReceiver(void *arg, const PGresult *result)
204{
205 char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
206 char *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
207 struct sqlca_t *sqlca = ECPGget_sqlca();
208 int sqlcode;
209
210 if (sqlca == NULL)
211 {
212 ecpg_log("out of memory");
213 return;
214 }
215
216 (void) arg; /* keep the compiler quiet */
217 if (sqlstate == NULL)
219
220 if (message == NULL) /* Shouldn't happen, but need to be sure */
221 message = ecpg_gettext("empty message text");
222
223 /* these are not warnings */
224 if (strncmp(sqlstate, "00", 2) == 0)
225 return;
226
227 ecpg_log("ECPGnoticeReceiver: %s\n", message);
228
229 /* map to SQLCODE for backward compatibility */
232 else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION) == 0)
236 else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR) == 0)
238 else
239 sqlcode = 0;
240
241 strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
242 sqlca->sqlcode = sqlcode;
243 sqlca->sqlwarn[2] = 'W';
244 sqlca->sqlwarn[0] = 'W';
245
246 strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
247 sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
248 sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
249
250 ecpg_log("raising sqlcode %d\n", sqlcode);
251}
252
253/* this contains some quick hacks, needs to be cleaned up, but it works */
254bool
255ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
256{
257 struct sqlca_t *sqlca = ECPGget_sqlca();
258 enum COMPAT_MODE compat = c;
259 struct connection *this;
260 int i,
261 connect_params = 0;
262 char *dbname = name ? ecpg_strdup(name, lineno) : NULL,
263 *host = NULL,
264 *tmp,
265 *port = NULL,
266 *realname = NULL,
267 *options = NULL;
268 const char **conn_keywords;
269 const char **conn_values;
270
271 if (sqlca == NULL)
272 {
276 return false;
277 }
278
280
281 /*
282 * clear auto_mem structure because some error handling functions might
283 * access it
284 */
286
288 {
289 char *envname;
290
291 /*
292 * Informix uses an environment variable DBPATH that overrides the
293 * connection parameters given here. We do the same with PG_DBPATH as
294 * the syntax is different.
295 */
296 envname = getenv("PG_DBPATH");
297 if (envname)
298 {
300 dbname = ecpg_strdup(envname, lineno);
301 }
302 }
303
304 if (dbname == NULL && connection_name == NULL)
305 connection_name = "DEFAULT";
306
308
309 /* check if the identifier is unique */
310 if (ecpg_get_connection(connection_name))
311 {
313 ecpg_log("ECPGconnect: connection identifier %s is already in use\n",
314 connection_name);
315 return false;
316 }
317
318 if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL)
319 {
321 return false;
322 }
323
324 if (dbname != NULL)
325 {
326 /* get the detail information from dbname */
327 if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
328 {
329 int offset = 0;
330
331 /*
332 * only allow protocols tcp and unix
333 */
334 if (strncmp(dbname, "tcp:", 4) == 0)
335 offset = 4;
336 else if (strncmp(dbname, "unix:", 5) == 0)
337 offset = 5;
338
339 if (strncmp(dbname + offset, "postgresql://", strlen("postgresql://")) == 0)
340 {
341
342 /*------
343 * new style:
344 * <tcp|unix>:postgresql://server[:port][/db-name][?options]
345 *------
346 */
347 offset += strlen("postgresql://");
348
349 tmp = strrchr(dbname + offset, '?');
350 if (tmp != NULL) /* options given */
351 {
352 options = ecpg_strdup(tmp + 1, lineno);
353 *tmp = '\0';
354 }
355
356 tmp = last_dir_separator(dbname + offset);
357 if (tmp != NULL) /* database name given */
358 {
359 if (tmp[1] != '\0') /* non-empty database name */
360 {
361 realname = ecpg_strdup(tmp + 1, lineno);
362 connect_params++;
363 }
364 *tmp = '\0';
365 }
366
367 tmp = strrchr(dbname + offset, ':');
368 if (tmp != NULL) /* port number given */
369 {
370 *tmp = '\0';
371 port = ecpg_strdup(tmp + 1, lineno);
372 connect_params++;
373 }
374
375 if (strncmp(dbname, "unix:", 5) == 0)
376 {
377 /*
378 * The alternative of using "127.0.0.1" here is deprecated
379 * and undocumented; we'll keep it for backward
380 * compatibility's sake, but not extend it to allow IPv6.
381 */
382 if (strcmp(dbname + offset, "localhost") != 0 &&
383 strcmp(dbname + offset, "127.0.0.1") != 0)
384 {
385 ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno);
387 if (host)
388 ecpg_free(host);
389 if (port)
391 if (options)
393 if (realname)
394 ecpg_free(realname);
395 if (dbname)
397 free(this);
398 return false;
399 }
400 }
401 else
402 {
403 if (*(dbname + offset) != '\0')
404 {
405 host = ecpg_strdup(dbname + offset, lineno);
406 connect_params++;
407 }
408 }
409 }
410 }
411 else
412 {
413 /* old style: dbname[@server][:port] */
414 tmp = strrchr(dbname, ':');
415 if (tmp != NULL) /* port number given */
416 {
417 port = ecpg_strdup(tmp + 1, lineno);
418 connect_params++;
419 *tmp = '\0';
420 }
421
422 tmp = strrchr(dbname, '@');
423 if (tmp != NULL) /* host name given */
424 {
425 host = ecpg_strdup(tmp + 1, lineno);
426 connect_params++;
427 *tmp = '\0';
428 }
429
430 if (strlen(dbname) > 0)
431 {
432 realname = ecpg_strdup(dbname, lineno);
433 connect_params++;
434 }
435 else
436 realname = NULL;
437 }
438 }
439 else
440 realname = NULL;
441
442 /*
443 * Count options for the allocation done below (this may produce an
444 * overestimate, it's ok).
445 */
446 if (options)
447 for (i = 0; options[i]; i++)
448 if (options[i] == '=')
449 connect_params++;
450
451 if (user && strlen(user) > 0)
452 connect_params++;
453 if (passwd && strlen(passwd) > 0)
454 connect_params++;
455
456 /*
457 * Allocate enough space for all connection parameters. These allocations
458 * are done before manipulating the list of connections to ease the error
459 * handling on failure.
460 */
461 conn_keywords = (const char **) ecpg_alloc((connect_params + 1) * sizeof(char *), lineno);
462 conn_values = (const char **) ecpg_alloc(connect_params * sizeof(char *), lineno);
463 if (conn_keywords == NULL || conn_values == NULL)
464 {
465 if (host)
466 ecpg_free(host);
467 if (port)
469 if (options)
471 if (realname)
472 ecpg_free(realname);
473 if (dbname)
475 if (conn_keywords)
476 ecpg_free(conn_keywords);
477 if (conn_values)
478 ecpg_free(conn_values);
479 free(this);
480 return false;
481 }
482
483 /* add connection to our list */
485
486 /*
487 * ... but first, make certain we have created ecpg_clocale. Rely on
488 * holding connections_mutex to ensure this is done by only one thread.
489 */
490#ifdef HAVE_USELOCALE
491 if (!ecpg_clocale)
492 {
493 ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
494 if (!ecpg_clocale)
495 {
499 if (host)
500 ecpg_free(host);
501 if (port)
503 if (options)
505 if (realname)
506 ecpg_free(realname);
507 if (dbname)
509 if (conn_keywords)
510 ecpg_free(conn_keywords);
511 if (conn_values)
512 ecpg_free(conn_values);
513 free(this);
514 return false;
515 }
516 }
517#endif
518
519 if (connection_name != NULL)
520 this->name = ecpg_strdup(connection_name, lineno);
521 else
522 this->name = ecpg_strdup(realname, lineno);
523
524 this->cache_head = NULL;
525 this->prep_stmts = NULL;
526
527 if (all_connections == NULL)
528 this->next = NULL;
529 else
530 this->next = all_connections;
531
532 all_connections = this;
535
536 ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n",
537 realname ? realname : "<DEFAULT>",
538 host ? host : "<DEFAULT>",
539 port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>",
540 options ? "with options " : "", options ? options : "",
541 (user && strlen(user) > 0) ? "for user " : "", user ? user : "");
542
543 i = 0;
544 if (realname)
545 {
546 conn_keywords[i] = "dbname";
547 conn_values[i] = realname;
548 i++;
549 }
550 if (host)
551 {
552 conn_keywords[i] = "host";
553 conn_values[i] = host;
554 i++;
555 }
556 if (port)
557 {
558 conn_keywords[i] = "port";
559 conn_values[i] = port;
560 i++;
561 }
562 if (user && strlen(user) > 0)
563 {
564 conn_keywords[i] = "user";
565 conn_values[i] = user;
566 i++;
567 }
568 if (passwd && strlen(passwd) > 0)
569 {
570 conn_keywords[i] = "password";
571 conn_values[i] = passwd;
572 i++;
573 }
574 if (options)
575 {
576 char *str;
577
578 /*
579 * The options string contains "keyword=value" pairs separated by
580 * '&'s. We must break this up into keywords and values to pass to
581 * libpq (it's okay to scribble on the options string). We ignore
582 * spaces just before each keyword or value. (The preprocessor used
583 * to add spaces around '&'s, making it necessary to ignore spaces
584 * before keywords here. While it no longer does that, we still must
585 * skip spaces to support code compiled with older preprocessors.)
586 */
587 for (str = options; *str;)
588 {
589 int e,
590 a;
591 char *token1,
592 *token2;
593
594 /* Skip spaces before keyword */
595 for (token1 = str; *token1 == ' '; token1++)
596 /* skip */ ;
597 /* Find end of keyword */
598 for (e = 0; token1[e] && token1[e] != '='; e++)
599 /* skip */ ;
600 if (token1[e]) /* found "=" */
601 {
602 token1[e] = '\0';
603 /* Skip spaces before value */
604 for (token2 = token1 + e + 1; *token2 == ' '; token2++)
605 /* skip */ ;
606 /* Find end of value */
607 for (a = 0; token2[a] && token2[a] != '&'; a++)
608 /* skip */ ;
609 if (token2[a]) /* found "&" => another option follows */
610 {
611 token2[a] = '\0';
612 str = token2 + a + 1;
613 }
614 else
615 str = token2 + a;
616
617 conn_keywords[i] = token1;
618 conn_values[i] = token2;
619 i++;
620 }
621 else
622 {
623 /* Bogus options syntax ... ignore trailing garbage */
624 str = token1 + e;
625 }
626 }
627 }
628
629 Assert(i <= connect_params);
630 conn_keywords[i] = NULL; /* terminator */
631
632 this->connection = PQconnectdbParams(conn_keywords, conn_values, 0);
633
634 if (host)
635 ecpg_free(host);
636 if (port)
638 if (options)
640 if (dbname)
642 ecpg_free(conn_values);
643 ecpg_free(conn_keywords);
644
645 if (PQstatus(this->connection) == CONNECTION_BAD)
646 {
647 const char *errmsg = PQerrorMessage(this->connection);
648 const char *db = realname ? realname : ecpg_gettext("<DEFAULT>");
649
650 /* PQerrorMessage's result already has a trailing newline */
651 ecpg_log("ECPGconnect: %s", errmsg);
652
653 ecpg_finish(this);
655
657 if (realname)
658 ecpg_free(realname);
659
660 return false;
661 }
662
663 if (realname)
664 ecpg_free(realname);
665
667
668 this->autocommit = autocommit;
669
671
672 return true;
673}
674
675bool
676ECPGdisconnect(int lineno, const char *connection_name)
677{
678 struct sqlca_t *sqlca = ECPGget_sqlca();
679 struct connection *con;
680
681 if (sqlca == NULL)
682 {
685 return false;
686 }
687
689
690 if (strcmp(connection_name, "ALL") == 0)
691 {
693 for (con = all_connections; con;)
694 {
695 struct connection *f = con;
696
697 con = con->next;
698 ecpg_finish(f);
699 }
700 }
701 else
702 {
703 con = ecpg_get_connection_nr(connection_name);
704
705 if (!ecpg_init(con, connection_name, lineno))
706 {
708 return false;
709 }
710 else
711 ecpg_finish(con);
712 }
713
715
716 return true;
717}
718
719PGconn *
720ECPGget_PGconn(const char *connection_name)
721{
722 struct connection *con;
723
724 con = ecpg_get_connection(connection_name);
725 if (con == NULL)
726 return NULL;
727
728 return con->connection;
729}
static int32 next
Definition: blutils.c:219
#define Assert(condition)
Definition: c.h:815
static struct connection * ecpg_get_connection_nr(const char *connection_name)
Definition: connect.c:36
static void ecpg_finish(struct connection *act)
Definition: connect.c:103
static pthread_mutex_t connections_mutex
Definition: connect.c:17
void ecpg_pthreads_init(void)
Definition: connect.c:30
static pthread_key_t actual_connection_key
Definition: connect.c:18
static struct connection * all_connections
Definition: connect.c:21
PGconn * ECPGget_PGconn(const char *connection_name)
Definition: connect.c:720
bool ECPGsetconn(int lineno, const char *connection_name)
Definition: connect.c:190
bool ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
Definition: connect.c:153
bool ECPGdisconnect(int lineno, const char *connection_name)
Definition: connect.c:676
static void ECPGnoticeReceiver(void *arg, const PGresult *result)
Definition: connect.c:203
static pthread_once_t actual_connection_key_once
Definition: connect.c:19
static struct connection * actual_connection
Definition: connect.c:20
bool ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
Definition: connect.c:255
struct connection * ecpg_get_connection(const char *connection_name)
Definition: connect.c:71
static void ecpg_actual_connection_init(void)
Definition: connect.c:24
bool autocommit
Definition: ecpg.c:15
enum COMPAT_MODE compat
Definition: ecpg.c:26
#define ECPG_WARNING_IN_TRANSACTION
Definition: ecpgerrno.h:72
#define ECPG_WARNING_UNKNOWN_PORTAL
Definition: ecpgerrno.h:70
#define ECPG_WARNING_PORTAL_EXISTS
Definition: ecpgerrno.h:77
#define ECPG_WARNING_NO_TRANSACTION
Definition: ecpgerrno.h:75
#define ECPG_OUT_OF_MEMORY
Definition: ecpgerrno.h:15
#define ECPG_CONNECT
Definition: ecpgerrno.h:51
#define ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION
bool ecpg_check_PQresult(PGresult *results, int lineno, PGconn *connection, enum COMPAT_MODE compat)
Definition: error.c:281
#define ecpg_gettext(x)
bool ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
Definition: prepare.c:337
#define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY
COMPAT_MODE
@ ECPG_COMPAT_PGSQL
char * ecpg_alloc(long size, int lineno)
Definition: memory.c:19
#define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR
#define ECPG_SQLSTATE_INVALID_CURSOR_NAME
void ecpg_log(const char *format,...) pg_attribute_printf(1
void ecpg_clear_auto_mem(void)
Definition: memory.c:151
bool ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
Definition: misc.c:73
#define ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION
#define INFORMIX_MODE(X)
#define ECPG_SQLSTATE_DUPLICATE_CURSOR
void ecpg_init_sqlca(struct sqlca_t *sqlca)
Definition: misc.c:67
struct var_list * ivlist
Definition: misc.c:535
#define ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION
void ecpg_raise(int line, int code, const char *sqlstate, const char *str)
Definition: error.c:13
bool ecpg_internal_regression_mode
Definition: misc.c:29
char * ecpg_strdup(const char *string, int lineno)
Definition: memory.c:47
void ecpg_free(void *ptr)
Definition: memory.c:13
int errmsg(const char *fmt,...)
Definition: elog.c:1070
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:7213
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7205
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4939
PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg)
Definition: fe-connect.c:7430
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7268
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:698
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:3466
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2262
const char * str
#define free(a)
Definition: header.h:65
struct sqlca_t * ECPGget_sqlca(void)
Definition: misc.c:108
int a
Definition: isn.c:68
int i
Definition: isn.c:72
@ CONNECTION_BAD
Definition: libpq-fe.h:82
@ PQTRANS_IDLE
Definition: libpq-fe.h:142
void * arg
static PgChecksumMode mode
Definition: pg_checksums.c:55
static char * user
Definition: pg_regress.c:119
static int port
Definition: pg_regress.c:115
char * last_dir_separator(const char *filename)
Definition: path.c:140
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
#define PG_DIAG_MESSAGE_PRIMARY
Definition: postgres_ext.h:58
char * c
e
Definition: preproc-init.c:82
int pthread_mutex_unlock(pthread_mutex_t *mp)
Definition: pthread-win32.c:60
int pthread_mutex_lock(pthread_mutex_t *mp)
Definition: pthread-win32.c:42
void pthread_setspecific(pthread_key_t key, void *val)
Definition: pthread-win32.c:24
void * pthread_getspecific(pthread_key_t key)
Definition: pthread-win32.c:29
#define PTHREAD_MUTEX_INITIALIZER
Definition: pthread-win32.h:16
ULONG pthread_key_t
Definition: pthread-win32.h:7
int pthread_once_t
Definition: pthread-win32.h:18
#define sqlca
Definition: sqlca.h:59
char * dbname
Definition: streamutil.c:50
struct ECPGtype_information_cache * next
PGconn * connection
struct ECPGtype_information_cache * cache_head
struct connection * next
struct prepared_statement * prep_stmts
Definition: sqlca.h:20
char sqlstate[5]
Definition: sqlca.h:53
long sqlcode
Definition: sqlca.h:23
struct var_list * next
const char * name
#define locale_t
Definition: win32_port.h:432