summaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/environ.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/odbc/environ.c')
-rw-r--r--src/interfaces/odbc/environ.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/src/interfaces/odbc/environ.c b/src/interfaces/odbc/environ.c
new file mode 100644
index 00000000000..b7d808476fe
--- /dev/null
+++ b/src/interfaces/odbc/environ.c
@@ -0,0 +1,416 @@
+
+/* 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 "statement.h"
+#include <stdlib.h>
+#include <malloc.h>
+
+/* The one instance of the handles */
+ConnectionClass *conns[MAX_CONNECTIONS];
+
+
+RETCODE SQL_API SQLAllocEnv(HENV FAR *phenv)
+{
+mylog("**** in SQLAllocEnv ** \n");
+
+ *phenv = (HENV) EN_Constructor();
+ if ( ! *phenv) {
+ *phenv = SQL_NULL_HENV;
+ return SQL_ERROR;
+ }
+
+ mylog("** exit SQLAllocEnv: phenv = %u **\n", *phenv);
+ return SQL_SUCCESS;
+}
+
+RETCODE SQL_API SQLFreeEnv(HENV henv)
+{
+EnvironmentClass *env = (EnvironmentClass *) henv;
+
+mylog("**** in SQLFreeEnv: env = %u ** \n", env);
+
+ if (env && EN_Destructor(env)) {
+ mylog(" ok\n");
+ return SQL_SUCCESS;
+ }
+
+ mylog(" error\n");
+ return SQL_ERROR;
+}
+
+// Returns the next SQL error information.
+
+RETCODE SQL_API SQLError(
+ HENV henv,
+ HDBC hdbc,
+ HSTMT hstmt,
+ UCHAR FAR *szSqlState,
+ SDWORD FAR *pfNativeError,
+ UCHAR FAR *szErrorMsg,
+ SWORD cbErrorMsgMax,
+ SWORD FAR *pcbErrorMsg)
+{
+char *msg;
+int status;
+
+ mylog("**** SQLError: henv=%u, hdbc=%u, hstmt=%u\n", henv, hdbc, hstmt);
+
+ if (SQL_NULL_HSTMT != hstmt) {
+ // CC: return an error of a hstmt
+ StatementClass *stmt = (StatementClass *) hstmt;
+
+ if (NULL == stmt)
+ return SQL_INVALID_HANDLE;
+
+ 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;
+ }
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = (SWORD)strlen(msg);
+
+ 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_TRUNCATED:
+ strcpy(szSqlState, "01004");
+ // data truncated
+ break;
+ case STMT_INFO_ONLY:
+ strcpy(szSqlState, "00000");
+ // just information that is returned, no error
+ break;
+ case STMT_EXEC_ERROR:
+ strcpy(szSqlState, "08S01");
+ // communication link failure
+ 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_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;
+ 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;
+ }
+ 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;
+ }
+
+ if (NULL != pcbErrorMsg)
+ *pcbErrorMsg = (SWORD)strlen(msg);
+ if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
+ strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
+ if (NULL != pfNativeError)
+ *pfNativeError = status;
+
+ if (NULL != szSqlState)
+ switch(status) {
+ 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:
+ strcpy(szSqlState, "S1C00");
+ 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;
+ }
+ 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]);
+ }
+
+ mylog("exit EN_Destructor: rv = %d\n", rv);
+ 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;
+}