Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Brian Bruns
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Library General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Library General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Library General Public
15 : * License along with this library; if not, write to the
16 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : * Boston, MA 02111-1307, USA.
18 : */
19 :
20 : #include <config.h>
21 :
22 : #include <stdarg.h>
23 : #include <stdio.h>
24 : #include <assert.h>
25 :
26 : #if HAVE_STDLIB_H
27 : #include <stdlib.h>
28 : #endif /* HAVE_STDLIB_H */
29 :
30 : #if HAVE_ERRNO_H
31 : # include <errno.h>
32 : #endif /* HAVE_ERRNO_H */
33 :
34 : #include <freetds/utils.h>
35 : #include <freetds/tds.h>
36 : #include <freetds/convert.h>
37 : #include <sybdb.h>
38 : #include <syberror.h>
39 : #include <dblib.h>
40 :
41 : /*
42 : * test include consistency
43 : * I don't think all compiler are able to compile this code... if not comment it
44 : */
45 : #if ENABLE_EXTRA_CHECKS
46 :
47 : /* TODO test SYBxxx consistency */
48 :
49 : #define TEST_ATTRIBUTE(t,sa,fa,sb,fb) \
50 : TDS_COMPILE_CHECK(t,sizeof(((sa*)0)->fa) == sizeof(((sb*)0)->fb) && TDS_OFFSET(sa,fa) == TDS_OFFSET(sb,fb))
51 :
52 : TEST_ATTRIBUTE(t21,TDS_MONEY4,mny4,DBMONEY4,mny4);
53 : TEST_ATTRIBUTE(t22,TDS_OLD_MONEY,mnyhigh,DBMONEY,mnyhigh);
54 : TEST_ATTRIBUTE(t23,TDS_OLD_MONEY,mnylow,DBMONEY,mnylow);
55 : TEST_ATTRIBUTE(t24,TDS_DATETIME,dtdays,DBDATETIME,dtdays);
56 : TEST_ATTRIBUTE(t25,TDS_DATETIME,dttime,DBDATETIME,dttime);
57 : TEST_ATTRIBUTE(t26,TDS_DATETIME4,days,DBDATETIME4,days);
58 : TEST_ATTRIBUTE(t27,TDS_DATETIME4,minutes,DBDATETIME4,minutes);
59 : TEST_ATTRIBUTE(t28,TDS_NUMERIC,precision,DBNUMERIC,precision);
60 : TEST_ATTRIBUTE(t29,TDS_NUMERIC,scale,DBNUMERIC,scale);
61 : TEST_ATTRIBUTE(t30,TDS_NUMERIC,array,DBNUMERIC,array);
62 : #endif
63 :
64 : /*
65 : * The next 2 functions receive the info and error messages that come from the TDS layer.
66 : * The address of this function is passed to the TDS layer in dbinit().
67 : * It takes a pointer to a DBPROCESS, it's just that the TDS layer didn't
68 : * know what it really was.
69 : */
70 : int
71 2244 : _dblib_handle_info_message(const TDSCONTEXT * tds_ctx, TDSSOCKET * tds, TDSMESSAGE * msg)
72 : {
73 2244 : DBPROCESS *dbproc = (tds && tds_get_parent(tds))? (DBPROCESS *) tds_get_parent(tds) : NULL;
74 :
75 2244 : tdsdump_log(TDS_DBG_FUNC, "_dblib_handle_info_message(%p, %p, %p)\n", tds_ctx, tds, msg);
76 2244 : tdsdump_log(TDS_DBG_FUNC, "msgno %d: \"%s\"\n", msg->msgno, msg->message);
77 :
78 : /*
79 : * Check to see if the user supplied a function, else ignore the message.
80 : */
81 2244 : if (_dblib_msg_handler) {
82 5058 : _dblib_msg_handler(dbproc,
83 : msg->msgno,
84 1686 : msg->state,
85 1686 : msg->severity, msg->message, msg->server, msg->proc_name, msg->line_number);
86 : }
87 :
88 2244 : if (msg->severity > 10 && _dblib_err_handler) { /* call the application's error handler, if installed. */
89 : /*
90 : * Sybase docs say SYBESMSG is generated only in specific
91 : * cases (severity greater than 16, or deadlock occurred, or
92 : * a syntax error occurred.) However, actual observed
93 : * behavior is that SYBESMSG is always generated for
94 : * server messages with severity greater than 10.
95 : */
96 : /* Cannot call dbperror() here because server messsage numbers (and text) are not in its lookup table. */
97 : static const char message[] = "General SQL Server error: Check messages from the SQL Server";
98 98 : (*_dblib_err_handler)(dbproc, msg->severity, SYBESMSG, DBNOERR, (char *) message, NULL);
99 : }
100 2244 : return TDS_SUCCESS;
101 : }
102 :
103 : /** \internal
104 : * \dblib_internal
105 : * \brief handle errors generated by libtds
106 : * \param tds_ctx actually a dbproc: contains all information needed by db-lib to manage communications with the server.
107 : * \param tds contains all information needed by libtds to manage communications with the server.
108 : * \param msg the message to send
109 : * \returns
110 : * \remarks This function is called by libtds via tds_ctx->err_handler. It exists to convert the db-lib
111 : * error handler's return code into one that libtds will know how to handle.
112 : * libtds conveniently issues msgno's with the same values and meanings as db-lib and ODBC use.
113 : * (N.B. ODBC actually uses db-lib msgno numbers for its driver-specific "server errors".
114 : */
115 : /*
116 : * Stack:
117 : * libtds
118 : * tds_ctx->err_handler (pointer to _dblib_handle_err_message)
119 : * _dblib_handle_err_message
120 : * dbperror
121 : * client (or default) error handler
122 : * returns db-lib defined return code INT_something.
123 : * returns db-lib return code with Sybase semantics (adjusting client's code if need be)
124 : * returns libtds return code
125 : * decides what to do based on the universal libtds return code, thank you.
126 : */
127 : int
128 64 : _dblib_handle_err_message(const TDSCONTEXT * tds_ctx TDS_UNUSED, TDSSOCKET * tds, TDSMESSAGE * msg)
129 : {
130 64 : DBPROCESS *dbproc = (tds && tds_get_parent(tds))? (DBPROCESS *) tds_get_parent(tds) : NULL;
131 64 : int rc = INT_CANCEL;
132 :
133 64 : assert(_dblib_err_handler);
134 64 : assert(msg);
135 :
136 64 : rc = dbperror(dbproc, msg->msgno, msg->oserr, 0, 0, 0, 0);
137 :
138 : /*
139 : * Preprocess the return code to handle INT_TIMEOUT/INT_CONTINUE
140 : * for non-SYBETIME errors in the strange and different ways as
141 : * specified by Sybase and Microsoft.
142 : */
143 64 : if (msg->msgno != SYBETIME) {
144 8 : switch (rc) {
145 : case INT_TIMEOUT:
146 : rc = INT_EXIT;
147 : break;
148 0 : case INT_CONTINUE:
149 0 : if (!dbproc || !dbproc->msdblib) {
150 : /* Sybase behavior */
151 0 : assert(0); /* dbperror() should prevent */
152 : rc = INT_EXIT;
153 : } else {
154 : /* Microsoft behavior */
155 : rc = INT_CANCEL;
156 : }
157 : break;
158 : default:
159 : break;
160 : }
161 56 : }
162 :
163 : /*
164 : * Convert db-lib return code to libtds return code, and return.
165 : */
166 64 : switch (rc) {
167 : case INT_CANCEL: return TDS_INT_CANCEL;
168 16 : case INT_TIMEOUT: return TDS_INT_TIMEOUT;
169 32 : case INT_CONTINUE: return TDS_INT_CONTINUE;
170 :
171 : case INT_EXIT:
172 0 : assert(0); /* dbperror() should prevent */
173 : default:
174 : /* unknown return code from error handler */
175 0 : exit(EXIT_FAILURE);
176 : break;
177 : }
178 :
179 : /* not reached */
180 : assert(0);
181 : return TDS_INT_CANCEL;
182 : }
183 :
184 : /**
185 : * \ingroup dblib_internal
186 : * \brief check interrupts for libtds.
187 : *
188 : * \param vdbproc a DBPROCESS pointer, contains all information needed by db-lib to manage communications with the server.
189 : * \sa DBDEAD(), dbsetinterrupt().
190 : */
191 : int
192 216 : _dblib_check_and_handle_interrupt(void * vdbproc)
193 : {
194 216 : DBPROCESS * dbproc = (DBPROCESS*) vdbproc;
195 216 : int ret = INT_CONTINUE;
196 :
197 216 : assert( dbproc != NULL );
198 :
199 216 : if (dbproc->chkintr == NULL || dbproc->hndlintr == NULL)
200 : return INT_CONTINUE;
201 :
202 96 : tdsdump_log(TDS_DBG_FUNC, "_dblib_check_and_handle_interrupt %p [%p, %p]\n", dbproc, dbproc->chkintr, dbproc->hndlintr);
203 :
204 96 : if (dbproc->chkintr(dbproc)){
205 0 : switch (ret = dbproc->hndlintr(dbproc)) {
206 0 : case INT_EXIT:
207 0 : tdsdump_log(TDS_DBG_FUNC, "dbproc->hndlintr returned INT_EXIT, goodbye!\n");
208 0 : exit(1);
209 0 : case INT_CANCEL:
210 0 : tdsdump_log(TDS_DBG_FUNC, "dbproc->hndlintr returned INT_CANCEL\n");
211 : break;
212 0 : case INT_CONTINUE:
213 0 : tdsdump_log(TDS_DBG_FUNC, "dbproc->hndlintr returned INT_CONTINUE\n");
214 : break;
215 0 : default:
216 0 : tdsdump_log(TDS_DBG_FUNC, "dbproc->hndlintr returned an invalid value (%d), returning INT_CONTINUE\n", ret);
217 : ret = INT_CONTINUE;
218 : break;
219 : }
220 96 : }
221 : return ret;
222 : }
223 :
224 :
225 : void
226 0 : _dblib_setTDS_version(TDSLOGIN * tds_login, DBINT version)
227 : {
228 0 : switch (version) {
229 0 : case DBVERSION_42:
230 0 : tds_set_version(tds_login, 4, 2);
231 0 : break;
232 0 : case DBVERSION_46:
233 0 : tds_set_version(tds_login, 4, 6);
234 0 : break;
235 0 : case DBVERSION_100:
236 0 : tds_set_version(tds_login, 5, 0);
237 0 : break;
238 : }
239 0 : }
240 :
241 : void
242 0 : _dblib_convert_err(DBPROCESS * dbproc, TDS_INT len)
243 : {
244 0 : switch (len) {
245 0 : case TDS_CONVERT_NOAVAIL:
246 0 : dbperror(dbproc, SYBERDCN, 0);
247 0 : break;
248 0 : case TDS_CONVERT_SYNTAX:
249 0 : dbperror(dbproc, SYBECSYN, 0);
250 0 : break;
251 0 : case TDS_CONVERT_NOMEM:
252 0 : dbperror(dbproc, SYBEMEM, ENOMEM);
253 0 : break;
254 0 : case TDS_CONVERT_OVERFLOW:
255 0 : dbperror(dbproc, SYBECOFL, 0);
256 0 : break;
257 0 : default:
258 : case TDS_CONVERT_FAIL:
259 0 : dbperror(dbproc, SYBECINTERNAL, 0);
260 0 : break;
261 : }
262 0 : }
263 :
|