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

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for 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 Brian Bruns
3  * Copyright (C) 2005-2014 Frediano Ziglio
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 /**
22  * \file
23  * \brief Grab data from TDS packets
24  */
25 
26 #include <config.h>
27 
28 #if HAVE_ERRNO_H
29 #include <errno.h>
30 #endif /* HAVE_ERRNO_H */
31 
32 #if HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif /* HAVE_STDLIB_H */
35 
36 #if HAVE_STRING_H
37 #include <string.h>
38 #endif /* HAVE_STRING_H */
39 
40 #if HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif /* HAVE_UNISTD_H */
43 
44 #include <assert.h>
45 
46 #include <freetds/tds.h>
47 #include <freetds/iconv.h>
48 #include <freetds/bytes.h>
49 #include <freetds/stream.h>
50 #include <freetds/string.h>
51 #include <freetds/checks.h>
52 
53 static size_t read_and_convert(TDSSOCKET * tds, TDSICONV * char_conv,
54  size_t * wire_size, char *outbuf, size_t outbytesleft);
55 
56 /**
57  * \ingroup libtds
58  * \defgroup network Network functions
59  * Functions for reading or writing from network.
60  */
61 
62 /**
63  * \addtogroup network
64  * @{
65  */
66 
67 /**
68  * Return a single byte from the input buffer
69  * \tds
70  */
71 unsigned char
73 {
74  while (tds->in_pos >= tds->in_len) {
75  if (tds_read_packet(tds) < 0)
76  return 0;
77  }
78  return tds->in_buf[tds->in_pos++];
79 }
80 
81 /**
82  * Unget will always work as long as you don't call it twice in a row. It
83  * it may work if you call it multiple times as long as you don't backup
84  * over the beginning of network packet boundary which can occur anywhere in
85  * the token stream.
86  * \tds
87  */
88 void
90 {
91  /* this is a one trick pony...don't call it twice */
92  tds->in_pos--;
93 }
94 
95 /**
96  * Reads a byte from the TDS stream without removing it
97  * \tds
98  */
99 unsigned char
101 {
102  unsigned char result = tds_get_byte(tds);
103  if (tds->in_pos > 0)
104  --tds->in_pos;
105  return result;
106 } /* tds_peek() */
107 
108 
109 /**
110  * Get an int16 from the server.
111  */
114 {
115  TDS_USMALLINT bytes[1];
116 
117  tds_get_n(tds, &bytes, 2);
118 #if WORDS_BIGENDIAN
120  return (TDS_USMALLINT) TDS_GET_A2LE(&bytes);
121 #endif
122  return (TDS_USMALLINT) TDS_GET_A2(&bytes);
123 }
124 
125 
126 /**
127  * Get an int32 from the server.
128  * \tds
129  */
130 TDS_UINT
132 {
133  TDS_UINT bytes;
134 
135  tds_get_n(tds, &bytes, 4);
136 #if WORDS_BIGENDIAN
138  return TDS_GET_A4LE(&bytes);
139 #endif
140  return TDS_GET_A4(&bytes);
141 }
142 
143 /**
144  * Get an uint64 from the server.
145  * \tds
146  */
147 TDS_UINT8
149 {
150  TDS_UINT h;
151  TDS_UINT l;
152  TDS_UINT bytes[2];
153 
154  tds_get_n(tds, bytes, 8);
155 #if WORDS_BIGENDIAN
156  if (tds->conn->emul_little_endian) {
157  l = TDS_GET_A4LE(bytes);
158  h = TDS_GET_A4LE(bytes+1);
159  } else {
160  h = TDS_GET_A4(bytes);
161  l = TDS_GET_A4(bytes+1);
162  }
163 #else
164  l = TDS_GET_A4(bytes);
165  h = TDS_GET_A4(bytes+1);
166 #endif
167  return (((TDS_UINT8) h) << 32) | l;
168 }
169 
170 /**
171  * Fetch a string from the wire.
172  * Output string is NOT null terminated.
173  * If TDS version is 7 or 8 read unicode string and convert it.
174  * This function should be use to read server default encoding strings like
175  * columns name, table names, etc, not for data (use tds_get_char_data instead)
176  * @return bytes written to \a dest
177  * @param tds connection information
178  * @param string_len length of string to read from wire
179  * (in server characters, bytes for tds4-tds5, ucs2 for tds7+)
180  * @param dest destination buffer, if NULL string is read and discarded
181  * @param dest_size destination buffer size, in bytes
182  */
183 size_t
184 tds_get_string(TDSSOCKET * tds, size_t string_len, char *dest, size_t dest_size)
185 {
186  size_t wire_bytes = string_len;
187  unsigned conv = client2server_chardata;
188 
189  if (IS_TDS7_PLUS(tds->conn)) {
190  wire_bytes *= 2u;
191  conv = client2ucs2;
192  }
193 
194  if (dest == NULL) {
195  tds_get_n(tds, NULL, wire_bytes);
196  return string_len;
197  }
198 
199  return read_and_convert(tds, tds->conn->char_convs[conv], &wire_bytes, dest, dest_size);
200 }
201 
202 /**
203  * Fetch character data the wire.
204  * Output is NOT null terminated.
205  * If \a char_conv is not NULL, convert data accordingly.
206  * \param tds state information for the socket and the TDS protocol
207  * \param row_buffer destination buffer in current_row. Can't be NULL
208  * \param wire_size size to read from wire (in bytes)
209  * \param curcol column information
210  * \return TDS_SUCCESS or TDS_FAIL (probably memory error on text data)
211  */
212 TDSRET
213 tds_get_char_data(TDSSOCKET * tds, char *row_buffer, size_t wire_size, TDSCOLUMN * curcol)
214 {
215  size_t in_left;
216 
217  assert(curcol->char_conv);
218 
219  /*
220  * row_buffer is a column buffer, allocated when the column's metadata are processed
221  * and reused for each row.
222  */
223 
224  /* silly case, empty string */
225  if (wire_size == 0) {
226  curcol->column_cur_size = 0;
227  return TDS_SUCCESS;
228  }
229 
230  in_left = curcol->column_size;
231  curcol->column_cur_size
232  = (TDS_INT) read_and_convert(tds, curcol->char_conv, &wire_size,
233  row_buffer, in_left);
234  if (TDS_UNLIKELY(wire_size > 0)) {
235  tds_get_n(tds, NULL, wire_size);
236  tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: discarded %u on wire while reading %d into client. \n",
237  (unsigned int) wire_size, curcol->column_cur_size);
238  return TDS_FAIL;
239  }
240  return TDS_SUCCESS;
241 }
242 
243 /**
244  * Get N bytes from the buffer and return them in the already allocated space
245  * given to us. We ASSUME that the person calling this function has done the
246  * bounds checking for us since they know how many bytes they want here.
247  * dest of NULL means we just want to eat the bytes. (tetherow@nol.org)
248  */
249 void *
250 tds_get_n(TDSSOCKET * tds, void *dest, size_t need)
251 {
252  for (;;) {
253  unsigned int have = tds->in_len - tds->in_pos;
254 
255  if (need <= have)
256  break;
257  /* We need more than is in the buffer, copy what is there */
258  if (dest != NULL) {
259  memcpy((char *) dest, tds->in_buf + tds->in_pos, have);
260  dest = (char *) dest + have;
261  }
262  need -= have;
264  || tds->in_buf[1] != 0
265  || tds_read_packet(tds) < 0)) {
266  tds_close_socket(tds); /* evidently out of sync */
267  return NULL;
268  }
269  }
270  if (need > 0) {
271  /* get the remainder if there is any */
272  if (dest != NULL) {
273  memcpy((char *) dest, tds->in_buf + tds->in_pos, need);
274  }
275  tds->in_pos += (unsigned int) need;
276  }
277  return dest;
278 }
279 
280 /**
281  * For UTF-8 and similar, tds_iconv() may encounter a partial sequence when the chunk boundary
282  * is not aligned with the character boundary. In that event, it will return an error, and
283  * some number of bytes (less than a character) will remain in the tail end of temp[]. They are
284  * moved to the beginning, ptemp is adjusted to point just behind them, and the next chunk is read.
285  * \tds
286  * \param char_conv conversion structure
287  * \param[out] wire_size size readed from wire
288  * \param outbuf buffer to write to
289  * \param outbytesleft buffer length
290  * \return bytes readed
291  */
292 static size_t
293 read_and_convert(TDSSOCKET * tds, TDSICONV * char_conv, size_t * wire_size, char *outbuf,
294  size_t outbytesleft)
295 {
296  /* int res; */
299 
300  tds_datain_stream_init(&r, tds, *wire_size);
301  tds_staticout_stream_init(&w, outbuf, outbytesleft);
302 
303  /* res = */ tds_convert_stream(tds, char_conv, to_client,
304  &r.stream, &w.stream);
305  *wire_size = r.wire_size;
306  return (char *) w.stream.buffer - outbuf;
307 }
308 
309 /**
310  * Reads a string from wire and put in a DSTR.
311  * On error we read the bytes from the wire anyway.
312  * \tds
313  * \param[out] s output string
314  * \param[in] len string length (in characters)
315  * \return string or NULL on error
316  */
317 DSTR*
319 {
320  size_t out_len;
321 
323 
324  /* assure sufficient space for every conversion */
325  if (TDS_UNLIKELY(!tds_dstr_alloc(s, len * 4))) {
326  tds_get_n(tds, NULL, len);
327  return NULL;
328  }
329 
330  out_len = tds_get_string(tds, len, tds_dstr_buf(s), len * 4);
331  tds_dstr_setlen(s, out_len);
332  return s;
333 }
334 
335 /** @} */
#define TDS_GET_A2(ptr)
Definition: bytes.h:134
#define TDS_GET_A2LE(ptr)
Definition: bytes.h:140
#define TDS_GET_A4LE(ptr)
Definition: bytes.h:141
#define TDS_GET_A4(ptr)
Definition: bytes.h:136
static TDSICONV * conv
Definition: charconv.c:168
#define CHECK_TDS_EXTRA(tds)
Definition: checks.h:31
static TDSSOCKET * tds
Definition: collations.c:37
#define NULL
Definition: ncbistd.hpp:225
DSTR * tds_dstr_setlen(DSTR *s, size_t length)
limit length of string, MUST be <= current length
Definition: tdsstring.c:146
DSTR * tds_dstr_alloc(DSTR *s, size_t length) TDS_WUR
allocate space for length char
Definition: tdsstring.c:166
static char * tds_dstr_buf(DSTR *s)
Returns a buffer to edit the string.
Definition: string.h:59
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
unsigned char tds_get_byte(TDSSOCKET *tds)
Return a single byte from the input buffer \tds.
Definition: read.c:72
unsigned char tds_peek(TDSSOCKET *tds)
Reads a byte from the TDS stream without removing it \tds.
Definition: read.c:100
static size_t read_and_convert(TDSSOCKET *tds, TDSICONV *char_conv, size_t *wire_size, char *outbuf, size_t outbytesleft)
For UTF-8 and similar, tds_iconv() may encounter a partial sequence when the chunk boundary is not al...
Definition: read.c:293
TDS_UINT8 tds_get_uint8(TDSSOCKET *tds)
Get an uint64 from the server.
Definition: read.c:148
TDSRET tds_get_char_data(TDSSOCKET *tds, char *row_buffer, size_t wire_size, TDSCOLUMN *curcol)
Fetch character data the wire.
Definition: read.c:213
size_t tds_get_string(TDSSOCKET *tds, size_t string_len, char *dest, size_t dest_size)
Fetch a string from the wire.
Definition: read.c:184
TDS_UINT tds_get_uint(TDSSOCKET *tds)
Get an int32 from the server.
Definition: read.c:131
TDS_USMALLINT tds_get_usmallint(TDSSOCKET *tds)
Get an int16 from the server.
Definition: read.c:113
void tds_unget_byte(TDSSOCKET *tds)
Unget will always work as long as you don't call it twice in a row.
Definition: read.c:89
void * tds_get_n(TDSSOCKET *tds, void *dest, size_t need)
Get N bytes from the buffer and return them in the already allocated space given to us.
Definition: read.c:250
DSTR * tds_dstr_get(TDSSOCKET *tds, DSTR *s, size_t len)
Reads a string from wire and put in a DSTR.
Definition: read.c:318
@ to_client
Definition: iconv.h:70
int len
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
#define tds_convert_stream
#define tds_close_socket
#define tds_read_packet
#define tds_datain_stream_init
#define tds_staticout_stream_init
#define assert(x)
Definition: srv_diag.hpp:58
Metadata about columns in regular and compute rows.
Definition: tds.h:761
TDS_INT column_size
maximun size of data.
Definition: tds.h:766
TDSICONV * char_conv
refers to previously allocated iconv information
Definition: tds.h:784
TDS_INT column_cur_size
size written in variable (ie: char, text, binary).
Definition: tds.h:811
TDSICONV ** char_convs
Definition: tds.h:1161
unsigned int emul_little_endian
Definition: tds.h:1167
input stream to read data from tds protocol
Definition: stream.h:63
Structure to hold a string.
Definition: tds.h:116
char * buffer
write buffer.
Definition: stream.h:50
unsigned capacity
Definition: tds.h:1126
Information for a server connection.
Definition: tds.h:1211
unsigned in_len
input buffer length
Definition: tds.h:1239
unsigned char * in_buf
Input buffer.
Definition: tds.h:1223
unsigned in_pos
current position in in_buf
Definition: tds.h:1237
TDSPACKET * recv_packet
Definition: tds.h:1254
TDSCONNECTION conn[1]
Definition: tds.h:1215
output stream to write data to a static buffer.
Definition: stream.h:92
TDSOUTSTREAM stream
Definition: stream.h:93
Main include file for libtds.
#define TDS_FAIL
Definition: tds.h:204
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
@ client2server_chardata
Definition: tds.h:1110
@ client2ucs2
Definition: tds.h:1109
#define tdsdump_log
Definition: tds.h:1561
#define IS_TDS7_PLUS(x)
Definition: tds.h:1708
tds_sysdep_uint64_type TDS_UINT8
Definition: tds.h:154
int TDSRET
Definition: tds.h:201
tds_sysdep_uint16_type TDS_USMALLINT
Definition: tds.h:148
#define TDS_UNLIKELY(x)
Definition: tds.h:372
#define TDS_SUCCESS
Definition: tds.h:203
tds_sysdep_uint32_type TDS_UINT
Definition: tds.h:150
#define TDS_DBG_NETWORK
Definition: tds.h:901
else result
Definition: token2.c:20
uchar outbuf[(1000000+1000000)]
Definition: unzcrash.c:41
Modified on Tue Apr 09 07:59:02 2024 by modify_doxy.py rev. 669887
Modified on Wed Apr 10 07:34:22 2024 by modify_doxy.py rev. 669887
Modified on Thu Apr 11 15:13:23 2024 by modify_doxy.py rev. 669887
Modified on Fri Apr 12 17:20:40 2024 by modify_doxy.py rev. 669887
Modified on Sat Apr 13 11:48:20 2024 by modify_doxy.py rev. 669887
Modified on Sun Apr 14 05:28:02 2024 by modify_doxy.py rev. 669887
Modified on Tue Apr 16 20:12:39 2024 by modify_doxy.py rev. 669887
Modified on Wed Apr 17 13:10:08 2024 by modify_doxy.py rev. 669887
Modified on Sat Apr 20 12:19:53 2024 by modify_doxy.py rev. 669887
Modified on Sun Apr 21 03:42:55 2024 by modify_doxy.py rev. 669887