'make test' on Windows doesn't need you to say "mono --debug".
[versaplex.git] / vxodbc / environ.cc
blobdb534c44571699555649f3382bf112726b2660c1
1 /*
2 * Description: This module contains routines related to
3 * the environment, such as storing connection handles,
4 * and returning errors.
5 */
7 #include "environ.h"
9 #include "connection.h"
10 #include "dlg_specific.h"
11 #include "statement.h"
12 #include <stdlib.h>
13 #include <string.h>
14 #include "pgapifunc.h"
15 #ifdef WIN32
16 #ifndef _WSASTARTUP_IN_DLLMAIN_
17 #include <winsock2.h>
18 #endif /* _WSASTARTUP_IN_DLLMAIN_ */
19 #endif /* WIN32 */
21 extern GLOBAL_VALUES globals;
23 /* The one instance of the handles */
24 ConnectionClass *conns[MAX_CONNECTIONS];
25 #if defined(WIN_MULTITHREAD_SUPPORT)
26 CRITICAL_SECTION conns_cs;
27 CRITICAL_SECTION common_cs; /* commonly used for short term blocking */
28 #elif defined(POSIX_MULTITHREAD_SUPPORT)
29 pthread_mutex_t conns_cs;
30 pthread_mutex_t common_cs;
31 #endif /* WIN_MULTITHREAD_SUPPORT */
34 RETCODE SQL_API PGAPI_AllocEnv(HENV FAR * phenv)
36 CSTR func = "PGAPI_AllocEnv";
37 SQLRETURN ret = SQL_SUCCESS;
39 mylog("**** in %s ** \n", func);
42 * Hack for systems on which none of the constructor-making techniques
43 * in psqlodbc.c work: if globals appears not to have been
44 * initialized, then cause it to be initialized. Since this should be
45 * the first function called in this shared library, doing it here
46 * should work.
48 initialize_global_cs();
49 getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
51 *phenv = (HENV) EN_Constructor();
52 if (!*phenv)
54 *phenv = SQL_NULL_HENV;
55 EN_log_error(func, "Error allocating environment", NULL);
56 ret = SQL_ERROR;
59 mylog("** exit %s: phenv = %p **\n", func, *phenv);
60 return ret;
64 RETCODE SQL_API PGAPI_FreeEnv(HENV henv)
66 CSTR func = "PGAPI_FreeEnv";
67 SQLRETURN ret = SQL_SUCCESS;
68 EnvironmentClass *env = (EnvironmentClass *) henv;
70 mylog("**** in PGAPI_FreeEnv: env = %p ** \n", env);
72 if (env && EN_Destructor(env))
74 #ifdef _HANDLE_ENLIST_IN_DTC_
75 CALL_DtcOnRelease();
76 #endif /* _HANDLE_ENLIST_IN_DTC_ */
77 mylog(" ok\n");
78 goto cleanup;
81 mylog(" error\n");
82 ret = SQL_ERROR;
83 EN_log_error(func, "Error freeing environment", env);
84 cleanup:
85 return ret;
89 static void
90 pg_sqlstate_set(const EnvironmentClass * env, UCHAR * szSqlState,
91 const char *ver3str, const char *ver2str)
93 strcpy((char *)szSqlState,
94 (const char *)(EN_is_odbc3(env) ? ver3str : ver2str));
97 PG_ErrorInfo *ER_Constructor(SDWORD errnumber, const char *msg)
99 PG_ErrorInfo *error;
100 ssize_t aladd, errsize;
102 if (DESC_OK == errnumber)
103 return NULL;
104 if (msg)
106 errsize = strlen(msg);
107 aladd = errsize;
108 } else
110 errsize = -1;
111 aladd = 0;
113 error = (PG_ErrorInfo *) malloc(sizeof(PG_ErrorInfo) + aladd);
114 if (error)
116 memset(error, 0, sizeof(PG_ErrorInfo));
117 error->status = errnumber;
118 error->errorsize = (Int4) errsize;
119 if (errsize > 0)
120 memcpy(error->__error_message, msg, errsize);
121 error->__error_message[aladd] = '\0';
122 error->recsize = -1;
124 return error;
127 void ER_Destructor(PG_ErrorInfo * self)
129 free(self);
132 PG_ErrorInfo *ER_Dup(const PG_ErrorInfo * self)
134 PG_ErrorInfo *n;
135 Int4 alsize;
137 if (!self)
138 return NULL;
139 alsize = sizeof(PG_ErrorInfo);
140 if (self->errorsize > 0)
141 alsize += self->errorsize;
142 n = (PG_ErrorInfo *) malloc(alsize);
143 memcpy(n, self, alsize);
145 return n;
148 #define DRVMNGRDIV 511
149 /* Returns the next SQL error information. */
150 RETCODE SQL_API
151 ER_ReturnError(PG_ErrorInfo ** pgerror,
152 SQLSMALLINT RecNumber,
153 SQLCHAR FAR * szSqlState,
154 SQLINTEGER FAR * pfNativeError,
155 SQLCHAR FAR * szErrorMsg,
156 SQLSMALLINT cbErrorMsgMax,
157 SQLSMALLINT FAR * pcbErrorMsg, UWORD flag)
159 CSTR func = "ER_ReturnError";
160 /* CC: return an error of a hstmt */
161 PG_ErrorInfo *error;
162 BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
163 clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
164 const char *msg;
165 SWORD msglen, stapos, wrtlen, pcblen;
167 if (!pgerror || !*pgerror)
168 return SQL_NO_DATA_FOUND;
169 error = *pgerror;
170 msg = error->__error_message;
171 mylog("%s: status = %d, msg = #%s#\n", func, error->status, msg);
172 msglen = (SQLSMALLINT) strlen(msg);
174 * Even though an application specifies a larger error message
175 * buffer, the driver manager changes it silently.
176 * Therefore we divide the error message into ...
178 if (error->recsize < 0)
180 if (cbErrorMsgMax > 0)
181 error->recsize = cbErrorMsgMax - 1; /* apply the first request */
182 else
183 error->recsize = DRVMNGRDIV;
185 if (RecNumber < 0)
187 if (0 == error->errorpos)
188 RecNumber = 1;
189 else
190 RecNumber = 2 + (error->errorpos - 1) / error->recsize;
192 stapos = (RecNumber - 1) * error->recsize;
193 if (stapos > msglen)
194 return SQL_NO_DATA_FOUND;
195 pcblen = wrtlen = msglen - stapos;
196 if (pcblen > error->recsize)
197 pcblen = error->recsize;
198 if (0 == cbErrorMsgMax)
199 wrtlen = 0;
200 else if (wrtlen >= cbErrorMsgMax)
202 if (partial_ok)
203 wrtlen = cbErrorMsgMax - 1;
204 else if (cbErrorMsgMax <= error->recsize)
205 wrtlen = 0;
206 else
207 wrtlen = error->recsize;
209 if (wrtlen > pcblen)
210 wrtlen = pcblen;
211 if (NULL != pcbErrorMsg)
212 *pcbErrorMsg = pcblen;
214 if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
216 memcpy(szErrorMsg, msg + stapos, wrtlen);
217 szErrorMsg[wrtlen] = '\0';
220 if (NULL != pfNativeError)
221 *pfNativeError = error->status;
223 if (NULL != szSqlState)
224 strncpy((char *)szSqlState, error->sqlstate, 6);
226 mylog(" szSqlState = '%s',len=%d, szError='%s'\n",
227 szSqlState, pcblen, szErrorMsg);
228 if (clear_str)
230 error->errorpos = stapos + wrtlen;
231 if (error->errorpos >= msglen)
233 ER_Destructor(error);
234 *pgerror = NULL;
237 if (wrtlen == 0)
238 return SQL_SUCCESS_WITH_INFO;
239 else
240 return SQL_SUCCESS;
244 RETCODE SQL_API
245 PGAPI_ConnectError(HDBC hdbc,
246 SQLSMALLINT RecNumber,
247 SQLCHAR FAR * szSqlState,
248 SQLINTEGER FAR * pfNativeError,
249 SQLCHAR FAR * szErrorMsg,
250 SQLSMALLINT cbErrorMsgMax,
251 SQLSMALLINT FAR * pcbErrorMsg, UWORD flag)
253 ConnectionClass *conn = (ConnectionClass *) hdbc;
254 EnvironmentClass *env = (EnvironmentClass *) conn->henv;
255 char *msg;
256 int status;
257 BOOL once_again = FALSE;
258 ssize_t msglen;
260 mylog("**** PGAPI_ConnectError: hdbc=%p <%d>\n", hdbc,
261 cbErrorMsgMax);
262 if (RecNumber != 1 && RecNumber != -1)
263 return SQL_NO_DATA_FOUND;
264 if (cbErrorMsgMax < 0)
265 return SQL_ERROR;
266 if (CONN_EXECUTING == conn->status
267 || !CC_get_error(conn, &status, &msg) || NULL == msg)
269 mylog("CC_Get_error returned nothing.\n");
270 if (NULL != szSqlState)
271 strcpy((char *)szSqlState, "00000");
272 if (NULL != pcbErrorMsg)
273 *pcbErrorMsg = 0;
274 if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
275 szErrorMsg[0] = '\0';
277 return SQL_NO_DATA_FOUND;
279 mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg);
281 msglen = strlen(msg);
282 if (NULL != pcbErrorMsg)
284 *pcbErrorMsg = (SQLSMALLINT) msglen;
285 if (cbErrorMsgMax == 0)
286 once_again = TRUE;
287 else if (msglen >= cbErrorMsgMax)
288 *pcbErrorMsg = cbErrorMsgMax - 1;
290 if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
291 strncpy_null((char *)szErrorMsg, msg, cbErrorMsgMax);
292 if (NULL != pfNativeError)
293 *pfNativeError = status;
295 if (NULL != szSqlState)
297 if (conn->sqlstate[0])
298 strcpy((char *)szSqlState, conn->sqlstate);
299 else
300 switch (status)
302 case CONN_OPTION_VALUE_CHANGED:
303 pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
304 break;
305 case CONN_TRUNCATED:
306 pg_sqlstate_set(env, szSqlState, "01004", "01004");
307 /* data truncated */
308 break;
309 case CONN_INIREAD_ERROR:
310 pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
311 /* data source not found */
312 break;
313 case CONNECTION_SERVER_NOT_REACHED:
314 case CONN_OPENDB_ERROR:
315 pg_sqlstate_set(env, szSqlState, "08001", "08001");
316 /* unable to connect to data source */
317 break;
318 case CONN_INVALID_AUTHENTICATION:
319 case CONN_AUTH_TYPE_UNSUPPORTED:
320 pg_sqlstate_set(env, szSqlState, "28000", "28000");
321 break;
322 case CONN_STMT_ALLOC_ERROR:
323 pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
324 /* memory allocation failure */
325 break;
326 case CONN_IN_USE:
327 pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
328 /* general error */
329 break;
330 case CONN_UNSUPPORTED_OPTION:
331 pg_sqlstate_set(env, szSqlState, "HYC00", "IM001");
332 /* driver does not support this function */
333 break;
334 case CONN_INVALID_ARGUMENT_NO:
335 pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
336 /* invalid argument value */
337 break;
338 case CONN_TRANSACT_IN_PROGRES:
339 pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
342 * when the user tries to switch commit mode in a
343 * transaction
345 /* -> function sequence error */
346 break;
347 case CONN_NO_MEMORY_ERROR:
348 pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
349 break;
350 case CONN_NOT_IMPLEMENTED_ERROR:
351 pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
352 break;
353 case CONN_VALUE_OUT_OF_RANGE:
354 pg_sqlstate_set(env, szSqlState, "HY019", "22003");
355 break;
356 case CONNECTION_COULD_NOT_SEND:
357 case CONNECTION_COULD_NOT_RECEIVE:
358 case CONNECTION_COMMUNICATION_ERROR:
359 pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
360 break;
361 default:
362 pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
363 /* general error */
364 break;
368 mylog(" szSqlState = '%s',len=%d, szError='%s'\n",
369 szSqlState, msglen, szErrorMsg);
370 if (once_again)
372 CC_set_errornumber(conn, status);
373 return SQL_SUCCESS_WITH_INFO;
374 } else
375 return SQL_SUCCESS;
378 RETCODE SQL_API
379 PGAPI_EnvError(HENV henv,
380 SQLSMALLINT RecNumber,
381 SQLCHAR FAR * szSqlState,
382 SQLINTEGER FAR * pfNativeError,
383 SQLCHAR FAR * szErrorMsg,
384 SQLSMALLINT cbErrorMsgMax,
385 SQLSMALLINT FAR * pcbErrorMsg, UWORD flag)
387 EnvironmentClass *env = (EnvironmentClass *) henv;
388 char *msg;
389 int status;
391 mylog("**** PGAPI_EnvError: henv=%p <%d>\n", henv, cbErrorMsgMax);
392 if (RecNumber != 1 && RecNumber != -1)
393 return SQL_NO_DATA_FOUND;
394 if (cbErrorMsgMax < 0)
395 return SQL_ERROR;
396 if (!EN_get_error(env, &status, &msg) || NULL == msg)
398 mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
400 if (NULL != szSqlState)
401 pg_sqlstate_set(env, szSqlState, "00000", "00000");
402 if (NULL != pcbErrorMsg)
403 *pcbErrorMsg = 0;
404 if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
405 szErrorMsg[0] = '\0';
407 return SQL_NO_DATA_FOUND;
409 mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
411 if (NULL != pcbErrorMsg)
412 *pcbErrorMsg = (SQLSMALLINT) strlen(msg);
413 if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
414 strncpy_null((char *)szErrorMsg, msg, cbErrorMsgMax);
415 if (NULL != pfNativeError)
416 *pfNativeError = status;
418 if (szSqlState)
420 switch (status)
422 case ENV_ALLOC_ERROR:
423 /* memory allocation failure */
424 pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
425 break;
426 default:
427 pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
428 /* general error */
429 break;
433 return SQL_SUCCESS;
437 /* Returns the next SQL error information. */
438 RETCODE SQL_API
439 PGAPI_Error(HENV henv,
440 HDBC hdbc,
441 HSTMT hstmt,
442 SQLCHAR FAR * szSqlState,
443 SQLINTEGER FAR * pfNativeError,
444 SQLCHAR FAR * szErrorMsg,
445 SQLSMALLINT cbErrorMsgMax, SQLSMALLINT FAR * pcbErrorMsg)
447 RETCODE ret;
448 UWORD flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR;
450 mylog("**** PGAPI_Error: henv=%p, hdbc=%p hstmt=%d\n", henv, hdbc,
451 hstmt);
453 if (cbErrorMsgMax < 0)
454 return SQL_ERROR;
455 if (SQL_NULL_HSTMT != hstmt)
456 ret = PGAPI_StmtError(hstmt, -1, szSqlState, pfNativeError,
457 szErrorMsg, cbErrorMsgMax, pcbErrorMsg,
458 flag);
459 else if (SQL_NULL_HDBC != hdbc)
460 ret = PGAPI_ConnectError(hdbc, -1, szSqlState, pfNativeError,
461 szErrorMsg, cbErrorMsgMax, pcbErrorMsg,
462 flag);
463 else if (SQL_NULL_HENV != henv)
464 ret = PGAPI_EnvError(henv, -1, szSqlState, pfNativeError,
465 szErrorMsg, cbErrorMsgMax, pcbErrorMsg,
466 flag);
467 else
469 if (NULL != szSqlState)
470 strcpy((char *)szSqlState, "00000");
471 if (NULL != pcbErrorMsg)
472 *pcbErrorMsg = 0;
473 if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
474 szErrorMsg[0] = '\0';
476 ret = SQL_NO_DATA_FOUND;
478 mylog("**** PGAPI_Error exit code=%d\n", ret);
479 return ret;
483 * EnvironmentClass implementation
485 EnvironmentClass *EN_Constructor(void)
487 EnvironmentClass *rv = NULL;
488 #ifdef WIN32
489 #ifndef _WSASTARTUP_IN_DLLMAIN_
490 WORD wVersionRequested;
491 WSADATA wsaData;
493 /* Load the WinSock Library */
494 wVersionRequested = MAKEWORD(1, 1);
496 if (WSAStartup(wVersionRequested, &wsaData))
497 return rv;
498 /* Verify that this is the minimum version of WinSock */
499 if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
501 goto cleanup;
503 #endif /* _WSASTARTUP_IN_DLLMAIN_ */
504 #endif
506 rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass));
507 cleanup:
508 if (rv)
510 rv->errormsg = 0;
511 rv->errornumber = 0;
512 rv->flag = 0;
513 INIT_ENV_CS(rv);
515 #ifdef WIN32
516 #ifndef _WSASTARTUP_IN_DLLMAIN_
517 else
518 WSACleanup();
519 #endif /* _WSASTARTUP_IN_DLLMAIN_ */
520 #endif
522 return rv;
526 char EN_Destructor(EnvironmentClass * self)
528 int lf;
529 char rv = 1;
531 mylog("in EN_Destructor, self=%p\n", self);
532 if (!self)
533 return 0;
536 * the error messages are static strings distributed throughout the
537 * source--they should not be freed
540 /* Free any connections belonging to this environment */
541 for (lf = 0; lf < MAX_CONNECTIONS; lf++)
543 if (conns[lf] && conns[lf]->henv == self)
545 if (CC_Destructor(conns[lf]))
546 conns[lf] = NULL;
547 else
548 rv = 0;
551 DELETE_ENV_CS(self);
552 free(self);
554 #ifdef WIN32
555 #ifndef _WSASTARTUP_IN_DLLMAIN_
556 WSACleanup();
557 #endif /* _WSASTARTUP_IN_DLLMAIN_ */
558 #endif
559 mylog("exit EN_Destructor: rv = %d\n", rv);
560 #ifdef _MEMORY_DEBUG_
561 debug_memory_check();
562 #endif /* _MEMORY_DEBUG_ */
563 return rv;
567 char EN_get_error(EnvironmentClass * self, int *number, char **message)
569 if (self && self->errormsg && self->errornumber)
571 *message = self->errormsg;
572 *number = self->errornumber;
573 self->errormsg = 0;
574 self->errornumber = 0;
575 return 1;
576 } else
577 return 0;
581 char EN_add_connection(EnvironmentClass * self, ConnectionClass * conn)
583 int i;
585 mylog("EN_add_connection: self = %p, conn = %p\n", self, conn);
587 ENTER_CONNS_CS;
588 for (i = 0; i < MAX_CONNECTIONS; i++)
590 if (!conns[i])
592 conn->henv = self;
593 conns[i] = conn;
594 LEAVE_CONNS_CS;
596 mylog
597 (" added at i =%d, conn->henv = %p, conns[i]->henv = %p\n",
598 i, conn->henv, conns[i]->henv);
600 return TRUE;
603 LEAVE_CONNS_CS;
605 return FALSE;
609 char
610 EN_remove_connection(EnvironmentClass * self, ConnectionClass * conn)
612 int i;
614 for (i = 0; i < MAX_CONNECTIONS; i++)
615 if (conns[i] == conn && conns[i]->status != CONN_EXECUTING)
617 ENTER_CONNS_CS;
618 conns[i] = NULL;
619 LEAVE_CONNS_CS;
620 return TRUE;
623 return FALSE;
627 void EN_log_error(const char *func, char *desc, EnvironmentClass * self)
629 if (self)
630 qlog("ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
631 else
632 qlog("INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func,
633 desc);