~ubuntu-branches/ubuntu/natty/psqlodbc/natty

« back to all changes in this revision

Viewing changes to connection.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-05-13 10:47:36 UTC
  • Revision ID: james.westby@ubuntu.com-20040513104736-a530gmn0p3knep89
Tags: upstream-07.03.0200
ImportĀ upstreamĀ versionĀ 07.03.0200

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/* Multibyte support    Eiji Tokuya 2001-03-15 */
 
16
 
 
17
#include "connection.h"
 
18
 
 
19
#include <stdio.h>
 
20
#include <string.h>
 
21
#include <ctype.h>
 
22
#ifndef WIN32
 
23
#include <errno.h>
 
24
#endif /* WIN32 */
 
25
 
 
26
#include "environ.h"
 
27
#include "socket.h"
 
28
#include "statement.h"
 
29
#include "qresult.h"
 
30
#include "lobj.h"
 
31
#include "dlg_specific.h"
 
32
 
 
33
#include "multibyte.h"
 
34
 
 
35
#include "pgapifunc.h"
 
36
#include "md5.h"
 
37
 
 
38
#define STMT_INCREMENT 16               /* how many statement holders to allocate
 
39
                                                                 * at a time */
 
40
 
 
41
#define PRN_NULLCHECK
 
42
 
 
43
extern GLOBAL_VALUES globals;
 
44
 
 
45
 
 
46
RETCODE         SQL_API
 
47
PGAPI_AllocConnect(
 
48
                                   HENV henv,
 
49
                                   HDBC FAR * phdbc)
 
50
{
 
51
        EnvironmentClass *env = (EnvironmentClass *) henv;
 
52
        ConnectionClass *conn;
 
53
        CSTR func = "PGAPI_AllocConnect";
 
54
 
 
55
        mylog("%s: entering...\n", func);
 
56
 
 
57
        conn = CC_Constructor();
 
58
        mylog("**** %s: henv = %u, conn = %u\n", func, henv, conn);
 
59
 
 
60
        if (!conn)
 
61
        {
 
62
                env->errormsg = "Couldn't allocate memory for Connection object.";
 
63
                env->errornumber = ENV_ALLOC_ERROR;
 
64
                *phdbc = SQL_NULL_HDBC;
 
65
                EN_log_error(func, "", env);
 
66
                return SQL_ERROR;
 
67
        }
 
68
 
 
69
        if (!EN_add_connection(env, conn))
 
70
        {
 
71
                env->errormsg = "Maximum number of connections exceeded.";
 
72
                env->errornumber = ENV_ALLOC_ERROR;
 
73
                CC_Destructor(conn);
 
74
                *phdbc = SQL_NULL_HDBC;
 
75
                EN_log_error(func, "", env);
 
76
                return SQL_ERROR;
 
77
        }
 
78
 
 
79
        if (phdbc)
 
80
                *phdbc = (HDBC) conn;
 
81
 
 
82
        return SQL_SUCCESS;
 
83
}
 
84
 
 
85
 
 
86
RETCODE         SQL_API
 
87
PGAPI_Connect(
 
88
                          HDBC hdbc,
 
89
                          UCHAR FAR * szDSN,
 
90
                          SWORD cbDSN,
 
91
                          UCHAR FAR * szUID,
 
92
                          SWORD cbUID,
 
93
                          UCHAR FAR * szAuthStr,
 
94
                          SWORD cbAuthStr)
 
95
{
 
96
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
97
        ConnInfo   *ci;
 
98
        CSTR func = "PGAPI_Connect";
 
99
 
 
100
        mylog("%s: entering...\n", func);
 
101
 
 
102
        if (!conn)
 
103
        {
 
104
                CC_log_error(func, "", NULL);
 
105
                return SQL_INVALID_HANDLE;
 
106
        }
 
107
 
 
108
        ci = &conn->connInfo;
 
109
 
 
110
        make_string(szDSN, cbDSN, ci->dsn);
 
111
 
 
112
        /* get the values for the DSN from the registry */
 
113
        memcpy(&ci->drivers, &globals, sizeof(globals));
 
114
        getDSNinfo(ci, CONN_OVERWRITE);
 
115
        logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
 
116
        /* initialize pg_version from connInfo.protocol    */
 
117
        CC_initialize_pg_version(conn);
 
118
 
 
119
        /*
 
120
         * override values from DSN info with UID and authStr(pwd) This only
 
121
         * occurs if the values are actually there.
 
122
         */
 
123
        make_string(szUID, cbUID, ci->username);
 
124
        make_string(szAuthStr, cbAuthStr, ci->password);
 
125
 
 
126
        /* fill in any defaults */
 
127
        getDSNdefaults(ci);
 
128
 
 
129
        qlog("conn = %u, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, ci->password ? "xxxxx" : "");
 
130
 
 
131
        if (CC_connect(conn, AUTH_REQ_OK, NULL) <= 0)
 
132
        {
 
133
                /* Error messages are filled in */
 
134
                CC_log_error(func, "Error on CC_connect", conn);
 
135
                return SQL_ERROR;
 
136
        }
 
137
 
 
138
        mylog("%s: returning...\n", func);
 
139
 
 
140
        return SQL_SUCCESS;
 
141
}
 
142
 
 
143
 
 
144
RETCODE         SQL_API
 
145
PGAPI_BrowseConnect(
 
146
                                        HDBC hdbc,
 
147
                                        UCHAR FAR * szConnStrIn,
 
148
                                        SWORD cbConnStrIn,
 
149
                                        UCHAR FAR * szConnStrOut,
 
150
                                        SWORD cbConnStrOutMax,
 
151
                                        SWORD FAR * pcbConnStrOut)
 
152
{
 
153
        CSTR func = "PGAPI_BrowseConnect";
 
154
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
155
 
 
156
        mylog("%s: entering...\n", func);
 
157
 
 
158
        CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "not implemented");
 
159
        CC_log_error(func, "Function not implemented", conn);
 
160
        return SQL_ERROR;
 
161
}
 
162
 
 
163
 
 
164
/* Drop any hstmts open on hdbc and disconnect from database */
 
165
RETCODE         SQL_API
 
166
PGAPI_Disconnect(
 
167
                                 HDBC hdbc)
 
168
{
 
169
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
170
        CSTR func = "PGAPI_Disconnect";
 
171
 
 
172
 
 
173
        mylog("%s: entering...\n", func);
 
174
 
 
175
        if (!conn)
 
176
        {
 
177
                CC_log_error(func, "", NULL);
 
178
                return SQL_INVALID_HANDLE;
 
179
        }
 
180
 
 
181
        qlog("conn=%u, %s\n", conn, func);
 
182
 
 
183
        if (conn->status == CONN_EXECUTING)
 
184
        {
 
185
                CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed");
 
186
                CC_log_error(func, "", conn);
 
187
                return SQL_ERROR;
 
188
        }
 
189
 
 
190
        logs_on_off(-1, conn->connInfo.drivers.debug, conn->connInfo.drivers.commlog);
 
191
        mylog("%s: about to CC_cleanup\n", func);
 
192
 
 
193
        /* Close the connection and free statements */
 
194
        CC_cleanup(conn);
 
195
 
 
196
        mylog("%s: done CC_cleanup\n", func);
 
197
        mylog("%s: returning...\n", func);
 
198
 
 
199
        return SQL_SUCCESS;
 
200
}
 
201
 
 
202
 
 
203
RETCODE         SQL_API
 
204
PGAPI_FreeConnect(
 
205
                                  HDBC hdbc)
 
206
{
 
207
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
208
        CSTR func = "PGAPI_FreeConnect";
 
209
 
 
210
        mylog("%s: entering...\n", func);
 
211
        mylog("**** in %s: hdbc=%u\n", func, hdbc);
 
212
 
 
213
        if (!conn)
 
214
        {
 
215
                CC_log_error(func, "", NULL);
 
216
                return SQL_INVALID_HANDLE;
 
217
        }
 
218
 
 
219
        /* Remove the connection from the environment */
 
220
        if (!EN_remove_connection(conn->henv, conn))
 
221
        {
 
222
                CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed");
 
223
                CC_log_error(func, "", conn);
 
224
                return SQL_ERROR;
 
225
        }
 
226
 
 
227
        CC_Destructor(conn);
 
228
 
 
229
        mylog("%s: returning...\n", func);
 
230
 
 
231
        return SQL_SUCCESS;
 
232
}
 
233
 
 
234
 
 
235
void
 
236
CC_conninfo_init(ConnInfo *conninfo)
 
237
{
 
238
                memset(conninfo, 0, sizeof(ConnInfo));
 
239
                conninfo->disallow_premature = -1;
 
240
                conninfo->allow_keyset = -1;
 
241
                conninfo->lf_conversion = -1;
 
242
                conninfo->true_is_minus1 = -1;
 
243
                conninfo->int8_as = -101;
 
244
                conninfo->bytea_as_longvarbinary = -1;
 
245
                conninfo->use_server_side_prepare = -1;
 
246
                memcpy(&(conninfo->drivers), &globals, sizeof(globals));
 
247
}
 
248
/*
 
249
 *              IMPLEMENTATION CONNECTION CLASS
 
250
 */
 
251
ConnectionClass *
 
252
CC_Constructor()
 
253
{
 
254
        ConnectionClass *rv;
 
255
 
 
256
        rv = (ConnectionClass *) malloc(sizeof(ConnectionClass));
 
257
 
 
258
        if (rv != NULL)
 
259
        {
 
260
                rv->henv = NULL;                /* not yet associated with an environment */
 
261
 
 
262
                rv->__error_message = NULL;
 
263
                rv->__error_number = 0;
 
264
                rv->errormsg_created = FALSE;
 
265
 
 
266
                rv->status = CONN_NOT_CONNECTED;
 
267
                rv->transact_status = CONN_IN_AUTOCOMMIT;               /* autocommit by default */
 
268
 
 
269
                CC_conninfo_init(&(rv->connInfo));
 
270
                rv->sock = SOCK_Constructor(rv);
 
271
                if (!rv->sock)
 
272
                        return NULL;
 
273
 
 
274
                rv->stmts = (StatementClass **) malloc(sizeof(StatementClass *) * STMT_INCREMENT);
 
275
                if (!rv->stmts)
 
276
                        return NULL;
 
277
                memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
 
278
 
 
279
                rv->num_stmts = STMT_INCREMENT;
 
280
 
 
281
                rv->lobj_type = PG_TYPE_LO_UNDEFINED;
 
282
 
 
283
                rv->ntables = 0;
 
284
                rv->col_info = NULL;
 
285
 
 
286
                rv->translation_option = 0;
 
287
                rv->translation_handle = NULL;
 
288
                rv->DataSourceToDriver = NULL;
 
289
                rv->DriverToDataSource = NULL;
 
290
                rv->driver_version = ODBCVER;
 
291
                memset(rv->pg_version, 0, sizeof(rv->pg_version));
 
292
                rv->pg_version_number = .0;
 
293
                rv->pg_version_major = 0;
 
294
                rv->pg_version_minor = 0;
 
295
                rv->ms_jet = 0;
 
296
                rv->unicode = 0;
 
297
                rv->result_uncommitted = 0;
 
298
                rv->schema_support = 0;
 
299
                rv->isolation = SQL_TXN_READ_COMMITTED;
 
300
                rv->client_encoding = NULL;
 
301
                rv->server_encoding = NULL;
 
302
                rv->current_schema = NULL;
 
303
 
 
304
 
 
305
                /* Initialize statement options to defaults */
 
306
                /* Statements under this conn will inherit these options */
 
307
 
 
308
                InitializeStatementOptions(&rv->stmtOptions);
 
309
                InitializeARDFields(&rv->ardOptions);
 
310
                InitializeAPDFields(&rv->apdOptions);
 
311
                INIT_CONN_CS(rv);
 
312
        }
 
313
        return rv;
 
314
}
 
