~ubuntu-branches/ubuntu/trusty/psqlodbc/trusty-proposed

« back to all changes in this revision

Viewing changes to environ.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-10-24 07:21:55 UTC
  • mfrom: (16.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20131024072155-xlf5odyk3iblcd51
Tags: 1:09.02.0100-2ubuntu1
* Merge with Debian unstable. Remaining Ubuntu changes:
  - debian/tests: Disable iodbc test and dependency, as in Ubuntu iodbc and
    unixodbc are not installable in parallel, and iodbc is obsolete and
    should be removed at some point.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-------
2
 
 * Module:                      environ.c
3
 
 *
4
 
 * Description:         This module contains routines related to
5
 
 *                                      the environment, such as storing connection handles,
6
 
 *                                      and returning errors.
7
 
 *
8
 
 * Classes:                     EnvironmentClass (Functions prefix: "EN_")
9
 
 *
10
 
 * API functions:       SQLAllocEnv, SQLFreeEnv, SQLError
11
 
 *
12
 
 * Comments:            See "notice.txt" for copyright and license information.
13
 
 *-------
14
 
 */
15
 
 
16
 
#include "environ.h"
17
 
 
18
 
#include "connection.h"
19
 
#include "dlg_specific.h"
20
 
#include "statement.h"
21
 
#include <stdlib.h>
22
 
#include <string.h>
23
 
#include "pgapifunc.h"
24
 
#ifdef  WIN32
25
 
#include <winsock2.h>
26
 
#endif /* WIN32 */
27
 
#include "loadlib.h"
28
 
 
29
 
extern GLOBAL_VALUES globals;
30
 
 
31
 
/* The one instance of the handles */
32
 
static int conns_count = 0;
33
 
static ConnectionClass **conns = NULL;
34
 
 
35
 
#if defined(WIN_MULTITHREAD_SUPPORT)
36
 
CRITICAL_SECTION        conns_cs;
37
 
CRITICAL_SECTION        common_cs; /* commonly used for short term blocking */
38
 
CRITICAL_SECTION        common_lcs; /* commonly used for not necessarily short term blocking */
39
 
#elif defined(POSIX_MULTITHREAD_SUPPORT)
40
 
pthread_mutex_t     conns_cs;
41
 
pthread_mutex_t     common_cs;
42
 
pthread_mutex_t     common_lcs;
43
 
#endif /* WIN_MULTITHREAD_SUPPORT */
44
 
 
45
 
void    shortterm_common_lock()
46
 
{
47
 
        ENTER_COMMON_CS;
48
 
}
49
 
void    shortterm_common_unlock()
50
 
{
51
 
        LEAVE_COMMON_CS;
52
 
}
53
 
 
54
 
int     getConnCount()
55
 
{
56
 
        return conns_count;
57
 
}
58
 
ConnectionClass * const *getConnList()
59
 
{
60
 
        return conns;
61
 
}
62
 
 
63
 
RETCODE         SQL_API
64
 
PGAPI_AllocEnv(HENV FAR * phenv)
65
 
{
66
 
        CSTR func = "PGAPI_AllocEnv";
67
 
        SQLRETURN       ret = SQL_SUCCESS;
68
 
 
69
 
        mylog("**** in %s ** \n", func);
70
 
 
71
 
        /*
72
 
         * Hack for systems on which none of the constructor-making techniques
73
 
         * in psqlodbc.c work: if globals appears not to have been
74
 
         * initialized, then cause it to be initialized.  Since this should be
75
 
         * the first function called in this shared library, doing it here
76
 
         * should work.
77
 
         */
78
 
        if (globals.socket_buffersize <= 0)
79
 
        {
80
 
                initialize_global_cs();
81
 
                getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
82
 
        }
83
 
 
84
 
        *phenv = (HENV) EN_Constructor();
85
 
        if (!*phenv)
86
 
        {
87
 
                *phenv = SQL_NULL_HENV;
88
 
                EN_log_error(func, "Error allocating environment", NULL);
89
 
                ret = SQL_ERROR;
90
 
        }
91
 
 
92
 
        mylog("** exit %s: phenv = %p **\n", func, *phenv);
93
 
        return ret;
94
 
}
95
 
 
96
 
 
97
 
RETCODE         SQL_API
98
 
PGAPI_FreeEnv(HENV henv)
99
 
{
100
 
        CSTR func = "PGAPI_FreeEnv";
101
 
        SQLRETURN       ret = SQL_SUCCESS;
102
 
        EnvironmentClass *env = (EnvironmentClass *) henv;
103
 
 
104
 
        mylog("**** in PGAPI_FreeEnv: env = %p ** \n", env);
105
 
 
106
 
        if (env && EN_Destructor(env))
107
 
        {
108
 
#ifdef  _HANDLE_ENLIST_IN_DTC_
109
 
                CALL_DtcOnRelease();
110
 
#endif /* _HANDLE_ENLIST_IN_DTC_ */
111
 
                mylog("   ok\n");
112
 
                goto cleanup;
113
 
        }
114
 
 
115
 
        mylog("    error\n");
116
 
        ret = SQL_ERROR;
117
 
        EN_log_error(func, "Error freeing environment", env);
118
 
cleanup:
119
 
        return ret;
120
 
}
121
 
 
122
 
 
123
 
static void
124
 
pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const UCHAR *ver3str, const UCHAR *ver2str)
125
 
{
126
 
        strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str);
127
 
}
128
 
 
129
 
PG_ErrorInfo    *ER_Constructor(SDWORD errnumber, const char *msg)
130
 
{
131
 
        PG_ErrorInfo    *error;
132
 
        ssize_t         aladd, errsize;
133
 
 
134
 
        if (DESC_OK == errnumber)
135
 
                return NULL;
136
 
        if (msg)
137
 
        {
138
 
                errsize = strlen(msg);
139
 
                aladd = errsize;
140
 
        }
141
 
        else
142
 
        {
143
 
                errsize = -1;
144
 
                aladd = 0;
145
 
        }
146
 
        error = (PG_ErrorInfo *) malloc(sizeof(PG_ErrorInfo) + aladd);
147
 
        if (error)
148
 
        {
149
 
                memset(error, 0, sizeof(PG_ErrorInfo));
150
 
                error->status = errnumber;
151
 
                error->errorsize = (Int4) errsize;
152
 
                if (errsize > 0)
153
 
                        memcpy(error->__error_message, msg, errsize);
154
 
                error->__error_message[aladd] = '\0';
155
 
                error->recsize = -1;
156
 
        }
157
 
        return error;
158
 
}
159
 
 
160
 
void
161
 
ER_Destructor(PG_ErrorInfo *self)
162
 
{
163
 
        free(self);
164
 
}
165
 
 
166
 
PG_ErrorInfo *ER_Dup(const PG_ErrorInfo *self)
167
 
{
168
 
        PG_ErrorInfo    *new;
169
 
        Int4            alsize;
170
 
 
171
 
        if (!self)
172
 
                return NULL;
173
 
        alsize = sizeof(PG_ErrorInfo);
174
 
        if (self->errorsize  > 0)
175
 
                alsize += self->errorsize;
176
 
        new = (PG_ErrorInfo *) malloc(alsize);
177
 
        memcpy(new, self, alsize);
178
 
 
179
 
        return new;
180
 
}
181
 
 
182
 
