]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/ecpglib/connect.c
- Enable FETCH without INTO.
[postgresql] / src / interfaces / ecpg / ecpglib / connect.c
1 /* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.6 2003/06/13 10:50:57 meskes Exp $ */
2
3 #include "postgres_fe.h"
4
5 #include "ecpgtype.h"
6 #include "ecpglib.h"
7 #include "ecpgerrno.h"
8 #include "extern.h"
9 #include "sqlca.h"
10
11 static struct connection *all_connections = NULL,
12                    *actual_connection = NULL;
13
14 struct connection *
15 ECPGget_connection(const char *connection_name)
16 {
17         struct connection *con = all_connections;
18
19         if (connection_name == NULL || strcmp(connection_name, "CURRENT") == 0)
20                 return actual_connection;
21
22         for (; con && strcmp(connection_name, con->name) != 0; con = con->next);
23         if (con)
24                 return con;
25         else
26                 return NULL;
27 }
28
29 static void
30 ecpg_finish(struct connection * act)
31 {
32         if (act != NULL)
33         {
34                 struct ECPGtype_information_cache *cache,
35                                    *ptr;
36
37                 ECPGlog("ecpg_finish: finishing %s.\n", act->name);
38                 PQfinish(act->connection);
39
40                 /* remove act from the list */
41                 if (act == all_connections)
42                         all_connections = act->next;
43                 else
44                 {
45                         struct connection *con;
46
47                         for (con = all_connections; con->next && con->next != act; con = con->next);
48                         if (con->next)
49                                 con->next = act->next;
50                 }
51
52                 if (actual_connection == act)
53                         actual_connection = all_connections;
54
55                 for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ECPGfree(ptr));
56                 ECPGfree(act->name);
57                 ECPGfree(act);
58         }
59         else
60                 ECPGlog("ecpg_finish: called an extra time.\n");
61 }
62
63 bool
64 ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
65 {
66         struct connection *con = ECPGget_connection(connection_name);
67         PGresult   *results;
68
69         if (!ECPGinit(con, connection_name, lineno))
70                 return (false);
71
72         ECPGlog("ECPGsetcommit line %d action = %s connection = %s\n", lineno, mode, con->name);
73
74         if (con->autocommit == true && strncmp(mode, "off", strlen("off")) == 0)
75         {
76                 if (con->committed)
77                 {
78                         if ((results = PQexec(con->connection, "begin transaction")) == NULL)
79                         {
80                                 ECPGraise(lineno, ECPG_TRANS, NULL);
81                                 return false;
82                         }
83                         PQclear(results);
84                         con->committed = false;
85                 }
86                 con->autocommit = false;
87         }
88         else if (con->autocommit == false && strncmp(mode, "on", strlen("on")) == 0)
89         {
90                 if (!con->committed)
91                 {
92                         if ((results = PQexec(con->connection, "commit")) == NULL)
93                         {
94                                 ECPGraise(lineno, ECPG_TRANS, NULL);
95                                 return false;
96                         }
97                         PQclear(results);
98                         con->committed = true;
99                 }
100                 con->autocommit = true;
101         }
102
103         return true;
104 }
105
106 bool
107 ECPGsetconn(int lineno, const char *connection_name)
108 {
109         struct connection *con = ECPGget_connection(connection_name);
110
111         if (!ECPGinit(con, connection_name, lineno))
112                 return (false);
113
114         actual_connection = con;
115         return true;
116 }
117
118 static void
119 ECPGnoticeProcessor_raise(int code, const char *message)
120 {
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);
125
126         /* remove trailing newline */
127         if (sqlca.sqlerrm.sqlerrml
128                 && sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml - 1] == '\n')
129         {
130                 sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml - 1] = 0;
131                 sqlca.sqlerrm.sqlerrml--;
132         }
133
134         ECPGlog("raising sqlcode %d\n", code);
135 }
136
137 /*
138  * I know this is a mess, but we can't redesign the backend
139  */
140
141 static void
142 ECPGnoticeProcessor(void *arg, const char *message)
143 {
144         /* these notices raise an error */
145         if (strncmp(message, "WARNING: ", 9))
146         {
147                 ECPGlog("ECPGnoticeProcessor: strange warning '%s'\n", message);
148                 ECPGnoticeProcessor_raise(ECPG_WARNING_UNRECOGNIZED, message);
149                 return;
150         }
151
152         message += 8;
153         while (*message == ' ')
154                 message++;
155         ECPGlog("WARNING: %s", message);
156
157         /* WARNING: (transaction aborted): queries ignored until END */
158
159         /*
160          * WARNING: current transaction is aborted, queries ignored until end
161          * of transaction block
162          */
163         if (strstr(message, "queries ignored") && strstr(message, "transaction")
164                 && strstr(message, "aborted"))
165         {
166                 ECPGnoticeProcessor_raise(ECPG_WARNING_QUERY_IGNORED, message);
167                 return;
168         }
169
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"))
174         {
175                 ECPGnoticeProcessor_raise(ECPG_WARNING_UNKNOWN_PORTAL, message);
176                 return;
177         }
178
179         /* WARNING: BEGIN: already a transaction in progress */
180         if (!strncmp(message, "BEGIN: already a transaction in progress", 40))
181         {
182                 ECPGnoticeProcessor_raise(ECPG_WARNING_IN_TRANSACTION, message);
183                 return;
184         }
185
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))
192         {
193                 ECPGnoticeProcessor_raise(ECPG_WARNING_NO_TRANSACTION, message);
194                 return;
195         }
196
197         /* WARNING: BlankPortalAssignName: portal * already exists */
198         if (!strncmp(message, "BlankPortalAssignName: portal", 29)
199                 && strstr(message + 29, "already exists"))
200         {
201                 ECPGnoticeProcessor_raise(ECPG_WARNING_PORTAL_EXISTS, message);
202                 return;
203         }
204
205         /* these are harmless - do nothing */
206
207         /*
208          * WARNING: CREATE TABLE / PRIMARY KEY will create implicit index '*'
209          * for table '*'
210          */
211
212         /*
213          * WARNING: ALTER TABLE ... ADD CONSTRAINT will create implicit
214          * trigger(s) for FOREIGN KEY check(s)
215          */
216
217         /*
218          * WARNING: CREATE TABLE will create implicit sequence '*' for SERIAL
219          * column '*.*'
220          */
221
222         /*
223          * WARNING: CREATE TABLE will create implicit trigger(s) for FOREIGN
224          * KEY check(s)
225          */
226         if ((!strncmp(message, "CREATE TABLE", 12) || !strncmp(message, "ALTER TABLE", 11))
227                 && strstr(message + 11, "will create implicit"))
228                 return;
229
230         /* WARNING: QUERY PLAN: */
231         if (!strncmp(message, "QUERY PLAN:", 11))       /* do we really see these? */
232                 return;
233
234         /*
235          * WARNING: DROP TABLE implicitly drops referential integrity trigger
236          * from table "*"
237          */
238         if (!strncmp(message, "DROP TABLE implicitly drops", 27))
239                 return;
240
241         /*
242          * WARNING: Caution: DROP INDEX cannot be rolled back, so don't abort
243          * now
244          */
245         if (strstr(message, "cannot be rolled back"))
246                 return;
247
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';
258 }
259
260 /* this contains some quick hacks, needs to be cleaned up, but it works */
261 bool
262 ECPGconnect(int lineno, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
263 {
264         struct connection *this;
265         char       *dbname = strdup(name),
266                            *host = NULL,
267                            *tmp,
268                            *port = NULL,
269                            *realname = NULL,
270                            *options = NULL;
271
272         ECPGinit_sqlca();
273
274         if ((this = (struct connection *) ECPGalloc(sizeof(struct connection), lineno)) == NULL)
275                 return false;
276
277         if (dbname == NULL && connection_name == NULL)
278                 connection_name = "DEFAULT";
279
280         /* get the detail information out of dbname */
281         if (strchr(dbname, '@') != NULL)
282         {
283                 /* old style: dbname[@server][:port] */
284                 tmp = strrchr(dbname, ':');
285                 if (tmp != NULL)                /* port number given */
286                 {
287                         port = strdup(tmp + 1);
288                         *tmp = '\0';
289                 }
290
291                 tmp = strrchr(dbname, '@');
292                 if (tmp != NULL)                /* host name given */
293                 {
294                         host = strdup(tmp + 1);
295                         *tmp = '\0';
296                 }
297                 realname = strdup(dbname);
298         }
299         else if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
300         {
301                 int                     offset = 0;
302
303                 /*
304                  * only allow protocols tcp and unix
305                  */
306                 if (strncmp(dbname, "tcp:", 4) == 0)
307                         offset = 4;
308                 else if (strncmp(dbname, "unix:", 5) == 0)
309                         offset = 5;
310
311                 if (strncmp(dbname + offset, "postgresql://", strlen("postgresql://")) == 0)
312                 {
313
314                         /*------
315                          * new style:
316                          *      <tcp|unix>:postgresql://server[:port|:/unixsocket/path:]
317                          *      [/db name][?options]
318                          *------
319                          */
320                         offset += strlen("postgresql://");
321
322                         tmp = strrchr(dbname + offset, '?');
323                         if (tmp != NULL)        /* options given */
324                         {
325                                 options = strdup(tmp + 1);
326                                 *tmp = '\0';
327                         }
328
329                         tmp = last_path_separator(dbname + offset); 
330                         if (tmp != NULL)        /* database name given */
331                         {
332                                 realname = strdup(tmp + 1);
333                                 *tmp = '\0';
334                         }
335
336                         tmp = strrchr(dbname + offset, ':');
337                         if (tmp != NULL)        /* port number or Unix socket path given */
338                         {
339                                 char       *tmp2;
340
341                                 *tmp = '\0';
342                                 if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
343                                 {
344                                         *tmp2 = '\0';
345                                         host = strdup(tmp + 1);
346                                         if (strncmp(dbname, "unix:", 5) != 0)
347                                         {
348                                                 ECPGlog("connect: socketname %s given for TCP connection in line %d\n", host, lineno);
349                                                 ECPGraise(lineno, ECPG_CONNECT, realname ? realname : "<DEFAULT>");
350                                                 if (host)
351                                                         ECPGfree(host);
352                                                 if (port)
353                                                         ECPGfree(port);
354                                                 if (options)
355                                                         ECPGfree(options);
356                                                 if (realname)
357                                                         ECPGfree(realname);
358                                                 if (dbname)
359                                                         ECPGfree(dbname);
360                                                 return false;
361                                         }
362                                 }
363                                 else
364                                         port = strdup(tmp + 1);
365                         }
366
367                         if (strncmp(dbname, "unix:", 5) == 0)
368                         {
369                                 if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0)
370                                 {
371                                         ECPGlog("connect: non-localhost access via sockets in line %d\n", lineno);
372                                         ECPGraise(lineno, ECPG_CONNECT, realname ? realname : "<DEFAULT>");
373                                         if (host)
374                                                 ECPGfree(host);
375                                         if (port)
376                                                 ECPGfree(port);
377                                         if (options)
378                                                 ECPGfree(options);
379                                         if (realname)
380                                                 ECPGfree(realname);
381                                         if (dbname)
382                                                 ECPGfree(dbname);
383                                         return false;
384                                 }
385                         }
386                         else
387                                 host = strdup(dbname + offset);
388
389                 }
390                 else
391                         realname = strdup(dbname);
392         }
393         else
394                 realname = strdup(dbname);
395
396         /* add connection to our list */
397         if (connection_name != NULL)
398                 this->name = ECPGstrdup(connection_name, lineno);
399         else
400                 this->name = ECPGstrdup(realname, lineno);
401
402         this->cache_head = NULL;
403
404         if (all_connections == NULL)
405                 this->next = NULL;
406         else
407                 this->next = all_connections;
408
409         actual_connection = all_connections = this;
410
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 : "");
417
418         this->connection = PQsetdbLogin(host, port, options, NULL, realname, user, passwd);
419
420         if (PQstatus(this->connection) == CONNECTION_BAD)
421         {
422         const char *errmsg = PQerrorMessage(this->connection);
423         char *db = realname ? realname : "<DEFAULT>";
424
425         set_backend_err(errmsg, lineno);
426                 ecpg_finish(this);
427                 ECPGlog("connect: could not open database %s on %s port %s %s%s%s%s in line %d\n\t%s\n",
428                 db,
429                                 host ? host : "<DEFAULT>",
430                                 port ? port : "<DEFAULT>",
431                                 options ? "with options " : "", options ? options : "",
432                                 user ? "for user " : "", user ? user : "",
433                                 lineno, errmsg);
434         
435                 ECPGraise(lineno, ECPG_CONNECT, db);
436                 if (host)
437                         ECPGfree(host);
438                 if (port)
439                         ECPGfree(port);
440                 if (options)
441                         ECPGfree(options);
442                 if (realname)
443                         ECPGfree(realname);
444                 if (dbname)
445                         ECPGfree(dbname);
446                 return false;
447         }
448
449         if (host)
450                 ECPGfree(host);
451         if (port)
452                 ECPGfree(port);
453         if (options)
454                 ECPGfree(options);
455         if (realname)
456                 ECPGfree(realname);
457         if (dbname)
458                 ECPGfree(dbname);
459
460         this->committed = true;
461         this->autocommit = autocommit;
462
463         PQsetNoticeProcessor(this->connection, &ECPGnoticeProcessor, (void *) this);
464
465         return true;
466 }
467
468 bool
469 ECPGdisconnect(int lineno, const char *connection_name)
470 {
471         struct connection *con;
472
473         if (strcmp(connection_name, "ALL") == 0)
474         {
475                 ECPGinit_sqlca();
476                 for (con = all_connections; con;)
477                 {
478                         struct connection *f = con;
479
480                         con = con->next;
481                         ecpg_finish(f);
482                 }
483         }
484         else
485         {
486                 con = ECPGget_connection(connection_name);
487
488                 if (!ECPGinit(con, connection_name, lineno))
489                         return (false);
490                 else
491                         ecpg_finish(con);
492         }
493
494         return true;
495 }