315
 
 
316
 
 
317
char
 
318
CC_Destructor(ConnectionClass *self)
 
319
{
 
320
        mylog("enter CC_Destructor, self=%u\n", self);
 
321
 
 
322
        if (self->status == CONN_EXECUTING)
 
323
                return 0;
 
324
 
 
325
        CC_cleanup(self);                       /* cleanup socket and statements */
 
326
 
 
327
        mylog("after CC_Cleanup\n");
 
328
 
 
329
        /* Free up statement holders */
 
330
        if (self->stmts)
 
331
        {
 
332
                free(self->stmts);
 
333
                self->stmts = NULL;
 
334
        }
 
335
        mylog("after free statement holders\n");
 
336
 
 
337
        if (self->__error_message)
 
338
                free(self->__error_message);
 
339
        DELETE_CONN_CS(self);
 
340
        free(self);
 
341
 
 
342
        mylog("exit CC_Destructor\n");
 
343
 
 
344
        return 1;
 
345
}
 
346
 
 
347
 
 
348
/*      Return how many cursors are opened on this connection */
 
349
int
 
350
CC_cursor_count(ConnectionClass *self)
 
351
{
 
352
        StatementClass *stmt;
 
353
        int                     i,
 
354
                                count = 0;
 
355
 
 
356
        mylog("CC_cursor_count: self=%u, num_stmts=%d\n", self, self->num_stmts);
 
357
 
 
358
        for (i = 0; i < self->num_stmts; i++)
 
359
        {
 
360
                stmt = self->stmts[i];
 
361
                if (stmt && SC_get_Result(stmt) && SC_get_Result(stmt)->cursor)
 
362
                        count++;
 
363
        }
 
364
 
 
365
        mylog("CC_cursor_count: returning %d\n", count);
 
366
 
 
367
        return count;
 
368
}
 
369
 
 
370
 
 
371
void
 
372
CC_clear_error(ConnectionClass *self)
 
373
{
 
374
        self->__error_number = 0;
 
375
        if (self->__error_message)
 
376
                free(self->__error_message);
 
377
        self->__error_message = NULL;
 
378
        self->errormsg_created = FALSE;
 
379
}
 
380
 
 
381
 
 
382
/*
 
383
 *      Used to begin a transaction.
 
384
 */
 
385
char
 
386
CC_begin(ConnectionClass *self)
 
387
{
 
388
        char    ret = TRUE;
 
389
        if (!CC_is_in_trans(self))
 
390
        {
 
391
                QResultClass *res = CC_send_query(self, "BEGIN", NULL, CLEAR_RESULT_ON_ABORT);
 
392
                mylog("CC_begin:  sending BEGIN!\n");
 
393
 
 
394
                if (res != NULL)
 
395
                {
 
396
                        ret = QR_command_maybe_successful(res);
 
397
                        QR_Destructor(res);
 
398
                }
 
399
                else
 
400
                        return FALSE;
 
401
        }
 
402
 
 
403
        return ret;
 
404
}
 
405
 
 
406
/*
 
407
 *      Used to commit a transaction.
 
408
 *      We are almost always in the middle of a transaction.
 
409
 */
 
410
char
 
411
CC_commit(ConnectionClass *self)
 
412
{
 
413
        char    ret = FALSE;
 
414
        if (CC_is_in_trans(self))
 
415
        {
 
416
                QResultClass *res = CC_send_query(self, "COMMIT", NULL, CLEAR_RESULT_ON_ABORT);
 
417
                mylog("CC_commit:  sending COMMIT!\n");
 
418
                if (res != NULL)
 
419
                {
 
420
                        ret = QR_command_maybe_successful(res);
 
421
                        QR_Destructor(res);
 
422
                }
 
423
                else
 
424
                        return FALSE;
 
425
        }
 
426
 
 
427
        return ret;
 
428
}
 
429
 
 
430
/*
 
431
 *      Used to cancel a transaction.
 
432
 *      We are almost always in the middle of a transaction.
 
433
 */
 
434
char
 
435
CC_abort(ConnectionClass *self)
 
436
{
 
437
        if (CC_is_in_trans(self))
 
438
        {
 
439
                QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, CLEAR_RESULT_ON_ABORT);
 
440
                mylog("CC_abort:  sending ABORT!\n");
 
441
                if (res != NULL)
 
442
                        QR_Destructor(res);
 
443
                else
 
444
                        return FALSE;
 
445
        }
 
446
 
 
447
        return TRUE;
 
448
}
 
449
 
 
450
 
 
451
/* This is called by SQLDisconnect also */
 
452
char
 
453
CC_cleanup(ConnectionClass *self)
 
454
{
 
455
        int                     i;
 
456
        StatementClass *stmt;
 
457
 
 
458
        if (self->status == CONN_EXECUTING)
 
459
                return FALSE;
 
460
 
 
461
        mylog("in CC_Cleanup, self=%u\n", self);
 
462
 
 
463
        /* Cancel an ongoing transaction */
 
464
        /* We are always in the middle of a transaction, */
 
465
        /* even if we are in auto commit. */
 
466
        if (self->sock)
 
467
        {
 
468
                CC_abort(self);
 
469
 
 
470
                mylog("after CC_abort\n");
 
471
 
 
472
                /* This actually closes the connection to the dbase */
 
473
                SOCK_Destructor(self->sock);
 
474
                self->sock = NULL;
 
475
        }
 
476
 
 
477
        mylog("after SOCK destructor\n");
 
478
 
 
479
        /* Free all the stmts on this connection */
 
480
        for (i = 0; i < self->num_stmts; i++)
 
481
        {
 
482
                stmt = self->stmts[i];
 
483
                if (stmt)
 
484
                {
 
485
                        stmt->hdbc = NULL;      /* prevent any more dbase interactions */
 
486
 
 
487
                        SC_Destructor(stmt);
 
488
 
 
489
                        self->stmts[i] = NULL;
 
490
                }
 
491
        }
 
492
 
 
493
        /* Check for translation dll */
 
494
#ifdef WIN32
 
495
        if (self->translation_handle)
 
496
        {
 
497
                FreeLibrary(self->translation_handle);
 
498
                self->translation_handle = NULL;
 
499
        }
 
500
#endif
 
501
 
 
502
        self->status = CONN_NOT_CONNECTED;
 
503
        self->transact_status = CONN_IN_AUTOCOMMIT;
 
504
        CC_conninfo_init(&(self->connInfo));
 
505
        if (self->client_encoding)
 
506
        {
 
507
                free(self->client_encoding);
 
508
                self->client_encoding = NULL;
 
509
        }
 
510
        if (self->server_encoding)
 
511
        {
 
512
                free(self->server_encoding);
 
513
                self->server_encoding = NULL;
 
514
        }
 
515
        if (self->current_schema)
 
516
        {
 
517
                free(self->current_schema);
 
518
                self->current_schema = NULL;
 
519
        }
 
520
        /* Free cached table info */
 
521
        if (self->col_info)
 
522
        {
 
523
                int                     i;
 
524
 
 
525
                for (i = 0; i < self->ntables; i++)
 
526
                {
 
527
                        if (self->col_info[i]->result)  /* Free the SQLColumns result structure */
 
528
                                QR_Destructor(self->col_info[i]->result);
 
529
 
 
530
                        if (self->col_info[i]->schema)
 
531
                                free(self->col_info[i]->schema);
 
532
                        free(self->col_info[i]);
 
533
                }
 
534
                free(self->col_info);
 
535
                self->col_info = NULL;
 
536
        }
 
537
        self->ntables = 0;
 
538
        mylog("exit CC_Cleanup\n");
 
539
        return TRUE;
 
540
}
 
541
 
 
542
 
 
543
int
 
544
CC_set_translation(ConnectionClass *self)
 
545
{
 
546
 
 
547
#ifdef WIN32
 
548
 
 
549
        if (self->translation_handle != NULL)
 
550
        {
 
551
                FreeLibrary(self->translation_handle);
 
552
                self->translation_handle = NULL;
 
553
        }
 
554
 
 
555
        if (self->connInfo.translation_dll[0] == 0)
 
556
                return TRUE;
 
557
 
 
558
        self->translation_option = atoi(self->connInfo.translation_option);
 
559
        self->translation_handle = LoadLibrary(self->connInfo.translation_dll);
 
560
 
 
561
        if (self->translation_handle == NULL)
 
562
        {
 
563
                CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not load the translation DLL.");
 
564
                return FALSE;
 
565
        }
 
566
 
 
567
        self->DataSourceToDriver
 
568
                = (DataSourceToDriverProc) GetProcAddress(self->translation_handle,
 
569
                                                                                                "SQLDataSourceToDriver");
 
570
 
 
571
        self->DriverToDataSource
 
572
                = (DriverToDataSourceProc) GetProcAddress(self->translation_handle,
 
573
                                                                                                "SQLDriverToDataSource");
 
574
 
 
575
        if (self->DataSourceToDriver == NULL || self->DriverToDataSource == NULL)
 
576
        {
 
577
                CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not find translation DLL functions.");
 
578
                return FALSE;
 
579
        }
 
580
#endif
 
581
        return TRUE;
 
582
}
 
583
 
 
584
static  int
 
585
md5_auth_send(ConnectionClass *self, const char *salt)
 
