LCOV - code coverage report
Current view: top level - src/server - server.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 105 235 44.7 %
Date: 2025-01-18 11:50:39 Functions: 12 18 66.7 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004  Brian Bruns
       3             :  * Copyright (C) 2010  Frediano Ziglio
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU Library General Public
       7             :  * License as published by the Free Software Foundation; either
       8             :  * version 2 of the License, or (at your option) any later version.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * Library General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU Library General Public
      16             :  * License along with this library; if not, write to the
      17             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      18             :  * Boston, MA 02111-1307, USA.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #if HAVE_STRING_H
      24             : #include <string.h>
      25             : #endif /* HAVE_STRING_H */
      26             : 
      27             : #include <assert.h>
      28             : 
      29             : #include <freetds/tds.h>
      30             : #include <freetds/server.h>
      31             : #include <freetds/utils/string.h>
      32             : #include <freetds/data.h>
      33             : #include <freetds/bytes.h>
      34             : 
      35             : static void
      36        2218 : tds_env_change_string(TDSSOCKET * tds, int type, const char *oldvalue, const char *newvalue)
      37             : {
      38             :         TDSFREEZE outer;
      39             : 
      40        2218 :         tds_put_byte(tds, TDS_ENVCHANGE_TOKEN);
      41        2218 :         tds_freeze(tds, &outer, 2);
      42        2218 :         tds_put_byte(tds, type);
      43        2218 :         TDS_START_LEN_TINYINT(tds) {
      44        2218 :                 tds_put_string(tds, newvalue, -1);
      45        2218 :         } TDS_END_LEN_STRING
      46        2218 :         TDS_START_LEN_TINYINT(tds) {
      47        2218 :                 tds_put_string(tds, oldvalue, -1);
      48        2218 :         } TDS_END_LEN_STRING
      49        2218 :         tds_freeze_close(&outer);
      50        2218 : }
      51             : 
      52             : void
      53        2218 : tds_env_change(TDSSOCKET * tds, int type, const char *oldvalue, const char *newvalue)
      54             : {
      55             :         TDS_SMALLINT totsize;
      56             : 
      57             :         /* If oldvalue is NULL, treat it like "" */
      58        2218 :         if (oldvalue == NULL)
      59         734 :                 oldvalue = "";
      60             : 
      61             :         /*
      62             :          * NOTE: I don't know why each type of environment value has a different
      63             :          * format.  According to the TDS5 specifications, they should all use
      64             :          * the same format.   The code for the TDS_ENV_CHARSET case *should*
      65             :          * work for all environment values.  -- Steve Kirkendall
      66             :          */
      67             : 
      68        2218 :         switch (type) {
      69        2218 :         case TDS_ENV_DATABASE:
      70             :         case TDS_ENV_LANG:
      71             :         case TDS_ENV_PACKSIZE:
      72             :         case TDS_ENV_CHARSET:
      73        2218 :                 tds_env_change_string(tds, type, oldvalue, newvalue);
      74        2218 :                 break;
      75           0 :         case TDS_ENV_LCID:
      76             :         case TDS_ENV_SQLCOLLATION:
      77             : #if 1
      78           0 :                 tds_put_byte(tds, TDS_ENVCHANGE_TOKEN);
      79             :                 /* totsize = type + len + newvalue + len + oldvalue */
      80           0 :                 totsize = 3 + strlen(newvalue) + strlen(oldvalue);
      81           0 :                 tds_put_smallint(tds, totsize);
      82           0 :                 tds_put_byte(tds, type);
      83           0 :                 tds_put_byte(tds, strlen(newvalue));
      84           0 :                 tds_put_n(tds, newvalue, strlen(newvalue));
      85           0 :                 tds_put_byte(tds, strlen(oldvalue));
      86           0 :                 tds_put_n(tds, oldvalue, strlen(oldvalue));
      87           0 :                 break;
      88             : #endif
      89           0 :         default:
      90           0 :                 tdsdump_log(TDS_DBG_WARN, "tds_env_change() ignoring unsupported environment code #%d", type);
      91             :         }
      92        2218 : }
      93             : 
      94             : void
      95           0 : tds_send_eed(TDSSOCKET * tds, int msgno, int msgstate, int severity, const char *msgtext, const char *srvname,
      96             :              const char *procname, int line, const char *sqlstate)
      97             : {
      98             :         TDSFREEZE outer;
      99             : 
     100           0 :         if (!procname)
     101           0 :                 procname = "";
     102             : 
     103           0 :         tds_put_byte(tds, TDS_EED_TOKEN);
     104           0 :         tds_freeze(tds, &outer, 2);
     105           0 :         tds_put_int(tds, msgno);
     106           0 :         tds_put_byte(tds, msgstate);
     107           0 :         tds_put_byte(tds, severity);
     108           0 :         TDS_START_LEN_TINYINT(tds) {
     109           0 :                 tds_put_string(tds, sqlstate, -1);
     110           0 :         } TDS_END_LEN_STRING
     111           0 :         tds_put_byte(tds, 0);   /* has EED */
     112           0 :         tds_put_byte(tds, 1);   /* status */
     113           0 :         tds_put_byte(tds, 0);   /* transaction state */
     114           0 :         TDS_START_LEN_USMALLINT(tds) {
     115           0 :                 tds_put_string(tds, msgtext, -1);
     116           0 :         } TDS_END_LEN_STRING
     117           0 :         TDS_START_LEN_TINYINT(tds) {
     118           0 :                 tds_put_string(tds, srvname, -1);
     119           0 :         } TDS_END_LEN_STRING
     120           0 :         TDS_START_LEN_TINYINT(tds) {
     121           0 :                 tds_put_string(tds, procname, -1);
     122           0 :         } TDS_END_LEN_STRING
     123           0 :         tds_put_smallint(tds, line);    /* line */
     124           0 :         tds_freeze_close(&outer);
     125           0 : }
     126             : 
     127             : static void
     128        1660 : tds_send_info(TDSSOCKET * tds, TDS_TINYINT token, int msgno, int msgstate, int severity,
     129             :               const char *msgtext, const char *srvname, const char *procname, int line)
     130             : {
     131             :         TDSFREEZE outer;
     132             : 
     133        1660 :         if (!procname)
     134        1660 :                 procname = "";
     135             : 
     136        1660 :         tds_put_byte(tds, token);
     137        1660 :         tds_freeze(tds, &outer, 2);
     138        1660 :         tds_put_int(tds, msgno);
     139        1660 :         tds_put_byte(tds, msgstate);
     140        1660 :         tds_put_byte(tds, severity);
     141        1660 :         TDS_START_LEN_USMALLINT(tds) {
     142        1660 :                 tds_put_string(tds, msgtext, -1);
     143        1660 :         } TDS_END_LEN_STRING
     144        1660 :         TDS_START_LEN_TINYINT(tds) {
     145        1660 :                 tds_put_string(tds, srvname, -1);
     146        1660 :         } TDS_END_LEN_STRING
     147        1660 :         TDS_START_LEN_TINYINT(tds) {
     148        1660 :                 tds_put_string(tds, procname, -1);
     149        1660 :         } TDS_END_LEN_STRING
     150        1660 :         if (IS_TDS72_PLUS(tds->conn))
     151         224 :                 tds_put_int(tds, line);
     152             :         else
     153        1436 :                 tds_put_smallint(tds, line);
     154        1660 :         tds_freeze_close(&outer);
     155        1660 : }
     156             : 
     157             : void
     158        1548 : tds_send_msg(TDSSOCKET * tds, int msgno, int msgstate, int severity,
     159             :              const char *msgtext, const char *srvname, const char *procname, int line)
     160             : {
     161        1548 :         tds_send_info(tds, TDS_INFO_TOKEN, msgno, msgstate, severity, msgtext, srvname, procname, line);
     162        1548 : }
     163             : 
     164             : void
     165         112 : tds_send_err(TDSSOCKET * tds, int msgno, int msgstate, int severity,
     166             :              const char *msgtext, const char *srvname, const char *procname, int line)
     167             : {
     168         112 :         tds_send_info(tds, TDS_ERROR_TOKEN, msgno, msgstate, severity, msgtext, srvname, procname, line);
     169         112 : }
     170             : 
     171             : void
     172         734 : tds_send_login_ack(TDSSOCKET * tds, const char *progname)
     173             : {
     174             :         TDS_UINT ui, version;
     175             :         TDSFREEZE outer;
     176             : 
     177         734 :         tds_put_byte(tds, TDS_LOGINACK_TOKEN);
     178         734 :         tds_freeze(tds, &outer, 2);         /* length of message */
     179         734 :         if (IS_TDS50(tds->conn)) {
     180           0 :                 tds_put_byte(tds, 5);
     181           0 :                 version = 0x05000000u;
     182             :         } else {
     183         734 :                 tds_put_byte(tds, 1);
     184             :                 /* see src/tds/token.c */
     185         734 :                 if (IS_TDS74_PLUS(tds->conn)) {
     186             :                         version = 0x74000004u;
     187         734 :                 } else if (IS_TDS73_PLUS(tds->conn)) {
     188             :                         version = 0x730B0003u;
     189         718 :                 } else if (IS_TDS72_PLUS(tds->conn)) {
     190             :                         version = 0x72090002u;
     191         718 :                 } else if (IS_TDS71_PLUS(tds->conn)) {
     192         718 :                         version = tds->conn->tds71rev1 ? 0x07010000u : 0x71000001u;
     193             :                 } else {
     194           0 :                         version = (TDS_MAJOR(tds->conn) << 24) | (TDS_MINOR(tds->conn) << 16);
     195             :                 }
     196             :         }
     197         734 :         TDS_PUT_A4BE(&ui, version);
     198         734 :         tds_put_n(tds, &ui, 4);
     199             : 
     200         734 :         TDS_START_LEN_TINYINT(tds) {
     201         734 :                 tds_put_string(tds, progname, -1);
     202         734 :         } TDS_END_LEN_STRING
     203             : 
     204             :         /* server version, always big endian */
     205         734 :         TDS_PUT_A4BE(&ui, tds->conn->product_version & 0x7fffffffu);
     206         734 :         tds_put_n(tds, &ui, 4);
     207             : 
     208         734 :         tds_freeze_close(&outer);
     209         734 : }
     210             : 
     211             : void
     212           0 : tds_send_capabilities_token(TDSSOCKET * tds)
     213             : {
     214           0 :         tds_put_byte(tds, TDS_CAPABILITY_TOKEN);
     215           0 :         tds_put_smallint(tds, 18);
     216           0 :         tds_put_byte(tds, 1);
     217           0 :         tds_put_byte(tds, 7);
     218           0 :         tds_put_byte(tds, 7);
     219           0 :         tds_put_byte(tds, 97);
     220           0 :         tds_put_byte(tds, 65);
     221           0 :         tds_put_byte(tds, 207);
     222           0 :         tds_put_byte(tds, 255);
     223           0 :         tds_put_byte(tds, 255);
     224           0 :         tds_put_byte(tds, 230);
     225           0 :         tds_put_byte(tds, 2);
     226           0 :         tds_put_byte(tds, 7);
     227           0 :         tds_put_byte(tds, 0);
     228           0 :         tds_put_byte(tds, 0);
     229           0 :         tds_put_byte(tds, 2);
     230           0 :         tds_put_byte(tds, 0);
     231           0 :         tds_put_byte(tds, 0);
     232           0 :         tds_put_byte(tds, 0);
     233           0 :         tds_put_byte(tds, 0);
     234           0 : }
     235             : 
     236             : /**
     237             :  * Send a "done" token, marking the end of a table, stored procedure, or query.
     238             :  * \param tds           Where the token will be written to.
     239             :  * \param token         The appropriate type of "done" token for this context:
     240             :  *                      TDS_DONE_TOKEN outside a stored procedure,
     241             :  *                      TDS_DONEINPROC_TOKEN inside a stored procedure, or
     242             :  *                      TDS_DONEPROC_TOKEN at the end of a stored procedure.
     243             :  * \param flags         Bitwise-OR of flags in the "enum tds_end" data type.
     244             :  *                      TDS_DONE_FINAL for the last statement in a query,
     245             :  *                      TDS_DONE_MORE_RESULTS if not the last statement,
     246             :  *                      TDS_DONE_ERROR if the statement had an error,
     247             :  *                      TDS_DONE_INXACT if a transaction is  pending,
     248             :  *                      TDS_DONE_PROC inside a stored procedure,
     249             :  *                      TDS_DONE_COUNT if a table was sent (and rows counted)
     250             :  *                      TDS_DONE_CANCELLED if the query was canceled, and
     251             :  *                      TDS_DONE_EVENT if the token marks an event.
     252             :  * \param numrows       Number of rows, if flags has TDS_DONE_COUNT.
     253             :  */
     254             : void
     255        1166 : tds_send_done(TDSSOCKET * tds, int token, TDS_SMALLINT flags, TDS_INT numrows)
     256             : {
     257        1166 :         tds_put_byte(tds, token);
     258        1166 :         tds_put_smallint(tds, flags);
     259        1166 :         tds_put_smallint(tds, 2); /* are these two bytes the transaction status? */
     260        1166 :         if (IS_TDS72_PLUS(tds->conn))
     261         448 :                 tds_put_int8(tds, numrows);
     262             :         else
     263         718 :                 tds_put_int(tds, numrows);
     264        1166 : }
     265             : 
     266             : void
     267         766 : tds_send_done_token(TDSSOCKET * tds, TDS_SMALLINT flags, TDS_INT numrows)
     268             : {
     269         766 :         tds_send_done(tds, TDS_DONE_TOKEN, flags, numrows);
     270         766 : }
     271             : 
     272             : void
     273           0 : tds_send_control_token(TDSSOCKET * tds, TDS_SMALLINT numcols)
     274             : {
     275             :         int i;
     276             : 
     277           0 :         tds_put_byte(tds, TDS_CONTROL_FEATUREEXTACK_TOKEN);
     278           0 :         tds_put_smallint(tds, numcols);
     279           0 :         for (i = 0; i < numcols; i++) {
     280           0 :                 tds_put_byte(tds, 0);
     281             :         }
     282           0 : }
     283             : 
     284             : static void
     285           0 : tds_send_col_name(TDSSOCKET * tds, TDSRESULTINFO * resinfo)
     286             : {
     287           0 :         int col, hdrsize = 0;
     288             :         TDSCOLUMN *curcol;
     289             : 
     290           0 :         tds_put_byte(tds, TDS_COLNAME_TOKEN);
     291           0 :         for (col = 0; col < resinfo->num_cols; col++) {
     292           0 :                 curcol = resinfo->columns[col];
     293           0 :                 hdrsize += tds_dstr_len(&curcol->column_name) + 1;
     294             :         }
     295             : 
     296           0 :         tds_put_smallint(tds, hdrsize);
     297           0 :         for (col = 0; col < resinfo->num_cols; col++) {
     298           0 :                 curcol = resinfo->columns[col];
     299           0 :                 tds_put_byte(tds, tds_dstr_len(&curcol->column_name));
     300             :                 /* exclude the null */
     301           0 :                 tds_put_n(tds, tds_dstr_cstr(&curcol->column_name), tds_dstr_len(&curcol->column_name));
     302             :         }
     303           0 : }
     304             : 
     305             : static void
     306           0 : tds_send_col_info(TDSSOCKET * tds, TDSRESULTINFO * resinfo)
     307             : {
     308           0 :         int col, hdrsize = 0;
     309             :         TDSCOLUMN *curcol;
     310             : 
     311           0 :         tds_put_byte(tds, TDS_COLFMT_TOKEN);
     312             : 
     313           0 :         for (col = 0; col < resinfo->num_cols; col++) {
     314           0 :                 curcol = resinfo->columns[col];
     315           0 :                 hdrsize += 5;
     316           0 :                 if (!is_fixed_type(curcol->column_type)) {
     317           0 :                         hdrsize++;
     318             :                 }
     319             :         }
     320           0 :         tds_put_smallint(tds, hdrsize);
     321             : 
     322           0 :         for (col = 0; col < resinfo->num_cols; col++) {
     323           0 :                 curcol = resinfo->columns[col];
     324           0 :                 tds_put_n(tds, "\0\0\0\0", 4);
     325           0 :                 tds_put_byte(tds, curcol->column_type);
     326           0 :                 if (!is_fixed_type(curcol->column_type)) {
     327           0 :                         tds_put_byte(tds, curcol->column_size);
     328             :                 }
     329             :         }
     330           0 : }
     331             : 
     332             : static void
     333           0 : tds_send_result(TDSSOCKET * tds, TDSRESULTINFO * resinfo)
     334             : {
     335             :         TDSCOLUMN *curcol;
     336             :         int i, totlen;
     337             :         size_t len;
     338             : 
     339           0 :         tds_put_byte(tds, TDS_RESULT_TOKEN);
     340           0 :         totlen = 2;
     341           0 :         for (i = 0; i < resinfo->num_cols; i++) {
     342           0 :                 curcol = resinfo->columns[i];
     343           0 :                 len = tds_dstr_len(&curcol->column_name);
     344           0 :                 totlen += 8;
     345           0 :                 totlen += len;
     346           0 :                 curcol = resinfo->columns[i];
     347           0 :                 if (!is_fixed_type(curcol->column_type)) {
     348           0 :                         totlen++;
     349             :                 }
     350             :         }
     351           0 :         tds_put_smallint(tds, totlen);
     352           0 :         tds_put_smallint(tds, resinfo->num_cols);
     353           0 :         for (i = 0; i < resinfo->num_cols; i++) {
     354           0 :                 curcol = resinfo->columns[i];
     355           0 :                 len = tds_dstr_len(&curcol->column_name);
     356           0 :                 tds_put_byte(tds, tds_dstr_len(&curcol->column_name));
     357           0 :                 tds_put_n(tds, tds_dstr_cstr(&curcol->column_name), len);
     358           0 :                 tds_put_byte(tds, '0');
     359           0 :                 tds_put_int(tds, curcol->column_usertype);
     360           0 :                 tds_put_byte(tds, curcol->column_type);
     361           0 :                 if (!is_fixed_type(curcol->column_type)) {
     362           0 :                         tds_put_byte(tds, curcol->column_size);
     363             :                 }
     364           0 :                 tds_put_byte(tds, 0);
     365             :         }
     366           0 : }
     367             : 
     368             : static TDSRET
     369         176 : tds7_send_result(TDSSOCKET * tds, TDSRESULTINFO * resinfo)
     370             : {
     371             :         int i;
     372             : 
     373             :         /* TDS7+ uses TDS7_RESULT_TOKEN to send column names and info */
     374         176 :         tds_put_byte(tds, TDS7_RESULT_TOKEN);
     375             : 
     376             :         /* send the number of columns */
     377         176 :         tds_put_smallint(tds, resinfo->num_cols);
     378             : 
     379             :         /* send info about each column */
     380         352 :         for (i = 0; i < resinfo->num_cols; i++) {
     381         176 :                 TDSCOLUMN *curcol = resinfo->columns[i];
     382             : 
     383             :                 /* usertype, flags, and type */
     384         176 :                 if (IS_TDS72_PLUS(tds->conn))
     385         176 :                         tds_put_int(tds, curcol->column_usertype);
     386             :                 else
     387           0 :                         tds_put_smallint(tds, curcol->column_usertype);
     388         176 :                 tds_put_smallint(tds, curcol->column_flags);
     389         176 :                 tds_put_byte(tds, curcol->on_server.column_type);
     390             : 
     391         176 :                 TDS_PROPAGATE(curcol->funcs->put_info(tds, curcol));
     392             : 
     393             :                 /* finally the name, in UTF-16 format */
     394         176 :                 TDS_START_LEN_TINYINT(tds) {
     395         528 :                         tds_put_string(tds, tds_dstr_cstr(&curcol->column_name), tds_dstr_len(&curcol->column_name));
     396         176 :                 } TDS_END_LEN_STRING
     397             :         }
     398             :         return TDS_SUCCESS;
     399             : }
     400             : 
     401             : /**
     402             :  * Send any tokens that mark the start of a table.  This automatically chooses
     403             :  * the right tokens for this client's version of the TDS protocol.  In other
     404             :  * words, it is a wrapper around tds_send_col_name(), tds_send_col_info(),
     405             :  * tds_send_result(), and tds7_send_result().
     406             :  * \param tds           The socket to which the tokens will be written.  Also,
     407             :  *                      it contains the TDS protocol version number.
     408             :  * \param resinfo       Describes the table to be send, especially the number
     409             :  *                      of columns and the names & data types of each column.
     410             :  */
     411             : TDSRET
     412         176 : tds_send_table_header(TDSSOCKET * tds, TDSRESULTINFO * resinfo)
     413             : {
     414         176 :         switch (TDS_MAJOR(tds->conn)) {
     415           0 :         case 4:
     416             :                 /*
     417             :                  * TDS4 uses TDS_COLNAME_TOKEN to send column names, and
     418             :                  * TDS_COLFMT_TOKEN to send column info.  The number of columns
     419             :                  * is implied by the number of column names.
     420             :                  */
     421           0 :                 tds_send_col_name(tds, resinfo);
     422           0 :                 tds_send_col_info(tds, resinfo);
     423           0 :                 break;
     424             : 
     425           0 :         case 5:
     426             :                 /* TDS5 uses a TDS_RESULT_TOKEN to send all column information */
     427           0 :                 tds_send_result(tds, resinfo);
     428           0 :                 break;
     429             : 
     430         176 :         case 7:
     431             :         case 8:
     432             :                 /*
     433             :                  * TDS7+ uses a TDS7_RESULT_TOKEN to send all column
     434             :                  * information.
     435             :                  */
     436         176 :                 return tds7_send_result(tds, resinfo);
     437             :                 break;
     438             :         }
     439             :         return TDS_SUCCESS;
     440             : }
     441             : 
     442             : TDSRET
     443         264 : tds_send_row(TDSSOCKET * tds, TDSRESULTINFO * resinfo)
     444             : {
     445             :         int i;
     446             : 
     447         264 :         tds_put_byte(tds, TDS_ROW_TOKEN);
     448         528 :         for (i = 0; i < resinfo->num_cols; i++) {
     449         264 :                 TDSCOLUMN *curcol = resinfo->columns[i];
     450             : 
     451         264 :                 TDS_PROPAGATE(curcol->funcs->put_data(tds, curcol, 0));
     452             :         }
     453             :         return TDS_SUCCESS;
     454             : }
     455             : 
     456             : void
     457          16 : tds71_send_prelogin(TDSSOCKET * tds)
     458             : {
     459             :         static const unsigned char prelogin_default[] = {
     460             :                 0x00, 0x00, 0x1a, 0x00, 0x06,
     461             :                 0x01, 0x00, 0x20, 0x00, 0x01,
     462             :                 0x02, 0x00, 0x21, 0x00, 0x01,
     463             :                 0x03, 0x00, 0x22, 0x00, 0x00,
     464             :                 0x04, 0x00, 0x22, 0x00, 0x01,
     465             :                 0xff,
     466             :                 0x08, 0x00, 0x01, 0x55, 0x00, 0x00,
     467             :                 0x02,
     468             :                 0x00,
     469             :                 0x00
     470             :         };
     471             :         unsigned char prelogin[sizeof(prelogin_default)];
     472             : 
     473          16 :         memcpy(prelogin, prelogin_default, sizeof(prelogin));
     474          16 :         TDS_PUT_A4BE(&prelogin[0x1a], tds->conn->product_version & 0x7fffffffu);
     475          16 :         tds_put_n(tds, prelogin, sizeof(prelogin));
     476          16 : }
     477             : 

Generated by: LCOV version 1.13