]> granicus.if.org Git - postgresql/blob - src/interfaces/odbc/connection.c
Version 06-30-0248
[postgresql] / src / interfaces / odbc / connection.c
1
2 /* Module:          connection.c
3  *
4  * Description:     This module contains routines related to 
5  *                  connecting to and disconnecting from the Postgres DBMS.
6  *
7  * Classes:         ConnectionClass (Functions prefix: "CC_")
8  *
9  * API functions:   SQLAllocConnect, SQLConnect, SQLDisconnect, SQLFreeConnect,
10  *                  SQLBrowseConnect(NI)
11  *
12  * Comments:        See "notice.txt" for copyright and license information.
13  *
14  */
15
16 #include "environ.h"
17 #include "connection.h"
18 #include "socket.h"
19 #include "statement.h"
20 #include "qresult.h"
21 #include "lobj.h"
22 #include "dlg_specific.h"
23 #include <stdio.h>
24 #include <string.h>
25
26 #ifndef UNIX
27 #include <odbcinst.h>
28 #endif
29
30 #define STMT_INCREMENT 16  /* how many statement holders to allocate at a time */
31
32 extern GLOBAL_VALUES globals;
33
34 // void CC_test(ConnectionClass *self);
35
36 RETCODE SQL_API SQLAllocConnect(
37                                 HENV     henv,
38                                 HDBC FAR *phdbc)
39 {
40 EnvironmentClass *env = (EnvironmentClass *)henv;
41 ConnectionClass *conn;
42 char *func="SQLAllocConnect";
43
44         conn = CC_Constructor();
45         mylog("**** SQLAllocConnect: henv = %u, conn = %u\n", henv, conn);
46
47     if( ! conn) {
48         env->errormsg = "Couldn't allocate memory for Connection object.";
49         env->errornumber = ENV_ALLOC_ERROR;
50                 *phdbc = SQL_NULL_HDBC;
51                 EN_log_error(func, "", env);
52         return SQL_ERROR;
53     }
54
55     if ( ! EN_add_connection(env, conn)) {
56         env->errormsg = "Maximum number of connections exceeded.";
57         env->errornumber = ENV_ALLOC_ERROR;
58         CC_Destructor(conn);
59                 *phdbc = SQL_NULL_HDBC;
60                 EN_log_error(func, "", env);
61         return SQL_ERROR;
62     }
63
64         *phdbc = (HDBC) conn;
65
66     return SQL_SUCCESS;
67 }
68
69
70 //      -       -       -       -       -       -       -       -       -
71
72 RETCODE SQL_API SQLConnect(
73                            HDBC      hdbc,
74                            UCHAR FAR *szDSN,
75                            SWORD     cbDSN,
76                            UCHAR FAR *szUID,
77                            SWORD     cbUID,
78                            UCHAR FAR *szAuthStr,
79                            SWORD     cbAuthStr)
80 {
81 ConnectionClass *conn = (ConnectionClass *) hdbc;
82 ConnInfo *ci;
83 char *func = "SQLConnect";
84
85         if ( ! conn) {
86                 CC_log_error(func, "", NULL);
87                 return SQL_INVALID_HANDLE;
88         }
89
90         ci = &conn->connInfo;
91
92         make_string(szDSN, cbDSN, ci->dsn);
93
94         /*      get the values for the DSN from the registry */
95         getDSNinfo(ci, CONN_OVERWRITE);
96         
97         /*      override values from DSN info with UID and authStr(pwd) 
98                 This only occurs if the values are actually there.
99         */
100         make_string(szUID, cbUID, ci->username);
101         make_string(szAuthStr, cbAuthStr, ci->password);
102
103         /* fill in any defaults */
104         getDSNdefaults(ci);
105
106         qlog("conn = %u, SQLConnect(DSN='%s', UID='%s', PWD='%s')\n", conn, ci->dsn, ci->username, ci->password);
107
108         if ( CC_connect(conn, FALSE) <= 0) {
109                 //      Error messages are filled in
110                 CC_log_error(func, "Error on CC_connect", conn);
111                 return SQL_ERROR;
112         }
113
114         return SQL_SUCCESS;
115 }
116
117 //      -       -       -       -       -       -       -       -       -
118
119 RETCODE SQL_API SQLBrowseConnect(
120         HDBC      hdbc,
121         UCHAR FAR *szConnStrIn,
122         SWORD     cbConnStrIn,
123         UCHAR FAR *szConnStrOut,
124         SWORD     cbConnStrOutMax,
125         SWORD FAR *pcbConnStrOut)
126 {
127         return SQL_SUCCESS;
128 }
129
130 //      -       -       -       -       -       -       -       -       -
131
132 /* Drop any hstmts open on hdbc and disconnect from database */
133 RETCODE SQL_API SQLDisconnect(
134         HDBC      hdbc)
135 {
136 ConnectionClass *conn = (ConnectionClass *) hdbc;
137 char *func = "SQLDisconnect";
138
139         mylog("**** in SQLDisconnect\n");
140
141         if ( ! conn) {
142                 CC_log_error(func, "", NULL);
143                 return SQL_INVALID_HANDLE;
144         }
145
146         qlog("conn=%u, SQLDisconnect\n", conn);
147
148         if (conn->status == CONN_EXECUTING) {
149                 conn->errornumber = CONN_IN_USE;
150                 conn->errormsg = "A transaction is currently being executed";
151                 CC_log_error(func, "", conn);
152                 return SQL_ERROR;
153         }
154
155         mylog("SQLDisconnect: about to CC_cleanup\n");
156
157         /*  Close the connection and free statements */
158         CC_cleanup(conn);
159
160         mylog("SQLDisconnect: done CC_cleanup\n");
161         mylog("exit SQLDisconnect\n");
162
163         return SQL_SUCCESS;
164 }
165
166
167 //      -       -       -       -       -       -       -       -       -
168
169 RETCODE SQL_API SQLFreeConnect(
170         HDBC      hdbc)
171 {
172 ConnectionClass *conn = (ConnectionClass *) hdbc;
173 char *func = "SQLFreeConnect";
174
175         mylog("**** in SQLFreeConnect: hdbc=%u\n", hdbc);
176
177         if ( ! conn) {
178                 CC_log_error(func, "", NULL);
179                 return SQL_INVALID_HANDLE;
180         }
181
182         /*  Remove the connection from the environment */
183         if ( ! EN_remove_connection(conn->henv, conn)) {
184                 conn->errornumber = CONN_IN_USE;
185                 conn->errormsg = "A transaction is currently being executed";
186                 CC_log_error(func, "", conn);
187                 return SQL_ERROR;
188         }
189
190         CC_Destructor(conn);
191
192         mylog("exit SQLFreeConnect\n");
193
194         return SQL_SUCCESS;
195 }
196
197
198 /*
199 *
200 *       IMPLEMENTATION CONNECTION CLASS
201 *
202 */
203
204 ConnectionClass
205 *CC_Constructor()
206 {
207 ConnectionClass *rv;
208
209     rv = (ConnectionClass *)malloc(sizeof(ConnectionClass));
210
211     if (rv != NULL) {
212
213                 rv->henv = NULL; /* not yet associated with an environment */
214
215         rv->errormsg = NULL;
216         rv->errornumber = 0;
217                 rv->errormsg_created = FALSE;
218
219         rv->status = CONN_NOT_CONNECTED;
220         rv->transact_status = CONN_IN_AUTOCOMMIT; // autocommit by default
221
222                 memset(&rv->connInfo, 0, sizeof(ConnInfo));
223
224                 rv->sock = SOCK_Constructor();
225                 if ( ! rv->sock)
226                         return NULL;
227
228                 rv->stmts = (StatementClass **) malloc( sizeof(StatementClass *) * STMT_INCREMENT);
229                 if ( ! rv->stmts)
230                         return NULL;
231                 memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
232
233                 rv->num_stmts = STMT_INCREMENT;
234
235                 rv->lobj_type = PG_TYPE_LO;
236
237                 rv->ntables = 0;
238                 rv->col_info = NULL;
239
240                 rv->translation_option = 0;
241                 rv->translation_handle = NULL;
242                 rv->DataSourceToDriver = NULL;
243                 rv->DriverToDataSource = NULL;
244     } 
245     return rv;
246 }
247
248
249 char
250 CC_Destructor(ConnectionClass *self)
251 {
252
253         mylog("enter CC_Destructor, self=%u\n", self);
254
255         if (self->status == CONN_EXECUTING)
256                 return 0;
257
258         CC_cleanup(self);   /* cleanup socket and statements */
259
260         mylog("after CC_Cleanup\n");
261
262         /*  Free up statement holders */
263         if (self->stmts) {
264                 free(self->stmts);
265                 self->stmts = NULL;
266         }
267         mylog("after free statement holders\n");
268
269         /*      Free cached table info */
270         if (self->col_info) {
271                 int i;
272                 for (i = 0; i < self->ntables; i++) {
273                         if (self->col_info[i]->result)          /*      Free the SQLColumns result structure */
274                                 QR_Destructor(self->col_info[i]->result);
275
276                         free(self->col_info[i]);
277                 }
278                 free(self->col_info);
279         }
280
281
282         free(self);
283
284         mylog("exit CC_Destructor\n");
285
286         return 1;
287 }
288
289 /*      Return how many cursors are opened on this connection */
290 int
291 CC_cursor_count(ConnectionClass *self)
292 {
293 StatementClass *stmt;
294 int i, count = 0;
295
296         mylog("CC_cursor_count: self=%u, num_stmts=%d\n", self, self->num_stmts);
297
298         for (i = 0; i < self->num_stmts; i++) {
299                 stmt = self->stmts[i];
300                 if (stmt && stmt->result && stmt->result->cursor)
301                         count++;
302         }
303
304         mylog("CC_cursor_count: returning %d\n", count);
305
306         return count;
307 }
308
309 void 
310 CC_clear_error(ConnectionClass *self)
311 {
312         self->errornumber = 0; 
313         self->errormsg = NULL; 
314         self->errormsg_created = FALSE;
315 }
316
317 //      Used to cancel a transaction
318 //      We are almost always in the middle of a transaction.
319 char
320 CC_abort(ConnectionClass *self)
321 {
322 QResultClass *res;
323
324         if ( CC_is_in_trans(self)) {
325                 res = NULL;
326
327                 mylog("CC_abort:  sending ABORT!\n");
328
329                 res = CC_send_query(self, "ABORT", NULL, NULL);
330                 CC_set_no_trans(self);
331
332                 if (res != NULL)
333                         QR_Destructor(res);
334                 else
335                         return FALSE;
336
337         }
338
339         return TRUE;
340 }
341
342 /* This is called by SQLDisconnect also */
343 char
344 CC_cleanup(ConnectionClass *self)
345 {
346 int i;
347 StatementClass *stmt;
348
349         if (self->status == CONN_EXECUTING)
350                 return FALSE;
351
352         mylog("in CC_Cleanup, self=%u\n", self);
353
354         // Cancel an ongoing transaction
355         // We are always in the middle of a transaction,
356         // even if we are in auto commit.
357         if (self->sock)
358                 CC_abort(self);
359
360         mylog("after CC_abort\n");
361
362         /*  This actually closes the connection to the dbase */
363         if (self->sock) {
364             SOCK_Destructor(self->sock);
365                 self->sock = NULL;
366         }
367
368         mylog("after SOCK destructor\n");
369
370         /*  Free all the stmts on this connection */
371         for (i = 0; i < self->num_stmts; i++) {
372                 stmt = self->stmts[i];
373                 if (stmt) {
374
375                         stmt->hdbc = NULL;      /* prevent any more dbase interactions */
376
377                         SC_Destructor(stmt);
378
379                         self->stmts[i] = NULL;
380                 }
381         }
382
383         /*      Check for translation dll */
384         if ( self->translation_handle) {
385                 FreeLibrary (self->translation_handle);
386                 self->translation_handle = NULL;
387         }
388
389         mylog("exit CC_Cleanup\n");
390         return TRUE;
391 }
392
393 int
394 CC_set_translation (ConnectionClass *self)
395 {
396
397         if (self->translation_handle != NULL) {
398                 FreeLibrary (self->translation_handle);
399                 self->translation_handle = NULL;
400         }
401
402         if (self->connInfo.translation_dll[0] == 0)
403                 return TRUE;
404
405         self->translation_option = atoi (self->connInfo.translation_option);
406         self->translation_handle = LoadLibrary (self->connInfo.translation_dll);
407
408         if (self->translation_handle == NULL) {
409                 self->errornumber = CONN_UNABLE_TO_LOAD_DLL;
410                 self->errormsg = "Could not load the translation DLL.";
411                 return FALSE;
412         }
413
414         self->DataSourceToDriver
415          = (DataSourceToDriverProc) GetProcAddress (self->translation_handle,
416                                                                                                 "SQLDataSourceToDriver");
417
418         self->DriverToDataSource
419          = (DriverToDataSourceProc) GetProcAddress (self->translation_handle,
420                                                                                                 "SQLDriverToDataSource");
421
422         if (self->DataSourceToDriver == NULL || self->DriverToDataSource == NULL) {
423                 self->errornumber = CONN_UNABLE_TO_LOAD_DLL;
424                 self->errormsg = "Could not find translation DLL functions.";
425                 return FALSE;
426         }
427
428         return TRUE;
429 }
430
431 char 
432 CC_connect(ConnectionClass *self, char do_password)
433 {
434 StartupPacket sp;
435 StartupPacket6_2 sp62;
436 QResultClass *res;
437 SocketClass *sock;
438 ConnInfo *ci = &(self->connInfo);
439 int areq = -1;
440 int beresp;
441 char msgbuffer[ERROR_MSG_LENGTH]; 
442 char salt[2];
443
444         if ( do_password)
445
446                 sock = self->sock;              /* already connected, just authenticate */
447
448         else {
449
450                 qlog("Global Options: fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
451                         globals.fetch_max, 
452                         globals.socket_buffersize, 
453                         globals.unknown_sizes, 
454                         globals.max_varchar_size, 
455                         globals.max_longvarchar_size);
456                 qlog("                disable_optimizer=%d, unique_index=%d, use_declarefetch=%d\n",
457                         globals.disable_optimizer,
458                         globals.unique_index,
459                         globals.use_declarefetch);
460                 qlog("                text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d\n",
461                         globals.text_as_longvarchar, 
462                         globals.unknowns_as_longvarchar, 
463                         globals.bools_as_char);
464                 qlog("                extra_systable_prefixes='%s', conn_settings='%s'\n",
465                         globals.extra_systable_prefixes, 
466                         globals.conn_settings);
467
468                 if (self->status != CONN_NOT_CONNECTED) {
469                         self->errormsg = "Already connected.";
470                         self->errornumber = CONN_OPENDB_ERROR;
471                         return 0;
472                 }
473
474                 if ( ci->server[0] == '\0' || ci->port[0] == '\0' || ci->database[0] == '\0') {
475                         self->errornumber = CONN_INIREAD_ERROR;
476                         self->errormsg = "Missing server name, port, or database name in call to CC_connect.";
477                         return 0;
478                 }
479
480                 mylog("CC_connect(): DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n",
481                                 ci->dsn, ci->server, ci->port, ci->database, ci->username, ci->password);
482
483                 /* If the socket was closed for some reason (like a SQLDisconnect, but no SQLFreeConnect
484                         then create a socket now.
485                 */
486                 if ( ! self->sock) {
487                         self->sock = SOCK_Constructor();
488                         if ( ! self->sock) {
489                                  self->errornumber = CONNECTION_SERVER_NOT_REACHED;
490                                  self->errormsg = "Could not open a socket to the server";
491                                  return 0;
492                         }
493                 }
494
495                 sock = self->sock;
496
497                 mylog("connecting to the server socket...\n");
498
499                 SOCK_connect_to(sock, (short) atoi(ci->port), ci->server);
500                 if (SOCK_get_errcode(sock) != 0) {
501                         mylog("connection to the server socket failed.\n");
502                         self->errornumber = CONNECTION_SERVER_NOT_REACHED;
503                         self->errormsg = "Could not connect to the server";
504                         return 0;
505                 }
506                 mylog("connection to the server socket succeeded.\n");
507
508                 if ( PROTOCOL_62(ci)) {
509                         sock->reverse = TRUE;           /* make put_int and get_int work for 6.2 */
510
511                         memset(&sp62, 0, sizeof(StartupPacket6_2));
512                         SOCK_put_int(sock, htonl(4+sizeof(StartupPacket6_2)), 4);
513                         sp62.authtype = htonl(NO_AUTHENTICATION);
514                         strncpy(sp62.database, ci->database, PATH_SIZE);
515                         strncpy(sp62.user, ci->username, NAMEDATALEN);
516                         SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2));
517                         SOCK_flush_output(sock);
518                 }
519                 else {
520                         memset(&sp, 0, sizeof(StartupPacket));
521
522                         mylog("sizeof startup packet = %d\n", sizeof(StartupPacket));
523
524                         // Send length of Authentication Block
525                         SOCK_put_int(sock, 4+sizeof(StartupPacket), 4); 
526
527                         sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LATEST);
528                         strncpy(sp.database, ci->database, SM_DATABASE);
529                         strncpy(sp.user, ci->username, SM_USER);
530
531                         SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket));
532                         SOCK_flush_output(sock);
533                 }
534
535                 mylog("sent the authentication block.\n");
536
537                 if (sock->errornumber != 0) {
538                         mylog("couldn't send the authentication block properly.\n");
539                         self->errornumber = CONN_INVALID_AUTHENTICATION;
540                         self->errormsg = "Sending the authentication packet failed";
541                         return 0;
542                 }
543                 mylog("sent the authentication block successfully.\n");
544         }
545
546
547         mylog("gonna do authentication\n");
548
549
550         // ***************************************************
551         //      Now get the authentication request from backend
552         // ***************************************************
553
554         if ( ! PROTOCOL_62(ci)) do {
555
556                 if (do_password)
557                         beresp = 'R';
558                 else
559                         beresp = SOCK_get_char(sock);
560
561                 switch(beresp) {
562                 case 'E':
563                         mylog("auth got 'E'\n");
564
565                         SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
566                         self->errornumber = CONN_INVALID_AUTHENTICATION;
567                         self->errormsg = msgbuffer;
568                         qlog("ERROR from backend during authentication: '%s'\n", self->errormsg);
569                         return 0;
570                 case 'R':
571
572                         if (do_password) {
573                                 mylog("in 'R' do_password\n");
574                                 areq = AUTH_REQ_PASSWORD;
575                                 do_password = FALSE;
576                         }
577                         else {
578                                 mylog("auth got 'R'\n");
579
580                                 areq = SOCK_get_int(sock, 4);
581                                 if (areq == AUTH_REQ_CRYPT)
582                                         SOCK_get_n_char(sock, salt, 2);
583
584                                 mylog("areq = %d\n", areq);
585                         }
586                         switch(areq) {
587                         case AUTH_REQ_OK:
588                                 break;
589
590                         case AUTH_REQ_KRB4:
591                                 self->errormsg = "Kerberos 4 authentication not supported";
592                                 self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
593                                 return 0;
594
595                         case AUTH_REQ_KRB5:
596                                 self->errormsg = "Kerberos 5 authentication not supported";
597                                 self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
598                                 return 0;
599
600                         case AUTH_REQ_PASSWORD:
601                                 mylog("in AUTH_REQ_PASSWORD\n");
602
603                                 if (ci->password[0] == '\0') {
604                                         self->errornumber = CONNECTION_NEED_PASSWORD;
605                                         self->errormsg = "A password is required for this connection.";
606                                         return -1;      /* need password */
607                                 }
608
609                                 mylog("past need password\n");
610
611                                 SOCK_put_int(sock, 4+strlen(ci->password)+1, 4);
612                                 SOCK_put_n_char(sock, ci->password, strlen(ci->password) + 1);
613                                 SOCK_flush_output(sock);
614
615                                 mylog("past flush\n");
616                                 break;
617
618                         case AUTH_REQ_CRYPT:
619                                 self->errormsg = "Password crypt authentication not supported";
620                                 self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
621                                 return 0;
622
623                         default:
624                                 self->errormsg = "Unknown authentication type";
625                                 self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
626                                 return 0;
627                         }
628                         break;
629                 default:
630                         self->errormsg = "Unexpected protocol character during authentication";
631                         self->errornumber = CONN_INVALID_AUTHENTICATION;
632                         return 0;
633                 }
634
635         } while (areq != AUTH_REQ_OK);          
636
637
638         CC_clear_error(self);   /* clear any password error */
639
640         /* send an empty query in order to find out whether the specified */
641         /* database really exists on the server machine */
642         mylog("sending an empty query...\n");
643
644         res = CC_send_query(self, " ", NULL, NULL);
645         if ( res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY) {
646                 mylog("got no result from the empty query.  (probably database does not exist)\n");
647                 self->errornumber = CONNECTION_NO_SUCH_DATABASE;
648                 self->errormsg = "The database does not exist on the server\nor user authentication failed.";
649                 if (res != NULL)
650                         QR_Destructor(res);
651                 return 0;
652         }
653         if (res)
654                 QR_Destructor(res);
655
656         mylog("empty query seems to be OK.\n");
657
658         CC_set_translation (self);
659
660         /**********************************************/
661         /*******   Send any initial settings  *********/
662         /**********************************************/
663
664         /*      Since these functions allocate statements, and since the connection is not
665                 established yet, it would violate odbc state transition rules.  Therefore,
666                 these functions call the corresponding local function instead.
667         */
668         CC_send_settings(self);
669         CC_lookup_lo(self);             /* a hack to get the oid of our large object oid type */
670
671 //      CC_test(self);
672
673         CC_clear_error(self);   /* clear any initial command errors */
674         self->status = CONN_CONNECTED;
675
676         return 1;
677
678 }
679
680 char
681 CC_add_statement(ConnectionClass *self, StatementClass *stmt)
682 {
683 int i;
684
685         mylog("CC_add_statement: self=%u, stmt=%u\n", self, stmt);
686
687         for (i = 0; i < self->num_stmts; i++) {
688                 if ( ! self->stmts[i]) {
689                         stmt->hdbc = self;
690                         self->stmts[i] = stmt;
691                         return TRUE;
692                 }
693         }
694
695         /* no more room -- allocate more memory */
696         self->stmts = (StatementClass **) realloc( self->stmts, sizeof(StatementClass *) * (STMT_INCREMENT + self->num_stmts));
697         if ( ! self->stmts)
698                 return FALSE;
699
700         memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT);
701
702         stmt->hdbc = self;
703         self->stmts[self->num_stmts] = stmt;
704
705         self->num_stmts += STMT_INCREMENT;
706
707         return TRUE;
708 }
709
710 char 
711 CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
712 {
713 int i;
714
715         for (i = 0; i < self->num_stmts; i++) {
716                 if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING) {
717                         self->stmts[i] = NULL;
718                         return TRUE;
719                 }
720         }
721
722         return FALSE;
723 }
724
725 /*      Create a more informative error message by concatenating the connection
726         error message with its socket error message.
727 */
728 char *
729 CC_create_errormsg(ConnectionClass *self)
730 {
731 SocketClass *sock = self->sock;
732 int pos;
733 static char msg[4096];
734
735         mylog("enter CC_create_errormsg\n");
736
737         msg[0] = '\0';
738
739         if (self->errormsg)
740                 strcpy(msg, self->errormsg);
741
742         mylog("msg = '%s'\n", msg);
743
744         if (sock && sock->errormsg && sock->errormsg[0] != '\0') {
745                 pos = strlen(msg);
746                 sprintf(&msg[pos], ";\n%s", sock->errormsg);
747         }
748
749         mylog("exit CC_create_errormsg\n");
750         return msg;
751 }
752
753
754 char 
755 CC_get_error(ConnectionClass *self, int *number, char **message)
756 {
757 int rv;
758
759         mylog("enter CC_get_error\n");
760
761         //      Create a very informative errormsg if it hasn't been done yet.
762         if ( ! self->errormsg_created) {
763                 self->errormsg = CC_create_errormsg(self);
764                 self->errormsg_created = TRUE;
765         }
766
767         if (self->errornumber) {
768                 *number = self->errornumber;
769                 *message = self->errormsg;
770         }
771         rv = (self->errornumber != 0);
772
773         self->errornumber = 0;          // clear the error
774
775         mylog("exit CC_get_error\n");
776
777         return rv;
778 }
779
780
781 /*      The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
782         the same existing QResultClass (this occurs when the tuple cache is depleted and
783         needs to be re-filled).
784
785         The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
786         (i.e., C3326857) for SQL select statements.  This cursor is then used in future 
787         'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
788 */
789 QResultClass *
790 CC_send_query(ConnectionClass *self, char *query, QResultClass *result_in, char *cursor)
791 {
792 QResultClass *res = NULL;
793 char id, swallow;
794 SocketClass *sock = self->sock;
795 static char msgbuffer[MAX_MESSAGE_LEN+1];
796 char cmdbuffer[MAX_MESSAGE_LEN+1];      // QR_set_command() dups this string so dont need static
797
798
799         mylog("send_query(): conn=%u, query='%s'\n", self, query);
800         qlog("conn=%u, query='%s'\n", self, query);
801
802         // Indicate that we are sending a query to the backend
803         if(strlen(query) > MAX_MESSAGE_LEN-2) {
804                 self->errornumber = CONNECTION_MSG_TOO_LONG;
805                 self->errormsg = "Query string is too long";
806                 return NULL;
807         }
808
809         if ((NULL == query) || (query[0] == '\0'))
810                 return NULL;
811
812         if (SOCK_get_errcode(sock) != 0) {
813                 self->errornumber = CONNECTION_COULD_NOT_SEND;
814                 self->errormsg = "Could not send Query to backend";
815                 CC_set_no_trans(self);
816                 return NULL;
817         }
818
819         SOCK_put_char(sock, 'Q');
820         if (SOCK_get_errcode(sock) != 0) {
821                 self->errornumber = CONNECTION_COULD_NOT_SEND;
822                 self->errormsg = "Could not send Query to backend";
823                 CC_set_no_trans(self);
824                 return NULL;
825         }
826
827         SOCK_put_string(sock, query);
828         SOCK_flush_output(sock);
829
830         if (SOCK_get_errcode(sock) != 0) {
831                 self->errornumber = CONNECTION_COULD_NOT_SEND;
832                 self->errormsg = "Could not send Query to backend";
833                 CC_set_no_trans(self);
834                 return NULL;
835         }
836
837         mylog("send_query: done sending query\n");
838
839         while(1) {
840                 /* what type of message is comming now ? */
841                 id = SOCK_get_char(sock);
842
843                 if ((SOCK_get_errcode(sock) != 0) || (id == EOF)) {
844                         self->errornumber = CONNECTION_NO_RESPONSE;
845                         self->errormsg = "No response from the backend";
846                         if (res)
847                                 QR_Destructor(res);
848
849                         mylog("send_query: 'id' - %s\n", self->errormsg);
850                         CC_set_no_trans(self);
851                         return NULL;
852                 }
853
854                 mylog("send_query: got id = '%c'\n", id);
855
856                 switch (id) {
857                 case 'A' : /* Asynchronous Messages are ignored */
858                         (void)SOCK_get_int(sock, 4); /* id of notification */
859                         SOCK_get_string(sock, msgbuffer, MAX_MESSAGE_LEN);
860                         /* name of the relation the message comes from */
861                         break;
862                 case 'C' : /* portal query command, no tuples returned */
863                         /* read in the return message from the backend */
864                         SOCK_get_string(sock, cmdbuffer, MAX_MESSAGE_LEN);
865                         if (SOCK_get_errcode(sock) != 0) {
866                                 self->errornumber = CONNECTION_NO_RESPONSE;
867                                 self->errormsg = "No response from backend while receiving a portal query command";
868                                 mylog("send_query: 'C' - %s\n", self->errormsg);
869                                 CC_set_no_trans(self);
870                                 return NULL;
871                         } else {
872
873                                 char clear = 0;
874
875                                 mylog("send_query: ok - 'C' - %s\n", cmdbuffer);
876
877                                 if (res == NULL)        /* allow for "show" style notices */
878                                         res = QR_Constructor();
879
880                                 mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer);
881
882                                 /*      Only save the first command */
883                                 QR_set_status(res, PGRES_COMMAND_OK);
884                                 QR_set_command(res, cmdbuffer);
885
886                                 /* (Quotation from the original comments)
887                                         since backend may produze more than one result for some commands
888                                         we need to poll until clear
889                                         so we send an empty query, and keep reading out of the pipe
890                                         until an 'I' is received
891                                 */
892
893
894                                 SOCK_put_string(sock, "Q ");
895                                 SOCK_flush_output(sock);
896                                 while(!clear) {
897                                         SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
898                                         mylog("send_query: read command '%s'\n", cmdbuffer);
899                                         clear = (cmdbuffer[0] == 'I');
900
901                                         if (cmdbuffer[0] == 'N')
902                                                 qlog("NOTICE from backend during send_query: '%s'\n", &cmdbuffer[1]);
903                                         else if (cmdbuffer[0] == 'E')
904                                                 qlog("ERROR from backend during send_query: '%s'\n", &cmdbuffer[1]);
905                                         else if (cmdbuffer[0] == 'C')
906                                                 qlog("Command response: '%s'\n", &cmdbuffer[1]);
907                                 }
908
909                                 mylog("send_query: returning res = %u\n", res);
910                                 return res;
911                         }
912                 case 'N' : /* NOTICE: */
913                         SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
914
915                         res = QR_Constructor();
916                         QR_set_status(res, PGRES_NONFATAL_ERROR);
917                         QR_set_notice(res, cmdbuffer);  /* will dup this string */
918
919                         mylog("~~~ NOTICE: '%s'\n", cmdbuffer);
920                         qlog("NOTICE from backend during send_query: '%s'\n", cmdbuffer);
921
922                         continue;               // dont return a result -- continue reading
923
924                 case 'I' : /* The server sends an empty query */
925                                 /* There is a closing '\0' following the 'I', so we eat it */
926                         swallow = SOCK_get_char(sock);
927                         if ((swallow != '\0') || SOCK_get_errcode(sock) != 0) {
928                                 self->errornumber = CONNECTION_BACKEND_CRAZY;
929                                 self->errormsg = "Unexpected protocol character from backend";
930                                 res = QR_Constructor();
931                                 QR_set_status(res, PGRES_FATAL_ERROR);
932                                 return res;
933                         } else {
934                                 /* We return the empty query */
935                                 res = QR_Constructor();
936                                 QR_set_status(res, PGRES_EMPTY_QUERY);
937                                 return res;
938                         }
939                         break;
940                 case 'E' : 
941                         SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
942
943                         /*      Remove a newline */
944                         if (msgbuffer[0] != '\0' && msgbuffer[strlen(msgbuffer)-1] == '\n')
945                                 msgbuffer[strlen(msgbuffer)-1] = '\0';
946
947                         self->errormsg = msgbuffer;
948
949                         mylog("send_query: 'E' - %s\n", self->errormsg);
950                         qlog("ERROR from backend during send_query: '%s'\n", self->errormsg);
951
952                         if ( ! strncmp(self->errormsg, "FATAL", 5)) {
953                                 self->errornumber = CONNECTION_SERVER_REPORTED_ERROR;
954                                 CC_set_no_trans(self);
955                         }
956                         else
957                                 self->errornumber = CONNECTION_SERVER_REPORTED_WARNING;
958
959                         return NULL;
960
961                 case 'P' : /* get the Portal name */
962                         SOCK_get_string(sock, msgbuffer, MAX_MESSAGE_LEN);
963                         break;
964                 case 'T': /* Tuple results start here */
965                         if (result_in == NULL) {
966                                 result_in = QR_Constructor();
967                                 mylog("send_query: 'T' no result_in: res = %u\n", result_in);
968                                 if ( ! result_in) {
969                                         self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
970                                         self->errormsg = "Could not create result info in send_query.";
971                                         return NULL;
972                                 }
973
974                                 if ( ! QR_fetch_tuples(result_in, self, cursor)) {
975                                         self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
976                                         self->errormsg = QR_get_message(result_in);
977                                         return NULL;
978                                 }
979                         }
980                         else {  // next fetch, so reuse an existing result
981                                 if ( ! QR_fetch_tuples(result_in, NULL, NULL)) {
982                                         self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
983                                         self->errormsg = QR_get_message(result_in);
984                                         return NULL;
985                                 }
986                         }
987
988                         return result_in;
989                 case 'D': /* Copy in command began successfully */
990                         res = QR_Constructor();
991                         QR_set_status(res, PGRES_COPY_IN);
992                         return res;
993                 case 'B': /* Copy out command began successfully */
994                         res = QR_Constructor();
995                         QR_set_status(res, PGRES_COPY_OUT);
996                         return res;
997                 default:
998                         self->errornumber = CONNECTION_BACKEND_CRAZY;
999                         self->errormsg = "Unexpected protocol character from backend";
1000                         CC_set_no_trans(self);
1001
1002                         mylog("send_query: error - %s\n", self->errormsg);
1003                         return NULL;
1004                 }
1005         }
1006 }
1007
1008 int
1009 CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
1010 {
1011 char id, c, done;
1012 SocketClass *sock = self->sock;
1013 static char msgbuffer[MAX_MESSAGE_LEN+1];
1014 int i;
1015
1016         mylog("send_function(): conn=%u, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);
1017 //      qlog("conn=%u, func=%d\n", self, fnid);
1018
1019         if (SOCK_get_errcode(sock) != 0) {
1020                 self->errornumber = CONNECTION_COULD_NOT_SEND;
1021                 self->errormsg = "Could not send function to backend";
1022                 CC_set_no_trans(self);
1023                 return FALSE;
1024         }
1025
1026         SOCK_put_string(sock, "F ");
1027         if (SOCK_get_errcode(sock) != 0) {
1028                 self->errornumber = CONNECTION_COULD_NOT_SEND;
1029                 self->errormsg = "Could not send function to backend";
1030                 CC_set_no_trans(self);
1031                 return FALSE;
1032         }
1033
1034         SOCK_put_int(sock, fnid, 4); 
1035         SOCK_put_int(sock, nargs, 4); 
1036
1037
1038         mylog("send_function: done sending function\n");
1039
1040         for (i = 0; i < nargs; ++i) {
1041
1042                 mylog("  arg[%d]: len = %d, isint = %d, integer = %d, ptr = %u\n", 
1043                         i, args[i].len, args[i].isint, args[i].u.integer, args[i].u.ptr);
1044
1045                 SOCK_put_int(sock, args[i].len, 4);
1046                 if (args[i].isint) 
1047                         SOCK_put_int(sock, args[i].u.integer, 4);
1048                 else
1049                         SOCK_put_n_char(sock, (char *) args[i].u.ptr, args[i].len);
1050
1051
1052         }
1053
1054         mylog("    done sending args\n");
1055
1056         SOCK_flush_output(sock);
1057         mylog("  after flush output\n");
1058
1059         done = FALSE;
1060         while ( ! done) {
1061                 id = SOCK_get_char(sock);
1062                 mylog("   got id = %c\n", id);
1063
1064                 switch(id) {
1065                 case 'V':
1066                         done = TRUE;
1067                         break;          /* ok */
1068
1069                 case 'N':
1070                         SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
1071                         mylog("send_function(V): 'N' - %s\n", msgbuffer);
1072                         /*      continue reading */
1073                         break;
1074
1075                 case 'E':
1076                         SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
1077                         self->errormsg = msgbuffer;
1078
1079                         mylog("send_function(V): 'E' - %s\n", self->errormsg);
1080                         qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
1081
1082                         return FALSE;
1083
1084                 default:
1085                         self->errornumber = CONNECTION_BACKEND_CRAZY;
1086                         self->errormsg = "Unexpected protocol character from backend";
1087                         CC_set_no_trans(self);
1088
1089                         mylog("send_function: error - %s\n", self->errormsg);
1090                         return FALSE;
1091                 }
1092         }
1093
1094         id = SOCK_get_char(sock);
1095         for (;;) {
1096                 switch (id) {
1097                 case 'G':       /* function returned properly */
1098                         mylog("  got G!\n");
1099
1100                         *actual_result_len = SOCK_get_int(sock, 4);
1101                         mylog("  actual_result_len = %d\n", *actual_result_len);
1102
1103                         if (result_is_int)
1104                                 *((int *) result_buf) = SOCK_get_int(sock, 4);
1105                         else
1106                                 SOCK_get_n_char(sock, (char *) result_buf, *actual_result_len);
1107
1108                         mylog("  after get result\n");
1109
1110                         c = SOCK_get_char(sock);        /* get the last '0' */
1111
1112                         mylog("   after get 0\n");
1113
1114                         return TRUE;
1115
1116                 case 'E':
1117                         SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
1118                         self->errormsg = msgbuffer;
1119
1120                         mylog("send_function(G): 'E' - %s\n", self->errormsg);
1121                         qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
1122
1123                         return FALSE;
1124
1125                 case 'N':
1126                         SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
1127
1128                         mylog("send_function(G): 'N' - %s\n", msgbuffer);
1129                         qlog("NOTICE from backend during send_function: '%s'\n", msgbuffer);
1130
1131                         continue;               // dont return a result -- continue reading
1132
1133                 case '0':       /* empty result */
1134                         return TRUE;
1135
1136                 default:
1137                         self->errornumber = CONNECTION_BACKEND_CRAZY;
1138                         self->errormsg = "Unexpected protocol character from backend";
1139                         CC_set_no_trans(self);
1140
1141                         mylog("send_function: error - %s\n", self->errormsg);
1142                         return FALSE;
1143                 }
1144         }
1145 }
1146
1147
1148 char
1149 CC_send_settings(ConnectionClass *self)
1150 {
1151 char ini_query[MAX_MESSAGE_LEN];
1152 ConnInfo *ci = &(self->connInfo);
1153 // QResultClass *res;
1154 HSTMT hstmt;
1155 StatementClass *stmt;
1156 RETCODE result;
1157 SWORD cols = 0;
1158
1159 /*      This function must use the local odbc API functions since the odbc state 
1160         has not transitioned to "connected" yet.
1161 */
1162         result = _SQLAllocStmt( self, &hstmt);
1163         if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1164                 return FALSE;
1165         }
1166         stmt = (StatementClass *) hstmt;
1167
1168         ini_query[0] = '\0';
1169
1170         /*      Set the Datestyle to the format the driver expects it to be in */
1171         sprintf(ini_query, "set DateStyle to 'ISO'");
1172
1173         /*      Disable genetic optimizer based on global flag */
1174         if (globals.disable_optimizer)
1175                 sprintf(&ini_query[strlen(ini_query)], "%sset geqo to 'OFF'", 
1176                         ini_query[0] != '\0' ? "; " : "");
1177
1178         /*      Global settings */
1179         if (globals.conn_settings[0] != '\0')
1180                 sprintf(&ini_query[strlen(ini_query)], "%s%s", 
1181                         ini_query[0] != '\0' ? "; " : "",
1182                         globals.conn_settings);
1183
1184         /*      Per Datasource settings */
1185         if (ci->conn_settings[0] != '\0')
1186                 sprintf(&ini_query[strlen(ini_query)], "%s%s",
1187                         ini_query[0] != '\0' ? "; " : "",
1188                         ci->conn_settings);
1189
1190         if (ini_query[0] != '\0') {
1191                 mylog("Sending Initial Connection query: '%s'\n", ini_query);
1192
1193                 result = _SQLExecDirect(hstmt, ini_query, SQL_NTS);
1194                 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1195                         _SQLFreeStmt(hstmt, SQL_DROP);
1196                         return FALSE;
1197                 }
1198
1199                 _SQLFreeStmt(hstmt, SQL_DROP);
1200
1201         }
1202         return TRUE;
1203 }
1204
1205 /*      This function is just a hack to get the oid of our Large Object oid type.
1206         If a real Large Object oid type is made part of Postgres, this function
1207         will go away and the define 'PG_TYPE_LO' will be updated.
1208 */
1209 void
1210 CC_lookup_lo(ConnectionClass *self) 
1211 {
1212 HSTMT hstmt;
1213 StatementClass *stmt;
1214 RETCODE result;
1215
1216 /*      This function must use the local odbc API functions since the odbc state 
1217         has not transitioned to "connected" yet.
1218 */
1219         result = _SQLAllocStmt( self, &hstmt);
1220         if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1221                 return;
1222         }
1223         stmt = (StatementClass *) hstmt;
1224
1225         result = _SQLExecDirect(hstmt, "select oid from pg_type where typname='" \
1226                 PG_TYPE_LO_NAME \
1227                 "'", SQL_NTS);
1228         if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1229                 _SQLFreeStmt(hstmt, SQL_DROP);
1230                 return;
1231         }
1232
1233         result = _SQLFetch(hstmt);
1234         if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1235                 _SQLFreeStmt(hstmt, SQL_DROP);
1236                 return;
1237         }
1238
1239         result = _SQLGetData(hstmt, 1, SQL_C_SLONG, &self->lobj_type, sizeof(self->lobj_type), NULL);
1240         if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1241                 _SQLFreeStmt(hstmt, SQL_DROP);
1242                 return;
1243         }
1244
1245         mylog("Got the large object oid: %d\n", self->lobj_type);
1246         qlog("    [ Large Object oid = %d ]\n", self->lobj_type);
1247
1248         result = _SQLFreeStmt(hstmt, SQL_DROP);
1249 }
1250
1251 void
1252 CC_log_error(char *func, char *desc, ConnectionClass *self)
1253 {
1254         if (self) {
1255                 qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
1256                 qlog("            ------------------------------------------------------------\n");
1257                 qlog("            henv=%u, conn=%u, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts);
1258                 qlog("            sock=%u, stmts=%u, lobj_type=%d\n", self->sock, self->stmts, self->lobj_type);
1259
1260                 qlog("            ---------------- Socket Info -------------------------------\n");
1261                 if (self->sock) {
1262                 SocketClass *sock = self->sock;
1263                 qlog("            socket=%d, reverse=%d, errornumber=%d, errormsg='%s'\n", sock->socket, sock->reverse, sock->errornumber, sock->errormsg);
1264                 qlog("            buffer_in=%u, buffer_out=%u\n", sock->buffer_in, sock->buffer_out);
1265                 qlog("            buffer_filled_in=%d, buffer_filled_out=%d, buffer_read_in=%d\n", sock->buffer_filled_in, sock->buffer_filled_out, sock->buffer_read_in);
1266                 }
1267         }
1268         else
1269                 qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
1270 }
1271
1272 /*
1273 void
1274 CC_test(ConnectionClass *self)
1275 {
1276 HSTMT hstmt1;
1277 RETCODE result;
1278 SDWORD pcbValue;
1279 UDWORD pcrow;
1280 UWORD rgfRowStatus;
1281 char name[255], type[255];
1282 SDWORD namelen, typelen;
1283 SWORD cols;
1284
1285         result = SQLAllocStmt( self, &hstmt1);
1286         if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1287                 return;
1288         }
1289
1290         result = SQLTables(hstmt1, "", SQL_NTS, "", SQL_NTS, "", SQL_NTS, "", SQL_NTS);
1291         qlog("SQLTables result = %d\n", result);
1292
1293         result = SQLNumResultCols(hstmt1, &cols);
1294         qlog("cols SQLTables result = %d\n", result);
1295
1296         result = SQLBindCol(hstmt1, 3, SQL_C_CHAR, name, sizeof(name), &namelen);
1297         qlog("bind result = %d\n", result);
1298
1299         result = SQLBindCol(hstmt1, 4, SQL_C_CHAR, type, sizeof(type), &typelen);
1300         qlog("bind result = %d\n", result);
1301         
1302         result = SQLFetch(hstmt1);
1303         qlog("SQLFetch result = %d\n", result);
1304         while (result != SQL_NO_DATA_FOUND) {
1305                 qlog("fetch on stmt1: result=%d, namelen=%d: name='%s', typelen=%d, type='%s'\n", result, namelen, name, typelen, type);
1306
1307                 result = SQLFetch(hstmt1);
1308         }
1309         qlog("SQLFetch result = %d\n", result);
1310         SQLFreeStmt(hstmt1, SQL_DROP);
1311
1312 }
1313 */
1314
1315