586
{
 
587
        char    *pwd1 = NULL, *pwd2 = NULL;
 
588
        ConnInfo   *ci = &(self->connInfo);
 
589
        SocketClass     *sock = self->sock;
 
590
 
 
591
        if (!(pwd1 = malloc(MD5_PASSWD_LEN + 1)))
 
592
                return 1;
 
593
        if (!EncryptMD5(ci->password, ci->username, strlen(ci->username), pwd1))
 
594
        {
 
595
                free(pwd1);
 
596
                return 1;
 
597
        } 
 
598
        if (!(pwd2 = malloc(MD5_PASSWD_LEN + 1)))
 
599
        {
 
600
                free(pwd1);
 
601
                return 1;
 
602
        } 
 
603
        if (!EncryptMD5(pwd1 + strlen("md5"), salt, 4, pwd2))
 
604
        {
 
605
                free(pwd2);
 
606
                free(pwd1);
 
607
                return 1;
 
608
        }
 
609
        free(pwd1);
 
610
        SOCK_put_int(sock, 4 + strlen(pwd2) + 1, 4);
 
611
        SOCK_put_n_char(sock, pwd2, strlen(pwd2) + 1);
 
612
        SOCK_flush_output(sock);
 
613
        free(pwd2);
 
614
        return 0; 
 
615
}
 
616
 
 
617
char
 
618
CC_connect(ConnectionClass *self, char password_req, char *salt_para)
 
619
{
 
620
        StartupPacket sp;
 
621
        StartupPacket6_2 sp62;
 
622
        QResultClass *res;
 
623
        SocketClass *sock;
 
624
        ConnInfo   *ci = &(self->connInfo);
 
625
        int                     areq = -1;
 
626
        int                     beresp;
 
627
        char            msgbuffer[ERROR_MSG_LENGTH];
 
628
        char            salt[5], notice[512];
 
629
        CSTR            func = "CC_connect";
 
630
        char       *encoding;
 
631
 
 
632
        mylog("%s: entering...\n", func);
 
633
 
 
634
        if (password_req != AUTH_REQ_OK)
 
635
 
 
636
                sock = self->sock;              /* already connected, just authenticate */
 
637
 
 
638
        else
 
639
        {
 
640
                qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
 
641
                         POSTGRESDRIVERVERSION,
 
642
                         ci->drivers.fetch_max,
 
643
                         ci->drivers.socket_buffersize,
 
644
                         ci->drivers.unknown_sizes,
 
645
                         ci->drivers.max_varchar_size,
 
646
                         ci->drivers.max_longvarchar_size);
 
647
                qlog("                disable_optimizer=%d, ksqo=%d, unique_index=%d, use_declarefetch=%d\n",
 
648
                         ci->drivers.disable_optimizer,
 
649
                         ci->drivers.ksqo,
 
650
                         ci->drivers.unique_index,
 
651
                         ci->drivers.use_declarefetch);
 
652
                qlog("                text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d NAMEDATALEN=%d\n",
 
653
                         ci->drivers.text_as_longvarchar,
 
654
                         ci->drivers.unknowns_as_longvarchar,
 
655
                         ci->drivers.bools_as_char,
 
656
                         TABLE_NAME_STORAGE_LEN);
 
657
 
 
658
                encoding = check_client_encoding(ci->conn_settings);
 
659
                if (encoding && strcmp(encoding, "OTHER"))
 
660
                        self->client_encoding = strdup(encoding);
 
661
                else
 
662
                {
 
663
                        encoding = check_client_encoding(ci->drivers.conn_settings);
 
664
                        if (encoding && strcmp(encoding, "OTHER"))
 
665
                                self->client_encoding = strdup(encoding);
 
666
                }
 
667
                if (self->client_encoding)
 
668
                        self->ccsc = pg_CS_code(self->client_encoding);
 
669
                qlog("                extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n",
 
670
                         ci->drivers.extra_systable_prefixes,
 
671
                         ci->drivers.conn_settings,
 
672
                         encoding ? encoding : "");
 
673
 
 
674
                if (self->status != CONN_NOT_CONNECTED)
 
675
                {
 
676
                        CC_set_error(self, CONN_OPENDB_ERROR, "Already connected.");
 
677
                        return 0;
 
678
                }
 
679
 
 
680
                if (ci->server[0] == '\0' || ci->port[0] == '\0' || ci->database[0] == '\0')
 
681
                {
 
682
                        CC_set_error(self, CONN_INIREAD_ERROR, "Missing server name, port, or database name in call to CC_connect.");
 
683
                        return 0;
 
684
                }
 
685
 
 
686
                mylog("CC_connect(): DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", ci->dsn, ci->server, ci->port, ci->database, ci->username, ci->password ? "xxxxx" : "");
 
687
 
 
688
another_version_retry:
 
689
 
 
690
                /*
 
691
                 * If the socket was closed for some reason (like a SQLDisconnect,
 
692
                 * but no SQLFreeConnect then create a socket now.
 
693
                 */
 
694
                if (!self->sock)
 
695
                {
 
696
                        self->sock = SOCK_Constructor(self);
 
697
                        if (!self->sock)
 
698
                        {
 
699
                                CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not open a socket to the server");
 
700
                                return 0;
 
701
                        }
 
702
                }
 
703
 
 
704
                sock = self->sock;
 
705
 
 
706
                mylog("connecting to the server socket...\n");
 
707
 
 
708
                SOCK_connect_to(sock, (short) atoi(ci->port), ci->server);
 
709
                if (SOCK_get_errcode(sock) != 0)
 
710
                {
 
711
                        mylog("connection to the server socket failed.\n");
 
712
                        CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not connect to the server");
 
713
                        return 0;
 
714
                }
 
715
                mylog("connection to the server socket succeeded.\n");
 
716
 
 
717
                if (PROTOCOL_62(ci))
 
718
                {
 
719
                        sock->reverse = TRUE;           /* make put_int and get_int work
 
720
                                                                                 * for 6.2 */
 
721
 
 
722
                        memset(&sp62, 0, sizeof(StartupPacket6_2));
 
723
                        SOCK_put_int(sock, htonl(4 + sizeof(StartupPacket6_2)), 4);
 
724
                        sp62.authtype = htonl(NO_AUTHENTICATION);
 
725
                        strncpy(sp62.database, ci->database, PATH_SIZE);
 
726
                        strncpy(sp62.user, ci->username, USRNAMEDATALEN);
 
727
                        SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2));
 
728
                        SOCK_flush_output(sock);
 
729
                }
 
730
                else
 
731
                {
 
732
                        memset(&sp, 0, sizeof(StartupPacket));
 
733
 
 
734
                        mylog("sizeof startup packet = %d\n", sizeof(StartupPacket));
 
735
 
 
736
                        /* Send length of Authentication Block */
 
737
                        SOCK_put_int(sock, 4 + sizeof(StartupPacket), 4);
 
738
 
 
739
                        if (PROTOCOL_63(ci))
 
740
                                sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_63);
 
741
                        else
 
742
                                sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LATEST);
 
743
 
 
744
                        strncpy(sp.database, ci->database, SM_DATABASE);
 
745
                        strncpy(sp.user, ci->username, SM_USER);
 
746
 
 
747
                        SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket));
 
748
                        SOCK_flush_output(sock);
 
749
                }
 
750
 
 
751
                mylog("sent the authentication block.\n");
 
752
 
 
753
                if (sock->errornumber != 0)
 
754
                {
 
755
                        mylog("couldn't send the authentication block properly.\n");
 
756
                        CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Sending the authentication packet failed");
 
757
                        return 0;
 
758
                }
 
759
                mylog("sent the authentication block successfully.\n");
 
760
        }
 
761
 
 
762
 
 
763
        mylog("gonna do authentication\n");
 
764
 
 
765
 
 
766
        /*
 
767
         * Now get the authentication request from backend
 
768
         */
 
769
 
 
770
        if (!PROTOCOL_62(ci))
 
771
        {
 
772
                BOOL            before_64 = PG_VERSION_LT(self, 6.4),
 
773
                                        ReadyForQuery = FALSE;
 
774
 
 
775
                do
 
776
                {
 
777
                        if (password_req != AUTH_REQ_OK)
 
778
                                beresp = 'R';
 
779
                        else
 
780
                        {
 
781
                                beresp = SOCK_get_char(sock);
 
782
                                mylog("auth got '%c'\n", beresp);
 
783
                        }
 
784
 
 
785
                        switch (beresp)
 
786
                        {
 
787
                                case 'E':
 
788
 
 
789
                                        SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
790
                                        CC_set_error(self, CONN_INVALID_AUTHENTICATION, msgbuffer);
 
791
                                        qlog("ERROR from backend during authentication: '%s'\n", msgbuffer);
 
792
                                        if (strncmp(msgbuffer, "Unsupported frontend protocol", 29) == 0)
 
793
                                        {                       /* retry older version */
 
794
                                                if (PROTOCOL_63(ci))
 
795
                                                        strcpy(ci->protocol, PG62);
 
796
                                                else
 
797
                                                        strcpy(ci->protocol, PG63);
 
798
                                                SOCK_Destructor(sock);
 
799
                                                self->sock = (SocketClass *) 0;
 
800
                                                CC_initialize_pg_version(self);
 
801
                                                goto another_version_retry;
 
802
                                        }
 
803
 
 
804
                                        return 0;
 
805
                                case 'R':
 
806
 
 
807
                                        if (password_req != AUTH_REQ_OK)
 
808
                                        {
 
809
                                                mylog("in 'R' password_req=%s\n", ci->password);
 
810
                                                areq = password_req;
 
811
                                                if (salt_para)
 
812
                                                        memcpy(salt, salt_para, sizeof(salt));
 
813
                                                password_req = AUTH_REQ_OK;
 
814
                                        }
 
815
                                        else
 
816
                                        {
 
817
 
 
818
                                                areq = SOCK_get_int(sock, 4);
 
819
                                                if (areq == AUTH_REQ_MD5)
 
820
                                                        SOCK_get_n_char(sock, salt, 4);
 
821
                                                else if (areq == AUTH_REQ_CRYPT)
 
822
                                                        SOCK_get_n_char(sock, salt, 2);
 
823
 
 
824
                                                mylog("areq = %d\n", areq);
 
825
                                        }
 
826
                                        switch (areq)
 
827
                                        {
 
828
                                                case AUTH_REQ_OK:
 
829
                                                        break;
 
830
 
 
831
                                                case AUTH_REQ_KRB4:
 
832
                                                        CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Kerberos 4 authentication not supported");
 
833
                                                        return 0;
 
834
 
 
835
                                                case AUTH_REQ_KRB5:
 
836
                                                        CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Kerberos 5 authentication not supported");
 
837
                                                        return 0;
 
838
 
 
839
                                                case AUTH_REQ_PASSWORD:
 
840
                                                        mylog("in AUTH_REQ_PASSWORD\n");
 
841
 
 
842
                                                        if (ci->password[0] == '\0')
 
843
                                                        {
 
844
                                                                CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.");
 
845
                                                                return -areq;           /* need password */
 
846
                                                        }
 
847
 
 
848
                                                        mylog("past need password\n");
 
849
 
 
850
                                                        SOCK_put_int(sock, 4 + strlen(ci->password) + 1, 4);
 
851
                                                        SOCK_put_n_char(sock, ci->password, strlen(ci->password) + 1);
 
852
                                                        SOCK_flush_output(sock);
 
853
 
 
854
                                                        mylog("past flush\n");
 
855
                                                        break;
 
856
 
 
857
                                                case AUTH_REQ_CRYPT:
 
858
                                                        CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Password crypt authentication not supported");
 
859
                                                        return 0;
 
860
                                                case AUTH_REQ_MD5:
 
861
                                                        mylog("in AUTH_REQ_MD5\n");
 
862
                                                        if (ci->password[0] == '\0')
 
863
                                                        {
 
864
                                                                CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.");
 
865
                                                                if (salt_para)
 
866
                                                                        memcpy(salt_para, salt, sizeof(salt));
 
867
                                                                return -areq; /* need password */
 
868
                                                        }
 
869
                                                        if (md5_auth_send(self, salt))
 
870
                                                        {
 
871
                                                                CC_set_error(self, CONN_INVALID_AUTHENTICATION, "md5 hashing failed");
 
872
                                                                return 0;
 
873
                                                        }
 
874
                                                        break;
 
875
 
 
876
                                                case AUTH_REQ_SCM_CREDS:
 
877
                                                        CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Unix socket credential authentication not supported");
 
878
                                                        return 0;
 
879
 
 
880
                                                default:
 
881
                                                        CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Unknown authentication type");
 
882
                                                        return 0;
 
883
                                        }
 
884
                                        break;
 
885
                                case 'K':               /* Secret key (6.4 protocol) */
 
886
                                        self->be_pid = SOCK_get_int(sock, 4);           /* pid */
 
887
                                        self->be_key = SOCK_get_int(sock, 4);           /* key */
 
888
 
 
889
                                        break;
 
890
                                case 'Z':               /* Backend is ready for new query (6.4) */
 
891
                                        ReadyForQuery = TRUE;
 
892
                                        break;
 
893
                                case 'N':       /* Notices may come */
 
894
                                        while (SOCK_get_string(sock, notice, sizeof(notice) - 1)) ;
 
895
                                        break;
 
896
                                default:
 
897
                                        CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Unexpected protocol character during authentication");
 
898
                                        return 0;
 
899
                        }
 
900
 
 
901
                        /*
 
902
                         * There were no ReadyForQuery responce before 6.4.
 
903
                         */
 
904
                        if (before_64 && areq == AUTH_REQ_OK)
 
905
                                ReadyForQuery = TRUE;
 
906
                } while (!ReadyForQuery);
 
907
        }
 