#define DRVMNGRDIV      511
183
 
/*              Returns the next SQL error information. */
184
 
RETCODE         SQL_API
185
 
ER_ReturnError(PG_ErrorInfo **pgerror,
186
 
                SQLSMALLINT     RecNumber,
187
 
                SQLCHAR FAR * szSqlState,
188
 
                SQLINTEGER FAR * pfNativeError,
189
 
                SQLCHAR FAR * szErrorMsg,
190
 
                SQLSMALLINT cbErrorMsgMax,
191
 
                SQLSMALLINT FAR * pcbErrorMsg,
192
 
                UWORD flag)
193
 
{
194
 
        CSTR func = "ER_ReturnError";
195
 
        /* CC: return an error of a hstmt  */
196
 
        PG_ErrorInfo    *error;
197
 
        BOOL            partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
198
 
                        clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
199
 
        const char      *msg;
200
 
        SWORD           msglen, stapos, wrtlen, pcblen;
201
 
 
202
 
        if (!pgerror || !*pgerror)
203
 
                return SQL_NO_DATA_FOUND;
204
 
        error = *pgerror;
205
 
        msg = error->__error_message;
206
 
        mylog("%s: status = %d, msg = #%s#\n", func, error->status, msg);
207
 
        msglen = (SQLSMALLINT) strlen(msg);
208
 
        /*
209
 
         *      Even though an application specifies a larger error message
210
 
         *      buffer, the driver manager changes it silently.
211
 
         *      Therefore we divide the error message into ... 
212
 
         */
213
 
        if (error->recsize < 0)
214
 
        {
215
 
                if (cbErrorMsgMax > 0)
216
 
                        error->recsize = cbErrorMsgMax - 1; /* apply the first request */
217
 
                else
218
 
                        error->recsize = DRVMNGRDIV;
219
 
        }
220
 
        if (RecNumber < 0)
221
 
        {
222
 
                if (0 == error->errorpos)
223
 
                        RecNumber = 1;
224
 
                else
225
 
                        RecNumber = 2 + (error->errorpos - 1) / error->recsize;
226
 
        }
227
 
        stapos = (RecNumber - 1) * error->recsize;
228
 
        if (stapos > msglen)
229
 
                return SQL_NO_DATA_FOUND; 
230
 
        pcblen = wrtlen = msglen - stapos;
231
 
        if (pcblen > error->recsize)
232
 
                pcblen = error->recsize;
233
 
        if (0 == cbErrorMsgMax)
234
 
                wrtlen = 0; 
235
 
        else if (wrtlen >= cbErrorMsgMax)
236
 
        {
237
 
                if (partial_ok)
238
 
                        wrtlen = cbErrorMsgMax - 1;
239
 
                else if (cbErrorMsgMax <= error->recsize)
240
 
                        wrtlen = 0;
241
 
                else 
242
 
                        wrtlen = error->recsize;
243
 
        }
244
 
        if (wrtlen > pcblen)
245
 
                wrtlen = pcblen;
246
 
        if (NULL != pcbErrorMsg)
247
 
                *pcbErrorMsg = pcblen;
248
 
 
249
 
        if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
250
 
        {
251
 
                memcpy(szErrorMsg, msg + stapos, wrtlen);
252
 
                szErrorMsg[wrtlen] = '\0';
253
 
        }
254
 
 
255
 
        if (NULL != pfNativeError)
256
 
                *pfNativeError = error->status;
257
 
 
258
 
        if (NULL != szSqlState)
259
 
                strncpy_null(szSqlState, error->sqlstate, 6);
260
 
 
261
 
        mylog("      szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg);
262
 
        if (clear_str)
263
 
        {
264
 
                error->errorpos = stapos + wrtlen;
265
 
                if (error->errorpos >= msglen)
266
 
                {
267
 
                        ER_Destructor(error);
268
 
                        *pgerror = NULL;
269
 
                }
270
 
        }
271
 
        if (wrtlen == 0)
272
 
                return SQL_SUCCESS_WITH_INFO;
273
 
        else
274
 
                return SQL_SUCCESS;
275
 
}
276
 
 
277
 
 
278
 
RETCODE         SQL_API
279
 
PGAPI_ConnectError(     HDBC hdbc,
280
 
                        SQLSMALLINT     RecNumber,
281
 
                        SQLCHAR FAR * szSqlState,
282
 
                        SQLINTEGER FAR * pfNativeError,
283
 
                        SQLCHAR FAR * szErrorMsg,
284
 
                        SQLSMALLINT cbErrorMsgMax,
285
 
                        SQLSMALLINT FAR * pcbErrorMsg,
286
 
                        UWORD flag)
287
 
{
288
 
        ConnectionClass *conn = (ConnectionClass *) hdbc;
289
 
        EnvironmentClass *env = (EnvironmentClass *) conn->henv;
290
 
        char            *msg;
291
 
        int             status;
292
 
        BOOL    once_again = FALSE;
293
 
        ssize_t         msglen;
294
 
 
295
 
        mylog("**** PGAPI_ConnectError: hdbc=%p <%d>\n", hdbc, cbErrorMsgMax);
296
 
        if (RecNumber != 1 && RecNumber != -1)
297
 
                return SQL_NO_DATA_FOUND;
298
 
        if (cbErrorMsgMax < 0)
299
 
                return SQL_ERROR;
300
 
        if (CONN_EXECUTING == conn->status || !CC_get_error(conn, &status, &msg) || NULL == msg)
301
 
        {
302
 
                mylog("CC_Get_error returned nothing.\n");
303
 
                if (NULL != szSqlState)
304
 
                        strcpy(szSqlState, "00000");
305
 
                if (NULL != pcbErrorMsg)
306
 
                        *pcbErrorMsg = 0;
307
 
                if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
308
 
                        szErrorMsg[0] = '\0';
309
 
 
310
 
                return SQL_NO_DATA_FOUND;
311
 
        }
312
 
        mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg);
313
 
 
314
 
        msglen = strlen(msg);
315
 
        if (NULL != pcbErrorMsg)
316
 
        {
317
 
                *pcbErrorMsg = (SQLSMALLINT) msglen;
318
 
                if (cbErrorMsgMax == 0)
319
 
                        once_again = TRUE;
320
 
                else if (msglen >= cbErrorMsgMax)
321
 
                        *pcbErrorMsg = cbErrorMsgMax - 1;
322
 
        }
323
 
        if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
324
 
                strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
325
 
        if (NULL != pfNativeError)
326
 
                *pfNativeError = status;
327
 
 
328
 
        if (NULL != szSqlState)
329
 
        {
330
 
                if (conn->sqlstate[0])
331
 
                        strcpy(szSqlState, conn->sqlstate);
332
 
                else    
333
 
                switch (status)
334
 
                {
335
 
                        case CONN_OPTION_VALUE_CHANGED:
336
 
                                pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
337
 
                                break;
338
 
                        case CONN_TRUNCATED:
339
 
                                pg_sqlstate_set(env, szSqlState, "01004", "01004");
340
 
                                /* data truncated */
341
 
                                break;
342
 
                        case CONN_INIREAD_ERROR:
343
 
                                pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
344
 
                                /* data source not found */
345
 
                                break;
346
 
                        case CONNECTION_SERVER_NOT_REACHED:
347
 
                        case CONN_OPENDB_ERROR:
348
 
                                pg_sqlstate_set(env, szSqlState, "08001", "08001");
349
 
                                /* unable to connect to data source */
350
 
                                break;
351
 
                        case CONN_INVALID_AUTHENTICATION:
352
 
                        case CONN_AUTH_TYPE_UNSUPPORTED:
353
 
                                pg_sqlstate_set(env, szSqlState, "28000", "28000");
354
 
                                break;
355
 
                        case CONN_STMT_ALLOC_ERROR:
356
 
                                pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
357
 
                                /* memory allocation failure */
358
 
                                break;
359
 
                        case CONN_IN_USE:
360
 
                                pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
361
 
                                /* general error */
362
 
                                break;
363
 
                        case CONN_UNSUPPORTED_OPTION:
364
 
                                pg_sqlstate_set(env, szSqlState, "HYC00", "IM001");
365
 
                                /* driver does not support this function */
366
 
                                break;
367
 
                        case CONN_INVALID_ARGUMENT_NO:
368
 
                                pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
369
 
                                /* invalid argument value */
370
 
                                break;
371
 
                        case CONN_TRANSACT_IN_PROGRES:
372
 
                                pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
373
 
 
374
 
                                /*
375
 
                                 * when the user tries to switch commit mode in a
376
 
                                 * transaction
377
 
                                 */
378
 
                                /* -> function sequence error */
379
 
                                break;
380
 
                        case CONN_NO_MEMORY_ERROR:
381
 
                                pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
382
 
                                break;
383
 
                        case CONN_NOT_IMPLEMENTED_ERROR:
384
 
                                pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
385
 
                                break;
386
 
                        case CONN_VALUE_OUT_OF_RANGE:
387
 
                                pg_sqlstate_set(env, szSqlState, "HY019", "22003");
388
 
                                break;
389
 
                        case CONNECTION_COULD_NOT_SEND:
390
 
                        case CONNECTION_COULD_NOT_RECEIVE:
391
 
                        case CONNECTION_COMMUNICATION_ERROR:
392
 
                        case CONNECTION_NO_RESPONSE:
393
 
                                pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
394
 
                                break;
395
 
                        default:
396
 
                                pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
397
 
                                /* general error */
398
 
                                break;
399
 
                }
400
 
        }
401
 
 
402
 
        mylog("      szSqlState = '%s',len=%d, szError='%s'\n", szSqlState ? (char *) szSqlState : PRINT_NULL, msglen, szErrorMsg ? (char *) szErrorMsg : PRINT_NULL);
403
 
        if (once_again)
404
 
        {
405
 
                CC_set_errornumber(conn, status);
406
 
                return SQL_SUCCESS_WITH_INFO;
407
 
        }
408
 
        else
409
 
                return SQL_SUCCESS;
410
 
}
411
 
 
412
 
