2 * Description: This module contains routines related to
3 * the environment, such as storing connection handles,
4 * and returning errors.
9 #include "connection.h"
10 #include "dlg_specific.h"
11 #include "statement.h"
14 #include "pgapifunc.h"
16 #ifndef _WSASTARTUP_IN_DLLMAIN_
18 #endif /* _WSASTARTUP_IN_DLLMAIN_ */
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
48 initialize_global_cs();
49 getCommonDefaults(DBMS_NAME
, ODBCINST_INI
, NULL
);
51 *phenv
= (HENV
) EN_Constructor();
54 *phenv
= SQL_NULL_HENV
;
55 EN_log_error(func
, "Error allocating environment", NULL
);
59 mylog("** exit %s: phenv = %p **\n", func
, *phenv
);
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_
76 #endif /* _HANDLE_ENLIST_IN_DTC_ */
83 EN_log_error(func
, "Error freeing environment", env
);
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
)
100 ssize_t aladd
, errsize
;
102 if (DESC_OK
== errnumber
)
106 errsize
= strlen(msg
);
113 error
= (PG_ErrorInfo
*) malloc(sizeof(PG_ErrorInfo
) + aladd
);
116 memset(error
, 0, sizeof(PG_ErrorInfo
));
117 error
->status
= errnumber
;
118 error
->errorsize
= (Int4
) errsize
;
120 memcpy(error
->__error_message
, msg
, errsize
);
121 error
->__error_message
[aladd
] = '\0';
127 void ER_Destructor(PG_ErrorInfo
* self
)
132 PG_ErrorInfo
*ER_Dup(const PG_ErrorInfo
* self
)
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
);
148 #define DRVMNGRDIV 511
149 /* Returns the next SQL error information. */
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 */
162 BOOL partial_ok
= ((flag
& PODBC_ALLOW_PARTIAL_EXTRACT
) != 0),
163 clear_str
= ((flag
& PODBC_ERROR_CLEAR
) != 0);
165 SWORD msglen
, stapos
, wrtlen
, pcblen
;
167 if (!pgerror
|| !*pgerror
)
168 return SQL_NO_DATA_FOUND
;
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 */
183 error
->recsize
= DRVMNGRDIV
;
187 if (0 == error
->errorpos
)
190 RecNumber
= 2 + (error
->errorpos
- 1) / error
->recsize
;
192 stapos
= (RecNumber
- 1) * error
->recsize
;
194 return SQL_NO_DATA_FOUND
;
195 pcblen
= wrtlen
= msglen
- stapos
;
196 if (pcblen
> error
->recsize
)
197 pcblen
= error
->recsize
;
198 if (0 == cbErrorMsgMax
)
200 else if (wrtlen
>= cbErrorMsgMax
)
203 wrtlen
= cbErrorMsgMax
- 1;
204 else if (cbErrorMsgMax
<= error
->recsize
)
207 wrtlen
= error
->recsize
;
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
);
230 error
->errorpos
= stapos
+ wrtlen
;
231 if (error
->errorpos
>= msglen
)
233 ER_Destructor(error
);
238 return SQL_SUCCESS_WITH_INFO
;
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
;
257 BOOL once_again
= FALSE
;
260 mylog("**** PGAPI_ConnectError: hdbc=%p <%d>\n", hdbc
,
262 if (RecNumber
!= 1 && RecNumber
!= -1)
263 return SQL_NO_DATA_FOUND
;
264 if (cbErrorMsgMax
< 0)
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
)
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)
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
);
302 case CONN_OPTION_VALUE_CHANGED
:
303 pg_sqlstate_set(env
, szSqlState
, "01S02", "01S02");
306 pg_sqlstate_set(env
, szSqlState
, "01004", "01004");
309 case CONN_INIREAD_ERROR
:
310 pg_sqlstate_set(env
, szSqlState
, "IM002", "IM002");
311 /* data source not found */
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 */
318 case CONN_INVALID_AUTHENTICATION
:
319 case CONN_AUTH_TYPE_UNSUPPORTED
:
320 pg_sqlstate_set(env
, szSqlState
, "28000", "28000");
322 case CONN_STMT_ALLOC_ERROR
:
323 pg_sqlstate_set(env
, szSqlState
, "HY001", "S1001");
324 /* memory allocation failure */
327 pg_sqlstate_set(env
, szSqlState
, "HY000", "S1000");
330 case CONN_UNSUPPORTED_OPTION
:
331 pg_sqlstate_set(env
, szSqlState
, "HYC00", "IM001");
332 /* driver does not support this function */
334 case CONN_INVALID_ARGUMENT_NO
:
335 pg_sqlstate_set(env
, szSqlState
, "HY009", "S1009");
336 /* invalid argument value */
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
345 /* -> function sequence error */
347 case CONN_NO_MEMORY_ERROR
:
348 pg_sqlstate_set(env
, szSqlState
, "HY001", "S1001");
350 case CONN_NOT_IMPLEMENTED_ERROR
:
351 pg_sqlstate_set(env
, szSqlState
, "HYC00", "S1C00");
353 case CONN_VALUE_OUT_OF_RANGE
:
354 pg_sqlstate_set(env
, szSqlState
, "HY019", "22003");
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");
362 pg_sqlstate_set(env
, szSqlState
, "HY000", "S1000");
368 mylog(" szSqlState = '%s',len=%d, szError='%s'\n",
369 szSqlState
, msglen
, szErrorMsg
);
372 CC_set_errornumber(conn
, status
);
373 return SQL_SUCCESS_WITH_INFO
;
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
;
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)
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
)
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
;
422 case ENV_ALLOC_ERROR
:
423 /* memory allocation failure */
424 pg_sqlstate_set(env
, szSqlState
, "HY001", "S1001");
427 pg_sqlstate_set(env
, szSqlState
, "HY000", "S1000");
437 /* Returns the next SQL error information. */
439 PGAPI_Error(HENV henv
,
442 SQLCHAR FAR
* szSqlState
,
443 SQLINTEGER FAR
* pfNativeError
,
444 SQLCHAR FAR
* szErrorMsg
,
445 SQLSMALLINT cbErrorMsgMax
, SQLSMALLINT FAR
* pcbErrorMsg
)
448 UWORD flag
= PODBC_ALLOW_PARTIAL_EXTRACT
| PODBC_ERROR_CLEAR
;
450 mylog("**** PGAPI_Error: henv=%p, hdbc=%p hstmt=%d\n", henv
, hdbc
,
453 if (cbErrorMsgMax
< 0)
455 if (SQL_NULL_HSTMT
!= hstmt
)
456 ret
= PGAPI_StmtError(hstmt
, -1, szSqlState
, pfNativeError
,
457 szErrorMsg
, cbErrorMsgMax
, pcbErrorMsg
,
459 else if (SQL_NULL_HDBC
!= hdbc
)
460 ret
= PGAPI_ConnectError(hdbc
, -1, szSqlState
, pfNativeError
,
461 szErrorMsg
, cbErrorMsgMax
, pcbErrorMsg
,
463 else if (SQL_NULL_HENV
!= henv
)
464 ret
= PGAPI_EnvError(henv
, -1, szSqlState
, pfNativeError
,
465 szErrorMsg
, cbErrorMsgMax
, pcbErrorMsg
,
469 if (NULL
!= szSqlState
)
470 strcpy((char *)szSqlState
, "00000");
471 if (NULL
!= pcbErrorMsg
)
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
);
483 * EnvironmentClass implementation
485 EnvironmentClass
*EN_Constructor(void)
487 EnvironmentClass
*rv
= NULL
;
489 #ifndef _WSASTARTUP_IN_DLLMAIN_
490 WORD wVersionRequested
;
493 /* Load the WinSock Library */
494 wVersionRequested
= MAKEWORD(1, 1);
496 if (WSAStartup(wVersionRequested
, &wsaData
))
498 /* Verify that this is the minimum version of WinSock */
499 if (LOBYTE(wsaData
.wVersion
) != 1 || HIBYTE(wsaData
.wVersion
) != 1)
503 #endif /* _WSASTARTUP_IN_DLLMAIN_ */
506 rv
= (EnvironmentClass
*) malloc(sizeof(EnvironmentClass
));
516 #ifndef _WSASTARTUP_IN_DLLMAIN_
519 #endif /* _WSASTARTUP_IN_DLLMAIN_ */
526 char EN_Destructor(EnvironmentClass
* self
)
531 mylog("in EN_Destructor, self=%p\n", self
);
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
]))
555 #ifndef _WSASTARTUP_IN_DLLMAIN_
557 #endif /* _WSASTARTUP_IN_DLLMAIN_ */
559 mylog("exit EN_Destructor: rv = %d\n", rv
);
560 #ifdef _MEMORY_DEBUG_
561 debug_memory_check();
562 #endif /* _MEMORY_DEBUG_ */
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
;
574 self
->errornumber
= 0;
581 char EN_add_connection(EnvironmentClass
* self
, ConnectionClass
* conn
)
585 mylog("EN_add_connection: self = %p, conn = %p\n", self
, conn
);
588 for (i
= 0; i
< MAX_CONNECTIONS
; i
++)
597 (" added at i =%d, conn->henv = %p, conns[i]->henv = %p\n",
598 i
, conn
->henv
, conns
[i
]->henv
);
610 EN_remove_connection(EnvironmentClass
* self
, ConnectionClass
* conn
)
614 for (i
= 0; i
< MAX_CONNECTIONS
; i
++)
615 if (conns
[i
] == conn
&& conns
[i
]->status
!= CONN_EXECUTING
)
627 void EN_log_error(const char *func
, char *desc
, EnvironmentClass
* self
)
630 qlog("ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func
, desc
, self
->errornumber
, self
->errormsg
);
632 qlog("INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func
,