1/**************************************************
2 *
3 **************************************************
4 * This code was created by Peter Harvey @ CodeByDesign.
5 * Released under LGPL 28.JAN.99
6 *
7 * Contributions from...
8 * -----------------------------------------------
9 * Peter Harvey - pharvey@codebydesign.com
10 **************************************************/
11#include <config.h>
12#include <odbcinstext.h>
13
14/*!
15 * \brief Standard installer error.
16 */
17typedef struct tODBCINSTErrorMsg
18{
19 int nCode; /*!< error code */
20 char * szMsg; /*!< error text */
21} ODBCINSTErrorMsg;
22
23/*!
24 * \brief A lookup for all standard installer (odbcinst) error codes and
25 * corresponding message text.
26 *
27 * An odd thing that we do here is that we assume the values of error codes
28 * (ODBC_ERROR_GENERAL_ERR, ODBC_ERROR_INVALID_BUFF_LEN, etc) are in the same
29 * sequence we have layed out here... ascending order starting at 1. We then
30 * can index into here using the standard error code and get the standard error
31 * text. This is why we have 0,"Filler" in here.
32 */
33static ODBCINSTErrorMsg aODBCINSTErrorMsgs[] =
34{
35 { 0, "Filler" },
36 { ODBC_ERROR_GENERAL_ERR, "General installer error" },
37 { ODBC_ERROR_INVALID_BUFF_LEN, "Invalid buffer length" },
38 { ODBC_ERROR_INVALID_HWND, "Invalid window handle" },
39 { ODBC_ERROR_INVALID_STR, "Invalid string" },
40 { ODBC_ERROR_INVALID_REQUEST_TYPE, "Invalid type of request" },
41 { ODBC_ERROR_COMPONENT_NOT_FOUND, "Unable to find component name" },
42 { ODBC_ERROR_INVALID_NAME, "Invalid driver or translator name" },
43 { ODBC_ERROR_INVALID_KEYWORD_VALUE, "Invalid keyword-value pairs" },
44 { ODBC_ERROR_INVALID_DSN, "Invalid DSN" },
45 { ODBC_ERROR_INVALID_INF, "Invalid INF" },
46 { ODBC_ERROR_REQUEST_FAILED, "General error request failed" },
47 { ODBC_ERROR_INVALID_PATH, "Invalid install path" },
48 { ODBC_ERROR_LOAD_LIB_FAILED, "Could not load the driver or translator setup library" },
49 { ODBC_ERROR_INVALID_PARAM_SEQUENCE, "Invalid parameter sequence" },
50 { ODBC_ERROR_INVALID_LOG_FILE, "Invalid log file" },
51 { ODBC_ERROR_USER_CANCELED, "User canceled operation" },
52 { ODBC_ERROR_USAGE_UPDATE_FAILED, "Could not increment or decrement the component usage count" },
53 { ODBC_ERROR_CREATE_DSN_FAILED, "Could not create the requested DSN" },
54 { ODBC_ERROR_WRITING_SYSINFO_FAILED, "Error writing sysinfo" },
55 { ODBC_ERROR_REMOVE_DSN_FAILED, "Removing DSN failed" },
56 { ODBC_ERROR_OUT_OF_MEM, "Out of memory" },
57 { ODBC_ERROR_OUTPUT_STRING_TRUNCATED, "String right truncated" }
58};
59
60/*!
61 * \brief Returns error information from odbcinst.
62 *
63 * All calls to odbcinst, except SQLInstallerError and SQLPostInstallerError, may
64 * post/log messages. An application checks the return value of a call and then
65 * calls SQLInstallerError, as needed, to get any error information.
66 *
67 * All calls to odbcinst, except SQLInstallerError and SQLPostInstallerError, will
68 * start by clearing out existing messages.
69 *
70 * \param nError Input. Messages are enumerated starting with 1 as the oldest. The
71 * ODBC specification states that there are a max 8 messages stored at
72 * any time but unixODBC may provide more than that.
73 * \param pnErrorCode Output. The odbcinst error code as per the ODBC specification.
74 * \param pszErrorMsg Output. The error text. In general this is the error text from
75 * the ODBC specification but unixODBC may provide an alternate, more
76 * meaningfull text.
77 * \param nErrorMsgMax Input. Max chars which can be returned in pszErrorMsg.
78 * \param pnErrorMsg Output. strlen of error text available to be returned.
79 *
80 * \return RETCODE
81 * \retval SQL_NO_DATA No data to be returned for nError.
82 * \retval SQL_ERROR Something went wrong - most likley bad args in call.
83 * \retval SQL_SUCCESS_WITH_INFO Text was truncated.
84 * \retval SQL_SUCCESS Error information was returned.
85 *
86 * \sa SQLPostInstallerError
87 * ODBCINSTErrorMsg
88 */
89RETCODE SQLInstallerError( WORD nError, DWORD *pnErrorCode, LPSTR pszErrorMsg, WORD nErrorMsgMax, WORD *pnErrorMsg )
90{
91 HLOGMSG hLogMsg = NULL;
92 WORD nErrorMsg = 0;
93 char * pszText = NULL;
94
95 /* these are mandatory so... */
96 if ( pnErrorCode == NULL || pszErrorMsg == NULL )
97 return SQL_ERROR;
98
99 /* this is optional so... */
100 if ( !pnErrorMsg )
101 pnErrorMsg = &nErrorMsg;
102
103 /* get our message */
104 if ( inst_logPeekMsg( nError, &hLogMsg ) != LOG_SUCCESS )
105 return SQL_NO_DATA;
106
107 /* return code */
108 *pnErrorCode = hLogMsg->nCode;
109
110 /* any custom message has precedence over the standard messages since its probably more meaningfull */
111 if ( *(hLogMsg->pszMessage) )
112 pszText = hLogMsg->pszMessage;
113 else
114 pszText = aODBCINSTErrorMsgs[hLogMsg->nCode].szMsg;
115
116 /* how many chars in error text? */
117 *pnErrorMsg = strlen( pszText );
118
119 /* are we going to have to truncate the text due to lack of buffer space? */
120 if ( *pnErrorMsg > nErrorMsgMax )
121 {
122 strncpy( pszErrorMsg, pszText, nErrorMsgMax );
123 pszErrorMsg[ nErrorMsgMax ] = '\0';
124 return SQL_SUCCESS_WITH_INFO;
125 }
126
127 /* success without further complications :) */
128 strcpy( pszErrorMsg, pszText );
129 return SQL_SUCCESS;
130}
131
132/*!
133 * \brief A wide char version of SQLInstallerError.
134 *
135 * \sa SQLInstallerError
136 */
137SQLRETURN INSTAPI SQLInstallerErrorW(WORD iError,
138 DWORD *pfErrorCode,
139 LPWSTR lpszErrorMsg,
140 WORD cbErrorMsgMax,
141 WORD *pcbErrorMsg)
142{
143 char *msg;
144 SQLRETURN ret;
145 WORD len;
146
147 if ( lpszErrorMsg )
148 {
149 if ( cbErrorMsgMax > 0 )
150 {
151 msg = calloc( cbErrorMsgMax + 1, 1 );
152 }
153 else
154 {
155 msg = NULL;
156 }
157 }
158 else
159 {
160 msg = NULL;
161 }
162
163 ret = SQLInstallerError( iError,
164 pfErrorCode,
165 msg,
166 cbErrorMsgMax,
167 &len );
168
169 if ( ret == SQL_SUCCESS )
170 {
171 if ( pcbErrorMsg )
172 *pcbErrorMsg = len;
173
174 if ( msg && lpszErrorMsg )
175 {
176 _single_copy_to_wide( lpszErrorMsg, msg, len + 1 );
177 }
178 }
179 else if ( ret == SQL_SUCCESS_WITH_INFO )
180 {
181 if ( pcbErrorMsg )
182 *pcbErrorMsg = len;
183
184 if ( msg && lpszErrorMsg )
185 {
186 _single_copy_to_wide( lpszErrorMsg, msg, cbErrorMsgMax );
187 }
188 }
189
190 if ( msg ) {
191 free( msg );
192 }
193
194 return ret;
195}
196