summaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/windev/environ.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/odbc/windev/environ.c')
-rw-r--r--src/interfaces/odbc/windev/environ.c588
1 files changed, 588 insertions, 0 deletions
diff --git a/src/interfaces/odbc/windev/environ.c b/src/interfaces/odbc/windev/environ.c
new file mode 100644
index 00000000000..304d31d33ef
--- /dev/null
+++ b/src/interfaces/odbc/windev/environ.c
@@ -0,0 +1,588 @@
+/*-------
+ * Module: environ.c
+ *
+ * Description: This module contains routines related to
+ * the environment, such as storing connection handles,
+ * and returning errors.
+ *
+ * Classes: EnvironmentClass (Functions prefix: "EN_")
+ *
+ * API functions: SQLAllocEnv, SQLFreeEnv, SQLError
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *-------
+ */
+
+#include "environ.h"
+
+#include "connection.h"
+#include "dlg_specific.h"
+#include "statement.h"
+#include <stdlib.h>
+#include <string.h>
+#include "pgapifunc.h"
+
+extern GLOBAL_VALUES globals;
+
+/* The one instance of the handles */
+ConnectionClass *conns[MAX_CONNECTIONS];
+
+
+RETCODE SQL_API
+PGAPI_AllocEnv(HENV FAR * phenv)
+{
+ static char *func = "PGAPI_AllocEnv";
+
+ mylog("**** in PGAPI_AllocEnv ** \n");
+
+ /*
+ * Hack for systems on which none of the constructor-making techniques
+ * in psqlodbc.c work: if globals appears not to have been
+ * initialized, then cause it to be initialized. Since this should be
+ * the first function called in this shared library, doing it here
+ * should work.
+ */
+ if (globals.socket_buffersize <= 0)
+ getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
+
+ *phenv = (HENV) EN_Constructor();
+ if (!*phenv)
+ {
+ *phenv = SQL_NULL_HENV;
+ EN_log_error(func, "Error allocating environment", NULL);
+ return SQL_ERROR;
+ }
+
+ mylog("** exit PGAPI_AllocEnv: phenv = %u **\n", *phenv);
+ return SQL_SUCCESS;
+}
+
+
+RETCODE SQL_API
+PGAPI_FreeEnv(HENV henv)
+{
+ static char *func = "PGAPI_FreeEnv";
+ EnvironmentClass *env = (EnvironmentClass *) henv;
+
+ mylog("**** in PGAPI_FreeEnv: env = %u ** \n", env);
+
+ if (env && EN_Destructor(env))
+ {
+ mylog(" ok\n");
+ return SQL_SUCCESS;
+ }
+
+ mylog(" error\n");
+ EN_log_error(func, "Error freeing environment", env);
+ return SQL_ERROR;
+}
+
+
+/* Returns the next SQL error information. */
+RETCODE SQL_API
+PGAPI_Error(
+ HENV henv,
+ HDBC hdbc,
+ HSTMT hstmt,
+ UCHAR FAR * szSqlState,
+ SDWORD FAR * pfNativeError,
+ UCHAR FAR * szErrorMsg,
+ SWORD cbErrorMsgMax,
+ SWORD FAR * pcbErrorMsg)
+{
+ char *msg;
+ int status;
+ BOOL once_again = FALSE;
+ SWORD msglen;
+
+ mylog("**** PGAPI_Error: henv=%u, hdbc=%u, hstmt=%u <%d>\n", henv, hdbc, hstmt, cbErrorMsgMax);
+
+ if (cbErrorMsgMax < 0)
+ return SQL_ERROR;
+ if (SQL_NULL_HSTMT != hstmt)
+ {
+ /* CC: return an error of a hstmt */
+ StatementClass *stmt = (StatementClass *) hstmt;
+
+ if (SC_get_error(stmt, &status, &msg))
+ {
+ mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg);
+ if (NULL == msg)
+ {
+ if (NULL != szSqlState)
+ strcpy(szSqlState, "00000");
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = 0;
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ szErrorMsg[0] = '\0';
+
+ return SQL_NO_DATA_FOUND;
+ }
+ msglen = (SWORD) strlen(msg);
+ if (NULL != pcbErrorMsg)
+ {
+ *pcbErrorMsg = msglen;
+ if (cbErrorMsgMax == 0)
+ once_again = TRUE;
+ else if (msglen >= cbErrorMsgMax)
+ {
+ once_again = TRUE;
+ *pcbErrorMsg = cbErrorMsgMax - 1;
+ }
+ }
+
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
+
+ if (NULL != pfNativeError)
+ *pfNativeError = status;
+
+ if (NULL != szSqlState)
+
+ switch (status)
+ {
+ /* now determine the SQLSTATE to be returned */
+ case STMT_ROW_VERSION_CHANGED:
+ strcpy(szSqlState, "01001");
+ /* data truncated */
+ break;
+ case STMT_TRUNCATED:
+ strcpy(szSqlState, "01004");
+ /* data truncated */
+ break;
+ case STMT_INFO_ONLY:
+ strcpy(szSqlState, "00000");
+ /* just information that is returned, no error */
+ break;
+ case STMT_BAD_ERROR:
+ strcpy(szSqlState, "08S01");
+ /* communication link failure */
+ break;
+ case STMT_CREATE_TABLE_ERROR:
+ strcpy(szSqlState, "S0001");
+ /* table already exists */
+ break;
+ case STMT_STATUS_ERROR:
+ case STMT_SEQUENCE_ERROR:
+ strcpy(szSqlState, "S1010");
+ /* Function sequence error */
+ break;
+ case STMT_NO_MEMORY_ERROR:
+ strcpy(szSqlState, "S1001");
+ /* memory allocation failure */
+ break;
+ case STMT_COLNUM_ERROR:
+ strcpy(szSqlState, "S1002");
+ /* invalid column number */
+ break;
+ case STMT_NO_STMTSTRING:
+ strcpy(szSqlState, "S1001");
+ /* having no stmtstring is also a malloc problem */
+ break;
+ case STMT_ERROR_TAKEN_FROM_BACKEND:
+ strcpy(szSqlState, "S1000");
+ /* general error */
+ break;
+ case STMT_INTERNAL_ERROR:
+ strcpy(szSqlState, "S1000");
+ /* general error */
+ break;
+ case STMT_ROW_OUT_OF_RANGE:
+ strcpy(szSqlState, "S1107");
+ break;
+
+ case STMT_OPERATION_CANCELLED:
+ strcpy(szSqlState, "S1008");
+ break;
+
+ case STMT_NOT_IMPLEMENTED_ERROR:
+ strcpy(szSqlState, "S1C00"); /* == 'driver not
+ * capable' */
+ break;
+ case STMT_OPTION_OUT_OF_RANGE_ERROR:
+ strcpy(szSqlState, "S1092");
+ break;
+ case STMT_BAD_PARAMETER_NUMBER_ERROR:
+ strcpy(szSqlState, "S1093");
+ break;
+ case STMT_INVALID_COLUMN_NUMBER_ERROR:
+ strcpy(szSqlState, "S1002");
+ break;
+ case STMT_RESTRICTED_DATA_TYPE_ERROR:
+ strcpy(szSqlState, "07006");
+ break;
+ case STMT_INVALID_CURSOR_STATE_ERROR:
+ strcpy(szSqlState, "24000");
+ break;
+ case STMT_OPTION_VALUE_CHANGED:
+ strcpy(szSqlState, "01S02");
+ break;
+ case STMT_POS_BEFORE_RECORDSET:
+ strcpy(szSqlState, "01S06");
+ break;
+ case STMT_INVALID_CURSOR_NAME:
+ strcpy(szSqlState, "34000");
+ break;
+ case STMT_NO_CURSOR_NAME:
+ strcpy(szSqlState, "S1015");
+ break;
+ case STMT_INVALID_ARGUMENT_NO:
+ strcpy(szSqlState, "S1009");
+ /* invalid argument value */
+ break;
+ case STMT_INVALID_CURSOR_POSITION:
+ strcpy(szSqlState, "S1109");
+ break;
+ case STMT_VALUE_OUT_OF_RANGE:
+ strcpy(szSqlState, "22003");
+ break;
+ case STMT_OPERATION_INVALID:
+ strcpy(szSqlState, "S1011");
+ break;
+ case STMT_INVALID_OPTION_IDENTIFIER:
+ strcpy(szSqlState, "HY092");
+ break;
+ case STMT_EXEC_ERROR:
+ default:
+ strcpy(szSqlState, "S1000");
+ /* also a general error */
+ break;
+ }
+ mylog(" szSqlState = '%s', szError='%s'\n", szSqlState, szErrorMsg);
+ }
+ else
+ {
+ if (NULL != szSqlState)
+ strcpy(szSqlState, "00000");
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = 0;
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ szErrorMsg[0] = '\0';
+
+ mylog(" returning NO_DATA_FOUND\n");
+
+ return SQL_NO_DATA_FOUND;
+ }
+
+ if (once_again)
+ {
+ int outlen;
+
+ stmt->errornumber = status;
+ if (cbErrorMsgMax > 0)
+ outlen = *pcbErrorMsg;
+ else
+ outlen = 0;
+ if (!stmt->errormsg_malloced || !stmt->errormsg)
+ {
+ stmt->errormsg = malloc(msglen - outlen + 1);
+ stmt->errormsg_malloced = TRUE;
+ }
+ memmove(stmt->errormsg, msg + outlen, msglen - outlen + 1);
+ }
+ else if (stmt->errormsg_malloced)
+ SC_clear_error(stmt);
+ if (cbErrorMsgMax == 0)
+ return SQL_SUCCESS_WITH_INFO;
+ else
+ return SQL_SUCCESS;
+ }
+ else if (SQL_NULL_HDBC != hdbc)
+ {
+ ConnectionClass *conn = (ConnectionClass *) hdbc;
+
+ mylog("calling CC_get_error\n");
+ if (CC_get_error(conn, &status, &msg))
+ {
+ mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg);
+ if (NULL == msg)
+ {
+ if (NULL != szSqlState)
+ strcpy(szSqlState, "00000");
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = 0;
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ szErrorMsg[0] = '\0';
+
+ return SQL_NO_DATA_FOUND;
+ }
+
+ msglen = strlen(msg);
+ if (NULL != pcbErrorMsg)
+ {
+ *pcbErrorMsg = msglen;
+ if (cbErrorMsgMax == 0)
+ once_again = TRUE;
+ else if (msglen >= cbErrorMsgMax)
+ *pcbErrorMsg = cbErrorMsgMax - 1;
+ }
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
+ if (NULL != pfNativeError)
+ *pfNativeError = status;
+
+ if (NULL != szSqlState)
+ switch (status)
+ {
+ case STMT_OPTION_VALUE_CHANGED:
+ case CONN_OPTION_VALUE_CHANGED:
+ strcpy(szSqlState, "01S02");
+ break;
+ case STMT_TRUNCATED:
+ case CONN_TRUNCATED:
+ strcpy(szSqlState, "01004");
+ /* data truncated */
+ break;
+ case CONN_INIREAD_ERROR:
+ strcpy(szSqlState, "IM002");
+ /* data source not found */
+ break;
+ case CONN_OPENDB_ERROR:
+ strcpy(szSqlState, "08001");
+ /* unable to connect to data source */
+ break;
+ case CONN_INVALID_AUTHENTICATION:
+ case CONN_AUTH_TYPE_UNSUPPORTED:
+ strcpy(szSqlState, "28000");
+ break;
+ case CONN_STMT_ALLOC_ERROR:
+ strcpy(szSqlState, "S1001");
+ /* memory allocation failure */
+ break;
+ case CONN_IN_USE:
+ strcpy(szSqlState, "S1000");
+ /* general error */
+ break;
+ case CONN_UNSUPPORTED_OPTION:
+ strcpy(szSqlState, "IM001");
+ /* driver does not support this function */
+ case CONN_INVALID_ARGUMENT_NO:
+ strcpy(szSqlState, "S1009");
+ /* invalid argument value */
+ break;
+ case CONN_TRANSACT_IN_PROGRES:
+ strcpy(szSqlState, "S1010");
+
+ /*
+ * when the user tries to switch commit mode in a
+ * transaction
+ */
+ /* -> function sequence error */
+ break;
+ case CONN_NO_MEMORY_ERROR:
+ strcpy(szSqlState, "S1001");
+ break;
+ case CONN_NOT_IMPLEMENTED_ERROR:
+ case STMT_NOT_IMPLEMENTED_ERROR:
+ strcpy(szSqlState, "S1C00");
+ break;
+ case CONN_VALUE_OUT_OF_RANGE:
+ case STMT_VALUE_OUT_OF_RANGE:
+ strcpy(szSqlState, "22003");
+ break;
+ default:
+ strcpy(szSqlState, "S1000");
+ /* general error */
+ break;
+ }
+ }
+ else
+ {
+ mylog("CC_Get_error returned nothing.\n");
+ if (NULL != szSqlState)
+ strcpy(szSqlState, "00000");
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = 0;
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ szErrorMsg[0] = '\0';
+
+ return SQL_NO_DATA_FOUND;
+ }
+
+ if (once_again)
+ {
+ conn->errornumber = status;
+ return SQL_SUCCESS_WITH_INFO;
+ }
+ else
+ return SQL_SUCCESS;
+ }
+ else if (SQL_NULL_HENV != henv)
+ {
+ EnvironmentClass *env = (EnvironmentClass *) henv;
+
+ if (EN_get_error(env, &status, &msg))
+ {
+ mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
+ if (NULL == msg)
+ {
+ if (NULL != szSqlState)
+ strcpy(szSqlState, "00000");
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = 0;
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ szErrorMsg[0] = '\0';
+
+ return SQL_NO_DATA_FOUND;
+ }
+
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = (SWORD) strlen(msg);
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
+ if (NULL != pfNativeError)
+ *pfNativeError = status;
+
+ if (szSqlState)
+ {
+ switch (status)
+ {
+ case ENV_ALLOC_ERROR:
+ /* memory allocation failure */
+ strcpy(szSqlState, "S1001");
+ break;
+ default:
+ strcpy(szSqlState, "S1000");
+ /* general error */
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (NULL != szSqlState)
+ strcpy(szSqlState, "00000");
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = 0;
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ szErrorMsg[0] = '\0';
+
+ return SQL_NO_DATA_FOUND;
+ }
+
+ return SQL_SUCCESS;
+ }
+
+ if (NULL != szSqlState)
+ strcpy(szSqlState, "00000");
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = 0;
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ szErrorMsg[0] = '\0';
+
+ return SQL_NO_DATA_FOUND;
+}
+
+
+/*
+ * EnvironmentClass implementation
+ */
+EnvironmentClass *
+EN_Constructor(void)
+{
+ EnvironmentClass *rv;
+
+ rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass));
+ if (rv)
+ {
+ rv->errormsg = 0;
+ rv->errornumber = 0;
+ }
+
+ return rv;
+}
+
+
+char
+EN_Destructor(EnvironmentClass *self)
+{
+ int lf;
+ char rv = 1;
+
+ mylog("in EN_Destructor, self=%u\n", self);
+
+ /*
+ * the error messages are static strings distributed throughout the
+ * source--they should not be freed
+ */
+
+ /* Free any connections belonging to this environment */
+ for (lf = 0; lf < MAX_CONNECTIONS; lf++)
+ {
+ if (conns[lf] && conns[lf]->henv == self)
+ rv = rv && CC_Destructor(conns[lf]);
+ }
+ free(self);
+
+ mylog("exit EN_Destructor: rv = %d\n", rv);
+#ifdef _MEMORY_DEBUG_
+ debug_memory_inouecheck();
+#endif /* _MEMORY_DEBUG_ */
+ return rv;
+}
+
+
+char
+EN_get_error(EnvironmentClass *self, int *number, char **message)
+{
+ if (self && self->errormsg && self->errornumber)
+ {
+ *message = self->errormsg;
+ *number = self->errornumber;
+ self->errormsg = 0;
+ self->errornumber = 0;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+char
+EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
+{
+ int i;
+
+ mylog("EN_add_connection: self = %u, conn = %u\n", self, conn);
+
+ for (i = 0; i < MAX_CONNECTIONS; i++)
+ {
+ if (!conns[i])
+ {
+ conn->henv = self;
+ conns[i] = conn;
+
+ mylog(" added at i =%d, conn->henv = %u, conns[i]->henv = %u\n", i, conn->henv, conns[i]->henv);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+char
+EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn)
+{
+ int i;
+
+ for (i = 0; i < MAX_CONNECTIONS; i++)
+ if (conns[i] == conn && conns[i]->status != CONN_EXECUTING)
+ {
+ conns[i] = NULL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+void
+EN_log_error(char *func, char *desc, EnvironmentClass *self)
+{
+ if (self)
+ qlog("ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
+ else
+ qlog("INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
+}