LCOV - code coverage report
Current view: top level - src/tds - data.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 638 740 86.2 %
Date: 2025-01-18 11:50:39 Functions: 36 51 70.6 %

          Line data    Source code
       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/utils.h>
     200             : #include <freetds/tds.h>
     201             : #include <freetds/bytes.h>
     202             : #include <freetds/iconv.h>
     203             : #include <freetds/checks.h>
     204             : #include <freetds/stream.h>
     205             : #include <freetds/data.h>
     206             : 
     207             : #define USE_ICONV (tds->conn->use_iconv)
     208             : 
     209             : static const TDSCOLUMNFUNCS *tds_get_column_funcs(TDSCONNECTION *conn, int type);
     210             : static void tds_swap_numeric(TDS_NUMERIC *num);
     211             : 
     212             : #undef MIN
     213             : #define MIN(a,b) (((a) < (b)) ? (a) : (b))
     214             : #undef MAX
     215             : #define MAX(a,b) (((a) > (b)) ? (a) : (b))
     216             : 
     217             : /**
     218             :  * Set type of column initializing all dependency.
     219             :  * column_usertype should already be set.
     220             :  * @param curcol column to set
     221             :  * @param type   type to set
     222             :  */
     223             : void
     224       73810 : tds_set_column_type(TDSCONNECTION * conn, TDSCOLUMN * curcol, TDS_SERVER_TYPE type)
     225             : {
     226             :         /* set type */
     227       73810 :         curcol->on_server.column_type = type;
     228       73810 :         curcol->funcs = tds_get_column_funcs(conn, type);
     229       73810 :         curcol->column_type = tds_get_cardinal_type(type, curcol->column_usertype);
     230             : 
     231             :         /* set size */
     232       73810 :         curcol->column_cur_size = -1;
     233       73810 :         curcol->column_varint_size = tds_get_varint_size(conn, type);
     234       73810 :         if (curcol->column_varint_size == 0)
     235       20434 :                 curcol->column_cur_size = curcol->on_server.column_size = curcol->column_size = tds_get_size_by_type(type);
     236             : 
     237       73810 : }
     238             : 
     239             : /**
     240             :  * Set type of column initializing all dependency
     241             :  * \param tds    state information for the socket and the TDS protocol
     242             :  * \param curcol column to set
     243             :  * \param type   type to set
     244             :  */
     245             : void
     246       16470 : tds_set_param_type(TDSCONNECTION * conn, TDSCOLUMN * curcol, TDS_SERVER_TYPE type)
     247             : {
     248       16470 :         if (IS_TDS7_PLUS(conn)) {
     249       13958 :                 switch (type) {
     250        1740 :                 case SYBVARCHAR:
     251        1740 :                         type = XSYBVARCHAR;
     252        1740 :                         break;
     253         858 :                 case SYBCHAR:
     254         858 :                         type = XSYBCHAR;
     255         858 :                         break;
     256         156 :                 case SYBVARBINARY:
     257         156 :                         type = XSYBVARBINARY;
     258         156 :                         break;
     259         826 :                 case SYBBINARY:
     260         826 :                         type = XSYBBINARY;
     261         826 :                         break;
     262         594 :                 case SYBBIT:
     263         594 :                         type = SYBBITN;
     264         594 :                         break;
     265             :                         /* avoid warning on other types */
     266             :                 default:
     267             :                         break;
     268             :                 }
     269        2512 :         } else if (IS_TDS50(conn)) {
     270        2512 :                 switch (type) {
     271          14 :                 case SYBINT8:
     272          14 :                         type = SYB5INT8;
     273          14 :                         break;
     274             :                         /* avoid warning on other types */
     275             :                 default:
     276             :                         break;
     277             :                 }
     278           0 :         }
     279       16470 :         tds_set_column_type(conn, curcol, type);
     280             : 
     281       16470 :         if (is_collate_type(type) || is_char_type(type)) {
     282        5712 :                 curcol->char_conv = conn->char_convs[is_unicode_type(type) ? client2ucs2 : client2server_chardata];
     283        5712 :                 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       16470 :         switch (type) {
     289          34 :         case SYBUNIQUE:
     290          34 :                 curcol->on_server.column_size = curcol->column_size = sizeof(TDS_UNIQUE);
     291          34 :                 break;
     292         596 :         case SYBBITN:
     293         596 :                 curcol->on_server.column_size = curcol->column_size = sizeof(TDS_TINYINT);
     294         596 :                 break;
     295             :         /* mssql 2005 don't like SYBINT4 as parameter closing connection  */
     296        3502 :         case SYBINT1:
     297             :         case SYBINT2:
     298             :         case SYBINT4:
     299             :         case SYBINT8:
     300        3502 :                 curcol->on_server.column_type = SYBINTN;
     301        3502 :                 curcol->column_varint_size = 1;
     302        3502 :                 curcol->column_cur_size = -1;
     303        3502 :                 break;
     304          48 :         case SYBMONEY4:
     305             :         case SYBMONEY:
     306          48 :                 curcol->on_server.column_type = SYBMONEYN;
     307          48 :                 curcol->column_varint_size = 1;
     308          48 :                 curcol->column_cur_size = -1;
     309          48 :                 break;
     310         726 :         case SYBDATETIME:
     311             :         case SYBDATETIME4:
     312         726 :                 curcol->on_server.column_type = SYBDATETIMN;
     313         726 :                 curcol->column_varint_size = 1;
     314         726 :                 curcol->column_cur_size = -1;
     315         726 :                 break;
     316        1846 :         case SYBFLT8:
     317             :         case SYBREAL:
     318        1846 :                 curcol->on_server.column_type = SYBFLTN;
     319        1846 :                 curcol->column_varint_size = 1;
     320        1846 :                 curcol->column_cur_size = -1;
     321        1846 :                 break;
     322         348 :         case SYBNTEXT:
     323         348 :                 if (IS_TDS72_PLUS(conn)) {
     324         116 :                         curcol->column_varint_size = 8;
     325         116 :                         curcol->on_server.column_type = XSYBNVARCHAR;
     326             :                 }
     327             :                 break;
     328         520 :         case SYBTEXT:
     329         520 :                 if (IS_TDS72_PLUS(conn)) {
     330         152 :                         curcol->column_varint_size = 8;
     331         152 :                         curcol->on_server.column_type = XSYBVARCHAR;
     332             :                 }
     333             :                 break;
     334         142 :         case SYBIMAGE:
     335         142 :                 if (IS_TDS72_PLUS(conn)) {
     336          44 :                         curcol->column_varint_size = 8;
     337          44 :                         curcol->on_server.column_type = XSYBVARBINARY;
     338             :                 }
     339             :                 break;
     340           0 :         case SYB5BIGTIME:
     341             :         case SYB5BIGDATETIME:
     342           0 :                 curcol->column_prec = 6;
     343           0 :                 curcol->column_scale = 6;
     344           0 :                 break;
     345             :         default:
     346             :                 break;
     347             :         }
     348       16470 : }
     349             : 
     350             : TDS_SERVER_TYPE
     351    10150073 : tds_get_cardinal_type(TDS_SERVER_TYPE datatype, int usertype)
     352             : {
     353    10150073 :         switch (datatype) {
     354             :         case XSYBVARBINARY:
     355             :                 return SYBVARBINARY;
     356        5492 :         case XSYBBINARY:
     357        5492 :                 return SYBBINARY;
     358       22698 :         case SYBNTEXT:
     359       22698 :                 return SYBTEXT;
     360     2072380 :         case XSYBNVARCHAR:
     361             :         case XSYBVARCHAR:
     362     2072380 :                 return SYBVARCHAR;
     363     1075553 :         case XSYBNCHAR:
     364             :         case XSYBCHAR:
     365     1075553 :                 return SYBCHAR;
     366         942 :         case SYB5INT8:
     367         942 :                 return SYBINT8;
     368       19112 :         case SYBLONGBINARY:
     369       19112 :                 switch (usertype) {
     370             :                 case USER_UNICHAR_TYPE:
     371             :                 case USER_UNIVARCHAR_TYPE:
     372             :                         return SYBTEXT;
     373             :                 }
     374             :                 break;
     375         208 :         case SYBMSXML:
     376         208 :                 return SYBLONGCHAR;
     377             :         default:
     378             :                 break;
     379             :         }
     380     6944392 :         return datatype;
     381             : }
     382             : 
     383             : TDSRET
     384       52892 : tds_generic_get_info(TDSSOCKET *tds, TDSCOLUMN *col)
     385             : {
     386       52892 :         switch (col->column_varint_size) {
     387           8 :         case 8:
     388           8 :                 col->column_size = 0x7ffffffflu;
     389           8 :                 break;
     390        2820 :         case 5:
     391             :         case 4:
     392        2820 :                 col->column_size = tds_get_int(tds);
     393        2820 :                 if (col->column_size < 0)
     394             :                         return TDS_FAIL;
     395             :                 break;
     396       15470 :         case 2:
     397             :                 /* assure > 0 */
     398       15470 :                 col->column_size = tds_get_smallint(tds);
     399             :                 /* under TDS7.2 this means ?var???(MAX) */
     400       15470 :                 if (col->column_size < 0 && IS_TDS72_PLUS(tds->conn)) {
     401         102 :                         if (is_char_type(col->column_type))
     402          82 :                                 col->column_size = 0x3ffffffflu;
     403             :                         else
     404          20 :                                 col->column_size = 0x7ffffffflu;
     405             : 
     406         102 :                         col->column_varint_size = 8;
     407             :                 }
     408       15470 :                 if (col->column_size < 0)
     409             :                         return TDS_FAIL;
     410             :                 break;
     411       21318 :         case 1:
     412       21318 :                 col->column_size = tds_get_byte(tds);
     413       21318 :                 break;
     414       13276 :         case 0:
     415       13276 :                 col->column_size = tds_get_size_by_type(col->column_type);
     416       13276 :                 break;
     417             :         }
     418             : 
     419       52892 :         if (IS_TDS71_PLUS(tds->conn) && is_collate_type(col->on_server.column_type)) {
     420             :                 /* based on true type as sent by server */
     421             :                 /*
     422             :                  * first 2 bytes are windows code (such as 0x409 for english)
     423             :                  * other 2 bytes ???
     424             :                  * last bytes is id in syscharsets
     425             :                  */
     426       16248 :                 tds_get_n(tds, col->column_collation, 5);
     427       16248 :                 col->char_conv =
     428       16248 :                         tds_iconv_from_collate(tds->conn, col->column_collation);
     429             :         }
     430             : 
     431             :         /* Only read table_name for blob columns (eg. not for SYBLONGBINARY) */
     432       52892 :         if (is_blob_type(col->on_server.column_type)) {
     433             :                 /* discard this additional byte */
     434        1922 :                 if (IS_TDS72_PLUS(tds->conn)) {
     435         486 :                         unsigned char num_parts = tds_get_byte(tds);
     436             :                         /* TODO do not discard first ones */
     437         972 :                         for (; num_parts; --num_parts) {
     438         486 :                                 tds_dstr_get(tds, &col->table_name, tds_get_usmallint(tds));
     439             :                         }
     440             :                 } else {
     441        1436 :                         tds_dstr_get(tds, &col->table_name, tds_get_usmallint(tds));
     442             :                 }
     443       50970 :         } else if (IS_TDS72_PLUS(tds->conn) && col->on_server.column_type == SYBMSXML) {
     444           8 :                 unsigned char has_schema = tds_get_byte(tds);
     445           8 :                 if (has_schema) {
     446             :                         /* discard schema information */
     447           2 :                         tds_get_string(tds, tds_get_byte(tds), NULL, 0);        /* dbname */
     448           2 :                         tds_get_string(tds, tds_get_byte(tds), NULL, 0);        /* schema owner */
     449           2 :                         tds_get_string(tds, tds_get_usmallint(tds), NULL, 0);    /* schema collection */
     450             :                 }
     451             :         }
     452             :         return TDS_SUCCESS;
     453             : }
     454             : 
     455             : /* tds_generic_row_len support also variant and return size to hold blob */
     456             : TDS_COMPILE_CHECK(variant_size, sizeof(TDSBLOB) >= sizeof(TDSVARIANT));
     457             : 
     458             : TDS_INT
     459      114636 : tds_generic_row_len(TDSCOLUMN *col)
     460             : {
     461      114636 :         CHECK_COLUMN_EXTRA(col);
     462             : 
     463      114636 :         if (is_blob_col(col))
     464             :                 return sizeof(TDSBLOB);
     465      107050 :         return col->column_size;
     466             : }
     467             : 
     468             : static TDSRET
     469        2776 : tds_get_char_dynamic(TDSSOCKET *tds, TDSCOLUMN *curcol, void **pp, size_t allocated, TDSINSTREAM *r_stream)
     470             : {
     471             :         TDSRET res;
     472             :         TDSDYNAMICSTREAM w;
     473             : 
     474             :         /*
     475             :          * Blobs don't use a column's fixed buffer because the official maximum size is 2 GB.
     476             :          * Instead, they're reallocated as necessary, based on the data's size.
     477             :          */
     478        2776 :         TDS_PROPAGATE(tds_dynamic_stream_init(&w, pp, allocated));
     479             : 
     480        2776 :         if (USE_ICONV && curcol->char_conv)
     481         840 :                 res = tds_convert_stream(tds, curcol->char_conv, to_client, r_stream, &w.stream);
     482             :         else
     483        1936 :                 res = tds_copy_stream(r_stream, &w.stream);
     484        2776 :         curcol->column_cur_size = w.size;
     485             :         return res;
     486             : }
     487             : 
     488             : typedef struct tds_varmax_stream {
     489             :         TDSINSTREAM stream;
     490             :         TDSSOCKET *tds;
     491             :         TDS_INT chunk_left;
     492             : } TDSVARMAXSTREAM;
     493             : 
     494             : static int
     495         174 : tds_varmax_stream_read(TDSINSTREAM *stream, void *ptr, size_t len)
     496             : {
     497         174 :         TDSVARMAXSTREAM *s = (TDSVARMAXSTREAM *) stream;
     498             : 
     499             :         /* read chunk len if needed */
     500         174 :         if (s->chunk_left == 0) {
     501         174 :                 TDS_INT l = tds_get_int(s->tds);
     502         174 :                 if (l <= 0) l = -1;
     503         174 :                 s->chunk_left = l;
     504             :         }
     505             : 
     506             :         /* no more data ?? */
     507         174 :         if (s->chunk_left < 0)
     508             :                 return 0;
     509             : 
     510             :         /* read part of data */
     511          80 :         if (len > s->chunk_left)
     512          80 :                 len = s->chunk_left;
     513          80 :         s->chunk_left -= len;
     514          80 :         if (tds_get_n(s->tds, ptr, len))
     515          80 :                 return len;
     516             :         return -1;
     517             : }
     518             : 
     519             : static TDSRET
     520          94 : tds72_get_varmax(TDSSOCKET * tds, TDSCOLUMN * curcol)
     521             : {
     522             :         TDS_INT8 len;
     523             :         TDSVARMAXSTREAM r;
     524          94 :         size_t allocated = 0;
     525          94 :         void **pp = (void**) &(((TDSBLOB*) curcol->column_data)->textvalue);
     526             : 
     527          94 :         len = tds_get_int8(tds);
     528             : 
     529             :         /* NULL */
     530          94 :         if (len == -1) {
     531           0 :                 curcol->column_cur_size = -1;
     532           0 :                 return TDS_SUCCESS;
     533             :         }
     534             : 
     535             :         /* try to allocate an initial buffer */
     536             :         if (len > (TDS_INT8) (~((size_t) 0) >> 1))
     537             :                 return TDS_FAIL;
     538          94 :         if (len > 0) {
     539          72 :                 TDS_ZERO_FREE(*pp);
     540          72 :                 allocated = (size_t) len;
     541          72 :                 if (is_unicode_type(curcol->on_server.column_type))
     542          22 :                         allocated /= 2;
     543             :         }
     544             : 
     545          94 :         r.stream.read = tds_varmax_stream_read;
     546          94 :         r.tds = tds;
     547          94 :         r.chunk_left = 0;
     548             : 
     549          94 :         return tds_get_char_dynamic(tds, curcol, pp, allocated, &r.stream);
     550             : }
     551             : 
     552             : TDS_COMPILE_CHECK(tds_variant_size,  sizeof(((TDSVARIANT*)0)->data) == sizeof(((TDSBLOB*)0)->textvalue));
     553             : TDS_COMPILE_CHECK(tds_variant_offset,TDS_OFFSET(TDSVARIANT, data) == TDS_OFFSET(TDSBLOB, textvalue));
     554             : 
     555             : /*
     556             :  * This strange type has following structure 
     557             :  * 0 len (int32) -- NULL 
     558             :  * len (int32), type (int8), data -- ints, date, etc
     559             :  * len (int32), type (int8), 7 (int8), collation, column size (int16) -- [n]char, [n]varchar, binary, varbinary 
     560             :  * BLOBS (text/image) not supported
     561             :  */
     562             : TDSRET
     563         104 : tds_variant_get(TDSSOCKET * tds, TDSCOLUMN * curcol)
     564             : {
     565         104 :         unsigned int colsize = tds_get_uint(tds);
     566             :         int varint;
     567             :         TDS_SERVER_TYPE type;
     568             :         TDS_UCHAR info_len;
     569             :         TDSVARIANT *v;
     570             :         TDSRET rc;
     571             : 
     572             :         /* NULL */
     573         104 :         curcol->column_cur_size = -1;
     574         104 :         if (colsize < 2) {
     575           4 :                 tds_get_n(tds, NULL, colsize);
     576           4 :                 return TDS_SUCCESS;
     577             :         }
     578             : 
     579         100 :         type = (TDS_SERVER_TYPE) tds_get_byte(tds);
     580         100 :         info_len = tds_get_byte(tds);
     581         100 :         if (!is_variant_inner_type(type))
     582             :                 goto error_type;
     583         100 :         v = (TDSVARIANT*) curcol->column_data;
     584         100 :         v->type = type;
     585         100 :         colsize -= 2;
     586         100 :         if (info_len > colsize)
     587             :                 goto error_type;
     588         100 :         if (is_collate_type(type)) {
     589          42 :                 if (sizeof(v->collation) > info_len)
     590             :                         goto error_type;
     591          42 :                 tds_get_n(tds, v->collation, sizeof(v->collation));
     592          42 :                 colsize -= sizeof(v->collation);
     593          42 :                 info_len -= sizeof(v->collation);
     594          42 :                 curcol->char_conv = is_unicode_type(type) ? 
     595          42 :                         tds->conn->char_convs[client2ucs2] : tds_iconv_from_collate(tds->conn, v->collation);
     596             :         }
     597             : 
     598             :         /* special case for numeric */
     599         100 :         if (is_numeric_type(type)) {
     600             :                 TDS_NUMERIC *num;
     601          12 :                 if (info_len != 2)
     602             :                         goto error_type;
     603          12 :                 if (v->data)
     604           6 :                         TDS_ZERO_FREE(v->data);
     605          12 :                 v->data_len = sizeof(TDS_NUMERIC);
     606          12 :                 num = tds_new0(TDS_NUMERIC, 1);
     607          12 :                 if (!num)
     608             :                         goto error_memory;
     609          12 :                 v->data = (TDS_CHAR *) num;
     610          12 :                 num->precision = tds_get_byte(tds);
     611          12 :                 num->scale     = tds_get_byte(tds);
     612          12 :                 colsize -= 2;
     613             :                 /* check prec/scale, don't let server crash us */
     614          12 :                 if (num->precision < 1 || num->precision > MAXPRECISION
     615          12 :                     || num->scale > num->precision)
     616             :                         goto error_type;
     617          12 :                 if (colsize > sizeof(num->array))
     618             :                         goto error_type;
     619          12 :                 curcol->column_cur_size = colsize;
     620          12 :                 tds_get_n(tds, num->array, colsize);
     621          12 :                 if (IS_TDS7_PLUS(tds->conn))
     622             :                         tds_swap_numeric(num);
     623             :                 return TDS_SUCCESS;
     624             :         }
     625             : 
     626             :         /* special case for MS date/time */
     627          88 :         switch (type) {
     628           8 :         case SYBMSTIME:
     629             :         case SYBMSDATETIME2:
     630             :         case SYBMSDATETIMEOFFSET:
     631           8 :                 if (info_len != 1)
     632             :                         goto error_type;
     633           8 :                 curcol->column_scale = curcol->column_prec = tds_get_byte(tds);
     634           8 :                 if (curcol->column_prec > 7)
     635             :                         goto error_type;
     636           8 :                 colsize -= info_len;
     637           8 :                 info_len = 0;
     638             :                 /* fall through */
     639           2 :         case SYBMSDATE:
     640           2 :                 if (info_len != 0)
     641             :                         goto error_type;
     642             :                 /* dirty trick */
     643          10 :                 tds->in_buf[--tds->in_pos] = colsize;
     644          10 :                 if (v->data)
     645           0 :                         TDS_ZERO_FREE(v->data);
     646          10 :                 v->data_len = sizeof(TDS_DATETIMEALL);
     647          10 :                 v->data = tds_new0(TDS_CHAR, sizeof(TDS_DATETIMEALL));
     648          10 :                 curcol->column_type = type;
     649          10 :                 curcol->column_data = (unsigned char *) v->data;
     650             :                 /* trick, call get function */
     651          10 :                 rc = tds_msdatetime_get(tds, curcol);
     652          10 :                 curcol->column_type = SYBVARIANT;
     653          10 :                 curcol->column_data = (unsigned char *) v;
     654          10 :                 return rc;
     655             :         default:
     656             :                 break;
     657             :         }
     658          78 :         varint = (type == SYBUNIQUE) ? 0 : tds_get_varint_size(tds->conn, type);
     659         156 :         if (varint != info_len || varint > 2)
     660             :                 goto error_type;
     661          78 :         switch (varint) {
     662          30 :         case 0:
     663          30 :                 v->size = tds_get_size_by_type(type);
     664          30 :                 break;
     665           0 :         case 1:
     666           0 :                 v->size = tds_get_byte(tds);
     667           0 :                 break;
     668          48 :         case 2:
     669          48 :                 v->size = tds_get_smallint(tds);
     670          48 :                 break;
     671             :         default:
     672             :                 goto error_type;
     673             :         }
     674          78 :         colsize -= info_len;
     675          78 :         curcol->column_cur_size = colsize;
     676          78 :         if (v->data)
     677           6 :                 TDS_ZERO_FREE(v->data);
     678          78 :         if (colsize) {
     679             :                 TDSDATAINSTREAM r;
     680             : 
     681          78 :                 if (USE_ICONV && curcol->char_conv)
     682          12 :                         v->type = tds_get_cardinal_type(type, 0);
     683             : 
     684          78 :                 tds_datain_stream_init(&r, tds, colsize);
     685          78 :                 TDS_PROPAGATE(tds_get_char_dynamic(tds, curcol, (void **) &v->data, colsize, &r.stream));
     686          78 :                 colsize = curcol->column_cur_size;
     687             : #ifdef WORDS_BIGENDIAN
     688             :                 tds_swap_datatype(tds_get_conversion_type(type, colsize), v->data);
     689             : #endif
     690             :         }
     691          78 :         v->data_len = colsize;
     692          78 :         CHECK_COLUMN_EXTRA(curcol);
     693          78 :         return TDS_SUCCESS;
     694             : 
     695           0 : error_type:
     696           0 : error_memory:
     697           0 :         tds_get_n(tds, NULL, colsize);
     698           0 :         return TDS_FAIL;
     699             : }
     700             : 
     701             : /**
     702             :  * Read a data from wire
     703             :  * \param tds state information for the socket and the TDS protocol
     704             :  * \param curcol column where store column information
     705             :  * \return TDS_FAIL on error or TDS_SUCCESS
     706             :  */
     707             : TDSRET
     708      933228 : tds_generic_get(TDSSOCKET * tds, TDSCOLUMN * curcol)
     709             : {
     710             :         unsigned char *dest;
     711             :         int len, colsize;
     712             :         int fillchar;
     713      933228 :         TDSBLOB *blob = NULL;
     714             : 
     715      933228 :         CHECK_TDS_EXTRA(tds);
     716      933228 :         CHECK_COLUMN_EXTRA(curcol);
     717             : 
     718      933228 :         tdsdump_log(TDS_DBG_INFO1, "tds_get_data: type %d, varint size %d\n", curcol->column_type, curcol->column_varint_size);
     719      933228 :         switch (curcol->column_varint_size) {
     720        2134 :         case 4:
     721             :                 /* It's a BLOB... */
     722        2134 :                 len = tds_get_byte(tds);
     723        2134 :                 blob = (TDSBLOB *) curcol->column_data;
     724        2134 :                 if (len == 16) {        /*  Jeff's hack */
     725        1944 :                         tds_get_n(tds, blob->textptr, 16);
     726        1944 :                         tds_get_n(tds, blob->timestamp, 8);
     727        1944 :                         blob->valid_ptr = true;
     728        2442 :                         if (IS_TDS72_PLUS(tds->conn) &&
     729         498 :                             memcmp(blob->textptr, "dummy textptr\0\0",16) == 0)
     730         498 :                                 blob->valid_ptr = false;
     731        1944 :                         colsize = tds_get_int(tds);
     732             :                 } else {
     733             :                         colsize = -1;
     734             :                 }
     735             :                 break;
     736         786 :         case 5:
     737         786 :                 colsize = tds_get_int(tds);
     738         786 :                 if (colsize == 0)
     739           0 :                         colsize = -1;
     740             :                 break;
     741          94 :         case 8:
     742          94 :                 return tds72_get_varmax(tds, curcol);
     743      308856 :         case 2:
     744      308856 :                 colsize = tds_get_smallint(tds);
     745      308856 :                 break;
     746      338733 :         case 1:
     747      338733 :                 colsize = tds_get_byte(tds);
     748      338733 :                 if (colsize == 0)
     749        7624 :                         colsize = -1;
     750             :                 break;
     751      282625 :         case 0:
     752             :                 /* TODO this should be column_size */
     753      282625 :                 colsize = tds_get_size_by_type(curcol->column_type);
     754             :                 break;
     755             :         default:
     756             :                 colsize = -1;
     757             :                 break;
     758             :         }
     759      933134 :         if (IS_TDSDEAD(tds))
     760             :                 return TDS_FAIL;
     761             : 
     762      933134 :         tdsdump_log(TDS_DBG_INFO1, "tds_get_data(): wire column size is %d \n", colsize);
     763             :         /* set NULL flag in the row buffer */
     764      933134 :         if (colsize < 0) {
     765       10674 :                 curcol->column_cur_size = -1;
     766       10674 :                 return TDS_SUCCESS;
     767             :         }
     768             : 
     769             :         /* 
     770             :          * We're now set to read the data from the wire.  For varying types (e.g. char/varchar)
     771             :          * make sure that curcol->column_cur_size reflects the size of the read data, 
     772             :          * after any charset conversion.  tds_get_char_data() does that for you, 
     773             :          * but of course tds_get_n() doesn't.  
     774             :          *
     775             :          * colsize == wire_size, bytes to read
     776             :          * curcol->column_cur_size == sizeof destination buffer, room to write
     777             :          */
     778      922460 :         dest = curcol->column_data;
     779      922460 :         if (is_blob_col(curcol)) {
     780             :                 TDSDATAINSTREAM r;
     781             :                 size_t allocated;
     782             :                 TDSRET ret;
     783             : 
     784        2730 :                 blob = (TDSBLOB *) dest;        /* cf. column_varint_size case 4, above */
     785             : 
     786             :                 /* empty string */
     787        2730 :                 if (colsize == 0) {
     788         126 :                         curcol->column_cur_size = 0;
     789         126 :                         if (blob->textvalue)
     790           0 :                                 TDS_ZERO_FREE(blob->textvalue);
     791             :                         return TDS_SUCCESS;
     792             :                 }
     793             : 
     794        2604 :                 allocated = MAX(curcol->column_cur_size, 0);
     795        2604 :                 if (colsize > allocated) {
     796        2332 :                         TDS_ZERO_FREE(blob->textvalue);
     797        2332 :                         allocated = colsize;
     798        2332 :                         if (is_unicode_type(curcol->on_server.column_type))
     799         530 :                                 allocated /= 2;
     800             :                 }
     801             : 
     802        2604 :                 tds_datain_stream_init(&r, tds, colsize);
     803        2604 :                 ret = tds_get_char_dynamic(tds, curcol, (void **) &blob->textvalue, allocated, &r.stream);
     804        2604 :                 if (TDS_FAILED(ret) && TDS_UNLIKELY(r.wire_size > 0)) {
     805           0 :                         tds_get_n(tds, NULL, r.wire_size);
     806           0 :                         return ret;
     807             :                 }
     808             :                 return TDS_SUCCESS;
     809             :         }
     810             : 
     811             :         /* non-numeric and non-blob */
     812             : 
     813      919730 :         if (USE_ICONV && curcol->char_conv) {
     814      381965 :                 TDS_PROPAGATE(tds_get_char_data(tds, (char *) dest, colsize, curcol));
     815             :         } else {
     816             :                 /*
     817             :                  * special case, some servers seem to return more data in some conditions
     818             :                  * (ASA 7 returning 4 byte nullable integer)
     819             :                  */
     820      537765 :                 int discard_len = 0;
     821      537765 :                 if (colsize > curcol->column_size) {
     822           0 :                         discard_len = colsize - curcol->column_size;
     823           0 :                         colsize = curcol->column_size;
     824             :                 }
     825      537765 :                 if (!tds_get_n(tds, dest, colsize))
     826             :                         return TDS_FAIL;
     827      537765 :                 if (discard_len > 0)
     828           0 :                         tds_get_n(tds, NULL, discard_len);
     829      537765 :                 curcol->column_cur_size = colsize;
     830             :         }
     831             : 
     832             :         /* pad (UNI)CHAR and BINARY types */
     833      919730 :         fillchar = 0;
     834      919730 :         switch (curcol->column_type) {
     835             :         /* extra handling for SYBLONGBINARY */
     836           0 :         case SYBLONGBINARY:
     837           0 :                 if (curcol->column_usertype != USER_UNICHAR_TYPE)
     838             :                         break;
     839             :         case SYBCHAR:
     840             :         case XSYBCHAR:
     841      166130 :                 if (curcol->column_size != curcol->on_server.column_size)
     842             :                         break;
     843             :                 /* FIXME use client charset */
     844             :                 fillchar = ' ';
     845      165770 :         case SYBBINARY:
     846             :         case XSYBBINARY:
     847      165770 :                 if (colsize < curcol->column_size)
     848          70 :                         memset(dest + colsize, fillchar, curcol->column_size - colsize);
     849      165770 :                 colsize = curcol->column_size;
     850      165770 :                 break;
     851             :         default:
     852             :                 break;
     853             :         }
     854             : 
     855             : #ifdef WORDS_BIGENDIAN
     856             :         tdsdump_log(TDS_DBG_INFO1, "swapping coltype %d\n", tds_get_conversion_type(curcol->column_type, colsize));
     857             :         tds_swap_datatype(tds_get_conversion_type(curcol->column_type, colsize), dest);
     858             : #endif
     859         456 :         return TDS_SUCCESS;
     860             : }
     861             : 
     862             : /**
     863             :  * Put data information to wire
     864             :  * \param tds   state information for the socket and the TDS protocol
     865             :  * \param col   column where to store information
     866             :  * \return TDS_SUCCESS or TDS_FAIL
     867             :  */
     868             : TDSRET
     869        8326 : tds_generic_put_info(TDSSOCKET * tds, TDSCOLUMN * col)
     870             : {
     871             :         size_t size;
     872             : 
     873        8326 :         CHECK_TDS_EXTRA(tds);
     874        8326 :         CHECK_COLUMN_EXTRA(col);
     875             : 
     876        8326 :         size = tds_fix_column_size(tds, col);
     877        8326 :         switch (col->column_varint_size) {
     878             :         case 0:
     879             :                 break;
     880        3712 :         case 1:
     881        3712 :                 tds_put_byte(tds, size);
     882        3712 :                 break;
     883        3056 :         case 2:
     884        3056 :                 tds_put_smallint(tds, size);
     885        3056 :                 break;
     886         630 :         case 5:
     887             :         case 4:
     888         630 :                 tds_put_int(tds, size);
     889         630 :                 break;
     890         314 :         case 8:
     891         314 :                 tds_put_smallint(tds, 0xffff);
     892         314 :                 break;
     893             :         }
     894             : 
     895             :         /* TDS5 wants a table name for LOBs */
     896        8326 :         if (IS_TDS50(tds->conn) && is_blob_type(col->on_server.column_type))
     897           0 :                 tds_put_smallint(tds, 0);
     898             : 
     899             :         /* TDS7.1 output collate information */
     900        8326 :         if (IS_TDS71_PLUS(tds->conn) && is_collate_type(col->on_server.column_type))
     901        3678 :                 tds_put_n(tds, tds->conn->collation, 5);
     902             : 
     903        8326 :         return TDS_SUCCESS;
     904             : }
     905             : 
     906             : /**
     907             :  * Write data to wire
     908             :  * \param tds state information for the socket and the TDS protocol
     909             :  * \param curcol column where store column information
     910             :  * \return TDS_FAIL on error or TDS_SUCCESS
     911             :  */
     912             : TDSRET
     913       14348 : tds_generic_put(TDSSOCKET * tds, TDSCOLUMN * curcol, int bcp7)
     914             : {
     915             :         unsigned char *src;
     916       14348 :         TDSBLOB *blob = NULL;
     917             :         size_t colsize, size;
     918             : 
     919             :         const char *s;
     920       14348 :         int converted = 0;
     921             : 
     922       14348 :         CHECK_TDS_EXTRA(tds);
     923       14348 :         CHECK_COLUMN_EXTRA(curcol);
     924             : 
     925       14348 :         tdsdump_log(TDS_DBG_INFO1, "tds_generic_put: colsize = %d\n", (int) curcol->column_cur_size);
     926             : 
     927             :         /* output NULL data */
     928       14348 :         if (curcol->column_cur_size < 0) {
     929        3892 :                 tdsdump_log(TDS_DBG_INFO1, "tds_generic_put: null param\n");
     930        3892 :                 switch (curcol->column_varint_size) {
     931           0 :                 case 5:
     932           0 :                         tds_put_int(tds, 0);
     933           0 :                         break;
     934          86 :                 case 4:
     935          86 :                         if ((bcp7 || !IS_TDS7_PLUS(tds->conn)) && is_blob_type(curcol->on_server.column_type))
     936          14 :                                 tds_put_byte(tds, 0);
     937             :                         else
     938          72 :                                 tds_put_int(tds, -1);
     939             :                         break;
     940        1050 :                 case 2:
     941        1050 :                         tds_put_smallint(tds, -1);
     942        1050 :                         break;
     943          40 :                 case 8:
     944          40 :                         tds_put_int8(tds, -1);
     945          40 :                         break;
     946        2716 :                 default:
     947        2716 :                         assert(curcol->column_varint_size);
     948             :                         /* FIXME not good for SYBLONGBINARY/SYBLONGCHAR (still not supported) */
     949        2716 :                         tds_put_byte(tds, 0);
     950        2716 :                         break;
     951             :                 }
     952             :                 return TDS_SUCCESS;
     953             :         }
     954       10456 :         colsize = curcol->column_cur_size;
     955             : 
     956       10456 :         size = tds_fix_column_size(tds, curcol);
     957             : 
     958       10456 :         src = curcol->column_data;
     959       10456 :         if (is_blob_col(curcol)) {
     960         854 :                 blob = (TDSBLOB *) src;
     961         854 :                 src = (unsigned char *) blob->textvalue;
     962             :         }
     963             : 
     964       10456 :         s = (char *) src;
     965             : 
     966             :         /* convert string if needed */
     967       10456 :         if (!bcp7 && curcol->char_conv && curcol->char_conv->flags != TDS_ENCODING_MEMCPY && colsize) {
     968             :                 size_t output_size;
     969             : #if 0
     970             :                 /* TODO this case should be optimized */
     971             :                 /* we know converted bytes */
     972             :                 if (curcol->char_conv->client_charset.min_bytes_per_char == curcol->char_conv->client_charset.max_bytes_per_char 
     973             :                     && curcol->char_conv->server_charset.min_bytes_per_char == curcol->char_conv->server_charset.max_bytes_per_char) {
     974             :                         converted_size = colsize * curcol->char_conv->server_charset.min_bytes_per_char / curcol->char_conv->client_charset.min_bytes_per_char;
     975             : 
     976             :                 } else {
     977             : #endif
     978             :                 /* we need to convert data before */
     979             :                 /* TODO this can be a waste of memory... */
     980        2258 :                 converted = 1;
     981        2258 :                 s = tds_convert_string(tds, curcol->char_conv, s, colsize, &output_size);
     982        2258 :                 colsize = (TDS_INT)output_size;
     983        2258 :                 if (!s) {
     984             :                         /* on conversion error put a empty string */
     985             :                         /* TODO on memory failure we should compute converted size and use chunks */
     986           0 :                         colsize = 0;
     987           0 :                         converted = -1;
     988             :                 }
     989             :         }
     990             : 
     991             :         /*
     992             :          * TODO here we limit data sent with MIN, should mark somewhere
     993             :          * and inform client ??
     994             :          * Test proprietary behavior
     995             :          */
     996       10456 :         if (IS_TDS7_PLUS(tds->conn)) {
     997        9822 :                 tdsdump_log(TDS_DBG_INFO1, "tds_generic_put: not null param varint_size = %d\n",
     998           0 :                             curcol->column_varint_size);
     999             : 
    1000        9822 :                 switch (curcol->column_varint_size) {
    1001         280 :                 case 8:
    1002             :                         /* this difference for BCP operation is due to
    1003             :                          * a bug in different server version that does
    1004             :                          * not accept a length here */
    1005         280 :                         tds_put_int8(tds, bcp7 ? (TDS_INT8) -2 : (TDS_INT8) colsize);
    1006         280 :                         tds_put_int(tds, colsize);
    1007         280 :                         break;
    1008         570 :                 case 4: /* It's a BLOB... */
    1009         570 :                         colsize = MIN(colsize, size);
    1010             :                         /* mssql require only size */
    1011         570 :                         if (bcp7 && is_blob_type(curcol->on_server.column_type)) {
    1012             :                                 static const unsigned char textptr[] = {
    1013             :                                         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    1014             :                                         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
    1015             :                                 };
    1016          48 :                                 tds_put_byte(tds, 16);
    1017          48 :                                 tds_put_n(tds, textptr, 16);
    1018          48 :                                 tds_put_n(tds, textptr, 8);
    1019             :                         }
    1020         570 :                         tds_put_int(tds, colsize);
    1021         570 :                         break;
    1022        3348 :                 case 2:
    1023        3348 :                         colsize = MIN(colsize, size);
    1024        3348 :                         tds_put_smallint(tds, colsize);
    1025        3348 :                         break;
    1026        2564 :                 case 1:
    1027        2564 :                         colsize = MIN(colsize, size);
    1028        2564 :                         tds_put_byte(tds, colsize);
    1029        2564 :                         break;
    1030        3060 :                 case 0:
    1031             :                         /* TODO should be column_size */
    1032        3060 :                         colsize = tds_get_size_by_type(curcol->on_server.column_type);
    1033        3060 :                         break;
    1034             :                 }
    1035             : 
    1036             :                 /* conversion error, exit with an error */
    1037        9822 :                 if (converted < 0)
    1038             :                         return TDS_FAIL;
    1039             : 
    1040             :                 /* put real data */
    1041        9822 :                 if (blob) {
    1042         850 :                         tds_put_n(tds, s, colsize);
    1043             :                 } else {
    1044             : #ifdef WORDS_BIGENDIAN
    1045             :                         unsigned char buf[64];
    1046             : 
    1047             :                         if (!converted && colsize < 64) {
    1048             :                                 tdsdump_log(TDS_DBG_INFO1, "swapping coltype %d\n",
    1049             :                                             tds_get_conversion_type(curcol->column_type, colsize));
    1050             :                                 memcpy(buf, s, colsize);
    1051             :                                 tds_swap_datatype(tds_get_conversion_type(curcol->column_type, colsize), buf);
    1052             :                                 s = (char *) buf;
    1053             :                         }
    1054             : #endif
    1055        8972 :                         tds_put_n(tds, s, colsize);
    1056             :                 }
    1057             :                 /* finish chunk for varchar/varbinary(max) */
    1058        9822 :                 if (curcol->column_varint_size == 8 && colsize)
    1059         272 :                         tds_put_int(tds, 0);
    1060             :         } else {
    1061             :                 /* TODO ICONV handle charset conversions for data */
    1062             :                 /* put size of data */
    1063         634 :                 switch (curcol->column_varint_size) {
    1064           4 :                 case 5: /* It's a LONGBINARY */
    1065           4 :                         colsize = MIN(colsize, 0x7fffffff);
    1066           4 :                         tds_put_int(tds, colsize);
    1067           4 :                         break;
    1068           0 :                 case 4: /* It's a BLOB... */
    1069           0 :                         tds_put_byte(tds, 16);
    1070           0 :                         tds_put_n(tds, blob->textptr, 16);
    1071           0 :                         tds_put_n(tds, blob->timestamp, 8);
    1072           0 :                         colsize = MIN(colsize, 0x7fffffff);
    1073           0 :                         tds_put_int(tds, colsize);
    1074           0 :                         break;
    1075           0 :                 case 2:
    1076           0 :                         colsize = MIN(colsize, 8000);
    1077           0 :                         tds_put_smallint(tds, colsize);
    1078           0 :                         break;
    1079         618 :                 case 1:
    1080         618 :                         if (!colsize) {
    1081          10 :                                 tds_put_byte(tds, 1);
    1082          10 :                                 if (is_char_type(curcol->column_type))
    1083          10 :                                         tds_put_byte(tds, ' ');
    1084             :                                 else
    1085           0 :                                         tds_put_byte(tds, 0);
    1086          10 :                                 if (converted > 0)
    1087           0 :                                         tds_convert_string_free((char*)src, s);
    1088             :                                 return TDS_SUCCESS;
    1089             :                         }
    1090         608 :                         colsize = MIN(colsize, 255);
    1091         608 :                         tds_put_byte(tds, colsize);
    1092         608 :                         break;
    1093          12 :                 case 0:
    1094             :                         /* TODO should be column_size */
    1095          12 :                         colsize = tds_get_size_by_type(curcol->column_type);
    1096          12 :                         break;
    1097             :                 }
    1098             : 
    1099             :                 /* conversion error, exit with an error */
    1100         624 :                 if (converted < 0)
    1101             :                         return TDS_FAIL;
    1102             : 
    1103             :                 /* put real data */
    1104         624 :                 if (blob) {
    1105           4 :                         tds_put_n(tds, s, colsize);
    1106             :                 } else {
    1107             : #ifdef WORDS_BIGENDIAN
    1108             :                         unsigned char buf[64];
    1109             : 
    1110             :                         if (!converted && colsize < 64) {
    1111             :                                 tdsdump_log(TDS_DBG_INFO1, "swapping coltype %d\n",
    1112             :                                             tds_get_conversion_type(curcol->column_type, colsize));
    1113             :                                 memcpy(buf, s, colsize);
    1114             :                                 tds_swap_datatype(tds_get_conversion_type(curcol->column_type, colsize), buf);
    1115             :                                 s = (char *) buf;
    1116             :                         }
    1117             : #endif
    1118         620 :                         tds_put_n(tds, s, colsize);
    1119             :                 }
    1120             :         }
    1121       10446 :         if (converted > 0)
    1122        2258 :                 tds_convert_string_free((char*)src, s);
    1123             :         return TDS_SUCCESS;
    1124             : }
    1125             : 
    1126             : TDSRET
    1127        1176 : tds_numeric_get_info(TDSSOCKET *tds, TDSCOLUMN *col)
    1128             : {
    1129        1176 :         col->column_size = tds_get_byte(tds);
    1130        1176 :         col->column_prec = tds_get_byte(tds);        /* precision */
    1131        1176 :         col->column_scale = tds_get_byte(tds);       /* scale */
    1132             : 
    1133             :         /* check prec/scale, don't let server crash us */
    1134        1176 :         if (col->column_prec < 1 || col->column_prec > MAXPRECISION
    1135        1176 :             || col->column_scale > col->column_prec)
    1136             :                 return TDS_FAIL;
    1137             : 
    1138        1176 :         return TDS_SUCCESS;
    1139             : }
    1140             : 
    1141             : TDS_INT
    1142        2760 : tds_numeric_row_len(TDSCOLUMN *col TDS_UNUSED)
    1143             : {
    1144        2760 :         return sizeof(TDS_NUMERIC);
    1145             : }
    1146             : 
    1147             : TDSRET
    1148        1474 : tds_numeric_get(TDSSOCKET * tds, TDSCOLUMN * curcol)
    1149             : {
    1150             :         int colsize;
    1151             :         TDS_NUMERIC *num;
    1152             : 
    1153        1474 :         CHECK_TDS_EXTRA(tds);
    1154        1474 :         CHECK_COLUMN_EXTRA(curcol);
    1155             : 
    1156        1474 :         colsize = tds_get_byte(tds);
    1157             : 
    1158             :         /* set NULL flag in the row buffer */
    1159        1474 :         if (colsize <= 0) {
    1160         332 :                 curcol->column_cur_size = -1;
    1161         332 :                 return TDS_SUCCESS;
    1162             :         }
    1163             : 
    1164             :         /* 
    1165             :          * Since these can be passed around independent
    1166             :          * of the original column they came from, we embed the TDS_NUMERIC datatype in the row buffer
    1167             :          * instead of using the wire representation, even though it uses a few more bytes.  
    1168             :          */
    1169        1142 :         num = (TDS_NUMERIC *) curcol->column_data;
    1170        1142 :         memset(num, '\0', sizeof(TDS_NUMERIC));
    1171             :         /* TODO perhaps it would be fine to change format ?? */
    1172        1142 :         num->precision = curcol->column_prec;
    1173        1142 :         num->scale = curcol->column_scale;
    1174             : 
    1175             :         /* server is going to crash freetds ?? */
    1176             :         /* TODO close connection it server try to do so ?? */
    1177        1142 :         if (colsize > sizeof(num->array))
    1178             :                 return TDS_FAIL;
    1179        1142 :         tds_get_n(tds, num->array, colsize);
    1180             : 
    1181        1142 :         if (IS_TDS7_PLUS(tds->conn))
    1182             :                 tds_swap_numeric(num);
    1183             : 
    1184             :         /* corrected colsize for column_cur_size */
    1185        1142 :         curcol->column_cur_size = sizeof(TDS_NUMERIC);
    1186             : 
    1187        1142 :         return TDS_SUCCESS;
    1188             : }
    1189             : 
    1190             : TDSRET
    1191         538 : tds_numeric_put_info(TDSSOCKET * tds, TDSCOLUMN * col)
    1192             : {
    1193         538 :         CHECK_TDS_EXTRA(tds);
    1194         538 :         CHECK_COLUMN_EXTRA(col);
    1195             : 
    1196             : #if 1
    1197         538 :         tds_put_byte(tds, tds_numeric_bytes_per_prec[col->column_prec]);
    1198         538 :         tds_put_byte(tds, col->column_prec);
    1199         538 :         tds_put_byte(tds, col->column_scale);
    1200             : #else
    1201             :         TDS_NUMERIC *num = (TDS_NUMERIC *) col->column_data;
    1202             :         tds_put_byte(tds, tds_numeric_bytes_per_prec[num->precision]);
    1203             :         tds_put_byte(tds, num->precision);
    1204             :         tds_put_byte(tds, num->scale);
    1205             : #endif
    1206             : 
    1207         538 :         return TDS_SUCCESS;
    1208             : }
    1209             : 
    1210             : TDSRET
    1211        1462 : tds_numeric_put(TDSSOCKET *tds, TDSCOLUMN *col, int bcp7 TDS_UNUSED)
    1212             : {
    1213        1462 :         TDS_NUMERIC *num = (TDS_NUMERIC *) col->column_data, buf;
    1214             :         unsigned char colsize;
    1215             : 
    1216        1462 :         if (col->column_cur_size < 0) {
    1217         606 :                 tds_put_byte(tds, 0);
    1218         606 :                 return TDS_SUCCESS;
    1219             :         }
    1220         856 :         colsize = tds_numeric_bytes_per_prec[num->precision];
    1221         856 :         tds_put_byte(tds, colsize);
    1222             : 
    1223         856 :         buf = *num;
    1224         856 :         if (IS_TDS7_PLUS(tds->conn))
    1225             :                 tds_swap_numeric(&buf);
    1226         856 :         tds_put_n(tds, buf.array, colsize);
    1227         856 :         return TDS_SUCCESS;
    1228             : }
    1229             : 
    1230             : TDSRET
    1231           0 : tds_variant_put_info(TDSSOCKET * tds TDS_UNUSED, TDSCOLUMN * col TDS_UNUSED)
    1232             : {
    1233             :         /* TODO */
    1234           0 :         return TDS_FAIL;
    1235             : }
    1236             : 
    1237             : TDSRET
    1238           0 : tds_variant_put(TDSSOCKET *tds TDS_UNUSED, TDSCOLUMN *col TDS_UNUSED, int bcp7 TDS_UNUSED)
    1239             : {
    1240             :         /* TODO */
    1241           0 :         return TDS_FAIL;
    1242             : }
    1243             : 
    1244             : TDSRET
    1245         130 : tds_msdatetime_get_info(TDSSOCKET * tds, TDSCOLUMN * col)
    1246             : {
    1247         130 :         col->column_scale = col->column_prec = 0;
    1248         130 :         if (col->column_type != SYBMSDATE) {
    1249          94 :                 col->column_scale = col->column_prec = tds_get_byte(tds);
    1250          94 :                 if (col->column_prec > 7)
    1251             :                         return TDS_FAIL;
    1252             :         }
    1253         130 :         col->on_server.column_size = col->column_size = sizeof(TDS_DATETIMEALL);
    1254         130 :         return TDS_SUCCESS;
    1255             : }
    1256             : 
    1257             : TDS_INT
    1258         896 : tds_msdatetime_row_len(TDSCOLUMN *col TDS_UNUSED)
    1259             : {
    1260         896 :         return sizeof(TDS_DATETIMEALL);
    1261             : }
    1262             : 
    1263             : TDSRET
    1264         130 : tds_msdatetime_get(TDSSOCKET * tds, TDSCOLUMN * col)
    1265             : {
    1266         130 :         TDS_DATETIMEALL *dt = (TDS_DATETIMEALL*) col->column_data;
    1267         130 :         int size = tds_get_byte(tds);
    1268             : 
    1269         130 :         if (size == 0) {
    1270           0 :                 col->column_cur_size = -1;
    1271           0 :                 return TDS_SUCCESS;
    1272             :         }
    1273             : 
    1274         130 :         memset(dt, 0, sizeof(*dt));
    1275             : 
    1276         130 :         if (col->column_type == SYBMSDATETIMEOFFSET)
    1277          10 :                 size -= 2;
    1278         130 :         if (col->column_type != SYBMSTIME)
    1279          92 :                 size -= 3;
    1280         130 :         if (size < 0)
    1281             :                 return TDS_FAIL;
    1282             : 
    1283         130 :         dt->time_prec = col->column_prec;
    1284             : 
    1285             :         /* get time part */
    1286         130 :         if (col->column_type != SYBMSDATE) {
    1287             :                 TDS_UINT8 u8;
    1288             :                 int i;
    1289             : 
    1290          94 :                 if (size < 3 || size > 5)
    1291           0 :                         return TDS_FAIL;
    1292          94 :                 u8 = 0;
    1293          94 :                 tds_get_n(tds, &u8, size);
    1294             : #ifdef WORDS_BIGENDIAN
    1295             :                 tds_swap_bytes(&u8, 8);
    1296             : #endif
    1297         216 :                 for (i = col->column_prec; i < 7; ++i)
    1298         122 :                         u8 *= 10;
    1299          94 :                 dt->time = u8;
    1300          94 :                 dt->has_time = 1;
    1301          36 :         } else if (size != 0)
    1302             :                 return TDS_FAIL;
    1303             : 
    1304             :         /* get date part */
    1305         130 :         if (col->column_type != SYBMSTIME) {
    1306             :                 TDS_UINT ui;
    1307             : 
    1308          92 :                 ui = 0;
    1309          92 :                 tds_get_n(tds, &ui, 3);
    1310             : #ifdef WORDS_BIGENDIAN
    1311             :                 tds_swap_bytes(&ui, 4);
    1312             : #endif
    1313          92 :                 dt->has_date = 1;
    1314          92 :                 dt->date = ui - 693595;
    1315             :         }
    1316             : 
    1317             :         /* get time offset */
    1318         130 :         if (col->column_type == SYBMSDATETIMEOFFSET) {
    1319          10 :                 dt->offset = tds_get_smallint(tds);
    1320          10 :                 if (dt->offset > 840 || dt->offset < -840)
    1321             :                         return TDS_FAIL;
    1322          10 :                 dt->has_offset = 1;
    1323             :         }
    1324         130 :         col->column_cur_size = sizeof(TDS_DATETIMEALL);
    1325         130 :         return TDS_SUCCESS;
    1326             : }
    1327             : 
    1328             : TDSRET
    1329         174 : tds_msdatetime_put_info(TDSSOCKET * tds, TDSCOLUMN * col)
    1330             : {
    1331             :         /* TODO precision */
    1332         174 :         if (col->on_server.column_type != SYBMSDATE)
    1333         162 :                 tds_put_byte(tds, 7);
    1334         174 :         return TDS_SUCCESS;
    1335             : }
    1336             : 
    1337             : TDSRET
    1338         174 : tds_msdatetime_put(TDSSOCKET *tds, TDSCOLUMN *col, int bcp7 TDS_UNUSED)
    1339             : {
    1340         174 :         const TDS_DATETIMEALL *dta = (const TDS_DATETIMEALL *) col->column_data;
    1341             :         unsigned char buf[12], *p;
    1342             : 
    1343         174 :         if (col->column_cur_size < 0) {
    1344          36 :                 tds_put_byte(tds, 0);
    1345          36 :                 return TDS_SUCCESS;
    1346             :         }
    1347             : 
    1348             :         /* TODO precision */
    1349         138 :         p = buf + 1;
    1350         138 :         if (col->on_server.column_type != SYBMSDATE) {
    1351         126 :                 TDS_PUT_UA4LE(p, (TDS_UINT) dta->time);
    1352         126 :                 p[4] = (unsigned char) (dta->time >> 32);
    1353         126 :                 p += 5;
    1354             :         }
    1355         138 :         if (col->on_server.column_type != SYBMSTIME) {
    1356         126 :                 TDS_UINT ui = dta->date + 693595;
    1357         126 :                 TDS_PUT_UA4LE(p, ui);
    1358         126 :                 p += 3;
    1359             :         }
    1360         138 :         if (col->on_server.column_type == SYBMSDATETIMEOFFSET) {
    1361           0 :                 TDS_PUT_UA2LE(p, dta->offset);
    1362           0 :                 p += 2;
    1363             :         }
    1364         138 :         buf[0] = p - buf - 1;
    1365         138 :         tds_put_n(tds, buf, p - buf);
    1366             : 
    1367         138 :         return TDS_SUCCESS;
    1368             : }
    1369             : 
    1370             : TDSRET
    1371           4 : tds_clrudt_get_info(TDSSOCKET * tds, TDSCOLUMN * col)
    1372             : {
    1373             :         /* TODO save fields */
    1374             :         /* FIXME support RPC */
    1375             : 
    1376             :         /* MAX_BYTE_SIZE */
    1377           4 :         tds_get_usmallint(tds);
    1378             : 
    1379             :         /* DB_NAME */
    1380           4 :         tds_get_string(tds, tds_get_byte(tds), NULL, 0);
    1381             : 
    1382             :         /* SCHEMA_NAME */
    1383           4 :         tds_get_string(tds, tds_get_byte(tds), NULL, 0);
    1384             : 
    1385             :         /* TYPE_NAME */
    1386           4 :         tds_get_string(tds, tds_get_byte(tds), NULL, 0);
    1387             : 
    1388             :         /* UDT_METADATA */
    1389           4 :         tds_get_string(tds, tds_get_usmallint(tds), NULL, 0);
    1390             : 
    1391           4 :         col->column_size = 0x7ffffffflu;
    1392           4 :         col->column_varint_size = 8;
    1393             : 
    1394           4 :         return TDS_SUCCESS;
    1395             : }
    1396             : 
    1397             : TDS_INT
    1398           8 : tds_clrudt_row_len(TDSCOLUMN *col)
    1399             : {
    1400           8 :         col->column_varint_size = 8;
    1401             :         /* TODO save other fields */
    1402           8 :         return sizeof(TDSBLOB);
    1403             : }
    1404             : 
    1405             : TDSRET
    1406           0 : tds_clrudt_put_info(TDSSOCKET * tds, TDSCOLUMN * col TDS_UNUSED)
    1407             : {
    1408             :         /* FIXME support properly */
    1409           0 :         tds_put_byte(tds, 0);   /* db_name */
    1410           0 :         tds_put_byte(tds, 0);   /* schema_name */
    1411           0 :         tds_put_byte(tds, 0);   /* type_name */
    1412             : 
    1413           0 :         return TDS_SUCCESS;
    1414             : }
    1415             : 
    1416             : TDSRET
    1417           0 : tds_sybbigtime_get_info(TDSSOCKET * tds, TDSCOLUMN * col)
    1418             : {
    1419           0 :         col->column_scale = col->column_prec = 6;
    1420           0 :         tds_get_byte(tds); /* 8, size */
    1421           0 :         tds_get_byte(tds); /* 6, precision ?? */
    1422           0 :         col->on_server.column_size = col->column_size = sizeof(TDS_UINT8);
    1423           0 :         return TDS_SUCCESS;
    1424             : }
    1425             : 
    1426             : TDS_INT
    1427          48 : tds_sybbigtime_row_len(TDSCOLUMN *col TDS_UNUSED)
    1428             : {
    1429          48 :         return sizeof(TDS_UINT8);
    1430             : }
    1431             : 
    1432             : TDSRET
    1433           0 : tds_sybbigtime_get(TDSSOCKET * tds, TDSCOLUMN * col)
    1434             : {
    1435           0 :         TDS_UINT8 *dt = (TDS_UINT8 *) col->column_data;
    1436           0 :         int size = tds_get_byte(tds);
    1437             : 
    1438           0 :         if (size == 0) {
    1439           0 :                 col->column_cur_size = -1;
    1440           0 :                 return TDS_SUCCESS;
    1441             :         }
    1442             : 
    1443           0 :         col->column_cur_size = sizeof(TDS_UINT8);
    1444           0 :         *dt = tds_get_int8(tds);
    1445             : 
    1446           0 :         return TDS_SUCCESS;
    1447             : }
    1448             : 
    1449             : TDSRET
    1450           0 : tds_sybbigtime_put_info(TDSSOCKET * tds, TDSCOLUMN * col TDS_UNUSED)
    1451             : {
    1452           0 :         tds_put_byte(tds, 8);
    1453           0 :         tds_put_byte(tds, 6);
    1454           0 :         return TDS_SUCCESS;
    1455             : }
    1456             : 
    1457             : TDSRET
    1458           0 : tds_sybbigtime_put(TDSSOCKET *tds, TDSCOLUMN *col, int bcp7 TDS_UNUSED)
    1459             : {
    1460           0 :         const TDS_UINT8 *dt = (const TDS_UINT8 *) col->column_data;
    1461             : 
    1462           0 :         if (col->column_cur_size < 0) {
    1463           0 :                 tds_put_byte(tds, 0);
    1464           0 :                 return TDS_SUCCESS;
    1465             :         }
    1466             : 
    1467           0 :         tds_put_byte(tds, 8);
    1468           0 :         tds_put_int8(tds, *dt);
    1469             : 
    1470           0 :         return TDS_SUCCESS;
    1471             : }
    1472             : 
    1473             : TDSRET
    1474           0 : tds_mstabletype_get_info(TDSSOCKET *tds TDS_UNUSED, TDSCOLUMN *col TDS_UNUSED)
    1475             : {
    1476             :         /* Table type is strictly only an input variable */
    1477           0 :         return TDS_FAIL;
    1478             : }
    1479             : 
    1480             : TDS_INT
    1481           4 : tds_mstabletype_row_len(TDSCOLUMN *col TDS_UNUSED)
    1482             : {
    1483           4 :         return sizeof(TDS_TVP);
    1484             : }
    1485             : 
    1486             : TDSRET
    1487           0 : tds_mstabletype_get(TDSSOCKET *tds TDS_UNUSED, TDSCOLUMN *col TDS_UNUSED)
    1488             : {
    1489             :         /* Table type is strictly only an input variable */
    1490           0 :         return TDS_FAIL;
    1491             : }
    1492             : 
    1493             : TDSRET
    1494           4 : tds_mstabletype_put_info(TDSSOCKET *tds, TDSCOLUMN *col)
    1495             : {
    1496           4 :         TDS_TVP *table = (TDS_TVP *) col->column_data;
    1497             :         TDSFREEZE current_freeze[1];
    1498             :         size_t written;
    1499             : 
    1500             :         /* TVP_TYPENAME */
    1501           4 :         tds_put_byte(tds, 0); /* Empty DB name */
    1502             : 
    1503           4 :         tds_freeze(tds, current_freeze, 1);
    1504           4 :         tds_put_string(tds, table->schema, -1);
    1505           4 :         written = tds_freeze_written(current_freeze) / 2;
    1506           4 :         tds_freeze_close_len(current_freeze, written);
    1507             : 
    1508           4 :         tds_freeze(tds, current_freeze, 1);
    1509           4 :         tds_put_string(tds, table->name, -1);
    1510           4 :         written = tds_freeze_written(current_freeze) / 2;
    1511           4 :         tds_freeze_close_len(current_freeze, written);
    1512             : 
    1513           4 :         return TDS_SUCCESS;
    1514             : }
    1515             : 
    1516             : TDSRET
    1517           4 : tds_mstabletype_put(TDSSOCKET *tds, TDSCOLUMN *col, int bcp7 TDS_UNUSED)
    1518             : {
    1519           4 :         TDS_TVP *table = (TDS_TVP *) col->column_data;
    1520             :         TDSPARAMINFO *params;
    1521             :         TDSCOLUMN *tds_col;
    1522             :         TDS_TVP_ROW *row;
    1523             :         int i;
    1524           4 :         TDS_USMALLINT num_cols = table->metadata ? table->metadata->num_cols : 0;
    1525             : 
    1526             :         /* COL_METADATA */
    1527           4 :         if (num_cols == 0)
    1528           0 :                 tds_put_smallint(tds, 0xffff); /* TVP_NULL_TOKEN */
    1529             :         else {
    1530           4 :                 tds_put_smallint(tds, num_cols);
    1531             : 
    1532           4 :                 params = table->metadata;
    1533          12 :                 for (i = 0; i < num_cols; i++) {
    1534           8 :                         tds_col = params->columns[i];
    1535             : 
    1536             :                         /* UserType*/
    1537           8 :                         tds_put_int(tds, tds_col->column_usertype);
    1538             :                         /* Flags */
    1539           8 :                         tds_put_smallint(tds, tds_col->column_flags);
    1540             :                         /* TYPE_INFO */
    1541           8 :                         tds_put_byte(tds, tds_col->on_server.column_type);
    1542           8 :                         TDS_PROPAGATE(tds_col->funcs->put_info(tds, tds_col));
    1543             : 
    1544             :                         /* ColName - Empty string */
    1545           8 :                         tds_put_byte(tds, 0x00);
    1546             :                 }
    1547             :         }
    1548             : 
    1549             :         /* TVP_END_TOKEN */
    1550           4 :         tds_put_byte(tds, 0x00);
    1551             : 
    1552          22 :         for (row = table->row; row != NULL; row = row->next) {
    1553             :                 /* TVP_ROW_TOKEN */
    1554          18 :                 tds_put_byte(tds, 0x01);
    1555             : 
    1556          18 :                 params = row->params;
    1557          54 :                 for (i = 0; i < num_cols; i++) {
    1558          36 :                         tds_col = params->columns[i];
    1559          36 :                         TDS_PROPAGATE(tds_col->funcs->put_data(tds, tds_col, 0));
    1560             :                 }
    1561             :         }
    1562             : 
    1563             :         /* TVP_END_TOKEN */
    1564           4 :         tds_put_byte(tds, 0x00);
    1565             : 
    1566           4 :         return TDS_SUCCESS;
    1567             : }
    1568             : 
    1569             : TDSRET
    1570           0 : tds_invalid_get_info(TDSSOCKET * tds TDS_UNUSED, TDSCOLUMN * col TDS_UNUSED)
    1571             : {
    1572           0 :         return TDS_FAIL;
    1573             : }
    1574             : 
    1575             : TDS_INT
    1576           0 : tds_invalid_row_len(TDSCOLUMN *col TDS_UNUSED)
    1577             : {
    1578           0 :         return 0;
    1579             : }
    1580             : 
    1581             : TDSRET
    1582           0 : tds_invalid_get(TDSSOCKET * tds TDS_UNUSED, TDSCOLUMN * col TDS_UNUSED)
    1583             : {
    1584           0 :         return TDS_FAIL;
    1585             : }
    1586             : 
    1587             : TDSRET
    1588           0 : tds_invalid_put_info(TDSSOCKET * tds TDS_UNUSED, TDSCOLUMN * col TDS_UNUSED)
    1589             : {
    1590           0 :         return TDS_FAIL;
    1591             : }
    1592             : 
    1593             : TDSRET
    1594           0 : tds_invalid_put(TDSSOCKET *tds TDS_UNUSED, TDSCOLUMN *col TDS_UNUSED, int bcp7 TDS_UNUSED)
    1595             : {
    1596           0 :         return TDS_FAIL;
    1597             : }
    1598             : 
    1599             : #if ENABLE_EXTRA_CHECKS
    1600             : int
    1601    10070955 : tds_generic_check(const TDSCOLUMN *col TDS_UNUSED)
    1602             : {
    1603    10070955 :         return 0;
    1604             : }
    1605             : 
    1606             : int
    1607         112 : tds_sybbigtime_check(const TDSCOLUMN *col)
    1608             : {
    1609         112 :         assert(col->column_type == col->on_server.column_type);
    1610         112 :         assert(col->on_server.column_size == col->column_size);
    1611         112 :         assert(!is_numeric_type(col->column_type));
    1612         112 :         assert(!is_fixed_type(col->column_type));
    1613         112 :         assert(!is_blob_type(col->column_type));
    1614         112 :         assert(!is_variable_type(col->column_type));
    1615         112 :         assert(is_nullable_type(col->column_type));
    1616         112 :         assert(col->column_varint_size == 1);
    1617         112 :         assert(col->column_prec == 6);
    1618         112 :         assert(col->column_scale == col->column_prec);
    1619             : 
    1620         112 :         return 1;
    1621             : }
    1622             : 
    1623             : int
    1624          12 : tds_mstabletype_check(const TDSCOLUMN *col TDS_UNUSED)
    1625             : {
    1626          12 :         return 0;
    1627             : }
    1628             : 
    1629             : int
    1630          84 : tds_clrudt_check(const TDSCOLUMN *col TDS_UNUSED)
    1631             : {
    1632          84 :         return 0;
    1633             : }
    1634             : 
    1635             : int
    1636        3726 : tds_msdatetime_check(const TDSCOLUMN *col)
    1637             : {
    1638        3726 :         assert(col->column_type == col->on_server.column_type);
    1639        3726 :         assert(col->on_server.column_size == col->column_size);
    1640        3726 :         assert(!is_numeric_type(col->column_type));
    1641        3726 :         if (col->column_type == SYBMSDATE) {
    1642        1076 :                 assert(is_fixed_type(col->column_type));
    1643             :         } else {
    1644        2650 :                 assert(!is_fixed_type(col->column_type));
    1645             :         }
    1646        3726 :         assert(!is_blob_type(col->column_type));
    1647        3726 :         assert(!is_variable_type(col->column_type));
    1648        3726 :         assert(is_nullable_type(col->column_type));
    1649        3726 :         assert(col->column_varint_size == 1);
    1650        3726 :         assert(col->column_prec >= 0 && col->column_prec <= 7);
    1651        3726 :         assert(col->column_scale == col->column_prec);
    1652             : 
    1653        3726 :         return 1;
    1654             : }
    1655             : 
    1656             : int
    1657        7226 : tds_variant_check(const TDSCOLUMN *col TDS_UNUSED)
    1658             : {
    1659        7226 :         return 0;
    1660             : }
    1661             : 
    1662             : int
    1663       64141 : tds_numeric_check(const TDSCOLUMN *col)
    1664             : {
    1665       64141 :         assert(col->column_type == col->on_server.column_type);
    1666       64141 :         assert(col->on_server.column_size == col->column_size);
    1667       64141 :         assert(is_numeric_type(col->column_type));
    1668       64141 :         assert(!is_fixed_type(col->column_type));
    1669       64141 :         assert(!is_blob_type(col->column_type));
    1670       64141 :         assert(!is_variable_type(col->column_type));
    1671       64141 :         assert(col->column_varint_size == 1);
    1672       64141 :         assert(col->column_prec >= 1 && col->column_prec <= MAXPRECISION);
    1673       64141 :         assert(col->column_scale <= col->column_prec);
    1674             : 
    1675       64141 :         return 1;
    1676             : }
    1677             : 
    1678             : int
    1679           0 : tds_invalid_check(const TDSCOLUMN *col TDS_UNUSED)
    1680             : {
    1681           0 :         return 1;
    1682             : }
    1683             : #endif
    1684             : 
    1685             : 
    1686             : #define TDS_DECLARE_FUNCS(name) \
    1687             :      extern const TDSCOLUMNFUNCS tds_ ## name ## _funcs
    1688             : 
    1689             : #include <freetds/pushvis.h>
    1690             : TDS_DECLARE_FUNCS(generic);
    1691             : TDS_DECLARE_FUNCS(numeric);
    1692             : TDS_DECLARE_FUNCS(variant);
    1693             : TDS_DECLARE_FUNCS(msdatetime);
    1694             : TDS_DECLARE_FUNCS(clrudt);
    1695             : TDS_DECLARE_FUNCS(sybbigtime);
    1696             : TDS_DECLARE_FUNCS(invalid);
    1697             : TDS_DECLARE_FUNCS(mstabletype);
    1698             : #include <freetds/popvis.h>
    1699             : 
    1700             : static const TDSCOLUMNFUNCS *
    1701       73810 : tds_get_column_funcs(TDSCONNECTION *conn, int type)
    1702             : {
    1703       73810 :         switch (type) {
    1704             :         case SYBNUMERIC:
    1705             :         case SYBDECIMAL:
    1706             :                 return &tds_numeric_funcs;
    1707           4 :         case SYBMSUDT:
    1708           4 :                 return &tds_clrudt_funcs;
    1709        1270 :         case SYBVARIANT:
    1710        1270 :                 if (IS_TDS7_PLUS(conn))
    1711             :                         return &tds_variant_funcs;
    1712             :                 break;
    1713        1786 :         case SYBMSDATE:
    1714             :         case SYBMSTIME:
    1715             :         case SYBMSDATETIME2:
    1716             :         case SYBMSDATETIMEOFFSET:
    1717        1786 :                 return &tds_msdatetime_funcs;
    1718          48 :         case SYB5BIGTIME:
    1719             :         case SYB5BIGDATETIME:
    1720          48 :                 return &tds_sybbigtime_funcs;
    1721           4 :         case SYBMSTABLE:
    1722           4 :                 return &tds_mstabletype_funcs;
    1723             :         }
    1724       68518 :         return &tds_generic_funcs;
    1725             : }
    1726             : #include "tds_types.h"
    1727             : 
    1728             : #ifdef WORDS_BIGENDIAN
    1729             : void
    1730             : tds_swap_datatype(int coltype, void *b)
    1731             : {
    1732             :         unsigned char *buf = (unsigned char *) b;
    1733             : 
    1734             :         switch (coltype) {
    1735             :         case SYBDATETIME4:
    1736             :                 tds_swap_bytes(&buf[2], 2);
    1737             :         case SYBINT2:
    1738             :         case SYBUINT2:
    1739             :                 tds_swap_bytes(buf, 2);
    1740             :                 break;
    1741             :         case SYBMONEY:
    1742             :         case SYBDATETIME:
    1743             :                 tds_swap_bytes(&buf[4], 4);
    1744             :         case SYBINT4:
    1745             :         case SYBUINT4:
    1746             :         case SYBMONEY4:
    1747             :         case SYBREAL:
    1748             :         case SYBDATE:
    1749             :         case SYBTIME:
    1750             :                 tds_swap_bytes(buf, 4);
    1751             :                 break;
    1752             :         case SYBINT8:
    1753             :         case SYBUINT8:
    1754             :         case SYBFLT8:
    1755             :         case SYB5BIGTIME:
    1756             :         case SYB5BIGDATETIME:
    1757             :                 tds_swap_bytes(buf, 8);
    1758             :                 break;
    1759             :         case SYBUNIQUE:
    1760             :                 tds_swap_bytes(buf, 4);
    1761             :                 tds_swap_bytes(&buf[4], 2);
    1762             :                 tds_swap_bytes(&buf[6], 2);
    1763             :                 break;
    1764             :         }
    1765             : }
    1766             : #endif
    1767             : 
    1768             : /**
    1769             :  * Converts numeric from Microsoft representation to internal one (Sybase).
    1770             :  * \param num numeric data to convert
    1771             :  */
    1772             : static void
    1773             : tds_swap_numeric(TDS_NUMERIC *num)
    1774             : {
    1775             :         /* swap the sign */
    1776        1706 :         num->array[0] = (num->array[0] == 0) ? 1 : 0;
    1777             :         /* swap the data */
    1778        1706 :         tds_swap_bytes(&(num->array[1]), tds_numeric_bytes_per_prec[num->precision] - 1);
    1779             : }
    1780             : 

Generated by: LCOV version 1.13