908
 
 
909
 
 
910
        CC_clear_error(self);           /* clear any password error */
 
911
 
 
912
        /*
 
913
         * send an empty query in order to find out whether the specified
 
914
         * database really exists on the server machine
 
915
         */
 
916
        mylog("sending an empty query...\n");
 
917
 
 
918
        res = CC_send_query(self, " ", NULL, CLEAR_RESULT_ON_ABORT);
 
919
        if (res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY)
 
920
        {
 
921
                mylog("got no result from the empty query.  (probably database does not exist)\n");
 
922
                CC_set_error(self, CONNECTION_NO_SUCH_DATABASE, "The database does not exist on the server\nor user authentication failed.");
 
923
                if (res != NULL)
 
924
                        QR_Destructor(res);
 
925
                return 0;
 
926
        }
 
927
        if (res)
 
928
                QR_Destructor(res);
 
929
 
 
930
        mylog("empty query seems to be OK.\n");
 
931
 
 
932
        CC_set_translation(self);
 
933
 
 
934
        /*
 
935
         * Send any initial settings
 
936
         */
 
937
 
 
938
        /* 
 
939
         * Get the version number first so we can check it before sending options
 
940
         * that are now obsolete. DJP 21/06/2002
 
941
         */
 
942
 
 
943
        CC_lookup_pg_version(self);             /* Get PostgreSQL version for
 
944
                                                   SQLGetInfo use */
 
945
        /*
 
946
         * Since these functions allocate statements, and since the connection
 
947
         * is not established yet, it would violate odbc state transition
 
948
         * rules.  Therefore, these functions call the corresponding local
 
949
         * function instead.
 
950
         */
 
951
        CC_send_settings(self);
 
952
        CC_clear_error(self);                   /* clear any error */
 
953
        CC_lookup_lo(self);                     /* a hack to get the oid of
 
954
                                                   our large object oid type */
 
955
 
 
956
        /*
 
957
         *      Multibyte handling is available ?
 
958
         */
 
959
        if (PG_VERSION_GE(self, 6.4))
 
960
        {
 
961
                CC_lookup_characterset(self);
 
962
                if (CC_get_errornumber(self) != 0)
 
963
                        return 0;
 
964
#ifdef UNICODE_SUPPORT
 
965
                if (self->unicode)
 
966
                {
 
967
                        if (!self->client_encoding ||
 
968
                            stricmp(self->client_encoding, "UNICODE"))
 
969
                        {
 
970
                                QResultClass    *res;
 
971
                                if (PG_VERSION_LT(self, 7.1))
 
972
                                {
 
973
                                        CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "UTF-8 conversion isn't implemented before 7.1");
 
974
                                        return 0;
 
975
                                }
 
976
                                if (self->client_encoding)
 
977
                                        free(self->client_encoding);
 
978
                                self->client_encoding = NULL;
 
979
                                if (res = CC_send_query(self, "set client_encoding to 'UTF8'", NULL, CLEAR_RESULT_ON_ABORT), res)
 
980
                                {
 
981
                                        self->client_encoding = strdup("UNICODE");
 
982
                                        self->ccsc = pg_CS_code(self->client_encoding);
 
983
                                        QR_Destructor(res);
 
984
                                        
 
985
                                }
 
986
                        }
 
987
                }
 
988
#else
 
989
                {
 
990
                }
 
991
#endif /* UNICODE_SUPPORT */
 
992
        }
 
993
#ifdef UNICODE_SUPPORT
 
994
        else if (self->unicode)
 
995
        {
 
996
                CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "Unicode isn't supported before 6.4");
 
997
                return 0;
 
998
        }
 
999
#endif /* UNICODE_SUPPORT */
 
1000
        ci->updatable_cursors = 0;
 
1001
#ifdef  DRIVER_CURSOR_IMPLEMENT
 
1002
        if (!ci->drivers.use_declarefetch &&
 
1003
                PG_VERSION_GE(self, 7.0)) /* Tid scan since 7.0 */
 
1004
                ci->updatable_cursors = ci->allow_keyset;
 
1005
#endif /* DRIVER_CURSOR_IMPLEMENT */
 
1006
 
 
1007
        CC_clear_error(self);           /* clear any initial command errors */
 
1008
        self->status = CONN_CONNECTED;
 
1009
 
 
1010
        mylog("%s: returning...\n", func);
 
1011
 
 
1012
        return 1;
 
1013
 
 
1014
}
 
1015
 
 
1016
 
 
1017
char
 
1018
CC_add_statement(ConnectionClass *self, StatementClass *stmt)
 
1019
{
 
1020
        int                     i;
 
1021
 
 
1022
        mylog("CC_add_statement: self=%u, stmt=%u\n", self, stmt);
 
1023
 
 
1024
        for (i = 0; i < self->num_stmts; i++)
 
1025
        {
 
1026
                if (!self->stmts[i])
 
1027
                {
 
1028
                        stmt->hdbc = self;
 
1029
                        self->stmts[i] = stmt;
 
1030
                        return TRUE;
 
1031
                }
 
1032
        }
 
1033
 
 
1034
        /* no more room -- allocate more memory */
 
1035
        self->stmts = (StatementClass **) realloc(self->stmts, sizeof(StatementClass *) * (STMT_INCREMENT + self->num_stmts));
 
1036
        if (!self->stmts)
 
1037
                return FALSE;
 
1038
 
 
1039
        memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT);
 
1040
 
 
1041
        stmt->hdbc = self;
 
1042
        self->stmts[self->num_stmts] = stmt;
 
1043
 
 
1044
        self->num_stmts += STMT_INCREMENT;
 
1045
 
 
1046
        return TRUE;
 
1047
}
 
1048
 
 
1049
 
 
1050
char
 
1051
CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
 
1052
{
 
1053
        int                     i;
 
1054
 
 
1055
        for (i = 0; i < self->num_stmts; i++)
 
1056
        {
 
1057
                if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING)
 
1058
                {
 
1059
                        self->stmts[i] = NULL;
 
1060
                        return TRUE;
 
1061
                }
 
1062
        }
 
1063
 
 
1064
        return FALSE;
 
1065
}
 
1066
 
 
1067
 
 
1068
/*
 
1069
 *      Create a more informative error message by concatenating the connection
 
1070
 *      error message with its socket error message.
 
1071
 */
 
1072
char *
 
1073
CC_create_errormsg(ConnectionClass *self)
 
1074
{
 
1075
        SocketClass *sock = self->sock;
 
1076
        int                     pos;
 
1077
        char     msg[4096];
 
1078
 
 
1079
        mylog("enter CC_create_errormsg\n");
 
1080
 
 
1081
        msg[0] = '\0';
 
1082
 
 
1083
        if (CC_get_errormsg(self))
 
1084
                strncpy(msg, CC_get_errormsg(self), sizeof(msg));
 
1085
 
 
1086
        mylog("msg = '%s'\n", msg);
 
1087
 
 
1088
        if (sock && sock->errormsg && sock->errormsg[0] != '\0')
 
1089
        {
 
1090
                pos = strlen(msg);
 
1091
                sprintf(&msg[pos], ";\n%s", sock->errormsg);
 
1092
        }
 
1093
 
 
1094
        mylog("exit CC_create_errormsg\n");
 
1095
        return msg ? strdup(msg) : NULL;
 
1096
}
 
1097
 
 
1098
 
 
1099
void
 
1100
CC_set_error(ConnectionClass *self, int number, const char *message)
 
1101
{
 
1102
        if (self->__error_message)
 
1103
                free(self->__error_message);
 
1104
        self->__error_number = number;
 
1105
        self->__error_message = message ? strdup(message) : NULL;
 
1106
}
 
1107
 
 
1108
 
 
1109
void
 
1110
CC_set_errormsg(ConnectionClass *self, const char *message)
 
1111
{
 
1112
        if (self->__error_message)
 
1113
                free(self->__error_message);
 
1114
        self->__error_message = message ? strdup(message) : NULL;
 
1115
}
 
1116
 
 
1117
 
 
1118
char
 
1119
CC_get_error(ConnectionClass *self, int *number, char **message)
 
1120
{
 
1121
        int                     rv;
 
1122
        char *msgcrt;
 
1123
 
 
1124
        mylog("enter CC_get_error\n");
 
1125
 
 
1126
        /* Create a very informative errormsg if it hasn't been done yet. */
 
1127
        if (!self->errormsg_created)
 
1128
        {
 
1129
                msgcrt = CC_create_errormsg(self);
 
1130
                if (self->__error_message)
 
1131
                        free(self->__error_message);
 
1132
                self->__error_message = msgcrt;
 
1133
                self->errormsg_created = TRUE;
 
1134
        }
 
1135
 
 
1136
        if (CC_get_errornumber(self))
 
1137
        {
 
1138
                *number = CC_get_errornumber(self);
 
1139
                *message = CC_get_errormsg(self);
 
1140
        }
 
1141
        rv = (CC_get_errornumber(self) != 0);
 
1142
 
 
1143
        self->__error_number = 0;               /* clear the error */
 
1144
 
 
1145
        mylog("exit CC_get_error\n");
 
1146
 
 
1147
        return rv;
 
1148
}
 