RETCODE         SQL_API
413
 
PGAPI_EnvError(         HENV henv,
414
 
                        SQLSMALLINT     RecNumber,
415
 
                        SQLCHAR FAR * szSqlState,
416
 
                        SQLINTEGER FAR * pfNativeError,
417
 
                        SQLCHAR FAR * szErrorMsg,
418
 
                        SQLSMALLINT cbErrorMsgMax,
419
 
                        SQLSMALLINT FAR * pcbErrorMsg,
420
 
                        UWORD flag)
421
 
{
422
 
        EnvironmentClass *env = (EnvironmentClass *) henv;
423
 
        char            *msg;
424
 
        int             status;
425
 
 
426
 
        mylog("**** PGAPI_EnvError: henv=%p <%d>\n", henv, cbErrorMsgMax);
427
 
        if (RecNumber != 1 && RecNumber != -1)
428
 
                return SQL_NO_DATA_FOUND;
429
 
        if (cbErrorMsgMax < 0)
430
 
                return SQL_ERROR;
431
 
        if (!EN_get_error(env, &status, &msg) || NULL == msg)
432
 
        {
433
 
                        mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
434
 
                
435
 
                if (NULL != szSqlState)
436
 
                        pg_sqlstate_set(env, szSqlState, "00000", "00000");
437
 
                if (NULL != pcbErrorMsg)
438
 
                        *pcbErrorMsg = 0;
439
 
                if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
440
 
                        szErrorMsg[0] = '\0';
441
 
 
442
 
                return SQL_NO_DATA_FOUND;
443
 
        }
444
 
        mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
445
 
 
446
 
        if (NULL != pcbErrorMsg)
447
 
                *pcbErrorMsg = (SQLSMALLINT) strlen(msg);
448
 
        if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
449
 
                strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
450
 
        if (NULL != pfNativeError)
451
 
                *pfNativeError = status;
452
 
 
453
 
        if (szSqlState)
454
 
        {
455
 
                switch (status)
456
 
                {
457
 
                        case ENV_ALLOC_ERROR:
458
 
                                /* memory allocation failure */
459
 
                                pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
460
 
                                break;
461
 
                        default:
462
 
                                pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
463
 
                                /* general error */
464
 
                                break;
465
 
                }
466
 
        }
467
 
 
468
 
        return SQL_SUCCESS;
469
 
}
470
 
 
471
 
 
472
 
/*              Returns the next SQL error information. */
473
 
RETCODE         SQL_API
474
 
PGAPI_Error(
475
 
                        HENV henv,
476
 
                        HDBC hdbc,
477
 
                        HSTMT hstmt,
478
 
                        SQLCHAR FAR * szSqlState,
479
 
                        SQLINTEGER FAR * pfNativeError,
480
 
                        SQLCHAR FAR * szErrorMsg,
481
 
                        SQLSMALLINT cbErrorMsgMax,
482
 
                        SQLSMALLINT FAR * pcbErrorMsg)
483
 
