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