1149
 
 
1150
 
 
1151
void    CC_on_commit(ConnectionClass *conn)
 
1152
{
 
1153
        if (CC_is_in_trans(conn))
 
1154
        {
 
1155
#ifdef  DRIVER_CURSOR_IMPLEMENT
 
1156
                if (conn->result_uncommitted)
 
1157
                        ProcessRollback(conn, FALSE);
 
1158
#endif /* DRIVER_CURSOR_IMPLEMENT */
 
1159
                CC_set_no_trans(conn);
 
1160
                CC_set_no_manual_trans(conn);
 
1161
        }
 
1162
        conn->result_uncommitted = 0;
 
1163
}
 
1164
void    CC_on_abort(ConnectionClass *conn, UDWORD opt)
 
1165
{
 
1166
        if (CC_is_in_trans(conn))
 
1167
        {
 
1168
#ifdef  DRIVER_CURSOR_IMPLEMENT
 
1169
                if (conn->result_uncommitted)
 
1170
                        ProcessRollback(conn, TRUE);
 
1171
#endif /* DRIVER_CURSOR_IMPLEMENT */
 
1172
                if (0 != (opt & NO_TRANS))
 
1173
                {
 
1174
                        CC_set_no_trans(conn);
 
1175
                        CC_set_no_manual_trans(conn);
 
1176
                }
 
1177
        }
 
1178
        if (0 != (opt & CONN_DEAD))
 
1179
        {
 
1180
                conn->status = CONN_DOWN;
 
1181
                if (conn->sock)
 
1182
                {
 
1183
                        SOCK_Destructor(conn->sock);
 
1184
                        conn->sock = NULL;
 
1185
                }
 
1186
        }
 
1187
        conn->result_uncommitted = 0;
 
1188
}
 
1189
 
 
1190
/*
 
1191
 *      The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
 
1192
 *      the same existing QResultClass (this occurs when the tuple cache is depleted and
 
1193
 *      needs to be re-filled).
 
1194
 *
 
1195
 *      The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
 
1196
 *      (i.e., C3326857) for SQL select statements.  This cursor is then used in future
 
1197
 *      'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
 
1198
 */
 
1199
 
 
1200
 
 
1201
QResultClass *
 
1202
CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
 
1203
{
 
1204
        QResultClass *cmdres = NULL,
 
1205
                           *retres = NULL,
 
1206
                           *res = NULL;
 
1207
        BOOL    clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0),
 
1208
                create_keyset = ((flag & CREATE_KEYSET) != 0),
 
1209
                issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self));
 
1210
        char            swallow, *wq, *ptr;
 
1211
        int                     id;
 
1212
        SocketClass *sock = self->sock;
 
1213
        int                     maxlen,
 
1214
                                empty_reqs;
 
1215
        BOOL            msg_truncated,
 
1216
                                ReadyToReturn,
 
1217
                                query_completed = FALSE,
 
1218
                                before_64 = PG_VERSION_LT(self, 6.4),
 
1219
                                aborted = FALSE,
 
1220
                                used_passed_result_object = FALSE;
 
1221
        UDWORD          abort_opt;
 
1222
 
 
1223
        /* ERROR_MSG_LENGTH is suffcient */
 
1224
        char msgbuffer[ERROR_MSG_LENGTH + 1];
 
1225
 
 
1226
        /* QR_set_command() dups this string so doesn't need static */
 
1227
        char            cmdbuffer[ERROR_MSG_LENGTH + 1];
 
1228
 
 
1229
        mylog("send_query(): conn=%u, query='%s'\n", self, query);
 
1230
        qlog("conn=%u, query='%s'\n", self, query);
 
1231
 
 
1232
        if (!self->sock)
 
1233
        {
 
1234
                CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query(connection dead)");
 
1235
                CC_on_abort(self, NO_TRANS);
 
1236
                return NULL;
 
1237
        }
 
1238
 
 
1239
        /* Indicate that we are sending a query to the backend */
 
1240
        maxlen = CC_get_max_query_len(self);
 
1241
        if (maxlen > 0 && maxlen < (int) strlen(query) + 1)
 
1242
        {
 
1243
                CC_set_error(self, CONNECTION_MSG_TOO_LONG, "Query string is too long");
 
1244
                return NULL;
 
1245
        }
 
1246
 
 
1247
        if ((NULL == query) || (query[0] == '\0'))
 
1248
                return NULL;
 
1249
 
 
1250
        if (SOCK_get_errcode(sock) != 0)
 
1251
        {
 
1252
                CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend");
 
1253
                CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1254
                return NULL;
 
1255
        }
 
1256
 
 
1257
        ENTER_CONN_CS(self);
 
1258
        SOCK_put_char(sock, 'Q');
 
1259
        if (SOCK_get_errcode(sock) != 0)
 
1260
        {
 
1261
                CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend");
 
1262
                CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1263
                RETURN_AFTER_LEAVE_CS(self, NULL);
 
1264
        }
 
1265
 
 
1266
        if (issue_begin)
 
1267
                SOCK_put_n_char(sock, "BEGIN;", 6);
 
1268
        SOCK_put_string(sock, query);
 
1269
        SOCK_flush_output(sock);
 
1270
 
 
1271
        if (SOCK_get_errcode(sock) != 0)
 
1272
        {
 
1273
                CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend");
 
1274
                CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1275
                RETURN_AFTER_LEAVE_CS(self, NULL);
 
1276
        }
 
1277
 
 
1278
        mylog("send_query: done sending query\n");
 
1279
 
 
1280
        ReadyToReturn = FALSE;
 
1281
        empty_reqs = 0;
 
1282
        for (wq = query; isspace((unsigned char) *wq); wq++)
 
1283
                ;
 
1284
        if (*wq == '\0')
 
1285
                empty_reqs = 1;
 
1286
        cmdres = qi ? qi->result_in : NULL;
 
1287
        if (cmdres)
 
1288
                used_passed_result_object = TRUE;
 
1289
        else
 
1290
        {
 
1291
                cmdres = QR_Constructor();
 
1292
                if (!cmdres)
 
1293
                {
 
1294
                        CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.");
 
1295
                        RETURN_AFTER_LEAVE_CS(self, NULL);
 
1296
                }
 
1297
        }
 
1298
        res = cmdres;
 
1299
        while (!ReadyToReturn)
 
