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 : #if HAVE_CONFIG_H
21 : #include <config.h>
22 : #endif /* HAVE_CONFIG_H */
23 :
24 : #if HAVE_STRING_H
25 : #include <string.h>
26 : #endif /* HAVE_STRING_H */
27 :
28 : #include "cspublic.h"
29 : #include "ctlib.h"
30 : #include "tds.h"
31 : #include "replacements.h"
32 : /* #include "fortify.h" */
33 :
34 :
35 : TDS_RCSID(var, "$Id: ctutil.c,v 1.29 2008/08/17 07:44:45 freddy77 Exp $");
36 :
37 : /*
38 : * test include consistency
39 : * I don't think all compiler are able to compile this code... if not comment it
40 : */
41 : #if ENABLE_EXTRA_CHECKS
42 :
43 : #if defined(__GNUC__) && __GNUC__ >= 2
44 : #define COMPILE_CHECK(name,check) \
45 : extern int name[(check)?1:-1] __attribute__ ((unused))
46 : #else
47 : #define COMPILE_CHECK(name,check) \
48 : extern int name[(check)?1:-1]
49 : #endif
50 :
51 : #define TEST_EQUAL(t,a,b) COMPILE_CHECK(t,a==b)
52 :
53 : TEST_EQUAL(t01,CS_FAIL,TDS_FAIL);
54 : TEST_EQUAL(t02,CS_SUCCEED,TDS_SUCCEED);
55 : TEST_EQUAL(t03,CS_NULLTERM,TDS_NULLTERM);
56 : TEST_EQUAL(t04,CS_CMD_SUCCEED,TDS_CMD_SUCCEED);
57 : TEST_EQUAL(t05,CS_CMD_FAIL,TDS_CMD_FAIL);
58 : TEST_EQUAL(t06,CS_CMD_DONE,TDS_CMD_DONE);
59 : TEST_EQUAL(t07,CS_NO_COUNT,TDS_NO_COUNT);
60 : TEST_EQUAL(t08,CS_COMPUTE_RESULT,TDS_COMPUTE_RESULT);
61 : TEST_EQUAL(t09,CS_PARAM_RESULT,TDS_PARAM_RESULT);
62 : TEST_EQUAL(t10,CS_ROW_RESULT,TDS_ROW_RESULT);
63 : TEST_EQUAL(t11,CS_STATUS_RESULT,TDS_STATUS_RESULT);
64 : TEST_EQUAL(t12,CS_COMPUTEFMT_RESULT,TDS_COMPUTEFMT_RESULT);
65 : TEST_EQUAL(t13,CS_ROWFMT_RESULT,TDS_ROWFMT_RESULT);
66 : TEST_EQUAL(t14,CS_MSG_RESULT,TDS_MSG_RESULT);
67 : TEST_EQUAL(t15,CS_DESCRIBE_RESULT,TDS_DESCRIBE_RESULT);
68 :
69 : #define TEST_ATTRIBUTE(t,sa,fa,sb,fb) \
70 : COMPILE_CHECK(t,sizeof(((sa*)0)->fa) == sizeof(((sb*)0)->fb) && (TDS_INTPTR)(&((sa*)0)->fa) == (TDS_INTPTR)(&((sb*)0)->fb))
71 :
72 : TEST_ATTRIBUTE(t21,TDS_MONEY4,mny4,CS_MONEY4,mny4);
73 : TEST_ATTRIBUTE(t22,TDS_OLD_MONEY,mnyhigh,CS_MONEY,mnyhigh);
74 : TEST_ATTRIBUTE(t23,TDS_OLD_MONEY,mnylow,CS_MONEY,mnylow);
75 : TEST_ATTRIBUTE(t24,TDS_DATETIME,dtdays,CS_DATETIME,dtdays);
76 : TEST_ATTRIBUTE(t25,TDS_DATETIME,dttime,CS_DATETIME,dttime);
77 : TEST_ATTRIBUTE(t26,TDS_DATETIME4,days,CS_DATETIME4,days);
78 : TEST_ATTRIBUTE(t27,TDS_DATETIME4,minutes,CS_DATETIME4,minutes);
79 : TEST_ATTRIBUTE(t28,TDS_NUMERIC,precision,CS_NUMERIC,precision);
80 : TEST_ATTRIBUTE(t29,TDS_NUMERIC,scale,CS_NUMERIC,scale);
81 : TEST_ATTRIBUTE(t30,TDS_NUMERIC,array,CS_NUMERIC,array);
82 : TEST_ATTRIBUTE(t30,TDS_NUMERIC,precision,CS_DECIMAL,precision);
83 : TEST_ATTRIBUTE(t31,TDS_NUMERIC,scale,CS_DECIMAL,scale);
84 : TEST_ATTRIBUTE(t32,TDS_NUMERIC,array,CS_DECIMAL,array);
85 : TEST_ATTRIBUTE(t33,TDS_VARBINARY,len,CS_VARBINARY,len);
86 : TEST_ATTRIBUTE(t34,TDS_VARBINARY,array,CS_VARBINARY,array);
87 : #endif
88 :
89 : /*
90 : * error handler
91 : * This callback function should be invoked only from libtds through tds_ctx->err_handler.
92 : */
93 : int
94 : _ct_handle_client_message(const TDSCONTEXT * ctx_tds, TDSSOCKET * tds, TDSMESSAGE * msg)
95 3 : {
96 : CS_CLIENTMSG errmsg;
97 3 : CS_CONNECTION *con = NULL;
98 3 : CS_CONTEXT *ctx = NULL;
99 3 : int ret = (int) CS_SUCCEED;
100 :
101 3 : if (tds && tds->parent) {
102 3 : con = (CS_CONNECTION *) tds->parent;
103 : }
104 :
105 3 : memset(&errmsg, '\0', sizeof(errmsg));
106 3 : errmsg.msgnumber = msg->msgno;
107 3 : strcpy(errmsg.msgstring, msg->message);
108 3 : errmsg.msgstringlen = strlen(msg->message);
109 3 : errmsg.osstring[0] = '\0';
110 3 : errmsg.osstringlen = 0;
111 : /* if there is no connection, attempt to call the context handler */
112 3 : if (!con) {
113 0 : ctx = (CS_CONTEXT *) ctx_tds->parent;
114 0 : if (ctx->_clientmsg_cb)
115 0 : ret = ctx->_clientmsg_cb(ctx, con, &errmsg);
116 3 : } else if (con->_clientmsg_cb)
117 0 : ret = con->_clientmsg_cb(con->ctx, con, &errmsg);
118 3 : else if (con->ctx->_clientmsg_cb)
119 0 : ret = con->ctx->_clientmsg_cb(con->ctx, con, &errmsg);
120 :
121 : /*
122 : * The return code from the error handler is either CS_SUCCEED or CS_FAIL.
123 : * This function was called by libtds with some kind of communications failure, and there are
124 : * no cases in which "succeed" could mean anything: In most cases, the function is going to fail
125 : * no matter what.
126 : *
127 : * Timeouts are a different matter; it's up to the client to decide whether to continue
128 : * waiting or to abort the operation and close the socket. ct-lib applications do their
129 : * own cancel processing -- they can call ct_cancel from within the error handler -- so
130 : * they don't need to return TDS_INT_TIMEOUT. They can, however, return TDS_INT_CONTINUE
131 : * or TDS_INT_CANCEL. We map the client's return code to those.
132 : *
133 : * Only for timeout errors does TDS_INT_CANCEL cause libtds to break the connection.
134 : */
135 3 : if (msg->msgno == TDSETIME) {
136 0 : switch (ret) {
137 0 : case CS_SUCCEED: return TDS_INT_CONTINUE;
138 0 : case CS_FAIL: return TDS_INT_CANCEL;
139 : }
140 : }
141 3 : return TDS_INT_CANCEL;
142 : }
143 :
144 : /* message handler */
145 : int
146 : _ct_handle_server_message(const TDSCONTEXT * ctx_tds, TDSSOCKET * tds, TDSMESSAGE * msg)
147 1156 : {
148 : CS_SERVERMSG errmsg;
149 1156 : CS_CONNECTION *con = NULL;
150 1156 : CS_CONTEXT *ctx = NULL;
151 1156 : int ret = (int) CS_SUCCEED;
152 :
153 1156 : if (tds && tds->parent) {
154 1156 : con = (CS_CONNECTION *) tds->parent;
155 : }
156 :
157 1156 : memset(&errmsg, '\0', sizeof(errmsg));
158 1156 : errmsg.msgnumber = msg->msgno;
159 1156 : tds_strlcpy(errmsg.text, msg->message, sizeof(errmsg.text));
160 1156 : errmsg.textlen = strlen(errmsg.text);
161 1156 : errmsg.sqlstate[0] = 0;
162 1156 : if (msg->sql_state)
163 23 : tds_strlcpy((char *) errmsg.sqlstate, msg->sql_state, sizeof(errmsg.sqlstate));
164 1156 : errmsg.sqlstatelen = strlen((char *) errmsg.sqlstate);
165 1156 : errmsg.state = msg->state;
166 1156 : errmsg.severity = msg->severity;
167 1156 : errmsg.line = msg->line_number;
168 1156 : if (msg->server) {
169 1156 : errmsg.svrnlen = strlen(msg->server);
170 1156 : tds_strlcpy(errmsg.svrname, msg->server, CS_MAX_NAME);
171 : }
172 1156 : if (msg->proc_name) {
173 1156 : errmsg.proclen = strlen(msg->proc_name);
174 1156 : tds_strlcpy(errmsg.proc, msg->proc_name, CS_MAX_NAME);
175 : }
176 : /* if there is no connection, attempt to call the context handler */
177 1156 : if (!con) {
178 0 : ctx = (CS_CONTEXT *) ctx_tds->parent;
179 0 : if (ctx->_servermsg_cb)
180 0 : ret = ctx->_servermsg_cb(ctx, con, &errmsg);
181 1156 : } else if (con->_servermsg_cb) {
182 3 : ret = con->_servermsg_cb(con->ctx, con, &errmsg);
183 1153 : } else if (con->ctx->_servermsg_cb) {
184 1150 : ret = con->ctx->_servermsg_cb(con->ctx, con, &errmsg);
185 : }
186 1156 : return ret;
187 : }
|