NCBI C++ ToolKit
util.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 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 
24 #include <freetds/time.h>
25 
26 #include <assert.h>
27 #include <ctype.h>
28 #include <limits.h>
29 #include <stdio.h>
30 
31 #if HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif /* HAVE_STDLIB_H */
34 
35 #if HAVE_STRING_H
36 #include <string.h>
37 #endif /* HAVE_STRING_H */
38 
39 #if HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif /* HAVE_UNISTD_H */
42 
43 #if HAVE_NETDB_H
44 #include <netdb.h>
45 #endif /* HAVE_NETDB_H */
46 
47 #ifdef _WIN32
48 #include <process.h>
49 #endif
50 
51 #include <freetds/tds.h>
52 #include <freetds/checks.h>
53 #include <freetds/thread.h>
54 
55 #define NCBI_INCLUDE_STRERROR_C
56 #include "ncbi_strerror.c"
57 
58 /**
59  * Set state of TDS connection, with logging and checking.
60  * \param tds state information for the socket and the TDS protocol
61  * \param state the new state of the connection, cf. TDS_STATE.
62  * \return the new state, which might not be \a state.
63  */
66 {
67  TDS_STATE prior_state;
68  static const char state_names[][8] = {
69  "IDLE",
70  "WRITING",
71  "SENDING",
72  "PENDING",
73  "READING",
74  "DEAD"
75  };
76  assert(state < TDS_VECTOR_SIZE(state_names));
77  assert(tds->state < TDS_VECTOR_SIZE(state_names));
78 
79  prior_state = tds->state;
80  if (state == prior_state)
81  return state;
82 
83  switch(state) {
84  case TDS_PENDING:
85  if (prior_state == TDS_READING || prior_state == TDS_WRITING) {
88  break;
89  }
90  tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n",
91  state_names[prior_state], state_names[state]);
92  break;
93  case TDS_READING:
94  /* transition to READING are valid only from PENDING */
96  return tds->state;
97  if (tds->state != TDS_PENDING) {
99  tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n",
100  state_names[prior_state], state_names[state]);
101  break;
102  }
103  tds->state = state;
104  break;
105  case TDS_SENDING:
106  if (prior_state != TDS_READING && prior_state != TDS_WRITING) {
107  tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n",
108  state_names[prior_state], state_names[state]);
109  break;
110  }
111  if (tds->state == TDS_READING) {
112  /* TODO check this code, copied from tds_submit_prepare */
118  }
119 
121  tds->state = state;
122  break;
123  case TDS_IDLE:
124  if (prior_state == TDS_DEAD && TDS_IS_SOCKET_INVALID(tds_get_s(tds))) {
125  tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n",
126  state_names[prior_state], state_names[state]);
127  break;
128  }
129  case TDS_DEAD:
130  if (prior_state == TDS_READING || prior_state == TDS_WRITING)
132  tds->state = state;
133  break;
134  case TDS_WRITING:
136 
138  return tds->state;
139 
140  if (tds->state == TDS_DEAD) {
142  tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n",
143  state_names[prior_state], state_names[state]);
145  break;
146  } else if (tds->state == TDS_READING) {
148  "tds_submit_query(): state is READING\n");
150  return tds->state;
151  } else if (tds->state != TDS_IDLE && tds->state != TDS_SENDING) {
153  tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n",
154  state_names[prior_state], state_names[state]);
156  break;
157  }
158 
159  if (tds->state == TDS_IDLE) {
160  /* TODO check this code, copied from tds_submit_prepare */
166  }
167 
168  tds->state = state;
169  break;
170  default:
171  assert(0);
172  break;
173  }
174 
175  state = tds->state;
176 
177  tdsdump_log(TDS_DBG_ERROR, "Changed query state from %s to %s\n", state_names[prior_state], state_names[state]);
179 
180  return state;
181 }
182 
183 
184 void
185 tds_swap_bytes(void *buf, int bytes)
186 {
187  unsigned char tmp, *begin, *last;
188 
189  begin = (unsigned char *) buf;
190  last = begin + bytes;
191 
192  while (begin < --last) {
193  tmp = *last;
194  *last = *begin;
195  *begin++ = tmp;
196  }
197 }
198 
199 /* not used by FreeTDS, uncomment if needed */
200 #ifdef ENABLE_DEVELOPING
201 unsigned int
202 tds_gettime_ms(void)
203 {
204 #ifdef _WIN32
205  return GetTickCount();
206 #elif defined(HAVE_GETHRTIME)
207  return (unsigned int) (gethrtime() / 1000000u);
208 #elif defined(HAVE_CLOCK_GETTIME) && defined(TDS_GETTIMEMILLI_CONST)
209  struct timespec ts;
210  clock_gettime(TDS_GETTIMEMILLI_CONST, &ts);
211  return (unsigned int) (ts.tv_sec * 1000u + ts.tv_nsec / 1000000u);
212 #elif defined(HAVE_GETTIMEOFDAY)
213  struct timeval tv;
214  gettimeofday(&tv, NULL);
215  return (unsigned int) (tv.tv_sec * 1000u + tv.tv_usec / 1000u);
216 #else
217 #error How to implement tds_gettime_ms ??
218 #endif
219 }
220 #endif
221 
222 /*
223  * Call the client library's error handler
224  */
225 #define EXINFO 1
226 #define EXUSER 2
227 #define EXNONFATAL 3
228 #define EXCONVERSION 4
229 #define EXSERVER 5
230 #define EXTIME 6
231 #define EXPROGRAM 7
232 #define EXRESOURCE 8
233 #define EXCOMM 9
234 #define EXFATAL 10
235 #define EXCONSISTENCY 11
236 
237 typedef struct tds_error_message
238 {
240  int severity;
241  const char *msgtext;
243 
245  { { TDSEICONVIU, EXCONVERSION, "Buffer exhausted converting characters from client into server's character set" }
246  , { TDSEICONVAVAIL, EXCONVERSION, "Character set conversion is not available between client character set '%.*s' and "
247  "server character set '%.*s'" }
248  , { TDSEICONVO, EXCONVERSION, "Error converting characters into server's character set. Some character(s) could "
249  "not be converted" }
250  , { TDSEICONVI, EXCONVERSION, "Some character(s) could not be converted into client's character set. "
251  "Unconverted bytes were changed to question marks ('?')" }
252  , { TDSEICONV2BIG, EXCONVERSION, "Some character(s) could not be converted into client's character set" }
253  , { TDSEPORTINSTANCE, EXUSER, "Both port and instance specified" }
254  , { TDSERPND, EXPROGRAM, "Attempt to initiate a new Adaptive Server operation with results pending" }
255  , { TDSEBTOK, EXCOMM, "Bad token from the server: Datastream processing out of sync" }
256  , { TDSECAP, EXCOMM, "DB-Library capabilities not accepted by the Server" }
257  , { TDSECAPTYP, EXCOMM, "Unexpected capability type in CAPABILITY datastream" }
258  , { TDSECLOS, EXCOMM, "Error in closing network connection" }
259  , { TDSECONN, EXCOMM, "Unable to connect: Adaptive Server is unavailable or does not exist" }
260  , { TDSEEUNR, EXCOMM, "Unsolicited event notification received" }
261  , { TDSEFCON, EXCOMM, "Adaptive Server connection failed" }
262  , { TDSENEG, EXCOMM, "Negotiated login attempt failed" }
263  , { TDSEOOB, EXCOMM, "Error in sending out-of-band data to the server" }
264  , { TDSEREAD, EXCOMM, "Read from the server failed" }
265  , { TDSETIME, EXTIME, "Adaptive Server connection timed out" }
266  , { TDSESEOF, EXCOMM, "Unexpected EOF from the server" }
267  , { TDSEINTF, EXUSER, "Server name not found in configuration files." }
268  , { TDSESOCK, EXCOMM, "Unable to open socket" }
269  , { TDSESYNC, EXCOMM, "Read attempted while out of synchronization with Adaptive Server" }
270  , { TDSEUHST, EXUSER, "Unknown host machine name." }
271  , { TDSEUMSG, EXCOMM, "Unknown message-id in MSG datastream" }
272  , { TDSEUSCT, EXCOMM, "Unable to set communications timer" }
273  , { TDSEUTDS, EXCOMM, "Unrecognized TDS version received from the server" }
274  , { TDSEWRIT, EXCOMM, "Write to the server failed" }
275  , { TDSECONF, EXUSER, "Local configuration error. "
276  "Check TDSDUMPCONFIG log for details." }
277  /* last, with msgno == TDSEOK */
278  , { TDSEOK, EXCONSISTENCY, "unrecognized msgno" }
279  };
280 
281 static
282 const char * retname(int retcode)
283 {
284  switch(retcode) {
285  case TDS_INT_CONTINUE:
286  return "TDS_INT_CONTINUE";
287  case TDS_INT_CANCEL:
288  return "TDS_INT_CANCEL";
289  case TDS_INT_TIMEOUT:
290  return "TDS_INT_TIMEOUT";
291  }
292  assert(0);
293  return "nonesuch";
294 }
295 
296 /**
297  * \brief Call the client library's error handler (for library-generated errors only)
298  *
299  * The client library error handler may return:
300  * TDS_INT_CANCEL -- Return TDS_FAIL to the calling function. For TDSETIME, closes the connection first.
301  * TDS_INT_CONTINUE -- For TDSETIME only, retry the network read/write operation. Else invalid.
302  * TDS_INT_TIMEOUT -- For TDSETIME only, send a TDSCANCEL packet. Else invalid.
303  *
304  * These are Sybase semantics, but they serve all purposes.
305  * The application tells the library to quit, fail, retry, or attempt to cancel. In the event of a network timeout,
306  * a failed operation necessarily means the connection becomes unusable, because no cancellation dialog was
307  * concluded with the server.
308  *
309  * It is the client library's duty to call the error handler installed by the application, if any, and to interpret the
310  * installed handler's return code. It may return to this function one of the above codes only. This function will not
311  * check the return code because there's nothing that can be done here except abort. It is merely passed to the
312  * calling function, which will (we hope) DTRT.
313  *
314  * \param tds_ctx points to a TDSCONTEXT structure
315  * \param tds the connection structure, may be NULL if not connected
316  * \param msgno an enumerated libtds msgno, cf. tds.h
317  * \param errnum the OS errno, if it matters, else zero
318  *
319  * \returns client library function's return code
320  */
321 int
322 tdserror (const TDSCONTEXT * tds_ctx, TDSSOCKET * tds, int msgno, int errnum)
323 {
324 #if 0
325  static const char int_exit_text[] = "FreeTDS: libtds: exiting because client error handler returned %d for msgno %d\n";
326  static const char int_invalid_text[] = "%s (%d) received from client library error handler for nontimeout for error %d."
327  " Treating as INT_EXIT\n";
328 #endif
329  const TDS_ERROR_MESSAGE *err;
330 
331  TDSMESSAGE msg;
332  int rc = TDS_INT_CANCEL;
333 
334  tdsdump_log(TDS_DBG_FUNC, "tdserror(%p, %p, %d, %d)\n", tds_ctx, tds, msgno, errnum);
335 
336  /* look up the error message */
337  for (err = tds_error_messages; err->msgno != TDSEOK; ++err) {
338  if (err->msgno == msgno)
339  break;
340  }
341 
342  CHECK_CONTEXT_EXTRA(tds_ctx);
343 
344  if (tds)
346 
347  if (tds_ctx && tds_ctx->err_handler) {
348  memset(&msg, 0, sizeof(TDSMESSAGE));
349  msg.msgno = msgno;
350  msg.severity = err->severity;
351  msg.state = -1;
352  msg.server = "OpenClient";
353  msg.line_number = -1;
354  msg.message = (TDS_CHAR*) err->msgtext;
356 
357  msg.oserr = errnum;
358  msg.osstr = errnum ? (char*) s_StrError(errnum) : NULL;
359 
360  /*
361  * Call client library handler.
362  * The client library must return a valid code. It is not checked again here.
363  */
364  rc = tds_ctx->err_handler(tds_ctx, tds, &msg);
365  tdsdump_log(TDS_DBG_FUNC, "tdserror: client library returned %s(%d)\n", retname(rc), rc);
366 
368  if (errnum) {
370  msg.osstr = NULL;
371  }
372  } else {
373  const static char msg[] = "tdserror: client library not called because either "
374  "tds_ctx (%p) or tds_ctx->err_handler is NULL\n";
375  tdsdump_log(TDS_DBG_ERROR, msg, tds_ctx);
376  }
377 
378 
379  assert(msgno == TDSETIME || rc != TDS_INT_TIMEOUT); /* client library should prevent */
380  assert(msgno == TDSETIME || rc != TDS_INT_CONTINUE); /* client library should prevent */
381 
382  if (msgno != TDSETIME && rc != TDS_INT_CANCEL) {
383  tdsdump_log(TDS_DBG_SEVERE, "exit: %s(%d) valid only for TDSETIME\n", retname(rc), rc);
384  rc = TDS_INT_CANCEL;
385  }
386 
387  if (rc == TDS_INT_TIMEOUT) {
389  rc = TDS_INT_CONTINUE;
390  }
391 
392  tdsdump_log(TDS_DBG_FUNC, "tdserror: returning %s(%d)\n", retname(rc), rc);
393 
394  return rc;
395 }
396 
397 /**
398  * Copy a string of length len to a new allocated buffer
399  * This function does not read more than len bytes
400  * Please note that some system implementation of strndup
401  * do not assure they don't read past len bytes as they
402  * use still strlen to check length to copy limiting
403  * after strlen to size passed
404  * Also this function is different from strndup as it assume
405  * that len bytes are valid
406  * String returned is NUL terminated
407  *
408  * \param s string to copy from
409  * \param len length to copy
410  *
411  * \returns string copied or NULL if errors
412  */
413 char *
414 tds_strndup(const void *s, TDS_INTPTR len)
415 {
416  char *out;
417 
418  if (len < 0)
419  return NULL;
420 
421  out = tds_new(char, len + 1);
422  if (out) {
423  memcpy(out, s, len);
424  out[len] = 0;
425  }
426  return out;
427 }
428 
std::ofstream out("events_result.xml")
main entry point for tests
#define CHECK_TDS_EXTRA(tds)
Definition: checks.h:31
#define CHECK_CONTEXT_EXTRA(ctx)
Definition: checks.h:32
static DLIST_TYPE *DLIST_NAME() last(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:51
#define TDS_IS_SOCKET_INVALID(s)
#define tds_new(type, n)
Definition: tds.h:1392
#define TDS_NO_COUNT
Definition: tds.h:214
#define TDS_INT_TIMEOUT
Definition: tds.h:211
@ TDS_OP_NONE
Definition: tds.h:873
#define tdsdump_log
Definition: tds.h:1561
static void tds_release_cur_dyn(TDSSOCKET *tds)
Definition: tds.h:1366
#define TDS_INT_CONTINUE
Definition: tds.h:209
#define TDS_DBG_SEVERE
Definition: tds.h:904
#define tds_get_s(tds)
Definition: tds.h:1298
tds_sysdep_intptr_type TDS_INTPTR
Definition: tds.h:155
#define TDS_INT_CANCEL
Definition: tds.h:210
@ TDS_PENDING
cilent is waiting for data
Definition: tds.h:866
@ TDS_SENDING
client would send data
Definition: tds.h:865
@ TDS_READING
client is reading data
Definition: tds.h:867
@ TDS_WRITING
client is writing data
Definition: tds.h:864
@ TDS_IDLE
no data expected
Definition: tds.h:863
@ TDS_DEAD
no connection
Definition: tds.h:868
TDSERRNO
Definition: tds.h:295
@ TDSEICONVO
Definition: tds.h:299
@ TDSEOOB
Definition: tds.h:317
@ TDSEICONVI
Definition: tds.h:300
@ TDSEFCON
Definition: tds.h:304
@ TDSEICONV2BIG
Definition: tds.h:301
@ TDSESYNC
Definition: tds.h:303
@ TDSEUMSG
Definition: tds.h:324
@ TDSEICONVAVAIL
Definition: tds.h:298
@ TDSECAPTYP
Definition: tds.h:325
@ TDSEBTOK
Definition: tds.h:316
@ TDSEPORTINSTANCE
Definition: tds.h:302
@ TDSECONF
Definition: tds.h:326
@ TDSESEOF
Definition: tds.h:314
@ TDSEUTDS
Definition: tds.h:320
@ TDSEEUNR
Definition: tds.h:321
@ TDSECONN
Definition: tds.h:309
@ TDSEREAD
Definition: tds.h:306
@ TDSECLOS
Definition: tds.h:318
@ TDSETIME
Definition: tds.h:305
@ TDSESOCK
Definition: tds.h:308
@ TDSEINTF
Definition: tds.h:311
@ TDSEICONVIU
Definition: tds.h:297
@ TDSEOK
Definition: tds.h:295
@ TDSEUHST
Definition: tds.h:312
@ TDSEWRIT
Definition: tds.h:307
@ TDSECAP
Definition: tds.h:322
@ TDSENEG
Definition: tds.h:323
@ TDSEUSCT
Definition: tds.h:319
@ TDSERPND
Definition: tds.h:315
#define TDS_VECTOR_SIZE(x)
Definition: tds.h:360
char TDS_CHAR
Definition: tds.h:144
enum tds_states TDS_STATE
values for tds->state
#define TDS_DBG_ERROR
Definition: tds.h:903
#define TDS_ZERO_FREE(x)
Definition: tds.h:359
#define tds_get_ctx(tds)
Definition: tds.h:1294
#define TDS_DBG_FUNC
Definition: tds.h:898
#define tds_mutex_trylock(x)
Definition: thread.h:422
#define tds_mutex_unlock(x)
Definition: thread.h:423
static char tmp[3200]
Definition: utf8.c:42
static TDSSOCKET * tds
Definition: collations.c:37
#define EXCONSISTENCY
Definition: util.c:235
char * tds_strndup(const void *s, TDS_INTPTR len)
Copy a string of length len to a new allocated buffer This function does not read more than len bytes...
Definition: util.c:414
TDS_STATE tds_set_state(TDSSOCKET *tds, TDS_STATE state)
Set state of TDS connection, with logging and checking.
Definition: util.c:65
struct tds_error_message TDS_ERROR_MESSAGE
#define EXCONVERSION
Definition: util.c:228
static const TDS_ERROR_MESSAGE tds_error_messages[]
Definition: util.c:244
#define EXCOMM
Definition: util.c:233
static const char * retname(int retcode)
Definition: util.c:282
#define EXTIME
Definition: util.c:230
#define EXPROGRAM
Definition: util.c:231
#define EXUSER
Definition: util.c:226
int tdserror(const TDSCONTEXT *tds_ctx, TDSSOCKET *tds, int msgno, int errnum)
Call the client library's error handler (for library-generated errors only)
Definition: util.c:322
void tds_swap_bytes(void *buf, int bytes)
Definition: util.c:185
#define tds_send_cancel
#define tds_alloc_client_sqlstate
#define tds_free_all_results
#define tds_release_cursor
unsigned int tds_gettime_ms(void)
Definition: util.c:209
#define NULL
Definition: ncbistd.hpp:225
#define UTIL_ReleaseBuffer(x)
Definition: ncbi_util.h:809
char * buf
int len
static const char * s_StrError(SOCK sock, int error)
Definition: ncbi_socket.c:326
#define assert(x)
Definition: srv_diag.hpp:58
int(* err_handler)(const TDSCONTEXT *, TDSSOCKET *, TDSMESSAGE *)
Definition: tds.h:1103
TDSERRNO msgno
Definition: util.c:239
const char * msgtext
Definition: util.c:241
TDS_CHAR * sql_state
Definition: tds.h:949
TDS_CHAR * message
Definition: tds.h:947
TDS_INT msgno
Definition: tds.h:950
TDS_CHAR * osstr
Definition: tds.h:958
TDS_INT line_number
Definition: tds.h:951
TDS_CHAR * server
Definition: tds.h:946
int oserr
Definition: tds.h:957
TDS_TINYINT severity
Definition: tds.h:955
TDS_SMALLINT state
Definition: tds.h:953
Information for a server connection.
Definition: tds.h:1211
TDSCURSOR * cur_cursor
cursor in use
Definition: tds.h:1268
tds_mutex wire_mtx
Definition: tds.h:1306
TDS_INT8 rows_affected
rows updated/deleted/inserted/selected, TDS_NO_COUNT if not valid
Definition: tds.h:1278
TDS_STATE state
Definition: tds.h:1273
TDS_OPERATION current_op
Definition: tds.h:1286
Modified on Sun Jun 23 05:15:10 2024 by modify_doxy.py rev. 669887