1300
        {
 
1301
                /* what type of message is coming now ? */
 
1302
                id = SOCK_get_char(sock);
 
1303
 
 
1304
                if ((SOCK_get_errcode(sock) != 0) || (id == EOF))
 
1305
                {
 
1306
                        CC_set_error(self, CONNECTION_NO_RESPONSE, "No response from the backend");
 
1307
 
 
1308
                        mylog("send_query: 'id' - %s\n", CC_get_errormsg(self));
 
1309
                        CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1310
                        ReadyToReturn = TRUE;
 
1311
                        retres = NULL;
 
1312
                        break;
 
1313
                }
 
1314
 
 
1315
                mylog("send_query: got id = '%c'\n", id);
 
1316
 
 
1317
                switch (id)
 
1318
                {
 
1319
                        case 'A':                       /* Asynchronous Messages are ignored */
 
1320
                                (void) SOCK_get_int(sock, 4);   /* id of notification */
 
1321
                                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
1322
                                /* name of the relation the message comes from */
 
1323
                                break;
 
1324
                        case 'C':                       /* portal query command, no tuples
 
1325
                                                                 * returned */
 
1326
                                /* read in the return message from the backend */
 
1327
                                SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
1328
                                if (SOCK_get_errcode(sock) != 0)
 
1329
                                {
 
1330
                                        CC_set_error(self, CONNECTION_NO_RESPONSE, "No response from backend while receiving a portal query command");
 
1331
                                        mylog("send_query: 'C' - %s\n", CC_get_errormsg(self));
 
1332
                                        CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1333
                                        ReadyToReturn = TRUE;
 
1334
                                        retres = NULL;
 
1335
                                }
 
1336
                                else
 
1337
                                {
 
1338
                                        mylog("send_query: ok - 'C' - %s\n", cmdbuffer);
 
1339
 
 
1340
                                        if (query_completed)    /* allow for "show" style notices */
 
1341
                                        {
 
1342
                                                res->next = QR_Constructor();
 
1343
                                                res = res->next;
 
1344
                                        } 
 
1345
 
 
1346
                                        mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer);
 
1347
 
 
1348
                                        if (strnicmp(cmdbuffer, "BEGIN", 5) == 0)
 
1349
                                        {
 
1350
                                                CC_set_in_trans(self);
 
1351
                                                if (issue_begin)
 
1352
                                                {
 
1353
                                                        issue_begin = FALSE;
 
1354
                                                        continue;
 
1355
                                                }
 
1356
                                        }
 
1357
                                        else if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
 
1358
                                                CC_on_commit(self);
 
1359
                                        else if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
 
1360
                                                CC_on_abort(self, NO_TRANS);
 
1361
                                        else if (strnicmp(cmdbuffer, "END", 3) == 0)
 
1362
                                                CC_on_commit(self);
 
1363
                                        else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
 
1364
                                                CC_on_abort(self, NO_TRANS);
 
1365
                                        else
 
1366
                                        {
 
1367
                                                trim(cmdbuffer); /* get rid of trailing space */ 
 
1368
                                                ptr = strrchr(cmdbuffer, ' ');
 
1369
                                                if (ptr)
 
1370
                                                        res->recent_processed_row_count = atoi(ptr + 1);
 
1371
                                                else
 
1372
                                                        res->recent_processed_row_count = -1;
 
1373
                                        }
 
1374
 
 
1375
                                        if (QR_command_successful(res))
 
1376
                                                QR_set_status(res, PGRES_COMMAND_OK);
 
1377
                                        QR_set_command(res, cmdbuffer);
 
1378
                                        query_completed = TRUE;
 
1379
                                        mylog("send_query: returning res = %u\n", res);
 
1380
                                        if (!before_64)
 
1381
                                                break;
 
1382
 
 
1383
                                        /*
 
1384
                                         * (Quotation from the original comments) since
 
1385
                                         * backend may produce more than one result for some
 
1386
                                         * commands we need to poll until clear so we send an
 
1387
                                         * empty query, and keep reading out of the pipe until
 
1388
                                         * an 'I' is received
 
1389
                                         */
 
1390
 
 
1391
                                        if (empty_reqs == 0)
 
1392
                                        {
 
1393
                                                SOCK_put_string(sock, "Q ");
 
1394
                                                SOCK_flush_output(sock);
 
1395
                                                empty_reqs++;
 
1396
                                        }
 
1397
                                }
 
1398
                                break;
 
1399
                        case 'Z':                       /* Backend is ready for new query (6.4) */
 
1400
                                if (empty_reqs == 0)
 
1401
                                {
 
1402
                                        ReadyToReturn = TRUE;
 
1403
                                        if (aborted || query_completed)
 
1404
                                                retres = cmdres;
 
1405
                                        else
 
1406
                                                ReadyToReturn = FALSE;
 
1407
                                }
 
1408
                                break;
 
1409
                        case 'N':                       /* NOTICE: */
 
1410
                                msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
1411
                                if (QR_command_successful(res))
 
1412
                                        QR_set_status(res, PGRES_NONFATAL_ERROR);
 
1413
                                QR_set_notice(res, cmdbuffer);  /* will dup this string */
 
1414
                                mylog("~~~ NOTICE: '%s'\n", cmdbuffer);
 
1415
                                qlog("NOTICE from backend during send_query: '%s'\n", cmdbuffer);
 
1416
                                while (msg_truncated)
 
1417
                                        msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
1418
 
 
1419
                                continue;               /* dont return a result -- continue
 
1420
                                                                 * reading */
 
1421
 
 
1422
                        case 'I':                       /* The server sends an empty query */
 
1423
                                /* There is a closing '\0' following the 'I', so we eat it */
 
1424
                                swallow = SOCK_get_char(sock);
 
1425
                                if ((swallow != '\0') || SOCK_get_errcode(sock) != 0)
 
1426
                                {
 
1427
                                        CC_set_errornumber(self, CONNECTION_BACKEND_CRAZY);
 
1428
                                        QR_set_message(res, "Unexpected protocol character from backend (send_query - I)");
 
1429
                                        QR_set_status(res, PGRES_FATAL_ERROR);
 
1430
                                        ReadyToReturn = TRUE;
 
1431
                                        retres = cmdres;
 
1432
                                        break;
 
1433
                                }
 
1434
                                else
 
1435
                                {
 
1436
                                        /* We return the empty query */
 
1437
                                        QR_set_status(res, PGRES_EMPTY_QUERY);
 
1438
                                }
 
1439
                                if (empty_reqs > 0)
 
1440
                                {
 
1441
                                        if (--empty_reqs == 0)
 
1442
                                                query_completed = TRUE;
 
1443
                                }
 
1444
                                break;
 
1445
                        case 'E':
 
1446
                                msg_truncated = SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
1447
 
 
1448
                                /* Remove a newline */
 
1449
                                if (msgbuffer[0] != '\0' && msgbuffer[strlen(msgbuffer) - 1] == '\n')
 
1450
                                        msgbuffer[strlen(msgbuffer) - 1] = '\0';
 
1451
 
 
1452
 
 
1453
                                mylog("send_query: 'E' - %s\n", msgbuffer);
 
1454
                                qlog("ERROR from backend during send_query: '%s'\n", msgbuffer);
 
1455
 
 
1456
                                /* We should report that an error occured. Zoltan */
 
1457
                                abort_opt = 0;
 
1458
                                if (!strncmp(msgbuffer, "FATAL", 5))
 
1459
                                {
 
1460
                                        CC_set_errornumber(self, CONNECTION_SERVER_REPORTED_ERROR);
 
1461
                                        abort_opt = NO_TRANS | CONN_DEAD;
 
1462
                                }
 
1463
                                else
 
1464
                                        CC_set_errornumber(self, CONNECTION_SERVER_REPORTED_WARNING);
 
1465
                                CC_on_abort(self, abort_opt);
 
1466
                                QR_set_status(res, PGRES_FATAL_ERROR);
 
1467
                                QR_set_message(res, msgbuffer);
 
1468
                                QR_set_aborted(res, TRUE);
 
1469
                                aborted = TRUE;
 
1470
                                while (msg_truncated)
 
1471
                                        msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
 
1472
 
 
1473
                                query_completed = TRUE;
 
1474
                                break;
 
1475
 
 
1476
                        case 'P':                       /* get the Portal name */
 
1477
                                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
1478
                                break;
 
1479
                        case 'T':                       /* Tuple results start here */
 
1480
                                if (query_completed)
 
1481
                                {
 
1482
                                        res->next = QR_Constructor();
 
1483
                                        if (!res->next)
 
1484
                                        {
 
1485
                                                CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.");
 
1486
                                                ReadyToReturn = TRUE;
 
1487
                                                retres = NULL;
 
1488
                                                break;
 
1489
                                        }
 
1490
                                        if (create_keyset)
 
1491
                                                QR_set_haskeyset(res->next);
 
1492
                                        mylog("send_query: 'T' no result_in: res = %u\n", res->next);
 
1493
                                        res = res->next;
 
1494
 
 
1495
                                        if (qi)
 
1496
                                                QR_set_cache_size(res, qi->row_size);
 
1497
                                }
 
1498
                                if (!used_passed_result_object)
 
1499
                                {
 
1500
                                        if (create_keyset)
 
1501
                                                QR_set_haskeyset(res);
 
1502
                                        if (!QR_fetch_tuples(res, self, qi ? qi->cursor : NULL))
 
1503
                                        {
 
1504
                                                CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res));
 
1505
                                                ReadyToReturn = TRUE;
 
1506
                                                if (PGRES_FATAL_ERROR == QR_get_status(res))
 
1507
                                                        retres = cmdres;
 
1508
                                                else
 
1509
                                                        retres = NULL;
 
1510
                                                break;
 
1511
                                        }
 
1512
                                        query_completed = TRUE;
 
1513
                                }
 
1514
                                else
 
1515
                                {                               /* next fetch, so reuse an existing result */
 
1516
 
 
1517
                                        /*
 
1518
                                         * called from QR_next_tuple and must return
 
1519
                                         * immediately.
 
1520
                                         */
 
1521
                                        ReadyToReturn = TRUE;
 
1522
                                        if (!QR_fetch_tuples(res, NULL, NULL))
 
1523
                                        {
 
1524
                                                CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res));
 
1525
                                                retres = NULL;
 
1526
                                                break;
 
1527
                                        }
 
1528
                                        retres = cmdres;
 
1529
                                }
 
1530
                                break;
 
1531
                        case 'D':                       /* Copy in command began successfully */
 
1532
                                if (query_completed)
 
1533
                                {
 
1534
                                        res->next = QR_Constructor();
 
1535
                                        res = res->next;
 
1536
                                }
 
1537
                                QR_set_status(res, PGRES_COPY_IN);
 
1538
                                ReadyToReturn = TRUE;
 
1539
                                retres = cmdres;
 
1540
                                break;
 
1541
                        case 'B':                       /* Copy out command began successfully */
 
1542
                                if (query_completed)
 
1543
                                {
 
1544
                                        res->next = QR_Constructor();
 
1545
                                        res = res->next;
 
1546
                                }
 
1547
                                QR_set_status(res, PGRES_COPY_OUT);
 
1548
                                ReadyToReturn = TRUE;
 
1549
                                retres = cmdres;
 
1550
                                break;
 
1551
                        default:
 
1552
                                CC_set_error(self, CONNECTION_BACKEND_CRAZY, "Unexpected protocol character from backend (send_query)");
 
1553
                                CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1554
 
 
1555
                                mylog("send_query: error - %s\n", CC_get_errormsg(self));
 
1556
                                ReadyToReturn = TRUE;
 
1557
                                retres = NULL;
 
1558
                                break;
 
1559
                }
 
1560
 
 
1561
                /*
 
1562
                 * There were no ReadyForQuery response before 6.4.
 
1563
                 */
 
1564
                if (before_64)
 
1565
                {
 
1566
                        if (empty_reqs == 0 && query_completed)
 
1567
                                break;
 
1568
                }
 
1569
        }
 
1570
 
 
1571
        /*
 
1572
         * Break before being ready to return.
 
1573
         */
 
1574
        if (!ReadyToReturn)
 
1575
                retres = cmdres;
 
1576
 
 
1577
        /*
 
1578
         * Cleanup garbage results before returning.
 
1579
         */
 
1580
        if (cmdres && retres != cmdres && !used_passed_result_object)
 
1581
                QR_Destructor(cmdres);
 
1582
        /*
 
1583
         * Cleanup the aborted result if specified
 
1584
         */
 
1585
        if (retres)
 
1586
        {
 
1587
                if (aborted)
 
1588
                {
 
1589
                        if (clear_result_on_abort)
 
1590
                        {
 
1591
                                if (!used_passed_result_object)
 
1592
                                {
 
1593
                                        QR_Destructor(retres);
 
1594
                                        retres = NULL;
 
1595
                                }
 
1596
                        }
 
1597
                        if (retres)
 
1598
                        {
 
1599
                                /*
 
1600
                                 *      discard results other than errors.
 
1601
                                 */
 
1602
                                QResultClass    *qres;
 
1603
                                for (qres = retres; qres->next; qres = retres)
 
1604
                                {
 
1605
                                        if (QR_get_aborted(qres))
 
1606
                                                break;
 
1607
                                        retres = qres->next;
 
1608
                                        qres->next = NULL;
 
1609
                                        QR_Destructor(qres);
 
1610
                                }
 
1611
                                /*
 
1612
                                 *      If error message isn't set
 
1613
                                 */
 
1614
                                if (retres && (!CC_get_errormsg(self) || !CC_get_errormsg(self)[0]))
 
1615
                                        CC_set_errormsg(self, QR_get_message(retres));
 
1616
                        }
 
1617
                }
 
1618
        }
 
1619
        RETURN_AFTER_LEAVE_CS(self, retres);
 
1620
}
 
1621
 
 
1622
 
 
1623
int
 
1624
CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
 