{
484
 
        RETCODE ret;
485
 
        UWORD   flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR;
486
 
 
487
 
        mylog("**** PGAPI_Error: henv=%p, hdbc=%p hstmt=%d\n", henv, hdbc, hstmt);
488
 
 
489
 
        if (cbErrorMsgMax < 0)
490
 
                return SQL_ERROR;
491
 
        if (SQL_NULL_HSTMT != hstmt)
492
 
                ret = PGAPI_StmtError(hstmt, -1, szSqlState, pfNativeError,
493
 
                         szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
494
 
        else if (SQL_NULL_HDBC != hdbc)
495
 
                ret = PGAPI_ConnectError(hdbc, -1, szSqlState, pfNativeError,
496
 
                         szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
497
 
        else if (SQL_NULL_HENV != henv)
498
 
                ret = PGAPI_EnvError(henv, -1, szSqlState, pfNativeError,
499
 
                         szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
500
 
        else
501
 
        {
502
 
                if (NULL != szSqlState)
503
 
                        strcpy(szSqlState, "00000");
504
 
                if (NULL != pcbErrorMsg)
505
 
                        *pcbErrorMsg = 0;
506
 
                if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
507
 
                        szErrorMsg[0] = '\0';
508
 
 
509
 
                ret = SQL_NO_DATA_FOUND;
510
 
        }
511
 
        mylog("**** PGAPI_Error exit code=%d\n", ret);
512
 
        return ret;
513
 
}
514
 
 
515
 
/*
516
 
 * EnvironmentClass implementation
517
 
 */
518
 
EnvironmentClass *
519
 
EN_Constructor(void)
520
 
{
521
 
        EnvironmentClass *rv = NULL;
522
 
#ifdef WIN32
523
 
        WORD            wVersionRequested;
524
 
        WSADATA         wsaData;
525
 
        const int       major = 2, minor = 2;
526
 
 
527
 
        /* Load the WinSock Library */
528
 
        wVersionRequested = MAKEWORD(major, minor);
529
 
 
530
 
        if (WSAStartup(wVersionRequested, &wsaData))
531
 
        {
532
 
                mylog("%s: WSAStartup error\n", __FUNCTION__);
533
 
                return rv;
534
 
        }
535
 
        /* Verify that this is the minimum version of WinSock */
536
 
        if (LOBYTE(wsaData.wVersion) >= 1 &&
537
 
            (LOBYTE(wsaData.wVersion) >= 2 ||
538
 
             HIBYTE(wsaData.wVersion) >= 1))
539
 
                ;
540
 
        else
541
 
        {
542
 
                mylog("%s: WSAStartup version=(%d,%d)\n", __FUNCTION__,
543
 
                        LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
544
 
                goto cleanup;
545
 
        }
546
 
#endif /* WIN32 */
547
 
 
548
 
        rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass));
549
 
        if (NULL == rv)
550
 
        {
551
 
                mylog("%s: malloc error\n", __FUNCTION__);
552
 
                goto cleanup;
553
 
        }
554
 
        rv->errormsg = 0;
555
 
        rv->errornumber = 0;
556
 
        rv->flag = 0;
557
 
        INIT_ENV_CS(rv);
558
 
cleanup:
559
 
#ifdef WIN32
560
 
        if (NULL == rv)
561
 
        {
562
 
                WSACleanup();
563
 
        }
564
 
#endif /* WIN32 */
565
 
 
566
 
        return rv;
567
 
}
568
 
 
569
 
 
570
 
char
571
 
EN_Destructor(EnvironmentClass *self)
572
 
{
573
 
        int             lf, nullcnt;
574
 
        char            rv = 1;
575
 
 
576
 
        mylog("in EN_Destructor, self=%p\n", self);
577
 
        if (!self)
578
 
                return 0;
579
 
 
580
 
        /*
581
 
         * the error messages are static strings distributed throughout the
582
 
         * source--they should not be freed
583
 
         */
584
 
 
585
 
        /* Free any connections belonging to this environment */
586
 
        for (lf = 0, nullcnt = 0; lf < conns_count; lf++)
587
 
        {
588
 
                if (NULL == conns[lf])
589
 
                        nullcnt++;
590
 
                else if (conns[lf]->henv == self)
591
 
                {
592
 
                        if (CC_Destructor(conns[lf]))
593
 
                                conns[lf] = NULL;
594
 
                        else
595
 
                                rv = 0;
596
 
                        nullcnt++;
597
 
                }
598
 
        }
599
 
        if (conns && nullcnt >= conns_count)
600
 
        {
601
 
                mylog("clearing conns count=%d\n", conns_count);
602
 
                free(conns);
603
 
                conns = NULL;
604
 
                conns_count = 0;
605
 
        }
606
 
        DELETE_ENV_CS(self);
607
 
        free(self);
608
 
 
609
 
#ifdef WIN32
610
 
        WSACleanup();
611
 
#endif
612
 
        mylog("exit EN_Destructor: rv = %d\n", rv);
613
 
#ifdef  _MEMORY_DEBUG_
614
 
        debug_memory_check();
615
 
#endif   /* _MEMORY_DEBUG_ */
616
 
        return rv;
617
 
}
618
 
 
619
 
 
620
 
char
621
 
EN_get_error(EnvironmentClass *self, int *number, char **message)
622
 
{
623
 
        if (self && self->errormsg && self->errornumber)
624
 
        {
625
 
                *message = self->errormsg;
626
 
                *number = self->errornumber;
627
 
                self->errormsg = 0;
628
 
                self->errornumber = 0;
629
 
                return 1;
630
 
        }
631
 
        else
632
 
                return 0;
633
 
}
634
 
 
635
 
#define INIT_CONN_COUNT 128
636
 
 
637
 
char
638
 
EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
639
 
{
640
 
        int     i, alloc;
641
 
        ConnectionClass **newa;
642
 
        char    ret = FALSE;
643
 
 
644
 
        mylog("EN_add_connection: self = %p, conn = %p\n", self, conn);
645
 
 
646
 
        ENTER_CONNS_CS;
647
 
        for (i = 0; i < conns_count; i++)
648
 
        {
649
 
                if (!conns[i])
650
 
                {
651
 
                        conn->henv = self;
652
 
                        conns[i] = conn;
653
 
                        ret = TRUE;
654
 
                        mylog("       added at i=%d, conn->henv = %p, conns[i]->henv = %p\n", i, conn->henv, conns[i]->henv);
655
 
                        goto cleanup;
656
 
                }
657
 
        }
658
 
        if (conns_count > 0)
659
 
                alloc = 2 * conns_count;
660
 
        else
661
 
                alloc = INIT_CONN_COUNT;
662
 
        if (newa = (ConnectionClass **) realloc(conns, alloc * sizeof(ConnectionClass *)), NULL == newa)
663
 
                goto cleanup;
664
 
        conn->henv = self;
665
 
        newa[conns_count] = conn;
666
 
        conns = newa;
667
 
        ret = TRUE;
668
 
        mylog("       added at %d, conn->henv = %p, conns[%d]->henv = %p\n", conns_count, conn->henv, conns_count, conns[conns_count]->henv);
669
 
        for (i = conns_count + 1; i < alloc; i++)
670
 
                conns[i] = NULL; 
671
 
        conns_count = alloc;
672
 
cleanup:
673
 
        LEAVE_CONNS_CS;
674
 
        return ret;
675
 
}
676
 
 
677
 
 
678
 
char
679
 
EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn)
680
 
{
681
 
        int                     i;
682
 
 
683
 
        for (i = 0; i < conns_count; i++)
684
 
                if (conns[i] == conn && conns[i]->status != CONN_EXECUTING)
685
 
                {
686
 
                        ENTER_CONNS_CS;
687
 
                        conns[i] = NULL;
688
 
                        LEAVE_CONNS_CS;
689
 
                        return TRUE;
690
 
                }
691
 
 
692
 
        return FALSE;
693
 
}
694
 
 
695
 
 
696
 
void
697
 
EN_log_error(const char *func, char *desc, EnvironmentClass *self)
698
 
{
699
 
        if (self)
700
 
                qlog("ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
701
 
        else
702
 
                qlog("INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
703
 
}
 
1
/*-------
 
2
 * Module:                      environ.c
 
3
 *
 
4
 * Description:         This module contains routines related to
 
5
 *                                      the environment, such as storing connection handles,
 
6
 *                                      and returning errors.
 
7
 *
 
8
 * Classes:                     EnvironmentClass (Functions prefix: "EN_")
 
9
 *
 
10
 * API functions:       SQLAllocEnv, SQLFreeEnv, SQLError
 
11
 *
 
12
 * Comments:            See "readme.txt" for copyright and license information.
 
13
 *-------
 
14
 */
 
15
 
 
16
#include "environ.h"
 
17
 
 
18
#include "connection.h"
 
19
#include "dlg_specific.h"
 
20
#include "statement.h"
 
21
#include <stdlib.h>
 
22
#include <string.h>
 
23
#include "pgapifunc.h"
 
24
#ifdef  WIN32
 
25
#include <winsock2.h>
 
26
#endif /* WIN32 */
 
27
#include "loadlib.h"
 
28
 
 
29
extern GLOBAL_VALUES globals;
 
30
 
 
31
/* The one instance of the handles */
 
32
static int conns_count = 0;
 
33
static ConnectionClass **conns = NULL;
 
34
 
 
35
#if defined(WIN_MULTITHREAD_SUPPORT)
 
36
CRITICAL_SECTION        conns_cs;
 
37
CRITICAL_SECTION        common_cs; /* commonly used for short term blocking */
 
38
CRITICAL_SECTION        common_lcs; /* commonly used for not necessarily short term blocking */
 
39
#elif defined(POSIX_MULTITHREAD_SUPPORT)
 
40
pthread_mutex_t     conns_cs;
 
41
pthread_mutex_t     common_cs;
 
42
pthread_mutex_t     common_lcs;
 
43
#endif /* WIN_MULTITHREAD_SUPPORT */
 
44
 
 
45
void    shortterm_common_lock()
 
46
{
 
47
        ENTER_COMMON_CS;
 
48
}
 
49
void    shortterm_common_unlock()
 
50
{
 
51
        LEAVE_COMMON_CS;
 
52
}
 
53
 
 
54
int     getConnCount()
 
55
{
 
56
        return conns_count;
 
57
}
 
58
ConnectionClass * const *getConnList()
 
59
{
 
60
        return conns;
 
61
}
 
62
 
 
63
RETCODE         SQL_API
 
64
PGAPI_AllocEnv(HENV FAR * phenv)
 
65
{
 
66
        CSTR func = "PGAPI_AllocEnv";
 
67
        SQLRETURN       ret = SQL_SUCCESS;
 
68
 
 
69
        mylog("**** in %s ** \n", func);
 
70
 
 
71
        /*
 
72
         * Hack for systems on which none of the constructor-making techniques
 
73
         * in psqlodbc.c work: if globals appears not to have been
 
74
         * initialized, then cause it to be initialized.  Since this should be
 
75
         * the first function called in this shared library, doing it here
 
76
         * should work.
 
77
         */
 
78
        if (globals.socket_buffersize <= 0)
 
79
        {
 
80
                initialize_global_cs();
 
81
                getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
 
82
        }
 
83
 
 
84
        *phenv = (HENV) EN_Constructor();
 
85
        if (!*phenv)
 
86
        {
 
87
                *phenv = SQL_NULL_HENV;
 
88
                EN_log_error(func, "Error allocating environment", NULL);
 
89
                ret = SQL_ERROR;
 
90
        }
 
91
 
 
92
        mylog("** exit %s: phenv = %p **\n", func, *phenv);
 
93
        return ret;
 
94
}
 
95
 
 
96
 
 
97
RETCODE         SQL_API
 
98
PGAPI_FreeEnv(HENV henv)
 
99
{
 
100
        CSTR func = "PGAPI_FreeEnv";
 
101
        SQLRETURN       ret = SQL_SUCCESS;
 
102
        EnvironmentClass *env = (EnvironmentClass *) henv;
 
103
 
 
104
        mylog("**** in PGAPI_FreeEnv: env = %p ** \n", env);
 
105
 
 
106
        if (env && EN_Destructor(env))
 
107
        {
 
108
#ifdef  _HANDLE_ENLIST_IN_DTC_
 
109
                CALL_DtcOnRelease();
 
110
#endif /* _HANDLE_ENLIST_IN_DTC_ */
 
111
                mylog("   ok\n");
 
112
                goto cleanup;
 
113
        }
 
114
 
 
115
        mylog("    error\n");
 
116
        ret = SQL_ERROR;
 
117
        EN_log_error(func, "Error freeing environment", env);
 
118
cleanup:
 
119
        return ret;
 
120
}
 
121
 
 
122
 
 
123
static void
 
124
pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const UCHAR *ver3str, const UCHAR *ver2str)
 
125
{
 
126
        strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str);
 
127
}
 
128
 
 
129
PG_ErrorInfo    *ER_Constructor(SDWORD errnumber, const char *msg)
 
130
{
 
131
        PG_ErrorInfo    *error;
 
132
        ssize_t         aladd, errsize;
 
133
 
 
134
        if (DESC_OK == errnumber)
 
135
                return NULL;
 
136
        if (msg)
 
137
        {
 
138
                errsize = strlen(msg);
 
139
                aladd = errsize;
 
140
        }
 
141
        else
 
142
        {
 
143
                errsize = -1;
 
144
                aladd = 0;
 
145
        }
 
146
        error = (PG_ErrorInfo *) malloc(sizeof(PG_ErrorInfo) + aladd);
 
147
        if (error)
 
148
        {
 
149
                memset(error, 0, sizeof(PG_ErrorInfo));
 
150
                error->status = errnumber;
 
151
                error->errorsize = (Int4) errsize;
 
152
                if (errsize > 0)
 
153
                        memcpy(error->__error_message, msg, errsize);
 
154
                error->__error_message[aladd] = '\0';
 
155
                error->recsize = -1;
 
156
        }
 
157
        return error;
 
158
}
 
159
 
 
160
void
 
161
ER_Destructor(PG_ErrorInfo *self)
 
162
{
 
163
        free(self);
 
164
}
 
165
 
 
166
PG_ErrorInfo *ER_Dup(const PG_ErrorInfo *self)
 
167
{
 
168
        PG_ErrorInfo    *new;
 
169
        Int4            alsize;
 
170
 
 
171
        if (!self)
 
172
                return NULL;
 
173
        alsize = sizeof(PG_ErrorInfo);
 
174
        if (self->errorsize  > 0)
 
175
                alsize += self->errorsize;
 
176
        new = (PG_ErrorInfo *) malloc(alsize);
 
177
        memcpy(new, self, alsize);
 
178
 
 
179
        return new;
 
180
}
 
181
 
 
182
#define DRVMNGRDIV      511
 
183
/*              Returns the next SQL error information. */
 
184
RETCODE         SQL_API
 
185
ER_ReturnError(PG_ErrorInfo **pgerror,
 
186
                SQLSMALLINT     RecNumber,
 
187
                SQLCHAR FAR * szSqlState,
 
188
                SQLINTEGER FAR * pfNativeError,
 
189
                SQLCHAR FAR * szErrorMsg,
 
190
                SQLSMALLINT cbErrorMsgMax,
 
191
                SQLSMALLINT FAR * pcbErrorMsg,
 
192
                UWORD flag)
 
193
{
 
194
        CSTR func = "ER_ReturnError";
 
195
        /* CC: return an error of a hstmt  */
 
196
        PG_ErrorInfo    *error;
 
197
        BOOL            partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
 
198
                        clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
 
199
        const char      *msg;
 
200
        SWORD           msglen, stapos, wrtlen, pcblen;
 
201
 
 
202
        if (!pgerror || !*pgerror)
 
203
                return SQL_NO_DATA_FOUND;
 
204
        error = *pgerror;
 
205
        msg = error->__error_message;
 
206
        mylog("%s: status = %d, msg = #%s#\n", func, error->status, msg);
 
207
        msglen = (SQLSMALLINT) strlen(msg);
 
208
        /*
 
209
         *      Even though an application specifies a larger error message
 
210
         *      buffer, the driver manager changes it silently.
 
211
         *      Therefore we divide the error message into ... 
 
212
         */
 
213
        if (error->recsize < 0)
 
214
        {
 
215
                if (cbErrorMsgMax > 0)
 
216
                        error->recsize = cbErrorMsgMax - 1; /* apply the first request */
 
217
                else
 
218
                        error->recsize = DRVMNGRDIV;
 
219
        }
 
220
        if (RecNumber < 0)
 
221
        {
 
222
                if (0 == error->errorpos)
 
223
                        RecNumber = 1;
 
224
                else
 
225
                        RecNumber = 2 + (error->errorpos - 1) / error->recsize;
 
226
        }
 
227
        stapos = (RecNumber - 1) * error->recsize;
 
228
        if (stapos > msglen)
 
229
                return SQL_NO_DATA_FOUND; 
 
230
        pcblen = wrtlen = msglen - stapos;
 
231
        if (pcblen > error->recsize)
 
232
                pcblen = error->recsize;
 
233
        if (0 == cbErrorMsgMax)
 
234
                wrtlen = 0; 
 
235
        else if (wrtlen >= cbErrorMsgMax)
 
236
        {
 
237
                if (partial_ok)
 
238
                        wrtlen = cbErrorMsgMax - 1;
 
239
                else if (cbErrorMsgMax <= error->recsize)
 
240
                        wrtlen = 0;
 
241
                else 
 
242
                        wrtlen = error->recsize;
 
243
        }
 
244
        if (wrtlen > pcblen)
 
245
                wrtlen = pcblen;
 
246
        if (NULL != pcbErrorMsg)
 
247
                *pcbErrorMsg = pcblen;
 
248
 
 
249
        if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
 
250
        {
 
251
                memcpy(szErrorMsg, msg + stapos, wrtlen);
 
252
                szErrorMsg[wrtlen] = '\0';
 
253
        }
 
254
 
 
255
        if (NULL != pfNativeError)
 
256
                *pfNativeError = error->status;
 
257
 
 
258
        if (NULL != szSqlState)
 
259
                strncpy_null(szSqlState, error->sqlstate, 6);
 
260
 
 
261
        mylog("      szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg);
 
262
        if (clear_str)
 
263
        {
 
264
                error->errorpos = stapos + wrtlen;
 
265
                if (error->errorpos >= msglen)
 
266
                {
 
267
                        ER_Destructor(error);
 
268
                        *pgerror = NULL;
 
269
                }
 
270
        }
 
271
        if (wrtlen == 0)
 
272
                return SQL_SUCCESS_WITH_INFO;
 
273
        else
 
274
                return SQL_SUCCESS;
 
275
}
 
276
 
 
277
 
 
278
RETCODE         SQL_API
 
279
PGAPI_ConnectError(     HDBC hdbc,
 
280
                        SQLSMALLINT     RecNumber,
 
281
                        SQLCHAR FAR * szSqlState,
 
282
                        SQLINTEGER FAR * pfNativeError,
 
283
                        SQLCHAR FAR * szErrorMsg,
 
284
                        SQLSMALLINT cbErrorMsgMax,
 
285
                        SQLSMALLINT FAR * pcbErrorMsg,
 
286
                        UWORD flag)
 
287
{
 
288
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
289
        EnvironmentClass *env = (EnvironmentClass *) conn->henv;
 
290
        char            *msg;
 
291
        int             status;
 
292
        BOOL    once_again = FALSE;
 
293
        ssize_t         msglen;
 
294
 
 
295
        mylog("**** PGAPI_ConnectError: hdbc=%p <%d>\n", hdbc, cbErrorMsgMax);
 
296
        if (RecNumber != 1 && RecNumber != -1)
 
297
                return SQL_NO_DATA_FOUND;
 
298
        if (cbErrorMsgMax < 0)
 
299
                return SQL_ERROR;
 
300
        if (CONN_EXECUTING == conn->status || !CC_get_error(conn, &status, &msg) || NULL == msg)
 
301
        {
 
302
                mylog("CC_Get_error returned nothing.\n");
 
303
                if (NULL != szSqlState)
 
304
                        strcpy(szSqlState, "00000");
 
305
                if (NULL != pcbErrorMsg)
 
306
                        *pcbErrorMsg = 0;
 
307
                if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
 
308
                        szErrorMsg[0] = '\0';
 
309
 
 
310
                return SQL_NO_DATA_FOUND;
 
311
        }
 
312
        mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg);
 
313
 
 
314
        msglen = strlen(msg);
 
315
        if (NULL != pcbErrorMsg)
 
316
        {
 
317
                *pcbErrorMsg = (SQLSMALLINT) msglen;
 
318
                if (cbErrorMsgMax == 0)
 
319
                        once_again = TRUE;
 
320
                else if (msglen >= cbErrorMsgMax)
 
321
                        *pcbErrorMsg = cbErrorMsgMax - 1;
 
322
        }
 
323
        if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
 
324
                strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
 
325
        if (NULL != pfNativeError)
 
326
                *pfNativeError = status;
 
327
 
 
328
        if (NULL != szSqlState)
 
329
        {
 
330
                if (conn->sqlstate[0])
 
331
                        strcpy(szSqlState, conn->sqlstate);
 
332
                else    
 
333
                switch (status)
 
334
                {
 
335
                        case CONN_OPTION_VALUE_CHANGED:
 
336
                                pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
 
337
                                break;
 
338
                        case CONN_TRUNCATED:
 
339
                                pg_sqlstate_set(env, szSqlState, "01004", "01004");
 
340
                                /* data truncated */
 
341
                                break;
 
342
                        case CONN_INIREAD_ERROR:
 
343
                                pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
 
344
                                /* data source not found */
 
345
                                break;
 
346
                        case CONNECTION_SERVER_NOT_REACHED:
 
347
                        case CONN_OPENDB_ERROR:
 
348
                                pg_sqlstate_set(env, szSqlState, "08001", "08001");
 
349
                                /* unable to connect to data source */
 
350
                                break;
 
351
                        case CONN_INVALID_AUTHENTICATION:
 
352
                        case CONN_AUTH_TYPE_UNSUPPORTED:
 
353
                                pg_sqlstate_set(env, szSqlState, "28000", "28000");
 
354
                                break;
 
355
                        case CONN_STMT_ALLOC_ERROR:
 
356
                                pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
 
357
                                /* memory allocation failure */
 
358
                                break;
 
359
                        case CONN_IN_USE:
 
360
                                pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
 
361
                                /* general error */
 
362
                                break;
 
363
                        case CONN_UNSUPPORTED_OPTION:
 
364
                                pg_sqlstate_set(env, szSqlState, "HYC00", "IM001");
 
365
                                /* driver does not support this function */
 
366
                                break;
 
367
                        case CONN_INVALID_ARGUMENT_NO:
 
368
                                pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
 
369
                                /* invalid argument value */
 
370
                                break;
 
371
                        case CONN_TRANSACT_IN_PROGRES:
 
372
                                pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
 
373
 
 
374
                                /*
 
375
                                 * when the user tries to switch commit mode in a
 
376
                                 * transaction
 
377
                                 */
 
378
                                /* -> function sequence error */
 
379
                                break;
 
380
                        case CONN_NO_MEMORY_ERROR:
 
381
                                pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
 
382
                                break;
 
383
                        case CONN_NOT_IMPLEMENTED_ERROR:
 
384
                                pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
 
385
                                break;
 
386
                        case CONN_VALUE_OUT_OF_RANGE:
 
387
                                pg_sqlstate_set(env, szSqlState, "HY019", "22003");
 
388
                                break;
 
389
                        case CONNECTION_COULD_NOT_SEND:
 
390
                        case CONNECTION_COULD_NOT_RECEIVE:
 
391
                        case CONNECTION_COMMUNICATION_ERROR:
 
392
                        case CONNECTION_NO_RESPONSE:
 
393
                                pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
 
394
                                break;
 
395
                        default:
 
396
                                pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
 
397
                                /* general error */
 
398
                                break;
 
399
                }
 
400
        }
 
401
 
 
402
        mylog("      szSqlState = '%s',len=%d, szError='%s'\n", szSqlState ? (char *) szSqlState : PRINT_NULL, msglen, szErrorMsg ? (char *) szErrorMsg : PRINT_NULL);
 
403
        if (once_again)
 
404
        {
 
405
                CC_set_errornumber(conn, status);
 
406
                return SQL_SUCCESS_WITH_INFO;
 
407
        }
 
408
        else
 
409
                return SQL_SUCCESS;
 
410
}
 
411
 
 
412
RETCODE         SQL_API
 
413
PGAPI_EnvError(         HENV henv,
 
414
                        SQLSMALLINT     RecNumber,
 
415
                        SQLCHAR FAR * szSqlState,
 
416
                        SQLINTEGER FAR * pfNativeError,
 
417
                        SQLCHAR FAR * szErrorMsg,
 
418
                        SQLSMALLINT cbErrorMsgMax,
 
419
                        SQLSMALLINT FAR * pcbErrorMsg,
 
420
                        UWORD flag)
 
421
{
 
422
        EnvironmentClass *env = (EnvironmentClass *) henv;
 
423
        char            *msg;
 
424
        int             status;
 
425
 
 
426
        mylog("**** PGAPI_EnvError: henv=%p <%d>\n", henv, cbErrorMsgMax);
 
427
        if (RecNumber != 1 && RecNumber != -1)
 
428
                return SQL_NO_DATA_FOUND;
 
429
        if (cbErrorMsgMax < 0)
 
430
                return SQL_ERROR;
 
431
        if (!EN_get_error(env, &status, &msg) || NULL == msg)
 
432
        {
 
433
                        mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
 
434
                
 
435
                if (NULL != szSqlState)
 
436
                        pg_sqlstate_set(env, szSqlState, "00000", "00000");
 
437
                if (NULL != pcbErrorMsg)
 
438
                        *pcbErrorMsg = 0;
 
439
                if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
 
440
                        szErrorMsg[0] = '\0';
 
441
 
 
442
                return SQL_NO_DATA_FOUND;
 
443
        }
 
444
        mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
 
445
 
 
446
        if (NULL != pcbErrorMsg)
 
447
                *pcbErrorMsg = (SQLSMALLINT) strlen(msg);
 
448
        if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
 
449
                strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
 
450
        if (NULL != pfNativeError)
 
451
                *pfNativeError = status;
 
452
 
 
453
        if (szSqlState)
 
454
        {
 
455
                switch (status)
 
456
                {
 
457
                        case ENV_ALLOC_ERROR:
 
458
                                /* memory allocation failure */
 
459
                                pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
 
460
                                break;
 
461
                        default:
 
462
                                pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
 
463
                                /* general error */
 
464
                                break;
 
465
                }
 
466
        }
 
467
 
 
468
        return SQL_SUCCESS;
 
469
}
 
470
 
 
471
 
 
472
/*              Returns the next SQL error information. */
 
473
RETCODE         SQL_API
 
474
PGAPI_Error(
 
475
                        HENV henv,
 
476
                        HDBC hdbc,
 
477
                        HSTMT hstmt,
 
478
                        SQLCHAR FAR * szSqlState,
 
479
                        SQLINTEGER FAR * pfNativeError,
 
480
                        SQLCHAR FAR * szErrorMsg,
 
481
                        SQLSMALLINT cbErrorMsgMax,
 
482
                        SQLSMALLINT FAR * pcbErrorMsg)
 
483
{
 
484
        RETCODE ret;
 
485
        UWORD   flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR;
 
486
 
 
487
        mylog("**** PGAPI_Error: henv=%p, hdbc=%p hstmt=%d\n", henv, hdbc, hstmt);
 
488
 
 
489
        if (cbErrorMsgMax < 0)
 
490
                return SQL_ERROR;
 
491
        if (SQL_NULL_HSTMT != hstmt)
 
492
                ret = PGAPI_StmtError(hstmt, -1, szSqlState, pfNativeError,
 
493
                         szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
 
494
        else if (SQL_NULL_HDBC != hdbc)
 
495
                ret = PGAPI_ConnectError(hdbc, -1, szSqlState, pfNativeError,
 
496
                         szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
 
497
        else if (SQL_NULL_HENV != henv)
 
498
                ret = PGAPI_EnvError(henv, -1, szSqlState, pfNativeError,
 
499
                         szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
 
500
        else
 
501
        {
 
502
                if (NULL != szSqlState)
 
503
                        strcpy(szSqlState, "00000");
 
504
                if (NULL != pcbErrorMsg)
 
505
                        *pcbErrorMsg = 0;
 
506
                if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
 
507
                        szErrorMsg[0] = '\0';
 
508
 
 
509
                ret = SQL_NO_DATA_FOUND;
 
510
        }
 
511
        mylog("**** PGAPI_Error exit code=%d\n", ret);
 
512
        return ret;
 
513
}
 
514
 
 
515
/*
 
516
 * EnvironmentClass implementation
 
517
 */
 
518
EnvironmentClass *
 
519
EN_Constructor(void)
 
520
{
 
521
        EnvironmentClass *rv = NULL;
 
522
#ifdef WIN32
 
523
        WORD            wVersionRequested;
 
524
        WSADATA         wsaData;
 
525
        const int       major = 2, minor = 2;
 
526
 
 
527
        /* Load the WinSock Library */
 
528
        wVersionRequested = MAKEWORD(major, minor);
 
529
 
 
530
        if (WSAStartup(wVersionRequested, &wsaData))
 
531
        {
 
532
                mylog("%s: WSAStartup error\n", __FUNCTION__);
 
533
                return rv;
 
534
        }
 
535
        /* Verify that this is the minimum version of WinSock */
 
536
        if (LOBYTE(wsaData.wVersion) >= 1 &&
 
537
            (LOBYTE(wsaData.wVersion) >= 2 ||
 
538
             HIBYTE(wsaData.wVersion) >= 1))
 
539
                ;
 
540
        else
 
541
        {
 
542
                mylog("%s: WSAStartup version=(%d,%d)\n", __FUNCTION__,
 
543
                        LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
 
544
                goto cleanup;
 
545
        }
 
546
#endif /* WIN32 */
 
547
 
 
548
        rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass));
 
549
        if (NULL == rv)
 
550
        {
 
551
                mylog("%s: malloc error\n", __FUNCTION__);
 
552
                goto cleanup;
 
553
        }
 
554
        rv->errormsg = 0;
 
555
        rv->errornumber = 0;
 
556
        rv->flag = 0;
 
557
        INIT_ENV_CS(rv);
 
558
cleanup:
 
559
#ifdef WIN32
 
560
        if (NULL == rv)
 
561
        {
 
562
                WSACleanup();
 
563
        }
 
564
#endif /* WIN32 */
 
565
 
 
566
        return rv;
 
567
}
 
568
 
 
569
 
 
570
char
 
571
EN_Destructor(EnvironmentClass *self)
 
572
{
 
573
        int             lf, nullcnt;
 
574
        char            rv = 1;
 
575
 
 
576
        mylog("in EN_Destructor, self=%p\n", self);
 
577
        if (!self)
 
578
                return 0;
 
579
 
 
580
        /*
 
581
         * the error messages are static strings distributed throughout the
 
582
         * source--they should not be freed
 
583
         */
 
584
 
 
585
        /* Free any connections belonging to this environment */
 
586
        ENTER_CONNS_CS;
 
587
        for (lf = 0, nullcnt = 0; lf < conns_count; lf++)
 
588
        {
 
589
                if (NULL == conns[lf])
 
590
                        nullcnt++;
 
591
                else if (conns[lf]->henv == self)
 
592
                {
 
593
                        if (CC_Destructor(conns[lf]))
 
594
                                conns[lf] = NULL;
 
595
                        else
 
596
                                rv = 0;
 
597
                        nullcnt++;
 
598
                }
 
599
        }
 
600
        if (conns && nullcnt >= conns_count)
 
601
        {
 
602
                mylog("clearing conns count=%d\n", conns_count);
 
603
                free(conns);
 
604
                conns = NULL;
 
605
                conns_count = 0;
 
606
        }
 
607
        LEAVE_CONNS_CS;
 
608
        DELETE_ENV_CS(self);
 
609
        free(self);
 
610
 
 
611
#ifdef WIN32
 
612
        WSACleanup();
 
613
#endif
 
614
        mylog("exit EN_Destructor: rv = %d\n", rv);
 
615
#ifdef  _MEMORY_DEBUG_
 
616
        debug_memory_check();
 
617
#endif   /* _MEMORY_DEBUG_ */
 
618
        return rv;
 
619
}
 
620
 
 
621
 
 
622
char
 
623
EN_get_error(EnvironmentClass *self, int *number, char **message)
 
624
{
 
625
        if (self && self->errormsg && self->errornumber)
 
626
        {
 
627
                *message = self->errormsg;
 
628
                *number = self->errornumber;
 
629
                self->errormsg = 0;
 
630
                self->errornumber = 0;
 
631
                return 1;
 
632
        }
 
633
        else
 
634
                return 0;
 
635
}
 
636
 
 
637
#define INIT_CONN_COUNT 128
 
638
 
 
639
char
 
640
EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
 
641
{
 
642
        int     i, alloc;
 
643
        ConnectionClass **newa;
 
644
        char    ret = FALSE;
 
645
 
 
646
        mylog("EN_add_connection: self = %p, conn = %p\n", self, conn);
 
647
 
 
648
        ENTER_CONNS_CS;
 
649
        for (i = 0; i < conns_count; i++)
 
650
        {
 
651
                if (!conns[i])
 
652
                {
 
653
                        conn->henv = self;
 
654
                        conns[i] = conn;
 
655
                        ret = TRUE;
 
656
                        mylog("       added at i=%d, conn->henv = %p, conns[i]->henv = %p\n", i, conn->henv, conns[i]->henv);
 
657
                        goto cleanup;
 
658
                }
 
659
        }
 
660
        if (conns_count > 0)
 
661
                alloc = 2 * conns_count;
 
662
        else
 
663
                alloc = INIT_CONN_COUNT;
 
664
        if (newa = (ConnectionClass **) realloc(conns, alloc * sizeof(ConnectionClass *)), NULL == newa)
 
665
                goto cleanup;
 
666
        conn->henv = self;
 
667
        newa[conns_count] = conn;
 
668
        conns = newa;
 
669
        ret = TRUE;
 
670
        mylog("       added at %d, conn->henv = %p, conns[%d]->henv = %p\n", conns_count, conn->henv, conns_count, conns[conns_count]->henv);
 
671
        for (i = conns_count + 1; i < alloc; i++)
 
672
                conns[i] = NULL; 
 
673
        conns_count = alloc;
 
674
cleanup:
 
675
        LEAVE_CONNS_CS;
 
676
        return ret;
 
677
}
 
678
 
 
679
 
 
680
char
 
681
EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn)
 
682
{
 
683
        int                     i;
 
684
 
 
685
        for (i = 0; i < conns_count; i++)
 
686
                if (conns[i] == conn && conns[i]->status != CONN_EXECUTING)
 
687
                {
 
688
                        ENTER_CONNS_CS;
 
689
                        conns[i] = NULL;
 
690
                        LEAVE_CONNS_CS;
 
691
                        return TRUE;
 
692
                }
 
693
 
 
694
        return FALSE;
 
695
}
 
696
 
 
697
 
 
698
void
 
699
EN_log_error(const char *func, char *desc, EnvironmentClass *self)
 
700
{
 
701
        if (self)
 
702
                qlog("ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
 
703
        else
 
704
                qlog("INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
 
705
}