1 /* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.6 2003/06/13 10:50:57 meskes Exp $ */
3 #include "postgres_fe.h"
11 static struct connection *all_connections = NULL,
12 *actual_connection = NULL;
15 ECPGget_connection(const char *connection_name)
17 struct connection *con = all_connections;
19 if (connection_name == NULL || strcmp(connection_name, "CURRENT") == 0)
20 return actual_connection;
22 for (; con && strcmp(connection_name, con->name) != 0; con = con->next);
30 ecpg_finish(struct connection * act)
34 struct ECPGtype_information_cache *cache,
37 ECPGlog("ecpg_finish: finishing %s.\n", act->name);
38 PQfinish(act->connection);
40 /* remove act from the list */
41 if (act == all_connections)
42 all_connections = act->next;
45 struct connection *con;
47 for (con = all_connections; con->next && con->next != act; con = con->next);
49 con->next = act->next;
52 if (actual_connection == act)
53 actual_connection = all_connections;
55 for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ECPGfree(ptr));
60 ECPGlog("ecpg_finish: called an extra time.\n");
64 ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
66 struct connection *con = ECPGget_connection(connection_name);
69 if (!ECPGinit(con, connection_name, lineno))
72 ECPGlog("ECPGsetcommit line %d action = %s connection = %s\n", lineno, mode, con->name);
74 if (con->autocommit == true && strncmp(mode, "off", strlen("off")) == 0)
78 if ((results = PQexec(con->connection, "begin transaction")) == NULL)
80 ECPGraise(lineno, ECPG_TRANS, NULL);
84 con->committed = false;
86 con->autocommit = false;
88 else if (con->autocommit == false && strncmp(mode, "on", strlen("on")) == 0)
92 if ((results = PQexec(con->connection, "commit")) == NULL)
94 ECPGraise(lineno, ECPG_TRANS, NULL);
98 con->committed = true;
100 con->autocommit = true;
107 ECPGsetconn(int lineno, const char *connection_name)
109 struct connection *con = ECPGget_connection(connection_name);
111 if (!ECPGinit(con, connection_name, lineno))
114 actual_connection = con;
119 ECPGnoticeProcessor_raise(int code, const char *message)
121 sqlca.sqlcode = code;
122 strncpy(sqlca.sqlerrm.sqlerrmc, message, sizeof(sqlca.sqlerrm.sqlerrmc));
123 sqlca.sqlerrm.sqlerrmc[sizeof(sqlca.sqlerrm.sqlerrmc) - 1] = 0;
124 sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc);
126 /* remove trailing newline */
127 if (sqlca.sqlerrm.sqlerrml
128 && sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml - 1] == '\n')
130 sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml - 1] = 0;
131 sqlca.sqlerrm.sqlerrml--;
134 ECPGlog("raising sqlcode %d\n", code);
138 * I know this is a mess, but we can't redesign the backend
142 ECPGnoticeProcessor(void *arg, const char *message)
144 /* these notices raise an error */
145 if (strncmp(message, "WARNING: ", 9))
147 ECPGlog("ECPGnoticeProcessor: strange warning '%s'\n", message);
148 ECPGnoticeProcessor_raise(ECPG_WARNING_UNRECOGNIZED, message);
153 while (*message == ' ')
155 ECPGlog("WARNING: %s", message);
157 /* WARNING: (transaction aborted): queries ignored until END */
160 * WARNING: current transaction is aborted, queries ignored until end
161 * of transaction block
163 if (strstr(message, "queries ignored") && strstr(message, "transaction")
164 && strstr(message, "aborted"))
166 ECPGnoticeProcessor_raise(ECPG_WARNING_QUERY_IGNORED, message);
170 /* WARNING: PerformPortalClose: portal "*" not found */
171 if ((!strncmp(message, "PerformPortalClose: portal", 26)
172 || !strncmp(message, "PerformPortalFetch: portal", 26))
173 && strstr(message + 26, "not found"))
175 ECPGnoticeProcessor_raise(ECPG_WARNING_UNKNOWN_PORTAL, message);
179 /* WARNING: BEGIN: already a transaction in progress */
180 if (!strncmp(message, "BEGIN: already a transaction in progress", 40))
182 ECPGnoticeProcessor_raise(ECPG_WARNING_IN_TRANSACTION, message);
186 /* WARNING: AbortTransaction and not in in-progress state */
187 /* WARNING: COMMIT: no transaction in progress */
188 /* WARNING: ROLLBACK: no transaction in progress */
189 if (!strncmp(message, "AbortTransaction and not in in-progress state", 45)
190 || !strncmp(message, "COMMIT: no transaction in progress", 34)
191 || !strncmp(message, "ROLLBACK: no transaction in progress", 36))
193 ECPGnoticeProcessor_raise(ECPG_WARNING_NO_TRANSACTION, message);
197 /* WARNING: BlankPortalAssignName: portal * already exists */
198 if (!strncmp(message, "BlankPortalAssignName: portal", 29)
199 && strstr(message + 29, "already exists"))
201 ECPGnoticeProcessor_raise(ECPG_WARNING_PORTAL_EXISTS, message);
205 /* these are harmless - do nothing */
208 * WARNING: CREATE TABLE / PRIMARY KEY will create implicit index '*'
213 * WARNING: ALTER TABLE ... ADD CONSTRAINT will create implicit
214 * trigger(s) for FOREIGN KEY check(s)
218 * WARNING: CREATE TABLE will create implicit sequence '*' for SERIAL
223 * WARNING: CREATE TABLE will create implicit trigger(s) for FOREIGN
226 if ((!strncmp(message, "CREATE TABLE", 12) || !strncmp(message, "ALTER TABLE", 11))
227 && strstr(message + 11, "will create implicit"))
230 /* WARNING: QUERY PLAN: */
231 if (!strncmp(message, "QUERY PLAN:", 11)) /* do we really see these? */
235 * WARNING: DROP TABLE implicitly drops referential integrity trigger
238 if (!strncmp(message, "DROP TABLE implicitly drops", 27))
242 * WARNING: Caution: DROP INDEX cannot be rolled back, so don't abort
245 if (strstr(message, "cannot be rolled back"))
248 /* these and other unmentioned should set sqlca.sqlwarn[2] */
249 /* WARNING: The ':' operator is deprecated. Use exp(x) instead. */
250 /* WARNING: Rel *: Uninitialized page 0 - fixing */
251 /* WARNING: PortalHeapMemoryFree: * not in alloc set! */
252 /* WARNING: Too old parent tuple found - can't continue vc_repair_frag */
253 /* WARNING: identifier "*" will be truncated to "*" */
254 /* WARNING: InvalidateSharedInvalid: cache state reset */
255 /* WARNING: RegisterSharedInvalid: SI buffer overflow */
256 sqlca.sqlwarn[2] = 'W';
257 sqlca.sqlwarn[0] = 'W';
260 /* this contains some quick hacks, needs to be cleaned up, but it works */
262 ECPGconnect(int lineno, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
264 struct connection *this;
265 char *dbname = strdup(name),
274 if ((this = (struct connection *) ECPGalloc(sizeof(struct connection), lineno)) == NULL)
277 if (dbname == NULL && connection_name == NULL)
278 connection_name = "DEFAULT";
280 /* get the detail information out of dbname */
281 if (strchr(dbname, '@') != NULL)
283 /* old style: dbname[@server][:port] */
284 tmp = strrchr(dbname, ':');
285 if (tmp != NULL) /* port number given */
287 port = strdup(tmp + 1);
291 tmp = strrchr(dbname, '@');
292 if (tmp != NULL) /* host name given */
294 host = strdup(tmp + 1);
297 realname = strdup(dbname);
299 else if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
304 * only allow protocols tcp and unix
306 if (strncmp(dbname, "tcp:", 4) == 0)
308 else if (strncmp(dbname, "unix:", 5) == 0)
311 if (strncmp(dbname + offset, "postgresql://", strlen("postgresql://")) == 0)
316 * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:]
317 * [/db name][?options]
320 offset += strlen("postgresql://");
322 tmp = strrchr(dbname + offset, '?');
323 if (tmp != NULL) /* options given */
325 options = strdup(tmp + 1);
329 tmp = last_path_separator(dbname + offset);
330 if (tmp != NULL) /* database name given */
332 realname = strdup(tmp + 1);
336 tmp = strrchr(dbname + offset, ':');
337 if (tmp != NULL) /* port number or Unix socket path given */
342 if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
345 host = strdup(tmp + 1);
346 if (strncmp(dbname, "unix:", 5) != 0)
348 ECPGlog("connect: socketname %s given for TCP connection in line %d\n", host, lineno);
349 ECPGraise(lineno, ECPG_CONNECT, realname ? realname : "<DEFAULT>");
364 port = strdup(tmp + 1);
367 if (strncmp(dbname, "unix:", 5) == 0)
369 if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0)
371 ECPGlog("connect: non-localhost access via sockets in line %d\n", lineno);
372 ECPGraise(lineno, ECPG_CONNECT, realname ? realname : "<DEFAULT>");
387 host = strdup(dbname + offset);
391 realname = strdup(dbname);
394 realname = strdup(dbname);
396 /* add connection to our list */
397 if (connection_name != NULL)
398 this->name = ECPGstrdup(connection_name, lineno);
400 this->name = ECPGstrdup(realname, lineno);
402 this->cache_head = NULL;
404 if (all_connections == NULL)
407 this->next = all_connections;
409 actual_connection = all_connections = this;
411 ECPGlog("ECPGconnect: opening database %s on %s port %s %s%s%s%s\n",
412 realname ? realname : "<DEFAULT>",
413 host ? host : "<DEFAULT>",
414 port ? port : "<DEFAULT>",
415 options ? "with options " : "", options ? options : "",
416 user ? "for user " : "", user ? user : "");
418 this->connection = PQsetdbLogin(host, port, options, NULL, realname, user, passwd);
420 if (PQstatus(this->connection) == CONNECTION_BAD)
422 const char *errmsg = PQerrorMessage(this->connection);
423 char *db = realname ? realname : "<DEFAULT>";
425 set_backend_err(errmsg, lineno);
427 ECPGlog("connect: could not open database %s on %s port %s %s%s%s%s in line %d\n\t%s\n",
429 host ? host : "<DEFAULT>",
430 port ? port : "<DEFAULT>",
431 options ? "with options " : "", options ? options : "",
432 user ? "for user " : "", user ? user : "",
435 ECPGraise(lineno, ECPG_CONNECT, db);
460 this->committed = true;
461 this->autocommit = autocommit;
463 PQsetNoticeProcessor(this->connection, &ECPGnoticeProcessor, (void *) this);
469 ECPGdisconnect(int lineno, const char *connection_name)
471 struct connection *con;
473 if (strcmp(connection_name, "ALL") == 0)
476 for (con = all_connections; con;)
478 struct connection *f = con;
486 con = ECPGget_connection(connection_name);
488 if (!ECPGinit(con, connection_name, lineno))