1625
{
 
1626
        char            id,
 
1627
                                c,
 
1628
                                done;
 
1629
        SocketClass *sock = self->sock;
 
1630
 
 
1631
        /* ERROR_MSG_LENGTH is sufficient */
 
1632
        char msgbuffer[ERROR_MSG_LENGTH + 1];
 
1633
        int                     i;
 
1634
 
 
1635
        mylog("send_function(): conn=%u, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);
 
1636
 
 
1637
        if (!self->sock)
 
1638
        {
 
1639
                CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function(connection dead)");
 
1640
                CC_on_abort(self, NO_TRANS);
 
1641
                return FALSE;
 
1642
        }
 
1643
 
 
1644
        if (SOCK_get_errcode(sock) != 0)
 
1645
        {
 
1646
                CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function to backend");
 
1647
                CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1648
                return FALSE;
 
1649
        }
 
1650
 
 
1651
        SOCK_put_string(sock, "F ");
 
1652
        if (SOCK_get_errcode(sock) != 0)
 
1653
        {
 
1654
                CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function to backend");
 
1655
                CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1656
                return FALSE;
 
1657
        }
 
1658
 
 
1659
        SOCK_put_int(sock, fnid, 4);
 
1660
        SOCK_put_int(sock, nargs, 4);
 
1661
 
 
1662
 
 
1663
        mylog("send_function: done sending function\n");
 
1664
 
 
1665
        for (i = 0; i < nargs; ++i)
 
1666
        {
 
1667
                mylog("  arg[%d]: len = %d, isint = %d, integer = %d, ptr = %u\n", i, args[i].len, args[i].isint, args[i].u.integer, args[i].u.ptr);
 
1668
 
 
1669
                SOCK_put_int(sock, args[i].len, 4);
 
1670
                if (args[i].isint)
 
1671
                        SOCK_put_int(sock, args[i].u.integer, 4);
 
1672
                else
 
1673
                        SOCK_put_n_char(sock, (char *) args[i].u.ptr, args[i].len);
 
1674
 
 
1675
 
 
1676
        }
 
1677
 
 
1678
        mylog("    done sending args\n");
 
1679
 
 
1680
        SOCK_flush_output(sock);
 
1681
        mylog("  after flush output\n");
 
1682
 
 
1683
        done = FALSE;
 
1684
        while (!done)
 
1685
        {
 
1686
                id = SOCK_get_char(sock);
 
1687
                mylog("   got id = %c\n", id);
 
1688
 
 
1689
                switch (id)
 
1690
                {
 
1691
                        case 'V':
 
1692
                                done = TRUE;
 
1693
                                break;                  /* ok */
 
1694
 
 
1695
                        case 'N':
 
1696
                                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
1697
                                mylog("send_function(V): 'N' - %s\n", msgbuffer);
 
1698
                                /* continue reading */
 
1699
                                break;
 
1700
 
 
1701
                        case 'E':
 
1702
                                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
1703
                                CC_set_errormsg(self, msgbuffer);
 
1704
                                CC_on_abort(self, 0);
 
1705
 
 
1706
                                mylog("send_function(V): 'E' - %s\n", CC_get_errormsg(self));
 
1707
                                qlog("ERROR from backend during send_function: '%s'\n", CC_get_errormsg(self));
 
1708
 
 
1709
                                return FALSE;
 
1710
 
 
1711
                        case 'Z':
 
1712
                                break;
 
1713
 
 
1714
                        default:
 
1715
                                CC_set_error(self, CONNECTION_BACKEND_CRAZY, "Unexpected protocol character from backend (send_function, args)");
 
1716
                                CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1717
 
 
1718
                                mylog("send_function: error - %s\n", CC_get_errormsg(self));
 
1719
                                return FALSE;
 
1720
                }
 
1721
        }
 
1722
 
 
1723
        id = SOCK_get_char(sock);
 
1724
        for (;;)
 
1725
        {
 
1726
                switch (id)
 
1727
                {
 
1728
                        case 'G':                       /* function returned properly */
 
1729
                                mylog("  got G!\n");
 
1730
 
 
1731
                                *actual_result_len = SOCK_get_int(sock, 4);
 
1732
                                mylog("  actual_result_len = %d\n", *actual_result_len);
 
1733
 
 
1734
                                if (result_is_int)
 
1735
                                        *((int *) result_buf) = SOCK_get_int(sock, 4);
 
1736
                                else
 
1737
                                        SOCK_get_n_char(sock, (char *) result_buf, *actual_result_len);
 
1738
 
 
1739
                                mylog("  after get result\n");
 
1740
 
 
1741
                                c = SOCK_get_char(sock);                /* get the last '0' */
 
1742
 
 
1743
                                mylog("   after get 0\n");
 
1744
 
 
1745
                                return TRUE;
 
1746
 
 
1747
                        case 'E':
 
1748
                                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
1749
                                CC_set_errormsg(self, msgbuffer);
 
1750
                                CC_on_abort(self, 0);
 
1751
                                mylog("send_function(G): 'E' - %s\n", CC_get_errormsg(self));
 
1752
                                qlog("ERROR from backend during send_function: '%s'\n", CC_get_errormsg(self));
 
1753
 
 
1754
                                return FALSE;
 
1755
 
 
1756
                        case 'N':
 
1757
                                SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
 
1758
 
 
1759
                                mylog("send_function(G): 'N' - %s\n", msgbuffer);
 
1760
                                qlog("NOTICE from backend during send_function: '%s'\n", msgbuffer);
 
1761
 
 
1762
                                continue;               /* dont return a result -- continue
 
1763
                                                                 * reading */
 
1764
 
 
1765
                        case '0':                       /* empty result */
 
1766
                                return TRUE;
 
1767
 
 
1768
                        default:
 
1769
                                CC_set_error(self, CONNECTION_BACKEND_CRAZY, "Unexpected protocol character from backend (send_function, result)");
 
1770
                                CC_on_abort(self, NO_TRANS | CONN_DEAD);
 
1771
 
 
1772
                                mylog("send_function: error - %s\n", CC_get_errormsg(self));
 
1773
                                return FALSE;
 
1774
                }
 
1775
        }
 
1776
}
 
1777
 
 
1778
 
 
1779
char
 
1780
CC_send_settings(ConnectionClass *self)
 
1781
{
 
1782
        /* char ini_query[MAX_MESSAGE_LEN]; */
 
1783
        ConnInfo   *ci = &(self->connInfo);
 
1784
 
 
1785
/* QResultClass *res; */
 
1786
        HSTMT           hstmt;
 
1787
        StatementClass *stmt;
 
1788
        RETCODE         result;
 
1789
        char            status = TRUE;
 
1790
        char       *cs,
 
1791
                           *ptr;
 
1792
#ifdef  HAVE_STRTOK_R
 
1793
        char    *last;
 
1794
#endif /* HAVE_STRTOK_R */
 
1795
        CSTR func = "CC_send_settings";
 
1796
 
 
1797
 
 
1798
        mylog("%s: entering...\n", func);
 
1799
 
 
1800
/*
 
1801
 *      This function must use the local odbc API functions since the odbc state
 
1802
 *      has not transitioned to "connected" yet.
 
1803
 */
 
1804
 
 
1805
        result = PGAPI_AllocStmt(self, &hstmt);
 
1806
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1807
                return FALSE;
 
1808
        stmt = (StatementClass *) hstmt;
 
1809
 
 
1810
        stmt->internal = TRUE;          /* ensure no BEGIN/COMMIT/ABORT stuff */
 
1811
 
 
1812
        /* Set the Datestyle to the format the driver expects it to be in */
 
1813
        result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS);
 
1814
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1815
                status = FALSE;
 
1816
 
 
1817
        mylog("%s: result %d, status %d from set DateStyle\n", func, result, status);
 
1818
 
 
1819
        /* Disable genetic optimizer based on global flag */
 
1820
        if (ci->drivers.disable_optimizer)
 
1821
        {
 
1822
                result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS);
 
1823
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1824
                        status = FALSE;
 
1825
 
 
1826
                mylog("%s: result %d, status %d from set geqo\n", func, result, status);
 
1827
 
 
1828
        }
 
1829
 
 
1830
        /* KSQO (not applicable to 7.1+ - DJP 21/06/2002) */
 
1831
        if (ci->drivers.ksqo && PG_VERSION_LT(self, 7.1))
 
1832
        {
 
1833
                result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS);
 
1834
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1835
                        status = FALSE;
 
1836
 
 
1837
                mylog("%s: result %d, status %d from set ksqo\n", func, result, status);
 
1838
 
 
1839
        }
 
1840
 
 
1841
        /* extra_float_digits (applicable since 7.4) */
 
1842
        if (PG_VERSION_GT(self, 7.3))
 
1843
        {
 
1844
                result = PGAPI_ExecDirect(hstmt, "set extra_float_digits to 2", SQL_NTS);
 
1845
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1846
                        status = FALSE;
 
1847
 
 
1848
                mylog("%s: result %d, status %d from set extra_float_digits\n", func, result, status);
 
1849
 
 
1850
        }
 
1851
 
 
1852
        /* Global settings */
 
1853
        if (ci->drivers.conn_settings[0] != '\0')
 
1854
        {
 
1855
                cs = strdup(ci->drivers.conn_settings);
 
1856
#ifdef  HAVE_STRTOK_R
 
1857
                ptr = strtok_r(cs, ";", &last);
 
1858
#else
 
1859
                ptr = strtok(cs, ";");
 
1860
#endif /* HAVE_STRTOK_R */
 
1861
                while (ptr)
 
1862
                {
 
1863
                        result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS);
 
1864
                        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1865
                                status = FALSE;
 
1866
 
 
1867
                        mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
 
1868
 
 
1869
#ifdef  HAVE_STRTOK_R
 
1870
                        ptr = strtok_r(NULL, ";", &last);
 
1871
#else
 
1872
                        ptr = strtok(NULL, ";");
 
1873
#endif /* HAVE_STRTOK_R */
 
1874
                }
 
1875
 
 
1876
                free(cs);
 
1877
        }
 
1878
 
 
1879
        /* Per Datasource settings */
 
1880
        if (ci->conn_settings[0] != '\0')
 
1881
        {
 
1882
                cs = strdup(ci->conn_settings);
 
1883
#ifdef  HAVE_STRTOK_R
 
1884
                ptr = strtok_r(cs, ";", &last);
 
1885
#else
 
1886
                ptr = strtok(cs, ";");
 
1887
#endif /* HAVE_STRTOK_R */
 
1888
                while (ptr)
 
1889
                {
 
1890
                        result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS);
 
1891
                        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1892
                                status = FALSE;
 
1893
 
 
1894
                        mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
 
1895
 
 
1896
#ifdef  HAVE_STRTOK_R
 
1897
                        ptr = strtok_r(NULL, ";", &last);
 
1898
#else
 
1899
                        ptr = strtok(NULL, ";");
 
1900
#endif /* HAVE_STRTOK_R */
 
1901
                }
 
1902
 
 
1903
                free(cs);
 
1904
        }
 
1905
 
 
1906
 
 
1907
        PGAPI_FreeStmt(hstmt, SQL_DROP);
 
1908
 
 
1909
        return status;
 
1910
}
 
1911
 
 
1912
 
 
1913
/*
 
1914
 *      This function is just a hack to get the oid of our Large Object oid type.
 
1915
 *      If a real Large Object oid type is made part of Postgres, this function
 
1916
 *      will go away and the define 'PG_TYPE_LO' will be updated.
 
1917
 */
 
1918
void
 
1919
CC_lookup_lo(ConnectionClass *self)
 
