NCBI C++ ToolKit
data.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) 2003-2011 Frediano Ziglio
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 /**
21  * \page new_type How to add a new type
22  * \section intro Introduction
23  * Adding a new type in FreeTDS is a quite complicated task involving
24  * different tasks.
25  *
26  * To see an example you can look at
27  * \commit{adb893f1381fd3ea40564c775e30dc8cdc81dcf2}
28  * ("Implement big(date)time types") and parent changes in the source
29  * repository.
30  *
31  * \section tds libTDS changes
32  * <ul>
33  * <li>protocol. First thing to do is add the type to the protocol.
34  * A type usually have some mnemonic constant and a structure.
35  * Declare them in \c include/freetds/proto.h file. Note that
36  * here you should declare the structure the server use not
37  * the structure to hold the data in libTDS.
38  * <br>Cfr \commit{a74a06e1f97f3137f6cf1bc7319dd7a2cfb52b1f}.
39  *
40  * <li>base information. Add the type to \c misc/types.csv file
41  * (I use LibreOffice Calc to do it). This table maintain the
42  * base information for a type.
43  * <br>Cfr \commit{680cb3371e042bb372cbc5e6feb4054e50d40c1a}.
44  *
45  * <li>data. There should be some code to handle this type to/from
46  * the server. This code is implemented in \c include/freetds/data.h
47  * and \c src/tds/data.c. You can either add a new set of functions
48  * to handle this new type or add the type handling do another set
49  * of types depending on how complicated is that type.
50  * One thing you have to to at this step is determine how you store
51  * that type in libTDS. This is quite important at upper level
52  * libraries will have to use these structures or even present
53  * these data to client code (like DB-Library usually do).
54  * Due to the way FreeTDS works now you would get a linker error
55  * in the ODBC part. You can either ignore the error and proceed
56  * with libTDS, add the code to ODBC or disable temporarily ODBC.
57  * <br>Cfr \commit{680cb3371e042bb372cbc5e6feb4054e50d40c1a}.
58  *
59  * <li>enable the type from server. In order to receive the new type
60  * from the server you have to tell the server that we support
61  * that type. This can be either done changing the protocol (usually
62  * Microsoft) or enabling some flags (capabilities for Sybase).
63  * <br>Cfr \commit{a498703ff9e309c656b19dd990f4cad0283a47c7}.
64  *
65  * <li>conversions. Conversions are not hard to write but usually
66  * require quite a bit of coding. After extending CONV_RESULT
67  * type in \c include/freetds/convert.h and adding the type to
68  * the script that generate the conversion tables in
69  * \c src/tds/tds_willconvert.pl you have to write the big part
70  * in \c src/tds/covnert.c. You have to implement all kind of
71  * conversions you declared in the previous file. Reuse the
72  * functions that are there (for instance there are some
73  * parser functions). Also if there are similar types it could
74  * be helpful to convert first your type to a super type then
75  * use the conversion for that type. For instance for SMALLINT
76  * type (\c tds_convert_int2) the type is just readed and then
77  * \c tds_convert_int is called which handle any int (actually
78  * 32 bit integer). Same for data where the \c TDS_DATETIMEALL
79  * structure is used. Note that conversions to binary (which
80  * usually are implemented) are done in another function
81  * (\c tds_convert_to_binary).
82  * <br>Cfr \commit{9ed52cb78f725607ac109c8c284ca7c4658d87a9}.
83  *
84  * <li>string definition. Add string for your type to
85  * \c src/tds/token.c in \c tds_prtype.
86  * <br>Cfr \commit{ac0d3b46db7d98436cd76f906b7d455f7651faae}.
87  *
88  * <li>conversion tests. You probably will have done some mistake
89  * with conversions but don't mind, there are some tests which
90  * will help sorting this out.
91  * \c src/tds/unittests/convert.c
92  * try any possible combination of conversion to check if
93  * all conversion are implemented (it does not check the
94  * conversions themself).
95  * \c src/tds/unittests/t0007.c test that your conversion
96  * are working. Just add manually the conversions you want
97  * to try.
98  * <br>Cfr \commit{abcc09c9a88acd0e9a45b46dab3ca44309917a02}.
99  *
100  * <li>parameter. Add type/parameter declaration in
101  * \c tds_get_column_declaration in \c src/tds/query.c.
102  * Also do any necessary step to initialize the parameter
103  * to send to server.
104  * <br>Cfr \commit{54fdd3233e430c045cf5524ac385770738d9e92c},
105  * \commit{88cfea19d91245372779b8893a2d62b42696cd49}.
106  *
107  * <li>emulated prepared/rpc. If needed handle your type
108  * in \c tds_put_param_as_string in \c src/tds/query.c.
109  * <br>Cfr \commit{017b7bf2fee0f09847e64546d27382d2f2b756f4}.
110  *
111  * </ul>
112  *
113  * \section odbc ODBC changes
114  * ODBC is the most complicated library to add a type to.
115  * Usually its data are different from libTDS so you have to add additional
116  * code for conversions which are not required by other libraries.
117  * <ul>
118  * <li>type information. Every type in ODBC have related information.
119  * These information are set in \c src/odbc/odbc_data.c.
120  * Depending on the changes you did for data in libTDS you should
121  * handle the new type.
122  * <br>Cfr \commit{71e189e206dc9b6f6513e0aa0e4133a4f8dec110}.
123  *
124  * <li>type information test. Related to the previous change there
125  * is \c src/odbc/unittests/describecol.c test. Add a test case
126  * for new type. You should attempt to run same test also on
127  * proprietary library if possible.
128  * <br>Cfr \commit{8a8ec16a6a514a5d6ac66c2470eff51f6a8d4a53}.
129  *
130  * <li>conversions from odbc. Define how the ODBC type should convert
131  * to the server and implement the conversion.
132  * <br>Cfr \commit{29606cbf413c44e49ddfcfb8a93b8a6bd2565a84},
133  * \commit{87c84e20a594472a72990b12d4a1451b22e6714b}.
134  *
135  * <li>conversions to binary. Binary representation in ODBC are usually
136  * different from server ones. If so implement the proper conversions.
137  * <br>Cfr \commit{56009f35d3e0def339a0c5cb98d006e5e710d523}.
138  *
139  * <li>conversions to characters. Same problem for character types.
140  * <br>Cfr \commit{25ff091880dabc32f28a73f09bf31c01314aca2f}.
141  *
142  * <li>conversion test. You probably want to test ODBC conversions.
143  * This can be done changing \c src/odbc/unittests/data.c test and
144  * \c src/odbc/unittests/genparams.c.
145  * <br>Cfr \commit{e69f7d564dac44884f7c5f0106cceafce4af168b}.
146  * </ul>
147  *
148  * \section ctlib CT-Library changes
149  * This is quite easy as usual the conversion in libTDS are fine for
150  * this library.
151  * <ul>
152  * <li>define type in \c include/cspublic.h
153  * <li>implement conversion in \c src/ctlib/cs.h
154  * <li>set corrent conversion from cs types to server in
155  * \c src/ctlib/ct.c
156  * </ul>
157  * Cfr \commit{c5e71e5ad4a557038ecedcec457e2531ab02a77b}.
158  *
159  * \section dblib DB-Library changes
160  * A bit more complicated than CT-Library but not that much.
161  * <ul>
162  * <li>add type and binding type to \c include/sybdb.h
163  * <li>add NULL handling in \c dbgetnull, \c dbsetnull
164  * and \c default_null_representation in
165  * \c src/dblib/dblib.c
166  * <li>add binding to dbbindtype
167  * <li>add support for conversion from/to server
168  * <li>add printable size
169  * <li>return correct type string
170  * </ul>
171  * Cfr \commit{99dd126e0eb248dd3079b2a7cf97437fe3bcd163}.
172  *
173  * \section apps Applications changes
174  * datacopy application requires some changes too to support new types
175  * so add them to \c src/apps/datacopy.c.
176  * <br>Cfr \commit{e59c48ac39c76abb036651f8ec238090eef321c9}.
177  */
178 
179 /**
180  * @file
181  * @brief Handle different data handling from network
182  */
183 
184 #include <config.h>
185 
186 #include <stdarg.h>
187 #include <stdio.h>
188 #include <assert.h>
189 
190 #if HAVE_STRING_H
191 #include <string.h>
192 #endif /* HAVE_STRING_H */
193 
194 #if HAVE_STDLIB_H
195 #include <stdlib.h>
196 #endif /* HAVE_STDLIB_H */
197 
198 #define TDS_DONT_DEFINE_DEFAULT_FUNCTIONS
199 #include <freetds/tds.h>
200 #include <freetds/bytes.h>
201 #include <freetds/iconv.h>
202 #include <freetds/checks.h>
203 #include <freetds/stream.h>
204 #include <freetds/data.h>
205 
206 #define USE_ICONV (tds->conn->use_iconv)
207 
209 #ifdef WORDS_BIGENDIAN
210 static void tds_swap_datatype(int coltype, void *b);
211 #endif
212 static void tds_swap_numeric(TDS_NUMERIC *num);
213 
214 #undef MIN
215 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
216 #undef MAX
217 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
218 
219 /**
220  * Set type of column initializing all dependency
221  * @param curcol column to set
222  * @param type type to set
223  */
224 void
226 {
227  /* set type */
228  curcol->on_server.column_type = type;
229  curcol->funcs = tds_get_column_funcs(conn, type);
231 
232  /* set size */
233  curcol->column_cur_size = -1;
235  if (curcol->column_varint_size == 0)
237 
238 }
239 
240 /**
241  * Set type of column initializing all dependency
242  * \param tds state information for the socket and the TDS protocol
243  * \param curcol column to set
244  * \param type type to set
245  */
246 void
248 {
249  if (IS_TDS7_PLUS(conn)) {
250  switch (type) {
251  case SYBNVARCHAR:
252  type = XSYBNVARCHAR;
253  break;
254  case SYBVARCHAR:
255  type = XSYBVARCHAR;
256  break;
257  case SYBCHAR:
258  type = XSYBCHAR;
259  break;
260  case SYBVARBINARY:
262  break;
263  case SYBBINARY:
264  type = XSYBBINARY;
265  break;
266  case SYBBIT:
267  if (IS_TDS71_PLUS(conn)) {
268  type = SYBINT1;
269  }
270  break;
271  /* avoid warning on other types */
272  default:
273  break;
274  }
275  } else if (IS_TDS50(conn)) {
276  if (type == SYBINT8)
277  type = SYB5INT8;
278  }
279  tds_set_column_type(conn, curcol, type);
280 
281  if (is_collate_type(type)) {
283  memcpy(curcol->column_collation, conn->collation, sizeof(conn->collation));
284  }
285 
286  /* special case, GUID, varint != 0 but only a size */
287  /* TODO VARIANT, when supported */
288  switch (type) {
289  case SYBUNIQUE:
290  curcol->on_server.column_size = curcol->column_size = sizeof(TDS_UNIQUE);
291  break;
292  case SYBBITN:
293  curcol->on_server.column_size = curcol->column_size = sizeof(TDS_TINYINT);
294  break;
295  /* mssql 2005 don't like SYBINT4 as parameter closing connection */
296  case SYBINT1:
297  case SYBINT2:
298  case SYBINT4:
299  case SYBINT8:
300  curcol->on_server.column_type = SYBINTN;
301  curcol->column_varint_size = 1;
302  curcol->column_cur_size = -1;
303  break;
304  case SYBMONEY4:
305  case SYBMONEY:
306  curcol->on_server.column_type = SYBMONEYN;
307  curcol->column_varint_size = 1;
308  curcol->column_cur_size = -1;
309  break;
310  case SYBDATETIME:
311  case SYBDATETIME4:
313  curcol->column_varint_size = 1;
314  curcol->column_cur_size = -1;
315  break;
316  case SYBFLT8:
317  case SYBREAL:
318  curcol->on_server.column_type = SYBFLTN;
319  curcol->column_varint_size = 1;
320  curcol->column_cur_size = -1;
321  break;
322  case SYBNTEXT:
323  if (IS_TDS72_PLUS(conn)) {
324  curcol->column_varint_size = 8;
326  }
327  break;
328  case SYBTEXT:
329  if (IS_TDS72_PLUS(conn)) {
330  curcol->column_varint_size = 8;
332  }
333  break;
334  case SYBIMAGE:
335  if (IS_TDS72_PLUS(conn)) {
336  curcol->column_varint_size = 8;
338  }
339  break;
340  case SYB5BIGTIME:
341  case SYB5BIGDATETIME:
342  curcol->column_prec = 6;
343  curcol->column_scale = 6;
344  break;
345  default:
346  break;
347  }
348 }
349 
351 tds_get_cardinal_type(TDS_SERVER_TYPE datatype, int usertype)
352 {
353  switch (datatype) {
354  case XSYBVARBINARY:
355  return SYBVARBINARY;
356  case XSYBBINARY:
357  return SYBBINARY;
358  case SYBNTEXT:
359  return SYBTEXT;
360  case XSYBNVARCHAR:
361  case XSYBVARCHAR:
362  return SYBVARCHAR;
363  case XSYBNCHAR:
364  case XSYBCHAR:
365  return SYBCHAR;
366  case SYB5INT8:
367  return SYBINT8;
368  case SYBLONGBINARY:
369  switch (usertype) {
370  case USER_UNICHAR_TYPE:
372  return SYBTEXT;
373  }
374  break;
375  default:
376  break;
377  }
378  return datatype;
379 }
380 
381 TDSRET
383 {
384  switch (col->column_varint_size) {
385  case 8:
386  col->column_size = 0x7ffffffflu;
387  break;
388  case 4:
389  col->column_size = tds_get_int(tds);
390  if (col->column_size < 0)
391  return TDS_FAIL;
392  break;
393  case 2:
394  /* assure > 0 */
396  /* under TDS7.2 this means ?var???(MAX) */
397  if (col->column_size < 0 && IS_TDS72_PLUS(tds->conn)) {
398  if (is_char_type(col->column_type)) {
399  col->column_size = 0x3ffffffflu;
400  } else {
401  col->column_size = 0x7ffffffflu;
402  }
403  col->column_varint_size = 8;
404  }
405  if (col->column_size < 0)
406  return TDS_FAIL;
407  break;
408  case 1:
409  col->column_size = tds_get_byte(tds);
410  break;
411  case 0:
413  break;
414  }
415 
417  /* based on true type as sent by server */
418  /*
419  * first 2 bytes are windows code (such as 0x409 for english)
420  * other 2 bytes ???
421  * last bytes is id in syscharsets
422  */
423  tds_get_n(tds, col->column_collation, 5);
424  col->char_conv =
426  }
427 
428  /* Only read table_name for blob columns (eg. not for SYBLONGBINARY) */
429  if (is_blob_type(col->on_server.column_type)) {
430  /* discard this additional byte */
431  if (IS_TDS72_PLUS(tds->conn)) {
432  unsigned char num_parts = tds_get_byte(tds);
433  /* TODO do not discard first ones */
434  for (; num_parts; --num_parts) {
436  }
437  } else {
439  }
440  } else if (IS_TDS72_PLUS(tds->conn) && col->on_server.column_type == SYBMSXML) {
441  unsigned char has_schema = tds_get_byte(tds);
442  if (has_schema) {
443  /* discard schema informations */
444  tds_get_string(tds, tds_get_byte(tds), NULL, 0); /* dbname */
445  tds_get_string(tds, tds_get_byte(tds), NULL, 0); /* schema owner */
446  tds_get_string(tds, tds_get_usmallint(tds), NULL, 0); /* schema collection */
447  }
448  }
449  return TDS_SUCCESS;
450 }
451 
452 /* tds_generic_row_len support also variant and return size to hold blob */
453 TDS_COMPILE_CHECK(variant_size, sizeof(TDSBLOB) >= sizeof(TDSVARIANT));
454 
455 TDS_INT
457 {
458  CHECK_COLUMN_EXTRA(col);
459 
460  if (is_blob_col(col))
461  return sizeof(TDSBLOB);
462  return col->column_size + col->column_varint_size;
463 }
464 
465 static TDSRET
466 tds_get_char_dynamic(TDSSOCKET *tds, TDSCOLUMN *curcol, void **pp, size_t allocated, TDSINSTREAM *r_stream)
467 {
468  TDSRET res;
470 
471  /*
472  * Blobs don't use a column's fixed buffer because the official maximum size is 2 GB.
473  * Instead, they're reallocated as necessary, based on the data's size.
474  */
475  res = tds_dynamic_stream_init(&w, pp, allocated);
476  if (TDS_FAILED(res))
477  return res;
478 
479  if (USE_ICONV && curcol->char_conv)
480  res = tds_convert_stream(tds, curcol->char_conv, to_client, r_stream, &w.stream);
481  else
482  res = tds_copy_stream(tds, r_stream, &w.stream);
483  curcol->column_cur_size = w.size;
484  return res;
485 }
486 
487 typedef struct tds_varmax_stream {
492 
493 static int
494 tds_varmax_stream_read(TDSINSTREAM *stream, void *ptr, size_t len)
495 {
496  TDSVARMAXSTREAM *s = (TDSVARMAXSTREAM *) stream;
497 
498  /* read chunk len if needed */
499  if (s->chunk_left == 0) {
500  TDS_INT l = tds_get_int(s->tds);
501  if (l <= 0) l = -1;
502  s->chunk_left = l;
503  }
504 
505  /* no more data ?? */
506  if (s->chunk_left < 0)
507  return 0;
508 
509  /* read part of data */
510  if (len > s->chunk_left)
511  len = s->chunk_left;
512  s->chunk_left -= (TDS_INT) len;
513  if (tds_get_n(s->tds, ptr, len))
514  return len;
515  return -1;
516 }
517 
518 static TDSRET
520 {
521  TDS_INT8 len;
523  size_t allocated = 0;
524  void **pp = (void**) &(((TDSBLOB*) curcol->column_data)->textvalue);
525 
526  len = tds_get_int8(tds);
527 
528  /* NULL */
529  if (len == -1) {
530  curcol->column_cur_size = -1;
531  return TDS_SUCCESS;
532  }
533 
534  /* try to allocate an initial buffer */
535  if (len > (TDS_INT8) (~((size_t) 0) >> 1))
536  return TDS_FAIL;
537  if (len > 0) {
538  TDS_ZERO_FREE(*pp);
539  allocated = (size_t) len;
541  allocated /= 2;
542  }
543 
544  r.stream.read = tds_varmax_stream_read;
545  r.tds = tds;
546  r.chunk_left = 0;
547 
548  return tds_get_char_dynamic(tds, curcol, pp, allocated, &r.stream);
549 }
550 
551 TDS_COMPILE_CHECK(tds_variant_size, sizeof(((TDSVARIANT*)0)->data) == sizeof(((TDSBLOB*)0)->textvalue));
552 TDS_COMPILE_CHECK(tds_variant_offset,TDS_OFFSET(TDSVARIANT, data) == TDS_OFFSET(TDSBLOB, textvalue));
553 
554 /*
555  * This strange type has following structure
556  * 0 len (int32) -- NULL
557  * len (int32), type (int8), data -- ints, date, etc
558  * len (int32), type (int8), 7 (int8), collation, column size (int16) -- [n]char, [n]varchar, binary, varbinary
559  * BLOBS (text/image) not supported
560  */
561 TDSRET
563 {
564  unsigned int colsize = tds_get_uint(tds);
565  int varint;
567  TDS_UCHAR info_len;
568  TDSVARIANT *v;
569  TDSRET rc;
570 
571  /* NULL */
572  curcol->column_cur_size = -1;
573  if (colsize < 2) {
574  tds_get_n(tds, NULL, colsize);
575  return TDS_SUCCESS;
576  }
577 
579  info_len = tds_get_byte(tds);
580  if (!is_tds_type_valid(type))
581  goto error_type;
582  v = (TDSVARIANT*) curcol->column_data;
583  v->type = type;
584  colsize -= 2;
585  if (info_len > colsize)
586  goto error_type;
587  if (is_collate_type(type)) {
588  if (sizeof(v->collation) > info_len)
589  goto error_type;
590  tds_get_n(tds, v->collation, sizeof(v->collation));
591  colsize -= sizeof(v->collation);
592  info_len -= sizeof(v->collation);
593  curcol->char_conv = is_unicode_type(type) ?
595  }
596 
597  /* special case for numeric */
598  if (is_numeric_type(type)) {
599  TDS_NUMERIC *num;
600  if (info_len != 2)
601  goto error_type;
602  if (v->data)
603  TDS_ZERO_FREE(v->data);
604  v->data_len = sizeof(TDS_NUMERIC);
605  num = tds_new0(TDS_NUMERIC, 1);
606  v->data = (TDS_CHAR *) num;
607  num->precision = tds_get_byte(tds);
608  num->scale = tds_get_byte(tds);
609  colsize -= 2;
610  /* check prec/scale, don't let server crash us */
611  if (num->precision < 1 || num->precision > MAXPRECISION
612  || num->scale > num->precision)
613  goto error_type;
614  if (colsize > sizeof(num->array))
615  goto error_type;
616  curcol->column_cur_size = colsize;
617  tds_get_n(tds, num->array, colsize);
618  if (IS_TDS7_PLUS(tds->conn))
619  tds_swap_numeric(num);
620  return TDS_SUCCESS;
621  }
622 
623  /* special case for MS date/time */
624  switch (type) {
625  case SYBMSTIME:
626  case SYBMSDATETIME2:
627  case SYBMSDATETIMEOFFSET:
628  if (info_len != 1)
629  goto error_type;
630  curcol->column_scale = curcol->column_prec = tds_get_byte(tds);
631  if (curcol->column_prec > 7)
632  goto error_type;
633  colsize -= info_len;
634  info_len = 0;
635  /* fall through */
636  case SYBMSDATE:
637  if (info_len != 0)
638  goto error_type;
639  /* dirty trick */
640  tds->in_buf[--tds->in_pos] = colsize;
641  if (v->data)
642  TDS_ZERO_FREE(v->data);
643  v->data_len = sizeof(TDS_DATETIMEALL);
644  v->data = tds_new0(TDS_CHAR, sizeof(TDS_DATETIMEALL));
645  curcol->column_type = type;
646  curcol->column_data = (unsigned char *) v->data;
647  /* trick, call get function */
648  rc = tds_msdatetime_get(tds, curcol);
649  curcol->column_type = SYBVARIANT;
650  curcol->column_data = (unsigned char *) v;
651  return rc;
652  default:
653  break;
654  }
655  varint = (type == SYBUNIQUE) ? 0 : tds_get_varint_size(tds->conn, type);
656  if (varint != info_len || varint > 2)
657  goto error_type;
658  switch (varint) {
659  case 0:
661  break;
662  case 1:
663  v->size = tds_get_byte(tds);
664  break;
665  case 2:
666  v->size = tds_get_smallint(tds);
667  break;
668  default:
669  goto error_type;
670  }
671  colsize -= info_len;
672  curcol->column_cur_size = colsize;
673  if (v->data)
674  TDS_ZERO_FREE(v->data);
675  if (colsize) {
676  TDSRET res;
678 
679  if (USE_ICONV && curcol->char_conv)
681 
682  tds_datain_stream_init(&r, tds, colsize);
683  res = tds_get_char_dynamic(tds, curcol, (void **) &v->data, colsize, &r.stream);
684  if (TDS_FAILED(res))
685  return res;
686  colsize = curcol->column_cur_size;
687 #ifdef WORDS_BIGENDIAN
689  tds_swap_datatype(tds_get_conversion_type(type, colsize), v->data);
690 #endif
691  }
692  v->data_len = colsize;
693  return TDS_SUCCESS;
694 
695 error_type:
696  tds_get_n(tds, NULL, colsize);
697  return TDS_FAIL;
698 }
699 
700 /**
701  * Read a data from wire
702  * \param tds state information for the socket and the TDS protocol
703  * \param curcol column where store column information
704  * \return TDS_FAIL on error or TDS_SUCCESS
705  */
706 TDSRET
708 {
709  unsigned char *dest;
710  int len, colsize;
711  int fillchar;
712  TDSBLOB *blob = NULL;
713 
715  CHECK_COLUMN_EXTRA(curcol);
716 
717  tdsdump_log(TDS_DBG_INFO1, "tds_get_data: type %d, varint size %d\n", curcol->column_type, curcol->column_varint_size);
718  switch (curcol->column_varint_size) {
719  case 4:
720  if (!is_blob_type(curcol->column_type)) {
721  /* Any other non-BLOB type (e.g., XSYBCHAR) */
722  colsize = tds_get_int(tds);
723  if (colsize == 0) {
724  colsize = -1;
725  }
726  break;
727  } else if (curcol->on_server.column_type == SYBLONGBINARY) {
728  blob = (TDSBLOB *) curcol->column_data;
729  colsize = tds_get_int(tds);
730  if (colsize == 0) {
731  colsize = -1;
732  }
733  break;
734  }
735 
736  /* It's a BLOB... */
737  len = tds_get_byte(tds);
738  blob = (TDSBLOB *) curcol->column_data;
739  if (len == 16) { /* Jeff's hack */
740  tds_get_n(tds, blob->textptr, 16);
741  tds_get_n(tds, blob->timestamp, 8);
742  blob->valid_ptr = 1;
743  if (IS_TDS72_PLUS(tds->conn) &&
744  memcmp(blob->textptr, "dummy textptr\0\0",16) == 0)
745  blob->valid_ptr = 0;
746  colsize = tds_get_int(tds);
747  } else {
748  colsize = -1;
749  }
750  break;
751  case 8:
752  return tds72_get_varmax(tds, curcol);
753  case 2:
754  colsize = tds_get_smallint(tds);
755  break;
756  case 1:
757  colsize = tds_get_byte(tds);
758  if (colsize == 0)
759  colsize = -1;
760  break;
761  case 0:
762  /* TODO this should be column_size */
763  colsize = tds_get_size_by_type(curcol->column_type);
764  break;
765  default:
766  colsize = -1;
767  break;
768  }
769  if (IS_TDSDEAD(tds))
770  return TDS_FAIL;
771 
772  tdsdump_log(TDS_DBG_INFO1, "tds_get_data(): wire column size is %d \n", colsize);
773  /* set NULL flag in the row buffer */
774  if (colsize < 0) {
775  curcol->column_cur_size = -1;
776  return TDS_SUCCESS;
777  }
778 
779  /*
780  * We're now set to read the data from the wire. For varying types (e.g. char/varchar)
781  * make sure that curcol->column_cur_size reflects the size of the read data,
782  * after any charset conversion. tds_get_char_data() does that for you,
783  * but of course tds_get_n() doesn't.
784  *
785  * colsize == wire_size, bytes to read
786  * curcol->column_cur_size == sizeof destination buffer, room to write
787  */
788  dest = curcol->column_data;
789  if (is_blob_col(curcol)) {
791  int allocated;
792  TDSRET ret;
793 
794  blob = (TDSBLOB *) dest; /* cf. column_varint_size case 4, above */
795 
796  /* empty string */
797  if (colsize == 0) {
798  curcol->column_cur_size = 0;
799  if (blob->textvalue)
800  TDS_ZERO_FREE(blob->textvalue);
801  return TDS_SUCCESS;
802  }
803 
804  allocated = MAX(curcol->column_cur_size, 0);
805  if (colsize > allocated) {
806  TDS_ZERO_FREE(blob->textvalue);
807  allocated = colsize;
809  allocated /= 2;
810  }
811 
812  tds_datain_stream_init(&r, tds, colsize);
813  ret = tds_get_char_dynamic(tds, curcol, (void **) &blob->textvalue, allocated, &r.stream);
814  if (TDS_FAILED(ret) && TDS_UNLIKELY(r.wire_size > 0)) {
815  tds_get_n(tds, NULL, r.wire_size);
816  return ret;
817  }
818  return TDS_SUCCESS;
819  }
820 
821  /* non-numeric and non-blob */
822 
823  if (USE_ICONV && curcol->char_conv) {
824  if (TDS_FAILED(tds_get_char_data(tds, (char *) dest, colsize, curcol)))
825  return TDS_FAIL;
826  } else {
827  /*
828  * special case, some servers seem to return more data in some conditions
829  * (ASA 7 returning 4 byte nullable integer)
830  */
831  int discard_len = 0;
832  if (colsize > curcol->column_size) {
833  discard_len = colsize - curcol->column_size;
834  colsize = curcol->column_size;
835  }
836  if (tds_get_n(tds, dest, colsize) == NULL)
837  return TDS_FAIL;
838  if (discard_len > 0)
839  tds_get_n(tds, NULL, discard_len);
840  curcol->column_cur_size = colsize;
841  }
842 
843  /* pad (UNI)CHAR and BINARY types */
844  fillchar = 0;
845  switch (curcol->column_type) {
846  /* extra handling for SYBLONGBINARY */
847  case SYBLONGBINARY:
848  if (curcol->column_usertype != USER_UNICHAR_TYPE)
849  break;
850  case SYBCHAR:
851  case XSYBCHAR:
852  if (curcol->column_size != curcol->on_server.column_size)
853  break;
854  /* FIXME use client charset */
855  fillchar = ' ';
856  case SYBBINARY:
857  case XSYBBINARY:
858  if (colsize < curcol->column_size)
859  memset(dest + colsize, fillchar, curcol->column_size - colsize);
860  colsize = curcol->column_size;
861  break;
862  default:
863  break;
864  }
865 
866 #ifdef WORDS_BIGENDIAN
867  if (tds->conn->emul_little_endian) {
868  tdsdump_log(TDS_DBG_INFO1, "swapping coltype %d\n", tds_get_conversion_type(curcol->column_type, colsize));
869  tds_swap_datatype(tds_get_conversion_type(curcol->column_type, colsize), dest);
870  }
871 #endif
872  return TDS_SUCCESS;
873 }
874 
875 /**
876  * Put data information to wire
877  * \param tds state information for the socket and the TDS protocol
878  * \param col column where to store information
879  * \return TDS_SUCCESS or TDS_FAIL
880  */
881 TDSRET
883 {
884  size_t size;
885 
887  CHECK_COLUMN_EXTRA(col);
888 
889  size = tds_fix_column_size(tds, col);
890  switch (col->column_varint_size) {
891  case 0:
892  break;
893  case 1:
894  if (col->column_output && col->column_size <= 0
895  && is_char_type(col->column_type)) {
896  size = 255;
897  }
898  tds_put_byte(tds, (unsigned char) size);
899  break;
900  case 2:
902  break;
903  case 4:
905  break;
906  case 8:
907  tds_put_smallint(tds, 0xffff);
908  break;
909  }
910 
911  /* TDS5 wants a table name for LOBs */
912  if (IS_TDS50(tds->conn)
913  && (col->on_server.column_type == SYBIMAGE || col->on_server.column_type == SYBTEXT))
914  tds_put_smallint(tds, 0);
915 
916  /* TDS7.1 output collate information */
918  tds_put_n(tds, tds->conn->collation, 5);
919 
920  return TDS_SUCCESS;
921 }
922 
923 unsigned
925 {
926  unsigned len = col->column_varint_size;
927 
929  CHECK_COLUMN_EXTRA(col);
930 
931  switch (col->column_varint_size) {
932  case 8:
933  len = 2;
934  break;
935  }
936 
937  if (IS_TDS50(tds->conn)
938  && (col->on_server.column_type == SYBIMAGE || col->on_server.column_type == SYBTEXT))
939  len += 2;
940 
941  /* TDS7.1 output collate information */
943  len += 5;
944 
945  return len;
946 }
947 
948 /**
949  * Write data to wire
950  * \param tds state information for the socket and the TDS protocol
951  * \param curcol column where store column information
952  * \return TDS_FAIL on error or TDS_SUCCESS
953  */
954 TDSRET
955 tds_generic_put(TDSSOCKET * tds, TDSCOLUMN * curcol, int bcp7)
956 {
957  unsigned char *src;
958  TDSBLOB *blob = NULL;
959  size_t colsize, size;
960 
961  const char *s;
962  int converted = 0;
963 
965  CHECK_COLUMN_EXTRA(curcol);
966 
967  tdsdump_log(TDS_DBG_INFO1, "tds_generic_put: colsize = %d\n", (int) curcol->column_cur_size);
968 
969  /* output NULL data */
970  if (curcol->column_cur_size < 0) {
971  tdsdump_log(TDS_DBG_INFO1, "tds_generic_put: null param\n");
972  switch (curcol->column_varint_size) {
973  case 4:
974  if ((bcp7 || !IS_TDS7_PLUS(tds->conn)) && is_blob_type(curcol->on_server.column_type))
975  tds_put_byte(tds, 0);
976  else
977  tds_put_int(tds, -1);
978  break;
979  case 2:
980  tds_put_smallint(tds, -1);
981  break;
982  case 8:
983  tds_put_int8(tds, -1);
984  break;
985  default:
986  assert(curcol->column_varint_size);
987  /* FIXME not good for SYBLONGBINARY/SYBLONGCHAR (still not supported) */
988  tds_put_byte(tds, 0);
989  break;
990  }
991  return TDS_SUCCESS;
992  }
993  colsize = curcol->column_cur_size;
994 
995  size = tds_fix_column_size(tds, curcol);
996 
997  src = curcol->column_data;
998  if (is_blob_col(curcol) && src != NULL) {
999  blob = (TDSBLOB *) src;
1000  src = (unsigned char *) blob->textvalue;
1001  }
1002 
1003  s = (char *) src;
1004 
1005  /* convert string if needed */
1006  if (!bcp7 && curcol->char_conv && curcol->char_conv->flags != TDS_ENCODING_MEMCPY && colsize) {
1007  size_t output_size;
1008 #if 0
1009  /* TODO this case should be optimized */
1010  /* we know converted bytes */
1011  if (curcol->char_conv->client_charset.min_bytes_per_char == curcol->char_conv->client_charset.max_bytes_per_char
1012  && curcol->char_conv->server_charset.min_bytes_per_char == curcol->char_conv->server_charset.max_bytes_per_char) {
1013  converted_size = colsize * curcol->char_conv->server_charset.min_bytes_per_char / curcol->char_conv->client_charset.min_bytes_per_char;
1014 
1015  } else {
1016 #endif
1017  /* we need to convert data before */
1018  /* TODO this can be a waste of memory... */
1019  converted = 1;
1020  s = tds_convert_string(tds, curcol->char_conv, s, colsize, &output_size);
1021  colsize = (TDS_INT)output_size;
1022  if (!s) {
1023  /* on conversion error put a empty string */
1024  /* TODO on memory failure we should compute converted size and use chunks */
1025  colsize = 0;
1026  converted = -1;
1027  }
1028  }
1029 
1030  /*
1031  * TODO here we limit data sent with MIN, should mark somewhere
1032  * and inform client ??
1033  * Test proprietary behavior
1034  */
1035  if (IS_TDS7_PLUS(tds->conn)) {
1036  tdsdump_log(TDS_DBG_INFO1, "tds_generic_put: not null param varint_size = %d\n",
1037  curcol->column_varint_size);
1038 
1039  switch (curcol->column_varint_size) {
1040  case 8:
1041  /* this difference for BCP operation is due to
1042  * a bug in different server version that does
1043  * not accept a length here */
1044  tds_put_int8(tds, bcp7 ? (TDS_INT8) -2 : (TDS_INT8) colsize);
1045  if (blob == NULL) { /* anticipate ctlib blk_textxfer */
1046  return TDS_SUCCESS;
1047  }
1048  tds_put_int(tds, colsize);
1049  break;
1050  case 4: /* It's a BLOB... */
1051  colsize = MIN(colsize, size);
1052  /* mssql require only size */
1053  if (bcp7 && is_blob_type(curcol->on_server.column_type)) {
1054  static const unsigned char textptr[] = {
1055  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1056  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1057  };
1058  tds_put_byte(tds, 16);
1059  tds_put_n(tds, textptr, 16);
1060  tds_put_n(tds, textptr, 8);
1061  }
1062  tds_put_int(tds, (TDS_INT) colsize);
1063  break;
1064  case 2:
1065  colsize = MIN(colsize, size);
1066  tds_put_smallint(tds, (TDS_SMALLINT) colsize);
1067  break;
1068  case 1:
1069  colsize = MIN(colsize, size);
1070  tds_put_byte(tds, (unsigned char) colsize);
1071  break;
1072  case 0:
1073  /* TODO should be column_size */
1074  colsize = tds_get_size_by_type(curcol->on_server.column_type);
1075  break;
1076  }
1077 
1078  /* conversion error, exit with an error */
1079  if (converted < 0)
1080  return TDS_FAIL;
1081 
1082  /* put real data */
1083  if (blob) {
1084  tds_put_n(tds, s, colsize);
1085  } else if (is_blob_col(curcol)) {
1086  return TDS_SUCCESS; /* anticipate ctlib blk_textxfer */
1087  } else {
1088 #ifdef WORDS_BIGENDIAN
1089  unsigned char buf[64];
1090 
1091  if (tds->conn->emul_little_endian && !converted && colsize < 64) {
1092  tdsdump_log(TDS_DBG_INFO1, "swapping coltype %d\n",
1093  tds_get_conversion_type(curcol->column_type, colsize));
1094  memcpy(buf, s, colsize);
1095  tds_swap_datatype(tds_get_conversion_type(curcol->column_type, colsize), buf);
1096  s = (char *) buf;
1097  }
1098 #endif
1099  tds_put_n(tds, s, colsize);
1100  }
1101  /* finish chunk for varchar/varbinary(max) */
1102  if (curcol->column_varint_size == 8 && colsize)
1103  tds_put_int(tds, 0);
1104  } else {
1105  /* TODO ICONV handle charset conversions for data */
1106  /* put size of data */
1107  switch (curcol->column_varint_size) {
1108  case 4:
1109  if ( !is_blob_col(curcol) ) {
1110  colsize = MAX(MIN(colsize, 0x7fffffff), 1);
1111  tds_put_int(tds, (TDS_INT)colsize);
1112  break;
1113  }
1114  /* It's a BLOB... */
1115  tds_put_byte(tds, 16);
1116  tds_put_n(tds, blob->textptr, 16);
1117  tds_put_n(tds, blob->timestamp, 8);
1118  colsize = MIN(colsize, 0x7fffffff);
1119  tds_put_int(tds, (TDS_INT) colsize);
1120  break;
1121  case 2:
1122  colsize = MIN(colsize, 8000);
1123  tds_put_smallint(tds, (TDS_SMALLINT) colsize);
1124  break;
1125  case 1:
1126  if (!colsize) {
1127  tds_put_byte(tds, 1);
1128  if (is_char_type(curcol->column_type))
1129  tds_put_byte(tds, ' ');
1130  else
1131  tds_put_byte(tds, 0);
1132  if (converted > 0)
1133  tds_convert_string_free((char*)src, s);
1134  return TDS_SUCCESS;
1135  }
1136  colsize = MIN(colsize, 255);
1137  tds_put_byte(tds, (unsigned char) colsize);
1138  break;
1139  case 0:
1140  /* TODO should be column_size */
1141  colsize = tds_get_size_by_type(curcol->column_type);
1142  break;
1143  }
1144 
1145  /* conversion error, exit with an error */
1146  if (converted < 0)
1147  return TDS_FAIL;
1148 
1149  /* put real data */
1150  if (blob) {
1151  tds_put_n(tds, s, colsize);
1152  } else if (is_blob_col(curcol)) {
1153  /* accommodate ctlib blk_textxfer */
1154  return TDS_SUCCESS;
1155  } else {
1156 #ifdef WORDS_BIGENDIAN
1157  unsigned char buf[64];
1158 
1159  if (tds->conn->emul_little_endian && !converted && colsize < 64) {
1160  tdsdump_log(TDS_DBG_INFO1, "swapping coltype %d\n",
1161  tds_get_conversion_type(curcol->column_type, colsize));
1162  memcpy(buf, s, colsize);
1163  tds_swap_datatype(tds_get_conversion_type(curcol->column_type, colsize), buf);
1164  s = (char *) buf;
1165  }
1166 #endif
1167  tds_put_n(tds, s, colsize);
1168  }
1169  }
1170  if (converted > 0)
1171  tds_convert_string_free((char*)src, s);
1172  return TDS_SUCCESS;
1173 }
1174 
1175 TDSRET
1177 {
1178  col->column_size = tds_get_byte(tds);
1179  col->column_prec = tds_get_byte(tds); /* precision */
1180  col->column_scale = tds_get_byte(tds); /* scale */
1181 
1182  /* check prec/scale, don't let server crash us */
1183  if (col->column_prec < 1 || col->column_prec > MAXPRECISION
1184  || col->column_scale > col->column_prec)
1185  return TDS_FAIL;
1186 
1187  return TDS_SUCCESS;
1188 }
1189 
1190 TDS_INT
1192 {
1193  return sizeof(TDS_NUMERIC);
1194 }
1195 
1196 TDSRET
1198 {
1199  int colsize;
1200  TDS_NUMERIC *num;
1201 
1203  CHECK_COLUMN_EXTRA(curcol);
1204 
1205  colsize = tds_get_byte(tds);
1206 
1207  /* set NULL flag in the row buffer */
1208  if (colsize <= 0) {
1209  curcol->column_cur_size = -1;
1210  return TDS_SUCCESS;
1211  }
1212 
1213  /*
1214  * Since these can be passed around independent
1215  * of the original column they came from, we embed the TDS_NUMERIC datatype in the row buffer
1216  * instead of using the wire representation, even though it uses a few more bytes.
1217  */
1218  num = (TDS_NUMERIC *) curcol->column_data;
1219  memset(num, '\0', sizeof(TDS_NUMERIC));
1220  /* TODO perhaps it would be fine to change format ?? */
1221  num->precision = curcol->column_prec;
1222  num->scale = curcol->column_scale;
1223 
1224  /* server is going to crash freetds ?? */
1225  /* TODO close connection it server try to do so ?? */
1226  if (colsize > sizeof(num->array))
1227  return TDS_FAIL;
1228  tds_get_n(tds, num->array, colsize);
1229 
1230  if (IS_TDS7_PLUS(tds->conn))
1231  tds_swap_numeric(num);
1232 
1233  /* corrected colsize for column_cur_size */
1234  curcol->column_cur_size = sizeof(TDS_NUMERIC);
1235 
1236  return TDS_SUCCESS;
1237 }
1238 
1239 TDSRET
1241 {
1243  CHECK_COLUMN_EXTRA(col);
1244 
1245 #if 1
1247  tds_put_byte(tds, col->column_prec);
1248  tds_put_byte(tds, col->column_scale);
1249 #else
1250  TDS_NUMERIC *num = (TDS_NUMERIC *) col->column_data;
1252  tds_put_byte(tds, num->precision);
1253  tds_put_byte(tds, num->scale);
1254 #endif
1255 
1256  return TDS_SUCCESS;
1257 }
1258 
1259 unsigned
1261 {
1263  CHECK_COLUMN_EXTRA(col);
1264 
1265  return 3;
1266 }
1267 
1268 TDSRET
1270 {
1271  TDS_NUMERIC *num = (TDS_NUMERIC *) col->column_data, buf;
1272  unsigned char colsize;
1273 
1274  if (col->column_cur_size < 0) {
1275  tds_put_byte(tds, 0);
1276  return TDS_SUCCESS;
1277  }
1278  colsize = tds_numeric_bytes_per_prec[num->precision];
1279  tds_put_byte(tds, colsize);
1280 
1281  buf = *num;
1282  if (IS_TDS7_PLUS(tds->conn))
1284  tds_put_n(tds, buf.array, colsize);
1285  return TDS_SUCCESS;
1286 }
1287 
1288 TDSRET
1290 {
1291  /* TODO */
1292  return TDS_FAIL;
1293 }
1294 
1295 TDSRET
1297 {
1298  /* TODO */
1299  return TDS_FAIL;
1300 }
1301 
1302 TDSRET
1304 {
1305  col->column_scale = col->column_prec = 0;
1306  if (col->column_type != SYBMSDATE) {
1307  col->column_scale = col->column_prec = tds_get_byte(tds);
1308  if (col->column_prec > 7)
1309  return TDS_FAIL;
1310  }
1311  col->on_server.column_size = col->column_size = sizeof(TDS_DATETIMEALL);
1312  return TDS_SUCCESS;
1313 }
1314 
1315 TDS_INT
1317 {
1318  return sizeof(TDS_DATETIMEALL);
1319 }
1320 
1321 TDSRET
1323 {
1325  int size = tds_get_byte(tds);
1326 
1327  if (size == 0) {
1328  col->column_cur_size = -1;
1329  return TDS_SUCCESS;
1330  }
1331 
1332  memset(dt, 0, sizeof(*dt));
1333 
1334  if (col->column_type == SYBMSDATETIMEOFFSET)
1335  size -= 2;
1336  if (col->column_type != SYBMSTIME)
1337  size -= 3;
1338  if (size < 0)
1339  return TDS_FAIL;
1340 
1341  dt->time_prec = col->column_prec;
1342 
1343  /* get time part */
1344  if (col->column_type != SYBMSDATE) {
1345  TDS_UINT8 u8;
1346  int i;
1347 
1348  if (size < 3 || size > 5)
1349  return TDS_FAIL;
1350  u8 = 0;
1351  tds_get_n(tds, &u8, size);
1352 #ifdef WORDS_BIGENDIAN
1353  tds_swap_bytes(&u8, 8);
1354 #endif
1355  for (i = col->column_prec; i < 7; ++i)
1356  u8 *= 10;
1357  dt->time = u8;
1358  dt->has_time = 1;
1359  } else if (size != 0)
1360  return TDS_FAIL;
1361 
1362  /* get date part */
1363  if (col->column_type != SYBMSTIME) {
1364  TDS_UINT ui;
1365 
1366  ui = 0;
1367  tds_get_n(tds, &ui, 3);
1368 #ifdef WORDS_BIGENDIAN
1369  tds_swap_bytes(&ui, 4);
1370 #endif
1371  dt->has_date = 1;
1372  dt->date = ui - 693595;
1373  }
1374 
1375  /* get time offset */
1376  if (col->column_type == SYBMSDATETIMEOFFSET) {
1377  dt->offset = tds_get_smallint(tds);
1378  if (dt->offset > 840 || dt->offset < -840)
1379  return TDS_FAIL;
1380  dt->has_offset = 1;
1381  }
1382  col->column_cur_size = sizeof(TDS_DATETIMEALL);
1383  return TDS_SUCCESS;
1384 }
1385 
1386 TDSRET
1388 {
1389  /* TODO precision */
1390  if (col->on_server.column_type != SYBMSDATE)
1391  tds_put_byte(tds, 7);
1392  return TDS_SUCCESS;
1393 }
1394 
1395 TDSRET
1397 {
1398  const TDS_DATETIMEALL *dta = (const TDS_DATETIMEALL *) col->column_data;
1399  unsigned char buf[12], *p;
1400 
1401  if (col->column_cur_size < 0) {
1402  tds_put_byte(tds, 0);
1403  return TDS_SUCCESS;
1404  }
1405 
1406  /* TODO precision */
1407  p = buf + 1;
1408  if (col->on_server.column_type != SYBMSDATE) {
1409  TDS_PUT_UA4LE(p, (TDS_UINT) dta->time);
1410  p[4] = (unsigned char) (dta->time >> 32);
1411  p += 5;
1412  }
1413  if (col->on_server.column_type != SYBMSTIME) {
1414  TDS_UINT ui = dta->date + 693595;
1415  TDS_PUT_UA4LE(p, ui);
1416  p += 3;
1417  }
1419  TDS_PUT_UA2LE(p, dta->offset);
1420  p += 2;
1421  }
1422  buf[0] = (unsigned char) (p - buf - 1);
1423  tds_put_n(tds, buf, p - buf);
1424 
1425  return TDS_SUCCESS;
1426 }
1427 
1428 TDSRET
1430 {
1431  /* TODO save fields */
1432  /* FIXME support RPC */
1433 
1434  /* MAX_BYTE_SIZE */
1436 
1437  /* DB_NAME */
1439 
1440  /* SCHEMA_NAME */
1442 
1443  /* TYPE_NAME */
1445 
1446  /* UDT_METADATA */
1448 
1449  col->column_size = 0x7ffffffflu;
1450 
1451  return TDS_SUCCESS;
1452 }
1453 
1454 TDS_INT
1456 {
1457  /* TODO save other fields */
1458  return sizeof(TDSBLOB);
1459 }
1460 
1461 TDSRET
1463 {
1464  /* FIXME support properly*/
1465  tds_put_byte(tds, 0); /* db_name */
1466  tds_put_byte(tds, 0); /* schema_name */
1467  tds_put_byte(tds, 0); /* type_name */
1468 
1469  return TDS_SUCCESS;
1470 }
1471 
1472 TDSRET
1474 {
1475  col->column_scale = col->column_prec = 6;
1476  tds_get_byte(tds); /* 8, size */
1477  tds_get_byte(tds); /* 6, precision ?? */
1478  col->on_server.column_size = col->column_size = sizeof(TDS_UINT8);
1479  return TDS_SUCCESS;
1480 }
1481 
1482 TDS_INT
1484 {
1485  return sizeof(TDS_UINT8);
1486 }
1487 
1488 TDSRET
1490 {
1491  TDS_UINT8 *dt = (TDS_UINT8 *) col->column_data;
1492  int size = tds_get_byte(tds);
1493 
1494  if (size == 0) {
1495  col->column_cur_size = -1;
1496  return TDS_SUCCESS;
1497  }
1498 
1499  col->column_cur_size = sizeof(TDS_UINT8);
1500  *dt = tds_get_int8(tds);
1501 
1502  return TDS_SUCCESS;
1503 }
1504 
1505 TDSRET
1507 {
1508  tds_put_byte(tds, 8);
1509  tds_put_byte(tds, 6);
1510  return TDS_SUCCESS;
1511 }
1512 
1513 unsigned
1515 {
1516  return 2;
1517 }
1518 
1519 TDSRET
1521 {
1522  const TDS_UINT8 *dt = (const TDS_UINT8 *) col->column_data;
1523 
1524  if (col->column_cur_size < 0) {
1525  tds_put_byte(tds, 0);
1526  return TDS_SUCCESS;
1527  }
1528 
1529  tds_put_byte(tds, 8);
1530  tds_put_int8(tds, *dt);
1531 
1532  return TDS_SUCCESS;
1533 }
1534 
1535 TDSRET
1537 {
1538  return TDS_FAIL;
1539 }
1540 
1541 TDS_INT
1543 {
1544  return 0;
1545 }
1546 
1547 TDSRET
1549 {
1550  return TDS_FAIL;
1551 }
1552 
1553 TDSRET
1555 {
1556  return TDS_FAIL;
1557 }
1558 
1559 unsigned
1561 {
1562  return 0;
1563 }
1564 
1565 TDSRET
1567 {
1568  return TDS_FAIL;
1569 }
1570 
1571 #if ENABLE_EXTRA_CHECKS
1572 int
1573 tds_generic_check(const TDSCOLUMN *col)
1574 {
1575  return 0;
1576 }
1577 
1578 int
1579 tds_sybbigtime_check(const TDSCOLUMN *col)
1580 {
1581  assert(col->column_type == col->on_server.column_type);
1582  assert(col->on_server.column_size == col->column_size);
1588  assert(col->column_varint_size == 1);
1589  assert(col->column_prec == 6);
1590  assert(col->column_scale == col->column_prec);
1591 
1592  return 1;
1593 }
1594 
1595 int
1596 tds_clrudt_check(const TDSCOLUMN *col)
1597 {
1598  return 0;
1599 }
1600 
1601 int
1602 tds_msdatetime_check(const TDSCOLUMN *col)
1603 {
1604  assert(col->column_type == col->on_server.column_type);
1605  assert(col->on_server.column_size == col->column_size);
1607  if (col->column_type == SYBMSDATE) {
1609  } else {
1611  }
1615  assert(col->column_varint_size == 1);
1616  assert(col->column_prec >= 0 && col->column_prec <= 7);
1617  assert(col->column_scale == col->column_prec);
1618 
1619  return 1;
1620 }
1621 
1622 int
1623 tds_variant_check(const TDSCOLUMN *col)
1624 {
1625  return 0;
1626 }
1627 
1628 int
1629 tds_numeric_check(const TDSCOLUMN *col)
1630 {
1631  assert(col->column_type == col->on_server.column_type);
1632  assert(col->on_server.column_size == col->column_size);
1637  assert(col->column_varint_size == 1);
1638  assert(col->column_prec >= 1 && col->column_prec <= MAXPRECISION);
1639  assert(col->column_scale <= col->column_prec);
1640 
1641  return 1;
1642 }
1643 
1644 int
1645 tds_invalid_check(const TDSCOLUMN *col)
1646 {
1647  return 1;
1648 }
1649 #endif
1650 
1651 
1652 #define TDS_DECLARE_FUNCS(name) \
1653  extern const TDSCOLUMNFUNCS tds_ ## name ## _funcs
1654 
1655 #include <freetds/pushvis.h>
1656 TDS_DECLARE_FUNCS(generic);
1657 TDS_DECLARE_FUNCS(numeric);
1658 TDS_DECLARE_FUNCS(variant);
1659 TDS_DECLARE_FUNCS(msdatetime);
1660 TDS_DECLARE_FUNCS(clrudt);
1661 TDS_DECLARE_FUNCS(sybbigtime);
1662 TDS_DECLARE_FUNCS(invalid);
1663 #include <freetds/popvis.h>
1664 
1665 static const TDSCOLUMNFUNCS *
1667 {
1668  switch (type) {
1669  case SYBNUMERIC:
1670  case SYBDECIMAL:
1671  return &tds_numeric_funcs;
1672  case SYBMSUDT:
1673  return &tds_clrudt_funcs;
1674  case SYBVARIANT:
1675  if (IS_TDS7_PLUS(conn))
1676  return &tds_variant_funcs;
1677  break;
1678  case SYBMSDATE:
1679  case SYBMSTIME:
1680  case SYBMSDATETIME2:
1681  case SYBMSDATETIMEOFFSET:
1682  return &tds_msdatetime_funcs;
1683  case SYB5BIGTIME:
1684  case SYB5BIGDATETIME:
1685  return &tds_sybbigtime_funcs;
1686  }
1687  return &tds_generic_funcs;
1688 }
1689 #include "tds_types.h"
1690 
1691 #ifdef WORDS_BIGENDIAN
1692 static void
1693 tds_swap_datatype(int coltype, void *b)
1694 {
1695  unsigned char *buf = (unsigned char *) b;
1696 
1697  switch (coltype) {
1698  case SYBDATETIME4:
1699  tds_swap_bytes(&buf[2], 2);
1700  case SYBINT2:
1701  tds_swap_bytes(buf, 2);
1702  break;
1703  case SYBMONEY:
1704  case SYBDATETIME:
1705  tds_swap_bytes(&buf[4], 4);
1706  case SYBINT4:
1707  case SYBMONEY4:
1708  case SYBREAL:
1709  case SYBDATE:
1710  case SYBTIME:
1711  tds_swap_bytes(buf, 4);
1712  break;
1713  case SYBINT8:
1714  case SYBFLT8:
1715  case SYB5BIGTIME:
1716  case SYB5BIGDATETIME:
1717  tds_swap_bytes(buf, 8);
1718  break;
1719  case SYBUNIQUE:
1720  tds_swap_bytes(buf, 4);
1721  tds_swap_bytes(&buf[4], 2);
1722  tds_swap_bytes(&buf[6], 2);
1723  break;
1724  }
1725 }
1726 #endif
1727 
1728 /**
1729  * Converts numeric from Microsoft representation to internal one (Sybase).
1730  * \param num numeric data to convert
1731  */
1732 static void
1734 {
1735  /* swap the sign */
1736  num->array[0] = (num->array[0] == 0) ? 1 : 0;
1737  /* swap the data */
1739 }
1740 
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
#define TDS_PUT_UA2LE(ptr, val)
Definition: bytes.h:61
#define TDS_PUT_UA4LE(ptr, val)
Definition: bytes.h:78
#define CHECK_COLUMN_EXTRA(column)
Definition: checks.h:34
#define CHECK_TDS_EXTRA(tds)
Definition: checks.h:31
@ to_client
Definition: iconv.h:70
#define TDS_ENCODING_MEMCPY
Definition: iconv.h:95
TDS_SERVER_TYPE
Definition: proto.h:161
@ SYBVARIANT
Definition: proto.h:200
@ SYB5INT8
Definition: proto.h:220
@ SYBLONGBINARY
Definition: proto.h:211
@ SYBUNIQUE
Definition: proto.h:199
@ XSYBNVARCHAR
Definition: proto.h:195
@ XSYBCHAR
Definition: proto.h:193
@ XSYBVARCHAR
Definition: proto.h:194
@ XSYBVARBINARY
Definition: proto.h:197
@ XSYBNCHAR
Definition: proto.h:196
@ SYBMSUDT
Definition: proto.h:201
@ SYB5BIGTIME
Definition: proto.h:231
@ XSYBBINARY
Definition: proto.h:198
@ SYBMSXML
Definition: proto.h:202
@ SYB5BIGDATETIME
Definition: proto.h:230
struct tdsunique TDS_UNIQUE
struct tdsnumeric TDS_NUMERIC
@ USER_UNICHAR_TYPE
Definition: proto.h:237
@ USER_UNIVARCHAR_TYPE
Definition: proto.h:238
#define TDS_FAIL
Definition: tds.h:204
#define is_numeric_type(x)
Definition: tds.h:454
#define TDS_FAILED(rc)
Definition: tds.h:206
#define TDS_OFFSET(str, field)
Definition: tds.h:364
#define IS_TDS71_PLUS(x)
Definition: tds.h:1709
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
#define is_variable_type(x)
Definition: tds.h:440
#define is_fixed_type(x)
Definition: tds.h:438
@ client2server_chardata
Definition: tds.h:1110
@ client2ucs2
Definition: tds.h:1109
#define tdsdump_log
Definition: tds.h:1561
#define TDS_DBG_INFO1
Definition: tds.h:900
#define IS_TDS50(x)
Definition: tds.h:1701
struct tds_blob TDSBLOB
Information about blobs (e.g.
#define tds_get_int(tds)
Definition: tds.h:1517
#define is_blob_type(x)
Definition: tds.h:443
#define tds_get_smallint(tds)
Definition: tds.h:1515
static bool is_tds_type_valid(int type)
Definition: tds.h:463
tds_sysdep_int64_type TDS_INT8
Definition: tds.h:153
unsigned char TDS_UCHAR
Definition: tds.h:145
#define is_unicode_type(x)
Definition: tds.h:457
#define is_blob_col(x)
Definition: tds.h:445
#define IS_TDS72_PLUS(x)
Definition: tds.h:1710
unsigned char TDS_TINYINT
Definition: tds.h:146
tds_sysdep_int16_type TDS_SMALLINT
Definition: tds.h:147
#define tds_convert_string_free(original, converted)
Definition: tds.h:1452
#define IS_TDS7_PLUS(x)
Definition: tds.h:1708
#define IS_TDSDEAD(x)
Definition: tds.h:1717
#define tds_new0(type, n)
Definition: tds.h:1393
#define is_char_type(x)
Definition: tds.h:460
char TDS_CHAR
Definition: tds.h:144
#define is_nullable_type(x)
Definition: tds.h:439
tds_sysdep_uint64_type TDS_UINT8
Definition: tds.h:154
int TDSRET
Definition: tds.h:201
#define TDS_UNLIKELY(x)
Definition: tds.h:372
#define TDS_SUCCESS
Definition: tds.h:203
#define is_collate_type(x)
Definition: tds.h:458
#define TDS_ZERO_FREE(x)
Definition: tds.h:359
tds_sysdep_uint32_type TDS_UINT
Definition: tds.h:150
#define MAXPRECISION
Definition: tds.h:470
#define tds_get_int8(tds)
Definition: tds.h:1519
static int type
Definition: getdata.c:31
#define SYBMSDATE
Definition: sybdb.h:222
#define SYBINT4
Definition: sybdb.h:170
#define SYBNUMERIC
Definition: sybdb.h:202
#define SYBVARCHAR
Definition: sybdb.h:162
#define SYBTEXT
Definition: sybdb.h:182
#define SYBNVARCHAR
Definition: sybdb.h:212
#define SYBDATE
Definition: sybdb.h:214
#define SYBINT8
Definition: sybdb.h:172
#define SYBMONEYN
Definition: sybdb.h:208
#define SYBMSDATETIME2
Definition: sybdb.h:226
#define SYBNTEXT
Definition: sybdb.h:184
#define SYBIMAGE
Definition: sybdb.h:186
#define SYBINTN
Definition: sybdb.h:164
#define SYBMSDATETIMEOFFSET
Definition: sybdb.h:228
#define SYBINT1
Definition: sybdb.h:166
#define SYBDATETIME4
Definition: sybdb.h:192
#define SYBDECIMAL
Definition: sybdb.h:204
#define SYBCHAR
Definition: sybdb.h:160
#define SYBREAL
Definition: sybdb.h:194
#define SYBDATETIMN
Definition: sybdb.h:210
#define SYBBITN
Definition: sybdb.h:180
#define SYBBINARY
Definition: sybdb.h:196
#define SYBTIME
Definition: sybdb.h:216
#define SYBMSTIME
Definition: sybdb.h:224
#define SYBDATETIME
Definition: sybdb.h:176
#define SYBVARBINARY
Definition: sybdb.h:200
#define SYBMONEY
Definition: sybdb.h:190
#define SYBMONEY4
Definition: sybdb.h:188
#define SYBFLT8
Definition: sybdb.h:174
#define SYBFLTN
Definition: sybdb.h:206
#define SYBINT2
Definition: sybdb.h:168
#define SYBBIT
Definition: sybdb.h:178
unsigned tds_sybbigtime_put_info_len(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1514
static const TDSCOLUMNFUNCS * tds_get_column_funcs(TDSCONNECTION *conn, int type)
Definition: data.c:1666
static int tds_varmax_stream_read(TDSINSTREAM *stream, void *ptr, size_t len)
Definition: data.c:494
static TDSRET tds_get_char_dynamic(TDSSOCKET *tds, TDSCOLUMN *curcol, void **pp, size_t allocated, TDSINSTREAM *r_stream)
Definition: data.c:466
TDSRET tds_generic_get_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:382
TDSRET tds_variant_get(TDSSOCKET *tds, TDSCOLUMN *curcol)
Definition: data.c:562
const TDSCOLUMNFUNCS tds_clrudt_funcs
Definition: data.h:109
TDSRET tds_invalid_put(TDSSOCKET *tds, TDSCOLUMN *col, int bcp7)
Definition: data.c:1566
const TDSCOLUMNFUNCS tds_numeric_funcs
Definition: data.h:106
void tds_set_column_type(TDSCONNECTION *conn, TDSCOLUMN *curcol, TDS_SERVER_TYPE type)
Set type of column initializing all dependency.
Definition: data.c:225
TDSRET tds_sybbigtime_put_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1506
TDSRET tds_invalid_get(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1548
#define MIN(a, b)
Definition: data.c:215
#define TDS_DECLARE_FUNCS(name)
Definition: data.c:1652
TDSRET tds_numeric_put(TDSSOCKET *tds, TDSCOLUMN *col, int bcp7)
Definition: data.c:1269
TDS_INT tds_clrudt_row_len(TDSCOLUMN *col)
Definition: data.c:1455
TDSRET tds_invalid_put_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1554
const TDSCOLUMNFUNCS tds_sybbigtime_funcs
Definition: data.h:110
TDS_INT tds_sybbigtime_row_len(TDSCOLUMN *col)
Definition: data.c:1483
const TDSCOLUMNFUNCS tds_generic_funcs
Definition: data.h:105
static TDSRET tds72_get_varmax(TDSSOCKET *tds, TDSCOLUMN *curcol)
Definition: data.c:519
TDSRET tds_msdatetime_get(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1322
unsigned tds_numeric_put_info_len(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1260
TDSRET tds_sybbigtime_put(TDSSOCKET *tds, TDSCOLUMN *col, int bcp7)
Definition: data.c:1520
TDSRET tds_numeric_put_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1240
struct tds_varmax_stream TDSVARMAXSTREAM
TDSRET tds_msdatetime_get_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1303
const TDSCOLUMNFUNCS tds_variant_funcs
Definition: data.h:107
TDS_INT tds_invalid_row_len(TDSCOLUMN *col)
Definition: data.c:1542
TDSRET tds_numeric_get_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1176
TDSRET tds_msdatetime_put_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1387
TDSRET tds_generic_put(TDSSOCKET *tds, TDSCOLUMN *curcol, int bcp7)
Write data to wire.
Definition: data.c:955
void tds_set_param_type(TDSCONNECTION *conn, TDSCOLUMN *curcol, TDS_SERVER_TYPE type)
Set type of column initializing all dependency.
Definition: data.c:247
TDS_SERVER_TYPE tds_get_cardinal_type(TDS_SERVER_TYPE datatype, int usertype)
Definition: data.c:351
unsigned tds_invalid_put_info_len(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1560
#define USE_ICONV
Definition: data.c:206
static void tds_swap_numeric(TDS_NUMERIC *num)
Converts numeric from Microsoft representation to internal one (Sybase).
Definition: data.c:1733
TDS_INT tds_generic_row_len(TDSCOLUMN *col)
Definition: data.c:456
TDSRET tds_numeric_get(TDSSOCKET *tds, TDSCOLUMN *curcol)
Definition: data.c:1197
TDSRET tds_generic_put_info(TDSSOCKET *tds, TDSCOLUMN *col)
Put data information to wire.
Definition: data.c:882
TDS_INT tds_numeric_row_len(TDSCOLUMN *col)
Definition: data.c:1191
TDS_COMPILE_CHECK(variant_size, sizeof(TDSBLOB) >=sizeof(TDSVARIANT))
TDSRET tds_variant_put_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1289
TDSRET tds_sybbigtime_get_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1473
TDSRET tds_generic_get(TDSSOCKET *tds, TDSCOLUMN *curcol)
Read a data from wire.
Definition: data.c:707
TDSRET tds_clrudt_put_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1462
TDSRET tds_clrudt_get_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1429
TDS_INT tds_msdatetime_row_len(TDSCOLUMN *col)
Definition: data.c:1316
TDSRET tds_invalid_get_info(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1536
TDSRET tds_msdatetime_put(TDSSOCKET *tds, TDSCOLUMN *col, int bcp7)
Definition: data.c:1396
TDSRET tds_sybbigtime_get(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:1489
const TDSCOLUMNFUNCS tds_msdatetime_funcs
Definition: data.h:108
unsigned tds_generic_put_info_len(TDSSOCKET *tds, TDSCOLUMN *col)
Definition: data.c:924
#define MAX(a, b)
Definition: data.c:217
TDSRET tds_variant_put(TDSSOCKET *tds, TDSCOLUMN *col, int bcp7)
Definition: data.c:1296
static TDSSOCKET * tds
Definition: collations.c:37
#define tds_get_char_data
#define tds_get_n
#define tds_put_n
#define tds_clrudt_check
#define tds_put_int8
#define tds_convert_stream
#define tds_put_int
#define tds_invalid_check
#define tds_fix_column_size
#define tds_get_string
#define tds_get_size_by_type
#define tds_generic_check
#define tds_put_smallint
#define tds_swap_bytes
#define tds_iconv_from_collate
#define tds_dynamic_stream_init
#define tds_convert_string
#define tds_get_byte
#define tds_msdatetime_check
#define tds_datain_stream_init
#define tds_get_usmallint
#define tds_numeric_bytes_per_prec
#define tds_dstr_get
#define tds_get_uint
#define tds_sybbigtime_check
#define tds_put_byte
#define tds_get_conversion_type
#define tds_copy_stream
#define tds_numeric_check
#define tds_get_varint_size
#define tds_variant_check
char data[12]
Definition: iconv.c:80
#define NULL
Definition: ncbistd.hpp:225
char * buf
int i
if(yy_accept[yy_current_state])
int len
const struct ncbi::grid::netcache::search::fields::SIZE size
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
#define assert(x)
Definition: srv_diag.hpp:58
this structure is not directed connected to a TDS protocol but keeps any DATE/TIME information.
Definition: tds.h:167
TDS_USMALLINT has_date
Definition: tds.h:174
TDS_INT date
date, 0 = 1900-01-01
Definition: tds.h:169
TDS_SMALLINT offset
time offset
Definition: tds.h:170
TDS_USMALLINT time_prec
Definition: tds.h:171
TDS_USMALLINT has_time
Definition: tds.h:173
TDS_USMALLINT has_offset
Definition: tds.h:175
TDS_UINT8 time
time, 7 digit precision
Definition: tds.h:168
Information about blobs (e.g.
Definition: tds.h:658
unsigned char valid_ptr
Definition: tds.h:662
TDS_CHAR * textvalue
Definition: tds.h:659
TDS_CHAR textptr[16]
Definition: tds.h:660
TDS_CHAR timestamp[8]
Definition: tds.h:661
Metadata about columns in regular and compute rows.
Definition: tds.h:761
TDS_TINYINT column_varint_size
size of length when reading from wire (0, 1, 2 or 4)
Definition: tds.h:773
TDS_INT column_size
maximun size of data.
Definition: tds.h:766
TDS_UCHAR column_collation[5]
Definition: tds.h:803
const TDSCOLUMNFUNCS * funcs
Definition: tds.h:762
TDS_TINYINT column_prec
precision for decimal/numeric
Definition: tds.h:775
TDS_SERVER_TYPE column_type
This type can be different from wire type because conversion (e.g.
Definition: tds.h:768
TDSICONV * char_conv
refers to previously allocated iconv information
Definition: tds.h:784
DSTR table_name
Definition: tds.h:786
TDS_TINYINT column_scale
scale for decimal/numeric
Definition: tds.h:776
unsigned char * column_data
Definition: tds.h:793
unsigned int column_output
Definition: tds.h:800
struct tds_column::@124 on_server
TDS_INT column_cur_size
size written in variable (ie: char, text, binary).
Definition: tds.h:811
TDS_INT column_usertype
Definition: tds.h:763
TDS_UCHAR collation[5]
Definition: tds.h:1163
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
output stream to write data to a dynamic buffer
Definition: stream.h:99
TDSOUTSTREAM stream
Definition: stream.h:100
size_t size
size of data inside buffer
Definition: stream.h:106
define a stream of data used for input
Definition: stream.h:30
Information for a server connection.
Definition: tds.h:1211
unsigned char * in_buf
Input buffer.
Definition: tds.h:1223
unsigned in_pos
current position in in_buf
Definition: tds.h:1237
TDSCONNECTION conn[1]
Definition: tds.h:1215
Store variant informations.
Definition: tds.h:669
TDS_SERVER_TYPE type
Definition: tds.h:674
TDS_UCHAR collation[5]
Definition: tds.h:675
TDS_CHAR * data
Definition: tds.h:671
TDS_INT data_len
Definition: tds.h:673
TDS_INT size
Definition: tds.h:672
TDSINSTREAM stream
Definition: data.c:488
TDS_INT chunk_left
Definition: data.c:490
TDSSOCKET * tds
Definition: data.c:489
unsigned int flags
Definition: iconv.h:96
unsigned char array[33]
Definition: proto.h:29
unsigned char scale
Definition: proto.h:28
unsigned char precision
Definition: proto.h:27
Definition: type.c:6
Modified on Fri Jun 14 16:49:03 2024 by modify_doxy.py rev. 669887