1920
{
 
1921
        HSTMT           hstmt;
 
1922
        StatementClass *stmt;
 
1923
        RETCODE         result;
 
1924
        CSTR func = "CC_lookup_lo";
 
1925
 
 
1926
        mylog("%s: entering...\n", func);
 
1927
 
 
1928
/*
 
1929
 *      This function must use the local odbc API functions since the odbc state
 
1930
 *      has not transitioned to "connected" yet.
 
1931
 */
 
1932
        result = PGAPI_AllocStmt(self, &hstmt);
 
1933
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1934
                return;
 
1935
        stmt = (StatementClass *) hstmt;
 
1936
 
 
1937
        result = PGAPI_ExecDirect(hstmt, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'", SQL_NTS);
 
1938
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1939
        {
 
1940
                PGAPI_FreeStmt(hstmt, SQL_DROP);
 
1941
                return;
 
1942
        }
 
1943
 
 
1944
        result = PGAPI_Fetch(hstmt);
 
1945
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1946
        {
 
1947
                PGAPI_FreeStmt(hstmt, SQL_DROP);
 
1948
                return;
 
1949
        }
 
1950
 
 
1951
        result = PGAPI_GetData(hstmt, 1, SQL_C_SLONG, &self->lobj_type, sizeof(self->lobj_type), NULL);
 
1952
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1953
        {
 
1954
                PGAPI_FreeStmt(hstmt, SQL_DROP);
 
1955
                return;
 
1956
        }
 
1957
 
 
1958
        mylog("Got the large object oid: %d\n", self->lobj_type);
 
1959
        qlog("    [ Large Object oid = %d ]\n", self->lobj_type);
 
1960
 
 
1961
        result = PGAPI_FreeStmt(hstmt, SQL_DROP);
 
1962
}
 
1963
 
 
1964
 
 
1965
/*
 
1966
 *      This function initializes the version of PostgreSQL from
 
1967
 *      connInfo.protocol that we're connected to.
 
1968
 *      h-inoue 01-2-2001
 
1969
 */
 
1970
void
 
1971
CC_initialize_pg_version(ConnectionClass *self)
 
1972
{
 
1973
        strcpy(self->pg_version, self->connInfo.protocol);
 
1974
        if (PROTOCOL_62(&self->connInfo))
 
1975
        {
 
1976
                self->pg_version_number = (float) 6.2;
 
1977
                self->pg_version_major = 6;
 
1978
                self->pg_version_minor = 2;
 
1979
        }
 
1980
        else if (PROTOCOL_63(&self->connInfo))
 
1981
        {
 
1982
                self->pg_version_number = (float) 6.3;
 
1983
                self->pg_version_major = 6;
 
1984
                self->pg_version_minor = 3;
 
1985
        }
 
1986
        else
 
1987
        {
 
1988
                self->pg_version_number = (float) 6.4;
 
1989
                self->pg_version_major = 6;
 
1990
                self->pg_version_minor = 4;
 
1991
        }
 
1992
}
 
1993
 
 
1994
 
 
1995
/*
 
1996
 *      This function gets the version of PostgreSQL that we're connected to.
 
1997
 *      This is used to return the correct info in SQLGetInfo
 
1998
 *      DJP - 25-1-2001
 
1999
 */
 
2000
void
 
2001
CC_lookup_pg_version(ConnectionClass *self)
 
2002
{
 
2003
        HSTMT           hstmt;
 
2004
        StatementClass *stmt;
 
2005
        RETCODE         result;
 
2006
        char            szVersion[32];
 
2007
        int                     major,
 
2008
                                minor;
 
2009
        CSTR            func = "CC_lookup_pg_version";
 
2010
 
 
2011
        mylog("%s: entering...\n", func);
 
2012
 
 
2013
/*
 
2014
 *      This function must use the local odbc API functions since the odbc state
 
2015
 *      has not transitioned to "connected" yet.
 
2016
 */
 
2017
        result = PGAPI_AllocStmt(self, &hstmt);
 
2018
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2019
                return;
 
2020
        stmt = (StatementClass *) hstmt;
 
2021
 
 
2022
        /* get the server's version if possible  */
 
2023
        result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS);
 
2024
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2025
        {
 
2026
                PGAPI_FreeStmt(hstmt, SQL_DROP);
 
2027
                return;
 
2028
        }
 
2029
 
 
2030
        result = PGAPI_Fetch(hstmt);
 
2031
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2032
        {
 
2033
                PGAPI_FreeStmt(hstmt, SQL_DROP);
 
2034
                return;
 
2035
        }
 
2036
 
 
2037
        result = PGAPI_GetData(hstmt, 1, SQL_C_CHAR, self->pg_version, MAX_INFO_STRING, NULL);
 
2038
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2039
        {
 
2040
                PGAPI_FreeStmt(hstmt, SQL_DROP);
 
2041
                return;
 
2042
        }
 
2043
 
 
2044
        /*
 
2045
         * Extract the Major and Minor numbers from the string. This assumes
 
2046
         * the string starts 'Postgresql X.X'
 
2047
         */
 
2048
        strcpy(szVersion, "0.0");
 
2049
        if (sscanf(self->pg_version, "%*s %d.%d", &major, &minor) >= 2)
 
2050
        {
 
2051
                sprintf(szVersion, "%d.%d", major, minor);
 
2052
                self->pg_version_major = major;
 
2053
                self->pg_version_minor = minor;
 
2054
        }
 
2055
        self->pg_version_number = (float) atof(szVersion);
 
2056
        if (PG_VERSION_GE(self, 7.3))
 
2057
                self->schema_support = 1;
 
2058
 
 
2059
        mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version);
 
2060
        mylog("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number);
 
2061
        qlog("    [ PostgreSQL version string = '%s' ]\n", self->pg_version);
 
2062
        qlog("    [ PostgreSQL version number = '%1.1f' ]\n", self->pg_version_number);
 
2063
 
 
2064
        result = PGAPI_FreeStmt(hstmt, SQL_DROP);
 
2065
}
 
2066
 
 
2067
 
 
2068
void
 
2069
CC_log_error(const char *func, const char *desc, const ConnectionClass *self)
 
2070
{
 
2071
#ifdef PRN_NULLCHECK
 
2072
#define nullcheck(a) (a ? a : "(NULL)")
 
2073
#endif
 
2074
 
 
2075
        if (self)
 
2076
        {
 
2077
                qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
 
2078
                mylog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
 
2079
                qlog("            ------------------------------------------------------------\n");
 
2080
                qlog("            henv=%u, conn=%u, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts);
 
2081
                qlog("            sock=%u, stmts=%u, lobj_type=%d\n", self->sock, self->stmts, self->lobj_type);
 
2082
 
 
2083
                qlog("            ---------------- Socket Info -------------------------------\n");
 
2084
                if (self->sock)
 
2085
                {
 
2086
                        SocketClass *sock = self->sock;
 
2087
 
 
2088
                        qlog("            socket=%d, reverse=%d, errornumber=%d, errormsg='%s'\n", sock->socket, sock->reverse, sock->errornumber, nullcheck(sock->errormsg));
 
2089
                        qlog("            buffer_in=%u, buffer_out=%u\n", sock->buffer_in, sock->buffer_out);
 
2090
                        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);
 
2091
                }
 
2092
        }
 
2093
        else
 
2094
{
 
2095
                qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
 
2096
                mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
 
2097
}
 
2098
#undef PRN_NULLCHECK
 
2099
}
 
2100
 
 
2101
int
 
2102
CC_get_max_query_len(const ConnectionClass *conn)
 
2103
{
 
2104
        int                     value;
 
2105
 
 
2106
        /* Long Queries in 7.0+ */
 
2107
        if (PG_VERSION_GE(conn, 7.0))
 
2108
                value = 0 /* MAX_STATEMENT_LEN */ ;
 
2109
        /* Prior to 7.0 we used 2*BLCKSZ */
 
2110
        else if (PG_VERSION_GE(conn, 6.5))
 
2111
                value = (2 * BLCKSZ);
 
2112
        else
 
2113
                /* Prior to 6.5 we used BLCKSZ */
 
2114
                value = BLCKSZ;
 
2115
        return value;
 
2116
}
 
2117
 
 
2118
/*
 
2119
 *      This deosn't really return the CURRENT SCHEMA
 
2120
 *      but there's no alternative.
 
2121
 */
 
2122
const char *
 
2123
CC_get_current_schema(ConnectionClass *conn)
 
2124
{
 
2125
        if (!conn->current_schema && conn->schema_support)
 
2126
        {
 
2127
                QResultClass    *res;
 
2128
 
 
2129
                if (res = CC_send_query(conn, "select current_schema()", NULL, CLEAR_RESULT_ON_ABORT), res)
 
2130
                {
 
2131
                        if (QR_get_num_total_tuples(res) == 1)
 
2132
                                conn->current_schema = strdup(QR_get_value_backend_row(res, 0, 0));
 
2133
                        QR_Destructor(res);
 
2134
                }
 
2135
        }
 
2136
        return (const char *) conn->current_schema;
 
2137
}
 
2138
 
 
2139
int
 
2140
CC_send_cancel_request(const ConnectionClass *conn)
 
2141
{
 
2142
#ifdef WIN32
 
2143
        int                     save_errno = (WSAGetLastError());
 
2144
#else
 
2145
        int                     save_errno = errno;
 
2146
#endif
 
2147
        int                     tmpsock = -1;
 
2148
        struct
 
2149
        {
 
2150
                uint32          packetlen;
 
2151
                CancelRequestPacket cp;
 
2152
        }                       crp;
 
2153
 
 
2154
        /* Check we have an open connection */
 
2155
        if (!conn)
 
2156
                return FALSE;
 
2157
 
 
2158
        if (conn->sock == NULL )
 
2159
        {
 
2160
                return FALSE;
 
2161
        }
 
2162
 
 
2163
        /*
 
2164
         * We need to open a temporary connection to the postmaster. Use the
 
2165
         * information saved by connectDB to do this with only kernel calls.
 
2166
        */
 
2167
        if ((tmpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 
2168
        {
 
2169
                return FALSE;
 
2170
        }
 
2171
        if (connect(tmpsock, (struct sockaddr *)&(conn->sock->sadr),
 
2172
                                sizeof(conn->sock->sadr)) < 0)
 
2173
        {
 
2174
                return FALSE;
 
2175
        }
 
2176
 
 
2177
        /*
 
2178
         * We needn't set nonblocking I/O or NODELAY options here.
 
2179
         */
 
2180
        crp.packetlen = htonl((uint32) sizeof(crp));
 
2181
        crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);
 
2182
        crp.cp.backendPID = htonl(conn->be_pid);
 
2183
        crp.cp.cancelAuthCode = htonl(conn->be_key);
 
2184
 
 
2185
        if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp))
 
2186
        {
 
2187
                return FALSE;
 
2188
        }
 
2189
 
 
2190
        /* Sent it, done */
 
2191
        closesocket(tmpsock);
 
2192
#ifdef WIN32
 
2193
        WSASetLastError(save_errno);
 
2194
#else
 
2195
        errno = save_errno;
 
2196
#endif
 
2197
        return TRUE;
 
2198
}